mirror of
https://github.com/All-Of-Us-Mods/MiraAPI.git
synced 2026-10-20 11:39:45 +00:00
Compare commits
40
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d751819534 | ||
|
|
b8b85e2bc3 | ||
|
|
043845ee11 | ||
|
|
df7c182abb | ||
|
|
2a4d16e65e | ||
|
|
840761787f | ||
|
|
615d527c86 | ||
|
|
7628a41d86 | ||
|
|
63d1003b2b | ||
|
|
0645c32cca | ||
|
|
8beabb20a2 | ||
|
|
3f28d70308 | ||
|
|
b919c55ef1 | ||
|
|
55a2161876 | ||
|
|
4ca2249fbd | ||
|
|
fc94c8e67e | ||
|
|
83e550c1f2 | ||
|
|
edee889ffe | ||
|
|
8c5aee4beb | ||
|
|
30a39fa223 | ||
|
|
228ed9711a | ||
|
|
7c085b1072 | ||
|
|
8750e5c894 | ||
|
|
1b40b1c5e4 | ||
|
|
0a0ad74419 | ||
|
|
992bdbcbf8 | ||
|
|
f9721a8d69 | ||
|
|
e541840da9 | ||
|
|
eb18d82d8e | ||
|
|
7afd899e56 | ||
|
|
5cccc192b1 | ||
|
|
9d7e41a3c9 | ||
|
|
662b52f78d | ||
|
|
dac1d82d5c | ||
|
|
1b718092ee | ||
|
|
3eb0a4fdb3 | ||
|
|
850e82155c | ||
|
|
ff30d5fdd6 | ||
|
|
2eecba2e51 | ||
|
|
84321f290e |
No files matched your search
@@ -8,7 +8,7 @@
|
||||
|
||||
<RestorePackagesWithLockFile>true</RestorePackagesWithLockFile>
|
||||
|
||||
<VersionPrefix>0.4.1</VersionPrefix>
|
||||
<VersionPrefix>0.4.3</VersionPrefix>
|
||||
<VersionSuffix>dev</VersionSuffix>
|
||||
|
||||
<Authors>All Of Us, XtraCube, Angxl</Authors>
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using System.Linq;
|
||||
using BepInEx;
|
||||
using BepInEx;
|
||||
using BepInEx.Configuration;
|
||||
using BepInEx.Unity.IL2CPP;
|
||||
using HarmonyLib;
|
||||
|
||||
@@ -10,6 +10,8 @@ public class ExampleOptions2 : AbstractOptionGroup
|
||||
|
||||
public override uint GroupPriority => 0; // This group will be displayed first. The default value is uint.MaxValue.
|
||||
|
||||
public override MenuCategory ParentMenu => MenuCategory.CustomTwo;
|
||||
|
||||
public ModdedPlayerOption PlayerOption2 { get; } = new("YOU MUST CHOSE A PLAYER", false);
|
||||
public ModdedPlayerOption PlayerOption { get; } = new("Eh whatever");
|
||||
public ModdedToggleOption ToggleOpt1 { get; } = new("Toggle Option 1", false);
|
||||
|
||||
@@ -9,7 +9,7 @@ public class GeneralModifierOptions : AbstractOptionGroup
|
||||
|
||||
public override uint GroupPriority => 0;
|
||||
|
||||
public override bool ShowInModifiersMenu => true;
|
||||
public override MenuCategory ParentMenu => MenuCategory.Modifiers;
|
||||
|
||||
[ModdedToggleOption("Some Boolean Option")]
|
||||
public bool SomeBooleanOption { get; set; } = true;
|
||||
|
||||
@@ -2,11 +2,17 @@
|
||||
using MiraAPI.GameOptions;
|
||||
using MiraAPI.GameOptions.Attributes;
|
||||
using MiraAPI.Utilities;
|
||||
using MiraAPI.Utilities.Assets;
|
||||
|
||||
namespace MiraAPI.Example.Options.Roles;
|
||||
|
||||
public class FreezerRoleSettings : AbstractOptionGroup<FreezerRole>
|
||||
{
|
||||
public override OptionNotifConfiguration Configuration => new(
|
||||
Palette.Blue,
|
||||
TmpSpriteUtils.CreateSpriteAsset(
|
||||
MiraAssets.ImpostorFile.LoadAsset(),
|
||||
"ApiExample.Role.Impostor.FreezerRole"));
|
||||
public override string GroupName => "Custom Role";
|
||||
|
||||
[ModdedNumberOption("Freeze Duration", 1, 15, 1, MiraNumberSuffixes.Seconds)]
|
||||
|
||||
@@ -6,7 +6,7 @@ using MiraAPI.Utilities;
|
||||
|
||||
namespace MiraAPI.Example.Options.Roles;
|
||||
|
||||
public class TeleporterOptions : AbstractOptionGroup<TeleporterRole>
|
||||
public class TeleporterOptions : AbstractRoleOptionGroup<TeleporterRole>
|
||||
{
|
||||
public override string GroupName => "Teleporter";
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using AmongUs.GameOptions;
|
||||
using MiraAPI.Patches.Stubs;
|
||||
using MiraAPI.Roles;
|
||||
using MiraAPI.Utilities.Assets;
|
||||
using Reactor.Utilities;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
@@ -20,6 +21,8 @@ public class ChameloenRole : CrewmateRole, ICustomRole
|
||||
public CustomRoleConfiguration Configuration => new(this)
|
||||
{
|
||||
OptionsScreenshot = ExampleAssets.Banner,
|
||||
Icon = MiraAssets.CrewmateFile,
|
||||
IconTmp = TmpSpriteUtils.CreateSpriteAsset(MiraAssets.CrewmateFile.LoadAsset(), "ApiExample.Role.Impostor.ChameleonRole"),
|
||||
IntroSound = CustomRoleUtils.GetIntroSound(RoleTypes.Shapeshifter),
|
||||
};
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using MiraAPI.Roles;
|
||||
using MiraAPI.Utilities.Assets;
|
||||
using UnityEngine;
|
||||
|
||||
namespace MiraAPI.Example.Roles;
|
||||
@@ -13,6 +14,8 @@ public class FreezerRole : ImpostorRole, ICustomRole
|
||||
|
||||
public CustomRoleConfiguration Configuration => new CustomRoleConfiguration(this)
|
||||
{
|
||||
Icon = MiraAssets.ImpostorFile,
|
||||
IconTmp = TmpSpriteUtils.CreateSpriteAsset(MiraAssets.ImpostorFile.LoadAsset(), "ApiExample.Role.Impostor.FreezerRole"),
|
||||
OptionsScreenshot = ExampleAssets.Banner,
|
||||
MaxRoleCount = 2,
|
||||
};
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using Reactor.Utilities;
|
||||
|
||||
namespace MiraAPI.Events;
|
||||
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
using MiraAPI.Voting;
|
||||
|
||||
namespace MiraAPI.Events.Vanilla.Meeting.Voting;
|
||||
namespace MiraAPI.Events.Vanilla.Meeting.Voting;
|
||||
|
||||
/// <summary>
|
||||
/// Event that is invoked after the local player successfully votes a player or skips. This event is not cancelable.
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
using MiraAPI.Voting;
|
||||
|
||||
namespace MiraAPI.Events.Vanilla.Meeting.Voting;
|
||||
namespace MiraAPI.Events.Vanilla.Meeting.Voting;
|
||||
|
||||
/// <summary>
|
||||
/// Event that is invoked before the local player confirms a vote on a player or when skipping. This event is cancelable.
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Reactor.Utilities;
|
||||
|
||||
namespace MiraAPI.GameEnd;
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Reactor.Utilities;
|
||||
|
||||
namespace MiraAPI.GameModes;
|
||||
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using MiraAPI.Modifiers;
|
||||
using MiraAPI.Roles;
|
||||
using UnityEngine;
|
||||
|
||||
namespace MiraAPI.GameOptions;
|
||||
@@ -40,7 +42,7 @@ public abstract class AbstractOptionGroup
|
||||
/// <summary>
|
||||
/// Gets a value indicating which menu the group is in.
|
||||
/// </summary>
|
||||
public virtual MenuCategory ParentMenu => MenuCategory.Roles;
|
||||
public virtual MenuCategory ParentMenu => MenuCategory.Game;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the function that determines whether the group should be visible or not.
|
||||
@@ -58,9 +60,16 @@ public abstract class AbstractOptionGroup
|
||||
/// </summary>
|
||||
public virtual uint GroupPriority => uint.MaxValue;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the default notification settings for the group.
|
||||
/// </summary>
|
||||
public virtual OptionNotifConfiguration Configuration => new(new Color(0.7333f, 0.7333f, 0.7333f, 1));
|
||||
|
||||
internal bool AllOptionsHidden { get; set; }
|
||||
|
||||
internal CategoryHeaderMasked? Header { get; set; }
|
||||
|
||||
internal bool Ready { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -72,9 +81,7 @@ public abstract class AbstractOptionGroup<T> : AbstractOptionGroup where T : IOp
|
||||
/// <inheritdoc />
|
||||
public override Type OptionableType => typeof(T);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating which menu the group is in.
|
||||
/// </summary>
|
||||
/// <inheritdoc />
|
||||
public override MenuCategory ParentMenu
|
||||
{
|
||||
get
|
||||
@@ -93,11 +100,43 @@ public abstract class AbstractOptionGroup<T> : AbstractOptionGroup where T : IOp
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Base class for option groups. An option group is a collection of options that are displayed together in the options menu.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The custom role that the group is for.</typeparam>
|
||||
public abstract class AbstractRoleOptionGroup<T>() : AbstractOptionGroup<T> where T : ICustomRole
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public override Type OptionableType => typeof(T);
|
||||
|
||||
/// <inheritdoc />
|
||||
public override MenuCategory ParentMenu => MenuCategory.Roles;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override OptionNotifConfiguration Configuration
|
||||
{
|
||||
get
|
||||
{
|
||||
var role = CustomRoleManager.CustomMiraRoles.FirstOrDefault(x => x.GetType() == OptionableType);
|
||||
if (role == null)
|
||||
{
|
||||
return new(new Color(0.7333f, 0.7333f, 0.7333f, 1));
|
||||
}
|
||||
return new(role.RoleColor, role.Configuration.IconTmp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Menu categories for option groups.
|
||||
/// </summary>
|
||||
public enum MenuCategory
|
||||
{
|
||||
/// <summary>
|
||||
/// Placeholder for indexing purposes. Options don't exist in the presset tab.
|
||||
/// </summary>
|
||||
Preset,
|
||||
|
||||
/// <summary>
|
||||
/// Determines the option group is in the game settings tab.
|
||||
/// </summary>
|
||||
|
||||
@@ -21,6 +21,16 @@ public interface IModdedOption
|
||||
/// </summary>
|
||||
string Title { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the parent <see cref="AbstractOptionGroup"/> of the option.
|
||||
/// </summary>
|
||||
AbstractOptionGroup ParentGroup { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the notification settings for the option.
|
||||
/// </summary>
|
||||
OptionNotifConfiguration Configuration { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="StringNames"/> for the option, used for localization.
|
||||
/// </summary>
|
||||
|
||||
@@ -12,6 +12,8 @@ using MiraAPI.PluginLoading;
|
||||
using MiraAPI.Utilities;
|
||||
using Reactor.Networking.Rpc;
|
||||
using Reactor.Utilities;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
|
||||
namespace MiraAPI.GameOptions;
|
||||
|
||||
@@ -30,6 +32,36 @@ public static class ModdedOptionsManager
|
||||
internal static uint NextId => _nextId++;
|
||||
private static uint _nextId = 1;
|
||||
|
||||
public static void AddSettingsChangeMessage(NotificationPopper notif, StringNames key, string value, Color textColor, TMP_SpriteAsset? sprite, bool playSound = true)
|
||||
{
|
||||
var item = string.Empty;
|
||||
var text = textColor.ToTextColor();
|
||||
if (sprite != null)
|
||||
{
|
||||
item = TranslationController.Instance.GetString(
|
||||
StringNames.LobbyChangeSettingNotification,
|
||||
string.Concat(
|
||||
"<sprite name=\"",
|
||||
sprite.name,
|
||||
"\"><font=\"Barlow-Black SDF\" material=\"Barlow-Black Outline\">",
|
||||
text,
|
||||
TranslationController.Instance.GetString(key),
|
||||
"</color></font>"),
|
||||
"<font=\"Barlow-Black SDF\" material=\"Barlow-Black Outline\">" + value + "</font>"
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
item = TranslationController.Instance.GetString(
|
||||
StringNames.LobbyChangeSettingNotification,
|
||||
"<font=\"Barlow-Black SDF\" material=\"Barlow-Black Outline\">" +
|
||||
text +
|
||||
TranslationController.Instance.GetString(key) + "</color></font>",
|
||||
"<font=\"Barlow-Black SDF\" material=\"Barlow-Black Outline\">" + value + "</font>");
|
||||
}
|
||||
notif.SettingsChangeMessageLogic(key, item, playSound);
|
||||
}
|
||||
|
||||
internal static bool RegisterGroup(Type type, MiraPluginInfo pluginInfo)
|
||||
{
|
||||
if (Activator.CreateInstance(type) is not AbstractOptionGroup group)
|
||||
@@ -123,6 +155,7 @@ public static class ModdedOptionsManager
|
||||
|
||||
option.ConfigDefinition = new ConfigDefinition(groupName, propertyName);
|
||||
|
||||
option.ParentGroup = group;
|
||||
option.ParentMod = pluginInfo.MiraPlugin;
|
||||
pluginInfo.InternalOptions.Add(option);
|
||||
ModdedOptions.Add(option.Id, option);
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
using System;
|
||||
using Il2CppInterop.Runtime.Attributes;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
namespace MiraAPI.GameOptions;
|
||||
|
||||
/// <summary>
|
||||
/// Used to configure the specific visuals for option notifications.
|
||||
/// </summary>
|
||||
public record struct OptionNotifConfiguration
|
||||
{
|
||||
#pragma warning disable S1133
|
||||
[Obsolete("Default constructor is not supported")]
|
||||
#pragma warning restore S1133
|
||||
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
|
||||
public OptionNotifConfiguration()
|
||||
#pragma warning restore CS1591 // Missing XML comment for publicly visible type or member
|
||||
{
|
||||
throw new NotImplementedException("Default constructor is not supported.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="OptionNotifConfiguration"/> struct based on a group.
|
||||
/// </summary>
|
||||
/// <param name="group">The <see cref="AbstractOptionGroup"/> in which you are configuring.</param>
|
||||
public OptionNotifConfiguration(AbstractOptionGroup group)
|
||||
{
|
||||
PopUpIconTmp = group.Configuration.PopUpIconTmp;
|
||||
PopUpTextColor = group.Configuration.PopUpTextColor;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="OptionNotifConfiguration"/> struct from scratch.
|
||||
/// </summary>
|
||||
/// <param name="color">The text <see cref="Color"/> for the configuration.</param>
|
||||
/// <param name="asset">The <see cref="TMP_SpriteAsset"/> icon for the configuration.</param>
|
||||
public OptionNotifConfiguration(Color color, TMP_SpriteAsset asset = null!)
|
||||
{
|
||||
PopUpIconTmp = asset;
|
||||
PopUpTextColor = color;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the <see cref="TMP_SpriteAsset"/> for the icon on the options pop-up.
|
||||
/// </summary>
|
||||
public TMP_SpriteAsset PopUpIconTmp { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the <see cref="Color"/> for the text on the options pop-up.
|
||||
/// </summary>
|
||||
[HideFromIl2Cpp]
|
||||
public Color PopUpTextColor { get; set; }
|
||||
}
|
||||
@@ -90,7 +90,13 @@ public class ModdedEnumOption : ModdedOption<int>
|
||||
/// <inheritdoc />
|
||||
protected override void OnValueChanged(int newValue)
|
||||
{
|
||||
HudManager.Instance.Notifier.AddSettingsChangeMessage(StringName, Data.GetValueString(newValue), false);
|
||||
ModdedOptionsManager.AddSettingsChangeMessage(
|
||||
HudManager.Instance.Notifier,
|
||||
StringName,
|
||||
Data.GetValueString(newValue),
|
||||
Configuration.PopUpTextColor,
|
||||
Configuration.PopUpIconTmp,
|
||||
false);
|
||||
if (!OptionBehaviour)
|
||||
{
|
||||
return;
|
||||
@@ -183,7 +189,13 @@ public class ModdedEnumOption<T> : ModdedOption<T> where T : Enum
|
||||
/// <inheritdoc />
|
||||
protected override void OnValueChanged(T newValue)
|
||||
{
|
||||
HudManager.Instance.Notifier.AddSettingsChangeMessage(StringName, Data.GetValueString(Convert.ToInt32(newValue, NumberFormatInfo.InvariantInfo)), false);
|
||||
ModdedOptionsManager.AddSettingsChangeMessage(
|
||||
HudManager.Instance.Notifier,
|
||||
StringName,
|
||||
Data.GetValueString(Convert.ToInt32(newValue, NumberFormatInfo.InvariantInfo)),
|
||||
Configuration.PopUpTextColor,
|
||||
Configuration.PopUpIconTmp,
|
||||
false);
|
||||
if (!OptionBehaviour)
|
||||
{
|
||||
return;
|
||||
|
||||
@@ -225,9 +225,12 @@ public class ModdedNumberOption : ModdedOption<float>
|
||||
protected override void OnValueChanged(float newValue)
|
||||
{
|
||||
Value = Mathf.Clamp(newValue, Min, Max);
|
||||
HudManager.Instance.Notifier.AddSettingsChangeMessage(
|
||||
ModdedOptionsManager.AddSettingsChangeMessage(
|
||||
HudManager.Instance.Notifier,
|
||||
StringName,
|
||||
Data.GetValueString(Value),
|
||||
Data.GetValueString(newValue),
|
||||
Configuration.PopUpTextColor,
|
||||
Configuration.PopUpIconTmp,
|
||||
false);
|
||||
|
||||
if (OptionBehaviour is NumberOption opt)
|
||||
|
||||
@@ -4,7 +4,6 @@ using MiraAPI.Networking;
|
||||
using MiraAPI.PluginLoading;
|
||||
using Reactor.Localization.Utilities;
|
||||
using Reactor.Networking.Rpc;
|
||||
using Reactor.Utilities;
|
||||
using UnityEngine;
|
||||
|
||||
namespace MiraAPI.GameOptions.OptionTypes;
|
||||
@@ -190,4 +189,10 @@ public abstract class ModdedOption<T> : IModdedOption
|
||||
{
|
||||
return option.Value;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public AbstractOptionGroup ParentGroup { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public virtual OptionNotifConfiguration Configuration => new(ParentGroup);
|
||||
}
|
||||
@@ -126,7 +126,13 @@ public class ModdedPlayerOption : ModdedOption<int>
|
||||
/// <inheritdoc />
|
||||
protected override void OnValueChanged(int newValue)
|
||||
{
|
||||
HudManager.Instance.Notifier.AddSettingsChangeMessage(StringName, Data.GetValueString(newValue), false);
|
||||
ModdedOptionsManager.AddSettingsChangeMessage(
|
||||
HudManager.Instance.Notifier,
|
||||
StringName,
|
||||
Data.GetValueString(newValue),
|
||||
Configuration.PopUpTextColor,
|
||||
Configuration.PopUpIconTmp,
|
||||
false);
|
||||
if (!OptionBehaviour)
|
||||
{
|
||||
return;
|
||||
|
||||
@@ -71,7 +71,13 @@ public class ModdedToggleOption : ModdedOption<bool>
|
||||
/// <inheritdoc />
|
||||
protected override void OnValueChanged(bool newValue)
|
||||
{
|
||||
HudManager.Instance.Notifier.AddSettingsChangeMessage(StringName, newValue ? "On" : "Off", false);
|
||||
ModdedOptionsManager.AddSettingsChangeMessage(
|
||||
HudManager.Instance.Notifier,
|
||||
StringName,
|
||||
newValue ? "On" : "Off",
|
||||
Configuration.PopUpTextColor,
|
||||
Configuration.PopUpIconTmp,
|
||||
false);
|
||||
if (!OptionBehaviour)
|
||||
{
|
||||
return;
|
||||
|
||||
@@ -7,7 +7,6 @@ using MiraAPI.LocalSettings;
|
||||
using MiraAPI.Patches;
|
||||
using MiraAPI.Utilities;
|
||||
using MiraAPI.Utilities.Assets;
|
||||
using Reactor.Utilities;
|
||||
using Rewired;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
|
||||
@@ -4,7 +4,6 @@ using System.Collections.ObjectModel;
|
||||
using System.Reflection;
|
||||
using MiraAPI.Events.Mira;
|
||||
using MiraAPI.PluginLoading;
|
||||
using UnityEngine;
|
||||
|
||||
namespace MiraAPI.Hud;
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
using System.Linq;
|
||||
using HarmonyLib;
|
||||
using Reactor.Utilities.Extensions;
|
||||
using UnityEngine;
|
||||
|
||||
namespace MiraAPI.Hud;
|
||||
|
||||
@@ -3,7 +3,6 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Il2CppInterop.Runtime.Attributes;
|
||||
using MiraAPI.Utilities;
|
||||
using Reactor.Utilities;
|
||||
using Rewired;
|
||||
|
||||
namespace MiraAPI.Keybinds;
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using System.Globalization;
|
||||
using Rewired;
|
||||
|
||||
namespace MiraAPI.Keybinds;
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using BepInEx.Configuration;
|
||||
|
||||
namespace MiraAPI.LocalSettings.Attributes;
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
using System;
|
||||
using MiraAPI.Utilities;
|
||||
using Reactor.Localization.Utilities;
|
||||
using Reactor.Utilities.Extensions;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using BepInEx.Unity.IL2CPP;
|
||||
using MiraAPI.GameOptions;
|
||||
using Reactor.Utilities;
|
||||
|
||||
namespace MiraAPI.LocalSettings;
|
||||
|
||||
@@ -14,6 +12,7 @@ public static class LocalSettingsManager
|
||||
{
|
||||
internal static readonly Dictionary<Type, LocalSettingsTab> TypeToTab = [];
|
||||
internal static readonly List<LocalSettingsTab> Tabs = [];
|
||||
internal static readonly List<LocalSettingsTab> AvailableTabs = [];
|
||||
|
||||
internal static bool RegisterTab(Type type, BasePlugin pluginInfo)
|
||||
{
|
||||
@@ -29,6 +28,10 @@ public static class LocalSettingsManager
|
||||
}
|
||||
|
||||
Tabs.Add(tab);
|
||||
if (tab.ShouldCreateButton)
|
||||
{
|
||||
AvailableTabs.Add(tab);
|
||||
}
|
||||
TypeToTab.Add(type, tab);
|
||||
|
||||
typeof(LocalSettingsTabSingleton<>).MakeGenericType(type)
|
||||
|
||||
@@ -8,7 +8,6 @@ using MiraAPI.LocalSettings;
|
||||
using MiraAPI.Modifiers.ModifierDisplay;
|
||||
using MiraAPI.Modifiers.Types;
|
||||
using MiraAPI.Patches.Roles;
|
||||
using Reactor.Utilities;
|
||||
using Reactor.Utilities.Attributes;
|
||||
using UnityEngine;
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@ using System.Linq;
|
||||
using HarmonyLib;
|
||||
using Il2CppInterop.Runtime.Attributes;
|
||||
using MiraAPI.LocalSettings;
|
||||
using MiraAPI.Utilities;
|
||||
using MiraAPI.Utilities.Assets;
|
||||
using Reactor.Utilities.Attributes;
|
||||
using Reactor.Utilities.Extensions;
|
||||
@@ -138,7 +137,7 @@ public class ModifierDisplayComponent(nint cppPtr) : MonoBehaviour(cppPtr)
|
||||
internal void DestroyComponent(ModifierUiComponent component)
|
||||
{
|
||||
_modifiers.Remove(component.Modifier!);
|
||||
component.gameObject.DeepDestroy();
|
||||
component.gameObject.Destroy();
|
||||
RefreshModifiers();
|
||||
}
|
||||
|
||||
@@ -208,7 +207,7 @@ public class ModifierDisplayComponent(nint cppPtr) : MonoBehaviour(cppPtr)
|
||||
continue;
|
||||
}
|
||||
|
||||
mod.Value.gameObject.DeepDestroy();
|
||||
mod.Value.gameObject.Destroy();
|
||||
_modifiers.Remove(mod.Key);
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@ using MiraAPI.Networking;
|
||||
using MiraAPI.Networking.Modifiers;
|
||||
using Reactor.Networking.Attributes;
|
||||
using Reactor.Networking.Rpc;
|
||||
using Reactor.Utilities;
|
||||
|
||||
namespace MiraAPI.Modifiers;
|
||||
|
||||
|
||||
@@ -6,7 +6,6 @@ using MiraAPI.Modifiers.Types;
|
||||
using MiraAPI.PluginLoading;
|
||||
using MiraAPI.Roles;
|
||||
using MiraAPI.Utilities;
|
||||
using Reactor.Utilities;
|
||||
using Reactor.Utilities.Extensions;
|
||||
using Random = System.Random;
|
||||
|
||||
@@ -153,7 +152,7 @@ public static class ModifierManager
|
||||
}
|
||||
|
||||
var candidates = availablePlayers
|
||||
.Where(x => IsGameModifierValid(x, modifier, modifier.TypeId))
|
||||
.Where(x => IsGameModifierPostCheck(x, modifier, modifier.TypeId))
|
||||
.ToList();
|
||||
|
||||
if (candidates.Count == 0)
|
||||
@@ -179,7 +178,12 @@ public static class ModifierManager
|
||||
private static bool IsGameModifierValid(PlayerControl player, GameModifier modifier, uint modifierId)
|
||||
{
|
||||
return (player.Data.Role is not ICustomRole role || role.IsModifierApplicable(modifier)) &&
|
||||
modifier.IsModifierValidOn(player.Data.Role) && !player.HasModifier(modifierId) &&
|
||||
!player.HasModifier(modifierId) && modifier.IsModifierValidOn(player.Data.Role) &&
|
||||
modifier.CanSpawnOnCurrentMode();
|
||||
}
|
||||
private static bool IsGameModifierPostCheck(PlayerControl player, GameModifier modifier, uint modifierId)
|
||||
{
|
||||
return (player.Data.Role is not ICustomRole role || role.IsModifierApplicable(modifier)) &&
|
||||
!player.HasModifier(modifierId) && modifier.IsModifierValidOnPostCheck(player.Data.Role);
|
||||
}
|
||||
}
|
||||
@@ -33,6 +33,13 @@ public abstract class GameModifier : BaseModifier
|
||||
/// <returns><see langword="true"/> if the modifier is valid on the role, otherwise <see langword="false"/>.</returns>
|
||||
public virtual bool IsModifierValidOn(RoleBehaviour role) => true;
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the modifier is valid on a role, which runs after players are determined but before the modifiers are given.
|
||||
/// </summary>
|
||||
/// <param name="role">The role to be checked.</param>
|
||||
/// <returns><see langword="true"/> if the modifier is valid on the role, otherwise <see langword="false"/>.</returns>
|
||||
public virtual bool IsModifierValidOnPostCheck(RoleBehaviour role) => IsModifierValidOn(role);
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the player won the game with this modifier. The modifier with the highest priority will override other modifiers.
|
||||
/// </summary>
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using Reactor.Utilities;
|
||||
using UnityEngine;
|
||||
|
||||
namespace MiraAPI.Modifiers.Types;
|
||||
|
||||
@@ -4,7 +4,6 @@ using InnerNet;
|
||||
using MiraAPI.GameEnd;
|
||||
using Reactor.Networking.Attributes;
|
||||
using Reactor.Networking.Rpc;
|
||||
using Reactor.Utilities;
|
||||
|
||||
namespace MiraAPI.Networking;
|
||||
|
||||
|
||||
@@ -10,9 +10,6 @@ using MiraAPI.Events.Vanilla.Gameplay;
|
||||
using MiraAPI.Utilities;
|
||||
using Reactor.Networking.Attributes;
|
||||
using Reactor.Networking.Rpc;
|
||||
using Reactor.Utilities;
|
||||
using Reactor.Utilities.Extensions;
|
||||
using Rewired;
|
||||
using UnityEngine;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@ using InnerNet;
|
||||
using MiraAPI.Events;
|
||||
using MiraAPI.Events.Vanilla.Meeting;
|
||||
using MiraAPI.Utilities;
|
||||
using Reactor.Utilities;
|
||||
|
||||
namespace MiraAPI.Patches.Events;
|
||||
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
using System.Linq;
|
||||
using AmongUs.GameOptions;
|
||||
using AmongUs.GameOptions;
|
||||
using HarmonyLib;
|
||||
using MiraAPI.Events;
|
||||
using MiraAPI.Events.Vanilla.Gameplay;
|
||||
using MiraAPI.Events.Vanilla.Usables;
|
||||
|
||||
namespace MiraAPI.Patches.Events;
|
||||
|
||||
|
||||
@@ -278,7 +278,6 @@ public static class TaskAdderPatches
|
||||
|
||||
__instance.ActiveItems.ToArray().Do(x => x.gameObject.DeepDestroy(false));
|
||||
__instance.ActiveItems.Clear();
|
||||
Utilities.Extensions.ClearGarbageCollector();
|
||||
|
||||
float num = 0f;
|
||||
float num2 = 0f;
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
using HarmonyLib;
|
||||
using MiraAPI.Hud;
|
||||
using Reactor.Utilities;
|
||||
|
||||
namespace MiraAPI.Patches.Hud;
|
||||
|
||||
|
||||
@@ -148,9 +148,8 @@ public static class HudManagerPatches
|
||||
|
||||
foreach (var t in BottomLeft.GetComponentsInChildren<ActionButton>(true))
|
||||
{
|
||||
t.gameObject.DeepDestroy(false);
|
||||
t.gameObject.Destroy();
|
||||
}
|
||||
Utilities.Extensions.ClearGarbageCollector();
|
||||
|
||||
var gridArrange = BottomLeft.GetComponent<GridArrange>();
|
||||
var aspectPosition = BottomLeft.GetComponent<AspectPosition>();
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Reflection;
|
||||
using HarmonyLib;
|
||||
using Il2CppInterop.Runtime.InteropTypes;
|
||||
using MiraAPI.Events;
|
||||
using MiraAPI.Events.Vanilla.Gameplay;
|
||||
using MiraAPI.Roles;
|
||||
using MiraAPI.Utilities;
|
||||
using Reactor.Utilities;
|
||||
|
||||
namespace MiraAPI.Patches;
|
||||
|
||||
|
||||
@@ -1,13 +1,8 @@
|
||||
using System.Linq;
|
||||
using HarmonyLib;
|
||||
using MiraAPI.Keybinds;
|
||||
using MiraAPI.LocalSettings;
|
||||
using Reactor.Utilities;
|
||||
using Reactor.Utilities.Extensions;
|
||||
using Rewired.UI.ControlMapper;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace MiraAPI.Patches.Keybinds;
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
using HarmonyLib;
|
||||
using MiraAPI.Keybinds;
|
||||
using MonoMod.Utils;
|
||||
using Rewired;
|
||||
|
||||
namespace MiraAPI.Patches.Keybinds;
|
||||
|
||||
@@ -3,7 +3,6 @@ using System.Linq;
|
||||
using HarmonyLib;
|
||||
using MiraAPI.LocalSettings;
|
||||
using MiraAPI.Utilities.Assets;
|
||||
using Reactor.Utilities;
|
||||
using Reactor.Utilities.Extensions;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
@@ -70,7 +69,7 @@ public static class OptionsMenuPatches
|
||||
int i = 0;
|
||||
int tabIdx = 0;
|
||||
int page = 1;
|
||||
foreach (var settings in LocalSettingsManager.Tabs)
|
||||
foreach (var settings in LocalSettingsManager.AvailableTabs)
|
||||
{
|
||||
var tab = settings.CreateTab(__instance);
|
||||
if (settings.ShouldCreateButton)
|
||||
@@ -165,12 +164,12 @@ public static class OptionsMenuPatches
|
||||
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
|
||||
LocalSettingsManager.AvailableTabs.ForEach(CustomClose); // Close all mod tabs
|
||||
|
||||
// Tabs with index 10 and above are the mod settings tabs
|
||||
if (index >= 10)
|
||||
{
|
||||
CustomOpen(LocalSettingsManager.Tabs[index - 10]);
|
||||
CustomOpen(LocalSettingsManager.AvailableTabs[index - 10]);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -184,7 +183,7 @@ public static class OptionsMenuPatches
|
||||
[HarmonyPatch(nameof(OptionsMenuBehaviour.Open))]
|
||||
public static void OpenPostfix(OptionsMenuBehaviour __instance)
|
||||
{
|
||||
LocalSettingsManager.Tabs.ForEach(CustomClose);
|
||||
LocalSettingsManager.AvailableTabs.ForEach(CustomClose);
|
||||
currentPage = 1;
|
||||
UpdatePages();
|
||||
}
|
||||
|
||||
@@ -100,10 +100,9 @@ public static class HatsTabPatches
|
||||
if (loadRoutine != null) Coroutines.Stop(loadRoutine);
|
||||
|
||||
hatIndex = 0;
|
||||
foreach (var instanceColorChip in __instance.ColorChips) instanceColorChip.gameObject.DeepDestroy(false);
|
||||
foreach (var instanceColorChip in __instance.ColorChips) instanceColorChip.gameObject.Destroy();
|
||||
__instance.ColorChips.Clear();
|
||||
__instance.scroller.Inner.GetComponentsInChildren<TextMeshPro>().Do(x => x.gameObject.DeepDestroy(false));
|
||||
Utilities.Extensions.ClearGarbageCollector();
|
||||
|
||||
var groupNameText = __instance.GetComponentInChildren<TextMeshPro>(false);
|
||||
var group = sortedHats.Where(x => x.Key == storeNames[page]);
|
||||
|
||||
@@ -81,10 +81,9 @@ public static class NameplatesTabPatches
|
||||
|
||||
private static void GenerateHats(NameplatesTab __instance, int page)
|
||||
{
|
||||
foreach (var instanceColorChip in __instance.ColorChips) instanceColorChip.gameObject.DeepDestroy(false);
|
||||
foreach (var instanceColorChip in __instance.ColorChips) instanceColorChip.gameObject.Destroy();
|
||||
__instance.ColorChips.Clear();
|
||||
__instance.scroller.Inner.GetComponentsInChildren<TextMeshPro>().Do(x => x.gameObject.DeepDestroy(false));
|
||||
Utilities.Extensions.ClearGarbageCollector();
|
||||
|
||||
var groupNameText = __instance.GetComponentInChildren<TextMeshPro>(false);
|
||||
|
||||
|
||||
@@ -83,10 +83,9 @@ public static class SkinsTabPatches
|
||||
|
||||
private static void GenerateHats(SkinsTab __instance, int page)
|
||||
{
|
||||
foreach (var instanceColorChip in __instance.ColorChips) instanceColorChip.gameObject.DeepDestroy(false);
|
||||
foreach (var instanceColorChip in __instance.ColorChips) instanceColorChip.gameObject.Destroy();
|
||||
__instance.ColorChips.Clear();
|
||||
__instance.scroller.Inner.GetComponentsInChildren<TextMeshPro>().Do(x => x.gameObject.DeepDestroy(false));
|
||||
Utilities.Extensions.ClearGarbageCollector();
|
||||
|
||||
var groupNameText = __instance.GetComponentInChildren<TextMeshPro>(false);
|
||||
|
||||
|
||||
@@ -80,10 +80,9 @@ public static class VisorsTabPatches
|
||||
|
||||
private static void GenerateHats(VisorsTab __instance, int page)
|
||||
{
|
||||
foreach (var instanceColorChip in __instance.ColorChips) instanceColorChip.gameObject.DeepDestroy(false);
|
||||
foreach (var instanceColorChip in __instance.ColorChips) instanceColorChip.gameObject.Destroy();
|
||||
__instance.ColorChips.Clear();
|
||||
__instance.scroller.Inner.GetComponentsInChildren<TextMeshPro>().Do(x => x.gameObject.DeepDestroy(false));
|
||||
Utilities.Extensions.ClearGarbageCollector();
|
||||
|
||||
var groupNameText = __instance.GetComponentInChildren<TextMeshPro>(false);
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Linq;
|
||||
using AmongUs.GameOptions;
|
||||
using BepInEx.Unity.IL2CPP.Utils.Collections;
|
||||
using HarmonyLib;
|
||||
using Il2CppInterop.Runtime.Attributes;
|
||||
using MiraAPI.GameOptions;
|
||||
using MiraAPI.Modifiers;
|
||||
using MiraAPI.Presets;
|
||||
@@ -21,6 +21,54 @@ namespace MiraAPI.Patches.Options;
|
||||
[HarmonyPatch(typeof(GameOptionsMenu))]
|
||||
internal static class GameOptionsMenuPatch
|
||||
{
|
||||
[HarmonyPrefix]
|
||||
[HarmonyPatch(nameof(GameOptionsMenu.Initialize))]
|
||||
// ReSharper disable once InconsistentNaming
|
||||
public static bool InitPatch(GameOptionsMenu __instance)
|
||||
{
|
||||
__instance.Children ??= new Il2CppSystem.Collections.Generic.List<OptionBehaviour>();
|
||||
__instance.Children.Clear();
|
||||
|
||||
if (MenuState.Instance.CurrentModIdx == 0)
|
||||
{
|
||||
__instance.MapPicker.gameObject.SetActive(true);
|
||||
__instance.cachedData = GameOptionsManager.Instance.CurrentGameOptions;
|
||||
var container = MenuState.Instance.CurrentContainer.transform;
|
||||
|
||||
if (container.childCount == 1)
|
||||
{
|
||||
__instance.MapPicker.Initialize(20);
|
||||
var mapNameSetting = GameManager.Instance.GameSettingsList.MapNameSetting;
|
||||
__instance.MapPicker.SetUpFromData(mapNameSetting, 20);
|
||||
__instance.Children.Add(__instance.MapPicker);
|
||||
__instance.CreateSettings();
|
||||
foreach (var optionBehaviour in __instance.Children)
|
||||
{
|
||||
if (AmongUsClient.Instance && !AmongUsClient.Instance.AmHost)
|
||||
{
|
||||
optionBehaviour.SetAsPlayer();
|
||||
}
|
||||
|
||||
optionBehaviour.OnValueChanged = new Action<OptionBehaviour>(__instance.ValueChanged);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var child in container.GetComponentsInChildren<OptionBehaviour>(true))
|
||||
{
|
||||
__instance.Children.Add(child);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
__instance.MapPicker.gameObject.SetActive(false);
|
||||
CustomCreateSettings(__instance);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
[HarmonyPostfix]
|
||||
[HarmonyPatch(nameof(GameOptionsMenu.OnEnable))]
|
||||
public static void OpenPatch(GameOptionsMenu __instance)
|
||||
@@ -40,43 +88,44 @@ internal static class GameOptionsMenuPatch
|
||||
// ReSharper disable once InconsistentNaming
|
||||
public static void UpdatePatch(GameOptionsMenu __instance)
|
||||
{
|
||||
if (GameSettingMenuPatches.SelectedModIdx == 0)
|
||||
if (MenuState.Instance.CurrentModIdx == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var num = 2.1f;
|
||||
if (__instance.name == "MODIFIERS TAB")
|
||||
{
|
||||
ModifiersUpdate(ref num);
|
||||
}
|
||||
else if (__instance.name == "CUSTOM TAB 1")
|
||||
{
|
||||
CustomMenuOneUpdate(ref num);
|
||||
}
|
||||
else if (__instance.name == "CUSTOM TAB 2")
|
||||
{
|
||||
CustomMenuTwoUpdate(ref num);
|
||||
}
|
||||
else
|
||||
{
|
||||
var filteredGroups =
|
||||
GameSettingMenuPatches.SelectedMod?.InternalOptionGroups
|
||||
.Where(x => x.OptionableType == null &&
|
||||
x.ParentMenu == MenuCategory.Roles) ?? [];
|
||||
|
||||
foreach (var group in filteredGroups)
|
||||
{
|
||||
UpdateGroup(group, ref num);
|
||||
}
|
||||
switch (MenuState.Instance.CurrentMenu)
|
||||
{
|
||||
case MenuCategory.Modifiers:
|
||||
ModifiersUpdate(ref num);
|
||||
break;
|
||||
case MenuCategory.CustomOne:
|
||||
CustomMenuOneUpdate(ref num);
|
||||
break;
|
||||
case MenuCategory.CustomTwo:
|
||||
CustomMenuTwoUpdate(ref num);
|
||||
break;
|
||||
default:
|
||||
var filteredGroups =
|
||||
MenuState.Instance.CurrentMod.InternalOptionGroups
|
||||
.Where(x => x.OptionableType == null &&
|
||||
x.ParentMenu == MenuCategory.Game) ?? [];
|
||||
|
||||
foreach (var group in filteredGroups)
|
||||
{
|
||||
UpdateGroup(group, ref num);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
__instance.scrollBar.SetYBoundsMax(-num - 1.65f);
|
||||
}
|
||||
|
||||
private static void UpdateGroup(AbstractOptionGroup group, ref float num)
|
||||
private static void UpdateGroup(AbstractOptionGroup? group, ref float num)
|
||||
{
|
||||
if (group.Options.Count == 0 || group.Header is null)
|
||||
if (group is null || !group.Ready || group.Options.Count == 0 || group.Header is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -102,7 +151,7 @@ internal static class GameOptionsMenuPatch
|
||||
{
|
||||
var newOpt = opt.OptionBehaviour;
|
||||
|
||||
if (newOpt is null)
|
||||
if (!newOpt || newOpt == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@@ -128,8 +177,8 @@ internal static class GameOptionsMenuPatch
|
||||
|
||||
private static void CustomMenuOneUpdate(ref float num)
|
||||
{
|
||||
var groups = GameSettingMenuPatches.SelectedMod?.InternalOptionGroups
|
||||
.Where(x => x.ParentMenu == MenuCategory.CustomOne) ?? [];
|
||||
var groups = MenuState.Instance.CurrentMod.InternalOptionGroups
|
||||
.Where(x => x.ParentMenu == MenuCategory.CustomOne);
|
||||
|
||||
foreach (var modGroup in groups)
|
||||
{
|
||||
@@ -137,20 +186,10 @@ internal static class GameOptionsMenuPatch
|
||||
}
|
||||
}
|
||||
|
||||
private static void CustomMenuOneCreate(GameOptionsMenu menu)
|
||||
{
|
||||
var groups = GameSettingMenuPatches.SelectedMod?.InternalOptionGroups
|
||||
.Where(x => x.ParentMenu == MenuCategory.CustomOne) ?? [];
|
||||
foreach (var group in groups)
|
||||
{
|
||||
CreateGroup(menu, group);
|
||||
}
|
||||
}
|
||||
|
||||
private static void CustomMenuTwoUpdate(ref float num)
|
||||
{
|
||||
var groups = GameSettingMenuPatches.SelectedMod?.InternalOptionGroups
|
||||
.Where(x => x.ParentMenu == MenuCategory.CustomTwo) ?? [];
|
||||
var groups = MenuState.Instance.CurrentMod.InternalOptionGroups
|
||||
.Where(x => x.ParentMenu == MenuCategory.CustomTwo);
|
||||
|
||||
foreach (var modGroup in groups)
|
||||
{
|
||||
@@ -158,20 +197,11 @@ internal static class GameOptionsMenuPatch
|
||||
}
|
||||
}
|
||||
|
||||
private static void CustomMenuTwoCreate(GameOptionsMenu menu)
|
||||
{
|
||||
var groups = GameSettingMenuPatches.SelectedMod?.InternalOptionGroups
|
||||
.Where(x => x.ParentMenu == MenuCategory.CustomTwo) ?? [];
|
||||
foreach (var group in groups)
|
||||
{
|
||||
CreateGroup(menu, group);
|
||||
}
|
||||
}
|
||||
|
||||
private static void ModifiersUpdate(ref float num)
|
||||
{
|
||||
var groups = GameSettingMenuPatches.SelectedMod?.InternalOptionGroups
|
||||
.Where(x => x.ParentMenu is MenuCategory.Modifiers || x.OptionableType?.IsAssignableTo(typeof(BaseModifier)) == true) ?? [];
|
||||
var groups = MenuState.Instance.CurrentMod.InternalOptionGroups
|
||||
.Where(x => x.ParentMenu is MenuCategory.Modifiers ||
|
||||
x.OptionableType?.IsAssignableTo(typeof(BaseModifier)) == true);
|
||||
|
||||
foreach (var modGroup in groups)
|
||||
{
|
||||
@@ -179,139 +209,114 @@ internal static class GameOptionsMenuPatch
|
||||
}
|
||||
}
|
||||
|
||||
private static void ModifiersCreate(GameOptionsMenu menu)
|
||||
private static Coroutine? _creationCoroutine;
|
||||
|
||||
public static void CustomCreateSettings(GameOptionsMenu menu)
|
||||
{
|
||||
var groups = GameSettingMenuPatches.SelectedMod?.InternalOptionGroups
|
||||
.Where(x => x.ParentMenu is MenuCategory.Modifiers || x.OptionableType?.IsAssignableTo(typeof(BaseModifier)) == true) ?? [];
|
||||
foreach (var group in groups)
|
||||
{
|
||||
CreateGroup(menu, group);
|
||||
}
|
||||
}
|
||||
menu.MapPicker.gameObject.SetActive(false);
|
||||
var mod = MenuState.Instance.CurrentMod;
|
||||
|
||||
[HarmonyPrefix]
|
||||
[HarmonyPatch(nameof(GameOptionsMenu.CreateSettings))]
|
||||
// ReSharper disable once InconsistentNaming
|
||||
public static bool SettingsPatch(GameOptionsMenu __instance)
|
||||
{
|
||||
if (GameSettingMenuPatches.SelectedModIdx == 0)
|
||||
var filteredGroups = MenuState.Instance.CurrentMenu switch
|
||||
{
|
||||
return true;
|
||||
MenuCategory.Game => mod.InternalOptionGroups.Where(x =>
|
||||
x.OptionableType == null && x.ParentMenu == MenuCategory.Game),
|
||||
MenuCategory.Modifiers => mod.InternalOptionGroups.Where(x =>
|
||||
x.ParentMenu is MenuCategory.Modifiers ||
|
||||
x.OptionableType?.IsAssignableTo(typeof(BaseModifier)) == true),
|
||||
MenuCategory.CustomOne => mod.InternalOptionGroups.Where(x => x.ParentMenu == MenuCategory.CustomOne),
|
||||
MenuCategory.CustomTwo => mod.InternalOptionGroups.Where(x => x.ParentMenu == MenuCategory.CustomTwo),
|
||||
_ => [],
|
||||
};
|
||||
|
||||
if (_creationCoroutine != null)
|
||||
{
|
||||
GameSettingMenu.Instance.StopCoroutine(_creationCoroutine);
|
||||
}
|
||||
|
||||
__instance.MapPicker.gameObject.SetActive(false);
|
||||
_creationCoroutine = GameSettingMenu.Instance.StartCoroutine(CreateGroups().WrapToIl2Cpp());
|
||||
|
||||
if (__instance.name == "MODIFIERS TAB")
|
||||
IEnumerator CreateGroups()
|
||||
{
|
||||
ModifiersCreate(__instance);
|
||||
return false;
|
||||
}
|
||||
else if (__instance.name == "CUSTOM TAB 1")
|
||||
{
|
||||
CustomMenuOneCreate(__instance);
|
||||
return false;
|
||||
}
|
||||
else if (__instance.name == "CUSTOM TAB 2")
|
||||
{
|
||||
CustomMenuTwoCreate(__instance);
|
||||
return false;
|
||||
}
|
||||
|
||||
var filteredGroups = GameSettingMenuPatches.SelectedMod?.InternalOptionGroups
|
||||
.Where(x => x.OptionableType == null && x.ParentMenu == MenuCategory.Roles) ?? [];
|
||||
|
||||
foreach (var group in filteredGroups)
|
||||
{
|
||||
CreateGroup(__instance, group);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
[HarmonyPrefix]
|
||||
[HarmonyPatch(nameof(GameOptionsMenu.Initialize))]
|
||||
// ReSharper disable once InconsistentNaming
|
||||
public static bool InitPatch(GameOptionsMenu __instance)
|
||||
{
|
||||
if (__instance.Children != null && __instance.Children.Count != 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
__instance.MapPicker.gameObject.SetActive(true);
|
||||
__instance.MapPicker.Initialize(20);
|
||||
var mapNameSetting = GameManager.Instance.GameSettingsList.MapNameSetting;
|
||||
__instance.MapPicker.SetUpFromData(mapNameSetting, 20);
|
||||
__instance.Children = new Il2CppSystem.Collections.Generic.List<OptionBehaviour>();
|
||||
__instance.Children.Add(__instance.MapPicker);
|
||||
__instance.CreateSettings();
|
||||
__instance.cachedData = GameOptionsManager.Instance.CurrentGameOptions;
|
||||
foreach (var optionBehaviour in __instance.Children)
|
||||
{
|
||||
if (AmongUsClient.Instance && !AmongUsClient.Instance.AmHost)
|
||||
foreach (var group in filteredGroups)
|
||||
{
|
||||
optionBehaviour.SetAsPlayer();
|
||||
yield return CoCreateGroup(menu, group);
|
||||
}
|
||||
|
||||
if (optionBehaviour.IsCustom())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
optionBehaviour.OnValueChanged = new Action<OptionBehaviour>(__instance.ValueChanged);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static void CreateGroup(GameOptionsMenu menu, AbstractOptionGroup group)
|
||||
private static IEnumerator CoCreateGroup(GameOptionsMenu menu, AbstractOptionGroup group)
|
||||
{
|
||||
var categoryHeaderMasked = Object.Instantiate(
|
||||
menu.categoryHeaderOrigin,
|
||||
Vector3.zero,
|
||||
Quaternion.identity,
|
||||
menu.settingsContainer);
|
||||
var container = MenuState.Instance.CurrentContainer.transform;
|
||||
|
||||
categoryHeaderMasked.SetHeader(CustomStringName.CreateAndRegister(group.GroupName), 20);
|
||||
categoryHeaderMasked.Background.color = group.GroupColor;
|
||||
categoryHeaderMasked.Divider.color = group.GroupColor;
|
||||
categoryHeaderMasked.Title.color = group.GroupColor.Equals(MiraApiPlugin.DefaultHeaderColor)
|
||||
? Color.white
|
||||
: group.GroupColor.FindAlternateColor();
|
||||
group.Ready = false;
|
||||
if (group.Header == null || !group.Header)
|
||||
{
|
||||
var categoryHeaderMasked = Object.Instantiate(
|
||||
menu.categoryHeaderOrigin,
|
||||
Vector3.zero,
|
||||
Quaternion.identity,
|
||||
container);
|
||||
|
||||
categoryHeaderMasked.Background.sprite = MiraAssets.CategoryHeader.LoadAsset();
|
||||
categoryHeaderMasked.Background.sprite.texture.filterMode = FilterMode.Bilinear;
|
||||
categoryHeaderMasked.Background.sprite.texture.wrapMode = TextureWrapMode.Clamp;
|
||||
categoryHeaderMasked.SetHeader(CustomStringName.CreateAndRegister(group.GroupName), 20);
|
||||
categoryHeaderMasked.Background.color = group.GroupColor;
|
||||
categoryHeaderMasked.Divider.color = group.GroupColor;
|
||||
categoryHeaderMasked.Title.color = group.GroupColor.Equals(MiraApiPlugin.DefaultHeaderColor)
|
||||
? Color.white
|
||||
: group.GroupColor.FindAlternateColor();
|
||||
|
||||
categoryHeaderMasked.Background.transform.localPosition = new Vector3(0.5f, -0.1833f, 0);
|
||||
categoryHeaderMasked.Background.size = new Vector2(
|
||||
categoryHeaderMasked.Background.size.x + 1.5f,
|
||||
categoryHeaderMasked.Background.size.y);
|
||||
categoryHeaderMasked.Background.sprite = MiraAssets.CategoryHeader.LoadAsset();
|
||||
categoryHeaderMasked.Background.sprite.texture.filterMode = FilterMode.Bilinear;
|
||||
categoryHeaderMasked.Background.sprite.texture.wrapMode = TextureWrapMode.Clamp;
|
||||
|
||||
categoryHeaderMasked.gameObject.SetActive(false);
|
||||
group.Header = categoryHeaderMasked;
|
||||
categoryHeaderMasked.Background.transform.localPosition = new Vector3(0.5f, -0.1833f, 0);
|
||||
categoryHeaderMasked.Background.size = new Vector2(
|
||||
categoryHeaderMasked.Background.size.x + 1.5f,
|
||||
categoryHeaderMasked.Background.size.y);
|
||||
|
||||
var newText = Object.Instantiate(categoryHeaderMasked.Title, categoryHeaderMasked.transform);
|
||||
newText.text = "<size=70%>(Click to close)</size>";
|
||||
newText.transform.localPosition = new Vector3(2.6249f, -0.165f, 0f);
|
||||
newText.gameObject.GetComponent<TextTranslatorTMP>().Destroy();
|
||||
categoryHeaderMasked.gameObject.SetActive(false);
|
||||
|
||||
var options = group.Options.Select(opt => opt.CreateOption(
|
||||
var newText = Object.Instantiate(categoryHeaderMasked.Title, categoryHeaderMasked.transform);
|
||||
newText.text = "<size=70%>(Click to close)</size>";
|
||||
newText.transform.localPosition = new Vector3(2.6249f, -0.165f, 0f);
|
||||
newText.gameObject.GetComponent<TextTranslatorTMP>().Destroy();
|
||||
|
||||
var boxCol = categoryHeaderMasked.gameObject.AddComponent<BoxCollider2D>();
|
||||
boxCol.size = new Vector2(7, 0.7f);
|
||||
boxCol.offset = new Vector2(1.5f, -0.3f);
|
||||
|
||||
var headerBtn = categoryHeaderMasked.gameObject.AddComponent<PassiveButton>();
|
||||
headerBtn.ClickSound = menu.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);
|
||||
|
||||
group.Header = categoryHeaderMasked;
|
||||
}
|
||||
|
||||
var options = group.Options.Where(opt => opt.OptionBehaviour == null || !opt.OptionBehaviour
|
||||
).Select(opt => opt.CreateOption(
|
||||
menu.checkboxOrigin,
|
||||
menu.numberOptionOrigin,
|
||||
menu.stringOptionOrigin,
|
||||
menu.playerOptionOrigin,
|
||||
menu.settingsContainer));
|
||||
container)
|
||||
);
|
||||
|
||||
OptionPreset? defaultPreset = null;
|
||||
if (GameSettingMenuPatches.SelectedMod != null && PresetManager.DefaultPresets.TryGetValue(
|
||||
GameSettingMenuPatches.SelectedMod,
|
||||
out var preset))
|
||||
if (PresetManager.DefaultPresets.TryGetValue(MenuState.Instance.CurrentMod, out var preset))
|
||||
{
|
||||
defaultPreset = preset;
|
||||
}
|
||||
|
||||
foreach (var newOpt in options)
|
||||
yield return options.CoLoopWithBudget(newOpt =>
|
||||
{
|
||||
newOpt.SetClickMask(menu.ButtonClickMask);
|
||||
|
||||
@@ -414,6 +419,7 @@ internal static class GameOptionsMenuPatch
|
||||
defaultPreset!.ResetOption(strOpt);
|
||||
}));
|
||||
}
|
||||
|
||||
if (!defaultPreset!.IsOptionInPreset(newOpt))
|
||||
{
|
||||
resetBtn.Destroy();
|
||||
@@ -421,24 +427,12 @@ internal static class GameOptionsMenuPatch
|
||||
|
||||
newOpt.Initialize();
|
||||
newOpt.gameObject.SetActive(false);
|
||||
}
|
||||
|
||||
var boxCol = categoryHeaderMasked.gameObject.AddComponent<BoxCollider2D>();
|
||||
boxCol.size = new Vector2(7, 0.7f);
|
||||
boxCol.offset = new Vector2(1.5f, -0.3f);
|
||||
|
||||
var headerBtn = categoryHeaderMasked.gameObject.AddComponent<PassiveButton>();
|
||||
headerBtn.ClickSound = menu.BackButton.GetComponent<PassiveButton>().ClickSound;
|
||||
headerBtn.OnMouseOver = new UnityEvent();
|
||||
headerBtn.OnMouseOut = new UnityEvent();
|
||||
headerBtn.OnClick.AddListener(
|
||||
(UnityAction)(() =>
|
||||
if (AmongUsClient.Instance && !AmongUsClient.Instance.AmHost)
|
||||
{
|
||||
group.AllOptionsHidden = !group.AllOptionsHidden;
|
||||
newText.text = group.AllOptionsHidden
|
||||
? "<size=70%>(Click to open)</size>"
|
||||
: "<size=70%>(Click to close)</size>";
|
||||
}));
|
||||
headerBtn.SetButtonEnableState(true);
|
||||
newOpt.SetAsPlayer();
|
||||
}
|
||||
}).WrapToIl2Cpp();
|
||||
group.Ready = true;
|
||||
}
|
||||
}
|
||||
@@ -3,12 +3,12 @@ using System.IO;
|
||||
using System.Linq;
|
||||
using BepInEx.Configuration;
|
||||
using HarmonyLib;
|
||||
using MiraAPI.GameOptions;
|
||||
using MiraAPI.PluginLoading;
|
||||
using MiraAPI.Presets;
|
||||
using MiraAPI.Roles;
|
||||
using MiraAPI.Utilities;
|
||||
using MiraAPI.Utilities.Assets;
|
||||
using Reactor.Utilities;
|
||||
using Reactor.Utilities.Extensions;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
@@ -24,8 +24,6 @@ internal static class GamePresetsTabPatches
|
||||
private static GameObject _refreshButton = null!;
|
||||
private static GameObject _folderButton = null!;
|
||||
private static GameObject _newDivider = null!;
|
||||
private static GameObject _presetHolder = null!;
|
||||
private static GridArrange _arrange = null!;
|
||||
|
||||
private static readonly object Lock = new();
|
||||
|
||||
@@ -42,10 +40,10 @@ internal static class GamePresetsTabPatches
|
||||
|
||||
CreatePresetMenu(__instance);
|
||||
|
||||
__instance.StandardPresetButton.gameObject.SetActive(GameSettingMenuPatches.SelectedModIdx == 0);
|
||||
__instance.SecondPresetButton.gameObject.SetActive(GameSettingMenuPatches.SelectedModIdx == 0);
|
||||
__instance.StandardPresetButton.gameObject.SetActive(MenuState.Instance.CurrentModIdx == 0);
|
||||
__instance.SecondPresetButton.gameObject.SetActive(MenuState.Instance.CurrentModIdx == 0);
|
||||
|
||||
if (GameSettingMenuPatches.SelectedModIdx != 0)
|
||||
if (MenuState.Instance.CurrentModIdx != 0)
|
||||
{
|
||||
__instance.PresetDescriptionText.text = "Select or create an options preset for this mod";
|
||||
}
|
||||
@@ -57,26 +55,41 @@ internal static class GamePresetsTabPatches
|
||||
// Show the save and refresh buttons
|
||||
if (_saveButton)
|
||||
{
|
||||
_saveButton.SetActive(GameSettingMenuPatches.SelectedModIdx != 0);
|
||||
_saveButton.SetActive(MenuState.Instance.CurrentModIdx != 0);
|
||||
}
|
||||
if (_refreshButton)
|
||||
{
|
||||
_refreshButton.SetActive(GameSettingMenuPatches.SelectedModIdx != 0);
|
||||
_refreshButton.SetActive(MenuState.Instance.CurrentModIdx != 0);
|
||||
}
|
||||
if (_folderButton)
|
||||
{
|
||||
_folderButton.SetActive(GameSettingMenuPatches.SelectedModIdx != 0);
|
||||
_folderButton.SetActive(MenuState.Instance.CurrentModIdx != 0);
|
||||
}
|
||||
if (_newDivider)
|
||||
{
|
||||
_newDivider.SetActive(GameSettingMenuPatches.SelectedModIdx != 0);
|
||||
_newDivider.SetActive(MenuState.Instance.CurrentModIdx != 0);
|
||||
}
|
||||
|
||||
if (MenuState.Instance.CurrentModIdx == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var prefab = GameSettingMenu.Instance.GameSettingsButton;
|
||||
|
||||
foreach (var preset in MiraPluginManager.Instance.RegisteredPlugins.SelectMany(x => x.InternalPresets))
|
||||
var presetHolder = MenuState.Instance.CurrentContainer;
|
||||
var arrange = presetHolder.GetComponent<GridArrange>();
|
||||
presetHolder.SetActive(true);
|
||||
|
||||
foreach (var preset in MenuState.Instance.CurrentMod.InternalPresets)
|
||||
{
|
||||
var button = Object.Instantiate(prefab, _presetHolder.transform);
|
||||
if (preset.PresetButton != null && preset.PresetButton)
|
||||
{
|
||||
preset.PresetButton.SetActive(true);
|
||||
continue;
|
||||
}
|
||||
|
||||
var button = Object.Instantiate(prefab, presetHolder.transform);
|
||||
button.buttonText.text = preset.Name;
|
||||
if (button.buttonText.TryGetComponent<TextTranslatorTMP>(out var tmp))
|
||||
{
|
||||
@@ -91,23 +104,12 @@ internal static class GamePresetsTabPatches
|
||||
{
|
||||
preset.LoadPreset();
|
||||
}));
|
||||
button.gameObject.SetActive(false);
|
||||
button.gameObject.SetActive(true);
|
||||
preset.PresetButton = button.gameObject;
|
||||
}
|
||||
|
||||
foreach (var mod in MiraPluginManager.Instance.RegisteredPlugins)
|
||||
{
|
||||
foreach (var button in mod.InternalPresets.Select(x => x.PresetButton))
|
||||
{
|
||||
if (button != null)
|
||||
{
|
||||
button.SetActive(mod == GameSettingMenuPatches.SelectedMod);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_arrange.Start();
|
||||
_arrange.ArrangeChilds();
|
||||
arrange.Start();
|
||||
arrange.ArrangeChilds();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -117,8 +119,6 @@ internal static class GamePresetsTabPatches
|
||||
// ReSharper disable once InconsistentNaming
|
||||
public static void Postfix()
|
||||
{
|
||||
Error("OnDisable called");
|
||||
|
||||
if (_saveButton)
|
||||
{
|
||||
_saveButton.SetActive(false);
|
||||
@@ -198,7 +198,7 @@ internal static class GamePresetsTabPatches
|
||||
saveButton.OnClick.AddListener(
|
||||
(UnityAction)(() =>
|
||||
{
|
||||
if (GameSettingMenuPatches.SelectedModIdx == 0)
|
||||
if (MenuState.Instance.CurrentModIdx == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -206,7 +206,7 @@ internal static class GamePresetsTabPatches
|
||||
SavePresetPopup.CreatePopup(
|
||||
name =>
|
||||
{
|
||||
if (GameSettingMenuPatches.SelectedMod == null)
|
||||
if (MenuState.Instance.CurrentModIdx == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -219,19 +219,19 @@ internal static class GamePresetsTabPatches
|
||||
var presetFile = new ConfigFile(
|
||||
Path.Combine(
|
||||
PresetManager.PresetDirectory,
|
||||
GameSettingMenuPatches.SelectedMod.PluginId,
|
||||
MenuState.Instance.CurrentMod.PluginId,
|
||||
$"{name}.cfg"),
|
||||
false)
|
||||
{
|
||||
SaveOnConfigSet = false,
|
||||
};
|
||||
|
||||
foreach (var option in GameSettingMenuPatches.SelectedMod.InternalOptions.Where(x => x.IncludeInPreset))
|
||||
foreach (var option in MenuState.Instance.CurrentMod.InternalOptions.Where(x => x.IncludeInPreset))
|
||||
{
|
||||
option.SaveToPreset(presetFile);
|
||||
}
|
||||
|
||||
foreach (var role in GameSettingMenuPatches.SelectedMod.InternalRoles.Values.OfType<ICustomRole>().Where(x=>!x.Configuration.HideSettings))
|
||||
foreach (var role in MenuState.Instance.CurrentMod.InternalRoles.Values.OfType<ICustomRole>().Where(x=>!x.Configuration.HideSettings))
|
||||
{
|
||||
role.SaveToPreset(presetFile);
|
||||
}
|
||||
@@ -262,7 +262,7 @@ internal static class GamePresetsTabPatches
|
||||
iconSpriteRend.sprite = MiraAssets.RefreshIcon.LoadAsset();
|
||||
|
||||
Helpers.DivideSize(refreshButton.gameObject, 2f);
|
||||
refreshButton.buttonText.gameObject.DeepDestroy();
|
||||
refreshButton.buttonText.gameObject.Destroy();
|
||||
|
||||
refreshButton.OnClick = new Button.ButtonClickedEvent();
|
||||
refreshButton.OnClick.AddListener((UnityAction)Refresh);
|
||||
@@ -286,7 +286,7 @@ internal static class GamePresetsTabPatches
|
||||
{
|
||||
var directory = Path.Combine(
|
||||
PresetManager.PresetDirectory,
|
||||
GameSettingMenuPatches.SelectedMod?.PluginId ?? string.Empty);
|
||||
MenuState.Instance.CurrentMod.PluginId);
|
||||
Directory.CreateDirectory(directory);
|
||||
Process.Start(
|
||||
new ProcessStartInfo
|
||||
@@ -302,31 +302,20 @@ internal static class GamePresetsTabPatches
|
||||
_refreshButton.SetActive(false);
|
||||
_folderButton.SetActive(false);
|
||||
_newDivider.SetActive(false);
|
||||
|
||||
if (!_presetHolder)
|
||||
{
|
||||
_presetHolder = new GameObject("PresetHolder");
|
||||
_presetHolder.transform.SetParent(presetTab.transform, false);
|
||||
_presetHolder.transform.localScale = new Vector3(0.9f, 0.9f, 1);
|
||||
_presetHolder.transform.localPosition = new Vector3(-1.9f, 1.7f, 0);
|
||||
_arrange = _presetHolder.AddComponent<GridArrange>();
|
||||
_arrange.Alignment = GridArrange.StartAlign.Right;
|
||||
_arrange.CellSize = new Vector2(2.15f, -.55f);
|
||||
_arrange.MaxColumns = 2;
|
||||
}
|
||||
}
|
||||
|
||||
private static void Refresh()
|
||||
{
|
||||
Error("Refreshing presets");
|
||||
if (GameSettingMenuPatches.SelectedMod == null)
|
||||
Info("Refreshing presets");
|
||||
if (MenuState.Instance.CurrentModIdx == 0)
|
||||
{
|
||||
Error("Selected mod is null, cannot refresh presets");
|
||||
Error("Current page is vanilla, cannot refresh presets");
|
||||
return;
|
||||
}
|
||||
|
||||
lock (Lock)
|
||||
{
|
||||
PresetManager.LoadPresets(GameSettingMenuPatches.SelectedMod);
|
||||
PresetManager.LoadPresets(MenuState.Instance.CurrentMod);
|
||||
}
|
||||
GameSettingMenu.Instance.ChangeTab(0, false); // refresh the tab
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using HarmonyLib;
|
||||
using MiraAPI.GameOptions;
|
||||
using MiraAPI.Modifiers;
|
||||
@@ -19,661 +18,38 @@ namespace MiraAPI.Patches.Options;
|
||||
[HarmonyPatch(typeof(GameSettingMenu))]
|
||||
internal static class GameSettingMenuPatches
|
||||
{
|
||||
public static int SelectedModIdx { get; private set; }
|
||||
|
||||
public static MiraPluginInfo? SelectedMod { get; private set; }
|
||||
|
||||
private static TextMeshPro? _text;
|
||||
|
||||
private static Vector3 _roleBtnOgPos;
|
||||
private static Vector3 _smallRoleBtnOgPos;
|
||||
private static Vector3 _modifierBtnOgPos;
|
||||
private static Vector3 _customOneBtnOgPos;
|
||||
private static Vector3 _customTwoBtnOgPos;
|
||||
|
||||
private static GameOptionsMenu? _modifiersTab;
|
||||
private static PassiveButton? _modifiersButton;
|
||||
private static PassiveButton? _smallRolesButton;
|
||||
private static GameOptionsMenu? _customOneTab;
|
||||
private static PassiveButton? _customOneButton;
|
||||
private static GameOptionsMenu? _customTwoTab;
|
||||
private static PassiveButton? _customTwoButton;
|
||||
private static GameObject? _nextModButton;
|
||||
private static GameObject? _previousModButton;
|
||||
|
||||
private static Dictionary<int, Vector3> OptionsPositions { get; } = [];
|
||||
private static Dictionary<int, Vector3> ModifiersPositions { get; } = [];
|
||||
private static Dictionary<int, Vector3> CustomOnePositions { get; } = [];
|
||||
private static Dictionary<int, Vector3> CustomTwoPositions { get; } = [];
|
||||
|
||||
private static void SaveScrollPositions(GameSettingMenu gameSettingMenu)
|
||||
{
|
||||
if (_modifiersTab)
|
||||
{
|
||||
ModifiersPositions[SelectedModIdx] = _modifiersTab!.scrollBar.Inner.localPosition;
|
||||
}
|
||||
else if (_customOneTab)
|
||||
{
|
||||
CustomOnePositions[SelectedModIdx] = _customOneTab!.scrollBar.Inner.localPosition;
|
||||
}
|
||||
else if (_customTwoTab)
|
||||
{
|
||||
CustomTwoPositions[SelectedModIdx] = _customTwoTab!.scrollBar.Inner.localPosition;
|
||||
}
|
||||
|
||||
RoleSettingMenuPatches.RolePositions[SelectedModIdx] = gameSettingMenu.RoleSettingsTab.scrollBar.Inner.localPosition;
|
||||
OptionsPositions[SelectedModIdx] = gameSettingMenu.GameSettingsTab.scrollBar.Inner.localPosition;
|
||||
}
|
||||
|
||||
[HarmonyPrefix]
|
||||
[HarmonyPatch(nameof(GameSettingMenu.ChangeTab))]
|
||||
|
||||
public static void ChangeTabPrefix(GameSettingMenu __instance)
|
||||
{
|
||||
SaveScrollPositions(__instance);
|
||||
}
|
||||
|
||||
[HarmonyPostfix]
|
||||
[HarmonyPatch(nameof(GameSettingMenu.ChangeTab))]
|
||||
public static void ChangeTabPostfix(GameSettingMenu __instance, int tabNum, bool previewOnly)
|
||||
{
|
||||
if ((previewOnly && Controller.currentTouchType == Controller.TouchType.Joystick) || !previewOnly)
|
||||
{
|
||||
if (_modifiersTab)
|
||||
{
|
||||
_modifiersTab!.gameObject.SetActive(tabNum == 3);
|
||||
}
|
||||
|
||||
if (_customOneTab)
|
||||
{
|
||||
_customOneTab!.gameObject.SetActive(tabNum == 4);
|
||||
}
|
||||
|
||||
if (_customTwoTab)
|
||||
{
|
||||
_customTwoTab!.gameObject.SetActive(tabNum == 5);
|
||||
}
|
||||
|
||||
_modifiersButton?.SelectButton(tabNum == 3);
|
||||
_smallRolesButton?.SelectButton(tabNum == 2);
|
||||
_customOneButton?.SelectButton(tabNum == 4);
|
||||
_customTwoButton?.SelectButton(tabNum == 5);
|
||||
if (tabNum >= 3 && tabNum <= 5)
|
||||
{
|
||||
if (__instance.RoleSettingsButton.gameObject.active)
|
||||
{
|
||||
__instance.RoleSettingsButton.SelectButton(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (tabNum)
|
||||
{
|
||||
case 3:
|
||||
_modifiersButton?.SelectButton(true);
|
||||
__instance.MenuDescriptionText.text = SelectedMod != null ? SelectedMod.MiraPlugin.ModifierMenuDescription : "Configure modifiers and their settings here!";
|
||||
break;
|
||||
case 4:
|
||||
_customOneButton?.SelectButton(true);
|
||||
__instance.MenuDescriptionText.text = SelectedMod != null ? SelectedMod.MiraPlugin.CustomOptionMenuOneDescription : "Apply game settings for this mod!";
|
||||
break;
|
||||
case 5:
|
||||
_customTwoButton?.SelectButton(true);
|
||||
__instance.MenuDescriptionText.text = SelectedMod != null ? SelectedMod.MiraPlugin.CustomOptionMenuTwoDescription : "Apply game settings for this mod!";
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (previewOnly)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_modifiersButton?.SelectButton(tabNum == 3);
|
||||
_smallRolesButton?.SelectButton(tabNum == 2);
|
||||
_customOneButton?.SelectButton(tabNum == 4);
|
||||
_customTwoButton?.SelectButton(tabNum == 5);
|
||||
|
||||
if (tabNum >= 3 && tabNum <= 5)
|
||||
{
|
||||
if (__instance.RoleSettingsButton.gameObject.active)
|
||||
{
|
||||
__instance.RoleSettingsButton.SelectButton(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (tabNum)
|
||||
{
|
||||
case 3:
|
||||
_modifiersButton?.SelectButton(true);
|
||||
break;
|
||||
case 4:
|
||||
_customOneButton?.SelectButton(true);
|
||||
break;
|
||||
case 5:
|
||||
_customTwoButton?.SelectButton(true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Prefix for the <see cref="GameSettingMenu.Start"/> method. Sets up the custom options.
|
||||
/// Prefix for the <see cref="GameSettingMenu.OnEnable"/> method. Sets up the custom options.
|
||||
/// </summary>
|
||||
/// <param name="__instance">The <see cref="GameSettingMenu"/> instance.</param>
|
||||
[HarmonyPrefix]
|
||||
[HarmonyPatch(nameof(GameSettingMenu.Start))]
|
||||
public static void StartPrefix(GameSettingMenu __instance)
|
||||
[HarmonyPatch(nameof(GameSettingMenu.OnEnable))]
|
||||
public static void OnEnablePrefix(GameSettingMenu __instance)
|
||||
{
|
||||
_roleBtnOgPos = __instance.RoleSettingsButton.transform.localPosition;
|
||||
__instance.transform.FindChild("GameSettingsLabel").gameObject.SetActive(false);
|
||||
|
||||
var helpThing = __instance.transform.FindChild("What Is This?");
|
||||
var tmpText = Object.Instantiate(helpThing.transform.FindChild("InfoText"), helpThing.parent).gameObject;
|
||||
|
||||
tmpText.GetComponent<TextTranslatorTMP>().Destroy();
|
||||
tmpText.name = "SelectedMod";
|
||||
tmpText.transform.localPosition = new Vector3(-3.3382f, 1.5399f, -2);
|
||||
|
||||
_text = tmpText.GetComponent<TextMeshPro>();
|
||||
_text.fontSizeMax = 3.2f;
|
||||
_text.overflowMode = TextOverflowModes.Overflow;
|
||||
|
||||
_text.alignment = TextAlignmentOptions.Center;
|
||||
|
||||
_nextModButton = Object.Instantiate(__instance.BackButton, __instance.BackButton.transform.parent).gameObject;
|
||||
_nextModButton.transform.localPosition = new Vector3(-2.2663f, 1.5272f, -25f);
|
||||
_nextModButton.name = "RightArrowButton";
|
||||
_nextModButton.transform.FindChild("Inactive").gameObject.GetComponent<SpriteRenderer>().sprite =
|
||||
MiraAssets.NextButton.LoadAsset();
|
||||
_nextModButton.transform.FindChild("Active").gameObject.GetComponent<SpriteRenderer>().sprite =
|
||||
MiraAssets.NextButtonActive.LoadAsset();
|
||||
_nextModButton.gameObject.GetComponent<CloseButtonConsoleBehaviour>().DestroyImmediate();
|
||||
|
||||
var passiveButton = _nextModButton.gameObject.GetComponent<PassiveButton>();
|
||||
passiveButton.OnClick = new ButtonClickedEvent();
|
||||
passiveButton.OnClick.AddListener(
|
||||
(UnityAction)(() =>
|
||||
{
|
||||
SaveScrollPositions(__instance);
|
||||
SelectedModIdx += 1;
|
||||
if (SelectedModIdx > MiraPluginManager.Instance.RegisteredPlugins.Length)
|
||||
{
|
||||
SelectedModIdx = 0;
|
||||
}
|
||||
|
||||
UpdateText(__instance, __instance.GameSettingsTab, __instance.RoleSettingsTab);
|
||||
}));
|
||||
|
||||
_previousModButton = Object.Instantiate(_nextModButton, __instance.BackButton.transform.parent).gameObject;
|
||||
_previousModButton.transform.localPosition = new Vector3(-4.4209f, 1.5272f, -25f);
|
||||
_previousModButton.name = "LeftArrowButton";
|
||||
_previousModButton.gameObject.GetComponent<CloseButtonConsoleBehaviour>().Destroy();
|
||||
_previousModButton.transform.FindChild("Active").gameObject.GetComponent<SpriteRenderer>().flipX =
|
||||
_previousModButton.transform.FindChild("Inactive").gameObject.GetComponent<SpriteRenderer>().flipX = true;
|
||||
_previousModButton.gameObject.GetComponent<PassiveButton>().OnClick.AddListener(
|
||||
(UnityAction)(() =>
|
||||
{
|
||||
SaveScrollPositions(__instance);
|
||||
SelectedModIdx -= 1;
|
||||
if (SelectedModIdx < 0)
|
||||
{
|
||||
SelectedModIdx = MiraPluginManager.Instance.RegisteredPlugins.Length;
|
||||
}
|
||||
|
||||
UpdateText(__instance, __instance.GameSettingsTab, __instance.RoleSettingsTab);
|
||||
}));
|
||||
|
||||
// clone game settings tab for modifiers
|
||||
_modifiersTab = Object.Instantiate(__instance.GameSettingsTab, __instance.GameSettingsTab.transform.parent);
|
||||
_modifiersTab.name = "MODIFIERS TAB";
|
||||
|
||||
// clone game settings tab for both custom tabs
|
||||
_customOneTab = Object.Instantiate(__instance.GameSettingsTab, __instance.GameSettingsTab.transform.parent);
|
||||
_customOneTab.name = "CUSTOM TAB 1";
|
||||
_customTwoTab = Object.Instantiate(__instance.GameSettingsTab, __instance.GameSettingsTab.transform.parent);
|
||||
_customTwoTab.name = "CUSTOM TAB 2";
|
||||
|
||||
// create button for the first custom category
|
||||
var customPos = new Vector3(
|
||||
__instance.RoleSettingsButton.transform.localPosition.x,
|
||||
__instance.RoleSettingsButton.transform.localPosition.y,
|
||||
__instance.RoleSettingsButton.transform.localPosition.z);
|
||||
_customOneButton = Object.Instantiate(__instance.RoleSettingsButton, __instance.RoleSettingsButton.transform.parent);
|
||||
_customOneButton.buttonText.gameObject.GetComponent<TextTranslatorTMP>().Destroy();
|
||||
_customOneButton.OnClick = new ButtonClickedEvent();
|
||||
_customOneButton.OnClick.AddListener(
|
||||
(UnityAction)(() =>
|
||||
{
|
||||
__instance.ChangeTab(4, false);
|
||||
}));
|
||||
_customOneButton.OnMouseOver = new UnityEvent();
|
||||
_customOneButton.OnMouseOver.AddListener(
|
||||
(UnityAction)(() =>
|
||||
{
|
||||
__instance.ChangeTab(4, true);
|
||||
}));
|
||||
|
||||
_customOneButton.buttonText.text = SelectedMod != null ? SelectedMod.MiraPlugin.CustomOptionMenuNameOne : "Custom Category 1";
|
||||
customPos.y -= 0.637f;
|
||||
_customOneButton.transform.localPosition = customPos;
|
||||
_customOneButton.name = "CustomOneButton";
|
||||
|
||||
_customOneBtnOgPos = _customOneButton.transform.localPosition;
|
||||
|
||||
// create button for the first custom category
|
||||
_customTwoButton = Object.Instantiate(_customOneButton, _customOneButton.transform.parent);
|
||||
_customTwoButton.OnClick = new ButtonClickedEvent();
|
||||
_customTwoButton.OnClick.AddListener(
|
||||
(UnityAction)(() =>
|
||||
{
|
||||
__instance.ChangeTab(5, false);
|
||||
}));
|
||||
_customTwoButton.OnMouseOver = new UnityEvent();
|
||||
_customTwoButton.OnMouseOver.AddListener(
|
||||
(UnityAction)(() =>
|
||||
{
|
||||
__instance.ChangeTab(5, true);
|
||||
}));
|
||||
|
||||
_customTwoButton.buttonText.text = SelectedMod != null ? SelectedMod.MiraPlugin.CustomOptionMenuNameTwo : "Custom Category 2";
|
||||
customPos.y -= 0.637f;
|
||||
_customTwoButton.transform.localPosition = customPos;
|
||||
_customTwoButton.name = "CustomTwoButton";
|
||||
|
||||
_customTwoBtnOgPos = _customTwoButton.transform.localPosition;
|
||||
|
||||
// create button for modifiers
|
||||
__instance.RoleSettingsButton.buttonText.gameObject.GetComponent<TextTranslatorTMP>().Destroy();
|
||||
__instance.RoleSettingsButton.gameObject.SetActive(false);
|
||||
_smallRolesButton = Object.Instantiate(
|
||||
__instance.RoleSettingsButton,
|
||||
__instance.RoleSettingsButton.transform.parent);
|
||||
var pos = new Vector3(
|
||||
-3.65f,
|
||||
_smallRolesButton.transform.localPosition.y,
|
||||
_smallRolesButton.transform.localPosition.z);
|
||||
_smallRolesButton.transform.localPosition = pos;
|
||||
_smallRolesButton.OnClick.AddListener(
|
||||
(UnityAction)(() =>
|
||||
{
|
||||
__instance.ChangeTab(2, false);
|
||||
}));
|
||||
_smallRolesButton.OnMouseOver.AddListener(
|
||||
(UnityAction)(() =>
|
||||
{
|
||||
__instance.ChangeTab(2, true);
|
||||
}));
|
||||
|
||||
_smallRoleBtnOgPos = _smallRolesButton.transform.localPosition;
|
||||
|
||||
var roleText = _smallRolesButton.buttonText;
|
||||
roleText.text = "Roles";
|
||||
roleText.GetComponent<TextTranslatorTMP>().Destroy();
|
||||
roleText.alignment = TextAlignmentOptions.Center;
|
||||
roleText.transform.parent.localPosition = new Vector3(
|
||||
-.525f,
|
||||
roleText.transform.parent.localPosition.y,
|
||||
roleText.transform.parent.localPosition.z);
|
||||
|
||||
foreach (var collider in _smallRolesButton.Colliders)
|
||||
// Add Menu State object
|
||||
if (!__instance.gameObject.GetComponent<MenuState>())
|
||||
{
|
||||
if (collider.TryCast<BoxCollider2D>() is { } col)
|
||||
{
|
||||
col.size = new Vector2(col.size.x / 2, col.size.y);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var rend in _smallRolesButton.GetComponentsInChildren<SpriteRenderer>(true))
|
||||
{
|
||||
rend.size = new Vector2(rend.size.x / 2, rend.size.y);
|
||||
}
|
||||
|
||||
_modifiersButton = Object.Instantiate(_smallRolesButton, _smallRolesButton.transform.parent);
|
||||
_modifiersButton.OnClick = new ButtonClickedEvent();
|
||||
_modifiersButton.OnClick.AddListener(
|
||||
(UnityAction)(() =>
|
||||
{
|
||||
__instance.ChangeTab(3, false);
|
||||
}));
|
||||
_modifiersButton.OnMouseOver = new UnityEvent();
|
||||
_modifiersButton.OnMouseOver.AddListener(
|
||||
(UnityAction)(() =>
|
||||
{
|
||||
__instance.ChangeTab(3, true);
|
||||
}));
|
||||
|
||||
_modifiersButton.buttonText.text = "Modifiers";
|
||||
pos.x = -2.27f;
|
||||
_modifiersButton.transform.localPosition = pos;
|
||||
_modifiersButton.name = "ModifiersButton";
|
||||
|
||||
_modifierBtnOgPos = _modifiersButton.transform.localPosition;
|
||||
|
||||
foreach (var plugin in MiraPluginManager.Instance.RegisteredPlugins)
|
||||
{
|
||||
PresetManager.LoadPresets(plugin);
|
||||
}
|
||||
|
||||
UpdateText(__instance, __instance.GameSettingsTab, __instance.RoleSettingsTab);
|
||||
}
|
||||
|
||||
private static void ChangeRoleSettingButton(bool replace, GameSettingMenu menu)
|
||||
{
|
||||
menu.RoleSettingsButton.OnClick = new ButtonClickedEvent();
|
||||
menu.RoleSettingsButton.OnMouseOver = new UnityEvent();
|
||||
|
||||
if (replace)
|
||||
{
|
||||
menu.RoleSettingsButton.buttonText.text = "Modifiers Settings";
|
||||
menu.RoleSettingsButton.OnClick.AddListener(
|
||||
(UnityAction)(() =>
|
||||
{
|
||||
menu.ChangeTab(3, false);
|
||||
}));
|
||||
menu.RoleSettingsButton.OnMouseOver.AddListener(
|
||||
(UnityAction)(() =>
|
||||
{
|
||||
menu.ChangeTab(3, true);
|
||||
}));
|
||||
__instance.gameObject.AddComponent<MenuState>();
|
||||
Info("MenuState component added to GameSettingMenu.");
|
||||
}
|
||||
else
|
||||
{
|
||||
menu.RoleSettingsButton.buttonText.text = "Roles Settings";
|
||||
menu.RoleSettingsButton.OnClick.AddListener(
|
||||
(UnityAction)(() =>
|
||||
{
|
||||
menu.ChangeTab(2, false);
|
||||
}));
|
||||
menu.RoleSettingsButton.OnMouseOver.AddListener(
|
||||
(UnityAction)(() =>
|
||||
{
|
||||
menu.ChangeTab(2, true);
|
||||
}));
|
||||
Info("MenuState component already added to GameSettingMenu.");
|
||||
}
|
||||
}
|
||||
|
||||
private static void UpdateText(GameSettingMenu menu, GameOptionsMenu settings, RolesSettingsMenu roles)
|
||||
[HarmonyPrefix]
|
||||
[HarmonyPatch(nameof(GameSettingMenu.ChangeTab))]
|
||||
public static bool ChangeTabPrefix(GameSettingMenu __instance, int tabNum, bool previewOnly)
|
||||
{
|
||||
if (_text is not null && SelectedModIdx == 0)
|
||||
if (MenuState.Instance)
|
||||
{
|
||||
_text.text = $"<size=40%>(Page 0/{MiraPluginManager.Instance.RegisteredPlugins.Length})</size>\nDefault";
|
||||
_text.fontSizeMax = 3.2f;
|
||||
SelectedMod = null;
|
||||
}
|
||||
else if (_text is not null)
|
||||
{
|
||||
_text.fontSizeMax = 2.3f;
|
||||
SelectedMod = MiraPluginManager.Instance.RegisteredPlugins[SelectedModIdx - 1];
|
||||
|
||||
var name = SelectedMod.MiraPlugin.OptionsTitleText;
|
||||
_text.text = $"<size=50%>(Page {SelectedModIdx}/{MiraPluginManager.Instance.RegisteredPlugins.Length})</size>\n" + name[..Math.Min(name.Length, 25)];
|
||||
}
|
||||
|
||||
bool replaceWithModifiers = true;
|
||||
_smallRolesButton!.transform.localPosition = _smallRoleBtnOgPos;
|
||||
_modifiersButton!.transform.localPosition = _modifierBtnOgPos;
|
||||
_customOneButton!.transform.localPosition = _customOneBtnOgPos;
|
||||
_customTwoButton!.transform.localPosition = _customTwoBtnOgPos;
|
||||
menu.RoleSettingsButton.transform.localPosition = _roleBtnOgPos;
|
||||
|
||||
if (SelectedModIdx != 0)
|
||||
{
|
||||
_customOneButton.buttonText.text = SelectedMod!.MiraPlugin.CustomOptionMenuNameOne;
|
||||
_customTwoButton.buttonText.text = SelectedMod!.MiraPlugin.CustomOptionMenuNameTwo;
|
||||
var modHasRoles = SelectedMod!.InternalRoles.Count != 0;
|
||||
var modHasCustomOne = SelectedMod.InternalOptionGroups.Exists(
|
||||
x => x.ParentMenu == MenuCategory.CustomOne);
|
||||
var modHasCustomTwo = SelectedMod.InternalOptionGroups.Exists(
|
||||
x => x.ParentMenu == MenuCategory.CustomTwo);
|
||||
var modHasModifiers = SelectedMod.InternalOptionGroups.Exists(
|
||||
x => x.ParentMenu == MenuCategory.Modifiers || x.OptionableType?.IsAssignableTo(typeof(BaseModifier)) == true);
|
||||
var modHasOptions =
|
||||
SelectedMod.InternalOptionGroups.Exists(x => x.OptionableType == null &&
|
||||
x.ParentMenu != MenuCategory.Modifiers && x.ParentMenu != MenuCategory.Roles);
|
||||
|
||||
_modifiersButton.gameObject.SetActive(true);
|
||||
_smallRolesButton.gameObject.SetActive(true);
|
||||
_customOneButton.gameObject.SetActive(true);
|
||||
_customTwoButton.gameObject.SetActive(true);
|
||||
menu.GameSettingsButton.gameObject.SetActive(true);
|
||||
menu.RoleSettingsButton.gameObject.SetActive(false);
|
||||
var defaultButton = menu.RoleSettingsButton;
|
||||
|
||||
// If there are no registered custom roles in the selected mod, hide the button.
|
||||
if (!modHasRoles)
|
||||
{
|
||||
_smallRolesButton.gameObject.SetActive(false);
|
||||
|
||||
if (roles.gameObject.active)
|
||||
{
|
||||
menu.ChangeTab(0, false);
|
||||
}
|
||||
|
||||
// If the mod has modifiers, we can disable the smaller modifier button and enable the bigger one.
|
||||
if (modHasModifiers)
|
||||
{
|
||||
_modifiersButton.gameObject.SetActive(false);
|
||||
menu.RoleSettingsButton.gameObject.SetActive(true);
|
||||
defaultButton = _modifiersButton;
|
||||
|
||||
if (_modifiersTab!.gameObject.active)
|
||||
{
|
||||
menu.RoleSettingsButton.SelectButton(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If there are no modifiers in the selected mod, hide the modifiers button.
|
||||
if (!modHasModifiers)
|
||||
{
|
||||
replaceWithModifiers = false;
|
||||
_modifiersButton.gameObject.SetActive(false);
|
||||
|
||||
if (_modifiersTab!.gameObject.active)
|
||||
{
|
||||
menu.ChangeTab(0, false);
|
||||
}
|
||||
|
||||
// If the mod has roles, we can enable the bigger role button and disable the small one.
|
||||
if (modHasRoles)
|
||||
{
|
||||
defaultButton = menu.RoleSettingsButton;
|
||||
menu.RoleSettingsButton.gameObject.SetActive(true);
|
||||
_smallRolesButton.gameObject.SetActive(false);
|
||||
}
|
||||
}
|
||||
|
||||
// If there are no custom game options registered (that aren't modifier options), hide game settings button.
|
||||
if (!modHasOptions)
|
||||
{
|
||||
menu.GameSettingsButton.gameObject.SetActive(false);
|
||||
|
||||
if (settings.gameObject.active)
|
||||
{
|
||||
menu.ChangeTab(0, false);
|
||||
}
|
||||
defaultButton = menu.RoleSettingsButton;
|
||||
|
||||
// If the mod has roles and modifiers, we can move their buttons to the game settings button position, since nothing is there.
|
||||
if (menu.RoleSettingsButton.gameObject.active)
|
||||
{
|
||||
menu.RoleSettingsButton.transform.localPosition = menu.GameSettingsButton.transform.localPosition;
|
||||
}
|
||||
else if (_modifiersButton.gameObject.active && _smallRolesButton.gameObject.active)
|
||||
{
|
||||
_modifiersButton.transform.localPosition = new Vector3(
|
||||
_modifiersButton.transform.localPosition.x,
|
||||
menu.GameSettingsButton.transform.localPosition.y,
|
||||
_modifiersButton.transform.localPosition.z);
|
||||
|
||||
_smallRolesButton.transform.localPosition = new Vector3(
|
||||
_smallRolesButton.transform.localPosition.x,
|
||||
menu.GameSettingsButton.transform.localPosition.y,
|
||||
_smallRolesButton.transform.localPosition.z);
|
||||
}
|
||||
}
|
||||
|
||||
// If the mod has no primary custom tab, we can go ahead and hide the button.
|
||||
if (!modHasCustomOne)
|
||||
{
|
||||
_customOneButton.gameObject.SetActive(false);
|
||||
if (_customOneTab!.gameObject.active)
|
||||
{
|
||||
defaultButton.SelectButton(true);
|
||||
}
|
||||
}
|
||||
// If the mod has no secondary custom tab, we can go ahead and hide the button.
|
||||
if (!modHasCustomTwo)
|
||||
{
|
||||
_customTwoButton.gameObject.SetActive(false);
|
||||
if (_customTwoTab!.gameObject.active)
|
||||
{
|
||||
defaultButton.SelectButton(true);
|
||||
}
|
||||
}
|
||||
MenuState.Instance.ChangeTabPatch(__instance, tabNum, previewOnly);
|
||||
}
|
||||
else
|
||||
{
|
||||
_modifiersButton.gameObject.SetActive(false);
|
||||
_smallRolesButton.gameObject.SetActive(false);
|
||||
_customOneButton.gameObject.SetActive(false);
|
||||
_customTwoButton.gameObject.SetActive(false);
|
||||
menu.RoleSettingsButton.gameObject.SetActive(true);
|
||||
menu.GameSettingsButton.gameObject.SetActive(true);
|
||||
replaceWithModifiers = false;
|
||||
|
||||
if (_modifiersTab!.gameObject.active || _customOneTab!.gameObject.active || _customTwoTab!.gameObject.active)
|
||||
{
|
||||
menu.ChangeTab(0, false);
|
||||
}
|
||||
}
|
||||
|
||||
if (menu.RoleSettingsButton.gameObject.active)
|
||||
{
|
||||
ChangeRoleSettingButton(replaceWithModifiers, menu);
|
||||
}
|
||||
|
||||
if (menu.PresetsTab.gameObject.active)
|
||||
{
|
||||
menu.ChangeTab(0, false);
|
||||
}
|
||||
|
||||
CleanupTab(settings, roles);
|
||||
}
|
||||
|
||||
private static void ClearOptions(Il2CppSystem.Collections.Generic.List<OptionBehaviour> options)
|
||||
{
|
||||
foreach (var child in options)
|
||||
{
|
||||
if (child.TryCast<GameOptionsMapPicker>() || !child.gameObject)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
child.gameObject.DestroyImmediate();
|
||||
}
|
||||
|
||||
options.Clear();
|
||||
}
|
||||
|
||||
private static void CleanupTab(GameOptionsMenu settings, RolesSettingsMenu roles)
|
||||
{
|
||||
if (roles.roleChances != null)
|
||||
{
|
||||
CleanupRoleSettings(roles);
|
||||
}
|
||||
|
||||
if (settings.Children != null)
|
||||
{
|
||||
CleanupSettings(settings);
|
||||
}
|
||||
|
||||
if (_modifiersTab?.Children?.Count > 0)
|
||||
{
|
||||
CleanupSettings(_modifiersTab, MenuCategory.Modifiers);
|
||||
}
|
||||
|
||||
if (_customOneTab?.Children?.Count > 0)
|
||||
{
|
||||
CleanupSettings(_customOneTab, MenuCategory.CustomOne);
|
||||
}
|
||||
|
||||
if (_customTwoTab?.Children?.Count > 0)
|
||||
{
|
||||
CleanupSettings(_customTwoTab, MenuCategory.CustomTwo);
|
||||
}
|
||||
|
||||
void CleanupRoleSettings(RolesSettingsMenu rolesMenu)
|
||||
{
|
||||
if (rolesMenu.advancedSettingChildren != null)
|
||||
{
|
||||
ClearOptions(rolesMenu.advancedSettingChildren);
|
||||
rolesMenu.advancedSettingChildren = null;
|
||||
}
|
||||
|
||||
rolesMenu.RoleChancesSettings
|
||||
.transform
|
||||
.GetComponentsInChildren<CategoryHeaderEditRole>()
|
||||
.ToList()
|
||||
.ForEach(header => header.gameObject.DestroyImmediate());
|
||||
|
||||
foreach (var role in rolesMenu.roleChances)
|
||||
{
|
||||
role.gameObject.DestroyImmediate();
|
||||
}
|
||||
|
||||
rolesMenu.roleChances?.Clear();
|
||||
|
||||
rolesMenu.AdvancedRolesSettings.gameObject.SetActive(false);
|
||||
rolesMenu.RoleChancesSettings.gameObject.SetActive(true);
|
||||
rolesMenu.SetQuotaTab();
|
||||
if (RoleSettingMenuPatches.RolePositions.TryGetValue(SelectedModIdx, out var pos))
|
||||
{
|
||||
rolesMenu.scrollBar.Inner.localPosition = pos;
|
||||
rolesMenu.scrollBar.UpdateScrollBars();
|
||||
}
|
||||
else
|
||||
{
|
||||
rolesMenu.scrollBar.ScrollToTop();
|
||||
}
|
||||
}
|
||||
|
||||
void CleanupSettings(GameOptionsMenu gameOptMenu, MenuCategory menuCategory = MenuCategory.Roles)
|
||||
{
|
||||
ClearOptions(gameOptMenu.Children);
|
||||
gameOptMenu.Children = null;
|
||||
|
||||
gameOptMenu.settingsContainer
|
||||
.GetComponentsInChildren<CategoryHeaderMasked>()
|
||||
.ToList()
|
||||
.ForEach(header => header.gameObject.DestroyImmediate());
|
||||
|
||||
gameOptMenu.Initialize();
|
||||
var positions = OptionsPositions;
|
||||
switch (menuCategory)
|
||||
{
|
||||
case MenuCategory.Modifiers:
|
||||
positions = ModifiersPositions;
|
||||
break;
|
||||
case MenuCategory.CustomOne:
|
||||
positions = CustomOnePositions;
|
||||
break;
|
||||
case MenuCategory.CustomTwo:
|
||||
positions = CustomTwoPositions;
|
||||
break;
|
||||
}
|
||||
if (positions.TryGetValue(SelectedModIdx, out var pos))
|
||||
{
|
||||
gameOptMenu.scrollBar.Inner.localPosition = pos;
|
||||
gameOptMenu.scrollBar.UpdateScrollBars();
|
||||
}
|
||||
else
|
||||
{
|
||||
gameOptMenu.scrollBar.ScrollToTop();
|
||||
}
|
||||
Error("MenuState instance is null. Cannot change tab.");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -25,7 +25,7 @@ public static class LobbyViewPanePatches
|
||||
|
||||
private static MiraPluginInfo? SelectedMod => SelectedModIdx == 0
|
||||
? null
|
||||
: MiraPluginManager.Instance.RegisteredPlugins[SelectedModIdx - 1];
|
||||
: MiraPluginManager.Instance.RegisteredPluginsWithOptions[SelectedModIdx - 1];
|
||||
|
||||
private static PassiveButton? ModifiersTabButton { get; set; }
|
||||
|
||||
@@ -75,7 +75,7 @@ public static class LobbyViewPanePatches
|
||||
(UnityAction)(() =>
|
||||
{
|
||||
SelectedModIdx += 1;
|
||||
if (SelectedModIdx > MiraPluginManager.Instance.RegisteredPlugins.Length)
|
||||
if (SelectedModIdx > MiraPluginManager.Instance.RegisteredPluginsWithOptions.Length)
|
||||
{
|
||||
SelectedModIdx = 0;
|
||||
}
|
||||
@@ -99,7 +99,7 @@ public static class LobbyViewPanePatches
|
||||
SelectedModIdx -= 1;
|
||||
if (SelectedModIdx < 0)
|
||||
{
|
||||
SelectedModIdx = MiraPluginManager.Instance.RegisteredPlugins.Length;
|
||||
SelectedModIdx = MiraPluginManager.Instance.RegisteredPluginsWithOptions.Length;
|
||||
}
|
||||
|
||||
Refresh(__instance);
|
||||
@@ -109,7 +109,7 @@ public static class LobbyViewPanePatches
|
||||
private static void Refresh(LobbyViewSettingsPane menu)
|
||||
{
|
||||
ModifiersTabButton?.gameObject.SetActive(SelectedModIdx != 0);
|
||||
menu.gameModeText.text = SelectedMod?.PluginInfo.Metadata.Name ?? "Default";
|
||||
menu.gameModeText.text = SelectedMod?.PluginInfo.Metadata.Name ?? "Main";
|
||||
menu.RefreshTab();
|
||||
menu.scrollBar.ScrollToTop();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,683 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Il2CppInterop.Runtime.Attributes;
|
||||
using MiraAPI.GameOptions;
|
||||
using MiraAPI.Modifiers;
|
||||
using MiraAPI.PluginLoading;
|
||||
using MiraAPI.Presets;
|
||||
using MiraAPI.Utilities.Assets;
|
||||
using Reactor.Utilities.Attributes;
|
||||
using Reactor.Utilities.Extensions;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace MiraAPI.Patches.Options;
|
||||
|
||||
[RegisterInIl2Cpp]
|
||||
public class MenuState(IntPtr cppPtr) : MonoBehaviour(cppPtr)
|
||||
{
|
||||
public static MenuState Instance { get; private set; } = null!;
|
||||
|
||||
public static int ModCount => MiraPluginManager.Instance.RegisteredPluginsWithOptions.Length;
|
||||
|
||||
private GameSettingMenu Gsm { get; set; }
|
||||
|
||||
public MenuCategory CurrentMenu { get; private set; }
|
||||
|
||||
public int CurrentModIdx { get; private set; }
|
||||
|
||||
public GameObject CurrentContainer => Containers[CurrentMenu][CurrentModIdx];
|
||||
|
||||
[HideFromIl2Cpp]
|
||||
public MiraPluginInfo CurrentMod => MiraPluginManager.Instance.RegisteredPluginsWithOptions[CurrentModIdx - 1];
|
||||
|
||||
// UI elements
|
||||
private TextMeshPro _text = null!;
|
||||
|
||||
private enum MenuButton
|
||||
{
|
||||
Roles,
|
||||
Modifiers,
|
||||
CustomOne,
|
||||
CustomTwo,
|
||||
}
|
||||
|
||||
private readonly Dictionary<MenuButton, PassiveButton> _smallButtons = [];
|
||||
private readonly Dictionary<MenuButton, PassiveButton> _largeButtons = [];
|
||||
|
||||
[HideFromIl2Cpp]
|
||||
public Dictionary<MenuCategory, Dictionary<int, GameObject>> Containers { get; } = new()
|
||||
{
|
||||
{ MenuCategory.Preset, [] },
|
||||
{ MenuCategory.Game, [] },
|
||||
{ MenuCategory.Roles, [] },
|
||||
{ MenuCategory.Modifiers, [] },
|
||||
{ MenuCategory.CustomOne, [] },
|
||||
{ MenuCategory.CustomTwo, [] },
|
||||
};
|
||||
|
||||
[HideFromIl2Cpp]
|
||||
internal Dictionary<int, bool> FinishedRoleMenus { get; } = [];
|
||||
|
||||
public void Awake()
|
||||
{
|
||||
if (Instance)
|
||||
{
|
||||
Error($"MenuState already exists! Destroying duplicate {name}.");
|
||||
Destroy(this);
|
||||
return;
|
||||
}
|
||||
|
||||
Instance = this;
|
||||
Gsm = GetComponent<GameSettingMenu>();
|
||||
|
||||
if (!Gsm)
|
||||
{
|
||||
Error($"MenuState could not find GameSettingMenu component! Destroying {name}.");
|
||||
Destroy(this);
|
||||
return;
|
||||
}
|
||||
|
||||
// Reload presets
|
||||
foreach (var plugin in MiraPluginManager.Instance.RegisteredPlugins)
|
||||
{
|
||||
PresetManager.LoadPresets(plugin);
|
||||
}
|
||||
|
||||
// Initialize and setup UI
|
||||
InitializeContainers();
|
||||
InitializeUi();
|
||||
UpdateUi();
|
||||
}
|
||||
|
||||
private void InitializeUi()
|
||||
{
|
||||
// Disable game settings label
|
||||
Gsm.transform.FindChild("GameSettingsLabel").gameObject.SetActive(false);
|
||||
|
||||
// Create mod name text
|
||||
var helpThing = Gsm.transform.FindChild("What Is This?");
|
||||
var tmpText = Instantiate(helpThing.transform.FindChild("InfoText"), helpThing.parent).gameObject;
|
||||
|
||||
Destroy(tmpText.GetComponent<TextTranslatorTMP>());
|
||||
tmpText.name = "SelectedMod";
|
||||
tmpText.transform.localPosition = new Vector3(-3.3382f, 1.5399f, -2);
|
||||
|
||||
_text = tmpText.GetComponent<TextMeshPro>();
|
||||
_text.fontSizeMax = 3.2f;
|
||||
_text.overflowMode = TextOverflowModes.Overflow;
|
||||
_text.alignment = TextAlignmentOptions.Center;
|
||||
_text.rectTransform.sizeDelta = new Vector2(1.5f, 0.8f);
|
||||
|
||||
// Create next and previous buttons
|
||||
var nextButton = Instantiate(Gsm.BackButton, Gsm.BackButton.transform.parent).gameObject;
|
||||
nextButton.transform.localPosition = new Vector3(-2.2663f, 1.5272f, -25f);
|
||||
nextButton.name = "RightArrowButton";
|
||||
nextButton.transform.FindChild("Inactive").gameObject.GetComponent<SpriteRenderer>().sprite =
|
||||
MiraAssets.NextButton.LoadAsset();
|
||||
nextButton.transform.FindChild("Active").gameObject.GetComponent<SpriteRenderer>().sprite =
|
||||
MiraAssets.NextButtonActive.LoadAsset();
|
||||
nextButton.gameObject.GetComponent<CloseButtonConsoleBehaviour>().DestroyImmediate();
|
||||
|
||||
var nextPassiveButton = nextButton.gameObject.GetComponent<PassiveButton>();
|
||||
nextPassiveButton.OnClick = new Button.ButtonClickedEvent();
|
||||
nextPassiveButton.OnClick.AddListener((UnityAction)NextMod);
|
||||
|
||||
var previousButton = Instantiate(nextButton, Gsm.BackButton.transform.parent).gameObject;
|
||||
previousButton.transform.localPosition = new Vector3(-4.4209f, 1.5272f, -25f);
|
||||
previousButton.name = "LeftArrowButton";
|
||||
previousButton.gameObject.GetComponent<CloseButtonConsoleBehaviour>().Destroy();
|
||||
previousButton.transform.FindChild("Active").gameObject.GetComponent<SpriteRenderer>().flipX =
|
||||
previousButton.transform.FindChild("Inactive").gameObject.GetComponent<SpriteRenderer>().flipX = true;
|
||||
|
||||
var prevPassiveButton = previousButton.gameObject.GetComponent<PassiveButton>();
|
||||
prevPassiveButton.OnClick = new Button.ButtonClickedEvent();
|
||||
prevPassiveButton.OnClick.AddListener((UnityAction)PreviousMod);
|
||||
|
||||
// Create menu buttons
|
||||
_largeButtons[(int)MenuButton.Roles] = Gsm.RoleSettingsButton;
|
||||
|
||||
// modifiers button
|
||||
var mBtn = Instantiate(Gsm.RoleSettingsButton, Gsm.RoleSettingsButton.transform.parent);
|
||||
_largeButtons[MenuButton.Modifiers] = mBtn;
|
||||
mBtn.name = "ModifiersButton";
|
||||
mBtn.buttonText.gameObject.GetComponent<TextTranslatorTMP>().Destroy();
|
||||
mBtn.buttonText.text = "Modifiers";
|
||||
mBtn.OnClick = new Button.ButtonClickedEvent();
|
||||
mBtn.OnClick.AddListener(
|
||||
(UnityAction)(() =>
|
||||
{
|
||||
Gsm.ChangeTab((int)MenuCategory.Modifiers, false);
|
||||
}));
|
||||
mBtn.OnMouseOver = new UnityEvent();
|
||||
mBtn.OnMouseOver.AddListener(
|
||||
(UnityAction)(() =>
|
||||
{
|
||||
Gsm.ChangeTab((int)MenuCategory.Modifiers, true);
|
||||
}));
|
||||
|
||||
// first custom menu
|
||||
var c1Btn = Instantiate(mBtn, mBtn.transform.parent);
|
||||
_largeButtons[MenuButton.CustomOne] = c1Btn;
|
||||
c1Btn.name = "CustomOneButton";
|
||||
c1Btn.buttonText.gameObject.GetComponent<TextTranslatorTMP>().Destroy();
|
||||
c1Btn.OnClick = new Button.ButtonClickedEvent();
|
||||
c1Btn.OnClick.AddListener(
|
||||
(UnityAction)(() =>
|
||||
{
|
||||
Gsm.ChangeTab((int)MenuCategory.CustomOne, false);
|
||||
}));
|
||||
c1Btn.OnMouseOver = new UnityEvent();
|
||||
c1Btn.OnMouseOver.AddListener(
|
||||
(UnityAction)(() =>
|
||||
{
|
||||
Gsm.ChangeTab((int)MenuCategory.CustomOne, true);
|
||||
}));
|
||||
|
||||
// second custom menu
|
||||
var c2Btn = Instantiate(c1Btn, c1Btn.transform.parent);
|
||||
_largeButtons[MenuButton.CustomTwo] = c2Btn;
|
||||
c2Btn.name = "CustomTwoButton";
|
||||
c2Btn.OnClick = new Button.ButtonClickedEvent();
|
||||
c2Btn.OnClick.AddListener(
|
||||
(UnityAction)(() =>
|
||||
{
|
||||
Gsm.ChangeTab((int)MenuCategory.CustomTwo, false);
|
||||
}));
|
||||
c2Btn.OnMouseOver = new UnityEvent();
|
||||
c2Btn.OnMouseOver.AddListener(
|
||||
(UnityAction)(() =>
|
||||
{
|
||||
Gsm.ChangeTab((int)MenuCategory.CustomTwo, true);
|
||||
}));
|
||||
|
||||
// small roles button
|
||||
var smRolesBtn = Instantiate(
|
||||
Gsm.RoleSettingsButton,
|
||||
Gsm.RoleSettingsButton.transform.parent);
|
||||
_smallButtons[MenuButton.Roles] = smRolesBtn;
|
||||
smRolesBtn.name = "SmallRolesButton";
|
||||
smRolesBtn.OnClick = new Button.ButtonClickedEvent();
|
||||
smRolesBtn.OnClick.AddListener(
|
||||
(UnityAction)(() =>
|
||||
{
|
||||
Gsm.ChangeTab((int)MenuCategory.Roles, false);
|
||||
}));
|
||||
smRolesBtn.OnMouseOver = new UnityEvent();
|
||||
smRolesBtn.OnMouseOver.AddListener(
|
||||
(UnityAction)(() =>
|
||||
{
|
||||
Gsm.ChangeTab((int)MenuCategory.Roles, true);
|
||||
}));
|
||||
|
||||
var roleText = smRolesBtn.buttonText;
|
||||
roleText.text = "Roles";
|
||||
roleText.GetComponent<TextTranslatorTMP>().Destroy();
|
||||
roleText.alignment = TextAlignmentOptions.Center;
|
||||
roleText.transform.parent.localPosition = new Vector3(
|
||||
-.525f,
|
||||
roleText.transform.parent.localPosition.y,
|
||||
roleText.transform.parent.localPosition.z);
|
||||
|
||||
foreach (var collider in smRolesBtn.Colliders)
|
||||
{
|
||||
if (collider.TryCast<BoxCollider2D>() is { } col)
|
||||
{
|
||||
col.size = new Vector2(col.size.x / 2, col.size.y);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var rend in smRolesBtn.GetComponentsInChildren<SpriteRenderer>(true))
|
||||
{
|
||||
rend.size = new Vector2(rend.size.x / 2, rend.size.y);
|
||||
}
|
||||
|
||||
// small modifiers button
|
||||
var smModBtn = Instantiate(smRolesBtn, smRolesBtn.transform.parent);
|
||||
_smallButtons[MenuButton.Modifiers] = smModBtn;
|
||||
smModBtn.name = "SmallModifiersButton";
|
||||
smModBtn.buttonText.text = "Modifiers";
|
||||
smModBtn.OnClick = new Button.ButtonClickedEvent();
|
||||
smModBtn.OnClick.AddListener(
|
||||
(UnityAction)(() =>
|
||||
{
|
||||
Gsm.ChangeTab((int)MenuCategory.Modifiers, false);
|
||||
}));
|
||||
smModBtn.OnMouseOver = new UnityEvent();
|
||||
smModBtn.OnMouseOver.AddListener(
|
||||
(UnityAction)(() =>
|
||||
{
|
||||
Gsm.ChangeTab((int)MenuCategory.Modifiers, true);
|
||||
}));
|
||||
|
||||
// small c1 button
|
||||
var smC1Btn = Instantiate(smModBtn, smModBtn.transform.parent);
|
||||
_smallButtons[MenuButton.CustomOne] = smC1Btn;
|
||||
smC1Btn.name = "SmallCustomOneButton";
|
||||
smC1Btn.buttonText.text = "Custom 1";
|
||||
smC1Btn.OnClick = new Button.ButtonClickedEvent();
|
||||
smC1Btn.OnClick.AddListener(
|
||||
(UnityAction)(() =>
|
||||
{
|
||||
Gsm.ChangeTab((int)MenuCategory.CustomOne, false);
|
||||
}));
|
||||
smC1Btn.OnMouseOver = new UnityEvent();
|
||||
smC1Btn.OnMouseOver.AddListener(
|
||||
(UnityAction)(() =>
|
||||
{
|
||||
Gsm.ChangeTab((int)MenuCategory.CustomOne, true);
|
||||
}));
|
||||
|
||||
// small c2 button
|
||||
var smC2Btn = Instantiate(smModBtn, smModBtn.transform.parent);
|
||||
_smallButtons[MenuButton.CustomTwo] = smC2Btn;
|
||||
smC2Btn.name = "SmallCustomTwoButton";
|
||||
smC2Btn.buttonText.text = "Custom 2";
|
||||
smC2Btn.OnClick = new Button.ButtonClickedEvent();
|
||||
smC2Btn.OnClick.AddListener(
|
||||
(UnityAction)(() =>
|
||||
{
|
||||
Gsm.ChangeTab((int)MenuCategory.CustomTwo, false);
|
||||
}));
|
||||
smC2Btn.OnMouseOver = new UnityEvent();
|
||||
smC2Btn.OnMouseOver.AddListener(
|
||||
(UnityAction)(() =>
|
||||
{
|
||||
Gsm.ChangeTab((int)MenuCategory.CustomTwo, true);
|
||||
}));
|
||||
}
|
||||
|
||||
private void InitializeContainers()
|
||||
{
|
||||
// Set vanilla containers
|
||||
Containers[MenuCategory.Game][0] = Gsm.GameSettingsTab.settingsContainer.gameObject;
|
||||
Containers[MenuCategory.Roles][0] = Gsm.RoleSettingsTab.RoleChancesSettings;
|
||||
|
||||
for (var idx = 0; idx < ModCount; idx++)
|
||||
{
|
||||
var mod = MiraPluginManager.Instance.RegisteredPluginsWithOptions[idx];
|
||||
|
||||
// Create preset container for each mod
|
||||
var presetContainer = new GameObject($"PresetHolder_{mod.PluginInfo.Metadata.Name}");
|
||||
presetContainer.transform.SetParent(Gsm.PresetsTab.transform, false);
|
||||
presetContainer.transform.localScale = new Vector3(0.9f, 0.9f, 1);
|
||||
presetContainer.transform.localPosition = new Vector3(-1.9f, 1.7f, 0);
|
||||
presetContainer.gameObject.SetActive(false);
|
||||
|
||||
var arrange = presetContainer.AddComponent<GridArrange>();
|
||||
arrange.Alignment = GridArrange.StartAlign.Right;
|
||||
arrange.CellSize = new Vector2(2.15f, -.55f);
|
||||
arrange.MaxColumns = 2;
|
||||
|
||||
Containers[MenuCategory.Preset][idx + 1] = presetContainer;
|
||||
|
||||
// Create game options container
|
||||
var gameContainer = Containers[MenuCategory.Game][idx + 1] = Instantiate(
|
||||
Gsm.GameSettingsTab.settingsContainer.gameObject,
|
||||
Gsm.GameSettingsTab.settingsContainer.gameObject.transform.parent);
|
||||
gameContainer.name = $"GameSettings_{mod.PluginInfo.Metadata.Name}";
|
||||
gameContainer.transform.DestroyChildren();
|
||||
gameContainer.SetActive(false);
|
||||
|
||||
// Roles container
|
||||
var rolesContainer = Containers[MenuCategory.Roles][idx + 1] = Instantiate(
|
||||
Gsm.RoleSettingsTab.RoleChancesSettings,
|
||||
Gsm.RoleSettingsTab.RoleChancesSettings.transform.parent);
|
||||
rolesContainer.name = $"RoleSettings_{mod.PluginInfo.Metadata.Name}";
|
||||
rolesContainer.transform.DestroyChildren();
|
||||
rolesContainer.SetActive(false);
|
||||
|
||||
// Modifiers + Custom containers
|
||||
for (var i = MenuCategory.Modifiers; i <= MenuCategory.CustomTwo; i++)
|
||||
{
|
||||
var cont = Containers[i][idx + 1] = Instantiate(
|
||||
Gsm.GameSettingsTab.settingsContainer.gameObject,
|
||||
Gsm.GameSettingsTab.settingsContainer.gameObject.transform.parent);
|
||||
cont.name = $"{i}_{mod.PluginInfo.Metadata.Name}";
|
||||
cont.transform.DestroyChildren();
|
||||
cont.SetActive(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateContainers()
|
||||
{
|
||||
foreach (var (_, dict) in Containers)
|
||||
{
|
||||
foreach (var (_, container) in dict)
|
||||
{
|
||||
container.SetActive(false);
|
||||
}
|
||||
}
|
||||
|
||||
Info($"Enabled {CurrentMenu} for {CurrentModIdx}");
|
||||
|
||||
// Preset containers
|
||||
if (CurrentModIdx != 0)
|
||||
{
|
||||
Containers[MenuCategory.Preset][CurrentModIdx].SetActive(true);
|
||||
}
|
||||
|
||||
// Game / Modifier / Custom Settings tab
|
||||
// GST.settingsContainer is same as GST.scrollBar.Inner
|
||||
if (CurrentMenu != MenuCategory.Preset && CurrentMenu != MenuCategory.Roles)
|
||||
{
|
||||
Gsm.GameSettingsTab.settingsContainer = Gsm.GameSettingsTab.scrollBar.Inner = CurrentContainer.transform;
|
||||
CurrentContainer.SetActive(true);
|
||||
}
|
||||
|
||||
// Role Settings Tab
|
||||
Gsm.RoleSettingsTab.RoleChancesSettings = Containers[MenuCategory.Roles][CurrentModIdx];
|
||||
Gsm.RoleSettingsTab.scrollBar.Inner = Containers[MenuCategory.Roles][CurrentModIdx].transform;
|
||||
Containers[MenuCategory.Roles][CurrentModIdx].SetActive(true);
|
||||
}
|
||||
|
||||
private void UpdateUi()
|
||||
{
|
||||
// Update mod text
|
||||
if (CurrentModIdx == 0)
|
||||
{
|
||||
_text.text = $"<size=40%>(Page 1/{ModCount + 1})</size>\nMain";
|
||||
}
|
||||
else
|
||||
{
|
||||
var modName = CurrentMod.MiraPlugin.OptionsTitleText;
|
||||
_text.text = $"<size=40%>(Page {CurrentModIdx + 1}/{ModCount + 1})</size>\n" +
|
||||
modName[..Math.Min(modName.Length, 25)];
|
||||
}
|
||||
|
||||
UpdateContainers();
|
||||
|
||||
// Update buttons
|
||||
foreach (var (_, btn) in _smallButtons)
|
||||
{
|
||||
btn.gameObject.SetActive(false);
|
||||
}
|
||||
|
||||
foreach (var (_, btn) in _largeButtons)
|
||||
{
|
||||
btn.gameObject.SetActive(false);
|
||||
}
|
||||
|
||||
if (CurrentModIdx == 0)
|
||||
{
|
||||
Gsm.GameSettingsButton.gameObject.SetActive(true);
|
||||
Gsm.RoleSettingsButton.gameObject.SetActive(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
var hasOptions =
|
||||
CurrentMod.InternalOptionGroups.Exists(g =>
|
||||
g.OptionableType == null && g.ParentMenu == MenuCategory.Game);
|
||||
var hasRoles = CurrentMod.InternalRoles.Count > 0;
|
||||
var hasModifiers = CurrentMod.InternalOptionGroups.Exists(g =>
|
||||
g.OptionableType?.IsAssignableTo(typeof(BaseModifier)) == true
|
||||
|| g.ParentMenu == MenuCategory.Modifiers);
|
||||
var hasC1 = CurrentMod.InternalOptionGroups.Exists(g => g.ParentMenu == MenuCategory.CustomOne);
|
||||
var hasC2 = CurrentMod.InternalOptionGroups.Exists(g => g.ParentMenu == MenuCategory.CustomTwo);
|
||||
const float leftPos = -3.65f;
|
||||
const float rightPos = -2.27f;
|
||||
|
||||
var smallRolesModifiers = hasRoles && hasModifiers && (hasC1 || hasC2);
|
||||
var smallC1C2 = hasC1 && hasC2;
|
||||
|
||||
Info("hasOptions: " + hasOptions);
|
||||
Info("hasRoles: " + hasRoles);
|
||||
Info("hasModifiers: " + hasModifiers);
|
||||
Info("hasC1: " + hasC1);
|
||||
Info("hasC2: " + hasC2);
|
||||
Info("smallC1C2: " + smallC1C2);
|
||||
Info("smallRolesModifiers: " + smallRolesModifiers);
|
||||
|
||||
var position = Gsm.GameSettingsButton.transform.localPosition;
|
||||
|
||||
// If this mod has game options, enable the game settings button
|
||||
if (hasOptions)
|
||||
{
|
||||
Gsm.GameSettingsButton.gameObject.SetActive(true);
|
||||
position.y -= 0.637f;
|
||||
}
|
||||
else
|
||||
{
|
||||
Gsm.GameSettingsButton.gameObject.SetActive(false);
|
||||
}
|
||||
|
||||
// If we should use small roles/modifiers buttons, enable them and position them accordingly
|
||||
if (smallRolesModifiers)
|
||||
{
|
||||
_smallButtons[MenuButton.Roles].gameObject.SetActive(true);
|
||||
_smallButtons[MenuButton.Roles].transform.localPosition = new Vector3(leftPos, position.y, position.z);
|
||||
_smallButtons[MenuButton.Modifiers].gameObject.SetActive(true);
|
||||
_smallButtons[MenuButton.Modifiers].transform.localPosition =
|
||||
new Vector3(rightPos, position.y, position.z);
|
||||
position.y -= 0.637f;
|
||||
}
|
||||
|
||||
// If we should use large roles button, enable and position, otherwise disable
|
||||
if (hasRoles && !smallRolesModifiers)
|
||||
{
|
||||
_largeButtons[MenuButton.Roles].gameObject.SetActive(true);
|
||||
_largeButtons[MenuButton.Roles].transform.localPosition = position;
|
||||
position.y -= 0.637f;
|
||||
}
|
||||
else
|
||||
{
|
||||
_largeButtons[MenuButton.Roles].gameObject.SetActive(false);
|
||||
}
|
||||
|
||||
// If we should use large modifiers button, enable and position, otherwise disable
|
||||
if (hasModifiers && !smallRolesModifiers)
|
||||
{
|
||||
_largeButtons[MenuButton.Modifiers].gameObject.SetActive(true);
|
||||
_largeButtons[MenuButton.Modifiers].transform.localPosition = position;
|
||||
position.y -= 0.637f;
|
||||
}
|
||||
else
|
||||
{
|
||||
_largeButtons[MenuButton.Modifiers].gameObject.SetActive(false);
|
||||
}
|
||||
|
||||
// if we should use small custom buttons, enable and position accordingly
|
||||
if (smallC1C2)
|
||||
{
|
||||
_smallButtons[MenuButton.CustomOne].gameObject.SetActive(true);
|
||||
_smallButtons[MenuButton.CustomOne].transform.localPosition =
|
||||
new Vector3(leftPos, position.y, position.z);
|
||||
_smallButtons[MenuButton.CustomOne].buttonText.text = CurrentMod.MiraPlugin.CustomOptionMenuNameOne;
|
||||
|
||||
_smallButtons[MenuButton.CustomTwo].gameObject.SetActive(true);
|
||||
_smallButtons[MenuButton.CustomTwo].transform.localPosition =
|
||||
new Vector3(rightPos, position.y, position.z);
|
||||
_smallButtons[MenuButton.CustomTwo].buttonText.text = CurrentMod.MiraPlugin.CustomOptionMenuNameTwo;
|
||||
position.y -= 0.637f;
|
||||
}
|
||||
|
||||
// C1 only
|
||||
if (hasC1 && !smallC1C2)
|
||||
{
|
||||
_largeButtons[MenuButton.CustomOne].gameObject.SetActive(true);
|
||||
_largeButtons[MenuButton.CustomOne].transform.localPosition = position;
|
||||
_largeButtons[MenuButton.CustomOne].buttonText.text = CurrentMod.MiraPlugin.CustomOptionMenuNameOne;
|
||||
position.y -= 0.637f;
|
||||
}
|
||||
else
|
||||
{
|
||||
_largeButtons[MenuButton.CustomOne].gameObject.SetActive(false);
|
||||
}
|
||||
|
||||
// C2 only
|
||||
if (hasC2 && !smallC1C2)
|
||||
{
|
||||
_largeButtons[MenuButton.CustomTwo].gameObject.SetActive(true);
|
||||
_largeButtons[MenuButton.CustomTwo].transform.localPosition = position;
|
||||
_largeButtons[MenuButton.CustomTwo].buttonText.text = CurrentMod.MiraPlugin.CustomOptionMenuNameTwo;
|
||||
position.y -= 0.637f;
|
||||
}
|
||||
else
|
||||
{
|
||||
_largeButtons[MenuButton.CustomTwo].gameObject.SetActive(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal void ChangeTabPatch(GameSettingMenu menu, int tabNum, bool previewOnly)
|
||||
{
|
||||
Info($"Changed tab to {(MenuCategory)tabNum} (previewOnly: {previewOnly}) for mod {CurrentModIdx}");
|
||||
if ((previewOnly && Controller.currentTouchType == Controller.TouchType.Joystick) || !previewOnly)
|
||||
{
|
||||
CurrentMenu = (MenuCategory)tabNum;
|
||||
UpdateContainers();
|
||||
|
||||
menu.PresetsTab.gameObject.SetActive(false);
|
||||
menu.GameSettingsTab.gameObject.SetActive(false);
|
||||
menu.RoleSettingsTab.gameObject.SetActive(false);
|
||||
|
||||
menu.GamePresetsButton.SelectButton(false);
|
||||
menu.GameSettingsButton.SelectButton(false);
|
||||
menu.RoleSettingsButton.SelectButton(false);
|
||||
|
||||
foreach (var (_, btn) in _largeButtons)
|
||||
{
|
||||
btn.SelectButton(false);
|
||||
}
|
||||
|
||||
foreach (var (_, btn) in _smallButtons)
|
||||
{
|
||||
btn.SelectButton(false);
|
||||
}
|
||||
|
||||
switch (CurrentMenu)
|
||||
{
|
||||
case MenuCategory.Preset:
|
||||
menu.PresetsTab.gameObject.SetActive(true);
|
||||
menu.MenuDescriptionText.text = TranslationController.Instance.GetString(StringNames.GamePresetsDescription);
|
||||
break;
|
||||
case MenuCategory.Game:
|
||||
menu.GameSettingsTab.gameObject.SetActive(true);
|
||||
menu.MenuDescriptionText.text = TranslationController.Instance.GetString(StringNames.GameSettingsDescription);
|
||||
break;
|
||||
case MenuCategory.Roles:
|
||||
menu.RoleSettingsTab.gameObject.SetActive(true);
|
||||
menu.RoleSettingsTab.OpenMenu(false);
|
||||
menu.MenuDescriptionText.text = TranslationController.Instance.GetString(StringNames.RoleSettingsDescription);
|
||||
break;
|
||||
|
||||
case MenuCategory.Modifiers:
|
||||
menu.GameSettingsTab.gameObject.SetActive(true);
|
||||
menu.MenuDescriptionText.text = CurrentMod.MiraPlugin.ModifierMenuDescription;
|
||||
break;
|
||||
case MenuCategory.CustomOne:
|
||||
menu.GameSettingsTab.gameObject.SetActive(true);
|
||||
menu.MenuDescriptionText.text = CurrentMod.MiraPlugin.CustomOptionMenuOneDescription;
|
||||
break;
|
||||
case MenuCategory.CustomTwo:
|
||||
menu.GameSettingsTab.gameObject.SetActive(true);
|
||||
menu.MenuDescriptionText.text = CurrentMod.MiraPlugin.CustomOptionMenuTwoDescription;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (previewOnly)
|
||||
{
|
||||
menu.ToggleLeftSideDarkener(false);
|
||||
menu.ToggleRightSideDarkener(true);
|
||||
return;
|
||||
}
|
||||
|
||||
menu.ToggleLeftSideDarkener(true);
|
||||
menu.ToggleRightSideDarkener(false);
|
||||
|
||||
CurrentMenu = (MenuCategory)tabNum;
|
||||
UpdateContainers();
|
||||
switch (CurrentMenu)
|
||||
{
|
||||
case MenuCategory.Preset:
|
||||
menu.PresetsTab.OpenMenu();
|
||||
menu.GamePresetsButton.SelectButton(true);
|
||||
break;
|
||||
case MenuCategory.Roles:
|
||||
menu.RoleSettingsTab.OpenMenu();
|
||||
SelectButton(MenuButton.Roles, MenuCategory.Roles);
|
||||
break;
|
||||
case MenuCategory.Game:
|
||||
case MenuCategory.Modifiers:
|
||||
case MenuCategory.CustomOne:
|
||||
case MenuCategory.CustomTwo:
|
||||
menu.GameSettingsButton.SelectButton(CurrentMenu == MenuCategory.Game);
|
||||
SelectButton(MenuButton.Modifiers, MenuCategory.Modifiers);
|
||||
SelectButton(MenuButton.CustomOne, MenuCategory.CustomOne);
|
||||
SelectButton(MenuButton.CustomTwo, MenuCategory.CustomTwo);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void SelectButton(MenuButton button, MenuCategory category)
|
||||
{
|
||||
if (_largeButtons[button].gameObject.activeInHierarchy)
|
||||
{
|
||||
_largeButtons[button].SelectButton(CurrentMenu == category);
|
||||
}
|
||||
|
||||
if (_smallButtons[button].gameObject.activeInHierarchy)
|
||||
{
|
||||
_smallButtons[button].SelectButton(CurrentMenu == category);
|
||||
}
|
||||
}
|
||||
|
||||
private MenuCategory GetNewPageIfNeeded()
|
||||
{
|
||||
if (CurrentModIdx == 0)
|
||||
{
|
||||
if (CurrentMenu >= MenuCategory.Modifiers)
|
||||
{
|
||||
return MenuCategory.Game;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var hasOptions =
|
||||
CurrentMod.InternalOptionGroups.Exists(g =>
|
||||
g.OptionableType == null && g.ParentMenu == MenuCategory.Game);
|
||||
var hasRoles = CurrentMod.InternalRoles.Count > 0;
|
||||
var hasModifiers = CurrentMod.InternalOptionGroups.Exists(g =>
|
||||
g.OptionableType?.IsAssignableTo(typeof(BaseModifier)) == true
|
||||
|| g.ParentMenu == MenuCategory.Modifiers);
|
||||
var hasC1 = CurrentMod.InternalOptionGroups.Exists(g => g.ParentMenu == MenuCategory.CustomOne);
|
||||
var hasC2 = CurrentMod.InternalOptionGroups.Exists(g => g.ParentMenu == MenuCategory.CustomTwo);
|
||||
|
||||
switch (CurrentMenu)
|
||||
{
|
||||
case MenuCategory.Game when !hasOptions:
|
||||
case MenuCategory.Roles when !hasRoles:
|
||||
case MenuCategory.Modifiers when !hasModifiers:
|
||||
case MenuCategory.CustomOne when !hasC1:
|
||||
case MenuCategory.CustomTwo when !hasC2:
|
||||
return MenuCategory.Preset;
|
||||
}
|
||||
}
|
||||
|
||||
return CurrentMenu;
|
||||
}
|
||||
|
||||
public void NextMod()
|
||||
{
|
||||
CurrentModIdx++;
|
||||
// The existence of vanilla settings offsets the off-by-one errors.
|
||||
if (CurrentModIdx > ModCount) CurrentModIdx = 0;
|
||||
CurrentMenu = GetNewPageIfNeeded();
|
||||
UpdateUi();
|
||||
ChangeTabPatch(Gsm, (int)CurrentMenu, false);
|
||||
}
|
||||
|
||||
public void PreviousMod()
|
||||
{
|
||||
CurrentModIdx--;
|
||||
// The existence of vanilla settings offsets the off-by-one errors.
|
||||
if (CurrentModIdx < 0) CurrentModIdx = ModCount;
|
||||
CurrentMenu = GetNewPageIfNeeded();
|
||||
UpdateUi();
|
||||
ChangeTabPatch(Gsm, (int)CurrentMenu, false);
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,6 @@
|
||||
using System.Linq;
|
||||
using HarmonyLib;
|
||||
using Il2CppSystem;
|
||||
using MiraAPI.Roles;
|
||||
using Object = Il2CppSystem.Object;
|
||||
|
||||
namespace MiraAPI.Patches.Options;
|
||||
|
||||
@@ -26,12 +24,14 @@ public static class NotificationPopperPatch
|
||||
|
||||
var textColor = customRole.OptionsMenuColor.ToTextColor();
|
||||
|
||||
var icon = customRole.Configuration.IconTmp ? $"<sprite name=\"{customRole.Configuration.IconTmp.name}\">" : string.Empty;
|
||||
var item = TranslationController.Instance.GetString(
|
||||
StringNames.LobbyChangeSettingNotificationRole,
|
||||
string.Concat(
|
||||
icon,
|
||||
"<font=\"Barlow-Black SDF\" material=\"Barlow-Black Outline\">",
|
||||
textColor,
|
||||
TranslationController.Instance.GetString(key, Array.Empty<Object>()),
|
||||
TranslationController.Instance.GetString(key),
|
||||
"</color></font>"
|
||||
),
|
||||
"<font=\"Barlow-Black SDF\" material=\"Barlow-Black Outline\">" + roleCount + "</font>",
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using HarmonyLib;
|
||||
using HarmonyLib;
|
||||
using Il2CppSystem;
|
||||
using MiraAPI.GameOptions;
|
||||
using MiraAPI.GameOptions.OptionTypes;
|
||||
using MiraAPI.Roles;
|
||||
using MiraAPI.Utilities;
|
||||
using UnityEngine;
|
||||
|
||||
@@ -1,12 +1,8 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Linq;
|
||||
using HarmonyLib;
|
||||
using MiraAPI.GameOptions;
|
||||
using MiraAPI.GameOptions.OptionTypes;
|
||||
using MiraAPI.Utilities;
|
||||
using Reactor.Utilities;
|
||||
using UnityEngine;
|
||||
using Object = Il2CppSystem.Object;
|
||||
|
||||
namespace MiraAPI.Patches.Options;
|
||||
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using AmongUs.GameOptions;
|
||||
using BepInEx.Unity.IL2CPP.Utils.Collections;
|
||||
using HarmonyLib;
|
||||
using Il2CppInterop.Runtime.InteropTypes.Arrays;
|
||||
using MiraAPI.GameOptions;
|
||||
using MiraAPI.Networking;
|
||||
using MiraAPI.Roles;
|
||||
@@ -11,7 +12,6 @@ using MiraAPI.Utilities;
|
||||
using MiraAPI.Utilities.Assets;
|
||||
using Reactor.Localization.Utilities;
|
||||
using Reactor.Networking.Rpc;
|
||||
using Reactor.Utilities;
|
||||
using Reactor.Utilities.Extensions;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
@@ -24,11 +24,7 @@ namespace MiraAPI.Patches.Options;
|
||||
[HarmonyPatch(typeof(RolesSettingsMenu))]
|
||||
public static class RoleSettingMenuPatches
|
||||
{
|
||||
public static Dictionary<int, Vector3> RolePositions { get; set; } = [];
|
||||
|
||||
private static Dictionary<RoleOptionsGroup, bool> RoleGroupHidden { get; set; } = [];
|
||||
private static List<GameObject> Headers { get; set; } = [];
|
||||
private static List<RoleOptionSetting> RoleOptionSettings { get; set; } = [];
|
||||
|
||||
private static float ScrollerNum { get; set; } = 0.522f;
|
||||
|
||||
@@ -42,337 +38,375 @@ public static class RoleSettingMenuPatches
|
||||
HudManager.Instance.PlayerCam.OverrideScreenShakeEnabled = false;
|
||||
}
|
||||
|
||||
[HarmonyPostfix]
|
||||
[HarmonyPatch(nameof(RolesSettingsMenu.SetQuotaTab))]
|
||||
public static void SetQuotaTabPostfix(RolesSettingsMenu __instance)
|
||||
private static IEnumerator CoQuotaTabPatch(RolesSettingsMenu roleMenu)
|
||||
{
|
||||
__instance.scrollBar.SetScrollBounds(__instance);
|
||||
}
|
||||
|
||||
[HarmonyPrefix]
|
||||
[HarmonyPatch(nameof(RolesSettingsMenu.SetQuotaTab))]
|
||||
public static bool SetQuotaTabPatch(RolesSettingsMenu __instance)
|
||||
{
|
||||
foreach (var obj in Headers)
|
||||
{
|
||||
if (!obj)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
obj.DeepDestroy(false);
|
||||
}
|
||||
Headers.Clear();
|
||||
foreach (var obj in RoleOptionSettings)
|
||||
{
|
||||
if (!obj)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
obj.gameObject.DeepDestroy(false);
|
||||
}
|
||||
RoleOptionSettings.Clear();
|
||||
CurrentRole = null;
|
||||
CurrentRoleOptions = null;
|
||||
|
||||
__instance.roleChances = new Il2CppSystem.Collections.Generic.List<RoleOptionSetting>();
|
||||
__instance.advancedSettingChildren = new Il2CppSystem.Collections.Generic.List<OptionBehaviour>();
|
||||
Utilities.Extensions.ClearGarbageCollector();
|
||||
roleMenu.QuotaTabSelectables.Clear();
|
||||
roleMenu.roleChances.Clear();
|
||||
roleMenu.advancedSettingChildren.Clear();
|
||||
|
||||
var maskBg = __instance.scrollBar.transform.FindChild("MaskBg");
|
||||
var hitbox = __instance.scrollBar.transform.FindChild("Hitbox");
|
||||
var dividerImage = __instance.transform.FindChild("HeaderButtons/DividerImage");
|
||||
var maskBg = roleMenu.scrollBar.transform.FindChild("MaskBg");
|
||||
var hitbox = roleMenu.scrollBar.transform.FindChild("Hitbox");
|
||||
var dividerImage = roleMenu.transform.FindChild("HeaderButtons/DividerImage");
|
||||
|
||||
if (GameSettingMenuPatches.SelectedModIdx == 0)
|
||||
if (MenuState.Instance.CurrentModIdx == 0)
|
||||
{
|
||||
__instance.AllButton.transform.parent.gameObject.SetActive(true);
|
||||
__instance.AllButton.gameObject.SetActive(true);
|
||||
__instance.scrollBar.transform.localPosition = new Vector3(-1.4957f, 0.657f, -4);
|
||||
roleMenu.AllButton.transform.parent.gameObject.SetActive(true);
|
||||
roleMenu.AllButton.gameObject.SetActive(true);
|
||||
roleMenu.scrollBar.transform.localPosition = new Vector3(-1.4957f, 0.657f, -4);
|
||||
maskBg.localPosition = new Vector3(1.5353f, -.5734f, -.1f);
|
||||
maskBg.localScale = new Vector3(6.6811f, 3.3563f, 0.5598f);
|
||||
hitbox.localPosition = new Vector3(0.3297f, -.2333f, 4f);
|
||||
hitbox.localScale = new Vector3(1, 1, 1);
|
||||
dividerImage.gameObject.SetActive(true);
|
||||
|
||||
var num = 0.662f;
|
||||
|
||||
var list = CustomRoleManager.AllRoles.Where(
|
||||
r => !r.IsCustomRole() && !r.IsRoleBlacklisted() && r.TeamType == RoleTeamTypes.Crewmate && r.Role != RoleTypes.Crewmate &&
|
||||
r.Role != RoleTypes.CrewmateGhost).ToList();
|
||||
var list2 = CustomRoleManager.AllRoles.Where(
|
||||
r => !r.IsCustomRole() && !r.IsRoleBlacklisted() && r.TeamType == RoleTeamTypes.Impostor && r.Role != RoleTypes.Impostor &&
|
||||
r.Role != RoleTypes.ImpostorGhost).ToList();
|
||||
|
||||
if (__instance.roleTabs == null || __instance.roleTabs.Count == 0)
|
||||
{
|
||||
var num2 = -1.928f;
|
||||
__instance.roleTabs = new();
|
||||
__instance.roleTabs.Add(__instance.AllButton);
|
||||
foreach (var t in list)
|
||||
{
|
||||
__instance.AddRoleTab(t, ref num2);
|
||||
}
|
||||
|
||||
foreach (var t in list2)
|
||||
{
|
||||
__instance.AddRoleTab(t, ref num2);
|
||||
}
|
||||
}
|
||||
|
||||
var categoryHeaderEditRole = Object.Instantiate(
|
||||
__instance.categoryHeaderEditRoleOrigin,
|
||||
Vector3.zero,
|
||||
Quaternion.identity,
|
||||
__instance.RoleChancesSettings.transform);
|
||||
categoryHeaderEditRole.SetHeader(StringNames.CrewmateRolesHeader, 20);
|
||||
categoryHeaderEditRole.transform.localPosition = new Vector3(4.986f, num, -2f);
|
||||
num -= 0.522f;
|
||||
var num3 = 0;
|
||||
foreach (var t in list)
|
||||
{
|
||||
__instance.CreateQuotaOption(t, ref num, num3);
|
||||
num3++;
|
||||
}
|
||||
|
||||
num -= 0.22f;
|
||||
var categoryHeaderEditRole2 = Object.Instantiate(
|
||||
__instance.categoryHeaderEditRoleOrigin,
|
||||
Vector3.zero,
|
||||
Quaternion.identity,
|
||||
__instance.RoleChancesSettings.transform);
|
||||
categoryHeaderEditRole2.SetHeader(StringNames.ImpostorRolesHeader, 20);
|
||||
categoryHeaderEditRole2.transform.localPosition = new Vector3(4.986f, num, -2f);
|
||||
num -= 0.522f;
|
||||
foreach (var t in list2)
|
||||
{
|
||||
__instance.CreateQuotaOption(t, ref num, num3);
|
||||
num3++;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
ScrollerNum = 0.522f;
|
||||
|
||||
__instance.AllButton.transform.parent.gameObject.SetActive(false);
|
||||
__instance.AllButton.gameObject.SetActive(false);
|
||||
__instance.scrollBar.transform.localPosition = new Vector3(-1.4957f, 1.5261f, -4);
|
||||
maskBg.localPosition = new Vector3(1.5353f, -1.0607f, -.1f);
|
||||
maskBg.localScale = new Vector3(6.6811f, 4.1563f, 0.5598f);
|
||||
hitbox.localPosition = new Vector3(0.3297f, -.6333f, 4f);
|
||||
hitbox.localScale = new Vector3(1, 1.2f, 1);
|
||||
dividerImage.gameObject.SetActive(false);
|
||||
|
||||
var num4 = 0;
|
||||
|
||||
var roleGroups = GameSettingMenuPatches.SelectedMod?.InternalRoles.Values.OfType<ICustomRole>()
|
||||
.ToLookup(x => x.RoleOptionsGroup);
|
||||
|
||||
if (roleGroups is null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// sort the groups by priority
|
||||
var sortedRoleGroups = roleGroups
|
||||
.OrderBy(x => x.Key.Priority)
|
||||
.ThenBy(x => x.Key.Name);
|
||||
|
||||
var quotaThing = __instance.categoryHeaderEditRoleOrigin.transform.FindChild("QuotaHeader");
|
||||
var usingNewQuota = false;
|
||||
var template = __instance.transform.parent.parent.GetComponent<GameSettingMenu>().GameSettingsTab.categoryHeaderOrigin;
|
||||
|
||||
foreach (var grouping in sortedRoleGroups)
|
||||
{
|
||||
if (!grouping.Any() || grouping.All(x=> x.Configuration.HideSettings || !x.VisibleInSettings()))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var group = grouping.Key;
|
||||
|
||||
RoleGroupHidden.TryAdd(group, false);
|
||||
|
||||
var name = group.Name switch
|
||||
{
|
||||
"Crewmate" => StringNames.CrewmateRolesHeader,
|
||||
"Impostor" => StringNames.ImpostorRolesHeader,
|
||||
_ => CustomStringName.CreateAndRegister(group.Name),
|
||||
};
|
||||
|
||||
var categoryHeaderMasked = Object.Instantiate(
|
||||
template,
|
||||
Vector3.zero,
|
||||
Quaternion.identity,
|
||||
__instance.RoleChancesSettings.transform);
|
||||
|
||||
categoryHeaderMasked.SetHeader(name, 20);
|
||||
|
||||
var quotaInst = Object.Instantiate(quotaThing, categoryHeaderMasked.transform);
|
||||
quotaInst.transform.localScale = new Vector3(1.3f, 1.3f, 1.3f);
|
||||
quotaInst.transform.localPosition = new Vector3(0.7f, -0.82f, 0);
|
||||
|
||||
var chanceText = quotaInst.transform.FindChild("Chance Text");
|
||||
chanceText.transform.localPosition = new Vector3(4.3f, 0.0993f, 0);
|
||||
|
||||
var countText = quotaInst.transform.FindChild("# Text");
|
||||
countText.transform.localPosition = new Vector3(1.9f, 0.0993f, 0f);
|
||||
|
||||
if (!usingNewQuota)
|
||||
{
|
||||
var blankLabel = quotaInst.transform.FindChild("BlankLabel").gameObject;
|
||||
var chanceLabel = quotaInst.transform.FindChild("Chance Label").gameObject;
|
||||
var countLabel = quotaInst.transform.FindChild("# Label").gameObject;
|
||||
blankLabel.DeepDestroy(false);
|
||||
chanceLabel.DeepDestroy(false);
|
||||
countLabel.DeepDestroy(false);
|
||||
usingNewQuota = true;
|
||||
quotaThing = quotaInst;
|
||||
}
|
||||
|
||||
categoryHeaderMasked.Background.sprite = MiraAssets.CategoryHeader.LoadAsset();
|
||||
categoryHeaderMasked.Background.sprite.texture.filterMode = FilterMode.Bilinear;
|
||||
categoryHeaderMasked.Background.sprite.texture.wrapMode = TextureWrapMode.Clamp;
|
||||
|
||||
categoryHeaderMasked.Background.transform.localPosition = new Vector3(0.5f, -0.1833f, 0);
|
||||
|
||||
switch (name)
|
||||
{
|
||||
case StringNames.CrewmateRolesHeader:
|
||||
categoryHeaderMasked.Title.color = Palette.CrewmateRoleHeaderTextBlue;
|
||||
categoryHeaderMasked.Background.color = Palette.CrewmateRoleHeaderBlue;
|
||||
break;
|
||||
case StringNames.ImpostorRolesHeader:
|
||||
categoryHeaderMasked.Title.color = Palette.ImpostorRoleHeaderTextRed;
|
||||
categoryHeaderMasked.Background.color = Palette.ImpostorRoleHeaderRed;
|
||||
break;
|
||||
default:
|
||||
categoryHeaderMasked.Title.color = group.Color.Equals(MiraApiPlugin.DefaultHeaderColor) ? Color.white : group.Color.FindAlternateColor();
|
||||
categoryHeaderMasked.Divider.color = group.Color;
|
||||
categoryHeaderMasked.Background.color = group.Color;
|
||||
break;
|
||||
}
|
||||
|
||||
categoryHeaderMasked.Title.fontStyle = __instance.categoryHeaderEditRoleOrigin.Title.fontStyle;
|
||||
categoryHeaderMasked.Title.font = __instance.categoryHeaderEditRoleOrigin.Title.font;
|
||||
categoryHeaderMasked.Title.fontMaterial = __instance.categoryHeaderEditRoleOrigin.Title.fontMaterial;
|
||||
|
||||
categoryHeaderMasked.Divider.color = categoryHeaderMasked.Background.color;
|
||||
categoryHeaderMasked.Background.transform.localPosition = new Vector3(0.55f, -0.1833f, 0);
|
||||
categoryHeaderMasked.Background.size = new Vector2(categoryHeaderMasked.Background.size.x + 1.5f, categoryHeaderMasked.Background.size.y);
|
||||
|
||||
categoryHeaderMasked.transform.localScale = Vector3.one * 0.63f;
|
||||
categoryHeaderMasked.transform.localPosition = new Vector3(-0.44f, ScrollerNum, -2f);
|
||||
categoryHeaderMasked.gameObject.SetActive(true);
|
||||
quotaInst.gameObject.SetActive(!RoleGroupHidden[group]);
|
||||
|
||||
var label = RoleGroupHidden[group]
|
||||
? "(Click to open)"
|
||||
: "(Click to close)";
|
||||
var newText = Object.Instantiate(categoryHeaderMasked.Title, categoryHeaderMasked.transform);
|
||||
newText.text = $"<size=70%>{label}</size>";
|
||||
newText.transform.localPosition = new Vector3(2.6249f, -0.165f, 0f);
|
||||
newText.gameObject.GetComponent<TextTranslatorTMP>().Destroy();
|
||||
|
||||
Headers.Add(categoryHeaderMasked.gameObject);
|
||||
ScrollerNum -= 0.422f;
|
||||
|
||||
if (!RoleGroupHidden[group])
|
||||
{
|
||||
foreach (var role in grouping)
|
||||
{
|
||||
if (role is not RoleBehaviour roleBehaviour)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var option = CreateQuotaOption(__instance, roleBehaviour, num4);
|
||||
if (option is not null)
|
||||
{
|
||||
RoleOptionSettings.Add(option);
|
||||
num4++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var boxCol = categoryHeaderMasked.gameObject.AddComponent<BoxCollider2D>();
|
||||
boxCol.size = new Vector2(7, 0.7f);
|
||||
boxCol.offset = new Vector2(1.5f, -0.3f);
|
||||
|
||||
var headerBtn = categoryHeaderMasked.gameObject.AddComponent<PassiveButton>();
|
||||
headerBtn.ClickSound = __instance.BackButton.GetComponent<PassiveButton>().ClickSound;
|
||||
headerBtn.OnMouseOver = new UnityEvent();
|
||||
headerBtn.OnMouseOut = new UnityEvent();
|
||||
headerBtn.OnClick.AddListener(
|
||||
(UnityAction)(() =>
|
||||
{
|
||||
RolePositions[GameSettingMenuPatches.SelectedModIdx] = __instance.scrollBar.Inner.localPosition;
|
||||
if (RoleGroupHidden.TryGetValue(group, out var groupHidden))
|
||||
{
|
||||
RoleGroupHidden[group] = !groupHidden;
|
||||
}
|
||||
foreach (var obj in Headers)
|
||||
{
|
||||
if (!obj)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
obj.DeepDestroy(false);
|
||||
}
|
||||
Headers.Clear();
|
||||
foreach (var obj in RoleOptionSettings)
|
||||
{
|
||||
if (!obj)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
obj.gameObject.DeepDestroy(false);
|
||||
}
|
||||
RoleOptionSettings.Clear();
|
||||
Utilities.Extensions.ClearGarbageCollector();
|
||||
__instance.SetQuotaTab();
|
||||
}));
|
||||
headerBtn.SetButtonEnableState(true);
|
||||
|
||||
if (RoleGroupHidden.TryGetValue(group, out var value) && !value)
|
||||
{
|
||||
ScrollerNum -= 0.4f;
|
||||
}
|
||||
}
|
||||
|
||||
__instance.scrollBar.SetScrollBounds(__instance);
|
||||
return false;
|
||||
}
|
||||
|
||||
private static void SetScrollBounds(this Scroller scroller, RolesSettingsMenu roleMenu)
|
||||
{
|
||||
if (GameSettingMenuPatches.SelectedModIdx == 0)
|
||||
{
|
||||
scroller.CalculateAndSetYBounds(roleMenu.roleChances.Count + 3, 1f, 6f, 0.43f);
|
||||
return;
|
||||
}
|
||||
|
||||
scroller.SetYBoundsMax(-ScrollerNum - 2);
|
||||
if (RolePositions.TryGetValue(GameSettingMenuPatches.SelectedModIdx, out var scroll))
|
||||
{
|
||||
scroller.Inner.localPosition = scroll;
|
||||
scroller.UpdateScrollBars();
|
||||
}
|
||||
else
|
||||
{
|
||||
scroller.ScrollToTop();
|
||||
roleMenu.AllButton.transform.parent.gameObject.SetActive(false);
|
||||
roleMenu.AllButton.gameObject.SetActive(false);
|
||||
roleMenu.scrollBar.transform.localPosition = new Vector3(-1.4957f, 1.5261f, -4);
|
||||
maskBg.localPosition = new Vector3(1.5353f, -1.0607f, -.1f);
|
||||
maskBg.localScale = new Vector3(6.6811f, 4.1563f, 0.5598f);
|
||||
hitbox.localPosition = new Vector3(0.3297f, -.6333f, 4f);
|
||||
hitbox.localScale = new Vector3(1, 1.2f, 1);
|
||||
dividerImage.gameObject.SetActive(false);
|
||||
}
|
||||
|
||||
if (MenuState.Instance.FinishedRoleMenus.TryGetValue(MenuState.Instance.CurrentModIdx, out var finished) && finished)
|
||||
{
|
||||
var roleOptionSettings = roleMenu.scrollBar.Inner.GetComponentsInChildren<RoleOptionSetting>(true);
|
||||
foreach (var r in roleOptionSettings)
|
||||
{
|
||||
roleMenu.roleChances.Add(r);
|
||||
roleMenu.QuotaTabSelectables.AddRange(new Il2CppSystem.Collections.Generic.IEnumerable<UiElement>(r.ControllerSelectable.Pointer));
|
||||
}
|
||||
|
||||
Info($"Already created role options for {MenuState.Instance.CurrentModIdx}");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (MenuState.Instance.CurrentModIdx == 0)
|
||||
{
|
||||
var num = 0.662f;
|
||||
|
||||
var list = CustomRoleManager.AllRoles.Where(r =>
|
||||
!r.IsCustomRole() && !r.IsRoleBlacklisted() && r.TeamType == RoleTeamTypes.Crewmate &&
|
||||
r.Role != RoleTypes.Crewmate &&
|
||||
r.Role != RoleTypes.CrewmateGhost).ToList();
|
||||
var list2 = CustomRoleManager.AllRoles.Where(r =>
|
||||
!r.IsCustomRole() && !r.IsRoleBlacklisted() && r.TeamType == RoleTeamTypes.Impostor &&
|
||||
r.Role != RoleTypes.Impostor &&
|
||||
r.Role != RoleTypes.ImpostorGhost).ToList();
|
||||
|
||||
if (roleMenu.roleTabs == null || roleMenu.roleTabs.Count == 0)
|
||||
{
|
||||
var num2 = -1.928f;
|
||||
roleMenu.roleTabs = new();
|
||||
roleMenu.roleTabs.Add(roleMenu.AllButton);
|
||||
foreach (var t in list)
|
||||
{
|
||||
roleMenu.AddRoleTab(t, ref num2);
|
||||
}
|
||||
|
||||
foreach (var t in list2)
|
||||
{
|
||||
roleMenu.AddRoleTab(t, ref num2);
|
||||
}
|
||||
}
|
||||
|
||||
var categoryHeaderEditRole = Object.Instantiate(
|
||||
roleMenu.categoryHeaderEditRoleOrigin,
|
||||
Vector3.zero,
|
||||
Quaternion.identity,
|
||||
roleMenu.RoleChancesSettings.transform);
|
||||
categoryHeaderEditRole.SetHeader(StringNames.CrewmateRolesHeader, 20);
|
||||
categoryHeaderEditRole.transform.localPosition = new Vector3(4.986f, num, -2f);
|
||||
num -= 0.522f;
|
||||
var num3 = 0;
|
||||
foreach (var t in list)
|
||||
{
|
||||
roleMenu.CreateQuotaOption(t, ref num, num3);
|
||||
num3++;
|
||||
}
|
||||
|
||||
num -= 0.22f;
|
||||
var categoryHeaderEditRole2 = Object.Instantiate(
|
||||
roleMenu.categoryHeaderEditRoleOrigin,
|
||||
Vector3.zero,
|
||||
Quaternion.identity,
|
||||
roleMenu.RoleChancesSettings.transform);
|
||||
categoryHeaderEditRole2.SetHeader(StringNames.ImpostorRolesHeader, 20);
|
||||
categoryHeaderEditRole2.transform.localPosition = new Vector3(4.986f, num, -2f);
|
||||
num -= 0.522f;
|
||||
foreach (var t in list2)
|
||||
{
|
||||
roleMenu.CreateQuotaOption(t, ref num, num3);
|
||||
num3++;
|
||||
}
|
||||
|
||||
Info($"Created {num3} role options for the default game.");
|
||||
}
|
||||
else
|
||||
{
|
||||
ScrollerNum = 0.522f;
|
||||
|
||||
var num4 = 0;
|
||||
|
||||
var roleGroups = MenuState.Instance.CurrentMod.InternalRoles.Values.OfType<ICustomRole>()
|
||||
.ToLookup(x => x.RoleOptionsGroup);
|
||||
|
||||
if (roleGroups.Count == 0)
|
||||
{
|
||||
Error("No role groups found for the selected mod.");
|
||||
}
|
||||
else
|
||||
{
|
||||
// sort the groups by priority
|
||||
var sortedRoleGroups = roleGroups
|
||||
.OrderBy(x => x.Key.Priority)
|
||||
.ThenBy(x => x.Key.Name);
|
||||
|
||||
var quotaThing = roleMenu.categoryHeaderEditRoleOrigin.transform.FindChild("QuotaHeader");
|
||||
var usingNewQuota = false;
|
||||
var template = roleMenu.transform.parent.parent.GetComponent<GameSettingMenu>().GameSettingsTab
|
||||
.categoryHeaderOrigin;
|
||||
|
||||
foreach (var grouping in sortedRoleGroups)
|
||||
{
|
||||
if (!grouping.Any() ||
|
||||
grouping.All(x => x.Configuration.HideSettings || !x.VisibleInSettings()))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var group = grouping.Key;
|
||||
|
||||
RoleGroupHidden.TryAdd(group, false);
|
||||
|
||||
var name = group.Name switch
|
||||
{
|
||||
"Crewmate" => StringNames.CrewmateRolesHeader,
|
||||
"Impostor" => StringNames.ImpostorRolesHeader,
|
||||
_ => CustomStringName.CreateAndRegister(group.Name),
|
||||
};
|
||||
|
||||
var categoryHeaderMasked = Object.Instantiate(
|
||||
template,
|
||||
Vector3.zero,
|
||||
Quaternion.identity,
|
||||
roleMenu.RoleChancesSettings.transform);
|
||||
|
||||
categoryHeaderMasked.SetHeader(name, 20);
|
||||
|
||||
var quotaInst = Object.Instantiate(quotaThing, categoryHeaderMasked.transform);
|
||||
quotaInst.transform.localScale = new Vector3(1.3f, 1.3f, 1.3f);
|
||||
quotaInst.transform.localPosition = new Vector3(0.7f, -0.82f, 0);
|
||||
|
||||
var chanceText = quotaInst.transform.FindChild("Chance Text");
|
||||
chanceText.transform.localPosition = new Vector3(4.3f, 0.0993f, 0);
|
||||
|
||||
var countText = quotaInst.transform.FindChild("# Text");
|
||||
countText.transform.localPosition = new Vector3(1.9f, 0.0993f, 0f);
|
||||
|
||||
if (!usingNewQuota)
|
||||
{
|
||||
var blankLabel = quotaInst.transform.FindChild("BlankLabel").gameObject;
|
||||
var chanceLabel = quotaInst.transform.FindChild("Chance Label").gameObject;
|
||||
var countLabel = quotaInst.transform.FindChild("# Label").gameObject;
|
||||
blankLabel.Destroy();
|
||||
chanceLabel.Destroy();
|
||||
countLabel.Destroy();
|
||||
usingNewQuota = true;
|
||||
quotaThing = quotaInst;
|
||||
}
|
||||
|
||||
categoryHeaderMasked.Background.sprite = MiraAssets.CategoryHeader.LoadAsset();
|
||||
categoryHeaderMasked.Background.sprite.texture.filterMode = FilterMode.Bilinear;
|
||||
categoryHeaderMasked.Background.sprite.texture.wrapMode = TextureWrapMode.Clamp;
|
||||
|
||||
categoryHeaderMasked.Background.transform.localPosition = new Vector3(0.5f, -0.1833f, 0);
|
||||
|
||||
switch (name)
|
||||
{
|
||||
case StringNames.CrewmateRolesHeader:
|
||||
categoryHeaderMasked.Title.color = Palette.CrewmateRoleHeaderTextBlue;
|
||||
categoryHeaderMasked.Background.color = Palette.CrewmateRoleHeaderBlue;
|
||||
break;
|
||||
case StringNames.ImpostorRolesHeader:
|
||||
categoryHeaderMasked.Title.color = Palette.ImpostorRoleHeaderTextRed;
|
||||
categoryHeaderMasked.Background.color = Palette.ImpostorRoleHeaderRed;
|
||||
break;
|
||||
default:
|
||||
categoryHeaderMasked.Title.color = group.Color.Equals(MiraApiPlugin.DefaultHeaderColor)
|
||||
? Color.white
|
||||
: group.Color.FindAlternateColor();
|
||||
categoryHeaderMasked.Divider.color = group.Color;
|
||||
categoryHeaderMasked.Background.color = group.Color;
|
||||
break;
|
||||
}
|
||||
|
||||
categoryHeaderMasked.Title.fontStyle = roleMenu.categoryHeaderEditRoleOrigin.Title.fontStyle;
|
||||
categoryHeaderMasked.Title.font = roleMenu.categoryHeaderEditRoleOrigin.Title.font;
|
||||
categoryHeaderMasked.Title.fontMaterial =
|
||||
roleMenu.categoryHeaderEditRoleOrigin.Title.fontMaterial;
|
||||
|
||||
categoryHeaderMasked.Divider.color = categoryHeaderMasked.Background.color;
|
||||
categoryHeaderMasked.Background.transform.localPosition = new Vector3(0.55f, -0.1833f, 0);
|
||||
categoryHeaderMasked.Background.size = new Vector2(
|
||||
categoryHeaderMasked.Background.size.x + 1.5f,
|
||||
categoryHeaderMasked.Background.size.y);
|
||||
|
||||
categoryHeaderMasked.transform.localScale = Vector3.one * 0.63f;
|
||||
categoryHeaderMasked.transform.localPosition = new Vector3(-0.44f, ScrollerNum, -2f);
|
||||
categoryHeaderMasked.gameObject.SetActive(true);
|
||||
quotaInst.gameObject.SetActive(!RoleGroupHidden[group]);
|
||||
|
||||
var label = RoleGroupHidden[group]
|
||||
? "(Click to open)"
|
||||
: "(Click to close)";
|
||||
var newText = Object.Instantiate(categoryHeaderMasked.Title, categoryHeaderMasked.transform);
|
||||
newText.text = $"<size=70%>{label}</size>";
|
||||
newText.transform.localPosition = new Vector3(2.6249f, -0.165f, 0f);
|
||||
newText.gameObject.GetComponent<TextTranslatorTMP>().Destroy();
|
||||
|
||||
ScrollerNum -= 0.422f;
|
||||
|
||||
if (!RoleGroupHidden[group])
|
||||
{
|
||||
yield return
|
||||
grouping.CoLoopWithBudget(role =>
|
||||
{
|
||||
if (role is not RoleBehaviour roleBehaviour)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var option = CreateQuotaOption(roleMenu, roleBehaviour, num4);
|
||||
if (option is not null)
|
||||
{
|
||||
num4++;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
var boxCol = categoryHeaderMasked.gameObject.AddComponent<BoxCollider2D>();
|
||||
boxCol.size = new Vector2(7, 0.7f);
|
||||
boxCol.offset = new Vector2(1.5f, -0.3f);
|
||||
|
||||
var headerBtn = categoryHeaderMasked.gameObject.AddComponent<PassiveButton>();
|
||||
headerBtn.ClickSound = roleMenu.BackButton.GetComponent<PassiveButton>().ClickSound;
|
||||
headerBtn.OnMouseOver = new UnityEvent();
|
||||
headerBtn.OnMouseOut = new UnityEvent();
|
||||
headerBtn.OnClick.AddListener(
|
||||
(UnityAction)(() =>
|
||||
{
|
||||
if (RoleGroupHidden.TryGetValue(group, out var groupHidden))
|
||||
{
|
||||
RoleGroupHidden[group] = !groupHidden;
|
||||
}
|
||||
|
||||
MenuState.Instance.FinishedRoleMenus[MenuState.Instance.CurrentModIdx] = false;
|
||||
|
||||
foreach (var child in roleMenu.RoleChancesSettings.transform)
|
||||
{
|
||||
var transform = child.Cast<Transform>();
|
||||
Object.Destroy(transform.gameObject);
|
||||
}
|
||||
|
||||
roleMenu.OpenChancesTab();
|
||||
}));
|
||||
headerBtn.SetButtonEnableState(true);
|
||||
|
||||
if (RoleGroupHidden.TryGetValue(group, out var value) && !value)
|
||||
{
|
||||
ScrollerNum -= 0.4f;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
MenuState.Instance.FinishedRoleMenus[MenuState.Instance.CurrentModIdx] = true;
|
||||
}
|
||||
|
||||
roleMenu.SetScrollBounds();
|
||||
_quotaTabCoroutine = null;
|
||||
}
|
||||
|
||||
private static Coroutine? _quotaTabCoroutine;
|
||||
|
||||
[HarmonyPrefix]
|
||||
[HarmonyPatch(nameof(RolesSettingsMenu.OpenChancesTab))]
|
||||
public static bool OpenChancesTabPatch(RolesSettingsMenu __instance, bool controllerSelected)
|
||||
{
|
||||
__instance.selectedRoleTab = 0;
|
||||
__instance.RoleChancesSettings.SetActive(true);
|
||||
__instance.AdvancedRolesSettings.SetActive(false);
|
||||
__instance.ControllerSelectable.Clear();
|
||||
if (_quotaTabCoroutine != null)
|
||||
{
|
||||
GameSettingMenu.Instance.StopCoroutine(_quotaTabCoroutine);
|
||||
}
|
||||
|
||||
__instance.QuotaTabSelectables ??= new();
|
||||
__instance.roleChances ??= new();
|
||||
__instance.advancedSettingChildren ??= new();
|
||||
|
||||
_quotaTabCoroutine = GameSettingMenu.Instance.StartCoroutine(CoOpenChancesTab().WrapToIl2Cpp());
|
||||
return false;
|
||||
|
||||
IEnumerator CoOpenChancesTab()
|
||||
{
|
||||
yield return CoQuotaTabPatch(__instance);
|
||||
if (controllerSelected)
|
||||
{
|
||||
__instance.ControllerSelectable.AddRange(
|
||||
new Il2CppSystem.Collections.Generic.IEnumerable<UiElement>(
|
||||
__instance.QuotaTabSelectables.Pointer));
|
||||
}
|
||||
|
||||
if (controllerSelected)
|
||||
{
|
||||
ControllerManager.Instance.CurrentUiState.SelectableUiElements = __instance.ControllerSelectable;
|
||||
if (__instance.ControllerSelectable.Count != 0)
|
||||
{
|
||||
ControllerManager.Instance.SetDefaultSelection(__instance.ControllerSelectable[0]);
|
||||
}
|
||||
}
|
||||
var passiveButton = __instance.currentTabButton;
|
||||
if (passiveButton)
|
||||
{
|
||||
passiveButton.SelectButton(false);
|
||||
}
|
||||
__instance.AllButton.SelectButton(true);
|
||||
__instance.currentTabButton = __instance.AllButton;
|
||||
}
|
||||
}
|
||||
|
||||
private static void SetScrollBounds(this RolesSettingsMenu menu, bool isRolesConfig = false)
|
||||
{
|
||||
var scroller = menu.scrollBar;
|
||||
|
||||
if (MenuState.Instance.CurrentModIdx == 0)
|
||||
{
|
||||
scroller.CalculateAndSetYBounds(menu.roleChances.Count + 3, 1f, 6f, 0.43f);
|
||||
return;
|
||||
}
|
||||
|
||||
scroller.Inner = isRolesConfig ? menu.AdvancedRolesSettings.transform : menu.RoleChancesSettings.transform;
|
||||
scroller.SetYBoundsMax(-ScrollerNum - 2);
|
||||
}
|
||||
|
||||
[HarmonyPrefix]
|
||||
// TODO: turn this into a fixed update
|
||||
[HarmonyPatch(nameof(RolesSettingsMenu.Update))]
|
||||
public static bool UpdatePatch(RolesSettingsMenu __instance)
|
||||
{
|
||||
if (GameSettingMenuPatches.SelectedModIdx == 0) return true;
|
||||
if (MenuState.Instance.CurrentModIdx == 0) return true;
|
||||
if (CurrentRole == null || CurrentRoleOptions == null) return false;
|
||||
|
||||
var hasImage = CurrentRole.RoleScreenshot != null;
|
||||
var num = hasImage ? -0.872f : -1;
|
||||
|
||||
foreach (var opt in CurrentRoleOptions)
|
||||
{
|
||||
if (opt.OptionBehaviour == null) continue;
|
||||
@@ -392,20 +426,6 @@ public static class RoleSettingMenuPatches
|
||||
return false;
|
||||
}
|
||||
|
||||
[HarmonyPostfix]
|
||||
[HarmonyPatch(nameof(RolesSettingsMenu.OpenChancesTab))]
|
||||
public static void OpenChancesTabPostfix(RolesSettingsMenu __instance)
|
||||
{
|
||||
if (!__instance.scrollBar)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
CurrentRole = null;
|
||||
CurrentRoleOptions = null;
|
||||
__instance.scrollBar.SetScrollBounds(__instance);
|
||||
}
|
||||
|
||||
private static void ValueChanged(OptionBehaviour obj)
|
||||
{
|
||||
var roleSetting = obj.Cast<RoleOptionSetting>();
|
||||
@@ -437,8 +457,7 @@ public static class RoleSettingMenuPatches
|
||||
roleSetting.Role.StringName,
|
||||
roleSetting.RoleMaxCount,
|
||||
roleSetting.RoleChance,
|
||||
roleSetting.Role.TeamType,
|
||||
false);
|
||||
roleSetting.Role.TeamType);
|
||||
|
||||
if (AmongUsClient.Instance.AmHost)
|
||||
{
|
||||
@@ -452,20 +471,17 @@ public static class RoleSettingMenuPatches
|
||||
{
|
||||
foreach (var optBehaviour in __instance.AdvancedRolesSettings.GetComponentsInChildren<OptionBehaviour>())
|
||||
{
|
||||
optBehaviour.gameObject.DeepDestroy(false);
|
||||
optBehaviour.gameObject.Destroy();
|
||||
}
|
||||
|
||||
CurrentRole = role;
|
||||
__instance.advancedSettingChildren.Clear();
|
||||
Utilities.Extensions.ClearGarbageCollector();
|
||||
|
||||
// TODO: create sub groups under the role settings.
|
||||
var filteredOptions = GameSettingMenuPatches.SelectedMod?.InternalOptionGroups
|
||||
var filteredOptions = MenuState.Instance.CurrentMod.InternalOptionGroups
|
||||
.Where(x => x.GroupVisible() && x.OptionableType == role.GetType())
|
||||
.SelectMany(x => x.Options)
|
||||
.ToList() ?? [];
|
||||
|
||||
CurrentRoleOptions = filteredOptions;
|
||||
.ToList();
|
||||
|
||||
foreach (var option in filteredOptions)
|
||||
{
|
||||
@@ -497,7 +513,7 @@ public static class RoleSettingMenuPatches
|
||||
newOpt.Initialize();
|
||||
}
|
||||
|
||||
__instance.scrollBar.ScrollToTop();
|
||||
CurrentRoleOptions = filteredOptions;
|
||||
}
|
||||
|
||||
private static void ChangeTab(RoleBehaviour role, RolesSettingsMenu __instance)
|
||||
@@ -508,8 +524,6 @@ public static class RoleSettingMenuPatches
|
||||
return;
|
||||
}
|
||||
|
||||
RolePositions[GameSettingMenuPatches.SelectedModIdx] = __instance.scrollBar.Inner.localPosition;
|
||||
|
||||
__instance.roleDescriptionText.text = customRole.RoleLongDescription;
|
||||
__instance.roleTitleText.text = role.GetRoleName();
|
||||
|
||||
@@ -564,9 +578,26 @@ public static class RoleSettingMenuPatches
|
||||
headerBtn.OnClick.AddListener(
|
||||
(UnityAction)(() =>
|
||||
{
|
||||
__instance.OpenChancesTab();
|
||||
GameSettingMenu.Instance.StartCoroutine(CoReturnToRoleSettings().WrapToIl2Cpp());
|
||||
}));
|
||||
headerBtn.SetButtonEnableState(true);
|
||||
|
||||
IEnumerator CoReturnToRoleSettings()
|
||||
{
|
||||
// set gameobjects
|
||||
__instance.RoleChancesSettings.SetActive(true);
|
||||
__instance.AdvancedRolesSettings.SetActive(false);
|
||||
|
||||
// wait a frame
|
||||
yield return null;
|
||||
|
||||
// re-enable page
|
||||
yield return CoQuotaTabPatch(__instance);
|
||||
|
||||
// set controller selected button
|
||||
__instance.AllButton.SelectButton(true);
|
||||
__instance.currentTabButton = __instance.AllButton;
|
||||
}
|
||||
}
|
||||
|
||||
var bg = __instance.AdvancedRolesSettings.transform.Find("Background");
|
||||
@@ -591,6 +622,8 @@ public static class RoleSettingMenuPatches
|
||||
|
||||
__instance.RoleChancesSettings.SetActive(false);
|
||||
__instance.AdvancedRolesSettings.SetActive(true);
|
||||
__instance.SetScrollBounds(true);
|
||||
__instance.scrollBar.ScrollToTop();
|
||||
__instance.RefreshChildren();
|
||||
}
|
||||
|
||||
@@ -642,14 +675,13 @@ public static class RoleSettingMenuPatches
|
||||
rend.maskInteraction = SpriteMaskInteraction.VisibleInsideMask;
|
||||
}
|
||||
|
||||
if (GameSettingMenuPatches.SelectedMod is null ||
|
||||
GameSettingMenuPatches.SelectedMod.InternalOptionGroups
|
||||
if (MenuState.Instance.CurrentMod.InternalOptionGroups
|
||||
.Exists(x => x.GroupVisible() && x.OptionableType == role.GetType() && x.Options.Any(y => y.Visible())))
|
||||
{
|
||||
var newButton = Object.Instantiate(roleOptionSetting.buttons[0], roleOptionSetting.transform);
|
||||
newButton.name = "ConfigButton";
|
||||
newButton.transform.localPosition = new Vector3(0.4473f, -0.3f, -2f);
|
||||
newButton.transform.FindChild("Text_TMP").gameObject.DeepDestroy();
|
||||
newButton.transform.FindChild("Text_TMP").gameObject.Destroy();
|
||||
newButton.activeSprites.Destroy();
|
||||
|
||||
var btnRend = newButton.transform.FindChild("ButtonSprite").GetComponent<SpriteRenderer>();
|
||||
@@ -675,7 +707,7 @@ public static class RoleSettingMenuPatches
|
||||
roleOptionSetting.ChancePlusBtn.gameObject.SetActive(false);
|
||||
}
|
||||
|
||||
if (index < GameSettingMenuPatches.SelectedMod?.InternalRoles.Count - 1)
|
||||
if (index < MenuState.Instance.CurrentMod.InternalRoles.Count - 1)
|
||||
{
|
||||
ScrollerNum -= 0.43f;
|
||||
}
|
||||
|
||||
@@ -8,7 +8,6 @@ using MiraAPI.Hud;
|
||||
using MiraAPI.Modifiers;
|
||||
using MiraAPI.Utilities;
|
||||
using MiraAPI.Voting;
|
||||
using Reactor.Utilities;
|
||||
using Reactor.Utilities.Extensions;
|
||||
|
||||
namespace MiraAPI.Patches;
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Linq;
|
||||
using AmongUs.GameOptions;
|
||||
using HarmonyLib;
|
||||
using MiraAPI.Roles;
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
using HarmonyLib;
|
||||
using InnerNet;
|
||||
using MiraAPI.Roles;
|
||||
using MiraAPI.Utilities;
|
||||
using Reactor.Utilities.Extensions;
|
||||
using UnityEngine;
|
||||
|
||||
namespace MiraAPI.Patches.Roles;
|
||||
|
||||
@@ -73,7 +71,7 @@ public static class HudManagerPatches
|
||||
}
|
||||
else if (RoleTab != null)
|
||||
{
|
||||
RoleTab.gameObject.DeepDestroy();
|
||||
RoleTab.gameObject.Destroy();
|
||||
RoleTab = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
using System.Linq;
|
||||
using AmongUs.GameOptions;
|
||||
using HarmonyLib;
|
||||
using InnerNet;
|
||||
using MiraAPI.Events;
|
||||
using MiraAPI.Events.Vanilla.Gameplay;
|
||||
using MiraAPI.Modifiers;
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
using HarmonyLib;
|
||||
using Il2CppSystem.Collections.Generic;
|
||||
using MiraAPI.Roles;
|
||||
using Reactor.Utilities;
|
||||
|
||||
namespace MiraAPI.Patches.Roles;
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
using System.Linq;
|
||||
using HarmonyLib;
|
||||
using Reactor.Utilities;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
using UnityEngine.SceneManagement;
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
using HarmonyLib;
|
||||
using MiraAPI.Utilities.Assets;
|
||||
using TMPro;
|
||||
|
||||
namespace MiraAPI.Patches;
|
||||
[HarmonyPatch]
|
||||
public static class TmpAwakePatch
|
||||
{
|
||||
[HarmonyPatch(typeof(TextMeshPro), nameof(TextMeshPro.Awake))]
|
||||
[HarmonyPostfix]
|
||||
public static void TmpAwakePostfix(TextMeshPro __instance)
|
||||
{
|
||||
if (!TmpSpriteUtils.AssetHolder || __instance.m_spriteAsset == TmpSpriteUtils.AssetHolder)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!__instance.m_spriteAsset)
|
||||
{
|
||||
__instance.m_spriteAsset = TmpSpriteUtils.AssetHolder;
|
||||
__instance.UpdateMeshPadding();
|
||||
return;
|
||||
}
|
||||
__instance.m_spriteAsset.fallbackSpriteAssets.Add(TmpSpriteUtils.AssetHolder);
|
||||
__instance.UpdateMeshPadding();
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,6 @@ using MiraAPI.Events;
|
||||
using MiraAPI.Events.Vanilla.Meeting.Voting;
|
||||
using MiraAPI.Utilities;
|
||||
using MiraAPI.Voting;
|
||||
using Reactor.Utilities;
|
||||
using Reactor.Utilities.Extensions;
|
||||
using UnityEngine;
|
||||
|
||||
|
||||
@@ -208,13 +208,6 @@ internal static class MeetingHudPatches
|
||||
public static bool PopulateResultsPatch(MeetingHud __instance, ref Il2CppStructArray<MeetingHud.VoterState> states)
|
||||
{
|
||||
var votes = states.Select(x=> new CustomVote(x.VoterId, x.VotedForId)).ToList();
|
||||
var @event = new PopulateResultsEvent(votes);
|
||||
MiraEventManager.InvokeEvent(@event);
|
||||
|
||||
if (@event.IsCancelled)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
VotingUtils.HandlePopulateResults(votes);
|
||||
return false;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using BepInEx.Configuration;
|
||||
using System.Linq;
|
||||
using BepInEx.Configuration;
|
||||
|
||||
namespace MiraAPI.PluginLoading;
|
||||
|
||||
@@ -7,11 +8,25 @@ namespace MiraAPI.PluginLoading;
|
||||
/// </summary>
|
||||
public interface IMiraPlugin
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether to display the plugin in the options menu.
|
||||
/// </summary>
|
||||
public virtual bool DisplayOnOptionsMenu => true;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the name to display on the options menu.
|
||||
/// </summary>
|
||||
string OptionsTitleText { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the abbreviated name to display for other mods to pick up.
|
||||
/// </summary>
|
||||
/// <returns>The <see cref="string"/> text for the plugin.</returns>
|
||||
public virtual string GetAbbreviatedModName()
|
||||
{
|
||||
return new(OptionsTitleText.Where(c => !char.IsLower(c) && !char.IsWhiteSpace(c)).ToArray());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the name for the first custom category in the game options menu, if any.
|
||||
/// </summary>
|
||||
|
||||
@@ -5,7 +5,6 @@ using BepInEx.Configuration;
|
||||
using MiraAPI.GameModes;
|
||||
using MiraAPI.GameOptions;
|
||||
using MiraAPI.Hud;
|
||||
using MiraAPI.LocalSettings;
|
||||
using MiraAPI.Modifiers;
|
||||
using MiraAPI.Presets;
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ using MiraAPI.Keybinds;
|
||||
using MiraAPI.LocalSettings;
|
||||
using MiraAPI.LocalSettings.Attributes;
|
||||
using MiraAPI.Modifiers;
|
||||
using MiraAPI.Patches.Options;
|
||||
using MiraAPI.Presets;
|
||||
using MiraAPI.Roles;
|
||||
using MiraAPI.Utilities;
|
||||
@@ -33,6 +34,7 @@ public sealed class MiraPluginManager
|
||||
private readonly Dictionary<Assembly, MiraPluginInfo> _registeredPlugins = [];
|
||||
|
||||
internal MiraPluginInfo[] RegisteredPlugins { get; private set; } = null!;
|
||||
internal MiraPluginInfo[] RegisteredPluginsWithOptions { get; private set; } = null!;
|
||||
|
||||
internal Dictionary<MiraPluginInfo, List<Type>> QueuedRoleRegistrations { get; } = [];
|
||||
internal static MiraPluginManager Instance { get; private set; } = new();
|
||||
@@ -141,6 +143,7 @@ public sealed class MiraPluginManager
|
||||
|
||||
// Cache all the registered plugins into an array for easy access
|
||||
RegisteredPlugins = [.. _registeredPlugins.Values];
|
||||
RegisteredPluginsWithOptions = [.. RegisteredPlugins.Where(m => m.MiraPlugin.DisplayOnOptionsMenu)];
|
||||
|
||||
ModifierManager.Modifiers = new ReadOnlyCollection<BaseModifier>(ModifierManager.InternalModifiers);
|
||||
};
|
||||
|
||||
@@ -4,8 +4,7 @@ using System.Linq;
|
||||
using BepInEx.Configuration;
|
||||
using MiraAPI.PluginLoading;
|
||||
using MiraAPI.Roles;
|
||||
using MiraAPI.Utilities;
|
||||
using Reactor.Utilities;
|
||||
using Reactor.Utilities.Extensions;
|
||||
using UnityEngine;
|
||||
|
||||
namespace MiraAPI.Presets;
|
||||
@@ -62,7 +61,7 @@ public static class PresetManager
|
||||
{
|
||||
if (btn != null)
|
||||
{
|
||||
btn.DeepDestroy();
|
||||
btn.Destroy();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ public class SavePresetPopup(nint cppPtr) : Minigame(cppPtr)
|
||||
// Cleanup holder object
|
||||
public void OnDestroy()
|
||||
{
|
||||
transform.parent.gameObject.DeepDestroy();
|
||||
transform.parent.gameObject.Destroy();
|
||||
}
|
||||
|
||||
public override void Close()
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 96 B |
@@ -3,6 +3,7 @@ using System;
|
||||
using Il2CppInterop.Runtime.Attributes;
|
||||
using MiraAPI.Patches.Freeplay;
|
||||
using MiraAPI.Utilities.Assets;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
namespace MiraAPI.Roles;
|
||||
|
||||
@@ -87,6 +88,12 @@ public record struct CustomRoleConfiguration
|
||||
[HideFromIl2Cpp]
|
||||
public LoadableAsset<Sprite>? Icon { get; set; } = null;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the <see cref="TMP_SpriteAsset"/> for the Role Icon.
|
||||
/// </summary>
|
||||
[HideFromIl2Cpp]
|
||||
public TMP_SpriteAsset IconTmp { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the Intro sound for the Role.
|
||||
/// </summary>
|
||||
|
||||
@@ -11,7 +11,6 @@ using MiraAPI.Utilities;
|
||||
using MiraAPI.Utilities.Assets;
|
||||
using Reactor.Localization.Utilities;
|
||||
using Reactor.Networking.Rpc;
|
||||
using Reactor.Utilities;
|
||||
using Reactor.Utilities.Extensions;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
@@ -142,7 +141,11 @@ public static class CustomRoleManager
|
||||
roleBehaviour.CanVent = customRole.Configuration.CanUseVent || customRole.Configuration.GetsVentData;
|
||||
roleBehaviour.DefaultGhostRole = customRole.Configuration.GhostRole;
|
||||
roleBehaviour.MaxCount = customRole.Configuration.MaxRoleCount;
|
||||
roleBehaviour.RoleScreenshot = customRole.Configuration.OptionsScreenshot?.LoadAsset();
|
||||
roleBehaviour.RoleScreenshot = Sprite.Create(
|
||||
customRole.Configuration.OptionsScreenshot?.LoadAsset().texture,
|
||||
new Rect(0, 0, 370, 230),
|
||||
Vector2.one / 2,
|
||||
100);
|
||||
|
||||
_emptySettings ??= new(0);
|
||||
_emptyKillAnimations ??= new(0);
|
||||
|
||||
@@ -4,7 +4,6 @@ using BepInEx.Configuration;
|
||||
using MiraAPI.GameOptions;
|
||||
using MiraAPI.Modifiers;
|
||||
using MiraAPI.PluginLoading;
|
||||
using Reactor.Utilities;
|
||||
using UnityEngine;
|
||||
|
||||
namespace MiraAPI.Roles;
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using Reactor.Utilities;
|
||||
using UnityEngine.AddressableAssets;
|
||||
|
||||
namespace MiraAPI.Utilities.Assets;
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using Reactor.Utilities;
|
||||
using UnityEngine.AddressableAssets;
|
||||
|
||||
namespace MiraAPI.Utilities.Assets;
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
namespace MiraAPI.Utilities.Assets;
|
||||
using Reactor.Utilities.Extensions;
|
||||
|
||||
namespace MiraAPI.Utilities.Assets;
|
||||
|
||||
/// <summary>
|
||||
/// An abstract class that provides a simple pattern for loading assets.
|
||||
@@ -18,4 +20,20 @@ public abstract class LoadableAsset<T> where T : UnityEngine.Object
|
||||
/// </summary>
|
||||
/// <returns>The loaded asset.</returns>
|
||||
public abstract T LoadAsset();
|
||||
|
||||
/// <summary>
|
||||
/// Unloads an asset.
|
||||
/// </summary>
|
||||
/// <returns>True if the asset was unloaded, false otherwise.</returns>
|
||||
public virtual bool UnloadAsset()
|
||||
{
|
||||
if (LoadedAsset == null || !LoadedAsset)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
LoadedAsset.DestroyImmediate();
|
||||
LoadedAsset = null;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -134,4 +134,6 @@ public static class MiraAssets
|
||||
/// Gets the sprite used for timed modifier file in TaskAdderGame.
|
||||
/// </summary>
|
||||
public static LoadableResourceAsset TimedModifierFile { get; } = new("MiraAPI.Resources.TimedModifierFile.png");
|
||||
|
||||
internal static LoadableResourceAsset BlankSprite { get; } = new("MiraAPI.Resources.BlankSprite.png");
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
using System.Collections.Generic;
|
||||
using Reactor.Utilities.Extensions;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
|
||||
namespace MiraAPI.Utilities.Assets;
|
||||
public static class TmpSpriteUtils
|
||||
{
|
||||
private static Shader _spriteShader;
|
||||
private static Dictionary<string, TMP_SpriteAsset> LoadedSprites = [];
|
||||
public static TMP_SpriteAsset AssetHolder;
|
||||
public static TMP_SpriteAsset CreateSpriteAsset(Sprite sprite, string assetName, float scale = 1)
|
||||
{
|
||||
return CreateSpriteAsset(sprite.texture, sprite.rect, assetName, scale);
|
||||
}
|
||||
public static TMP_SpriteAsset CreateSpriteAsset(Texture2D sourceTexture, Rect rect, string assetName, float scale = 1)
|
||||
{
|
||||
if (LoadedSprites.TryGetValue(assetName, out var existingAsset))
|
||||
{
|
||||
return existingAsset;
|
||||
}
|
||||
|
||||
if (!AssetHolder)
|
||||
{
|
||||
AssetHolder = ScriptableObject.CreateInstance<TMP_SpriteAsset>();
|
||||
AssetHolder.DontUnload().DontDestroy();
|
||||
AssetHolder.fallbackSpriteAssets = new();
|
||||
}
|
||||
TMP_SpriteAsset spriteAsset = ScriptableObject.CreateInstance<TMP_SpriteAsset>();
|
||||
spriteAsset.name = assetName;
|
||||
spriteAsset.spriteSheet = sourceTexture;
|
||||
|
||||
if (!_spriteShader)
|
||||
{
|
||||
_spriteShader = Shader.Find("TextMeshPro/Sprite");
|
||||
}
|
||||
|
||||
var material = new Material(_spriteShader)
|
||||
{
|
||||
name = assetName + " Material",
|
||||
};
|
||||
material.SetTexture(ShaderUtilities.ID_MainTex, sourceTexture);
|
||||
// TODO: Using these values, the icons will NOT clip through chatboxes. However, this breaks quite literally every other tmp text that isn't masked. Please fix this if a good solution is found.
|
||||
/*material.SetFloat(ShaderUtilities.ID_StencilComp, 4);
|
||||
material.SetFloat(ShaderUtilities.ID_StencilID, 1);*/
|
||||
material.SetFloat(ShaderUtilities.ID_StencilComp, 0);
|
||||
material.SetFloat(ShaderUtilities.ID_StencilID, 0);
|
||||
material.SetFloat(ShaderUtilities.ID_StencilOp, 0);
|
||||
material.SetFloat(ShaderUtilities.ID_StencilWriteMask, 255);
|
||||
material.SetFloat(ShaderUtilities.ID_StencilReadMask, 255);
|
||||
material.SetFloat(ShaderUtilities.ShaderTag_CullMode, 0);
|
||||
spriteAsset.material = material;
|
||||
|
||||
spriteAsset.spriteInfoList = new Il2CppSystem.Collections.Generic.List<TMP_Sprite>();
|
||||
|
||||
AddSpriteToAsset(spriteAsset, rect, assetName, scale);
|
||||
|
||||
spriteAsset.DontUnload().DontDestroy();
|
||||
spriteAsset.UpdateLookupTables();
|
||||
spriteAsset.fallbackSpriteAssets = new();
|
||||
AssetHolder.fallbackSpriteAssets.Add(spriteAsset);
|
||||
AssetHolder.UpdateLookupTables();
|
||||
|
||||
LoadedSprites.Add(assetName, spriteAsset);
|
||||
return spriteAsset;
|
||||
}
|
||||
|
||||
private static void AddSpriteToAsset(TMP_SpriteAsset spriteAsset, Rect rect, string spriteName, float scale)
|
||||
{
|
||||
TMP_Sprite newSprite = new TMP_Sprite
|
||||
{
|
||||
name = spriteName,
|
||||
hashCode = TMP_TextUtilities.GetSimpleHashCode(spriteName),
|
||||
x = 0,
|
||||
y = 0,
|
||||
width = rect.width,
|
||||
height = rect.height,
|
||||
xOffset = -(rect.width / 3) + (scale - 1) * (rect.width / 2),
|
||||
yOffset = rect.height / 1.25f,
|
||||
xAdvance = rect.width,
|
||||
scale = scale,
|
||||
};
|
||||
|
||||
spriteAsset.spriteInfoList.Add(newSprite);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
@@ -8,10 +9,8 @@ using System.Text.RegularExpressions;
|
||||
using HarmonyLib;
|
||||
using MiraAPI.GameOptions;
|
||||
using MiraAPI.Networking;
|
||||
using MiraAPI.Patches.Menu;
|
||||
using MiraAPI.Roles;
|
||||
using MiraAPI.Voting;
|
||||
using Reactor.Utilities;
|
||||
using Reactor.Utilities.Extensions;
|
||||
using Rewired;
|
||||
using Rewired.Data;
|
||||
@@ -56,7 +55,7 @@ public static class Extensions
|
||||
bool isComplete;
|
||||
if (self.amClosing == Minigame.CloseState.Closing)
|
||||
{
|
||||
self.gameObject.DeepDestroy();
|
||||
self.gameObject.Destroy();
|
||||
return;
|
||||
}
|
||||
if (self.CloseSound && Constants.ShouldPlaySfx())
|
||||
@@ -229,13 +228,44 @@ public static class Extensions
|
||||
/// <param name="clearGc">Whether to run the garbage collector immediately.</param>
|
||||
public static void DeepDestroy(this GameObject obj, bool clearGc = true)
|
||||
{
|
||||
if (MainMenuManagerPatches.NeedsDeepDestroy)
|
||||
obj.Destroy();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Runs a given action in a loop with a frame budget based on the current target frame rate. Once the budget is hit, the loop continues on the next frame.
|
||||
/// </summary>
|
||||
/// <param name="collection">The collection to iterate over.</param>
|
||||
/// <param name="action">The action to perform on each item.</param>
|
||||
/// <typeparam name="T">The type of the collection.</typeparam>
|
||||
/// <returns>Coroutine.</returns>
|
||||
public static IEnumerator CoLoopWithBudget<T>(this IEnumerable<T> collection, Action<T> action)
|
||||
{
|
||||
var fps = Application.targetFrameRate > 0 ? Application.targetFrameRate : 60;
|
||||
long budget = 1 / (fps * 2); // default is half of current frame time.
|
||||
yield return collection.CoLoopWithBudget(budget, action);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Runs a given action in a loop with a given frame budget. Once the budget is hit, the loop continues on the next frame.
|
||||
/// </summary>
|
||||
/// <param name="collection">The collection to iterate over.</param>
|
||||
/// <param name="frameBudget">The # of milliseconds to spend in the loop.</param>
|
||||
/// <param name="action">The action to perform on each item.</param>
|
||||
/// <typeparam name="T">The type of the collection.</typeparam>
|
||||
/// <returns>Coroutine.</returns>
|
||||
public static IEnumerator CoLoopWithBudget<T>(this IEnumerable<T> collection, long frameBudget, Action<T> action)
|
||||
{
|
||||
var timer = new Stopwatch();
|
||||
timer.Start();
|
||||
foreach (var item in collection)
|
||||
{
|
||||
Coroutines.Start(Nuke(obj, clearGc));
|
||||
}
|
||||
else
|
||||
{
|
||||
obj?.Destroy();
|
||||
action(item);
|
||||
|
||||
if (timer.ElapsedMilliseconds > frameBudget)
|
||||
{
|
||||
timer.Restart();
|
||||
yield return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -324,10 +354,6 @@ public static class Extensions
|
||||
|
||||
UnityEngine.Object.Destroy(go);
|
||||
yield return null;
|
||||
if (clearGc)
|
||||
{
|
||||
yield return CoFreeResources();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -335,16 +361,9 @@ public static class Extensions
|
||||
/// </summary>
|
||||
public static void ClearGarbageCollector()
|
||||
{
|
||||
Coroutines.Start(CoFreeResources());
|
||||
}
|
||||
|
||||
private static IEnumerator CoFreeResources()
|
||||
{
|
||||
yield return Resources.UnloadUnusedAssets();
|
||||
|
||||
GC.Collect(0, GCCollectionMode.Forced, blocking: true);
|
||||
GC.WaitForPendingFinalizers();
|
||||
GC.Collect(0, GCCollectionMode.Forced, blocking: true);
|
||||
Resources.UnloadUnusedAssets();
|
||||
Il2CppSystem.GC.Collect();
|
||||
GC.Collect();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -2,12 +2,10 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using AmongUs.GameOptions;
|
||||
using HarmonyLib;
|
||||
using Il2CppInterop.Runtime.InteropTypes.Arrays;
|
||||
using MiraAPI.Roles;
|
||||
using MiraAPI.Utilities.Assets;
|
||||
using Reactor.Utilities;
|
||||
using Rewired;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
|
||||
@@ -5,7 +5,6 @@ using MiraAPI.Events.Vanilla.Meeting.Voting;
|
||||
using MiraAPI.Networking;
|
||||
using MiraAPI.Utilities;
|
||||
using Reactor.Networking.Attributes;
|
||||
using Reactor.Utilities;
|
||||
|
||||
namespace MiraAPI.Voting;
|
||||
|
||||
@@ -207,6 +206,9 @@ public static class VotingUtils
|
||||
return;
|
||||
}
|
||||
|
||||
// If modified, these will visually change.
|
||||
votes = @event.Votes;
|
||||
|
||||
MeetingHud.Instance.TitleText.text =
|
||||
TranslationController.Instance.GetString(
|
||||
StringNames.MeetingVotingResults,
|
||||
|
||||
Reference in new issue
Block a user