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 uLight { public nint Object = 0x0; public virtual int Type => -1; public virtual string Name => $"uLight"; public virtual string Info => $"0x{Object:X}"; public List Parameters = new List(); public void UpdateParams() { Assert(Object != 0x0); foreach (Parameter param in Parameters) { param.Update(Object); } } public uLight(nint lightObject) { Object = lightObject; Parameters.AddRange(new Parameter[]{ M("Group", 0x13C, ParameterType.INT, 0x7, pMinMaxStep(0, 7, 1)), // 1 = World, (1 << 1) = Player/Palico, (1 << 2) = NPCs M("Priority", 0x138, ParameterType.INT, (0xFF << 6), pMinMaxStep(0, 255, 1)), P("Color", 0x140, ParameterType.COLOR), P("Intensity", 0x144, ParameterType.FLOAT), P("Min Roughness", 0x58C, ParameterType.FLOAT, pStep(0.001f)), M("Disp", 0x138, ParameterType.FLAG, (1 << 24)), M("Primary", 0x138, ParameterType.FLAG, (1 << 26)), M("Shadow Cast", 0x138, ParameterType.FLAG, (1 << 23)), M("Shadow Priority", 0x138, ParameterType.INT, (0xFF << 14), pMinMaxStep(0, 255, 1)), P("Shadow Map Size", 0x1B8, ParameterType.ALIGNED_INT, pMinStep(0, 128)), // Result of mShadowMapSize. P("Near Clip Distance", 0x1B4, ParameterType.FLOAT), P("Shadow Depth Bias", 0x57C, ParameterType.FLOAT, pStep(0.00001f)), P("Shadow Sloped Depth Bias", 0x580, ParameterType.FLOAT, pStep(0.00001f)), P("Shadow Max Depth Bias", 0x584, ParameterType.FLOAT, pStep(0.00001f)), P("Use Umbra", 0x591, ParameterType.BOOL), P("Enable Camera Lod", 0x592, ParameterType.BOOL), P("Do Volumetric", 0x590, ParameterType.BOOL) }); UpdateParams(); } } private class uInfiniteLight : uLight { public override int Type => 1; public override string Name => $"uInfiniteLight"; // mpTexture unaccounted for. public uInfiniteLight(nint lightObject) : base(lightObject) { Parameters.AddRange(new Parameter[]{ P("Direction", 0x5A0, ParameterType.VECTOR3, pStep(0.00025f)), P("Shadow Distance", 0x5B0, ParameterType.FLOAT), P("Shadow Backforward Distance", 0x5B8, ParameterType.FLOAT), P("Shadow Distribution", 0x5B4, ParameterType.FLOAT), P("Shadow Radius Scale", 0x5BC, ParameterType.FLOAT), P("Manual Split", 0x5C1, ParameterType.BOOL), P("Individual Shadow Bias", 0x5D0, ParameterType.BOOL), P("Cascade Blend", 0x5C0, ParameterType.FLOAT), P("Fov", 0x630, ParameterType.FLOAT), P("Is Fixed Fov Mode", 0x634, ParameterType.BOOL), P("Is Discretized Fov Mode", 0x63C, ParameterType.BOOL), P("Discretization Angle", 0x638, ParameterType.FLOAT), P("Manual Split Distance[0]", 0x5C4, ParameterType.FLOAT), P("Cascade Depth Bias[0]", 0x5D4, ParameterType.FLOAT, pStep(0.00001f)), P("Cascade Sloped Depth Bias[0]", 0x5E0, ParameterType.FLOAT, pStep(0.00001f)), P("Cascade Max Depth Bias[0]", 0x5EC, ParameterType.FLOAT, pStep(0.00001f)), P("Manual Split Distance[1]", 0x5C8, ParameterType.FLOAT), P("Cascade Depth Bias[1]", 0x5D8, ParameterType.FLOAT, pStep(0.00001f)), P("Cascade Sloped Depth Bias[1]", 0x5E4, ParameterType.FLOAT, pStep(0.00001f)), P("Cascade Max Depth Bias[1]", 0x5F0, ParameterType.FLOAT, pStep(0.00001f)), P("Manual Split Distance[2]", 0x5CC, ParameterType.FLOAT), P("Cascade Depth Bias[2]", 0x5DC, ParameterType.FLOAT, pStep(0.00001f)), P("Cascade Sloped Depth Bias[2]", 0x5E8, ParameterType.FLOAT, pStep(0.00001f)), P("Cascade Max Depth Bias[2]", 0x5F4, ParameterType.FLOAT, pStep(0.00001f)), P("Projection Scale", 0x600, ParameterType.VECTOR2), P("Projection Offset", 0x60C, ParameterType.VECTOR2), P("Projection Up", 0x620, ParameterType.VECTOR3) }); UpdateParams(); } } private class uMhInfiniteLight : uInfiniteLight { public override string Name => $"uMhInfiniteLight"; public uMhInfiniteLight(nint lightObject) : base(lightObject) { Parameters.AddRange(new Parameter[]{ P("Projection Offset Speed", 0x6D0, ParameterType.VECTOR2), P("Projection Offset Current", 0x6D8, ParameterType.VECTOR2) }); UpdateParams(); } } private class uMhActorInfiniteLight : uMhInfiniteLight { public override string Name => $"uMhActorInfiniteLight"; public uMhActorInfiniteLight(nint lightObject) : base(lightObject) { } } private class uLlkInfiniteLight : uInfiniteLight { public override string Name => $"uLlkInfiniteLight"; public nint CycleTimelineRes => MemoryUtil.Read(Object + 0x658); public int CycleAnimNo => MemoryUtil.Read(Object + 0x7A8); public uLlkInfiniteLight(nint lightObject) : base(lightObject) { Parameters.AddRange(new Parameter[]{ P("Llk Color", 0x640, ParameterType.COLOR), P("Llk Intensity", 0x644, ParameterType.FLOAT), P("Projection Offset Speed", 0x648, ParameterType.VECTOR2) }); UpdateParams(); } } private class uLlkActorInfiniteLight : uLlkInfiniteLight { public override string Name => $"uLlkActorInfiniteLight"; public uLlkActorInfiniteLight(nint lightObject) : base(lightObject) { } } private class uLlkFollowCameraInfiniteLight : uLlkInfiniteLight { public override string Name => $"uLlkFollowCameraInfiniteLight"; public uLlkFollowCameraInfiniteLight(nint lightObject) : base(lightObject) { } } private class uPointLight : uLight { public override int Type => 2; public override string Name => $"uPointLight"; public override string Info => $"0x{Object:X}" + (Parent != 0x0 ? $", Parent: 0x{Parent:X}" : ""); public nint Parent => MemoryUtil.Read(Object + 0x5C0); public int ParentNo => MemoryUtil.Read(Object + 0x5C8); public Vector3 Position => MemoryUtil.Read(Object + 0x5A0); public uPointLight(nint lightObject) : base(lightObject) { Parameters.AddRange(new Parameter[]{ P("Position", 0x5A0, ParameterType.VECTOR3, pStep(0.15f)), P("Radius", 0x1B0, ParameterType.FLOAT), P("Effective Radius", 0x588, ParameterType.FLOAT) }); UpdateParams(); } } private class uMhPointLight : uPointLight { public override string Name => $"uMhPointLight"; public uMhPointLight(nint lightObject) : base(lightObject) { Parameters.AddRange(new Parameter[]{ P("Multiply Radius Square", 0x5D0, ParameterType.BOOL) }); UpdateParams(); } public uMhPointLight(nint lightObject, Vector3 pos) : this(lightObject) { foreach (Parameter param in Parameters) { param.OverrideOn(false); } Parameters[0].SetOverrideValue(default, 0x7); Parameters[3].SetOverrideValue(new Vector4(10.0f, 0.0f, 0.0f, 0.0f), 0); Parameters[17].SetOverrideValue(new Vector4(pos.X, pos.Y, pos.Z, 0.0f), 0); } } private class uMhActorPointLight : uMhPointLight { public override string Name => $"uMhActorPointLight"; public uMhActorPointLight(nint lightObject) : base(lightObject) { } } private class uLlkPointLight : uPointLight { public override string Name => $"uLlkPointLight"; public nint TimelineRes => MemoryUtil.Read(Object + 0x8A4); public int AnimNo => MemoryUtil.Read(Object + 0x7A8); public NativeAction PlayResource = new NativeAction(0x141F89CB0); public NativeAction StopResource = new NativeAction(0x141F8A0C0); public nint CycleTimelineRes => MemoryUtil.Read(Object + 0x750); public int CycleAnimNo => MemoryUtil.Read(Object + 0x8A0); public uLlkPointLight(nint lightObject) : base(lightObject) { Parameters.AddRange(new Parameter[]{ P("Llk Color", 0x970, ParameterType.COLOR), P("Llk Intensity", 0x974, ParameterType.FLOAT), P("Llk Radius", 0x978, ParameterType.FLOAT), P("Llk Effective Radius", 0x97C, ParameterType.FLOAT), P("Multiply Radius Square", 0x980, ParameterType.BOOL), P("Random Param Bits", 0x6C8, ParameterType.HEX), P("Force Set Time", 0x8B4, ParameterType.FLOAT), P("Near Fade Out Start Distance", 0x8D4, ParameterType.FLOAT), P("Near Fade Out End Distance", 0x8D8, ParameterType.FLOAT), P("Fade Out Start Distance", 0x8DC, ParameterType.FLOAT), P("Fade Out End Distance", 0x8E0, ParameterType.FLOAT), P("Random Move Radius", 0x8E8, ParameterType.FLOAT), P("Random Move Friction", 0x900, ParameterType.VECTOR3), P("Random Move Force To Center", 0x8EC, ParameterType.FLOAT), P("Random Move Time Min", 0x8F8, ParameterType.FLOAT), P("Random Move Time Max", 0x8FC, ParameterType.FLOAT), P("Random Move Speed V Max", 0x940, ParameterType.VECTOR3), P("Random Move Force V Max", 0x960, ParameterType.VECTOR3) }); UpdateParams(); } } private class uLlkActorPointLight : uLlkPointLight { public override string Name => $"uLlkActorPointLight"; public uLlkActorPointLight(nint lightObject) : base(lightObject) { } } private class uLlkFollowCameraPointLight : uLlkPointLight { public override string Name => $"uLlkFollowCameraPointLight"; public uLlkFollowCameraPointLight(nint lightObject) : base(lightObject) { } } private class uSpotLight : uLight { public override int Type => 3; public override string Name => $"uSpotLight"; public override string Info => $"0x{Object:X}, Parent: 0x{Parent:X}"; public nint Parent => MemoryUtil.Read(Object + 0x600); public int ParentNo => MemoryUtil.Read(Object + 0x610); public nint Target => MemoryUtil.Read(Object + 0x608); public int TargetNo => MemoryUtil.Read(Object + 0x614); public nint Texture => MemoryUtil.Read(Object + 0x670); public nint ShadowCacheResource => MemoryUtil.Read(Object + 0x698); public Vector3 Position => MemoryUtil.Read(Object + 0x5A0); public uSpotLight(nint lightObject) : base(lightObject) { Parameters.AddRange(new Parameter[]{ P("Position", 0x5A0, ParameterType.VECTOR3, pStep(0.15f)), P("Direction", 0x5B0, ParameterType.VECTOR3, pStep(0.0025f)), P("Target Position", 0x5C0, ParameterType.VECTOR3, pStep(0.15f)), P("Target Mode", 0x5F8, ParameterType.BOOL), P("Radius", 0x1B0, ParameterType.FLOAT), P("Effective Radius", 0x588, ParameterType.FLOAT), P("Cone", 0x5F0, ParameterType.FLOAT, pStep(0.01f)), P("Spread", 0x5F0, ParameterType.FLOAT, pStep(0.01f)), P("Falloff", 0x618, ParameterType.FLOAT, pStep(0.01f)), P("Projection Scale", 0x67C, ParameterType.VECTOR2), P("Projection Offset", 0x684, ParameterType.VECTOR2), P("Projection Rotation Z", 0x68C, ParameterType.FLOAT), P("Texture Index", 0x678, ParameterType.INT, pStep(1)), P("Use Shadow Cache", 0x690, ParameterType.BOOL) }); UpdateParams(); } } private class uMhSpotLight : uSpotLight { public override string Name => $"uMhSpotLight"; public uMhSpotLight(nint lightObject) : base(lightObject) { Parameters.AddRange(new Parameter[]{ P("Multiply Radius Square", 0x6A0, ParameterType.BOOL), }); UpdateParams(); } public uMhSpotLight(nint lightObject, Vector3 pos) : this(lightObject) { foreach (Parameter param in Parameters) { param.OverrideOn(false); } Parameters[0].SetOverrideValue(default, 0x7); Parameters[3].SetOverrideValue(new Vector4(350.0f, 0.0f, 0.0f, 0.0f), 0); Parameters[17].SetOverrideValue(new Vector4(pos.X, pos.Y + 200.0f, pos.Z, 0.0f), 0); Parameters[19].SetOverrideValue(new Vector4(pos.X, pos.Y, pos.Z, 0.0f), 0); Parameters[20].SetOverrideValue(default, 1); Parameters[23].SetOverrideValue(new Vector4(45.0f, 0.0f, 0.0f, 0.0f), 0); } } private class uMhActorSpotLight : uMhSpotLight { public override string Name => $"uMhActorSpotLight"; public uMhActorSpotLight(nint lightObject) : base(lightObject) { } } private class uLlkSpotLight : uSpotLight { public override string Name => $"uLlkSpotLight"; public nint TimelineRes => MemoryUtil.Read(Object + 0x790); public int AnimNo => MemoryUtil.Read(Object + 0x974); public NativeAction PlayResource = new NativeAction(0x141F8D550); public NativeAction StopResource = new NativeAction(0x141F8D970); public nint CycleTimelineRes => MemoryUtil.Read(Object + 0x820); public int CycleAnimNo => MemoryUtil.Read(Object + 0x970); public uLlkSpotLight(nint lightObject) : base(lightObject) { Parameters.AddRange(new Parameter[]{ P("Llk Color", 0xA40, ParameterType.COLOR), P("Llk Intensity", 0xA44, ParameterType.FLOAT), P("Llk Radius", 0xA48, ParameterType.FLOAT), P("Llk Effective Radius", 0xA4C, ParameterType.FLOAT), P("Llk Cone", 0xA50, ParameterType.FLOAT), P("Llk Spread", 0xA54, ParameterType.FLOAT), P("Llk Falloff", 0xA58, ParameterType.FLOAT), P("Multiply Radius Square", 0xA68, ParameterType.BOOL), P("Random Param Bits", 0x798, ParameterType.HEX), P("Force Set Time", 0x984, ParameterType.FLOAT), P("Near Fade Out Start Distance", 0x9A4, ParameterType.FLOAT), P("Near Fade Out End Distance", 0x9A8, ParameterType.FLOAT), P("Fade Out Start Distance", 0x9AC, ParameterType.FLOAT), P("Fade Out End Distance", 0x9B0, ParameterType.FLOAT), P("Random Move Radius", 0x9B8, ParameterType.FLOAT), P("Random Move Friction", 0x9D0, ParameterType.VECTOR3), P("Random Move Force To Center", 0x9BC, ParameterType.FLOAT), P("Random Move Time Min", 0x9C8, ParameterType.FLOAT), P("Random Move Time Max", 0x9CC, ParameterType.FLOAT), P("Random Move Speed V Max", 0xA10, ParameterType.VECTOR3), P("Random Move Force V Max", 0xA30, ParameterType.VECTOR3), P("Projection Offset Speed", 0xA60, ParameterType.VECTOR2) }); UpdateParams(); } } private class uLlkActorSpotLight : uLlkSpotLight { public override string Name => $"uLlkActorSpotLight"; public uLlkActorSpotLight(nint lightObject) : base(lightObject) { } } private class uLlkNullAngleSpotLight : uLlkSpotLight { public override string Name => $"uLlkNullAngleSpotLight"; public uLlkNullAngleSpotLight(nint lightObject) : base(lightObject) { } } private class uLlkFollowCameraSpotLight : uLlkSpotLight { public override string Name => $"uLlkFollowCameraSpotLight"; public uLlkFollowCameraSpotLight(nint lightObject) : base(lightObject) { } } private class uHemiSphereLight : uLight { public override int Type => 4; public override string Name => $"uHemiSphereLight"; public uHemiSphereLight(nint lightObject) : base(lightObject) { Parameters.AddRange(new Parameter[]{ P("Rev Color", 0x5A0, ParameterType.COLOR), P("Rev Intensity", 0x5A4, ParameterType.FLOAT), P("Direction", 0x5B0, ParameterType.VECTOR3, pStep(0.00025f)) }); UpdateParams(); } } private class uMhHemiSphereLight : uHemiSphereLight { public override string Name => $"uMhHemiSphereLight"; public uMhHemiSphereLight(nint lightObject) : base(lightObject) { } public uMhHemiSphereLight(nint lightObject, Vector3 pos) : this(lightObject) { foreach (Parameter param in Parameters) { param.OverrideOn(false); } } } private class uLlkHemiSphereLight : uHemiSphereLight { public override string Name => $"uLlkHemiSphereLight"; public nint CycleTimelineRes => MemoryUtil.Read(Object + 0x5D0); public int CycleAnimNo => MemoryUtil.Read(Object + 0x720); public uLlkHemiSphereLight(nint lightObject) : base(lightObject) { Parameters.AddRange(new Parameter[]{ P("Llk Color", 0x5C0, ParameterType.COLOR), P("Llk Intensity", 0x5C8, ParameterType.FLOAT), P("Llk Rev Color", 0x5C4, ParameterType.COLOR), P("Llk Rev Intensity", 0x5CC, ParameterType.FLOAT) }); UpdateParams(); } } private class uMhObjectLight : uLight { public override int Type => 5; public override string Name => $"uMhObjectLight"; public uMhObjectLight(nint lightObject) : base(lightObject) { } } private class uLlkObjectLight : uLight { public override string Name => $"uLlkObjectLight"; public uLlkObjectLight(nint lightObject) : base(lightObject) { } } private delegate nint CreateLightObject(nint lightObject); private delegate nint DestroyLightObject(nint lightObjectInternal, int unknownInt); private Hook? createLightObject; private static Dictionary> lightTypes = new Dictionary>() { { lton(0x143514168), (x) => new uLight(x) }, { lton(0x143514288), (x) => new uInfiniteLight(x) }, { lton(0x1434994D0), (x) => new uMhInfiniteLight(x) }, { lton(0x1434954F0), (x) => new uMhActorInfiniteLight(x) }, { lton(0x143494150), (x) => new uLlkInfiniteLight(x) }, { lton(0x1434936A0), (x) => new uLlkActorInfiniteLight(x) }, { lton(0x143493E30), (x) => new uLlkFollowCameraInfiniteLight(x) }, { lton(0x1435143A8), (x) => new uPointLight(x) }, { lton(0x14349A6C8), (x) => new uMhPointLight(x) }, { lton(0x1434952B0), (x) => new uMhActorPointLight(x) }, { lton(0x1434944E8), (x) => new uLlkPointLight(x) }, { lton(0x143493460), (x) => new uLlkActorPointLight(x) }, { lton(0x143493BF0), (x) => new uLlkFollowCameraPointLight(x) }, { lton(0x1435144C8), (x) => new uSpotLight(x) }, { lton(0x14349E280), (x) => new uMhSpotLight(x) }, { lton(0x1434953D0), (x) => new uMhActorSpotLight(x) }, { lton(0x143494888), (x) => new uLlkSpotLight(x) }, { lton(0x143493580), (x) => new uLlkActorSpotLight(x) }, { lton(0x1434937C0), (x) => new uLlkNullAngleSpotLight(x) }, { lton(0x143493D10), (x) => new uLlkFollowCameraSpotLight(x) }, { lton(0x1435145E8), (x) => new uHemiSphereLight(x) }, { lton(0x143499378), (x) => new uMhHemiSphereLight(x) }, { lton(0x143493F98), (x) => new uLlkHemiSphereLight(x) }, { lton(0x14349A498), (x) => new uMhObjectLight(x) }, { lton(0x1434942A0), (x) => new uLlkObjectLight(x) }, { lton(0x143493918), (x) => new uLight(x) }, // @TODO: uLlkBaseModel is not implemented. }; private static nint[] lightObjectDestructors = { lton(0x142311FF0), // # uLight lton(0x142311F40), // # uInfiniteLight lton(0x141FB8F50), // # uMhInfiniteLight lton(0x141F91DE0), // # uMhActorInfiniteLight lton(0x141F855A0), // # uLlkInfiniteLight lton(0x141F81940), // # uLlkActorInfiniteLight lton(0x141F83B00), // # uLlkFollowCameraInfiniteLight lton(0x142312070), // # uPointLight lton(0x141FC0950), // # uMhPointLight lton(0x141F91E80), // # uMhActorPointLight lton(0x141F87D90), // # uLlkPointLight lton(0x141F819B0), // # uLlkActorPointLight lton(0x141F83B70), // # uLlkFollowCameraPointLight lton(0x1423120F0), // # uSpotLight lton(0x141FDE0D0), // # uMhSpotLight lton(0x141F91F20), // # uMhActorSpotLight lton(0x141F8B390), // # uLlkSpotLight lton(0x141F81A20), // # uLlkActorSpotLight lton(0x141F81A90), // # uLlkNullAngleSpotLight lton(0x141F83BE0), // # uLlkFollowCameraSpotLight lton(0x142311EC0), // # uHemiSphereLight lton(0x141FB8C20), // # uMhHemiSphereLight lton(0x141F84A40), // # uLlkHemiSphereLight lton(0x141FBF6B0), // # uMhObjectLight lton(0x141F86270), // # uLlkObjectLight lton(0x141F83460), // # uLlkBaseModel }; private Hook[] lightObjectDestructorHooks = new Hook[lightObjectDestructors.Length]; private List newLights = new List(); private List sceneLights = new List(); private bool sortByDistanceToPlayerPoint = false; private bool sortByDistanceToPlayerSpot = false; private NativeAction addToScene; private NativeAction removeFromScene; private List ourLights = new List(); public void Initialize() { createLightObject = Hook.Create(0x142311420, CreateLightObjectHook); DestroyLightObject[] destructorHookFuncs = { DestroyLightObjectHook0, DestroyLightObjectHook1, DestroyLightObjectHook2, DestroyLightObjectHook3, DestroyLightObjectHook4, DestroyLightObjectHook5, DestroyLightObjectHook6, DestroyLightObjectHook7, DestroyLightObjectHook8, DestroyLightObjectHook9, DestroyLightObjectHook10, DestroyLightObjectHook11, DestroyLightObjectHook12, DestroyLightObjectHook13, DestroyLightObjectHook14, DestroyLightObjectHook15, DestroyLightObjectHook16, DestroyLightObjectHook17, DestroyLightObjectHook18, DestroyLightObjectHook19, DestroyLightObjectHook20, DestroyLightObjectHook21, DestroyLightObjectHook22, DestroyLightObjectHook23, DestroyLightObjectHook24, DestroyLightObjectHook25 }; for (int i = 0; i < lightObjectDestructors.Length; i++) { lightObjectDestructorHooks[i] = Hook.Create(lightObjectDestructors[i], destructorHookFuncs[i]); } addToScene = new NativeAction(0x142219070); removeFromScene = new NativeAction(0x142228F10); } public void PostUpdateLightLinker() { foreach (uLight light in sceneLights) { foreach (Parameter param in light.Parameters) { param.Update(light.Object); } } } public void OnUpdate() { lock (newLights) { for (int i = newLights.Count - 1; i >= 0; i--) { uLight light = newLights[i]; newLights.RemoveAt(i); nint vTable = MemoryUtil.Read(light.Object); if (lightTypes.ContainsKey(vTable)) { if (vTable == lton(0x143514168)) { Log.Error("Light is still uLight OnUpdate()."); } sceneLights.Add(lightTypes[vTable](light.Object)); } else { Log.Error($"Unknown Light Type: 0x{vTable:X}."); } } } } private nint CreateLightObjectHook(nint lightObject) { lightObject = createLightObject!.Original(lightObject); uLight light = new uLight(lightObject); lock (newLights) { newLights.Add(light); } return lightObject; } private void cleanupCommon(nint lightObject) { for (int i = 0; i < sceneLights.Count; i++) { uLight light = sceneLights[i]; if (lightObject == light.Object) { sceneLights.RemoveAt(i); return; } } for (int i = 0; i < ourLights.Count; i++) { uLight light = ourLights[i]; if (lightObject == light.Object) { ourLights.RemoveAt(i); return; } } lock (newLights) { for (int i = 0; i < newLights.Count; i++) { uLight light = newLights[i]; if (lightObject == light.Object) { newLights.RemoveAt(i); return; } } } } private nint DestroyLightObjectHook0(nint lightObject, int unknownInt) { Assert(unknownInt == 1); cleanupCommon(lightObject); return lightObjectDestructorHooks[0]!.Original(lightObject, unknownInt); } private nint DestroyLightObjectHook1(nint lightObject, int unknownInt) { Assert(unknownInt == 1); cleanupCommon(lightObject); return lightObjectDestructorHooks[1]!.Original(lightObject, unknownInt); } private nint DestroyLightObjectHook2(nint lightObject, int unknownInt) { Assert(unknownInt == 1); cleanupCommon(lightObject); return lightObjectDestructorHooks[2]!.Original(lightObject, unknownInt); } private nint DestroyLightObjectHook3(nint lightObject, int unknownInt) { Assert(unknownInt == 1); cleanupCommon(lightObject); return lightObjectDestructorHooks[3]!.Original(lightObject, unknownInt); } private nint DestroyLightObjectHook4(nint lightObject, int unknownInt) { Assert(unknownInt == 1); cleanupCommon(lightObject); return lightObjectDestructorHooks[4]!.Original(lightObject, unknownInt); } private nint DestroyLightObjectHook5(nint lightObject, int unknownInt) { Assert(unknownInt == 1); cleanupCommon(lightObject); return lightObjectDestructorHooks[5]!.Original(lightObject, unknownInt); } private nint DestroyLightObjectHook6(nint lightObject, int unknownInt) { Assert(unknownInt == 1); cleanupCommon(lightObject); return lightObjectDestructorHooks[6]!.Original(lightObject, unknownInt); } private nint DestroyLightObjectHook7(nint lightObject, int unknownInt) { Assert(unknownInt == 1); cleanupCommon(lightObject); return lightObjectDestructorHooks[7]!.Original(lightObject, unknownInt); } private nint DestroyLightObjectHook8(nint lightObject, int unknownInt) { Assert(unknownInt == 1); cleanupCommon(lightObject); return lightObjectDestructorHooks[8]!.Original(lightObject, unknownInt); } private nint DestroyLightObjectHook9(nint lightObject, int unknownInt) { Assert(unknownInt == 1); cleanupCommon(lightObject); return lightObjectDestructorHooks[9]!.Original(lightObject, unknownInt); } private nint DestroyLightObjectHook10(nint lightObject, int unknownInt) { Assert(unknownInt == 1); cleanupCommon(lightObject); return lightObjectDestructorHooks[10]!.Original(lightObject, unknownInt); } private nint DestroyLightObjectHook11(nint lightObject, int unknownInt) { Assert(unknownInt == 1); cleanupCommon(lightObject); return lightObjectDestructorHooks[11]!.Original(lightObject, unknownInt); } private nint DestroyLightObjectHook12(nint lightObject, int unknownInt) { Assert(unknownInt == 1); cleanupCommon(lightObject); return lightObjectDestructorHooks[12]!.Original(lightObject, unknownInt); } private nint DestroyLightObjectHook13(nint lightObject, int unknownInt) { Assert(unknownInt == 1); cleanupCommon(lightObject); return lightObjectDestructorHooks[13]!.Original(lightObject, unknownInt); } private nint DestroyLightObjectHook14(nint lightObject, int unknownInt) { Assert(unknownInt == 1); cleanupCommon(lightObject); return lightObjectDestructorHooks[14]!.Original(lightObject, unknownInt); } private nint DestroyLightObjectHook15(nint lightObject, int unknownInt) { Assert(unknownInt == 1); cleanupCommon(lightObject); return lightObjectDestructorHooks[15]!.Original(lightObject, unknownInt); } private nint DestroyLightObjectHook16(nint lightObject, int unknownInt) { Assert(unknownInt == 1); cleanupCommon(lightObject); return lightObjectDestructorHooks[16]!.Original(lightObject, unknownInt); } private nint DestroyLightObjectHook17(nint lightObject, int unknownInt) { Assert(unknownInt == 1); cleanupCommon(lightObject); return lightObjectDestructorHooks[17]!.Original(lightObject, unknownInt); } private nint DestroyLightObjectHook18(nint lightObject, int unknownInt) { Assert(unknownInt == 1); cleanupCommon(lightObject); return lightObjectDestructorHooks[18]!.Original(lightObject, unknownInt); } private nint DestroyLightObjectHook19(nint lightObject, int unknownInt) { Assert(unknownInt == 1); cleanupCommon(lightObject); return lightObjectDestructorHooks[19]!.Original(lightObject, unknownInt); } private nint DestroyLightObjectHook20(nint lightObject, int unknownInt) { Assert(unknownInt == 1); cleanupCommon(lightObject); return lightObjectDestructorHooks[20]!.Original(lightObject, unknownInt); } private nint DestroyLightObjectHook21(nint lightObject, int unknownInt) { Assert(unknownInt == 1); cleanupCommon(lightObject); return lightObjectDestructorHooks[21]!.Original(lightObject, unknownInt); } private nint DestroyLightObjectHook22(nint lightObject, int unknownInt) { Assert(unknownInt == 1); cleanupCommon(lightObject); return lightObjectDestructorHooks[22]!.Original(lightObject, unknownInt); } private nint DestroyLightObjectHook23(nint lightObject, int unknownInt) { Assert(unknownInt == 1); cleanupCommon(lightObject); return lightObjectDestructorHooks[23]!.Original(lightObject, unknownInt); } private nint DestroyLightObjectHook24(nint lightObject, int unknownInt) { Assert(unknownInt == 1); cleanupCommon(lightObject); return lightObjectDestructorHooks[24]!.Original(lightObject, unknownInt); } private nint DestroyLightObjectHook25(nint lightObject, int unknownInt) { Assert(unknownInt == 1); cleanupCommon(lightObject); return lightObjectDestructorHooks[25]!.Original(lightObject, unknownInt); } private void DrawLights(IEnumerable lights, float width) { bool disableAll = ImGui.Button("Disable All"); if (ImGui.BeginItemTooltip()) { ImGui.Text("Set \"Group\" to 0, \"Intensity\" to 0.0 and Disable \"Shadow Cast\" and \"Do Volumetric\"."); ImGui.EndTooltip(); } ImGui.SameLine(); bool enableAll = ImGui.Button("Enable All"); foreach (uLight light in lights) { ImGui.PushID(light.Object); if (disableAll) { light.Parameters[0].ForceOverrideOn(); light.Parameters[0].SetOverrideValue(default, 0); light.Parameters[3].ForceOverrideOn(); light.Parameters[3].SetOverrideValue(new Vector4(0.0f, 0.0f, 0.0f, 0.0f), 0); light.Parameters[7].ForceOverrideOn(); light.Parameters[7].SetOverrideValue(default, 0); light.Parameters[16].ForceOverrideOn(); light.Parameters[16].SetOverrideValue(default, 0); if (light is uLlkPointLight) { light.Parameters[21].ForceOverrideOn(); light.Parameters[21].SetOverrideValue(new Vector4(0.0f, 0.0f, 0.0f, 0.0f), 0); } if (light is uLlkSpotLight) { light.Parameters[32].ForceOverrideOn(); light.Parameters[32].SetOverrideValue(new Vector4(0.0f, 0.0f, 0.0f, 0.0f), 0); } if (light is uHemiSphereLight) { light.Parameters[18].ForceOverrideOn(); light.Parameters[18].SetOverrideValue(new Vector4(0.0f, 0.0f, 0.0f, 0.0f), 0); } if (light is uLlkHemiSphereLight) { light.Parameters[21].ForceOverrideOn(); light.Parameters[21].SetOverrideValue(new Vector4(0.0f, 0.0f, 0.0f, 0.0f), 0); light.Parameters[23].ForceOverrideOn(); light.Parameters[23].SetOverrideValue(new Vector4(0.0f, 0.0f, 0.0f, 0.0f), 0); } } if (enableAll) { light.Parameters[0].ForceOverrideOff(); light.Parameters[3].ForceOverrideOff(); light.Parameters[7].ForceOverrideOff(); light.Parameters[16].ForceOverrideOff(); if (light is uLlkPointLight) { light.Parameters[21].ForceOverrideOff(); } if (light is uLlkSpotLight) { light.Parameters[32].ForceOverrideOff(); } if (light is uHemiSphereLight) { light.Parameters[18].ForceOverrideOff(); } if (light is uLlkHemiSphereLight) { light.Parameters[21].ForceOverrideOff(); light.Parameters[23].ForceOverrideOff(); } } if (ImGui.CollapsingHeader(($"{light.Name} ({light.Info})"))) { foreach (Parameter param in light.Parameters) { param.Draw(width); } } ImGui.PopID(); } } public unsafe void DrawUI(float width) { int lightType = -1; nint lightObject = 0x0; if (ImGui.Button("New Point Light")) { lightType = 2; lightObject = new NativeFunction(0x141FC0780).Invoke(); } ImGui.SameLine(); if (ImGui.Button("New Spot Light")) { lightType = 3; lightObject = new NativeFunction(0x141FDDF00).Invoke(); } ImGui.SameLine(); if (ImGui.Button("New Hemi Sphere Light")) { lightType = 4; lightObject = new NativeFunction(0x141FB8A50).Invoke(); } bool lightTook = false; lock (newLights) { for (int i = newLights.Count - 1; i >= 0; i--) { uLight light = newLights[i]; if (light.Object == lightObject) { newLights.RemoveAt(i); lightTook = true; break; } } } if (lightTook && lightObject != 0x0) { Vector3 pos = default; Player? player = Player.MainPlayer; if (player != null) { pos = player.Position; pos.Y += 30.0f; } if (lightType == 2) { ourLights.Add(new uMhPointLight(lightObject, pos)); } else if (lightType == 3) { ourLights.Add(new uMhSpotLight(lightObject, pos)); } else if (lightType == 4) { ourLights.Add(new uMhHemiSphereLight(lightObject, pos)); } // mov byte ptr[rsp+20],00 unaccounted for, hopefully it never matters. addToScene.Invoke(MemoryUtil.Read(0x1451238C8), 0x16, lightObject, 0x0); } ImGui.PushID("Ours"); for (int i = 0; i < ourLights.Count; i++) { uLight light = ourLights[i]; ImGui.PushID(i); if (ImGui.Button("X")) { removeFromScene.Invoke(light.Object); // removeFromScene triggers destructor. } ImGui.SameLine(); if (ImGui.CollapsingHeader(($"{light.Name} (0x{light.Object:X})"))) { foreach (Parameter param in light.Parameters) { param.Draw(width, true); } } ImGui.PopID(); } ImGui.PopID(); ImGui.Separator(); ImGui.PushID("Scene"); ImGuiTreeNodeFlags flags = ImGuiTreeNodeFlags.Framed; if (ImGui.TreeNodeEx("Scene Lights", flags)) { ImGui.PushID("Infinite"); if (ImGui.CollapsingHeader("Infinite")) { DrawLights(sceneLights.Where(x => (x.Type == 1)), width); ImGui.Separator(); } ImGui.PopID(); ImGui.PushID("Point"); if (ImGui.CollapsingHeader("Point")) { ImGui.Checkbox("Sort By Distance To Player", ref sortByDistanceToPlayerPoint); ImGui.SameLine(); if (sortByDistanceToPlayerPoint) { Vector3 pos = default; Player? player = Player.MainPlayer; if (player != null) pos = player.Position; DrawLights(Enumerable.OrderBy(sceneLights.Where(x => (x.Type == 2)), x => x, Comparer.Create((x, y) => { Vector3 xPos = ((uPointLight)x).Position; if (((uPointLight)x).Parent != 0x0) { xPos += MemoryUtil.GetRef(((uPointLight)x).Parent + 0x160); } Vector3 yPos = ((uPointLight)y).Position; if (((uPointLight)y).Parent != 0x0) { yPos += MemoryUtil.GetRef(((uPointLight)y).Parent + 0x160); } float distX = Vector3.Distance(pos, xPos); float distY = Vector3.Distance(pos, yPos); if (distX < distY) return -1; else if (distX > distY) return 1; return 0; })), width); } else { DrawLights(sceneLights.Where(x => (x.Type == 2)), width); } ImGui.Separator(); } ImGui.PopID(); ImGui.PushID("Spot"); if (ImGui.CollapsingHeader("Spot")) { ImGui.Checkbox("Sort By Distance To Player", ref sortByDistanceToPlayerSpot); ImGui.SameLine(); if (sortByDistanceToPlayerSpot) { Vector3 pos = default; Player? player = Player.MainPlayer; if (player != null) pos = player.Position; DrawLights(Enumerable.OrderBy(sceneLights.Where(x => (x.Type == 3)), x => x, Comparer.Create((x, y) => { Vector3 xPos = ((uSpotLight)x).Position; if (((uSpotLight)x).Parent != 0x0) { xPos += MemoryUtil.GetRef(((uSpotLight)x).Parent + 0x160); } Vector3 yPos = ((uSpotLight)y).Position; if (((uSpotLight)y).Parent != 0x0) { yPos += MemoryUtil.GetRef(((uSpotLight)y).Parent + 0x160); } float distX = Vector3.Distance(pos, xPos); float distY = Vector3.Distance(pos, yPos); if (distX < distY) return -1; else if (distX > distY) return 1; return 0; })), width); } else { DrawLights(sceneLights.Where(x => (x.Type == 3)), width); } ImGui.Separator(); } ImGui.PopID(); ImGui.PushID("HemiSphere"); if (ImGui.CollapsingHeader("Hemi Sphere")) { DrawLights(sceneLights.Where(x => (x.Type == 4)), width); ImGui.Separator(); } ImGui.PopID(); ImGui.PushID("Other"); if (ImGui.CollapsingHeader("Other")) { DrawLights(sceneLights.Where(x => (x.Type == -1 || x.Type == 5)), width); } ImGui.PopID(); ImGui.TreePop(); } ImGui.PopID(); } } }