Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of ToolOfTheTrade v1.0.0
ToolOfTheTrade.dll
Decompiled 4 days 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.ComponentModel; using System.Diagnostics; using System.Globalization; using System.IO; using System.IO.Compression; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Serialization; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using System.Text.RegularExpressions; using BeastRunes.Registration; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using ItemManager; using JetBrains.Annotations; using Microsoft.CodeAnalysis; using ServerSync; using TMPro; using UnityEngine; using UnityEngine.Audio; using UnityEngine.EventSystems; using UnityEngine.Events; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: AssemblyTitle("ToolOfTheTrade")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("Yggdrah")] [assembly: AssemblyProduct("ToolOfTheTrade")] [assembly: AssemblyCopyright("Copyright \ufffd 2025")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("E0E2F92E-557C-4A05-9D89-AA92A0BD75C4")] [assembly: AssemblyFileVersion("1.0.0")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace BeastRunes { [BepInPlugin("Yggdrah.ToolOfTheTrade", "ToolOfTheTrade", "1.0.0")] public class BeastRunesPlugin : BaseUnityPlugin { private class ConfigurationManagerAttributes { public int? Order; public bool? Browsable; public string? Category; public Action<ConfigEntryBase>? CustomDrawer; } private class AcceptableShortcuts : AcceptableValueBase { public AcceptableShortcuts() : base(typeof(KeyboardShortcut)) { } public override object Clamp(object value) { return value; } public override bool IsValid(object value) { return true; } public override string ToDescriptionString() { return "# Acceptable values: " + string.Join(", ", UnityInput.Current.SupportedKeyCodes); } } internal const string ModName = "ToolOfTheTrade"; internal const string ModVersion = "1.0.0"; internal const string Author = "Yggdrah"; private const string ModGUID = "Yggdrah.ToolOfTheTrade"; private readonly Harmony _harmony = new Harmony("Yggdrah.ToolOfTheTrade"); internal static BeastRunesPlugin? context; public static readonly ManualLogSource BeastRunesLogger = Logger.CreateLogSource("ToolOfTheTrade"); public const string bundleName = "beastrunes"; private static readonly Dictionary<string, AssetBundle> _assetBundleCache = new Dictionary<string, AssetBundle>(); private static readonly string ConfigFileName = "Yggdrah.ToolOfTheTrade.cfg"; private static readonly string ConfigFileFullPath; private static readonly ConfigSync ConfigSync; internal static string ConnectionError; private static ConfigEntry<bool>? _serverConfigLocked; private const long RELOAD_DELAY = 10000000L; private FileSystemWatcher? _watcher; private DateTime _lastConfigReloadTime; private readonly object _reloadLock = new object(); public void Awake() { bool saveOnConfigSet = ((BaseUnityPlugin)this).Config.SaveOnConfigSet; ((BaseUnityPlugin)this).Config.SaveOnConfigSet = false; context = this; _serverConfigLocked = config("01 - ServerSync", "01 - Lock Configuration", value: true, "Whether to enable or disable if the configuration is locked in which only server admins can change"); ConfigSync.AddLockingConfigEntry<bool>(_serverConfigLocked); Config.RegisterAllConfigs(((BaseUnityPlugin)this).Config, "Yggdrah.ToolOfTheTrade"); Assembly executingAssembly = Assembly.GetExecutingAssembly(); _harmony.PatchAll(executingAssembly); SetupWatcher(); BeastRunes.Registration.Item.RegisterAll("beastrunes"); ((BaseUnityPlugin)this).Config.Save(); if (saveOnConfigSet) { ((BaseUnityPlugin)this).Config.SaveOnConfigSet = saveOnConfigSet; } BeastRunesLogger.LogInfo((object)"ToolOfTheTrade 1.0.0 loaded successfully."); BeastRunesLogger.LogInfo((object)"Using AssetBundle: beastrunes"); } private void OnDestroy() { SaveWithRespectToConfigSet(); _watcher?.Dispose(); _harmony.UnpatchSelf(); } public static AssetBundle? GetAssetBundle(string filename) { if (string.IsNullOrEmpty(filename)) { BeastRunesLogger.LogWarning((object)"Attempted to load an AssetBundle with an empty name."); return null; } if (_assetBundleCache.TryGetValue(filename, out AssetBundle value)) { return value; } AssetBundle val = ((IEnumerable<AssetBundle>)Resources.FindObjectsOfTypeAll<AssetBundle>()).FirstOrDefault((Func<AssetBundle, bool>)((AssetBundle a) => ((Object)a).name == filename)); if ((Object)(object)val != (Object)null) { _assetBundleCache[filename] = val; return val; } try { Assembly executingAssembly = Assembly.GetExecutingAssembly(); string text = executingAssembly.GetManifestResourceNames().FirstOrDefault((string str) => str.EndsWith(filename, StringComparison.OrdinalIgnoreCase)); if (text == null) { BeastRunesLogger.LogError((object)("Could not find embedded AssetBundle resource ending with '" + filename + "'.")); return null; } using Stream stream = executingAssembly.GetManifestResourceStream(text); if (stream == null) { BeastRunesLogger.LogError((object)("Could not open AssetBundle resource '" + text + "'.")); return null; } AssetBundle val2 = AssetBundle.LoadFromStream(stream); if ((Object)(object)val2 == (Object)null) { BeastRunesLogger.LogError((object)("AssetBundle.LoadFromStream failed for '" + filename + "'.")); return null; } _assetBundleCache[filename] = val2; BeastRunesLogger.LogInfo((object)("Loaded AssetBundle '" + filename + "' from '" + text + "'.")); return val2; } catch (Exception arg) { BeastRunesLogger.LogError((object)$"Failed loading AssetBundle '{filename}': {arg}"); return null; } } private void SetupWatcher() { _watcher = new FileSystemWatcher(Paths.ConfigPath, ConfigFileName); _watcher.Changed += ReadConfigValues; _watcher.Created += ReadConfigValues; _watcher.Renamed += ReadConfigValues; _watcher.IncludeSubdirectories = true; _watcher.SynchronizingObject = ThreadingHelper.SynchronizingObject; _watcher.EnableRaisingEvents = true; } private void ReadConfigValues(object sender, FileSystemEventArgs e) { DateTime now = DateTime.Now; long num = now.Ticks - _lastConfigReloadTime.Ticks; if (num < 10000000) { return; } lock (_reloadLock) { if (!File.Exists(ConfigFileFullPath)) { BeastRunesLogger.LogWarning((object)"Config file does not exist. Skipping reload."); return; } try { BeastRunesLogger.LogDebug((object)"Reloading configuration..."); SaveWithRespectToConfigSet(reload: true); BeastRunesLogger.LogInfo((object)"Configuration reload complete."); } catch (Exception ex) { BeastRunesLogger.LogError((object)("Error reloading configuration: " + ex.Message)); } } _lastConfigReloadTime = now; } private void SaveWithRespectToConfigSet(bool reload = false) { bool saveOnConfigSet = ((BaseUnityPlugin)this).Config.SaveOnConfigSet; ((BaseUnityPlugin)this).Config.SaveOnConfigSet = false; if (reload) { ((BaseUnityPlugin)this).Config.Reload(); } ((BaseUnityPlugin)this).Config.Save(); if (saveOnConfigSet) { ((BaseUnityPlugin)this).Config.SaveOnConfigSet = saveOnConfigSet; } } internal ConfigEntry<T> config<T>(string group, string name, T value, ConfigDescription description, bool synchronizedSetting = true) { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Expected O, but got Unknown ConfigDescription val = new ConfigDescription(description.Description + (synchronizedSetting ? " [Synced with Server]" : " [Not Synced with Server]"), description.AcceptableValues, description.Tags); ConfigEntry<T> val2 = ((BaseUnityPlugin)this).Config.Bind<T>(group, name, value, val); SyncedConfigEntry<T> syncedConfigEntry = ConfigSync.AddConfigEntry<T>(val2); syncedConfigEntry.SynchronizedConfig = synchronizedSetting; return val2; } internal ConfigEntry<T> config<T>(string group, string name, T value, string description, bool synchronizedSetting = true) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Expected O, but got Unknown return config(group, name, value, new ConfigDescription(description, (AcceptableValueBase)null, Array.Empty<object>()), synchronizedSetting); } static BeastRunesPlugin() { string configPath = Paths.ConfigPath; char directorySeparatorChar = Path.DirectorySeparatorChar; ConfigFileFullPath = configPath + directorySeparatorChar + ConfigFileName; ConfigSync = new ConfigSync("Yggdrah.ToolOfTheTrade") { DisplayName = "ToolOfTheTrade", CurrentVersion = "1.0.0", MinimumRequiredVersion = "1.0.0", ModRequired = false }; ConnectionError = ""; } } public static class KeyboardExtensions { public static bool IsKeyDown(this KeyboardShortcut shortcut) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) return (int)((KeyboardShortcut)(ref shortcut)).MainKey != 0 && Input.GetKeyDown(((KeyboardShortcut)(ref shortcut)).MainKey) && ((KeyboardShortcut)(ref shortcut)).Modifiers.All((Func<KeyCode, bool>)Input.GetKey); } public static bool IsKeyHeld(this KeyboardShortcut shortcut) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) return (int)((KeyboardShortcut)(ref shortcut)).MainKey != 0 && Input.GetKey(((KeyboardShortcut)(ref shortcut)).MainKey) && ((KeyboardShortcut)(ref shortcut)).Modifiers.All((Func<KeyCode, bool>)Input.GetKey); } } [HarmonyPatch(typeof(ZNet), "OnNewConnection")] public static class RegisterAndCheckVersion { private static void Prefix(ZNetPeer peer, ref ZNet __instance) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Expected O, but got Unknown peer.m_rpc.Register<ZPackage>("ToolOfTheTrade_VersionCheck", (Action<ZRpc, ZPackage>)RpcHandlers.RPC_WaitForMe_Version); ZPackage val = new ZPackage(); val.Write("1.0.0"); peer.m_rpc.Invoke("ToolOfTheTrade_VersionCheck", new object[1] { val }); } } [HarmonyPatch(typeof(ZNet), "RPC_PeerInfo")] public static class VerifyClient { private static bool Prefix(ZRpc rpc, ZPackage pkg, ref ZNet __instance) { if (!__instance.IsServer() || RpcHandlers.ValidatedPeers.Contains(rpc)) { return true; } rpc.Invoke("Error", new object[1] { 3 }); return false; } private static void Postfix(ZNet __instance) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Expected O, but got Unknown ZRoutedRpc.instance.InvokeRoutedRPC(ZRoutedRpc.instance.GetServerPeerID(), "RequestAdminSync", new object[1] { (object)new ZPackage() }); } } [HarmonyPatch(typeof(FejdStartup), "ShowConnectError")] public class ShowConnectionError { private static void Postfix(FejdStartup __instance) { if (__instance.m_connectionFailedPanel.activeSelf) { __instance.m_connectionFailedError.fontSizeMax = 25f; __instance.m_connectionFailedError.fontSizeMin = 15f; TMP_Text connectionFailedError = __instance.m_connectionFailedError; connectionFailedError.text = connectionFailedError.text + "\n" + BeastRunesPlugin.ConnectionError; } } } [HarmonyPatch(typeof(ZNet), "Disconnect")] public static class RemoveDisconnectedPeerFromVerified { private static void Prefix(ZNetPeer peer, ref ZNet __instance) { if (__instance.IsServer()) { RpcHandlers.ValidatedPeers.Remove(peer.m_rpc); } } } public static class RpcHandlers { public static readonly List<ZRpc> ValidatedPeers = new List<ZRpc>(); public static void RPC_WaitForMe_Version(ZRpc rpc, ZPackage pkg) { string text = pkg.ReadString(); if (text != "1.0.0") { BeastRunesPlugin.ConnectionError = "ToolOfTheTrade Installed: 1.0.0\n Needed: " + text; if (ZNet.instance.IsServer()) { rpc.Invoke("Error", new object[1] { 3 }); } } else if (ZNet.instance.IsServer()) { ValidatedPeers.Add(rpc); } } } } namespace BeastRunes.Registration { public static class Config { public static ConfigEntry<T> LocalConfig<T>(string section, string key, T defaultValue, string description) { if ((Object)(object)BeastRunesPlugin.context == (Object)null) { return null; } return ((BaseUnityPlugin)BeastRunesPlugin.context).Config.Bind<T>(section, key, defaultValue, description); } public static ConfigEntry<T> LocalConfig<T>(string section, string key, T defaultValue, ConfigDescription description) { if ((Object)(object)BeastRunesPlugin.context == (Object)null || ((BaseUnityPlugin)BeastRunesPlugin.context).Config == null) { return null; } return ((BaseUnityPlugin)BeastRunesPlugin.context).Config.Bind<T>(section, key, defaultValue, description); } public static ConfigEntry<T> SyncConfig<T>(string section, string key, T defaultValue, string description) { if ((Object)(object)BeastRunesPlugin.context == (Object)null) { return null; } return BeastRunesPlugin.context.config(section, key, defaultValue, description); } public static void RegisterAllConfigs(ConfigFile config, string modGuid) { } } public static class Item { public static ItemManager.Item? GoldBar_Yggg { get; private set; } public static ItemManager.Item? KnifeChitinGold { get; private set; } public static ItemManager.Item? KnifeSkollAndHatiGold { get; private set; } public static ItemManager.Item? Axe_Eikthyr_Ygg { get; private set; } public static ItemManager.Item? Golden_Hammer_Ygg { get; private set; } public static ItemManager.Item? Axe_Yggdrah_Ygg { get; private set; } public static ItemManager.Item? Belt_Gold_Ygg { get; private set; } public static ItemManager.Item? Belt_Silver_Ygg { get; private set; } public static ItemManager.Item? BeltOdin_Ygg { get; private set; } public static ItemManager.Item? CapeOdin_Ygg { get; private set; } public static ItemManager.Item? HelmetOdin_Ygg { get; private set; } public static ItemManager.Item? Ygg_pants { get; private set; } public static ItemManager.Item? DragonSlayer_Helm_Ygg { get; private set; } public static ItemManager.Item? DragonSlayer_Chest_Ygg { get; private set; } public static ItemManager.Item? DragonSlayer_Legs_Ygg { get; private set; } public static ItemManager.Item? KnifeStone_Ygg { get; private set; } public static void RegisterAll(string bundleName) { RegisterItems(bundleName); } private static void RegisterItems(string bundleName) { GoldBar_Yggg = new ItemManager.Item(bundleName, "GoldBar_Yggg"); GoldBar_Yggg.Name.English("Gold Bar"); GoldBar_Yggg.Crafting.Add(CraftingTable.Forge, 1); GoldBar_Yggg.RequiredItems.Add("Coins", 999); GoldBar_Yggg.CraftAmount = 1; KnifeChitinGold = new ItemManager.Item(bundleName, "KnifeChitinGold"); KnifeChitinGold.Name.English("Golden Abyssal Razor. (Indestructable)"); KnifeChitinGold.Crafting.Add(CraftingTable.Forge, 1); KnifeChitinGold.RequiredItems.Add("KnifeChitin", 1); KnifeChitinGold.RequiredItems.Add("GoldBar_Yggg", 1); KnifeChitinGold.CraftAmount = 1; KnifeSkollAndHatiGold = new ItemManager.Item(bundleName, "KnifeSkollAndHatiGold"); KnifeSkollAndHatiGold.Name.English("Golden Skoll and Hati. (Indestructable)"); KnifeSkollAndHatiGold.Crafting.Add(CraftingTable.BlackForge, 1); KnifeSkollAndHatiGold.RequiredItems.Add("KnifeChitinGold", 1); KnifeSkollAndHatiGold.RequiredItems.Add("KnifeSkollAndHati", 1); KnifeSkollAndHatiGold.RequiredItems.Add("GoldBar_Yggg", 2); KnifeSkollAndHatiGold.CraftAmount = 1; Axe_Eikthyr_Ygg = new ItemManager.Item(bundleName, "Axe_Eikthyr_Ygg"); Axe_Eikthyr_Ygg.Name.English("Forsaken Golden Artifact Tool. (Indestructable)"); Golden_Hammer_Ygg = new ItemManager.Item(bundleName, "Golden_Hammer_Ygg"); Golden_Hammer_Ygg.Name.English("Golden Indestructable Hammer"); KnifeStone_Ygg = new ItemManager.Item(bundleName, "KnifeStone_Ygg"); KnifeStone_Ygg.Name.English("Stone Knife"); KnifeStone_Ygg.Crafting.Add(CraftingTable.Inventory, 0); KnifeStone_Ygg.RequiredItems.Add("Stone", 3); KnifeStone_Ygg.CraftAmount = 1; Axe_Yggdrah_Ygg = new ItemManager.Item(bundleName, "Axe_Yggdrah_Ygg"); Axe_Yggdrah_Ygg.Name.English("Yggdrah's Golden Dual Axe"); Belt_Gold_Ygg = new ItemManager.Item(bundleName, "Belt_Gold_Ygg"); Belt_Gold_Ygg.Name.English("Golden Artifact Belt. (Indestructable)"); Belt_Silver_Ygg = new ItemManager.Item(bundleName, "Belt_Silver_Ygg"); Belt_Silver_Ygg.Name.English("Silver Megingjord"); Belt_Silver_Ygg.Crafting.Add(CraftingTable.Forge, 1); Belt_Silver_Ygg.RequiredItems.Add("BeltStrength", 1); Belt_Silver_Ygg.RequiredItems.Add("TrophyGoblinKing", 1); Belt_Silver_Ygg.RequiredItems.Add("Silver", 5); Belt_Silver_Ygg.CraftAmount = 1; BeltOdin_Ygg = new ItemManager.Item(bundleName, "BeltOdin_Ygg"); BeltOdin_Ygg.Name.English("Belt of Odin"); CapeOdin_Ygg = new ItemManager.Item(bundleName, "CapeOdin_Ygg"); CapeOdin_Ygg.Name.English("Cape of Odin"); HelmetOdin_Ygg = new ItemManager.Item(bundleName, "HelmetOdin_Ygg"); HelmetOdin_Ygg.Name.English("Hood of Odin"); Ygg_pants = new ItemManager.Item(bundleName, "Ygg_pants"); Ygg_pants.Name.English("Golden Indestructable Armor"); DragonSlayer_Helm_Ygg = new ItemManager.Item(bundleName, "DragonSlayer_Helm_Ygg"); DragonSlayer_Helm_Ygg.Name.English("Golden Indestructable Armor"); DragonSlayer_Chest_Ygg = new ItemManager.Item(bundleName, "DragonSlayer_Chest_Ygg"); DragonSlayer_Chest_Ygg.Name.English("Golden Indestructable Armor"); DragonSlayer_Legs_Ygg = new ItemManager.Item(bundleName, "DragonSlayer_Legs_Ygg"); DragonSlayer_Legs_Ygg.Name.English("Golden Indestructable Armor"); } } } namespace BeastRunes.Patches { internal static class GatherForagingSystem { private const float DefaultGatherDuration = 1.5f; private const float CopperKnifeDuration = 1.2f; private const float AbyssalRazorDuration = 1f; private const float GoldenAbyssalRazorDuration = 0.75f; private const float SilverKnifeDuration = 0.65f; private const float BlackMetalKnifeDuration = 0.5f; private const float SkollAndHatiDuration = 0.01f; private const float GoldenSkollAndHatiDuration = 0.01f; private const float MaxGatherDistance = 2.4f; private const float MoveCancelDistance = 0.3f; private const float MoveCancelThresholdSqr = 0.01f; private static ForageWorkSession _session; private static ItemData _gatherKnife; private static ItemData _originalWeapon; private static bool _knifeWasAutoEquipped; private static bool _equipmentCaptured; private static bool _knifeCheckedOutFromToolSlot; internal static bool AllowOriginalInteract { get; private set; } public static bool Active => _session != null && _session.Active; public static bool IsTarget(Pickable pickable) { return Active && _session != null && (Object)(object)_session.Target == (Object)(object)pickable; } public static bool IsSupportedForage(Pickable pickable) { if ((Object)(object)pickable == (Object)null || (Object)(object)((Component)pickable).gameObject == (Object)null) { return false; } string cleanName = GetCleanName(((Object)((Component)pickable).gameObject).name); if (string.IsNullOrEmpty(cleanName)) { return false; } return Matches(cleanName, "RaspberryBush") || Matches(cleanName, "BlueberryBush") || Matches(cleanName, "CloudberryBush") || Matches(cleanName, "Pickable_Raspberry") || Matches(cleanName, "Pickable_Blueberry") || Matches(cleanName, "Pickable_Cloudberry") || Matches(cleanName, "Mushroom") || Matches(cleanName, "MushroomYellow") || Matches(cleanName, "MushroomBlue") || Matches(cleanName, "Pickable_Mushroom") || Matches(cleanName, "Pickable_MushroomYellow") || Matches(cleanName, "Pickable_MushroomBlue") || Matches(cleanName, "Dandelion") || Matches(cleanName, "Pickable_Dandelion") || Matches(cleanName, "Thistle") || Matches(cleanName, "Pickable_Thistle"); } private static bool Matches(string actual, string expected) { return string.Equals(actual, expected, StringComparison.OrdinalIgnoreCase); } private static string GetCleanName(string name) { if (string.IsNullOrEmpty(name)) { return string.Empty; } int num = name.IndexOf("(Clone)", StringComparison.Ordinal); if (num >= 0) { name = name.Substring(0, num); } return name.Trim(); } private static string GetKnifePrefabName(ItemData knife) { if (knife == null) { return string.Empty; } try { if ((Object)(object)knife.m_dropPrefab != (Object)null) { return GetCleanName(((Object)knife.m_dropPrefab).name); } } catch { } return string.Empty; } private static float GetGatherDurationForKnife(ItemData knife) { if (IsSkollAndHatiKnife(knife)) { string knifePrefabName = GetKnifePrefabName(knife); return Matches(knifePrefabName, "KnifeSkollAndHatiGold") ? 0.01f : 0.01f; } string knifePrefabName2 = GetKnifePrefabName(knife); if (Matches(knifePrefabName2, "KnifeCopper")) { return 1.2f; } if (Matches(knifePrefabName2, "KnifeChitin")) { return 1f; } if (Matches(knifePrefabName2, "KnifeChitinGold")) { return 0.75f; } if (Matches(knifePrefabName2, "KnifeSilver")) { return 0.65f; } if (Matches(knifePrefabName2, "KnifeBlackMetal")) { return 0.5f; } if (Matches(knifePrefabName2, "KnifeSkollaAndHati")) { return 0.01f; } if (Matches(knifePrefabName2, "KnifeSkollAndHatiGold")) { return 0.01f; } return 1.5f; } private static bool IsSkollAndHatiKnife(ItemData knife) { if (knife == null) { return false; } string knifePrefabName = GetKnifePrefabName(knife); if (Matches(knifePrefabName, "KnifeSkollaAndHati") || Matches(knifePrefabName, "KnifeSkollAndHatiGold")) { return true; } try { string text = ((knife.m_shared != null) ? knife.m_shared.m_name : string.Empty); if (!string.IsNullOrEmpty(text)) { string text2 = text.ToLowerInvariant(); return text2.Contains("skoll") && text2.Contains("hati"); } } catch { } return false; } public static ItemData GetEquippedKnife(Player player) { if ((Object)(object)player == (Object)null) { return null; } ItemData currentWeapon = ((Humanoid)player).GetCurrentWeapon(); return IsUsableKnife(currentWeapon) ? currentWeapon : null; } public static ItemData FindUsableKnife(Player player) { if ((Object)(object)player == (Object)null) { return null; } ItemData val = ToolSlots.PeekKnife(); if (IsUsableKnife(val)) { return val; } return FindUsableKnifeFallback(player); } private static ItemData FindUsableKnifeFallback(Player player) { //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_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)player == (Object)null) { return null; } ItemData equippedKnife = GetEquippedKnife(player); if (equippedKnife != null) { return equippedKnife; } Inventory inventory = ((Humanoid)player).GetInventory(); if (inventory == null) { return null; } List<ItemData> allItems = inventory.GetAllItems(); if (allItems == null || allItems.Count == 0) { return null; } ItemData val = null; float num = float.MinValue; foreach (ItemData item in allItems) { if (IsUsableKnife(item)) { DamageTypes damages = item.m_shared.m_damages; float num2 = damages.m_slash + damages.m_pierce + damages.m_blunt; if (val == null || num2 > num) { val = item; num = num2; } } } return val; } private static bool IsUsableKnife(ItemData item) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Invalid comparison between Unknown and I4 if (item == null || item.m_shared == null) { return false; } return (int)item.m_shared.m_skillType == 2 && item.HavePrimaryAttack() && (!item.m_shared.m_useDurability || item.m_durability > 0f); } private static void CaptureOriginalEquipment(Player player) { _originalWeapon = null; _gatherKnife = null; _knifeWasAutoEquipped = false; _equipmentCaptured = false; _knifeCheckedOutFromToolSlot = false; if (!((Object)(object)player == (Object)null)) { _originalWeapon = ((Humanoid)player).GetCurrentWeapon(); _equipmentCaptured = true; } } private static ItemData GetOrEquipKnife(Player player) { if ((Object)(object)player == (Object)null) { return null; } _knifeCheckedOutFromToolSlot = false; ItemData val = null; ItemData item = ToolSlots.PeekKnife(); if (IsUsableKnife(item)) { val = ToolSlots.CheckoutKnife(player); if (val != null && IsUsableKnife(val)) { _knifeCheckedOutFromToolSlot = true; if (((Humanoid)player).GetCurrentWeapon() == val || ((Humanoid)player).IsItemEquiped(val) || ((Humanoid)player).EquipItem(val, true)) { _gatherKnife = val; _knifeWasAutoEquipped = true; return val; } ToolSlots.ReturnKnifeToSlot(player, val); _knifeCheckedOutFromToolSlot = false; val = null; } } val = FindUsableKnifeFallback(player); if (val == null) { return null; } _gatherKnife = val; if (((Humanoid)player).GetCurrentWeapon() == val || ((Humanoid)player).IsItemEquiped(val)) { return val; } Inventory inventory = ((Humanoid)player).GetInventory(); if (inventory == null || !inventory.ContainsItem(val)) { BeastRunesPlugin.BeastRunesLogger.LogWarning((object)"[GatherForaging] Inventory fallback knife was found but is no longer in the player's inventory."); _gatherKnife = null; return null; } ItemData currentWeapon = ((Humanoid)player).GetCurrentWeapon(); try { if (currentWeapon != null && currentWeapon != val && ((Humanoid)player).IsItemEquiped(currentWeapon)) { ((Humanoid)player).UnequipItem(currentWeapon, true); } if (!((Humanoid)player).EquipItem(val, true) && !((Humanoid)player).IsItemEquiped(val) && ((Humanoid)player).GetCurrentWeapon() != val) { if (currentWeapon != null && inventory.ContainsItem(currentWeapon)) { ((Humanoid)player).EquipItem(currentWeapon, true); } BeastRunesPlugin.BeastRunesLogger.LogWarning((object)("[GatherForaging] Failed equipping inventory fallback knife '" + val.m_shared.m_name + "'.")); _gatherKnife = null; return null; } } catch (Exception ex) { if (currentWeapon != null && inventory.ContainsItem(currentWeapon)) { try { ((Humanoid)player).EquipItem(currentWeapon, true); } catch { } } BeastRunesPlugin.BeastRunesLogger.LogWarning((object)("[GatherForaging] Inventory fallback knife equip failed: " + ex.Message)); _gatherKnife = null; return null; } _knifeWasAutoEquipped = true; BeastRunesPlugin.BeastRunesLogger.LogDebug((object)("[GatherForaging] Equipped inventory fallback knife '" + val.m_shared.m_name + "'.")); return val; } private static void ConsumeKnifeDurability(Player player, ItemData knife) { if ((Object)(object)player == (Object)null || knife == null || knife.m_shared == null || !knife.m_shared.m_useDurability) { return; } try { float num = knife.m_shared.m_useDurabilityDrain; if (num <= 0f) { num = 1f; } knife.m_durability = Mathf.Max(0f, knife.m_durability - num); if (knife.m_durability <= 0f && ((Humanoid)player).IsItemEquiped(knife)) { ((Humanoid)player).UnequipItem(knife, true); } } catch (Exception ex) { BeastRunesPlugin.BeastRunesLogger.LogDebug((object)("Could not consume knife durability after gathering: " + ex.Message)); } } private static void RestoreOriginalEquipment(Player player) { if (!_equipmentCaptured || !_knifeWasAutoEquipped || (Object)(object)player == (Object)null) { ClearEquipmentState(); return; } try { if (_gatherKnife != null && ((Humanoid)player).IsItemEquiped(_gatherKnife)) { ((Humanoid)player).UnequipItem(_gatherKnife, true); } if (_originalWeapon != null) { ((Humanoid)player).EquipItem(_originalWeapon, true); } } catch (Exception ex) { BeastRunesPlugin.BeastRunesLogger.LogDebug((object)("Could not restore previous weapon after gathering: " + ex.Message)); } if (_knifeCheckedOutFromToolSlot && _gatherKnife != null) { ToolSlots.ReturnKnifeToSlot(player, _gatherKnife); } ClearEquipmentState(); } private static void ClearEquipmentState() { _gatherKnife = null; _originalWeapon = null; _knifeWasAutoEquipped = false; _equipmentCaptured = false; _knifeCheckedOutFromToolSlot = false; } public static bool TryBeginFromIntercept(Pickable target, MethodBase originalMethod, object[] originalArguments, out bool result) { //IL_0244: Unknown result type (might be due to invalid IL or missing references) result = false; if (AllowOriginalInteract || (Object)(object)target == (Object)null || originalMethod == null || !IsSupportedForage(target)) { return false; } Player val = FindPlayerArgument(originalArguments); if ((Object)(object)val == (Object)null || (Object)(object)val != (Object)(object)Player.m_localPlayer) { return false; } if (HasHeldInteraction(originalArguments)) { result = false; return true; } if (IsTarget(target)) { Cancel(notify: false); result = true; return true; } if (!CanStart(val, target)) { result = true; return true; } if (Active) { Cancel(notify: false); } CaptureOriginalEquipment(val); ItemData orEquipKnife = GetOrEquipKnife(val); if (orEquipKnife == null) { ClearEquipmentState(); if ((Object)(object)MessageHud.instance != (Object)null) { MessageHud.instance.ShowMessage((MessageType)2, "You need a usable knife to gather this", 0, (Sprite)null, false, true); } result = true; return true; } float gatherDurationForKnife = GetGatherDurationForKnife(orEquipKnife); if (gatherDurationForKnife <= 0f) { try { AllowOriginalInteract = true; MethodInfo methodInfo = originalMethod as MethodInfo; if (methodInfo != null) { if (methodInfo.Invoke(target, CloneArguments(originalArguments)) is bool flag) { result = flag; } else { result = true; } ConsumeKnifeDurability(val, orEquipKnife); } else { result = true; } } catch (TargetInvocationException ex) { Exception arg = ex.InnerException ?? ex; BeastRunesPlugin.BeastRunesLogger.LogWarning((object)$"Instant gather failed: {arg}"); result = true; } catch (Exception arg2) { BeastRunesPlugin.BeastRunesLogger.LogWarning((object)$"Instant gather failed: {arg2}"); result = true; } finally { AllowOriginalInteract = false; GatherForagingHud.Hide(); RestoreOriginalEquipment(val); } return true; } _session = new ForageWorkSession(target, val, originalMethod, CloneArguments(originalArguments), gatherDurationForKnife, 2.4f, 0.3f, 0.01f); _session.Start(); ForagePlayerWorkPose.Begin(val, _session.LockPosition); if (IsSkollAndHatiKnife(orEquipKnife)) { GatherForagingHud.Hide(); } else { GatherForagingHud.Show(); } result = true; return true; } private static Player FindPlayerArgument(object[] args) { if (args == null) { return null; } for (int i = 0; i < args.Length; i++) { object obj = args[i]; Player val = (Player)((obj is Player) ? obj : null); if (val != null) { return val; } object obj2 = args[i]; Humanoid val2 = (Humanoid)((obj2 is Humanoid) ? obj2 : null); if (val2 != null) { Player val3 = (Player)(object)((val2 is Player) ? val2 : null); if ((Object)(object)val3 != (Object)null) { return val3; } } } return null; } private static bool HasHeldInteraction(object[] args) { if (args == null) { return false; } for (int i = 0; i < args.Length; i++) { if (args[i] is bool result) { return result; } } return false; } private static object[] CloneArguments(object[] args) { if (args == null) { return Array.Empty<object>(); } object[] array = new object[args.Length]; Array.Copy(args, array, args.Length); return array; } private static bool CanStart(Player player, Pickable target) { //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)player == (Object)null || (Object)(object)target == (Object)null) { return false; } if (((Character)player).IsDead() || ((Character)player).InAttack() || ((Character)player).InDodge() || ((Character)player).IsStaggering() || ((Character)player).IsKnockedBack()) { return false; } float num = Vector3.Distance(((Character)player).GetCenterPoint(), ((Component)target).transform.position); if (num > 2.4f) { if ((Object)(object)MessageHud.instance != (Object)null) { MessageHud.instance.ShowMessage((MessageType)2, "Move closer to gather", 0, (Sprite)null, false, true); } return false; } return true; } public static void Tick() { //IL_0029: Unknown result type (might be due to invalid IL or missing references) if (Active && _session != null) { ForagePlayerWorkPose.Tick(_session.Player, _session.LockPosition); ForageWorkSession.WorkState workState = _session.Tick(); GatherForagingHud.SetProgress(_session.Progress); switch (workState) { case ForageWorkSession.WorkState.Running: break; case ForageWorkSession.WorkState.Completed: CompleteCurrentSession(); break; case ForageWorkSession.WorkState.Cancelled: case ForageWorkSession.WorkState.Invalid: Cancel(notify: false); break; } } } private static void CompleteCurrentSession() { if (_session == null) { return; } ForageWorkSession session = _session; _session = null; GatherForagingHud.Hide(); ForagePlayerWorkPose.End(session.Player); ConsumeKnifeDurability(session.Player, _gatherKnife); RestoreOriginalEquipment(session.Player); string arg = (((Object)(object)session.Target != (Object)null && (Object)(object)((Component)session.Target).gameObject != (Object)null) ? GetCleanName(((Object)((Component)session.Target).gameObject).name) : "Unknown"); try { AllowOriginalInteract = true; session.InvokeOriginalInteraction(); } catch (TargetInvocationException ex) { Exception arg2 = ex.InnerException ?? ex; BeastRunesPlugin.BeastRunesLogger.LogWarning((object)$"Gather completion failed for '{arg}': {arg2}"); } catch (Exception arg3) { BeastRunesPlugin.BeastRunesLogger.LogWarning((object)$"Gather completion failed for '{arg}': {arg3}"); } finally { AllowOriginalInteract = false; } } public static void Cancel(bool notify) { if (_session == null) { GatherForagingHud.Hide(); return; } if (notify && (Object)(object)_session.Player != (Object)null && (Object)(object)MessageHud.instance != (Object)null) { MessageHud.instance.ShowMessage((MessageType)2, "Stopped gathering", 0, (Sprite)null, false, true); } string text = (((Object)(object)_session.Target != (Object)null && (Object)(object)((Component)_session.Target).gameObject != (Object)null) ? GetCleanName(((Object)((Component)_session.Target).gameObject).name) : "Unknown"); Player player = _session.Player; _session.Stop(); _session = null; GatherForagingHud.Hide(); ForagePlayerWorkPose.End(player); RestoreOriginalEquipment(player); } } internal sealed class ForageWorkSession { internal enum WorkState { Running, Completed, Cancelled, Invalid } private readonly MethodBase _originalMethod; private readonly object[] _originalArguments; private readonly float _duration; private readonly float _maxDistance; private readonly float _moveCancelDistance; private readonly float _moveCancelThresholdSqr; private float _startedAt; private Vector3 _startPosition; private bool _armedForUseCancel; private bool _stopped; public Pickable Target { get; } public Player Player { get; } public Vector3 LockPosition => _startPosition; public bool Active => !_stopped && (Object)(object)Target != (Object)null && (Object)(object)Player != (Object)null; public float Progress { get { if (!Active || _duration <= 0f) { return 0f; } return Mathf.Clamp01((Time.time - _startedAt) / _duration); } } public ForageWorkSession(Pickable target, Player player, MethodBase originalMethod, object[] originalArguments, float duration, float maxDistance, float moveCancelDistance, float moveCancelThresholdSqr) { Target = target; Player = player; _originalMethod = originalMethod; _originalArguments = originalArguments ?? Array.Empty<object>(); _duration = Mathf.Max(0f, duration); _maxDistance = Mathf.Max(0.5f, maxDistance); _moveCancelDistance = Mathf.Max(0.05f, moveCancelDistance); _moveCancelThresholdSqr = Mathf.Max(0f, moveCancelThresholdSqr); } public void Start() { //IL_002d: 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_0032: Unknown result type (might be due to invalid IL or missing references) _startedAt = Time.time; _startPosition = (((Object)(object)Player != (Object)null) ? ((Component)Player).transform.position : Vector3.zero); _armedForUseCancel = false; _stopped = false; } public void Stop() { _stopped = true; } public WorkState Tick() { if (_stopped) { return WorkState.Cancelled; } if (!StillValid()) { return WorkState.Invalid; } if (!_armedForUseCancel) { if (!ZInput.GetButton("Use")) { _armedForUseCancel = true; } } else if (ZInput.GetButtonDown("Use")) { return WorkState.Cancelled; } if (ZInput.GetButtonDown("Attack") || ZInput.GetButtonDown("SecondaryAttack")) { return WorkState.Cancelled; } if (Progress >= 1f) { return WorkState.Completed; } return WorkState.Running; } private bool StillValid() { //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Invalid comparison between Unknown and I4 //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)Target == (Object)null || (Object)(object)Player == (Object)null) { return false; } if ((Object)(object)Player != (Object)(object)Player.m_localPlayer || ((Character)Player).IsDead()) { return false; } ItemData currentWeapon = ((Humanoid)Player).GetCurrentWeapon(); if (currentWeapon == null || currentWeapon.m_shared == null || (int)currentWeapon.m_shared.m_skillType != 2 || (currentWeapon.m_shared.m_useDurability && currentWeapon.m_durability <= 0f)) { return false; } if (((Character)Player).InAttack() || ((Character)Player).InDodge() || ((Character)Player).IsStaggering() || ((Character)Player).IsKnockedBack()) { return false; } float num = Vector3.Distance(((Character)Player).GetCenterPoint(), ((Component)Target).transform.position); if (num > _maxDistance) { return false; } return true; } public object InvokeOriginalInteraction() { if (_originalMethod == null || (Object)(object)Target == (Object)null) { return null; } MethodInfo methodInfo = _originalMethod as MethodInfo; if (methodInfo == null) { return null; } return methodInfo.Invoke(Target, _originalArguments); } } internal static class ForagePlayerWorkPose { private const string StartSfxPrefab = "sfx_build_cultivator"; private static readonly MethodInfo SetCrouchMethod = AccessTools.Method(typeof(Player), "SetCrouch", new Type[1] { typeof(bool) }, (Type[])null); private static readonly FieldInfo PlayerCrouchField = AccessTools.Field(typeof(Player), "m_crouch"); private static readonly FieldInfo CharacterMoveDirField = AccessTools.Field(typeof(Character), "m_moveDir"); private static Player _activePlayer; public static void Begin(Player player, Vector3 lockPosition) { //IL_0035: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)player == (Object)null) && !((Object)(object)player != (Object)(object)Player.m_localPlayer)) { _activePlayer = player; PlayStartSfx(player); ForceCrouch(player, crouch: true); LockMovement(player, lockPosition); } } public static void Tick(Player player, Vector3 lockPosition) { //IL_0035: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)player == (Object)null) && !((Object)(object)player != (Object)(object)Player.m_localPlayer) && !((Object)(object)player != (Object)(object)_activePlayer)) { ForceCrouch(player, crouch: true); LockMovement(player, lockPosition); } } public static void End(Player player) { //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)player == (Object)null) { _activePlayer = null; return; } ForceCrouch(player, crouch: false); Rigidbody component = ((Component)player).GetComponent<Rigidbody>(); if ((Object)(object)component != (Object)null) { Vector3 velocity = component.velocity; velocity.x = 0f; velocity.z = 0f; component.velocity = velocity; } _activePlayer = null; } private static void PlayStartSfx(Player player) { //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) try { if (!((Object)(object)ZNetScene.instance == (Object)null)) { GameObject prefab = ZNetScene.instance.GetPrefab("sfx_build_cultivator"); if ((Object)(object)prefab == (Object)null) { BeastRunesPlugin.BeastRunesLogger.LogWarning((object)"Could not find forage start SFX prefab 'sfx_build_cultivator'."); } else { Object.Instantiate<GameObject>(prefab, ((Component)player).transform.position, Quaternion.identity); } } } catch (Exception ex) { BeastRunesPlugin.BeastRunesLogger.LogDebug((object)("Forage start SFX could not play: " + ex.Message)); } } private static void ForceCrouch(Player player, bool crouch) { if ((Object)(object)player == (Object)null) { return; } try { if (SetCrouchMethod != null) { SetCrouchMethod.Invoke(player, new object[1] { crouch }); } else if (PlayerCrouchField != null) { PlayerCrouchField.SetValue(player, crouch); } } catch (Exception ex) { BeastRunesPlugin.BeastRunesLogger.LogDebug((object)("Could not force harvesting crouch state: " + ex.Message)); } } private static void LockMovement(Player player, Vector3 lockPosition) { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)player == (Object)null) { return; } try { if (CharacterMoveDirField != null) { CharacterMoveDirField.SetValue(player, Vector3.zero); } Rigidbody component = ((Component)player).GetComponent<Rigidbody>(); if ((Object)(object)component != (Object)null) { Vector3 velocity = component.velocity; velocity.x = 0f; velocity.z = 0f; component.velocity = velocity; } Vector3 position = ((Component)player).transform.position; position.x = lockPosition.x; position.z = lockPosition.z; ((Component)player).transform.position = position; } catch (Exception ex) { BeastRunesPlugin.BeastRunesLogger.LogDebug((object)("Could not lock player during harvesting: " + ex.Message)); } } } internal static class GatherForagingHud { private static GatherForagingHudBehaviour _behaviour; public static void Show() { EnsureCreated(); if ((Object)(object)_behaviour != (Object)null) { _behaviour.Show(); } } public static void Hide() { if ((Object)(object)_behaviour != (Object)null) { _behaviour.Hide(); } } public static void SetProgress(float progress) { EnsureCreated(); if ((Object)(object)_behaviour != (Object)null) { _behaviour.SetProgress(progress); } } public static void Preload() { EnsureCreated(); } private static void EnsureCreated() { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Expected O, but got Unknown if (!((Object)(object)_behaviour != (Object)null)) { GameObject val = new GameObject("BeastRunes_GatherForagingHud"); Object.DontDestroyOnLoad((Object)(object)val); _behaviour = val.AddComponent<GatherForagingHudBehaviour>(); } } } internal sealed class GatherForagingHudBehaviour : MonoBehaviour { private const int TextureSize = 160; private const float RingSize = 58f; private bool _visible; private float _progress; private Texture2D _backgroundRing; private Texture2D _progressRing; private float _lastRenderedProgress = -1f; private Color _lastRenderedColor = Color.clear; private readonly Color _backgroundColor = new Color(1f, 1f, 1f, 0.16f); private readonly Color _startColor = new Color(0.24f, 0.95f, 0.34f, 1f); private readonly Color _endColor = new Color(0.24f, 0.95f, 0.34f, 0.08f); private void Awake() { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) _backgroundRing = CreateRingTexture(1f, Color.white); _progressRing = CreateEmptyTexture("BeastRunes_GatherProgressRing"); RebuildProgressRing(0f, _startColor); } private Texture2D CreateEmptyTexture(string name) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Expected O, but got Unknown Texture2D val = new Texture2D(160, 160, (TextureFormat)4, false); ((Object)val).name = name; ((Texture)val).wrapMode = (TextureWrapMode)1; ((Texture)val).filterMode = (FilterMode)1; return val; } private void OnDestroy() { DestroyTexture(_backgroundRing); DestroyTexture(_progressRing); } private static void DestroyTexture(Texture2D texture) { if ((Object)(object)texture != (Object)null) { Object.Destroy((Object)(object)texture); } } public void Show() { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) _progress = 0f; _lastRenderedProgress = -1f; _lastRenderedColor = Color.clear; _visible = true; RebuildProgressRing(0f, _startColor); } public void Hide() { _visible = false; _progress = 0f; } public void SetProgress(float progress) { _progress = Mathf.Clamp01(progress); } private void OnGUI() { //IL_001d: 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_003c: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_0105: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) if (_visible) { Color progressColor = GetProgressColor(_progress); if (Mathf.Abs(_progress - _lastRenderedProgress) >= 0.01f || progressColor != _lastRenderedColor || _progress >= 0.999f) { RebuildProgressRing(_progress, progressColor); } Vector2 val = default(Vector2); ((Vector2)(ref val))..ctor((float)Screen.width * 0.5f, (float)Screen.height * 0.5f); Rect val2 = default(Rect); ((Rect)(ref val2))..ctor(val.x - 29f, val.y - 29f, 58f, 58f); Color color = GUI.color; Matrix4x4 matrix = GUI.matrix; GUI.color = _backgroundColor; GUI.DrawTexture(val2, (Texture)(object)_backgroundRing, (ScaleMode)2, true); GUI.color = Color.white; GUI.DrawTexture(val2, (Texture)(object)_progressRing, (ScaleMode)2, true); GUI.matrix = matrix; GUI.color = color; } } private Texture2D CreateRingTexture(float fill, Color color) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) Texture2D val = CreateEmptyTexture("BeastRunes_GatherRing"); PaintArc(val, fill, color); return val; } private Color GetProgressColor(float progress) { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0035: 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_003d: Unknown result type (might be due to invalid IL or missing references) float num = Mathf.Clamp01(progress); float num2 = Mathf.SmoothStep(0f, 1f, Mathf.InverseLerp(0.45f, 1f, num)); return Color.Lerp(_startColor, _endColor, num2); } private void RebuildProgressRing(float progress, Color color) { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_progressRing == (Object)null)) { PaintRemainingArc(_progressRing, Mathf.Clamp01(progress), color); _lastRenderedProgress = progress; _lastRenderedColor = color; } } private static void PaintArc(Texture2D texture, float fillAmount, Color color) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) PaintRingInternal(texture, Mathf.Clamp01(fillAmount), color, paintRemaining: false); } private static void PaintRemainingArc(Texture2D texture, float progress, Color color) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) PaintRingInternal(texture, Mathf.Clamp01(progress), color, paintRemaining: true); } private static void PaintRingInternal(Texture2D texture, float amount, Color color, bool paintRemaining) { //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_01c0: Unknown result type (might be due to invalid IL or missing references) //IL_01c1: Unknown result type (might be due to invalid IL or missing references) //IL_01d9: Unknown result type (might be due to invalid IL or missing references) //IL_01db: Unknown result type (might be due to invalid IL or missing references) //IL_01e0: Unknown result type (might be due to invalid IL or missing references) //IL_01b4: Unknown result type (might be due to invalid IL or missing references) //IL_01b9: Unknown result type (might be due to invalid IL or missing references) int width = ((Texture)texture).width; float num = (float)(width - 1) * 0.5f; float num2 = (float)width * 0.47f; float num3 = (float)width * 0.365f; float num4 = 2.4f; Color32[] array = (Color32[])(object)new Color32[width * width]; float num5 = Mathf.Clamp01(amount); for (int i = 0; i < width; i++) { for (int j = 0; j < width; j++) { float num6 = (float)j - num; float num7 = (float)i - num; float num8 = Mathf.Sqrt(num6 * num6 + num7 * num7); float num9 = Mathf.Clamp01((num2 - num8) / num4); float num10 = Mathf.Clamp01((num8 - num3) / num4); float num11 = Mathf.Min(num9, num10); if (num11 <= 0f) { array[i * width + j] = new Color32(byte.MaxValue, byte.MaxValue, byte.MaxValue, (byte)0); continue; } float num12 = Mathf.Atan2(num7, num6) * 57.29578f; for (num12 = 0f - num12 + 90f; num12 < 0f; num12 += 360f) { } while (num12 >= 360f) { num12 -= 360f; } float num13 = num12 / 360f; bool flag; if (paintRemaining) { flag = num13 > num5; if (num5 <= 0.0001f) { flag = true; } if (num5 >= 0.9999f) { flag = false; } } else { flag = num5 >= 0.9999f || num13 <= num5; } if (!flag) { array[i * width + j] = new Color32(byte.MaxValue, byte.MaxValue, byte.MaxValue, (byte)0); continue; } Color val = color; val.a *= num11; array[i * width + j] = Color32.op_Implicit(val); } } texture.SetPixels32(array); texture.Apply(false, false); } } [HarmonyPatch(typeof(Pickable), "Interact", new Type[] { typeof(Humanoid), typeof(bool), typeof(bool) })] internal static class BeastRunes_Pickable_Interact_GatherForagingPatch { private static bool Prefix(Pickable __instance, Humanoid __0, bool __1, bool __2, ref bool __result, MethodBase __originalMethod) { if (GatherForagingSystem.AllowOriginalInteract) { return true; } bool flag = __1; bool flag2 = __2; if ((Object)(object)__instance == (Object)null || !GatherForagingSystem.IsSupportedForage(__instance)) { return true; } Player val = (Player)(object)((__0 is Player) ? __0 : null); if ((Object)(object)val == (Object)null || (Object)(object)val != (Object)(object)Player.m_localPlayer) { return true; } if (flag || flag2) { __result = false; return false; } object[] originalArguments = new object[3] { __0, flag, flag2 }; if (!GatherForagingSystem.TryBeginFromIntercept(__instance, __originalMethod, originalArguments, out var result)) { return true; } __result = result; return false; } } [HarmonyPatch(typeof(Pickable), "GetHoverText")] internal static class BeastRunes_Pickable_GetHoverText_GatherForagingPatch { private static void Postfix(Pickable __instance, ref string __result) { if (!((Object)(object)__instance == (Object)null) && GatherForagingSystem.IsSupportedForage(__instance)) { string hoverName; try { hoverName = __instance.GetHoverName(); } catch { return; } string text = (GatherForagingSystem.IsTarget(__instance) ? "Stop gathering" : ((GatherForagingSystem.FindUsableKnife(Player.m_localPlayer) != null) ? "Gather" : "Need a knife")); __result = Localization.instance.Localize(hoverName + "\n[<color=yellow><b>$KEY_Use</b></color>] " + text); } } } [HarmonyPatch(typeof(Player), "Update")] internal static class BeastRunes_Player_Update_GatherForagingPatch { private static void Postfix(Player __instance) { if (!((Object)(object)__instance == (Object)null) && !((Object)(object)__instance != (Object)(object)Player.m_localPlayer)) { GatherForagingSystem.Tick(); } } } [HarmonyPatch(typeof(ZNetScene), "Awake")] [HarmonyPriority(0)] internal static class BeastRunes_ZNetScene_Awake_GatherForagingPatch { private static void Postfix() { GatherForagingHud.Preload(); BeastRunesPlugin.BeastRunesLogger.LogInfo((object)"GatherForagingSystem work-session patch ready."); } } [HarmonyPatch(typeof(Player), "OnDestroy")] internal static class BeastRunes_Player_Destroy_GatherForagingPatch { private static void Prefix(Player __instance) { if ((Object)(object)__instance == (Object)(object)Player.m_localPlayer) { GatherForagingSystem.Cancel(notify: false); } } } public static class GoldenHammerPatch { [HarmonyPatch(typeof(ObjectDB), "Awake")] private static class ObjectDB_Awake_Patch { [HarmonyPostfix] private static void Postfix(ObjectDB __instance) { TryConfigure(__instance, "ObjectDB.Awake"); } } [HarmonyPatch(typeof(ZNetScene), "Awake")] private static class ZNetScene_Awake_Patch { [HarmonyPostfix] private static void Postfix() { TryConfigure(ObjectDB.instance, "ZNetScene.Awake"); } } private const string GoldenHammerPrefabName = "Golden_Hammer_Ygg"; private const string VanillaHammerPrefabName = "Hammer"; private static bool _configured; private static void TryConfigure(ObjectDB objectDb, string source) { //IL_019c: Unknown result type (might be due to invalid IL or missing references) if (_configured) { return; } try { if ((Object)(object)objectDb == (Object)null) { BeastRunesPlugin.BeastRunesLogger.LogDebug((object)("[GoldenHammer] ObjectDB was null during " + source + ".")); return; } GameObject itemPrefab = objectDb.GetItemPrefab("Golden_Hammer_Ygg"); GameObject itemPrefab2 = objectDb.GetItemPrefab("Hammer"); if ((Object)(object)itemPrefab == (Object)null) { BeastRunesPlugin.BeastRunesLogger.LogDebug((object)("[GoldenHammer] Golden_Hammer_Ygg not found yet during " + source + "; will retry later.")); return; } if ((Object)(object)itemPrefab2 == (Object)null) { BeastRunesPlugin.BeastRunesLogger.LogWarning((object)("[GoldenHammer] Could not find vanilla Hammer during " + source + ".")); return; } ItemDrop component = itemPrefab.GetComponent<ItemDrop>(); ItemDrop component2 = itemPrefab2.GetComponent<ItemDrop>(); if ((Object)(object)component == (Object)null) { BeastRunesPlugin.BeastRunesLogger.LogWarning((object)"[GoldenHammer] Golden_Hammer_Ygg has no ItemDrop component."); return; } if ((Object)(object)component2 == (Object)null) { BeastRunesPlugin.BeastRunesLogger.LogWarning((object)"[GoldenHammer] Vanilla Hammer has no ItemDrop component."); return; } if (component.m_itemData == null || component2.m_itemData == null) { BeastRunesPlugin.BeastRunesLogger.LogWarning((object)"[GoldenHammer] One of the hammer ItemData objects was null."); return; } SharedData shared = component.m_itemData.m_shared; SharedData shared2 = component2.m_itemData.m_shared; if (shared == null) { BeastRunesPlugin.BeastRunesLogger.LogWarning((object)"[GoldenHammer] Golden Hammer SharedData was null."); return; } if (shared2 == null) { BeastRunesPlugin.BeastRunesLogger.LogWarning((object)"[GoldenHammer] Vanilla Hammer SharedData was null."); return; } shared.m_itemType = (ItemType)19; shared.m_buildPieces = shared2.m_buildPieces; if ((Object)(object)shared.m_buildPieces == (Object)null) { BeastRunesPlugin.BeastRunesLogger.LogWarning((object)"[GoldenHammer] Vanilla Hammer PieceTable was null."); return; } if (shared.m_attack != null && shared2.m_attack != null) { shared.m_attack.m_attackAnimation = shared2.m_attack.m_attackAnimation; } if (shared.m_secondaryAttack != null && shared2.m_secondaryAttack != null) { shared.m_secondaryAttack.m_attackAnimation = shared2.m_secondaryAttack.m_attackAnimation; } if (shared.m_attack != null) { shared.m_attack.m_attackStamina = 0f; } if (shared.m_secondaryAttack != null) { shared.m_secondaryAttack.m_attackStamina = 0f; } shared.m_useDurability = false; _configured = true; BeastRunesPlugin.BeastRunesLogger.LogInfo((object)("[GoldenHammer] Golden_Hammer_Ygg configured successfully during " + source + ".")); BeastRunesPlugin.BeastRunesLogger.LogInfo((object)"[GoldenHammer] Vanilla Hammer PieceTable applied."); BeastRunesPlugin.BeastRunesLogger.LogInfo((object)"[GoldenHammer] Stamina cost: 0."); BeastRunesPlugin.BeastRunesLogger.LogInfo((object)"[GoldenHammer] Durability usage disabled."); } catch (Exception arg) { BeastRunesPlugin.BeastRunesLogger.LogError((object)$"[GoldenHammer] Failed to configure during {source}: {arg}"); } } } internal static class MinePickingSystem { private static ConfigEntry<bool> _enableAutoMining; private static ConfigEntry<float> _minePickingMaximumDistance; private static readonly Collider[] NearbyColliders = (Collider[])(object)new Collider[64]; private static MinePickingInteraction _target; private static Collider _collider; private static Vector3 _localSurfacePoint; private static Player _player; private static ItemData _pickaxe; private static ItemData _originalWeapon; private static bool _pickaxeWasAutoEquipped; private static bool _equipmentCaptured; private static bool _pickaxeCheckedOutFromToolSlot; private static bool _armedForCancel; private static float _nextAttackAttempt; private static float _firstFailedAttempt = -1f; private static float _retargetDeadline = -1f; private const float RetargetGraceSeconds = 1.5f; internal static bool AutoMiningEnabled { get { EnsureConfig(); return _enableAutoMining == null || _enableAutoMining.Value; } } private static float ConfiguredInteractionReach { get { EnsureConfig(); return (_minePickingMaximumDistance != null) ? _minePickingMaximumDistance.Value : 1.1f; } } public static bool Active => (Object)(object)_player != (Object)null && _pickaxe != null; private static void EnsureConfig() { if (!((Object)(object)BeastRunesPlugin.context == (Object)null)) { if (_enableAutoMining == null) { _enableAutoMining = BeastRunesPlugin.context.config("Auto Mining", "Enable Auto Mining", value: true, "Enable Press-E automatic pickaxe mining."); } if (_minePickingMaximumDistance == null) { _minePickingMaximumDistance = BeastRunesPlugin.context.config("Auto Mining", "Maximum Interaction Distance", 1.1f, "Maximum distance from a mineable node to start automatic mining."); } } } public static bool IsTarget(MinePickingInteraction target) { return Active && (Object)(object)target != (Object)null && (Object)(object)_target != (Object)null && (Object)(object)_target == (Object)(object)target; } public static ItemData GetEquippedPickaxe(Player player) { if ((Object)(object)player == (Object)null) { return null; } ItemData currentWeapon = ((Humanoid)player).GetCurrentWeapon(); return IsUsablePickaxe(currentWeapon) ? currentWeapon : null; } public static ItemData FindUsablePickaxe(Player player) { if ((Object)(object)player == (Object)null) { return null; } ItemData val = ToolSlots.PeekPickaxe(); if (IsUsablePickaxe(val)) { return val; } return FindUsablePickaxeFallback(player); } private static ItemData FindUsablePickaxeFallback(Player player) { if ((Object)(object)player == (Object)null) { return null; } ItemData equippedPickaxe = GetEquippedPickaxe(player); if (equippedPickaxe != null) { return equippedPickaxe; } Inventory inventory = ((Humanoid)player).GetInventory(); if (inventory == null) { return null; } List<ItemData> allItems = inventory.GetAllItems(); if (allItems == null || allItems.Count == 0) { return null; } ItemData val = null; float num = float.MinValue; foreach (ItemData item in allItems) { if (IsUsablePickaxe(item)) { float pickaxe = item.m_shared.m_damages.m_pickaxe; if (val == null || pickaxe > num) { val = item; num = pickaxe; } } } return val; } public static ItemData GetOrEquipPickaxe(Player player) { if ((Object)(object)player == (Object)null) { return null; } _pickaxeCheckedOutFromToolSlot = false; ItemData val = null; ItemData item = ToolSlots.PeekPickaxe(); if (IsUsablePickaxe(item)) { val = ToolSlots.CheckoutPickaxe(player); if (val != null && IsUsablePickaxe(val)) { _pickaxeCheckedOutFromToolSlot = true; if (((Humanoid)player).GetCurrentWeapon() == val || ((Humanoid)player).IsItemEquiped(val) || ((Humanoid)player).EquipItem(val, true)) { _pickaxeWasAutoEquipped = true; return val; } ToolSlots.ReturnPickaxeToSlot(player, val); _pickaxeCheckedOutFromToolSlot = false; val = null; } } val = FindUsablePickaxeFallback(player); if (val == null) { return null; } if (((Humanoid)player).GetCurrentWeapon() == val || ((Humanoid)player).IsItemEquiped(val)) { return val; } Inventory inventory = ((Humanoid)player).GetInventory(); if (inventory == null || !inventory.ContainsItem(val)) { BeastRunesPlugin.BeastRunesLogger.LogWarning((object)"[MinePicking] Inventory fallback pickaxe was found but is no longer in the player's inventory."); return null; } ItemData currentWeapon = ((Humanoid)player).GetCurrentWeapon(); try { if (currentWeapon != null && currentWeapon != val && ((Humanoid)player).IsItemEquiped(currentWeapon)) { ((Humanoid)player).UnequipItem(currentWeapon, true); } if (!((Humanoid)player).EquipItem(val, true) && !((Humanoid)player).IsItemEquiped(val) && ((Humanoid)player).GetCurrentWeapon() != val) { if (currentWeapon != null && inventory.ContainsItem(currentWeapon)) { ((Humanoid)player).EquipItem(currentWeapon, true); } BeastRunesPlugin.BeastRunesLogger.LogWarning((object)("[MinePicking] Failed equipping inventory fallback pickaxe '" + val.m_shared.m_name + "'.")); return null; } } catch (Exception ex) { if (currentWeapon != null && inventory.ContainsItem(currentWeapon)) { try { ((Humanoid)player).EquipItem(currentWeapon, true); } catch { } } BeastRunesPlugin.BeastRunesLogger.LogWarning((object)("[MinePicking] Inventory fallback pickaxe equip failed: " + ex.Message)); return null; } _pickaxeWasAutoEquipped = true; BeastRunesPlugin.BeastRunesLogger.LogDebug((object)("[MinePicking] Equipped inventory fallback pickaxe '" + val.m_shared.m_name + "'.")); return val; } public static void CaptureOriginalEquipment(Player player) { _originalWeapon = null; _pickaxeWasAutoEquipped = false; _equipmentCaptured = false; _pickaxeCheckedOutFromToolSlot = false; if (!((Object)(object)player == (Object)null)) { _originalWeapon = ((Humanoid)player).GetCurrentWeapon(); _equipmentCaptured = true; } } private static void RestoreOriginalEquipment(Player player) { if (!_equipmentCaptured || !_pickaxeWasAutoEquipped || (Object)(object)player == (Object)null) { ClearEquipmentState(); return; } try { if (_pickaxe != null && ((Humanoid)player).IsItemEquiped(_pickaxe)) { ((Humanoid)player).UnequipItem(_pickaxe, true); } if (_originalWeapon != null) { ((Humanoid)player).EquipItem(_originalWeapon, true); } } catch (Exception ex) { BeastRunesPlugin.BeastRunesLogger.LogDebug((object)("Could not restore previous weapon after mining: " + ex.Message)); } if (_pickaxeCheckedOutFromToolSlot && _pickaxe != null) { ToolSlots.ReturnPickaxeToSlot(player, _pickaxe); } ClearEquipmentState(); } private static void ClearEquipmentState() { _originalWeapon = null; _pickaxeWasAutoEquipped = false; _equipmentCaptured = false; _pickaxeCheckedOutFromToolSlot = false; } private static bool IsUsablePickaxe(ItemData item) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Invalid comparison between Unknown and I4 if (item == null || item.m_shared == null) { return false; } return (int)item.m_shared.m_skillType == 12 && item.m_shared.m_damages.m_pickaxe > 0f && item.HavePrimaryAttack() && (!item.m_shared.m_useDurability || item.m_durability > 0f); } private static float GetInteractionReach() { float configuredInteractionReach = ConfiguredInteractionReach; return Mathf.Clamp(configuredInteractionReach, 0.5f, 4f); } public static bool IsColliderNearby(Player player, Collider collider) { //IL_0029: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)player == (Object)null || (Object)(object)collider == (Object)null || !collider.enabled) { return false; } int num = Physics.OverlapSphereNonAlloc(((Character)player).GetCenterPoint(), GetInteractionReach(), NearbyColliders, -1, (QueryTriggerInteraction)1); for (int i = 0; i < num; i++) { if ((Object)(object)NearbyColliders[i] == (Object)(object)collider) { return true; } } return false; } public static bool TryGetCrosshairPoint(Player player, Collider collider, out Vector3 point) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0018: 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_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0020: 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_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) Vector3 val; if (!((Object)(object)collider != (Object)null)) { val = Vector3.zero; } else { Bounds bounds = collider.bounds; val = ((Bounds)(ref bounds)).center; } point = val; if ((Object)(object)player == (Object)null || (Object)(object)collider == (Object)null || !collider.enabled || (Object)(object)GameCamera.instance == (Object)null) { return false; } Transform transform = ((Component)GameCamera.instance).transform; Ray val2 = default(Ray); ((Ray)(ref val2))..ctor(transform.position, transform.forward); RaycastHit val3 = default(RaycastHit); if (!collider.Raycast(val2, ref val3, 50f)) { return false; } point = ((RaycastHit)(ref val3)).point; return true; } public static void Begin(MinePickingInteraction target, Collider collider, Vector3 surfacePoint, Player player, ItemData pickaxe) { //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)target == (Object)null) && !((Object)(object)collider == (Object)null) && !((Object)(object)player == (Object)null) && pickaxe != null) { if (Active) { Cancel(notify: false); } _target = target; _collider = collider; _localSurfacePoint = ((Component)collider).transform.InverseTransformPoint(surfacePoint); _player = player; _pickaxe = pickaxe; _armedForCancel = false; _nextAttackAttempt = 0f; _firstFailedAttempt = -1f; _retargetDeadline = -1f; BeastRunesPlugin.BeastRunesLogger.LogInfo((object)("Started mining '" + ((Object)((Component)target).gameObject).name + "' with '" + pickaxe.m_shared.m_name + "'.")); } } public static void Tick() { if (!Active) { return; } if (!CanContinueMiningSession()) { Cancel(notify: false); return; } if (!HasValidCurrentTarget()) { if (_retargetDeadline < 0f) { _retargetDeadline = Time.time + 1.5f; } if (!TryRetargetMineable()) { if (Time.time >= _retargetDeadline) { Cancel(notify: false); } return; } _retargetDeadline = -1f; } else { _retargetDeadline = -1f; } if (!StillValid()) { Cancel(notify: false); return; } if (!_armedForCancel) { if (!ZInput.GetButton("Use")) { _armedForCancel = true; } } else if (ZInput.GetButtonDown("Use")) { Cancel(notify: false); return; } if (ZInput.GetButtonDown("Attack")) { Cancel(notify: false); } else { if (((Character)_player).InAttack() || Time.time < _nextAttackAttempt) { return; } FaceTarget(); bool flag = ((Character)_player).StartAttack((Character)null, false); _nextAttackAttempt = Time.time + 0.12f; if (flag) { _firstFailedAttempt = -1f; return; } if (_firstFailedAttempt < 0f) { _firstFailedAttempt = Time.time; } if (Time.time - _firstFailedAttempt > 1f) { if ((Object)(object)MessageHud.instance != (Object)null) { MessageHud.instance.ShowMessage((MessageType)2, "Unable to continue mining", 0, (Sprite)null, false, true); } Cancel(notify: false); } } } private static bool CanContinueMiningSession() { //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_player == (Object)null || _pickaxe == null) { return false; } if (!AutoMiningEnabled) { return false; } if ((Object)(object)_player != (Object)(object)Player.m_localPlayer || ((Character)_player).IsDead()) { return false; } if (((Humanoid)_player).GetCurrentWeapon() != _pickaxe || !IsUsablePickaxe(_pickaxe)) { return false; } if (((Character)_player).InDodge() || ((Character)_player).IsStaggering() || ((Character)_player).IsKnockedBack()) { return false; } Vector3 moveDir = ((Character)_player).GetMoveDir(); if (((Vector3)(ref moveDir)).sqrMagnitude > 0.01f) { return false; } return true; } private static bool HasValidCurrentTarget() { return (Object)(object)_target != (Object)null && (Object)(object)_collider != (Object)null && _collider.enabled && _target.IsAvailable() && IsColliderNearby(_player, _collider); } private static bool TryRetargetMineable() { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_017c: Unknown result type (might be due to invalid IL or missing references) //IL_017e: Unknown result type (might be due to invalid IL or missing references) //IL_0183: Unknown result type (might be due to invalid IL or missing references) //IL_0165: Unknown result type (might be due to invalid IL or missing references) //IL_016a: Unknown result type (might be due to invalid IL or missing references) //IL_016f: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_player == (Object)null) { return false; } int num = Physics.OverlapSphereNonAlloc(((Character)_player).GetCenterPoint(), GetInteractionReach(), NearbyColliders, -1, (QueryTriggerInteraction)1); MinePickingInteraction minePickingInteraction = null; Collider val = null; float num2 = float.MaxValue; for (int i = 0; i < num; i++) { Collider val2 = NearbyColliders[i]; if ((Object)(object)val2 == (Object)null || !val2.enabled) { continue; } MinePickingInteractionPoint component = ((Component)val2).GetComponent<MinePickingInteractionPoint>(); if (!((Object)(object)component == (Object)null) && !((Object)(object)component.Target == (Object)null) && component.Target.IsAvailable()) { Bounds bounds = val2.bounds; Vector3 val3 = ((Bounds)(ref bounds)).center - ((Character)_player).GetCenterPoint(); float sqrMagnitude = ((Vector3)(ref val3)).sqrMagnitude; if (!(sqrMagnitude >= num2)) { num2 = sqrMagnitude; minePickingInteraction = component.Target; val = val2; } } } if ((Object)(object)minePickingInteraction == (Object)null || (Object)(object)val == (Object)null) { return false; } _target = minePickingInteraction; _collider = val; if (!TryGetCrosshairPoint(_player, _collider, out var point)) { point = _collider.ClosestPoint(((Character)_player).GetCenterPoint()); } _localSurfacePoint = ((Component)_collider).transform.InverseTransformPoint(point); BeastRunesPlugin.BeastRunesLogger.LogInfo((object)("Mining target transitioned to '" + ((Object)((Component)_target).gameObject).name + "'.")); return true; } private static bool StillValid() { //IL_0122: Unknown result type (might be due to invalid IL or missing references) //IL_0127: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_target == (Object)null || (Object)(object)_collider == (Object)null || (Object)(object)_player == (Object)null || _pickaxe == null) { return false; } if (!AutoMiningEnabled) { return false; } if ((Object)(object)_player != (Object)(object)Player.m_localPlayer) { return false; } if (((Character)_player).IsDead()) { return false; } if (!_target.IsAvailable()) { return false; } if (((Humanoid)_player).GetCurrentWeapon() != _pickaxe) { return false; } if (!IsUsablePickaxe(_pickaxe)) { return false; } if (((Character)_player).InDodge()) { return false; } if (((Character)_player).IsStaggering()) { return false; } if (((Character)_player).IsKnockedBack()) { return false; } Vector3 moveDir = ((Character)_player).GetMoveDir(); if (((Vector3)(ref moveDir)).sqrMagnitude > 0.01f) { return false; } if (!IsColliderNearby(_player, _collider)) { return false; } return true; } private static Vector3 GetSurfacePoint() { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0028: 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) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_collider == (Object)null) { return Vector3.zero; } return ((Component)_collider).transform.TransformPoint(_localSurfacePoint); } private static void FaceTarget() { //IL_0013: 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_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_player == (Object)null)) { Vector3 val = GetSurfacePoint() - ((Component)_player).transform.position; val.y = 0f; if (!(((Vector3)(ref val)).sqrMagnitude <= 0.001f)) { ((Character)_player).SetLookDir(((Vector3)(ref val)).normalized, 0.08f); } } } public static void Cancel(bool notify) { //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) if (Active) { if (notify && (Object)(object)_player != (Object)null && (Object)(object)MessageHud.instance != (Object)null) { MessageHud.instance.ShowMessage((MessageType)2, "Stopped mining", 0, (Sprite)null, false, true); } string text = (((Object)(object)_target != (Object)null) ? ((Object)((Component)_target).gameObject).name : "Unknown"); BeastRunesPlugin.BeastRunesLogger.LogInfo((object)("Stopped mining '" + text + "'.")); Player player = _player; RestoreOriginalEquipment(player); _target = null; _collider = null; _localSurfacePoint = Vector3.zero; _player = null; _pickaxe = null; _armedForCancel = false; _nextAttackAttempt = 0f; _firstFailedAttempt = -1f; _retargetDeadline = -1f; } } } public sealed class MinePickingInteraction : MonoBehaviour { private MineRock _mineRock; private MineRock5 _mineRock5; private Destructible _destructible; private ZNetView _nview; private void Awake() { _mineRock = ((Component)this).GetComponent<MineRock>(); _mineRock5 = ((Component)this).GetComponent<MineRock5>(); _destructible = ((Component)this).GetComponent<Destructible>(); _nview = ((Component)this).GetComponent<ZNetView>(); } public bool IsAvailable() { if (!MinePickingSystem.AutoMiningEnabled) { return false; } if ((Object)(object)_mineRock == (Object)null && (Object)(object)_mineRock5 == (Object)null && (Object)(object)_destructible == (Object)null) { return false; } if ((Object)(object)_nview != (Object)null && !_nview.IsValid()) { return false; } return true; } public string GetHoverName(Collider collider) { if (!IsAvailable()) { return string.Empty; } if (!MinePickingSystem.IsColliderNearby(Player.m_localPlayer, collider)) { return string.Empty; } return "Mineable"; } public string GetHoverText(Collider collider) { if (!IsAvailable()) { return string.Empty; } Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { return string.Empty; } if (!MinePickingSystem.IsColliderNearby(localPlayer, collider)) { return string.Empty; } string text = (MinePickingSystem.IsTarget(this) ? "Stop mining" : ((MinePickingSystem.FindUsablePickaxe(localPlayer) != null) ? "Start mining" : "Need a pickaxe")); return Localization.instance.Localize("[<color=yellow><b>$KEY_Use</b></color>] " + text); } public bool Interact(Humanoid user, bool hold, bool alt, Collider collider) { //IL_0102: Unknown result type (might be due to invalid IL or missing references) if (hold || alt || !IsAvailable()) { return false; } Player val = (Player)(object)((user is Player) ? user : null); if ((Object)(object)val == (Object)null || (Object)(object)val != (Object)(object)Player.m_localPlayer) { return false; } if (MinePickingSystem.IsTarget(this)) { MinePickingSystem.Cancel(notify: false); return false; } MinePickingSystem.CaptureOriginalEquipment(val); ItemData orEquipPickaxe = MinePickingSystem.GetOrEquipPickaxe(val); if (orEquipPickaxe == null) { MinePickingSystem.CaptureOriginalEquipment(null); if ((Object)(object)MessageHud.instance != (Object)null) { MessageHud.instance.ShowMessage((MessageType)2, "You need a usable pickaxe to start mining", 0, (Sprite)null, false, true); } return false; } if (!MinePickingSystem.IsColliderNearby(val, collider)) { if ((Object)(object)MessageHud.instance != (Object)null) { MessageHud.instance.ShowMessage((MessageType)2, "Move closer to start mining", 0, (Sprite)null, false, true); } return false; } MinePickingSystem.TryGetCrosshairPoint(val, collider, out var point); MinePickingSystem.Begin(this, collider, point, val, orEquipPickaxe); return false; } } public sealed class MinePickingInteractionPoint : MonoBehaviour, Hoverable, Interactable { public MinePickingInteraction Target; private Collider _collider; private Collider PointCollider { get { if ((Object)(object)_collider == (Object)null) { _collider = ((Component)this).GetComponent<Collider>(); } return _collider; } } private void Awake() { _collider = ((Component)this).GetComponent<Collider>(); } public string GetHoverName() { if ((Object)(object)Target == (Object)null) { return string.Empty; } return Target.GetHoverName(PointCollider); } public string GetHoverText() { if ((Object)(object)Target == (Object)null) { return string.Empty; } return Target.GetHoverText(PointCollider); } public bool Interact(Humanoid user, bool hold, bool alt) { return (Object)(object)Target != (Object)null && Target.Interact(user, hold, alt, PointCollider); } public float GetHoverOffset() { return 0f; } public bool UseItem(Humanoid user, ItemData item) { return false; } } internal static class MinePickingInstaller { public static void Install(GameObject root) { if ((Object)(object)root == (Object)null) { return; } MinePickingInteraction minePickingInteraction = null; try { minePickingInteraction = root.GetComponent<MinePickingInteraction>(); if ((Object)(object)minePickingInteraction == (Object)null) { minePickingInteraction = root.AddComponent<MinePickingInteraction>(); } } catch (Exception ex) { BeastRunesPlugin.BeastRunesLogger.LogWarning((object)("[MinePicking] Could not attach MinePickingInteraction to '" + ((Object)root).name + "': " + ex.Message)); return; } if ((Object)(object)minePickingInteraction == (Object)null) { BeastRunesPlugin.BeastRunesLogger.LogWarning((object)("[MinePicking] Unity refused to create MinePickingInteraction on '" + ((Object)root).name + "'.")); return; } Collider[] componentsInChildren; try { componentsInChildren = root.GetComponentsInChildren<Collider>(true); } catch (Exception ex2) { BeastRunesPlugin.BeastRunesLogger.LogWarning((object)("[MinePicking] Could not enumerate colliders for '" + ((Object)root).name + "': " + ex2.Message)); return; } if (componentsInChildren == null || componentsInChildren.Length == 0) { return; } Collider[] array = componentsInChildren; foreach (Collider val in array) { if ((Object)(object)val == (Object)null || (Object)(object)((Component)val).gameObject == (Object)null) { continue; } try { MinePickingInteractionPoint minePickingInteractionPoint = ((Component)val).GetComponent<MinePickingInteractionPoint>(); if ((Object)(object)minePickingInteractionPoint == (Object)null) { minePickingInteractionPoint = ((Component)val).gameObject.AddComponent<MinePickingInteractionPoint>(); } if ((Object)(object)minePickingInteractionPoint == (Object)null) { BeastRunesPlugin.BeastRunesLogger.LogWarning((object)("[MinePicking] Unity refused to create MinePickingInteractionPoint on '" + ((Object)((Component)val).gameObject).name + "'.")); } else { minePickingInteractionPoint.Target = minePickingInteraction; } } catch (Exception ex3) { BeastRunesPlugin.BeastRunesLogger.LogWarning((object)("[MinePicking] Could not attach interaction point to '" + ((Object)((Component)val).gameObject).name + "' on '" + ((Object)root).name + "': " + ex3.Message)); } } } } [HarmonyPatch(typeof(ZNetScene), "Awake")] [HarmonyPriority(0)] internal static class BeastRunes_ZNetScene_Awake_MinePickingPatch { private static void Postfix(ZNetScene __instance) { if ((Object)(object)__instance == (Object)null || __instance.m_prefabs == null) { return; } int num = 0; foreach (GameObject prefab in __instance.m_prefabs) { if (!((Object)(object)prefab == (Object)null) && IsMineablePrefab(prefab)) { MinePickingInstaller.Install(prefab); num++; } } BeastRunesPlugin.BeastRunesLogger.LogInfo((object)$"MinePicking installed on {num} mineable prefab(s)."); } private static bool IsMineablePrefab(GameObject prefab) { if ((Object)(object)prefab == (Object)null) { return false; } if ((Object)(object)prefab.GetComponent<MineRock>() != (Object)null || (Object)(object)prefab.GetComponent<MineRock5>() != (Object)null) { return true; } Destructible component = prefab.GetComponent<Destructible>(); if ((Object)(object)component == (Object)null) { return false; } string text = ((((Object)prefab).name != null) ? ((Object)prefab).name.ToLowerInvariant() : string.Empty); if (text.StartsWith("rock") || text.StartsWith("minerock")) { return true; } if (text.Contains("copper") || text.Contains("tin") || text.Contains("obsidian") || text.Contains("silvervein") || text.Contains("silver_vein") || text.Contains("flametal") || text.Contains("marble")) { return true; } if (text.StartsWith("mudpile") || text.Contains("scrap_pile") || text.Contains("scrappile")) { return true; } if (text.Contains("oredeposit") || text.Contains("ore_deposit") || text.Contains("mineraldeposit") || text.Contains("mineral_deposit")) { return true; } return false; } } [HarmonyPatch(typeof(Player), "Update")] internal static class BeastRunes_Player_Update_MinePickingPatch { private static void Postfix(Player __instance) { if (!((Object)(object)__instance == (Object)null) && !((Object)(object)__instance != (Object)(object)Player.m_localPlayer)) { MinePickingSystem.Tick(); } } } [HarmonyPatch(typeof(Player), "OnDestroy")] internal static class BeastRunes_Player_Destroy_MinePickingPatch { private static void Prefix(Player __instance) { if ((Object)(object)__instance == (Object)(object)Player.m_localPlayer) { MinePickingSystem.Cancel(notify: false); } } } public static class ToolSlots { private sealed class PendingToolReturn { public Player Player; public ItemData Item; public ToolSlotType SlotType; public float NotBefore; } public enum ToolSlotType { Axe, Pickaxe, Dagger } public class ToolSlotsCtrlDrag : MonoBehaviour, IBeginDragHandler, IEventSystemHandler, IDragHandler, IEndDragHandler { public RectTransform Target; public Canvas Canvas; private bool _dragging; private bool _moved; private bool _suppressNextClick; private Vector2 _dragStartPosition; private static bool CtrlHeld() { return Input.GetKey((KeyCode)306) || Input.GetKey((KeyCode)305); } public void OnBeginDrag(PointerEventData eventData) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) _dragging = false; _moved = false; if (eventData != null && (int)eventData.button == 0 && CtrlHeld() && !((Object)(object)Target == (Object)null)) { _dragging = true; _dragStartPosition = Target.anchoredPosition; } } public void OnDrag(PointerEventData eventData) { //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) if (!_dragging || eventData == null || (Object)(object)Target == (Object)null) { return; } float num = (((Object)(object)Canvas != (Object)null && Canvas.scaleFactor > 0f) ? Canvas.scaleFactor : 1f); RectTransform target = Target; target.anchoredPosition += eventData.delta / num; if (!_moved) { Vector2 val = Target.anchoredPosition - _dragStartPosition; if (((Vector2)(ref val)).sqrMagnitude > 1f) { _moved = true; } } } public void OnEndDrag(PointerEventData eventData) { //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) if (_dragging) { _dragging = false; if (_moved && !((Object)(object)Target == (Object)null)) { _suppressNextClick = true; PlayerPrefs.SetFloat("BeastRunes.ToolSlots.PosX", Target.anchoredPosition.x); PlayerPrefs.SetFloat("BeastRunes.ToolSlots.PosY", Target.anchoredPosition.y); PlayerPrefs.Save(); } } } public bool ConsumeSuppressedClick() { if (!_suppressNextClick) { return false; } _suppressNextClick = false; return true; } } public class ToolSlotDeferredDropDriver : MonoBehaviour { private InventoryGui _gui; private Player _player; private ItemData _item; private ToolSlotType _slotType; private int _waitFrames; private bool _pending; public void Queue(InventoryGui gui, Player player, ToolSlotType slotType, ItemData item) { _gui = gui; _player = player; _slotType = slotType; _item = item; _waitFrames = 1; _pending = true; } private void LateUpdate() { if (!_pending) { return; } if (_waitFrames > 0) { _waitFrames--; return; } InventoryGui gui = _gui; Player player = _player; ItemData item = _item; ToolSlotType slotType = _slotType; _pending = false; _gui = null; _player = null; _item = null; if (!((Object)(object)gui == (Object)null) && !((Object)(object)player == (Object)null) && item != null && gui.m_dragItem == item) { StoreDraggedTool(gui, player, slotType, item); } } } public class ToolSlotDragReleaseDriver : MonoBehaviour { private InventoryGui _gui; private int _lateFramesRemaining; public void Begin(InventoryGui gui) { _gui = gui; _lateFramesRemaining = 1; } private void LateUpdate() { if (!((Object)(object)_gui == (Object)null) && _lateFramesRemaining > 0) { ClearInventoryDrag(_gui); _lateFramesRemaining--; if (_lateFramesRemaining <= 0) { _gui = null; } } } } public class ToolSlotVisual : MonoBehaviour { public Image Placeholder; public Image ItemIcon; } public class ToolSlotPointerHandler : MonoBehaviour, IPointerClickHandler, IEventSystemHandler { public int SlotIndex; public void OnPointerClick(PointerEventData eventData) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Invalid comparison between Unknown and I4 if (eventData != null && (int)eventData.button == 1) { ReturnToolToInventory((ToolSlotType)SlotIndex); } } } [HarmonyPatch] private static class InventoryGui_UpdateItemDrag_NoItemSafety_Patch { private static MethodBase TargetMethod() { return AccessTools.Method(typeof(InventoryGui), "UpdateItemDrag", (Type[])null, (Type[])null); } private static bool Prefix(InventoryGui __instance) { if ((Object)(object)__instance == (Object)null) { return false; } try { ItemData value = Traverse.Create((object)__instance).Field("m_dragItem").GetValue<ItemData>(); if (value == null) { return false; } } catch { return true; } return true; } } [HarmonyPatch] private static class InventoryGui_OnDropOutside_ToolSlotsSafety_Patch { private static MethodBase TargetMethod() { return AccessTools.Method(typeof(InventoryGui), "OnDropOutside", (Type[])null, (Type[])null); } private static bool Prefix(InventoryGui __instance) { if ((Object)(object)__instance == (Object)null) { return false; } ItemData val = null; try { val = Traverse.Create((object)__instance).Field("m_dragItem").GetValue<ItemData>(); } catch { return true; } if (val == null) { return false; } return tru