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 DryPits v1.0.0
plugins/DryPits.dll
Decompiled 2 days agousing System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using BepInEx; using BepInEx.Configuration; using HarmonyLib; using Microsoft.CodeAnalysis; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyVersion("0.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace DryPits { internal static class DryPitsSystem { private sealed class Binding { internal readonly int Zx; internal readonly int Zz; internal readonly Heightmap Heightmap; internal readonly WaterSurfaceView View; internal readonly float LoadedAt; internal WaterRecord Record; internal ZNetView Terrain; internal int ShownRevision = -1; internal float NextVisual; internal float NextTerrainLookup; internal float NextRecordCheck; internal bool WasCustom; internal bool StateLoaded; internal Binding(int zx, int zz, Heightmap heightmap, WaterSurfaceView view, float now) { Zx = zx; Zz = zz; Heightmap = heightmap; View = view; LoadedAt = now; } } [Serializable] [CompilerGenerated] private sealed class <>c { public static readonly <>c <>9 = new <>c(); public static ConsoleEvent <>9__36_0; internal void <RegisterCommand>b__36_0(ConsoleEventArgs args) { foreach (string item in Describe()) { Terminal context = args.Context; if (context != null) { context.AddString(item); } Plugin.Log(item); } } } private const string PlanetWorldKey = "planetprototype_v1"; internal static readonly FloodGrid Grid = new FloodGrid(); internal static bool QueryActive; private static readonly Dictionary<long, Binding> bindings = new Dictionary<long, Binding>(); private static readonly Dictionary<Heightmap, long> zoneOf = new Dictionary<Heightmap, long>(); private static readonly Dictionary<Heightmap, float[]> baseHeights = new Dictionary<Heightmap, float[]>(); private static readonly Dictionary<long, WaterRecord> records = new Dictionary<long, WaterRecord>(); private static readonly Dictionary<ZNetView, WaterRecord> recordViews = new Dictionary<ZNetView, WaterRecord>(); private static readonly List<WaterRecord> duplicates = new List<WaterRecord>(); private static readonly List<ZDO> sectorObjects = new List<ZDO>(); private static readonly FieldRef<Heightmap, List<float>> heightsOf = AccessTools.FieldRefAccess<Heightmap, List<float>>("m_heights"); private static readonly float[] groundBuffer = new float[4225]; private static readonly float[] originalBuffer = new float[4225]; private static World checkedWorld; private static bool worldAllowed; private static bool suspended; private static bool announced; private static float nextFlush; private static bool WorldAllowed() { if ((Object)(object)ZNet.instance == (Object)null || (Object)(object)ZoneSystem.instance == (Object)null || WorldGenerator.instance == null) { return false; } World world = WorldGenerator.instance.m_world; if (world != checkedWorld) { checkedWorld = world; worldAllowed = world != null && !world.m_menu && !world.m_startingGlobalKeys.Contains("planetprototype_v1"); if (world != null && !world.m_menu && !worldAllowed) { Plugin.Log("PlanetPrototype world: Dry Pits stays inactive here."); } } return worldAllowed; } internal static void ResetSession() { foreach (Binding value in bindings.Values) { value.View.Dispose(); } bindings.Clear(); zoneOf.Clear(); baseHeights.Clear(); records.Clear(); recordViews.Clear(); duplicates.Clear(); Grid.Clear(); DungeonVolumes.Clear(); DungeonVolumes.Active = false; QueryActive = false; checkedWorld = null; announced = false; nextFlush = 0f; } internal static void DungeonsChanged() { foreach (FloodPage item in new List<FloodPage>(Grid.Pages)) { Grid.SetDungeon(item.Zx, item.Zz, DungeonVolumes.WaterZones.Contains(FloodGrid.Key(item.Zx, item.Zz))); } } internal static void CaptureBase(Heightmap hm, float[] heights) { if ((Object)(object)hm != (Object)null && heights != null) { baseHeights[hm] = heights; } } internal static void HeightsChanged(Heightmap hm) { //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_013c: Unknown result type (might be due to invalid IL or missing references) if (hm.IsDistantLod || hm.m_width != 64 || Mathf.Abs(hm.m_scale - 1f) > 0.001f || !WorldAllowed()) { return; } List<float> list = heightsOf.Invoke(hm); if (list == null || list.Count != 4225) { return; } Vector3 position = ((Component)hm).transform.position; int num = Mathf.RoundToInt(position.x / 64f); int num2 = Mathf.RoundToInt(position.z / 64f); if (Mathf.Abs(position.x - (float)num * 64f) > 0.01f || Mathf.Abs(position.z - (float)num2 * 64f) > 0.01f) { return; } long num3 = FloodGrid.Key(num, num2); float time = Time.time; if (!bindings.TryGetValue(num3, out var value) || value.Heightmap != hm) { WaterSurfaceView waterSurfaceView = WaterSurfaceView.Find(hm); if (waterSurfaceView == null) { return; } if (value != null) { Release(num3, value); } value = (bindings[num3] = new Binding(num, num2, hm, waterSurfaceView, time)); zoneOf[hm] = num3; if (records.TryGetValue(num3, out var value2)) { value.Record = value2; } } float num4 = position.y - ZoneSystem.instance.m_waterLevel; baseHeights.TryGetValue(hm, out var value3); bool flag = value3 != null && value3.Length == 4225; for (int i = 0; i < 4225; i++) { groundBuffer[i] = list[i] + num4; originalBuffer[i] = (flag ? value3[i] : list[i]) + num4; } bool num5 = Grid.Page(num, num2) == null; if ((Object)(object)value.Record == (Object)null) { value.NextTerrainLookup = 0f; } Grid.UpdateGround(num, num2, groundBuffer, originalBuffer, IsAuthority(value, time), flag); Grid.SetDungeon(num, num2, DungeonVolumes.WaterZones.Contains(num3)); if (num5 && (Object)(object)value.Record != (Object)null) { value.StateLoaded = true; } } internal static void HeightmapDestroyed(Heightmap hm) { baseHeights.Remove(hm); if (zoneOf.TryGetValue(hm, out var value)) { if (bindings.TryGetValue(value, out var value2) && value2.Heightmap == hm) { Flush(value2); Release(value, value2); } zoneOf.Remove(hm); } } private static void Release(long key, Binding binding) { binding.View.Dispose(); bindings.Remove(key); zoneOf.Remove(binding.Heightmap); Grid.Remove(binding.Zx, binding.Zz); } private static bool IsAuthority(Binding b, float now) { //IL_0059: Unknown result type (might be due to invalid IL or missing references) WaterRecord record = b.Record; if ((Object)(object)record != (Object)null && record.Valid) { return record.View.IsOwner(); } if (now >= b.NextTerrainLookup) { b.NextTerrainLookup = now + 1f; TerrainComp val = TerrainComp.FindTerrainCompiler(new Vector3((float)b.Zx * 64f, 0f, (float)b.Zz * 64f)); b.Terrain = (((Object)(object)val != (Object)null) ? ((Component)val).GetComponent<ZNetView>() : null); } if ((Object)(object)b.Terrain != (Object)null && b.Terrain.IsValid()) { return b.Terrain.IsOwner(); } return false; } internal static void Tick() { DungeonVolumes.Active = Plugin.Enabled.Value && WorldAllowed(); if (!DungeonVolumes.Active) { if (suspended) { return; } suspended = true; QueryActive = false; { foreach (Binding value2 in bindings.Values) { value2.View.Restore(); } return; } } if (suspended) { suspended = false; foreach (Binding value3 in bindings.Values) { value3.ShownRevision = -1; } } float time = Time.time; RemoveDuplicates(); foreach (Binding value4 in bindings.Values) { FloodPage floodPage = Grid.Page(value4.Zx, value4.Zz); if (floodPage != null) { Grid.SetAuthority(floodPage, IsAuthority(value4, time)); } } float value = Plugin.FillSpeed.Value; if (value > 0f && value <= 10f) { Grid.Step(Mathf.Min(Time.deltaTime, 0.1f) * value); } bool flag = false; foreach (Binding value5 in bindings.Values) { FloodPage floodPage2 = Grid.Page(value5.Zx, value5.Zz); if (floodPage2 == null) { continue; } flag |= floodPage2.Custom; if (floodPage2.Revision != value5.ShownRevision && time >= value5.NextVisual) { value5.ShownRevision = floodPage2.Revision; value5.NextVisual = time + 0.2f; if (floodPage2.Custom) { value5.View.Show(floodPage2, time); } else { value5.View.Restore(); } if (floodPage2.Custom != value5.WasCustom) { value5.WasCustom = floodPage2.Custom; string text = "zone " + value5.Zx + "," + value5.Zz + (floodPage2.Custom ? (" uses local water (" + value5.View.TriangleCount + " water triangles)") : " is back to vanilla water"); if (floodPage2.Custom && !announced) { announced = true; Plugin.Log("First dry pit this session: " + text); } else { Plugin.Trace(text); } } } value5.View.Update(time); CreateRecordIfNeeded(value5, floodPage2, time); } QueryActive = flag; if (time >= nextFlush) { nextFlush = time + 1f; FlushAll(); } } private static void CreateRecordIfNeeded(Binding b, FloodPage page, float now) { //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: 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) if ((Object)(object)b.Record != (Object)null || !page.Authority || !page.PersistDirty || now < b.NextRecordCheck || now - b.LoadedAt < 5f) { return; } b.NextRecordCheck = now + 2f; if (ZoneState.Capture(page).Trivial) { page.PersistDirty = false; return; } Vector2s val = default(Vector2s); ((Vector2s)(ref val))..ctor(b.Zx, b.Zz); if ((Object)(object)ZNetScene.instance == (Object)null || ZDOMan.instance == null || !ZoneSystem.instance.IsZoneLoaded(val)) { return; } sectorObjects.Clear(); ZDOMan.instance.FindSectorObjects(val, new SimulationDistance(0, 0, false), sectorObjects, (List<ZDO>)null); foreach (ZDO sectorObject in sectorObjects) { if (sectorObject.GetPrefab() == WaterRecord.PrefabHash) { return; } } GameObject prefab = ZNetScene.instance.GetPrefab(WaterRecord.PrefabHash); if (!((Object)(object)prefab == (Object)null)) { Object.Instantiate<GameObject>(prefab, new Vector3((float)b.Zx * 64f, ZoneSystem.instance.m_waterLevel, (float)b.Zz * 64f), Quaternion.identity); Plugin.Trace("zone " + b.Zx + "," + b.Zz + ": water record created"); } } internal static void RegisterRecord(WaterRecord record) { //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) long key = FloodGrid.Key(record.Zx, record.Zz); if (records.TryGetValue(key, out var value) && (Object)(object)value != (Object)(object)record && (Object)(object)value != (Object)null && value.Valid) { ZDOID uid = value.Uid; bool num = ((ZDOID)(ref uid)).CompareTo(record.Uid) <= 0; WaterRecord waterRecord = (num ? record : value); if (waterRecord.Owned) { duplicates.Add(waterRecord); } if (num) { record.Rejected = true; return; } UnregisterRecord(value); value.Rejected = true; } records[key] = record; recordViews[record.View] = record; record.Registered = true; if (bindings.TryGetValue(key, out var value2)) { value2.Record = record; value2.NextTerrainLookup = 0f; } RecordChanged(record); } internal static void UnregisterRecord(WaterRecord record) { if (record.Registered) { record.Registered = false; long key = FloodGrid.Key(record.Zx, record.Zz); if (records.TryGetValue(key, out var value) && (Object)(object)value == (Object)(object)record) { records.Remove(key); } if (record.View != null) { recordViews.Remove(record.View); } if (bindings.TryGetValue(key, out var value2) && (Object)(object)value2.Record == (Object)(object)record) { value2.Record = null; } } } internal static void RecordChanged(WaterRecord record) { if (!record.Registered) { return; } byte[] array = record.Read(); if (array == null || array.Length == 0) { return; } ZoneState zoneState = null; try { zoneState = ZoneState.Deserialize(Utils.Decompress(array)); } catch (Exception) { } if (zoneState == null) { Plugin.Log("zone " + record.Zx + "," + record.Zz + ": ignored a damaged water record"); return; } bindings.TryGetValue(FloodGrid.Key(record.Zx, record.Zz), out var value); FloodPage floodPage = Grid.Page(record.Zx, record.Zz); if (value == null || floodPage == null || !floodPage.Authority || !value.StateLoaded) { Grid.ApplyRecord(record.Zx, record.Zz, zoneState); if (value != null && floodPage != null) { value.StateLoaded = true; } } } private static void RemoveDuplicates() { if (duplicates.Count == 0 || (Object)(object)ZNetScene.instance == (Object)null) { return; } foreach (WaterRecord duplicate in duplicates) { if ((Object)(object)duplicate != (Object)null && duplicate.Owned) { ZNetScene.instance.Destroy(((Component)duplicate).gameObject); } } duplicates.Clear(); } private static void Flush(Binding b) { FloodPage floodPage = Grid.Page(b.Zx, b.Zz); if (floodPage != null && floodPage.Loaded && floodPage.Authority && floodPage.PersistDirty && !((Object)(object)b.Record == (Object)null) && b.Record.Owned) { b.Record.Write(Utils.Compress(ZoneState.Capture(floodPage).Serialize())); floodPage.PersistDirty = false; b.StateLoaded = true; } } internal static void FlushAll() { foreach (Binding value in bindings.Values) { Flush(value); } } internal static void BeforeViewReset(ZNetView view) { if (recordViews.Count != 0 && recordViews.TryGetValue(view, out var value)) { if (bindings.TryGetValue(FloodGrid.Key(value.Zx, value.Zz), out var value2) && (Object)(object)value2.Record == (Object)(object)value) { Flush(value2); } UnregisterRecord(value); } } internal static void RegisterCommand() { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Expected O, but got Unknown object obj = <>c.<>9__36_0; if (obj == null) { ConsoleEvent val = delegate(ConsoleEventArgs args) { foreach (string item in Describe()) { Terminal context = args.Context; if (context != null) { context.AddString(item); } Plugin.Log(item); } }; <>c.<>9__36_0 = val; obj = (object)val; } new ConsoleCommand("drypits", "Dry Pits: water state at the player (also written to the BepInEx log)", (ConsoleEvent)obj, false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false); } private static List<string> Describe() { //IL_01c1: Unknown result type (might be due to invalid IL or missing references) //IL_01c6: Unknown result type (might be due to invalid IL or missing references) //IL_01c7: Unknown result type (might be due to invalid IL or missing references) //IL_01df: Unknown result type (might be due to invalid IL or missing references) //IL_01e0: Unknown result type (might be due to invalid IL or missing references) //IL_01e5: Unknown result type (might be due to invalid IL or missing references) //IL_01ec: Unknown result type (might be due to invalid IL or missing references) //IL_01f3: Unknown result type (might be due to invalid IL or missing references) //IL_02f5: Unknown result type (might be due to invalid IL or missing references) //IL_02fc: Unknown result type (might be due to invalid IL or missing references) //IL_0497: Unknown result type (might be due to invalid IL or missing references) //IL_04b5: Unknown result type (might be due to invalid IL or missing references) //IL_05c9: Unknown result type (might be due to invalid IL or missing references) //IL_05cf: Unknown result type (might be due to invalid IL or missing references) //IL_064b: Unknown result type (might be due to invalid IL or missing references) List<string> list = new List<string>(); int num = 0; foreach (Binding value2 in bindings.Values) { FloodPage floodPage = Grid.Page(value2.Zx, value2.Zz); if (floodPage != null && floodPage.Custom) { num++; } } list.Add("Dry Pits 0.3.0: enabled=" + Plugin.Enabled.Value + ", world ok=" + WorldAllowed() + ", zones=" + bindings.Count + ", zones with local water=" + num + ", records=" + records.Count + ", fill speed=" + Plugin.FillSpeed.Value + ", simulated samples=" + Grid.SimulatedSamples + (Grid.Sleeping ? " (still)" : " (flowing)")); list.Add("dungeons in the world (not in the sky): room volumes=" + DungeonVolumes.Count + ", zones where they reach sea level=" + DungeonVolumes.WaterZones.Count); Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null || (Object)(object)ZoneSystem.instance == (Object)null) { list.Add("no local player"); return list; } Vector3 position = ((Component)localPlayer).transform.position; if (DungeonVolumes.Contains(position, 0.3f)) { list.Add("player is inside a dungeon room: always dry here"); } Vector2s zone = ZoneSystem.GetZone(position); FloodPage floodPage2 = Grid.Page(zone.x, zone.y); if (floodPage2 == null) { list.Add("zone " + zone.x + "," + zone.y + ": not tracked"); return list; } int num2 = 0; int num3 = 0; int num4 = 0; int num5 = 0; float num6 = 0f; for (int i = 0; i < 4225; i++) { if (floodPage2.Reclaimed[i]) { num5++; } if (floodPage2.IsSource(i)) { if (floodPage2.Ground[i] < 0f) { num2++; } } else if (floodPage2.IsNode(i)) { if (floodPage2.Depth[i] > 0.005f) { num4++; } else { num3++; } if (FloodPage.IsHome(i)) { num6 += floodPage2.Depth[i]; } } } bindings.TryGetValue(FloodGrid.Key(zone.x, zone.y), out var value); list.Add("zone " + zone.x + "," + zone.y + ": local water=" + floodPage2.Custom + ", simulated here=" + floodPage2.Authority + ", record=" + ((value == null || !((Object)(object)value.Record != (Object)null)) ? "none" : (value.Record.Owned ? "mine" : "remote")) + ", mesh shown=" + (value?.View.Shown ?? false) + ", water triangles=" + (value?.View.TriangleCount ?? 0)); list.Add("samples: sea=" + num2 + " dry pit=" + num3 + " flooded pit=" + num4 + " reclaimed=" + num5 + ", water in pits=" + num6.ToString("F1") + " m3"); float waterLevel = ZoneSystem.instance.m_waterLevel; int num7 = Mathf.Clamp(Mathf.RoundToInt(position.x - (float)floodPage2.OriginX), 0, 64); int num8 = Mathf.Clamp(Mathf.RoundToInt(position.z - (float)floodPage2.OriginZ), 0, 64); int num9 = num8 * 65 + num7; list.Add("nearest sample " + (floodPage2.OriginX + num7) + "," + (floodPage2.OriginZ + num8) + ": " + Kind(floodPage2, num9) + ", ground " + (waterLevel + floodPage2.Ground[num9]).ToString("F2") + ", original " + (waterLevel + floodPage2.Original[num9]).ToString("F2") + (floodPage2.IsNode(num9) ? (", water depth " + floodPage2.Depth[num9].ToString("F2")) : "")); bool wet; float level; string text = ((!Grid.Query(position.x, position.z, out wet, out level)) ? "vanilla" : (wet ? ("water at " + (waterLevel + level).ToString("F2")) : "dry")); list.Add("player y " + position.y.ToString("F2") + ": local water=" + text + ", liquid level seen by the game=" + Floating.GetLiquidLevel(position, 1f, (LiquidType)10).ToString("F2")); return list; } private static string Kind(FloodPage p, int i) { if (p.IsSource(i)) { if (!(p.Ground[i] < 0f)) { return "raised sea floor"; } return "sea"; } if (p.IsNode(i)) { if (!(p.Depth[i] > 0.005f)) { return "dry pit"; } return "flooded pit"; } if (!p.Reclaimed[i]) { return "land"; } return "reclaimed land"; } } internal static class DungeonVolumes { private struct Volume { internal Vector3 Center; internal Vector3 Half; internal Vector3 Right; internal Vector3 Forward; internal bool Contains(Vector3 p, float margin) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) Vector3 val = p - Center; if (Mathf.Abs(val.y) <= Half.y + margin && Mathf.Abs(val.x * Right.x + val.z * Right.z) <= Half.x + margin) { return Mathf.Abs(val.x * Forward.x + val.z * Forward.z) <= Half.z + margin; } return false; } internal void Extent(out float minX, out float maxX, out float minZ, out float maxZ) { float num = Mathf.Abs(Right.x) * Half.x + Mathf.Abs(Forward.x) * Half.z; float num2 = Mathf.Abs(Right.z) * Half.x + Mathf.Abs(Forward.z) * Half.z; minX = Center.x - num; maxX = Center.x + num; minZ = Center.z - num2; maxZ = Center.z + num2; } } private const float SkyInteriors = 3000f; private const float WaterBand = 2f; private static readonly Dictionary<GameObject, List<Volume>> owners = new Dictionary<GameObject, List<Volume>>(); private static readonly List<Volume> all = new List<Volume>(); private static readonly Dictionary<long, List<int>> buckets = new Dictionary<long, List<int>>(); internal static readonly HashSet<long> WaterZones = new HashSet<long>(); internal static bool Active; internal static int Count => all.Count; internal static void Clear() { owners.Clear(); all.Clear(); buckets.Clear(); WaterZones.Clear(); } private static int Zone(float v) { return Mathf.FloorToInt((v + 32f) / 64f); } internal static bool Contains(Vector3 p, float margin) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) if (all.Count == 0 || !buckets.TryGetValue(FloodGrid.Key(Zone(p.x), Zone(p.z)), out var value)) { return false; } foreach (int item in value) { if (all[item].Contains(p, margin)) { return true; } } return false; } internal static void FromGenerator(DungeonGenerator generator) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) if (((Component)generator).transform.position.y > 3000f) { return; } List<Volume> list = new List<Volume>(); Room[] componentsInChildren = ((Component)generator).GetComponentsInChildren<Room>(true); foreach (Room val in componentsInChildren) { if (((Vector3Int)(ref val.m_size)).x != 0 && ((Vector3Int)(ref val.m_size)).z != 0) { list.Add(Box(((Component)val).transform.position, new Vector3((float)((Vector3Int)(ref val.m_size)).x, (float)((Vector3Int)(ref val.m_size)).y, (float)((Vector3Int)(ref val.m_size)).z) * 0.5f, ((Component)val).transform.forward)); } } Register(((Component)generator).gameObject, list); } internal static void FromLocation(Location location) { //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Expected O, but got Unknown //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_01bf: Unknown result type (might be due to invalid IL or missing references) //IL_01c1: Unknown result type (might be due to invalid IL or missing references) //IL_01c3: Unknown result type (might be due to invalid IL or missing references) //IL_01cd: Unknown result type (might be due to invalid IL or missing references) //IL_01d2: Unknown result type (might be due to invalid IL or missing references) //IL_01d7: Unknown result type (might be due to invalid IL or missing references) //IL_01d9: Unknown result type (might be due to invalid IL or missing references) //IL_01db: Unknown result type (might be due to invalid IL or missing references) //IL_01e5: Unknown result type (might be due to invalid IL or missing references) //IL_01eb: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Unknown result type (might be due to invalid IL or missing references) //IL_0113: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_011c: Unknown result type (might be due to invalid IL or missing references) //IL_0121: Unknown result type (might be due to invalid IL or missing references) //IL_012c: 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_016e: Unknown result type (might be due to invalid IL or missing references) //IL_0173: Unknown result type (might be due to invalid IL or missing references) //IL_0178: 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_0182: Unknown result type (might be due to invalid IL or missing references) //IL_0184: 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_0188: Unknown result type (might be due to invalid IL or missing references) //IL_018d: Unknown result type (might be due to invalid IL or missing references) //IL_018f: Unknown result type (might be due to invalid IL or missing references) //IL_0191: Unknown result type (might be due to invalid IL or missing references) //IL_0193: Unknown result type (might be due to invalid IL or missing references) //IL_0198: Unknown result type (might be due to invalid IL or missing references) if (!location.m_hasInterior) { return; } Transform val = (((Object)(object)location.m_interiorTransform != (Object)null) ? location.m_interiorTransform : ((Component)location).transform.Find("Interior")); if ((Object)(object)val == (Object)null || val.position.y > 3000f || (Object)(object)((Component)val).GetComponentInChildren<DungeonGenerator>(true) != (Object)null) { return; } List<Volume> list = new List<Volume>(); Matrix4x4 worldToLocalMatrix = val.worldToLocalMatrix; foreach (Transform item in val) { Transform val2 = item; if (!((Component)val2).gameObject.activeInHierarchy || (Object)(object)((Component)val2).GetComponent<Teleport>() != (Object)null) { continue; } bool flag = false; Vector3 val3 = Vector3.positiveInfinity; Vector3 val4 = Vector3.negativeInfinity; MeshFilter[] componentsInChildren = ((Component)val2).GetComponentsInChildren<MeshFilter>(); foreach (MeshFilter val5 in componentsInChildren) { Mesh sharedMesh = val5.sharedMesh; MeshRenderer component = ((Component)val5).GetComponent<MeshRenderer>(); if (!((Object)(object)sharedMesh == (Object)null) && !((Object)(object)component == (Object)null) && ((Renderer)component).enabled) { Matrix4x4 val6 = worldToLocalMatrix * ((Component)val5).transform.localToWorldMatrix; Bounds bounds = sharedMesh.bounds; for (int j = 0; j < 8; j++) { Vector3 val7 = ((Matrix4x4)(ref val6)).MultiplyPoint3x4(((Bounds)(ref bounds)).center + Vector3.Scale(((Bounds)(ref bounds)).extents, new Vector3(((j & 1) == 0) ? (-1f) : 1f, ((j & 2) == 0) ? (-1f) : 1f, ((j & 4) == 0) ? (-1f) : 1f))); val3 = Vector3.Min(val3, val7); val4 = Vector3.Max(val4, val7); } flag = true; } } if (flag) { list.Add(Box(val.TransformPoint((val3 + val4) * 0.5f), (val4 - val3) * 0.5f, val.forward)); } } Register(((Component)location).gameObject, list); } private static Volume Box(Vector3 center, Vector3 half, Vector3 forward) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) forward.y = 0f; forward = ((((Vector3)(ref forward)).sqrMagnitude < 1E-06f) ? Vector3.forward : ((Vector3)(ref forward)).normalized); return new Volume { Center = center, Half = half, Forward = forward, Right = new Vector3(forward.z, 0f, 0f - forward.x) }; } private static void Register(GameObject owner, List<Volume> list) { if (list.Count == 0) { Remove(owner); return; } owners[owner] = list; Rebuild(); } internal static void Remove(GameObject owner) { if (owners.Remove(owner)) { Rebuild(); } } private static void Rebuild() { //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) all.Clear(); buckets.Clear(); WaterZones.Clear(); float num = (((Object)(object)ZoneSystem.instance != (Object)null) ? ZoneSystem.instance.m_waterLevel : 30f); foreach (List<Volume> value2 in owners.Values) { foreach (Volume item in value2) { int count = all.Count; all.Add(item); item.Extent(out var minX, out var maxX, out var minZ, out var maxZ); bool flag = item.Center.y - item.Half.y < num + 2f && item.Center.y + item.Half.y > num - 2f; for (int i = Zone(minX - 0.5f); i <= Zone(maxX + 0.5f); i++) { for (int j = Zone(minZ - 0.5f); j <= Zone(maxZ + 0.5f); j++) { long num2 = FloodGrid.Key(i, j); if (!buckets.TryGetValue(num2, out var value)) { buckets.Add(num2, value = new List<int>()); } value.Add(count); if (flag) { WaterZones.Add(num2); } } } } } DryPitsSystem.DungeonsChanged(); } } internal sealed class FloodPage { internal const int Size = 65; internal const int Count = 4225; internal readonly int Zx; internal readonly int Zz; internal readonly int OriginX; internal readonly int OriginZ; internal readonly float[] Original = new float[4225]; internal readonly float[] Ground = new float[4225]; internal readonly float[] Depth = new float[4225]; internal readonly float[] Flow = new float[16900]; internal readonly bool[] Reclaimed = new bool[4225]; internal bool HasGround; internal bool Authority; internal bool Custom; internal bool PersistDirty; internal bool Dungeon; internal bool Loaded; internal ZoneState Pending; internal int Revision; internal FloodPage(int zx, int zz) { Zx = zx; Zz = zz; OriginX = zx * 64 - 32; OriginZ = zz * 64 - 32; } internal bool IsSource(int i) { if (!Reclaimed[i]) { return Original[i] <= 0f; } return false; } internal bool IsNode(int i) { if (Reclaimed[i] || Original[i] > 0f) { return Ground[i] < 0f; } return false; } internal static bool IsHome(int i) { if (i % 65 < 64) { return i / 65 < 64; } return false; } } internal static class FloodMath { internal const float Gravity = 9.81f; internal const float Still = 2E-06f; internal const float Overshoot = 0.05f; internal static float MaxDt = 0.02f; internal static float Damping = 0.5f; internal static float Share = 0.5f; internal static float Pipe(float flow, float dt, float from, float to, float crest) { float num = from - crest; float num2 = from - to; if (num <= 0f || num2 <= 0f) { return 0f; } flow = flow * Math.Max(0f, 1f - Damping * dt) + dt * 9.81f * num2 * num; flow = Math.Min(flow, num2 * Share / dt); if (!(flow * dt < 2E-06f)) { return flow; } return 0f; } } internal sealed class ZoneState { internal const short Dry = short.MinValue; private const int Version = 1; internal readonly short[] Levels = new short[4225]; internal readonly bool[] Reclaimed = new bool[4225]; internal bool Trivial { get { for (int i = 0; i < 4225; i++) { if (Levels[i] != short.MinValue || Reclaimed[i]) { return false; } } return true; } } internal static ZoneState Capture(FloodPage p) { ZoneState zoneState = new ZoneState(); for (int i = 0; i < 4225; i++) { zoneState.Reclaimed[i] = p.Reclaimed[i]; zoneState.Levels[i] = ((p.IsNode(i) && p.Depth[i] > 0.0005f) ? ((short)Math.Max(-32767, Math.Min(0, (int)Math.Round((p.Ground[i] + p.Depth[i]) * 1000f)))) : short.MinValue); } return zoneState; } internal float DepthAt(int i, float ground) { if (Levels[i] == short.MinValue || ground >= 0f) { return 0f; } return Math.Max(0f, Math.Min(0f - ground, (float)Levels[i] / 1000f - ground)); } internal byte[] Serialize() { using MemoryStream memoryStream = new MemoryStream(); using BinaryWriter binaryWriter = new BinaryWriter(memoryStream); binaryWriter.Write(1); binaryWriter.Write(65); short[] levels = Levels; foreach (short value in levels) { binaryWriter.Write(value); } byte b = 0; for (int j = 0; j < 4225; j++) { if (Reclaimed[j]) { b |= (byte)(1 << (j & 7)); } if ((j & 7) == 7 || j == 4224) { binaryWriter.Write(b); b = 0; } } binaryWriter.Flush(); return memoryStream.ToArray(); } internal static ZoneState Deserialize(byte[] data) { if (data == null || data.Length < 8) { return null; } try { using BinaryReader binaryReader = new BinaryReader(new MemoryStream(data)); if (binaryReader.ReadInt32() != 1 || binaryReader.ReadInt32() != 65) { return null; } ZoneState zoneState = new ZoneState(); for (int i = 0; i < 4225; i++) { zoneState.Levels[i] = Math.Min((short)0, binaryReader.ReadInt16()); } byte b = 0; for (int j = 0; j < 4225; j++) { if ((j & 7) == 0) { b = binaryReader.ReadByte(); } zoneState.Reclaimed[j] = (b & (1 << (j & 7))) != 0; } return zoneState; } catch (EndOfStreamException) { return null; } } } internal sealed class FloodGrid { private sealed class Node { internal FloodPage Page; internal int Index; internal float Ground; internal float Published; internal readonly FloodPage[] Next = new FloodPage[4]; internal readonly int[] NextIndex = new int[4]; internal readonly byte[] Kind = new byte[4]; internal readonly float[] Crest = new float[4]; internal readonly float[] BackCrest = new float[4]; } private static readonly int[] StepX = new int[4] { -1, 1, 0, 0 }; private static readonly int[] StepZ = new int[4] { 0, 0, -1, 1 }; private readonly Dictionary<long, FloodPage> pages = new Dictionary<long, FloodPage>(); private readonly Dictionary<long, ZoneState> saved = new Dictionary<long, ZoneState>(); private readonly List<Node> nodes = new List<Node>(); private readonly HashSet<FloodPage> touched = new HashSet<FloodPage>(); private readonly FloodPage[] copyPages = new FloodPage[4]; private readonly int[] copyIndex = new int[4]; private int nodeCount; private bool nodesDirty = true; private bool sleeping; internal int MaxWork = 250000; internal IEnumerable<FloodPage> Pages => pages.Values; internal int SimulatedSamples => nodeCount; internal bool Sleeping => sleeping; internal static long Key(int zx, int zz) { return ((long)zx << 32) | (uint)zz; } internal static int ZoneOf(int sample) { int num = sample + 32; if (num < 0) { return -((63 - num) / 64); } return num / 64; } internal FloodPage Page(int zx, int zz) { if (!pages.TryGetValue(Key(zx, zz), out var value) || !value.HasGround) { return null; } return value; } internal void Clear() { pages.Clear(); saved.Clear(); touched.Clear(); nodeCount = 0; Wake(); } private void Wake() { nodesDirty = true; sleeping = false; } internal void SetAuthority(FloodPage p, bool authority) { authority &= p.Loaded; if (p.Authority != authority) { p.Authority = authority; Wake(); } } internal bool TryHome(int x, int z, out FloodPage page, out int index) { page = Page(ZoneOf(x), ZoneOf(z)); index = ((page == null) ? (-1) : ((z - page.OriginZ) * 65 + x - page.OriginX)); return page != null; } internal bool TrySample(int x, int z, out FloodPage page, out int index) { int num = Copies(x, z); page = ((num > 0) ? copyPages[0] : null); index = ((num > 0) ? copyIndex[0] : (-1)); return num > 0; } private int Copies(int x, int z) { int num = ZoneOf(x); int num2 = ZoneOf(z); int num3 = 0; bool flag = x == num * 64 - 32; bool flag2 = z == num2 * 64 - 32; for (int i = 0; i < 4; i++) { int num4 = i & 1; int num5 = i >> 1; if ((num4 != 1 || flag) && (num5 != 1 || flag2)) { FloodPage floodPage = Page(num - num4, num2 - num5); if (floodPage != null) { copyPages[num3] = floodPage; copyIndex[num3++] = (z - floodPage.OriginZ) * 65 + x - floodPage.OriginX; } } } return num3; } private void SetDepth(int x, int z, float depth) { int num = Copies(x, z); for (int i = 0; i < num; i++) { FloodPage floodPage = copyPages[i]; int num2 = copyIndex[i]; if (floodPage.Depth[num2] != depth) { floodPage.Depth[num2] = depth; floodPage.Revision++; floodPage.PersistDirty = true; touched.Add(floodPage); } } } internal FloodPage UpdateGround(int zx, int zz, float[] ground, float[] original, bool authority, bool ready = true) { long key = Key(zx, zz); if (!pages.TryGetValue(key, out var value)) { pages.Add(key, value = new FloodPage(zx, zz)); } if (!value.HasGround) { saved.TryGetValue(key, out value.Pending); } Array.Copy(ground, value.Ground, 4225); Array.Copy(original, value.Original, 4225); value.HasGround = true; touched.Clear(); if (!value.Loaded && ready) { value.Loaded = true; if (value.Pending != null) { Load(value, value.Pending); } else { AdoptEdges(value); } value.Pending = null; } value.Authority = authority && value.Loaded; if (value.Authority) { Reclaim(value); } if (value.Loaded) { Clamp(value); } value.Revision++; touched.Add(value); RefreshTouched(); Wake(); return value; } internal void ApplyRecord(int zx, int zz, ZoneState state) { Remember(Key(zx, zz), state); FloodPage floodPage = Page(zx, zz); if (floodPage != null) { if (!floodPage.Loaded) { floodPage.Pending = state; return; } touched.Clear(); Load(floodPage, state); Clamp(floodPage); floodPage.Revision++; touched.Add(floodPage); RefreshTouched(); Wake(); } } internal void SetDungeon(int zx, int zz, bool dungeon) { FloodPage floodPage = Page(zx, zz); if (floodPage != null && floodPage.Dungeon != dungeon) { floodPage.Dungeon = dungeon; touched.Clear(); floodPage.Revision++; touched.Add(floodPage); RefreshTouched(); } } internal void Remove(int zx, int zz) { long key = Key(zx, zz); if (pages.TryGetValue(key, out var value)) { if (value.Loaded) { Remember(key, ZoneState.Capture(value)); } else if (value.Pending != null) { Remember(key, value.Pending); } pages.Remove(key); Wake(); } } private void Remember(long key, ZoneState state) { if (state.Trivial) { saved.Remove(key); } else { saved[key] = state; } } private void Load(FloodPage p, ZoneState state) { for (int i = 0; i < 4225; i++) { if (state.Reclaimed[i]) { p.Reclaimed[i] = true; } } for (int j = 0; j < 4225; j++) { p.Depth[j] = (p.IsNode(j) ? state.DepthAt(j, p.Ground[j]) : 0f); } AdoptEdges(p); } private void AdoptEdges(FloodPage p) { for (int i = 0; i < 4225; i++) { int num = i % 65; int num2 = i / 65; if (num != 0 && num != 64 && num2 != 0 && num2 != 64) { continue; } int x = p.OriginX + num; int z = p.OriginZ + num2; int num3 = Copies(x, z); if (num3 < 2) { continue; } bool flag = false; for (int j = 0; j < num3; j++) { flag |= copyPages[j].Reclaimed[copyIndex[j]]; } for (int k = 0; k < num3; k++) { if (flag && !copyPages[k].Reclaimed[copyIndex[k]]) { copyPages[k].Reclaimed[copyIndex[k]] = true; copyPages[k].Revision++; touched.Add(copyPages[k]); } } if (TryHome(x, z, out var page, out var index) && page != p) { if (page.Loaded) { p.Depth[i] = (page.IsNode(index) ? page.Depth[index] : 0f); } } else { SetDepth(x, z, p.Depth[i]); } } } private void Reclaim(FloodPage p) { for (int i = 0; i < 4225; i++) { if (FloodPage.IsHome(i) && !p.Reclaimed[i] && !(p.Original[i] > 0f) && !(p.Ground[i] <= 0.05f)) { int x = p.OriginX + i % 65; int z = p.OriginZ + i / 65; int num = Copies(x, z); for (int j = 0; j < num; j++) { FloodPage floodPage = copyPages[j]; floodPage.Reclaimed[copyIndex[j]] = true; floodPage.PersistDirty = true; floodPage.Revision++; touched.Add(floodPage); } SetDepth(x, z, 0f); } } } private static void Clamp(FloodPage p) { for (int i = 0; i < 4225; i++) { float num = (p.IsNode(i) ? (0f - p.Ground[i]) : 0f); float num2 = p.Depth[i]; float num3 = ((num2 < 0f) ? 0f : ((num2 > num) ? num : num2)); if (num3 != num2) { p.Depth[i] = num3; p.PersistDirty = true; p.Revision++; } } } private void RefreshTouched() { foreach (FloodPage item in touched) { bool flag = false; for (int i = 0; i < 4225; i++) { if (flag) { break; } flag = item.IsNode(i) && item.Ground[i] + item.Depth[i] < -0.02f; } item.Custom = flag || item.Dungeon; } touched.Clear(); } private void RebuildNodes() { nodesDirty = false; nodeCount = 0; foreach (FloodPage value in pages.Values) { if (!value.HasGround || !value.Authority) { continue; } for (int i = 0; i < 64; i++) { for (int j = 0; j < 64; j++) { int num = i * 65 + j; if (!value.IsNode(num)) { continue; } if (nodeCount == nodes.Count) { nodes.Add(new Node()); } Node node = nodes[nodeCount++]; node.Page = value; node.Index = num; node.Ground = value.Ground[num]; node.Published = value.Depth[num]; for (int k = 0; k < 4; k++) { node.Kind[k] = 0; int x = value.OriginX + j + StepX[k]; int z = value.OriginZ + i + StepZ[k]; if (!TrySample(x, z, out var page, out var index)) { continue; } float num2 = page.Ground[index]; float val = (node.Ground + num2) * 0.5f; if (page.IsNode(index)) { if (!TryHome(x, z, out page, out index) || !page.Authority) { continue; } node.Kind[k] = 1; } else { if (!page.IsSource(index) || !(num2 < 0f)) { continue; } node.Kind[k] = 2; } node.Next[k] = page; node.NextIndex[k] = index; node.Crest[k] = Math.Max(val, num2); node.BackCrest[k] = Math.Max(val, node.Ground); } for (int l = 0; l < 4; l++) { if (node.Kind[l] == 0) { value.Flow[num * 4 + l] = 0f; } } } } } } internal void Step(float seconds) { if (sleeping || seconds <= 0f) { return; } if (nodesDirty) { RebuildNodes(); } if (nodeCount == 0) { sleeping = true; return; } int num = Math.Min((int)Math.Ceiling(seconds / FloodMath.MaxDt), Math.Max(1, MaxWork / nodeCount)); float dt = Math.Min(FloodMath.MaxDt, seconds / (float)num); bool flag = false; for (int i = 0; i < num; i++) { flag |= Substep(dt); } Publish(); if (!flag) { sleeping = true; } } private bool Substep(float dt) { bool flag = false; for (int i = 0; i < nodeCount; i++) { Node node = nodes[i]; FloodPage page = node.Page; int num = node.Index * 4; float num2 = page.Depth[node.Index]; float num3 = node.Ground + num2; for (int j = 0; j < 4; j++) { float num4 = 0f; int num5 = node.Kind[j]; if (num5 != 0) { FloodPage floodPage = node.Next[j]; int num6 = node.NextIndex[j]; if (num2 > 0f) { num4 = FloodMath.Pipe(page.Flow[num + j], dt, num3, (num5 == 1) ? (floodPage.Ground[num6] + floodPage.Depth[num6]) : 0f, node.Crest[j]); } if (num5 == 2) { int num7 = num6 * 4 + (j ^ 1); float num8 = FloodMath.Pipe(floodPage.Flow[num7], dt, 0f, num3, node.BackCrest[j]); floodPage.Flow[num7] = num8; flag = flag || num8 > 0f; } } page.Flow[num + j] = num4; flag = flag || num4 > 0f; } } if (!flag) { return false; } for (int k = 0; k < nodeCount; k++) { Node node2 = nodes[k]; float[] flow = node2.Page.Flow; int num9 = node2.Index * 4; float num10 = (flow[num9] + flow[num9 + 1] + flow[num9 + 2] + flow[num9 + 3]) * dt; float num11 = node2.Page.Depth[node2.Index]; if (!(num10 <= num11)) { float num12 = ((num10 > 0f) ? (num11 / num10) : 0f); flow[num9] *= num12; flow[num9 + 1] *= num12; flow[num9 + 2] *= num12; flow[num9 + 3] *= num12; } } for (int l = 0; l < nodeCount; l++) { Node node3 = nodes[l]; FloodPage page2 = node3.Page; int num13 = node3.Index * 4; float num14 = 0f - (page2.Flow[num13] + page2.Flow[num13 + 1] + page2.Flow[num13 + 2] + page2.Flow[num13 + 3]); for (int m = 0; m < 4; m++) { if (node3.Kind[m] != 0) { num14 += node3.Next[m].Flow[node3.NextIndex[m] * 4 + (m ^ 1)]; } } float num15 = page2.Depth[node3.Index] + num14 * dt; float num16 = 0.05f - node3.Ground; page2.Depth[node3.Index] = ((num15 < 0f) ? 0f : ((num15 > num16) ? num16 : num15)); } return true; } private void Publish() { touched.Clear(); for (int i = 0; i < nodeCount; i++) { Node node = nodes[i]; FloodPage page = node.Page; int index = node.Index; float num = page.Depth[index]; if (!(Math.Abs(num - node.Published) < 0.0005f) || (num == 0f && node.Published != 0f)) { node.Published = num; page.Revision++; page.PersistDirty = true; touched.Add(page); SetDepth(page.OriginX + index % 65, page.OriginZ + index / 65, num); } } RefreshTouched(); } internal static float Mask(FloodPage p, int i, out bool wet, out float level) { float num = p.Ground[i]; if (p.IsSource(i)) { wet = num < 0f; level = 0f; return num; } if (p.IsNode(i)) { float num2 = p.Depth[i]; if (num2 > 0.005f) { wet = true; level = num + num2; return 0f - num2; } wet = false; level = num; return 1f; } wet = false; level = 0f; return Math.Max(num, 0.01f); } internal static int Classify(FloodPage p, int i, out float level) { Mask(p, i, out var wet, out level); if (!wet) { if (!p.IsNode(i)) { return 0; } return 2; } return 1; } internal bool Query(float x, float z, out bool wet, out float level) { wet = false; level = 0f; int zx = (int)Math.Floor((x + 32f) / 64f); int zz = (int)Math.Floor((z + 32f) / 64f); if (!pages.TryGetValue(Key(zx, zz), out var value) || !value.HasGround || !value.Custom) { return false; } float num = x - (float)value.OriginX; float num2 = z - (float)value.OriginZ; int num3 = Math.Min(63, Math.Max(0, (int)Math.Floor(num))); int num4 = Math.Min(63, Math.Max(0, (int)Math.Floor(num2))); float num5 = Math.Min(1f, Math.Max(0f, num - (float)num3)); float num6 = Math.Min(1f, Math.Max(0f, num2 - (float)num4)); float num7 = 0f; float num8 = 0f; float num9 = 0f; for (int i = 0; i < 4; i++) { int num10 = i & 1; int num11 = i >> 1; int i2 = (num4 + num11) * 65 + num3 + num10; float num12 = ((num10 == 1) ? num5 : (1f - num5)) * ((num11 == 1) ? num6 : (1f - num6)); num7 += num12 * Mask(value, i2, out var wet2, out var level2); if (wet2) { num8 += num12; num9 += num12 * level2; } } if (num7 > -0.002f || num8 <= 0.0001f) { return true; } wet = true; level = num9 / num8; return true; } } internal static class Guard { private static float nextReport; internal static void Report(string where, Exception e) { if (!(Time.realtimeSinceStartup < nextReport)) { nextReport = Time.realtimeSinceStartup + 10f; Plugin.Error("error in " + where + ": " + e); } } } [HarmonyPatch(typeof(TerrainComp), "ApplyToHeightmap")] internal static class CaptureOriginalHeights { private static void Prefix(float[] baseHeights, Heightmap hm) { try { DryPitsSystem.CaptureBase(hm, baseHeights); } catch (Exception e) { Guard.Report("terrain capture", e); } } } [HarmonyPatch(typeof(Heightmap), "RebuildCollisionMesh")] internal static class TerrainRebuilt { private static void Postfix(Heightmap __instance) { try { DryPitsSystem.HeightsChanged(__instance); } catch (Exception e) { Guard.Report("terrain update", e); } } } [HarmonyPatch(typeof(Heightmap), "OnDestroy")] internal static class TerrainDestroyed { private static void Prefix(Heightmap __instance) { try { DryPitsSystem.HeightmapDestroyed(__instance); } catch (Exception e) { Guard.Report("zone unload", e); } } } [HarmonyPatch(typeof(WaterVolume), "GetWaterSurface")] internal static class LocalWaterSurface { private static void Postfix(WaterVolume __instance, Vector3 point, ref float __result) { //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) if (__instance.m_heightmap != null) { bool wet; float level; if (DungeonVolumes.Active && DungeonVolumes.Count > 0 && DungeonVolumes.Contains(point, 0.3f)) { __result = -10000f; } else if (DryPitsSystem.QueryActive && DryPitsSystem.Grid.Query(point.x, point.z, out wet, out level)) { __result = (wet ? (__result + level) : (-10000f)); } } } } [HarmonyPatch(typeof(DungeonGenerator), "Generate", new Type[] { typeof(int), typeof(SpawnMode) })] internal static class DungeonGenerated { private static void Postfix(DungeonGenerator __instance, SpawnMode mode) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) if ((int)mode != 0) { return; } try { DungeonVolumes.FromGenerator(__instance); } catch (Exception e) { Guard.Report("dungeon rooms", e); } } } [HarmonyPatch(typeof(DungeonGenerator), "Spawn")] internal static class DungeonLoaded { private static void Postfix(DungeonGenerator __instance) { try { DungeonVolumes.FromGenerator(__instance); } catch (Exception e) { Guard.Report("dungeon rooms", e); } } } [HarmonyPatch(typeof(DungeonGenerator), "OnDestroy")] internal static class DungeonUnloaded { private static void Prefix(DungeonGenerator __instance) { try { DungeonVolumes.Remove(((Component)__instance).gameObject); } catch (Exception e) { Guard.Report("dungeon unload", e); } } } [HarmonyPatch(typeof(Location), "Awake")] internal static class LocationLoaded { private static void Postfix(Location __instance) { try { DungeonVolumes.FromLocation(__instance); } catch (Exception e) { Guard.Report("location interior", e); } } } [HarmonyPatch(typeof(Location), "OnDestroy")] internal static class LocationUnloaded { private static void Prefix(Location __instance) { try { DungeonVolumes.Remove(((Component)__instance).gameObject); } catch (Exception e) { Guard.Report("location unload", e); } } } [HarmonyPatch(typeof(BaseAI), "IsValidRandomMovePoint")] internal static class DryDungeonFloors { private static void Prefix(BaseAI __instance, Vector3 point, out bool __state) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) __state = false; if (!__instance.m_avoidWater || !DungeonVolumes.Active || DungeonVolumes.Count == 0) { return; } try { if (DungeonVolumes.Contains(point, 1f)) { __instance.m_avoidWater = false; __state = true; } } catch (Exception e) { Guard.Report("dungeon wander", e); } } private static void Postfix(BaseAI __instance, bool __state) { if (__state) { __instance.m_avoidWater = true; } } } [HarmonyPatch(typeof(ZNetScene), "Awake")] internal static class SessionStart { private static void Postfix(ZNetScene __instance) { try { DryPitsSystem.ResetSession(); WaterRecord.RegisterPrefab(__instance); } catch (Exception e) { Guard.Report("session start", e); } } } [HarmonyPatch(typeof(ZNetScene), "OnDestroy")] internal static class SessionEnd { private static void Prefix() { try { DryPitsSystem.ResetSession(); } catch (Exception e) { Guard.Report("session end", e); } } } [HarmonyPatch(typeof(ZNetView), "ResetZDO")] internal static class SaveBeforeUnload { private static void Prefix(ZNetView __instance) { try { DryPitsSystem.BeforeViewReset(__instance); } catch (Exception e) { Guard.Report("record unload", e); } } } [HarmonyPatch(typeof(ZNet), "SaveWorld")] internal static class SaveBeforeWorldSave { private static void Prefix() { try { DryPitsSystem.FlushAll(); } catch (Exception e) { Guard.Report("world save", e); } } } [HarmonyPatch(typeof(ZNet), "Shutdown")] internal static class SaveBeforeShutdown { private static void Prefix() { try { DryPitsSystem.FlushAll(); } catch (Exception e) { Guard.Report("shutdown", e); } } } [HarmonyPatch(typeof(Terminal), "InitTerminal")] internal static class ConsoleRegistration { private static void Postfix() { try { DryPitsSystem.RegisterCommand(); } catch (Exception e) { Guard.Report("console", e); } } } [BepInPlugin("local.valheim.drypits", "Dry Pits", "0.3.0")] public sealed class Plugin : BaseUnityPlugin { public const string Id = "local.valheim.drypits"; public const string Version = "0.3.0"; internal static Plugin Instance; internal static ConfigEntry<bool> Enabled; internal static ConfigEntry<bool> VerboseLog; internal static ConfigEntry<float> FillSpeed; private Harmony harmony; private void Awake() { //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Expected O, but got Unknown //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Expected O, but got Unknown Instance = this; Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Ground dug below sea level away from the sea stays dry. Turning it off restores vanilla water at once."); FillSpeed = ((BaseUnityPlugin)this).Config.Bind<float>("Water", "FillSpeedMultiplier", 1f, new ConfigDescription("How fast connected pits fill: 1 = normal, 2 = twice as fast, 0 = paused. The final level stays the same. In multiplayer each zone runs at its owner's setting.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 10f), Array.Empty<object>())); VerboseLog = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "VerboseLog", false, "Log every zone that switches between vanilla and local water, and every new water record."); harmony = new Harmony("local.valheim.drypits"); harmony.PatchAll(); if ((bool)AccessTools.Field(typeof(Terminal), "m_terminalInitialized").GetValue(null)) { DryPitsSystem.RegisterCommand(); } ((BaseUnityPlugin)this).Logger.LogInfo((object)"Dry Pits 0.3.0 ready: dry pits, flooding and dry dungeons. Console: drypits"); } private void Update() { try { DryPitsSystem.Tick(); } catch (Exception e) { Guard.Report("update", e); } } private void OnDestroy() { Harmony obj = harmony; if (obj != null) { obj.UnpatchSelf(); } } internal static void Log(string message) { ((BaseUnityPlugin)Instance).Logger.LogInfo((object)message); } internal static void Error(string message) { ((BaseUnityPlugin)Instance).Logger.LogError((object)message); } internal static void Trace(string message) { if (VerboseLog.Value) { ((BaseUnityPlugin)Instance).Logger.LogInfo((object)message); } } } public sealed class WaterRecord : MonoBehaviour { internal const string PrefabName = "DryPits_WaterState"; internal const string PayloadKey = "drypits_state_v1"; internal static readonly int PrefabHash = StringExtensionMethods.GetStableHashCode("DryPits_WaterState"); private static readonly FieldRef<ZNetScene, Dictionary<int, GameObject>> namedPrefabs = AccessTools.FieldRefAccess<ZNetScene, Dictionary<int, GameObject>>("m_namedPrefabs"); internal ZNetView View; internal int Zx; internal int Zz; internal bool Registered; internal bool Rejected; private uint seenRevision = uint.MaxValue; internal bool Valid { get { if ((Object)(object)View != (Object)null) { return View.IsValid(); } return false; } } internal bool Owned { get { if (Valid) { return View.IsOwner(); } return false; } } internal ZDOID Uid => View.GetZDO().m_uid; internal static void RegisterPrefab(ZNetScene scene) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Expected O, but got Unknown //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Expected O, but got Unknown GameObject val = new GameObject("DryPits prefabs"); val.SetActive(false); val.transform.SetParent(((Component)scene).transform, false); GameObject val2 = new GameObject("DryPits_WaterState"); val2.transform.SetParent(val.transform, false); val2.AddComponent<ZNetView>().m_persistent = true; val2.AddComponent<WaterRecord>(); namedPrefabs.Invoke(scene)[PrefabHash] = val2; } private void Awake() { TryRegister(); } private void Update() { if (!Registered) { if (!Rejected) { TryRegister(); } } else if (Valid) { uint dataRevision = View.GetZDO().DataRevision; if (dataRevision != seenRevision) { seenRevision = dataRevision; DryPitsSystem.RecordChanged(this); } } } private void OnDestroy() { DryPitsSystem.UnregisterRecord(this); } private void TryRegister() { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)View == (Object)null) { View = ((Component)this).GetComponent<ZNetView>(); } if (Valid) { Vector2s zone = ZoneSystem.GetZone(((Component)this).transform.position); Zx = zone.x; Zz = zone.y; seenRevision = View.GetZDO().DataRevision; DryPitsSystem.RegisterRecord(this); } } internal byte[] Read() { if (!Valid) { return null; } return View.GetZDO().GetByteArray("drypits_state_v1", (byte[])null); } internal void Write(byte[] payload) { ZDO zDO = View.GetZDO(); zDO.Set("drypits_state_v1", payload); seenRevision = zDO.DataRevision; } } internal sealed class WaterSurfaceView { private const int S = 65; private static readonly List<Vector3> vertices = new List<Vector3>(); private static readonly List<Vector3> normals = new List<Vector3>(); private static readonly List<Vector4> tangents = new List<Vector4>(); private static readonly List<Vector2> uvs = new List<Vector2>(); private static readonly List<int> triangles = new List<int>(); private static readonly int[] kinds = new int[4225]; private static readonly float[] levels = new float[4225]; private readonly Transform surface; private readonly MeshFilter filter; private readonly Mesh original; private readonly BoxCollider[] boxes; private readonly bool[] boxEnabled; private Mesh mesh; private MeshCollider collider; private bool shown; private bool cookPending; private float nextCook; internal bool Shown => shown; internal int TriangleCount { get; private set; } private WaterSurfaceView(Transform surface, MeshFilter filter) { this.surface = surface; this.filter = filter; original = filter.sharedMesh; boxes = ((Component)surface).GetComponents<BoxCollider>(); boxEnabled = new bool[boxes.Length]; } internal static WaterSurfaceView Find(Heightmap hm) { Transform parent = ((Component)hm).transform.parent; if ((Object)(object)parent == (Object)null) { return null; } WaterVolume componentInChildren = ((Component)parent).GetComponentInChildren<WaterVolume>(true); if ((Object)(object)componentInChildren == (Object)null || (Object)(object)componentInChildren.m_waterSurface == (Object)null || (Object)(object)componentInChildren.m_heightmap != (Object)(object)hm) { return null; } MeshFilter component = ((Component)componentInChildren.m_waterSurface).GetComponent<MeshFilter>(); if (!((Object)(object)component == (Object)null)) { return new WaterSurfaceView(((Component)componentInChildren.m_waterSurface).transform, component); } return null; } internal void Show(FloodPage p, float now) { //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Expected O, but got Unknown //IL_0160: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)surface == (Object)null) { return; } Build(p); if ((Object)(object)mesh == (Object)null) { mesh = new Mesh { name = "DryPits water" }; mesh.MarkDynamic(); } mesh.Clear(); mesh.SetVertices(vertices); mesh.SetNormals(normals); mesh.SetTangents(tangents); mesh.SetUVs(0, uvs); mesh.SetTriangles(triangles, 0, false); mesh.bounds = new Bounds(Vector3.zero, new Vector3(2.2f, 44f, 2.2f)); TriangleCount = triangles.Count / 3; if (!shown) { shown = true; filter.sharedMesh = mesh; for (int i = 0; i < boxes.Length; i++) { boxEnabled[i] = ((Collider)boxes[i]).enabled; ((Collider)boxes[i]).enabled = false; } collider = ((Component)surface).gameObject.AddComponent<MeshCollider>(); collider.convex = false; ((Collider)collider).excludeLayers = LayerMask.op_Implicit(-1); nextCook = 0f; } cookPending = true; Update(now); } internal void Update(float now) { if (shown && cookPending && !(now < nextCook) && !((Object)(object)collider == (Object)null)) { cookPending = false; nextCook = now + 1.5f; collider.sharedMesh = null; ((Collider)collider).enabled = TriangleCount > 0; if (TriangleCount > 0) { collider.sharedMesh = mesh; } } } internal void Restore() { if (!shown) { return; } shown = false; cookPending = false; if ((Object)(object)filter != (Object)null) { filter.sharedMesh = original; } for (int i = 0; i < boxes.Length; i++) { if ((Object)(object)boxes[i] != (Object)null) { ((Collider)boxes[i]).enabled = boxEnabled[i]; } } if ((Object)(object)collider != (Object)null) { Object.Destroy((Object)(object)collider); } collider = null; } internal void Dispose() { Restore(); if ((Object)(object)mesh != (Object)null) { Object.Destroy((Object)(object)mesh); } mesh = null; } private void Build(FloodPage p) { //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) vertices.Clear(); normals.Clear(); tangents.Clear(); uvs.Clear(); triangles.Clear(); for (int i = 0; i < 4225; i++) { kinds[i] = FloodGrid.Classify(p, i, out levels[i]); } Matrix4x4 worldToLocalMatrix = surface.worldToLocalMatrix; float waterLevel = ZoneSystem.instance.m_waterLevel; for (int j = 0; j < 64; j++) { for (int k = 0; k < 64; k++) { int num = j * 65 + k; int num2 = num + 1; int num3 = num + 65; int c = num3 + 1; Triangle(p, worldToLocalMatrix, waterLevel, num, num3, num2); Triangle(p, worldToLocalMatrix, waterLevel, num2, num3, c); } } } private void Triangle(FloodPage p, Matrix4x4 toLocal, float sea, int a, int b, int c) { //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) int num = kinds[a]; int num2 = kinds[b]; int num3 = kinds[c]; if (num == 1 || num2 == 1 || num3 == 1) { float num4 = float.MinValue; if (num == 1) { num4 = Mathf.Max(num4, levels[a]); } if (num2 == 1) { num4 = Mathf.Max(num4, levels[b]); } if (num3 == 1) { num4 = Mathf.Max(num4, levels[c]); } if (!Deep(p, a, num, num4) && !Deep(p, b, num2, num4) && !Deep(p, c, num3, num4)) { Vertex(p, toLocal, sea, a, (num == 1) ? levels[a] : num4); Vertex(p, toLocal, sea, b, (num2 == 1) ? levels[b] : num4); Vertex(p, toLocal, sea, c, (num3 == 1) ? levels[c] : num4); } } } private static bool Deep(FloodPage p, int i, int kind, float top) { if (kind == 2) { return p.Ground[i] < top - 0.25f; } return false; } private static void Vertex(FloodPage p, Matrix4x4 toLocal, float sea, int i, float level) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) Vector3 val = ((Matrix4x4)(ref toLocal)).MultiplyPoint3x4(new Vector3((float)(p.OriginX + i % 65), sea + level, (float)(p.OriginZ + i / 65))); triangles.Add(vertices.Count); vertices.Add(val); normals.Add(Vector3.up); tangents.Add(new Vector4(1f, 0f, 0f, -1f)); uvs.Add(new Vector2((val.x + 1f) * 0.5f, (val.z + 1f) * 0.5f)); } } }