using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using StartingAbilityPicker; using UnityEngine; using UnityEngine.SceneManagement; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyVersion("0.0.0.0")] namespace HKSilksong_Randomizer; public static class RoomMapGenerator { private static readonly bool[,] letters; static RoomMapGenerator() { letters = new bool[128, 25]; string[] array = new string[26] { "01110100011000111111000110001", "11110100011111010001100011111", "01110100011000010000100000111", "11110100011000110001100011110", "11111100001111010000100011111", "11111100001111010000100010000", "01110100011000010111100001111", "10001100011111110001100011000", "01110001000010000100001000111", "00111000100001000100011001100", "10001100101110010010100011000", "10000100001000010000100001111", "10001110111010110001100011000", "10001110011010110011100011000", "01110100011000110001100010111", "11110100011111010000100010000", "01110100011000110001101010101", "11110100011111010010100011001", "01111100000111000001100011110", "11111001000010000100001000010", "10001100011000110001100001110", "10001100011000101010001000100", "10001100011000110101101011010", "10001010100010001010100010001", "10001010100010000100001000010", "11111000100010001000100011111" }; for (int i = 0; i < 26; i++) { string text = array[i]; for (int j = 0; j < 25; j++) { letters[65 + i, j] = text[j] == '1'; } } string[] array2 = new string[10] { "01110100011000110001100010111", "00100011000010000100001000111", "01110100010001000100010001111", "11110000111100000011100011110", "10001100111110000010000100010", "11111100001111000001100011111", "01110100001111010001100010111", "11111000010001000100001000010", "01110100011000101110100010111", "01110100011000101111000011110" }; for (int k = 0; k < 10; k++) { string text2 = array2[k]; for (int l = 0; l < 25; l++) { letters[48 + k, l] = text2[l] == '1'; } } string text3 = "00000000000000000000011111"; for (int m = 0; m < 25; m++) { letters[95, m] = text3[m] == '1'; } } public static bool GenerateFromFile(string connectionsFilePath, string outputImagePath) { if (!File.Exists(connectionsFilePath)) { Debug.LogWarning((object)("File not found: " + connectionsFilePath)); return false; } string[] array = File.ReadAllLines(connectionsFilePath); Dictionary> dictionary = new Dictionary>(StringComparer.OrdinalIgnoreCase); string[] array2 = array; for (int i = 0; i < array2.Length; i++) { string text = array2[i]?.Trim(); if (string.IsNullOrEmpty(text) || text.StartsWith("#")) { continue; } string[] array3 = text.Split(new char[1] { '|' }); if (array3.Length != 4) { continue; } string text2 = array3[0]; string text3 = array3[2]; if (!string.IsNullOrEmpty(text2) && !string.IsNullOrEmpty(text3)) { if (!dictionary.ContainsKey(text2)) { dictionary[text2] = new HashSet(StringComparer.OrdinalIgnoreCase); } if (!dictionary.ContainsKey(text3)) { dictionary[text3] = new HashSet(StringComparer.OrdinalIgnoreCase); } dictionary[text2].Add(text3); dictionary[text3].Add(text2); } } if (dictionary.Count == 0) { Debug.LogWarning((object)"No connections found."); return false; } GenerateMapTexture(dictionary, outputImagePath); Debug.Log((object)("Map saved to " + outputImagePath)); return true; } private static void GenerateMapTexture(Dictionary> graph, string outputPath) { //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Expected O, but got Unknown //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_01ee: Unknown result type (might be due to invalid IL or missing references) //IL_01fb: Unknown result type (might be due to invalid IL or missing references) //IL_0208: Unknown result type (might be due to invalid IL or missing references) //IL_0216: Unknown result type (might be due to invalid IL or missing references) //IL_0226: Unknown result type (might be due to invalid IL or missing references) //IL_023b: Unknown result type (might be due to invalid IL or missing references) //IL_015a: Unknown result type (might be due to invalid IL or missing references) //IL_0169: Unknown result type (might be due to invalid IL or missing references) //IL_0178: 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_0196: Unknown result type (might be due to invalid IL or missing references) int num = 250; int num2 = 120; int num3 = 100; int num4 = 80; List list = graph.Keys.ToList(); int num5 = (int)Math.Ceiling(Math.Sqrt(list.Count)); int num6 = (int)Math.Ceiling((double)list.Count / (double)num5); int num7 = num5 * (num + num3) + num3; int num8 = num6 * (num2 + num4) + num4; Texture2D val = new Texture2D(num7, num8, (TextureFormat)4, false); Color[] array = (Color[])(object)new Color[num7 * num8]; for (int i = 0; i < array.Length; i++) { array[i] = Color.black; } val.SetPixels(array); Dictionary dictionary = new Dictionary(); int num9 = 0; int num10 = 0; foreach (string item in list) { dictionary[item] = new Vector2((float)(num3 + num9 * (num + num3)), (float)(num4 + num10 * (num2 + num4))); num9++; if (num9 >= num5) { num9 = 0; num10++; } } foreach (KeyValuePair> item2 in graph) { if (!dictionary.TryGetValue(item2.Key, out var value)) { continue; } foreach (string item3 in item2.Value) { if (dictionary.TryGetValue(item3, out var value2)) { DrawLine(val, (int)(value.x + (float)(num / 2)) + 2, (int)(value.y + (float)(num2 / 2)) + 2, (int)(value2.x + (float)(num / 2)) + 2, (int)(value2.y + (float)(num2 / 2)) + 2, Color.gray, 3); } } } foreach (KeyValuePair item4 in dictionary) { DrawEmptyRectangle(val, (int)item4.Value.x, (int)item4.Value.y, num, num2, Color.gray); DrawTextBitmap(val, (int)item4.Value.x + 10, (int)item4.Value.y + 35, item4.Key, Color.white); } val.Apply(); string directoryName = Path.GetDirectoryName(outputPath); if (!string.IsNullOrEmpty(directoryName) && !Directory.Exists(directoryName)) { Directory.CreateDirectory(directoryName); } File.WriteAllBytes(outputPath, ImageConversion.EncodeToPNG(val)); Object.DestroyImmediate((Object)(object)val); } private static void DrawEmptyRectangle(Texture2D tex, int x, int y, int w, int h, Color color) { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0079: 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 = x; i < x + w; i++) { if (i >= 0 && i < ((Texture)tex).width) { if (y >= 0 && y < ((Texture)tex).height) { tex.SetPixel(i, y, color); } if (y + h - 1 >= 0 && y + h - 1 < ((Texture)tex).height) { tex.SetPixel(i, y + h - 1, color); } } } for (int j = y; j < y + h; j++) { if (j >= 0 && j < ((Texture)tex).height) { if (x >= 0 && x < ((Texture)tex).width) { tex.SetPixel(x, j, color); } if (x + w - 1 >= 0 && x + w - 1 < ((Texture)tex).width) { tex.SetPixel(x + w - 1, j, color); } } } } private static void DrawTextBitmap(Texture2D tex, int x, int y, string text, Color color) { //IL_00c6: Unknown result type (might be due to invalid IL or missing references) int num = x; int num2 = 4; int num3 = 1; string text2 = text.ToUpper(); foreach (char c in text2) { if ((c < 'A' || c > 'Z') && (c < '0' || c > '9') && c != '_') { num += 5 * num2 + num2; continue; } for (int j = 0; j < 5; j++) { for (int k = 0; k < 5; k++) { if (!letters[(uint)c, j * 5 + k]) { continue; } int num4 = ((c != '_') ? (4 - j) : (4 - j - num3)); for (int l = 0; l < num2; l++) { for (int m = 0; m < num2; m++) { int num5 = num + k * num2 + l; int num6 = y + num4 * num2 + m; if (num5 >= 0 && num5 < ((Texture)tex).width && num6 >= 0 && num6 < ((Texture)tex).height) { tex.SetPixel(num5, num6, color); } } } } } num += 5 * num2 + num2; } } private static void DrawLine(Texture2D tex, int x0, int y0, int x1, int y1, Color color, int thickness = 2) { //IL_006d: Unknown result type (might be due to invalid IL or missing references) int num = Math.Abs(x1 - x0); int num2 = ((x0 < x1) ? 1 : (-1)); int num3 = -Math.Abs(y1 - y0); int num4 = ((y0 < y1) ? 1 : (-1)); int num5 = num + num3; while (true) { for (int i = -thickness / 2; i <= thickness / 2; i++) { for (int j = -thickness / 2; j <= thickness / 2; j++) { int num6 = x0 + i; int num7 = y0 + j; if (num6 >= 0 && num6 < ((Texture)tex).width && num7 >= 0 && num7 < ((Texture)tex).height) { tex.SetPixel(num6, num7, color); } } } if (x0 != x1 || y0 != y1) { int num8 = 2 * num5; if (num8 >= num3) { num5 += num3; x0 += num2; } if (num8 <= num) { num5 += num; y0 += num4; } continue; } break; } } } [BepInPlugin("com.yourname.randomsceneloader", "Random Scene Loader", "0.1.1")] public class RandomSceneLoader : BaseUnityPlugin { internal class SceneConfig { public List Exits; public SceneConfig(List exits) { Exits = exits ?? new List(); } } [CompilerGenerated] private sealed class d__42 : IEnumerator, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public RandomSceneLoader <>4__this; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__42(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { int num = <>1__state; RandomSceneLoader randomSceneLoader = <>4__this; switch (num) { default: return false; case 0: <>1__state = -1; <>2__current = randomSceneLoader.waitHalfSecond; <>1__state = 1; return true; case 1: <>1__state = -1; randomSceneLoader.DiscoverGatesInCurrentScene(); return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class d__45 : IEnumerator, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public RandomSceneLoader <>4__this; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__45(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: 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) int num = <>1__state; RandomSceneLoader randomSceneLoader = <>4__this; switch (num) { default: return false; case 0: <>1__state = -1; <>2__current = randomSceneLoader.waitThirdSecond; <>1__state = 1; return true; case 1: <>1__state = -1; try { HeroController instance = HeroController.instance; if ((Object)(object)instance != (Object)null) { Vector3 position = ((Component)instance).transform.position; GameObject[] array = Object.FindObjectsByType((FindObjectsSortMode)0); foreach (GameObject val in array) { string text = ((Object)val).name.ToLower(); if ((text.StartsWith("left") || text.StartsWith("right") || text.StartsWith("top") || text.StartsWith("bot")) && text.Length <= 6 && char.IsDigit(text[text.Length - 1]) && (double)Vector3.Distance(position, val.transform.position) < 10.0) { if (string.IsNullOrEmpty(randomSceneLoader.lastEntryGateUsed)) { randomSceneLoader.lastEntryGateUsed = ((Object)val).name; randomSceneLoader.log.LogInfo((object)("Auto-detected entry gate: " + ((Object)val).name)); } break; } } } } catch (Exception ex) { randomSceneLoader.log.LogWarning((object)("DetectEntryGate failed: " + ex.Message)); } return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class d__40 : IEnumerator, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public RandomSceneLoader <>4__this; public string entryGate; public string sceneName; private float 5__2; private float 5__3; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__40(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_014f: Unknown result type (might be due to invalid IL or missing references) //IL_0154: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: 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_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Expected O, but got Unknown int num = <>1__state; RandomSceneLoader randomSceneLoader = <>4__this; Scene activeScene; switch (num) { default: return false; case 0: <>1__state = -1; if (randomSceneLoader.isTransitioning) { break; } randomSceneLoader.loadRequested = false; randomSceneLoader.isTransitioning = true; randomSceneLoader.lastEntryGateUsed = entryGate; 5__2 = 8f; 5__3 = Time.time; if (!string.IsNullOrEmpty(sceneName) && (Object)(object)GameManager.instance != (Object)null) { try { GameManager.instance.BeginSceneTransition(new SceneLoadInfo { SceneName = sceneName, EntryGateName = entryGate, PreventCameraFadeOut = false, WaitForSceneTransitionCameraFade = true, Visualization = (SceneLoadVisualizations)0 }); } catch (Exception ex) { randomSceneLoader.log.LogWarning((object)("BeginSceneTransition failed: " + ex.Message)); randomSceneLoader.isTransitioning = false; SuppressTransitionPatch = false; return false; } goto IL_014f; } try { SceneManager.LoadScene(sceneName); } catch (Exception ex2) { randomSceneLoader.log.LogWarning((object)("SceneManager.LoadScene failed: " + ex2.Message)); } finally { randomSceneLoader.isTransitioning = false; } break; case 1: <>1__state = -1; goto IL_014f; case 2: { <>1__state = -1; randomSceneLoader.isTransitioning = false; break; } IL_014f: activeScene = SceneManager.GetActiveScene(); if (((Scene)(ref activeScene)).name != sceneName) { if (Time.time - 5__3 > 5__2) { randomSceneLoader.log.LogWarning((object)("LoadSceneCoroutine timeout waiting for scene " + sceneName)); randomSceneLoader.isTransitioning = false; SuppressTransitionPatch = false; return false; } <>2__current = randomSceneLoader.waitTenthSecond; <>1__state = 1; return true; } <>2__current = randomSceneLoader.waitFifthSecond; <>1__state = 2; return true; } SuppressTransitionPatch = false; return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } internal ManualLogSource log; private Random rng; internal readonly Dictionary sceneConfigs = new Dictionary(StringComparer.OrdinalIgnoreCase) { { "Tut_01", new SceneConfig(new List { "left1", "left2", "left3", "right1", "right2", "top1" }) }, { "Tut_01b", new SceneConfig(new List { "left1", "left2", "right1" }) }, { "Tut_02", new SceneConfig(new List { "right1", "right2" }) }, { "Tut_03", new SceneConfig(new List { "right1", "top1" }) }, { "Bonetown", new SceneConfig(new List { "bot1", "bot2", "left1", "left2", "right1", "right2", "top1", "top2", "top3", "top4", "top5", "top6" }) }, { "Weave_02", new SceneConfig(new List { "left2", "left3", "left4", "right1", "right2", "right3" }) }, { "Weave_03", new SceneConfig(new List { "right1" }) }, { "Weave_04", new SceneConfig(new List { "left1", "right2" }) }, { "Weave_05b", new SceneConfig(new List { "left1" }) }, { "Weave_07", new SceneConfig(new List { "left1", "right1" }) }, { "Weave_08", new SceneConfig(new List { "left1", "right1" }) }, { "Weave_10", new SceneConfig(new List { "left1" }) }, { "Weave_11", new SceneConfig(new List { "right1", "top1" }) }, { "Weave_12", new SceneConfig(new List { "left1" }) }, { "Weave_13", new SceneConfig(new List { "left1", "right1" }) }, { "Weave_14", new SceneConfig(new List { "bot1" }) }, { "Bone_01", new SceneConfig(new List { "left2", "right1", "right2", "top2" }) }, { "Bone_04", new SceneConfig(new List { "bot2", "left1", "left2", "right1", "top1" }) }, { "Bone_05", new SceneConfig(new List { "bot1", "left1", "right1" }) }, { "Bone_03", new SceneConfig(new List { "bot1", "left1", "left2", "left4", "right1", "right3", "top1" }) }, { "Bone_05b", new SceneConfig(new List { "left1", "top1" }) }, { "Bone_06", new SceneConfig(new List { "bot1", "left1", "right1" }) }, { "Bone_07", new SceneConfig(new List { "left1", "right1", "right2", "top1" }) }, { "Bone_08", new SceneConfig(new List { "bot1", "left2", "left3", "right2", "right3" }) }, { "Bone_09", new SceneConfig(new List { "left1", "right1", "right2", "top1" }) }, { "Bone_10", new SceneConfig(new List { "bot1", "left1", "right1" }) }, { "Bone_11", new SceneConfig(new List { "bot1", "left1", "right1", "right2", "top1" }) }, { "Bone_14", new SceneConfig(new List { "left1", "right1" }) }, { "Bone_15", new SceneConfig(new List { "bot1", "left1" }) }, { "Bone_16", new SceneConfig(new List { "left1", "right1", "top1" }) }, { "Bone_17", new SceneConfig(new List { "right1" }) }, { "Bone_18", new SceneConfig(new List { "left1" }) }, { "Bone_19", new SceneConfig(new List { "bot1" }) }, { "Bone_East_01", new SceneConfig(new List { "left1", "left2", "right1", "right2", "right3" }) }, { "Bone_East_02", new SceneConfig(new List { "left1", "right1", "top1" }) }, { "Bone_East_04", new SceneConfig(new List { "bot1", "left1", "right1", "right2", "top2" }) }, { "Bone_East_05", new SceneConfig(new List { "left1", "right1" }) }, { "Bone_East_07", new SceneConfig(new List { "left1", "left2", "left3", "left4", "right1", "right2", "right3", "right4", "right5", "top1" }) }, { "Bone_East_09", new SceneConfig(new List { "left2", "left3", "right1", "right2", "top1" }) }, { "Bone_East_10", new SceneConfig(new List { "left1", "left2", "right1", "right2" }) }, { "Bone_East_11", new SceneConfig(new List { "bot1", "left1", "right1", "right2" }) }, { "Bone_East_12", new SceneConfig(new List { "bot1", "left1", "right1" }) }, { "Bone_East_13", new SceneConfig(new List { "left1" }) }, { "Bone_East_14", new SceneConfig(new List { "left1", "left2", "right1", "right2" }) }, { "Bone_East_15", new SceneConfig(new List { "bot1", "left1", "right1" }) }, { "Bone_East_16", new SceneConfig(new List { "bot1", "right1" }) }, { "Bone_East_17", new SceneConfig(new List { "bot1", "left1", "right1" }) }, { "Bone_East_18", new SceneConfig(new List { "left1", "right1", "top1" }) }, { "Bone_East_18b", new SceneConfig(new List { "left1", "top1" }) }, { "Bone_East_18c", new SceneConfig(new List { "left1", "right1" }) }, { "Bone_East_20", new SceneConfig(new List { "right1" }) }, { "Bone_East_22", new SceneConfig(new List { "left1" }) }, { "Bone_East_24", new SceneConfig(new List { "bot1", "left1", "right1" }) }, { "Bone_East_25", new SceneConfig(new List { "left1" }) }, { "Bone_East_26", new SceneConfig(new List { "bot1", "top1" }) }, { "Bone_East_27", new SceneConfig(new List { "bot1", "left1", "right1" }) }, { "Bone_East_04c", new SceneConfig(new List { "left1" }) }, { "Bone_East_04b", new SceneConfig(new List { "left1", "right1", "top1" }) }, { "Bone_East_09b", new SceneConfig(new List { "bot1", "left1", "top1" }) }, { "Bone_East_14b", new SceneConfig(new List { "left1", "left2", "right1" }) }, { "Ant_02", new SceneConfig(new List { "left1", "right1" }) }, { "Ant_03", new SceneConfig(new List { "left2", "right3" }) }, { "Ant_04", new SceneConfig(new List { "left1", "right1" }) }, { "Ant_04_left", new SceneConfig(new List { "left1", "right1" }) }, { "Ant_04_mid", new SceneConfig(new List { "left1", "right1" }) }, { "Ant_05b", new SceneConfig(new List { "bot1", "bot2", "right1" }) }, { "Ant_05c", new SceneConfig(new List { "left1", "right1" }) }, { "Ant_09", new SceneConfig(new List { "left1", "right1" }) }, { "Ant_14", new SceneConfig(new List { "left1", "left2", "left3", "left4", "left5", "right2", "right3" }) }, { "Ant_17", new SceneConfig(new List { "right1" }) }, { "Ant_19", new SceneConfig(new List { "left1" }) }, { "Ant_20", new SceneConfig(new List { "left1" }) }, { "Ant_21", new SceneConfig(new List { "right1" }) }, { "Ant_Merchant", new SceneConfig(new List { "right1" }) }, { "Ant_Queen", new SceneConfig(new List { "left1" }) }, { "Aspid_01", new SceneConfig(new List { "bot1", "bot2", "bot3", "bot4", "bot5", "bot6", "bot7", "bot8", "left1", "left2", "right2", "right3", "right4", "top1", "top2", "top3", "top4", "top5", "top6", "top7" }) }, { "Belltown_04", new SceneConfig(new List { "bot1", "left1", "left2" }) }, { "Belltown_06", new SceneConfig(new List { "left1", "left3", "right1" }) }, { "Belltown_Room_shellwood", new SceneConfig(new List { "left1" }) }, { "Belltown_Shrine", new SceneConfig(new List { "right1", "top1" }) }, { "Belltown_basement_03", new SceneConfig(new List { "left1", "top1" }) }, { "Bellshrine", new SceneConfig(new List { "left1", "right1" }) }, { "Bellshrine_03", new SceneConfig(new List { "left1", "right1" }) }, { "Bonegrave", new SceneConfig(new List { "right1", "right2", "top1" }) }, { "Bone_01c", new SceneConfig(new List { "left1", "left2", "right1" }) }, { "Bone_02", new SceneConfig(new List { "left1", "right1", "top1", "top2" }) }, { "Bellshrine_05", new SceneConfig(new List { "left1", "right1" }) }, { "Bellway_03", new SceneConfig(new List { "left1", "right1" }) }, { "Greymoor_01", new SceneConfig(new List { "bot1", "left1", "left2", "right1", "right2", "right3" }) }, { "Bellshrine_02", new SceneConfig(new List { "left1", "right1" }) }, { "Greymoor_02", new SceneConfig(new List { "left1", "left2", "left3", "right1", "right2", "right3" }) }, { "Greymoor_15", new SceneConfig(new List { "left1", "left3", "right2", "right3" }) }, { "Greymoor_15b", new SceneConfig(new List { "left2", "left3", "right1", "top1" }) }, { "Room_CrowCourt", new SceneConfig(new List { "bot1", "left1" }) }, { "Room_CrowCourt_02", new SceneConfig(new List { "top1" }) }, { "Clover_01", new SceneConfig(new List { "left1", "right1" }) }, { "Greymoor_22", new SceneConfig(new List { "bot1" }) }, { "Greymoor_12", new SceneConfig(new List { "left1", "right1" }) }, { "Greymoor_03", new SceneConfig(new List { "left1", "left2", "left3", "right1", "right2", "right3", "right4", "right5" }) }, { "Dust_01", new SceneConfig(new List { "left1", "right1" }) }, { "Dust_02", new SceneConfig(new List { "left1", "left2", "right1", "right2", "right3", "top1" }) }, { "Dust_03", new SceneConfig(new List { "bot1", "left1", "top1" }) }, { "Dust_Chef", new SceneConfig(new List { "bot1", "left1" }) }, { "Dust_04", new SceneConfig(new List { "left1", "left2", "right1" }) }, { "Dust_Shack", new SceneConfig(new List { "left1" }) }, { "Dust_10", new SceneConfig(new List { "right1" }) }, { "Dust_05", new SceneConfig(new List { "bot1", "left1", "right1" }) }, { "Dust_06", new SceneConfig(new List { "left1", "right1", "right2", "right3" }) }, { "Dust_12", new SceneConfig(new List { "left1" }) }, { "Dust_11", new SceneConfig(new List { "bot1", "left1" }) }, { "Greymoor_17", new SceneConfig(new List { "left1", "top1" }) }, { "Halfway_01", new SceneConfig(new List { "bot1", "left1", "right1" }) }, { "Greymoor_04", new SceneConfig(new List { "left1", "left2", "left3", "right1", "right2" }) }, { "Greymoor_11", new SceneConfig(new List { "left1", "right1" }) }, { "Greymoor_06", new SceneConfig(new List { "left1", "left2", "left3", "right1", "right2", "right3", "right4", "top1" }) }, { "Greymoor_10", new SceneConfig(new List { "left1", "right1" }) }, { "Wisp_03", new SceneConfig(new List { "right1", "top1" }) }, { "Wisp_06", new SceneConfig(new List { "bot1" }) }, { "Greymoor_07", new SceneConfig(new List { "bot1", "left1", "right1", "right2" }) }, { "Greymoor_20b", new SceneConfig(new List { "right1" }) }, { "Greymoor_20c", new SceneConfig(new List { "left1" }) }, { "Greymoor_08", new SceneConfig(new List { "left2", "right1", "top1" }) }, { "Greymoor_16", new SceneConfig(new List { "left1", "top1" }) }, { "Bellway_04", new SceneConfig(new List { "bot1", "left1" }) }, { "Greymoor_05", new SceneConfig(new List { "left1", "left2", "right1", "right2" }) }, { "Belltown", new SceneConfig(new List { "left3", "right2" }) }, { "Memory_Needolin", new SceneConfig(new List { "left1", "right1" }) }, { "Belltown_07", new SceneConfig(new List { "left1", "right1" }) }, { "Shellwood_01", new SceneConfig(new List { "left1", "left2", "right1", "right2" }) }, { "Shellwood_02", new SceneConfig(new List { "left2", "left3", "right1", "right2" }) }, { "Shellwood_16", new SceneConfig(new List { "left1", "right1" }) }, { "Shellwood_03", new SceneConfig(new List { "bot1", "left1", "left3", "right1", "right2", "right3" }) }, { "Shellwood_04b", new SceneConfig(new List { "left1", "right1", "top1", "top2" }) }, { "Shellwood_08c", new SceneConfig(new List { "left1", "right1" }) }, { "Shellwood_04c", new SceneConfig(new List { "bot1", "top1" }) }, { "Shellwood_08", new SceneConfig(new List { "bot1", "left1", "right1" }) }, { "Coral_19", new SceneConfig(new List { "bot1", "bot2", "bot3", "bot4", "bot5", "bot6", "bot7", "right1", "top1", "top2", "top3", "top4", "top5", "top6", "top7", "top8" }) }, { "Shellwood_19", new SceneConfig(new List { "left1", "right1" }) }, { "Shellwood_14", new SceneConfig(new List { "left1" }) }, { "Shellwood_10", new SceneConfig(new List { "left1", "left2", "left3", "right1", "right2", "right3" }) }, { "Shellwood_11", new SceneConfig(new List { "right1", "right2" }) }, { "Shellwood_26", new SceneConfig(new List { "bot1", "left1" }) }, { "Shellwood_18", new SceneConfig(new List { "left1", "right1", "top1" }) }, { "Shellwood_13", new SceneConfig(new List { "left1", "left2", "right1" }) }, { "Shellwood_01b", new SceneConfig(new List { "left1", "left2", "right1", "right2", "right3" }) }, { "Shellwood_20", new SceneConfig(new List { "left1", "right1" }) }, { "Shellwood_Witch", new SceneConfig(new List { "right1" }) }, { "Dock_08", new SceneConfig(new List { "left1", "left2", "right1" }) }, { "Dock_01", new SceneConfig(new List { "left1", "right1", "right2" }) }, { "Bellway_02", new SceneConfig(new List { "left1", "right1" }) }, { "Dock_16", new SceneConfig(new List { "right1" }) }, { "Bone_East_03", new SceneConfig(new List { "left1", "top1" }) }, { "Room_Forge", new SceneConfig(new List { "left1", "right1", "top1" }) }, { "Dock_04", new SceneConfig(new List { "left1", "right1", "right2", "right3" }) }, { "Dock_06_Church", new SceneConfig(new List { "bot1", "right1" }) }, { "Dock_10", new SceneConfig(new List { "left1", "right1" }) }, { "Dock_15", new SceneConfig(new List { "left1", "left2", "right1", "right2", "right3" }) }, { "Dock_13", new SceneConfig(new List { "right1" }) }, { "Dock_11", new SceneConfig(new List { "left1", "right1" }) }, { "Dock_12", new SceneConfig(new List { "left1" }) }, { "Dock_14", new SceneConfig(new List { "left1" }) }, { "Dock_09", new SceneConfig(new List { "left1", "right1" }) }, { "Dock_02", new SceneConfig(new List { "left1", "left2", "right1", "right2", "right3" }) }, { "Dock_02b", new SceneConfig(new List { "left1", "left2", "left3", "right1", "right2" }) }, { "Dock_03c", new SceneConfig(new List { "left2", "top1", "top2" }) }, { "Dock_03", new SceneConfig(new List { "bot1", "left1", "right1" }) }, { "Dock_03b", new SceneConfig(new List { "left1", "right1" }) }, { "Shellwood_15", new SceneConfig(new List { "left1", "right1" }) }, { "Coral_19b", new SceneConfig(new List { "bot1" }) }, { "Coral_02", new SceneConfig(new List { "bot2", "right1" }) }, { "Coral_03", new SceneConfig(new List { "bot1", "bot2", "bot3", "bot4", "bot5", "bot6", "left1", "left2", "left3", "right1", "right2", "right3" }) }, { "Coral_12", new SceneConfig(new List { "left2", "left3", "right1" }) }, { "Coral_11", new SceneConfig(new List { "left1", "right1" }) }, { "Coral_11b", new SceneConfig(new List { "left1", "right1" }) }, { "Coral_34", new SceneConfig(new List { "right1", "top1" }) }, { "Coral_25", new SceneConfig(new List { "bot1", "right1" }) }, { "Coral_23", new SceneConfig(new List { "left1", "left2", "right1" }) }, { "Coral_39", new SceneConfig(new List { "right1" }) }, { "Coral_35b", new SceneConfig(new List { "bot1", "left2", "left3", "left4", "left5", "right1", "right2" }) }, { "Coral_40", new SceneConfig(new List { "right1" }) }, { "Coral_41", new SceneConfig(new List { "right1" }) }, { "Coral_35", new SceneConfig(new List { "left1", "left2", "right1", "right2", "top1" }) }, { "Coral_24", new SceneConfig(new List { "left1", "right1" }) }, { "Coral_26", new SceneConfig(new List { "left1", "left2", "right1" }) }, { "Coral_38", new SceneConfig(new List { "bot1", "left1", "right1" }) }, { "Coral_44", new SceneConfig(new List { "left1", "right1" }) }, { "Coral_29", new SceneConfig(new List { "left1" }) }, { "Coral_27", new SceneConfig(new List { "left1", "right1" }) }, { "Coral_28", new SceneConfig(new List { "right1" }) }, { "Coral_Tower_01", new SceneConfig(new List { "left1" }) }, { "Coral_42", new SceneConfig(new List { "right1" }) }, { "Coral_43", new SceneConfig(new List { "left1", "right1" }) }, { "Bellway_08", new SceneConfig(new List { "left1", "right1" }) }, { "Coral_32", new SceneConfig(new List { "left1", "right1", "top1" }) }, { "Coral_Judge_Arena", new SceneConfig(new List { "left1", "right1" }) }, { "Coral_10", new SceneConfig(new List { "left1", "right1" }) }, { "Song_19_entrance", new SceneConfig(new List { "left1", "right1", "right2" }) }, { "Song_01c", new SceneConfig(new List { "left1", "top1" }) }, { "Song_01", new SceneConfig(new List { "bot1", "right2", "top1" }) }, { "Under_07b", new SceneConfig(new List { "bot1", "left1" }) }, { "Song_01b", new SceneConfig(new List { "bot1", "right1", "top1" }) }, { "Song_05", new SceneConfig(new List { "left3", "left4", "left5", "right2", "right3", "right4" }) }, { "Song_02", new SceneConfig(new List { "left2", "right1" }) }, { "Ward_01", new SceneConfig(new List { "left1", "left2", "left3", "right1", "right2", "right3" }) }, { "Ward_02", new SceneConfig(new List { "bot1", "right1", "top1" }) }, { "Ward_02b", new SceneConfig(new List { "bot1", "right1" }) }, { "Ward_03", new SceneConfig(new List { "bot1", "left1", "top1" }) }, { "Ward_07", new SceneConfig(new List { "bot1" }) }, { "Ward_06", new SceneConfig(new List { "bot1", "top1" }) }, { "Song_07", new SceneConfig(new List { "right1" }) }, { "Song_27", new SceneConfig(new List { "left1", "right1", "top1" }) }, { "Song_20", new SceneConfig(new List { "left1", "left2", "right4", "right5", "right6", "top1" }) }, { "Bellway_City", new SceneConfig(new List { "left1", "right1" }) }, { "Library_13", new SceneConfig(new List { "left1", "right1", "right2" }) }, { "Song_11", new SceneConfig(new List { "left1", "left2", "left3", "left4", "right1", "right2", "right3" }) }, { "Song_15", new SceneConfig(new List { "left1", "right1" }) }, { "Song_17", new SceneConfig(new List { "left1", "right1" }) }, { "Hang_01", new SceneConfig(new List { "right1", "right2" }) }, { "Hang_02", new SceneConfig(new List { "left1", "right1" }) }, { "Hang_03", new SceneConfig(new List { "left1", "left2", "right1", "right2", "top1" }) }, { "Hang_10", new SceneConfig(new List { "left1", "right1" }) }, { "Hang_03_top", new SceneConfig(new List { "bot1" }) }, { "Hang_13", new SceneConfig(new List { "left1", "right1" }) }, { "Hang_08", new SceneConfig(new List { "bot1", "left1", "left2", "left3", "left4", "right1" }) }, { "Hang_09", new SceneConfig(new List { "right1" }) }, { "Hang_16", new SceneConfig(new List { "right1" }) }, { "Hang_06", new SceneConfig(new List { "bot1", "left1", "right1", "top1" }) }, { "Hang_06b", new SceneConfig(new List { "left1" }) }, { "Hang_17b", new SceneConfig(new List { "left1" }) }, { "Hang_04", new SceneConfig(new List { "left1", "right1" }) }, { "Hang_12", new SceneConfig(new List { "right1" }) }, { "Hang_07", new SceneConfig(new List { "bot1", "left1", "right1", "top1" }) }, { "Song_09", new SceneConfig(new List { "bot1", "right1", "top1" }) }, { "Song_09b", new SceneConfig(new List { "left1", "top1" }) }, { "Cog_05", new SceneConfig(new List { "left1", "right2", "top1" }) }, { "Cog_Dancers", new SceneConfig(new List { "bot1", "bot2", "left1", "right1", "top1" }) }, { "Cog_04", new SceneConfig(new List { "left2", "right2", "right3", "top1", "top2" }) }, { "Cog_Bench", new SceneConfig(new List { "left1" }) }, { "Song_25", new SceneConfig(new List { "bot1", "left1", "right1", "top1", "top2" }) }, { "Song_Enclave", new SceneConfig(new List { "bot1", "left1", "left2", "top1" }) }, { "Song_Enclave_Tube", new SceneConfig(new List { "bot1" }) }, { "Under_01", new SceneConfig(new List { "left1", "left2", "left3", "right1" }) }, { "Under_27", new SceneConfig(new List { "left1", "right1", "right2" }) }, { "Shellwood_22", new SceneConfig(new List { "right1" }) }, { "Shellwood_11b", new SceneConfig(new List { "right1" }) }, { "Under_01b", new SceneConfig(new List { "left1", "right1" }) }, { "Under_02", new SceneConfig(new List { "left1", "left3", "right1", "right2", "right3", "right4" }) }, { "Under_14", new SceneConfig(new List { "left1" }) }, { "Under_16", new SceneConfig(new List { "right1" }) }, { "Under_03b", new SceneConfig(new List { "left1", "right1" }) }, { "Under_07", new SceneConfig(new List { "left3", "right2" }) }, { "Under_07c", new SceneConfig(new List { "left2", "top1" }) }, { "Under_06", new SceneConfig(new List { "left1", "right1", "top1" }) }, { "Under_08", new SceneConfig(new List { "bot1", "top1" }) }, { "Under_05", new SceneConfig(new List { "left1", "left2", "left3", "right1", "right2", "right3" }) }, { "Under_11", new SceneConfig(new List { "left1", "right1" }) }, { "Under_23", new SceneConfig(new List { "bot1", "right1" }) }, { "Wisp_09", new SceneConfig(new List { "right1", "top1" }) }, { "Wisp_05", new SceneConfig(new List { "bot1", "left1" }) }, { "Wisp_02", new SceneConfig(new List { "left1", "right1", "top1" }) }, { "Belltown_08", new SceneConfig(new List { "right1" }) }, { "Wisp_04", new SceneConfig(new List { "bot1", "left1", "right1" }) }, { "Wisp_08", new SceneConfig(new List { "left1", "right1" }) }, { "Wisp_07", new SceneConfig(new List { "left1" }) }, { "Under_04", new SceneConfig(new List { "left1", "right1", "top1" }) }, { "Under_03c", new SceneConfig(new List { "left1", "left2", "right1" }) }, { "Under_03", new SceneConfig(new List { "right1" }) }, { "Under_10", new SceneConfig(new List { "left1", "right1" }) }, { "Under_12", new SceneConfig(new List { "left1" }) }, { "Under_13", new SceneConfig(new List { "left1", "left2", "left3", "left4", "right1", "right2", "right3" }) }, { "Under_22", new SceneConfig(new List { "right1" }) }, { "Under_21", new SceneConfig(new List { "right1" }) }, { "Under_19", new SceneConfig(new List { "left1", "top1" }) }, { "Under_19c", new SceneConfig(new List { "bot1", "left1", "left2" }) }, { "Under_19b", new SceneConfig(new List { "right1" }) }, { "Under_18", new SceneConfig(new List { "left1", "right1", "top1", "top2" }) }, { "Under_17", new SceneConfig(new List { "bot1", "bot2", "left1", "right1", "top1" }) }, { "Library_11b", new SceneConfig(new List { "left3", "right1" }) }, { "Library_11", new SceneConfig(new List { "left1", "left2", "left3", "right1", "right2" }) }, { "Library_13b", new SceneConfig(new List { "left1", "right1" }) }, { "Library_04", new SceneConfig(new List { "left1", "left2", "left3", "left4", "right1", "right2", "right3", "right4", "right5", "right6", "top1" }) }, { "Library_16", new SceneConfig(new List { "right1" }) }, { "Library_10", new SceneConfig(new List { "bot1", "left1" }) }, { "Library_12b", new SceneConfig(new List { "left1", "top1" }) }, { "Library_12", new SceneConfig(new List { "left1", "left2", "right1" }) }, { "Library_05", new SceneConfig(new List { "left1", "left2", "right1", "right2" }) }, { "Library_06", new SceneConfig(new List { "left1", "left2", "right1" }) }, { "Library_07", new SceneConfig(new List { "bot1", "bot2", "bot3", "left1", "left2", "top1" }) }, { "Library_08", new SceneConfig(new List { "left1", "right1" }) }, { "Library_09", new SceneConfig(new List { "bot1", "left1" }) }, { "Library_14", new SceneConfig(new List { "left1" }) }, { "Library_01", new SceneConfig(new List { "left1", "left2", "left3", "right1", "right2" }) }, { "Library_15", new SceneConfig(new List { "right1" }) }, { "Library_03", new SceneConfig(new List { "left1", "right1" }) }, { "Song_24", new SceneConfig(new List { "right1" }) }, { "Song_20b", new SceneConfig(new List { "bot1", "left2", "left4", "right2", "right3", "top1" }) }, { "Library_02", new SceneConfig(new List { "left1", "left2", "right1", "right2" }) }, { "Song_29", new SceneConfig(new List { "right1" }) }, { "Arborium_01", new SceneConfig(new List { "bot1", "left1", "left2", "left3", "right1", "right2", "right3", "right4", "right5" }) }, { "Cog_10", new SceneConfig(new List { "bot1" }) }, { "Cog_07", new SceneConfig(new List { "left1" }) }, { "Cog_06", new SceneConfig(new List { "left2", "right1" }) }, { "Arborium_04", new SceneConfig(new List { "left1", "right1" }) }, { "Arborium_03", new SceneConfig(new List { "left1", "left2", "left3", "left4", "right1", "right2" }) }, { "Arborium_02", new SceneConfig(new List { "left1", "right1" }) }, { "Arborium_05", new SceneConfig(new List { "right1", "top1" }) }, { "Arborium_06", new SceneConfig(new List { "bot1", "left1", "right1" }) }, { "Arborium_09", new SceneConfig(new List { "right1", "right2" }) }, { "Arborium_Tube", new SceneConfig(new List { "right1" }) }, { "Arborium_07", new SceneConfig(new List { "left1", "top1" }) }, { "Arborium_08", new SceneConfig(new List { "bot1", "left1" }) }, { "Song_13", new SceneConfig(new List { "left1", "right1" }) }, { "Song_18", new SceneConfig(new List { "bot1", "left1" }) }, { "Song_03", new SceneConfig(new List { "bot1", "top1" }) }, { "Song_04", new SceneConfig(new List { "bot1", "left1", "right1", "right2" }) }, { "Song_10", new SceneConfig(new List { "left1", "right1" }) }, { "Song_12", new SceneConfig(new List { "left1", "left2", "left3", "left4", "right1", "right2", "right3" }) }, { "Song_14", new SceneConfig(new List { "left1" }) }, { "Song_26", new SceneConfig(new List { "right1" }) }, { "Song_28", new SceneConfig(new List { "right1" }) }, { "Song_08", new SceneConfig(new List { "right1" }) }, { "Slab_01", new SceneConfig(new List { "left1", "right1" }) }, { "Slab_02", new SceneConfig(new List { "left1", "right1" }) }, { "Slab_03", new SceneConfig(new List { "left1", "left2", "left3", "left4", "left5", "left6", "left7", "left8", "right1", "right2", "right3", "right4", "right5", "right7", "right8", "right9" }) }, { "Slab_04", new SceneConfig(new List { "bot1", "right1", "top1" }) }, { "Slab_23", new SceneConfig(new List { "left1", "right1" }) }, { "Slab_21", new SceneConfig(new List { "left1", "left3", "top1" }) }, { "Slab_22", new SceneConfig(new List { "bot1", "bot2" }) }, { "Slab_Cell_Creature", new SceneConfig(new List { "left1" }) }, { "Slab_20", new SceneConfig(new List { "left1" }) }, { "Slab_17", new SceneConfig(new List { "left1" }) }, { "Slab_18", new SceneConfig(new List { "left1", "right1" }) }, { "Slab_16", new SceneConfig(new List { "bot1", "left1", "right1", "top1" }) }, { "Slab_15", new SceneConfig(new List { "bot1", "left1", "right1", "top1" }) }, { "Peak_01", new SceneConfig(new List { "left1", "left2", "left3", "left4", "right1", "right2", "right3", "right4", "top1", "top2", "top3", "top4" }) }, { "Slab_14", new SceneConfig(new List { "right1", "top1" }) }, { "Slab_13", new SceneConfig(new List { "bot1", "left1", "right1" }) }, { "Slab_05", new SceneConfig(new List { "bot1", "right1", "top1" }) }, { "Slab_06", new SceneConfig(new List { "left1", "top1" }) }, { "Peak_07", new SceneConfig(new List { "bot1", "bot2", "bot3", "bot4", "bot5", "top1", "top2" }) }, { "Peak_08b", new SceneConfig(new List { "bot4", "bot5", "bot6", "left1", "left2" }) }, { "Peak_08", new SceneConfig(new List { "bot1", "right1", "top1" }) }, { "Peak_05d", new SceneConfig(new List { "bot1" }) }, { "Peak_05", new SceneConfig(new List { "bot1", "right3", "top2" }) }, { "Peak_05c", new SceneConfig(new List { "left2", "right1" }) }, { "Peak_05e", new SceneConfig(new List { "left1", "right1", "right2" }) }, { "Peak_06b", new SceneConfig(new List { "left1" }) }, { "Peak_02", new SceneConfig(new List { "left1", "left2", "left3", "right1", "right2", "right3", "right4" }) }, { "Peak_04d", new SceneConfig(new List { "left1", "right1" }) }, { "Peak_04", new SceneConfig(new List { "left1", "right1" }) }, { "Bellway_Peak", new SceneConfig(new List { "left1", "left2", "right1", "right2", "top1" }) }, { "Bellway_Peak_02", new SceneConfig(new List { "left1" }) }, { "Peak_04c", new SceneConfig(new List { "right1", "right2" }) }, { "Peak_10", new SceneConfig(new List { "right1" }) }, { "Slab_08", new SceneConfig(new List { "left1" }) }, { "Slab_Cell_Quiet", new SceneConfig(new List { "left1", "left2" }) }, { "Slab_19b", new SceneConfig(new List { "left1", "right1" }) }, { "Slab_07", new SceneConfig(new List { "right1", "right2" }) }, { "Slab_12", new SceneConfig(new List { "left1" }) }, { "Slab_10c", new SceneConfig(new List { "left1" }) }, { "Slab_10b", new SceneConfig(new List { "left1" }) }, { "Cog_10_Destroyed", new SceneConfig(new List { "bot1", "left1" }) }, { "Cog_09_Destroyed", new SceneConfig(new List { "right1", "top1" }) }, { "Song_Tower_Destroyed", new SceneConfig(new List { "bot1", "top1" }) }, { "Arborium_10", new SceneConfig(new List { "left1" }) }, { "Arborium_11", new SceneConfig(new List { "left1", "right1" }) }, { "Aqueduct_01", new SceneConfig(new List { "left1", "right1" }) }, { "Aqueduct_02", new SceneConfig(new List { "left1", "left2", "left3", "right1", "right2", "right3" }) }, { "Bellway_Aqueduct", new SceneConfig(new List { "left1", "right1" }) }, { "Aqueduct_07", new SceneConfig(new List { "right1" }) }, { "Aqueduct_04", new SceneConfig(new List { "bot1", "right1" }) }, { "Aqueduct_03", new SceneConfig(new List { "left1", "right1", "top1" }) }, { "Aqueduct_06", new SceneConfig(new List { "bot1", "left1", "left2" }) }, { "Aqueduct_08", new SceneConfig(new List { "left1", "right1" }) }, { "Aqueduct_05", new SceneConfig(new List { "left1" }) }, { "Shadow_01", new SceneConfig(new List { "left1", "left2", "left3", "right1", "right2", "right3", "top1" }) }, { "Shadow_18", new SceneConfig(new List { "left1", "right1" }) }, { "Shadow_12", new SceneConfig(new List { "left1", "right1" }) }, { "Shadow_19", new SceneConfig(new List { "left1", "left2", "right1", "right2" }) }, { "Shadow_24", new SceneConfig(new List { "left1" }) }, { "Shadow_10", new SceneConfig(new List { "bot1", "left1", "right1" }) }, { "Shadow_25", new SceneConfig(new List { "left1" }) }, { "Shadow_08", new SceneConfig(new List { "left1", "top1" }) }, { "Shadow_27", new SceneConfig(new List { "left1", "right1" }) }, { "Shadow_26", new SceneConfig(new List { "left1", "left2", "right1", "right2" }) }, { "Shadow_16", new SceneConfig(new List { "left1", "right1" }) }, { "Shadow_15", new SceneConfig(new List { "right1", "right2" }) }, { "Shadow_14", new SceneConfig(new List { "right1", "right2" }) }, { "Shadow_02", new SceneConfig(new List { "left1", "left2", "right1", "right2", "right3" }) }, { "Shadow_11", new SceneConfig(new List { "left1", "right1" }) }, { "Shadow_13", new SceneConfig(new List { "left1" }) }, { "Shadow_23", new SceneConfig(new List { "left1" }) }, { "Shadow_03", new SceneConfig(new List { "left1", "right1", "top1" }) }, { "Shadow_21", new SceneConfig(new List { "bot1" }) }, { "Shadow_09", new SceneConfig(new List { "left1", "left2", "left3", "right1" }) }, { "Shadow_Weavehome", new SceneConfig(new List { "left1" }) }, { "Shadow_05", new SceneConfig(new List { "left1", "right1" }) }, { "Shadow_04b", new SceneConfig(new List { "left1", "right1" }) }, { "Shadow_04", new SceneConfig(new List { "left1", "right1", "right2", "top1" }) }, { "Shadow_20", new SceneConfig(new List { "bot1", "top1" }) }, { "Bellway_Shadow", new SceneConfig(new List { "left1" }) }, { "Tube_Hub", new SceneConfig(new List { "left1", "left3", "left4" }) }, { "Cradle_01", new SceneConfig(new List { "left1", "right1" }) }, { "Cradle_02", new SceneConfig(new List { "left2", "right1", "right2" }) }, { "Cradle_02b", new SceneConfig(new List { "right1" }) }, { "Cradle_03", new SceneConfig(new List { "left2", "right2" }) }, { "Crawl_04", new SceneConfig(new List { "left1", "right1" }) }, { "Crawl_02", new SceneConfig(new List { "left1", "left2", "right1", "right2", "right3" }) }, { "Crawl_06", new SceneConfig(new List { "left1" }) }, { "Crawl_01", new SceneConfig(new List { "left1", "right1" }) }, { "Crawl_03", new SceneConfig(new List { "bot1", "left1", "right1", "top1" }) }, { "Crawl_08", new SceneConfig(new List { "bot1" }) }, { "Crawl_05", new SceneConfig(new List { "right1" }) }, { "Crawl_03b", new SceneConfig(new List { "bot1", "right1", "top1" }) }, { "Crawl_07", new SceneConfig(new List { "bot1", "left1", "top1" }) }, { "Crawl_09", new SceneConfig(new List { "left1", "right1" }) }, { "Crawl_10", new SceneConfig(new List { "right1" }) }, { "Abyss_12", new SceneConfig(new List { "left1", "right2" }) }, { "Abyss_05", new SceneConfig(new List { "left2", "right1" }) }, { "Abyss_08", new SceneConfig(new List { "left1" }) }, { "Abyss_07", new SceneConfig(new List { "left1", "right1" }) }, { "Abyss_01", new SceneConfig(new List { "left1", "right2", "right3", "right4" }) }, { "Abyss_06", new SceneConfig(new List { "right1" }) }, { "Abyss_04", new SceneConfig(new List { "left1" }) }, { "Abyss_02b", new SceneConfig(new List { "left2", "right1", "top1" }) }, { "Abyss_02", new SceneConfig(new List { "left1", "right1" }) }, { "Abyss_03", new SceneConfig(new List { "left1", "left2" }) }, { "Abyss_13", new SceneConfig(new List { "left1", "right1", "top1" }) }, { "Abyss_11", new SceneConfig(new List { "bot1", "right1" }) }, { "Abyss_09", new SceneConfig(new List { "bot1", "top1" }) }, { "Greymoor_13", new SceneConfig(new List { "bot1", "left1", "right1" }) }, { "Clover_01b", new SceneConfig(new List { "right1" }) }, { "Clover_02c", new SceneConfig(new List { "left1", "left2", "right1" }) }, { "Clover_05c", new SceneConfig(new List { "left1", "left2", "right1", "right2", "right3" }) }, { "Clover_21", new SceneConfig(new List { "right1" }) }, { "Clover_16", new SceneConfig(new List { "right1", "top1" }) }, { "Clover_06", new SceneConfig(new List { "bot1", "bot2" }) }, { "Clover_19", new SceneConfig(new List { "left1", "top1" }) }, { "Clover_04b", new SceneConfig(new List { "left1", "left2", "right1" }) }, { "Clover_11", new SceneConfig(new List { "right1" }) }, { "Clover_03", new SceneConfig(new List { "left1", "left2", "right1" }) }, { "Clover_18", new SceneConfig(new List { "left1" }) }, { "Tut_04", new SceneConfig(new List { "left1", "right1" }) }, { "Cog_09", new SceneConfig(new List { "bot1" }) }, { "Cog_08", new SceneConfig(new List { "bot1", "top1" }) } }; private string lastEntryGateUsed; private string previousSceneName; private string currentSceneName = "(unknown)"; private bool isTransitioning; private bool loadRequested; public static bool SuppressTransitionPatch; private bool autoDiscoveryMode; private HashSet discoveredScenes = new HashSet(StringComparer.OrdinalIgnoreCase); private string discoveryFilePath; private readonly List preferredSceneSubstrings = new List(); private WaitForSeconds waitHalfSecond; private WaitForSeconds waitThirdSecond; private WaitForSeconds waitTenthSecond; private WaitForSeconds waitFifthSecond; private GUIStyle sceneLabelStyle; private string cachedSceneLabel = ""; private string lastRenderedScene = ""; private ConfigEntry cfgShowSceneLabel; private ConfigEntry cfgTeleportScene; private ConfigEntry cfgTeleportConfirm; private HashSet visitedScenesF6 = new HashSet(StringComparer.OrdinalIgnoreCase); public static bool EnableRandomization; private ConfigEntry cfgEnableRandomization; private ConfigEntry cfgInstantMusicTransition; private bool _apiInitialized; public static int CurrentSeed { get; internal set; } private void Awake() { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Expected O, but got Unknown //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Expected O, but got Unknown //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Expected O, but got Unknown //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Expected O, but got Unknown //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Expected O, but got Unknown //IL_02ab: Unknown result type (might be due to invalid IL or missing references) //IL_02ff: Unknown result type (might be due to invalid IL or missing references) //IL_0304: Unknown result type (might be due to invalid IL or missing references) //IL_0315: Expected O, but got Unknown //IL_034f: Unknown result type (might be due to invalid IL or missing references) //IL_0354: Unknown result type (might be due to invalid IL or missing references) //IL_0365: Expected O, but got Unknown log = ((BaseUnityPlugin)this).Logger; rng = new Random(); Scene activeScene = SceneManager.GetActiveScene(); currentSceneName = ((Scene)(ref activeScene)).name; waitHalfSecond = new WaitForSeconds(0.5f); waitThirdSecond = new WaitForSeconds(0.3f); waitTenthSecond = new WaitForSeconds(0.1f); waitFifthSecond = new WaitForSeconds(0.2f); sceneLabelStyle = new GUIStyle(); try { cfgShowSceneLabel = ((BaseUnityPlugin)this).Config.Bind("UI", "ShowSceneLabel", true, "Show small scene label in upper-left (toggle)"); } catch { } try { cfgTeleportScene = ((BaseUnityPlugin)this).Config.Bind("Teleport", "TeleportScene", "", "Scene name to teleport to (type exact scene name)"); } catch { } try { cfgTeleportConfirm = ((BaseUnityPlugin)this).Config.Bind("Teleport", "TeleportConfirm", false, "Set to true to teleport to scene in TeleportScene (resets automatically)"); } catch { } try { cfgEnableRandomization = ((BaseUnityPlugin)this).Config.Bind("General", "EnableRandomization", false, "Enable/disable scene transition randomization"); EnableRandomization = cfgEnableRandomization.Value; } catch { } try { cfgInstantMusicTransition = ((BaseUnityPlugin)this).Config.Bind("Audio", "InstantMusicTransition", true, "Instant music transition when changing scenes (disable fade in/out)"); } catch { } discoveryFilePath = Path.Combine(Paths.PluginPath, "discovered_exits.txt"); log.LogInfo((object)("RandomSceneLoader loaded. Current scene: " + currentSceneName + ". F5=random, F7=discover")); try { if (sceneConfigs != null) { discoveredScenes.UnionWith(sceneConfigs.Keys); log.LogInfo((object)$"Preloaded {discoveredScenes.Count} known scenes into discovered set"); } } catch { } try { string path = Path.Combine(Paths.PluginPath, "roomrando_connections.txt"); if (File.Exists(path)) { string[] array = File.ReadAllLines(path); foreach (string text in array) { if (text.StartsWith("#seed|", StringComparison.OrdinalIgnoreCase)) { string[] array2 = text.Split(new char[1] { '|' }); if (array2.Length >= 2 && int.TryParse(array2[1], out var result)) { CurrentSeed = result; log.LogInfo((object)$"Preloaded room random seed: {CurrentSeed}"); break; } } } } } catch (Exception ex) { log.LogWarning((object)("Failed to preload room random seed: " + ex.Message)); } if (autoDiscoveryMode) { log.LogInfo((object)("Auto-discovery mode enabled. RoomRando disabled. Results saved to: " + discoveryFilePath)); return; } try { new Harmony("com.yourname.randomsceneloader").PatchAll(); log.LogInfo((object)"Harmony patches applied successfully"); } catch (Exception ex2) { log.LogError((object)("Failed to apply Harmony patches: " + ex2.Message)); } try { if ((Object)(object)GameObject.Find("__RoomRando") == (Object)null) { GameObject val = new GameObject("__RoomRando"); val.AddComponent().Initialize(this); Object.DontDestroyOnLoad((Object)val); } } catch (Exception ex3) { log.LogError((object)("Failed to create RoomRando: " + ex3.Message)); } try { if ((Object)(object)GameObject.Find("__SeedManager") == (Object)null) { GameObject val2 = new GameObject("__SeedManager"); val2.AddComponent().Initialize(this); Object.DontDestroyOnLoad((Object)val2); } } catch (Exception ex4) { log.LogError((object)("Failed to create SeedManager: " + ex4.Message)); } GameObject obj7 = GameObject.Find("__RoomRando"); RoomRando rando = ((obj7 != null) ? obj7.GetComponent() : null); HKSilksong_RandomizerAPI.Initialize(this, rando); _apiInitialized = true; } public string GetCurrentSceneName() { return currentSceneName; } public void SetShowSceneLabel(bool show) { if (cfgShowSceneLabel != null) { cfgShowSceneLabel.Value = show; } } public bool GetShowSceneLabel() { return cfgShowSceneLabel?.Value ?? true; } public void SetLastEntryGate(string gateName) { lastEntryGateUsed = gateName; } public void TeleportToScene(string sceneName) { try { if (isTransitioning) { log.LogInfo((object)"Teleport skipped: transition already in progress"); return; } if (string.IsNullOrWhiteSpace(sceneName)) { log.LogWarning((object)"TeleportToScene called with empty scene name"); return; } string text = null; string scenePart = sceneName.Trim(); int num = scenePart.LastIndexOf(' '); if (num > 0) { text = scenePart.Substring(num + 1).Trim(); scenePart = scenePart.Substring(0, num).Trim(); if (string.IsNullOrEmpty(text)) { text = null; } } string text2 = null; SceneConfig value = null; string text3 = null; if (sceneConfigs != null && sceneConfigs.TryGetValue(scenePart, out value)) { text3 = scenePart; } else if (sceneConfigs != null) { List source = sceneConfigs.Keys.ToList(); string inputLetters = new string(scenePart.Where(char.IsLetter).ToArray()); string inputDigits = new string(scenePart.Where(char.IsDigit).ToArray()); text3 = source.FirstOrDefault((string s) => string.Equals(s, scenePart, StringComparison.OrdinalIgnoreCase)); if (text3 == null && !string.IsNullOrEmpty(inputLetters) && !string.IsNullOrEmpty(inputDigits)) { text3 = source.FirstOrDefault(delegate(string s) { string text4 = new string(s.Where(char.IsDigit).ToArray()); string text5 = new string(s.Where(char.IsLetter).ToArray()); return !string.IsNullOrEmpty(text4) && text5.IndexOf(inputLetters, StringComparison.OrdinalIgnoreCase) >= 0 && text4.IndexOf(inputDigits, StringComparison.OrdinalIgnoreCase) >= 0; }); } if (text3 == null && !string.IsNullOrEmpty(inputLetters) && string.IsNullOrEmpty(inputDigits)) { text3 = source.FirstOrDefault((string s) => string.IsNullOrEmpty(new string(s.Where(char.IsDigit).ToArray())) && s.IndexOf(inputLetters, StringComparison.OrdinalIgnoreCase) >= 0); } if (text3 == null) { text3 = source.FirstOrDefault((string s) => s.IndexOf(scenePart, StringComparison.OrdinalIgnoreCase) >= 0); } } if (text3 != null && sceneConfigs.TryGetValue(text3, out value)) { if (text != null) { if (value.Exits != null && value.Exits.Contains(text, StringComparer.OrdinalIgnoreCase)) { text2 = text; } else { log.LogWarning((object)("TeleportToScene: entry '" + text + "' not valid for scene '" + text3 + "', will pick random.")); if (value.Exits != null && value.Exits.Count > 0) { text2 = value.Exits[rng.Next(value.Exits.Count)]; } } } else if (value.Exits != null && value.Exits.Count > 0) { text2 = value.Exits[rng.Next(value.Exits.Count)]; } log.LogInfo((object)("Teleport: " + scenePart + " -> " + text3 + " (entry '" + (text2 ?? "(null)") + "')")); } else { log.LogWarning((object)("TeleportToScene: scene '" + scenePart + "' not found in sceneConfigs. Attempting direct load.")); text3 = scenePart; if (text != null) { text2 = text; } } SuppressTransitionPatch = true; ((MonoBehaviour)this).StartCoroutine(LoadSceneCoroutine(text3, text2)); } catch (Exception arg) { log.LogError((object)$"TeleportToScene failed: {arg}"); } } private void LoadRandomUniqueScene() { if (isTransitioning) { log.LogInfo((object)"LoadRandomUniqueScene skipped: transition already in progress"); return; } List list = sceneConfigs.Keys.Where((string k) => !string.Equals(k, currentSceneName, StringComparison.OrdinalIgnoreCase) && !visitedScenesF6.Contains(k)).ToList(); if (list.Count == 0) { log.LogInfo((object)"F6: All scenes have been visited already (or no candidates available). Clearing visited list."); visitedScenesF6.Clear(); list = sceneConfigs.Keys.Where((string k) => !string.Equals(k, currentSceneName, StringComparison.OrdinalIgnoreCase)).ToList(); if (list.Count == 0) { return; } } List list2 = null; try { List lowered = (from s in preferredSceneSubstrings where !string.IsNullOrWhiteSpace(s) select s.ToLower()).ToList(); list2 = list.Where((string c) => lowered.Any((string sub) => c.ToLower().Contains(sub))).ToList(); } catch { } List list3 = ((list2 != null && list2.Count > 0) ? list2 : list); string text = list3[rng.Next(list3.Count)]; SceneConfig sceneConfig = (sceneConfigs.ContainsKey(text) ? sceneConfigs[text] : null); string text2 = null; if (sceneConfig != null && sceneConfig.Exits != null && sceneConfig.Exits.Count > 0) { text2 = sceneConfig.Exits[rng.Next(sceneConfig.Exits.Count)]; } visitedScenesF6.Add(text); lastEntryGateUsed = text2; log.LogInfo((object)("[F6] Selected unique random scene: " + text + " (enter via gate '" + (text2 ?? "(null)") + "')")); SuppressTransitionPatch = true; ((MonoBehaviour)this).StartCoroutine(LoadSceneCoroutine(text, text2)); } private void LoadRandomScene() { if (isTransitioning) { log.LogInfo((object)"LoadRandomScene skipped: transition already in progress"); return; } loadRequested = true; List list = sceneConfigs.Keys.Where((string k) => !string.Equals(k, currentSceneName, StringComparison.OrdinalIgnoreCase)).ToList(); if (list.Count == 0) { log.LogWarning((object)"No candidate scenes found in sceneConfigs."); return; } List list2 = null; try { List lowered = (from s in preferredSceneSubstrings where !string.IsNullOrWhiteSpace(s) select s.ToLower()).ToList(); list2 = list.Where((string c) => lowered.Any((string sub) => c.ToLower().Contains(sub))).ToList(); } catch { } List list3 = ((list2 != null && list2.Count > 0) ? list2 : list); string text = list3[rng.Next(list3.Count)]; SceneConfig sceneConfig = (sceneConfigs.ContainsKey(text) ? sceneConfigs[text] : null); string text2 = null; if (sceneConfig != null && sceneConfig.Exits != null && sceneConfig.Exits.Count > 0) { text2 = sceneConfig.Exits[rng.Next(sceneConfig.Exits.Count)]; } lastEntryGateUsed = text2; log.LogInfo((object)("Selected random scene: " + text + " (enter via gate '" + (text2 ?? "(null)") + "')")); SuppressTransitionPatch = true; ((MonoBehaviour)this).StartCoroutine(LoadSceneCoroutine(text, text2)); } [IteratorStateMachine(typeof(d__40))] private IEnumerator LoadSceneCoroutine(string sceneName, string entryGate) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__40(0) { <>4__this = this, sceneName = sceneName, entryGate = entryGate }; } private void OnSceneLoaded(Scene scene, LoadSceneMode mode) { currentSceneName = ((Scene)(ref scene)).name; cachedSceneLabel = Locale.Get("Scene: ") + currentSceneName; lastRenderedScene = currentSceneName; log.LogInfo((object)("Scene loaded: " + currentSceneName)); if (autoDiscoveryMode) { ((MonoBehaviour)this).StartCoroutine(AutoDiscoverAfterLoad()); } else { ((MonoBehaviour)this).StartCoroutine(DetectEntryGateAfterLoad()); } if (cfgInstantMusicTransition != null && cfgInstantMusicTransition.Value) { SetMusicRegionsInstantTransition(); } if (_apiInitialized && ((Scene)(ref scene)).name != "Menu_Title" && ((Scene)(ref scene)).name != "Menu" && ((Scene)(ref scene)).name != "Loading" && (Object)(object)HeroController.instance != (Object)null) { HKSilksong_RandomizerAPI.MarkGameReady(); } } [IteratorStateMachine(typeof(d__42))] private IEnumerator AutoDiscoverAfterLoad() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__42(0) { <>4__this = this }; } private void DiscoverGatesInCurrentScene() { //IL_0100: Unknown result type (might be due to invalid IL or missing references) log.LogInfo((object)"=== DISCOVERING GATES ==="); log.LogInfo((object)("Scene: " + currentSceneName)); try { List list = Object.FindObjectsByType((FindObjectsSortMode)0).Where(delegate(GameObject obj) { string text2 = ((Object)obj).name.ToLower(); return (text2.StartsWith("left") || text2.StartsWith("right") || text2.StartsWith("top") || text2.StartsWith("bot")) && text2.Length <= 6 && char.IsDigit(text2[text2.Length - 1]); }).ToList(); log.LogInfo((object)$"Found {list.Count} gates:"); IOrderedEnumerable> orderedEnumerable = from g in list group g by ((Object)g).name into g orderby g.Key select g; foreach (IGrouping item in orderedEnumerable) { log.LogInfo((object)$" - {item.Key} (count: {item.Count()}, pos: {item.First().transform.position})"); } List list2 = orderedEnumerable.Select((IGrouping g) => g.Key).ToList(); if (list2.Count > 0) { string text = "{ \"" + currentSceneName + "\", new SceneConfig(new List { " + string.Join(", ", list2.Select((string e) => "\"" + e + "\"")) + " }) },"; log.LogInfo((object)("Suggested: " + text)); if (autoDiscoveryMode) { SaveDiscoveryToFile(currentSceneName, list2, text); } } } catch (Exception ex) { log.LogError((object)("DiscoverGates failed: " + ex.Message)); } } private void SaveDiscoveryToFile(string sceneName, List exitNames, string configLine) { try { if (!discoveredScenes.Contains(sceneName)) { if (sceneConfigs != null && sceneConfigs.ContainsKey(sceneName)) { log.LogInfo((object)("Discovery skipped for " + sceneName + ": already exists in sceneConfigs.")); discoveredScenes.Add(sceneName); return; } discoveredScenes.Add(sceneName); File.AppendAllText(discoveryFilePath, string.Format("\n[{0:yyyy-MM-dd HH:mm:ss}] {1}\n Gates found: {2}\n Config: {3}\n", DateTime.Now, sceneName, string.Join(", ", exitNames), configLine)); log.LogInfo((object)$"Saved discovery for {sceneName} to file ({exitNames.Count} exits)"); } } catch (Exception ex) { log.LogError((object)("Failed to save discovery to file: " + ex.Message)); } } [IteratorStateMachine(typeof(d__45))] private IEnumerator DetectEntryGateAfterLoad() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__45(0) { <>4__this = this }; } private void OnActiveSceneChanged(Scene prev, Scene next) { if (((Scene)(ref next)).name == "Menu_Title" || ((Scene)(ref next)).name == "Quit_To_Menu") { lastEntryGateUsed = null; return; } previousSceneName = currentSceneName; currentSceneName = ((Scene)(ref next)).name; try { GameObject obj = GameObject.Find("__RoomRando"); RoomRando roomRando = ((obj != null) ? obj.GetComponent() : null); if ((Object)(object)roomRando != (Object)null && !string.IsNullOrEmpty(previousSceneName) && !string.IsNullOrEmpty(lastEntryGateUsed)) { roomRando.OnExitUsed(previousSceneName, lastEntryGateUsed); } } catch (Exception ex) { log.LogWarning((object)("RoomRando notify failed: " + ex.Message)); } lastEntryGateUsed = null; } private void OnGUI() { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0036: 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_0041: 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_0058: Expected O, but got Unknown //IL_00bd: Unknown result type (might be due to invalid IL or missing references) try { if (sceneLabelStyle.normal.textColor != Color.white || sceneLabelStyle.fontSize != 14) { GUIStyle val = new GUIStyle(GUI.skin.label); val.normal.textColor = Color.white; val.fontSize = 14; sceneLabelStyle = val; } if (cfgShowSceneLabel == null || cfgShowSceneLabel.Value) { if (currentSceneName != lastRenderedScene) { cachedSceneLabel = Locale.Get("Scene: ") + currentSceneName; lastRenderedScene = currentSceneName; } GUI.Label(new Rect(8f, 8f, 300f, 20f), cachedSceneLabel, sceneLabelStyle); } } catch { } } private void SetMusicRegionsInstantTransition() { //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) try { Type type = Type.GetType("MusicRegion, Assembly-CSharp"); if (type == null) { return; } Object[] array = Resources.FindObjectsOfTypeAll(type); FieldInfo field = type.GetField("enterTransitionTime"); FieldInfo field2 = type.GetField("exitTransitionTime"); FieldInfo field3 = type.GetField("delay"); if (field == null || field2 == null) { return; } int num = 0; Object[] array2 = array; foreach (Object val in array2) { if (val == (Object)null) { continue; } Object obj = ((val is Component) ? val : null); GameObject val2 = ((obj != null) ? ((Component)obj).gameObject : null); if ((Object)(object)val2 != (Object)null && val2.scene == SceneManager.GetActiveScene()) { field.SetValue(val, 0f); field2.SetValue(val, 0f); if (field3 != null) { field3.SetValue(val, 0); } num++; } } if (num > 0) { log.LogInfo((object)$"Set {num} MusicRegion transition times to 0."); } } catch (Exception ex) { log.LogWarning((object)("SetMusicRegionsInstantTransition error: " + ex.Message)); } } } public class RoomRando : MonoBehaviour { private Dictionary connections = new Dictionary(StringComparer.OrdinalIgnoreCase); private List availableScenes = new List(); private bool enableRandomization = true; private RandomSceneLoader sceneLoader; private string saveFilePath; private Random rng; private int generationSeed; private bool enableMapGeneration; private List<(string beforeScene, string afterScene)> precedencePairs = new List<(string, string)>(); private bool forceExactSeed; private static readonly HashSet BlacklistedExits = new HashSet(StringComparer.OrdinalIgnoreCase) { "Bone_11_top1", "Bellshrine_right1", "Bellshrine_05_right1", "Dock_06_Church_right1", "Bone_East_09_top1", "Bellshrine_02_left1", "Dust_04_right1", "Dust_05_right1", "Dust_06_left1", "Shadow_20_bot1", "Bellshrine_03_right1", "Shellwood_19_left1", "Shellwood_01b_right2", "Bellshrine_02_right1", "Dust_06_right1", "Mosstown_03_top1", "Coral_10_left1", "Song_27_left1", "Dock_01_right1", "Dock_01_right2", "Bone_East_14_right1", "Bone_East_14_right2", "Greymoor_01_right1", "Greymoor_01_right2", "Dust_02_right1", "Dust_02_right2", "Dust_04_left1", "Dust_04_left2", "Song_25_top1", "Song_25_top2", "Arborium_05_top1", "Hang_07_top1", "Hang_07_left1", "Slab_02_left1", "Slab_05_right1", "Cog_06_right1", "Library_11b_right1", "Dock_03_bot1", "Dock_03c_top1", "Dock_03c_left2", "Dock_02_left1", "Shellwood_02_right2", "Shellwood_01_left2", "Dust_Chef_left1", "Song_11_left4", "Slab_03_right1", "Slab_03_right2", "Slab_03_right5", "Slab_03_right7", "Slab_03_left6", "Under_05_left2", "Under_02_right4", "Under_02_left1", "Bone_East_12_right1", "Shadow_27_right1", "Halfway_01_right1", "Wisp_03_top1", "Arborium_01_right1", "Arborium_04_left1", "Library_13_left1", "Hang_03_right2", "Aqueduct_02_right3", "Song_19_entrance_left1", "Weave_04_right2", "Slab_16_right1", "Bone_East_04_left1", "Bone_East_10_right1", "Bone_East_18c_left1", "Greymoor_05_left1", "Hang_08_left1", "Arborium_08_left1" }; private static readonly HashSet SkipExits = new HashSet(StringComparer.OrdinalIgnoreCase) { "Bone_01_bot1", "Bone_01_left4", "Bone_01_right3", "Aspid_01_bot8", "Aspid_01_left2", "Aspid_01_right4", "Crawl_03b_right1", "Shellwood_10_left3", "Shellwood_10_right3", "Dust_02_left2", "Dust_02_right2", "Coral_24_left1", "Coral_24_right1", "Coral_35b_bot1", "Coral_35b_left5", "Coral_35b_right2", "Peak_07_bot5", "Peak_07_top2", "Peak_01_left4", "Peak_01_right4", "Peak_01_top4", "Peak_02_left3", "Peak_02_right4", "Peak_04_left1", "Peak_04_right1", "Peak_05_bot1", "Peak_05_right3", "Peak_05_top2", "Peak_05c_left2", "Peak_05c_right1", "Peak_05e_left1", "Peak_05e_right2", "Song_05_left5", "Song_05_right4", "Song_11_right3", "Song_01c" }; private static readonly Dictionary SingleExitPairedCounts = new Dictionary(StringComparer.OrdinalIgnoreCase); private static readonly HashSet HighPriorityRooms = new HashSet(StringComparer.OrdinalIgnoreCase) { "Bonegrave", "Shellwood_04c", "Coral_02", "Coral_35", "Coral_32", "Coral_24", "Coral_23", "Coral_25", "Dust_03", "Dust_06", "Shadow_05", "Shadow_08", "Shadow_09", "Shadow_16", "Shadow_10", "Shadow_19", "Shadow_24", "Shadow_01", "Shadow_14", "Aqueduct_04", "Aqueduct_03", "Aqueduct_01", "Arborium_11", "Arborium_09", "Arborium_05", "Song_Enclave", "Song_09b", "Song_11", "Song_01", "Song_19_entrance", "Under_02", "Under_07c", "Under_27", "Under_17", "Under_10", "Under_19c", "Library_11", "Library_12", "Library_12b", "Library_02", "Song_20b", "Song_20", "Library_03", "Slab_06", "Slab_05", "Slab_19b", "Slab_15", "Coral_27", "Coral_44", "Abyss_13", "Abyss_01", "Cog_08", "Cog_09", "Ward_02", "Wisp_05", "Wisp_08", "Slab_07", "Weave_08", "Song_03", "Abyss_05", "Cradle_02", "Hang_02", "Hang_03", "Hang_13", "Hang_10", "Hang_16", "Bone_East_15", "Cog_04", "Arborium_08", "Under_23", "Bellway_03", "Dock_15", "Dust_04" }; private RoomRandomConfig _cachedConfig; private bool _hasPendingConfig; private bool _isInitialized; public void Initialize(RandomSceneLoader loader) { sceneLoader = loader; if ((Object)(object)sceneLoader != (Object)null) { foreach (string key in sceneLoader.sceneConfigs.Keys) { if (key.StartsWith("Peak_", StringComparison.OrdinalIgnoreCase)) { HighPriorityRooms.Add(key); } if (key.StartsWith("Ward_", StringComparison.OrdinalIgnoreCase)) { HighPriorityRooms.Add(key); } if (key.StartsWith("Clover_", StringComparison.OrdinalIgnoreCase)) { HighPriorityRooms.Add(key); } } } _isInitialized = true; if (_hasPendingConfig && _cachedConfig != null) { ApplyConfig(); } else { InitializeRoomRando(); } } public void SetConfig(RoomRandomConfig config) { _cachedConfig = config; _hasPendingConfig = true; if (_isInitialized) { ApplyConfig(); } } private void ApplyConfig() { if (_cachedConfig != null) { generationSeed = _cachedConfig.Seed; enableRandomization = _cachedConfig.EnableRandomization; enableMapGeneration = _cachedConfig.EnableMapGeneration; precedencePairs = new List<(string, string)>(_cachedConfig.PrecedencePairs); _hasPendingConfig = false; if (enableRandomization) { InitializeRoomRando(); } } } private void InitializeRoomRando() { try { availableScenes = sceneLoader.sceneConfigs.Keys.ToList(); } catch (Exception ex) { Debug.LogWarning((object)("RoomRando: failed to populate availableScenes from sceneLoader: " + ex.Message)); } InitializePredefinedConnections(); try { saveFilePath = Path.Combine(Paths.PluginPath, "roomrando_connections.txt"); } catch { saveFilePath = "roomrando_connections.txt"; } Debug.Log((object)$"RoomRando: saveFilePath set to '{saveFilePath}' (exists={File.Exists(saveFilePath)})"); if (!enableRandomization) { return; } if (TryLoadConnectionsFromFile()) { bool flag = false; foreach (KeyValuePair connection in connections) { int num = connection.Key.LastIndexOf('_'); if (num > 0) { string sceneA = connection.Key.Substring(0, num); string exitA = connection.Key.Substring(num + 1); string item = connection.Value.Item1; string item2 = connection.Value.Item2; if (!IsConnectionAllowed(sceneA, exitA, item, item2)) { flag = true; break; } } } if (flag) { Debug.LogWarning((object)"RoomRando: Loaded connections conflict with current rules. Forcing regeneration..."); connections.Clear(); GenerateAllConnectionsAtStart(); SaveConnectionsToFile(); } else { Debug.Log((object)("RoomRando: loaded randomized connections from " + saveFilePath)); } } else { GenerateAllConnectionsAtStart(); SaveConnectionsToFile(); } if (enableMapGeneration) { TryGenerateMap(); } } private void GenerateAllConnectionsAtStart() { int num = ((generationSeed == 0) ? Environment.TickCount : generationSeed); int finalConnectionCount = 0; RandomSceneLoader.SceneConfig value5; List list = availableScenes.Where((string s) => (Object)(object)sceneLoader != (Object)null && sceneLoader.sceneConfigs.TryGetValue(s, out value5) && value5.Exits != null && value5.Exits.Count > 0).ToList(); List list2 = new List(); List list3 = new List(); List list4 = new List(); foreach (string item4 in list) { if (GetActualExitCount(item4) == 1) { list4.Add(item4); } else if (HighPriorityRooms.Contains(item4)) { list3.Add(item4); } else { list2.Add(item4); } } Debug.Log((object)$"RoomRando: 普通房间(>1出口)数量: {list2.Count}, 高房间(>1出口)数量: {list3.Count}, 单出口房间数量: {list4.Count}"); bool flag = false; int num2 = (forceExactSeed ? 1 : 8); for (int i = 0; i < num2; i++) { if (flag) { break; } int num3 = (forceExactSeed ? num : (num + i)); rng = new Random(num3); connections.Clear(); finalConnectionCount = 0; Debug.Log((object)$"RoomRando: generation attempt {i + 1}/{num2} using seed={num3}"); InitializePredefinedConnections(); Dictionary> dictionary = BuildFreeExits(list2); SingleExitPairedCounts.Clear(); foreach (KeyValuePair item5 in connections.ToList()) { int num4 = item5.Key.LastIndexOf('_'); if (num4 > 0) { string key = item5.Key.Substring(0, num4); string item = item5.Key.Substring(num4 + 1); if (dictionary.ContainsKey(key)) { dictionary[key].Remove(item); } } } try { foreach (var (text, text2) in precedencePairs) { if (!string.IsNullOrEmpty(text) && !string.IsNullOrEmpty(text2) && dictionary.ContainsKey(text) && dictionary.ContainsKey(text2) && dictionary[text].Count > 0 && dictionary[text2].Count > 0) { ConnectScenesWithFreeExits(text, text2, dictionary); } } } catch (Exception ex) { Debug.LogWarning((object)("precedencePairs error: " + ex.Message)); } List list5 = list2.OrderBy((string _) => rng.Next()).ToList(); for (int j = 1; j < list5.Count; j++) { string text3 = null; string text4 = null; for (int num5 = j - 1; num5 >= 0; num5--) { if (dictionary[list5[num5]].Count > 0) { text3 = list5[num5]; break; } } for (int k = j; k < list5.Count; k++) { if (dictionary[list5[k]].Count > 0) { text4 = list5[k]; break; } } if (text3 != null && text4 != null && !string.Equals(text3, text4, StringComparison.OrdinalIgnoreCase)) { ConnectScenesWithFreeExits(text3, text4, dictionary); } } Dictionary> neighbors = new Dictionary>(StringComparer.OrdinalIgnoreCase); foreach (KeyValuePair connection in connections) { int num6 = connection.Key.LastIndexOf('_'); if (num6 > 0) { AddNeighborEdge(neighbors, connection.Key.Substring(0, num6), connection.Value.Item1); } } List<(string, string)> source = dictionary.SelectMany((KeyValuePair> kv) => kv.Value.Select((string e) => (kv.Key, e))).ToList(); bool flag2 = false; int num7 = 6; for (int l = 0; l < num7; l++) { if (flag2) { break; } List<(string, string)> list6 = source.OrderBy(((string, string) _) => rng.Next()).ToList(); HashSet hashSet = new HashSet(); List<((string, string), (string, string))> list7 = new List<((string, string), (string, string))>(); bool flag3 = false; for (int m = 0; m < list6.Count; m++) { if (hashSet.Contains(m)) { continue; } (string, string) tuple2 = list6[m]; int num8 = -1; int num9 = int.MinValue; for (int num10 = m + 1; num10 < list6.Count; num10++) { if (hashSet.Contains(num10)) { continue; } (string, string) tuple3 = list6[num10]; if (!string.Equals(tuple2.Item1, tuple3.Item1, StringComparison.OrdinalIgnoreCase)) { int num11 = 0; if (!IsOriginalSingle(tuple3.Item1)) { num11 += 20; } if (!IsOriginalSingle(tuple2.Item1)) { num11 += 10; } if (IsOriginalSingle(tuple2.Item1) && IsOriginalSingle(tuple3.Item1)) { num11 -= 1000; } neighbors.TryGetValue(tuple2.Item1, out var value); neighbors.TryGetValue(tuple3.Item1, out var value2); int num12 = value?.Count((string n) => IsLeaf(neighbors, n)) ?? 0; int num13 = value2?.Count((string n) => IsLeaf(neighbors, n)) ?? 0; bool flag4 = IsLeaf(neighbors, tuple3.Item1); bool flag5 = IsLeaf(neighbors, tuple2.Item1); if (num12 + (flag4 ? 1 : 0) > 1) { num11 -= 50; } if (num13 + (flag5 ? 1 : 0) > 1) { num11 -= 50; } if (num11 > num9) { num9 = num11; num8 = num10; } } } if (num8 < 0) { flag3 = true; break; } hashSet.Add(m); hashSet.Add(num8); list7.Add((list6[m], list6[num8])); AddNeighborEdge(neighbors, list6[m].Item1, list6[num8].Item1); } if (flag3) { neighbors.Clear(); foreach (KeyValuePair connection2 in connections) { int num14 = connection2.Key.LastIndexOf('_'); if (num14 > 0) { AddNeighborEdge(neighbors, connection2.Key.Substring(0, num14), connection2.Value.Item1); } } continue; } bool flag6 = false; foreach (var (tuple5, tuple6) in list7) { if (IsOriginalSingle(tuple5.Item1) && IsOriginalSingle(tuple6.Item1)) { flag6 = true; break; } } Dictionary dictionary2 = new Dictionary(StringComparer.OrdinalIgnoreCase); foreach (KeyValuePair> item6 in neighbors) { dictionary2[item6.Key] = item6.Value.Count((string n) => IsLeaf(neighbors, n)); } if (dictionary2.Values.Any((int c) => c > 1)) { flag6 = true; } if (flag6) { neighbors.Clear(); foreach (KeyValuePair connection3 in connections) { int num15 = connection3.Key.LastIndexOf('_'); if (num15 > 0) { AddNeighborEdge(neighbors, connection3.Key.Substring(0, num15), connection3.Value.Item1); } } continue; } foreach (var item7 in list7) { (string, string) item2 = item7.Item1; (string, string) item3 = item7.Item2; string key2 = MakeKey(item2.Item1, item2.Item2); string key3 = MakeKey(item3.Item1, item3.Item2); if (!connections.ContainsKey(key2) && !connections.ContainsKey(key3)) { connections[key2] = (item3.Item1, item3.Item2); connections[key3] = (item2.Item1, item2.Item2); dictionary[item2.Item1].Remove(item2.Item2); dictionary[item3.Item1].Remove(item3.Item2); finalConnectionCount++; } } flag2 = true; } if (!flag2) { Debug.LogWarning((object)"第一阶段智能配对失败,使用贪心配对"); List<(string, string)> list8 = source.OrderBy(((string, string) _) => rng.Next()).ToList(); for (int num16 = 0; num16 + 1 < list8.Count; num16 += 2) { (string, string) tuple7 = list8[num16]; (string, string) tuple8 = list8[num16 + 1]; if (!string.Equals(tuple7.Item1, tuple8.Item1, StringComparison.OrdinalIgnoreCase)) { string key4 = MakeKey(tuple7.Item1, tuple7.Item2); string key5 = MakeKey(tuple8.Item1, tuple8.Item2); if (!connections.ContainsKey(key4) && !connections.ContainsKey(key5)) { connections[key4] = (tuple8.Item1, tuple8.Item2); connections[key5] = (tuple7.Item1, tuple7.Item2); finalConnectionCount++; dictionary[tuple7.Item1].Remove(tuple7.Item2); dictionary[tuple8.Item1].Remove(tuple8.Item2); } } } } List<(string, string)> list9 = dictionary.SelectMany((KeyValuePair> kv) => kv.Value.Select((string e) => (kv.Key, e))).ToList(); if (list9.Count > 0) { Debug.LogWarning((object)$"第一阶段剩余 {list9.Count} 个未配对出口"); } Dictionary> dictionary3 = BuildFreeExits(list3); List<(string, string)> list10 = new List<(string, string)>(); list10.AddRange(list9); foreach (KeyValuePair> item8 in dictionary3) { foreach (string item9 in item8.Value) { list10.Add((item8.Key, item9)); } } if (list10.Count > 0) { Debug.Log((object)$"第二阶段开始,共 {list10.Count} 个出口"); PairExitsSimple(list10); } neighbors.Clear(); foreach (KeyValuePair connection4 in connections) { int num17 = connection4.Key.LastIndexOf('_'); if (num17 > 0) { AddNeighborEdge(neighbors, connection4.Key.Substring(0, num17), connection4.Value.Item1); } } bool flag7 = false; foreach (KeyValuePair> item10 in neighbors) { if (item10.Value.Count((string n) => IsLeaf(neighbors, n)) > 3) { flag7 = true; break; } } if (!flag7) { flag = true; generationSeed = num3; RandomSceneLoader.CurrentSeed = generationSeed; Debug.Log((object)$"成功,种子={num3}"); } else { Debug.LogWarning((object)$"尝试 {i + 1} 失败:叶子节点过多"); } } if (!flag) { Debug.LogWarning((object)$"所有尝试失败,使用最后一次结果,种子={generationSeed}"); } Debug.Log((object)$"生成了 {finalConnectionCount} 对双向连接 ({connections.Count} 条单向)"); static void AddNeighborEdge(Dictionary> graph, string s1, string s2) { if (!string.Equals(s1, s2, StringComparison.OrdinalIgnoreCase)) { if (!graph.ContainsKey(s1)) { graph[s1] = new HashSet(StringComparer.OrdinalIgnoreCase); } if (!graph.ContainsKey(s2)) { graph[s2] = new HashSet(StringComparer.OrdinalIgnoreCase); } graph[s1].Add(s2); graph[s2].Add(s1); } } void ConnectScenesWithFreeExits(string scA, string scB, Dictionary> freeExits) { if (freeExits.ContainsKey(scA) && freeExits.ContainsKey(scB) && freeExits[scA].Count != 0 && freeExits[scB].Count != 0) { string text5 = freeExits[scA][rng.Next(freeExits[scA].Count)]; string text6 = freeExits[scB][rng.Next(freeExits[scB].Count)]; if (IsConnectionAllowed(scA, text5, scB, text6)) { string key6 = MakeKey(scA, text5); string key7 = MakeKey(scB, text6); if (!connections.ContainsKey(key6) && !connections.ContainsKey(key7)) { connections[key6] = (scB, text6); connections[key7] = (scA, text5); freeExits[scA].Remove(text5); freeExits[scB].Remove(text6); finalConnectionCount++; UpdateSingleExitCount(scA, scB); } } } } static bool IsLeaf(Dictionary> graph, string scene) { if (graph.TryGetValue(scene, out var value3)) { return value3.Count == 1; } return false; } bool IsOriginalSingle(string scene) { if (sceneLoader.sceneConfigs.TryGetValue(scene, out var value4) && value4.Exits != null) { return value4.Exits.Count == 1; } return false; } } private Dictionary> BuildFreeExits(List scenes) { Dictionary> dictionary = new Dictionary>(StringComparer.OrdinalIgnoreCase); foreach (string scene in scenes) { List list = new List(sceneLoader.sceneConfigs[scene].Exits); foreach (string blacklistedExit in BlacklistedExits) { int num = blacklistedExit.LastIndexOf('_'); if (num > 0) { string a = blacklistedExit.Substring(0, num); string item = blacklistedExit.Substring(num + 1); if (string.Equals(a, scene, StringComparison.OrdinalIgnoreCase)) { list.Remove(item); } } } dictionary[scene] = list; } return dictionary; } private void PairExitsSimple(List<(string scene, string exit)> exitPool) { List<(string, string)> list = exitPool.OrderBy(((string scene, string exit) _) => rng.Next()).ToList(); HashSet hashSet = new HashSet(); for (int i = 0; i < list.Count; i++) { if (hashSet.Contains(i)) { continue; } (string, string) tuple = list[i]; int num = -1; for (int j = i + 1; j < list.Count; j++) { if (!hashSet.Contains(j)) { (string, string) tuple2 = list[j]; if (!string.Equals(tuple.Item1, tuple2.Item1, StringComparison.OrdinalIgnoreCase) && (!(tuple.Item1 == "Tut_01") || !HighPriorityRooms.Contains(tuple2.Item1)) && (!(tuple2.Item1 == "Tut_01") || !HighPriorityRooms.Contains(tuple.Item1))) { num = j; break; } } } if (num >= 0) { hashSet.Add(i); hashSet.Add(num); (string, string) tuple3 = list[num]; string key = MakeKey(tuple.Item1, tuple.Item2); string key2 = MakeKey(tuple3.Item1, tuple3.Item2); if (!connections.ContainsKey(key) && !connections.ContainsKey(key2)) { connections[key] = (tuple3.Item1, tuple3.Item2); connections[key2] = (tuple.Item1, tuple.Item2); } } } if (list.Count - hashSet.Count > 0) { Debug.LogWarning((object)$"第二阶段配对后剩余 {list.Count - hashSet.Count} 个未配对出口"); } } private int GetActualExitCount(string scene) { RandomSceneLoader.SceneConfig sceneConfig = sceneLoader.sceneConfigs[scene]; int num = sceneConfig.Exits.Count((string e) => BlacklistedExits.Contains(MakeKey(scene, e))); return sceneConfig.Exits.Count - num; } private bool IsConnectionAllowed(string sceneA, string exitA, string sceneB, string exitB) { if (string.Equals(sceneA, sceneB, StringComparison.OrdinalIgnoreCase)) { return false; } if ((sceneA == "Tut_01" && HighPriorityRooms.Contains(sceneB)) || (sceneB == "Tut_01" && HighPriorityRooms.Contains(sceneA))) { return false; } string text = MakeKey(sceneA, exitA); string text2 = MakeKey(sceneB, exitB); if (BlacklistedExits.Contains(text) || BlacklistedExits.Contains(text2)) { return false; } int count = sceneLoader.sceneConfigs[sceneA].Exits.Count; int count2 = sceneLoader.sceneConfigs[sceneB].Exits.Count; int num = sceneLoader.sceneConfigs[sceneA].Exits.Count((string e) => BlacklistedExits.Contains(MakeKey(sceneA, e))); int num2 = sceneLoader.sceneConfigs[sceneB].Exits.Count((string e) => BlacklistedExits.Contains(MakeKey(sceneB, e))); int num3 = count - num; int num4 = count2 - num2; if (num3 == 1 && num4 < 3) { return false; } if (num4 == 1 && num3 < 3) { return false; } if (num3 == 1 && num4 >= 3 && (SingleExitPairedCounts.TryGetValue(sceneB, out var value) ? value : 0) >= num4 - 2) { return false; } if (num4 == 1 && num3 >= 3 && (SingleExitPairedCounts.TryGetValue(sceneA, out var value2) ? value2 : 0) >= num3 - 2) { return false; } if (text == "Tut_01_left3" || text2 == "Tut_01_left3") { if (!(text == "Tut_01_left3")) { _ = sceneA; } else { _ = sceneB; } _ = text == "Tut_01_left3"; string item = ((text == "Tut_01_left3") ? text2 : text); if (((text == "Tut_01_left3") ? num4 : num3) == 1) { return false; } if (new HashSet(StringComparer.OrdinalIgnoreCase).Contains(item)) { return false; } } return true; } private void UpdateSingleExitCount(string sceneA, string sceneB) { int count = sceneLoader.sceneConfigs[sceneA].Exits.Count; int count2 = sceneLoader.sceneConfigs[sceneB].Exits.Count; int num = sceneLoader.sceneConfigs[sceneA].Exits.Count((string e) => BlacklistedExits.Contains(MakeKey(sceneA, e))); int num2 = sceneLoader.sceneConfigs[sceneB].Exits.Count((string e) => BlacklistedExits.Contains(MakeKey(sceneB, e))); int num3 = count - num; int num4 = count2 - num2; if (num3 == 1 && num4 >= 3) { if (!SingleExitPairedCounts.ContainsKey(sceneB)) { SingleExitPairedCounts[sceneB] = 1; } else { SingleExitPairedCounts[sceneB]++; } } if (num4 == 1 && num3 >= 3) { if (!SingleExitPairedCounts.ContainsKey(sceneA)) { SingleExitPairedCounts[sceneA] = 1; } else { SingleExitPairedCounts[sceneA]++; } } } private bool TryLoadConnectionsFromFile() { try { if (string.IsNullOrWhiteSpace(saveFilePath)) { Debug.LogWarning((object)"RoomRando: saveFilePath is empty or null"); return false; } if (!File.Exists(saveFilePath)) { Debug.Log((object)("RoomRando: connections file not found at " + saveFilePath)); return false; } string[] array = File.ReadAllLines(saveFilePath); Debug.Log((object)$"RoomRando: read {array.Length} lines from {saveFilePath}"); int num = 0; for (int i = 0; i < array.Length; i++) { string text = array[i]?.Trim(); if (string.IsNullOrWhiteSpace(text)) { num = i + 1; continue; } if (text.StartsWith("#seed|", StringComparison.OrdinalIgnoreCase)) { string[] array2 = text.Split(new char[1] { '|' }); if (array2.Length >= 2 && int.TryParse(array2[1], out var result)) { generationSeed = result; RandomSceneLoader.CurrentSeed = generationSeed; rng = new Random(generationSeed); Debug.Log((object)$"RoomRando: loaded generation seed {generationSeed} from {saveFilePath}"); } num = i + 1; } else { num = i; } break; } int num2 = 0; int num3 = 0; for (int j = num; j < array.Length; j++) { string text2 = array[j]; if (string.IsNullOrWhiteSpace(text2) || text2.StartsWith("#")) { continue; } string[] array3 = text2.Split(new char[1] { '|' }); if (array3.Length != 4) { num3++; continue; } string text3 = array3[0] + "_" + array3[1]; string item = array3[2] + "_" + array3[3]; if (BlacklistedExits.Contains(text3) || BlacklistedExits.Contains(item)) { num3++; continue; } connections[text3] = (array3[2], array3[3]); num2++; } Debug.Log((object)$"RoomRando: parsed {num2} connection lines, skipped {num3} invalid lines, total connections now {connections.Count}"); if (num2 != 0 || generationSeed == 0) { return connections.Count > 0; } Debug.Log((object)$"RoomRando: file contained seed {generationSeed} but no explicit connections; will regenerate deterministically using that seed"); return false; } catch (Exception ex) { Debug.LogWarning((object)("RoomRando: failed to load connections file: " + ex.Message)); return false; } } private void SaveConnectionsToFile() { try { using (StreamWriter streamWriter = new StreamWriter(saveFilePath, append: false)) { if (generationSeed == 0) { generationSeed = Environment.TickCount; } streamWriter.WriteLine($"#seed|{generationSeed}"); foreach (KeyValuePair connection in connections) { string key = connection.Key; int num = key.LastIndexOf('_'); if (num > 0) { string text = key.Substring(0, num); string text2 = key.Substring(num + 1); streamWriter.WriteLine(text + "|" + text2 + "|" + connection.Value.Item1 + "|" + connection.Value.Item2); } } } Debug.Log((object)$"RoomRando: saved {connections.Count} connections to {saveFilePath}"); } catch (Exception ex) { Debug.LogWarning((object)("RoomRando: failed to save connections: " + ex.Message)); } } private void TryGenerateMap() { if (!enableMapGeneration) { Debug.Log((object)"RoomRando: map generation is disabled"); return; } try { string text = Path.Combine(Paths.PluginPath, "RoomRandoMap.png"); if (RoomMapGenerator.GenerateFromFile(saveFilePath, text)) { Debug.Log((object)("RoomRando: generated map image at " + text)); } else { Debug.LogWarning((object)"RoomRando: map generation reported failure or no data."); } } catch (Exception ex) { Debug.LogWarning((object)("RoomRando: map generation failed: " + ex.Message)); } } private void InitializePredefinedConnections() { List<(string, string, string, string)> list = new List<(string, string, string, string)>(); foreach (var item5 in list) { string item = item5.Item1; string item2 = item5.Item2; string item3 = item5.Item3; string item4 = item5.Item4; string text = MakeKey(item, item2); string text2 = MakeKey(item3, item4); connections[text] = (item3, item4); connections[text2] = (item, item2); Debug.Log((object)("RoomRando: predefined " + text + " <-> " + text2)); } Debug.Log((object)$"RoomRando: initialized with {list.Count} predefined pairs"); } private string MakeKey(string scene, string exit) { return scene + "_" + exit; } public (string targetScene, string targetGate)? GetConnection(string currentScene, string exitName) { if (string.IsNullOrEmpty(exitName)) { return null; } if (!connections.TryGetValue(MakeKey(currentScene, exitName), out (string, string) value)) { return null; } return value; } public List GetValidExitsForScene(string sceneName) { if (!((Object)(object)sceneLoader != (Object)null) || !sceneLoader.sceneConfigs.TryGetValue(sceneName, out var value)) { return new List(); } return value.Exits ?? new List(); } public void OnExitUsed(string currentScene, string exitName) { if (string.IsNullOrEmpty(exitName)) { Debug.LogWarning((object)("RoomRando: OnExitUsed called with null/empty exitName from " + currentScene)); return; } string text = MakeKey(currentScene, exitName); if (connections.TryGetValue(text, out (string, string) value)) { Debug.Log((object)("RoomRando: using connection " + text + " -> " + value.Item1 + " via " + value.Item2)); LoadScene(value.Item1, value.Item2); } else { Debug.LogWarning((object)("RoomRando: no connection found for " + text)); } } private void LoadScene(string sceneName, string entryGate) { //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_005b: 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_0069: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Expected O, but got Unknown if ((Object)(object)GameManager.instance == (Object)null) { Debug.LogError((object)"RoomRando: GameManager not available"); return; } try { RandomSceneLoader randomSceneLoader = Object.FindFirstObjectByType(); if ((Object)(object)randomSceneLoader != (Object)null) { randomSceneLoader.SetLastEntryGate(entryGate); } } catch (Exception ex) { Debug.LogWarning((object)("RoomRando: failed to notify RandomSceneLoader: " + ex.Message)); } try { GameManager.instance.BeginSceneTransition(new SceneLoadInfo { SceneName = sceneName, EntryGateName = entryGate, PreventCameraFadeOut = false, WaitForSceneTransitionCameraFade = true, Visualization = (SceneLoadVisualizations)0 }); } catch (Exception arg) { Debug.LogError((object)$"RoomRando: BeginSceneTransition failed: {arg}"); } } public void LogAllConnections() { Debug.Log((object)$"RoomRando: {connections.Count} connections:"); foreach (KeyValuePair connection in connections) { Debug.Log((object)(" " + connection.Key + " -> " + connection.Value.Item1 + " (via " + connection.Value.Item2 + ")")); } } public int GetGenerationSeed() { return generationSeed; } public void RegenerateWithSeed(int seed) { generationSeed = seed; RandomSceneLoader.CurrentSeed = generationSeed; rng = new Random(generationSeed); connections.Clear(); forceExactSeed = true; Debug.Log((object)$"RoomRando: regenerating with exact seed {seed}"); GenerateAllConnectionsAtStart(); forceExactSeed = false; SaveConnectionsToFile(); Debug.Log((object)$"RoomRando: regeneration complete with seed {generationSeed}, saved to {saveFilePath}"); } } public class RoomRandomConfig { public int Seed; public bool EnableRandomization; public bool EnableMapGeneration; public List<(string before, string after)> PrecedencePairs = new List<(string, string)>(); } public static class HKSilksong_RandomizerAPI { private static RandomSceneLoader _sceneLoader; private static RoomRando _roomRando; private static SeedManager _seedManager; private static RoomRandomConfig _cachedConfig = new RoomRandomConfig(); private static bool _hasPendingChanges = false; private static bool _isGameReady = false; private static bool _pendingShowSeed = true; private static int _pendingNewSeed = 0; private static bool _pendingRegenerate = false; internal static void Initialize(RandomSceneLoader loader, RoomRando rando) { _sceneLoader = loader; _roomRando = rando; GameObject obj = GameObject.Find("__SeedManager"); _seedManager = ((obj != null) ? obj.GetComponent() : null); } internal static void MarkGameReady() { _isGameReady = true; if (_hasPendingChanges) { ApplyPending(); } } public static void SetConfig(RoomRandomConfig config) { if (config != null) { _cachedConfig.Seed = config.Seed; _cachedConfig.EnableRandomization = config.EnableRandomization; _cachedConfig.EnableMapGeneration = config.EnableMapGeneration; _cachedConfig.PrecedencePairs = new List<(string, string)>(config.PrecedencePairs); _hasPendingChanges = true; if (_isGameReady) { ApplyPending(); } } } public static void SetSeed(int seed) { _cachedConfig.Seed = seed; _hasPendingChanges = true; if (_isGameReady) { ApplyPending(); } } public static void SetEnabled(bool enabled) { _cachedConfig.EnableRandomization = enabled; _hasPendingChanges = true; if (_isGameReady) { ApplyPending(); } } public static void SetMapGenerationEnabled(bool enabled) { _cachedConfig.EnableMapGeneration = enabled; _hasPendingChanges = true; if (_isGameReady) { ApplyPending(); } } public static void SetPrecedencePairs(List<(string, string)> pairs) { _cachedConfig.PrecedencePairs = pairs; _hasPendingChanges = true; if (_isGameReady) { ApplyPending(); } } public static RoomRandomConfig GetConfig() { return new RoomRandomConfig { Seed = _cachedConfig.Seed, EnableRandomization = _cachedConfig.EnableRandomization, EnableMapGeneration = _cachedConfig.EnableMapGeneration, PrecedencePairs = new List<(string, string)>(_cachedConfig.PrecedencePairs) }; } public static void ApplyPending() { if ((Object)(object)_roomRando != (Object)null) { _roomRando.SetConfig(_cachedConfig); } RandomSceneLoader.EnableRandomization = _cachedConfig.EnableRandomization; if ((Object)(object)_seedManager != (Object)null && _pendingShowSeed != _seedManager.GetShowSeedOnScreen()) { _seedManager.SetShowSeedOnScreen(_pendingShowSeed); } if (_pendingRegenerate && _pendingNewSeed != 0 && (Object)(object)_roomRando != (Object)null) { _roomRando.RegenerateWithSeed(_pendingNewSeed); _pendingRegenerate = false; } _hasPendingChanges = false; } public static void SetShowSeedOnScreen(bool show) { _pendingShowSeed = show; if (_isGameReady && (Object)(object)_seedManager != (Object)null) { _seedManager.SetShowSeedOnScreen(show); } } public static bool GetShowSeedOnScreen() { return _seedManager?.GetShowSeedOnScreen() ?? true; } public static void RegenerateWithSeed(int seed) { if (_isGameReady && (Object)(object)_roomRando != (Object)null) { _roomRando.RegenerateWithSeed(seed); return; } _pendingNewSeed = seed; _pendingRegenerate = true; _hasPendingChanges = true; } public static int GetCurrentRoomSeed() { return _roomRando?.GetGenerationSeed() ?? 0; } public static bool IsSceneRandomEnabled() { return RandomSceneLoader.EnableRandomization; } public static string GetCurrentSceneName() { return _sceneLoader?.GetCurrentSceneName() ?? ""; } public static void TeleportToScene(string sceneName, string entryGate = null) { _sceneLoader?.TeleportToScene((entryGate == null) ? sceneName : (sceneName + " " + entryGate)); } public static void SetShowSceneLabel(bool show) { _sceneLoader?.SetShowSceneLabel(show); } public static bool GetShowSceneLabel() { return _sceneLoader?.GetShowSceneLabel() ?? true; } public static void LogAllRoomConnections() { _roomRando?.LogAllConnections(); } } public class SeedManager : MonoBehaviour { private RoomRando roomRando; private RandomSceneLoader sceneLoader; private ConfigEntry cfgNewSeed; private ConfigEntry cfgRegenerateTrigger; private ConfigEntry cfgCurrentSeed; private ConfigEntry cfgShowSeedOnScreen; private GUIStyle seedLabelStyle; private string cachedSeedLabel = ""; private int lastRenderedSeed = -1; private float configPollTimer; private const float CONFIG_POLL_INTERVAL = 0.1f; private int _pendingSeed; private bool _pendingRegenerate; private bool _pendingShowSeed = true; private bool _hasPendingConfig; private bool _isInitialized; public void Initialize(RandomSceneLoader loader) { //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Expected O, but got Unknown sceneLoader = loader; roomRando = Object.FindAnyObjectByType(); if ((Object)(object)roomRando == (Object)null) { Debug.LogWarning((object)"SeedManager: Could not find RoomRando component!"); return; } try { ConfigFile config = ((BaseUnityPlugin)sceneLoader).Config; cfgShowSeedOnScreen = config.Bind("Seed Manager", "ShowSeedOnScreen", true, "Show current seed text on screen (toggle to hide)"); cfgCurrentSeed = config.Bind("Seed Manager", "CurrentSeed", roomRando.GetGenerationSeed().ToString(), "Current generation seed (read-only display)"); cfgNewSeed = config.Bind("Seed Manager", "NewSeed", 0, "Enter a seed value to regenerate the map"); cfgRegenerateTrigger = config.Bind("Seed Manager", "RegenerateNow", false, "Set to true to regenerate map with NewSeed (resets automatically)"); UpdateCurrentSeedDisplay(); seedLabelStyle = new GUIStyle(); _isInitialized = true; if (_hasPendingConfig) { ApplyPendingConfig(); } } catch (Exception ex) { Debug.LogError((object)("SeedManager: Failed to bind config entries: " + ex.Message)); } } public void SetShowSeedOnScreen(bool show) { _pendingShowSeed = show; _hasPendingConfig = true; if (_isInitialized) { ApplyPendingConfig(); } } public bool GetShowSeedOnScreen() { return cfgShowSeedOnScreen?.Value ?? true; } public void SetNewSeed(int seed) { _pendingSeed = seed; _pendingRegenerate = true; _hasPendingConfig = true; if (_isInitialized) { ApplyPendingConfig(); } } private void ApplyPendingConfig() { if (!_isInitialized) { return; } if (cfgShowSeedOnScreen != null && cfgShowSeedOnScreen.Value != _pendingShowSeed) { cfgShowSeedOnScreen.Value = _pendingShowSeed; } if (_pendingRegenerate && _pendingSeed != 0) { if (cfgNewSeed != null) { cfgNewSeed.Value = _pendingSeed; } if (cfgRegenerateTrigger != null) { cfgRegenerateTrigger.Value = true; } _pendingRegenerate = false; } _hasPendingConfig = false; } private void Update() { if ((Object)(object)roomRando == (Object)null || cfgRegenerateTrigger == null || cfgNewSeed == null) { return; } configPollTimer += Time.deltaTime; if (configPollTimer < 0.1f) { return; } configPollTimer = 0f; try { if (cfgRegenerateTrigger.Value) { int value = cfgNewSeed.Value; if (value != 0) { Debug.Log((object)$"SeedManager: Regenerating connections with seed {value}"); roomRando.RegenerateWithSeed(value); UpdateCurrentSeedDisplay(); } else { Debug.LogWarning((object)"SeedManager: NewSeed is 0, please enter a valid seed value"); } cfgRegenerateTrigger.Value = false; } } catch (Exception ex) { Debug.LogError((object)("SeedManager: Error during regeneration: " + ex.Message)); cfgRegenerateTrigger.Value = false; } } private void UpdateCurrentSeedDisplay() { if (!((Object)(object)roomRando == (Object)null) && cfgCurrentSeed != null) { int generationSeed = roomRando.GetGenerationSeed(); cfgCurrentSeed.Value = generationSeed.ToString(); cachedSeedLabel = Locale.Get("Current Seed: ") + generationSeed; lastRenderedSeed = generationSeed; } } private void OnGUI() { //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_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_0066: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Expected O, but got Unknown //IL_00d0: Unknown result type (might be due to invalid IL or missing references) if (cfgShowSeedOnScreen == null || !cfgShowSeedOnScreen.Value || (Object)(object)roomRando == (Object)null) { return; } try { if (seedLabelStyle.normal.textColor != Color.white || seedLabelStyle.fontSize != 16) { GUIStyle val = new GUIStyle(GUI.skin.label); val.normal.textColor = Color.white; val.fontSize = 16; val.fontStyle = (FontStyle)1; seedLabelStyle = val; } int generationSeed = roomRando.GetGenerationSeed(); if (generationSeed != lastRenderedSeed) { cachedSeedLabel = Locale.Get("Seed: ") + generationSeed; lastRenderedSeed = generationSeed; } GUI.Label(new Rect(10f, 40f, 400f, 25f), cachedSeedLabel, seedLabelStyle); } catch { } } } [HarmonyPatch(typeof(GameManager), "BeginSceneTransition")] public class TransitionPatch { private static RoomRando roomRando; private static bool isRedirecting; private static bool Prefix(ref SceneLoadInfo info) { //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_0177: Unknown result type (might be due to invalid IL or missing references) //IL_017c: Unknown result type (might be due to invalid IL or missing references) //IL_018e: Unknown result type (might be due to invalid IL or missing references) //IL_01a0: Unknown result type (might be due to invalid IL or missing references) //IL_01ab: Unknown result type (might be due to invalid IL or missing references) //IL_01b2: Unknown result type (might be due to invalid IL or missing references) //IL_01b9: 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_01c0: Unknown result type (might be due to invalid IL or missing references) //IL_01c9: Expected O, but got Unknown try { if (isRedirecting) { isRedirecting = false; return true; } if ((Object)(object)GameManager.instance != (Object)null && GameManager.instance.RespawningHero) { return true; } if (!RandomSceneLoader.EnableRandomization) { return true; } try { if (RandomSceneLoader.SuppressTransitionPatch) { Debug.Log((object)"TransitionPatch: suppression active, allowing original transition"); return true; } } catch { } if ((Object)(object)roomRando == (Object)null) { GameObject val = GameObject.Find("__RoomRando"); if ((Object)(object)val != (Object)null) { roomRando = val.GetComponent(); } } if ((Object)(object)roomRando == (Object)null) { Debug.LogWarning((object)"TransitionPatch: RoomRando not found, allowing normal transition"); return true; } Scene activeScene = SceneManager.GetActiveScene(); string name = ((Scene)(ref activeScene)).name; if (!string.IsNullOrEmpty(info.EntryGateName)) { Debug.Log((object)("TransitionPatch: intercepted transition from " + name + " via exit to " + info.SceneName + " entry gate " + info.EntryGateName)); string text = FindExitGateBeingUsed(name, info); if (!string.IsNullOrEmpty(text)) { Debug.Log((object)("TransitionPatch: detected exit gate used: " + text)); (string, string)? connection = roomRando.GetConnection(name, text); if (connection.HasValue) { Debug.Log((object)("TransitionPatch: redirecting to " + connection.Value.Item1 + " via " + connection.Value.Item2)); SceneLoadInfo val2 = new SceneLoadInfo { SceneName = connection.Value.Item1, EntryGateName = connection.Value.Item2, EntryDelay = 0f, WaitForSceneTransitionCameraFade = true, PreventCameraFadeOut = false, Visualization = (SceneLoadVisualizations)0, AlwaysUnloadUnusedAssets = true }; isRedirecting = true; GameManager.instance.BeginSceneTransition(val2); return false; } Debug.Log((object)("TransitionPatch: no randomized connection for " + name + "_" + text)); } } Debug.Log((object)("TransitionPatch: allowing normal transition from " + name + " to " + info.SceneName)); return true; } catch (Exception arg) { Debug.LogError((object)$"TransitionPatch error: {arg}"); return true; } } private static string FindExitGateBeingUsed(string currentScene, SceneLoadInfo info) { //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) try { List list = roomRando?.GetValidExitsForScene(currentScene); if (list == null || list.Count == 0) { Debug.LogWarning((object)("FindExitGateBeingUsed: no valid exits found for " + currentScene)); return null; } HeroController instance = HeroController.instance; if ((Object)(object)instance == (Object)null) { return null; } Vector3 position = ((Component)instance).transform.position; GameObject[] array = Object.FindObjectsByType((FindObjectsSortMode)0); float num = float.MaxValue; string text = null; GameObject[] array2 = array; foreach (GameObject val in array2) { string name = ((Object)val).name; if (list.Any((string exit) => string.Equals(exit, name, StringComparison.OrdinalIgnoreCase))) { float num2 = Vector3.Distance(position, val.transform.position); if ((double)num2 < 5.0 && num2 < num) { num = num2; text = name; } } } if (!string.IsNullOrEmpty(text)) { Debug.Log((object)("FindExitGateBeingUsed: found valid exit '" + text + "' near hero in " + currentScene)); } return text; } catch (Exception ex) { Debug.LogWarning((object)("FindExitGateBeingUsed error: " + ex.Message)); return null; } } }