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 CartTracking v1.0.0
BepInEx/plugins/CartTracking.dll
Decompiled a day agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using UnityEngine; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyCompany("CartTracking")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+a4fb8dce80820c0961c57266fa24d5d796d707ac")] [assembly: AssemblyProduct("CartTracking")] [assembly: AssemblyTitle("CartTracking")] [assembly: AssemblyVersion("1.0.0.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 CartTracking { internal static class CartCatalog { internal readonly struct PrefabInfo { public readonly string Prefab; public readonly string Label; public readonly int Hash; public PrefabInfo(string prefab, string label) { Prefab = prefab; Label = label; Hash = StringExtensionMethods.GetStableHashCode(prefab); } } internal static readonly PrefabInfo[] Prefabs = new PrefabInfo[1] { new PrefabInfo("Cart", "Cart") }; private static readonly Dictionary<int, PrefabInfo> ByHash = BuildLookup(); private static Dictionary<int, PrefabInfo> BuildLookup() { Dictionary<int, PrefabInfo> dictionary = new Dictionary<int, PrefabInfo>(); PrefabInfo[] prefabs = Prefabs; for (int i = 0; i < prefabs.Length; i++) { PrefabInfo value = prefabs[i]; dictionary[value.Hash] = value; } return dictionary; } internal static bool TryGet(int prefabHash, out PrefabInfo info) { return ByHash.TryGetValue(prefabHash, out info); } } internal static class CartPins { private sealed class MarkerState { public Vector3 Pos; public int PrefabHash; public GameObject? Marker; } private static readonly Dictionary<ZDOID, MarkerState> Markers = new Dictionary<ZDOID, MarkerState>(); private static readonly Dictionary<int, Sprite?> SpriteCache = new Dictionary<int, Sprite>(); private static Sprite? _fallbackSprite; private static int _lastLoggedCount = -1; internal static void Clear() { foreach (MarkerState value in Markers.Values) { DestroyMarker(value); } Markers.Clear(); _lastLoggedCount = -1; } internal static void Apply(IReadOnlyList<CartSnapshot> carts) { try { ApplyInternal(carts); } catch (Exception arg) { CartTrackingPlugin.Log.LogError((object)$"CartPins.Apply failed: {arg}"); } } private static void ApplyInternal(IReadOnlyList<CartSnapshot> carts) { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0055: 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) //IL_007f: 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_0070: 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_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Unknown result type (might be due to invalid IL or missing references) //IL_0194: Unknown result type (might be due to invalid IL or missing references) if (!CartTrackingPlugin.ShowPins.Value) { Clear(); return; } HashSet<ZDOID> hashSet = new HashSet<ZDOID>(); foreach (CartSnapshot cart in carts) { hashSet.Add(cart.Id); if (!IsSanePosition(cart.Position)) { RemoveTracked(cart.Id); continue; } if (!Markers.TryGetValue(cart.Id, out MarkerState value)) { value = new MarkerState(); Markers[cart.Id] = value; } value.Pos = cart.Position; value.PrefabHash = cart.PrefabHash; } List<ZDOID> list = new List<ZDOID>(); foreach (ZDOID key in Markers.Keys) { if (!hashSet.Contains(key)) { list.Add(key); } } foreach (ZDOID item in list) { RemoveTracked(item); } if (Markers.Count == _lastLoggedCount) { return; } _lastLoggedCount = Markers.Count; CartTrackingPlugin.Log.LogInfo((object)$"Map markers tracked: {Markers.Count}"); foreach (KeyValuePair<ZDOID, MarkerState> marker in Markers) { CartTrackingPlugin.Log.LogInfo((object)$" Cart @ {marker.Value.Pos}"); } } internal static void UpdateDrawnMarkers() { //IL_019e: Unknown result type (might be due to invalid IL or missing references) try { if (!CartTrackingPlugin.ShowPins.Value || !Object.op_Implicit((Object)(object)Minimap.instance) || Markers.Count == 0) { if (Markers.Count == 0) { return; } { foreach (MarkerState value in Markers.Values) { DestroyMarker(value); } return; } } Minimap instance = Minimap.instance; GameObject field = GetField<GameObject>(instance, "m_largeRoot"); RawImage field2 = GetField<RawImage>(instance, "m_mapImageLarge"); RawImage field3 = GetField<RawImage>(instance, "m_mapImageSmall"); RectTransform field4 = GetField<RectTransform>(instance, "m_pinRootLarge"); RectTransform field5 = GetField<RectTransform>(instance, "m_pinRootSmall"); GameObject field6 = GetField<GameObject>(instance, "m_pinPrefab"); if (!Object.op_Implicit((Object)(object)field) || !Object.op_Implicit((Object)(object)field2) || !Object.op_Implicit((Object)(object)field3) || !Object.op_Implicit((Object)(object)field4) || !Object.op_Implicit((Object)(object)field5) || !Object.op_Implicit((Object)(object)field6)) { return; } bool activeSelf = field.activeSelf; RawImage val = (activeSelf ? field2 : field3); RectTransform val2 = (activeSelf ? field4 : field5); if (!Object.op_Implicit((Object)(object)val) || !Object.op_Implicit((Object)(object)val2) || !Object.op_Implicit((Object)(object)((Graphic)val).rectTransform)) { return; } float num = (activeSelf ? GetField<float>(instance, "m_pinSizeLarge") : GetField<float>(instance, "m_pinSizeSmall")); if (num <= 0f) { num = (activeSelf ? 32f : 16f); } foreach (MarkerState item in new List<MarkerState>(Markers.Values)) { if (item != null) { if (!IsPointVisible(item.Pos, val, instance)) { DestroyMarker(item); } else { DrawMarker(item, num, val2, val, field6, instance); } } } } catch (Exception ex) { CartTrackingPlugin.Log.LogWarning((object)("UpdateDrawnMarkers: " + ex.Message)); } } private static void DrawMarker(MarkerState state, float size, RectTransform parent, RawImage rawImage, GameObject pinPrefab, Minimap mm) { //IL_00b2: 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_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Unknown result type (might be due to invalid IL or missing references) GameObject val = state.Marker; if (!Object.op_Implicit((Object)(object)val) || (Object)(object)val.transform.parent != (Object)(object)parent) { if (Object.op_Implicit((Object)(object)val)) { Object.Destroy((Object)(object)val); } val = (state.Marker = Object.Instantiate<GameObject>(pinPrefab)); val.transform.SetParent((Transform)(object)parent, false); Image component = val.GetComponent<Image>(); if (Object.op_Implicit((Object)(object)component)) { component.sprite = ResolveSprite(state.PrefabHash) ?? component.sprite; } Transform transform = val.transform; RectTransform val2 = (RectTransform)(object)((transform is RectTransform) ? transform : null); if (Object.op_Implicit((Object)(object)val2)) { val2.SetSizeWithCurrentAnchors((Axis)0, size * 1.25f); val2.SetSizeWithCurrentAnchors((Axis)1, size * 1.25f); } } WorldToMapPoint(state.Pos, mm, out var mx, out var my); Vector2 anchoredPosition = MapPointToLocalGuiPos(mx, my, rawImage); Transform transform2 = val.transform; RectTransform val3 = (RectTransform)(object)((transform2 is RectTransform) ? transform2 : null); if (Object.op_Implicit((Object)(object)val3)) { val3.anchoredPosition = anchoredPosition; } Transform val4 = val.transform.Find("Checked"); if (Object.op_Implicit((Object)(object)val4)) { ((Component)val4).gameObject.SetActive(false); } Transform val5 = val.transform.Find("Name"); if (Object.op_Implicit((Object)(object)val5)) { ((Component)val5).gameObject.SetActive(false); } } private static Sprite? ResolveSprite(int prefabHash) { if (SpriteCache.TryGetValue(prefabHash, out Sprite value)) { return value ?? GetFallbackSprite(); } Sprite val = null; try { if ((Object)(object)ZNetScene.instance != (Object)null) { GameObject prefab = ZNetScene.instance.GetPrefab(prefabHash); if (Object.op_Implicit((Object)(object)prefab)) { Piece component = prefab.GetComponent<Piece>(); if (Object.op_Implicit((Object)(object)component)) { object? obj = AccessTools.Field(typeof(Piece), "m_icon")?.GetValue(component); val = (Sprite)((obj is Sprite) ? obj : null); } } } } catch { } SpriteCache[prefabHash] = val; return val ?? GetFallbackSprite(); } private static Sprite? GetFallbackSprite() { if (Object.op_Implicit((Object)(object)_fallbackSprite)) { return _fallbackSprite; } try { Minimap instance = Minimap.instance; if (!Object.op_Implicit((Object)(object)instance)) { return null; } if (GetField<object>(instance, "m_icons") is IList list) { foreach (object item in list) { if (item == null) { continue; } string text = item.GetType().GetField("m_name")?.GetValue(item)?.ToString() ?? item.GetType().GetField("m_type")?.GetValue(item)?.ToString(); object? obj = item.GetType().GetField("m_icon")?.GetValue(item); Sprite val = (Sprite)(((obj is Sprite) ? obj : null) ?? ((object)/*isinst with value type is only supported in some contexts*/)); if (!((Object)(object)val == (Object)null)) { if (text != null && (text.Contains("Death") || text.Contains("Icon0"))) { _fallbackSprite = val; return _fallbackSprite; } if (_fallbackSprite == null) { _fallbackSprite = val; } } } } } catch { } return _fallbackSprite; } private static bool IsPointVisible(Vector3 p, RawImage map, Minimap mm) { //IL_0000: 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_0011: Unknown result type (might be due to invalid IL or missing references) WorldToMapPoint(p, mm, out var mx, out var my); Rect uvRect = map.uvRect; if (mx > ((Rect)(ref uvRect)).xMin && mx < ((Rect)(ref uvRect)).xMax && my > ((Rect)(ref uvRect)).yMin) { return my < ((Rect)(ref uvRect)).yMax; } return false; } private static void WorldToMapPoint(Vector3 p, Minimap mm, out float mx, out float my) { //IL_0038: 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) int field = GetField<int>(mm, "m_textureSize"); float field2 = GetField<float>(mm, "m_pixelSize"); if (field <= 0 || field2 <= 0f) { mx = 0f; my = 0f; return; } int num = field / 2; mx = p.x / field2 + (float)num; my = p.z / field2 + (float)num; mx /= field; my /= field; } private static Vector2 MapPointToLocalGuiPos(float mx, float my, RawImage img) { //IL_0015: 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_0021: 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_0073: 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_009d: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)img) || !Object.op_Implicit((Object)(object)((Graphic)img).rectTransform)) { return Vector2.zero; } Rect uvRect = img.uvRect; if (((Rect)(ref uvRect)).width <= 0f || ((Rect)(ref uvRect)).height <= 0f) { return Vector2.zero; } Vector2 result = default(Vector2); ((Vector2)(ref result))..ctor((mx - ((Rect)(ref uvRect)).xMin) / ((Rect)(ref uvRect)).width, (my - ((Rect)(ref uvRect)).yMin) / ((Rect)(ref uvRect)).height); Rect rect = ((Graphic)img).rectTransform.rect; result.x *= ((Rect)(ref rect)).width; result.y *= ((Rect)(ref rect)).height; return result; } private static T? GetField<T>(object obj, string name) { FieldInfo fieldInfo = AccessTools.Field(obj.GetType(), name); if (fieldInfo == null) { return default(T); } object value = fieldInfo.GetValue(obj); if (value is T) { return (T)value; } if (typeof(T).IsValueType && value != null) { return (T)value; } return default(T); } private static void RemoveTracked(ZDOID id) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) if (Markers.TryGetValue(id, out MarkerState value)) { DestroyMarker(value); Markers.Remove(id); } } private static void DestroyMarker(MarkerState state) { if (Object.op_Implicit((Object)(object)state.Marker)) { Object.Destroy((Object)(object)state.Marker); state.Marker = null; } } private static bool IsSanePosition(Vector3 pos) { //IL_0000: 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_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) if (float.IsNaN(pos.x) || float.IsNaN(pos.y) || float.IsNaN(pos.z)) { return false; } if (float.IsInfinity(pos.x) || float.IsInfinity(pos.y) || float.IsInfinity(pos.z)) { return false; } if (((Vector3)(ref pos)).sqrMagnitude < 0.01f) { return false; } return true; } } internal sealed class CartSnapshot { public ZDOID Id; public Vector3 Position; public int PrefabHash; } internal static class CartSync { private static float _timer; private static readonly List<CartSnapshot> Latest = new List<CartSnapshot>(); private static readonly object Gate = new object(); private static int _lastLoggedCount = -1; private static bool _loggedProtocolMismatch; internal static IReadOnlyList<CartSnapshot> GetLatest() { lock (Gate) { return Latest.ToArray(); } } internal static void Tick(float dt) { if ((Object)(object)ZNet.instance == (Object)null || ZDOMan.instance == null || !ZNet.instance.IsServer()) { return; } float num = Mathf.Clamp(CartTrackingPlugin.SyncInterval.Value, 1f, 30f); _timer += dt; if (_timer < num) { return; } _timer = 0f; try { BroadcastNow(); } catch (Exception arg) { CartTrackingPlugin.Log.LogError((object)$"Cart sync failed: {arg}"); } } internal static void BroadcastNow() { if (!((Object)(object)ZNet.instance == (Object)null) && ZNet.instance.IsServer() && ZDOMan.instance != null) { List<CartSnapshot> list = CollectCarts(); ZPackage val = WritePackage(list); lock (Gate) { Latest.Clear(); Latest.AddRange(list); } if (list.Count != _lastLoggedCount) { _lastLoggedCount = list.Count; CartTrackingPlugin.Log.LogInfo((object)$"Broadcasting {list.Count} cart pin(s) to clients."); } if (!ZNet.instance.IsDedicated() && Object.op_Implicit((Object)(object)Minimap.instance)) { CartPins.Apply(list); } ZRoutedRpc.instance.InvokeRoutedRPC(0L, "CartTracking.Sync", new object[1] { val }); } } internal static void RequestFromServer() { if ((Object)(object)ZNet.instance == (Object)null || ZRoutedRpc.instance == null) { return; } if (ZNet.instance.IsServer()) { BroadcastNow(); return; } long serverPeerIdSafe = GetServerPeerIdSafe(); if (serverPeerIdSafe != 0L) { ZRoutedRpc.instance.InvokeRoutedRPC(serverPeerIdSafe, "CartTracking.RequestSync", Array.Empty<object>()); } } internal static void HandleRequestSync(long sender) { if (!((Object)(object)ZNet.instance == (Object)null) && ZNet.instance.IsServer()) { ZPackage val = WritePackage(CollectCarts()); ZRoutedRpc.instance.InvokeRoutedRPC(sender, "CartTracking.Sync", new object[1] { val }); } } internal static void HandleSync(long sender, ZPackage pkg) { if ((Object)(object)ZNet.instance == (Object)null || ZNet.instance.IsDedicated() || pkg == null || pkg.Size() == 0) { return; } try { pkg.SetPos(0); if (TryReadPackage(pkg, out List<CartSnapshot> carts)) { lock (Gate) { Latest.Clear(); Latest.AddRange(carts); } if (carts.Count != _lastLoggedCount) { _lastLoggedCount = carts.Count; CartTrackingPlugin.Log.LogInfo((object)$"Received {carts.Count} cart pin(s) from server."); } CartPins.Apply(carts); } } catch (Exception arg) { CartTrackingPlugin.Log.LogError((object)$"Cart sync receive failed: {arg}"); } } private static long GetServerPeerIdSafe() { try { MethodInfo methodInfo = AccessTools.Method(typeof(ZRoutedRpc), "GetServerPeerID", (Type[])null, (Type[])null); if (methodInfo != null && ZRoutedRpc.instance != null && methodInfo.Invoke(ZRoutedRpc.instance, null) is long result) { return result; } } catch (Exception ex) { CartTrackingPlugin.Log.LogWarning((object)("GetServerPeerID reflection failed: " + ex.Message)); } try { ZNetPeer val = (((Object)(object)ZNet.instance != (Object)null) ? ZNet.instance.GetServerPeer() : null); if (val != null) { FieldInfo fieldInfo = AccessTools.Field(((object)val).GetType(), "m_uid"); if (fieldInfo != null && fieldInfo.GetValue(val) is long result2) { return result2; } } } catch (Exception ex2) { CartTrackingPlugin.Log.LogWarning((object)("GetServerPeer fallback failed: " + ex2.Message)); } return 0L; } private static List<CartSnapshot> CollectCarts() { List<CartSnapshot> result = new List<CartSnapshot>(); ZDOMan instance = ZDOMan.instance; if (instance == null) { return result; } HashSet<ZDOID> seen = new HashSet<ZDOID>(); CollectFromObjectsById(instance, Consider); if (result.Count == 0) { CollectFromPrefabIterative(instance, Consider); } return result; void Consider(ZDO? zdo) { //IL_0013: 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_0036: 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_0049: 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_0050: Unknown result type (might be due to invalid IL or missing references) if (zdo != null && zdo.IsValid() && seen.Add(zdo.m_uid) && CartCatalog.TryGet(zdo.GetPrefab(), out var info)) { Vector3 position = zdo.GetPosition(); result.Add(new CartSnapshot { Id = zdo.m_uid, Position = position, PrefabHash = info.Hash }); } } } private static void CollectFromObjectsById(ZDOMan zdoMan, Action<ZDO?> consider) { try { object obj = AccessTools.Field(typeof(ZDOMan), "m_objectsByID")?.GetValue(zdoMan); if (obj is IDictionary dictionary) { { foreach (object value2 in dictionary.Values) { ZDO val = (ZDO)((value2 is ZDO) ? value2 : null); if (val != null) { consider(val); } } return; } } if (!(obj is IEnumerable enumerable)) { return; } foreach (object item in enumerable) { ZDO val2 = (ZDO)((item is ZDO) ? item : null); if (val2 != null) { consider(val2); } else if (item is DictionaryEntry dictionaryEntry) { object? value = dictionaryEntry.Value; ZDO val3 = (ZDO)((value is ZDO) ? value : null); if (val3 != null) { consider(val3); } } } } catch (Exception ex) { CartTrackingPlugin.Log.LogWarning((object)("ZDO id scan failed: " + ex.Message)); } } private static void CollectFromPrefabIterative(ZDOMan zdoMan, Action<ZDO?> consider) { List<ZDO> list = new List<ZDO>(); CartCatalog.PrefabInfo[] prefabs = CartCatalog.Prefabs; for (int i = 0; i < prefabs.Length; i++) { CartCatalog.PrefabInfo prefabInfo = prefabs[i]; list.Clear(); int num = 0; int num2 = 0; while (!zdoMan.GetAllZDOsWithPrefabIterative(prefabInfo.Prefab, list, ref num)) { if (++num2 > 100000) { CartTrackingPlugin.Log.LogWarning((object)("Prefab scan aborted for " + prefabInfo.Prefab)); break; } } foreach (ZDO item in list) { consider(item); } } } private static ZPackage WritePackage(List<CartSnapshot> carts) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Expected O, but got Unknown //IL_002c: 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) ZPackage val = new ZPackage(); val.Write(1); val.Write(carts.Count); foreach (CartSnapshot cart in carts) { val.Write(cart.Id); val.Write(cart.Position); val.Write(cart.PrefabHash); } return val; } private static bool TryReadPackage(ZPackage pkg, out List<CartSnapshot> carts) { //IL_005e: 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_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) carts = new List<CartSnapshot>(); int num = pkg.ReadInt(); if (num != 1) { NotifyProtocolMismatch(num); return false; } int num2 = pkg.ReadInt(); if (num2 < 0 || num2 > 512) { CartTrackingPlugin.Log.LogWarning((object)$"Cart sync rejected: unreasonable cart count {num2}."); return false; } carts = new List<CartSnapshot>(num2); for (int i = 0; i < num2; i++) { carts.Add(new CartSnapshot { Id = pkg.ReadZDOID(), Position = pkg.ReadVector3(), PrefabHash = pkg.ReadInt() }); } return true; } private static void NotifyProtocolMismatch(int serverVersion) { if (_loggedProtocolMismatch) { return; } _loggedProtocolMismatch = true; int num = 1; string text = ((serverVersion >= num) ? $"CartTracking: your mod is outdated (server protocol {serverVersion}, you have {num}). Update CartTracking to match the server." : $"CartTracking: server mod is outdated (server protocol {serverVersion}, you have {num}). Ask the host to update CartTracking."); CartTrackingPlugin.Log.LogWarning((object)text); try { if (Object.op_Implicit((Object)(object)MessageHud.instance)) { MessageHud.instance.ShowMessage((MessageType)2, text, 0, (Sprite)null, false, true); } } catch (Exception ex) { CartTrackingPlugin.Log.LogWarning((object)("Could not show protocol mismatch HUD: " + ex.Message)); } try { if (Object.op_Implicit((Object)(object)Chat.instance)) { ((Terminal)Chat.instance).AddString("CartTracking", text, (Type)1, false); } } catch { } } } [BepInPlugin("matthb1.carttracking", "CartTracking", "1.0.0")] public class CartTrackingPlugin : BaseUnityPlugin { public const string GUID = "matthb1.carttracking"; public const string NAME = "CartTracking"; public const string VERSION = "1.0.0"; public const int ProtocolVersion = 1; public const string RpcSync = "CartTracking.Sync"; public const string RpcRequestSync = "CartTracking.RequestSync"; internal static CartTrackingPlugin Instance; internal static ConfigEntry<bool> ShowPins; internal static ConfigEntry<float> SyncInterval; internal static ManualLogSource Log; private void Awake() { //IL_006a: Unknown result type (might be due to invalid IL or missing references) Instance = this; Log = ((BaseUnityPlugin)this).Logger; ShowPins = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "ShowPins", true, "Show cart pins on the minimap and world map."); SyncInterval = ((BaseUnityPlugin)this).Config.Bind<float>("General", "SyncInterval", 3f, "Seconds between server cart-position syncs (1-30)."); ((BaseUnityPlugin)this).Logger.LogInfo((object)"CartTracking 1.0.0 loaded - server syncs cart map pins."); new Harmony("matthb1.carttracking").PatchAll(); } private void Update() { CartSync.Tick(Time.deltaTime); } } } namespace CartTracking.Patches { [HarmonyPatch(typeof(Game), "Start")] internal static class GameStartPatch { private static void Prefix() { ZRoutedRpc.instance.Register("CartTracking.RequestSync", (Action<long>)CartSync.HandleRequestSync); ZRoutedRpc.instance.Register<ZPackage>("CartTracking.Sync", (Action<long, ZPackage>)CartSync.HandleSync); } } [HarmonyPatch(typeof(Game), "Logout")] internal static class GameLogoutPatch { private static void Prefix() { CartPins.Clear(); } } [HarmonyPatch(typeof(Minimap), "OnDestroy")] internal static class MinimapDestroyPatch { private static void Postfix() { CartPins.Clear(); } } [HarmonyPatch(typeof(Minimap), "Awake")] internal static class MinimapAwakePatch { private static void Postfix() { CartSync.RequestFromServer(); } } [HarmonyPatch(typeof(Minimap), "UpdatePins")] internal static class MinimapUpdatePinsPatch { private static void Postfix() { CartPins.UpdateDrawnMarkers(); } } [HarmonyPatch(typeof(Minimap), "UpdateMap")] internal static class MinimapUpdateRefreshPatch { private static float _next; private static void Postfix() { if (!(Time.time < _next)) { _next = Time.time + 5f; IReadOnlyList<CartSnapshot> latest = CartSync.GetLatest(); if (latest.Count > 0) { CartPins.Apply(latest); } } } } }