From c691596de197ce3feec1217643b09783010fc415 Mon Sep 17 00:00:00 2001 From: Andrew Opalach Date: Tue, 16 Jun 2026 15:08:46 -0400 Subject: Optimize transitions, fix crash on new character Signed-off-by: Andrew Opalach --- Config.cs | 168 +++++++++++++++++++++++-------- Plugin.cs | 339 +++++++++++++++++++++++++++++++++++++++++++------------------- 2 files changed, 363 insertions(+), 144 deletions(-) diff --git a/Config.cs b/Config.cs index 2e43817..55441f2 100755 --- a/Config.cs +++ b/Config.cs @@ -3,89 +3,178 @@ using SharpPluginLoader.Core; namespace WorldTuningTool { + public enum StageExt : uint + { + Global = 0, + InfinityOfNothingHandler = 100, + AncientForest = 101, + WildspireWaste = 102, + CoralHighlands = 103, + RottenVale = 104, + ElderRecess = 105, + GreatRavine = 106, + GreatRavineStory = 107, + HoarfrostReach = 108, + GuidingLands = 109, + InfinityOfNothing = 200, + SpecialArena = 201, + ChallengeArena = 202, + Astera = 301, + AsteraHub = 302, + ResearchBase = 303, + Seliana = 305, + SelianaHub = 306, + Opening = 401, + Everstream = 403, + ConfluenceOfFates = 405, + AncientForestOpening = 406, + CharacterCreation = 407, + DebugMap = 408, + ElDorado = 409, + SelianaSupplyCache = 411, + OriginIsleNergigante = 412, + OriginIsleSharaIshvalda = 413, + SecludedValley = 415, + AlatreonStage = 416, + CastleSchrade = 417, + LivingQuarters = 501, + PrivateQuarters = 502, + PrivateSuite = 503, + TrainingCamp = 504, + ChamberOfFive = 505, + SelianaRoom = 506 + } + internal class Config : IConfig { public String Name => "WorldTuningTool"; - public String Version => "0.9"; + public String Version => "0.9.3"; - public static string StageToString(Stage stage) + public static string StageToString(StageExt stage) { switch (stage) { - case Stage.InfinityOfNothingHandler: + case StageExt.Global: return "Global"; - case Stage.AncientForest: + case StageExt.InfinityOfNothingHandler: + return "Infinity Of Nothing Handler"; + case StageExt.AncientForest: return "Ancient Forest"; - case Stage.WildspireWaste: + case StageExt.WildspireWaste: return "Wildspire Waste"; - case Stage.CoralHighlands: + case StageExt.CoralHighlands: return "Coral Highlands"; - case Stage.RottenVale: + case StageExt.RottenVale: return "Rotten Vale"; - case Stage.ElderRecess: + case StageExt.ElderRecess: return "Elder Recess"; - case Stage.GreatRavine: + case StageExt.GreatRavine: return "Great Ravine"; - case Stage.GreatRavineStory: + case StageExt.GreatRavineStory: return "Great Ravine Story"; - case Stage.HoarfrostReach: + case StageExt.HoarfrostReach: return "Hoarfrost Reach"; - case Stage.GuidingLands: + case StageExt.GuidingLands: return "Guiding Lands"; - case Stage.InfinityOfNothing: + case StageExt.InfinityOfNothing: return "Infinity Of Nothing"; - case Stage.SpecialArena: + case StageExt.SpecialArena: return "Special Arena"; - case Stage.ChallengeArena: + case StageExt.ChallengeArena: return "Challenge Arena"; - case Stage.Astera: + case StageExt.Astera: return "Astera"; - case Stage.AsteraHub: + case StageExt.AsteraHub: return "Astera Hub"; - case Stage.ResearchBase: + case StageExt.ResearchBase: return "Research Base"; - case Stage.Seliana: + case StageExt.Seliana: return "Seliana"; - case Stage.SelianaHub: + case StageExt.SelianaHub: return "Seliana Hub"; - case Stage.Everstream: + case StageExt.Opening: + return "Opening"; + case StageExt.Everstream: return "Everstream"; - case Stage.ConfluenceOfFates: + case StageExt.ConfluenceOfFates: return "Confluence Of Fates"; - case Stage.CharacterCreation: + case StageExt.AncientForestOpening: + return "Ancient Forest (Opening)"; + case StageExt.CharacterCreation: return "Character Creation"; - case Stage.DebugMap: + case StageExt.DebugMap: return "Debug Map"; - case Stage.ElDorado: + case StageExt.ElDorado: return "El Dorado"; - case Stage.SelianaSupplyCache: + case StageExt.SelianaSupplyCache: return "Seliana Supply Cache"; - case Stage.OriginIsleNergigante: + case StageExt.OriginIsleNergigante: return "Origin Isle Nergigante"; - case Stage.OriginIsleSharaIshvalda: + case StageExt.OriginIsleSharaIshvalda: return "Origin Isle Shara Ishvalda"; - case Stage.SecludedValley: + case StageExt.SecludedValley: return "Secluded Valley"; - case Stage.AlatreonStage: + case StageExt.AlatreonStage: return "Alatreon Stage"; - case Stage.CastleSchrade: + case StageExt.CastleSchrade: return "Castle Schrade"; - case Stage.LivingQuarters: + case StageExt.LivingQuarters: return "Living Quarters"; - case Stage.PrivateQuarters: + case StageExt.PrivateQuarters: return "Private Quarters"; - case Stage.PrivateSuite: + case StageExt.PrivateSuite: return "Private Suite"; - case Stage.TrainingCamp: + case StageExt.TrainingCamp: return "Training Camp"; - case Stage.ChamberOfFive: + case StageExt.ChamberOfFive: return "Chamber Of Five"; - case Stage.SelianaRoom: + case StageExt.SelianaRoom: return "Seliana Room"; } - return "Global (null)"; + return $"(Error: {stage})"; } + public static List OrderedStages = new List() + { + StageExt.Astera, + StageExt.AsteraHub, + StageExt.ResearchBase, + StageExt.Seliana, + StageExt.SelianaHub, + StageExt.LivingQuarters, + StageExt.PrivateQuarters, + StageExt.PrivateSuite, + StageExt.SelianaRoom, + StageExt.TrainingCamp, + StageExt.AncientForest, + StageExt.WildspireWaste, + StageExt.CoralHighlands, + StageExt.RottenVale, + StageExt.ElderRecess, + StageExt.GreatRavine, + StageExt.GreatRavineStory, + StageExt.HoarfrostReach, + StageExt.GuidingLands, + StageExt.SpecialArena, + StageExt.ChallengeArena, + StageExt.Everstream, + StageExt.ConfluenceOfFates, + StageExt.ElDorado, + StageExt.SelianaSupplyCache, + StageExt.OriginIsleNergigante, + StageExt.OriginIsleSharaIshvalda, + StageExt.SecludedValley, + StageExt.AlatreonStage, + StageExt.CastleSchrade, + StageExt.ChamberOfFive, + StageExt.Opening, + StageExt.AncientForestOpening, + StageExt.CharacterCreation, + StageExt.InfinityOfNothing, + StageExt.InfinityOfNothingHandler, + StageExt.DebugMap + }; + public struct PatchConfig { public bool FullResolutionVolumeBlur { get; set; } = false; @@ -98,7 +187,8 @@ namespace WorldTuningTool public PatchConfig Patches { get; set; } = new PatchConfig(); - public Dictionary> Overrides { get; set; } = new Dictionary>(); + public Dictionary> Overrides { get; set; } = new Dictionary>(); public Dictionary> Presets { get; set; } = new Dictionary>(); + public string SelectedPreset { get; set; } = ""; } } diff --git a/Plugin.cs b/Plugin.cs index 47dce7e..93119c3 100755 --- a/Plugin.cs +++ b/Plugin.cs @@ -1,6 +1,7 @@ //#define ENABLE_ASSERTS //#define OVERSIZED_SHADOW_MAP //#define SHADER_FEATURES +//#define RESOURCE_ADJUSTMENT using System.Numerics; using System.Globalization; @@ -13,13 +14,14 @@ using SharpPluginLoader.Core; #if SHADER_FEATURES using SharpPluginLoader.Core.Rendering; #endif -//using SharpPluginLoader.Core.Resources; +#if RESOURCE_ADJUSTMENT +using SharpPluginLoader.Core.Resources; +#endif using SharpPluginLoader.Core.Configuration; using SharpPluginLoader.Core.Memory; using SharpPluginLoader.Core.Entities; // @TODO: -// - Hair clipping while looking down. // - Optimized update logic. // - Only update non-override values when ui is shown. // - Map sky params. @@ -37,6 +39,7 @@ using SharpPluginLoader.Core.Entities; // - Hotload nukes config? // // Known issues to think about: +// - Hair clipping while looking down. // - Volume rendering can look really bad with multiple overlapped sources(?) (Guding lands vines). // - Screen space reflections often look bad. // - Facial contact shadows incorrectly move based on camera position. @@ -133,23 +136,31 @@ namespace WorldTuningTool static void saveConfig() { ConfigManager.SaveConfig(Instance!); + selectedOrderChanged = false; + presetOrderChanged = false; } private const float defaultParamWidth = 0.215f; private static bool ignoreMinMax = false; - private const Stage globalStage = Stage.InfinityOfNothingHandler; - private static Stage currentStage => Area.CurrentStage; - private static Stage selectedStage = globalStage; - private static Stage previousStage = selectedStage; - + private const StageExt globalStage = StageExt.Global; + private static StageExt currentStage => (StageExt)Area.CurrentStage; private static List? maybeGetStageOverrides(Config config) { - return (currentStage != 0) ? config.Overrides[currentStage] : null; + if (!config.Overrides.ContainsKey(currentStage)) + { + return null; + } + return (currentStage != StageExt.Global) ? config.Overrides[currentStage] : null; } + private static StageExt selectedStage = globalStage; + private static StageExt previousStage = selectedStage; + private static bool selectedOrderChanged = false; + private static string selectedPreset = ""; + private static bool presetOrderChanged = false; private static bool renamingPreset = false; private static string typedPresetName = ""; @@ -236,6 +247,7 @@ namespace WorldTuningTool protected float stepf, minf, maxf; protected int step, min, max; + private bool pendingWrite = false; private Vector4 valueV = default; private int valueInt = 0; private Vector4 oValueV; // Original value. @@ -287,8 +299,25 @@ namespace WorldTuningTool return mask; } + public void Resolve() + { + Assert(!InTransition); + if (pendingWrite) + { + pendingWrite = false; + maybeWriteCurrentValue(); + } + } + private void maybeWriteCurrentValue() { + if (InTransition) + { + pendingWrite = true; + DirtyParams.Add(this); + return; + } + Assert(!pendingWrite); switch (Type) { case ParameterType.PATCH_FLOAT: @@ -752,8 +781,10 @@ namespace WorldTuningTool public void Draw(ref Vector4 v4, ref int i1, float width, bool assumeOverride) { ImGui.PushID(Name); + if (NoOverride) { + // Dependent on overall ImGui style. ImGui.SetCursorPos(ImGui.GetCursorPos() + new Vector2(40.0f, 0.0f)); } else if (!assumeOverride) @@ -794,6 +825,7 @@ namespace WorldTuningTool } ImGui.SameLine(); } + if (!overrideValue) { ImGui.PushItemFlag(ImGuiItemFlags.Disabled, true); @@ -806,7 +838,7 @@ namespace WorldTuningTool { ImGui.PopItemFlag(); } - Config config = getConfig(); + bool showButtons = !assumeOverride && overrideValue && !pendingUpdate; if (showButtons) { @@ -836,13 +868,12 @@ namespace WorldTuningTool bValue = false; } } + + Config config = getConfig(); List selectedOverrides = config.Overrides[selectedStage]; List? stageOverrides = maybeGetStageOverrides(config); + // Deciding when to set globalOverrides copies the logic in OnImGuiRender(). List? globalOverrides = null; - if (selectedStage != globalStage) - { - globalOverrides = config.Overrides[globalStage]; - } if (selectedPreset != "") { List presetOverrides = config.Presets[selectedPreset]; @@ -853,19 +884,20 @@ namespace WorldTuningTool { // Create override before unsetting global. Override ov = new Override(this, v4, i1); + globalOverrides = config.Overrides[globalStage]; bool superseded = overridesContainsParam(externalOverrides.Values, this); if (!superseded) { + BeginTransition(); if (!(stageOverrides != null && unsetIfOverridesContainsParam(stageOverrides, this))) { - if (globalOverrides != null) - { - unsetIfOverridesContainsParam(globalOverrides, this); - } + unsetIfOverridesContainsParam(globalOverrides, this); } ov.Set(); + EndTransition(); } presetOverrides.Add(ov); + presetOrderChanged = true; } if (ImGui.BeginItemTooltip()) { @@ -881,16 +913,23 @@ namespace WorldTuningTool { // Create override before unsetting global. Override ov = new Override(this, v4, i1); + if (selectedStage != globalStage) + { + globalOverrides = config.Overrides[globalStage]; + } bool superseded = selectedOverrideSuperseded(config, globalOverrides, stageOverrides, this); if (!superseded) { + BeginTransition(); if (globalOverrides != null) { unsetIfOverridesContainsParam(globalOverrides, this); } ov.Set(); + EndTransition(); } selectedOverrides.Add(ov); + selectedOrderChanged = true; } if (ImGui.BeginItemTooltip()) { @@ -898,9 +937,11 @@ namespace WorldTuningTool ImGui.EndTooltip(); } } + ImGui.SameLine(); DrawReferenceValue("Original", oValueV, oValueInt); } + ImGui.PopID(); } } @@ -1133,6 +1174,7 @@ namespace WorldTuningTool bool isSelected = Param == iterParam; if (ImGui.Selectable(iterParam.Name, isSelected)) { + BeginTransition(); bool wasSet = isSet; if (wasSet) { @@ -1179,6 +1221,7 @@ namespace WorldTuningTool Set(); } } + EndTransition(); } if (isSelected) ImGui.SetItemDefaultFocus(); } @@ -1255,6 +1298,24 @@ namespace WorldTuningTool private delegate void OnAreaChange(nint unknownPtr); private Hook? onAreaChange; + private static bool InTransition = false; + private static List DirtyParams = new List(); + private static void BeginTransition() + { + Assert(!InTransition && DirtyParams.Count == 0); + InTransition = true; + } + private static void EndTransition() + { + Assert(InTransition); + InTransition = false; + foreach (Parameter param in DirtyParams) + { + param.Resolve(); + } + DirtyParams.Clear(); + } + private static MtObject? sMhScene = null; private static Parameter hqMode = newParameter("HQ Mode", 0xE9A3, ParameterType.BOOL); @@ -1840,6 +1901,7 @@ namespace WorldTuningTool { Override ov = new Override(param, v4, i1); Config config = getConfig(); + BeginTransition(); if (!(selectedPreset != "" && unsetIfOverridesContainsParam(config.Presets[selectedPreset], param))) { List? stageOverrides = maybeGetStageOverrides(config); @@ -1849,6 +1911,7 @@ namespace WorldTuningTool } } ov.Set(); + EndTransition(); externalId++; externalOverrides.Add(externalId, ov); return externalId; @@ -1862,6 +1925,7 @@ namespace WorldTuningTool if (externalOverrides.ContainsKey(id)) { Override ovE = externalOverrides[id]; + BeginTransition(); ovE.Unset(); Config config = getConfig(); if (!(selectedPreset != "" && setIfOverridesContainsParam(config.Presets[selectedPreset], ovE.Param!))) @@ -1872,6 +1936,7 @@ namespace WorldTuningTool setIfOverridesContainsParam(config.Overrides[globalStage], ovE.Param!); } } + EndTransition(); externalOverrides.Remove(id); } } @@ -1886,6 +1951,13 @@ namespace WorldTuningTool Assert(Array.FindAll(allParameters, (p => p.Name == param.Name)).Length == 1); } + // Assert OrderedStages covers all values. + foreach (StageExt stage in Enum.GetValues(typeof(StageExt))) + { + if (stage == StageExt.Global) continue; + Assert(Config.OrderedStages.Contains(stage)); + } + onAreaChange = Hook.Create(0x141AC27D0, OnAreaChangeHook); // nint // Needed for at least "Broad Area Shadow Dir". Otherwise it will flicker during an update on center change. @@ -2121,7 +2193,11 @@ namespace WorldTuningTool sMhScene = SingletonManager.GetSingleton("sMhScene")!; sLightProbes = SingletonManager.GetSingleton("sLightProbes")!; Config config = getConfig(); - foreach (Stage area in Enum.GetValues(typeof(Stage))) + if (!config.Overrides.ContainsKey(globalStage)) + { + config.Overrides.Add(globalStage, new List()); + } + foreach (StageExt area in Config.OrderedStages) { if (!config.Overrides.ContainsKey(area)) { @@ -2132,13 +2208,21 @@ namespace WorldTuningTool { ovG.Set(); } + selectedPreset = config.SelectedPreset; + if (selectedPreset != "") + { + List globalOverrides = config.Overrides[globalStage]; + List? stageOverrides = maybeGetStageOverrides(config); + HandlePresetChange("", globalOverrides, stageOverrides); + } saveConfig(); } - /* It's hard to test, but I'm pretty sure just updating stepTime isn't enough for a higher rate to look right. + // It's hard to test, but I'm pretty sure just updating stepTime isn't enough for a higher rate to look right. // https://github.com/AsteriskAmpersand/CTC-MHW-Editor/blob/9ec6303042690478398801b1bb860a2d38298eee/structures/Ctc.py#L23 - private static bool adjustCtcParams = false; - private static float stepTimeFps = 60.0f; +#if RESOURCE_ADJUSTMENT + private bool adjustCtcParams = false; + private float stepTimeFps = 60.0f; public void OnResourceLoad(Resource? resource, MtDti dti, string path, LoadFlags flags) { if (adjustCtcParams && resource != null && resource.FileExtension == "ctc") @@ -2153,10 +2237,15 @@ namespace WorldTuningTool MemoryUtil.GetRef(resource.Instance + 0xC4) = 1.0f / stepTimeFps; } } - */ +#endif public void OnUpdate(float deltaTime) { + StageExt stage = currentStage; + if (stage == StageExt.Global && previousStage != StageExt.Global) + { + HandleAreaChange(stage); + } hqMode.Update(sMhScene!.Instance); foreach (Parameter param in lodParameters) { @@ -2613,35 +2702,77 @@ namespace WorldTuningTool } } - private void OnAreaChangeHook(nint unknownPtr) + private void HandlePresetChange(string prevPreset, List globalOverrides, List? stageOverrides) { - onAreaChange!.Original(unknownPtr); - Stage stage = currentStage; - if (stage == 0) stage = globalStage; - if (stage == previousStage) return; Config config = getConfig(); - List prevOverrides = config.Overrides[previousStage]; - previousStage = stage; - List? globalOverrides = null; - if (stage != globalStage) + BeginTransition(); + if (prevPreset != "") { - globalOverrides = config.Overrides[globalStage]; + List prevOverrides = config.Presets[prevPreset]; + foreach (Override ovR in prevOverrides) + { + bool superseded = ovR.Param != null && overridesContainsParam(externalOverrides.Values, ovR.Param); + if (!superseded) + { + ovR.Unset(); + if (ovR.Param != null) + { + if (!(stageOverrides != null && setIfOverridesContainsParam(stageOverrides, ovR.Param))) + { + setIfOverridesContainsParam(globalOverrides, ovR.Param); + } + } + } + } + } + if (selectedPreset != "") + { + List newOverrides = config.Presets[selectedPreset]; + foreach (Override ovN in newOverrides) + { + bool superseded = ovN.Param != null && overridesContainsParam(externalOverrides.Values, ovN.Param); + if (!superseded) + { + if (ovN.Param != null) + { + if (!(stageOverrides != null && unsetIfOverridesContainsParam(stageOverrides, ovN.Param))) + { + unsetIfOverridesContainsParam(globalOverrides, ovN.Param); + } + } + ovN.Set(); + } + } + } + EndTransition(); + } + + private void HandleAreaChange(StageExt stage) + { + Config config = getConfig(); + if (!config.Overrides.ContainsKey(stage)) + { + return; } - foreach (Override ovR in prevOverrides) + List prevOverrides = config.Overrides[previousStage]; + List globalOverrides = config.Overrides[globalStage]; + BeginTransition(); + if (previousStage != globalStage) { - // If previousStage was global, none of it's parameters could have been - // superseded by a non-global stage override. - bool superseded = stageOverrideSuperseded(config, ovR.Param); - if (!superseded) + foreach (Override ovR in prevOverrides) { - ovR.Unset(); - if (ovR.Param != null && globalOverrides != null) + bool superseded = stageOverrideSuperseded(config, ovR.Param); + if (!superseded) { - setIfOverridesContainsParam(globalOverrides, ovR.Param); + ovR.Unset(); + if (ovR.Param != null) + { + setIfOverridesContainsParam(globalOverrides, ovR.Param); + } } } } - if (globalOverrides != null) // Stage isn't global. + if (stage != globalStage) { List stageOverrides = config.Overrides[stage]; foreach (Override ovS in stageOverrides) @@ -2657,6 +2788,19 @@ namespace WorldTuningTool } } } + EndTransition(); + previousStage = stage; + } + + private void OnAreaChangeHook(nint unknownPtr) + { + onAreaChange!.Original(unknownPtr); + StageExt stage = currentStage; + if (stage == previousStage) + { + return; + } + HandleAreaChange(stage); } public void OnImGuiRender() @@ -2664,25 +2808,11 @@ namespace WorldTuningTool float width = ImGui.GetWindowWidth(); width /= width / 600.0f; - /* - if (ImGui.TextLink($"Current Stage: {Config.StageToString(currentStage)}")) - { - if (currentStage == 0) - { - selectedStage = globalStage; - } - else - { - selectedStage = currentStage; - } - } - */ ImGui.Text($"Current Stage: {Config.StageToString(currentStage)}"); - ImGui.PushItemWidth(width * 0.35f); if (ImGui.BeginCombo("##Stage", Config.StageToString(selectedStage), ImGuiComboFlags.HeightLarge)) { - foreach (Stage area in Enum.GetValues(typeof(Stage))) + foreach (StageExt area in Config.OrderedStages) { string name = Config.StageToString(area); bool isSelected = selectedStage == area; @@ -2695,23 +2825,27 @@ namespace WorldTuningTool ImGui.EndCombo(); } ImGui.SameLine(); + Config config = getConfig(); + bool invalidStage = !config.Overrides.ContainsKey(currentStage); + if (invalidStage) + { + ImGui.PushItemFlag(ImGuiItemFlags.Disabled, true); + ImGui.PushStyleVar(ImGuiStyleVar.Alpha, ImGui.GetStyle().Alpha * 0.5f); + } if (ImGui.Button("Current")) { - if (currentStage != 0) - { - selectedStage = currentStage; - } - else - { - selectedStage = globalStage; - } + selectedStage = currentStage; + } + if (invalidStage) + { + ImGui.PopStyleVar(); + ImGui.PopItemFlag(); } ImGui.SameLine(); if (ImGui.Button("Global")) { selectedStage = globalStage; } - Config config = getConfig(); List selectedOverrides = config.Overrides[selectedStage]; List? stageOverrides = maybeGetStageOverrides(config); List? globalOverrides = null; @@ -2722,11 +2856,12 @@ namespace WorldTuningTool if (ImGui.Button("Add override")) { Override ov = new Override(); - if (selectedStage == currentStage || selectedStage == globalStage) + if (selectedStage == currentStage) { ov.Set(); // Empty override never superseded. } selectedOverrides.Add(ov); + selectedOrderChanged = true; } ImGui.PopItemWidth(); for (int i = 0; i < selectedOverrides.Count; i++) @@ -2743,23 +2878,28 @@ namespace WorldTuningTool if (requestDown && i < selectedOverrides.Count - 1) { (selectedOverrides[i], selectedOverrides[i + 1]) = (selectedOverrides[i + 1], selectedOverrides[i]); + selectedOrderChanged = true; } ovS.Draw(selectedOverrides, null, globalOverrides, superseded, false, width); if (requestUp && i > 0) { (selectedOverrides[i], selectedOverrides[i - 1]) = (selectedOverrides[i - 1], selectedOverrides[i]); + selectedOrderChanged = true; } if (requestRemove) { if (!superseded) { + BeginTransition(); ovS.Unset(); if (ovS.Param != null && globalOverrides != null) { setIfOverridesContainsParam(globalOverrides, ovS.Param); } + EndTransition(); } selectedOverrides.RemoveAt(i); + selectedOrderChanged = true; i--; } ImGui.PopID(); @@ -2779,10 +2919,17 @@ namespace WorldTuningTool } saveConfig(); } + if (selectedOrderChanged) + { + ImGui.SameLine(); + ImGui.PushStyleVar(ImGuiStyleVar.Alpha, ImGui.GetStyle().Alpha * 0.5f); + ImGui.Text("(Not Saved)"); + ImGui.PopStyleVar(); + } ImGui.Separator(); - // Global overrides and presets could now be show at the same time. + // We now have to consider both global and stage overrides. globalOverrides = config.Overrides[globalStage]; ImGui.PushID("Preset"); @@ -2799,6 +2946,8 @@ namespace WorldTuningTool } config.Presets[presetName] = new List(); selectedPreset = presetName; + config.SelectedPreset = selectedPreset; + saveConfig(); } ImGui.SameLine(); if (renamingPreset) @@ -2825,44 +2974,9 @@ namespace WorldTuningTool } if (prevPreset != selectedPreset) { - if (prevPreset != "") - { - List prevOverrides = config.Presets[prevPreset]; - foreach (Override ovR in prevOverrides) - { - bool superseded = ovR.Param != null && overridesContainsParam(externalOverrides.Values, ovR.Param); - if (!superseded) - { - ovR.Unset(); - if (ovR.Param != null) - { - if (!(stageOverrides != null && setIfOverridesContainsParam(stageOverrides, ovR.Param))) - { - setIfOverridesContainsParam(globalOverrides, ovR.Param); - } - } - } - } - } - if (selectedPreset != "") - { - List newOverrides = config.Presets[selectedPreset]; - foreach (Override ovN in newOverrides) - { - bool superseded = ovN.Param != null && overridesContainsParam(externalOverrides.Values, ovN.Param); - if (!superseded) - { - if (ovN.Param != null) - { - if (!(stageOverrides != null && unsetIfOverridesContainsParam(stageOverrides, ovN.Param))) - { - unsetIfOverridesContainsParam(globalOverrides, ovN.Param); - } - } - ovN.Set(); - } - } - } + HandlePresetChange(prevPreset, globalOverrides, stageOverrides); + config.SelectedPreset = selectedPreset; + saveConfig(); } if (renamingPreset) { @@ -2898,6 +3012,8 @@ namespace WorldTuningTool config.Presets.Remove(selectedPreset); config.Presets[presetName] = tmpOverrides; selectedPreset = presetName; + config.SelectedPreset = selectedPreset; + saveConfig(); } renamingPreset = false; } @@ -2919,6 +3035,7 @@ namespace WorldTuningTool Override ov = new Override(); ov.Set(); // Empty override never superseded. presetOverrides.Add(ov); + presetOrderChanged = true; } for (int i = 0; i < presetOverrides.Count; i++) { @@ -2934,16 +3051,19 @@ namespace WorldTuningTool if (requestDown && i < presetOverrides.Count - 1) { (presetOverrides[i], presetOverrides[i + 1]) = (presetOverrides[i + 1], presetOverrides[i]); + presetOrderChanged = true; } ovP.Draw(presetOverrides, stageOverrides, globalOverrides, superseded, true, width); if (requestUp && i > 0) { (presetOverrides[i], presetOverrides[i - 1]) = (presetOverrides[i - 1], presetOverrides[i]); + presetOrderChanged = true; } if (requestRemove) { if (!superseded) { + BeginTransition(); ovP.Unset(); if (ovP.Param != null) { @@ -2952,8 +3072,10 @@ namespace WorldTuningTool setIfOverridesContainsParam(globalOverrides, ovP.Param); } } + EndTransition(); } presetOverrides.RemoveAt(i); + presetOrderChanged = true; i--; } ImGui.PopID(); @@ -2973,6 +3095,13 @@ namespace WorldTuningTool } saveConfig(); } + if (presetOrderChanged) + { + ImGui.SameLine(); + ImGui.PushStyleVar(ImGuiStyleVar.Alpha, ImGui.GetStyle().Alpha * 0.5f); + ImGui.Text("(Not Saved)"); + ImGui.PopStyleVar(); + } } ImGui.PopID(); -- cgit v1.2.3-101-g0448