Decompiled source of Riverheim v0.12.0
Riverheim.dll
Decompiled 5 months ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.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