Decompiled source of Riverheim v0.12.0

Riverheim.dll

Decompiled 5 months ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Numerics;
using System.Reflection;
using System.Reflection.Emit;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Cryptography;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using DelaunatorSharp;
using FxResources.Microsoft.Bcl.HashCode;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Riverheim.Pipeline;
using Riverheim.Rendering;
using Riverheim.Rendering.Rivers;
using Riverheim.Rendering.Splats;
using Riverheim.Util;
using Riverheim.Util.Debug;
using Riverheim.Util.Random;
using Riverheim.Util.Sdf;
using Riverheim.Util.Splines;
using Riverheim.Util.Tilings;
using Riverheim.Util.Tilings.Internal;
using Riverheim.World;
using Riverheim.World.Biomes;
using Riverheim.World.Height;
using Riverheim.World.Landmass;
using Riverheim.World.Landmass.Internal;
using Riverheim.World.Rivers;
using Riverheim.World.Rivers.Internal;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyCompany("Riverheim")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("Advanced terrain generator for Valheim")]
[assembly: AssemblyFileVersion("0.12.0.0")]
[assembly: AssemblyInformationalVersion("0.12.0+eded1471f6b43d8664b81558ce37d976b58a4e58")]
[assembly: AssemblyProduct("Riverheim")]
[assembly: AssemblyTitle("Riverheim")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.12.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.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;
		}
	}
}
internal static class PluginInfo
{
	public const string PLUGIN_GUID = "Riverheim";

	public const string PLUGIN_NAME = "Riverheim";

	public const string PLUGIN_VERSION = "0.12.0";
}
namespace Riverheim.Plugin
{
	[BepInPlugin("dev.gurebu.riverheim", "Riverheim", "0.12.0")]
	public class RiverheimPlugin : BaseUnityPlugin
	{
		private class ValheimWorldRenderer
		{
			[CompilerGenerated]
			private float <heightOffset>P;

			private readonly float BaseHeightScale;

			private readonly WorldRenderer Renderer;

			public ValheimWorldRenderer(RandomEngine random, CommonConfig commonConfig, WorldRenderer.Config config, WorldState state, float baseHeightMultiplier, float heightOffset, WorldGenerator worldGenInstance)
			{
				<heightOffset>P = heightOffset;
				BaseHeightScale = 1f / baseHeightMultiplier;
				Renderer = new WorldRenderer(random, commonConfig, config, state, delegate(Biome biome, Rfloat2 pos, out double height, out double meta)
				{
					//IL_0064: Unknown result type (might be due to invalid IL or missing references)
					switch (biome)
					{
					case Biome.AshLands:
					{
						height = baseHeightMultiplier * WorldGeneratorPatch.GetAshlandsHeight(worldGenInstance, (float)pos.x, (float)pos.y, out var mask, cheap: false) - <heightOffset>P;
						meta = mask.a;
						return true;
					}
					case Biome.DeepNorth:
						height = baseHeightMultiplier * WorldGeneratorPatch.GetDeepNorthHeight(worldGenInstance, (float)pos.x, (float)pos.y) - <heightOffset>P;
						meta = 1.0;
						return true;
					default:
						height = 0.0;
						meta = 1.0;
						return false;
					}
				});
				base..ctor();
			}

			private static Biome ToValheim(Biome biome)
			{
				//IL_002f: 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_0037: Unknown result type (might be due to invalid IL or missing references)
				//IL_003b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0040: 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_004a: Unknown result type (might be due to invalid IL or missing references)
				//IL_0052: Unknown result type (might be due to invalid IL or missing references)
				//IL_005a: Unknown result type (might be due to invalid IL or missing references)
				//IL_005f: 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)
				return (Biome)(biome switch
				{
					Biome.Meadows => 1, 
					Biome.Swamp => 2, 
					Biome.Mountain => 4, 
					Biome.BlackForest => 8, 
					Biome.Plains => 16, 
					Biome.AshLands => 32, 
					Biome.DeepNorth => 64, 
					Biome.Ocean => 256, 
					Biome.Mistlands => 512, 
					_ => 0, 
				});
			}

			private static Biome ToRiverheim(Biome biome)
			{
				//IL_0000: Unknown result type (might be due to invalid IL or missing references)
				//IL_0003: Invalid comparison between Unknown and I4
				//IL_003b: Unknown result type (might be due to invalid IL or missing references)
				//IL_003e: Invalid comparison between Unknown and I4
				//IL_0005: Unknown result type (might be due to invalid IL or missing references)
				//IL_002f: Expected I4, but got Unknown
				//IL_0040: Unknown result type (might be due to invalid IL or missing references)
				//IL_0046: Invalid comparison between Unknown and I4
				//IL_002f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0032: Invalid comparison between Unknown and I4
				//IL_0048: Unknown result type (might be due to invalid IL or missing references)
				//IL_004e: Invalid comparison between Unknown and I4
				//IL_0034: Unknown result type (might be due to invalid IL or missing references)
				//IL_0037: Invalid comparison between Unknown and I4
				if ((int)biome <= 32)
				{
					switch ((int)biome)
					{
					default:
						if ((int)biome != 16)
						{
							if ((int)biome != 32)
							{
								break;
							}
							return Biome.AshLands;
						}
						return Biome.Plains;
					case 1:
						return Biome.Meadows;
					case 2:
						return Biome.Swamp;
					case 4:
						return Biome.Mountain;
					case 8:
						return Biome.BlackForest;
					case 0:
						return Biome.None;
					case 3:
					case 5:
					case 6:
					case 7:
						break;
					}
				}
				else
				{
					if ((int)biome == 64)
					{
						return Biome.DeepNorth;
					}
					if ((int)biome == 256)
					{
						return Biome.Ocean;
					}
					if ((int)biome == 512)
					{
						return Biome.Mistlands;
					}
				}
				return Biome.None;
			}

			public float GetBaseHeight(float wx, float wy)
			{
				return BaseHeightScale * (<heightOffset>P + (float)Renderer.GetBaseHeight(new Rfloat2(wx, wy)));
			}

			public float GetBiomeHeight(Biome biome, float wx, float wy, out Color mask)
			{
				//IL_000c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0037: Unknown result type (might be due to invalid IL or missing references)
				//IL_003c: Unknown result type (might be due to invalid IL or missing references)
				double meta;
				float result = <heightOffset>P + (float)Renderer.GetBiomeHeight(ToRiverheim(biome), new Rfloat2(wx, wy), out meta);
				mask = new Color(0f, 0f, 0f, (float)meta);
				return result;
			}

			public Biome GetBiome(float wx, float wy)
			{
				//IL_0014: Unknown result type (might be due to invalid IL or missing references)
				return ToValheim(Renderer.GetBiome(new Rfloat2(wx, wy)));
			}

			public float GetVegetationDensity(float wx, float wy)
			{
				return (float)Renderer.GetVegetationDensity(new Rfloat2(wx, wy));
			}
		}

		[HarmonyPatch(typeof(WorldGenerator))]
		private static class WorldGeneratorPatch
		{
			private static readonly ConditionalWeakTable<WorldGenerator, ValheimWorldRenderer> Renderers = new ConditionalWeakTable<WorldGenerator, ValheimWorldRenderer>();

			[HarmonyPrefix]
			[HarmonyPatch("Pregenerate")]
			private static bool Pregenerate(WorldGenerator __instance)
			{
				WorldStateGenerator obj = new WorldStateGenerator
				{
					Verbose = true
				};
				WorldState state = obj.Generate(__instance.GetSeed(), DefaultConfig.Config());
				Logger.LogInfo(obj.GetResult<WorldMetrics>());
				Renderers.Add(__instance, new ValheimWorldRenderer(new RandomEngine(__instance.GetSeed()), DefaultConfig.Config().common, DefaultConfig.RendererConfig(), state, WorldGenerator.GetHeightMultiplier(), 30f, __instance));
				return false;
			}

			[HarmonyPrefix]
			[HarmonyPatch("GetBaseHeight")]
			private static bool GetBaseHeight(WorldGenerator __instance, float wx, float wy, bool menuTerrain, ref float __result)
			{
				if (menuTerrain || !Renderers.TryGetValue(__instance, out var value))
				{
					return true;
				}
				__result = value.GetBaseHeight(wx, wy);
				return false;
			}

			[HarmonyPrefix]
			[HarmonyPatch("GetBiomeHeight")]
			private static bool GetBiomeHeight(WorldGenerator __instance, Biome biome, float wx, float wy, out Color mask, ref float __result, World ___m_world)
			{
				//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_0029: Unknown result type (might be due to invalid IL or missing references)
				mask = Color.black;
				if (___m_world.m_menu || !Renderers.TryGetValue(__instance, out var value))
				{
					return true;
				}
				__result = value.GetBiomeHeight(biome, wx, wy, out mask);
				return false;
			}

			[HarmonyPrefix]
			[HarmonyPatch("GetBiome", new Type[]
			{
				typeof(float),
				typeof(float),
				typeof(float),
				typeof(bool)
			})]
			private static bool GetBiome(WorldGenerator __instance, float wx, float wy, ref Biome __result, World ___m_world)
			{
				//IL_001e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0024: Expected I4, but got Unknown
				if (___m_world.m_menu || !Renderers.TryGetValue(__instance, out var value))
				{
					return true;
				}
				__result = (Biome)(int)value.GetBiome(wx, wy);
				return false;
			}

			[HarmonyPrefix]
			[HarmonyPatch("GetForestFactor")]
			private static bool GetForestFactor(ref Vector3 pos, ref float __result)
			{
				if (!Renderers.TryGetValue(WorldGenerator.instance, out var value))
				{
					return true;
				}
				__result = value.GetVegetationDensity(pos.x, pos.z);
				return false;
			}

			[HarmonyReversePatch(/*Could not decode attribute arguments.*/)]
			[HarmonyPatch("GetAshlandsHeight")]
			internal static float GetAshlandsHeight(object instance, float wx, float wy, out Color mask, bool cheap)
			{
				throw new Exception();
			}

			[HarmonyReversePatch(/*Could not decode attribute arguments.*/)]
			[HarmonyPatch("GetDeepNorthHeight")]
			internal static float GetDeepNorthHeight(object instance, float wx, float wy)
			{
				throw new Exception();
			}

			[HarmonyPostfix]
			[HarmonyPatch("Initialize")]
			private static void Initialize()
			{
				ExpressPerfTest.Measure(WorldGenerator.instance);
			}
		}

		private static class ExpressPerfTest
		{
			private const int COUNT = 1000000;

			[MethodImpl(MethodImplOptions.NoOptimization)]
			public static void Measure(WorldGenerator worldGen)
			{
				//IL_0062: Unknown result type (might be due to invalid IL or missing references)
				//IL_0067: Unknown result type (might be due to invalid IL or missing references)
				//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
				//IL_00bb: Expected I4, but got Unknown
				Logger.LogInfo("Express testing performance...");
				float worldSize = DefaultConfig.Config().common.WorldSize;
				Vector2[] array = (Vector2[])(object)new Vector2[1000000];
				for (int i = 0; i < 1000000; i++)
				{
					float num = Mathf.Sqrt(Random.value * worldSize);
					float num2 = Random.value * (float)Math.PI * 2f;
					array[i] = new Vector2(num * Mathf.Cos(num2), num * Mathf.Sin(num2));
				}
				Biome[] array2 = (Biome[])(object)new Biome[1000000];
				DateTime now = DateTime.Now;
				for (int j = 0; j < 1000000; j++)
				{
					array2[j] = (Biome)(int)worldGen.GetBiome(array[j].x, array[j].y, 0.02f, false);
				}
				float num3 = (float)(DateTime.Now - now).TotalMilliseconds;
				now = DateTime.Now;
				Color val = default(Color);
				for (int k = 0; k < 1000000; k++)
				{
					worldGen.GetBiomeHeight(array2[k], array[k].x, array[k].y, ref val, false);
				}
				float num4 = (float)(DateTime.Now - now).TotalMilliseconds;
				Logger.LogInfo($"GetBiome(): {1000000f / num3:0.00} calls/ms");
				Logger.LogInfo($"GetBiomeHeight(): {1000000f / num4:0.00} calls/ms");
				Logger.LogInfo($"Combined: {1000000f / (num3 + num4):0.00} calls/ms");
			}
		}

		[HarmonyPatch(typeof(World))]
		private static class WorldSaveLoadPatch
		{
			private const int CUSTOM_WORLDGEN_MARKER = -1;

			private const string RIVERHEIM_WORLDGEN = "dev.gurebu.riverheim";

			private static void WriteCustomMetaData(ZPackage package)
			{
				package.Write(-1);
				package.Write("dev.gurebu.riverheim");
			}

			private static bool ReadCustomMetaData(ZPackage package)
			{
				int num = package.ReadInt();
				if (num != -1)
				{
					ZLog.Log((object)$"World doesn't have custom worldgen marker {-1}, instead got: {num}, skipping");
					return false;
				}
				string text = package.ReadString();
				if (text != "dev.gurebu.riverheim")
				{
					ZLog.Log((object)("Custom worldgen '" + text + "' does not match 'dev.gurebu.riverheim', skipping"));
					return false;
				}
				return true;
			}

			[HarmonyTranspiler]
			[HarmonyPatch("SaveWorldMetaData")]
			[HarmonyPatch(/*Could not decode attribute arguments.*/)]
			private static IEnumerable<CodeInstruction> TranspileWorldSave(IEnumerable<CodeInstruction> instructions)
			{
				//IL_0002: Unknown result type (might be due to invalid IL or missing references)
				//IL_000e: Expected O, but got Unknown
				CodeInstruction pushZPackage;
				return CodeMatcherExtensions.AdvanceToAfterZPackageConstructor(new CodeMatcher(instructions, (ILGenerator)null), out pushZPackage).InsertAndAdvance((CodeInstruction[])(object)new CodeInstruction[1] { pushZPackage }).InsertAndAdvance((CodeInstruction[])(object)new CodeInstruction[1] { CodeInstruction.Call(typeof(WorldSaveLoadPatch), "WriteCustomMetaData", (Type[])null, (Type[])null) })
					.InstructionEnumeration();
			}

			[HarmonyTranspiler]
			[HarmonyPatch("LoadWorld")]
			private static IEnumerable<CodeInstruction> TranspileWorldLoad(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
			{
				//IL_0002: Unknown result type (might be due to invalid IL or missing references)
				//IL_000e: Expected O, but got Unknown
				//IL_0060: Unknown result type (might be due to invalid IL or missing references)
				//IL_0066: Expected O, but got Unknown
				Label label;
				CodeInstruction pushZPackage;
				return CodeMatcherExtensions.MatchBadVersionWorldConstructor(new CodeMatcher(instructions, generator), out label).Start().AdvanceToAfterZPackageConstructor(out pushZPackage)
					.InsertAndAdvance((CodeInstruction[])(object)new CodeInstruction[1] { pushZPackage })
					.InsertAndAdvance((CodeInstruction[])(object)new CodeInstruction[1] { CodeInstruction.Call(typeof(WorldSaveLoadPatch), "ReadCustomMetaData", (Type[])null, (Type[])null) })
					.InsertAndAdvance((CodeInstruction[])(object)new CodeInstruction[1]
					{
						new CodeInstruction(OpCodes.Brfalse_S, (object)label)
					})
					.InstructionEnumeration();
			}
		}

		[HarmonyPatch(typeof(World))]
		private static class WorldServerLoadPatch
		{
			[HarmonyPrefix]
			[HarmonyPatch("GetCreateWorld")]
			private static void GetCreateWorld(ref World __result, string name, FileSource source)
			{
				//IL_001e: 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)
				SaveWithBackups val = default(SaveWithBackups);
				if (SaveSystem.TryGetSaveByName(name, (SaveDataType)0, ref val) && !val.IsDeleted)
				{
					__result = World.LoadWorld(val);
					if ((int)__result.m_dataError != 0)
					{
						throw new Exception($"Failed to load world with name \"{name}\", data error {__result.m_dataError}.");
					}
				}
			}
		}

		[HarmonyPatch(typeof(ZNet))]
		private static class ZNetPatch
		{
			private static readonly Version localVersion = new Version("0.12.0");

			private static readonly ConditionalWeakTable<ZRpc, Version> PeerVersions = new ConditionalWeakTable<ZRpc, Version>();

			private static bool VersionIsCompatible(Version remoteVersion)
			{
				if (localVersion.Major == remoteVersion.Major)
				{
					return localVersion.Minor == remoteVersion.Minor;
				}
				return false;
			}

			private static void RPC_AssertModVersion(ZRpc sender, string versionString)
			{
				Version version = new Version(versionString);
				PeerVersions.Add(sender, version);
				if (!VersionIsCompatible(version))
				{
					ZLog.Log((object)$"Riverheim plugin version mismatch! Local version: {localVersion}, remote: {version}");
					sender.Invoke("Error", new object[1] { (object)(ConnectionStatus)3 });
				}
			}

			[HarmonyPriority(700)]
			[HarmonyPrefix]
			[HarmonyPatch("OnNewConnection")]
			private static void OnNewConnection(ZNet __instance, ZNetPeer peer)
			{
				peer.m_rpc.Register<string>("AssertRiverheimVersion", (Action<ZRpc, string>)RPC_AssertModVersion);
			}

			[HarmonyPriority(700)]
			[HarmonyPrefix]
			[HarmonyPatch("RPC_ClientHandshake")]
			private static void RPC_ClientHandshake(ZNet __instance, ZRpc rpc)
			{
				rpc.Invoke("AssertRiverheimVersion", new object[1] { "0.12.0" });
			}

			[HarmonyPriority(700)]
			[HarmonyPrefix]
			[HarmonyPatch("RPC_ServerHandshake")]
			private static void RPC_ServerHandshake(ZNet __instance, ZRpc rpc)
			{
				rpc.Invoke("AssertRiverheimVersion", new object[1] { "0.12.0" });
			}

			[HarmonyPriority(700)]
			[HarmonyPrefix]
			[HarmonyPatch("SendPeerInfo")]
			private static bool SendPeerInfo(ZNet __instance, ZRpc rpc)
			{
				if (ZNet.instance.IsServer())
				{
					return true;
				}
				if (PeerVersions.TryGetValue(rpc, out var value) && VersionIsCompatible(value))
				{
					return true;
				}
				ZLog.Log((object)$"Riverheim plugin version mismatch! Local version: {localVersion}, remote: {value}");
				rpc.Invoke("Disconnect", Array.Empty<object>());
				return false;
			}

			[HarmonyPriority(700)]
			[HarmonyPrefix]
			[HarmonyPatch("RPC_PeerInfo")]
			private static bool RPC_PeerInfo(ZNet __instance, ZRpc rpc)
			{
				if (!ZNet.instance.IsServer())
				{
					return true;
				}
				if (PeerVersions.TryGetValue(rpc, out var value) && VersionIsCompatible(value))
				{
					return true;
				}
				ZLog.Log((object)$"Riverheim plugin version mismatch! Local version: {localVersion}, remote: {value}");
				rpc.Invoke("Error", new object[1] { (object)(ConnectionStatus)3 });
				return false;
			}
		}

		public const string GUID = "dev.gurebu.riverheim";

		public void Awake()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			new Harmony("dev.gurebu.riverheim").PatchAll();
			Logger.SetLogger(delegate(Logger.LogLevel level, object message)
			{
				switch (level)
				{
				case Logger.LogLevel.Info:
					((BaseUnityPlugin)this).Logger.LogInfo(message);
					break;
				case Logger.LogLevel.Warning:
					((BaseUnityPlugin)this).Logger.LogWarning(message);
					break;
				case Logger.LogLevel.Error:
					((BaseUnityPlugin)this).Logger.LogError(message);
					break;
				default:
					throw new ArgumentOutOfRangeException("level", level, null);
				}
			});
		}
	}
	internal static class CodeMatcherExtensions
	{
		public static CodeMatcher AdvanceToAfterZPackageConstructor(this CodeMatcher matcher, out CodeInstruction pushZPackage)
		{
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Expected O, but got Unknown
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Expected O, but got Unknown
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Expected O, but got Unknown
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Expected O, but got Unknown
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Expected O, but got Unknown
			//IL_011d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0123: Expected O, but got Unknown
			//IL_0104: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: Expected O, but got Unknown
			matcher.MatchForward(true, (CodeMatch[])(object)new CodeMatch[2]
			{
				new CodeMatch((Func<CodeInstruction, bool>)((CodeInstruction instruction) => !(instruction.opcode != OpCodes.Newobj) && ((ConstructorInfo)instruction.operand).DeclaringType == typeof(ZPackage)), (string)null),
				new CodeMatch((Func<CodeInstruction, bool>)((CodeInstruction instruction) => CodeInstructionExtensions.IsStloc(instruction, (LocalBuilder)null)), (string)null)
			});
			if (matcher.IsInvalid)
			{
				throw new InvalidOperationException("Error patching, unable to find zPackage instancing");
			}
			if (matcher.Instruction.opcode == OpCodes.Stloc_0)
			{
				pushZPackage = new CodeInstruction(OpCodes.Ldloc_0, (object)null);
			}
			else if (matcher.Instruction.opcode == OpCodes.Stloc_1)
			{
				pushZPackage = new CodeInstruction(OpCodes.Ldloc_1, (object)null);
			}
			else if (matcher.Instruction.opcode == OpCodes.Stloc_2)
			{
				pushZPackage = new CodeInstruction(OpCodes.Ldloc_2, (object)null);
			}
			else if (matcher.Instruction.opcode == OpCodes.Stloc_3)
			{
				pushZPackage = new CodeInstruction(OpCodes.Ldloc_3, (object)null);
			}
			else
			{
				pushZPackage = new CodeInstruction(OpCodes.Ldloc_S, matcher.Instruction.operand);
			}
			return matcher.Advance(1);
		}

		public static CodeMatcher MatchBadVersionWorldConstructor(this CodeMatcher matcher, out Label label)
		{
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Expected O, but got Unknown
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Expected O, but got Unknown
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Expected O, but got Unknown
			matcher.MatchForward(false, (CodeMatch[])(object)new CodeMatch[3]
			{
				new CodeMatch((Func<CodeInstruction, bool>)((CodeInstruction instruction) => CodeInstructionExtensions.IsLdarg(instruction, (int?)null)), (string)null),
				new CodeMatch((Func<CodeInstruction, bool>)((CodeInstruction instruction) => instruction.opcode == OpCodes.Ldc_I4_1 || CodeInstructionExtensions.Is(instruction, OpCodes.Ldc_I4, (object)1) || CodeInstructionExtensions.Is(instruction, OpCodes.Ldc_I4_S, (object)1)), (string)null),
				new CodeMatch((Func<CodeInstruction, bool>)delegate(CodeInstruction instruction)
				{
					if (instruction.opcode != OpCodes.Newobj)
					{
						return false;
					}
					ConstructorInfo constructorInfo = (ConstructorInfo)instruction.operand;
					if (constructorInfo.DeclaringType != typeof(World))
					{
						return false;
					}
					ParameterInfo[] parameters = constructorInfo.GetParameters();
					if (parameters.Length != 2)
					{
						return false;
					}
					return parameters[0].ParameterType == typeof(SaveWithBackups) && parameters[1].ParameterType == typeof(SaveDataError);
				}, (string)null)
			});
			if (matcher.IsInvalid)
			{
				throw new InvalidOperationException("Error patching, unable to find World instancing");
			}
			matcher.CreateLabel(ref label);
			return matcher;
		}
	}
}
namespace Riverheim
{
	[Serializable]
	public readonly struct Rfloat2 : IEquatable<Rfloat2>
	{
		private const MethodImplOptions Inline = MethodImplOptions.AggressiveInlining;

		private const double TOLERANCE = 1E-06;

		public readonly double x;

		public readonly double y;

		public double Length
		{
			[MethodImpl(MethodImplOptions.AggressiveInlining)]
			get
			{
				return Math.Sqrt(x * x + y * y);
			}
		}

		public double SqrLength
		{
			[MethodImpl(MethodImplOptions.AggressiveInlining)]
			get
			{
				return x * x + y * y;
			}
		}

		public static Rfloat2 Zero => new Rfloat2(0.0, 0.0);

		public static Rfloat2 One => new Rfloat2(1.0, 1.0);

		public Rfloat2 Normalized
		{
			[MethodImpl(MethodImplOptions.AggressiveInlining)]
			get
			{
				double length = Length;
				return new Rfloat2(x / length, y / length);
			}
		}

		public Rfloat2(double x, double y)
		{
			this.x = x;
			this.y = y;
		}

		public Rfloat2(double val)
			: this(val, val)
		{
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static implicit operator Rfloat2(Rint2 ivec)
		{
			return new Rfloat2(ivec.x, ivec.y);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static double Distance(Rfloat2 lhs, Rfloat2 rhs)
		{
			return (lhs - rhs).Length;
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static double Dot(Rfloat2 lhs, Rfloat2 rhs)
		{
			return lhs.x * rhs.x + lhs.y * rhs.y;
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static double Cross(Rfloat2 lhs, Rfloat2 rhs)
		{
			return lhs.x * rhs.y - lhs.y * rhs.x;
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public double DistanceTo(Rfloat2 other)
		{
			return (this - other).Length;
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public Rint2 FloorToInt()
		{
			return new Rint2(Rmath.FloorToInt(x), Rmath.FloorToInt(y));
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public Rint2 CeilToInt()
		{
			return new Rint2(Rmath.CeilToInt(x), Rmath.CeilToInt(y));
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public Rint2 RoundToInt()
		{
			return new Rint2(Rmath.RoundToInt(x), Rmath.RoundToInt(y));
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public bool Equals(Rfloat2 other)
		{
			double num = x;
			if (num.Equals(other.x))
			{
				num = y;
				return num.Equals(other.y);
			}
			return false;
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public override bool Equals(object obj)
		{
			if (obj is Rfloat2 other)
			{
				return Equals(other);
			}
			return false;
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public override int GetHashCode()
		{
			return <cea2f7d2-7d32-438d-9027-5fd2d8593fdd>HashCode.Combine(x, y);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public override string ToString()
		{
			return $"({x}, {y})";
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static bool operator ==(Rfloat2 lhs, Rfloat2 rhs)
		{
			if (Math.Abs(lhs.x - rhs.x) < 1E-06)
			{
				return Math.Abs(lhs.y - rhs.y) < 1E-06;
			}
			return false;
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static bool operator !=(Rfloat2 lhs, Rfloat2 rhs)
		{
			if (!(Math.Abs(lhs.x - rhs.x) > 1E-06))
			{
				return Math.Abs(lhs.y - rhs.y) > 1E-06;
			}
			return true;
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static Rfloat2 operator +(Rfloat2 lhs, Rfloat2 rhs)
		{
			return new Rfloat2(lhs.x + rhs.x, lhs.y + rhs.y);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static Rfloat2 operator -(Rfloat2 lhs, Rfloat2 rhs)
		{
			return new Rfloat2(lhs.x - rhs.x, lhs.y - rhs.y);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static Rfloat2 operator -(Rfloat2 vec)
		{
			return new Rfloat2(0.0 - vec.x, 0.0 - vec.y);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static Rfloat2 operator +(Rfloat2 vec, double scalar)
		{
			return new Rfloat2(vec.x + scalar, vec.y + scalar);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static Rfloat2 operator +(double scalar, Rfloat2 vec)
		{
			return new Rfloat2(scalar * vec.x, scalar * vec.y);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static Rfloat2 operator -(Rfloat2 vec, double scalar)
		{
			return new Rfloat2(vec.x - scalar, vec.y - scalar);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static Rfloat2 operator -(double scalar, Rfloat2 vec)
		{
			return new Rfloat2(scalar - vec.x, scalar - vec.y);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static Rfloat2 operator *(Rfloat2 lhs, Rfloat2 rhs)
		{
			return new Rfloat2(lhs.x * rhs.x, lhs.y * rhs.y);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static Rfloat2 operator *(Rfloat2 vec, double scalar)
		{
			return new Rfloat2(vec.x * scalar, vec.y * scalar);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static Rfloat2 operator *(double scalar, Rfloat2 vec)
		{
			return new Rfloat2(scalar * vec.x, scalar * vec.y);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static Rfloat2 operator /(Rfloat2 lhs, Rfloat2 rhs)
		{
			return new Rfloat2(lhs.x / rhs.x, lhs.y / rhs.y);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static Rfloat2 operator /(Rfloat2 vec, double scalar)
		{
			return new Rfloat2(vec.x / scalar, vec.y / scalar);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static Rfloat2 operator /(double scalar, Rfloat2 vec)
		{
			return new Rfloat2(scalar / vec.x, scalar / vec.y);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static implicit operator Vector2(Rfloat2 vec)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			return new Vector2((float)vec.x, (float)vec.y);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static implicit operator Rfloat2(Vector2 vec)
		{
			//IL_0000: 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)
			return new Rfloat2(vec.x, vec.y);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static implicit operator Vector2(Rfloat2 vec)
		{
			return new Vector2((float)vec.x, (float)vec.y);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static implicit operator Rfloat2(Vector2 vec)
		{
			return new Rfloat2(vec.X, vec.Y);
		}
	}
	[Serializable]
	public struct Rint2 : IEquatable<Rint2>
	{
		private const MethodImplOptions Inline = MethodImplOptions.AggressiveInlining;

		public readonly int x;

		public readonly int y;

		public static Rint2 Zero => new Rint2(0, 0);

		public static Rint2 One => new Rint2(1, 1);

		public Rint2(int x, int y)
		{
			this.x = x;
			this.y = y;
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public bool Equals(Rint2 other)
		{
			if (x == other.x)
			{
				return y == other.y;
			}
			return false;
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public override bool Equals(object obj)
		{
			if (obj is Rint2 other)
			{
				return Equals(other);
			}
			return false;
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public override int GetHashCode()
		{
			return <cea2f7d2-7d32-438d-9027-5fd2d8593fdd>HashCode.Combine(x, y);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static bool operator ==(Rint2 left, Rint2 right)
		{
			return left.Equals(right);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static bool operator !=(Rint2 left, Rint2 right)
		{
			return !left.Equals(right);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public override string ToString()
		{
			return $"({x}, {y})";
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static Rint2 operator +(Rint2 lhs, Rint2 rhs)
		{
			return new Rint2(lhs.x + rhs.x, lhs.y + rhs.y);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static Rint2 operator -(Rint2 lhs, Rint2 rhs)
		{
			return new Rint2(lhs.x - rhs.x, lhs.y - rhs.y);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static Rint2 operator -(Rint2 vec)
		{
			return new Rint2(-vec.x, -vec.y);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static Rint2 operator +(Rint2 vec, int scalar)
		{
			return new Rint2(vec.x + scalar, vec.y + scalar);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static Rint2 operator +(int scalar, Rint2 vec)
		{
			return new Rint2(scalar * vec.x, scalar * vec.y);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static Rint2 operator -(Rint2 vec, int scalar)
		{
			return new Rint2(vec.x - scalar, vec.y - scalar);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static Rint2 operator -(int scalar, Rint2 vec)
		{
			return new Rint2(scalar - vec.x, scalar - vec.y);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static Rint2 operator *(Rint2 lhs, Rint2 rhs)
		{
			return new Rint2(lhs.x * rhs.x, lhs.y * rhs.x);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static Rint2 operator *(Rint2 vec, int scalar)
		{
			return new Rint2(vec.x * scalar, vec.y * scalar);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static Rint2 operator *(int scalar, Rint2 vec)
		{
			return new Rint2(scalar * vec.x, scalar * vec.y);
		}
	}
	public static class Rmath
	{
		private const short INLINE = 256;

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static int FloorToInt(double f)
		{
			if (f < 0.0)
			{
				return (int)f - 1;
			}
			return (int)f;
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static int CeilToInt(double f)
		{
			if (f > 0.0)
			{
				return (int)f + 1;
			}
			return (int)f;
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static int RoundToInt(double f)
		{
			return FloorToInt(f + 0.5);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static double Smooth3(double t)
		{
			return t * t * (3.0 - 2.0 * t);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static double Smooth5(double t)
		{
			return t * t * t * (t * (t * 6.0 - 15.0) + 10.0);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static double UnclampedLerp(double t, double a, double b)
		{
			return a + t * (b - a);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static double Lerp(double t, double a, double b)
		{
			return UnclampedLerp(Clamp01(t), a, b);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static double SmoothStep(double t, double a, double b)
		{
			if (!(t <= 0.0))
			{
				if (t >= 1.0)
				{
					return b;
				}
				return UnclampedLerp(Smooth3(t), a, b);
			}
			return a;
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static double SmoothStep5(double t, double a, double b)
		{
			if (!(t <= 0.0))
			{
				if (t >= 1.0)
				{
					return b;
				}
				return UnclampedLerp(Smooth5(t), a, b);
			}
			return a;
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static double InverseLerp(double value, double a, double b)
		{
			if (a.Equals(b))
			{
				return 0.0;
			}
			return Clamp01((value - a) / (b - a));
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static double Clamp(double value, double min, double max)
		{
			if (value < min)
			{
				return min;
			}
			if (!(value > max))
			{
				return value;
			}
			return max;
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static double Clamp01(double value)
		{
			if (!(value < 0.0))
			{
				if (value > 1.0)
				{
					return 1.0;
				}
				return value;
			}
			return 0.0;
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static double Sigmoid(double value)
		{
			return 2.0 / (1.0 + Math.Exp(-2.0 * value)) - 1.0;
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static double Bump(double value)
		{
			double num = Clamp(value, -1.0, 1.0);
			return Math.Exp(1.0 + 1.0 / (num * num - 1.0));
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static double Rectifier(double value)
		{
			if (!(value > 0.0))
			{
				return 0.0;
			}
			return value;
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		private static double PolySinglet(double x)
		{
			return -8.0 * x * x * (x - 1.0) * (x - 1.0) * (2.0 * x - 1.0);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static double ShapeStep(double x, double start, double end, double magnitude = 1.0)
		{
			return x + (end - start) * magnitude * PolySinglet(InverseLerp(x, start, end));
		}
	}
	public static class DefaultConfig
	{
		public static WorldStateGenerator.Config Config()
		{
			WorldStateGenerator.Config result = default(WorldStateGenerator.Config);
			result.common = new CommonConfig
			{
				WorldSize = 10500f,
				TileSpacing = 70f,
				MountainHeight = 50f,
				OceanDepth = -85f
			};
			result.polar = new PolarBeltConfig
			{
				offset = 4000f,
				radius = 12000f,
				width = 120f,
				noiseScale = 500f,
				variability = 0.7f
			};
			result.painter = new LandmassPainterConfig
			{
				layerCount = 6,
				layerScale = 2f,
				layerWarp = new VectorNoiseField.WarpConfig
				{
					frequency = 1f,
					intensity = 0.64f
				},
				layers = new StaticArray<LandmassLayerConfig>
				{
					new LandmassLayerConfig
					{
						budget = 0.05f,
						greediness = 0.2f,
						variance = 0.3f
					},
					new LandmassLayerConfig
					{
						budget = 0.06f,
						greediness = 0.4f,
						variance = 0.3f
					},
					new LandmassLayerConfig
					{
						budget = 0.08f,
						greediness = 0.5f,
						variance = 0.3f
					},
					new LandmassLayerConfig
					{
						budget = 0.09f,
						greediness = 0.6f,
						variance = 0.25f
					},
					new LandmassLayerConfig
					{
						budget = 0.12f,
						greediness = 0.8f,
						variance = 0.2f
					},
					new LandmassLayerConfig
					{
						budget = 0.2f,
						greediness = 0.9f,
						variance = 0.1f
					}
				}
			};
			result.painterRestrictions = new LandmassRestrictionConfig
			{
				swirlRays = 8,
				swirlExponent = 1.4f,
				swirlStartRadius = 5800f,
				swirlNoiseScale = 2000f,
				swirlNoiseOffset = 0.54f,
				swirlToleranceMult = 0.02f,
				toleranceScalePow = 0.8f,
				harbor = new HarborConfig
				{
					offset = 150f,
					radius = 1700f,
					circularity = 0.045f
				}
			};
			result.landmassPostprocessing = new LandmassPostprocessingConfig
			{
				coastalTrimNoiseScale = 200f,
				coastalTrimDistance = 80f,
				coastalTrimVariance = 0.32f,
				effectiveSpawnRadius = 280f
			};
			result.precipitation = new PrecipitationConfig
			{
				NoiseScale = 1050f,
				Variability = 1.9f,
				SpawnMinRadius = 300f,
				SpawnMaxRadius = 1500f,
				BasinContribution = 0.7f
			};
			result.rivers = new RiverConfig
			{
				startingDensity = 0.25f,
				startingVariability = 0.9f,
				weightRecovery = 0.05f,
				minRiverMouthLandNeighbors = 2,
				minRiverMouthPointerMagnitude = 0.8f,
				inlet = new RiverInletConfig
				{
					GoodBendAngle = (float)Math.PI / 6f,
					BadBendAngle = (float)Math.PI / 3f,
					MinBendScore = 0.05f,
					OptimalForkAngle = (float)Math.PI / 3f,
					OptimalForkAngleDiff = (float)Math.PI / 6f,
					WorstForkAngleDiff = (float)Math.PI / 2f,
					MinForkScore = 0.05f,
					flowthroughScoreMult = 16f,
					forkScoreMult = 256f
				},
				prune = new RiverPruneConfig
				{
					minStrahler = 2,
					minWidth = 12.5f,
					maxCatchmentDiff = 5.5f
				},
				width = new RiverWidthConfig
				{
					scale = 140f,
					power = 0.4f,
					offset = -5f
				}
			};
			result.riverCuriosities = new RiverCuriosityConfig
			{
				sourceMult = 0.1f,
				sourceMinLength = 150f,
				sourceMaxLength = 800f,
				proximityMult = 1f,
				proximityScanRange = 240f,
				proximityDifferentBasinsMultiplier = 1.5f,
				proximityMinRatio = 2.5f,
				proximityMaxRatio = 5f,
				angleMult = 1f,
				angleMinDegrees = 30f,
				angleMaxDegrees = 100f,
				angleNormWidth = 30f,
				smoothingRange = 180f
			};
			result.coastalProximityHeight = new CoastalProximityHeightComponent.Config
			{
				displacementNoiseScale = 800f,
				displacementNoiseThreshold = 0.5f,
				displacementMagnitudeLand = 300f,
				displacementMagnitudeWater = 150f,
				southPolarScale = 0.35f,
				oceanTrenchDepthScale = 5f,
				landProfile = new HeightUtility.CoastalProfileConfig
				{
					steepness = 0.5f,
					beachWidth = 120f,
					transitionSteepness = 1.7f
				},
				oceanProfileSteepness = 0.2f
			};
			result.heightClamping = new HeightClampingComponent.Config
			{
				minLandHeight = 40f,
				maxLandHeight = 390f,
				maxOceanDepth = -40f,
				noiseScale = 800f,
				noiseAmplitude = 0.3f,
				noiseFractal = new NoiseField.FractalConfig
				{
					Octaves = 3,
					Lacunarity = 1.8f,
					Gain = 0.6f
				},
				startingAreaInnerRadius = 800f,
				startingAreaOuterRadius = 1200f
			};
			result.heightFlatlands = new FlatlandsComponent.Config
			{
				lowlandNoise = new HeightUtility.SplatterNoiseConfig
				{
					scale = 1100f,
					modulationAmplitude = 3.65f,
					modulationFrequency = 5f,
					threshold = 0.22f
				},
				highlandNoise = new HeightUtility.SplatterNoiseConfig
				{
					scale = 1700f,
					modulationAmplitude = 3.2f,
					modulationFrequency = 6f,
					threshold = 0.15f
				}
			};
			result.lakes = new LakeComponent.Config
			{
				noiseScale = 600f,
				threshold = 0.9f,
				lowlandContribution = 0.35f,
				curiosityContribution = 0.8f
			};
			result.riverValleys = new RiverValleyComponent.Config
			{
				offset = -160f,
				magnitude = 13f,
				exponent = 0.5f,
				profileSteepness = 0.25f,
				profilePower = 1.12f
			};
			result.height = new HeightConfig
			{
				LowlandHeight = 8f,
				HillHeight = 40f,
				mountainSpikeHeight = 10f,
				smallMountainTileSpan = 3,
				mountainRemovalCutdown = 4f
			};
			result.biomes = new BiomeCalculationConfig
			{
				OceanDepth = -20f,
				MountainHeightWiggle = 5f,
				NoiseBiasContribution = 127f,
				NoiseModulationRatio = 6f,
				NoiseModulationIntensity = 0.13f,
				Meadows = new BiomeConfig
				{
					NoiseScale = 400f,
					TravelDistanceBias = new StaticArray<Rfloat2>(new Rfloat2[4]
					{
						new Rfloat2(180.0, 100.0),
						new Rfloat2(250.0, 50.0),
						new Rfloat2(500.0, 0.0),
						new Rfloat2(5000.0, -35.0)
					}),
					RiverDistanceBias = new StaticArray<Rfloat2>(new Rfloat2[2]
					{
						new Rfloat2(0.0, 15.0),
						new Rfloat2(140.0, 0.0)
					}),
					HeightBias = new StaticArray<Rfloat2>(new Rfloat2[2]
					{
						new Rfloat2(30.0, 0.0),
						new Rfloat2(40.0, -10.0)
					}),
					RoughnessBias = new StaticArray<Rfloat2>(new Rfloat2[2]
					{
						new Rfloat2(0.0, 0.0),
						new Rfloat2(1.0, -20.0)
					})
				},
				BlackForest = new BiomeConfig
				{
					NoiseScale = 700f,
					FixedBias = -5f
				},
				Swamp = new BiomeConfig
				{
					NoiseScale = 900f,
					FixedBias = 8f,
					TravelDistanceBias = new StaticArray<Rfloat2>(new Rfloat2[4]
					{
						new Rfloat2(1350.0, -100.0),
						new Rfloat2(2200.0, 0.0),
						new Rfloat2(5000.0, 0.0),
						new Rfloat2(7000.0, -100.0)
					}),
					CoastalDistanceBias = new StaticArray<Rfloat2>(new Rfloat2[2]
					{
						new Rfloat2(0.0, -90.0),
						new Rfloat2(300.0, 0.0)
					}),
					RiverDistanceBias = new StaticArray<Rfloat2>(new Rfloat2[3]
					{
						new Rfloat2(0.0, -25.0),
						new Rfloat2(140.0, -15.0),
						new Rfloat2(170.0, 0.0)
					}),
					HeightBias = new StaticArray<Rfloat2>(new Rfloat2[4]
					{
						new Rfloat2(-20.0, -100.0),
						new Rfloat2(-5.0, 60.0),
						new Rfloat2(5.0, 60.0),
						new Rfloat2(20.0, -100.0)
					}),
					RoughnessBias = new StaticArray<Rfloat2>(new Rfloat2[2]
					{
						new Rfloat2(0.0, 0.0),
						new Rfloat2(0.5, -20.0)
					})
				},
				Plains = new BiomeConfig
				{
					NoiseScale = 1200f,
					FixedBias = 5f,
					TravelDistanceBias = new StaticArray<Rfloat2>(new Rfloat2[4]
					{
						new Rfloat2(2800.0, -100.0),
						new Rfloat2(3200.0, 0.0),
						new Rfloat2(6800.0, 0.0),
						new Rfloat2(7200.0, -100.0)
					}),
					HeightBias = new StaticArray<Rfloat2>(new Rfloat2[2]
					{
						new Rfloat2(30.0, 0.0),
						new Rfloat2(40.0, -5.0)
					})
				},
				Mistlands = new BiomeConfig
				{
					NoiseScale = 1000f,
					TravelDistanceBias = new StaticArray<Rfloat2>(new Rfloat2[2]
					{
						new Rfloat2(5500.0, -100.0),
						new Rfloat2(6500.0, 10.0)
					}),
					CoastalDistanceBias = new StaticArray<Rfloat2>(new Rfloat2[2]
					{
						new Rfloat2(0.0, 10.0),
						new Rfloat2(200.0, 0.0)
					})
				}
			};
			result.biomePostprocessing = new BiomePostprocessingConfig
			{
				mountainHeightMinMultiplier = 1.1f,
				mountainHeightMaxMultiplier = 1.9f,
				mountainHeightNoiseScale = 300f,
				swampBaseHeight = -0.2f,
				plateauBumpHeight = 0.7f,
				plateauAmount = 0.45f,
				plateauNoiseScale = 650f,
				plateauMinProximity = 15f,
				plainSmoothOverWater = false,
				plainSmoothingRange = 100f
			};
			result.plateaus = new PlateauConfig
			{
				spawnNoiseScale = 700f,
				mountainPeaks = new PlateauMountainPeakConfig
				{
					spawnRate = 1f,
					minHeightDiff = 4f,
					minSize = 55f,
					maxSize = 70f,
					gradientClamping = new ClampingConfig
					{
						mode = ClampingConfig.Mode.Asymptotic,
						min = 0.3f,
						max = 0.9f,
						rate = 1.5f
					},
					bulgeMultiplier = 0.1f
				},
				seasideCliffs = new PlateauSeasideCliffConfig
				{
					spawnRate = 0.8f,
					minHeight = 22f,
					minSize = 30f,
					maxSize = 50f,
					gradientClamping = new ClampingConfig
					{
						mode = ClampingConfig.Mode.Asymptotic,
						min = 0f,
						max = 0.65f,
						rate = 0.9f
					},
					minBulge = 0.04f,
					maxBulge = 0.12f
				},
				hills = new PlateauHillConfig
				{
					spawnRate = 0.5f,
					minHeightDiff = 5f,
					minSize = 30f,
					maxSize = 50f,
					maxLength = 35f,
					gradientClamping = new ClampingConfig
					{
						mode = ClampingConfig.Mode.Linear,
						min = 0.2f,
						max = 0.35f,
						rate = 1f
					},
					bulgeMultiplier = 0.2f
				},
				swampDitchHeight = 2.5f,
				swampDitchTileCount = 10
			};
			return result;
		}

		public static WorldRenderer.Config RendererConfig()
		{
			WorldRenderer.Config result = default(WorldRenderer.Config);
			result.interpolationResolution = 40f;
			result.southPolarBeltScale = 0.5f;
			result.biomeWarp = new VectorNoiseField.WarpConfig
			{
				frequency = 2f,
				intensity = 0.4f
			};
			result.rivers = new RiverRenderer.Config
			{
				spatialIndexSpacing = 30f,
				sdfMergingRange = 15f,
				meanderAmplitude = 0.55f,
				meanderPeriod = 2.4f,
				width = new RiverRenderer.WidthConfig
				{
					depthPower = 1.5f,
					minShrinking = 0.1f
				},
				tesselation = new TesselationConfig
				{
					minStep = 0.5f,
					maxStep = 30f,
					stepRatio = 0.75f,
					tension = 0.4f,
					balance = -0.8f
				},
				profile = new RiverRenderer.ProfileConfig
				{
					useRationalProfile = true,
					minDepth = 2.5f,
					steepness = 0.25f,
					maxBankHeight = 70f,
					waterlineSmoothness = 0.8f,
					widthRangeStart = 10f,
					widthRangeEnd = 40f,
					steepnessRangeStart = 3.5f,
					steepnessRangeEnd = 2.3f,
					rationalProfileWidthToDepth = 3.3f,
					bankSmoothness = 3f,
					noiseScale = 40f,
					noiseAmplitude = 12f,
					noiseKickInStart = 0.5f,
					noiseKickInEnd = 1.2f,
					noiseCompensation = 0.35f,
					noiseFractal = new NoiseField.FractalConfig
					{
						Octaves = 3,
						Lacunarity = 2.5f,
						Gain = 0.6f
					}
				}
			};
			result.biomes = new BiomeRendererConfig
			{
				fine = new FineDetailConfig
				{
					largerScale = 10f,
					largerScaleMagnitude = 1f,
					smallerScale = 2.5f,
					smallerScaleMagnitude = 0.3f
				},
				coarse = new CoarseDetailConfig
				{
					largerScale = 100f,
					smallerScale = 20f
				},
				coarseDetailMagnitudes = new CoarseDetailMagnitudeConfig
				{
					meadows = 10f,
					forest = 25f,
					swamp = 7.5f,
					mountain = 51f,
					plains = 18f,
					mistlands = 102f
				},
				swamp = new SwampConfig
				{
					coarseScale = 25f,
					pathVerticalCutoff = 0.95f,
					pathBandWidth = 30f,
					pathBandDepth = -14f,
					pathNoiseScale = 200f,
					pathNoiseIntensity = 0.6f,
					pathWarp = new VectorNoiseField.WarpConfig
					{
						frequency = 2f,
						intensity = 0.15f
					},
					pathBlendingStrength = 0.5f
				},
				mistlands = new MistlandsConfig
				{
					largerScale = 71.5f,
					largerScaleMultiplier = 2f,
					smallerScale = 47.5f,
					smallerScaleMultiplier = 1.65f,
					pow = 1.5f,
					bias = -13f
				},
				vegetation = new VegetationConfig
				{
					noiseScale = 250f,
					fractal = new NoiseField.FractalConfig
					{
						Octaves = 4,
						Lacunarity = 1.6f,
						Gain = 0.7f
					},
					cliffDensityThreshold = 1.15f,
					cliffDensityMargin = 0.018f,
					cliffMaxHeight = 4.5f,
					cliffNoiseScale = 25f,
					cliffNoiseThreshold = 0.7f,
					cliffNoiseMargin = 0.2f
				}
			};
			result.worldEdge = new WorldRenderer.WorldEdgeConfig
			{
				width = 20f,
				offworldDepth = -430f
			};
			result.cliffs = new WorldRenderer.CliffConfig
			{
				lowScale = 40f,
				lowP1 = 0.25f,
				lowP2 = 5f,
				highScale = 15f,
				highP1 = 2f,
				highP2 = 1f
			};
			result.idw = new WorldRenderer.IDWConfig
			{
				power = 1.7f,
				maxDistance = 1f,
				maxHops = 2
			};
			result.splats = new SplatConfig
			{
				isEnabled = true,
				smaxBlendRange = 7f,
				sminBlendRange = 2f,
				warpPeriod = 70f,
				warp = new VectorNoiseField.WarpConfig
				{
					frequency = 1f,
					intensity = 0.4f
				},
				plateauNoiseScale = 40f,
				plateauNoiseAmplitude = 25f,
				plateauNoiseFractal = new NoiseField.FractalConfig
				{
					Octaves = 3,
					Lacunarity = 2.5f,
					Gain = 0.6f
				},
				plateauSkirtRange = 35f,
				plateauSkirtMellowness = 35f
			};
			return result;
		}
	}
}
namespace Riverheim.World
{
	public delegate float CoastalProximityMap(Tile<TileFlags> tile);
	[Producer(typeof(CoastalProximityMap))]
	[ConfiguredBy(typeof(CommonConfig))]
	[Consumer(typeof(ITiling<TileFlags>))]
	public class CoastalProximityComponent
	{
		private readonly CommonConfig config;

		private readonly ITiling<TileFlags> flags;

		public CoastalProximityComponent(CommonConfig config, ITiling<TileFlags> flags)
		{
			this.config = config;
			this.flags = flags;
		}

		public CoastalProximityMap Compute()
		{
			ITiling<float> tiling = flags.CreateDistanceField((Tile<TileFlags> tile) => (!tile.Data.IsShore) ? null : new float?(config.TileSpacing / 2f));
			return (Tile<TileFlags> tile) => tile.SisterData(tiling);
		}
	}
	[Serializable]
	public struct CommonConfig
	{
		public float WorldSize;

		public float TileSpacing;

		public float MountainHeight;

		public float OceanDepth;
	}
	public class LandmassInfo
	{
		public int tiles;

		public int border;

		public float area;

		public float coastline;

		public float Compactness => (float)Math.PI * 4f * area / (coastline * coastline);
	}
	public struct LandmassMetrics
	{
		public int count;

		public float totalArea;

		public float maxArea;

		public float avgArea;

		public float avgCompactness;
	}
	public struct RiverMetrics
	{
		public int count;

		public float maxLength;

		public float avgLength;
	}
	public class BiomeMetrics
	{
		public float totalArea;

		public float innerArea;
	}
	public struct WorldMetrics
	{
		public LandmassMetrics landmassMetrics;

		public RiverMetrics riverMetrics;

		public Dictionary<Biome, BiomeMetrics> biomeMetrics;

		public override string ToString()
		{
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.AppendLine("World Metrics:");
			stringBuilder.AppendLine("  Total Land: " + ToPercentage(landmassMetrics.totalArea));
			stringBuilder.AppendLine($"  Landmass Count: {landmassMetrics.count}");
			stringBuilder.AppendLine("  Largest Landmass: " + ToPercentage(landmassMetrics.maxArea));
			stringBuilder.AppendLine("  Average Landmass: " + ToPercentage(landmassMetrics.avgArea));
			stringBuilder.AppendLine($"  Average Compactness: {landmassMetrics.avgCompactness:0.0}");
			stringBuilder.AppendLine();
			stringBuilder.AppendLine($"  Total Rivers: {riverMetrics.count}");
			stringBuilder.AppendLine($"  Longest River: {riverMetrics.maxLength:0.0}m");
			stringBuilder.AppendLine($"  Average River: {riverMetrics.avgLength:0.0}m");
			foreach (Biome key in this.biomeMetrics.Keys)
			{
				stringBuilder.AppendLine();
				stringBuilder.AppendLine($"  {key}:");
				BiomeMetrics biomeMetrics = this.biomeMetrics[key];
				stringBuilder.AppendLine("    Total Area: " + ToPercentage(biomeMetrics.totalArea));
				stringBuilder.AppendLine("    Total Inner Area: " + ToPercentage(biomeMetrics.innerArea));
			}
			return stringBuilder.ToString();
		}

		private static string ToPercentage(float value)
		{
			return $"{value * 100f:0.00}%";
		}
	}
	[Producer(typeof(WorldMetrics))]
	[Consumer(typeof(Landmasses))]
	[Consumer(typeof(List<River>))]
	[Consumer(typeof(ITiling<Biome>))]
	[Consumer(typeof(BiomePostprocessedHeightMap))]
	public class WorldMetricCalculator
	{
		private readonly Landmasses landmasses;

		private readonly List<River> rivers;

		private readonly ITiling<Biome> biomes;

		private readonly BiomePostprocessedHeightMap heights;

		public WorldMetricCalculator(Landmasses landmasses, List<River> rivers, ITiling<Biome> biomes, BiomePostprocessedHeightMap heights)
		{
			this.landmasses = landmasses;
			this.rivers = rivers;
			this.biomes = biomes;
			this.heights = heights;
		}

		public WorldMetrics Compute()
		{
			WorldMetrics result = default(WorldMetrics);
			result.landmassMetrics = ComputeLandmassMetrics();
			result.riverMetrics = ComputeRiverMetrics();
			result.biomeMetrics = ComputeBiomeMetrics();
			return result;
		}

		private List<LandmassInfo> ComputeLandmassInfos()
		{
			Dictionary<short, LandmassInfo> dictionary = new Dictionary<short, LandmassInfo>();
			foreach (Tile<short> tile in landmasses.LandmassIds.Tiles)
			{
				if (tile.Data != -1)
				{
					if (!dictionary.ContainsKey(tile.Data))
					{
						dictionary[tile.Data] = new LandmassInfo();
					}
					dictionary[tile.Data].tiles++;
					dictionary[tile.Data].area += tile.Area;
					if (tile.GetNeighbors().Any((Tile<short> neighbor) => neighbor.Data != tile.Data))
					{
						dictionary[tile.Data].border++;
					}
				}
			}
			foreach (LandmassInfo value in dictionary.Values)
			{
				value.coastline = (float)value.border * landmasses.LandmassIds.Spacing;
			}
			return dictionary.Values.ToList();
		}

		private LandmassMetrics ComputeLandmassMetrics()
		{
			List<LandmassInfo> list = ComputeLandmassInfos();
			LandmassMetrics result = default(LandmassMetrics);
			result.count = list.Count;
			result.totalArea = list.Sum((LandmassInfo x) => x.area) / landmasses.LandmassIds.Area;
			result.maxArea = list.Max((LandmassInfo x) => x.area) / landmasses.LandmassIds.Area;
			result.avgArea = list.Average((LandmassInfo x) => x.area) / landmasses.LandmassIds.Area;
			result.avgCompactness = list.Average((LandmassInfo x) => x.Compactness);
			return result;
		}

		private RiverMetrics ComputeRiverMetrics()
		{
			List<float> source = rivers.Select(RiverLength).ToList();
			RiverMetrics result = default(RiverMetrics);
			result.count = rivers.Count;
			result.maxLength = source.Max();
			result.avgLength = source.Average();
			return result;
		}

		private static float RiverLength(River river)
		{
			return river.vertices.Zip(river.vertices.Skip(1), delegate(RiverVertex a, RiverVertex b)
			{
				//IL_0001: 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_0011: Unknown result type (might be due to invalid IL or missing references)
				Vector2 val = a.pos - b.pos;
				return ((Vector2)(ref val)).magnitude;
			}).Sum();
		}

		private Dictionary<Biome, BiomeMetrics> ComputeBiomeMetrics()
		{
			Dictionary<Biome, BiomeMetrics> dictionary = new Dictionary<Biome, BiomeMetrics>();
			foreach (Tile<Biome> tile in biomes.Tiles)
			{
				if (!dictionary.ContainsKey(tile.Data))
				{
					dictionary[tile.Data] = new BiomeMetrics();
				}
				float num = tile.Area / biomes.Area;
				dictionary[tile.Data].totalArea += num;
				if (tile.GetNeighbors().All((Tile<Biome> neighbor) => neighbor.Data == tile.Data))
				{
					dictionary[tile.Data].innerArea += num;
				}
			}
			return dictionary;
		}
	}
	public enum PolarProximityType
	{
		Any,
		North,
		South
	}
	public delegate float PolarProximityMap(Vector2 pos, PolarProximityType type = PolarProximityType.Any);
	[Serializable]
	public struct PolarBeltConfig
	{
		public float offset;

		public float radius;

		public float width;

		public float noiseScale;

		public float variability;
	}
	[Producer(typeof(PolarProximityMap))]
	[Randomized("PolarProximityMap")]
	[ConfiguredBy(typeof(PolarBeltConfig))]
	public class PolarProximityComponent
	{
		private readonly PolarBeltConfig config;

		private readonly NoiseField noise;

		public PolarProximityComponent(RandomEngine random, PolarBeltConfig config)
		{
			this.config = config;
			noise = random.MetricNoise2D("PolarProximity", config.noiseScale);
		}

		public PolarProximityMap Compute()
		{
			return delegate(Vector2 pos, PolarProximityType type)
			{
				//IL_0000: Unknown result type (might be due to invalid IL or missing references)
				//IL_0006: 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_0042: Unknown result type (might be due to invalid IL or missing references)
				//IL_0047: Unknown result type (might be due to invalid IL or missing references)
				//IL_004c: 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)
				//IL_0067: Unknown result type (might be due to invalid IL or missing references)
				//IL_006c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0071: 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)
				float num = Mathf.Atan2(pos.x, pos.y);
				float num2 = config.radius + Mathf.Sin(num * 20f) * 100f;
				Vector2 val = pos + new Vector2(0f, config.offset);
				float magnitude = ((Vector2)(ref val)).magnitude;
				val = pos - new Vector2(0f, config.offset);
				float magnitude2 = ((Vector2)(ref val)).magnitude;
				float num3 = config.width * (1f + config.variability * noise.Sample(pos));
				return type switch
				{
					PolarProximityType.North => (magnitude - num2) / num3, 
					PolarProximityType.South => (magnitude2 - num2) / num3, 
					PolarProximityType.Any => Mathf.Max(magnitude2 - num2, magnitude - num2) / num3, 
					_ => throw new ArgumentOutOfRangeException(), 
				};
			};
		}
	}
	public readonly struct TileFlags
	{
		public readonly bool IsLand;

		public readonly bool IsCenter;

		public readonly bool IsSouthPolar;

		public readonly bool IsNorthPolar;

		public readonly bool IsShore;

		public bool IsOcean => !IsLand;

		public bool IsPolar
		{
			get
			{
				if (!IsSouthPolar)
				{
					return IsNorthPolar;
				}
				return true;
			}
		}

		public TileFlags(bool isLand, bool isCenter, bool isSouthPolar, bool isNorthPolar, bool isShore)
		{
			IsLand = isLand;
			IsCenter = isCenter;
			IsSouthPolar = isSouthPolar;
			IsNorthPolar = isNorthPolar;
			IsShore = isShore;
		}
	}
	[Producer(typeof(ITiling<TileFlags>))]
	[Consumer(typeof(Landmasses))]
	[Consumer(typeof(PolarProximityMap))]
	public class TileFlagComponent
	{
		private readonly ITiling<short> landmassIds;

		private readonly PolarProximityMap polarProximityMap;

		public TileFlagComponent(Landmasses landmasses, PolarProximityMap polarProximityMap)
		{
			landmassIds = landmasses.LandmassIds;
			this.polarProximityMap = polarProximityMap;
		}

		public ITiling<TileFlags> Compute()
		{
			return landmassIds.CreateSisterTiling(delegate(Tile<short> tile)
			{
				//IL_000e: Unknown result type (might be due to invalid IL or missing references)
				//IL_003a: Unknown result type (might be due to invalid IL or missing references)
				//IL_0054: Unknown result type (might be due to invalid IL or missing references)
				bool isLand = isLandTile(tile);
				Tile<short> value = tile;
				Tile<short>? tile2 = landmassIds.GetTile(Vector2.zero);
				return new TileFlags(isLand, value == tile2, polarProximityMap(tile.Center, PolarProximityType.South) > 0f, polarProximityMap(tile.Center, PolarProximityType.North) > 0f, isShoreTile(tile));
			});
			static bool isLandTile(Tile<short> tile)
			{
				return tile.Data != -1;
			}
			static bool isShoreTile(Tile<short> tile)
			{
				foreach (Tile<short> neighbor in tile.GetNeighbors())
				{
					if (isLandTile(tile) != isLandTile(neighbor))
					{
						return true;
					}
				}
				return false;
			}
		}
	}
	[Producer(typeof(ITiling<byte>[]))]
	[Randomized("Tiling")]
	[ConfiguredBy(typeof(CommonConfig))]
	[ConfiguredBy(typeof(LandmassPainterConfig))]
	public class TilingComponent
	{
		private readonly RandomEngine random;

		private readonly CommonConfig commonConfig;

		private readonly LandmassPainterConfig painterConfig;

		public TilingComponent(RandomEngine random, CommonConfig commonConfig, LandmassPainterConfig painterConfig)
		{
			this.random = random;
			this.commonConfig = commonConfig;
			this.painterConfig = painterConfig;
		}

		public ITiling<byte>[] Compute()
		{
			ITiling<byte>[] array = new ITiling<byte>[painterConfig.layerCount];
			for (int i = 0; i < array.Length; i++)
			{
				array[i] = TilingUtility.CreateVoronoiFromPoissonDisc<byte>(random.CreateEngine("Tiling" + i), commonConfig.WorldSize, commonConfig.TileSpacing * Mathf.Pow(painterConfig.layerScale, (float)i));
			}
			return array;
		}
	}
	public delegate float TravelDistanceMap(Tile<TileFlags> tile);
	[Producer(typeof(TravelDistanceMap))]
	[Consumer(typeof(ITiling<TileFlags>))]
	[Consumer(typeof(RiverState))]
	public class TravelDistanceComponent
	{
		private readonly ITiling<TileFlags> flags;

		private readonly RiverState riverState;

		public TravelDistanceComponent(ITiling<TileFlags> flags, RiverState riverState)
		{
			this.flags = flags;
			this.riverState = riverState;
		}

		public TravelDistanceMap Compute()
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: 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)
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			ITiling<RiverBasinCell> basinTiling = riverState.basinTiling;
			ITiling<float> result = flags.CreateSisterTiling(float.MaxValue);
			Tile<float>? tile2 = result.GetTile(Vector2.zero);
			if (tile2.HasValue)
			{
				Tile<float> valueOrDefault = tile2.GetValueOrDefault();
				valueOrDefault.Data = 0f;
				Queue<Tile<float>> queue = new Queue<Tile<float>>();
				queue.Enqueue(valueOrDefault);
				while (queue.Count > 0)
				{
					Tile<float> tile3 = queue.Dequeue();
					foreach (Tile<float> neighbor in tile3.GetNeighbors())
					{
						Vector2 val = tile3.Center - neighbor.Center;
						float num = ((Vector2)(ref val)).magnitude;
						if (tile3.SisterData(flags).IsLand != neighbor.SisterData(flags).IsLand)
						{
							num *= 5f;
						}
						else if (tile3.SisterData(flags).IsOcean)
						{
							num *= 0.75f;
						}
						else if (tile3.SisterData(basinTiling).HasRiver || neighbor.SisterData(basinTiling).HasRiver)
						{
							num *= 1.5f;
						}
						if (neighbor.Data > tile3.Data + num)
						{
							neighbor.Data = tile3.Data + num;
							queue.Enqueue(neighbor);
						}
					}
				}
				return (Tile<TileFlags> tile) => tile.SisterData(result);
			}
			return (Tile<TileFlags> _) => 0f;
		}
	}
	public struct WorldState
	{
		public ITiling<float> Heightmap;

		public ITiling<Biome> Biomes;

		public List<River> rivers;

		public Plateau[] plateaus;

		public PolarProximityMap polarProximity;
	}
	[Producer(typeof(WorldState))]
	[Consumer(typeof(BiomePostprocessedHeightMap))]
	[Consumer(typeof(ITiling<Biome>))]
	[Consumer(typeof(List<River>))]
	[Consumer(typeof(Plateau[]))]
	[Consumer(typeof(PolarProximityMap))]
	public class WorldStateCompiler
	{
		private readonly ITiling<float> heights;

		private readonly ITiling<Biome> biomes;

		private readonly List<River> rivers;

		private readonly Plateau[] plateaus;

		private readonly PolarProximityMap polarProximity;

		public WorldStateCompiler(BiomePostprocessedHeightMap heights, ITiling<Biome> biomes, List<River> rivers, Plateau[] plateaus, PolarProximityMap polarProximity)
		{
			this.heights = heights.Data;
			this.biomes = biomes;
			this.rivers = rivers;
			this.plateaus = plateaus;
			this.polarProximity = polarProximity;
		}

		public WorldState Compute()
		{
			WorldState result = default(WorldState);
			result.Heightmap = heights;
			result.Biomes = biomes;
			result.rivers = rivers;
			result.plateaus = plateaus;
			result.polarProximity = polarProximity;
			return result;
		}
	}
	public class WorldStateGenerator
	{
		[Serializable]
		public struct Config
		{
			public CommonConfig common;

			public PolarBeltConfig polar;

			public LandmassPainterConfig painter;

			public LandmassRestrictionConfig painterRestrictions;

			public LandmassPostprocessingConfig landmassPostprocessing;

			public PrecipitationConfig precipitation;

			public RiverConfig rivers;

			public RiverCuriosityConfig riverCuriosities;

			public CoastalProximityHeightComponent.Config coastalProximityHeight;

			public HeightClampingComponent.Config heightClamping;

			public FlatlandsComponent.Config heightFlatlands;

			public LakeComponent.Config lakes;

			public RiverValleyComponent.Config riverValleys;

			public HeightConfig height;

			public BiomeCalculationConfig biomes;

			public BiomePostprocessingConfig biomePostprocessing;

			public PlateauConfig plateaus;
		}

		private readonly GeneratorPipeline pipeline = new GeneratorPipeline(typeof(WorldState), typeof(WorldMetrics));

		public bool Verbose
		{
			get
			{
				return pipeline.Verbose;
			}
			set
			{
				pipeline.Verbose = value;
			}
		}

		public WorldState Generate(int seed, Config config)
		{
			pipeline.Compute(seed, config);
			return pipeline.GetResult<WorldState>();
		}

		public T GetResult<T>()
		{
			return pipeline.GetResult<T>();
		}
	}
}
namespace Riverheim.World.Rivers
{
	public delegate float BasinBoundaryProximityMap(Tile<TileFlags> tile);
	[Producer(typeof(BasinBoundaryProximityMap))]
	[Consumer(typeof(ITiling<TileFlags>))]
	[Consumer(typeof(RiverState))]
	public class BasinBoundaryProximityComponent
	{
		private readonly ITiling<TileFlags> flags;

		private readonly RiverState riverState;

		public BasinBoundaryProximityComponent(ITiling<TileFlags> flags, RiverState riverState)
		{
			this.flags = flags;
			this.riverState = riverState;
		}

		public BasinBoundaryProximityMap Compute()
		{
			ITiling<float> tiling = flags.CreateDistanceField(delegate(Tile<TileFlags> tile)
			{
				int basinId = tile.SisterData(riverState.basinTiling).basinId;
				if (basinId == -1)
				{
					return null;
				}
				foreach (Tile<TileFlags> neighbor in tile.GetNeighbors())
				{
					int basinId2 = neighbor.SisterData(riverState.basinTiling).basinId;
					if (basinId2 != -1 && basinId2 != basinId)
					{
						return flags.Spacing / 2f;
					}
				}
				return null;
			}, (Tile<TileFlags> tile) => tile.Data.IsLand);
			return (Tile<TileFlags> tile) => tile.SisterData(tiling);
		}
	}
	public delegate float PrecipitationMap(Vector2 pos);
	[Serializable]
	public struct PrecipitationConfig
	{
		public float NoiseScale;

		public float Variability;

		public float SpawnMinRadius;

		public float SpawnMaxRadius;

		public float BasinContribution;
	}
	[Producer(typeof(PrecipitationMap))]
	[Randomized("PrecipitationMap")]
	[ConfiguredBy(typeof(PrecipitationConfig))]
	[Consumer(typeof(Landmasses))]
	public class PrecipitationComponent
	{
		private readonly RandomEngine random;

		private readonly PrecipitationConfig config;

		private readonly Landmasses landmasses;

		public PrecipitationComponent(RandomEngine random, PrecipitationConfig config, Landmasses landmasses)
		{
			this.random = random;
			this.config = config;
			this.landmasses = landmasses;
		}

		public PrecipitationMap Compute()
		{
			NoiseField noise = random.MetricNoise2D("Precipitation", config.NoiseScale);
			return delegate(Vector2 pos)
			{
				//IL_0016: Unknown result type (might be due to invalid IL or missing references)
				//IL_0073: Unknown result type (might be due to invalid IL or missing references)
				float num = Mathf.Clamp(config.Variability * noise.Sample(pos), Mathf.Lerp(1f, -1f, Mathf.InverseLerp(config.SpawnMinRadius, config.SpawnMaxRadius, ((Vector2)(ref pos)).magnitude)), 1f);
				Tile<LandmassArtifacts>? tile = landmasses.Artifacts.GetTile(pos);
				if (tile.HasValue && tile.GetValueOrDefault().Data.IsBasin)
				{
					num += config.BasinContribution;
				}
				return 1f + num;
			};
		}
	}
	public delegate float RiverCuriosityScore(Tile<TileFlags> tile);
	[Serializable]
	public struct RiverCuriosityConfig
	{
		public float sourceMult;

		public float sourceMinLength;

		public float sourceMaxLength;

		public float proximityMult;

		public float proximityScanRange;

		public float proximityDifferentBasinsMultiplier;

		public float proximityMinRatio;

		public float proximityMaxRatio;

		public float angleMult;

		public float angleMinDegrees;

		public float angleMaxDegrees;

		public float angleNormWidth;

		public float smoothingRange;
	}
	[Producer(typeof(RiverCuriosityScore))]
	[ConfiguredBy(typeof(CommonConfig))]
	[ConfiguredBy(typeof(RiverCuriosityConfig))]
	[Consumer(typeof(RiverState))]
	public class RiverCuriosityComponent
	{
		private class TileData
		{
			public readonly Dictionary<int, float> lengthsById;

			public float score;

			public float Length
			{
				get
				{
					float num = 0f;
					foreach (float value in lengthsById.Values)
					{
						num += value;
					}
					return num;
				}
			}

			public TileData(Dictionary<int, float> lengths)
			{
				lengthsById = ((lengths == null) ? new Dictionary<int, float>() : new Dictionary<int, float>(lengths));
				score = 0f;
			}
		}

		private readonly CommonConfig commonConfig;

		private readonly RiverCuriosityConfig config;

		private readonly RiverState riverState;

		private readonly ITiling<TileData> data;

		public RiverCuriosityComponent(CommonConfig commonConfig, RiverCuriosityConfig config, RiverState riverState)
		{
			this.commonConfig = commonConfig;
			this.config = config;
			this.riverState = riverState;
			data = riverState.riverTiling.CreateSisterTiling<TileData>();
		}

		public RiverCuriosityScore Compute()
		{
			ITiling<float> result = data.CreateSisterTiling(0f);
			List<Tile<RiverCell>> list = FindMouths();
			foreach (Tile<RiverCell> item in list)
			{
				MarkLengths(item);
			}
			foreach (Tile<RiverCell> item2 in list)
			{
				MarkScores(item2);
			}
			foreach (Tile<RiverCell> item3 in list)
			{
				SmoothScores(item3, result);
			}
			return (Tile<TileFlags> tile) => tile.SisterData(result);
		}

		private List<Tile<RiverCell>> FindMouths()
		{
			List<Tile<RiverCell>> list = new List<Tile<RiverCell>>();
			foreach (Tile<RiverCell> tile in riverState.riverTiling.Tiles)
			{
				if (tile.Data != null && tile.Data.IsRiverMouth)
				{
					list.Add(tile);
				}
			}
			return list;
		}

		private void MarkLengths(Tile<RiverCell> tile, Dictionary<int, float> parentLengths = null, float segmentLength = 0f)
		{
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			tile.SisterData(data) = new TileData(parentLengths);
			Dictionary<int, float> lengthsById = tile.SisterData(data).lengthsById;
			int id = tile.Data.Id;
			if (!lengthsById.ContainsKey(id))
			{
				lengthsById[id] = segmentLength;
			}
			else
			{
				lengthsById[id] += segmentLength;
			}
			foreach (Tile<RiverCell> inlet in tile.Data.Inlets)
			{
				Tile<RiverCell> tile2 = inlet;
				Vector2 val = tile.Center - inlet.Center;
				MarkLengths(tile2, lengthsById, ((Vector2)(ref val)).magnitude);
			}
		}

		private void MarkScores(Tile<RiverCell> tile)
		{
			ref float score = ref tile.SisterData(data).score;
			score += config.sourceMult * ComputeSourceScore(data.GetTile(tile.Id));
			score += config.proximityMult * ComputeProximityScore(data.GetTile(tile.Id));
			score += config.angleMult * ComputeAngleScore(tile);
			foreach (Tile<RiverCell> inlet in tile.Data.Inlets)
			{
				MarkScores(inlet);
			}
		}

		private float ComputeSourceScore(Tile<TileData> tile)
		{
			if (!tile.SisterData(riverState.riverTiling).IsTermination)
			{
				return 0f;
			}
			return Mathf.InverseLerp(config.sourceMinLength, config.sourceMaxLength, tile.Data.Length);
		}

		private float ComputeProximityScore(Tile<TileData> tile)
		{
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			float num = 0f;
			foreach (Tile<TileData> item in tile.Scan(config.proximityScanRange))
			{
				if (item.Data != null)
				{
					Vector2 val = tile.Center - item.Center;
					float magnitude = ((Vector2)(ref val)).magnitude;
					float num2 = GraphDistance(tile, item);
					float num3 = ((tile.SisterData(riverState.basinTiling).basinId != item.SisterData(riverState.basinTiling).basinId) ? config.proximityDifferentBasinsMultiplier : 1f);
					float num4 = Mathf.InverseLerp(config.proximityMinRatio, config.proximityMaxRatio, num2 / magnitude * num3);
					num += num4 * Gauss(magnitude / config.proximityScanRange);
				}
			}
			float num5 = commonConfig.TileSpacing / config.proximityScanRange;
			return num * num5 * num5;
		}

		private float ComputeAngleScore(Tile<RiverCell> tile)
		{
			float num = 0f;
			Direction direction = tile.DirectionTo(tile.Data.Outlet);
			foreach (Tile<RiverCell> inlet in tile.Data.Inlets)
			{
				float num2 = Mathf.Abs(tile.DirectionTo(inlet) - direction);
				float num3 = 1f - Mathf.InverseLerp(config.angleMinDegrees, config.angleMaxDegrees, num2 * 57.29578f);
				num += num3 * tile.Data.Width / config.angleNormWidth;
			}
			return num;
		}

		private void SmoothScores(Tile<RiverCell> tile, ITiling<float> result)
		{
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			float smoothingRange = config.smoothingRange;
			float score = tile.SisterData(data).score;
			if (score > 0f)
			{
				tile.SisterData(result) += score;
				foreach (Tile<RiverCell> item in tile.Scan(smoothingRange))
				{
					Vector2 val = (tile.Center - item.Center) / smoothingRange;
					item.SisterData(result) += score * Gauss2(((Vector2)(ref val)).SqrMagnitude());
				}
			}
			foreach (Tile<RiverCell> inlet in tile.Data.Inlets)
			{
				SmoothScores(inlet, result);
			}
		}

		private static float Gauss(float x)
		{
			return Gauss2(x * x);
		}

		private static float Gauss2(float x2)
		{
			return Mathf.Exp(-4.5f * x2);
		}

		private static float GraphDistance(Tile<TileData> from, Tile<TileData> to)
		{
			Dictionary<int, float> dictionary = new Dictionary<int, float>(from.Data.lengthsById);
			foreach (KeyValuePair<int, float> item in to.Data.lengthsById)
			{
				if (!dictionary.ContainsKey(item.Key))
				{
					dictionary[item.Key] = 0f - item.Value;
				}
				else
				{
					dictionary[item.Key] -= item.Value;
				}
			}
			float num = 0f;
			foreach (float value in dictionary.Values)
			{
				num += Mathf.Abs(value);
			}
			return num;
		}
	}
	public class RiverCell
	{
		public Tile<RiverCell> Outlet;

		public List<Tile<RiverCell>> Inlets;

		public int Id;

		public float Catchment;

		public float Width;

		public int StrahlerNumber;

		public bool IsRiverMouth => Outlet.Data == null;

		public bool IsFork => Inlets.Count > 1;

		public bool IsTermination => Inlets.Count == 0;
	}
	[Serializable]
	public struct RiverConfig
	{
		[Range(0f, 1f)]
		public float startingDensity;

		[Range(0f, 1f)]
		public float startingVariability;

		[Range(0f, 1f)]
		public float weightRecovery;

		public int minRiverMouthLandNeighbors;

		public float minRiverMouthPointerMagnitude;

		public RiverInletConfig inlet;

		public RiverPruneConfig prune;

		public RiverWidthConfig width;
	}
	[Serializable]
	public struct RiverInletConfig
	{
		[Range(0f, (float)Math.PI)]
		public float GoodBendAngle;

		[Range(0f, (float)Math.PI)]
		public float BadBendAngle;

		[Range(0f, 1f)]
		public float MinBendScore;

		[Range(0f, (float)Math.PI)]
		public float OptimalForkAngle;

		[Range(0f, (float)Math.PI)]
		public float OptimalForkAngleDiff;

		[Range(0f, (float)Math.PI)]
		public float WorstForkAngleDiff;

		[Range(0f, 1f)]
		public float MinForkScore;

		public float flowthroughScoreMult;

		public float forkScoreMult;
	}
	[Serializable]
	public struct RiverPruneConfig
	{
		public int minStrahler;

		public float minWidth;

		public float maxCatchmentDiff;
	}
	[Serializable]
	public struct RiverWidthConfig
	{
		public float scale;

		public float power;

		public float offset;
	}
	[Producer(typeof(RiverState))]
	[Randomized("Rivers")]
	[ConfiguredBy(typeof(RiverConfig))]
	[Consumer(typeof(ITiling<TileFlags>))]
	[Consumer(typeof(Landmasses))]
	[Consumer(typeof(PrecipitationMap))]
	public class RiverFill
	{
		private struct FillTile : WeightedRand.IItem
		{
			public Tile<RiverCell> Tile;

			public uint Weight { get; set; }
		}

		private struct InletConfiguration : WeightedRand.IItem
		{
			public List<Direction> Directions;

			public uint Weight { get; set; }
		}

		private readonly RandomEngine random;

		private readonly ITiling<TileFlags> Input;

		private readonly ITiling<short> LandmassIds;

		private readonly PrecipitationMap Precipitation;

		private readonly ITiling<RiverCell> Rivers;

		private readonly ITiling<RiverBasinCell> Basins;

		private readonly RiverConfig Config;

		private int MaxRiverId;

		public RiverFill(RandomEngine randomEngine, RiverConfig config, ITiling<TileFlags> flags, Landmasses landmasses, PrecipitationMap precipitation)
		{
			random = randomEngine;
			Config = config;
			Input = flags;
			LandmassIds = landmasses.LandmassIds;
			Precipitation = precipitation;
			Rivers = flags.CreateSisterTiling((Func<Tile<TileFlags>, RiverCell>)((Tile<TileFlags> _) => null));
			Basins = flags.CreateSisterTiling(delegate
			{
				RiverBasinCell result = default(RiverBasinCell);
				result.basinId = -1;
				result.Catchment = 0f;
				return result;
			});
		}

		private FillTile MakeFillTile(Tile<RiverCell> tile, float weight)
		{
			FillTile result = default(FillTile);
			result.Tile = tile;
			result.Weight = (uint)Mathf.Clamp(Mathf.RoundToInt(1000f * weight), 1, 1000);
			return result;
		}

		private FillTile MakeFillTile(Tile<RiverCell> tile)
		{
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			return MakeFillTile(tile, (float)random.Range(Math.Max(0f, 1f - Config.startingVariability), 1.0) * Precipitation(tile.Center));
		}

		private FillTile MakeFillTile(Tile<RiverCell> tile, uint prevWeight)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			float num = Precipitation(tile.Center);
			float num2 = (float)prevWeight / 1000f;
			if (num2 > num)
			{
				num2 = num;
			}
			if (num2 < num)
			{
				num2 += (num - num2) * Config.weightRecovery;
			}
			return MakeFillTile(tile, num2);
		}

		private void AddInlet(Tile<RiverCell> to, Tile<RiverCell> from)
		{
			to.Data.Inlets.Add(from);
			from.Data = new RiverCell
			{
				Outlet = to,
				Inlets = new List<Tile<RiverCell>>(),
				Catchment = 0f,
				Width = 0f
			};
			Tile<RiverBasinCell> tile = Basins.GetTile(from.Id);
			ref RiverBasinCell data = ref tile.Data;
			tile = Basins.GetTile(to.Id);
			data.basinId = tile.Data.basinId;
		}

		private List<InletConfiguration> GetInletConfigurations(List<Direction> validInlets, Direction outletDirection)
		{
			List<InletConfiguration> list = new List<InletConfiguration> { inletConfiguration(new List<Direction>()) };
			for (int i = 0; i < validInlets.Count; i++)
			{
				list.Add(inletConfiguration(new List<Direction> { validInlets[i] }));
				for (int j = i + 1; j < validInlets.Count; j++)
				{
					list.Add(inletConfiguration(new List<Direction>
					{
						validInlets[i],
						validInlets[j]
					}));
				}
			}
			List<InletConfiguration> list2 = new List<InletConfiguration>();
			foreach (InletConfiguration item in list)
			{
				if (item.Weight != 0)
				{
					list2.Add(item);
				}
			}
			return list2;
			static uint configurationWeight(float score)
			{
				return (uint)Mathf.Max(0, Mathf.RoundToInt(score * 100f));
			}
			InletConfiguration inletConfiguration(List<Direction> directions)
			{
				InletConfiguration result = default(InletConfiguration);
				result.Directions = directions;
				result.Weight = configurationWeight(InletConfigurationScore(directions, outletDirection));
				return result;
			}
		}

		private float BendScore(Direction bent, Direction straight)
		{
			float num = Mathf.Abs(straight - bent);
			return Mathf.Lerp(1f, Config.inlet.MinBendScore, Mathf.InverseLerp(Config.inlet.GoodBendAngle, Config.inlet.BadBendAngle, num));
		}

		private float ForkScore(Direction lhs, Direction rhs, Direction straight)
		{
			float num = Mathf.Abs(lhs - rhs);
			float num2 = Mathf.Lerp(1f, Config.inlet.MinForkScore, Mathf.InverseLerp(Config.inlet.OptimalForkAngleDiff, Config.inlet.WorstForkAngleDiff, Mathf.Abs(num - Config.inlet.OptimalForkAngle)));
			float num3 = BendScore(Direction.Average(lhs, rhs), straight);
			return num2 * num3;
		}

		private float InletConfigurationScore(List<Direction> configuration, Direction outletDirection)
		{
			return configuration.Count switch
			{
				0 => 1f, 
				1 => Config.inlet.flowthroughScoreMult * BendScore(configuration[0], ~outletDirection), 
				2 => Config.inlet.forkScoreMult * ForkScore(configuration[0], configuration[1], ~outletDirection), 
				_ => 0f, 
			};
		}

		public RiverState Compute()
		{
			return Compute(prune: true);
		}

		public RiverState Compute(bool prune)
		{
			List<Tile<RiverCell>> list = InitRivers(Config.startingDensity);
			if (list.Count == 0)
			{
				Logger.LogWarning("Failed to produce any river mouths!");
			}
			Dictionary<short, List<Tile<RiverCell>>> dictionary = new Dictionary<short, List<Tile<RiverCell>>>();
			foreach (Tile<RiverCell> item in list)
			{
				short data = LandmassIds.GetTile(item.Id).Data;
				if (!dictionary.ContainsKey(data))
				{
					dictionary[data] = new List<Tile<RiverCell>>();
				}
				dictionary[data].Add(item);
			}
			foreach (List<Tile<RiverCell>> value in dictionary.Values)
			{
				WeightedRandomSet<FillTile> weightedRandomSet = new WeightedRandomSet<FillTile>(random);
				foreach (Tile<RiverCell> item2 in value)
				{
					weightedRandomSet.Add(MakeFillTile(item2));
				}
				while (weightedRandomSet.Count > 0)
				{
					FillTile fillTile = weightedRandomSet.Pop();
					Tile<RiverCell> tile = fillTile.Tile;
					Dictionary<Direction, Tile<RiverCell>> dictionary2 = new Dictionary<Direction, Tile<RiverCell>>();
					foreach (Tile<RiverCell> neighbor in tile.GetNeighbors())
					{
						if (!(neighbor == tile.Data.Outlet) && Input.GetTile(neighbor.Id).Data.IsSuitableLand() && neighbor.Data == null)
						{
							dictionary2[tile.DirectionTo(neighbor)] = neighbor;
						}
					}
					if (dictionary2.Count == 0)
					{
						continue;
					}
					List<InletConfiguration> inletConfigurations = GetInletConfigurations(new List<Direction>(dictionary2.Keys), tile.DirectionTo(tile.Data.Outlet));
					foreach (Direction direction in WeightedRand.Sample(random, inletConfigurations).Directions)
					{
						Tile<RiverCell> tile2 = dictionary2[direction];
						AddInlet(tile, tile2);
						weightedRandomSet.Add(MakeFillTile(tile2, fillTile.Weight));
					}
				}
			}
			foreach (Tile<RiverCell> item3 in list)
			{
				MarkWeights(item3);
				if (prune)
				{
					Prune(item3, Config.prune);
				}
				if (item3.Data != null)
				{
					MarkRiverIds(item3);
				}
			}
			foreach (Tile<RiverBasinCell> tile3 in Basins.Tiles)
			{
				tile3.Data.HasRiver = tile3.SisterData(Rivers) != null;
			}
			foreach (Tile<RiverCell> item4 in list)
			{
				if (item4.Data != null)
				{
					item4.SisterData(Basins).HasRiverMouth = true;
					item4.Data.Outlet.SisterData(Basins).HasRiverMouth = true;
				}
			}
			RiverState result = default(RiverState);
			result.riverTiling = Rivers;
			result.basinTiling = Basins;
			return result;
		}

		private void Prune(Tile<RiverCell> start, RiverPruneConfig config)
		{
			Queue<Tile<RiverCell>> queue = new Queue<Tile<RiverCell>>();
			queue.Enqueue(start);
			while (queue.Count > 0)
			{
				Tile<RiverCell> tile = queue.Dequeue();
				if (tile.Data.StrahlerNumber < config.minStrahler)
				{
					DeleteRiver(tile);
					continue;
				}
				if (config.minWidth > 0f && tile.Data.Width < config.minWidth)
				{
					DeleteRiver(tile);
					continue;
				}
				List<Tile<RiverCell>> list = new List<Tile<RiverCell>>(tile.Data.Inlets);
				if (list.Count == 0)
				{
					continue;
				}
				float num = 0f;
				foreach (Tile<RiverCell> item in list)
				{
					if (item.Data.Catchment > num)
					{
						num = item.Data.Catchment;
					}
				}
				foreach (Tile<RiverCell> item2 in list)
				{
					if (item2.Data.Catchment > 0f && num / item2.Data.Catchment > config.maxCatchmentDiff)
					{
						DeleteRiver(item2);
					}
					else
					{
						queue.Enqueue(item2);
					}
				}
			}
		}

		private void DeleteRiver(Tile<RiverCell> tile)
		{
			tile.Data.Outlet.Data?.Inlets.Remove(tile);
			Tile<RiverCell>[] array = tile.Data.Inlets.ToArray();
			foreach (Tile<RiverCell> tile2 in array)
			{
				DeleteRiver(tile2);
			}
			tile.Data = null;
		}

		private int ComputeStrahlerNumber(List<int> upstreamNumbers)
		{
			if (upstreamNumbers.Count == 0)
			{
				return 1;
			}
			if (upstreamNumbers.Count == 1)
			{
				return upstreamNumbers[0];
			}
			upstreamNumbers.Sort();
			upstreamNumbers.Reverse();
			if (upstreamNumbers[0] == upstreamNumbers[1])
			{
				return upstreamNumbers[0] + 1;
			}
			return upstreamNumbers[0];
		}

		private void MarkWeights(Tile<RiverCell> tile)
		{
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			List<int> list = new List<int>();
			float num = 0f;
			for (int i = 0; i < tile.Data.Inlets.Count; i++)
			{
				Tile<RiverCell> tile2 = tile.Data.Inlets[i];
				MarkWeights(tile2);
				list.Add(tile2.Data.StrahlerNumber);
				num += tile2.Data.Catchment;
			}
			tile.Data.StrahlerNumber = ComputeStrahlerNumber(list);
			tile.Data.Catchment = num + Precipitation(tile.Center) * tile.Area;
			tile.Data.Width = RiverWidth(tile.Data.Catchment);
			tile.SisterData(Basins).Catchment = tile.Data.Catchment;
			tile.SisterData(Basins).FlowDirection = tile.DirectionTo(tile.Data.Outlet);
		}

		private void MarkRiverIds(Tile<RiverCell> tile)
		{
			if (tile.Data.IsTermination)
			{
				tile.Data.Id = MaxRiverId++;
				return;
			}
			float num = float.MinValue;
			RiverCell riverCell = null;
			foreach (Tile<RiverCell> inlet in tile.Data.Inlets)
			{
				MarkRiverIds(inlet);
				if (inlet.Data.Catchment > num)
				{
					riverCell = inlet.Data;
				}
			}
			tile.Data.Id = riverCell.Id;
		}

		private List<Tile<RiverCell>> InitRivers(float startingDensity)
		{
			//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0103: Unknown result type (might be due to invalid IL or missing references)
			//IL_012a: 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_0135: Unknown result type (might be due to invalid IL or missing references)
			//IL_013a: Unknown result type (might be due to invalid IL or missing references)
			//IL_013f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0143: Unknown result type (might be due to invalid IL or missing references)
			//IL_0148: Unknown result type (might be due to invalid IL or missing references)
			//IL_014d: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b2: Unknown result type (might be due to invalid IL or missing references)
			RandomSet<Tile<TileFlags>> randomSet = new RandomSet<Tile<TileFlags>>(random);
			foreach (Tile<TileFlags> tile3 in Input.Tiles)
			{
				if (tile3.Data.IsSuitableShore())
				{
					randomSet.Add(tile3);
				}
			}
			List<Tile<RiverCell>> list = new List<Tile<RiverCell>>();
			int num = Mathf.RoundToInt(startingDensity * (float)randomSet.Count);
			while (list.Count < num)
			{
				if (randomSet.Count == 0)
				{
					Logger.LogError($"Not enough shore to place {num} riverMouths, stopped abruptly at {list.Count}!");
					break;
				}
				Tile<TileFlags> tile = randomSet.Pop();
				int num2 = 0;
				foreach (Tile<TileFlags> neighbor in tile.GetNeighbors())
				{
					if (neighbor.Data.IsSuitableLand())
					{
						num2++;
					}
				}
				if (num2 < Config.minRiverMouthLandNeighbors)
				{
					continue;
				}
				Vector2 val = Vector2.zero;
				foreach (Tile<TileFlags> neighbor2 in tile.GetNeighbors())
				{
					if (neighbor2.Data.IsOcean)
					{
						Vector2 val2 = val;
						Vector2 val3 = neighbor2.Center - tile.Center;
						val = val2 + ((Vector2)(ref val3)).normalized;
					}
				}
				if (!(((Vector2)(ref val)).magnitude < Config.minRiverMouthPointerMagnitude))
				{
					tile.SisterData(Basins).basinId = list.Count;
					Tile<RiverCell> tile2 = Rivers.GetTile(tile.Id);
					tile2.Data = new RiverCell
					{
						Outlet = tile2.GetNeighbor(new Direction(val)),
						Inlets = new List<Tile<RiverCell>>(),
						Catchment = 0f,
						Width = 0f
					};
					list.Add(tile2);
				}
			}
			return list;
		}

		private float RiverWidth(float catchment)
		{
			float num = catchment * 7.293252E-08f;
			return Config.width.scale * Mathf.Pow(num, Config.width.power) + Config.width.offset;
		}
	}
	public delegate float RiverProximityMap(Tile<TileFlags> tile);
	[Producer(typeof(RiverProximityMap))]
	[Consumer(typeof(RiverState))]
	public class RiverProximityComponent
	{
		private readonly RiverState riverState;

		public RiverProximityComponent(RiverState riverState)
		{
			this.riverState = riverState;
		}

		public RiverProximityMap Compute()
		{
			ITiling<float> result = riverState.basinTiling.CreateDistanceField((Tile<RiverBasinCell> tile) => (!tile.Data.HasRiver) ? null : new float?(0f));
			return (Tile<TileFlags> tile) => tile.SisterData(result);
		}
	}
	public struct RiverState
	{
		public ITiling<RiverCell> riverTiling;

		public ITiling<RiverBasinCell> basinTiling;
	}
	public struct RiverBasinCell
	{
		public const int NO_BASIN_ID = -1;

		public const float AVG_ANNUAL_DISCHARGE_CM = 230f;

		public const float SECONDS_IN_YEAR = 31536000f;

		public const float AVG_DISCHARGE_FLOW = 7.293252E-08f;

		public int basinId;

		public bool HasRiver;

		public bool HasRiverMouth;

		public Direction FlowDirection;

		public float Catchment;

		public readonly float Discharge => Catchment * 7.293252E-08f;
	}
	public struct RiverVertex
	{
		public Vector2 pos;

		public RiverVertexData data;
	}
	public struct RiverVertexData
	{
		public float meanderiness;

		public float depth;

		public float width;
	}
	public struct River
	{
		public int id;

		public List<RiverVertex> vertices;
	}
	[Producer(typeof(List<River>))]
	[Consumer(typeof(RiverState))]
	public class RiverVerticesCalculator
	{
		private readonly ITiling<RiverCell> rivers;

		public RiverVerticesCalculator(RiverState riverState)
		{
			rivers = riverState.riverTiling;
		}

		public List<River> Compute()
		{
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fa: Unknown result type (might be due to invalid IL or missing references)
			Dictionary<int, List<RiverVertex>> dictionary = new Dictionary<int, List<RiverVertex>>();
			Stack<Tile<RiverCell>> stack = new Stack<Tile<RiverCell>>();
			foreach (Tile<RiverCell> tile2 in rivers.Tiles)
			{
				if (tile2.Data != null && tile2.Data.IsRiverMouth)
				{
					stack.Push(tile2);
					dictionary.Add(tile2.Data.Id, new List<RiverVertex>
					{
						new RiverVertex
						{
							pos = tile2.Data.Outlet.Center,
							data = new RiverVertexData
							{
								meanderiness = 0f,
								depth = 1f,
								width = tile2.Data.Width
							}
						}
					});
				}
			}
			while (stack.Count > 0)
			{
				Tile<RiverCell> tile = stack.Pop();
				HashSet<int> hashSet = new HashSet<int> { tile.Data.Id };
				foreach (Tile<RiverCell> inlet in tile.Data.Inlets)
				{
					hashSet.Add(inlet.Data.Id);
				}
				foreach (int id in hashSet)
				{
					float width = tile.Data.Width;
					if (!dictionary.ContainsKey(id))
					{
						dictionary[id] = new List<RiverVertex>();
						width = tile.Data.Inlets.Find((Tile<RiverCell> inlet) => inlet.Data.Id == id).Data.Width;
					}
					dictionary[id].Add(new RiverVertex
					{
						pos = tile.Center,
						data = new RiverVertexData
						{
							meanderiness = ((!tile.Data.IsFork) ? 1 : 0),
							depth = ((!tile.Data.IsTermination) ? 1 : 0),
							width = width
						}
					});
				}
				foreach (Tile<RiverCell> inlet2 in tile.Data.Inlets)
				{
					stack.Push(inlet2);
				}
			}
			List<River> list = new List<River>();
			foreach (KeyValuePair<int, List<RiverVertex>> item in dictionary)
			{
				list.Add(new River
				{
					id = item.Key,
					vertices = item.Value
				});
			}
			return list;
		}
	}
}
namespace Riverheim.World.Rivers.Internal
{
	internal static class RiverFillExtensions
	{
		public static bool IsSuitableForRiver(this TileFlags flags)
		{
			if (!flags.IsCenter)
			{
				return !flags.IsPolar;
			}
			return false;
		}

		public static bool IsSuitableLand(this TileFlags flags)
		{
			if (flags.IsLand && !flags.IsShore)
			{
				return flags.IsSuitableForRiver();
			}
			return false;
		}

		public static bool IsSuitableShore(this TileFlags flags)
		{
			if (flags.IsLand && flags.IsShore)
			{
				return flags.IsSuitableForRiver();
			}
			return false;
		}
	}
}
namespace Riverheim.World.Landmass
{
	public struct LandmassArtifacts
	{
		public bool IsBasin;

		public bool IsFault;
	}
	[Serializable]
	public struct LandmassLayerConfig
	{
		public float budget;

		public float greediness;

		public float variance;
	}
	[Serializable]
	public struct LandmassPainterConfig
	{
		public int layerCount;

		public float layerScale;

		public VectorNoiseField.WarpConfig layerWarp;

		public StaticArray<LandmassLayerConfig> layers;
	}
	[Producer(typeof(ITiling<short>[]))]
	[Randomized("LandmassPainter")]
	[ConfiguredBy(typeof(CommonConfig))]
	[ConfiguredBy(typeof(LandmassPainterConfig))]
	[Consumer(typeof(ITiling<byte>[]))]
	[Consumer(typeof(LandmassRestrictions))]
	public class LandmassPainter
	{
		private struct WeightedTile : WeightedRand.IItem
		{
			public Tile<short> tile;

			public float weight;

			public readonly uint Weight => (uint)Mathf.CeilToInt(weight * 1000f);
		}

		private const short NO_LANDMASS_ID = -1;

		private readonly RandomEngine random;

		private readonly CommonConfig commonConfig;

		private readonly LandmassPainterConfig config;

		private readonly ITiling<byte>[] tilings;

		private readonly LandmassRestrictions restrictions;

		private short currentId;

		public LandmassPainter(RandomEngine random, CommonConfig commonConfig, LandmassPainterConfig config, ITiling<byte>[] tilings, LandmassRestrictions restrictions)
		{
			this.random = random;
			this.commonConfig = commonConfig;
			this.config = config;
			this.tilings = tilings;
			this.restrictions = restrictions;
		}

		public ITiling<short>[] Compute()
		{
			//IL_0108: Unknown result type (might be due to invalid IL or missing references)
			ITiling<short>[] array = new ITiling<short>[tilings.Length];
			for (int i = 0; i < array.Length; i++)
			{
				array[i] = tilings[i].CreateSisterTiling((short)(-1));
			}
			float num = commonConfig.WorldSize * commonConfig.WorldSize * (float)Math.PI;
			float num2 = 0f;
			for (int num3 = array.Length - 1; num3 >= 0; num3--)
			{
				float tileScale = array[num3].Spacing / commonConfig.TileSpacing;
				float area = 0f;
				if (num3 < array.Length - 1)
				{
					InheritLayer(array[num3], array[num3 + 1], tileScale, out area);
				}
				num2 += config.layers[num3].budget;
				PaintLayer(CalcAvailableTiles(array[num3], tileScale), num * num2 - area, config.layers[num3].greediness, config.layers[num3].variance);
				Tile<short>? tile = array[num3].GetTile(Vector2.zero);
				if (tile.HasValue)
				{
					Tile<short> valueOrDefault = tile.GetValueOrDefault();
					if (valueOrDefault.Data == -1)
					{
						foreach (Tile<short> neighbor in valueOrDefault.GetNeighbors())
						{
							if (neighbor.Data != -1)
							{
								valueOrDefault.Data = neighbor.Data;
							}
						}
						if (valueOrDefault.Data == -1)
						{
							valueOrDefault.Data = currentId++;
						}
					}
				}
			}
			return array;
		}

		private RandomSet<Tile<short>> CalcAvailableTiles(ITiling<short> tiling, float tileScale)
		{
			RandomSet<Tile<short>> randomSet = new RandomSet<Tile<short>>(random, tiling.Tiles);
			foreach (Tile<short> tile in tiling.Tiles)
			{
				if (!restrictions.IsTileValidForLand(tile, tileScale))
				{
					randomSet.Remove(tile);
				}
				if (tile.Data == -1)
				{
					continue;
				}
				randomSet.Remove(tile);
				foreach (Tile<short> neighbor in tile.GetNeighbors())
				{
					randomSet.Remove(neighbor);
				}
			}
			return randomSet;
		}

		private void InheritLayer(ITiling<short> to, ITiling<short> from, float tileScale, out float area)
		{
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			area = 0f;
			VectorNoiseField vectorNoiseField = random.WarpNoise("LandmassLayerWarp", to.Spacing, config.layerWarp);
			foreach (Tile<short> tile2 in to.Tiles)
			{
				if (restrictions.IsTileValidForLand(tile2, tileScale))
				{
					Tile<short>? tile = from.GetTile(tile2.Center + vectorNoiseField.Sample(tile2.Center));
					if (tile.HasValue)
					{
						Tile<short> valueOrDefault = tile.GetValueOrDefault();
						tile2.Data = valueOrDefault.Data;
					}
					if (tile2.Data != -1)
					{
						area += tile2.Area;
					}
				}
			}
		}

		private void PaintLayer(RandomSet<Tile<short>> available, float totalBudget, float greediness, float variance)
		{
			while (totalBudget > 0f && available.Count > 0)
			{
				float num = totalBudget * greediness * (1f + (float)random.Range(-1, 1) * variance);
				if (num <= 0f)
				{
					break;
				}
				foreach (Tile<short> item in PaintLandmass(available.Sample(), num, available))
				{
					item.Data = currentId;
					available.Remove(item);
					foreach (Tile<short> neighbor in item.GetNeighbors())
					{
						available.Remove(neighbor);
					}
					totalBudget -= item.Area;
				}
				currentId++;
			}
		}

		private HashSet<Tile<short>> PaintLandmass(Tile<short> origin, float budget, RandomSet<Tile<short>> available)
		{
			//IL_00a8: 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_00b9: Unknown result type (might be due to invalid IL or missing references)
			HashSet<Tile<short>> hashSet = new HashSet<Tile<short>>();
			WeightedRandomSet<WeightedTile> weightedRandomSet = new WeightedRandomSet<WeightedTile>(random);
			weightedRandomSet.Add(new WeightedTile