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 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) { 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) - P; meta = mask.a; return true; } case Biome.DeepNorth: height = baseHeightMultiplier * WorldGeneratorPatch.GetDeepNorthHeight(worldGenInstance, (float)pos.x, (float)pos.y) - 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 * (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 = 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 Renderers = new ConditionalWeakTable(); [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 TranspileWorldSave(IEnumerable 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 TranspileWorldLoad(IEnumerable 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 PeerVersions = new ConditionalWeakTable(); 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("AssertRiverheimVersion", (Action)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()); 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 instruction) => !(instruction.opcode != OpCodes.Newobj) && ((ConstructorInfo)instruction.operand).DeclaringType == typeof(ZPackage)), (string)null), new CodeMatch((Func)((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 instruction) => CodeInstructionExtensions.IsLdarg(instruction, (int?)null)), (string)null), new CodeMatch((Func)((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)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 { 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 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 { 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 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 { 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(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(new Rfloat2[2] { new Rfloat2(0.0, 15.0), new Rfloat2(140.0, 0.0) }), HeightBias = new StaticArray(new Rfloat2[2] { new Rfloat2(30.0, 0.0), new Rfloat2(40.0, -10.0) }), RoughnessBias = new StaticArray(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(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(new Rfloat2[2] { new Rfloat2(0.0, -90.0), new Rfloat2(300.0, 0.0) }), RiverDistanceBias = new StaticArray(new Rfloat2[3] { new Rfloat2(0.0, -25.0), new Rfloat2(140.0, -15.0), new Rfloat2(170.0, 0.0) }), HeightBias = new StaticArray(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(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(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(new Rfloat2[2] { new Rfloat2(30.0, 0.0), new Rfloat2(40.0, -5.0) }) }, Mistlands = new BiomeConfig { NoiseScale = 1000f, TravelDistanceBias = new StaticArray(new Rfloat2[2] { new Rfloat2(5500.0, -100.0), new Rfloat2(6500.0, 10.0) }), CoastalDistanceBias = new StaticArray(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 tile); [Producer(typeof(CoastalProximityMap))] [ConfiguredBy(typeof(CommonConfig))] [Consumer(typeof(ITiling))] public class CoastalProximityComponent { private readonly CommonConfig config; private readonly ITiling flags; public CoastalProximityComponent(CommonConfig config, ITiling flags) { this.config = config; this.flags = flags; } public CoastalProximityMap Compute() { ITiling tiling = flags.CreateDistanceField((Tile tile) => (!tile.Data.IsShore) ? null : new float?(config.TileSpacing / 2f)); return (Tile 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 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))] [Consumer(typeof(ITiling))] [Consumer(typeof(BiomePostprocessedHeightMap))] public class WorldMetricCalculator { private readonly Landmasses landmasses; private readonly List rivers; private readonly ITiling biomes; private readonly BiomePostprocessedHeightMap heights; public WorldMetricCalculator(Landmasses landmasses, List rivers, ITiling 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 ComputeLandmassInfos() { Dictionary dictionary = new Dictionary(); foreach (Tile 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 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 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 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 ComputeBiomeMetrics() { Dictionary dictionary = new Dictionary(); foreach (Tile 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 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))] [Consumer(typeof(Landmasses))] [Consumer(typeof(PolarProximityMap))] public class TileFlagComponent { private readonly ITiling landmassIds; private readonly PolarProximityMap polarProximityMap; public TileFlagComponent(Landmasses landmasses, PolarProximityMap polarProximityMap) { landmassIds = landmasses.LandmassIds; this.polarProximityMap = polarProximityMap; } public ITiling Compute() { return landmassIds.CreateSisterTiling(delegate(Tile 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 value = tile; Tile? 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 tile) { return tile.Data != -1; } static bool isShoreTile(Tile tile) { foreach (Tile neighbor in tile.GetNeighbors()) { if (isLandTile(tile) != isLandTile(neighbor)) { return true; } } return false; } } } [Producer(typeof(ITiling[]))] [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[] Compute() { ITiling[] array = new ITiling[painterConfig.layerCount]; for (int i = 0; i < array.Length; i++) { array[i] = TilingUtility.CreateVoronoiFromPoissonDisc(random.CreateEngine("Tiling" + i), commonConfig.WorldSize, commonConfig.TileSpacing * Mathf.Pow(painterConfig.layerScale, (float)i)); } return array; } } public delegate float TravelDistanceMap(Tile tile); [Producer(typeof(TravelDistanceMap))] [Consumer(typeof(ITiling))] [Consumer(typeof(RiverState))] public class TravelDistanceComponent { private readonly ITiling flags; private readonly RiverState riverState; public TravelDistanceComponent(ITiling 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 basinTiling = riverState.basinTiling; ITiling result = flags.CreateSisterTiling(float.MaxValue); Tile? tile2 = result.GetTile(Vector2.zero); if (tile2.HasValue) { Tile valueOrDefault = tile2.GetValueOrDefault(); valueOrDefault.Data = 0f; Queue> queue = new Queue>(); queue.Enqueue(valueOrDefault); while (queue.Count > 0) { Tile tile3 = queue.Dequeue(); foreach (Tile 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 tile) => tile.SisterData(result); } return (Tile _) => 0f; } } public struct WorldState { public ITiling Heightmap; public ITiling Biomes; public List rivers; public Plateau[] plateaus; public PolarProximityMap polarProximity; } [Producer(typeof(WorldState))] [Consumer(typeof(BiomePostprocessedHeightMap))] [Consumer(typeof(ITiling))] [Consumer(typeof(List))] [Consumer(typeof(Plateau[]))] [Consumer(typeof(PolarProximityMap))] public class WorldStateCompiler { private readonly ITiling heights; private readonly ITiling biomes; private readonly List rivers; private readonly Plateau[] plateaus; private readonly PolarProximityMap polarProximity; public WorldStateCompiler(BiomePostprocessedHeightMap heights, ITiling biomes, List 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(); } public T GetResult() { return pipeline.GetResult(); } } } namespace Riverheim.World.Rivers { public delegate float BasinBoundaryProximityMap(Tile tile); [Producer(typeof(BasinBoundaryProximityMap))] [Consumer(typeof(ITiling))] [Consumer(typeof(RiverState))] public class BasinBoundaryProximityComponent { private readonly ITiling flags; private readonly RiverState riverState; public BasinBoundaryProximityComponent(ITiling flags, RiverState riverState) { this.flags = flags; this.riverState = riverState; } public BasinBoundaryProximityMap Compute() { ITiling tiling = flags.CreateDistanceField(delegate(Tile tile) { int basinId = tile.SisterData(riverState.basinTiling).basinId; if (basinId == -1) { return null; } foreach (Tile neighbor in tile.GetNeighbors()) { int basinId2 = neighbor.SisterData(riverState.basinTiling).basinId; if (basinId2 != -1 && basinId2 != basinId) { return flags.Spacing / 2f; } } return null; }, (Tile tile) => tile.Data.IsLand); return (Tile 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? tile = landmasses.Artifacts.GetTile(pos); if (tile.HasValue && tile.GetValueOrDefault().Data.IsBasin) { num += config.BasinContribution; } return 1f + num; }; } } public delegate float RiverCuriosityScore(Tile 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 lengthsById; public float score; public float Length { get { float num = 0f; foreach (float value in lengthsById.Values) { num += value; } return num; } } public TileData(Dictionary lengths) { lengthsById = ((lengths == null) ? new Dictionary() : new Dictionary(lengths)); score = 0f; } } private readonly CommonConfig commonConfig; private readonly RiverCuriosityConfig config; private readonly RiverState riverState; private readonly ITiling data; public RiverCuriosityComponent(CommonConfig commonConfig, RiverCuriosityConfig config, RiverState riverState) { this.commonConfig = commonConfig; this.config = config; this.riverState = riverState; data = riverState.riverTiling.CreateSisterTiling(); } public RiverCuriosityScore Compute() { ITiling result = data.CreateSisterTiling(0f); List> list = FindMouths(); foreach (Tile item in list) { MarkLengths(item); } foreach (Tile item2 in list) { MarkScores(item2); } foreach (Tile item3 in list) { SmoothScores(item3, result); } return (Tile tile) => tile.SisterData(result); } private List> FindMouths() { List> list = new List>(); foreach (Tile tile in riverState.riverTiling.Tiles) { if (tile.Data != null && tile.Data.IsRiverMouth) { list.Add(tile); } } return list; } private void MarkLengths(Tile tile, Dictionary 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 lengthsById = tile.SisterData(data).lengthsById; int id = tile.Data.Id; if (!lengthsById.ContainsKey(id)) { lengthsById[id] = segmentLength; } else { lengthsById[id] += segmentLength; } foreach (Tile inlet in tile.Data.Inlets) { Tile tile2 = inlet; Vector2 val = tile.Center - inlet.Center; MarkLengths(tile2, lengthsById, ((Vector2)(ref val)).magnitude); } } private void MarkScores(Tile 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 inlet in tile.Data.Inlets) { MarkScores(inlet); } } private float ComputeSourceScore(Tile tile) { if (!tile.SisterData(riverState.riverTiling).IsTermination) { return 0f; } return Mathf.InverseLerp(config.sourceMinLength, config.sourceMaxLength, tile.Data.Length); } private float ComputeProximityScore(Tile 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 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 tile) { float num = 0f; Direction direction = tile.DirectionTo(tile.Data.Outlet); foreach (Tile 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 tile, ITiling 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 item in tile.Scan(smoothingRange)) { Vector2 val = (tile.Center - item.Center) / smoothingRange; item.SisterData(result) += score * Gauss2(((Vector2)(ref val)).SqrMagnitude()); } } foreach (Tile 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 from, Tile to) { Dictionary dictionary = new Dictionary(from.Data.lengthsById); foreach (KeyValuePair 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 Outlet; public List> 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))] [Consumer(typeof(Landmasses))] [Consumer(typeof(PrecipitationMap))] public class RiverFill { private struct FillTile : WeightedRand.IItem { public Tile Tile; public uint Weight { get; set; } } private struct InletConfiguration : WeightedRand.IItem { public List Directions; public uint Weight { get; set; } } private readonly RandomEngine random; private readonly ITiling Input; private readonly ITiling LandmassIds; private readonly PrecipitationMap Precipitation; private readonly ITiling Rivers; private readonly ITiling Basins; private readonly RiverConfig Config; private int MaxRiverId; public RiverFill(RandomEngine randomEngine, RiverConfig config, ITiling flags, Landmasses landmasses, PrecipitationMap precipitation) { random = randomEngine; Config = config; Input = flags; LandmassIds = landmasses.LandmassIds; Precipitation = precipitation; Rivers = flags.CreateSisterTiling((Func, RiverCell>)((Tile _) => null)); Basins = flags.CreateSisterTiling(delegate { RiverBasinCell result = default(RiverBasinCell); result.basinId = -1; result.Catchment = 0f; return result; }); } private FillTile MakeFillTile(Tile 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 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 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 to, Tile from) { to.Data.Inlets.Add(from); from.Data = new RiverCell { Outlet = to, Inlets = new List>(), Catchment = 0f, Width = 0f }; Tile tile = Basins.GetTile(from.Id); ref RiverBasinCell data = ref tile.Data; tile = Basins.GetTile(to.Id); data.basinId = tile.Data.basinId; } private List GetInletConfigurations(List validInlets, Direction outletDirection) { List list = new List { inletConfiguration(new List()) }; for (int i = 0; i < validInlets.Count; i++) { list.Add(inletConfiguration(new List { validInlets[i] })); for (int j = i + 1; j < validInlets.Count; j++) { list.Add(inletConfiguration(new List { validInlets[i], validInlets[j] })); } } List list2 = new List(); 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 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 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> list = InitRivers(Config.startingDensity); if (list.Count == 0) { Logger.LogWarning("Failed to produce any river mouths!"); } Dictionary>> dictionary = new Dictionary>>(); foreach (Tile item in list) { short data = LandmassIds.GetTile(item.Id).Data; if (!dictionary.ContainsKey(data)) { dictionary[data] = new List>(); } dictionary[data].Add(item); } foreach (List> value in dictionary.Values) { WeightedRandomSet weightedRandomSet = new WeightedRandomSet(random); foreach (Tile item2 in value) { weightedRandomSet.Add(MakeFillTile(item2)); } while (weightedRandomSet.Count > 0) { FillTile fillTile = weightedRandomSet.Pop(); Tile tile = fillTile.Tile; Dictionary> dictionary2 = new Dictionary>(); foreach (Tile 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 inletConfigurations = GetInletConfigurations(new List(dictionary2.Keys), tile.DirectionTo(tile.Data.Outlet)); foreach (Direction direction in WeightedRand.Sample(random, inletConfigurations).Directions) { Tile tile2 = dictionary2[direction]; AddInlet(tile, tile2); weightedRandomSet.Add(MakeFillTile(tile2, fillTile.Weight)); } } } foreach (Tile item3 in list) { MarkWeights(item3); if (prune) { Prune(item3, Config.prune); } if (item3.Data != null) { MarkRiverIds(item3); } } foreach (Tile tile3 in Basins.Tiles) { tile3.Data.HasRiver = tile3.SisterData(Rivers) != null; } foreach (Tile 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 start, RiverPruneConfig config) { Queue> queue = new Queue>(); queue.Enqueue(start); while (queue.Count > 0) { Tile 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> list = new List>(tile.Data.Inlets); if (list.Count == 0) { continue; } float num = 0f; foreach (Tile item in list) { if (item.Data.Catchment > num) { num = item.Data.Catchment; } } foreach (Tile item2 in list) { if (item2.Data.Catchment > 0f && num / item2.Data.Catchment > config.maxCatchmentDiff) { DeleteRiver(item2); } else { queue.Enqueue(item2); } } } } private void DeleteRiver(Tile tile) { tile.Data.Outlet.Data?.Inlets.Remove(tile); Tile[] array = tile.Data.Inlets.ToArray(); foreach (Tile tile2 in array) { DeleteRiver(tile2); } tile.Data = null; } private int ComputeStrahlerNumber(List 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 tile) { //IL_008c: Unknown result type (might be due to invalid IL or missing references) List list = new List(); float num = 0f; for (int i = 0; i < tile.Data.Inlets.Count; i++) { Tile 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 tile) { if (tile.Data.IsTermination) { tile.Data.Id = MaxRiverId++; return; } float num = float.MinValue; RiverCell riverCell = null; foreach (Tile inlet in tile.Data.Inlets) { MarkRiverIds(inlet); if (inlet.Data.Catchment > num) { riverCell = inlet.Data; } } tile.Data.Id = riverCell.Id; } private List> 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> randomSet = new RandomSet>(random); foreach (Tile tile3 in Input.Tiles) { if (tile3.Data.IsSuitableShore()) { randomSet.Add(tile3); } } List> list = new List>(); 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 tile = randomSet.Pop(); int num2 = 0; foreach (Tile neighbor in tile.GetNeighbors()) { if (neighbor.Data.IsSuitableLand()) { num2++; } } if (num2 < Config.minRiverMouthLandNeighbors) { continue; } Vector2 val = Vector2.zero; foreach (Tile 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 tile2 = Rivers.GetTile(tile.Id); tile2.Data = new RiverCell { Outlet = tile2.GetNeighbor(new Direction(val)), Inlets = new List>(), 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 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 result = riverState.basinTiling.CreateDistanceField((Tile tile) => (!tile.Data.HasRiver) ? null : new float?(0f)); return (Tile tile) => tile.SisterData(result); } } public struct RiverState { public ITiling riverTiling; public ITiling 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 vertices; } [Producer(typeof(List))] [Consumer(typeof(RiverState))] public class RiverVerticesCalculator { private readonly ITiling rivers; public RiverVerticesCalculator(RiverState riverState) { rivers = riverState.riverTiling; } public List 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> dictionary = new Dictionary>(); Stack> stack = new Stack>(); foreach (Tile tile2 in rivers.Tiles) { if (tile2.Data != null && tile2.Data.IsRiverMouth) { stack.Push(tile2); dictionary.Add(tile2.Data.Id, new List { new RiverVertex { pos = tile2.Data.Outlet.Center, data = new RiverVertexData { meanderiness = 0f, depth = 1f, width = tile2.Data.Width } } }); } } while (stack.Count > 0) { Tile tile = stack.Pop(); HashSet hashSet = new HashSet { tile.Data.Id }; foreach (Tile 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(); width = tile.Data.Inlets.Find((Tile 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 inlet2 in tile.Data.Inlets) { stack.Push(inlet2); } } List list = new List(); foreach (KeyValuePair> 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 layers; } [Producer(typeof(ITiling[]))] [Randomized("LandmassPainter")] [ConfiguredBy(typeof(CommonConfig))] [ConfiguredBy(typeof(LandmassPainterConfig))] [Consumer(typeof(ITiling[]))] [Consumer(typeof(LandmassRestrictions))] public class LandmassPainter { private struct WeightedTile : WeightedRand.IItem { public Tile 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[] tilings; private readonly LandmassRestrictions restrictions; private short currentId; public LandmassPainter(RandomEngine random, CommonConfig commonConfig, LandmassPainterConfig config, ITiling[] tilings, LandmassRestrictions restrictions) { this.random = random; this.commonConfig = commonConfig; this.config = config; this.tilings = tilings; this.restrictions = restrictions; } public ITiling[] Compute() { //IL_0108: Unknown result type (might be due to invalid IL or missing references) ITiling[] array = new ITiling[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? tile = array[num3].GetTile(Vector2.zero); if (tile.HasValue) { Tile valueOrDefault = tile.GetValueOrDefault(); if (valueOrDefault.Data == -1) { foreach (Tile neighbor in valueOrDefault.GetNeighbors()) { if (neighbor.Data != -1) { valueOrDefault.Data = neighbor.Data; } } if (valueOrDefault.Data == -1) { valueOrDefault.Data = currentId++; } } } } return array; } private RandomSet> CalcAvailableTiles(ITiling tiling, float tileScale) { RandomSet> randomSet = new RandomSet>(random, tiling.Tiles); foreach (Tile tile in tiling.Tiles) { if (!restrictions.IsTileValidForLand(tile, tileScale)) { randomSet.Remove(tile); } if (tile.Data == -1) { continue; } randomSet.Remove(tile); foreach (Tile neighbor in tile.GetNeighbors()) { randomSet.Remove(neighbor); } } return randomSet; } private void InheritLayer(ITiling to, ITiling 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 tile2 in to.Tiles) { if (restrictions.IsTileValidForLand(tile2, tileScale)) { Tile? tile = from.GetTile(tile2.Center + vectorNoiseField.Sample(tile2.Center)); if (tile.HasValue) { Tile valueOrDefault = tile.GetValueOrDefault(); tile2.Data = valueOrDefault.Data; } if (tile2.Data != -1) { area += tile2.Area; } } } } private void PaintLayer(RandomSet> 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 item in PaintLandmass(available.Sample(), num, available)) { item.Data = currentId; available.Remove(item); foreach (Tile neighbor in item.GetNeighbors()) { available.Remove(neighbor); } totalBudget -= item.Area; } currentId++; } } private HashSet> PaintLandmass(Tile origin, float budget, RandomSet> 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> hashSet = new HashSet>(); WeightedRandomSet weightedRandomSet = new WeightedRandomSet(random); weightedRandomSet.Add(new WeightedTile { tile = origin, weight = 1f }); while (weightedRandomSet.Count > 0 && budget > 0f) { Tile tile = weightedRandomSet.Pop().tile; budget -= tile.Area; hashSet.Add(tile); foreach (Tile neighbor in tile.GetNeighbors()) { if (available.Contains(neighbor) && !hashSet.Contains(neighbor)) { WeightedTile item = new WeightedTile { tile = neighbor }; float spacing = origin.Tiling.Spacing; Vector2 val = tile.Center - origin.Center; item.weight = spacing / ((Vector2)(ref val)).sqrMagnitude; weightedRandomSet.Add(item); } } } return hashSet; } } public struct Landmasses { public ITiling LandmassIds; public ITiling Artifacts; } [Serializable] public struct LandmassPostprocessingConfig { public float coastalTrimNoiseScale; public float coastalTrimDistance; public float coastalTrimVariance; public float effectiveSpawnRadius; } [Producer(typeof(Landmasses))] [Randomized("LandmassPostprocessor")] [ConfiguredBy(typeof(LandmassPostprocessingConfig))] [Consumer(typeof(ITiling[]))] public class LandmassPostprocessor { private readonly RandomEngine random; private readonly LandmassPostprocessingConfig config; private readonly ITiling tiling; public LandmassPostprocessor(RandomEngine random, LandmassPostprocessingConfig config, ITiling[] tilings) { this.random = random; this.config = config; tiling = tilings[0].CreateSisterTiling((short data) => data >= 0); } public Landmasses Compute() { NoiseField noise = random.MetricNoise2D("CoastalTrim", config.coastalTrimNoiseScale); float minArea = (float)Math.PI * config.effectiveSpawnRadius * config.effectiveSpawnRadius; LandmassUtility.TrimCoastline(tiling, noise, config.coastalTrimDistance, config.coastalTrimVariance); LandmassUtility.Trim(tiling); LandmassUtility.RemoveLakes(tiling, out var lakeTiles); LandmassUtility.EnsureStartingAreaIsLand(tiling, minArea); Landmasses result = default(Landmasses); result.LandmassIds = LandmassUtility.MarkLandmassIds(tiling); result.Artifacts = tiling.CreateSisterTiling(delegate(Tile tile) { LandmassArtifacts result2 = default(LandmassArtifacts); result2.IsBasin = lakeTiles.Contains(tile); result2.IsFault = false; return result2; }); return result; } } [Serializable] public struct LandmassRestrictionConfig { public int swirlRays; public float swirlExponent; public float swirlStartRadius; public float swirlNoiseScale; public float swirlNoiseOffset; public float swirlToleranceMult; public float toleranceScalePow; public HarborConfig harbor; } [Serializable] public struct HarborConfig { public float offset; public float radius; public float circularity; } [Producer(typeof(LandmassRestrictions))] [Randomized("LandmassRestrictions")] [ConfiguredBy(typeof(CommonConfig))] [ConfiguredBy(typeof(LandmassRestrictionConfig))] [Consumer(typeof(PolarProximityMap))] public class LandmassRestrictionComponent { private readonly RandomEngine random; private readonly CommonConfig commonConfig; private readonly LandmassRestrictionConfig config; private readonly PolarProximityMap polarProximity; public LandmassRestrictionComponent(RandomEngine random, CommonConfig commonConfig, LandmassRestrictionConfig config, PolarProximityMap polarProximity) { this.random = random; this.commonConfig = commonConfig; this.config = config; this.polarProximity = polarProximity; } public LandmassRestrictions Compute() { return new LandmassRestrictions(commonConfig, config, Math.Sign(random.Value - 0.5), new Direction((float)random.Range(Math.PI * 2.0)), random.MetricNoise2D("LandmassSwirl", config.swirlNoiseScale) + config.swirlNoiseOffset, new Direction((float)random.Range(Math.PI * 2.0)), polarProximity); } } public readonly struct LandmassRestrictions { private readonly LandmassRestrictionConfig config; private readonly CommonConfig commonConfig; private readonly float swirlChirality; private readonly Direction swirlRotation; private readonly NoiseField swirlNoise; private readonly Direction harborRotation; private readonly PolarProximityMap polarProximity; public LandmassRestrictions(CommonConfig commonConfig, LandmassRestrictionConfig config, float swirlChirality, Direction swirlRotation, NoiseField swirlNoise, Direction harborRotation, PolarProximityMap polarProximity) { this.commonConfig = commonConfig; this.config = config; this.swirlChirality = swirlChirality; this.swirlRotation = swirlRotation; this.swirlNoise = swirlNoise; this.harborRotation = harborRotation; this.polarProximity = polarProximity; } public bool IsTileValidForLand(Tile tile, float tileScale) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) float toleranceScale = Mathf.Pow(tileScale, config.toleranceScalePow); if (tile.DistanceToBounds == 0) { return false; } Vector2 center = tile.Center; if (((Vector2)(ref center)).magnitude > commonConfig.WorldSize - commonConfig.TileSpacing) { return false; } if (IsTileInHarbor(tile)) { return false; } switch (TilePolarity(tile, toleranceScale)) { case 0: return false; case 1: return true; default: if (IsTileInSwirl(tile, toleranceScale)) { return false; } return true; } } private bool IsTileInHarbor(Tile tile) { //IL_003e: 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_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) float offset = config.harbor.offset; float radius = config.harbor.radius; float angle = harborRotation.Angle; if (radius <= 0f) { return false; } Vector2 val = tile.Center - (offset + radius) * new Vector2(Mathf.Cos(angle), Mathf.Sin(angle)); return ((Vector2)(ref val)).sqrMagnitude <= HarborFunc(val.x, val.y, angle); } private float HarborFunc(float x, float y, float angle) { float radius = config.harbor.radius; float circularity = config.harbor.circularity; return radius * radius * BellCurve((x * Mathf.Sin(angle) - y * Mathf.Cos(angle)) / (radius * circularity)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] private static float BellCurve(float x) { return 1f / (1f + x * x); } private int TilePolarity(Tile tile, float toleranceScale) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) float num = polarProximity(tile.Center) / toleranceScale; if (!(num >= 1f)) { if (num <= -1f) { return -1; } return 0; } return 1; } private bool IsTileInSwirl(Tile tile, float toleranceScale) { //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_0018: 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) Vector2 center = tile.Center; float magnitude = ((Vector2)(ref center)).magnitude; float num = swirlChirality * (new Direction(tile.Center) - swirlRotation); if (magnitude < config.swirlStartRadius) { return false; } float num2 = toleranceScale * config.swirlToleranceMult * swirlNoise.Sample(tile.Center); for (int i = 0; i <= 10; i++) { for (float num3 = 0f; num3 < (float)config.swirlRays; num3 += 1f) { float num4 = (float)Math.PI * 2f * ((float)i + num3 / (float)config.swirlRays); float num5 = Mathf.Pow(config.swirlExponent, num + num4); if (Mathf.Abs(magnitude - num5) < num5 * num2) { return true; } if (num5 > commonConfig.WorldSize) { return false; } } } return false; } } public static class LandmassUtility { public const short NO_LANDMASS_ID = -1; public static Dictionary CalcLandmassAreas(ITiling landmassIds) { Dictionary dictionary = new Dictionary(); foreach (Tile tile in landmassIds.Tiles) { if (isLand(tile.Data) && !dictionary.ContainsKey(tile.Data)) { dictionary[tile.Data] = CalcLandmassArea(tile, isLand); } } return dictionary; static bool isLand(short id) { return id != -1; } } public static float CalcLandmassArea(Tile origin, Predicate isLand) { float num = 0f; if (!isLand(origin.Data)) { return num; } HashSet> hashSet = new HashSet>(); Queue> queue = new Queue>(); hashSet.Add(origin); queue.Enqueue(origin); while (queue.Count > 0) { Tile tile = queue.Dequeue(); num += tile.Area; foreach (Tile neighbor in tile.GetNeighbors()) { if (isLand(neighbor.Data) && hashSet.Add(neighbor)) { queue.Enqueue(neighbor); } } } return num; } public static void Trim(ITiling landTiling, int distance = 1) { foreach (Tile tile in landTiling.Tiles) { if (tile.DistanceToBounds < distance) { tile.Data = false; } } } public static void TrimCoastline(ITiling tiling, NoiseField noise, float threshold, float variance) { //IL_0069: Unknown result type (might be due to invalid IL or missing references) foreach (Tile tile in tiling.CreateDistanceField(delegate(Tile tile) { foreach (Tile neighbor in tile.GetNeighbors()) { if (!neighbor.IsLand()) { return 0.5f * tiling.Spacing; } } return null; }, (Tile tile) => tile.IsLand()).Tiles) { if (tile.Data < threshold * (1f + variance * noise.Sample(tile.Center))) { tile.SisterData(tiling) = false; } } } public static void EnsureStartingAreaIsLand(ITiling landTiling, float minArea = 0f) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) Tile? tile = landTiling.GetTile(Vector2.zero); if (!tile.HasValue) { return; } Tile valueOrDefault = tile.GetValueOrDefault(); valueOrDefault.Data = true; int num = 1; while (CalcLandmassArea(valueOrDefault, (bool isLand) => isLand) < minArea) { foreach (Tile neighbor in valueOrDefault.GetNeighbors(num++)) { neighbor.Data = true; } } } public static void RemoveLakes(ITiling landTiling, out HashSet> removed) { Queue> queue = new Queue>(); HashSet> hashSet = new HashSet>(); foreach (Tile tile in landTiling.Tiles) { if (!tile.IsLand()) { if (tile.DistanceToBounds == 0) { queue.Enqueue(tile); } else { hashSet.Add(tile); } } } if (queue.Count == 0) { Logger.LogError("landmass doesn't contain any ocean at bounds!"); } while (queue.Count > 0) { foreach (Tile neighbor in queue.Dequeue().GetNeighbors()) { if (hashSet.Contains(neighbor)) { hashSet.Remove(neighbor); queue.Enqueue(neighbor); } } } removed = hashSet; foreach (Tile item in removed) { item.Data = true; } } public static ITiling MarkLandmassIds(ITiling landTiling) { ITiling tiling = landTiling.CreateSisterTiling((Func, short>)((Tile _) => -1)); short num = 0; foreach (Tile tile in tiling.Tiles) { if (tile.Data != -1 || !landTiling.GetTile(tile.Id).IsLand()) { continue; } Queue> queue = new Queue>(); tile.Data = num; queue.Enqueue(tile); while (queue.Count > 0) { foreach (Tile neighbor in queue.Dequeue().GetNeighbors()) { if (landTiling.GetTile(neighbor.Id).IsLand() && neighbor.Data == -1) { neighbor.Data = num; queue.Enqueue(neighbor); } } } num++; } return tiling; } } } namespace Riverheim.World.Landmass.Internal { internal static class Extensions { public static bool IsLand(this Tile tile) { return tile.Data; } } } namespace Riverheim.World.Height { public struct CoastalProximityBasedHeightMap { public ITiling proximity; public ITiling height; } [Producer(typeof(CoastalProximityBasedHeightMap))] [Randomized("Heights/CoastalProximity")] [ConfiguredBy(typeof(CommonConfig))] [ConfiguredBy(typeof(Config))] [Consumer(typeof(ITiling))] [Consumer(typeof(PolarProximityMap))] [Consumer(typeof(RiverState))] [Consumer(typeof(ITiling))] public class CoastalProximityHeightComponent { [Serializable] public struct Config { public float displacementNoiseScale; public float displacementNoiseThreshold; public float displacementMagnitudeLand; public float displacementMagnitudeWater; public float southPolarScale; public float oceanTrenchDepthScale; public HeightUtility.CoastalProfileConfig landProfile; public float oceanProfileSteepness; } private readonly CommonConfig commonConfig; private readonly Config config; private readonly ITiling flags; private readonly PolarProximityMap polarProximity; private readonly RiverState riverState; private readonly ITiling waterFlags; private readonly NoiseField displacementNoise; public CoastalProximityHeightComponent(RandomEngine random, CommonConfig commonConfig, Config config, ITiling flags, PolarProximityMap polarProximity, RiverState riverState, ITiling waterFlags) { this.commonConfig = commonConfig; this.config = config; this.flags = flags; this.polarProximity = polarProximity; this.riverState = riverState; this.waterFlags = waterFlags; displacementNoise = random.BiasedMetricNoise2D("Heights/CoastalDisplacement", config.displacementNoiseScale); } public CoastalProximityBasedHeightMap Compute() { ITiling proximity = GetProximity(); CoastalProximityBasedHeightMap result = default(CoastalProximityBasedHeightMap); result.proximity = proximity; result.height = flags.CreateSisterTiling((Tile tile) => (!tile.SisterData(waterFlags).isLand) ? HeightUtility.SaturationProfile(tile.SisterData(proximity), config.oceanProfileSteepness, commonConfig.OceanDepth) : HeightUtility.CoastalProfile(tile.SisterData(proximity), config.landProfile)); return result; } private ITiling GetProximity() { //IL_00a3: Unknown result type (might be due to invalid IL or missing references) ITiling landProximity = GetLandProximity(); foreach (Tile tile in landProximity.Tiles) { if (tile.SisterData(flags).IsSouthPolar) { tile.Data *= config.southPolarScale; } } ITiling oceanProximity = GetWaterProximity(); foreach (Tile tile2 in oceanProximity.Tiles) { tile2.Data *= PolarFactor(tile2.Center); } return flags.CreateSisterTiling((Tile tile) => (!tile.SisterData(waterFlags).isLand) ? tile.SisterData(oceanProximity) : tile.SisterData(landProximity)); } private ITiling GetLandProximity() { return flags.CreateDistanceField((Tile tile) => (!tile.SisterData(waterFlags).isCoast) ? null : new float?(0.5f * commonConfig.TileSpacing + Mathf.Max(0f, config.displacementMagnitudeLand * DisplacementIntensity(tile.Center))), (Tile tile) => tile.SisterData(waterFlags).isLand); } private ITiling GetWaterProximity() { ITiling riverMouthProximity = flags.CreateDistanceField((Tile tile) => (!tile.SisterData(riverState.basinTiling).HasRiverMouth) ? null : new float?(0f), delegate(Tile tile) { TileFlags data = tile.Data; return data.IsOcean && data.IsShore; }); return flags.CreateDistanceField(delegate(Tile tile) { //IL_0040: Unknown result type (might be due to invalid IL or missing references) if (!tile.SisterData(waterFlags).isCoast) { return null; } float num = Mathf.Max(0f, config.displacementMagnitudeWater * DisplacementIntensity(tile.Center)); float num2 = Mathf.Max(0f, config.displacementMagnitudeWater - riverMouthProximity.GetTile(tile.Id).Data); return 0.5f * commonConfig.TileSpacing + Mathf.Max(num, num2); }, (Tile tile) => tile.SisterData(waterFlags).isWater); } private float DisplacementIntensity(Vector2 pos) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) float num = displacementNoise.Sample(pos); float displacementNoiseThreshold = config.displacementNoiseThreshold; return (num - displacementNoiseThreshold) / (1f - displacementNoiseThreshold); } private float PolarFactor(Vector2 pos) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) return 1f + config.oceanTrenchDepthScale * Mathf.Exp(0f - Math.Abs(polarProximity(pos))); } } public struct FlatlandMap { public Func lowlands; public Func highlands; } [Producer(typeof(FlatlandMap))] [Randomized("Heights/Flatlands")] [ConfiguredBy(typeof(Config))] [Consumer(typeof(Landmasses))] public class FlatlandsComponent { [Serializable] public struct Config { public HeightUtility.SplatterNoiseConfig lowlandNoise; public HeightUtility.SplatterNoiseConfig highlandNoise; } private readonly RandomEngine random; private readonly Config config; private readonly Landmasses landmasses; public FlatlandsComponent(RandomEngine random, Config config, Landmasses landmasses) { this.random = random; this.config = config; this.landmasses = landmasses; } public FlatlandMap Compute() { Func lowlands = HeightUtility.SplatterNoise(random, "Heights/Flatlands/Lowlands", config.lowlandNoise); Func highlands = HeightUtility.SplatterNoise(random, "Heights/Flatlands/Highlands", config.highlandNoise); FlatlandMap result = default(FlatlandMap); result.lowlands = (Vector2 pos) => lowlands(pos) || (landmasses.Artifacts.GetTile(pos)?.Data.IsBasin ?? false); result.highlands = (Vector2 pos) => highlands(pos); return result; } } public struct HeightMap { public ITiling Data; } [Serializable] public struct HeightConfig { public float LowlandHeight; public float HillHeight; public float mountainSpikeHeight; public int smallMountainTileSpan; public float mountainRemovalCutdown; } [Producer(typeof(HeightMap))] [Randomized("HeightCalculator")] [ConfiguredBy(typeof(CommonConfig))] [ConfiguredBy(typeof(HeightConfig))] [Consumer(typeof(ITiling))] [Consumer(typeof(CoastalProximityBasedHeightMap))] [Consumer(typeof(ITiling))] [Consumer(typeof(FlatlandMap))] [Consumer(typeof(ITiling))] [Consumer(typeof(RiverValleyMap))] public class HeightCalculator { private readonly CommonConfig commonConfig; private readonly HeightConfig config; private readonly ITiling flags; private readonly CoastalProximityBasedHeightMap coastalProximityHeights; private readonly ITiling heightClamping; private readonly FlatlandMap flatlandMap; private readonly ITiling waterFlags; private readonly RiverValleyMap riverValleyMap; public HeightCalculator(RandomEngine random, CommonConfig commonConfig, HeightConfig config, ITiling flags, CoastalProximityBasedHeightMap coastalProximityHeights, ITiling heightClamping, FlatlandMap flatlandMap, ITiling waterFlags, RiverValleyMap riverValleyMap) { this.commonConfig = commonConfig; this.config = config; this.flags = flags; this.coastalProximityHeights = coastalProximityHeights; this.heightClamping = heightClamping; this.flatlandMap = flatlandMap; this.waterFlags = waterFlags; this.riverValleyMap = riverValleyMap; } public HeightMap Compute() { ITiling lowlands = CreateLowlandHeightMap(); ITiling highlands = CreateHighlandHeightMap(); ITiling tiling = flags.CreateSisterTiling(delegate(Tile tile) { float num; if (tile.SisterData(waterFlags).isWater) { num = tile.SisterData(coastalProximityHeights.height); } else { float data = lowlands.GetTile(tile.Id).Data; float num2 = tile.SisterData(coastalProximityHeights.height); num = Mathf.Max(highlands.GetTile(tile.Id).Data, Mathf.Min(num2, data)); } HeightClampingRange heightClampingRange = tile.SisterData(heightClamping); return Mathf.Clamp(num, heightClampingRange.min, heightClampingRange.max); }); Postprocess(tiling); HeightMap result = default(HeightMap); result.Data = tiling; return result; } private void Postprocess(ITiling heights) { SinkWorldEdge(heights); CullMountains(heights); } private void SinkWorldEdge(ITiling heights) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) foreach (Tile tile in heights.Tiles) { Vector2 center = tile.Center; if (((Vector2)(ref center)).magnitude > commonConfig.WorldSize - commonConfig.TileSpacing) { tile.Data = commonConfig.OceanDepth; } } } private void CullMountains(ITiling heights) { foreach (Tile item in FindMountainSpikes(heights)) { item.Data = commonConfig.MountainHeight - config.mountainRemovalCutdown; } foreach (Tile item2 in FindSmallMountains(heights)) { item2.Data = commonConfig.MountainHeight - config.mountainRemovalCutdown; } } private HashSet> FindMountainSpikes(ITiling heights) { HashSet> hashSet = new HashSet>(); foreach (Tile tile in heights.Tiles) { if (!(tile.Data < commonConfig.MountainHeight) && (from neighbor in tile.GetNeighbors() select neighbor.Data).Min() < commonConfig.MountainHeight - config.mountainSpikeHeight) { hashSet.Add(tile); } } return hashSet; } private HashSet> FindSmallMountains(ITiling heights) { HashSet> hashSet = new HashSet>(); HashSet> hashSet2 = new HashSet>(); Queue> queue = new Queue>(); foreach (Tile tile in heights.Tiles) { if (tile.Data < commonConfig.MountainHeight || hashSet2.Contains(tile)) { continue; } HashSet> hashSet3 = new HashSet>(); hashSet2.Add(tile); queue.Enqueue(tile); while (queue.Count > 0) { Tile item = queue.Dequeue(); hashSet3.Add(item); foreach (Tile neighbor in item.GetNeighbors()) { if (!hashSet2.Contains(neighbor) && neighbor.Data >= commonConfig.MountainHeight) { hashSet2.Add(neighbor); queue.Enqueue(neighbor); } } } if (hashSet3.Count <= config.smallMountainTileSpan) { hashSet.UnionWith(hashSet3); } } return hashSet; } private ITiling CreateLowlandHeightMap() { ITiling lowlands = flags.CreateDistanceField((Tile tile) => (!flatlandMap.lowlands(tile.Center)) ? null : new float?(0f), (Tile tile) => tile.Data.IsLand).CreateSisterTiling(RiverHeightFunc); return flags.CreateSisterTiling((Tile tile) => config.LowlandHeight + Mathf.Min(tile.SisterData(riverValleyMap.heights), tile.SisterData(lowlands))); } private ITiling CreateHighlandDistanceMap() { return flags.CreateDistanceField((Tile tile) => (!tile.SisterData(waterFlags).isCoast && flatlandMap.highlands(tile.Center)) ? new float?(0f) : null, (Tile tile) => tile.SisterData(waterFlags).isLand); } private ITiling CreateHighlandHeightMap() { ITiling distanceMap = CreateHighlandDistanceMap(); return flags.CreateSisterTiling((Tile tile) => (tile.Data.IsOcean || tile.Data.IsShore) ? commonConfig.OceanDepth : (config.HillHeight - ShoreHeightFunc(tile.SisterData(distanceMap)))); } private float RiverHeightFunc(float distance) { return Mathf.Pow(0.25f * Mathf.Max(0f, distance), 1.12f); } private float ShoreHeightFunc(float distance) { return distance * 0.5f * (float)Math.Pow(Rmath.Sigmoid(distance / 120f), 1.7); } } public struct HeightClampingRange { public float min; public float max; } [Producer(typeof(ITiling))] [Randomized("Heights/Clamping")] [ConfiguredBy(typeof(CommonConfig))] [ConfiguredBy(typeof(Config))] [Consumer(typeof(ITiling))] [Consumer(typeof(TravelDistanceMap))] public class HeightClampingComponent { [Serializable] public struct Config { public float minLandHeight; public float maxLandHeight; public float maxOceanDepth; public float noiseScale; public float noiseAmplitude; public NoiseField.FractalConfig noiseFractal; public float startingAreaInnerRadius; public float startingAreaOuterRadius; } private readonly RandomEngine random; private readonly CommonConfig commonConfig; private readonly Config config; private readonly ITiling flags; private readonly TravelDistanceMap travelDistance; public HeightClampingComponent(RandomEngine random, CommonConfig commonConfig, Config config, ITiling flags, TravelDistanceMap travelDistance) { this.random = random; this.commonConfig = commonConfig; this.config = config; this.flags = flags; this.travelDistance = travelDistance; } public ITiling Compute() { NoiseField noise = random.MetricNoise2D("Ceiling", config.noiseScale).Fractal(config.noiseFractal).Normalize01() * 2f - 1f; return flags.CreateSisterTiling(delegate(Tile tile) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) float num = 1f + config.noiseAmplitude * noise.Sample(tile.Center); HeightClampingRange result = default(HeightClampingRange); result.min = config.maxOceanDepth; result.max = num * Mathf.Lerp(config.minLandHeight, config.maxLandHeight, Mathf.InverseLerp(config.startingAreaInnerRadius, config.startingAreaOuterRadius, travelDistance(tile))); return result; }); } } public static class HeightUtility { [Serializable] public struct SplatterNoiseConfig { public float scale; public float modulationFrequency; public float modulationAmplitude; public float threshold; } [Serializable] public struct CoastalProfileConfig { public float steepness; public float beachWidth; public float transitionSteepness; } public static NoiseField DualMetricNoise2D(RandomEngine random, string id, float featureSize, float modAmplitude, float modFrequency) { NoiseField noiseField = random.BiasedMetricNoise2D(id, featureSize); noiseField *= 1f + modAmplitude * noiseField.Modulate(modFrequency); return noiseField.Normalize01(); } public static Func SplatterNoise(RandomEngine random, string id, SplatterNoiseConfig config) { NoiseField noise = DualMetricNoise2D(random, id, config.scale, config.modulationAmplitude, config.modulationFrequency); return (Vector2 pos) => noise.Sample(pos) < config.threshold; } public static float CoastalProfile(float distance, CoastalProfileConfig config) { return config.steepness * distance * (float)Math.Pow(Rmath.Sigmoid(distance / config.beachWidth), config.transitionSteepness); } public static float ValleyProfile(float distance, float steepness, float power) { return Mathf.Pow(steepness * distance, power); } public static float SaturationProfile(float distance, float steepness, float saturated) { return saturated * (float)Rmath.Smooth3(Rmath.Clamp01(steepness * distance / Math.Abs(saturated))); } } public struct WaterFlags { public bool isWater; public bool isCoast; public bool isLake; public bool isLand => !isWater; public bool isOcean { get { if (isWater) { return !isLake; } return false; } } } [Producer(typeof(ITiling))] [Randomized("Heights/Lakes")] [ConfiguredBy(typeof(Config))] [Consumer(typeof(ITiling))] [Consumer(typeof(CoastalProximityMap))] [Consumer(typeof(RiverCuriosityScore))] [Consumer(typeof(FlatlandMap))] public class LakeComponent { [Serializable] public struct Config { public float noiseScale; public float threshold; public float lowlandContribution; public float curiosityContribution; } private readonly RandomEngine random; private readonly Config config; private readonly ITiling flags; private readonly CoastalProximityMap coastalProximity; private readonly RiverCuriosityScore riverCuriosities; private readonly FlatlandMap flatlandMap; public LakeComponent(RandomEngine random, Config config, ITiling flags, CoastalProximityMap coastalProximity, RiverCuriosityScore riverCuriosities, FlatlandMap flatlandMap) { this.random = random; this.config = config; this.flags = flags; this.coastalProximity = coastalProximity; this.riverCuriosities = riverCuriosities; this.flatlandMap = flatlandMap; } public ITiling Compute() { NoiseField noise = HeightUtility.DualMetricNoise2D(random, "Heights/LakeNoise", config.noiseScale, 3.2f, 6f); ITiling tiling = flags.CreateDistanceField(delegate(Tile tile) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) float num = noise.Sample(tile.Center); if (flatlandMap.lowlands(tile.Center)) { num += config.lowlandContribution; } num += riverCuriosities(tile) * config.curiosityContribution; return (num > config.threshold) ? new float?(0f) : null; }, (Tile tile) => tile.Data.IsLand && coastalProximity(tile) > 200f).CreateSisterTiling(delegate(float distance) { WaterFlags result = default(WaterFlags); result.isLake = distance <= 70f; return result; }); foreach (Tile tile in tiling.Tiles) { tile.Data.isWater = tile.Data.isLake || tile.SisterData(flags).IsOcean; tile.Data.isCoast = tile.SisterData(flags).IsShore || IsLakeShore(tile); } return tiling; } private bool IsLakeShore(Tile tile) { if (!tile.SisterData(flags).IsLand) { return false; } return tile.GetNeighbors().Any((Tile neighbor) => neighbor.Data.isLake != tile.Data.isLake); } } public struct Plateau { public Vector2 p1; public Vector2 p2; public float height; public float radius; public Vector2 incline; public Vector2 bulge; public bool inverse; } [Serializable] public struct PlateauConfig { public float spawnNoiseScale; public PlateauMountainPeakConfig mountainPeaks; public PlateauSeasideCliffConfig seasideCliffs; public PlateauHillConfig hills; public float swampDitchHeight; public int swampDitchTileCount; } [Serializable] public struct PlateauMountainPeakConfig { public float spawnRate; public float minHeightDiff; public float minSize; public float maxSize; public ClampingConfig gradientClamping; public float bulgeMultiplier; } [Serializable] public struct PlateauSeasideCliffConfig { public float spawnRate; public float minHeight; public float minSize; public float maxSize; public ClampingConfig gradientClamping; public float minBulge; public float maxBulge; } [Serializable] public struct PlateauHillConfig { public float spawnRate; public float minHeightDiff; public float minSize; public float maxSize; public float maxLength; public ClampingConfig gradientClamping; public float bulgeMultiplier; } [Serializable] public struct ClampingConfig { public enum Mode { Linear, Asymptotic } public Mode mode; public float min; public float max; public float rate; } [Producer(typeof(Plateau[]))] [Randomized("Plateaus")] [ConfiguredBy(typeof(PlateauConfig))] [Consumer(typeof(BiomePostprocessedHeightMap))] [Consumer(typeof(ITiling))] public class PlateauComponent { private readonly RandomEngine random; private readonly PlateauConfig config; private readonly ITiling heights; private readonly ITiling biomes; public PlateauComponent(RandomEngine random, PlateauConfig config, BiomePostprocessedHeightMap heights, ITiling biomes) { this.random = random; this.config = config; this.heights = heights.Data; this.biomes = biomes; } public Plateau[] Compute() { List list = new List(); HashSet> hashSet = new HashSet>(); AddMountainPeaks(list, hashSet); AddMountainLedges(list, hashSet); AddSeasideCliffs(list, hashSet); AddHills(list, hashSet); AddSwampDitches(list, hashSet); return list.ToArray(); } private void AddMountainPeaks(List result, HashSet> visited) { //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_0126: 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_015a: Unknown result type (might be due to invalid IL or missing references) //IL_015f: Unknown result type (might be due to invalid IL or missing references) //IL_0182: Unknown result type (might be due to invalid IL or missing references) //IL_0194: Unknown result type (might be due to invalid IL or missing references) //IL_0199: Unknown result type (might be due to invalid IL or missing references) //IL_01a2: Unknown result type (might be due to invalid IL or missing references) //IL_01b7: Unknown result type (might be due to invalid IL or missing references) //IL_01bc: Unknown result type (might be due to invalid IL or missing references) NoiseField noiseField = random.BiasedMetricNoise2D("Plateau/SpawnRate/MountainPeaks", config.spawnNoiseScale); NoiseField noiseField2 = random.BiasedNoise2D("Plateau/Size"); foreach (Tile tile in heights.Tiles) { if (tile.SisterData(biomes) == Biome.Mountain && !(noiseField.Sample(tile.Center) > config.mountainPeaks.spawnRate) && !tile.GetNeighbors().Any((Tile neighbor) => neighbor.SisterData(biomes) != Biome.Mountain) && !tile.GetNeighbors().Any((Tile neighbor) => neighbor.Data > tile.Data - config.mountainPeaks.minHeightDiff) && visited.Add(tile)) { Vector2 vector = HeightGradient(tile); float radius = Mathf.Lerp(config.mountainPeaks.minSize, config.mountainPeaks.maxSize, noiseField2.Sample(tile.Center)); result.Add(new Plateau { p1 = tile.Center, p2 = tile.Center, height = tile.Data, radius = radius, incline = Clamp(vector, config.mountainPeaks.gradientClamping), bulge = ((Vector2)(ref vector)).normalized * config.mountainPeaks.bulgeMultiplier }); } } } private void AddMountainLedges(List result, HashSet> visited) { } private void AddSeasideCliffs(List result, HashSet> visited) { //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_019c: Unknown result type (might be due to invalid IL or missing references) //IL_01a3: Unknown result type (might be due to invalid IL or missing references) //IL_01a8: Unknown result type (might be due to invalid IL or missing references) //IL_01ad: 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) //IL_01ee: Unknown result type (might be due to invalid IL or missing references) //IL_0200: Unknown result type (might be due to invalid IL or missing references) //IL_0205: Unknown result type (might be due to invalid IL or missing references) //IL_0266: Unknown result type (might be due to invalid IL or missing references) //IL_026d: Unknown result type (might be due to invalid IL or missing references) //IL_0272: Unknown result type (might be due to invalid IL or missing references) //IL_0283: Unknown result type (might be due to invalid IL or missing references) //IL_0294: Unknown result type (might be due to invalid IL or missing references) //IL_0299: Unknown result type (might be due to invalid IL or missing references) //IL_02aa: Unknown result type (might be due to invalid IL or missing references) //IL_02be: Unknown result type (might be due to invalid IL or missing references) //IL_02c3: Unknown result type (might be due to invalid IL or missing references) //IL_02c8: Unknown result type (might be due to invalid IL or missing references) //IL_02cd: Unknown result type (might be due to invalid IL or missing references) //IL_033c: Unknown result type (might be due to invalid IL or missing references) //IL_0341: Unknown result type (might be due to invalid IL or missing references) //IL_034a: Unknown result type (might be due to invalid IL or missing references) //IL_034f: Unknown result type (might be due to invalid IL or missing references) //IL_0368: Unknown result type (might be due to invalid IL or missing references) //IL_036a: Unknown result type (might be due to invalid IL or missing references) //IL_0372: Unknown result type (might be due to invalid IL or missing references) //IL_03a2: Unknown result type (might be due to invalid IL or missing references) //IL_03d6: Unknown result type (might be due to invalid IL or missing references) //IL_03db: Unknown result type (might be due to invalid IL or missing references) //IL_02f9: Unknown result type (might be due to invalid IL or missing references) //IL_02fb: Unknown result type (might be due to invalid IL or missing references) //IL_0301: Unknown result type (might be due to invalid IL or missing references) //IL_030e: Unknown result type (might be due to invalid IL or missing references) //IL_0323: Unknown result type (might be due to invalid IL or missing references) //IL_0328: Unknown result type (might be due to invalid IL or missing references) //IL_032d: Unknown result type (might be due to invalid IL or missing references) NoiseField noiseField = random.BiasedMetricNoise2D("Plateau/SpawnRate/SeasideCliffs", config.spawnNoiseScale); NoiseField noiseField2 = random.BiasedNoise2D("Plateau/Size"); NoiseField noiseField3 = random.BiasedNoise2D("PlateauBulgeRandomX"); NoiseField noiseField4 = random.BiasedNoise2D("PlateauBulgeRandomY"); HashSet> hashSet = new HashSet>(); List<(Tile, Tile)> list = new List<(Tile, Tile)>(); foreach (Tile tile2 in heights.Tiles) { if (tile2.Data < config.seasideCliffs.minHeight || noiseField.Sample(tile2.Center) > config.seasideCliffs.spawnRate || tile2.GetNeighbors().All((Tile neighbor) => neighbor.Data >= 0f) || !visited.Add(tile2)) { continue; } hashSet.Add(tile2); foreach (Tile neighbor in tile2.GetNeighbors()) { if (hashSet.Contains(neighbor)) { list.Add((tile2, neighbor)); } } } foreach (var item3 in list) { Tile item = item3.Item1; Tile item2 = item3.Item2; Vector2 val = 0.5f * (item.Center + item2.Center); float num = 0.5f * (item.Data + item2.Data); float radius = Mathf.Lerp(config.seasideCliffs.minSize, config.seasideCliffs.maxSize, noiseField2.Sample(val)); Vector2 val2 = HeightGradient(item, item2); List> list2 = item.GetNeighbors().Intersect(item2.GetNeighbors()).ToList(); if (list2.Count != 2) { continue; } int num2 = list2.Count((Tile neighbor) => neighbor.Data >= 0f); if (num2 != 0) { if (num2 != 1) { continue; } Tile tile = list2.First((Tile neighbor) => neighbor.Data >= 0f); val2 += Clamp(HeightGradient(val, num, tile.Center, tile.Data), config.seasideCliffs.gradientClamping); } else { float num3 = Mathf.Sign(Vector2.Dot(Normal(item.Center, item2.Center), list2[1].Center - list2[0].Center)); val2 += num3 * HeightGradient(list2[0], list2[1]); } result.Add(new Plateau { p1 = item.Center, p2 = item2.Center, height = num, radius = radius, incline = val2, bulge = new Rfloat2(Rmath.Lerp(noiseField3.Sample(val), config.seasideCliffs.minBulge, config.seasideCliffs.maxBulge), Rmath.Lerp(noiseField4.Sample(val), config.seasideCliffs.minBulge, config.seasideCliffs.maxBulge)) }); } } private void AddHills(List result, HashSet> visited) { //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_011b: Unknown result type (might be due to invalid IL or missing references) //IL_0130: 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_0139: Unknown result type (might be due to invalid IL or missing references) //IL_0146: Unknown result type (might be due to invalid IL or missing references) //IL_0150: Unknown result type (might be due to invalid IL or missing references) //IL_015a: Unknown result type (might be due to invalid IL or missing references) //IL_016f: Unknown result type (might be due to invalid IL or missing references) //IL_0174: Unknown result type (might be due to invalid IL or missing references) //IL_0188: Unknown result type (might be due to invalid IL or missing references) //IL_018d: Unknown result type (might be due to invalid IL or missing references) //IL_018f: Unknown result type (might be due to invalid IL or missing references) //IL_0194: Unknown result type (might be due to invalid IL or missing references) //IL_01a2: Unknown result type (might be due to invalid IL or missing references) //IL_01a7: Unknown result type (might be due to invalid IL or missing references) //IL_01a9: Unknown result type (might be due to invalid IL or missing references) //IL_01ae: Unknown result type (might be due to invalid IL or missing references) //IL_01f1: Unknown result type (might be due to invalid IL or missing references) //IL_0207: Unknown result type (might be due to invalid IL or missing references) //IL_0209: Unknown result type (might be due to invalid IL or missing references) //IL_0212: Unknown result type (might be due to invalid IL or missing references) //IL_0227: Unknown result type (might be due to invalid IL or missing references) //IL_022c: Unknown result type (might be due to invalid IL or missing references) NoiseField noiseField = random.BiasedMetricNoise2D("Plateau/SpawnRate/Hills", config.spawnNoiseScale); NoiseField noiseField2 = random.BiasedNoise2D("Plateau/Size"); NoiseField noiseField3 = random.Noise2D("Plateau/Length"); HashSet hashSet = new HashSet { Biome.Meadows, Biome.BlackForest, Biome.Plains }; foreach (Tile tile in heights.Tiles) { if (hashSet.Contains(tile.SisterData(biomes)) && !(noiseField.Sample(tile.Center) > config.hills.spawnRate) && !tile.GetNeighbors().Any((Tile neighbor) => neighbor.Data > tile.Data - config.hills.minHeightDiff) && visited.Add(tile)) { Vector2 incline = Clamp(HeightGradient(tile), config.hills.gradientClamping); Vector2 val = ((Vector2)(ref incline)).normalized * noiseField3.Sample(tile.Center) * 0.5f * config.hills.maxLength; result.Add(new Plateau { p1 = tile.Center + val, p2 = tile.Center - val, height = tile.Data, radius = Mathf.Lerp(config.hills.minSize, config.hills.maxSize, noiseField2.Sample(tile.Center)), incline = incline, bulge = ((Vector2)(ref incline)).normalized * config.hills.bulgeMultiplier }); } } } private void AddSwampDitches(List result, HashSet> allVisited) { //IL_011a: Unknown result type (might be due to invalid IL or missing references) //IL_011f: Unknown result type (might be due to invalid IL or missing references) //IL_0128: Unknown result type (might be due to invalid IL or missing references) //IL_012d: Unknown result type (might be due to invalid IL or missing references) HashSet> hashSet = new HashSet>(); Queue> queue = new Queue>(); foreach (Tile tile in heights.Tiles) { if (tile.SisterData(biomes) != Biome.Swamp || hashSet.Contains(tile)) { continue; } HashSet> hashSet2 = new HashSet>(); hashSet.Add(tile); queue.Enqueue(tile); while (queue.Count > 0) { Tile item = queue.Dequeue(); hashSet2.Add(item); foreach (Tile neighbor in item.GetNeighbors()) { if (!hashSet.Contains(neighbor) && neighbor.SisterData(biomes) == Biome.Swamp) { hashSet.Add(neighbor); queue.Enqueue(neighbor); } } } if (hashSet2.Count > config.swampDitchTileCount) { continue; } foreach (Tile item2 in hashSet2) { if (allVisited.Add(item2)) { result.Add(new Plateau { p1 = item2.Center, p2 = item2.Center, height = config.swampDitchHeight, radius = item2.Tiling.Spacing / 2f, inverse = true }); } } } } private static Vector2 Normal(Vector2 v1, Vector2 v2) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) Vector2 val = v2 - v1; return new Vector2(val.y, 0f - val.x); } private static Vector2 HeightGradient(Vector2 v1, float h1, Vector2 v2, float h2) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000b: 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_0018: Unknown result type (might be due to invalid IL or missing references) Vector2 val = v2 - v1; return (h2 - h1) * val / ((Vector2)(ref val)).sqrMagnitude; } private static Vector2 HeightGradient(Tile t1, Tile t2) { //IL_0002: 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) //IL_001e: Unknown result type (might be due to invalid IL or missing references) return HeightGradient(t1.Center, t1.Data, t2.Center, t2.Data); } private static Vector2 HeightGradient(Tile tile) { //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_001c: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0024: 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) //IL_003e: Unknown result type (might be due to invalid IL or missing references) Vector2 val = Vector2.zero; foreach (Tile neighbor in tile.GetNeighbors()) { val += HeightGradient(tile, neighbor); } return val; } private static Vector2 Clamp(Vector2 vector, ClampingConfig config) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) float magnitude = ((Vector2)(ref vector)).magnitude; if (magnitude < 1E-05f) { return config.min * Vector2.left; } float num = config.max - config.min; return (float)(config.mode switch { ClampingConfig.Mode.Linear => Rmath.Clamp(magnitude, config.min, config.max), ClampingConfig.Mode.Asymptotic => (double)config.min + (double)num * Rmath.Sigmoid(magnitude * config.rate / num), _ => throw new ArgumentOutOfRangeException(), }) / magnitude * vector; } } public struct RiverValleyMap { public ITiling proximity; public ITiling heights; } [Producer(typeof(RiverValleyMap))] [ConfiguredBy(typeof(Config))] [Consumer(typeof(ITiling))] [Consumer(typeof(RiverState))] public class RiverValleyComponent { [Serializable] public struct Config { public float offset; public float magnitude; public float exponent; public float profileSteepness; public float profilePower; } private readonly Config config; private readonly ITiling flags; private readonly RiverState riverState; public RiverValleyComponent(Config config, ITiling flags, RiverState riverState) { this.config = config; this.flags = flags; this.riverState = riverState; } public RiverValleyMap Compute() { ITiling tiling = riverState.basinTiling.CreateDistanceField((Tile tile) => config.magnitude * Mathf.Pow(tile.Data.Discharge, 0f - config.exponent) + config.offset, (Tile tile) => tile.SisterData(flags).IsLand).CreateSisterTiling((float distance) => Math.Max(0f, distance)); RiverValleyMap result = default(RiverValleyMap); result.proximity = tiling; result.heights = tiling.CreateSisterTiling(RiverProfile); return result; } private float RiverProfile(float distance) { return HeightUtility.ValleyProfile(distance, config.profileSteepness, config.profilePower); } } } namespace Riverheim.World.Biomes { public enum Biome : short { None, Meadows, Swamp, Mountain, BlackForest, Plains, AshLands, DeepNorth, Ocean, Mistlands } [Serializable] public struct BiomeConfig { public float NoiseScale; public float FixedBias; public StaticArray TravelDistanceBias; public StaticArray CoastalDistanceBias; public StaticArray RiverDistanceBias; public StaticArray HeightBias; public StaticArray RoughnessBias; } [Serializable] public struct BiomeCalculationConfig { public float NoiseBiasContribution; public float NoiseModulationRatio; public float NoiseModulationIntensity; public float OceanDepth; public float MountainHeightWiggle; public BiomeConfig Meadows; public BiomeConfig BlackForest; public BiomeConfig Swamp; public BiomeConfig Plains; public BiomeConfig Mistlands; } [Producer(typeof(ITiling))] [Randomized("BiomeCalculator")] [ConfiguredBy(typeof(CommonConfig))] [ConfiguredBy(typeof(BiomeCalculationConfig))] [Consumer(typeof(HeightMap))] [Consumer(typeof(ITiling))] [Consumer(typeof(TravelDistanceMap))] [Consumer(typeof(CoastalProximityMap))] [Consumer(typeof(RiverProximityMap))] [Consumer(typeof(RoughnessMap))] public class BiomeCalculator { private struct BiomeBiases { public float Fixed; public PiecewiseCurve TravelDistance; public PiecewiseCurve CoastalDistance; public PiecewiseCurve RiverDistance; public PiecewiseCurve Height; public PiecewiseCurve Roughness; } private readonly RandomEngine random; private readonly CommonConfig commonConfig; private readonly BiomeCalculationConfig config; private readonly ITiling heights; private readonly ITiling flags; private readonly TravelDistanceMap travelDistance; private readonly CoastalProximityMap coastalProximity; private readonly RiverProximityMap riverProximity; private readonly RoughnessMap roughness; public BiomeCalculator(RandomEngine random, CommonConfig commonConfig, BiomeCalculationConfig config, HeightMap heights, ITiling flags, TravelDistanceMap travelDistance, CoastalProximityMap coastalProximity, RiverProximityMap riverProximity, RoughnessMap roughness) { this.random = random; this.commonConfig = commonConfig; this.config = config; this.heights = heights.Data; this.flags = flags; this.travelDistance = travelDistance; this.coastalProximity = coastalProximity; this.riverProximity = riverProximity; this.roughness = roughness; } public ITiling Compute() { Dictionary biomeNoises = new Dictionary(); foreach (Biome value in Enum.GetValues(typeof(Biome))) { NoiseField noiseField = CreateNoiseField(value); if (noiseField != null) { biomeNoises[value] = noiseField; } } Dictionary biomeBiases = new Dictionary(); foreach (Biome value2 in Enum.GetValues(typeof(Biome))) { BiomeConfig? biomeConfig = BiomeConfig(value2); if (biomeConfig.HasValue) { BiomeConfig valueOrDefault = biomeConfig.GetValueOrDefault(); biomeBiases[value2] = new BiomeBiases { Fixed = valueOrDefault.FixedBias, TravelDistance = new PiecewiseCurve(valueOrDefault.TravelDistanceBias), CoastalDistance = new PiecewiseCurve(valueOrDefault.CoastalDistanceBias), RiverDistance = new PiecewiseCurve(valueOrDefault.RiverDistanceBias), Height = new PiecewiseCurve(valueOrDefault.HeightBias), Roughness = new PiecewiseCurve(valueOrDefault.RoughnessBias) }; } } return flags.CreateSisterTiling((Tile tile) => CalculateBiome(heights.GetTile(tile.Id), travelDistance(tile), tile.Data, roughness(tile).absolute, coastalProximity(tile), riverProximity(tile), biomeNoises, biomeBiases)); } private NoiseField CreateNoiseField(Biome biome) { float? num = BiomeConfig(biome)?.NoiseScale; if (num.HasValue) { float valueOrDefault = num.GetValueOrDefault(); NoiseField noiseField = random.BiasedMetricNoise2D("BiomeNoise_" + biome, valueOrDefault); noiseField *= 1f + 2f * config.NoiseModulationIntensity * (noiseField.Modulate(config.NoiseModulationRatio) - 0.5f); return noiseField.Normalize01(); } return null; } private Biome CalculateBiome(Tile tile, float distance, TileFlags flags, float roughness, float coastalDistance, float riverDistance, Dictionary biomeNoises, Dictionary biomeBiases) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0169: Unknown result type (might be due to invalid IL or missing references) float data = tile.Data; if (flags.IsSouthPolar) { return Biome.AshLands; } Vector2 center = tile.Center; if (((Vector2)(ref center)).magnitude > commonConfig.WorldSize) { return Biome.Ocean; } if (data <= config.OceanDepth && !flags.IsLand && tile.GetNeighbors().Max((Tile t) => t.Data) < 0f) { return Biome.Ocean; } if (data >= commonConfig.MountainHeight) { float num = commonConfig.MountainHeight; foreach (Tile neighbor in tile.GetNeighbors()) { num = Mathf.Min(num, neighbor.Data); } if (num > commonConfig.MountainHeight - config.MountainHeightWiggle) { return Biome.Mountain; } } if (flags.IsNorthPolar) { return Biome.DeepNorth; } Dictionary dictionary = new Dictionary(); foreach (Biome value in Enum.GetValues(typeof(Biome))) { float? num2 = Bias(biomeBiases, value, data, distance, coastalDistance, riverDistance, roughness); if (num2.HasValue) { float valueOrDefault = num2.GetValueOrDefault(); dictionary[value] = config.NoiseBiasContribution * biomeNoises[value].Sample(tile.Center) + valueOrDefault; } } KeyValuePair keyValuePair = new KeyValuePair(Biome.Ocean, float.MinValue); foreach (KeyValuePair item in dictionary) { if (item.Value > keyValuePair.Value) { keyValuePair = item; } } return keyValuePair.Key; } private BiomeConfig? BiomeConfig(Biome biome) { return biome switch { Biome.Meadows => config.Meadows, Biome.BlackForest => config.BlackForest, Biome.Swamp => config.Swamp, Biome.Plains => config.Plains, Biome.Mistlands => config.Mistlands, _ => null, }; } private float? Bias(Dictionary biomeBiases, Biome biome, float height, float travelDistance, float coastalDistance, float riverDistance, float roughness) { if (!biomeBiases.TryGetValue(biome, out var value)) { return null; } return (float)(0.0 + (double)value.Fixed + value.TravelDistance.Eval(travelDistance) + value.CoastalDistance.Eval(coastalDistance) + value.RiverDistance.Eval(riverDistance) + value.Height.Eval(height) + value.Roughness.Eval(roughness)); } } public struct BiomePostprocessedHeightMap { public ITiling Data; } [Serializable] public struct BiomePostprocessingConfig { public float mountainHeightMinMultiplier; public float mountainHeightMaxMultiplier; public float mountainHeightNoiseScale; public float swampBaseHeight; public float plateauBumpHeight; public float plateauAmount; public float plateauNoiseScale; public float plateauMinProximity; public bool plainSmoothOverWater; public float plainSmoothingRange; } [Producer(typeof(BiomePostprocessedHeightMap))] [Randomized("BiomeHeightPostprocessor")] [ConfiguredBy(typeof(CommonConfig))] [ConfiguredBy(typeof(BiomePostprocessingConfig))] [Consumer(typeof(HeightMap))] [Consumer(typeof(ITiling))] public class BiomeHeightPostprocessor { private readonly RandomEngine random; private readonly CommonConfig commonConfig; private readonly BiomePostprocessingConfig config; private readonly ITiling baseHeights; private readonly ITiling biomes; private readonly NoiseField heightNoise; public BiomeHeightPostprocessor(RandomEngine random, CommonConfig commonConfig, BiomePostprocessingConfig config, HeightMap baseHeights, ITiling biomes) { this.random = random; this.commonConfig = commonConfig; this.config = config; this.baseHeights = baseHeights.Data; this.biomes = biomes; heightNoise = random.BiasedMetricNoise2D("MountainHeightMultiplier", config.mountainHeightNoiseScale); } public BiomePostprocessedHeightMap Compute() { ITiling tiling = baseHeights.CreateSisterTiling((Tile tile) => GetAdjustedHeight(tile.Data, tile.Center, tile.SisterData(biomes))); AdjustMountains(tiling); SmoothPlains(tiling); BiomePostprocessedHeightMap result = default(BiomePostprocessedHeightMap); result.Data = tiling; return result; } private float GetAdjustedHeight(float height, Vector2 pos, Biome biome) { //IL_004d: Unknown result type (might be due to invalid IL or missing references) switch (biome) { case Biome.Mountain: { float num2 = Mathf.Lerp(config.mountainHeightMinMultiplier, config.mountainHeightMaxMultiplier, heightNoise.Sample(pos)); return commonConfig.MountainHeight + num2 * (height - commonConfig.MountainHeight); } case Biome.Meadows: case Biome.Plains: { float num = Mathf.Clamp01(height / commonConfig.MountainHeight); if (height > 0f) { height -= 0.75f * height * (1f - num); } return height; } case Biome.Swamp: return Mathf.Lerp(height, config.swampBaseHeight, Mathf.InverseLerp(-15f, -2f, height)); default: return height; } } private void AdjustMountains(ITiling heights) { List> plateauPeaks = GetPlateauPeaks(heights); Queue> queue = new Queue>(); foreach (Tile item in plateauPeaks) { float num = item.SisterData(heights); HashSet> hashSet = new HashSet> { item }; queue.Enqueue(item); while (queue.Count > 0) { foreach (Tile neighbor in queue.Dequeue().GetNeighbors()) { if (neighbor.Data == item.Data && hashSet.Add(neighbor)) { float num2 = neighbor.SisterData(heights); float num3 = Mathf.InverseLerp(commonConfig.MountainHeight, num, num2); float num4 = (float)Rmath.Bump(2f * num3 - 1f); neighbor.SisterData(heights) = num2 + num4 * 0.5f * config.plateauBumpHeight * (num - commonConfig.MountainHeight); queue.Enqueue(neighbor); } } } } } private List> GetPlateauPeaks(ITiling heights) { ITiling proximity = biomes.CreateDistanceField(delegate(Tile tile) { foreach (Tile neighbor in tile.GetNeighbors()) { if (neighbor.Data != Biome.Mountain) { return 0f; } } return null; }, (Tile tile) => tile.Data == Biome.Mountain); NoiseField noise = random.BiasedMetricNoise2D("MountainPlateaus", config.plateauNoiseScale); List> list = new List>(); Queue> queue = new Queue>(); foreach (Tile tile3 in biomes.CreateSisterTiling((Tile _) => -1).Tiles) { if (!canBePlateau(tile3)) { continue; } int count = list.Count; tile3.Data = count; queue.Enqueue(tile3); Tile item = tile3; while (queue.Count > 0) { Tile tile2 = queue.Dequeue(); if (tile2.SisterData(heights) > item.SisterData(heights)) { item = tile2; } foreach (Tile neighbor2 in tile2.GetNeighbors()) { if (canBePlateau(neighbor2)) { neighbor2.Data = count; queue.Enqueue(neighbor2); } } } list.Add(item); } return list; bool canBePlateau(Tile tile) { //IL_0028: Unknown result type (might be due to invalid IL or missing references) if (tile.Data >= 0) { return false; } if (tile.SisterData(biomes) != Biome.Mountain) { return false; } if (noise.Sample(tile.Center) > config.plateauAmount) { return false; } if (tile.SisterData(proximity) >= config.plateauMinProximity) { return true; } foreach (Tile neighbor3 in tile.GetNeighbors()) { if (neighbor3.SisterData(biomes) == Biome.Mountain && neighbor3.SisterData(proximity) >= config.plateauMinProximity) { return true; } } return false; } } private bool IsSmoothablePlainsTile(Tile tile) { if (tile.SisterData(biomes) != Biome.Plains) { return false; } if (tile.Data <= 0f && !config.plainSmoothOverWater) { return false; } return true; } private void SmoothPlains(ITiling heights) { //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) foreach (Tile tile in heights.Copy().Tiles) { if (!IsSmoothablePlainsTile(tile)) { continue; } float num = tile.Data; float num2 = 1f; foreach (Tile item in tile.Scan(config.plainSmoothingRange)) { if (IsSmoothablePlainsTile(item)) { Vector2 val = (tile.Center - item.Center) / config.plainSmoothingRange; float num3 = Gauss2(((Vector2)(ref val)).sqrMagnitude); num += item.Data * num3; num2 += num3; } } tile.SisterData(heights) = num / num2; } } private static float Gauss2(float x2) { return Mathf.Exp(-4.5f * x2); } } public struct Roughness { public float absolute; public Vector2 gradient; } public delegate Roughness RoughnessMap(Tile flags); [Producer(typeof(RoughnessMap))] [Consumer(typeof(HeightMap))] public class RoughnessComponent { private readonly HeightMap heights; public RoughnessComponent(HeightMap heights) { this.heights = heights; } public RoughnessMap Compute() { //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Unknown result type (might be due to invalid IL or missing references) //IL_010b: Unknown result type (might be due to invalid IL or missing references) ITiling result = heights.Data.CreateSisterTiling(); foreach (Tile tile in heights.Data.Tiles) { ref Roughness reference = ref tile.SisterData(result); reference.absolute = 0f; reference.gradient = Vector2.zero; float num = 0f; foreach (Tile neighbor in tile.GetNeighbors()) { Vector2 val = neighbor.Center - tile.Center; float num2 = ((Vector2)(ref val)).SqrMagnitude(); Vector2 val2 = (neighbor.Data - tile.Data) / num2 * val; float num3 = result.Spacing * result.Spacing / num2; reference.absolute += ((Vector2)(ref val2)).magnitude * num3; ref Vector2 gradient = ref reference.gradient; gradient += val2 * num3; num += num3; } if (num != 0f) { reference.absolute /= num; } } return (Tile tile) => tile.SisterData(result); } } } namespace Riverheim.Util { public struct BoundingBox { public double x; public double y; public double w; public double h; public Rfloat2 pos { get { return new Rfloat2(x, y); } set { double num = value.x; double num2 = value.y; x = num; y = num2; } } public Rfloat2 size { get { return new Rfloat2(w, h); } set { double num = value.x; double num2 = value.y; w = num; h = num2; } } public Rfloat2 center { get { return new Rfloat2(x + w / 2.0, y + h / 2.0); } set { x = value.x - w / 2.0; y = value.y - h / 2.0; } } public BoundingBox(Rfloat2 pos, Rfloat2 size) { x = pos.x; y = pos.y; w = size.x; h = size.y; } public BoundingBox(IEnumerable points) { double num = double.MaxValue; double num2 = double.MaxValue; double num3 = double.MinValue; double num4 = double.MinValue; foreach (Rfloat2 point in points) { num = Math.Min(point.x, num); num2 = Math.Min(point.y, num2); num3 = Math.Max(point.x, num3); num4 = Math.Max(point.y, num4); } x = num; y = num2; w = num3 - num; h = num4 - num2; } public static BoundingBox ZeroCentered(Rfloat2 size) { return new BoundingBox(-0.5 * size, size); } public bool Contains(Rfloat2 point) { if (point.x >= x && point.x <= x + w && point.y >= y) { return point.y <= y + h; } return false; } public bool Overlaps(BoundingBox other) { if (other.x + other.w > x && other.x < x + w && other.y + other.h > y) { return other.y < y + h; } return false; } public override string ToString() { return $"BoundingBox({pos}, {size})"; } } public struct Direction : IEquatable { private float AngleValue; public float Angle { get { return AngleValue; } set { AngleValue = Clamped(value); } } private static float Clamped(float angle) { return angle - (float)Math.PI * 2f * Mathf.Floor(0.5f * (1f + angle / (float)Math.PI)); } public Direction(float angle) { AngleValue = Clamped(angle); } public Direction(Vector2 v) { //IL_0006: 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) AngleValue = Clamped((float)Math.PI / 180f * Vector2.SignedAngle(v, Vector2.up)); } public static Direction Average(Direction lhs, Direction rhs) { return new Direction((lhs.Angle + rhs.Angle) / 2f); } public static float operator -(Direction lhs, Direction rhs) { return Clamped(lhs.Angle - rhs.Angle); } public static Direction operator ~(Direction d) { return new Direction(d.AngleValue + (float)Math.PI); } public bool Equals(Direction other) { return Mathf.Approximately(AngleValue, other.AngleValue); } public override bool Equals(object obj) { if (obj is Direction other) { return Equals(other); } return false; } public static bool operator ==(Direction d1, Direction d2) { return d1.Equals(d2); } public static bool operator !=(Direction d1, Direction d2) { return !(d1 == d2); } public override int GetHashCode() { return AngleValue.GetHashCode(); } } public static class SmoothMin { [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Quadratic(double a, double b, double k) { double num = k * 4.0; double num2 = Math.Max(0.0, num - Math.Abs(a - b)) / num; return Math.Min(a, b) - num2 * num2 * k; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Cubic(double a, double b, double k) { double num = k * 6.0; double num2 = Math.Max(0.0, num - Math.Abs(a - b)) / num; return Math.Min(a, b) - num2 * num2 * num2 * k; } } public static class SmoothMax { [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Quadratic(double a, double b, double k) { double num = k * 4.0; double num2 = Math.Max(0.0, num - Math.Abs(a - b)) / num; return Math.Max(a, b) + num2 * num2 * k; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Cubic(double a, double b, double k) { double num = k * 6.0; double num2 = Math.Max(0.0, num - Math.Abs(a - b)) / num; return Math.Max(a, b) + num2 * num2 * num2 * k; } } public class BicubicInterpolator { private static readonly Matrix4x4 CatmullRom = new Matrix4x4(0f, 1f, 0f, 0f, -0.5f, 0f, 0.5f, 0f, 1f, -2.5f, 2f, -0.5f, -0.5f, 1.5f, -1.5f, 0.5f); private readonly Rint2 Size; private readonly Rfloat2 Scale; private readonly float[,] Data; [MethodImpl(MethodImplOptions.AggressiveInlining)] private static float Interpolate(Vector2 t, in Matrix4x4 F) { Vector4 vector = new Vector4(1f, t.X, t.X * t.X, t.X * t.X * t.X); Vector4 vector2 = new Vector4(1f, t.Y, t.Y * t.Y, t.Y * t.Y * t.Y); Vector4 vector3 = Vector4.Transform(vector, CatmullRom); Vector4 vector4 = Vector4.Transform(vector2, CatmullRom); return Vector4.Dot(vector3, Vector4.Transform(vector4, F)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] private static (float, Vector2) InterpolateWithGradient(Vector2 t, in Matrix4x4 F) { Vector4 vector = new Vector4(1f, t.X, t.X * t.X, t.X * t.X * t.X); Vector4 vector2 = new Vector4(1f, t.Y, t.Y * t.Y, t.Y * t.Y * t.Y); Vector4 vector3 = new Vector4(0f, 1f, 2f * t.X, 3f * t.X * t.X); Vector4 vector4 = new Vector4(0f, 1f, 2f * t.Y, 3f * t.Y * t.Y); Vector4 vector5 = Vector4.Transform(vector, CatmullRom); Vector4 vector6 = Vector4.Transform(vector2, CatmullRom); Vector4 vector7 = Vector4.Transform(vector3, CatmullRom); Vector4 vector8 = Vector4.Transform(vector4, CatmullRom); Vector4 vector9 = Vector4.Transform(vector6, F); Vector4 vector10 = Vector4.Transform(vector8, F); return (Vector4.Dot(vector5, vector9), new Vector2(Vector4.Dot(vector7, vector9), Vector4.Dot(vector5, vector10))); } public BicubicInterpolator(Rfloat2 range, Rfloat2 resolution, Func signal) { Size = (range / resolution).CeilToInt() + Rint2.One; Scale = new Rfloat2(1.0 / resolution.x, 1.0 / resolution.y); Data = new float[2 * Size.x + 1, 2 * Size.y + 1]; for (int i = 0; i < Data.GetLength(0); i++) { for (int j = 0; j < Data.GetLength(1); j++) { Data[i, j] = (float)signal(resolution * (new Rfloat2(i, j) - Size)); } } } [MethodImpl(MethodImplOptions.AggressiveOptimization)] public double Interpolate(Rfloat2 pos, double defaultValue = 0.0) { Rint2 rint = (pos * Scale).FloorToInt(); Rfloat2 rfloat = pos * Scale - rint; rint += Size - Rint2.One; int x = rint.x; int y = rint.y; if (x < 0 || x >= 2 * Size.x - 2) { return defaultValue; } if (y < 0 || y >= 2 * Size.y - 2) { return defaultValue; } Vector2 t = rfloat; Matrix4x4 F = new Matrix4x4(Data[x, y], Data[x + 1, y], Data[x + 2, y], Data[x + 3, y], Data[x, y + 1], Data[x + 1, y + 1], Data[x + 2, y + 1], Data[x + 3, y + 1], Data[x, y + 2], Data[x + 1, y + 2], Data[x + 2, y + 2], Data[x + 3, y + 2], Data[x, y + 3], Data[x + 1, y + 3], Data[x + 2, y + 3], Data[x + 3, y + 3]); return Interpolate(t, in F); } [MethodImpl(MethodImplOptions.AggressiveOptimization)] public double Interpolate(Rfloat2 pos, out Rfloat2 gradient, double defaultValue = 0.0) { gradient = Rfloat2.Zero; Rint2 rint = (pos * Scale).FloorToInt(); Rfloat2 rfloat = pos * Scale - rint; rint += Size - Rint2.One; int x = rint.x; int y = rint.y; if (x < 0 || x >= 2 * Size.x - 2) { return defaultValue; } if (y < 0 || y >= 2 * Size.y - 2) { return defaultValue; } Vector2 t = rfloat; Matrix4x4 F = new Matrix4x4(Data[x, y], Data[x + 1, y], Data[x + 2, y], Data[x + 3, y], Data[x, y + 1], Data[x + 1, y + 1], Data[x + 2, y + 1], Data[x + 3, y + 1], Data[x, y + 2], Data[x + 1, y + 2], Data[x + 2, y + 2], Data[x + 3, y + 2], Data[x, y + 3], Data[x + 1, y + 3], Data[x + 2, y + 3], Data[x + 3, y + 3]); (float, Vector2) tuple = InterpolateWithGradient(t, in F); float item = tuple.Item1; Vector2 item2 = tuple.Item2; gradient = (Rfloat2)item2 * Scale; return item; } } public class IdwInterpolator { private readonly double Pow; private readonly double MaxRadius; private readonly int MaxHops; private readonly ITiling Tiling; private readonly Func GetValue; public IdwInterpolator(ITiling tiling, double pow, double maxRadius, int maxHops, Func valueMap) { Tiling = tiling; Pow = pow; MaxRadius = maxRadius; MaxHops = maxHops; GetValue = valueMap; } public double Interpolate(Rfloat2 pos, double defaultValue = 0.0) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) Tile? tile = Tiling.GetTile((Vector2)pos); if (tile.HasValue) { Tile valueOrDefault = tile.GetValueOrDefault(); if (valueOrDefault.Center == pos) { return GetValue(valueOrDefault.Data); } double num = (double)Tiling.Spacing * MaxRadius; double num2 = num * num; double num3 = Math.Pow((valueOrDefault.Center - pos).SqrLength, -0.5 * Pow); double num4 = GetValue(valueOrDefault.Data) * num3; foreach (Tile neighbor in valueOrDefault.GetNeighbors(MaxHops)) { double sqrLength = (neighbor.Center - pos).SqrLength; if (!(sqrLength > num2)) { double num5 = Math.Pow(sqrLength, -0.5 * Pow); num3 += num5; num4 += GetValue(neighbor.Data) * num5; } } return num4 / num3; } return defaultValue; } } public class IdwInterpolator : IdwInterpolator { public IdwInterpolator(ITiling tiling, double pow, double maxRadius, int maxHops) : base(tiling, pow, maxRadius, maxHops, (Func)((float v) => v)) { } } public readonly struct PiecewiseCurve { private readonly Rfloat2[] points; public PiecewiseCurve(IEnumerable points) { this.points = points.ToArray(); for (int i = 0; i < this.points.Length - 1; i++) { if (this.points[i].x > this.points[i + 1].x) { throw new ArgumentException(); } } } public double Eval(double x) { if (points.Length == 0) { return 0.0; } if (x <= points[0].x) { return points[0].y; } for (int i = 1; i < points.Length; i++) { if (!(x > points[i].x)) { Rfloat2 rfloat = points[i]; Rfloat2 rfloat2 = points[i - 1]; return Rmath.Lerp(Rmath.InverseLerp(x, rfloat2.x, rfloat.x), rfloat2.y, rfloat.y); } } return points[points.Length - 1].y; } } public interface IGeometry { BoundingBox Bbox { get; } bool HitTest(Rfloat2 point); bool HitTest(BoundingBox rect); } public readonly struct Circle : IGeometry { public readonly Rfloat2 Center; public readonly double Radius; public BoundingBox Bbox => new BoundingBox(Center - Radius, 2.0 * Radius * Rfloat2.One); public Circle(Rfloat2 center, double radius) { Center = center; Radius = radius; } public bool HitTest(Rfloat2 point) { return (Center - point).SqrLength <= Radius * Radius; } public bool HitTest(BoundingBox rect) { Rfloat2 rfloat = Center - rect.center; if (Math.Abs(rfloat.x) < Radius + 0.5 * rect.w) { return Math.Abs(rfloat.y) < Radius + 0.5 * rect.h; } return false; } } public class SpatialHashGrid { [CompilerGenerated] private sealed class d__4 : IEnumerable, IEnumerable, IEnumerator, IDisposable, IEnumerator { private int <>1__state; private IGeometry <>2__current; private int <>l__initialThreadId; public SpatialHashGrid <>4__this; private Rfloat2 pos; public Rfloat2 <>3__pos; private bool exact; public bool <>3__exact; private List.Enumerator <>7__wrap1; IGeometry IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__4(int <>1__state) { this.<>1__state = <>1__state; <>l__initialThreadId = Environment.CurrentManagedThreadId; } [DebuggerHidden] void IDisposable.Dispose() { int num = <>1__state; if (num == -3 || num == 1) { try { } finally { <>m__Finally1(); } } <>7__wrap1 = default(List.Enumerator); <>1__state = -2; } private bool MoveNext() { try { int num = <>1__state; SpatialHashGrid spatialHashGrid = <>4__this; switch (num) { default: return false; case 0: { <>1__state = -1; (int, int) key = spatialHashGrid.Index(pos); if (!spatialHashGrid.Data.TryGetValue(key, out var value)) { return false; } <>7__wrap1 = value.GetEnumerator(); <>1__state = -3; break; } case 1: <>1__state = -3; break; } while (<>7__wrap1.MoveNext()) { IGeometry current = <>7__wrap1.Current; if (!exact || current.HitTest(pos)) { <>2__current = current; <>1__state = 1; return true; } } <>m__Finally1(); <>7__wrap1 = default(List.Enumerator); return false; } catch { //try-fault ((IDisposable)this).Dispose(); throw; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } private void <>m__Finally1() { <>1__state = -1; ((IDisposable)<>7__wrap1).Dispose(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { d__4 d__; if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; d__ = this; } else { d__ = new d__4(0) { <>4__this = <>4__this }; } d__.pos = <>3__pos; d__.exact = <>3__exact; return d__; } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)this).GetEnumerator(); } } [CompilerGenerated] private sealed class d__5 : IEnumerable, IEnumerable, IEnumerator, IDisposable, IEnumerator where T : IGeometry { private int <>1__state; private T <>2__current; private int <>l__initialThreadId; public SpatialHashGrid <>4__this; private Rfloat2 pos; public Rfloat2 <>3__pos; private bool exact; public bool <>3__exact; private IEnumerator <>7__wrap1; T IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__5(int <>1__state) { this.<>1__state = <>1__state; <>l__initialThreadId = Environment.CurrentManagedThreadId; } [DebuggerHidden] void IDisposable.Dispose() { int num = <>1__state; if (num == -3 || num == 1) { try { } finally { <>m__Finally1(); } } <>7__wrap1 = null; <>1__state = -2; } private bool MoveNext() { try { int num = <>1__state; SpatialHashGrid spatialHashGrid = <>4__this; switch (num) { default: return false; case 0: <>1__state = -1; <>7__wrap1 = spatialHashGrid.Query(pos, exact).GetEnumerator(); <>1__state = -3; break; case 1: <>1__state = -3; break; } while (<>7__wrap1.MoveNext()) { if (<>7__wrap1.Current is T val) { <>2__current = val; <>1__state = 1; return true; } } <>m__Finally1(); <>7__wrap1 = null; return false; } catch { //try-fault ((IDisposable)this).Dispose(); throw; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } private void <>m__Finally1() { <>1__state = -1; if (<>7__wrap1 != null) { <>7__wrap1.Dispose(); } } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { d__5 d__; if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; d__ = this; } else { d__ = new d__5(0) { <>4__this = <>4__this }; } d__.pos = <>3__pos; d__.exact = <>3__exact; return d__; } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)this).GetEnumerator(); } } private readonly double CellSize; private readonly Dictionary<(int, int), List> Data; public SpatialHashGrid(double cellSize) { CellSize = cellSize; Data = new Dictionary<(int, int), List>(); } public void Add(IGeometry geometry) { BoundingBox bbox = geometry.Bbox; for (int i = Index(bbox.x); i <= Index(bbox.x + bbox.w); i++) { for (int j = Index(bbox.y); j <= Index(bbox.y + bbox.h); j++) { TryAdd((i, j), geometry); } } } [IteratorStateMachine(typeof(d__4))] public IEnumerable Query(Rfloat2 pos, bool exact = false) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__4(-2) { <>4__this = this, <>3__pos = pos, <>3__exact = exact }; } [IteratorStateMachine(typeof(d__5<>))] public IEnumerable Query(Rfloat2 pos, bool exact = false) where T : IGeometry { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__5(-2) { <>4__this = this, <>3__pos = pos, <>3__exact = exact }; } private void TryAdd((int, int) index, IGeometry geometry) { if (geometry.HitTest(CellRect(index))) { if (!Data.ContainsKey(index)) { Data[index] = new List(); } Data[index].Add(geometry); } } private int Index(double x) { return Rmath.FloorToInt(x / CellSize); } private (int, int) Index(Rfloat2 pos) { return (Index(pos.x), Index(pos.y)); } private BoundingBox CellRect((int, int) index) { return new BoundingBox(CellSize * new Rfloat2(index.Item1, index.Item2), CellSize * Rfloat2.One); } } [Serializable] public struct StaticArray : IEnumerable, IEnumerable { [CompilerGenerated] private sealed class d__18 : IEnumerator, IDisposable, IEnumerator { private int <>1__state; private T <>2__current; public StaticArray <>4__this; private int 5__2; T IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__18(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { switch (<>1__state) { default: return false; case 0: <>1__state = -1; 5__2 = 0; break; case 1: <>1__state = -1; 5__2++; break; } if (5__2 < <>4__this.Count) { <>2__current = <>4__this[5__2]; <>1__state = 1; return true; } return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } public const int Capacity = 8; private int Count; private T p0; private T p1; private T p2; private T p3; private T p4; private T p5; private T p6; private T p7; public readonly int Length => Count; public T this[int index] { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { if (index < 0 || index >= Count) { throw new IndexOutOfRangeException(); } return index switch { 0 => p0, 1 => p1, 2 => p2, 3 => p3, 4 => p4, 5 => p5, 6 => p6, 7 => p7, _ => throw new IndexOutOfRangeException(), }; } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { if (index < 0 || index >= Count) { throw new IndexOutOfRangeException(); } switch (index) { case 0: p0 = value; break; case 1: p1 = value; break; case 2: p2 = value; break; case 3: p3 = value; break; case 4: p4 = value; break; case 5: p5 = value; break; case 6: p6 = value; break; case 7: p7 = value; break; default: throw new IndexOutOfRangeException(); } } } public StaticArray(T[] array) { if (array == null) { throw new ArgumentNullException(); } this = new StaticArray(array.Length); switch (array.Length) { case 8: p7 = array[7]; goto case 7; case 7: p6 = array[6]; goto case 6; case 6: p5 = array[5]; goto case 5; case 5: p4 = array[4]; goto case 4; case 4: p3 = array[3]; goto case 3; case 3: p2 = array[2]; goto case 2; case 2: p1 = array[1]; goto case 1; case 1: p0 = array[0]; break; default: throw new IndexOutOfRangeException(); case 0: break; } } public StaticArray(int count = 0) { this = default(StaticArray); if (count > 8) { throw new ArgumentOutOfRangeException("count"); } Count = count; } public readonly T[] ToArray() { T[] array = new T[Count]; switch (Count) { case 8: array[7] = p7; goto case 7; case 7: array[6] = p6; goto case 6; case 6: array[5] = p5; goto case 5; case 5: array[4] = p4; goto case 4; case 4: array[3] = p3; goto case 3; case 3: array[2] = p2; goto case 2; case 2: array[1] = p1; goto case 1; case 1: array[0] = p0; break; } return array; } [IteratorStateMachine(typeof(StaticArray<>.d__18))] public IEnumerator GetEnumerator() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__18(0) { <>4__this = this }; } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } public void Add(T value) { if (Count == 8) { throw new IndexOutOfRangeException(); } this[Count++] = value; } } } namespace Riverheim.Util.Tilings { public abstract class Grid : ITiling, ITilingKernel { [CompilerGenerated] private sealed class d__33 : IEnumerable>, IEnumerable, IEnumerator>, IDisposable, IEnumerator { private int <>1__state; private Tile <>2__current; private int <>l__initialThreadId; public Grid <>4__this; private ValueType tileId; public ValueType <>3__tileId; private int hops; public int <>3__hops; private IEnumerator> <>7__wrap1; Tile IEnumerator>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__33(int <>1__state) { this.<>1__state = <>1__state; <>l__initialThreadId = Environment.CurrentManagedThreadId; } [DebuggerHidden] void IDisposable.Dispose() { int num = <>1__state; if (num == -3 || num == 1) { try { } finally { <>m__Finally1(); } } <>7__wrap1 = null; <>1__state = -2; } private bool MoveNext() { try { int num = <>1__state; Grid grid = <>4__this; switch (num) { default: return false; case 0: <>1__state = -1; <>7__wrap1 = grid.Circle((Rint2)(object)tileId, hops).GetEnumerator(); <>1__state = -3; break; case 1: <>1__state = -3; break; } while (<>7__wrap1.MoveNext()) { Tile current = <>7__wrap1.Current; if (!object.Equals(current.Id, tileId)) { <>2__current = current; <>1__state = 1; return true; } } <>m__Finally1(); <>7__wrap1 = null; return false; } catch { //try-fault ((IDisposable)this).Dispose(); throw; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } private void <>m__Finally1() { <>1__state = -1; if (<>7__wrap1 != null) { <>7__wrap1.Dispose(); } } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator> IEnumerable>.GetEnumerator() { d__33 d__; if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; d__ = this; } else { d__ = new d__33(0) { <>4__this = <>4__this }; } d__.tileId = <>3__tileId; d__.hops = <>3__hops; return d__; } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable>)this).GetEnumerator(); } } private readonly T[,] Storage; public abstract int Count { get; } public float Area => (float)Count * GetCellArea(); public abstract float Spacing { get; } public IEnumerable> Tiles => All(); ITilingKernel ITiling.Kernel => this; public ITiling Tiling => this; public Grid(Rint2 storageSize) { Storage = new T[storageSize.x, storageSize.y]; } public abstract Grid CreateSisterGrid(Func, V> dataConv = null); public ITiling CreateSisterTiling(Func, V> tileConv = null) { return CreateSisterGrid(tileConv); } public abstract Vector2 GetCellCenter(Rint2 pos); public abstract int DistanceToBounds(Rint2 pos); public abstract float GetCellArea(); public abstract IEnumerable> All(); public abstract IEnumerable> Circle(Rint2 center, int radius); protected abstract bool OutOfBounds(Rint2 pos); protected abstract Rint2 GetGridPos(Vector2 vector); protected abstract Rint2 GetDataPos(Rint2 pos); public Tile? GetCell(Rint2 pos) { if (OutOfBounds(pos)) { return null; } return new Tile(pos, this); } public Tile GetTile(ValueType id) { return GetCell((Rint2)(object)id).Value; } public Tile? GetCell(Vector2 pos) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) return GetCell(GetGridPos(pos)); } public Tile? GetTile(Vector2 pos) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) return GetCell(pos); } public Vector2 Center(ValueType tileId) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) return GetCellCenter((Rint2)(object)tileId); } public ref T Data(ValueType tileId) { Rint2 dataPos = GetDataPos((Rint2)(object)tileId); return ref Storage[dataPos.x, dataPos.y]; } float ITilingKernel.Area(ValueType tileId) { return GetCellArea(); } public int DistanceToBounds(ValueType tileId) { return DistanceToBounds((Rint2)(object)tileId); } public IEnumerable> GetNeighbors(ValueType tileId) { return GetNeighbors(tileId, 1); } [IteratorStateMachine(typeof(Grid<>.d__33))] public IEnumerable> GetNeighbors(ValueType tileId, int hops) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__33(-2) { <>4__this = this, <>3__tileId = tileId, <>3__hops = hops }; } } public class HexGrid : Grid { [CompilerGenerated] private sealed class d__11 : IEnumerable>, IEnumerable, IEnumerator>, IDisposable, IEnumerator { private int <>1__state; private Tile <>2__current; private int <>l__initialThreadId; private int radius; public int <>3__radius; private Rint2 center; public Rint2 <>3__center; public HexGrid <>4__this; private int 5__2; private int 5__3; private int 5__4; Tile IEnumerator>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__11(int <>1__state) { this.<>1__state = <>1__state; <>l__initialThreadId = Environment.CurrentManagedThreadId; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { int num = <>1__state; HexGrid hexGrid = <>4__this; if (num != 0) { if (num != 1) { return false; } <>1__state = -1; goto IL_00d7; } <>1__state = -1; 5__2 = -radius; goto IL_012f; IL_012f: if (5__2 <= radius) { 5__3 = -radius; goto IL_010c; } return false; IL_00d7: 5__4++; goto IL_00e9; IL_010c: if (5__3 <= radius) { 5__4 = -radius; goto IL_00e9; } 5__2++; goto IL_012f; IL_00e9: if (5__4 <= radius) { if (5__2 + 5__3 + 5__4 == 0) { HexVectorExtensions.Rint3 rint = center.AxialToCube(); Tile? cell = hexGrid.GetCell(new HexVectorExtensions.Rint3(rint.x + 5__2, rint.y + 5__3, rint.z + 5__4).CubeToAxial()); if (cell.HasValue) { <>2__current = cell.Value; <>1__state = 1; return true; } } goto IL_00d7; } 5__3++; goto IL_010c; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator> IEnumerable>.GetEnumerator() { d__11 d__; if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; d__ = this; } else { d__ = new d__11(0) { <>4__this = <>4__this }; } d__.center = <>3__center; d__.radius = <>3__radius; return d__; } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable>)this).GetEnumerator(); } } private static readonly float sqrt3 = Mathf.Sqrt(3f); public readonly int Radius; public readonly float CellSize; public override int Count => 1 + Radius * (Radius + 1) * 3; public override float Spacing => sqrt3 * CellSize; public HexGrid(int radius, float cellSize) : base(new Rint2(radius * 2 + 1, radius * 2 + 1)) { Radius = radius; CellSize = cellSize; } public override Grid CreateSisterGrid(Func, V> tileConv = null) { HexGrid hexGrid = new HexGrid(Radius, CellSize); if (tileConv != null) { foreach (Tile tile in base.Tiles) { hexGrid.GetTile(tile.Id).Data = tileConv(tile); } } return hexGrid; } public override Vector2 GetCellCenter(Rint2 pos) { //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) return new Vector2((float)pos.x * 1.5f, (float)pos.x * sqrt3 / 2f + (float)pos.y * sqrt3) * CellSize; } public override IEnumerable> All() { return Circle(Rint2.Zero, Radius); } [IteratorStateMachine(typeof(HexGrid<>.d__11))] public override IEnumerable> Circle(Rint2 center, int radius) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__11(-2) { <>4__this = this, <>3__center = center, <>3__radius = radius }; } protected override bool OutOfBounds(Rint2 pos) { HexVectorExtensions.Rint3 rint = pos.AxialToCube(); if (rint.x < -Radius || rint.x > Radius) { return true; } if (rint.y < -Radius || rint.y > Radius) { return true; } if (rint.z < -Radius || rint.z > Radius) { return true; } return false; } public override int DistanceToBounds(Rint2 pos) { HexVectorExtensions.Rint3 rint = pos.AxialToCube(); return Math.Min(Radius - Math.Abs(rint.x), Math.Min(Radius - Math.Abs(rint.y), Radius - Math.Abs(rint.z))); } public override float GetCellArea() { return 1.5f * sqrt3 * CellSize * CellSize; } protected override Rint2 GetGridPos(Vector2 vector) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_002a: 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) float num = 2f / 3f * vector.x / CellSize; float num2 = (sqrt3 / 3f * vector.y - 1f / 3f * vector.x) / CellSize; return HexVectorExtensions.AxialRound(new Vector2(num, num2)); } protected override Rint2 GetDataPos(Rint2 pos) { return new Rint2(pos.x + Radius, pos.y + Radius); } } internal static class HexVectorExtensions { public struct Rint3 { public int x; public int y; public int z; public Rint3(int x, int y, int z) { this.x = x; this.y = y; this.z = z; } } public static Vector3 AxialToCube(this Vector2 v) { //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_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) return new Vector3(v.x, v.y, 0f - (v.x + v.y)); } public static Vector2 CubeToAxial(this Vector3 v) { //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_000c: Unknown result type (might be due to invalid IL or missing references) return new Vector2(v.x, v.y); } public static Rint3 AxialToCube(this Rint2 v) { return new Rint3(v.x, v.y, -(v.x + v.y)); } public static Rint2 CubeToAxial(this Rint3 v) { return new Rint2(v.x, v.y); } public static Rint3 CubeRound(this Vector3 v) { //IL_0000: 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_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0024: 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_0043: Unknown result type (might be due to invalid IL or missing references) int num = Mathf.RoundToInt(v.x); int num2 = Mathf.RoundToInt(v.y); int num3 = Mathf.RoundToInt(v.z); float num4 = Math.Abs(v.x - (float)num); float num5 = Math.Abs(v.y - (float)num2); float num6 = Math.Abs(v.z - (float)num3); if (num4 > num5 && num4 > num6) { num = -(num2 + num3); } else if (num5 > num6) { num2 = -(num + num3); } else { num3 = -(num + num2); } return new Rint3(num, num2, num3); } public static Rint2 AxialRound(this Vector2 vec) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) return vec.AxialToCube().CubeRound().CubeToAxial(); } } public readonly struct Tile : IEquatable> { private readonly ITilingKernel Kernel; public ValueType Id { get; } public ITiling Tiling => Kernel.Tiling; public Vector2 Center => Kernel.Center(Id); public ref T Data => ref Kernel.Data(Id); public float Area => Kernel.Area(Id); public int DistanceToBounds => Kernel.DistanceToBounds(Id); internal Tile(ValueType id, ITilingKernel kernel) { Id = id; Kernel = kernel; } public IEnumerable> GetNeighbors() { return Kernel.GetNeighbors(Id); } public IEnumerable> GetNeighbors(int hops) { return Kernel.GetNeighbors(Id, hops); } public ref V SisterData(ITiling sisterTiling) { return ref sisterTiling.Kernel.Data(Id); } public static bool operator ==(Tile lhs, Tile rhs) { if (lhs.Kernel.Equals(rhs.Kernel)) { return lhs.Id.Equals(rhs.Id); } return false; } public static bool operator !=(Tile lhs, Tile rhs) { return !(lhs == rhs); } public bool Equals(Tile other) { return this == other; } public override bool Equals(object obj) { if (obj is Tile other) { return Equals(other); } return false; } public override int GetHashCode() { return HashCode.Combine(Id, Tiling); } public override string ToString() { //IL_000c: Unknown result type (might be due to invalid IL or missing references) return $"Tile {{ id = {Id}, center = {Center}, distanceToBounds = {DistanceToBounds} }}"; } } public interface ITiling { int Count { get; } float Area { get; } float Spacing { get; } IEnumerable> Tiles { get; } internal ITilingKernel Kernel { get; } Tile GetTile(ValueType id); Tile? GetTile(Vector2 pos); ITiling CreateSisterTiling(Func, V> tileConv = null); } internal interface ITilingKernel { ITiling Tiling { get; } Vector2 Center(ValueType tileId); ref T Data(ValueType tileId); float Area(ValueType tileId); int DistanceToBounds(ValueType tileId); IEnumerable> GetNeighbors(ValueType tileId); IEnumerable> GetNeighbors(ValueType tileId, int hops); } public static class Extensions { public static ITiling CreateSisterTiling(this ITiling tiling, V value) { return tiling.CreateSisterTiling((Tile _) => value); } public static ITiling CreateSisterTiling(this ITiling tiling, Func dataConv) { return tiling.CreateSisterTiling((Tile tile) => dataConv(tile.Data)); } public static ITiling Copy(this ITiling tiling) { return tiling.CreateSisterTiling((Tile tile) => tile.Data); } } public class PoissonDiscSampler { private const int K = 10; private readonly RandomEngine random; private readonly double minSpacing; private readonly List points; private readonly RandomSet active; private readonly Grid grid; public PoissonDiscSampler(RandomEngine random, double boundingRadius, double minSpacing) { this.random = random; this.minSpacing = minSpacing; points = new List(); active = new RandomSet(random); grid = InitGrid(boundingRadius, minSpacing); Generate(); } public List GetPoints() { return points; } private static Grid InitGrid(double boundingRadius, double r) { //IL_0035: Unknown result type (might be due to invalid IL or missing references) double num = r / Math.Sqrt(2.0); int num2 = Rmath.CeilToInt(boundingRadius / num); SquareGrid squareGrid = new SquareGrid(new Rint2(2 * num2, 2 * num2), (float)num, (double)num2 * num * Rfloat2.One); foreach (Tile tile in squareGrid.Tiles) { tile.Data = -1; } return squareGrid; } private void Generate() { AddPoint(random.VRange(0.0 - minSpacing, minSpacing)); while (active.Count > 0) { int num = active.Sample(); bool flag = false; int num2 = 0; while (!flag && num2++ < 10) { flag = TryAddPoint(points[num] + RandomOffset()); } if (!flag) { active.Remove(num); } } } [MethodImpl(MethodImplOptions.AggressiveInlining)] private void AddPoint(Rfloat2 point) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) Tile tile = grid.GetCell(point) ?? throw new Exception("point out of bounds"); int count = points.Count; tile.Data = count; active.Add(count); points.Add(point); } [MethodImpl(MethodImplOptions.AggressiveInlining)] private bool HasPointWithinRange(Rfloat2 point, Tile tile) { foreach (Tile neighbor in tile.GetNeighbors()) { if (neighbor.Data != -1 && (points[neighbor.Data] - point).SqrLength < minSpacing * minSpacing) { return true; } } return false; } [MethodImpl(MethodImplOptions.AggressiveInlining)] private bool TryAddPoint(Rfloat2 point) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) Tile? cell = grid.GetCell(point); if (cell.HasValue) { Tile valueOrDefault = cell.GetValueOrDefault(); if (valueOrDefault.Data != -1) { return false; } if (HasPointWithinRange(point, valueOrDefault)) { return false; } AddPoint(point); return true; } return false; } [MethodImpl(MethodImplOptions.AggressiveInlining)] private Rfloat2 RandomOffset() { double num = minSpacing * minSpacing; double num2 = Math.Sqrt(3.0 * num * random.Value + num); double num3 = random.Range(0.0, Math.PI * 2.0); return new Rfloat2(num2 * Math.Cos(num3), num2 * Math.Sin(num3)); } } public class RectangularGrid : Grid { [CompilerGenerated] private sealed class d__17 : IEnumerable>, IEnumerable, IEnumerator>, IDisposable, IEnumerator { private int <>1__state; private Tile <>2__current; private int <>l__initialThreadId; public RectangularGrid <>4__this; private int 5__2; private int 5__3; Tile IEnumerator>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__17(int <>1__state) { this.<>1__state = <>1__state; <>l__initialThreadId = Environment.CurrentManagedThreadId; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { int num = <>1__state; RectangularGrid rectangularGrid = <>4__this; if (num != 0) { if (num != 1) { return false; } <>1__state = -1; 5__3++; goto IL_0072; } <>1__state = -1; 5__2 = 0; goto IL_0095; IL_0072: if (5__3 < rectangularGrid.Size.y) { <>2__current = new Tile(new Rint2(5__2, 5__3), rectangularGrid); <>1__state = 1; return true; } 5__2++; goto IL_0095; IL_0095: if (5__2 < rectangularGrid.Size.x) { 5__3 = 0; goto IL_0072; } return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator> IEnumerable>.GetEnumerator() { d__17 result; if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; result = this; } else { result = new d__17(0) { <>4__this = <>4__this }; } return result; } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable>)this).GetEnumerator(); } } [CompilerGenerated] private sealed class d__18 : IEnumerable>, IEnumerable, IEnumerator>, IDisposable, IEnumerator { private int <>1__state; private Tile <>2__current; private int <>l__initialThreadId; private int radius; public int <>3__radius; public RectangularGrid <>4__this; private Rint2 center; public Rint2 <>3__center; private int 5__2; private int 5__3; Tile IEnumerator>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__18(int <>1__state) { this.<>1__state = <>1__state; <>l__initialThreadId = Environment.CurrentManagedThreadId; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { int num = <>1__state; RectangularGrid rectangularGrid = <>4__this; if (num != 0) { if (num != 1) { return false; } <>1__state = -1; goto IL_008a; } <>1__state = -1; 5__2 = -radius; goto IL_00bc; IL_00bc: if (5__2 <= radius) { 5__3 = -radius; goto IL_009c; } return false; IL_009c: if (5__3 <= radius) { Tile? cell = rectangularGrid.GetCell(center + new Rint2(5__2, 5__3)); if (cell.HasValue) { Tile valueOrDefault = cell.GetValueOrDefault(); <>2__current = valueOrDefault; <>1__state = 1; return true; } goto IL_008a; } 5__2++; goto IL_00bc; IL_008a: 5__3++; goto IL_009c; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator> IEnumerable>.GetEnumerator() { d__18 d__; if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; d__ = this; } else { d__ = new d__18(0) { <>4__this = <>4__this }; } d__.center = <>3__center; d__.radius = <>3__radius; return d__; } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable>)this).GetEnumerator(); } } public Rint2 Size { get; } public Vector2 CellSize { get; } public Vector2 Offset { get; } public override int Count => Size.x * Size.y; public override float Spacing => (CellSize.x + CellSize.y) / 2f; public RectangularGrid(Rint2 size, Vector2 cellSize, Vector2 offset) : base(size) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) Size = size; CellSize = cellSize; Offset = offset; } public RectangularGrid(Rint2 size, Vector2 cellSize) : this(size, cellSize, Vector2.zero) { }//IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Unknown result type (might be due to invalid IL or missing references) public override Grid CreateSisterGrid(Func, V> tileConv = null) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) RectangularGrid rectangularGrid = new RectangularGrid(Size, CellSize, Offset); if (tileConv != null) { foreach (Tile tile in base.Tiles) { rectangularGrid.GetTile(tile.Id).Data = tileConv(tile); } } return rectangularGrid; } public override Vector2 GetCellCenter(Rint2 pos) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0013: 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_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002d: 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_0038: Unknown result type (might be due to invalid IL or missing references) return (new Vector2((float)pos.x, (float)pos.y) + Vector2.one / 2f) * CellSize - Offset; } [IteratorStateMachine(typeof(RectangularGrid<>.d__17))] public override IEnumerable> All() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__17(-2) { <>4__this = this }; } [IteratorStateMachine(typeof(RectangularGrid<>.d__18))] public override IEnumerable> Circle(Rint2 center, int radius) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__18(-2) { <>4__this = this, <>3__center = center, <>3__radius = radius }; } protected override bool OutOfBounds(Rint2 pos) { if (pos.x >= 0 && pos.y >= 0 && pos.x < Size.x) { return pos.y >= Size.y; } return true; } public override int DistanceToBounds(Rint2 pos) { return Math.Min(Math.Min(pos.x, Size.x - pos.x - 1), Math.Min(pos.y, Size.y - pos.y - 1)); } public override float GetCellArea() { //IL_0001: 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) return CellSize.x * CellSize.y; } protected override Rint2 GetGridPos(Vector2 pos) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) Vector2 val = (pos + Offset) / CellSize; return new Rint2(Mathf.FloorToInt(val.x), Mathf.FloorToInt(val.y)); } protected override Rint2 GetDataPos(Rint2 pos) { return new Rint2(pos.x, pos.y); } } public class SquareGrid : RectangularGrid { public new float CellSize => base.CellSize.x; public SquareGrid(Rint2 size, float cellSize, Vector2 offset) : base(size, new Vector2(cellSize, cellSize), offset) { }//IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) public SquareGrid(Rint2 size, float cellSize) : this(size, cellSize, Vector2.zero) { }//IL_0003: Unknown result type (might be due to invalid IL or missing references) } public static class TilingExtensions { [CompilerGenerated] private sealed class d__2 : IEnumerable>, IEnumerable, IEnumerator>, IDisposable, IEnumerator { private int <>1__state; private Tile <>2__current; private int <>l__initialThreadId; private Tile from; public Tile <>3__from; private float radius; public float <>3__radius; private HashSet> 5__2; private Queue> 5__3; private float 5__4; private IEnumerator> <>7__wrap4; private Tile 5__6; Tile IEnumerator>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__2(int <>1__state) { this.<>1__state = <>1__state; <>l__initialThreadId = Environment.CurrentManagedThreadId; } [DebuggerHidden] void IDisposable.Dispose() { int num = <>1__state; if (num == -3 || num == 1) { try { } finally { <>m__Finally1(); } } 5__2 = null; 5__3 = null; <>7__wrap4 = null; 5__6 = default(Tile); <>1__state = -2; } private bool MoveNext() { //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) try { int num = <>1__state; if (num != 0) { if (num != 1) { return false; } <>1__state = -3; 5__3.Enqueue(5__6); 5__6 = default(Tile); goto IL_0121; } <>1__state = -1; 5__2 = new HashSet> { from }; 5__3 = new Queue>(); 5__3.Enqueue(from); 5__4 = radius * radius; goto IL_013e; IL_0121: while (<>7__wrap4.MoveNext()) { 5__6 = <>7__wrap4.Current; if (5__2.Add(5__6)) { Vector2 val = 5__6.Center - from.Center; if (!(((Vector2)(ref val)).sqrMagnitude > 5__4)) { <>2__current = 5__6; <>1__state = 1; return true; } } } <>m__Finally1(); <>7__wrap4 = null; goto IL_013e; IL_013e: if (5__3.Count > 0) { <>7__wrap4 = 5__3.Dequeue().GetNeighbors().GetEnumerator(); <>1__state = -3; goto IL_0121; } return false; } catch { //try-fault ((IDisposable)this).Dispose(); throw; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } private void <>m__Finally1() { <>1__state = -1; if (<>7__wrap4 != null) { <>7__wrap4.Dispose(); } } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator> IEnumerable>.GetEnumerator() { d__2 d__; if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; d__ = this; } else { d__ = new d__2(0); } d__.from = <>3__from; d__.radius = <>3__radius; return d__; } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable>)this).GetEnumerator(); } } public static Direction DirectionTo(this Tile tile, Tile to) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) return new Direction(to.Center - tile.Center); } public static Tile GetNeighbor(this Tile tile, Direction direction) { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) float num = float.MaxValue; Tile result = default(Tile); foreach (Tile neighbor in tile.GetNeighbors()) { float num2 = Math.Abs(new Direction(neighbor.Center - tile.Center) - direction); if (num2 < num) { num = num2; result = neighbor; } } return result; } [IteratorStateMachine(typeof(d__2<>))] public static IEnumerable> Scan(this Tile from, float radius) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__2(-2) { <>3__from = from, <>3__radius = radius }; } public static ITiling CreateDistanceField(this ITiling tiling, Func, float?> init, Predicate> isReachable = null) { //IL_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Unknown result type (might be due to invalid IL or missing references) //IL_0104: Unknown result type (might be due to invalid IL or missing references) if (isReachable == null) { isReachable = (Tile _) => true; } ITiling tiling2 = tiling.CreateSisterTiling((Tile tile) => (isReachable(tile) ? init(tile) : null).GetValueOrDefault(float.MaxValue)); Queue> queue = new Queue>(); foreach (Tile tile3 in tiling2.Tiles) { if (isReachable(tiling.GetTile(tile3.Id)) && tile3.Data < float.MaxValue) { queue.Enqueue(tile3); } } while (queue.Count > 0) { Tile tile2 = queue.Dequeue(); foreach (Tile neighbor in tile2.GetNeighbors()) { if (isReachable(tiling.GetTile(neighbor.Id))) { Vector2 val = tile2.Center - neighbor.Center; float magnitude = ((Vector2)(ref val)).magnitude; if (neighbor.Data > tile2.Data + magnitude) { neighbor.Data = tile2.Data + magnitude; queue.Enqueue(neighbor); } } } } return tiling2; } } public static class TilingUtility { public static VoronoiTiling CreateVoronoiFromJitteredSquare(RandomEngine random, float radius, float spacing, Func dataMap = null) { //IL_0053: 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_0060: 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_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Unknown result type (might be due to invalid IL or missing references) //IL_010a: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Unknown result type (might be due to invalid IL or missing references) float tilingBounds = radius + Mathf.Sqrt(3f) * spacing; float num = 3f * spacing / (2f + Mathf.Sqrt(2f)); int num2 = Mathf.CeilToInt(tilingBounds / num); SquareGrid squareGrid = new SquareGrid(2 * Rint2.One * num2, num, Vector2.one * (float)num2 * num); foreach (Tile tile in squareGrid.Tiles) { tile.Data = 0.85f * spacing * random.VRange(-0.5, 0.5); } List list = new List(); foreach (Tile tile2 in squareGrid.Tiles) { Vector2 val = tile2.Center + tile2.Data; if (boundingFunc(val)) { list.Add(val); } } return new VoronoiTiling(list, spacing, boundingFunc, dataMap); bool boundingFunc(Vector2 point) { return ((Vector2)(ref point)).magnitude < tilingBounds; } } public static VoronoiTiling CreateVoronoiFromJitteredHex(RandomEngine random, float radius, float spacing, Func dataMap = null) { //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) float tilingBounds = radius + Mathf.Sqrt(3f) * spacing; float num = spacing / Mathf.Sqrt(3f); HexGrid hexGrid = new HexGrid(Mathf.CeilToInt(0.75f * tilingBounds / num), num); foreach (Tile tile in hexGrid.Tiles) { tile.Data = 0.7f * spacing * random.VRange(-0.5, 0.5); } List list = new List(); foreach (Tile tile2 in hexGrid.Tiles) { Vector2 val = tile2.Center + tile2.Data; if (boundingFunc(val)) { list.Add(val); } } return new VoronoiTiling(list, spacing, boundingFunc, dataMap); bool boundingFunc(Vector2 point) { return ((Vector2)(ref point)).magnitude < tilingBounds; } } public static VoronoiTiling CreateVoronoiFromPoissonDisc(RandomEngine random, float radius, float spacing, Func dataMap = null) { //IL_0051: 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) float tilingBounds = radius + Mathf.Sqrt(3f) * spacing; List list = new List(); foreach (Rfloat2 point in new PoissonDiscSampler(random, tilingBounds, spacing / Mathf.Sqrt(2f)).GetPoints()) { if (boundingFunc(point)) { list.Add(point); } } return new VoronoiTiling(list, spacing, boundingFunc, dataMap); bool boundingFunc(Vector2 point) { return ((Vector2)(ref point)).magnitude < tilingBounds; } } } public class VoronoiTiling : ITiling, ITilingKernel { [CompilerGenerated] private sealed class d__7 : IEnumerable, IEnumerable, IEnumerator, IDisposable, IEnumerator { private int <>1__state; private int <>2__current; private int <>l__initialThreadId; private Dictionary distancesToBounds; public Dictionary <>3__distancesToBounds; private Dictionary> graph; public Dictionary> <>3__graph; private HashSet.Enumerator <>7__wrap1; int IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__7(int <>1__state) { this.<>1__state = <>1__state; <>l__initialThreadId = Environment.CurrentManagedThreadId; } [DebuggerHidden] void IDisposable.Dispose() { int num = <>1__state; if (num == -3 || num == 1) { try { } finally { <>m__Finally1(); } } <>7__wrap1 = default(HashSet.Enumerator); <>1__state = -2; } private bool MoveNext() { try { switch (<>1__state) { default: return false; case 0: { <>1__state = -1; int num = 0; int item = -1; foreach (KeyValuePair distancesToBound in distancesToBounds) { if (distancesToBound.Value > num) { num = distancesToBound.Value; item = distancesToBound.Key; } } HashSet hashSet = new HashSet(graph.Keys); hashSet.Remove(item); Queue queue = new Queue(); queue.Enqueue(item); while (queue.Count > 0) { int key = queue.Dequeue(); foreach (int item2 in graph[key]) { if (hashSet.Contains(item2)) { hashSet.Remove(item2); queue.Enqueue(item2); } } } <>7__wrap1 = hashSet.GetEnumerator(); <>1__state = -3; break; } case 1: <>1__state = -3; break; } if (<>7__wrap1.MoveNext()) { int current3 = <>7__wrap1.Current; <>2__current = current3; <>1__state = 1; return true; } <>m__Finally1(); <>7__wrap1 = default(HashSet.Enumerator); return false; } catch { //try-fault ((IDisposable)this).Dispose(); throw; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } private void <>m__Finally1() { <>1__state = -1; ((IDisposable)<>7__wrap1).Dispose(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { d__7 d__; if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; d__ = this; } else { d__ = new d__7(0); } d__.graph = <>3__graph; d__.distancesToBounds = <>3__distancesToBounds; return d__; } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)this).GetEnumerator(); } } [CompilerGenerated] private sealed class d__32 : IEnumerable>, IEnumerable, IEnumerator>, IDisposable, IEnumerator { private int <>1__state; private Tile <>2__current; private int <>l__initialThreadId; public VoronoiTiling <>4__this; private ValueType tileId; public ValueType <>3__tileId; private int[] <>7__wrap1; private int <>7__wrap2; Tile IEnumerator>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__32(int <>1__state) { this.<>1__state = <>1__state; <>l__initialThreadId = Environment.CurrentManagedThreadId; } [DebuggerHidden] void IDisposable.Dispose() { <>7__wrap1 = null; <>1__state = -2; } private bool MoveNext() { int num = <>1__state; VoronoiTiling voronoiTiling = <>4__this; switch (num) { default: return false; case 0: <>1__state = -1; <>7__wrap1 = voronoiTiling.TileInfos[(int)(object)tileId].Adjacency; <>7__wrap2 = 0; break; case 1: <>1__state = -1; <>7__wrap2++; break; } if (<>7__wrap2 < <>7__wrap1.Length) { int num2 = <>7__wrap1[<>7__wrap2]; <>2__current = new Tile(num2, voronoiTiling); <>1__state = 1; return true; } <>7__wrap1 = null; return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator> IEnumerable>.GetEnumerator() { d__32 d__; if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; d__ = this; } else { d__ = new d__32(0) { <>4__this = <>4__this }; } d__.tileId = <>3__tileId; return d__; } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable>)this).GetEnumerator(); } } [CompilerGenerated] private sealed class d__33 : IEnumerable>, IEnumerable, IEnumerator>, IDisposable, IEnumerator { private int <>1__state; private Tile <>2__current; private int <>l__initialThreadId; private ValueType tileId; public ValueType <>3__tileId; public VoronoiTiling <>4__this; private int hops; public int <>3__hops; private int 5__2; private HashSet 5__3; private List 5__4; private List.Enumerator <>7__wrap4; private int 5__6; Tile IEnumerator>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__33(int <>1__state) { this.<>1__state = <>1__state; <>l__initialThreadId = Environment.CurrentManagedThreadId; } [DebuggerHidden] void IDisposable.Dispose() { int num = <>1__state; if (num == -3 || num == 1) { try { } finally { <>m__Finally1(); } } 5__3 = null; 5__4 = null; <>7__wrap4 = default(List.Enumerator); <>1__state = -2; } private bool MoveNext() { try { int num = <>1__state; VoronoiTiling voronoiTiling = <>4__this; if (num != 0) { if (num != 1) { return false; } <>1__state = -3; goto IL_00e2; } <>1__state = -1; 5__2 = (int)(object)tileId; 5__3 = new HashSet { 5__2 }; 5__4 = new List { 5__2 }; goto IL_0160; IL_0160: if (hops-- >= 0 && 5__4.Count > 0) { List list = 5__4; 5__4 = new List(); <>7__wrap4 = list.GetEnumerator(); <>1__state = -3; goto IL_013e; } return false; IL_013e: if (<>7__wrap4.MoveNext()) { 5__6 = <>7__wrap4.Current; if (5__6 != 5__2) { <>2__current = new Tile(5__6, voronoiTiling); <>1__state = 1; return true; } goto IL_00e2; } <>m__Finally1(); <>7__wrap4 = default(List.Enumerator); goto IL_0160; IL_00e2: int[] adjacency = voronoiTiling.TileInfos[5__6].Adjacency; foreach (int item in adjacency) { if (!5__3.Contains(item)) { 5__3.Add(item); 5__4.Add(item); } } goto IL_013e; } catch { //try-fault ((IDisposable)this).Dispose(); throw; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } private void <>m__Finally1() { <>1__state = -1; ((IDisposable)<>7__wrap4).Dispose(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator> IEnumerable>.GetEnumerator() { d__33 d__; if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; d__ = this; } else { d__ = new d__33(0) { <>4__this = <>4__this }; } d__.tileId = <>3__tileId; d__.hops = <>3__hops; return d__; } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable>)this).GetEnumerator(); } } [CompilerGenerated] private sealed class d__22 : IEnumerable>, IEnumerable, IEnumerator>, IDisposable, IEnumerator { private int <>1__state; private Tile <>2__current; private int <>l__initialThreadId; public VoronoiTiling <>4__this; private int 5__2; Tile IEnumerator>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__22(int <>1__state) { this.<>1__state = <>1__state; <>l__initialThreadId = Environment.CurrentManagedThreadId; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { int num = <>1__state; VoronoiTiling voronoiTiling = <>4__this; switch (num) { default: return false; case 0: <>1__state = -1; 5__2 = 0; break; case 1: <>1__state = -1; 5__2++; break; } if (5__2 < voronoiTiling.Count) { <>2__current = new Tile(5__2, voronoiTiling); <>1__state = 1; return true; } return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator> IEnumerable>.GetEnumerator() { d__22 result; if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; result = this; } else { result = new d__22(0) { <>4__this = <>4__this }; } return result; } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable>)this).GetEnumerator(); } } private readonly TileInfo[] TileInfos; private readonly T[] Storage; private readonly VoronoiSpatialIndex SpatialIndex; public int Count => TileInfos.Length; public float Area { get; } public float Spacing { get; } public IEnumerable> Tiles { [IteratorStateMachine(typeof(VoronoiTiling<>.d__22))] get { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__22(-2) { <>4__this = this }; } } ITilingKernel ITiling.Kernel => this; public ITiling Tiling => this; public VoronoiTiling(List points, float spacingHint, Func boundingHint = null, Func dataMap = null) { //IL_017c: Unknown result type (might be due to invalid IL or missing references) <71c98ed0-65e2-4d7b-9d9e-046a047365d7>Delaunator <71c98ed0-65e2-4d7b-9d9e-046a047365d7>Delaunator = ComputeDelaunay(points); Dictionary> dictionary = <71c98ed0-65e2-4d7b-9d9e-046a047365d7>Delaunator.ComputeAdjacencies(); Dictionary dictionary2 = ComputeDistancesToBounds(dictionary, new HashSet(<71c98ed0-65e2-4d7b-9d9e-046a047365d7>Delaunator.Hull), -2); foreach (int key in dictionary2.Keys) { if (dictionary2[key] >= 0) { continue; } foreach (int item in dictionary[key]) { if (dictionary.ContainsKey(item)) { dictionary[item].Remove(key); } } dictionary.Remove(key); } foreach (int item2 in FindDisconnectedVertices(dictionary, dictionary2)) { dictionary.Remove(item2); } if (dictionary.Count == 0) { throw new Exception("VoronoiTiling left with no vertices after culling border!"); } Dictionary areas = <71c98ed0-65e2-4d7b-9d9e-046a047365d7>Delaunator.ComputeVoronoiCellAreas(); Dictionary dictionary3 = ComputeCompressedIdxMapping(dictionary); TileInfos = Compress(<71c98ed0-65e2-4d7b-9d9e-046a047365d7>Delaunator, dictionary3, dictionary, areas, dictionary2); Area = ComputeTotalArea(); Spacing = spacingHint; SpatialIndex = new VoronoiSpatialIndex(<71c98ed0-65e2-4d7b-9d9e-046a047365d7>Delaunator, dictionary3, spacingHint, boundingHint); Storage = new T[TileInfos.Length]; if (dataMap != null) { for (int i = 0; i < Count; i++) { Storage[i] = dataMap(TileInfos[i].Center); } } } private VoronoiTiling(TileInfo[] tileInfos, float area, float spacingHint, VoronoiSpatialIndex spatialIndex) { TileInfos = tileInfos; Area = area; Spacing = spacingHint; SpatialIndex = spatialIndex; Storage = new T[TileInfos.Length]; } private static <71c98ed0-65e2-4d7b-9d9e-046a047365d7>Delaunator ComputeDelaunay(List points) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) <71c98ed0-65e2-4d7b-9d9e-046a047365d7>IPoint[] array = new <71c98ed0-65e2-4d7b-9d9e-046a047365d7>IPoint[points.Count]; for (int i = 0; i < array.Length; i++) { array[i] = new <71c98ed0-65e2-4d7b-9d9e-046a047365d7>Point(points[i].x, points[i].y); } return new <71c98ed0-65e2-4d7b-9d9e-046a047365d7>Delaunator(array); } private static Dictionary ComputeDistancesToBounds(Dictionary> graph, HashSet bounds, int start = 0) { Dictionary dictionary = new Dictionary(); foreach (int key2 in graph.Keys) { dictionary[key2] = (bounds.Contains(key2) ? start : int.MaxValue); } Queue queue = new Queue(bounds); while (queue.Count > 0) { int key = queue.Dequeue(); int num = dictionary[key] + 1; foreach (int item in graph[key]) { if (dictionary[item] > num) { dictionary[item] = num; queue.Enqueue(item); } } } return dictionary; } [IteratorStateMachine(typeof(VoronoiTiling<>.d__7))] private static IEnumerable FindDisconnectedVertices(Dictionary> graph, Dictionary distancesToBounds) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__7(-2) { <>3__graph = graph, <>3__distancesToBounds = distancesToBounds }; } private static Dictionary ComputeCompressedIdxMapping(Dictionary> graph) { Dictionary dictionary = new Dictionary(); int num = 0; foreach (int key in graph.Keys) { dictionary[key] = num++; } return dictionary; } private static TileInfo[] Compress(<71c98ed0-65e2-4d7b-9d9e-046a047365d7>Delaunator delaunay, Dictionary idxMapping, Dictionary> graph, Dictionary areas, Dictionary hullDistances) { //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) TileInfo[] array = new TileInfo[idxMapping.Count]; foreach (int key in idxMapping.Keys) { List list = new List(); foreach (int item in graph[key]) { if (idxMapping.ContainsKey(item)) { list.Add(idxMapping[item]); } } array[idxMapping[key]] = new TileInfo { Center = delaunay.Points[key].ToVector2(), Area = areas[key], Adjacency = list.ToArray(), DistanceToBounds = hullDistances[key] }; } return array; } private float ComputeTotalArea() { float num = 0f; TileInfo[] tileInfos = TileInfos; for (int i = 0; i < tileInfos.Length; i++) { TileInfo tileInfo = tileInfos[i]; num += tileInfo.Area; } return num; } public Tile GetTile(ValueType id) { return new Tile((int)(object)id, this); } public Tile? GetTile(Vector2 pos) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) int? tileIndex = SpatialIndex.GetTileIndex(pos); if (tileIndex.HasValue) { int valueOrDefault = tileIndex.GetValueOrDefault(); return new Tile(valueOrDefault, this); } return null; } public ITiling CreateSisterTiling(Func, V> tileConv = null) { VoronoiTiling voronoiTiling = new VoronoiTiling(TileInfos, Area, Spacing, SpatialIndex); if (tileConv != null) { foreach (Tile tile in Tiles) { voronoiTiling.Storage[(int)(object)tile.Id] = tileConv(tile); } } return voronoiTiling; } public Vector2 Center(ValueType tileId) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) return TileInfos[(int)(object)tileId].Center; } public ref T Data(ValueType tileId) { return ref Storage[(int)(object)tileId]; } float ITilingKernel.Area(ValueType tileId) { return TileInfos[(int)(object)tileId].Area; } public int DistanceToBounds(ValueType tileId) { return TileInfos[(int)(object)tileId].DistanceToBounds; } [IteratorStateMachine(typeof(VoronoiTiling<>.d__32))] public IEnumerable> GetNeighbors(ValueType tileId) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__32(-2) { <>4__this = this, <>3__tileId = tileId }; } [IteratorStateMachine(typeof(VoronoiTiling<>.d__33))] public IEnumerable> GetNeighbors(ValueType tileId, int hops) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__33(-2) { <>4__this = this, <>3__tileId = tileId, <>3__hops = hops }; } } internal static class DelaunayExtensions { [CompilerGenerated] private sealed class d__1 : IEnumerable<(int, int)>, IEnumerable, IEnumerator<(int, int)>, IDisposable, IEnumerator { private int <>1__state; private (int, int) <>2__current; private int <>l__initialThreadId; private <71c98ed0-65e2-4d7b-9d9e-046a047365d7>Delaunator delaunay; public <71c98ed0-65e2-4d7b-9d9e-046a047365d7>Delaunator <>3__delaunay; private int 5__2; private List 5__3; private int 5__4; (int, int) IEnumerator<(int, int)>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__1(int <>1__state) { this.<>1__state = <>1__state; <>l__initialThreadId = Environment.CurrentManagedThreadId; } [DebuggerHidden] void IDisposable.Dispose() { 5__3 = null; <>1__state = -2; } private bool MoveNext() { int num = <>1__state; if (num != 0) { if (num != 1) { return false; } <>1__state = -1; int num2 = 5__4 + 1; 5__4 = num2; goto IL_00b4; } <>1__state = -1; 5__2 = 0; goto IL_00de; IL_00b4: if (5__4 < 5__3.Count) { int index = ((5__4 < 5__3.Count - 1) ? (5__4 + 1) : 0); <>2__current = (5__3[5__4], 5__3[index]); <>1__state = 1; return true; } 5__3 = null; 5__2++; goto IL_00de; IL_00de: if (5__2 < delaunay.Triangles.Length / 3) { 5__3 = new List(delaunay.PointsOfTriangle(5__2)); 5__4 = 0; goto IL_00b4; } return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator<(int, int)> IEnumerable<(int, int)>.GetEnumerator() { d__1 d__; if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; d__ = this; } else { d__ = new d__1(0); } d__.delaunay = <>3__delaunay; return d__; } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable<(int, int)>)this).GetEnumerator(); } } public static Vector2 ToVector2(this <71c98ed0-65e2-4d7b-9d9e-046a047365d7>IPoint point) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) return new Vector2((float)point.X, (float)point.Y); } [IteratorStateMachine(typeof(d__1))] public static IEnumerable<(int, int)> GetEdgeConnections(this <71c98ed0-65e2-4d7b-9d9e-046a047365d7>Delaunator delaunay) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__1(-2) { <>3__delaunay = delaunay }; } public static Dictionary> ComputeAdjacencies(this <71c98ed0-65e2-4d7b-9d9e-046a047365d7>Delaunator delaunay) { Dictionary> dictionary = new Dictionary>(); foreach (var (key, item) in delaunay.GetEdgeConnections()) { if (!dictionary.ContainsKey(key)) { dictionary[key] = new List(); } dictionary[key].Add(item); } return dictionary; } public static float Area(this <71c98ed0-65e2-4d7b-9d9e-046a047365d7>IVoronoiCell cell) { double num = 0.0; for (int i = 0; i < cell.Points.Length; i++) { num += det(cell.Points[i], cell.Points[(i + 1) % cell.Points.Length]); } return Mathf.Max(0f, (float)num * 0.5f); static double det(<71c98ed0-65e2-4d7b-9d9e-046a047365d7>IPoint p1, <71c98ed0-65e2-4d7b-9d9e-046a047365d7>IPoint p2) { return p1.X * p2.Y - p2.X * p1.Y; } } public static Dictionary ComputeVoronoiCellAreas(this <71c98ed0-65e2-4d7b-9d9e-046a047365d7>Delaunator delaunay) { Dictionary dictionary = new Dictionary(); foreach (<71c98ed0-65e2-4d7b-9d9e-046a047365d7>IVoronoiCell voronoiCellsBasedOnCircumcenter in delaunay.GetVoronoiCellsBasedOnCircumcenters()) { dictionary[voronoiCellsBasedOnCircumcenter.Index] = voronoiCellsBasedOnCircumcenter.Area(); } return dictionary; } } } namespace Riverheim.Util.Tilings.Internal { internal struct TileInfo { public Vector2 Center; public float Area; public int[] Adjacency; public int DistanceToBounds; } internal class VoronoiSpatialIndex { private struct TilePointRef { public Vector2 Pos; public int? Index; } private readonly List[,] Grid; private readonly Func InBounds; private readonly float QueryRadius; private readonly Vector2 Offset; private readonly float CellSize; public VoronoiSpatialIndex(<71c98ed0-65e2-4d7b-9d9e-046a047365d7>Delaunator delaunay, Dictionary tileIndices, float spacingHint, Func boundCheck) { //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0084: 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) BoundingBox bbox = ComputeBoundingRect(delaunay); Rint2 rint = (bbox.size / spacingHint).CeilToInt() + Rint2.One; Grid = new List[rint.x, rint.y]; Offset = (Vector2)bbox.center - 0.5f * spacingHint * new Vector2((float)rint.x, (float)rint.y); CellSize = spacingHint; FillGrid(delaunay, tileIndices); InBounds = boundCheck ?? ((Func)((Vector2 point) => bbox.Contains(point))); QueryRadius = spacingHint * 0.5f; } private static BoundingBox ComputeBoundingRect(<71c98ed0-65e2-4d7b-9d9e-046a047365d7>Delaunator delaunay) { return new BoundingBox(from p in delaunay.GetHullPoints() select new Rfloat2(p.X, p.Y)); } private Rint2 GridPos(Vector2 pos) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) return ((Rfloat2)(pos - Offset) / (double)CellSize).RoundToInt(); } private void FillGrid(<71c98ed0-65e2-4d7b-9d9e-046a047365d7>Delaunator delaunay, Dictionary tileIndices) { //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) for (int i = 0; i < Grid.GetLength(0); i++) { for (int j = 0; j < Grid.GetLength(1); j++) { Grid[i, j] = new List(); } } for (int k = 0; k < delaunay.Points.Length; k++) { Vector2 pos = delaunay.Points[k].ToVector2(); Rint2 rint = GridPos(pos); Grid[rint.x, rint.y].Add(new TilePointRef { Pos = pos, Index = (tileIndices.TryGetValue(k, out var value) ? new int?(value) : null) }); } } public int? GetTileIndex(Vector2 pos) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003a: 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_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: 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) if (!InBounds(pos)) { return null; } float num = QueryRadius; do { float num2 = float.MaxValue; int? result = null; Rint2 rint = GridPos(pos - Vector2.one * num); Rint2 rint2 = GridPos(pos + Vector2.one * num); for (int i = Math.Max(0, rint.x); i <= Math.Min(Grid.GetLength(0) - 1, rint2.x); i++) { for (int j = Math.Max(0, rint.y); j <= Math.Min(Grid.GetLength(1) - 1, rint2.y); j++) { foreach (TilePointRef item in Grid[i, j]) { Vector2 val = pos - item.Pos; float sqrMagnitude = ((Vector2)(ref val)).sqrMagnitude; if (sqrMagnitude < num2) { num2 = sqrMagnitude; result = item.Index; } } } } if (num2 < float.MaxValue) { return result; } num *= 1.4f; } while (num < 100f * QueryRadius); return null; } } } namespace Riverheim.Util.Splines { public class BSplineImpl : ISplineImpl { private readonly Rfloat2[] points; public int SegmentCount => points.Length - 3; public BSplineImpl(ICollection points) { if (points.Count < 2) { throw new ArgumentException("Spline must have at least 2 points"); } this.points = new Rfloat2[points.Count + 2]; int num = 1; foreach (Rfloat2 point in points) { this.points[num++] = point; } this.points[0] = 2.0 * this.points[1] - this.points[2]; this.points[num] = 2.0 * this.points[num - 1] - this.points[num - 2]; } public Rfloat2 EvaluatePosition(in PolylinePosition pos) { if (pos.index < 0 || pos.index > SegmentCount - 1) { throw new IndexOutOfRangeException(); } double t = pos.t; double num = t * t; double num2 = t * t * t; Rfloat2 rfloat = points[pos.index]; Rfloat2 rfloat2 = points[pos.index + 1]; Rfloat2 rfloat3 = points[pos.index + 2]; Rfloat2 rfloat4 = points[pos.index + 3]; return 1.0 / 6.0 * (rfloat * (-1.0 * num2 + 3.0 * num - 3.0 * t + 1.0) + rfloat2 * (3.0 * num2 - 6.0 * num + 4.0) + rfloat3 * (-3.0 * num2 + 3.0 * num + 3.0 * t + 1.0) + rfloat4 * num2); } public Rfloat2 EvaluateTangent(in PolylinePosition pos) { if (pos.index < 0 || pos.index > SegmentCount - 1) { throw new IndexOutOfRangeException(); } double t = pos.t; double num = t * t; Rfloat2 rfloat = points[pos.index]; Rfloat2 rfloat2 = points[pos.index + 1]; Rfloat2 rfloat3 = points[pos.index + 2]; Rfloat2 rfloat4 = points[pos.index + 3]; return 1.0 / 6.0 * (rfloat * (-3.0 * num + 6.0 * t - 3.0) + rfloat2 * (9.0 * num - 12.0 * t) + rfloat3 * (-9.0 * num + 6.0 * t + 3.0) + rfloat4 * 3.0 * num); } public Rfloat2 EvaluateAcceleration(in PolylinePosition pos) { if (pos.index < 0 || pos.index > SegmentCount - 1) { throw new IndexOutOfRangeException(); } double t = pos.t; Rfloat2 rfloat = points[pos.index]; Rfloat2 rfloat2 = points[pos.index + 1]; Rfloat2 rfloat3 = points[pos.index + 2]; Rfloat2 rfloat4 = points[pos.index + 3]; return 1.0 / 6.0 * (rfloat * (-6.0 * t + 6.0) + rfloat2 * (18.0 * t - 12.0) + rfloat3 * (-18.0 * t + 6.0) + rfloat4 * 6.0 * t); } Rfloat2 ISplineImpl.EvaluatePosition(in PolylinePosition pos) { return EvaluatePosition(in pos); } Rfloat2 ISplineImpl.EvaluateTangent(in PolylinePosition pos) { return EvaluateTangent(in pos); } Rfloat2 ISplineImpl.EvaluateAcceleration(in PolylinePosition pos) { return EvaluateAcceleration(in pos); } } public class HermiteSplineImpl : ISplineImpl { private readonly Rfloat2[] points; private readonly Rfloat2[] tangents; public int SegmentCount => points.Length - 1; public HermiteSplineImpl(ICollection points, ICollection tangents) { if (points.Count < 2) { throw new ArgumentException("Spline must have at least 2 points"); } if (points.Count != tangents.Count) { throw new ArgumentException("Number of points and tangents must be the same"); } this.points = points.ToArray(); this.tangents = tangents.ToArray(); } public Rfloat2 EvaluatePosition(in PolylinePosition pos) { if (pos.index < 0 || pos.index > SegmentCount - 1) { throw new IndexOutOfRangeException(); } double t = pos.t; double num = t * t; double num2 = t * t * t; Rfloat2 rfloat = points[pos.index]; Rfloat2 rfloat2 = points[pos.index + 1]; Rfloat2 rfloat3 = tangents[pos.index]; Rfloat2 rfloat4 = tangents[pos.index + 1]; return (2.0 * num2 - 3.0 * num + 1.0) * rfloat + (num2 - 2.0 * num + t) * rfloat3 + (-2.0 * num2 + 3.0 * num) * rfloat2 + (num2 - num) * rfloat4; } public Rfloat2 EvaluateTangent(in PolylinePosition pos) { if (pos.index < 0 || pos.index > SegmentCount - 1) { throw new IndexOutOfRangeException(); } double t = pos.t; double num = t * t; Rfloat2 rfloat = points[pos.index]; Rfloat2 rfloat2 = points[pos.index + 1]; Rfloat2 rfloat3 = tangents[pos.index]; Rfloat2 rfloat4 = tangents[pos.index + 1]; return (6.0 * num - 6.0 * t) * rfloat + (3.0 * num - 4.0 * t + 1.0) * rfloat3 + (-6.0 * num + 6.0 * t) * rfloat2 + (3.0 * num - 2.0 * t) * rfloat4; } public Rfloat2 EvaluateAcceleration(in PolylinePosition pos) { if (pos.index < 0 || pos.index > SegmentCount - 1) { throw new IndexOutOfRangeException(); } double t = pos.t; Rfloat2 rfloat = points[pos.index]; Rfloat2 rfloat2 = points[pos.index + 1]; Rfloat2 rfloat3 = tangents[pos.index]; Rfloat2 rfloat4 = tangents[pos.index + 1]; return (12.0 * t - 6.0) * rfloat + (6.0 * t - 4.0) * rfloat3 + (-12.0 * t + 6.0) * rfloat2 + (6.0 * t - 2.0) * rfloat4; } Rfloat2 ISplineImpl.EvaluatePosition(in PolylinePosition pos) { return EvaluatePosition(in pos); } Rfloat2 ISplineImpl.EvaluateTangent(in PolylinePosition pos) { return EvaluateTangent(in pos); } Rfloat2 ISplineImpl.EvaluateAcceleration(in PolylinePosition pos) { return EvaluateAcceleration(in pos); } } public interface ISplineImpl { int SegmentCount { get; } Rfloat2 EvaluatePosition(in PolylinePosition pos); Rfloat2 EvaluateTangent(in PolylinePosition pos); Rfloat2 EvaluateAcceleration(in PolylinePosition pos); } public class PolylineData { public delegate T Interpolator(double t, T lhs, T rhs); private readonly T[] data; private readonly Interpolator interpolator; public PolylineData(ICollection data, Interpolator interpolator) { this.data = data.ToArray(); this.interpolator = interpolator; } public T Evaluate(PolylinePosition position) { int index = position.index; double t = position.t; if (index < 0 || index >= data.Length - 1) { throw new IndexOutOfRangeException(); } return interpolator(t, data[index], data[index + 1]); } } public readonly struct PolylinePosition { public readonly int index; public readonly double t; public PolylinePosition(int index, double t) { this.index = index; this.t = t; } public static implicit operator PolylinePosition(double progress) { int num = Rmath.FloorToInt(progress); double num2 = progress - (double)num; if (num <= 0 || !(num2 < double.Epsilon)) { return new PolylinePosition(num, num2); } return new PolylinePosition(num - 1, 1.0); } public static implicit operator double(PolylinePosition position) { return (double)position.index + position.t; } } public class Spline { private struct SegmentLengthInfo { public const int SUBSEGMENT_COUNT = 32; public double[] distances; public readonly double Total => distances[31]; } [CompilerGenerated] private sealed class d__14 : IEnumerable, IEnumerable, IEnumerator, IDisposable, IEnumerator { private int <>1__state; private double <>2__current; private int <>l__initialThreadId; private double step; public double <>3__step; double IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__14(int <>1__state) { this.<>1__state = <>1__state; <>l__initialThreadId = Environment.CurrentManagedThreadId; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = 0.0; <>1__state = 1; return true; case 1: <>1__state = -1; break; case 2: <>1__state = -1; break; } <>2__current = step; <>1__state = 2; return true; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { d__14 d__; if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; d__ = this; } else { d__ = new d__14(0); } d__.step = <>3__step; return d__; } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)this).GetEnumerator(); } } [CompilerGenerated] private sealed class d__15 : IEnumerable, IEnumerable, IEnumerator, IDisposable, IEnumerator { private int <>1__state; private double <>2__current; private int <>l__initialThreadId; private Func func; public Func <>3__func; double IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__15(int <>1__state) { this.<>1__state = <>1__state; <>l__initialThreadId = Environment.CurrentManagedThreadId; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { int num = <>1__state; if (num != 0) { if (num != 1) { return false; } <>1__state = -1; } else { <>1__state = -1; } <>2__current = func(); <>1__state = 1; return true; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { d__15 d__; if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; d__ = this; } else { d__ = new d__15(0); } d__.func = <>3__func; return d__; } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)this).GetEnumerator(); } } [CompilerGenerated] private sealed class d__13 : IEnumerable, IEnumerable, IEnumerator, IDisposable, IEnumerator { private int <>1__state; private PolylinePosition <>2__current; private int <>l__initialThreadId; private IEnumerable stepDistances; public IEnumerable <>3__stepDistances; public Spline <>4__this; private int 5__2; private double 5__3; private IEnumerator <>7__wrap3; PolylinePosition IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__13(int <>1__state) { this.<>1__state = <>1__state; <>l__initialThreadId = Environment.CurrentManagedThreadId; } [DebuggerHidden] void IDisposable.Dispose() { int num = <>1__state; if (num == -3 || (uint)(num - 1) <= 1u) { try { } finally { <>m__Finally1(); } } <>7__wrap3 = null; <>1__state = -2; } private bool MoveNext() { bool result; try { int num = <>1__state; Spline spline = <>4__this; switch (num) { default: result = false; goto end_IL_0000; case 0: <>1__state = -1; 5__2 = 0; 5__3 = 0.0; <>7__wrap3 = stepDistances.GetEnumerator(); <>1__state = -3; break; case 1: <>1__state = -3; result = false; <>m__Finally1(); goto end_IL_0000; case 2: <>1__state = -3; break; } if (<>7__wrap3.MoveNext()) { double current = <>7__wrap3.Current; double num2 = 5__3 + current; while (true) { if (num2 > spline.SegmentLength(5__2)) { if (5__2 == spline.SegmentCount - 1) { <>2__current = new PolylinePosition(5__2, 1.0); <>1__state = 1; result = true; break; } num2 -= spline.SegmentLength(5__2); 5__2++; continue; } 5__3 = num2; <>2__current = new PolylinePosition(5__2, spline.InverseEvaluate(5__2, 5__3)); <>1__state = 2; result = true; break; } } else { <>m__Finally1(); <>7__wrap3 = null; result = false; } end_IL_0000:; } catch { //try-fault ((IDisposable)this).Dispose(); throw; } return result; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } private void <>m__Finally1() { <>1__state = -1; if (<>7__wrap3 != null) { <>7__wrap3.Dispose(); } } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { d__13 d__; if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; d__ = this; } else { d__ = new d__13(0) { <>4__this = <>4__this }; } d__.stepDistances = <>3__stepDistances; return d__; } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)this).GetEnumerator(); } } protected readonly ISplineImpl impl; private readonly SegmentLengthInfo[] segmentLengths; public int SegmentCount => impl.SegmentCount; public double Length => segmentLengths.Sum((SegmentLengthInfo lengthInfo) => lengthInfo.Total); public Spline(ISplineImpl impl) { this.impl = impl; segmentLengths = new SegmentLengthInfo[this.impl.SegmentCount]; for (int i = 0; i < segmentLengths.Length; i++) { segmentLengths[i] = CalculateSegmentLength(i); } } public Rfloat2 EvaluatePosition(PolylinePosition pos) { return impl.EvaluatePosition(in pos); } public Rfloat2 EvaluateTangent(PolylinePosition pos) { return impl.EvaluateTangent(in pos); } private SegmentLengthInfo CalculateSegmentLength(int index) { SegmentLengthInfo segmentLengthInfo = default(SegmentLengthInfo); segmentLengthInfo.distances = new double[32]; SegmentLengthInfo result = segmentLengthInfo; Rfloat2[] array = new Rfloat2[33]; for (int i = 0; i < 33; i++) { int num = i; ISplineImpl splineImpl = impl; PolylinePosition pos = new PolylinePosition(index, 1.0 / 32.0 * (double)i); array[num] = splineImpl.EvaluatePosition(in pos); } double num2 = 0.0; for (int j = 0; j < 32; j++) { num2 += (array[j + 1] - array[j]).Length; result.distances[j] = num2; } return result; } private double SegmentLength(int index) { if (index < 0 || index > segmentLengths.Length - 1) { throw new IndexOutOfRangeException(); } return segmentLengths[index].Total; } private double InverseEvaluate(int segmentIndex, double segmentDistance) { SegmentLengthInfo segmentLengthInfo = segmentLengths[segmentIndex]; if (segmentDistance <= 0.0) { return 0.0; } for (int i = 0; i < segmentLengthInfo.distances.Length; i++) { if (!(segmentDistance > segmentLengthInfo.distances[i])) { double num = Rmath.InverseLerp(segmentDistance, (i > 0) ? segmentLengthInfo.distances[i - 1] : 0.0, segmentLengthInfo.distances[i]); return ((double)i + num) / 32.0; } } return 1.0; } [IteratorStateMachine(typeof(d__13))] protected IEnumerable Steps(IEnumerable stepDistances) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__13(-2) { <>4__this = this, <>3__stepDistances = stepDistances }; } [IteratorStateMachine(typeof(d__14))] protected static IEnumerable FixedSteps(double step) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__14(-2) { <>3__step = step }; } [IteratorStateMachine(typeof(d__15))] protected static IEnumerable FuncSteps(Func func) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__15(-2) { <>3__func = func }; } public IEnumerable<(PolylinePosition, Rfloat2, Rfloat2)> Walk(IEnumerable steps) { return from pos in Steps(steps) select (pos, impl.EvaluatePosition(in pos), impl.EvaluateTangent(in pos)); } public IEnumerable<(PolylinePosition, Rfloat2, Rfloat2)> Walk(double step) { return Walk(FixedSteps(step)); } public IEnumerable<(PolylinePosition, Rfloat2, Rfloat2)> Walk(Func stepFunc) { return Walk(FuncSteps(stepFunc)); } } public static class Tangents { public static Rfloat2[] FiniteDifference(IList knots, double tension = 0.5, double balance = 0.0) { Rfloat2[] array = new Rfloat2[knots.Count]; for (int i = 0; i < knots.Count; i++) { if (i == 0) { array[i] = knots[i + 1] - knots[i]; } else if (i == knots.Count - 1) { array[i] = knots[i] - knots[i - 1]; } else { Rfloat2 rfloat = knots[i] - knots[i - 1]; Rfloat2 rfloat2 = knots[i + 1] - knots[i]; double length = rfloat.Length; double length2 = rfloat2.Length; double num = length + length2; double num2 = length2 - length; array[i] += rfloat * (num - balance * num2); array[i] += rfloat2 * (num + balance * num2); array[i] /= num; } array[i] *= 1.0 - tension; } return array; } } } namespace Riverheim.Util.Sdf { public readonly struct DiskSdf : ISdf { private readonly Rfloat2 p; private readonly double r; public BoundingBox ContourBounds => new BoundingBox(p - r * Rfloat2.One, 2.0 * r * Rfloat2.One); public DiskSdf(Rfloat2 p, double r) { this.p = p; this.r = r; } public double Evaluate(Rfloat2 pos) { return (pos - p).Length - r; } } public interface ISdf { BoundingBox ContourBounds { get; } double Evaluate(Rfloat2 pos); } public readonly struct PointSdf : ISdf { private readonly Rfloat2 p; public BoundingBox ContourBounds => new BoundingBox(p, Rfloat2.Zero); public PointSdf(Rfloat2 p) { this.p = p; } public double Evaluate(Rfloat2 pos) { return (pos - p).Length; } } public readonly struct SegmentSdf : ISdf { private readonly Rfloat2 a; private readonly Rfloat2 b; public BoundingBox ContourBounds { get; } public SegmentSdf(Rfloat2 a, Rfloat2 b) { this.a = a; this.b = b; ContourBounds = new BoundingBox(new List { a, b }); } public double Evaluate(Rfloat2 pos) { Rfloat2 rfloat = pos - a; Rfloat2 rfloat2 = b - a; if (rfloat2.Equals(Rfloat2.Zero)) { return rfloat.Length; } double num = Rmath.Clamp01(Rfloat2.Dot(rfloat, rfloat2) / Rfloat2.Dot(rfloat2, rfloat2)); return (rfloat - num * rfloat2).Length; } public double Evaluate(Rfloat2 pos, out double h) { h = 0.0; Rfloat2 rfloat = pos - a; Rfloat2 rfloat2 = b - a; if (rfloat2.Equals(Rfloat2.Zero)) { return rfloat.Length; } h = Rmath.Clamp01(Rfloat2.Dot(rfloat, rfloat2) / Rfloat2.Dot(rfloat2, rfloat2)); return (rfloat - h * rfloat2).Length; } public double EvaluateSquared(Rfloat2 pos, out double h) { h = 0.0; Rfloat2 rfloat = pos - a; Rfloat2 rfloat2 = b - a; if (rfloat2.Equals(Rfloat2.Zero)) { return rfloat.SqrLength; } h = Rmath.Clamp01(Rfloat2.Dot(rfloat, rfloat2) / Rfloat2.Dot(rfloat2, rfloat2)); return (rfloat - h * rfloat2).SqrLength; } } } namespace Riverheim.Util.Random { public static class GradientNoise { private const short INLINE = 256; private static readonly Rfloat2[] gradients = new Rfloat2[16] { new Rfloat2(0.9914448613738104, 0.13052619222005157), new Rfloat2(0.8660254037844387, 0.49999999999999994), new Rfloat2(0.6087614290087207, 0.7933533402912352), new Rfloat2(0.25881904510252074, 0.9659258262890683), new Rfloat2(-0.1305261922200516, 0.9914448613738104), new Rfloat2(-0.4999999999999998, 0.8660254037844387), new Rfloat2(-0.793353340291235, 0.6087614290087209), new Rfloat2(-0.9659258262890682, 0.258819045102521), new Rfloat2(-0.9914448613738105, -0.13052619222005132), new Rfloat2(-0.8660254037844388, -0.4999999999999997), new Rfloat2(-0.6087614290087209, -0.7933533402912349), new Rfloat2(-0.2588190451025215, -0.9659258262890681), new Rfloat2(0.13052619222005127, -0.9914448613738105), new Rfloat2(0.5000000000000001, -0.8660254037844386), new Rfloat2(0.7933533402912349, -0.608761429008721), new Rfloat2(0.9659258262890681, -0.25881904510252157) }; [MethodImpl(MethodImplOptions.AggressiveInlining)] private static double Grad(int x, int y, double u, double v, uint seed) { Rfloat2 rfloat = gradients[HashTools.Squirrel3Hash(x, y, seed) & 0xF]; return rfloat.x * u + rfloat.y * v; } public static double Sample(uint seed, double x, double y) { int num = Rmath.FloorToInt(x); int num2 = Rmath.FloorToInt(y); x -= (double)num; y -= (double)num2; double t = Rmath.Smooth5(x); double t2 = Rmath.Smooth5(y); return 1.4373534528320246 * Rmath.UnclampedLerp(t2, Rmath.UnclampedLerp(t, Grad(num, num2, x, y, seed), Grad(num + 1, num2, x - 1.0, y, seed)), Rmath.UnclampedLerp(t, Grad(num, num2 + 1, x, y - 1.0, seed), Grad(num + 1, num2 + 1, x - 1.0, y - 1.0, seed))); } } public static class HashTools { private const short INLINE = 256; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ulong Squirrel3Hash(ulong position, uint seed) { long num = (long)position * -5392644604628993459L + seed; long num2 = (num ^ (num >>> 8)) + 7557917191629381028L; long num3 = (num2 ^ (num2 << 8)) * 1969978392486266089L; return (ulong)num3 ^ ((ulong)num3 >> 8); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ulong Squirrel3Hash(int x, int y, uint seed) { return Squirrel3Hash((ulong)(x + 198491317 * y), seed); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint SdbmLikeHash(uint seed, string s) { uint num = seed; for (int i = 0; i < s.Length; i++) { num = s[i] + (num << 6) + (num << 16) - num; } if (num == 0) { return seed; } return num; } } public readonly struct Domain { public readonly float LowerBound; public readonly float UpperBound; public float Scale => UpperBound - LowerBound; public float Offset => LowerBound; public Domain(float bound1, float bound2) { LowerBound = Mathf.Min(bound1, bound2); UpperBound = Mathf.Max(bound1, bound2); } public static Domain operator +(Domain d, float scalar) { return new Domain(d.LowerBound + scalar, d.UpperBound + scalar); } public static Domain operator +(Domain lhs, Domain rhs) { return new Domain(lhs.LowerBound + rhs.LowerBound, lhs.UpperBound + rhs.UpperBound); } public static Domain operator -(Domain d, float scalar) { return new Domain(d.LowerBound - scalar, d.UpperBound - scalar); } public static Domain operator -(float scalar, Domain d) { return new Domain(scalar - d.UpperBound, scalar - d.LowerBound); } public static Domain operator -(Domain lhs, Domain rhs) { return new Domain(lhs.LowerBound - rhs.UpperBound, lhs.UpperBound - rhs.LowerBound); } public static Domain operator *(Domain d, float scalar) { return new Domain(d.LowerBound * scalar, d.UpperBound * scalar); } public static Domain operator *(Domain lhs, Domain rhs) { return new Domain(lhs.LowerBound * rhs.LowerBound, lhs.UpperBound * rhs.UpperBound); } public static Domain operator /(Domain d, float scalar) { return d * (1f / scalar); } } public class NoiseField { public delegate float SamplingFunction(Vector2 pos); [Serializable] public struct FractalConfig { public int Octaves; public float Lacunarity; public float Gain; } private readonly SamplingFunction samplingFunction; public readonly Domain Domain; public float Scale => Domain.Scale; public NoiseField(SamplingFunction func, Domain domain) { samplingFunction = func; Domain = domain; } public float Sample(Vector2 pos) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) return samplingFunction(pos); } public static NoiseField operator *(NoiseField f, float m) { return new NoiseField((Vector2 pos) => m * f.Sample(pos), f.Domain * m); } public static NoiseField operator *(float m, NoiseField f) { return f * m; } public static NoiseField operator *(NoiseField lhs, NoiseField rhs) { return new NoiseField((Vector2 pos) => lhs.Sample(pos) * rhs.Sample(pos), lhs.Domain * rhs.Domain); } public static NoiseField operator /(NoiseField f, float m) { return new NoiseField((Vector2 pos) => f.Sample(pos) / m, f.Domain / m); } public static NoiseField operator +(NoiseField f, float m) { return new NoiseField((Vector2 pos) => f.Sample(pos) + m, f.Domain + m); } public static NoiseField operator +(float m, NoiseField f) { return f + m; } public static NoiseField operator +(NoiseField lhs, NoiseField rhs) { return new NoiseField((Vector2 pos) => lhs.Sample(pos) + rhs.Sample(pos), lhs.Domain + rhs.Domain); } public static NoiseField operator -(NoiseField f, float m) { return new NoiseField((Vector2 pos) => f.Sample(pos) - m, f.Domain - m); } public static NoiseField operator -(float scalar, NoiseField f) { return new NoiseField((Vector2 pos) => scalar - f.Sample(pos), scalar - f.Domain); } public static NoiseField operator -(NoiseField lhs, NoiseField rhs) { return new NoiseField((Vector2 pos) => lhs.Sample(pos) - rhs.Sample(pos), lhs.Domain - rhs.Domain); } public NoiseField Normalize01() { return new NoiseField((Vector2 pos) => (samplingFunction(pos) - Domain.Offset) / Domain.Scale, new Domain(0f, 1f)); } public NoiseField Modulate(float ratio) { return new NoiseField((Vector2 pos) => samplingFunction(pos * ratio), Domain); } public NoiseField Fractal(FractalConfig config) { return Fractal(config.Octaves, config.Lacunarity, config.Gain); } public NoiseField Fractal(int octaves, float lacunarity, float gain) { float num = 0f; float num2 = 1f; for (int i = 0; i < octaves; i++) { num += num2; num2 *= gain; } return new NoiseField((Vector2 pos) => Fractal(samplingFunction, pos, octaves, lacunarity, gain), Domain * num); } private static float Fractal(SamplingFunction samplingFunction, Vector2 pos, int octaves, float lacunarity, float gain) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) float num = 0f; float num2 = 1f; float num3 = 1f; for (int i = 0; i < octaves; i++) { num += num3 * samplingFunction(pos * num2); num2 *= lacunarity; num3 *= gain; } return num; } public static NoiseField Perlin(float frequency, uint seed, Rfloat2 offset = default(Rfloat2)) { return new NoiseField((Vector2 pos) => (float)GradientNoise.Sample(seed, (double)(frequency * pos.x) + offset.x, (double)(frequency * pos.y) + offset.y), new Domain(-1f, 1f)); } public static NoiseField BiasedPerlin(float frequency, uint seed, Rfloat2 offset = default(Rfloat2)) { return new NoiseField((Vector2 pos) => 0.5f + 0.5f * (float)GradientNoise.Sample(seed, (double)(frequency * pos.x) + offset.x, (double)(frequency * pos.y) + offset.y), new Domain(0f, 1f)); } public static NoiseField Cellular(uint seed, float frequency, float intensity) { return new NoiseField((Vector2 pos) => (float)VoronoiNoise.Sample(seed, frequency * pos.x, frequency * pos.y, intensity), new Domain(0f, 1f)); } public static NoiseField SmoothCellular(uint seed, float frequency) { return new NoiseField((Vector2 pos) => (float)VoronoiNoise.SampleSmooth(seed, frequency * pos.x, frequency * pos.y), new Domain(-1f, 1f)); } } public class RandomEngine { [StructLayout(LayoutKind.Explicit)] private struct Union { [FieldOffset(0)] public float f; [FieldOffset(0)] public uint u; } private const uint UnitMantissa = 1065353216u; private const int NonFractBitCount = 9; private readonly uint seed; private uint state; public double Value => Nextf(); private static float Utof(uint u) { Union union = default(Union); union.u = u; return union.f; } private static float Float01(uint p) { return Utof(0x3F800000u | (p >> 9)) - 1f; } private static int Int(uint p, int offset, uint range) { return offset + (int)((long)p * (long)range >>> 32); } private static uint XorShift(uint p) { p ^= p << 13; p ^= p >> 17; p ^= p << 5; return p; } public RandomEngine(int seed) : this((uint)seed, XorShift((uint)seed)) { } private RandomEngine(uint seed, string name) : this(seed, HashTools.SdbmLikeHash(seed, name)) { } private RandomEngine(uint seed, uint state) { if (seed == 0 || state == 0) { throw new ArgumentOutOfRangeException("seed"); } this.seed = seed; this.state = state; } public RandomEngine CreateEngine(string name) { return new RandomEngine(seed, name); } private uint Next() { return state = XorShift(state); } private double Nextf() { return Float01(Next()); } private int Nexti(int min, int max) { return Int(Next(), min, (uint)(max - min)); } public double Range(double max) { return Nextf() * max; } public double Range(double min, double max) { return min + Nextf() * (max - min); } public Rfloat2 VRange(double max) { return new Rfloat2(Range(max), Range(max)); } public Rfloat2 VRange(double min, double max) { return new Rfloat2(Range(min, max), Range(min, max)); } public int Range(int max) { return Nexti(0, max); } public int Range(int min, int max) { return Nexti(min, max); } public NoiseField Noise2D(string name, float frequency = 1f) { RandomEngine randomEngine = CreateEngine(name); return NoiseField.Perlin(frequency, randomEngine.Next(), randomEngine.VRange(1.0)); } public NoiseField BiasedNoise2D(string name, float frequency = 1f) { RandomEngine randomEngine = CreateEngine(name); return NoiseField.BiasedPerlin(frequency, randomEngine.Next(), randomEngine.VRange(1.0)); } public NoiseField CellularNoise2D(string name, float frequency = 1f, float intensity = 1f) { return NoiseField.Cellular(CreateEngine(name).Next(), frequency, intensity); } public NoiseField SmoothCellularNoise2D(string name, float frequency = 1f) { return NoiseField.SmoothCellular(CreateEngine(name).Next(), frequency); } public VectorNoiseField WarpNoise(string name, float period, VectorNoiseField.WarpConfig config) { RandomEngine randomEngine = CreateEngine(name); return VectorNoiseField.PerlinWarp(period, config, randomEngine.Next(), randomEngine.Next()); } } public static class RandomEngineExtensions { public static NoiseField MetricNoise2D(this RandomEngine engine, string id, float featureSize) { return engine.Noise2D(id, 1f / featureSize); } public static NoiseField BiasedMetricNoise2D(this RandomEngine engine, string id, float featureSize) { return engine.BiasedNoise2D(id, 1f / featureSize); } } public readonly struct VectorNoiseField { [Serializable] public struct WarpConfig { public float frequency; public float intensity; } private readonly NoiseField x; private readonly NoiseField y; public static VectorNoiseField Perlin(float frequency, float amplitude, uint seedx, uint seedy) { return new VectorNoiseField(amplitude * NoiseField.Perlin(frequency, seedx), amplitude * NoiseField.Perlin(frequency, seedy)); } public static VectorNoiseField PerlinWarp(float period, WarpConfig config, uint seedx, uint seedy) { return Perlin(config.frequency / period, config.intensity * period, seedx, seedy); } private VectorNoiseField(NoiseField x, NoiseField y) { this.x = x; this.y = y; } public Vector2 Sample(Vector2 pos) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) return new Vector2(x.Sample(pos), y.Sample(pos)); } } public static class VoronoiNoise { private static readonly Rfloat2[] displacements = PrecomputeDisplacements(); private static Rfloat2[] PrecomputeDisplacements() { Rfloat2[] array = new Rfloat2[64]; for (int i = 0; i < 64; i++) { double num = (double)i * 2.0 / 64.0 * Math.PI; array[i] = 0.49 * new Rfloat2(Math.Cos(num), Math.Sin(num)); } return array; } public static double Sample(uint seed, double x, double y, double displacementMult = 1.0) { int num = Rmath.FloorToInt(x); int num2 = Rmath.FloorToInt(y); x -= (double)num + 0.5; y -= (double)num2 + 0.5; double num3 = double.MaxValue; double num4 = double.MaxValue; for (int i = -1; i <= 1; i++) { for (int j = -1; j <= 1; j++) { int x2 = num + j; int y2 = num2 + i; Rfloat2 rfloat = displacementMult * displacements[HashTools.Squirrel3Hash(x2, y2, seed) & 0x3F]; double num5 = (double)j - x + rfloat.x; double num6 = (double)i - y + rfloat.y; double val = num5 * num5 + num6 * num6; num4 = Math.Max(Math.Min(num4, val), num3); num3 = Math.Min(num3, val); } } return num3 / num4; } public static double SampleSmooth(uint seed, double x, double y) { int num = Rmath.FloorToInt(x); int num2 = Rmath.FloorToInt(y); x -= (double)num + 0.5; y -= (double)num2 + 0.5; double b = double.MaxValue; double num3 = double.MaxValue; for (int i = -1; i <= 1; i++) { for (int j = -1; j <= 1; j++) { int x2 = num + j; int y2 = num2 + i; Rfloat2 rfloat = displacements[HashTools.Squirrel3Hash(x2, y2, seed) & 0x3F]; double num4 = (double)j - x + rfloat.x; double num5 = (double)i - y + rfloat.y; double num6 = num4 * num4 + num5 * num5; num3 = SmoothMax.Quadratic(SmoothMin.Quadratic(num3, num6, 0.025), b, 0.025); b = SmoothMin.Quadratic(num6, b, 0.025); } } return num3 - 1.0; } } internal class IndexedSet : IEnumerable, IEnumerable { private readonly List items = new List(); private readonly Dictionary index = new Dictionary(); public int Count => items.Count; public bool Contains(T item) { return index.ContainsKey(item); } public void Add(T item) { if (!Contains(item)) { index[item] = items.Count; items.Add(item); } } public void Remove(T item) { if (Contains(item)) { int num = index[item]; if (num != items.Count - 1) { items[num] = items[items.Count - 1]; index[items[num]] = num; } items.RemoveAt(items.Count - 1); index.Remove(item); } } public T Get(int index) { return items[index]; } public IEnumerator GetEnumerator() { return items.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return items.GetEnumerator(); } } public class RandomSet { private readonly RandomEngine random; private readonly IndexedSet items = new IndexedSet(); public int Count => items.Count; public RandomSet(RandomEngine randomEngine) { random = randomEngine; } public RandomSet(RandomEngine randomEngine, IEnumerable collection) : this(randomEngine) { foreach (T item in collection) { Add(item); } } public void Add(T item) { items.Add(item); } public void Remove(T item) { items.Remove(item); } public bool Contains(T item) { return items.Contains(item); } public T Sample() { if (items.Count == 0) { throw new KeyNotFoundException("attempt to sample random value from an empty set!"); } return items.Get(random.Range(items.Count)); } public T Pop() { T val = Sample(); Remove(val); return val; } } public static class WeightedRand { public interface IItem { uint Weight { get; } } public static T Sample(RandomEngine random, ICollection items) where T : IItem { uint num = 0u; foreach (T item in items) { num += item.Weight; } return Sample(random, items, num); } public static T Sample(RandomEngine random, IEnumerable items, uint sum) where T : IItem { uint num = (uint)random.Range((int)sum); foreach (T item in items) { if (item.Weight > num) { return item; } num -= item.Weight; } throw new KeyNotFoundException("attempt to sample random value from an empty set!"); } } public class WeightedRandomSet where T : WeightedRand.IItem { private readonly RandomEngine random; private readonly IndexedSet items = new IndexedSet(); private uint weightSum; public int Count => items.Count; public WeightedRandomSet(RandomEngine randomEngine) { random = randomEngine; } public WeightedRandomSet(RandomEngine randomEngine, IEnumerable items) : this(randomEngine) { foreach (T item in items) { Add(item); } } public void Add(T item) { if (!items.Contains(item)) { items.Add(item); weightSum += item.Weight; } } public void Remove(T item) { if (items.Contains(item)) { items.Remove(item); weightSum -= item.Weight; } } public T Sample() { return WeightedRand.Sample(random, items, weightSum); } public T Pop() { T val = Sample(); Remove(val); return val; } } } namespace Riverheim.Util.Debug { public static class Dump { public static string ToString(object obj, int indent = 0) { Type type = obj.GetType(); if (!type.IsValueType || type.IsPrimitive) { return obj.ToString(); } FieldInfo[] fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public); if (fields.Length == 0) { return type.FullName + " {}\n"; } StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append(type.FullName).Append(" {\n"); FieldInfo[] array = fields; foreach (FieldInfo fieldInfo in array) { stringBuilder.Append(new string(' ', indent + 2)).Append(fieldInfo.Name + " = " + ToString(fieldInfo.GetValue(obj), indent + 2) + ",\n"); } stringBuilder.Append(new string(' ', indent)).Append("}"); return stringBuilder.ToString(); } } public static class Logger { public enum LogLevel { Info, Warning, Error } private static Action impl = delegate(LogLevel _, object message) { Console.WriteLine(message); }; public static void SetLogger(Action logger) { impl = logger; } public static void LogInfo(object message) { impl(LogLevel.Info, message); } public static void LogWarning(object message) { impl(LogLevel.Warning, message); } public static void LogError(object message) { impl(LogLevel.Error, message); } } } namespace Riverheim.Rendering { [Serializable] public struct BiomeRendererConfig { public FineDetailConfig fine; public CoarseDetailConfig coarse; public CoarseDetailMagnitudeConfig coarseDetailMagnitudes; public SwampConfig swamp; public MistlandsConfig mistlands; public VegetationConfig vegetation; } [Serializable] public struct FineDetailConfig { public float largerScale; public float largerScaleMagnitude; public float smallerScale; public float smallerScaleMagnitude; } [Serializable] public struct CoarseDetailConfig { public float largerScale; public float smallerScale; } [Serializable] public struct CoarseDetailMagnitudeConfig { public float meadows; public float forest; public float swamp; public float mountain; public float plains; public float mistlands; } [Serializable] public struct SwampConfig { public float coarseScale; public float pathVerticalCutoff; public float pathBandWidth; public float pathBandDepth; public float pathNoiseScale; public float pathNoiseIntensity; public VectorNoiseField.WarpConfig pathWarp; public float pathBlendingStrength; } [Serializable] public struct MistlandsConfig { public float largerScale; public float largerScaleMultiplier; public float smallerScale; public float smallerScaleMultiplier; public float pow; public float bias; } [Serializable] public struct VegetationConfig { public float noiseScale; public NoiseField.FractalConfig fractal; public float cliffDensityThreshold; public float cliffDensityMargin; public float cliffMaxHeight; public float cliffNoiseScale; public float cliffNoiseThreshold; public float cliffNoiseMargin; } public class BiomeRenderer { private readonly BiomeRendererConfig config; private readonly NoiseField biasedNoise; private readonly NoiseField unbiasedNoise; private readonly NoiseField vegetationNoise; private readonly NoiseField vegetationCliffNoise; private readonly VectorNoiseField swampWarpNoise; private readonly NoiseField swampPathNoise; private const float BINOISE_AVG = 0.25f; private const float COARSE_AVG = 9f / 32f; public BiomeRenderer(RandomEngine random, BiomeRendererConfig config) { this.config = config; biasedNoise = random.BiasedNoise2D("BiomeHeights"); unbiasedNoise = random.Noise2D("BiomeHeights"); vegetationNoise = random.BiasedMetricNoise2D("Vegetation", config.vegetation.noiseScale).Fractal(config.vegetation.fractal); vegetationCliffNoise = random.BiasedMetricNoise2D("VegetationCliff", config.vegetation.cliffNoiseScale); swampWarpNoise = random.WarpNoise("BiomeRendering/Swamp/Warp", config.swamp.pathNoiseScale, config.swamp.pathWarp); swampPathNoise = random.CellularNoise2D("BiomeRendering/Swamp/Paths", 1f / config.swamp.pathNoiseScale, config.swamp.pathNoiseIntensity); } public (float, float) BiomeHeight(Biome biome, Vector2 pos, float baseHeight, ref double meta) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_0112: Unknown result type (might be due to invalid IL or missing references) //IL_0167: Unknown result type (might be due to invalid IL or missing references) float fineDetail = ((biome != 0) ? GetFineDetail(pos) : 0f); CoarseDetailMagnitudeConfig coarseDetailMagnitudes = config.coarseDetailMagnitudes; float num = biome switch { Biome.Meadows => coarseDetailMagnitudes.meadows * GetCoarseDetail(pos), Biome.BlackForest => coarseDetailMagnitudes.forest * GetCoarseDetail(pos), Biome.Swamp => GetSwampCoarseDetail(pos, baseHeight), Biome.Mountain => coarseDetailMagnitudes.mountain * GetCoarseDetail(pos), Biome.Plains => coarseDetailMagnitudes.plains * GetCoarseDetail(pos), Biome.Mistlands => GetMistlandsHeight(pos, baseHeight, out fineDetail, out meta), _ => 0f, }; if (biome == Biome.Ocean) { fineDetail = 0f; } if (biome == Biome.Plains) { fineDetail *= 0.7f; } if (biome == Biome.Meadows) { float num2 = Mathf.InverseLerp(config.vegetation.cliffDensityThreshold + config.vegetation.cliffDensityMargin, config.vegetation.cliffDensityThreshold - config.vegetation.cliffDensityMargin, GetVegetationDensity(pos)); float num3 = Mathf.InverseLerp(config.vegetation.cliffNoiseThreshold - config.vegetation.cliffNoiseMargin, config.vegetation.cliffNoiseThreshold + config.vegetation.cliffNoiseMargin, vegetationCliffNoise.Sample(pos)); num += Mathf.SmoothStep(0f, config.vegetation.cliffMaxHeight * num3, num2); fineDetail *= 0.6f; } return (num, fineDetail); } public float GetVegetationDensity(Vector2 pos) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) return 0.85f * vegetationNoise.Sample(pos); } private float Binoise(Vector2 pos, float featureSize, float multiplier = 2f) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) float num = 1f / featureSize; return biasedNoise.Sample(num * pos) * biasedNoise.Sample(multiplier * num * pos); } private float Trinoise(Vector2 pos, float scale1, float scale2, float blendScale) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) return Mathf.Lerp(unbiasedNoise.Sample(pos / scale1), unbiasedNoise.Sample(pos / scale2), biasedNoise.Sample(pos / blendScale)); } private float GetCoarseDetail(Vector2 pos) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) return Binoise(pos, config.coarse.largerScale) * (1f + 0.5f * Binoise(pos, config.coarse.smallerScale)) - 9f / 32f; } private float GetSwampCoarseDetail(Vector2 pos, float baseHeight) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) float num = config.coarseDetailMagnitudes.swamp * (Binoise(pos, config.swamp.coarseScale) - 0.25f); float num2 = swampPathNoise.Sample(pos + swampWarpNoise.Sample(pos)); num2 = (float)Rmath.Lerp(Rmath.Smooth5(Rmath.InverseLerp(num2, 0.0, config.swamp.pathVerticalCutoff)), (double)config.swamp.pathBandDepth - 0.5 * (double)config.swamp.pathBandWidth, (double)config.swamp.pathBandDepth + 0.5 * (double)config.swamp.pathBandWidth); return (float)SmoothMax.Quadratic(num, num2, config.swamp.pathBlendingStrength); } private float GetMistlandsCoarseDetail(Vector2 pos) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) return Mathf.Pow(Binoise(pos, config.mistlands.largerScale, config.mistlands.largerScaleMultiplier) * (1f + 0.5f * Binoise(pos, config.mistlands.smallerScale, config.mistlands.smallerScaleMultiplier)), config.mistlands.pow); } private float GetFineDetail(Vector2 pos) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0048: 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) return config.fine.largerScaleMagnitude * unbiasedNoise.Sample(pos / config.fine.largerScale) + config.fine.smallerScaleMagnitude * unbiasedNoise.Sample(pos / config.fine.smallerScale); } private float GetMistlandsHeight(Vector2 pos, float baseHeight, out float fineDetail, out double meta) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) float mistlandsCoarseDetail = GetMistlandsCoarseDetail(pos); float num = GetFineDetail(pos) + 0.5f * (config.fine.largerScaleMagnitude + config.fine.smallerScaleMagnitude); float num2 = Mathf.Clamp01(mistlandsCoarseDetail * 7f); meta = Mathf.InverseLerp(0.1f, 0.3f, num2) - 1.2f * num2; float num3 = baseHeight + config.mistlands.bias; num3 += config.coarseDetailMagnitudes.mistlands * mistlandsCoarseDetail; num3 += 2f * num2 * num; float num4 = num3 + num2 * num; num4 = Mathf.Lerp(num4 + 0.5f * biasedNoise.Sample(pos / config.fine.smallerScale), Mathf.Ceil(num4 * 2f) / 2f, num2); fineDetail = num4 - num3; return num3 - baseHeight; } } [Serializable] public struct SplatConfig { public bool isEnabled; public float smaxBlendRange; public float sminBlendRange; public float warpPeriod; public VectorNoiseField.WarpConfig warp; public float plateauNoiseScale; public float plateauNoiseAmplitude; public NoiseField.FractalConfig plateauNoiseFractal; public float plateauSkirtRange; public float plateauSkirtMellowness; } public class SplatRenderer { private readonly SplatConfig config; private readonly SpatialHashGrid spatialIndex; private readonly NoiseField profileNoise; private readonly VectorNoiseField warpNoise; public SplatRenderer(RandomEngine random, SplatConfig config, SpatialHashGrid spatialIndex, Plateau[] plateaus) { this.config = config; this.spatialIndex = spatialIndex; profileNoise = random.BiasedMetricNoise2D("SplatProfile", config.plateauNoiseScale).Fractal(config.plateauNoiseFractal).Normalize01(); warpNoise = random.WarpNoise("SplatWarp", config.warpPeriod, config.warp); AddPlateaus(plateaus); } private void AddPlateaus(Plateau[] plateaus) { //IL_0017: 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_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Unknown result type (might be due to invalid IL or missing references) for (int i = 0; i < plateaus.Length; i++) { Plateau plateau = plateaus[i]; Vector2 val = 0.5f * (plateau.p1 + plateau.p2); float num = Math.Min(this.config.plateauNoiseAmplitude, plateau.radius / 2f); CliffSplat.Config config = default(CliffSplat.Config); config.fixedFlatRange = plateau.radius - num; config.variableFlatRange = num; config.skirtRange = this.config.plateauSkirtRange; config.skirtMellowness = this.config.plateauSkirtMellowness; config.incline = plateau.incline; config.bulge = plateau.bulge; config.inverse = plateau.inverse; CliffSplat.Config config2 = config; spatialIndex.Add(new SplatObject(new CliffSplat(config2, new SegmentSdf(plateau.p1 - val, plateau.p2 - val)), val, plateau.height)); } } public float BlendSplats(Vector2 pos, float height) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0021: 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) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) if (!config.isEnabled) { return height; } pos += warpNoise.Sample(pos); float num = profileNoise.Sample(pos); foreach (SplatObject item in spatialIndex.Query(pos)) { height = item.BlendMode switch { ISplat.SplatBlendMode.SMax => (float)SmoothMax.Cubic(height, item.Render(pos, num), config.smaxBlendRange), ISplat.SplatBlendMode.SMin => (float)SmoothMin.Cubic(height, item.Render(pos, num), config.sminBlendRange), _ => throw new ArgumentOutOfRangeException(), }; } return height; } } public class WorldRenderer { [Serializable] public struct WorldEdgeConfig { public float width; public float offworldDepth; } [Serializable] public struct CliffConfig { public float lowScale; public float lowP1; public float lowP2; public float highScale; public float highP1; public float highP2; } [Serializable] public struct Config { public float interpolationResolution; public float southPolarBeltScale; public VectorNoiseField.WarpConfig biomeWarp; public RiverRenderer.Config rivers; public BiomeRendererConfig biomes; public WorldEdgeConfig worldEdge; public CliffConfig cliffs; public IDWConfig idw; public SplatConfig splats; } [Serializable] public struct IDWConfig { public float power; public float maxDistance; public int maxHops; } public delegate bool BiomeHeightFunc(Biome biome, Rfloat2 pos, out double height, out double meta); private readonly CommonConfig commonConfig; private readonly Config config; private readonly WorldState state; private readonly BicubicInterpolator interpolator; private readonly SpatialHashGrid spatialIndex; private readonly RiverRenderer riverRenderer; private readonly SplatRenderer splatRenderer; private readonly BiomeRenderer biomeRenderer; private readonly VectorNoiseField biomeWarpNoise; private readonly NoiseField cliffHighNoise; private readonly NoiseField cliffLowNoise; private const float MAX_GRADIENT = 8f; private readonly BiomeHeightFunc externalBiomeFunction; public WorldRenderer(RandomEngine random, CommonConfig commonConfig, Config config, WorldState state, BiomeHeightFunc externalBiomeFunction) { this.commonConfig = commonConfig; this.config = config; this.state = state; this.externalBiomeFunction = externalBiomeFunction; interpolator = CreateInterpolator(commonConfig.WorldSize, config.interpolationResolution); spatialIndex = new SpatialHashGrid(commonConfig.TileSpacing); riverRenderer = new RiverRenderer(random.CreateEngine("RiverRenderer"), commonConfig.WorldSize, config.rivers, state.rivers); biomeRenderer = new BiomeRenderer(random.CreateEngine("BiomeRenderer"), config.biomes); splatRenderer = new SplatRenderer(random.CreateEngine("SplatRenderer"), config.splats, spatialIndex, state.plateaus); biomeWarpNoise = random.WarpNoise("BiomeWarp", state.Heightmap.Spacing, config.biomeWarp); cliffHighNoise = random.SmoothCellularNoise2D("CliffHigh", 1f / config.cliffs.highScale); cliffLowNoise = random.SmoothCellularNoise2D("CliffLow", 1f / config.cliffs.lowScale); } private BicubicInterpolator CreateInterpolator(float worldSize, float resolution) { IdwInterpolator idw = new IdwInterpolator(state.Heightmap, config.idw.power, config.idw.maxDistance, config.idw.maxHops); return new BicubicInterpolator(new Rfloat2(worldSize, worldSize), new Rfloat2(resolution, resolution), (Rfloat2 pos) => idw.Interpolate(pos, commonConfig.OceanDepth)); } public double GetBaseHeight(Rfloat2 pos) { return interpolator.Interpolate(pos, commonConfig.OceanDepth); } public Biome GetBiome(Rfloat2 pos) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) Tile? tile = state.Biomes.GetTile((Vector2)pos + biomeWarpNoise.Sample(pos)); if (!tile.HasValue) { return Biome.Ocean; } return tile.GetValueOrDefault().Data; } public double GetBiomeHeight(Biome biome, Rfloat2 pos, out double meta) { //IL_0094: 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_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) if (externalBiomeFunction(biome, pos, out var height, out meta)) { if (biome == Biome.AshLands) { float num = config.southPolarBeltScale * state.polarProximity(pos, PolarProximityType.South); if (num < 1f) { height = Rmath.SmoothStep(num, GetBaseHeight(pos), height); } } return ShapeHeight(pos, (float)height); } meta = 1.0; float num2 = (float)interpolator.Interpolate(pos, out var gradient, commonConfig.OceanDepth); (float, float) tuple = biomeRenderer.BiomeHeight(biome, pos, num2, ref meta); float item = tuple.Item1; float item2 = tuple.Item2; num2 += item; num2 = splatRenderer.BlendSplats(pos, num2); num2 = (float)riverRenderer.BlendRivers(pos, num2); num2 += CliffNoise(pos, (float)Math.Min(8.0, gradient.Length)); num2 += item2; return ShapeHeight(pos, num2); } public double GetVegetationDensity(Rfloat2 pos) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) return biomeRenderer.GetVegetationDensity(pos); } private float CliffNoise(Vector2 pos, float gradient) { //IL_002a: 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) return gradient * ((config.cliffs.highP1 + config.cliffs.highP2 * gradient) * cliffHighNoise.Sample(pos) + (config.cliffs.lowP1 + config.cliffs.lowP2 * gradient) * cliffLowNoise.Sample(pos)); } private float ShapeHeight(Vector2 pos, float height) { return ApplyWorldEdge(height, ((Vector2)(ref pos)).magnitude); } private float ApplyWorldEdge(float height, float distanceFromCenter) { return Mathf.Lerp(height, config.worldEdge.offworldDepth, Mathf.InverseLerp(commonConfig.WorldSize - config.worldEdge.width, commonConfig.WorldSize, distanceFromCenter)); } } } namespace Riverheim.Rendering.Splats { public readonly struct CliffSplat : ISplat { [Serializable] public struct Config { public double fixedFlatRange; public double variableFlatRange; public double skirtRange; public double skirtMellowness; public Rfloat2 incline; public Rfloat2 bulge; public bool inverse; } private readonly Config config; private readonly ISdf sdf; public BoundingBox Bbox { get; } public ISplat.SplatBlendMode BlendMode { get { if (!config.inverse) { return ISplat.SplatBlendMode.SMax; } return ISplat.SplatBlendMode.SMin; } } public CliffSplat(Config config, ISdf sdf) { this.config = config; this.sdf = sdf; BoundingBox contourBounds = sdf.ContourBounds; double num = config.fixedFlatRange + config.variableFlatRange + config.skirtRange; Bbox = new BoundingBox(contourBounds.pos - num, contourBounds.size + 2.0 * num); } public double Render(Rfloat2 pos, double noise) { double num = Rmath.Rectifier(sdf.Evaluate(pos) - config.fixedFlatRange - config.variableFlatRange * noise); double num2 = config.skirtMellowness * Falloff(num / config.skirtRange) * (double)((!config.inverse) ? 1 : (-1)); double num3 = Rfloat2.Dot(pos, config.incline); double num4 = Rfloat2.Dot(pos, config.bulge); return num2 + num3 - num4 * num4; } private static double Falloff(double t) { if (!(t >= 1.0)) { return FalloffBottomless(1.0 - Rmath.Smooth3(t)); } return double.MinValue; } private static double FalloffBottomless(double t) { return (t - 1.0) / t; } } public interface ISplat { public enum SplatBlendMode { SMin, SMax } BoundingBox Bbox { get; } SplatBlendMode BlendMode { get; } double Render(Rfloat2 pos, double noise); } public class SplatObject : IGeometry { private readonly ISplat impl; private readonly Rfloat2 pos; private readonly double height; public BoundingBox Bbox { get; } public ISplat.SplatBlendMode BlendMode => impl.BlendMode; public SplatObject(ISplat impl, Rfloat2 pos, double height) { this.impl = impl; this.pos = pos; this.height = height; BoundingBox bbox = impl.Bbox; bbox.pos += pos; Bbox = bbox; } public bool HitTest(Rfloat2 point) { return Bbox.Contains(point); } public bool HitTest(BoundingBox rect) { return rect.Overlaps(Bbox); } public double Render(Rfloat2 pos, double noise = 0.0) { return impl.Render(pos - this.pos, noise) + height; } } } namespace Riverheim.Rendering.Rivers { public static class RiverBankUtility { public struct QuadraticProfileConfig { public double width; public double steepness; public double minDepth; public double smoothing; } public struct RationalProfileConfig { public double slope; public double w; public double scale; public static RationalProfileConfig FromMetrics(double width, double depth, double steepness) { double num = width / depth; RationalProfileConfig result = default(RationalProfileConfig); result.slope = steepness; result.w = num * (steepness * num - 1.0); result.scale = depth; return result; } public static RationalProfileConfig Lerp(double t, in RationalProfileConfig lhs, in RationalProfileConfig rhs) { RationalProfileConfig result = default(RationalProfileConfig); result.slope = Rmath.Lerp(t, lhs.slope, rhs.slope); result.w = Rmath.Lerp(t, lhs.w, rhs.w); result.scale = Rmath.Lerp(t, lhs.scale, rhs.scale); return result; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double QuadraticProfile(double distance, in QuadraticProfileConfig config) { double num = distance / config.width; double num2 = num * num - 1.0; double num3 = config.width * config.steepness; if (num3 >= config.minDepth) { return num2 * num3; } return SmoothMin.Cubic(num2 * num3, num2 * config.minDepth, config.smoothing); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double QuadraticProfileDerivative(double distance, in QuadraticProfileConfig config) { double num = distance / (config.width * config.width); return 2.0 * num * config.steepness; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double QuadraticProfileRange(double targetHeight, in QuadraticProfileConfig config) { return Math.Sqrt(config.width * targetHeight / config.steepness + 0.5 * config.width * config.width); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double RationalProfile(double distance, in RationalProfileConfig config) { double num = distance / config.scale; return config.scale * (config.slope * num * num / (num + config.w) - 1.0); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double RationalProfileDerivative(double distance, in RationalProfileConfig config) { double num = distance / config.scale; return config.slope * num * (num + 2.0 * config.w) / ((num + config.w) * (num + config.w)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double RationalProfileRange(double targetHeight, in RationalProfileConfig config) { double num = (targetHeight + config.scale) / config.scale; return config.scale / (2.0 * config.slope) * (num + Math.Sqrt(num * num + 4.0 * num * config.slope * config.w)); } } public struct RiverPointData { public double width; public double blendingDepth; public RiverBankUtility.RationalProfileConfig rationalProfile; } public class RiverRenderer { [Serializable] public struct WidthConfig { public float depthPower; public float minShrinking; } [Serializable] public struct ProfileConfig { public bool useRationalProfile; public float minDepth; public float steepness; public float maxBankHeight; public float waterlineSmoothness; public float rationalProfileWidthToDepth; public float widthRangeStart; public float widthRangeEnd; public float steepnessRangeStart; public float steepnessRangeEnd; public float bankSmoothness; public float noiseScale; public float noiseAmplitude; public float noiseKickInStart; public float noiseKickInEnd; public float noiseCompensation; public NoiseField.FractalConfig noiseFractal; } [Serializable] public struct Config { public float spatialIndexSpacing; public float sdfMergingRange; public float meanderAmplitude; public float meanderPeriod; public WidthConfig width; public TesselationConfig tesselation; public ProfileConfig profile; } [CompilerGenerated] private sealed class d__14 : IEnumerable<(int, double, PolylinePosition)>, IEnumerable, IEnumerator<(int, double, PolylinePosition)>, IDisposable, IEnumerator { private int <>1__state; private (int, double, PolylinePosition) <>2__current; private int <>l__initialThreadId; public RiverRenderer <>4__this; private Rfloat2 pos; public Rfloat2 <>3__pos; private RiverSpatialIndex.LocalRiver[] <>7__wrap1; private int <>7__wrap2; (int, double, PolylinePosition) IEnumerator<(int, double, PolylinePosition)>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__14(int <>1__state) { this.<>1__state = <>1__state; <>l__initialThreadId = Environment.CurrentManagedThreadId; } [DebuggerHidden] void IDisposable.Dispose() { <>7__wrap1 = null; <>1__state = -2; } private bool MoveNext() { int num = <>1__state; RiverRenderer riverRenderer = <>4__this; if (num != 0) { if (num != 1) { return false; } <>1__state = -1; goto IL_0215; } <>1__state = -1; <>7__wrap1 = riverRenderer.riverSpatialIndex.Query(pos); <>7__wrap2 = 0; goto IL_0223; IL_0215: <>7__wrap2++; goto IL_0223; IL_0223: if (<>7__wrap2 < <>7__wrap1.Length) { RiverSpatialIndex.LocalRiver localRiver = <>7__wrap1[<>7__wrap2]; RiverSegment[] segments = localRiver.segments; double[] array = new double[segments.Length]; double[] array2 = new double[segments.Length]; int num2 = -1; double num3 = double.MaxValue; for (int i = 0; i < segments.Length; i++) { array[i] = segments[i].sdf.EvaluateSquared(pos, out var h); double num4 = Rmath.Lerp(h, segments[i].r1, segments[i].r2); if (array[i] > num4 * num4) { array[i] = double.MaxValue; continue; } if (array[i] < num3) { num2 = i; num3 = array[i]; } array2[i] = h; } if (num2 != -1) { double num5 = Rmath.Lerp(array2[num2], segments[num2].splinePos1, segments[num2].splinePos2); double num6 = 1.0; double num7 = Math.Sqrt(num3); for (int j = 0; j < segments.Length; j++) { if (j != num2) { double num8 = Math.Sqrt(array[j]) - num7; if (!(num8 > (double)riverRenderer.config.sdfMergingRange)) { double num9 = 1.0 - num8 / (double)riverRenderer.config.sdfMergingRange; double num10 = num9 * num9 * num9; num5 += Rmath.Lerp(array2[j], segments[j].splinePos1, segments[j].splinePos2) * num10; num6 += num10; } } } num5 /= num6; <>2__current = (localRiver.id, num7, num5); <>1__state = 1; return true; } goto IL_0215; } <>7__wrap1 = null; return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator<(int, double, PolylinePosition)> IEnumerable<(int, double, PolylinePosition)>.GetEnumerator() { d__14 d__; if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; d__ = this; } else { d__ = new d__14(0) { <>4__this = <>4__this }; } d__.pos = <>3__pos; return d__; } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable<(int, double, PolylinePosition)>)this).GetEnumerator(); } } private readonly Config config; private readonly RiverSpatialIndex riverSpatialIndex; private readonly NoiseField riverProfileNoise; private readonly Dictionary> riverData; public RiverRenderer(RandomEngine random, double worldSize, Config config, List rivers) { this.config = config; riverData = BuildRiverData(rivers); riverSpatialIndex = BuildSpatialIndex(worldSize, rivers); riverProfileNoise = random.MetricNoise2D("RiverProfile", config.profile.noiseScale); float scale = riverProfileNoise.Scale; riverProfileNoise = riverProfileNoise.Fractal(config.profile.noiseFractal); riverProfileNoise *= scale / riverProfileNoise.Scale; } private Dictionary> BuildRiverData(List rivers) { Dictionary> dictionary = new Dictionary>(); foreach (River river in rivers) { dictionary[river.id] = new PolylineData(river.vertices.Select(MakeRiverPointData).ToList(), delegate(double t, RiverPointData lhs, RiverPointData rhs) { RiverPointData result = default(RiverPointData); result.width = Rmath.Lerp(t, lhs.width, rhs.width); result.blendingDepth = Rmath.Lerp(t, lhs.blendingDepth, rhs.blendingDepth); result.rationalProfile = RiverBankUtility.RationalProfileConfig.Lerp(t, in lhs.rationalProfile, in rhs.rationalProfile); return result; }); } return dictionary; } private RiverSpatialIndex BuildSpatialIndex(double worldSize, List rivers) { RiverSpatialIndex.Builder builder = new RiverSpatialIndex.Builder(config.spatialIndexSpacing, BoundingBox.ZeroCentered(new Rfloat2(2.0 * worldSize))); RiverTesselator riverTesselator = new RiverTesselator(config.tesselation); foreach (River river in rivers) { (PolylinePosition, RiverVertex)[] array = riverTesselator.GenerateVertices(river.vertices, RiverMeander).ToArray(); foreach (RiverSegment item in array.Zip(array.Skip(1), MakeRiverSegment)) { builder.Add(river.id, item); } } return builder.Build(); } private double RiverPointWidth(RiverVertex vertex) { double num = Rmath.Lerp(Math.Pow(vertex.data.depth, config.width.depthPower), config.width.minShrinking, 1.0); return 0.5 * (double)vertex.data.width * num; } private RiverPointData MakeRiverPointData(RiverVertex vertex) { double width = RiverPointWidth(vertex); RiverPointData result = default(RiverPointData); result.width = width; result.blendingDepth = vertex.data.depth; result.rationalProfile = RationalProfileConfig(width); return result; } private RiverBankUtility.RationalProfileConfig RationalProfileConfig(double width) { double b = width / (double)config.profile.rationalProfileWidthToDepth; return RiverBankUtility.RationalProfileConfig.FromMetrics(width, SmoothMax.Cubic(config.profile.minDepth, b, config.profile.waterlineSmoothness), Rmath.Lerp(Rmath.InverseLerp(width, config.profile.widthRangeStart, config.profile.widthRangeEnd), config.profile.steepnessRangeStart, config.profile.steepnessRangeEnd)); } private RiverSegment MakeRiverSegment((PolylinePosition, RiverVertex) p1, (PolylinePosition, RiverVertex) p2) { //IL_002c: 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 r = RiverBankRange(RiverPointWidth(p1.Item2)); double r2 = RiverBankRange(RiverPointWidth(p2.Item2)); return new RiverSegment(p1.Item2.pos, p2.Item2.pos, p1.Item1, p2.Item1, r, r2); } [IteratorStateMachine(typeof(d__14))] private IEnumerable<(int, double, PolylinePosition)> GetRivers(Rfloat2 pos) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__14(-2) { <>4__this = this, <>3__pos = pos }; } public double BlendRivers(Rfloat2 pos, double height) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) float num = Math.Abs(riverProfileNoise.Sample(pos)) - config.profile.noiseCompensation; foreach (var river in GetRivers(pos)) { int item = river.Item1; double item2 = river.Item2; PolylinePosition item3 = river.Item3; height = BlendRiver(height, item2, riverData[item].Evaluate(item3), num); } return height; } private double BlendRiver(double height, double distance, RiverPointData data, double noiseValue) { double val = (double)config.profile.noiseAmplitude * Rmath.InverseLerp(distance, data.width * (double)config.profile.noiseKickInStart, data.width * (double)config.profile.noiseKickInEnd); val = Math.Min(val, 0.5 * distance); return SmoothMin.Cubic(RiverBankProfile(distance + noiseValue * val, data) + (1.0 - data.blendingDepth) * height, height, config.profile.bankSmoothness); } [MethodImpl(MethodImplOptions.AggressiveInlining)] private double RiverBankProfile(double distance, RiverPointData data) { if (config.profile.useRationalProfile) { return RiverBankUtility.RationalProfile(distance, in data.rationalProfile); } RiverBankUtility.QuadraticProfileConfig quadraticProfileConfig = new RiverBankUtility.QuadraticProfileConfig { width = data.width, steepness = config.profile.steepness, minDepth = data.blendingDepth * (double)config.profile.minDepth, smoothing = config.profile.waterlineSmoothness }; return RiverBankUtility.QuadraticProfile(distance, in quadraticProfileConfig); } private double RiverBankRange(double width) { if (config.profile.useRationalProfile) { double targetHeight = config.profile.maxBankHeight; RiverBankUtility.RationalProfileConfig rationalProfileConfig = RationalProfileConfig(width); return RiverBankUtility.RationalProfileRange(targetHeight, in rationalProfileConfig); } double targetHeight2 = config.profile.maxBankHeight; RiverBankUtility.QuadraticProfileConfig quadraticProfileConfig = new RiverBankUtility.QuadraticProfileConfig { width = width, steepness = config.profile.steepness, minDepth = config.profile.minDepth, smoothing = config.profile.waterlineSmoothness }; return RiverBankUtility.QuadraticProfileRange(targetHeight2, in quadraticProfileConfig); } private float RiverMeander(float distance, float width) { float t = distance / config.meanderPeriod; return config.meanderAmplitude * width * Meander(t); } private static float Meander(float t) { return (float)(Math.Sin(Math.PI * (double)t) + 0.5 * Math.Sin(2f * t)) / 1.5f; } } public readonly struct RiverSegment { public readonly double splinePos1; public readonly double splinePos2; public readonly double r1; public readonly double r2; public readonly SegmentSdf sdf; public BoundingBox Bbox { get; } public RiverSegment(Rfloat2 p1, Rfloat2 p2, double splinePos1, double splinePos2, double r1, double r2) { this.splinePos1 = splinePos1; this.splinePos2 = splinePos2; this.r1 = r1; this.r2 = r2; sdf = new SegmentSdf(p1, p2); double num = Math.Max(r1, r2); BoundingBox boundingBox = new BoundingBox(new List { p1, p2 }); Bbox = new BoundingBox(boundingBox.pos - num, boundingBox.size + 2.0 * num); } public bool HitTest(BoundingBox rect) { return rect.Overlaps(Bbox); } } public class RiverSpatialIndex { public readonly struct LocalRiver { public readonly int id; public readonly RiverSegment[] segments; public LocalRiver(int id, RiverSegment[] segments) { this.id = id; this.segments = segments; } } public class Builder { private readonly double cellSize; private readonly Rfloat2 offset; private readonly Rint2 size; private readonly Dictionary>[] segments; public Builder(double cellSize, BoundingBox bounds) { this.cellSize = cellSize; offset = bounds.pos; size = (bounds.size / cellSize).CeilToInt(); segments = new Dictionary>[size.x * size.y]; for (int i = 0; i < segments.Length; i++) { segments[i] = new Dictionary>(); } } public RiverSpatialIndex Build() { LocalRiver[][] array = new LocalRiver[size.x * size.y][]; for (int i = 0; i < segments.Length; i++) { List list = new List(); foreach (int key in segments[i].Keys) { list.Add(new LocalRiver(key, segments[i][key].ToArray())); } list.Sort(delegate(LocalRiver a, LocalRiver b) { int id = a.id; return id.CompareTo(b.id); }); array[i] = list.ToArray(); } return new RiverSpatialIndex(cellSize, offset, size, array); } public void Add(int riverId, RiverSegment segment) { BoundingBox bbox = segment.Bbox; bbox.x -= offset.x; bbox.y -= offset.y; for (int i = Index(bbox.x); i <= Index(bbox.x + bbox.w); i++) { for (int j = Index(bbox.y); j <= Index(bbox.y + bbox.h); j++) { TryAdd(new Rint2(i, j), riverId, segment); } } } private void TryAdd(Rint2 index, int riverId, RiverSegment segment) { if (segment.HitTest(CellRect(index)) && index.x >= 0 && index.y >= 0 && index.x < size.x && index.y < size.y) { Dictionary> dictionary = segments[index.x * size.y + index.y]; if (!dictionary.ContainsKey(riverId)) { dictionary.Add(riverId, new List()); } dictionary[riverId].Add(segment); } } private int Index(double x) { return Rmath.FloorToInt(x / cellSize); } private BoundingBox CellRect(Rint2 index) { return new BoundingBox(cellSize * (Rfloat2)index + offset, cellSize * Rfloat2.One); } } private readonly double cellSize; private readonly Rfloat2 offset; private readonly Rint2 size; private readonly LocalRiver[][] data; private readonly LocalRiver[] sentinel; private RiverSpatialIndex(double cellSize, Rfloat2 offset, Rint2 size, LocalRiver[][] data) { this.cellSize = cellSize; this.offset = offset; this.size = size; this.data = data; sentinel = Array.Empty(); } public LocalRiver[] Query(Rfloat2 pos) { pos -= offset; int num = Index(pos.x); int num2 = Index(pos.y); if (num < 0 || num >= size.x || num2 < 0 || num2 >= size.y) { return sentinel; } return data[num * size.y + num2]; } [MethodImpl(MethodImplOptions.AggressiveInlining)] private int Index(double x) { return Rmath.FloorToInt(x / cellSize); } } [Serializable] public struct TesselationConfig { public float minStep; public float maxStep; public float stepRatio; public float tension; public float balance; } public class RiverTesselator { public delegate float MeanderFunc(float distance, float width); [CompilerGenerated] private sealed class <>c__DisplayClass3_0 { public double step; public Func <>9__3; internal double b__3() { return step; } } [CompilerGenerated] private sealed class d__3 : IEnumerable<(PolylinePosition, RiverVertex)>, IEnumerable, IEnumerator<(PolylinePosition, RiverVertex)>, IDisposable, IEnumerator { private int <>1__state; private (PolylinePosition, RiverVertex) <>2__current; private int <>l__initialThreadId; private List river; public List <>3__river; public RiverTesselator <>4__this; private MeanderFunc meanderFunc; public MeanderFunc <>3__meanderFunc; private <>c__DisplayClass3_0 <>8__1; private PolylineData 5__2; private double 5__3; private IEnumerator<(PolylinePosition, Rfloat2, Rfloat2)> <>7__wrap3; private RiverVertexData 5__5; (PolylinePosition, RiverVertex) IEnumerator<(PolylinePosition, RiverVertex)>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__3(int <>1__state) { this.<>1__state = <>1__state; <>l__initialThreadId = Environment.CurrentManagedThreadId; } [DebuggerHidden] void IDisposable.Dispose() { int num = <>1__state; if (num == -3 || num == 1) { try { } finally { <>m__Finally1(); } } <>8__1 = null; 5__2 = null; <>7__wrap3 = null; <>1__state = -2; } private bool MoveNext() { //IL_01f4: Unknown result type (might be due to invalid IL or missing references) //IL_01f9: Unknown result type (might be due to invalid IL or missing references) try { int num = <>1__state; RiverTesselator riverTesselator = <>4__this; switch (num) { default: return false; case 0: { <>1__state = -1; <>8__1 = new <>c__DisplayClass3_0(); List list = ((IEnumerable)river).Select((Func)((RiverVertex vertex) => vertex.pos)).ToList(); 5__2 = new PolylineData(river.Select((RiverVertex vertex) => vertex.data).ToList(), delegate(double t, RiverVertexData lhs, RiverVertexData rhs) { RiverVertexData result = default(RiverVertexData); result.width = (float)Rmath.UnclampedLerp(t, lhs.width, rhs.width); result.depth = (float)Rmath.UnclampedLerp(t, lhs.depth, rhs.depth); result.meanderiness = (float)Rmath.UnclampedLerp(t, lhs.meanderiness, rhs.meanderiness); return result; }); Spline spline = new Spline(new HermiteSplineImpl(list, Tangents.FiniteDifference(list, riverTesselator.config.tension, riverTesselator.config.balance))); 5__3 = 0.0; <>8__1.step = 0.0; <>7__wrap3 = spline.Walk(() => <>8__1.step).GetEnumerator(); <>1__state = -3; break; } case 1: <>1__state = -3; <>8__1.step = Math.Min(riverTesselator.config.maxStep, Math.Max(riverTesselator.config.minStep, 5__5.width * riverTesselator.config.stepRatio)); 5__3 += <>8__1.step / (double)5__5.width; break; } if (<>7__wrap3.MoveNext()) { (PolylinePosition, Rfloat2, Rfloat2) current = <>7__wrap3.Current; PolylinePosition item = current.Item1; Rfloat2 item2 = current.Item2; Rfloat2 item3 = current.Item3; 5__5 = 5__2.Evaluate(item); Rfloat2 normalized = new Rfloat2(0.0 - item3.y, item3.x).Normalized; Rfloat2 rfloat = 5__5.meanderiness * meanderFunc((float)5__3, 5__5.width) * normalized; <>2__current = (item, new RiverVertex { pos = item2 + rfloat, data = 5__5 }); <>1__state = 1; return true; } <>m__Finally1(); <>7__wrap3 = null; return false; } catch { //try-fault ((IDisposable)this).Dispose(); throw; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } private void <>m__Finally1() { <>1__state = -1; if (<>7__wrap3 != null) { <>7__wrap3.Dispose(); } } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator<(PolylinePosition, RiverVertex)> IEnumerable<(PolylinePosition, RiverVertex)>.GetEnumerator() { d__3 d__; if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; d__ = this; } else { d__ = new d__3(0) { <>4__this = <>4__this }; } d__.river = <>3__river; d__.meanderFunc = <>3__meanderFunc; return d__; } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable<(PolylinePosition, RiverVertex)>)this).GetEnumerator(); } } private readonly TesselationConfig config; public RiverTesselator(TesselationConfig config) { this.config = config; } [IteratorStateMachine(typeof(d__3))] public IEnumerable<(PolylinePosition, RiverVertex)> GenerateVertices(List river, MeanderFunc meanderFunc) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__3(-2) { <>4__this = this, <>3__river = river, <>3__meanderFunc = meanderFunc }; } } } namespace Riverheim.Pipeline { [AttributeUsage(AttributeTargets.Class)] internal class Producer : Attribute { public readonly Type Computation; public Producer(Type computation) { Computation = computation ?? throw new PipelineError("computation must not be null"); } } [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] internal class Consumer : Attribute { public readonly Type Computation; public Consumer(Type computation) { Computation = computation ?? throw new PipelineError("computation must not be null"); } } [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] internal class ConfiguredBy : Attribute { public readonly Type Config; public ConfiguredBy(Type config) { Config = config ?? throw new PipelineError("config must not be null"); } } [AttributeUsage(AttributeTargets.Class)] internal class Randomized : Attribute { public readonly string Key; public Randomized(string key) { Key = key ?? throw new PipelineError("randomize key must not be null"); } } internal class ComponentWrapper { private readonly Type componentType; private readonly ConstructorInfo constructorInfo; private readonly MethodInfo computeMethodInfo; public readonly List DependsOn = new List(); public readonly List Blocks = new List(); public object Cache { get; private set; } public Type Result => componentType.GetCustomAttribute().Computation; public IEnumerable Configs => from attr in componentType.GetCustomAttributes() select attr.Config; public IEnumerable Dependencies => from attr in componentType.GetCustomAttributes() select attr.Computation; public ComponentWrapper(Type componentType) { this.componentType = componentType; List list = new List(); if (componentType.GetCustomAttribute() != null) { list.Add(typeof(RandomEngine)); } list.AddRange(Configs); list.AddRange(Dependencies); constructorInfo = componentType.GetConstructor(list.ToArray()); if (constructorInfo == null) { throw new PipelineError("Can't find constructor for component " + componentType.Name + " producing " + Result.Name); } computeMethodInfo = componentType.GetMethod("Compute", BindingFlags.Instance | BindingFlags.Public, null, CallingConventions.Any, new Type[0], null); if (computeMethodInfo == null || computeMethodInfo.ReturnType != Result) { throw new PipelineError("Can't find 'Compute' method for component " + componentType.Name + " producing " + Result.Name); } Cache = null; } public void Compute(RandomEngine random, IEnumerable configs, IEnumerable dependencies, out bool cached) { cached = Cache != null; if (!cached) { List list = new List(); Randomized customAttribute = componentType.GetCustomAttribute(); if (customAttribute != null) { list.Add((customAttribute.Key != null) ? random.CreateEngine(customAttribute.Key) : random); } list.AddRange(configs); list.AddRange(dependencies); object obj = constructorInfo.Invoke(list.ToArray()); Cache = computeMethodInfo.Invoke(obj, new object[0]); } } public void InvalidateCache() { Cache = null; Blocks.ForEach(delegate(ComponentWrapper blocked) { blocked.InvalidateCache(); }); } } public class GeneratorPipeline { private readonly Dictionary components = new Dictionary(); private readonly List computationRoots = new List(); private readonly Dictionary> configDependencies; private readonly Dictionary configCache = new Dictionary(); private int? prevSeed; public bool Verbose; public GeneratorPipeline(params Type[] resultTypes) { Dictionary dictionary = GetComponents(GetType().Assembly, resultTypes.ToList()); foreach (Type key in dictionary.Keys) { components[key] = new ComponentWrapper(dictionary[key]); } foreach (ComponentWrapper value in components.Values) { foreach (Type dependency in value.Dependencies) { ComponentWrapper componentWrapper = components[dependency]; value.DependsOn.Add(componentWrapper); componentWrapper.Blocks.Add(value); } if (value.DependsOn.Count == 0) { computationRoots.Add(value); } } configDependencies = GetConfigDependencies(components); foreach (Type key2 in configDependencies.Keys) { configCache[key2] = null; } } public static GeneratorPipeline CreateDependencyPipeline(Type producer) { return new GeneratorPipeline(GetDependencies(producer).ToArray()); } private static IEnumerable GetDependencies(Type producer) { return from attr in producer.GetCustomAttributes() select attr.Computation; } private static Dictionary GetComponents(Assembly assembly, List outputs) { Dictionary dictionary = new Dictionary(); Type[] types = assembly.GetTypes(); foreach (Type type in types) { Producer customAttribute = type.GetCustomAttribute(); if (customAttribute != null) { Type computation = customAttribute.Computation; if (dictionary.TryGetValue(computation, out var value)) { throw new PipelineError($"Ambiguous component producing '{computation}': '{type}' and '{value}'"); } dictionary[computation] = type; } } HashSet computations = new HashSet(); foreach (Type output in outputs) { computations.UnionWith(GetAllComputations(output, dictionary)); } return dictionary.Where((KeyValuePair kv) => computations.Contains(kv.Key)).ToDictionary((KeyValuePair kv) => kv.Key, (KeyValuePair kv) => kv.Value); } private static HashSet GetAllComputations(Type computation, Dictionary allComponents) { if (!allComponents.ContainsKey(computation)) { throw new PipelineError("No known component producing '" + computation.Name + "'"); } HashSet hashSet = new HashSet { computation }; foreach (Type dependency in GetDependencies(allComponents[computation])) { hashSet.UnionWith(GetAllComputations(dependency, allComponents)); } return hashSet; } private static Dictionary> GetConfigDependencies(Dictionary components) { Dictionary> dictionary = new Dictionary>(); foreach (ComponentWrapper value in components.Values) { foreach (Type config in value.Configs) { if (!dictionary.ContainsKey(config)) { dictionary[config] = new List(); } dictionary[config].Add(value); } } return dictionary; } public T GetResult() { return (T)components[typeof(T)].Cache; } public void Compute(int seed, ValueType masterConfig) { List list = new List(); FieldInfo[] fields = masterConfig.GetType().GetFields(BindingFlags.Instance | BindingFlags.Public); foreach (FieldInfo fieldInfo in fields) { list.Add(fieldInfo.GetValue(masterConfig)); } Compute(seed, list); } public void Compute(int seed, List configs) { if (seed != prevSeed) { foreach (ComponentWrapper computationRoot in computationRoots) { computationRoot.InvalidateCache(); } } prevSeed = seed; UpdateConfigs(configs); ComputeAll(new RandomEngine(seed)); } private void ComputeAll(RandomEngine random) { DateTime now = DateTime.Now; HashSet completed = new HashSet(); Queue queue = new Queue(); foreach (ComponentWrapper computationRoot in computationRoots) { queue.Enqueue(computationRoot); } while (queue.Count > 0) { ComponentWrapper componentWrapper = queue.Dequeue(); Compute(componentWrapper, random); completed.Add(componentWrapper.Result); componentWrapper.Blocks.ForEach(delegate(ComponentWrapper blocked) { if (blocked.DependsOn.All((ComponentWrapper dep) => completed.Contains(dep.Result)) && !completed.Contains(blocked.Result)) { queue.Enqueue(blocked); } }); } Log($"Done computing pipeline in {(DateTime.Now - now).TotalMilliseconds:0.} ms"); } private void Compute(ComponentWrapper component, RandomEngine random) { DateTime now = DateTime.Now; component.Compute(random, component.Configs.Select((Type type) => configCache[type]), component.Dependencies.Select((Type type) => components[type].Cache), out var cached); Log($"Done computing {component.Result.Name} in {(DateTime.Now - now).TotalMilliseconds:0.} ms" + (cached ? " (cached)" : "")); } private void UpdateConfigs(List configList) { Dictionary dictionary = new Dictionary(); foreach (object config in configList) { dictionary[config.GetType()] = config; } foreach (Type item in configCache.Keys.ToList()) { if (!dictionary.TryGetValue(item, out var value)) { throw new PipelineError("Missing config '" + item.Name + "'"); } if (!value.Equals(configCache[item])) { configDependencies[item].ForEach(delegate(ComponentWrapper component) { component.InvalidateCache(); }); } configCache[item] = dictionary[item]; } } private void Log(string msg) { if (Verbose) { Logger.LogInfo(msg); } } } public class GeneratorPipeline : GeneratorPipeline { public GeneratorPipeline() : base(typeof(T)) { } public T GetResult() { return GetResult(); } } internal class PipelineError : Exception { public PipelineError(string msg) : base(msg) { } } } namespace DelaunatorSharp { internal class <71c98ed0-65e2-4d7b-9d9e-046a047365d7>Delaunator { private readonly double EPSILON = Math.Pow(2.0, -52.0); private readonly int[] EDGE_STACK = new int[512]; private readonly int hashSize; private readonly int[] hullPrev; private readonly int[] hullNext; private readonly int[] hullTri; private readonly int[] hullHash; private double cx; private double cy; private int trianglesLen; private readonly double[] coords; private readonly int hullStart; private readonly int hullSize; public int[] Triangles { get; private set; } public int[] Halfedges { get; private set; } public <71c98ed0-65e2-4d7b-9d9e-046a047365d7>IPoint[] Points { get; private set; } public int[] Hull { get; private set; } public <71c98ed0-65e2-4d7b-9d9e-046a047365d7>Delaunator(<71c98ed0-65e2-4d7b-9d9e-046a047365d7>IPoint[] points) { if (points.Length < 3) { throw new ArgumentOutOfRangeException("Need at least 3 points"); } Points = points; coords = new double[Points.Length * 2]; for (int i = 0; i < Points.Length; i++) { <71c98ed0-65e2-4d7b-9d9e-046a047365d7>IPoint <71c98ed0-65e2-4d7b-9d9e-046a047365d7>IPoint2 = Points[i]; coords[2 * i] = <71c98ed0-65e2-4d7b-9d9e-046a047365d7>IPoint2.X; coords[2 * i + 1] = <71c98ed0-65e2-4d7b-9d9e-046a047365d7>IPoint2.Y; } int num = points.Length; int num2 = 2 * num - 5; Triangles = new int[num2 * 3]; Halfedges = new int[num2 * 3]; hashSize = (int)Math.Ceiling(Math.Sqrt(num)); hullPrev = new int[num]; hullNext = new int[num]; hullTri = new int[num]; hullHash = new int[hashSize]; int[] array = new int[num]; double num3 = double.PositiveInfinity; double num4 = double.PositiveInfinity; double num5 = double.NegativeInfinity; double num6 = double.NegativeInfinity; for (int j = 0; j < num; j++) { double num7 = coords[2 * j]; double num8 = coords[2 * j + 1]; if (num7 < num3) { num3 = num7; } if (num8 < num4) { num4 = num8; } if (num7 > num5) { num5 = num7; } if (num8 > num6) { num6 = num8; } array[j] = j; } double ax = (num3 + num5) / 2.0; double ay = (num4 + num6) / 2.0; double num9 = double.PositiveInfinity; int num10 = 0; int num11 = 0; int num12 = 0; for (int k = 0; k < num; k++) { double num13 = Dist(ax, ay, coords[2 * k], coords[2 * k + 1]); if (num13 < num9) { num10 = k; num9 = num13; } } double num14 = coords[2 * num10]; double num15 = coords[2 * num10 + 1]; num9 = double.PositiveInfinity; for (int l = 0; l < num; l++) { if (l != num10) { double num16 = Dist(num14, num15, coords[2 * l], coords[2 * l + 1]); if (num16 < num9 && num16 > 0.0) { num11 = l; num9 = num16; } } } double num17 = coords[2 * num11]; double num18 = coords[2 * num11 + 1]; double num19 = double.PositiveInfinity; for (int m = 0; m < num; m++) { if (m != num10 && m != num11) { double num20 = Circumradius(num14, num15, num17, num18, coords[2 * m], coords[2 * m + 1]); if (num20 < num19) { num12 = m; num19 = num20; } } } double num21 = coords[2 * num12]; double num22 = coords[2 * num12 + 1]; if (num19 == double.PositiveInfinity) { throw new Exception("No Delaunay triangulation exists for this input."); } if (Orient(num14, num15, num17, num18, num21, num22)) { int num23 = num11; double num24 = num17; double num25 = num18; num11 = num12; num17 = num21; num18 = num22; num12 = num23; num21 = num24; num22 = num25; } <71c98ed0-65e2-4d7b-9d9e-046a047365d7>Point <71c98ed0-65e2-4d7b-9d9e-046a047365d7>Point2 = Circumcenter(num14, num15, num17, num18, num21, num22); cx = <71c98ed0-65e2-4d7b-9d9e-046a047365d7>Point2.X; cy = <71c98ed0-65e2-4d7b-9d9e-046a047365d7>Point2.Y; double[] array2 = new double[num]; for (int n = 0; n < num; n++) { array2[n] = Dist(coords[2 * n], coords[2 * n + 1], <71c98ed0-65e2-4d7b-9d9e-046a047365d7>Point2.X, <71c98ed0-65e2-4d7b-9d9e-046a047365d7>Point2.Y); } Quicksort(array, array2, 0, num - 1); hullStart = num10; hullSize = 3; hullNext[num10] = (hullPrev[num12] = num11); hullNext[num11] = (hullPrev[num10] = num12); hullNext[num12] = (hullPrev[num11] = num10); hullTri[num10] = 0; hullTri[num11] = 1; hullTri[num12] = 2; hullHash[HashKey(num14, num15)] = num10; hullHash[HashKey(num17, num18)] = num11; hullHash[HashKey(num21, num22)] = num12; trianglesLen = 0; AddTriangle(num10, num11, num12, -1, -1, -1); double num26 = 0.0; double num27 = 0.0; for (int num28 = 0; num28 < array.Length; num28++) { int num29 = array[num28]; double num30 = coords[2 * num29]; double num31 = coords[2 * num29 + 1]; if (num28 > 0 && Math.Abs(num30 - num26) <= EPSILON && Math.Abs(num31 - num27) <= EPSILON) { continue; } num26 = num30; num27 = num31; if (num29 == num10 || num29 == num11 || num29 == num12) { continue; } int num32 = 0; for (int num33 = 0; num33 < hashSize; num33++) { int num34 = HashKey(num30, num31); num32 = hullHash[(num34 + num33) % hashSize]; if (num32 != -1 && num32 != hullNext[num32]) { break; } } num32 = hullPrev[num32]; int num35 = num32; int num36 = hullNext[num35]; while (!Orient(num30, num31, coords[2 * num35], coords[2 * num35 + 1], coords[2 * num36], coords[2 * num36 + 1])) { num35 = num36; if (num35 == num32) { num35 = int.MaxValue; break; } num36 = hullNext[num35]; } if (num35 == int.MaxValue) { continue; } int num37 = AddTriangle(num35, num29, hullNext[num35], -1, -1, hullTri[num35]); hullTri[num29] = Legalize(num37 + 2); hullTri[num35] = num37; hullSize++; int num38 = hullNext[num35]; num36 = hullNext[num38]; while (Orient(num30, num31, coords[2 * num38], coords[2 * num38 + 1], coords[2 * num36], coords[2 * num36 + 1])) { num37 = AddTriangle(num38, num29, num36, hullTri[num29], -1, hullTri[num38]); hullTri[num29] = Legalize(num37 + 2); hullNext[num38] = num38; hullSize--; num38 = num36; num36 = hullNext[num38]; } if (num35 == num32) { num36 = hullPrev[num35]; while (Orient(num30, num31, coords[2 * num36], coords[2 * num36 + 1], coords[2 * num35], coords[2 * num35 + 1])) { num37 = AddTriangle(num36, num29, num35, -1, hullTri[num35], hullTri[num36]); Legalize(num37 + 2); hullTri[num36] = num37; hullNext[num35] = num35; hullSize--; num35 = num36; num36 = hullPrev[num35]; } } hullStart = (hullPrev[num29] = num35); hullNext[num35] = (hullPrev[num38] = num29); hullNext[num29] = num38; hullHash[HashKey(num30, num31)] = num29; hullHash[HashKey(coords[2 * num35], coords[2 * num35 + 1])] = num35; } Hull = new int[hullSize]; int num39 = hullStart; for (int num40 = 0; num40 < hullSize; num40++) { Hull[num40] = num39; num39 = hullNext[num39]; } hullPrev = (hullNext = (hullTri = null)); Triangles = Triangles.Take(trianglesLen).ToArray(); Halfedges = Halfedges.Take(trianglesLen).ToArray(); } private int Legalize(int a) { int num = 0; int num4; while (true) { int num2 = Halfedges[a]; int num3 = a - a % 3; num4 = num3 + (a + 2) % 3; if (num2 == -1) { if (num == 0) { break; } a = EDGE_STACK[--num]; continue; } int num5 = num2 - num2 % 3; int num6 = num3 + (a + 1) % 3; int num7 = num5 + (num2 + 2) % 3; int num8 = Triangles[num4]; int num9 = Triangles[a]; int num10 = Triangles[num6]; int num11 = Triangles[num7]; if (InCircle(coords[2 * num8], coords[2 * num8 + 1], coords[2 * num9], coords[2 * num9 + 1], coords[2 * num10], coords[2 * num10 + 1], coords[2 * num11], coords[2 * num11 + 1])) { Triangles[a] = num11; Triangles[num2] = num8; int num12 = Halfedges[num7]; if (num12 == -1) { int num13 = hullStart; do { if (hullTri[num13] == num7) { hullTri[num13] = a; break; } num13 = hullPrev[num13]; } while (num13 != hullStart); } Link(a, num12); Link(num2, Halfedges[num4]); Link(num4, num7); int num14 = num5 + (num2 + 1) % 3; if (num < EDGE_STACK.Length) { EDGE_STACK[num++] = num14; } } else { if (num == 0) { break; } a = EDGE_STACK[--num]; } } return num4; } private static bool InCircle(double ax, double ay, double bx, double by, double cx, double cy, double px, double py) { double num = ax - px; double num2 = ay - py; double num3 = bx - px; double num4 = by - py; double num5 = cx - px; double num6 = cy - py; double num7 = num * num + num2 * num2; double num8 = num3 * num3 + num4 * num4; double num9 = num5 * num5 + num6 * num6; return num * (num4 * num9 - num8 * num6) - num2 * (num3 * num9 - num8 * num5) + num7 * (num3 * num6 - num4 * num5) < 0.0; } private int AddTriangle(int i0, int i1, int i2, int a, int b, int c) { int num = trianglesLen; Triangles[num] = i0; Triangles[num + 1] = i1; Triangles[num + 2] = i2; Link(num, a); Link(num + 1, b); Link(num + 2, c); trianglesLen += 3; return num; } private void Link(int a, int b) { Halfedges[a] = b; if (b != -1) { Halfedges[b] = a; } } private int HashKey(double x, double y) { return (int)(Math.Floor(PseudoAngle(x - cx, y - cy) * (double)hashSize) % (double)hashSize); } private static double PseudoAngle(double dx, double dy) { double num = dx / (Math.Abs(dx) + Math.Abs(dy)); return ((dy > 0.0) ? (3.0 - num) : (1.0 + num)) / 4.0; } private static void Quicksort(int[] ids, double[] dists, int left, int right) { if (right - left <= 20) { for (int i = left + 1; i <= right; i++) { int num = ids[i]; double num2 = dists[num]; int num3 = i - 1; while (num3 >= left && dists[ids[num3]] > num2) { ids[num3 + 1] = ids[num3--]; } ids[num3 + 1] = num; } return; } int i2 = left + right >> 1; int num4 = left + 1; int num5 = right; Swap(ids, i2, num4); if (dists[ids[left]] > dists[ids[right]]) { Swap(ids, left, right); } if (dists[ids[num4]] > dists[ids[right]]) { Swap(ids, num4, right); } if (dists[ids[left]] > dists[ids[num4]]) { Swap(ids, left, num4); } int num6 = ids[num4]; double num7 = dists[num6]; while (true) { num4++; if (!(dists[ids[num4]] < num7)) { do { num5--; } while (dists[ids[num5]] > num7); if (num5 < num4) { break; } Swap(ids, num4, num5); } } ids[left + 1] = ids[num5]; ids[num5] = num6; if (right - num4 + 1 >= num5 - left) { Quicksort(ids, dists, num4, right); Quicksort(ids, dists, left, num5 - 1); } else { Quicksort(ids, dists, left, num5 - 1); Quicksort(ids, dists, num4, right); } } private static void Swap(int[] arr, int i, int j) { int num = arr[i]; arr[i] = arr[j]; arr[j] = num; } private static bool Orient(double px, double py, double qx, double qy, double rx, double ry) { return (qy - py) * (rx - qx) - (qx - px) * (ry - qy) < 0.0; } private static double Circumradius(double ax, double ay, double bx, double by, double cx, double cy) { double num = bx - ax; double num2 = by - ay; double num3 = cx - ax; double num4 = cy - ay; double num5 = num * num + num2 * num2; double num6 = num3 * num3 + num4 * num4; double num7 = 0.5 / (num * num4 - num2 * num3); double num8 = (num4 * num5 - num2 * num6) * num7; double num9 = (num * num6 - num3 * num5) * num7; return num8 * num8 + num9 * num9; } private static <71c98ed0-65e2-4d7b-9d9e-046a047365d7>Point Circumcenter(double ax, double ay, double bx, double by, double cx, double cy) { double num = bx - ax; double num2 = by - ay; double num3 = cx - ax; double num4 = cy - ay; double num5 = num * num + num2 * num2; double num6 = num3 * num3 + num4 * num4; double num7 = 0.5 / (num * num4 - num2 * num3); double x = ax + (num4 * num5 - num2 * num6) * num7; double y = ay + (num * num6 - num3 * num5) * num7; return new <71c98ed0-65e2-4d7b-9d9e-046a047365d7>Point(x, y); } private static double Dist(double ax, double ay, double bx, double by) { double num = ax - bx; double num2 = ay - by; return num * num + num2 * num2; } public IEnumerable<<71c98ed0-65e2-4d7b-9d9e-046a047365d7>ITriangle> GetTriangles() { for (int t = 0; t < Triangles.Length / 3; t++) { yield return new <71c98ed0-65e2-4d7b-9d9e-046a047365d7>Triangle(t, GetTrianglePoints(t)); } } public IEnumerable<<71c98ed0-65e2-4d7b-9d9e-046a047365d7>IEdge> GetEdges() { for (int e = 0; e < Triangles.Length; e++) { if (e > Halfedges[e]) { <71c98ed0-65e2-4d7b-9d9e-046a047365d7>IPoint p = Points[Triangles[e]]; <71c98ed0-65e2-4d7b-9d9e-046a047365d7>IPoint q = Points[Triangles[NextHalfedge(e)]]; yield return new <71c98ed0-65e2-4d7b-9d9e-046a047365d7>Edge(e, p, q); } } } public IEnumerable<<71c98ed0-65e2-4d7b-9d9e-046a047365d7>IEdge> GetVoronoiEdges(FuncIPoint> triangleVerticeSelector = null) { if (triangleVerticeSelector == null) { triangleVerticeSelector = (int x) => GetCentroid(x); } for (int e = 0; e < Triangles.Length; e++) { if (e < Halfedges[e]) { <71c98ed0-65e2-4d7b-9d9e-046a047365d7>IPoint p = triangleVerticeSelector(TriangleOfEdge(e)); <71c98ed0-65e2-4d7b-9d9e-046a047365d7>IPoint q = triangleVerticeSelector(TriangleOfEdge(Halfedges[e])); yield return new <71c98ed0-65e2-4d7b-9d9e-046a047365d7>Edge(e, p, q); } } } public IEnumerable<<71c98ed0-65e2-4d7b-9d9e-046a047365d7>IEdge> GetVoronoiEdgesBasedOnCircumCenter() { return GetVoronoiEdges(GetTriangleCircumcenter); } public IEnumerable<<71c98ed0-65e2-4d7b-9d9e-046a047365d7>IEdge> GetVoronoiEdgesBasedOnCentroids() { return GetVoronoiEdges(GetCentroid); } public IEnumerable<<71c98ed0-65e2-4d7b-9d9e-046a047365d7>IVoronoiCell> GetVoronoiCells(FuncIPoint> triangleVerticeSelector = null) { if (triangleVerticeSelector == null) { triangleVerticeSelector = (int x) => GetCentroid(x); } HashSet seen = new HashSet(); List<<71c98ed0-65e2-4d7b-9d9e-046a047365d7>IPoint> vertices = new List<<71c98ed0-65e2-4d7b-9d9e-046a047365d7>IPoint>(10); for (int e = 0; e < Triangles.Length; e++) { int num = Triangles[NextHalfedge(e)]; if (!seen.Add(num)) { continue; } foreach (int item in EdgesAroundPoint(e)) { vertices.Add(triangleVerticeSelector(TriangleOfEdge(item))); } yield return new <71c98ed0-65e2-4d7b-9d9e-046a047365d7>VoronoiCell(num, vertices.ToArray()); vertices.Clear(); } } public IEnumerable<<71c98ed0-65e2-4d7b-9d9e-046a047365d7>IVoronoiCell> GetVoronoiCellsBasedOnCircumcenters() { return GetVoronoiCells(GetTriangleCircumcenter); } public IEnumerable<<71c98ed0-65e2-4d7b-9d9e-046a047365d7>IVoronoiCell> GetVoronoiCellsBasedOnCentroids() { return GetVoronoiCells(GetCentroid); } public IEnumerable<<71c98ed0-65e2-4d7b-9d9e-046a047365d7>IEdge> GetHullEdges() { return CreateHull(GetHullPoints()); } public <71c98ed0-65e2-4d7b-9d9e-046a047365d7>IPoint[] GetHullPoints() { return Array.ConvertAll(Hull, (int x) => Points[x]); } public <71c98ed0-65e2-4d7b-9d9e-046a047365d7>IPoint[] GetTrianglePoints(int t) { List<<71c98ed0-65e2-4d7b-9d9e-046a047365d7>IPoint> list = new List<<71c98ed0-65e2-4d7b-9d9e-046a047365d7>IPoint>(); foreach (int item in PointsOfTriangle(t)) { list.Add(Points[item]); } return list.ToArray(); } public <71c98ed0-65e2-4d7b-9d9e-046a047365d7>IPoint[] GetRellaxedPoints() { List<<71c98ed0-65e2-4d7b-9d9e-046a047365d7>IPoint> list = new List<<71c98ed0-65e2-4d7b-9d9e-046a047365d7>IPoint>(); foreach (<71c98ed0-65e2-4d7b-9d9e-046a047365d7>IVoronoiCell voronoiCellsBasedOnCircumcenter in GetVoronoiCellsBasedOnCircumcenters()) { list.Add(GetCentroid(voronoiCellsBasedOnCircumcenter.Points)); } return list.ToArray(); } public IEnumerable<<71c98ed0-65e2-4d7b-9d9e-046a047365d7>IEdge> GetEdgesOfTriangle(int t) { return CreateHull(from p in EdgesOfTriangle(t) select Points[p]); } public static IEnumerable<<71c98ed0-65e2-4d7b-9d9e-046a047365d7>IEdge> CreateHull(IEnumerable<<71c98ed0-65e2-4d7b-9d9e-046a047365d7>IPoint> points) { return points.Zip(points.Skip(1).Append<<71c98ed0-65e2-4d7b-9d9e-046a047365d7>IPoint>(points.FirstOrDefault()), (<71c98ed0-65e2-4d7b-9d9e-046a047365d7>IPoint a, <71c98ed0-65e2-4d7b-9d9e-046a047365d7>IPoint b) => new <71c98ed0-65e2-4d7b-9d9e-046a047365d7>Edge(0, a, b)).OfType<<71c98ed0-65e2-4d7b-9d9e-046a047365d7>IEdge>(); } public <71c98ed0-65e2-4d7b-9d9e-046a047365d7>IPoint GetTriangleCircumcenter(int t) { <71c98ed0-65e2-4d7b-9d9e-046a047365d7>IPoint[] trianglePoints = GetTrianglePoints(t); return GetCircumcenter(trianglePoints[0], trianglePoints[1], trianglePoints[2]); } public <71c98ed0-65e2-4d7b-9d9e-046a047365d7>IPoint GetCentroid(int t) { return GetCentroid(GetTrianglePoints(t)); } public static <71c98ed0-65e2-4d7b-9d9e-046a047365d7>IPoint GetCircumcenter(<71c98ed0-65e2-4d7b-9d9e-046a047365d7>IPoint a, <71c98ed0-65e2-4d7b-9d9e-046a047365d7>IPoint b, <71c98ed0-65e2-4d7b-9d9e-046a047365d7>IPoint c) { return Circumcenter(a.X, a.Y, b.X, b.Y, c.X, c.Y); } public static <71c98ed0-65e2-4d7b-9d9e-046a047365d7>IPoint GetCentroid(<71c98ed0-65e2-4d7b-9d9e-046a047365d7>IPoint[] points) { double num = 0.0; double num2 = 0.0; double num3 = 0.0; int num4 = 0; int num5 = points.Length - 1; while (num4 < points.Length) { double num6 = points[num4].X * points[num5].Y - points[num5].X * points[num4].Y; num += num6; num2 += (points[num4].X + points[num5].X) * num6; num3 += (points[num4].Y + points[num5].Y) * num6; num5 = num4++; } if (Math.Abs(num) < 1.0000000116860974E-07) { return default(<71c98ed0-65e2-4d7b-9d9e-046a047365d7>Point); } num *= 3.0; return new <71c98ed0-65e2-4d7b-9d9e-046a047365d7>Point(num2 / num, num3 / num); } public void ForEachTriangle(Action<<71c98ed0-65e2-4d7b-9d9e-046a047365d7>ITriangle> callback) { foreach (<71c98ed0-65e2-4d7b-9d9e-046a047365d7>ITriangle triangle in GetTriangles()) { callback?.Invoke(triangle); } } public void ForEachTriangleEdge(Action<<71c98ed0-65e2-4d7b-9d9e-046a047365d7>IEdge> callback) { foreach (<71c98ed0-65e2-4d7b-9d9e-046a047365d7>IEdge edge in GetEdges()) { callback?.Invoke(edge); } } public void ForEachVoronoiEdge(Action<<71c98ed0-65e2-4d7b-9d9e-046a047365d7>IEdge> callback) { foreach (<71c98ed0-65e2-4d7b-9d9e-046a047365d7>IEdge voronoiEdge in GetVoronoiEdges()) { callback?.Invoke(voronoiEdge); } } public void ForEachVoronoiCellBasedOnCentroids(Action<<71c98ed0-65e2-4d7b-9d9e-046a047365d7>IVoronoiCell> callback) { foreach (<71c98ed0-65e2-4d7b-9d9e-046a047365d7>IVoronoiCell voronoiCellsBasedOnCentroid in GetVoronoiCellsBasedOnCentroids()) { callback?.Invoke(voronoiCellsBasedOnCentroid); } } public void ForEachVoronoiCellBasedOnCircumcenters(Action<<71c98ed0-65e2-4d7b-9d9e-046a047365d7>IVoronoiCell> callback) { foreach (<71c98ed0-65e2-4d7b-9d9e-046a047365d7>IVoronoiCell voronoiCellsBasedOnCircumcenter in GetVoronoiCellsBasedOnCircumcenters()) { callback?.Invoke(voronoiCellsBasedOnCircumcenter); } } public void ForEachVoronoiCell(Action<<71c98ed0-65e2-4d7b-9d9e-046a047365d7>IVoronoiCell> callback, FuncIPoint> triangleVertexSelector = null) { foreach (<71c98ed0-65e2-4d7b-9d9e-046a047365d7>IVoronoiCell voronoiCell in GetVoronoiCells(triangleVertexSelector)) { callback?.Invoke(voronoiCell); } } public IEnumerable EdgesAroundPoint(int start) { int incoming = start; do { yield return incoming; int num = NextHalfedge(incoming); incoming = Halfedges[num]; } while (incoming != -1 && incoming != start); } public IEnumerable PointsOfTriangle(int t) { int[] array = EdgesOfTriangle(t); foreach (int num in array) { yield return Triangles[num]; } } public IEnumerable TrianglesAdjacentToTriangle(int t) { List list = new List(); int[] array = EdgesOfTriangle(t); foreach (int num in array) { int num2 = Halfedges[num]; if (num2 >= 0) { list.Add(TriangleOfEdge(num2)); } } return list; } public static int NextHalfedge(int e) { if (e % 3 != 2) { return e + 1; } return e - 2; } public static int PreviousHalfedge(int e) { if (e % 3 != 0) { return e - 1; } return e + 2; } public static int[] EdgesOfTriangle(int t) { return new int[3] { 3 * t, 3 * t + 1, 3 * t + 2 }; } public static int TriangleOfEdge(int e) { return e / 3; } } internal interface <71c98ed0-65e2-4d7b-9d9e-046a047365d7>IEdge { <71c98ed0-65e2-4d7b-9d9e-046a047365d7>IPoint P { get; } <71c98ed0-65e2-4d7b-9d9e-046a047365d7>IPoint Q { get; } int Index { get; } } internal interface <71c98ed0-65e2-4d7b-9d9e-046a047365d7>IPoint { double X { get; set; } double Y { get; set; } } internal interface <71c98ed0-65e2-4d7b-9d9e-046a047365d7>ITriangle { IEnumerable<<71c98ed0-65e2-4d7b-9d9e-046a047365d7>IPoint> Points { get; } int Index { get; } } internal interface <71c98ed0-65e2-4d7b-9d9e-046a047365d7>IVoronoiCell { <71c98ed0-65e2-4d7b-9d9e-046a047365d7>IPoint[] Points { get; } int Index { get; } } internal struct <71c98ed0-65e2-4d7b-9d9e-046a047365d7>Edge : <71c98ed0-65e2-4d7b-9d9e-046a047365d7>IEdge { public <71c98ed0-65e2-4d7b-9d9e-046a047365d7>IPoint P { get; set; } public <71c98ed0-65e2-4d7b-9d9e-046a047365d7>IPoint Q { get; set; } public int Index { get; set; } public <71c98ed0-65e2-4d7b-9d9e-046a047365d7>Edge(int e, <71c98ed0-65e2-4d7b-9d9e-046a047365d7>IPoint p, <71c98ed0-65e2-4d7b-9d9e-046a047365d7>IPoint q) { Index = e; P = p; Q = q; } } internal struct <71c98ed0-65e2-4d7b-9d9e-046a047365d7>Point : <71c98ed0-65e2-4d7b-9d9e-046a047365d7>IPoint { public double X { get; set; } public double Y { get; set; } public <71c98ed0-65e2-4d7b-9d9e-046a047365d7>Point(double x, double y) { X = x; Y = y; } public override string ToString() { return $"{X},{Y}"; } } internal struct <71c98ed0-65e2-4d7b-9d9e-046a047365d7>Triangle : <71c98ed0-65e2-4d7b-9d9e-046a047365d7>ITriangle { public int Index { get; set; } public IEnumerable<<71c98ed0-65e2-4d7b-9d9e-046a047365d7>IPoint> Points { get; set; } public <71c98ed0-65e2-4d7b-9d9e-046a047365d7>Triangle(int t, IEnumerable<<71c98ed0-65e2-4d7b-9d9e-046a047365d7>IPoint> points) { Points = points; Index = t; } } internal struct <71c98ed0-65e2-4d7b-9d9e-046a047365d7>VoronoiCell : <71c98ed0-65e2-4d7b-9d9e-046a047365d7>IVoronoiCell { public <71c98ed0-65e2-4d7b-9d9e-046a047365d7>IPoint[] Points { get; set; } public int Index { get; set; } public <71c98ed0-65e2-4d7b-9d9e-046a047365d7>VoronoiCell(int triangleIndex, <71c98ed0-65e2-4d7b-9d9e-046a047365d7>IPoint[] points) { Points = points; Index = triangleIndex; } } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module | AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class NullablePublicOnlyAttribute : Attribute { public readonly bool IncludesInternals; public NullablePublicOnlyAttribute(bool P_0) { IncludesInternals = P_0; } } } internal class Interop { internal unsafe static void GetRandomBytes(byte* buffer, int length) { if (!LocalAppContextSwitches.UseNonRandomizedHashSeed) { using (RandomNumberGenerator randomNumberGenerator = RandomNumberGenerator.Create()) { byte[] array = new byte[length]; randomNumberGenerator.GetBytes(array); Marshal.Copy(array, 0, (IntPtr)buffer, length); } } } } namespace FxResources.Microsoft.Bcl.HashCode { internal static class SR { } } namespace System { internal struct HashCode { private static readonly uint s_seed = GenerateGlobalSeed(); private const uint Prime1 = 2654435761u; private const uint Prime2 = 2246822519u; private const uint Prime3 = 3266489917u; private const uint Prime4 = 668265263u; private const uint Prime5 = 374761393u; private uint _v1; private uint _v2; private uint _v3; private uint _v4; private uint _queue1; private uint _queue2; private uint _queue3; private uint _length; private unsafe static uint GenerateGlobalSeed() { uint result = default(uint); Interop.GetRandomBytes((byte*)(&result), 4); return result; } public static int Combine(T1 value1) { uint queuedValue = (uint)(value1?.GetHashCode() ?? 0); uint num = MixEmptyState(); num += 4; num = QueueRound(num, queuedValue); return (int)MixFinal(num); } public static int Combine(T1 value1, T2 value2) { uint queuedValue = (uint)(value1?.GetHashCode() ?? 0); uint queuedValue2 = (uint)(value2?.GetHashCode() ?? 0); uint num = MixEmptyState(); num += 8; num = QueueRound(num, queuedValue); num = QueueRound(num, queuedValue2); return (int)MixFinal(num); } public static int Combine(T1 value1, T2 value2, T3 value3) { uint queuedValue = (uint)(value1?.GetHashCode() ?? 0); uint queuedValue2 = (uint)(value2?.GetHashCode() ?? 0); uint queuedValue3 = (uint)(value3?.GetHashCode() ?? 0); uint num = MixEmptyState(); num += 12; num = QueueRound(num, queuedValue); num = QueueRound(num, queuedValue2); num = QueueRound(num, queuedValue3); return (int)MixFinal(num); } public static int Combine(T1 value1, T2 value2, T3 value3, T4 value4) { uint input = (uint)(value1?.GetHashCode() ?? 0); uint input2 = (uint)(value2?.GetHashCode() ?? 0); uint input3 = (uint)(value3?.GetHashCode() ?? 0); uint input4 = (uint)(value4?.GetHashCode() ?? 0); Initialize(out var v, out var v2, out var v3, out var v4); v = Round(v, input); v2 = Round(v2, input2); v3 = Round(v3, input3); v4 = Round(v4, input4); uint num = MixState(v, v2, v3, v4); num += 16; return (int)MixFinal(num); } public static int Combine(T1 value1, T2 value2, T3 value3, T4 value4, T5 value5) { uint input = (uint)(value1?.GetHashCode() ?? 0); uint input2 = (uint)(value2?.GetHashCode() ?? 0); uint input3 = (uint)(value3?.GetHashCode() ?? 0); uint input4 = (uint)(value4?.GetHashCode() ?? 0); uint queuedValue = (uint)(value5?.GetHashCode() ?? 0); Initialize(out var v, out var v2, out var v3, out var v4); v = Round(v, input); v2 = Round(v2, input2); v3 = Round(v3, input3); v4 = Round(v4, input4); uint num = MixState(v, v2, v3, v4); num += 20; num = QueueRound(num, queuedValue); return (int)MixFinal(num); } public static int Combine(T1 value1, T2 value2, T3 value3, T4 value4, T5 value5, T6 value6) { uint input = (uint)(value1?.GetHashCode() ?? 0); uint input2 = (uint)(value2?.GetHashCode() ?? 0); uint input3 = (uint)(value3?.GetHashCode() ?? 0); uint input4 = (uint)(value4?.GetHashCode() ?? 0); uint queuedValue = (uint)(value5?.GetHashCode() ?? 0); uint queuedValue2 = (uint)(value6?.GetHashCode() ?? 0); Initialize(out var v, out var v2, out var v3, out var v4); v = Round(v, input); v2 = Round(v2, input2); v3 = Round(v3, input3); v4 = Round(v4, input4); uint num = MixState(v, v2, v3, v4); num += 24; num = QueueRound(num, queuedValue); num = QueueRound(num, queuedValue2); return (int)MixFinal(num); } public static int Combine(T1 value1, T2 value2, T3 value3, T4 value4, T5 value5, T6 value6, T7 value7) { uint input = (uint)(value1?.GetHashCode() ?? 0); uint input2 = (uint)(value2?.GetHashCode() ?? 0); uint input3 = (uint)(value3?.GetHashCode() ?? 0); uint input4 = (uint)(value4?.GetHashCode() ?? 0); uint queuedValue = (uint)(value5?.GetHashCode() ?? 0); uint queuedValue2 = (uint)(value6?.GetHashCode() ?? 0); uint queuedValue3 = (uint)(value7?.GetHashCode() ?? 0); Initialize(out var v, out var v2, out var v3, out var v4); v = Round(v, input); v2 = Round(v2, input2); v3 = Round(v3, input3); v4 = Round(v4, input4); uint num = MixState(v, v2, v3, v4); num += 28; num = QueueRound(num, queuedValue); num = QueueRound(num, queuedValue2); num = QueueRound(num, queuedValue3); return (int)MixFinal(num); } public static int Combine(T1 value1, T2 value2, T3 value3, T4 value4, T5 value5, T6 value6, T7 value7, T8 value8) { uint input = (uint)(value1?.GetHashCode() ?? 0); uint input2 = (uint)(value2?.GetHashCode() ?? 0); uint input3 = (uint)(value3?.GetHashCode() ?? 0); uint input4 = (uint)(value4?.GetHashCode() ?? 0); uint input5 = (uint)(value5?.GetHashCode() ?? 0); uint input6 = (uint)(value6?.GetHashCode() ?? 0); uint input7 = (uint)(value7?.GetHashCode() ?? 0); uint input8 = (uint)(value8?.GetHashCode() ?? 0); Initialize(out var v, out var v2, out var v3, out var v4); v = Round(v, input); v2 = Round(v2, input2); v3 = Round(v3, input3); v4 = Round(v4, input4); v = Round(v, input5); v2 = Round(v2, input6); v3 = Round(v3, input7); v4 = Round(v4, input8); uint num = MixState(v, v2, v3, v4); num += 32; return (int)MixFinal(num); } [MethodImpl(MethodImplOptions.AggressiveInlining)] private static void Initialize(out uint v1, out uint v2, out uint v3, out uint v4) { v1 = (uint)((int)s_seed + -1640531535 + -2048144777); v2 = s_seed + 2246822519u; v3 = s_seed; v4 = s_seed - 2654435761u; } [MethodImpl(MethodImplOptions.AggressiveInlining)] private static uint Round(uint hash, uint input) { return BitOperations.RotateLeft(hash + (uint)((int)input * -2048144777), 13) * 2654435761u; } [MethodImpl(MethodImplOptions.AggressiveInlining)] private static uint QueueRound(uint hash, uint queuedValue) { return BitOperations.RotateLeft(hash + (uint)((int)queuedValue * -1028477379), 17) * 668265263; } [MethodImpl(MethodImplOptions.AggressiveInlining)] private static uint MixState(uint v1, uint v2, uint v3, uint v4) { return BitOperations.RotateLeft(v1, 1) + BitOperations.RotateLeft(v2, 7) + BitOperations.RotateLeft(v3, 12) + BitOperations.RotateLeft(v4, 18); } private static uint MixEmptyState() { return s_seed + 374761393; } [MethodImpl(MethodImplOptions.AggressiveInlining)] private static uint MixFinal(uint hash) { hash ^= hash >> 15; hash *= 2246822519u; hash ^= hash >> 13; hash *= 3266489917u; hash ^= hash >> 16; return hash; } public void Add(T value) { Add(value?.GetHashCode() ?? 0); } public void Add(T value, IEqualityComparer? comparer) { Add(comparer?.GetHashCode(value) ?? value?.GetHashCode() ?? 0); } private void Add(int value) { uint num = _length++; switch (num % 4) { case 0u: _queue1 = (uint)value; return; case 1u: _queue2 = (uint)value; return; case 2u: _queue3 = (uint)value; return; } if (num == 3) { Initialize(out _v1, out _v2, out _v3, out _v4); } _v1 = Round(_v1, _queue1); _v2 = Round(_v2, _queue2); _v3 = Round(_v3, _queue3); _v4 = Round(_v4, (uint)value); } public int ToHashCode() { uint length = _length; uint num = length % 4; uint num2 = ((length < 4) ? MixEmptyState() : MixState(_v1, _v2, _v3, _v4)); num2 += length * 4; if (num != 0) { num2 = QueueRound(num2, _queue1); if (num > 1) { num2 = QueueRound(num2, _queue2); if (num > 2) { num2 = QueueRound(num2, _queue3); } } } return (int)MixFinal(num2); } [Obsolete("HashCode is a mutable struct and should not be compared with other HashCodes. Use ToHashCode to retrieve the computed hash code.", true)] [EditorBrowsable(EditorBrowsableState.Never)] public override int GetHashCode() { throw new NotSupportedException(SR.HashCode_HashCodeNotSupported); } [Obsolete("HashCode is a mutable struct and should not be compared with other HashCodes.", true)] [EditorBrowsable(EditorBrowsableState.Never)] public override bool Equals(object? obj) { throw new NotSupportedException(SR.HashCode_EqualityNotSupported); } } internal static class LocalAppContextSwitches { private static int s_useNonRandomizedHashSeed; public static bool UseNonRandomizedHashSeed { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return GetCachedSwitchValue("Switch.System.Data.UseNonRandomizedHashSeed", ref s_useNonRandomizedHashSeed); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static bool GetCachedSwitchValue(string switchName, ref int cachedSwitchValue) { if (cachedSwitchValue < 0) { return false; } if (cachedSwitchValue > 0) { return true; } return GetCachedSwitchValueInternal(switchName, ref cachedSwitchValue); } private static bool GetCachedSwitchValueInternal(string switchName, ref int cachedSwitchValue) { if (!AppContext.TryGetSwitch(switchName, out var isEnabled)) { isEnabled = GetSwitchDefaultValue(switchName); } AppContext.TryGetSwitch("TestSwitch.LocalAppContext.DisableCaching", out var isEnabled2); if (!isEnabled2) { cachedSwitchValue = (isEnabled ? 1 : (-1)); } return isEnabled; } private static bool GetSwitchDefaultValue(string switchName) { if (switchName == "Switch.System.Runtime.Serialization.SerializationGuard") { return true; } return false; } } internal static class SR { private static ResourceManager s_resourceManager; internal static ResourceManager ResourceManager => s_resourceManager ?? (s_resourceManager = new ResourceManager(typeof(FxResources.Microsoft.Bcl.HashCode.SR))); internal static string HashCode_EqualityNotSupported => GetResourceString("HashCode_EqualityNotSupported"); internal static string HashCode_HashCodeNotSupported => GetResourceString("HashCode_HashCodeNotSupported"); [MethodImpl(MethodImplOptions.NoInlining)] private static bool UsingResourceKeys() { return false; } internal static string GetResourceString(string resourceKey, string defaultString = null) { if (UsingResourceKeys()) { return defaultString ?? resourceKey; } string text = null; try { text = ResourceManager.GetString(resourceKey); } catch (MissingManifestResourceException) { } if (defaultString != null && resourceKey.Equals(text)) { return defaultString; } return text; } internal static string Format(string resourceFormat, object p1) { if (UsingResourceKeys()) { return string.Join(", ", resourceFormat, p1); } return string.Format(resourceFormat, p1); } internal static string Format(string resourceFormat, object p1, object p2) { if (UsingResourceKeys()) { return string.Join(", ", resourceFormat, p1, p2); } return string.Format(resourceFormat, p1, p2); } internal static string Format(string resourceFormat, object p1, object p2, object p3) { if (UsingResourceKeys()) { return string.Join(", ", resourceFormat, p1, p2, p3); } return string.Format(resourceFormat, p1, p2, p3); } internal static string Format(string resourceFormat, params object[] args) { if (args != null) { if (UsingResourceKeys()) { return resourceFormat + ", " + string.Join(", ", args); } return string.Format(resourceFormat, args); } return resourceFormat; } internal static string Format(IFormatProvider provider, string resourceFormat, object p1) { if (UsingResourceKeys()) { return string.Join(", ", resourceFormat, p1); } return string.Format(provider, resourceFormat, p1); } internal static string Format(IFormatProvider provider, string resourceFormat, object p1, object p2) { if (UsingResourceKeys()) { return string.Join(", ", resourceFormat, p1, p2); } return string.Format(provider, resourceFormat, p1, p2); } internal static string Format(IFormatProvider provider, string resourceFormat, object p1, object p2, object p3) { if (UsingResourceKeys()) { return string.Join(", ", resourceFormat, p1, p2, p3); } return string.Format(provider, resourceFormat, p1, p2, p3); } internal static string Format(IFormatProvider provider, string resourceFormat, params object[] args) { if (args != null) { if (UsingResourceKeys()) { return resourceFormat + ", " + string.Join(", ", args); } return string.Format(provider, resourceFormat, args); } return resourceFormat; } } } namespace System.Numerics { internal static class BitOperations { [MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint RotateLeft(uint value, int offset) { return (value << offset) | (value >> 32 - offset); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ulong RotateLeft(ulong value, int offset) { return (value << offset) | (value >> 64 - offset); } } }