Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

set options as default for new game #1705

Draft
wants to merge 9 commits into
base: options-XML3
Choose a base branch
from
24 changes: 15 additions & 9 deletions TLM/TLM/State/GlobalConfig.cs
Expand Up @@ -8,9 +8,7 @@ namespace TrafficManager.State {
using TrafficManager.Util;
using TrafficManager.Lifecycle;

[XmlRootAttribute(
"GlobalConfig",
IsNullable = false)]
[XmlRoot("GlobalConfig", IsNullable = false)]
public class GlobalConfig : GenericObservable<GlobalConfig> {
public const string FILENAME = "TMPE_GlobalConfig.xml";
public const string BACKUP_FILENAME = FILENAME + ".bak";
Expand Down Expand Up @@ -79,17 +77,25 @@ public class GlobalConfig : GenericObservable<GlobalConfig> {

public ConfigData.TimedTrafficLights TimedTrafficLights = new();

[XmlElement("DefaultsForNewGame")]
public SavedGameOptions SavedGameOptions = null;

internal static void WriteConfig() {
ModifiedTime = WriteConfig(Instance);
}

/// <summary>
/// Replaces global config file with default config.
/// </summary>
/// <param name="oldConfig">if null, all is reset, otherwise old config is migrated to new config.</param>
/// <param name="modifiedTime">time of the file created</param>
/// <returns>the new default config</returns>
private static GlobalConfig WriteDefaultConfig(GlobalConfig oldConfig,
bool resetAll,
out DateTime modifiedTime) {
Log._Debug($"Writing default config...");
GlobalConfig conf = new GlobalConfig();

if (!resetAll && oldConfig != null) {
if (oldConfig != null) {
conf.Main.MainMenuButtonX = oldConfig.Main.MainMenuButtonX;
conf.Main.MainMenuButtonY = oldConfig.Main.MainMenuButtonY;

Expand Down Expand Up @@ -190,7 +196,7 @@ public class GlobalConfig : GenericObservable<GlobalConfig> {
}
catch (Exception e) {
Log.Warning($"Could not load global config: {e} Generating default config.");
return WriteDefaultConfig(null, false, out modifiedTime);
return WriteDefaultConfig(null, out modifiedTime);
}
}

Expand All @@ -214,17 +220,17 @@ public class GlobalConfig : GenericObservable<GlobalConfig> {
$"Error occurred while saving backup config to '{filename}': {e.ToString()}");
}

Reset(conf);
Reset(oldConfig: conf);
} else {
Instance = conf;
ModifiedTime = WriteConfig(Instance);
}
}

public static void Reset(GlobalConfig oldConfig, bool resetAll = false) {
public static void Reset(GlobalConfig oldConfig) {
Log.Info($"Resetting global config.");
DateTime modifiedTime;
Instance = WriteDefaultConfig(oldConfig, resetAll, out modifiedTime);
Instance = WriteDefaultConfig(oldConfig, out modifiedTime);
ModifiedTime = modifiedTime;
}

Expand Down
14 changes: 12 additions & 2 deletions TLM/TLM/State/OptionsTabs/MaintenanceTab_ConfigGroup.cs
Expand Up @@ -13,10 +13,15 @@ public static class MaintenanceTab_ConfigGroup {
Handler = OnReloadGlobalConfigClicked,
};
public static ActionButton ResetGlobalConfig = new() {
Label = "Maintenance.Button:Reset global configuration",
Label = "Maintenance.Button:Reset all configuration",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

? This will be super confusing for users.
1, they will ask what happened to reset global config button
2. they will ash what does "all" even mean.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

global is also not accurate because we are resetting defaults for new game too.
@krzychu124 what do you suggest I do?

Copy link
Member

@krzychu124 krzychu124 Dec 5, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure why you decided to save defaults in global config?
Global settings are user regardless of state but the defaults would be used only in specific condition which suggest that is not the best place for that.
Maybe we just need something like TMPE_DefaultGameSettings.xml created automatically, and then the user could even change things by hand? This way we could easily handle multiple versions of settings, e.g.: with popup with list of configs to use, similar to MoveIt Import/Export modal (it could simply overwrite the main file with selected one). That seem to be more future proof and most likely easier to manage.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cool I create new file.

@krzychu124 but I still don't understand what should I call that button? should I split it into 2 buttons?

i mean its kind of global and currently there is no way for user to tell which settings are global except for trial and error (or read the xml files).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm, maybe we need and icon or something to mark in-game specific options? I can be even ❔ button with a tooltip informing that setting is in-game only

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

or maybe saved game options can have different text color in main menu.

@krzychu124 but I still don't understand what should I call that button? should I split it into 2 buttons?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Leave it like it was "Global configuration" has its own meaning in the mod, wiki etc., always refers to GlobalConfig configuration file

Handler = OnResetGlobalConfigClicked,
};

public static ActionButton SetAsDefaultForNewGames = new() {
Label = "Maintenance.Button:Set as default for new games",
Handler = OnSetAsDefaultForNewGamesClicked,
};

#if DEBUG
public static ActionButton DebugSwiches = new() {
Translator = key => key,
Expand All @@ -33,6 +38,7 @@ public static class MaintenanceTab_ConfigGroup {
#if DEBUG
DebugSwiches.AddUI(group);
#endif
SetAsDefaultForNewGames.AddUI(group);
}

private static string T(string key) => Translation.Options.Get(key);
Expand All @@ -41,6 +47,10 @@ private static void OnReloadGlobalConfigClicked()
=> GlobalConfig.Reload();

private static void OnResetGlobalConfigClicked()
=> GlobalConfig.Reset(oldConfig: null, resetAll: true);
=> GlobalConfig.Reset(oldConfig: null);
private static void OnSetAsDefaultForNewGamesClicked() {
GlobalConfig.Instance.SavedGameOptions = SavedGameOptions.Instance;
krzychu124 marked this conversation as resolved.
Show resolved Hide resolved
GlobalConfig.WriteConfig();
}
}
}
14 changes: 11 additions & 3 deletions TLM/TLM/State/SavedGameOptions.cs
Expand Up @@ -3,7 +3,7 @@ namespace TrafficManager.State;
using System;
using System.Text;
using TrafficManager.API.Traffic.Enums;
using TrafficManager.Custom.PathFinding;
using TrafficManager.Lifecycle;
using TrafficManager.Util;

public class SavedGameOptions {
Expand Down Expand Up @@ -112,10 +112,19 @@ public class SavedGameOptions {
public static bool Available { get; set; } = false;

public static SavedGameOptions Instance { get; private set; }

/// <summary>
/// ensures SavedGameOptions exists.
/// if not then it is set to global default or built-in default (if global default does not exist).
/// </summary>
public static void Ensure() {
Log.Info("SavedGameOptions.Ensure() called");
if (Instance == null) {
Create();
if (GlobalConfig.Instance?.SavedGameOptions != null) {
krzychu124 marked this conversation as resolved.
Show resolved Hide resolved
Instance = GlobalConfig.Instance.SavedGameOptions;
} else {
Create();
}
}
}
private static void Create() {
Expand All @@ -142,7 +151,6 @@ public class SavedGameOptions {
return null;
}
}

public static bool Deserialzie(byte[] data) {
try {
if (!data.IsNullOrEmpty()) {
Expand Down
15 changes: 4 additions & 11 deletions TLM/TLM/UI/Helpers/CheckboxOption.cs
Expand Up @@ -112,22 +112,15 @@ public CheckboxOption(string fieldName, Scope scope = Scope.Savegame)
protected override void UpdateTooltip() {
if (!HasUI) return;

_ui.tooltip = IsInScope
? string.IsNullOrEmpty(_tooltip)
? string.Empty // avoid invalidating UI if already no tooltip
: Translate(_tooltip)
: Translate(INGAME_ONLY_SETTING);
_ui.tooltip = Tooltip;
}

protected override void UpdateReadOnly() {
if (!HasUI) return;
Log._Debug($"CheckboxOption.UpdateReadOnly() - `{FieldName}` is {(ReadOnly ? "read-only" : "writeable")}");

var readOnly = !IsInScope || _readOnly;

Log._Debug($"CheckboxOption.UpdateReadOnly() - `{FieldName}` is {(readOnly ? "read-only" : "writeable")}");

_ui.readOnly = readOnly;
_ui.opacity = readOnly ? 0.3f : 1f;
_ui.readOnly = ReadOnly;
_ui.opacity = ReadOnly ? 0.3f : 1f;
}

/* UI helper methods */
Expand Down
4 changes: 2 additions & 2 deletions TLM/TLM/UI/Helpers/DLCRestrictedCheckboxOption.cs
Expand Up @@ -15,7 +15,7 @@ public class DLCRestrictedCheckboxOption : CheckboxOption {
SteamHelper.DLC requiredDLC,
Scope scope = Scope.Savegame) : base(fieldName, scope) {
_requiredDLC = requiredDLC;
_readOnly = !SteamHelper.IsDLCOwned(_requiredDLC);
ReadOnly = !SteamHelper.IsDLCOwned(_requiredDLC);
}

public override CheckboxOption AddUI(UIHelperBase container) {
Expand All @@ -36,7 +36,7 @@ public class DLCRestrictedCheckboxOption : CheckboxOption {
innerPanel.autoFitChildrenVertically = true;
innerPanel.autoLayout = true;

if (_readOnly) {
if (ReadOnly) {
icon.tooltip = Locale.Get("CONTENT_REQUIRED", _requiredDLC.ToString());
_ui.tooltip = Translate("Checkbox:DLC is required to change this option and see effects in game");
}
Expand Down
21 changes: 7 additions & 14 deletions TLM/TLM/UI/Helpers/DropDownOption.cs
Expand Up @@ -94,25 +94,18 @@ public DropDownOption(string fieldName, Scope scope = Scope.Savegame)
}

protected override void UpdateTooltip() {
if (!HasUI) return;

//UIDropDown parent(UIPanel) handles tooltip
_ui.parent.tooltip = IsInScope
? $"{_tooltip}"
: Translate(INGAME_ONLY_SETTING);
if (HasUI) {
_ui.parent.tooltip = Tooltip;
}
}

protected override void UpdateReadOnly() {
if (!HasUI) return;
Log._Debug($"DropDownOption.UpdateReadOnly() - `{FieldName}` is {(ReadOnly ? "read-only" : "writeable")}");

var readOnly = !IsInScope || _readOnly;

Log._Debug($"DropDownOption.UpdateReadOnly() - `{FieldName}` is {(readOnly ? "read-only" : "writeable")}");

_ui.isInteractive = !readOnly;
_ui.opacity = readOnly ? 0.3f : 1f;
// parent is UIPanel containing text label and dropdown
_dropdownLabel.opacity = readOnly ? 0.3f : 1f;
_ui.isInteractive = !ReadOnly;
_ui.opacity = ReadOnly ? 0.3f : 1f;
_dropdownLabel.opacity = ReadOnly ? 0.3f : 1f;
}
}
}
23 changes: 5 additions & 18 deletions TLM/TLM/UI/Helpers/SerializableUIOptionBase.cs
Expand Up @@ -39,8 +39,6 @@ public abstract class SerializableUIOptionBase<TVal, TUI, TComponent> : ILegacyS
/// </summary>
public ValidatorDelegate Validator { get; set; }

protected Scope _scope;

[CanBeNull]
private FieldInfo _fieldInfo;

Expand All @@ -52,7 +50,6 @@ public abstract class SerializableUIOptionBase<TVal, TUI, TComponent> : ILegacyS
public SerializableUIOptionBase(string fieldName, Scope scope) {

_fieldName = fieldName;
_scope = scope;
if (scope.IsFlagSet(Scope.Savegame)) {
_fieldInfo = typeof(SavedGameOptions).GetField(fieldName);

Expand Down Expand Up @@ -98,16 +95,6 @@ public abstract class SerializableUIOptionBase<TVal, TUI, TComponent> : ILegacyS

public string FieldName => _fieldInfo?.Name ?? _fieldName;

/// <summary>Returns <c>true</c> if setting can persist in current <see cref="_scope"/>.</summary>
/// <remarks>
/// When <c>false</c>, UI component should be <see cref="_readOnly"/>
/// and <see cref="_tooltip"/> should be set to <see cref="INGAME_ONLY_SETTING"/>.
/// </remarks>
protected bool IsInScope =>
_scope.IsFlagSet(Scope.Global) ||
(_scope.IsFlagSet(Scope.Savegame) && TMPELifecycle.AppMode != null) ||
_scope == Scope.None;

public static implicit operator TVal(SerializableUIOptionBase<TVal, TUI, TComponent> a) => a.Value;

public void DefaultOnValueChanged(TVal newVal) {
Expand All @@ -126,10 +113,10 @@ public abstract class SerializableUIOptionBase<TVal, TUI, TComponent> : ILegacyS
public bool HasUI => _ui != null;
protected TUI _ui;

protected string _label;
protected string _tooltip;
private string _label;
private string _tooltip;

protected bool _readOnly;
private bool _readOnly;

private TranslatorDelegate _translator;
public delegate string TranslatorDelegate(string key);
Expand Down Expand Up @@ -161,7 +148,7 @@ public abstract class SerializableUIOptionBase<TVal, TUI, TComponent> : ILegacyS
}

public string Tooltip {
get => _tooltip;
get => _tooltip ?? string.Empty;
set {
_tooltip = value;
UpdateTooltip();
Expand All @@ -171,7 +158,7 @@ public abstract class SerializableUIOptionBase<TVal, TUI, TComponent> : ILegacyS
public bool ReadOnly {
get => _readOnly;
set {
_readOnly = !IsInScope || value;
_readOnly = value;
UpdateReadOnly();
}
}
Expand Down
16 changes: 6 additions & 10 deletions TLM/TLM/UI/Helpers/SliderOption.cs
Expand Up @@ -110,7 +110,7 @@ public byte FloatToByte(float val)
protected override void UpdateLabel() {
if (!HasUI) return;

string tooltip = IsInScope ? $"{Value}{_tooltip}" : Translate(INGAME_ONLY_SETTING);
string tooltip = $"{Value}{Tooltip}";
string label = Translate(Label);
_sliderLabel.text = label + ": " + tooltip;
}
Expand All @@ -119,16 +119,12 @@ public byte FloatToByte(float val)

protected override void UpdateReadOnly() {
if (!HasUI) return;
Log._Debug($"SliderOption.UpdateReadOnly() - `{FieldName}` is {(ReadOnly ? "read-only" : "writeable")}");

var readOnly = !IsInScope || _readOnly;

Log._Debug($"SliderOption.UpdateReadOnly() - `{FieldName}` is {(readOnly ? "read-only" : "writeable")}");

_ui.isInteractive = !readOnly;
_ui.thumbObject.isInteractive = !readOnly;
_ui.thumbObject.opacity = readOnly ? 0.3f : 1f;
// parent is UIPanel containing text label and slider
_sliderLabel.opacity = readOnly ? 0.3f : 1f;
_ui.isInteractive = !ReadOnly;
_ui.thumbObject.isInteractive = !ReadOnly;
_ui.thumbObject.opacity = ReadOnly ? 0.3f : 1f;
_sliderLabel.opacity = ReadOnly ? 0.3f : 1f;
}
}
}
18 changes: 6 additions & 12 deletions TLM/TLM/UI/Helpers/TriStateCheckboxOption.cs
Expand Up @@ -101,24 +101,18 @@ public TriStateCheckboxOption(string fieldName, Scope scope = Scope.Savegame)
}

protected override void UpdateTooltip() {
if (!HasUI) return;

_ui.tooltip = IsInScope
? string.IsNullOrEmpty(_tooltip)
? string.Empty // avoid invalidating UI if already no tooltip
: Translate(_tooltip)
: Translate(INGAME_ONLY_SETTING);
if (HasUI) {
_ui.tooltip = Tooltip;
}
}

protected override void UpdateReadOnly() {
if (!HasUI) return;

var readOnly = !IsInScope || _readOnly;

Log._Debug($"TriStateCheckboxOption.UpdateReadOnly() - `{FieldName}` is {(readOnly ? "read-only" : "writeable")}");
Log._Debug($"TriStateCheckboxOption.UpdateReadOnly() - `{FieldName}` is {(ReadOnly ? "read-only" : "writeable")}");

_ui.readOnly = readOnly;
_ui.opacity = readOnly ? 0.3f : 1f;
_ui.readOnly = ReadOnly;
_ui.opacity = ReadOnly ? 0.3f : 1f;
}

/* UI helper methods */
Expand Down