//#define ENABLE_ASSERTS //#define ADDR_ASSERTS //#define SHADER_FEATURES 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.Resources; using SharpPluginLoader.Core.Configuration; using SharpPluginLoader.Core.Memory; using SharpPluginLoader.Core.Entities; // @TODO: // - Inter-op. // - Lights. // - float format. // - Override presets. // - Centeralize transition from global to stage. // - Try to understand shadow distance vs backforward distance vs bias. // - Re-evaluate volume upsample shaders. // - Guiding lands? // - Shadow distance retuning. // - Weird shadow area in Rotten Vale. // - 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, PATCH_FLOAT } static IPlugin? Instance = null; static Config getConfig() { return ConfigManager.GetConfig(Instance!); } private const float defaultParamWidth = 0.215f; private static Stage selectedStage = Stage.InfinityOfNothingHandler; private static Stage previousStage = selectedStage; private static bool stageIsGlobal(Stage stage) { return stage == Stage.InfinityOfNothingHandler; } 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; if (Type == ParameterType.PATCH_FLOAT) { valueV.X = MemoryUtil.Read(offset); pendingUpdate = false; } 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; case ParameterType.PATCH_FLOAT: new Patch(offset, BitConverter.GetBytes(valueV.X)).Enable(); 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; } case ParameterType.PATCH_FLOAT: { ImGui.SetNextItemWidth(width * defaultParamWidth); float f1 = v4.X; if (ImGui.InputFloat(label, ref f1, 0.0f, 0.0f, "%.4f", ImGuiInputTextFlags.EnterReturnsTrue)) { v4.X = f1; 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("Set by Config/Preset"); } 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 && !overrideForStage) { ImGui.SameLine(); if (ImGui.Button("▲")) { Config config = getConfig(); List stageOverrides = config.Overrides[selectedStage]; Override ov = new Override(this, v4, i1); ov.Set(); stageOverrides.Add(ov); } if (ImGui.BeginItemTooltip()) { ImGui.Text("Add to Selected Stage"); ImGui.EndTooltip(); } } 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: case ParameterType.PATCH_FLOAT: { ImGui.Text($"(Original: {oValueV.X:0.00000})"); break; } case ParameterType.VECTOR3: { ImGui.Text($"(Original: {oValueV.X:0.0000}, {oValueV.Y:0.0000}, {oValueV.Z:0.0000})"); break; } case ParameterType.VECTOR4: { ImGui.Text($"(Original: {oValueV.X:0.0000}, {oValueV.Y:0.0000}, {oValueV.Z:0.0000}, {oValueV.W:0.00000})"); break; } } //ImGui.SameLine(); //ImGui.Text($"(Address: {lastAddr:X})"); ImGui.PopStyleVar(); } 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: case ParameterType.PATCH_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: case ParameterType.PATCH_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 Override() { } public Override(Parameter param, Vector4 v4, int i1) { Param = param; valueV = v4; valueInt = i1; } 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) { if (currentOverrides == null) { ImGui.PushItemFlag(ImGuiItemFlags.Disabled, true); } ImGui.PushItemWidth(width * 0.475f); if (ImGui.BeginCombo("##Parameters", Param != null ? Param.Name : "")) { if (currentOverrides != null) { 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 (currentOverrides == null) { ImGui.PopItemFlag(); } 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("Restore")) { Param.OverrideValue(valueV, valueInt); } } } } } private delegate void OnAreaChange(nint unknownPtr); private Hook? onAreaChange; private static MtObject? sMhScene = null; private delegate void UpdateSSAOParams(nint sceneObjectInternal, nint stackOffset); private Hook? updateSSAOParams; private static Parameter[] ssaoParameters = { new Parameter("SSAO Depth Bias", 0xB4B0, ParameterType.FLOAT, false, 0.00001f), new Parameter("SSAO Sloped Depth Bias", 0xB4B4, ParameterType.FLOAT, false, 0.00001f), new Parameter("SSAO Max Depth Bias", 0xB4B8, ParameterType.FLOAT, false, 0.00001f), 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("Debug View", 0x264, ParameterType.INT, false, 1), new Parameter("Debug View Channel", 0x268, ParameterType.INT, false, 1), new Parameter("Debug View Bg Alpha", 0x26C, ParameterType.FLOAT, false), new Parameter("Debug View Fg Alpha", 0x270, ParameterType.FLOAT, false), new Parameter("Debug Texture", 0x274, ParameterType.INT, false, 1), new Parameter("Debug Sampler", 0x278, ParameterType.INT, false, 1), new Parameter("Debug Cluster", 0x27C, ParameterType.INT, false, 1), new Parameter("Debug Light Max Count", 0x280, ParameterType.INT, false, 1), new Parameter("Wireframe", 0x284, ParameterType.BOOL, false), */ new Parameter("Material Draw SS Normal", 0x5626, ParameterType.BOOL, false), new Parameter("Material Height Factor", 0x5628, ParameterType.FLOAT, false), new Parameter("Model Detail", 0x190, ParameterType.INT, false, 1), 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("Fake Light Intensity", 0xEC40, ParameterType.FLOAT, false), // MonsterHunterWorld.exe+1B18711 - mov [rbx+0000EC44],3F800000 (Other unknown reference). new Parameter("Fake Light Intensity (Gameplay)", new IntPtr(0x141B1A19F) + 0x6, ParameterType.PATCH_FLOAT, false), new Parameter("Fake Light Blend", new IntPtr(0x141CDE0CE) + 0x6, ParameterType.PATCH_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.VECTOR3, false), new Parameter("Broad Area Shadow Range", 0x5560, ParameterType.VECTOR3, false), new Parameter("Broad Area Shadow Dir", 0x5550, ParameterType.VECTOR4, false), //new Parameter("Broad Area Shadow Depth Bias", 0x5570, ParameterType.FLOAT, false, 0.00001f), //new Parameter("Broad Area Shadow Sloped Depth Bias", 0x5574, ParameterType.FLOAT, false, 0.00001f), //new Parameter("Broad Area Shadow Max Depth Bias", 0x5578, ParameterType.FLOAT, false, 0.00001f), new Parameter("Broad Area Shadow Max LOD Level", 0x5524, ParameterType.FLOAT, false), new Parameter("Broad Area Shadow Culling Size", 0x5528, ParameterType.FLOAT, false), new Parameter("Broad Area Shadow Precision", 0x5518, ParameterType.INT, false, 1, 0, 2), // Maybe 3? new Parameter("Shadow Culling Length", 0x5C, ParameterType.FLOAT, false), new Parameter("Light Frustum Cull Enable", 0x552C, ParameterType.BOOL, 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, 0.005f, 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), //new Parameter("Target Joint No", 0x240, ParameterType.INT, true, 1), }; 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 static MtObject? sLightProbes = null; private static Parameter[] lightProbesParameters = { //new Parameter("Enable Neighbor Search", 0x40, ParameterType.BOOL, false), //new Parameter("WF Count", 0x90, ParameterType.INT, false, 1), //new Parameter("CU Mask", 0x94, ParameterType.HEX, false), new Parameter("Debug Mode", 0x98, ParameterType.INT, false, 1), //new Parameter("Daytime State", 0x9C, ParameterType.INT, true, 1), //new Parameter("Daytime Interpolation", 0xA0, ParameterType.FLOAT, false), //new Parameter("Max Iter", 0xA4, ParameterType.INT, true, 1) }; private delegate nint CreateLightingObject(); private delegate nint DestroyLightingObject(nint lightingObjectInternal, int unknownInt); private Hook? createLightingObject; private Hook? destroyLightingObject; private nint lightingObject = 0x0; /* Compute Luminance (bool) +0x170 Luminance Version (int) +0x168 LUT Blend (bool) +0x1C8 Vfx LUT Blend (bool) +0x1D0 Input Color Linear to PQ (bool) +0x1A1 Output Color PQ to Linear (bool) +0x1A0 */ private static Parameter[] lightingParameters = { new Parameter("Tone Map Type", 0x16C, ParameterType.INT, false, 1, 1, 7), new Parameter("Shoulder Strength", 0x168, ParameterType.FLOAT, false), 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 = { }; // This is actually an InfiniteLight object. 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), // Aligned to 128. 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.VECTOR3, true), new Parameter("Broad Area Shadow Depth Bias", 0x1C4, ParameterType.FLOAT, true, 0.00001f), new Parameter("Broad Area Shadow Sloped Depth Bias", 0x1CC, ParameterType.FLOAT, true, 0.00001f), new Parameter("Broad Area Shadow Max Depth Bias", 0x1D4, ParameterType.FLOAT, true, 0.00001f), 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 MtObject? sMain = null; private static MtObject? sLightLinker = null; private static MtObject? sMhSpeedTree = null; 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 fullResVolumeBlur = 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 fullResVolumeBlurEnable() { volumeSars1.Enable(); volumeSars2.Enable(); volumeSars3.Enable(); volumeSars4.Enable(); volumeSars5.Enable(); volumeSars6.Enable(); volumeSars7.Enable(); volumeSars8.Enable(); volumeSars9.Enable(); } private void fullResVolumeBlurDisable() { 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 Patch defaultViewModeLODLimit_3; private Patch defaultViewModeLODLimit_4; private void disableLODLimitsEnable() { defaultViewModeLODLimit.Enable(); defaultViewModeLODLimit_1.Enable(); defaultViewModeLODLimit_2.Enable(); defaultViewModeLODLimit_3.Enable(); defaultViewModeLODLimit_4.Enable(); } private void disableLODLimitsDisable() { defaultViewModeLODLimit.Disable(); defaultViewModeLODLimit_1.Disable(); defaultViewModeLODLimit_2.Disable(); defaultViewModeLODLimit_3.Disable(); defaultViewModeLODLimit_4.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.INT, false, 1, 1, 3), new Parameter("Position", 0x5A0, ParameterType.VECTOR3, true, 0.1f), new Parameter("Color", 0x140, ParameterType.COLOR, true), new Parameter("Intensity", 0x8A8, ParameterType.FLOAT, true, 0.1f), new Parameter("Radius", 0x6A0, ParameterType.FLOAT, true, 0.01f), new Parameter("Effective Radius", 0x588, ParameterType.FLOAT, true, 0.01f), new Parameter("Min Roughness", 0x58C, ParameterType.FLOAT, true), new Parameter("Do Volumetric", 0x590, ParameterType.BOOL, true), new Parameter("Near Clip Distance", 0x1B4, ParameterType.FLOAT, true), new Parameter("Shadow Cast", 0x138, ParameterType.FLAG, false, (1 << 23)), new Parameter("Shadow Map Size", 0x1B8, ParameterType.INT, false), // Aligned to 128. new Parameter("Shadow Depth Bias", 0x57C, ParameterType.FLOAT, true, 0.00001f), new Parameter("Shadow Sloped Depth Bias", 0x580, ParameterType.FLOAT, true, 0.00001f), new Parameter("Shadow Max Depth Bias", 0x584, ParameterType.FLOAT, true, 0.00001f), //new Parameter("Use Umbra", 0x591, ParameterType.BOOL, true), //new Parameter("Enable Camera LOD", 0x592, ParameterType.BOOL, true), //new Parameter("Llk Intensity", 0x974, ParameterType.FLOAT, true), //new Parameter("Llk Radius", 0x978, ParameterType.FLOAT, true), //new Parameter("Llk Effective Radius", 0x97C, ParameterType.FLOAT, true), //new Parameter("Cone", 0x5F0, ParameterType.FLOAT, true, 0.1f), //new Parameter("Spread", 0x5F4, ParameterType.FLOAT, true, 0.1f) }; public Parameter[] RandomMoveParameters = { new Parameter("Random Move Radius", 0x8E8, ParameterType.FLOAT, true), new Parameter("Random Move Force To Center", 0x8EC, ParameterType.FLOAT, true), new Parameter("Random Move Time Min", 0x8F8, ParameterType.FLOAT, true), new Parameter("Random Move Time Max", 0x8FC, ParameterType.FLOAT, true), new Parameter("Random Move Friction", 0x900, ParameterType.FLOAT, true), new Parameter("Random Move Speed V Max", 0x940, ParameterType.VECTOR3, true), new Parameter("Random Move Force V Max", 0x960, ParameterType.VECTOR3, true) }; public Light(nint lightObject, Vector3 pos) { Object = lightObject; foreach (Parameter param in Parameters) { param.OverrideOn(false); } foreach (Parameter param in RandomMoveParameters) { param.OverrideOn(false); } Parameters[0].OverrideValue(default, 3); Parameters[1].OverrideValue(new Vector4(pos.X, pos.Y, pos.Z, 0.0f), 0); Parameters[3].OverrideValue(new Vector4(10.0f, 0.0f, 0.0f, 0.0f), 0); foreach (Parameter param in Parameters) { param.Update(lightObject); } foreach (Parameter param in RandomMoveParameters) { 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; private Dictionary externalOverrides = new Dictionary(); private int externalId = 0; public int AddOverride(string name, Vector4 v4, int i1) { foreach (Parameter param in allParameters) { if (param.Name == name) { externalId++; Override ov = new Override(param, v4, i1); ov.Set(); externalOverrides.Add(externalId, ov); return externalId; } } return 0; } public void RemoveOverride(int id) { if (externalOverrides.ContainsKey(id)) { Config config = getConfig(); List globalOverrides = config.Overrides[Stage.InfinityOfNothingHandler]; Override ovE = externalOverrides[id]; ovE.Unset(); setIfOverridesContainsParam(globalOverrides, ovE.Param!); externalOverrides.Remove(id); } } public PluginData Initialize() { Instance = this; 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 IntPtr addr = PatternScanner.FindFirst(Pattern.FromString("48 89 5C 24 10 48 89 74 24 18 48 89 7C 24 20 55 41 56 41 57 48 8B EC 48 83 EC 30 48 8B FA 48 8B D9 E8 AA B6 C1 FF 48 8B 47 10 48 8D 57 50")); #if ADDR_ASSERTS Assert(addr == 0x141AB2260); // nint, nint #endif updateShadowParams = Hook.Create(addr, UpdateShadowParamsHook); staticShadowParams = Hook.Create(0x1416D94F0, StaticShadowParamsHook); // nint, nint setShadowQuality = new NativeAction(0x14043FF80); addr = PatternScanner.FindFirst(Pattern.FromString("48 83 EC 28 F3 0F 10 0D ?? ?? ?? ?? 80 F9 04 75 2F 48 8B 0D ?? ?? ?? ?? E8 D3 8A E4 01 48 8B 0D ?? ?? ?? ?? 33 D2 E8 ?? ?? ?? ??")); #if ADDR_ASSERTS Assert(addr == 0x14043FF80); Assert(MemoryUtil.Read(0x142E4FE5C) == 3.0f); #endif shadowRes1_3x = new Patch(addr + 0x8, [0xD0, 0xFE, 0xA0, 0x02]); // 3.0. shadowRes1_1 = new Patch(addr + 0x65, [0x17]); // Always set "Value is not 1.0" flag. shadowRes1_2 = new Patch(addr + 0x68, [0x59]); // movss -> mulss. shadowRes1_3 = new Patch(addr + 0x77, [0x59]); // movss -> mulss. // shadowRes2/3 control the detail of the infrequently updated fallback shadows. 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. ]); // The volume blur filter is created at a different place in the code and happens at a different // time (area change/createLightingObject() vs change of Volume Quality setting). It's also rendered // in a seperate pass that happens after the initial volume rendering. So keep that in mind if inspecting // a frame in renderdoc. volumeSars1 = new Patch(new IntPtr(0x1424D0159), [0x90, 0x90]); volumeSars2 = new Patch(new IntPtr(0x1424D01A0), [0x90, 0x90]); volumeSars3 = new Patch(new IntPtr(0x1424D01C6), [0x90, 0x90]); volumeSars4 = new Patch(new IntPtr(0x1424D0219), [0x90, 0x90]); volumeSars5 = new Patch(new IntPtr(0x1424D0242), [0x90, 0x90]); volumeSars6 = new Patch(new IntPtr(0x1424D029D), [0x90, 0x90]); volumeSars7 = new Patch(new IntPtr(0x1424D02C6), [0x90, 0x90]); volumeSars8 = new Patch(new IntPtr(0x1424D0321), [0x90, 0x90]); volumeSars9 = new Patch(new IntPtr(0x1424D034A), [0x90, 0x90]); /* As far as I can tell this is limited by buffers created cpu-side, seems like it * would be an extremely hard change. froxelRes1 = new Patch(new IntPtr(0x142384F15) + 0x1, [0x02]); // 4 -> 2 froxelRes2 = new Patch(new IntPtr(0x142389711) + 0x1, [0x02]); // 4 -> 2 froxelRes3 = new Patch(new IntPtr(0x142389878) + 0x1, [0x02]); // 4 -> 2 froxelRes4 = new Patch(new IntPtr(0x14238989E) + 0x1, [0x02]); // 4 -> 2 froxelRes5 = new Patch(new IntPtr(0x1423898D8) + 0x1, [0x02]); // 4 -> 2 froxelRes6 = new Patch(new IntPtr(0x14238992B) + 0x1, [0x02]); // 4 -> 2 froxelRes7 = new Patch(new IntPtr(0x14238FED1) + 0x4, [0x7B, 0xFF, 0xAB, 0x00]); // 0.25 -> 0.50 froxelRes8 = new Patch(new IntPtr(0x14239009C) + 0x4, [0xB0, 0xFD, 0xAB, 0X00]); // 0.25 -> 0.50 */ /* Would require a complicated shader edit to maybe work. Similar to SSLR. checkerRes1 = new Patch(new IntPtr(0x14238580D) + 0x4, [0x43]); // 0.5 -> 1.0 checkerRes2 = new Patch(new IntPtr(0x14238FFC3) + 0x4, [0x8D]); // 0.5 -> 1.0 */ value2ForVolumeQuality = new Patch(new IntPtr(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 Assert(addr == 0x141B1A0B4); #endif defaultViewModeLODLimit = new Patch(addr + 0x40, [0x07, 0x74, 0x0A, 0xC7, 0x83, 0xDC, 0xEB, 0x00, 0x00, 0x07]); // In room. addr = PatternScanner.FindFirst(Pattern.FromString("8B 9F CC 00 00 00 81 FB F9 01 00 00 74 0C 8B CB E8 95 3F 65 01 83 F8 05 75 11 48 8B 0D 61 C8 F6 04 BA 02 00 00 00 E8 DF 2D 8C 01 48 8B 0D A0 C7 F6 04 8B D3")); #if ADDR_ASSERTS Assert(addr == 0x140257AE6); #endif defaultViewModeLODLimit_1 = new Patch(addr + 0x22, [0x07]); // Forging/Changing Equipment. addr = PatternScanner.FindFirst(Pattern.FromString("BA 02 00 00 00 E8 6E C0 80 00 48 8B 74 24 38 48 8B 57 28 48 8D 4F 30 E8 4C 79 B4 FE 48 8B 0D 0D FF A6 03 BA 04 00 00 00 E8 8B 64 3C 00 48 8B 05 D4 01 A7 03 80 B8 FD 46 01 00 00")); #if ADDR_ASSERTS Assert(addr == 0x141754438); #endif defaultViewModeLODLimit_2 = new Patch(addr + 0x24, [0x07]); // Unknown. defaultViewModeLODLimit_3 = new Patch(new IntPtr(0x14128F1AC) + 0x1, [0x07]); // Talking to NPC. defaultViewModeLODLimit_4 = new Patch(new IntPtr(0x14128F1AC) + 0xF, [0x07]); addr = PatternScanner.FindFirst(Pattern.FromString("74 4D 33 C0 48 81 C1 00 02 00 00 F3 0F 10 11 0F 2F CA 72 0C FF C0 48 83 C1 04 83 F8 03 72 EC C3")); #if ADDR_ASSERTS Assert(addr == 0x1426D89CA); #endif addressHigherValueForFoliageSway = new Patch(addr + 0x7, [0x04]); // Found using mFrameSkipNum annotation from MHW-DTI-Dumps. zeroFrameSkip = new Patch(new IntPtr(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); // Gui animation rate? //new Patch(new IntPtr(0x142F15C90), BitConverter.GetBytes(60.0f)).Enable(); return new PluginData(); } public void OnPreMain() { Config config = getConfig(); Config.PatchConfig patches = config.Patches; tripleShadowResolution = patches.TripleShadowResolution; if (tripleShadowResolution) { tripleShadowResEnable(); } fullResVolumeBlur = patches.FullResolutionVolumeBlur; if (fullResVolumeBlur) { fullResVolumeBlurEnable(); } higherVolumeQuality = patches.HigherThanHighestVolumeRendering; if (higherVolumeQuality) { value2ForVolumeQuality.Enable(); } disableLODLimits = patches.DisableLODLimits; if (disableLODLimits) { disableLODLimitsEnable(); } largerFoliageSwayRange = patches.LargerFoliageSwayRange; if (largerFoliageSwayRange) { addressHigherValueForFoliageSway.Enable(); } disableReducedRateAnimations = patches.DisableReducedRateAnimations; if (disableReducedRateAnimations) { zeroFrameSkip.Enable(); } } public void OnLoad() { sMain = SingletonManager.GetSingleton("sMhMain")!; sMhScene = SingletonManager.GetSingleton("sMhScene")!; sLightProbes = SingletonManager.GetSingleton("sLightProbes")!; sLightLinker = SingletonManager.GetSingleton("sLightLinker")!; sMhSpeedTree = SingletonManager.GetSingleton("sMhSpeedTree")!; Config config = getConfig(); 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); } /* // https://github.com/AsteriskAmpersand/CTC-MHW-Editor/blob/9ec6303042690478398801b1bb860a2d38298eee/structures/Ctc.py#L23 private static bool adjustCtcParams = false; private static float stepTimeFps = 60.0f; public void OnResourceLoad(Resource? resource, MtDti dti, string path, LoadFlags flags) { if (adjustCtcParams && resource != null && resource.FileExtension == "ctc") { Log.Info($"Attempting to increase physics update rate of {resource.FilePath} @ {resource.Instance:X}."); int numARecords = MemoryUtil.GetRef(resource.Instance + 0xB8); nint aRecords = MemoryUtil.GetRef(resource.Instance + 0xF8); for (int i = 0; i < numARecords; i++) { nint aRecord = aRecords + (0x50 * i); } MemoryUtil.GetRef(resource.Instance + 0xC4) = 1.0f / stepTimeFps; } } */ 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 (sLightProbes!.Instance != 0x0) { foreach (Parameter param in lightProbesParameters) { param.Update(sLightProbes!.Instance); } } 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; } 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; } private nint CreateMotionBlurObject2Hook(nint unknownPtr) { motionBlurObject = createMotionBlurObject2!.Original(unknownPtr); foreach (Parameter param in motionBlurParameters) { param.Update(motionBlurObject); } return motionBlurObject; } 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); } private void UpdateMotionBlurParamsHook(nint unknownPtr, nint unknownPtr2) { foreach (Parameter param in motionBlurParameters) { if (param.PerFrame) { param.Update(motionBlurObject); } } updateMotionBlurParams!.Original(unknownPtr, unknownPtr2); } private nint CreateBloomObjectHook() { bloomObject = createBloomObject!.Original(); foreach (Parameter param in bloomParameters) { param.Update(bloomObject); } return bloomObject; } private nint CreateBloomObject2Hook(nint unknownPtr) { bloomObject = createBloomObject2!.Original(unknownPtr); foreach (Parameter param in bloomParameters) { param.Update(bloomObject); } return bloomObject; } private nint DestroyBloomObjectHook(nint bloomObjectInternal, int unknownInt) { Assert(unknownInt == 1); if (bloomObject == bloomObjectInternal) { bloomObject = 0x0; foreach (Parameter param in bloomParameters) { param.Update(bloomObject); } } return destroyBloomObject!.Original(bloomObjectInternal, unknownInt); } private nint CreateLightingObjectHook() { 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) { nint shadowCascadeMode = MemoryUtil.GetRef(stackOffset + 0x170) >> 32; bool firstPass = shadowCascadeMode == 3; if (!firstPass) { 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 shadowParameters2) { param.Update(shadowObjectStatic); } } staticShadowParams!.Original(shadowObjectStatic, shadowObjectInternal); } private void OnAreaChangeHook(nint unknownPtr) { onAreaChange!.Original(unknownPtr); Stage stage = Area.CurrentStage; if (stage == 0x0) { stage = Stage.InfinityOfNothingHandler; } if (stage == previousStage) return; Config config = getConfig(); 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.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 = getConfig(); 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); } ImGui.Separator(); ImGui.PushID("External"); ImGui.Text("External:"); foreach (Override ovE in externalOverrides.Values) { ovE.Draw(null, null, width); } ImGui.PopID(); ImGui.Separator(); if (ImGui.CollapsingHeader("Patches")) { Config.PatchConfig patches = config.Patches; if (ImGui.Checkbox("3x Shadow Resolution", ref tripleShadowResolution)) { if (tripleShadowResolution) { tripleShadowResEnable(); } else { tripleShadowResDisable(); } setShadowQuality.Invoke(MemoryUtil.Read(sMhScene!.Instance + 0x5530) + 1); patches.TripleShadowResolution = tripleShadowResolution; config.Patches = patches; ConfigManager.SaveConfig(this); } 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 fullResVolumeBlur)) { if (fullResVolumeBlur) { fullResVolumeBlurEnable(); } else { fullResVolumeBlurDisable(); } patches.FullResolutionVolumeBlur = fullResVolumeBlur; config.Patches = patches; ConfigManager.SaveConfig(this); } 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 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(); } patches.HigherThanHighestVolumeRendering = higherVolumeQuality; config.Patches = patches; ConfigManager.SaveConfig(this); } 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(); } patches.DisableLODLimits = disableLODLimits; config.Patches = patches; ConfigManager.SaveConfig(this); } 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(); } patches.LargerFoliageSwayRange = largerFoliageSwayRange; config.Patches = patches; ConfigManager.SaveConfig(this); } 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(); } patches.DisableReducedRateAnimations = disableReducedRateAnimations; config.Patches = patches; ConfigManager.SaveConfig(this); } 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("Lights")) { /* ImGui.NextItemWidth(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 += 30.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.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.CollapsingHeader("Random Move")) { foreach (Parameter param in light.RandomMoveParameters) { 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.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("Light Probes Parameters")) { ImGui.PushID("LightProbes"); ImGui.Text($"Address: {sLightProbes!.Instance:X}"); foreach (Parameter param in lightProbesParameters) { 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")) { 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(); ImGui.Text($"sLightLinker: {sLightLinker!.Instance:X}"); ImGui.Text($"sMhSpeedTree: {sMhSpeedTree!.Instance:X}"); } } #if SHADER_FEATURES private static bool replaceShaderFromFile(ShaderInfo *info, string path) { if (!System.IO.File.Exists(path)) { Log.Warn($"File not found: {path}."); return false; } byte[] shaderData; try { shaderData = System.IO.File.ReadAllBytes(path); } catch (Exception) { Log.Error($"Failed to read: {path}."); return false; } info->Replacement.Length = shaderData.Length; info->Replacement.Source = (byte *)Marshal.UnsafeAddrOfPinnedArrayElement(shaderData, 0); return true; } private string shaderPath = "nativePC/plugins/CSharp/Shaders"; private bool shadersLoadedOnce = false; public unsafe void OnCreateShader(ShaderInfo *info) { string hash = new string(info->DxbcHash); if (!shadersLoadedOnce && hash == "2e4e18fd-6ea5eeae-2de3d65c-26ab36dd") { if (replaceShaderFromFile(info, $"{shaderPath}/volume_upsample1.shdr")) { info->Replacement.Type = ShaderSourceType.BINARY; Log.Info("Volume upsample shader 1 replaced."); } } else if (!shadersLoadedOnce && hash == "e2c8c13e-45bc99b2-4c3d7699-3d66188e") { if (replaceShaderFromFile(info, $"{shaderPath}/volume_upsample2.shdr")) { info->Replacement.Type = ShaderSourceType.BINARY; Log.Info("Volume upsample shader 2 replaced."); } // This allows us to A/B using the volume rendering value 2 switch. //shadersLoadedOnce = true; } else if (hash == "8cf2a107-ecde214b-9939b350-7b2af1a7") { if (replaceShaderFromFile(info, $"{shaderPath}/cube_only.shdr")) { info->Replacement.Type = ShaderSourceType.BINARY; Log.Info("Cube Only shader replaced."); } } else if (hash == "b21dd223-98ab56ae-918264e6-eb6e8ee4") { if (replaceShaderFromFile(info, $"{shaderPath}/sslr.shdr")) { info->Replacement.Type = ShaderSourceType.BINARY; Log.Info("SSLR shader replaced."); } } else if (hash == "9ff245fb-4fd555e0-04d0ef15-84609fe1") { if (replaceShaderFromFile(info, $"{shaderPath}/fxaa_max_quality.hlsl")) { info->Replacement.Type = ShaderSourceType.HLSL; Log.Info("FXAA shader replaced."); } } else if (hash == "2eed1f00-e24d1b19-9d521064-17b9a586") { if (replaceShaderFromFile(info, $"{shaderPath}/body_skin.shdr")) { info->Replacement.Type = ShaderSourceType.BINARY; Log.Info("Body skin shader replaced."); } } else if (hash == "8e5e3c09-ebe77ee4-ba1cb659-d25bc7bf") { if (replaceShaderFromFile(info, $"{shaderPath}/face.shdr")) { info->Replacement.Type = ShaderSourceType.BINARY; 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."); } } */ } #endif } }