mirror of
https://github.com/dcs-retribution/dcs-retribution.git
synced 2025-11-10 15:41:24 +00:00
#110 Ability to load/save settings
Also includes support for remaining enum/timedelta settings through the yaml file. - timedelta's in minutes - enum's should be written out: enumType.enumValue
This commit is contained in:
parent
5916ed43d2
commit
3f509a876e
@ -27,6 +27,10 @@ def base_path() -> str:
|
||||
return _dcs_saved_game_folder
|
||||
|
||||
|
||||
def settings_dir() -> Path:
|
||||
return Path(base_path()) / "Retribution" / "Settings"
|
||||
|
||||
|
||||
def save_dir() -> Path:
|
||||
return Path(base_path()) / "Retribution" / "Saves"
|
||||
|
||||
|
||||
@ -16,6 +16,8 @@ from .skilloption import skill_option
|
||||
from ..ato.starttype import StartType
|
||||
from ..weather import NightMissions
|
||||
|
||||
Views = ForcedOptions.Views
|
||||
|
||||
|
||||
@unique
|
||||
class AutoAtoBehavior(Enum):
|
||||
@ -126,18 +128,18 @@ class Settings:
|
||||
choices=["Full", "Abbreviated", "Dot Only", "Neutral Dot", "Off"],
|
||||
default="Full",
|
||||
)
|
||||
map_coalition_visibility: ForcedOptions.Views = choices_option(
|
||||
map_coalition_visibility: Views = choices_option(
|
||||
"Map visibility options",
|
||||
page=DIFFICULTY_PAGE,
|
||||
section=MISSION_RESTRICTIONS_SECTION,
|
||||
choices={
|
||||
"All": ForcedOptions.Views.All,
|
||||
"Fog of war": ForcedOptions.Views.Allies,
|
||||
"Allies only": ForcedOptions.Views.OnlyAllies,
|
||||
"Own aircraft only": ForcedOptions.Views.MyAircraft,
|
||||
"Map only": ForcedOptions.Views.OnlyMap,
|
||||
"All": Views.All,
|
||||
"Fog of war": Views.Allies,
|
||||
"Allies only": Views.OnlyAllies,
|
||||
"Own aircraft only": Views.MyAircraft,
|
||||
"Map only": Views.OnlyMap,
|
||||
},
|
||||
default=ForcedOptions.Views.All,
|
||||
default=Views.All,
|
||||
)
|
||||
external_views_allowed: bool = boolean_option(
|
||||
"Allow external views",
|
||||
@ -673,6 +675,15 @@ class Settings:
|
||||
self.plugins[self.plugin_settings_key(identifier)] = value
|
||||
|
||||
def __setstate__(self, state: dict[str, Any]) -> None:
|
||||
# restore Enum & timedelta types
|
||||
for key, value in state.items():
|
||||
if isinstance(self.__dict__.get(key), timedelta) and isinstance(value, int):
|
||||
state[key] = timedelta(minutes=value)
|
||||
elif isinstance(self.__dict__.get(key), Enum) and isinstance(value, str):
|
||||
state[key] = eval(value)
|
||||
elif isinstance(value, dict):
|
||||
state[key] = self.obj_hook(value)
|
||||
|
||||
# __setstate__ is called with the dict of the object being unpickled. We
|
||||
# can provide save compatibility for new settings options (which
|
||||
# normally would not be present in the unpickled object) by creating a
|
||||
@ -716,3 +727,22 @@ class Settings:
|
||||
for settings_field in fields(cls):
|
||||
if SETTING_DESCRIPTION_KEY in settings_field.metadata:
|
||||
yield settings_field
|
||||
|
||||
@staticmethod
|
||||
def default_json(obj: Any) -> Any:
|
||||
# Known types that don't like being serialized,
|
||||
# so we introduce our own implementation...
|
||||
if isinstance(obj, Enum):
|
||||
return {"Enum": str(obj)}
|
||||
elif isinstance(obj, timedelta):
|
||||
return {"timedelta": round(obj.seconds / 60)}
|
||||
return obj
|
||||
|
||||
@staticmethod
|
||||
def obj_hook(obj: Any) -> Any:
|
||||
if (value := obj.get("Enum")) is not None:
|
||||
return eval(value)
|
||||
elif (value := obj.get("timedelta")) is not None:
|
||||
return timedelta(minutes=value)
|
||||
else:
|
||||
return obj
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
import json
|
||||
import logging
|
||||
import textwrap
|
||||
from typing import Callable
|
||||
import zipfile
|
||||
|
||||
from PySide2.QtCore import QItemSelectionModel, QPoint, QSize, Qt
|
||||
from PySide2.QtGui import QStandardItem, QStandardItemModel
|
||||
@ -19,10 +21,12 @@ from PySide2.QtWidgets import (
|
||||
QStackedLayout,
|
||||
QVBoxLayout,
|
||||
QWidget,
|
||||
QFileDialog,
|
||||
)
|
||||
|
||||
import qt_ui.uiconstants as CONST
|
||||
from game.game import Game
|
||||
from game.persistency import settings_dir
|
||||
from game.server import EventStream
|
||||
from game.settings import (
|
||||
BooleanOption,
|
||||
@ -332,6 +336,13 @@ class QSettingsWindow(QDialog):
|
||||
self.layout.addWidget(self.categoryList, 0, 0, 1, 1)
|
||||
self.layout.addLayout(self.right_layout, 0, 1, 5, 1)
|
||||
|
||||
load = QPushButton("Load Settings")
|
||||
load.clicked.connect(self.load_settings)
|
||||
self.layout.addWidget(load, 1, 0, 1, 1)
|
||||
save = QPushButton("Save Settings")
|
||||
save.clicked.connect(self.save_settings)
|
||||
self.layout.addWidget(save, 2, 0, 1, 1)
|
||||
|
||||
self.setLayout(self.layout)
|
||||
|
||||
def initCheatLayout(self):
|
||||
@ -387,3 +398,41 @@ class QSettingsWindow(QDialog):
|
||||
def onSelectionChanged(self):
|
||||
index = self.categoryList.selectionModel().currentIndex().row()
|
||||
self.right_layout.setCurrentIndex(index)
|
||||
|
||||
def load_settings(self):
|
||||
sd = settings_dir()
|
||||
if not sd.exists():
|
||||
sd.mkdir()
|
||||
fd = QFileDialog(caption="Load Settings", directory=str(sd), filter="*.zip")
|
||||
if fd.exec_():
|
||||
zipfilename = fd.selectedFiles()[0]
|
||||
with zipfile.ZipFile(zipfilename, "r") as zf:
|
||||
filename = zipfilename.split("/")[-1].replace(".zip", ".json")
|
||||
settings = json.loads(
|
||||
zf.read(filename).decode("utf-8"),
|
||||
object_hook=self.game.settings.obj_hook,
|
||||
)
|
||||
self.game.settings.__setstate__(settings)
|
||||
self.close()
|
||||
new = QSettingsWindow(self.game)
|
||||
new.exec_()
|
||||
|
||||
def save_settings(self):
|
||||
sd = settings_dir()
|
||||
if not sd.exists():
|
||||
sd.mkdir()
|
||||
fd = QFileDialog(caption="Save Settings", directory=str(sd), filter="*.zip")
|
||||
fd.setAcceptMode(QFileDialog.AcceptSave)
|
||||
if fd.exec_():
|
||||
zipfilename = fd.selectedFiles()[0]
|
||||
with zipfile.ZipFile(zipfilename, "w", zipfile.ZIP_DEFLATED) as zf:
|
||||
filename = zipfilename.split("/")[-1].replace(".zip", ".json")
|
||||
zf.writestr(
|
||||
filename,
|
||||
json.dumps(
|
||||
self.game.settings.__dict__,
|
||||
indent=2,
|
||||
default=self.game.settings.default_json,
|
||||
),
|
||||
zipfile.ZIP_DEFLATED,
|
||||
)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user