mirror of
https://github.com/All-Of-Us-Mods/MiraAPI.git
synced 2026-10-20 11:39:45 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
575f7a78a1 | ||
|
|
bf7edb30ab | ||
|
|
b4527014b7 | ||
|
|
277391ef1c | ||
|
|
6b3038f397 | ||
|
|
4e1db039a0 | ||
|
|
62bee24789 | ||
|
|
2156c80467 | ||
|
|
0ff60071c2 | ||
|
|
de2f3f0d95 | ||
|
|
05f132c506 | ||
|
|
ab54c44434 | ||
|
|
bf652b68c3 | ||
|
|
00377c7926 | ||
|
|
55555604f3 | ||
|
|
de77a9fa92 | ||
|
|
eba2a037d3 | ||
|
|
bc7f772de9 | ||
|
|
f43191c4f2 |
No files matched your search
@@ -6,7 +6,10 @@ namespace MiraAPI.Example;
|
||||
[RegisterCustomColors]
|
||||
public static class ExampleColors
|
||||
{
|
||||
public static CustomColor Cerulean { get; } = new("Cerulean", new Color(0.0f, 0.48f, 0.65f));
|
||||
public static CustomColor Cerulean { get; } = new("Cerulean", new Color(0.0f, 0.48f, 0.65f))
|
||||
{
|
||||
ColorBrightness = CustomColorBrightness.Lighter,
|
||||
};
|
||||
|
||||
public static CustomColor Rose { get; } = new("Rose", new Color(0.98f, 0.26f, 0.62f));
|
||||
|
||||
|
||||
@@ -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 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);
|
||||
|
||||
public ModdedToggleOption ToggleOpt2 { get; } = new("Toggle Option 2", false)
|
||||
|
||||
@@ -13,19 +13,24 @@ namespace MiraAPI.Colors;
|
||||
public sealed class CustomColor(StringNames name, Color32 mainColor, Color32 shadowColor)
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the main color.
|
||||
/// Gets or sets the main color.
|
||||
/// </summary>
|
||||
public Color32 MainColor { get; } = mainColor;
|
||||
public Color32 MainColor { get; set; } = mainColor;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the shadow color.
|
||||
/// Gets or sets the shadow color.
|
||||
/// </summary>
|
||||
public Color32 ShadowColor { get; } = shadowColor;
|
||||
public Color32 ShadowColor { get; set; } = shadowColor;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the name of the color.
|
||||
/// Gets or sets the name of the color.
|
||||
/// </summary>
|
||||
public StringNames Name { get; } = name;
|
||||
public StringNames Name { get; set; } = name;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets whether the color is lighter or darker. Can be used to help with colorblind stuff.
|
||||
/// </summary>
|
||||
public CustomColorBrightness ColorBrightness { get; set; } = CustomColorBrightness.Darker;
|
||||
|
||||
/// <inheritdoc />
|
||||
public CustomColor(StringNames name, Color32 mainColor) : this(name, mainColor, mainColor.GetShadowColor(60))
|
||||
@@ -42,3 +47,19 @@ public sealed class CustomColor(StringNames name, Color32 mainColor, Color32 sha
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Can be used to help with colorblind stuff.
|
||||
/// </summary>
|
||||
public enum CustomColorBrightness
|
||||
{
|
||||
/// <summary>
|
||||
/// A lighter color.
|
||||
/// </summary>
|
||||
Lighter,
|
||||
|
||||
/// <summary>
|
||||
/// A darker color.
|
||||
/// </summary>
|
||||
Darker,
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace MiraAPI.Game;
|
||||
|
||||
public enum PlayerContext
|
||||
{
|
||||
|
||||
}
|
||||
@@ -62,9 +62,10 @@ public interface IModdedOption
|
||||
/// <param name="toggleOpt">The ToggleOption template.</param>
|
||||
/// <param name="numberOpt">The NumberOption template.</param>
|
||||
/// <param name="stringOpt">The StringOption template.</param>
|
||||
/// <param name="playerOpt">The PlayerOption template.</param>
|
||||
/// <param name="container">>The Transform container for the option.</param>
|
||||
/// <returns>>The created OptionBehaviour object.</returns>
|
||||
OptionBehaviour CreateOption(ToggleOption toggleOpt, NumberOption numberOpt, StringOption stringOpt, Transform container);
|
||||
OptionBehaviour CreateOption(ToggleOption toggleOpt, NumberOption numberOpt, StringOption stringOpt, PlayerOption playerOpt, Transform container);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the value as a float.
|
||||
|
||||
@@ -6,6 +6,7 @@ using System.Reflection;
|
||||
using BepInEx.Configuration;
|
||||
using HarmonyLib;
|
||||
using MiraAPI.GameOptions.Attributes;
|
||||
using MiraAPI.GameOptions.OptionTypes;
|
||||
using MiraAPI.Networking;
|
||||
using MiraAPI.PluginLoading;
|
||||
using MiraAPI.Utilities;
|
||||
@@ -22,6 +23,7 @@ public static class ModdedOptionsManager
|
||||
private static readonly Dictionary<PropertyInfo, ModdedOptionAttribute> OptionAttributes = [];
|
||||
private static readonly Dictionary<Type, AbstractOptionGroup> TypeToGroup = [];
|
||||
|
||||
internal static readonly Dictionary<OptionBehaviour, ModdedPlayerOption> CreatedPlayerOptions = [];
|
||||
internal static readonly Dictionary<uint, IModdedOption> ModdedOptions = [];
|
||||
internal static readonly List<AbstractOptionGroup> Groups = [];
|
||||
|
||||
|
||||
@@ -44,7 +44,7 @@ public class ModdedEnumOption : ModdedOption<int>
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override OptionBehaviour CreateOption(ToggleOption toggleOpt, NumberOption numberOpt, StringOption stringOpt, Transform container)
|
||||
public override OptionBehaviour CreateOption(ToggleOption toggleOpt, NumberOption numberOpt, StringOption stringOpt, PlayerOption playerOpt, Transform container)
|
||||
{
|
||||
var stringOption = Object.Instantiate(stringOpt, container);
|
||||
|
||||
@@ -135,7 +135,7 @@ public class ModdedEnumOption<T> : ModdedOption<T> where T : Enum
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override OptionBehaviour CreateOption(ToggleOption toggleOpt, NumberOption numberOpt, StringOption stringOpt, Transform container)
|
||||
public override OptionBehaviour CreateOption(ToggleOption toggleOpt, NumberOption numberOpt, StringOption stringOpt, PlayerOption playerOpt, Transform container)
|
||||
{
|
||||
var stringOption = Object.Instantiate(stringOpt, container);
|
||||
|
||||
|
||||
@@ -93,6 +93,7 @@ public class ModdedNumberOption : ModdedOption<float>
|
||||
ToggleOption toggleOpt,
|
||||
NumberOption numberOpt,
|
||||
StringOption stringOpt,
|
||||
PlayerOption playerOpt,
|
||||
Transform container)
|
||||
{
|
||||
var numberOption = Object.Instantiate(numberOpt, Vector3.zero, Quaternion.identity, container);
|
||||
|
||||
@@ -37,6 +37,7 @@ public abstract class ModdedOption<T> : IModdedOption
|
||||
{
|
||||
if (_parentMod != null || value == null) return;
|
||||
_parentMod = value;
|
||||
|
||||
var entry = _parentMod.GetConfigFile().Bind(ConfigDefinition, DefaultValue);
|
||||
Value = entry.Value;
|
||||
}
|
||||
@@ -177,6 +178,7 @@ public abstract class ModdedOption<T> : IModdedOption
|
||||
ToggleOption toggleOpt,
|
||||
NumberOption numberOpt,
|
||||
StringOption stringOpt,
|
||||
PlayerOption playerOpt,
|
||||
Transform container);
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -0,0 +1,138 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Il2CppSystem.Collections.Generic;
|
||||
using MiraAPI.Networking;
|
||||
using MiraAPI.Utilities;
|
||||
using UnityEngine;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
namespace MiraAPI.GameOptions.OptionTypes;
|
||||
|
||||
/// <summary>
|
||||
/// An option for selecting an ingame player. It returns an index of the values list, NOT A PLAYER ID. To get a player out of this, index the Values list.
|
||||
/// </summary>
|
||||
public class ModdedPlayerOption : ModdedOption<int>
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the included players.
|
||||
/// </summary>
|
||||
public List<NetworkedPlayerInfo> Values { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a filter for the players included in the option.
|
||||
/// </summary>
|
||||
public Func<NetworkedPlayerInfo, bool>? PlayerFilter { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether the option includes a "None" option. If None is selected, value will return -1.
|
||||
/// </summary>
|
||||
public bool AllowNone { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ModdedPlayerOption"/> class.
|
||||
/// </summary>
|
||||
/// <param name="title">The title of the option.</param>
|
||||
/// <param name="allowNone">Whether the option includes a none option. If None is selected, value will return -1.</param>
|
||||
public ModdedPlayerOption(string title, bool allowNone = true) : base(title, allowNone ? -1 : 0, false)
|
||||
{
|
||||
Data = ScriptableObject.CreateInstance<PlayerSelectionGameSetting>();
|
||||
var data = (PlayerSelectionGameSetting)Data;
|
||||
|
||||
data.Title = StringName;
|
||||
data.Type = global::OptionTypes.Player;
|
||||
|
||||
Values = new List<NetworkedPlayerInfo>();
|
||||
AllowNone = allowNone;
|
||||
Value = DefaultValue;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override OptionBehaviour CreateOption(
|
||||
ToggleOption toggleOpt,
|
||||
NumberOption numberOpt,
|
||||
StringOption stringOpt,
|
||||
PlayerOption playerOpt,
|
||||
Transform container)
|
||||
{
|
||||
var playerOption = Object.Instantiate(playerOpt, container);
|
||||
|
||||
var filteredList = GetFilteredPlayers();
|
||||
Values = filteredList.ToIl2CppList();
|
||||
|
||||
playerOption.SetUpFromData(Data, 20);
|
||||
playerOption.OnValueChanged = (Il2CppSystem.Action<OptionBehaviour>)ValueChanged;
|
||||
|
||||
playerOption.Title = StringName;
|
||||
playerOption.TitleText.text = TranslationController.Instance.GetString(StringName);
|
||||
playerOption.Values = Values;
|
||||
playerOption.Value = Value;
|
||||
playerOption.playerIndex = filteredList.FindIndex(p => p.PlayerId == Value);
|
||||
|
||||
OptionBehaviour = playerOption;
|
||||
ModdedOptionsManager.CreatedPlayerOptions.TryAdd(playerOption, this);
|
||||
|
||||
playerOption.SetValueText();
|
||||
playerOption.AdjustButtonsActiveState();
|
||||
|
||||
return playerOption;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a player ran through the filter.
|
||||
/// </summary>
|
||||
/// <returns>A list of filtered players.</returns>
|
||||
public System.Collections.Generic.List<NetworkedPlayerInfo> GetFilteredPlayers()
|
||||
{
|
||||
return GameData.Instance.AllPlayers.ToArray()
|
||||
.Where(x => PlayerFilter?.Invoke(x) ?? true)
|
||||
.ToList();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a player from the value. If AllowNone is enabled and none is enabled this will return null.
|
||||
/// </summary>
|
||||
/// <returns>A player or null if chosen none.</returns>
|
||||
public NetworkedPlayerInfo? GetPlayerValue()
|
||||
{
|
||||
return Value < 0 ? null : Values[Value];
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override float GetFloatData()
|
||||
{
|
||||
return Value;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override NetData GetNetData()
|
||||
{
|
||||
return new NetData(Id, BitConverter.GetBytes(Value));
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void HandleNetData(byte[] data)
|
||||
{
|
||||
SetValue(BitConverter.ToInt32(data));
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override int GetValueFromOptionBehaviour(OptionBehaviour optionBehaviour)
|
||||
{
|
||||
return optionBehaviour.GetInt();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void OnValueChanged(int newValue)
|
||||
{
|
||||
HudManager.Instance.Notifier.AddSettingsChangeMessage(StringName, Data.GetValueString(newValue), false);
|
||||
if (!OptionBehaviour)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (OptionBehaviour is PlayerOption opt)
|
||||
{
|
||||
opt.Value = newValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -26,7 +26,7 @@ public class ModdedToggleOption : ModdedOption<bool>
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override OptionBehaviour CreateOption(ToggleOption toggleOpt, NumberOption numberOpt, StringOption stringOpt, Transform container)
|
||||
public override OptionBehaviour CreateOption(ToggleOption toggleOpt, NumberOption numberOpt, StringOption stringOpt, PlayerOption playerOpt, Transform container)
|
||||
{
|
||||
var toggleOption = Object.Instantiate(toggleOpt, Vector3.zero, Quaternion.identity, container);
|
||||
|
||||
|
||||
@@ -64,6 +64,11 @@ public abstract class BaseModifier : IOptionable
|
||||
/// </summary>
|
||||
public virtual bool ShowInFreeplay => false;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating the color that should be used for the modifier within freeplay.
|
||||
/// </summary>
|
||||
public virtual Color FreeplayFileColor => Color.gray;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the modifier is unique. If true, the player can only have one instance of this modifier.
|
||||
/// </summary>
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace MiraAPI.Modifiers;
|
||||
|
||||
public enum ModifierContext
|
||||
{
|
||||
|
||||
}
|
||||
@@ -5,6 +5,7 @@ using System.Runtime.Serialization;
|
||||
using MiraAPI.Modifiers.Types;
|
||||
using MiraAPI.PluginLoading;
|
||||
using MiraAPI.Roles;
|
||||
using MiraAPI.Utilities;
|
||||
using Reactor.Utilities;
|
||||
using Reactor.Utilities.Extensions;
|
||||
using Random = System.Random;
|
||||
@@ -21,6 +22,13 @@ public static class ModifierManager
|
||||
/// </summary>
|
||||
public static bool MiraAssignsModifiers { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the list of all registered modifiers.
|
||||
/// </summary>
|
||||
public static IReadOnlyList<BaseModifier> Modifiers { get; internal set; } = [];
|
||||
|
||||
internal static List<BaseModifier> InternalModifiers { get; } = [];
|
||||
|
||||
private static readonly Dictionary<uint, Type> IdToTypeModifierMap = [];
|
||||
private static readonly Dictionary<Type, uint> TypeToIdModifierMap = [];
|
||||
private static readonly Dictionary<int, List<uint>> PrioritiesToIdsMap = [];
|
||||
@@ -80,6 +88,7 @@ public static class ModifierManager
|
||||
}
|
||||
|
||||
info.InternalModifiers.Add(modifier);
|
||||
InternalModifiers.Add(modifier);
|
||||
|
||||
if (modifier is not GameModifier gameModifier)
|
||||
{
|
||||
@@ -117,6 +126,7 @@ public static class ModifierManager
|
||||
.Select(x => Activator.CreateInstance(x.Value) as GameModifier)
|
||||
.OfType<GameModifier>()
|
||||
.Where(x => x.GetAmountPerGame() > 0 && x.GetAssignmentChance() > 0)
|
||||
.Shuffle()
|
||||
.OrderByDescending(x => x.Priority())
|
||||
.ToArray();
|
||||
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
using HarmonyLib;
|
||||
using UnityEngine;
|
||||
|
||||
namespace MiraAPI.Patches;
|
||||
|
||||
#pragma warning disable SA1629
|
||||
/// <summary>
|
||||
/// Allows players to paste text into chat.
|
||||
/// Source: https://github.com/CallOfCreator/NewMod/blob/main/NewMod/Patches/ClipboardPatch.cs
|
||||
/// </summary>
|
||||
#pragma warning restore SA1629
|
||||
[HarmonyPatch(typeof(ChatController), nameof(ChatController.Update))]
|
||||
public static class ChatControllerPatch
|
||||
{
|
||||
public static void Prefix(ChatController __instance)
|
||||
{
|
||||
if (!HudManager.Instance.Chat.IsOpenOrOpening) return;
|
||||
|
||||
var ctrlPressed = Input.GetKey(KeyCode.LeftControl) || Input.GetKey(KeyCode.RightControl);
|
||||
|
||||
if (!ctrlPressed || !Input.GetKeyDown(KeyCode.V)) return;
|
||||
|
||||
var clipboard = GUIUtility.systemCopyBuffer;
|
||||
|
||||
if (string.IsNullOrWhiteSpace(clipboard)) return;
|
||||
clipboard = clipboard.Replace("<", string.Empty)
|
||||
.Replace(">", string.Empty)
|
||||
.Replace("\r", string.Empty);
|
||||
|
||||
if (!Input.GetKey(KeyCode.LeftShift) && !Input.GetKey(KeyCode.RightShift))
|
||||
clipboard = clipboard.Replace("\n", string.Empty);
|
||||
|
||||
__instance.freeChatField.textArea.SetText(__instance.freeChatField.textArea.text + clipboard);
|
||||
}
|
||||
}
|
||||
@@ -12,14 +12,16 @@ public static class CanUsePatches
|
||||
public static IEnumerable<MethodBase> TargetMethods()
|
||||
{
|
||||
yield return AccessTools.Method(typeof(Console), nameof(Console.CanUse));
|
||||
yield return AccessTools.Method(typeof(MapConsole), nameof(MapConsole.CanUse));
|
||||
yield return AccessTools.Method(typeof(SystemConsole), nameof(SystemConsole.CanUse));
|
||||
yield return AccessTools.Method(typeof(Ladder), nameof(Ladder.CanUse));
|
||||
yield return AccessTools.Method(typeof(PlatformConsole), nameof(PlatformConsole.CanUse));
|
||||
yield return AccessTools.Method(typeof(OpenDoorConsole), nameof(OpenDoorConsole.CanUse));
|
||||
yield return AccessTools.Method(typeof(DeconControl), nameof(DeconControl.CanUse));
|
||||
yield return AccessTools.Method(typeof(DoorConsole), nameof(DoorConsole.CanUse));
|
||||
yield return AccessTools.Method(typeof(Ladder), nameof(Ladder.CanUse));
|
||||
yield return AccessTools.Method(typeof(MapConsole), nameof(MapConsole.CanUse));
|
||||
yield return AccessTools.Method(typeof(OpenDoorConsole), nameof(OpenDoorConsole.CanUse));
|
||||
yield return AccessTools.Method(typeof(OptionsConsole), nameof(OptionsConsole.CanUse));
|
||||
yield return AccessTools.Method(typeof(PlatformConsole), nameof(PlatformConsole.CanUse));
|
||||
yield return AccessTools.Method(typeof(SystemConsole), nameof(SystemConsole.CanUse));
|
||||
yield return AccessTools.Method(typeof(ZiplineConsole), nameof(ZiplineConsole.CanUse));
|
||||
// vent is not necessary as it has its own patch
|
||||
}
|
||||
|
||||
[HarmonyPriority(Priority.Last)]
|
||||
|
||||
@@ -22,15 +22,4 @@ internal static class TaskAddButtonPatches
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[HarmonyPostfix]
|
||||
[HarmonyPatch(nameof(TaskAddButton.Role), MethodType.Setter)]
|
||||
public static void RoleGetterPatch(TaskAddButton __instance)
|
||||
{
|
||||
if (__instance.role is ICustomRole { Team: ModdedRoleTeams.Custom } customRole)
|
||||
{
|
||||
__instance.FileImage.color = customRole.IntroConfiguration?.IntroTeamColor ?? Color.gray;
|
||||
}
|
||||
__instance.RolloverHandler.OutColor = __instance.FileImage.color;
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,7 @@ using MiraAPI.Utilities;
|
||||
using MiraAPI.Utilities.Assets;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
using UnityEngine.UI;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
@@ -19,7 +20,6 @@ namespace MiraAPI.Patches.Freeplay;
|
||||
internal static class TaskAdderPatches
|
||||
{
|
||||
private static Scroller _scroller = null!;
|
||||
|
||||
[HarmonyPostfix]
|
||||
[HarmonyPatch(nameof(TaskAdderGame.Begin))]
|
||||
public static void AddRolesFolder(TaskAdderGame __instance)
|
||||
@@ -32,6 +32,11 @@ internal static class TaskAdderPatches
|
||||
_scroller.allowY = true;
|
||||
_scroller.Inner = inner.transform;
|
||||
|
||||
var scrollerHelper = __instance.TaskParent.gameObject.AddComponent<ManualScrollHelper>();
|
||||
scrollerHelper.scroller = _scroller;
|
||||
scrollerHelper.verticalAxis = RewiredConstsEnum.Action.TaskRVertical;
|
||||
scrollerHelper.scrollSpeed = 10f;
|
||||
|
||||
GameObject hitbox = new("Hitbox")
|
||||
{
|
||||
layer = 5,
|
||||
@@ -295,7 +300,7 @@ internal static class TaskAdderPatches
|
||||
|
||||
if (_scroller)
|
||||
{
|
||||
_scroller.CalculateAndSetYBounds(__instance.ActiveItems.Count, 6, 5, 1.4f);
|
||||
_scroller.CalculateAndSetYBounds(__instance.ActiveItems.Count, 6, 4.5f, 1.65f);
|
||||
_scroller.SetYBoundsMin(0.0f);
|
||||
_scroller.ScrollToTop();
|
||||
}
|
||||
@@ -332,7 +337,8 @@ internal static class TaskAdderPatches
|
||||
taskAddButton.SafePositionWorld = instance.SafePositionWorld;
|
||||
taskAddButton.Text.text = modifier.ModifierName;
|
||||
taskAddButton.Text.EnableMasking();
|
||||
|
||||
taskAddButton.FileImage.color = modifier.FreeplayFileColor;
|
||||
taskAddButton.RolloverHandler.OutColor = modifier.FreeplayFileColor;
|
||||
taskAddButton.Button.OnClick = new Button.ButtonClickedEvent();
|
||||
taskAddButton.Button.OnClick.AddListener((UnityEngine.Events.UnityAction)(() =>
|
||||
{
|
||||
@@ -384,6 +390,20 @@ internal static class TaskAdderPatches
|
||||
|
||||
instance.AddFileAsChildCustom(taskAddButton2, ref num, ref num2, ref num3);
|
||||
taskAddButton2.Role = roleBehaviour;
|
||||
if (roleBehaviour is ICustomRole custom)
|
||||
{
|
||||
var customColor = custom.IntroConfiguration?.IntroTeamColor ?? Color.gray;
|
||||
if (custom.Team is ModdedRoleTeams.Crewmate)
|
||||
{
|
||||
customColor = Palette.CrewmateBlue;
|
||||
}
|
||||
else if (custom.Team is ModdedRoleTeams.Impostor)
|
||||
{
|
||||
customColor = Palette.ImpostorRed;
|
||||
}
|
||||
taskAddButton2.FileImage.color = customColor;
|
||||
taskAddButton2.RolloverHandler.OutColor = customColor;
|
||||
}
|
||||
if (taskAddButton2.Button == null)
|
||||
{
|
||||
continue;
|
||||
|
||||
@@ -1,37 +1,25 @@
|
||||
using HarmonyLib;
|
||||
using MiraAPI.Hud;
|
||||
using Reactor.Utilities;
|
||||
|
||||
namespace MiraAPI.Patches.Hud;
|
||||
|
||||
/// <summary>
|
||||
/// Reset button patches.
|
||||
/// </summary>
|
||||
[HarmonyPatch]
|
||||
[HarmonyPatch(typeof(MeetingHud), nameof(MeetingHud.Start))]
|
||||
[HarmonyPatch(typeof(ExileController), nameof(ExileController.ReEnableGameplay))]
|
||||
public static class ButtonResetPatches
|
||||
{
|
||||
/// <summary>
|
||||
/// Resets the cooldown and effect of all custom buttons when the meeting starts.
|
||||
/// </summary>
|
||||
[HarmonyPostfix]
|
||||
[HarmonyPatch(typeof(MeetingHud), nameof(MeetingHud.Start))]
|
||||
public static void MeetingHudStartPostfix()
|
||||
public static void Postfix()
|
||||
{
|
||||
foreach (var customActionButton in CustomButtonManager.CustomButtons)
|
||||
{
|
||||
customActionButton.ResetCooldownAndOrEffect();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets the cooldown and effect of all custom buttons after the exile screen is closed.
|
||||
/// </summary>
|
||||
[HarmonyPostfix]
|
||||
[HarmonyPatch(typeof(ExileController), nameof(ExileController.ReEnableGameplay))]
|
||||
public static void ExileControllerReEnableGameplayPostfix()
|
||||
{
|
||||
foreach (var customActionButton in CustomButtonManager.CustomButtons)
|
||||
{
|
||||
customActionButton.ResetCooldownAndOrEffect();
|
||||
try
|
||||
{
|
||||
customActionButton.ResetCooldownAndOrEffect();
|
||||
}
|
||||
catch (System.Exception ex)
|
||||
{
|
||||
Logger<MiraApiPlugin>.Error($"Error resetting cooldown and effect for button {customActionButton.GetType().Name}: {ex}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
using HarmonyLib;
|
||||
using MiraAPI.Hud;
|
||||
using Reactor.Utilities;
|
||||
using Reactor.Utilities.Extensions;
|
||||
using UnityEngine;
|
||||
using Object = UnityEngine.Object;
|
||||
@@ -77,7 +78,14 @@ public static class HudManagerPatches
|
||||
continue;
|
||||
}
|
||||
|
||||
button.CreateButton(location);
|
||||
try
|
||||
{
|
||||
button.CreateButton(location);
|
||||
}
|
||||
catch (System.Exception e)
|
||||
{
|
||||
Logger<MiraApiPlugin>.Error($"Failed to create custom button {button.GetType().Name}: {e}");
|
||||
}
|
||||
}
|
||||
|
||||
gridArrange.Start();
|
||||
@@ -105,7 +113,14 @@ public static class HudManagerPatches
|
||||
|
||||
foreach (var button in CustomButtonManager.CustomButtons)
|
||||
{
|
||||
button.SetActive(isActive, role);
|
||||
try
|
||||
{
|
||||
button.SetActive(isActive, role);
|
||||
}
|
||||
catch (System.Exception e)
|
||||
{
|
||||
Logger<MiraApiPlugin>.Error($"Failed to set custom button {button.GetType().Name} active: {e}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -84,7 +84,7 @@ public static class HatsTabPatches
|
||||
text.gameObject.transform.localScale = Vector3.one;
|
||||
text.GetComponent<TextTranslatorTMP>().Destroy();
|
||||
text.EnableStencilMasking();
|
||||
text.text = $"{groupName}\nPress Ctrl or Tab to cycle pages";
|
||||
text.text = $"{groupName} ({currentPage + 1}/{sortedHats.Count})\nPress Ctrl or Tab to cycle pages";
|
||||
text.alignment = TextAlignmentOptions.Center;
|
||||
text.fontSize = 3f;
|
||||
text.fontSizeMax = 3f;
|
||||
@@ -114,7 +114,7 @@ public static class HatsTabPatches
|
||||
yield return null;
|
||||
}
|
||||
|
||||
__instance.scroller.ContentYBounds.max = -(__instance.YStart - (hatIndex + 1) / __instance.NumPerRow * __instance.YOffset) - 3f;
|
||||
__instance.SetScrollerBounds();
|
||||
yield return new WaitForSeconds(0.01f);
|
||||
}
|
||||
__instance.currentHatIsEquipped = true;
|
||||
|
||||
@@ -73,7 +73,7 @@ public static class NameplatesTabPatches
|
||||
text.gameObject.transform.localScale = Vector3.one;
|
||||
text.GetComponent<TextTranslatorTMP>().Destroy();
|
||||
text.EnableStencilMasking();
|
||||
text.text = $"{groupName}\nPress Ctrl or Tab to cycle pages";
|
||||
text.text = $"{groupName} ({currentPage + 1}/{SortedNameplates.Count})\nPress Ctrl or Tab to cycle pages";
|
||||
text.alignment = TextAlignmentOptions.Center;
|
||||
text.fontSize = 3f;
|
||||
text.fontSizeMax = 3f;
|
||||
@@ -91,7 +91,7 @@ public static class NameplatesTabPatches
|
||||
hatIndex += 1;
|
||||
}
|
||||
|
||||
__instance.scroller.ContentYBounds.max = -(__instance.YStart - (hatIndex + 1) / __instance.NumPerRow * __instance.YOffset) - 3f;
|
||||
__instance.SetScrollerBounds();
|
||||
__instance.currentNameplateIsEquipped = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -76,7 +76,7 @@ public static class SkinsTabPatches
|
||||
text.gameObject.transform.localScale = Vector3.one;
|
||||
text.GetComponent<TextTranslatorTMP>().Destroy();
|
||||
text.EnableStencilMasking();
|
||||
text.text = $"{groupName}\nPress Ctrl or Tab to cycle pages";
|
||||
text.text = $"{groupName} ({currentPage + 1}/{sortedSkins.Count})\nPress Ctrl or Tab to cycle pages";
|
||||
text.alignment = TextAlignmentOptions.Center;
|
||||
text.fontSize = 3f;
|
||||
text.fontSizeMax = 3f;
|
||||
@@ -94,7 +94,7 @@ public static class SkinsTabPatches
|
||||
hatIndex += 1;
|
||||
}
|
||||
|
||||
__instance.scroller.ContentYBounds.max = -(__instance.YStart - (hatIndex + 1) / __instance.NumPerRow * __instance.YOffset) - 3f;
|
||||
__instance.SetScrollerBounds();
|
||||
__instance.currentSkinIsEquipped = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -72,7 +72,7 @@ public static class VisorsTabPatches
|
||||
text.gameObject.transform.localScale = Vector3.one;
|
||||
text.GetComponent<TextTranslatorTMP>().Destroy();
|
||||
text.EnableStencilMasking();
|
||||
text.text = $"{groupName}\nPress Ctrl or Tab to cycle pages";
|
||||
text.text = $"{groupName} ({currentPage + 1}/{SortedVisors.Count})\nPress Ctrl or Tab to cycle pages";
|
||||
text.alignment = TextAlignmentOptions.Center;
|
||||
text.fontSize = 3f;
|
||||
text.fontSizeMax = 3f;
|
||||
@@ -90,7 +90,7 @@ public static class VisorsTabPatches
|
||||
hatIndex += 1;
|
||||
}
|
||||
|
||||
__instance.scroller.ContentYBounds.max = -(__instance.YStart - (hatIndex + 1) / __instance.NumPerRow * __instance.YOffset) - 3f;
|
||||
__instance.SetScrollerBounds();
|
||||
__instance.currentVisorIsEquipped = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -220,6 +220,7 @@ internal static class GameOptionsMenuPatch
|
||||
menu.checkboxOrigin,
|
||||
menu.numberOptionOrigin,
|
||||
menu.stringOptionOrigin,
|
||||
menu.playerOptionOrigin,
|
||||
menu.settingsContainer));
|
||||
|
||||
foreach (var newOpt in options)
|
||||
|
||||
@@ -288,7 +288,7 @@ internal static class GameSettingMenuPatches
|
||||
{
|
||||
if (_text is not null && SelectedModIdx == 0)
|
||||
{
|
||||
_text.text = "Default";
|
||||
_text.text = $"<size=40%>(Page 0/{MiraPluginManager.Instance.RegisteredPlugins.Length})</size>\nDefault";
|
||||
_text.fontSizeMax = 3.2f;
|
||||
SelectedMod = null;
|
||||
}
|
||||
@@ -298,7 +298,7 @@ internal static class GameSettingMenuPatches
|
||||
SelectedMod = MiraPluginManager.Instance.RegisteredPlugins[SelectedModIdx - 1];
|
||||
|
||||
var name = SelectedMod.MiraPlugin.OptionsTitleText;
|
||||
_text.text = name[..Math.Min(name.Length, 25)];
|
||||
_text.text = $"<size=50%>(Page {SelectedModIdx}/{MiraPluginManager.Instance.RegisteredPlugins.Length})</size>\n" + name[..Math.Min(name.Length, 25)];
|
||||
}
|
||||
|
||||
bool replaceWithModifiers = true;
|
||||
|
||||
@@ -1,7 +1,13 @@
|
||||
using HarmonyLib;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using HarmonyLib;
|
||||
using Il2CppSystem;
|
||||
using MiraAPI.GameOptions;
|
||||
using MiraAPI.GameOptions.OptionTypes;
|
||||
using MiraAPI.Roles;
|
||||
using MiraAPI.Utilities;
|
||||
using UnityEngine;
|
||||
using Object = Il2CppSystem.Object;
|
||||
|
||||
namespace MiraAPI.Patches.Options;
|
||||
|
||||
@@ -22,7 +28,9 @@ public static class OptionsPatches
|
||||
__instance.roleMaxCount = 1;
|
||||
}
|
||||
|
||||
__instance.roleChance += 10;
|
||||
var increment = Input.GetKey(KeyCode.LeftShift) ? 5 : 10;
|
||||
__instance.roleChance += increment;
|
||||
|
||||
if (__instance.roleChance > 100)
|
||||
{
|
||||
__instance.roleChance = 0;
|
||||
@@ -46,7 +54,9 @@ public static class OptionsPatches
|
||||
__instance.roleMaxCount = 1;
|
||||
}
|
||||
|
||||
__instance.roleChance -= 10;
|
||||
var increment = Input.GetKey(KeyCode.LeftShift) ? 5 : 10;
|
||||
__instance.roleChance -= increment;
|
||||
|
||||
if (__instance.roleChance < 0)
|
||||
{
|
||||
__instance.roleChance = 100;
|
||||
@@ -107,6 +117,7 @@ public static class OptionsPatches
|
||||
[HarmonyPrefix]
|
||||
[HarmonyPatch(typeof(NumberOption), nameof(NumberOption.AdjustButtonsActiveState))]
|
||||
[HarmonyPatch(typeof(StringOption), nameof(StringOption.AdjustButtonsActiveState))]
|
||||
[HarmonyPatch(typeof(PlayerOption), nameof(PlayerOption.AdjustButtonsActiveState))]
|
||||
[HarmonyPatch(typeof(RoleOptionSetting), nameof(RoleOptionSetting.AdjustChanceButtonsActiveState))]
|
||||
[HarmonyPatch(typeof(RoleOptionSetting), nameof(RoleOptionSetting.AdjustCountButtonsActiveState))]
|
||||
public static bool AdjustButtonsPrefix(OptionBehaviour __instance)
|
||||
@@ -123,6 +134,11 @@ public static class OptionsPatches
|
||||
stringOption.MinusBtn.SetInteractable(true);
|
||||
stringOption.PlusBtn.SetInteractable(true);
|
||||
}
|
||||
if (__instance.TryCast<PlayerOption>() is { } playerOption)
|
||||
{
|
||||
playerOption.MinusBtn.SetInteractable(true);
|
||||
playerOption.PlusBtn.SetInteractable(true);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -172,6 +188,7 @@ public static class OptionsPatches
|
||||
[HarmonyPrefix]
|
||||
[HarmonyPatch(typeof(StringOption), nameof(StringOption.UpdateValue))]
|
||||
[HarmonyPatch(typeof(NumberOption), nameof(NumberOption.UpdateValue))]
|
||||
[HarmonyPatch(typeof(PlayerOption), nameof(PlayerOption.UpdateValue))]
|
||||
public static bool UpdateValuePrefix(OptionBehaviour __instance)
|
||||
{
|
||||
return !__instance.IsCustom();
|
||||
|
||||
@@ -0,0 +1,128 @@
|
||||
using System;
|
||||
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;
|
||||
|
||||
[HarmonyPatch(typeof(PlayerOption))]
|
||||
public static class PlayerOptionPatches
|
||||
{
|
||||
// Updates the list of players according to the filter.
|
||||
[HarmonyPrefix]
|
||||
[HarmonyPatch(nameof(PlayerOption.FixedUpdate))]
|
||||
public static bool PlayerOptionUpdatePatch(PlayerOption __instance)
|
||||
{
|
||||
if (!__instance.IsCustom())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!ModdedOptionsManager.CreatedPlayerOptions.TryGetValue(__instance, out var moddedPlrOpt)) return false;
|
||||
|
||||
var filteredPlayers = moddedPlrOpt.GetFilteredPlayers();
|
||||
if (filteredPlayers.Count != __instance.Values.Count)
|
||||
{
|
||||
filteredPlayers.Sort((a, b) => a.PlayerId.CompareTo(b.PlayerId));
|
||||
|
||||
__instance.Values = filteredPlayers.ToIl2CppList();
|
||||
moddedPlrOpt.Values = __instance.Values;
|
||||
__instance.playerIndex = filteredPlayers.FindIndex(p => p.PlayerId == __instance.Value);
|
||||
__instance.SetValueText();
|
||||
}
|
||||
|
||||
__instance.CheckValueChanged();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Disable going under 0 if you aren't allowed to choose None.
|
||||
[HarmonyPrefix]
|
||||
[HarmonyPatch(nameof(PlayerOption.UpdatePlayerIndex))]
|
||||
public static bool UpdatePlayerIndexPatch(PlayerOption __instance, int index)
|
||||
{
|
||||
if (!__instance.IsCustom() || ModdedOptionsManager.CreatedPlayerOptions[__instance].AllowNone)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
var newIndex = Mathf.Clamp(index, 0, __instance.Values.Count - 1);
|
||||
__instance.playerIndex = newIndex;
|
||||
__instance.Value = __instance.Values[newIndex].PlayerId;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Replace "Round Robin" with "None" in the Host Options Menu.
|
||||
[HarmonyPostfix]
|
||||
[HarmonyPatch(nameof(PlayerOption.SetValueText))]
|
||||
public static void SetValueTextPatch(PlayerOption __instance)
|
||||
{
|
||||
if (__instance.playerIndex < 0)
|
||||
{
|
||||
__instance.ValueText.text = TranslationController.Instance.GetString(StringNames.FilterNone);
|
||||
}
|
||||
}
|
||||
|
||||
// Innersloth hardcode literally replaces the value with the HNS impostor option OnEnable, so I have to patch that out. Smh.
|
||||
[HarmonyPrefix]
|
||||
[HarmonyPatch(nameof(PlayerOption.OnEnable))]
|
||||
public static bool OnEnablePatch(PlayerOption __instance)
|
||||
{
|
||||
return !__instance.IsCustom();
|
||||
}
|
||||
|
||||
[HarmonyPrefix]
|
||||
[HarmonyPatch(nameof(PlayerOption.GetInt))]
|
||||
public static bool GetIntPatch(PlayerOption __instance, ref int __result)
|
||||
{
|
||||
if (!__instance.IsCustom())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
__result = __instance.Value;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Used to replace "Round Robin" with "None" for option notification & view pane.
|
||||
[HarmonyPrefix]
|
||||
[HarmonyPatch(typeof(PlayerSelectionGameSetting), nameof(PlayerSelectionGameSetting.GetValueString))]
|
||||
public static bool GetStringPatch(PlayerSelectionGameSetting __instance, float value, ref string __result)
|
||||
{
|
||||
var option = ModdedOptionsManager.ModdedOptions.FirstOrDefault(x => x.Value.Data == __instance).Value;
|
||||
if (option == null) return true;
|
||||
|
||||
var networkedPlayerInfo = GameData.Instance.AllPlayers.ToArray().FirstOrDefault(p => p.PlayerId == (int)value);
|
||||
if (networkedPlayerInfo != null)
|
||||
{
|
||||
__result = networkedPlayerInfo.PlayerName;
|
||||
return false;
|
||||
}
|
||||
|
||||
__result = TranslationController.Instance.GetString(StringNames.FilterNone);
|
||||
return false;
|
||||
}
|
||||
|
||||
// "UpdateValue" was inlined and I needed to replace it, so I just rewrote the method where it's called from.
|
||||
[HarmonyPrefix]
|
||||
[HarmonyPatch(nameof(PlayerOption.CheckValueChanged))]
|
||||
public static bool UpdateValuePatch(PlayerOption __instance)
|
||||
{
|
||||
if (!__instance.IsCustom())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (__instance.oldValue == __instance.Value) return false;
|
||||
|
||||
__instance.oldValue = __instance.Value;
|
||||
__instance.SetValueText();
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using HarmonyLib;
|
||||
using Il2CppInterop.Runtime.InteropTypes.Arrays;
|
||||
using MiraAPI.GameOptions;
|
||||
using MiraAPI.Networking;
|
||||
using MiraAPI.Roles;
|
||||
using MiraAPI.Utilities;
|
||||
@@ -30,6 +31,9 @@ public static class RoleSettingMenuPatches
|
||||
|
||||
private static float ScrollerNum { get; set; } = 0.522f;
|
||||
|
||||
private static RoleBehaviour? CurrentRole { get; set; }
|
||||
private static List<IModdedOption>? CurrentRoleOptions { get; set; }
|
||||
|
||||
[HarmonyPostfix]
|
||||
[HarmonyPatch(nameof(RolesSettingsMenu.SetQuotaTab))]
|
||||
public static void SetQuotaTabPostfix(RolesSettingsMenu __instance)
|
||||
@@ -45,6 +49,8 @@ public static class RoleSettingMenuPatches
|
||||
RoleOptionSettings.ForEach(Object.Destroy);
|
||||
Headers.Clear();
|
||||
RoleOptionSettings.Clear();
|
||||
CurrentRole = null;
|
||||
CurrentRoleOptions = null;
|
||||
|
||||
__instance.roleChances = new Il2CppSystem.Collections.Generic.List<RoleOptionSetting>();
|
||||
__instance.advancedSettingChildren = new Il2CppSystem.Collections.Generic.List<OptionBehaviour>();
|
||||
@@ -262,9 +268,31 @@ public static class RoleSettingMenuPatches
|
||||
|
||||
[HarmonyPrefix]
|
||||
[HarmonyPatch(nameof(RolesSettingsMenu.Update))]
|
||||
public static bool UpdatePatch()
|
||||
public static bool UpdatePatch(RolesSettingsMenu __instance)
|
||||
{
|
||||
return GameSettingMenuPatches.SelectedModIdx == 0;
|
||||
if (GameSettingMenuPatches.SelectedModIdx == 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;
|
||||
|
||||
if (!opt.Visible.Invoke())
|
||||
{
|
||||
opt.OptionBehaviour.gameObject.SetActive(false);
|
||||
continue;
|
||||
}
|
||||
|
||||
opt.OptionBehaviour.transform.localPosition = new Vector3(hasImage ? 2.17f : 1.1f, num, -2f);
|
||||
opt.OptionBehaviour.gameObject.SetActive(true);
|
||||
num += -0.45f;
|
||||
}
|
||||
|
||||
__instance.scrollBar.SetYBoundsMax(-num - 3);
|
||||
return false;
|
||||
}
|
||||
|
||||
[HarmonyPostfix]
|
||||
@@ -276,6 +304,8 @@ public static class RoleSettingMenuPatches
|
||||
return;
|
||||
}
|
||||
|
||||
CurrentRole = null;
|
||||
CurrentRoleOptions = null;
|
||||
__instance.scrollBar.SetScrollBounds(__instance);
|
||||
}
|
||||
|
||||
@@ -328,27 +358,26 @@ public static class RoleSettingMenuPatches
|
||||
optBehaviour.gameObject.DestroyImmediate();
|
||||
}
|
||||
|
||||
CurrentRole = role;
|
||||
__instance.advancedSettingChildren.Clear();
|
||||
|
||||
var hasImage = role.RoleScreenshot != null;
|
||||
var num = hasImage ? -0.872f : -1;
|
||||
|
||||
// TODO: create sub groups under the role settings.
|
||||
var filteredOptions = GameSettingMenuPatches.SelectedMod?.InternalOptionGroups
|
||||
.Where(x => x.GroupVisible() && x.OptionableType == role.GetType())
|
||||
.SelectMany(x => x.Options)
|
||||
.Where(x => x.Visible())
|
||||
.ToList() ?? [];
|
||||
|
||||
CurrentRoleOptions = filteredOptions;
|
||||
|
||||
foreach (var option in filteredOptions)
|
||||
{
|
||||
var newOpt = option.CreateOption(
|
||||
__instance.checkboxOrigin,
|
||||
__instance.numberOptionOrigin,
|
||||
__instance.stringOptionOrigin,
|
||||
GameSettingMenu.Instance.GameSettingsTab.playerOptionOrigin,
|
||||
__instance.AdvancedRolesSettings.transform);
|
||||
|
||||
newOpt.transform.localPosition = new Vector3(hasImage ? 2.17f : 1.1f, num, -2f);
|
||||
newOpt.SetClickMask(__instance.ButtonClickMask);
|
||||
|
||||
SpriteRenderer[] componentsInChildren = newOpt.GetComponentsInChildren<SpriteRenderer>(true);
|
||||
@@ -366,11 +395,10 @@ public static class RoleSettingMenuPatches
|
||||
newOpt.LabelBackground.enabled = false;
|
||||
__instance.advancedSettingChildren.Add(newOpt);
|
||||
|
||||
num += -0.45f;
|
||||
newOpt.gameObject.SetActive(false);
|
||||
newOpt.Initialize();
|
||||
}
|
||||
|
||||
__instance.scrollBar.SetYBoundsMax(-num - 3);
|
||||
__instance.scrollBar.ScrollToTop();
|
||||
}
|
||||
|
||||
@@ -506,7 +534,7 @@ public static class RoleSettingMenuPatches
|
||||
|
||||
if (GameSettingMenuPatches.SelectedMod is null ||
|
||||
GameSettingMenuPatches.SelectedMod.InternalOptionGroups
|
||||
.Exists(x => x.OptionableType == role.GetType()))
|
||||
.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";
|
||||
|
||||
@@ -7,6 +7,7 @@ using MiraAPI.Hud;
|
||||
using MiraAPI.Modifiers;
|
||||
using MiraAPI.Utilities;
|
||||
using MiraAPI.Voting;
|
||||
using Reactor.Utilities;
|
||||
using Reactor.Utilities.Extensions;
|
||||
|
||||
namespace MiraAPI.Patches;
|
||||
@@ -94,12 +95,19 @@ internal static class PlayerControlPatches
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!button.Enabled(__instance.Data?.Role))
|
||||
try
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (!button.Enabled(__instance.Data?.Role))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
button.FixedUpdateHandler(__instance);
|
||||
button.FixedUpdateHandler(__instance);
|
||||
}
|
||||
catch (System.Exception e)
|
||||
{
|
||||
Logger<MiraApiPlugin>.Error($"Failed to update custom button {button.GetType().Name}: {e}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -23,7 +23,11 @@ public static class GameStartupPatch
|
||||
|
||||
_runOnce = true;
|
||||
|
||||
if (MiraPluginManager.Instance.QueuedRoleRegistrations.Count <= 0) return;
|
||||
if (MiraPluginManager.Instance.QueuedRoleRegistrations.Count <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var queue in MiraPluginManager.Instance.QueuedRoleRegistrations)
|
||||
{
|
||||
CustomRoleManager.RegisterRoleTypes(queue.Value, queue.Key);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using HarmonyLib;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
using UnityEngine.SceneManagement;
|
||||
|
||||
namespace MiraAPI.Patches;
|
||||
|
||||
@@ -14,6 +15,8 @@ public static class ServerDropdownPatch
|
||||
|
||||
foreach (var regionInfo in DestroyableSingleton<ServerManager>.Instance.AvailableRegions)
|
||||
{
|
||||
var findingGame = SceneManager.GetActiveScene().name is "FindAGame";
|
||||
|
||||
if (DestroyableSingleton<ServerManager>.Instance.CurrentRegion.Equals(regionInfo))
|
||||
{
|
||||
__instance.defaultButtonSelected = __instance.firstOption;
|
||||
@@ -27,6 +30,10 @@ public static class ServerDropdownPatch
|
||||
var region = regionInfo;
|
||||
var serverListButton = __instance.ButtonPool.Get<ServerListButton>();
|
||||
var x = num % 2 == 0 ? -2 : 2;
|
||||
if (findingGame)
|
||||
{
|
||||
x += 2;
|
||||
}
|
||||
var y = -0.55f * (num / 2);
|
||||
serverListButton.transform.localPosition = new Vector3(x, __instance.y_posButton + y, -1f);
|
||||
serverListButton.transform.localScale = Vector3.one;
|
||||
@@ -39,7 +46,7 @@ public static class ServerDropdownPatch
|
||||
serverListButton.Button.OnClick.AddListener((UnityAction)(() => { __instance.ChooseOption(region); }));
|
||||
__instance.controllerSelectable.Add(serverListButton.Button);
|
||||
__instance.background.transform.localPosition = new Vector3(
|
||||
0f,
|
||||
findingGame ? 2f : 0f,
|
||||
__instance.initialYPos + (-0.3f * (num / 2)),
|
||||
0f);
|
||||
__instance.background.size = new Vector2(__instance.background.size.x, 1.2f + (0.6f * (num / 2)));
|
||||
|
||||
@@ -130,6 +130,8 @@ public sealed class MiraPluginManager
|
||||
|
||||
// Cache all the registered plugins into an array for easy access
|
||||
RegisteredPlugins = [.._registeredPlugins.Values];
|
||||
|
||||
ModifierManager.Modifiers = new ReadOnlyCollection<BaseModifier>(ModifierManager.InternalModifiers);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -96,6 +96,3 @@ public class SavePresetPopup(nint cppPtr) : Minigame(cppPtr)
|
||||
popup.Begin(null);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
Binary file not shown.
@@ -35,6 +35,16 @@ public static class CustomRoleManager
|
||||
public static readonly LoadableAsset<AudioClip> ImpostorIntroSound =
|
||||
CustomRoleUtils.GetIntroSound(RoleTypes.Impostor)!;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the list of custom roles as RoleBehaviour objects.
|
||||
/// </summary>
|
||||
public static IReadOnlyList<RoleBehaviour> CustomRoleBehaviours { get; private set; } = [];
|
||||
|
||||
/// <summary>
|
||||
/// Gets the list of custom roles as ICustomRole objects.
|
||||
/// </summary>
|
||||
public static IReadOnlyList<ICustomRole> CustomMiraRoles { get; private set; } = [];
|
||||
|
||||
internal static readonly Dictionary<ushort, RoleBehaviour> CustomRoles = [];
|
||||
internal static readonly Dictionary<Type, ushort> RoleIds = [];
|
||||
|
||||
@@ -53,6 +63,9 @@ public static class CustomRoleManager
|
||||
{
|
||||
RoleManager.GhostRoles.Add(role.Role);
|
||||
}
|
||||
|
||||
CustomRoleBehaviours = CustomRoles.Values.ToList();
|
||||
CustomMiraRoles = CustomRoles.Values.OfType<ICustomRole>().ToList();
|
||||
}
|
||||
|
||||
internal static void RegisterRoleTypes(List<Type> roles, MiraPluginInfo pluginInfo)
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace MiraAPI.Roles;
|
||||
|
||||
public enum RoleContext
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace MiraAPI.Utilities;
|
||||
|
||||
/// <summary>
|
||||
/// Extensions for IEnumerable.
|
||||
/// </summary>
|
||||
public static class EnumerableExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Shuffle the elements of the source enumerable using a new instance of Random.
|
||||
/// </summary>
|
||||
/// <param name="source">The source enumerable.</param>
|
||||
/// <typeparam name="T">The type of the elements.</typeparam>
|
||||
/// <returns>>The shuffled enumerable.</returns>
|
||||
public static IEnumerable<T> Shuffle<T>(this IEnumerable<T> source)
|
||||
{
|
||||
return source.Shuffle(new Random());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Shuffle the elements of the source enumerable using the provided Random instance.
|
||||
/// </summary>
|
||||
/// <param name="source">The source enumerable.</param>
|
||||
/// <param name="rng">The Random instance to use for shuffling.</param>
|
||||
/// <typeparam name="T">The type of the elements.</typeparam>
|
||||
/// <returns>>The shuffled enumerable.</returns>
|
||||
public static IEnumerable<T> Shuffle<T>(this IEnumerable<T> source, Random rng)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(source);
|
||||
ArgumentNullException.ThrowIfNull(rng);
|
||||
|
||||
return source.ShuffleIterator(rng);
|
||||
}
|
||||
|
||||
private static IEnumerable<T> ShuffleIterator<T>(this IEnumerable<T> source, Random rng)
|
||||
{
|
||||
var buffer = source.ToList();
|
||||
for (var i = 0; i < buffer.Count; i++)
|
||||
{
|
||||
var j = rng.Next(i, buffer.Count);
|
||||
yield return buffer[j];
|
||||
|
||||
buffer[j] = buffer[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -154,6 +154,24 @@ public static class Extensions
|
||||
return TutorialManager.InstanceExists || AmongUsClient.Instance.HostId == playerControl.OwnerId;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Used to convert a System.Collections.Generic.List to Il2cppSystem.
|
||||
/// </summary>
|
||||
/// <param name="systemList">The list.</param>
|
||||
/// <typeparam name="T">The type in the list.</typeparam>
|
||||
/// <returns>The converted list.</returns>
|
||||
public static Il2CppSystem.Collections.Generic.List<T> ToIl2CppList<T>(this List<T> systemList)
|
||||
{
|
||||
var il2cppList = new Il2CppSystem.Collections.Generic.List<T>();
|
||||
|
||||
foreach (var item in systemList)
|
||||
{
|
||||
il2cppList.Add(item);
|
||||
}
|
||||
|
||||
return il2cppList;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines if a float is an integer.
|
||||
/// </summary>
|
||||
|
||||
Reference in new issue
Block a user