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 VeinMining v0.3.4
BepInEx/plugins/VeinMining/VeinMining.dll
Decompiled 4 days agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Jotunn.Managers; using Jotunn.Utils; using Microsoft.CodeAnalysis; using UnityEngine; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: InternalsVisibleTo("SharedMining.RuntimeTests")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyCompany("VeinMining")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("0.3.4.0")] [assembly: AssemblyInformationalVersion("0.3.4")] [assembly: AssemblyProduct("VeinMining")] [assembly: AssemblyTitle("VeinMining")] [assembly: AssemblyVersion("0.3.4.0")] [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 SharedMining { internal static class Catalog { private static readonly HashSet<string> Ores = new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "CopperOre", "TinOre", "IronScrap", "SilverOre", "FlametalOre", "FlametalOreNew", "CopperScrap", "BlackMetalScrap", "Obsidian", "Chitin" }; internal static string PrefabName(GameObject go) { ZNetView component = go.GetComponent<ZNetView>(); GameObject val = ((Object.op_Implicit((Object)(object)component) && component.IsValid() && Object.op_Implicit((Object)(object)ZNetScene.instance)) ? ZNetScene.instance.GetPrefab(component.GetZDO().GetPrefab()) : null); if (!Object.op_Implicit((Object)(object)val)) { return Utils.GetPrefabName(go); } return ((Object)val).name; } internal static IEnumerable<string> Drops(GameObject go, int depth = 0) { IEnumerable<string> enumerable = (from d in (go.GetComponent<MineRock5>()?.m_dropItems ?? go.GetComponent<MineRock>()?.m_dropItems ?? go.GetComponent<DropOnDestroyed>()?.m_dropWhenDestroyed)?.m_drops where Object.op_Implicit((Object)(object)d.m_item) select Utils.GetPrefabName(d.m_item)) ?? Enumerable.Empty<string>(); GameObject val = go.GetComponent<Destructible>()?.m_spawnWhenDestroyed; if (!Object.op_Implicit((Object)(object)val) || depth >= 4) { return enumerable; } return enumerable.Concat(Drops(val, depth + 1)).Distinct(); } internal static bool Supported(GameObject go) { //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Invalid comparison between Unknown and I4 //IL_00ef: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Invalid comparison between Unknown and I4 if (!Object.op_Implicit((Object)(object)Deposit.ComponentOn(go)) || Object.op_Implicit((Object)(object)go.GetComponent<Piece>())) { return false; } Destructible component = go.GetComponent<Destructible>(); if (Object.op_Implicit((Object)(object)component) && (Object.op_Implicit((Object)(object)component.m_spawnWhenDamaged) || (Object.op_Implicit((Object)(object)component.m_spawnWhenDestroyed) && !Object.op_Implicit((Object)(object)component.m_spawnWhenDestroyed.GetComponent<MineRock5>())))) { return false; } string name = PrefabName(go); if (Plugin.Instance.Excluded.Value.Split(new char[1] { ',' }).Any((string x) => x.Trim() == name)) { return false; } if (Plugin.Instance.Included.Value.Split(new char[1] { ',' }).Any((string x) => x.Trim() == name)) { return true; } if (Object.op_Implicit((Object)(object)component) && ((int)component.m_damages.m_pickaxe == 3 || (int)component.m_damages.m_chop != 3 || Object.op_Implicit((Object)(object)go.GetComponent<Character>()))) { return false; } return Drops(go).Any((string d) => Ores.Contains(d) || d.EndsWith("Ore", StringComparison.OrdinalIgnoreCase)); } internal static int RequiredTier(GameObject go) { Destructible component = go.GetComponent<Destructible>(); int num = go.GetComponent<MineRock5>()?.m_minToolTier ?? go.GetComponent<MineRock>()?.m_minToolTier ?? component?.m_minToolTier ?? 0; if (!Object.op_Implicit((Object)(object)component) || !Object.op_Implicit((Object)(object)component.m_spawnWhenDestroyed)) { return num; } return Math.Max(num, RequiredTier(component.m_spawnWhenDestroyed)); } internal static void Audit() { if (!Object.op_Implicit((Object)(object)ZNetScene.instance)) { return; } List<string> list = new List<string> { "prefab\tadapter\tenabled\tdrops\tstaged\tonDamaged\tonDestroyed\thealth\tpickaxe\tchop" }; foreach (GameObject item in from g in ZNetScene.instance.m_prefabs where Object.op_Implicit((Object)(object)g) && Object.op_Implicit((Object)(object)Deposit.ComponentOn(g)) orderby ((Object)g).name select g) { Destructible component = item.GetComponent<Destructible>(); list.Add(string.Format("{0}\t{1}\t{2}\t{3}\t{4}\t{5}\t{6}\t{7}\t{8}\t{9}", ((Object)item).name, ((object)Deposit.ComponentOn(item)).GetType().Name, Supported(item), string.Join(",", Drops(item)), Object.op_Implicit((Object)(object)component) && (Object.op_Implicit((Object)(object)component.m_spawnWhenDestroyed) || Object.op_Implicit((Object)(object)component.m_spawnWhenDamaged)), (Object.op_Implicit((Object)(object)component) && Object.op_Implicit((Object)(object)component.m_spawnWhenDamaged)) ? ((Object)component.m_spawnWhenDamaged).name : "", (Object.op_Implicit((Object)(object)component) && Object.op_Implicit((Object)(object)component.m_spawnWhenDestroyed)) ? ((Object)component.m_spawnWhenDestroyed).name : "", Object.op_Implicit((Object)(object)component) ? component.m_health : 0f, Object.op_Implicit((Object)(object)component) ? ((object)Unsafe.As<DamageModifier, DamageModifier>(ref component.m_damages.m_pickaxe)/*cast due to .constrained prefix*/).ToString() : "", Object.op_Implicit((Object)(object)component) ? ((object)Unsafe.As<DamageModifier, DamageModifier>(ref component.m_damages.m_chop)/*cast due to .constrained prefix*/).ToString() : "")); } string text = Path.Combine(Paths.ConfigPath, "SharedMining.prefabs.tsv"); File.WriteAllLines(text, list); Plugin.Instance.Log.LogInfo((object)$"Prefab audit written: {text}; {list.Count - 1} destructible prefabs examined."); } } internal static class Client { internal static ZDOID Target = ZDOID.None; private static long token; private static int sequence; private static float requestAt; private static float heartbeatAt; private static float missingSince; private static bool pending; private static ItemData? tool; private static Attack? attack; private static readonly List<(int index, HitData hit)> Batch = new List<(int, HitData)>(); private static readonly MiningInput InputState = new MiningInput(); internal static bool Running => token != 0; [MethodImpl(MethodImplOptions.NoInlining)] internal static bool IsHolding() { //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) if (Application.isFocused) { if (!InputState.Latched) { KeyboardShortcut value = Plugin.Instance.HoldKey.Value; return ((KeyboardShortcut)(ref value)).IsPressed(); } return true; } return false; } internal static void Reset(bool keepTap = false) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) InputState.Clear(keepTap); Target = ZDOID.None; token = 0L; sequence = 0; pending = false; tool = null; attack = null; missingSince = 0f; Batch.Clear(); } private static void Message(string text) { if (Object.op_Implicit((Object)(object)MessageHud.instance)) { MessageHud.instance.ShowMessage((MessageType)2, text, 0, (Sprite)null, false, true); } } internal static void Stop(string message, bool keepTap = false) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Expected O, but got Unknown if (token != 0L && ZRoutedRpc.instance != null) { ZPackage val = new ZPackage(); val.Write(token); ZRoutedRpc.instance.InvokeRoutedRPC("SharedMining.Stop.v1", new object[1] { val }); } Reset(keepTap); if (message.Length > 0) { Message(message); } } internal static void Update() { //IL_002d: 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) //IL_018f: Unknown result type (might be due to invalid IL or missing references) //IL_0196: Expected O, but got Unknown //IL_0212: Unknown result type (might be due to invalid IL or missing references) //IL_0219: Invalid comparison between Unknown and I4 //IL_025c: Unknown result type (might be due to invalid IL or missing references) //IL_0267: Unknown result type (might be due to invalid IL or missing references) //IL_031f: Unknown result type (might be due to invalid IL or missing references) //IL_0326: Unknown result type (might be due to invalid IL or missing references) //IL_0349: Unknown result type (might be due to invalid IL or missing references) //IL_034e: Unknown result type (might be due to invalid IL or missing references) //IL_0363: Unknown result type (might be due to invalid IL or missing references) //IL_036a: Expected O, but got Unknown //IL_0374: Unknown result type (might be due to invalid IL or missing references) //IL_0381: Unknown result type (might be due to invalid IL or missing references) Player localPlayer = Player.m_localPlayer; if (!Object.op_Implicit((Object)(object)localPlayer) || ZRoutedRpc.instance == null) { Reset(); return; } int num; if (Application.isFocused) { KeyboardShortcut value = Plugin.Instance.HoldKey.Value; num = (((KeyboardShortcut)(ref value)).IsDown() ? 1 : 0); } else { num = 0; } bool flag = (byte)num != 0; if (!Application.isFocused || InputBlocked()) { InputState.Clear(); } else if (flag && InputState.Press(Time.unscaledTime)) { Stop("Mining paused."); return; } if ((Running || pending) && !IsHolding()) { Stop("", Application.isFocused && !InputBlocked()); return; } if (pending && Time.time - requestAt > 8f) { Stop("The server did not respond. Check that Vein Mining is installed on it."); } if (Running && (!ValidPlayer(localPlayer) || ((Humanoid)localPlayer).GetCurrentWeapon() != tool || (tool.m_shared.m_useDurability && tool.m_durability <= 0f))) { Stop("Mining stopped. Shared progress has been saved."); } if (Running && (Object)(object)TargetView() == (Object)null) { if (missingSince == 0f) { missingSince = Time.time; } if (Time.time - missingSince > 2f) { Stop(""); } } else { missingSince = 0f; } if (Running && Time.time >= heartbeatAt) { heartbeatAt = Time.time + 3f; ZPackage val = new ZPackage(); val.Write(token); ZRoutedRpc.instance.InvokeRoutedRPC("SharedMining.Keep.v1", new object[1] { val }); } if (!flag || !IsHolding() || InputBlocked() || Running || pending) { return; } if (!MiningCompatibility.Ready) { Message("This version of Smoothbrain Mining is not supported."); return; } tool = ((Humanoid)localPlayer).GetCurrentWeapon(); if (!ValidPlayer(localPlayer) || tool == null || (int)tool.m_shared.m_skillType != 12 || (tool.m_shared.m_useDurability && tool.m_durability <= 0f)) { Message("Equip a usable pickaxe first."); return; } Camera mainCamera = Utils.GetMainCamera(); RaycastHit val2 = default(RaycastHit); if (!Object.op_Implicit((Object)(object)mainCamera) || !Physics.Raycast(((Component)mainCamera).transform.position, ((Component)mainCamera).transform.forward, ref val2, 50f, LayerMask.GetMask(new string[5] { "Default", "static_solid", "Default_small", "piece", "terrain" }), (QueryTriggerInteraction)1)) { return; } ZNetView componentInParent = ((Component)((RaycastHit)(ref val2)).collider).GetComponentInParent<ZNetView>(); if (!Object.op_Implicit((Object)(object)componentInParent) || !componentInParent.IsValid() || !Object.op_Implicit((Object)(object)Deposit.ComponentOn(((Component)componentInParent).gameObject))) { Message("Aim at an ore deposit."); return; } int num2 = Catalog.RequiredTier(((Component)componentInParent).gameObject); if (tool.m_shared.m_toolTier < num2) { Message("Your pickaxe is too weak for this deposit."); return; } if (Vector3.Distance(((Component)localPlayer).transform.position, ((RaycastHit)(ref val2)).point) > 6f) { Message("Move closer to the deposit."); return; } Target = componentInParent.GetZDO().m_uid; pending = true; requestAt = Time.time; ZPackage val3 = new ZPackage(); val3.Write(1); val3.Write(Target); val3.Write(((Character)localPlayer).GetZDOID()); ZRoutedRpc.instance.InvokeRoutedRPC("SharedMining.Start.v1", new object[1] { val3 }); } private static bool ValidPlayer(Player player) { if (!((Character)player).IsDead() && !((Character)player).IsTeleporting() && !((Character)player).InCutscene()) { return !((Character)player).InPlaceMode(); } return false; } private static bool InputBlocked() { if ((!Object.op_Implicit((Object)(object)Chat.instance) || !Chat.instance.HasFocus()) && !Console.IsVisible() && !TextInput.IsVisible() && !InventoryGui.IsVisible()) { return Menu.IsVisible(); } return true; } private static ZNetView? TargetView() { //IL_0014: Unknown result type (might be due to invalid IL or missing references) GameObject val = (Object.op_Implicit((Object)(object)ZNetScene.instance) ? ZNetScene.instance.FindInstance(Target) : null); ZNetView val2 = (Object.op_Implicit((Object)(object)val) ? val.GetComponent<ZNetView>() : null); if (!Object.op_Implicit((Object)(object)val2) || !val2.IsValid()) { return null; } return val2; } internal static void Reply(long sender, ZPackage pkg) { //IL_001c: 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) if (sender != Server.ServerId) { return; } try { if (pkg.GetArray().Length > 2048) { return; } ZDOID val = pkg.ReadZDOID(); long num = pkg.ReadLong(); string text = pkg.ReadString(); if (!(val != Target) && (pending || Running)) { pending = false; if (num == 0L) { Reset(); } else { token = num; sequence = 0; } Message(text); } } catch (Exception ex) { Plugin.Instance.Log.LogWarning((object)ex.Message); } } internal static void Retarget(long sender, ZPackage pkg) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_003b: 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) if (sender != Server.ServerId) { return; } try { ZDOID val = pkg.ReadZDOID(); ZDOID target = pkg.ReadZDOID(); long num = pkg.ReadLong(); if (Running && Target == val && token == num) { Target = target; missingSince = 0f; } } catch (Exception ex) { Plugin.Instance.Log.LogDebug((object)ex.Message); } } internal static void Controls(Player player, Vector3 movedir, ref bool primary, ref bool hold, bool cancel) { if ((Object)(object)player != (Object)(object)Player.m_localPlayer || !Running) { return; } if (cancel || ((Vector3)(ref movedir)).sqrMagnitude > 0.01f || InputBlocked()) { Stop("Mining paused."); } else if (!IsHolding()) { Stop("Mining paused.", Application.isFocused); } else if (Object.op_Implicit((Object)(object)TargetView())) { if (((Humanoid)player).GetCurrentWeapon() != tool || tool == null || (tool.m_shared.m_useDurability && tool.m_durability <= 0f)) { Stop(""); return; } primary = true; hold = true; } } internal static void Begin(Attack current, Humanoid character) { if (Running && !((Object)(object)character != (Object)(object)Player.m_localPlayer)) { attack = current; Batch.Clear(); } } internal static bool Capture(Component rock, HitData hit) { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_01be: Unknown result type (might be due to invalid IL or missing references) //IL_01c5: Expected O, but got Unknown //IL_01cd: Unknown result type (might be due to invalid IL or missing references) ZNetView component = rock.GetComponent<ZNetView>(); if (!Object.op_Implicit((Object)(object)component) || !component.IsValid()) { return true; } if (attack != null && Running && component.GetZDO().m_uid == Target && (Object)(object)hit.GetAttacker() == (Object)(object)Player.m_localPlayer) { MineRock5 val = (MineRock5)(object)((rock is MineRock5) ? rock : null); int num; if (val != null) { num = (int)AccessTools.Method(typeof(MineRock5), "GetAreaIndex", (Type[])null, (Type[])null).Invoke(val, new object[1] { hit.m_hitCollider }); } else { MineRock val2 = (MineRock)(object)((rock is MineRock) ? rock : null); num = ((val2 != null) ? Array.IndexOf((Collider[])AccessTools.Field(typeof(MineRock), "m_hitAreas").GetValue(val2), hit.m_hitCollider) : 0); } if (num >= 0 && Batch.Count < 64) { Batch.Add((num, hit.Clone())); } return false; } if (component.GetZDO().GetBool("SharedMining.active.v1", false) && (Object)(object)hit.GetAttacker() == (Object)(object)Player.m_localPlayer && hit.m_damage.m_pickaxe > 0f) { MineRock5 val3 = (MineRock5)(object)((rock is MineRock5) ? rock : null); int num2; if (val3 == null) { MineRock val4 = (MineRock)(object)((rock is MineRock) ? rock : null); num2 = ((val4 != null) ? Array.IndexOf((Collider[])AccessTools.Field(typeof(MineRock), "m_hitAreas").GetValue(val4), hit.m_hitCollider) : 0); } else { num2 = (int)AccessTools.Method(typeof(MineRock5), "GetAreaIndex", (Type[])null, (Type[])null).Invoke(val3, new object[1] { hit.m_hitCollider }); } int num3 = num2; if (num3 < 0) { return true; } ZPackage val5 = new ZPackage(); val5.Write(component.GetZDO().m_uid); val5.Write(num3); hit.Serialize(ref val5); ZRoutedRpc.instance.InvokeRoutedRPC("SharedMining.Manual.v1", new object[1] { val5 }); return false; } return true; } internal static void End(Attack current, Exception? error) { //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Expected O, but got Unknown if (attack != current) { return; } attack = null; if (error != null) { Batch.Clear(); Stop("Mining stopped because of an error."); return; } if (Batch.Count == 0) { Stop("Your pickaxe missed the deposit. Adjust your aim, then hold Alt again."); return; } if (Running) { ZPackage val = new ZPackage(); val.Write(token); val.Write(++sequence); val.Write(Batch.Count); foreach (var item in Batch) { val.Write(item.index); item.hit.Serialize(ref val); } ZRoutedRpc.instance.InvokeRoutedRPC("SharedMining.Hit.v1", new object[1] { val }); } Batch.Clear(); } internal static void Draw() { Player localPlayer = Player.m_localPlayer; if (!Object.op_Implicit((Object)(object)localPlayer)) { MiningHud.Hide(); return; } ZNetView val = TargetView(); if (!Object.op_Implicit((Object)(object)val)) { GameObject hoverObject = ((Humanoid)localPlayer).GetHoverObject(); val = (Object.op_Implicit((Object)(object)hoverObject) ? hoverObject.GetComponentInParent<ZNetView>() : null); } if (!Object.op_Implicit((Object)(object)val) || !val.IsValid() || !val.GetZDO().GetBool("SharedMining.active.v1", false)) { MiningHud.Hide(); return; } float progress = Mathf.Clamp01(val.GetZDO().GetFloat("SharedMining.progress.v1", 0f)); ZDO zDO = val.GetZDO(); int miners = ((Object.op_Implicit((Object)(object)ZNet.instance) && ZNet.instance.GetTimeSeconds() - (double)zDO.GetLong("VeinMining.activityTime", 0L) < 6.0) ? zDO.GetInt("VeinMining.miners", 0) : 0); float num = zDO.GetFloat("VeinMining.speed", 0f); if (Server.IsServer) { num = Plugin.Instance.OreWorkMultiplier.Value; } else if (num <= 0f) { num = 3f; } MiningHud.Draw(progress, miners, num, InputState.Latched && Running); } } [HarmonyPatch(typeof(Player), "SetControls")] internal static class AutoSwing { private static void Prefix(Player __instance, Vector3 movedir, ref bool attack, ref bool attackHold, bool secondaryAttack, bool secondaryAttackHold, bool block, bool blockHold, bool jump, bool dodge) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) Client.Controls(__instance, movedir, ref attack, ref attackHold, secondaryAttack || secondaryAttackHold || block || blockHold || jump || dodge); } } [HarmonyPatch(typeof(Attack), "DoMeleeAttack")] internal static class SwingBatch { private static void Prefix(Attack __instance, Humanoid ___m_character) { Client.Begin(__instance, ___m_character); } private static void Finalizer(Attack __instance, Exception __exception) { Client.End(__instance, __exception); } } [HarmonyPatch] internal static class CaptureHit { private static IEnumerable<MethodBase> TargetMethods() { yield return AccessTools.Method(typeof(MineRock5), "Damage", (Type[])null, (Type[])null); yield return AccessTools.Method(typeof(MineRock), "Damage", (Type[])null, (Type[])null); yield return AccessTools.Method(typeof(Destructible), "Damage", (Type[])null, (Type[])null); } [HarmonyPriority(800)] private static bool Prefix(Component __instance, HitData hit) { if (!Plugin.Completing) { return Client.Capture(__instance, hit); } return true; } } internal sealed class Deposit { internal const string ActiveKey = "SharedMining.active.v1"; internal const string DataKey = "SharedMining.ledger.v1"; internal const string ProgressKey = "SharedMining.progress.v1"; internal readonly Component Rock; internal readonly ZNetView View; internal readonly Collider[] Parts; internal readonly float[] Health; internal readonly int Tier; internal readonly DamageModifiers Resistance; internal readonly MineRock5? nextStage; internal static readonly List<ZNetView> Spawned = new List<ZNetView>(); internal ZDO Data => View.GetZDO(); internal string Name => Catalog.PrefabName(Rock.gameObject); internal float WorkMultiplier => Plugin.Instance.OreWorkMultiplier.Value; internal Deposit(Component rock) { //IL_01a5: Unknown result type (might be due to invalid IL or missing references) //IL_01ab: Expected O, but got Unknown //IL_0215: Unknown result type (might be due to invalid IL or missing references) //IL_021a: Unknown result type (might be due to invalid IL or missing references) //IL_0199: Unknown result type (might be due to invalid IL or missing references) //IL_019e: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Unknown result type (might be due to invalid IL or missing references) //IL_0113: Unknown result type (might be due to invalid IL or missing references) Deposit deposit = this; Rock = rock; View = rock.GetComponent<ZNetView>(); if (!Object.op_Implicit((Object)(object)View) || !View.IsValid()) { throw new InvalidOperationException("Deposit is not networked"); } MineRock5 val = (MineRock5)(object)((rock is MineRock5) ? rock : null); if (val != null) { AccessTools.Method(typeof(MineRock5), "LoadHealth", (Type[])null, (Type[])null).Invoke(val, null); IList source = (IList)AccessTools.Field(typeof(MineRock5), "m_hitAreas").GetValue(val); Parts = source.Cast<object>().Select((Func<object, Collider>)((object a) => (Collider)AccessTools.Field(a.GetType(), "m_collider").GetValue(a))).ToArray(); Health = (from object a in source select Math.Max(0f, (float)AccessTools.Field(a.GetType(), "m_health").GetValue(a))).ToArray(); Tier = val.m_minToolTier; Resistance = val.m_damageModifiers; return; } MineRock old = (MineRock)(object)((rock is MineRock) ? rock : null); if (old != null) { Parts = (Collider[])AccessTools.Field(typeof(MineRock), "m_hitAreas").GetValue(old); Health = (from i in Enumerable.Range(0, Parts.Length) select Math.Max(0f, deposit.Data.GetFloat("Health" + i, old.GetHealth()))).ToArray(); Tier = old.m_minToolTier; Resistance = old.m_damageModifiers; return; } Destructible val2 = (Destructible)rock; Parts = (Collider[])(object)new Collider[1] { rock.GetComponentInChildren<Collider>() }; Health = new float[1] { Math.Max(0f, Data.GetFloat(ZDOVars.s_health, val2.m_health * (1f + (float)Game.m_worldLevel * Game.instance.m_worldLevelMineHPMultiplier))) }; Tier = val2.m_minToolTier; Resistance = val2.m_damages; nextStage = (Object.op_Implicit((Object)(object)val2.m_spawnWhenDestroyed) ? val2.m_spawnWhenDestroyed.GetComponent<MineRock5>() : null); if (Object.op_Implicit((Object)(object)nextStage)) { int count = ((Component)nextStage).GetComponentsInChildren<Collider>().Length; float element = nextStage.m_health * (1f + (float)Game.m_worldLevel * Game.instance.m_worldLevelMineHPMultiplier); Health = Health.Concat(Enumerable.Repeat(element, count)).ToArray(); Tier = Math.Max(Tier, nextStage.m_minToolTier); } } internal static Component? ComponentOn(GameObject go) { return (Component?)(go.GetComponent<MineRock5>() ?? ((object)go.GetComponent<MineRock>()) ?? ((object)go.GetComponent<Destructible>())); } internal static Deposit? Find(ZDOID id) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) GameObject val = (Object.op_Implicit((Object)(object)ZNetScene.instance) ? ZNetScene.instance.FindInstance(id) : null); if (!Object.op_Implicit((Object)(object)val) || !Catalog.Supported(val)) { return null; } Component val2 = ComponentOn(val); if (!Object.op_Implicit((Object)(object)val2)) { return null; } return new Deposit(val2); } internal int Index(Collider collider) { if (!(Rock is Destructible)) { return Array.IndexOf(Parts, collider); } return 0; } internal DamageModifiers ResistanceAt(int index) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)nextStage) || index <= 0) { return Resistance; } return nextStage.m_damageModifiers; } internal float Distance(Vector3 position) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) return Parts.Where((Collider c) => Object.op_Implicit((Object)(object)c) && c.enabled).Select(delegate(Collider c) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0019: 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_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002a: 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) MeshCollider val = (MeshCollider)(object)((c is MeshCollider) ? c : null); Vector3 val2; if (val == null || val.convex) { val2 = c.ClosestPoint(position); } else { Bounds bounds = c.bounds; val2 = ((Bounds)(ref bounds)).ClosestPoint(position); } return Vector3.Distance(val2, position); }).DefaultIfEmpty(float.MaxValue) .Min(); } internal WorkLedger Load() { //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Expected O, but got Unknown byte[] byteArray = Data.GetByteArray("SharedMining.ledger.v1", (byte[])null); if (byteArray == null || byteArray.Length == 0) { return new WorkLedger(Health, Health.Sum()); } ZPackage val = new ZPackage(byteArray); if (val.ReadInt() != 1 || val.ReadInt() != Health.Length) { throw new InvalidOperationException("Deposit layout changed; refusing stale progress"); } float total = val.ReadSingle(); float[] array = new float[Health.Length]; for (int i = 0; i < array.Length; i++) { array[i] = val.ReadSingle(); } return new WorkLedger(array, total); } internal void Save(WorkLedger ledger) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Expected O, but got Unknown ZPackage val = new ZPackage(); val.Write(1); val.Write(ledger.Remaining.Length); val.Write(ledger.Total); float[] remaining = ledger.Remaining; foreach (float num in remaining) { val.Write(num); } Data.Set("SharedMining.ledger.v1", val.GetArray()); Data.Set("SharedMining.progress.v1", ledger.Progress); } internal void Finish(HitData source) { //IL_00b7: 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) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_0113: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_011c: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Unknown result type (might be due to invalid IL or missing references) //IL_0121: Unknown result type (might be due to invalid IL or missing references) bool completing = Plugin.Completing; Plugin.Completing = true; try { string expectedStage = (Object.op_Implicit((Object)(object)nextStage) ? Utils.GetPrefabName(((Component)nextStage).gameObject) : null); float[] array = (from i in Enumerable.Range(0, Health.Length) select Data.GetFloat("SharedMining.factor." + i, 0f)).ToArray(); int count = Spawned.Count; for (int num = 0; num < Parts.Length; num++) { if (!Object.op_Implicit((Object)(object)Rock)) { break; } if (!View.IsValid()) { break; } if (Health[num] <= 0f) { continue; } using (MiningCompatibility.Scope(Data.GetFloat("SharedMining.factor." + num, 0f))) { HitData val = source.Clone(); val.m_damage = new DamageTypes { m_damage = Health[num] + 1f }; val.m_toolTier = short.MaxValue; Vector3 point; if (!Object.op_Implicit((Object)(object)Parts[num])) { point = Rock.transform.position; } else { Bounds bounds = Parts[num].bounds; point = ((Bounds)(ref bounds)).center; } val.m_point = point; val.m_hitCollider = Parts[num]; Component rock = Rock; MineRock5 val2 = (MineRock5)(object)((rock is MineRock5) ? rock : null); if (val2 != null) { AccessTools.Method(typeof(MineRock5), "DamageArea", (Type[])null, (Type[])null).Invoke(val2, new object[2] { num, val }); continue; } Component rock2 = Rock; MineRock val3 = (MineRock)(object)((rock2 is MineRock) ? rock2 : null); if (val3 != null) { AccessTools.Method(typeof(MineRock), "RPC_Hit", (Type[])null, (Type[])null).Invoke(val3, new object[3] { 0L, val, num }); } else { AccessTools.Method(typeof(Destructible), "RPC_Damage", (Type[])null, (Type[])null).Invoke(Rock, new object[2] { 0L, val }); } } } if (expectedStage != null) { ZNetView? obj = Spawned.Skip(count).FirstOrDefault((Func<ZNetView, bool>)((ZNetView v) => Object.op_Implicit((Object)(object)v) && v.IsValid() && v.GetZDO().GetPrefab() == StringExtensionMethods.GetStableHashCode(expectedStage))); if (!Object.op_Implicit((Object)(object)obj)) { throw new InvalidOperationException("Native ore transition did not create " + expectedStage); } Deposit deposit = new Deposit((Component)(object)((Component)obj).GetComponent<MineRock5>()); for (int num2 = 0; num2 < deposit.Health.Length; num2++) { deposit.Data.Set("SharedMining.factor." + num2, array[num2 + 1]); } deposit.Finish(source); } if (Object.op_Implicit((Object)(object)Rock) && View.IsValid()) { Data.Set("SharedMining.active.v1", false); } } finally { Plugin.Completing = completing; if (!completing) { Spawned.Clear(); } } } } [HarmonyPatch(typeof(ZNetScene), "AddInstance")] internal static class CaptureNativeStage { private static void Postfix(ZNetView nview) { if (Plugin.Completing) { Deposit.Spawned.Add(nview); } ManualMining.RecordSpawn(nview); } } internal static class ManualMining { internal sealed class Snapshot { internal Deposit Deposit; internal ZDOID Id; internal WorkLedger Ledger; internal HitData Hit; internal float[] Factors = Array.Empty<float>(); internal readonly List<(ZDOID id, int prefab)> Spawned = new List<(ZDOID, int)>(); } private static readonly List<Snapshot> Active = new List<Snapshot>(); internal static void Reset() { Active.Clear(); } internal static Snapshot? Begin(Component rock, HitData hit) { //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) if (Plugin.Completing || !Server.IsServer || Active.Any((Snapshot s) => (Object)(object)s.Deposit.Rock == (Object)(object)rock)) { return null; } ZNetView component = rock.GetComponent<ZNetView>(); if (!Object.op_Implicit((Object)(object)component) || !component.IsValid() || !component.IsOwner() || !component.GetZDO().GetBool("SharedMining.active.v1", false)) { return null; } Deposit d = new Deposit(rock); Snapshot snapshot = new Snapshot { Deposit = d, Id = d.Data.m_uid, Ledger = d.Load(), Hit = hit.Clone(), Factors = (from i in Enumerable.Range(0, d.Health.Length) select d.Data.GetFloat("SharedMining.factor." + i, 0f)).ToArray() }; Active.Add(snapshot); return snapshot; } internal static void RecordSpawn(ZNetView view) { //IL_0043: Unknown result type (might be due to invalid IL or missing references) if (Plugin.Completing || Active.Count == 0 || !Object.op_Implicit((Object)(object)view) || !view.IsValid()) { return; } foreach (Snapshot item in Active) { item.Spawned.Add((view.GetZDO().m_uid, view.GetZDO().GetPrefab())); } } internal static void End(Snapshot? s) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_016c: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_0201: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_0153: Unknown result type (might be due to invalid IL or missing references) //IL_015e: Unknown result type (might be due to invalid IL or missing references) if (s == null) { return; } Active.Remove(s); try { Deposit deposit = Deposit.Find(s.Id); WorkLedger workLedger = s.Ledger; float[] array = s.Deposit.Health; int num = 0; if (deposit == null && Object.op_Implicit((Object)(object)s.Deposit.nextStage)) { int expected = StringExtensionMethods.GetStableHashCode(((Object)((Component)s.Deposit.nextStage).gameObject).name); (ZDOID id, int prefab) tuple = s.Spawned.FirstOrDefault(((ZDOID id, int prefab) x) => x.prefab == expected); if (tuple.id == ZDOID.None) { throw new InvalidOperationException("Native shell transition was not captured"); } deposit = Deposit.Find(tuple.id); if (deposit == null) { Server.Completed(s.Id); return; } workLedger = new WorkLedger(workLedger.Remaining.Skip(1).ToArray(), workLedger.Total); array = array.Skip(1).ToArray(); num = 1; deposit.Data.SetOwner(Server.ServerId); deposit.Data.Set("SharedMining.active.v1", true); for (int num2 = 0; num2 < deposit.Health.Length; num2++) { deposit.Data.Set("SharedMining.factor." + num2, s.Factors[num2 + num]); } Server.Retarget(s.Id, deposit.Data.m_uid); } if (deposit == null) { Server.Completed(s.Id); return; } workLedger.ReconcileNative(array, deposit.Health); Character attacker = s.Hit.GetAttacker(); Player val = (Player)(object)((attacker is Player) ? attacker : null); if (Object.op_Implicit((Object)(object)val)) { for (int num3 = 0; num3 < deposit.Health.Length; num3++) { if (deposit.Health[num3] < array[num3]) { deposit.Data.Set("SharedMining.factor." + num3, MiningCompatibility.Factor(val)); } } } deposit.Save(workLedger); if (workLedger.Complete) { ZDOID uid = deposit.Data.m_uid; if (deposit.Health.Any((float h) => h > 0f)) { deposit.Finish(s.Hit); } else { deposit.Data.Set("SharedMining.active.v1", false); } Server.Completed(uid); } } catch (Exception ex) { Plugin.Instance.Log.LogError((object)("Could not reconcile ordinary mining: " + ex)); } } } [HarmonyPatch] internal static class ObserveNativeMining { private static IEnumerable<MethodBase> TargetMethods() { yield return AccessTools.Method(typeof(MineRock5), "RPC_Damage", (Type[])null, (Type[])null); yield return AccessTools.Method(typeof(MineRock), "RPC_Hit", (Type[])null, (Type[])null); yield return AccessTools.Method(typeof(Destructible), "RPC_Damage", (Type[])null, (Type[])null); } [HarmonyPriority(800)] private static void Prefix(Component __instance, HitData hit, out ManualMining.Snapshot? __state) { __state = null; try { __state = ManualMining.Begin(__instance, hit); } catch (Exception ex) { Plugin.Instance.Log.LogError((object)("Could not snapshot ordinary mining: " + ex)); } } private static void Finalizer(ManualMining.Snapshot? __state) { ManualMining.End(__state); } } internal static class MiningCompatibility { private sealed class MiningScope : IDisposable { private readonly object? oldMining; private readonly object? oldFactor; internal MiningScope(float value) { oldMining = mining?.GetValue(null); oldFactor = factor?.GetValue(null); mining?.SetValue(null, true); factor?.SetValue(null, value); } public void Dispose() { mining?.SetValue(null, oldMining); factor?.SetValue(null, oldFactor); } } private static Type? flag; private static MethodInfo? handle; private static FieldInfo? mining; private static FieldInfo? factor; internal static bool Ready { get; private set; } = true; internal static void Initialize(Harmony harmony) { //IL_0119: Unknown result type (might be due to invalid IL or missing references) //IL_0127: Expected O, but got Unknown if (Chainloader.PluginInfos.TryGetValue("org.bepinex.plugins.mining", out var value)) { flag = ((object)value.Instance).GetType().GetNestedType("SetMiningFlag", BindingFlags.Public); handle = ((flag == null) ? null : AccessTools.Method(flag, "HandleMining", (Type[])null, (Type[])null)); mining = ((flag == null) ? null : AccessTools.Field(flag, "IsMining")); factor = ((flag == null) ? null : AccessTools.Field(flag, "MiningFactor")); Ready = handle != null && mining != null && factor != null && value.Metadata.Version.ToString() == "1.1.6"; if (!Ready) { Plugin.Instance.Log.LogError((object)"Unknown Smoothbrain Mining API/version. Shared mining is disabled to protect compatibility."); } else { harmony.Patch((MethodBase)handle, new HarmonyMethod(typeof(MiningCompatibility), "BeforeHandle", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } } } private static bool BeforeHandle(ref bool __result) { if (!Plugin.Completing) { return true; } __result = true; return false; } internal static float Factor(Player player) { return ((Component)player).GetComponent<ZNetView>().GetZDO().GetFloat("Mining Skill Factor", 0f); } internal static void Contribute(HitData hit, Deposit deposit) { if (!(handle == null)) { Character attacker = hit.GetAttacker(); Player val = (Player)(object)((attacker is Player) ? attacker : null); if (Object.op_Implicit((Object)(object)val)) { ((Component)val).GetComponent<ZNetView>().InvokeRPC("Mining IncreaseSkill", new object[1] { 1 }); } } } internal static IDisposable Scope(float value) { return new MiningScope(value); } } internal static class MiningHud { private static GameObject? root; private static Text? heading; private static Text? percent; private static Text? activity; private static RectTransform? fill; private static Texture2D? leatherTexture; private static Sprite? leatherSprite; private static RectTransform Rect(string name, Transform parent, float x, float y, float w, float h) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003f: 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) //IL_005e: 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) RectTransform component = new GameObject(name, new Type[1] { typeof(RectTransform) }).GetComponent<RectTransform>(); ((Transform)component).SetParent(parent, false); Vector2 val = default(Vector2); ((Vector2)(ref val))..ctor(0f, 1f); component.anchorMax = val; component.anchorMin = val; component.pivot = new Vector2(0f, 1f); component.anchoredPosition = new Vector2(x, 0f - y); component.sizeDelta = new Vector2(w, h); return component; } private static Image Image(RectTransform rect, Color color, Sprite? sprite = null) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) Image val = ((Component)rect).gameObject.AddComponent<Image>(); ((Graphic)val).raycastTarget = false; ((Graphic)val).color = color; val.sprite = sprite; if (Object.op_Implicit((Object)(object)sprite)) { val.type = (Type)1; } return val; } private static Text Text(RectTransform rect, int size, TextAnchor alignment, bool bold = false) { //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) Text obj = ((Component)rect).gameObject.AddComponent<Text>(); obj.font = (bold ? GUIManager.Instance.AveriaSerifBold : GUIManager.Instance.AveriaSerif); obj.fontSize = size; obj.alignment = alignment; ((Graphic)obj).color = new Color(0.97f, 0.9f, 0.72f); obj.supportRichText = false; ((Graphic)obj).raycastTarget = false; obj.horizontalOverflow = (HorizontalWrapMode)1; return obj; } private static Sprite PanelSprite() { //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Expected O, but got Unknown //IL_0146: Unknown result type (might be due to invalid IL or missing references) //IL_0155: Unknown result type (might be due to invalid IL or missing references) if (Object.op_Implicit((Object)(object)leatherSprite)) { return leatherSprite; } using Stream stream = typeof(MiningHud).Assembly.GetManifestResourceStream("VeinMining.HudLeather.png") ?? throw new InvalidOperationException("HUD leather resource missing"); using MemoryStream memoryStream = new MemoryStream(); stream.CopyTo(memoryStream); leatherTexture = new Texture2D(2, 2, (TextureFormat)4, false); if (!AssetUtils.LoadImage(leatherTexture, memoryStream.ToArray())) { throw new InvalidOperationException("HUD texture failed to load"); } ((Texture)leatherTexture).wrapMode = (TextureWrapMode)1; ((Texture)leatherTexture).filterMode = (FilterMode)1; Color32[] pixels = leatherTexture.GetPixels32(); int width = ((Texture)leatherTexture).width; int height = ((Texture)leatherTexture).height; int num = width; int num2 = height; int num3 = -1; int num4 = -1; for (int i = 0; i < height; i++) { for (int j = 0; j < width; j++) { if (pixels[i * width + j].a >= 64) { num = Math.Min(num, j); num2 = Math.Min(num2, i); num3 = Math.Max(num3, j); num4 = Math.Max(num4, i); } } } if (num3 < 0) { throw new InvalidOperationException("HUD texture is empty"); } leatherSprite = Sprite.Create(leatherTexture, new Rect((float)num, (float)num2, (float)(num3 - num + 1), (float)(num4 - num2 + 1)), new Vector2(0.5f, 0.5f), 100f, 0u, (SpriteMeshType)0); return leatherSprite; } private static void Create() { //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Expected O, but got Unknown //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_015a: Unknown result type (might be due to invalid IL or missing references) //IL_01a2: Unknown result type (might be due to invalid IL or missing references) //IL_0220: Unknown result type (might be due to invalid IL or missing references) //IL_026c: Unknown result type (might be due to invalid IL or missing references) root = new GameObject("VeinMiningHud", new Type[3] { typeof(RectTransform), typeof(Canvas), typeof(CanvasScaler) }); Canvas component = root.GetComponent<Canvas>(); component.renderMode = (RenderMode)0; component.sortingOrder = 20; RectTransform val = Rect("MiningPanel", root.transform, 0f, 0f, 360f, 84f); Vector2 val2 = default(Vector2); ((Vector2)(ref val2))..ctor(0.5f, 0.29f); val.anchorMax = val2; val.anchorMin = val2; val.pivot = new Vector2(0.5f, 0.5f); val.anchoredPosition = Vector2.zero; Image(val, Color.white, PanelSprite()).type = (Type)0; heading = Text(Rect("Title", (Transform)(object)val, 18f, 11f, 230f, 22f), 16, (TextAnchor)3, bold: true); percent = Text(Rect("Percent", (Transform)(object)val, 264f, 11f, 78f, 22f), 16, (TextAnchor)5, bold: true); Image(Rect("BarBorder", (Transform)(object)val, 18f, 37f, 324f, 13f), new Color(0.65f, 0.43f, 0.17f), GUIManager.Instance.GetSprite("UISprite")); Image(Rect("BarTrack", (Transform)(object)val, 19f, 38f, 322f, 11f), new Color(0.05f, 0.05f, 0.035f), GUIManager.Instance.GetSprite("UISprite")); RectTransform val3 = Rect("ProgressClip", (Transform)(object)val, 20f, 39f, 320f, 9f); ((Component)val3).gameObject.AddComponent<RectMask2D>(); fill = Rect("Progress", (Transform)(object)val3, 0f, 0f, 320f, 9f); Image(fill, new Color(0.93f, 0.58f, 0.12f), GUIManager.Instance.GetSprite("UISprite")); Image(Rect("Highlight", (Transform)(object)fill, 0f, 0f, 320f, 2f), new Color(0.98f, 0.76f, 0.36f)); activity = Text(Rect("Activity", (Transform)(object)val, 18f, 54f, 324f, 20f), 13, (TextAnchor)4); } internal static void Draw(float progress, int miners, float oreSpeed, bool automatic) { //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) if (Object.op_Implicit((Object)(object)Hud.instance) && Object.op_Implicit((Object)(object)GUIManager.Instance.AveriaSerif)) { if (!Object.op_Implicit((Object)(object)root)) { Create(); } root.SetActive(true); root.GetComponent<CanvasScaler>().scaleFactor = Mathf.Clamp((float)Screen.width / 1280f, 0.85f, 1f); heading.text = "Vein Mining"; percent.text = $"{Mathf.RoundToInt(Mathf.Clamp01(progress) * 100f)}%"; fill.sizeDelta = new Vector2(320f * Mathf.Clamp01(progress), 9f); ((Component)((Transform)fill).GetChild(0)).GetComponent<RectTransform>().sizeDelta = new Vector2(fill.sizeDelta.x, 2f); string arg = ((miners == 1) ? "1 miner" : $"{Mathf.Max(0, miners)} miners"); activity.text = $"{oreSpeed:0.##}× · {arg}"; } } internal static void Hide() { if (Object.op_Implicit((Object)(object)root)) { root.SetActive(false); } } internal static void Destroy() { if (Object.op_Implicit((Object)(object)root)) { Object.Destroy((Object)(object)root); } root = null; } } internal sealed class MiningInput { private float lastPress = float.NegativeInfinity; internal bool Latched { get; private set; } internal bool Press(float now) { if (Latched) { Clear(); return true; } if (now >= lastPress && now - lastPress <= 0.35f) { Latched = true; lastPress = float.NegativeInfinity; } else { lastPress = now; } return false; } internal void Clear(bool keepTap = false) { Latched = false; if (!keepTap) { lastPress = float.NegativeInfinity; } } } [BepInPlugin("local.valheim.sharedmining", "Vein Mining", "0.3.4")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [NetworkCompatibility(/*Could not decode attribute arguments.*/)] public sealed class Plugin : BaseUnityPlugin { private sealed class ConfigurationManagerAttributes { public bool? Browsable = false; } public const string Id = "local.valheim.sharedmining"; public const string Version = "0.3.4"; internal static Plugin Instance; internal static bool Completing; internal ConfigEntry<KeyboardShortcut> HoldKey; internal ConfigEntry<string> Included; internal ConfigEntry<string> Excluded; internal ConfigEntry<float> Range; internal ConfigEntry<float> OreWorkMultiplier; private Harmony harmony; private ZRoutedRpc? bound; private ZNetScene? audited; private float auditAt; internal ManualLogSource Log => ((BaseUnityPlugin)this).Logger; private void Awake() { //IL_0021: 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_0044: Expected O, but got Unknown //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Expected O, but got Unknown //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Expected O, but got Unknown //IL_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Expected O, but got Unknown //IL_0131: Unknown result type (might be due to invalid IL or missing references) //IL_013b: Expected O, but got Unknown //IL_0146: Unknown result type (might be due to invalid IL or missing references) //IL_0150: Expected O, but got Unknown Instance = this; HoldKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Client", "HoldKey", new KeyboardShortcut((KeyCode)308, Array.Empty<KeyCode>()), new ConfigDescription("Hold Alt or double-tap for automatic mining.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes() })); Included = ((BaseUnityPlugin)this).Config.Bind<string>("Server", "AdditionalPrefabs", "", new ConfigDescription("Additional ore prefabs.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes() })); Excluded = ((BaseUnityPlugin)this).Config.Bind<string>("Server", "ExcludedPrefabs", "", new ConfigDescription("Excluded ore prefabs.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes() })); Range = ((BaseUnityPlugin)this).Config.Bind<float>("Server", "MaximumDistance", 6f, new ConfigDescription("Maximum contributor distance to an exposed deposit collider.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(2f, 12f), new object[1] { new ConfigurationManagerAttributes() })); OreWorkMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Multiplayer", "Ore Mining Multiplayer", 3f, new ConfigDescription("Applies to all supported ore deposits. 3 is the default; 1 is normal work per hit; 10 is the maximum. Only the host/server value is used. Team speed: 1 miner = 1x, 2 = 2x, 3 = 2.5x, then +0.5x per miner. Does not change loot or per-hit durability; fewer hits means less total wear. This is a speed adjustment, not simulated structural collapse.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 10f), Array.Empty<object>())); harmony = new Harmony("local.valheim.sharedmining"); harmony.PatchAll(); MiningCompatibility.Initialize(harmony); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Vein Mining 0.3.4 experimental build loaded; hold Left Alt to mine."); } private void Update() { if (ZRoutedRpc.instance != bound) { bound = ZRoutedRpc.instance; Server.Reset(); Client.Reset(); if (bound != null) { Server.Register(bound); } } if ((Object)(object)ZNetScene.instance != (Object)(object)audited) { audited = ZNetScene.instance; auditAt = Time.time + 8f; } if (Object.op_Implicit((Object)(object)audited) && auditAt > 0f && Time.time >= auditAt) { auditAt = 0f; try { Catalog.Audit(); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)ex); } } Server.UpdateActivity(); Client.Update(); Client.Draw(); } private void OnDestroy() { MiningHud.Destroy(); Harmony obj = harmony; if (obj != null) { obj.UnpatchSelf(); } Client.Reset(); Server.Reset(); } } internal static class Server { private sealed class Session { internal ZDOID Target; internal ZDOID Player; internal long Token; internal int Sequence; internal float LastHit = -10f; internal float LastSeen; } internal const string StartRpc = "SharedMining.Start.v1"; internal const string StopRpc = "SharedMining.Stop.v1"; internal const string HitRpc = "SharedMining.Hit.v1"; internal const string ReplyRpc = "SharedMining.Reply.v1"; internal const string KeepRpc = "SharedMining.Keep.v1"; internal const string ManualRpc = "SharedMining.Manual.v1"; internal const string MoveRpc = "SharedMining.Move.v1"; private static readonly Dictionary<long, Session> Sessions = new Dictionary<long, Session>(); private static long nextToken; internal const string MinersKey = "VeinMining.miners"; internal const string NamesKey = "VeinMining.names"; internal const string SpeedKey = "VeinMining.speed"; internal const string ActivityTimeKey = "VeinMining.activityTime"; private static readonly HashSet<ZDOID> ActivityTargets = new HashSet<ZDOID>(); private static float nextActivity; private static readonly Dictionary<ZDOID, float> Pins = new Dictionary<ZDOID, float>(); internal static bool IsServer { get { if (Object.op_Implicit((Object)(object)ZNet.instance)) { return ZNet.instance.IsServer(); } return false; } } internal static long ServerId { get { if (ZRoutedRpc.instance != null) { return (long)AccessTools.Method(typeof(ZRoutedRpc), "GetServerPeerID", (Type[])null, (Type[])null).Invoke(ZRoutedRpc.instance, null); } return 0L; } } internal static void Reset() { Sessions.Clear(); Pins.Clear(); ActivityTargets.Clear(); nextActivity = 0f; ManualMining.Reset(); } private static Session[] ActiveMiners(ZDOID id) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) return Sessions.Values.Where((Session s) => s.Target == id && Time.time - s.LastHit <= 4f && Time.time - s.LastSeen <= 15f).ToArray(); } internal static void UpdateActivity() { //IL_0044: 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_008a: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: 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_0179: Unknown result type (might be due to invalid IL or missing references) if (!IsServer || Time.time < nextActivity) { return; } nextActivity = Time.time + 0.5f; foreach (Session value in Sessions.Values) { ActivityTargets.Add(value.Target); } ZDOID[] array = ActivityTargets.ToArray(); foreach (ZDOID id in array) { ZDO zDO = ZDOMan.instance.GetZDO(id); if (zDO == null) { ActivityTargets.Remove(id); continue; } Session[] array2 = ActiveMiners(id); zDO.Set("VeinMining.miners", array2.Length); zDO.Set("VeinMining.speed", Plugin.Instance.OreWorkMultiplier.Value); zDO.Set("VeinMining.activityTime", (long)ZNet.instance.GetTimeSeconds()); zDO.Set("VeinMining.names", string.Join(", ", array2.Select(delegate(Session s) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) GameObject val = ZNetScene.instance.FindInstance(s.Player); Player val2 = (Object.op_Implicit((Object)(object)val) ? val.GetComponent<Player>() : null); string text = (Object.op_Implicit((Object)(object)val2) ? val2.GetPlayerName() : "Miner"); return (text.Length <= 24) ? text : text.Substring(0, 24); }).Take(6))); if (array2.Length == 0 && !Sessions.Values.Any((Session s) => s.Target == id)) { ActivityTargets.Remove(id); } } } internal static void Register(ZRoutedRpc rpc) { rpc.Register<ZPackage>("SharedMining.Start.v1", (Action<long, ZPackage>)Start); rpc.Register<ZPackage>("SharedMining.Stop.v1", (Action<long, ZPackage>)Stop); rpc.Register<ZPackage>("SharedMining.Hit.v1", (Action<long, ZPackage>)Hit); rpc.Register<ZPackage>("SharedMining.Reply.v1", (Action<long, ZPackage>)Client.Reply); rpc.Register<ZPackage>("SharedMining.Keep.v1", (Action<long, ZPackage>)Keep); rpc.Register<ZPackage>("SharedMining.Manual.v1", (Action<long, ZPackage>)Manual); rpc.Register<ZPackage>("SharedMining.Move.v1", (Action<long, ZPackage>)Client.Retarget); } private static void Manual(long sender, ZPackage pkg) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Expected O, but got Unknown //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_004f: 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_0087: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_0104: Unknown result type (might be due to invalid IL or missing references) if (!IsServer) { return; } try { if (pkg.GetArray().Length <= 2048) { ZDOID val = pkg.ReadZDOID(); int index = pkg.ReadInt(); HitData val2 = new HitData(); val2.Deserialize(ref pkg); ZDO zDO = ZDOMan.instance.GetZDO(val2.m_attacker); ZDO zDO2 = ZDOMan.instance.GetZDO(val); if (zDO != null && zDO2 != null && zDO.GetOwner() == sender && zDO2.GetBool("SharedMining.active.v1", false) && !(Vector3.Distance(zDO.GetPosition(), zDO2.GetPosition()) > 80f) && WorkLedger.Finite(val2.GetTotalDamage()) && !(val2.GetTotalDamage() <= 0f) && !(val2.GetTotalDamage() > 100000f) && WorkLedger.Finite(val2.m_damage.m_pickaxe) && !(val2.m_damage.m_pickaxe <= 0f) && EnsureLoaded(val2.m_attacker, player: true, sender) && EnsureLoaded(val, player: false, sender)) { ((MonoBehaviour)Plugin.Instance).StartCoroutine(ManualAfterLoad(sender, val, index, val2)); } } } catch (Exception ex) { Plugin.Instance.Log.LogWarning((object)("Manual mining request failed: " + ex.Message)); } } private static IEnumerator ManualAfterLoad(long sender, ZDOID id, int index, HitData hit) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) yield return null; try { Player val = PlayerFor(sender, hit.m_attacker); Deposit deposit = Deposit.Find(id); if (Object.op_Implicit((Object)(object)val) && deposit != null && index >= 0 && index < deposit.Parts.Length && !(deposit.Distance(((Component)val).transform.position) > Plugin.Instance.Range.Value)) { deposit.Data.SetOwner(ServerId); if (deposit.Rock is MineRock5) { AccessTools.Method(typeof(MineRock5), "RPC_Damage", (Type[])null, (Type[])null).Invoke(deposit.Rock, new object[3] { sender, hit, index }); } else if (deposit.Rock is MineRock) { AccessTools.Method(typeof(MineRock), "RPC_Hit", (Type[])null, (Type[])null).Invoke(deposit.Rock, new object[3] { sender, hit, index }); } else { AccessTools.Method(typeof(Destructible), "RPC_Damage", (Type[])null, (Type[])null).Invoke(deposit.Rock, new object[2] { sender, hit }); } } } catch (Exception ex) { Plugin.Instance.Log.LogError((object)("Manual mining failed: " + ex)); } } internal static void Retarget(ZDOID previous, ZDOID next) { //IL_0005: 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_001d: 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) //IL_004f: 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) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Expected O, but got Unknown //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) ActivityTargets.Add(previous); ActivityTargets.Add(next); Pins[next] = Time.time + 15f; foreach (KeyValuePair<long, Session> session in Sessions) { if (!(session.Value.Target != previous)) { session.Value.Target = next; ZPackage val = new ZPackage(); val.Write(previous); val.Write(next); val.Write(session.Value.Token); ZRoutedRpc.instance.InvokeRoutedRPC(session.Key, "SharedMining.Move.v1", new object[1] { val }); } } } internal static void Completed(ZDOID id) { //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_0076: Unknown result type (might be due to invalid IL or missing references) List<long> list = new List<long>(); foreach (KeyValuePair<long, Session> session in Sessions) { if (session.Value.Target == id) { list.Add(session.Key); } } foreach (long item in list) { Sessions.Remove(item); Reply(item, id, 0L, "Deposit fully mined."); } } private static bool EnsureLoaded(ZDOID id, bool player, long sender) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) ZDO zDO = ZDOMan.instance.GetZDO(id); if (zDO == null) { return false; } GameObject prefab = ZNetScene.instance.GetPrefab(zDO.GetPrefab()); if (Object.op_Implicit((Object)(object)prefab)) { bool num; if (!player) { num = !Catalog.Supported(prefab); } else { if (!Object.op_Implicit((Object)(object)prefab.GetComponent<Player>())) { goto IL_0056; } num = zDO.GetOwner() != sender; } if (!num) { Pins[id] = Time.time + 15f; if (!Object.op_Implicit((Object)(object)ZNetScene.instance.FindInstance(id))) { AccessTools.Method(typeof(ZNetScene), "CreateObject", (Type[])null, (Type[])null).Invoke(ZNetScene.instance, new object[1] { zDO }); } return true; } } goto IL_0056; IL_0056: return false; } internal static void KeepInstances(List<ZDO> currentNearObjects) { //IL_0057: 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_0103: Unknown result type (might be due to invalid IL or missing references) //IL_0124: Unknown result type (might be due to invalid IL or missing references) //IL_0167: Unknown result type (might be due to invalid IL or missing references) //IL_016c: Unknown result type (might be due to invalid IL or missing references) //IL_0173: Unknown result type (might be due to invalid IL or missing references) if (!IsServer) { return; } List<long> list = new List<long>(); foreach (KeyValuePair<long, Session> session in Sessions) { if (Time.time - session.Value.LastSeen > 15f) { list.Add(session.Key); continue; } Pins[session.Value.Target] = Time.time + 1f; Pins[session.Value.Player] = Time.time + 1f; } foreach (long item in list) { Sessions.Remove(item); } List<ZDOID> list2 = new List<ZDOID>(); foreach (KeyValuePair<ZDOID, float> pin in Pins) { ZDO zDO = ZDOMan.instance.GetZDO(pin.Key); if (Time.time > pin.Value || zDO == null) { list2.Add(pin.Key); } else if (!currentNearObjects.Contains(zDO)) { currentNearObjects.Add(zDO); } } foreach (ZDOID item2 in list2) { Pins.Remove(item2); } } private static void Keep(long sender, ZPackage pkg) { //IL_0039: 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_008b: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) if (!IsServer) { return; } try { if (pkg.GetArray().Length <= 16 && Sessions.TryGetValue(sender, out Session value) && pkg.ReadLong() == value.Token) { Player val = PlayerFor(sender, value.Player); Deposit deposit = Deposit.Find(value.Target); if (!Object.op_Implicit((Object)(object)val) || deposit == null || deposit.Distance(((Component)val).transform.position) > Plugin.Instance.Range.Value) { Sessions.Remove(sender); Reply(sender, value.Target, 0L, "Mining stopped. Shared progress has been saved."); } else { value.LastSeen = Time.time; } } } catch (Exception ex) { Plugin.Instance.Log.LogDebug((object)ex.Message); } } private static Player? PlayerFor(long sender, ZDOID id) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) GameObject val = (Object.op_Implicit((Object)(object)ZNetScene.instance) ? ZNetScene.instance.FindInstance(id) : null); Player val2 = (Object.op_Implicit((Object)(object)val) ? val.GetComponent<Player>() : null); ZNetView val3 = (Object.op_Implicit((Object)(object)val2) ? ((Component)val2).GetComponent<ZNetView>() : null); if (!Object.op_Implicit((Object)(object)val3) || !val3.IsValid() || val3.GetZDO().GetOwner() != sender || ((Character)val2).IsDead() || ((Character)val2).IsTeleporting()) { return null; } return val2; } private static void Reply(long sender, ZDOID id, long token, string message) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Expected O, but got Unknown //IL_0007: Unknown result type (might be due to invalid IL or missing references) ZPackage val = new ZPackage(); val.Write(id); val.Write(token); val.Write(message); ZRoutedRpc.instance.InvokeRoutedRPC(sender, "SharedMining.Reply.v1", new object[1] { val }); } private static void Start(long sender, ZPackage pkg) { //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0044: 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) //IL_0056: 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) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: 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 (!IsServer) { return; } ZDOID val = ZDOID.None; try { if (pkg.GetArray().Length <= 256 && pkg.ReadInt() == 1 && MiningCompatibility.Ready) { val = pkg.ReadZDOID(); ZDOID val2 = pkg.ReadZDOID(); ZDO zDO = ZDOMan.instance.GetZDO(val2); ZDO zDO2 = ZDOMan.instance.GetZDO(val); if (zDO == null || zDO2 == null || zDO.GetOwner() != sender || Vector3.Distance(zDO.GetPosition(), zDO2.GetPosition()) > 80f || !EnsureLoaded(val2, player: true, sender) || !EnsureLoaded(val, player: false, sender)) { Reply(sender, val, 0L, "This deposit is not supported or is too far away."); } else { ((MonoBehaviour)Plugin.Instance).StartCoroutine(StartAfterLoad(sender, val, val2)); } } } catch (Exception ex) { Plugin.Instance.Log.LogWarning((object)("Cannot load shared mining: " + ex.Message)); Reply(sender, val, 0L, "Could not load the deposit. Check the server log."); } } private static IEnumerator StartAfterLoad(long sender, ZDOID id, ZDOID playerId) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0015: 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) yield return null; try { Player val = PlayerFor(sender, playerId); Deposit deposit = Deposit.Find(id); if (!Object.op_Implicit((Object)(object)val) || deposit == null || deposit.Distance(((Component)val).transform.position) > Plugin.Instance.Range.Value) { Reply(sender, id, 0L, "This deposit is unavailable or is not supported."); yield break; } WorkLedger ledger = deposit.Load(); deposit.Data.SetOwner(ServerId); deposit.Data.Set("SharedMining.active.v1", true); deposit.Data.Set("VeinMining.speed", Plugin.Instance.OreWorkMultiplier.Value); deposit.Save(ledger); Sessions[sender] = new Session { Target = id, Player = playerId, Token = ++nextToken, LastSeen = Time.time }; Reply(sender, id, nextToken, "Vein Mining started. Hold Alt, or double-tap Alt for automatic mining."); } catch (Exception ex) { Plugin.Instance.Log.LogWarning((object)("Cannot start shared mining: " + ex.Message)); Reply(sender, id, 0L, "Could not start mining. Check the server log."); } } private static void Stop(long sender, ZPackage pkg) { if (!IsServer) { return; } try { if (pkg.GetArray().Length <= 32) { long num = pkg.ReadLong(); if (Sessions.TryGetValue(sender, out Session value) && value.Token == num) { Sessions.Remove(sender); } } } catch (Exception ex) { Plugin.Instance.Log.LogDebug((object)ex.Message); } } private static void Hit(long sender, ZPackage pkg) { //IL_0079: 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_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Expected O, but got Unknown //IL_01df: Unknown result type (might be due to invalid IL or missing references) //IL_01eb: Unknown result type (might be due to invalid IL or missing references) //IL_0122: Unknown result type (might be due to invalid IL or missing references) //IL_0128: Unknown result type (might be due to invalid IL or missing references) //IL_0264: Unknown result type (might be due to invalid IL or missing references) //IL_0323: Unknown result type (might be due to invalid IL or missing references) if (!IsServer) { return; } try { if (pkg.GetArray().Length > 32768 || !Sessions.TryGetValue(sender, out Session value)) { return; } long num = pkg.ReadLong(); int num2 = pkg.ReadInt(); int num3 = pkg.ReadInt(); if (num != value.Token || num2 <= value.Sequence || num3 < 1 || num3 > 64 || Time.time - value.LastHit < 0.15f) { return; } Player val = PlayerFor(sender, value.Player); Deposit deposit = Deposit.Find(value.Target); if (!Object.op_Implicit((Object)(object)val) || deposit == null || deposit.Distance(((Component)val).transform.position) > Plugin.Instance.Range.Value) { Sessions.Remove(sender); Reply(sender, value.Target, 0L, "Mining stopped. Shared progress has been saved."); return; } List<(int, HitData, float)> list = new List<(int, HitData, float)>(); for (int i = 0; i < num3; i++) { int num4 = pkg.ReadInt(); HitData val2 = new HitData(); val2.Deserialize(ref pkg); if (num4 < 0 || num4 >= deposit.Health.Length || val2.m_attacker != value.Player || val2.m_toolTier < deposit.Tier || !WorkLedger.Finite(val2.m_damage.m_pickaxe) || val2.m_damage.m_pickaxe <= 0f || !WorkLedger.Finite(val2.GetTotalDamage()) || val2.GetTotalDamage() <= 0f || val2.GetTotalDamage() > 100000f) { return; } list.Add((num4, val2, 0f)); } value.Sequence = num2; value.LastHit = (value.LastSeen = Time.time); ActivityTargets.Add(value.Target); float num5 = TeamScaling.PerMiner(ActiveMiners(value.Target).Length); deposit.Data.SetOwner(ServerId); WorkLedger workLedger = deposit.Load(); float num6 = MiningCompatibility.Factor(val); DamageModifier val3 = default(DamageModifier); foreach (var item in list) { if (workLedger.Complete) { break; } int index = workLedger.Next(item.Item1); HitData obj = item.Item2.Clone(); obj.ApplyResistance(deposit.ResistanceAt(index), ref val3); float num7 = obj.GetTotalDamage() * deposit.WorkMultiplier * num5; if (WorkLedger.Finite(num7) && !(num7 <= 0f)) { MiningCompatibility.Contribute(item.Item2, deposit); int num8 = workLedger.Apply(num7, item.Item1); if (num8 >= 0) { deposit.Data.Set("SharedMining.factor." + num8, num6); } } } deposit.Save(workLedger); if (workLedger.Complete) { deposit.Finish(list[list.Count - 1].Item2); Completed(value.Target); } } catch (Exception ex) { Plugin.Instance.Log.LogError((object)("Shared mining hit failed: " + ex)); } } } [HarmonyPatch(typeof(ZNetScene), "RemoveObjects")] internal static class ServerInstances { private static void Prefix(List<ZDO> currentNearObjects) { Server.KeepInstances(currentNearObjects); } } [HarmonyPatch(typeof(ZDO), "SetOwner")] internal static class KeepServerOwnership { private static void Prefix(ZDO __instance, ref long uid) { if (__instance.GetBool("SharedMining.active.v1", false) && Server.ServerId != 0L) { uid = Server.ServerId; } } } internal static class TeamScaling { internal static float Total(int miners) { if (miners > 0) { if (miners > 2) { return 2f + (float)(miners - 2) * 0.5f; } return miners; } return 0f; } internal static float PerMiner(int miners) { if (miners > 0) { return Total(miners) / (float)miners; } return 1f; } } public sealed class WorkLedger { public float[] Remaining { get; } public float Total { get; } public bool Complete => Remaining.All((float x) => x <= 0f); public float Progress { get { if (!(Total > 0f)) { return 1f; } return Math.Max(0f, Math.Min(1f, 1f - Remaining.Sum() / Total)); } } public WorkLedger(float[] remaining, float total) { if (remaining.Length == 0 || remaining.Length > 4096 || remaining.Any((float x) => !Finite(x) || x < 0f) || !Finite(total) || total <= 0f || remaining.Sum() > total + 0.1f) { throw new ArgumentException("Invalid deposit state"); } Remaining = (float[])remaining.Clone(); Total = total; } public int Apply(float damage, int preferred) { if (!Finite(damage) || damage <= 0f || Complete) { return -1; } int num = Next(preferred); Remaining[num] = Math.Max(0f, Remaining[num] - damage); return num; } public int Next(int preferred) { if (preferred < 0 || preferred >= Remaining.Length || !(Remaining[preferred] > 0f)) { return Array.FindIndex(Remaining, (float x) => x > 0f); } return preferred; } public void ReconcileNative(float[] before, float[] after) { if (before.Length != Remaining.Length || after.Length != Remaining.Length || before.Any((float x) => !Finite(x) || x < 0f) || after.Any((float x) => !Finite(x) || x < 0f)) { throw new ArgumentException("Invalid native health snapshot"); } for (int num = 0; num < Remaining.Length; num++) { Remaining[num] = ((after[num] <= 0f) ? 0f : Math.Max(0f, Remaining[num] - Math.Max(0f, before[num] - after[num]))); } } public void Explode() { Array.Clear(Remaining, 0, Remaining.Length); } public static bool Finite(float value) { if (!float.IsNaN(value)) { return !float.IsInfinity(value); } return false; } } }