From 5658a33e763cb3ed296f683b5dd128dc94f113e9 Mon Sep 17 00:00:00 2001 From: Andrew Opalach Date: Wed, 21 Oct 2026 17:18:23 -0400 Subject: Factor out Parameter class Make it less dependent on Plugin specific code so it can be more easily reused. Signed-off-by: Andrew Opalach --- Plugin.cs | 1406 ++++++++----------------------------------------------------- 1 file changed, 187 insertions(+), 1219 deletions(-) (limited to 'Plugin.cs') diff --git a/Plugin.cs b/Plugin.cs index 3218403..aa3f854 100644 --- a/Plugin.cs +++ b/Plugin.cs @@ -1,17 +1,8 @@ -//#define ENABLE_ASSERTS //#define OVERSIZED_SHADOW_MAP //#define SHADER_FEATURES //#define RESOURCE_ADJUSTMENT using System.Numerics; -using System.Globalization; -using System.Runtime.CompilerServices; -#if ENABLE_ASSERTS -using System.Diagnostics; -#endif -#if SHADER_FEATURES -using System.Runtime.InteropServices; -#endif using ImGuiNET; using SharpPluginLoader.Core; @@ -56,6 +47,9 @@ using SharpPluginLoader.Core.Resources; namespace WorldTuningTool { + using static Utility; + using static Parameter; + using static PFuncs; using static Config; public unsafe class Plugin : IPlugin @@ -63,138 +57,6 @@ namespace WorldTuningTool public string Name => "World Tuning Tool"; public string Author => "Akon City Software"; - private static bool loggedAssertFailed = false; - internal static void Assert(bool condition = false, [CallerLineNumber] int line = 0) - { - if (!condition && !loggedAssertFailed) - { - Log.Error($"Assert failed on line {line}, further asserts won't be logged."); - loggedAssertFailed = true; - } -#if ENABLE_ASSERTS - Trace.Assert(condition); -#endif - } - - private static byte ByteFlag(bool f) { return f ? (byte)0x1 : (byte)0x0; } - - internal static T Get(nint addr, nint offset = 0x0) where T : unmanaged - { - return MemoryUtil.Read(addr + offset); - } - - internal static T Get(long addr, nint offset = 0x0) where T : unmanaged - { - return MemoryUtil.Read((nint)addr + offset); - } - - internal static T *GetPtrInline(nint addr, nint offset = 0x0) where T : unmanaged - { - return (T *)(addr + offset); - } - - internal static ref T GetRef(nint addr, nint offset = 0x0) where T : unmanaged - { - return ref MemoryUtil.GetRef(addr + offset); - } - - private static int BitIndex(int mask) - { - return BitOperations.Log2((uint)(mask & (-mask))); - } - - private static Vector4 ColorVectorFromInt(int c) - { - return new Vector4( - ((c ) & 0xFF) / 255.0f, - ((c >> 8 ) & 0xFF) / 255.0f, - ((c >> 16) & 0xFF) / 255.0f, - ((c >> 24) & 0xFF) / 255.0f); - } - - private static int ColorVectorToInt(Vector4 v) - { - return ((int)MathF.Round(v.X * 255.0f) | - ((int)MathF.Round(v.Y * 255.0f) << 8) | - ((int)MathF.Round(v.Z * 255.0f) << 16) | - ((int)MathF.Round(v.W * 255.0f) << 24)); - } - - private static float StringToSingle(string s) { return Convert.ToSingle(s, CultureInfo.InvariantCulture); } - private static bool StringToBoolean(string s) { return Convert.ToBoolean(s, CultureInfo.InvariantCulture); } - private static int StringToInt32(string s, int fromBase = 10) - { - if (fromBase == 10) return Convert.ToInt32(s, CultureInfo.InvariantCulture); - return Convert.ToInt32(s, fromBase); - } - private static string SingleToString(float f, string? format = null) { return f.ToString(format, CultureInfo.InvariantCulture); } - private static string BooleanToString(bool b) { return b.ToString(CultureInfo.InvariantCulture); } - private static string Int32ToString(int i, string? format = null) { return i.ToString(format, CultureInfo.InvariantCulture); } - - internal static Vector2 StringToVector2(string s, char delim = ',') - { - if (String.IsNullOrEmpty(s)) throw new FormatException(); - string[] sp = s.Split(delim).Select((v) => v.Trim()).ToArray(); - if (sp.Length != 2) throw new FormatException(); - return new Vector2(StringToSingle(sp[0]), StringToSingle(sp[1])); - } - - internal static Vector3 StringToVector3(string s, char delim = ',') - { - if (String.IsNullOrEmpty(s)) throw new FormatException(); - string[] sp = s.Split(delim).Select((v) => v.Trim()).ToArray(); - if (sp.Length != 3) throw new FormatException(); - return new Vector3(StringToSingle(sp[0]), StringToSingle(sp[1]), StringToSingle(sp[2])); - } - - internal static Vector4 StringToVector4(string s, char delim = ',') - { - if (String.IsNullOrEmpty(s)) throw new FormatException(); - string[] sp = s.Split(delim).Select((v) => v.Trim()).ToArray(); - if (sp.Length != 4) throw new FormatException(); - return new Vector4(StringToSingle(sp[0]), StringToSingle(sp[1]), StringToSingle(sp[2]), StringToSingle(sp[3])); - } - - private static string Vector2ToString(Vector2 v) - { - return string.Format(CultureInfo.InvariantCulture, "{0},{1}", v.X, v.Y); - } - - private static string Vector3ToString(Vector3 v) - { - return string.Format(CultureInfo.InvariantCulture, "{0},{1},{2}", v.X, v.Y, v.Z); - } - - private static string Vector4ToString(Vector4 v) - { - return string.Format(CultureInfo.InvariantCulture, "{0},{1},{2},{3}", v.X, v.Y, v.Z, v.W); - } - - public enum ParameterType - { - BOOL, - FLAG, - BYTE, - INT, - ALIGNED_INT, - HEX, - BITS, - COLOR, - COLOR_FACTOR, - FLOAT, - VECTOR3, - VECTOR2, - VECTOR4, - PATCH_FLOAT, - SHADOW_RESOLUTION - } - - private const float defaultParamWidth = 0.21f; - private const float fadeAlphaFactor = 0.7f; - private const float disableAlphaFactor = 0.6f; - - private static bool ignoreMinMax = false; - private static IPlugin? Instance = null; private static Config getConfig() @@ -227,1107 +89,221 @@ namespace WorldTuningTool } private const StageExt globalStage = StageExt.Global; - private static StageExt currentStage => (StageExt)Area.CurrentStage; - private static List? maybeGetStageOverrides(Config config) - { - if (currentStage != StageExt.Global && config.Overrides.TryGetValue(currentStage, out List? stageOverrides)) - { - return stageOverrides; - } - return null; - } - - private static StageExt selectedStage = globalStage; - private static StageExt previousStage = selectedStage; - - private static string selectedGlobal = ""; - - private static string selectedSet = ""; - private static bool renamingSet = false; - private static string typedSetName = ""; - - private static Dictionary externalOverrides = new Dictionary(); - private static int externalId = 0; - - private static bool overridesContainsParam(IEnumerable overrides, Parameter param) - { - 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; - } - - // globalOverrides == null: selectedStage is globalStage. - private static bool selectedOverrideSuperseded(Config config, List? globalOverrides, List? stageOverrides, Parameter? param) - { - // Non-current stage always superseded (inactive). - bool superseded = globalOverrides != null && selectedStage != currentStage; - if (!superseded && param != null) - { - // If Global is selected, check if superseded by a currentStage override. - superseded |= globalOverrides == null && stageOverrides != null && overridesContainsParam(stageOverrides, param); - // Any other selectedStage override is either inactive or could only be superseded by a set or external override. - superseded |= selectedSet != "" && overridesContainsParam(config.Sets[selectedSet], param); - superseded |= overridesContainsParam(externalOverrides.Values, param); - } - return superseded; - } - - private static bool stageOverrideSuperseded(Config config, Parameter? param) - { - bool superseded = false; - if (param != null) - { - superseded |= selectedSet != "" && overridesContainsParam(config.Sets[selectedSet], param); - superseded |= overridesContainsParam(externalOverrides.Values, param); - } - return superseded; - } - - public static class ParameterFlags - { - public const int ViewOnly = 1; - } - - public abstract class Parameter - { - public string Name; - private string hiddenName; - public ParameterType Type; - - private nint offset; - private int mask; - private nint lastAddr = 0x0; - private bool overrideValue = false; - private bool overrideForStage = false; - private bool overrideWasOn = false; - - private int flags; - public bool ViewOnly => (flags & ParameterFlags.ViewOnly) == ParameterFlags.ViewOnly; - - protected float stepf, minf, maxf; - protected int step, min, max; - - private bool fallbackUpdate = true; - private bool pendingWrite = false; - private Vector4 valueV = default; - private int valueInt = 0; - private Vector4 oValueV; // Original value. - private int oValueInt; - - private bool pendingUpdate = true; - private bool queuedOverride = false; - private bool queuedValue = false; - private Vector4 qValueV; // Queued value. - private int qValueInt; - - private bool bValue = false; - private Vector4 bValueV; // B value in A/B. - private int bValueInt; - - public Parameter(string name, nint offset, int mask, ParameterType type, int flags) - { - Name = name; - hiddenName = "##" + Name; - Type = type; - switch (Type) - { - case ParameterType.FLAG: - Assert(mask != 0); - break; - case ParameterType.PATCH_FLOAT: - valueV.X = Get(offset); - pendingUpdate = false; - break; - case ParameterType.SHADOW_RESOLUTION: - valueInt = 1; - pendingUpdate = false; - break; - } - this.offset = offset; - this.mask = mask; - this.flags = flags; - } - - public bool PendingUpdate() - { - return pendingUpdate; - } - - public (Vector4, int) GetValue() - { - return (valueV, valueInt); - } - - public int GetMask() - { - return mask; - } - - public void Resolve() - { - Assert(!InTransition && pendingWrite); - pendingWrite = false; - maybeWriteCurrentValue(); - } - - private void maybeWriteCurrentValue() - { - if (InTransition) - { - if (!DirtyParams.Contains(this)) - { - pendingWrite = true; - DirtyParams.Add(this); - } - else - { - Assert(pendingWrite); - } - return; - } - Assert(!pendingWrite); - switch (Type) - { - case ParameterType.PATCH_FLOAT: - new Patch(offset, BitConverter.GetBytes(valueV.X)).Enable(); - break; - case ParameterType.SHADOW_RESOLUTION: - if (valueInt > 1) - { - shadowResEnable(valueInt); - } - else - { - shadowResDisable(); - } - break; - } - if (lastAddr == 0x0) - { - return; - } - switch (Type) - { - case ParameterType.BOOL: - case ParameterType.BYTE: - GetRef(lastAddr, offset) = (byte)valueInt; - break; - case ParameterType.FLAG: - { - ref int i1 = ref GetRef(lastAddr, offset); - if (valueInt != 0) - { - i1 |= mask; - } - else - { - i1 &= ~mask; - } - break; - } - case ParameterType.INT: - case ParameterType.ALIGNED_INT: - case ParameterType.HEX: - case ParameterType.BITS: - case ParameterType.COLOR: - { - ref int i1 = ref GetRef(lastAddr, offset); - if (mask != 0) - { - i1 = (i1 & ~mask) | ((valueInt << BitIndex(mask)) & mask); - } - else - { - i1 = valueInt; - } - break; - } - case ParameterType.FLOAT: - GetRef(lastAddr, offset) = valueV.X; - break; - case ParameterType.VECTOR2: - GetRef(lastAddr, offset) = new Vector2(valueV.X, valueV.Y); - break; - case ParameterType.VECTOR3: - case ParameterType.COLOR_FACTOR: - GetRef(lastAddr, offset) = new Vector3(valueV.X, valueV.Y, valueV.Z); - break; - case ParameterType.VECTOR4: - GetRef(lastAddr, offset) = valueV; - break; - } - } - - public void ForceOverrideOn() - { - if (!queuedOverride && !overrideValue) - { - OverrideOn(false); - } - } - - public void ForceOverrideOff() - { - if (queuedOverride || overrideValue) - { - OverrideOff(); - } - } - - public void OverrideOn(bool forStage) - { - if (pendingUpdate) - { - if (queuedOverride) - { - Assert(!overrideWasOn && forStage); - overrideWasOn = true; - } - else - { - queuedOverride = true; - } - } - else - { - if (overrideValue) - { - Assert(!overrideWasOn && forStage); - overrideWasOn = true; - } - else - { - oValueV = valueV; - oValueInt = valueInt; - maybeWriteCurrentValue(); - overrideValue = true; - } - } - overrideForStage = forStage; - } - - public void OverrideOff() - { - if (queuedOverride) - { - if (overrideWasOn) - { - Assert(overrideForStage); - overrideWasOn = false; - } - else - { - queuedOverride = false; - } - } - else - { - Assert(overrideValue); - if (overrideWasOn) - { - Assert(overrideForStage); - overrideWasOn = false; - } - else - { - valueV = oValueV; - valueInt = oValueInt; - maybeWriteCurrentValue(); - bValue = false; - overrideValue = false; - } - } - overrideForStage = false; - } - - public void SetOverrideValue(Vector4 v4, int i1) - { - if (queuedOverride) - { - qValueV = v4; - qValueInt = i1; - queuedValue = true; - } - else - { - valueV = v4; - valueInt = i1; - maybeWriteCurrentValue(); - } - } - - public void Update(nint baseObject, bool fromHook = false) - { - lastAddr = baseObject; - - if (baseObject == 0x0) - { - pendingUpdate = true; - return; - } - - if (fromHook) - { - fallbackUpdate = false; - } - else if (!fallbackUpdate) - { - fallbackUpdate = true; - return; - } - - // Trying to track changes to the original value is a "best effort" - // approach because it can't work if the in-game value is updated - // to the same value as a current override. - switch (Type) - { - case ParameterType.BOOL: - case ParameterType.BYTE: - { - ref byte b1 = ref GetRef(baseObject, offset); - byte b = b1; - if (overrideValue) - { - if (b != (byte)valueInt) - { - oValueInt = b; - } - b1 = (byte)valueInt; - } - else - { - valueInt = b; - } - break; - } - case ParameterType.FLAG: - { - ref int i1 = ref GetRef(baseObject, offset); - int b1 = ByteFlag((i1 & mask) == mask); - if (overrideValue) - { - if (b1 != valueInt) - { - oValueInt = b1; - } - if (valueInt != 0) - { - i1 |= mask; - } - else - { - i1 &= ~mask; - } - } - else - { - valueInt = b1; - } - break; - } - case ParameterType.INT: - case ParameterType.ALIGNED_INT: - case ParameterType.HEX: - case ParameterType.BITS: - case ParameterType.COLOR: - { - ref int i1 = ref GetRef(baseObject, offset); - int m = i1; - if (mask != 0) - { - m = (m & mask) >> BitIndex(mask); - } - if (overrideValue) - { - if (m != valueInt) - { - oValueInt = m; - } - if (mask != 0) - { - i1 = (i1 & ~mask) | ((valueInt << BitIndex(mask)) & mask); - } - else - { - i1 = valueInt; - } - } - else - { - valueInt = m; - } - break; - } - case ParameterType.FLOAT: - { - ref float f1 = ref GetRef(baseObject, offset); - float f = f1; - if (overrideValue) - { - if (f != valueV.X) - { - oValueV.X = f; - } - f1 = valueV.X; - } - else - { - valueV.X = f; - } - break; - } - case ParameterType.VECTOR2: - { - ref Vector2 v2 = ref GetRef(baseObject, offset); - Vector2 v = v2; - if (overrideValue) - { - Vector2 valueV2 = new Vector2(valueV.X, valueV.Y); - if (v != valueV2) - { - oValueV = new Vector4(v.X, v.Y, 0.0f, 0.0f); - } - v2 = valueV2; - } - else - { - valueV = new Vector4(v.X, v.Y, 0.0f, 0.0f); - } - break; - } - case ParameterType.VECTOR3: - case ParameterType.COLOR_FACTOR: - { - ref Vector3 v3 = ref GetRef(baseObject, offset); - Vector3 v = v3; - if (overrideValue) - { - Vector3 valueV3 = new Vector3(valueV.X, valueV.Y, valueV.Z); - if (v != valueV3) - { - oValueV = new Vector4(v.X, v.Y, v.Z, 0.0f); - } - v3 = valueV3; - } - else - { - valueV = new Vector4(v.X, v.Y, v.Z, 0.0f); - } - break; - } - case ParameterType.VECTOR4: - { - ref Vector4 v4 = ref GetRef(baseObject, offset); - Vector4 v = v4; - if (overrideValue) - { - if (v != valueV) - { - oValueV = v; - } - v4 = valueV; - } - else - { - valueV = v; - } - break; - } - } - - if (pendingUpdate) - { - pendingUpdate = false; - if (queuedOverride) - { - Assert(!overrideValue); - OverrideOn(overrideForStage); - if (queuedValue) - { - valueV = qValueV; - valueInt = qValueInt; - maybeWriteCurrentValue(); - queuedValue = false; - } - queuedOverride = false; - } - } - } - - public void AdjustValue(ref Vector4 v4, ref int i1) - { - if (Type == ParameterType.SHADOW_RESOLUTION) // Hard limit. - { -#if OVERSIZED_SHADOW_MAP - i1 = Math.Clamp(i1, 1, 6); -#else - i1 = Math.Clamp(i1, 1, 5); -#endif - } - else if (!ignoreMinMax) - { - switch (Type) - { - case ParameterType.BOOL: - case ParameterType.FLAG: - case ParameterType.BYTE: - case ParameterType.INT: - case ParameterType.HEX: - case ParameterType.BITS: - i1 = Math.Clamp(i1, min, max); - break; - case ParameterType.ALIGNED_INT: - i1 = Math.Clamp((i1 + (step - 1))&~(step - 1), min, max); - break; - case ParameterType.FLOAT: - case ParameterType.PATCH_FLOAT: - case ParameterType.VECTOR2: - case ParameterType.VECTOR3: - case ParameterType.COLOR_FACTOR: - case ParameterType.VECTOR4: - v4 = new Vector4( - Math.Clamp(v4.X, minf, maxf), - Math.Clamp(v4.Y, minf, maxf), - Math.Clamp(v4.Z, minf, maxf), - Math.Clamp(v4.W, minf, maxf)); - break; - } - } - } - - public bool DrawValue(ref Vector4 v4, ref int i1, float width, bool drawLabel) - { - bool valueChanged = false; - string label = drawLabel ? Name : hiddenName; - float displayMinf = ignoreMinMax ? 0.0f : minf; - float displayMaxf = ignoreMinMax ? 0.0f : maxf; - switch (Type) - { - case ParameterType.BOOL: - case ParameterType.FLAG: - { - bool b = i1 != 0; - if (ImGui.Checkbox(label, ref b)) - { - i1 = ByteFlag(b); - valueChanged = true; - } - break; - } - case ParameterType.BYTE: - { - ImGuiInputTextFlags flags = ImGuiInputTextFlags.EnterReturnsTrue; - ImGui.SetNextItemWidth(width * defaultParamWidth); - if (ImGui.InputInt(label, ref i1, step, 0, flags)) - { - valueChanged = true; - } - break; - } - case ParameterType.INT: - case ParameterType.ALIGNED_INT: - case ParameterType.HEX: - case ParameterType.SHADOW_RESOLUTION: - { - ImGuiInputTextFlags flags = ImGuiInputTextFlags.EnterReturnsTrue; - if (Type == ParameterType.HEX) - { - flags |= ImGuiInputTextFlags.CharsHexadecimal; - } - ImGui.SetNextItemWidth(width * defaultParamWidth); - if (ImGui.InputInt(label, ref i1, step, 0, flags)) - { - valueChanged = true; - } - break; - } - case ParameterType.BITS: - { - for (int i = 0; i < 32; i++) - { - int bit = (1 << i); - if ((mask & bit) == bit) - { - bool set = (i1 & bit) == bit; - if (ImGui.Checkbox($"##Bit{i}", ref set)) - { - if (set) - { - i1 |= bit; - } - else - { - i1 &= ~bit; - } - valueChanged = true; - } - ImGui.SameLine(); - } - } - ImGui.Text(label); - break; - } - case ParameterType.COLOR: - { - Vector4 colorV = ColorVectorFromInt(i1); - ImGui.SetNextItemWidth(width * defaultParamWidth * 3.0f); - if (ImGui.ColorEdit4(label, ref colorV)) - { - i1 = ColorVectorToInt(colorV); - valueChanged = true; - } - break; - } - case ParameterType.FLOAT: - case ParameterType.PATCH_FLOAT: - { - float f1 = v4.X; - ImGui.SetNextItemWidth(width * defaultParamWidth); - if (ImGui.DragFloat(label, ref f1, stepf, displayMinf, displayMaxf, "%.6f", ImGuiSliderFlags.NoRoundToFormat)) - { - v4 = new Vector4(f1, 0.0f, 0.0f, 0.0f); - valueChanged = true; - } - break; - } - case ParameterType.VECTOR2: - { - Vector2 v2 = new Vector2(v4.X, v4.Y); - ImGui.SetNextItemWidth(width * defaultParamWidth * 2.0f); - if (ImGui.DragFloat2(label, ref v2, stepf, displayMinf, displayMaxf, "%.5f", ImGuiSliderFlags.NoRoundToFormat)) - { - v4 = new Vector4(v2.X, v2.Y, 0.0f, 0.0f); - valueChanged = true; - } - break; - } - case ParameterType.VECTOR3: - case ParameterType.COLOR_FACTOR: - { - Vector3 v3 = new Vector3(v4.X, v4.Y, v4.Z); - if (Type == ParameterType.COLOR_FACTOR) - { - Vector3 v3Color = v3; - // Only scale the color vector if max is unbound. Otherwise, assume that intensity and color are seperate. - if (maxf == Single.MaxValue) - { - float v3Max = MathF.Max(Math.Abs(v3.X), MathF.Max(Math.Abs(v3.Y), Math.Abs(v3.Z))); - if (v3Max != 0.0f) - { - // I believe a compromise is needed here. These are the options I can think of. - //v3Color /= v3Max; // Preview will be full "brightness" at low intensities. - v3Color = v3Color * (v3Color / v3Max); // Preview will converge towards white at high intensities. - } - } - ImGui.ColorEdit3(label, ref v3Color, ImGuiColorEditFlags.NoPicker | ImGuiColorEditFlags.NoLabel | ImGuiColorEditFlags.NoInputs); - ImGui.SameLine(); - } - ImGui.SetNextItemWidth(width * defaultParamWidth * 3.0f); - if (ImGui.DragFloat3(label, ref v3, stepf, displayMinf, displayMaxf, "%.5f", ImGuiSliderFlags.NoRoundToFormat)) - { - v4 = new Vector4(v3.X, v3.Y, v3.Z, 0.0f); - valueChanged = true; - } - break; - } - case ParameterType.VECTOR4: - { - ImGui.SetNextItemWidth(width * defaultParamWidth * 4.0f); - if (ImGui.DragFloat4(label, ref v4, stepf, displayMinf, displayMaxf, "%.5f", ImGuiSliderFlags.NoRoundToFormat)) - { - valueChanged = true; - } - break; - } - } - if (valueChanged) - { - AdjustValue(ref v4, ref i1); - } - return valueChanged; + private static StageExt currentStage => (StageExt)Area.CurrentStage; + private static List? maybeGetStageOverrides(Config config) + { + if (currentStage != StageExt.Global && config.Overrides.TryGetValue(currentStage, out List? stageOverrides)) + { + return stageOverrides; } + return null; + } + + private static StageExt selectedStage = globalStage; + private static StageExt previousStage = selectedStage; + + private static string selectedGlobal = ""; + + private static string selectedSet = ""; + private static bool renamingSet = false; + private static string typedSetName = ""; + + private static Dictionary externalOverrides = new Dictionary(); + private static int externalId = 0; - public void DrawReferenceValue(string name, Vector4 v4, int i1) + private static bool overridesContainsParam(IEnumerable overrides, Parameter param) + { + foreach (Override ov in overrides) { - ImGui.PushStyleVar(ImGuiStyleVar.Alpha, ImGui.GetStyle().Alpha * fadeAlphaFactor); - switch (Type) - { - case ParameterType.BOOL: - case ParameterType.FLAG: - ImGui.Text($"({name}: {i1 != 0})"); - break; - case ParameterType.BYTE: - case ParameterType.INT: - case ParameterType.ALIGNED_INT: - case ParameterType.SHADOW_RESOLUTION: - ImGui.Text($"({name}: {i1})"); - break; - case ParameterType.HEX: - case ParameterType.BITS: - case ParameterType.COLOR: - ImGui.Text($"({name}: {i1:X})"); - break; - case ParameterType.FLOAT: - case ParameterType.PATCH_FLOAT: - ImGui.Text($"({name}: {v4.X:0.000000})"); - break; - case ParameterType.VECTOR2: - ImGui.Text($"({name}: {v4.X:0.00000}, {v4.Y:0.00000})"); - break; - case ParameterType.VECTOR3: - case ParameterType.COLOR_FACTOR: - ImGui.Text($"({name}: {v4.X:0.00000}, {v4.Y:0.00000}, {v4.Z:0.00000})"); - break; - case ParameterType.VECTOR4: - ImGui.Text($"({name}: {v4.X:0.00000}, {v4.Y:0.00000}, {v4.Z:0.00000}, {v4.W:0.00000})"); - break; + if (ov.Param == param) + { + return true; } - ImGui.PopStyleVar(); } + return false; + } - public string SetByLine(Config config, List? stageOverrides, List? globalOverrides, bool forSet, bool allowGlobal) + private static bool unsetIfOverridesContainsParam(IEnumerable overrides, Parameter param) + { + foreach (Override ov in overrides) { - // Reverse order of selectedOverrideSuperseded(). - if (overridesContainsParam(externalOverrides.Values, this)) - { - return "Set by 'External'"; - } - Assert(!forSet); - if (selectedSet != "" && overridesContainsParam(config.Sets[selectedSet], this)) - { - return $"Set by '{selectedSet}'"; - } - if ((allowGlobal || globalOverrides == null) && stageOverrides != null && overridesContainsParam(stageOverrides, this)) + if (ov.Param == param) { - return $"Set by '{StageToString(currentStage)}'"; + ov.Unset(); + return true; } - if (allowGlobal) + } + return false; + } + + private static bool setIfOverridesContainsParam(IEnumerable overrides, Parameter param) + { + foreach (Override ov in overrides) + { + if (ov.Param == param) { - return "Set by \'Global\'"; + ov.Set(); + return true; } - // Superseded because inactive. - Assert(globalOverrides != null && selectedStage != currentStage); - return ""; } + return false; + } - public void Draw(float width, bool assumeOverride = false) + // globalOverrides == null: selectedStage is globalStage. + private static bool selectedOverrideSuperseded(Config config, List? globalOverrides, List? stageOverrides, Parameter? param) + { + // Non-current stage always superseded (inactive). + bool superseded = globalOverrides != null && selectedStage != currentStage; + if (!superseded && param != null) { - Draw(ref valueV, ref valueInt, width, assumeOverride); + // If Global is selected, check if superseded by a currentStage override. + superseded |= globalOverrides == null && stageOverrides != null && overridesContainsParam(stageOverrides, param); + // Any other selectedStage override is either inactive or could only be superseded by a set or external override. + superseded |= selectedSet != "" && overridesContainsParam(config.Sets[selectedSet], param); + superseded |= overridesContainsParam(externalOverrides.Values, param); } + return superseded; + } - public void Draw(ref Vector4 v4, ref int i1, float width, bool assumeOverride) + private static bool stageOverrideSuperseded(Config config, Parameter? param) + { + bool superseded = false; + if (param != null) { - ImGui.PushID(Name); + superseded |= selectedSet != "" && overridesContainsParam(config.Sets[selectedSet], param); + superseded |= overridesContainsParam(externalOverrides.Values, param); + } + return superseded; + } - if (ViewOnly) - { - ImGui.SetCursorPos(ImGui.GetCursorPos() + new Vector2(ImGui.GetFrameHeight() + ImGui.GetStyle().ItemSpacing.X, 0.0f)); - } - else if (!assumeOverride) + internal static Parameter? getParameterByName(string name) + { + if (OldParameterNames.TryGetValue(name, out string? newName)) + { + Log.Warn($"Paramter '{name}' renamed to '{newName}'."); + name = newName; + } + foreach (Parameter param in allParameters) + { + if (param.Name == name) { - if (overrideForStage) - { - ImGui.PushItemFlag(ImGuiItemFlags.Disabled, true); - ImGui.PushItemFlag(ImGuiItemFlags.MixedValue, true); - } - // If OverrideOn() were to set queuedOverride instead of overrideValue, this parameter shouldn't be drawn. - Assert(!PendingUpdate()); - bool toggleOverride = overrideValue; - if (ImGui.Checkbox("##Override", ref toggleOverride)) - { - if (toggleOverride) - { - OverrideOn(false); - } - else - { - OverrideOff(); - } - } - if (ImGui.BeginItemTooltip()) - { - if (overrideForStage) - { - Config config = getConfig(); - List? globalOverrides = config.Overrides[globalStage]; - List? stageOverrides = maybeGetStageOverrides(config); - ImGui.Text(SetByLine(config, stageOverrides, globalOverrides, false, true)); - } - else if (overrideValue) - { - ImGui.Text("Set"); - } - else - { - ImGui.Text("Set override"); - } - ImGui.EndTooltip(); - } - if (overrideForStage) - { - ImGui.PopItemFlag(); - ImGui.PopItemFlag(); - } - ImGui.SameLine(); + return param; } + } + return null; + } - if (!overrideValue) - { - ImGui.PushItemFlag(ImGuiItemFlags.Disabled, true); - } - if (DrawValue(ref valueV, ref valueInt, width, !bValue)) - { - maybeWriteCurrentValue(); - } - if (!overrideValue) - { - ImGui.PopItemFlag(); - } + internal static void drawStageOverrideTooltip(Parameter param) + { + Config config = getConfig(); + List? globalOverrides = config.Overrides[globalStage]; + List? stageOverrides = maybeGetStageOverrides(config); + ImGui.Text(setByLine(param, config, stageOverrides, globalOverrides, false, true)); + } - bool showButtons = !assumeOverride && overrideValue && !pendingUpdate; - if (showButtons) + internal static void drawExtraButtons(Parameter param) + { + Config config = getConfig(); + List selectedOverrides = config.Overrides[selectedStage]; + List? stageOverrides = maybeGetStageOverrides(config); + // Deciding when to set globalOverrides copies the logic in OnImGuiRender(). + // Selected: Set if selectedStage != globalStage. + // Set: Always set. + List? globalOverrides = null; + if (selectedSet != "") + { + List setOverrides = config.Sets[selectedSet]; + if (!overridesContainsParam(setOverrides, param)) { ImGui.SameLine(); - if (!bValue) - { - if (ImGui.Button("B")) - { - bValueV = oValueV; - bValueInt = oValueInt; - bValue = true; - } - } - else - { - if (ImGui.Button("A/B")) - { - (bValueV, valueV) = (valueV, bValueV); - (bValueInt, valueInt) = (valueInt, bValueInt); - maybeWriteCurrentValue(); - } - ImGui.SameLine(); - DrawValue(ref bValueV, ref bValueInt, width, true); - ImGui.SameLine(); - if (ImGui.Button("< B")) - { - bValue = false; - } - } - - Config config = getConfig(); - List selectedOverrides = config.Overrides[selectedStage]; - List? stageOverrides = maybeGetStageOverrides(config); - // Deciding when to set globalOverrides copies the logic in OnImGuiRender(). - // Selected: Set if selectedStage != globalStage. - // Set: Always set. - List? globalOverrides = null; - if (selectedSet != "") - { - List setOverrides = config.Sets[selectedSet]; - if (!overridesContainsParam(setOverrides, this)) + if (ImGui.Button("▲")) + { + // Create the new override before unsetting any lower priority overrides. + // Effectively, copy the current override value. + (Vector4 v4, int i1) = param.GetValue(); + Override ov = new Override(param, v4, i1); + globalOverrides = config.Overrides[globalStage]; + bool superseded = overridesContainsParam(externalOverrides.Values, param); + if (!superseded) { - ImGui.SameLine(); - if (ImGui.Button("▲")) - { - // Create the new override before unsetting any lower priority overrides. - // Effectively, copy the current override value. - 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))) - { - unsetIfOverridesContainsParam(globalOverrides, this); - } - ov.Set(); - EndTransition(); - } - setOverrides.Add(ov); - configState |= SetNotSaved; - } - if (ImGui.BeginItemTooltip()) + BeginTransition(); + if (!(stageOverrides != null && unsetIfOverridesContainsParam(stageOverrides, param))) { - ImGui.Text($"Add to '{selectedSet}'"); - ImGui.EndTooltip(); + unsetIfOverridesContainsParam(globalOverrides, param); } + ov.Set(); + EndTransition(); } + setOverrides.Add(ov); + configState |= SetNotSaved; } - else if (!overridesContainsParam(selectedOverrides, this)) + if (ImGui.BeginItemTooltip()) { - ImGui.SameLine(); - if (ImGui.Button("▲")) - { - 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); - if (selectedStage == globalStage) - { - rebuildConfig(config, selectedOverrides); - } - configState |= SelectedNotSaved; - } - if (ImGui.BeginItemTooltip()) - { - ImGui.Text($"Add to '{StageToString(selectedStage)}'"); - ImGui.EndTooltip(); - } + ImGui.Text($"Add to '{selectedSet}'"); + ImGui.EndTooltip(); } - - ImGui.SameLine(); - DrawReferenceValue("Original", oValueV, oValueInt); } - - ImGui.PopID(); } - } - - public class Parameter : Parameter where T : unmanaged - { - public Parameter(string name, nint offset, int mask, ParameterType type, T? min, T? max, T? step, int flags) : base(name, offset, mask, type, flags) + else if (!overridesContainsParam(selectedOverrides, param)) { - if (typeof(T) == typeof(float)) - { - Assert(type == ParameterType.FLOAT || - type == ParameterType.VECTOR2 || - type == ParameterType.VECTOR3 || - type == ParameterType.VECTOR4 || - type == ParameterType.PATCH_FLOAT || - type == ParameterType.COLOR_FACTOR); - this.stepf = (step != null) ? Convert.ToSingle(step) : 0.1f; - this.minf = (min != null) ? Convert.ToSingle(min) : -Single.MaxValue; - this.maxf = (max != null) ? Convert.ToSingle(max) : Single.MaxValue; - } - else + ImGui.SameLine(); + if (ImGui.Button("▲")) { - this.step = (step != null) ? Convert.ToInt32(step) : 0; - if (typeof(T) == typeof(int)) - { - Assert(type == ParameterType.INT || - type == ParameterType.ALIGNED_INT || - type == ParameterType.HEX || - type == ParameterType.BITS || - type == ParameterType.COLOR || - type == ParameterType.SHADOW_RESOLUTION); - this.min = (min != null) ? Convert.ToInt32(min) : Int32.MinValue; - this.max = (max != null) ? Convert.ToInt32(max) : Int32.MaxValue; - } - else if (typeof(T) == typeof(byte)) + (Vector4 v4, int i1) = param.GetValue(); + Override ov = new Override(param, v4, i1); + if (selectedStage != globalStage) { - Assert(type == ParameterType.BYTE); - this.min = (min != null) ? Convert.ToInt32(min) : 0x0; - this.max = (max != null) ? Convert.ToInt32(max) : 0xFF; + globalOverrides = config.Overrides[globalStage]; } - else if (typeof(T) == typeof(bool)) + bool superseded = selectedOverrideSuperseded(config, globalOverrides, stageOverrides, param); + if (!superseded) { - Assert(type == ParameterType.BOOL || - type == ParameterType.FLAG); - this.min = 0; - this.max = 1; + BeginTransition(); + if (globalOverrides != null) + { + unsetIfOverridesContainsParam(globalOverrides, param); + } + ov.Set(); + EndTransition(); } - else + selectedOverrides.Add(ov); + if (selectedStage == globalStage) { - Assert(); + rebuildConfig(config, selectedOverrides); } + configState |= SelectedNotSaved; + } + if (ImGui.BeginItemTooltip()) + { + ImGui.Text($"Add to '{StageToString(selectedStage)}'"); + ImGui.EndTooltip(); } } } - public static (float?, float?, float?) pStep(float step) { return (null, null, step); } - public static (float?, float?, float?) pMin(float min) { return (min, null, null); } - public static (float?, float?, float?) pMax(float max) { return (null, max, null); } - public static (float?, float?, float?) pMinStep(float min, float step) { return (min, null, step); } - public static (float?, float?, float?) pMaxStep(float max, float step) { return (null, max, step); } - public static (float?, float?, float?) pMinMaxStep(float min, float max, float step) { return (min, max, step); } - public static (int?, int?, int?) pStep(int step) { return (null, null, step); } - public static (int?, int?, int?) pMin(int min) { return (min, null, null); } - public static (int?, int?, int?) pMax(int max) { return (null, max, null); } - public static (int?, int?, int?) pMinStep(int min, int step) { return (min, null, step); } - public static (int?, int?, int?) pMaxStep(int max, int step) { return (null, max, step); } - public static (int?, int?, int?) pMinMaxStep(int min, int max, int step) { return (min, max, step); } - public static (byte?, byte?, byte?) pStep(byte step) { return (null, null, step); } - - public static Parameter P(string name, nint offset, ParameterType type, (T? min, T? max, T? step) m = default) where T : unmanaged - { - return new Parameter(name, offset, 0, type, m.min, m.max, m.step, 0); - } - - public static Parameter P(string name, long offset, ParameterType type, (T? min, T? max, T? step) m = default) where T : unmanaged - { - return new Parameter(name, (nint)offset, 0, type, m.min, m.max, m.step, 0); - } - - public static Parameter V(string name, nint offset, ParameterType type, (T? min, T? max, T? step) m = default) where T : unmanaged + private static string setByLine(Parameter param, Config config, List? stageOverrides, List? globalOverrides, bool forSet, bool allowGlobal) { - return new Parameter(name, offset, 0, type, m.min, m.max, m.step, ParameterFlags.ViewOnly); - } - - public static Parameter M(string name, nint offset, ParameterType type, int mask, (T? min, T? max, T? step) m = default) where T : unmanaged - { - return new Parameter(name, offset, mask, type, m.min, m.max, m.step, 0); - } - - internal static Parameter? getParameterByName(string name) - { - if (OldParameterNames.TryGetValue(name, out string? newName)) + // Reverse order of selectedOverrideSuperseded(). + if (overridesContainsParam(externalOverrides.Values, param)) { - Log.Warn($"Paramter '{name}' renamed to '{newName}'."); - name = newName; + return "Set by 'External'"; } - foreach (Parameter param in allParameters) + Assert(!forSet); + if (selectedSet != "" && overridesContainsParam(config.Sets[selectedSet], param)) { - if (param.Name == name) - { - return param; - } + return $"Set by '{selectedSet}'"; } - return null; + if ((allowGlobal || globalOverrides == null) && stageOverrides != null && overridesContainsParam(stageOverrides, param)) + { + return $"Set by '{StageToString(currentStage)}'"; + } + if (allowGlobal) + { + return "Set by \'Global\'"; + } + // Superseded because inactive. + Assert(globalOverrides != null && selectedStage != currentStage); + return ""; } public class Override @@ -1629,7 +605,7 @@ namespace WorldTuningTool if (superseded) { // Global is the lowest priority so "Set by 'Global'" never applies here. - byLine = Param.SetByLine(config, stageOverrides, globalOverrides, forSet, false); + byLine = setByLine(Param, config, stageOverrides, globalOverrides, forSet, false); } Param.DrawReferenceValue((byLine == "") ? "Current" : byLine, v4, i1); hasStatus = true; @@ -1662,24 +638,6 @@ namespace WorldTuningTool private delegate void UpdateToneMapParams(nint stackOffset, nint toneMapObjectInternal); private Hook? updateToneMapParams; - 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 MtObject? sMhMain = null; private static MtObject? sMhRender = null; @@ -2387,6 +1345,18 @@ namespace WorldTuningTool setShadowQuality.Invoke(sMhScene!.Get(0x5530) + 1); } + private static void handleShadowResParameter(int multiplier) + { + if (multiplier > 1) + { + shadowResEnable(multiplier); + } + else + { + shadowResDisable(); + } + } + #if SHADER_FEATURES private bool fullResSSLR = false; #endif @@ -2573,6 +1543,10 @@ namespace WorldTuningTool { Instance = this; + PFuncs.HandleShadowResolution = handleShadowResParameter; + PFuncs.DrawStageOverrideTooltip = drawStageOverrideTooltip; + PFuncs.DrawExtraButtons = drawExtraButtons; + // Assert no duplicate names. foreach (Parameter param in allParameters) { @@ -3685,8 +2659,7 @@ namespace WorldTuningTool private void HandleGlobalChange() { Config config = getConfig(); - - // Unset current Global overrides. + // Unset and drop current Global overrides. List? stageOverrides = maybeGetStageOverrides(config); List globalOverrides = config.Overrides[globalStage]; foreach (Override ovG in globalOverrides) @@ -3697,17 +2670,12 @@ namespace WorldTuningTool ovG.Unset(); } } - - // Drop current Global overrides. globalOverrides.Clear(); - // Rebuild from new selections. foreach (Override ovG in config.Globals[selectedGlobal]) { globalOverrides.Add(ovG); } - - // Set new Global overrides. foreach (Override ovG in globalOverrides) { bool superseded = selectedOverrideSuperseded(config, null, stageOverrides, ovG.Param); @@ -4847,7 +3815,7 @@ namespace WorldTuningTool if (ImGui.CollapsingHeader("DEBUG")) { - ImGui.Checkbox("Globally Ignore Parameter Min/Max", ref ignoreMinMax); + ImGui.Checkbox("Globally Ignore Parameter Min/Max", ref IgnoreMinMax); if (ImGui.BeginItemTooltip()) { ImGui.Text("Some min/max values are set to avoid crashes, so be warned."); -- cgit v1.2.3-101-g0448