From 3ff2dff147b24d9c64d92609f866a2fcd7b6b197 Mon Sep 17 00:00:00 2001 From: Andrew Opalach Date: Tue, 19 May 2026 19:30:13 -0400 Subject: Add preset function, improve restore button logic Signed-off-by: Andrew Opalach --- Plugin.cs | 882 ++++++++++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 605 insertions(+), 277 deletions(-) (limited to 'Plugin.cs') diff --git a/Plugin.cs b/Plugin.cs index 30d9a88..15ba88b 100755 --- a/Plugin.cs +++ b/Plugin.cs @@ -1,12 +1,11 @@ -//#define ENABLE_ASSERTS -//#define ADDR_ASSERTS -//#define SHADER_FEATURES +#define ENABLE_ASSERTS +#define SHADER_FEATURES using System.Numerics; -using System.Reflection; -using System.Diagnostics; -using System.Runtime.Loader; using System.Runtime.InteropServices; +#if ENABLE_ASSERTS +using System.Diagnostics; +#endif using ImGuiNET; using SharpPluginLoader.Core; @@ -16,23 +15,63 @@ using SharpPluginLoader.Core.Memory; using SharpPluginLoader.Core.Entities; // @TODO: +// - Remove all parameters deemed mostly useless and/or unsafe. +// - SPL Patches: +// - Dialoge fix. +// - No crash on empty config. +// - Style change +// - Optimized update logic. +// - Only update non-override values when ui is shown. +// - Tune parameter settings (step, min/max, format, etc). +// - PerFrame. +// - Create light hook. // - Inter-op. // - Lights. -// - float format. -// - Override presets. -// - Centeralize transition from global to stage. // - Try to understand shadow distance vs backforward distance vs bias. -// - Re-evaluate volume upsample shaders. -// - Guiding lands? // - Shadow distance retuning. // - Weird shadow area in Rotten Vale. +// - float format. // - Descriptions. +// +// Known issues to think about: +// - Volume rendering can look really bad with multiple sources(?) (Guding lands vines). +// - Screen space reflections often look bad. +// - Facial contact shadows incorrectly move based on camera position. namespace WorldTuningTool { - public unsafe class Plugin : IPlugin + public class Interop { - public string Name => "World Tuning Tool"; + public static string PluginName = "World Tuning Tool"; + private static dynamic? Instance = null; + + public bool InitFromLoadedInstance() + { + Instance = IPlugin.GetInstance(Plugin.PluginName); + return Instance != null; + } + + public virtual int AddOverride(string name, Vector4 v4, int i1) + { + if (Instance != null) + { + return Instance.AddOverride(name, v4, i1); + } + return 0; + } + + public virtual void RemoveOverride(int id) + { + if (Instance != null) + { + Instance.RemoveOverride(id); + } + } + } + + public unsafe class Plugin : Interop, IPlugin + { + public string Name => PluginName; public string Author => "Akon City Software"; private static void Assert(bool condition) @@ -84,11 +123,59 @@ namespace WorldTuningTool private const float defaultParamWidth = 0.215f; - private static Stage selectedStage = Stage.InfinityOfNothingHandler; + private const Stage globalStage = Stage.InfinityOfNothingHandler; + private static Stage currentStage => Area.CurrentStage; + private static Stage selectedStage = globalStage; private static Stage previousStage = selectedStage; - private static bool stageIsGlobal(Stage stage) + + private List? maybeGetStageOverrides(Config config) + { + return currentStage != 0 ? config.Overrides[currentStage] : null; + } + + private static string selectedPreset = ""; + private static bool renamingPreset = false; + private static string typedPresetName = ""; + + private static Dictionary externalOverrides = new Dictionary(); + private static int externalId = 0; + + private static bool overridesContainsParam(IEnumerable overrides, Parameter param) { - return stage == Stage.InfinityOfNothingHandler; + foreach (Override ov in overrides) + { + if (ov.Param == param) + { + return true; + } + } + return false; + } + + private static bool unsetIfOverridesContainsParam(IEnumerable overrides, Parameter param) + { + foreach (Override ov in overrides) + { + if (ov.Param == param) + { + ov.Unset(); + return true; + } + } + return false; + } + + private static bool setIfOverridesContainsParam(IEnumerable overrides, Parameter param) + { + foreach (Override ov in overrides) + { + if (ov.Param == param) + { + ov.Set(); + return true; + } + } + return false; } public abstract class Parameter @@ -263,18 +350,18 @@ namespace WorldTuningTool overrideForStage = false; } - public void OverrideValue(Vector4 v, int i) + public void OverrideValue(Vector4 v4, int i1) { if (queuedOverride) { - qValueV = v; - qValueInt = i; + qValueV = v4; + qValueInt = i1; queuedValue = true; } else { - valueV = v; - valueInt = i; + valueV = v4; + valueInt = i1; if (!PerFrame) { writeCurrentValue(); @@ -510,13 +597,11 @@ namespace WorldTuningTool { ImGui.SetNextItemWidth(width * defaultParamWidth); float f1 = v4.X; + // Ideally we want ImGuiInputTextFlags.EnterReturnsTrue behavior here. if (ImGui.DragFloat(label, ref f1, stepf, minf, maxf, "%.5f", ImGuiSliderFlags.NoRoundToFormat)) { - //if (ImGui.IsItemDeactivatedAfterEdit()) - //{ - v4.X = f1; - valueChanged = true; - //} + v4.X = f1; + valueChanged = true; } break; } @@ -557,6 +642,60 @@ namespace WorldTuningTool return valueChanged; } + public void DrawReferenceValue(string name, Vector4 v4, int i1) + { + ImGui.PushStyleVar(ImGuiStyleVar.Alpha, ImGui.GetStyle().Alpha * 0.7f); + switch (Type) + { + case ParameterType.BOOL: + { + ImGui.Text($"({name}: {i1 == 0x1})"); + break; + } + case ParameterType.BYTE: + { + ImGui.Text($"({name}: {i1})"); + break; + } + case ParameterType.FLAG: + { + ImGui.Text($"({name}: {i1 != 0})"); + break; + } + case ParameterType.INT: + case ParameterType.HEX: + case ParameterType.COLOR: + { + if (Type == ParameterType.INT) + { + ImGui.Text($"({name}: {i1})"); + } + else + { + ImGui.Text($"({name}: {i1:X})"); + } + break; + } + case ParameterType.FLOAT: + case ParameterType.PATCH_FLOAT: + { + ImGui.Text($"({name}: {v4.X:0.00000})"); + break; + } + case ParameterType.VECTOR3: + { + ImGui.Text($"({name}: {v4.X:0.0000}, {v4.Y:0.0000}, {v4.Z:0.0000})"); + break; + } + case ParameterType.VECTOR4: + { + ImGui.Text($"({name}: {v4.X:0.0000}, {v4.Y:0.0000}, {v4.Z:0.0000}, {v4.W:0.00000})"); + break; + } + } + ImGui.PopStyleVar(); + } + public void Draw(float width, bool assumeOverride = false) { Draw(ref valueV, ref valueInt, width, assumeOverride); @@ -588,11 +727,11 @@ namespace WorldTuningTool { if (overrideForStage) { - ImGui.Text("Set by Config/Preset"); + ImGui.Text("Set by an Override"); } else { - ImGui.Text("Override Value"); + ImGui.Text("Override"); } ImGui.EndTooltip(); } @@ -611,20 +750,30 @@ namespace WorldTuningTool { writeCurrentValue(); } - if (!assumeOverride && overrideValue && !overrideForStage) + Config config = getConfig(); + List selectedOverrides = config.Overrides[selectedStage]; + if (!assumeOverride && overrideValue && !overridesContainsParam(selectedOverrides, this)) { ImGui.SameLine(); if (ImGui.Button("▲")) { - Config config = getConfig(); - List stageOverrides = config.Overrides[selectedStage]; + // Create override before unsetting global. Override ov = new Override(this, v4, i1); - ov.Set(); - stageOverrides.Add(ov); + if (selectedStage != globalStage) + { + unsetIfOverridesContainsParam(config.Overrides[globalStage], this); + } + bool superseded = selectedPreset != "" && overridesContainsParam(config.Presets[selectedPreset], this); + superseded |= overridesContainsParam(externalOverrides.Values, this); + if (!superseded) + { + ov.Set(); + } + selectedOverrides.Add(ov); } if (ImGui.BeginItemTooltip()) { - ImGui.Text("Add to Selected Stage"); + ImGui.Text($"Add to {Config.StageToString(selectedStage)}"); ImGui.EndTooltip(); } } @@ -660,58 +809,7 @@ namespace WorldTuningTool } } ImGui.SameLine(); - ImGui.PushStyleVar(ImGuiStyleVar.Alpha, ImGui.GetStyle().Alpha * 0.7f); - switch (Type) - { - case ParameterType.BOOL: - { - ImGui.Text($"(Original: {oValueInt == 0x1})"); - break; - } - case ParameterType.BYTE: - { - ImGui.Text($"(Original: {oValueInt})"); - break; - } - case ParameterType.FLAG: - { - ImGui.Text($"(Original: {oValueInt != 0})"); - break; - } - case ParameterType.INT: - case ParameterType.HEX: - case ParameterType.COLOR: - { - if (Type == ParameterType.INT) - { - ImGui.Text($"(Original: {oValueInt})"); - } - else - { - ImGui.Text($"(Original: {oValueInt:X})"); - } - break; - } - case ParameterType.FLOAT: - case ParameterType.PATCH_FLOAT: - { - ImGui.Text($"(Original: {oValueV.X:0.00000})"); - break; - } - case ParameterType.VECTOR3: - { - ImGui.Text($"(Original: {oValueV.X:0.0000}, {oValueV.Y:0.0000}, {oValueV.Z:0.0000})"); - break; - } - case ParameterType.VECTOR4: - { - ImGui.Text($"(Original: {oValueV.X:0.0000}, {oValueV.Y:0.0000}, {oValueV.Z:0.0000}, {oValueV.W:0.00000})"); - break; - } - } - //ImGui.SameLine(); - //ImGui.Text($"(Address: {lastAddr:X})"); - ImGui.PopStyleVar(); + DrawReferenceValue("Original", oValueV, oValueInt); } if (!overrideValue) { @@ -730,6 +828,10 @@ namespace WorldTuningTool this.stepf = step != null ? Convert.ToSingle(step) : 0.01f; this.minf = Convert.ToSingle(min); this.maxf = Convert.ToSingle(max); + if (type == ParameterType.FLOAT && this.minf == 0.0f && this.maxf == 0.0f) + { + this.maxf = Single.MaxValue; + } } else if (typeof(T) == typeof(int) || typeof(T) == typeof(byte)) { @@ -746,42 +848,6 @@ namespace WorldTuningTool } } - private static bool overridesContainsParam(List overrides, Parameter param) - { - foreach (Override ov in overrides) - { - if (ov.Param == param) - { - return true; - } - } - return false; - } - - private static void unsetIfOverridesContainsParam(List overrides, Parameter param) - { - foreach (Override ov in overrides) - { - if (ov.Param == param) - { - ov.Unset(); - break; - } - } - } - - private static void setIfOverridesContainsParam(List overrides, Parameter param) - { - foreach (Override ov in overrides) - { - if (ov.Param == param) - { - ov.Set(); - break; - } - } - } - private static Parameter? getParameterByName(string name) { foreach (Parameter param in allParameters) @@ -873,6 +939,8 @@ namespace WorldTuningTool case ParameterType.VECTOR4: break; } + sValueV = valueV; + sValueInt = valueInt; } catch (FormatException) { @@ -885,6 +953,8 @@ namespace WorldTuningTool private Vector4 valueV = default; private int valueInt = 0; private bool isSet = false; + private Vector4 sValueV = default; + private int sValueInt = 0; public Override() { } @@ -893,6 +963,14 @@ namespace WorldTuningTool Param = param; valueV = v4; valueInt = i1; + sValueV = v4; + sValueInt = i1; + } + + public void Save() + { + sValueV = valueV; + sValueInt = valueInt; } public void Set() @@ -916,42 +994,57 @@ namespace WorldTuningTool } } - public void Draw(List? currentOverrides, List? globalOverrides, float width) + public void Draw(List? currentOverrides, List? stageOverrides, List? globalOverrides, bool superseded, float width) { - if (currentOverrides == null) + if (currentOverrides == null || superseded) { ImGui.PushItemFlag(ImGuiItemFlags.Disabled, true); } + if (superseded) // superseded == !isSet, superseded is more clear in the context of drawing. + { + Assert(!isSet); + ImGui.PushStyleVar(ImGuiStyleVar.Alpha, ImGui.GetStyle().Alpha * 0.5f); + } ImGui.PushItemWidth(width * 0.475f); if (ImGui.BeginCombo("##Parameters", Param != null ? Param.Name : "")) { if (currentOverrides != null) { - foreach (Parameter param in allParameters) + foreach (Parameter iterParam in allParameters) { - if (overridesContainsParam(currentOverrides, param)) - { - continue; - } - bool isSelected = Param == param; - if (ImGui.Selectable(param.Name, isSelected)) + if (overridesContainsParam(currentOverrides, iterParam)) continue; + bool isSelected = Param == iterParam; + if (ImGui.Selectable(iterParam.Name, isSelected)) { bool wasSet = isSet; if (wasSet) { Unset(); - if (globalOverrides != null) + if (Param != null) + { + if (!(stageOverrides != null && setIfOverridesContainsParam(stageOverrides, Param))) + { + if (globalOverrides != null) + { + setIfOverridesContainsParam(globalOverrides, Param); + } + } + } + if (!(stageOverrides != null && unsetIfOverridesContainsParam(stageOverrides, iterParam))) { - if (Param != null) + if (globalOverrides != null) { - setIfOverridesContainsParam(globalOverrides, Param); + unsetIfOverridesContainsParam(globalOverrides, iterParam); } - unsetIfOverridesContainsParam(globalOverrides, param); } } - Param = param; + Param = iterParam; (valueV, valueInt) = Param.GetValue(); - if (wasSet) Set(); + // If this override is superseded, expect this Combo to be disabled. + if (wasSet) + { + Set(); + } } if (isSelected) ImGui.SetItemDefaultFocus(); } @@ -959,25 +1052,53 @@ namespace WorldTuningTool ImGui.EndCombo(); } ImGui.PopItemWidth(); - if (currentOverrides == null) + if (superseded) + { + ImGui.PopStyleVar(); + } + if (currentOverrides == null || superseded) { ImGui.PopItemFlag(); } if (Param != null) { ImGui.SameLine(); - if (Param.DrawValue(ref valueV, ref valueInt, width, false) && isSet) + if (Param.DrawValue(ref valueV, ref valueInt, width, false) && !superseded) { Param.OverrideValue(valueV, valueInt); } - if (isSet && !Param.PendingUpdate() && (valueV, valueInt) != Param.GetValue()) + (Vector4 v4, int i1) = Param.GetValue(); + bool valueDiffers = (v4, i1) != (valueV, valueInt); + if ((valueV, valueInt) != (sValueV, sValueInt) || (valueDiffers && !Param.PendingUpdate() && !superseded)) + { + ImGui.SameLine(); + if (ImGui.Button("⇄")) + { + valueV = sValueV; + valueInt = sValueInt; + if (!superseded) + { + Param.OverrideValue(valueV, valueInt); + } + } + } + if (Param.PendingUpdate()) { ImGui.SameLine(); - if (ImGui.Button("Restore")) + ImGui.PushStyleVar(ImGuiStyleVar.Alpha, ImGui.GetStyle().Alpha * 0.7f); + ImGui.Text("(Pending)"); + ImGui.PopStyleVar(); + if (ImGui.BeginItemTooltip()) { - Param.OverrideValue(valueV, valueInt); + ImGui.Text("The object this parameter belongs to has no current object"); + ImGui.EndTooltip(); } } + else if (valueDiffers || superseded) + { + ImGui.SameLine(); + Param.DrawReferenceValue("Current", v4, i1); + } } } } @@ -1046,17 +1167,6 @@ namespace WorldTuningTool new Parameter("LOD Culling Length Bias", 0x224, ParameterType.FLOAT, false), new Parameter("LOD Culling Pixel Bias", 0x228, ParameterType.FLOAT, false), new Parameter("Is Calc LOD Bias Use Boundary", 0x218, ParameterType.BOOL, false), - /* - new Parameter("Debug View", 0x264, ParameterType.INT, false, 1), - new Parameter("Debug View Channel", 0x268, ParameterType.INT, false, 1), - new Parameter("Debug View Bg Alpha", 0x26C, ParameterType.FLOAT, false), - new Parameter("Debug View Fg Alpha", 0x270, ParameterType.FLOAT, false), - new Parameter("Debug Texture", 0x274, ParameterType.INT, false, 1), - new Parameter("Debug Sampler", 0x278, ParameterType.INT, false, 1), - new Parameter("Debug Cluster", 0x27C, ParameterType.INT, false, 1), - new Parameter("Debug Light Max Count", 0x280, ParameterType.INT, false, 1), - new Parameter("Wireframe", 0x284, ParameterType.BOOL, false), - */ new Parameter("Material Draw SS Normal", 0x5626, ParameterType.BOOL, false), new Parameter("Material Height Factor", 0x5628, ParameterType.FLOAT, false), new Parameter("Model Detail", 0x190, ParameterType.INT, false, 1), @@ -1086,7 +1196,6 @@ namespace WorldTuningTool new Parameter("Force Disable Capsule AO", 0xB503, ParameterType.BOOL, false), new Parameter("Capsule AO Distance Fall Coef", 0xE5B4, ParameterType.FLOAT, false), new Parameter("Capsule AO Light Channel Mask", 0xE5BC, ParameterType.INT, false), - //new Parameter("Capsule AO Null Parent Matrix", 0xE570, ParameterType.FLOAT, false), new Parameter("Capsule Light Dir XZY", 0xE548, ParameterType.VECTOR3, false), new Parameter("Capsule Light W Dir", 0xE560, ParameterType.FLOAT, false), new Parameter("Capsule Light Angle", 0xE5B0, ParameterType.FLOAT, false), @@ -1096,9 +1205,6 @@ namespace WorldTuningTool new Parameter("Broad Area Shadow Center", 0x5540, ParameterType.VECTOR3, false), new Parameter("Broad Area Shadow Range", 0x5560, ParameterType.VECTOR3, false), new Parameter("Broad Area Shadow Dir", 0x5550, ParameterType.VECTOR4, false), - //new Parameter("Broad Area Shadow Depth Bias", 0x5570, ParameterType.FLOAT, false, 0.00001f), - //new Parameter("Broad Area Shadow Sloped Depth Bias", 0x5574, ParameterType.FLOAT, false, 0.00001f), - //new Parameter("Broad Area Shadow Max Depth Bias", 0x5578, ParameterType.FLOAT, false, 0.00001f), new Parameter("Broad Area Shadow Max LOD Level", 0x5524, ParameterType.FLOAT, false), new Parameter("Broad Area Shadow Culling Size", 0x5528, ParameterType.FLOAT, false), new Parameter("Broad Area Shadow Precision", 0x5518, ParameterType.INT, false, 1, 0, 2), // Maybe 3? @@ -1158,7 +1264,6 @@ namespace WorldTuningTool new Parameter("Vignetting Offset", 0x1F8, ParameterType.FLOAT, true), new Parameter("Vignetting Pow", 0x1FC, ParameterType.FLOAT, true), new Parameter("Vignetting Color", 0x208, ParameterType.COLOR, true), - //new Parameter("Target Joint No", 0x240, ParameterType.INT, true, 1), }; private delegate nint CreateMotionBlurObject(); @@ -1202,27 +1307,13 @@ namespace WorldTuningTool private static MtObject? sLightProbes = null; private static Parameter[] lightProbesParameters = { - //new Parameter("Enable Neighbor Search", 0x40, ParameterType.BOOL, false), - //new Parameter("WF Count", 0x90, ParameterType.INT, false, 1), - //new Parameter("CU Mask", 0x94, ParameterType.HEX, false), new Parameter("Debug Mode", 0x98, ParameterType.INT, false, 1), - //new Parameter("Daytime State", 0x9C, ParameterType.INT, true, 1), - //new Parameter("Daytime Interpolation", 0xA0, ParameterType.FLOAT, false), - //new Parameter("Max Iter", 0xA4, ParameterType.INT, true, 1) }; private delegate nint CreateLightingObject(); private delegate nint DestroyLightingObject(nint lightingObjectInternal, int unknownInt); private Hook? createLightingObject; private Hook? destroyLightingObject; private nint lightingObject = 0x0; - /* - Compute Luminance (bool) +0x170 - Luminance Version (int) +0x168 - LUT Blend (bool) +0x1C8 - Vfx LUT Blend (bool) +0x1D0 - Input Color Linear to PQ (bool) +0x1A1 - Output Color PQ to Linear (bool) +0x1A0 - */ private static Parameter[] lightingParameters = { new Parameter("Tone Map Type", 0x16C, ParameterType.INT, false, 1, 1, 7), new Parameter("Shoulder Strength", 0x168, ParameterType.FLOAT, false), @@ -1233,7 +1324,7 @@ namespace WorldTuningTool new Parameter("White Point", 0x18C, ParameterType.FLOAT, false), new Parameter("Enable Color Grading", 0x1D8, ParameterType.BOOL, false), new Parameter("Dispersion", 0x19C, ParameterType.FLOAT, false), - new Parameter("Edge Sharpness", 0x198, ParameterType.FLOAT, false), + new Parameter("Edge Sharpness", 0x198, ParameterType.FLOAT, false, 0.00001f), new Parameter("Downsample Volume", 0x210, ParameterType.BOOL, false) }; @@ -1318,7 +1409,7 @@ namespace WorldTuningTool private Patch shadowRes1_3; private Patch shadowRes2; private Patch shadowRes3; - private Patch shadowRes4_Limit; + //private Patch shadowRes4_Limit; private void tripleShadowResEnable() { @@ -1328,7 +1419,6 @@ namespace WorldTuningTool shadowRes1_3.Enable(); shadowRes2.Enable(); shadowRes3.Enable(); - //shadowRes4_Limit.Enable(); } private void tripleShadowResDisable() @@ -1339,7 +1429,6 @@ namespace WorldTuningTool shadowRes1_3.Disable(); shadowRes2.Disable(); shadowRes3.Disable(); - //shadowRes4_Limit.Disable(); } private bool fullResVolumeBlur = false; @@ -1482,18 +1571,24 @@ namespace WorldTuningTool private delegate void UpdateLights(nint lightObject); private Hook? updateLights; - private Dictionary externalOverrides = new Dictionary(); - private int externalId = 0; - - public int AddOverride(string name, Vector4 v4, int i1) + public override int AddOverride(string name, Vector4 v4, int i1) { foreach (Parameter param in allParameters) { if (param.Name == name) { - externalId++; Override ov = new Override(param, v4, i1); + Config config = getConfig(); + if (!(selectedPreset != "" && unsetIfOverridesContainsParam(config.Presets[selectedPreset], param))) + { + List? stageOverrides = maybeGetStageOverrides(config); + if (!(stageOverrides != null && unsetIfOverridesContainsParam(stageOverrides, param))) + { + unsetIfOverridesContainsParam(config.Overrides[globalStage], param); + } + } ov.Set(); + externalId++; externalOverrides.Add(externalId, ov); return externalId; } @@ -1501,15 +1596,21 @@ namespace WorldTuningTool return 0; } - public void RemoveOverride(int id) + public override void RemoveOverride(int id) { if (externalOverrides.ContainsKey(id)) { - Config config = getConfig(); - List globalOverrides = config.Overrides[Stage.InfinityOfNothingHandler]; Override ovE = externalOverrides[id]; ovE.Unset(); - setIfOverridesContainsParam(globalOverrides, ovE.Param!); + Config config = getConfig(); + if (!(selectedPreset != "" && setIfOverridesContainsParam(config.Presets[selectedPreset], ovE.Param!))) + { + List? stageOverrides = maybeGetStageOverrides(config); + if (!(stageOverrides != null && setIfOverridesContainsParam(stageOverrides, ovE.Param!))) + { + setIfOverridesContainsParam(config.Overrides[globalStage], ovE.Param!); + } + } externalOverrides.Remove(id); } } @@ -1546,41 +1647,33 @@ namespace WorldTuningTool destroyLightingObject = Hook.Create(0x1424CE380, DestroyLightingObjectHook); // nint, int IntPtr addr = PatternScanner.FindFirst(Pattern.FromString("48 89 5C 24 10 48 89 74 24 18 48 89 7C 24 20 55 41 56 41 57 48 8B EC 48 83 EC 30 48 8B FA 48 8B D9 E8 AA B6 C1 FF 48 8B 47 10 48 8D 57 50")); -#if ADDR_ASSERTS Assert(addr == 0x141AB2260); // nint, nint -#endif updateShadowParams = Hook.Create(addr, UpdateShadowParamsHook); staticShadowParams = Hook.Create(0x1416D94F0, StaticShadowParamsHook); // nint, nint setShadowQuality = new NativeAction(0x14043FF80); addr = PatternScanner.FindFirst(Pattern.FromString("48 83 EC 28 F3 0F 10 0D ?? ?? ?? ?? 80 F9 04 75 2F 48 8B 0D ?? ?? ?? ?? E8 D3 8A E4 01 48 8B 0D ?? ?? ?? ?? 33 D2 E8 ?? ?? ?? ??")); -#if ADDR_ASSERTS Assert(addr == 0x14043FF80); Assert(MemoryUtil.Read(0x142E4FE5C) == 3.0f); -#endif shadowRes1_3x = new Patch(addr + 0x8, [0xD0, 0xFE, 0xA0, 0x02]); // 3.0. shadowRes1_1 = new Patch(addr + 0x65, [0x17]); // Always set "Value is not 1.0" flag. shadowRes1_2 = new Patch(addr + 0x68, [0x59]); // movss -> mulss. shadowRes1_3 = new Patch(addr + 0x77, [0x59]); // movss -> mulss. - // shadowRes2/3 control the detail of the infrequently updated fallback shadows. + // shadowRes2/3 control the detail of the infrequently updated fallback shadows (Broad Area). addr = PatternScanner.FindFirst(Pattern.FromString("83 FA FF 74 06 89 91 1C 55 00 00 8B 91 30 55 00 00 83 FA FF 7F 06 8B 91 1C 55 00 00 85 D2 74 4B 83 EA 01 74 3B 83 EA 01 74 2B 83 EA 01 74 1B 83 FA 01 74 0B C7 81 20 55 00 00 01 00 00 00 C3 C7 81 20 55 00 00 00 10 00 00")); -#if ADDR_ASSERTS Assert(addr == 0x142287A50); -#endif shadowRes2 = new Patch(addr + 0x3F, [ 0xC7, 0x81, 0x20, 0x55, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0xC3, 0xC7, 0x81, 0x20, 0x55, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0xC3, - 0xC7, 0x81, 0x20, 0x55, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0xC3, // High. - 0xC7, 0x81, 0x20, 0x55, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0xC3, // Mid. - 0xC7, 0x81, 0x20, 0x55, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0xC3 // Low. + 0xC7, 0x81, 0x20, 0x55, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0xC3, // High (8192x8192). + 0xC7, 0x81, 0x20, 0x55, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0xC3, // Mid (6144x6144). + 0xC7, 0x81, 0x20, 0x55, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0xC3 // Low (4096x4096). ]); addr = PatternScanner.FindFirst(Pattern.FromString("89 91 30 55 00 00 83 FA FF 7F 06 8B 91 1C 55 00 00 85 D2 74 4B 83 EA 01 74 3B 83 EA 01 74 2B 83 EA 01 74 1B 83 FA 01 74 0B C7 81 20 55 00 00 01 00 00 00 C3 C7 81 20 55 00 00 00 10 00 00")); -#if ADDR_ASSERTS Assert(addr == 0x142287AD0); -#endif shadowRes3 = new Patch(addr + 0x34, [ 0xC7, 0x81, 0x20, 0x55, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0xC3, 0xC7, 0x81, 0x20, 0x55, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0xC3, @@ -1590,15 +1683,15 @@ namespace WorldTuningTool ]); addr = PatternScanner.FindFirst(Pattern.FromString("89 91 00 55 00 00 83 FA 05 77 41 48 63 C2 4C 8D 05 ?? ?? ?? ?? 41 8B 94 80 84 8B 28 02 49 03 D0 FF E2 B8 00 08 00 00")); -#if ADDR_ASSERTS Assert(addr == 0x142288B00); -#endif // This value controls the shadow map texture resolution. 16384x16384 is likely the limit for many drivers // and any value higher would crash. Keeping this at the default value (unpatched) *should* work unless the // game does something unpredictable. At 3x Shadow Resolution + High, the shadow map will be 8448x8448. + /* Results in 16320x16320, not sure why not 16128. shadowRes4_Limit = new Patch(addr + 0x29, [ // N/64 = 255, fractional values closer to 256 not tested. 0xB8, 0x40, 0x15, 0x00, 0x00, 0xEB, 0x21 // This case is used for Low, Medium and High in-game. ]); + */ // The volume blur filter is created at a different place in the code and happens at a different // time (area change/createLightingObject() vs change of Volume Quality setting). It's also rendered @@ -1633,23 +1726,17 @@ namespace WorldTuningTool // Gameplay. addr = PatternScanner.FindFirst(Pattern.FromString("80 BB 34 EC 00 00 00 88 8B 31 EC 00 00 C6 83 30 EC 00 00 00 74 1C C6 83 34 EC 00 00 00 48 8B 0D 68 4B 4F 03 80 B9 58 02 00 00 00 75 05 E8 5A F5 01 00 48 8B CB E8 E2 05 00 00 83 BB DC EB 00 00 06 74 0A C7 83 DC EB 00 00 06 00 00 00")); -#if ADDR_ASSERTS Assert(addr == 0x141B1A0B4); -#endif defaultViewModeLODLimit = new Patch(addr + 0x40, [0x07, 0x74, 0x0A, 0xC7, 0x83, 0xDC, 0xEB, 0x00, 0x00, 0x07]); // In room. addr = PatternScanner.FindFirst(Pattern.FromString("8B 9F CC 00 00 00 81 FB F9 01 00 00 74 0C 8B CB E8 95 3F 65 01 83 F8 05 75 11 48 8B 0D 61 C8 F6 04 BA 02 00 00 00 E8 DF 2D 8C 01 48 8B 0D A0 C7 F6 04 8B D3")); -#if ADDR_ASSERTS Assert(addr == 0x140257AE6); -#endif defaultViewModeLODLimit_1 = new Patch(addr + 0x22, [0x07]); // Forging/Changing Equipment. addr = PatternScanner.FindFirst(Pattern.FromString("BA 02 00 00 00 E8 6E C0 80 00 48 8B 74 24 38 48 8B 57 28 48 8D 4F 30 E8 4C 79 B4 FE 48 8B 0D 0D FF A6 03 BA 04 00 00 00 E8 8B 64 3C 00 48 8B 05 D4 01 A7 03 80 B8 FD 46 01 00 00")); -#if ADDR_ASSERTS Assert(addr == 0x141754438); -#endif defaultViewModeLODLimit_2 = new Patch(addr + 0x24, [0x07]); // Unknown. @@ -1659,9 +1746,7 @@ namespace WorldTuningTool defaultViewModeLODLimit_4 = new Patch(new IntPtr(0x14128F1AC) + 0xF, [0x07]); addr = PatternScanner.FindFirst(Pattern.FromString("74 4D 33 C0 48 81 C1 00 02 00 00 F3 0F 10 11 0F 2F CA 72 0C FF C0 48 83 C1 04 83 F8 03 72 EC C3")); -#if ADDR_ASSERTS Assert(addr == 0x1426D89CA); -#endif addressHigherValueForFoliageSway = new Patch(addr + 0x7, [0x04]); // Found using mFrameSkipNum annotation from MHW-DTI-Dumps. @@ -1704,9 +1789,6 @@ namespace WorldTuningTool removeFromScene = new NativeAction(0x142228F10); updateLights = Hook.Create(0x141F88F30, UpdateLightsHook); - // Gui animation rate? - //new Patch(new IntPtr(0x142F15C90), BitConverter.GetBytes(60.0f)).Enable(); - return new PluginData(); } @@ -1761,8 +1843,7 @@ namespace WorldTuningTool config.Overrides.Add(area, new List()); } } - List globalOverrides = config.Overrides[Stage.InfinityOfNothingHandler]; - foreach (Override ovG in globalOverrides) + foreach (Override ovG in config.Overrides[globalStage]) { ovG.Set(); } @@ -1795,10 +1876,7 @@ namespace WorldTuningTool { foreach (Parameter param in fxaaParameters) { - if (!param.PerFrame) - { - param.Update(fxaaObject); - } + param.Update(fxaaObject); } } if (dofObject != 0x0) @@ -2104,29 +2182,56 @@ namespace WorldTuningTool staticShadowParams!.Original(shadowObjectStatic, shadowObjectInternal); } - private void OnAreaChangeHook(nint unknownPtr) + private void UpdateLightsHook(nint lightObject) { - onAreaChange!.Original(unknownPtr); - Stage stage = Area.CurrentStage; - if (stage == 0x0) + Light? ourLight = null; + for (int i = 0; i < ourLights.Count; i++) { - stage = Stage.InfinityOfNothingHandler; + if (lightObject == ourLights[i].Object) + { + ourLight = ourLights[i]; + break; + } + } + updateLights!.Original(lightObject); + if (ourLight != null) + { + foreach (Parameter param in ourLight.Parameters) + { + param.Update(lightObject); + } } + } + + private void OnAreaChangeHook(nint unknownPtr) + { + 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 (!stageIsGlobal(stage)) + if (stage != globalStage) { - globalOverrides = config.Overrides[Stage.InfinityOfNothingHandler]; + globalOverrides = config.Overrides[globalStage]; } - foreach (Override ovP in prevOverrides) + foreach (Override ovR in prevOverrides) { - ovP.Unset(); - if (globalOverrides != null && ovP.Param != null) + bool superseded = false; + if (ovR.Param != null) { - setIfOverridesContainsParam(globalOverrides, ovP.Param); + superseded |= selectedPreset != "" && overridesContainsParam(config.Presets[selectedPreset], ovR.Param); + superseded |= overridesContainsParam(externalOverrides.Values, ovR.Param); + } + if (!superseded) + { + ovR.Unset(); + if (globalOverrides != null && ovR.Param != null) + { + setIfOverridesContainsParam(globalOverrides, ovR.Param); + } } } if (globalOverrides != null) // Stage isn't global. @@ -2134,32 +2239,20 @@ namespace WorldTuningTool List stageOverrides = config.Overrides[stage]; foreach (Override ovS in stageOverrides) { + bool superseded = false; if (ovS.Param != null) { - unsetIfOverridesContainsParam(globalOverrides, ovS.Param); + superseded |= selectedPreset != "" && overridesContainsParam(config.Presets[selectedPreset], ovS.Param); + superseded |= overridesContainsParam(externalOverrides.Values, ovS.Param); + } + if (!superseded) + { + if (ovS.Param != null) + { + unsetIfOverridesContainsParam(globalOverrides, ovS.Param); + } + ovS.Set(); } - ovS.Set(); - } - } - } - - private void UpdateLightsHook(nint lightObject) - { - Light? ourLight = null; - for (int i = 0; i < ourLights.Count; i++) - { - if (lightObject == ourLights[i].Object) - { - ourLight = ourLights[i]; - break; - } - } - updateLights!.Original(lightObject); - if (ourLight != null) - { - foreach (Parameter param in ourLight.Parameters) - { - param.Update(lightObject); } } } @@ -2167,22 +2260,22 @@ namespace WorldTuningTool public void OnImGuiRender() { float width = ImGui.GetWindowWidth(); - width /= (width / 600.0f); + width /= width / 600.0f; /* - if (ImGui.TextLink($"Current Stage: {Config.StageToString(Area.CurrentStage)}")) + if (ImGui.TextLink($"Current Stage: {Config.StageToString(currentStage)}")) { - if (Area.CurrentStage == 0) + if (currentStage == 0) { - selectedStage = Stage.InfinityOfNothingHandler; + selectedStage = globalStage; } else { - selectedStage = Area.CurrentStage; + selectedStage = currentStage; } } */ - ImGui.Text($"Current Stage: {Config.StageToString(Area.CurrentStage)}"); + ImGui.Text($"Current Stage: {Config.StageToString(currentStage)}"); ImGui.PushItemWidth(width * 0.35f); if (ImGui.BeginCombo("##Stage", Config.StageToString(selectedStage))) @@ -2202,80 +2295,308 @@ namespace WorldTuningTool ImGui.SameLine(); if (ImGui.Button("Current")) { - if (Area.CurrentStage != 0x0) + if (currentStage != 0) { - selectedStage = Area.CurrentStage; + selectedStage = currentStage; } else { - selectedStage = Stage.InfinityOfNothingHandler; + selectedStage = globalStage; } } ImGui.SameLine(); if (ImGui.Button("Global")) { - selectedStage = Stage.InfinityOfNothingHandler; + selectedStage = globalStage; } Config config = getConfig(); - List stageOverrides = config.Overrides[selectedStage]; + List selectedOverrides = config.Overrides[selectedStage]; + List? stageOverrides = maybeGetStageOverrides(config); List? globalOverrides = null; - if (!stageIsGlobal(selectedStage)) + if (selectedStage != globalStage) { - globalOverrides = config.Overrides[Stage.InfinityOfNothingHandler]; + globalOverrides = config.Overrides[globalStage]; } if (ImGui.Button("Add override")) { Override ov = new Override(); - if (Area.CurrentStage == selectedStage || stageIsGlobal(selectedStage)) + if (currentStage == selectedStage || selectedStage == globalStage) { - ov.Set(); + ov.Set(); // Empty override never superseded. } - stageOverrides.Add(ov); + selectedOverrides.Add(ov); } ImGui.PopItemWidth(); - for (int i = 0; i < stageOverrides.Count; i++) + for (int i = 0; i < selectedOverrides.Count; i++) { - Override ovS = stageOverrides[i]; ImGui.PushID(i); + Override ovS = selectedOverrides[i]; + bool superseded = false; + if (ovS.Param != null) + { + superseded |= globalOverrides == null && stageOverrides != null && + overridesContainsParam(stageOverrides, ovS.Param); + superseded |= selectedPreset != "" && overridesContainsParam(config.Presets[selectedPreset], ovS.Param); + superseded |= overridesContainsParam(externalOverrides.Values, ovS.Param); + } bool requestRemove = ImGui.Button("X"); ImGui.SameLine(); bool requestUp = ImGui.Button("▲"); ImGui.SameLine(); bool requestDown = ImGui.Button("▼"); ImGui.SameLine(); - if (requestDown && i < stageOverrides.Count - 1) + if (requestDown && i < selectedOverrides.Count - 1) { - (stageOverrides[i], stageOverrides[i + 1]) = (stageOverrides[i + 1], stageOverrides[i]); + (selectedOverrides[i], selectedOverrides[i + 1]) = (selectedOverrides[i + 1], selectedOverrides[i]); } - ovS.Draw(stageOverrides, globalOverrides, width); + ovS.Draw(selectedOverrides, null, globalOverrides, superseded, width); if (requestUp && i > 0) { - (stageOverrides[i], stageOverrides[i - 1]) = (stageOverrides[i - 1], stageOverrides[i]); + (selectedOverrides[i], selectedOverrides[i - 1]) = (selectedOverrides[i - 1], selectedOverrides[i]); } if (requestRemove) { - ovS.Unset(); - if (globalOverrides != null && ovS.Param != null) + if (!superseded) { - setIfOverridesContainsParam(globalOverrides, ovS.Param); + ovS.Unset(); + if (ovS.Param != null && globalOverrides != null) + { + setIfOverridesContainsParam(globalOverrides, ovS.Param); + } } - stageOverrides.RemoveAt(i); + selectedOverrides.RemoveAt(i); i--; } ImGui.PopID(); } if (ImGui.Button("Save")) { + for (int i = 0; i < selectedOverrides.Count; i++) + { + Override ovS = selectedOverrides[i]; + if (ovS.Param == null) + { + selectedOverrides.RemoveAt(i); + i--; + continue; + } + ovS.Save(); + } ConfigManager.SaveConfig(this); } ImGui.Separator(); + // Global overrides and presets could now be show at the same time. + globalOverrides = config.Overrides[globalStage]; + + ImGui.PushID("Preset"); + ImGui.Text("Quick Presets:"); + ImGui.PushItemWidth(width * 0.35f); + if (ImGui.Button("+")) + { + string presetName = "New Set"; + int presetDup = 0; + while (config.Presets.ContainsKey(presetName)) + { + presetDup++; + presetName = $"New Set ({presetDup})"; + } + config.Presets[presetName] = new List(); + selectedPreset = presetName; + } + ImGui.SameLine(); + if (renamingPreset) + { + ImGui.PushItemFlag(ImGuiItemFlags.Disabled, true); + ImGui.PushStyleVar(ImGuiStyleVar.Alpha, ImGui.GetStyle().Alpha * 0.5f); + } + string prevPreset = selectedPreset; + if (ImGui.BeginCombo("##Presets", selectedPreset)) + { + if (ImGui.Selectable("(None)", false)) + { + selectedPreset = ""; + } + foreach ((string name, List overrides) in config.Presets) + { + bool isSelected = name == selectedPreset; + if (ImGui.Selectable(name, isSelected)) + { + selectedPreset = name; + } + } + ImGui.EndCombo(); + } + if (prevPreset != selectedPreset) + { + if (prevPreset != "") + { + List prevOverrides = config.Presets[prevPreset]; + foreach (Override ovR in prevOverrides) + { + bool superseded = false; + if (ovR.Param != null) + { + superseded |= 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 = false; + if (ovN.Param != null) + { + superseded |= overridesContainsParam(externalOverrides.Values, ovN.Param); + } + if (!superseded) + { + if (ovN.Param != null) + { + if (!(stageOverrides != null && unsetIfOverridesContainsParam(stageOverrides, ovN.Param))) + { + unsetIfOverridesContainsParam(globalOverrides, ovN.Param); + } + } + ovN.Set(); + } + } + } + } + if (renamingPreset) + { + ImGui.PopStyleVar(); + ImGui.PopItemFlag(); + } + ImGui.PopItemWidth(); + if (selectedPreset != "") + { + ImGui.SameLine(); + ImGui.PushItemWidth(width * 0.2f); + if (renamingPreset) + { + ImGui.InputText("##Preset Name", ref typedPresetName, 99); + ImGui.SameLine(); + if (typedPresetName == "") + { + ImGui.PushItemFlag(ImGuiItemFlags.Disabled, true); + ImGui.PushStyleVar(ImGuiStyleVar.Alpha, ImGui.GetStyle().Alpha * 0.5f); + } + if (ImGui.Button("Save")) + { + string presetName = typedPresetName; + int presetDup = 0; + while (config.Presets.ContainsKey(presetName)) + { + presetDup++; + presetName = $"{typedPresetName} ({presetDup})"; + } + List tmpOverrides = config.Presets[selectedPreset]; + config.Presets.Remove(selectedPreset); + config.Presets[presetName] = tmpOverrides; + selectedPreset = presetName; + renamingPreset = false; + } + if (typedPresetName == "") + { + ImGui.PopStyleVar(); + ImGui.PopItemFlag(); + } + } + else if (ImGui.Button("Rename")) + { + renamingPreset = true; + typedPresetName = selectedPreset; + } + ImGui.PopItemWidth(); + List presetOverrides = config.Presets[selectedPreset]; + if (ImGui.Button("Add override")) + { + Override ov = new Override(); + ov.Set(); // Empty override never superseded. + presetOverrides.Add(ov); + } + for (int i = 0; i < presetOverrides.Count; i++) + { + ImGui.PushID(i); + Override ovP = presetOverrides[i]; + bool superseded = false; + if (ovP.Param != null) + { + superseded |= overridesContainsParam(externalOverrides.Values, ovP.Param); + } + bool requestRemove = ImGui.Button("X"); + ImGui.SameLine(); + bool requestUp = ImGui.Button("▲"); + ImGui.SameLine(); + bool requestDown = ImGui.Button("▼"); + ImGui.SameLine(); + if (requestDown && i < presetOverrides.Count - 1) + { + (presetOverrides[i], presetOverrides[i + 1]) = (presetOverrides[i + 1], presetOverrides[i]); + } + ovP.Draw(presetOverrides, stageOverrides, globalOverrides, superseded, width); + if (requestUp && i > 0) + { + (presetOverrides[i], presetOverrides[i - 1]) = (presetOverrides[i - 1], presetOverrides[i]); + } + if (requestRemove) + { + if (!superseded) + { + ovP.Unset(); + if (ovP.Param != null) + { + if (!(stageOverrides != null && setIfOverridesContainsParam(stageOverrides, ovP.Param))) + { + setIfOverridesContainsParam(globalOverrides, ovP.Param); + } + } + } + presetOverrides.RemoveAt(i); + i--; + } + ImGui.PopID(); + } + if (ImGui.Button("Save")) + { + for (int i = 0; i < presetOverrides.Count; i++) + { + Override ovP = presetOverrides[i]; + if (ovP.Param == null) + { + presetOverrides.RemoveAt(i); + i--; + continue; + } + ovP.Save(); + } + ConfigManager.SaveConfig(this); + } + } + ImGui.PopID(); + + ImGui.Separator(); + ImGui.PushID("External"); ImGui.Text("External:"); foreach (Override ovE in externalOverrides.Values) { - ovE.Draw(null, null, width); + ovE.Draw(null, null, null, false, width); } ImGui.PopID(); @@ -2707,6 +3028,13 @@ namespace WorldTuningTool Log.Info("Face shader replaced."); } } + else if (hash == "18a797dc-9458d333-59e6dff0-9790fcea") + { + if (replaceShaderFromFile(info, $"{shaderPath}/sssss.shdr")) { + info->Replacement.Type = ShaderSourceType.BINARY; + Log.Info("SSSSS shader replaced."); + } + } /* else if (hash == "d7e47ffe-82572c64-795c4698-341e5b91") { -- cgit v1.2.3-101-g0448