using System; using System.Collections; using System.Collections.Generic; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using BepInEx; using HarmonyLib; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: AssemblyVersion("0.0.0.0")] namespace TokControlGolfPatches; public static class Bootstrap { internal static string LogPath; internal static int OverflowIndex = 20000; internal static object PlayerOverride; internal static string RecentLocalEventId; internal static DateTime RecentLocalEventAt; internal static bool TryAddPatched; internal static bool InGameNotify = true; internal static ulong RemoteEventPlayerId; internal static bool SuppressHostLocalEvent; internal static Harmony HarmonyInst; internal static bool ConfigPatched; public static void Init() { //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Expected O, but got Unknown try { string directoryName = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); LogPath = Path.Combine(directoryName ?? ".", "tokcontrol_patches_log.txt"); Log("Init Harmony patches"); HarmonyInst = new Harmony("tokcontrol.battlegolf.patches"); Type[] types = typeof(Bootstrap).Assembly.GetTypes(); for (int i = 0; i < types.Length; i++) { try { HarmonyInst.CreateClassProcessor(types[i]).Patch(); } catch (Exception ex) { Log("skip patch " + types[i].Name + ": " + ex.Message); } } TryPatchConfig(); AppDomain.CurrentDomain.AssemblyLoad += OnAssemblyLoad; Log("Harmony patches applied inGameNotify=" + InGameNotify); } catch (Exception ex2) { Log("Init error: " + ex2); } } private static void OnAssemblyLoad(object sender, AssemblyLoadEventArgs args) { try { if (args != null && !(args.LoadedAssembly == null) && !ConfigPatched) { string name = args.LoadedAssembly.GetName().Name; if (name != null && name.IndexOf("Interactive", StringComparison.OrdinalIgnoreCase) >= 0) { TryPatchConfig(); } } } catch { } } internal static void TryPatchConfig() { //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Expected O, but got Unknown if (!ConfigPatched && HarmonyInst != null) { MethodBase methodBase = FindConfigStringMethod(); if (!(methodBase == null)) { HarmonyInst.Patch(methodBase, (HarmonyMethod)null, new HarmonyMethod(typeof(ConfigNotifyPatch), "Postfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); ConfigPatched = true; Log("patched config " + methodBase.DeclaringType.FullName + "." + methodBase.Name); } } } private static MethodBase FindConfigStringMethod() { Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); MethodBase methodBase = null; for (int i = 0; i < assemblies.Length; i++) { Type[] types; try { types = assemblies[i].GetTypes(); } catch (ReflectionTypeLoadException ex) { types = ex.Types; } catch { continue; } if (types == null) { continue; } foreach (Type type in types) { if (type == null) { continue; } string name = type.Name; if (name.IndexOf("InteractiveMod") < 0) { continue; } MethodInfo[] methods; try { methods = type.GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); } catch { continue; } foreach (MethodInfo methodInfo in methods) { if (methodInfo.Name.IndexOf("Config") < 0) { continue; } ParameterInfo[] parameters = methodInfo.GetParameters(); if (parameters.Length >= 1 && !(parameters[0].ParameterType != typeof(string))) { if (methodInfo.Name.IndexOf("OnConfig") >= 0) { return methodInfo; } if (methodBase == null) { methodBase = methodInfo; } } } } } return methodBase; } internal static bool ReadJsonBool(string json, string key, bool fallback) { if (string.IsNullOrEmpty(json) || string.IsNullOrEmpty(key)) { return fallback; } int num = json.IndexOf(key, StringComparison.OrdinalIgnoreCase); if (num < 0) { return fallback; } int num2 = json.IndexOf(':', num + key.Length); if (num2 < 0) { return fallback; } int i; for (i = num2 + 1; i < json.Length && (json[i] == ' ' || json[i] == '\t' || json[i] == '\r' || json[i] == '\n' || json[i] == '\\' || json[i] == '"'); i++) { } if (i + 4 <= json.Length && string.Compare(json, i, "true", 0, 4, StringComparison.OrdinalIgnoreCase) == 0) { return true; } if (i + 5 <= json.Length && string.Compare(json, i, "false", 0, 5, StringComparison.OrdinalIgnoreCase) == 0) { return false; } return fallback; } internal static void ApplyConfigJson(string json) { if (!string.IsNullOrEmpty(json) && json.IndexOf("inGameNotify", StringComparison.OrdinalIgnoreCase) >= 0) { InGameNotify = ReadJsonBool(json, "inGameNotify", InGameNotify); Log("inGameNotify=" + InGameNotify); } } internal static void Log(string message) { try { if (!string.IsNullOrEmpty(LogPath)) { File.AppendAllText(LogPath, DateTime.Now.ToString("HH:mm:ss") + " " + message + Environment.NewLine); } } catch { } } internal static ulong ReadLocalPlayerGuid() { try { Type type = AccessTools.TypeByName("GameManager"); PropertyInfo propertyInfo = ((type == null) ? null : AccessTools.Property(type, "LocalPlayerInfo")); object obj = ((propertyInfo == null) ? null : propertyInfo.GetValue(null, null)); Type type2 = AccessTools.TypeByName("bft_mod.GameUtils"); MethodInfo methodInfo = ((type2 == null) ? null : AccessTools.Method(type2, "GetPlayerGUID", (Type[])null, (Type[])null)); if (methodInfo == null || obj == null) { return 0uL; } return Convert.ToUInt64(methodInfo.Invoke(null, new object[1] { obj })); } catch { return 0uL; } } internal static bool IsRemoteEventForOtherPlayer() { if (RemoteEventPlayerId == 0 || RemoteEventPlayerId == ulong.MaxValue) { return false; } ulong num = ReadLocalPlayerGuid(); if (num != 0) { return RemoteEventPlayerId != num; } return false; } internal static object PlayerForRemoteOrLocal() { if (PlayerOverride != null) { return PlayerOverride; } if (IsRemoteEventForOtherPlayer()) { Type type = AccessTools.TypeByName("bft_mod.GameUtils"); MethodInfo methodInfo = ((type == null) ? null : AccessTools.Method(type, "GetPlayerByNetworkID", (Type[])null, (Type[])null)); object obj = ((methodInfo == null) ? null : methodInfo.Invoke(null, new object[1] { RemoteEventPlayerId })); if (obj != null) { return obj; } } Type type2 = AccessTools.TypeByName("bft_mod.GameUtils"); MethodInfo methodInfo2 = ((type2 == null) ? null : AccessTools.Method(type2, "GetCurrentPlayer", (Type[])null, (Type[])null)); if (!(methodInfo2 == null)) { return methodInfo2.Invoke(null, null); } return null; } internal static void ClearRemoteEventTarget() { RemoteEventPlayerId = 0uL; SuppressHostLocalEvent = false; PlayerOverride = null; } } internal static class InventoryUtil { internal static object GetInventory(object player) { if (player == null) { return null; } PropertyInfo propertyInfo = AccessTools.Property(player.GetType(), "Inventory"); if (!(propertyInfo == null)) { return propertyInfo.GetValue(player, null); } return null; } internal static int GetSlotCount(object inventory) { if (inventory == null) { return 0; } object obj = null; FieldInfo fieldInfo = AccessTools.Field(inventory.GetType(), "slots"); if (fieldInfo != null) { obj = fieldInfo.GetValue(inventory); } if (obj == null) { PropertyInfo propertyInfo = AccessTools.Property(inventory.GetType(), "slots"); if (propertyInfo != null) { obj = propertyInfo.GetValue(inventory, null); } } if (obj is ICollection collection) { return collection.Count; } if (obj != null) { PropertyInfo property = obj.GetType().GetProperty("Count"); if (property != null) { return Convert.ToInt32(property.GetValue(obj, null)); } } return 8; } internal static int CountOccupied(object inventory) { if (inventory == null) { return 0; } int slotCount = GetSlotCount(inventory); MethodInfo methodInfo = AccessTools.Method(inventory.GetType(), "IsItemSlotOccupied", new Type[1] { typeof(int) }, (Type[])null); int num = 0; for (int i = 0; i < slotCount; i++) { try { if (methodInfo != null && Convert.ToBoolean(methodInfo.Invoke(inventory, new object[1] { i }))) { num++; } } catch { } } return num; } internal static int CountFree(object inventory) { int slotCount = GetSlotCount(inventory); int num = CountOccupied(inventory); int num2 = slotCount - num; if (num2 >= 0) { return num2; } return 0; } internal static object ParseItemType(string itemName) { Type type = AccessTools.TypeByName("ItemType"); if (type == null || string.IsNullOrEmpty(itemName)) { return null; } string[] array = new string[2] { itemName, AliasItemName(itemName) }; for (int i = 0; i < array.Length; i++) { if (!string.IsNullOrEmpty(array[i])) { try { return Enum.Parse(type, array[i], ignoreCase: true); } catch { } } } Array values = Enum.GetValues(type); string text = AliasItemName(itemName).ToLowerInvariant(); for (int i = 0; i < values.Length; i++) { object value = values.GetValue(i); if (value != null && value.ToString().ToLowerInvariant() == text) { return value; } } return null; } internal static string AliasItemName(string itemName) { if (string.Equals(itemName, "ThunderStorm", StringComparison.OrdinalIgnoreCase)) { return "Thunderstorm"; } if (string.Equals(itemName, "RailGun", StringComparison.OrdinalIgnoreCase)) { return "Railgun"; } return itemName; } internal static object GetSlots(object inventory) { if (inventory == null) { return null; } FieldInfo fieldInfo = AccessTools.Field(inventory.GetType(), "slots"); object obj = ((fieldInfo == null) ? null : fieldInfo.GetValue(inventory)); if (obj == null) { PropertyInfo propertyInfo = AccessTools.Property(inventory.GetType(), "slots"); obj = ((propertyInfo == null) ? null : propertyInfo.GetValue(inventory, null)); } return obj; } internal static object ReadItemType(object entry) { if (entry == null) { return null; } Type type = entry.GetType(); if (type.IsEnum && type.Name.IndexOf("Item") >= 0) { return entry; } string[] array = new string[10] { "ItemType", "itemType", "Type", "type", "item", "Item", "itemData", "ItemData", "data", "Data" }; for (int i = 0; i < array.Length; i++) { PropertyInfo propertyInfo = AccessTools.Property(type, array[i]); object obj = ((propertyInfo == null) ? null : propertyInfo.GetValue(entry, null)); if (obj != null) { if (obj.GetType().IsEnum) { return obj; } object obj2 = ReadItemType(obj); if (obj2 != null) { return obj2; } } FieldInfo fieldInfo = AccessTools.Field(type, array[i]); obj = ((fieldInfo == null) ? null : fieldInfo.GetValue(entry)); if (obj != null) { if (obj.GetType().IsEnum) { return obj; } object obj3 = ReadItemType(obj); if (obj3 != null) { return obj3; } } } FieldInfo[] fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); for (int i = 0; i < fields.Length; i++) { object value = fields[i].GetValue(entry); if (value != null && value.GetType().IsEnum && value.GetType().Name.IndexOf("Item") >= 0) { return value; } } PropertyInfo[] properties = type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); for (int i = 0; i < properties.Length; i++) { if (properties[i].GetIndexParameters().Length <= 0) { object obj4 = null; try { obj4 = properties[i].GetValue(entry, null); } catch { } if (obj4 != null && obj4.GetType().IsEnum && obj4.GetType().Name.IndexOf("Item") >= 0) { return obj4; } } } return null; } internal static int FindSlotByItemName(object inventory, string itemName) { object obj = ParseItemType(itemName); if (inventory == null || obj == null) { return -1; } int slotCount = GetSlotCount(inventory); MethodInfo methodInfo = AccessTools.Method(inventory.GetType(), "GetEffectiveSlot", new Type[1] { typeof(int) }, (Type[])null); object slots = GetSlots(inventory); IList list = slots as IList; for (int i = 0; i < slotCount; i++) { object obj2 = null; if (methodInfo != null) { try { obj2 = methodInfo.Invoke(inventory, new object[1] { i }); } catch { obj2 = null; } } if (obj2 == null && list != null && i < list.Count) { obj2 = list[i]; } object obj4 = ReadItemType(obj2); if (obj4 != null && obj4.ToString() == obj.ToString()) { return i; } } return -1; } internal static bool SelectSlot(object inventory, int slot) { if (inventory == null || slot < 0) { return false; } Type type = inventory.GetType(); MethodInfo methodInfo = AccessTools.Method(type, "TrySelectItemSlot", new Type[2] { typeof(int), typeof(bool) }, (Type[])null); if (methodInfo != null) { object obj = methodInfo.Invoke(inventory, new object[2] { slot, true }); if (obj == null || Convert.ToBoolean(obj)) { return true; } } PropertyInfo propertyInfo = AccessTools.Property(type, "EquippedItemIndex"); if (propertyInfo != null && propertyInfo.CanWrite && propertyInfo.PropertyType == typeof(int)) { propertyInfo.SetValue(inventory, slot, null); return true; } MethodInfo methodInfo2 = AccessTools.Method(type, "set_EquippedItemIndex", new Type[1] { typeof(int) }, (Type[])null); if (methodInfo2 != null) { methodInfo2.Invoke(inventory, new object[1] { slot }); return true; } string[] array = new string[7] { "SelectSlot", "SetSelectedSlot", "CmdSelectSlot", "ServerSelectSlot", "TrySelectSlot", "SetSlot", "ChangeSlot" }; for (int i = 0; i < array.Length; i++) { MethodInfo methodInfo3 = AccessTools.Method(type, array[i], new Type[1] { typeof(int) }, (Type[])null); if (!(methodInfo3 == null)) { methodInfo3.Invoke(inventory, new object[1] { slot }); return true; } } string[] array2 = new string[7] { "selectedSlot", "SelectedSlot", "currentSlot", "CurrentSlot", "selectedIndex", "SelectedIndex", "equippedSlotIndex" }; for (int i = 0; i < array2.Length; i++) { PropertyInfo propertyInfo2 = AccessTools.Property(type, array2[i]); if (propertyInfo2 != null && propertyInfo2.CanWrite && propertyInfo2.PropertyType == typeof(int)) { propertyInfo2.SetValue(inventory, slot, null); return true; } FieldInfo fieldInfo = AccessTools.Field(type, array2[i]); if (fieldInfo != null && fieldInfo.FieldType == typeof(int)) { fieldInfo.SetValue(inventory, slot); return true; } } return false; } internal static bool FreeLastOccupied(object inventory) { if (inventory == null) { return false; } int slotCount = GetSlotCount(inventory); MethodInfo methodInfo = AccessTools.Method(inventory.GetType(), "IsItemSlotOccupied", new Type[1] { typeof(int) }, (Type[])null); MethodInfo methodInfo2 = AccessTools.Method(inventory.GetType(), "CmdRemoveItemAt", new Type[2] { typeof(int), typeof(bool) }, (Type[])null); if (methodInfo2 == null) { methodInfo2 = AccessTools.Method(inventory.GetType(), "RemoveItemAt", new Type[2] { typeof(int), typeof(bool) }, (Type[])null); } if (methodInfo2 == null) { methodInfo2 = AccessTools.Method(inventory.GetType(), "CmdRemoveItemAt", (Type[])null, (Type[])null); } if (methodInfo2 == null) { methodInfo2 = AccessTools.Method(inventory.GetType(), "RemoveItemAt", (Type[])null, (Type[])null); } if (methodInfo2 == null) { return false; } for (int num = slotCount - 1; num >= 0; num--) { if (methodInfo == null || Convert.ToBoolean(methodInfo.Invoke(inventory, new object[1] { num }))) { ParameterInfo[] parameters = methodInfo2.GetParameters(); object[] parameters2 = ((parameters.Length >= 2) ? new object[2] { num, false } : ((parameters.Length != 1) ? new object[0] : new object[1] { num })); methodInfo2.Invoke(inventory, parameters2); Bootstrap.Log("itemfx freed slot " + num); return true; } } return false; } internal static MethodInfo FindRemoveItemAt(object inventory) { if (inventory == null) { return null; } Type type = inventory.GetType(); MethodInfo[] methods = type.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); MethodInfo methodInfo = null; MethodInfo methodInfo2 = null; foreach (MethodInfo methodInfo3 in methods) { if (methodInfo3.Name == "RemoveItemAt" && HasSlotParameter(methodInfo3) && (methodInfo == null || methodInfo3.GetParameters().Length > methodInfo.GetParameters().Length)) { methodInfo = methodInfo3; } if (methodInfo3.Name == "CmdRemoveItemAt" && HasSlotParameter(methodInfo3) && methodInfo2 == null) { methodInfo2 = methodInfo3; } } if (methodInfo != null) { return methodInfo; } return methodInfo2; } private static bool HasSlotParameter(MethodInfo method) { ParameterInfo[] parameters = method.GetParameters(); for (int i = 0; i < parameters.Length; i++) { if (parameters[i].ParameterType == typeof(int)) { return true; } } return false; } internal static void InvokeSlotMethod(MethodInfo method, object inventory, int slot) { if (method == null || inventory == null) { return; } ParameterInfo[] parameters = method.GetParameters(); object[] array = new object[parameters.Length]; for (int i = 0; i < parameters.Length; i++) { Type parameterType = parameters[i].ParameterType; if (parameterType == typeof(int)) { array[i] = slot; } else if (parameterType == typeof(bool)) { array[i] = false; } else if (parameterType.IsValueType) { array[i] = Activator.CreateInstance(parameterType); } else { array[i] = null; } } method.Invoke(inventory, array); } internal static int ClearAllOccupied(object inventory) { if (inventory == null) { return 0; } MethodInfo methodInfo = AccessTools.Method(inventory.GetType(), "IsItemSlotOccupied", new Type[1] { typeof(int) }, (Type[])null); MethodInfo methodInfo2 = FindRemoveItemAt(inventory); MethodInfo methodInfo3 = AccessTools.Method(inventory.GetType(), "DropItem", Type.EmptyTypes, (Type[])null); if (methodInfo3 == null) { methodInfo3 = AccessTools.Method(inventory.GetType(), "DropItem", (Type[])null, (Type[])null); } int num = 0; int slotCount = GetSlotCount(inventory); for (int num2 = slotCount - 1; num2 >= 0; num2--) { if (methodInfo == null || Convert.ToBoolean(methodInfo.Invoke(inventory, new object[1] { num2 }))) { SelectSlot(inventory, num2); if (methodInfo2 != null) { InvokeSlotMethod(methodInfo2, inventory, num2); num++; Bootstrap.Log("clear_inventory: RemoveItemAt slot " + num2); } } } int num3 = 0; int num4 = Math.Max(slotCount, 8) * 2; while (num3 < num4 && CountOccupied(inventory) > 0) { num3++; int num5 = -1; for (int num2 = 0; num2 < GetSlotCount(inventory); num2++) { if (methodInfo == null || Convert.ToBoolean(methodInfo.Invoke(inventory, new object[1] { num2 }))) { num5 = num2; break; } } if (num5 < 0) { break; } SelectSlot(inventory, num5); if (methodInfo3 != null) { methodInfo3.Invoke(inventory, null); num++; Bootstrap.Log("clear_inventory: DropItem slot " + num5); continue; } if (!(methodInfo2 != null)) { break; } InvokeSlotMethod(methodInfo2, inventory, num5); num++; } return num; } internal static object ResolvePlayer(object inventory) { if (Bootstrap.PlayerOverride != null) { return Bootstrap.PlayerOverride; } Type type = AccessTools.TypeByName("bft_mod.GameUtils"); MethodInfo methodInfo = ((type == null) ? null : AccessTools.Method(type, "GetCurrentPlayer", (Type[])null, (Type[])null)); object obj = ((methodInfo == null) ? null : methodInfo.Invoke(null, null)); if (obj != null) { return obj; } if (inventory == null) { return null; } string[] array = new string[5] { "Player", "player", "Owner", "owner", "GolfPlayer" }; for (int i = 0; i < array.Length; i++) { PropertyInfo propertyInfo = AccessTools.Property(inventory.GetType(), array[i]); if (propertyInfo != null) { object value = propertyInfo.GetValue(inventory, null); if (value != null) { return value; } } FieldInfo fieldInfo = AccessTools.Field(inventory.GetType(), array[i]); if (fieldInfo != null) { object value2 = fieldInfo.GetValue(inventory); if (value2 != null) { return value2; } } } return null; } } [HarmonyPatch] internal static class ClearInventoryPatch { private static MethodBase TargetMethod() { Type type = AccessTools.TypeByName("bft_mod.Commands.ClearInventory"); if (!(type == null)) { return AccessTools.Method(type, "Execute", (Type[])null, (Type[])null); } return null; } private static bool Prefix(object __instance, IEnumerable args, ref bool __result) { try { object obj = Bootstrap.PlayerForRemoteOrLocal(); if (obj == null) { Bootstrap.Log("clear_inventory: no player"); __result = true; return false; } object inventory = InventoryUtil.GetInventory(obj); if (inventory == null) { Bootstrap.Log("clear_inventory: no inventory"); __result = true; return false; } int num = InventoryUtil.CountOccupied(inventory); MethodInfo methodInfo = InventoryUtil.FindRemoveItemAt(inventory); int num2 = InventoryUtil.ClearAllOccupied(inventory); int num3 = InventoryUtil.CountOccupied(inventory); Bootstrap.Log("clear_inventory: occupied=" + num + " cleared=" + num2 + " remaining=" + num3 + " via " + ((methodInfo == null) ? "none" : methodInfo.Name)); __result = num3 <= 0; return false; } catch (Exception ex) { Bootstrap.Log("clear_inventory error: " + ex); return true; } } } [HarmonyPatch] internal static class GiveItemOverflowPatch { private static MethodBase TargetMethod() { Type type = AccessTools.TypeByName("bft_mod.Commands.GiveItem"); if (!(type == null)) { return AccessTools.Method(type, "ExecuteHostAction", (Type[])null, (Type[])null); } return null; } private static void Prefix(object __instance, IEnumerable args, object targetPlayer, ref int __state) { __state = InventoryUtil.CountOccupied(InventoryUtil.GetInventory(targetPlayer)); } private static void Postfix(object __instance, IEnumerable args, object targetPlayer, int __state) { try { if (!Bootstrap.TryAddPatched && targetPlayer != null) { object inventory = InventoryUtil.GetInventory(targetPlayer); int num = InventoryUtil.CountOccupied(inventory); if (num <= __state && InventoryUtil.CountFree(inventory) <= 0) { SpawnDropped(args, targetPlayer); } } } catch (Exception ex) { Bootstrap.Log("give overflow error: " + ex); } } private static object GetInventory(object player) { return InventoryUtil.GetInventory(player); } private static string ReadArg(IEnumerable args, int index, string fallback) { if (args == null) { return fallback; } int num = 0; foreach (string arg in args) { if (num == index) { return string.IsNullOrEmpty(arg) ? fallback : arg; } num++; } return fallback; } private static void SpawnDropped(IEnumerable args, object targetPlayer) { string text = ReadArg(args, 0, "random"); int num = 1; if (int.TryParse(ReadArg(args, 1, "1"), out var result) && result > 0) { num = result; } Type type = AccessTools.TypeByName("ItemType"); if (type == null) { Bootstrap.Log("overflow: ItemType missing"); return; } object obj; if (string.Equals(text, "random", StringComparison.OrdinalIgnoreCase)) { Array values = Enum.GetValues(type); obj = values.GetValue(1 + Bootstrap.OverflowIndex % Math.Max(1, values.Length - 1)); } else { try { obj = Enum.Parse(type, text, ignoreCase: true); } catch { Bootstrap.Log("overflow: cannot parse " + text); return; } } object inventory = GetInventory(targetPlayer); object playerPosition = GetPlayerPosition(targetPlayer); Type type2 = AccessTools.TypeByName("UnityEngine.Vector3"); Type type3 = AccessTools.TypeByName("UnityEngine.Quaternion"); if (playerPosition == null || type2 == null || type3 == null) { Bootstrap.Log("overflow: no position"); return; } object obj3 = null; PropertyInfo propertyInfo = AccessTools.Property(type2, "zero"); if (propertyInfo != null) { obj3 = propertyInfo.GetValue(null, null); } if (obj3 == null) { FieldInfo fieldInfo = AccessTools.Field(type2, "zero"); obj3 = ((fieldInfo == null) ? null : fieldInfo.GetValue(null)); } if (obj3 == null) { obj3 = Activator.CreateInstance(type2); } object value = AccessTools.Property(type3, "identity").GetValue(null, null); object b = MakeOffset(type2); playerPosition = AddVec(type2, playerPosition, b); object obj4 = MakeItemUseId(targetPlayer, obj); Type type4 = AccessTools.TypeByName("CourseManager"); MethodInfo methodInfo = ((type4 == null) ? null : AccessTools.Method(type4, "ServerSpawnItem", (Type[])null, (Type[])null)); if (methodInfo == null) { MethodInfo[] array = ((type4 == null) ? new MethodInfo[0] : type4.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)); for (int i = 0; i < array.Length; i++) { if (array[i].Name == "ServerSpawnItem" && array[i].GetParameters().Length >= 8) { methodInfo = array[i]; break; } } } if (methodInfo == null) { Bootstrap.Log("overflow: ServerSpawnItem missing"); return; } ParameterInfo[] parameters = methodInfo.GetParameters(); object[] array2 = new object[parameters.Length]; for (int j = 0; j < parameters.Length; j++) { string text2 = ((parameters[j].Name == null) ? "" : parameters[j].Name.ToLowerInvariant()); Type parameterType = parameters[j].ParameterType; if (parameterType == type) { array2[j] = obj; } else if (parameterType == typeof(int)) { array2[j] = num; } else if (parameterType == type2 && text2.IndexOf("pos") >= 0) { array2[j] = playerPosition; } else if (parameterType == type2) { array2[j] = obj3; } else if (parameterType == type3) { array2[j] = value; } else if (parameterType.Name == "ItemUseId") { array2[j] = obj4; } else if (parameterType.Name == "PlayerInventory") { array2[j] = inventory; } else if (parameterType == typeof(bool)) { array2[j] = true; } else { array2[j] = (parameterType.IsValueType ? Activator.CreateInstance(parameterType) : null); } } methodInfo.Invoke(null, array2); Bootstrap.Log("overflow: spawned " + text + " on ground"); } internal static void SpawnFromAddArgs(object inventory, object[] args) { object obj = null; int num = 1; if (args != null) { foreach (object obj2 in args) { if (obj2 != null) { Type type = obj2.GetType(); if (type.IsEnum && type.Name.IndexOf("Item") >= 0) { obj = obj2; } else if (obj2 is int num2 && num2 >= 1 && num2 <= 99) { num = num2; } } } } if (obj == null) { Bootstrap.Log("overflow tryadd: no ItemType"); return; } object targetPlayer = InventoryUtil.ResolvePlayer(inventory); List list = new List(); list.Add(obj.ToString()); list.Add(num.ToString()); SpawnDropped(list, targetPlayer); } private static object GetPlayerPosition(object player) { PropertyInfo propertyInfo = AccessTools.Property(player.GetType(), "Movement"); object obj = ((propertyInfo == null) ? null : propertyInfo.GetValue(player, null)); if (obj != null) { PropertyInfo propertyInfo2 = AccessTools.Property(obj.GetType(), "Position"); if (propertyInfo2 != null) { return propertyInfo2.GetValue(obj, null); } } PropertyInfo propertyInfo3 = AccessTools.Property(player.GetType(), "transform"); object obj2 = ((propertyInfo3 == null) ? null : propertyInfo3.GetValue(player, null)); if (obj2 == null) { return null; } PropertyInfo propertyInfo4 = AccessTools.Property(obj2.GetType(), "position"); if (!(propertyInfo4 == null)) { return propertyInfo4.GetValue(obj2, null); } return null; } private static object MakeOffset(Type vec3) { float num = (float)(Bootstrap.OverflowIndex++ % 8) * 0.785f; float num2 = (float)Math.Cos(num) * 1.2f; float num3 = (float)Math.Sin(num) * 1.2f; ConstructorInfo constructor = vec3.GetConstructor(new Type[3] { typeof(float), typeof(float), typeof(float) }); return constructor.Invoke(new object[3] { num2, 0.25f, num3 }); } private static object AddVec(Type vec3, object a, object b) { MethodInfo methodInfo = AccessTools.Method(vec3, "op_Addition", new Type[2] { vec3, vec3 }, (Type[])null); if (methodInfo != null) { return methodInfo.Invoke(null, new object[2] { a, b }); } return a; } private static object MakeItemUseId(object player, object itemType) { Type type = AccessTools.TypeByName("ItemUseId"); if (type == null) { return null; } ulong num = 0uL; Type type2 = AccessTools.TypeByName("bft_mod.GameUtils"); MethodInfo methodInfo = ((type2 == null) ? null : AccessTools.Method(type2, "GetPlayerGUID", (Type[])null, (Type[])null)); if (methodInfo != null) { object obj = ((methodInfo.GetParameters().Length == 0) ? methodInfo.Invoke(null, null) : methodInfo.Invoke(null, new object[1] { player })); if (obj != null) { num = Convert.ToUInt64(obj); } } ConstructorInfo constructor = type.GetConstructor(new Type[4] { typeof(ulong), typeof(int), itemType.GetType(), typeof(bool) }); if (constructor != null) { return constructor.Invoke(new object[4] { num, Bootstrap.OverflowIndex++, itemType, false }); } ConstructorInfo constructor2 = type.GetConstructor(new Type[3] { typeof(ulong), typeof(int), itemType.GetType() }); if (constructor2 != null) { return constructor2.Invoke(new object[3] { num, Bootstrap.OverflowIndex++, itemType }); } return Activator.CreateInstance(type); } } [HarmonyPatch] internal static class GetCurrentPlayerOverridePatch { private static MethodBase TargetMethod() { Type type = AccessTools.TypeByName("bft_mod.GameUtils"); if (!(type == null)) { return AccessTools.Method(type, "GetCurrentPlayer", (Type[])null, (Type[])null); } return null; } private static void Postfix(ref object __result) { if (Bootstrap.PlayerOverride != null) { __result = Bootstrap.PlayerOverride; } } } [HarmonyPatch] internal static class ClientLocalEventPatch { private static MethodBase TargetMethod() { Type type = AccessTools.TypeByName("bft_mod.InteractiveMod"); if (!(type == null)) { return AccessTools.Method(type, "ProcessEvent", (Type[])null, (Type[])null); } return null; } private static void Postfix(object __instance, object data) { try { if (__instance == null || data == null) { return; } Type type = AccessTools.TypeByName("bft_mod.GameUtils"); MethodInfo methodInfo = ((type == null) ? null : AccessTools.Method(type, "IsHost", (Type[])null, (Type[])null)); if (!(methodInfo != null) || !Convert.ToBoolean(methodInfo.Invoke(null, null))) { MethodInfo methodInfo2 = AccessTools.Method(__instance.GetType(), "ActivateEventLocally", (Type[])null, (Type[])null); if (!(methodInfo2 == null)) { methodInfo2.Invoke(__instance, new object[1] { data }); Bootstrap.RecentLocalEventId = ReadEventId(data); Bootstrap.RecentLocalEventAt = DateTime.UtcNow; Bootstrap.Log("client self: ActivateEventLocally after host relay"); } } } catch (Exception ex) { Bootstrap.Log("client local event error: " + ex); } } internal static string ReadEventId(object data) { if (data == null) { return ""; } PropertyInfo propertyInfo = AccessTools.Property(data.GetType(), "EventID"); if (propertyInfo == null) { propertyInfo = AccessTools.Property(data.GetType(), "EventId"); } object obj = ((propertyInfo == null) ? null : propertyInfo.GetValue(data, null)); if (obj != null) { return Convert.ToString(obj); } return ""; } } [HarmonyPatch] internal static class SkipDuplicateClientLocalPatch { private static MethodBase TargetMethod() { Type type = AccessTools.TypeByName("bft_mod.InteractiveMod"); if (!(type == null)) { return AccessTools.Method(type, "ActivateEventLocally", (Type[])null, (Type[])null); } return null; } private static bool Prefix(object data) { try { Type type = AccessTools.TypeByName("bft_mod.GameUtils"); MethodInfo methodInfo = ((type == null) ? null : AccessTools.Method(type, "IsHost", (Type[])null, (Type[])null)); if (methodInfo != null && Convert.ToBoolean(methodInfo.Invoke(null, null))) { return true; } string text = ClientLocalEventPatch.ReadEventId(data); if (string.IsNullOrEmpty(text) || text != Bootstrap.RecentLocalEventId) { return true; } if ((DateTime.UtcNow - Bootstrap.RecentLocalEventAt).TotalSeconds > 6.0) { return true; } string stackTrace = Environment.StackTrace; if (stackTrace.IndexOf("ProcessNetworkEvents_OnClientSide") >= 0) { Bootstrap.Log("client self: skip duplicate ActivateEventLocally from host chat"); return false; } } catch { } return true; } } [HarmonyPatch] internal static class HostRemoteEventTargetPatch { private static MethodBase TargetMethod() { Type type = AccessTools.TypeByName("bft_mod.Services.ChaosModNetwork"); if (!(type == null)) { return AccessTools.Method(type, "ProcessNetworkEvents_OnHostSide", (Type[])null, (Type[])null); } return null; } private static void Prefix() { try { Type type = AccessTools.TypeByName("bft_mod.Services.ChaosModNetwork"); FieldInfo fieldInfo = ((type == null) ? null : AccessTools.Field(type, "commandQueue")); object obj = ((fieldInfo == null) ? null : fieldInfo.GetValue(null)); if (obj == null) { return; } MethodInfo methodInfo = AccessTools.Method(obj.GetType(), "Peek", (Type[])null, (Type[])null); object obj2 = ((methodInfo == null) ? null : methodInfo.Invoke(obj, null)); if (obj2 == null) { return; } FieldInfo fieldInfo2 = AccessTools.Field(obj2.GetType(), "playerID"); if (!(fieldInfo2 == null)) { ulong num = (Bootstrap.RemoteEventPlayerId = Convert.ToUInt64(fieldInfo2.GetValue(obj2))); Bootstrap.SuppressHostLocalEvent = false; if (Bootstrap.IsRemoteEventForOtherPlayer()) { Type type2 = AccessTools.TypeByName("bft_mod.GameUtils"); MethodInfo methodInfo2 = ((type2 == null) ? null : AccessTools.Method(type2, "GetPlayerByNetworkID", (Type[])null, (Type[])null)); object obj3 = (Bootstrap.PlayerOverride = ((methodInfo2 == null) ? null : methodInfo2.Invoke(null, new object[1] { num }))); Bootstrap.SuppressHostLocalEvent = true; Bootstrap.Log("host remote event target guid=" + num + " player=" + ((obj3 == null) ? "null" : obj3.ToString())); } } } catch (Exception ex) { Bootstrap.Log("host remote event prefix: " + ex); } } private static void Postfix() { Bootstrap.ClearRemoteEventTarget(); } } [HarmonyPatch] internal static class HostSkipRemoteLocalPatch { private static MethodBase TargetMethod() { Type type = AccessTools.TypeByName("bft_mod.InteractiveMod"); if (!(type == null)) { return AccessTools.Method(type, "ActivateEventLocally", (Type[])null, (Type[])null); } return null; } private static bool Prefix() { if (!Bootstrap.SuppressHostLocalEvent) { return true; } Bootstrap.Log("host skip local apply — event is for another player"); return false; } } [HarmonyPatch] internal static class NarrowAllPlayersToTriggerPatch { private static MethodBase TargetMethod() { Type type = AccessTools.TypeByName("bft_mod.Services.ChaosModNetwork"); if (!(type == null)) { return AccessTools.Method(type, "ApplyCommandsHostEffectsForOthers", (Type[])null, (Type[])null); } return null; } private static void Prefix(ref ulong targetPlayerID) { if (Bootstrap.IsRemoteEventForOtherPlayer() && targetPlayerID == ulong.MaxValue) { targetPlayerID = Bootstrap.RemoteEventPlayerId; Bootstrap.Log("narrow all-players host effects to trigger guid=" + targetPlayerID); } } } [HarmonyPatch] internal static class GiveItemSelfPatch { private static MethodBase TargetMethod() { Type type = AccessTools.TypeByName("bft_mod.Commands.GiveItem"); if (!(type == null)) { return AccessTools.Method(type, "Execute", (Type[])null, (Type[])null); } return null; } private static bool Prefix(object __instance, IEnumerable args, ref bool __result) { try { Type type = AccessTools.TypeByName("bft_mod.GameUtils"); MethodInfo methodInfo = ((type == null) ? null : AccessTools.Method(type, "IsHost", (Type[])null, (Type[])null)); if (methodInfo == null || !Convert.ToBoolean(methodInfo.Invoke(null, null))) { return true; } object obj = Bootstrap.PlayerForRemoteOrLocal(); MethodInfo methodInfo2 = AccessTools.Method(__instance.GetType(), "ExecuteHostAction", (Type[])null, (Type[])null); if (methodInfo2 == null || obj == null) { return true; } object obj2 = methodInfo2.Invoke(__instance, new object[2] { args, obj }); __result = obj2 == null || Convert.ToBoolean(obj2); return false; } catch (Exception ex) { Bootstrap.Log("GiveItem self execute: " + ex); return true; } } } [HarmonyPatch] internal static class MinesSurroundSelfPatch { private static MethodBase TargetMethod() { Type type = AccessTools.TypeByName("bft_mod.Commands.MinesSurround"); if (!(type == null)) { return AccessTools.Method(type, "Execute", (Type[])null, (Type[])null); } return null; } private static bool Prefix(object __instance, IEnumerable args, ref bool __result) { try { Type type = AccessTools.TypeByName("bft_mod.GameUtils"); MethodInfo methodInfo = ((type == null) ? null : AccessTools.Method(type, "IsHost", (Type[])null, (Type[])null)); if (methodInfo == null || !Convert.ToBoolean(methodInfo.Invoke(null, null))) { return true; } object obj = Bootstrap.PlayerForRemoteOrLocal(); MethodInfo methodInfo2 = AccessTools.Method(__instance.GetType(), "ExecuteHostAction", (Type[])null, (Type[])null); if (methodInfo2 == null || obj == null) { return true; } object obj2 = methodInfo2.Invoke(__instance, new object[2] { args, obj }); __result = obj2 == null || Convert.ToBoolean(obj2); Bootstrap.Log("mines_surround self execute"); return false; } catch (Exception ex) { Bootstrap.Log("mines_surround self execute: " + ex); return true; } } } [HarmonyPatch] internal static class HostApplyOthersLocalCommandsPatch { private static MethodBase TargetMethod() { Type type = AccessTools.TypeByName("bft_mod.Services.ChaosModNetwork"); if (!(type == null)) { return AccessTools.Method(type, "ApplyCommandsHostEffectsForOthers", (Type[])null, (Type[])null); } return null; } private static void Postfix(string[] eventCommands, ulong targetPlayerID, object commands) { if (eventCommands == null || commands == null) { return; } try { Type type = AccessTools.TypeByName("bft_mod.GameUtils"); MethodInfo methodInfo = ((type == null) ? null : AccessTools.Method(type, "GetPlayerByNetworkID", (Type[])null, (Type[])null)); object obj = ((methodInfo == null) ? null : methodInfo.Invoke(null, new object[1] { targetPlayerID })); if (obj == null) { return; } Type type2 = AccessTools.TypeByName("bft_mod.Commands.Interfaces.IHostNetworkCommand"); PropertyInfo property = commands.GetType().GetProperty("Item"); Bootstrap.PlayerOverride = obj; foreach (string text in eventCommands) { if (string.IsNullOrEmpty(text)) { continue; } string[] array = text.Trim().Split(new char[1] { ' ' }, StringSplitOptions.RemoveEmptyEntries); if (array.Length == 0) { continue; } object obj2 = null; try { obj2 = ((property == null) ? null : property.GetValue(commands, new object[1] { array[0] })); } catch { obj2 = null; } if (obj2 == null || (type2 != null && type2.IsInstanceOfType(obj2))) { continue; } MethodInfo methodInfo2 = AccessTools.Method(obj2.GetType(), "Execute", (Type[])null, (Type[])null); if (methodInfo2 != null) { List list = new List(); for (int j = 1; j < array.Length; j++) { list.Add(array[j]); } methodInfo2.Invoke(obj2, new object[1] { list }); } } } catch (Exception ex) { Bootstrap.Log("host apply others local cmds: " + ex); } finally { Bootstrap.PlayerOverride = null; } } } [HarmonyPatch] internal static class TryAddOverflowPatch { private static IEnumerable TargetMethods() { List list = new List(); Type type = AccessTools.TypeByName("PlayerInventory"); if (type == null) { Bootstrap.Log("overflow: PlayerInventory type missing"); return list; } MethodInfo[] methods = type.GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); for (int i = 0; i < methods.Length; i++) { if (methods[i].Name == "ServerTryAddItem") { list.Add(methods[i]); Bootstrap.Log("overflow: will patch ServerTryAddItem argc=" + methods[i].GetParameters().Length); } } if (list.Count == 0) { for (int i = 0; i < methods.Length; i++) { if (methods[i].Name == "CmdAddItem") { list.Add(methods[i]); Bootstrap.Log("overflow: will patch CmdAddItem argc=" + methods[i].GetParameters().Length); } } } if (list.Count > 0) { Bootstrap.TryAddPatched = true; } return list; } private static void Prefix(object __instance, ref int __state) { __state = ((__instance == null) ? (-1) : InventoryUtil.CountOccupied(__instance)); } private static void Postfix(object __instance, object[] __args, int __state) { try { if (__instance != null && __state >= 0) { int num = InventoryUtil.CountOccupied(__instance); if (num <= __state && InventoryUtil.CountFree(__instance) <= 0) { Bootstrap.Log("overflow: bag full (" + num + " occupied) dropping extra on ground"); GiveItemOverflowPatch.SpawnFromAddArgs(__instance, __args); } } } catch (Exception ex) { Bootstrap.Log("overflow tryadd error: " + ex); } } } internal static class ConfigNotifyPatch { internal static void Postfix(object[] __args) { if (__args == null) { return; } for (int i = 0; i < __args.Length; i++) { string text = __args[i] as string; if (!string.IsNullOrEmpty(text)) { Bootstrap.ApplyConfigJson(text); } } } } [HarmonyPatch] internal static class NotifySkipLogoPatch { private static MethodBase TargetMethod() { Type type = AccessTools.TypeByName("ModHelperUnity.TypedNotify"); if (type == null) { type = AccessTools.TypeByName("TypedNotify"); } if (type == null) { return null; } MethodInfo methodInfo = AccessTools.Method(type, "LoadImage", (Type[])null, (Type[])null); if (methodInfo == null) { type = AccessTools.TypeByName("ModHelperUnity.TypedNotifyBase"); methodInfo = ((type == null) ? null : AccessTools.Method(type, "LoadImage", (Type[])null, (Type[])null)); } return methodInfo; } private static bool Prefix() { return false; } } [HarmonyPatch] internal static class NotifyGateQueuePatch { private static MethodBase TargetMethod() { Type type = AccessTools.TypeByName("ModHelperUnity.TypedNotify"); if (type == null) { type = AccessTools.TypeByName("TypedNotify"); } if (!(type == null)) { return AccessTools.Method(type, "AddNotifyToQueue", (Type[])null, (Type[])null); } return null; } private static bool Prefix() { return Bootstrap.InGameNotify; } } [HarmonyPatch] internal static class NotifyGateGuiPatch { private static MethodBase TargetMethod() { Type type = AccessTools.TypeByName("ModHelperUnity.TypedNotify"); if (type == null) { type = AccessTools.TypeByName("TypedNotify"); } MethodInfo methodInfo = ((type == null) ? null : AccessTools.Method(type, "TypedNotifyOnGUI", (Type[])null, (Type[])null)); if (methodInfo == null && type != null) { methodInfo = AccessTools.Method(type, "OnGUI", (Type[])null, (Type[])null); } return methodInfo; } private static bool Prefix() { return Bootstrap.InGameNotify; } } internal static class ItemFx { private static bool dumpedInv; internal static void TryApply(string eventId) { if (!Bootstrap.SuppressHostLocalEvent && !string.IsNullOrEmpty(eventId)) { switch (eventId) { case "buff_eat_burger": UseHeld("JumboBurger", new string[1] { "EatJumboBurgerRoutine" }); break; case "debuff_invis_smoke": UseHeld("SmokeBomb", new string[2] { "ThrowSmokeBombRoutine", "SmokeBombInvisibilityRoutine" }); break; case "debuff_lightning_storm": UseHeld("Thunderstorm", new string[2] { "UseThunderstormRoutine", "UseThunderStormRoutine" }); break; case "buff_flash_pop": UseHeld("FlashCamera", new string[1] { "UseFlashCameraRoutine" }); break; } } } private static void DumpInv(object inv) { if (dumpedInv || inv == null) { return; } dumpedInv = true; try { Type type = inv.GetType(); MethodInfo[] methods = type.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); for (int i = 0; i < methods.Length; i++) { string name = methods[i].Name; if (name.IndexOf("Slot", StringComparison.OrdinalIgnoreCase) >= 0 || name.IndexOf("Select", StringComparison.OrdinalIgnoreCase) >= 0 || name.IndexOf("Use", StringComparison.OrdinalIgnoreCase) >= 0 || name.IndexOf("Item", StringComparison.OrdinalIgnoreCase) >= 0) { Bootstrap.Log("inv method " + methods[i]); } } } catch (Exception ex) { Bootstrap.Log("inv dump: " + ex.Message); } } private static void GiveByName(object player, object inv, string itemName) { object obj = InventoryUtil.ParseItemType(itemName); if (inv != null && obj != null) { try { MethodInfo methodInfo = AccessTools.Method(inv.GetType(), "ServerTryAddItem", (Type[])null, (Type[])null); if (methodInfo != null) { ParameterInfo[] parameters = methodInfo.GetParameters(); object[] array = new object[parameters.Length]; for (int i = 0; i < parameters.Length; i++) { Type parameterType = parameters[i].ParameterType; if (parameterType.IsEnum && parameterType.Name.IndexOf("Item") >= 0) { array[i] = obj; } else if (parameterType == typeof(int)) { array[i] = 1; } else if (parameterType.IsValueType) { array[i] = Activator.CreateInstance(parameterType); } else { array[i] = null; } } methodInfo.Invoke(inv, array); Bootstrap.Log("itemfx ServerTryAddItem " + obj); return; } MethodInfo methodInfo2 = AccessTools.Method(inv.GetType(), "CmdAddItem", new Type[1] { obj.GetType() }, (Type[])null); if (methodInfo2 != null) { methodInfo2.Invoke(inv, new object[1] { obj }); Bootstrap.Log("itemfx CmdAddItem " + obj); return; } } catch (Exception ex) { Bootstrap.Log("itemfx add: " + ex.Message); } } try { Type type = AccessTools.TypeByName("bft_mod.Commands.GiveItem"); if (!(type == null) && player != null) { object obj2 = Activator.CreateInstance(type); MethodInfo methodInfo3 = AccessTools.Method(type, "ExecuteHostAction", (Type[])null, (Type[])null); if (!(methodInfo3 == null) && obj2 != null) { List list = new List(); list.Add(InventoryUtil.AliasItemName(itemName)); methodInfo3.Invoke(obj2, new object[2] { list, player }); Bootstrap.Log("itemfx give " + InventoryUtil.AliasItemName(itemName)); } } } catch (Exception ex2) { Bootstrap.Log("itemfx give error: " + ex2.Message); } } private static void DumpSlotPeek(object inv, string itemName) { try { MethodInfo methodInfo = AccessTools.Method(inv.GetType(), "GetEffectiveSlot", new Type[1] { typeof(int) }, (Type[])null); int slotCount = InventoryUtil.GetSlotCount(inv); for (int i = 0; i < slotCount; i++) { object obj = ((methodInfo == null) ? null : methodInfo.Invoke(inv, new object[1] { i })); object obj2 = InventoryUtil.ReadItemType(obj); Bootstrap.Log("itemfx peek slot " + i + " entry=" + ((obj == null) ? "null" : obj.GetType().Name) + " type=" + ((obj2 == null) ? "null" : obj2.ToString())); if (obj != null && obj2 == null) { FieldInfo[] fields = obj.GetType().GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); for (int j = 0; j < fields.Length && j < 12; j++) { object value = fields[j].GetValue(obj); Bootstrap.Log(" field " + fields[j].Name + "=" + ((value == null) ? "null" : value.ToString())); } } } } catch (Exception ex) { Bootstrap.Log("itemfx peek: " + ex.Message); } } private static void UseHeld(string itemName, string[] routines) { object obj = InventoryUtil.ResolvePlayer(null); if (obj == null) { Bootstrap.Log("itemfx: no player for " + itemName); return; } object inventory = InventoryUtil.GetInventory(obj); if (inventory == null) { Bootstrap.Log("itemfx: no inventory"); return; } DumpInv(inventory); int num = InventoryUtil.FindSlotByItemName(inventory, itemName); if (num < 0) { if (InventoryUtil.CountFree(inventory) <= 0) { InventoryUtil.FreeLastOccupied(inventory); } GiveByName(obj, inventory, itemName); num = InventoryUtil.FindSlotByItemName(inventory, itemName); } if (num < 0) { Bootstrap.Log("itemfx: no slot for " + itemName); DumpSlotPeek(inventory, itemName); return; } if (!InventoryUtil.SelectSlot(inventory, num)) { Bootstrap.Log("itemfx: could not select slot " + num); } else { Bootstrap.Log("itemfx equipped slot " + num + " for " + itemName); } bool flag = TryUseSelected(inventory); for (int i = 0; i < routines.Length; i++) { if (StartRoutine(inventory, routines[i])) { Bootstrap.Log("itemfx routine " + routines[i]); flag = true; } } if (!flag) { Bootstrap.Log("itemfx use failed for " + itemName); } } private static bool TryUseSelected(object inv) { try { MethodInfo[] methods = inv.GetType().GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); for (int i = 0; i < methods.Length; i++) { if (methods[i].Name != "TryUseItem") { continue; } ParameterInfo[] parameters = methods[i].GetParameters(); object[] array = new object[parameters.Length]; for (int j = 0; j < parameters.Length; j++) { Type parameterType = parameters[j].ParameterType; if (parameterType == typeof(bool) || parameterType == typeof(bool).MakeByRefType()) { array[j] = j == 0; } else if (parameterType.IsByRef) { Type elementType = parameterType.GetElementType(); array[j] = ((elementType != null && elementType.IsValueType) ? Activator.CreateInstance(elementType) : null); } else if (parameterType.IsValueType) { array[j] = Activator.CreateInstance(parameterType); } else { array[j] = null; } } object obj = methods[i].Invoke(inv, array); bool flag = obj == null || Convert.ToBoolean(obj); Bootstrap.Log("itemfx TryUseItem argc=" + parameters.Length + " ok=" + flag); return flag; } } catch (Exception ex) { Bootstrap.Log("itemfx TryUseItem: " + ex.Message); } return false; } private static bool StartRoutine(object inv, string name) { try { MethodInfo methodInfo = FindMethod(inv.GetType(), "StartCoroutine", new Type[1] { typeof(string) }); if (methodInfo != null) { methodInfo.Invoke(inv, new object[1] { name }); return true; } } catch (Exception ex) { Bootstrap.Log("itemfx StartCoroutine(string) " + name + ": " + ex.Message); } try { MethodInfo methodInfo2 = AccessTools.Method(inv.GetType(), name, (Type[])null, (Type[])null); if (methodInfo2 == null) { return false; } ParameterInfo[] parameters = methodInfo2.GetParameters(); object[] array = new object[parameters.Length]; for (int i = 0; i < parameters.Length; i++) { Type parameterType = parameters[i].ParameterType; if (parameterType == typeof(bool)) { array[i] = true; } else if (parameterType.IsValueType) { array[i] = Activator.CreateInstance(parameterType); } else { array[i] = null; } } object obj = methodInfo2.Invoke(inv, array); if (!(obj is IEnumerator enumerator)) { return obj != null; } MethodInfo methodInfo3 = FindMethod(inv.GetType(), "StartCoroutine", new Type[1] { typeof(IEnumerator) }); if (methodInfo3 == null) { return false; } methodInfo3.Invoke(inv, new object[1] { enumerator }); return true; } catch (Exception ex2) { Bootstrap.Log("itemfx StartRoutine " + name + ": " + ex2.Message); return false; } } private static MethodInfo FindMethod(Type type, string name, Type[] args) { Type type2 = type; while (type2 != null) { MethodInfo methodInfo = AccessTools.Method(type2, name, args, (Type[])null); if (methodInfo != null) { return methodInfo; } type2 = type2.BaseType; } return null; } } [HarmonyPatch] internal static class ItemUseEffectPatch { private static MethodBase TargetMethod() { Type type = AccessTools.TypeByName("bft_mod.InteractiveMod"); if (!(type == null)) { return AccessTools.Method(type, "ActivateEventLocally", (Type[])null, (Type[])null); } return null; } private static void Postfix(object data) { try { string eventId = ClientLocalEventPatch.ReadEventId(data); ItemFx.TryApply(eventId); } catch (Exception ex) { Bootstrap.Log("itemfx postfix: " + ex); } } } [BepInPlugin("tokcontrol.battlegolf", "TokControl Battle Golf Patches", "1.2.9")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class BepInExPlugin : BaseUnityPlugin { private void Awake() { Bootstrap.Init(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"TokControl Battle Golf patches loaded"); } }