diff --git a/changelog.md b/changelog.md index 6338d8ad..b3368e40 100644 --- a/changelog.md +++ b/changelog.md @@ -39,6 +39,7 @@ * **[Mission Generation]** Automatic datalink network setup for applicable aircraft (_should_ in theory avoid the need to re-save the mission) * **[Options]** New option to force-enable deck-crew for super-carriers on dedicated server. * **[Mission Generation]** Enable Supercarrier's LSO & Airboss stations +* **[UX]** Default settings are now loaded from Default.zip * **[Autoplanner]** Plan Air-to-Air Escorts for AWACS & Tankers ## Fixes diff --git a/game/settings/settings.py b/game/settings/settings.py index b808591a..4326da56 100644 --- a/game/settings/settings.py +++ b/game/settings/settings.py @@ -1339,27 +1339,31 @@ 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 # new settings object, updating it with the unpickled state, and # updating our dict with that. new_state = Settings().__dict__ - new_state.update(state) + new_state.update(self.deserialize_state_dict(state)) self.__dict__.update(new_state) from game.plugins import LuaPluginManager LuaPluginManager().load_settings(self) + @staticmethod + def deserialize_state_dict(state: dict[str, Any]) -> dict[str, Any]: + # restore Enum & timedelta types + s = Settings() + for key, value in state.items(): + if isinstance(s.__dict__.get(key), timedelta) and isinstance(value, int): + state[key] = timedelta(minutes=value) + elif isinstance(s.__dict__.get(key), Enum) and isinstance(value, str): + state[key] = eval(value) + elif isinstance(value, dict): + state[key] = s.obj_hook(value) + return state + @classmethod def _field_description(cls, settings_field: Field[Any]) -> OptionDescription: return settings_field.metadata[SETTING_DESCRIPTION_KEY] diff --git a/qt_ui/windows/newgame/WizardPages/QNewGameSettings.py b/qt_ui/windows/newgame/WizardPages/QNewGameSettings.py index edbd970f..1c6d273a 100644 --- a/qt_ui/windows/newgame/WizardPages/QNewGameSettings.py +++ b/qt_ui/windows/newgame/WizardPages/QNewGameSettings.py @@ -12,26 +12,29 @@ class NewGameSettings(QtWidgets.QWizardPage): super().__init__(parent) self.setTitle("Campaign options") - self.setSubTitle("\nAll other options unrelated to campaign generation.") + self.setSubTitle( + "\nAll other options unrelated to campaign generation. Defaults can be changed by overwriting Default.zip" + ) self.setPixmap( QtWidgets.QWizard.WizardPixmap.LogoPixmap, QtGui.QPixmap("./resources/ui/wizard/logo1.png"), ) settings = Settings() - settings.__setstate__(campaign.settings) + self.settings_widget = QSettingsWidget(settings) + self.settings_widget.load_default_settings() + settings.__dict__.update(Settings.deserialize_state_dict(campaign.settings)) settings.player_income_multiplier = ( campaign.recommended_player_income_multiplier ) settings.enemy_income_multiplier = campaign.recommended_enemy_income_multiplier - settings.__dict__.update(campaign.settings) - self.settings_widget = QSettingsWidget(settings) + self.settings_widget.update_from_settings() self.setLayout(self.settings_widget.layout) def set_campaign_values(self, c: Campaign): sw = self.settings_widget - sw.settings.__setstate__(c.settings) + sw.load_default_settings() + sw.settings.__dict__.update(Settings.deserialize_state_dict(c.settings)) sw.settings.player_income_multiplier = c.recommended_player_income_multiplier sw.settings.enemy_income_multiplier = c.recommended_enemy_income_multiplier - sw.settings.__dict__.update(c.settings) sw.update_from_settings() diff --git a/qt_ui/windows/settings/QSettingsWindow.py b/qt_ui/windows/settings/QSettingsWindow.py index 6d4525b2..68bf96fd 100644 --- a/qt_ui/windows/settings/QSettingsWindow.py +++ b/qt_ui/windows/settings/QSettingsWindow.py @@ -572,3 +572,33 @@ class QSettingsWidget(QtWidgets.QWizardPage, SettingsContainer): ), zipfile.ZIP_DEFLATED, ) + + def load_default_settings(self): + sd = settings_dir() + default_zip_path = sd / "Default.zip" + if default_zip_path.exists(): + with zipfile.ZipFile(default_zip_path, "r") as zf: + filename = "Default.json" + if filename in zf.namelist(): + settings_data = json.loads( + zf.read(filename).decode("utf-8"), + object_hook=self.settings.obj_hook, + ) + self.settings.__setstate__(settings_data) + else: + if self.settings is None: + default_settings = Settings() + else: + default_settings = self.settings + with zipfile.ZipFile(default_zip_path, "w", zipfile.ZIP_DEFLATED) as zf: + filename = "Default.json" + zf.writestr( + filename, + json.dumps( + default_settings.__dict__, + indent=2, + default=default_settings.default_json, + ), + zipfile.ZIP_DEFLATED, + ) + self.settings.__setstate__(default_settings.__dict__)