Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of LivingMap v0.15.3
LivingMap.dll
Decompiled a day ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Text; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using UnityEngine; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: AssemblyVersion("0.0.0.0")] namespace LivingMap; [BepInPlugin("j1ga.livingmap", "Living Map", "0.15.3")] public class LivingMapPlugin : BaseUnityPlugin { private struct PieceRec { public float X0; public float Z0; public float X1; public float Z1; public float Y; public byte Mat; public float CX => (X0 + X1) * 0.5f; public float CZ => (Z0 + Z1) * 0.5f; } private struct PrefabInfo { public bool IsPiece; public bool IsTree; public bool IsTerrain; public byte Mat; public Vector3 Min; public Vector3 Max; } private const byte LayerBuildings = 1; private const byte LayerPaths = 2; private const byte LayerForest = 4; private const float DefaultResetRadius = 100f; private const string SecGeneral = "01 General"; private const string SecLayers = "02 Layers"; private const string SecScanning = "03 Scanning"; private const string SecRendering = "04 Rendering"; private const string SecColors = "05 Colors"; private const string SecAdvanced = "06 Advanced"; private const string SecDebug = "07 Debug"; public const string Guid = "j1ga.livingmap"; public const string Name = "Living Map"; public const string Version = "0.15.3"; private const byte MatNone = byte.MaxValue; private const byte TerrainNone = 0; private const byte TerrainCultivated = 1; private const byte TerrainPaved = 2; private const byte TerrainDirt = 3; private const byte TerrainCleared = 4; private const float RefogInterval = 15f; private const float MaxFootprint = 32f; private const int MaxErrors = 25; private const int MaxTerrainErrors = 10; private const string OldGuid = "j1ga.mapoverlay"; private const string OldFolder = "MapOverlay"; private const int ForestZonesPerFrame = 150; private const int BiomeLookupsPerFrame = 600; private const int MaxIncrementalPieces = 1500; private const float MapRebuildInterval = 0.5f; private const float ScanMoveDelta = 8f; private const float ScanInterval = 1f; private const float IdleRescanInterval = 10f; private const int MaxColliders = 8192; private const float SaveInterval = 60f; private const int TerrainZonesPerFrame = 4; private const int MaxTcErrors = 10; private const int MaxZdoErrors = 10; private ConfigEntry<bool> _cfgEnabled; private ConfigEntry<bool> _cfgPersist; private ConfigEntry<bool> _cfgShowBuildings; private ConfigEntry<bool> _cfgOnlyPlayerBuilt; private ConfigEntry<bool> _cfgShowPaths; private ConfigEntry<bool> _cfgShowCleared; private ConfigEntry<bool> _cfgShowForest; private ConfigEntry<float> _cfgForestRadius; private ConfigEntry<int> _cfgForestMaxTrees; private ConfigEntry<bool> _cfgShowPlanted; private ConfigEntry<int> _cfgPlantedMinTrees; private ConfigEntry<bool> _cfgPlantedAnyBiome; private ConfigEntry<bool> _cfgRespectFog; private ConfigEntry<string> _cfgScanSource; private ConfigEntry<string> _cfgPathSource; private ConfigEntry<float> _cfgZdoInterval; private ConfigEntry<int> _cfgMapScale; private ConfigEntry<float> _cfgPieceSize; private ConfigEntry<bool> _cfgOutline; private ConfigEntry<float> _cfgOutlineWidth; private ConfigEntry<float> _cfgTerrainGrid; private ConfigEntry<Color>[] _cfgMatColor; private ConfigEntry<Color> _cfgMatUnknownColor; private ConfigEntry<Color> _cfgCultivatedColor; private ConfigEntry<Color> _cfgPavedColor; private ConfigEntry<Color> _cfgDirtColor; private ConfigEntry<Color> _cfgClearedColor; private ConfigEntry<Color> _cfgOutlineColor; private ConfigEntry<int> _cfgZdoPerFrame; private ConfigEntry<float> _cfgScanRadius; private ConfigEntry<int> _cfgMaxPieces; private ConfigEntry<int> _cfgMaxTerrain; private ConfigEntry<bool> _cfgDebug; private ConfigEntry<bool> _cfgDebugMarker; private ConfigEntry<bool> _cfgIncremental; private ConfigEntry<bool> _cfgLinearFix; private ConfigEntry<bool> _cfgMapFlipY; private static readonly string[] MatNames = new string[9] { "Wood", "Stone", "Iron", "HardWood", "Marble", "Ashstone", "Ancient", "Ice", "Timberwood" }; private static readonly string[] DroppedSettings = new string[16] { "MapRebuildInterval", "MoveDelta", "ScanInterval", "IdleRescanInterval", "SaveInterval", "MaxColliders", "PaintMapTexture", "DetailedOverlay", "MinimapOverlay", "FlushInterval", "PixelsPerFlush", "OverlayOpacity", "SmoothOverlay", "MinimapOverlayResolution", "DetailedOverlayResolution", "DetailedOverlayInterval" }; private readonly Dictionary<int, List<PieceRec>> _pieces = new Dictionary<int, List<PieceRec>>(); private int _pieceCount; private readonly Dictionary<long, byte> _terrain = new Dictionary<long, byte>(); private readonly List<int> _circleScratch = new List<int>(); private readonly Dictionary<int, List<PieceRec>> _scanBuckets = new Dictionary<int, List<PieceRec>>(); private readonly List<long> _terrainScratch = new List<long>(); private Minimap _mm; private Texture2D _vanillaTex; private Texture _origSmallTex; private Texture _origLargeTex; private int _texSize; private float _pixelSize; private bool _ready; private Vector3 _lastScanPos; private float _nextScanTime; private float _lastScanTime; private float _nextSaveTime; private float _nextRefogTime; private FieldInfo _fiExplored; private FieldInfo _fiExploredOthers; private int _errorCount; private int _terrainErrorCount; private bool _disabledByErrors; private bool _terrainDisabled; private readonly HashSet<string> _loggedErrors = new HashSet<string>(); private bool _oldPluginChecked; private FieldInfo _fiGeneratedZones; private BitArray _forestMask; private BitArray _pixelTrusted; private byte[] _treeCount; private readonly HashSet<int> _clearedForest = new HashSet<int>(); private readonly HashSet<int> _trustedZones = new HashSet<int>(); private readonly List<int> _trustedZoneScratch = new List<int>(); private readonly List<int> _forestSample = new List<int>(); private bool _forestDisabled; private int _forestCursor = -1; private bool _forestChanged; private int _forestAdded; private int _forestRemoved; private readonly HashSet<int> _plantedForest = new HashSet<int>(); private readonly Dictionary<int, int> _outsideCounts = new Dictionary<int, int>(); private readonly Dictionary<int, bool> _forestBiome = new Dictionary<int, bool>(); private int _biomeLookupsThisFrame; private RenderTexture _rtMask; private Material _glMatMask; private Material _glMatMaskAdd; private Texture2D _vanillaMask; private Texture _origSmallMask; private Texture _origLargeMask; private RenderTexture _rt; private Material _glMat; private bool _gpuUnavailable; private bool _rtDirty; private bool _maskDirty; private readonly List<PieceRec> _addPieces = new List<PieceRec>(); private readonly List<long> _addTerrain = new List<long>(); private readonly List<PieceRec> _fogPieces = new List<PieceRec>(); private readonly List<long> _fogTerrain = new List<long>(); private readonly List<int> _fogForest = new List<int>(); private readonly List<PieceRec> _groupScratch = new List<PieceRec>(); private readonly List<PieceRec> _fillScratch = new List<PieceRec>(); private int _rtIncrements; private bool _drawnBuildings; private bool _drawnPaths; private bool _drawnOutline; private float _nextRtRebuild; private int _rtScale = 1; private int _rtRebuilds; private static float MapPixelSize; private static bool LinearColors; private Collider[] _colliderBuf; private int _pieceLayerMask; private long _worldUid; private bool _storeChanged; private readonly List<ZDO> _tcZdos = new List<ZDO>(); private readonly Dictionary<ZDOID, uint> _tcRevision = new Dictionary<ZDOID, uint>(); private int _tcCursor = -1; private int _tcParsed; private int _tcSkipped; private int _tcAdded; private int _tcRemoved; private int _tcChanged; private int _tcErrorCount; private int _tcPasses; private double _tcMs; private bool _tcDisabled; private bool[] _tcHeightScratch; private byte[] _tcKindScratch; private FieldInfo _fiObjectsByID; private int _zdoPieceLayer = -1; private readonly Dictionary<int, PrefabInfo> _prefabCache = new Dictionary<int, PrefabInfo>(); private readonly List<ZDO> _zdoSnapshot = new List<ZDO>(); private readonly Dictionary<int, List<PieceRec>> _zdoBuckets = new Dictionary<int, List<PieceRec>>(); private readonly Stack<List<PieceRec>> _listPool = new Stack<List<PieceRec>>(); private readonly List<int> _removeScratch = new List<int>(); private int _zdoCursor = -1; private float _nextZdoPass; private Vector3 _zdoPassOrigin; private Vector3 _zdoPrevOrigin; private bool _zdoHavePrevOrigin; private bool _zdoAuthoritative; private int _zdoPasses; private int _zdoPassFrames; private int _zdoErrorCount; private readonly Stopwatch _sw = new Stopwatch(); private double _zdoPassMs; private double _forestMs; private bool _zdoDisabled; private bool _zdoPassPieces; private bool _piecesOnlyPlayerBuilt; private bool ForestWanted { get { if ((_cfgShowForest.Value || _cfgShowPlanted.Value) && !_forestDisabled) { return UseZdoScan; } return false; } } private bool UseZdoPaths { get { if (UseZdoScan && !_tcDisabled) { return string.Equals(_cfgPathSource.Value, "ZDO", StringComparison.OrdinalIgnoreCase); } return false; } } private bool UseZdoScan { get { if (!_zdoDisabled && _fiObjectsByID != null) { return string.Equals(_cfgScanSource.Value, "ZDO", StringComparison.OrdinalIgnoreCase); } return false; } } private void RegisterCommands() { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Expected O, but got Unknown //IL_0020: Unknown result type (might be due to invalid IL or missing references) new ConsoleCommand("livingmap", "Living Map. 'livingmap status' shows what the map remembers; 'livingmap reset [buildings|paths|forest] [metres|all]' forgets it around you (100 m by default) and collects it again", (ConsoleEvent)delegate(ConsoleEventArgs args) { RunCommand(args); }, false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false); } private static void Say(ConsoleEventArgs args, string text) { if (args != null && (Object)(object)args.Context != (Object)null) { args.Context.AddString(text); } } private void RunCommand(ConsoleEventArgs args) { //IL_01b6: Unknown result type (might be due to invalid IL or missing references) try { string text = ((args.Args.Length > 1) ? args.Args[1].ToLowerInvariant() : ""); if (text == "status") { Say(args, StatusText()); return; } if (text != "reset") { Say(args, "livingmap status | livingmap reset [buildings|paths|forest] [metres|all]"); return; } byte b = 0; float radius = 100f; bool world = false; for (int i = 2; i < args.Args.Length; i++) { string text2 = args.Args[i].ToLowerInvariant(); switch (text2) { case "buildings": case "pieces": b |= 1; continue; case "paths": case "terrain": b |= 2; continue; case "forest": case "trees": b |= 4; continue; case "all": case "world": world = true; continue; } if (float.TryParse(text2, NumberStyles.Float, CultureInfo.InvariantCulture, out var result) && result > 0f) { radius = result; continue; } Say(args, "livingmap: unknown word '" + args.Args[i] + "'"); return; } if (b == 0) { b = 7; } if (!_ready || (Object)(object)_mm == (Object)null) { Say(args, "livingmap: not attached to a map right now"); } else if ((Object)(object)Player.m_localPlayer == (Object)null) { Say(args, "livingmap: no player"); } else { Say(args, ResetData(b, ((Component)Player.m_localPlayer).transform.position, radius, world)); } } catch (Exception e) { HandleError("console command", e); Say(args, "livingmap: failed, see the BepInEx log"); } } private string StatusText() { if (!_ready || (Object)(object)_mm == (Object)null) { return "Living Map 0.15.3: not attached to a map"; } return string.Format("Living Map {0}: {1} pieces in {2} map pixels, {3} path cells, forest cleared {4} / planted {5}; buildings via {6}, paths via {7}; map {8}px ({9:0.##} m/px); last pass {10} frames, {11:0.0} ms", "0.15.3", _pieceCount, _pieces.Count, _terrain.Count, _clearedForest.Count, _plantedForest.Count, (!UseZdoScan) ? "physics" : (_zdoAuthoritative ? "ZDO (host, whole world)" : "ZDO (client)"), UseZdoPaths ? "terrain records" : "loaded heightmaps", ((Object)(object)_rt != (Object)null) ? ((Texture)_rt).width : 0, ((Object)(object)_rt != (Object)null) ? (_pixelSize / (float)_rtScale) : 0f, _zdoPassFrames, _zdoPassMs); } private string ResetData(byte layers, Vector3 center, float radius, bool world) { //IL_0255: Unknown result type (might be due to invalid IL or missing references) //IL_026b: 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_0232: Unknown result type (might be due to invalid IL or missing references) //IL_0237: Unknown result type (might be due to invalid IL or missing references) float half = (float)_texSize * 0.5f; float num = radius * radius; int num2 = 0; int num3 = 0; int num4 = 0; if ((layers & 1) != 0) { _removeScratch.Clear(); foreach (KeyValuePair<int, List<PieceRec>> piece in _pieces) { if (world || PixelWithin(piece.Key, center, num, half)) { _removeScratch.Add(piece.Key); } } for (int i = 0; i < _removeScratch.Count; i++) { List<PieceRec> list = _pieces[_removeScratch[i]]; num2 += list.Count; _pieceCount -= list.Count; ReturnList(list); _pieces.Remove(_removeScratch[i]); } _removeScratch.Clear(); _addPieces.Clear(); _fogPieces.Clear(); } if ((layers & 2) != 0) { float num5 = Mathf.Max(0.5f, _cfgTerrainGrid.Value); List<long> list2 = new List<long>(); foreach (KeyValuePair<long, byte> item in _terrain) { if (!world) { float num6 = ((float)(int)(item.Key >> 32) + 0.5f) * num5 - center.x; float num7 = ((float)(int)(item.Key & 0xFFFFFFFFu) + 0.5f) * num5 - center.z; if (num6 * num6 + num7 * num7 > num) { continue; } } list2.Add(item.Key); } for (int j = 0; j < list2.Count; j++) { _terrain.Remove(list2[j]); } num3 = list2.Count; _addTerrain.Clear(); _fogTerrain.Clear(); _tcRevision.Clear(); _lastScanPos = new Vector3(float.MinValue, 0f, float.MinValue); _nextScanTime = 0f; } if ((layers & 4) != 0) { num4 += RemovePixels(_clearedForest, center, num, half, world); num4 += RemovePixels(_plantedForest, center, num, half, world); _trustedZones.Clear(); _fogForest.Clear(); _maskDirty = true; } ResetZdoPass(); _nextZdoPass = 0f; _rtDirty = true; _storeChanged = true; string text = (world ? "the whole world" : $"{radius:0} m around you"); string text2 = $"Living Map: forgot {num2} pieces, {num3} path cells, {num4} forest pixels in {text}; collecting again"; ((BaseUnityPlugin)this).Logger.LogInfo((object)text2); return text2; } private bool PixelWithin(int idx, Vector3 center, float r2, float half) { float num = ((float)(idx % _texSize) - half) * _pixelSize - center.x; float num2 = ((float)(idx / _texSize) - half) * _pixelSize - center.z; return num * num + num2 * num2 <= r2; } private int RemovePixels(HashSet<int> pixels, Vector3 center, float r2, float half, bool world) { //IL_0032: Unknown result type (might be due to invalid IL or missing references) if (world) { int count = pixels.Count; pixels.Clear(); return count; } _removeScratch.Clear(); foreach (int pixel in pixels) { if (PixelWithin(pixel, center, r2, half)) { _removeScratch.Add(pixel); } } for (int i = 0; i < _removeScratch.Count; i++) { pixels.Remove(_removeScratch[i]); } int count2 = _removeScratch.Count; _removeScratch.Clear(); return count2; } private void BindConfig() { //IL_0117: Unknown result type (might be due to invalid IL or missing references) //IL_0121: Expected O, but got Unknown //IL_014b: Unknown result type (might be due to invalid IL or missing references) //IL_0155: Expected O, but got Unknown //IL_01a0: Unknown result type (might be due to invalid IL or missing references) //IL_01aa: Expected O, but got Unknown //IL_022f: Unknown result type (might be due to invalid IL or missing references) //IL_0239: Expected O, but got Unknown //IL_027c: Unknown result type (might be due to invalid IL or missing references) //IL_0286: Expected O, but got Unknown //IL_02bb: Unknown result type (might be due to invalid IL or missing references) //IL_02c5: Expected O, but got Unknown //IL_030a: Unknown result type (might be due to invalid IL or missing references) //IL_0314: Expected O, but got Unknown //IL_0349: Unknown result type (might be due to invalid IL or missing references) //IL_0353: Expected O, but got Unknown //IL_03a9: Unknown result type (might be due to invalid IL or missing references) //IL_03b3: Expected O, but got Unknown //IL_03e8: Unknown result type (might be due to invalid IL or missing references) //IL_03f2: Expected O, but got Unknown //IL_042e: Unknown result type (might be due to invalid IL or missing references) //IL_0433: Unknown result type (might be due to invalid IL or missing references) //IL_0454: Unknown result type (might be due to invalid IL or missing references) //IL_0459: Unknown result type (might be due to invalid IL or missing references) //IL_047a: Unknown result type (might be due to invalid IL or missing references) //IL_047f: Unknown result type (might be due to invalid IL or missing references) //IL_04a0: Unknown result type (might be due to invalid IL or missing references) //IL_04a5: Unknown result type (might be due to invalid IL or missing references) //IL_04c6: Unknown result type (might be due to invalid IL or missing references) //IL_04cb: Unknown result type (might be due to invalid IL or missing references) //IL_04ec: Unknown result type (might be due to invalid IL or missing references) //IL_04f1: Unknown result type (might be due to invalid IL or missing references) //IL_0512: Unknown result type (might be due to invalid IL or missing references) //IL_0517: Unknown result type (might be due to invalid IL or missing references) //IL_0538: Unknown result type (might be due to invalid IL or missing references) //IL_053d: Unknown result type (might be due to invalid IL or missing references) //IL_055e: Unknown result type (might be due to invalid IL or missing references) //IL_0563: Unknown result type (might be due to invalid IL or missing references) //IL_0599: Unknown result type (might be due to invalid IL or missing references) //IL_05ed: Unknown result type (might be due to invalid IL or missing references) //IL_0626: Unknown result type (might be due to invalid IL or missing references) //IL_065f: Unknown result type (might be due to invalid IL or missing references) //IL_0698: Unknown result type (might be due to invalid IL or missing references) //IL_06d1: Unknown result type (might be due to invalid IL or missing references) //IL_070a: Unknown result type (might be due to invalid IL or missing references) //IL_074e: Unknown result type (might be due to invalid IL or missing references) //IL_0758: Expected O, but got Unknown //IL_078d: Unknown result type (might be due to invalid IL or missing references) //IL_0797: Expected O, but got Unknown //IL_07cc: Unknown result type (might be due to invalid IL or missing references) //IL_07d6: Expected O, but got Unknown //IL_080b: Unknown result type (might be due to invalid IL or missing references) //IL_0815: Expected O, but got Unknown _cfgEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("01 General", "Enabled", true, "Master switch."); _cfgPersist = ((BaseUnityPlugin)this).Config.Bind<bool>("01 General", "SaveOverlay", true, "Remember what was collected between sessions, in a file per world. The host collects everything again within seconds anyway; this matters on a client of a dedicated server, which only ever gets what the server has sent it."); _cfgShowBuildings = ((BaseUnityPlugin)this).Config.Bind<bool>("02 Layers", "ShowBuildings", true, "Show build pieces."); _cfgOnlyPlayerBuilt = ((BaseUnityPlugin)this).Config.Bind<bool>("02 Layers", "OnlyPlayerBuilt", false, "Show only pieces placed by players. Pieces that came with a location - ruins, draugr villages, dvergr outposts, stone circles - carry no creator and are skipped. Switching it drops the stored pieces and collects them again: the host has them all within seconds, a client of a dedicated server gets pieces from earlier sessions back only by passing by them."); _cfgShowPaths = ((BaseUnityPlugin)this).Config.Bind<bool>("02 Layers", "ShowPaths", true, "Show ground painted with the hoe: dirt paths, cultivated soil and paving."); _cfgShowCleared = ((BaseUnityPlugin)this).Config.Bind<bool>("02 Layers", "ShowClearedGround", false, "Also mark ground that was merely levelled or raised, with no paint applied. This covers everything you have terraformed, so it paints wide areas."); _cfgShowForest = ((BaseUnityPlugin)this).Config.Bind<bool>("02 Layers", "ShowClearedForest", true, "Erase the map's forest pattern where the trees are gone. The vanilla forest layer comes from the world generator and never changes, so a clear-cut around your base still shows as woods; this compares it with the trees that actually exist in the object database. On the host every generated zone is checked; on a client of a dedicated server only zones you have been near this session, remembered between sessions. Clearings the game itself makes around locations show up too. Needs BuildingScanSource = ZDO."); _cfgForestRadius = ((BaseUnityPlugin)this).Config.Bind<float>("02 Layers", "ClearedForestRadius", 12f, new ConfigDescription("Metres around a map pixel that are checked for trees when deciding whether the pixel is cleared forest. 12 = the pixel and its neighbours, a 36 x 36 m window. Larger ignores natural gaps between trees, smaller follows the edge of a clearing more closely.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(6f, 96f), new object[0])); _cfgForestMaxTrees = ((BaseUnityPlugin)this).Config.Bind<int>("02 Layers", "ClearedForestMaxTrees", 2, new ConfigDescription("Trees allowed inside that window for the pixel to still count as cleared. A natural wood has 6 to 40 in a 36 x 36 m window, a clearing with a couple of trees left standing has 1 or 2.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 50), new object[0])); _cfgShowPlanted = ((BaseUnityPlugin)this).Config.Bind<bool>("02 Layers", "ShowPlantedForest", true, "Draw the map's own forest pattern where trees stand but the map shows none: a grove you planted, or woods the generator's mask missed. It is the vanilla pattern, so it looks like any other forest. Limited to the biomes where the vanilla map draws forest at all (Meadows, Black Forest, Plains) unless PlantedForestAnyBiome is on. Needs BuildingScanSource = ZDO."); _cfgPlantedMinTrees = ((BaseUnityPlugin)this).Config.Bind<int>("02 Layers", "PlantedForestMinTrees", 6, new ConfigDescription("Trees a map pixel (12 x 12 m at vanilla map resolution) must hold to be drawn as forest. A planted grove has 15 or more; the edge of a natural wood that the mask cuts off mid-pixel has up to about 5.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 30), new object[0])); _cfgPlantedAnyBiome = ((BaseUnityPlugin)this).Config.Bind<bool>("02 Layers", "PlantedForestAnyBiome", false, "Draw forest in biomes where the vanilla map never does: swamps, mountains, Mistlands, Ashlands. Their natural woods then get the forest pattern as well, which changes the look of the whole map."); _cfgRespectFog = ((BaseUnityPlugin)this).Config.Bind<bool>("02 Layers", "RespectFog", true, "Only draw on explored ground. Off shows everything the mod knows about, which on the host is the whole world."); _cfgScanSource = ((BaseUnityPlugin)this).Config.Bind<string>("03 Scanning", "BuildingScanSource", "ZDO", new ConfigDescription("Where build pieces are read from. ZDO walks the game's object database: on the host (single player, or the player hosting the game) that is every piece in the whole world at once, and pieces that were torn down disappear from the map; on a client of a dedicated server it is everything the server has sent this session. Physics is the old way: only colliders in the loaded zones around you, within ScanRadius. ZDO falls back to Physics on its own if the database cannot be read.", (AcceptableValueBase)(object)new AcceptableValueList<string>(new string[2] { "ZDO", "Physics" }), new object[0])); _cfgPathSource = ((BaseUnityPlugin)this).Config.Bind<string>("03 Scanning", "PathScanSource", "ZDO", new ConfigDescription("Where hoe-painted ground is read from. ZDO reads each zone's terrain record from the object database (the same _TerrainCompiler data the game saves): on the host every modified zone of the world at once, on a client of a dedicated server the zones the server has sent this session. Only records whose revision changed are re-read. Heightmap is the old way: sampling the loaded terrain around you within ScanRadius. ZDO needs BuildingScanSource = ZDO and falls back to Heightmap on its own if the records cannot be read.", (AcceptableValueBase)(object)new AcceptableValueList<string>(new string[2] { "ZDO", "Heightmap" }), new object[0])); _cfgZdoInterval = ((BaseUnityPlugin)this).Config.Bind<float>("03 Scanning", "ZdoScanInterval", 5f, new ConfigDescription("Seconds between full passes over the object database: how long a new or removed piece takes to reach the map.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 120f), new object[0])); _cfgMapScale = ((BaseUnityPlugin)this).Config.Bind<int>("04 Rendering", "MapTextureScale", 4, new ConfigDescription("Resolution multiplier for the map layer: how crisp buildings and paths are drawn. The terrain itself stays the vanilla 12 m texture and does not get more detailed. Vanilla 2048 is 12 m per pixel. 2 = 4096 = 6 m/px (~67 MB of video memory), 4 = 8192 = 3 m/px (~268 MB), 8 = 16384 = 1.5 m/px (~1 GB, only worth it on a card with plenty of VRAM). Video memory only, nothing is held in RAM. If the card refuses the size the mod steps down automatically. Takes effect on the next world load.", (AcceptableValueBase)(object)new AcceptableValueList<int>(new int[4] { 1, 2, 4, 8 }), new object[0])); _cfgPieceSize = ((BaseUnityPlugin)this).Config.Bind<float>("04 Rendering", "MinPieceSizeMeters", 2f, new ConfigDescription("Smallest size, in metres, that a build piece is drawn at. Pieces use their real footprint; this is the floor so thin walls stay visible however sharp the map texture is. Raise it if buildings read as too faint.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 8f), new object[0])); _cfgOutline = ((BaseUnityPlugin)this).Config.Bind<bool>("04 Rendering", "BuildingOutline", true, "Draw a dark halo behind every build piece. Without it a wooden building blends into the dirt path it usually stands on."); _cfgOutlineWidth = ((BaseUnityPlugin)this).Config.Bind<float>("04 Rendering", "OutlineWidthMeters", 1f, new ConfigDescription("How far the halo extends past a piece, in metres.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 4f), new object[0])); _cfgTerrainGrid = ((BaseUnityPlugin)this).Config.Bind<float>("04 Rendering", "TerrainGridSize", 2f, new ConfigDescription("Metres per cell of the path layer. The terrain records hold 1 m; 2 is plenty up to MapTextureScale 4, at 8 the difference shows. Halving it means four times the cells in memory and in the file. Changing it drops the stored path cells: the host has them back within one pass, a client of a dedicated server as the server sends the zones again.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 8f), new object[0])); _cfgMatColor = new ConfigEntry<Color>[MatNames.Length]; Color[] array = (Color[])(object)new Color[9] { new Color(0.95f, 0.55f, 0.15f, 1f), new Color(0.72f, 0.74f, 0.8f, 1f), new Color(0.4f, 0.44f, 0.52f, 1f), new Color(0.55f, 0.34f, 0.16f, 1f), new Color(0.9f, 0.87f, 0.8f, 1f), new Color(0.45f, 0.2f, 0.2f, 1f), new Color(0.36f, 0.52f, 0.36f, 1f), new Color(0.65f, 0.85f, 0.95f, 1f), new Color(0.7f, 0.45f, 0.3f, 1f) }; for (int i = 0; i < MatNames.Length; i++) { _cfgMatColor[i] = ((BaseUnityPlugin)this).Config.Bind<Color>("05 Colors", "Material_" + MatNames[i], array[i], "Colour for " + MatNames[i] + " pieces."); } _cfgMatUnknownColor = ((BaseUnityPlugin)this).Config.Bind<Color>("05 Colors", "Material_Unknown", new Color(0.85f, 0.3f, 0.75f, 1f), "Colour for pieces with no material information."); _cfgCultivatedColor = ((BaseUnityPlugin)this).Config.Bind<Color>("05 Colors", "Terrain_Cultivated", new Color(0.36f, 0.26f, 0.12f, 0.85f), "Colour for cultivated soil (the cultivator)."); _cfgPavedColor = ((BaseUnityPlugin)this).Config.Bind<Color>("05 Colors", "Terrain_Paved", new Color(0.62f, 0.62f, 0.66f, 0.9f), "Colour for paved ground (the hoe's paving)."); _cfgDirtColor = ((BaseUnityPlugin)this).Config.Bind<Color>("05 Colors", "Terrain_DirtPath", new Color(0.42f, 0.36f, 0.3f, 0.8f), "Colour for dirt paths (the hoe's path tool). Kept deliberately dull so buildings stand out against it."); _cfgClearedColor = ((BaseUnityPlugin)this).Config.Bind<Color>("05 Colors", "Terrain_Cleared", new Color(0.5f, 0.47f, 0.36f, 0.5f), "Colour for levelled ground with no paint, when ShowClearedGround is on."); _cfgOutlineColor = ((BaseUnityPlugin)this).Config.Bind<Color>("05 Colors", "Building_Outline", new Color(0.1f, 0.07f, 0.04f, 0.85f), "Colour of the halo drawn behind build pieces, when BuildingOutline is on."); _cfgZdoPerFrame = ((BaseUnityPlugin)this).Config.Bind<int>("06 Advanced", "ZdoObjectsPerFrame", 4000, new ConfigDescription("Objects examined per frame during a pass over the object database. A world of 70 000 objects takes about 18 frames at the default; raise it if you would rather have the map update sooner than smoother.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(500, 50000), new object[0])); _cfgScanRadius = ((BaseUnityPlugin)this).Config.Bind<float>("06 Advanced", "ScanRadius", 64f, new ConfigDescription("Radius in metres scanned around the player by the old scanners: build pieces with BuildingScanSource = Physics, paths with PathScanSource = Heightmap. Unused with the default ZDO sources. Objects exist only while their zone is loaded, so much above ~128 gains nothing.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(16f, 256f), new object[0])); _cfgMaxPieces = ((BaseUnityPlugin)this).Config.Bind<int>("06 Advanced", "MaxPieces", 300000, new ConfigDescription("Hard cap on stored build pieces; beyond it new pieces are not recorded, with one warning in the log. 300 000 pieces take about 7 MB.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1000, 3000000), new object[0])); _cfgMaxTerrain = ((BaseUnityPlugin)this).Config.Bind<int>("06 Advanced", "MaxTerrainCells", 500000, new ConfigDescription("Hard cap on stored path cells; beyond it new cells are not recorded, with one warning in the log.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1000, 5000000), new object[0])); _cfgDebug = ((BaseUnityPlugin)this).Config.Bind<bool>("07 Debug", "Debug", false, "Verbose logging, with timings of every scan and redraw, and a self-check of terrain records against the loaded terrain."); _cfgDebugMarker = ((BaseUnityPlugin)this).Config.Bind<bool>("07 Debug", "DebugMarker", false, "Draw a magenta cross at your own position on the map. Use it once to confirm the layer lines up with the vanilla player arrow; while it is on, every update is a full rebuild."); _cfgIncremental = ((BaseUnityPlugin)this).Config.Bind<bool>("07 Debug", "IncrementalRedraw", true, "Draw new shapes on top of the existing map texture; a full rebuild happens only when something disappeared, a layer was switched, or too much arrived at once. Off = rebuild the whole texture on every change, as before 0.11.0. Only for pinning down a drawing glitch."); _cfgLinearFix = ((BaseUnityPlugin)this).Config.Bind<bool>("07 Debug", "LinearColorFix", true, "Convert the colours to linear before drawing on the GPU. The game renders in linear colour space, and the conversion is applied only then; without it everything comes out pale and washed out. Off only to check whether the colours are the problem."); _cfgMapFlipY = ((BaseUnityPlugin)this).Config.Bind<bool>("07 Debug", "MapLayerFlipY", false, "Flip the drawn shapes vertically. Only needed if the graphics API renders the map layer upside down - check with DebugMarker, set it once and the whole layer lines up."); } private void MigrateConfigLayout(HashSet<ConfigDefinition> inFile) { Dictionary<ConfigDefinition, string> dictionary = OrphanedConfigEntries(); if (dictionary == null || dictionary.Count == 0) { return; } Dictionary<string, ConfigEntryBase> dictionary2 = new Dictionary<string, ConfigEntryBase>(); foreach (ConfigDefinition key in ((BaseUnityPlugin)this).Config.Keys) { dictionary2[key.Key] = ((BaseUnityPlugin)this).Config[key]; } List<ConfigDefinition> list = new List<ConfigDefinition>(); int num = 0; bool saveOnConfigSet = ((BaseUnityPlugin)this).Config.SaveOnConfigSet; ((BaseUnityPlugin)this).Config.SaveOnConfigSet = false; try { foreach (KeyValuePair<ConfigDefinition, string> item in dictionary) { string text = item.Key.Key; if (item.Key.Section == "06 Colors" && text == "BuildingOutline") { text = "Building_Outline"; } if (!dictionary2.TryGetValue(text, out var value)) { if (Array.IndexOf(DroppedSettings, text) >= 0) { list.Add(item.Key); } continue; } list.Add(item.Key); if (inFile == null || !inFile.Contains(value.Definition)) { try { value.SetSerializedValue(item.Value); num++; } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Could not carry the setting " + item.Key.Section + "/" + item.Key.Key + " over: " + ex.Message)); } } } for (int i = 0; i < list.Count; i++) { dictionary.Remove(list[i]); } } finally { ((BaseUnityPlugin)this).Config.SaveOnConfigSet = saveOnConfigSet; } if (list.Count != 0) { ((BaseUnityPlugin)this).Config.Save(); ((BaseUnityPlugin)this).Logger.LogInfo((object)("Settings file updated to the 0.15.0 layout: " + num + " values moved to their new sections, " + (list.Count - num) + " obsolete lines removed.")); } } private HashSet<ConfigDefinition> SettingsInFile() { Dictionary<ConfigDefinition, string> dictionary = OrphanedConfigEntries(); if (dictionary == null) { return null; } return new HashSet<ConfigDefinition>(dictionary.Keys); } private Dictionary<ConfigDefinition, string> OrphanedConfigEntries() { try { PropertyInfo property = typeof(ConfigFile).GetProperty("OrphanedEntries", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (property != null) { return property.GetValue(((BaseUnityPlugin)this).Config, null) as Dictionary<ConfigDefinition, string>; } } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Could not read the unbound settings: " + ex.Message)); } return null; } private void Awake() { try { MigrateFromMapOverlay(); HashSet<ConfigDefinition> inFile = SettingsInFile(); BindConfig(); MigrateConfigLayout(inFile); RegisterCommands(); _pieceLayerMask = LayerMask.GetMask(new string[1] { "piece" }); _zdoPieceLayer = LayerMask.NameToLayer("piece"); FieldInfo field = typeof(ZDOMan).GetField("m_objectsByID", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field != null && typeof(Dictionary<ZDOID, ZDO>).IsAssignableFrom(field.FieldType)) { _fiObjectsByID = field; } else { ((BaseUnityPlugin)this).Logger.LogWarning((object)"ZDOMan.m_objectsByID was not found or has an unexpected type; build pieces will be scanned through physics instead."); } FieldInfo field2 = typeof(ZoneSystem).GetField("m_generatedZones", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field2 != null && typeof(HashSet<Vector2s>).IsAssignableFrom(field2.FieldType)) { _fiGeneratedZones = field2; } else { ((BaseUnityPlugin)this).Logger.LogWarning((object)"ZoneSystem.m_generatedZones was not found; the cleared-forest layer will only cover zones you have visited this session, even on the host."); } _fiExplored = typeof(Minimap).GetField("m_explored", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); _fiExploredOthers = typeof(Minimap).GetField("m_exploredOthers", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Living Map 0.15.3 loaded. No Harmony patches are applied."); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)("Awake failed, mod is inert: " + ex)); _disabledByErrors = true; } } private void OnDestroy() { try { SaveStore(); Teardown(restoreVanillaTexture: true); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("OnDestroy: " + ex.Message)); } } private void Update() { if (_disabledByErrors) { return; } try { Tick(); } catch (Exception e) { HandleError("Tick", e); } } private void Tick() { //IL_011b: Unknown result type (might be due to invalid IL or missing references) //IL_0120: Unknown result type (might be due to invalid IL or missing references) //IL_012b: Unknown result type (might be due to invalid IL or missing references) //IL_012e: Unknown result type (might be due to invalid IL or missing references) //IL_0133: Unknown result type (might be due to invalid IL or missing references) //IL_0138: Unknown result type (might be due to invalid IL or missing references) //IL_017e: Unknown result type (might be due to invalid IL or missing references) //IL_0180: Unknown result type (might be due to invalid IL or missing references) //IL_0186: Unknown result type (might be due to invalid IL or missing references) //IL_01d0: Unknown result type (might be due to invalid IL or missing references) if (!_oldPluginChecked && OldPluginLoaded()) { return; } Minimap instance = Minimap.instance; if ((Object)(object)instance == (Object)null || (Object)(object)ZNet.instance == (Object)null) { if ((Object)(object)_mm != (Object)null) { SaveStore(); Teardown(restoreVanillaTexture: false); } } else if (!_cfgEnabled.Value) { if ((Object)(object)_mm != (Object)null) { SaveStore(); Teardown(restoreVanillaTexture: true); } } else { if ((Object)(object)Player.m_localPlayer == (Object)null) { return; } bool flag = (Object)(object)_rt == (Object)null; bool flag2 = (Object)(object)_rt != (Object)null && ForestWanted != ((Object)(object)_rtMask != (Object)null); if ((!_ready || (Object)(object)_mm != (Object)(object)instance || flag || flag2 || (Object)(object)instance.m_mapTexture == (Object)null || _texSize != instance.m_textureSize || (Object)(object)_vanillaTex != (Object)(object)instance.m_mapTexture) && !Setup(instance)) { return; } float realtimeSinceStartup = Time.realtimeSinceStartup; Vector3 position = ((Component)Player.m_localPlayer).transform.position; if (realtimeSinceStartup >= _nextScanTime) { Vector3 val = position - _lastScanPos; bool flag3 = ((Vector3)(ref val)).sqrMagnitude >= 64f; bool flag4 = realtimeSinceStartup >= _lastScanTime + 10f; if (flag3 || flag4) { _nextScanTime = realtimeSinceStartup + 1f; _lastScanTime = realtimeSinceStartup; _lastScanPos = position; Scan(position); } else { _nextScanTime = realtimeSinceStartup + 0.25f; } } if (UseZdoScan && (_cfgShowBuildings.Value || _treeCount != null || (UseZdoPaths && _cfgShowPaths.Value))) { StepZdoScan(realtimeSinceStartup, position); } if (realtimeSinceStartup >= _nextRefogTime && (_fogPieces.Count > 0 || _fogTerrain.Count > 0 || _fogForest.Count > 0)) { _nextRefogTime = realtimeSinceStartup + 15f; ReleaseFromFog(); } if ((Object)(object)_rt != (Object)null) { if (!_rt.IsCreated()) { _rtDirty = true; } if ((Object)(object)_rtMask != (Object)null && !_rtMask.IsCreated()) { _maskDirty = true; } if (_cfgShowBuildings.Value != _drawnBuildings || _cfgShowPaths.Value != _drawnPaths || _cfgOutline.Value != _drawnOutline) { _rtDirty = true; } bool flag5 = _addPieces.Count > 0 || _addTerrain.Count > 0; if ((_rtDirty || flag5 || _maskDirty) && realtimeSinceStartup >= _nextRtRebuild) { _nextRtRebuild = realtimeSinceStartup + 0.5f; if (_rtDirty || (flag5 && (!_cfgIncremental.Value || _cfgDebugMarker.Value || _addPieces.Count > 1500 || _addTerrain.Count > 1500))) { _rtDirty = false; RebuildGpuLayer(); } else if (flag5) { DrawAdditions(); } if (_maskDirty && (Object)(object)_rt != (Object)null) { _maskDirty = false; RebuildMask(); } } } if (_cfgPersist.Value && _storeChanged && realtimeSinceStartup >= _nextSaveTime) { _nextSaveTime = realtimeSinceStartup + 60f; SaveStore(); } } } private bool Setup(Minimap mm) { //IL_01f4: Unknown result type (might be due to invalid IL or missing references) //IL_01f9: Unknown result type (might be due to invalid IL or missing references) if (_ready) { SaveStore(); } Teardown(restoreVanillaTexture: true); Texture2D mapTexture = mm.m_mapTexture; if ((Object)(object)mapTexture == (Object)null || mm.m_textureSize <= 0 || mm.m_pixelSize <= 0f) { return false; } if (((Texture)mapTexture).width != mm.m_textureSize || ((Texture)mapTexture).height != mm.m_textureSize) { return false; } _mm = mm; _vanillaTex = mapTexture; _texSize = mm.m_textureSize; _pixelSize = mm.m_pixelSize; MapPixelSize = _pixelSize; _colliderBuf = (Collider[])(object)new Collider[8192]; _worldUid = 0L; try { if ((Object)(object)ZNet.instance != (Object)null) { _worldUid = ZNet.instance.GetWorldUID(); } } catch (Exception e) { HandleError("Setup/GetWorldUID", e); } _pieces.Clear(); _terrain.Clear(); _pieceCount = 0; _storeChanged = false; _piecesOnlyPlayerBuilt = _cfgOnlyPlayerBuilt.Value; if (_cfgPersist.Value) { LoadStore(); } ResetZdoPass(); _zdoHavePrevOrigin = false; _nextZdoPass = 0f; InitForestLayer(); bool flag = false; if (!_gpuUnavailable) { try { flag = InitGpuLayer(); } catch (Exception e2) { _gpuUnavailable = true; ReleaseGpuLayer(); HandleError("GPU map layer", e2); } } if (!flag) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"The map layer could not be created on the graphics card; Living Map is off for this session and the vanilla map is untouched."); Teardown(restoreVanillaTexture: true); _disabledByErrors = true; return false; } ApplyTextureToMap((Texture)(object)_rt, rememberOriginals: true); if ((Object)(object)_rtMask != (Object)null) { ApplyMaskToMap((Texture)(object)_rtMask, rememberOriginals: true); } else { DropForestData(); } PokeMinimap(); _rtDirty = true; _maskDirty = (Object)(object)_rtMask != (Object)null; _nextRtRebuild = 0f; _lastScanPos = new Vector3(float.MinValue, 0f, float.MinValue); _nextScanTime = 0f; _lastScanTime = 0f; _nextSaveTime = Time.realtimeSinceStartup + 60f; _ready = true; ((BaseUnityPlugin)this).Logger.LogInfo((object)string.Format("Attached to map: vanilla {0}px at {1} m/px; map layer {2}; buildings via {3}; forest layers {4}; world={5}, restored pieces={6}, terrain cells={7}, forest pixels cleared={8} planted={9}", _texSize, _pixelSize.ToString("0.##"), ((Texture)_rt).width + "px on the GPU = " + (_pixelSize / (float)_rtScale).ToString("0.##") + " m/px", UseZdoScan ? "the object database (ZDO)" : "physics", ((_treeCount != null) ? "on" : "off") + "; paths via " + (UseZdoPaths ? "terrain records (ZDO)" : "loaded heightmaps"), _worldUid, _pieceCount, _terrain.Count, _clearedForest.Count, _plantedForest.Count)); return true; } private void Teardown(bool restoreVanillaTexture) { if (restoreVanillaTexture && (Object)(object)_mm != (Object)null) { try { RestoreOriginalTextures(); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Could not restore the vanilla map texture: " + ex.Message)); } } ReleaseGpuLayer(); _mm = null; _vanillaTex = null; _origSmallTex = null; _origLargeTex = null; _vanillaMask = null; _origSmallMask = null; _origLargeMask = null; DropForestData(); _clearedForest.Clear(); _plantedForest.Clear(); _trustedZones.Clear(); _forestBiome.Clear(); _colliderBuf = null; _texSize = 0; _pixelSize = 0f; _ready = false; _pieces.Clear(); _terrain.Clear(); _pieceCount = 0; _circleScratch.Clear(); _scanBuckets.Clear(); _terrainScratch.Clear(); ResetZdoPass(); _prefabCache.Clear(); } private void ApplyTextureToMap(Texture tex, bool rememberOriginals) { if ((Object)(object)_mm == (Object)null) { return; } if ((Object)(object)_mm.m_mapImageSmall != (Object)null && (Object)(object)((Graphic)_mm.m_mapImageSmall).material != (Object)null) { if (rememberOriginals) { _origSmallTex = ((Graphic)_mm.m_mapImageSmall).material.GetTexture("_MainTex"); } ((Graphic)_mm.m_mapImageSmall).material.SetTexture("_MainTex", tex); } if ((Object)(object)_mm.m_mapImageLarge != (Object)null && (Object)(object)((Graphic)_mm.m_mapImageLarge).material != (Object)null) { if (rememberOriginals) { _origLargeTex = ((Graphic)_mm.m_mapImageLarge).material.GetTexture("_MainTex"); } ((Graphic)_mm.m_mapImageLarge).material.SetTexture("_MainTex", tex); } } private void PokeMinimap() { if ((Object)(object)_mm != (Object)null && (Object)(object)_mm.m_smallRoot != (Object)null && _mm.m_smallRoot.activeSelf) { _mm.m_smallRoot.SetActive(false); _mm.m_smallRoot.SetActive(true); } } private void ApplyMaskToMap(Texture tex, bool rememberOriginals) { if ((Object)(object)_mm == (Object)null) { return; } if ((Object)(object)_mm.m_mapImageSmall != (Object)null && (Object)(object)((Graphic)_mm.m_mapImageSmall).material != (Object)null) { if (rememberOriginals) { _origSmallMask = ((Graphic)_mm.m_mapImageSmall).material.GetTexture("_MaskTex"); } ((Graphic)_mm.m_mapImageSmall).material.SetTexture("_MaskTex", tex); } if ((Object)(object)_mm.m_mapImageLarge != (Object)null && (Object)(object)((Graphic)_mm.m_mapImageLarge).material != (Object)null) { if (rememberOriginals) { _origLargeMask = ((Graphic)_mm.m_mapImageLarge).material.GetTexture("_MaskTex"); } ((Graphic)_mm.m_mapImageLarge).material.SetTexture("_MaskTex", tex); } } private void RestoreOriginalTextures() { if ((Object)(object)_mm == (Object)null) { return; } if ((Object)(object)_mm.m_mapImageSmall != (Object)null && (Object)(object)((Graphic)_mm.m_mapImageSmall).material != (Object)null) { ((Graphic)_mm.m_mapImageSmall).material.SetTexture("_MainTex", (Texture)(((Object)(object)_origSmallTex != (Object)null) ? ((object)_origSmallTex) : ((object)_vanillaTex))); if ((Object)(object)_origSmallMask != (Object)null) { ((Graphic)_mm.m_mapImageSmall).material.SetTexture("_MaskTex", _origSmallMask); } } if ((Object)(object)_mm.m_mapImageLarge != (Object)null && (Object)(object)((Graphic)_mm.m_mapImageLarge).material != (Object)null) { ((Graphic)_mm.m_mapImageLarge).material.SetTexture("_MainTex", (Texture)(((Object)(object)_origLargeTex != (Object)null) ? ((object)_origLargeTex) : ((object)_vanillaTex))); if ((Object)(object)_origLargeMask != (Object)null) { ((Graphic)_mm.m_mapImageLarge).material.SetTexture("_MaskTex", _origLargeMask); } } PokeMinimap(); } private Color TerrainColor(byte kind) { //IL_000a: 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_0036: 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) return (Color)(kind switch { 2 => _cfgPavedColor.Value, 3 => _cfgDirtColor.Value, 1 => _cfgCultivatedColor.Value, _ => _cfgClearedColor.Value, }); } private Color MatColor(byte mat) { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) if (mat != byte.MaxValue && mat < _cfgMatColor.Length) { return _cfgMatColor[mat].Value; } return _cfgMatUnknownColor.Value; } private static bool IsExplored(BitArray explored, BitArray exploredOthers, int idx) { if (explored == null && exploredOthers == null) { return true; } if (explored != null && idx < explored.Length && explored[idx]) { return true; } if (exploredOthers != null && idx < exploredOthers.Length && exploredOthers[idx]) { return true; } return false; } private bool IsWorldExplored(BitArray explored, BitArray exploredOthers, float wx, float wz) { //IL_0018: Unknown result type (might be due to invalid IL or missing references) if (!_cfgRespectFog.Value) { return true; } if (!WorldToIndex(new Vector3(wx, 0f, wz), out var idx)) { return false; } return IsExplored(explored, exploredOthers, idx); } private bool WorldToIndex(Vector3 world, out int idx) { idx = -1; if (_texSize <= 0 || _pixelSize <= 0f) { return false; } float num = (float)_texSize * 0.5f; int num2 = Mathf.RoundToInt(world.x / _pixelSize + num); int num3 = Mathf.RoundToInt(world.z / _pixelSize + num); if (num2 < 0 || num3 < 0 || num2 >= _texSize || num3 >= _texSize) { return false; } idx = num3 * _texSize + num2; return true; } private void CollectPixelsInCircle(Vector3 center, float radius, List<int> result) { result.Clear(); float num = (float)_texSize * 0.5f; int num2 = Mathf.RoundToInt(center.x / _pixelSize + num); int num3 = Mathf.RoundToInt(center.z / _pixelSize + num); int num4 = Mathf.CeilToInt(radius / _pixelSize) + 1; float num5 = radius * radius; for (int i = num3 - num4; i <= num3 + num4; i++) { if (i < 0 || i >= _texSize) { continue; } for (int j = num2 - num4; j <= num2 + num4; j++) { if (j >= 0 && j < _texSize) { float num6 = ((float)j - num) * _pixelSize; float num7 = ((float)i - num) * _pixelSize; float num8 = num6 - center.x; float num9 = num7 - center.z; if (!(num8 * num8 + num9 * num9 > num5)) { result.Add(i * _texSize + j); } } } } } private void MigrateFromMapOverlay() { try { string text = Path.Combine(Paths.ConfigPath, "j1ga.mapoverlay.cfg"); if (!File.Exists(((BaseUnityPlugin)this).Config.ConfigFilePath) && File.Exists(text)) { File.Copy(text, ((BaseUnityPlugin)this).Config.ConfigFilePath); ((BaseUnityPlugin)this).Config.Reload(); ((BaseUnityPlugin)this).Logger.LogInfo((object)("Copied the MapOverlay settings to " + Path.GetFileName(((BaseUnityPlugin)this).Config.ConfigFilePath) + ".")); } } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Could not carry the MapOverlay settings over: " + ex.Message)); } } private void MigrateStoreFromMapOverlay(string path) { try { string text = Path.Combine(Path.Combine(Paths.ConfigPath, "MapOverlay"), _worldUid + ".bin"); if (!File.Exists(path) && File.Exists(text)) { string directoryName = Path.GetDirectoryName(path); if (!string.IsNullOrEmpty(directoryName) && !Directory.Exists(directoryName)) { Directory.CreateDirectory(directoryName); } File.Copy(text, path); ((BaseUnityPlugin)this).Logger.LogInfo((object)("Copied the MapOverlay data for this world to " + path + ".")); } } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Could not carry the MapOverlay data over: " + ex.Message)); } } private bool OldPluginLoaded() { _oldPluginChecked = true; bool flag = false; try { flag = Chainloader.PluginInfos.ContainsKey("j1ga.mapoverlay"); } catch { } if (!flag) { return false; } _disabledByErrors = true; ((BaseUnityPlugin)this).Logger.LogError((object)"The old MapOverlay plugin is loaded as well. Living Map is the same mod renamed; remove BepInEx\\plugins\\MapOverlay\\MapOverlay.dll. Living Map stays inert until then."); return true; } private void LogOnce(string key, string message) { if (_loggedErrors.Add("once:" + key)) { ((BaseUnityPlugin)this).Logger.LogWarning((object)message); } } private void HandleError(string where, Exception e) { _errorCount++; string item = where + "|" + ((e != null) ? (e.GetType().Name + "|" + e.Message) : "null"); if (_loggedErrors.Add(item)) { ((BaseUnityPlugin)this).Logger.LogError((object)("[" + where + "] " + e)); } if (_errorCount >= 25 && !_disabledByErrors) { _disabledByErrors = true; ((BaseUnityPlugin)this).Logger.LogError((object)"Too many errors, Living Map is switching itself off for this session. The game is unaffected."); try { Teardown(restoreVanillaTexture: true); } catch { } } } private void InitForestLayer() { DropForestData(); if ((Object)(object)_mm == (Object)null || !ForestWanted) { if ((_cfgShowForest.Value || _cfgShowPlanted.Value) && !_forestDisabled && !UseZdoScan) { LogOnce("forestzdo", "The forest layers need BuildingScanSource = ZDO and are off."); } return; } try { Texture2D val = null; if ((Object)(object)_mm.m_mapImageLarge != (Object)null && (Object)(object)((Graphic)_mm.m_mapImageLarge).material != (Object)null) { Texture texture = ((Graphic)_mm.m_mapImageLarge).material.GetTexture("_MaskTex"); val = (Texture2D)(object)((texture is Texture2D) ? texture : null); } if ((Object)(object)val == (Object)null || ((Texture)val).width != _texSize || ((Texture)val).height != _texSize) { _forestDisabled = true; ((BaseUnityPlugin)this).Logger.LogWarning((object)"The map's forest mask is missing or has an unexpected size; the cleared-forest layer is off."); return; } Color32[] pixels = val.GetPixels32(); BitArray bitArray = new BitArray(pixels.Length); int num = 0; for (int i = 0; i < pixels.Length; i++) { if (pixels[i].r > 127) { bitArray[i] = true; num++; } } _vanillaMask = val; _forestMask = bitArray; _pixelTrusted = new BitArray(pixels.Length); _treeCount = new byte[pixels.Length]; if (_cfgDebug.Value) { ((BaseUnityPlugin)this).Logger.LogInfo((object)("Forest mask read: " + num + " forest pixels.")); } } catch (Exception e) { _forestDisabled = true; DropForestData(); HandleError("forest mask", e); ((BaseUnityPlugin)this).Logger.LogWarning((object)"Could not read the map's forest mask; the cleared-forest layer is off."); } } private void DropForestData() { _forestMask = null; _pixelTrusted = null; _treeCount = null; _trustedZoneScratch.Clear(); _outsideCounts.Clear(); _forestCursor = -1; } private bool IsTreePrefab(GameObject prefab) { if ((Object)(object)prefab.GetComponent<TreeBase>() == (Object)null) { return false; } if (_cfgDebug.Value) { ((BaseUnityPlugin)this).Logger.LogInfo((object)("Tree prefab: " + ((Object)prefab).name)); } return true; } private static int ZoneKey(int zx, int zy) { return (zx << 16) | (zy & 0xFFFF); } private void ForestError(Exception e) { HandleError("cleared forest", e); DropForestData(); _forestDisabled = true; ((BaseUnityPlugin)this).Logger.LogWarning((object)"The cleared-forest layer failed and is off for this session. Buildings and paths keep working."); } private int BeginForestEval() { //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_0113: 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_011a: 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_011f: Unknown result type (might be due to invalid IL or missing references) //IL_012b: Unknown result type (might be due to invalid IL or missing references) //IL_012e: Unknown result type (might be due to invalid IL or missing references) _forestCursor = -1; _forestChanged = false; _forestAdded = 0; _forestRemoved = 0; _forestMs = 0.0; _forestSample.Clear(); _pixelTrusted.SetAll(value: false); _trustedZoneScratch.Clear(); HashSet<Vector2s> hashSet = null; if (_zdoAuthoritative && _fiGeneratedZones != null && (Object)(object)ZoneSystem.instance != (Object)null) { hashSet = _fiGeneratedZones.GetValue(ZoneSystem.instance) as HashSet<Vector2s>; } if (hashSet != null) { foreach (Vector2s item in hashSet) { _trustedZoneScratch.Add(ZoneKey(item.x, item.y)); } } else { if (_zdoHavePrevOrigin) { Vector2s zone = ZoneSystem.GetZone(_zdoPassOrigin); Vector2s val = default(Vector2s); for (int i = -4; i <= 4; i++) { for (int j = -4; j <= 4; j++) { ((Vector2s)(ref val))..ctor(zone.x + j, zone.y + i); Vector3 zonePos = ZoneSystem.GetZonePos(val); if (ZNetScene.InActiveArea(zonePos, _zdoPassOrigin) && ZNetScene.InActiveArea(zonePos, _zdoPrevOrigin)) { _trustedZones.Add(ZoneKey(val.x, val.y)); } } } } foreach (int trustedZone in _trustedZones) { _trustedZoneScratch.Add(trustedZone); } } int count = _trustedZoneScratch.Count; if (count == 0) { return 0; } float half = (float)_texSize * 0.5f; for (int k = 0; k < count; k++) { ZonePixelRange(_trustedZoneScratch[k], half, out var px, out var py, out var px2, out var py2); for (int l = py; l <= py2; l++) { for (int m = px; m <= px2; m++) { _pixelTrusted[l * _texSize + m] = true; } } } if (!_cfgShowForest.Value) { if (_clearedForest.Count > 0) { _clearedForest.Clear(); _forestChanged = true; } return 0; } _forestCursor = 0; return count; } private bool UpdatePlantedForest() { if (!_cfgShowPlanted.Value) { if (_plantedForest.Count == 0) { return false; } _plantedForest.Clear(); return true; } int num = Mathf.Max(1, _cfgPlantedMinTrees.Value); int num2 = 0; int num3 = 0; foreach (KeyValuePair<int, int> outsideCount in _outsideCounts) { if (outsideCount.Value >= num && _plantedForest.Add(outsideCount.Key)) { num2++; if (_forestSample.Count < 6) { _forestSample.Add(outsideCount.Key); } } } _removeScratch.Clear(); foreach (int item in _plantedForest) { if ((!_outsideCounts.TryGetValue(item, out var value) || value < num) && (_zdoAuthoritative || _pixelTrusted[item])) { _removeScratch.Add(item); } } for (int i = 0; i < _removeScratch.Count; i++) { if (_plantedForest.Remove(_removeScratch[i])) { num3++; } } _removeScratch.Clear(); if (_cfgDebug.Value && (num2 > 0 || num3 > 0)) { ((BaseUnityPlugin)this).Logger.LogInfo((object)$"Planted forest: {_plantedForest.Count} pixels (+{num2}, -{num3}), {_outsideCounts.Count} tree pixels outside the vanilla forest, {_forestBiome.Count} biome lookups cached{SampleText()}"); } else { _forestSample.Clear(); } if (num2 <= 0) { return num3 > 0; } return true; } private bool PixelCanHoldForest(int idx) { //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_007f: 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_0084: Invalid comparison between Unknown and I4 //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Invalid comparison between Unknown and I4 //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Invalid comparison between Unknown and I4 if (_cfgPlantedAnyBiome.Value) { return true; } if (_forestBiome.TryGetValue(idx, out var value)) { return value; } WorldGenerator instance = WorldGenerator.instance; if (instance == null) { return false; } _biomeLookupsThisFrame++; float num = (float)_texSize * 0.5f; Vector3 val = default(Vector3); ((Vector3)(ref val))..ctor(((float)(idx % _texSize) - num) * _pixelSize, 0f, ((float)(idx / _texSize) - num) * _pixelSize); Biome biome = instance.GetBiome(val); value = (int)biome == 1 || (int)biome == 8 || (int)biome == 16; _forestBiome[idx] = value; return value; } private void StepForestEval() { if (_forestCursor < 0) { return; } if (_pixelTrusted == null || _treeCount == null || _forestMask == null) { _forestCursor = -1; return; } try { _sw.Restart(); float half = (float)_texSize * 0.5f; int r = Mathf.Max(1, Mathf.CeilToInt(_cfgForestRadius.Value / _pixelSize)); int maxTrees = Mathf.Max(0, _cfgForestMaxTrees.Value); int num = Mathf.Min(_trustedZoneScratch.Count, _forestCursor + 150); while (_forestCursor < num) { EvalForestZone(_trustedZoneScratch[_forestCursor], half, r, maxTrees); _forestCursor++; } _forestMs += _sw.Elapsed.TotalMilliseconds; if (_forestCursor < _trustedZoneScratch.Count) { return; } _forestCursor = -1; if (_forestChanged) { _storeChanged = true; _maskDirty = true; if (_cfgDebug.Value) { ((BaseUnityPlugin)this).Logger.LogInfo((object)$"Cleared forest: {_clearedForest.Count} pixels (+{_forestAdded}, -{_forestRemoved}) over {_trustedZoneScratch.Count} zones, {_forestMs:0.0} ms CPU{SampleText()}"); } } } catch (Exception e) { ForestError(e); } } private void EvalForestZone(int key, float half, int r, int maxTrees) { ZonePixelRange(key, half, out var px, out var py, out var px2, out var py2); for (int i = py; i <= py2; i++) { for (int j = px; j <= px2; j++) { int num = i * _texSize + j; bool flag = false; if (_forestMask[num]) { flag = true; int num2 = 0; for (int k = i - r; k <= i + r; k++) { if (!flag) { break; } if (k < 0 || k >= _texSize) { flag = false; break; } int num3 = k * _texSize; for (int l = j - r; l <= j + r; l++) { if (l < 0 || l >= _texSize || !_pixelTrusted[num3 + l]) { flag = false; break; } num2 += _treeCount[num3 + l]; if (num2 > maxTrees) { flag = false; break; } } } } if (flag) { if (_clearedForest.Add(num)) { _forestChanged = true; _forestAdded++; if (_forestSample.Count < 6) { _forestSample.Add(num); } } } else if (_clearedForest.Remove(num)) { _forestChanged = true; _forestRemoved++; } } } } private string SampleText() { if (_forestSample.Count == 0) { return ""; } float num = (float)_texSize * 0.5f; StringBuilder stringBuilder = new StringBuilder(", e.g. at"); for (int i = 0; i < _forestSample.Count; i++) { int num2 = _forestSample[i]; stringBuilder.Append($" ({((float)(num2 % _texSize) - num) * _pixelSize:0}, {((float)(num2 / _texSize) - num) * _pixelSize:0})"); } _forestSample.Clear(); return stringBuilder.ToString(); } private void ZonePixelRange(int key, float half, out int px0, out int py0, out int px1, out int py1) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) Vector3 zonePos = ZoneSystem.GetZonePos(new Vector2s((short)(key >> 16), (short)(key & 0xFFFF))); px0 = Mathf.Clamp(Mathf.CeilToInt((zonePos.x - 32f) / _pixelSize + half), 0, _texSize - 1); px1 = Mathf.Clamp(Mathf.CeilToInt((zonePos.x + 32f) / _pixelSize + half) - 1, 0, _texSize - 1); py0 = Mathf.Clamp(Mathf.CeilToInt((zonePos.z - 32f) / _pixelSize + half), 0, _texSize - 1); py1 = Mathf.Clamp(Mathf.CeilToInt((zonePos.z + 32f) / _pixelSize + half) - 1, 0, _texSize - 1); } private bool InitGpuLayer() { //IL_0237: Unknown result type (might be due to invalid IL or missing references) //IL_023e: Expected O, but got Unknown //IL_0262: Unknown result type (might be due to invalid IL or missing references) //IL_0274: Unknown result type (might be due to invalid IL or missing references) //IL_0117: Unknown result type (might be due to invalid IL or missing references) //IL_011e: Expected O, but got Unknown //IL_0142: Unknown result type (might be due to invalid IL or missing references) //IL_0154: Unknown result type (might be due to invalid IL or missing references) //IL_0294: Unknown result type (might be due to invalid IL or missing references) //IL_029e: Expected O, but got Unknown //IL_0302: Unknown result type (might be due to invalid IL or missing references) //IL_030c: Expected O, but got Unknown //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Invalid comparison between Unknown and I4 //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Expected O, but got Unknown if (!SystemInfo.supportsRenderTextures) { return false; } Shader val = Shader.Find("Hidden/Internal-Colored"); if ((Object)(object)val == (Object)null) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"The built-in colored shader is missing, cannot render the map layer on the GPU."); return false; } int num = Mathf.Clamp(_cfgMapScale.Value, 1, 8); int num2 = ((SystemInfo.maxTextureSize > 0) ? SystemInfo.maxTextureSize : 8192); while (_texSize * num > num2 && num > 1) { num /= 2; } if (_texSize * num > num2) { return false; } LinearColors = _cfgLinearFix.Value && (int)QualitySettings.activeColorSpace == 1; _glMat = new Material(val); ((Object)_glMat).hideFlags = (HideFlags)61; _glMat.SetInt("_SrcBlend", 5); _glMat.SetInt("_DstBlend", 10); _glMat.SetInt("_Cull", 0); _glMat.SetInt("_ZWrite", 0); _glMat.SetInt("_ZTest", 8); while (num >= 1) { int num3 = _texSize * num; RenderTexture val2 = new RenderTexture(num3, num3, 0, (RenderTextureFormat)0); ((Object)val2).name = "LivingMap_MapTexture"; val2.useMipMap = false; val2.autoGenerateMips = false; ((Texture)val2).filterMode = ((Texture)_vanillaTex).filterMode; ((Texture)val2).wrapMode = ((Texture)_vanillaTex).wrapMode; bool flag = false; try { flag = val2.Create(); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Could not create a " + num3 + "px map texture: " + ex.Message)); } if (flag) { _rt = val2; break; } try { Object.Destroy((Object)(object)val2); } catch { } ((BaseUnityPlugin)this).Logger.LogWarning((object)("The card refused a " + num3 + "px map texture, stepping down.")); if (num == 1) { break; } num /= 2; } if ((Object)(object)_rt == (Object)null) { ReleaseGpuLayer(); return false; } _rtScale = num; _rtRebuilds = 0; if (_forestMask != null) { try { RenderTexture val3 = new RenderTexture(_texSize, _texSize, 0, (RenderTextureFormat)0); ((Object)val3).name = "LivingMap_ForestMask"; val3.useMipMap = false; val3.autoGenerateMips = false; ((Texture)val3).filterMode = ((Texture)_vanillaMask).filterMode; ((Texture)val3).wrapMode = ((Texture)_vanillaMask).wrapMode; if (val3.Create()) { _rtMask = val3; _glMatMask = new Material(val); ((Object)_glMatMask).hideFlags = (HideFlags)61; _glMatMask.SetInt("_SrcBlend", 2); _glMatMask.SetInt("_DstBlend", 0); _glMatMask.SetInt("_Cull", 0); _glMatMask.SetInt("_ZWrite", 0); _glMatMask.SetInt("_ZTest", 8); _glMatMaskAdd = new Material(val); ((Object)_glMatMaskAdd).hideFlags = (HideFlags)61; _glMatMaskAdd.SetInt("_SrcBlend", 1); _glMatMaskAdd.SetInt("_DstBlend", 1); _glMatMaskAdd.SetInt("_Cull", 0); _glMatMaskAdd.SetInt("_ZWrite", 0); _glMatMaskAdd.SetInt("_ZTest", 8); } else { try { Object.Destroy((Object)(object)val3); } catch { } } } catch (Exception e) { HandleError("forest mask texture", e); _rtMask = null; } if ((Object)(object)_rtMask == (Object)null) { _forestDisabled = true; ((BaseUnityPlugin)this).Logger.LogWarning((object)"The card refused the forest mask texture; the cleared-forest layer is off for this session."); } } RebuildGpuLayer(); if ((Object)(object)_rtMask != (Object)null) { RebuildMask(); } return true; } private void ReleaseGpuLayer() { if ((Object)(object)_rt != (Object)null) { try { _rt.Release(); Object.Destroy((Object)(object)_rt); } catch { } _rt = null; } if ((Object)(object)_glMat != (Object)null) { try { Object.Destroy((Object)(object)_glMat); } catch { } _glMat = null; } if ((Object)(object)_rtMask != (Object)null) { try { _rtMask.Release(); Object.Destroy((Object)(object)_rtMask); } catch { } _rtMask = null; } if ((Object)(object)_glMatMask != (Object)null) { try { Object.Destroy((Object)(object)_glMatMask); } catch { } _glMatMask = null; } if ((Object)(object)_glMatMaskAdd != (Object)null) { try { Object.Destroy((Object)(object)_glMatMaskAdd); } catch { } _glMatMaskAdd = null; } _rtScale = 1; _rtDirty = false; _maskDirty = false; _addPieces.Clear(); _addTerrain.Clear(); _fogPieces.Clear(); _fogTerrain.Clear(); _fogForest.Clear(); } private void RebuildGpuLayer() { //IL_04cc: Unknown result type (might be due to invalid IL or missing references) //IL_04d1: Unknown result type (might be due to invalid IL or missing references) //IL_051b: Unknown result type (might be due to invalid IL or missing references) //IL_0578: Unknown result type (might be due to invalid IL or missing references) //IL_0318: Unknown result type (might be due to invalid IL or missing references) //IL_031d: Unknown result type (might be due to invalid IL or missing references) //IL_027f: Unknown result type (might be due to invalid IL or missing references) //IL_045d: Unknown result type (might be due to invalid IL or missing references) //IL_0393: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_rt == (Object)null || (Object)(object)_glMat == (Object)null || (Object)(object)_vanillaTex == (Object)null) { return; } try { if (!_rt.IsCreated() && !_rt.Create()) { return; } _sw.Restart(); Graphics.Blit((Texture)(object)_vanillaTex, _rt); _addPieces.Clear(); _addTerrain.Clear(); _fogPieces.Clear(); _fogTerrain.Clear(); _drawnBuildings = _cfgShowBuildings.Value; _drawnPaths = _cfgShowPaths.Value; _drawnOutline = _cfgOutline.Value; BitArray explored = null; BitArray exploredOthers = null; if (_cfgRespectFog.Value) { explored = ((_fiExplored != null) ? (_fiExplored.GetValue(_mm) as BitArray) : null); exploredOthers = ((_fiExploredOthers != null) ? (_fiExploredOthers.GetValue(_mm) as BitArray) : null); } float k = (float)((Texture)_rt).width / (float)_texSize; float half = (float)_texSize * 0.5f; bool value = _cfgMapFlipY.Value; int height = ((Texture)_rt).height; int num = 0; RenderTexture active = RenderTexture.active; RenderTexture.active = _rt; GL.PushMatrix(); GL.LoadPixelMatrix(0f, (float)((Texture)_rt).width, 0f, (float)height); _glMat.SetPass(0); GL.Begin(7); if (_cfgShowPaths.Value && _terrain.Count > 0) { float num2 = Mathf.Max(0.5f, _cfgTerrainGrid.Value); float num3 = num2 * 0.5f; foreach (KeyValuePair<long, byte> item2 in _terrain) { int num4 = (int)(item2.Key >> 32); int num5 = (int)(item2.Key & 0xFFFFFFFFu); float num6 = ((float)num4 + 0.5f) * num2; float num7 = ((float)num5 + 0.5f) * num2; if (!IsWorldExplored(explored, exploredOthers, num6, num7)) { _fogTerrain.Add(item2.Key); continue; } EmitQuad(num6 - num3, num7 - num3, num6 + num3, num7 + num3, TerrainColor(item2.Value), k, half, height, value, num2); num++; } } if (_cfgShowBuildings.Value && _pieces.Count > 0) { float num8 = Mathf.Max(0.1f, _cfgPieceSize.Value); if (_cfgOutline.Value) { float num9 = Mathf.Max(0f, _cfgOutlineWidth.Value); Color value2 = _cfgOutlineColor.Value; foreach (KeyValuePair<int, List<PieceRec>> piece in _pieces) { List<PieceRec> value3 = piece.Value; for (int i = 0; i < value3.Count; i++) { PieceRec pieceRec = value3[i]; if (IsWorldExplored(explored, exploredOthers, pieceRec.CX, pieceRec.CZ)) { EmitQuad(pieceRec.X0 - num9, pieceRec.Z0 - num9, pieceRec.X1 + num9, pieceRec.Z1 + num9, value2, k, half, height, value, num8 + num9 * 2f); num++; } } } } foreach (KeyValuePair<int, List<PieceRec>> piece2 in _pieces) { List<PieceRec> value4 = piece2.Value; for (int j = 0; j < value4.Count; j++) { PieceRec item = value4[j]; if (!IsWorldExplored(explored, exploredOthers, item.CX, item.CZ)) { _fogPieces.Add(item); continue; } EmitQuad(item.X0, item.Z0, item.X1, item.Z1, MatColor(item.Mat), k, half, height, value, num8); num++; } } } if (_cfgDebugMarker.Value && (Object)(object)Player.m_localPlayer != (Object)null) { Vector3 position = ((Component)Player.m_localPlayer).transform.position; EmitQuad(position.x - 12f, position.z - 2f, position.x + 12f, position.z + 2f, new Color(1f, 0f, 1f, 1f), k, half, height, value, 0f); EmitQuad(position.x - 2f, position.z - 12f, position.x + 2f, position.z + 12f, new Color(1f, 0f, 1f, 1f), k, half, height, value, 0f); } GL.End(); GL.PopMatrix(); RenderTexture.active = active; _rtRebuilds++; if (_rtRebuilds == 1 || (_cfgDebug.Value && _rtRebuilds % 20 == 1)) { ((BaseUnityPlugin)this).Logger.LogInfo((object)string.Format("Map layer rebuilt on the GPU: {0}px ({1:0.##} m/px), {2} shapes drawn, {3} held back by fog, {4:0} MB of video memory, linear colours {5}, {6:0.0} ms CPU", ((Texture)_rt).width, _pixelSize / (float)_rtScale, num, _fogPieces.Count + _fogTerrain.Count, (float)(((long)((Texture)_rt).width * (long)((Texture)_rt).height + (((Object)(object)_rtMask != (Object)null) ? ((long)((Texture)_rtMask).width * (long)((Texture)_rtMask).height) : 0)) * 4) / 1048576f, LinearColors ? "on" : "off", _sw.Elapsed.TotalMilliseconds)); } } catch (Exception e) { GpuFailed("GPU map layer rebuild", e); } } private void DrawAdditions() { //IL_01f8: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_rt == (Object)null || (Object)(object)_glMat == (Object)null) { return; } try { if (!_rt.IsCreated()) { _rtDirty = true; return; } _sw.Restart(); BitArray explored = null; BitArray exploredOthers = null; if (_cfgRespectFog.Value) { explored = ((_fiExplored != null) ? (_fiExplored.GetValue(_mm) as BitArray) : null); exploredOthers = ((_fiExploredOthers != null) ? (_fiExploredOthers.GetValue(_mm) as BitArray) : null); } float k = (float)((Texture)_rt).width / (float)_texSize; float half = (float)_texSize * 0.5f; bool value = _cfgMapFlipY.Value; int height = ((Texture)_rt).height; int num = 0; int num2 = 0; int num3 = 0; RenderTexture active = RenderTexture.active; RenderTexture.active = _rt; GL.PushMatrix(); GL.LoadPixelMatrix(0f, (float)((Texture)_rt).width, 0f, (float)height); _glMat.SetPass(0); GL.Begin(7); if (_addTerrain.Count > 0) { float num4 = Mathf.Max(0.5f, _cfgTerrainGrid.Value); float num5 = num4 * 0.5f; for (int i = 0; i < _addTerrain.Count; i++) { long num6 = _addTerrain[i]; if (!_terrain.TryGetValue(num6, out var value2)) { continue; } float num7 = ((float)(int)(num6 >> 32) + 0.5f) * num4; float num8 = ((float)(int)(num6 & 0xFFFFFFFFu) + 0.5f) * num4; if (!IsWorldExplored(explored, exploredOthers, num7, num8)) { _fogTerrain.Add(num6); } else { if (!_cfgShowPaths.Value) { continue; } EmitQuad(num7 - num5, num8 - num5, num7 + num5, num8 + num5, TerrainColor(value2), k, half, height, value, num4); num++; num2++; if (_cfgShowBuildings.Value) { _groupScratch.Clear(); PiecesIntersecting(num7 - num5, num8 - num5, num7 + num5, num8 + num5, withHalo: true, _groupScratch); if (_groupScratch.Count > 0) { num += DrawPieceGroup(_groupScratch, explored, exploredOthers, k, half, height, value); } } } } _addTerrain.Clear(); } if (_addPieces.Count > 0) { for (int j = 0; j < _addPieces.Count; j++) { PieceRec item = _addPieces[j]; if (!IsWorldExplored(explored, exploredOthers, item.CX, item.CZ)) { _fogPieces.Add(item); } else if (_cfgShowBuildings.Value) { _groupScratch.Clear(); _groupScratch.Add(item); num += DrawPieceGroup(_groupScratch, explored, exploredOthers, k, half, height, value); num3++; } } _addPieces.Clear(); } GL.End(); GL.PopMatrix(); RenderTexture.active = active; _rtIncrements++; if (_cfgDebug.Value && (_rtIncrements == 1 || _rtIncrements % 20 == 0)) { ((BaseUnityPlugin)this).Logger.LogInfo((object)$"Map layer updated in place: {num3} new pieces, {num2} new cells, {num} quads, {_sw.Elapsed.TotalMilliseconds:0.00} ms CPU (update #{_rtIncrements})"); } } catch (Exception e) { GpuFailed("GPU map layer update", e); } } private int DrawPieceGroup(List<PieceRec> group, BitArray explored, BitArray exploredOthers, float k, float half, int h, bool flip) { //IL_01b9: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Unknown result type (might be due to invalid IL or missing references) float num = Mathf.Max(0.1f, _cfgPieceSize.Value); float num2 = (_cfgOutline.Value ? Mathf.Max(0f, _cfgOutlineWidth.Value) : 0f); int num3 = 0; float num4 = float.MaxValue; float num5 = float.MaxValue; float num6 = float.MinValue; float num7 = float.MinValue; for (int i = 0; i < group.Count; i++) { PieceRec rec = group[i]; DrawnRect(rec, num2, num + num2 * 2f, out var x, out var z, out var x2, out var z2); if (x < num4) { num4 = x; } if (z < num5) { num5 = z; } if (x2 > num6) { num6 = x2; } if (z2 > num7) { num7 = z2; } if (_cfgOutline.Value && IsWorldExplored(explored, exploredOthers, rec.CX, rec.CZ)) { EmitQuad(rec.X0 - num2, rec.Z0 - num2, rec.X1 + num2, rec.Z1 + num2, _cfgOutlineColor.Value, k, half, h, flip, num + num2 * 2f); num3++; } } _fillScratch.Clear(); if (_cfgOutline.Value) { PiecesIntersecting(num4, num5, num6, num7, withHalo: false, _fillScratch); } else { _fillScratch.AddRange(group); } for (int j = 0; j < _fillScratch.Count; j++) { PieceRec pieceRec = _fillScratch[j]; if (IsWorldExplored(explored, exploredOthers, pieceRec.CX, pieceRec.CZ)) { EmitQuad(pieceRec.X0, pieceRec.Z0, pieceRec.X1, pieceRec.Z1, MatColor(pieceRec.Mat), k, half, h, flip, num); num3++; } } return num3; } private static void DrawnRect(PieceRec rec, float grow, float minWorld, out float x0, out float z0, out float x1, out float z1) { x0 = rec.X0 - grow; x1 = rec.X1 + grow; z0 = rec.Z0 - grow; z1 = rec.Z1 + grow; if (x1 - x0 < minWorld) { float num = (x0 + x1) * 0.5f; x0 = num - minWorld * 0.5f; x1 = num + minWorld * 0.5f; } if (z1 - z0 < minWorld) { float num2 = (z0 + z1) * 0.5f; z0 = num2 - minWorld * 0.5f; z1 = num2 + minWorld * 0.5f; } } private void PiecesIntersecting(float x0, float z0, float x1, float z1, bool withHalo, List<PieceRec> result) { float num = Mathf.Max(0.1f, _cfgPieceSize.Value); float num2 = (_cfgOutline.Value ? Mathf.Max(0f, _cfgOutlineWidth.Value) : 0f); float num3 = 16f + num2 + num; float num4 = (float)_texSize * 0.5f; int num5 = Mathf.Clamp(Mathf.FloorToInt((x0 - num3) / _pixelSize + num4), 0, _texSize - 1); int num6 = Mathf.Clamp(Mathf.CeilToInt((x1 + num3) / _pixelSize + num4), 0, _texSize - 1); int num7 = Mathf.Clamp(Mathf.FloorToInt((z0 - num3) / _pixelSize + num4), 0, _texSize - 1); int num8 = Mathf.Clamp(Mathf.CeilToInt((z1 + num3) / _pixelSize + num4), 0, _texSize - 1); float grow = (withHalo ? num2 : 0f); float minWorld = (withHalo ? (num + num2 * 2f) : num); for (int i = num7; i <= num8; i++) { for (int j = num5; j <= num6; j++) { if (!_pieces.TryGetValue(i * _texSize + j, out var value)) { continue; } for (int k = 0; k < value.Count; k++) { PieceRec pieceRec = value[k]; DrawnRect(pieceRec, grow, minWorld, out var x2, out var z2, out var x3, out var z3); if (!(x3 < x0) && !(x2 > x1) && !(z3 < z0) && !(z2 > z1)) { result.Add(pieceRec); } } } } } private void ReleaseFromFog() { if ((Object)(object)_rt == (Object)null || !_cfgRespectFog.Value) { return; } BitArray explored = ((_fiExplored != null) ? (_fiExplored.GetValue(_mm) as BitArray) : null); BitArray exploredOthers = ((_fiExploredOthers != null) ? (_fiExploredOthers.GetValue(_mm) as BitArray) : null); int num = 0; for (int i = 0; i < _fogPieces.Count; i++) { PieceRec pieceRec = _fogPieces[i]; if (IsWorldExplored(explored, exploredOthers, pieceRec.CX, pieceRec.CZ)) { _addPieces.Add(pieceRec); } else { _fogPieces[num++] = pieceRec; } } _fogPieces.RemoveRange(num, _fogPieces.Count - num); float num2 = Mathf.Max(0.5f, _cfgTerrainGrid.Value); num = 0; for (int j = 0; j < _fogTerrain.Count; j++) { long num3 = _fogTerrain[j]; float wx = ((float)(int)(num3 >> 32) + 0.5f) * num2; float wz = ((float)(int)(num3 & 0xFFFFFFFFu) + 0.5f) * num2; if (IsWorldExplored(explored, exploredOthers, wx, wz)) { _addTerrain.Add(num3); } else { _fogTerrain[num++] = num3; } } _fogTerrain.RemoveRange(num, _fogTerrain.Count - num); for (int k = 0; k < _fogForest.Count; k++) { if (IsExplored(explored, exploredOthers, _fogForest[k])) { _maskDirty = true; break; } } } private void RebuildMask() { //IL_016b: Unknown result type (might be due to invalid IL or missing references) //IL_01b6: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_rtMask == (Object)null || (Object)(object)_glMatMask == (Object)null || (Object)(object)_glMatMaskAdd == (Object)null || (Object)(object)_vanillaMask == (Object)null) { return; } try { if (_rtMask.IsCreated() || _rtMask.Create()) { _sw.Restart(); BitArray explored = null; BitArray exploredOthers = null; if (_cfgRespectFog.Value) { explored = ((_fiExplored != null) ? (_fiExplored.GetValue(_mm) as BitArray) : null); exploredOthers = ((_fiExploredOthers != null) ? (_fiExploredOthers.GetValue(_mm) as BitArray) : null); } bool value = _cfgMapFlipY.Value; _fogForest.Clear(); RenderTexture active = RenderTexture.active; Graphics.Blit((Texture)(object)_vanillaMask, _rtMask); RenderTexture.active = _rtMask; GL.PushMatrix(); GL.LoadPixelMatrix(0f, (float)((Texture)_rtMask).width, 0f, (float)((Texture)_rtMask).height); int num = 0; int num2 = 0; if (_cfgShowForest.Value && _clearedForest.Count > 0) { num = DrawMaskPixels(_clearedForest, _glMatMask, new Color(0f, 1f, 1f, 1f), explored, exploredOthers, value); } if (_cfgShowPlanted.Value && _plantedForest.Count > 0) { num2 = DrawMaskPixels(_plantedForest, _glMatMaskAdd, new Color(1f, 0f, 0f, 0f), explored, exploredOthers, value); } GL.PopMatrix(); RenderTexture.active = active; if (_cfgDebug.Value) { ((BaseUnityPlugin)this).Logger.LogInfo((object)$"Forest mask rebuilt: {num} cleared, {num2} planted, {_fogForest.Count} held back by fog, {_sw.Elapsed.TotalMilliseconds:0.0} ms CPU"); } } } catch (Exception e) { GpuFailed("forest mask rebuild", e); } } private void GpuFailed(string where, Exception e) { RenderTexture.active = null; _gpuUnavailable = true; HandleError(where, e); try { RestoreOriginalTextures(); ReleaseGpuLayer(); } catch { } ((BaseUnityPlugin)this).Logger.LogWarning((object)"The GPU map layer failed and was switched off; restart the world to fall back to CPU painting."); } private int DrawMaskPixels(HashSet<int> pixels, Material mat, Color c, BitArray explored, BitArray exploredOthers, bool flip) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) int height = ((Texture)_rtMask).height; int num = 0; mat.SetPass(0); GL.Begin(7); GL.Color(c); foreach (int pixel in pixels) { if (_cfgRespectFog.Value && !IsExplored(explored, exploredOthers, pixel)) { _fogForest.Add(pixel); continue; } float num2 = pixel % _texSize; float num3 = pixel / _texSize; if (flip) { num3 = (float)(height - 1) - num3; } GL.Vertex3(num2, num3, 0f); GL.Vertex3(num2 + 1f, num3, 0f); GL.Vertex3(num2 + 1f, num3 + 1f, 0f); GL.Vertex3(num2, num3 + 1f, 0f); num++; } GL.End(); return num; } private static void EmitQuad(float wx0, float wz0, float wx1, float wz1, Color c, float k, float half, int rtHeight, bool flip, float minWorld) { //IL_0105: 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) if (minWorld > 0f) { if (wx1 - wx0 < minWorld) { float num = (wx0 + wx1) * 0.5f; wx0 = num - minWorld * 0.5f; wx1 = num + minWorld * 0.5f; } if (wz1 - wz0 < minWorld) { float num2 = (wz0 + wz1) * 0.5f; wz0 = num2 - minWorld * 0.5f; wz1 = num2 + minWorld * 0.5f; } } float num3 = (wx0 / MapPixelSize + half) * k; float num4 = (wx1 / MapPixelSize + half) * k; float num5 = (wz0 / MapPixelSize + half) * k; float num6 = (wz1 / MapPixelSize + half) * k; if (num4 - num3 < 1f) { float num7 = (num3 + num4) * 0.5f; num3 = num7 - 0.5f; num4 = num7 + 0.5f; } if (num6 - num5 < 1f) { float num8 = (num5 + num6) * 0.5f; num5 = num8 - 0.5f; num6 = num8 + 0.5f; } if (flip) { float num9 = (float)rtHeight - num6; float num10 = (float)rtHeight - num5; num5 = num9; num6 = num10; } GL.Color(GlColor(c)); GL.Vertex3(num3, num5, 0f); GL.Vertex3(num4, num5, 0f); GL.Vertex3(num4, num6, 0f); GL.Vertex3(num3, num6, 0f); } private static Color GlColor(Color c) { //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_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) if (!LinearColors) { return c; } Color linear = ((Color)(ref c)).linear; linear.a = c.a; return linear; } private void Scan(Vector3 center) { //IL_0018: 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) bool flag = false; if (_cfgShowBuildings.Value && !UseZdoScan && ScanBuildings(center)) { flag = true; _rtDirty = true; } if (_cfgShowPaths.Value && !_terrainDisabled && !UseZdoPaths) { flag |= ScanTerrain(center); } if (flag) { _storeChanged = true; } } private bool ScanBuildings(Vector3 center) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0220: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: 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) //IL_0124: Unknown result type (might be due to invalid IL or missing references) //IL_017d: Unknown result type (might be due to invalid IL or missing references) //IL_0190: Unknown result type (might be due to invalid IL or missing references) //IL_01a3: Unknown result type (might be due to invalid IL or missing references) //IL_01b6: Unknown result type (might be due to invalid IL or missing references) //IL_01c9: 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_0155: Expected I4, but got Unknown float value = _cfgScanRadius.Value; float num = value * 0.9f; _scanBuckets.Clear(); int num2 = Physics.OverlapSphereNonAlloc(center, value, _colliderBuf, _pieceLayerMask); for (int i = 0; i < num2; i++) { Collider val = _colliderBuf[i]; if ((Object)(object)val == (Object)null) { continue; } Piece componentInParent = ((Component)val).GetComponentInParent<Piece>(); if ((Object)(object)componentInParent == (Object)null) { continue; } ZNetView componentInParent2 = ((Component)componentInParent).GetComponentInParent<ZNetView>(); if ((Object)(object)componentInParent2 == (Object)null || !componentInParent2.IsValid() || (_cfgOnlyPlayerBuilt.Value && componentInParent2.GetZDO().GetLong(ZDOVars.s_creator, 0L) == 0)) { continue; } Bounds bounds = val.bounds; Vector3 center2 = ((Bounds)(ref bounds)).center; float num3 = center2.x - center.x; float num4 = center2.z - center.z; if (!(num3 * num3 + num4 * num4 > num * num) && !(((Bounds)(ref bounds)).size.x > 32f) && !(((Bounds)(ref bounds)).size.z > 32f) && WorldToIndex(center2, out var idx)) { byte mat = byte.MaxValue; WearNTear component = ((Component)componentInParent).GetComponent<WearNTear>(); if ((Object)(object)component != (Object)null) { int num5 = (int)component.m_materialType; mat = ((num5 >= 0 && num5 < MatNames.Length) ? ((byte)num5) : byte.MaxValue); } PieceRec item = new PieceRec { X0 = ((Bounds)(ref bounds)).min.x, X1 = ((Bounds)(ref bounds)).max.x, Z0 = ((Bounds)(ref bounds)).min.z, Z1 = ((Bounds)(ref bounds)).max.z, Y = ((Bounds)(ref bounds)).max.y, Mat = mat }; if (!_scanBuckets.TryGetValue(idx, out var value2)) { value2 = new List<PieceRec>(); _scanBuckets[idx] = value2; } value2.Add(item); } } bool result = false; CollectPixelsInCircle(center, num, _circleScratch); for (int j = 0; j < _circleScratch.Count; j++) { int key = _circleScratch[j]; _scanBuckets.TryGetValue(key, out var value3); List<PieceRec> value4; bool flag = _pieces.TryGetValue(key, out value4); int num6 = (flag ? value4.Count : 0); int num7 = value3?.Count ?? 0; if ((num6 == 0 && num7 == 0) || (flag && value3 != null && SameBucket(value4, value3))) { continue; } if (flag) { _pieceCount -= num6; } if (num7 == 0) { _pieces.Remove(key); result = true; } else if (_pieceCount + num7 > _cfgMaxPieces.Value) { LogOnce("piececap", "Reached MaxPieces (" + _cfgMaxPieces.Value + "), no more build pieces are recorded."); if (flag) { _pieceCount += num6; } } else { _pieces[key] = value3; _pieceCount += num7; result = true; } } return result; } private bool ScanTerrain(Vector3 center) { //IL_0107: Unknown result type (might be due to invalid IL or missing references) //IL_0138: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Unknown result type (might be due to invalid IL or missing references) //IL_0142: Unknown result type (might be due to invalid IL or missing references) List<Heightmap> allHeightmaps; try { allHeightmaps = Heightmap.GetAllHeightmaps(); } catch (Exception e) { TerrainError("GetAllHeightmaps", e); return false; } if (allHeightmaps == null || allHeightmaps.Count == 0) { return false; } float num = _cfgScanRadius.Value * 0.9f; float num2 = Mathf.Max(0.5f, _cfgTerrainGrid.Value); int num3 = Mathf.CeilToInt(num / num2); float num4 = num * num; Heightmap cached = null; _sw.Restart(); int num5 = 0; int num6 = 0; bool result = false; int num7 = Mathf.FloorToInt(center.x / num2); int num8 = Mathf.FloorToInt(center.z / num2); try { Vector3 p = default(Vector3); for (int i = num7 - num3; i <= num7 + num3; i++) { for (int j = num8 - num3; j <= num8 + num3; j++) { float num9 = ((float)i + 0.5f) * num2; float num10 = ((float)j + 0.5f) * num2; float num11 = num9 - center.x; float num12 = num10 - center.z; if (num11 * num11 + num12 * num12 > num4) { continue; } ((Vector3)(ref p))..ctor(num9, center.y, num10); Heightmap val = PickHeightmap(allHeightmaps, p, ref cached); if ((Object)(object)val == (Object)null) { continue; } Color paintMask = val.GetPaintMask(new Vector3(num9 - 0.5f, center.y, num10 - 0.5f)); num5++; byte b = 0; if (paintMask.b > 0.5f) { b = 2; } else if (paintMask.r > 0.5f) { b = 3; } else if (paintMask.g > 0.5f) { b = 1; } else if (_cfgShowCleared.Value && paintMask.a < 0.5f) { b = 4; } long num13 = ((long)i << 32) | (uint)j; byte value; bool flag = _terrain.TryGetValue(num13, out value); if (b == 0) { if (flag) { _terrain.Remove(num13); result = true; _rtDirty = true; } continue; } num6++; if (flag && value == b) { continue; } if (!flag && _terrain.Count >= _cfgMaxTerrain.Value) { LogOnce("terraincap", "Reached MaxTerrainCells (" + _cfgMaxTerrain.Value + ")."); continue; } _terrain[num13] = b; result = true; if (flag) { _rtDirty = true; } else { _addTerrain.Add(num13); } } } } catch (Exception e2) { TerrainError("terrain sampling", e2); return result; } if (_cfgDebug.Value) { ((BaseUnityPlugin)this).Logger.LogInfo((object)$"Terrain scan: heightmaps={allHeightmaps.Count}, samples={num5}, painted={num6}, stored={_terrain.Count}, {_sw.Elapsed.TotalMilliseconds:0.0} ms"); } return result; } private static Heightmap PickHeightmap(List<Heightmap> maps, Vector3 p, ref Heightmap cached) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)cached != (Object)null) { Vector3 position = ((Component)cached).transform.position; if (Mathf.Abs(p.x - position.x) <= 32f && Mathf.Abs(p.z - position.z) <= 32f) { return cached; } } for (int i = 0; i < maps.Count; i++) { Heightmap val = maps[i]; if (!((Object)(object)val == (Object)null) && !val.IsDistantLod) { Vector3 position2 = ((Component)val).transform.position; if (Mathf.Abs(p.x - position2.x) <= 32f && Mathf.Abs(p.z - position2.z) <= 32f) { cached = val; return val; } } } return null; } private void TerrainError(string where, Exception e) { _terrainErrorCount++; HandleError("terrain: " + where, e); if (_terrainErrorCount >= 10 && !_terrainDisabled) { _terrainDisabled = true; ((BaseUnityPlugin)this).Logger.LogWarning((object)"The path layer failed too often and is off for this session. Buildings keep working."); } } private string StorePath() { return Path.Combine(Path.Combine(Paths.ConfigPath, "LivingMap"), _worldUid + ".bin"); } private void LoadStore() { //IL_0145: Unknown result type (might be due to invalid IL or missing references) try { if (_worldUid == 0) { return; } string path = StorePath(); MigrateStoreFromMapOverlay(path); if (!File.Exists(path)) { return; } using FileStream input = new FileStream(path, FileMode.Open, FileAccess.Read); using BinaryReader binaryReader = new BinaryReader(input); if (binaryReader.ReadUInt32() != 860835149) { return; } int num = binaryReader.ReadInt32(); if (num < 3 || num > 7) { return; } long num2 = binaryReader.ReadInt64(); int num3 = binaryReader.ReadInt32(); float num4 = binaryReader.ReadSingle(); if (num2 != _worldUid || num3 != _texSize || Mathf.Abs(num4 - _pixelSize) > 0.001f) { ((BaseUnityPlugin)this).Logger.LogInfo((object)"Stored overlay does not match this map, starting fresh."); return; } int num5 = binaryReader.ReadInt32(); for (int i = 0; i < num5; i++) { PieceRec item = new PieceRec { X0 = binaryReader.ReadSingle(), X1 = binaryReader.ReadSingle(), Z0 = binaryReader.ReadSingle(), Z1 = binaryReader.ReadSingle(), Y = binaryReader.ReadSingle(), Mat = binaryReader.ReadByte() }; if (_pieceCount < _cfgMaxPieces.Value && WorldToIndex(new Vector3(item.CX, item.Y, item.CZ), out var idx)) { if (!_pieces.TryGetValue(idx, out var value)) { value = new List<PieceRec>(); _pieces[idx] = value; } value.Add(item); _pieceCount++; } } int num6 = binaryReader.ReadInt32(); for (int j = 0; j < num6; j++) { long key = binaryReader.ReadInt64(); byte b = binaryReader.ReadByte(); if (b != 0 && _terrain.Count < _cfgMaxTerrain.Value) { _terrain[key] = b; } } int num7 = _texSize * _texSize; if (num >= 4) { int num8 = binaryReader.ReadInt32(); for (int k = 0; k < num8; k++) { int num9 = binaryReader.ReadInt32(); if (num9 >= 0 && num9 < num7) { _clearedForest.Add(num9); } } } if (num >= 5) { int num10 = binaryReader.ReadInt32(); for (int l = 0; l < num10; l++) { int num11 = binaryReader.ReadInt32(); if (num11 >= 0 && num11 < num7) { _plantedForest.Add(num11); } } } bool flag = (_piecesOnlyPlayerBuilt = num >= 6 && binaryReader.ReadBoolean()); if (flag != _cfgOnlyPlayerBuilt.Value) { DropPieces("the file was collected with OnlyPlayerBuilt " + (flag ? "on" : "off")); } float num12 = Mathf.Max(0.5f, _cfgTerrainGrid.Value); if (num >= 7) { float num13 = binaryReader.ReadSingle(); if (Mathf.Abs(num13 - num12) > 0.001f) { _terrain.Clear(); _storeChanged = true; ((BaseUnityPlugin)this).Logger.LogInfo((object)("Stored path cells dropped (the file was collected with TerrainGridSize " + num13 +