Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of Beyond v0.32.1
plugins/Beyond.dll
Decompiled 5 hours ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Numerics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security.Cryptography; using System.Text; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using Beyond.Core; using Beyond.Plugin.Integration; using Beyond.Plugin.Runtime; using Beyond.Plugin.World; using HarmonyLib; using Jotunn; using Jotunn.Entities; using Jotunn.Managers; using Jotunn.Utils; using Microsoft.CodeAnalysis; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using Newtonsoft.Json.Serialization; using PassiveTree; using SoftReferenceableAssets; using Splatform; using TMPro; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.Events; using UnityEngine.Rendering; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("Brom8")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("0.32.1.0")] [assembly: AssemblyInformationalVersion("0.32.1+7631678d0972989b79d54fd3945dbfa47aa166be")] [assembly: AssemblyProduct("Beyond")] [assembly: AssemblyTitle("Beyond")] [assembly: AssemblyVersion("0.32.1.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [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] [Embedded] [AttributeUsage(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] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace Beyond.Plugin { [BepInPlugin("brom8.beyond", "Beyond", "0.32.1")] [BepInDependency("com.jotunn.jotunn", "2.30.2")] [BepInDependency(/*Could not decode attribute arguments.*/)] [NetworkCompatibility(/*Could not decode attribute arguments.*/)] public sealed class BeyondPlugin : BaseUnityPlugin { public const string PluginGuid = "brom8.beyond"; public const string PluginName = "Beyond"; public const string PluginVersion = "0.32.1"; public const string PathOfValheimanGuid = "treextr.pathofvalheiman"; private BeyondSettings _settings; private string _assetReport = "Asset probe pending world prefab registration."; private string _targetVersion = "unknown"; private bool _loaded; private bool _voidRegistryPending; private Harmony? _patches; internal static BeyondPlugin? Instance { get; private set; } internal TrialRuntime? Runtime { get; private set; } internal void LoggerForWorld(string message) { ((BaseUnityPlugin)this).Logger.LogInfo((object)message); } private void Awake() { //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Expected O, but got Unknown TestSaveDirectory.Apply(((BaseUnityPlugin)this).Logger); _settings = new BeyondSettings(((BaseUnityPlugin)this).Config); Instance = this; Runtime = new TrialRuntime(_settings, ((BaseUnityPlugin)this).Logger); _patches = new Harmony("brom8.beyond"); try { _patches.PatchAll(typeof(BeyondPlugin).Assembly); } catch (Exception ex) { _patches.UnpatchSelf(); Runtime.Dispose(); Runtime = null; ((BaseUnityPlugin)this).Logger.LogError((object)("Beyond could not install its scoped game hooks and has stopped: " + ex)); return; } if (Chainloader.PluginInfos.TryGetValue("treextr.pathofvalheiman", out var value)) { _targetVersion = value.Metadata.Version.ToString(); } PrefabManager.OnPrefabsRegistered += OnPrefabsRegistered; ItemManager.OnItemsRegistered += OnVoidItemsRegistered; PrefabManager.OnVanillaPrefabsAvailable += RegisterContent; CommandManager.Instance.AddConsoleCommand((ConsoleCommand)(object)new StatusCommand(Describe, delegate(string text) { ((BaseUnityPlugin)this).Logger.LogInfo((object)text); })); _loaded = true; ((BaseUnityPlugin)this).Logger.LogInfo((object)("Beyond 0.32.1 experimental Trial loaded; PathOfValheiman " + _targetVersion + ". Use the separate test profile and test saves.")); } private void RegisterContent() { try { TrialEnemyDirector.RegisterPrefab(); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)("Beyond content registration failed: " + ex)); Runtime?.BlockStarts("Beyond content is unavailable. Check the host log and restart after fixing dependencies."); } try { VoidCreatures.Register(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Void creatures registered: Beyond_VoidEidolon, Beyond_Riftstalker, Beyond_HollowCantor, Beyond_VoidBlob (no rewards)."); } catch (Exception ex2) { ((BaseUnityPlugin)this).Logger.LogError((object)("Void creature registration failed; do not use their spawn commands: " + ex2)); } } private void Update() { Runtime?.Tick(); } private void LateUpdate() { Runtime?.LateUpdate(); } private void OnPrefabsRegistered() { _assetReport = VisualAssets.Probe(); ((BaseUnityPlugin)this).Logger.LogInfo((object)("Beyond asset probe:\n" + _assetReport)); if (EnemyPrefabRegistry.CheckScene(out string message)) { ((BaseUnityPlugin)this).Logger.LogInfo((object)message); } else { ((BaseUnityPlugin)this).Logger.LogWarning((object)message); } _voidRegistryPending = true; if (!VoidBlob.CheckWeapon()) { ((BaseUnityPlugin)this).Logger.LogInfo((object)"Void spawn registry: waiting for ObjectDB animation-weapon registration."); } else { OnVoidItemsRegistered(); } } private void OnVoidItemsRegistered() { if (_voidRegistryPending && !((Object)(object)ZNetScene.instance == (Object)null)) { _voidRegistryPending = false; if (VoidCreatures.CheckScene(out string message)) { ((BaseUnityPlugin)this).Logger.LogInfo((object)message); } else { ((BaseUnityPlugin)this).Logger.LogError((object)message); } } } private string Describe() { if (!_loaded) { return "Beyond foundation is not active."; } FloorRules val = _settings.SnapshotTrial(); return "Beyond 0.32.1 | PathOfValheiman " + _targetVersion + "\n" + $"Floor 0 Trial: gate {val.EntryWindowSeconds}s, survival {val.SurvivalSeconds}s, shared coin pool {val.CoinPool}, participant cap {val.ParticipantLimit}.\n" + "Experimental Beyond: " + Runtime?.Status + "\n" + Runtime?.Client?.GroundStatus + "\n" + _assetReport; } private void OnDestroy() { _loaded = false; PrefabManager.OnPrefabsRegistered -= OnPrefabsRegistered; ItemManager.OnItemsRegistered -= OnVoidItemsRegistered; PrefabManager.OnVanillaPrefabsAvailable -= RegisterContent; Runtime?.Dispose(); VoidModels.Dispose(); Harmony? patches = _patches; if (patches != null) { patches.UnpatchSelf(); } Instance = null; } } internal sealed class BeyondSettings { private readonly ConfigEntry<float>[] _floorHealth = new ConfigEntry<float>[21]; private readonly ConfigEntry<float>[] _floorDamage = new ConfigEntry<float>[21]; private readonly ConfigEntry<int>[] _offerPrices = new ConfigEntry<int>[ShopCatalogue.ExtendedOffers.Count]; public ConfigEntry<int> EntryCoinsPerFloor { get; } public ConfigEntry<int> ClearCoinsPerFloor { get; } public ConfigEntry<bool> AllowNewRuns { get; } public ConfigEntry<int> ScalingStartFloor { get; } public ConfigEntry<float> HealthGrowth { get; } public ConfigEntry<KeyboardShortcut> MenuShortcut { get; } public ConfigEntry<float> DamageGrowth { get; } public ConfigEntry<float> NamedHealthBonusEffect { get; } public ConfigEntry<int> EntryWindowSeconds { get; } public ConfigEntry<int> SurvivalSeconds { get; } public ConfigEntry<int> CoinPool { get; } public ConfigEntry<int> ParticipantLimit { get; } public ConfigEntry<int> MaxInstances { get; } public ConfigEntry<int> EnemyLimit { get; } public ConfigEntry<int> IronPrice { get; } public ConfigEntry<int> TinPrice { get; } public ConfigEntry<int> CopperPrice { get; } public ConfigEntry<int> BronzePrice { get; } public ConfigEntry<int> SimpleRunePacketPrice { get; } public ConfigEntry<int> SurtlingCorePrice { get; } public ConfigEntry<int> CoreWoodPrice { get; } public ConfigEntry<int> FineWoodPrice { get; } public ConfigEntry<int> AncientBarkPrice { get; } public ConfigEntry<int> GuckPrice { get; } public ConfigEntry<int> SilverPrice { get; } public ConfigEntry<int> ObsidianPrice { get; } public ConfigEntry<int> CrystalPrice { get; } public SharedRealmSettings Realm { get; } public BeyondSettings(ConfigFile config) { //IL_0056: 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_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_00a1: Expected O, but got Unknown //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Expected O, but got Unknown //IL_0103: Unknown result type (might be due to invalid IL or missing references) //IL_010d: Expected O, but got Unknown //IL_01c1: Unknown result type (might be due to invalid IL or missing references) //IL_01cb: Expected O, but got Unknown //IL_020d: Unknown result type (might be due to invalid IL or missing references) //IL_0217: Expected O, but got Unknown //IL_028d: Unknown result type (might be due to invalid IL or missing references) //IL_0297: Expected O, but got Unknown //IL_02cb: Unknown result type (might be due to invalid IL or missing references) //IL_02d5: Expected O, but got Unknown //IL_0309: Unknown result type (might be due to invalid IL or missing references) //IL_0313: Expected O, but got Unknown //IL_03e6: Unknown result type (might be due to invalid IL or missing references) //IL_03f0: Expected O, but got Unknown //IL_041a: Unknown result type (might be due to invalid IL or missing references) //IL_0424: Expected O, but got Unknown //IL_0451: Unknown result type (might be due to invalid IL or missing references) //IL_045b: Expected O, but got Unknown //IL_048b: Unknown result type (might be due to invalid IL or missing references) //IL_0495: Expected O, but got Unknown //IL_0371: Unknown result type (might be due to invalid IL or missing references) //IL_037b: Expected O, but got Unknown //IL_03af: Unknown result type (might be due to invalid IL or missing references) //IL_03b9: Expected O, but got Unknown //IL_0508: Unknown result type (might be due to invalid IL or missing references) //IL_0512: Expected O, but got Unknown //IL_053a: Unknown result type (might be due to invalid IL or missing references) //IL_0544: Expected O, but got Unknown //IL_0568: Unknown result type (might be due to invalid IL or missing references) //IL_0572: Expected O, but got Unknown //IL_059c: Unknown result type (might be due to invalid IL or missing references) //IL_05a6: Expected O, but got Unknown //IL_0634: Unknown result type (might be due to invalid IL or missing references) //IL_063e: Expected O, but got Unknown //IL_065a: Unknown result type (might be due to invalid IL or missing references) //IL_0664: Expected O, but got Unknown //IL_06ab: Unknown result type (might be due to invalid IL or missing references) //IL_06b5: Expected O, but got Unknown //IL_070d: Unknown result type (might be due to invalid IL or missing references) //IL_0717: Expected O, but got Unknown //IL_0744: Unknown result type (might be due to invalid IL or missing references) //IL_074e: Expected O, but got Unknown //IL_077b: Unknown result type (might be due to invalid IL or missing references) //IL_0785: Expected O, but got Unknown //IL_07b2: Unknown result type (might be due to invalid IL or missing references) //IL_07bc: Expected O, but got Unknown //IL_07e9: Unknown result type (might be due to invalid IL or missing references) //IL_07f3: Expected O, but got Unknown //IL_0820: Unknown result type (might be due to invalid IL or missing references) //IL_082a: Expected O, but got Unknown //IL_0857: Unknown result type (might be due to invalid IL or missing references) //IL_0861: Expected O, but got Unknown //IL_088e: Unknown result type (might be due to invalid IL or missing references) //IL_0898: Expected O, but got Unknown //IL_08c5: Unknown result type (might be due to invalid IL or missing references) //IL_08cf: Expected O, but got Unknown //IL_08fc: Unknown result type (might be due to invalid IL or missing references) //IL_0906: Expected O, but got Unknown //IL_0933: Unknown result type (might be due to invalid IL or missing references) //IL_093d: Expected O, but got Unknown //IL_096a: Unknown result type (might be due to invalid IL or missing references) //IL_0974: Expected O, but got Unknown //IL_0990: Unknown result type (might be due to invalid IL or missing references) //IL_099a: Expected O, but got Unknown Realm = new SharedRealmSettings(config); ConfigEntry<KeyboardShortcut> val = config.Bind<KeyboardShortcut>("UI", "MenuShortcut", new KeyboardShortcut((KeyCode)289, Array.Empty<KeyCode>()), "Retired shortcut location."); MenuShortcut = config.Bind<KeyboardShortcut>("00 - Interface", "MenuShortcut", val.Value, "Local Beyond menu shortcut. Default F8. Inventory can stay open; approach the stone to open a portal. Suppressed while typing, fighting in Beyond or using other blocking interfaces."); config.Remove(((ConfigEntryBase)val).Definition); ConfigurationManagerAttributes val2 = new ConfigurationManagerAttributes { IsAdminOnly = true }; EntryCoinsPerFloor = config.Bind<int>("01 - Economy", "EntryCoinsPerFloor", 100, new ConfigDescription("Numbered floor entry = floor number times this amount. Bank first plus carried shortfall. Only opener pays; friends enter free.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 50000), new object[1] { val2 })); ClearCoinsPerFloor = config.Bind<int>("01 - Economy", "ClearCoinsPerFloor", 300, new ConfigDescription("Numbered clear reward = floor number times this amount. Banked only for a surviving opener. Trial remains 200 by default.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 50000), new object[1] { val2 })); foreach (ShopOffer extendedOffer in ShopCatalogue.ExtendedOffers) { _offerPrices[extendedOffer.PriceIndex] = config.Bind<int>("Shop.Floor" + extendedOffer.Tab, extendedOffer.Request + "Price", extendedOffer.DefaultPrice, new ConfigDescription("Coin price for " + extendedOffer.Quantity + " " + extendedOffer.DisplayName + ". Captured at run start.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 1000000), new object[1] { val2 })); } ScalingStartFloor = config.Bind<int>("Scaling", "StartFloor", 1, new ConfigDescription("First floor receiving one growth step. Floor1 at10% grows to1.10x; Floor2 to1.21x. Trial stays neutral by default.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 1000), new object[1] { val2 })); ConfigEntry<int> val3 = config.Bind<int>("Migration", "ScalingRevision", 0, "Internal default migration; leave unchanged."); if (val3.Value < 1) { if (ScalingStartFloor.Value == 10) { ScalingStartFloor.Value = 1; } val3.Value = 1; } NamedHealthBonusEffect = config.Bind<float>("Scaling", "NamedHealthBonusEffect", 2f, new ConfigDescription("Multiply only the added health-growth bonus for required named targets.2 means normal+21% becomes named+42%; authored base health/stars/rarity and per-floor overrides remain separate. Captured at run start.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 5f), new object[1] { val2 })); HealthGrowth = config.Bind<float>("Scaling", "HealthGrowthPerFloor", 0.1f, new ConfigDescription("Additional compounded health growth per floor from StartFloor. 0.10 means 10%; final factors clamp to 0.01..100.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), new object[1] { val2 })); DamageGrowth = config.Bind<float>("Scaling", "DamageGrowthPerFloor", 0f, new ConfigDescription("Separate compounded damage growth per floor from StartFloor. Default 0 keeps damage unchanged.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), new object[1] { val2 })); for (int i = 0; i <= 20; i++) { string text = ((i == 0) ? "Trial" : ("Floor" + i)); _floorHealth[i] = config.Bind<float>(text, "HealthMultiplier", 1f, new ConfigDescription("Additional health multiplier for this floor; combines once with Scaling growth and PoV difficulty. Captured at run start.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 10f), new object[1] { val2 })); _floorDamage[i] = config.Bind<float>(text, "DamageMultiplier", 1f, new ConfigDescription("Additional damage multiplier for this floor; default 1. Captured at run start.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 10f), new object[1] { val2 })); } AllowNewRuns = config.Bind<bool>("General", "AllowNewRuns", true, new ConfigDescription("Enable new Beyond runs. Disable to stop new runs while retaining recovery/exits. Use test saves.", (AcceptableValueBase)null, new object[1] { val2 })); EntryWindowSeconds = config.Bind<int>("Trial", "EntryWindowSeconds", 10, new ConfigDescription("Entry reservation window for all floors (legacy Trial section). Accepted transfers have a bounded arrival wait before combat.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 120), new object[1] { val2 })); SurvivalSeconds = config.Bind<int>("Trial", "SurvivalSeconds", 100, new ConfigDescription("Host survival duration in seconds; captured when an attempt starts.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 3600), new object[1] { val2 })); CoinPool = config.Bind<int>("Trial", "CoinPool", 200, new ConfigDescription("Trial reward banked for the surviving portal opener. Design default: 200.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 1000000), new object[1] { val2 })); for (int j = 1; j <= 20; j++) { ConfigEntry<int> val4 = config.Bind<int>("Floor" + j, "CoinPool", 300 * j, "Retired by C11 economy."); config.Remove(((ConfigEntryBase)val4).Definition); } ParticipantLimit = config.Bind<int>("Dungeons", "ParticipantLimit", 8, new ConfigDescription("Bound on unique participants in one attempt. Initial test target is solo then two players.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 16), new object[1] { val2 })); MaxInstances = config.Bind<int>("Dungeons", "MaxConcurrentInstances", 4, new ConfigDescription("Maximum simultaneous Beyond instances, including shops and pending returns. Fixed support layouts are pooled; hard maximum 4.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 4), new object[1] { val2 })); ConfigEntry<int> val5 = config.Bind<int>("Trial", "MaxLivingEnemies", 50, new ConfigDescription("Retired Trial limit, migrated to the per-instance setting.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 50), Array.Empty<object>())); EnemyLimit = config.Bind<int>("Dungeons", "MaxLivingEnemiesPerInstance", val5.Value, new ConfigDescription("Living-enemy limit for EACH independent Beyond instance, including boss/adds. No shared population cap. Four instances can total 200 enemies at 50 each. Spawn pacing stays bounded.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 50), new object[1] { val2 })); ConfigEntry<int> val6 = config.Bind<int>("Dungeons", "MaxLivingEnemiesTotal", 50, "Retired shared cap; no longer enforced."); config.Remove(((ConfigEntryBase)val5).Definition); config.Remove(((ConfigEntryBase)val6).Definition); config.Save(); ConfigEntry<int> val7 = config.Bind<int>("Shop", "BeyondEntranceKeyPrice", 100, "Retired item."); config.Remove(((ConfigEntryBase)val7).Definition); IronPrice = config.Bind<int>("Shop", "TrialIronPrice", 100, new ConfigDescription("Standard coin price for a packet of 2 iron bars in floor tab 3. Legacy setting name retained.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 1000000), new object[1] { val2 })); ConfigEntry<int> val8 = config.Bind<int>("Migration", "IronPriceRevision", 0, new ConfigDescription("Internal one-time iron-price migration marker.", (AcceptableValueBase)null, Array.Empty<object>())); if (val8.Value < 1) { if (IronPrice.Value == 10) { IronPrice.Value = 50; } val8.Value = 1; } ConfigEntry<int> val9 = config.Bind<int>("Migration", "IronPacketRevision", 0, new ConfigDescription("Internal one-time migration of the former iron default to packet pricing.", (AcceptableValueBase)null, Array.Empty<object>())); if (val9.Value < 1) { if (IronPrice.Value == 50) { IronPrice.Value = 100; } val9.Value = 1; } TinPrice = config.Bind<int>("Shop", "TinPrice", 10, new ConfigDescription("Standard coin price per Tin bar in the Trial tab.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 1000000), new object[1] { val2 })); CopperPrice = config.Bind<int>("Shop", "CopperPrice", 10, new ConfigDescription("Standard coin price per Copper bar in the Trial tab.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 1000000), new object[1] { val2 })); BronzePrice = config.Bind<int>("Shop", "BronzePrice", 30, new ConfigDescription("Standard coin price per Bronze bar in the Trial tab.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 1000000), new object[1] { val2 })); SimpleRunePacketPrice = config.Bind<int>("Shop", "SimpleRunePacketPrice", 100, new ConfigDescription("Standard coin price per basic PoV rune packet in every Trial tab. Fixed packets use base ordinary-dust costs at 100 dust: Insight/Guise 10, Spark 7, Weaving 5, Change 4. Ignores blank runestones and passive discounts. Host-controlled; captured at run start.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 1000000), new object[1] { val2 })); SurtlingCorePrice = config.Bind<int>("Shop", "SurtlingCorePrice", 100, new ConfigDescription("Standard coin price for a packet of 2 Surtling cores in floor tab 1.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 1000000), new object[1] { val2 })); CoreWoodPrice = config.Bind<int>("Shop", "CoreWoodPrice", 100, new ConfigDescription("Standard coin price for a packet of 10 core wood in floor tab 2.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 1000000), new object[1] { val2 })); FineWoodPrice = config.Bind<int>("Shop", "FineWoodPrice", 100, new ConfigDescription("Standard coin price for a packet of 10 fine wood in floor tab 2.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 1000000), new object[1] { val2 })); AncientBarkPrice = config.Bind<int>("Shop", "AncientBarkPrice", 100, new ConfigDescription("Coin price per packet of 10 ancient bark in tab 4.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 1000000), new object[1] { val2 })); GuckPrice = config.Bind<int>("Shop", "GuckPrice", 100, new ConfigDescription("Coin price per packet of 5 guck in tab 4.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 1000000), new object[1] { val2 })); SilverPrice = config.Bind<int>("Shop", "SilverPrice", 100, new ConfigDescription("Coin price per packet of 2 silver bars in tab 5.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 1000000), new object[1] { val2 })); ObsidianPrice = config.Bind<int>("Shop", "ObsidianPrice", 100, new ConfigDescription("Coin price per packet of 10 obsidian in tab 6.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 1000000), new object[1] { val2 })); CrystalPrice = config.Bind<int>("Shop", "CrystalPrice", 100, new ConfigDescription("Coin price per packet of 5 crystal in tab 6.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 1000000), new object[1] { val2 })); ConfigEntry<int> val10 = config.Bind<int>("Migration", "ShopPacketRevision", 0, new ConfigDescription("Internal one-time migration of former default unit prices to packet prices.", (AcceptableValueBase)null, Array.Empty<object>())); if (val10.Value < 1) { if (SurtlingCorePrice.Value == 50) { SurtlingCorePrice.Value = 100; } if (CoreWoodPrice.Value == 10) { CoreWoodPrice.Value = 100; } if (FineWoodPrice.Value == 10) { FineWoodPrice.Value = 100; } val10.Value = 1; } config.Save(); } public CreaturePower SnapshotScaling(int floor) { //IL_0095: Unknown result type (might be due to invalid IL or missing references) return new CreaturePower(FloorScaling.Factor(floor, ScalingStartFloor.Value, HealthGrowth.Value, _floorHealth[floor].Value), FloorScaling.Factor(floor, ScalingStartFloor.Value, DamageGrowth.Value, _floorDamage[floor].Value), (float?)FloorScaling.NamedFactor(FloorScaling.Factor(floor, ScalingStartFloor.Value, HealthGrowth.Value, 1f), NamedHealthBonusEffect.Value, _floorHealth[floor].Value)); } public ShopPrices SnapshotShop() { return new ShopPrices { tin = TinPrice.Value, copper = CopperPrice.Value, bronze = BronzePrice.Value, iron = IronPrice.Value, surtlingCore = SurtlingCorePrice.Value, coreWood = CoreWoodPrice.Value, fineWood = FineWoodPrice.Value, ancientBark = AncientBarkPrice.Value, guck = GuckPrice.Value, silver = SilverPrice.Value, obsidian = ObsidianPrice.Value, crystal = CrystalPrice.Value, simpleRunePacket = SimpleRunePacketPrice.Value, extended = Array.ConvertAll(_offerPrices, (ConfigEntry<int> entry) => entry.Value) }; } public FloorRules SnapshotTrial() { //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Expected O, but got Unknown return new FloorRules(0, (double)SurvivalSeconds.Value, CoinPool.Value, ParticipantLimit.Value, (double)EntryWindowSeconds.Value, 45.0, 2.0, (FloorObjective)0); } public FloorRules SnapshotFloor(int floor) { //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Expected O, but got Unknown if (floor != 0) { return new FloorRules(floor, 100.0, ClearCoinsPerFloor.Value * floor, ParticipantLimit.Value, (double)EntryWindowSeconds.Value, 45.0, 2.0, (FloorObjective)1); } return SnapshotTrial(); } } internal sealed class SharedRealmSettings { public ConfigEntry<bool> Enabled { get; } public ConfigEntry<bool> LandscapePreview { get; } public ConfigEntry<int> MinimumFloor { get; } public ConfigEntry<int> RespawnSeconds { get; } public ConfigEntry<int> EnemyLimit { get; } public ConfigEntry<float> Health { get; } public ConfigEntry<float> Damage { get; } public SharedRealmSettings(ConfigFile file) { //IL_0006: 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_0013: Expected O, but got Unknown //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Expected O, but got Unknown //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Expected O, but got Unknown //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Expected O, but got Unknown //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Expected O, but got Unknown //IL_00ff: Unknown result type (might be due to invalid IL or missing references) //IL_0109: Expected O, but got Unknown //IL_013d: Unknown result type (might be due to invalid IL or missing references) //IL_0147: Expected O, but got Unknown //IL_017b: Unknown result type (might be due to invalid IL or missing references) //IL_0185: Expected O, but got Unknown ConfigurationManagerAttributes val = new ConfigurationManagerAttributes { IsAdminOnly = true }; Enabled = file.Bind<bool>("Shared realm", "Enabled", true, new ConfigDescription("Host: allow new free shared-realm visits; exits/recovery remain available when disabled.", (AcceptableValueBase)null, new object[1] { val })); LandscapePreview = file.Bind<bool>("Shared realm", "LandscapePreview", true, new ConfigDescription("Host: new shared visits use the separate768m six-setting biome showcase (no enemies). False selects the original1km realm. Destination is pinned per visit; reload world to change.", (AcceptableValueBase)null, new object[1] { val })); MinimumFloor = file.Bind<int>("Shared realm", "MinimumCompletedFloor", 14, new ConfigDescription("Personal highest completion required for shared-realm entry. Use0 for testing after Trial.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 20), new object[1] { val })); RespawnSeconds = file.Bind<int>("Shared realm", "RespawnSeconds", 600, new ConfigDescription("Earliest respawn after confirmed native death processing, measured in host-running seconds. Living actors are never replaced.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(60, 3600), new object[1] { val })); EnemyLimit = file.Bind<int>("Shared realm", "MaxLivingEnemies", 50, new ConfigDescription("Independent shared-realm ceiling including named targets/adds. Not shared with numbered instances; authored initial roster is eight named targets.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 50), new object[1] { val })); Health = file.Bind<float>("Shared realm", "HealthMultiplier", 1f, new ConfigDescription("Additional shared-realm health factor, independent of numbered-floor exponential scaling. Native stars/authored base health remain explicit.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 20f), new object[1] { val })); Damage = file.Bind<float>("Shared realm", "DamageMultiplier", 1f, new ConfigDescription("Additional shared-realm damage factor. Physical-world biome/corruption multipliers are excluded.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 10f), new object[1] { val })); } } internal sealed class StatusCommand : ConsoleCommand { private readonly Func<string> _describe; private readonly Action<string> _writeLog; public override string Name => "beyond_status"; public override string Help => "Show Beyond foundation/version/config status and runtime asset availability; makes no world changes."; public StatusCommand(Func<string> describe, Action<string> writeLog) { _describe = describe; _writeLog = writeLog; } public override void Run(string[] args) { _writeLog(_describe()); } public override void Run(string[] args, Terminal terminal) { terminal.AddString(_describe()); } } internal static class VisualAssets { internal static readonly (string Role, string Prefab)[] Candidates = new(string, string)[11] { ("entrance totem", "StatueEvil"), ("portal", "portal_wood"), ("arena floor", "stone_floor_2x2"), ("ruin boundary", "stone_wall_4x2"), ("blue accent light", "piece_groundtorch_blue"), ("Trial enemy", "Troll"), ("bear option", "Bjorn"), ("goblin", "Goblin"), ("trader", "Haldor"), ("currency", "Coins"), ("first shop resource", "Iron") }; internal static string Probe() { List<string> list = new List<string>(); (string, string)[] candidates = Candidates; for (int i = 0; i < candidates.Length; i++) { (string, string) tuple = candidates[i]; bool flag = (Object)(object)PrefabManager.Instance.GetPrefab(tuple.Item2) != (Object)null; list.Add(tuple.Item1 + ": " + tuple.Item2 + " = " + (flag ? "available" : "missing")); } return string.Join("\n", list); } } } namespace Beyond.Plugin.World { internal static class AdvancedFloorLayout { public static Vector3 Entry(int floor) { //IL_0025: 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_003c: 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_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) return (Vector3)(floor switch { 4 => new Vector3(0f, 2f, -35f), 5 => new Vector3(0f, 2f, -36f), 6 => new Vector3(-20f, 2f, -77f), _ => throw new ArgumentOutOfRangeException("floor"), }); } public static Vector3 Boss(int floor) { //IL_0025: 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_003c: 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_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) return (Vector3)(floor switch { 4 => new Vector3(12f, 1.5f, 20f), 5 => new Vector3(0f, 1.5f, 28f), 6 => new Vector3(18f, 1.5f, 73f), _ => throw new ArgumentOutOfRangeException("floor"), }); } public static Vector3 ShopGate(int floor) { //IL_0001: 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) //IL_001a: Unknown result type (might be due to invalid IL or missing references) return Boss(floor) + new Vector3(0f, -1.5f, -9f); } public static Vector3 Group(int floor, int group) { //IL_0019: 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_00cf: 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) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_008c: 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_0070: 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_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: 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_006a: 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_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) return (Vector3)(floor switch { 4 => Vector3.zero, 5 => group switch { 0 => new Vector3(-22f, 0f, -12f), 1 => new Vector3(22f, 0f, 0f), _ => new Vector3(0f, 0f, 24f), }, 6 => group switch { 0 => new Vector3(-18f, 0f, -48f), 1 => new Vector3(18f, 0f, -2f), _ => new Vector3(-18f, 0f, 43f), }, _ => throw new ArgumentOutOfRangeException("floor"), }); } public static Vector3 Guard(int floor, int index, int groupSize) { //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0077: 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) int num = index / groupSize; int num2 = index % groupSize; if (floor == 4) { float num3 = ((float)num2 * 137.5f + (float)(num * 41)) * (MathF.PI / 180f); float num4 = 15 + num2 % 3 * 2; return new Vector3(Mathf.Sin(num3) * num4, 1.5f, Mathf.Cos(num3) * num4); } return Group(floor, num) + new Vector3(((float)(num2 % 4) - 1.5f) * 2.7f, 1.5f, ((float)(num2 / 4) - 1.5f) * 3f); } public static Mesh RoundBoundary() { //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_0078: 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_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) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) CanyonLayout.Builder builder = new CanyonLayout.Builder(); Vector3 val = default(Vector3); Vector3 val2 = default(Vector3); for (int i = 0; i < 64; i++) { float num = (float)i * MathF.PI / 32f; float num2 = (float)(i + 1) * MathF.PI / 32f; ((Vector3)(ref val))..ctor(Mathf.Sin(num) * 46f, -2f, Mathf.Cos(num) * 46f); ((Vector3)(ref val2))..ctor(Mathf.Sin(num2) * 46f, -2f, Mathf.Cos(num2) * 46f); builder.Quad(val, val + Vector3.up * 40f, val2 + Vector3.up * 40f, val2, doubleSided: true); } return builder.Build("Beyond compact floor invisible rim"); } public static void Build(NativeScenery scenery, Transform parent, Vector3 origin, int floor) { //IL_0015: 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_017e: Unknown result type (might be due to invalid IL or missing references) //IL_0183: 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_01aa: Unknown result type (might be due to invalid IL or missing references) //IL_01af: Unknown result type (might be due to invalid IL or missing references) //IL_01c0: Unknown result type (might be due to invalid IL or missing references) //IL_01c5: Unknown result type (might be due to invalid IL or missing references) //IL_01d6: Unknown result type (might be due to invalid IL or missing references) //IL_01db: Unknown result type (might be due to invalid IL or missing references) //IL_01ec: 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) int count = 0; bool frost = floor >= 5; if (floor == 4 || floor == 5) { for (int i = 0; i < 28; i++) { float num = (float)i * MathF.PI * 2f / 28f; Rock(Mathf.Sin(num) * 44f, Mathf.Cos(num) * 44f, 15f, (floor == 4) ? 14 : 23, 17f, i * 73); if (floor == 4 && i % 2 == 0) { Place((i % 4 == 0) ? "SwampTree2" : "SwampTree1", Mathf.Sin(num) * 40f, Mathf.Cos(num) * 40f, 1f, 24 + i % 4, 1f, i * 39, uniform: true); } if (floor == 5 && i % 4 == 0) { Place("FirTree_small", Mathf.Sin(num) * 38f, Mathf.Cos(num) * 38f, 1f, 10 + i % 3, 1f, i * 37, uniform: true); } } if (floor == 4) { Vector2[] array = (Vector2[])(object)new Vector2[6] { new Vector2(-8f, -7f), new Vector2(8f, -6f), new Vector2(-5f, 8f), new Vector2(7f, 9f), new Vector2(-12f, 0f), new Vector2(2f, -12f) }; for (int j = 0; j < array.Length; j++) { Rock(array[j].x, array[j].y, 3.4f, 0.9f, 4f, j * 67, 0.72f); } for (int k = 0; k < 3; k++) { float num2 = (float)k * MathF.PI * 2f / 3f; float num3 = Mathf.Cos(num2) * 30f; float num4 = Mathf.Sin(num2) * 30f; Rock(num3, num4, 10f, 6f, 10f, k * 81); Place("SwampTree2", num3, num4, 1f, 26f, 1f, k * 100, uniform: true); Place("SwampTree2_log", num3 + 2f, num4 + 3f, 9f, 1.8f, 3f, k * 110); } } else { Rock(0f, -2f, 18f, 21f, 25f, 17f); Rock(-4f, -7f, 12f, 10f, 14f, 93f); Rock(5f, 5f, 11f, 15f, 12f, 42f); } for (int l = 0; l < 22; l++) { float num5 = (float)l * 137.5f * (MathF.PI / 180f); float x = Mathf.Sin(num5) * 33f; float z = Mathf.Cos(num5) * 33f; Rock(x, z, 3 + l % 3, 0.8f, 4f, l * 47, 0.8f); if (floor == 4) { Place("Bush01", x, z, 2.5f, 1.2f, 2.5f, l * 81); } else if (l % 3 == 0) { Place("FirTree_small_dead", x, z, 1f, 5f, 1f, l * 89, uniform: true); } } return; } if (floor == 6) { for (int m = -1; m <= 1; m += 2) { for (int n = 0; n < 17; n++) { Rock(m * 43, -95 + n * 12, 18f, 24 + n % 3 * 3, 20f, n * 53); } } for (int num6 = -1; num6 <= 1; num6 += 2) { for (int num7 = 0; num7 < 7; num7++) { Rock(-42 + num7 * 14, num6 * 98, 22f, 28f, 18f, num7 * 71); } } for (int num8 = 0; num8 < 3; num8++) { int num9 = ((num8 % 2 == 0) ? 1 : (-1)); float num10 = -44 + num8 * 44; Rock(num9 * 18, num10, 23f, 18f, 19f, 20 + num8 * 57); Rock(num9 * 30, num10 - 4f, 17f, 24f, 16f, num8 * 83); Place("Pickable_MountainCaveCrystal", num9 * 12, num10 - 9f, 2f, 3f, 2f, num8 * 109); Place("Pickable_MountainCaveCrystal", num9 * 28, num10 + 10f, 3f, 4f, 3f, num8 * 39); } for (int num11 = -1; num11 <= 1; num11 += 2) { for (int num12 = 0; num12 < 12; num12++) { Rock(num11 * 34, -85 + num12 * 15, 4f, 0.7f, 5f, num12 * 47, 0.8f); if (num12 % 3 == 0) { Place("Pickable_MountainCaveCrystal", num11 * 36, -85 + num12 * 15, 2f, 2.5f, 2f, num12 * 67); } } } scenery.Run(delegate { //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_001c: 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_003d: 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_006d: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("Beyond warm sanctum court"); val.transform.SetParent(parent, false); val.transform.position = origin + NumberedFloorLayout.AtGround(floor, new Vector3(18f, 5f, 73f)); Light obj = val.AddComponent<Light>(); obj.type = (LightType)2; obj.color = new Color(1f, 0.36f, 0.12f); obj.range = 26f; obj.intensity = 2.3f; obj.shadows = (LightShadows)0; }); return; } throw new ArgumentOutOfRangeException("floor"); void Place(string prefab, float num13, float num14, float w, float h, float d, float yaw = 0f, bool uniform = false, float embed = 0f) { //IL_0031: 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) //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_005e: Unknown result type (might be due to invalid IL or missing references) if (++count > 190) { throw new InvalidOperationException("Beyond advanced scenery budget exceeded."); } scenery.Place(parent, prefab, origin + NumberedFloorLayout.AtGround(floor, new Vector3(num13, -0.1f - h * embed, num14)), new Vector3(w, h, d), yaw, uniform, warm: false, frost); } void Rock(float x2, float z2, float w, float h, float d, float yaw = 0f, float embed = 0.5f) { Place("Rock_7", x2, z2, w, h, d, yaw, uniform: false, embed); } } } internal sealed class AuthoredVoidSkin { private readonly List<Object> Assets = new List<Object>(); private readonly string _prefix; private readonly VoidKind _kind; private static readonly Dictionary<VoidKind, AuthoredVoidSkin> Skins = new Dictionary<VoidKind, AuthoredVoidSkin>(); private Mesh[]? _meshes; private Material[]? _materials; private string[] _names = Array.Empty<string>(); private AuthoredVoidSkin(VoidKind kind) { //IL_001d: 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_0024: 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_0029: Invalid comparison between Unknown and I4 _kind = kind; _prefix = (((int)kind == 0) ? "eidolon" : (((int)kind == 1) ? "riftstalker" : "hollowcantor")); } internal static void Build(VoidKind kind, Transform rig, IReadOnlyDictionary<string, Transform> bones, Material native) { //IL_0005: 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_001b: Unknown result type (might be due to invalid IL or missing references) if (!Skins.TryGetValue(kind, out AuthoredVoidSkin value)) { value = new AuthoredVoidSkin(kind); Skins.Add(kind, value); } value.Attach(rig, bones, native); } private void Attach(Transform rig, IReadOnlyDictionary<string, Transform> bones, Material native) { //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: 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_010f: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Unknown result type (might be due to invalid IL or missing references) if (_meshes == null) { Load(rig, bones, native); } Transform[] array = (Transform[])(object)new Transform[_names.Length]; for (int i = 0; i < array.Length; i++) { array[i] = bones[_names[i]]; } for (int j = 0; j < 3; j++) { GameObject val = new GameObject("Stone" + j); val.transform.SetParent(rig, false); SkinnedMeshRenderer obj = val.AddComponent<SkinnedMeshRenderer>(); obj.sharedMesh = _meshes[j]; ((Renderer)obj).sharedMaterial = _materials[j]; obj.bones = array; obj.rootBone = bones["body"]; obj.quality = (SkinQuality)4; obj.updateWhenOffscreen = false; ((Renderer)obj).localBounds = (((int)_kind == 0) ? new Bounds(new Vector3(0f, 2.8f, 0f), new Vector3(11f, 10f, 10f)) : new Bounds(new Vector3(0f, 1.3f, 0f), new Vector3(7f, 7f, 8f))); ((Renderer)obj).shadowCastingMode = (ShadowCastingMode)(j != 2); ((Renderer)obj).receiveShadows = j != 2; } } private void Load(Transform rig, IReadOnlyDictionary<string, Transform> bones, Material native) { //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_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_01c2: Unknown result type (might be due to invalid IL or missing references) //IL_01c7: 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) //IL_010a: Unknown result type (might be due to invalid IL or missing references) //IL_010f: Unknown result type (might be due to invalid IL or missing references) //IL_0114: Unknown result type (might be due to invalid IL or missing references) //IL_02b2: Unknown result type (might be due to invalid IL or missing references) //IL_0310: Unknown result type (might be due to invalid IL or missing references) //IL_0312: Unknown result type (might be due to invalid IL or missing references) //IL_05aa: Unknown result type (might be due to invalid IL or missing references) //IL_05af: Unknown result type (might be due to invalid IL or missing references) //IL_03fc: Unknown result type (might be due to invalid IL or missing references) //IL_0401: Unknown result type (might be due to invalid IL or missing references) //IL_040e: Unknown result type (might be due to invalid IL or missing references) //IL_0413: Unknown result type (might be due to invalid IL or missing references) //IL_0420: Unknown result type (might be due to invalid IL or missing references) //IL_0425: Unknown result type (might be due to invalid IL or missing references) //IL_0432: Unknown result type (might be due to invalid IL or missing references) //IL_0437: Unknown result type (might be due to invalid IL or missing references) //IL_044f: Unknown result type (might be due to invalid IL or missing references) //IL_0454: Unknown result type (might be due to invalid IL or missing references) //IL_0471: Unknown result type (might be due to invalid IL or missing references) //IL_05fe: Unknown result type (might be due to invalid IL or missing references) //IL_0603: Unknown result type (might be due to invalid IL or missing references) //IL_0486: Expected O, but got Unknown //IL_0639: Unknown result type (might be due to invalid IL or missing references) //IL_063e: Unknown result type (might be due to invalid IL or missing references) //IL_0660: Unknown result type (might be due to invalid IL or missing references) //IL_0668: Unknown result type (might be due to invalid IL or missing references) //IL_0669: Unknown result type (might be due to invalid IL or missing references) //IL_0673: Unknown result type (might be due to invalid IL or missing references) //IL_0674: Unknown result type (might be due to invalid IL or missing references) //IL_0680: Expected O, but got Unknown //IL_06a2: Unknown result type (might be due to invalid IL or missing references) //IL_0798: Unknown result type (might be due to invalid IL or missing references) //IL_07ae: Unknown result type (might be due to invalid IL or missing references) using BinaryReader binaryReader = new BinaryReader(Resource(_prefix + ".mesh")); if (Encoding.ASCII.GetString(binaryReader.ReadBytes(8)) != "BEVM0001") { throw new InvalidDataException("Invalid Eidolon skin format."); } int num = binaryReader.ReadInt32(); int num2 = binaryReader.ReadInt32(); if (num < 3 || num > 100000 || num % 3 != 0 || num2 < 1 || num2 > 64) { throw new InvalidDataException("Invalid Eidolon skin counts."); } _names = new string[num2]; Matrix4x4[] array = (Matrix4x4[])(object)new Matrix4x4[num2]; HashSet<string> hashSet = new HashSet<string>(); for (int i = 0; i < num2; i++) { int num3 = binaryReader.ReadInt32(); if (num3 < 1 || num3 > 64) { throw new InvalidDataException("Invalid joint name."); } string text = Encoding.UTF8.GetString(binaryReader.ReadBytes(num3)); if (!hashSet.Add(text) || !bones.TryGetValue(text, out Transform value)) { throw new InvalidDataException("Missing/repeated Eidolon joint: " + text); } _names[i] = text; array[i] = value.worldToLocalMatrix * rig.localToWorldMatrix; } Vector3[] array2 = (Vector3[])(object)new Vector3[num]; Vector3[] array3 = (Vector3[])(object)new Vector3[num]; Vector2[] array4 = (Vector2[])(object)new Vector2[num]; BoneWeight[] array5 = (BoneWeight[])(object)new BoneWeight[num]; List<int>[] array6 = new List<int>[3] { new List<int>(), new List<int>(), new List<int>() }; int num4 = -1; for (int j = 0; j < num; j++) { array2[j] = new Vector3(F(binaryReader), F(binaryReader), F(binaryReader)); array3[j] = new Vector3(F(binaryReader), F(binaryReader), F(binaryReader)); array4[j] = new Vector2(F(binaryReader), F(binaryReader)); int[] array7 = new int[4] { binaryReader.ReadInt32(), binaryReader.ReadInt32(), binaryReader.ReadInt32(), binaryReader.ReadInt32() }; float[] array8 = new float[4] { F(binaryReader), F(binaryReader), F(binaryReader), F(binaryReader) }; float num5 = 0f; for (int k = 0; k < 4; k++) { if (array7[k] < 0 || array7[k] >= num2 || array8[k] < 0f || array8[k] > 1f) { throw new InvalidDataException("Invalid skin influence."); } num5 += array8[k]; } if (Mathf.Abs(num5 - 1f) > 0.001f || ((Vector3)(ref array3[j])).sqrMagnitude < 0.1f) { throw new InvalidDataException("Invalid skin weight sum/normal."); } int num6 = j; BoneWeight val = default(BoneWeight); ((BoneWeight)(ref val)).boneIndex0 = array7[0]; ((BoneWeight)(ref val)).boneIndex1 = array7[1]; ((BoneWeight)(ref val)).boneIndex2 = array7[2]; ((BoneWeight)(ref val)).boneIndex3 = array7[3]; ((BoneWeight)(ref val)).weight0 = array8[0]; ((BoneWeight)(ref val)).weight1 = array8[1]; ((BoneWeight)(ref val)).weight2 = array8[2]; ((BoneWeight)(ref val)).weight3 = array8[3]; array5[num6] = val; int num7 = binaryReader.ReadInt32(); if (num7 < 0 || num7 > 2 || (j % 3 != 0 && num7 != num4)) { throw new InvalidDataException("Invalid material triangle."); } num4 = num7; array6[num7].Add(j); } if (binaryReader.BaseStream.Position != binaryReader.BaseStream.Length) { throw new InvalidDataException("Trailing Eidolon skin data."); } Mesh[] array9 = (Mesh[])(object)new Mesh[3]; for (int l = 0; l < 3; l++) { if (array6[l].Count == 0) { throw new InvalidDataException("Empty Eidolon skin material."); } int count = array6[l].Count; Vector3[] array10 = (Vector3[])(object)new Vector3[count]; Vector3[] array11 = (Vector3[])(object)new Vector3[count]; Vector2[] array12 = (Vector2[])(object)new Vector2[count]; BoneWeight[] array13 = (BoneWeight[])(object)new BoneWeight[count]; int[] array14 = new int[count]; for (int m = 0; m < count; m++) { int num8 = array6[l][m]; array10[m] = array2[num8]; array11[m] = array3[num8]; array12[m] = array4[num8]; array13[m] = array5[num8]; array14[m] = m; } Mesh val2 = new Mesh { name = _prefix + " sculpted skin " + l, indexFormat = (IndexFormat)(count > 65535) }; Assets.Add((Object)(object)val2); val2.vertices = array10; val2.normals = array11; val2.uv = array12; val2.boneWeights = array13; val2.bindposes = array; val2.SetTriangles(array14, 0); val2.RecalculateTangents(); val2.RecalculateBounds(); array9[l] = val2; } Texture2D val3 = Texture(_prefix + "_basecolor.png", linear: false); Texture2D val4 = Texture(_prefix + "_normal.png", linear: true); Texture2D val5 = Texture(_prefix + "_roughness.png", linear: true); Texture2D val6 = Texture(_prefix + "_occlusion.png", linear: true); Texture2D val7 = Texture(_prefix + "_emission.png", linear: false); Color32[] pixels = val4.GetPixels32(); for (int n = 0; n < pixels.Length; n++) { pixels[n] = new Color32(byte.MaxValue, pixels[n].g, pixels[n].b, pixels[n].r); } val4.SetPixels32(pixels); val4.Apply(true, true); Color32[] pixels2 = val5.GetPixels32(); for (int num9 = 0; num9 < pixels2.Length; num9++) { pixels2[num9] = new Color32((byte)0, (byte)0, (byte)0, (byte)(255 - pixels2[num9].r)); } val5.SetPixels32(pixels2); val5.Apply(true, true); Material[] array15 = (Material[])(object)new Material[3]; for (int num10 = 0; num10 < 3; num10++) { Material val8 = new Material(native) { name = "Beyond sculpted " + _prefix + " " + num10, mainTexture = (Texture)(object)val3, mainTextureScale = Vector2.one, mainTextureOffset = Vector2.zero }; Assets.Add((Object)(object)val8); if (val8.HasProperty("_Color")) { val8.SetColor("_Color", Color.white); } if (val8.HasProperty("_Metallic")) { val8.SetFloat("_Metallic", 0f); } Map(val8, "_BumpMap", (Texture)(object)val4, "_NORMALMAP"); Map(val8, "_MetallicGlossMap", (Texture)(object)val5, "_METALLICGLOSSMAP"); Map(val8, "_OcclusionMap", (Texture)(object)val6); Map(val8, "_EmissionMap", (Texture)(object)val7, "_EMISSION"); if (val8.HasProperty("_BumpScale")) { val8.SetFloat("_BumpScale", 0.7f); } if (val8.HasProperty("_OcclusionStrength")) { val8.SetFloat("_OcclusionStrength", 0.65f); } if (val8.HasProperty("_GlossMapScale")) { val8.SetFloat("_GlossMapScale", 1f); } if (val8.HasProperty("_EmissionColor")) { val8.SetColor("_EmissionColor", new Color(0.8f, 0.01f, 1f) * ((num10 == 2) ? 3f : 0.3f)); } array15[num10] = val8; } val3.Apply(true, true); val6.Apply(true, true); val7.Apply(true, true); _meshes = array9; _materials = array15; Debug.Log((object)("Beyond " + _prefix + " weighted skin loaded: " + num / 3 + " triangles, " + num2 + " joints, 1024px base/normal/response/AO/emission. Native appearance/deformation still require testing.")); Debug.Log((object)("Beyond " + _prefix + " native shader '" + ((Object)native.shader).name + "'; map properties normal=" + native.HasProperty("_BumpMap") + ", roughness=" + native.HasProperty("_MetallicGlossMap") + ", AO=" + native.HasProperty("_OcclusionMap") + ", emission=" + native.HasProperty("_EmissionMap") + ".")); } private static float F(BinaryReader reader) { float num = reader.ReadSingle(); if (float.IsNaN(num) || float.IsInfinity(num)) { throw new InvalidDataException("Non-finite Eidolon skin data."); } return num; } private Stream Resource(string name) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) return Assembly.GetExecutingAssembly().GetManifestResourceStream((((int)_kind == 0) ? "Beyond.Eidolon." : "Beyond.Adds.") + name) ?? throw new InvalidDataException("Missing authored Eidolon asset: " + name); } private Texture2D Texture(string name, bool linear) { //IL_001a: 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_0030: 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_003f: Expected O, but got Unknown using Stream stream = Resource(name); using MemoryStream memoryStream = new MemoryStream(); stream.CopyTo(memoryStream); Texture2D val = new Texture2D(2, 2, (TextureFormat)4, true, linear) { name = "Beyond " + name, filterMode = (FilterMode)1, wrapMode = (TextureWrapMode)1 }; Assets.Add((Object)(object)val); if (!ImageConversion.LoadImage(val, memoryStream.ToArray(), false) || ((Texture)val).width != 1024 || ((Texture)val).height != 1024) { throw new InvalidDataException("Invalid authored Eidolon map: " + name); } return val; } private static void Map(Material material, string property, Texture texture, string keyword = "") { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) if (material.HasProperty(property)) { material.SetTexture(property, texture); material.SetTextureScale(property, Vector2.one); material.SetTextureOffset(property, Vector2.zero); if (keyword.Length > 0) { material.EnableKeyword(keyword); } } } internal static void Dispose() { foreach (AuthoredVoidSkin value in Skins.Values) { foreach (Object asset in value.Assets) { if (asset != (Object)null) { Object.Destroy(asset); } } } Skins.Clear(); } } internal sealed class BeyondAtmosphere : IDisposable { private const string ArenaName = "brom8.beyond.island"; private const string CanyonName = "brom8.beyond.canyon"; private const string ForestName = "brom8.beyond.forest"; private const string SwampName = "brom8.beyond.swamp"; private const string MountainName = "brom8.beyond.mountain"; private const string SanctumName = "brom8.beyond.sanctum"; private const string ShopName = "brom8.beyond.stars"; private readonly TrialWorld _world; private readonly BeyondIslandMist _mist = new BeyondIslandMist(); private readonly BeyondSnow _snow = new BeyondSnow(); private readonly Dictionary<int, EnvSetup> _later = new Dictionary<int, EnvSetup>(); private EnvMan? _manager; private EnvSetup? _arena; private EnvSetup? _canyon; private EnvSetup? _forest; private EnvSetup? _swamp; private EnvSetup? _mountain; private EnvSetup? _sanctum; private EnvSetup? _shop; private Camera? _camera; private CameraClearFlags _clear; private Color _background; private float _far; private bool _active; private bool _inShop; private int _floor; private bool _fog; private FogMode _fogMode; private float _fogDensity; private Color _fogColor; private EnvSetup? FloorEnvironment { get { if (_later.TryGetValue(_floor, out EnvSetup value)) { return value; } EnvSetup result; switch (_floor) { case 1: result = _canyon; break; case 2: result = _forest; break; case 3: case 4: result = _swamp; break; case 5: result = _mountain; break; case 6: result = _sanctum; break; default: result = _arena; break; } return result; } } public string? EnvironmentOverride { get { if (!_active) { return null; } if (!_inShop) { return FloorEnvironment?.m_name; } return "brom8.beyond.stars"; } } public BeyondAtmosphere(TrialWorld world) { _world = world; } public void LateUpdate() { //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_037d: Unknown result type (might be due to invalid IL or missing references) //IL_0382: Unknown result type (might be due to invalid IL or missing references) //IL_0393: Unknown result type (might be due to invalid IL or missing references) //IL_0398: Unknown result type (might be due to invalid IL or missing references) //IL_03b4: Unknown result type (might be due to invalid IL or missing references) //IL_0410: Unknown result type (might be due to invalid IL or missing references) //IL_0457: Unknown result type (might be due to invalid IL or missing references) //IL_0479: Unknown result type (might be due to invalid IL or missing references) //IL_047e: Unknown result type (might be due to invalid IL or missing references) //IL_048b: Unknown result type (might be due to invalid IL or missing references) //IL_04a0: Unknown result type (might be due to invalid IL or missing references) //IL_0659: Unknown result type (might be due to invalid IL or missing references) //IL_059f: Unknown result type (might be due to invalid IL or missing references) //IL_05a4: Unknown result type (might be due to invalid IL or missing references) //IL_05b0: Unknown result type (might be due to invalid IL or missing references) //IL_05b5: Unknown result type (might be due to invalid IL or missing references) //IL_060d: Unknown result type (might be due to invalid IL or missing references) //IL_05fb: Unknown result type (might be due to invalid IL or missing references) //IL_0325: Unknown result type (might be due to invalid IL or missing references) //IL_032a: Unknown result type (might be due to invalid IL or missing references) //IL_032b: 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) //IL_0332: Unknown result type (might be due to invalid IL or missing references) //IL_0334: Unknown result type (might be due to invalid IL or missing references) //IL_0553: Unknown result type (might be due to invalid IL or missing references) //IL_0558: Unknown result type (might be due to invalid IL or missing references) //IL_0560: Unknown result type (might be due to invalid IL or missing references) //IL_0565: Unknown result type (might be due to invalid IL or missing references) Player localPlayer = Player.m_localPlayer; BeyondPlugin? instance = BeyondPlugin.Instance; bool flag = instance != null && instance.Runtime?.Realm?.Inside == true; if (!((Object)(object)localPlayer != (Object)null) || !(_world.IsBeyond(((Component)localPlayer).transform.position) || flag)) { Restore(); } else { if ((Object)(object)EnvMan.instance == (Object)null) { return; } if ((Object)(object)_manager != (Object)(object)EnvMan.instance) { _manager = EnvMan.instance; EnvSetup source = (from e in _manager.m_environments where e.m_name.IndexOf("mist", StringComparison.OrdinalIgnoreCase) >= 0 orderby e.m_fogDensityDay descending select e).FirstOrDefault() ?? _manager.m_environments.First(); _arena = Create(source, "brom8.beyond.island", shop: false); _shop = Create(source, "brom8.beyond.stars", shop: true); _canyon = CreateCanyon(source); _forest = CreateForest(source); _swamp = CreateSwamp(source); _manager.m_environments.Add(_arena); _manager.m_environments.Add(_shop); _manager.m_environments.Add(_canyon); _manager.m_environments.Add(_forest); _manager.m_environments.Add(_swamp); _mountain = CreateMountain(source, sanctum: false); _sanctum = CreateMountain(source, sanctum: true); _manager.m_environments.Add(_mountain); _manager.m_environments.Add(_sanctum); _later.Clear(); for (int num = 7; num <= 20; num++) { EnvSetup val; if ((uint)(num - 13) <= 1u) { val = CreateMountain(source, sanctum: false); } else { EnvSetup val2; if (((uint)(num - 7) <= 1u || (uint)(num - 11) <= 1u) ? true : false) { val2 = CreateCanyon(source); } else { bool flag2 = ((num == 9 || num == 17) ? true : false); val2 = (flag2 ? CreateForest(source) : CreateMountain(source, sanctum: true)); } val = val2; } EnvSetup val3 = val; val3.m_name = "brom8.beyond.floor" + num; if ((uint)(num - 13) <= 1u) { val3.m_snowBuildup = 1f; val3.m_fogDensityDay = (val3.m_fogDensityNight = 0.008f); } if (((uint)(num - 11) <= 1u || num == 18) ? true : false) { val3.m_ambColorDay = (val3.m_ambColorNight = new Color(0.43f, 0.22f, 0.16f)); } _later.Add(num, val3); _manager.m_environments.Add(val3); } } if (!_active) { _fog = RenderSettings.fog; _fogMode = RenderSettings.fogMode; _fogDensity = RenderSettings.fogDensity; _fogColor = RenderSettings.fogColor; } _active = true; _inShop = !flag && _world.IsShop(((Component)localPlayer).transform.position); _floor = (flag ? BeyondPlugin.Instance.Runtime.Realm.EnvironmentFloor : _world.SelectedFloor); _mist.Update(!_inShop && _floor == 0, _world.Arena); BeyondSnow snow = _snow; bool flag3 = !_inShop; if (flag3) { int floor = _floor; bool flag4 = (uint)(floor - 13) <= 1u; flag3 = flag4; } snow.Update(flag3, ((Component)localPlayer).transform.position); EnvSetup val4 = (_inShop ? _shop : FloorEnvironment); Color val5 = val4.m_fogColorDay; if (flag && SharedRealmWorld.ContainsPreview(((Component)localPlayer).transform.position)) { float num2 = ((Component)localPlayer).transform.position.z - SharedRealmWorld.PreviewOrigin.z; int num3 = LandscapePreviewLayout.Section(num2); if (num3 > 0) { int num4 = LandscapePreviewLayout.EnvironmentFloor((float)(num3 * 128 - 65)); EnvSetup value; EnvSetup val = (EnvSetup)((!_later.TryGetValue(num4, out value)) ? (num4 switch { 1 => _canyon, 2 => _forest, 3 => _swamp, 6 => _sanctum, _ => _mountain, }) : value); EnvSetup val6 = val; if (val6 != null) { val5 = Color.Lerp(val6.m_fogColorDay, val5, LandscapePreviewLayout.Transition(num2)); } } } Camera main = Camera.main; if ((Object)(object)main != (Object)(object)_camera) { RestoreCamera(); _camera = main; if ((Object)(object)_camera != (Object)null) { _clear = _camera.clearFlags; _background = _camera.backgroundColor; _far = _camera.farClipPlane; } } if ((Object)(object)_camera != (Object)null) { _camera.clearFlags = (CameraClearFlags)2; _camera.backgroundColor = (Color)((_inShop || _floor == 0) ? new Color(0.009f, 0.006f, 0.022f) : val5); _camera.farClipPlane = (flag ? 650 : (_inShop ? 90 : ((_floor == 0) ? 160 : 210))); } RenderSettings.fog = true; RenderSettings.fogMode = (FogMode)3; RenderSettings.fogColor = val5; RenderSettings.fogDensity = (flag ? 0.0025f : val4.m_fogDensityDay); } } private static EnvSetup CreateCanyon(EnvSetup source) { //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_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0030: 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_0049: 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_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0055: 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_0057: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_005d: 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_005f: 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_0065: Unknown result type (might be due to invalid IL or missing references) //IL_0066: 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) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_007d: 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) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_008d: 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_00d1: 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_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_00da: 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_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: 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) EnvSetup obj = Create(source, "brom8.beyond.canyon", shop: false); obj.m_alwaysDark = false; obj.m_ambColorDay = (obj.m_ambColorNight = new Color(0.68f, 0.46f, 0.29f)); obj.m_fogColorDay = (obj.m_fogColorMorning = (obj.m_fogColorEvening = (obj.m_fogColorNight = new Color(0.64f, 0.39f, 0.18f)))); obj.m_fogColorSunDay = (obj.m_fogColorSunMorning = (obj.m_fogColorSunEvening = (obj.m_fogColorSunNight = obj.m_fogColorDay))); obj.m_fogDensityDay = (obj.m_fogDensityMorning = (obj.m_fogDensityEvening = (obj.m_fogDensityNight = 0.009f))); obj.m_sunColorDay = (obj.m_sunColorMorning = (obj.m_sunColorEvening = (obj.m_sunColorNight = new Color(1f, 0.75f, 0.42f)))); obj.m_lightIntensityDay = (obj.m_lightIntensityNight = 0.75f); return obj; } private static EnvSetup CreateForest(EnvSetup source) { //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_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0030: 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_0049: 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_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0055: 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_0057: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_005d: 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_005f: 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_0065: Unknown result type (might be due to invalid IL or missing references) //IL_0066: 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) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_007d: 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) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_008d: 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_00d1: 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_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_00da: 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_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: 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) EnvSetup obj = Create(source, "brom8.beyond.forest", shop: false); obj.m_alwaysDark = false; obj.m_ambColorDay = (obj.m_ambColorNight = new Color(0.34f, 0.42f, 0.32f)); obj.m_fogColorDay = (obj.m_fogColorMorning = (obj.m_fogColorEvening = (obj.m_fogColorNight = new Color(0.08f, 0.14f, 0.12f)))); obj.m_fogColorSunDay = (obj.m_fogColorSunMorning = (obj.m_fogColorSunEvening = (obj.m_fogColorSunNight = obj.m_fogColorDay))); obj.m_fogDensityDay = (obj.m_fogDensityMorning = (obj.m_fogDensityEvening = (obj.m_fogDensityNight = 0.012f))); obj.m_sunColorDay = (obj.m_sunColorMorning = (obj.m_sunColorEvening = (obj.m_sunColorNight = new Color(0.66f, 0.76f, 0.52f)))); obj.m_lightIntensityDay = (obj.m_lightIntensityNight = 0.6f); return obj; } private static EnvSetup CreateSwamp(EnvSetup source) { //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_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) //IL_0029: 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_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_0048: 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) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0050: 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_0056: 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_0058: 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_005e: 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_0069: 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_006f: 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) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_007d: 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) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: 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_00d1: 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_00d3: 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_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) EnvSetup obj = Create(source, "brom8.beyond.swamp", shop: false); obj.m_ambColorDay = (obj.m_ambColorNight = new Color(0.25f, 0.31f, 0.16f)); obj.m_fogColorDay = (obj.m_fogColorMorning = (obj.m_fogColorEvening = (obj.m_fogColorNight = new Color(0.06f, 0.1f, 0.045f)))); obj.m_fogColorSunDay = (obj.m_fogColorSunMorning = (obj.m_fogColorSunEvening = (obj.m_fogColorSunNight = obj.m_fogColorDay))); obj.m_fogDensityDay = (obj.m_fogDensityMorning = (obj.m_fogDensityEvening = (obj.m_fogDensityNight = 0.018f))); obj.m_sunColorDay = (obj.m_sunColorMorning = (obj.m_sunColorEvening = (obj.m_sunColorNight = new Color(0.45f, 0.5f, 0.22f)))); obj.m_lightIntensityDay = (obj.m_lightIntensityNight = 0.38f); return obj; } private static EnvSetup CreateMountain(EnvSetup source, bool sanctum) { //IL_0047: 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_004c: Unknown result type (might be due to invalid IL or missing references) //IL_004d: 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_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0085: 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_008a: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_008c: 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_0092: 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) //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_009a: Unknown result type (might be due to invalid IL or missing references) //IL_009b: 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_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: 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_00b3: 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_00b9: 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_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: 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) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Unknown result type (might be due to invalid IL or missing references) //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_0117: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_011d: Unknown result type (might be due to invalid IL or missing references) //IL_011e: Unknown result type (might be due to invalid IL or missing references) //IL_011f: Unknown result type (might be due to invalid IL or missing references) //IL_0120: Unknown result type (might be due to invalid IL or missing references) //IL_0125: 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_0127: 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) //IL_012e: Unknown result type (might be due to invalid IL or missing references) EnvSetup obj = Create(source, sanctum ? "brom8.beyond.sanctum" : "brom8.beyond.mountain", shop: false); obj.m_alwaysDark = sanctum; obj.m_ambColorDay = (obj.m_ambColorNight = (sanctum ? new Color(0.27f, 0.31f, 0.43f) : new Color(0.57f, 0.65f, 0.78f))); obj.m_fogColorDay = (obj.m_fogColorMorning = (obj.m_fogColorEvening = (obj.m_fogColorNight = (sanctum ? new Color(0.055f, 0.075f, 0.13f) : new Color(0.31f, 0.41f, 0.55f))))); obj.m_fogColorSunDay = (obj.m_fogColorSunMorning = (obj.m_fogColorSunEvening = (obj.m_fogColorSunNight = obj.m_fogColorDay))); obj.m_fogDensityDay = (obj.m_fogDensityMorning = (obj.m_fogDensityEvening = (obj.m_fogDensityNight = (sanctum ? 0.012f : 0.008f)))); obj.m_sunColorDay = (obj.m_sunColorMorning = (obj.m_sunColorEvening = (obj.m_sunColorNight = new Color(0.68f, 0.78f, 1f)))); obj.m_lightIntensityDay = (obj.m_lightIntensityNight = (sanctum ? 0.45f : 0.8f)); return obj; } private static EnvSetup Create(EnvSetup source, string name, bool shop) { //IL_00be: 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_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: 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_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_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: 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_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: 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_00f9: 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_0100: 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_010f: Unknown result type (might be due to invalid IL or missing references) //IL_0110: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Unknown result type (might be due to invalid IL or missing references) //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_0117: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Unknown result type (might be due to invalid IL or missing references) //IL_011e: Unknown result type (might be due to invalid IL or missing references) //IL_011f: Unknown result type (might be due to invalid IL or missing references) //IL_0120: Unknown result type (might be due to invalid IL or missing references) //IL_0121: 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_0127: 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_0187: 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_0189: Unknown result type (might be due to invalid IL or missing references) //IL_018e: 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_0190: Unknown result type (might be due to invalid IL or missing references) //IL_0191: Unknown result type (might be due to invalid IL or missing references) //IL_0196: Unknown result type (might be due to invalid IL or missing references) //IL_0197: Unknown result type (might be due to invalid IL or missing references) //IL_0198: 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_019e: Unknown result type (might be due to invalid IL or missing references) //IL_019f: Unknown result type (might be due to invalid IL or missing references) EnvSetup obj = source.Clone(); obj.m_name = name; obj.m_default = false; obj.m_isWet = (obj.m_isCold = (obj.m_isColdAtNight = (obj.m_isFreezing = (obj.m_isFreezingAtNight = false)))); obj.m_snowBuildup = 0f; obj.m_alwaysDark = true; obj.m_envObject = null; obj.m_psystems = Array.Empty<GameObject>(); obj.m_ambientLoop = null; obj.m_ambientList = ""; obj.m_rainCloudAlpha = 0f; obj.m_windMin = (obj.m_windMax = 0f); obj.m_ambColorDay = (obj.m_ambColorNight = (shop ? new Color(0.45f, 0.4f, 0.55f) : new Color(0.28f, 0.24f, 0.4f))); obj.m_fogColorDay = (obj.m_fogColorMorning = (obj.m_fogColorEvening = (obj.m_fogColorNight = new Color(0.025f, 0.018f, 0.055f)))); obj.m_fogColorSunDay = (obj.m_fogColorSunMorning = (obj.m_fogColorSunEvening = (obj.m_fogColorSunNight = obj.m_fogColorDay))); float fogDensityNight = (shop ? 0.002f : Mathf.Max(0.018f, source.m_fogDensityDay * 0.5f)); obj.m_fogDensityDay = (obj.m_fogDensityMorning = (obj.m_fogDensityEvening = (obj.m_fogDensityNight = fogDensityNight))); obj.m_sunColorDay = (obj.m_sunColorMorning = (obj.m_sunColorEvening = (obj.m_sunColorNight = new Color(0.3f, 0.25f, 0.45f)))); obj.m_lightIntensityDay = (obj.m_lightIntensityNight = (shop ? 0.3f : 0.15f)); return obj; } private void RestoreCamera() { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_camera != (Object)null) { _camera.clearFlags = _clear; _camera.backgroundColor = _background; _camera.farClipPlane = _far; } _camera = null; } private void Restore() { //IL_0010: 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_003d: 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) if (_active) { _mist.Update(active: false, Vector3.zero); _snow.Update(active: false, Vector3.zero); RestoreCamera(); RenderSettings.fog = _fog; RenderSettings.fogMode = _fogMode; RenderSettings.fogDensity = _fogDensity; RenderSettings.fogColor = _fogColor; _active = false; } } public void Dispose() { Restore(); _mist.Dispose(); _snow.Dispose(); if ((Object)(object)_manager != (Object)null) { foreach (EnvSetup value in _later.Values) { _manager.m_environments.Remove(value); } } _later.Clear(); if ((Object)(object)_manager != (Object)null) { if (_arena != null) { _manager.m_environments.Remove(_arena); } if (_shop != null) { _manager.m_environments.Remove(_shop); } if (_canyon != null) { _manager.m_environments.Remove(_canyon); } if (_forest != null) { _manager.m_environments.Remove(_forest); } if (_swamp != null) { _manager.m_environments.Remove(_swamp); } } if ((Object)(object)_manager != (Object)null) { if (_mountain != null) { _manager.m_environments.Remove(_mountain); } if (_sanctum != null) { _manager.m_environments.Remove(_sanctum); } } } } [HarmonyPatch(typeof(EnvMan), "GetEnvironmentOverride")] internal static class BeyondEnvironmentPatch { private static void Postfix(ref string __result) { string text = BeyondPlugin.Instance?.Runtime?.Client?.Atmosphere.EnvironmentOverride; if (text != null) { __result = text; } } } internal sealed class BeyondIslandMist : IDisposable { private const int MaximumParticles = 512; private GameObject? _root; private ParticleSystem? _particles; private Vector3 _center; private bool _active; private bool _warned; private float _nextSearch; private float _accumulator; private float _perSecond = 25f; private MinMaxGradient _color; public void Update(bool active, Vector3 center) { //IL_00c5: 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_00d6: 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) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) if (!active) { if (_active && (Object)(object)_particles != (Object)null) { _particles.Stop(true, (ParticleSystemStopBehavior)0); _root.SetActive(false); } _active = false; _accumulator = 0f; return; } if ((Object)(object)_particles == (Object)null) { if (Time.unscaledTime < _nextSearch) { return; } _nextSearch = Time.unscaledTime + 10f; ParticleMist val = FindSource(); if ((Object)(object)val == (Object)null || !Create(val)) { if (!_warned) { Debug.LogWarning((object)"[Beyond] Native ParticleMist visual is unavailable; arena uses environment haze only. Visible mist needs a supported native particle material."); _warned
plugins/Beyond.Core.dll
Decompiled 5 hours ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics; using System.Globalization; using System.Linq; using System.Numerics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using Microsoft.CodeAnalysis; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("Brom8")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("0.32.1.0")] [assembly: AssemblyInformationalVersion("0.32.1+7631678d0972989b79d54fd3945dbfa47aa166be")] [assembly: AssemblyProduct("Beyond.Core")] [assembly: AssemblyTitle("Beyond.Core")] [assembly: AssemblyVersion("0.32.1.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [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] [Embedded] [AttributeUsage(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] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace Beyond.Core { [Serializable] public sealed class BankAccount { public string character = ""; public int balance; public long revision; } [Serializable] public sealed class BankTransfer { public string character = ""; public string transaction = ""; public string kind = ""; public string state = "waiting"; public int amount; public int moved; public bool confirmed; public int beforeBalance; public long revision; } public sealed class BankLedger { public const int MaximumBalance = 1000000000; private readonly List<BankAccount> _accounts; private readonly List<BankTransfer> _transfers; public BankLedger(List<BankAccount> accounts, List<BankTransfer> transfers) { _accounts = accounts ?? throw new ArgumentNullException("accounts"); _transfers = transfers ?? throw new ArgumentNullException("transfers"); if (accounts.Any((BankAccount a) => a == null || string.IsNullOrEmpty(a.character) || a.balance < 0 || a.balance > 1000000000 || a.revision < 0 || a.revision == long.MaxValue) || accounts.Select((BankAccount a) => a.character).Distinct<string>(StringComparer.Ordinal).Count() != accounts.Count || transfers.Any((BankTransfer t) => t == null || string.IsNullOrEmpty(t.character) || !Guid.TryParseExact(t.transaction, "N", out var _) || (t.kind != "deposit" && t.kind != "withdraw") || !SupportedAmount(t.amount) || t.revision < 0 || t.revision == long.MaxValue || t.beforeBalance < 0 || t.beforeBalance > 1000000000 || (t.state != "waiting" && t.state != "settled") || t.moved < 0 || t.moved > t.amount || (t.kind == "deposit" && t.moved != 0 && t.moved != t.amount) || (t.state == "waiting" && (t.moved != 0 || t.confirmed)) || !accounts.Any((BankAccount a) => a.character == t.character)) || transfers.Select((BankTransfer t) => t.transaction).Distinct<string>(StringComparer.Ordinal).Count() != transfers.Count || transfers.Where((BankTransfer t) => t.state == "waiting").GroupBy<BankTransfer, string>((BankTransfer t) => t.character, StringComparer.Ordinal).Any((IGrouping<string, BankTransfer> g) => g.Count() > 1)) { throw new ArgumentException("Invalid bank ledger; preserve the original journal."); } foreach (BankTransfer transfer in transfers.Where((BankTransfer t) => t.state == "waiting")) { if (!_accounts.Any((BankAccount a) => a.character == transfer.character) || Balance(transfer.character) > 1000000000 - transfer.amount) { throw new ArgumentException("Invalid bank reservation headroom."); } } } public int Balance(string character) { return _accounts.Find((BankAccount a) => a.character == character)?.balance ?? 0; } public BankTransfer? Pending(string character) { return _transfers.Find((BankTransfer t) => t.character == character && t.state == "waiting"); } public BankTransfer? Find(string character, string transaction) { return _transfers.Find((BankTransfer t) => t.character == character && t.transaction == transaction); } public static bool SupportedAmount(int amount) { switch (amount) { case 100: case 500: case 1000: case 2000: return true; default: return false; } } public bool Synchronize(string character, int balance, long revision) { if (string.IsNullOrEmpty(character) || balance < 0 || balance > 1000000000 || revision < 0 || revision == long.MaxValue || Pending(character) != null) { return false; } BankAccount bankAccount = _accounts.Find((BankAccount a) => a.character == character); if (bankAccount == null) { bankAccount = new BankAccount { character = character }; _accounts.Add(bankAccount); } bankAccount.balance = balance; bankAccount.revision = revision; return true; } public bool TryAuthorize(string character, string transaction, string kind, int amount, out BankTransfer? transfer, out string reason) { transfer = null; reason = "Invalid bank request."; if (string.IsNullOrEmpty(character) || !Guid.TryParseExact(transaction, "N", out var _) || (kind != "deposit" && kind != "withdraw") || !SupportedAmount(amount)) { return false; } BankTransfer bankTransfer = _transfers.Find((BankTransfer t) => t.transaction == transaction); if (bankTransfer != null) { if (bankTransfer.character != character || bankTransfer.kind != kind || bankTransfer.amount != amount) { return false; } transfer = bankTransfer; reason = ""; return true; } if (Pending(character) != null) { reason = "Finish the pending bank transfer first."; return false; } BankAccount bankAccount = _accounts.Find((BankAccount a) => a.character == character); int num = bankAccount?.balance ?? 0; if (bankAccount != null && bankAccount.revision >= 9223372036854775806L) { reason = "Bank revision limit reached; preserve the account for recovery."; return false; } if (kind == "withdraw" && num < amount) { reason = "Not enough coins in your bank."; return false; } if (kind == "deposit" && num > 1000000000 - amount) { reason = "Bank balance limit reached."; return false; } if (bankAccount == null) { bankAccount = new BankAccount { character = character }; _accounts.Add(bankAccount); } if (kind == "withdraw") { bankAccount.balance -= amount; } transfer = new BankTransfer { character = character, transaction = transaction, kind = kind, amount = amount, beforeBalance = num, revision = bankAccount.revision }; _transfers.Add(transfer); reason = ""; return true; } public bool Settle(BankTransfer transfer, int moved) { if (!_transfers.Contains(transfer) || moved < 0 || moved > transfer.amount || (transfer.kind == "deposit" && moved != 0 && moved != transfer.amount)) { return false; } if (transfer.state == "settled") { return transfer.moved == moved; } BankAccount bankAccount = _accounts.Find((BankAccount a) => a.character == transfer.character) ?? throw new InvalidOperationException("Missing bank account."); int num = ((transfer.kind == "deposit") ? moved : (transfer.amount - moved)); if (bankAccount.balance > 1000000000 - num) { return false; } bankAccount.balance += num; transfer.moved = moved; transfer.state = "settled"; bankAccount.revision = transfer.revision + 1; return true; } public void Trim(string character) { BankTransfer[] array = _transfers.Where((BankTransfer t) => t.character == character && t.state == "settled" && t.confirmed).ToArray(); foreach (BankTransfer item in array.Take(Math.Max(0, array.Length - 256))) { _transfers.Remove(item); } } } public static class BankReceipt { public static bool TryResult(string receipt, out int moved) { string text = (receipt.StartsWith("done:", StringComparison.Ordinal) ? receipt.Substring(5) : (receipt.StartsWith("settled:", StringComparison.Ordinal) ? receipt.Substring(8) : null)); moved = 0; if (text != null && int.TryParse(text, NumberStyles.None, CultureInfo.InvariantCulture, out moved) && moved >= 0) { return moved <= 2000; } return false; } public static bool ResolvesIntent(string receipt, string kind, int amount) { if ((kind == "deposit" || kind == "withdraw") && BankLedger.SupportedAmount(amount) && TryResult(receipt, out var moved) && moved <= amount) { if (!(kind == "withdraw") && moved != 0) { return moved == amount; } return true; } return false; } } [Serializable] public sealed class CharacterAccount { public int schema = 1; public string epoch = ""; public int highest = -1; public bool allowLegacyProgress = true; public int balance; public long revision; public long deaths; public long bossKills; public string trackingSince = ""; public bool Valid { get { if (schema == 1 && Guid.TryParseExact(epoch, "N", out var _) && highest >= -1 && highest <= 20 && balance >= 0 && balance <= 1000000000 && revision >= 0 && revision < long.MaxValue && deaths >= 0 && bossKills >= 0 && trackingSince != null) { return trackingSince.Length <= 40; } return false; } } public static CharacterAccount Create(int highest = -1) { return new CharacterAccount { epoch = Guid.NewGuid().ToString("N"), highest = highest }; } public bool Complete(string expectedEpoch, int floor) { if (!Valid || epoch != expectedEpoch || floor < 0 || floor > 20 || floor <= highest) { return false; } highest = floor; return true; } public bool Reset(string expectedEpoch) { if (!Valid || epoch != expectedEpoch) { return false; } epoch = Guid.NewGuid().ToString("N"); highest = -1; allowLegacyProgress = false; return true; } public bool ApplyBank(int before, long expectedRevision, string kind, int amount, int moved) { if (!Valid || revision >= 9223372036854775806L || balance != before || revision != expectedRevision || (amount != 500 && amount != 2000) || (kind != "deposit" && kind != "withdraw") || moved < 0 || moved > amount || (kind == "deposit" && moved != 0 && moved != amount)) { return false; } long num = (long)balance + (long)((kind == "deposit") ? moved : (-moved)); if (num < 0 || num > 1000000000) { return false; } balance = (int)num; revision++; return true; } } public static class CleanupSequence { public static void Run(params Action[] actions) { List<Exception> list = null; foreach (Action action in actions) { try { action(); } catch (Exception item) { (list ?? (list = new List<Exception>())).Add(item); } } if (list != null) { throw new AggregateException("One or more cleanup operations failed.", list); } } } public static class CoinSplit { public static IReadOnlyDictionary<string, int> Divide(int pool, IEnumerable<string> survivors) { if (pool < 0) { throw new ArgumentOutOfRangeException("pool"); } if (survivors == null) { throw new ArgumentNullException("survivors"); } string[] array = survivors.ToArray(); if (array.Length == 0 || array.Any(string.IsNullOrWhiteSpace)) { throw new ArgumentException("At least one valid survivor ID is required.", "survivors"); } if (array.Distinct<string>(StringComparer.Ordinal).Count() != array.Length) { throw new ArgumentException("Survivor IDs must be unique.", "survivors"); } Array.Sort(array, (IComparer<string>?)StringComparer.Ordinal); Dictionary<string, int> dictionary = new Dictionary<string, int>(StringComparer.Ordinal); int num = pool / array.Length; int num2 = pool % array.Length; for (int i = 0; i < array.Length; i++) { dictionary.Add(array[i], num + ((i < num2) ? 1 : 0)); } return new ReadOnlyDictionary<string, int>(dictionary); } } [Serializable] public sealed class CommerceOperation { public string id = ""; public string character = ""; public string kind = ""; public string run = ""; public string product = ""; public string source = ""; public string state = "queued"; public long world; public long revision; public int floor; public int amount; public int bankPart; public int carriedPart; public int quantity; public int beforeBalance; public bool confirmed; public bool IsDebit { get { if (!(kind == "entry")) { return kind == "purchase"; } return true; } } public bool IsCredit { get { if (!(kind == "reward")) { return kind == "refund"; } return true; } } public bool IsStatistic { get { if (!(kind == "death")) { return kind == "bosskill"; } return true; } } public int AfterBalance => beforeBalance + (IsDebit ? (-bankPart) : (IsCredit ? bankPart : 0)); public bool Valid { get { if (Guid.TryParseExact(id, "N", out var result) && !string.IsNullOrEmpty(character) && character.Length <= 32 && (IsDebit || IsCredit || IsStatistic) && (state == "queued" || state == "waiting" || state == "done" || state == "declined") && floor >= 0 && floor <= 20 && amount >= 0 && amount <= 1000000 && bankPart >= 0 && carriedPart >= 0 && bankPart <= amount && carriedPart <= amount && quantity >= 0 && quantity <= 9999 && product != null && product.Length <= 128 && source != null && source.Length <= 100 && run != null && (run.Length == 0 || Guid.TryParseExact(run, "N", out result)) && beforeBalance >= 0 && beforeBalance <= 1000000000 && revision >= 0 && revision < 9223372036854775806L && (kind != "purchase" || (product.Length > 0 && quantity > 0)) && (!IsStatistic || (amount == 0 && bankPart == 0 && carriedPart == 0)) && (state == "queued" || IsStatistic || bankPart + carriedPart == amount) && (kind != "reward" || state == "queued" || carriedPart == 0)) { if (!(state == "queued")) { if (AfterBalance >= 0) { return AfterBalance <= 1000000000; } return false; } return true; } return false; } } public bool Authorize(CharacterAccount account) { if (state != "queued" || !Valid || !account.Valid || account.revision >= 9223372036854775805L) { return false; } if (IsDebit) { bankPart = Math.Min(account.balance, amount); carriedPart = amount - bankPart; } else if (kind == "reward") { bankPart = amount; carriedPart = 0; } if (IsCredit && (long)account.balance + (long)bankPart > 1000000000) { return false; } beforeBalance = account.balance; revision = account.revision; state = "waiting"; return Valid; } public bool Apply(CharacterAccount account) { if (!Valid || state != "waiting" || !account.Valid || account.balance != beforeBalance || account.revision != revision) { return false; } if ((kind == "death" && account.deaths == long.MaxValue) || (kind == "bosskill" && account.bossKills == long.MaxValue)) { return false; } account.balance = AfterBalance; account.revision++; if (kind == "death") { account.deaths++; } if (kind == "bosskill") { account.bossKills++; } return true; } public bool Matches(CommerceOperation other) { if (id == other.id && character == other.character && world == other.world && kind == other.kind && run == other.run && floor == other.floor && amount == other.amount && bankPart == other.bankPart && carriedPart == other.carriedPart && product == other.product && quantity == other.quantity && source == other.source && beforeBalance == other.beforeBalance) { return revision == other.revision; } return false; } } public sealed class DungeonInstance { public FloorAttempt Attempt { get; } public int Slot { get; } public Guid RunId => Attempt.RunId; public int MemberCount { get; internal set; } internal DungeonInstance(FloorAttempt attempt, int slot) { Attempt = attempt; Slot = slot; } } public sealed class DungeonDirectory { public const int HardInstanceLimit = 4; private readonly Dictionary<Guid, DungeonInstance> _instances = new Dictionary<Guid, DungeonInstance>(); private readonly Dictionary<string, Guid> _members = new Dictionary<string, Guid>(StringComparer.Ordinal); public IReadOnlyCollection<DungeonInstance> Instances => _instances.Values; public bool TryOpen(FloorRules rules, double now, int maxInstances, out DungeonInstance? instance, int? preferredSlot = null) { if (rules == null) { throw new ArgumentNullException("rules"); } if (maxInstances < 1 || maxInstances > 4) { throw new ArgumentOutOfRangeException("maxInstances"); } instance = null; if (_instances.Count >= maxInstances || _instances.Values.Any((DungeonInstance i) => i.Attempt.EntrancePortalOpen)) { return false; } int slot = preferredSlot.GetValueOrDefault(); if (slot < 0 || slot >= 4) { throw new ArgumentOutOfRangeException("preferredSlot"); } if (preferredSlot.HasValue && _instances.Values.Any((DungeonInstance i) => i.Slot == slot)) { return false; } for (; _instances.Values.Any((DungeonInstance i) => i.Slot == slot); slot++) { } instance = new DungeonInstance(new FloorAttempt(rules, now), slot); _instances.Add(instance.RunId, instance); return true; } public DungeonInstance? Find(Guid id) { if (!_instances.TryGetValue(id, out DungeonInstance value)) { return null; } return value; } public DungeonInstance? FindForPlayer(string player) { ValidatePlayer(player); if (!_members.TryGetValue(player, out var value)) { return null; } return Find(value); } public bool TryReserve(Guid run, string player, double now, double pressedAt) { ValidatePlayer(player); DungeonInstance dungeonInstance = Find(run); if (_members.ContainsKey(player) || dungeonInstance == null || !dungeonInstance.Attempt.ReserveEntry(player, now, pressedAt)) { return false; } _members.Add(player, run); dungeonInstance.MemberCount++; return true; } public bool ReleasePlayer(string player) { ValidatePlayer(player); DungeonInstance dungeonInstance = FindForPlayer(player); if (dungeonInstance == null) { return false; } dungeonInstance.Attempt.TryRemove(player); _members.Remove(player); dungeonInstance.MemberCount--; return true; } public bool TryRelease(Guid run) { DungeonInstance dungeonInstance = Find(run); if (dungeonInstance == null || dungeonInstance.MemberCount != 0) { return false; } if (dungeonInstance.Attempt.Phase != FloorPhase.Closed && !dungeonInstance.Attempt.TryClose(protectedBelongingsResolved: true)) { return false; } return _instances.Remove(run); } private static void ValidatePlayer(string player) { if (string.IsNullOrWhiteSpace(player)) { throw new ArgumentException("Player ID is required.", "player"); } } } public sealed class EncounterProgress { public int Total { get; } public int CompletedStages { get; private set; } public bool Stopped { get; private set; } public bool Complete => CompletedStages == Total; public EncounterProgress(int total) { if (total <= 0) { throw new ArgumentOutOfRangeException("total"); } Total = total; } public void CompleteStage() { if (!Stopped && !Complete) { CompletedStages++; } } public void Stop() { Stopped = true; } public string Describe(Func<int, string> title) { if (!Complete) { if (!Stopped) { return title(CompletedStages) + "\nSTAGES CLEARED " + CompletedStages + " / " + Total; } return "FLOOR ENDED"; } return "FLOOR COMPLETE"; } } public static class EnemyLootPolicy { public static bool Suppress(bool managedPrefab, bool namedTarget, string? run) { Guid result; if (managedPrefab && !namedTarget) { return Guid.TryParseExact(run, "N", out result); } return false; } } public enum FloorPhase { Admission, Arriving, Active, Shop, Failed, Closed } public sealed class FloorAttempt { private readonly Dictionary<string, bool> _participants = new Dictionary<string, bool>(StringComparer.Ordinal); private readonly HashSet<string> _claimed = new HashSet<string>(StringComparer.Ordinal); private readonly HashSet<string> _reservations = new HashSet<string>(StringComparer.Ordinal); private readonly HashSet<string> _pending = new HashSet<string>(StringComparer.Ordinal); private IReadOnlyDictionary<string, int>? _allocations; private readonly double _entryClosesAt; private readonly double _openedAt; private double _combatStartsAt; private double _lastObservedTime; public Guid RunId { get; } public FloorRules Rules { get; } public FloorPhase Phase { get; private set; } public bool EntrancePortalOpen => Phase == FloorPhase.Admission; public bool ShopExitOpen => Phase == FloorPhase.Shop; public string ObjectiveLabel { get { if (Phase != FloorPhase.Active) { return string.Empty; } if (Rules.Objective != FloorObjective.BossKill) { return "Survive"; } return "Kill the Undead King"; } } public double EntrySecondsRemaining { get { if (Phase != FloorPhase.Admission) { return 0.0; } return Math.Max(0.0, _entryClosesAt - _lastObservedTime); } } public double ArrivalSecondsRemaining { get { if (Phase != FloorPhase.Arriving) { return 0.0; } return Math.Max(0.0, _entryClosesAt + Rules.ArrivalGraceSeconds - _lastObservedTime); } } public double SurvivalSecondsRemaining { get { if (Rules.Objective == FloorObjective.Survival) { if (Phase != FloorPhase.Admission && Phase != FloorPhase.Arriving) { if (Phase != FloorPhase.Active) { return 0.0; } return Math.Max(0.0, Rules.SurvivalSeconds - (_lastObservedTime - _combatStartsAt)); } return Rules.SurvivalSeconds; } return 0.0; } } public int EnemyPressureStage { get { if (Phase != FloorPhase.Active) { return 0; } return Math.Min(4, 1 + (int)((_lastObservedTime - _combatStartsAt) / Rules.SurvivalSeconds * 4.0)); } } public int LivingInside => _participants.Count<KeyValuePair<string, bool>>((KeyValuePair<string, bool> p) => p.Value); public int PendingArrivals => _pending.Count; public FloorAttempt(FloorRules rules, double openedAt = 0.0) { Rules = rules ?? throw new ArgumentNullException("rules"); if (double.IsNaN(openedAt) || double.IsInfinity(openedAt) || openedAt < 0.0) { throw new ArgumentOutOfRangeException("openedAt"); } _lastObservedTime = openedAt; _openedAt = openedAt; _entryClosesAt = openedAt + rules.EntryWindowSeconds; _combatStartsAt = _entryClosesAt; RunId = Guid.NewGuid(); } public bool ReserveEntry(string playerId, double now) { return ReserveEntry(playerId, now, now); } public bool ReserveEntry(string playerId, double now, double pressedAt) { ValidateId(playerId); Advance(now); if (double.IsNaN(pressedAt) || double.IsInfinity(pressedAt) || pressedAt < _openedAt || pressedAt >= _entryClosesAt || pressedAt > now) { return false; } bool flag = Phase == FloorPhase.Arriving && now < _entryClosesAt + Rules.RequestGraceSeconds && now - pressedAt <= Rules.RequestGraceSeconds; if ((!EntrancePortalOpen && !flag) || _reservations.Count >= Rules.ParticipantLimit || !_reservations.Add(playerId)) { return false; } _pending.Add(playerId); return true; } public bool ConfirmArrival(string playerId, double now) { ValidateId(playerId); Advance(now); if ((Phase != FloorPhase.Admission && Phase != FloorPhase.Arriving) || !_pending.Remove(playerId)) { return false; } _participants.Add(playerId, value: true); if (Phase == FloorPhase.Arriving && _pending.Count == 0 && now >= _entryClosesAt + Rules.RequestGraceSeconds) { StartCombat(now); } return true; } public bool IsAlive(string playerId) { bool value; return _participants.TryGetValue(playerId, out value) && value; } public bool TryEnter(string playerId, double now) { if (ReserveEntry(playerId, now)) { return ConfirmArrival(playerId, now); } return false; } public bool TryRemove(string playerId) { ValidateId(playerId); if (Phase != FloorPhase.Admission && Phase != FloorPhase.Arriving && Phase != FloorPhase.Active) { return false; } if (!_pending.Remove(playerId) && (!_participants.TryGetValue(playerId, out var value) || !value)) { return false; } _participants[playerId] = false; if (Phase == FloorPhase.Arriving && _pending.Count == 0 && _lastObservedTime >= _entryClosesAt + Rules.RequestGraceSeconds) { StartCombat(_lastObservedTime); } if (Phase == FloorPhase.Active && LivingInside == 0) { Phase = FloorPhase.Failed; } return true; } public void Abort() { if (Phase != FloorPhase.Closed) { _pending.Clear(); string[] array = _participants.Keys.ToArray(); foreach (string key in array) { _participants[key] = false; } _allocations = null; Phase = FloorPhase.Failed; } } public void Advance(double now) { if (double.IsNaN(now) || double.IsInfinity(now) || now < _lastObservedTime) { throw new ArgumentOutOfRangeException("now", "Use nonnegative monotonic host time."); } _lastObservedTime = now; if (Phase == FloorPhase.Admission && now >= _entryClosesAt) { if (_pending.Count > 0 || now < _entryClosesAt + Rules.RequestGraceSeconds) { Phase = FloorPhase.Arriving; } else { StartCombat(_entryClosesAt + Rules.RequestGraceSeconds); } } if (Phase == FloorPhase.Arriving && _pending.Count == 0 && now >= _entryClosesAt + Rules.RequestGraceSeconds) { StartCombat(_entryClosesAt + Rules.RequestGraceSeconds); } if (Phase == FloorPhase.Arriving && now >= _entryClosesAt + Rules.ArrivalGraceSeconds) { _pending.Clear(); StartCombat(_entryClosesAt + Rules.ArrivalGraceSeconds); } if (Rules.Objective == FloorObjective.Survival && Phase == FloorPhase.Active && !(now - _combatStartsAt < Rules.SurvivalSeconds)) { Complete(); } } public bool CompleteBoss() { if (Rules.Objective != FloorObjective.BossKill || Phase != FloorPhase.Active || LivingInside == 0) { return false; } Complete(); return true; } private void Complete() { _allocations = CoinSplit.Divide(Rules.CoinPool, from p in _participants where p.Value select p.Key); Phase = FloorPhase.Shop; } private void StartCombat(double now) { _combatStartsAt = now; Phase = ((LivingInside > 0) ? FloorPhase.Active : FloorPhase.Failed); } public bool CanUseShop(string playerId) { ValidateId(playerId); if (Phase == FloorPhase.Shop && _allocations != null) { return _allocations.ContainsKey(playerId); } return false; } public IReadOnlyList<int> VisibleShopTabs(string playerId) { if (!CanUseShop(playerId)) { return Array.Empty<int>(); } return ShopAccess.TabsFor(Rules.Floor); } public bool TryClaimCoins(string playerId, out int coins) { coins = 0; if (!CanUseShop(playerId) || !_claimed.Add(playerId)) { return false; } coins = _allocations[playerId]; return true; } public bool TryClose(bool protectedBelongingsResolved) { if ((Phase != FloorPhase.Shop && Phase != FloorPhase.Failed) || !protectedBelongingsResolved) { return false; } Phase = FloorPhase.Closed; return true; } private static void ValidateId(string playerId) { if (string.IsNullOrWhiteSpace(playerId)) { throw new ArgumentException("Player ID is required.", "playerId"); } } } public static class FloorCatalog { public const int HighestImplemented = 20; public static string Name(int floor) { return floor switch { 0 => "Trial", 1 => "The Hollow Crown", 2 => "The Rootbound Hollow", 3 => "The Drowned Court", 4 => "The Sunken Vigil", 5 => "The Shattered Cirque", 6 => "The Emberfang Sanctum", 7 => "The Thresher's Run", 8 => "Crown of Cinders", 9 => "The Skybreak Crag", 10 => "The Amber Vault", 11 => "The Cinder Delta", 12 => "The Last Ember", 13 => "The White Maw", 14 => "The Silent Aurora", 15 => "The Runebound Conclave", 16 => "The Shattered Oath", 17 => "The Blight Orchard", 18 => "The Crimson Harvest", 19 => "The Forsaken Procession", 20 => "The Last Convergence", _ => throw new ArgumentOutOfRangeException("floor"), }; } public static int LootLevel(int floor) { switch (floor) { case 0: return 1; case 1: case 2: return 19; case 3: case 4: return 43; case 5: case 6: return 77; case 7: case 8: return 97; case 9: case 10: return 130; case 11: case 12: return 181; case 13: case 14: return 246; case 15: case 16: case 17: case 18: case 19: case 20: return 246; default: throw new ArgumentOutOfRangeException("floor"); } } public static string Biome(int floor) { switch (floor) { case 0: return "Meadows"; case 1: case 2: return "BlackForest"; case 3: case 4: return "Swamp"; case 5: case 6: return "Mountain"; case 7: case 8: return "Plains"; case 9: case 10: return "Mistlands"; case 11: case 12: return "AshLands"; case 13: case 14: case 15: case 16: case 17: case 18: case 19: case 20: return "DeepNorth"; default: throw new ArgumentOutOfRangeException("floor"); } } public static (int X, int Z) LayoutOffset(int floor) { switch (floor) { default: throw new ArgumentOutOfRangeException("floor"); case 0: case 1: case 2: case 3: case 4: case 5: case 6: return (X: 0, Z: floor * 512); case 7: case 8: case 9: case 10: case 11: case 12: case 13: case 14: case 15: case 16: case 17: case 18: case 19: case 20: { int num = floor - 7; return (X: (num < 7) ? (-2560) : 2560, Z: num % 7 * 512); } } } } public static class FloorProgression { public const int KeyPrice = 100; public const int KeyStackSize = 999; public static bool CanOpen(int floor, int highestCompleted, int highestAvailable) { if (floor < 0 || floor > 1000 || highestCompleted < -1 || highestCompleted > 1000 || highestAvailable < 0 || highestAvailable > 1000) { throw new ArgumentOutOfRangeException("floor"); } if (floor != 0) { if (floor <= highestAvailable) { return floor <= highestCompleted + 1; } return false; } return true; } public static int RecordCompletion(int highestCompleted, int completedFloor) { if (highestCompleted < -1 || highestCompleted > 1000 || completedFloor < 0 || completedFloor > 1000) { throw new ArgumentOutOfRangeException("completedFloor"); } return Math.Max(highestCompleted, completedFloor); } } public readonly struct RouteRoom { public double X { get; } public double Z { get; } public double Height { get; } public double Radius { get; } public RouteRoom(double x, double z, double height, double radius = 11.0) { X = x; Z = z; Height = height; Radius = radius; } } public sealed class FloorRoute { public const double PassageHalfWidth = 8.0; private static readonly FloorRoute[] Routes = Build(); public IReadOnlyList<RouteRoom> Rooms { get; } public IReadOnlyList<(int A, int B)> Links { get; } public IReadOnlyList<int> Targets { get; } public string Shape { get; } private FloorRoute(string shape, RouteRoom[] rooms, (int, int)[] links, params int[] targets) { Shape = shape; Rooms = Array.AsReadOnly(rooms); Links = Array.AsReadOnly(links); Targets = Array.AsReadOnly(targets); } public static FloorRoute For(int floor) { if (floor < 7 || floor > 20) { throw new ArgumentOutOfRangeException("floor"); } return Routes[floor - 7]; } public RouteRoom Target(int index) { return Rooms[Targets[index % Targets.Count]]; } public static bool IsStaged(int floor) { if (floor != 8) { return floor == 19; } return true; } public double Clearance(double x, double z) { double num = double.MaxValue; foreach (RouteRoom room in Rooms) { num = Math.Min(num, Math.Sqrt(Squared(x - room.X, z - room.Z)) - room.Radius); } foreach (var link in Links) { RouteRoom routeRoom = Rooms[link.A]; RouteRoom routeRoom2 = Rooms[link.B]; double num2 = routeRoom2.X - routeRoom.X; double num3 = routeRoom2.Z - routeRoom.Z; double num4 = Math.Max(0.0, Math.Min(1.0, ((x - routeRoom.X) * num2 + (z - routeRoom.Z) * num3) / Squared(num2, num3))); num = Math.Min(num, Math.Sqrt(Squared(x - routeRoom.X - num2 * num4, z - routeRoom.Z - num3 * num4)) - 8.0); } return num; } public double Elevation(double x, double z) { double num = 0.0; double num2 = 0.0; foreach (RouteRoom room in Rooms) { double num3 = Math.Exp((0.0 - Squared(x - room.X, z - room.Z)) / 900.0); num += num3; num2 += room.Height * num3; } return num2 / Math.Max(num, 1E-30); } private static double Squared(double x, double z) { return x * x + z * z; } private static RouteRoom R(double x, double z, double h, double radius = 11.0) { return new RouteRoom(x, z, h, radius); } private static FloorRoute[] Build() { return new FloorRoute[14] { new FloorRoute("Windbreak tree", new RouteRoom[8] { R(-25.0, -80.0, 0.0), R(-12.0, -48.0, 2.0), R(-29.0, -10.0, 7.0, 14.0), R(18.0, -34.0, 3.0), R(28.0, 3.0, 9.0, 14.0), R(-10.0, 25.0, 4.0), R(-25.0, 63.0, 10.0, 14.0), R(21.0, 66.0, 5.0) }, new(int, int)[7] { (0, 1), (1, 2), (1, 3), (3, 4), (2, 5), (5, 6), (5, 7) }, 2, 4, 6), new FloorRoute("Cinder ring", new RouteRoom[8] { R(-26.0, -78.0, 5.0), R(-28.0, -35.0, 6.0), R(-29.0, 20.0, 8.0), R(0.0, 55.0, 9.0), R(29.0, 20.0, 8.0), R(28.0, -35.0, 6.0), R(0.0, -25.0, 2.0, 15.0), R(0.0, 6.0, 1.0, 19.0) }, new(int, int)[10] { (0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 0), (1, 6), (5, 6), (6, 7), (7, 3) }, 6, 7, 7), new FloorRoute("Forked crag", new RouteRoom[7] { R(23.0, -80.0, 0.0), R(5.0, -52.0, 3.0), R(-28.0, -32.0, 7.0, 14.0), R(28.0, -13.0, 6.0), R(-6.0, 12.0, 11.0), R(-28.0, 48.0, 15.0, 14.0), R(24.0, 62.0, 17.0, 17.0) }, new(int, int)[8] { (0, 1), (1, 2), (1, 3), (2, 4), (3, 4), (4, 5), (5, 6), (3, 6) }, 2, 5, 6), new FloorRoute("Amber honeycomb", new RouteRoom[8] { R(-27.0, -78.0, 1.0), R(-27.0, -37.0, 3.0), R(20.0, -50.0, 5.0), R(-28.0, 8.0, 8.0, 15.0), R(20.0, -5.0, 2.0), R(-18.0, 56.0, 5.0, 15.0), R(27.0, 58.0, 13.0, 16.0), R(28.0, 29.0, 9.0) }, new(int, int)[10] { (0, 1), (0, 2), (1, 3), (1, 4), (2, 4), (3, 5), (4, 5), (4, 7), (7, 6), (5, 6) }, 3, 5, 6), new FloorRoute("Braided ash delta", new RouteRoom[8] { R(0.0, -81.0, 0.0), R(-27.0, -54.0, 2.0), R(26.0, -36.0, 7.0, 14.0), R(-27.0, -9.0, 9.0, 14.0), R(0.0, 15.0, 2.0), R(-27.0, 58.0, 5.0), R(27.0, 59.0, 13.0, 16.0), R(28.0, 14.0, 8.0) }, new(int, int)[10] { (0, 1), (0, 2), (1, 3), (2, 4), (3, 4), (3, 5), (4, 6), (2, 7), (7, 6), (5, 6) }, 2, 3, 6), new FloorRoute("Ember horseshoe", new RouteRoom[8] { R(0.0, -82.0, 0.0), R(-28.0, -49.0, 3.0), R(-28.0, 0.0, 6.0, 14.0), R(-23.0, 58.0, 13.0), R(23.0, 58.0, 16.0, 16.0), R(29.0, 7.0, 7.0, 14.0), R(28.0, -48.0, 4.0), R(0.0, -6.0, 2.0) }, new(int, int)[9] { (0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6), (6, 0), (2, 7), (7, 5) }, 2, 5, 4), new FloorRoute("Alpine branching tree", new RouteRoom[8] { R(26.0, -79.0, 0.0), R(4.0, -52.0, 3.0), R(-28.0, -34.0, 8.0, 14.0), R(27.0, -2.0, 10.0, 14.0), R(-7.0, 17.0, 7.0), R(-28.0, 61.0, 15.0, 16.0), R(26.0, 62.0, 12.0), R(-28.0, 4.0, 5.0) }, new(int, int)[7] { (0, 1), (1, 2), (1, 3), (2, 7), (3, 4), (4, 5), (4, 6) }, 2, 3, 5), new FloorRoute("Aurora crescent", new RouteRoom[8] { R(-27.0, -80.0, 0.0), R(3.0, -58.0, 3.0), R(29.0, -20.0, 9.0, 14.0), R(28.0, 28.0, 12.0), R(3.0, 65.0, 17.0, 16.0), R(-29.0, 30.0, 10.0, 14.0), R(-25.0, -12.0, 4.0), R(0.0, 4.0, 2.0) }, new(int, int)[9] { (0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6), (6, 0), (6, 7), (7, 2) }, 2, 5, 4), new FloorRoute("Runic clover", new RouteRoom[7] { R(0.0, -81.0, 0.0), R(0.0, -39.0, 2.0), R(-28.0, -14.0, 9.0, 15.0), R(27.0, -7.0, 12.0, 15.0), R(0.0, 19.0, 4.0), R(-25.0, 61.0, 8.0), R(26.0, 62.0, 15.0, 16.0) }, new(int, int)[8] { (0, 1), (1, 2), (1, 3), (2, 4), (3, 4), (4, 5), (5, 6), (6, 4) }, 2, 3, 6), new FloorRoute("Oathbound quarry", new RouteRoom[7] { R(-27.0, -79.0, 1.0), R(-27.0, -32.0, 4.0), R(24.0, -28.0, 12.0, 16.0), R(-6.0, 7.0, 3.0), R(-27.0, 53.0, 8.0), R(25.0, 60.0, 17.0, 17.0), R(29.0, 11.0, 11.0) }, new(int, int)[7] { (0, 1), (1, 2), (1, 3), (3, 4), (4, 5), (3, 6), (6, 5) }, 2, 5), new FloorRoute("Root garden maze", new RouteRoom[8] { R(26.0, -80.0, 1.0), R(25.0, -38.0, 3.0), R(-25.0, -52.0, 8.0, 14.0), R(-26.0, -5.0, 4.0), R(25.0, 5.0, 10.0, 14.0), R(-23.0, 51.0, 7.0), R(26.0, 64.0, 14.0, 17.0), R(0.0, 33.0, 2.0) }, new(int, int)[9] { (0, 1), (0, 2), (2, 3), (3, 4), (1, 4), (3, 5), (5, 7), (7, 4), (7, 6) }, 2, 4, 6), new FloorRoute("Split crimson diamond", new RouteRoom[8] { R(0.0, -81.0, 1.0), R(-28.0, -45.0, 3.0), R(27.0, -37.0, 10.0, 14.0), R(-28.0, 5.0, 5.0, 14.0), R(27.0, 22.0, 15.0), R(0.0, 55.0, 7.0), R(-25.0, 72.0, 14.0, 16.0), R(0.0, -6.0, 2.0) }, new(int, int)[9] { (0, 1), (0, 2), (1, 3), (2, 4), (3, 5), (4, 5), (5, 6), (1, 7), (7, 4) }, 2, 3, 6), new FloorRoute("Procession spiral", new RouteRoom[8] { R(-27.0, -80.0, 0.0), R(-28.0, -34.0, 4.0), R(-28.0, 25.0, 7.0), R(0.0, 65.0, 11.0), R(29.0, 29.0, 9.0), R(28.0, -30.0, 5.0), R(0.0, -25.0, 2.0), R(0.0, 12.0, 1.0, 20.0) }, new(int, int)[8] { (0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6), (6, 7), (7, 2) }, 7, 7, 7), new FloorRoute("Convergence labyrinth", new RouteRoom[9] { R(0.0, -81.0, 1.0), R(-28.0, -50.0, 3.0), R(27.0, -46.0, 7.0), R(-28.0, 0.0, 11.0, 16.0), R(27.0, -1.0, 16.0, 16.0), R(0.0, 22.0, 7.0), R(-27.0, 62.0, 5.0), R(27.0, 67.0, 18.0, 17.0), R(0.0, -20.0, 2.0) }, new(int, int)[11] { (0, 1), (0, 2), (1, 3), (2, 4), (3, 5), (4, 5), (5, 6), (6, 7), (7, 4), (1, 8), (8, 4) }, 3, 4, 7) }; } } public enum FloorObjective { Survival, BossKill } public sealed class FloorRules { public int Floor { get; } public double SurvivalSeconds { get; } public int CoinPool { get; } public int ParticipantLimit { get; } public double EntryWindowSeconds { get; } public double ArrivalGraceSeconds { get; } public double RequestGraceSeconds { get; } public FloorObjective Objective { get; } public FloorRules(int floor = 0, double survivalSeconds = 100.0, int coinPool = 200, int participantLimit = 8, double entryWindowSeconds = 10.0, double arrivalGraceSeconds = 45.0, double requestGraceSeconds = 0.0, FloorObjective objective = FloorObjective.Survival) { if (floor < 0 || floor > 1000) { throw new ArgumentOutOfRangeException("floor"); } if (double.IsNaN(survivalSeconds) || double.IsInfinity(survivalSeconds) || survivalSeconds <= 0.0 || survivalSeconds > 3600.0) { throw new ArgumentOutOfRangeException("survivalSeconds"); } if (coinPool < 0 || coinPool > 1000000) { throw new ArgumentOutOfRangeException("coinPool"); } if (participantLimit < 1 || participantLimit > 16) { throw new ArgumentOutOfRangeException("participantLimit"); } if (double.IsNaN(entryWindowSeconds) || double.IsInfinity(entryWindowSeconds) || entryWindowSeconds <= 0.0 || entryWindowSeconds > 120.0) { throw new ArgumentOutOfRangeException("entryWindowSeconds"); } if (double.IsNaN(arrivalGraceSeconds) || double.IsInfinity(arrivalGraceSeconds) || arrivalGraceSeconds < 1.0 || arrivalGraceSeconds > 120.0) { throw new ArgumentOutOfRangeException("arrivalGraceSeconds"); } if (double.IsNaN(requestGraceSeconds) || double.IsInfinity(requestGraceSeconds) || requestGraceSeconds < 0.0 || requestGraceSeconds > 5.0 || requestGraceSeconds >= arrivalGraceSeconds) { throw new ArgumentOutOfRangeException("requestGraceSeconds"); } if (objective != FloorObjective.Survival && objective != FloorObjective.BossKill) { throw new ArgumentOutOfRangeException("objective"); } Floor = floor; SurvivalSeconds = survivalSeconds; CoinPool = coinPool; ParticipantLimit = participantLimit; EntryWindowSeconds = entryWindowSeconds; ArrivalGraceSeconds = arrivalGraceSeconds; RequestGraceSeconds = requestGraceSeconds; Objective = objective; } } public readonly struct CreaturePower { public float Health { get; } public float Damage { get; } public float NamedHealth { get; } public CreaturePower(float health, float damage, float? namedHealth = null) { Health = health; Damage = damage; NamedHealth = namedHealth ?? health; } public CreaturePower ForNamedTarget() { return new CreaturePower(NamedHealth, Damage, NamedHealth); } } public static class FloorScaling { public static float NamedFactor(float growthFactor, float bonusEffect = 2f, float floorOverride = 1f) { if (float.IsNaN(growthFactor) || float.IsInfinity(growthFactor) || growthFactor < 1f || growthFactor > 100f || float.IsNaN(bonusEffect) || float.IsInfinity(bonusEffect) || bonusEffect < 1f || bonusEffect > 5f || float.IsNaN(floorOverride) || float.IsInfinity(floorOverride) || floorOverride < 0.1f || floorOverride > 10f) { throw new ArgumentOutOfRangeException("growthFactor"); } return Math.Min(100f, (1f + bonusEffect * (growthFactor - 1f)) * floorOverride); } public static float Factor(int floor, int start, float growth, float floorOverride = 1f) { if (floor < 0 || start < 0 || float.IsNaN(growth) || float.IsInfinity(growth) || growth < 0f || growth > 1f || float.IsNaN(floorOverride) || float.IsInfinity(floorOverride) || floorOverride < 0.1f || floorOverride > 10f) { throw new ArgumentOutOfRangeException("floor"); } double val = Math.Pow(1.0 + (double)growth, Math.Max(0L, (long)floor - (long)start + 1)) * (double)floorOverride; return (float)Math.Max(0.01, Math.Min(100.0, val)); } } public static class FloorTerrain { public const int Cell = 3; public const int HalfWidth = 48; public const int HalfLength = 102; public static double Height(int floor, double x, double z) { if (floor < 1 || floor > 20) { throw new ArgumentOutOfRangeException("floor"); } x = Math.Max(-48.0, Math.Min(47.999999, x)); z = Math.Max(-102.0, Math.Min(101.999999, z)); double num = Math.Floor((x + 48.0) / 3.0) * 3.0 - 48.0; double num2 = Math.Floor((z + 102.0) / 3.0) * 3.0 - 102.0; double num3 = (x - num) / 3.0; double num4 = (z - num2) / 3.0; double num5 = Vertex(floor, num, num2); double num6 = Vertex(floor, num, num2 + 3.0); double num7 = Vertex(floor, num + 3.0, num2); double num8 = Vertex(floor, num + 3.0, num2 + 3.0); if (!(num3 + num4 <= 1.0)) { return num8 + (1.0 - num3) * (num6 - num8) + (1.0 - num4) * (num7 - num8); } return num5 + num3 * (num7 - num5) + num4 * (num6 - num5); } public static double Vertex(int floor, double x, double z) { if (floor >= 7 && floor <= 20) { return FloorRoute.For(floor).Elevation(x, z); } switch (floor) { case 1: return ramp(-62.0, -30.0, 3.0) + ramp(14.0, 52.0, 5.0) + hill(-24.0, -18.0, 22.0, 2.5) - hill(18.0, 0.0, 24.0, 1.2); case 2: return hill(-18.0, -24.0, 27.0, 2.4) + hill(22.0, 39.0, 24.0, 3.2); case 3: case 4: return 0.0; case 5: return hill(0.0, 2.0, 26.0, 8.0) + hill(-20.0, 25.0, 24.0, 3.0); case 6: return ramp(-60.0, -26.0, 3.0) + ramp(10.0, 50.0, 4.0); default: throw new ArgumentOutOfRangeException("floor"); } double hill(double cx, double cz, double width, double height) { return height * Math.Exp((0.0 - ((x - cx) * (x - cx) + (z - cz) * (z - cz))) / (width * width)); } double ramp(double start, double end, double height) { return height * Smooth((z - start) / (end - start)); } } private static double Smooth(double t) { t = Math.Max(0.0, Math.Min(1.0, t)); return t * t * (3.0 - 2.0 * t); } } public sealed class HuntProgress { private readonly bool[] _spawned; private readonly bool[] _defeated; public int Total => _spawned.Length; public int Defeated { get; private set; } public bool Complete => Defeated == Total; public bool Stopped { get; private set; } public HuntProgress(int targets) { if (targets < 1 || targets > 10) { throw new ArgumentOutOfRangeException("targets"); } _spawned = new bool[targets]; _defeated = new bool[targets]; } public bool IsSpawned(int index) { return _spawned[index]; } public bool IsDefeated(int index) { return _defeated[index]; } public string Describe(Func<int, string> name) { if (Complete) { return "FLOOR COMPLETE"; } string text = ""; for (int i = 0; i < Total; i++) { if (!_defeated[i]) { text = text + ((text.Length == 0) ? "" : " · ") + name(i); } } return "HUNT THE CHAMPIONS\n" + Defeated + " / " + Total + "\n<size=24>" + text + "</size>"; } public void Spawn(int index) { if (!Stopped) { _spawned[index] = true; } } public void Defeat(int index) { if (!Stopped && _spawned[index] && !_defeated[index]) { _defeated[index] = true; Defeated++; } } public void Stop() { Stopped = true; } } public sealed class InputBlockLease : IDisposable { private readonly Action<bool> _change; public bool Held { get; private set; } public InputBlockLease(Action<bool> change) { _change = change ?? throw new ArgumentNullException("change"); } public void Acquire() { if (!Held) { Held = true; _change(obj: true); } } public void Dispose() { if (Held) { Held = false; _change(obj: false); } } } public static class ItemOrigin { public const string Key = "brom8.beyond.origin.v1"; public static string Create(string kind, string identity, string prefab) { string text = "1|" + kind + "|" + identity + "|" + prefab; if (!Valid(text, prefab)) { throw new ArgumentException("Invalid Beyond item origin."); } return text; } public static bool Valid(string? value, string? actualPrefab) { if (string.IsNullOrEmpty(value) || value.Length > 200 || string.IsNullOrEmpty(actualPrefab) || actualPrefab.Length > 128) { return false; } string[] array = value.Split('|'); if (array.Length == 4 && array[0] == "1" && (array[1] == "shop" || array[1] == "bank" || array[1] == "loot") && Guid.TryParseExact(array[2], "N", out var _)) { return array[3] == actualPrefab; } return false; } } public static class LandscapePreviewLayout { public const int Revision = 2; public const float HalfSize = 64f; public const int MinZ = -64; public const int MaxZ = 704; public const int SectionCount = 6; public const float FoundationX = -23f; public const float FoundationZ = 19f; public const float FoundationHeight = 5f; public const float WaterHeight = -1.1f; public static bool Contains(float x, float y, float z) { if (Math.Abs(x) <= 70f && z >= -70f && z <= 710f && y >= -25f) { return y <= 130f; } return false; } public static bool InsideTravelBounds(float x, float y, float z) { if (Math.Abs(x) <= 62f && z >= -62f && z <= 702f && y >= -15f) { return y <= 120f; } return false; } public static int Section(float z) { return Math.Max(0, Math.Min(5, (int)Math.Floor((z + 64f) / 128f))); } public static float Transition(float z) { if (Section(z) != 0) { return Smooth((z - (float)(Section(z) * 128 - 64)) / 24f); } return 1f; } public static int SurfaceSection(float x, float z) { int num = Section(z); if (num == 0) { return 0; } if (!((Noise(x * 0.31f, z * 0.31f, 947) + 1f) * 0.5f < Transition(z))) { return num - 1; } return num; } public static string SectionName(int section) { return section switch { 1 => "The Gloaming Fen", 2 => "The Ochre Expanse", 3 => "The Stonevein Vault", 4 => "The Frostbound Pass", 5 => "The Emberwood", _ => "The Rootlit Forest", }; } public static int EnvironmentFloor(float z) { return Section(z) switch { 1 => 3, 2 => 1, 3 => 6, 4 => 13, 5 => 12, _ => 2, }; } public static bool SupportMatches(bool preview, int mode, string expected, string actual) { if (mode == (preview ? 1 : 0) && !string.IsNullOrEmpty(expected) && expected.Length <= 128) { return string.Equals(expected, actual, StringComparison.Ordinal); } return false; } public static float PathX(float z) { return 11f + (float)Math.Sin((double)(z + 14f) * 0.055) * 13f; } public static float PathDistance(float x, float z) { return Math.Abs(x - PathX(z)); } public static float FoundationDistance(float x, float z, float halfX = 16f, float halfZ = 16f) { return Math.Max(Math.Abs(x - -23f) - halfX, Math.Abs(z - 19f) - halfZ); } public static float Height(float x, float z, float halfX = 16f, float halfZ = 16f) { if (z <= 64f) { return ForestHeight(x, z, halfX, halfZ); } int num = Section(z); float num2 = num * 128 - 64; float num3 = SectionHeight(num, x, z); float num4 = Smooth((z - num2) / 24f); if (num4 < 1f) { num3 = Lerp((num == 1) ? ForestHeight(x, z, halfX, halfZ) : SectionHeight(num - 1, x, z), num3, num4); } if (((uint)(num - 1) <= 1u || num == 4) ? true : false) { float t = 1f - Smooth((LandmarkDistance(num, x, z) + 0.5f) / 4f); num3 = Lerp(num3, LandmarkHeight(num), t); } return num3; } public static float LandmarkX(int section) { return (section == 4) ? (-32) : (-34); } public static float LandmarkZ(int section) { return section * 128; } public static float LandmarkHeight(int section) { return RouteHeight(LandmarkZ(section)) + 0.4f; } public static float LandmarkDistance(int section, float x, float z) { return Math.Max(Math.Abs(x - LandmarkX(section)) - 16.5f, Math.Abs(z - LandmarkZ(section)) - 16.5f); } public static float RouteHeight(float z) { if (z <= 64f) { return ForestHeight(PathX(z), z, 16f, 16f); } float num = 64f; float num2 = ForestHeight(PathX(64f), 64f, 16f, 16f); for (int i = 1; i <= 6; i++) { float num3 = ((i == 6) ? 704 : (i * 128)); float num4 = i switch { 1 => 3.6f, 2 => 10f, 3 => 14f, 4 => 44f, _ => 22f, }; if (z <= num3) { return Lerp(num2, num4, (z - num) / (num3 - num)); } num = num3; num2 = num4; } return num2; } public static float RouteDistance(float x, float z) { float num = PathDistance(x, z); if (z <= 64f) { return num; } int num2 = Section(z); float num3 = num2 * 128; float num4 = x - (PathX(num3) + (float)((num2 % 2 == 0) ? (-10) : 10)); float num5 = z - num3; float val = Math.Abs((float)Math.Sqrt(num4 * num4 / 784f + num5 * num5 / 1444f) - (1f + Noise(x * 0.035f, z * 0.035f, 871) * 0.13f)) * 28f; float num6 = Math.Min(num, val); if (((uint)(num2 - 1) <= 1u || num2 == 4) ? true : false) { float num7 = LandmarkX(num2); float num8 = PathX(num3); float num9 = Math.Max(0f, Math.Min(1f, (x - num8) / (num7 - num8))); float num10 = num8 + (num7 - num8) * num9; num6 = Math.Min(num6, (float)Math.Sqrt((x - num10) * (x - num10) + (z - num3) * (z - num3))); } return num6; } private static float SectionHeight(int section, float x, float z) { float num = RouteHeight(z); float value = x - PathX(z); float num2 = Noise(x * 0.23f, z * 0.23f, 391) * 0.35f + Noise(x * 0.61f, z * 0.61f, 121) * 0.1f; float num3 = Noise(x * 0.055f, z * 0.055f, 713); float num4 = Noise(x * 0.018f, z * 0.018f, 671); float a = section switch { 1 => 0.6f + num3 * 1.1f + num4 * 0.7f + num2, 2 => num + 2f + (float)Math.Sin(x * 0.13f + z * 0.035f) * 3f + num3 * 2f + num2, 3 => num + 3f + Math.Abs(value) * 0.13f + num3 * 3f + num2, 4 => num + 7f + Math.Abs(value) * 0.4f + num4 * 8f + num3 * 4f + num2, _ => num + 3f + num3 * 3f + num4 * 3f + num2, }; float t = 1f - Smooth((RouteDistance(x, z) - 2.5f) / 4.5f); a = Lerp(a, num + num2 * 0.12f, t); if (section == 3) { a += Smooth((Math.Abs(value) - 13f) / 15f) * 10f; } return a; } private static float Lerp(float a, float b, float t) { return a + (b - a) * t; } private static float ForestHeight(float x, float z, float halfX, float halfZ) { float num = Noise(x * 0.018f, z * 0.018f, 671) * 11f; float num2 = Noise(x * 0.062f, z * 0.062f, 713) * 2.5f; float num3 = Noise(x * 0.25f, z * 0.25f, 391) * 0.43f + Noise(x * 0.61f, z * 0.61f, 121) * 0.12f; float num4 = 8f * (float)Math.Exp(0f - ((x + 45f) * (x + 45f) / 300f + (z + 25f) * (z + 25f) / 950f)); float num5 = 4f + num + num2 + num3 + num4; float num6 = Smooth((x - 31f) / 26f) * Smooth((25f - z) / 25f); num5 = num5 * (1f - num6) + (-3.4f + num3) * num6; float num7 = 1f - Smooth((PathDistance(x, z) - 1.4f) / 3.5f); float num8 = 3.2f + 0.028f * z + (float)Math.Sin(z * 0.045f) * 1.1f; num5 += (num8 - num5) * num7 * 0.94f; float num9 = 1f - Smooth((FoundationDistance(x, z, halfX, halfZ) + 0.5f) / 4.5f); return num5 + (5f - num5) * num9; } public static float CollisionHeight(float x, float z, float halfX = 16f, float halfZ = 16f) { float num = (float)Math.Floor(x); float num2 = (float)Math.Floor(z); float num3 = x - num; float num4 = z - num2; float num5 = Height(num, num2, halfX, halfZ); float num6 = Height(num + 1f, num2, halfX, halfZ); float num7 = Height(num, num2 + 1f, halfX, halfZ); float num8 = Height(num + 1f, num2 + 1f, halfX, halfZ); if (!(num3 + num4 <= 1f)) { return num8 + (num7 - num8) * (1f - num3) + (num6 - num8) * (1f - num4); } return num5 + (num6 - num5) * num3 + (num7 - num5) * num4; } public static float Noise(float x, float z, int seed) { int num = (int)Math.Floor(x); int num2 = (int)Math.Floor(z); float num3 = Smooth(x - (float)num); float num4 = Smooth(z - (float)num2); float num5 = Hash(num, num2, seed); float num6 = Hash(num + 1, num2, seed); float num7 = Hash(num, num2 + 1, seed); float num8 = Hash(num + 1, num2 + 1, seed); return (num5 + (num6 - num5) * num3) * (1f - num4) + (num7 + (num8 - num7) * num3) * num4; } private static float Hash(int x, int z, int seed) { int num = x * 374761393 + z * 668265263 + seed * 1442695041; int num2 = (num ^ (num >>> 13)) * 1274126177; return (float)(uint)(num2 ^ (num2 >>> 16)) / 4.2949673E+09f * 2f - 1f; } public static float Smooth(float t) { t = Math.Max(0f, Math.Min(1f, t)); return t * t * (3f - 2f * t); } } public static class MenuMovementPolicy { public static bool Allow(bool menuOwnsInput, bool soleInputRequest, bool otherUi, bool playerReady) { return menuOwnsInput && soleInputRequest && !otherUi && playerReady; } } public readonly struct PreparationIdentity { public string Token { get; } public string Run { get; } public int Floor { get; } public int Slot { get; } public PreparationIdentity(string token, string run, int floor, int slot) { if (!Guid.TryParseExact(token, "N", out var result) || (run != "" && !Guid.TryParseExact(run, "N", out result)) || floor < 0 || floor > 20 || slot < 0 || slot >= 4) { throw new ArgumentException("Invalid layout preparation identity."); } Token = token; Run = run; Floor = floor; Slot = slot; } public bool Matches(string token, string run, int floor, int slot) { if (string.Equals(Token, token, StringComparison.Ordinal) && string.Equals(Run, run, StringComparison.Ordinal) && Floor == floor) { return Slot == slot; } return false; } } public enum PreparationPhase { Queued, Building, Ready, Failed, Cancelled } public sealed class PreparationWork : IDisposable { private IEnumerator<Action>? _steps; public PreparationPhase Phase { get; private set; } public string Error { get; private set; } = ""; public bool Terminal { get { if (Phase != PreparationPhase.Ready && Phase != PreparationPhase.Failed) { return Phase == PreparationPhase.Cancelled; } return true; } } public PreparationWork(IEnumerator<Action> steps) { _steps = steps ?? throw new ArgumentNullException("steps"); } public void Step() { if (Terminal) { return; } Phase = PreparationPhase.Building; try { if (_steps.MoveNext()) { _steps.Current(); return; } Phase = PreparationPhase.Ready; DisposeSteps(); } catch (Exception ex) { Error = ex.Message; Phase = PreparationPhase.Failed; try { DisposeSteps(); } catch (Exception ex2) { Error = Error + "; preparation disposal: " + ex2.Message; } } } private void DisposeSteps() { IEnumerator<Action>? steps = _steps; _steps = null; steps?.Dispose(); } public void Dispose() { if (!Terminal) { Phase = PreparationPhase.Cancelled; } try { DisposeSteps(); } catch (Exception ex) { Error = Error + "; preparation disposal: " + ex.Message; } } } public sealed class RealmSpawnSlot { public int slot; public int generation; public string phase = "empty"; public string run = ""; public long user; public long authority; public uint id; public double due; public bool deathProcessed; public string diagnostic = ""; public bool Eligible(double clock) { if (!(phase == "empty")) { if (phase == "cooling") { return clock >= due; } return false; } return true; } public void Begin(double clock) { if (!Eligible(clock) || generation == int.MaxValue) { throw new InvalidOperationException("Realm slot is not eligible."); } if (double.IsNaN(clock) || double.IsInfinity(clock) || clock < 0.0) { throw new ArgumentOutOfRangeException("clock"); } generation++; phase = "intent"; run = Guid.NewGuid().ToString("N"); user = 0L; authority = 0L; id = 0u; deathProcessed = false; diagnostic = ""; } public void Attach(long owner, uint nativeId) { if (phase != "intent" || nativeId == 0) { throw new InvalidOperationException("Invalid realm spawn attachment."); } user = owner; id = nativeId; phase = "alive"; } public void DeathProcessed() { if (!(phase != "alive") || !(phase != "dying")) { phase = "dying"; deathProcessed = true; } } public void Removed(double clock, int delay) { if (phase != "dying" || !deathProcessed) { Quarantine("Native record disappeared without completed death evidence."); return; } if (delay < 1 || double.IsNaN(clock) || double.IsInfinity(clock) || clock < 0.0) { throw new ArgumentOutOfRangeException("clock"); } phase = "cooling"; due = clock + (double)delay; } public void Quarantine(string reason) { phase = "quarantined"; diagnostic = reason; } public bool Valid() { if (slot >= 0 && slot < 8 && generation >= 0 && diagnostic != null && diagnostic.Length <= 500) { bool num; if (generation != 0) { num = Guid.TryParseExact(run, "N", out var _); } else { if (!(run == "")) { goto IL_01e7; } if (phase == "empty") { goto IL_009f; } num = phase == "quarantined"; } if (num) { goto IL_009f; } } goto IL_01e7; IL_009f: if ((phase == "empty" || phase == "intent" || phase == "alive" || phase == "dying" || phase == "cooling" || phase == "quarantined") && !double.IsNaN(due) && !double.IsInfinity(due) && due >= 0.0 && ((phase != "alive" && phase != "dying" && phase != "cooling") || id != 0) && (phase != "empty" || (generation == 0 && id == 0 && user == 0L && !deathProcessed)) && (phase != "intent" || id == 0)) { if (!(phase != "cooling")) { return deathProcessed; } return true; } goto IL_01e7; IL_01e7: return false; } } public readonly struct RealmPoint { public readonly float X; public readonly float Y; public readonly float Z; public RealmPoint(float x, float y, float z) { X = x; Y = y; Z = z; } } public sealed class RealmDistrict { public int Id { get; } public string Name { get; } public RealmPoint Center { get; } public RealmDistrict(int id, string name, float x, float y, float z) { Id = id; Name = name; Center = new RealmPoint(x, y, z); } } public static class SharedRealmLayout { public const int Revision = 1; public const float Radius = 500f; public static readonly IReadOnlyList<RealmDistrict> Districts = Array.AsReadOnly(new RealmDistrict[9] { new RealmDistrict(0, "Lantern Shelf", -215f, 35f, -325f), new RealmDistrict(1, "Whispercut Valley", -295f, 40f, -35f), new RealmDistrict(2, "Mirrorfen", 65f, -24f, -80f), new RealmDistrict(3, "The Hanging Wood", 245f, 80f, 120f), new RealmDistrict(4, "Sunderfall Gorge", 295f, 25f, -155f), new RealmDistrict(5, "The Undervein", -65f, -60f, 65f), new RealmDistrict(6, "Glasswind Saddle", -145f, 105f, 280f), new RealmDistrict(7, "The Broken Crown", 65f, 180f, 265f), new RealmDistrict(8, "Cinder Garden", 115f, 25f, -295f) }); public static readonly RealmPoint[][] Paths = new RealmPoint[10][] { new RealmPoint[3] { P(0), new RealmPoint(-305f, 35f, -230f), P(1) }, new RealmPoint[4] { P(1), new RealmPoint(-330f, 65f, 130f), new RealmPoint(-245f, 80f, 205f), P(6) }, new RealmPoint[7] { P(6), new RealmPoint(-65f, 115f, 355f), new RealmPoint(25f, 125f, 325f), new RealmPoint(-50f, 140f, 235f), new RealmPoint(15f, 150f, 200f), new RealmPoint(120f, 165f, 230f), P(7) }, new RealmPoint[4] { P(7), new RealmPoint(195f, 150f, 325f), new RealmPoint(290f, 125f, 265f), P(3) }, new RealmPoint[3] { P(3), new RealmPoint(355f, 55f, 10f), P(4) }, new RealmPoint[3] { P(4), new RealmPoint(310f, 25f, -280f), P(8) }, new RealmPoint[3] { P(8), new RealmPoint(-50f, 28f, -355f), P(0) }, new RealmPoint[6] { P(1), new RealmPoint(-175f, 10f, -140f), new RealmPoint(-90f, -23f, -195f), new RealmPoint(65f, -24f, -195f), new RealmPoint(185f, -22f, -185f), P(4) }, new RealmPoint[3] { new RealmPoint(65f, -24f, -195f), new RealmPoint(20f, -5f, -245f), P(8) }, new RealmPoint[3] { new RealmPoint(-90f, -23f, -195f), new RealmPoint(-75f, -24f, -100f), P(2) } }; public static readonly RealmPoint[][] Caves = BuildCaves(); private static RealmPoint[][] BuildCaves() { return new RealmPoint[3][] { Spiral(-150f, 65f, 25f, MathF.PI, 2, -45f), Spiral(20f, 260f, 40f, -MathF.PI / 2f, 3, -40f), Spiral(-135f, -100f, 30f, MathF.PI, 2, -50f) }; static RealmPoint[] Spiral(float cx, float cz, float radius, float startAngle, int turns, float bottom) { int num = turns * 32; float x = cx + (float)Math.Cos(startAngle) * radius; float z = cz + (float)Math.Sin(startAngle) * radius; float num2 = Height(x, z); List<RealmPoint> list = new List<RealmPoint>(); for (int i = 0; i <= num; i++) { float num3 = (float)i / (float)num; float num4 = startAngle + num3 * (float)turns * MathF.PI * 2f; list.Add(new RealmPoint(cx + (float)Math.Cos(num4) * radius, num2 + (bottom - num2) * num3, cz + (float)Math.Sin(num4) * radius)); } list.Add(P(5)); return list.ToArray(); } } private static RealmPoint P(int id) { return Districts[id].Center; } private static float Smooth(float t) { t = Math.Max(0f, Math.Min(1f, t)); return t * t * (3f - 2f * t); } public static float HeightBase(float x, float z) { float num = 165f * (float)Math.Exp(0f - (x * x / 65000f + (z - 285f) * (z - 285f) / 22000f)); float num2 = 60f * (float)Math.Exp(0f - ((x - 255f) * (x - 255f) / 24000f + (z - 120f) * (z - 120f) / 32000f)); float num3 = -72f * (float)Math.Exp(0f - ((x - 60f) * (x - 60f) / 23000f + (z + 65f) * (z + 65f) / 18000f)); float num4 = (float)(Math.Sin((double)x * 0.021) * Math.Cos((double)z * 0.017) * 5.0 + Math.Sin((double)(x + z) * 0.038) * 2.0); float num5 = Smooth(((float)Math.Sqrt(x * x + z * z) - 425f) / 55f) * 65f; return 25f + num + num2 + num3 + num4 + num5; } public static float Height(float x, float z) { float num = HeightBase(x, z); float num2 = 45f; float num3 = num; RealmPoint[][] paths = Paths; foreach (RealmPoint[] array in paths) { for (int j = 1; j < array.Length; j++) { RealmPoint realmPoint = array[j - 1]; RealmPoint realmPoint2 = array[j]; float num4 = realmPoint2.X - realmPoint.X; float num5 = realmPoint2.Z - realmPoint.Z; float num6 = Math.Max(0f, Math.Min(1f, ((x - realmPoint.X) * num4 + (z - realmPoint.Z) * num5) / (num4 * num4 + num5 * num5))); float num7 = (float)Math.Sqrt(Sq(x - realmPoint.X - num6 * num4) + Sq(z - realmPoint.Z - num6 * num5)); if (num7 < num2) { num2 = num7; num3 = realmPoint.Y + (realmPoint2.Y - realmPoint.Y) * num6; } } } num += (num3 - num) * (1f - Smooth((num2 - 9f) / 26f)); for (int k = 0; k < Districts.Count; k++) { if (k != 5) { RealmPoint realmPoint3 = P(k); float num8 = (float)Math.Sqrt(Sq(x - realmPoint3.X) + Sq(z - realmPoint3.Z)); float num9 = k switch { 0 => 48, 2 => 55, 3 => 55, 4 => 60, 7 => 48, _ => 24, }; num += (realmPoint3.Y - num) * (1f - Smooth((num8 - num9) / 20f)); } } float num10 = 1f - Smooth((Math.Abs(x - 295f) - 5f) / 10f); float num11 = Smooth((z + 245f) / 25f) * (1f - Smooth((z - 5f) / 30f)); num -= 12f * num10 * num11; float num12 = 1f - Smooth(((float)Math.Sqrt(Sq((x - 295f) * 1.15f) + Sq(z + 226f)) - 12f) / 16f); num -= 28f * num12; float num13 = (float)Math.Sqrt(x * x + z * z); if (num13 > 485f) { num -= Smooth((num13 - 485f) / 15f) * 110f; } return num; } public static float CollisionHeight(float x, float z) { float num = (float)Math.Floor(x / 4f) * 4f; float num2 = (float)Math.Floor(z / 4f) * 4f; float num3 = (x - num) / 4f; float num4 = (z - num2) / 4f; float num5 = Height(num, num2); float num6 = Height(num + 4f, num2); float num7 = Height(num, num2 + 4f); float num8 = Height(num + 4f, num2 + 4f); if (!(num3 + num4 <= 1f)) { return num8 + (num7 - num8) * (1f - num3) + (num6 - num8) * (1f - num4); } return num5 + (num6 - num5) * num3 + (num7 - num5) * num4; } public static float RouteDistance(float x, float z) { float num = float.MaxValue; RealmPoint[][] paths = Paths; foreach (RealmPoint[] array in paths) { for (int j = 1; j < array.Length; j++) { RealmPoint realmPoint = array[j - 1]; RealmPoint realmPoint2 = array[j]; float num2 = realmPoint2.X - realmPoint.X; float num3 = realmPoint2.Z - realmPoint.Z; float num4 = Math.Max(0f, Math.Min(1f, ((x - realmPoint.X) * num2 + (z - realmPoint.Z) * num3) / (num2 * num2 + num3 * num3))); num = Math.Min(num, (float)Math.Sqrt(Sq(x - realmPoint.X - num4 * num2) + Sq(z - realmPoint.Z - num4 * num3))); } } return num; } public static bool Contains(float x, float y, float z) { if (x * x + z * z <= 260100f && y >= -150f) { return y <= 330f; } return false; } public static int DistrictAt(float x, float y, float z) { if (y < -35f && Math.Abs(x + 65f) < 150f && Math.Abs(z - 65f) < 180f) { return 5; } float num = float.MaxValue; int result = 0; for (int i = 0; i < Districts.Count; i++) { if (i != 5) { RealmPoint realmPoint = P(i); float num2 = Sq(x - realmPoint.X) + Sq(z - realmPoint.Z); if (num2 < num) { num = num2; result = i; } } } return result; } private static float Sq(float x) { return x * x; } } public static class ShopAccess { public static IReadOnlyList<int> TabsFor(int currentCompletedFloor) { if (currentCompletedFloor < 0 || currentCompletedFloor > 1000) { throw new ArgumentOutOfRangeException("currentCompletedFloor"); } int[] array = new int[currentCompletedFloor + 1]; for (int i = 0; i < array.Length; i++) { array[i] = i; } return Array.AsReadOnly(array); } } public static class ShopFootprint { public const float HalfExtent = 21f; public const float MinHeight = -8f; public const float MaxHeight = 24f; public static bool Contains(float x, float y, float z) { if (Math.Abs(x) <= 21f && Math.Abs(z) <= 21f && y >= -8f) { return y <= 24f; } return false; } } public sealed class StoneLease { private readonly double _leaseSeconds; private double _lastObservedTime; public long Owner { get; private set; } public string Token { get; private set; } = string.Empty; public double ExpiresAt { get; private set; } public StoneLease(double leaseSeconds = 15.0) { if (double.IsNaN(leaseSeconds) || double.IsInfinity(leaseSeconds) || leaseSeconds <= 0.0 || leaseSeconds > 120.0) { throw new ArgumentOutOfRangeException("leaseSeconds"); } _leaseSeconds = leaseSeconds; } public void Advance(double now) { if (double.IsNaN(now) || double.IsInfinity(now) || now < _lastObservedTime || double.IsInfinity(now + _leaseSeconds)) { throw new ArgumentOutOfRangeException("now", "Use nonnegative monotonic host time."); } _lastObservedTime = now; if (Owner != 0L && now >= ExpiresAt) { Clear(); } } public bool TryAcquire(long owner, double now, out string token) { Advance(now); token = string.Empty; if (owner == 0L || (Owner != 0L && Owner != owner)) { return false; } if (Owner == 0L) { Owner = owner; Token = Guid.NewGuid().ToString("N"); } ExpiresAt = now + _leaseSeconds; token = Token; return true; } public bool IsOwner(long owner, string token, double now) { Advance(now); return Matches(owner, token); } public bool Renew(long owner, string token, double now) { if (!IsOwner(owner, token, now)) { return false; } ExpiresAt = now + _leaseSeconds; return true; } public bool Release(long owner, string token) { if (!Matches(owner, token)) { return false; } Clear(); return true; } private bool Matches(long owner, string token) { if (owner != 0L && Owner == owner) { return string.Equals(Token, token, StringComparison.Ordinal); } return false; } private void Clear() { Owner = 0L; Token = string.Empty; ExpiresAt = 0.0; } } public sealed class StrandedGuardTimeout { public const double Seconds = 30.0; private double? _since; private double _lastObserved; private float _health; public bool Observe(double now, float health, bool eligible) { if (!eligible || double.IsNaN(now) || double.IsInfinity(now) || now < 0.0 || float.IsNaN(health) || float.IsInfinity(health) || health <= 0f) { _since = null; return false; } if (!_since.HasValue || now < _lastObserved || health != _health) { _since = now; } _health = health; _lastObserved = now; return now - _since.Value >= 30.0; } } public enum TrialCreature { Greydwarf, Bear, Troll } public static class TrialSpawnRules { public const int HardEnemyLimit = 50; public const double MinimumInterval = 0.1; public const int MaximumModifiers = 5; public const int TrialMaximumModifiers = 3; public static TrialCreature CreatureAt(int spawnIndex) { if (spawnIndex < 0) { throw new ArgumentOutOfRangeException("spawnIndex"); } if (spawnIndex < 5) { return TrialCreature.Greydwarf; } return ((spawnIndex - 5) % 20) switch { 19 => TrialCreature.Troll, 9 => TrialCreature.Bear, _ => TrialCreature.Greydwarf, }; } public static double Interval(double combatSeconds) { ValidateTime(combatSeconds); return Math.Max(0.1, 10.0 / Math.Pow(100.0, Math.Min(combatSeconds, 90.0) / 90.0)); } public static int ModifierCeiling(double combatSeconds) { ValidateTime(combatSeconds); if (!(combatSeconds < 50.0)) { if (!(combatSeconds < 85.0)) { return 3; } return 2; } return 1; } public static int ModifierCount(double combatSeconds, int spawnIndex) { if (spawnIndex < 0) { throw new ArgumentOutOfRangeException("spawnIndex"); } return 1 + spawnIndex % ModifierCeiling(combatSeconds); } private static void ValidateTime(double combatSeconds) { if (double.IsNaN(combatSeconds) || double.IsInfinity(combatSeconds) || combatSeconds < 0.0) { throw new ArgumentOutOfRangeException("combatSeconds"); } } } public static class VoidAttackGeometry { public static (float[] Vertices, int[] Triangles, float[] UV) Shell(bool seed) { List<float> list = new List<float>(); List<float> list2 = new List<float>(); List<int> list3 = new List<int>(); int num = (seed ? 5 : 3); int num2 = (seed ? 11 : 9); for (int i = 0; i < num; i++) { int num3 = list.Count / 3; for (int j = 0; j < num2; j++) { float num4 = (float)j / (float)(num2 - 1); float num5 = (float)Math.Sin((double)num4 * Math.PI); float num6 = (float)i * MathF.PI * 2f / (float)num + (seed ? 0.36f : 0.65f) * (num4 - 0.5f); float num7 = (seed ? (0.38f + 0.32f * num5) : (0.2f + 0.16f * num5)); float num8 = (seed ? 0.3f : 0.13f) * (float)Math.Pow(num5, 0.6) + 0.008f; float item = (num4 - 0.5f) * (seed ? 1.65f : 2.7f) + ((i % 2 == 0) ? 0.06f : (-0.09f)) * num5; float num9 = (seed ? (0.08f * (float)Math.Sin((double)num4 * Math.PI * 2.0)) : (0.22f * (num4 * num4 - 0.3f))); for (int k = 0; k < 4; k++) { float num10 = ((k >= 2) ? 1 : (-1)); float num11 = ((k == 0 || k == 3) ? (-0.035f) : 0.055f); float item2 = (num7 + num11) * (float)Math.Cos(num6) - num10 * num8 * (float)Math.Sin(num6) + num9; float item3 = (num7 + num11) * (float)Math.Sin(num6) + num10 * num8 * (float)Math.Cos(num6); list.Add(item2); list.Add(item); list.Add(item3); list2.Add(0.015f + 0.97f * ((float)i / (float)num + (float)k / (float)(4 * num))); list2.Add(0.015f + 0.97f * num4); } } for (int l = 0; l < num2 - 1; l++) { for (int m = 0; m < 4; m++) { int num12 = num3 + l * 4 + m; int num13 = num3 + l * 4 + (m + 1) % 4; int item4 = num12 + 4; int item5 = num13 + 4; list3.Add(num12); list3.Add(num13); list3.Add(item4); list3.Add(item4); list3.Add(num13); list3.Add(item5); } } int[] array = new int[2] { 0, num2 - 1 }; foreach (int num14 in array) { int num15 = num3 + num14 * 4; if (num14 == 0) { list3.Add(num15); list3.Add(num15 + 2); list3.Add(num15 + 1); list3.Add(num15); list3.Add(num15 + 3); list3.Add(num15 + 2); } else { list3.Add(num15); list3.Add(num15 + 1); list3.Add(num15 + 2); list3.Add(num15); list3.Add(num15 + 2); list3.Add(num15 + 3); } } } for (int num16 = 0; num16 < list3.Count; num16 += 3) { int value = list3[num16]; list3[num16] = list3[num16 + 2]; list3[num16 + 2] = value; } return (Vertices: list.ToArray(), Triangles: list3.ToArray(), UV: list2.ToArray()); } public static (float[] Vertices, int[] Triangles, float[] UV) Core(bool seed) { List<float> list = new List<float>(); List<float> list2 = new List<float>(); List<int> list3 = new List<int>(); for (int i = 0; i < 11; i++) { for (int j = 0; j <= 16; j++) { float num = (float)i / 10f; float num2 = (float)j / 16f * MathF.PI * 2f; float num3 = (seed ? 0.44f : 0.17f) * (0.035f + 0.965f * (float)Math.Pow(Math.Sin((double)num * Math.PI), 0.75)); num3 *= 1f + 0.1f * (float)Math.Sin(num2 * 3f + num * 9f) + 0.06f * (float)Math.Cos(num2 * 5f - num * 7f); list.Add(num3 * (float)Math.Cos(num2)); list.Add((num - 0.5f) * (seed ? 1.4f : 2.25f)); list.Add(num3 * (float)Math.Sin(num2)); list2.Add(0.015f + 0.97f * (float)j / 16f); list2.Add(0.015f + 0.97f * num); if (i != 10 && j != 16) { int num4 = i * 17 + j; int num5 = num4 + 16 + 1; list3.Add(num4); list3.Add(num5); list3.Add(num4 + 1); list3.Add(num4 + 1); list3.Add(num5); list3.Add(num5 + 1); } } } return (Vertices: list.ToArray(), Triangles: list3.ToArray(), UV: list2.ToArray()); } public static (float[] Vertices, int[] Triangles, float[] UV) ImpactBloom() { List<float> list = new List<float>(); List<float> list2 = new List<float>(); List<int> list3 = new List<int>(); for (int i = 0; i < 9; i++) { for (int j = 0; j <= 24; j++) { float num = (float)i / 8f; float num2 = (float)j / 24f * MathF.PI * 2f; float num3 = (float)Math.Sin((double)num * Math.PI); float num4 = 1f + 0.18f * (float)Math.Sin(num2 * 5f + num * 4f) + 0.09f * (float)Math.Cos(num2 * 3f - num * 7f); float num5 = num3 * num4; list.Add(num5 * (float)Math.Cos(num2)); list.Add(num * 1.65f + num3 * 0.13f * (float)Math.Sin(num2 * 5f + num * 3f)); list.Add(num5 * (float)Math.Sin(num2)); list2.Add(0.02f + 0.96f * (float)j / 24f); list2.Add(0.02f + 0.96f * num); if (i != 8 && j != 24) { int num6 = i * 25 + j; int num7 = num6 + 24 + 1; if (i > 0) { list3.Add(num6); list3.Add(num6 + 1); list3.Add(num7); } if (i < 7) { list3.Add(num6 + 1); list3.Add(num7 + 1); list3.Add(num7); } } } } return (Vertices: list.ToArray(), Triangles: list3.ToArray(), UV: list2.ToArray()); } public static (float[] Vertices, int[] Triangles, float[] UV) Impact() { List<float> list = new List<float>(); List<float> list2 = new List<float>(); List<int> list3 = new List<int>(); for (int i = 0; i < 7; i++) { for (int j = 0; j <= 32; j++) { float num = (float)i / 6f; float num2 = (float)j / 32f * MathF.PI * 2f; float num3 = 0.015f + 0.985f * num; list.Add(num3 * (float)Math.Cos(num2)); list.Add((1f - num * num) * 0.45f); list.Add(num3 * (float)Math.Sin(num2)); list2.Add(0.5f + 0.48f * num3 * (float)Math.Cos(num2)); list2.Add(0.5f + 0.48f * num3 * (float)Math.Sin(num2)); if (i != 6 && j != 32) { int num4 = i * 33 + j; int num5 = num4 + 32 + 1; list3.Add(num4); list3.Add(num4 + 1); list3.Add(num5); list3.Add(num4 + 1); list3.Add(num5 + 1); list3.Add(num5); } } } return (Vertices: list.ToArray(), Triangles: list3.ToArray(), UV: list2.ToArray()); } } public static class VoidBlobRules { public const string Prefab = "Beyond_VoidBlob"; public const float Scale = 0.5159053f; public const float Health = 400f; public const float SpiritDamage = 125f; public const float Radius = 3.2f; public const double Windup = 0.85; public const double ReleaseGrace = 0.25; public const double AttackInterval = 3.6; public static bool CanResolve(double age, bool resolved, bool ownedBeforeRelease) { if (!double.IsNaN(age) && !double.IsInfinity(age) && !resolved && ownedBeforeRelease && age >= 0.85) { return age <= 1.1; } return false; } public static string SummonPrefab(int lifetimeIndex) { if (lifetimeIndex < 0 || lifetimeIndex >= 6) { throw new ArgumentOutOfRangeException("lifetimeIndex"); } return (lifetimeIndex % 3) switch { 0 => "Beyond_VoidBlob", 1 => VoidCreatureRules.Prefab(VoidKind.Stalker), _ => VoidCreatureRules.Prefab(VoidKind.Cantor), }; } } public static class VoidBroodRules { public const int Children = 6; public const int MaximumCasts = 2; public const int MaximumAttempts = 30; public const double InitialDelay = 10.0; public const double Cooldown = 40.0; public const double Lifetime = 4.0; public const double MaximumStep = 0.35; public const double QueueLifetime = 20.0; public const float Reach = 24f; public const float Gravity = 12f; public const float Radius = 0.42f; public static bool CanCast(double now, double nextCast, int casts, int living, int remaining, bool flying, bool ritualPending) { if (Finite(now) && Finite(nextCast) && now >= nextCast && casts >= 0 && casts < 2 && living == 0 && remaining == 0 && !flying) { return !ritualPending; } return false; } public static bool CanSweep(double age, double previous, bool continuousOwner) { if (continuousOwner && Finite(age) && Finite(previous) && previous >= 0.0 && age > previous && age <= 4.0) { return age - previous <= 0.35; } return false; } public static float FlightTime(float horizontalDistance) { return Math.Max(0.7f, Math.Min(1.8f, horizontalDistance / 12f)); } public static float PlacementRadius(int attempt) { return 2.6f + (float)(Math.Max(0, attempt) % 3) * 0.85f + Math.Min(3f, (float)(Math.Max(0, attempt) / 6) * 0.75f); } public static Vector3 Velocity(Vector3 start, Vector3 aim) { Vector3 vector = aim - start; float num = FlightTime(new Vector2(vector.X, vector.Z).Length()); return vector / num + Vector3.UnitY * (12f * num * 0.5f); } public static Vector3 Position(Vector3 start, Vector3 velocity, float age) { return start + velocity * age - Vector3.UnitY * (12f * age * age * 0.5f); } private static bool Finite(double value) { if (!double.IsNaN(value)) { return !double.IsInfinity(value); } return false; } } public enum VoidKind { Eidolon, Stalker, Cantor } public enum VoidAttack { None, Sweep, ReturnSweep, Fracture, Pulse, Advance, Pounce, Claw, Shards, Rupture, Summon, Brood } public static class VoidCreatureRules { public const int MaximumAdds = 3; public const int LifetimeAdds = 6; public const float ClawReach = 4.2f; public const float ClawArc = 75f; public const float PounceReach = 8f; public const float PounceRadius = 2.2f; public const float SweepReach = 7f; public const float SweepArc = 100f; public const float FractureReach = 16f; public const float AdvanceReach = 10f; public const float PulseInner = 3f; public const float PulseOuter = 17f; public const float ShardReach = 44f; public const float ShardSpeed = 12f; public const float RuptureRadius = 3f; public static string Prefab(VoidKind kind) { return kind switch { VoidKind.Eidolon => "Beyond_VoidEidolon", VoidKind.Stalker => "Beyond_Riftstalker", _ => "Beyond_HollowCantor", }; } public static float Health(VoidKind kind) { return kind switch { VoidKind.Eidolon => 45000, VoidKind.Stalker => 1800, _ => 1400, }; } public static int Phase(float fraction) { if (!(fraction <= 0.3f)) { return (fraction <= 0.65f) ? 1 : 0; } return 2; } public static int NewThresholds(float fraction, int handled) { return (int)(((Phase(fraction) >= 1) ? 1u : 0u) | (uint)((Phase(fraction) >= 2) ? 2 : 0)) & ~handled; } public static float Windup(VoidAttack attack) { return attack switch { VoidAttack.Sweep => 0.65f, VoidAttack.ReturnSweep => 0.6f, VoidAttack.Fracture => 1.05f, VoidAttack.Pulse => 1.3f, VoidAttack.Advance => 0.9f, VoidAttack.Pounce => 0.3f, VoidAttack.Claw => 0.5f, VoidAttack.Shards => 0.7f, VoidAttack.Rupture => 1.05f, VoidAttack.Summon => 1.5f, VoidAttack.Brood => 1.2f, _ => 0f, }; } public static float Active(VoidAttack attack) { switch (attack) { case VoidAttack.Sweep: case VoidAttack.ReturnSweep: return 0.28f; case VoidAttack.Pulse: return 1.4f; case VoidAttack.Fracture: return 0.9f; case VoidAttack.Advance: return 0.85f; case VoidAttack.Pounce: return 0.7f; case VoidAttack.Claw: return 0.34f; case VoidAttack.Shards: return 4f; default: return 0.2f; } } public static float StrikeDelay(VoidAttack attack) { if (((uint)(attack - 1) > 1u && attack != VoidAttack.Claw) || 1 == 0) { return 0f; } return Active(attack) * 0.45f; } public static float Recovery(VoidAttack attack) { return attack switch { VoidAttack.Claw => 0.5f, VoidAttack.Pounce => 0.75f, VoidAttack.Sweep => 0.75f, VoidAttack.ReturnSweep => 0.85f, VoidAttack.Shards => 0.85f, _ => 1.05f, }; } public static float Duration(VoidAttack attack) { return Windup(attack) + Active(attack) + Recovery(attack); } public static float Damage(VoidAttack attack) { return attack switch { VoidAttack.Sweep => 600, VoidAttack.ReturnSweep => 575, VoidAttack.Fracture => 900, VoidAttack.Pulse => 700, VoidAttack.Advance => 875, VoidAttack.Pounce => 675, VoidAttack.Claw => 600, VoidAttack.Shards => 475, VoidAttack.Rupture => 550, _ => 0, }; } public static float SpiritShare(VoidAttack attack) { switch (attack) { case VoidAttack.Sweep: case VoidAttack.ReturnSweep: case VoidAttack.Pounce: return 0.25f; case VoidAttack.Fracture: case VoidAttack.Advance: return 0.3f; case VoidAttack.Pulse: return 0.7f; case VoidAttack.Claw: return 0.2f; case VoidAttack.Shards: return 0.6f; case VoidAttack.Rupture: return 0.65f; default: return 0f; } } public static bool IsWindowLive(double age, VoidAttack attack) { if (!double.IsNaN(age) && !double.IsInfinity(age) && age >= (double)Windup(attack)) { return age <= (double)(Windup(attack) + Active(attack)); } return false; } } public static class VoidLocomotion { public const float BossEngageRange = 6.5f; public const float BossCycleMetres = 3.2f; public const float HunterCycleMetres = 2.6f; public const float HunterSpeed = 5.85f; public const float HunterRunSpeed = 9.75f; public const float EngageFraction = 0.8f; public static float EngageDistance(VoidAttack attack) { float num; switch (attack) { case VoidAttack.Claw: num = 4.2f; break; case VoidAttack.Pounce: num = 8f; break; case VoidAttack.Shards: case VoidAttack.Rupture: num = 44f; break; default: num = 0f; break; } return 0.8f * num; } public static bool CanEngage(VoidAttack attack, float distance) { if (float.IsFinite(distance) && distance >= 0f && EngageDistance(attack) > 0f) { return distance <= EngageDistance(attack); } return false; } public static bool BossMustApproach(float distance) { if (float.IsFinite(distance)) { return distance > 6.5f; } return false; } public static float PhaseStep(float horizontalSpeed, float dt, float cycleMetres = 3.2f) { if (!float.IsFinite(horizontalSpeed) || !float.IsFinite(dt) || !float.IsFinite(cycleMetres) || horizontalSpeed <= 0.04f || dt <= 0f || cycleMetres <= 0f) { return 0f; } return Math.Min(horizontalSpeed, 20f) * Math.Min(dt, 0.1f) * (MathF.PI * 2f / cycleMetres); } } public sealed class VoidBone { public string Name { get; } public string Parent { get; } public float[] Position { get; } public VoidBone(string name, string parent, float x, float y, float z) { Name = name; Parent = parent; Position = new float[3] { x, y, z }; } } public sealed class VoidPart { public string Bone { get; } public string Shape { get; } public int Material { get; } public float[] Position { get; } public float[] Size { get; } public float[] Rotation { get; } public VoidPart(string bone, string shape, int material, float x, float y, float z, float sx, float sy, float sz, float rx, float ry, float rz) { Bone = bone; Shape = shape; Material = material; Position = new float[3] { x, y, z }; Size = new float[3] { sx, sy, sz }; Rotation = new float[3] { rx, ry, rz }; } } public sealed class VoidModelBlueprint { public List<VoidBone> Bones { get; } = new List<VoidBone>(); public List<VoidPart> Parts { get; } = new List<VoidPart>(); private void Bone(string name, string parent, float x, float y, float z) { Bones.Add(new VoidBone(name, parent, x, y, z)); } private void Part(string bone, float x, float y, float z, float sx, float sy, float sz, int mat = 0, string shape = "shell", float rx = 0f, float ry = 0f, float rz = 0f) { Parts.Add(new VoidPart(bone, shape, mat, x, y, z, sx, sy, sz, rx, ry, rz)); } public static VoidModelBlueprint Create(VoidKind kind) { VoidModelBlueprint voidModelBlueprint = new VoidModelBlueprint(); switch (kind) { case VoidKind.Eidolon: voidModelBlueprint.Boss(); break; case VoidKind.Stalker: voidModelBlueprint.Hunter(); break; default: voidModelBlueprint.Caster(); break; } return voidModelBlueprint; } private void Boss() { Bone("body", "", 0f, 2.15f, 0f); Bone("chest", "body", 0f, 1f, 0f); Bone("head", "chest", 0f, 1.05f, 0f); Bone("core", "chest", 0f, 0f, 0.12f); Part("body", 0f, 0f, 0f, 1.15f, 0.62f, 0.65f); Part("body", 0f, -0.3f, 0.28f, 0.48f, 0.65f, 0.22f, 1, "shell", 0f, 0f, 180f); for (int i = -1; i <= 1; i += 2) { string text = ((i < 0) ? "L" : "R"); Bone("arm" + text, "chest", (float)i * 0.92f, 0.43f, 0f); Bone("fore" + text, "arm" + text, (float)i * 0.12f, -0.9f, 0f); if (i > 0) { Bone("handR", "foreR", 0.24f, -0.7f, 0.31f); } Bone("leg" + text, "body", (float)i * 0.44f, -0.13f, 0f); Bone("shin" + text, "leg" + text, 0f, -0.98f, 0f); Bone("foot" + text, "shin" + text, 0f, -0.8f, 0.15f); Part("chest", (float)i * 0.57f, 0.1f, 0f, 0.36f, 1.15f, 0.62f, 0, "shell", 0f, 0f, i * -12); Part("chest", (float)i * 0.37f, 0.55f, 0.03f, 0.76f, 0.3f, 0.67f, 0, "shell", 0f, 0f, i * 20); Part("chest", (float)i * 0.4f, -0.47f, 0.07f, 0.64f, 0.3f, 0.59f, 0, "shell", 0f, 0f, i * -28); for (int j = 0; j < 3; j++) { Part("chest", (float)i * (0.49f - (float)j * 0.035f), 0.32f - (float)j * 0.3f, 0.32f, 0.42f, 0.105f, 0.27f, 1, "shell", 0f, 0f, i * (24 - j * 24)); } Part("arm" + text, (float)i * 0.13f, -0.12f, 0f, 0.9f, 0.65f, 0.85f, 0, "shell", 0f, 0f, i * 20); Part("arm" + text, (float)i * 0.36f, 0.1f, -0.04f, 0.42f, 0.35f, 0.35f, 1, "shell", 0f, 0f, i * -25); Part("arm" + text, 0f, -0.57f, 0f, 0.44f, 0.82f, 0.48f, 0, "shell", 0f, 0f, i * -8); Part("arm" + text, 0f, -0.52f, 0.235f, 0.14f, 0.6f, 0.04f, 2, "shell", 0f, 0f, i * -8); Part("fore" + text, 0f, -0.48f, 0f, 0.55f, 0.95f, 0.57f, 0, "shell", 0f, 0f, i * 7); Part("fore" + text, 0f, -0.52f, 0.29f, 0.3f, 0.7f, 0.07f, 1, "shell", 0f, 0f, i * 7); Part("fore" + text, 0f, -0.99f, 0.08f, 0.44f, 0.34f, 0.48f); for (int k = 0; k < 3; k++) { Part("fore" + text, (float)(k - 1) * 0.13f, -1.16f, 0.2f, 0.12f, 0.3f, 0.15f, 1, "shell", -20f); } Part("body", (float)i * 0.52f, -0.3f, 0.02f, 0.44f, 0.84f, 0.7f, 0, "shell", 0f, 0f, i * 18); Part("leg" + text, 0f, -0.46f, 0f, 0.51f, 0.94f, 0.62f, 0, "shell", 0f, 0f, i * 4); Part("leg" + text, 0f, -0.51f, 0.31f, 0.18f, 0.53f, 0.045f, 1); Part("shin" + text, 0f, -0.43f, 0f, 0.42f, 0.87f, 0.48f); Part("shin" + text, 0f, -0.44f, 0.245f, 0.08f, 0.65f, 0.035f, 2); Part("foot" + text, 0f, -0.03f, 0.05f, 0.56f, 0.3f, 0.89f); Part("head", (float)i * 0.2f, 0.05f, 0f, 0.34f, 0.53f, 0.5f, 0, "shell", 0f, 0f, i * -9); Part("head", (float)i * 0.28f, 0.32f, -0.04f, 0.27f, 0.44f, 0.31f, 1, "shell", 0f, 0f, i * -18); Part("head", (float)i * 0.13f, 0.04f, 0.29f, 0.13f, 0.065f, 0.025f, 2, "shell", 0f, 0f, i * 14); } Part("head", 0f, -0.21f, 0.02f, 0.39f, 0.23f, 0.4f); Part("head", 0f, -0.05f, 0.28f, 0.065f, 0.42f, 0.06f, 2); Part("chest", 0f, 0.04f, -0.3f, 0.31f, 1.2f, 0.25f); Part("core", 0f, 0f, 0f, 0.42f, 0.62f, 0.42f, 2, "crystal", 0f, 0f, 18f); Part("core", 0f, 0f, 0f, 0.56f, 0.21f, 0.56f, 1, "crystal", 0f, 45f); Part("foreR", 0.37f, -0.55f, 0.08f, 0.33f, 1.85f, 0.3f, 0, "blade", 0f, 0f, -15f); Part("foreR", 0.57f, -0.54f, 0.08f, 0.1f, 1.7f, 0.13f, 2, "blade", 0f, 0f, -15f); for (int l = 0; l < 3; l++) { Part("chest", 0f, 0.4f - (float)l * 0.35f, -0.4f, 0.35f, 0.25f, 0.29f, 1, "shell", -20f); } } private void Hunter() { Bone("body", "", 0f, 0.98f, -0.12f); Bone("thorax", "body", 0f, 0.02f, 0.35f); Bone("abdomen", "body", 0f, 0f, -0.48f); Bone("head", "thorax", 0f, 0.02f, 0.67f); Bone("tail", "abdomen", 0f, 0.03f, -0.47f); Bone("tailtip", "tail", 0f, 0f, -0.72f); Part("thorax", 0f, 0.15f, 0.35f, 0.64f, 0.28f, 0.55f); Part("abdomen", 0f, 0.1f, -0.15f, 0.54f, 0.3f, 0.52f); Part("body", 0f, 0.02f, -0.08f, 0.12f, 1.15f, 0.12f, 2, "shell", 90f); for (int i = 0; i < 3; i++) { Part("body", 0f, 0.27f, -0.57f + (float)i * 0.35f, 0.39f, 0.18f, 0.4f, 1, "shell", 8f); Part("body", 0f, 0.37f, -0.57f + (float)i * 0.35f, 0.035f, 0.035f, 0.22f, 2); } for (int j = -1; j <= 1; j += 2) { string text = ((j < 0) ? "L" : "R"); Bone("neck" + text, "head", (float)j * 0.24f, 0.045f, -0.08f); Bone("head" + text, "neck" + text, 0f, 0.025f, 0.16f); Bone("jaw" + text, "head" + text, 0f, -0.08f, 0.06f); Part("neck" + text, 0f, 0f, 0.04f, 0.24f, 0.22f, 0.35f); Part("thorax", (float)j * 0.23f, 0.02f, 0.41f, 0.22f, 0.26f, 0.6f, 0, "shell", 0f, j * 12); for (int k = 0; k < 4; k++) { Part("body", (float)j * 0.25f, -0.025f, -0.5f + (float)k * 0.3f, 0.15f, 0.39f, 0.18f, 1, "shell", 0f, 0f, j * -22); } for (int l = 0; l < 2; l++) { string text2 = ((l == 0) ? "front" : "rear") + text; Bone(text2, (l == 0) ? "thorax" : "abdomen", (float)j * 0.28f, -0.03f, (l == 0) ? (-0.03f) : (-0.14f)); Bone(text2 + "lower", text2, (float)j * 0.28f, -0.35f, (l == 0) ? (-0.14f) : 0.14f); Bone(text2 + "foot", text2 + "lower", (float)j * 0.1f, -0.49f, 0.06f); Part(text2, (float)j * 0.12f, -0.12f, 0f, 0.24f, 0.58f, 0.26f, 0, "shell", rz: j * 38, rx: (l == 0) ? 18 : (-18)); Part(text2 + "lower", (float)j * 0.07f, -0.24f, 0f, 0.19f, 0.65f, 0.2f, 0, "shell", rz: j * 12, rx: (l == 0) ? (-12) : 12); Part(text2 + "foot", (float)j * 0.04f, -0.02f, 0.11f, 0.25f, 0.13f, 0.4f, 1); Part(text2, (float)j * 0.17f, -0.09f, -0.02f, 0.24f, 0.23f, 0.28f, 1, "shell", 0f, 0f, j * -20); } Bone("sickle" + text, "thorax", (float)j * 0.37f, 0.12f, 0.27f); Bone("hook" + text, "sickle" + text, (float)j * 0.14f, -0.26f, 0.35f); Part("sickle" + text, (float)j * 0.08f, -0.12f, 0.16f, 0.24f, 0.58f, 0.25f, 0, "shell", -52f, 0f, j * 15); Part("hook" + text, (float)j * 0.06f, -0.19f, 0.19f, 0.2f, 0.65f, 0.26f, 0, "blade", -32f, 0f, j * -12); Part("hook" + text, (float)j * 0.12f, -0.16f, 0.23f, 0.04f, 0.56f, 0.08f, 2, "blade", -32f, 0f, j * -12); for (int m = -1; m <= 1; m += 2) { Part("head" + text, (float)m * 0.105f, 0.02f, 0.23f, 0.21f, 0.65f, 0.32f, 0, "shell", 90f, 0f, m * 7); Part("jaw" + text, (float)m * 0.1f, -0.06f, 0.22f, 0.105f, 0.4f, 0.14f, 1, "shell", 80f, 0f, m * -8); } Part("head" + text, 0f, 0.02f, 0.23f, 0.04f, 0.55f, 0.06f, 2, "shell", 90f); } Part("tail", 0f, 0f, -0.3f, 0.26f, 0.77f, 0.25f, 0, "shell", 90f); Part("tailtip", 0f, 0.01f, -0.28f, 0.18f, 0.68f, 0.19f, 1, "shell", 90f); Part("tailtip", 0f, 0.07f, -0.45f, 0.035f, 0.29f, 0.05f, 2, "shell", 90f); } private void Caster() { Bone("body", "", 0f, 1.25f, 0f); Bone("chest", "body", 0f, 0.26f, 0f); Bone("head", "chest", 0f, 0.6f, 0f); Bone("core", "chest", 0f, 0.27f, 0.05f); for (int i = -1; i <= 1; i += 2) { string text = ((i < 0) ? "L" : "R"); Bone("veil" + text, "body", (float)i * 0.25f, -0.28f, 0f); Bone("arm" + text, "chest", (float)i * 0.48f, 0.26f, 0f); Bone("fore" + text, "arm" + text, (float)i * 0.14f, -0.42f, 0.06f); Part("chest", (float)i * 0.28f, 0f, -0.01f, 0.21f, 0.78f, 0.43f, 0, "shell", 0f, 0f, i * -8); Part("arm" + text, (float)i * 0.12f, -0.03f, 0f, 0.46f, 0.32f, 0.45f, 0, "shell", 0f, 0f, i * 22); Part("arm" + text, (float)i * 0.06f, -0.29f, 0f, 0.19f, 0.57f, 0.24f, 0, "shell", 0f, 0f, i * 14); Part("fore" + text, 0f, -0.24f, 0.01f, 0.18f, 0.53f, 0.22f, 0, "shell", -22f); Part("fore" + text, 0f, -0.48f, 0.14f, 0.22f, 0.23f, 0.23f, 1); for (int j = 0; j < 3; j++) { Part("fore" + text, (float)(j - 1) * 0.065f, -0.56f, 0.27f, 0.06f, 0.18f, 0.07f, 1, "shell", -55f); } Part("head", (float)i * 0.25f, 0.02f, 0f, 0.22f, 0.68f, 0.5f, 0, "shell", 0f, 0f, i * -13); Part("head", (float)i * 0.15f, 0.33f, -0.01f, 0.34f, 0.17f, 0.51f, 0, "shell", 0f, 0f, i * 26); Part("head", (float)i * 0.2f, 0.09f, 0.255f, 0.035f, 0.29f, 0.025f, 2, "shell", 0f, 0f, i * -13); for (int k = 0; k < 3; k++) { Part("chest", (float)i * 0.22f, 0.19f - (float)k * 0.19f, 0.25f, 0.26f, 0.055f, 0.14f, 1, "shell", 0f, 0f, i * (28 - k * 20)); } for (int l = 0; l < 3; l++) { Part("veil" + text, (float)i * (-0.04f + (float)l * 0.07f), -0.11f, -0.08f + (float)l * 0.18f, 0.27f, 0.96f, 0.24f, (l == 1) ? 1 : 0, "shell", -8f, 0f, i * (8 + l * 5)); } } Part("head", 0f, 0.08f, -0.21f, 0.47f, 0.61f, 0.14f); Part("head", 0f, 0.38f, -0.07f, 0.29f, 0.31f, 0.26f, 1); Part("core", 0f, 0f, 0f, 0.19f, 0.39f, 0.19f, 2, "crystal"); Part("chest", 0f, -0.3f, 0.08f, 0.23f, 0.3f, 0.29f, 1, "crystal"); Part("body", 0f, -0.55f, 0.18f, 0.1f, 0.53f, 0.08f, 2, "crystal"); } public static (float[] Vertices, int[] Triangles, float[] UV) Geometry(string shape) { int sides = ((shape == "shell") ? 10 : ((shape == "plate") ? 8 : 6)); float[] heights = ((!(shape == "shell")) ? ((!(shape == "spike")) ? new floa