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 SmelterLinkMPFix v0.1.0
SmelterLinkFix.dll
Decompiled a week agousing System; using System.Collections.Generic; using System.Diagnostics; 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 Microsoft.CodeAnalysis; using UnityEngine; using UnityEngine.Rendering; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyCompany("SmelterLinkFix")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("0.1.0.0")] [assembly: AssemblyInformationalVersion("0.1.0+9eab8a94d563b5e02bc6be49a5ce9c5766bcb90f")] [assembly: AssemblyProduct("SmelterLinkFix")] [assembly: AssemblyTitle("SmelterLinkFix")] [assembly: AssemblyVersion("0.1.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [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 SmelterLinkFix { internal static class ActionBlockPatches { private static bool Blocking(Player player) { if (Plugin.BlockActions.Value) { return InputBlockPatches.IsLinking(player); } return false; } public static bool TakeInputPrefix(Player __instance, ref bool __result) { if (!Blocking(__instance)) { return true; } __result = false; return false; } public static void SetControlsPrefix(Player __instance, ref bool attack, ref bool attackHold, ref bool secondaryAttack, ref bool secondaryAttackHold, ref bool block, ref bool blockHold, bool jump) { if (Blocking(__instance)) { attack = (attackHold = false); secondaryAttack = (secondaryAttackHold = false); if (!jump) { block = (blockHold = false); } } } public static bool InventoryShowPrefix() { return !Blocking(Player.m_localPlayer); } public static bool SetMapModePrefix(MapMode mode) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Invalid comparison between Unknown and I4 if ((int)mode == 2) { return !Blocking(Player.m_localPlayer); } return true; } public static void ApplyDamagePrefix(Character __instance, out float __state) { __state = -1f; try { if (Plugin.CancelOnDamage.Value && InputBlockPatches.IsLinking((Player)(object)((__instance is Player) ? __instance : null))) { __state = __instance.GetHealth(); } } catch (Exception e) { ErrorLog.Once("ApplyDamagePrefix", e); } } public static void ApplyDamagePostfix(Character __instance, HitData hit, float __state) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Invalid comparison between Unknown and I4 //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Invalid comparison between Unknown and I4 //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Invalid comparison between Unknown and I4 try { if (!(__state < 0f) && hit != null && !(__instance.GetHealth() >= __state) && ((int)hit.m_hitType == 1 || (int)hit.m_hitType == 2 || (int)hit.m_hitType == 16) && InputBlockPatches.IsLinking((Player)(object)((__instance is Player) ? __instance : null))) { LinkModeAccess.Cancel(); Notify.Center("Linking cancelled: you were hit"); } } catch (Exception e) { ErrorLog.Once("ApplyDamagePostfix", e); } } } internal static class ChestAccess { private static Func<Container, bool> s_load; public static bool Init() { MethodInfo methodInfo = AccessTools.Method(typeof(Container), "Load", Type.EmptyTypes, (Type[])null); if (methodInfo == null || methodInfo.ReturnType != typeof(bool)) { return false; } s_load = (Func<Container, bool>)Delegate.CreateDelegate(typeof(Func<Container, bool>), methodInfo, throwOnBindFailure: false); return s_load != null; } public static Container Live(ZDO chest) { if ((Object)(object)ZNetScene.instance == (Object)null) { return null; } ZNetView val = ZNetScene.instance.FindInstance(chest); if (!((Object)(object)val != (Object)null)) { return null; } return ((Component)val).GetComponentInChildren<Container>(); } public static void Refresh(Container live) { if (!live.IsInUse()) { s_load(live); } } public static bool IsInUse(ZDO chest, Container live) { if ((Object)(object)live != (Object)null && chest.IsOwner()) { return live.IsInUse(); } return chest.GetInt(ZDOVars.s_inUse, 0) == 1; } public static bool HasLiveOwner(ZDO chest) { if (!chest.HasOwner()) { return false; } long owner = chest.GetOwner(); if (owner == ZDOMan.GetSessionID() || (Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer()) { return true; } return ZNet.instance.GetPeer(owner) != null; } public static bool TryClaimUnowned(ZDO chest) { if ((Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer()) { return false; } if (HasLiveOwner(chest) || chest.GetInt(ZDOVars.s_inUse, 0) == 1) { return false; } chest.SetOwner(ZDOMan.GetSessionID()); return true; } public static int TakeLocal(ZDO chest, string prefabName, int want) { Container val = Live(chest); if (IsInUse(chest, val)) { return 0; } if ((Object)(object)val != (Object)null) { Refresh(val); return RemoveMatching(val.GetInventory(), prefabName, want); } Inventory val2 = LoadFromZdo(chest); if (val2 == null) { return 0; } int num = RemoveMatching(val2, prefabName, want); if (num > 0) { SaveToZdo(chest, val2); } return num; } public static bool PutLocal(ZDO chest, string prefabName, int amount) { Container val = Live(chest); if ((Object)(object)val != (Object)null) { Refresh(val); return AddIfFits(val.GetInventory(), prefabName, amount); } Inventory val2 = LoadFromZdo(chest); if (val2 == null || !AddIfFits(val2, prefabName, amount)) { return false; } SaveToZdo(chest, val2); return true; } public static bool Fits(ZDO chest, string prefabName, int amount) { Inventory val = LoadFromZdo(chest); if (val != null) { return CanFit(val, prefabName, amount); } return false; } public static void Drop(string prefabName, int amount, Vector3 position) { //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0091: 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_00a0: 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_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) GameObject val = (((Object)(object)ObjectDB.instance != (Object)null) ? ObjectDB.instance.GetItemPrefab(prefabName) : null); ItemDrop val2 = (((Object)(object)val != (Object)null) ? val.GetComponent<ItemDrop>() : null); if ((Object)(object)val2 == (Object)null || (Object)(object)ZNetScene.instance == (Object)null) { Plugin.Log.LogError((object)$"Cannot drop {amount}x {prefabName}: item prefab or scene not available, items lost"); return; } int num = Mathf.Max(1, val2.m_itemData.m_shared.m_maxStackSize); int num2 = amount; while (num2 > 0) { int num3 = Mathf.Min(num2, num); num2 -= num3; ItemDrop component = Object.Instantiate<GameObject>(val, position + Vector3.up + Random.insideUnitSphere * 0.3f, Quaternion.identity).GetComponent<ItemDrop>(); component.m_itemData.m_stack = num3; ItemDrop.OnCreateNew(component, false); component.SetStack(num3); } Plugin.Log.LogWarning((object)$"Dropped {amount}x {prefabName} at {position:0} (chest full or unreachable)"); } private static int RemoveMatching(Inventory inventory, string prefabName, int want) { int num = 0; foreach (ItemData item in new List<ItemData>(inventory.GetAllItems())) { if (num >= want) { break; } if (!((Object)(object)item?.m_dropPrefab == (Object)null) && !(((Object)item.m_dropPrefab).name != prefabName)) { int num2 = Mathf.Min(item.m_stack, want - num); if (inventory.RemoveItem(item, num2)) { num += num2; } } } return num; } private static bool AddIfFits(Inventory inventory, string prefabName, int amount) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) if (!CanFit(inventory, prefabName, amount)) { return false; } ItemData obj = inventory.AddItem(prefabName, amount, 1, 0, 0L, "", new Vector2i(-1, -1), false, false, false); if (obj == null) { Plugin.Log.LogError((object)$"AddItem {amount}x {prefabName} failed after CanAddItem said it fits"); } return obj != null; } private static bool CanFit(Inventory inventory, string prefabName, int amount) { GameObject val = (((Object)(object)ObjectDB.instance != (Object)null) ? ObjectDB.instance.GetItemPrefab(prefabName) : null); ItemDrop val2 = (((Object)(object)val != (Object)null) ? val.GetComponent<ItemDrop>() : null); if ((Object)(object)val2 == (Object)null) { return false; } ItemData val3 = val2.m_itemData.Clone(); val3.m_quality = 1; val3.m_worldLevel = (byte)Game.m_worldLevel; return inventory.CanAddItem(val3, amount); } private static Inventory LoadFromZdo(ZDO chest) { //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Expected O, but got Unknown //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Expected O, but got Unknown GameObject val = (((Object)(object)ZNetScene.instance != (Object)null) ? ZNetScene.instance.GetPrefab(chest.GetPrefab()) : null); Container val2 = (((Object)(object)val != (Object)null) ? val.GetComponentInChildren<Container>() : null); if ((Object)(object)val2 == (Object)null) { return null; } Inventory val3 = new Inventory(val2.m_name, val2.m_bkg, val2.m_width, val2.m_height); byte[] byteArray = chest.GetByteArray(ZDOVars.s_items, (byte[])null); if (byteArray != null) { val3.Load(new ZPackage(byteArray)); } return val3; } private static void SaveToZdo(ZDO chest, Inventory inventory) { //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(); inventory.Save(val); chest.Set(ZDOVars.s_items, val.GetArray()); } } internal static class ChestFinder { private delegate void FindObjectsFn(ZDOMan self, Vector2s sector, List<ZDO> objects, HashSet<SectorIndex> visited); private struct Miss { public float RetryAt; public float Delay; } private const float MinRetrySeconds = 1f; private const float MaxRetrySeconds = 10f; private static FindObjectsFn s_findObjects; private static ZDOMan s_zdoMan; private static readonly Dictionary<(long, Vector2s), ZDO> s_found = new Dictionary<(long, Vector2s), ZDO>(); private static readonly Dictionary<(long, Vector2s), Miss> s_misses = new Dictionary<(long, Vector2s), Miss>(); private static readonly Dictionary<int, bool> s_containerPrefabs = new Dictionary<int, bool>(); private static readonly List<ZDO> s_buffer = new List<ZDO>(); private static readonly HashSet<SectorIndex> s_visited = new HashSet<SectorIndex>(); public static bool Init() { MethodInfo methodInfo = AccessTools.Method(typeof(ZDOMan), "FindObjects", new Type[3] { typeof(Vector2s), typeof(List<ZDO>), typeof(HashSet<SectorIndex>) }, (Type[])null); if (methodInfo == null) { return false; } s_findObjects = (FindObjectsFn)Delegate.CreateDelegate(typeof(FindObjectsFn), methodInfo, throwOnBindFailure: false); return s_findObjects != null; } public static ZDO Find(long uid, Vector3 near) { //IL_003e: 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_0099: 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) ZDOMan instance = ZDOMan.instance; if (uid == 0L || instance == null) { return null; } if (instance != s_zdoMan) { s_zdoMan = instance; s_found.Clear(); s_misses.Clear(); } float value = Plugin.SearchRadius.Value; (long, Vector2s) key = (uid, ZoneSystem.GetZone(near)); if (s_found.TryGetValue(key, out var value2)) { if (Matches(value2, uid) && InRange(value2, near, value)) { return value2; } s_found.Remove(key); } s_misses.TryGetValue(key, out var value3); if (Time.time < value3.RetryAt) { return null; } ZDO val = Scan(instance, uid, near, value); if (val != null) { s_found[key] = val; s_misses.Remove(key); } else { float num = ((value3.Delay <= 0f) ? 1f : Mathf.Min(value3.Delay * 2f, 10f)); s_misses[key] = new Miss { RetryAt = Time.time + num, Delay = num }; } return val; } public static bool IsContainer(ZDO zdo) { int prefab = zdo.GetPrefab(); if (s_containerPrefabs.TryGetValue(prefab, out var value)) { return value; } if ((Object)(object)ZNetScene.instance == (Object)null) { return false; } GameObject prefab2 = ZNetScene.instance.GetPrefab(prefab); if ((Object)(object)prefab2 == (Object)null) { return false; } value = (Object)(object)prefab2.GetComponent<Container>() != (Object)null; s_containerPrefabs[prefab] = value; return value; } private static bool Matches(ZDO zdo, long uid) { if (zdo.IsValid() && IsContainer(zdo)) { return zdo.GetLong(ChestUid.UidKey, 0L) == uid; } return false; } private static bool InRange(ZDO zdo, Vector3 near, float radius) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) return HorizontalDistanceSqr(zdo.GetPosition(), near) <= radius * radius; } public static float HorizontalDistanceSqr(Vector3 a, Vector3 b) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) float num = a.x - b.x; float num2 = a.z - b.z; return num * num + num2 * num2; } public static float HorizontalDistance(Vector3 a, Vector3 b) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) return Mathf.Sqrt(HorizontalDistanceSqr(a, b)); } private static ZDO Scan(ZDOMan zdoMan, long uid, Vector3 near, float radius) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //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_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_0052: 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_00ae: Unknown result type (might be due to invalid IL or missing references) int num = Mathf.CeilToInt(radius / 64f + 0.5f); Vector2s zone = ZoneSystem.GetZone(near); s_buffer.Clear(); s_visited.Clear(); for (int i = -num; i <= num; i++) { for (int j = -num; j <= num; j++) { s_findObjects(zdoMan, new Vector2s(zone.x + i, zone.y + j), s_buffer, s_visited); } } ZDO result = null; float num2 = radius * radius; foreach (ZDO item in s_buffer) { if (item != null && Matches(item, uid)) { float num3 = HorizontalDistanceSqr(item.GetPosition(), near); if (num3 <= num2) { result = item; num2 = num3; } } } s_buffer.Clear(); return result; } } internal static class ChestPatches { private delegate bool PeerAreaFn(ZDOMan self, Vector3 point, long uid); private static PeerAreaFn s_isInPeerActiveArea; public static bool Init() { MethodInfo methodInfo = AccessTools.Method(typeof(ZDOMan), "IsInPeerActiveArea", new Type[2] { typeof(Vector3), typeof(long) }, (Type[])null); if (methodInfo == null) { return false; } s_isInPeerActiveArea = (PeerAreaFn)Delegate.CreateDelegate(typeof(PeerAreaFn), methodInfo, throwOnBindFailure: false); return s_isInPeerActiveArea != null; } public static bool TakePrefix(ZDO zdo, string prefabName, int want, ref int __result) { __result = 0; try { if (want <= 0 || zdo == null || !zdo.IsValid() || !ChestFinder.IsContainer(zdo)) { return false; } if (zdo.IsOwner() || ChestAccess.TryClaimUnowned(zdo)) { __result = ChestAccess.TakeLocal(zdo, prefabName, want); } else if (ChestAccess.HasLiveOwner(zdo)) { ChestRpc.RequestOwnership(zdo); } } catch (Exception e) { ErrorLog.Once("TakePrefix", e); __result = 0; } return false; } public static bool PutPrefix(ZDO zdo, string prefabName, int amount, ref bool __result) { __result = false; try { if (amount <= 0) { __result = true; return false; } if (zdo == null || !zdo.IsValid() || !ChestFinder.IsContainer(zdo)) { return false; } if (zdo.IsOwner() || ChestAccess.TryClaimUnowned(zdo)) { __result = ChestAccess.PutLocal(zdo, prefabName, amount); } else if (ChestAccess.HasLiveOwner(zdo) && ChestAccess.Fits(zdo, prefabName, amount)) { ChestRpc.SendPut(zdo, prefabName, amount); __result = true; } } catch (Exception e) { ErrorLog.Once("PutPrefix", e); __result = false; } return false; } public static void SetInUsePrefix(Container __instance, bool inUse) { try { if (inUse && !__instance.IsInUse() && __instance.IsOwner()) { ChestAccess.Refresh(__instance); } } catch (Exception e) { ErrorLog.Once("SetInUsePrefix", e); } } public static void StackResponsePrefix(Container __instance, bool granted) { try { if (granted) { ChestAccess.Refresh(__instance); } } catch (Exception e) { ErrorLog.Once("StackResponsePrefix", e); } } public static bool GuardIntPrefix(ZDO zdo, ref int __result) { if (!HandledByOtherPeer(zdo)) { return true; } __result = 0; return false; } public static bool GuardBoolPrefix(ZDO zdo, ref bool __result) { if (!HandledByOtherPeer(zdo)) { return true; } __result = false; return false; } private static bool HandledByOtherPeer(ZDO smelter) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) try { return smelter != null && smelter.HasOwner() && !smelter.IsOwner() && s_isInPeerActiveArea(ZDOMan.instance, smelter.GetPosition(), smelter.GetOwner()); } catch (Exception e) { ErrorLog.Once("HandledByOtherPeer", e); return false; } } } internal static class ChestRpc { private struct PendingPut { public string Prefab; public int Amount; public Vector3 DropPosition; public long Owner; public float Deadline; } private const string PutRpc = "SLFix_Put"; private const string PutAckRpc = "SLFix_PutAck"; private const string OwnerRpc = "SLFix_RequestChestOwner"; private const float PutTimeoutSeconds = 30f; private const float OwnerRequestCooldown = 3f; private const int MaxPutAmount = 100000; private static readonly Dictionary<long, PendingPut> s_pendingPuts = new Dictionary<long, PendingPut>(); private static readonly Dictionary<ZDOID, float> s_ownerRequestAt = new Dictionary<ZDOID, float>(); private static long s_nextRequestId = 1L; public static void Register() { FlushPending("world closed"); s_ownerRequestAt.Clear(); if (ZRoutedRpc.instance == null) { return; } try { ZRoutedRpc.instance.Register<ZDOID, string, int, Vector3, long>("SLFix_Put", (Method<ZDOID, string, int, Vector3, long>)RPC_Put); ZRoutedRpc.instance.Register<long>("SLFix_PutAck", (Action<long, long>)RPC_PutAck); ZRoutedRpc.instance.Register<ZDOID>("SLFix_RequestChestOwner", (Action<long, ZDOID>)RPC_RequestOwner); } catch (Exception arg) { Plugin.Log.LogError((object)$"Chest RPC registration failed: {arg}"); } } public static void SendPut(ZDO chest, string prefab, int amount) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001c: 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_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) long owner = chest.GetOwner(); long num = s_nextRequestId++; Vector3 position = chest.GetPosition(); s_pendingPuts[num] = new PendingPut { Prefab = prefab, Amount = amount, DropPosition = position, Owner = owner, Deadline = Time.time + 30f }; ZRoutedRpc.instance.InvokeRoutedRPC(owner, "SLFix_Put", new object[5] { chest.m_uid, prefab, amount, position, num }); } public static void RequestOwnership(ZDO chest) { //IL_0006: 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_0051: Unknown result type (might be due to invalid IL or missing references) if (!s_ownerRequestAt.TryGetValue(chest.m_uid, out var value) || !(Time.time < value)) { s_ownerRequestAt[chest.m_uid] = Time.time + 3f; ZRoutedRpc.instance.InvokeRoutedRPC(chest.GetOwner(), "SLFix_RequestChestOwner", new object[1] { chest.m_uid }); } } public static void CheckTimeouts() { //IL_00e2: Unknown result type (might be due to invalid IL or missing references) if (s_pendingPuts.Count == 0 || (Object)(object)ZNet.instance == (Object)null) { return; } List<long> list = null; foreach (KeyValuePair<long, PendingPut> s_pendingPut in s_pendingPuts) { if (Time.time > s_pendingPut.Value.Deadline) { (list ?? (list = new List<long>())).Add(s_pendingPut.Key); } } if (list == null) { return; } foreach (long item in list) { PendingPut pendingPut = s_pendingPuts[item]; s_pendingPuts.Remove(item); Plugin.Log.LogWarning((object)string.Format("{0} #{1} not confirmed by {2}, dropping items instead", "SLFix_Put", item, pendingPut.Owner)); ChestAccess.Drop(pendingPut.Prefab, pendingPut.Amount, pendingPut.DropPosition); } } public static void ShutdownPrefix() { //IL_0040: Unknown result type (might be due to invalid IL or missing references) try { if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer()) { foreach (PendingPut value in s_pendingPuts.Values) { ChestAccess.Drop(value.Prefab, value.Amount, value.DropPosition); } s_pendingPuts.Clear(); } FlushPending("world closed"); } catch (Exception e) { ErrorLog.Once("ShutdownPrefix", e); } } private static void FlushPending(string reason) { foreach (KeyValuePair<long, PendingPut> s_pendingPut in s_pendingPuts) { Plugin.Log.LogWarning((object)string.Format("{0} #{1} ({2}x {3}) unconfirmed ({4})", "SLFix_Put", s_pendingPut.Key, s_pendingPut.Value.Amount, s_pendingPut.Value.Prefab, reason)); } s_pendingPuts.Clear(); } private static void RPC_Put(long sender, ZDOID chestId, string prefab, int amount, Vector3 dropPosition, long id) { //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_0055: 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_0084: Unknown result type (might be due to invalid IL or missing references) bool flag = false; try { if (amount <= 0 || amount > 100000) { Plugin.Log.LogWarning((object)string.Format("{0} #{1} from {2}: invalid amount {3}, ignored", "SLFix_Put", id, sender, amount)); flag = true; } else { ZDO zDO = ZDOMan.instance.GetZDO(chestId); if (zDO != null && zDO.IsOwner() && ChestFinder.IsContainer(zDO) && ChestAccess.PutLocal(zDO, prefab, amount)) { flag = true; } else { flag = true; ChestAccess.Drop(prefab, amount, (zDO != null) ? zDO.GetPosition() : dropPosition); } } } catch (Exception arg) { Plugin.Log.LogError((object)string.Format("{0} #{1} failed: {2}", "SLFix_Put", id, arg)); if (!flag) { try { ChestAccess.Drop(prefab, amount, dropPosition); } catch (Exception ex) { Plugin.Log.LogError((object)string.Format("{0} #{1} drop failed, {2}x {3} lost: {4}", "SLFix_Put", id, amount, prefab, ex)); } } } ZRoutedRpc.instance.InvokeRoutedRPC(sender, "SLFix_PutAck", new object[1] { id }); } private static void RPC_PutAck(long sender, long id) { if (s_pendingPuts.TryGetValue(id, out var value) && value.Owner == sender) { s_pendingPuts.Remove(id); } } private static void RPC_RequestOwner(long sender, ZDOID chestId) { //IL_0005: 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) try { ZDO zDO = ZDOMan.instance.GetZDO(chestId); if (zDO != null && zDO.IsOwner() && !ChestAccess.IsInUse(zDO, ChestAccess.Live(zDO))) { ZDOMan.instance.ForceSendZDO(sender, chestId); zDO.SetOwner(sender); } } catch (Exception e) { ErrorLog.Once("SLFix_RequestChestOwner", e); } } } internal static class ChestUid { public static readonly int UidKey = StringExtensionMethods.GetStableHashCode("slfix_uid"); private static readonly int[] s_slotKeys = new int[3] { StringExtensionMethods.GetStableHashCode("slfix_in"), StringExtensionMethods.GetStableHashCode("slfix_fuel"), StringExtensionMethods.GetStableHashCode("slfix_out") }; public static int SlotKey(int slot) { return s_slotKeys[slot]; } public static int SlotIndex(object slot) { int num = Convert.ToInt32(slot); if (num < 0 || num >= s_slotKeys.Length) { throw new ArgumentOutOfRangeException("slot", num, "Unknown SmelterLink slot"); } return num; } public static long NewUid() { long num; do { num = BitConverter.ToInt64(Guid.NewGuid().ToByteArray(), 0); } while (num == 0L); return num; } } internal static class ErrorLog { private static readonly HashSet<string> s_logged = new HashSet<string>(); public static void Once(string where, Exception e) { if (s_logged.Add(where)) { Plugin.Log.LogError((object)$"{where} failed: {e}"); } } } internal static class InputBlockPatches { public static bool UseHotbarItemPrefix(Player __instance) { return !IsLinking(__instance); } public static bool StartEmotePrefix(Player __instance, string emote, ref bool __result) { if (emote != "sit" || !IsLinking(__instance)) { return true; } __result = false; return false; } public static bool MenuShowPrefix() { try { return !ZInput.GetKeyDown((KeyCode)27, true) || !LinkModeAccess.SelectingNowOrLastFrame; } catch (Exception e) { ErrorLog.Once("MenuShowPrefix", e); return true; } } public static void TrackSelecting() { try { LinkModeAccess.LateUpdate(); } catch (Exception e) { ErrorLog.Once("TrackSelecting", e); } } public static bool IsLinking(Player player) { try { return (Object)(object)player != (Object)null && (Object)(object)player == (Object)(object)Player.m_localPlayer && LinkModeAccess.Selecting; } catch (Exception e) { ErrorLog.Once("IsLinking", e); return false; } } } internal static class LinkModeAccess { private static Func<bool> s_selecting; private static Action s_cancel; private static FieldInfo s_smelterField; private static int s_lastSelectingFrame = -1; public static bool CanCancel => s_cancel != null; public static bool CanGetSmelter => s_smelterField != null; public static bool Selecting => s_selecting(); public static ZDO Smelter { get { //IL_002d: Unknown result type (might be due to invalid IL or missing references) if (s_smelterField == null || !Selecting || ZDOMan.instance == null) { return null; } ZDO zDO = ZDOMan.instance.GetZDO((ZDOID)s_smelterField.GetValue(null)); if (zDO == null || !zDO.IsValid()) { return null; } return zDO; } } public static bool SelectingNowOrLastFrame { get { if (!Selecting) { return s_lastSelectingFrame == Time.frameCount - 1; } return true; } } public static bool Init() { Type type = AccessTools.TypeByName("SmelterLink.LinkMode"); if (type == null) { return false; } MethodInfo methodInfo = AccessTools.PropertyGetter(type, "Selecting"); if (methodInfo == null || methodInfo.ReturnType != typeof(bool)) { return false; } s_selecting = (Func<bool>)Delegate.CreateDelegate(typeof(Func<bool>), methodInfo); MethodInfo methodInfo2 = AccessTools.Method(type, "Cancel", Type.EmptyTypes, (Type[])null); if (methodInfo2 != null && methodInfo2.IsStatic && methodInfo2.ReturnType == typeof(void)) { s_cancel = (Action)Delegate.CreateDelegate(typeof(Action), methodInfo2); } FieldInfo fieldInfo = AccessTools.Field(type, "_smelter"); if (fieldInfo != null && fieldInfo.IsStatic && fieldInfo.FieldType == typeof(ZDOID)) { s_smelterField = fieldInfo; } return true; } public static void Cancel() { s_cancel(); } public static void LateUpdate() { if (Selecting) { s_lastSelectingFrame = Time.frameCount; } } } internal static class LinkPatches { private static readonly KeyValuePair<int, int>[] s_legacyKeys = new KeyValuePair<int, int>[3] { ZDO.GetHashZDOID("slink_in"), ZDO.GetHashZDOID("slink_fuel"), ZDO.GetHashZDOID("slink_out") }; private static Action<ZDO> s_claimSmelter; private static Action<ZDO> s_trackSmelter; public static bool Init(Type links, Type registry) { s_claimSmelter = StaticAction(links, "Claim"); s_trackSmelter = StaticAction(registry, "Track"); if (s_claimSmelter != null) { return s_trackSmelter != null; } return false; } private static Action<ZDO> StaticAction(Type type, string name) { MethodInfo methodInfo = ((type == null) ? null : AccessTools.Method(type, name, new Type[1] { typeof(ZDO) }, (Type[])null)); if (!(methodInfo == null)) { return (Action<ZDO>)Delegate.CreateDelegate(typeof(Action<ZDO>), methodInfo, throwOnBindFailure: false); } return null; } public static bool GetPrefix(ZDO zdo, object slot, ref ZDOID __result) { //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_000c: 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) try { __result = FindTarget(zdo, slot)?.m_uid ?? ZDOID.None; } catch (Exception e) { ErrorLog.Once("GetPrefix", e); __result = ZDOID.None; } return false; } public static bool ResolvePrefix(ZDO smelter, object slot, ref ZDO __result) { try { __result = FindTarget(smelter, slot); } catch (Exception e) { ErrorLog.Once("ResolvePrefix", e); __result = null; } return false; } public static bool HasAnyPrefix(ZDO zdo, ref bool __result) { try { __result = zdo != null && (zdo.GetLong(ChestUid.SlotKey(0), 0L) != 0L || zdo.GetLong(ChestUid.SlotKey(1), 0L) != 0L || zdo.GetLong(ChestUid.SlotKey(2), 0L) != 0); } catch (Exception e) { ErrorLog.Once("HasAnyPrefix", e); __result = false; } return false; } public static bool SetPrefix(ZDO zdo, object slot, ZDOID target) { //IL_0013: 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_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0068: 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) try { if (zdo == null) { return false; } int slot2 = ChestUid.SlotIndex(slot); UidRpc.CancelPending(zdo.m_uid, slot2); if (((ZDOID)(ref target)).IsNone()) { WriteLink(zdo, slot2, 0L); return false; } ZDO zDO = ZDOMan.instance.GetZDO(target); if (zDO == null || !ChestFinder.IsContainer(zDO)) { Notify.Center("Link failed: chest not found"); return false; } float num = ChestFinder.HorizontalDistance(zdo.GetPosition(), zDO.GetPosition()); if (num > Plugin.SearchRadius.Value) { Notify.Center($"Chest is {num:0}m away, more than SearchRadius ({Plugin.SearchRadius.Value:0}m): link saved but not used"); } long num2 = zDO.GetLong(ChestUid.UidKey, 0L); if (num2 != 0L) { WriteLink(zdo, slot2, num2); } else if (zDO.IsOwner()) { num2 = ChestUid.NewUid(); zDO.Set(ChestUid.UidKey, num2); WriteLink(zdo, slot2, num2); } else { UidRpc.Request(zdo.m_uid, slot2, zDO); } } catch (Exception e) { ErrorLog.Once("SetPrefix", e); } return false; } public static void WriteLink(ZDO smelter, int slot, long uid) { s_claimSmelter(smelter); smelter.Set(ChestUid.SlotKey(slot), uid); ClearLegacyLinks(smelter); if (uid != 0L) { s_trackSmelter(smelter); } } private static void ClearLegacyLinks(ZDO smelter) { //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_0025: Unknown result type (might be due to invalid IL or missing references) KeyValuePair<int, int>[] array = s_legacyKeys; foreach (KeyValuePair<int, int> keyValuePair in array) { ZDOID zDOID = smelter.GetZDOID(keyValuePair); if (!((ZDOID)(ref zDOID)).IsNone()) { smelter.Set(keyValuePair, ZDOID.None); } } } private static ZDO FindTarget(ZDO smelter, object slot) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) if (smelter == null) { return null; } return ChestFinder.Find(smelter.GetLong(ChestUid.SlotKey(ChestUid.SlotIndex(slot)), 0L), smelter.GetPosition()); } } internal static class Notify { private static string s_pending; private static int s_showFrame; public static void Center(string text) { Plugin.Log.LogInfo((object)text); s_pending = text; s_showFrame = Time.frameCount + 1; } public static void Update() { if (s_pending != null && Time.frameCount >= s_showFrame) { if ((Object)(object)MessageHud.instance != (Object)null) { MessageHud.instance.ShowMessage((MessageType)2, s_pending, 0, (Sprite)null, false, true); } s_pending = null; } } } [BepInPlugin("radek.smelterlinkfix", "SmelterLinkFix", "0.1.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class Plugin : BaseUnityPlugin { public const string PluginGuid = "radek.smelterlinkfix"; public const string PluginName = "SmelterLinkFix"; public const string PluginVersion = "0.1.0"; private const string TargetGuid = "nishinku.smelterlink"; private const string TargetVersion = "0.2.0"; private Harmony _harmony; private bool _active; private bool _updateErrorLogged; internal static ManualLogSource Log { get; private set; } internal static ConfigEntry<float> SearchRadius { get; private set; } internal static ConfigEntry<bool> BlockActions { get; private set; } internal static ConfigEntry<bool> CancelOnDamage { get; private set; } internal static ConfigEntry<bool> ShowRange { get; private set; } private void Awake() { //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Expected O, but got Unknown //IL_0138: Unknown result type (might be due to invalid IL or missing references) //IL_0142: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; SearchRadius = ((BaseUnityPlugin)this).Config.Bind<float>("Links", "SearchRadius", 64f, new ConfigDescription("How far from a smelter (horizontal distance in meters) linked chests are searched for. Chests further away stay linked but are not used", (AcceptableValueBase)(object)new AcceptableValueRange<float>(16f, 256f), Array.Empty<object>())); BlockActions = ((BaseUnityPlugin)this).Config.Bind<bool>("LinkMode", "BlockActionsWhileLinking", true, "While linking you can only move (walk, run, jump, crouch, dodge, look). Off: only SmelterLink keys (1/2/3, X, Esc) are blocked from triggering game actions"); CancelOnDamage = ((BaseUnityPlugin)this).Config.Bind<bool>("LinkMode", "CancelOnDamage", true, "Getting hit by a creature, player or turret cancels linking, so you can fight back. Poison, fire, frost and drowning do not"); ShowRange = ((BaseUnityPlugin)this).Config.Bind<bool>("LinkMode", "ShowRange", true, "While linking, draw the link range (Links.SearchRadius) around the smelter and show chest distance in its hover text"); if (!IsTargetSupported(out var version)) { return; } Type type = AccessTools.TypeByName("SmelterLink.Links"); Type registry = AccessTools.TypeByName("SmelterLink.Registry"); Type type2 = AccessTools.TypeByName("SmelterLink.ContainerIO"); Type type3 = AccessTools.TypeByName("SmelterLink.SmelterOps"); if (!LinkModeAccess.Init() || type == null || !LinkPatches.Init(type, registry) || !ChestFinder.Init() || type2 == null || type3 == null || !ChestPatches.Init() || !ChestAccess.Init()) { ((BaseUnityPlugin)this).Logger.LogError((object)"SmelterLink or Valheim internals not found, patches disabled"); return; } _harmony = new Harmony("radek.smelterlinkfix"); try { Prefix(AccessTools.Method(typeof(Player), "UseHotbarItem", (Type[])null, (Type[])null), typeof(InputBlockPatches), "UseHotbarItemPrefix"); Prefix(AccessTools.Method(typeof(Player), "StartEmote", (Type[])null, (Type[])null), typeof(InputBlockPatches), "StartEmotePrefix"); Prefix(AccessTools.Method(typeof(Menu), "Show", (Type[])null, (Type[])null), typeof(InputBlockPatches), "MenuShowPrefix"); Prefix(AccessTools.Method(type, "Get", (Type[])null, (Type[])null), typeof(LinkPatches), "GetPrefix"); Prefix(AccessTools.Method(type, "Set", (Type[])null, (Type[])null), typeof(LinkPatches), "SetPrefix"); Prefix(AccessTools.Method(type, "Resolve", (Type[])null, (Type[])null), typeof(LinkPatches), "ResolvePrefix"); Prefix(AccessTools.Method(type, "HasAny", (Type[])null, (Type[])null), typeof(LinkPatches), "HasAnyPrefix"); Postfix(AccessTools.Method(typeof(ZNet), "Awake", (Type[])null, (Type[])null), typeof(UidRpc), "Register"); Prefix(AccessTools.Method(type2, "Take", (Type[])null, (Type[])null), typeof(ChestPatches), "TakePrefix"); Prefix(AccessTools.Method(type2, "Put", (Type[])null, (Type[])null), typeof(ChestPatches), "PutPrefix"); Prefix(AccessTools.Method(type3, "FeedFuel", (Type[])null, (Type[])null), typeof(ChestPatches), "GuardIntPrefix"); Prefix(AccessTools.Method(type3, "FeedOre", (Type[])null, (Type[])null), typeof(ChestPatches), "GuardIntPrefix"); Prefix(AccessTools.Method(type3, "Simulate", (Type[])null, (Type[])null), typeof(ChestPatches), "GuardIntPrefix"); Prefix(AccessTools.Method(type3, "FlushPendingOutput", (Type[])null, (Type[])null), typeof(ChestPatches), "GuardBoolPrefix"); Postfix(AccessTools.Method(typeof(ZNet), "Awake", (Type[])null, (Type[])null), typeof(ChestRpc), "Register"); Prefix(AccessTools.Method(typeof(ZNet), "Shutdown", (Type[])null, (Type[])null), typeof(ChestRpc), "ShutdownPrefix"); Prefix(AccessTools.Method(typeof(Container), "SetInUse", (Type[])null, (Type[])null), typeof(ChestPatches), "SetInUsePrefix"); Prefix(AccessTools.Method(typeof(Container), "RPC_StackResponse", (Type[])null, (Type[])null), typeof(ChestPatches), "StackResponsePrefix"); Prefix(AccessTools.Method(typeof(Player), "TakeInput", (Type[])null, (Type[])null), typeof(ActionBlockPatches), "TakeInputPrefix"); Prefix(AccessTools.Method(typeof(Player), "SetControls", (Type[])null, (Type[])null), typeof(ActionBlockPatches), "SetControlsPrefix"); Prefix(AccessTools.Method(typeof(InventoryGui), "Show", (Type[])null, (Type[])null), typeof(ActionBlockPatches), "InventoryShowPrefix"); Prefix(AccessTools.Method(typeof(Minimap), "SetMapMode", (Type[])null, (Type[])null), typeof(ActionBlockPatches), "SetMapModePrefix"); if (LinkModeAccess.CanCancel) { MethodInfo original = AccessTools.Method(typeof(Character), "ApplyDamage", (Type[])null, (Type[])null); Prefix(original, typeof(ActionBlockPatches), "ApplyDamagePrefix"); Postfix(original, typeof(ActionBlockPatches), "ApplyDamagePostfix"); } else { ((BaseUnityPlugin)this).Logger.LogWarning((object)"SmelterLink.LinkMode.Cancel not found, CancelOnDamage disabled"); } if (!LinkModeAccess.CanGetSmelter) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"SmelterLink.LinkMode._smelter not found, link range display disabled"); } Postfix(AccessTools.Method(typeof(Container), "GetHoverText", (Type[])null, (Type[])null), typeof(RangeDisplay), "ContainerHoverPostfix", 200); } catch (Exception arg) { ((BaseUnityPlugin)this).Logger.LogError((object)$"Patching failed, patches disabled: {arg}"); _harmony.UnpatchSelf(); return; } _active = true; ((BaseUnityPlugin)this).Logger.LogInfo((object)("SmelterLinkFix 0.1.0 loaded (SmelterLink " + version + ", Valheim " + Version.GetVersionString(false) + ")")); } private void Update() { if (!_active) { return; } try { UidRpc.CheckTimeouts(); ChestRpc.CheckTimeouts(); Notify.Update(); } catch (Exception arg) { if (!_updateErrorLogged) { ((BaseUnityPlugin)this).Logger.LogError((object)$"Update failed: {arg}"); } _updateErrorLogged = true; } } private void LateUpdate() { if (!_active) { return; } InputBlockPatches.TrackSelecting(); try { RangeDisplay.LateUpdate(); } catch (Exception e) { ErrorLog.Once("RangeDisplay", e); } } private void Prefix(MethodInfo original, Type patchClass, string patch) { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Expected O, but got Unknown if (original == null) { throw new MissingMethodException("Target method for " + patch + " not found"); } _harmony.Patch((MethodBase)original, new HarmonyMethod(patchClass, patch, (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } private void Postfix(MethodInfo original, Type patchClass, string patch, int priority = 400) { //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) //IL_003f: Expected O, but got Unknown if (original == null) { throw new MissingMethodException("Target method for " + patch + " not found"); } _harmony.Patch((MethodBase)original, (HarmonyMethod)null, new HarmonyMethod(patchClass, patch, (Type[])null) { priority = priority }, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } private bool IsTargetSupported(out string version) { version = null; if (!Chainloader.PluginInfos.TryGetValue("nishinku.smelterlink", out var value)) { ((BaseUnityPlugin)this).Logger.LogError((object)"SmelterLink (nishinku.smelterlink) not found, patches disabled"); return false; } version = value.Metadata.Version.ToString(); if (version != "0.2.0") { ((BaseUnityPlugin)this).Logger.LogWarning((object)("SmelterLink " + version + " is not supported (expected 0.2.0), patches disabled")); return false; } return true; } } internal static class RangeDisplay { private const int Segments = 96; private const float HeightOffset = 0.3f; private const float Width = 0.15f; private const float IncompleteRetrySeconds = 2f; private static readonly Color RingColor = new Color(1f, 0.85f, 0.3f, 0.8f); private static LineRenderer s_ring; private static Material s_material; private static bool s_shaderMissing; private static ZDOID s_builtFor = ZDOID.None; private static Vector3 s_builtCenter; private static float s_builtRadius; private static bool s_incomplete; private static float s_retryAt; public static void LateUpdate() { //IL_0058: 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_006a: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) ZDO val = (Plugin.ShowRange.Value ? LinkModeAccess.Smelter : null); if (val == null) { if ((Object)(object)s_ring != (Object)null && ((Component)s_ring).gameObject.activeSelf) { ((Component)s_ring).gameObject.SetActive(false); } return; } LineRenderer ring = GetRing(); if (!((Object)(object)ring == (Object)null)) { Vector3 position = val.GetPosition(); float value = Plugin.SearchRadius.Value; if (val.m_uid != s_builtFor || position != s_builtCenter || value != s_builtRadius || (s_incomplete && Time.time >= s_retryAt)) { s_incomplete = !Build(ring, position, value); s_retryAt = Time.time + 2f; s_builtFor = val.m_uid; s_builtCenter = position; s_builtRadius = value; } if (!((Component)ring).gameObject.activeSelf) { ((Component)ring).gameObject.SetActive(true); } } } public static void ContainerHoverPostfix(Container __instance, ref string __result) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) try { if (Plugin.ShowRange.Value && !((Object)(object)__instance == (Object)null)) { ZDO smelter = LinkModeAccess.Smelter; if (smelter != null) { float num = ChestFinder.HorizontalDistance(smelter.GetPosition(), ((Component)__instance).transform.position); float value = Plugin.SearchRadius.Value; __result += ((num <= value) ? $"\n<color=#9BE39B>{num:0}m / {value:0}m</color>" : $"\n<color=#FF6B6B>{num:0}m / {value:0}m, out of range</color>"); } } } catch (Exception e) { ErrorLog.Once("ContainerHoverPostfix", e); } } private static LineRenderer GetRing() { //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00be: 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_00c5: 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) //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Expected O, but got Unknown if ((Object)(object)s_ring != (Object)null) { return s_ring; } if (s_shaderMissing) { return null; } if ((Object)(object)s_material == (Object)null) { Shader val = Shader.Find("Sprites/Default"); if ((Object)(object)val == (Object)null) { s_shaderMissing = true; Plugin.Log.LogWarning((object)"Shader Sprites/Default not found, link range ring disabled"); return null; } s_material = new Material(val) { hideFlags = (HideFlags)32 }; } s_ring = new GameObject("SmelterLinkFix_Range").AddComponent<LineRenderer>(); ((Renderer)s_ring).sharedMaterial = s_material; s_ring.useWorldSpace = true; s_ring.loop = true; s_ring.widthMultiplier = 0.15f; LineRenderer obj = s_ring; Color startColor = (s_ring.endColor = RingColor); obj.startColor = startColor; ((Renderer)s_ring).shadowCastingMode = (ShadowCastingMode)0; ((Renderer)s_ring).receiveShadows = false; s_builtFor = ZDOID.None; return s_ring; } private static bool Build(LineRenderer ring, Vector3 center, float radius) { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0037: 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_0063: 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_008f: Unknown result type (might be due to invalid IL or missing references) bool result = true; Vector3[] array = (Vector3[])(object)new Vector3[96]; Vector3 val = default(Vector3); float y = default(float); for (int i = 0; i < 96; i++) { float num = (float)i * (float)Math.PI * 2f / 96f; ((Vector3)(ref val))..ctor(center.x + Mathf.Cos(num) * radius, center.y, center.z + Mathf.Sin(num) * radius); if ((Object)(object)ZoneSystem.instance != (Object)null && ZoneSystem.instance.GetGroundHeight(val, ref y)) { val.y = y; } else { result = false; } val.y += 0.3f; array[i] = val; } ring.positionCount = 96; ring.SetPositions(array); return result; } } internal static class UidRpc { private struct Pending { public ZDOID Smelter; public int Slot; public ZDOID Chest; public long Owner; public float Deadline; } private const string AssignRpc = "SLFix_AssignUid"; private const string AckRpc = "SLFix_AssignUidAck"; private const float TimeoutSeconds = 5f; private static readonly List<Pending> s_pending = new List<Pending>(); public static void Register() { s_pending.Clear(); if (ZRoutedRpc.instance == null) { return; } try { ZRoutedRpc.instance.Register<ZDOID>("SLFix_AssignUid", (Action<long, ZDOID>)RPC_Assign); ZRoutedRpc.instance.Register<ZDOID, long>("SLFix_AssignUidAck", (Action<long, ZDOID, long>)RPC_Ack); } catch (Exception arg) { Plugin.Log.LogError((object)$"RPC registration failed, linking chests owned by other players will not work: {arg}"); } } public static void Request(ZDOID smelter, int slot, ZDO chest) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0025: 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_0073: Unknown result type (might be due to invalid IL or missing references) long owner = chest.GetOwner(); if (owner == 0L) { Notify.Center("Link failed: chest has no owner, try again"); return; } s_pending.Add(new Pending { Smelter = smelter, Slot = slot, Chest = chest.m_uid, Owner = owner, Deadline = Time.time + 5f }); ZRoutedRpc.instance.InvokeRoutedRPC(owner, "SLFix_AssignUid", new object[1] { chest.m_uid }); } public static void CancelPending(ZDOID smelter, int slot) { //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) s_pending.RemoveAll((Pending p) => p.Smelter == smelter && p.Slot == slot); } public static void CheckTimeouts() { if (s_pending.Count != 0 && s_pending.RemoveAll((Pending p) => Time.time > p.Deadline) > 0) { Notify.Center("Link failed: chest owner did not respond (does everyone have SmelterLinkFix?)"); } } private static void RPC_Assign(long sender, ZDOID chestId) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) long num = 0L; try { ZDO zDO = ZDOMan.instance.GetZDO(chestId); if (zDO != null && zDO.IsOwner() && ChestFinder.IsContainer(zDO)) { num = zDO.GetLong(ChestUid.UidKey, 0L); if (num == 0L) { num = ChestUid.NewUid(); zDO.Set(ChestUid.UidKey, num); } } } catch (Exception arg) { Plugin.Log.LogError((object)string.Format("{0} failed: {1}", "SLFix_AssignUid", arg)); num = 0L; } ZRoutedRpc.instance.InvokeRoutedRPC(sender, "SLFix_AssignUidAck", new object[2] { chestId, num }); } private static void RPC_Ack(long sender, ZDOID chestId, long uid) { //IL_001c: 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_0043: Unknown result type (might be due to invalid IL or missing references) try { for (int num = s_pending.Count - 1; num >= 0; num--) { Pending pending = s_pending[num]; if (!(pending.Chest != chestId) && pending.Owner == sender) { s_pending.RemoveAt(num); ZDO zDO = ZDOMan.instance.GetZDO(pending.Smelter); if (uid == 0L || zDO == null || !zDO.IsValid()) { Notify.Center("Link failed, try again"); } else { LinkPatches.WriteLink(zDO, pending.Slot, uid); } } } } catch (Exception arg) { Plugin.Log.LogError((object)string.Format("{0} failed: {1}", "SLFix_AssignUidAck", arg)); } } } }