Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of Riverheim v0.13.0
Riverheim.dll
Decompiled 5 days 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: IgnoresAccessChecksTo("assembly_utils")] [assembly: IgnoresAccessChecksTo("assembly_valheim")] [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.13.0.0")] [assembly: AssemblyInformationalVersion("0.13.0+ab27ec7bcd6e8fd3e15d20e7b95acb600253566f")] [assembly: AssemblyProduct("Riverheim")] [assembly: AssemblyTitle("Riverheim")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.13.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.13.0"; } namespace Riverheim.Plugin { [BepInPlugin("dev.gurebu.riverheim", "Riverheim", "0.13.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) { WorldState state = new WorldStateGenerator { Verbose = true }.Generate(__instance.GetSeed(), DefaultConfig.Config()); 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(); } } [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; } public 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.13.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.13.0" }); } [HarmonyPriority(700)] [HarmonyPrefix] [HarmonyPatch("RPC_ServerHandshake")] private static void RPC_ServerHandshake(ZNet __instance, ZRpc rpc) { rpc.Invoke("AssertRiverheimVersion", new object[1] { "0.13.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) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Expected O, but got Unknown Harmony val = new Harmony("dev.gurebu.riverheim"); val.PatchAll(); val.Patch((MethodBase)FindWorldSaveMethod(), (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(ReplaceWorldSaveMethod()), (HarmonyMethod)null, (HarmonyMethod)null); 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); } }); } private MethodInfo FindWorldSaveMethod() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: 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_000f: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) GameVersion currentVersion = Version.CurrentVersion; string text; Type[] array; if (currentVersion >= new GameVersion(0, 221, 13)) { text = "SaveWorldFWLData"; array = new Type[2] { typeof(DateTime), typeof(FileWriter).MakeByRefType() }; } else { text = "SaveWorldMetaData"; array = new Type[4] { typeof(DateTime), typeof(bool), typeof(bool).MakeByRefType(), typeof(FileWriter).MakeByRefType() }; } ((BaseUnityPlugin)this).Logger.LogDebug((object)$"Patching world load method: '{text}' for game version {currentVersion}"); return AccessTools.Method(typeof(World), text, array, (Type[])null); } private static MethodInfo ReplaceWorldSaveMethod() { return AccessTools.Method(typeof(WorldSaveLoadPatch), "TranspileWorldSave", (Type[])null, (Type[])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 System.Runtime.CompilerServices { [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] internal sealed class IgnoresAccessChecksToAttribute : Attribute { public IgnoresAccessChecksToAttribute(string assemblyName) { } } } 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<We