ability to tag the patch, and can overwrite and remove the tagged patch.

This commit is contained in:
zhurengong
2022-03-22 18:09:18 +08:00
parent 9694895b71
commit a1ec0fc807
@@ -12,8 +12,8 @@ namespace Barotrauma
{ {
public LuaHook() public LuaHook()
{ {
_hookPrefixMethods = new Dictionary<long, HashSet<object>>(); _hookPrefixMethods = new Dictionary<long, HashSet<Tuple<string, object>>>();
_hookPostfixMethods = new Dictionary<long, HashSet<object>>(); _hookPostfixMethods = new Dictionary<long, HashSet<Tuple<string, object>>>();
} }
public class HookFunction public class HookFunction
@@ -32,8 +32,8 @@ namespace Barotrauma
private Dictionary<string, Dictionary<string, HookFunction>> hookFunctions = new Dictionary<string, Dictionary<string, HookFunction>>(); private Dictionary<string, Dictionary<string, HookFunction>> hookFunctions = new Dictionary<string, Dictionary<string, HookFunction>>();
private static Dictionary<long, HashSet<object>> _hookPrefixMethods; private static Dictionary<long, HashSet<Tuple<string, object>>> _hookPrefixMethods;
private static Dictionary<long, HashSet<object>> _hookPostfixMethods; private static Dictionary<long, HashSet<Tuple<string, object>>> _hookPostfixMethods;
private Queue<Tuple<float, object, object[]>> queuedFunctionCalls = new Queue<Tuple<float, object, object[]>>(); private Queue<Tuple<float, object, object[]>> queuedFunctionCalls = new Queue<Tuple<float, object, object[]>>();
@@ -53,38 +53,38 @@ namespace Barotrauma
try try
{ {
var @params = __originalMethod.GetParameters();
var ptable = new Dictionary<string, object>();
for (int i = 0; i < @params.Length; i++)
{
ptable.Add(@params[i].Name, __args[i]);
}
var funcAddr = ((long)__originalMethod.MethodHandle.GetFunctionPointer()); var funcAddr = ((long)__originalMethod.MethodHandle.GetFunctionPointer());
HashSet<object> methodSet = null; HashSet<Tuple<string, object>> methodSet = null;
switch (hookMethodType) switch (hookMethodType)
{ {
case HookMethodType.Before: case HookMethodType.Before:
methodSet = _hookPrefixMethods[funcAddr]; _hookPrefixMethods.TryGetValue(funcAddr, out methodSet);
break; break;
case HookMethodType.After: case HookMethodType.After:
methodSet = _hookPostfixMethods[funcAddr]; _hookPostfixMethods.TryGetValue(funcAddr, out methodSet);
break; break;
default: default:
break; break;
} }
if (methodSet != null) if (methodSet != null)
{ {
foreach (var hookMethod in methodSet) var @params = __originalMethod.GetParameters();
var ptable = new Dictionary<string, object>();
for (int i = 0; i < @params.Length; i++)
{ {
result = new LuaResult(GameMain.Lua.lua.Call(hookMethod, __instance, ptable)); ptable.Add(@params[i].Name, __args[i]);
}
foreach (var tuple in methodSet)
{
result = new LuaResult(GameMain.Lua.lua.Call(tuple.Item2, __instance, ptable));
} }
} }
} }
catch (Exception ex) catch (Exception ex)
{ {
GameMain.Lua.HandleLuaException(ex, nameof(_hookLuaPatch)); GameMain.Lua.HandleLuaException(ex);
} }
} }
@@ -126,20 +126,14 @@ namespace Barotrauma
private static MethodInfo _miHookLuaPatchRetPrefix = typeof(LuaHook).GetMethod("HookLuaPatchRetPrefix", 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 _miHookLuaPatchPostfix = typeof(LuaHook).GetMethod("HookLuaPatchPostfix", BindingFlags.NonPublic | BindingFlags.Static);
private static MethodInfo _miHookLuaPatchRetPostfix = typeof(LuaHook).GetMethod("HookLuaPatchRetPostfix", BindingFlags.NonPublic | BindingFlags.Static); private static MethodInfo _miHookLuaPatchRetPostfix = typeof(LuaHook).GetMethod("HookLuaPatchRetPostfix", BindingFlags.NonPublic | BindingFlags.Static);
public void HookMethod(string className, string methodName, string[] parameterNames, object hookMethod, HookMethodType hookMethodType = HookMethodType.Before) public void HookMethod(string identifier, string className, string methodName, string[] parameterNames, object hookMethod, HookMethodType hookMethodType = HookMethodType.Before)
{ {
if (hookMethod == null) var classType = LuaUserData.GetType(className);
{
GameMain.Lua.PrintError("hookMethod cannot be null");
return;
}
var classType = Type.GetType(className);
MethodInfo methodInfo = null; MethodInfo methodInfo = null;
if (parameterNames != null) if (parameterNames != null)
{ {
Type[] parameterTypes = parameterNames.Select(x => AccessTools.TypeByName(x)).ToArray(); Type[] parameterTypes = parameterNames.Select(x => LuaUserData.GetType(x)).ToArray();
methodInfo = classType.GetMethod(methodName, DefaultBindingFlags, null, parameterTypes, null); methodInfo = classType.GetMethod(methodName, DefaultBindingFlags, null, parameterTypes, null);
} }
else else
@@ -149,7 +143,7 @@ namespace Barotrauma
if (methodInfo == null) if (methodInfo == null)
{ {
GameMain.Lua.PrintError($"can't find method({className}.{methodName}) with these parameters' types({string.Join(", ", parameterNames)})"); GameMain.Lua.PrintError($"Method '{methodName}' with parameter '{string.Join(", ", parameterNames)}' not found from Class '{className}'");
return; return;
} }
@@ -173,13 +167,20 @@ namespace Barotrauma
} }
} }
if (_hookPrefixMethods.TryGetValue(funcAddr, out HashSet<object> methodSet)) if (_hookPrefixMethods.TryGetValue(funcAddr, out HashSet<Tuple<string, object>> methodSet))
{ {
methodSet.Add(hookMethod); if (identifier != "")
{
methodSet.RemoveWhere(tuple => tuple.Item1 == identifier);
}
if (hookMethod != null)
{
methodSet.Add(Tuple.Create(identifier, hookMethod));
}
} }
else else if (hookMethod != null)
{ {
_hookPrefixMethods.Add(funcAddr, new HashSet<object>() { hookMethod }); _hookPrefixMethods.Add(funcAddr, new HashSet<Tuple<string, object>>() { Tuple.Create(identifier, hookMethod) });
} }
} }
@@ -200,13 +201,20 @@ namespace Barotrauma
} }
} }
if (_hookPostfixMethods.TryGetValue(funcAddr, out HashSet<object> methodSet)) if (_hookPostfixMethods.TryGetValue(funcAddr, out HashSet<Tuple<string, object>> methodSet))
{ {
methodSet.Add(hookMethod); if (identifier != "")
{
methodSet.RemoveWhere(tuple => tuple.Item1 == identifier);
}
if (hookMethod != null)
{
methodSet.Add(Tuple.Create(identifier, hookMethod));
}
} }
else else if (hookMethod != null)
{ {
_hookPostfixMethods.Add(funcAddr, new HashSet<object>() { hookMethod }); _hookPostfixMethods.Add(funcAddr, new HashSet<Tuple<string, object>>() { Tuple.Create(identifier, hookMethod) });
} }
} }
@@ -215,9 +223,18 @@ namespace Barotrauma
public void HookMethod(string className, string methodName, object hookMethod, HookMethodType hookMethodType = HookMethodType.Before) public void HookMethod(string className, string methodName, object hookMethod, HookMethodType hookMethodType = HookMethodType.Before)
{ {
HookMethod(className, methodName, null, hookMethod, hookMethodType); HookMethod("", className, methodName, null, hookMethod, hookMethodType);
} }
public void HookMethod(string className, string methodName, string[] parameterNames, object hookMethod, HookMethodType hookMethodType = HookMethodType.Before)
{
HookMethod("", className, methodName, parameterNames, hookMethod, hookMethodType);
}
public void HookMethod(string identifier, string className, string methodName, object hookMethod, HookMethodType hookMethodType = HookMethodType.Before)
{
HookMethod(identifier, className, methodName, null, hookMethod, hookMethodType);
}
public void EnqueueFunction(object function, params object[] args) public void EnqueueFunction(object function, params object[] args)
{ {