do a hook call inside callback param of HookMethod, and wrapped __params

This commit is contained in:
zhurengong
2021-11-11 17:19:06 +08:00
parent 9635db22fc
commit d1188a1ea5
4 changed files with 86 additions and 65 deletions

View File

@@ -1,10 +1,24 @@
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
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)

View File

@@ -2304,6 +2304,11 @@ 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)
@@ -2337,6 +2342,11 @@ 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)

View File

@@ -692,8 +692,7 @@ namespace Barotrauma
public LuaHook(LuaSetup e)
{
env = e;
_methodPathToHookName = new Dictionary<string, string>();
_luaPatchParamsMap = new Dictionary<string, object>();
_hookMethods = new Dictionary<string, object>();
}
public class HookFunction
@@ -712,8 +711,7 @@ namespace Barotrauma
private Dictionary<string, Dictionary<string, HookFunction>> hookFunctions = new Dictionary<string, Dictionary<string, HookFunction>>();
private static Dictionary<string, string> _methodPathToHookName;
private static Dictionary<string, object> _luaPatchParamsMap;
private static Dictionary<string, object> _hookMethods;
private Queue<Tuple<object, object[]>> queuedFunctionCalls = new Queue<Tuple<object, object[]>>();
@@ -722,48 +720,50 @@ namespace Barotrauma
Before, After
}
static void _hookLuaPatchPreProcess(MethodBase __originalMethod, object[] __params, object __instance, out string hookName, out object[] parameters)
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 @class = __originalMethod.DeclaringType;
var methodPath = $"{@class.Namespace}.{@class.Name}.{__originalMethod.Name}";
var classType = __originalMethod.DeclaringType;
var methodPath = $"{hookMethodType}:{classType.Namespace}.{classType.Name}.{__originalMethod.Name}";
hookName = _methodPathToHookName[methodPath];
var @params = __originalMethod.GetParameters();
var ptable = new Dictionary<string, object>();
for (int i = 0; i < @params.Length; i++)
{
ptable.Add(@params[i].Name, __params[i]);
// 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))
}
if (_hookMethods.TryGetValue(methodPath, out object hookMethod))
{
var result = luaSetup.hook.env.lua.Call(map, parameters);
if (!result.IsNil()) parameters = result.ToObject<object[]>();
result = new LuaResult(luaSetup.hook.env.lua.Call(hookMethod, __instance, ptable));
}
else
{
DebugConsole.ThrowError($"No hook method found in _hookMethods[{methodPath}]");
}
}
catch (Exception ex)
{
parameters = null;
hookName = null;
DebugConsole.ThrowError(nameof(_hookLuaPatchPreProcess), ex);
DebugConsole.ThrowError(nameof(_hookLuaPatch), ex);
}
}
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));
_hookLuaPatch(__originalMethod, __params, __instance, out LuaResult result, HookMethodType.Before);
return result.IsNull();
}
static bool HookLuaPatchRetPrefix(MethodBase __originalMethod, object[] __params, ref object __result, object __instance)
{
_hookLuaPatchPreProcess(__originalMethod, __params, __instance, out string hookName, out object[] parameters);
var result = new LuaResult(luaSetup.hook.Call(hookName, parameters));
_hookLuaPatch(__originalMethod, __params, __instance, out LuaResult result, HookMethodType.Before);
if (!result.IsNull())
{
@@ -776,71 +776,69 @@ namespace Barotrauma
static void HookLuaPatchPostfix(MethodBase __originalMethod, object[] __params, object __instance)
{
_hookLuaPatchPreProcess(__originalMethod, __params, __instance, out string hookName, out object[] parameters);
luaSetup.hook.Call(hookName, parameters);
_hookLuaPatch(__originalMethod, __params, __instance, out LuaResult result, HookMethodType.After);
}
static void HookLuaPatchRetPostfix(MethodBase __originalMethod, object[] __params, ref object __result, object __instance)
{
_hookLuaPatchPreProcess(__originalMethod, __params, __instance, out string hookName, out object[] parameters);
var result = new LuaResult(luaSetup.hook.Call(hookName, 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, object paramsMap, 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 @class = Type.GetType(className);
var methodInfos = @class.GetMethods();
var classType = Type.GetType(className);
var methodInfos = classType.GetMethods();
HarmonyMethod harmonyMethod = new HarmonyMethod();
HarmonyMethod harmonyMethodRet = new HarmonyMethod();
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);
}
foreach (var methodInfo in methodInfos)
{
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);
}
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)
// build an unique method path by patch type, class, method self
var methodPath = $"{hookMethodType}:{classType.Namespace}.{classType.Name}.{methodInfo.Name}";
if (hookMethod != 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()}]");
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;
}

View File

@@ -324,7 +324,6 @@ namespace Barotrauma
UserData.RegisterType<LuaFile>();
UserData.RegisterType<LuaNetworking>();
UserData.RegisterType<LuaUserData>();
UserData.RegisterType<LuaHook.HookMethodType>();
UserData.RegisterType<IUserDataDescriptor>();