diff --git a/MiraAPI/Events/Mira/MiraButtonClickEvent.cs b/MiraAPI/Events/Mira/MiraButtonClickEvent.cs index dea3635..6126483 100644 --- a/MiraAPI/Events/Mira/MiraButtonClickEvent.cs +++ b/MiraAPI/Events/Mira/MiraButtonClickEvent.cs @@ -11,7 +11,7 @@ namespace MiraAPI.Events.Mira; /// The type. /// The that was clicked. /// The generic invoked before button-specific events. -public sealed class MiraButtonClickEvent(T button, MiraButtonClickEvent genericClickEvent) : MiraCancelableEvent where T : CustomActionButton +public class MiraButtonClickEvent(T button, MiraButtonClickEvent genericClickEvent) : MiraCancelableEvent where T : CustomActionButton { /// /// Gets the that was clicked. @@ -31,7 +31,7 @@ public sealed class MiraButtonClickEvent(T button, MiraButtonClickEvent gener /// Do not use for vanilla s. /// /// The that was clicked. -public sealed class MiraButtonClickEvent(CustomActionButton button) : MiraCancelableEvent +public class MiraButtonClickEvent(CustomActionButton button) : MiraCancelableEvent { /// /// Gets the that was clicked. diff --git a/MiraAPI/Hud/CustomButtonManager.cs b/MiraAPI/Hud/CustomButtonManager.cs index 378c907..9ea1953 100644 --- a/MiraAPI/Hud/CustomButtonManager.cs +++ b/MiraAPI/Hud/CustomButtonManager.cs @@ -18,6 +18,20 @@ public static class CustomButtonManager /// public static ReadOnlyCollection Buttons { get; internal set; } = new([]); + /// + /// Gets a list of all registered button-specific s. + /// + public static ReadOnlyDictionary EventTypes { get; internal set; } = new( + new Dictionary + { }); + + /// + /// Gets a list of all registered button-specific s. + /// + public static ReadOnlyDictionary CancelledEventTypes { get; internal set; } = new( + new Dictionary + { }); + internal static readonly List CustomButtons = []; internal static readonly Dictionary ButtonEventTypes = []; internal static readonly Dictionary ButtonCancelledEventTypes = []; diff --git a/MiraAPI/Patches/Options/RoleSettingMenuPatches.cs b/MiraAPI/Patches/Options/RoleSettingMenuPatches.cs index 4aecf06..b564f81 100644 --- a/MiraAPI/Patches/Options/RoleSettingMenuPatches.cs +++ b/MiraAPI/Patches/Options/RoleSettingMenuPatches.cs @@ -545,12 +545,8 @@ public static class RoleSettingMenuPatches __instance.roleDescriptionText.transform.parent.localScale = new Vector3(0.0675f, 0.1494f, 0.5687f); labelBg.transform.localPosition = new Vector3(1.082f, 0.1054f, -2.5f); - __instance.roleScreenshot.sprite = Sprite.Create( - role.RoleScreenshot.texture, - new Rect(0, 0, 370, 230), - Vector2.one / 2, - 100); - __instance.roleScreenshot.drawMode = SpriteDrawMode.Sliced; + __instance.roleScreenshot.sprite = role.RoleScreenshot; + __instance.roleScreenshot.drawMode = SpriteDrawMode.Simple; } __instance.roleHeaderSprite.color = customRole.OptionsMenuColor; diff --git a/MiraAPI/PluginLoading/MiraPluginManager.cs b/MiraAPI/PluginLoading/MiraPluginManager.cs index 8d385b5..1194533 100644 --- a/MiraAPI/PluginLoading/MiraPluginManager.cs +++ b/MiraAPI/PluginLoading/MiraPluginManager.cs @@ -139,6 +139,8 @@ public sealed class MiraPluginManager { // Save all buttons into a read-only collection for easy access CustomButtonManager.Buttons = new ReadOnlyCollection(CustomButtonManager.CustomButtons); + CustomButtonManager.EventTypes = new ReadOnlyDictionary(CustomButtonManager.ButtonEventTypes); + CustomButtonManager.CancelledEventTypes = new ReadOnlyDictionary(CustomButtonManager.ButtonCancelledEventTypes); // Cache all the registered plugins into an array for easy access RegisteredPlugins = [.. _registeredPlugins.Values]; diff --git a/MiraAPI/Roles/CustomRoleManager.cs b/MiraAPI/Roles/CustomRoleManager.cs index c5d62b2..91c3763 100644 --- a/MiraAPI/Roles/CustomRoleManager.cs +++ b/MiraAPI/Roles/CustomRoleManager.cs @@ -141,11 +141,18 @@ public static class CustomRoleManager roleBehaviour.CanVent = customRole.Configuration.CanUseVent || customRole.Configuration.GetsVentData; roleBehaviour.DefaultGhostRole = customRole.Configuration.GhostRole; roleBehaviour.MaxCount = customRole.Configuration.MaxRoleCount; - roleBehaviour.RoleScreenshot = Sprite.Create( - customRole.Configuration.OptionsScreenshot?.LoadAsset().texture, - new Rect(0, 0, 370, 230), - Vector2.one / 2, - 100); + if (customRole.Configuration.OptionsScreenshot != null) + { + roleBehaviour.RoleScreenshot = customRole.Configuration.OptionsScreenshot.LoadAsset(); + } + else + { + roleBehaviour.RoleScreenshot = Sprite.Create( + null, + new Rect(0, 0, 370, 230), + Vector2.one / 2, + 100); + } _emptySettings ??= new(0); _emptyKillAnimations ??= new(0); diff --git a/MiraAPI/Utilities/Assets/LoadableBundleSubAsset.cs b/MiraAPI/Utilities/Assets/LoadableBundleSubAsset.cs new file mode 100644 index 0000000..ef7aea3 --- /dev/null +++ b/MiraAPI/Utilities/Assets/LoadableBundleSubAsset.cs @@ -0,0 +1,37 @@ +using System; +using System.Linq; +using UnityEngine; + +namespace MiraAPI.Utilities.Assets; + +/// +/// A utility class for loading multiple assets from an . +/// +/// The name of the asset. +/// The that contains the asset. +public class LoadableBundleSubAsset(string name, LoadableBundleSubAssetHolder assetHolder) : LoadableAsset +{ + /// + /// Loads the asset from the . + /// + /// The asset. + /// The asset did not load properly. + public override Sprite LoadAsset() + { + if (LoadedAsset != null) + { + return LoadedAsset; + } + + assetHolder.TryInit(); + + var loadedAsset = assetHolder.SubSprites.FirstOrDefault(x => x.name == name); + + if (loadedAsset == null) + { + throw new InvalidOperationException($"INVALID ASSETS: {name}"); + } + LoadedAsset = loadedAsset; + return LoadedAsset; + } +} diff --git a/MiraAPI/Utilities/Assets/LoadableBundleSubAssetHolder.cs b/MiraAPI/Utilities/Assets/LoadableBundleSubAssetHolder.cs new file mode 100644 index 0000000..3b84d8d --- /dev/null +++ b/MiraAPI/Utilities/Assets/LoadableBundleSubAssetHolder.cs @@ -0,0 +1,86 @@ +using System; +using System.Linq; +using HarmonyLib; +using Il2CppInterop.Runtime; +using Reactor.Utilities.Extensions; +using UnityEngine; + +namespace MiraAPI.Utilities.Assets; + +/// +/// A utility class for loading multiple assets from an . +/// +public class LoadableBundleSubAssetHolder +{ + /// + /// Initializes a new instance of the class. + /// + /// The name of the assets to pull from. + /// The that contains the assets. + public LoadableBundleSubAssetHolder(string[] names, AssetBundle bundle) + { + Bundle = bundle; + SpriteNames = names; + } + + /// + /// Initializes a new instance of the class. + /// + /// The name of the asset. + /// The that contains the assets. + public LoadableBundleSubAssetHolder(string name, AssetBundle bundle) + { + Bundle = bundle; + SpriteNames = [name]; + } + internal string[] SpriteNames = []; + internal AssetBundle Bundle; + public Sprite[] SubSprites = []; + + public void TryInit() + { + if (SubSprites.Length == 0) + { + var newSprites = Array.Empty(); + foreach (var name in SpriteNames) + { + var loadedAssets = Bundle.LoadAssetWithSubAssets(name, Il2CppType.From(typeof(Sprite))).ToArray(); + + if (loadedAssets == null) + { + throw new InvalidOperationException($"INVALID ASSETS: {name}"); + } + foreach (var obj in loadedAssets) + { + var img = obj.TryCast(); + if (img != null) + { + img.DontDestroy().DontUnload(); + newSprites = newSprites.AddToArray(img); + } + } + } + + SubSprites = newSprites; + } + } + + /// + /// Unloads an asset. + /// + /// True if the asset was unloaded, false otherwise. + public bool UnloadAsset() + { + if (SubSprites.Length == 0) + { + return false; + } + + foreach (var sprite in SubSprites) + { + sprite.DestroyImmediate(); + } + SubSprites = []; + return true; + } +} diff --git a/MiraAPI/Utilities/Assets/TmpSpriteUtils.cs b/MiraAPI/Utilities/Assets/TmpSpriteUtils.cs index 8b9bf9f..561bfd0 100644 --- a/MiraAPI/Utilities/Assets/TmpSpriteUtils.cs +++ b/MiraAPI/Utilities/Assets/TmpSpriteUtils.cs @@ -106,8 +106,8 @@ public static class TmpSpriteUtils { name = spriteName, hashCode = TMP_TextUtilities.GetSimpleHashCode(spriteName), - x = 0, - y = 0, + x = rect.x, + y = rect.y, width = rect.width, height = rect.height, xOffset = -(rect.width / 3) + (scale - 1) * (rect.width / 2),