//#define HOOK_OBJECT_LIGHTS 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 BaseLight { public nint Object = 0x0; public virtual int Type => -1; public virtual string Name => $"Light"; public virtual string Info => $"0x{Object:X}"; public List Parameters = new List(); public BaseLight(nint lightObject) { Object = lightObject; } public void UpdateParams() { Assert(Object != 0x0); foreach (Parameter param in Parameters) { param.Update(Object); } } } private class uLight : BaseLight { public override string Name => $"uLight"; public uLight(nint lightObject) : base(lightObject) { Parameters.AddRange(new Parameter[]{ M("Group", 0x13C, ParameterType.BITS, 0x7), // 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 != 0x0 ? $", 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(); } } #if HOOK_OBJECT_LIGHTS private class uMhObjectLight : BaseLight { public override int Type => 5; public override string Name => $"uMhObjectLight"; public uMhObjectLight(nint lightObject) : base(lightObject) { Parameters.AddRange(new Parameter[]{ P("Position", 0x160, ParameterType.VECTOR3), P("Shape", 0x590, ParameterType.INT, pStep(1)), P("Color", 0x5A0, ParameterType.COLOR), P("Intensity", 0x5A4, ParameterType.FLOAT), }); UpdateParams(); } } private class uLlkObjectLight : BaseLight { public override int Type => 5; public override string Name => $"uLlkObjectLight"; public uLlkObjectLight(nint lightObject) : base(lightObject) { Parameters.AddRange(new Parameter[]{ P("Position", 0x160, ParameterType.VECTOR3) }); UpdateParams(); } } private delegate nint CreateMhObjectLight(); private delegate nint CreateMhObjectLight2(nint unknownPtr); private delegate nint DestroyMhObjectLight(nint mhObjectLightInternal, int unknownInt); private Hook? createMhObjectLight; private Hook? createMhObjectLight2; private Hook? destroyMhObjectLight; private delegate nint CreateLlkObjectLight(); private delegate nint CreateLlkObjectLight2(nint unknownPtr); private delegate nint DestroyLlkObjectLight(nint llkObjectLightInternal, int unknownInt); private Hook? createLlkObjectLight; private Hook? createLlkObjectLight2; private Hook? destroyLlkObjectLight; #endif 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) } }; 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 }; 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(); #if HOOK_OBJECT_LIGHTS private List objectLights = new List(); #endif 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 }; for (int i = 0; i < lightObjectDestructors.Length; i++) { lightObjectDestructorHooks[i] = Hook.Create(lightObjectDestructors[i], destructorHookFuncs[i]); } #if HOOK_OBJECT_LIGHTS createMhObjectLight = Hook.Create(0x141FBF290, CreateMhObjectLightHook); createMhObjectLight2 = Hook.Create(0x141FBF500, CreateMhObjectLight2Hook); destroyMhObjectLight = Hook.Create(0x141FBF6B0, DestroyMhObjectLightHook); createLlkObjectLight = Hook.Create(0x141F85DF0, CreateLlkObjectLightHook); createLlkObjectLight2 = Hook.Create(0x141F86090, CreateLlkObjectLight2Hook); destroyLlkObjectLight = Hook.Create(0x141F86270, DestroyLlkObjectLightHook); #endif 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); } #if HOOK_OBJECT_LIGHTS private nint CreateMhObjectLightHook() { nint objectLight = createMhObjectLight!.Original(); objectLights.Add(new uMhObjectLight(objectLight)); return objectLight; } private nint CreateMhObjectLight2Hook(nint unknownPtr) { nint objectLight = createMhObjectLight2!.Original(unknownPtr); objectLights.Add(new uMhObjectLight(objectLight)); return objectLight; } private nint DestroyMhObjectLightHook(nint mhObjectLightInternal, int unknownInt) { Assert(unknownInt == 1); for (int i = 0; i < objectLights.Count; i++) { BaseLight light = objectLights[i]; if (mhObjectLightInternal == light.Object) { objectLights.RemoveAt(i); break; } } return destroyMhObjectLight!.Original(mhObjectLightInternal, unknownInt); } private nint CreateLlkObjectLightHook() { nint objectLight = createLlkObjectLight!.Original(); objectLights.Add(new uLlkObjectLight(objectLight)); return objectLight; } private nint CreateLlkObjectLight2Hook(nint unknownPtr) { nint objectLight = createLlkObjectLight2!.Original(unknownPtr); objectLights.Add(new uLlkObjectLight(objectLight)); return objectLight; } private nint DestroyLlkObjectLightHook(nint llkObjectLightInternal, int unknownInt) { Assert(unknownInt == 1); for (int i = 0; i < objectLights.Count; i++) { BaseLight light = objectLights[i]; if (llkObjectLightInternal == light.Object) { objectLights.RemoveAt(i); break; } } return destroyLlkObjectLight!.Original(llkObjectLightInternal, unknownInt); } #endif 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 (BaseLight 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(); #if HOOK_OBJECT_LIGHTS ImGui.PushID("ObjectLights"); if (ImGui.CollapsingHeader("Object Lights")) { DrawLights(objectLights, width); } ImGui.PopID(); #endif ImGui.TreePop(); } ImGui.PopID(); } } }