From 47ba7138ae1fc3f090905a0a3feee3b5ae36cbf2 Mon Sep 17 00:00:00 2001 From: Andrew Opalach Date: Tue, 31 Mar 2026 15:48:56 -0400 Subject: First version of parameters Signed-off-by: Andrew Opalach --- Config.cs | 95 ++ Plugin.cs | 2371 +++++++++++++++++++++++++++++++++++++++++++-- Scripts/generate_diffs.sh | 2 + 3 files changed, 2398 insertions(+), 70 deletions(-) diff --git a/Config.cs b/Config.cs index bbb785b..356c746 100755 --- a/Config.cs +++ b/Config.cs @@ -1,4 +1,5 @@ using SharpPluginLoader.Core.Configuration; +using SharpPluginLoader.Core; namespace WorldTuningTool { @@ -6,5 +7,99 @@ namespace WorldTuningTool { public String Name => "WorldTuningTool"; public String Version => "1.0"; + + public static string StageToString(Stage stage) + { + switch (stage) + { + case Stage.InfinityOfNothingHandler: + return "Global"; + case Stage.AncientForest: + return "Ancient Forest"; + case Stage.WildspireWaste: + return "Wildspire Waste"; + case Stage.CoralHighlands: + return "Coral Highlands"; + case Stage.RottenVale: + return "Rotten Vale"; + case Stage.ElderRecess: + return "Elder Recess"; + case Stage.GreatRavine: + return "Great Ravine"; + case Stage.GreatRavineStory: + return "Great Ravine Story"; + case Stage.HoarfrostReach: + return "Hoarfrost Reach"; + case Stage.GuidingLands: + return "Guiding Lands"; + case Stage.InfinityOfNothing: + return "Infinity Of Nothing"; + case Stage.SpecialArena: + return "Special Arena"; + case Stage.ChallengeArena: + return "Challenge Arena"; + case Stage.Astera: + return "Astera"; + case Stage.AsteraHub: + return "Astera Hub"; + case Stage.ResearchBase: + return "Research Base"; + case Stage.Seliana: + return "Seliana"; + case Stage.SelianaHub: + return "Seliana Hub"; + case Stage.Everstream: + return "Everstream"; + case Stage.ConfluenceOfFates: + return "Confluence Of Fates"; + case Stage.CharacterCreation: + return "Character Creation"; + case Stage.DebugMap: + return "Debug Map"; + case Stage.ElDorado: + return "El Dorado"; + case Stage.SelianaSupplyCache: + return "Seliana Supply Cache"; + case Stage.OriginIsleNergigante: + return "Origin Isle Nergigante"; + case Stage.OriginIsleSharaIshvalda: + return "Origin Isle Shara Ishvalda"; + case Stage.SecludedValley: + return "Secluded Valley"; + case Stage.AlatreonStage: + return "Alatreon Stage"; + case Stage.CastleSchrade: + return "Castle Schrade"; + case Stage.LivingQuarters: + return "Living Quarters"; + case Stage.PrivateQuarters: + return "Private Quarters"; + case Stage.PrivateSuite: + return "Private Suite"; + case Stage.TrainingCamp: + return "Training Camp"; + case Stage.ChamberOfFive: + return "Chamber Of Five"; + case Stage.SelianaRoom: + return "Seliana Room"; + } + return "Global (null)"; + } + + /* + public class StageExt + { + Stage s { + get + { + } + set + { + } + }; + } + */ + + public Dictionary> Overrides { get; set; } = new Dictionary>(); } } diff --git a/Plugin.cs b/Plugin.cs index c647785..da94bb8 100755 --- a/Plugin.cs +++ b/Plugin.cs @@ -1,67 +1,2319 @@ -using System.Reflection; +//#define ENABLE_ASSERTS + +using System.Numerics; +using System.Reflection; +using System.Diagnostics; using System.Runtime.Loader; using System.Runtime.InteropServices; -using ImGuiNET; -using SharpPluginLoader.Core; -using SharpPluginLoader.Core.Memory; +using ImGuiNET; +using SharpPluginLoader.Core; +using SharpPluginLoader.Core.Configuration; +using SharpPluginLoader.Core.Memory; +using SharpPluginLoader.Core.Entities; + +// @TODO: +// - Inter-op. +// - Motion blur for freeze. +// - Binds. +// - Lights. +// - Try to understand shadow distance vs backforward distance vs bias. +// - Shadow distance retuning. +// - Descriptions. + +namespace WorldTuningTool +{ + public unsafe class Plugin : IPlugin + { + public string Name => "World Tuning Tool"; + public string Author => "Akon City Software"; + + private static void Assert(bool condition) + { +#if ENABLE_ASSERTS + Trace.Assert(condition); +#endif + } + + private static byte ByteFlag(bool f) { return f ? (byte)0x1 : (byte)0x0; } + + 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)); + } + + public enum ParameterType + { + BOOL, + BYTE, + FLAG, + INT, + HEX, + COLOR, + FLOAT, + VECTOR3, + VECTOR4 + } + + private const float defaultParamWidth = 0.215f; + + public abstract class Parameter + { + public string Name; + private string hiddenName; + public ParameterType Type; + public bool PerFrame; + + private nint offset; + private nint lastAddr = 0x0; + private bool overrideValue = false; + private bool overrideForStage = false; + private bool overrideWasOn = false; + + protected float stepf, minf, maxf; + protected int step, min, max; + protected int mask; + + private Vector4 valueV = default; + private int valueInt = 0; + private Vector4 oValueV; + private int oValueInt; + + private bool pendingUpdate = true; + private bool queuedOverride = false; + private bool queuedValue = false; + private Vector4 qValueV; + private int qValueInt; + + private bool bValue = false; + private Vector4 bValueV; + private int bValueInt; + + public Parameter(string name, nint offset, ParameterType type, bool perFrame) + { + Name = name; + hiddenName = "##" + Name; + this.offset = offset; + Type = type; + PerFrame = perFrame; + } + + public bool PendingUpdate() + { + return pendingUpdate; + } + + public (Vector4, int) GetValue() + { + return (valueV, valueInt); + } + + public int GetMask() + { + return mask; + } + + private void writeCurrentValue() + { + if (lastAddr == 0x0) return; + switch (Type) + { + case ParameterType.BOOL: + case ParameterType.BYTE: + MemoryUtil.GetRef(lastAddr + offset) = (byte)valueInt; + break; + case ParameterType.FLAG: + if (valueInt == 0) + { + MemoryUtil.GetRef(lastAddr + offset) &= ~mask; + } + else + { + MemoryUtil.GetRef(lastAddr + offset) |= mask; + } + break; + case ParameterType.INT: + case ParameterType.HEX: + case ParameterType.COLOR: + MemoryUtil.GetRef(lastAddr + offset) = valueInt; + break; + case ParameterType.FLOAT: + MemoryUtil.GetRef(lastAddr + offset) = valueV.X; + break; + case ParameterType.VECTOR3: + MemoryUtil.GetRef(lastAddr + offset) = new Vector3(valueV.X, valueV.Y, valueV.Z); + break; + case ParameterType.VECTOR4: + MemoryUtil.GetRef(lastAddr + offset) = valueV; + break; + } + } + + 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; + if (!PerFrame) + { + writeCurrentValue(); + } + 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; + bValue = false; + if (!PerFrame) + { + writeCurrentValue(); + } + overrideValue = false; + } + } + overrideForStage = false; + } + + public void OverrideValue(Vector4 v, int i) + { + if (queuedOverride) + { + qValueV = v; + qValueInt = i; + queuedValue = true; + } + else + { + valueV = v; + valueInt = i; + if (!PerFrame) + { + writeCurrentValue(); + } + } + } + + public void Update(nint baseObject) + { + lastAddr = baseObject; + + if (baseObject == 0x0) + { + pendingUpdate = 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 and the override value are the same. + switch (Type) + { + case ParameterType.BOOL: + case ParameterType.BYTE: + { + ref byte b1 = ref MemoryUtil.GetRef(baseObject + offset); + if (b1 != (byte)valueInt && b1 != (byte)oValueInt) + { + oValueInt = (byte)b1; + } + if (overrideValue) + { + b1 = (byte)valueInt; + } + else + { + valueInt = b1; + } + break; + } + case ParameterType.FLAG: + { + ref int i1 = ref MemoryUtil.GetRef(baseObject + offset); + int f1 = i1 & mask; + if (f1 != valueInt && f1 != oValueInt) + { + oValueInt = f1; + } + if (overrideValue) + { + if (f1 == 0) + { + i1 &= ~mask; + } + else + { + i1 |= mask; + } + } + else + { + valueInt = f1; + } + break; + } + case ParameterType.INT: + case ParameterType.HEX: + case ParameterType.COLOR: + { + ref int i1 = ref MemoryUtil.GetRef(baseObject + offset); + if (i1 != valueInt && i1 != oValueInt) + { + oValueInt = i1; + } + if (overrideValue) + { + i1 = valueInt; + } + else + { + valueInt = i1; + } + break; + } + case ParameterType.FLOAT: + { + ref float f1 = ref MemoryUtil.GetRef(baseObject + offset); + if (f1 != valueV.X && f1 != oValueV.X) + { + oValueV.X = f1; + } + if (overrideValue) + { + f1 = valueV.X; + } + else + { + valueV.X = f1; + } + break; + } + case ParameterType.VECTOR3: + { + ref Vector3 v3 = ref MemoryUtil.GetRef(baseObject + offset); + Vector3 valueV3 = new Vector3(valueV.X, valueV.Y, valueV.Z); + if (v3 != valueV3 && v3 != valueV3) + { + oValueV.X = v3.X; + oValueV.Y = v3.Y; + oValueV.Z = v3.Z; + } + if (overrideValue) + { + v3 = valueV3; + } + else + { + valueV.X = v3.X; + valueV.Y = v3.Y; + valueV.Z = v3.Z; + } + break; + } + case ParameterType.VECTOR4: + { + ref Vector4 v4 = ref MemoryUtil.GetRef(baseObject + offset); + if (v4 != valueV && v4 != oValueV) + { + oValueV = v4; + } + if (overrideValue) + { + v4 = valueV; + } + else + { + valueV = v4; + } + break; + } + } + + if (pendingUpdate) + { + pendingUpdate = false; + if (queuedOverride) + { + Assert(!overrideValue); + OverrideOn(overrideForStage); + if (queuedValue) + { + valueV = qValueV; + valueInt = qValueInt; + if (!PerFrame) + { + writeCurrentValue(); + } + queuedValue = false; + } + queuedOverride = false; + } + } + } + + public bool DrawValue(ref Vector4 v4, ref int i1, float width, bool drawLabel) + { + bool valueChanged = false; + string label = drawLabel ? Name : hiddenName; + switch (Type) + { + case ParameterType.BOOL: + { + bool b = i1 == 0x1; + if (ImGui.Checkbox(label, ref b)) + { + i1 = ByteFlag(b); + valueChanged = true; + } + break; + } + case ParameterType.BYTE: + { + ImGui.SetNextItemWidth(width * defaultParamWidth); + ImGuiInputTextFlags flags = ImGuiInputTextFlags.EnterReturnsTrue; + if (ImGui.InputInt(label, ref i1, step, 0, flags)) + { + i1 = Math.Clamp(i1, min, max); + valueChanged = true; + } + break; + } + case ParameterType.INT: + case ParameterType.HEX: + { + ImGui.SetNextItemWidth(width * defaultParamWidth); + ImGuiInputTextFlags flags = ImGuiInputTextFlags.EnterReturnsTrue; + if (Type == ParameterType.HEX) + { + flags |= ImGuiInputTextFlags.CharsHexadecimal; + } + if (ImGui.InputInt(label, ref i1, step, 0, flags)) + { + if (max > min) + { + i1 = Math.Clamp(i1, min, max); + } + valueChanged = true; + } + break; + } + case ParameterType.FLAG: + { + bool b = i1 == mask; + if (ImGui.Checkbox(label, ref b)) + { + i1 = b ? mask : 0; + valueChanged = true; + } + break; + } + case ParameterType.COLOR: + { + ImGui.SetNextItemWidth(width * defaultParamWidth * 3.0f); + Vector4 colorV = ColorVectorFromInt(i1); + if (ImGui.ColorEdit4(label, ref colorV)) + { + i1 = ColorVectorToInt(colorV); + valueChanged = true; + } + break; + } + case ParameterType.FLOAT: + { + ImGui.SetNextItemWidth(width * defaultParamWidth); + float f1 = v4.X; + if (ImGui.DragFloat(label, ref f1, stepf, minf, maxf, "%.5f", ImGuiSliderFlags.NoRoundToFormat)) + { + //if (ImGui.IsItemDeactivatedAfterEdit()) + //{ + v4.X = f1; + valueChanged = true; + //} + } + break; + } + case ParameterType.VECTOR3: + { + ImGui.SetNextItemWidth(width * defaultParamWidth * 3.0f); + Vector3 v3 = new Vector3(v4.X, v4.Y, v4.Z); + if (ImGui.DragFloat3(label, ref v3, stepf, minf, maxf, "%.4f", ImGuiSliderFlags.NoRoundToFormat)) + { + v4.X = v3.X; + v4.Y = v3.Y; + v4.Z = v3.Z; + valueChanged = true; + } + break; + } + case ParameterType.VECTOR4: + { + ImGui.SetNextItemWidth(width * defaultParamWidth * 4.0f); + if (ImGui.DragFloat4(label, ref v4, stepf, minf, maxf, "%.4f", ImGuiSliderFlags.NoRoundToFormat)) + { + valueChanged = true; + } + break; + } + } + return valueChanged; + } + + public void Draw(float width, bool assumeOverride = false) + { + Draw(ref valueV, ref valueInt, width, assumeOverride); + } + + public void Draw(ref Vector4 v4, ref int i1, float width, bool assumeOverride) + { + ImGui.PushID(Name); + if (!assumeOverride) + { + if (overrideForStage) + { + ImGui.PushItemFlag(ImGuiItemFlags.Disabled, true); + ImGui.PushItemFlag(ImGuiItemFlags.MixedValue, true); + } + bool toggleOverride = overrideValue; + if (ImGui.Checkbox("##Override", ref toggleOverride)) + { + if (toggleOverride) + { + OverrideOn(false); + } + else + { + OverrideOff(); + } + } + if (ImGui.BeginItemTooltip()) + { + if (overrideForStage) + { + ImGui.Text("Overridden by Config"); + } + else + { + ImGui.Text("Override Value"); + } + ImGui.EndTooltip(); + } + if (overrideForStage) + { + ImGui.PopItemFlag(); + ImGui.PopItemFlag(); + } + ImGui.SameLine(); + } + if (!overrideValue) + { + ImGui.PushItemFlag(ImGuiItemFlags.Disabled, true); + } + if (DrawValue(ref valueV, ref valueInt, width, !bValue) && !PerFrame) + { + writeCurrentValue(); + } + if (!assumeOverride && overrideValue && !pendingUpdate) + { + 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); + if (!PerFrame) + { + writeCurrentValue(); + } + } + ImGui.SameLine(); + DrawValue(ref bValueV, ref bValueInt, width, true); + ImGui.SameLine(); + if (ImGui.Button("< B")) + { + bValue = false; + } + } + 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: + { + 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(); + } + if (!overrideValue) + { + ImGui.PopItemFlag(); + } + ImGui.PopID(); + } + } + + public class Parameter : Parameter where T : unmanaged + { + public Parameter(string name, nint offset, ParameterType type, bool perFrame, T? step = null, T min = default, T max = default) : base(name, offset, type, perFrame) + { + if (typeof(T) == typeof(float)) + { + this.stepf = step != null ? Convert.ToSingle(step) : 0.01f; + this.minf = Convert.ToSingle(min); + this.maxf = Convert.ToSingle(max); + } + else if (typeof(T) == typeof(int) || typeof(T) == typeof(byte)) + { + this.step = step != null ? Convert.ToInt32(step) : 0; + mask = this.step; + this.min = Convert.ToInt32(min); + this.max = Convert.ToInt32(max); + if (typeof(T) == typeof(byte) && this.min == 0 && this.max == 0) + { + this.min = 0x0; + this.max = 0xFF; + } + } + } + } + + 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) + { + if (param.Name == name) + { + return param; + } + } + return null; + } + + public class Override + { + public Parameter? Param = null; + public string Name + { + get + { + return Param != null ? Param.Name : ""; + } + set + { + Param = getParameterByName(value); + } + } + public string Value + { + get + { + if (Param != null) + { + switch (Param.Type) + { + case ParameterType.BOOL: + return (valueInt == 0x1).ToString(); + case ParameterType.BYTE: + return valueInt.ToString(); + case ParameterType.FLAG: + return (valueInt != 0).ToString(); + case ParameterType.INT: + return valueInt.ToString(); + case ParameterType.HEX: + case ParameterType.COLOR: + return valueInt.ToString("X8"); + case ParameterType.FLOAT: + return valueV.X.ToString(); + case ParameterType.VECTOR3: + { + Vector3 valueV3 = new Vector3(valueV.X, valueV.Y, valueV.Z); + return valueV3.ToString(); + } + case ParameterType.VECTOR4: + return valueV.ToString(); + } + } + return ""; + } + set + { + if (Param == null) return; + try + { + switch (Param.Type) + { + case ParameterType.BOOL: + valueInt = ByteFlag(Convert.ToBoolean(value)); + break; + case ParameterType.BYTE: + valueInt = Convert.ToInt32(value); + break; + case ParameterType.FLAG: + valueInt = Convert.ToBoolean(value) ? Param.GetMask() : 0; + break; + case ParameterType.INT: + valueInt = Convert.ToInt32(value); + break; + case ParameterType.HEX: + case ParameterType.COLOR: + valueInt = Convert.ToInt32(value, 16); + break; + case ParameterType.FLOAT: + valueV.X = Convert.ToSingle(value); + break; + case ParameterType.VECTOR3: + break; + case ParameterType.VECTOR4: + break; + } + } + catch (FormatException) + { + } + catch (OverflowException) + { + } + } + } + private Vector4 valueV = default; + private int valueInt = 0; + private bool isSet = false; + + public void Set() + { + Assert(!isSet); + isSet = true; + if (Param != null) + { + Param.OverrideOn(true); + Param.OverrideValue(valueV, valueInt); + } + } + + public void Unset() + { + Assert(isSet); + isSet = false; + if (Param != null) + { + Param.OverrideOff(); + } + } + + public void Draw(List currentOverrides, List? globalOverrides, float width) + { + ImGui.PushItemWidth(width * 0.35f); + if (ImGui.BeginCombo("##Parameters", Param != null ? Param.Name : "")) + { + foreach (Parameter param in allParameters) + { + if (overridesContainsParam(currentOverrides, param)) + { + continue; + } + bool isSelected = Param == param; + if (ImGui.Selectable(param.Name, isSelected)) + { + bool wasSet = isSet; + if (wasSet) + { + Unset(); + if (globalOverrides != null) + { + if (Param != null) + { + setIfOverridesContainsParam(globalOverrides, Param); + } + unsetIfOverridesContainsParam(globalOverrides, param); + } + } + Param = param; + (valueV, valueInt) = Param.GetValue(); + if (wasSet) Set(); + } + if (isSelected) ImGui.SetItemDefaultFocus(); + } + ImGui.EndCombo(); + } + ImGui.PopItemWidth(); + if (Param != null) + { + ImGui.SameLine(); + if (Param.DrawValue(ref valueV, ref valueInt, width, false) && isSet) + { + Param.OverrideValue(valueV, valueInt); + } + if (isSet && !Param.PendingUpdate() && (valueV, valueInt) != Param.GetValue()) + { + ImGui.SameLine(); + if (ImGui.Button("Set")) + { + Param.OverrideValue(valueV, valueInt); + } + } + } + } + } + + private delegate void OnAreaChange(nint unknownPtr); + private Hook? onAreaChange; + + private static readonly MtObject sMain = SingletonManager.GetSingleton("sMhMain")!; + private static readonly MtObject sMhRender = SingletonManager.GetSingleton("sMhRender")!; + + private static readonly MtObject sMhScene = SingletonManager.GetSingleton("sMhScene")!; + private delegate void UpdateSSAOParams(nint sceneObjectInternal, nint stackOffset); + private Hook? updateSSAOParams; + private static Parameter[] ssaoParameters = { + new Parameter("SSAO Depth Bias", 0xB4B0, ParameterType.FLOAT, false), + new Parameter("SSAO Sloped Depth Bias", 0xB4B4, ParameterType.FLOAT, false), + new Parameter("SSAO Max Depth Bias", 0xB4B8, ParameterType.FLOAT, false), + new Parameter("SSAO Dispersion", 0xB4BC, ParameterType.FLOAT, false), + new Parameter("SSAO Effect", 0xB430, ParameterType.FLOAT, false), + new Parameter("SSAO Effect GI", 0xB434, ParameterType.FLOAT, false), + new Parameter("SSAO Depth Difference", 0xB4C0, ParameterType.FLOAT, false), + new Parameter("SSAO Samples Per Pixel", 0xB4C4, ParameterType.FLOAT, false), + new Parameter("SSAO Max Sample Num", 0xB4C8, ParameterType.INT, false), + new Parameter("SSAO Max Sample Num (HQ)", 0xB4D0, ParameterType.INT, false), + new Parameter("SSAO Radius", 0xB4D4, ParameterType.FLOAT, false), + new Parameter("SSAO Bias", 0xB4D8, ParameterType.FLOAT, false), + new Parameter("SSAO Intensity", 0xB4E0, ParameterType.FLOAT, false), + new Parameter("SSAO Use HiZ", 0xB4E5, ParameterType.BOOL, false), + new Parameter("SSAO Edge Atten Rate", 0xB4DC, ParameterType.FLOAT, false) + }; + private delegate void UpdateSSLRParams(nint stackOffset); + private Hook? updateSSLRParams; + private static Parameter[] sslrParameters = { + new Parameter("SSLR Loop Count", 0xE628, ParameterType.INT, false), + new Parameter("SSLR Loop Count Factor for CBR", 0xE62C, ParameterType.FLOAT, false), + new Parameter("SSLR Eliminate Depth", 0xE630, ParameterType.FLOAT, false), + new Parameter("SSLR Accurate Threshold", 0xE644, ParameterType.FLOAT, false), + new Parameter("SSLR Accurate Threshold (HQ)", 0xE64C, ParameterType.FLOAT, false), + new Parameter("SSLR Dither Radius", 0xE634, ParameterType.FLOAT, false), + new Parameter("SSLR Importance Bias", 0xE638, ParameterType.FLOAT, false), + new Parameter("SSLR Mip Scale", 0xE63C, ParameterType.FLOAT, false), + new Parameter("SSLR Mip Bias", 0xE640, ParameterType.FLOAT, false), + new Parameter("SSLR Dither Resolve", 0xB43F, ParameterType.BOOL, false), + new Parameter("SSLR Edge Atten Rate", 0xB428, ParameterType.FLOAT, false), + new Parameter("SSLR Mip 0 Count Threshold", 0xB438, ParameterType.INT, false, 1), + new Parameter("SSLR Depth Eliminate Rate", 0xB42C, ParameterType.FLOAT, false), + new Parameter("SSLR Use Mipmap", 0xE650, ParameterType.BOOL, false), + new Parameter("SSLR GBuffer Jitter", 0xB440, ParameterType.BOOL, false), + }; + private static Parameter[] sceneParameters = { + new Parameter("HQ Mode", 0xE9A3, ParameterType.BOOL, false), + new Parameter("Shadow Cascade 2Way Bias (HQ)", 0x58, ParameterType.FLOAT, false), + new Parameter("Primary Shadow Sample Num", 0xE5C4, ParameterType.INT, false), + new Parameter("Primary Shadow Sample Num (HQ)", 0xE5CC, ParameterType.INT, false), + new Parameter("Primary Shadow HQ", 0xE5C0, ParameterType.BOOL, false), + new Parameter("Primary Shadow HQ (HQ)", 0xE5C2, ParameterType.BOOL, false), + new Parameter("LOD Bias 1", 0x21C, ParameterType.FLOAT, false), + new Parameter("LOD Bias 2", 0x220, ParameterType.FLOAT, false), + new Parameter("LOD Caster Bias", 0x1E4, ParameterType.FLOAT, false), + new Parameter("LOD Length Bias", 0x1F4, ParameterType.FLOAT, false), + new Parameter("LOD Length Bias (HQ)", 0x1FC, ParameterType.FLOAT, false), + new Parameter("LOD Pixel Size Bias", 0x200, ParameterType.FLOAT, false), + new Parameter("LOD Pixel Size Bias (HQ)", 0x208, ParameterType.FLOAT, false), + new Parameter("LOD Limit", 0xE898, ParameterType.INT, false, 1), + new Parameter("LOD Passthrough Culling Rate", 0x1F0, ParameterType.FLOAT, false), + new Parameter("Far Culling Fade Length Max", 0x20C, ParameterType.FLOAT, false), + new Parameter("Far Culling Fade Pixel Max", 0x210, ParameterType.FLOAT, false), + new Parameter("Speed Tree LOD Billboard Fade Range", 0x214, ParameterType.FLOAT, false), + 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("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), + new Parameter("Passthrough Active", 0xE9A0, ParameterType.BOOL, false), + new Parameter("Passthrough Culling Active", 0xE9A2, ParameterType.BOOL, false), + new Parameter("Passthrough Near", 0xE940, ParameterType.FLOAT, false), + new Parameter("Passthrough Far", 0xE944, ParameterType.FLOAT, false), + new Parameter("Passthrough Near Alpha", 0xE948, ParameterType.FLOAT, false), + new Parameter("Passthrough Far Alpha", 0xE94C, ParameterType.FLOAT, false), + new Parameter("Passthrough Correct", 0xE950, ParameterType.FLOAT, false), + new Parameter("LOD Length Platform Bias[2]", 0x22C + (4 * 2), ParameterType.FLOAT, false), + new Parameter("LOD Pixel Size Platform Bias[2]", 0x244 + (4 * 2), ParameterType.FLOAT, false), + new Parameter("Contact Shadows Enabled", 0xB4EC, ParameterType.BOOL, false), + new Parameter("Force Disable Contact Shadows", 0xB4ED, ParameterType.BOOL, false), + new Parameter("Facial Contact Shadows Enabled", 0xB4EE, ParameterType.BOOL, false), + new Parameter("Contact Shadows Enable Noise", 0xB500, ParameterType.BOOL, false), + new Parameter("Facial Contact Shadows Enable Noise", 0xB501, ParameterType.BOOL, false), + new Parameter("Contact Shadow Intensity", 0xB4F0, ParameterType.FLOAT, false), + new Parameter("Contact Shadow Length", 0xB4F4, ParameterType.FLOAT, false), + new Parameter("Contact Shadow Accept Maximum Length", 0xB4F8, ParameterType.FLOAT, false), + new Parameter("Contact Shadow Accept Minimum Length", 0xB4FC, ParameterType.FLOAT, false), + new Parameter("Capsule AO Enabled", 0xB502, ParameterType.BOOL, false), + 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), + new Parameter("Capsule AO Intensity", 0xE5B8, ParameterType.FLOAT, false), + new Parameter("Accurate Cascade 1 Shadow", 0x44F, ParameterType.BOOL, false), + new Parameter("Broad Area Shadow Enable", 0x5534, ParameterType.BOOL, false), + new Parameter("Broad Area Shadow Center", 0x5540, ParameterType.FLOAT, false), + //new Parameter("Broad Area Shadow Range", 0x5560, ParameterType.FLOAT, false), + new Parameter("Broad Area Shadow Dir", 0x5550, ParameterType.VECTOR4, false), + //new Parameter("Broad Area Shadow Depth Bias", 0x5570, ParameterType.FLOAT, false), + //new Parameter("Broad Area Shadow Sloped Depth Bias", 0x5574, ParameterType.FLOAT, false), + //new Parameter("Broad Area Shadow Max Depth Bias", 0x5578, ParameterType.FLOAT, false), + 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("Checkerboard Alpha Unroll Near", 0xE964, ParameterType.FLOAT, false), + new Parameter("Checkerboard Alpha Unroll Far", 0xE968, ParameterType.FLOAT, false), + new Parameter("Checkerboard History Blend Rate", 0xE96C, ParameterType.FLOAT, false), + new Parameter("Checkerboard Sanitize Color", 0xE972, ParameterType.BOOL, false), + new Parameter("Checkerboard Blend Dither", 0xE973, ParameterType.BOOL, false), + new Parameter("Checkerboard BBox Strength", 0xE974, ParameterType.FLOAT, false), + new Parameter("Checkerboard Dither Passthru Weight", 0xE978, ParameterType.FLOAT, false), + new Parameter("Checkerboard Dither Filtered Weight", 0xE97C, ParameterType.FLOAT, false), + new Parameter("Checkerboard Continous History Reset", 0xE971, ParameterType.BOOL, false), + new Parameter("Snow Field 4 Global LOD Param", 0x5718, ParameterType.FLOAT, false) + }; + + private delegate nint CreateFXAAObject(); + private delegate nint CreateFXAAObject2(nint unknownPtr); + private delegate nint DestroyFXAAObject(nint fxaaObjectInternal, int unknownInt); + private Hook? createFXAAObject; + private Hook? createFXAAObject2; + private Hook? destroyFXAAObject; + private nint fxaaObject = 0x0; + private static Parameter[] fxaaParameters = { + new Parameter("FXAA Subpix", 0x178, ParameterType.FLOAT, false, null, 0.0f, 1.0f), + new Parameter("FXAA Edge Threshold", 0x17C, ParameterType.FLOAT, false, 0.001f, 0.0f, 1.0f), + new Parameter("FXAA Edge Threshold Min", 0x180, ParameterType.FLOAT, false, 0.001f, 0.0f, 1.0f) + }; + + private delegate nint CreateDofObject(); + private delegate nint CreateDofObject2(nint unknownPtr); + private delegate nint DestroyDofObject(nint dofObjectInternal, int unknownInt); + private Hook? createDofObject; + private Hook? createDofObject2; + private Hook? destroyDofObject; + private delegate void UpdateDofParams(nint unknownPtr); + private Hook? updateDofParams; + private nint dofObject = 0x0; + private static Parameter[] dofParameters = { + new Parameter("Enabled", 0x1DD, ParameterType.BOOL, false), + new Parameter("New Version", 0x1DC, ParameterType.BOOL, false), + new Parameter("F Number", 0x1A0, ParameterType.FLOAT, true, 0.001f), + new Parameter("Sensor Size", 0x1A4, ParameterType.FLOAT, true, 0.001f), + new Parameter("Focus Distance", 0x1A8, ParameterType.FLOAT, true, 0.2f), + new Parameter("Near Coef", 0x1CC, ParameterType.FLOAT, false, 0.001f), + new Parameter("Far Coef", 0x1C8, ParameterType.FLOAT, false, 0.001f), + new Parameter("Near Enable", 0x1DE, ParameterType.BOOL, false), + new Parameter("Far Enable", 0x1DF, ParameterType.BOOL, false), + new Parameter("Debug Draw", 0x1E0, ParameterType.BOOL, false), + new Parameter("Radius", 0x1D0, ParameterType.FLOAT, false, 0.001f), + new Parameter("Depth Scale Foreground", 0x1D4, ParameterType.FLOAT, false, 0.0001f), + new Parameter("Aspect", 0x1D8, ParameterType.FLOAT, false, 0.001f), + new Parameter("Vignetting Enabled", 0x200, ParameterType.BOOL, true), + new Parameter("Vignetting Ellipse", 0x201, ParameterType.BOOL, true), + new Parameter("Vignetting Ellipticity", 0x204, ParameterType.FLOAT, true), + new Parameter("Vignetting Offset", 0x1F8, ParameterType.FLOAT, true), + new Parameter("Vignetting Pow", 0x1FC, ParameterType.FLOAT, true), + new Parameter("Vignetting Color", 0x208, ParameterType.COLOR, true) + }; + + private delegate nint CreateMotionBlurObject(); + private delegate nint CreateMotionBlurObject2(nint unknownPtr); + private delegate nint DestroyMotionBlurObject(nint motionBlurObjectInternal, int unknownInt); + private Hook? createMotionBlurObject; + private Hook? createMotionBlurObject2; + private Hook? destroyMotionBlurObject; + private delegate void UpdateMotionBlurParams(nint unknownPtr, nint unknownPtr2); + private Hook? updateMotionBlurParams; + private nint motionBlurObject = 0x0; + private static Parameter[] motionBlurParameters = { + new Parameter("Type", 0x168, ParameterType.INT, false, 1), + new Parameter("Sample Num", 0x180, ParameterType.INT, false, 1), + new Parameter("Shutter Speed", 0x184, ParameterType.FLOAT, true), + new Parameter("Fur Shutter Speed", 0x188, ParameterType.FLOAT, false), + new Parameter("Blur Threshold", 0x18C, ParameterType.FLOAT, false) + }; + + private delegate nint CreateBloomObject(); + private delegate nint CreateBloomObject2(nint unknownPtr); + private delegate nint DestroyBloomObject(nint bloomObjectInternal, int unknownInt); + private Hook? createBloomObject; + private Hook? createBloomObject2; + private Hook? destroyBloomObject; + private nint bloomObject = 0x0; + private static Parameter[] bloomParameters = { + new Parameter("Enabled", 0x48, ParameterType.BOOL, false), + new Parameter("Threshold", 0x204, ParameterType.FLOAT, false), + new Parameter("Renormalize", 0x208, ParameterType.FLOAT, false), + new Parameter("Dispersion for CBR", 0x210, ParameterType.FLOAT, false), + new Parameter("is SRGB Gamut", 0x214, ParameterType.BOOL, false), + new Parameter("Enable Optimize", 0x215, ParameterType.BOOL, false), + new Parameter("Color", 0x200, ParameterType.COLOR, false), + new Parameter("Dirt Color", 0x230, ParameterType.FLOAT, false), + new Parameter("Flip Dirt Intensity", 0x240, ParameterType.BOOL, false), + new Parameter("Downsample Count", 0x168, ParameterType.INT, false), + new Parameter("Reduction Resolution", 0x16C, ParameterType.INT, false), + new Parameter("Compute Luminance", 0x241, ParameterType.BOOL, false) + }; + + 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), + new Parameter("Linear Strength", 0x178, ParameterType.FLOAT, false), + new Parameter("Linear Angle", 0x17C, ParameterType.FLOAT, false), + new Parameter("Toe Strength", 0x180, ParameterType.FLOAT, false), + new Parameter("Toe Num", 0x184, ParameterType.FLOAT, false), + 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("Downsample Volume", 0x210, ParameterType.BOOL, false) + }; + + private delegate void UpdateShadowParams(nint shadowObjectInternal, nint stackOffset); + private Hook? updateShadowParams; + private Hook? staticShadowParams; + private static Parameter[] shadowParameters1 = { + }; + private static Parameter[] shadowParameters2 = { + new Parameter("Color", 0xE0, ParameterType.FLOAT, true), + new Parameter("Intensity", 0xF4, ParameterType.FLOAT, true), + new Parameter("Min Roughness", 0xFC, ParameterType.FLOAT, true), + new Parameter("Dir", 0x110, ParameterType.VECTOR4, true), + new Parameter("Group", 0x14, ParameterType.BYTE, true), + new Parameter("Priority", 0x1A, ParameterType.BYTE, true), + new Parameter("Primary", 0x1D, ParameterType.BOOL, true), + new Parameter("Shadow Cast", 0x23, ParameterType.BOOL, true), + new Parameter("Near Clip Distance", 0x28, ParameterType.FLOAT, true), + new Parameter("Shadow Sloped Depth Bias", 0x40, ParameterType.FLOAT, true, 0.00001f), + new Parameter("Shadow Map Size", 0x30, ParameterType.INT, true), + new Parameter("Shadow Depth Bias", 0x38, ParameterType.FLOAT, true, 0.00001f), + new Parameter("Shadow Max Depth Bias", 0x48, ParameterType.FLOAT, true, 0.00001f), + new Parameter("Do Volumetric", 0x1F, ParameterType.BOOL, true), + new Parameter("Draw Mode", 0x21, ParameterType.BYTE, true), + new Parameter("Shadow Distance", 0x6C, ParameterType.FLOAT, true, 5.0f), + new Parameter("Shadow Backforward Distance", 0x7C, ParameterType.FLOAT, true, 5.0f), + new Parameter("Shadow Distribution", 0x74, ParameterType.FLOAT, true, 0.001f), + new Parameter("Manual Split", 0x4D, ParameterType.BOOL, true), + new Parameter("Individual Shadow Bias", 0x81, ParameterType.BOOL, true), + new Parameter("Manual Split Distance[0]", 0x54, ParameterType.FLOAT, true), + new Parameter("Cascade Depth Bias[0]", 0x88, ParameterType.FLOAT, true, 0.00001f), + new Parameter("Cascade Sloped Depth Bias[0]", 0xA0, ParameterType.FLOAT, true, 0.00001f), + new Parameter("Cascade Max Depth Bias[0]", 0xB8, ParameterType.FLOAT, true, 0.00001f), + new Parameter("Manual Split Distance[1]", 0x5C, ParameterType.FLOAT, true), + new Parameter("Cascade Depth Bias[1]", 0x90, ParameterType.FLOAT, true, 0.00001f), + new Parameter("Cascade Sloped Depth Bias[1]", 0xA8, ParameterType.FLOAT, true, 0.00001f), + new Parameter("Cascade Max Depth Bias[1]", 0xC0, ParameterType.FLOAT, true, 0.00001f), + new Parameter("Manual Split Distance[2]", 0x64, ParameterType.FLOAT, true), + new Parameter("Cascade Depth Bias[2]", 0x98, ParameterType.FLOAT, true, 0.00001f), + new Parameter("Cascade Sloped Depth Bias[2]", 0xB0, ParameterType.FLOAT, true, 0.00001f), + new Parameter("Cascade Max Depth Bias[2]", 0xC8, ParameterType.FLOAT, true, 0.00001f), + new Parameter("Projection Scale", 0x134, ParameterType.FLOAT, true), + new Parameter("Projection Offset Speed", 0x144, ParameterType.FLOAT, true), + new Parameter("Projection Up", 0x160, ParameterType.VECTOR3, true), + new Parameter("Shadow Cascade Mode", 0x174, ParameterType.BYTE, true, 1, 0, 3), + new Parameter("Shadow Cascade 2Way Bias", 0x17C, ParameterType.FLOAT, true), + new Parameter("Shadow Culling Length[0]", 0x184, ParameterType.FLOAT, true), + new Parameter("Shadow Culling Length[1]", 0x18C, ParameterType.FLOAT, true), + new Parameter("Shadow Culling Length[2]", 0x194, ParameterType.FLOAT, true), + new Parameter("Broad Area Shadow Range", 0x1B0, ParameterType.FLOAT, true, 0.0001f), + new Parameter("Broad Area Shadow Depth Bias", 0x1C4, ParameterType.FLOAT, true, 0.0001f), + new Parameter("Broad Area Shadow Sloped Depth Bias", 0x1CC, ParameterType.FLOAT, true, 0.0001f), + new Parameter("Broad Area Shadow Max Depth Bias", 0x1D4, ParameterType.FLOAT, true, 0.0001f), + new Parameter("Primary Shadow Sample Num", 0x1DC, ParameterType.INT, true), + new Parameter("Primary Shadow Radius", 0x1EC, ParameterType.FLOAT, true, 0.0001f), + new Parameter("Fov", 0x1F4, ParameterType.FLOAT, true, 0.0001f), + new Parameter("Is Fixed Fov Mode", 0x1F9, ParameterType.BOOL, true), + new Parameter("Discretization Angle", 0x200, ParameterType.FLOAT, true, 0.0001f), + new Parameter("Is Discretization Fov Mode", 0x205, ParameterType.BOOL, true) + }; + + private static Parameter[] allParameters = sceneParameters + .Concat(ssaoParameters) + .Concat(sslrParameters) + .Concat(fxaaParameters) + .Concat(dofParameters) + .Concat(motionBlurParameters) + .Concat(bloomParameters) + .Concat(lightingParameters) + .Concat(shadowParameters2).ToArray(); + + private bool tripleShadowResolution = false; + private NativeAction setShadowQuality; + private Patch shadowRes1_3x; + private Patch shadowRes1_1; + private Patch shadowRes1_2; + private Patch shadowRes1_3; + private Patch shadowRes2; + private Patch shadowRes3; + private Patch shadowRes4_Limit; + + private void tripleShadowResEnable() + { + shadowRes1_3x.Enable(); + shadowRes1_1.Enable(); + shadowRes1_2.Enable(); + shadowRes1_3.Enable(); + shadowRes2.Enable(); + shadowRes3.Enable(); + //shadowRes4_Limit.Enable(); + } + + private void tripleShadowResDisable() + { + shadowRes1_3x.Disable(); + shadowRes1_1.Disable(); + shadowRes1_2.Disable(); + shadowRes1_3.Disable(); + shadowRes2.Disable(); + shadowRes3.Disable(); + //shadowRes4_Limit.Disable(); + } + + private bool disableVolumeDownsample = false; + private Patch volumeSars1; + private Patch volumeSars2; + private Patch volumeSars3; + private Patch volumeSars4; + private Patch volumeSars5; + private Patch volumeSars6; + private Patch volumeSars7; + private Patch volumeSars8; + private Patch volumeSars9; + + private void disableVolumeDownsampleEnable() + { + volumeSars1.Enable(); + volumeSars2.Enable(); + volumeSars3.Enable(); + volumeSars4.Enable(); + volumeSars5.Enable(); + volumeSars6.Enable(); + volumeSars7.Enable(); + volumeSars8.Enable(); + volumeSars9.Enable(); + } + + private void disableVolumeDownsampleDisable() + { + volumeSars1.Disable(); + volumeSars2.Disable(); + volumeSars3.Disable(); + volumeSars4.Disable(); + volumeSars5.Disable(); + volumeSars6.Disable(); + volumeSars7.Disable(); + volumeSars8.Disable(); + volumeSars9.Disable(); + } + + private bool higherVolumeQuality = false; + private Patch value2ForVolumeQuality; + + private bool disableLODLimits = false; + private Patch defaultViewModeLODLimit; + private Patch defaultViewModeLODLimit_1; + private Patch defaultViewModeLODLimit_2; + + private void disableLODLimitsEnable() + { + defaultViewModeLODLimit.Enable(); + defaultViewModeLODLimit_1.Enable(); + defaultViewModeLODLimit_2.Enable(); + } + + private void disableLODLimitsDisable() + { + defaultViewModeLODLimit.Disable(); + defaultViewModeLODLimit_1.Disable(); + defaultViewModeLODLimit_2.Disable(); + } + + private bool largerFoliageSwayRange = false; + private Patch addressHigherValueForFoliageSway; + + private bool disableReducedRateAnimations = false; + private Patch zeroFrameSkip; + + private class Light + { + public nint Object; + public Parameter[] Parameters = { + new Parameter("Group", 0x13C, ParameterType.BYTE, false, 1), + new Parameter("Position", 0x5A0, ParameterType.VECTOR3, true, 0.1f), + new Parameter("Intensity", 0x8A8, ParameterType.FLOAT, true, 0.1f), + new Parameter("Radius", 0x6A0, ParameterType.FLOAT, true, 0.1f), + new Parameter("Depth Bias", 0x57C, ParameterType.FLOAT, true, 0.00001f), + new Parameter("Sloped Depth Bias", 0x580, ParameterType.FLOAT, true, 0.00001f), + new Parameter("Max Depth Bias", 0x584, ParameterType.FLOAT, true, 0.00001f), + new Parameter("Color", 0x140, ParameterType.COLOR, true), + new Parameter("Cone", 0x5F0, ParameterType.FLOAT, true, 0.1f), + new Parameter("Spread", 0x5F4, ParameterType.FLOAT, true, 0.1f), + new Parameter("Shadow Cast", 0x138, ParameterType.FLAG, false, (1 << 23)), + new Parameter("Draw Mode", 0x48, ParameterType.BYTE, false, 1), + new Parameter("Target Mode", 0x5F8, ParameterType.BOOL, true), + new Parameter("Do Volumetric", 0x590, ParameterType.BOOL, true), + new Parameter("Use Umbra", 0x591, ParameterType.BOOL, true), + new Parameter("Enable Camera LOD", 0x592, ParameterType.BOOL, true) + }; + + public Light(nint lightObject, Vector3 pos) + { + Object = lightObject; + foreach (Parameter param in Parameters) + { + param.OverrideOn(false); + } + Parameters[0].OverrideValue(default, 3); + Parameters[1].OverrideValue(new Vector4(pos.X, pos.Y, pos.Z, 0.0f), 0); + Parameters[2].OverrideValue(new Vector4(10.0f, 0.0f, 0.0f, 0.0f), 0); + foreach (Parameter param in Parameters) + { + param.Update(lightObject); + } + } + } + + private int requestLightType = 2; + private NativeFunction createLight; + private List ourLights = new List(); + private NativeAction addToScene; + private NativeAction removeFromScene; + private delegate void UpdateLights(nint lightObject); + private Hook? updateLights; + + public PluginData Initialize() + { + onAreaChange = Hook.Create(0x141AC27D0, OnAreaChangeHook); // nint + + // These run during cutscenes. + updateSSAOParams = Hook.Create(0x1416D8B10, UpdateSSAOParamsHook); // nint, nint + updateSSLRParams = Hook.Create(0x1416DA3F0, UpdateSSLRParamsHook); // nint + + createFXAAObject = Hook.Create(0x142393560, CreateFXAAObjectHook); + createFXAAObject2 = Hook.Create(0x142393680, CreateFXAAObject2Hook); // nint + destroyFXAAObject = Hook.Create(0x142393740, DestroyFXAAObjectHook); // nint, int + + createDofObject = Hook.Create(0x142421E80, CreateDofObjectHook); + createDofObject2 = Hook.Create(0x1424220A0, CreateDofObject2Hook); // nint + destroyDofObject = Hook.Create(0x142422290, DestroyDofObjectHook); // nint, int + updateDofParams = Hook.Create(0x1412BA6A0, UpdateDofParamsHook); // nint + + createMotionBlurObject = Hook.Create(0x1424C95E0, CreateMotionBlurObjectHook); + createMotionBlurObject2 = Hook.Create(0x1424C9740, CreateMotionBlurObject2Hook); // nint + destroyMotionBlurObject = Hook.Create(0x1424C97E0, DestroyMotionBlurObjectHook); // nint, int + updateMotionBlurParams = Hook.Create(0x1424CADF0, UpdateMotionBlurParamsHook); // nint, nint + + createBloomObject = Hook.Create(0x1424CB3C0, CreateBloomObjectHook); + createBloomObject2 = Hook.Create(0x1424CB5E0, CreateBloomObject2Hook); // nint + destroyBloomObject = Hook.Create(0x1424CB750, DestroyBloomObjectHook); // nint, int + + createLightingObject = Hook.Create(0x1424CDE20, CreateLightingObjectHook); + destroyLightingObject = Hook.Create(0x1424CE380, DestroyLightingObjectHook); // nint, int + + nint 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. + 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. + ]); + + 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, + 0xC7, 0x81, 0x20, 0x55, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0xC3, + 0xC7, 0x81, 0x20, 0x55, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0xC3, + 0xC7, 0x81, 0x20, 0x55, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0xC3 + ]); + + 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. + 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. + ]); + + volumeSars1 = new Patch((nint)0x1424D0159, [0x90, 0x90]); + volumeSars2 = new Patch((nint)0x1424D01A0, [0x90, 0x90]); + volumeSars3 = new Patch((nint)0x1424D01C6, [0x90, 0x90]); + volumeSars4 = new Patch((nint)0x1424D0219, [0x90, 0x90]); + volumeSars5 = new Patch((nint)0x1424D0242, [0x90, 0x90]); + volumeSars6 = new Patch((nint)0x1424D029D, [0x90, 0x90]); + volumeSars7 = new Patch((nint)0x1424D02C6, [0x90, 0x90]); + volumeSars8 = new Patch((nint)0x1424D0321, [0x90, 0x90]); + volumeSars9 = new Patch((nint)0x1424D034A, [0x90, 0x90]); + + value2ForVolumeQuality = new Patch((nint)0x142389652, [0xB8, 0x02, 0x00, 0x00, 0x00, 0x90]); + + // 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 + ssert(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]); + + 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. + zeroFrameSkip = new Patch((nint)0x142246948, [0x31, 0xC0, 0x90, 0x90, 0x90, 0x90]); + + // The game will crash when trying to switch to the FULL_RES path for SSR. It's likley because + // it tries to access resources (shader, buffer, texture, etc.) that are not loaded. + // Ex: MonsterHunterWorld.exe+228C4A7 - mov rdi,[rdi+00000120] # Attempted read. + // MonsterHunterWorld.exe+259329B - lea rcx,[rdi+00000120] # Zero. + // The code that zero's these addresses looks like a shell of where they would be loaded. So my assumption + // is that it's compiled out and that this method of increasing the SSR resolution will not work. + // Though, it may still be possible by finagling the parameters of the half res case. + /* + // Attempt to forcefully enable FULL_RES path for SSR. + ssrRes1 = new Patch((nint)0x14228894D, [0x0F, 0x85, 0xB9, 0xAA, 0x30, 0x00]); + ssrRes1_1 = new Patch((nint)0x14259340C, [0xC6, 0x81, 0x28, 0x02, 0x00, 0x00, 0x00, 0x90, 0x90, 0x90]); + ssrRes2 = new Patch((nint)0x14228897D, [0x0F, 0x85, 0x99, 0xAA, 0x30, 0x00]); + ssrRes2_1 = new Patch((nint)0x14259341C, [0xC6, 0x81, 0x30, 0x02, 0x00, 0x00, 0x00, 0x90, 0x90, 0x90]); + ssrRes3 = new Patch((nint)0x1422889AD, [0x0F, 0x85, 0x79, 0xAA, 0x30, 0x00]); + ssrRes3_1 = new Patch((nint)0x14259342C, [0xC6, 0x81, 0x2C, 0x02, 0x00, 0x00, 0x00, 0x90, 0x90, 0x90]); + ssrRes4 = new Patch((nint)0x14259268C, [0x41, 0xC7, 0x86, 0x28, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0xC7, 0x86, 0x2C, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0xC7, 0x86, 0x30, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0xC7, 0x86, 0x34, 0x02, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x41, 0xC7, 0x86, 0x38, 0x02, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3F, 0x41, 0xC6, 0x86, 0x3C, 0x02, 0x00, 0x00, 0x01]); + */ + // None of these work either. + /* + // Don't scale resolution by SSR Factor. + ssrRes10 = new Patch((nint)0x142592DEF, [0x90, 0x90, 0x90, 0x90]); + ssrRes11 = new Patch((nint)0x142592E00, [0x90, 0x90, 0x90, 0x90]); + + // Make SSR Factor 1.0. + ssrRes12 = new Patch((nint)0x1425926B8 + 0x7, [0x00, 0x00, 0x80, 0x3F]); + */ + /* Double width and height (3rd and 4th parameter). + initSSRHook = Hook.Create(0x1425924D5, InitSSRHook); // nint, nint, int, int + increaseSSRMipSize1 = new Patch((nint)0x142592EBA + 0x2, [0x2]); + increaseSSRMipSize2 = new Patch((nint)0x142592ED0 + 0x2, [0x2]); + */ + + createLight = new NativeFunction(0x1418A3EF0); + addToScene = new NativeAction(0x142219070); + removeFromScene = new NativeAction(0x142228F10); + updateLights = Hook.Create(0x141F88F30, UpdateLightsHook); + + return new PluginData(); + } + + public void OnLoad() + { + Config config = ConfigManager.GetConfig(this); + foreach (Stage area in Enum.GetValues(typeof(Stage))) + { + if (!config.Overrides.ContainsKey(area)) + { + config.Overrides.Add(area, new List()); + } + } + List globalOverrides = config.Overrides[Stage.InfinityOfNothingHandler]; + foreach (Override ovG in globalOverrides) + { + ovG.Set(); + } + ConfigManager.SaveConfig(this); + } + + public void OnUpdate(float deltaTime) + { + if (fxaaObject != 0x0) + { + foreach (Parameter param in fxaaParameters) + { + if (!param.PerFrame) + { + param.Update(fxaaObject); + } + } + } + if (dofObject != 0x0) + { + foreach (Parameter param in dofParameters) + { + if (!param.PerFrame) + { + param.Update(dofObject); + } + } + } + if (motionBlurObject != 0x0) + { + foreach (Parameter param in motionBlurParameters) + { + if (!param.PerFrame) + { + param.Update(motionBlurObject); + } + } + } + if (bloomObject != 0x0) + { + foreach (Parameter param in bloomParameters) + { + if (!param.PerFrame) + { + param.Update(bloomObject); + } + } + } + if (lightingObject != 0x0) + { + foreach (Parameter param in lightingParameters) + { + if (!param.PerFrame) + { + param.Update(lightingObject); + } + } + } + if (sMhScene.Instance != 0x0) + { + foreach (Parameter param in ssaoParameters) + { + if (!param.PerFrame) + { + param.Update(sMhScene.Instance); + } + } + foreach (Parameter param in sslrParameters) + { + if (!param.PerFrame) + { + param.Update(sMhScene.Instance); + } + } + foreach (Parameter param in sceneParameters) + { + if (!param.PerFrame) + { + param.Update(sMhScene.Instance); + } + } + } + } + + private void UpdateSSAOParamsHook(nint sceneObjectInternal, nint stackOffset) + { + updateSSAOParams!.Original(sceneObjectInternal, stackOffset); + foreach (Parameter param in ssaoParameters) + { + param.Update(sMhScene.Instance); + } + } + + private void UpdateSSLRParamsHook(nint stackOffset) + { + updateSSLRParams!.Original(stackOffset); + foreach (Parameter param in sslrParameters) + { + param.Update(sMhScene.Instance); + } + } + + private nint CreateFXAAObjectHook() + { + fxaaObject = createFXAAObject!.Original(); + foreach (Parameter param in fxaaParameters) + { + param.Update(fxaaObject); + } + return fxaaObject; + } + + private nint CreateFXAAObject2Hook(nint unknownPtr) + { + fxaaObject = createFXAAObject2!.Original(unknownPtr); + foreach (Parameter param in fxaaParameters) + { + param.Update(fxaaObject); + } + return fxaaObject; + } + + private nint DestroyFXAAObjectHook(nint fxaaObjectInternal, int unknownInt) + { + Assert(unknownInt == 1); + if (fxaaObject == fxaaObjectInternal) + { + fxaaObject = 0x0; + foreach (Parameter param in fxaaParameters) + { + param.Update(fxaaObject); + } + } + return destroyFXAAObject!.Original(fxaaObjectInternal, unknownInt); + } + + private nint CreateDofObjectHook() + { + dofObject = createDofObject!.Original(); + foreach (Parameter param in dofParameters) + { + param.Update(dofObject); + } + return dofObject; + } -namespace WorldTuningTool -{ - public unsafe class Plugin : IPlugin - { - public string Name => "World Tuning Tool"; - public string Author => "Akon City Software"; + private nint CreateDofObject2Hook(nint unknownPtr) + { + dofObject = createDofObject2!.Original(unknownPtr); + foreach (Parameter param in dofParameters) + { + param.Update(dofObject); + } + return dofObject; + } + + private nint DestroyDofObjectHook(nint dofObjectInternal, int unknownInt) + { + Assert(unknownInt == 1); + if (dofObject == dofObjectInternal) + { + dofObject = 0x0; + foreach (Parameter param in dofParameters) + { + param.Update(dofObject); + } + } + return destroyDofObject!.Original(dofObjectInternal, unknownInt); + } + + private void UpdateDofParamsHook(nint unknownPtr) + { + updateDofParams!.Original(unknownPtr); + foreach (Parameter param in dofParameters) + { + if (param.PerFrame) + { + param.Update(dofObject); + } + } + } + + private nint CreateMotionBlurObjectHook() + { + motionBlurObject = createMotionBlurObject!.Original(); + foreach (Parameter param in motionBlurParameters) + { + param.Update(motionBlurObject); + } + return motionBlurObject; + } - // @TODO: - // - Port FXAA object. - // - Port some stuff as is. - // - OnAreaChange. - // - Shadow distance retuning. - // - Work out obvious simplifications. - // - sMhRenderer vs common parameter address. - // - Overrides system. - // - Pass on LODs. - // - Verbose descriptions. - // - Re-implement shadow res override for hoarfrost. - // - Exact float flag for hex input? + private nint CreateMotionBlurObject2Hook(nint unknownPtr) + { + motionBlurObject = createMotionBlurObject2!.Original(unknownPtr); + foreach (Parameter param in motionBlurParameters) + { + param.Update(motionBlurObject); + } + return motionBlurObject; + } - private bool dofDisabled = false; - private Patch jmpOverDof; + private nint DestroyMotionBlurObjectHook(nint motionBlurObjectInternal, int unknownInt) + { + Assert(unknownInt == 1); + if (motionBlurObject == motionBlurObjectInternal) + { + motionBlurObject = 0x0; + foreach (Parameter param in motionBlurParameters) + { + param.Update(motionBlurObject); + } + } + return destroyMotionBlurObject!.Original(motionBlurObjectInternal, unknownInt); + } - public void SetDofForceOff(bool off) + private void UpdateMotionBlurParamsHook(nint unknownPtr, nint unknownPtr2) { - if (off && !dofDisabled) + foreach (Parameter param in motionBlurParameters) { - jmpOverDof.Enable(); + if (param.PerFrame) + { + param.Update(motionBlurObject); + } } - else if (!off && dofDisabled) + updateMotionBlurParams!.Original(unknownPtr, unknownPtr2); + } + + private nint CreateBloomObjectHook() + { + bloomObject = createBloomObject!.Original(); + foreach (Parameter param in bloomParameters) { - jmpOverDof.Disable(); + param.Update(bloomObject); } - dofDisabled = off; + return bloomObject; } - public bool GetDofDisabled() + private nint CreateBloomObject2Hook(nint unknownPtr) { - return dofDisabled; + bloomObject = createBloomObject2!.Original(unknownPtr); + foreach (Parameter param in bloomParameters) + { + param.Update(bloomObject); + } + return bloomObject; } - /* - public PluginData Initialize() + private nint DestroyBloomObjectHook(nint bloomObjectInternal, int unknownInt) { - PluginData data = new PluginData(); - data.ExportedFunctions.Add(("SetDofForceOff", SetDofForceOff)); - data.ExportedFunctions.Add(("GetDofDisabled", GetDofDisabled)); - return data; + Assert(unknownInt == 1); + if (bloomObject == bloomObjectInternal) + { + bloomObject = 0x0; + foreach (Parameter param in bloomParameters) + { + param.Update(bloomObject); + } + } + return destroyBloomObject!.Original(bloomObjectInternal, unknownInt); } - */ - public void OnPreMain() + private nint CreateLightingObjectHook() { - unchecked + lightingObject = createLightingObject!.Original(); + foreach (Parameter param in lightingParameters) + { + param.Update(lightingObject); + } + return lightingObject; + } + + private nint DestroyLightingObjectHook(nint lightingObjectInternal, int unknownInt) + { + Assert(unknownInt == 1); + if (lightingObject == lightingObjectInternal) + { + lightingObject = 0x0; + foreach (Parameter param in lightingParameters) + { + param.Update(lightingObject); + } + } + return destroyLightingObject!.Original(lightingObjectInternal, unknownInt); + } + + private void UpdateShadowParamsHook(nint shadowObjectInternal, nint stackOffset) + { + ref nint rax = ref MemoryUtil.GetRef(stackOffset + 0x170); + nint shadowCascadeMode = rax >> 32; + bool firstPass = shadowCascadeMode == 3; + + if (firstPass) + { + } + else + { + foreach (Parameter param in shadowParameters2) + { + param.Update(stackOffset); + } + } + + updateShadowParams!.Original(shadowObjectInternal, stackOffset); + } + + private void StaticShadowParamsHook(nint shadowObjectStatic, nint shadowObjectInternal) + { + if (shadowObjectInternal == 0x0) + { + foreach (Parameter param in shadowParameters1) + { + param.Update(shadowObjectStatic); + } + } + staticShadowParams!.Original(shadowObjectStatic, shadowObjectInternal); + } + + private Stage previousStage = Stage.InfinityOfNothingHandler; + private Stage selectedStage = Stage.InfinityOfNothingHandler; + private static bool stageIsGlobal(Stage stage) + { + return stage == Stage.InfinityOfNothingHandler; + } + + private void OnAreaChangeHook(nint unknownPtr) + { + onAreaChange!.Original(unknownPtr); + Stage stage = Area.CurrentStage; + if (stage == 0x0) + { + stage = Stage.InfinityOfNothingHandler; + } + if (stage == previousStage) return; + Config config = ConfigManager.GetConfig(this); + List prevOverrides = config.Overrides[previousStage]; + previousStage = stage; + List? globalOverrides = null; + if (!stageIsGlobal(stage)) + { + globalOverrides = config.Overrides[Stage.InfinityOfNothingHandler]; + } + foreach (Override ovP in prevOverrides) + { + ovP.Unset(); + if (globalOverrides != null && ovP.Param != null) + { + setIfOverridesContainsParam(globalOverrides, ovP.Param); + } + } + if (globalOverrides != null) // Stage isn't global. + { + List stageOverrides = config.Overrides[stage]; + foreach (Override ovS in stageOverrides) + { + if (ovS.Param != null) + { + unsetIfOverridesContainsParam(globalOverrides, ovS.Param); + } + 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); + } + } + } + + public void OnImGuiRender() + { + float width = ImGui.GetWindowWidth(); + width /= (width / 600.0f); + + if (ImGui.CollapsingHeader("Lights")) + { + ImGui.PushItemWidth(width * 0.25f); + ImGui.InputInt("Type", ref requestLightType, 1); + ImGui.SameLine(); + if (ImGui.Button("New")) + { + nint lightObject = createLight.Invoke(requestLightType); + Vector3 pos = default; + Player? player = Player.MainPlayer; + if (player != null) + { + pos = player.Position; + pos.Y += 20.0f; + } + ourLights.Add(new Light(lightObject, pos)); + // mov byte ptr[rsp+20],00 unaccounted for, hopefully it doesn't matter. + addToScene.Invoke(MemoryUtil.Read(0x1451238C8), 0x16, lightObject, 0x0); + } + ImGui.PopItemWidth(); + ImGui.Separator(); + for (int i = 0; i < ourLights.Count; i++) + { + Light light = ourLights[i]; + ImGui.PushID(i); + ImGui.Text($"Address: {light.Object:X}"); + foreach (Parameter param in light.Parameters) + { + param.Draw(width, true); + } + if (ImGui.Button("Remove")) + { + /* + nint vTable = MemoryUtil.Read(lightObject); + NativeAction freeLight = new NativeAction(MemoryUtil.Read(vTable)); + freeLight.Invoke(lightObject, 1); + */ + // removeFromScene triggers destructor. + removeFromScene.Invoke(light.Object); + ourLights.RemoveAt(i); + i--; + } + ImGui.PopID(); + ImGui.Separator(); + } + } + + /* + if (ImGui.TextLink($"Current Stage: {Config.StageToString(Area.CurrentStage)}")) + { + if (Area.CurrentStage == 0) + { + selectedStage = Stage.InfinityOfNothingHandler; + } + else + { + selectedStage = Area.CurrentStage; + } + } + */ + ImGui.Text($"Current Stage: {Config.StageToString(Area.CurrentStage)}"); + + ImGui.PushItemWidth(width * 0.35f); + if (ImGui.BeginCombo("##Stage", Config.StageToString(selectedStage))) + { + foreach (Stage area in Enum.GetValues(typeof(Stage))) + { + string name = Config.StageToString(area); + bool isSelected = selectedStage == area; + if (ImGui.Selectable(name, isSelected)) + { + selectedStage = area; + } + if (isSelected) ImGui.SetItemDefaultFocus(); + } + ImGui.EndCombo(); + } + ImGui.SameLine(); + if (ImGui.Button("Current")) + { + if (Area.CurrentStage != 0x0) + { + selectedStage = Area.CurrentStage; + } + else + { + selectedStage = Stage.InfinityOfNothingHandler; + } + } + ImGui.SameLine(); + if (ImGui.Button("Global")) + { + selectedStage = Stage.InfinityOfNothingHandler; + } + Config config = ConfigManager.GetConfig(this); + List stageOverrides = config.Overrides[selectedStage]; + List? globalOverrides = null; + if (!stageIsGlobal(selectedStage)) + { + globalOverrides = config.Overrides[Stage.InfinityOfNothingHandler]; + } + if (ImGui.Button("Add override")) + { + Override ov = new Override(); + if (Area.CurrentStage == selectedStage || stageIsGlobal(selectedStage)) + { + ov.Set(); + } + stageOverrides.Add(ov); + } + ImGui.PopItemWidth(); + for (int i = 0; i < stageOverrides.Count; i++) + { + Override ovS = stageOverrides[i]; + ImGui.PushID(i); + 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) + { + (stageOverrides[i], stageOverrides[i + 1]) = (stageOverrides[i + 1], stageOverrides[i]); + } + ovS.Draw(stageOverrides, globalOverrides, width); + if (requestUp && i > 0) + { + (stageOverrides[i], stageOverrides[i - 1]) = (stageOverrides[i - 1], stageOverrides[i]); + } + if (requestRemove) + { + ovS.Unset(); + if (globalOverrides != null && ovS.Param != null) + { + setIfOverridesContainsParam(globalOverrides, ovS.Param); + } + stageOverrides.RemoveAt(i); + i--; + } + ImGui.PopID(); + } + if (ImGui.Button("Save")) + { + ConfigManager.SaveConfig(this); + } + + if (ImGui.CollapsingHeader("Patches")) + { + if (ImGui.Checkbox("3x Shadow Resolution", ref tripleShadowResolution)) + { + if (tripleShadowResolution) + { + tripleShadowResEnable(); + } + else + { + tripleShadowResDisable(); + } + setShadowQuality.Invoke(MemoryUtil.Read(sMhScene.Instance + 0x5530) + 1); + } + if (ImGui.BeginItemTooltip()) + { + ImGui.Text("In-Game Settings:\n - High: 1.0 -> 3.0\n - Mid: 0.7 -> 2.1\n - Low: 0.5 -> 1.5"); + ImGui.EndTooltip(); + } + + if (ImGui.Checkbox("Volume Rendering Full Resolution Blur Pass (Requires Area Change)", ref disableVolumeDownsample)) + { + if (disableVolumeDownsample) + { + disableVolumeDownsampleEnable(); + } + else + { + disableVolumeDownsampleDisable(); + } + } + if (ImGui.BeginItemTooltip()) + { + ImGui.Text("This can get rid of excessive aliasing when something is in front of a volumetric effect.\nMove to a different area one time for this to apply, it will stay applied after that."); + ImGui.EndTooltip(); + } + + if (ImGui.Checkbox("Higher Than \"Highest\" Volume Rendering Quality", ref higherVolumeQuality)) + { + if (higherVolumeQuality) + { + value2ForVolumeQuality.Enable(); + } + else + { + value2ForVolumeQuality.Disable(); + } + } + if (ImGui.BeginItemTooltip()) + { + ImGui.Text("*Extremely Resource Intensive* Only noticeable effect is likely in areas that had visible breakup with Volume Rendering Quality: Highest.\nThis takes mostly the same path as Highest."); + ImGui.EndTooltip(); + } + + if (ImGui.Checkbox("Disable Player/Palico/NPC LOD Limit in Gameplay", ref disableLODLimits)) + { + if (disableLODLimits) + { + disableLODLimitsEnable(); + } + else + { + disableLODLimitsDisable(); + } + } + if (ImGui.BeginItemTooltip()) + { + ImGui.Text("This will make the default (gameplay) LOD limits equivalent to View Mode. Disabling the limit on:\n - Player Models & Shadows\n - Palico Models & Shadows\n - NPC Models & Shadows\n - Simple NPC Models & Shadows\nAlso equivalent to the settings applied in your room with the addition of disabled Simple NPC limits."); + ImGui.EndTooltip(); + } + + if (ImGui.Checkbox("Larger Foliage Sway Range", ref largerFoliageSwayRange)) + { + if (largerFoliageSwayRange) + { + addressHigherValueForFoliageSway.Enable(); + } + else + { + addressHigherValueForFoliageSway.Disable(); + } + } + if (ImGui.BeginItemTooltip()) + { + ImGui.Text("Increase the distance at which Foliage Sway is still applied to lower priority plants."); + ImGui.EndTooltip(); + } + + if (ImGui.Checkbox("Disable Reduced Rate Animations", ref disableReducedRateAnimations)) + { + if (disableReducedRateAnimations) + { + zeroFrameSkip.Enable(); + } + else + { + zeroFrameSkip.Disable(); + } + } + if (ImGui.BeginItemTooltip()) + { + ImGui.Text("Ignore the frame skip set on an animal's animation when are far from the camera."); + ImGui.EndTooltip(); + } + } + + if (ImGui.CollapsingHeader("Parameters")) + { + if (ImGui.CollapsingHeader("FXAA Parameters")) + { + ImGui.PushID("FXAA"); + ImGui.Text($"Address: {fxaaObject:X}"); + if (fxaaObject != 0x0) + { + foreach (Parameter param in fxaaParameters) + { + param.Draw(width); + } + } + ImGui.PopID(); + } + + if (ImGui.CollapsingHeader("Depth of Field Parameters")) + { + ImGui.PushID("DepthOfField"); + ImGui.Text($"Address: {dofObject:X}"); + if (dofObject != 0x0) + { + foreach (Parameter param in dofParameters) + { + param.Draw(width); + } + } + ImGui.PopID(); + } + + if (ImGui.CollapsingHeader("Motion Blur Parameters")) + { + ImGui.PushID("MotionBlur"); + ImGui.Text($"Address: {motionBlurObject:X}"); + if (motionBlurObject != 0x0) + { + foreach (Parameter param in motionBlurParameters) + { + param.Draw(width); + } + } + } + + if (ImGui.CollapsingHeader("Bloom Parameters")) + { + ImGui.PushID("Bloom"); + ImGui.Text($"Address: {bloomObject:X}"); + if (bloomObject != 0x0) + { + foreach (Parameter param in bloomParameters) + { + param.Draw(width); + } + } + } + + if (ImGui.CollapsingHeader("Lighting Parameters")) + { + ImGui.PushID("Lighting"); + ImGui.Text($"Address: {lightingObject:X}"); + if (lightingObject != 0x0) + { + foreach (Parameter param in lightingParameters) + { + param.Draw(width); + } + } + ImGui.PopID(); + } + + if (ImGui.CollapsingHeader("Shadow Parameters")) + { + ImGui.PushID("Shadows"); + // MonsterHunterWorld.exe+1AB99E0 - mov rax,[MonsterHunterWorld.exe+500E180] + nint shadowAddr = MemoryUtil.Read(0x14500E180); + nint shadowObject = MemoryUtil.Read(shadowAddr + 0x4B0); + shadowAddr += 0x5B0; + ImGui.Text($"Address: {shadowAddr:X}, Object: {shadowObject:X}"); + /* + if (ImGui.CollapsingHeader("Pass 1")) + { + ImGui.PushID("Pass1"); + foreach (Parameter param in shadowParameters1) + { + param.Draw(width); + } + ImGui.PopID(); + } + if (ImGui.CollapsingHeader("Pass 2")) + { + ImGui.PushID("Pass2"); + */ + foreach (Parameter param in shadowParameters2) + { + param.Draw(width); + } + /* + ImGui.PopID(); + } + */ + ImGui.PopID(); + } + + if (ImGui.CollapsingHeader("SSAO Parameters")) + { + ImGui.PushID("SSAO"); + ImGui.Text($"Address: {sMhScene.Instance:X}"); + foreach (Parameter param in ssaoParameters) + { + param.Draw(width); + } + ImGui.PopID(); + } + + if (ImGui.CollapsingHeader("SSLR Parameters")) + { + ImGui.PushID("SSLR"); + ImGui.Text($"Address: {sMhScene.Instance:X}"); + foreach (Parameter param in sslrParameters) + { + param.Draw(width); + } + ImGui.PopID(); + } + + if (ImGui.CollapsingHeader("Scene Parameters")) + { + ImGui.PushID("Scene"); + ImGui.Text($"Address: {sMhScene.Instance:X}"); + foreach (Parameter param in sceneParameters) + { + param.Draw(width); + } + ImGui.PopID(); + } + } + + if (ImGui.CollapsingHeader("DEBUG")) { - jmpOverDof = new Patch((nint)0x1424233C6, [0xEB]); // je -> jmp. + ImGui.PushItemWidth(width * 0.15f); + ImGui.Text($"FPS: {MemoryUtil.GetRef(sMain.Instance + 0x68)}"); + ImGui.Text($"Delta Time: {MemoryUtil.GetRef(sMain.Instance + 0x94)}"); + // Locations taken from MHW-DTI-Dumps/wip_dump_15_20_00.h. + ImGui.InputFloat("Simulation FPS", ref MemoryUtil.GetRef(sMain.Instance + 0x58)); + if (ImGui.BeginItemTooltip()) + { + ImGui.Text("This does not apply to jiggle physics."); + ImGui.EndTooltip(); + } + ImGui.InputFloat("Max FPS", ref MemoryUtil.GetRef(sMain.Instance + 0x5C)); + ImGui.PopItemWidth(); } } @@ -143,34 +2395,13 @@ namespace WorldTuningTool Log.Info("Face shader replaced."); } } - /* - else if (hash == "d7e47ffe-82572c64-795c4698-341e5b91") - { - if (replaceShaderFromFile(info, $"{shaderPath}/sslr_mips.shdr")) { - info->Replacement.Type = ShaderSourceType.BINARY; - Log.Info("SSLR mips shader replaced."); - } - } - */ - } - - public void OnLoad() - { - } - - public void OnImGuiRender() - { - if (ImGui.Checkbox("Disable Depth of Field", ref dofDisabled)) - { - if (dofDisabled) - { - jmpOverDof.Enable(); - } - else - { - jmpOverDof.Disable(); - } - } + //else if (hash == "d7e47ffe-82572c64-795c4698-341e5b91") + //{ + // if (replaceShaderFromFile(info, $"{shaderPath}/sslr_mips.shdr")) { + // info->Replacement.Type = ShaderSourceType.BINARY; + // Log.Info("SSLR mips shader replaced."); + // } + //} } } } diff --git a/Scripts/generate_diffs.sh b/Scripts/generate_diffs.sh index d7e0d70..fa95217 100755 --- a/Scripts/generate_diffs.sh +++ b/Scripts/generate_diffs.sh @@ -3,6 +3,8 @@ # https://github.com/bo3b/3Dmigoto # Disassemble: cmd_Decompiler.exe -d shader.dxbc (saved from RenderDoc). # Assemble: cmd_Decompiler.exe -a shader.asm (edited) +# +# Compile: dxc.exe shader.hlsl -T [v|p|c]s_5_0 #wine cmd_Decompiler.exe -d ../Shaders/Original/*.dxbc #wine cmd_Decompiler.exe -d ../Shaders/*.shdr -- cgit v1.2.3-101-g0448