From a83f8f9368e7a94b82df4abd1bd90801c9472932 Mon Sep 17 00:00:00 2001 From: Andrew Opalach Date: Wed, 21 Oct 2026 16:13:13 -0400 Subject: Cleanup MemoryUtil usage, use header for overrides Signed-off-by: Andrew Opalach --- Plugin.cs | 191 ++++++++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 125 insertions(+), 66 deletions(-) (limited to 'Plugin.cs') diff --git a/Plugin.cs b/Plugin.cs index 89c1ba3..3218403 100644 --- a/Plugin.cs +++ b/Plugin.cs @@ -26,7 +26,6 @@ using SharpPluginLoader.Core.Resources; // @TODO: // - https://dev.epicgames.com/community/learning/tutorials/34xz/unreal-engine-ocio-3d-luts-applying-3d-luts-when-using-ocio -// - Hook sMhScene constructor to set hqMode. // - Configurable Broad Area Shadow Resolution. // - Optimized update logic. // - Only update non-override values when UI is shown. @@ -65,7 +64,7 @@ namespace WorldTuningTool public string Author => "Akon City Software"; private static bool loggedAssertFailed = false; - public static void Assert(bool condition, [CallerLineNumber] int line = 0) + internal static void Assert(bool condition = false, [CallerLineNumber] int line = 0) { if (!condition && !loggedAssertFailed) { @@ -79,6 +78,26 @@ namespace WorldTuningTool private static byte ByteFlag(bool f) { return f ? (byte)0x1 : (byte)0x0; } + internal static T Get(nint addr, nint offset = 0x0) where T : unmanaged + { + return MemoryUtil.Read(addr + offset); + } + + internal static T Get(long addr, nint offset = 0x0) where T : unmanaged + { + return MemoryUtil.Read((nint)addr + offset); + } + + internal static T *GetPtrInline(nint addr, nint offset = 0x0) where T : unmanaged + { + return (T *)(addr + offset); + } + + internal static ref T GetRef(nint addr, nint offset = 0x0) where T : unmanaged + { + return ref MemoryUtil.GetRef(addr + offset); + } + private static int BitIndex(int mask) { return BitOperations.Log2((uint)(mask & (-mask))); @@ -112,7 +131,7 @@ namespace WorldTuningTool private static string BooleanToString(bool b) { return b.ToString(CultureInfo.InvariantCulture); } private static string Int32ToString(int i, string? format = null) { return i.ToString(format, CultureInfo.InvariantCulture); } - public static Vector2 StringToVector2(string s, char delim = ',') + internal static Vector2 StringToVector2(string s, char delim = ',') { if (String.IsNullOrEmpty(s)) throw new FormatException(); string[] sp = s.Split(delim).Select((v) => v.Trim()).ToArray(); @@ -120,7 +139,7 @@ namespace WorldTuningTool return new Vector2(StringToSingle(sp[0]), StringToSingle(sp[1])); } - public static Vector3 StringToVector3(string s, char delim = ',') + internal static Vector3 StringToVector3(string s, char delim = ',') { if (String.IsNullOrEmpty(s)) throw new FormatException(); string[] sp = s.Split(delim).Select((v) => v.Trim()).ToArray(); @@ -128,7 +147,7 @@ namespace WorldTuningTool return new Vector3(StringToSingle(sp[0]), StringToSingle(sp[1]), StringToSingle(sp[2])); } - public static Vector4 StringToVector4(string s, char delim = ',') + internal static Vector4 StringToVector4(string s, char delim = ',') { if (String.IsNullOrEmpty(s)) throw new FormatException(); string[] sp = s.Split(delim).Select((v) => v.Trim()).ToArray(); @@ -295,7 +314,7 @@ namespace WorldTuningTool return superseded; } - private static class ParameterFlags + public static class ParameterFlags { public const int ViewOnly = 1; } @@ -347,7 +366,7 @@ namespace WorldTuningTool Assert(mask != 0); break; case ParameterType.PATCH_FLOAT: - valueV.X = MemoryUtil.Read(offset); + valueV.X = Get(offset); pendingUpdate = false; break; case ParameterType.SHADOW_RESOLUTION: @@ -422,11 +441,11 @@ namespace WorldTuningTool { case ParameterType.BOOL: case ParameterType.BYTE: - MemoryUtil.GetRef(lastAddr + offset) = (byte)valueInt; + GetRef(lastAddr, offset) = (byte)valueInt; break; case ParameterType.FLAG: { - ref int i1 = ref MemoryUtil.GetRef(lastAddr + offset); + ref int i1 = ref GetRef(lastAddr, offset); if (valueInt != 0) { i1 |= mask; @@ -443,7 +462,7 @@ namespace WorldTuningTool case ParameterType.BITS: case ParameterType.COLOR: { - ref int i1 = ref MemoryUtil.GetRef(lastAddr + offset); + ref int i1 = ref GetRef(lastAddr, offset); if (mask != 0) { i1 = (i1 & ~mask) | ((valueInt << BitIndex(mask)) & mask); @@ -455,17 +474,17 @@ namespace WorldTuningTool break; } case ParameterType.FLOAT: - MemoryUtil.GetRef(lastAddr + offset) = valueV.X; + GetRef(lastAddr, offset) = valueV.X; break; case ParameterType.VECTOR2: - MemoryUtil.GetRef(lastAddr + offset) = new Vector2(valueV.X, valueV.Y); + GetRef(lastAddr, offset) = new Vector2(valueV.X, valueV.Y); break; case ParameterType.VECTOR3: case ParameterType.COLOR_FACTOR: - MemoryUtil.GetRef(lastAddr + offset) = new Vector3(valueV.X, valueV.Y, valueV.Z); + GetRef(lastAddr, offset) = new Vector3(valueV.X, valueV.Y, valueV.Z); break; case ParameterType.VECTOR4: - MemoryUtil.GetRef(lastAddr + offset) = valueV; + GetRef(lastAddr, offset) = valueV; break; } } @@ -596,7 +615,7 @@ namespace WorldTuningTool case ParameterType.BOOL: case ParameterType.BYTE: { - ref byte b1 = ref MemoryUtil.GetRef(baseObject + offset); + ref byte b1 = ref GetRef(baseObject, offset); byte b = b1; if (overrideValue) { @@ -614,7 +633,7 @@ namespace WorldTuningTool } case ParameterType.FLAG: { - ref int i1 = ref MemoryUtil.GetRef(baseObject + offset); + ref int i1 = ref GetRef(baseObject, offset); int b1 = ByteFlag((i1 & mask) == mask); if (overrideValue) { @@ -643,7 +662,7 @@ namespace WorldTuningTool case ParameterType.BITS: case ParameterType.COLOR: { - ref int i1 = ref MemoryUtil.GetRef(baseObject + offset); + ref int i1 = ref GetRef(baseObject, offset); int m = i1; if (mask != 0) { @@ -672,7 +691,7 @@ namespace WorldTuningTool } case ParameterType.FLOAT: { - ref float f1 = ref MemoryUtil.GetRef(baseObject + offset); + ref float f1 = ref GetRef(baseObject, offset); float f = f1; if (overrideValue) { @@ -690,7 +709,7 @@ namespace WorldTuningTool } case ParameterType.VECTOR2: { - ref Vector2 v2 = ref MemoryUtil.GetRef(baseObject + offset); + ref Vector2 v2 = ref GetRef(baseObject, offset); Vector2 v = v2; if (overrideValue) { @@ -710,7 +729,7 @@ namespace WorldTuningTool case ParameterType.VECTOR3: case ParameterType.COLOR_FACTOR: { - ref Vector3 v3 = ref MemoryUtil.GetRef(baseObject + offset); + ref Vector3 v3 = ref GetRef(baseObject, offset); Vector3 v = v3; if (overrideValue) { @@ -729,7 +748,7 @@ namespace WorldTuningTool } case ParameterType.VECTOR4: { - ref Vector4 v4 = ref MemoryUtil.GetRef(baseObject + offset); + ref Vector4 v4 = ref GetRef(baseObject, offset); Vector4 v = v4; if (overrideValue) { @@ -1215,28 +1234,47 @@ namespace WorldTuningTool { if (typeof(T) == typeof(float)) { + Assert(type == ParameterType.FLOAT || + type == ParameterType.VECTOR2 || + type == ParameterType.VECTOR3 || + type == ParameterType.VECTOR4 || + type == ParameterType.PATCH_FLOAT || + type == ParameterType.COLOR_FACTOR); this.stepf = (step != null) ? Convert.ToSingle(step) : 0.1f; this.minf = (min != null) ? Convert.ToSingle(min) : -Single.MaxValue; this.maxf = (max != null) ? Convert.ToSingle(max) : Single.MaxValue; } - else if (typeof(T) == typeof(int) || typeof(T) == typeof(byte) || typeof(T) == typeof(bool)) + else { this.step = (step != null) ? Convert.ToInt32(step) : 0; if (typeof(T) == typeof(int)) { + Assert(type == ParameterType.INT || + type == ParameterType.ALIGNED_INT || + type == ParameterType.HEX || + type == ParameterType.BITS || + type == ParameterType.COLOR || + type == ParameterType.SHADOW_RESOLUTION); this.min = (min != null) ? Convert.ToInt32(min) : Int32.MinValue; this.max = (max != null) ? Convert.ToInt32(max) : Int32.MaxValue; } else if (typeof(T) == typeof(byte)) { + Assert(type == ParameterType.BYTE); this.min = (min != null) ? Convert.ToInt32(min) : 0x0; this.max = (max != null) ? Convert.ToInt32(max) : 0xFF; } else if (typeof(T) == typeof(bool)) { + Assert(type == ParameterType.BOOL || + type == ParameterType.FLAG); this.min = 0; this.max = 1; } + else + { + Assert(); + } } } } @@ -1275,7 +1313,7 @@ namespace WorldTuningTool return new Parameter(name, offset, mask, type, m.min, m.max, m.step, 0); } - private static Parameter? getParameterByName(string name) + internal static Parameter? getParameterByName(string name) { if (OldParameterNames.TryGetValue(name, out string? newName)) { @@ -1889,7 +1927,7 @@ namespace WorldTuningTool private delegate void UpdateSSLREnvMapIntensity(nint stackOffset, bool unknownBool); private Hook? updateSSLREnvMapIntensity; - private static Parameter sslrEnvMapIntensity = P("SSLR Env Map Intensity", 0xB420, ParameterType.FLOAT); + private static Parameter sslrEnvMapIntensity = P("SSLR Env Map Intensity", 0xB420, ParameterType.FLOAT, pMinStep(0.0f, 0.01f)); private static Parameter[] sslrParameters = { P("SSLR Loop Count", 0xE628, ParameterType.INT, pStep(1)), P("SSLR Eliminate Depth", 0xE630, ParameterType.FLOAT), @@ -1936,7 +1974,7 @@ namespace WorldTuningTool // can be seen when returning to title or opening a guild card for the first time. Setting 'Bloom Renormalize' // to 0.0 or 'Bloom Reduction Resolution' to -1 can both effectively disable bloom without that issue. //newFlag("Bloom Enabled", 0x14, ParameterType.FLAG, (1 << 1)), // Draw - P("Bloom Threshold", 0x204, ParameterType.FLOAT), + P("Bloom Threshold", 0x204, ParameterType.FLOAT, pStep(0.001f)), P("Bloom Renormalize", 0x208, ParameterType.FLOAT, pMin(0.0f)), P("Bloom Color", 0x200, ParameterType.COLOR), P("Bloom Downsample Count", 0x168, ParameterType.INT, pMinMaxStep(0, 8, 1)), @@ -2043,9 +2081,9 @@ namespace WorldTuningTool P("Sky Sun Light Mask UV Scale", 0x2D0, ParameterType.FLOAT, pStep(0.001f)), P("Sky Sun Bloom Intensity", 0x2AC, ParameterType.FLOAT), P("Sky Sun Bloom Transparency Coefficient", 0x2B0, ParameterType.FLOAT, pStep(0.025f)), - P("Sky Sun Bloom Threshold", 0x2B4, ParameterType.FLOAT), + P("Sky Sun Bloom Threshold", 0x2B4, ParameterType.FLOAT, pStep(0.001f)), P("Sky Sun Bloom Dispersion", 0x2B8, ParameterType.FLOAT), - P("Sky Sun Bloom Downsample Count", 0x2C0, ParameterType.FLOAT), + P("Sky Sun Bloom Downsample Count", 0x2C0, ParameterType.FLOAT, pMinMaxStep(0, 8, 1)), P("Sky Sun Bloom Reduction Resolution", 0x2C4, ParameterType.INT, pStep(1)), P("Sky Sun Light Sky Color", 0x2E0, ParameterType.COLOR_FACTOR, pStep(0.001f)), P("Sky Sun Light Sky Mask UV Scale", 0x2F0, ParameterType.FLOAT, pStep(0.001f)), @@ -2240,9 +2278,9 @@ namespace WorldTuningTool bool reset = multiplier == 1; int unused1Value = Math.Clamp(0x1000 * multiplier, 0x1000, 0x4000); int unused2Value = Math.Clamp(0xC00 * multiplier, 0xC00, 0x4000); - int highValue = Math.Clamp((reset ? 0x800 : 0xC00) * multiplier, reset ? 0x800 : 0xC00, 0x4000); - int midValue = Math.Clamp( (reset ? 0x600 : 0x800) * multiplier, reset ? 0x600 : 0x800, 0x4000); - int lowValue = Math.Clamp( (reset ? 0x400 : 0x600) * multiplier, reset ? 0x400 : 0x600, 0x4000); + int highValue = Math.Clamp((reset ? 0x800 : 0xC00) * multiplier, (reset ? 0x800 : 0xC00), 0x4000); + int midValue = Math.Clamp( (reset ? 0x600 : 0x800) * multiplier, (reset ? 0x600 : 0x800), 0x4000); + int lowValue = Math.Clamp( (reset ? 0x400 : 0x600) * multiplier, (reset ? 0x400 : 0x600), 0x4000); new Patch(broadAreaShadowRes1_Addr + 0x45, BitConverter.GetBytes(unused1Value)).Enable(); new Patch(broadAreaShadowRes1_Addr + 0x45 + 0xB, BitConverter.GetBytes(unused2Value)).Enable(); new Patch(broadAreaShadowRes1_Addr + 0x45 + 0x16, BitConverter.GetBytes(highValue)).Enable(); @@ -2311,7 +2349,7 @@ namespace WorldTuningTool } setBroadAreaShadowResolution(multiplier); currentShadowResMultiplier = multiplier; - setShadowQuality.Invoke(MemoryUtil.Read(sMhScene!.Instance + 0x5530) + 1); + setShadowQuality.Invoke(sMhScene!.Get(0x5530) + 1); } private static void shadowResDisable() @@ -2346,7 +2384,7 @@ namespace WorldTuningTool shadowRes1_4.Disable(); setBroadAreaShadowResolution(1); currentShadowResMultiplier = 1; - setShadowQuality.Invoke(MemoryUtil.Read(sMhScene!.Instance + 0x5530) + 1); + setShadowQuality.Invoke(sMhScene!.Get(0x5530) + 1); } #if SHADER_FEATURES @@ -2616,11 +2654,11 @@ namespace WorldTuningTool 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 ?? ?? ?? ??")); Assert(addr == 0x14043FF80); - Assert(MemoryUtil.Read(0x142EE1A90) == 0x40000000); // 2.0. - Assert(MemoryUtil.Read(0x142E4FE5C) == 0x40400000); // 3.0. - Assert(MemoryUtil.Read(0x142F1FD4C) == 0x40800000); // 4.0. - Assert(MemoryUtil.Read(0x142F1FD50) == 0x40A00000); // 5.0. - Assert(MemoryUtil.Read(0x14321222C) == 0x40C00000); // 6.0. + Assert(Get(0x142EE1A90) == 0x40000000); // 2.0. + Assert(Get(0x142E4FE5C) == 0x40400000); // 3.0. + Assert(Get(0x142F1FD4C) == 0x40800000); // 4.0. + Assert(Get(0x142F1FD50) == 0x40A00000); // 5.0. + Assert(Get(0x14321222C) == 0x40C00000); // 6.0. shadowRes1_2x = new Patch(addr + 0x8, [0x04, 0x1B, 0xAA, 0x02]); shadowRes1_3x = new Patch(addr + 0x8, [0xD0, 0xFE, 0xA0, 0x02]); shadowRes1_4x = new Patch(addr + 0x8, [0xC0, 0xFD, 0xAD, 0x02]); @@ -2968,13 +3006,13 @@ namespace WorldTuningTool 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); + int numARecords = resource.Get(0xB8); + nint aRecords = resource.Get(0xF8); for (int i = 0; i < numARecords; i++) { nint aRecord = aRecords + (0x50 * i); } - MemoryUtil.GetRef(resource.Instance + 0xC4) = 1.0f / stepTimeFps; + resource.GetRef(0xC4) = 1.0f / stepTimeFps; } } #endif @@ -3001,7 +3039,7 @@ namespace WorldTuningTool if (setWeatherMode) { - MemoryUtil.GetRef(sQuest!.Instance + 0x293B4) = requestWeatherMode; + sQuest!.GetRef(0x293B4) = requestWeatherMode; } foreach (Parameter param in sTimeParameters) @@ -3561,7 +3599,7 @@ namespace WorldTuningTool private void UpdatePrimaryLightParamsHook(nint primaryLightParams, nint stackOffset) { - bool isPrimary = MemoryUtil.Read(stackOffset + 0x1D) == 0x1; + bool isPrimary = Get(stackOffset, 0x1D) == 0x1; if (isPrimary) { foreach (Parameter param in primaryLightParameters) @@ -3778,12 +3816,8 @@ namespace WorldTuningTool drawList.AddRectFilled(windowPos, windowPos + new Vector2(boxWidth, boxHeight), (uint)ColorVectorToInt(boxColor)); } - public void OnImGuiRender() + private void drawOverrides(Config config, List? globalOverrides, List? stageOverrides, float width) { - float width = ImGui.GetWindowWidth(); - width /= width / (600.0f * ImGui.GetIO().FontGlobalScale); - - ImGui.Text($"Current Stage: {StageToString(currentStage)}"); ImGui.PushItemWidth(width * 0.35f); if (ImGui.BeginCombo("##Stage", StageToString(selectedStage), ImGuiComboFlags.HeightLarge)) { @@ -3800,7 +3834,6 @@ namespace WorldTuningTool ImGui.EndCombo(); } ImGui.SameLine(); - Config config = getConfig(); bool errorStage = !config.Overrides.ContainsKey(currentStage); if (errorStage) { @@ -3849,8 +3882,7 @@ namespace WorldTuningTool selectedOrderChanged = true; } } - List? stageOverrides = maybeGetStageOverrides(config); - List? globalOverrides = null; + if (selectedStage != globalStage) { globalOverrides = config.Overrides[globalStage]; @@ -3884,6 +3916,7 @@ namespace WorldTuningTool } } ImGui.PopItemWidth(); + for (int i = 0; i < selectedOverrides.Count; i++) { ImGui.PushID(i); @@ -3930,6 +3963,7 @@ namespace WorldTuningTool } ImGui.PopID(); } + if (ImGui.Button("Save")) { for (int i = 0; i < selectedOverrides.Count; i++) @@ -3962,12 +3996,31 @@ namespace WorldTuningTool } ImGui.Separator(); + } + + public void OnImGuiRender() + { + float width = ImGui.GetWindowWidth(); + width /= width / (600.0f * ImGui.GetIO().FontGlobalScale); + + Config config = getConfig(); + + List? stageOverrides = maybeGetStageOverrides(config); + List? globalOverrides = null; + + bool expand = ImGui.CollapsingHeader("Current Stage:", ImGuiTreeNodeFlags.DefaultOpen); + ImGui.SameLine(); + ImGui.Text($"{StageToString(currentStage)}"); + if (expand) + { + drawOverrides(config, globalOverrides, stageOverrides, width); + } // From this point forward, we have to consider both globalOverrides and stageOverrides. globalOverrides = config.Overrides[globalStage]; ImGui.PushID("Set"); - ImGui.Text("Quick Sets:"); + ImGui.Text("Quick Sets"); ImGui.PushItemWidth(width * 0.35f); string prevSet = selectedSet; if (ImGui.Button("+")) @@ -4165,7 +4218,7 @@ namespace WorldTuningTool ImGui.Separator(); ImGui.PushID("External"); - ImGui.Text("External:"); + ImGui.Text("External"); foreach (Override ovE in externalOverrides.Values) { Vector2 cursorPos = default; @@ -4383,11 +4436,11 @@ namespace WorldTuningTool { if (ImGui.CollapsingHeader("Lights")) { - Lights.DrawUI(width); + Lights.drawUI(width); } } - bool expand = ImGui.CollapsingHeader("Parameters"); + expand = ImGui.CollapsingHeader("Parameters"); if (ImGui.BeginItemTooltip()) { ImGui.Text("(Original: X) may be inaccurate for various reasons, such as\n 1. The game set the parameter to the same value as an override from this mod.\n 2. The game is dynamically updating the parameter in a location unknown to this mod."); @@ -4476,10 +4529,16 @@ namespace WorldTuningTool ImGui.PopID(); ImGui.PushID("PrimaryLight"); - if (ImGui.CollapsingHeader("Primary Light")) + expand = ImGui.CollapsingHeader("Primary Light"); + if (ImGui.BeginItemTooltip()) + { + ImGui.Text("These are the per-frame parameters of the Primary uMhInfiniteLight, which can also be found under Lights -> Scene Lights -> Infinite"); + ImGui.EndTooltip(); + } + if (expand) { // MonsterHunterWorld.exe+1AB99E0 - mov rax,[MonsterHunterWorld.exe+500E180] - nint primaryLightObject = MemoryUtil.Read(MemoryUtil.Read(0x14500E180) + 0x4B0); + nint primaryLightObject = Get(Get(0x14500E180), 0x4B0); ImGui.Text($"Address: 0x{primaryLightObject:X}"); foreach (Parameter param in primaryLightParameters) { @@ -4550,17 +4609,17 @@ namespace WorldTuningTool { if (ImGui.CollapsingHeader("LUTs")) { - nint lutBlendTexture = MemoryUtil.Read(toneMapObject + 0x1C0); + nint lutBlendTexture = Get(toneMapObject, 0x1C0); ImGui.Text($"LUT Blend: 0x{lutBlendTexture:X}"); - nint lutMap0 = MemoryUtil.Read(toneMapObject + 0x1A8); + nint lutMap0 = Get(toneMapObject, 0x1A8); if (lutMap0 != 0x0) { - WorldLUTs.DrawUI(lutMap0, toneMapObject, 0, width); + WorldLUTs.drawUI(lutMap0, toneMapObject, 0, width); } - nint lutMap1 = MemoryUtil.Read(toneMapObject + 0x1B0); + nint lutMap1 = Get(toneMapObject, 0x1B0); if (lutMap1 != 0x0) { - WorldLUTs.DrawUI(lutMap1, toneMapObject, 1, width); + WorldLUTs.drawUI(lutMap1, toneMapObject, 1, width); } } foreach (Parameter param in toneMapParameters) @@ -4866,16 +4925,16 @@ namespace WorldTuningTool } ImGui.PushItemWidth(width * 0.15f); - ImGui.Text($"FPS: {MemoryUtil.GetRef(sMhMain!.Instance + 0x68)}"); - ImGui.Text($"Delta Time: {MemoryUtil.GetRef(sMhMain!.Instance + 0x94)}"); + ImGui.Text($"FPS: {sMhMain!.Get(0x68)}"); + ImGui.Text($"Delta Time: {sMhMain!.Get(0x94)}"); // Locations taken from MHW-DTI-Dumps/wip_dump_15_20_00.h. - ImGui.InputFloat("Simulation FPS", ref MemoryUtil.GetRef(sMhMain!.Instance + 0x58)); + ImGui.InputFloat("Simulation FPS", ref sMhMain!.GetRef(0x58)); if (ImGui.BeginItemTooltip()) { ImGui.Text("This does not apply to jiggle physics."); ImGui.EndTooltip(); } - ImGui.InputFloat("Max FPS", ref MemoryUtil.GetRef(sMhMain!.Instance + 0x5C)); + ImGui.InputFloat("Max FPS", ref sMhMain!.GetRef(0x5C)); ImGui.PopItemWidth(); ImGui.Text($"sLightLinker: 0x{sLightLinker!.Instance:X}"); @@ -4911,7 +4970,7 @@ namespace WorldTuningTool private const string shaderPath = "nativePC/plugins/CSharp/Shaders"; private bool shadersLoadedOnce = false; - public unsafe void OnCreateShader(ShaderInfo *info) + public void OnCreateShader(ShaderInfo *info) { string hash = new string(info->DxbcHash); -- cgit v1.2.3-101-g0448