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 SilkRoomUtils v0.0.23
BepInEx/plugins/SilkRoomUtils/SilkRoomUtils.dll
Decompiled 9 months agousing System; 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 System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Logging; using Microsoft.CodeAnalysis; using UnityEngine; using UnityEngine.SceneManagement; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("SilkRoomUtils")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("0.1.0.0")] [assembly: AssemblyInformationalVersion("0.1.0+275c2df1d9c5d7fdc7136ab8998caeab3ee513b8")] [assembly: AssemblyProduct("SilkRoomUtils")] [assembly: AssemblyTitle("SilkRoomUtils")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.1.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] 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; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace BepInEx { [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)] [Conditional("CodeGeneration")] internal sealed class BepInAutoPluginAttribute : Attribute { public BepInAutoPluginAttribute(string? id = null, string? name = null, string? version = null) { } } } namespace BepInEx.Preloader.Core.Patching { [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)] [Conditional("CodeGeneration")] internal sealed class PatcherAutoPluginAttribute : Attribute { public PatcherAutoPluginAttribute(string? id = null, string? name = null, string? version = null) { } } } namespace SilksongRooms._1 { public interface IRoomIntegrator { void RegisterRooms(IReadOnlyList<LoadedRoom> rooms); void OnSceneLoaded(Scene scene, LoadSceneMode mode, IReadOnlyList<LoadedRoom> rooms); } [Serializable] public class RoomDefinition { public string id = string.Empty; public string bundle = string.Empty; public string prefab = string.Empty; public Vector3 entryPoint; public string[] tags = Array.Empty<string>(); public Connection[] connections = Array.Empty<Connection>(); } [Serializable] public class Connection { public string toRoomId = string.Empty; public string doorName = string.Empty; } public class LoadedRoom { public RoomDefinition Definition = new RoomDefinition(); public AssetBundle? Bundle; public GameObject? Prefab; public string SourceJsonPath = string.Empty; } public sealed class RoomLoader { private readonly ManualLogSource _log; public List<LoadedRoom> LoadedRooms { get; } = new List<LoadedRoom>(); public RoomLoader(ManualLogSource log) { _log = log; } public void LoadAll(string roomsFolder) { LoadedRooms.Clear(); AddFromFolder(roomsFolder); } public List<LoadedRoom> AddFromFolder(string roomsFolder) { List<LoadedRoom> list = new List<LoadedRoom>(); if (!Directory.Exists(roomsFolder)) { _log.LogWarning((object)("Rooms folder does not exist: " + roomsFolder)); return list; } foreach (string item in Directory.EnumerateFiles(roomsFolder, "*.room.json", SearchOption.AllDirectories)) { LoadedRoom loaded = TryLoadFromJsonFile(item, roomsFolder); if (loaded != null) { int num = LoadedRooms.FindIndex((LoadedRoom r) => string.Equals(r.Definition.id, loaded.Definition.id, StringComparison.Ordinal)); if (num >= 0) { _log.LogWarning((object)("Room id '" + loaded.Definition.id + "' already loaded; replacing with definition from '" + item + "'.")); LoadedRooms[num] = loaded; } else { LoadedRooms.Add(loaded); } list.Add(loaded); } } return list; } public LoadedRoom? AddFromJsonFile(string jsonPath, string? resolveRoot = null) { string resolveRoot2 = resolveRoot ?? Path.GetDirectoryName(jsonPath) ?? Environment.CurrentDirectory; LoadedRoom loaded = TryLoadFromJsonFile(jsonPath, resolveRoot2); if (loaded == null) { return null; } int num = LoadedRooms.FindIndex((LoadedRoom r) => string.Equals(r.Definition.id, loaded.Definition.id, StringComparison.Ordinal)); if (num >= 0) { _log.LogWarning((object)("Room id '" + loaded.Definition.id + "' already loaded; replacing with definition from '" + jsonPath + "'.")); LoadedRooms[num] = loaded; } else { LoadedRooms.Add(loaded); } return loaded; } public bool TryGetRoom(string id, out LoadedRoom? room) { string id2 = id; room = LoadedRooms.FirstOrDefault((LoadedRoom r) => string.Equals(r.Definition.id, id2, StringComparison.Ordinal)); return room != null; } private LoadedRoom? TryLoadFromJsonFile(string jsonPath, string resolveRoot) { try { RoomDefinition roomDefinition = JsonUtility.FromJson<RoomDefinition>(File.ReadAllText(jsonPath)); if (roomDefinition == null || string.IsNullOrWhiteSpace(roomDefinition.id)) { _log.LogWarning((object)("Skipping invalid room: " + jsonPath)); return null; } LoadedRoom loadedRoom = new LoadedRoom { Definition = roomDefinition, SourceJsonPath = jsonPath }; if (!string.IsNullOrWhiteSpace(roomDefinition.bundle)) { string text = Path.Combine(resolveRoot, roomDefinition.bundle.Replace('/', Path.DirectorySeparatorChar)); if (File.Exists(text)) { loadedRoom.Bundle = AssetBundle.LoadFromFile(text); if ((Object)(object)loadedRoom.Bundle == (Object)null) { _log.LogError((object)("Failed to load AssetBundle for room '" + roomDefinition.id + "' at '" + text + "'.")); } else { if (!string.IsNullOrWhiteSpace(roomDefinition.prefab)) { loadedRoom.Prefab = loadedRoom.Bundle.LoadAsset<GameObject>(roomDefinition.prefab); if ((Object)(object)loadedRoom.Prefab == (Object)null) { _log.LogWarning((object)("Prefab '" + roomDefinition.prefab + "' not found in bundle for room '" + roomDefinition.id + "'.")); } } if ((Object)(object)loadedRoom.Prefab == (Object)null) { string[] allAssetNames = loadedRoom.Bundle.GetAllAssetNames(); foreach (string text2 in allAssetNames) { GameObject val = loadedRoom.Bundle.LoadAsset<GameObject>(text2); if ((Object)(object)val != (Object)null) { loadedRoom.Prefab = val; break; } } if ((Object)(object)loadedRoom.Prefab == (Object)null) { _log.LogWarning((object)("No GameObject prefab found in bundle for room '" + roomDefinition.id + "'.")); } } } } else { _log.LogError((object)("Bundle path not found for room '" + roomDefinition.id + "': " + text)); } } _log.LogDebug((object)("Loaded definition for room '" + roomDefinition.id + "'.")); return loadedRoom; } catch (Exception arg) { _log.LogError((object)$"Error loading room JSON '{jsonPath}': {arg}"); return null; } } } public static class RoomsApi { private static readonly List<Action<SilksongRooms__1Plugin>> _pending = new List<Action<SilksongRooms__1Plugin>>(); public static event Action<IReadOnlyList<LoadedRoom>>? RoomsAdded; internal static void Bind(SilksongRooms__1Plugin plugin) { if (_pending.Count <= 0) { return; } Action<SilksongRooms__1Plugin>[] array = _pending.ToArray(); foreach (Action<SilksongRooms__1Plugin> action in array) { try { action(plugin); } catch (Exception) { } } _pending.Clear(); } public static void RegisterRoomsFolder(string folder) { string folder2 = folder; SilksongRooms__1Plugin instanceOrNull = SilksongRooms__1Plugin.InstanceOrNull; if (instanceOrNull != null) { Do(instanceOrNull); } else { _pending.Add(Do); } void Do(SilksongRooms__1Plugin p) { IReadOnlyList<LoadedRoom> obj = p.RegisterRoomsFolder(folder2); RoomsApi.RoomsAdded?.Invoke(obj); } } public static void RegisterRoomJson(string jsonFilePath, string? resolveRoot = null) { string jsonFilePath2 = jsonFilePath; string resolveRoot2 = resolveRoot; SilksongRooms__1Plugin instanceOrNull = SilksongRooms__1Plugin.InstanceOrNull; if (instanceOrNull != null) { Do(instanceOrNull); } else { _pending.Add(Do); } void Do(SilksongRooms__1Plugin p) { LoadedRoom loadedRoom = p.RegisterRoomJson(jsonFilePath2, resolveRoot2); if (loadedRoom != null) { RoomsApi.RoomsAdded?.Invoke(new LoadedRoom[1] { loadedRoom }); } } } public static string GetDefaultRoomsFolder(string pluginName) { return Path.Combine(Paths.PluginPath, pluginName, "Rooms"); } } public sealed class SilksongRoomIntegrator : IRoomIntegrator { private readonly ManualLogSource _log; public SilksongRoomIntegrator(ManualLogSource log) { _log = log; } public void RegisterRooms(IReadOnlyList<LoadedRoom> rooms) { _log.LogInfo((object)$"Registering {rooms.Count} loaded room(s)."); foreach (LoadedRoom room in rooms) { _log.LogInfo((object)("Room: " + room.Definition.id + " | Bundle: " + (Object.op_Implicit((Object)(object)room.Bundle) ? ((Object)room.Bundle).name : "(none)") + " | Prefab: " + (Object.op_Implicit((Object)(object)room.Prefab) ? ((Object)room.Prefab).name : "(none)"))); } } public void OnSceneLoaded(Scene scene, LoadSceneMode mode, IReadOnlyList<LoadedRoom> rooms) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) GameObject val = (GameObject)(((object)GameObject.Find("__RoomsSandbox")) ?? ((object)new GameObject("__RoomsSandbox"))); Object.DontDestroyOnLoad((Object)(object)val); foreach (LoadedRoom room in rooms) { if (!((Object)(object)room.Prefab == (Object)null) && !((Object)(object)val.transform.Find(room.Definition.id) != (Object)null)) { GameObject obj = Object.Instantiate<GameObject>(room.Prefab, room.Definition.entryPoint, Quaternion.identity, val.transform); ((Object)obj).name = room.Definition.id; obj.SetActive(false); _log.LogInfo((object)("Spawned prefab for room '" + room.Definition.id + "' into sandbox (inactive). Enable it manually to preview.")); } } } } [BepInPlugin("io.github.silksongrooms__1", "SilkRoomUtils", "0.1.0")] public class SilksongRooms__1Plugin : BaseUnityPlugin { private static ManualLogSource? _log; private RoomLoader? _loader; private IRoomIntegrator? _integrator; public const string Id = "io.github.silksongrooms__1"; internal static ManualLogSource LogS => _log ?? (_log = Logger.CreateLogSource("SilksongRooms")); internal static SilksongRooms__1Plugin? InstanceOrNull { get; private set; } private string RoomsFolder => Path.Combine(Paths.PluginPath, ((BaseUnityPlugin)this).Info.Metadata.Name, "Rooms"); public static string Name => "SilkRoomUtils"; public static string Version => "0.1.0"; private void Awake() { InstanceOrNull = this; Directory.CreateDirectory(RoomsFolder); ((BaseUnityPlugin)this).Logger.LogInfo((object)("Plugin " + Name + " (io.github.silksongrooms__1) has loaded! Rooms folder: " + RoomsFolder)); _loader = new RoomLoader(((BaseUnityPlugin)this).Logger); _integrator = new SilksongRoomIntegrator(((BaseUnityPlugin)this).Logger); RoomsApi.Bind(this); SafeLoadAllRooms(); SceneManager.sceneLoaded += OnSceneLoaded; } private void OnDestroy() { SceneManager.sceneLoaded -= OnSceneLoaded; InstanceOrNull = null; } private void OnSceneLoaded(Scene scene, LoadSceneMode mode) { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) if (_loader == null || _integrator == null) { return; } try { _integrator.OnSceneLoaded(scene, mode, _loader.LoadedRooms); } catch (Exception arg) { ((BaseUnityPlugin)this).Logger.LogError((object)$"Room integrator OnSceneLoaded failed: {arg}"); } } private void SafeLoadAllRooms() { if (_loader == null || _integrator == null) { return; } try { _loader.LoadAll(RoomsFolder); _integrator.RegisterRooms(_loader.LoadedRooms); ((BaseUnityPlugin)this).Logger.LogInfo((object)$"Loaded {_loader.LoadedRooms.Count} room(s)."); } catch (Exception arg) { ((BaseUnityPlugin)this).Logger.LogError((object)$"Failed to load rooms: {arg}"); } } internal IReadOnlyList<LoadedRoom> RegisterRoomsFolder(string folder) { if (_loader == null || _integrator == null) { return Array.Empty<LoadedRoom>(); } List<LoadedRoom> list = _loader.AddFromFolder(folder); if (list.Count > 0) { _integrator.RegisterRooms(_loader.LoadedRooms); ((BaseUnityPlugin)this).Logger.LogInfo((object)$"Added {list.Count} room(s) from '{folder}'. Total: {_loader.LoadedRooms.Count}."); } else { ((BaseUnityPlugin)this).Logger.LogInfo((object)("No rooms found in '" + folder + "'.")); } return list; } internal LoadedRoom? RegisterRoomJson(string jsonFilePath, string? resolveRoot) { if (_loader == null || _integrator == null) { return null; } LoadedRoom loadedRoom = _loader.AddFromJsonFile(jsonFilePath, resolveRoot); if (loadedRoom != null) { _integrator.RegisterRooms(_loader.LoadedRooms); ((BaseUnityPlugin)this).Logger.LogInfo((object)$"Added room '{loadedRoom.Definition.id}' from '{jsonFilePath}'. Total: {_loader.LoadedRooms.Count}."); } return loadedRoom; } } }