mirror of
https://github.com/All-Of-Us-Mods/MiraAPI.git
synced 2026-10-20 01:46:15 +00:00
Major work/rewrite on local settings
This commit is contained in:
1 parent
5fb59408fa
commit
b4e6e448f2
22 files changed
+539
-114
No files matched your search
@@ -5,10 +5,37 @@ using Reactor.Utilities;
|
||||
|
||||
namespace MiraAPI.Example;
|
||||
|
||||
public static class ExampleLocalSetings
|
||||
public class ExampleLocalSettings(ConfigFile config) : LocalSettingsTab(config)
|
||||
{
|
||||
public static LocalSettingsTab ModTab { get; } = new("Example Tab");
|
||||
public override string TabName => "Mira Example";
|
||||
|
||||
[LocalSetting]
|
||||
public static ConfigEntry<bool> ExampleToggleSetting { get; private set; }
|
||||
[LocalSettingToggle]
|
||||
public ConfigEntry<bool> PlayStartupSound { get; private set; } = config.Bind("Audio", "Play Startup Sound", true);
|
||||
|
||||
[LocalSettingToggle]
|
||||
public ConfigEntry<bool> MuteInBackground { get; private set; } = config.Bind("Audio", "Mute In Background", false);
|
||||
|
||||
[LocalSettingToggle]
|
||||
public ConfigEntry<bool> AutoSaveEnabled { get; private set; } = config.Bind("General", "Auto Save Enabled", true);
|
||||
|
||||
[LocalSettingToggle]
|
||||
public ConfigEntry<bool> EnableCloudSync { get; private set; } = config.Bind("General", "Enable Cloud Sync", false);
|
||||
|
||||
[LocalSettingToggle]
|
||||
public ConfigEntry<bool> ShowAdvancedTooltips { get; private set; } = config.Bind("UI", "Show Advanced Tooltips", true);
|
||||
|
||||
[LocalSettingToggle]
|
||||
public ConfigEntry<bool> CompactUI { get; private set; } = config.Bind("UI", "Compact UI Layout", false);
|
||||
|
||||
[LocalSettingToggle]
|
||||
public ConfigEntry<bool> EnableControllerSupport { get; private set; } = config.Bind("Input", "Enable Controller Support", true);
|
||||
|
||||
[LocalSettingToggle]
|
||||
public ConfigEntry<bool> EnableVibration { get; private set; } = config.Bind("Input", "Enable Controller Vibration", true);
|
||||
|
||||
[LocalSettingToggle]
|
||||
public ConfigEntry<bool> ShowPlayerNames { get; private set; } = config.Bind("Gameplay", "Show Player Names", true);
|
||||
|
||||
[LocalSettingToggle]
|
||||
public ConfigEntry<bool> EnableHardMode { get; private set; } = config.Bind("Gameplay", "Enable Hard Mode", false);
|
||||
}
|
||||
@@ -24,7 +24,5 @@ public partial class ExamplePlugin : BasePlugin, IMiraPlugin
|
||||
{
|
||||
ExampleEventHandlers.Initialize();
|
||||
Harmony.PatchAll();
|
||||
|
||||
Config.Keys.
|
||||
}
|
||||
}
|
||||
@@ -1,22 +1,21 @@
|
||||
using System;
|
||||
using BepInEx.Configuration;
|
||||
using UnityEngine;
|
||||
|
||||
namespace MiraAPI.LocalSettings.Attributes;
|
||||
|
||||
/// <summary>
|
||||
/// Base class for all local settings attributes.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The local setting type the attribute handles.</typeparam>
|
||||
[AttributeUsage(AttributeTargets.Property)]
|
||||
public abstract class LocalSettingAttribute(
|
||||
LocalSettingsTab tab,
|
||||
string? name = null,
|
||||
string? description = null) : Attribute
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns the created setting object.
|
||||
/// </summary>
|
||||
/// <param name="tab">Gets the tab where the setting is located.</param>
|
||||
/// <param name="configEntryBase">Gets the config entry the setting is attached to.</param>
|
||||
/// <returns>The created class.</returns>
|
||||
protected abstract GameObject CreateSetting();
|
||||
internal abstract ILocalSetting CreateSetting(Type tab, ConfigEntryBase configEntryBase);
|
||||
}
|
||||
@@ -10,17 +10,13 @@ namespace MiraAPI.LocalSettings.Attributes;
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Property)]
|
||||
public class LocalSettingToggleAttribute(
|
||||
LocalSettingsTab tab,
|
||||
string? name = null,
|
||||
string? description = null,
|
||||
Color? toggleColor = null,
|
||||
Color? toggleHoverColor = null,
|
||||
Color? toggleActiveColor = null
|
||||
) : LocalSettingAttribute<LocalSettingToggle>(tab, name, description)
|
||||
string? description = null
|
||||
) : LocalSettingAttribute(name, description)
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
protected override LocalSettingToggle CreateSetting(ConfigEntryBase configEntry)
|
||||
internal override LocalSettingToggle CreateSetting(Type tab, ConfigEntryBase configEntryBase)
|
||||
{
|
||||
return new LocalSettingToggle(tab, configEntry, name, description, toggleColor, toggleHoverColor, toggleActiveColor);
|
||||
return new LocalSettingToggle(tab, configEntryBase, name, description);
|
||||
}
|
||||
}
|
||||
@@ -8,9 +8,35 @@ namespace MiraAPI.LocalSettings;
|
||||
/// </summary>
|
||||
public interface ILocalSetting
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the preferred name of a setting.
|
||||
/// </summary>
|
||||
string Name { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the description of a setting.
|
||||
/// </summary>
|
||||
string Description { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the setting's gameobject.
|
||||
/// </summary>
|
||||
GameObject? Setting { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the setting's config entry.
|
||||
/// </summary>
|
||||
ConfigEntryBase ConfigEntry { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Used to create the setting
|
||||
/// </summary>
|
||||
/// <param name="toggle">Toggle template.</param>
|
||||
/// <param name="slider">Slider template.</param>
|
||||
/// <param name="parent">The parent of the setting.</param>
|
||||
/// <param name="offset">The offset.</param>
|
||||
/// <param name="order">The order.</param>
|
||||
/// <param name="last">Whether it's the last on the row.</param>
|
||||
/// <returns>The created setting.</returns>
|
||||
GameObject? CreateOption(ToggleButtonBehaviour toggle, SlideBar slider, Transform parent, ref float offset, ref int order, bool last);
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using BepInEx.Unity.IL2CPP;
|
||||
using MiraAPI.GameOptions;
|
||||
using Reactor.Utilities;
|
||||
|
||||
namespace MiraAPI.LocalSettings;
|
||||
|
||||
/// <summary>
|
||||
/// Manages local settings.
|
||||
/// </summary>
|
||||
public static class LocalSettingsManager
|
||||
{
|
||||
internal static readonly Dictionary<Type, LocalSettingsTab> TypeToTab = [];
|
||||
internal static readonly List<LocalSettingsTab> Tabs = [];
|
||||
|
||||
internal static bool RegisterTab(Type type, BasePlugin pluginInfo)
|
||||
{
|
||||
if (Activator.CreateInstance(type, pluginInfo.Config) is not LocalSettingsTab tab)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (TypeToTab.ContainsKey(type))
|
||||
{
|
||||
Logger<MiraApiPlugin>.Error($"Local settings tab {type.Name} already exists.");
|
||||
return false;
|
||||
}
|
||||
|
||||
Tabs.Add(tab);
|
||||
TypeToTab.Add(type, tab);
|
||||
|
||||
typeof(LocalSettingsTabSingleton<>).MakeGenericType(type)
|
||||
#pragma warning disable S3011
|
||||
.GetField("_instance", BindingFlags.Static | BindingFlags.NonPublic)!
|
||||
#pragma warning restore S3011
|
||||
.SetValue(null, tab);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1,81 +1,136 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using BepInEx.Configuration;
|
||||
using HarmonyLib;
|
||||
using MiraAPI.Patches.LocalSettings;
|
||||
using MiraAPI.Utilities;
|
||||
using MiraAPI.Utilities.Assets;
|
||||
using Reactor.Utilities.Extensions;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
namespace MiraAPI.LocalSettings;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a local settings tab. Gets a button by default
|
||||
/// </summary>
|
||||
public class LocalSettingsTab
|
||||
public abstract class LocalSettingsTab(ConfigFile config)
|
||||
{
|
||||
public string TabName { get; }
|
||||
public Color TabColor { get; }
|
||||
public Color TabHoverColor { get; }
|
||||
public Color TabActiveColor { get; }
|
||||
public LoadableAsset<Sprite>? TabIcon { get; }
|
||||
|
||||
public TabGroup? TabButton { get; protected set; }
|
||||
private bool ShouldCreateButton { get; set; }
|
||||
|
||||
public List<ILocalSetting> Settings { get; }
|
||||
/// <summary>
|
||||
/// Gets the name of the tab
|
||||
/// </summary>
|
||||
public abstract string TabName { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="LocalSettingsTab"/> class.
|
||||
/// Gets the tab button icon.
|
||||
/// </summary>
|
||||
/// <param name="tabName">The name of the tab.</param>
|
||||
/// <param name="tabColor">The color of the tab.</param>
|
||||
/// <param name="tabHoverColor">The hover color of the tab.</param>
|
||||
/// <param name="tabActiveColor">The active color of the tab.</param>
|
||||
/// <param name="tabIcon">The tab icon. Defaults to no icon.</param>
|
||||
/// <param name="createButton">Should the tab button be created. Without it the tab needs to be opened manually.</param>
|
||||
public LocalSettingsTab(string tabName, Color? tabColor = null, Color? tabHoverColor = null, Color? tabActiveColor = null, LoadableAsset<Sprite>? tabIcon = null, bool createButton = true)
|
||||
{
|
||||
TabName = tabName;
|
||||
TabColor = tabColor ?? Color.white;
|
||||
TabHoverColor = tabHoverColor ?? Palette.AcceptedGreen;
|
||||
TabActiveColor = tabActiveColor ?? Palette.AcceptedGreen;
|
||||
TabIcon = tabIcon;
|
||||
ShouldCreateButton = createButton;
|
||||
Settings = new();
|
||||
}
|
||||
public virtual LoadableAsset<Sprite>? TabIcon => null;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the color of the tab button.
|
||||
/// </summary>
|
||||
public virtual Color TabColor => Color.white;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the color of the tab button when hovered.
|
||||
/// </summary>
|
||||
public Color TabHoverColor => Palette.AcceptedGreen;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the color of the tab button when active.
|
||||
/// </summary>
|
||||
public virtual Color TabActiveColor => Palette.AcceptedGreen;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether a button should be created for the tab.
|
||||
/// </summary>
|
||||
protected virtual bool ShouldCreateButton => true;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the mod's config file. Automatically found in the plugin loader.
|
||||
/// </summary>
|
||||
public ConfigFile Config { get; } = config ?? throw new ArgumentNullException(nameof(config));
|
||||
|
||||
internal TabGroup? TabButton { get; set; }
|
||||
internal List<ILocalSetting> Settings { get; } = [];
|
||||
private Scroller? Scroller { get; set; }
|
||||
|
||||
internal GameObject? CreateTab(OptionsMenuBehaviour instance, ref int tabIdx, ref float offset)
|
||||
{
|
||||
if (ShouldCreateButton)
|
||||
{
|
||||
CreateTabButton(instance, ref tabIdx, ref offset);
|
||||
}
|
||||
|
||||
var tab = Object.Instantiate(instance.transform.FindChild("GeneralTab").gameObject, instance.transform);
|
||||
tab.name = $"{TabName}Tab";
|
||||
tab.transform.DestroyChildren();
|
||||
tab.gameObject.SetActive(false);
|
||||
|
||||
if (Scroller == null)
|
||||
{
|
||||
Scroller = Helpers.CreateScroller(tab.transform, OptionsMenuPatches.MaskCollider);
|
||||
}
|
||||
|
||||
if (TabButton != null)
|
||||
{
|
||||
TabButton.Content = tab.gameObject;
|
||||
}
|
||||
|
||||
var generalLabel = instance.transform.FindChild("GeneralTab").FindChild("ControlGroup")
|
||||
.FindChild("ControlText_TMP").gameObject;
|
||||
var toggle = instance.transform.FindChild("GeneralTab").FindChild("ChatGroup").FindChild("CensorChatButton").GetComponent<ToggleButtonBehaviour>();
|
||||
var slider = instance.transform.FindChild("GeneralTab").FindChild("SoundGroup").FindChild("SFXSlider").GetComponent<SlideBar>();
|
||||
|
||||
Dictionary<string, List<ILocalSetting>> entriesByGroup = new();
|
||||
foreach (var entry in Settings)
|
||||
{
|
||||
var group = entry.ConfigEntry.Definition.Section;
|
||||
if (!entriesByGroup.ContainsKey(group))
|
||||
entriesByGroup.Add(group, []);
|
||||
|
||||
entriesByGroup[group].Add(entry);
|
||||
}
|
||||
|
||||
float contentOffset = 0;
|
||||
var contentOrder = 1;
|
||||
var contentIndex = 1;
|
||||
foreach (var setting in Settings)
|
||||
|
||||
foreach (var pair in entriesByGroup)
|
||||
{
|
||||
setting.CreateOption(
|
||||
CreateLabel(generalLabel, Scroller.Inner, pair.Key, ref contentOffset);
|
||||
|
||||
foreach (var setting in pair.Value)
|
||||
{
|
||||
var obj = setting.CreateOption(
|
||||
toggle,
|
||||
slider,
|
||||
tab.transform,
|
||||
Scroller.Inner,
|
||||
ref contentOffset,
|
||||
ref contentOrder,
|
||||
contentIndex == Settings.Count);
|
||||
contentIndex == pair.Value.Count);
|
||||
|
||||
obj!.GetComponentsInChildren<SpriteRenderer>().Do(x =>
|
||||
{
|
||||
x.maskInteraction = SpriteMaskInteraction.VisibleInsideMask;
|
||||
x.sortingOrder = 150;
|
||||
x.sortingLayerName = "Default";
|
||||
});
|
||||
obj.GetComponentsInChildren<PassiveButton>().Do(x => { x.ClickMask = OptionsMenuPatches.MaskCollider; });
|
||||
|
||||
contentIndex++;
|
||||
}
|
||||
|
||||
if (ShouldCreateButton)
|
||||
contentOrder = 1;
|
||||
}
|
||||
|
||||
Scroller.SetBounds(new FloatRange(0, Settings.Count * 0.5f - 5f), new FloatRange(0, 0));
|
||||
return tab;
|
||||
}
|
||||
|
||||
private void CreateTabButton(OptionsMenuBehaviour instance, ref int tabIdx, ref float offset)
|
||||
{
|
||||
var tabButtonObject = Object.Instantiate(instance.Tabs[0], instance.transform);
|
||||
tabButtonObject.name = $"{TabName} Button";
|
||||
@@ -96,59 +151,81 @@ public class LocalSettingsTab
|
||||
rollover.OverColor = TabColor;
|
||||
rollover.OutColor = TabColor;
|
||||
|
||||
SpriteRenderer tabButtonRend = null;
|
||||
SpriteRenderer? tabButtonRend = null;
|
||||
if (TabIcon != null)
|
||||
{
|
||||
tabButtonRend = new GameObject("sprite").AddComponent<SpriteRenderer>();
|
||||
tabButtonRend.gameObject.layer = 5; // ui layer
|
||||
tabButtonRend.transform.SetParent(tabButtonObject.transform);
|
||||
tabButtonRend.transform.localPosition = new Vector3(0.5f, 0, -2);
|
||||
tabButtonRend.transform.localScale = new Vector3(0.5f, 0.5f, 1);
|
||||
tabButtonRend.transform.localScale = new Vector3(0.2f, 0.2f, 1);
|
||||
tabButtonRend.sprite = TabIcon.LoadAsset();
|
||||
tabButtonText.gameObject.SetActive(false);
|
||||
}
|
||||
|
||||
int tabIndex = tabIdx; // Local copies of the tab variables so we can use them in the lambdas
|
||||
float tabOffset = offset;
|
||||
tabButton.OnClick.AddListener((UnityAction)(() =>
|
||||
{
|
||||
instance.OpenTabGroup(tabIndex + 10);
|
||||
}));
|
||||
var tabIndex = tabIdx; // Local copies of the tab variables so we can use them in the lambdas
|
||||
var tabOffset = offset;
|
||||
tabButton.OnClick.AddListener((UnityAction)(() => { instance.OpenTabGroup(tabIndex + 10); }));
|
||||
tabButton.OnMouseOver.AddListener((UnityAction)(() =>
|
||||
{
|
||||
tabButton.transform.localPosition = new Vector3(3.55f, 2.1f - tabOffset, 5.5f);
|
||||
|
||||
if (tabButtonRend != null)
|
||||
{
|
||||
tabButtonRend.gameObject.SetActive(false);
|
||||
}
|
||||
tabButtonObject.Button.color = TabHoverColor;
|
||||
tabButtonObject.Rollover.OutColor = TabHoverColor;
|
||||
tabButtonText.gameObject.SetActive(true);
|
||||
tabButtonText.transform.localPosition = new Vector3(0.045f, 0, 0);
|
||||
tabButtonText.transform.localPosition = new Vector3(-0.024f, 0, 0);
|
||||
tabButtonText.maxVisibleCharacters = int.MaxValue;
|
||||
tabButtonText.text = TabName;
|
||||
tabButtonText.alignment = TextAlignmentOptions.Left;
|
||||
}));
|
||||
tabButton.OnMouseOut.AddListener((UnityAction)(() =>
|
||||
{
|
||||
tabButton.transform.localPosition = new Vector3(2.4f, 2.1f - tabOffset, 5.5f);
|
||||
if (!tabButtonObject.Content.gameObject.activeSelf)
|
||||
{
|
||||
tabButtonObject.Button.color = TabColor;
|
||||
tabButtonObject.Rollover.OutColor = TabColor;
|
||||
}
|
||||
|
||||
tabButton.transform.localPosition = new Vector3(2.4f, 2.1f - tabOffset, 5.5f);
|
||||
tabButtonText.alignment = TextAlignmentOptions.Right;
|
||||
if (tabButtonRend != null)
|
||||
{
|
||||
tabButtonRend.gameObject.SetActive(true);
|
||||
tabButtonText.gameObject.SetActive(false);
|
||||
}
|
||||
|
||||
tabButtonText.transform.localPosition = new Vector3(0.1f, 0, 0);
|
||||
tabButtonText.maxVisibleCharacters = 4;
|
||||
tabButtonText.text = $"<b>{GetShortName(TabName)}</b>";
|
||||
}));
|
||||
|
||||
offset += 0.6f;
|
||||
tabIdx++;
|
||||
}
|
||||
|
||||
return tab;
|
||||
private static void CreateLabel(GameObject template, Transform parent, string text, ref float offset)
|
||||
{
|
||||
var label = Object.Instantiate(template, parent);
|
||||
label.transform.localPosition = new Vector3(0, 1.85f - offset);
|
||||
label.GetComponent<TextTranslatorTMP>().Destroy();
|
||||
label.name = text;
|
||||
|
||||
var tmp = label.GetComponent<TextMeshPro>();
|
||||
tmp.text = $"<font=\"LiberationSans SDF\" material=\"LiberationSans SDF - Chat Message Masked\"><b>{text}</b></font>";
|
||||
tmp.alignment = TextAlignmentOptions.Center;
|
||||
|
||||
var meshRend = label.GetComponent<MeshRenderer>();
|
||||
meshRend.sortingLayerName = "Default";
|
||||
meshRend.sortingOrder = 151;
|
||||
|
||||
offset += 0.5f;
|
||||
}
|
||||
|
||||
|
||||
private static string GetShortName(string name)
|
||||
{
|
||||
string shortName = string.Empty;
|
||||
var shortName = string.Empty;
|
||||
name.Split(' ').Do(x => shortName += x[0]);
|
||||
return shortName;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
using System.Linq;
|
||||
using MiraAPI.LocalSettings;
|
||||
|
||||
namespace MiraAPI.GameOptions;
|
||||
|
||||
/// <summary>
|
||||
/// Singleton for local settings tabs.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The settings tab type.</typeparam>
|
||||
public static class LocalSettingsTabSingleton<T> where T : LocalSettingsTab
|
||||
{
|
||||
private static T? _instance;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the instance of the setting tab.
|
||||
/// </summary>
|
||||
#pragma warning disable CA1000
|
||||
public static T Instance => _instance ??= LocalSettingsManager.Tabs.OfType<T>().Single();
|
||||
#pragma warning restore CA1000
|
||||
}
|
||||
@@ -1,15 +1,23 @@
|
||||
using BepInEx.Configuration;
|
||||
using System;
|
||||
using BepInEx.Configuration;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
|
||||
namespace MiraAPI.LocalSettings.SettingTypes;
|
||||
|
||||
/// <inheritdoc />
|
||||
public abstract class LocalSettingBase<T> : ILocalSetting
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public string Name { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Description { get; }
|
||||
|
||||
public GameObject? Setting { get; }
|
||||
/// <inheritdoc />
|
||||
public GameObject? Setting { get; } = null!;
|
||||
|
||||
/// <inheritdoc />
|
||||
public ConfigEntryBase ConfigEntry { get; }
|
||||
|
||||
/// <summary>
|
||||
@@ -19,13 +27,13 @@ public abstract class LocalSettingBase<T> : ILocalSetting
|
||||
/// <param name="configEntry">The config entry.</param>
|
||||
/// <param name="name">The name of the setting.</param>
|
||||
/// <param name="description">The description of the setting.</param>
|
||||
protected LocalSettingBase(LocalSettingsTab tab, ConfigEntryBase configEntry, string? name = null, string? description = null)
|
||||
protected LocalSettingBase(Type tab, ConfigEntryBase configEntry, string? name = null, string? description = null)
|
||||
{
|
||||
ConfigEntry = configEntry;
|
||||
Name = name ?? ConfigEntry.Definition.Key;
|
||||
Description = description ?? ConfigEntry.Description.Description;
|
||||
|
||||
tab.Settings.Add(this);
|
||||
LocalSettingsManager.TypeToTab[tab].Settings.Add(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
using BepInEx.Configuration;
|
||||
using System;
|
||||
using BepInEx.Configuration;
|
||||
using MiraAPI.Utilities;
|
||||
using Reactor.Localization.Utilities;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
namespace MiraAPI.LocalSettings.SettingTypes;
|
||||
|
||||
@@ -37,7 +40,7 @@ public class LocalSettingToggle : LocalSettingBase<bool>
|
||||
/// <param name="toggleHoverColor">The hover color of the toggle.</param>
|
||||
/// <param name="toggleActiveColor">The active color of the toggle.</param>
|
||||
public LocalSettingToggle(
|
||||
LocalSettingsTab tab,
|
||||
Type tab,
|
||||
ConfigEntryBase configEntry,
|
||||
string? name = null,
|
||||
string? description = null,
|
||||
@@ -66,7 +69,7 @@ public class LocalSettingToggle : LocalSettingBase<bool>
|
||||
}
|
||||
else
|
||||
{
|
||||
toggleObject.transform.localPosition = new Vector3(order == 1 ? -1.35f : 1.28f, 1.85f - offset);
|
||||
toggleObject.transform.localPosition = new Vector3(order == 1 ? -1.185f : 1.185f, 1.85f - offset);
|
||||
}
|
||||
|
||||
toggleObject.BaseText = CustomStringName.CreateAndRegister(Name);
|
||||
@@ -95,6 +98,8 @@ public class LocalSettingToggle : LocalSettingBase<bool>
|
||||
toggleObject.Background.color = GetValue() ? ToggleActiveColor : ToggleColor;
|
||||
}));
|
||||
|
||||
Helpers.DivideSize(toggleObject.gameObject, 1.1f);
|
||||
|
||||
order++;
|
||||
if (order > 2 && !last)
|
||||
{
|
||||
|
||||
@@ -30,10 +30,6 @@ public partial class MiraApiPlugin : BasePlugin
|
||||
/// </summary>
|
||||
public static Color DefaultHeaderColor { get; } = new Color32(77, 77, 77, 255);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Mira Api Config Handler.
|
||||
/// </summary>
|
||||
public MiraApiConfig? MiraConfig { get; private set; }
|
||||
private static MiraPluginManager? PluginManager { get; set; }
|
||||
internal Harmony Harmony { get; } = new(Id);
|
||||
|
||||
@@ -44,7 +40,6 @@ public partial class MiraApiPlugin : BasePlugin
|
||||
|
||||
ReactorCredits.Register("Mira API", Version, true, ReactorCredits.AlwaysShow);
|
||||
|
||||
MiraConfig = new MiraApiConfig(Config);
|
||||
PluginManager = new MiraPluginManager();
|
||||
PluginManager.Initialize();
|
||||
}
|
||||
|
||||
@@ -2,7 +2,10 @@
|
||||
using BepInEx.Configuration;
|
||||
using BepInEx.Unity.IL2CPP;
|
||||
using HarmonyLib;
|
||||
using MiraAPI.LocalSettings;
|
||||
using MiraAPI.LocalSettings.Attributes;
|
||||
using MiraAPI.PluginLoading;
|
||||
using MiraAPI.Utilities.Assets;
|
||||
using Reactor;
|
||||
using Reactor.Networking;
|
||||
using Reactor.Networking.Attributes;
|
||||
@@ -14,10 +17,17 @@ namespace MiraAPI;
|
||||
/// <summary>
|
||||
/// Mira API Config File Handler
|
||||
/// </summary>
|
||||
public class MiraApiConfig(ConfigFile config)
|
||||
public class MiraApiSettings(ConfigFile config) : LocalSettingsTab(config)
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public override string TabName => "Mira API";
|
||||
|
||||
/// <inheritdoc />
|
||||
public override LoadableAsset<Sprite>? TabIcon => MiraAssets.SettingsIcon;
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether the modifiers hud should be on the left side of the screen (under roles/task tab). Recommended for streamers.
|
||||
/// </summary>
|
||||
[LocalSettingToggle]
|
||||
public ConfigEntry<bool> ModifiersHudLeftSide { get; private set; } = config.Bind("Displays", "Show Modifiers HUD on Left Side", false);
|
||||
}
|
||||
@@ -4,6 +4,7 @@ using System.Collections.Immutable;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using Il2CppInterop.Runtime.Attributes;
|
||||
using MiraAPI.GameOptions;
|
||||
using MiraAPI.Modifiers.ModifierDisplay;
|
||||
using MiraAPI.Modifiers.Types;
|
||||
using MiraAPI.Patches.Roles;
|
||||
@@ -129,7 +130,7 @@ public class ModifierComponent(IntPtr cppPtr) : MonoBehaviour(cppPtr)
|
||||
{
|
||||
var taskPanelOpen = HudManager.Instance.TaskPanel.open;
|
||||
var roleTabOpen = HudManagerPatches.RoleTab != null && HudManagerPatches.RoleTab.open;
|
||||
var leftSideHud = PluginSingleton<MiraApiPlugin>.Instance.MiraConfig!.ModifiersHudLeftSide.Value;
|
||||
var leftSideHud = LocalSettingsTabSingleton<MiraApiSettings>.Instance.ModifiersHudLeftSide.Value;
|
||||
|
||||
if (leftSideHud && (taskPanelOpen || roleTabOpen))
|
||||
{
|
||||
|
||||
@@ -4,6 +4,7 @@ using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using HarmonyLib;
|
||||
using Il2CppInterop.Runtime.Attributes;
|
||||
using MiraAPI.GameOptions;
|
||||
using MiraAPI.Patches.Roles;
|
||||
using MiraAPI.Utilities.Assets;
|
||||
using Reactor.Utilities;
|
||||
@@ -98,7 +99,7 @@ public class ModifierDisplayComponent(nint cppPtr) : MonoBehaviour(cppPtr)
|
||||
IsOpen = false;
|
||||
_children.gameObject.SetActive(false);
|
||||
|
||||
if (PluginSingleton<MiraApiPlugin>.Instance.MiraConfig!.ModifiersHudLeftSide.Value)
|
||||
if (LocalSettingsTabSingleton<MiraApiSettings>.Instance.ModifiersHudLeftSide.Value)
|
||||
{
|
||||
var aspect = GetComponent<AspectPosition>();
|
||||
_toggleButton.transform.localPosition = new Vector3(-1f, 2.7f, 0f);
|
||||
|
||||
@@ -0,0 +1,116 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using HarmonyLib;
|
||||
using MiraAPI.LocalSettings;
|
||||
using Reactor.Localization.Utilities;
|
||||
using Reactor.Utilities.Extensions;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
|
||||
namespace MiraAPI.Patches.LocalSettings;
|
||||
|
||||
[HarmonyPatch(typeof(OptionsMenuBehaviour))]
|
||||
public static class OptionsMenuPatches
|
||||
{
|
||||
internal static BoxCollider2D MaskCollider;
|
||||
/// <summary>
|
||||
/// Creates the tabs and their content
|
||||
/// </summary>
|
||||
[HarmonyPostfix]
|
||||
[HarmonyPatch(nameof(OptionsMenuBehaviour.Start))]
|
||||
public static void StartPostfix(OptionsMenuBehaviour __instance)
|
||||
{
|
||||
// Fix for tabs not being clickable in the main menu
|
||||
if (!AmongUsClient.Instance.IsInGame)
|
||||
{
|
||||
__instance.Background.GetComponent<BoxCollider2D>().enabled = false;
|
||||
__instance.transform.FindChild("Tint").SetLocalZ(5.6f);
|
||||
}
|
||||
|
||||
var maskObj = new GameObject
|
||||
{
|
||||
layer = 5,
|
||||
name = "SpriteMask",
|
||||
};
|
||||
maskObj.transform.SetParent(__instance.transform);
|
||||
maskObj.transform.localPosition = new Vector3(0, -0.3f, 0);
|
||||
maskObj.transform.localScale = new Vector3(500, 120, 1);
|
||||
|
||||
var blank = Sprite.Create(
|
||||
Texture2D.whiteTexture,
|
||||
new Rect(0, 0, Texture2D.whiteTexture.width, Texture2D.whiteTexture.height),
|
||||
new Vector2(0.5f, 0.5f));
|
||||
|
||||
var mask = maskObj.AddComponent<SpriteMask>();
|
||||
mask.sprite = blank;
|
||||
mask.isCustomRangeActive = true;
|
||||
mask.sortingLayerName = "Default";
|
||||
mask.backSortingOrder = 100;
|
||||
mask.frontSortingOrder = 500;
|
||||
|
||||
MaskCollider = maskObj.AddComponent<BoxCollider2D>();
|
||||
MaskCollider.size = new Vector2(0.01f, 0.1f);
|
||||
MaskCollider.isTrigger = true;
|
||||
MaskCollider.enabled = true;
|
||||
|
||||
float yOffset = 0;
|
||||
var i = 0;
|
||||
foreach (var settings in LocalSettingsManager.Tabs)
|
||||
{
|
||||
settings.CreateTab(__instance, ref i, ref yOffset);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Modifies how opening tabs is handled for the custom ones to work
|
||||
/// </summary>
|
||||
[HarmonyPrefix]
|
||||
[HarmonyPatch(nameof(OptionsMenuBehaviour.OpenTabGroup))]
|
||||
public static bool OpenTabGroupPrefix(OptionsMenuBehaviour __instance, ref int index)
|
||||
{
|
||||
__instance.Tabs.ToList().ForEach(x => x.Close()); // Close all vanilla tabs
|
||||
LocalSettingsManager.Tabs.ForEach(CustomClose); // Close all mod tabs
|
||||
|
||||
if (index >= 10) // Tabs with index 10 and above are the mod settings tabs
|
||||
{
|
||||
CustomOpen(LocalSettingsManager.Tabs[index - 10]);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Makes the custom tabs close when opening the options menu
|
||||
/// </summary>
|
||||
[HarmonyPostfix]
|
||||
[HarmonyPatch(nameof(OptionsMenuBehaviour.Open))]
|
||||
public static void OpenPostfix(OptionsMenuBehaviour __instance)
|
||||
{
|
||||
LocalSettingsManager.Tabs.ForEach(CustomClose);
|
||||
}
|
||||
|
||||
private static void CustomOpen(LocalSettingsTab tab)
|
||||
{
|
||||
if (tab.TabButton?.Button)
|
||||
tab.TabButton!.Button.color = tab.TabHoverColor;
|
||||
|
||||
if (tab.TabButton?.Rollover)
|
||||
tab.TabButton!.Rollover.OutColor = tab.TabHoverColor;
|
||||
|
||||
if (tab.TabButton?.Content)
|
||||
tab.TabButton!.Content.SetActive(true);
|
||||
}
|
||||
private static void CustomClose(LocalSettingsTab tab)
|
||||
{
|
||||
if (tab.TabButton?.Button)
|
||||
tab.TabButton!.Button.color = tab.TabColor;
|
||||
|
||||
if (tab.TabButton?.Rollover)
|
||||
tab.TabButton!.Rollover.OutColor = tab.TabColor;
|
||||
|
||||
if (tab.TabButton?.Content)
|
||||
tab.TabButton!.Content.SetActive(false);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
using HarmonyLib;
|
||||
using UnityEngine;
|
||||
|
||||
namespace MiraAPI.Patches.LocalSettings;
|
||||
|
||||
[HarmonyPatch(typeof(ToggleButtonBehaviour))]
|
||||
public static class ToggleBehaviourPatch
|
||||
{
|
||||
/// <summary>
|
||||
/// ResetText was inlined ofc
|
||||
/// </summary>
|
||||
[HarmonyPrefix]
|
||||
[HarmonyPatch(nameof(ToggleButtonBehaviour.UpdateText))]
|
||||
public static bool ResetTextPrefix(ToggleButtonBehaviour __instance, bool on)
|
||||
{
|
||||
__instance.onState = on;
|
||||
var color = on ? new Color(0f, 1f, 0.16470589f, 1f) : Color.white;
|
||||
__instance.Background.color = color;
|
||||
|
||||
// Used to mask the text
|
||||
__instance.Text.richText = true;
|
||||
__instance.Text.text = $"<font=\"LiberationSans SDF\" material=\"LiberationSans SDF - Chat Message Masked\">" +
|
||||
$"{DestroyableSingleton<TranslationController>.Instance.GetString(__instance.BaseText)}: <b>" +
|
||||
$"{DestroyableSingleton<TranslationController>.Instance.GetString(__instance.onState ? StringNames.SettingsOn : StringNames.SettingsOff)}</b></font>";
|
||||
|
||||
__instance.Text.sortingOrder = 151;
|
||||
__instance.Text.renderer.sortingLayerName = "Default";
|
||||
__instance.Text.renderer.sortingOrder = 151;
|
||||
|
||||
if (__instance.Rollover)
|
||||
{
|
||||
__instance.Rollover.ChangeOutColor(color);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,7 @@ using HarmonyLib;
|
||||
using MiraAPI.PluginLoading;
|
||||
using MiraAPI.Presets;
|
||||
using MiraAPI.Roles;
|
||||
using MiraAPI.Utilities;
|
||||
using MiraAPI.Utilities.Assets;
|
||||
using Reactor.Utilities;
|
||||
using Reactor.Utilities.Extensions;
|
||||
@@ -28,22 +29,6 @@ internal static class GamePresetsTabPatches
|
||||
|
||||
private static readonly object Lock = new();
|
||||
|
||||
public static void DivideSize(GameObject obj, float amount)
|
||||
{
|
||||
foreach (var collider in obj.GetComponentsInChildren<Collider2D>(true))
|
||||
{
|
||||
if (collider.TryCast<BoxCollider2D>() is { } col)
|
||||
{
|
||||
col.size = new Vector2(col.size.x / amount, col.size.y);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var rend in obj.GetComponentsInChildren<SpriteRenderer>(true))
|
||||
{
|
||||
rend.size = new Vector2(rend.size.x / amount, rend.size.y);
|
||||
}
|
||||
}
|
||||
|
||||
[HarmonyPatch(typeof(GamePresetsTab), nameof(GamePresetsTab.OnEnable))]
|
||||
public static class GamePresetsOnEnablePatch
|
||||
{
|
||||
@@ -207,7 +192,7 @@ internal static class GamePresetsTabPatches
|
||||
saveText.transform.parent.localPosition.y,
|
||||
saveText.transform.parent.localPosition.z);
|
||||
|
||||
DivideSize(saveButton.gameObject, 2f);
|
||||
Helpers.DivideSize(saveButton.gameObject, 2f);
|
||||
|
||||
saveButton.OnClick = new Button.ButtonClickedEvent();
|
||||
saveButton.OnClick.AddListener(
|
||||
@@ -276,7 +261,7 @@ internal static class GamePresetsTabPatches
|
||||
var iconSpriteRend = icon.AddComponent<SpriteRenderer>();
|
||||
iconSpriteRend.sprite = MiraAssets.RefreshIcon.LoadAsset();
|
||||
|
||||
DivideSize(refreshButton.gameObject, 2f);
|
||||
Helpers.DivideSize(refreshButton.gameObject, 2f);
|
||||
refreshButton.buttonText.gameObject.Destroy();
|
||||
|
||||
refreshButton.OnClick = new Button.ButtonClickedEvent();
|
||||
|
||||
@@ -5,6 +5,7 @@ using BepInEx.Configuration;
|
||||
using MiraAPI.GameModes;
|
||||
using MiraAPI.GameOptions;
|
||||
using MiraAPI.Hud;
|
||||
using MiraAPI.LocalSettings;
|
||||
using MiraAPI.Modifiers;
|
||||
using MiraAPI.Presets;
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ using MiraAPI.GameOptions;
|
||||
using MiraAPI.GameOptions.Attributes;
|
||||
using MiraAPI.Hud;
|
||||
using MiraAPI.Keybinds;
|
||||
using MiraAPI.LocalSettings;
|
||||
using MiraAPI.LocalSettings.Attributes;
|
||||
using MiraAPI.Modifiers;
|
||||
using MiraAPI.Presets;
|
||||
@@ -95,6 +96,11 @@ public sealed class MiraPluginManager
|
||||
continue;
|
||||
}
|
||||
|
||||
if (RegisterLocalTabs(type, plugin))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (RegisterRole(type, info, out var role))
|
||||
{
|
||||
roles.Add(role);
|
||||
@@ -111,7 +117,6 @@ public sealed class MiraPluginManager
|
||||
continue;
|
||||
}
|
||||
|
||||
RegisterLocalSettings(type);
|
||||
RegisterColorClasses(type);
|
||||
}
|
||||
|
||||
@@ -150,6 +155,8 @@ public sealed class MiraPluginManager
|
||||
Logger<MiraApiPlugin>.Info($"Registered keybind for button '{button.GetType().Name}' with default key {(KeyboardKeyCode)button.DefaultKeybind}.");
|
||||
}
|
||||
};
|
||||
|
||||
RegisterLocalTabs(typeof(MiraApiSettings), PluginSingleton<MiraApiPlugin>.Instance);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -321,45 +328,63 @@ public sealed class MiraPluginManager
|
||||
return false;
|
||||
}
|
||||
|
||||
private static void RegisterLocalSettings(Type type)
|
||||
private static bool RegisterLocalTabs(Type type, BasePlugin pluginInfo)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!type.IsStatic())
|
||||
if (!type.IsAssignableTo(typeof(LocalSettingsTab)))
|
||||
{
|
||||
Logger<MiraApiPlugin>.Error($"The type {type.Name} has to be static for local settings.");
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!LocalSettingsManager.RegisterTab(type, pluginInfo))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach (var property in type.GetProperties())
|
||||
{
|
||||
if (property.PropertyType.IsAssignableTo(typeof(ConfigEntryBase)))
|
||||
if (!typeof(ConfigEntryBase).IsAssignableFrom(property.PropertyType))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (property.GetValue(null) is not ConfigEntryBase configEntry)
|
||||
if (property.GetMethod?.IsStatic == true)
|
||||
{
|
||||
Logger<MiraApiPlugin>.Error($"Option property {property.Name} in {type.Name} must not be static.");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (LocalSettingsManager.TypeToTab[type] is not { } tabInstance)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var attribute = property.GetCustomAttribute<BaseLocalSettingAttribute>();
|
||||
if (property.GetValue(tabInstance) is not ConfigEntryBase configEntry)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var attribute = property.GetCustomAttribute<LocalSettingAttribute>();
|
||||
if (attribute == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
attribute.Create(configEntry);
|
||||
attribute.CreateSetting(type, configEntry);
|
||||
}
|
||||
|
||||
foreach (var field in type.GetFields().Where(f => f.FieldType.IsAssignableTo(typeof(ConfigEntryBase)) && f.GetCustomAttribute<BaseLocalSettingAttribute>() != null))
|
||||
foreach (var field in type.GetFields().Where(f => f.FieldType.IsAssignableTo(typeof(ConfigEntryBase)) && f.GetCustomAttribute<LocalSettingAttribute>() != null))
|
||||
{
|
||||
Logger<MiraApiPlugin>.Error($"{field.Name} is a field, not a property. Use properties for local settings.");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger<MiraApiPlugin>.Error($"Failed to register local settings from {type.Name}: {e}");
|
||||
Logger<MiraApiPlugin>.Error($"Failed to register options for {type.Name}: {e.ToString()}");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 9.4 KiB |
@@ -70,6 +70,11 @@ public static class MiraAssets
|
||||
/// </summary>
|
||||
public static LoadableResourceAsset NextButton { get; } = new("MiraAPI.Resources.NextButton.png");
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Mira settings icon..
|
||||
/// </summary>
|
||||
public static LoadableResourceAsset SettingsIcon { get; } = new("MiraAPI.Resources.Settings.png");
|
||||
|
||||
/// <summary>
|
||||
/// Gets the highlighted Next Button sprite.
|
||||
/// </summary>
|
||||
|
||||
@@ -3,8 +3,10 @@ using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using Il2CppInterop.Runtime.InteropTypes.Arrays;
|
||||
using Il2CppSystem.IO;
|
||||
using MiraAPI.Keybinds;
|
||||
using MiraAPI.Patches.LocalSettings;
|
||||
using MiraAPI.Utilities.Assets;
|
||||
using Rewired;
|
||||
using TMPro;
|
||||
@@ -26,6 +28,7 @@ public static class Helpers
|
||||
{
|
||||
return [.. GameData.Instance.AllPlayers.ToArray().Where(x => !x.IsDead && !x.Disconnected && x.Object).Select(x => x.Object)];
|
||||
}
|
||||
|
||||
internal static GameObject CreateKeybindIcon(GameObject button, KeyboardKeyCode keyCode, Vector3 localPos)
|
||||
{
|
||||
var keybindIcon = Object.Instantiate(HudManager.Instance.AbilityButton.usesRemainingSprite.gameObject, button.transform);
|
||||
@@ -36,6 +39,54 @@ public static class Helpers
|
||||
return keybindIcon;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a draggable scroller. Add items into the scroller.Inner transform. This does not automatically position children.
|
||||
/// </summary>
|
||||
/// <param name="parent">Where the scroller should be parented to.</param>
|
||||
/// <param name="hitBoxCollider">The collider of the scroller. Used to drag.</param>
|
||||
/// <returns>The created scroller object.</returns>
|
||||
public static Scroller CreateScroller(Transform parent, BoxCollider2D hitBoxCollider)
|
||||
{
|
||||
var scrollObj = new GameObject("Scroller");
|
||||
scrollObj.transform.SetParent(parent);
|
||||
scrollObj.transform.localScale = new Vector3(1, 1, 1);
|
||||
|
||||
var inner = new GameObject("Inner");
|
||||
inner.transform.SetParent(scrollObj.transform);
|
||||
inner.transform.localScale = new Vector3(1, 1, 1);
|
||||
inner.transform.localPosition = new Vector3(0, 0, 2);
|
||||
|
||||
var scroller = scrollObj.AddComponent<Scroller>();
|
||||
scroller.allowX = false;
|
||||
scroller.allowY = true;
|
||||
scroller.DragScrollSpeed = 1f;
|
||||
scroller.Colliders = new Il2CppReferenceArray<Collider2D>([hitBoxCollider]);
|
||||
scroller.Inner = inner.transform;
|
||||
|
||||
return scroller;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Divides a button/etc by a certain amount by resizing colliders and renderer sizes.
|
||||
/// </summary>
|
||||
/// <param name="obj">The object you want to divide.</param>
|
||||
/// <param name="amount">How much you want to divide by.</param>
|
||||
public static void DivideSize(GameObject obj, float amount)
|
||||
{
|
||||
foreach (var collider in obj.GetComponentsInChildren<Collider2D>(true))
|
||||
{
|
||||
if (collider.TryCast<BoxCollider2D>() is { } col)
|
||||
{
|
||||
col.size = new Vector2(col.size.x / amount, col.size.y);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var rend in obj.GetComponentsInChildren<SpriteRenderer>(true))
|
||||
{
|
||||
rend.size = new Vector2(rend.size.x / amount, rend.size.y);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the keybind for an action with ReInput.
|
||||
/// </summary>
|
||||
|
||||
Reference in new issue
Block a user