diff --git a/Barotrauma/BarotraumaShared/Lua/DefaultHook.lua b/Barotrauma/BarotraumaShared/Lua/DefaultHook.lua new file mode 100644 index 000000000..7cdac4356 --- /dev/null +++ b/Barotrauma/BarotraumaShared/Lua/DefaultHook.lua @@ -0,0 +1,24 @@ + +Hook.HookMethod("Barotrauma.Item", "TryInteract", function (instance, p) + Hook.Call("itemInteract", instance, p.picker, p.ignoreRequiredItems, p.forceSelectKey, p.forceActionKey) +end, Hook.HookMethodType.Before) + +Hook.HookMethod("Barotrauma.Item", "ApplyTreatment", function (instance, p) + Hook.Call("itemApplyTreatment", instance, p.user, p.character, p.targetLimb) +end, Hook.HookMethodType.Before) + +Hook.HookMethod("Barotrauma.Item", "Combine", function (instance, p) + Hook.Call("itemCombine", instance, p.item, p.user) +end, Hook.HookMethodType.Before) + +Hook.HookMethod("Barotrauma.Item", "Drop", function (instance, p) + Hook.Call("itemDrop", instance, p.dropper) +end, Hook.HookMethodType.Before) + +Hook.HookMethod("Barotrauma.Item", "Equip", function (instance, p) + Hook.Call("itemEquip", instance, p.character) +end, Hook.HookMethodType.Before) + +Hook.HookMethod("Barotrauma.Item", "Unequip", function (instance, p) + Hook.Call("itemUnequip", instance, p.character) +end, Hook.HookMethodType.Before) \ No newline at end of file diff --git a/Barotrauma/BarotraumaShared/Lua/DefaultLib.lua b/Barotrauma/BarotraumaShared/Lua/DefaultLib.lua index 9f74e2163..19a764ffe 100644 --- a/Barotrauma/BarotraumaShared/Lua/DefaultLib.lua +++ b/Barotrauma/BarotraumaShared/Lua/DefaultLib.lua @@ -49,7 +49,7 @@ if SERVER then elseif CLIENT then defaultLib["Sprite"] = CreateStatic("Sprite") - defaultLib["Keys"] = LuaUserData.RegisterType("Microsoft.Xna.Framework.Input.Keys") + defaultLib["Keys"] = LuaUserData.CreateStatic("Microsoft.Xna.Framework.Input.Keys") defaultLib["PlayerInput"] = CreateStatic("PlayerInput") end diff --git a/Barotrauma/BarotraumaShared/Lua/LuaSetup.lua b/Barotrauma/BarotraumaShared/Lua/LuaSetup.lua index cd058681c..b9640b786 100644 --- a/Barotrauma/BarotraumaShared/Lua/LuaSetup.lua +++ b/Barotrauma/BarotraumaShared/Lua/LuaSetup.lua @@ -11,6 +11,8 @@ for key, value in pairs(defaultLib) do _G[key] = value end +require("DefaultHook") + -- Execute Mods if SERVER and Game.IsDedicated then diff --git a/Barotrauma/BarotraumaShared/SharedSource/Items/Item.cs b/Barotrauma/BarotraumaShared/SharedSource/Items/Item.cs index 8ddd1506a..04a2b68b9 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Items/Item.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Items/Item.cs @@ -2166,11 +2166,6 @@ namespace Barotrauma public bool TryInteract(Character picker, bool ignoreRequiredItems = false, bool forceSelectKey = false, bool forceActionKey = false) { - var should = new LuaResult(GameMain.Lua.hook.Call("itemInteract", new object[] { this, picker, ignoreRequiredItems, forceSelectKey, forceActionKey })); - - if (!should.IsNull()) - return should.Bool(); - if (CampaignInteractionType != CampaignMode.InteractionType.None) { return false; } bool picked = false, selected = false; @@ -2352,7 +2347,6 @@ namespace Barotrauma if (should.Bool()) return; - bool remove = false; foreach (ItemComponent ic in components) @@ -2384,11 +2378,6 @@ namespace Barotrauma public void ApplyTreatment(Character user, Character character, Limb targetLimb) { - var should = new LuaResult(GameMain.Lua.hook.Call("itemApplyTreatment", new object[] { this, user, character, targetLimb })); - - if (should.Bool()) - return; - //can't apply treatment to dead characters if (character.IsDead) { return; } if (!UseInHealthInterface) { return; } @@ -2454,11 +2443,6 @@ namespace Barotrauma public bool Combine(Item item, Character user) { - var should = new LuaResult(GameMain.Lua.hook.Call("itemCombine", new object[] { this, item, user })); - - if (!should.IsNull()) - return should.Bool(); - if (item == this) { return false; } bool isCombined = false; foreach (ItemComponent ic in components) @@ -2473,11 +2457,6 @@ namespace Barotrauma public void Drop(Character dropper, bool createNetworkEvent = true) { - var should = new LuaResult(GameMain.Lua.hook.Call("itemDrop", new object[] { this, dropper})); - - if (should.Bool()) - return; - if (createNetworkEvent) { if (parentInventory != null && !parentInventory.Owner.Removed && !Removed && @@ -2530,11 +2509,6 @@ namespace Barotrauma public void Equip(Character character) { - var should = new LuaResult(GameMain.Lua.hook.Call("itemEquip", new object[] { this, character})); - - if (should.Bool()) - return; - if (Removed) { DebugConsole.ThrowError($"Tried to equip a removed item ({Name}).\n{Environment.StackTrace.CleanupStackTrace()}"); @@ -2546,11 +2520,6 @@ namespace Barotrauma public void Unequip(Character character) { - var should = new LuaResult(GameMain.Lua.hook.Call("itemUnequip", new object[] { this, character })); - - if (should.Bool()) - return; - foreach (ItemComponent ic in components) { ic.Unequip(character); } } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Lua/LuaClasses.cs b/Barotrauma/BarotraumaShared/SharedSource/Lua/LuaClasses.cs index e836f1827..698967aec 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Lua/LuaClasses.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Lua/LuaClasses.cs @@ -62,12 +62,12 @@ namespace Barotrauma descriptor.AddMetaMember("__call", new ObjectCallbackMemberDescriptor("__call", LuaSetup.luaSetup.HandleCall)); } - public static void MakeFieldAccessible(IUserDataDescriptor IUUD, string methodName) + public static void MakeFieldAccessible(IUserDataDescriptor IUUD, string fieldName) { var descriptor = (StandardUserDataDescriptor)IUUD; - var field = IUUD.Type.GetField(methodName, BindingFlags.NonPublic | BindingFlags.Instance); - descriptor.RemoveMember(methodName); - descriptor.AddMember(methodName, new FieldMemberDescriptor(field, InteropAccessMode.Default)); + var field = IUUD.Type.GetField(fieldName, BindingFlags.NonPublic | BindingFlags.Instance); + descriptor.RemoveMember(fieldName); + descriptor.AddMember(fieldName, new FieldMemberDescriptor(field, InteropAccessMode.Default)); } public static void MakeMethodAccessible(IUserDataDescriptor IUUD, string methodName) @@ -692,7 +692,7 @@ namespace Barotrauma public LuaHook(LuaSetup e) { env = e; - methodNameToHookName = new Dictionary(); + _hookMethods = new Dictionary(); } public class HookFunction @@ -711,7 +711,7 @@ namespace Barotrauma private Dictionary> hookFunctions = new Dictionary>(); - private static Dictionary methodNameToHookName; + private static Dictionary _hookMethods; private Queue> queuedFunctionCalls = new Queue>(); @@ -720,47 +720,50 @@ namespace Barotrauma Before, After } + static void _hookLuaPatch(MethodBase __originalMethod, object[] __params, object __instance, out LuaResult result, HookMethodType hookMethodType) + { + // Although it works correctly, the performance is low + result = new LuaResult(null); + + try + { + var classType = __originalMethod.DeclaringType; + var methodPath = $"{hookMethodType}:{classType.Namespace}.{classType.Name}.{__originalMethod.Name}"; + + var @params = __originalMethod.GetParameters(); + var ptable = new Dictionary(); + for (int i = 0; i < @params.Length; i++) + { + ptable.Add(@params[i].Name, __params[i]); + + } + + if (_hookMethods.TryGetValue(methodPath, out object hookMethod)) + { + result = new LuaResult(luaSetup.hook.env.lua.Call(hookMethod, __instance, ptable)); + } + else + { + DebugConsole.ThrowError($"No hook method found in _hookMethods[{methodPath}]"); + } + + } + catch (Exception ex) + { + DebugConsole.ThrowError(nameof(_hookLuaPatch), ex); + } + } + static bool HookLuaPatchPrefix(MethodBase __originalMethod, object[] __params, object __instance) { - object[] parameters; - - if (__instance == null) - { - parameters = __params; - } - else - { - parameters = new object[__params.Length + 1]; - __params.CopyTo(parameters, 1); - parameters[0] = __instance; - } - - var result = new LuaResult(luaSetup.hook.Call(methodNameToHookName[__originalMethod.Name], parameters)); - - if (!result.IsNull()) - { - return false; - } - - return true; + _hookLuaPatch(__originalMethod, __params, __instance, out LuaResult result, HookMethodType.Before); + + return result.IsNull(); } static bool HookLuaPatchRetPrefix(MethodBase __originalMethod, object[] __params, ref object __result, object __instance) { - object[] parameters; - - if (__instance == null) - { - parameters = __params; - } - else - { - parameters = new object[__params.Length + 1]; - __params.CopyTo(parameters, 1); - parameters[0] = __instance; - } - - var result = new LuaResult(luaSetup.hook.Call(methodNameToHookName[__originalMethod.Name], parameters)); + _hookLuaPatch(__originalMethod, __params, __instance, out LuaResult result, HookMethodType.Before); if (!result.IsNull()) { @@ -773,34 +776,22 @@ namespace Barotrauma static void HookLuaPatchPostfix(MethodBase __originalMethod, object[] __params, object __instance) { - if (__instance == null) - luaSetup.hook.Call(methodNameToHookName[__originalMethod.Name], __params); - else - luaSetup.hook.Call(methodNameToHookName[__originalMethod.Name], __instance, __params); + _hookLuaPatch(__originalMethod, __params, __instance, out LuaResult result, HookMethodType.After); } static void HookLuaPatchRetPostfix(MethodBase __originalMethod, object[] __params, ref object __result, object __instance) { - object[] parameters; - - if (__instance == null) - { - parameters = __params; - } - else - { - parameters = new object[__params.Length + 1]; - __params.CopyTo(parameters, 1); - parameters[0] = __instance; - } - - var result = new LuaResult(luaSetup.hook.Call(methodNameToHookName[__originalMethod.Name], parameters)); + _hookLuaPatch(__originalMethod, __params, __instance, out LuaResult result, HookMethodType.After); if (!result.IsNull()) __result = result.Object(); } - public void HookMethod(string className, string methodName, string hookName, HookMethodType hookMethodType = HookMethodType.Before) + private static MethodInfo _miHookLuaPatchPrefix = typeof(LuaHook).GetMethod("HookLuaPatchPrefix", BindingFlags.NonPublic | BindingFlags.Static); + private static MethodInfo _miHookLuaPatchRetPrefix = typeof(LuaHook).GetMethod("HookLuaPatchRetPrefix", BindingFlags.NonPublic | BindingFlags.Static); + private static MethodInfo _miHookLuaPatchPostfix = typeof(LuaHook).GetMethod("HookLuaPatchPostfix", BindingFlags.NonPublic | BindingFlags.Static); + private static MethodInfo _miHookLuaPatchRetPostfix = typeof(LuaHook).GetMethod("HookLuaPatchRetPostfix", BindingFlags.NonPublic | BindingFlags.Static); + public void HookMethod(string className, string methodName, object hookMethod, HookMethodType hookMethodType = HookMethodType.Before) { var classType = Type.GetType(className); var methodInfos = classType.GetMethods(); @@ -809,42 +800,50 @@ namespace Barotrauma if (hookMethodType == HookMethodType.Before) { - harmonyMethod = new HarmonyMethod(GetType().GetMethod("HookLuaPatchPrefix", BindingFlags.NonPublic | BindingFlags.Static)); - - harmonyMethodRet = new HarmonyMethod(GetType().GetMethod("HookLuaPatchRetPrefix", BindingFlags.NonPublic | BindingFlags.Static)); + harmonyMethod = new HarmonyMethod(_miHookLuaPatchPrefix); + harmonyMethodRet = new HarmonyMethod(_miHookLuaPatchRetPrefix); } else if (hookMethodType == HookMethodType.After) { - harmonyMethod = new HarmonyMethod(GetType().GetMethod("HookLuaPatchPostfix", BindingFlags.NonPublic | BindingFlags.Static)); - - harmonyMethodRet = new HarmonyMethod(GetType().GetMethod("HookLuaPatchRetPrefix", BindingFlags.NonPublic | BindingFlags.Static)); + harmonyMethod = new HarmonyMethod(_miHookLuaPatchPostfix); + harmonyMethodRet = new HarmonyMethod(_miHookLuaPatchRetPostfix); } - var foundAny = false; - foreach (var methodInfo in methodInfos) { - if(methodInfo.Name == methodName) + if (methodInfo.Name == methodName) { if (hookMethodType == HookMethodType.Before) + { if (methodInfo.ReturnType == typeof(void)) - env.harmony.Patch(methodInfo, harmonyMethod); + env.harmony.Patch(methodInfo, prefix: harmonyMethod); else - env.harmony.Patch(methodInfo, harmonyMethodRet); - - + env.harmony.Patch(methodInfo, prefix: harmonyMethodRet); + } else if (hookMethodType == HookMethodType.After) + { if (methodInfo.ReturnType == typeof(void)) env.harmony.Patch(methodInfo, postfix: harmonyMethod); else env.harmony.Patch(methodInfo, postfix: harmonyMethodRet); + } - foundAny = true; + // build an unique method path by patch type, class, method self + var methodPath = $"{hookMethodType}:{classType.Namespace}.{classType.Name}.{methodInfo.Name}"; + + if (hookMethod != null) + { + if (!_hookMethods.TryAdd(methodPath, hookMethod)) + DebugConsole.ThrowError($"Failed to add key-value in {nameof(_hookMethods)}\n[{methodPath}, {hookMethod.ToString()}]"); +#if DEBUG + else + DebugConsole.NewMessage($"Sucessfully added key-value in {nameof(_hookMethods)}\n[{methodPath}, {hookMethod.ToString()}]", Color.LightSkyBlue); +#endif + } + break; } } - if(foundAny) - methodNameToHookName.Add(methodName, hookName); } public void EnqueueFunction(object function, params object[] args) diff --git a/Barotrauma/BarotraumaShared/SharedSource/Lua/LuaSetup.cs b/Barotrauma/BarotraumaShared/SharedSource/Lua/LuaSetup.cs index feb05ffea..b10afe263 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Lua/LuaSetup.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Lua/LuaSetup.cs @@ -324,7 +324,6 @@ namespace Barotrauma UserData.RegisterType(); UserData.RegisterType(); UserData.RegisterType(); - UserData.RegisterType(); UserData.RegisterType();