Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of AlwaysCubeRoom v1.2.0
AlwaysCubeRoom.dll
Decompiled 4 days agousing System; using System.Collections; using System.Collections.Generic; using System.Reflection; using System.Runtime.CompilerServices; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: AssemblyVersion("0.0.0.0")] namespace AlwaysCubeRoom; [BepInPlugin("f0xb0t.AlwaysCubeRoom", "AlwaysCubeRoom", "1.2.0")] public class Plugin : BaseUnityPlugin { public const string PluginGuid = "f0xb0t.AlwaysCubeRoom"; public const string PluginName = "AlwaysCubeRoom"; public const string PluginVersion = "1.2.0"; internal static ManualLogSource Log; internal static ConfigEntry<bool> Enabled; internal static ConfigEntry<bool> AllowLargeVolumeFallback; internal static ConfigEntry<bool> ForceRoom; internal static ConfigEntry<bool> PrankRooms; internal static ConfigEntry<bool> PrankCubes; internal static ConfigEntry<int> PrankRoomCount; private void Awake() { //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Expected O, but got Unknown //IL_00e4: Unknown result type (might be due to invalid IL or missing references) Log = ((BaseUnityPlugin)this).Logger; Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Force the Cube of Knowledge to spawn on every level whose valuable pool contains it (Swiftbroom Academy)."); ForceRoom = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "ForceCursedTreeRoom", true, "Force the Cursed Tree room (where the Knowledge Platforms for the cube puzzle are) to generate."); AllowLargeVolumeFallback = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "AllowLargeVolumeFallback", true, "If a level has no Big valuable spots, put the cube in a Wide / Very Tall spot instead."); PrankRooms = ((BaseUnityPlugin)this).Config.Bind<bool>("Prank", "EveryRoomIsCursedTree", false, "Rebuild Swiftbroom Academy's layout as a grid of 2x2 blocks and make every block the Cursed Tree. Only the truck and the extraction rooms (needed to finish the level) stay normal."); PrankRoomCount = ((BaseUnityPlugin)this).Config.Bind<int>("Prank", "CursedTreeCount", 12, new ConfigDescription("How many Cursed Tree rooms to build per level when EveryRoomIsCursedTree is on.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 40), new object[0])); PrankCubes = ((BaseUnityPlugin)this).Config.Bind<bool>("Prank", "EveryValuableIsCube", false, "Replace every valuable on Swiftbroom Academy with the Cube of Knowledge, whatever the spot size."); new Harmony("f0xb0t.AlwaysCubeRoom").PatchAll(typeof(Patches)); Log.LogInfo((object)"AlwaysCubeRoom 1.2.0 loaded."); } } internal static class Cube { internal static bool PlacedThisLevel; internal static bool LoggedMissingThisLevel; internal static int PrankSwaps; private static readonly Dictionary<string, bool> Cache = new Dictionary<string, bool>(); private static readonly FieldInfo BigValuablesField = AccessTools.Field(typeof(ValuableDirector), "bigValuables"); private static readonly FieldInfo BigVolumesField = AccessTools.Field(typeof(ValuableDirector), "bigVolumes"); internal static string Key(PrefabRef r) { if (r == null) { return null; } string text = null; try { text = ((PrefabRef<GameObject>)(object)r).ResourcePath; } catch (Exception) { } if (string.IsNullOrEmpty(text)) { try { text = ((PrefabRef<GameObject>)(object)r).PrefabName; } catch (Exception) { } } return text; } internal static bool IsCube(PrefabRef r) { string text = Key(r); if (text == null) { return false; } if (Cache.TryGetValue(text, out var value)) { return value; } value = text.IndexOf("Cube of Knowledge", StringComparison.OrdinalIgnoreCase) >= 0; if (!value) { try { GameObject prefab = ((PrefabRef<GameObject>)(object)r).Prefab; value = (Object)(object)prefab != (Object)null && (Object)(object)prefab.GetComponentInChildren<ValuableCubeOfKnowledge>(true) != (Object)null; } catch (Exception) { } } Cache[text] = value; return value; } internal static PrefabRef FindIn(List<PrefabRef> list) { if (list == null) { return null; } for (int i = 0; i < list.Count; i++) { if (IsCube(list[i])) { return list[i]; } } return null; } internal static List<PrefabRef> BigValuablesOf(ValuableDirector d) { try { return (List<PrefabRef>)BigValuablesField.GetValue(d); } catch (Exception) { return null; } } internal static int BigVolumeCount(ValuableDirector d) { try { return ((List<ValuableVolume>)BigVolumesField.GetValue(d))?.Count ?? 0; } catch (Exception) { return 0; } } } internal static class Room { internal static bool Boosted; internal static bool Placed; internal static bool Pending; internal static int PlacedCount; private static int savedCooldown; private static int savedBadLuck; private static readonly FieldInfo CooldownField = AccessTools.Field(typeof(RunManager), "megaModuleCooldownCount"); private static readonly FieldInfo BadLuckField = AccessTools.Field(typeof(RunManager), "megaModuleBadLuckCount"); private static readonly Dictionary<string, bool> Cache = new Dictionary<string, bool>(); internal static void Reset() { if (Boosted) { Restore(); } Placed = false; Pending = false; PlacedCount = 0; } internal static void Release() { Boosted = false; } internal static void Boost() { RunManager instance = RunManager.instance; if (!((Object)(object)instance == (Object)null) && !(CooldownField == null) && !(BadLuckField == null)) { savedCooldown = (int)CooldownField.GetValue(instance); savedBadLuck = (int)BadLuckField.GetValue(instance); CooldownField.SetValue(instance, 0); BadLuckField.SetValue(instance, 1000); Boosted = true; Plugin.Log.LogInfo((object)("Level can have the Cursed Tree; forcing a mega room (real cooldown " + savedCooldown + ", bad luck " + savedBadLuck + ").")); } } internal static void Restore() { if (Boosted) { Boosted = false; RunManager instance = RunManager.instance; if (!((Object)(object)instance == (Object)null)) { CooldownField.SetValue(instance, savedCooldown); BadLuckField.SetValue(instance, savedBadLuck); } } } internal static bool IsRoom(PrefabRef r) { string text = Cube.Key(r); if (text == null) { return false; } if (Cache.TryGetValue(text, out var value)) { return value; } value = text.IndexOf("Cursed Tree", StringComparison.OrdinalIgnoreCase) >= 0; if (!value) { try { GameObject prefab = ((PrefabRef<GameObject>)(object)r).Prefab; value = (Object)(object)prefab != (Object)null && (Object)(object)prefab.GetComponentInChildren<KnowledgePlatform>(true) != (Object)null; } catch (Exception) { } } Cache[text] = value; return value; } internal static PrefabRef FindIn(List<PrefabRef> list) { if (list == null) { return null; } for (int i = 0; i < list.Count; i++) { if (IsRoom(list[i])) { return list[i]; } } return null; } } internal static class Layout { internal static bool Applied; internal static int Blocks; internal static int BlocksWide; private static readonly FieldInfo GridField = AccessTools.Field(typeof(LevelGenerator), "LevelGrid"); private static readonly FieldInfo MegaTilesField = AccessTools.Field(typeof(LevelGenerator), "MegaTiles"); private static readonly FieldInfo DeadEndField = AccessTools.Field(typeof(LevelGenerator), "DeadEndAmount"); private static readonly FieldInfo SpecialField = AccessTools.Field(typeof(LevelGenerator), "SpecialAmount"); private static readonly FieldInfo ExtractionField = AccessTools.Field(typeof(LevelGenerator), "ExtractionAmount"); private static LevelGenerator resizedGen; private static int origWidth; private static int origHeight; internal static bool Wanted(LevelGenerator gen) { if (!Plugin.Enabled.Value || !Plugin.ForceRoom.Value || !Plugin.PrankRooms.Value) { return false; } if ((Object)(object)gen == (Object)null || (Object)(object)gen.Level == (Object)null || !SemiFunc.RunIsLevel()) { return false; } Level level = gen.Level; if (Room.FindIn(level.ModulesMega1) == null && Room.FindIn(level.ModulesMega2) == null) { return Room.FindIn(level.ModulesMega3) != null; } return true; } internal static void Unsize(LevelGenerator gen) { if (!((Object)(object)gen == (Object)null) && !((Object)(object)gen != (Object)(object)resizedGen)) { gen.LevelWidth = origWidth; gen.LevelHeight = origHeight; resizedGen = null; } } internal static void Size(LevelGenerator gen) { Applied = false; if ((Object)(object)resizedGen != (Object)(object)gen) { resizedGen = gen; origWidth = gen.LevelWidth; origHeight = gen.LevelHeight; } Blocks = Math.Max(1, Plugin.PrankRoomCount.Value); BlocksWide = Math.Max(2, (int)Math.Ceiling(Math.Sqrt(Blocks))); int num = (Blocks + BlocksWide - 1) / BlocksWide; gen.LevelWidth = 2 * BlocksWide + 2; gen.LevelHeight = 2 * num + 1; } internal static void Apply(LevelGenerator gen) { if (!(GridField.GetValue(gen) is Tile[,] array)) { return; } int length = array.GetLength(0); int length2 = array.GetLength(1); int num = (Blocks + BlocksWide - 1) / BlocksWide; if (length < 2 * BlocksWide + 2 || length2 < 2 * num + 1) { Plugin.Log.LogWarning((object)("Prank layout skipped: grid is " + length + "x" + length2 + ", smaller than planned.")); return; } for (int i = 0; i < length; i++) { for (int j = 0; j < length2; j++) { array[i, j].active = false; } } for (int k = 0; k < Blocks; k++) { int num2 = 1 + 2 * (k % BlocksWide); int num3 = 2 * (k / BlocksWide); array[num2, num3].active = true; array[num2 + 1, num3].active = true; array[num2, num3 + 1].active = true; array[num2 + 1, num3 + 1].active = true; } if (!array[length / 2, 0].active) { Plugin.Log.LogWarning((object)"Prank layout: start tile not covered; keeping it."); array[length / 2, 0].active = true; } DeadEndField.SetValue(gen, 0); SpecialField.SetValue(gen, 0); if ((int)ExtractionField.GetValue(gen) < 1) { ExtractionField.SetValue(gen, 1); } Applied = true; Plugin.Log.LogInfo((object)string.Concat("Prank layout: ", Blocks, " 2x2 blocks on a ", length, "x", length2, " grid, extraction rooms: ", ExtractionField.GetValue(gen), ".")); } internal static void SetMegaTiles(LevelGenerator gen) { //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Expected O, but got Unknown if (!Applied || !(GridField.GetValue(gen) is Tile[,] array)) { return; } List<MegaTile> list = new List<MegaTile>(); for (int i = 0; i < Blocks; i++) { int num = 1 + 2 * (i % BlocksWide); int num2 = 2 * (i / BlocksWide); Tile[] array2 = (Tile[])(object)new Tile[4] { array[num, num2 + 1], array[num, num2], array[num + 1, num2 + 1], array[num + 1, num2] }; bool flag = true; for (int j = 0; j < 4; j++) { if (!array2[j].active || (int)array2[j].type != 0) { flag = false; } } if (flag) { MegaTile val = new MegaTile(); val.tiles = array2; list.Add(val); } } MegaTilesField.SetValue(gen, list); Plugin.Log.LogInfo((object)("Prank layout: offering " + list.Count + " mega spots.")); } internal static IEnumerator Wrap(IEnumerator inner, LevelGenerator gen) { bool first = true; while (inner.MoveNext()) { if (first) { first = false; try { Apply(gen); } catch (Exception ex) { Plugin.Log.LogError((object)("Prank layout failed: " + ex)); } } yield return inner.Current; } } } internal static class Patches { [HarmonyPrefix] [HarmonyPatch(typeof(LevelGenerator), "TileGeneration")] private static void TileGenerationPrefix(LevelGenerator __instance) { Layout.Applied = false; if (Layout.Wanted(__instance)) { Layout.Size(__instance); } else { Layout.Unsize(__instance); } } [HarmonyPostfix] [HarmonyPatch(typeof(LevelGenerator), "TileGeneration")] private static void TileGenerationPostfix(LevelGenerator __instance, ref IEnumerator __result) { if (Layout.Wanted(__instance)) { __result = Layout.Wrap(__result, __instance); } } [HarmonyPrefix] [HarmonyPatch(typeof(ValuableDirector), "SetupHost")] private static void SetupHostPrefix() { if (Cube.PrankSwaps > 0) { Plugin.Log.LogInfo((object)("Prank: turned " + Cube.PrankSwaps + " valuables into cubes last level.")); } Cube.PlacedThisLevel = false; Cube.LoggedMissingThisLevel = false; Cube.PrankSwaps = 0; string text = (((Object)(object)LevelGenerator.Instance != (Object)null && (Object)(object)LevelGenerator.Instance.Level != (Object)null) ? ((Object)LevelGenerator.Instance.Level).name : "?"); Plugin.Log.LogInfo((object)("Spawning valuables as host for level: " + text)); } [HarmonyPatch(typeof(ValuableDirector), "SpawnValuable")] [HarmonyPrefix] private static void SpawnValuablePrefix(ValuableDirector __instance, ref PrefabRef __0, ValuableVolume __1) { //IL_009b: 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_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Invalid comparison between Unknown and I4 //IL_0120: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Invalid comparison between Unknown and I4 //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Invalid comparison between Unknown and I4 if (!Plugin.Enabled.Value || (Object)(object)__1 == (Object)null || (Cube.PlacedThisLevel && !Plugin.PrankCubes.Value)) { return; } PrefabRef val = Cube.FindIn(Cube.BigValuablesOf(__instance)); if (val != null && Plugin.PrankCubes.Value) { if (Cube.PrankSwaps == 0) { Plugin.Log.LogInfo((object)"Prank: every valuable on this level becomes the Cube of Knowledge."); } if (!Cube.IsCube(__0)) { Cube.PrankSwaps++; } __0 = val; Cube.PlacedThisLevel = true; return; } if (val == null) { if (!Cube.LoggedMissingThisLevel) { Cube.LoggedMissingThisLevel = true; Plugin.Log.LogInfo((object)"This level's valuable pool has no Cube of Knowledge; leaving it alone."); } return; } Type volumeType = __1.VolumeType; bool flag = (int)volumeType == 3; if (!flag && Plugin.AllowLargeVolumeFallback.Value && Cube.BigVolumeCount(__instance) == 0) { flag = (int)volumeType == 4 || (int)volumeType == 6; } if (flag) { if (Cube.IsCube(__0)) { Plugin.Log.LogInfo((object)"The game picked the Cube of Knowledge on its own this time."); } else { Plugin.Log.LogInfo((object)string.Concat("Swapping ", Cube.Key(__0), " for ", Cube.Key(val), " in a ", volumeType, " spot.")); } __0 = val; Cube.PlacedThisLevel = true; } } [HarmonyPrefix] [HarmonyPatch(typeof(LevelGenerator), "ModuleGeneration")] private static void ModuleGenerationPrefix(LevelGenerator __instance) { Room.Reset(); if (!Plugin.Enabled.Value || !Plugin.ForceRoom.Value) { return; } Level level = __instance.Level; if (!((Object)(object)level == (Object)null) && (Room.FindIn(level.ModulesMega1) != null || Room.FindIn(level.ModulesMega2) != null || Room.FindIn(level.ModulesMega3) != null)) { try { Layout.SetMegaTiles(__instance); } catch (Exception ex) { Plugin.Log.LogError((object)("Prank mega spots failed: " + ex)); } Room.Boost(); } } [HarmonyPatch(typeof(LevelGenerator), "PickModule")] [HarmonyPrefix] private static bool PickModulePrefix(List<PrefabRef> __0, List<PrefabRef> __1, List<PrefabRef> __2, ref PrefabRef __result) { if (!Room.Boosted || (Room.Placed && !Plugin.PrankRooms.Value)) { return true; } PrefabRef val = Room.FindIn(__0); if (val == null) { val = Room.FindIn(__1); } if (val == null) { val = Room.FindIn(__2); } if (val == null) { return true; } Room.Pending = true; __result = val; return false; } [HarmonyPostfix] [HarmonyPatch(typeof(LevelGenerator), "PlanModule")] private static void PlanModulePostfix(Type _type, bool __result) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Invalid comparison between Unknown and I4 if (!Room.Boosted) { return; } if ((int)_type == 5) { if (!Room.Pending) { return; } Room.Pending = false; if (__result) { Room.Placed = true; Room.PlacedCount++; if (!Plugin.PrankRooms.Value) { Plugin.Log.LogInfo((object)"Placed the Cursed Tree (Cube of Knowledge puzzle room)."); Room.Restore(); } } } else { if (!Room.Placed) { Plugin.Log.LogWarning((object)"Could not place the Cursed Tree this level (the layout had no free 2x2 spot for a mega room)."); } else if (Plugin.PrankRooms.Value) { Plugin.Log.LogInfo((object)("Prank: placed " + Room.PlacedCount + " Cursed Tree rooms (every free 2x2 spot).")); Room.Release(); return; } Room.Restore(); } } [HarmonyPatch(typeof(KnowledgePlatform), "Awake")] [HarmonyPostfix] private static void KnowledgePlatformAwakePostfix(KnowledgePlatform __instance) { Transform root = ((Component)__instance).transform.root; Plugin.Log.LogInfo((object)("Knowledge Platform '" + ((Object)__instance).name + "' is inside '" + (((Object)(object)root != (Object)null) ? ((Object)root).name : "?") + "'")); } }