Decompiled source of MaxAxe v0.5.6
MaxAxe.dll
Decompiled 2 months ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using HarmonyLib; using TMPro; using UnityEngine; using UnityEngine.Rendering; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("MaxAxe")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("MaxAxe")] [assembly: AssemblyCopyright("Copyright © 2022")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("9f8a1b6e-6d0e-4dab-bbd8-9ed433836544")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] internal sealed class ConfigurationManagerAttributes { public delegate void CustomHotkeyDrawerFunc(ConfigEntryBase setting, ref bool isCurrentlyAcceptingInput); public bool? ShowRangeAsPercent; public Action<ConfigEntryBase> CustomDrawer; public CustomHotkeyDrawerFunc CustomHotkeyDrawer; public bool? Browsable; public string Category; public object DefaultValue; public bool? HideDefaultButton; public bool? HideSettingName; public string Description; public string DispName; public int? Order; public bool? ReadOnly; public bool? IsAdvanced; public Func<object, string> ObjToStr; public Func<string, object> StrToObj; } namespace neobotics.ValheimMods; public class ConfigMock { public bool Value { get; set; } } internal class CustomDataWrapper { private Dictionary<string, string> playerData; private CustomDataWrapper instance; private Dictionary<string, string> Data { get; set; } public CustomDataWrapper(Dictionary<string, string> sourceData, string keyPrefix) { CustomDataWrapper customDataWrapper = this; playerData = sourceData; Data = new Dictionary<string, string>(); sourceData.Keys.ToList().ForEach(delegate(string key) { if (key.StartsWith(keyPrefix)) { customDataWrapper.Data.Add(key, sourceData[key]); } }); } public void Add(string key, string value) { Data.Add(key, value); playerData.Add(key, value); } public bool Remove(string key) { return Data.Remove(key) & playerData.Remove(key); } public void Set(string key, string value) { if (Data.ContainsKey(key)) { Data[key] = value; } else { Data.Add(key, value); } if (playerData.ContainsKey(key)) { playerData[key] = value; } else { playerData.Add(key, value); } } public string Get(string key) { if (Data.ContainsKey(key)) { return Data[key]; } return null; } public bool ContainsKey(string key) { return Data.ContainsKey(key); } public void PreSaveSync() { foreach (KeyValuePair<string, string> datum in Data) { if (!playerData.ContainsKey(datum.Key)) { playerData.Add(datum.Key, datum.Value); } } } } internal class CustomSkill { [HarmonyPatch(typeof(Skills), "Load")] private static class Skills_Load_Patch { private static void Prefix(Skills __instance) { //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Expected O, but got Unknown if (__instance?.m_skills != null && cSkillDef != null && !__instance.m_skills.Contains(cSkillDef)) { Logging.GetLogger().Debug("Adding custom skill definition"); Sprite prefabIcon = Utils.GetPrefabIcon(cIconPrefab); if ((Object)(object)prefabIcon != (Object)null) { cSkillDef.m_icon = prefabIcon; } cSkill = new Skill(cSkillDef); __instance.m_skills.Add(cSkillDef); } } private static void Postfix(Skills __instance, Dictionary<SkillType, Skill> ___m_skillData) { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) if (__instance?.m_skills == null || ___m_skillData == null || cSkillDef == null) { return; } Logging.GetLogger().Debug("Skills Load Postfix"); if (!___m_skillData.ContainsKey(cSkillType)) { Logging.GetLogger().Debug("No custom skill in the player profile"); if (Cfg.useSkill.Value) { Logging.GetLogger().Debug("Adding custom skill to player profile"); cSkill.m_accumulator = 0f; cSkill.m_level = 0f; ___m_skillData.Add(cSkillType, cSkill); } } else { cSkill = ___m_skillData[cSkillType]; Logging.GetLogger().Debug("Custom skill is already in the player profile"); if (!Cfg.useSkill.Value) { Logging.GetLogger().Debug("...but it's not enabled"); ___m_skillData.Remove(cSkillType); } } } } [HarmonyPatch(typeof(Skills), "Save")] private static class Skills_Save_Patch { private static void Prefix(Skills __instance, ZPackage pkg, Dictionary<SkillType, Skill> ___m_skillData) { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)__instance == (Object)null) && ___m_skillData != null && ___m_skillData.Count != 0) { Logging.GetLogger().Debug("Skills Save Prefix"); if (!___m_skillData.ContainsKey(cSkillType)) { Logging.GetLogger().Debug("Saving custom skill"); ___m_skillData.Add(cSkillType, cSkill); } string value = $"{cSkill.m_level}:{cSkill.m_accumulator}"; if (__instance.m_player.m_customData.ContainsKey(saveName)) { __instance.m_player.m_customData[saveName] = value; } else { __instance.m_player.m_customData.Add(saveName, value); } } } private static void Postfix(Skills __instance, ZPackage pkg, Dictionary<SkillType, Skill> ___m_skillData) { //IL_0040: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)__instance == (Object)null) && ___m_skillData != null && ___m_skillData.Count != 0) { Logging.GetLogger().Debug("Skills Save Postfix"); if (!Cfg.useSkill.Value) { Logging.GetLogger().Debug("Removing disabled custom skill from the player profile"); ___m_skillData.Remove(cSkillType); } } } } [HarmonyPatch(typeof(Skills), "RaiseSkill")] private static class Skills_RaiseSkill_Patch { [HarmonyPrefix] private static void Skills_RaiseSkill_Prefix(Skills __instance, ref SkillType skillType, float factor) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Invalid comparison between I4 and Unknown if ((int)skillType == (int)cSkillType && !Cfg.useSkill.Value) { skillType = (SkillType)0; } } } [HarmonyPatch(typeof(Skills), "IsSkillValid")] private static class Skills_IsSkillValid_Patch { private static void Postfix(ref bool __result, SkillType type) { //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) if (!__result && type == cSkillType) { Logging.GetLogger().Debug("Skill type matches custom skill"); __result = true; } } } [HarmonyPatch(typeof(Skills), "CheatRaiseSkill")] private static class Skills_CheatRaiseSkill_Patch { private static bool Prefix(Skills __instance, string name, float value, Dictionary<SkillType, Skill> ___m_skillData) { //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Expected I4, but got Unknown Logging.GetLogger().Debug("Skills CheatRaiseSkill Prefix"); if (Cfg.useSkill.Value && name.ToLower().Equals(cSkillName.ToLower()) && ___m_skillData.TryGetValue(cSkillType, out var value2)) { Logging.GetLogger().Debug($"Skill {value2.m_info} found"); Skill obj = value2; obj.m_level += value; value2.m_level = Mathf.Clamp(value2.m_level, 0f, 100f); if (__instance.m_useSkillCap) { __instance.RebalanceSkills(cSkillType); } if (value2.m_info != null) { ((Character)Player.m_localPlayer).Message((MessageType)1, $"Skill increased {Utils.GetTranslated((int)value2.m_info.m_skill)}: {(int)value2.m_level}", 0, (Sprite)null); Console.instance.Print($"Skill {cSkillName} = {value2.m_level}"); } return false; } return true; } } [HarmonyPatch(typeof(Skills), "CheatResetSkill")] private static class Skills_CheatResetSkill_Patch { private static bool Prefix(string name, Skills __instance, Dictionary<SkillType, Skill> ___m_skillData) { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Expected I4, but got Unknown Logging.GetLogger().Debug("Skills CheatResetSkill Prefix"); if (Cfg.useSkill.Value && name.ToLower().Equals(cSkillName.ToLower())) { if (___m_skillData.TryGetValue(cSkillType, out var value)) { value.m_accumulator = 0f; value.m_level = 0f; } Console.instance.Print("Skill " + Utils.GetTranslated((int)value.m_info.m_skill) + " reset"); return false; } return true; } } [HarmonyPatch(typeof(SkillsDialog), "Setup")] private static class SkillsDialog_Setup_Patch { private static void Postfix(Player player, ref List<GameObject> ___m_elements) { Logging logger = Logging.GetLogger(); logger.Debug("SkillsDialog Setup Postfix"); if (!Cfg.useSkill.Value) { return; } object obj; if (player == null) { obj = null; } else { Skills skills = ((Character)player).GetSkills(); obj = ((skills != null) ? skills.GetSkillList() : null); } List<Skill> list = (List<Skill>)obj; if (list == null) { logger.Debug("Can't get player skill list"); return; } int num = list.FindIndex((Skill s) => s.m_info == cSkillDef); if (num < 0) { logger.Debug("Can't find custom skill"); return; } GameObject val = ___m_elements[num]; if ((Object)(object)val == (Object)null) { logger.Debug("Skill game object is null"); return; } Transform obj2 = Utils.FindChild(val.transform, "name"); object obj3; if (obj2 == null) { obj3 = null; } else { Text component = ((Component)obj2).GetComponent<Text>(); obj3 = ((component != null) ? component.text : null); } if (obj3 == null) { logger.Debug("Can't find and set custom skill text"); } else { _ = cSkillName; } } } public static SkillType cSkillType = (SkillType)0; public static SkillDef cSkillDef = null; public static Skill cSkill = null; private static string cSkillName = ""; private static string cIconPrefab = null; private static string saveName; public static SkillType GetCustomSkillType() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) return cSkillType; } public static SkillDef GetCustomSkillDef() { return cSkillDef; } public static Skill GetCustomSkill() { return cSkill; } public static void CheckForPreExistingCustomSkill(Player player) { if (cSkill == null || cSkill.m_level != 0f || cSkill.m_accumulator != 0f) { return; } Logging.GetLogger().Debug("Looking for pre-existing skill"); if (player.m_customData.TryGetValue(saveName, out var value)) { Logging.GetLogger().Debug("Found pre-existing skill values"); string[] array = value.Split(new char[1] { ':' }); if (array.Length == 2 && float.TryParse(array[0], out var result) && float.TryParse(array[1], out var result2)) { cSkill.m_level = result; cSkill.m_accumulator = result2; } } } public static void ToggleCustomSkill(bool enable) { //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) Player localPlayer = Player.m_localPlayer; Skills val = ((localPlayer != null) ? ((Character)localPlayer).GetSkills() : null); if ((Object)(object)val == (Object)null) { return; } Dictionary<SkillType, Skill> skillData = val.m_skillData; if (skillData == null) { return; } if (enable) { if (skillData.ContainsKey(cSkillType)) { skillData[cSkillType] = cSkill; } else { skillData.Add(cSkillType, cSkill); } } else { skillData.Remove(cSkillType); } } public static void ConfigureSkillDef(string name, string descrip, string iconPrefabName) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Expected O, but got Unknown //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) int num = Math.Abs(StringExtensionMethods.GetStableHashCode(name)); cSkillType = (SkillType)num; cSkillDef = new SkillDef(); cSkillDef.m_description = descrip; cSkillDef.m_increseStep = 1f; cSkillDef.m_skill = cSkillType; cSkillName = name; cIconPrefab = iconPrefabName; saveName = "NEObotics_" + cSkillName; Utils.SetTranslator(num, name); } } internal class DebugUtils { public static void ObjectInspector(object o) { if (o == null) { Debug.Log((object)"Object is null"); return; } BindingFlags bindingAttr = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic; Type type = o.GetType(); Debug.Log((object)(o.ToString() + " Type " + type.Name)); PropertyInfo[] properties = type.GetProperties(bindingAttr); foreach (PropertyInfo propertyInfo in properties) { Debug.Log((object)$"{type.Name}.{propertyInfo.Name} = {propertyInfo.GetValue(o)}"); } FieldInfo[] fields = type.GetFields(bindingAttr); foreach (FieldInfo field in fields) { FieldPrinter(o, type, field); } } public static void MethodInspector(object o) { if (o == null) { Debug.Log((object)"Object is null"); return; } BindingFlags bindingAttr = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic; Type type = o.GetType(); Debug.Log((object)(o.ToString() + " Type " + type.Name)); MethodInfo[] methods = type.GetMethods(bindingAttr); foreach (MethodInfo methodInfo in methods) { methodInfo.GetParameters(); string arg = string.Join(", ", (from x in methodInfo.GetParameters() select x.ParameterType?.ToString() + " " + x.Name).ToArray()); Debug.Log((object)$"{methodInfo.ReturnType} {methodInfo.Name} ({arg})"); } } private static void ItemDataInspector(ItemData item) { ObjectInspector(item); ObjectInspector(item.m_shared); } private static void FieldPrinter(object o, Type t, FieldInfo field) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Expected O, but got Unknown //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Expected O, but got Unknown //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Expected O, but got Unknown try { if (field.FieldType == typeof(ItemData)) { ItemData val = (ItemData)field.GetValue(o); if (val != null) { ItemDataInspector(val); } else { Debug.Log((object)$"{t.Name}.{field.Name} = {field.GetValue(o)} [null]"); } } else if (field.FieldType == typeof(Transform)) { Transform val2 = (Transform)field.GetValue(o); if ((Object)(object)val2 != (Object)null) { Debug.Log((object)("\tTransform.parent = " + ((Object)val2.parent).name)); } else { Debug.Log((object)$"{t.Name}.{field.Name} = {field.GetValue(o)} [null]"); } } else if (field.FieldType == typeof(EffectList)) { EffectList val3 = (EffectList)field.GetValue(o); if (val3 != null) { Debug.Log((object)$"{t.Name}.{field.Name} = {field.GetValue(o)}:"); EffectData[] effectPrefabs = val3.m_effectPrefabs; foreach (EffectData val4 in effectPrefabs) { Debug.Log((object)("\tEffectData.m_prefab = " + ((Object)val4.m_prefab).name)); } } else { Debug.Log((object)$"{t.Name}.{field.Name} = {field.GetValue(o)} [null]"); } } else { Debug.Log((object)$"{t.Name}.{field.Name} = {field.GetValue(o)}"); } } catch (Exception) { Debug.Log((object)("Exception accessing " + t?.Name + "." + field?.Name)); } } public static void GameObjectInspector(GameObject go) { Debug.Log((object)("\n\nInspecting GameObject " + ((Object)go).name)); ObjectInspector(go); Component[] componentsInChildren = go.GetComponentsInChildren<Component>(); foreach (Component val in componentsInChildren) { try { string obj = ((val != null) ? ((Object)val).name : null); object obj2; if (val == null) { obj2 = null; } else { Transform transform = val.transform; if (transform == null) { obj2 = null; } else { Transform parent = transform.parent; obj2 = ((parent != null) ? ((Object)parent).name : null); } } Debug.Log((object)("\n\nInspecting Component " + obj + " with parent " + (string?)obj2)); ObjectInspector(val); } catch (Exception) { } } } public static void PrintList<T>(List<T> l) { foreach (T item in l) { Debug.Log((object)item.ToString()); } } public static void ComponentInspector(Component c) { Debug.Log((object)("\n\nInspecting Component " + ((Object)c).name)); ObjectInspector(c); } public static void EffectsInspector(EffectList e) { EffectData[] effectPrefabs = e.m_effectPrefabs; Debug.Log((object)$"Effect list has effects {e.HasEffects()} count {effectPrefabs.Length}"); EffectData[] array = effectPrefabs; foreach (EffectData val in array) { Debug.Log((object)$"Effect Data {val} prefab name {((Object)val.m_prefab).name} prefab GameObject name {((Object)val.m_prefab.gameObject).name}"); } } public static void PrintInventory() { foreach (ItemData allItem in ((Humanoid)Player.m_localPlayer).GetInventory().GetAllItems()) { Debug.Log((object)allItem.m_shared.m_name); } } public static void PrintAllObjects() { ZNetScene.instance.m_prefabs.ForEach(delegate(GameObject x) { Debug.Log((object)("GameObject " + ((Object)x).name)); }); } public static void PrintAllCharacters() { Character.GetAllCharacters().ForEach(delegate(Character x) { Debug.Log((object)("Character " + ((Object)x).name)); }); } public static void PrintAllLayers() { string[] array = (from index in Enumerable.Range(0, 31) select LayerMask.LayerToName(index) into l where !string.IsNullOrEmpty(l) select l).ToArray(); foreach (string text in array) { Debug.Log((object)("Layer " + text + " " + Convert.ToString(LayerMask.NameToLayer(text), 2).PadLeft(32, '0'))); } } } public class DelegatedConfigEntry<T> : DelegatedConfigEntryBase { private ConfigEntry<T> _entry; private EventHandler rootHandler; private Action<object, EventArgs> clientDelegate; private Logging Log; public ConfigEntry<T> ConfigEntry { get { return _entry; } set { _entry = value; if (_entry != null && rootHandler != null) { _entry.SettingChanged += rootHandler; } Name = ((ConfigEntryBase)_entry).Definition.Key; Section = ((ConfigEntryBase)_entry).Definition.Section; ServerValue = ((ConfigEntryBase)_entry).GetSerializedValue(); Log.Trace("Set " + Section + " " + Name + " to serialized value " + ServerValue); } } public T Value { get { return _entry.Value; } set { _entry.Value = value; } } public DelegatedConfigEntry(bool useServerDelegate = false) : this((Action<object, EventArgs>)null, useServerDelegate) { } public DelegatedConfigEntry(Action<object, EventArgs> delegateHandler, bool useServerDelegate = false) { Log = Logging.GetLogger(); Log.Trace("DelegatedConfigEntry"); if (delegateHandler != null) { clientDelegate = delegateHandler; } if (useServerDelegate) { Log.Trace("Configuring server delegate"); rootHandler = delegate(object s, EventArgs e) { ServerDelegate(s, e); }; ServerConfiguration.ServerDelegatedEntries.Add(this); } else if (clientDelegate != null) { rootHandler = delegate(object s, EventArgs e) { clientDelegate(s, e); }; } } private void ServerDelegate(object sender, EventArgs args) { //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Expected O, but got Unknown Logging.GetLogger().Trace("ServerDelegate"); _entry.SettingChanged -= rootHandler; ZNet instance = ZNet.instance; bool? flag = ((instance != null) ? new bool?(instance.IsServer()) : null); if (flag.HasValue) { if (flag == false && ServerConfiguration.Instance.ReceivedServerValues) { if (ServerValue != null) { ((ConfigEntryBase)_entry).SetSerializedValue(ServerValue); Log.Debug("Setting " + Name + " to server value " + ServerValue); } } else if (flag == true) { ServerValue = ((ConfigEntryBase)_entry).GetSerializedValue(); ServerConfiguration.Instance.SendConfigToAllClients(sender, (SettingChangedEventArgs)args); } } if (clientDelegate != null) { clientDelegate(sender, args); } _entry.SettingChanged += rootHandler; } public void EnableHandler(bool setActive) { if (setActive) { _entry.SettingChanged += rootHandler; } else { _entry.SettingChanged -= rootHandler; } } public bool IsKeyPressed() { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) if (ConfigEntry is ConfigEntry<KeyboardShortcut> val) { KeyboardShortcut value = val.Value; foreach (KeyCode modifier in ((KeyboardShortcut)(ref value)).Modifiers) { if (!Input.GetKey(modifier)) { return false; } } if (!Input.GetKeyDown(((KeyboardShortcut)(ref value)).MainKey)) { return false; } return true; } Log.Error("Keyboard read attempted on non-KeyboardShortcut config."); return false; } public bool IsKeyDown() { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) if (ConfigEntry is ConfigEntry<KeyboardShortcut> val) { KeyboardShortcut value = val.Value; foreach (KeyCode modifier in ((KeyboardShortcut)(ref value)).Modifiers) { if (!Input.GetKey(modifier)) { return false; } } if (!Input.GetKey(((KeyboardShortcut)(ref value)).MainKey)) { return false; } return true; } Log.Error("Keyboard read attempted on non-KeyboardShortcut config."); return false; } public bool IsKeyReleased() { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) if (ConfigEntry is ConfigEntry<KeyboardShortcut> val) { KeyboardShortcut value = val.Value; foreach (KeyCode modifier in ((KeyboardShortcut)(ref value)).Modifiers) { if (!Input.GetKeyUp(modifier)) { return false; } } if (!Input.GetKeyUp(((KeyboardShortcut)(ref value)).MainKey)) { return false; } return true; } Log.Error("Keyboard read attempted on non-KeyboardShortcut config."); return false; } } public class DelegatedConfigEntryBase { public string Name; public string Section; public string ServerValue; } internal class HarmonyHelper { public enum PatchType { Prefix, Postfix, Transpiler, Finalizer } private static Dictionary<string, string> detectionSet = new Dictionary<string, string>(); private static Dictionary<string, string> unpatchMods = new Dictionary<string, string>(); public static void GetDetectionSet(Dictionary<string, string> harmonyIds) { Logging logger = Logging.GetLogger(); foreach (KeyValuePair<string, string> harmonyId in harmonyIds) { if (Harmony.HasAnyPatches(harmonyId.Key)) { logger.Debug("Detected " + harmonyId.Value + " from Harmony"); if (!detectionSet.ContainsKey(harmonyId.Key)) { detectionSet.Add(harmonyId.Key, harmonyId.Value); } } else if (Chainloader.PluginInfos.ContainsKey(harmonyId.Key)) { logger.Debug("Detected " + harmonyId.Value + " from BepInEx"); if (!detectionSet.ContainsKey(harmonyId.Key)) { detectionSet.Add(harmonyId.Key, harmonyId.Value); } } } } public static void AddExclusion(string key) { if (detectionSet.ContainsKey(key)) { unpatchMods.Add(key, detectionSet[key]); } } public static void UnpatchMods(Harmony harmony) { Logging logger = Logging.GetLogger(); foreach (KeyValuePair<string, string> unpatchMod in unpatchMods) { logger.Warning("Not compatible with " + unpatchMod.Value); harmony.UnpatchAll(unpatchMod.Key); detectionSet.Remove(unpatchMod.Key); logger.Warning("Disabled " + unpatchMod.Value); } } public static bool IsModDetected(string key) { return detectionSet.ContainsKey(key); } public static bool IsModNameDetected(string value) { return detectionSet.ContainsValue(value); } public static bool TryGetDetectedModName(string key, out string mod) { return detectionSet.TryGetValue(key, out mod); } public static bool TryGetDetectedModKey(string value, out string key) { key = null; foreach (string key2 in detectionSet.Keys) { if (detectionSet[key2] == value) { key = key2; return true; } } return false; } public static string AddAnonymousPatch(string baseMethodName, PatchType patchType, string modName, string patchMethodName = null) { string text = null; int num = 0; Logging logger = Logging.GetLogger(); foreach (MethodBase item in Harmony.GetAllPatchedMethods().ToList()) { MethodBaseExtensions.HasMethodBody(item); Patches patchInfo = Harmony.GetPatchInfo(item); ReadOnlyCollection<Patch> readOnlyCollection = patchInfo.Prefixes; switch (patchType) { case PatchType.Postfix: readOnlyCollection = patchInfo.Postfixes; break; case PatchType.Prefix: readOnlyCollection = patchInfo.Prefixes; break; case PatchType.Transpiler: readOnlyCollection = patchInfo.Transpilers; break; case PatchType.Finalizer: readOnlyCollection = patchInfo.Finalizers; break; } foreach (Patch item2 in readOnlyCollection) { if (!item2.owner.StartsWith("harmony-auto") || !(item.Name == baseMethodName)) { continue; } if (patchMethodName != null) { if (item2.PatchMethod.Name == patchMethodName) { num++; text = item2.owner; } } else { num++; text = item2.owner; } } if (num == 1) { detectionSet.Add(text, modName); logger.Info($"Added unique anonymous {baseMethodName} {patchType}: {text} as {modName}"); } else if (num > 1) { text = null; logger.Warning($"Found multiple anonymous {baseMethodName} {patchType} entries. Can't identify correct patch to remove or modify."); } } if (num == 0) { logger.Info("No patch found for " + modName); } return text; } } public class Logging { public enum LogLevels { Critical, Error, Warning, Info, Debug, Trace } private static Logging _logger; public LogLevels LogLevel { get; set; } public string ModName { get; set; } private Logging(LogLevels level, string name) { LogLevel = level; ModName = name; } public static Logging GetLogger(LogLevels level, string name) { if (_logger == null) { _logger = new Logging(level, name); } return _logger; } public static Logging GetLogger() { if (_logger == null) { throw new NullReferenceException("Logger not initialized"); } return _logger; } public void Trace(string msg) { if (LogLevel >= LogLevels.Trace) { Debug.Log((object)Message(msg)); } } public void Debug(string msg) { if (LogLevel >= LogLevels.Debug) { Debug.Log((object)Message(msg)); } } public void Info(string msg) { if (LogLevel >= LogLevels.Info) { Debug.Log((object)Message(msg)); } } public void Warning(string msg) { if (LogLevel >= LogLevels.Warning) { Debug.LogWarning((object)Message(msg)); } } public void Error(string msg) { if (LogLevel >= LogLevels.Error) { Debug.LogWarning((object)Message(msg)); } } public void Error(Exception e) { Error(e, stackTrace: false); } public void Error(Exception e, bool stackTrace) { if (LogLevel >= LogLevels.Error) { Warning(Message(e.Message)); if (stackTrace) { Warning(e.StackTrace); } } } public void Critical(Exception e) { if (LogLevel >= LogLevels.Critical) { Debug(Message(e.Message)); Error(e.StackTrace); } } private string Message(string msg) { return ModName + ": " + msg; } public static void ChangeLogging(object s, EventArgs e) { SettingChangedEventArgs val = (SettingChangedEventArgs)(object)((e is SettingChangedEventArgs) ? e : null); GetLogger().Debug($"ChangeLog {val.ChangedSetting.Definition.Key} to {val.ChangedSetting.BoxedValue}"); GetLogger().LogLevel = Cfg.debugLevel.Value; } } public class ServerConfiguration { [HarmonyPatch(typeof(ZNet), "StopAll")] private static class ZNet_Shutdown_Patch { [HarmonyPrefix] private static void ZNet_StopAll_Prefix(ZNet __instance) { Log.Debug("ZNet_StopAll_Patch_Prefix"); if (Instance != null) { Instance.ReceivedServerValues = false; } } } [HarmonyPatch(typeof(ZNet), "OnNewConnection")] private static class ZNet_OnNewConnection_Patch { private static void Postfix(ZNet __instance, ZNetPeer peer) { Log.Debug("ZNet OnNewConnection postfix"); if (!__instance.IsServer()) { try { peer.m_rpc.Register<ZPackage>("ClientConfigReceiver." + GetPluginGuid(), (Action<ZRpc, ZPackage>)Instance.RPC_ClientConfigReceiver); Log.Debug("Player registered RPC_ClientConfigReceiver"); return; } catch (Exception) { Log.Warning("Failed to register RPC"); return; } } try { Instance.SendConfigToClient(peer); } catch (Exception) { Log.Warning("Error sending server configuration to client"); } } } public static List<DelegatedConfigEntryBase> ServerDelegatedEntries = new List<DelegatedConfigEntryBase>(); private static ConfigFile LocalConfig; private static BaseUnityPlugin Mod; private static string ConfigFileName; private static ServerConfiguration _instance; private static Logging Log; public bool IsSetup; public bool ReceivedServerValues; public FileSystemWatcher ConfigWatcher; private const string NOT_CONFIGURED = "ServerConfiguration not initialized. Setup first."; public static ServerConfiguration Instance { get { if (_instance == null) { _instance = new ServerConfiguration(); } return _instance; } } private ServerConfiguration() { } public void Setup(ConfigFile config, BaseUnityPlugin modInstance) { LocalConfig = config; Log = Logging.GetLogger(); Log.Trace("ServerConfiguration Setup"); Mod = modInstance; ConfigFileName = Path.GetFileName(LocalConfig.ConfigFilePath); IsSetup = true; } public void CreateConfigWatcher() { ConfigWatcher = Utils.CreateFileWatcher(LocalConfig.ConfigFilePath, LoadConfig); } private void LoadConfig(object sender, FileSystemEventArgs e) { if (!File.Exists(LocalConfig.ConfigFilePath)) { return; } try { Log.Debug($"Loading configuration {e.ChangeType}"); LocalConfig.Reload(); } catch { Log.Error("Error loading configuration file " + ConfigFileName); } } public static string GetPluginGuid() { return Mod.Info.Metadata.GUID; } public void RPC_ClientConfigReceiver(ZRpc zrpc, ZPackage package) { if (!Instance.IsSetup) { Log.Error("ServerConfiguration not initialized. Setup first."); return; } Log.Debug("ClientConfigReceiver"); string section; string name; while (package.GetPos() < package.Size()) { section = package.ReadString(); name = package.ReadString(); string text = package.ReadString(); Log.Trace("Reading " + section + " " + name + " value " + text + " from ZPackage"); DelegatedConfigEntryBase delegatedConfigEntryBase = ServerDelegatedEntries.Find((DelegatedConfigEntryBase e) => e.Name == name && e.Section == section); if (delegatedConfigEntryBase != null) { Log.Trace("Found DCEB on client and setting to server value " + text); delegatedConfigEntryBase.ServerValue = text; } ConfigEntryBase val = LocalConfig[section, name]; if (val != null) { Log.Trace("Found local CEB and setting underlying config value " + text); val.SetSerializedValue(text); } } ReceivedServerValues = true; } internal void WriteConfigEntries(ZPackage zpkg) { foreach (DelegatedConfigEntryBase serverDelegatedEntry in ServerDelegatedEntries) { Log.Trace("Writing " + serverDelegatedEntry.Section + " " + serverDelegatedEntry.Name + " value " + serverDelegatedEntry.ServerValue + " to ZPackage"); zpkg.Write(serverDelegatedEntry.Section); zpkg.Write(serverDelegatedEntry.Name); zpkg.Write(serverDelegatedEntry.ServerValue); } } internal void SendConfigToClient(ZNetPeer peer) { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Expected O, but got Unknown if (!Instance.IsSetup) { Log.Error("ServerConfiguration not initialized. Setup first."); return; } Log.Debug("SendConfigToClient"); ZPackage val = new ZPackage(); WriteConfigEntries(val); peer.m_rpc.Invoke("ClientConfigReceiver." + GetPluginGuid(), new object[1] { val }); Log.Trace("Invoked ClientConfigReceiver on peer"); } public void SendConfigToAllClients(object o, SettingChangedEventArgs e) { //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Expected O, but got Unknown if (!IsSetup) { Log.Error("ServerConfiguration not initialized. Setup first."); } else if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer() && ZNet.instance.GetPeerConnections() > 0) { Log.Debug("SendConfigToAllClients"); ZPackage zpkg = new ZPackage(); WriteConfigEntries(zpkg); ((MonoBehaviour)Mod).StartCoroutine(_instance.Co_BroadcastConfig(zpkg)); } } private IEnumerator Co_BroadcastConfig(ZPackage zpkg) { Log.Debug("Co_BroadcastConfig"); List<ZNetPeer> connectedPeers = ZNet.instance.GetConnectedPeers(); foreach (ZNetPeer item in connectedPeers) { if (item != ZNet.instance.GetServerPeer()) { item.m_rpc.Invoke("ClientConfigReceiver." + GetPluginGuid(), new object[1] { zpkg }); Log.Trace("Invoked ClientConfigReceiver on peer"); } yield return null; } } } internal class Utils { public static TEnum Guardrails<TEnum>(string value, TEnum enumDefault) where TEnum : struct { if (Enum.TryParse<TEnum>(value, ignoreCase: true, out var result)) { return result; } return enumDefault; } public static int Guardrails(int value, int lbound, int ubound) { if (value < lbound) { return lbound; } if (value > ubound) { return ubound; } return value; } public static string truncate(string value, int maxChars) { if (value == null) { return null; } if (value.Length <= maxChars) { return value; } return value.Substring(0, maxChars); } public static void GetCharactersInRangeXZ(Vector3 point, float radius, List<Character> characters) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) float num = radius * radius; foreach (Character s_character in Character.s_characters) { if (DistanceSqrXZ(((Component)s_character).transform.position, point) < num) { characters.Add(s_character); } } } public static float DistanceSqr(Vector3 v0, Vector3 v1) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) float num = v1.x - v0.x; float num2 = v1.y - v0.y; float num3 = v1.z - v0.z; return num * num + num2 * num2 + num3 * num3; } public static float DistanceSqrXZ(Vector3 v0, Vector3 v1) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) float num = v1.x - v0.x; float num2 = v1.z - v0.z; return num * num + num2 * num2; } public static float DistanceXZ(Vector3 v0, Vector3 v1) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) float num = v1.x - v0.x; float num2 = v1.z - v0.z; return Mathf.Sqrt(num * num + num2 * num2); } public static float Guardrails(float value, float lbound, float ubound) { if (value < lbound) { return lbound; } if (value > ubound) { return ubound; } return value; } public static string UnClonifiedName(string name) { if (name == null) { return null; } int num = name.IndexOf("(Clone)"); if (num < 1) { return name; } return name.Substring(0, num); } public static void SetTranslator(int id, string idText) { typeof(Localization).GetMethod("AddWord", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(Localization.instance, new object[2] { "skill_" + id, idText }); } public static string GetTranslated(int id) { Logging.GetLogger().Debug(string.Format("Got translation for id {0} to {1}", id, Localization.instance.Localize("skill_" + id))); return Localization.instance.Localize("$skill_" + id); } public static string GetAssemblyPathedFile(string fileName) { return new FileInfo(Assembly.GetExecutingAssembly().Location).DirectoryName.Replace('\\', '/') + "/" + fileName; } public static Sprite GetPrefabIcon(string prefabName) { Sprite result = null; GameObject prefab = GetPrefab(prefabName); ItemDrop val = default(ItemDrop); if ((Object)(object)prefab != (Object)null && prefab.TryGetComponent<ItemDrop>(ref val)) { result = val.m_itemData.GetIcon(); } return result; } public static Player GetPlayerByZDOID(ZDOID zid) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) foreach (Player allPlayer in Player.GetAllPlayers()) { ZDOID zDOID = ((Character)allPlayer).GetZDOID(); if (((ZDOID)(ref zDOID)).Equals(zid)) { return allPlayer; } } return null; } public static Character GetCharacterByZDOID(string cid) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) foreach (Character allCharacter in Character.GetAllCharacters()) { ZDOID zDOID = allCharacter.GetZDOID(); if (((object)(ZDOID)(ref zDOID)).ToString().Equals(cid)) { return allCharacter; } } return null; } public static Character GetCharacterByZDOID(ZDOID cid) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) foreach (Character allCharacter in Character.GetAllCharacters()) { ZDOID zDOID = allCharacter.GetZDOID(); if (((ZDOID)(ref zDOID)).Equals(cid)) { return allCharacter; } } return null; } public static ZNetPeer GetPeerByRPC(ZRpc rpc) { foreach (ZNetPeer peer in ZNet.instance.GetPeers()) { if (peer.m_rpc == rpc) { return peer; } } return null; } public static List<GameObject> GetGameObjectsOfType(Type t) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) List<GameObject> list = new List<GameObject>(); Object[] array = Object.FindObjectsOfType(t); foreach (Object val in array) { list.Add(((Component)val).gameObject); } return list; } public static GameObject GetClosestGameObjectOfType(Type t, Vector3 point, float radius) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) return GetGameObjectsOfTypeInRangeByDistance(t, point, radius)?[0]; } public static List<GameObject> GetGameObjectsOfTypeInRangeByDistance(Type t, Vector3 point, float radius) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) List<KeyValuePair<GameObject, float>> list = new List<KeyValuePair<GameObject, float>>(); List<GameObject> gameObjectsOfTypeInRange = GetGameObjectsOfTypeInRange(t, point, radius); if (gameObjectsOfTypeInRange.Count > 0) { foreach (GameObject item in gameObjectsOfTypeInRange) { list.Add(new KeyValuePair<GameObject, float>(item, Vector3.Distance(item.transform.position, point))); } list.Sort((KeyValuePair<GameObject, float> pair1, KeyValuePair<GameObject, float> pair2) => pair1.Value.CompareTo(pair2.Value)); return list.ConvertAll((KeyValuePair<GameObject, float> x) => x.Key); } return null; } public static List<GameObject> GetGameObjectsOfTypeInRange(Type t, Vector3 point, float radius) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) return (from x in GetGameObjectsOfType(t) where Vector3.Distance(x.transform.position, point) < radius select x).ToList(); } public static float GetPointDepth(Vector3 p) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) return ZoneSystem.instance.m_waterLevel - GetSolidHeight(p); } public static List<string> GetDelimitedStringAsList(string delimitedString, char delimiter) { List<string> list = new List<string>(); string[] array = delimitedString.Split(new char[1] { delimiter }, StringSplitOptions.RemoveEmptyEntries); foreach (string text in array) { list.Add(text.Trim()); } return list; } public static float GetSolidHeight(Vector3 p) { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) int solidRayMask = ZoneSystem.instance.m_solidRayMask; float result = 0f; p.y += 1000f; RaycastHit val = default(RaycastHit); if (Physics.Raycast(p, Vector3.down, ref val, 2000f, solidRayMask) && !Object.op_Implicit((Object)(object)((RaycastHit)(ref val)).collider.attachedRigidbody)) { result = ((RaycastHit)(ref val)).point.y; } return result; } public static Transform FindChild(Transform aParent, string aName) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Expected O, but got Unknown foreach (Transform item in aParent) { Transform val = item; if (((Object)val).name == aName) { return val; } Transform val2 = FindChild(val, aName); if ((Object)(object)val2 != (Object)null) { return val2; } } return null; } public static Transform FindParent(Transform go) { while ((Object)(object)go.parent != (Object)null) { go = go.parent; } return go; } public static GameObject GetPrefab(int prefabHash) { return GetPrefabByHash(prefabHash); } public static GameObject GetPrefabByHash(int prefabHash) { GameObject val = ObjectDB.instance.GetItemPrefab(prefabHash); Logging logger = Logging.GetLogger(); if ((Object)(object)val != (Object)null) { logger.Debug("Found prefab in ObjectDB"); } else { ZNetScene instance = ZNetScene.instance; val = ((instance != null) ? instance.GetPrefab(prefabHash) : null); if ((Object)(object)val != (Object)null) { logger.Debug("Found prefab in Scene"); } } return val; } public static GameObject GetPrefab(string prefabName) { GameObject val = ObjectDB.instance.GetItemPrefab(prefabName); Logging logger = Logging.GetLogger(); if ((Object)(object)val != (Object)null) { logger.Debug("Found " + prefabName + " in ObjectDB"); } else { ZNetScene instance = ZNetScene.instance; val = ((instance != null) ? instance.GetPrefab(prefabName) : null); if ((Object)(object)val != (Object)null) { logger.Debug("Found " + prefabName + " in Scene"); } } return val; } public static string SerializeFromDictionary<K, V>(string delimp, string delimc, IDictionary<K, V> dict) { if (dict == null) { return null; } IEnumerable<string> values = dict.Select(delegate(KeyValuePair<K, V> kvp) { KeyValuePair<K, V> keyValuePair = kvp; string? obj = keyValuePair.Key?.ToString(); string text = delimc; keyValuePair = kvp; return obj + text + keyValuePair.Value; }); return string.Join(delimp, values); } public static void DeserializeToDictionary<K, V>(string serializedString, string delimp, string delimc, ref IDictionary<K, V> dict) { if (dict == null) { return; } dict.Clear(); string[] separator = new string[1] { delimp }; string[] separator2 = new string[1] { delimc }; string[] array = serializedString.Split(separator, StringSplitOptions.RemoveEmptyEntries); for (int i = 0; i < array.Length; i++) { string[] array2 = array[i].Split(separator2, StringSplitOptions.RemoveEmptyEntries); if (array2.Length == 2) { dict.Add(TypedValue<K>(array2[0]), TypedValue<V>(array2[1])); } } } public static FileSystemWatcher CreateFileWatcher(string fullPath, FileSystemEventHandler handler) { string fileName = Path.GetFileName(fullPath); FileSystemWatcher fileSystemWatcher = new FileSystemWatcher(fullPath.Substring(0, fullPath.Length - fileName.Length), fileName); fileSystemWatcher.NotifyFilter = NotifyFilters.Attributes | NotifyFilters.Size | NotifyFilters.LastWrite | NotifyFilters.CreationTime; fileSystemWatcher.Changed += handler; fileSystemWatcher.Created += handler; fileSystemWatcher.IncludeSubdirectories = false; fileSystemWatcher.SynchronizingObject = ThreadingHelper.SynchronizingObject; fileSystemWatcher.EnableRaisingEvents = true; return fileSystemWatcher; } public static T TypedValue<T>(object a) { return (T)Convert.ChangeType(a, typeof(T)); } public static float TimeAdjustedRamp(float maxValue, float duration, float elapsedTime, float pctFromStartRise, float pctFromEndFall) { float num = elapsedTime / duration; if (num <= pctFromStartRise) { return maxValue * (num / pctFromStartRise); } if (num >= 1f - pctFromEndFall) { return maxValue * ((1f - num) / pctFromEndFall); } return maxValue; } public static bool CopyComponentToGameObject(Component original, ref GameObject destination) { //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Expected O, but got Unknown Logging logger = Logging.GetLogger(); Type type = ((object)original).GetType(); logger.Debug($"Original Type is {type}"); GameObject obj = destination; logger.Debug("Destination GameObject " + ((obj != null) ? ((Object)obj).name : null)); Component val = destination.GetComponent(type); if ((Object)(object)val == (Object)null) { val = destination.AddComponent(type); } if ((Object)(object)val == (Object)null) { logger.Debug("Destination component is null"); return false; } Component val2 = (Component)Activator.CreateInstance(type); if ((Object)(object)val2 == (Object)null) { logger.Debug("Destination component is null"); return false; } if ((Object)(object)val2 == (Object)null) { logger.Debug("Boxed component is null"); return false; } FieldInfo[] fields = type.GetFields(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); foreach (FieldInfo fieldInfo in fields) { fieldInfo.SetValue(val2, fieldInfo.GetValue(original)); } val = val2; return true; } public static bool CopyObject(object original, object target) { Logging logger = Logging.GetLogger(); Type type = original.GetType(); Type type2 = target.GetType(); if (type == null) { logger.Warning("Copy Object: Source object is null"); Activator.CreateInstance(type); return false; } if (type2 == null) { logger.Warning("Copy Object: Destination object is null"); return false; } if (type2 != type) { logger.Warning("Copy Object: Source and destination components are different types"); return false; } FieldInfo[] fields = type.GetFields(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); foreach (FieldInfo fieldInfo in fields) { fieldInfo.SetValue(target, fieldInfo.GetValue(original)); } return true; } } internal class AtgeirBuilder { public static SecondaryAttacks GetSecondaryAttacks(ItemData item) { //IL_0059: Unknown result type (might be due to invalid IL or missing references) SecondaryAttacks secondaryAttacks = new SecondaryAttacks(); AttackPrototype attackPrototype = Prototypes.GetAttackPrototype("Battleaxe"); Logging logger = Logging.GetLogger(); logger.Debug("Using atgeir secondary melee attack"); secondaryAttacks.melee = item.m_shared.m_secondaryAttack.Clone(); logger.Debug("Creating atgeir secondary projectile attack"); secondaryAttacks.projectile = attackPrototype.primaryAttack.Clone(); secondaryAttacks.projectile.m_attackType = (AttackType)2; secondaryAttacks.projectile.m_consumeItem = true; secondaryAttacks.projectile.m_projectileAccuracy = 1f; Prototypes.ConfigAttackForWeapon(secondaryAttacks.projectile, item, item.m_shared.m_secondaryAttack, 2f, 1f, 2f, 1.5f); secondaryAttacks.projectile.m_attackProjectile = null; return secondaryAttacks; } } public class AttackPrototype { public ItemData item; public Attack secondaryAttack; public Attack primaryAttack; public CharacterAnimEvent secondaryAnimationEvent; public CharacterAnimEvent primaryAnimationEvent; } internal class ItemStackState { public bool Flag; public int SourceStack { get; set; } public int DestStack { get; set; } public int Amount { get; set; } } internal class StaffBuilder2H { public static SecondaryAttacks GetSecondaryAttacks(ItemData item) { //IL_0202: Unknown result type (might be due to invalid IL or missing references) //IL_0207: Unknown result type (might be due to invalid IL or missing references) SecondaryAttacks secondaryAttacks = new SecondaryAttacks(); AttackPrototype attackPrototype = Prototypes.GetAttackPrototype("AtgeirIron"); Logging logger = Logging.GetLogger(); logger.Debug("Creating staff secondary melee attack"); float pierce = attackPrototype.item.m_shared.m_damages.m_pierce; float num = (float)Cfg.staffDamage.Value / pierce; logger.Debug($"Scaling to {num} of prototype"); secondaryAttacks.melee = attackPrototype.item.m_shared.m_secondaryAttack.Clone(); secondaryAttacks.melee.m_weapon = Prototypes.ConfigAttackForWeapon(secondaryAttacks.melee, item, attackPrototype.item.m_shared.m_secondaryAttack, num, num, num, num, num); secondaryAttacks.melee.m_weapon.m_shared.m_damages.m_pierce = 0f; secondaryAttacks.melee.m_weapon.m_shared.m_damages.m_blunt = Cfg.staffDamage.Value; if (Cfg.elementalDamagePct.Value > 0) { float num2 = (float)Cfg.staffDamage.Value * ((float)Cfg.elementalDamagePct.Value / 100f); switch (((Object)item.m_dropPrefab).name) { case "StaffFireball": case "StaffClusterbomb": secondaryAttacks.melee.m_weapon.m_shared.m_damages.m_fire = num2; break; case "StaffIceShards": secondaryAttacks.melee.m_weapon.m_shared.m_damages.m_frost = num2; break; case "StaffGreenRoots": secondaryAttacks.melee.m_weapon.m_shared.m_damages.m_poison = num2; break; } } ((DamageTypes)(ref secondaryAttacks.melee.m_weapon.m_shared.m_damages)).Modify(num); secondaryAttacks.melee.m_attackAnimation = attackPrototype.secondaryAttack.m_attackAnimation; secondaryAttacks.melee.m_animEvent = attackPrototype.secondaryAnimationEvent; secondaryAttacks.melee.m_attackType = attackPrototype.secondaryAttack.m_attackType; secondaryAttacks.melee.m_attackAngle = attackPrototype.secondaryAttack.m_attackAngle; secondaryAttacks.melee.m_requiresReload = false; secondaryAttacks.melee.m_attackEitr = 0f; return secondaryAttacks; } } internal class AxeBuilder2H { public static SecondaryAttacks GetSecondaryAttacks(ItemData item) { //IL_008b: Unknown result type (might be due to invalid IL or missing references) SecondaryAttacks secondaryAttacks = new SecondaryAttacks(); AttackPrototype attackPrototype = Prototypes.GetAttackPrototype("Battleaxe"); AttackPrototype attackPrototype2 = Prototypes.GetAttackPrototype("PickaxeBronze"); Logging logger = Logging.GetLogger(); logger.Debug("Using 2H axe secondary melee attack"); secondaryAttacks.melee = item.m_shared.m_secondaryAttack.Clone(); logger.Debug("Creating 2H axe secondary projectile attack"); secondaryAttacks.projectile = attackPrototype.secondaryAttack.Clone(); secondaryAttacks.projectile.m_attackAnimation = attackPrototype2.primaryAttack.m_attackAnimation; secondaryAttacks.projectile.m_animEvent = attackPrototype2.primaryAnimationEvent; secondaryAttacks.projectile.m_attackType = (AttackType)2; secondaryAttacks.projectile.m_consumeItem = true; secondaryAttacks.projectile.m_projectileAccuracy = 1f; Prototypes.ConfigAttackForWeapon(secondaryAttacks.projectile, item, item.m_shared.m_attack, 1.5f, 1f, 2f, 1.5f, 2f); secondaryAttacks.projectile.m_attackProjectile = null; return secondaryAttacks; } } internal class AxeBuilder { public static SecondaryAttacks GetSecondaryAttacks(ItemData item) { SecondaryAttacks secondaryAttacks = new SecondaryAttacks(); AttackPrototype attackPrototype = Prototypes.GetAttackPrototype("SpearBronze"); Logging logger = Logging.GetLogger(); logger.Debug("Using axe secondary melee attack"); secondaryAttacks.melee = item.m_shared.m_secondaryAttack.Clone(); logger.Debug("Creating axe secondary projectile attack"); secondaryAttacks.projectile = attackPrototype.secondaryAttack.Clone(); Prototypes.ConfigAttackForWeapon(secondaryAttacks.projectile, item, item.m_shared.m_secondaryAttack); secondaryAttacks.projectile.m_attackProjectile = null; return secondaryAttacks; } } internal class Cfg { public static DelegatedConfigEntry<bool> enableAxes = null; public static DelegatedConfigEntry<bool> enableKnives = null; public static DelegatedConfigEntry<bool> enableSpears = null; public static DelegatedConfigEntry<bool> enableClubs = null; public static DelegatedConfigEntry<bool> enableSwords = null; public static DelegatedConfigEntry<bool> enablePickaxes = null; public static DelegatedConfigEntry<bool> weaponStones = null; public static DelegatedConfigEntry<bool> weaponWisps = null; public static DelegatedConfigEntry<bool> weaponEitr = null; public static DelegatedConfigEntry<bool> weaponEggs = null; public static DelegatedConfigEntry<bool> weaponTankards = null; public static DelegatedConfigEntry<bool> enableShields = null; public static DelegatedConfigEntry<bool> throwUnderhand = null; public static DelegatedConfigEntry<int> targetAdjustment = null; public static DelegatedConfigEntry<Logging.LogLevels> debugLevel = null; public static DelegatedConfigEntry<MaxAxe.Dynamics> gravity = null; public static DelegatedConfigEntry<bool> useSkill = null; public static DelegatedConfigEntry<string> externalExclude = null; public static DelegatedConfigEntry<bool> stackableWeapons = null; public static DelegatedConfigEntry<bool> mjolnirMode = null; public static DelegatedConfigEntry<bool> enablePolearms = null; public static DelegatedConfigEntry<bool> allow2Handed = null; public static DelegatedConfigEntry<bool> elementalStaffMelee = null; public static DelegatedConfigEntry<bool> bloodStaffMelee = null; public static DelegatedConfigEntry<int> staffDamage = null; public static DelegatedConfigEntry<int> elementalDamagePct = null; public static DelegatedConfigEntry<float> globalThrowingDamageModifer = null; public static DelegatedConfigEntry<bool> restrictCloseThrows = null; public static ConfigEntry<bool> useMelee = null; public static ConfigEntry<bool> autoMelee = null; public static ConfigEntry<bool> autoEquip = null; public static ConfigEntry<bool> throwingStatus = null; public static ConfigEntry<MaxAxe.Finders> weaponFinder = null; public static ConfigEntry<Color> itemAmountColor = null; public static ConfigEntry<bool> forceSimpleTrail = null; public static ConfigEntry<bool> useKeyRelease = null; public static ConfigEntry<bool> autoEquipShields = null; public static ConfigEntry<bool> saveSlotForFrostner = null; public static ConfigEntry<bool> autoPickupThrown = null; private static KeyCode[] keyModifiers = (KeyCode[])(object)new KeyCode[1] { (KeyCode)308 }; private static KeyboardShortcut toggleMeleeKeyDefault = new KeyboardShortcut((KeyCode)98, keyModifiers); public static DelegatedConfigEntry<KeyboardShortcut> toggleMeleeKey = null; private static KeyboardShortcut throwOneKeyDefault = new KeyboardShortcut((KeyCode)116, Array.Empty<KeyCode>()); public static DelegatedConfigEntry<KeyboardShortcut> throwOneKey = null; private static KeyboardShortcut throwShieldKeyDefault = new KeyboardShortcut((KeyCode)103, Array.Empty<KeyCode>()); public static DelegatedConfigEntry<KeyboardShortcut> throwShieldKey = null; public static void BepInExConfig(BaseUnityPlugin _instance) { //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Expected O, but got Unknown //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Expected O, but got Unknown //IL_0106: Unknown result type (might be due to invalid IL or missing references) //IL_012c: Unknown result type (might be due to invalid IL or missing references) //IL_0136: Expected O, but got Unknown //IL_016d: Unknown result type (might be due to invalid IL or missing references) //IL_0177: Expected O, but got Unknown //IL_019c: Unknown result type (might be due to invalid IL or missing references) //IL_01c2: Unknown result type (might be due to invalid IL or missing references) //IL_01cc: Expected O, but got Unknown //IL_0213: Unknown result type (might be due to invalid IL or missing references) //IL_021d: Expected O, but got Unknown //IL_0264: Unknown result type (might be due to invalid IL or missing references) //IL_026e: Expected O, but got Unknown //IL_02b5: Unknown result type (might be due to invalid IL or missing references) //IL_02bf: Expected O, but got Unknown //IL_0306: Unknown result type (might be due to invalid IL or missing references) //IL_0310: Expected O, but got Unknown //IL_0357: Unknown result type (might be due to invalid IL or missing references) //IL_0361: Expected O, but got Unknown //IL_03a8: Unknown result type (might be due to invalid IL or missing references) //IL_03b2: Expected O, but got Unknown //IL_03f9: Unknown result type (might be due to invalid IL or missing references) //IL_0403: Expected O, but got Unknown //IL_044a: Unknown result type (might be due to invalid IL or missing references) //IL_0454: Expected O, but got Unknown //IL_049b: Unknown result type (might be due to invalid IL or missing references) //IL_04a5: Expected O, but got Unknown //IL_04f8: Unknown result type (might be due to invalid IL or missing references) //IL_0502: Expected O, but got Unknown //IL_0555: Unknown result type (might be due to invalid IL or missing references) //IL_055f: Expected O, but got Unknown //IL_05b2: Unknown result type (might be due to invalid IL or missing references) //IL_05bc: Expected O, but got Unknown //IL_060f: Unknown result type (might be due to invalid IL or missing references) //IL_0619: Expected O, but got Unknown //IL_066c: Unknown result type (might be due to invalid IL or missing references) //IL_0676: Expected O, but got Unknown //IL_06bd: Unknown result type (might be due to invalid IL or missing references) //IL_06c7: Expected O, but got Unknown //IL_070e: Unknown result type (might be due to invalid IL or missing references) //IL_0718: Expected O, but got Unknown //IL_076b: Unknown result type (might be due to invalid IL or missing references) //IL_0775: Expected O, but got Unknown //IL_07ab: Unknown result type (might be due to invalid IL or missing references) //IL_07b5: Expected O, but got Unknown //IL_0807: Unknown result type (might be due to invalid IL or missing references) //IL_0811: Expected O, but got Unknown //IL_0847: Unknown result type (might be due to invalid IL or missing references) //IL_0851: Expected O, but got Unknown //IL_0887: Unknown result type (might be due to invalid IL or missing references) //IL_0891: Expected O, but got Unknown //IL_08c7: Unknown result type (might be due to invalid IL or missing references) //IL_08d1: Expected O, but got Unknown //IL_0920: Unknown result type (might be due to invalid IL or missing references) //IL_092a: Expected O, but got Unknown //IL_0970: Unknown result type (might be due to invalid IL or missing references) //IL_097a: Expected O, but got Unknown //IL_09b0: Unknown result type (might be due to invalid IL or missing references) //IL_09ba: Expected O, but got Unknown //IL_0a60: Unknown result type (might be due to invalid IL or missing references) //IL_0a6a: Expected O, but got Unknown //IL_0aae: Unknown result type (might be due to invalid IL or missing references) //IL_0ab8: Expected O, but got Unknown //IL_0afb: Unknown result type (might be due to invalid IL or missing references) //IL_0b05: Expected O, but got Unknown //IL_0b8a: Unknown result type (might be due to invalid IL or missing references) debugLevel = new DelegatedConfigEntry<Logging.LogLevels>(MaxAxe.LogChange); debugLevel.ConfigEntry = _instance.Config.Bind<Logging.LogLevels>("Utility", "LogLevel", Logging.LogLevels.Info, "Controls the level of information contained in the log. Set to 'Info' for normal use."); MaxAxe.Log.LogLevel = debugLevel.Value; useMelee = _instance.Config.Bind<bool>("General", "MeleeAttack", true, new ConfigDescription("When True, uses a melee secondary attack. Toggled in-game using the ToggleMeleeAttack key.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = 30 } })); toggleMeleeKey = new DelegatedConfigEntry<KeyboardShortcut>(); toggleMeleeKey.ConfigEntry = _instance.Config.Bind<KeyboardShortcut>("General", "ToggleMeleeAttack", toggleMeleeKeyDefault, new ConfigDescription("Press this key to toggle in-game between Throw and Melee mode for enabled weapons.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = 29 } })); throwOneKey = new DelegatedConfigEntry<KeyboardShortcut>(); throwOneKey.ConfigEntry = _instance.Config.Bind<KeyboardShortcut>("General", "ThrowOne", throwOneKeyDefault, new ConfigDescription("Press this key to throw the current weapon, regardless of Melee or Throw mode.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = 28 } })); useKeyRelease = _instance.Config.Bind<bool>("General", "ThrowOnRelease", false, new ConfigDescription("Set to True to throw when the ThrowOne or ThrowShield keys are released instead of pressed.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = 27 } })); throwShieldKey = new DelegatedConfigEntry<KeyboardShortcut>(); throwShieldKey.ConfigEntry = _instance.Config.Bind<KeyboardShortcut>("General", "ThrowShield", throwShieldKeyDefault, new ConfigDescription("Press this key to throw an equipped round shield.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = 26 } })); throwUnderhand = new DelegatedConfigEntry<bool>(); throwUnderhand.ConfigEntry = _instance.Config.Bind<bool>("General", "UnderhandShield", false, new ConfigDescription("Set to True to throw your shield using an underhand throw. Shields must also be enabled.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = 25 } })); enableAxes = new DelegatedConfigEntry<bool>(useServerDelegate: true); enableAxes.ConfigEntry = _instance.Config.Bind<bool>("General", "EnableAxes", true, new ConfigDescription("Set to True to enable secondary throwing attacks for one-handed axes.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = 24 } })); enableClubs = new DelegatedConfigEntry<bool>(useServerDelegate: true); enableClubs.ConfigEntry = _instance.Config.Bind<bool>("General", "EnableClubs", true, new ConfigDescription("Set to True to enable secondary throwing attacks for blunt weapons & torches. Torches, stones, sledges & wooden clubs also get secondary melee attacks.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = 23 } })); enableKnives = new DelegatedConfigEntry<bool>(useServerDelegate: true); enableKnives.ConfigEntry = _instance.Config.Bind<bool>("General", "EnableKnives", true, new ConfigDescription("Set to True to enable secondary throwing attacks for knives.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = 22 } })); enablePolearms = new DelegatedConfigEntry<bool>(useServerDelegate: true); enablePolearms.ConfigEntry = _instance.Config.Bind<bool>("General", "EnablePolearms", true, new ConfigDescription("Set to True to enable secondary throwing attacks for polearms. AllowTwoHandedWeapons must also be true.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = 21 } })); enableSpears = new DelegatedConfigEntry<bool>(useServerDelegate: true); enableSpears.ConfigEntry = _instance.Config.Bind<bool>("General", "EnableSpears", true, new ConfigDescription("Set to True to enable secondary melee attack for spears.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = 20 } })); enableSwords = new DelegatedConfigEntry<bool>(useServerDelegate: true); enableSwords.ConfigEntry = _instance.Config.Bind<bool>("General", "EnableSwords", true, new ConfigDescription("Set to True to enable secondary throwing attacks for swords.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = 19 } })); enablePickaxes = new DelegatedConfigEntry<bool>(useServerDelegate: true); enablePickaxes.ConfigEntry = _instance.Config.Bind<bool>("General", "EnablePickaxes", true, new ConfigDescription("Set to True to enable secondary throwing and melee attacks for pickaxes. AllowTwoHandedWeapons must also be true.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = 18 } })); enableShields = new DelegatedConfigEntry<bool>(useServerDelegate: true); enableShields.ConfigEntry = _instance.Config.Bind<bool>("General", "EnableShields", true, new ConfigDescription("Set to True to enable throwing round shields, by using the ThrowShield key.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = 17 } })); weaponStones = new DelegatedConfigEntry<bool>(MaxAxe.GroupsChange, useServerDelegate: true); weaponStones.ConfigEntry = _instance.Config.Bind<bool>("General", "WeaponStones", true, new ConfigDescription("Set to True to enable equipping and attacking with stones.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = 16 } })); weaponWisps = new DelegatedConfigEntry<bool>(MaxAxe.GroupsChange, useServerDelegate: true); weaponWisps.ConfigEntry = _instance.Config.Bind<bool>("General", "WeaponWisps", true, new ConfigDescription("Set to True to enable equipping and attacking with Wisps.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = 15 } })); weaponEitr = new DelegatedConfigEntry<bool>(MaxAxe.GroupsChange, useServerDelegate: true); weaponEitr.ConfigEntry = _instance.Config.Bind<bool>("General", "WeaponEitr", true, new ConfigDescription("Set to True to enable equipping and attacking with refined Eitr.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = 14 } })); weaponEggs = new DelegatedConfigEntry<bool>(MaxAxe.GroupsChange, useServerDelegate: true); weaponEggs.ConfigEntry = _instance.Config.Bind<bool>("General", "WeaponEggs", true, new ConfigDescription("Set to True to enable equipping and attacking with Eggs.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = 13 } })); weaponTankards = new DelegatedConfigEntry<bool>(MaxAxe.GroupsChange, useServerDelegate: true); weaponTankards.ConfigEntry = _instance.Config.Bind<bool>("General", "WeaponTankards", true, new ConfigDescription("Set to True to enable equipping and attacking with Tankards.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = 12 } })); mjolnirMode = new DelegatedConfigEntry<bool>(useServerDelegate: true); mjolnirMode.ConfigEntry = _instance.Config.Bind<bool>("General", "MjolnirMode", false, new ConfigDescription("Set to True to enable Frostner returning to your hand after throwing.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = 11 } })); allow2Handed = new DelegatedConfigEntry<bool>(useServerDelegate: true); allow2Handed.ConfigEntry = _instance.Config.Bind<bool>("General", "AllowTwoHandedWeapons", false, new ConfigDescription("Set to True to allow two-handed weapons to be thrown.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = 10 } })); stackableWeapons = new DelegatedConfigEntry<bool>(MaxAxe.StackableChange, useServerDelegate: true); stackableWeapons.ConfigEntry = _instance.Config.Bind<bool>("General", "StackableWeapons", false, new ConfigDescription("Set to True to allow throwable weapons to stack. See documentation for details before enabling stackable weapons.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = 9 } })); throwingStatus = _instance.Config.Bind<bool>("General", "ThrowingStatus", true, new ConfigDescription("Set to True to display a status effect if throwing is active.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = 8 } })); useSkill = new DelegatedConfigEntry<bool>(MaxAxe.ToggleSkill, useServerDelegate: true); useSkill.ConfigEntry = _instance.Config.Bind<bool>("Skill", "UseThrowingSkill", false, new ConfigDescription("Set to True to enable the Throwing skill. Used in place of specific weapon skills to improve stats for all thrown items.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = 7 } })); autoMelee = _instance.Config.Bind<bool>("General", "AutoMelee", false, new ConfigDescription("Set to True to automatically switch to melee mode after throwing a weapon, OR if last weapon in a stack (if StackableWeapons is True).", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = 6 } })); autoEquip = _instance.Config.Bind<bool>("General", "AutoEquip", true, new ConfigDescription("Set to True to automatically equip another weapon after throwing a weapon.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = 5 } })); autoEquipShields = _instance.Config.Bind<bool>("General", "AutoEquipShields", true, new ConfigDescription("Set to True to automatically equip shields after picking them up.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = 4 } })); targetAdjustment = new DelegatedConfigEntry<int>(); targetAdjustment.ConfigEntry = _instance.Config.Bind<int>("General", "TargetAdjustment", -7, new ConfigDescription("Adjusts the throwing impact point in relation to the target reticle (the +). Set _instanced upon your 'typical' throwing distance. Default is -7.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(-20, 20), new object[1] { new ConfigurationManagerAttributes { Order = 3 } })); gravity = new DelegatedConfigEntry<MaxAxe.Dynamics>(useServerDelegate: true); gravity.ConfigEntry = _instance.Config.Bind<MaxAxe.Dynamics>("Throwing Dynamics", "ThrowingMode", MaxAxe.Dynamics.Default, new ConfigDescription("Sets the type of weapon dynamics in flight. Better uses earth nominal gravity and applies inertia and drag to thrown weapons.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = 2 } })); weaponFinder = _instance.Config.Bind<MaxAxe.Finders>("General", "WeaponFinder", MaxAxe.Finders.Wishbone, new ConfigDescription("Type of 'locator' effect added to thrown weapon to make it easier to find.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = 1 } })); elementalStaffMelee = new DelegatedConfigEntry<bool>(useServerDelegate: true); elementalStaffMelee.ConfigEntry = _instance.Config.Bind<bool>("Staffs", "EnableElementalStaffMelee", false, "Set to true to allow a sweeping melee secondary attack for Elemental Magic staffs, except for Dundr."); bloodStaffMelee = new DelegatedConfigEntry<bool>(useServerDelegate: true); bloodStaffMelee.ConfigEntry = _instance.Config.Bind<bool>("Staffs", "EnableBloodStaffMelee", false, "Set to true to allow a sweeping melee secondary attack for Blood Magic staffs, except for Dead Raiser."); staffDamage = new DelegatedConfigEntry<int>(MaxAxe.StaffDamageChange, useServerDelegate: true); staffDamage.ConfigEntry = _instance.Config.Bind<int>("Staffs", "StaffDamage", 65, new ConfigDescription("The 'base' damage to each target hit by the staff sweeping attack. Will be adjusted by modifiers, skill, resistances, etc.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(15, 80), Array.Empty<object>())); elementalDamagePct = new DelegatedConfigEntry<int>(MaxAxe.StaffDamageChange, useServerDelegate: true); elementalDamagePct.ConfigEntry = _instance.Config.Bind<int>("Staffs", "AddElementalDamage", 0, new ConfigDescription("Add this percent of 'base' damage as elemental damage for melee attacks with Elemental Magic staffs. Staffs still do blunt damage if set to 0, or not enough Eitr is available. Costs this much Eitr per attack.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 10), Array.Empty<object>())); globalThrowingDamageModifer = new DelegatedConfigEntry<float>(useServerDelegate: true); globalThrowingDamageModifer.ConfigEntry = _instance.Config.Bind<float>("Tweaks", "ThrowingDamage", 1f, new ConfigDescription("Percent of damage for thrown weapons. Default damage (100%) is generally equivalent to melee secondary attacks. Use this to reduce the amount of all throwing damage.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>())); restrictCloseThrows = new DelegatedConfigEntry<bool>(useServerDelegate: true); restrictCloseThrows.ConfigEntry = _instance.Config.Bind<bool>("Tweaks", "RestrictCloseThrows", true, "Set to true to prevent throwing at enemies in melee range. If an enemy is within a weapons melee area, attack will automatically change to the primary attack."); autoPickupThrown = _instance.Config.Bind<bool>("Utility", "AutoPickupThrownWeapons", false, "Set to True to allow autopickup of thrown weapons."); saveSlotForFrostner = _instance.Config.Bind<bool>("Utility", "SaveSpaceForFrostner", false, "Set to True to ensure autopickup doesn't use up the last inventory slot for a returning weapon. Only active if Mjolnir mode is also on."); itemAmountColor = _instance.Config.Bind<Color>("Utility", "ItemAmountColor", Color.yellow, "Color of item quantity text in hotbar and inventory."); forceSimpleTrail = _instance.Config.Bind<bool>("Utility", "ForceSimpleTrail", false, "Set to True for MaxAxe to use the 'simple' trail of earlier releases."); externalExclude = new DelegatedConfigEntry<string>(MaxAxe.ExcludeChange, useServerDelegate: true); externalExclude.ConfigEntry = _instance.Config.Bind<string>("Mod Compatibility", "ExcludePrefabs", "", "A comma delimited string of prefabs to exclude from being thrown. Example: PrefabNameA,PrefabNameB"); } } internal class ClubBuilder { public static SecondaryAttacks GetSecondaryAttacks(ItemData item) { //IL_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Unknown result type (might be due to invalid IL or missing references) SecondaryAttacks secondaryAttacks = new SecondaryAttacks(); AttackPrototype attackPrototype = Prototypes.GetAttackPrototype("SpearBronze"); AttackPrototype attackPrototype2 = Prototypes.GetAttackPrototype("MaceBronze"); Logging logger = Logging.GetLogger(); if (!string.IsNullOrEmpty(item.m_shared.m_secondaryAttack.m_attackAnimation)) { logger.Debug("Using club secondary melee attack"); secondaryAttacks.melee = item.m_shared.m_secondaryAttack.Clone(); } else { logger.Debug("Creating club secondary melee attack"); secondaryAttacks.melee = item.m_shared.m_attack.Clone(); Prototypes.ConfigAttackForWeapon(secondaryAttacks.melee, item, item.m_shared.m_attack, 2f, 2f, 2f, 2f, 2f); secondaryAttacks.melee.m_attackAnimation = attackPrototype2.secondaryAttack.m_attackAnimation; secondaryAttacks.melee.m_animEvent = attackPrototype2.secondaryAnimationEvent; secondaryAttacks.melee.m_attackType = attackPrototype2.secondaryAttack.m_attackType; secondaryAttacks.melee.m_attackAngle = attackPrototype2.secondaryAttack.m_attackAngle; } logger.Debug("Creating club secondary projectile attack"); secondaryAttacks.projectile = attackPrototype.secondaryAttack.Clone(); Prototypes.ConfigAttackForWeapon(secondaryAttacks.projectile, item, item.m_shared.m_secondaryAttack); secondaryAttacks.projectile.m_attackProjectile = null; return secondaryAttacks; } } public class DynamicProps { public float Vel { get; set; } public float Drag { get; set; } internal DynamicProps(float v, float d) { Vel = v; Drag = d; } } public class EffectGroup { public float scale { get; } public HashSet<string> effects { get; } public EffectGroup(float scale, HashSet<string> effects) { this.effects = effects; this.scale = scale; } } internal class EggBuilder { public static SecondaryAttacks GetSecondaryAttacks(ItemData item) { SecondaryAttacks secondaryAttacks = new SecondaryAttacks(); AttackPrototype attackPrototype = Prototypes.GetAttackPrototype("SpearBronze"); Logging logger = Logging.GetLogger(); secondaryAttacks.melee = null; logger.Debug("Creating egg secondary projectile attack"); secondaryAttacks.projectile = attackPrototype.secondaryAttack.Clone(); secondaryAttacks.projectile.m_attackStamina = 2f; secondaryAttacks.projectile.m_attackAnimation = attackPrototype.secondaryAttack.m_attackAnimation; secondaryAttacks.projectile.m_animEvent = attackPrototype.secondaryAnimationEvent; secondaryAttacks.projectile.m_attackProjectile = null; return secondaryAttacks; } } internal class Finder { private GameObject _finderEffect; private string PrefabName { get; } internal Vector3 Offset { get; } internal GameObject FinderEffect { get { if ((Object)(object)_finderEffect == (Object)null) { _finderEffect = Utils.GetPrefab(PrefabName); } return _finderEffect; } } internal Finder(string name, Vector3 offset) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) PrefabName = name; Offset = offset; } } internal class KnifeBuilder { public static SecondaryAttacks GetSecondaryAttacks(ItemData item) { SecondaryAttacks secondaryAttacks = new SecondaryAttacks(); AttackPrototype attackPrototype = Prototypes.GetAttackPrototype("SpearBronze"); Logging logger = Logging.GetLogger(); logger.Debug("Using knife secondary melee attack"); secondaryAttacks.melee = item.m_shared.m_secondaryAttack.Clone(); logger.Debug("Creating knife secondary projectile attack"); secondaryAttacks.projectile = attackPrototype.secondaryAttack.Clone(); Prototypes.ConfigAttackForWeapon(secondaryAttacks.projectile, item, item.m_shared.m_secondaryAttack); secondaryAttacks.projectile.m_attackProjectile = null; return secondaryAttacks; } } internal class MagicBuilder { public static SecondaryAttacks GetSecondaryAttacks(ItemData item) { SecondaryAttacks secondaryAttacks = new SecondaryAttacks(); AttackPrototype attackPrototype = Prototypes.GetAttackPrototype("SpearBronze"); Logging logger = Logging.GetLogger(); secondaryAttacks.melee = null; logger.Debug("Creating magic secondary projectile attack"); secondaryAttacks.projectile = attackPrototype.secondaryAttack.Clone(); secondaryAttacks.projectile.m_attackStamina = 3f; secondaryAttacks.projectile.m_attackAnimation = attackPrototype.secondaryAttack.m_attackAnimation; secondaryAttacks.projectile.m_animEvent = attackPrototype.secondaryAnimationEvent; secondaryAttacks.projectile.m_attackProjectile = null; return secondaryAttacks; } } [BepInPlugin("neobotics.valheim_mod.maxaxe", "MaxAxe", "0.5.6")] [BepInProcess("valheim.exe")] [BepInProcess("valheim_server.exe")] public class MaxAxe : BaseUnityPlugin { public enum Finders { Wishbone, Autopick, None } public enum Dynamics { Default, Better } [HarmonyPatch(typeof(Inventory), "HaveEmptySlot")] private static class Inventory_HaveEmptySlot_Patch { [HarmonyPostfix] private static void Inventory_HaveEmptySlot_Postfix(Inventory __instance, ref bool __result) { Player localPlayer = Player.m_localPlayer; if (__instance == ((Humanoid)(localPlayer?)).m_inventory && Cfg.mjolnirMode.Value && Cfg.saveSlotForFrostner.Value && ((Humanoid)localPlayer).GetCurrentWeapon() == ((Humanoid)localPlayer).m_unarmedWeapon.m_itemData && __instance.GetEmptySlots() <= 1) { Log.Trace("Saving space for returning weapons"); __result = false; } } } [HarmonyPatch(typeof(Inventory), "AddItem", new Type[] { typeof(string), typeof(int), typeof(float), typeof(Vector2i), typeof(bool), typeof(int), typeof(int), typeof(long), typeof(string), typeof(Dictionary<string, string>), typeof(int), typeof(bool) })] private static class Inventory_AddItem_AddOnLoad_Patch { private static void Prefix(Inventory __instance, string name, int stack, float durability, Vector2i pos, bool equipped, int quality, int variant, long crafterID, string crafterName, Dictionary<string, string> customData) { Log.Trace($"AddItem_OnLoad prefix {name} stack {stack}"); if (stack > 1) { if (customData == null) { customData = new Dictionary<string, string>(); } customData.Add(Z_MAXAXE.ToString(), stack.ToString()); } } } [HarmonyPatch(typeof(Inventory), "AddItem", new Type[] { typeof(ItemData) })] private static class Inventory_AddItem_AddNew_Patch { private static bool Prefix(Inventory __instance, ItemData item, string ___m_name, out bool __result) { //IL_011a: Unknown result type (might be due to invalid IL or missing references) //IL_011f: Unknown result type (might be due to invalid IL or missing references) //IL_0121: Unknown result type (might be due to invalid IL or missing references) //IL_012e: Unknown result type (might be due to invalid IL or missing references) //IL_0135: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) Log.Trace("InventoryAddItem_AddNew prefix " + __instance.GetName()); __result = true; if (BlacksmithingDetected() && item != null && item.m_shared.m_maxStackSize > 1 && Cfg.stackableWeapons.Value && IsStackableWeapon(item)) { for (int i = 0; i < item.m_stack; i++) { ItemData val = FindMaxFreeStackItem(__instance, item.m_shared.m_name, item.m_quality, item.m_worldLevel, item.m_shared.m_maxDurability); if (val != null) { val.m_stack++; continue; } item.m_stack -= i; Vector2i val2 = __instance.FindEmptySlot(true); if (val2.x >= 0) { item.m_gridPos = val2; __instance.m_inventory.Add(item); } else { __result = false; } break; } return false; } if (item != null && !Cfg.stackableWeapons.Value && IsStackableWeapon(item) && item.m_stack > 1) { __result = false; int stack = item.m_stack; bool flag = false; for (int j = 0; j < stack; j++) { Vector2i val3 = __instance.FindEmptySlot(true); if (val3.x >= 0) { flag = __instance.AddItem(item, 1, val3.x, val3.y); } if (!flag) { break; } } if (flag) { item.m_shared.m_maxStackSize = Math.Max(item.m_stack, 1); } return false; } return true; } } [HarmonyPatch(typeof(Inventory), "AddItem", new Type[] { typeof(ItemData), typeof(int), typeof(int), typeof(int) })] private static class Inventory_AddItem_ToSlot_Patch { private static bool Prefix(Inventory __instance, ItemData item, ref int amount, int x, int y, string ___m_name, ref ItemStackState __state) { __state = new ItemStackState(); Log.Trace("AddItem_ToSlot prefix " + __instance.GetName()); string key = Z_MAXAXE.ToString(); if (item != null && item.m_customData.TryGetValue(key, out var value)) { if (IsStackableWeapon(item)) { int num = (amount = (item.m_stack = int.Parse(value))); if (item.m_shared.m_maxStackSize < num) { item.m_shared.m_maxStackSize = num; } } item.m_customData.Remove(key); } if (item != null && Cfg.stackableWeapons.Value && stackables.ContainsKey(item.m_shared.m_name)) { ItemData itemAt = __instance.GetItemAt(x, y); if (itemAt != null) { __state.SourceStack = item.m_stack; __state.DestStack = itemAt.m_stack; __state.Amount = amount; } if (itemAt == null) { if (Cfg.stackableWeapons.Value && stackables.ContainsKey(item.m_shared.m_name)) { item.m_shared.m_maxStackSize = stackables[item.m_shared.m_name]; } Log.Debug("Empty target slot"); return true; } if (itemAt != null && item.m_durability <= 0f && itemAt.m_durability <= 0f && item.m_shared.m_maxDurability == itemAt.m_shared.m_maxDurability) { __state.Flag = true; Log.Debug("Allowed target stack for broken weapon"); return true; } if (itemAt != null && item.m_durability <= 0f) { Log.Debug("Can't stack broken item with good item"); return false; } if (itemAt != null && itemAt.m_durability <= 0f) { Log.Debug("Can't stack good item with broken item"); return false; } if (itemAt != null && itemAt.m_shared.m_maxDurability != item.m_shared.m_maxDurability) { Log.Debug("Can't stack items with different max durability"); return false; } if (itemAt != null && itemAt.m_quality != item.m_quality) { Log.Debug("Can't stack items with different quality"); return false; } if (itemAt != null && item.m_durability > 0f && itemAt.m_durability > 0f) { __state.Flag = true; Log.Debug("Stacking weapons"); if (item.m_durability != itemAt.m_durability) { Log.Debug("Setting durability to lesser of both stacks"); itemAt.m_durability = Mathf.Min(item.m_durability, itemAt.m_durability); } return true; } } return true; } [HarmonyPriority(100)] private static void Postfix(Inventory __instance, ItemData item, ref int amount, int x, int y, string ___m_name, ref ItemStackState __state, ref bool __result) { Log.Trace("AddItem_ToSlot postfix " + __instance.GetName()); if (!__state.Flag || !BlacksmithingDetected()) { return; } ItemData itemAt = __instance.GetItemAt(x, y); if (itemAt != null) { int num = itemAt.m_shared.m_maxStackSize - __state.DestStack; if (num > 0) { int num2 = Mathf.Min(num, __state.Amount); itemAt.m_stack = __state.DestStack + num2; item.m_stack = __state.SourceStack - num2; bool flag = num2 == amount; ZLog.Log((object)("Added to stack" + itemAt.m_stack + " " + item.m_stack)); __instance.Changed(); __result = flag; } } } } [HarmonyPatch(typeof(Inventory), "MoveItemToThis", new Type[] { typeof(Inventory), typeof(ItemData), typeof(int), typeof(int), typeof(int) })] private static class Inventory_MoveItemToThis_Slot_Patch { private static void Prefix(Inventory __instance, Inventory fromInventory, ItemData item, ref int amount, int x, int y, string ___m_name) { Log.Trace("MoveItemToThis_Slot to " + __instance.GetName() + " from " + fromInventory.GetName() + " item " + item?.m_shared.m_name); if (item != null && !Cfg.stackableWeapons.Value && IsStackableWeapon(item)) { amount = 1; } } } [HarmonyPatch(typeof(Inventory), "MoveItemToThis", new Type[] { typeof(Inventory), typeof(ItemData) })] private static class Inventory_MoveItemToThis_Patch { private static bool Prefix(Inventory __instance, Inventory fromInventory, ItemData item, string ___m_name) { //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) Log.Trace("MoveItemToThis to " + __instance.GetName() + " from " + ((fromInventory != null) ? fromInventory.GetName() : null) + " item " + item?.m_shared.m_name); if (item != null && !Cfg.stackableWeapons.Value && IsStackableWeapon(item) && item.m_stack > 1) { int stack = item.m_stack; bool flag = false; for (int i = 0; i < stack; i++) { Vector2i val = __instance.FindEmptySlot(true); if (val.x >= 0) { flag = __instance.MoveItemToThis(fromInventory, item, 1, val.x, val.y); } if (!flag) { break; } } if (flag) { item.m_shared.m_maxStackSize = Math.Max(item.m_stack, 1); } return false; } return true; } } [HarmonyPatch(typeof(VisEquipment), "AttachItem")] private static class VisEquipment_AttachItem_Patch { private static void Postfix(VisEquipment __instance, int itemHash, int variant, Transform joint, bool enableEquipEffects, GameObject __result) { if (shieldVariant != 0 && __instance.m_isPlayer) { ItemStyle componentInChildren = __result.GetComponentInChildren<ItemStyle>(); if (componentInChildren != null) { componentInChildren.Setup(shieldVariant); } shieldVariant = 0; } } } [HarmonyPatch(typeof(VisEquipment), "SetRightHandEquipped")] private static class VisEquipment_SetRightHandEquiped_Patch { [HarmonyAfter(new string[] { "blacks7ar.WeaponHolsterOverhaul" })] private static void Postfix(int hash, GameObject ___m_rightItemInstance, int ___m_currentRightItemHash, bool __result) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) if (TryGetActiveNonWeapon(hash, out var nonWeapon) && __result && (Object)(object)___m_rightItemInstance != (Object)null) { ___m_rightItemInstance.transform.localScale = nonWeapon.localScale; ___m_rightItemInstance.transform.localPosition = nonWeapon.rightHandOffset; MeshRenderer val = default(MeshRenderer); if (___m_rightItemInstance.TryGetComponent<MeshRenderer>(ref val)) { ((Renderer)val).enabled = true; } } } } [HarmonyPatch(typeof(VisEquipment), "SetLeftHandEquipped")] private static class VisEquipment_SetLeftHandEquiped_Patch { [HarmonyAfter(new string[] { "blacks7ar.WeaponHolsterOverhaul" })] private static void Postfix(int hash, GameObject ___m_leftItemInstance, bool __result) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) if (TryGetActiveNonWeapon(hash, out var nonWeapon) && __result && (Object)(object)___m_leftItemInstance != (Object)null) { ___m_leftItemInstance.transform.localScale = nonWeapon.localScale; ___m_leftItemInstance.transform.localPosition = nonWeapon.leftHandOffset; MeshRenderer val = default(MeshRenderer); if (___m_leftItemInstance.TryGetComponent<MeshRenderer>(ref val)) { ((Renderer)val).enabled = true; } } } } [HarmonyPatch(typeof(VisEquipment), "AttachBackItem")] private static class VisEquipment_AttachBackItem_Patch { [HarmonyAfter(new string[] { "blacks7ar.WeaponHolsterOverhaul" })] private static void Postfix(GameObject __result, int hash, int variant, bool rightHand) { Log.Debug("VisEquipment AttachBackItem postfix"); if (TryGetActiveNonWeapon(hash, out var _)) { Log.Debug("Attaching back item"); __result.SetActive(false); } } } [HarmonyPatch(typeof(SEMan), "GetHUDStatusEffects")] private static class Hud_GetHUDStatusEffects_Patch { private static void Prefix(List<StatusEffect> effects) { //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Invalid comparison between Unknown and I4 //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Invalid comparison between Unknown and I4 //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Invalid comparison between Unknown and I4 //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Invalid comparison between Unknown and I4 if (!Cfg.throwingStatus.Value || Cfg.useMelee.Value || ((Character)Player.m_localPlayer).InPlaceMode()) { return; } if ((Object)(object)throwingSE == (Object)null) { CreateThrowingStatusEffect(); } ItemData currentWeapon = ((Humanoid)Player.m_localPlayer).GetCurrentWeapon(); if (currentWeapon == null) { return; } if ((int)currentWeapon.m_shared.m_skillType == 11) { ((StatusEffect)throwingSE).m_icon = unarmedIcon; ((StatusEffect)throwingSE).m_flashIcon = false; } else { ((StatusEffect)throwingSE).m_icon = currentWeapon.GetIcon(); DelegatedConfigEntry<bool> dce; if (IsExcluded(currentWeapon)) { ((StatusEffect)throwingSE).m_flashIcon = true; } else if ((int)currentWeapon.m_shared.m_skillType == 9 || (int)currentWeapon.m_shared.m_skillType == 10) { ((StatusEffect)throwingSE).m_flashIcon = true; } else if ((int)currentWeapon.m_shared.m_itemType == 14 && !Cfg.allow2Handed.Value) { ((StatusEffect)throwingSE).m_flashIcon = true; } else if (TryGetWeaponGroup(currentWeapon, out dce)) { ((StatusEffect)throwingSE).m_flashIcon = !dce.Value; } else if (IsActiveWeapon(currentWeapon)) { ((StatusEffect)throwingSE).m_flashIcon = false; } else { ((StatusEffect)throwingSE).m_flashIcon = true; } } effects.Add((StatusEffect)(object)throwingSE); } } [HarmonyPatch(typeof(Humanoid), "DrainEquipedItemDurability")] private static class Humanoid_DrainEquipedItemDurability_Patch { private static bool Prefix(Humanoid __instance, ItemData item, float dt) { //IL_013a: Unknown result type (might be due to invalid IL or missing references) //IL_013f: Unknown result type (might be due to invalid IL or missing references) //IL_0142: Unknown result type (might be due to invalid IL or missing references) //IL_0144: Unknown result type (might be due to invalid IL or missing references) if (item != null && Cfg.stackableWeapons.Value && stackables.ContainsKey(item.m_shared.m_name) && item.m_stack > 1) { item.m_durability -= item.m_shared.m_durabilityDrain * dt; if (item.m_durability <= 0f && (Object)(object)item.m_lastProjectile == (Object)null) { Inventory inventory = __instance.m_inventory; ((Character)__instance).Message((MessageType)1, Localization.instance.Localize("$msg_broke", new string[1] { item.m_shared.m_name }), 0, item.GetIcon()); ItemData val = item.Clone(); val.m_equipped = false; Log.Debug("Removing broken item from stack"); inventory.RemoveItem(item, 1); item.m_durability = MaxLeveledDurability(item); Log.Debug("Set remaining stack durability to max"); if (!item.m_shared.m_destroyBroken) { List<ItemData> inventory2 = inventory.m_inventory; ItemData val2 = FindAvailableBrokenStack(inventory2, item); if (val2 != null) { val2.m_stack++; Log.Debug("Broken item added to existing stack"); } else if (inventory.HaveEmptySlot()) { Vector2i gridPos = inventory.FindEmptySlot(false); val.m_gridPos = gridPos; inventory2.Add(val); val.m_stack = 1; inventory.Changed(); Log.Debug("Broken item was added to new slot"); } else { wasDropped = true; __instance.DropItem(inventory, val, 1); Log.Debug("Broken item was dropped"); } } } return false; } return true; } } [HarmonyPatch(typeof(Humanoid), "StartAttack")] private static class Humanoid_StartAttack_Patch { [HarmonyPriority(700)] private static bool Prefix(Humanoid __instance, Character target, ref bool secondaryAttack, out StateResult __state, float ___m_timeSinceLastAttack, ref ItemData ___m_rightItem) { //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Invalid comparison between Unknown and I4 //IL_00a8: Unknown r