Decompiled source of DeepSeaTreasures v1.1.3

DeepSeaTreasures.dll

Decompiled 2 weeks ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[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 DeepSeaTreasures
{
	[BepInPlugin("alkin.DeepSeaTreasures", "DeepSeaTreasures", "1.1.3")]
	public sealed class Plugin : BaseUnityPlugin
	{
		public const string GUID = "alkin.DeepSeaTreasures";

		public const string NAME = "DeepSeaTreasures";

		public const string VERSION = "1.1.3";

		internal static Plugin Instance;

		internal static ConfigEntry<bool> ModEnabled;

		internal static ConfigEntry<bool> DepthMultiplierEnabled;

		internal static ConfigEntry<float> BaseMultiplier;

		internal static ConfigEntry<float> IncreasePerMeter;

		internal static ConfigEntry<float> MinimumDepthBonus;

		internal static ConfigEntry<float> MaximumDepthBonus;

		internal static ConfigEntry<float> ScanRadius;

		internal static ConfigEntry<int> CellsPerFrame;

		internal static readonly Dictionary<Biome, ConfigEntry<string>> LootConfigs = new Dictionary<Biome, ConfigEntry<string>>();

		private readonly Queue<CellCoord> _pending = new Queue<CellCoord>();

		private readonly HashSet<CellCoord> _queued = new HashSet<CellCoord>();

		private ProcessedCellStore _store;

		private float _nextScan;

		internal const float CellArea = 1000f;

		internal static readonly float CellSize = Mathf.Sqrt(1000f);

		private void Awake()
		{
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Expected O, but got Unknown
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Expected O, but got Unknown
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ee: Expected O, but got Unknown
			//IL_0121: Unknown result type (might be due to invalid IL or missing references)
			//IL_012b: Expected O, but got Unknown
			//IL_015e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0168: Expected O, but got Unknown
			//IL_019b: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a5: Expected O, but got Unknown
			Instance = this;
			ModEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Enables DeepSeaTreasures.");
			ScanRadius = ((BaseUnityPlugin)this).Config.Bind<float>("General", "ScanRadius", 180f, new ConfigDescription("Radius in meters around active players in which new 1000 m² seabed cells are evaluated.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(32f, 1000f), Array.Empty<object>()));
			CellsPerFrame = ((BaseUnityPlugin)this).Config.Bind<int>("General", "CellsPerFrame", 2, new ConfigDescription("Maximum new seabed cells evaluated per frame.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 64), Array.Empty<object>()));
			DepthMultiplierEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Depth Multipliers", "DepthMultiplierEnabled", true, "If true, all item spawn chances are multiplied according to water depth.");
			BaseMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Depth Multipliers", "BaseMultiplier", 1f, new ConfigDescription("Base multiplier applied to every item chance.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f), Array.Empty<object>()));
			IncreasePerMeter = ((BaseUnityPlugin)this).Config.Bind<float>("Depth Multipliers", "IncreasePerMeter", 0.01f, new ConfigDescription("Relative multiplier added for each eligible meter of depth. 0.01 = +1% of the base chance per meter.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 10f), Array.Empty<object>()));
			MinimumDepthBonus = ((BaseUnityPlugin)this).Config.Bind<float>("Depth Multipliers", "MinimumDepthBonus", 5f, new ConfigDescription("Depth in meters at which IncreasePerMeter begins accumulating.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 10000f), Array.Empty<object>()));
			MaximumDepthBonus = ((BaseUnityPlugin)this).Config.Bind<float>("Depth Multipliers", "MaximumDepthBonus", 100f, new ConfigDescription("Maximum NUMBER OF METERS counted for IncreasePerMeter, starting after MinimumDepthBonus.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 10000f), Array.Empty<object>()));
			BindBiome((Biome)1, "Meadows", "Stone,0.396,1,1,1,0;Wood,0.192,1,1,1,0;Flint,0.128,1,1,1,0;BoneFragments,0.04,1,1,3,0;LeatherScraps,0.0168,1,1,2,500;DeerHide,0.0112,1,1,3,750;Coins,0.003,1,5,4,1000;AxeFlint,0.0004,1,1,6,2500,0.05,0.25");
			BindBiome((Biome)8, "BlackForest", "Stone,0.44,1,1,1,0;Wood,0.18,1,1,1,0;RoundLog,0.112,1,1,2,0;CopperOre,0.0252,1,1,5,1500;TinOre,0.021,1,1,4,1200;BoneFragments,0.0288,1,1,4,0;SurtlingCore,0.006,1,1,7,1800;Amber,0.0084,1,1,5,2000;AmberPearl,0.0025,1,1,7,2500;Coins,0.005,2,8,5,1800;SwordBronze,0.00035,1,1,10,4500,0.05,0.22;ArmorBronzeChest,0.00018,1,1,12,6000,0.04,0.18");
			BindBiome((Biome)2, "Swamp", "Stone,0.252,1,1,1,0;Wood,0.112,1,1,1,0;ElderBark,0.072,1,1,2,0;IronScrap,0.0252,1,1,5,2500;BoneFragments,0.045,1,1,3,0;Entrails,0.0168,1,1,3,1500;Chain,0.0035,1,1,8,3500;Coins,0.006,2,10,5,2500;SwordIron,0.00035,1,1,10,6000,0.04,0.20;ArmorIronChest,0.00016,1,1,12,6500,0.03,0.15");
			BindBiome((Biome)4, "Mountain", "Stone,0.288,1,1,1,0;Crystal,0.049,1,1,4,0;Obsidian,0.04,1,1,4,2500;SilverOre,0.0126,1,1,7,4000;WolfPelt,0.0098,1,1,4,3000;FreezeGland,0.0084,1,1,5,3500;Coins,0.004,2,10,6,4000;SwordSilver,0.00028,1,1,12,7500,0.04,0.18;ArmorWolfChest,0.00014,1,1,14,9000,0.03,0.14");
			BindBiome((Biome)256, "Ocean", "Stone,0.55,1,1,2,0;Wood,0.32,1,1,2,0;FineWood,0.12,1,1,4,2000;Coins,0.06,3,15,5,2000;Amber,0.04,1,1,6,2500;AmberPearl,0.025,1,1,8,3000;Chitin,0.03,1,1,8,3500;IronScrap,0.028,1,1,8,4000;SilverOre,0.012,1,1,12,6500;BlackMetalScrap,0.006,1,1,15,7500;SwordIron,0.00055,1,1,12,6000,0.03,0.18;SwordSilver,0.0004,1,1,15,7000,0.03,0.16;SwordBlackmetal,0.00022,1,1,18,8000,0.02,0.12");
			BindBiome((Biome)16, "Plains", "Stone,0.324,1,1,1,0;Wood,0.096,1,1,1,0;FineWood,0.056,1,1,3,2500;BlackMetalScrap,0.0196,1,1,6,4500;Needle,0.0192,1,1,4,3000;LoxPelt,0.0098,1,1,4,3500;Coins,0.008,3,12,5,4500;Barley,0.0096,1,1,3,4000;Flax,0.0096,1,1,3,4000;SwordBlackmetal,0.00025,1,1,12,6500,0.03,0.17;ArmorPaddedCuirass,0.00012,1,1,14,7500,0.02,0.12");
			BindBiome((Biome)512, "Mistlands", "Stone,0.288,1,1,1,0;BlackMarble,0.112,1,1,3,2500;CopperScrap,0.04,1,1,4,3500;IronScrap,0.0196,1,1,5,4500;Softtissue,0.0084,1,1,7,6500;YggdrasilWood,0.04,1,1,3,3000;SurtlingCore,0.004,1,1,8,5000;Coins,0.009,3,15,5,5000;Carapace,0.0084,1,1,7,7000;SwordMistwalker,0.00018,1,1,14,8000,0.02,0.14;ArmorCarapaceChest,0.00009,1,1,16,8500,0.02,0.10");
			BindBiome((Biome)32, "Ashlands", "Stone,0.32,1,1,1,0;BlackMarble,0.088,1,1,3,3000;Ashwood,0.064,1,1,3,3500;BoneFragments,0.045,1,1,3,0;SurtlingCore,0.0126,1,1,7,5000;FlametalOreNew,0.006,1,1,9,7000;FlametalNew,0.002,1,1,12,6500;Coins,0.010,4,18,6,6000;CharredBone,0.0192,1,1,5,5000;ArmorFlametalChest,0.00007,1,1,18,8750,0.01,0.08;ArmorAshlandsMediumChest,0.00007,1,1,18,8750,0.01,0.08");
			BindBiome((Biome)64, "DeepNorth", "Stone,0.32,1,1,1,0;Crystal,0.112,1,1,3,0;Obsidian,0.04,1,1,4,5000;SilverOre,0.0168,1,1,6,7000;FreezeGland,0.024,1,1,4,5000;FlametalNew,0.0015,1,1,15,8500;Coins,0.012,4,20,6,7000;ArmorFlametalChest,0.00005,1,1,20,9000,0.01,0.06");
			_store = new ProcessedCellStore(((BaseUnityPlugin)this).Logger);
			((BaseUnityPlugin)this).Logger.LogInfo((object)string.Format("{0} {1} loaded. Cell size: {2:0.###} m ({3:0} m²).", "DeepSeaTreasures", "1.1.3", CellSize, 1000f));
		}

		private void BindBiome(Biome biome, string section, string defaults)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			LootConfigs[biome] = ((BaseUnityPlugin)this).Config.Bind<string>(section, "Loot", defaults, "Entries: Prefab,Chance,MinAmount,MaxAmount,MinimumDepth,MinimumDistanceFromCenter[,MinDurability,MaxDurability]. Chance/durability are 0..1; distances are meters. Example: SwordIron,0.001,1,1,15,9000,0.03,0.15");
		}

		private void Update()
		{
			if (!ModEnabled.Value || (Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer())
			{
				return;
			}
			if (Time.unscaledTime >= _nextScan)
			{
				_nextScan = Time.unscaledTime + 2f;
				QueueCellsAroundPlayers();
			}
			int num = Mathf.Min(CellsPerFrame.Value, _pending.Count);
			for (int i = 0; i < num; i++)
			{
				CellCoord cellCoord = _pending.Dequeue();
				_queued.Remove(cellCoord);
				if (!_store.IsProcessed(cellCoord))
				{
					try
					{
						EvaluateCell(cellCoord);
						_store.MarkProcessed(cellCoord);
					}
					catch (Exception arg)
					{
						((BaseUnityPlugin)this).Logger.LogWarning((object)$"Failed evaluating cell {cellCoord}: {arg}");
					}
				}
			}
		}

		private void QueueCellsAroundPlayers()
		{
			//IL_005b: 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_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			List<Player> allPlayers = Player.GetAllPlayers();
			if (allPlayers == null)
			{
				return;
			}
			int num = Mathf.CeilToInt(ScanRadius.Value / CellSize);
			Vector2 val = default(Vector2);
			foreach (Player item in allPlayers)
			{
				if ((Object)(object)item == (Object)null)
				{
					continue;
				}
				CellCoord cellCoord = CellCoord.FromWorld(((Component)item).transform.position);
				for (int i = -num; i <= num; i++)
				{
					for (int j = -num; j <= num; j++)
					{
						CellCoord cellCoord2 = new CellCoord(cellCoord.X + i, cellCoord.Z + j);
						Vector3 center = cellCoord2.Center;
						((Vector2)(ref val))..ctor(center.x - ((Component)item).transform.position.x, center.z - ((Component)item).transform.position.z);
						if (!(((Vector2)(ref val)).sqrMagnitude > ScanRadius.Value * ScanRadius.Value) && !_store.IsProcessed(cellCoord2) && _queued.Add(cellCoord2))
						{
							_pending.Enqueue(cellCoord2);
						}
					}
				}
			}
		}

		private void EvaluateCell(CellCoord cell)
		{
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ca: Unknown result type (might be due to invalid IL or missing references)
			Random random = new Random(cell.StableSeed());
			float num = 2f;
			float num2 = Mathf.Max(0.1f, CellSize - num * 2f);
			Vector3 xz = default(Vector3);
			((Vector3)(ref xz))..ctor((float)cell.X * CellSize + num + (float)random.NextDouble() * num2, 0f, (float)cell.Z * CellSize + num + (float)random.NextDouble() * num2);
			if (!WorldQueries.TryGetNaturalSeabed(xz, out var seabed, out var _, out var depth, out var biome) || !LootConfigs.TryGetValue(biome, out var value))
			{
				return;
			}
			List<LootRule> list = LootRule.ParseList(value.Value, ((BaseUnityPlugin)this).Logger);
			foreach (LootRule item in list)
			{
				if (depth < item.MinimumDepth)
				{
					continue;
				}
				Vector2 val = new Vector2(seabed.x, seabed.z);
				float magnitude = ((Vector2)(ref val)).magnitude;
				if (!(magnitude < item.MinimumDistanceFromCenter))
				{
					float num3 = item.Chance;
					if (DepthMultiplierEnabled.Value)
					{
						float num4 = Mathf.Clamp(depth - MinimumDepthBonus.Value, 0f, MaximumDepthBonus.Value);
						float num5 = BaseMultiplier.Value + num4 * IncreasePerMeter.Value;
						num3 *= num5;
					}
					num3 = Mathf.Clamp01(num3);
					if (!(random.NextDouble() > (double)num3))
					{
						int amount = ((item.MinAmount == item.MaxAmount) ? item.MinAmount : random.Next(item.MinAmount, item.MaxAmount + 1));
						SpawnItem(item, amount, seabed, random);
					}
				}
			}
		}

		private void SpawnItem(LootRule rule, int amount, Vector3 seabed, Random rng)
		{
			//IL_00fc: 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)
			//IL_00ff: 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)
			string prefab = rule.Prefab;
			if (amount <= 0 || (Object)(object)ZNetScene.instance == (Object)null)
			{
				return;
			}
			GameObject prefab2 = ZNetScene.instance.GetPrefab(prefab);
			if ((Object)(object)prefab2 == (Object)null)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("Unknown prefab '" + prefab + "'. Entry skipped."));
				return;
			}
			ItemDrop component = prefab2.GetComponent<ItemDrop>();
			if ((Object)(object)component == (Object)null)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("Prefab '" + prefab + "' is not an ItemDrop. Entry skipped."));
				return;
			}
			int num = Mathf.Max(1, component.m_itemData.m_shared.m_maxStackSize);
			int num2 = amount;
			Vector3 val = default(Vector3);
			while (num2 > 0)
			{
				int num3 = Mathf.Min(num, num2);
				num2 -= num3;
				((Vector3)(ref val))..ctor(((float)rng.NextDouble() - 0.5f) * 1.2f, 0.15f, ((float)rng.NextDouble() - 0.5f) * 1.2f);
				GameObject val2 = Object.Instantiate<GameObject>(prefab2, seabed + val, Quaternion.Euler(0f, (float)rng.NextDouble() * 360f, 0f));
				ItemDrop component2 = val2.GetComponent<ItemDrop>();
				if ((Object)(object)component2 != (Object)null)
				{
					component2.m_itemData.m_stack = num3;
					if (rule.HasDurabilityRange && component2.m_itemData.m_shared.m_useDurability && component2.m_itemData.GetMaxDurability() > 0f)
					{
						float num4 = Mathf.Lerp(rule.MinDurability, rule.MaxDurability, (float)rng.NextDouble());
						component2.m_itemData.m_durability = Mathf.Max(1f, component2.m_itemData.GetMaxDurability() * num4);
					}
				}
			}
		}

		private void OnDestroy()
		{
			_store?.Save();
		}
	}
	internal readonly struct CellCoord : IEquatable<CellCoord>
	{
		public readonly int X;

		public readonly int Z;

		public Vector3 Center => new Vector3(((float)X + 0.5f) * Plugin.CellSize, 0f, ((float)Z + 0.5f) * Plugin.CellSize);

		public CellCoord(int x, int z)
		{
			X = x;
			Z = z;
		}

		public static CellCoord FromWorld(Vector3 p)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			return new CellCoord(Mathf.FloorToInt(p.x / Plugin.CellSize), Mathf.FloorToInt(p.z / Plugin.CellSize));
		}

		public int StableSeed()
		{
			int num = 17;
			num = num * 31 + X;
			return num * 31 + Z;
		}

		public bool Equals(CellCoord other)
		{
			return X == other.X && Z == other.Z;
		}

		public override bool Equals(object obj)
		{
			return obj is CellCoord other && Equals(other);
		}

		public override int GetHashCode()
		{
			return (X * 397) ^ Z;
		}

		public override string ToString()
		{
			return $"{X},{Z}";
		}
	}
	internal sealed class LootRule
	{
		public string Prefab;

		public float Chance;

		public int MinAmount;

		public int MaxAmount;

		public float MinimumDepth;

		public float MinimumDistanceFromCenter;

		public bool HasDurabilityRange;

		public float MinDurability;

		public float MaxDurability;

		public static List<LootRule> ParseList(string text, ManualLogSource log)
		{
			List<LootRule> list = new List<LootRule>();
			if (string.IsNullOrWhiteSpace(text))
			{
				return list;
			}
			string[] array = text.Split(new char[1] { ';' }, StringSplitOptions.RemoveEmptyEntries);
			string[] array2 = array;
			foreach (string text2 in array2)
			{
				string[] array3 = text2.Split(new char[1] { ',' });
				if (array3.Length != 6 && array3.Length != 8)
				{
					log.LogWarning((object)("Invalid loot entry '" + text2 + "'. Expected Prefab,Chance,MinAmount,MaxAmount,MinimumDepth,MinimumDistanceFromCenter[,MinDurability,MaxDurability]."));
					continue;
				}
				string text3 = array3[0].Trim();
				if (string.IsNullOrWhiteSpace(text3))
				{
					continue;
				}
				if (!float.TryParse(array3[1].Trim(), NumberStyles.Float, CultureInfo.InvariantCulture, out var result) || !int.TryParse(array3[2].Trim(), NumberStyles.Integer, CultureInfo.InvariantCulture, out var result2) || !int.TryParse(array3[3].Trim(), NumberStyles.Integer, CultureInfo.InvariantCulture, out var result3) || !float.TryParse(array3[4].Trim(), NumberStyles.Float, CultureInfo.InvariantCulture, out var result4) || !float.TryParse(array3[5].Trim(), NumberStyles.Float, CultureInfo.InvariantCulture, out var result5))
				{
					log.LogWarning((object)("Invalid numeric value in loot entry '" + text2 + "'."));
					continue;
				}
				if (result < 0f || result > 1f)
				{
					log.LogWarning((object)("Chance for '" + text3 + "' must be between 0 and 1. Entry skipped."));
					continue;
				}
				if (result2 < 1 || result3 < result2)
				{
					log.LogWarning((object)("Invalid amount range for '" + text3 + "'. Entry skipped."));
					continue;
				}
				if (result4 < 0f || result5 < 0f)
				{
					log.LogWarning((object)("MinimumDepth for '" + text3 + "' cannot be negative. Entry skipped."));
					continue;
				}
				LootRule lootRule = new LootRule
				{
					Prefab = text3,
					Chance = result,
					MinAmount = result2,
					MaxAmount = result3,
					MinimumDepth = result4,
					MinimumDistanceFromCenter = result5
				};
				if (array3.Length == 8)
				{
					if (!float.TryParse(array3[6].Trim(), NumberStyles.Float, CultureInfo.InvariantCulture, out var result6) || !float.TryParse(array3[7].Trim(), NumberStyles.Float, CultureInfo.InvariantCulture, out var result7) || result6 < 0f || result7 > 1f || result7 < result6)
					{
						log.LogWarning((object)("Invalid durability range in loot entry '" + text2 + "'."));
						continue;
					}
					lootRule.HasDurabilityRange = true;
					lootRule.MinDurability = result6;
					lootRule.MaxDurability = result7;
				}
				list.Add(lootRule);
			}
			return list;
		}
	}
	internal static class WorldQueries
	{
		private static readonly MethodInfo FindHeightmap = AccessTools.Method(typeof(Heightmap), "FindHeightmap", new Type[1] { typeof(Vector3) }, (Type[])null);

		private static readonly MethodInfo HeightmapGetBiome = typeof(Heightmap).GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).FirstOrDefault((MethodInfo m) => m.Name == "GetBiome" && m.ReturnType == typeof(Biome) && m.GetParameters().Length == 1 && m.GetParameters()[0].ParameterType == typeof(Vector3));

		private static readonly MethodInfo ZoneGetGroundHeight = typeof(ZoneSystem).GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).FirstOrDefault((MethodInfo m) => m.Name == "GetGroundHeight" && m.ReturnType == typeof(bool) && m.GetParameters().Length >= 2 && m.GetParameters()[0].ParameterType == typeof(Vector3));

		private static readonly MethodInfo ZoneGetWaterLevel = typeof(ZoneSystem).GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).FirstOrDefault((MethodInfo m) => m.Name == "GetWaterLevel" && m.GetParameters().Length >= 1 && m.GetParameters()[0].ParameterType == typeof(Vector3));

		public static bool TryGetNaturalSeabed(Vector3 xz, out Vector3 seabed, out float waterLevel, out float depth, out Biome biome)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_012c: Unknown result type (might be due to invalid IL or missing references)
			//IL_012d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0133: Expected I4, but got Unknown
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0141: 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)
			//IL_011d: Unknown result type (might be due to invalid IL or missing references)
			//IL_011e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0124: Expected I4, but got Unknown
			//IL_0107: 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_0119: Expected I4, but got Unknown
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			seabed = default(Vector3);
			waterLevel = 0f;
			depth = 0f;
			biome = (Biome)0;
			if ((Object)(object)ZoneSystem.instance == (Object)null)
			{
				return false;
			}
			if (!TryGroundHeight(xz, out var height))
			{
				return false;
			}
			Vector3 val = default(Vector3);
			((Vector3)(ref val))..ctor(xz.x, height, xz.z);
			if (!TryWaterLevel(val, out waterLevel))
			{
				return false;
			}
			depth = waterLevel - height;
			if (depth <= 0.05f)
			{
				return false;
			}
			Heightmap val2 = null;
			try
			{
				if (FindHeightmap != null)
				{
					object? obj = FindHeightmap.Invoke(null, new object[1] { val });
					val2 = (Heightmap)((obj is Heightmap) ? obj : null);
				}
			}
			catch
			{
			}
			if ((Object)(object)val2 == (Object)null)
			{
				return false;
			}
			try
			{
				if (HeightmapGetBiome != null)
				{
					biome = (Biome)(int)(Biome)HeightmapGetBiome.Invoke(val2, new object[1] { val });
				}
				else
				{
					biome = (Biome)(int)Heightmap.FindBiome(val);
				}
			}
			catch
			{
				try
				{
					biome = (Biome)(int)Heightmap.FindBiome(val);
				}
				catch
				{
					return false;
				}
			}
			seabed = val;
			return (int)biome != 0;
		}

		private static bool TryGroundHeight(Vector3 p, out float height)
		{
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			height = 0f;
			if (ZoneGetGroundHeight == null)
			{
				return false;
			}
			try
			{
				ParameterInfo[] parameters = ZoneGetGroundHeight.GetParameters();
				object[] array = new object[parameters.Length];
				array[0] = p;
				for (int i = 1; i < parameters.Length; i++)
				{
					Type parameterType = parameters[i].ParameterType;
					Type type = (parameterType.IsByRef ? parameterType.GetElementType() : parameterType);
					array[i] = ((type == typeof(float)) ? ((object)0f) : ((type == typeof(Vector3)) ? ((object)Vector3.zero) : (type.IsValueType ? Activator.CreateInstance(type) : null)));
				}
				if (!(ZoneGetGroundHeight.Invoke(ZoneSystem.instance, array) is bool flag) || !flag)
				{
					return false;
				}
				for (int j = 1; j < parameters.Length; j++)
				{
					Type type2 = (parameters[j].ParameterType.IsByRef ? parameters[j].ParameterType.GetElementType() : parameters[j].ParameterType);
					if (type2 == typeof(float))
					{
						height = (float)array[j];
						return true;
					}
				}
			}
			catch
			{
			}
			return false;
		}

		private static bool TryWaterLevel(Vector3 p, out float water)
		{
			//IL_0032: 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)
			water = 0f;
			if (ZoneGetWaterLevel != null)
			{
				try
				{
					ParameterInfo[] parameters = ZoneGetWaterLevel.GetParameters();
					object[] array = new object[parameters.Length];
					array[0] = p;
					for (int i = 1; i < parameters.Length; i++)
					{
						Type parameterType = parameters[i].ParameterType;
						Type type = (parameterType.IsByRef ? parameterType.GetElementType() : parameterType);
						array[i] = ((type == typeof(float)) ? ((object)0f) : ((type == typeof(Vector3)) ? ((object)Vector3.zero) : (type.IsValueType ? Activator.CreateInstance(type) : null)));
					}
					object obj = ZoneGetWaterLevel.Invoke(ZoneSystem.instance, array);
					if (obj is float num)
					{
						water = num;
						return !float.IsNaN(num);
					}
					bool flag = default(bool);
					int num2;
					if (obj is bool)
					{
						flag = (bool)obj;
						num2 = 1;
					}
					else
					{
						num2 = 0;
					}
					if (((uint)num2 & (flag ? 1u : 0u)) != 0)
					{
						for (int j = 1; j < parameters.Length; j++)
						{
							Type type2 = (parameters[j].ParameterType.IsByRef ? parameters[j].ParameterType.GetElementType() : parameters[j].ParameterType);
							if (type2 == typeof(float))
							{
								water = (float)array[j];
								return true;
							}
						}
					}
				}
				catch
				{
				}
			}
			try
			{
				FieldInfo fieldInfo = AccessTools.Field(typeof(ZoneSystem), "m_waterLevel");
				if (fieldInfo != null)
				{
					water = Convert.ToSingle(fieldInfo.GetValue(ZoneSystem.instance));
					return true;
				}
			}
			catch
			{
			}
			return false;
		}
	}
	internal sealed class ProcessedCellStore
	{
		private readonly HashSet<CellCoord> _cells = new HashSet<CellCoord>();

		private readonly ManualLogSource _log;

		private string _loadedWorld = "";

		private string _path = "";

		private bool _dirty;

		public ProcessedCellStore(ManualLogSource log)
		{
			_log = log;
		}

		public bool IsProcessed(CellCoord c)
		{
			EnsureWorld();
			return _cells.Contains(c);
		}

		public void MarkProcessed(CellCoord c)
		{
			EnsureWorld();
			if (_cells.Add(c))
			{
				_dirty = true;
				if ((_cells.Count & 0x7F) == 0)
				{
					Save();
				}
			}
		}

		private void EnsureWorld()
		{
			string worldKey = GetWorldKey();
			if (worldKey == _loadedWorld)
			{
				return;
			}
			Save();
			_cells.Clear();
			_loadedWorld = worldKey;
			string text = MakeSafeFileName(worldKey);
			string text2 = Path.Combine(Paths.ConfigPath, "DeepSeaTreasures");
			Directory.CreateDirectory(text2);
			_path = Path.Combine(text2, "processed_" + text + ".txt");
			if (!File.Exists(_path))
			{
				return;
			}
			string[] array = File.ReadAllLines(_path);
			foreach (string text3 in array)
			{
				string[] array2 = text3.Split(new char[1] { ',' });
				if (array2.Length == 2 && int.TryParse(array2[0], NumberStyles.Integer, CultureInfo.InvariantCulture, out var result) && int.TryParse(array2[1], NumberStyles.Integer, CultureInfo.InvariantCulture, out var result2))
				{
					_cells.Add(new CellCoord(result, result2));
				}
			}
			_log.LogInfo((object)$"Loaded {_cells.Count} processed treasure cells for world '{worldKey}'.");
		}

		public void Save()
		{
			if (!_dirty || string.IsNullOrEmpty(_path))
			{
				return;
			}
			try
			{
				using (StreamWriter streamWriter = new StreamWriter(_path, append: false))
				{
					foreach (CellCoord cell in _cells)
					{
						int x = cell.X;
						string text = x.ToString(CultureInfo.InvariantCulture);
						x = cell.Z;
						streamWriter.WriteLine(text + "," + x.ToString(CultureInfo.InvariantCulture));
					}
				}
				_dirty = false;
			}
			catch (Exception ex)
			{
				_log.LogWarning((object)("Could not save processed-cell database: " + ex.Message));
			}
		}

		private static string GetWorldKey()
		{
			try
			{
				if ((Object)(object)ZNet.instance != (Object)null)
				{
					World world = ZNet.instance.GetWorld();
					if (world != null)
					{
						return world.m_name + "_" + world.m_seedName;
					}
				}
			}
			catch
			{
			}
			return "unknown_world";
		}

		private static string MakeSafeFileName(string s)
		{
			char[] invalidFileNameChars = Path.GetInvalidFileNameChars();
			foreach (char oldChar in invalidFileNameChars)
			{
				s = s.Replace(oldChar, '_');
			}
			return s;
		}
	}
}