using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using ExitGames.Client.Photon; using HarmonyLib; using Microsoft.CodeAnalysis; using Peak; using Peak.Network; using Photon.Pun; using Photon.Realtime; using TerrainRandomiser; using TerrainRandomiser.TerrainGeneration; using UnityEngine; using UnityEngine.SceneManagement; using Zorro.Core; [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("Aeralis Foundation")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyDescription("Library for custom segments. (Works as an independent mod)")] [assembly: AssemblyFileVersion("1.2.0.0")] [assembly: AssemblyInformationalVersion("1.2.0+e8bed72db5b1ae204a6c57dde40e8c11fa9193e5")] [assembly: AssemblyProduct("AF.PLL.Library")] [assembly: AssemblyTitle("AF.PLL.Library")] [assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/Aurora-Aeralis/PLL_Library")] [assembly: AssemblyVersion("1.2.0.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 PLL.Library { public static class MyPluginInfo { public const string PLUGIN_GUID = "af.pll.library"; public const string PLUGIN_NAME = "AF.PLL.Library"; public const string PLUGIN_VERSION = "1.2.0"; } public static class PLLLibrary { public const string PluginGuid = "af.pll.library"; public const string PluginName = "AF.PLL.Library"; public const string PluginVersion = "1.2.0"; } [BepInPlugin("af.pll.library", "AF.PLL.Library", "1.2.0")] [BepInDependency("com.snosz.terrainrandomiser", "1.1.7")] public sealed class Plugin : BaseUnityPlugin { public static ManualLogSource PLLLog { get; private set; } private void Awake() { //IL_0020: Unknown result type (might be due to invalid IL or missing references) PLLLog = ((BaseUnityPlugin)this).Logger; FileManager.Initialize(((BaseUnityPlugin)this).Info.Metadata); new Harmony("af.pll.library").PatchAll(typeof(Plugin).Assembly); PLLLog.LogInfo((object)"AF.PLL.Library 1.2.0 loaded."); } } public static class FileManager { private const string DefaultLayoutOrder = "Beach > Tropics > Roots > Alpine > Mesa > Caldera > Volcano > Peak"; internal const string DefaultRepeatable = "Tropics > Roots > Alpine > Mesa > Caldera"; internal const string DefaultChances = "1 > 1 > 1 > 1 > 1"; private const int DefaultScale = 8; public static ConfigEntry LayoutOrder { get; private set; } public static ConfigEntry DoOrder { get; private set; } public static ConfigEntry InfiniteMap { get; private set; } public static ConfigEntry InfiniteMapRepeatable { get; private set; } public static ConfigEntry InfiniteMapChances { get; private set; } public static ConfigEntry InfiniteMapScale { get; private set; } public static ConfigEntry InfiniteMapBeginIndex { get; private set; } public static ConfigEntry InfiniteMapRemoveOld { get; private set; } public static ConfigEntry Winnable { get; private set; } public static ConfigEntry PeakAtEnd { get; private set; } public static ConfigEntry WaterFollowsBeach { get; private set; } public static ConfigEntry RelocatePlane { get; private set; } public static ConfigEntry RelocateStart { get; private set; } public static ConfigEntry LazyGeneration { get; private set; } public static ConfigEntry LazyFeatures { get; private set; } public static ConfigEntry Fogless { get; private set; } public static ConfigEntry NoWater { get; private set; } public static ConfigEntry NoPlane { get; private set; } public static ConfigEntry RemoveOld { get; private set; } internal static void Initialize(BepInPlugin ownerMetadata) { //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) string text = Path.Combine(Paths.ConfigPath, "AF", "PLL_Library"); string text2 = Path.Combine(text, "config.cfg"); Directory.CreateDirectory(text); bool flag = File.Exists(text2); bool flag2 = flag && new ConfigFile(text2, false, ownerMetadata) { SaveOnConfigSet = false }.Bind("Version", "LibraryVersion", string.Empty, (ConfigDescription)null).Value != "1.2.0"; bool flag3 = !flag || TypeMatches(text2, "Version", "LibraryVersion", typeof(string).Name); bool flag4 = !flag || TypeMatches(text2, "Map", "LayoutOrder", typeof(string).Name); bool flag5 = !flag || TypeMatches(text2, "Map", "DoOrder", typeof(bool).Name); bool flag6 = !flag || TypeMatches(text2, "Map", "InfiniteMap", typeof(bool).Name); bool flag7 = !flag || TypeMatches(text2, "Fields", "InfiniteMap: Repeatable", typeof(string).Name); bool flag8 = !flag || TypeMatches(text2, "Fields", "InfiniteMap: Chances", typeof(string).Name); bool flag9 = !flag || TypeMatches(text2, "Fields", "InfiniteMap: Scale", typeof(int).Name); bool flag10 = !flag || TypeMatches(text2, "Fields", "InfiniteMap: Begin Index", typeof(int).Name); bool flag11 = !flag || TypeMatches(text2, "Fields", "InfiniteMap: Remove Old", typeof(bool).Name); bool flag12 = !flag || TypeMatches(text2, "Behaviors", "Winnable", typeof(bool).Name); bool flag13 = !flag || TypeMatches(text2, "Behaviors", "Peak at end", typeof(bool).Name); bool flag14 = !flag || TypeMatches(text2, "Behaviors", "Water follows Beach", typeof(bool).Name); bool flag15 = !flag || TypeMatches(text2, "Prerequisites", "Relocate Plane", typeof(bool).Name); bool flag16 = !flag || TypeMatches(text2, "Prerequisites", "Relocate Start", typeof(bool).Name); bool flag17 = !flag || TypeMatches(text2, "Optimizations", "Lazy Generation", typeof(bool).Name); bool flag18 = !flag || TypeMatches(text2, "Optimizations", "Lazy Features", typeof(bool).Name); bool flag19 = !flag || TypeMatches(text2, "Optimizations", "Fogless", typeof(bool).Name); bool flag20 = !flag || TypeMatches(text2, "Optimizations", "No Water", typeof(bool).Name); bool flag21 = !flag || TypeMatches(text2, "Optimizations", "No Plane", typeof(bool).Name); bool flag22 = !flag || TypeMatches(text2, "Optimizations", "Remove Old", typeof(bool).Name); bool flag23 = flag2 || !flag3 || !SchemaMatches(text2); flag23 = flag23 || !flag4 || !flag5 || !flag6 || !flag7 || !flag8 || !flag9 || !flag10 || !flag11 || !flag12 || !flag13 || !flag14 || !flag15 || !flag16 || !flag17 || !flag18 || !flag19 || !flag20 || !flag21 || !flag22; ConfigFile val = BindConfig(text2, ownerMetadata); if (!flag4) { LayoutOrder.Value = "Beach > Tropics > Roots > Alpine > Mesa > Caldera > Volcano > Peak"; } if (!flag5) { DoOrder.Value = true; } if (!flag6) { InfiniteMap.Value = false; } if (!flag7) { InfiniteMapRepeatable.Value = "Tropics > Roots > Alpine > Mesa > Caldera"; } if (!flag8) { InfiniteMapChances.Value = "1 > 1 > 1 > 1 > 1"; } if (!flag9) { InfiniteMapScale.Value = 8; } if (!flag10) { InfiniteMapBeginIndex.Value = -1; } if (!flag11) { InfiniteMapRemoveOld.Value = false; } if (!flag12) { Winnable.Value = true; } if (!flag13) { PeakAtEnd.Value = false; } if (!flag14) { WaterFollowsBeach.Value = true; } if (!flag15) { RelocatePlane.Value = true; } if (!flag16) { RelocateStart.Value = true; } if (!flag17) { LazyGeneration.Value = true; } if (!flag18) { LazyFeatures.Value = false; } if (!flag19) { Fogless.Value = false; } if (!flag20) { NoWater.Value = false; } if (!flag21) { NoPlane.Value = false; } if (!flag22) { RemoveOld.Value = false; } if (flag23) { string value = LayoutOrder.Value; bool value2 = DoOrder.Value; bool value3 = InfiniteMap.Value; string value4 = InfiniteMapRepeatable.Value; string value5 = InfiniteMapChances.Value; int value6 = InfiniteMapScale.Value; int value7 = InfiniteMapBeginIndex.Value; bool value8 = InfiniteMapRemoveOld.Value; bool value9 = Winnable.Value; bool value10 = PeakAtEnd.Value; bool value11 = WaterFollowsBeach.Value; bool value12 = RelocatePlane.Value; bool value13 = RelocateStart.Value; bool value14 = LazyGeneration.Value; bool value15 = LazyFeatures.Value; bool value16 = Fogless.Value; bool value17 = NoWater.Value; bool value18 = NoPlane.Value; bool value19 = RemoveOld.Value; File.Delete(text2); val = BindConfig(text2, ownerMetadata); LayoutOrder.Value = value; DoOrder.Value = value2; InfiniteMap.Value = value3; InfiniteMapRepeatable.Value = value4; InfiniteMapChances.Value = value5; InfiniteMapScale.Value = value6; InfiniteMapBeginIndex.Value = value7; InfiniteMapRemoveOld.Value = value8; Winnable.Value = value9; PeakAtEnd.Value = value10; WaterFollowsBeach.Value = value11; RelocatePlane.Value = value12; RelocateStart.Value = value13; LazyGeneration.Value = value14; LazyFeatures.Value = value15; Fogless.Value = value16; NoWater.Value = value17; NoPlane.Value = value18; RemoveOld.Value = value19; } val.Save(); val.SaveOnConfigSet = true; } private static ConfigFile BindConfig(string path, BepInPlugin ownerMetadata) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Expected O, but got Unknown //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Expected O, but got Unknown ConfigFile val = new ConfigFile(path, false, ownerMetadata) { SaveOnConfigSet = false }; val.Bind("Version", "LibraryVersion", "1.2.0", "Tracks the PLL Library version."); LayoutOrder = val.Bind("Map", "LayoutOrder", "Beach > Tropics > Roots > Alpine > Mesa > Caldera > Volcano > Peak", "Defines the map layout order; Peak is the structural attachment in Caldera > Volcano > Peak."); DoOrder = val.Bind("Map", "DoOrder", true, "Enables LayoutOrder for the map."); InfiniteMap = val.Bind("Map", "InfiniteMap", false, "Enables infinite map generation."); InfiniteMapRepeatable = val.Bind("Fields", "InfiniteMap: Repeatable", "Tropics > Roots > Alpine > Mesa > Caldera", "Segment names eligible for repetition, separated by >."); InfiniteMapChances = val.Bind("Fields", "InfiniteMap: Chances", "1 > 1 > 1 > 1 > 1", "Non-negative weights mapped by position to InfiniteMap: Repeatable, separated by >."); InfiniteMapScale = val.Bind("Fields", "InfiniteMap: Scale", 8, new ConfigDescription("Total number of segments created by InfiniteMap.", (AcceptableValueBase)(object)new AcceptableValueRange(1, 255), Array.Empty())); InfiniteMapBeginIndex = val.Bind("Fields", "InfiniteMap: Begin Index", -1, "-1 appends generated segments after the final zone; other values are clamped to a zero-based logical segment boundary."); InfiniteMapRemoveOld = val.Bind("Fields", "InfiniteMap: Remove Old", false, "Removes the default layout so only InfiniteMap: Repeatable segments are used."); Winnable = val.Bind("Behaviors", "Winnable", true, "Enables the configured final-zone win behavior."); PeakAtEnd = val.Bind("Behaviors", "Peak at end", false, "Places Peak at the end of the generated layout."); WaterFollowsBeach = val.Bind("Behaviors", "Water follows Beach", true, "Activates the water floor when Beach is reached; otherwise enables it beneath the first segment from the start."); RelocatePlane = val.Bind("Prerequisites", "Relocate Plane", true, "Relocates the crashed plane to the player start when the layout does not begin with Beach."); RelocateStart = val.Bind("Prerequisites", "Relocate Start", true, "Aligns the world start with the beginning of the first segment."); LazyGeneration = val.Bind("Optimizations", "Lazy Generation", true, "Defers procedural prop generation until its prerequisite zone is reached."); LazyFeatures = val.Bind("Optimizations", "Lazy Features", false, "Extends Lazy Generation by keeping future cloned feature components inactive until segment load. Generating more than six new segments without it may take over 10 minutes, especially due to lighting."); Fogless = val.Bind("Optimizations", "Fogless", false, "Disables the fog sphere and its relocation behavior."); NoWater = val.Bind("Optimizations", "No Water", false, "Disables Beach water and all water relocation behavior."); NoPlane = val.Bind("Optimizations", "No Plane", false, "Removes the crashed plane and its affiliates except spawn points."); RemoveOld = val.Bind("Optimizations", "Remove Old", false, "Destroys map zones older than the immediately previous zone after progression."); return val; } private static bool TypeMatches(string path, string section, string key, string expectedType) { string text = string.Empty; string text2 = string.Empty; foreach (string item in File.ReadLines(path)) { string text3 = item.Trim(); if (text3.StartsWith("[", StringComparison.Ordinal) && text3.EndsWith("]", StringComparison.Ordinal)) { text = text3.Substring(1, text3.Length - 2); text2 = string.Empty; continue; } if (text3.StartsWith("# Setting type:", StringComparison.Ordinal)) { text2 = text3.Substring("# Setting type:".Length).Trim(); continue; } int num = text3.IndexOf('='); if (num >= 0 && !text3.StartsWith("#", StringComparison.Ordinal)) { string text4 = text3.Substring(0, num).Trim(); if (text == section && text4 == key) { string value = text3.Substring(num + 1).Trim(); return text2 == expectedType && ValueMatches(value, expectedType); } text2 = string.Empty; } } return true; } private static bool SchemaMatches(string path) { if (!File.Exists(path)) { return true; } string section = string.Empty; foreach (string item in File.ReadLines(path)) { string text = item.Trim(); if (text.StartsWith("[", StringComparison.Ordinal) && text.EndsWith("]", StringComparison.Ordinal)) { section = text.Substring(1, text.Length - 2); continue; } int num = text.IndexOf('='); if (num >= 0 && !text.StartsWith("#", StringComparison.Ordinal)) { string key = text.Substring(0, num).Trim(); if (!IsKnown(section, key)) { return false; } } } return true; } private static bool IsKnown(string section, string key) { if (!(section == "Version") || !(key == "LibraryVersion")) { if (section == "Map") { switch (key) { case "LayoutOrder": case "DoOrder": case "InfiniteMap": goto IL_0179; } } if (section == "Fields") { switch (key) { case "InfiniteMap: Repeatable": case "InfiniteMap: Chances": case "InfiniteMap: Scale": case "InfiniteMap: Begin Index": case "InfiniteMap: Remove Old": goto IL_0179; } } if (section == "Behaviors") { switch (key) { case "Winnable": case "Peak at end": case "Water follows Beach": goto IL_0179; } } if (!(section == "Prerequisites") || (!(key == "Relocate Plane") && !(key == "Relocate Start"))) { if (section == "Optimizations") { switch (key) { default: return key == "Remove Old"; case "Lazy Generation": case "Lazy Features": case "Fogless": case "No Water": case "No Plane": return true; } } return false; } } goto IL_0179; IL_0179: return true; } private static bool ValueMatches(string value, string expectedType) { if (!(expectedType == typeof(string).Name) && (!(expectedType == typeof(bool).Name) || !bool.TryParse(value, out var _))) { int result2; if (expectedType == typeof(int).Name) { return int.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out result2); } return false; } return true; } } internal static class TerrainRandomizer { [HarmonyPatch(typeof(PropGrouperHelpers), "RunRootPropGrouper")] private static class GenerationPatch { [HarmonyPrefix] private static void Prefix() { Map.SuppressOriginals(); } } [HarmonyPatch(typeof(LightMapBaker), "RunBake")] private static class LightMapPatch { [HarmonyPrefix] private static bool Prefix() { return featureGenerationDepth == 0; } } [HarmonyPatch] private static class LightSamplePatch { private static MethodBase TargetMethod() { return AccessTools.DeclaredMethod(GameLightVolume, "SamplePosition", new Type[1] { typeof(Vector3) }, (Type[])null) ?? throw new MissingMethodException("LightVolume.SamplePosition was not found."); } [HarmonyPrefix] private static void Prefix(ref Vector3 worldPos) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) if (featureGenerationDepth != 0) { worldPos -= featureOffset; } } } [HarmonyPatch(typeof(PropSpawnerHelpers), "AssignMasterClientViewID")] private static class ViewIdPatch { [HarmonyPrefix] private static bool Prefix(GameObject go, ref int __result) { if (roomViewIdDepth == 0 || PhotonNetwork.CurrentRoom == null || !PhotonNetwork.IsMasterClient) { return true; } PhotonView component = go.GetComponent(); if (!Object.op_Implicit((Object)(object)component) || !PhotonNetwork.AllocateRoomViewID(component) || component.ViewID <= 0) { throw new InvalidOperationException("A TerrainRandomiser PhotonView could not receive a room ViewID."); } __result = component.ViewID; return false; } } internal const string PluginGuid = "com.snosz.terrainrandomiser"; internal const string PluginVersion = "1.1.7"; internal const string ViewProperty = "propViews"; private static int featureGenerationDepth; private static int roomViewIdDepth; private static Vector3 featureOffset; private static readonly Type GameLightVolume = typeof(MapHandler).Assembly.GetType("LightVolume") ?? throw new TypeLoadException("PEAK's LightVolume type was not found."); internal static Action GenerateSegmentFeatures { get; } = (Action)Delegate.CreateDelegate(typeof(Action), AccessTools.DeclaredMethod(typeof(PropGrouperHelpers), "RunRootPropGrouper", new Type[1] { typeof(PropGrouper) }, (Type[])null) ?? throw new MissingMethodException("TerrainRandomiser feature generation method was not found.")); internal static void RunSegmentFeatures(PropGrouper grouper, Vector3 offset) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0007: 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) Vector3 val = featureOffset; featureOffset = offset; featureGenerationDepth++; roomViewIdDepth++; try { GenerateSegmentFeatures(grouper); } finally { PropGrouperHelpers.deferredSteps.Clear(); roomViewIdDepth--; featureGenerationDepth--; featureOffset = val; } } internal static List GetAndAssignAllUnassignedViews() { roomViewIdDepth++; try { return MapHandlerHelpers.GetAndAssignAllUnassignedViews(); } finally { roomViewIdDepth--; } } } internal static class ConfigSync { [HarmonyPatch(typeof(AirportCheckInKiosk), "LoadIslandMaster")] private static class PublishPatch { [HarmonyPrefix] private static void Prefix() { if (NetCode.Session.IsHost && !LoadingScreenHandler.loading) { Publish(); } } } private const string PropertyKey = "af.pll.library/c"; internal const string StatePrefix = "af.pll.library/state/"; private static object? publishedRoom; private static string? publishedPayload; private static string? publishedPreviousPayload; internal static string LayoutOrder { get; private set; } = string.Empty; internal static bool DoOrder { get; private set; } internal static bool InfiniteMap { get; private set; } internal static string Repeatable { get; private set; } = string.Empty; internal static string Chances { get; private set; } = string.Empty; internal static int Scale { get; private set; } internal static int BeginIndex { get; private set; } internal static bool RemoveOld { get; private set; } internal static bool Winnable { get; private set; } internal static bool PeakAtEnd { get; private set; } internal static bool WaterFollowsBeach { get; private set; } internal static bool RelocatePlane { get; private set; } internal static bool RelocateStart { get; private set; } internal static bool LazyGeneration { get; private set; } internal static bool LazyFeatures { get; private set; } internal static bool Fogless { get; private set; } internal static bool NoWater { get; private set; } internal static bool NoPlane { get; private set; } internal static bool RemoveOldZones { get; private set; } internal static string GenerationEpoch { get; private set; } = string.Empty; internal static void Publish() { //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Expected O, but got Unknown Room currentRoom = PhotonNetwork.CurrentRoom; if (PhotonNetwork.OfflineMode || currentRoom == null || !PhotonNetwork.IsMasterClient) { return; } LoadLocal(); GenerationEpoch = Guid.NewGuid().ToString("N"); string text = Serialize(); publishedRoom = currentRoom; publishedPayload = text; publishedPreviousPayload = ((RoomInfo)currentRoom).CustomProperties[(object)"af.pll.library/c"] as string; Hashtable val = new Hashtable { [(object)"af.pll.library/c"] = text, [(object)"propViews"] = Array.Empty() }; foreach (object key in ((Dictionary)(object)((RoomInfo)currentRoom).CustomProperties).Keys) { if (key is string text2 && text2.StartsWith("af.pll.library/state/", StringComparison.Ordinal)) { val[key] = Array.Empty(); } } if (currentRoom.SetCustomProperties(val, (Hashtable)null, (WebFlags)null)) { return; } publishedRoom = null; publishedPayload = null; publishedPreviousPayload = null; throw new InvalidOperationException("PLL Library could not publish the room configuration."); } internal static void Resolve() { Room currentRoom = PhotonNetwork.CurrentRoom; if (PhotonNetwork.OfflineMode || currentRoom == null) { LoadLocal(); return; } if (PhotonNetwork.IsMasterClient && publishedRoom == currentRoom && publishedPayload != null) { string text = ((RoomInfo)currentRoom).CustomProperties[(object)"af.pll.library/c"] as string; if (text == publishedPayload || text == publishedPreviousPayload) { return; } publishedRoom = null; publishedPayload = null; publishedPreviousPayload = null; } if (!((Dictionary)(object)((RoomInfo)currentRoom).CustomProperties).TryGetValue((object)"af.pll.library/c", out object value) || !(value is string text2)) { if (PhotonNetwork.IsMasterClient) { Publish(); return; } throw Reject("The host did not publish a PLL Library room configuration."); } int offset = 0; if (!Read(text2, ref offset, out string value2) || !Read(text2, ref offset, out string value3) || !Read(text2, ref offset, out string value4) || !Read(text2, ref offset, out string value5) || !Read(text2, ref offset, out string value6) || !Read(text2, ref offset, out string value7) || !Read(text2, ref offset, out string value8) || !Read(text2, ref offset, out string value9) || !Read(text2, ref offset, out string value10) || !Read(text2, ref offset, out string value11) || !Read(text2, ref offset, out string value12) || !Read(text2, ref offset, out string value13) || !Read(text2, ref offset, out string value14) || !Read(text2, ref offset, out string value15) || !Read(text2, ref offset, out string value16) || !Read(text2, ref offset, out string value17) || !Read(text2, ref offset, out string value18) || !Read(text2, ref offset, out string value19) || !Read(text2, ref offset, out string value20) || !Read(text2, ref offset, out string value21) || !Read(text2, ref offset, out string value22) || offset != text2.Length || (value5 != "0" && value5 != "1") || (value6 != "0" && value6 != "1") || (value11 != "0" && value11 != "1") || (value12 != "0" && value12 != "1") || (value13 != "0" && value13 != "1") || (value14 != "0" && value14 != "1") || (value15 != "0" && value15 != "1") || (value16 != "0" && value16 != "1") || (value17 != "0" && value17 != "1") || (value18 != "0" && value18 != "1") || (value19 != "0" && value19 != "1") || (value20 != "0" && value20 != "1") || (value21 != "0" && value21 != "1") || (value22 != "0" && value22 != "1") || !Guid.TryParseExact(value3, "N", out var _) || !int.TryParse(value9, NumberStyles.None, CultureInfo.InvariantCulture, out var result2) || !int.TryParse(value10, NumberStyles.Integer, CultureInfo.InvariantCulture, out var result3) || result2 < 1 || result2 > 255) { throw Reject("The host published a malformed PLL Library room configuration."); } if (!string.Equals(value2, "1.2.0", StringComparison.Ordinal)) { throw Reject("PLL Library version mismatch: host " + value2 + ", client 1.2.0."); } GenerationEpoch = value3; LayoutOrder = value4; DoOrder = value5 == "1"; InfiniteMap = value6 == "1"; Repeatable = value7; Chances = value8; Scale = result2; BeginIndex = result3; RemoveOld = value11 == "1"; Winnable = value12 == "1"; PeakAtEnd = value13 == "1"; WaterFollowsBeach = value14 == "1"; RelocatePlane = value15 == "1"; RelocateStart = value16 == "1"; LazyGeneration = value17 == "1"; LazyFeatures = value18 == "1"; Fogless = value19 == "1"; NoWater = value20 == "1"; NoPlane = value21 == "1"; RemoveOldZones = value22 == "1"; } private static string Serialize() { StringBuilder stringBuilder = new StringBuilder(); Append(stringBuilder, "1.2.0"); Append(stringBuilder, GenerationEpoch); Append(stringBuilder, LayoutOrder); Append(stringBuilder, DoOrder ? "1" : "0"); Append(stringBuilder, InfiniteMap ? "1" : "0"); Append(stringBuilder, Repeatable); Append(stringBuilder, Chances); Append(stringBuilder, Scale.ToString(CultureInfo.InvariantCulture)); Append(stringBuilder, BeginIndex.ToString(CultureInfo.InvariantCulture)); Append(stringBuilder, RemoveOld ? "1" : "0"); Append(stringBuilder, Winnable ? "1" : "0"); Append(stringBuilder, PeakAtEnd ? "1" : "0"); Append(stringBuilder, WaterFollowsBeach ? "1" : "0"); Append(stringBuilder, RelocatePlane ? "1" : "0"); Append(stringBuilder, RelocateStart ? "1" : "0"); Append(stringBuilder, LazyGeneration ? "1" : "0"); Append(stringBuilder, LazyFeatures ? "1" : "0"); Append(stringBuilder, Fogless ? "1" : "0"); Append(stringBuilder, NoWater ? "1" : "0"); Append(stringBuilder, NoPlane ? "1" : "0"); Append(stringBuilder, RemoveOldZones ? "1" : "0"); return stringBuilder.ToString(); } private static void LoadLocal() { LayoutOrder = FileManager.LayoutOrder.Value; DoOrder = FileManager.DoOrder.Value; InfiniteMap = FileManager.InfiniteMap.Value; Repeatable = FileManager.InfiniteMapRepeatable.Value; Chances = FileManager.InfiniteMapChances.Value; Scale = FileManager.InfiniteMapScale.Value; BeginIndex = FileManager.InfiniteMapBeginIndex.Value; RemoveOld = FileManager.InfiniteMapRemoveOld.Value; Winnable = FileManager.Winnable.Value; PeakAtEnd = FileManager.PeakAtEnd.Value; WaterFollowsBeach = FileManager.WaterFollowsBeach.Value; RelocatePlane = FileManager.RelocatePlane.Value; RelocateStart = FileManager.RelocateStart.Value; LazyGeneration = FileManager.LazyGeneration.Value; LazyFeatures = FileManager.LazyFeatures.Value; Fogless = FileManager.Fogless.Value; NoWater = FileManager.NoWater.Value; NoPlane = FileManager.NoPlane.Value; RemoveOldZones = FileManager.RemoveOld.Value; } private static void Append(StringBuilder result, string value) { result.Append(value.Length.ToString(CultureInfo.InvariantCulture)).Append(':').Append(value); } private static bool Read(string data, ref int offset, out string value) { value = string.Empty; int num = data.IndexOf(':', offset); if (num <= offset || !int.TryParse(data.AsSpan(offset, num - offset), NumberStyles.None, CultureInfo.InvariantCulture, out var result) || result < 0 || result > data.Length - num - 1) { return false; } offset = num + 1; value = data.Substring(offset, result); offset += result; return true; } private static Exception Reject(string message) { PhotonNetwork.Disconnect(); return new InvalidOperationException(message); } internal static void OnMasterClientSwitched() { if (!PhotonNetwork.IsMasterClient) { publishedRoom = null; publishedPayload = null; publishedPreviousPayload = null; } } } internal static class InfiniteMap { private sealed class Choice { internal LayoutOrder.Source Source { get; } internal double Weight { get; } internal Choice(LayoutOrder.Source source, double weight) { Source = source; Weight = weight; } } private sealed class FastRandom { private uint state; internal FastRandom(uint seed) { state = seed; } internal double NextDouble() { uint num = state; num ^= num << 13; num ^= num >> 17; return (double)((state = num ^ (num << 5)) >> 8) * 5.960464477539063E-08; } } internal static List Apply(Dictionary catalog, List layout) { if (!ConfigSync.InfiniteMap) { if (ConfigSync.PeakAtEnd) { LayoutOrder.EnsureTerminalPeak(catalog, layout); } return layout; } List list = CreateChoices(catalog, ConfigSync.Repeatable, ConfigSync.Chances); if (list.Count == 0) { Plugin.PLLLog.LogWarning((object)"InfiniteMap: Repeatable had no valid segments; the default repeatable segments were used."); list = CreateChoices(catalog, "Tropics > Roots > Alpine > Mesa > Caldera", "1 > 1 > 1 > 1 > 1"); } if (list.Count == 0 && !ConfigSync.PeakAtEnd) { return layout; } int num = Math.Max((!ConfigSync.PeakAtEnd) ? 1 : 2, Math.Min(ConfigSync.Scale, 255)); List list2 = (ConfigSync.RemoveOld ? new List(num + 1) : new List(layout)); if (ConfigSync.PeakAtEnd) { LayoutOrder.EnsureTerminalPeak(catalog, list2, num); } else { Trim(list2, num); } if (list.Count == 0) { return list2; } int num2 = InsertionIndex(list2, ConfigSync.BeginIndex, ConfigSync.PeakAtEnd); FastRandom random = new FastRandom(CreateSeed(list)); for (int i = SegmentCount(list2); i < num; i++) { list2.Insert(num2++, Select(list, random)); } return list2; } private static int InsertionIndex(IReadOnlyList layout, int requested, bool terminalPeak) { int num = (terminalPeak ? TerminalGroupStart(layout) : (-1)); if (num < 0) { num = layout.Count; } if (num > 0 && layout[num - 1].Name == "Volcano") { num--; } if (requested == -1) { return num; } requested = Math.Max(0, requested); int num2 = 0; for (int i = 0; i < num; i++) { if (num2 >= requested) { return i; } if (IsGroup(layout, i)) { num2 += 2; i += 2; if (num2 >= requested) { return i + 1; } } else if (!layout[i].IsAttachment) { num2++; } } return num; } private static List CreateChoices(Dictionary catalog, string repeatable, string chances) { string[] array = LayoutOrder.Split(repeatable); string[] array2 = LayoutOrder.Split(chances); double[] array3 = new double[array.Length]; bool flag = array.Length != 0 && array.Length == array2.Length; double num = 0.0; if (flag) { for (int i = 0; i < array2.Length && double.TryParse(array2[i].Trim(), NumberStyles.Float, CultureInfo.InvariantCulture, out array3[i]) && array3[i] >= 0.0 && !double.IsInfinity(array3[i]); i++) { num = Math.Max(num, array3[i]); } flag = num > 0.0; } if (!flag) { Plugin.PLLLog.LogWarning((object)"InfiniteMap: Chances must contain one finite non-negative weight per repeatable segment, with at least one positive value; equal weights were used."); } List list = new List(array.Length); for (int j = 0; j < array.Length; j++) { if (LayoutOrder.TryGet(catalog, array[j], out LayoutOrder.Source source)) { if (source.IsAttachment) { Plugin.PLLLog.LogWarning((object)("Attachment '" + source.Name + "' cannot be repeated and was ignored.")); continue; } if (source.Name.Equals("Volcano", StringComparison.OrdinalIgnoreCase)) { Plugin.PLLLog.LogWarning((object)"Volcano cannot be repeated without its singleton Peak attachment and was ignored."); continue; } if (!Object.op_Implicit((Object)(object)source.SegmentCampfire)) { Plugin.PLLLog.LogWarning((object)("Terminal segment '" + source.Name + "' cannot be repeated and was ignored.")); continue; } double num2 = (flag ? (array3[j] / num) : 1.0); if (num2 > 0.0) { list.Add(new Choice(source, num2)); } } else { Plugin.PLLLog.LogWarning((object)("Unknown repeatable segment '" + array[j].Trim() + "' was ignored.")); } } return list; } private static void Trim(List layout, int target) { if (SegmentCount(layout) <= target) { return; } int num = TerminalGroupStart(layout); if (num >= 0 && target >= 2) { List list = new List(target + 1); int num2 = target - 2; for (int i = 0; i < num; i++) { if (num2 <= 0) { break; } if (IsGroup(layout, i)) { if (num2 < 2) { break; } list.Add(layout[i]); list.Add(layout[i + 1]); list.Add(layout[i + 2]); num2 -= 2; i += 2; } else { LayoutOrder.Source source = layout[i]; if (!source.IsAttachment) { list.Add(source); num2--; } } } list.Add(layout[num]); list.Add(layout[num + 1]); list.Add(layout[num + 2]); layout.Clear(); layout.AddRange(list); NormalizeAttachments(layout); return; } int num3 = 0; int j; for (j = 0; j < layout.Count; j++) { if (num3 >= target) { break; } if (!layout[j].IsAttachment) { num3++; } } if (j > 0 && IsGroup(layout, j - 1)) { j--; } if (j < layout.Count && layout[j].IsAttachment && IsGroup(layout, j - 2)) { j++; } if (j < layout.Count) { layout.RemoveRange(j, layout.Count - j); } NormalizeAttachments(layout); } private static int SegmentCount(IEnumerable layout) { int num = 0; foreach (LayoutOrder.Source item in layout) { if (!item.IsAttachment) { num++; } } return num; } private static int TerminalGroupStart(IReadOnlyList layout) { if (layout.Count < 3 || !layout[layout.Count - 1].IsAttachment || !IsGroup(layout, layout.Count - 3)) { return -1; } return layout.Count - 3; } private static bool IsGroup(IReadOnlyList layout, int index) { if (index >= 0 && index + 2 < layout.Count && layout[index].Name == "Caldera" && layout[index + 1].Name == "Volcano") { return layout[index + 2].IsAttachment; } return false; } private static void NormalizeAttachments(List layout) { for (int i = 0; i < layout.Count; i++) { if (layout[i].IsAttachment && !IsGroup(layout, i - 2)) { layout.RemoveAt(i--); } } } private static LayoutOrder.Source Select(List choices, FastRandom random) { double num = 0.0; foreach (Choice choice in choices) { num += choice.Weight; } double num2 = random.NextDouble() * num; foreach (Choice choice2 in choices) { num2 -= choice2.Weight; if (num2 < 0.0) { return choice2.Source; } } return choices[choices.Count - 1].Source; } private static uint CreateSeed(IEnumerable choices) { LevelGeneration val = Object.FindAnyObjectByType(); int num = Plugin.Instance?.roomMapSettings?.seed ?? (Object.op_Implicit((Object)(object)val) ? val.seed : 0); uint num2 = (uint)(-2128831035 ^ num); foreach (Choice choice in choices) { num2 = Hash(num2, choice.Source.Name.ToUpperInvariant()); num2 = Hash(num2, choice.Weight.ToString("R", CultureInfo.InvariantCulture)); } num2 = (num2 ^ (uint)ConfigSync.Scale) * 16777619; if (num2 != 0) { return num2; } return 2654435769u; } private static uint Hash(uint hash, string value) { foreach (char c in value) { hash = (hash ^ c) * 16777619; } return hash; } } internal static class LayoutOrder { internal sealed class Source { private readonly Vector3? fixedEnd; internal string Name { get; } internal Segment Role { get; } internal BiomeType Biome { get; } internal GameObject SegmentParent { get; } internal GameObject? SegmentCampfire { get; } internal GameObject? WallNext { get; } internal GameObject? WallPrevious { get; } internal Transform? ReconnectSpawnPos { get; } internal DayNightProfile? DayNightProfile { get; } internal Transform Container { get; } internal bool IsAttachment { get; } internal Vector3 Start { get; set; } internal Vector3? BoundaryEnd { get; set; } internal Vector3 End { get { //IL_0072: 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_0062: 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_0045: Unknown result type (might be due to invalid IL or missing references) Vector3? val = fixedEnd; if (!val.HasValue) { Vector3? boundaryEnd = BoundaryEnd; if (!boundaryEnd.HasValue) { if (!Object.op_Implicit((Object)(object)SegmentCampfire)) { if (!Object.op_Implicit((Object)(object)ReconnectSpawnPos)) { return SegmentParent.transform.position; } return ReconnectSpawnPos.position; } return SegmentCampfire.transform.position; } return boundaryEnd.GetValueOrDefault(); } return val.GetValueOrDefault(); } } internal Source(string name, Segment role, MapSegment segment) { //IL_000e: 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_0021: Unknown result type (might be due to invalid IL or missing references) Name = name; Role = role; Biome = RawBiome.Invoke(segment); SegmentParent = RawParent.Invoke(segment); SegmentCampfire = RawCampfire.Invoke(segment); WallNext = segment.wallNext; WallPrevious = segment.wallPrevious; ReconnectSpawnPos = segment.reconnectSpawnPos; DayNightProfile = RawDayNight.Invoke(segment); Container = SegmentParent.transform.parent ?? SegmentParent.transform; } internal Source(Source volcano, Transform peak, Transform reconnect) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001f: 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) Name = "Peak"; Role = (Segment)5; Biome = volcano.Biome; SegmentParent = ((Component)peak).gameObject; SegmentCampfire = null; WallNext = null; WallPrevious = null; ReconnectSpawnPos = reconnect; DayNightProfile = volcano.DayNightProfile; Container = volcano.Container; IsAttachment = true; fixedEnd = peak.position; } } private const string DefaultOrder = "Beach > Tropics > Roots > Alpine > Mesa > Caldera > Volcano > Peak"; private static readonly string[] BaseNames = new string[5] { "Beach", "Tropics", "Alpine", "Caldera", "Volcano" }; internal static readonly FieldRef RawBiome = AccessTools.FieldRefAccess("_biome"); internal static readonly FieldRef RawParent = AccessTools.FieldRefAccess("_segmentParent"); internal static readonly FieldRef RawCampfire = AccessTools.FieldRefAccess("_segmentCampfire"); internal static readonly FieldRef RawDayNight = AccessTools.FieldRefAccess("_dayNightProfile"); internal unsafe static Dictionary CreateCatalog(MapHandler handler) { //IL_008f: 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_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_01a5: 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_01b9: Unknown result type (might be due to invalid IL or missing references) //IL_01be: Unknown result type (might be due to invalid IL or missing references) //IL_01dc: Unknown result type (might be due to invalid IL or missing references) //IL_01e3: Expected I4, but got Unknown //IL_0219: Unknown result type (might be due to invalid IL or missing references) //IL_020f: Unknown result type (might be due to invalid IL or missing references) //IL_0261: Unknown result type (might be due to invalid IL or missing references) Dictionary dictionary = new Dictionary(StringComparer.OrdinalIgnoreCase); Source[] array = new Source[BaseNames.Length]; for (int i = 0; i < Math.Min(handler.segments.Length, BaseNames.Length); i++) { Source source = new Source(BaseNames[i], (Segment)(byte)i, handler.segments[i]); dictionary.Add(source.Name, source); array[i] = source; } MapSegment[] variantSegments = handler.variantSegments; foreach (MapSegment val in variantSegments) { BiomeType val2 = RawBiome.Invoke(val); int num = -1; for (int k = 0; k < handler.segments.Length; k++) { if (handler.segments[k].hasVariant && handler.segments[k].variantBiome == val2) { num = k; break; } } if (num >= 0 && num <= 255) { string text = ((object)(*(BiomeType*)(&val2))/*cast due to .constrained prefix*/).ToString(); if (!dictionary.ContainsKey(text)) { dictionary.Add(text, new Source(text, (Segment)(byte)num, val)); } } } if (!dictionary.TryGetValue("Volcano", out var value) || !Object.op_Implicit((Object)(object)handler.respawnThePeak)) { throw new InvalidOperationException("PEAK's Volcano or Peak attachment was not found."); } dictionary["Peak"] = new Source(value, FindPeak(value.Container), handler.respawnThePeak); Vector3 val3 = ((handler.segments.Length != 0 && Object.op_Implicit((Object)(object)handler.segments[0].reconnectSpawnPos)) ? handler.segments[0].reconnectSpawnPos.position : (Object.op_Implicit((Object)(object)handler.globalParent) ? handler.globalParent.position : ((Component)handler).transform.position)); foreach (Source value2 in dictionary.Values) { int num2 = (int)value2.Role; Source source2 = ((num2 >= 0 && num2 < array.Length) ? array[num2] : null); value2.Start = (Object.op_Implicit((Object)(object)source2?.ReconnectSpawnPos) ? source2.ReconnectSpawnPos.position : val3); Source source3 = ((num2 + 1 < array.Length) ? array[num2 + 1] : null); value2.BoundaryEnd = (Object.op_Implicit((Object)(object)source3?.ReconnectSpawnPos) ? new Vector3?(source3.ReconnectSpawnPos.position) : ((Vector3?)null)); } return dictionary; } internal static List Resolve(Dictionary catalog, string value) { List list = ResolveCore(catalog, value); if (!HasSegments(list)) { list = ResolveCore(catalog, "Beach > Tropics > Roots > Alpine > Mesa > Caldera > Volcano > Peak"); } Limit(list); return list; } internal static string[] Split(string value) { return value.Split(new char[1] { '>' }, StringSplitOptions.RemoveEmptyEntries); } internal static bool TryGet(Dictionary catalog, string value, out Source source) { string text = value.Trim(); if (text.Equals("Shore", StringComparison.OrdinalIgnoreCase)) { text = "Beach"; } else if (text.Equals("Kiln", StringComparison.OrdinalIgnoreCase) || text.Equals("The Kiln", StringComparison.OrdinalIgnoreCase) || text.Equals("TheKiln", StringComparison.OrdinalIgnoreCase)) { text = "Volcano"; } return catalog.TryGetValue(text, out source); } internal static void EnsureTerminalPeak(Dictionary catalog, List layout, int segmentLimit = 255) { if (!catalog.TryGetValue("Caldera", out Source value) || !catalog.TryGetValue("Volcano", out Source value2) || !catalog.TryGetValue("Peak", out Source value3)) { throw new InvalidOperationException("PEAK's Caldera > Volcano > Peak group was not found."); } for (int num = layout.Count - 1; num >= 0; num--) { Source source = layout[num]; if (source.IsAttachment || source.Name.Equals("Caldera", StringComparison.OrdinalIgnoreCase) || source.Name.Equals("Volcano", StringComparison.OrdinalIgnoreCase)) { layout.RemoveAt(num); } } segmentLimit = Math.Max(2, Math.Min(segmentLimit, 255)); int num2 = segmentLimit - 2; for (int i = 0; i < layout.Count; i++) { if (!layout[i].IsAttachment && num2-- <= 0) { layout.RemoveRange(i, layout.Count - i); break; } } layout.Add(value); layout.Add(value2); layout.Add(value3); } private static List ResolveCore(Dictionary catalog, string value) { List list = new List(); Source source = null; Source source2 = null; string[] array = Split(value); foreach (string text in array) { if (!TryGet(catalog, text, out Source source3)) { Plugin.PLLLog.LogWarning((object)("Unknown map segment '" + text.Trim() + "' was ignored.")); source = (source2 = null); } else if (source3.IsAttachment) { if (source?.Name == "Caldera" && source2?.Name == "Volcano") { list.Add(source3); } else { Plugin.PLLLog.LogWarning((object)"Peak was ignored because it must directly follow Caldera > Volcano."); } source = (source2 = null); } else { list.Add(source3); source = source2; source2 = source3; } } return list; } private static Transform FindPeak(Transform container) { Transform val = null; for (int i = 0; i < container.childCount; i++) { Transform child = container.GetChild(i); if (!(((Object)child).name != "Peak")) { if (Object.op_Implicit((Object)(object)val)) { throw new InvalidOperationException("PEAK's Volcano contains more than one Peak attachment."); } val = child; } } if (!Object.op_Implicit((Object)(object)val)) { throw new InvalidOperationException("PEAK's Volcano Peak attachment was not found."); } return val; } private static bool HasSegments(IEnumerable layout) { foreach (Source item in layout) { if (!item.IsAttachment) { return true; } } return false; } private static void Limit(List layout) { int num = 0; for (int i = 0; i < layout.Count; i++) { if (!layout[i].IsAttachment && ++num > 255) { layout.RemoveRange(i, layout.Count - i); break; } } } } internal static class Campfire { [HarmonyPatch(typeof(Campfire), "IsMiniRunEndingCampfire")] private static class MiniRunPatch { [HarmonyPostfix] private static void Postfix(Campfire __instance, ref bool __result) { if (Map.Active && TryGetSlot(__instance, out var _)) { __result = false; } } } [HarmonyPatch(typeof(Campfire), "Light_Rpc")] private static class LightPatch { [HarmonyPrefix] private static void Prefix(Campfire __instance, ref bool updateSegment, out int __state) { __state = -1; if (!updateSegment || !Map.Active) { return; } if (!TryGetSlot(__instance, out var index) || index != Map.Index) { updateSegment = false; return; } Bind(__instance, index); if (Map.IsPeakGate(index) || Map.IsRunTerminal(index)) { updateSegment = false; } __state = index; } [HarmonyPostfix] private static void Postfix(int __state) { if (__state >= 0 && Map.Active) { if (Map.IsRunTerminal(__state)) { Map.OnFinalCampfireLit(__state); } else if (Map.Index == __state + 1) { Map.OnCampfireTransition(__state); Map.ActivateWater(__state + 1); } } } } [HarmonyPatch(typeof(Campfire_Set_Segment), "ModifyObject")] private static class GeneratedCampfirePatch { [HarmonyPostfix] private static void Postfix(GameObject spawned) { if (!Map.Active || !Object.op_Implicit((Object)(object)spawned)) { return; } Campfire[] componentsInChildren = spawned.GetComponentsInChildren(true); foreach (Campfire campfire in componentsInChildren) { if (TryGetSlot(campfire, out var index)) { Bind(campfire, index); } } } } private static readonly Dictionary Slots = new Dictionary(); internal static void Bind() { Slots.Clear(); for (int i = 0; i < Map.Slots.Length; i++) { if (!Map.Slots[i].Released) { GameObject segmentCampfire = Map.Slots[i].Segment.segmentCampfire; if (Object.op_Implicit((Object)(object)segmentCampfire)) { Bind(segmentCampfire, i); } } } for (int j = 0; j < Map.Slots.Length; j++) { if (!Map.Slots[j].Released) { GameObject segmentParent = Map.Slots[j].Segment.segmentParent; if (Object.op_Implicit((Object)(object)segmentParent)) { Bind(segmentParent, j); } } } } internal static void Bind(int index) { if (index >= 0 && index < Map.Slots.Length && !Map.Slots[index].Released) { MapSegment segment = Map.Slots[index].Segment; if (Object.op_Implicit((Object)(object)segment.segmentCampfire)) { Bind(segment.segmentCampfire, index); } if (Object.op_Implicit((Object)(object)segment.segmentParent)) { Bind(segment.segmentParent, index); } } } private static void Bind(GameObject root, int index) { Campfire[] componentsInChildren = root.GetComponentsInChildren(true); foreach (Campfire campfire in componentsInChildren) { Bind(campfire, index); } } private static void Bind(Campfire campfire, int index) { //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) if (!Slots.ContainsKey(campfire)) { Slots.Add(campfire, index); campfire.advanceToSegment = ((index + 1 < Map.Slots.Length) ? Map.Slots[index + 1].Role : Map.Slots[index].Role); } } private static bool TryGetSlot(Campfire campfire, out int index) { if (Slots.TryGetValue(campfire, out index)) { return true; } if (!Map.TryGetSlot(campfire, out index)) { return false; } Bind(campfire, index); return true; } } internal static class Effects { private readonly struct BoundsState { internal Bounds Inner { get; } internal Bounds Outer { get; } internal BoundsState(Bounds inner, Bounds outer) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) Inner = inner; Outer = outer; } } [HarmonyPatch(typeof(MapHandler), "InitializeMap")] private static class MapPatch { [HarmonyPrefix] [HarmonyPriority(801)] private static void Prefix() { CaptureManagers(); } [HarmonyPostfix] [HarmonyPriority(0)] private static void Postfix() { BindManagers(); } } [HarmonyPatch(typeof(FogConfig), "SetFog")] private static class WeatherPatch { [HarmonyPrefix] private static bool Prefix(FogConfig __instance) { if (!Map.Active) { ownedFog = null; return true; } FogConfig val = FogFor(SelectStorm()); if ((Object)(object)val != (Object)(object)__instance) { return false; } ownedFog = __instance; return true; } } [HarmonyPatch(typeof(TerrainSplat), "Start")] private static class TerrainStartPatch { [HarmonyPostfix] private static void Postfix(TerrainSplat __instance) { terrainOwner = __instance; terrainStarted = true; terrainBound = Map.Active; terrainSlots = (Map.Active ? Map.Slots : Array.Empty()); } } [HarmonyPatch(typeof(FogConfig), "Update")] private static class WeatherRestorePatch { [HarmonyPrefix] private static void Prefix() { if (!Map.Active && ownedFog != null) { RestoreWeather(); } } } [HarmonyPatch(typeof(StormVisual), "OnDisable")] private static class WeatherDisablePatch { [HarmonyPostfix] private static void Postfix(StormVisual __instance) { if (Map.Active && !((Object)(object)FogConfig.currentFog != (Object)(object)FogFor(__instance))) { FogConfig.currentFog = null; ownedFog = null; Shader.SetGlobalFloat(WeatherBlend, 0f); } } } [HarmonyPatch(typeof(FogCutoutHandler), "OnEnable")] private static class CutoutEnablePatch { [HarmonyPostfix] private static void Postfix(FogCutoutHandler __instance) { if ((Object)(object)cutoutOwner != (Object)(object)__instance) { CaptureCutouts(__instance); } else if (!Map.Active && !Object.op_Implicit((Object)(object)cutoutRoot)) { capturedCurrentCutout = CurrentCutout.Invoke(__instance); capturedCutoutIndex = __instance.index; } if (Map.Active) { BindCutouts(__instance, force: true); } } } [HarmonyPatch(typeof(FogCutoutHandler), "Update")] private static class CutoutUpdatePatch { [HarmonyPrefix] private static void Prefix(FogCutoutHandler __instance) { BindCutouts(__instance); } } [HarmonyPatch(typeof(SpecialDayManager), "Start")] private static class SpecialStartPatch { [HarmonyPostfix] private static void Postfix(SpecialDayManager __instance) { if ((Object)(object)specialOwner != (Object)(object)__instance) { CaptureSpecialDays(__instance); } if (Map.Active) { BindSpecialDays(__instance, force: true); } } } [HarmonyPatch(typeof(SpecialDayManager), "Update")] private static class SpecialUpdatePatch { [HarmonyPrefix] private static void Prefix(SpecialDayManager __instance) { BindSpecialDays(__instance); } } private static readonly FieldRef StormFog = AccessTools.FieldRefAccess("fogConfig"); private static readonly FieldRef CurrentCutout = AccessTools.FieldRefAccess("currentCutoutZone"); private static readonly Func SelectStorm = (Func)Delegate.CreateDelegate(typeof(Func), AccessTools.DeclaredMethod(typeof(Map), "SelectStorm", (Type[])null, (Type[])null) ?? throw new MissingMethodException("Map.SelectStorm was not found.")); private static readonly int WeatherBlend = Shader.PropertyToID("_WeatherBlend"); private static FogConfig? ownedFog; private static FogCutoutHandler? cutoutOwner; private static FogCutoutZone[] capturedCutouts = Array.Empty(); private static FogCutoutZone? capturedCurrentCutout; private static int capturedCutoutIndex; private static int cutoutRevision = int.MinValue; private static GameObject? cutoutRoot; private static SpecialDayManager? specialOwner; private static SpecialDayZone[] capturedSpecialDays = Array.Empty(); private static SpecialDayZone[] boundSpecialDays = Array.Empty(); private static readonly Dictionary specialBounds = new Dictionary(); private static int specialRevision = int.MinValue; private static TerrainSplat? terrainOwner; private static Map.Slot[] terrainSlots = Array.Empty(); private static bool terrainStarted; private static bool terrainBound; private static FogConfig? FogFor(StormVisual? visual) { if (!Object.op_Implicit((Object)(object)visual)) { return null; } FogConfig val = StormFog.Invoke(visual); if (!Object.op_Implicit((Object)(object)val)) { return ((Component)visual).GetComponentInParent(true); } return val; } private static int Revision() { if (!Map.Active) { return 0; } int num = Map.Slots.Length; Map.Slot[] slots = Map.Slots; foreach (Map.Slot slot in slots) { num = (num * 397) ^ (Object.op_Implicit((Object)(object)slot.Container) ? ((Object)slot.Container).GetInstanceID() : 0); num = (num * 397) ^ (slot.Released ? 1 : 0); num = (num * 397) ^ ((Object.op_Implicit((Object)(object)slot.Container) && ((Component)slot.Container).gameObject.activeInHierarchy) ? 1 : 0); num = (num * 397) ^ (slot.FeaturesActivated ? 1 : 0); num = (num * 397) ^ (slot.Segment.segmentParent.activeInHierarchy ? 1 : 0); num = (num * 397) ^ ((Object.op_Implicit((Object)(object)slot.PeakAttachment) && ((Component)slot.PeakAttachment).gameObject.activeInHierarchy) ? 1 : 0); } return num; } private static void CaptureCutouts(FogCutoutHandler instance) { if (!((Object)(object)cutoutOwner == (Object)(object)instance) || capturedCutouts.Length == 0) { RestoreCutouts(); cutoutOwner = instance; FogCutoutZone[] cutoutZones = instance.cutoutZones; capturedCutouts = ((cutoutZones != null && cutoutZones.Length > 0) ? ((FogCutoutZone[])instance.cutoutZones.Clone()) : Array.Empty()); capturedCurrentCutout = CurrentCutout.Invoke(instance); capturedCutoutIndex = instance.index; cutoutRevision = int.MinValue; } } private static void BindCutouts(FogCutoutHandler instance, bool force = false) { //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Expected O, but got Unknown //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Expected I4, but got Unknown //IL_01af: Unknown result type (might be due to invalid IL or missing references) //IL_014b: Unknown result type (might be due to invalid IL or missing references) //IL_0151: Unknown result type (might be due to invalid IL or missing references) //IL_0156: Unknown result type (might be due to invalid IL or missing references) //IL_01de: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)cutoutOwner != (Object)(object)instance) { CaptureCutouts(instance); } if (!Map.Active) { RestoreCutouts(); return; } int num = Revision(); if ((!force && Object.op_Implicit((Object)(object)cutoutRoot) && cutoutRevision == num) || capturedCutouts.Length == 0) { return; } ((MonoBehaviour)instance).StopAllCoroutines(); if (Object.op_Implicit((Object)(object)cutoutRoot)) { Object.DestroyImmediate((Object)(object)cutoutRoot); } cutoutRoot = new GameObject("PLL_FogCutouts"); cutoutRoot.transform.SetParent(((Component)instance).transform, false); List list = new List(Map.Slots.Length); try { for (int i = 0; i < Map.Slots.Length; i++) { Map.Slot slot = Map.Slots[i]; if (!slot.Released) { int num2 = (int)slot.Role; if (num2 < 0 || num2 >= capturedCutouts.Length || !Object.op_Implicit((Object)(object)capturedCutouts[num2])) { throw new InvalidOperationException("The " + slot.Source.Name + " fog cutout template was not found."); } GameObject val = Object.Instantiate(((Component)capturedCutouts[num2]).gameObject, cutoutRoot.transform, true); ((Object)val).name = $"PLL_FogCutout_{i:D3}_{slot.Source.Name}"; val.transform.position = ((Component)capturedCutouts[num2]).transform.position + slot.Offset; val.SetActive(true); list.Add(val.GetComponent()); } } instance.cutoutZones = list.ToArray(); if (list.Count != 0) { int j = 0; Character localCharacter = Character.localCharacter; if (Object.op_Implicit((Object)(object)localCharacter)) { for (float z = localCharacter.Center.z; j + 1 < list.Count && z > ((Component)list[j]).transform.position.z + list[j].transitionPoint; j++) { } } instance.setFogCutoutZone(j); instance.index = Math.Min(j + 1, list.Count); } else { CurrentCutout.Invoke(instance) = null; } cutoutRevision = num; } catch { if (Object.op_Implicit((Object)(object)cutoutRoot)) { Object.DestroyImmediate((Object)(object)cutoutRoot); } cutoutRoot = null; instance.cutoutZones = capturedCutouts; CurrentCutout.Invoke(instance) = capturedCurrentCutout; instance.index = capturedCutoutIndex; cutoutRevision = int.MinValue; throw; } } private static void RestoreCutouts() { FogCutoutHandler val = cutoutOwner; if (Object.op_Implicit((Object)(object)val) && Object.op_Implicit((Object)(object)cutoutRoot)) { ((MonoBehaviour)val).StopAllCoroutines(); Object.DestroyImmediate((Object)(object)cutoutRoot); val.cutoutZones = capturedCutouts; CurrentCutout.Invoke(val) = capturedCurrentCutout; val.index = capturedCutoutIndex; if (((Behaviour)val).isActiveAndEnabled && Object.op_Implicit((Object)(object)capturedCurrentCutout)) { int num = Array.IndexOf(capturedCutouts, capturedCurrentCutout); if (num >= 0) { val.setFogCutoutZone(num); } val.index = capturedCutoutIndex; } } else if (Object.op_Implicit((Object)(object)cutoutRoot)) { Object.DestroyImmediate((Object)(object)cutoutRoot); } cutoutRoot = null; cutoutRevision = int.MinValue; } private static void CaptureSpecialDays(SpecialDayManager instance) { //IL_0080: 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) if ((Object)(object)specialOwner == (Object)(object)instance && capturedSpecialDays.Length != 0) { return; } SpecialDayZone[] zones = instance.zones; SpecialDayZone[] array = ((zones != null && zones.Length > 0) ? ((SpecialDayZone[])instance.zones.Clone()) : Object.FindObjectsByType((FindObjectsInactive)0, (FindObjectsSortMode)0)); RestoreSpecialDays(); specialOwner = instance; capturedSpecialDays = array; SpecialDayZone[] array2 = capturedSpecialDays; foreach (SpecialDayZone val in array2) { if (Object.op_Implicit((Object)(object)val) && !specialBounds.ContainsKey(val)) { specialBounds.Add(val, new BoundsState(val.bounds, val.outerBounds)); } } specialRevision = int.MinValue; } private static void BindSpecialDays(SpecialDayManager instance, bool force = false) { //IL_00ff: Unknown result type (might be due to invalid IL or missing references) //IL_0104: Unknown result type (might be due to invalid IL or missing references) //IL_010f: Unknown result type (might be due to invalid IL or missing references) //IL_011b: Unknown result type (might be due to invalid IL or missing references) //IL_011d: Unknown result type (might be due to invalid IL or missing references) //IL_0124: Unknown result type (might be due to invalid IL or missing references) //IL_0129: Unknown result type (might be due to invalid IL or missing references) //IL_0134: Unknown result type (might be due to invalid IL or missing references) //IL_0142: Unknown result type (might be due to invalid IL or missing references) //IL_0147: Unknown result type (might be due to invalid IL or missing references) //IL_0153: Unknown result type (might be due to invalid IL or missing references) //IL_0158: Unknown result type (might be due to invalid IL or missing references) //IL_0164: Unknown result type (might be due to invalid IL or missing references) //IL_0166: 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_00ee: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)specialOwner != (Object)(object)instance) { CaptureSpecialDays(instance); } if (!Map.Active) { RestoreSpecialDays(); return; } int num = Revision(); if (!force && specialRevision == num) { return; } List list = new List(); HashSet hashSet = new HashSet(); HashSet hashSet2 = new HashSet(); Map.Slot[] slots = Map.Slots; foreach (Map.Slot slot in slots) { Transform container = slot.Container; if (slot.Released || !Object.op_Implicit((Object)(object)container) || !hashSet.Add(((Object)container).GetInstanceID())) { continue; } SpecialDayZone[] componentsInChildren = ((Component)container).GetComponentsInChildren(true); foreach (SpecialDayZone val in componentsInChildren) { if (Object.op_Implicit((Object)(object)val) && ((Behaviour)val).isActiveAndEnabled && hashSet2.Add(((Object)val).GetInstanceID())) { if (!specialBounds.ContainsKey(val)) { specialBounds.Add(val, new BoundsState(val.bounds, val.outerBounds)); } Bounds bounds = val.bounds; ((Bounds)(ref bounds)).center = ((Component)val).transform.position; val.bounds = bounds; Bounds outerBounds = val.outerBounds; ((Bounds)(ref outerBounds)).center = ((Component)val).transform.position; ((Bounds)(ref outerBounds)).size = ((Bounds)(ref bounds)).size + Vector3.one * val.blendSize; val.outerBounds = outerBounds; list.Add(val); } } } HashSet hashSet3 = new HashSet(); foreach (SpecialDayZone item in list) { hashSet3.Add(((Object)item).GetInstanceID()); } SpecialDayZone[] array = boundSpecialDays; foreach (SpecialDayZone val2 in array) { if (Object.op_Implicit((Object)(object)val2) && !hashSet3.Contains(((Object)val2).GetInstanceID()) && Object.op_Implicit((Object)(object)val2.specialLight)) { ((Behaviour)val2.specialLight).enabled = false; } } boundSpecialDays = list.ToArray(); instance.zones = boundSpecialDays; specialRevision = num; } private static void RestoreSpecialDays() { //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0074: 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_0090: Unknown result type (might be due to invalid IL or missing references) SpecialDayZone[] array = boundSpecialDays; foreach (SpecialDayZone val in array) { if (Object.op_Implicit((Object)(object)val) && Object.op_Implicit((Object)(object)val.specialLight)) { ((Behaviour)val.specialLight).enabled = false; } } foreach (KeyValuePair specialBound in specialBounds) { if (Object.op_Implicit((Object)(object)specialBound.Key)) { specialBound.Key.bounds = specialBound.Value.Inner; specialBound.Key.outerBounds = specialBound.Value.Outer; } } if (Object.op_Implicit((Object)(object)specialOwner)) { specialOwner.zones = capturedSpecialDays; } boundSpecialDays = Array.Empty(); specialBounds.Clear(); specialRevision = int.MinValue; } private static void CaptureManagers() { FogCutoutHandler val = Object.FindAnyObjectByType(); if (Object.op_Implicit((Object)(object)val)) { CaptureCutouts(val); } SpecialDayManager val2 = Object.FindAnyObjectByType(); if (Object.op_Implicit((Object)(object)val2)) { CaptureSpecialDays(val2); } CaptureTerrain(); } private static void CaptureTerrain() { TerrainSplat val = Object.FindAnyObjectByType(); if (Object.op_Implicit((Object)(object)val) && !((Object)(object)terrainOwner == (Object)(object)val)) { terrainOwner = val; terrainSlots = Array.Empty(); terrainStarted = false; terrainBound = false; } } private static void BindTerrain() { if (!Map.Active) { RestoreTerrain(); return; } CaptureTerrain(); if (Object.op_Implicit((Object)(object)terrainOwner) && terrainStarted && terrainSlots != Map.Slots) { terrainOwner.Generate((BrushType)2); terrainSlots = Map.Slots; terrainBound = true; } } internal static void RefreshTerrain() { terrainSlots = Array.Empty(); BindTerrain(); } private static void RestoreTerrain() { if (Object.op_Implicit((Object)(object)terrainOwner) && terrainStarted && terrainBound) { terrainOwner.Generate((BrushType)2); } terrainSlots = Array.Empty(); terrainBound = false; } private static void RestoreWeather() { if (ownedFog != null) { if ((Object)(object)FogConfig.currentFog == (Object)(object)ownedFog || !Object.op_Implicit((Object)(object)FogConfig.currentFog)) { FogConfig.currentFog = null; Shader.SetGlobalFloat(WeatherBlend, 0f); } ownedFog = null; } } private static void BindManagers() { if (!Map.Active) { RestoreWeather(); } BindTerrain(); FogCutoutHandler val = (FogCutoutHandler)(Object.op_Implicit((Object)(object)cutoutOwner) ? ((object)cutoutOwner) : ((object)Object.FindAnyObjectByType())); if (Object.op_Implicit((Object)(object)val)) { BindCutouts(val, force: true); } SpecialDayManager val2 = (SpecialDayManager)(Object.op_Implicit((Object)(object)specialOwner) ? ((object)specialOwner) : ((object)Object.FindAnyObjectByType())); if (Object.op_Implicit((Object)(object)val2)) { BindSpecialDays(val2, force: true); } } } internal static class Fog { [HarmonyPatch(typeof(OrbFogHandler), "Start")] private static class StartPatch { [HarmonyPostfix] private static void Postfix(OrbFogHandler __instance) { Apply(__instance); } } [HarmonyPatch(typeof(OrbFogHandler), "SetFogOrigin")] private static class OriginPatch { [HarmonyPrefix] private static void Prefix(OrbFogHandler __instance) { if ((Object)(object)owner == (Object)(object)__instance && Map.Active) { Origins.Invoke(__instance) = current; } } [HarmonyPostfix] private static void Postfix(OrbFogHandler __instance) { if ((Object)(object)owner == (Object)(object)__instance && Map.Active && ConfigSync.Fogless) { DisableSpheres(__instance); } } } [HarmonyPatch(typeof(OrbFogHandler), "WaitForReveal")] private static class RevealPatch { [HarmonyPostfix] private static void Postfix(OrbFogHandler __instance, ref IEnumerator __result) { __result = FollowReveal(__instance, __result); } } private static readonly FieldRef Origins = AccessTools.FieldRefAccess("origins"); private static readonly FieldRef Sphere = AccessTools.FieldRefAccess("sphere"); private static OrbFogHandler? owner; private static FogSphereOrigin[] captured = Array.Empty(); private static FogSphereOrigin[] current = Array.Empty(); private static GameObject[] spheres = Array.Empty(); private static bool[] sphereStates = Array.Empty(); private static GameObject? root; internal static void Capture() { OrbFogHandler val = Object.FindAnyObjectByType(); if (Object.op_Implicit((Object)(object)val)) { owner = val; FogSphereOrigin[] array = Origins.Invoke(val); captured = ((array != null && array.Length > 0) ? ((FogSphereOrigin[])array.Clone()) : ((Component)((Component)val).transform.root).GetComponentsInChildren()); FogSphere[] componentsInChildren = ((Component)val).GetComponentsInChildren(true); spheres = Array.ConvertAll(componentsInChildren, (FogSphere component) => ((Component)component).gameObject); sphereStates = Array.ConvertAll(spheres, (GameObject sphere) => sphere.activeSelf); } } internal static void Bind(MapHandler _, Map.Slot[] slots) { //IL_0110: Unknown result type (might be due to invalid IL or missing references) //IL_011a: Expected O, but got Unknown //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Expected O, but got Unknown //IL_0155: Unknown result type (might be due to invalid IL or missing references) //IL_015c: Expected O, but got Unknown //IL_022a: Unknown result type (might be due to invalid IL or missing references) //IL_0233: Unknown result type (might be due to invalid IL or missing references) //IL_0238: Unknown result type (might be due to invalid IL or missing references) OrbFogHandler val = (OrbFogHandler)(Object.op_Implicit((Object)(object)owner) ? ((object)owner) : ((object)Object.FindAnyObjectByType())); if (!Object.op_Implicit((Object)(object)val)) { return; } owner = val; if (captured.Length == 0) { Capture(); } if (Object.op_Implicit((Object)(object)root)) { Object.DestroyImmediate((Object)(object)root); } RestoreSpheres(); if (ConfigSync.Fogless) { root = new GameObject("PLL_FoglessWall"); root.transform.SetParent(((Component)val).transform.root, false); root.SetActive(false); current = Array.Empty(); Origins.Invoke(val) = current; foreach (Map.Slot slot in slots) { slot.Segment.wallNext = root; slot.Segment.wallPrevious = root; } if (Object.op_Implicit((Object)(object)Sphere.Invoke(val))) { val.SetFogOrigin(Map.Index); DisableSpheres(val); } return; } root = new GameObject("PLL_FogOrigins"); root.transform.SetParent(((Component)val).transform.root, false); current = (FogSphereOrigin[])(object)new FogSphereOrigin[Math.Max(0, slots.Length - 1)]; if (slots.Length == 1) { GameObject val2 = new GameObject("PLL_WallNext_000"); val2.transform.SetParent(root.transform, false); val2.SetActive(false); slots[0].Segment.wallNext = val2; } GameObject[] array = (GameObject[])(object)new GameObject[current.Length]; GameObject[] array2 = (GameObject[])(object)new GameObject[current.Length]; try { for (int j = 0; j < current.Length; j++) { bool placed; FogSphereOrigin val3 = Template(slots[j], out placed); if (((Component)val3).gameObject.GetComponents().Length != 1) { throw new InvalidOperationException("The " + slots[j].Source.Name + " fog origin is ambiguous."); } GameObject val4 = Object.Instantiate(((Component)val3).gameObject, root.transform, true); ((Object)val4).name = $"PLL_FogOrigin_{j:D3}"; if (!placed) { Transform transform = val4.transform; transform.position += slots[j].Offset; } val4.SetActive(true); current[j] = val4.GetComponent(); array[j] = Unique(val4.transform, "Fogwall_Next"); array2[j] = Unique(val4.transform, "Fogwall_Prev"); } for (int k = 0; k < current.Length; k++) { slots[k].Segment.wallNext = array[k]; slots[k + 1].Segment.wallPrevious = array2[k]; } Origins.Invoke(val) = current; if (Object.op_Implicit((Object)(object)Sphere.Invoke(val))) { val.SetFogOrigin(Map.Index); } } catch { if (Object.op_Implicit((Object)(object)root)) { Object.DestroyImmediate((Object)(object)root); } Origins.Invoke(val) = captured; current = Array.Empty(); root = null; throw; } } private static FogSphereOrigin Template(Map.Slot slot, out bool placed) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Expected I4, but got Unknown FogSphereOrigin val = Ancestor(slot.Segment.wallNext); if (Object.op_Implicit((Object)(object)val)) { placed = true; return val; } int num = (int)slot.Role; if (num >= 0 && num < captured.Length && Object.op_Implicit((Object)(object)captured[num])) { placed = false; return captured[num]; } if (Object.op_Implicit((Object)(object)slot.PeakAttachment) && captured.Length != 0 && Object.op_Implicit((Object)(object)captured[captured.Length - 1])) { placed = false; return captured[captured.Length - 1]; } throw new InvalidOperationException("The " + slot.Source.Name + " fog origin was not found."); } private static FogSphereOrigin? Ancestor(GameObject? wall) { if (!Object.op_Implicit((Object)(object)wall)) { return null; } FogSphereOrigin val = null; Transform val2 = wall.transform; while (Object.op_Implicit((Object)(object)val2)) { FogSphereOrigin[] components = ((Component)val2).GetComponents(); if (components.Length > 1 || (components.Length == 1 && Object.op_Implicit((Object)(object)val))) { throw new InvalidOperationException("The fog origin above " + ((Object)wall).name + " is ambiguous."); } if (components.Length == 1) { val = components[0]; } val2 = val2.parent; } return val; } private static GameObject Unique(Transform hierarchy, string name) { Transform val = null; Transform[] componentsInChildren = ((Component)hierarchy).GetComponentsInChildren(true); foreach (Transform val2 in componentsInChildren) { if (!(((Object)val2).name != name)) { if (Object.op_Implicit((Object)(object)val)) { throw new InvalidOperationException("The fog hierarchy contains more than one " + name + "."); } val = val2; } } if (!Object.op_Implicit((Object)(object)val)) { throw new InvalidOperationException("The fog hierarchy contains no " + name + "."); } return ((Component)val).gameObject; } internal static void Restore() { if (Object.op_Implicit((Object)(object)root)) { Object.DestroyImmediate((Object)(object)root); } if (Object.op_Implicit((Object)(object)owner)) { Origins.Invoke(owner) = captured; } RestoreSpheres(); current = Array.Empty(); root = null; } private static void DisableSpheres(OrbFogHandler instance) { GameObject[] array = spheres; foreach (GameObject val in array) { if (Object.op_Implicit((Object)(object)val) && (Object)(object)val != (Object)(object)((Component)instance).gameObject) { val.SetActive(false); } } } private static void RestoreSpheres() { for (int i = 0; i < spheres.Length; i++) { if (Object.op_Implicit((Object)(object)spheres[i])) { spheres[i].SetActive(sphereStates[i]); } } } private static void Apply(OrbFogHandler instance) { if ((Object)(object)owner != (Object)(object)instance || !Map.Active) { return; } Origins.Invoke(instance) = current; if (ConfigSync.Fogless) { if (Object.op_Implicit((Object)(object)Sphere.Invoke(instance))) { instance.SetFogOrigin(Map.Index); } DisableSpheres(instance); } else if (Object.op_Implicit((Object)(object)Sphere.Invoke(instance))) { instance.SetFogOrigin(Map.Index); } } private static IEnumerator FollowReveal(OrbFogHandler instance, IEnumerator routine) { while (routine.MoveNext()) { yield return routine.Current; } if ((Object)(object)owner == (Object)(object)instance && Map.Active && (int)Map.RoleAt(Map.Index) == 4 && Object.op_Implicit((Object)(object)Sphere.Invoke(instance))) { instance.SetFogOrigin(Map.Index); } } } internal static class Map { private enum ViewBatchState { Absent, Applied, Invalid } private readonly struct StormEntry { internal StormVisual Visual { get; } internal WindChillZone Zone { get; } internal StormEntry(StormVisual visual, WindChillZone zone) { Visual = visual; Zone = zone; } } internal sealed class Slot { internal LayoutOrder.Source Source { get; } internal MapSegment Segment { get; } internal Transform Container { get; } internal Vector3 Offset { get; } internal bool IsClone { get; } internal bool TerrainReady { get; set; } internal bool CampfireReady { get; set; } internal Transform? PeakAttachment { get; set; } internal Transform? PeakRespawn { get; set; } internal bool ViewBatchReady { get; set; } = true; internal bool FeaturesActivated { get; set; } internal bool Released { get; set; } internal Segment Role => Source.Role; internal bool FeaturesReady { get { if (TerrainReady) { return CampfireReady; } return false; } } internal Slot(LayoutOrder.Source source, MapSegment segment, Transform container, Vector3 offset, bool isClone, bool terrainReady, bool campfireReady) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) Source = source; Segment = segment; Container = container; Offset = offset; IsClone = isClone; TerrainReady = terrainReady; CampfireReady = campfireReady; } } private sealed class ViewBatch { internal PhotonView[] Views { get; } internal int PathHash { get; } internal FakeItem[] FakeItems { get; } internal int FakePathHash { get; } internal int Seed { get; } internal ViewBatch(PhotonView[] views, int pathHash, FakeItem[] fakeItems, int fakePathHash, int seed) { Views = views; PathHash = pathHash; FakeItems = fakeItems; FakePathHash = fakePathHash; Seed = seed; } } private sealed class QueuedJump { internal Segment Segment { get; } internal HashSet Players { get; } internal bool SendToEveryone { get; private set; } internal bool UpdateFog { get; private set; } internal QueuedJump(Segment segment, HashSet players, bool sendToEveryone, bool updateFog) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) Segment = segment; Players = new HashSet(players); SendToEveryone = sendToEveryone; UpdateFog = updateFog; } internal void Merge(HashSet players, bool sendToEveryone, bool updateFog) { Players.UnionWith(players); SendToEveryone |= sendToEveryone; UpdateFog |= updateFog; } } private sealed class Placement { internal LayoutOrder.Source[] Sources { get; } internal Transform Container { get; } internal Vector3 Offset { get; } internal int Index { get; } internal bool Reuse { get; set; } internal Slot[] Slots { get; set; } = Array.Empty(); internal Transform? AttachmentRespawn { get; set; } internal Placement(LayoutOrder.Source[] sources, Transform container, Vector3 offset, int index) { //IL_0020: 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) Sources = sources; Container = container; Offset = offset; Index = index; } } private sealed class DetachedPlane { internal Transform Value { get; } private Transform? Parent { get; } private int Sibling { get; } private Vector3 Position { get; } private Quaternion Rotation { get; } private Vector3 LocalScale { get; } private bool Active { get; } internal DetachedPlane(Transform value) { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) Value = value; Parent = value.parent; Sibling = value.GetSiblingIndex(); Position = value.position; Rotation = value.rotation; LocalScale = value.localScale; Active = ((Component)value).gameObject.activeSelf; } internal void Restore() { //IL_0057: 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_006e: Unknown result type (might be due to invalid IL or missing references) if (Object.op_Implicit((Object)(object)Value)) { Value.SetParent(Parent, true); if (Object.op_Implicit((Object)(object)Parent)) { Value.SetSiblingIndex(Math.Min(Sibling, Parent.childCount - 1)); } Value.SetPositionAndRotation(Position, Rotation); Value.localScale = LocalScale; ((Component)Value).gameObject.SetActive(Active); } } } private sealed class EnvironmentState { private readonly Dictionary water = new Dictionary(); private readonly Dictionary wind = new Dictionary(); private readonly Dictionary tracks = new Dictionary(); private readonly Dictionary movement = new Dictionary(); private readonly Dictionary heights = new Dictionary(); internal void TranslateWater(IEnumerable roots, Vector3 offset, bool capture) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) foreach (GameObject root in roots) { if (Object.op_Implicit((Object)(object)root)) { TranslateWater(root, offset, capture); } } } internal void Rebase(GameObject root, Vector3 offset, bool capture) { //IL_0002: 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_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0074: 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_003c: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_0161: Unknown result type (might be due to invalid IL or missing references) //IL_0166: Unknown result type (might be due to invalid IL or missing references) //IL_0171: 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_0189: Unknown result type (might be due to invalid IL or missing references) //IL_014b: Unknown result type (might be due to invalid IL or missing references) //IL_01fd: Unknown result type (might be due to invalid IL or missing references) //IL_0213: Unknown result type (might be due to invalid IL or missing references) TranslateWater(root, offset, capture); WindChillZone[] componentsInChildren = root.GetComponentsInChildren(true); foreach (WindChillZone val in componentsInChildren) { if (capture && !wind.ContainsKey(val)) { wind.Add(val, WindBounds.Invoke(val)); } Bounds val2 = WindBounds.Invoke(val); ((Bounds)(ref val2)).center = ((Component)val).transform.position; WindBounds.Invoke(val) = val2; } PlayerTrackParticles[] componentsInChildren2 = root.GetComponentsInChildren(true); foreach (PlayerTrackParticles val3 in componentsInChildren2) { if (capture && !tracks.ContainsKey(val3)) { tracks.Add(val3, TrackBounds.Invoke(val3)); } Bounds val4 = TrackBounds.Invoke(val3); ((Bounds)(ref val4)).center = ((Component)val3).transform.position; TrackBounds.Invoke(val3) = val4; } PlayerMoveZone[] componentsInChildren3 = root.GetComponentsInChildren(true); foreach (PlayerMoveZone val5 in componentsInChildren3) { if (capture && !movement.ContainsKey(val5)) { movement.Add(val5, MoveBounds.Invoke(val5)); } Bounds val6 = MoveBounds.Invoke(val5); ((Bounds)(ref val6)).center = ((Component)val5).transform.position; MoveBounds.Invoke(val5) = val6; } WindHeightEffect[] componentsInChildren4 = root.GetComponentsInChildren(true); foreach (WindHeightEffect val7 in componentsInChildren4) { if (capture && !heights.ContainsKey(val7)) { heights.Add(val7, (WindFromHeight.Invoke(val7), WindToHeight.Invoke(val7))); } WindFromHeight.Invoke(val7) += offset.y; WindToHeight.Invoke(val7) += offset.y; } } private void TranslateWater(GameObject root, Vector3 offset, bool capture) { //IL_0048: 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_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_006c: 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) //IL_0033: Unknown result type (might be due to invalid IL or missing references) WaterZone[] componentsInChildren = root.GetComponentsInChildren(true); foreach (WaterZone val in componentsInChildren) { if (capture && !water.ContainsKey(val)) { water.Add(val, WaterBounds.Invoke(val)); } Bounds val2 = WaterBounds.Invoke(val); ((Bounds)(ref val2)).center = ((Bounds)(ref val2)).center + offset; WaterBounds.Invoke(val) = val2; } } internal void Restore() { //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: 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_0149: Unknown result type (might be due to invalid IL or missing references) //IL_014e: Unknown result type (might be due to invalid IL or missing references) foreach (KeyValuePair item in water) { if (Object.op_Implicit((Object)(object)item.Key)) { WaterBounds.Invoke(item.Key) = item.Value; } } foreach (KeyValuePair item2 in wind) { if (Object.op_Implicit((Object)(object)item2.Key)) { WindBounds.Invoke(item2.Key) = item2.Value; } } foreach (KeyValuePair track in tracks) { if (Object.op_Implicit((Object)(object)track.Key)) { TrackBounds.Invoke(track.Key) = track.Value; } } foreach (KeyValuePair item3 in movement) { if (Object.op_Implicit((Object)(object)item3.Key)) { MoveBounds.Invoke(item3.Key) = item3.Value; } } foreach (KeyValuePair height in heights) { if (Object.op_Implicit((Object)(object)height.Key)) { WindFromHeight.Invoke(height.Key) = height.Value.Item1; WindToHeight.Invoke(height.Key) = height.Value.Item2; } } } } private sealed class PreparedMap { internal MapHandler Handler { get; } internal Slot[] Slots { get; } internal Dictionary Originals { get; } internal Dictionary Positions { get; } internal HashSet Reused { get; } internal GameObject[] WaterObjects { get; } internal bool[] WaterStates { get; } internal Vector3[] WaterPositions { get; } internal EnvironmentState Environment { get; } internal Transform? TerminalRespawn { get; } internal DetachedPlane? Plane { get; } internal MapSegment[]? OriginalSegments { get; set; } internal List? OriginalBiomes { get; set; } internal Transform? OriginalKilnRespawn { get; set; } internal Transform? OriginalPeakRespawn { get; set; } internal List GeneratedGroupers { get; } = new List(); internal List AddedGroupers { get; } = new List(); internal bool Committed { get; set; } internal PreparedMap(MapHandler handler, Slot[] slots, Dictionary originals, Dictionary positions, HashSet reused, GameObject[] waterObjects, bool[] waterStates, Vector3[] waterPositions, EnvironmentState environment, Transform? terminalRespawn, DetachedPlane? plane) { Handler = handler; Slots = slots; Originals = originals; Positions = positions; Reused = reused; WaterObjects = waterObjects; WaterStates = waterStates; WaterPositions = waterPositions; Environment = environment; TerminalRespawn = terminalRespawn; Plane = plane; } } [HarmonyPatch(typeof(StormVisual), "LateUpdate")] private static class StormVisualUpdatePatch { [HarmonyPostfix] private static void Postfix() { PublishStorm(); } } [HarmonyPatch(typeof(StormVisual), "OnDisable")] private static class StormVisualDisablePatch { [HarmonyPostfix] private static void Postfix(StormVisual __instance) { if (Active) { __instance.observedPlayerInWindZone = false; stormFrame = -1; PublishStorm(); } } } [HarmonyPatch(typeof(DisableIfWindActive), "FixedUpdate")] private static class DisableIfWindActivePatch { [HarmonyPrefix] private static void Prefix(DisableIfWindActive __instance, out RootsWind? __state) { __state = RootsWind.instance; if (Active && disabledWindOwners.TryGetValue(__instance, out RootsWind value) && Object.op_Implicit((Object)(object)value)) { RootsWind.instance = value; } } [HarmonyFinalizer] private static Exception? Finalizer(Exception? __exception, RootsWind? __state) { RootsWind.instance = __state; return __exception; } } [HarmonyPatch(typeof(WindAffectedStatusEmitter), "FixedUpdate")] private static class WindAffectedStatusEmitterPatch { [HarmonyPrefix] private static void Prefix(WindAffectedStatusEmitter __instance, out RootsWind? __state) { __state = RootsWind.instance; if (Active && windEmitterOwners.TryGetValue(__instance, out RootsWind value) && Object.op_Implicit((Object)(object)value)) { RootsWind.instance = value; } } [HarmonyFinalizer] private static Exception? Finalizer(Exception? __exception, RootsWind? __state) { RootsWind.instance = __state; return __exception; } } [HarmonyPatch(typeof(MapHandler), "InitializeMap")] [HarmonyBefore(new string[] { "com.snosz.terrainrandomiser" })] [HarmonyPriority(800)] private static class PreparePatch { [HarmonyPrefix] private static void Prefix() { Prepare(); } [HarmonyFinalizer] private static Exception? Finalizer(Exception? __exception) { if (__exception != null && pending != null) { RollbackPending(); } return __exception; } } [HarmonyPatch(typeof(MapHandler), "InitializeMap")] [HarmonyAfter(new string[] { "com.snosz.terrainrandomiser" })] [HarmonyPriority(0)] private static class CommitPatch { [HarmonyPrefix] private static void Prefix() { Commit(); } [HarmonyPostfix] private static void Postfix() { CompleteCommit(); } } [HarmonyPatch(typeof(MapHandler), "GoToSegment")] private static class TransitionPatch { [HarmonyTranspiler] private static IEnumerable Transpiler(IEnumerable instructions) { //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Expected O, but got Unknown List list = new List(instructions); MethodInfo operand = AccessTools.DeclaredMethod(typeof(Map), "CanTransition", (Type[])null, (Type[])null); for (int i = 0; i < list.Count; i++) { if (!(list[i].opcode != OpCodes.Bgt) || !(list[i].opcode != OpCodes.Bgt_S)) { object operand2 = list[i].operand; list[i].opcode = OpCodes.Call; list[i].operand = operand; list.Insert(i + 1, new CodeInstruction(OpCodes.Brtrue, operand2)); return list; } } throw new MissingMethodException("MapHandler.GoToSegment transition guard was not found."); } } [HarmonyPatch(typeof(MapHandler), "GetCurrentSegment")] private static class CurrentRolePatch { [HarmonyPostfix] private static void Postfix(MapHandler __instance, ref Segment __result) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Expected I4, but got Unknown if ((Object)(object)owner == (Object)(object)__instance) { __result = (Segment)(int)RoleAt(CurrentSegment.Invoke(__instance)); } } } [HarmonyPatch(typeof(MapHandler), "JumpToSegmentLogic")] private static class WaterJumpPatch { [HarmonyPrefix] [HarmonyPriority(800)] private static bool Prefix(Segment __0, HashSet __1, bool __2, bool __3) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Expected I4, but got Unknown //IL_006d: Unknown result type (might be due to invalid IL or missing references) if (replayingJump || !Active || !ConfigSync.LazyGeneration) { return true; } int num = (int)__0; if (num < 0 || num >= Slots.Length) { return true; } GenerateLazySlot(num); if (Slots[num].FeaturesReady && Slots[num].ViewBatchReady) { return true; } if (pendingJumps.TryGetValue(num, out QueuedJump value)) { value.Merge(__1, __2, __3); } else { pendingJumps.Add(num, new QueuedJump(__0, __1, __2, __3)); } return false; } [HarmonyTranspiler] private static IEnumerable Transpiler(IEnumerable instructions) { //IL_0160: Unknown result type (might be due to invalid IL or missing references) //IL_016a: Expected O, but got Unknown List list = new List(instructions); MethodInfo operand = AccessTools.DeclaredMethod(typeof(Map), "UseVanillaPeakAlias", (Type[])null, (Type[])null) ?? throw new MissingMethodException("UseVanillaPeakAlias"); MethodInfo methodInfo = AccessTools.DeclaredMethod(typeof(Map), "IsJumpRole", (Type[])null, (Type[])null) ?? throw new MissingMethodException("IsJumpRole"); bool flag = false; bool flag2 = false; bool flag3 = false; for (int i = 0; i + 2 < list.Count; i++) { if (list[i].opcode != OpCodes.Ldarg_0) { continue; } CodeInstruction val = list[i + 2]; if (!flag && LoadsInt(list[i + 1], 5) && IsNotEqualBranch(val.opcode)) { list[i + 1].opcode = OpCodes.Call; list[i + 1].operand = operand; val.opcode = ((val.opcode == OpCodes.Bne_Un_S) ? OpCodes.Brfalse_S : OpCodes.Brfalse); flag = true; continue; } bool flag4 = !flag2 && LoadsInt(list[i + 1], 4) && IsNotEqualBranch(val.opcode); bool flag5 = !flag3 && LoadsInt(list[i + 1], 5) && IsEqualBranch(val.opcode); if (flag4 || flag5) { list.Insert(i + 2, new CodeInstruction(OpCodes.Call, (object)methodInfo)); val.opcode = ((!flag4) ? ((val.opcode == OpCodes.Beq_S) ? OpCodes.Brtrue_S : OpCodes.Brtrue) : ((val.opcode == OpCodes.Bne_Un_S) ? OpCodes.Brfalse_S : OpCodes.Brfalse)); flag2 = flag2 || flag4; flag3 = flag3 || flag5; i += 2; } } if (!flag || !flag2 || !flag3) { throw new MissingMethodException("MapHandler.JumpToSegmentLogic role guards were not found."); } return list; } [HarmonyPostfix] private static void Postfix() { SyncWater(); ReleaseOldZones(); } } [HarmonyPatch(typeof(OrbFogHandler), "WaitForFogCatchUp")] private static class LazyRevealPatch { [HarmonyPostfix] private static void Postfix(ref IEnumerator __result) { if (Active && ConfigSync.LazyGeneration) { __result = WaitForLazyGeneration(__result, Index); } } } [HarmonyPatch(/*Could not decode attribute arguments.*/)] private static class CampfireSafetyPatch { [HarmonyPrefix] private static bool Prefix(ref bool __result) { if (!Active) { return true; } __result = LastSeenCampfireIsSafe(); return false; } } [HarmonyPatch(/*Could not decode attribute arguments.*/)] private static class PreviousBaseCampPatch { [HarmonyPrefix] private static bool Prefix(ref bool __result) { if (!Active) { return true; } __result = PreviousSegmentIsStillBaseCamp(); return false; } } [HarmonyPatch(/*Could not decode attribute arguments.*/)] private static class PreviousScoutStatuePatch { [HarmonyPrefix] private static bool Prefix(ref RespawnChest __result) { int num = Index - 1; if (!Active || num < 0 || num >= Slots.Length || !Slots[num].Released) { return true; } GameObject val = Slots[num].Segment.segmentCampfire ?? Slots[num].Segment.segmentParent; __result = (Object.op_Implicit((Object)(object)val) ? val.GetComponentInChildren(true) : null); return false; } } [HarmonyPatch(/*Could not decode attribute arguments.*/)] private static class BaseCampSpawnPatch { [HarmonyPrefix] private static bool Prefix(ref Transform __result) { if (!Active) { return true; } if (Index == 0) { if (!ConfigSync.RelocateStart || !Object.op_Implicit((Object)(object)SpawnPoint.LocalSpawnPoint)) { return true; } __result = ((Component)SpawnPoint.LocalSpawnPoint).transform; return false; } int num = Math.Min(Index, Slots.Length - 1); if (num > 0 && Object.op_Implicit((Object)(object)Slots[num].PeakAttachment) && Slots[num - 1].Released && Object.op_Implicit((Object)(object)Slots[num].PeakRespawn)) { __result = Slots[num].PeakRespawn; return false; } Campfire val = (PreviousSegmentIsStillBaseCamp() ? MapHandler.PreviousCampfire : MapHandler.CurrentCampfire); __result = (Object.op_Implicit((Object)(object)val) ? ((Component)val).transform : Slots[num].Segment.reconnectSpawnPos); return false; } } [HarmonyPatch] private static class MiniRunJumpPatch { private static MethodBase TargetMethod() { MethodInfo methodInfo = AccessTools.DeclaredMethod(typeof(RunManager), "JumpToMiniRunBiomeWhenReady", (Type[])null, (Type[])null) ?? throw new MissingMethodException("RunManager.JumpToMiniRunBiomeWhenReady was not found."); return AccessTools.EnumeratorMoveNext((MethodBase)methodInfo) ?? throw new MissingMethodException("RunManager.JumpToMiniRunBiomeWhenReady iterator was not found."); } [HarmonyTranspiler] private static IEnumerable Transpiler(IEnumerable instructions) { MethodInfo original = AccessTools.DeclaredMethod(typeof(RunSettings), "GetValue", new Type[2] { typeof(SETTINGTYPE), typeof(bool) }, (Type[])null); MethodInfo replacement = AccessTools.DeclaredMethod(typeof(Map), "GetMiniRunStart", (Type[])null, (Type[])null); int replaced = 0; foreach (CodeInstruction instruction in instructions) { if (CodeInstructionExtensions.Calls(instruction, original)) { instruction.operand = replacement; replaced++; } yield return instruction; } if (replaced != 1) { throw new MissingMethodException("The mini-run start setting was not found."); } } } [HarmonyPatch(typeof(CharacterSpawner), "RPC_MiniRunPlayerSpawn")] private static class MiniRunSpawnPatch { [HarmonyPrefix] private static bool Prefix(ref Segment __0) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Expected I4, but got Unknown __0 = (Segment)(int)LogicalIndexForRole(__0); return SlotReady((int)__0); } } [HarmonyPatch(typeof(CharacterSpawner), "SpawnHostCharacter")] private static class HostSpawnReadinessPatch { [HarmonyPrefix] private static bool Prefix() { return SlotReady(HostSpawnIndex()); } } [HarmonyPatch] private static class RemoteSpawnReadinessPatch { private static IEnumerable TargetMethods() { yield return AccessTools.DeclaredMethod(typeof(CharacterSpawner), "RPC_ReconnectingPlayerSpawn", (Type[])null, (Type[])null); yield return AccessTools.DeclaredMethod(typeof(CharacterSpawner), "RPC_NewPlayerSpawn", (Type[])null, (Type[])null); } [HarmonyPrefix] private static bool Prefix(Segment __0) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Expected I4, but got Unknown return SlotReady((int)__0); } } [HarmonyPatch] private static class PersistencePatch { private static IEnumerable TargetMethods() { yield return AccessTools.DeclaredMethod(typeof(ReconnectData), "CreateFromCharacter", (Type[])null, (Type[])null) ?? throw new MissingMethodException("ReconnectData.CreateFromCharacter was not found."); Type type = AccessTools.TypeByName("Peak.Quicksave+RunProgress") ?? throw new MissingMemberException("Peak.Quicksave.RunProgress was not found."); yield return AccessTools.DeclaredMethod(type, "Create", (Type[])null, (Type[])null) ?? throw new MissingMethodException("Peak.Quicksave.RunProgress.Create was not found."); } [HarmonyTranspiler] private static IEnumerable Transpiler(IEnumerable instructions) { MethodInfo current = AccessTools.DeclaredMethod(typeof(MapHandler), "GetCurrentSegment", (Type[])null, (Type[])null); MethodInfo logical = AccessTools.DeclaredMethod(typeof(Map), "LogicalSegment", (Type[])null, (Type[])null); bool replaced = false; foreach (CodeInstruction instruction in instructions) { if (CodeInstructionExtensions.Calls(instruction, current)) { instruction.opcode = OpCodes.Call; instruction.operand = logical; replaced = true; } yield return instruction; } if (!replaced) { throw new MissingMethodException("The persisted map segment getter was not found."); } } } [HarmonyPatch(typeof(MountainProgressHandler), "InitProgressPoints")] private static class ProgressPatch { [HarmonyPrefix] private static bool Prefix(MountainProgressHandler __instance) { return InitializeProgress(__instance); } } [HarmonyPatch(typeof(MountainProgressHandler), "CheckProgress")] private static class PeakProgressWinPatch { [HarmonyPostfix] private static void Postfix(MountainProgressHandler __instance) { if (!Active) { return; } foreach (KeyValuePair peakTransition in peakTransitions) { if (!peakTransition.Key.Reached || peakTransition.Value != Index) { continue; } ReleaseCalderaAtPeak(peakTransition.Value); if (IsRunTerminal(peakTransition.Value)) { if (ConfigSync.Winnable && !Ascents.shouldSpawnFlare) { RequestFinishRun(); } } else { RequestPeakTransition(peakTransition.Value); } break; } } } [HarmonyPatch(typeof(Flare), "SetFlareLitRPC")] private static class FinalFlarePatch { [HarmonyPostfix] private static void Postfix(Flare __instance) { if (Active && ConfigSync.Winnable && IsWinningFlare(__instance)) { FinishRun(); } } } [HarmonyPatch(typeof(Flare), "TriggerHelicopter")] private static class HelicopterPatch { [HarmonyPrefix] private static bool Prefix(Flare __instance) { if (!Active) { return true; } if (IsWinningFlare(__instance)) { FinishRun(); return false; } if (ConfigSync.Winnable && IsRunTerminal(Index)) { return Object.op_Implicit((Object)(object)Slots[Index].PeakAttachment); } return false; } } private static readonly FieldRef CurrentSegment = AccessTools.FieldRefAccess("currentSegment"); private static readonly FieldRef> SpawnTrackers = AccessTools.FieldRefAccess>("_spawnTrackers"); private static readonly FieldRef> FakeItems = AccessTools.FieldRefAccess>("allFakeItems"); private static readonly FieldRef FakeData = AccessTools.FieldRefAccess("fakeItemData"); private static readonly FieldRef SceneViewId = AccessTools.FieldRefAccess("sceneViewId"); private static readonly FieldRef ViewId = AccessTools.FieldRefAccess("viewIdField"); private static readonly FieldRef InstantiationId = AccessTools.FieldRefAccess("InstantiationId"); private static readonly FieldRef RemovedFromViewList = AccessTools.FieldRefAccess("removedFromLocalViewList"); private static readonly FieldRef RpcMonoBehaviours = AccessTools.FieldRefAccess("RpcMonoBehaviours"); private static readonly FieldRef ProgressInitialized = AccessTools.FieldRefAccess("_isInitialized"); private static readonly FieldRef> SkippedBiomes = AccessTools.FieldRefAccess>("_skippedBiomes"); private static readonly FieldRef MaxProgress = AccessTools.FieldRefAccess("k__BackingField"); private static readonly StructFieldRef SavedRunBiome = AccessTools.StructFieldRefAccess("biomeReached"); private static readonly FieldRef WaterBounds = AccessTools.FieldRefAccess("zoneBounds"); private static readonly FieldRef WindBounds = AccessTools.FieldRefAccess("windZoneBounds"); private static readonly FieldRef TrackBounds = AccessTools.FieldRefAccess("bounds"); private static readonly FieldRef MoveBounds = AccessTools.FieldRefAccess("zoneBounds"); private static readonly FieldRef WindFromHeight = AccessTools.FieldRefAccess("fromHeight"); private static readonly FieldRef WindToHeight = AccessTools.FieldRefAccess("toHeight"); private static readonly FieldRef StormZone = AccessTools.FieldRefAccess("zone"); private static readonly FieldRef StormWindIntensity = AccessTools.FieldRefAccess("windIntensity"); private static readonly Action EndCharacterGame = (Action)Delegate.CreateDelegate(typeof(Action), AccessTools.DeclaredMethod(typeof(Character), "EndGame", (Type[])null, (Type[])null) ?? throw new MissingMethodException("Character.EndGame was not found.")); private static readonly Action, bool, bool> JumpToSegment = (Action, bool, bool>)Delegate.CreateDelegate(typeof(Action, bool, bool>), AccessTools.DeclaredMethod(typeof(MapHandler), "JumpToSegmentLogic", new Type[4] { typeof(Segment), typeof(HashSet), typeof(bool), typeof(bool) }, (Type[])null) ?? throw new MissingMethodException("MapHandler.JumpToSegmentLogic was not found.")); private static PreparedMap? pending; private static MapHandler? owner; private static MountainProgressHandler? progressOwner; private static ProgressPoint[] progressTemplates = Array.Empty(); private static List? progressSkipped; private static int progressMax; private static bool progressWasInitialized; private static GameObject? progressRoot; private static GameObject? releasedRoot; private static GameObject[] waterObjects = Array.Empty(); private static Vector3[] authoredWaterPositions = Array.Empty(); private static readonly HashSet generatedFeatureRoots = new HashSet(); private static readonly HashSet winningFlareViews = new HashSet(); private static readonly Dictionary peakTransitions = new Dictionary(); private static readonly HashSet requestedPeakTransitions = new HashSet(); private static readonly Dictionary pendingViewBatches = new Dictionary(); private static readonly Dictionary pendingJumps = new Dictionary(); private static readonly Dictionary retiredViews = new Dictionary(); private static readonly Dictionary disabledWindOwners = new Dictionary(); private static readonly Dictionary windEmitterOwners = new Dictionary(); private static readonly int GlobalWind = Shader.PropertyToID("GlobalWind"); private const string PeakRequestKey = "af.pll.library/state/peak/request"; private const string PeakTransitionKey = "af.pll.library/state/peak/transition"; private const string WinRequestKey = "af.pll.library/state/win/request"; private const string WinFlareKey = "af.pll.library/state/win/flares"; private const string ReleasedKey = "af.pll.library/state/released"; private static bool runFinished; private static bool runFinishRequested; private static bool replayingJump; private static bool lazyGenerationAborted; private static bool mapViewBatchReady = true; private static int releasedThrough = -1; private static int pendingReleasedThrough = -1; private static int fakeItemHighWater; private static int layoutRevision; private static StormEntry[] storms = Array.Empty(); private static int stormFrame = -1; private static int selectedStorm = -1; internal static Slot[] Slots { get; private set; } = Array.Empty(); internal static bool Active { get { if (Object.op_Implicit((Object)(object)owner)) { return Slots.Length != 0; } return false; } } internal static int Index { get { if (!Object.op_Implicit((Object)(object)owner)) { return 0; } return CurrentSegment.Invoke(owner); } } internal static bool HasTerminalPeak => EndsAtPeak(Slots); internal static Segment RoleAt(int index) { //IL_0018: Unknown result type (might be due to invalid IL or missing references) if (index < 0 || index >= Slots.Length) { return (Segment)(byte)index; } return Slots[index].Role; } internal static Segment LogicalSegment(MapHandler handler) { return (Segment)(byte)CurrentSegment.Invoke(handler); } internal static void ActivateWater(int index) { //IL_0068: Unknown result type (might be due to invalid IL or missing references) if (Active && !ConfigSync.NoWater && ConfigSync.WaterFollowsBeach && index >= 0 && index < Slots.Length && !Slots[index].Released && !(Slots[index].Source.Name != "Beach") && waterObjects.Length != 0) { MoveWater(waterObjects, authoredWaterPositions, Slots[index].Offset); SetActive(waterObjects, active: true); } } private static void MoveWater(IReadOnlyList values, IReadOnlyList authoredPositions, Vector3 offset) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_005b: 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_006a: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0083: 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) for (int i = 0; i < values.Count; i++) { GameObject val = values[i]; if (Object.op_Implicit((Object)(object)val)) { Vector3 val2 = authoredPositions[i] + offset; Vector3 val3 = val2 - val.transform.position; WaterZone[] componentsInChildren = val.GetComponentsInChildren(true); foreach (WaterZone val4 in componentsInChildren) { Bounds val5 = WaterBounds.Invoke(val4); ((Bounds)(ref val5)).center = ((Bounds)(ref val5)).center + val3; WaterBounds.Invoke(val4) = val5; } val.transform.position = val2; } } } private static void SetActive(IEnumerable values, bool active) { foreach (GameObject value in values) { if (Object.op_Implicit((Object)(object)value)) { value.SetActive(active); } } } private static void BindEnvironment() { List list = new List(); HashSet hashSet = new HashSet(); HashSet hashSet2 = new HashSet(); disabledWindOwners.Clear(); windEmitterOwners.Clear(); Slot[] slots = Slots; foreach (Slot slot in slots) { if (slot.Released) { continue; } Transform container = slot.Container; if (!Object.op_Implicit((Object)(object)container) || !hashSet2.Add(ObjectId((Object)(object)container))) { continue; } StormVisual[] componentsInChildren = ((Component)container).GetComponentsInChildren(true); foreach (StormVisual val in componentsInChildren) { if (Object.op_Implicit((Object)(object)val) && hashSet.Add(ObjectId((Object)(object)val))) { WindChillZone val2 = StormZone.Invoke(val); if (!Object.op_Implicit((Object)(object)val2)) { val2 = ((Component)val).GetComponentInParent(true); } if (Object.op_Implicit((Object)(object)val2)) { list.Add(new StormEntry(val, val2)); } } } RootsWind[] componentsInChildren2 = ((Component)container).GetComponentsInChildren(true); if (componentsInChildren2.Length == 0) { continue; } DisableIfWindActive[] componentsInChildren3 = ((Component)container).GetComponentsInChildren(true); foreach (DisableIfWindActive val3 in componentsInChildren3) { if (Object.op_Implicit((Object)(object)val3)) { disabledWindOwners[val3] = Closest(((Component)val3).transform, componentsInChildren2); } } WindAffectedStatusEmitter[] componentsInChildren4 = ((Component)container).GetComponentsInChildren(true); foreach (WindAffectedStatusEmitter val4 in componentsInChildren4) { if (Object.op_Implicit((Object)(object)val4)) { windEmitterOwners[val4] = Closest(((Component)val4).transform, componentsInChildren2); } } } storms = list.ToArray(); stormFrame = -1; selectedStorm = -1; } private static RootsWind Closest(Transform value, IReadOnlyList roots) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //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_0037: 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) RootsWind val = roots[0]; Vector3 val2 = ((Component)val).transform.position - value.position; float num = ((Vector3)(ref val2)).sqrMagnitude; for (int i = 1; i < roots.Count; i++) { val2 = ((Component)roots[i]).transform.position - value.position; float sqrMagnitude = ((Vector3)(ref val2)).sqrMagnitude; if (!(sqrMagnitude >= num)) { val = roots[i]; num = sqrMagnitude; } } return val; } private static bool ValidStorm(int index) { if (index >= 0 && index < storms.Length && Object.op_Implicit((Object)(object)storms[index].Visual) && ((Behaviour)storms[index].Visual).isActiveAndEnabled && Object.op_Implicit((Object)(object)storms[index].Zone)) { return ((Behaviour)storms[index].Zone).isActiveAndEnabled; } return false; } private static StormVisual? SelectStorm() { //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0088: 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_0091: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //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) if (stormFrame == Time.frameCount) { if (!ValidStorm(selectedStorm)) { return null; } return storms[selectedStorm].Visual; } stormFrame = Time.frameCount; Character observedCharacter = Character.observedCharacter; int num = -1; bool flag = false; float num2 = float.PositiveInfinity; if (Object.op_Implicit((Object)(object)observedCharacter)) { Vector3 center = observedCharacter.Center; for (int i = 0; i < storms.Length; i++) { if (!ValidStorm(i)) { continue; } Bounds val = WindBounds.Invoke(storms[i].Zone); if (((Bounds)(ref val)).Contains(center)) { bool windActive = storms[i].Zone.windActive; Vector3 val2 = ((Bounds)(ref val)).center - center; float sqrMagnitude = ((Vector3)(ref val2)).sqrMagnitude; if (num < 0 || ((!flag || windActive) && (flag != windActive || !(sqrMagnitude >= num2)))) { num = i; flag = windActive; num2 = sqrMagnitude; } } } } if (num >= 0) { selectedStorm = num; } else if (!ValidStorm(selectedStorm)) { selectedStorm = -1; } if (selectedStorm < 0) { return null; } return storms[selectedStorm].Visual; } private static void PublishStorm() { //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_007a: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Invalid comparison between Unknown and I4 //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Invalid comparison between Unknown and I4 //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Invalid comparison between Unknown and I4 //IL_00c7: 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_00d4: Invalid comparison between Unknown and I4 //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Invalid comparison between Unknown and I4 if (!Active) { return; } StormVisual val = SelectStorm(); StormType val2 = (StormType)((!Object.op_Implicit((Object)(object)val)) ? (-1) : ((int)val.stormType)); if (Object.op_Implicit((Object)(object)DayNightManager.instance)) { DayNightManager instance = DayNightManager.instance; bool flag = (((int)val2 == 0 || (int)val2 == 2) ? true : false); instance.rainstormWindFactor = (flag ? val.windFactor : 0f); DayNightManager.instance.snowstormWindFactor = (((int)val2 == 1) ? val.windFactor : 0f); } Shader.SetGlobalFloat(GlobalWind, ((int)val2 == 2) ? StormWindIntensity.Invoke(val) : 0f); Character observedCharacter = Character.observedCharacter; if (!Object.op_Implicit((Object)(object)observedCharacter) || !Object.op_Implicit((Object)(object)val)) { return; } StormAudio stormAudio = observedCharacter.refs.animations.stormAudio; if (Object.op_Implicit((Object)(object)stormAudio)) { if ((int)val2 == 0) { stormAudio.rainVisual = val; } else if ((int)val2 == 1) { stormAudio.stormVisual = val; } else if ((int)val2 == 2) { stormAudio.windVisual = val; } } } private static void ClearEnvironment() { storms = Array.Empty(); stormFrame = -1; selectedStorm = -1; disabledWindOwners.Clear(); windEmitterOwners.Clear(); } internal static bool TryGetSlot(Campfire campfire, out int index) { for (int i = 0; i < Slots.Length; i++) { if (!Slots[i].Released) { GameObject segmentCampfire = Slots[i].Segment.segmentCampfire; GameObject segmentParent = Slots[i].Segment.segmentParent; if ((Object.op_Implicit((Object)(object)segmentCampfire) && ((Object)(object)((Component)campfire).transform == (Object)(object)segmentCampfire.transform || ((Component)campfire).transform.IsChildOf(segmentCampfire.transform))) || (Object.op_Implicit((Object)(object)segmentParent) && ((Object)(object)((Component)campfire).transform == (Object)(object)segmentParent.transform || ((Component)campfire).transform.IsChildOf(segmentParent.transform)))) { index = i; return true; } } } index = -1; return false; } internal static bool IsPeakGate(int index) { if (Active && index >= 0 && index < Slots.Length - 1 && !IsRunTerminal(index)) { return Object.op_Implicit((Object)(object)Slots[index].PeakAttachment); } return false; } internal static bool IsRunTerminal(int index) { if (Active) { return index == RunTerminalIndex(); } return false; } internal static void OnCampfireTransition(int completedIndex) { int num = completedIndex + 1; if (Active && num == Index && num < Slots.Length) { if (ConfigSync.LazyGeneration) { GenerateLazySlot(num); } ReleaseOldZones(); } } internal static void ReleaseOldZones() { if (Active && ConfigSync.RemoveOldZones) { Room currentRoom = PhotonNetwork.CurrentRoom; if (currentRoom != null) { HandleReleasedProperties(((RoomInfo)currentRoom).CustomProperties); } RequestReleasedThrough(Math.Min(Index - 2, Slots.Length - 1)); } } private static void ReleaseCalderaAtPeak(int index) { //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Invalid comparison between Unknown and I4 if (Active && ConfigSync.RemoveOldZones && index > 0 && index < Slots.Length && Object.op_Implicit((Object)(object)Slots[index].PeakAttachment) && Object.op_Implicit((Object)(object)Slots[index].PeakRespawn) && !Slots[index - 1].Released && (int)Slots[index - 1].Role == 3 && Overlaps(Slots[index - 1].Container, Slots[index].Container)) { RequestReleasedThrough(index - 1); } } private static void RequestReleasedThrough(int target) { //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Expected O, but got Unknown if (target < 0 || target >= Slots.Length) { return; } Room currentRoom = PhotonNetwork.CurrentRoom; if (PhotonNetwork.OfflineMode || currentRoom == null) { pendingReleasedThrough = Math.Max(pendingReleasedThrough, target); TryApplyReleasedPrefix(); return; } HandleReleasedProperties(((RoomInfo)currentRoom).CustomProperties); if (target > Math.Max(releasedThrough, pendingReleasedThrough) && PhotonNetwork.IsMasterClient) { if (!currentRoom.SetCustomProperties(new Hashtable { [(object)"af.pll.library/state/released"] = RunValue(target) }, (Hashtable)null, (WebFlags)null)) { Plugin.PLLLog.LogError((object)"The released-zone prefix could not be published."); return; } pendingReleasedThrough = target; TryApplyReleasedPrefix(); } } private static void HandleReleasedProperties(Hashtable properties) { if (!ConfigSync.RemoveOldZones || !((Dictionary)(object)properties).ContainsKey((object)"af.pll.library/state/released") || (properties[(object)"af.pll.library/state/released"] is object[] array && array.Length == 0)) { return; } if (!(properties[(object)"af.pll.library/state/released"] is object[] array2) || array2.Length != 3 || !(array2[0] is string text)) { AbortLazyGeneration(Index, "Released-zone state validation failed"); } else if (!(text != ConfigSync.GenerationEpoch)) { if (!(array2[1] is int num) || num != layoutRevision || !(array2[2] is int num2) || num2 < 0 || num2 >= Slots.Length) { AbortLazyGeneration(Index, "Released-zone state validation failed"); return; } if (num2 < releasedThrough || num2 < pendingReleasedThrough) { Plugin.PLLLog.LogWarning((object)"Ignored a regressive released-zone prefix."); return; } pendingReleasedThrough = num2; TryApplyReleasedPrefix(); } } private static bool TryApplyReleasedPrefix() { if (pendingReleasedThrough <= releasedThrough) { return true; } if (!mapViewBatchReady || Plugin.awaitingViewIDs) { return false; } for (int i = releasedThrough + 1; i <= pendingReleasedThrough; i++) { if (!ValidateReleasedViewBatch(i)) { AbortLazyGeneration(Index, "Released-zone object batch validation failed"); return false; } } bool flag = false; for (int j = releasedThrough + 1; j <= pendingReleasedThrough; j++) { if (!Slots[j].Released && !ReleaseSlot(j, RetainedBaseCampSpawn(j))) { return false; } if (!ReserveReleasedViewBatch(j)) { AbortLazyGeneration(Index, "Released-zone PhotonView retirement failed"); return false; } releasedThrough = j; flag = true; } if (flag) { RefreshReleasedZones(); } return true; } private static bool ValidateReleasedViewBatch(int index) { int[] ids; return TryGetReleasedViewIds(index, out ids); } private static bool ReserveReleasedViewBatch(int index) { if (!TryGetReleasedViewIds(index, out int[] ids)) { return false; } int[] array = ids; foreach (int num in array) { if (retiredViews.TryGetValue(num, out PhotonView value)) { if (!Object.op_Implicit((Object)(object)value) || value.ViewID != num || (Object)(object)PhotonNetwork.GetPhotonView(num) != (Object)(object)value) { return false; } } else if (!Object.op_Implicit((Object)(object)PhotonNetwork.GetPhotonView(num))) { PhotonView val = CreateRetiredView(); val.ViewID = num; if ((Object)(object)PhotonNetwork.GetPhotonView(num) != (Object)(object)val) { return false; } retiredViews.Add(num, val); } } return true; } private static bool TryGetReleasedViewIds(int index, out int[] ids) { ids = Array.Empty(); if (index > 0) { Room currentRoom = PhotonNetwork.CurrentRoom; if (currentRoom != null && ((RoomInfo)currentRoom).CustomProperties[(object)ViewBatchKey(index)] != null) { if (!(((RoomInfo)currentRoom).CustomProperties[(object)ViewBatchKey(index)] is object[] array)) { return false; } if (array.Length == 0) { return true; } if (!(array[0] is string text)) { return false; } if (text != ConfigSync.GenerationEpoch) { return true; } if (array.Length != 9 || !(array[1] is int num) || num != 2 || !(array[2] is int num2) || num2 != layoutRevision || !(array[3] is int num3) || num3 != MapSeed() || !(array[4] is int) || !(array[5] is int[] array2) || !(array[6] is int) || !(array[7] is int[] array3) || !(array[8] is int num4) || num4 < 0) { return false; } HashSet hashSet = new HashSet(); int[] array4 = array2; foreach (int num5 in array4) { if (num5 <= 0 || !hashSet.Add(num5)) { return false; } } hashSet.Clear(); int[] array5 = array3; foreach (int num6 in array5) { if (num6 < 0 || num6 >= num4 || !hashSet.Add(num6)) { return false; } } fakeItemHighWater = Math.Max(fakeItemHighWater, num4); ids = array2; return true; } } return true; } private static Transform? RetainedBaseCampSpawn(int index) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Invalid comparison between Unknown and I4 if (index < 0 || index + 1 >= Slots.Length || (int)Slots[index].Role != 3 || !Object.op_Implicit((Object)(object)Slots[index + 1].PeakAttachment) || !Object.op_Implicit((Object)(object)Slots[index + 1].PeakRespawn) || !Overlaps(Slots[index].Container, Slots[index + 1].Container)) { return null; } return Slots[index + 1].PeakRespawn; } private static bool ReleaseSlot(int index, Transform? retainedSpawn) { if (index < 0 || index >= Slots.Length || Slots[index].Released) { return false; } Slot slot = Slots[index]; GameObject segmentCampfire = slot.Segment.segmentCampfire; Campfire val = ((Object.op_Implicit((Object)(object)retainedSpawn) && Object.op_Implicit((Object)(object)segmentCampfire)) ? segmentCampfire.GetComponentInChildren(true) : null); if (Object.op_Implicit((Object)(object)retainedSpawn) && (!Object.op_Implicit((Object)(object)segmentCampfire) || !Object.op_Implicit((Object)(object)val) || !Object.op_Implicit((Object)(object)segmentCampfire.GetComponentInChildren(true)))) { Plugin.PLLLog.LogError((object)$"Caldera base-camp retention failed for layout position {index + 1}."); return false; } slot.Released = true; slot.TerrainReady = false; slot.CampfireReady = false; slot.ViewBatchReady = false; pendingViewBatches.Remove(index); pendingJumps.Remove(index); requestedPeakTransitions.Remove(index); GameObject segmentParent = slot.Segment.segmentParent; bool flag = false; for (int i = 0; i < Slots.Length; i++) { if (i != index && !Slots[i].Released && Object.op_Implicit((Object)(object)Slots[i].Container) && Object.op_Implicit((Object)(object)slot.Container) && Overlaps(slot.Container, Slots[i].Container)) { flag = true; break; } } ReplaceReleasedSegment(slot, index, retainedSpawn, val); if (!Object.op_Implicit((Object)(object)slot.Container)) { return true; } if (!flag) { ReleaseObject(((Component)slot.Container).gameObject); return true; } if (Object.op_Implicit((Object)(object)segmentParent) && !RequiredByLiveSlot(segmentParent.transform, index)) { ReleaseObject(segmentParent); } if (!Object.op_Implicit((Object)(object)retainedSpawn) && Object.op_Implicit((Object)(object)segmentCampfire) && (!Object.op_Implicit((Object)(object)segmentParent) || !segmentCampfire.transform.IsChildOf(segmentParent.transform)) && !RequiredByLiveSlot(segmentCampfire.transform, index)) { ReleaseObject(segmentCampfire); } return true; } private static void ReplaceReleasedSegment(Slot slot, int index, Transform? retainedSpawn, Campfire? retainedCampfire) { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Expected O, but got Unknown //IL_0049: 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_00a2: 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_00b7: 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_00c7: 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_00de: 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_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Unknown result type (might be due to invalid IL or missing references) GameObject val = ReleasedZones(); Transform reconnectSpawnPos = slot.Segment.reconnectSpawnPos; GameObject val2 = new GameObject($"PLL_Released_{index:D3}"); val2.transform.SetParent(val.transform, false); if (Object.op_Implicit((Object)(object)reconnectSpawnPos)) { val2.transform.SetPositionAndRotation(reconnectSpawnPos.position, reconnectSpawnPos.rotation); } GameObject segmentCampfire = slot.Segment.segmentCampfire; if (Object.op_Implicit((Object)(object)retainedSpawn) && Object.op_Implicit((Object)(object)retainedCampfire) && Object.op_Implicit((Object)(object)segmentCampfire)) { RetireFakeItems(segmentCampfire); segmentCampfire.transform.SetParent(val2.transform, true); segmentCampfire.transform.rotation = retainedSpawn.rotation * Quaternion.Inverse(((Component)retainedCampfire).transform.rotation) * segmentCampfire.transform.rotation; Transform transform = segmentCampfire.transform; transform.position += retainedSpawn.position - ((Component)retainedCampfire).transform.position; } val2.SetActive(false); LayoutOrder.RawParent.Invoke(slot.Segment) = val2; LayoutOrder.RawCampfire.Invoke(slot.Segment) = (Object.op_Implicit((Object)(object)retainedSpawn) ? segmentCampfire : null); slot.Segment.reconnectSpawnPos = (Object.op_Implicit((Object)(object)retainedSpawn) ? ((Component)retainedCampfire).transform : val2.transform); slot.Segment.wallNext = null; slot.Segment.wallPrevious = null; slot.PeakAttachment = null; slot.PeakRespawn = null; } private static GameObject ReleasedZones() { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Expected O, but got Unknown if (Object.op_Implicit((Object)(object)releasedRoot)) { return releasedRoot; } releasedRoot = new GameObject("PLL_ReleasedZones"); releasedRoot.transform.SetParent(Object.op_Implicit((Object)(object)owner) ? ((Component)owner).transform : null, false); releasedRoot.SetActive(false); return releasedRoot; } private static bool RequiredByLiveSlot(Transform root, int released) { for (int i = 0; i < Slots.Length; i++) { if (i != released && !Slots[i].Released) { Slot slot = Slots[i]; if (Contains(root, slot.Segment.segmentParent) || Contains(root, slot.Segment.segmentCampfire) || Contains(root, slot.Segment.reconnectSpawnPos) || Contains(root, slot.Segment.wallNext) || Contains(root, slot.Segment.wallPrevious) || Contains(root, slot.PeakAttachment) || Contains(root, slot.PeakRespawn)) { return true; } } } return false; } private static bool Contains(Transform root, GameObject? value) { if (Object.op_Implicit((Object)(object)value)) { if (!((Object)(object)value.transform == (Object)(object)root)) { return value.transform.IsChildOf(root); } return true; } return false; } private static bool Contains(Transform root, Transform? value) { if (Object.op_Implicit((Object)(object)value)) { if (!((Object)(object)value == (Object)(object)root)) { return value.IsChildOf(root); } return true; } return false; } private static void ReleaseObject(GameObject value) { if (!Object.op_Implicit((Object)(object)value)) { return; } value.SetActive(false); RetireFakeItems(value); RetirePhotonViews(value); if (Object.op_Implicit((Object)(object)owner)) { Transform root = value.transform; SpawnTrackers.Invoke(owner)?.RemoveAll((SpawnedItemTracker tracker) => !Object.op_Implicit((Object)(object)tracker) || (Object)(object)((Component)tracker).transform == (Object)(object)root || ((Component)tracker).transform.IsChildOf(root)); } PropGrouper[] componentsInChildren = value.GetComponentsInChildren(true); foreach (PropGrouper val in componentsInChildren) { if (Object.op_Implicit((Object)(object)val)) { try { val.ClearAll(); } catch (Exception arg) { Plugin.PLLLog.LogError((object)$"Released map feature cleanup failed. {arg}"); } } } Object.Destroy((Object)(object)value); } private static void RetirePhotonViews(GameObject value) { List<(PhotonView, int)> list = new List<(PhotonView, int)>(); HashSet hashSet = new HashSet(); PhotonView[] componentsInChildren = value.GetComponentsInChildren(true); foreach (PhotonView val in componentsInChildren) { if (Object.op_Implicit((Object)(object)val) && val.ViewID > 0) { int viewID = val.ViewID; PhotonView photonView = PhotonNetwork.GetPhotonView(viewID); if (!hashSet.Add(viewID) || retiredViews.ContainsKey(viewID) || (Object.op_Implicit((Object)(object)photonView) && (Object)(object)photonView != (Object)(object)val)) { throw new InvalidOperationException($"PhotonView {viewID} cannot be retired safely."); } list.Add((val, viewID)); } } if (list.Count == 0) { return; } PhotonView[] array = (PhotonView[])(object)new PhotonView[list.Count]; for (int j = 0; j < array.Length; j++) { array[j] = CreateRetiredView(); } for (int k = 0; k < list.Count; k++) { PhotonView item = list[k].Item1; int item2 = list[k].Item2; PhotonView val2 = array[k]; item.ViewID = 0; if (Object.op_Implicit((Object)(object)PhotonNetwork.GetPhotonView(item2))) { throw new InvalidOperationException($"PhotonView {item2} did not unregister during retirement."); } val2.ViewID = item2; if ((Object)(object)PhotonNetwork.GetPhotonView(item2) != (Object)(object)val2) { throw new InvalidOperationException($"PhotonView {item2} did not register its retirement marker."); } retiredViews.Add(item2, val2); } } private static PhotonView CreateRetiredView() { //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) PhotonView val = ReleasedZones().AddComponent(); ((Behaviour)val).enabled = false; SceneViewId.Invoke(val) = 0; InstantiationId.Invoke(val) = 0; val.observableSearch = (ObservableSearch)0; val.Synchronization = (ViewSynchronization)0; val.ObservedComponents = new List(); RpcMonoBehaviours.Invoke(val) = Array.Empty(); return val; } private static void ClearReleasedZones() { foreach (KeyValuePair retiredView in retiredViews) { PhotonView value = retiredView.Value; if (Object.op_Implicit((Object)(object)value)) { PhotonView photonView = PhotonNetwork.GetPhotonView(retiredView.Key); if (!Object.op_Implicit((Object)(object)photonView) || (Object)(object)photonView == (Object)(object)value) { value.ViewID = 0; continue; } ViewId.Invoke(value) = 0; RemovedFromViewList.Invoke(value) = true; } } retiredViews.Clear(); if (Object.op_Implicit((Object)(object)releasedRoot)) { Object.DestroyImmediate((Object)(object)releasedRoot); } releasedRoot = null; } private static void RetireFakeItems(GameObject value) { FakeItemManager instance = FakeItemManager.Instance; if (!Object.op_Implicit((Object)(object)instance) || !Object.op_Implicit((Object)(object)value)) { return; } FakeItem[] componentsInChildren = value.GetComponentsInChildren(true); if (componentsInChildren.Length == 0) { return; } HashSet targets = new HashSet(); FakeItem[] array = componentsInChildren; foreach (FakeItem val in array) { if (Object.op_Implicit((Object)(object)val)) { targets.Add(ObjectId((Object)(object)val)); } } if (targets.Count == 0) { return; } ref List reference = ref FakeItems.Invoke(instance); if (reference == null) { return; } HashSet retired = new HashSet(); reference.RemoveAll(delegate(FakeItem item) { if (!Object.op_Implicit((Object)(object)item)) { return true; } if (!targets.Contains(ObjectId((Object)(object)item))) { return false; } if (item.index >= 0) { retired.Add(item.index); } return true; }); if (retired.Count != 0) { FakeData.Invoke(instance).hiddenItems?.RemoveAll(retired.Contains); } } private static void ResetReleasedState() { releasedThrough = -1; pendingReleasedThrough = -1; mapViewBatchReady = true; fakeItemHighWater = 0; } private static void RefreshReleasedZones() { if (!ConfigSync.NoWater && ConfigSync.WaterFollowsBeach) { bool flag = false; for (int i = 0; i < Slots.Length; i++) { if (!Slots[i].Released && Slots[i].Source.Name == "Beach") { flag = true; break; } } if (!flag) { GameObject[] array = waterObjects; foreach (GameObject value in array) { ReleaseObject(value); } waterObjects = Array.Empty(); authoredWaterPositions = Array.Empty(); } } Campfire.Bind(); BindEnvironment(); Effects.RefreshTerrain(); SyncWater(); PublishStorm(); } internal static void OnFinalCampfireLit(int index) { if (Active && ConfigSync.Winnable && IsRunTerminal(index) && !Object.op_Implicit((Object)(object)Slots[index].PeakAttachment)) { if (!Ascents.shouldSpawnFlare) { RequestFinishRun(); } else { SpawnFinalFlare(index); } } } private static void GenerateLazySlot(int index) { if (index < 0 || index >= Slots.Length || Slots[index].Released) { return; } ActivateLazyFeatures(index); if (Slots[index].FeaturesReady) { if (!Slots[index].ViewBatchReady && pendingViewBatches.ContainsKey(index)) { TryApplyViewBatch(index); } return; } (bool, bool)[] array = new(bool, bool)[Slots.Length]; for (int i = 0; i < Slots.Length; i++) { array[i] = (Slots[i].TerrainReady, Slots[i].CampfireReady); } HashSet hashSet = new HashSet(generatedFeatureRoots); List generatedGroupers = new List(); List addedGroupers = new List(); HashSet fakeItems; HashSet assignedBefore = BeginLazyViewBatch(index, includeMap: false, out fakeItems); bool flag = false; try { Slots[index].ViewBatchReady = false; int num = GenerateFeatures(index, generatedGroupers, addedGroupers); if (num != 0) { Campfire.Bind(index); BindEnvironment(); flag = true; SynchronizeLazyViews(index, assignedBefore, fakeItems); Plugin.PLLLog.LogInfo((object)$"Generated {num} feature roots for layout position {index + 1}."); } else { Slots[index].ViewBatchReady = true; } } catch (Exception exception) { if (flag) { Slots[index].ViewBatchReady = false; AbortLazyGeneration(index, "Lazy feature synchronization failed", exception); return; } ResetGeneratedFeatures(generatedGroupers, addedGroupers); generatedFeatureRoots.Clear(); foreach (int item in hashSet) { generatedFeatureRoots.Add(item); } for (int j = 0; j < Slots.Length; j++) { Slots[j].TerrainReady = array[j].Item1; Slots[j].CampfireReady = array[j].Item2; } Slots[index].ViewBatchReady = false; AbortLazyGeneration(index, "Lazy feature generation failed", exception); } } private static void ActivateLazyFeatures(int index) { if (ConfigSync.LazyGeneration && ConfigSync.LazyFeatures && Slots[index].IsClone && !Slots[index].FeaturesActivated) { Slot slot = Slots[index]; slot.FeaturesActivated = true; slot.Segment.segmentParent.SetActive(true); if (Object.op_Implicit((Object)(object)slot.Segment.segmentCampfire)) { slot.Segment.segmentCampfire.SetActive(true); } if (Object.op_Implicit((Object)(object)slot.PeakAttachment)) { ((Component)slot.PeakAttachment).gameObject.SetActive(true); } ((Component)slot.Container).gameObject.SetActive(true); Physics.SyncTransforms(); Campfire.Bind(index); BindEnvironment(); Effects.RefreshTerrain(); } } private static bool SlotReady(int index) { if (!GameHandler.IsOnIsland) { return true; } if (!MapHandler.ExistsAndInitialized) { return false; } if (!Active) { return true; } Room currentRoom = PhotonNetwork.CurrentRoom; if (currentRoom != null) { HandleReleasedProperties(((RoomInfo)currentRoom).CustomProperties); } if (!TryApplyReleasedPrefix()) { return false; } if (lazyGenerationAborted || index < 0 || index >= Slots.Length || Slots[index].Released) { return false; } if (ConfigSync.LazyGeneration) { Room currentRoom2 = PhotonNetwork.CurrentRoom; if (currentRoom2 != null) { for (int i = 0; i < Slots.Length; i++) { if (i != index && !Slots[i].Released && ((RoomInfo)currentRoom2).CustomProperties[(object)ViewBatchKey(i)] is object[] array && array.Length > 0 && array[0] is string text && !(text != ConfigSync.GenerationEpoch)) { GenerateLazySlot(i); if (!Slots[i].FeaturesReady || !Slots[i].ViewBatchReady) { return false; } } } } GenerateLazySlot(index); } if (!lazyGenerationAborted && !Plugin.awaitingViewIDs) { if (ConfigSync.LazyGeneration) { if (Slots[index].FeaturesReady) { return Slots[index].ViewBatchReady; } return false; } return true; } return false; } private static int HostSpawnIndex() { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) if (!Quicksave.ShouldUseSaveData) { return Index; } RunProgress savedRun = Quicksave.SavedRun; return (int)SavedRunBiome.Invoke(ref savedRun); } private static void AbortLazyGeneration(int index, string message, Exception? exception = null) { if (!lazyGenerationAborted) { lazyGenerationAborted = true; Plugin.PLLLog.LogError((object)$"{message} for layout position {index + 1}; the run was aborted.{((exception == null) ? string.Empty : $" {exception}")}"); if (PhotonNetwork.OfflineMode || PhotonNetwork.CurrentRoom == null) { SceneManager.LoadScene("Title"); } else { PhotonNetwork.Disconnect(); } } } private static void SpawnFinalFlare(int index) { //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Expected O, but got Unknown //IL_00f9: 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_009f: Unknown result type (might be due to invalid IL or missing references) //IL_01c8: Unknown result type (might be due to invalid IL or missing references) //IL_01d4: Unknown result type (might be due to invalid IL or missing references) //IL_01f7: Expected O, but got Unknown if (!PhotonNetwork.IsMasterClient || winningFlareViews.Count != 0) { return; } GameObject segmentCampfire = Slots[index].Segment.segmentCampfire; Campfire val = (Object.op_Implicit((Object)(object)segmentCampfire) ? segmentCampfire.GetComponentInChildren(true) : null); if (!Object.op_Implicit((Object)(object)val)) { Plugin.PLLLog.LogError((object)"The final map zone has no generated campfire for its endgame flare."); return; } EndgameFlareSpawner val2 = null; EndgameFlareSpawner[] array = Resources.FindObjectsOfTypeAll(); foreach (EndgameFlareSpawner val3 in array) { if (Object.op_Implicit((Object)(object)val3) && Object.op_Implicit((Object)(object)((SingleItemSpawner)val3).prefab) && Object.op_Implicit((Object)(object)owner) && !(((Component)val3).gameObject.scene != ((Component)owner).gameObject.scene)) { val2 = val3; break; } } if (!Object.op_Implicit((Object)(object)val2)) { Plugin.PLLLog.LogError((object)"PEAK's endgame flare spawner was not found."); return; } GameObject val4 = new GameObject("PLL_EndgameFlareSpawner"); val4.transform.SetParent(((Component)val).transform, false); val4.transform.localPosition = Vector3.up; EndgameFlareSpawner val5 = val4.AddComponent(); ((SingleItemSpawner)val5).prefab = ((SingleItemSpawner)val2).prefab; ((SingleItemSpawner)val5).isKinematic = true; ((SingleItemSpawner)val5).playersInRoomRequirement = 0; ((SingleItemSpawner)val5).belowAscentRequirement = int.MaxValue; foreach (PhotonView item in ((SingleItemSpawner)val5).TrySpawnItems()) { if (Object.op_Implicit((Object)(object)item) && Object.op_Implicit((Object)(object)((Component)item).GetComponentInChildren(true)) && item.ViewID > 0) { winningFlareViews.Add(item.ViewID); } } Object.Destroy((Object)(object)val4); if (winningFlareViews.Count == 0) { Plugin.PLLLog.LogError((object)"The final endgame flare could not be spawned."); } else if (PhotonNetwork.CurrentRoom != null && !PhotonNetwork.CurrentRoom.SetCustomProperties(new Hashtable { [(object)"af.pll.library/state/win/flares"] = RunValue(new List(winningFlareViews).ToArray()) }, (Hashtable)null, (WebFlags)null)) { Plugin.PLLLog.LogError((object)"The final endgame flare identity could not be published."); } } private static void FinishRun() { if (!runFinished && PhotonNetwork.IsMasterClient && Object.op_Implicit((Object)(object)Character.localCharacter)) { runFinished = true; EndCharacterGame(Character.localCharacter); } } private static void RequestFinishRun() { //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Expected O, but got Unknown if (!runFinished && !runFinishRequested && CanFinishRun(verifyPeakProgress: true)) { if (PhotonNetwork.CurrentRoom == null || PhotonNetwork.IsMasterClient) { FinishRun(); } else if (!PhotonNetwork.CurrentRoom.SetCustomProperties(new Hashtable { [(object)"af.pll.library/state/win/request"] = RunValue(true) }, (Hashtable)null, (WebFlags)null)) { Plugin.PLLLog.LogError((object)"The synchronized run-finish request could not be published."); } else { runFinishRequested = true; } } } private static bool CanFinishRun(bool verifyPeakProgress) { int num = RunTerminalIndex(); if (!Active || !ConfigSync.Winnable || Ascents.shouldSpawnFlare || num < 0 || num >= Slots.Length || Index != num) { return false; } if (!verifyPeakProgress || !Object.op_Implicit((Object)(object)Slots[num].PeakAttachment)) { return true; } foreach (KeyValuePair peakTransition in peakTransitions) { if (peakTransition.Value == num) { return peakTransition.Key.Reached; } } return false; } private static void Prepare() { //IL_082c: Unknown result type (might be due to invalid IL or missing references) //IL_01f7: Unknown result type (might be due to invalid IL or missing references) //IL_0326: Unknown result type (might be due to invalid IL or missing references) //IL_0313: 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_0413: Unknown result type (might be due to invalid IL or missing references) //IL_0417: Unknown result type (might be due to invalid IL or missing references) //IL_041c: Unknown result type (might be due to invalid IL or missing references) //IL_0421: Unknown result type (might be due to invalid IL or missing references) //IL_043c: Unknown result type (might be due to invalid IL or missing references) //IL_0451: Unknown result type (might be due to invalid IL or missing references) //IL_0456: Unknown result type (might be due to invalid IL or missing references) //IL_0458: Unknown result type (might be due to invalid IL or missing references) //IL_045d: Unknown result type (might be due to invalid IL or missing references) //IL_03a9: Unknown result type (might be due to invalid IL or missing references) //IL_03af: 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_03b9: Unknown result type (might be due to invalid IL or missing references) //IL_03c6: Unknown result type (might be due to invalid IL or missing references) //IL_03d8: Unknown result type (might be due to invalid IL or missing references) //IL_03dd: Unknown result type (might be due to invalid IL or missing references) //IL_03df: Unknown result type (might be due to invalid IL or missing references) //IL_03e4: Unknown result type (might be due to invalid IL or missing references) //IL_0594: Unknown result type (might be due to invalid IL or missing references) //IL_061c: Unknown result type (might be due to invalid IL or missing references) //IL_074b: Unknown result type (might be due to invalid IL or missing references) //IL_0758: Unknown result type (might be due to invalid IL or missing references) //IL_075d: Unknown result type (might be due to invalid IL or missing references) //IL_0764: Unknown result type (might be due to invalid IL or missing references) //IL_0769: 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_0789: Unknown result type (might be due to invalid IL or missing references) //IL_079d: Unknown result type (might be due to invalid IL or missing references) //IL_07a3: Unknown result type (might be due to invalid IL or missing references) MapHandler instance = Singleton.Instance; if (!Object.op_Implicit((Object)(object)instance) || (Object)(object)owner == (Object)(object)instance || (Object)(object)pending?.Handler == (Object)(object)instance) { return; } ClearReleasedZones(); ResetReleasedState(); List list = new List(); Dictionary dictionary = new Dictionary(); Dictionary positions = new Dictionary(); HashSet hashSet = new HashSet(); EnvironmentState environmentState = new EnvironmentState(); HashSet hashSet2 = new HashSet(); HashSet hashSet3 = new HashSet(); GameObject[] array = Array.Empty(); bool[] array2 = Array.Empty(); Vector3[] array3 = Array.Empty(); Transform terminalRespawn = null; DetachedPlane detachedPlane = null; try { ConfigSync.Resolve(); if (!ConfigSync.DoOrder && !ConfigSync.InfiniteMap && !ConfigSync.PeakAtEnd && !ConfigSync.LazyGeneration && !ConfigSync.LazyFeatures && !ConfigSync.Fogless && !ConfigSync.NoWater && !ConfigSync.NoPlane && !ConfigSync.RemoveOldZones && !ConfigSync.RelocatePlane && !ConfigSync.RelocateStart && ConfigSync.WaterFollowsBeach && ConfigSync.Winnable) { return; } Plugin instance2 = Plugin.Instance; if (instance2 != null && instance2.roomMapSettings?.enableRandomiser == true) { Plugin.PLLLog.LogWarning((object)"Map layout was skipped because TerrainRandomiser map generation is enabled."); return; } Fog.Capture(); CaptureAuthoredFeatures(instance, hashSet2, hashSet3); Dictionary dictionary2 = LayoutOrder.CreateCatalog(instance); List layout = (ConfigSync.DoOrder ? LayoutOrder.Resolve(dictionary2, ConfigSync.LayoutOrder) : CurrentLayout(dictionary2, instance)); List list2 = InfiniteMap.Apply(dictionary2, layout); if (list2.Count == 0) { return; } ValidatePlan(list2); ValidateMiniRun(list2); array = FindWaterObjects(instance); array2 = Array.ConvertAll(array, (GameObject val7) => val7.activeSelf); array3 = Array.ConvertAll(array, (GameObject val7) => val7.transform.position); environmentState.TranslateWater(array, Vector3.zero, capture: true); foreach (LayoutOrder.Source value2 in dictionary2.Values) { if (!dictionary.ContainsKey(((Component)value2.Container).gameObject)) { dictionary.Add(((Component)value2.Container).gameObject, ((Component)value2.Container).gameObject.activeSelf); } } List catalog = new List(dictionary2.Values); List placements = new List(list2.Count); Transform val = (Object.op_Implicit((Object)(object)instance.globalParent) ? instance.globalParent : ((Component)instance).transform); if ((ConfigSync.NoPlane || (ConfigSync.RelocatePlane && list2[0].Name != "Beach")) && dictionary2.TryGetValue("Beach", out var value)) { detachedPlane = DetachPlane(value, val); if (ConfigSync.NoPlane) { ((Component)detachedPlane.Value).gameObject.SetActive(false); } } Vector3 val2 = (ConfigSync.RelocateStart ? dictionary2["Beach"].Start : list2[0].Start); int num = 0; for (int num2 = 0; num2 < list2.Count; num2++) { if (IsVolcanoGroup(list2, num2)) { LayoutOrder.Source[] array4 = new LayoutOrder.Source[3] { list2[num2], list2[num2 + 1], list2[num2 + 2] }; Transform val3 = SharedContainer(array4, catalog); if (!dictionary.ContainsKey(((Component)val3).gameObject)) { dictionary.Add(((Component)val3).gameObject, ((Component)val3).gameObject.activeSelf); } Vector3 val4 = val2 - array4[0].Start; placements.Add(new Placement(array4, val3, val4, num)); val2 = array4[2].End + val4; num += 2; num2 += 2; } else { LayoutOrder.Source source = list2[num2]; if (source.IsAttachment) { throw new InvalidOperationException("Peak must remain attached to Caldera > Volcano."); } Vector3 val5 = val2 - source.Start; placements.Add(new Placement(new LayoutOrder.Source[1] { source }, source.Container, val5, num++)); val2 = source.End + val5; } } List list3 = new List(placements.Count); for (int num3 = 0; num3 < placements.Count; num3++) { list3.Add(num3); } list3.Sort(delegate(int left, int right) { int num7 = Depth(placements[left].Container).CompareTo(Depth(placements[right].Container)); return (num7 == 0) ? placements[left].Index.CompareTo(placements[right].Index) : num7; }); foreach (int item in list3) { Placement placement = placements[item]; bool flag = false; foreach (Transform item2 in hashSet) { if (Overlaps(placement.Container, item2)) { flag = true; break; } } if (!flag) { placement.Reuse = true; hashSet.Add(placement.Container); } } foreach (Placement item3 in placements) { if (!item3.Reuse) { item3.Slots = Place(item3.Sources, catalog, item3.Index, item3.Offset, item3.Container, val, isClone: true, hashSet2, hashSet3, dictionary, positions, environmentState, out Transform attachmentRespawn); item3.AttachmentRespawn = attachmentRespawn; list.AddRange(item3.Slots); } } foreach (Placement item4 in placements) { if (item4.Reuse) { item4.Slots = Place(item4.Sources, catalog, item4.Index, item4.Offset, item4.Container, val, isClone: false, hashSet2, hashSet3, dictionary, positions, environmentState, out Transform attachmentRespawn2); item4.AttachmentRespawn = attachmentRespawn2; list.AddRange(item4.Slots); } } List list4 = new List(num); foreach (Placement item5 in placements) { list4.AddRange(item5.Slots); if (Object.op_Implicit((Object)(object)item5.AttachmentRespawn)) { terminalRespawn = item5.AttachmentRespawn; } } ValidateTransitions(list4); if (!ConfigSync.NoWater && ConfigSync.WaterFollowsBeach) { ValidateWater(list4); } DeactivateUnusedOriginals(dictionary.Keys, hashSet); if (ConfigSync.NoWater) { GameObject[] array5 = array; foreach (GameObject val6 in array5) { val6.SetActive(false); } } else { LayoutOrder.Source source2 = dictionary2["Beach"]; Vector3 offset = ((!ConfigSync.WaterFollowsBeach) ? (list4[0].Source.Start + list4[0].Offset - source2.Start) : ((list2[0].Name == "Beach") ? list4[0].Offset : Vector3.zero)); MoveWater(array, array3, offset); SetActive(array, !ConfigSync.WaterFollowsBeach || list2[0].Name == "Beach"); } pending = new PreparedMap(instance, list4.ToArray(), dictionary, positions, hashSet, array, array2, array3, environmentState, terminalRespawn, detachedPlane); } catch (Exception arg) { RestoreOriginals(dictionary, positions); detachedPlane?.Restore(); for (int num5 = 0; num5 < array.Length; num5++) { if (Object.op_Implicit((Object)(object)array[num5])) { array[num5].transform.position = array3[num5]; } } for (int num6 = 0; num6 < array.Length; num6++) { if (Object.op_Implicit((Object)(object)array[num6])) { array[num6].SetActive(array2[num6]); } } environmentState.Restore(); Destroy(list); Plugin.PLLLog.LogError((object)$"Map layout preparation failed; PEAK's authored map was preserved. {arg}"); } } private static GameObject[] FindWaterObjects(MapHandler handler) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) GameObject val = null; GameObject val2 = null; GameObject val3 = null; Scene scene = ((Component)handler).gameObject.scene; GameObject[] rootGameObjects = ((Scene)(ref scene)).GetRootGameObjects(); foreach (GameObject val4 in rootGameObjects) { if (((Object)val4).name != "Misc") { continue; } for (int j = 0; j < val4.transform.childCount; j++) { Transform child = val4.transform.GetChild(j); if (((Object)child).name == "Water") { if (Object.op_Implicit((Object)(object)val)) { throw new InvalidOperationException("The PEAK scene contains more than one Misc/Water floor."); } val = ((Component)child).gameObject; } else if (((Object)child).name == "WaterMesh") { if (Object.op_Implicit((Object)(object)val2)) { throw new InvalidOperationException("The PEAK scene contains more than one Misc/WaterMesh object."); } val2 = ((Component)child).gameObject; } else if (((Object)child).name == "WaterZone") { if (Object.op_Implicit((Object)(object)val3)) { throw new InvalidOperationException("The PEAK scene contains more than one Misc/WaterZone object."); } val3 = ((Component)child).gameObject; } } } if (!Object.op_Implicit((Object)(object)val) || val.transform.childCount != 1) { throw new InvalidOperationException("The PEAK Misc/Water floor was not found."); } Transform child2 = val.transform.GetChild(0); if (((Object)child2).name != "Collision" || !Object.op_Implicit((Object)(object)((Component)child2).GetComponent())) { throw new InvalidOperationException("The PEAK Misc/Water/Collision floor was not found."); } if (!Object.op_Implicit((Object)(object)val2) || !Object.op_Implicit((Object)(object)val3)) { throw new InvalidOperationException("The PEAK water mesh or water zone was not found."); } return (GameObject[])(object)new GameObject[3] { val, val2, val3 }; } private static List CurrentLayout(Dictionary catalog, MapHandler handler) { //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Invalid comparison between Unknown and I4 //IL_0088: 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) List list = new List(handler.segments.Length + 1); for (int i = 0; i < handler.segments.Length; i++) { MapSegment val = handler.segments[i]; GameObject segmentParent = val.segmentParent; GameObject segmentCampfire = val.segmentCampfire; BiomeType biome = val.biome; LayoutOrder.Source source = null; foreach (LayoutOrder.Source value2 in catalog.Values) { if (!value2.IsAttachment && (int)value2.Role == i && !((Object)(object)value2.SegmentParent != (Object)(object)segmentParent) && !((Object)(object)value2.SegmentCampfire != (Object)(object)segmentCampfire) && value2.Biome == biome) { source = value2; break; } } list.Add(source ?? throw new InvalidOperationException($"The effective map segment at index {i} did not exactly match PEAK's segment catalog.")); } if (list.Count >= 2 && list[list.Count - 2].Name == "Caldera" && list[list.Count - 1].Name == "Volcano" && catalog.TryGetValue("Peak", out LayoutOrder.Source value)) { list.Add(value); } return list; } private static bool IsVolcanoGroup(IReadOnlyList plan, int index) { if (index + 2 < plan.Count && plan[index].Name == "Caldera" && plan[index + 1].Name == "Volcano" && plan[index + 2].Name == "Peak") { return plan[index + 2].IsAttachment; } return false; } private static void ValidatePlan(IReadOnlyList plan) { for (int i = 0; i < plan.Count; i++) { if (plan[i].IsAttachment && (i < 2 || plan[i - 2].Name != "Caldera" || plan[i - 1].Name != "Volcano")) { throw new InvalidOperationException("Peak must remain attached to Caldera > Volcano."); } if (!(plan[i].Name != "Volcano") && i + 1 < plan.Count && !plan[i + 1].IsAttachment) { throw new InvalidOperationException("A nonterminal Volcano must retain its Peak attachment."); } } } private static void ValidateMiniRun(IReadOnlyList plan) { //IL_0014: 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_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Invalid comparison between Unknown and I4 if (!RunSettings.isMiniRun) { return; } Segment val = (Segment)(byte)RunSettings.GetValue((SETTINGTYPE)10050, false); for (int i = 0; i < plan.Count; i++) { if (!plan[i].IsAttachment && plan[i].Role == val && ((int)val != 3 || IsVolcanoGroup(plan, i))) { return; } } throw new InvalidOperationException($"The map layout does not contain the selected mini-run segment {val}."); } private static Transform SharedContainer(IReadOnlyList group, IEnumerable catalog) { Transform val = group[1].Container; if ((Object)(object)group[0].Container == (Object)(object)val && (Object)(object)group[2].Container == (Object)(object)val && Object.op_Implicit((Object)(object)val.parent)) { val = val.parent; } while (Object.op_Implicit((Object)(object)val) && !ContainsAll(val, group)) { val = val.parent; } if (!Object.op_Implicit((Object)(object)val)) { throw new InvalidOperationException("The Caldera, Volcano, and Peak attachments do not share a container."); } Transform reconnectSpawnPos = group[2].ReconnectSpawnPos; if (reconnectSpawnPos == null || !Object.op_Implicit((Object)(object)reconnectSpawnPos) || !Inside(reconnectSpawnPos, val)) { throw new InvalidOperationException("The coupled Volcano container does not contain PEAK's terminal respawn anchor."); } foreach (LayoutOrder.Source item in catalog) { if (!Selected(group, item) && Inside(item.SegmentParent.transform, val)) { throw new InvalidOperationException("The coupled Volcano container also contains the unrelated " + item.Name + " segment."); } } return val; } private static bool ContainsAll(Transform container, IReadOnlyList sources) { for (int i = 0; i < sources.Count; i++) { LayoutOrder.Source source = sources[i]; if (!Inside(source.SegmentParent.transform, container) || (Object.op_Implicit((Object)(object)source.SegmentCampfire) && !Inside(source.SegmentCampfire.transform, container))) { return false; } } return true; } private static bool Selected(IReadOnlyList sources, LayoutOrder.Source source) { for (int i = 0; i < sources.Count; i++) { if (sources[i] == source) { return true; } } return false; } private static void CaptureAuthoredFeatures(MapHandler handler, HashSet terrain, HashSet campfires) { MapSegment[] segments = handler.segments; foreach (MapSegment val in segments) { GameObject segmentParent = val.segmentParent; if (Object.op_Implicit((Object)(object)segmentParent)) { terrain.Add(ObjectId((Object)(object)segmentParent)); } GameObject segmentCampfire = val.segmentCampfire; if (Object.op_Implicit((Object)(object)segmentCampfire) && Object.op_Implicit((Object)(object)segmentCampfire.GetComponentInChildren(true))) { campfires.Add(ObjectId((Object)(object)segmentCampfire)); } } } private static DetachedPlane DetachPlane(LayoutOrder.Source beach, Transform parent) { Transform val = null; Transform[] componentsInChildren = beach.SegmentParent.GetComponentsInChildren(true); foreach (Transform val2 in componentsInChildren) { if (((Object)val2).name.Equals("crashed plane", StringComparison.OrdinalIgnoreCase)) { if (Object.op_Implicit((Object)(object)val)) { throw new InvalidOperationException("The Beach segment contains more than one crashed plane."); } val = val2; } } if (!Object.op_Implicit((Object)(object)val)) { throw new InvalidOperationException("The Beach crashed plane was not found."); } DetachedPlane result = new DetachedPlane(val); val.SetParent(parent, true); return result; } private static bool Inside(Transform child, Transform root) { if (!((Object)(object)child == (Object)(object)root)) { return child.IsChildOf(root); } return true; } private static bool Overlaps(Transform left, Transform right) { if (!((Object)(object)left == (Object)(object)right) && !left.IsChildOf(right)) { return right.IsChildOf(left); } return true; } private static int ObjectId(Object value) { return value.GetInstanceID(); } private static int Depth(Transform value) { int num = 0; while (Object.op_Implicit((Object)(object)value.parent)) { value = value.parent; num++; } return num; } private static void RememberActive(Dictionary originals, GameObject value) { if (!originals.ContainsKey(value)) { originals.Add(value, value.activeSelf); } } private static void SetPlacedActive(GameObject value, bool active, bool isClone, Dictionary originals) { if (!isClone) { RememberActive(originals, value); } value.SetActive(active); } private static void DeactivateUnusedOriginals(IEnumerable originals, IEnumerable reused) { foreach (GameObject original in originals) { if (!Object.op_Implicit((Object)(object)original)) { continue; } bool flag = false; foreach (Transform item in reused) { if (Object.op_Implicit((Object)(object)item) && Overlaps(original.transform, item)) { flag = true; break; } } if (!flag) { original.SetActive(false); } } } private static void RestoreOriginals(IEnumerable> originals, IEnumerable> positions) { //IL_0027: Unknown result type (might be due to invalid IL or missing references) foreach (KeyValuePair position in positions) { if (Object.op_Implicit((Object)(object)position.Key)) { position.Key.position = position.Value; } } foreach (KeyValuePair original in originals) { if (Object.op_Implicit((Object)(object)original.Key)) { original.Key.SetActive(original.Value); } } } private static void ValidateTransitions(IReadOnlyList slots) { for (int i = 0; i + 1 < slots.Count; i++) { if (!Object.op_Implicit((Object)(object)slots[i].Segment.segmentCampfire)) { throw new InvalidOperationException($"The {slots[i].Source.Name} segment at layout position {i + 1} has no campfire to advance the map."); } } } private static void ValidateWater(IReadOnlyList slots) { for (int i = 1; i < slots.Count; i++) { if (slots[i].Source.Name == "Beach" && !Object.op_Implicit((Object)(object)slots[i - 1].Segment.segmentCampfire)) { throw new InvalidOperationException($"The Beach at layout position {i + 1} has no preceding campfire to activate its water floor."); } } } private static Slot[] Place(IReadOnlyList selected, IEnumerable catalog, int index, Vector3 offset, Transform container, Transform cloneParent, bool isClone, HashSet authoredTerrain, HashSet authoredCampfires, Dictionary originals, Dictionary positions, EnvironmentState environment, out Transform? attachmentRespawn) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_01eb: 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_01ed: Unknown result type (might be due to invalid IL or missing references) //IL_01fa: Unknown result type (might be due to invalid IL or missing references) //IL_03ef: Unknown result type (might be due to invalid IL or missing references) //IL_03f4: 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_0404: Unknown result type (might be due to invalid IL or missing references) //IL_0418: Unknown result type (might be due to invalid IL or missing references) //IL_041f: Unknown result type (might be due to invalid IL or missing references) //IL_0422: Unknown result type (might be due to invalid IL or missing references) //IL_0427: Unknown result type (might be due to invalid IL or missing references) //IL_042c: Unknown result type (might be due to invalid IL or missing references) //IL_0435: Expected O, but got Unknown //IL_0443: Unknown result type (might be due to invalid IL or missing references) //IL_0449: Expected I4, but got Unknown //IL_04cb: Unknown result type (might be due to invalid IL or missing references) attachmentRespawn = null; GameObject gameObject = ((Component)container).gameObject; bool activeSelf = gameObject.activeSelf; Vector3 position = container.position; GameObject val = null; try { if (!isClone) { RememberActive(originals, gameObject); if (!positions.ContainsKey(container)) { positions.Add(container, container.position); } } gameObject.SetActive(false); val = (isClone ? Object.Instantiate(gameObject, cloneParent, true) : gameObject); if (isClone) { string text = selected[0].Name; for (int i = 1; i < selected.Count; i++) { text = text + "_" + selected[i].Name; } ((Object)val).name = $"PLL_{index:D3}_{text}"; } val.SetActive(false); Transform transform = val.transform; if (isClone) { PhotonView[] componentsInChildren = val.GetComponentsInChildren(true); foreach (PhotonView val2 in componentsInChildren) { SceneViewId.Invoke(val2) = 0; ViewId.Invoke(val2) = 0; InstantiationId.Invoke(val2) = 0; RemovedFromViewList.Invoke(val2) = false; } } foreach (LayoutOrder.Source item in catalog) { if (!Selected(selected, item) && Inside(item.SegmentParent.transform, container)) { Transform val3 = Resolve(item.SegmentParent.transform, container, transform); Transform val4 = (Object.op_Implicit((Object)(object)item.SegmentCampfire) ? Resolve(item.SegmentCampfire.transform, container, transform) : null); if (Object.op_Implicit((Object)(object)val3)) { SetPlacedActive(((Component)val3).gameObject, active: false, isClone, originals); } if (Object.op_Implicit((Object)(object)val4)) { SetPlacedActive(((Component)val4).gameObject, active: false, isClone, originals); } } } transform.position = position + offset; environment.Rebase(val, offset, !isClone); int num = 0; for (int k = 0; k < selected.Count; k++) { if (!selected[k].IsAttachment) { num++; } } if (num == 0) { throw new InvalidOperationException("A map attachment cannot be placed without a segment."); } Slot[] array = new Slot[num]; int num2 = 0; Transform val5 = null; for (int l = 0; l < selected.Count; l++) { LayoutOrder.Source source = selected[l]; if (source.IsAttachment) { val5 = Resolve(source.SegmentParent.transform, container, transform); if (!Object.op_Implicit((Object)(object)val5)) { throw new InvalidOperationException("The placed Volcano group is missing its Peak attachment."); } attachmentRespawn = (Object.op_Implicit((Object)(object)source.ReconnectSpawnPos) ? Resolve(source.ReconnectSpawnPos, container, transform) : null); if (!Object.op_Implicit((Object)(object)attachmentRespawn)) { throw new InvalidOperationException("The placed Volcano group is missing PEAK's respawn anchor."); } continue; } Transform val6 = Resolve(source.SegmentParent.transform, container, transform) ?? throw new InvalidOperationException("The " + source.Name + " segment parent is outside its authored container."); Transform val7 = (Object.op_Implicit((Object)(object)source.SegmentCampfire) ? Resolve(source.SegmentCampfire.transform, container, transform) : null); if (Object.op_Implicit((Object)(object)source.SegmentCampfire) && !Object.op_Implicit((Object)(object)val7)) { throw new InvalidOperationException("The " + source.Name + " campfire is outside its authored container."); } object obj; if (!Object.op_Implicit((Object)(object)source.WallNext)) { obj = null; } else { Transform? obj2 = Resolve(source.WallNext.transform, container, transform); obj = ((obj2 != null) ? ((Component)obj2).gameObject : null); } GameObject wallNext = (GameObject)obj; object obj3; if (!Object.op_Implicit((Object)(object)source.WallPrevious)) { obj3 = null; } else { Transform? obj4 = Resolve(source.WallPrevious.transform, container, transform); obj3 = ((obj4 != null) ? ((Component)obj4).gameObject : null); } GameObject wallPrevious = (GameObject)obj3; Transform val8 = (Object.op_Implicit((Object)(object)source.ReconnectSpawnPos) ? Resolve(source.ReconnectSpawnPos, container, transform) : null); MapSegment val9 = new MapSegment { wallNext = wallNext, wallPrevious = wallPrevious, reconnectSpawnPos = (val8 ?? val7 ?? val6), hasVariant = false, variantBiome = source.Biome, isVariant = false }; LayoutOrder.RawBiome.Invoke(val9) = (BiomeType)(int)source.Biome; LayoutOrder.RawParent.Invoke(val9) = ((Component)val6).gameObject; LayoutOrder.RawCampfire.Invoke(val9) = (Object.op_Implicit((Object)(object)val7) ? ((Component)val7).gameObject : null); LayoutOrder.RawDayNight.Invoke(val9) = source.DayNightProfile; SetPlacedActive(((Component)val6).gameObject, active: true, isClone, originals); if (Object.op_Implicit((Object)(object)val7)) { SetPlacedActive(((Component)val7).gameObject, active: true, isClone, originals); } array[num2++] = new Slot(source, val9, transform, offset, isClone, !isClone && authoredTerrain.Contains(ObjectId((Object)(object)((Component)val6).gameObject)), !Object.op_Implicit((Object)(object)val7) || (!isClone && authoredCampfires.Contains(ObjectId((Object)(object)((Component)val7).gameObject)))); } if (Object.op_Implicit((Object)(object)val5)) { array[^1].PeakAttachment = val5; array[^1].PeakRespawn = attachmentRespawn; } if (isClone && ConfigSync.LazyGeneration && ConfigSync.LazyFeatures) { for (int m = ((index == 0) ? 1 : 0); m < array.Length; m++) { array[m].Segment.segmentParent.SetActive(false); if (Object.op_Implicit((Object)(object)array[m].Segment.segmentCampfire)) { array[m].Segment.segmentCampfire.SetActive(false); } if (Object.op_Implicit((Object)(object)array[m].PeakAttachment)) { ((Component)array[m].PeakAttachment).gameObject.SetActive(false); } } } if (!isClone || !ConfigSync.LazyGeneration || !ConfigSync.LazyFeatures || index == 0) { SetPlacedActive(val, active: true, isClone, originals); } return array; } catch { if (isClone && Object.op_Implicit((Object)(object)val)) { Object.DestroyImmediate((Object)(object)val); } throw; } finally { if (isClone && Object.op_Implicit((Object)(object)gameObject)) { gameObject.SetActive(activeSelf); } } } private static Transform? Resolve(Transform original, Transform originalRoot, Transform cloneRoot) { List list = new List(); Transform val = original; while ((Object)(object)val != (Object)(object)originalRoot) { if (!Object.op_Implicit((Object)(object)val.parent)) { return null; } list.Add(val.GetSiblingIndex()); val = val.parent; } val = cloneRoot; for (int num = list.Count - 1; num >= 0; num--) { if (list[num] >= val.childCount) { return null; } val = val.GetChild(list[num]); } return val; } private static void Commit() { //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Invalid comparison between Unknown and I4 //IL_011c: Unknown result type (might be due to invalid IL or missing references) PreparedMap preparedMap = pending; if (preparedMap == null) { return; } if (!Object.op_Implicit((Object)(object)preparedMap.Handler)) { DiscardPending(); return; } MapHandler handler = preparedMap.Handler; preparedMap.OriginalSegments = handler.segments; preparedMap.OriginalBiomes = new List(handler.biomes); preparedMap.OriginalKilnRespawn = handler.respawnTheKiln; preparedMap.OriginalPeakRespawn = handler.respawnThePeak; preparedMap.Committed = true; try { handler.segments = Array.ConvertAll(preparedMap.Slots, (Slot slot4) => slot4.Segment); if (Object.op_Implicit((Object)(object)preparedMap.TerminalRespawn)) { handler.respawnTheKiln = (handler.respawnThePeak = preparedMap.TerminalRespawn); } else if ((int)preparedMap.Slots[preparedMap.Slots.Length - 1].Role == 4) { handler.respawnTheKiln = preparedMap.Slots[preparedMap.Slots.Length - 1].Segment.reconnectSpawnPos; } handler.biomes.Clear(); Slot[] slots = preparedMap.Slots; foreach (Slot slot in slots) { handler.biomes.Add(slot.Source.Biome); } DeactivateUnusedOriginals(preparedMap.Originals.Keys, preparedMap.Reused); bool flag = ConfigSync.LazyGeneration && ConfigSync.LazyFeatures; HashSet hashSet = new HashSet(); if (flag) { Transform container = preparedMap.Slots[0].Container; Slot[] slots2 = preparedMap.Slots; foreach (Slot slot2 in slots2) { if (Object.op_Implicit((Object)(object)slot2.Container) && Object.op_Implicit((Object)(object)container) && Overlaps(slot2.Container, container)) { hashSet.Add(ObjectId((Object)(object)slot2.Container)); } } } for (int num3 = 0; num3 < preparedMap.Slots.Length; num3++) { Slot slot3 = preparedMap.Slots[num3]; if (flag && slot3.IsClone && !hashSet.Contains(ObjectId((Object)(object)slot3.Container))) { ((Component)slot3.Container).gameObject.SetActive(false); continue; } ((Component)slot3.Container).gameObject.SetActive(true); if (flag && slot3.IsClone && num3 != 0) { slot3.Segment.segmentParent.SetActive(false); if (Object.op_Implicit((Object)(object)slot3.Segment.segmentCampfire)) { slot3.Segment.segmentCampfire.SetActive(false); } if (Object.op_Implicit((Object)(object)slot3.PeakAttachment)) { ((Component)slot3.PeakAttachment).gameObject.SetActive(false); } } else { slot3.Segment.segmentParent.SetActive(true); if (Object.op_Implicit((Object)(object)slot3.Segment.segmentCampfire)) { slot3.Segment.segmentCampfire.SetActive(true); } slot3.FeaturesActivated = true; } } owner = handler; Slots = preparedMap.Slots; waterObjects = preparedMap.WaterObjects; authoredWaterPositions = preparedMap.WaterPositions; generatedFeatureRoots.Clear(); winningFlareViews.Clear(); peakTransitions.Clear(); requestedPeakTransitions.Clear(); pendingViewBatches.Clear(); pendingJumps.Clear(); runFinished = false; runFinishRequested = false; lazyGenerationAborted = false; fakeItemHighWater = 0; layoutRevision = LayoutRevision(Slots); mapViewBatchReady = false; if (!Object.op_Implicit((Object)(object)((Component)handler).GetComponent())) { ((Component)handler).gameObject.AddComponent(); } Room currentRoom = PhotonNetwork.CurrentRoom; if (currentRoom != null) { HandleReleasedProperties(((RoomInfo)currentRoom).CustomProperties); } HashSet hashSet2 = null; HashSet fakeItems = null; if (ConfigSync.LazyGeneration) { Slots[0].ViewBatchReady = false; FakeItemManager.Instance.RefreshList(); hashSet2 = BeginLazyViewBatch(0, includeMap: true, out fakeItems); } else { BeginViewBatch(); } int num4 = (ConfigSync.LazyGeneration ? GenerateFeatures(0, preparedMap.GeneratedGroupers, preparedMap.AddedGroupers) : GenerateFeatures(0, Slots.Length, preparedMap.GeneratedGroupers, preparedMap.AddedGroupers)); SyncWater(); Campfire.Bind(); BindEnvironment(); Fog.Bind(handler, Slots); MountainProgressHandler val = Object.FindAnyObjectByType(); if (Object.op_Implicit((Object)(object)val)) { InitializeProgress(val); } if (hashSet2 == null) { SynchronizeViews(); mapViewBatchReady = true; TryApplyReleasedPrefix(); } else { SynchronizeLazyViews(0, hashSet2, fakeItems, includeMap: true); } if (PhotonNetwork.CurrentRoom != null) { HandlePeakProperties(((RoomInfo)PhotonNetwork.CurrentRoom).CustomProperties); } Plugin.PLLLog.LogInfo((object)((num4 == 0) ? $"Built a {Slots.Length}-segment map layout." : $"Built a {Slots.Length}-segment map layout and generated {num4} feature roots.")); } catch (Exception ex) { bool flag2 = PhotonNetwork.CurrentRoom != null && !PhotonNetwork.OfflineMode; if (!flag2) { Plugin.PLLLog.LogError((object)$"Map layout commit failed. {ex}"); } RollbackPending(); if (flag2) { AbortLazyGeneration(0, "Map layout synchronization failed", ex); } } } private static int GenerateFeatures(int index, List generatedGroupers, List addedGroupers) { return GenerateFeatures(index, 1, generatedGroupers, addedGroupers); } private static int GenerateFeatures(int start, int count, List generatedGroupers, List addedGroupers) { //IL_0212: 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) LevelGeneration val = Object.FindAnyObjectByType(); int seed = Plugin.Instance?.roomMapSettings?.seed ?? (Object.op_Implicit((Object)(object)val) ? val.seed : 0); State state = Random.state; int num = 0; try { int num2 = Math.Min(start + count, Slots.Length); for (int i = Math.Max(0, start); i < num2; i++) { Slot slot = Slots[i]; List<(Collider, bool)> list = new List<(Collider, bool)>(); HashSet hashSet = new HashSet(); HashSet hashSet2 = new HashSet(); try { for (int j = i + 1; j < Slots.Length; j++) { Transform container = Slots[j].Container; if (!Object.op_Implicit((Object)(object)container) || Overlaps(slot.Container, container) || !hashSet.Add(ObjectId((Object)(object)container))) { continue; } Collider[] componentsInChildren = ((Component)container).GetComponentsInChildren(true); foreach (Collider val2 in componentsInChildren) { if (Object.op_Implicit((Object)(object)val2) && hashSet2.Add(ObjectId((Object)(object)val2))) { list.Add((val2, val2.enabled)); if (val2.enabled) { val2.enabled = false; } } } } Physics.SyncTransforms(); num += GenerateRoot(slot, i, slot.Segment.segmentParent, terrain: true, seed, generatedGroupers, addedGroupers); num += GenerateRoot(slot, i, slot.Segment.segmentCampfire, terrain: false, seed, generatedGroupers, addedGroupers); } finally { for (int num3 = list.Count - 1; num3 >= 0; num3--) { (Collider, bool) tuple = list[num3]; if (Object.op_Implicit((Object)(object)tuple.Item1) && tuple.Item1.enabled != tuple.Item2) { tuple.Item1.enabled = tuple.Item2; } } Physics.SyncTransforms(); } } return num; } finally { Random.state = state; } } private static int GenerateRoot(Slot slot, int index, GameObject? root, bool terrain, int seed, List generatedGroupers, List addedGroupers) { //IL_00bb: Unknown result type (might be due to invalid IL or missing references) if (terrain ? slot.TerrainReady : slot.CampfireReady) { return 0; } if (!Object.op_Implicit((Object)(object)root)) { SetRootReady(root, terrain); return 0; } int item = ObjectId((Object)(object)root); if (generatedFeatureRoots.Contains(item)) { SetRootReady(root, terrain); return 0; } bool activeSelf = root.activeSelf; PropGrouper val = null; bool flag = false; try { root.SetActive(true); Random.InitState(FeatureSeed(seed, index, slot.Source.Name + ":" + (terrain ? "terrain" : "campfire"))); val = root.GetComponent(); flag = !Object.op_Implicit((Object)(object)val); if (!Object.op_Implicit((Object)(object)val)) { val = root.AddComponent(); } generatedGroupers.Add(val); if (flag) { addedGroupers.Add(val); } TerrainRandomizer.RunSegmentFeatures(val, slot.Offset); if (!terrain && !Object.op_Implicit((Object)(object)root.GetComponentInChildren(true))) { throw new InvalidOperationException($"TerrainRandomiser did not generate a campfire for layout position {index + 1}."); } } finally { if (Object.op_Implicit((Object)(object)root)) { root.SetActive(activeSelf); } } generatedFeatureRoots.Add(item); SetRootReady(root, terrain); return 1; } private static void SetRootReady(GameObject? root, bool terrain) { for (int i = 0; i < Slots.Length; i++) { GameObject val = (terrain ? Slots[i].Segment.segmentParent : Slots[i].Segment.segmentCampfire); if (!((Object)(object)val != (Object)(object)root)) { if (terrain) { Slots[i].TerrainReady = true; } else { Slots[i].CampfireReady = true; } } } } private static void ResetGeneratedFeatures(IEnumerable generatedGroupers, IEnumerable addedGroupers) { foreach (PropGrouper generatedGrouper in generatedGroupers) { if (Object.op_Implicit((Object)(object)generatedGrouper)) { try { generatedGrouper.ClearAll(); } catch (Exception arg) { Plugin.PLLLog.LogError((object)$"Generated map feature rollback failed. {arg}"); } } } foreach (PropGrouper addedGrouper in addedGroupers) { if (Object.op_Implicit((Object)(object)addedGrouper)) { Object.DestroyImmediate((Object)(object)addedGrouper); } } } private static int FeatureSeed(int seed, int index, string name) { uint num = (uint)((-2128831035 ^ seed ^ index) * 16777619); foreach (char c in name) { num = (num ^ c) * 16777619; } if (num != 0) { return (int)num; } return -1640531527; } private static int MapSeed() { LevelGeneration val = Object.FindAnyObjectByType(); int? num = Plugin.Instance?.roomMapSettings?.seed; if (!num.HasValue) { if (!Object.op_Implicit((Object)(object)val)) { return 0; } return val.seed; } return num.GetValueOrDefault(); } private static int LayoutRevision(IReadOnlyList slots) { //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Expected I4, but got Unknown uint num = (uint)((-2128831035 ^ MapSeed() ^ slots.Count) * 16777619); string generationEpoch = ConfigSync.GenerationEpoch; foreach (char c in generationEpoch) { num = (num ^ c) * 16777619; } foreach (Slot slot in slots) { string name = slot.Source.Name; foreach (char c2 in name) { num = (num ^ c2) * 16777619; } num = (uint)(int)((num ^ slot.Role) * 16777619); } if (num != 0) { return (int)num; } return -1640531527; } private static void BeginViewBatch() { Plugin.viewIDsToSend = new List(); Plugin.viewsRequiringIDs = new List(); if (Plugin.receivedViewIDs == null) { Plugin.receivedViewIDs = new List(); } Room currentRoom = PhotonNetwork.CurrentRoom; if (!(((currentRoom != null) ? ((RoomInfo)currentRoom).CustomProperties[(object)"propViews"] : null) is int[] array) || array.Length == 0) { Plugin.receivedViewIDs.Clear(); } Plugin.awaitingViewIDs = false; } private static HashSet BeginLazyViewBatch(int index, bool includeMap, out HashSet fakeItems) { Plugin.viewIDsToSend = new List(); Plugin.viewsRequiringIDs = new List(); Plugin.awaitingViewIDs = false; HashSet result = new HashSet(); if (includeMap) { Slot[] slots = Slots; foreach (Slot slot in slots) { AddAssignedViews(((Component)slot.Container).gameObject, result); } } else { AddAssignedViews(((Component)Slots[index].Container).gameObject, result); } fakeItems = new HashSet(); FakeItem[] array = Object.FindObjectsByType((FindObjectsInactive)1, (FindObjectsSortMode)0); foreach (FakeItem val in array) { if (Object.op_Implicit((Object)(object)val)) { fakeItems.Add(ObjectId((Object)(object)val)); } } return result; } private static void AddAssignedViews(GameObject? root, HashSet result) { if (!Object.op_Implicit((Object)(object)root)) { return; } PhotonView[] componentsInChildren = root.GetComponentsInChildren(true); foreach (PhotonView val in componentsInChildren) { if (Object.op_Implicit((Object)(object)val) && val.ViewID != 0) { result.Add(val); } } } private static void SynchronizeViews() { Plugin val = Plugin.Instance ?? throw new InvalidOperationException("TerrainRandomiser is not initialized."); bool isMasterClient = PhotonNetwork.IsMasterClient; if (isMasterClient) { Plugin.viewIDsToSend.AddRange(TerrainRandomizer.GetAndAssignAllUnassignedViews()); } else { Plugin.awaitingViewIDs = true; if (Plugin.receivedViewIDs.Count != 0) { val.UpdateRequiredViewIDs(); } } FakeItemManager.Instance.RefreshList(); if (isMasterClient) { val.SendViewIDsToClients(Plugin.viewIDsToSend); } } private static void RecoverEagerViews() { if (ConfigSync.LazyGeneration || !Plugin.awaitingViewIDs || !PhotonNetwork.IsMasterClient) { return; } Room currentRoom = PhotonNetwork.CurrentRoom; if (currentRoom == null) { return; } try { if (((RoomInfo)currentRoom).CustomProperties[(object)"propViews"] is int[] array && array.Length > 0) { ApplyEagerViewBatch(array); } else { PublishEagerViewBatch(); } } catch (Exception exception) { AbortLazyGeneration(Index, "Eager ViewID recovery failed", exception); } } private static void ApplyEagerViewBatch(int[] ids) { List list = Plugin.viewsRequiringIDs ?? throw new InvalidOperationException("TerrainRandomiser's required PhotonView list is unavailable."); List list2 = new List(list.Count); HashSet hashSet = new HashSet(); foreach (PhotonView item in list) { if (!Object.op_Implicit((Object)(object)item) || !hashSet.Add(item)) { throw new InvalidOperationException("TerrainRandomiser's required PhotonView list diverged."); } list2.Add(item); } foreach (PhotonView allUnassignedView in MapHandlerHelpers.GetAllUnassignedViews()) { if (Object.op_Implicit((Object)(object)allUnassignedView) && !hashSet.Contains(allUnassignedView)) { list2.Add(allUnassignedView); } } if (list2.Count != ids.Length) { throw new InvalidOperationException("TerrainRandomiser's recovered PhotonView count diverged."); } HashSet hashSet2 = new HashSet(); for (int i = 0; i < list2.Count; i++) { int num = ids[i]; PhotonView val = ((num > 0) ? PhotonNetwork.GetPhotonView(num) : null); if (num <= 0 || !hashSet2.Add(num) || (Object.op_Implicit((Object)(object)val) && (Object)(object)val != (Object)(object)list2[i]) || (list2[i].ViewID != 0 && list2[i].ViewID != num)) { throw new InvalidOperationException("TerrainRandomiser's recovered PhotonView ordering diverged."); } } for (int j = 0; j < list2.Count; j++) { list2[j].ViewID = ids[j]; } for (int k = 0; k < list2.Count; k++) { if ((Object)(object)PhotonNetwork.GetPhotonView(ids[k]) != (Object)(object)list2[k]) { throw new InvalidOperationException("TerrainRandomiser's recovered PhotonView registration diverged."); } } CompleteEagerViews(ids, list); } private static void PublishEagerViewBatch() { Plugin val = Plugin.Instance ?? throw new InvalidOperationException("TerrainRandomiser is not initialized."); List list = Plugin.viewsRequiringIDs ?? throw new InvalidOperationException("TerrainRandomiser's required PhotonView list is unavailable."); List list2 = new List(list.Count); HashSet hashSet = new HashSet(); foreach (PhotonView item in list) { if (!Object.op_Implicit((Object)(object)item) || (item.ViewID == 0 && !PhotonNetwork.AllocateRoomViewID(item)) || item.ViewID <= 0 || !hashSet.Add(item.ViewID)) { throw new InvalidOperationException("A recovered TerrainRandomiser PhotonView could not receive a room ViewID."); } list2.Add(item.ViewID); } foreach (int andAssignAllUnassignedView in TerrainRandomizer.GetAndAssignAllUnassignedViews()) { if (andAssignAllUnassignedView <= 0 || !hashSet.Add(andAssignAllUnassignedView)) { throw new InvalidOperationException("A recovered TerrainRandomiser PhotonView received an invalid ViewID."); } list2.Add(andAssignAllUnassignedView); } Plugin.viewIDsToSend = list2; CompleteEagerViews(list2, list); val.SendViewIDsToClients(list2); } private static void CompleteEagerViews(IEnumerable ids, List required) { Plugin.viewIDsToSend = new List(ids); Plugin.receivedViewIDs?.Clear(); required.Clear(); Plugin.awaitingViewIDs = false; } private static void SynchronizeLazyViews(int index, HashSet assignedBefore, HashSet fakeItemsBefore, bool includeMap = false) { List<(PhotonView, string)> list = CollectGeneratedViews(index, assignedBefore, includeMap); PhotonView[] array = (PhotonView[])(object)new PhotonView[list.Count]; uint num = 2166136261u; for (int i = 0; i < list.Count; i++) { array[i] = list[i].Item1; string item = list[i].Item2; foreach (char c in item) { num = (num ^ c) * 16777619; } } List<(FakeItem, string)> list2 = CollectGeneratedFakeItems(index, fakeItemsBefore, includeMap); FakeItem[] array2 = (FakeItem[])(object)new FakeItem[list2.Count]; uint num2 = 2166136261u; for (int k = 0; k < list2.Count; k++) { array2[k] = list2[k].Item1; string item2 = list2[k].Item2; foreach (char c2 in item2) { num2 = (num2 ^ c2) * 16777619; } } int seed = MapSeed(); ViewBatch viewBatch = new ViewBatch(array, (int)num, array2, (int)num2, seed); pendingViewBatches[index] = viewBatch; if (PhotonNetwork.CurrentRoom == null) { PhotonView[] array3 = array; foreach (PhotonView val in array3) { if (val.ViewID == 0 && !PhotonNetwork.AllocateViewID(val)) { throw new InvalidOperationException("A lazy-generated PhotonView could not receive a local ViewID."); } } int nextFakeId; int[] ids = AllocateFakeItemIds(viewBatch.FakeItems.Length, out nextFakeId); if (!ApplyFakeItemBatch(viewBatch, ids, nextFakeId)) { throw new InvalidOperationException("A lazy-generated FakeItem batch could not be registered locally."); } CompleteViewBatch(index); } else if (TryApplyViewBatch(index) == ViewBatchState.Absent && PhotonNetwork.IsMasterClient) { PublishViewBatch(index, viewBatch); } } private static void PublishViewBatch(int index, ViewBatch batch) { //IL_011f: Unknown result type (might be due to invalid IL or missing references) //IL_012c: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Expected O, but got Unknown Room val = PhotonNetwork.CurrentRoom ?? throw new InvalidOperationException("The lazy-generation ViewID batch has no Photon room."); int[] array = new int[batch.Views.Length]; HashSet hashSet = new HashSet(); for (int i = 0; i < batch.Views.Length; i++) { PhotonView val2 = batch.Views[i]; if (!Object.op_Implicit((Object)(object)val2)) { throw new InvalidOperationException("A lazy-generated PhotonView was destroyed before publication."); } if (val2.ViewID == 0 && !PhotonNetwork.AllocateRoomViewID(val2)) { throw new InvalidOperationException("A lazy-generated PhotonView could not receive a room ViewID."); } if (val2.ViewID <= 0 || !hashSet.Add(val2.ViewID)) { throw new InvalidOperationException("A lazy-generated PhotonView received an invalid or duplicate ViewID."); } array[i] = val2.ViewID; } int nextFakeId; int[] array2 = AllocateFakeItemIds(batch.FakeItems.Length, out nextFakeId); object[] array3 = new object[9] { ConfigSync.GenerationEpoch, 2, layoutRevision, batch.Seed, batch.PathHash, array, batch.FakePathHash, array2, nextFakeId }; if (!val.SetCustomProperties(new Hashtable { [(object)ViewBatchKey(index)] = array3 }, (Hashtable)null, (WebFlags)null)) { throw new InvalidOperationException("The lazy-generation ViewID batch could not be published."); } if (!ApplyFakeItemBatch(batch, array2, nextFakeId)) { throw new InvalidOperationException("The lazy-generated FakeItem batch could not be registered."); } CompleteViewBatch(index); } private static List<(PhotonView View, string Path)> CollectGeneratedViews(int index, HashSet assignedBefore, bool includeMap) { List<(PhotonView, string)> list = new List<(PhotonView, string)>(); HashSet seen = new HashSet(); if (includeMap) { for (int i = 0; i < Slots.Length; i++) { AddViews(((Component)Slots[i].Container).gameObject, i, assignedBefore, list, seen); } } else { AddViews(((Component)Slots[index].Container).gameObject, 0, assignedBefore, list, seen); } list.Sort(((PhotonView View, string Path) left, (PhotonView View, string Path) right) => string.CompareOrdinal(left.Path, right.Path)); return list; } private static void AddViews(GameObject? root, int rootIndex, HashSet assignedBefore, List<(PhotonView View, string Path)> result, HashSet seen) { if (!Object.op_Implicit((Object)(object)root)) { return; } PhotonView[] componentsInChildren = root.GetComponentsInChildren(true); foreach (PhotonView val in componentsInChildren) { if (!Object.op_Implicit((Object)(object)val) || assignedBefore.Contains(val) || !seen.Add(ObjectId((Object)(object)val))) { continue; } List list = new List(); Transform val2 = ((Component)val).transform; while ((Object)(object)val2 != (Object)(object)root.transform) { if (!Object.op_Implicit((Object)(object)val2.parent)) { throw new InvalidOperationException("A generated PhotonView is outside its feature root."); } list.Add(val2.GetSiblingIndex()); val2 = val2.parent; } StringBuilder stringBuilder = new StringBuilder().Append(rootIndex).Append(':'); for (int num = list.Count - 1; num >= 0; num--) { stringBuilder.Append(list[num]).Append('/'); } PhotonView[] components = ((Component)val).gameObject.GetComponents(); int j; for (j = 0; j < components.Length && (Object)(object)components[j] != (Object)(object)val; j++) { } result.Add((val, stringBuilder.Append('#').Append(j).ToString())); } } private static List<(FakeItem Item, string Path)> CollectGeneratedFakeItems(int index, HashSet assignedBefore, bool includeMap) { List<(FakeItem, string)> list = new List<(FakeItem, string)>(); HashSet seen = new HashSet(); if (includeMap) { for (int i = 0; i < Slots.Length; i++) { AddFakeItems(((Component)Slots[i].Container).gameObject, i, assignedBefore, list, seen); } } else { AddFakeItems(((Component)Slots[index].Container).gameObject, 0, assignedBefore, list, seen); } list.Sort(((FakeItem Item, string Path) left, (FakeItem Item, string Path) right) => string.CompareOrdinal(left.Path, right.Path)); return list; } private static void AddFakeItems(GameObject? root, int rootIndex, HashSet assignedBefore, List<(FakeItem Item, string Path)> result, HashSet seen) { if (!Object.op_Implicit((Object)(object)root)) { return; } FakeItem[] componentsInChildren = root.GetComponentsInChildren(true); foreach (FakeItem val in componentsInChildren) { if (!Object.op_Implicit((Object)(object)val) || assignedBefore.Contains(ObjectId((Object)(object)val)) || !seen.Add(ObjectId((Object)(object)val))) { continue; } List list = new List(); Transform val2 = ((Component)val).transform; while ((Object)(object)val2 != (Object)(object)root.transform) { if (!Object.op_Implicit((Object)(object)val2.parent)) { throw new InvalidOperationException("A generated FakeItem is outside its feature root."); } list.Add(val2.GetSiblingIndex()); val2 = val2.parent; } StringBuilder stringBuilder = new StringBuilder().Append(rootIndex).Append(':'); for (int num = list.Count - 1; num >= 0; num--) { stringBuilder.Append(list[num]).Append('/'); } FakeItem[] components = ((Component)val).gameObject.GetComponents(); int j; for (j = 0; j < components.Length && (Object)(object)components[j] != (Object)(object)val; j++) { } result.Add((val, stringBuilder.Append('#').Append(j).ToString())); } } private static int[] AllocateFakeItemIds(int count, out int nextFakeId) { nextFakeId = FakeItemHighWater(); int[] array = new int[count]; for (int i = 0; i < array.Length; i++) { if (nextFakeId == int.MaxValue) { throw new InvalidOperationException("The synchronized FakeItem index space is exhausted."); } array[i] = nextFakeId++; } return array; } private static int FakeItemHighWater() { int num = fakeItemHighWater; FakeItemManager instance = FakeItemManager.Instance; if (Object.op_Implicit((Object)(object)instance)) { List list = FakeItems.Invoke(instance); if (list != null) { foreach (FakeItem item in list) { if (Object.op_Implicit((Object)(object)item)) { if (item.index < 0 || item.index == int.MaxValue) { throw new InvalidOperationException("The FakeItem registry contains an invalid index."); } num = Math.Max(num, item.index + 1); } } } } Room currentRoom = PhotonNetwork.CurrentRoom; if (currentRoom == null) { return num; } for (int i = 0; i < Slots.Length; i++) { if (!(((RoomInfo)currentRoom).CustomProperties[(object)ViewBatchKey(i)] is object[] array) || array.Length <= 0 || !(array[0] is string text) || text != ConfigSync.GenerationEpoch) { continue; } if (array.Length != 9 || !(array[1] is int num2) || num2 != 2 || !(array[2] is int num3) || num3 != layoutRevision || !(array[3] is int num4) || num4 != MapSeed() || !(array[4] is int) || !(array[5] is int[] array2) || !(array[6] is int) || !(array[7] is int[] array3) || !(array[8] is int num5) || num5 < 0) { throw new InvalidOperationException("A cached lazy-generation object batch is invalid."); } HashSet hashSet = new HashSet(); int[] array4 = array2; foreach (int num6 in array4) { if (num6 <= 0 || !hashSet.Add(num6)) { throw new InvalidOperationException("A cached lazy-generation PhotonView batch is invalid."); } } HashSet hashSet2 = new HashSet(); int[] array5 = array3; foreach (int num7 in array5) { if (num7 < 0 || num7 >= num5 || !hashSet2.Add(num7)) { throw new InvalidOperationException("A cached lazy-generation FakeItem batch is invalid."); } } num = Math.Max(num, num5); } return num; } private static bool ApplyFakeItemBatch(ViewBatch batch, int[] ids, int nextFakeId) { if (ids.Length != batch.FakeItems.Length || nextFakeId < 0) { return false; } Dictionary dictionary = new Dictionary(batch.FakeItems.Length); HashSet hashSet = new HashSet(); for (int i = 0; i < batch.FakeItems.Length; i++) { FakeItem val = batch.FakeItems[i]; if (!Object.op_Implicit((Object)(object)val) || ids[i] < 0 || ids[i] >= nextFakeId || !hashSet.Add(ids[i]) || !dictionary.TryAdd(ObjectId((Object)(object)val), ids[i])) { return false; } } FakeItemManager instance = FakeItemManager.Instance; if (!Object.op_Implicit((Object)(object)instance)) { return batch.FakeItems.Length == 0; } ref List reference = ref FakeItems.Invoke(instance); if (reference == null) { reference = new List(); } List list = new List(reference.Count); hashSet.Clear(); foreach (FakeItem item2 in reference) { if (!Object.op_Implicit((Object)(object)item2)) { continue; } if (dictionary.TryGetValue(ObjectId((Object)(object)item2), out var value)) { if (item2.index != value) { return false; } continue; } if (item2.index < 0 || !hashSet.Add(item2.index)) { return false; } list.Add(item2); } foreach (int item in ids) { if (!hashSet.Add(item)) { return false; } } reference.Clear(); reference.AddRange(list); ref FakeItemData reference2 = ref FakeData.Invoke(instance); List hiddenItems = reference2.hiddenItems; HashSet hashSet2 = ((hiddenItems != null && hiddenItems.Count > 0) ? new HashSet(reference2.hiddenItems) : null); for (int k = 0; k < batch.FakeItems.Length; k++) { FakeItem val2 = batch.FakeItems[k]; val2.index = ids[k]; reference.Add(val2); if (hashSet2 != null && hashSet2.Contains(ids[k])) { ((Component)val2).gameObject.SetActive(false); val2.pickedUp = true; } } fakeItemHighWater = Math.Max(fakeItemHighWater, nextFakeId); return true; } private static ViewBatchState TryApplyViewBatch(int index) { if (!pendingViewBatches.TryGetValue(index, out ViewBatch value) || PhotonNetwork.CurrentRoom == null) { return ViewBatchState.Absent; } if (index >= 0 && index < Slots.Length && (Slots[index].Released || index <= releasedThrough)) { if (!ReserveReleasedViewBatch(index)) { AbortLazyGeneration(index, "Released-zone object batch validation failed"); return ViewBatchState.Invalid; } pendingViewBatches.Remove(index); return ViewBatchState.Applied; } Hashtable customProperties = ((RoomInfo)PhotonNetwork.CurrentRoom).CustomProperties; if (!(customProperties[(object)ViewBatchKey(index)] is object[] array)) { return ViewBatchState.Absent; } if (array.Length == 0) { return ViewBatchState.Absent; } if (!(array[0] is string text) || text != ConfigSync.GenerationEpoch) { return ViewBatchState.Absent; } if (array.Length != 9 || !(array[1] is int num) || num != 2 || !(array[2] is int num2) || num2 != layoutRevision || !(array[3] is int num3) || num3 != value.Seed || !(array[4] is int num4) || num4 != value.PathHash || !(array[5] is int[] array2) || array2.Length != value.Views.Length || !(array[6] is int num5) || num5 != value.FakePathHash || !(array[7] is int[] array3) || array3.Length != value.FakeItems.Length || !(array[8] is int num6) || num6 < 0) { AbortLazyGeneration(index, "Lazy-generation object batch validation failed"); return ViewBatchState.Invalid; } HashSet hashSet = new HashSet(); for (int i = 0; i < value.Views.Length; i++) { PhotonView val = value.Views[i]; int num7 = array2[i]; PhotonView val2 = ((num7 > 0) ? PhotonNetwork.GetPhotonView(num7) : null); if (num7 <= 0 || !hashSet.Add(num7) || !Object.op_Implicit((Object)(object)val) || (Object.op_Implicit((Object)(object)val2) && (Object)(object)val2 != (Object)(object)val) || (val.ViewID != 0 && val.ViewID != num7)) { AbortLazyGeneration(index, "Lazy-generation PhotonView ordering diverged"); return ViewBatchState.Invalid; } } for (int j = 0; j < value.Views.Length; j++) { value.Views[j].ViewID = array2[j]; } for (int k = 0; k < value.Views.Length; k++) { if ((Object)(object)PhotonNetwork.GetPhotonView(array2[k]) != (Object)(object)value.Views[k]) { AbortLazyGeneration(index, "Lazy-generation PhotonView registration diverged"); return ViewBatchState.Invalid; } } if (!ApplyFakeItemBatch(value, array3, num6)) { AbortLazyGeneration(index, "Lazy-generation FakeItem registration diverged"); return ViewBatchState.Invalid; } CompleteViewBatch(index); return ViewBatchState.Applied; } private static void CompleteViewBatch(int index) { pendingViewBatches.Remove(index); if (index >= 0 && index < Slots.Length) { Slots[index].ViewBatchReady = true; } if (index == 0 && !mapViewBatchReady) { mapViewBatchReady = true; TryApplyReleasedPrefix(); } ReplayJumps(index); } private static void ReplayJumps(int index) { //IL_0052: Unknown result type (might be due to invalid IL or missing references) if (index < 0 || index >= Slots.Length || !Slots[index].FeaturesReady || !Slots[index].ViewBatchReady || !pendingJumps.TryGetValue(index, out QueuedJump value)) { return; } pendingJumps.Remove(index); replayingJump = true; try { JumpToSegment(value.Segment, value.Players, value.SendToEveryone, value.UpdateFog); } finally { replayingJump = false; } } private static string ViewBatchKey(int index) { return "af.pll.library/state/view/" + index.ToString("D3", CultureInfo.InvariantCulture); } private static object[] RunValue(object value) { return new object[3] { ConfigSync.GenerationEpoch, layoutRevision, value }; } private static bool TryReadRunValue(object? value, out T result) { result = default(T); if (!(value is object[] array) || array.Length != 3 || !(array[0] is string text) || text != ConfigSync.GenerationEpoch || !(array[1] is int num) || num != layoutRevision || !(array[2] is T val)) { return false; } result = val; return true; } internal static void OnRoomPropertiesUpdate(Hashtable changed) { if (!Active) { return; } HandleReleasedProperties(changed); if (lazyGenerationAborted) { return; } for (int i = 1; i <= releasedThrough; i++) { if (((Dictionary)(object)changed).ContainsKey((object)ViewBatchKey(i)) && !ReserveReleasedViewBatch(i)) { AbortLazyGeneration(Index, "Released-zone object batch validation failed"); return; } } List list = new List(pendingViewBatches.Keys); foreach (int item in list) { if (((Dictionary)(object)changed).ContainsKey((object)ViewBatchKey(item)) && TryApplyViewBatch(item) == ViewBatchState.Absent && PhotonNetwork.IsMasterClient && pendingViewBatches.TryGetValue(item, out ViewBatch value)) { try { PublishViewBatch(item, value); } catch (Exception exception) { AbortLazyGeneration(item, "Lazy-generation ViewID recovery failed", exception); } } } HandlePeakProperties(changed); } internal static void OnMasterClientSwitched() { if (!Active) { return; } Room currentRoom = PhotonNetwork.CurrentRoom; if (currentRoom == null) { return; } HandleReleasedProperties(((RoomInfo)currentRoom).CustomProperties); if (!PhotonNetwork.IsMasterClient || lazyGenerationAborted) { return; } RecoverEagerViews(); if (lazyGenerationAborted) { return; } List list = new List(pendingViewBatches.Keys); foreach (int item in list) { if (!pendingViewBatches.TryGetValue(item, out ViewBatch value)) { continue; } try { if (TryApplyViewBatch(item) == ViewBatchState.Absent) { PublishViewBatch(item, value); } } catch (Exception exception) { AbortLazyGeneration(item, "Lazy-generation ViewID recovery failed", exception); } } HandlePeakProperties(((RoomInfo)currentRoom).CustomProperties); ReleaseOldZones(); } private static void RequestPeakTransition(int index) { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Expected O, but got Unknown if (IsPeakGate(index) && requestedPeakTransitions.Add(index)) { if (PhotonNetwork.CurrentRoom == null) { ApplyPeakTransition(index); } else if (!PhotonNetwork.CurrentRoom.SetCustomProperties(new Hashtable { [(object)"af.pll.library/state/peak/request"] = RunValue(index) }, (Hashtable)null, (WebFlags)null)) { requestedPeakTransitions.Remove(index); Plugin.PLLLog.LogError((object)"The Peak transition request could not be published."); } } } private static void HandlePeakProperties(Hashtable changed) { //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Expected O, but got Unknown if (TryReadRunValue(changed[(object)"af.pll.library/state/peak/request"], out var result) && PhotonNetwork.IsMasterClient && result == Index && IsPeakGate(result) && PhotonNetwork.CurrentRoom != null && !PhotonNetwork.CurrentRoom.SetCustomProperties(new Hashtable { [(object)"af.pll.library/state/peak/transition"] = RunValue(result) }, (Hashtable)null, (WebFlags)null)) { Plugin.PLLLog.LogError((object)"The synchronized Peak transition could not be published."); } if (TryReadRunValue(changed[(object)"af.pll.library/state/peak/transition"], out var result2)) { ApplyPeakTransition(result2); } if (TryReadRunValue(changed[(object)"af.pll.library/state/win/request"], out var result3) && result3 && PhotonNetwork.IsMasterClient && CanFinishRun(verifyPeakProgress: false)) { FinishRun(); } if (!TryReadRunValue(changed[(object)"af.pll.library/state/win/flares"], out var result4)) { return; } winningFlareViews.Clear(); int[] array = result4; foreach (int num in array) { if (num > 0) { winningFlareViews.Add(num); } } } private static void ApplyPeakTransition(int index) { if (Object.op_Implicit((Object)(object)owner) && index == Index && IsPeakGate(index) && index + 1 < Slots.Length) { GenerateLazySlot(index + 1); owner.GoToSegment((Segment)(byte)(index + 1)); if (Index == index + 1) { SyncWater(); ReleaseOldZones(); } } } private static bool IsWinningFlare(Flare flare) { PhotonView componentInParent = ((Component)flare).GetComponentInParent(); if (Object.op_Implicit((Object)(object)componentInParent)) { return winningFlareViews.Contains(componentInParent.ViewID); } return false; } private static IEnumerator WaitForLazyGeneration(IEnumerator original, int index) { GenerateLazySlot(index); while (original.MoveNext()) { yield return original.Current; } while (index >= 0 && index < Slots.Length && (!Slots[index].FeaturesReady || !Slots[index].ViewBatchReady || (index == 0 && Plugin.awaitingViewIDs))) { yield return null; } } internal static void SuppressOriginals() { if (pending != null) { DeactivateUnusedOriginals(pending.Originals.Keys, pending.Reused); } } private static void CompleteCommit() { DayNightProfile val = (Active ? Slots[0].Source.DayNightProfile : null); if (Object.op_Implicit((Object)(object)val) && Object.op_Implicit((Object)(object)DayNightManager.instance)) { DayNightManager.instance.BlendProfiles(val); } if (ConfigSync.NoPlane) { DetachedPlane detachedPlane = pending?.Plane; if (detachedPlane != null) { Transform value = detachedPlane.Value; if (Object.op_Implicit((Object)(object)value)) { ReleaseObject(((Component)value).gameObject); } } } pending = null; ReleaseOldZones(); } private static void RollbackPending() { PreparedMap preparedMap = pending; if (preparedMap == null) { return; } if (preparedMap.Committed && Object.op_Implicit((Object)(object)preparedMap.Handler)) { ResetGeneratedFeatures(preparedMap.GeneratedGroupers, preparedMap.AddedGroupers); if (preparedMap.OriginalSegments != null) { preparedMap.Handler.segments = preparedMap.OriginalSegments; } preparedMap.Handler.respawnTheKiln = preparedMap.OriginalKilnRespawn; preparedMap.Handler.respawnThePeak = preparedMap.OriginalPeakRespawn; if (preparedMap.OriginalBiomes != null) { preparedMap.Handler.biomes.Clear(); preparedMap.Handler.biomes.AddRange(preparedMap.OriginalBiomes); } Fog.Restore(); RestoreProgress(); owner = null; Slots = Array.Empty(); generatedFeatureRoots.Clear(); winningFlareViews.Clear(); requestedPeakTransitions.Clear(); pendingViewBatches.Clear(); pendingJumps.Clear(); ClearEnvironment(); runFinished = false; runFinishRequested = false; lazyGenerationAborted = false; waterObjects = Array.Empty(); authoredWaterPositions = Array.Empty(); } ClearReleasedZones(); DiscardPending(); } private static void DiscardPending() { if (pending != null) { RestoreOriginals(pending.Originals, pending.Positions); pending.Plane?.Restore(); RestoreWater(pending); pending.Environment.Restore(); Destroy(pending.Slots); } pending = null; waterObjects = Array.Empty(); authoredWaterPositions = Array.Empty(); ResetReleasedState(); } private static void Destroy(IEnumerable slots) { HashSet hashSet = new HashSet(); foreach (Slot slot in slots) { if (slot.IsClone && Object.op_Implicit((Object)(object)slot.Container)) { hashSet.Add(slot.Container); } } foreach (Transform item in hashSet) { if (Object.op_Implicit((Object)(object)item)) { Object.DestroyImmediate((Object)(object)((Component)item).gameObject); } } } private static void SyncWater() { if (!Active) { return; } if (ConfigSync.NoWater) { SetActive(waterObjects, active: false); return; } if (!ConfigSync.WaterFollowsBeach) { SetActive(waterObjects, active: true); return; } int num = Math.Max(0, Math.Min(Index, Slots.Length - 1)); for (int num2 = num; num2 >= 0; num2--) { if (!Slots[num2].Released && !(Slots[num2].Source.Name != "Beach")) { ActivateWater(num2); return; } } SetActive(waterObjects, active: false); } private static void RestoreWater(PreparedMap prepared) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) MoveWater(prepared.WaterObjects, prepared.WaterPositions, Vector3.zero); for (int i = 0; i < prepared.WaterObjects.Length; i++) { if (Object.op_Implicit((Object)(object)prepared.WaterObjects[i])) { prepared.WaterObjects[i].SetActive(prepared.WaterStates[i]); } } } internal static bool CanTransition(Segment target, int current) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Invalid comparison between Unknown and I4 if (Active) { return current + 1 < Slots.Length; } return (int)target > current; } private static bool IsJumpRole(Segment requested, Segment role) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Expected I4, but got Unknown //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) if (Active) { return RoleAt((int)requested) == role; } return requested == role; } private static bool UseVanillaPeakAlias(Segment requested) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Invalid comparison between Unknown and I4 if (!Active) { return (int)requested == 5; } return false; } private static bool LoadsInt(CodeInstruction instruction, int value) { if ((value != 4 || !(instruction.opcode == OpCodes.Ldc_I4_4)) && (value != 5 || !(instruction.opcode == OpCodes.Ldc_I4_5)) && (!(instruction.opcode == OpCodes.Ldc_I4) || !(instruction.operand is int num) || num != value)) { if (instruction.opcode == OpCodes.Ldc_I4_S && instruction.operand is sbyte b) { return b == value; } return false; } return true; } private static bool IsNotEqualBranch(OpCode opcode) { if (!(opcode == OpCodes.Bne_Un)) { return opcode == OpCodes.Bne_Un_S; } return true; } private static bool IsEqualBranch(OpCode opcode) { if (!(opcode == OpCodes.Beq)) { return opcode == OpCodes.Beq_S; } return true; } private static bool LastSeenCampfireIsSafe() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Invalid comparison between Unknown and I4 if ((int)RoleAt(Index) == 4) { return !Singleton.Instance.started; } if (OrbFogHandler.IsFoggingCurrentSegment) { return MapHandler.CurrentCampfire.EveryoneInRange(); } return true; } private static bool PreviousSegmentIsStillBaseCamp() { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Invalid comparison between Unknown and I4 if (Index == 0) { return false; } if ((int)RoleAt(Index) == 4) { return true; } return !MapHandler.CurrentCampfire.EveryoneInRange(); } private static Segment LogicalIndexForRole(Segment role) { //IL_0007: 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_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Invalid comparison between Unknown and I4 if (!Active) { return role; } for (int i = 0; i < Slots.Length; i++) { if (!Slots[i].Released && Slots[i].Role == role && ((int)role != 3 || (i + 1 < Slots.Length && Object.op_Implicit((Object)(object)Slots[i + 1].PeakAttachment)))) { return (Segment)(byte)i; } } throw new InvalidOperationException($"Mini-run segment {role} is absent from the map layout."); } private static int GetMiniRunStart(SETTINGTYPE setting, bool local) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Invalid comparison between Unknown and I4 //IL_0021: Unknown result type (might be due to invalid IL or missing references) int value = RunSettings.GetValue(setting, local); if (!Active) { return value; } Segment val = LogicalIndexForRole((Segment)(byte)value); if ((int)val != Index) { MapHandler.JumpToSegment(val); } return 0; } private static int RunTerminalIndex() { //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_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Expected I4, but got Unknown //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Invalid comparison between Unknown and I4 if (!RunSettings.isMiniRun) { return Slots.Length - 1; } Segment val = (Segment)(byte)RunSettings.GetValue((SETTINGTYPE)10050, false); int num = (int)LogicalIndexForRole(val); if ((int)val != 3) { return num; } return num + 1; } private static bool EndsAtPeak(IReadOnlyList slots) { if (slots.Count != 0) { return Object.op_Implicit((Object)(object)slots[slots.Count - 1].PeakAttachment); } return false; } private static bool InitializeProgress(MountainProgressHandler handler) { //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Expected O, but got Unknown //IL_0108: Unknown result type (might be due to invalid IL or missing references) //IL_011b: Expected I4, but got Unknown //IL_0133: Unknown result type (might be due to invalid IL or missing references) //IL_0145: Unknown result type (might be due to invalid IL or missing references) //IL_0171: Unknown result type (might be due to invalid IL or missing references) //IL_01a9: Unknown result type (might be due to invalid IL or missing references) //IL_01b6: Unknown result type (might be due to invalid IL or missing references) //IL_01bb: Unknown result type (might be due to invalid IL or missing references) //IL_019b: Unknown result type (might be due to invalid IL or missing references) //IL_01f7: Unknown result type (might be due to invalid IL or missing references) //IL_024d: Unknown result type (might be due to invalid IL or missing references) //IL_025a: Unknown result type (might be due to invalid IL or missing references) //IL_025f: Unknown result type (might be due to invalid IL or missing references) //IL_023f: Unknown result type (might be due to invalid IL or missing references) //IL_022b: Unknown result type (might be due to invalid IL or missing references) if (!Active) { return true; } int num = Slots.Length; for (int i = 0; i < Slots.Length; i++) { if (Object.op_Implicit((Object)(object)Slots[i].PeakAttachment)) { num++; } } if ((Object)(object)progressOwner == (Object)(object)handler && handler.progressPoints.Length == num) { return false; } if ((Object)(object)progressOwner != (Object)(object)handler) { progressOwner = handler; progressTemplates = handler.progressPoints; progressSkipped = SkippedBiomes.Invoke(handler); progressMax = MaxProgress.Invoke(handler); progressWasInitialized = ProgressInitialized.Invoke(handler); } if (progressTemplates.Length == 0) { return true; } if (Object.op_Implicit((Object)(object)progressRoot)) { Object.DestroyImmediate((Object)(object)progressRoot); } progressRoot = new GameObject("PLL_ProgressPoints"); progressRoot.transform.SetParent(((Component)handler).transform, false); ProgressPoint[] array = (ProgressPoint[])(object)new ProgressPoint[num]; int num2 = 0; for (int j = 0; j < Slots.Length; j++) { ProgressPoint val = progressTemplates[Math.Min((int)Slots[j].Role, progressTemplates.Length - 1)]; ProgressPoint[] array2 = progressTemplates; foreach (ProgressPoint val2 in array2) { if (val2.biome == Slots[j].Source.Biome) { val = val2; break; } } array[num2] = CreateProgressPoint(val, Slots[j].Source.Biome, Object.op_Implicit((Object)(object)val.transform) ? (val.transform.position + Slots[j].Offset) : Slots[j].Segment.segmentParent.transform.position, num2++); if (Object.op_Implicit((Object)(object)Slots[j].PeakAttachment)) { ProgressPoint val3 = progressTemplates[progressTemplates.Length - 1]; ProgressPoint val4 = CreateProgressPoint(val3, val3.biome, Object.op_Implicit((Object)(object)val3.transform) ? (val3.transform.position + Slots[j].Offset) : (Object.op_Implicit((Object)(object)Slots[j].PeakRespawn) ? Slots[j].PeakRespawn.position : Slots[j].PeakAttachment.position), num2); array[num2++] = val4; peakTransitions[val4] = j; } } handler.progressPoints = array; SkippedBiomes.Invoke(handler) = new List(); MaxProgress.Invoke(handler) = -1; ProgressInitialized.Invoke(handler) = true; return false; } private static ProgressPoint CreateProgressPoint(ProgressPoint template, BiomeType biome, Vector3 position, int index) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Expected O, but got Unknown //IL_0032: 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_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_0073: 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_008b: 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_0092: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_0098: 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_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Expected O, but got Unknown GameObject val = new GameObject($"PLL_Progress_{index:D3}"); val.transform.SetParent(progressRoot.transform, false); val.transform.position = position; val.transform.rotation = (Object.op_Implicit((Object)(object)template.transform) ? template.transform.rotation : Quaternion.identity); return new ProgressPoint { transform = val.transform, title = template.title, clip = template.clip, achievement = template.achievement, biome = biome, Reached = false }; } private static void RestoreProgress() { if (Object.op_Implicit((Object)(object)progressOwner)) { progressOwner.progressPoints = progressTemplates; SkippedBiomes.Invoke(progressOwner) = progressSkipped ?? new List(); MaxProgress.Invoke(progressOwner) = progressMax; ProgressInitialized.Invoke(progressOwner) = progressWasInitialized; } if (Object.op_Implicit((Object)(object)progressRoot)) { Object.DestroyImmediate((Object)(object)progressRoot); } progressOwner = null; progressTemplates = Array.Empty(); progressSkipped = null; progressRoot = null; peakTransitions.Clear(); } } internal sealed class MapNetworkBridge : MonoBehaviourPunCallbacks { public override void OnRoomPropertiesUpdate(Hashtable propertiesThatChanged) { Map.OnRoomPropertiesUpdate(propertiesThatChanged); } public override void OnMasterClientSwitched(Player newMasterClient) { ConfigSync.OnMasterClientSwitched(); Map.OnMasterClientSwitched(); } } internal static class Sounds { [HarmonyPatch(typeof(AmbienceAudio), "Update")] private static class AmbiencePatch { [HarmonyPrefix] private static void Prefix(AmbienceAudio __instance) { if (!Map.Active) { currentContainer = null; currentVolcano = null; return; } int index = Map.Index; if (index < 0 || index >= Map.Slots.Length || Map.Slots[index].Released) { return; } Map.Slot slot = Map.Slots[index]; if ((Object)(object)currentContainer != (Object)(object)slot.Container || (currentVolcano != null && !Object.op_Implicit((Object)(object)currentVolcano))) { currentContainer = slot.Container; string name = slot.Source.Name; bool flag = ((name == "Caldera" || name == "Volcano") ? true : false); currentVolcano = (flag ? FindVolcano(slot.Container) : null); } GameObject val = VolcanoObject.Invoke(__instance); if (!((Object)(object)val == (Object)(object)currentVolcano)) { VolcanoObject.Invoke(__instance) = currentVolcano; VolcanoState.Invoke(__instance) = false; VolcanoTimer.Invoke(__instance) = 0f; Animator val2 = Volumes.Invoke(__instance); if (Object.op_Implicit((Object)(object)val2)) { val2.SetBool("Volcano", false); } AudioReverbZone val3 = Reverb.Invoke(__instance); if (Object.op_Implicit((Object)(object)val3)) { ((Behaviour)val3).enabled = true; } } } [HarmonyTranspiler] private static IEnumerable Transpiler(IEnumerable instructions) { int biomes = 0; int positions = 0; foreach (CodeInstruction instruction in instructions) { if (CodeInstructionExtensions.Calls(instruction, BiomeIsPresent)) { instruction.opcode = OpCodes.Call; instruction.operand = CurrentBiomeMethod; biomes++; } else if (CodeInstructionExtensions.Calls(instruction, TransformPosition)) { instruction.opcode = OpCodes.Call; instruction.operand = LogicalPositionMethod; positions++; } yield return instruction; } if (biomes == 0 || positions == 0) { throw new MissingMethodException("AmbienceAudio.Update biome or position routing was not found."); } } } private static readonly FieldRef Volumes = AccessTools.FieldRefAccess("ambienceVolumes"); private static readonly FieldRef VolcanoObject = AccessTools.FieldRefAccess("volcanoObj"); private static readonly FieldRef VolcanoState = AccessTools.FieldRefAccess("volcano"); private static readonly FieldRef VolcanoTimer = AccessTools.FieldRefAccess("vulcanoT"); private static readonly FieldRef Reverb = AccessTools.FieldRefAccess("reverb"); private static readonly MethodInfo BiomeIsPresent = AccessTools.DeclaredMethod(typeof(MapHandler), "BiomeIsPresent", new Type[1] { typeof(BiomeType) }, (Type[])null); private static readonly MethodInfo CurrentBiomeMethod = AccessTools.DeclaredMethod(typeof(Sounds), "CurrentBiome", (Type[])null, (Type[])null); private static readonly MethodInfo TransformPosition = AccessTools.PropertyGetter(typeof(Transform), "position"); private static readonly MethodInfo LogicalPositionMethod = AccessTools.DeclaredMethod(typeof(Sounds), "LogicalPosition", (Type[])null, (Type[])null); private static Transform? currentContainer; private static GameObject? currentVolcano; private static bool CurrentBiome(MapHandler handler, BiomeType biome) { //IL_0008: 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) if (!Map.Active) { return handler.BiomeIsPresent(biome); } int index = Map.Index; if (index >= 0 && index < Map.Slots.Length && !Map.Slots[index].Released) { return Map.Slots[index].Source.Biome == biome; } return false; } private static Vector3 LogicalPosition(Transform value) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0034: 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) Vector3 position = value.position; if (!Map.Active) { return position; } int index = Map.Index; if (index < 0 || index >= Map.Slots.Length || Map.Slots[index].Released) { return position; } return position - Map.Slots[index].Offset; } private static GameObject? FindVolcano(Transform root) { Transform[] componentsInChildren = ((Component)root).GetComponentsInChildren(true); foreach (Transform val in componentsInChildren) { if (((Object)val).name == "VolcanoModel") { return ((Component)val).gameObject; } } return null; } } }