Possible to setup custom saved game and installation directory.

This commit is contained in:
Khopa
2020-06-05 14:21:42 +02:00
parent ce70242c35
commit b219b2a71b
13 changed files with 402 additions and 176 deletions

View File

@@ -4,6 +4,7 @@ import sys
from shutil import copyfile
import dcs
from PySide2 import QtWidgets
from PySide2.QtGui import QPixmap
from PySide2.QtWidgets import QApplication, QSplashScreen
from dcs import installation
@@ -11,12 +12,22 @@ from dcs import installation
from qt_ui import uiconstants
from qt_ui.windows.GameUpdateSignal import GameUpdateSignal
from qt_ui.windows.QLiberationWindow import QLiberationWindow
from userdata import persistency, logging as logging_module
from qt_ui.windows.preferences.QLiberationFirstStartWindow import QLiberationFirstStartWindow
from userdata import persistency, logging as logging_module, liberation_install
if __name__ == "__main__":
persistency.setup(installation.get_dcs_saved_games_directory())
app = QApplication(sys.argv)
css = ""
with open("./resources/stylesheets/style.css") as stylesheet:
app.setStyleSheet(stylesheet.read())
# Logging setup
VERSION_STRING = "2.0RC6"
logging_module.setup_version_string(VERSION_STRING)
# Inject custom payload in pydcs framework
custom_payloads = os.path.join(os.path.dirname(os.path.realpath(__file__)), "..\\resources\\customized_payloads")
if os.path.exists(custom_payloads):
dcs.planes.FlyingType.payload_dirs.append(custom_payloads)
@@ -27,11 +38,14 @@ if __name__ == "__main__":
if os.path.exists(custom_payloads):
dcs.planes.FlyingType.payload_dirs.append(custom_payloads)
VERSION_STRING = "2.0RC6"
logging_module.setup_version_string(VERSION_STRING)
logging.info("Using {} as userdata folder".format(persistency.base_path()))
app = QApplication(sys.argv)
first_start = liberation_install.init()
if first_start:
window = QLiberationFirstStartWindow()
window.exec_()
logging.info("Using {} as 'Saved Game Folder'".format(persistency.base_path()))
logging.info("Using {} as 'DCS installation folder'".format(liberation_install.get_dcs_install_directory()))
# Splash screen setup
pixmap = QPixmap("./resources/ui/splash_screen.png")
@@ -44,24 +58,28 @@ if __name__ == "__main__":
uiconstants.load_aircraft_icons()
uiconstants.load_vehicle_icons()
css = ""
with open("./resources/stylesheets/style.css") as stylesheet:
css = stylesheet.read()
# Replace DCS Mission scripting file to allow DCS Liberation to work
print("Replace : " + installation.get_dcs_install_directory() + os.path.sep + "Scripts/MissionScripting.lua")
copyfile("./resources/scripts/MissionScripting.lua", installation.get_dcs_install_directory() + os.path.sep + "Scripts/MissionScripting.lua")
app.processEvents()
try:
liberation_install.replace_mission_scripting_file()
except:
error_dialog = QtWidgets.QErrorMessage()
error_dialog.setWindowTitle("Wrong DCS installation directory.")
error_dialog.showMessage("Unable to modify Mission Scripting file. Possible issues with rights. Try running as admin, or please perform the modification of the MissionScripting file manually.")
error_dialog.exec_()
# Apply CSS (need works)
app.setStyleSheet(css)
GameUpdateSignal()
# Start window
window = QLiberationWindow()
window.showMaximized()
splash.finish(window)
sys.exit(app.exec_())
qt_execution_code = app.exec_()
# Restore Mission Scripting file
logging.info("QT App terminated with status code : " + str(qt_execution_code))
logging.info("Attempt to restore original mission scripting file")
liberation_install.restore_original_mission_scripting()
sys.exit(qt_execution_code)

View File

@@ -8,12 +8,12 @@ from game.event import UnitsDeliveryEvent, FrontlineAttackEvent
from theater.theatergroundobject import CATEGORY_MAP
URLS : Dict[str, str] = {
"Manual": "https://github.com/shdwp/dcs_liberation/wiki/Manual",
"Manual": "https://github.com/khopa/dcs_liberation/wiki",
"Troubleshooting": "https://github.com/shdwp/dcs_liberation/wiki/Troubleshooting",
"Modding": "https://github.com/shdwp/dcs_liberation/wiki/Modding-tutorial",
"Repository": "https://github.com/shdwp/dcs_liberation",
"Repository": "https://github.com/khopa/dcs_liberation",
"ForumThread": "https://forums.eagle.ru/showthread.php?t=214834",
"Issues": "https://github.com/shdwp/dcs_liberation/issues"
"Issues": "https://github.com/khopa/dcs_liberation/issues"
}
LABELS_OPTIONS = ["Full", "Abbreviated", "Dot Only", "Off"]

View File

@@ -1,10 +1,9 @@
import sys
import webbrowser
from PySide2 import QtGui
from PySide2.QtCore import Qt
from PySide2.QtGui import QIcon
from PySide2.QtWidgets import QWidget, QHBoxLayout, QVBoxLayout, QMainWindow, QAction, QMessageBox, QDesktopWidget, \
from PySide2.QtWidgets import QWidget, QVBoxLayout, QMainWindow, QAction, QMessageBox, QDesktopWidget, \
QSplitter
import qt_ui.uiconstants as CONST
@@ -12,10 +11,12 @@ from game import Game
from qt_ui.uiconstants import URLS
from qt_ui.widgets.QTopPanel import QTopPanel
from qt_ui.widgets.map.QLiberationMap import QLiberationMap
from qt_ui.windows.preferences import QLiberationPreferences
from qt_ui.windows.GameUpdateSignal import GameUpdateSignal, DebriefingSignal
from qt_ui.windows.QDebriefingWindow import QDebriefingWindow
from qt_ui.windows.QNewGameWizard import NewGameWizard
from qt_ui.windows.infos.QInfoPanel import QInfoPanel
from qt_ui.windows.preferences.QLiberationPreferencesWindow import QLiberationPreferencesWindow
from userdata import persistency
@@ -79,6 +80,10 @@ class QLiberationWindow(QMainWindow):
self.showAboutDialogAction.setIcon(QIcon.fromTheme("help-about"))
self.showAboutDialogAction.triggered.connect(self.showAboutDialog)
self.showLiberationPrefDialogAction = QAction("Preferences", self)
self.showLiberationPrefDialogAction.setIcon(QIcon.fromTheme("help-about"))
self.showLiberationPrefDialogAction.triggered.connect(self.showLiberationDialog)
def initToolbar(self):
self.tool_bar = self.addToolBar("File")
self.tool_bar.addAction(self.newGameAction)
@@ -92,17 +97,21 @@ class QLiberationWindow(QMainWindow):
file_menu.addAction(self.newGameAction)
#file_menu.addAction(QIcon(CONST.ICONS["Open"]), "Open") # TODO : implement
file_menu.addAction(self.saveGameAction)
file_menu.addSeparator()
file_menu.addAction(self.showLiberationPrefDialogAction)
file_menu.addSeparator()
#file_menu.addAction("Save As") # TODO : implement
#file_menu.addAction("Close Current Game", lambda: self.closeGame()) # Not working
file_menu.addAction("Exit" , lambda: self.exit())
help_menu = self.menu.addMenu("Help")
#help_menu.addAction("Online Manual", lambda: webbrowser.open_new_tab(URLS["Manual"]))
help_menu.addAction("Online Manual", lambda: webbrowser.open_new_tab(URLS["Manual"]))
help_menu.addAction("Discord", lambda: webbrowser.open_new_tab("https://" + "discord.gg" + "/" + "bKrt" + "rkJ"))
#help_menu.addAction("Troubleshooting Guide", lambda: webbrowser.open_new_tab(URLS["Troubleshooting"]))
#help_menu.addAction("Modding Guide", lambda: webbrowser.open_new_tab(URLS["Modding"]))
#help_menu.addSeparator() ----> Note from Khopa : I disable these links since it's not up to date for this branch
help_menu.addAction("Contribute", lambda: webbrowser.open_new_tab(URLS["Repository"]))
#help_menu.addAction("Contribute", lambda: webbrowser.open_new_tab(URLS["Repository"]))
help_menu.addAction("Forum Thread", lambda: webbrowser.open_new_tab(URLS["ForumThread"]))
help_menu.addAction("Report an issue", lambda: webbrowser.open_new_tab(URLS["Issues"]))
help_menu.addSeparator()
@@ -192,6 +201,10 @@ class QLiberationWindow(QMainWindow):
print(about.textFormat())
about.exec_()
def showLiberationDialog(self):
self.subwindow = QLiberationPreferencesWindow()
self.subwindow.show()
def onDebriefing(self, debrief: DebriefingSignal):
print("On Debriefing")
self.debriefing = QDebriefingWindow(debrief.debriefing, debrief.gameEvent, debrief.game)

View File

@@ -0,0 +1,80 @@
from PySide2.QtGui import QIcon, Qt
from PySide2.QtWidgets import QDialog, QVBoxLayout, QPushButton, QHBoxLayout, QPlainTextEdit, QTextEdit
from qt_ui.windows.preferences.QLiberationPreferences import QLiberationPreferences
class QLiberationFirstStartWindow(QDialog):
def __init__(self):
super(QLiberationFirstStartWindow, self).__init__()
self.setModal(True)
self.setWindowTitle("First start configuration")
self.setMinimumSize(500, 200)
self.setWindowIcon(QIcon("./resources/icon.png"))
self.setWindowFlags(Qt.WindowStaysOnTopHint | Qt.Dialog | Qt.WindowTitleHint)
self.setWindowModality(Qt.WindowModal)
self.preferences = QLiberationPreferences()
WARN_TEXT = """
<strong>Welcome to DCS Liberation !</strong>
<br/><br>
<strong>Please take 30 seconds to read this :</strong>
<p>DCS Liberation will modify this file in your DCS installation directory :</p>
<br/>
<strong>&lt;dcs_installation_directory&gt;/Scripts/MissionScripting.lua</strong><br/>
<p>
This will disable some security limits of the DCS World Lua scripting environment, in order to allow communication between DCS World and DCS Liberation.
However, the modification of this file could potentially grant access to your filesystem to malicious DCS mission files.
</p>
<p>So, you should not join untrusted servers or open untrusted mission files within DCS world while DCS Liberation is running.</p>
<p>
DCS Liberation will restore your original MissionScripting file when it close.
</p>
<p>
However, should DCS Liberation encounter an unexpected crash (which should not happen), the MissionScripting file might not be restored.
If that occurs, you can use the backup file saved in the DCS Liberation directory there :
</p>
<br/>
<strong>./resources/scripts/MissionScripting.original.lua</strong><br/>
<p>Then copy it in your DCS installation directory to replace this file :</p>
<br/>
<strong>&lt;dcs_installation_directory&gt;/Scripts/MissionScripting.lua</strong><br/>
<p>As you click on the button below, the file will be replaced in your DCS installation directory.</p>
<br/><br/>
<strong>Thank you for reading !</strong>
"""
self.warning_text = QTextEdit(WARN_TEXT)
self.warning_text.setReadOnly(True)
self.apply_button = QPushButton("I have read everything and I Accept")
self.apply_button.clicked.connect(lambda : self.apply())
self.initUI()
def initUI(self):
layout = QVBoxLayout()
layout.addWidget(self.preferences)
layout.addWidget(self.warning_text)
layout.addStretch()
apply_btn_layout = QHBoxLayout()
apply_btn_layout.addStretch()
apply_btn_layout.addWidget(self.apply_button)
layout.addLayout(apply_btn_layout)
self.setLayout(layout)
def apply(self):
print("Applying changes")
if self.preferences.apply():
self.close()

View File

@@ -0,0 +1,93 @@
import os
from PySide2 import QtWidgets
from PySide2.QtGui import Qt
from PySide2.QtWidgets import QFrame, QLineEdit, QGridLayout, QVBoxLayout, QLabel, QPushButton, \
QFileDialog, QMessageBox, QDialog
from userdata import liberation_install
class QLiberationPreferences(QFrame):
def __init__(self):
super(QLiberationPreferences, self).__init__()
self.saved_game_dir = ""
self.dcs_install_dir = ""
self.dcs_install_dir = liberation_install.get_dcs_install_directory()
self.saved_game_dir = liberation_install.get_saved_game_dir()
self.edit_dcs_install_dir = QLineEdit(self.dcs_install_dir)
self.edit_saved_game_dir = QLineEdit(self.saved_game_dir)
self.edit_dcs_install_dir.setMinimumWidth(300)
self.edit_saved_game_dir.setMinimumWidth(300)
self.browse_saved_game = QPushButton("Browse...")
self.browse_saved_game.clicked.connect(self.on_browse_saved_games)
self.browse_install_dir = QPushButton("Browse...")
self.browse_install_dir.clicked.connect(self.on_browse_installation_dir)
self.initUi()
def initUi(self):
main_layout = QVBoxLayout()
layout = QGridLayout()
layout.addWidget(QLabel("<strong>DCS saved game directory:</strong>"), 0, 0, alignment=Qt.AlignLeft)
layout.addWidget(self.edit_saved_game_dir, 1, 0, alignment=Qt.AlignRight)
layout.addWidget(self.browse_saved_game, 1, 1, alignment=Qt.AlignRight)
layout.addWidget(QLabel("<strong>DCS installation directory:</strong>"), 2, 0, alignment=Qt.AlignLeft)
layout.addWidget(self.edit_dcs_install_dir, 3, 0, alignment=Qt.AlignRight)
layout.addWidget(self.browse_install_dir, 3, 1, alignment=Qt.AlignRight)
main_layout.addLayout(layout)
main_layout.addStretch()
self.setLayout(main_layout)
def on_browse_saved_games(self):
saved_game_dir = str(QFileDialog.getExistingDirectory(self, "Select DCS Saved Game Directory"))
if saved_game_dir:
self.saved_game_dir = saved_game_dir
self.edit_saved_game_dir.setText(saved_game_dir)
def on_browse_installation_dir(self):
install_dir = str(QFileDialog.getExistingDirectory(self, "Select DCS Installation Directory"))
if install_dir:
self.dcs_install_dir = install_dir
self.edit_dcs_install_dir.setText(install_dir)
def apply(self):
print("Applying changes")
self.saved_game_dir = self.edit_saved_game_dir.text()
self.dcs_install_dir = self.edit_dcs_install_dir.text()
if not os.path.isdir(self.saved_game_dir):
error_dialog = QMessageBox.critical(self, "Wrong DCS Saved Games directory.",
self.saved_game_dir + " is not a valid directory",
QMessageBox.StandardButton.Ok)
error_dialog.exec_()
return False
if not os.path.isdir(self.dcs_install_dir):
error_dialog = QMessageBox.critical(self, "Wrong DCS installation directory.",
self.dcs_install_dir + " is not a valid directory",
QMessageBox.StandardButton.Ok)
error_dialog.exec_()
return False
if not os.path.isdir(os.path.join(self.dcs_install_dir, "Scripts")) and os.path.isfile(os.path.join(self.dcs_install_dir, "bin", "DCS.exe")):
error_dialog = QMessageBox.critical(self, "Wrong DCS installation directory.",
self.dcs_install_dir + " is not a valid DCS installation directory",
QMessageBox.StandardButton.Ok)
error_dialog.exec_()
return False
liberation_install.setup(self.saved_game_dir, self.dcs_install_dir)
liberation_install.save_config()
return True

View File

@@ -0,0 +1,37 @@
from PySide2.QtGui import QIcon, Qt
from PySide2.QtWidgets import QDialog, QVBoxLayout, QPushButton, QHBoxLayout
from qt_ui.windows.preferences.QLiberationPreferences import QLiberationPreferences
class QLiberationPreferencesWindow(QDialog):
def __init__(self):
super(QLiberationPreferencesWindow, self).__init__()
self.setModal(True)
self.setWindowTitle("Preferences")
self.setMinimumSize(300, 200)
self.setWindowIcon(QIcon("./resources/icon.png"))
self.preferences = QLiberationPreferences()
self.apply_button = QPushButton("Apply")
self.apply_button.clicked.connect(lambda : self.apply())
self.initUI()
def initUI(self):
layout = QVBoxLayout()
layout.addWidget(self.preferences)
layout.addStretch()
apply_btn_layout = QHBoxLayout()
apply_btn_layout.addStretch()
apply_btn_layout.addWidget(self.apply_button)
layout.addLayout(apply_btn_layout)
self.setLayout(layout)
def apply(self):
if self.preferences.apply():
print("Closing")
self.close()
else:
print("Not Closing")

View File

@@ -98,11 +98,11 @@ class QSettingsWindow(QDialog):
self.enemyAASkill.currentIndexChanged.connect(self.applySettings)
self.difficultyLayout.addWidget(QLabel("Player coalition skill"), 0, 0)
self.difficultyLayout.addWidget(self.playerCoalitionSkill, 0, 1)
self.difficultyLayout.addWidget(self.playerCoalitionSkill, 0, 1, Qt.AlignRight)
self.difficultyLayout.addWidget(QLabel("Enemy skill"), 1, 0)
self.difficultyLayout.addWidget(self.enemyCoalitionSkill, 1, 1)
self.difficultyLayout.addWidget(self.enemyCoalitionSkill, 1, 1, Qt.AlignRight)
self.difficultyLayout.addWidget(QLabel("Enemy AA and vehicles skill"), 2, 0)
self.difficultyLayout.addWidget(self.enemyAASkill, 2, 1)
self.difficultyLayout.addWidget(self.enemyAASkill, 2, 1, Qt.AlignRight)
self.difficultyLabel = QComboBox()
[self.difficultyLabel.addItem(t) for t in CONST.LABELS_OPTIONS]
@@ -110,13 +110,13 @@ class QSettingsWindow(QDialog):
self.difficultyLabel.currentIndexChanged.connect(self.applySettings)
self.difficultyLayout.addWidget(QLabel("In Game Labels"), 3, 0)
self.difficultyLayout.addWidget(self.difficultyLabel, 3, 1)
self.difficultyLayout.addWidget(self.difficultyLabel, 3, 1, Qt.AlignRight)
self.noNightMission = QCheckBox()
self.noNightMission.setChecked(self.game.settings.night_disabled)
self.noNightMission.toggled.connect(self.applySettings)
self.difficultyLayout.addWidget(QLabel("No night missions"), 4, 0)
self.difficultyLayout.addWidget(self.noNightMission, 4, 1)
self.difficultyLayout.addWidget(self.noNightMission, 4, 1, Qt.AlignRight)
def initGeneratorLayout(self):
@@ -135,7 +135,7 @@ class QSettingsWindow(QDialog):
self.supercarrier.toggled.connect(self.applySettings)
self.gameplayLayout.addWidget(QLabel("Use Supercarrier Module"), 0, 0)
self.gameplayLayout.addWidget(self.supercarrier, 0, 1)
self.gameplayLayout.addWidget(self.supercarrier, 0, 1, Qt.AlignRight)
self.performance = QGroupBox("Performance")
self.performanceLayout = QGridLayout();
@@ -162,16 +162,22 @@ class QSettingsWindow(QDialog):
self.infantry.setChecked(self.game.settings.perf_infantry)
self.infantry.toggled.connect(self.applySettings)
self.ai_parking_start = QCheckBox()
self.ai_parking_start.setChecked(self.game.settings.perf_ai_parking_start)
self.ai_parking_start.toggled.connect(self.applySettings)
self.performanceLayout.addWidget(QLabel("Smoke visual effect on frontline"), 0, 0)
self.performanceLayout.addWidget(self.smoke, 0, 1)
self.performanceLayout.addWidget(self.smoke, 0, 1, alignment=Qt.AlignRight)
self.performanceLayout.addWidget(QLabel("SAM starts in RED alert mode"), 1, 0)
self.performanceLayout.addWidget(self.red_alert, 1, 1)
self.performanceLayout.addWidget(self.red_alert, 1, 1, alignment=Qt.AlignRight)
self.performanceLayout.addWidget(QLabel("Artillery strikes"), 2, 0)
self.performanceLayout.addWidget(self.arti, 2, 1)
self.performanceLayout.addWidget(self.arti, 2, 1, alignment=Qt.AlignRight)
self.performanceLayout.addWidget(QLabel("Moving ground units"), 3, 0)
self.performanceLayout.addWidget(self.moving_units, 3, 1)
self.performanceLayout.addWidget(self.moving_units, 3, 1, alignment=Qt.AlignRight)
self.performanceLayout.addWidget(QLabel("Generate infantry squads along vehicles"), 4, 0)
self.performanceLayout.addWidget(self.infantry, 4, 1)
self.performanceLayout.addWidget(self.infantry, 4, 1, alignment=Qt.AlignRight)
self.performanceLayout.addWidget(QLabel("AI planes parking start (AI starts in flight if disabled)"), 5, 0)
self.performanceLayout.addWidget(self.ai_parking_start, 5, 1, alignment=Qt.AlignRight)
self.generatorLayout.addWidget(self.gameplay)
self.generatorLayout.addWidget(QLabel("Disabling settings below may improve performance, but will impact the overall quality of the experience."))
@@ -230,6 +236,7 @@ class QSettingsWindow(QDialog):
self.game.settings.perf_artillery = self.arti.isChecked()
self.game.settings.perf_moving_units = self.moving_units.isChecked()
self.game.settings.perf_infantry = self.infantry.isChecked()
self.game.settings.perf_ai_parking_start = self.ai_parking_start.isChecked()
GameUpdateSignal.get_instance().updateGame(self.game)