using System.Reflection; using System.Runtime.Loader; using System.Runtime.InteropServices; using ImGuiNET; using SharpPluginLoader.Core; using SharpPluginLoader.Core.Memory; namespace WorldTuningTool { public unsafe class Plugin : IPlugin { public string Name => "World Tuning Tool"; public string Author => "Akon City Software"; // @TODO: // - Port FXAA object. // - Port some stuff as is. // - OnAreaChange. // - Shadow distance retuning. // - Work out obvious simplifications. // - sMhRenderer vs common parameter address. // - Overrides system. // - Pass on LODs. // - Verbose descriptions. // - Re-implement shadow res override for hoarfrost. // - Exact float flag for hex input? private bool dofDisabled = false; private Patch jmpOverDof; public void SetDofForceOff(bool off) { if (off && !dofDisabled) { jmpOverDof.Enable(); } else if (!off && dofDisabled) { jmpOverDof.Disable(); } dofDisabled = off; } public bool GetDofDisabled() { return dofDisabled; } /* public PluginData Initialize() { PluginData data = new PluginData(); data.ExportedFunctions.Add(("SetDofForceOff", SetDofForceOff)); data.ExportedFunctions.Add(("GetDofDisabled", GetDofDisabled)); return data; } */ public void OnPreMain() { unchecked { jmpOverDof = new Patch((nint)0x1424233C6, [0xEB]); // je -> jmp. } } 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_upsample.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."); } } */ } public void OnLoad() { } public void OnImGuiRender() { if (ImGui.Checkbox("Disable Depth of Field", ref dofDisabled)) { if (dofDisabled) { jmpOverDof.Enable(); } else { jmpOverDof.Disable(); } } } } }