From 6b1aca8efad6d4211db06a79b1f228be911ecb7b Mon Sep 17 00:00:00 2001 From: zhurengong <2731412072@qq.com> Date: Wed, 10 Nov 2021 21:07:19 +0800 Subject: [PATCH] modified way to patch, can realize params map for compatibility, and try to hook Item in lua. --- .../BarotraumaShared/Lua/DefaultHook.lua | 10 ++ .../BarotraumaShared/Lua/DefaultLib.lua | 2 +- Barotrauma/BarotraumaShared/Lua/LuaSetup.lua | 2 + .../SharedSource/Items/Item.cs | 41 ------ .../SharedSource/Lua/LuaClasses.cs | 117 +++++++++--------- 5 files changed, 72 insertions(+), 100 deletions(-) create mode 100644 Barotrauma/BarotraumaShared/Lua/DefaultHook.lua diff --git a/Barotrauma/BarotraumaShared/Lua/DefaultHook.lua b/Barotrauma/BarotraumaShared/Lua/DefaultHook.lua new file mode 100644 index 000000000..40bfc8b70 --- /dev/null +++ b/Barotrauma/BarotraumaShared/Lua/DefaultHook.lua @@ -0,0 +1,10 @@ + +Hook.HookMethod("Barotrauma.Item", "TryInteract", "itemInteract", nil) -- instance, picker, ignoreRequiredItems, forceSelectKey, forceActionKey +Hook.HookMethod("Barotrauma.Item", "Use", "itemUse", function (instance, deltaTime, character, targetLimb) return {instance, character, targetLimb} end) +Hook.HookMethod("Barotrauma.Item", "SecondaryUse", "itemSecondaryUse", function (instance, deltaTime, character) return {instance, character} end) +Hook.HookMethod("Barotrauma.Item", "ApplyTreatment", "itemApplyTreatment", nil) -- instance, user, character, targetLimb +Hook.HookMethod("Barotrauma.Item", "Combine", "itemCombine", nil) -- instance, item, user +Hook.HookMethod("Barotrauma.Item", "Drop", "itemDrop", function (instance, dropper, createNetworkEvent) return {instance, dropper} end) +Hook.HookMethod("Barotrauma.Item", "Equip", "itemEquip", nil) -- instance, character +Hook.HookMethod("Barotrauma.Item", "Unequip", "itemUnequip", nil) -- instance, character + 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..d1d17d44b 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; @@ -2309,11 +2304,6 @@ namespace Barotrauma if (condition == 0.0f) { return; } - var should = new LuaResult(GameMain.Lua.hook.Call("itemUse", new object[] { this, character, targetLimb })); - - if (should.Bool()) - return; - bool remove = false; foreach (ItemComponent ic in components) @@ -2347,12 +2337,6 @@ namespace Barotrauma { if (condition == 0.0f) { return; } - var should = new LuaResult(GameMain.Lua.hook.Call("itemSecondaryUse", new object[] { this, character})); - - if (should.Bool()) - return; - - bool remove = false; foreach (ItemComponent ic in components) @@ -2384,11 +2368,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 +2433,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 +2447,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 +2499,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 +2510,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 88c980a46..44148123f 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Lua/LuaClasses.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Lua/LuaClasses.cs @@ -77,12 +77,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) @@ -712,7 +712,8 @@ namespace Barotrauma public LuaHook(LuaSetup e) { env = e; - methodNameToHookName = new Dictionary(); + _methodPathToHookName = new Dictionary(); + _luaPatchParamsMap = new Dictionary(); } public class HookFunction @@ -731,7 +732,8 @@ namespace Barotrauma private Dictionary> hookFunctions = new Dictionary>(); - private static Dictionary methodNameToHookName; + private static Dictionary _methodPathToHookName; + private static Dictionary _luaPatchParamsMap; private Queue> queuedFunctionCalls = new Queue>(); @@ -740,47 +742,48 @@ namespace Barotrauma Before, After } - static bool HookLuaPatchPrefix(MethodBase __originalMethod, object[] __params, object __instance) + static void _hookLuaPatchPreProcess(MethodBase __originalMethod, object[] __params, object __instance, out string hookName, out object[] parameters) { - object[] parameters; + try + { + var @class = __originalMethod.DeclaringType; + var methodPath = $"{@class.Namespace}.{@class.Name}.{__originalMethod.Name}"; - if (__instance == null) - { - parameters = __params; - } - else - { + hookName = _methodPathToHookName[methodPath]; + + // Regardless of whether __instance is null or not, it's necessaray to avoid the inability to distinguish parameters when adding hooks in lua. parameters = new object[__params.Length + 1]; __params.CopyTo(parameters, 1); parameters[0] = __instance; + // Map the parameters for compatibility + if (_luaPatchParamsMap.TryGetValue(methodPath, out object map)) + { + var result = luaSetup.hook.env.lua.Call(map, parameters); + if (!result.IsNil()) parameters = result.ToObject(); + } + } - - var result = new LuaResult(luaSetup.hook.Call(methodNameToHookName[__originalMethod.Name], parameters)); - - if (!result.IsNull()) + catch (Exception ex) { - return false; + parameters = null; + hookName = null; + DebugConsole.ThrowError(nameof(_hookLuaPatchPreProcess), ex); } + } - return true; + static bool HookLuaPatchPrefix(MethodBase __originalMethod, object[] __params, object __instance) + { + _hookLuaPatchPreProcess(__originalMethod, __params, __instance, out string hookName, out object[] parameters); + + var result = new LuaResult(luaSetup.hook.Call(hookName, parameters)); + return result.IsNull(); } static bool HookLuaPatchRetPrefix(MethodBase __originalMethod, object[] __params, ref object __result, object __instance) { - object[] parameters; + _hookLuaPatchPreProcess(__originalMethod, __params, __instance, out string hookName, out 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)); + var result = new LuaResult(luaSetup.hook.Call(hookName, parameters)); if (!result.IsNull()) { @@ -793,37 +796,26 @@ 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); + _hookLuaPatchPreProcess(__originalMethod, __params, __instance, out string hookName, out object[] parameters); + luaSetup.hook.Call(hookName, parameters); } + + static void HookLuaPatchRetPostfix(MethodBase __originalMethod, object[] __params, ref object __result, object __instance) { - object[] parameters; + _hookLuaPatchPreProcess(__originalMethod, __params, __instance, out string hookName, out 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)); + var result = new LuaResult(luaSetup.hook.Call(hookName, parameters)); if (!result.IsNull()) __result = result.Object(); } - public void HookMethod(string className, string methodName, string hookName, HookMethodType hookMethodType = HookMethodType.Before) + public void HookMethod(string className, string methodName, string hookName, object paramsMap, HookMethodType hookMethodType = HookMethodType.Before) { - var classType = Type.GetType(className); - var methodInfos = classType.GetMethods(); + var @class = Type.GetType(className); + var methodInfos = @class.GetMethods(); HarmonyMethod harmonyMethod = new HarmonyMethod(); HarmonyMethod harmonyMethodRet = new HarmonyMethod(); @@ -840,11 +832,10 @@ namespace Barotrauma harmonyMethodRet = new HarmonyMethod(GetType().GetMethod("HookLuaPatchRetPrefix", BindingFlags.NonPublic | BindingFlags.Static)); } - 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)) @@ -859,12 +850,22 @@ namespace Barotrauma else env.harmony.Patch(methodInfo, postfix: harmonyMethodRet); - foundAny = true; + var methodPath = $"{@class.Namespace}.{@class.Name}.{methodInfo.Name}"; + if (_methodPathToHookName.TryAdd(methodPath, hookName)) + DebugConsole.NewMessage($"Sucessfully added key-value in {nameof(_methodPathToHookName)}\n[{methodPath}, {hookName}]", Color.LightSkyBlue); + else DebugConsole.ThrowError($"Failed to add key-value in {nameof(_methodPathToHookName)}\n[{methodPath}, {hookName}]"); + + if (paramsMap != null) + { + if (_luaPatchParamsMap.TryAdd(methodPath, paramsMap)) + DebugConsole.NewMessage($"Sucessfully added key-value in {nameof(_luaPatchParamsMap)}\n[{methodPath}, {paramsMap.ToString()}]", Color.LightSkyBlue); + else DebugConsole.ThrowError($"Failed to add key-value in {nameof(_luaPatchParamsMap)}\n[{methodPath}, {paramsMap.ToString()}]"); + + } + break; } } - if(foundAny) - methodNameToHookName.Add(methodName, hookName); } public void EnqueueFunction(object function, params object[] args)