using System.Numerics; using ImGuiNET; using SharpPluginLoader.Core; using SharpPluginLoader.Core.Memory; using SharpPluginLoader.Core.Entities; namespace WorldTuningTool { using static Plugin; public class Lights { public Lights() { } private class Light { public nint Object; public int Type; public Parameter[] Parameters = { newParameter("Group", 0x13C, ParameterType.INT, pMinMaxStep(1, 255, 1)), // 1 = World, (1 << 1) = Player/Palico, (1 << 2) = NPCs newFrameParameter("Position", 0x5A0, ParameterType.VECTOR3, pStep(0.15f)), newFrameParameter("Color", 0x140, ParameterType.COLOR), newFrameParameter("Intensity", 0x8A8, ParameterType.FLOAT), newFrameParameter("Radius", 0x6A0, ParameterType.FLOAT, pStep(0.25f)), newFrameParameter("Effective Radius", 0x588, ParameterType.FLOAT, pStep(0.25f)), newFrameParameter("Min Roughness", 0x58C, ParameterType.FLOAT, pStep(0.0025f)), newParameter("Do Volumetric", 0x590, ParameterType.BOOL), newFlag("Shadow Cast", 0x138, ParameterType.FLAG, (1 << 23)), newParameter("Shadow Map Size", 0x1B8, ParameterType.ALIGNED_INT, pMinStep(0, 128)), newParameter("Shadow Near Clip Distance", 0x1B4, ParameterType.FLOAT), newFrameParameter("Shadow Depth Bias", 0x57C, ParameterType.FLOAT, pStep(0.00001f)), newFrameParameter("Shadow Sloped Depth Bias", 0x580, ParameterType.FLOAT, pStep(0.00001f)), newFrameParameter("Shadow Max Depth Bias", 0x584, ParameterType.FLOAT, pStep(0.00001f)), }; public Light(nint lightObject, int type) { Object = lightObject; Type = type; foreach (Parameter param in Parameters) { param.Update(lightObject); } } public Light(nint lightObject, int type, Vector3 pos) { Object = lightObject; Type = type; foreach (Parameter param in Parameters) { param.OverrideOn(false); } Parameters[0].SetOverrideValue(default, 255); Parameters[1].SetOverrideValue(new Vector4(pos.X, pos.Y, pos.Z, 0.0f), 0); Parameters[3].SetOverrideValue(new Vector4(10.0f, 0.0f, 0.0f, 0.0f), 0); foreach (Parameter param in Parameters) { param.Update(lightObject); } } } // Point Light (2): // Create1: 0x141F875A0 () // Create2: 0x141F87CD0 (nint) // Destroy: 0x141F87D90 (nint, int) // // Spot Light (3): // Create1: 0x141F8AE80 () // Create2: 0x141F8B2D0 (nint) // Destroy: 0x141F8B390 (nint, int) // // Hemi Sphere Light (4): // Create1: 0x141F84840 () // Create2: 0x141F84990 (nint) // Destroy: 0x141F84A40 (nint, int) // // Wrapper? (8): // Create1: 0x141F816C0 () // Create2: 0x141F81800 () // Destroy: 0x141F81940 (nint, int) private int requestLightType = 2; private NativeFunction createLight; //private bool interceptCreateLight = false; private List ourLights = new List(); //private List sceneLights = new List(); private NativeAction addToScene; private NativeAction removeFromScene; //private delegate nint CreateLightObject(int type); //private Hook? createLightObject; private delegate void DestroyLightObject(nint lightObject, int unknownInt); private Hook? destroyLightObject; private delegate void UpdateLights(nint lightObject); private Hook? updateLights; public void Initialize() { createLight = new NativeFunction(0x1418A3EF0); //createLightObject = Hook.Create(0x1418A3EF0, CreateLightObjectHook); destroyLightObject = Hook.Create(0x141F87D90, DestroyLightObjectHook); addToScene = new NativeAction(0x142219070); removeFromScene = new NativeAction(0x142228F10); updateLights = Hook.Create(0x141F88F30, UpdateLightsHook); } /* private nint CreateLightObjectHook(int type) { nint lightObject = createLightObject!.Original(type); if (interceptCreateLight) { interceptCreateLight = false; } //else if (type == 2) else { sceneLights.Add(new Light(lightObject, type)); } return lightObject; } */ private void UpdateLightsHook(nint lightObject) { Light? light = null; /* for (int i = 0; i < sceneLights.Count; i++) { if (lightObject == sceneLights[i].Object) { light = sceneLights[i]; break; } } */ if (light == null) { for (int i = 0; i < ourLights.Count; i++) { if (lightObject == ourLights[i].Object) { light = ourLights[i]; break; } } } updateLights!.Original(lightObject); if (light != null) { foreach (Parameter param in light.Parameters) { param.Update(lightObject); } } } private void DestroyLightObjectHook(nint lightObject, int unknownInt) { /* for (int i = 0; i < sceneLights.Count; i++) { if (lightObject == sceneLights[i].Object) { sceneLights.RemoveAt(i); break; } } */ for (int i = 0; i < ourLights.Count; i++) { if (lightObject == ourLights[i].Object) { ourLights.RemoveAt(i); break; } } destroyLightObject!.Original(lightObject, unknownInt); } public unsafe void DrawUI(float width) { /* ImGui.NextItemWidth(width * 0.25f); ImGui.InputInt("Type", ref requestLightType, 1); ImGui.SameLine(); */ if (ImGui.Button("New")) { //interceptCreateLight = true; 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, requestLightType, pos)); // mov byte ptr[rsp+20],00 unaccounted for, hopefully it never matters. addToScene.Invoke(MemoryUtil.Read(0x1451238C8), 0x16, lightObject, 0x0); } ImGui.Separator(); ImGui.PushID("Ours"); for (int i = 0; i < ourLights.Count; i++) { Light light = ourLights[i]; ImGui.PushID(i); ImGui.Text($"Type: {light.Type}, Address: 0x{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); } ImGui.PopID(); ImGui.Separator(); } ImGui.PopID(); ImGui.PushID("Scene"); /* if (ImGui.CollapsingHeader("Scene Lights")) { for (int i = 0; i < sceneLights.Count; i++) { Light light = sceneLights[i]; ImGui.PushID(i); ImGui.Text($"Type: {light.Type}, Address: 0x{light.Object:X}"); foreach (Parameter param in light.Parameters) { param.Draw(width); } if (ImGui.Button("Remove")) { removeFromScene.Invoke(light.Object); } ImGui.PopID(); ImGui.Separator(); } } */ ImGui.PopID(); } } }