Collapsible options, and fixes

This commit is contained in:
ang-xd committed 2024-08-27 13:57:38 -04:00
1 parent f4f2cf9182
commit 8a8fb7ced4
19 files changed
+209 -107

No files matched your search

@@ -11,7 +11,7 @@ public class ExampleTargetButton : CustomActionButton<PlayerControl>
public override float EffectDuration => 0f;
public override int MaxUses => 0;
public override LoadableAsset<Sprite> Sprite => ExampleAssets.ExampleButton;
protected override void OnClick()
{
PlayerControl.LocalPlayer.CmdCheckMurder(Target);
+2 -1
View File
@@ -9,7 +9,7 @@ using Reactor.Networking.Attributes;
namespace MiraAPI.Example;
[BepInAutoPlugin("mira.example", "MiraAPIExample")]
[BepInAutoPlugin("mira.example", "MiraExampleMod")]
[BepInProcess("Among Us.exe")]
[BepInDependency(ReactorPlugin.Id)]
[BepInDependency(MiraApiPlugin.Id)]
@@ -17,6 +17,7 @@ namespace MiraAPI.Example;
public partial class ExamplePlugin : BasePlugin, IMiraPlugin
{
public Harmony Harmony { get; } = new(Id);
public string OptionsTitleText => "Mira API\nExample Mod";
public ConfigFile GetConfigFile() => Config;
public override void Load()
{
+15 -15
View File
@@ -6,28 +6,28 @@ namespace MiraAPI.Example.Options;
public class ExampleOptions : AbstractOptionGroup
{
public override string GroupName => "General Group";
public override Color GroupColor => Color.red;
public override string GroupName => "Example Options 1";
public override Color GroupColor => Color.green;
[ModdedToggleOption("Use Thing")]
public bool UseThing { get; set; } = false;
[ModdedToggleOption("Toggle Opt 1")]
public bool ToggleOpt { get; set; } = false;
[ModdedToggleOption("Use another thing")]
public bool UseAnotherThing { get; set; } = true;
[ModdedToggleOption("Toggle Opt 2")]
public bool ToggleOpt2 { get; set; } = true;
[ModdedNumberOption("Sussy level", min: 0, max: 10)]
public float SussyLevel { get; set; } = 4f;
[ModdedNumberOption("Number Opt", min: 0, max: 10)]
public float NumberOpt { get; set; } = 4f;
[ModdedStringOption("Sus choices", ["hello", "hello 2", "hello 3"])]
public int SusChoices { get; set; } = 2;
[ModdedStringOption("String Opt", ["Hello", "Hey", "Bye"])]
public int StringOpt { get; set; } = 2;
[ModdedEnumOption("Enum test", typeof(TestEnum))]
public TestEnum EnumTest { get; set; } = TestEnum.Bye;
[ModdedEnumOption("Enum Opt", typeof(TestEnum))]
public TestEnum EnumOpt { get; set; } = TestEnum.Mira;
}
public enum TestEnum
{
Hello,
Hi,
Bye
Welcome,
To,
Mira
}
+16 -16
View File
@@ -5,23 +5,23 @@ namespace MiraAPI.Example.Options;
public class ExampleOptions2 : AbstractOptionGroup
{
public override string GroupName => "Example 2";
public ModdedToggleOption UseThing { get; } = new("Use Thingy 5", false);
public ModdedToggleOption UseThing2 { get; } = new("Use Thingy 6", false);
public ModdedStringOption Sussy { get; } = new("Sussy", 0, ["Sussy 1", "Sussy 2", "Sussy 3"]);
public ModdedEnumOption SussyEnum { get; } = new("Sussy Enum", 0, typeof(SussyEnum));
public ModdedNumberOption YeezyLevel { get; } = new("Yeezy Level", 50, 0, 100, 25, NumberSuffixes.Multiplier);
public override string GroupName => "Example Options 2";
public ModdedToggleOption ToggleOpt1 { get; } = new("Toggle Option 1", false);
public ModdedToggleOption ToggleOpt2 { get; } = new("Toggle Option 2", false)
{
Visible = () => OptionGroupSingleton<ExampleOptions2>.Instance.ToggleOpt1.Value
};
public ModdedStringOption StringOpt { get; } = new("String Opt", 0, ["Choice 1", "Choice 2", "Choice 3"]);
public ModdedEnumOption EnumOpt { get; } = new("Enum Opt", 0, typeof(TestingEnum));
}
public enum SussyEnum
public enum TestingEnum
{
Sussy,
Baka,
Imposter,
Kanye
Happy,
Sad,
Neutral
}
@@ -1,7 +1,7 @@
using System;
using MiraAPI.Example.Roles;
using MiraAPI.Example.Roles;
using MiraAPI.GameOptions;
using MiraAPI.GameOptions.Attributes;
using System;
namespace MiraAPI.Example.Options.Roles;
@@ -10,7 +10,7 @@ public class CustomRole2Settings : AbstractOptionGroup
public override string GroupName => "Custom Role";
public override Type AdvancedRole => typeof(CustomRole2);
[ModdedToggleOption("Teleportation ability")] public bool Teleport { get; set; } = true;
}
@@ -1,7 +1,7 @@
using System;
using MiraAPI.Example.Roles;
using MiraAPI.Example.Roles;
using MiraAPI.GameOptions;
using MiraAPI.GameOptions.Attributes;
using System;
namespace MiraAPI.Example.Options.Roles;
@@ -10,7 +10,7 @@ public class CustomRoleSettings : AbstractOptionGroup
public override string GroupName => "Custom Role";
public override Type AdvancedRole => typeof(CustomRole);
[ModdedNumberOption("Testing level", min: 3, max: 9)] public float TestingLevel { get; set; } = 4;
[ModdedNumberOption("Number Opt", min: 3, max: 9)] public float NumberOpt { get; set; } = 4;
}
+3 -3
View File
@@ -7,11 +7,11 @@ namespace MiraAPI.Example.Roles;
[RegisterCustomRole]
public class CustomRole : ImpostorRole, ICustomRole
{
public string RoleName => "fortnite killer";
public string RoleLongDescription => "ok so your objective is to eliminate everyone with your fortnite tactical shotgun, good luck";
public string RoleName => "Custom Role";
public string RoleLongDescription => "Eliminate everyone with your special ability!";
public string RoleDescription => RoleLongDescription;
public Color RoleColor => Palette.Black;
public ModdedRoleTeams Team => ModdedRoleTeams.Impostor;
public LoadableAsset<Sprite> OptionsScreenshot => ExampleAssets.Banner;
}
+3 -3
View File
@@ -7,11 +7,11 @@ namespace MiraAPI.Example.Roles;
[RegisterCustomRole]
public class CustomRole2 : CrewmateRole, ICustomRole
{
public string RoleName => "fortnite defender";
public string RoleLongDescription => "ok so your objective is to save everyone from the fortnite killer";
public string RoleName => "Custom Role 2";
public string RoleLongDescription => "Save everyone from dying!";
public string RoleDescription => RoleLongDescription;
public Color RoleColor => Palette.AcceptedGreen;
public ModdedRoleTeams Team => ModdedRoleTeams.Crewmate;
public LoadableAsset<Sprite> OptionsScreenshot => ExampleAssets.Banner;
}
-17
View File
@@ -1,17 +0,0 @@
using MiraAPI.Roles;
using MiraAPI.Utilities.Assets;
using UnityEngine;
namespace MiraAPI.Example.Roles;
[RegisterCustomRole]
public class CustomRole3 : CrewmateRole, ICustomRole
{
public string RoleName => "fortnite helper";
public string RoleLongDescription => "ok so your objective is to help";
public string RoleDescription => RoleLongDescription;
public Color RoleColor => Palette.Brown;
public ModdedRoleTeams Team => ModdedRoleTeams.Crewmate;
public LoadableAsset<Sprite> OptionsScreenshot => ExampleAssets.Banner;
}
+7 -4
View File
@@ -7,24 +7,27 @@ namespace MiraAPI.GameOptions;
public abstract class AbstractOptionGroup
{
public List<IModdedOption> Options { get; } = [];
/// <summary>
/// The name of the group. Visible in options menu.
/// </summary>
public abstract string GroupName { get; }
/// <summary>
/// A function that returns whether the group should be visible or not.
/// </summary>
public virtual Func<bool> GroupVisible => () => true;
/// <summary>
/// The group color. This is used to color the group in the options menu.
/// </summary>
public virtual Color GroupColor => Color.clear;
/// <summary>
/// The role the group is associated with. This is used for the advanced role options menu.
/// </summary>
public virtual Type AdvancedRole => null;
internal bool AllOptionsHidden = true;
internal CategoryHeaderMasked Header;
}
@@ -1,10 +1,10 @@
using MiraAPI.PluginLoading;
using BepInEx.Configuration;
using MiraAPI.Networking;
using MiraAPI.PluginLoading;
using MiraAPI.Roles;
using Reactor.Localization.Utilities;
using System;
using BepInEx.Configuration;
using MiraAPI.Networking;
using Reactor.Networking.Rpc;
using System;
using UnityEngine;
namespace MiraAPI.GameOptions.OptionTypes;
@@ -12,7 +12,7 @@ namespace MiraAPI.GameOptions.OptionTypes;
public abstract class ModdedOption<T> : IModdedOption
{
private IMiraPlugin _parentMod;
public uint Id { get; }
public BaseGameSetting Data { get; protected init; }
public IMiraPlugin ParentMod
@@ -33,7 +33,7 @@ public abstract class ModdedOption<T> : IModdedOption
public Func<bool> Visible { get; set; }
public Type AdvancedRole { get; set; }
public OptionBehaviour OptionBehaviour { get; set; }
public ConfigDefinition ConfigDefinition => new ("Options", Title);
public ConfigDefinition ConfigDefinition => new("Options", Title);
protected ModdedOption(string title, T defaultValue, Type roleType)
{
@@ -68,17 +68,17 @@ public abstract class ModdedOption<T> : IModdedOption
{
Rpc<SyncOptionsRpc>.Instance.Send(PlayerControl.LocalPlayer, [GetNetData()], true);
}
if (ParentMod?.GetConfigFile().TryGetEntry<T>(ConfigDefinition, out var entry) == true)
{
entry.Value = Value;
}
OnValueChanged(newValue);
}
public abstract NetData GetNetData();
public abstract void HandleNetData(byte[] data);
public abstract void OnValueChanged(T newValue);
+7
View File
@@ -9,8 +9,15 @@
<Description>Simple and easy to use Among Us modding API.</Description>
<Authors>Angxl, XtraCube</Authors>
</PropertyGroup>
<ItemGroup>
<None Remove="Resources\Buttons.png" />
<None Remove="Resources\Checkmark.png" />
<None Remove="Resources\CheckMarkBox.png" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Resources\Checkmark.png" />
<EmbeddedResource Include="Resources\CheckMarkBox.png" />
<EmbeddedResource Include="Resources\Cog.png" />
<EmbeddedResource Include="Resources\CogActive.png" />
<EmbeddedResource Include="Resources\NextButton.png" />
+3 -3
View File
@@ -2,8 +2,8 @@
using BepInEx.Unity.IL2CPP;
using HarmonyLib;
using MiraAPI.PluginLoading;
using Reactor;
using MiraAPI.Utilities;
using Reactor;
using Reactor.Networking;
using Reactor.Networking.Attributes;
using Reactor.Utilities;
@@ -19,13 +19,13 @@ public partial class MiraApiPlugin : BasePlugin
{
public Harmony Harmony { get; } = new(Id);
private static MiraPluginManager PluginManager { get; set; }
public static Color MiraColor = new Color32(238, 154, 112, 255);
public override void Load()
{
Harmony.PatchAll();
ReactorCredits.Register("Mira API", Version.Truncate(15, "") ?? Version, true, ReactorCredits.AlwaysShow);
PluginManager = new MiraPluginManager();
+96 -18
View File
@@ -1,11 +1,14 @@
using HarmonyLib;
using Il2CppSystem.Collections.Generic;
using MiraAPI.GameOptions;
using MiraAPI.Utilities;
using MiraAPI.Utilities.Assets;
using Reactor.Localization.Utilities;
using Reactor.Utilities.Extensions;
using System.Collections.Generic;
using System.Linq;
using TMPro;
using UnityEngine;
using UnityEngine.Events;
namespace MiraAPI.Patches.Options;
@@ -13,6 +16,59 @@ namespace MiraAPI.Patches.Options;
[HarmonyPatch(typeof(GameOptionsMenu))]
public static class GameOptionsMenuPatch
{
[HarmonyPostfix]
[HarmonyPatch(nameof(GameOptionsMenu.Update))]
public static void UpdatePatch(GameOptionsMenu __instance)
{
if (GameSettingMenuPatches.CurrentSelectedMod == 0)
{
return;
}
float num = 2.1f;
var filteredGroups = GameSettingMenuPatches.SelectedMod.OptionGroups.Where(x => x.GroupVisible.Invoke() && x.AdvancedRole is null);
foreach (AbstractOptionGroup group in filteredGroups)
{
var filteredOpts = group.Options.Where(x => x.Visible.Invoke()).ToList();
if (filteredOpts.Count == 0)
{
continue;
}
group.Header.gameObject.SetActive(true);
group.Header.transform.localScale = Vector3.one * 0.63f;
group.Header.transform.localPosition = new Vector3(-0.903f, num, -2f);
num -= 0.58f;
foreach (var opt in group.Options)
{
OptionBehaviour newOpt = opt.OptionBehaviour;
if (opt.Visible.Invoke() == false)
{
newOpt.gameObject.SetActive(false);
continue;
}
if (!group.AllOptionsHidden)
{
newOpt.gameObject.SetActive(true);
newOpt.transform.localPosition = new Vector3(0.952f, num, -2f);
num -= 0.45f;
}
else
{
newOpt.gameObject.SetActive(false);
}
}
}
__instance.scrollBar.SetYBoundsMax(-num - 1.65f);
}
[HarmonyPrefix]
[HarmonyPatch(nameof(GameOptionsMenu.CreateSettings))]
public static bool SettingsPatch(GameOptionsMenu __instance)
@@ -24,33 +80,31 @@ public static class GameOptionsMenuPatch
__instance.MapPicker.gameObject.SetActive(false);
float num = 2.1f;
var filteredGroups = GameSettingMenuPatches.SelectedMod.OptionGroups.Where(x => x.GroupVisible.Invoke() && x.AdvancedRole is null);
var filteredGroups = GameSettingMenuPatches.SelectedMod.OptionGroups.Where(x => x.AdvancedRole is null);
foreach (AbstractOptionGroup group in filteredGroups)
{
var filteredOpts = group.Options.Where(x => x.Visible.Invoke()).ToList();
if (filteredOpts.Count == 0)
{
continue;
}
CategoryHeaderMasked categoryHeaderMasked = Object.Instantiate(__instance.categoryHeaderOrigin, Vector3.zero, Quaternion.identity, __instance.settingsContainer);
categoryHeaderMasked.SetHeader(CustomStringName.CreateAndRegister(group.GroupName), 20);
if (group.GroupColor != Color.clear)
{
categoryHeaderMasked.Background.color = group.GroupColor;
categoryHeaderMasked.Divider.color = group.GroupColor;
categoryHeaderMasked.Title.color = group.GroupColor.GetAlternateColor();
}
categoryHeaderMasked.transform.localScale = Vector3.one * 0.63f;
categoryHeaderMasked.transform.localPosition = new Vector3(-0.903f, num, -2f);
num -= 0.63f;
categoryHeaderMasked.Background.size = new Vector2(categoryHeaderMasked.Background.size.x + 1.5f, categoryHeaderMasked.Background.size.y);
categoryHeaderMasked.gameObject.SetActive(false);
group.Header = categoryHeaderMasked;
foreach (var opt in filteredOpts)
TextMeshPro newText = GameObject.Instantiate(categoryHeaderMasked.Title, categoryHeaderMasked.transform);
newText.text = $"<size=70%>(Click to open)</size>";
newText.transform.localPosition = new Vector3(2.6249f, -0.165f, 0f);
newText.gameObject.GetComponent<TextTranslatorTMP>().Destroy();
List<OptionBehaviour> newOpts = new();
foreach (var opt in group.Options)
{
OptionBehaviour newOpt = opt.CreateOption(__instance.checkboxOrigin, __instance.numberOptionOrigin, __instance.stringOptionOrigin, __instance.settingsContainer);
newOpt.transform.localPosition = new Vector3(0.952f, num, -2f);
newOpt.SetClickMask(__instance.ButtonClickMask);
SpriteRenderer[] componentsInChildren = newOpt.GetComponentsInChildren<SpriteRenderer>(true);
@@ -80,14 +134,38 @@ public static class GameOptionsMenuPatch
textMeshPro.fontMaterial.SetFloat(ShaderID.Stencil, 20);
}
if (newOpt is ToggleOption toggle)
{
toggle.CheckMark.sprite = MiraAssets.Checkmark.LoadAsset();
SpriteRenderer rend = toggle.CheckMark.transform.parent.FindChild("ActiveSprite").GetComponent<SpriteRenderer>();
rend.sprite = MiraAssets.CheckmarkBox.LoadAsset();
rend.color = group.GroupColor;
}
__instance.Children.Add(newOpt);
num -= 0.45f;
newOpt.Initialize();
newOpts.Add(newOpt);
newOpt.gameObject.SetActive(false);
}
BoxCollider2D boxCol = categoryHeaderMasked.gameObject.AddComponent<BoxCollider2D>();
boxCol.size = new Vector2(7, 0.7f);
boxCol.offset = new Vector2(1.5f, -0.3f);
PassiveButton headerBtn = categoryHeaderMasked.gameObject.AddComponent<PassiveButton>();
headerBtn.ClickSound = __instance.BackButton.GetComponent<PassiveButton>().ClickSound;
headerBtn.OnMouseOver = new UnityEvent();
headerBtn.OnMouseOut = new UnityEvent();
headerBtn.OnClick.AddListener((UnityAction)(() =>
{
group.AllOptionsHidden = !group.AllOptionsHidden;
newText.text = group.AllOptionsHidden ? "<size=70%>(Click to open)</size>" : "<size=70%>(Click to close)</size>";
}));
headerBtn.SetButtonEnableState(true);
}
__instance.scrollBar.SetYBoundsMax(-num - 1.65f);
return false;
}
@@ -101,7 +179,7 @@ public static class GameOptionsMenuPatch
__instance.MapPicker.Initialize(20);
BaseGameSetting mapNameSetting = GameManager.Instance.GameSettingsList.MapNameSetting;
__instance.MapPicker.SetUpFromData(mapNameSetting, 20);
__instance.Children = new List<OptionBehaviour>();
__instance.Children = new Il2CppSystem.Collections.Generic.List<OptionBehaviour>();
__instance.Children.Add(__instance.MapPicker);
__instance.CreateSettings();
__instance.cachedData = GameOptionsManager.Instance.CurrentGameOptions;
@@ -21,10 +21,13 @@ public static class GameSettingMenuPatches
private static TextMeshPro _text;
private static Vector3 _roleBtnOgPos;
[HarmonyPrefix]
[HarmonyPatch(nameof(GameSettingMenu.Start))]
public static void StartPrefix(GameSettingMenu __instance)
{
_roleBtnOgPos = __instance.RoleSettingsButton.transform.localPosition;
__instance.transform.FindChild("GameSettingsLabel").gameObject.SetActive(false);
Transform helpThing = __instance.transform.FindChild("What Is This?");
@@ -36,7 +39,9 @@ public static class GameSettingMenuPatches
_text = tmpText.GetComponent<TextMeshPro>();
_text.fontSizeMax = 3.2f;
UpdateText(__instance.GameSettingsTab, __instance.RoleSettingsTab);
_text.overflowMode = TextOverflowModes.Overflow;
UpdateText(__instance, __instance.GameSettingsTab, __instance.RoleSettingsTab);
_text.alignment = TextAlignmentOptions.Center;
@@ -54,7 +59,7 @@ public static class GameSettingMenuPatches
if (CurrentSelectedMod != MiraPluginManager.Instance.RegisteredPlugins.Count)
{
CurrentSelectedMod += 1;
UpdateText(__instance.GameSettingsTab, __instance.RoleSettingsTab);
UpdateText(__instance, __instance.GameSettingsTab, __instance.RoleSettingsTab);
}
}));
@@ -68,12 +73,12 @@ public static class GameSettingMenuPatches
if (CurrentSelectedMod != 0)
{
CurrentSelectedMod -= 1;
UpdateText(__instance.GameSettingsTab, __instance.RoleSettingsTab);
UpdateText(__instance, __instance.GameSettingsTab, __instance.RoleSettingsTab);
}
}));
}
private static void UpdateText(GameOptionsMenu settings, RolesSettingsMenu roles)
private static void UpdateText(GameSettingMenu menu, GameOptionsMenu settings, RolesSettingsMenu roles)
{
if (CurrentSelectedMod == 0)
{
@@ -82,19 +87,41 @@ public static class GameSettingMenuPatches
}
else
{
_text.fontSizeMax = 2f;
_text.fontSizeMax = 2.3f;
SelectedMod = MiraPluginManager.Instance.RegisteredPlugins.ElementAt(CurrentSelectedMod - 1).Value;
if (SelectedMod == null)
{
CurrentSelectedMod = 0;
UpdateText(settings, roles);
UpdateText(menu, settings, roles);
}
string name = SelectedMod?.PluginInfo.Metadata.Name;
_text.text = name?[..Math.Min(name.Length, 15)];
string name = SelectedMod?.MiraPlugin.OptionsTitleText;
_text.text = name?[..Math.Min(name.Length, 25)];
}
if (roles?.roleChances != null)
menu.RoleSettingsButton.transform.localPosition = _roleBtnOgPos;
menu.GameSettingsButton.gameObject.SetActive(true);
menu.RoleSettingsButton.gameObject.SetActive(true);
if (CurrentSelectedMod != 0)
{
if (SelectedMod.OptionGroups.Count == 0)
{
menu.GameSettingsButton.gameObject.SetActive(false);
}
if (SelectedMod.CustomRoles.Count == 0)
{
menu.RoleSettingsButton.gameObject.SetActive(false);
}
if (!menu.GameSettingsButton.gameObject.active && menu.RoleSettingsButton.gameObject.active)
{
menu.RoleSettingsButton.transform.localPosition = menu.GameSettingsButton.transform.localPosition;
}
}
if (roles?.roleChances != null && SelectedMod != null && SelectedMod.CustomRoles.Count != 0)
{
if (roles.advancedSettingChildren is not null)
{
@@ -126,7 +153,7 @@ public static class GameSettingMenuPatches
roles.scrollBar.ScrollToTop();
}
if (settings?.Children != null)
if (settings?.Children != null && SelectedMod.OptionGroups.Count != 0)
{
foreach (var child in settings.Children)
{
+1
View File
@@ -4,5 +4,6 @@ namespace MiraAPI.PluginLoading;
public interface IMiraPlugin
{
string OptionsTitleText { get; }
public ConfigFile GetConfigFile();
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 347 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 370 B

+2
View File
@@ -7,4 +7,6 @@ public static class MiraAssets
public static readonly LoadableResourceAsset NextButton = new("MiraAPI.Resources.NextButton.png");
public static readonly LoadableResourceAsset NextButtonActive = new("MiraAPI.Resources.NextButtonActive.png");
public static readonly LoadableResourceAsset Cog = new("MiraAPI.Resources.Cog.png");
public static readonly LoadableResourceAsset Checkmark = new("MiraAPI.Resources.Checkmark.png");
public static readonly LoadableResourceAsset CheckmarkBox = new("MiraAPI.Resources.CheckMarkBox.png");
}