From f238775474f9557968fc54502418b6e2f1c060c6 Mon Sep 17 00:00:00 2001 From: Andrew Opalach Date: Thu, 2 Apr 2026 22:30:59 -0400 Subject: Add basic interop api, misc fixes Signed-off-by: Andrew Opalach --- Plugin.cs | 338 +++++++++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 227 insertions(+), 111 deletions(-) (limited to 'Plugin.cs') diff --git a/Plugin.cs b/Plugin.cs index 68f5f00..0258ef9 100755 --- a/Plugin.cs +++ b/Plugin.cs @@ -1,4 +1,5 @@ //#define ENABLE_ASSERTS +//#define SHADER_FEATURES using System.Numerics; using System.Reflection; @@ -14,8 +15,6 @@ 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. @@ -40,18 +39,18 @@ namespace WorldTuningTool 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); + ((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)); + 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 @@ -825,6 +824,18 @@ namespace WorldTuningTool private int valueInt = 0; private bool isSet = false; + public Override() + { + } + + public Override(Parameter param, Vector4 v4, int i1) + { + Param = param; + valueV = v4; + valueInt = i1; + Set(); + } + public void Set() { Assert(!isSet); @@ -846,42 +857,53 @@ namespace WorldTuningTool } } - public void Draw(List currentOverrides, List? globalOverrides, float width) + public void Draw(List? currentOverrides, List? globalOverrides, float width) { - ImGui.PushItemWidth(width * 0.35f); + if (currentOverrides == null) + { + ImGui.PushItemFlag(ImGuiItemFlags.Disabled, true); + } + ImGui.PushItemWidth(width * 0.475f); if (ImGui.BeginCombo("##Parameters", Param != null ? Param.Name : "")) { - foreach (Parameter param in allParameters) + if (currentOverrides != null) { - if (overridesContainsParam(currentOverrides, param)) - { - continue; - } - bool isSelected = Param == param; - if (ImGui.Selectable(param.Name, isSelected)) + foreach (Parameter param in allParameters) { - bool wasSet = isSet; - if (wasSet) + if (overridesContainsParam(currentOverrides, param)) + { + continue; + } + bool isSelected = Param == param; + if (ImGui.Selectable(param.Name, isSelected)) { - Unset(); - if (globalOverrides != null) + bool wasSet = isSet; + if (wasSet) { - if (Param != null) + Unset(); + if (globalOverrides != null) { - setIfOverridesContainsParam(globalOverrides, Param); + if (Param != null) + { + setIfOverridesContainsParam(globalOverrides, Param); + } + unsetIfOverridesContainsParam(globalOverrides, param); } - unsetIfOverridesContainsParam(globalOverrides, param); } + Param = param; + (valueV, valueInt) = Param.GetValue(); + if (wasSet) Set(); } - Param = param; - (valueV, valueInt) = Param.GetValue(); - if (wasSet) Set(); + if (isSelected) ImGui.SetItemDefaultFocus(); } - if (isSelected) ImGui.SetItemDefaultFocus(); } ImGui.EndCombo(); } ImGui.PopItemWidth(); + if (currentOverrides == null) + { + ImGui.PopItemFlag(); + } if (Param != null) { ImGui.SameLine(); @@ -892,7 +914,7 @@ namespace WorldTuningTool if (isSet && !Param.PendingUpdate() && (valueV, valueInt) != Param.GetValue()) { ImGui.SameLine(); - if (ImGui.Button("Set")) + if (ImGui.Button("Restore")) { Param.OverrideValue(valueV, valueInt); } @@ -943,6 +965,7 @@ namespace WorldTuningTool new Parameter("SSLR Use Mipmap", 0xE650, ParameterType.BOOL, false), new Parameter("SSLR GBuffer Jitter", 0xB440, ParameterType.BOOL, false), }; + //private NativeAction refreshBroadAreaShadow; private static Parameter[] sceneParameters = { new Parameter("HQ Mode", 0xE9A3, ParameterType.BOOL, false), new Parameter("Shadow Cascade 2Way Bias (HQ)", 0x58, ParameterType.FLOAT, false), @@ -997,14 +1020,17 @@ namespace WorldTuningTool 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 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.0001f), //new Parameter("Broad Area Shadow Sloped Depth Bias", 0x5574, ParameterType.FLOAT, false, 0.0001f), //new Parameter("Broad Area Shadow Max Depth Bias", 0x5578, ParameterType.FLOAT, false, 0.0001f), 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), @@ -1025,7 +1051,7 @@ namespace WorldTuningTool 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 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) }; @@ -1173,7 +1199,7 @@ namespace WorldTuningTool 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), + //new Parameter("Broad Area Shadow Range", 0x1B0, ParameterType.VECTOR3, true), 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), @@ -1271,12 +1297,16 @@ namespace WorldTuningTool 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() @@ -1284,6 +1314,8 @@ namespace WorldTuningTool defaultViewModeLODLimit.Disable(); defaultViewModeLODLimit_1.Disable(); defaultViewModeLODLimit_2.Disable(); + defaultViewModeLODLimit_3.Disable(); + defaultViewModeLODLimit_4.Disable(); } private bool largerFoliageSwayRange = false; @@ -1296,22 +1328,35 @@ namespace WorldTuningTool { public nint Object; public Parameter[] Parameters = { - new Parameter("Group", 0x13C, ParameterType.BYTE, false, 1), + new Parameter("Group", 0x13C, ParameterType.INT, false, 1, 1, 3), 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("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("Use Umbra", 0x591, ParameterType.BOOL, true), - new Parameter("Enable Camera LOD", 0x592, 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 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) @@ -1321,13 +1366,21 @@ namespace WorldTuningTool { 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[2].OverrideValue(new Vector4(10.0f, 0.0f, 0.0f, 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); + } } } @@ -1341,6 +1394,36 @@ namespace WorldTuningTool private static MtObject? sMain = null; + 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++; + externalOverrides.Add(externalId, new Override(param, v4, i1)); + return externalId; + } + } + return 0; + } + + public void RemoveOverride(int id) + { + if (externalOverrides.ContainsKey(id)) + { + Config config = ConfigManager.GetConfig(this); + List globalOverrides = config.Overrides[Stage.InfinityOfNothingHandler]; + Override ovE = externalOverrides[id]; + ovE.Unset(); + setIfOverridesContainsParam(globalOverrides, ovE.Param!); + externalOverrides.Remove(id); + } + } + public PluginData Initialize() { onAreaChange = Hook.Create(0x141AC27D0, OnAreaChangeHook); // nint @@ -1379,6 +1462,8 @@ namespace WorldTuningTool setShadowQuality = new NativeAction(0x14043FF80); + //refreshBroadAreaShadow = new NativeAction(0x142284B20); + 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); @@ -1458,6 +1543,12 @@ namespace WorldTuningTool #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); @@ -1845,14 +1936,10 @@ namespace WorldTuningTool private void UpdateShadowParamsHook(nint shadowObjectInternal, nint stackOffset) { - ref nint rax = ref MemoryUtil.GetRef(stackOffset + 0x170); - nint shadowCascadeMode = rax >> 32; + nint shadowCascadeMode = MemoryUtil.GetRef(stackOffset + 0x170) >> 32; bool firstPass = shadowCascadeMode == 3; - if (firstPass) - { - } - else + if (!firstPass) { foreach (Parameter param in shadowParameters2) { @@ -1867,7 +1954,7 @@ namespace WorldTuningTool { if (shadowObjectInternal == 0x0) { - foreach (Parameter param in shadowParameters1) + foreach (Parameter param in shadowParameters2) { param.Update(shadowObjectStatic); } @@ -1947,53 +2034,6 @@ namespace WorldTuningTool 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)}")) { @@ -2094,6 +2134,18 @@ namespace WorldTuningTool 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; @@ -2219,6 +2271,60 @@ namespace WorldTuningTool } } + 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.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")) @@ -2348,6 +2454,12 @@ namespace WorldTuningTool { ImGui.PushID("Scene"); ImGui.Text($"Address: {sMhScene!.Instance:X}"); + /* + if (ImGui.Button("Refresh Broad Area Shadow")) + { + refreshBroadAreaShadow.Invoke(sMhScene!.Instance); + } + */ foreach (Parameter param in sceneParameters) { param.Draw(width); @@ -2373,6 +2485,7 @@ namespace WorldTuningTool } } +#if SHADER_FEATURES private static bool replaceShaderFromFile(ShaderInfo *info, string path) { if (!System.IO.File.Exists(path)) @@ -2414,7 +2527,7 @@ namespace WorldTuningTool Log.Info("Volume upsample shader 2 replaced."); } // This allows us to A/B using the volume rendering value 2 switch. - shadersLoadedOnce = true; + //shadersLoadedOnce = true; } else if (hash == "8cf2a107-ecde214b-9939b350-7b2af1a7") { @@ -2451,13 +2564,16 @@ 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."); - // } - //} + /* + 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 } } -- cgit v1.2.3-101-g0448