modified way to patch, can realize params map for compatibility, and try to hook Item in lua.

This commit is contained in:
zhurengong
2021-11-10 21:07:19 +08:00
parent 5c6450c6a2
commit 6b1aca8efa
5 changed files with 72 additions and 100 deletions
@@ -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
@@ -49,7 +49,7 @@ if SERVER then
elseif CLIENT then elseif CLIENT then
defaultLib["Sprite"] = CreateStatic("Sprite") 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") defaultLib["PlayerInput"] = CreateStatic("PlayerInput")
end end
@@ -11,6 +11,8 @@ for key, value in pairs(defaultLib) do
_G[key] = value _G[key] = value
end end
require("DefaultHook")
-- Execute Mods -- Execute Mods
if SERVER and Game.IsDedicated then if SERVER and Game.IsDedicated then
@@ -2166,11 +2166,6 @@ namespace Barotrauma
public bool TryInteract(Character picker, bool ignoreRequiredItems = false, bool forceSelectKey = false, bool forceActionKey = false) 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; } if (CampaignInteractionType != CampaignMode.InteractionType.None) { return false; }
bool picked = false, selected = false; bool picked = false, selected = false;
@@ -2309,11 +2304,6 @@ namespace Barotrauma
if (condition == 0.0f) { return; } 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; bool remove = false;
foreach (ItemComponent ic in components) foreach (ItemComponent ic in components)
@@ -2347,12 +2337,6 @@ namespace Barotrauma
{ {
if (condition == 0.0f) { return; } 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; bool remove = false;
foreach (ItemComponent ic in components) foreach (ItemComponent ic in components)
@@ -2384,11 +2368,6 @@ namespace Barotrauma
public void ApplyTreatment(Character user, Character character, Limb targetLimb) 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 //can't apply treatment to dead characters
if (character.IsDead) { return; } if (character.IsDead) { return; }
if (!UseInHealthInterface) { return; } if (!UseInHealthInterface) { return; }
@@ -2454,11 +2433,6 @@ namespace Barotrauma
public bool Combine(Item item, Character user) 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; } if (item == this) { return false; }
bool isCombined = false; bool isCombined = false;
foreach (ItemComponent ic in components) foreach (ItemComponent ic in components)
@@ -2473,11 +2447,6 @@ namespace Barotrauma
public void Drop(Character dropper, bool createNetworkEvent = true) 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 (createNetworkEvent)
{ {
if (parentInventory != null && !parentInventory.Owner.Removed && !Removed && if (parentInventory != null && !parentInventory.Owner.Removed && !Removed &&
@@ -2530,11 +2499,6 @@ namespace Barotrauma
public void Equip(Character character) public void Equip(Character character)
{ {
var should = new LuaResult(GameMain.Lua.hook.Call("itemEquip", new object[] { this, character}));
if (should.Bool())
return;
if (Removed) if (Removed)
{ {
DebugConsole.ThrowError($"Tried to equip a removed item ({Name}).\n{Environment.StackTrace.CleanupStackTrace()}"); DebugConsole.ThrowError($"Tried to equip a removed item ({Name}).\n{Environment.StackTrace.CleanupStackTrace()}");
@@ -2546,11 +2510,6 @@ namespace Barotrauma
public void Unequip(Character character) 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); } foreach (ItemComponent ic in components) { ic.Unequip(character); }
} }
@@ -77,12 +77,12 @@ namespace Barotrauma
descriptor.AddMetaMember("__call", new ObjectCallbackMemberDescriptor("__call", LuaSetup.luaSetup.HandleCall)); 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 descriptor = (StandardUserDataDescriptor)IUUD;
var field = IUUD.Type.GetField(methodName, BindingFlags.NonPublic | BindingFlags.Instance); var field = IUUD.Type.GetField(fieldName, BindingFlags.NonPublic | BindingFlags.Instance);
descriptor.RemoveMember(methodName); descriptor.RemoveMember(fieldName);
descriptor.AddMember(methodName, new FieldMemberDescriptor(field, InteropAccessMode.Default)); descriptor.AddMember(fieldName, new FieldMemberDescriptor(field, InteropAccessMode.Default));
} }
public static void MakeMethodAccessible(IUserDataDescriptor IUUD, string methodName) public static void MakeMethodAccessible(IUserDataDescriptor IUUD, string methodName)
@@ -712,7 +712,8 @@ namespace Barotrauma
public LuaHook(LuaSetup e) public LuaHook(LuaSetup e)
{ {
env = e; env = e;
methodNameToHookName = new Dictionary<string, string>(); _methodPathToHookName = new Dictionary<string, string>();
_luaPatchParamsMap = new Dictionary<string, object>();
} }
public class HookFunction public class HookFunction
@@ -731,7 +732,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<string, string> methodNameToHookName; private static Dictionary<string, string> _methodPathToHookName;
private static Dictionary<string, object> _luaPatchParamsMap;
private Queue<Tuple<object, object[]>> queuedFunctionCalls = new Queue<Tuple<object, object[]>>(); private Queue<Tuple<object, object[]>> queuedFunctionCalls = new Queue<Tuple<object, object[]>>();
@@ -740,47 +742,48 @@ namespace Barotrauma
Before, After 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) hookName = _methodPathToHookName[methodPath];
{
parameters = __params; // Regardless of whether __instance is null or not, it's necessaray to avoid the inability to distinguish parameters when adding hooks in lua.
}
else
{
parameters = new object[__params.Length + 1]; parameters = new object[__params.Length + 1];
__params.CopyTo(parameters, 1); __params.CopyTo(parameters, 1);
parameters[0] = __instance; 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<object[]>();
}
} }
catch (Exception ex)
var result = new LuaResult(luaSetup.hook.Call(methodNameToHookName[__originalMethod.Name], parameters));
if (!result.IsNull())
{ {
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) 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) var result = new LuaResult(luaSetup.hook.Call(hookName, parameters));
{
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()) if (!result.IsNull())
{ {
@@ -793,37 +796,26 @@ namespace Barotrauma
static void HookLuaPatchPostfix(MethodBase __originalMethod, object[] __params, object __instance) static void HookLuaPatchPostfix(MethodBase __originalMethod, object[] __params, object __instance)
{ {
if (__instance == null) _hookLuaPatchPreProcess(__originalMethod, __params, __instance, out string hookName, out object[] parameters);
luaSetup.hook.Call(methodNameToHookName[__originalMethod.Name], __params); luaSetup.hook.Call(hookName, parameters);
else
luaSetup.hook.Call(methodNameToHookName[__originalMethod.Name], __instance, __params);
} }
static void HookLuaPatchRetPostfix(MethodBase __originalMethod, object[] __params, ref object __result, object __instance) 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) var result = new LuaResult(luaSetup.hook.Call(hookName, parameters));
{
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()) if (!result.IsNull())
__result = result.Object(); __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 @class = Type.GetType(className);
var methodInfos = classType.GetMethods(); var methodInfos = @class.GetMethods();
HarmonyMethod harmonyMethod = new HarmonyMethod(); HarmonyMethod harmonyMethod = new HarmonyMethod();
HarmonyMethod harmonyMethodRet = new HarmonyMethod(); HarmonyMethod harmonyMethodRet = new HarmonyMethod();
@@ -840,11 +832,10 @@ namespace Barotrauma
harmonyMethodRet = new HarmonyMethod(GetType().GetMethod("HookLuaPatchRetPrefix", BindingFlags.NonPublic | BindingFlags.Static)); harmonyMethodRet = new HarmonyMethod(GetType().GetMethod("HookLuaPatchRetPrefix", BindingFlags.NonPublic | BindingFlags.Static));
} }
var foundAny = false;
foreach (var methodInfo in methodInfos) foreach (var methodInfo in methodInfos)
{ {
if(methodInfo.Name == methodName) if (methodInfo.Name == methodName)
{ {
if (hookMethodType == HookMethodType.Before) if (hookMethodType == HookMethodType.Before)
if (methodInfo.ReturnType == typeof(void)) if (methodInfo.ReturnType == typeof(void))
@@ -859,12 +850,22 @@ namespace Barotrauma
else else
env.harmony.Patch(methodInfo, postfix: harmonyMethodRet); 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) public void EnqueueFunction(object function, params object[] args)