using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security.Cryptography; using System.Text; using System.Threading; using BepInEx; using BepInEx.Logging; using HarmonyLib; using JG224.ModCore.API; using Microsoft.CodeAnalysis; using Splatform; using TMPro; using UnityEngine; using UnityEngine.Events; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyFileVersion("0.5.1.0")] [assembly: AssemblyInformationalVersion("0.5.1")] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyVersion("0.5.1.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 SharedMap { internal static class MapAccess { private static readonly FieldInfo ExploredField = AccessTools.Field(typeof(Minimap), "m_explored"); private static readonly FieldInfo HasGeneratedField = AccessTools.Field(typeof(Minimap), "m_hasGenerated"); private static readonly FieldInfo ExploredOthersField = AccessTools.Field(typeof(Minimap), "m_exploredOthers"); private static readonly FieldInfo FogTextureField = AccessTools.Field(typeof(Minimap), "m_fogTexture"); private static readonly FieldInfo ShowSharedField = AccessTools.Field(typeof(Minimap), "m_showSharedMapData"); private static readonly FieldInfo SharedFadeField = AccessTools.Field(typeof(Minimap), "m_sharedMapDataFade"); private static readonly FieldInfo LargeMaterialField = AccessTools.Field(typeof(Minimap), "m_mapLargeShader"); private static readonly FieldInfo SmallMaterialField = AccessTools.Field(typeof(Minimap), "m_mapSmallShader"); private static readonly FieldInfo LargeZoomField = AccessTools.Field(typeof(Minimap), "m_largeZoom"); private static readonly FieldInfo NamePinField = AccessTools.Field(typeof(Minimap), "m_namePin"); private static readonly FieldInfo PinUpdateRequiredField = AccessTools.Field(typeof(Minimap), "m_pinUpdateRequired"); private static readonly MethodInfo ScreenToWorldMethod = AccessTools.Method(typeof(Minimap), "ScreenToWorldPoint", new Type[1] { typeof(Vector3) }, (Type[])null); private static readonly MethodInfo GetClosestPinMethod = AccessTools.Method(typeof(Minimap), "GetClosestPin", new Type[3] { typeof(Vector3), typeof(float), typeof(bool) }, (Type[])null); private static readonly MethodInfo SelectIconMethod = AccessTools.Method(typeof(Minimap), "SelectIcon", new Type[1] { typeof(PinType) }, (Type[])null); private static Minimap _fogMap; private static Texture2D _fogTexture; private static Material _largeMaterial; private static Material _smallMaterial; private static SharedMapFogMask _sharedFog; private static BitArray _vanillaOthers; private static bool _vanillaVisible; private static float _lastVanillaFade; internal static bool IsReady(Minimap map) { bool flag = default(bool); int num; if ((Object)(object)map != (Object)null && HasGeneratedField != null) { object value = HasGeneratedField.GetValue(map); if (value is bool) { flag = (bool)value; num = 1; } else { num = 0; } } else { num = 0; } if (((uint)num & (flag ? 1u : 0u)) != 0 && ExploredField.GetValue(map) is BitArray bitArray) { return bitArray.Length == map.m_textureSize * map.m_textureSize; } return false; } internal static BitArray GetExplored(Minimap map) { return (BitArray)ExploredField.GetValue(map); } internal static byte[] PackLocalExploration(Minimap map) { return SharedMapExploration.Pack(GetExplored(map)); } internal static bool ApplyFullSharedExploration(Minimap map, int mapSize, byte[] packed) { if (!IsReady(map) || map.m_textureSize != mapSize || packed == null || packed.Length != PackedLength(mapSize)) { return false; } if (!EnsureSharedLayer(map)) { return false; } _sharedFog.Replace(packed); RecomposeSharedFog(map); return true; } internal static bool ApplySharedDelta(Minimap map, int mapSize, IReadOnlyList indices) { if (!IsReady(map) || map.m_textureSize != mapSize || indices == null) { return false; } if (!EnsureSharedLayer(map)) { return false; } bool flag = false; for (int i = 0; i < indices.Count; i++) { int index = indices[i]; if (_sharedFog.Add(index)) { flag |= ComposePixel(index); } } if (!flag) { return false; } _fogTexture.Apply(); return true; } internal static void SetShowShared(Minimap map, bool show) { if (!show) { ClearSharedExploration(); } else { EnsureSharedLayer(map); } } internal static void RefreshSharedPresentation(Minimap map, bool visible, float fade) { if (map == _fogMap && _sharedFog != null) { if (visible != _vanillaVisible) { RecomposeSharedFog(map); } if (fade != _lastVanillaFade) { _lastVanillaFade = fade; SetMaterialFade(1f); } } } internal static void RecomposeSharedFog(Minimap map) { if (map != _fogMap || _sharedFog == null || (Object)(object)_fogTexture == (Object)null) { return; } BitArray bitArray = (BitArray)ExploredOthersField.GetValue(map); if (bitArray == null || bitArray.Length != _sharedFog.PixelCount) { return; } _vanillaOthers = bitArray; _vanillaVisible = (bool)ShowSharedField.GetValue(map); Color32[] pixels = _fogTexture.GetPixels32(); if (pixels.Length == bitArray.Length) { for (int i = 0; i < pixels.Length; i++) { pixels[i].g = (byte)((!_sharedFog.Reveals(i, bitArray[i], _vanillaVisible)) ? byte.MaxValue : 0); } _fogTexture.SetPixels32(pixels); _fogTexture.Apply(); _lastVanillaFade = (float)SharedFadeField.GetValue(map); SetMaterialFade(1f); } } internal static void AfterVanillaSharedPixel(Minimap map, int x, int y) { if (map == _fogMap && _sharedFog != null && x >= 0 && y >= 0 && x < map.m_textureSize && y < map.m_textureSize) { ComposePixel(y * map.m_textureSize + x); } } internal static void ClearSharedExploration() { if ((Object)(object)_fogMap != (Object)null && (Object)(object)_fogTexture != (Object)null) { BitArray bitArray = (BitArray)ExploredOthersField.GetValue(_fogMap); Color32[] pixels = _fogTexture.GetPixels32(); if (bitArray != null && bitArray.Length == pixels.Length) { for (int i = 0; i < pixels.Length; i++) { pixels[i].g = (byte)((!bitArray[i]) ? byte.MaxValue : 0); } _fogTexture.SetPixels32(pixels); _fogTexture.Apply(); } SetMaterialFade((float)SharedFadeField.GetValue(_fogMap)); } _fogMap = null; _fogTexture = null; _largeMaterial = null; _smallMaterial = null; _sharedFog = null; _vanillaOthers = null; } private static bool EnsureSharedLayer(Minimap map) { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Expected O, but got Unknown //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Expected O, but got Unknown //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Expected O, but got Unknown if (!IsReady(map)) { return false; } if (map == _fogMap && _sharedFog != null) { return true; } ClearSharedExploration(); Texture2D val = (Texture2D)FogTextureField.GetValue(map); BitArray bitArray = (BitArray)ExploredOthersField.GetValue(map); if ((Object)(object)val == (Object)null || bitArray == null || bitArray.Length != map.m_textureSize * map.m_textureSize) { return false; } _fogMap = map; _fogTexture = val; _largeMaterial = (Material)LargeMaterialField.GetValue(map); _smallMaterial = (Material)SmallMaterialField.GetValue(map); _sharedFog = new SharedMapFogMask(bitArray.Length); _vanillaOthers = bitArray; RecomposeSharedFog(map); return true; } private static bool ComposePixel(int index) { //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_0051: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) int num = index % _fogMap.m_textureSize; int num2 = index / _fogMap.m_textureSize; Color pixel = _fogTexture.GetPixel(num, num2); float num3 = (_sharedFog.Reveals(index, _vanillaOthers[index], _vanillaVisible) ? 0f : 1f); if (pixel.g == num3) { return false; } pixel.g = num3; _fogTexture.SetPixel(num, num2, pixel); return true; } private static void SetMaterialFade(float fade) { if ((Object)(object)_largeMaterial != (Object)null) { _largeMaterial.SetFloat("_SharedFade", fade); } if ((Object)(object)_smallMaterial != (Object)null) { _smallMaterial.SetFloat("_SharedFade", fade); } } internal static PinData GetNamePin(Minimap map) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Expected O, but got Unknown if (!((Object)(object)map == (Object)null)) { return (PinData)NamePinField.GetValue(map); } return null; } internal static void RequirePinUpdate(Minimap map) { if ((Object)(object)map != (Object)null) { PinUpdateRequiredField.SetValue(map, true); } } internal static void SelectIcon(Minimap map, PinType type) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) SelectIconMethod.Invoke(map, new object[1] { type }); } internal static PinData GetClosestVisiblePin(Minimap map, Vector3 worldPosition, float radius) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Expected O, but got Unknown return (PinData)GetClosestPinMethod.Invoke(map, new object[3] { worldPosition, radius, true }); } internal static Vector3 ScreenToWorld(Minimap map, Vector3 screenPosition) { //IL_000e: 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) return (Vector3)ScreenToWorldMethod.Invoke(map, new object[1] { screenPosition }); } internal static float GetClickRadius(Minimap map) { return map.m_removeRadius * (float)LargeZoomField.GetValue(map) * 2f; } internal static int PackedLength(int mapSize) { return checked(mapSize * mapSize + 7) / 8; } internal static bool IsSet(byte[] packed, int index) { return (packed[index >> 3] & (1 << (index & 7))) != 0; } } internal sealed class PublicMarker { internal string Id = string.Empty; internal long OwnerPlayerId; internal string OwnerAccountKey = string.Empty; internal string OwnerName = string.Empty; internal Vector3 Position; internal PinType Type; internal string Name = string.Empty; internal bool Checked; internal long Revision; internal PublicMarker Copy() { //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0043: 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) return new PublicMarker { Id = Id, OwnerPlayerId = OwnerPlayerId, OwnerAccountKey = OwnerAccountKey, OwnerName = OwnerName, Position = Position, Type = Type, Name = Name, Checked = Checked, Revision = Revision }; } } internal static class SharedMapClient { internal readonly struct MarkerCheckState { internal string MarkerId { get; } internal bool WasChecked { get; } internal bool IsValid => !string.IsNullOrEmpty(MarkerId); internal MarkerCheckState(string markerId, bool wasChecked) { MarkerId = markerId; WasChecked = wasChecked; } } internal sealed class PinSaveState { internal readonly List> Pins = new List>(); internal bool Restored; } private const double DeltaIntervalSeconds = 10.0; private const double ParticipationRetrySeconds = 30.0; private const int MaximumDeltaEntries = 16384; private static readonly Color PublicMarkerColor = new Color(0.3f, 0.95f, 0.36f, 1f); private static readonly Dictionary Markers = new Dictionary(StringComparer.Ordinal); private static readonly Dictionary PinsById = new Dictionary(StringComparer.Ordinal); private static readonly Dictionary IdsByPin = new Dictionary(); private static readonly HashSet PendingExploration = new HashSet(); private static Minimap _pinMap; private static string _preferenceKey; private static long _worldUid; private static long _playerId; private static bool _sharing; private static bool _participationSent; private static bool _snapshotReceived; private static double _nextParticipationRetry; private static double _nextDelta; private static PinData _pendingNamePin; private static PinType _pendingPublicType; private static bool _committingPublicPin; internal static bool Sharing => _sharing; internal static bool ReadyForPublicMarkers => SharedMapUiRules.CanUsePublicMarkers(_sharing, _snapshotReceived); internal static long CurrentWorldUid => _worldUid; internal static IEnumerable MarkerDescriptions() { return from marker in Markers.Values.OrderBy((PublicMarker marker) => marker.Name, StringComparer.OrdinalIgnoreCase) select marker.Id + " | " + marker.Name + " | " + marker.OwnerName + " (" + marker.OwnerPlayerId + ")"; } internal static void Tick(double now) { SharedMapNetwork.Tick(now); if (Application.isBatchMode) { return; } ZNet instance = ZNet.instance; Player localPlayer = Player.m_localPlayer; Minimap instance2 = Minimap.instance; if ((Object)(object)instance == (Object)null || (Object)(object)localPlayer == (Object)null || (Object)(object)instance2 == (Object)null || !MapAccess.IsReady(instance2)) { return; } InitializePreference(instance.GetWorldUID(), localPlayer.GetPlayerID()); SharedMapUi.Ensure(instance2); SharedMapUi.Refresh(_sharing, ReadyForPublicMarkers); EnsurePinMap(instance2); MapAccess.SetShowShared(instance2, _sharing); if (!_sharing) { return; } if (_participationSent && !_snapshotReceived && now >= _nextParticipationRetry && SharedMapNetwork.CanRetryParticipation(now)) { _participationSent = false; } if (!_participationSent) { byte[] snapshot = MapAccess.PackLocalExploration(instance2); if (SharedMapNetwork.SendParticipation(enabled: true, instance2.m_textureSize, snapshot)) { _participationSent = true; PendingExploration.Clear(); _nextParticipationRetry = now + 30.0; _nextDelta = now + 10.0; } } else if (_snapshotReceived && now >= _nextDelta) { FlushExploration(instance2); _nextDelta = now + 10.0; } } internal static void SetSharing(bool enabled) { if (_sharing == enabled) { SharedMapUi.Refresh(_sharing, ReadyForPublicMarkers); return; } _sharing = enabled; if (!string.IsNullOrEmpty(_preferenceKey)) { PlayerPrefs.SetInt(_preferenceKey, enabled ? 1 : 0); PlayerPrefs.Save(); } Minimap instance = Minimap.instance; MapAccess.SetShowShared(instance, enabled); if (!enabled) { if (_participationSent) { SharedMapNetwork.SendParticipation(enabled: false, 0, Array.Empty()); } SharedMapNetwork.ResetClientTransfer(); _participationSent = false; _snapshotReceived = false; PendingExploration.Clear(); ClearRenderedPins(); SharedMapUi.ClearPublicSelection(); } else { _participationSent = false; _snapshotReceived = false; EnsurePinMap(instance); RenderAllMarkers(); } SharedMapUi.Refresh(_sharing, ReadyForPublicMarkers); } internal static void RecordLocalExploration(Minimap map, int x, int y, bool newlyExplored) { if (newlyExplored && _sharing && !((Object)(object)map == (Object)null) && !((Object)(object)map != (Object)(object)Minimap.instance) && x >= 0 && y >= 0 && x < map.m_textureSize && y < map.m_textureSize) { PendingExploration.Add(y * map.m_textureSize + x); } } internal static void ReceiveSnapshot(long worldUid, int mapSize, byte[] exploration, IReadOnlyList markers) { if (!_sharing || worldUid != _worldUid) { return; } Minimap instance = Minimap.instance; if (!((Object)(object)instance == (Object)null) && MapAccess.IsReady(instance) && instance.m_textureSize == mapSize) { MapAccess.ApplyFullSharedExploration(instance, mapSize, exploration); _snapshotReceived = true; ClearRenderedPins(); Markers.Clear(); for (int i = 0; i < markers.Count; i++) { PublicMarker publicMarker = markers[i]; Markers[publicMarker.Id] = publicMarker.Copy(); } EnsurePinMap(instance); RenderAllMarkers(); SharedMapUi.Refresh(_sharing, ReadyForPublicMarkers); ManualLogSource log = SharedMapPlugin.Log; if (log != null) { log.LogInfo((object)$"Received SharedMap snapshot: {markers.Count} public marker(s), map {mapSize}x{mapSize}."); } } } internal static void ReceiveExplorationDelta(long worldUid, int mapSize, IReadOnlyList indices) { if (_sharing && worldUid == _worldUid) { MapAccess.ApplySharedDelta(Minimap.instance, mapSize, indices); } } internal static void ReceiveExplorationSnapshot(long worldUid, int mapSize, byte[] exploration) { if (_sharing && worldUid == _worldUid) { Minimap instance = Minimap.instance; if (!((Object)(object)instance == (Object)null) && MapAccess.IsReady(instance) && instance.m_textureSize == mapSize) { MapAccess.ApplyFullSharedExploration(instance, mapSize, exploration); } } } internal static void UpsertMarker(PublicMarker marker) { if (marker != null && !string.IsNullOrEmpty(marker.Id) && (!Markers.TryGetValue(marker.Id, out var value) || value.Revision <= marker.Revision)) { Markers[marker.Id] = marker.Copy(); if (_sharing) { EnsurePinMap(Minimap.instance); RemoveRenderedPin(marker.Id); RenderMarker(marker); } } } internal static void RemoveMarker(string markerId) { if (!string.IsNullOrEmpty(markerId)) { Markers.Remove(markerId); RemoveRenderedPin(markerId); } } internal static void TintPublicPins(Minimap map) { //IL_0052: 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) if (!_sharing || (Object)(object)map == (Object)null || (Object)(object)map != (Object)(object)_pinMap) { return; } foreach (PinData value in PinsById.Values) { if ((Object)(object)value?.m_iconElement != (Object)null) { ((Graphic)value.m_iconElement).color = PublicMarkerColor; } object obj; if (value == null) { obj = null; } else { PinNameData namePinData = value.m_NamePinData; obj = ((namePinData != null) ? namePinData.PinNameText : null); } if ((Object)obj != (Object)null) { ((Graphic)value.m_NamePinData.PinNameText).color = PublicMarkerColor; } } } internal static MarkerCheckState CaptureClosestPublicCheck(Minimap map, Vector3 screenPosition) { //IL_001b: 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_0023: Unknown result type (might be due to invalid IL or missing references) if (!_sharing || (Object)(object)map == (Object)null) { return default(MarkerCheckState); } Vector3 worldPosition = MapAccess.ScreenToWorld(map, screenPosition); PinData closestVisiblePin = MapAccess.GetClosestVisiblePin(map, worldPosition, MapAccess.GetClickRadius(map)); if (closestVisiblePin == null || !IdsByPin.TryGetValue(closestVisiblePin, out var value)) { return default(MarkerCheckState); } return new MarkerCheckState(value, closestVisiblePin.m_checked); } internal static void SubmitCheckChange(MarkerCheckState state) { if (state.IsValid && PinsById.TryGetValue(state.MarkerId, out var value) && value != null && value.m_checked != state.WasChecked) { bool isChecked = value.m_checked; value.m_checked = state.WasChecked; MapAccess.RequirePinUpdate(_pinMap); SharedMapNetwork.RequestMarkerChecked(state.MarkerId, isChecked); } } internal static bool TryHandleRemoveAt(Minimap map, Vector3 worldPosition, float radius, out bool result) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) result = false; if (!_sharing || (Object)(object)map == (Object)null) { return false; } PinData closestVisiblePin = MapAccess.GetClosestVisiblePin(map, worldPosition, radius); if (closestVisiblePin == null || !IdsByPin.TryGetValue(closestVisiblePin, out var value)) { return false; } result = true; if (!Markers.ContainsKey(value)) { return true; } SharedMapNetwork.RequestMarkerDelete(value); return true; } internal static void AfterShowPinNameInput(Minimap map) { //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) CancelPendingPublicPin(map); if (!_sharing || !SharedMapUi.PublicMarkerSelected) { return; } PinData namePin = MapAccess.GetNamePin(map); if (namePin != null) { _pendingNamePin = namePin; _pendingPublicType = SharedMapUi.SelectedPublicType; namePin.m_save = false; if (!ReadyForPublicMarkers) { ShowMessage("SharedMap is still syncing. This public marker will not be created."); } } } internal static PinData BeforePinTextEntered(Minimap map) { if (_pendingNamePin == null || MapAccess.GetNamePin(map) != _pendingNamePin) { return null; } _committingPublicPin = true; return _pendingNamePin; } internal static void AfterPinTextEntered(Minimap map, PinData pending) { //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_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_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) _committingPublicPin = false; if (pending != null) { Vector3 pos = pending.m_pos; string name = pending.m_name ?? string.Empty; PinType pendingPublicType = _pendingPublicType; map.RemovePin(pending); _pendingNamePin = null; if (ReadyForPublicMarkers) { SharedMapNetwork.RequestMarkerCreate(pendingPublicType, pos, name); } else { ShowMessage("SharedMap is still syncing. Try placing the public marker again in a moment."); } } } internal static void BeforeHidePinTextInput(Minimap map) { if (!_committingPublicPin && _pendingNamePin != null) { CancelPendingPublicPin(map); } } internal static PinSaveState SuspendPublicPinsForSerialization() { PinSaveState pinSaveState = new PinSaveState(); foreach (PinData value in PinsById.Values) { if (value != null) { pinSaveState.Pins.Add(new KeyValuePair(value, value.m_save)); value.m_save = false; } } return pinSaveState; } internal static void RestorePublicPinsAfterSerialization(PinSaveState state) { if (state == null || state.Restored) { return; } state.Restored = true; for (int i = 0; i < state.Pins.Count; i++) { KeyValuePair keyValuePair = state.Pins[i]; if (keyValuePair.Key != null) { keyValuePair.Key.m_save = keyValuePair.Value; } } } internal static void OnMinimapDestroyed(Minimap map) { if (_pinMap == map) { MapAccess.ClearSharedExploration(); PinsById.Clear(); IdsByPin.Clear(); _pinMap = null; _pendingNamePin = null; _committingPublicPin = false; ResetConnection(clearOutgoing: false); SharedMapUi.Destroy(map); } } internal static void ShowMessage(string message) { if (!string.IsNullOrWhiteSpace(message)) { Player localPlayer = Player.m_localPlayer; if (localPlayer != null) { ((Character)localPlayer).Message((MessageType)2, message, 0, (Sprite)null, false); } } } internal static void ResetConnection(bool clearOutgoing = true) { MapAccess.ClearSharedExploration(); if (clearOutgoing) { SharedMapNetwork.ResetConnectionTransfers(); } else { SharedMapNetwork.ResetClientTransfer(); } _participationSent = false; _snapshotReceived = false; _nextParticipationRetry = 0.0; PendingExploration.Clear(); CancelPendingPublicPin(Minimap.instance); SharedMapUi.ClearPublicSelection(); SharedMapUi.Refresh(_sharing, ReadyForPublicMarkers); } internal static void ResetSession() { MapAccess.ClearSharedExploration(); SharedMapNetwork.ResetConnectionTransfers(); ClearRenderedPins(); Markers.Clear(); PendingExploration.Clear(); _preferenceKey = null; _worldUid = 0L; _playerId = 0L; _sharing = false; _participationSent = false; _snapshotReceived = false; _nextParticipationRetry = 0.0; _nextDelta = 0.0; _pendingNamePin = null; _committingPublicPin = false; SharedMapUi.Destroy(null); } private static void InitializePreference(long worldUid, long playerId) { string text = "com.jg224.sharedmap.share." + worldUid + "." + playerId; if (!string.Equals(_preferenceKey, text, StringComparison.Ordinal)) { MapAccess.ClearSharedExploration(); ClearRenderedPins(); SharedMapNetwork.ResetConnectionTransfers(); Markers.Clear(); PendingExploration.Clear(); _worldUid = worldUid; _playerId = playerId; _preferenceKey = text; _sharing = PlayerPrefs.GetInt(text, 0) == 1; _participationSent = false; _snapshotReceived = false; _nextParticipationRetry = 0.0; _nextDelta = 0.0; } } private static void FlushExploration(Minimap map) { while (PendingExploration.Count > 0) { List list = PendingExploration.OrderBy((int index) => index).Take(16384).ToList(); if (!SharedMapNetwork.SendExplorationDelta(map.m_textureSize, list)) { break; } for (int num = 0; num < list.Count; num++) { PendingExploration.Remove(list[num]); } } } private static void EnsurePinMap(Minimap map) { if (!((Object)(object)map == (Object)null) && _pinMap != map) { PinsById.Clear(); IdsByPin.Clear(); _pinMap = map; if (_sharing) { RenderAllMarkers(); } } } internal static void AfterVanillaMapLoaded(Minimap map) { if (map == _pinMap) { ClearRenderedPins(); if (_sharing) { RenderAllMarkers(); } MapAccess.RecomposeSharedFog(map); } } private static void RenderAllMarkers() { if (!_sharing || (Object)(object)_pinMap == (Object)null) { return; } foreach (PublicMarker item in Markers.Values.OrderBy((PublicMarker marker) => marker.Id, StringComparer.Ordinal)) { if (!PinsById.ContainsKey(item.Id)) { RenderMarker(item); } } } private static void RenderMarker(PublicMarker marker) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) if (_sharing && !((Object)(object)_pinMap == (Object)null) && marker != null) { PinData val = _pinMap.AddPin(marker.Position, marker.Type, marker.Name, true, marker.Checked, 0L, PlatformUserID.None); val.m_save = true; PinsById[marker.Id] = val; IdsByPin[val] = marker.Id; MapAccess.RequirePinUpdate(_pinMap); } } private static void RemoveRenderedPin(string markerId) { if (!PinsById.TryGetValue(markerId, out var value)) { return; } PinsById.Remove(markerId); if (value != null) { IdsByPin.Remove(value); if ((Object)(object)_pinMap != (Object)null) { _pinMap.RemovePin(value); } } } private static void ClearRenderedPins() { if ((Object)(object)_pinMap != (Object)null) { PinData[] array = PinsById.Values.ToArray(); foreach (PinData val in array) { if (val != null) { _pinMap.RemovePin(val); } } } PinsById.Clear(); IdsByPin.Clear(); } private static void CancelPendingPublicPin(Minimap map) { if (_pendingNamePin != null && (Object)(object)map != (Object)null) { map.RemovePin(_pendingNamePin); } _pendingNamePin = null; _committingPublicPin = false; } } internal static class SharedMapCommands { [Serializable] [CompilerGenerated] private sealed class <>c { public static readonly <>c <>9 = new <>c(); public static ConsoleEvent <>9__0_0; internal void b__0_0(ConsoleEventArgs args) { //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Unknown result type (might be due to invalid IL or missing references) //IL_017c: Unknown result type (might be due to invalid IL or missing references) string[] args2 = args.Args; if (args2.Length < 2 || args2[1] == "list") { if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer()) { SharedMapServer.ManageMarker(0L, host: true, "list", string.Empty, string.Empty, Vector3.zero); } else { foreach (string item in SharedMapClient.MarkerDescriptions()) { args.Context.AddString(item); } } args.Context.AddString("sharedmap rename | move | delete | cleanup | peers | bind (admin)"); return; } string text = args2[1].ToLowerInvariant(); if (text == "peers") { SharedMapNetwork.ManageMarker(text, string.Empty, string.Empty, Vector3.zero); return; } if (args2.Length < 3) { args.Context.AddString("A public marker ID or character owner ID is required."); return; } if (text == "bind" && args2.Length != 4) { args.Context.AddString("Use sharedmap bind ; inspect sharedmap peers first."); return; } Vector3 zero = Vector3.zero; if (text == "move") { if (args2.Length != 5 || !float.TryParse(args2[3], NumberStyles.Float, CultureInfo.InvariantCulture, out var result) || !float.TryParse(args2[4], NumberStyles.Float, CultureInfo.InvariantCulture, out var result2)) { args.Context.AddString("Use sharedmap move ."); return; } ((Vector3)(ref zero))..ctor(result, 0f, result2); } SharedMapNetwork.ManageMarker(text, args2[2], string.Join(" ", args2.Skip(3)), zero); } } internal static void Register() { //IL_0033: 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) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Expected O, but got Unknown object obj = <>c.<>9__0_0; if (obj == null) { ConsoleEvent val = delegate(ConsoleEventArgs args) { //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Unknown result type (might be due to invalid IL or missing references) //IL_017c: Unknown result type (might be due to invalid IL or missing references) string[] args2 = args.Args; if (args2.Length < 2 || args2[1] == "list") { if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer()) { SharedMapServer.ManageMarker(0L, host: true, "list", string.Empty, string.Empty, Vector3.zero); } else { foreach (string item in SharedMapClient.MarkerDescriptions()) { args.Context.AddString(item); } } args.Context.AddString("sharedmap rename | move | delete | cleanup | peers | bind (admin)"); } else { string text = args2[1].ToLowerInvariant(); if (text == "peers") { SharedMapNetwork.ManageMarker(text, string.Empty, string.Empty, Vector3.zero); } else if (args2.Length < 3) { args.Context.AddString("A public marker ID or character owner ID is required."); } else if (text == "bind" && args2.Length != 4) { args.Context.AddString("Use sharedmap bind ; inspect sharedmap peers first."); } else { Vector3 zero = Vector3.zero; if (text == "move") { if (args2.Length != 5 || !float.TryParse(args2[3], NumberStyles.Float, CultureInfo.InvariantCulture, out var result) || !float.TryParse(args2[4], NumberStyles.Float, CultureInfo.InvariantCulture, out var result2)) { args.Context.AddString("Use sharedmap move ."); return; } ((Vector3)(ref zero))..ctor(result, 0f, result2); } SharedMapNetwork.ManageMarker(text, args2[2], string.Join(" ", args2.Skip(3)), zero); } } }; <>c.<>9__0_0 = val; obj = (object)val; } new ConsoleCommand("sharedmap", "Public markers: list; rename ; move ; delete ; cleanup ; peers; bind (last three require admin).", (ConsoleEvent)obj, false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false); } } internal static class SharedMapExploration { internal static byte[] Pack(BitArray explored) { if (explored == null) { throw new ArgumentNullException("explored"); } byte[] array = new byte[(explored.Length + 7) / 8]; explored.CopyTo(array, 0); return array; } } internal sealed class SharedMapFogMask { private byte[] _pixels; internal int PixelCount { get; } internal SharedMapFogMask(int pixelCount) { if (pixelCount <= 0) { throw new ArgumentOutOfRangeException("pixelCount"); } PixelCount = pixelCount; _pixels = new byte[(pixelCount + 7) / 8]; } internal void Replace(byte[] pixels) { if (pixels == null || pixels.Length != _pixels.Length) { throw new ArgumentException("SharedMap exploration dimensions must match.", "pixels"); } _pixels = (byte[])pixels.Clone(); } internal bool Add(int index) { if (index < 0 || index >= PixelCount) { return false; } int num = index >> 3; byte b = (byte)(1 << (index & 7)); if ((_pixels[num] & b) != 0) { return false; } _pixels[num] |= b; return true; } internal bool Reveals(int index, bool vanillaExplored, bool vanillaVisible) { if (index < 0 || index >= PixelCount) { return false; } if (!(vanillaExplored && vanillaVisible)) { return (_pixels[index >> 3] & (1 << (index & 7))) != 0; } return true; } } internal static class SharedMapNetwork { private const int MaximumPackageBytes = 131072; private const int MaximumParticipationPayloadBytes = 2097160; private const int MaximumDeltaEntries = 16384; private const int MaximumMarkers = 5000; private const string ParticipationRpc = "com.jg224.sharedmap.Participation"; private const string DeltaRequestRpc = "com.jg224.sharedmap.ExplorationDeltaRequest"; private const string SnapshotRequestRpc = "com.jg224.sharedmap.SnapshotRequest"; private const string SnapshotRpc = "com.jg224.sharedmap.Snapshot"; private const string ExplorationSnapshotRpc = "com.jg224.sharedmap.ExplorationSnapshot"; private const string DeltaRpc = "com.jg224.sharedmap.ExplorationDelta"; private const string MarkerCreateRpc = "com.jg224.sharedmap.MarkerCreate"; private const string MarkerCheckedRpc = "com.jg224.sharedmap.MarkerChecked"; private const string MarkerDeleteRpc = "com.jg224.sharedmap.MarkerDelete"; private const string MarkerManageRpc = "com.jg224.sharedmap.MarkerManage"; private const string MarkerEventRpc = "com.jg224.sharedmap.MarkerEvent"; private const string NoticeRpc = "com.jg224.sharedmap.Notice"; private static readonly HashSet ClientRequestHashes = new HashSet { StringExtensionMethods.GetStableHashCode("com.jg224.sharedmap.Participation"), StringExtensionMethods.GetStableHashCode("com.jg224.sharedmap.ExplorationDeltaRequest"), StringExtensionMethods.GetStableHashCode("com.jg224.sharedmap.SnapshotRequest"), StringExtensionMethods.GetStableHashCode("com.jg224.sharedmap.MarkerCreate"), StringExtensionMethods.GetStableHashCode("com.jg224.sharedmap.MarkerChecked"), StringExtensionMethods.GetStableHashCode("com.jg224.sharedmap.MarkerDelete"), StringExtensionMethods.GetStableHashCode("com.jg224.sharedmap.MarkerManage") }; private static readonly HashSet ServerEventHashes = new HashSet { StringExtensionMethods.GetStableHashCode("com.jg224.sharedmap.Snapshot"), StringExtensionMethods.GetStableHashCode("com.jg224.sharedmap.ExplorationSnapshot"), StringExtensionMethods.GetStableHashCode("com.jg224.sharedmap.ExplorationDelta"), StringExtensionMethods.GetStableHashCode("com.jg224.sharedmap.MarkerEvent"), StringExtensionMethods.GetStableHashCode("com.jg224.sharedmap.Notice") }; private static readonly Dictionary ParticipationTransfers = new Dictionary(); private static readonly SharedMapTransfer SnapshotTransfer = new SharedMapTransfer(); private static readonly SharedMapTransfer ExplorationTransfer = new SharedMapTransfer(); private static readonly SharedMapSendQueue Outgoing = new SharedMapSendQueue(); private static readonly SharedMapContributionBudget Contributions = new SharedMapContributionBudget(); private static readonly List ExpiredParticipationPeers = new List(); private static readonly Func SocketQueueReader = ReadSocketQueue; private static readonly Func FrameSender = SendQueuedFrame; private static double _lastClientTransportActivity; private static double _nextResync; private static double _nextTransportWarning; private static double _nextSnapshotRequest; private static ZRoutedRpc _registeredInstance; private static long _nextTransferId; internal static bool TryGetRpcDirection(int methodHash, out bool serverToClient) { serverToClient = ServerEventHashes.Contains(methodHash); if (!serverToClient) { return ClientRequestHashes.Contains(methodHash); } return true; } internal static bool HasBoundedRoutedParameters(ZPackage package) { if (package.Size() - package.GetPos() < 4) { return false; } int num = package.ReadInt(); if (num < 4 || num > 131076 || num != package.Size() - package.GetPos()) { return false; } int num2 = package.ReadInt(); if (num2 >= 4 && SharedMapPayloadBounds.Allows(num2, package.Size() - package.GetPos(), 131072)) { return num2 == package.Size() - package.GetPos(); } return false; } internal static void Register(ZRoutedRpc rpc) { if (rpc != null && _registeredInstance != rpc) { ResetTransfers(); rpc.Register("com.jg224.sharedmap.Participation", (Action)OnParticipation); rpc.Register("com.jg224.sharedmap.ExplorationDeltaRequest", (Action)OnDeltaRequest); rpc.Register("com.jg224.sharedmap.SnapshotRequest", (Action)OnSnapshotRequest); rpc.Register("com.jg224.sharedmap.Snapshot", (Action)OnSnapshot); rpc.Register("com.jg224.sharedmap.ExplorationSnapshot", (Action)OnExplorationSnapshot); rpc.Register("com.jg224.sharedmap.ExplorationDelta", (Action)OnDelta); rpc.Register("com.jg224.sharedmap.MarkerCreate", (Action)OnMarkerCreate); rpc.Register("com.jg224.sharedmap.MarkerChecked", (Action)OnMarkerChecked); rpc.Register("com.jg224.sharedmap.MarkerDelete", (Action)OnMarkerDelete); rpc.Register("com.jg224.sharedmap.MarkerManage", (Action)OnMarkerManage); rpc.Register("com.jg224.sharedmap.MarkerEvent", (Action)OnMarkerEvent); rpc.Register("com.jg224.sharedmap.Notice", (Action)OnNotice); _registeredInstance = rpc; ManualLogSource log = SharedMapPlugin.Log; if (log != null) { log.LogInfo((object)$"Registered SharedMap routed RPC protocol {3}."); } } } internal static void Shutdown() { ResetTransfers(); _registeredInstance = null; } internal static void Tick(double now) { FlushOutgoing(now); if (SnapshotTransfer.Expire(now)) { ManualLogSource log = SharedMapPlugin.Log; if (log != null) { log.LogWarning((object)"Discarded an incomplete SharedMap snapshot transfer after a timeout."); } RequestResync(); } if (ExplorationTransfer.Expire(now)) { RequestResync(); } if (ParticipationTransfers.Count == 0) { return; } ExpiredParticipationPeers.Clear(); foreach (KeyValuePair participationTransfer in ParticipationTransfers) { if (participationTransfer.Value.Expire(now)) { ExpiredParticipationPeers.Add(participationTransfer.Key); } } for (int i = 0; i < ExpiredParticipationPeers.Count; i++) { long num = ExpiredParticipationPeers[i]; ParticipationTransfers.Remove(num); ManualLogSource log2 = SharedMapPlugin.Log; if (log2 != null) { log2.LogWarning((object)$"Discarded an incomplete SharedMap participation transfer from peer {num} after a timeout."); } } } internal static void ForgetPeer(long peerUid) { if (peerUid != 0L) { ParticipationTransfers.Remove(peerUid); Contributions.Remove(peerUid); Outgoing.Remove(peerUid); } } internal static void ResetClientTransfer() { SnapshotTransfer.Reset(); ExplorationTransfer.Reset(); _lastClientTransportActivity = 0.0; } internal static void ResetConnectionTransfers() { ResetClientTransfer(); if ((Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer()) { Outgoing.Clear(); } _nextSnapshotRequest = 0.0; } internal static void ResetServerTransfers() { ParticipationTransfers.Clear(); Contributions.Clear(); Outgoing.Clear(); } internal static bool CanRetryParticipation(double now) { ZNet instance = ZNet.instance; ZNetPeer val = ((instance != null) ? instance.GetServerPeer() : null); return SharedMapRetryPolicy.Allows(now, _lastClientTransportActivity, val != null && Outgoing.HasPending(val.m_uid), SnapshotTransfer.HasActiveTransfer); } internal static bool SendParticipation(bool enabled, int mapSize, byte[] snapshot) { //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Expected O, but got Unknown if (!TryPrepareClient(out var znet, out var rpc)) { return false; } if (znet.IsServer()) { SharedMapServer.SetHostParticipation(enabled, mapSize, snapshot); return true; } ZNetPeer serverPeer = znet.GetServerPeer(); if (serverPeer == null) { return false; } try { if (!enabled) { Outgoing.Remove(serverPeer.m_uid); ZPackage val = NewPackage(); val.Write(false); return InvokeBounded(rpc, serverPeer.m_uid, "com.jg224.sharedmap.Participation", val); } if (mapSize < 256 || mapSize > 4096 || snapshot == null || snapshot.Length != MapAccess.PackedLength(mapSize)) { throw new InvalidOperationException("Invalid local exploration snapshot dimensions."); } ZPackage val2 = new ZPackage(); val2.Write(mapSize); val2.Write(snapshot); Outgoing.RemoveMethod(serverPeer.m_uid, "com.jg224.sharedmap.Participation"); bool num = SendTransfer(rpc, serverPeer.m_uid, "com.jg224.sharedmap.Participation", val2.GetArray(), writeParticipationFlag: true); if (num) { _lastClientTransportActivity = Time.unscaledTimeAsDouble; } return num; } catch (Exception ex) { ManualLogSource log = SharedMapPlugin.Log; if (log != null) { log.LogWarning((object)("Could not send SharedMap participation to the server: " + ex.Message)); } return false; } } internal static bool SendExplorationDelta(int mapSize, IReadOnlyList indices) { if (indices == null || indices.Count == 0 || indices.Count > 16384 || !TryPrepareClient(out var znet, out var rpc)) { return false; } if (znet.IsServer()) { SharedMapServer.ReceiveHostDelta(mapSize, indices); return true; } ZNetPeer serverPeer = znet.GetServerPeer(); if (serverPeer == null) { return false; } ZPackage package = NewPackage(); WriteIndices(package, mapSize, indices); return InvokeBounded(rpc, serverPeer.m_uid, "com.jg224.sharedmap.ExplorationDeltaRequest", package); } internal static void RequestMarkerCreate(PinType type, Vector3 position, string name) { //IL_0014: 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_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Expected I4, but got Unknown //IL_0036: Unknown result type (might be due to invalid IL or missing references) if (!TryPrepareClient(out var znet, out var rpc)) { return; } if (znet.IsServer()) { SharedMapServer.RequestCreateHost(type, position, name); return; } ZNetPeer serverPeer = znet.GetServerPeer(); if (serverPeer != null) { ZPackage val = NewPackage(); val.Write((int)type); val.Write(position); val.Write(name ?? string.Empty); InvokeBounded(rpc, serverPeer.m_uid, "com.jg224.sharedmap.MarkerCreate", val); } } internal static void RequestMarkerChecked(string markerId, bool isChecked) { if (!TryPrepareClient(out var znet, out var rpc)) { return; } if (znet.IsServer()) { SharedMapServer.RequestCheckedHost(markerId, isChecked); return; } ZNetPeer serverPeer = znet.GetServerPeer(); if (serverPeer != null) { ZPackage val = NewPackage(); val.Write(markerId ?? string.Empty); val.Write(isChecked); InvokeBounded(rpc, serverPeer.m_uid, "com.jg224.sharedmap.MarkerChecked", val); } } internal static void RequestMarkerDelete(string markerId) { if (!TryPrepareClient(out var znet, out var rpc)) { return; } if (znet.IsServer()) { SharedMapServer.RequestDeleteHost(markerId); return; } ZNetPeer serverPeer = znet.GetServerPeer(); if (serverPeer != null) { ZPackage val = NewPackage(); val.Write(markerId ?? string.Empty); InvokeBounded(rpc, serverPeer.m_uid, "com.jg224.sharedmap.MarkerDelete", val); } } internal static void ManageMarker(string action, string id, string value, Vector3 position) { //IL_001a: 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) if (!TryPrepareClient(out var znet, out var rpc)) { return; } if (znet.IsServer()) { SharedMapServer.ManageMarker(0L, host: true, action, id, value, position); return; } ZNetPeer serverPeer = znet.GetServerPeer(); if (serverPeer != null) { ZPackage val = NewPackage(); val.Write(Bound(action, 16)); val.Write(Bound(id, 32)); val.Write(Bound(value, 64)); val.Write(position); InvokeBounded(rpc, serverPeer.m_uid, "com.jg224.sharedmap.MarkerManage", val); } } private static void OnMarkerManage(long sender, ZPackage package) { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) if (!IsServerRequest(sender, package)) { return; } try { string action = ReadBoundedString(package, 16); string id = ReadBoundedString(package, 32); string value = ReadBoundedString(package, 64); Vector3 position = package.ReadVector3(); RequireConsumed(package); SharedMapServer.ManageMarker(sender, host: false, action, id, value, position); } catch (Exception exception) { Reject("marker management", sender, exception); } } internal static bool BroadcastSnapshot(IEnumerable peers, long worldUid, int mapSize, byte[] exploration, IReadOnlyList markers) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Expected O, but got Unknown if (ZRoutedRpc.instance == null) { return false; } SharedMapOutboundMessage message; try { ZPackage val = new ZPackage(); val.Write(worldUid); val.Write(mapSize); val.Write(exploration ?? Array.Empty()); val.Write(markers.Count); for (int i = 0; i < markers.Count; i++) { WriteMarker(val, markers[i]); } message = new SharedMapOutboundMessage("com.jg224.sharedmap.Snapshot", val.GetArray(), NextTransferId()); } catch (Exception ex) { ManualLogSource log = SharedMapPlugin.Log; if (log != null) { log.LogWarning((object)("Could not prepare a bounded SharedMap snapshot: " + ex.Message)); } return false; } bool flag = true; foreach (long item in SnapshotPeers(peers)) { try { flag &= Outgoing.Enqueue(item, message, authoritativeSnapshot: true, resyncOnOverflow: true); } catch (Exception ex2) { ManualLogSource log2 = SharedMapPlugin.Log; if (log2 != null) { log2.LogWarning((object)$"Could not send SharedMap snapshot to peer {item}: {ex2.Message}"); } flag = false; } } return flag; } internal static void BroadcastExplorationSnapshot(IEnumerable peers, long worldUid, int mapSize, byte[] exploration) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Expected O, but got Unknown if (ZRoutedRpc.instance == null || exploration == null) { return; } ZPackage val = new ZPackage(); val.Write(worldUid); val.Write(mapSize); val.Write(exploration); SharedMapOutboundMessage message = new SharedMapOutboundMessage("com.jg224.sharedmap.ExplorationSnapshot", val.GetArray(), NextTransferId()); foreach (long item in SnapshotPeers(peers)) { Outgoing.Enqueue(item, message, authoritativeSnapshot: false, resyncOnOverflow: true); } } internal static void BroadcastExplorationDelta(IEnumerable peers, long worldUid, int mapSize, IReadOnlyList indices) { ZRoutedRpc instance = ZRoutedRpc.instance; if (instance == null || indices == null || indices.Count == 0) { return; } foreach (long item in SnapshotPeers(peers)) { ZPackage val = NewPackage(); val.Write(worldUid); WriteIndices(val, mapSize, indices); InvokeBounded(instance, item, "com.jg224.sharedmap.ExplorationDelta", val); } } internal static void BroadcastMarker(IEnumerable peers, PublicMarker marker) { ZRoutedRpc instance = ZRoutedRpc.instance; if (instance == null || marker == null) { return; } foreach (long item in SnapshotPeers(peers)) { ZPackage val = NewPackage(); val.Write(1); WriteMarker(val, marker); InvokeBounded(instance, item, "com.jg224.sharedmap.MarkerEvent", val); } } internal static void BroadcastMarkerRemoval(IEnumerable peers, string markerId, long revision) { ZRoutedRpc instance = ZRoutedRpc.instance; if (instance == null) { return; } foreach (long item in SnapshotPeers(peers)) { ZPackage val = NewPackage(); val.Write(2); val.Write(markerId ?? string.Empty); val.Write(revision); InvokeBounded(instance, item, "com.jg224.sharedmap.MarkerEvent", val); } } internal static void SendNotice(long peerUid, string message) { ZRoutedRpc instance = ZRoutedRpc.instance; if (instance != null) { ZPackage val = NewPackage(); val.Write(Bound(message, 256)); InvokeBounded(instance, peerUid, "com.jg224.sharedmap.Notice", val); } } private static void OnParticipation(long sender, ZPackage package) { //IL_0154: Unknown result type (might be due to invalid IL or missing references) //IL_0159: Unknown result type (might be due to invalid IL or missing references) //IL_0161: Unknown result type (might be due to invalid IL or missing references) //IL_016c: Expected O, but got Unknown //IL_0173: Expected O, but got Unknown if (!IsServerRequest(sender, package)) { return; } try { if (!package.ReadBool()) { RequireConsumed(package); ParticipationTransfers.Remove(sender); Outgoing.Remove(sender); SharedMapServer.SetRemoteParticipation(sender, enabled: false, 0, Array.Empty()); return; } long transferId = package.ReadLong(); int num = package.ReadInt(); int chunkCount = package.ReadInt(); int chunkIndex = package.ReadInt(); if (!Contributions.Accept(sender, transferId, package.Size(), Time.unscaledTimeAsDouble)) { return; } byte[] data = ReadBoundedBytes(package, 32768); RequireConsumed(package); if (num > 2097160) { throw new InvalidOperationException("SharedMap participation payload exceeds its limit."); } if (!ParticipationTransfers.TryGetValue(sender, out var value)) { if (ParticipationTransfers.Count >= 128) { return; } value = new SharedMapTransfer(); ParticipationTransfers.Add(sender, value); } long num2 = num; foreach (KeyValuePair participationTransfer in ParticipationTransfers) { if (participationTransfer.Key != sender) { num2 += participationTransfer.Value.ExpectedLength; } } if (num2 <= 33554432 && value.Accept(transferId, num, chunkCount, chunkIndex, data, Time.unscaledTimeAsDouble, out var payload) == SharedMapTransferResult.Completed) { ZPackage val = new ZPackage(payload); int mapSize = val.ReadInt(); byte[] snapshot = ReadBoundedBytes(val, 2097152); RequireConsumed(val); SharedMapServer.SetRemoteParticipation(sender, enabled: true, mapSize, snapshot); } } catch (Exception exception) { ParticipationTransfers.Remove(sender); Reject("participation", sender, exception); } } private static void OnDeltaRequest(long sender, ZPackage package) { if (!IsServerRequest(sender, package) || !Contributions.Accept(sender, 0L, package.Size(), Time.unscaledTimeAsDouble, delta: true)) { return; } try { ReadIndices(package, out var mapSize, out var indices); RequireConsumed(package); SharedMapServer.ReceiveRemoteDelta(sender, mapSize, indices); } catch (Exception exception) { Reject("exploration delta", sender, exception); } } private static void OnSnapshot(long sender, ZPackage package) { //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Expected O, but got Unknown if (!IsTrustedServer(sender, package)) { return; } try { ReadTransferChunk(package, out var transferId, out var totalLength, out var chunkCount, out var chunkIndex, out var data); RequireConsumed(package); byte[] payload; SharedMapTransferResult num = SnapshotTransfer.Accept(transferId, totalLength, chunkCount, chunkIndex, data, Time.unscaledTimeAsDouble, out payload); if (num != SharedMapTransferResult.Duplicate) { _lastClientTransportActivity = Time.unscaledTimeAsDouble; } if (num != SharedMapTransferResult.Completed) { return; } ZPackage val = new ZPackage(payload); long worldUid = val.ReadLong(); int num2 = val.ReadInt(); byte[] array = ReadBoundedBytes(val, 2097152); if (num2 < 256 || num2 > 4096 || array.Length != MapAccess.PackedLength(num2)) { throw new InvalidOperationException("Invalid exploration snapshot dimensions."); } int num3 = val.ReadInt(); if (num3 < 0 || num3 > 5000) { throw new InvalidOperationException("Invalid marker count."); } List list = new List(num3); HashSet hashSet = new HashSet(StringComparer.Ordinal); for (int i = 0; i < num3; i++) { PublicMarker publicMarker = ReadMarker(val); if (!hashSet.Add(publicMarker.Id)) { throw new InvalidOperationException("Duplicate public marker ID."); } list.Add(publicMarker); } RequireConsumed(val); ExplorationTransfer.Reset(); SharedMapClient.ReceiveSnapshot(worldUid, num2, array, list); } catch (Exception exception) { SnapshotTransfer.Reset(); Reject("snapshot", sender, exception); RequestResync(); } } private static void OnExplorationSnapshot(long sender, ZPackage package) { //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_0062: 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_0075: Expected O, but got Unknown //IL_007c: Expected O, but got Unknown if (!IsTrustedServer(sender, package)) { return; } try { ReadTransferChunk(package, out var transferId, out var totalLength, out var chunkCount, out var chunkIndex, out var data); RequireConsumed(package); if (totalLength > 2097168) { throw new InvalidOperationException("SharedMap exploration payload exceeds its limit."); } if (ExplorationTransfer.Accept(transferId, totalLength, chunkCount, chunkIndex, data, Time.unscaledTimeAsDouble, out var payload) == SharedMapTransferResult.Completed) { ZPackage val = new ZPackage(payload); long worldUid = val.ReadLong(); int num = val.ReadInt(); byte[] array = ReadBoundedBytes(val, 2097152); RequireConsumed(val); if (num < 256 || num > 4096 || array.Length != MapAccess.PackedLength(num)) { throw new InvalidOperationException("Invalid exploration snapshot dimensions."); } SharedMapClient.ReceiveExplorationSnapshot(worldUid, num, array); } } catch (Exception exception) { ExplorationTransfer.Reset(); Reject("exploration snapshot", sender, exception); RequestResync(); } } private static void OnSnapshotRequest(long sender, ZPackage package) { if (!IsServerRequest(sender, package)) { return; } try { RequireConsumed(package); if (Contributions.Accept(sender, 0L, package.Size(), Time.unscaledTimeAsDouble, delta: false, restart: true)) { SharedMapServer.TrySendResync(sender); } } catch (Exception exception) { Reject("snapshot request", sender, exception); } } private static void RequestResync() { double unscaledTimeAsDouble = Time.unscaledTimeAsDouble; ZNet instance = ZNet.instance; ZNetPeer val = (((Object)(object)instance == (Object)null || instance.IsServer()) ? null : instance.GetServerPeer()); if (val != null && SharedMapClient.Sharing && !(unscaledTimeAsDouble < _nextSnapshotRequest) && InvokeBounded(ZRoutedRpc.instance, val.m_uid, "com.jg224.sharedmap.SnapshotRequest", NewPackage())) { _nextSnapshotRequest = unscaledTimeAsDouble + 120.0; } } private static void OnDelta(long sender, ZPackage package) { if (!IsTrustedServer(sender, package)) { return; } try { long worldUid = package.ReadLong(); ReadIndices(package, out var mapSize, out var indices); RequireConsumed(package); SharedMapClient.ReceiveExplorationDelta(worldUid, mapSize, indices); } catch (Exception exception) { Reject("server exploration delta", sender, exception); } } private static void OnMarkerCreate(long sender, ZPackage package) { //IL_0011: 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_0018: 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_002a: Unknown result type (might be due to invalid IL or missing references) if (!IsServerRequest(sender, package)) { return; } try { PinType type = (PinType)package.ReadInt(); Vector3 position = package.ReadVector3(); string name = ReadBoundedString(package, 64); RequireConsumed(package); SharedMapServer.RequestCreateRemote(sender, type, position, name); } catch (Exception exception) { Reject("marker creation", sender, exception); } } private static void OnMarkerChecked(long sender, ZPackage package) { if (!IsServerRequest(sender, package)) { return; } try { string markerId = ReadMarkerId(package); bool isChecked = package.ReadBool(); RequireConsumed(package); SharedMapServer.RequestCheckedRemote(sender, markerId, isChecked); } catch (Exception exception) { Reject("marker X update", sender, exception); } } private static void OnMarkerDelete(long sender, ZPackage package) { if (!IsServerRequest(sender, package)) { return; } try { string markerId = ReadMarkerId(package); RequireConsumed(package); SharedMapServer.RequestDeleteRemote(sender, markerId); } catch (Exception exception) { Reject("marker deletion", sender, exception); } } private static void OnMarkerEvent(long sender, ZPackage package) { if (!IsTrustedServer(sender, package)) { return; } try { switch (package.ReadInt()) { case 1: SharedMapClient.UpsertMarker(ReadMarker(package)); break; case 2: { string markerId = ReadMarkerId(package); package.ReadLong(); SharedMapClient.RemoveMarker(markerId); break; } default: throw new InvalidOperationException("Invalid marker event operation."); } RequireConsumed(package); } catch (Exception exception) { Reject("marker event", sender, exception); } } private static void OnNotice(long sender, ZPackage package) { if (!IsTrustedServer(sender, package)) { return; } try { string message = ReadBoundedString(package, 256); RequireConsumed(package); SharedMapClient.ShowMessage(message); } catch (Exception exception) { Reject("notice", sender, exception); } } private static ZPackage NewPackage() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Expected O, but got Unknown ZPackage val = new ZPackage(); val.Write(3); return val; } private static bool IsServerRequest(long sender, ZPackage package) { ZNet instance = ZNet.instance; if ((Object)(object)instance == (Object)null || !instance.IsServer() || !IsBounded(package)) { return false; } ZNetPeer peer = instance.GetPeer(sender); if (peer != null && peer.m_uid == sender) { return ReadProtocol(package); } return false; } private static bool IsTrustedServer(long sender, ZPackage package) { ZNet instance = ZNet.instance; if ((Object)(object)instance == (Object)null || instance.IsServer() || !IsBounded(package)) { return false; } ZNetPeer serverPeer = instance.GetServerPeer(); if (serverPeer != null && sender == serverPeer.m_uid) { return ReadProtocol(package); } return false; } private static bool ReadProtocol(ZPackage package) { try { int num = package.ReadInt(); if (num == 3) { return true; } ManualLogSource log = SharedMapPlugin.Log; if (log != null) { log.LogWarning((object)$"Ignored SharedMap protocol {num}; expected {3}."); } } catch (Exception ex) { ManualLogSource log2 = SharedMapPlugin.Log; if (log2 != null) { log2.LogWarning((object)("Ignored malformed SharedMap protocol header: " + ex.Message)); } } return false; } private static bool IsBounded(ZPackage package) { if (package != null && package.Size() > 0) { return package.Size() <= 131072; } return false; } private static bool SendTransfer(ZRoutedRpc rpc, long peerUid, string rpcName, byte[] payload, bool writeParticipationFlag) { if (rpc == null) { return false; } return Outgoing.Enqueue(peerUid, new SharedMapOutboundMessage(rpcName, payload, NextTransferId(), writeParticipationFlag)); } private static void WriteTransferChunk(ZPackage package, SharedMapTransferChunk chunk) { package.Write(chunk.TransferId); package.Write(chunk.TotalLength); package.Write(chunk.ChunkCount); package.Write(chunk.ChunkIndex); package.Write(chunk.Data); } private static void ReadTransferChunk(ZPackage package, out long transferId, out int totalLength, out int chunkCount, out int chunkIndex, out byte[] data) { transferId = package.ReadLong(); totalLength = package.ReadInt(); chunkCount = package.ReadInt(); chunkIndex = package.ReadInt(); data = ReadBoundedBytes(package, 32768); } private static byte[] ReadBoundedBytes(ZPackage package, int maximum) { if (package.Size() - package.GetPos() < 4) { throw new InvalidOperationException("SharedMap byte-array length is missing."); } int num = package.ReadInt(); if (!SharedMapPayloadBounds.Allows(num, package.Size() - package.GetPos(), maximum)) { throw new InvalidOperationException("SharedMap byte-array length exceeds its payload or limit."); } return package.ReadByteArray(num); } private static bool InvokeBounded(ZRoutedRpc rpc, long peerUid, string rpcName, ZPackage package) { if (rpc == null) { throw new InvalidOperationException("SharedMap routed RPC is unavailable."); } if (!IsBounded(package)) { throw new InvalidOperationException($"SharedMap refused to enqueue an RPC larger than {131072} bytes."); } return Outgoing.Enqueue(peerUid, new SharedMapOutboundMessage(rpcName, package.GetArray(), 0L), authoritativeSnapshot: false, (Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer()); } private static void FlushOutgoing(double now) { ZNet instance = ZNet.instance; ZRoutedRpc instance2 = ZRoutedRpc.instance; if ((Object)(object)instance == (Object)null || instance2 == null) { return; } if (now >= _nextResync) { _nextResync = now + 1.0; long[] array = Outgoing.PeerIds(); foreach (long num in array) { if (instance.GetPeer(num) == null) { ForgetPeer(num); } } if (instance.IsServer()) { array = Outgoing.ResyncPeers(); for (int i = 0; i < array.Length; i++) { SharedMapServer.TrySendResync(array[i]); } } } Outgoing.Flush(now, SocketQueueReader, FrameSender); } private static int ReadSocketQueue(long peerUid) { try { ZNet instance = ZNet.instance; ZNetPeer val = ((instance != null) ? instance.GetPeer(peerUid) : null); object obj = val?.m_socket; if (obj == null) { if (val == null) { obj = null; } else { ZRpc rpc = val.m_rpc; obj = ((rpc != null) ? rpc.GetSocket() : null); } } ISocket val2 = (ISocket)obj; if (val2 == null || !val2.IsConnected()) { return -1; } return SharedMapSocketBudget.ActualBytes(val2.GetSendQueueSize(), val2 is ZPlayFabSocket); } catch { return -1; } } private static bool SendQueuedFrame(long peerUid, SharedMapOutboundFrame frame) { //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Expected O, but got Unknown double unscaledTimeAsDouble = Time.unscaledTimeAsDouble; ZNet instance = ZNet.instance; ZRoutedRpc instance2 = ZRoutedRpc.instance; if ((Object)(object)instance == (Object)null || instance2 == null) { return false; } try { ZPackage val; if (frame.Message.TransferId == 0L) { val = new ZPackage(frame.Message.Payload); } else { val = NewPackage(); if (frame.Message.Participation) { val.Write(true); } byte[] array = new byte[frame.Length]; Buffer.BlockCopy(frame.Message.Payload, frame.Offset, array, 0, array.Length); WriteTransferChunk(val, new SharedMapTransferChunk(frame.Message.TransferId, frame.Message.Payload.Length, frame.Message.FrameCount, frame.Index, array)); } if (!IsBounded(val)) { throw new InvalidOperationException("SharedMap queued frame exceeds its limit."); } instance2.InvokeRoutedRPC(peerUid, frame.Message.Method, new object[1] { val }); if (!instance.IsServer()) { _lastClientTransportActivity = unscaledTimeAsDouble; } return true; } catch (Exception ex) { if (unscaledTimeAsDouble >= _nextTransportWarning) { _nextTransportWarning = unscaledTimeAsDouble + 30.0; ManualLogSource log = SharedMapPlugin.Log; if (log != null) { log.LogWarning((object)("SharedMap transport is waiting to retry: " + ex.Message)); } } return false; } } private static long NextTransferId() { long num = Interlocked.Increment(ref _nextTransferId); if (num > 0) { return num; } Interlocked.Exchange(ref _nextTransferId, 0L); return Interlocked.Increment(ref _nextTransferId); } private static void ResetTransfers() { ParticipationTransfers.Clear(); SnapshotTransfer.Reset(); ExplorationTransfer.Reset(); Contributions.Clear(); Outgoing.Clear(); _lastClientTransportActivity = 0.0; _nextResync = 0.0; _nextSnapshotRequest = 0.0; _nextTransportWarning = 0.0; } private static bool TryPrepareClient(out ZNet znet, out ZRoutedRpc rpc) { znet = ZNet.instance; rpc = ZRoutedRpc.instance; if ((Object)(object)znet != (Object)null) { return rpc != null; } return false; } private static void WriteIndices(ZPackage package, int mapSize, IReadOnlyList indices) { package.Write(mapSize); package.Write(indices.Count); for (int i = 0; i < indices.Count; i++) { package.Write(indices[i]); } } private static void ReadIndices(ZPackage package, out int mapSize, out List indices) { mapSize = package.ReadInt(); if (mapSize < 256 || mapSize > 4096) { throw new InvalidOperationException("Invalid map size."); } int num = package.ReadInt(); if (num < 0 || num > 16384) { throw new InvalidOperationException("Invalid exploration delta count."); } int num2 = checked(mapSize * mapSize); indices = new List(num); for (int i = 0; i < num; i++) { int num3 = package.ReadInt(); if (num3 < 0 || num3 >= num2) { throw new InvalidOperationException("Invalid map index."); } indices.Add(num3); } } private static void WriteMarker(ZPackage package, PublicMarker marker) { //IL_002f: 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_0045: Expected I4, but got Unknown package.Write(marker.Id); package.Write(marker.OwnerPlayerId); package.Write(marker.OwnerName ?? string.Empty); package.Write(marker.Position); package.Write((int)marker.Type); package.Write(marker.Name ?? string.Empty); package.Write(marker.Checked); package.Write(marker.Revision); } private static PublicMarker ReadMarker(ZPackage package) { //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_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_0080: Unknown result type (might be due to invalid IL or missing references) PublicMarker publicMarker = new PublicMarker { Id = ReadMarkerId(package), OwnerPlayerId = package.ReadLong(), OwnerName = ReadBoundedString(package, 64), Position = package.ReadVector3(), Type = (PinType)package.ReadInt(), Name = ReadBoundedString(package, 64), Checked = package.ReadBool(), Revision = package.ReadLong() }; if (publicMarker.OwnerPlayerId == 0L || !IsPublicMarkerType(publicMarker.Type) || !IsFinite(publicMarker.Position)) { throw new InvalidOperationException("Invalid public marker record."); } return publicMarker; } private static string ReadMarkerId(ZPackage package) { string obj = package.ReadString() ?? string.Empty; if (obj.Length != 32) { throw new InvalidOperationException("Invalid public marker ID."); } return obj; } private static string ReadBoundedString(ZPackage package, int maximum) { string obj = package.ReadString() ?? string.Empty; if (obj.Length > maximum) { throw new InvalidOperationException("SharedMap string exceeds its limit."); } return obj; } private static bool IsPublicMarkerType(PinType type) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Invalid comparison between Unknown and I4 //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Invalid comparison between Unknown and I4 //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Invalid comparison between Unknown and I4 //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Invalid comparison between Unknown and I4 if ((int)type != 0 && (int)type != 1 && (int)type != 2 && (int)type != 3) { return (int)type == 6; } return true; } private static bool IsFinite(Vector3 value) { //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_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) if (!float.IsNaN(value.x) && !float.IsInfinity(value.x) && !float.IsNaN(value.y) && !float.IsInfinity(value.y) && !float.IsNaN(value.z)) { return !float.IsInfinity(value.z); } return false; } private static List SnapshotPeers(IEnumerable peers) { if (peers != null) { return new List(peers); } return new List(); } private static string Bound(string value, int maximum) { value = value ?? string.Empty; if (value.Length > maximum) { return value.Substring(0, maximum); } return value; } private static void RequireConsumed(ZPackage package) { if (package.GetPos() != package.Size()) { throw new InvalidOperationException("Unexpected trailing SharedMap data."); } } private static void Reject(string label, long sender, Exception exception) { ManualLogSource log = SharedMapPlugin.Log; if (log != null) { log.LogWarning((object)$"Rejected SharedMap {label} from peer {sender}: {exception.Message}"); } } } internal static class SharedMapOwnership { internal const int MaximumCharacters = 100000; internal const int MaximumCharactersPerAccount = 128; internal const string LocalHostAccount = "local-host"; internal static bool TryAccountKey(string transport, string authenticatedHost, out string key) { key = string.Empty; string text = ((transport == "ZSteamSocket") ? "steam:" : ((transport == "ZPlayFabSocket") ? "playfab:" : null)); if (text == null || string.IsNullOrWhiteSpace(authenticatedHost) || authenticatedHost.Length > 256 || string.Equals(authenticatedHost, "None", StringComparison.OrdinalIgnoreCase)) { return false; } if (transport == "ZSteamSocket" && (!ulong.TryParse(authenticatedHost, out var result) || result == 0L)) { return false; } if (transport == "ZPlayFabSocket" && (!authenticatedHost.StartsWith("playfab/", StringComparison.Ordinal) || authenticatedHost.Length <= 8)) { return false; } foreach (char c in authenticatedHost) { if (char.IsControl(c) || char.IsWhiteSpace(c)) { return false; } } using SHA256 sHA = SHA256.Create(); byte[] array = sHA.ComputeHash(Encoding.UTF8.GetBytes(authenticatedHost)); key = text + BitConverter.ToString(array).Replace("-", string.Empty).ToLowerInvariant(); return true; } internal static bool IsAccountKey(string key) { if (key == "local-host") { return true; } if (key == null) { return false; } int num = (key.StartsWith("steam:", StringComparison.Ordinal) ? 6 : (key.StartsWith("playfab:", StringComparison.Ordinal) ? 8 : 0)); if (num == 0 || key.Length != num + 64) { return false; } for (int i = num; i < key.Length; i++) { if ((key[i] < '0' || key[i] > '9') && (key[i] < 'a' || key[i] > 'f')) { return false; } } return true; } internal static bool CanManage(string owner, string actor, bool administrator) { if (!administrator) { if (IsAccountKey(actor)) { return string.Equals(owner, actor, StringComparison.Ordinal); } return false; } return true; } internal static bool CanCreateMarker(IEnumerable markerOwners, string account) { if (!IsAccountKey(account)) { return false; } int num = 0; int num2 = 0; foreach (string markerOwner in markerOwners) { num++; if (markerOwner == account) { num2++; } if (num >= 5000 || num2 >= 200) { return false; } } return true; } internal static bool IsAdministrator(string transport, bool platformClaimIsAdmin, bool authenticatedEndpointIsAdmin) { if (!(transport == "ZSteamSocket")) { return transport == "ZPlayFabSocket" && authenticatedEndpointIsAdmin; } return platformClaimIsAdmin; } internal static bool TryClaimCharacter(SharedMapPlayerClaims claims, Dictionary registry, long peer, long player, long hostPlayer, string account) { if (!IsAccountKey(account) || (registry.TryGetValue(player, out var value) && value.Length != 0 && value != account)) { return false; } return claims.Accept(peer, player, hostPlayer); } internal static bool TryRegister(Dictionary registry, long playerId, string account, out bool changed, out bool legacy, out string error) { changed = false; legacy = false; error = string.Empty; if (playerId == 0L || !IsAccountKey(account)) { error = "SharedMap requires an authenticated Steam or PlayFab account."; return false; } if (registry.TryGetValue(playerId, out var value)) { legacy = value.Length == 0; if (legacy || string.Equals(value, account, StringComparison.Ordinal)) { return true; } error = "This SharedMap character ID is registered to a different authenticated account. Ask a server administrator for help."; return false; } int num = 0; foreach (string value2 in registry.Values) { if (value2 == account) { num++; } } if (registry.Count >= 100000 || num >= 128) { error = "The SharedMap character registration limit has been reached."; return false; } registry.Add(playerId, account); changed = true; return true; } internal static bool TryBindLegacy(Dictionary registry, long playerId, string account, bool administrator, out string error) { error = string.Empty; if (!administrator || !IsAccountKey(account)) { error = "Legacy ownership binding requires a server administrator and an authenticated connected account."; return false; } if (!registry.TryGetValue(playerId, out var value) || value.Length != 0) { error = "Only an unbound legacy character ID can be bound; existing account ownership cannot be reassigned."; return false; } registry[playerId] = account; return true; } } [HarmonyPatch(typeof(ZNet), "Awake")] internal static class SharedMapZNetAwakePatch { [HarmonyPostfix] private static void Postfix() { SharedMapClient.ResetConnection(); SharedMapNetwork.Register(ZRoutedRpc.instance); } } [HarmonyPatch(typeof(Game), "Awake")] internal static class SharedMapGameAwakePatch { [HarmonyPostfix] private static void Postfix() { if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer()) { SharedMapServer.LoadForCurrentWorld(); } } } [HarmonyPatch(typeof(Game), "OnDestroy")] internal static class SharedMapGameDestroyPatch { [HarmonyPrefix] private static void Prefix() { SharedMapServer.Shutdown(); SharedMapClient.ResetSession(); } } [HarmonyPatch(typeof(ZNet), "Shutdown", new Type[] { typeof(bool) })] internal static class SharedMapZNetShutdownPatch { [HarmonyPrefix] private static void Prefix(ZNet __instance) { if (__instance.IsServer()) { SharedMapServer.Shutdown(); } } } [HarmonyPatch(typeof(ZNet), "Disconnect", new Type[] { typeof(ZNetPeer) })] internal static class SharedMapDisconnectPatch { [HarmonyPrefix] private static void Prefix(ZNet __instance, ZNetPeer peer) { if (__instance.IsServer()) { SharedMapServer.RemoveParticipant(peer?.m_uid ?? 0); } else { SharedMapClient.ResetConnection(); } } } [HarmonyPatch(typeof(Minimap), "Start")] internal static class SharedMapMinimapStartPatch { [HarmonyPostfix] private static void Postfix(Minimap __instance) { SharedMapUi.Ensure(__instance); } } [HarmonyPatch(typeof(Minimap), "OnDestroy")] internal static class SharedMapMinimapDestroyPatch { [HarmonyPrefix] private static void Prefix(Minimap __instance) { SharedMapClient.OnMinimapDestroyed(__instance); } } [HarmonyPatch(typeof(Minimap), "UpdatePins")] internal static class SharedMapUpdatePinsPatch { [HarmonyPostfix] private static void Postfix(Minimap __instance) { SharedMapClient.TintPublicPins(__instance); } } [HarmonyPatch(typeof(Minimap), "Explore", new Type[] { typeof(int), typeof(int) })] internal static class SharedMapExplorePixelPatch { [HarmonyPostfix] private static void Postfix(Minimap __instance, int x, int y, bool __result) { SharedMapClient.RecordLocalExploration(__instance, x, y, __result); } } [HarmonyPatch(typeof(Minimap), "ExploreOthers", new Type[] { typeof(int), typeof(int) })] internal static class SharedMapVanillaSharedPixelPatch { [HarmonyPostfix] private static void Postfix(Minimap __instance, int x, int y) { MapAccess.AfterVanillaSharedPixel(__instance, x, y); } } [HarmonyPatch(typeof(Minimap), "Update")] internal static class SharedMapFogPresentationPatch { [HarmonyPostfix] private static void Postfix(Minimap __instance, bool ___m_showSharedMapData, float ___m_sharedMapDataFade) { MapAccess.RefreshSharedPresentation(__instance, ___m_showSharedMapData, ___m_sharedMapDataFade); } } [HarmonyPatch] internal static class SharedMapFogResetPatch { [HarmonyTargetMethods] private static IEnumerable TargetMethods() { yield return AccessTools.Method(typeof(Minimap), "Reset", Type.EmptyTypes, (Type[])null); yield return AccessTools.Method(typeof(Minimap), "ResetSharedMapData", Type.EmptyTypes, (Type[])null); yield return AccessTools.Method(typeof(Minimap), "ResetAndExplore", new Type[2] { typeof(byte[]), typeof(byte[]) }, (Type[])null); yield return AccessTools.Method(typeof(Minimap), "OnToggleSharedMapData", Type.EmptyTypes, (Type[])null); } [HarmonyPostfix] private static void Postfix(Minimap __instance) { MapAccess.RecomposeSharedFog(__instance); } } [HarmonyPatch(typeof(Minimap), "SetMapData", new Type[] { typeof(byte[]) })] internal static class SharedMapVanillaMapLoadedPatch { [HarmonyPostfix] private static void Postfix(Minimap __instance) { SharedMapClient.AfterVanillaMapLoaded(__instance); } } [HarmonyPatch(typeof(Minimap), "SelectIcon", new Type[] { typeof(PinType) })] internal static class SharedMapSelectIconPatch { [HarmonyPostfix] private static void Postfix() { SharedMapUi.OnVanillaIconSelected(); } } [HarmonyPatch(typeof(Minimap), "ShowPinNameInput", new Type[] { typeof(Vector3) })] internal static class SharedMapShowPinNamePatch { [HarmonyPostfix] private static void Postfix(Minimap __instance) { SharedMapClient.AfterShowPinNameInput(__instance); } } [HarmonyPatch(typeof(Minimap), "OnPinTextEntered", new Type[] { typeof(string) })] internal static class SharedMapPinTextPatch { [HarmonyPrefix] private static void Prefix(Minimap __instance, out PinData __state) { __state = SharedMapClient.BeforePinTextEntered(__instance); } [HarmonyPostfix] private static void Postfix(Minimap __instance, PinData __state) { SharedMapClient.AfterPinTextEntered(__instance, __state); } } [HarmonyPatch(typeof(Minimap), "HidePinTextInput", new Type[] { typeof(bool) })] internal static class SharedMapHidePinTextPatch { [HarmonyPrefix] private static void Prefix(Minimap __instance) { SharedMapClient.BeforeHidePinTextInput(__instance); } } [HarmonyPatch(typeof(Minimap), "OnMapLeftClick")] internal static class SharedMapLeftClickPatch { [HarmonyPrefix] private static void Prefix(Minimap __instance, out SharedMapClient.MarkerCheckState __state) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) __state = SharedMapClient.CaptureClosestPublicCheck(__instance, ZInput.pointerPosition); } [HarmonyPostfix] private static void Postfix(SharedMapClient.MarkerCheckState __state) { SharedMapClient.SubmitCheckChange(__state); } } [HarmonyPatch(typeof(Minimap), "UpdateMap", new Type[] { typeof(Player), typeof(float), typeof(bool) })] internal static class SharedMapUpdateMapPatch { [HarmonyPrefix] private static void Prefix(Minimap __instance, bool takeInput, out SharedMapClient.MarkerCheckState __state) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Invalid comparison between Unknown and I4 //IL_0035: Unknown result type (might be due to invalid IL or missing references) __state = ((takeInput && (int)__instance.m_mode == 2 && ZInput.GetButtonDown("JoyTabLeft")) ? SharedMapClient.CaptureClosestPublicCheck(__instance, new Vector3((float)(Screen.width / 2), (float)(Screen.height / 2))) : default(SharedMapClient.MarkerCheckState)); } [HarmonyPostfix] private static void Postfix(SharedMapClient.MarkerCheckState __state) { SharedMapClient.SubmitCheckChange(__state); } } [HarmonyPatch(typeof(Minimap), "RemovePin", new Type[] { typeof(Vector3), typeof(float) })] internal static class SharedMapRemovePinAtPatch { [HarmonyPrefix] private static bool Prefix(Minimap __instance, Vector3 pos, float radius, ref bool __result) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) if (!SharedMapClient.TryHandleRemoveAt(__instance, pos, radius, out var result)) { return true; } __result = result; return false; } } [HarmonyPatch(typeof(Minimap), "GetMapData")] internal static class SharedMapPrivateSerializationPatch { [HarmonyPrefix] private static void Prefix(out SharedMapClient.PinSaveState __state) { __state = SharedMapClient.SuspendPublicPinsForSerialization(); } [HarmonyPostfix] private static void Postfix(SharedMapClient.PinSaveState __state) { SharedMapClient.RestorePublicPinsAfterSerialization(__state); } [HarmonyFinalizer] private static Exception Finalizer(Exception __exception, SharedMapClient.PinSaveState __state) { SharedMapClient.RestorePublicPinsAfterSerialization(__state); return __exception; } } [HarmonyPatch(typeof(Minimap), "GetSharedMapData", new Type[] { typeof(byte[]) })] internal static class SharedMapSharedSerializationPatch { [HarmonyPrefix] private static void Prefix(out SharedMapClient.PinSaveState __state) { __state = SharedMapClient.SuspendPublicPinsForSerialization(); } [HarmonyPostfix] private static void Postfix(SharedMapClient.PinSaveState __state) { SharedMapClient.RestorePublicPinsAfterSerialization(__state); } [HarmonyFinalizer] private static Exception Finalizer(Exception __exception, SharedMapClient.PinSaveState __state) { SharedMapClient.RestorePublicPinsAfterSerialization(__state); return __exception; } } [BepInPlugin("com.jg224.sharedmap", "SharedMap", "0.5.1")] [BepInDependency("com.jg224.modcore", "0.5.0")] public sealed class SharedMapPlugin : BaseUnityPlugin { public const string PluginGuid = "com.jg224.sharedmap"; public const string PluginName = "SharedMap"; public const string PluginVersion = "0.5.1"; public const string ModCoreGuid = "com.jg224.modcore"; public const int ProtocolVersion = 3; public static readonly ModuleId ModuleId = new ModuleId("sharedmap"); private Harmony _harmony; private readonly List _registrations = new List(); private bool _shutDown; internal static ManualLogSource Log { get; private set; } internal static ICoreServices Core { get; private set; } private void Awake() { //IL_01a8: 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_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Expected O, but got Unknown //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Unknown result type (might be due to invalid IL or missing references) //IL_011f: Expected O, but got Unknown //IL_012a: Unknown result type (might be due to invalid IL or missing references) //IL_0134: Expected O, but got Unknown //IL_0153: Unknown result type (might be due to invalid IL or missing references) Log = ((BaseUnityPlugin)this).Logger; try { if (!ModCoreApi.IsAvailable) { throw new InvalidOperationException("ModCore did not initialize before SharedMap."); } Core = ModCoreApi.Services; SemanticVersion val = default(SemanticVersion); if (!SemanticVersion.TryParse("0.5.1", ref val)) { throw new InvalidOperationException("Invalid SharedMap plugin version."); } _registrations.Add(Core.Modules.Register(new ModuleDescriptor(ModuleId, "com.jg224.sharedmap", "SharedMap", val, 3, (ModuleSide)3, (ModuleRequirement)4, 0uL, 1, 1))); _registrations.Add(Core.Namespaces.Register(ModuleId, (NamespaceKind)6, "com.jg224.sharedmap.", 1, Array.Empty())); _registrations.Add(Core.Namespaces.Register(ModuleId, (NamespaceKind)4, "SharedMap", 1, Array.Empty())); _registrations.Add(Core.Namespaces.Register(ModuleId, (NamespaceKind)8, "sharedmap.", 1, Array.Empty())); _registrations.Add(Core.Ui.Reserve(new UiReservation(ModuleId, (UiSurface)6, "minimap.public-markers", 20, true))); _harmony = new Harmony("com.jg224.sharedmap"); _harmony.PatchAll(Assembly.GetExecutingAssembly()); SharedMapCommands.Register(); Core.Modules.SetState(ModuleId, (ModuleRuntimeState)2, "Required server-authoritative map synchronization ready."); Game.isModded = true; ((BaseUnityPlugin)this).Logger.LogInfo((object)"SharedMap 0.5.1 loaded."); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)string.Format("{0} failed to initialize safely: {1}", "SharedMap", ex)); if (Core != null) { Core.Modules.SetState(ModuleId, (ModuleRuntimeState)5, ex.Message); } Shutdown(); throw; } } private void Update() { SharedMapClient.Tick(Time.unscaledTimeAsDouble); SharedMapServer.Tick(Time.unscaledTimeAsDouble); } private void OnDestroy() { Shutdown(); } private void Shutdown() { //IL_00a3: Unknown result type (might be due to invalid IL or missing references) if (_shutDown) { return; } _shutDown = true; SharedMapServer.Shutdown(); SharedMapClient.ResetSession(); SharedMapNetwork.Shutdown(); Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } _harmony = null; for (int num = _registrations.Count - 1; num >= 0; num--) { try { _registrations[num].Dispose(); } catch (Exception ex) { ManualLogSource logger = ((BaseUnityPlugin)this).Logger; if (logger != null) { logger.LogWarning((object)("Registration cleanup failed: " + ex.Message)); } } } _registrations.Clear(); if (Core != null) { Core.Metrics.RemoveOwner(ModuleId); } Core = null; Log = null; } } [HarmonyPatch(typeof(ZRoutedRpc), "RPC_RoutedRPC")] internal static class SharedMapRpcIngress { private const int RoutingHeaderBytes = 40; [HarmonyPrefix] private static bool Prefix(ZRpc rpc, ZPackage pkg) { //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_00cc: 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) if (pkg == null || pkg.Size() - pkg.GetPos() < 40) { return true; } int pos = pkg.GetPos(); try { pkg.ReadLong(); long claimedSender = pkg.ReadLong(); long target = pkg.ReadLong(); ZDOID val = pkg.ReadZDOID(); if (!SharedMapNetwork.TryGetRpcDirection(pkg.ReadInt(), out var serverToClient)) { return true; } if (!SharedMapNetwork.HasBoundedRoutedParameters(pkg)) { return false; } ZNet instance = ZNet.instance; PlayerIdentity val2 = default(PlayerIdentity); if ((Object)(object)instance == (Object)null || SharedMapPlugin.Core == null || !SharedMapPlugin.Core.Identity.TryGetByConnection((object)rpc, ref val2)) { return false; } return SharedMapIngressPolicy.Allows(serverPeer: (instance.IsServer() ? null : instance.GetServerPeer())?.m_uid ?? 0, isServer: instance.IsServer(), serverToClient: serverToClient, connectionPeer: val2.PeerId, claimedSender: claimedSender, target: target, localPeer: ZNet.GetUID(), hasTargetObject: val != ZDOID.None); } finally { pkg.SetPos(pos); } } } internal static class SharedMapPayloadBounds { internal static bool Allows(int declared, int remaining, int maximum) { if (declared >= 0 && declared <= remaining) { return declared <= maximum; } return false; } } internal static class SharedMapIngressPolicy { internal static bool Allows(bool isServer, bool serverToClient, long connectionPeer, long claimedSender, long target, long localPeer, long serverPeer, bool hasTargetObject) { if (connectionPeer == 0L || connectionPeer != claimedSender || hasTargetObject || target != localPeer) { return false; } if (!isServer) { if (serverToClient) { return connectionPeer == serverPeer; } return false; } return !serverToClient; } } internal sealed class SharedMapPlayerClaims { private readonly Dictionary _claims = new Dictionary(); internal bool Accept(long peer, long player, long hostPlayer) { if (peer == 0L || player == 0L || player == hostPlayer) { return false; } if (_claims.TryGetValue(peer, out var value)) { return value == player; } foreach (long value2 in _claims.Values) { if (value2 == player) { return false; } } _claims.Add(peer, player); return true; } internal void Remove(long peer) { _claims.Remove(peer); } internal void Clear() { _claims.Clear(); } } internal sealed class MarkerRequestBudget { internal const int PerPlayerMarkerLimit = 200; private readonly Dictionary> _requests = new Dictionary>(); internal bool Accept(long peer, double now) { if (double.IsNaN(now) || double.IsInfinity(now)) { return false; } if (!_requests.TryGetValue(peer, out var value)) { _requests.Add(peer, value = new Queue()); } while (value.Count > 0 && now - value.Peek() >= 10.0) { value.Dequeue(); } if (value.Count >= 20) { return false; } value.Enqueue(now); return true; } internal void Remove(long peer) { _requests.Remove(peer); } internal void Clear() { _requests.Clear(); } internal static bool CanManage(long owner, long actor, bool administrator) { return owner == actor || administrator; } } internal static class SharedMapRecovery { internal static bool Load(string path, Action loader, out string status) { if (!File.Exists(path) && !File.Exists(path + ".bak")) { status = "New world store."; return true; } Exception ex2; try { loader(path); status = "Loaded primary store."; return true; } catch (Exception ex) { ex2 = ex; } string text = path + ".recovering"; try { loader(path + ".bak"); File.Copy(path + ".bak", text, overwrite: true); if (File.Exists(path)) { File.Replace(text, path, path + ".corrupt", ignoreMetadataErrors: true); } else { File.Move(text, path); } status = "Recovered validated backup; damaged primary retained as .corrupt."; return true; } catch (Exception ex3) { status = "Store is read-only: " + ex2.Message + "; backup recovery: " + ex3.Message; return false; } finally { try { if (File.Exists(text)) { File.Delete(text); } } catch (IOException) { } } } } internal static class ExplorationMerge { internal static IEnumerable> Merge(byte[] target, byte[] incoming, int batchSize) { if (target == null || incoming == null || target.Length != incoming.Length) { throw new ArgumentException("Exploration dimensions must match."); } if (batchSize <= 0) { throw new ArgumentOutOfRangeException("batchSize"); } List list = new List(batchSize); for (int index = 0; index < target.Length; index++) { int added = incoming[index] & ~target[index]; target[index] |= incoming[index]; for (int bit = 0; bit < 8; bit++) { if ((added & (1 << bit)) != 0) { list.Add(index * 8 + bit); if (list.Count == batchSize) { yield return list; list = new List(batchSize); } } } } if (list.Count != 0) { yield return list; } } } internal static class SharedMapServer { private sealed class RequestContext { internal long PeerUid { get; } internal long PlayerId { get; } internal string PlayerName { get; } internal bool IsHost { get; } internal string AccountKey { get; } internal bool IsAdmin { get; } internal RequestContext(long peerUid, long playerId, string playerName, bool isHost, string accountKey, bool isAdmin) { PeerUid = peerUid; PlayerId = playerId; PlayerName = (string.IsNullOrWhiteSpace(playerName) ? "Unknown player" : playerName); IsHost = isHost; AccountKey = accountKey; IsAdmin = isAdmin; } } private sealed class PendingParticipation { internal int MapSize { get; } internal byte[] Snapshot { get; } internal double ExpiresAt { get; } internal PendingParticipation(int mapSize, byte[] snapshot, double expiresAt) { MapSize = mapSize; Snapshot = (byte[])snapshot.Clone(); ExpiresAt = expiresAt; } } private const int MaximumMarkers = 5000; private const double SaveIntervalSeconds = 30.0; private const double PendingParticipationTimeoutSeconds = 30.0; private const double PendingParticipationPollSeconds = 0.25; private static readonly HashSet RemoteParticipants = new HashSet(); private static readonly Dictionary PendingParticipations = new Dictionary(); private static readonly List PendingPeerScratch = new List(); private static readonly MarkerRequestBudget MarkerBudget = new MarkerRequestBudget(); private static readonly SharedMapPlayerClaims PlayerClaims = new SharedMapPlayerClaims(); private static readonly Dictionary Characters = new Dictionary(); private static readonly Dictionary Markers = new Dictionary(StringComparer.Ordinal); private static long _worldUid; private static int _mapSize; private static byte[] _exploration = Array.Empty(); private static long _revision; private static bool _hostParticipating; private static bool _dirty; private static bool _storeReadOnly; private static double _nextSave; private static double _nextPendingParticipationPoll; internal static void LoadForCurrentWorld() { ZNet instance = ZNet.instance; if (!((Object)(object)instance == (Object)null) && instance.IsServer()) { long worldUID = instance.GetWorldUID(); if (_worldUid != worldUID || worldUID == 0L) { ClearMemory(); _worldUid = worldUID; _nextSave = Time.unscaledTimeAsDouble + 30.0; Load(); } } } internal static void Tick(double now) { ResolvePendingParticipations(now); if (_dirty && _worldUid != 0L && !(now < _nextSave)) { ZNet instance = ZNet.instance; if (!((Object)(object)instance == (Object)null) && instance.IsServer()) { Save(); _nextSave = now + 30.0; } } } internal static void SetRemoteParticipation(long peerUid, bool enabled, int mapSize, byte[] snapshot) { EnsureWorldLoaded(); string error; RequestContext context; if (!enabled) { PendingParticipations.Remove(peerUid); RemoteParticipants.Remove(peerUid); } else if (!TryValidateMap(mapSize, snapshot, out error)) { PendingParticipations.Remove(peerUid); SharedMapNetwork.SendNotice(peerUid, error); } else if (!TryResolveRemote(peerUid, out context)) { if (!RejectConflictingAccount(peerUid)) { PendingParticipations[peerUid] = new PendingParticipation(mapSize, snapshot, Time.unscaledTimeAsDouble + 30.0); ManualLogSource log = SharedMapPlugin.Log; if (log != null) { log.LogInfo((object)$"Deferred SharedMap participation for peer {peerUid} until its player identity is ready."); } } } else { PendingParticipations.Remove(peerUid); AcceptRemoteParticipation(peerUid, context, mapSize, snapshot); } } private static void AcceptRemoteParticipation(long peerUid, RequestContext context, int mapSize, byte[] snapshot) { if (!EnsureAccountRegistered(context)) { return; } if (!TryAcceptMap(mapSize, snapshot, out var error)) { SharedMapNetwork.SendNotice(peerUid, error); return; } bool num = RemoteParticipants.Add(peerUid); MergeJoiningSnapshot(snapshot, peerUid, joiningHost: false); SendJoiningSnapshot(peerUid, host: false); if (num) { ManualLogSource log = SharedMapPlugin.Log; if (log != null) { log.LogInfo((object)$"{context.PlayerName} opted into SharedMap; {RemoteParticipants.Count + (_hostParticipating ? 1 : 0)} participant(s)."); } } } internal static void SetHostParticipation(bool enabled, int mapSize, byte[] snapshot) { EnsureWorldLoaded(); RequestContext context; if (!enabled) { _hostParticipating = false; } else if (TryResolveHost(out context) && EnsureAccountRegistered(context)) { if (!TryAcceptMap(mapSize, snapshot, out var error)) { SharedMapClient.ShowMessage(error); return; } _hostParticipating = true; MergeJoiningSnapshot(snapshot, 0L, joiningHost: true); SendJoiningSnapshot(0L, host: true); } } internal static void ReceiveRemoteDelta(long peerUid, int mapSize, IReadOnlyList indices) { if (RemoteParticipants.Contains(peerUid) && TryResolveRemote(peerUid, out var _)) { ReceiveDelta(mapSize, indices); } } internal static void ReceiveHostDelta(int mapSize, IReadOnlyList indices) { if (_hostParticipating) { ReceiveDelta(mapSize, indices); } } internal static void RequestCreateRemote(long peerUid, PinType type, Vector3 position, string name) { //IL_0011: 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) if (TryResolveParticipatingRemote(peerUid, "marker creation", out var context)) { CreateMarker(context, type, position, name); } } internal static void RequestCreateHost(PinType type, Vector3 position, string name) { //IL_0012: 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) if (_hostParticipating && TryResolveHost(out var context)) { CreateMarker(context, type, position, name); } } internal static void RequestCheckedRemote(long peerUid, string markerId, bool isChecked) { if (TryResolveParticipatingRemote(peerUid, "marker X update", out var context) && CanWriteMarker(context)) { SetChecked(markerId, isChecked); } } internal static void RequestCheckedHost(string markerId, bool isChecked) { if (_hostParticipating && TryResolveHost(out var context) && CanWriteMarker(context)) { SetChecked(markerId, isChecked); } } internal static void RequestDeleteRemote(long peerUid, string markerId) { if (TryResolveParticipatingRemote(peerUid, "marker deletion", out var context)) { DeleteMarker(context, markerId); } } internal static void RequestDeleteHost(string markerId) { if (_hostParticipating && TryResolveHost(out var context)) { DeleteMarker(context, markerId); } } internal static void RemoveParticipant(long peerUid) { SharedMapNetwork.ForgetPeer(peerUid); PendingParticipations.Remove(peerUid); RemoteParticipants.Remove(peerUid); MarkerBudget.Remove(peerUid); PlayerClaims.Remove(peerUid); } internal static void Shutdown() { if (_dirty && _worldUid != 0L) { Save(); } ClearMemory(); } private static void ReceiveDelta(int mapSize, IReadOnlyList indices) { EnsureWorldLoaded(); if (_storeReadOnly || mapSize != _mapSize || indices == null || indices.Count == 0) { return; } int num = checked(_mapSize * _mapSize); List list = new List(indices.Count); for (int i = 0; i < indices.Count; i++) { int num2 = indices[i]; if (num2 >= 0 && num2 < num) { int num3 = num2 >> 3; byte b = (byte)(1 << (num2 & 7)); if ((_exploration[num3] & b) == 0) { _exploration[num3] |= b; list.Add(num2); } } } if (list.Count != 0) { _dirty = true; if (_hostParticipating) { SharedMapClient.ReceiveExplorationDelta(_worldUid, _mapSize, list); } SharedMapNetwork.BroadcastExplorationDelta(RemoteParticipants, _worldUid, _mapSize, list); } } private static void CreateMarker(RequestContext context, PinType type, Vector3 position, string name) { //IL_0037: 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_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Unknown result type (might be due to invalid IL or missing references) //IL_0108: 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_010f: Unknown result type (might be due to invalid IL or missing references) if (CanWriteMarker(context)) { if (!Characters.TryGetValue(context.PlayerId, out var value) || value != context.AccountKey) { SendNotice(context, "This character has legacy markers. A server administrator must bind its owner ID before it can create public markers."); return; } if (!IsPublicMarkerType(type) || !IsFinite(position) || Math.Abs(position.x) > 20000f || Math.Abs(position.z) > 20000f) { SendNotice(context, "That public marker is invalid."); return; } if (!SharedMapOwnership.CanCreateMarker(Markers.Values.Select((PublicMarker marker) => marker.OwnerAccountKey), context.AccountKey)) { SendNotice(context, "The public-marker limit has been reached (200 per account, 5000 per world)."); return; } PublicMarker publicMarker = new PublicMarker { Id = Guid.NewGuid().ToString("N"), OwnerPlayerId = context.PlayerId, OwnerAccountKey = context.AccountKey, OwnerName = Bound(context.PlayerName, 64), Position = position, Type = type, Name = SanitizeName(name), Checked = false, Revision = NextRevision() }; Markers.Add(publicMarker.Id, publicMarker); _dirty = true; BroadcastMarker(publicMarker); } } private static void SetChecked(string markerId, bool isChecked) { if (!string.IsNullOrEmpty(markerId) && Markers.TryGetValue(markerId, out var value) && value.Checked != isChecked) { value.Checked = isChecked; value.Revision = NextRevision(); _dirty = true; BroadcastMarker(value); } } private static void DeleteMarker(RequestContext context, string markerId) { if (!CanWriteMarker(context) || string.IsNullOrEmpty(markerId) || !Markers.TryGetValue(markerId, out var value)) { return; } if (!SharedMapOwnership.CanManage(value.OwnerAccountKey, context.AccountKey, context.IsAdmin)) { SendNotice(context, "Only " + value.OwnerName + "'s authenticated account or a server administrator can delete this public marker."); BroadcastMarker(value); return; } Markers.Remove(markerId); _dirty = true; if (_hostParticipating) { SharedMapClient.RemoveMarker(markerId); } SharedMapNetwork.BroadcastMarkerRemoval(RemoteParticipants, markerId, NextRevision()); } private static void BroadcastMarker(PublicMarker marker) { if (_hostParticipating) { SharedMapClient.UpsertMarker(marker.Copy()); } SharedMapNetwork.BroadcastMarker(RemoteParticipants, marker); } internal static bool TrySendResync(long peerUid) { if (!RemoteParticipants.Contains(peerUid) || !TryResolveRemote(peerUid, out var _)) { return false; } return SendJoiningSnapshot(peerUid, host: false); } private static bool SendJoiningSnapshot(long peerUid, bool host) { List markers = (from marker in Markers.Values.OrderBy((PublicMarker marker) => marker.Id, StringComparer.Ordinal) select marker.Copy()).ToList(); byte[] exploration = (byte[])_exploration.Clone(); if (host) { SharedMapClient.ReceiveSnapshot(_worldUid, _mapSize, exploration, markers); return true; } return SharedMapNetwork.BroadcastSnapshot(new long[1] { peerUid }, _worldUid, _mapSize, exploration, markers); } private static bool TryValidateMap(int mapSize, byte[] snapshot, out string error) { error = string.Empty; if (mapSize < 256 || mapSize > 4096 || snapshot == null || snapshot.Length != MapAccess.PackedLength(mapSize)) { error = "SharedMap rejected an incompatible exploration snapshot."; return false; } if (_mapSize != 0 && (_mapSize != mapSize || _exploration.Length != snapshot.Length)) { error = $"SharedMap map-size mismatch (server {_mapSize}, client {mapSize})."; return false; } return true; } private static bool TryAcceptMap(int mapSize, byte[] snapshot, out string error) { if (_storeReadOnly) { error = "SharedMap storage needs administrator recovery; writes are paused."; return false; } if (!TryValidateMap(mapSize, snapshot, out error)) { return false; } if (_mapSize != 0) { return true; } _mapSize = mapSize; _exploration = new byte[snapshot.Length]; _dirty = true; return true; } private static void MergeJoiningSnapshot(byte[] snapshot, long joiningPeer, bool joiningHost) { long[] peers = RemoteParticipants.Where((long peer) => peer != joiningPeer).ToArray(); if (SharedMapPackedMerge.Merge(_exploration, snapshot)) { _dirty = true; if (_hostParticipating && !joiningHost) { SharedMapClient.ReceiveExplorationSnapshot(_worldUid, _mapSize, _exploration); } SharedMapNetwork.BroadcastExplorationSnapshot(peers, _worldUid, _mapSize, _exploration); } } private static bool CanWriteMarker(RequestContext context) { if (!MarkerBudget.Accept(context.PeerUid, Time.unscaledTimeAsDouble)) { return false; } if (_storeReadOnly || _worldUid == 0L) { SendNotice(context, "SharedMap storage is unavailable or read-only pending recovery."); return false; } return true; } internal static void ManageMarker(long peerUid, bool host, string action, string id, string value, Vector3 position) { //IL_035b: Unknown result type (might be due to invalid IL or missing references) //IL_0364: Unknown result type (might be due to invalid IL or missing references) //IL_0377: Unknown result type (might be due to invalid IL or missing references) //IL_038b: Unknown result type (might be due to invalid IL or missing references) //IL_038d: Unknown result type (might be due to invalid IL or missing references) EnsureWorldLoaded(); RequestContext context; if (host && (Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer()) { long peerUid2 = 0L; Player localPlayer = Player.m_localPlayer; context = new RequestContext(peerUid2, (localPlayer != null) ? localPlayer.GetPlayerID() : 0, "Server administrator", isHost: true, "local-host", isAdmin: true); } else if (!TryResolveRemoteAccount(peerUid, out context)) { return; } if (action == "peers") { if (!context.IsAdmin || !MarkerBudget.Accept(context.PeerUid, Time.unscaledTimeAsDouble)) { return; } { foreach (string item in PeerDescriptions()) { SendNotice(context, item); } return; } } if (action == "list" && context.IsAdmin) { if (!MarkerBudget.Accept(context.PeerUid, Time.unscaledTimeAsDouble)) { return; } { foreach (PublicMarker item2 in Markers.Values.OrderBy((PublicMarker item) => item.Id, StringComparer.Ordinal).Take(context.IsHost ? 5000 : 50)) { SendNotice(context, item2.Id + " | " + item2.Name + " | " + item2.OwnerName + " (" + item2.OwnerPlayerId + ")" + ((item2.OwnerAccountKey.Length == 0) ? " | LEGACY UNBOUND" : string.Empty)); } return; } } if (action == "bind") { if (CanWriteMarker(context)) { BindLegacy(context, id, value); } } else { if ((!context.IsAdmin && !TryResolveParticipatingRemote(peerUid, "marker edit", out context)) || !CanWriteMarker(context)) { return; } bool isAdmin = context.IsAdmin; if (action == "cleanup") { if (!isAdmin || !long.TryParse(id, out var owner)) { SendNotice(context, "Cleanup requires a server administrator and player ID."); return; } PublicMarker[] array = Markers.Values.Where((PublicMarker marker) => marker.OwnerPlayerId == owner).ToArray(); for (int num = 0; num < array.Length; num++) { RemoveMarker(array[num].Id); } SendNotice(context, "Removed public markers for player " + owner + "."); return; } if (!Markers.TryGetValue(id ?? string.Empty, out var value2)) { SendNotice(context, "Public marker ID not found."); return; } if (!SharedMapOwnership.CanManage(value2.OwnerAccountKey, context.AccountKey, isAdmin)) { SendNotice(context, "Only the creator's authenticated account or a server administrator can edit this marker."); return; } switch (action) { case "delete": RemoveMarker(value2.Id); return; case "rename": value2.Name = SanitizeName(value); break; case "move": if (IsFinite(position) && Math.Abs(position.x) <= 20000f && Math.Abs(position.z) <= 20000f) { value2.Position = position; break; } goto default; default: SendNotice(context, "Invalid marker operation or position."); return; } value2.Revision = NextRevision(); _dirty = true; BroadcastMarker(value2); } } private static void RemoveMarker(string id) { if (Markers.Remove(id)) { _dirty = true; if (_hostParticipating) { SharedMapClient.RemoveMarker(id); } SharedMapNetwork.BroadcastMarkerRemoval(RemoteParticipants, id, NextRevision()); } } private static bool TryResolveParticipatingRemote(long peerUid, string action, out RequestContext context) { context = null; if (RemoteParticipants.Contains(peerUid) && TryResolveRemote(peerUid, out context)) { return true; } if (!MarkerBudget.Accept(peerUid, Time.unscaledTimeAsDouble)) { return false; } SharedMapNetwork.SendNotice(peerUid, "SharedMap is still syncing. Try again in a moment."); ManualLogSource log = SharedMapPlugin.Log; if (log != null) { log.LogWarning((object)$"Rejected SharedMap {action} from peer {peerUid} before participation was ready."); } return false; } private static void ResolvePendingParticipations(double now) { if (PendingParticipations.Count == 0 || now < _nextPendingParticipationPoll) { return; } _nextPendingParticipationPoll = now + 0.25; PendingPeerScratch.Clear(); foreach (long key in PendingParticipations.Keys) { PendingPeerScratch.Add(key); } for (int i = 0; i < PendingPeerScratch.Count; i++) { long num = PendingPeerScratch[i]; if (!PendingParticipations.TryGetValue(num, out var value)) { continue; } if (TryResolveRemote(num, out var context)) { PendingParticipations.Remove(num); AcceptRemoteParticipation(num, context, value.MapSize, value.Snapshot); } else if (!RejectConflictingAccount(num) && !(now < value.ExpiresAt)) { PendingParticipations.Remove(num); SharedMapNetwork.SendNotice(num, "SharedMap could not finish syncing your player identity. It will retry automatically."); ManualLogSource log = SharedMapPlugin.Log; if (log != null) { log.LogWarning((object)$"Expired deferred SharedMap participation for unresolved peer {num}."); } } } PendingPeerScratch.Clear(); } private static bool TryResolveRemote(long peerUid, out RequestContext context) { //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_0053: Unknown result type (might be due to invalid IL or missing references) context = null; if (!TryResolveRemoteAccount(peerUid, out var context2)) { return false; } ZNet instance = ZNet.instance; ZNetPeer val = ((instance != null) ? instance.GetPeer(peerUid) : null); if (val == null || val.m_characterID == ZDOID.None || ZDOMan.instance == null || (Object)(object)ZNetScene.instance == (Object)null) { return false; } ZDO zDO = ZDOMan.instance.GetZDO(val.m_characterID); if (zDO == null || zDO.GetOwner() != val.m_uid) { return false; } GameObject prefab = ZNetScene.instance.GetPrefab(zDO.GetPrefab()); if ((Object)(object)prefab == (Object)null || (Object)(object)prefab.GetComponent() == (Object)null) { return false; } long num = zDO.GetLong(ZDOVars.s_playerID, 0L); long hostPlayer = (((Object)(object)Player.m_localPlayer == (Object)null) ? 0 : Player.m_localPlayer.GetPlayerID()); if (!SharedMapOwnership.TryClaimCharacter(PlayerClaims, Characters, peerUid, num, hostPlayer, context2.AccountKey)) { return false; } string playerName = zDO.GetString(ZDOVars.s_playerName, val.m_playerName ?? string.Empty); context = new RequestContext(peerUid, num, playerName, isHost: false, context2.AccountKey, context2.IsAdmin); return true; } private static bool RejectConflictingAccount(long peerUid) { //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_003c: Unknown result type (might be due to invalid IL or missing references) if (!TryResolveRemoteAccount(peerUid, out var context)) { return false; } ZNetPeer peer = ZNet.instance.GetPeer(peerUid); if (peer == null || peer.m_characterID == ZDOID.None || ZDOMan.instance == null) { return false; } ZDO zDO = ZDOMan.instance.GetZDO(peer.m_characterID); if (zDO == null || zDO.GetOwner() != peerUid || !Characters.TryGetValue(zDO.GetLong(ZDOVars.s_playerID, 0L), out var value) || value.Length == 0 || value == context.AccountKey) { return false; } PendingParticipations.Remove(peerUid); SharedMapNetwork.SendNotice(peerUid, "This SharedMap character ID belongs to a different authenticated account. Contact a server administrator; retrying cannot change its owner."); return true; } private static bool TryResolveRemoteAccount(long peerUid, out RequestContext context) { context = null; ZNet instance = ZNet.instance; ZNetPeer val = ((instance != null) ? instance.GetPeer(peerUid) : null); PlayerIdentity val2 = default(PlayerIdentity); if ((Object)(object)instance == (Object)null || !instance.IsServer() || val?.m_rpc == null || val.m_socket == null || SharedMapPlugin.Core == null || !SharedMapPlugin.Core.Identity.TryGetByConnection((object)val.m_rpc, ref val2) || !val2.IsResolved || val2.PeerId != peerUid || peerUid == 0L || val2.IsServer) { return false; } string name = ((object)val.m_socket).GetType().Name; string text = ((name == "ZPlayFabSocket") ? val.m_socket.GetEndPointString() : val2.HostName); if (!SharedMapOwnership.TryAccountKey(name, text, out var key)) { return false; } bool isAdmin = SharedMapOwnership.IsAdministrator(name, val2.IsAdmin, name == "ZPlayFabSocket" && instance.IsAdmin(text)); context = new RequestContext(peerUid, 0L, val2.DisplayName, isHost: false, key, isAdmin); return true; } private static bool TryResolveHost(out RequestContext context) { context = null; Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null || localPlayer.GetPlayerID() == 0L) { return false; } context = new RequestContext(0L, localPlayer.GetPlayerID(), localPlayer.GetPlayerName(), isHost: true, "local-host", isAdmin: true); return true; } private static void SendNotice(RequestContext context, string message) { if (context.IsHost) { if ((Object)(object)Player.m_localPlayer != (Object)null) { SharedMapClient.ShowMessage(message); return; } ManualLogSource log = SharedMapPlugin.Log; if (log != null) { log.LogInfo((object)message); } } else { SharedMapNetwork.SendNotice(context.PeerUid, message); } } private static void EnsureWorldLoaded() { if (_worldUid == 0L) { LoadForCurrentWorld(); } } private static bool EnsureAccountRegistered(RequestContext context) { if (_storeReadOnly || _worldUid == 0L) { SendNotice(context, "SharedMap storage needs administrator recovery; writes and participation are paused."); return false; } SharedMapWorldDocument sharedMapWorldDocument = CaptureDocument(); if (!SharedMapOwnership.TryRegister(sharedMapWorldDocument.Characters, context.PlayerId, context.AccountKey, out var changed, out var legacy, out var error)) { SendNotice(context, error); return false; } if (changed) { if (!CommitOwnership(sharedMapWorldDocument)) { SendNotice(context, "SharedMap could not safely persist account ownership; participation is paused until server recovery."); return false; } Characters.Add(context.PlayerId, context.AccountKey); } if (legacy) { SendNotice(context, "Your legacy public markers are preserved. Ask a server administrator to bind owner ID " + context.PlayerId + " to your connected account before creating or editing your markers."); } return true; } private static IEnumerable PeerDescriptions() { ZNet znet = ZNet.instance; if ((Object)(object)znet == (Object)null) { yield break; } bool found = false; if ((Object)(object)Player.m_localPlayer != (Object)null) { found = true; yield return "peer=0 | " + Bound(Player.m_localPlayer.GetPlayerName(), 64) + " | authenticated=local-host"; } foreach (ZNetPeer connectedPeer in znet.GetConnectedPeers()) { if (TryResolveRemoteAccount(connectedPeer.m_uid, out var context)) { found = true; string text = ((((object)connectedPeer.m_socket).GetType().Name == "ZPlayFabSocket") ? connectedPeer.m_socket.GetEndPointString() : connectedPeer.m_socket.GetHostName()); yield return "peer=" + connectedPeer.m_uid + " | " + Bound(context.PlayerName, 64) + " | authenticated=" + text; } } if (!found) { yield return "No authenticated remote SharedMap accounts are connected."; } } private static void BindLegacy(RequestContext administrator, string playerText, string peerText) { //IL_0161: Unknown result type (might be due to invalid IL or missing references) //IL_0166: Unknown result type (might be due to invalid IL or missing references) //IL_0180: Unknown result type (might be due to invalid IL or missing references) if (!administrator.IsAdmin || !long.TryParse(playerText, NumberStyles.Integer, CultureInfo.InvariantCulture, out var result) || !long.TryParse(peerText, NumberStyles.Integer, CultureInfo.InvariantCulture, out var result2)) { SendNotice(administrator, "Use sharedmap bind as a server administrator; get peer UIDs with sharedmap peers."); return; } if ((result2 == 0L) ? (!TryResolveHost(out var context)) : (!TryResolveRemoteAccount(result2, out context))) { SendNotice(administrator, "That authenticated account is no longer connected. Run sharedmap peers again."); return; } SharedMapWorldDocument sharedMapWorldDocument = CaptureDocument(); if (!SharedMapOwnership.TryBindLegacy(sharedMapWorldDocument.Characters, result, context.AccountKey, administrator.IsAdmin, out var error)) { SendNotice(administrator, error); return; } foreach (SharedMapStoredMarker marker in sharedMapWorldDocument.Markers) { if (marker.OwnerPlayerId == result) { marker.OwnerAccountKey = context.AccountKey; } } if (!CommitOwnership(sharedMapWorldDocument)) { SendNotice(administrator, "Ownership was not acknowledged: the primary and backup could not both be saved. Storage is paused; recover while stopped and restart."); return; } Characters[result] = context.AccountKey; foreach (PublicMarker value in Markers.Values) { if (value.OwnerPlayerId == result) { value.OwnerAccountKey = context.AccountKey; } } foreach (ZNetPeer connectedPeer in ZNet.instance.GetConnectedPeers()) { if (!(connectedPeer.m_characterID == ZDOID.None) && ZDOMan.instance != null) { ZDO zDO = ZDOMan.instance.GetZDO(connectedPeer.m_characterID); if (zDO != null && zDO.GetLong(ZDOVars.s_playerID, 0L) == result && TryResolveRemoteAccount(connectedPeer.m_uid, out var context2) && !(context2.AccountKey == context.AccountKey)) { RemoveParticipant(connectedPeer.m_uid); SharedMapNetwork.SendNotice(connectedPeer.m_uid, "That character's legacy map ownership was bound to a different authenticated account."); } } } SendNotice(administrator, "Bound legacy SharedMap owner " + result + " to the authenticated account currently connected as " + context.PlayerName + " (peer " + result2 + ")."); ManualLogSource log = SharedMapPlugin.Log; if (log != null) { log.LogInfo((object)("SharedMap administrator peer " + administrator.PeerUid + " bound legacy owner " + result + " to authenticated peer " + result2 + ".")); } } private static bool CommitOwnership(SharedMapWorldDocument candidate) { try { SharedMapStorePersistence.Save(StorePath(), candidate, ownershipCommit: true); _dirty = false; return true; } catch (Exception ex) { _storeReadOnly = true; ManualLogSource log = SharedMapPlugin.Log; if (log != null) { log.LogError((object)("SharedMap ownership commit failed; writes and new participation are paused: " + ex.Message)); } return false; } } private static long NextRevision() { _revision = Math.Max(_revision + 1, DateTime.UtcNow.Ticks); return _revision; } private static bool IsPublicMarkerType(PinType type) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Invalid comparison between Unknown and I4 //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Invalid comparison between Unknown and I4 //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Invalid comparison between Unknown and I4 //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Invalid comparison between Unknown and I4 if ((int)type != 0 && (int)type != 1 && (int)type != 2 && (int)type != 3) { return (int)type == 6; } return true; } private static bool IsFinite(Vector3 value) { //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_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) if (!float.IsNaN(value.x) && !float.IsInfinity(value.x) && !float.IsNaN(value.y) && !float.IsInfinity(value.y) && !float.IsNaN(value.z)) { return !float.IsInfinity(value.z); } return false; } private static string SanitizeName(string value) { return Bound((value ?? string.Empty).Replace('$', ' ').Replace('<', ' ').Replace('>', ' '), 64); } private static string Bound(string value, int maximum) { value = value ?? string.Empty; if (value.Length > maximum) { return value.Substring(0, maximum); } return value; } private static string StorePath() { return Path.Combine(Paths.ConfigPath, "SharedMap", "world-" + _worldUid.ToString(CultureInfo.InvariantCulture) + ".bin"); } private static void Load() { //IL_015b: Unknown result type (might be due to invalid IL or missing references) //IL_0160: Unknown result type (might be due to invalid IL or missing references) //IL_016d: Unknown result type (might be due to invalid IL or missing references) string path = StorePath(); SharedMapWorldDocument loaded = null; _storeReadOnly = !SharedMapRecovery.Load(path, delegate(string candidate) { loaded = SharedMapWorldStore.Read(candidate, _worldUid); }, out var status); if (_storeReadOnly) { ManualLogSource log = SharedMapPlugin.Log; if (log != null) { log.LogError((object)status); } } else if (loaded == null) { ManualLogSource log2 = SharedMapPlugin.Log; if (log2 != null) { log2.LogInfo((object)status); } } else { if (!CommitOwnership(loaded)) { return; } _mapSize = loaded.MapSize; _exploration = loaded.Exploration; Characters.Clear(); foreach (KeyValuePair character in loaded.Characters) { Characters.Add(character.Key, character.Value); } Markers.Clear(); foreach (SharedMapStoredMarker marker in loaded.Markers) { PublicMarker publicMarker = new PublicMarker { Id = marker.Id, OwnerPlayerId = marker.OwnerPlayerId, OwnerAccountKey = marker.OwnerAccountKey, OwnerName = marker.OwnerName, Position = new Vector3(marker.X, marker.Y, marker.Z), Type = (PinType)marker.Type, Name = marker.Name, Checked = marker.Checked, Revision = marker.Revision }; Markers.Add(publicMarker.Id, publicMarker); _revision = Math.Max(_revision, publicMarker.Revision); } _dirty = false; ManualLogSource log3 = SharedMapPlugin.Log; if (log3 != null) { log3.LogInfo((object)(status + " Loaded SharedMap world " + _worldUid + ": " + _mapSize + "px map, " + Markers.Count + " marker(s), " + Characters.Count + " registered or reserved character(s).")); } if (loaded.SourceVersion == 1) { ManualLogSource log4 = SharedMapPlugin.Log; if (log4 != null) { log4.LogWarning((object)"Migrated SharedMap store to v2; original preserved as .v1.bak. Legacy markers remain visible, but creator rights require an administrator's sharedmap bind command."); } } } } private static SharedMapWorldDocument CaptureDocument() { //IL_0104: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Expected I4, but got Unknown SharedMapWorldDocument sharedMapWorldDocument = new SharedMapWorldDocument { WorldUid = _worldUid, MapSize = _mapSize, Exploration = _exploration }; foreach (KeyValuePair character in Characters) { sharedMapWorldDocument.Characters.Add(character.Key, character.Value); } foreach (PublicMarker value in Markers.Values) { sharedMapWorldDocument.Markers.Add(new SharedMapStoredMarker { Id = value.Id, OwnerPlayerId = value.OwnerPlayerId, OwnerAccountKey = value.OwnerAccountKey, OwnerName = value.OwnerName, X = value.Position.x, Y = value.Position.y, Z = value.Position.z, Type = (int)value.Type, Name = value.Name, Checked = value.Checked, Revision = value.Revision }); } return sharedMapWorldDocument; } private static void Save() { if (_storeReadOnly) { return; } try { SharedMapStorePersistence.Save(StorePath(), CaptureDocument(), ownershipCommit: false); _dirty = false; } catch (Exception ex) { ManualLogSource log = SharedMapPlugin.Log; if (log != null) { log.LogError((object)("Could not save SharedMap data '" + StorePath() + "': " + ex.Message)); } } } private static void ClearMemory() { SharedMapNetwork.ResetServerTransfers(); PendingParticipations.Clear(); PendingPeerScratch.Clear(); RemoteParticipants.Clear(); Markers.Clear(); MarkerBudget.Clear(); PlayerClaims.Clear(); Characters.Clear(); _worldUid = 0L; _mapSize = 0; _exploration = Array.Empty(); _revision = 0L; _hostParticipating = false; _dirty = false; _storeReadOnly = false; _nextSave = 0.0; _nextPendingParticipationPoll = 0.0; } } internal enum SharedMapTransferResult { Accepted, Duplicate, Completed } internal sealed class SharedMapTransferChunk { internal long TransferId { get; } internal int TotalLength { get; } internal int ChunkCount { get; } internal int ChunkIndex { get; } internal byte[] Data { get; } internal SharedMapTransferChunk(long transferId, int totalLength, int chunkCount, int chunkIndex, byte[] data) { TransferId = transferId; TotalLength = totalLength; ChunkCount = chunkCount; ChunkIndex = chunkIndex; Data = data ?? throw new ArgumentNullException("data"); } } internal sealed class SharedMapTransfer { internal const int ChunkSize = 32768; internal const int MaximumPayloadBytes = 8388608; internal const int MaximumChunkCount = 256; internal const double TimeoutSeconds = 120.0; internal const double MaximumLifetimeSeconds = 1800.0; private byte[][] _chunks; private long _activeTransferId; private int _expectedLength; private int _expectedChunkCount; private int _receivedChunkCount; private double _lastActivity; private double _startedAt; private long _lastCompletedTransferId; private long _highestTransferId; private int _lastCompletedLength; private int _lastCompletedChunkCount; internal bool HasActiveTransfer => _chunks != null; internal long ActiveTransferId => _activeTransferId; internal int ExpectedLength => _expectedLength; internal int ExpectedChunkCount => _expectedChunkCount; internal int ReceivedChunkCount => _receivedChunkCount; internal double LastActivity => _lastActivity; internal static IReadOnlyList Split(long transferId, byte[] payload) { if (transferId <= 0) { throw new ArgumentOutOfRangeException("transferId"); } if (payload == null) { throw new ArgumentNullException("payload"); } if (payload.Length == 0 || payload.Length > 8388608) { throw new ArgumentOutOfRangeException("payload", $"SharedMap transfer payload must contain 1 to {8388608} bytes."); } int num = ExpectedCount(payload.Length); List list = new List(num); for (int i = 0; i < num; i++) { int num2 = checked(i * 32768); int num3 = Math.Min(32768, payload.Length - num2); byte[] array = new byte[num3]; Buffer.BlockCopy(payload, num2, array, 0, num3); list.Add(new SharedMapTransferChunk(transferId, payload.Length, num, i, array)); } return list; } internal SharedMapTransferResult Accept(long transferId, int totalLength, int chunkCount, int chunkIndex, byte[] data, double now, out byte[] payload) { payload = null; ValidateEnvelope(transferId, totalLength, chunkCount, chunkIndex, data, now); if (transferId < _highestTransferId) { return SharedMapTransferResult.Duplicate; } if (transferId == _lastCompletedTransferId) { if (totalLength != _lastCompletedLength || chunkCount != _lastCompletedChunkCount) { throw new InvalidOperationException("A completed SharedMap transfer ID was reused."); } return SharedMapTransferResult.Duplicate; } if (!HasActiveTransfer || transferId != _activeTransferId) { Begin(transferId, totalLength, chunkCount, now); } else if (totalLength != _expectedLength || chunkCount != _expectedChunkCount) { throw new InvalidOperationException("SharedMap transfer metadata changed before completion."); } byte[] array = _chunks[chunkIndex]; if (array != null) { if (!Equal(array, data)) { ResetActive(); throw new InvalidOperationException("SharedMap transfer contains a conflicting duplicate chunk."); } return SharedMapTransferResult.Duplicate; } byte[] array2 = new byte[data.Length]; Buffer.BlockCopy(data, 0, array2, 0, data.Length); _chunks[chunkIndex] = array2; _receivedChunkCount++; _lastActivity = now; if (_receivedChunkCount != _expectedChunkCount) { return SharedMapTransferResult.Accepted; } payload = Assemble(); _lastCompletedTransferId = _activeTransferId; _lastCompletedLength = _expectedLength; _lastCompletedChunkCount = _expectedChunkCount; ResetActive(); return SharedMapTransferResult.Completed; } internal bool Expire(double now) { if (!HasActiveTransfer || double.IsNaN(now) || double.IsInfinity(now) || (now - _lastActivity < 120.0 && now - _startedAt < 1800.0)) { return false; } ResetActive(); return true; } internal void Reset() { ResetActive(); _lastCompletedTransferId = 0L; _highestTransferId = 0L; _lastCompletedLength = 0; _lastCompletedChunkCount = 0; } private static void ValidateEnvelope(long transferId, int totalLength, int chunkCount, int chunkIndex, byte[] data, double now) { if (transferId <= 0) { throw new InvalidOperationException("Invalid SharedMap transfer ID."); } if (totalLength <= 0 || totalLength > 8388608) { throw new InvalidOperationException("Invalid SharedMap transfer length."); } int num = ExpectedCount(totalLength); if (chunkCount != num || chunkCount > 256) { throw new InvalidOperationException("Invalid SharedMap transfer chunk count."); } if (chunkIndex < 0 || chunkIndex >= chunkCount) { throw new InvalidOperationException("Invalid SharedMap transfer chunk index."); } if (data == null || data.Length != ExpectedChunkLength(totalLength, chunkIndex)) { throw new InvalidOperationException("Invalid SharedMap transfer chunk length."); } if (double.IsNaN(now) || double.IsInfinity(now)) { throw new InvalidOperationException("Invalid SharedMap transfer timestamp."); } } private static int ExpectedCount(int totalLength) { return checked(totalLength + 32768 - 1) / 32768; } private static int ExpectedChunkLength(int totalLength, int chunkIndex) { return Math.Min(32768, totalLength - checked(chunkIndex * 32768)); } private void Begin(long transferId, int totalLength, int chunkCount, double now) { _activeTransferId = transferId; _highestTransferId = transferId; _expectedLength = totalLength; _expectedChunkCount = chunkCount; _receivedChunkCount = 0; _lastActivity = now; _startedAt = now; _chunks = new byte[chunkCount][]; } private byte[] Assemble() { byte[] array = new byte[_expectedLength]; int num = 0; for (int i = 0; i < _chunks.Length; i++) { byte[] array2 = _chunks[i]; if (array2 == null) { throw new InvalidOperationException("SharedMap transfer is incomplete."); } Buffer.BlockCopy(array2, 0, array, num, array2.Length); num += array2.Length; } if (num != array.Length) { throw new InvalidOperationException("SharedMap transfer length changed during assembly."); } return array; } private void ResetActive() { _chunks = null; _activeTransferId = 0L; _expectedLength = 0; _expectedChunkCount = 0; _receivedChunkCount = 0; _lastActivity = 0.0; _startedAt = 0.0; } private static bool Equal(byte[] left, byte[] right) { if (left.Length != right.Length) { return false; } for (int i = 0; i < left.Length; i++) { if (left[i] != right[i]) { return false; } } return true; } } internal sealed class SharedMapOutboundMessage { internal const int FramingAllowance = 128; internal string Method { get; } internal byte[] Payload { get; } internal long TransferId { get; } internal bool Participation { get; } internal int FrameCount { get; } internal int Cost { get; } internal SharedMapOutboundMessage(string method, byte[] payload, long transferId = 0L, bool participation = false) { Method = method ?? throw new ArgumentNullException("method"); Payload = payload ?? throw new ArgumentNullException("payload"); if (payload.Length == 0 || payload.Length > ((transferId > 0) ? 8388608 : 131072)) { throw new ArgumentOutOfRangeException("payload"); } TransferId = transferId; Participation = participation; FrameCount = ((transferId <= 0) ? 1 : ((payload.Length + 32768 - 1) / 32768)); Cost = checked(payload.Length + FrameCount * 128); } } internal readonly struct SharedMapOutboundFrame { internal SharedMapOutboundMessage Message { get; } internal int Index { get; } internal int Offset { get; } internal int Length { get; } internal int Cost => Length + 128; internal SharedMapOutboundFrame(SharedMapOutboundMessage message, int index) { Message = message; Index = index; Offset = ((message.TransferId > 0) ? (index * 32768) : 0); Length = ((message.TransferId > 0) ? Math.Min(32768, message.Payload.Length - Offset) : message.Payload.Length); } } internal sealed class SharedMapSendQueue { private sealed class Peer { internal readonly Queue Messages = new Queue(); internal int Bytes; internal bool Resync; internal double Tokens = 131200.0; } private sealed class Pending { internal readonly SharedMapOutboundMessage Message; internal int Index; internal Pending(SharedMapOutboundMessage message) { Message = message; } } internal const int MaximumPeerBytes = 8454144; internal const int MaximumGlobalBytes = 33554432; internal const int MaximumPeers = 128; internal const int MaximumSocketBytes = 262144; internal const int PeerBytesPerSecond = 131072; internal const int GlobalBytesPerSecond = 524288; private const int MaximumFramesPerTick = 16; private const int PeerBurst = 131200; private const int GlobalBurst = 262144; private readonly Dictionary _peers = new Dictionary(); private readonly List _order = new List(); private int _cursor; private int _bytes; private double _lastTick; private double _globalTokens = 262144.0; internal int QueuedBytes => _bytes; internal int PeerCount => _peers.Count; internal long[] PeerIds() { return _order.ToArray(); } internal bool HasPending(long id) { if (_peers.TryGetValue(id, out var value)) { return value.Messages.Count != 0; } return false; } internal bool NeedsResync(long id) { if (_peers.TryGetValue(id, out var value)) { return value.Resync; } return false; } internal int PeerQueuedBytes(long id) { if (!_peers.TryGetValue(id, out var value)) { return 0; } return value.Bytes; } internal long[] ResyncPeers() { List list = new List(); foreach (long item in _order) { if (_peers[item].Resync) { list.Add(item); } } return list.ToArray(); } internal bool Enqueue(long id, SharedMapOutboundMessage message, bool authoritativeSnapshot = false, bool resyncOnOverflow = false) { if (id == 0L || message == null) { return false; } if (!_peers.TryGetValue(id, out var value)) { if (_peers.Count >= 128) { return false; } value = new Peer(); _peers.Add(id, value); _order.Add(id); } if (value.Resync && !authoritativeSnapshot) { return false; } int num = ((!authoritativeSnapshot) ? value.Bytes : 0); int num2 = _bytes - value.Bytes + num; if (message.Cost > 8454144 - num || message.Cost > 33554432 - num2) { if (resyncOnOverflow) { MarkForResync(id); } return false; } if (authoritativeSnapshot) { ClearMessages(value); } value.Resync = false; value.Messages.Enqueue(new Pending(message)); value.Bytes += message.Cost; _bytes += message.Cost; return true; } internal void MarkForResync(long id) { if (_peers.TryGetValue(id, out var value)) { ClearMessages(value); value.Resync = true; } } internal int Flush(double now, Func socketQueuedBytes, Func send) { if (double.IsNaN(now) || double.IsInfinity(now)) { return 0; } double num = Math.Max(0.0, now - _lastTick); _lastTick = now; _globalTokens = Math.Min(262144.0, _globalTokens + num * 524288.0); foreach (Peer value in _peers.Values) { value.Tokens = Math.Min(131200.0, value.Tokens + num * 131072.0); } int num2 = 0; int num3 = 0; while (_order.Count != 0 && num2 < 16 && num3 < _order.Count) { if (_cursor >= _order.Count) { _cursor = 0; } long num4 = _order[_cursor++]; Peer peer = _peers[num4]; if (peer.Resync || peer.Messages.Count == 0) { num3++; continue; } Pending pending = peer.Messages.Peek(); SharedMapOutboundFrame arg = new SharedMapOutboundFrame(pending.Message, pending.Index); int num5 = socketQueuedBytes(num4); if ((double)arg.Cost > peer.Tokens || (double)arg.Cost > _globalTokens || num5 < 0 || num5 > 262144 - arg.Cost || !send(num4, arg)) { num3++; continue; } num3 = 0; num2++; peer.Tokens -= arg.Cost; _globalTokens -= arg.Cost; if (++pending.Index == pending.Message.FrameCount) { peer.Messages.Dequeue(); peer.Bytes -= pending.Message.Cost; _bytes -= pending.Message.Cost; } } return num2; } internal void Remove(long id) { if (_peers.TryGetValue(id, out var value)) { ClearMessages(value); _peers.Remove(id); _order.Remove(id); if (_cursor > _order.Count) { _cursor = 0; } } } internal void RemoveMethod(long id, string method) { if (!_peers.TryGetValue(id, out var value)) { return; } int count = value.Messages.Count; for (int i = 0; i < count; i++) { Pending pending = value.Messages.Dequeue(); if (pending.Message.Method != method) { value.Messages.Enqueue(pending); continue; } value.Bytes -= pending.Message.Cost; _bytes -= pending.Message.Cost; } } internal void Clear() { _peers.Clear(); _order.Clear(); _bytes = 0; _cursor = 0; _lastTick = 0.0; _globalTokens = 262144.0; } private void ClearMessages(Peer peer) { _bytes -= peer.Bytes; peer.Bytes = 0; peer.Messages.Clear(); } } internal sealed class SharedMapContributionBudget { private sealed class Budget { internal double Last; internal double Starts = 2.0; internal double Bytes = 262144.0; internal double Packets = 32.0; internal double DeltaBytes = 262144.0; internal long TransferId; } private readonly Dictionary _peers = new Dictionary(); internal bool Accept(long peer, long transferId, int bytes, double now, bool delta = false, bool restart = false) { if (peer == 0L || transferId < 0 || bytes <= 0 || bytes > 131072 || double.IsNaN(now) || double.IsInfinity(now)) { return false; } if (!_peers.TryGetValue(peer, out var value)) { if (_peers.Count >= 128) { return false; } value = new Budget { Last = now }; _peers.Add(peer, value); } double num = Math.Max(0.0, now - value.Last); value.Last = now; value.Starts = Math.Min(2.0, value.Starts + num / 60.0); value.Bytes = Math.Min(262144.0, value.Bytes + num * 256.0 * 1024.0); value.Packets = Math.Min(32.0, value.Packets + num * 16.0); value.DeltaBytes = Math.Min(262144.0, value.DeltaBytes + num * 192.0 * 1024.0); bool flag = restart || (!delta && transferId != 0L && transferId != value.TransferId); if (value.Packets < 1.0 || value.Bytes < (double)bytes || (flag && value.Starts < 1.0) || (delta && value.DeltaBytes < (double)bytes)) { return false; } value.Packets -= 1.0; value.Bytes -= bytes; if (delta) { value.DeltaBytes -= bytes; } if (flag) { value.Starts -= 1.0; value.TransferId = transferId; } return true; } internal void Remove(long peer) { _peers.Remove(peer); } internal void Clear() { _peers.Clear(); } } internal static class SharedMapPackedMerge { internal static bool Merge(byte[] aggregate, byte[] contribution) { if (aggregate == null || contribution == null || aggregate.Length != contribution.Length) { throw new ArgumentException("Shared exploration dimensions differ."); } bool result = false; for (int i = 0; i < aggregate.Length; i++) { byte b = (byte)(aggregate[i] | contribution[i]); if (b != aggregate[i]) { aggregate[i] = b; result = true; } } return result; } } internal static class SharedMapSocketBudget { internal static int ActualBytes(int reported, bool playFab) { if (reported < 0) { return -1; } if (!playFab || reported == 0) { return reported; } if (reported <= 536870911) { return reported * 4 + 3; } return int.MaxValue; } } internal static class SharedMapRetryPolicy { internal static bool Allows(double now, double lastActivity, bool queued, bool receiving) { if (!double.IsNaN(now) && !double.IsInfinity(now) && !queued && !receiving) { return now - lastActivity >= 120.0; } return false; } } internal static class SharedMapUi { private readonly struct ColumnButton { internal RectTransform Source { get; } internal RectTransform Clone { get; } internal ColumnButton(RectTransform source, RectTransform clone) { Source = source; Clone = clone; } } private readonly struct IconSource { internal PinType Type { get; } internal Image Selection { get; } internal IconSource(PinType type, Image selection) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) Type = type; Selection = selection; } } [CompilerGenerated] private static class <>O { public static WillRenderCanvases <0>__LayoutPublicMarkers; public static UnityAction <1>__OnShareToggleChanged; } private const float ShareToggleVerticalOffset = 42f; private static readonly Color PublicIconColor = new Color(0.3f, 0.95f, 0.36f, 1f); private static readonly Dictionary PublicSelections = new Dictionary(); private static readonly List CreatedObjects = new List(); private static readonly List PublicButtonGroups = new List(); private static readonly List ColumnButtons = new List(); private static readonly Vector3[] CornerBuffer = (Vector3[])(object)new Vector3[4]; private static Camera _uiCamera; private static Minimap _map; private static Toggle _shareToggle; private static TMP_Text _shareLabel; private static TMP_Text _heading; private static bool _settingToggle; private static bool _publicMarkerSelected; private static PinType _selectedPublicType = (PinType)0; internal static bool PublicMarkerSelected => _publicMarkerSelected; internal static PinType SelectedPublicType => _selectedPublicType; internal static void Ensure(Minimap map) { //IL_0071: 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_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Expected O, but got Unknown if (!Application.isBatchMode && !((Object)(object)map == (Object)null) && !((Object)(object)map.m_largeRoot == (Object)null) && !((Object)(object)map.m_publicPosition == (Object)null) && (_map != map || !((Object)(object)_shareToggle != (Object)null))) { Destroy(null); _map = map; CreateShareToggle(map); CreatePublicMarkerColumn(map); Canvas componentInParent = map.m_largeRoot.GetComponentInParent(); _uiCamera = (((Object)(object)componentInParent != (Object)null && (int)componentInParent.renderMode != 0) ? componentInParent.worldCamera : null); object obj = <>O.<0>__LayoutPublicMarkers; if (obj == null) { WillRenderCanvases val = LayoutPublicMarkers; <>O.<0>__LayoutPublicMarkers = val; obj = (object)val; } Canvas.willRenderCanvases += (WillRenderCanvases)obj; Refresh(SharedMapClient.Sharing, SharedMapClient.ReadyForPublicMarkers); } } internal static void Refresh(bool sharing, bool publicMarkersReady) { if ((Object)(object)_shareToggle != (Object)null) { _settingToggle = true; _shareToggle.SetIsOnWithoutNotify(sharing); _settingToggle = false; } if ((Object)(object)_shareLabel != (Object)null && _shareLabel.text != "Share map with other players") { _shareLabel.text = "Share map with other players"; } if ((Object)(object)_heading != (Object)null && _heading.text != "Public\nmarkers") { _heading.text = "Public\nmarkers"; } for (int i = 0; i < PublicButtonGroups.Count; i++) { PublicButtonGroups[i].alpha = (publicMarkersReady ? 1f : 0.55f); } if (!publicMarkersReady) { ClearPublicSelection(); } } internal static void ClearPublicSelection(bool restoreVanillaSelection = true) { //IL_0066: Unknown result type (might be due to invalid IL or missing references) bool publicMarkerSelected = _publicMarkerSelected; _publicMarkerSelected = false; foreach (Image value in PublicSelections.Values) { if ((Object)(object)value != (Object)null) { ((Behaviour)value).enabled = false; } } if (publicMarkerSelected && restoreVanillaSelection && (Object)(object)_map != (Object)null) { MapAccess.SelectIcon(_map, _selectedPublicType); } } internal static void OnVanillaIconSelected() { ClearPublicSelection(restoreVanillaSelection: false); } internal static void Destroy(Minimap map) { //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Expected O, but got Unknown //IL_00cc: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)map != (Object)null && (Object)(object)_map != (Object)null && map != _map) { return; } object obj = <>O.<0>__LayoutPublicMarkers; if (obj == null) { WillRenderCanvases val = LayoutPublicMarkers; <>O.<0>__LayoutPublicMarkers = val; obj = (object)val; } Canvas.willRenderCanvases -= (WillRenderCanvases)obj; for (int num = CreatedObjects.Count - 1; num >= 0; num--) { if ((Object)(object)CreatedObjects[num] != (Object)null) { Object.Destroy((Object)(object)CreatedObjects[num]); } } CreatedObjects.Clear(); PublicButtonGroups.Clear(); PublicSelections.Clear(); ColumnButtons.Clear(); _uiCamera = null; _map = null; _shareToggle = null; _shareLabel = null; _heading = null; _settingToggle = false; _publicMarkerSelected = false; _selectedPublicType = (PinType)0; } private static void CreateShareToggle(Minimap map) { //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Expected O, but got Unknown //IL_0050: 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) GameObject val = Object.Instantiate(((Component)map.m_publicPosition).gameObject, ((Component)map.m_publicPosition).transform.parent, false); ((Object)val).name = "SharedMap.ShareMapToggle"; CreatedObjects.Add(val); IgnoreParentLayout(val); RectTransform component = val.GetComponent(); if ((Object)(object)component != (Object)null) { component.anchoredPosition += new Vector2(0f, 42f); } _shareToggle = val.GetComponent(); _shareToggle.onValueChanged = new ToggleEvent(); ((UnityEvent)(object)_shareToggle.onValueChanged).AddListener((UnityAction)OnShareToggleChanged); DisableGamepadShortcuts(val); _shareLabel = FindToggleLabel(val); if ((Object)(object)_shareLabel != (Object)null) { _shareLabel.text = "Share map with other players"; } } private static void CreatePublicMarkerColumn(Minimap map) { //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_010d: 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_0121: Unknown result type (might be due to invalid IL or missing references) //IL_0132: Unknown result type (might be due to invalid IL or missing references) //IL_013e: Expected O, but got Unknown //IL_018c: 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_014e: Unknown result type (might be due to invalid IL or missing references) //IL_0159: Unknown result type (might be due to invalid IL or missing references) //IL_020d: Unknown result type (might be due to invalid IL or missing references) IconSource[] array = new IconSource[5] { new IconSource((PinType)0, map.m_selectedIcon0), new IconSource((PinType)1, map.m_selectedIcon1), new IconSource((PinType)2, map.m_selectedIcon2), new IconSource((PinType)3, map.m_selectedIcon3), new IconSource((PinType)6, map.m_selectedIcon4) }; RectTransform val = null; for (int i = 0; i < array.Length; i++) { IconSource iconSource = array[i]; if ((Object)(object)iconSource.Selection == (Object)null) { continue; } Transform val2 = FindClickableRoot(((Component)iconSource.Selection).transform, map.m_largeRoot.transform); GameObject val3 = Object.Instantiate(((Component)val2).gameObject, val2.parent, false); ((Object)val3).name = "SharedMap.PublicMarker." + ((object)iconSource.Type/*cast due to .constrained prefix*/).ToString(); CreatedObjects.Add(val3); IgnoreParentLayout(val3); RectTransform component = val3.GetComponent(); if ((Object)(object)component != (Object)null) { component.anchoredPosition += new Vector2(128f, 0f); ColumnButtons.Add(new ColumnButton((RectTransform)val2, component)); if ((Object)(object)val == (Object)null || component.anchoredPosition.y > val.anchoredPosition.y) { val = component; } } CanvasGroup item = val3.GetComponent() ?? val3.AddComponent(); PublicButtonGroups.Add(item); ReplaceClickHandlers(val3, iconSource.Type); DisableGamepadShortcuts(val3); TintMarkerImages(val3, GetMarkerSprite(map, iconSource.Type)); string text = RelativePath(val2, ((Component)iconSource.Selection).transform); Transform obj = (string.IsNullOrEmpty(text) ? val3.transform : val3.transform.Find(text)); Image val4 = ((obj != null) ? ((Component)obj).GetComponent() : null); if ((Object)(object)val4 != (Object)null) { ((Behaviour)val4).enabled = false; PublicSelections[iconSource.Type] = val4; } } if ((Object)(object)val != (Object)null) { CreateHeading(map, val); } } private static void CreateHeading(Minimap map, RectTransform topButton) { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Expected O, but got Unknown //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0096: 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_012d: Unknown result type (might be due to invalid IL or missing references) //IL_0139: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("SharedMap.PublicMarkersHeading", new Type[1] { typeof(RectTransform) }); val.transform.SetParent((Transform)(object)topButton, false); CreatedObjects.Add(val); IgnoreParentLayout(val); RectTransform component = val.GetComponent(); Vector2 val2 = default(Vector2); ((Vector2)(ref val2))..ctor(0.5f, 1f); component.anchorMax = val2; component.anchorMin = val2; component.pivot = new Vector2(0.5f, 0f); component.sizeDelta = new Vector2(128f, 64f); component.anchoredPosition = new Vector2(0f, 8f); TextMeshProUGUI val3 = (TextMeshProUGUI)(object)(_heading = (TMP_Text)(object)val.AddComponent()); ((TMP_Text)val3).text = "Public\nmarkers"; ((TMP_Text)val3).alignment = (TextAlignmentOptions)1026; ((TMP_Text)val3).textWrappingMode = (TextWrappingModes)0; ((TMP_Text)val3).overflowMode = (TextOverflowModes)0; ((Graphic)val3).raycastTarget = false; TMP_Text val4 = _shareLabel; if ((Object)(object)val4 == (Object)null) { val4 = map.m_biomeNameLarge; } if ((Object)(object)val4 != (Object)null) { ((TMP_Text)val3).font = val4.font; ((TMP_Text)val3).fontSharedMaterial = val4.fontSharedMaterial; ((TMP_Text)val3).fontSize = Mathf.Max(16f, val4.fontSize * 0.85f); ((TMP_Text)val3).fontStyle = val4.fontStyle; ((Graphic)val3).color = ((Graphic)val4).color; } component.SetSizeWithCurrentAnchors((Axis)1, Mathf.Max(64f, ((TMP_Text)val3).fontSize * 2.5f)); component.SetSizeWithCurrentAnchors((Axis)0, Mathf.Max(128f, ((TMP_Text)val3).GetPreferredValues("Public\nmarkers").x + 4f)); } private static void ReplaceClickHandlers(GameObject clone, PinType type) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Expected O, but got Unknown //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Expected O, but got Unknown //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Expected O, but got Unknown //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Expected O, but got Unknown //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Expected O, but got Unknown //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) MouseClick[] componentsInChildren = clone.GetComponentsInChildren(true); for (int i = 0; i < componentsInChildren.Length; i++) { componentsInChildren[i].m_leftClick = new UnityEvent(); componentsInChildren[i].m_middleClick = new UnityEvent(); componentsInChildren[i].m_rightClick = new UnityEvent(); ((Behaviour)componentsInChildren[i]).enabled = false; } Button[] componentsInChildren2 = clone.GetComponentsInChildren