using System; using System.CodeDom.Compiler; using System.Collections; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Resources; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Configuration; using ExitGames.Client.Photon; using HarmonyLib; using Microsoft.CodeAnalysis; using Newtonsoft.Json; using Photon.Pun; using Photon.Realtime; using PhotonCustomPropsUtils; using Steamworks; using TerrainRandomiser.TerrainGeneration; using Unity.Burst; using Unity.Collections; using Unity.Jobs; using Unity.Mathematics; using UnityEngine; using UnityEngine.Rendering; using UnityEngine.UIElements; using Zorro.ControllerSupport; using Zorro.Core; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("TerrainRandomiser")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyFileVersion("1.1.6")] [assembly: AssemblyInformationalVersion("1.1.6+08cc08ce79d4943a800271485298219e6520b1d3")] [assembly: AssemblyProduct("TerrainRandomiser")] [assembly: AssemblyTitle("TerrainRandomiser")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.1.6.0")] [module: UnverifiableCode] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } } namespace TerrainRandomiser { public static class BiomeDatabase { public static List GetAllSections() { //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_014e: Unknown result type (might be due to invalid IL or missing references) //IL_01e8: Unknown result type (might be due to invalid IL or missing references) //IL_0248: Unknown result type (might be due to invalid IL or missing references) return new List { new SectionData { sectionName = "Biome_1", biomes = new List { new BiomeData { biomeName = "Shore", biomeType = (BiomeType)0, variants = new List { "Default", "SnakeBeach", "RedBeach", "BlueBeach", "JellyHell", "BlackSand" }, variantSelectionType = VariantSelectionType.BiomeVariant } } }, new SectionData { sectionName = "Biome_2", biomes = new List { new BiomeData { biomeName = "Tropics", biomeType = (BiomeType)1, variants = new List { "Default", "Lava", "Pillars", "Thorny", "Bombs", "Ivy", "SkyJungle" }, variantSelectionType = VariantSelectionType.BiomeVariant }, new BiomeData { biomeName = "Roots", biomeType = (BiomeType)7, variants = new List { "Default", "Cave Mania", "Deep Water", "Bomb Beetle", "Deep Woods", "Clearcut" }, variantSelectionType = VariantSelectionType.VariantObject } } }, new SectionData { sectionName = "Biome_3", biomes = new List { new BiomeData { biomeName = "Alpine", biomeType = (BiomeType)2, variants = new List { "Default", "Lava", "Spiky", "GeyserHell" }, variantSelectionType = VariantSelectionType.BiomeVariant }, new BiomeData { biomeName = "Mesa", biomeType = (BiomeType)6, variants = new List { "NoVariant", "ScorpionsHell", "CacusHell", "CactusForest", "DynamiteHell", "TornadoHell", "TumblerHell" }, variantSelectionType = VariantSelectionType.VariantObject } } } }; } public static List GetRuntimeValidSections() { HashSet validBiomeNames = Enum.GetNames(typeof(BiomeType)).ToHashSet(); List allSections = GetAllSections(); return (from section in allSections select new SectionData { sectionName = section.sectionName, biomes = section.biomes.Where((BiomeData b) => validBiomeNames.Contains(b.biomeName)).ToList() } into section where section.biomes.Count > 0 select section).ToList(); } } public enum VariantSelectionType { BiomeVariant, VariantObject } [Serializable] public class MapSettings { public bool enableRandomiser; public int seed; public bool autoRandomSeed; public bool fullyRandom; public List biomes = new List(); public static MapSettings CreateDefaultMapSettings() { List runtimeValidSections = BiomeDatabase.GetRuntimeValidSections(); List list = new List(); foreach (SectionData item in runtimeValidSections) { if (item.biomes.Count != 0) { BiomeData biomeData = item.biomes[0]; string selectedVariant = ((biomeData.variants.Count > 0) ? biomeData.variants[0] : ""); list.Add(new BiomeSettings { overrideEnabled = true, sectionName = item.sectionName, selectedBiome = biomeData, selectedVariant = selectedVariant }); } } return new MapSettings { seed = 42, autoRandomSeed = false, fullyRandom = false, biomes = list }; } } [Serializable] public class BiomeSettings { public bool overrideEnabled; public string sectionName; public BiomeData selectedBiome; public string selectedVariant; public bool randomBiome; public bool randomVariant; } [Serializable] public class SectionData { public string sectionName; public List biomes = new List(); } [Serializable] public class BiomeData { public string biomeName; public BiomeType biomeType; public List variants = new List(); public VariantSelectionType variantSelectionType = VariantSelectionType.BiomeVariant; } [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInPlugin("com.snosz.terrainrandomiser", "TerrainRandomiser", "1.1.7")] public class Plugin : BaseUnityPlugin { [HarmonyPatch(typeof(BoardingPass), "Initialize")] private static class BoardingPassInitializePatch { private static void Postfix(BoardingPass __instance) { Instance.CreateUI(__instance); } } [HarmonyPatch(typeof(BoardingPass), "StartGame")] private static class BoardingPassStartGamePatch { private static void Prefix(BoardingPass __instance) { if (!PhotonNetwork.IsMasterClient) { return; } if (!Instance.mapSettings.enableRandomiser) { Instance.roomMapSettings = Instance.mapSettings; SaveMapSettings(); SyncWithClients(Instance.mapSettings); return; } MapSettings mapSettings = Instance.mapSettings; SaveMapSettings(); if (mapSettings.fullyRandom || mapSettings.autoRandomSeed) { RandomiseSeed(mapSettings); } if (mapSettings.fullyRandom) { RandomiseAllSections(mapSettings); } else { RandomiseOverrides(mapSettings); } SyncWithClients(mapSettings); } } [HarmonyPatch(typeof(NavigationContainerHandler), "LateUpdate")] internal static class NavHandler_LateUpdate_Patch { public static bool Prefix() { if ((Object)(object)GUIManager.instance == (Object)null || (Object)(object)GUIManager.instance.boardingPass == (Object)null) { return true; } if (((MenuWindow)GUIManager.instance.boardingPass).isOpen) { return false; } return true; } } [HarmonyPatch(typeof(SteamLobbyHandler), "OnLobbyEnter")] private static class OnLobbyEnter { private static void Postfix(SteamLobbyHandler __instance, LobbyEnter_t param) { //IL_0001: 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) if (param.m_EChatRoomEnterResponse == 1) { string lobbyData = SteamMatchmaking.GetLobbyData(__instance.LobbySteamId, "TR_roomMapSettings"); if (!string.IsNullOrEmpty(lobbyData)) { Instance.roomMapSettings = JsonConvert.DeserializeObject(lobbyData); } } } } [HarmonyPatch(typeof(MapHandler), "InitializeMap")] private static class MapHandlerInitializeMapPatch { private static bool Prefix() { if (Instance.roomMapSettings == null || !Instance.roomMapSettings.enableRandomiser) { return true; } MapSettings roomMapSettings = Instance.roomMapSettings; viewIDsToSend = new List(); viewsRequiringIDs = new List(); Debug.Log((object)$"[TerrainRandomiser] Starting generation with seed: {roomMapSettings.seed}"); string text = JsonConvert.SerializeObject((object)roomMapSettings, (Formatting)0); Debug.Log((object)text); Random.InitState(roomMapSettings.seed); for (int i = 0; i < roomMapSettings.biomes.Count; i++) { MapHandlerHelpers.ApplyBiomeToSegment(Singleton.Instance, i, roomMapSettings.biomes[i]); } List list = Singleton.Instance.segments.ToList(); list.AddRange(Singleton.Instance.variantSegments); foreach (MapSegment item in list) { if ((Object)(object)item.segmentParent.GetComponent() == (Object)null) { item.segmentParent.gameObject.AddComponent(); } } Stopwatch stopwatch = Stopwatch.StartNew(); PropGrouper component = ((Component)Singleton.Instance).GetComponent(); PropGrouperHelpers.RunRootPropGrouper(component); stopwatch.Stop(); Debug.Log((object)$"[TerrainRandomiser] Generation took: {stopwatch.ElapsedMilliseconds}"); if (PhotonNetwork.IsMasterClient) { List andAssignAllUnassignedViews = MapHandlerHelpers.GetAndAssignAllUnassignedViews(); viewIDsToSend.AddRange(andAssignAllUnassignedViews); Instance.SendViewIDsToClients(viewIDsToSend); } else { awaitingViewIDs = true; if (receivedViewIDs != null && receivedViewIDs.Count > 0) { Instance.UpdateRequiredViewIDs(); } } FakeItemManager.Instance.RefreshList(); return true; } private static void Postfix(MapHandler __instance) { if (Instance.roomMapSettings != null && Instance.roomMapSettings.enableRandomiser && !PhotonNetwork.IsMasterClient) { Instance.roomMapSettings = null; } } } public static Plugin Instance; private static Harmony _harmony; public static List viewIDsToSend; public static List? viewsRequiringIDs; public static List receivedViewIDs; public static bool awaitingViewIDs = false; public AssetBundle seedPickerUIBundle; public const int MAX_SEED_VALUE = 999999999; public MapSettings mapSettings; public MapSettings roomMapSettings; private RandomiserUIManager uiManager; private PhotonScopedManager photonManager; private GameObject uidocObject; public AssetBundle visibilityComputeBundle; private static readonly string SavePath = Path.Combine(Application.persistentDataPath, "TerrainRandomiser", "MapSettings.json"); public static ConfigEntry EnableLightMapBaking; public static int masterSeed => Instance.roomMapSettings.seed; private void Awake() { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Expected O, but got Unknown Instance = this; _harmony = new Harmony("com.snosz.terrainrandomiser"); ((BaseUnityPlugin)this).Config.SaveOnConfigSet = true; EnableLightMapBaking = ((BaseUnityPlugin)this).Config.Bind("General", "EnableLightMapBaking", true, "Generates a lightmap which is used for certain game mechanics. Disable this if the game crashes."); byte[] terrainrandomiser = Resource1.terrainrandomiser; seedPickerUIBundle = AssetBundle.LoadFromMemory(terrainrandomiser); byte[] visibilitycompute = Resource1.visibilitycompute; visibilityComputeBundle = AssetBundle.LoadFromMemory(visibilitycompute); LightMapBaker.computeShader = visibilityComputeBundle.LoadAsset("SkyVisibilityDDA"); LoadMapSettings(); if (mapSettings == null) { mapSettings = MapSettings.CreateDefaultMapSettings(); } AddPhotonManager(); _harmony.PatchAll(); } private void OnDestroy() { _harmony.UnpatchSelf(); if ((Object)(object)seedPickerUIBundle != (Object)null) { if ((Object)(object)uidocObject != (Object)null) { uidocObject.GetComponent().rootVisualElement.Clear(); Object.Destroy((Object)(object)uidocObject); } seedPickerUIBundle.Unload(true); seedPickerUIBundle = null; } } private void AddPhotonManager() { photonManager = PhotonCustomPropsUtilsPlugin.GetManager("com.snosz.terrainrandomiser"); photonManager.RegisterOnJoinedRoom((Action)delegate { if (PhotonNetwork.IsMasterClient) { string text = JsonConvert.SerializeObject((object)mapSettings, (Formatting)0); photonManager.SetRoomProperty("roomMapSettings", (object)text); } }); photonManager.RegisterRoomProperty("roomMapSettings", (RoomEventType)2, (Action)delegate(string value) { roomMapSettings = JsonConvert.DeserializeObject(value); }); photonManager.RegisterRoomProperty("propViews", (RoomEventType)2, (Action)delegate(int[] val) { if (!PhotonNetwork.IsMasterClient) { if (receivedViewIDs == null) { receivedViewIDs = new List(); } else { receivedViewIDs.Clear(); } receivedViewIDs = val.ToList(); if (awaitingViewIDs) { Instance.UpdateRequiredViewIDs(); } } }); } public void UpdateRequiredViewIDs() { if (PhotonNetwork.IsMasterClient) { return; } if (viewsRequiringIDs == null || receivedViewIDs == null) { Debug.LogError((object)"[TerrainRandomiser] Required lists did not initialize or have already been resolved."); return; } if (viewsRequiringIDs.Count > receivedViewIDs.Count) { Debug.LogError((object)"[TerrainRandomiser] ID Count mismatch! Map will be out of sync!"); return; } for (int i = 0; i < viewsRequiringIDs.Count; i++) { if ((Object)(object)viewsRequiringIDs[i] != (Object)null && (Object)(object)((Component)viewsRequiringIDs[i]).gameObject != (Object)null) { viewsRequiringIDs[i].ViewID = receivedViewIDs[i]; } else { Debug.LogError((object)$"Null or destroyed PhotonView at index {i}"); } } List allUnassignedViews = MapHandlerHelpers.GetAllUnassignedViews(); for (int j = 0; j < allUnassignedViews.Count; j++) { allUnassignedViews[j].ViewID = receivedViewIDs[viewsRequiringIDs.Count + j]; } Debug.LogError((object)$"[TerrainRandomiser] Updated receivedViewIDs with {receivedViewIDs.Count} IDs"); receivedViewIDs.Clear(); viewsRequiringIDs.Clear(); viewsRequiringIDs = null; awaitingViewIDs = false; } private void CreateUI(BoardingPass bpInstance) { GameObject val = Instance.seedPickerUIBundle.LoadAsset("UIDocument"); Instance.uidocObject = Object.Instantiate(val, ((Component)bpInstance).transform); uiManager = Instance.uidocObject.AddComponent(); } private static void RandomiseSeed(MapSettings settings) { settings.seed = Random.Range(0, 999999999); } private static void RandomiseAllSections(MapSettings settings) { List runtimeValidSections = BiomeDatabase.GetRuntimeValidSections(); for (int i = 0; i < runtimeValidSections.Count; i++) { ApplyRandomBiomeAndVariant(settings, i, runtimeValidSections[i]); } } private static void RandomiseOverrides(MapSettings settings) { List runtimeValidSections = BiomeDatabase.GetRuntimeValidSections(); for (int i = 0; i < settings.biomes.Count; i++) { BiomeSettings biomeSettings = settings.biomes[i]; if (biomeSettings.overrideEnabled) { if (biomeSettings.randomBiome) { ApplyRandomBiomeAndVariant(settings, i, runtimeValidSections[i]); } else if (biomeSettings.randomVariant) { ApplyRandomVariant(settings, i); } } } } private static void ApplyRandomBiomeAndVariant(MapSettings settings, int index, SectionData section) { int index2 = Random.Range(0, section.biomes.Count); settings.biomes[index].selectedBiome = section.biomes[index2]; ApplyRandomVariant(settings, index); } private static void ApplyRandomVariant(MapSettings settings, int index) { BiomeData selectedBiome = settings.biomes[index].selectedBiome; int index2 = Random.Range(0, selectedBiome.variants.Count); settings.biomes[index].selectedVariant = selectedBiome.variants[index2]; } private static void SyncWithClients(MapSettings settings) { //IL_003a: Unknown result type (might be due to invalid IL or missing references) Instance.roomMapSettings = settings; string text = JsonConvert.SerializeObject((object)Instance.roomMapSettings, (Formatting)0); Instance.photonManager.SetRoomProperty("roomMapSettings", (object)text); SteamLobbyHandler service = GameHandler.GetService(); SteamMatchmaking.SetLobbyData(service.LobbySteamId, "TR_roomMapSettings", text); } public void SendViewIDsToClients(List viewIDs) { photonManager.SetRoomProperty("propViews", (object)viewIDs.ToArray()); } public static void SaveMapSettings() { string contents = JsonConvert.SerializeObject((object)Instance.mapSettings, (Formatting)1); File.WriteAllText(SavePath, contents); } public static void LoadMapSettings() { string directoryName = Path.GetDirectoryName(SavePath); if (!Directory.Exists(directoryName)) { Directory.CreateDirectory(directoryName); } if (!File.Exists(SavePath)) { return; } string text = File.ReadAllText(SavePath); MapSettings mapSettings = JsonConvert.DeserializeObject(text); if (mapSettings == null) { return; } Instance.mapSettings = mapSettings; foreach (BiomeSettings biome in Instance.mapSettings.biomes) { if (biome.selectedBiome.variants.Count == 0) { Instance.mapSettings = MapSettings.CreateDefaultMapSettings(); break; } } } } public class RandomiserUIManager : MonoBehaviour { [SerializeField] private UIDocument uiDocument; private IntegerField seedInput; private Button randomSeedButton; private Toggle autoSeedToggle; private Toggle fullyRandomToggle; private Toggle enableRandomiserToggle; private VisualElement randomiserMenu; private VisualElement biomeTabContainer; private List biomeOverrideToggles = new List(); private List biomeDropdowns = new List(); private List variantDropdowns = new List(); private List runtimeSections; private MapSettings mapSettings; public void OnEnable() { runtimeSections = BiomeDatabase.GetRuntimeValidSections(); mapSettings = Plugin.Instance.mapSettings; biomeOverrideToggles.Clear(); biomeDropdowns.Clear(); variantDropdowns.Clear(); uiDocument = ((Component)this).GetComponent(); VisualElement rootVisualElement = uiDocument.rootVisualElement; seedInput = UQueryExtensions.Q(rootVisualElement, "seedInput", (string)null); randomSeedButton = UQueryExtensions.Q