mirror of
https://github.com/All-Of-Us-Mods/MiraAPI.git
synced 2026-10-20 01:46:15 +00:00
Compare commits
23
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
86f970c989 | ||
|
|
7aafaf478c | ||
|
|
451a626370 | ||
|
|
e02c06ca07 | ||
|
|
e43cd0ceff | ||
|
|
e680b5c872 | ||
|
|
b6f304fe1d | ||
|
|
e52f48c20d | ||
|
|
d97588b356 | ||
|
|
68304a5eb8 | ||
|
|
f2add2a65b | ||
|
|
bbff2dd2d9 | ||
|
|
d9081ed17b | ||
|
|
6f248221d6 | ||
|
|
b67fdf5ab1 | ||
|
|
26afd47d2a | ||
|
|
2e0ecd95a6 | ||
|
|
669d5765e6 | ||
|
|
309094bdf8 | ||
|
|
49d09bb44f | ||
|
|
f77b694e78 | ||
|
|
e3cf884975 | ||
|
|
3d91c8de25 |
No files matched your search
@@ -8,7 +8,7 @@
|
||||
|
||||
<RestorePackagesWithLockFile>true</RestorePackagesWithLockFile>
|
||||
|
||||
<VersionPrefix>0.1.9</VersionPrefix>
|
||||
<VersionPrefix>0.2.0</VersionPrefix>
|
||||
<VersionSuffix>dev</VersionSuffix>
|
||||
|
||||
<Authors>All Of Us, XtraCube, Angxl</Authors>
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
using MiraAPI.Example.Options.Roles;
|
||||
using System.Collections;
|
||||
using MiraAPI.Example.Options.Roles;
|
||||
using MiraAPI.Example.Roles;
|
||||
using MiraAPI.GameOptions;
|
||||
using MiraAPI.Hud;
|
||||
using MiraAPI.Utilities.Assets;
|
||||
using Reactor.Utilities;
|
||||
using System.Collections;
|
||||
using UnityEngine;
|
||||
|
||||
namespace MiraAPI.Example.Buttons.Teleporter;
|
||||
@@ -19,7 +19,7 @@ public class TeleportButton : CustomActionButton
|
||||
public override int MaxUses => 2;
|
||||
|
||||
public override LoadableAsset<Sprite> Sprite => ExampleAssets.TeleportButton;
|
||||
|
||||
public override Color TextOutlineColor => new Color32(221, 176, 152, 255);
|
||||
public static bool IsZoom { get; private set; }
|
||||
|
||||
public override bool Enabled(RoleBehaviour? role)
|
||||
|
||||
@@ -12,11 +12,7 @@ public static class ExampleEventHandlers
|
||||
{
|
||||
public static void Initialize()
|
||||
{
|
||||
// Register event handlers here
|
||||
MiraEventManager.RegisterEventHandler<MiraButtonClickEvent<FreezeButton>>(FreezeButtonClickHandler, 1);
|
||||
MiraEventManager.RegisterEventHandler<MiraButtonCancelledEvent<FreezeButton>>(FreezeButtonCancelledHandler);
|
||||
MiraEventManager.RegisterEventHandler<UpdateSystemEvent>(UpdateSystemEventHandler);
|
||||
|
||||
// You can register event handlers with the MiraEventManager class.
|
||||
MiraEventManager.RegisterEventHandler<BeforeMurderEvent>(@event =>
|
||||
{
|
||||
Logger<ExamplePlugin>.Info($"{@event.Source.Data.PlayerName} is about to kill {@event.Target.Data.PlayerName}");
|
||||
@@ -33,12 +29,15 @@ public static class ExampleEventHandlers
|
||||
});
|
||||
}
|
||||
|
||||
// Events can be registered using an attribute as well.
|
||||
[RegisterEvent]
|
||||
public static void UpdateSystemEventHandler(UpdateSystemEvent @event)
|
||||
{
|
||||
Logger<ExamplePlugin>.Error(@event.SystemType.ToString());
|
||||
}
|
||||
|
||||
// Example event handler
|
||||
[RegisterEvent(1)]
|
||||
public static void FreezeButtonClickHandler(MiraButtonClickEvent<FreezeButton> @event)
|
||||
{
|
||||
Logger<ExamplePlugin>.Warning("Freeze button clicked!");
|
||||
@@ -51,6 +50,7 @@ public static class ExampleEventHandlers
|
||||
}
|
||||
|
||||
// Example event handler
|
||||
[RegisterEvent]
|
||||
public static void FreezeButtonCancelledHandler(MiraButtonCancelledEvent<FreezeButton> @event)
|
||||
{
|
||||
Logger<ExamplePlugin>.Warning("Freeze button cancelled!");
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using MiraAPI.GameEnd;
|
||||
using MiraAPI.Example.Roles;
|
||||
using MiraAPI.GameEnd;
|
||||
using MiraAPI.Utilities;
|
||||
using UnityEngine;
|
||||
|
||||
@@ -6,6 +7,11 @@ namespace MiraAPI.Example.GameOver;
|
||||
|
||||
public class NeutralKillerGameOver : CustomGameOver
|
||||
{
|
||||
public override bool VerifyCondition(PlayerControl playerControl, NetworkedPlayerInfo[] winners)
|
||||
{
|
||||
return winners is [{ Role: NeutralKillerRole }];
|
||||
}
|
||||
|
||||
public override void AfterEndGameSetup(EndGameManager endGameManager)
|
||||
{
|
||||
endGameManager.WinText.text = "Outcast Killer Wins!";
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
using MiraAPI.Modifiers.Types;
|
||||
using MiraAPI.Example.Options.Modifiers;
|
||||
using MiraAPI.GameOptions;
|
||||
using MiraAPI.Modifiers.Types;
|
||||
|
||||
namespace MiraAPI.Example.Modifiers;
|
||||
|
||||
@@ -6,13 +8,13 @@ public class CaptainModifier : GameModifier
|
||||
{
|
||||
public override string ModifierName => "Captain";
|
||||
|
||||
public override int GetAmountPerGame()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
public override int GetAssignmentChance()
|
||||
{
|
||||
return 100;
|
||||
return (int)OptionGroupSingleton<CaptainModifierSettings>.Instance.Chance;
|
||||
}
|
||||
|
||||
public override int GetAmountPerGame()
|
||||
{
|
||||
return (int)OptionGroupSingleton<CaptainModifierSettings>.Instance.Amount;
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ namespace MiraAPI.Example.Modifiers;
|
||||
public class HighPriorityModifier : GameModifier
|
||||
{
|
||||
public override string ModifierName => "High Priority";
|
||||
|
||||
public override int GetAssignmentChance()
|
||||
{
|
||||
return 100;
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
using MiraAPI.Example.Modifiers;
|
||||
using MiraAPI.GameOptions;
|
||||
using MiraAPI.GameOptions.Attributes;
|
||||
|
||||
namespace MiraAPI.Example.Options.Modifiers;
|
||||
|
||||
public class CaptainModifierSettings : AbstractOptionGroup<CaptainModifier>
|
||||
{
|
||||
public override string GroupName => "Captain Settings";
|
||||
|
||||
[ModdedNumberOption("Amount", 0, 5)]
|
||||
public float Amount { get; set; } = 1;
|
||||
|
||||
[ModdedNumberOption("Chance", 0, 100, 10)]
|
||||
public float Chance { get; set; } = 50;
|
||||
|
||||
[ModdedNumberOption("Uses", 1, 5)]
|
||||
public float NumUses { get; set; } = 3;
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
using MiraAPI.Example.Modifiers.Freezer;
|
||||
using MiraAPI.GameOptions;
|
||||
using MiraAPI.GameOptions.Attributes;
|
||||
|
||||
namespace MiraAPI.Example.Options.Modifiers;
|
||||
|
||||
public class FreezeModifierSettings : AbstractOptionGroup<FreezeModifier>
|
||||
{
|
||||
public override string GroupName => "Freeze";
|
||||
|
||||
[ModdedToggleOption("Use Color")]
|
||||
public bool UseColor { get; set; } = true;
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
using MiraAPI.GameOptions;
|
||||
using MiraAPI.GameOptions.Attributes;
|
||||
|
||||
namespace MiraAPI.Example.Options.Modifiers;
|
||||
|
||||
public class GeneralModifierOptions : AbstractOptionGroup
|
||||
{
|
||||
public override string GroupName => "General";
|
||||
|
||||
public override uint GroupPriority => 0;
|
||||
|
||||
public override bool ShowInModifiersMenu => true;
|
||||
|
||||
[ModdedToggleOption("Some Boolean Option")]
|
||||
public bool SomeBooleanOption { get; set; } = true;
|
||||
|
||||
[ModdedNumberOption("Number Option", 0, 10, 1)]
|
||||
public float NumberOption { get; set; } = 5;
|
||||
}
|
||||
@@ -1,17 +1,14 @@
|
||||
using MiraAPI.Example.Roles;
|
||||
using MiraAPI.GameOptions;
|
||||
using MiraAPI.GameOptions.Attributes;
|
||||
using System;
|
||||
using MiraAPI.Utilities;
|
||||
|
||||
namespace MiraAPI.Example.Options.Roles;
|
||||
|
||||
public class FreezerRoleSettings : AbstractOptionGroup
|
||||
public class FreezerRoleSettings : AbstractOptionGroup<FreezerRole>
|
||||
{
|
||||
public override string GroupName => "Custom Role";
|
||||
|
||||
public override Type AdvancedRole => typeof(FreezerRole);
|
||||
|
||||
[ModdedNumberOption("Freeze Duration", 1, 15, 1, MiraNumberSuffixes.Seconds)]
|
||||
public float FreezeDuration { get; set; } = 5;
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using MiraAPI.Example.Roles;
|
||||
using MiraAPI.Example.Roles;
|
||||
using MiraAPI.GameOptions;
|
||||
using MiraAPI.GameOptions.Attributes;
|
||||
using MiraAPI.GameOptions.OptionTypes;
|
||||
@@ -7,12 +6,10 @@ using MiraAPI.Utilities;
|
||||
|
||||
namespace MiraAPI.Example.Options.Roles;
|
||||
|
||||
public class TeleporterOptions : AbstractOptionGroup
|
||||
public class TeleporterOptions : AbstractOptionGroup<TeleporterRole>
|
||||
{
|
||||
public override string GroupName => "Teleporter";
|
||||
|
||||
public override Type AdvancedRole => typeof(TeleporterRole);
|
||||
|
||||
public ModdedNumberOption TeleportCooldown { get; set; } = new("Teleport Cooldown", 10, 5, 60, 2.5f, MiraNumberSuffixes.Seconds);
|
||||
|
||||
[ModdedNumberOption("Teleport Duration", 5, 25, 1, MiraNumberSuffixes.Seconds)]
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using Reactor.Utilities;
|
||||
|
||||
namespace MiraAPI.Events;
|
||||
|
||||
@@ -54,6 +56,30 @@ public static class MiraEventManager
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Register an event.
|
||||
/// </summary>
|
||||
/// <param name="type">The type of event.</param>
|
||||
/// <param name="methodInfo">The MethodInfo of the event handler.</param>
|
||||
/// <param name="priority">The priority of the event handler. Higher values are called first.</param>
|
||||
public static void RegisterEventHandler(Type type, MethodInfo methodInfo, int priority = 0)
|
||||
{
|
||||
if (!type.IsSubclassOf(typeof(MiraEvent)))
|
||||
{
|
||||
Logger<MiraApiPlugin>.Error($"Type must be a subclass of MiraEvent: {nameof(type)}");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!EventWrappers.TryGetValue(type, out var handlers))
|
||||
{
|
||||
handlers = [];
|
||||
EventWrappers.Add(type, handlers);
|
||||
}
|
||||
|
||||
var @delegate = Delegate.CreateDelegate(typeof(Action<>).MakeGenericType(type), methodInfo);
|
||||
handlers.Add(new MiraEventWrapper(@delegate, priority));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Register an event.
|
||||
/// </summary>
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
using System;
|
||||
|
||||
namespace MiraAPI.Events;
|
||||
|
||||
/// <summary>
|
||||
/// Register an event.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Method)]
|
||||
public class RegisterEventAttribute : Attribute
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the priority of the event.
|
||||
/// </summary>
|
||||
public int Priority { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="RegisterEventAttribute"/> class.
|
||||
/// </summary>
|
||||
/// <param name="priority">The priority of the event.</param>
|
||||
public RegisterEventAttribute(int priority = 0)
|
||||
{
|
||||
Priority = priority;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
namespace MiraAPI.Events.Vanilla.Meeting;
|
||||
|
||||
/// <summary>
|
||||
/// The event that is invoked when a body is reported.
|
||||
/// This is invoked in CmdReportBody.
|
||||
/// </summary>
|
||||
public class ReportBodyEvent : MiraCancelableEvent
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the player that is reporting the body.
|
||||
/// </summary>
|
||||
public PlayerControl Reporter { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the player that is being reported. Will be null for emergency meeting.
|
||||
/// </summary>
|
||||
public NetworkedPlayerInfo? Target { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the body that is being reported. Will be null for emergency meeting.
|
||||
/// </summary>
|
||||
public DeadBody? Body { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ReportBodyEvent"/> class.
|
||||
/// </summary>
|
||||
/// <param name="reporter">The player who reported the body.</param>
|
||||
/// <param name="target">The player being reported.</param>
|
||||
/// <param name="body">The body being reported.</param>
|
||||
public ReportBodyEvent(PlayerControl reporter, NetworkedPlayerInfo? target, DeadBody? body)
|
||||
{
|
||||
Reporter = reporter;
|
||||
Target = target;
|
||||
Body = body;
|
||||
}
|
||||
}
|
||||
@@ -1,35 +1,22 @@
|
||||
namespace MiraAPI.Events.Vanilla.Meeting;
|
||||
|
||||
/// <summary>
|
||||
/// The event that is invoked when a meeting is called.
|
||||
/// The event that is invoked when a meeting is called. This event is not cancelable.
|
||||
/// This event is called after Mira resets votes, so if you plan on adding votes to a specific player, do it with this event.
|
||||
/// </summary>
|
||||
public class StartMeetingEvent : MiraCancelableEvent
|
||||
public class StartMeetingEvent : MiraEvent
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the player that is calling the meeting.
|
||||
/// Gets the MeetingHud instance.
|
||||
/// </summary>
|
||||
public PlayerControl Reporter { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the player that is being reported. Will be null for emergency meeting.
|
||||
/// </summary>
|
||||
public NetworkedPlayerInfo? Target { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the body that is being reported. Will be null for emergency meeting.
|
||||
/// </summary>
|
||||
public DeadBody? Body { get; }
|
||||
public MeetingHud MeetingHud { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="StartMeetingEvent"/> class.
|
||||
/// </summary>
|
||||
/// <param name="reporter">The player who reported the body.</param>
|
||||
/// <param name="target">The player being reported.</param>
|
||||
/// <param name="body">The body being reported.</param>
|
||||
public StartMeetingEvent(PlayerControl reporter, NetworkedPlayerInfo? target, DeadBody? body)
|
||||
/// <param name="meetingHud">The MeetingHud instance.</param>
|
||||
public StartMeetingEvent(MeetingHud meetingHud)
|
||||
{
|
||||
Reporter = reporter;
|
||||
Target = target;
|
||||
Body = body;
|
||||
MeetingHud = meetingHud;
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
using System.Collections.Generic;
|
||||
using MiraAPI.Networking;
|
||||
using Reactor.Networking.Rpc;
|
||||
using Reactor.Utilities;
|
||||
|
||||
namespace MiraAPI.GameEnd;
|
||||
|
||||
@@ -15,6 +14,17 @@ public abstract class CustomGameOver
|
||||
/// </summary>
|
||||
public static CustomGameOver? Instance { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Verifies if the condition for this CustomGameOver is met.
|
||||
/// </summary>
|
||||
/// <param name="playerControl">The PlayerControl that requested the Game Over.</param>
|
||||
/// <param name="winners">The collection of winners.</param>
|
||||
/// <returns>True if the condition is met, otherwise false.</returns>
|
||||
public virtual bool VerifyCondition(PlayerControl playerControl, NetworkedPlayerInfo[] winners)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Runs before the base game calls EndGameManager.SetEverythingUp.
|
||||
/// </summary>
|
||||
@@ -50,12 +60,6 @@ public abstract class CustomGameOver
|
||||
/// <typeparam name="T">Type of the custom game over.</typeparam>
|
||||
public static void Trigger<T>(IEnumerable<NetworkedPlayerInfo> winners) where T : CustomGameOver
|
||||
{
|
||||
if (!AmongUsClient.Instance.AmHost)
|
||||
{
|
||||
Logger<MiraApiPlugin>.Error("Only the host can send a custom game over.");
|
||||
return;
|
||||
}
|
||||
|
||||
var reason = GameOverManager.GetGameOverId<T>();
|
||||
var data = new GameOverData(reason, [.. winners]);
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Reactor.Utilities;
|
||||
|
||||
namespace MiraAPI.GameEnd;
|
||||
@@ -51,7 +52,7 @@ public static class GameOverManager
|
||||
/// <param name="id">ID of the custom game over.</param>
|
||||
/// <param name="customGameOver">The created instance of the custom game over.</param>
|
||||
/// <returns>An instance of the custom game over.</returns>
|
||||
public static bool TryGetGameOver(int id, out CustomGameOver? customGameOver)
|
||||
public static bool TryGetGameOver(int id, [NotNullWhen(true)] out CustomGameOver? customGameOver)
|
||||
{
|
||||
if (GameOverTypes.TryGetValue(id, out var gameOverType))
|
||||
{
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using Reactor.Utilities;
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Reactor.Utilities;
|
||||
|
||||
namespace MiraAPI.GameModes;
|
||||
|
||||
|
||||
@@ -16,6 +16,17 @@ public abstract class AbstractOptionGroup
|
||||
/// </summary>
|
||||
public abstract string GroupName { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Optionable type of the group.
|
||||
/// </summary>
|
||||
public virtual Type? OptionableType => null;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the group should be shown in the modifiers menu.
|
||||
/// </summary>
|
||||
// TODO: make this not a boolean
|
||||
public virtual bool ShowInModifiersMenu => false;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the function that determines whether the group should be visible or not.
|
||||
/// </summary>
|
||||
@@ -32,12 +43,17 @@ public abstract class AbstractOptionGroup
|
||||
/// </summary>
|
||||
public virtual uint GroupPriority => uint.MaxValue;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the role the group is associated with. This is used for the advanced role options menu.
|
||||
/// </summary>
|
||||
public virtual Type? AdvancedRole => null;
|
||||
|
||||
internal bool AllOptionsHidden { get; set; }
|
||||
|
||||
internal CategoryHeaderMasked? Header { get; set; }
|
||||
}
|
||||
|
||||
/// <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 type of the optionable that this group contains.</typeparam>
|
||||
public abstract class AbstractOptionGroup<T> : AbstractOptionGroup where T : IOptionable
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public override Type OptionableType => typeof(T);
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
using MiraAPI.GameOptions.OptionTypes;
|
||||
using System;
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using MiraAPI.GameOptions.OptionTypes;
|
||||
|
||||
namespace MiraAPI.GameOptions.Attributes;
|
||||
|
||||
@@ -8,12 +8,12 @@ namespace MiraAPI.GameOptions.Attributes;
|
||||
/// Attribute for creating an enum option.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Property)]
|
||||
public class ModdedEnumOptionAttribute(string title, Type enumType, string[]? values = null, Type? roleType = null)
|
||||
: ModdedOptionAttribute(title, roleType)
|
||||
public class ModdedEnumOptionAttribute(string title, Type enumType, string[]? values = null)
|
||||
: ModdedOptionAttribute(title)
|
||||
{
|
||||
internal override IModdedOption CreateOption(object? value, PropertyInfo property)
|
||||
{
|
||||
var opt = new ModdedEnumOption(Title, (int)(value ?? 0), enumType, values, RoleType);
|
||||
var opt = new ModdedEnumOption(Title, (int)(value ?? 0), enumType, values);
|
||||
return opt;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using MiraAPI.GameOptions.OptionTypes;
|
||||
using MiraAPI.Utilities;
|
||||
using System;
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using MiraAPI.GameOptions.OptionTypes;
|
||||
using MiraAPI.Utilities;
|
||||
|
||||
namespace MiraAPI.GameOptions.Attributes;
|
||||
|
||||
@@ -16,13 +16,12 @@ public class ModdedNumberOptionAttribute(
|
||||
float increment = 1,
|
||||
MiraNumberSuffixes suffixType = MiraNumberSuffixes.None,
|
||||
string? formatString = null,
|
||||
bool zeroInfinity = false,
|
||||
Type? roleType = null)
|
||||
: ModdedOptionAttribute(title, roleType)
|
||||
bool zeroInfinity = false)
|
||||
: ModdedOptionAttribute(title)
|
||||
{
|
||||
internal override IModdedOption CreateOption(object? value, PropertyInfo property)
|
||||
{
|
||||
return new ModdedNumberOption(Title, (float)(value ?? min+increment), min, max, increment, suffixType, formatString, zeroInfinity, RoleType);
|
||||
return new ModdedNumberOption(Title, (float)(value ?? min+increment), min, max, increment, suffixType, formatString, zeroInfinity);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using MiraAPI.GameOptions.OptionTypes;
|
||||
using System;
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using MiraAPI.GameOptions.OptionTypes;
|
||||
|
||||
namespace MiraAPI.GameOptions.Attributes;
|
||||
|
||||
@@ -8,13 +8,12 @@ namespace MiraAPI.GameOptions.Attributes;
|
||||
/// Attribute for a toggle option.
|
||||
/// </summary>
|
||||
/// <param name="title">The option title.</param>
|
||||
/// <param name="roleType">An optional role type.</param>
|
||||
[AttributeUsage(AttributeTargets.Property)]
|
||||
public class ModdedToggleOptionAttribute(string title, Type? roleType = null) : ModdedOptionAttribute(title, roleType)
|
||||
public class ModdedToggleOptionAttribute(string title) : ModdedOptionAttribute(title)
|
||||
{
|
||||
internal override IModdedOption CreateOption(object? value, PropertyInfo property)
|
||||
{
|
||||
var toggleOpt = new ModdedToggleOption(Title, (bool)(value ?? false), RoleType);
|
||||
var toggleOpt = new ModdedToggleOption(Title, (bool)(value ?? false));
|
||||
return toggleOpt;
|
||||
}
|
||||
|
||||
|
||||
@@ -13,7 +13,6 @@ public interface IModdedOption
|
||||
StringNames StringName { get; }
|
||||
IMiraPlugin? ParentMod { get; set; }
|
||||
BaseGameSetting Data { get; }
|
||||
Type? AdvancedRole { get; set; }
|
||||
OptionBehaviour? OptionBehaviour { get; }
|
||||
Func<bool> Visible { get; set; }
|
||||
ConfigDefinition? ConfigDefinition { get; set; }
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace MiraAPI.GameOptions;
|
||||
|
||||
/// <summary>
|
||||
/// Interface for classes that can be used for option groups.
|
||||
/// </summary>
|
||||
public interface IOptionable;
|
||||
@@ -108,7 +108,7 @@ public static class ModdedOptionsManager
|
||||
RegisterOption(option, group, property.Name, pluginInfo);
|
||||
}
|
||||
|
||||
private static void RegisterOption(
|
||||
internal static void RegisterOption(
|
||||
IModdedOption option,
|
||||
AbstractOptionGroup group,
|
||||
string propertyName,
|
||||
@@ -119,10 +119,7 @@ public static class ModdedOptionsManager
|
||||
option.ConfigDefinition = new ConfigDefinition(groupName, propertyName);
|
||||
|
||||
option.ParentMod = pluginInfo.MiraPlugin;
|
||||
option.AdvancedRole = group.AdvancedRole;
|
||||
|
||||
pluginInfo.Options.Add(option);
|
||||
|
||||
ModdedOptions.Add(option.Id, option);
|
||||
group.Options.Add(option);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
using System.Linq;
|
||||
|
||||
namespace MiraAPI.GameOptions;
|
||||
|
||||
internal class ModifierOptionGroup : AbstractOptionGroup
|
||||
{
|
||||
public override string GroupName { get; }
|
||||
|
||||
public ModifierOptionGroup(string name, IModdedOption[] options, params AbstractOptionGroup[] groups)
|
||||
{
|
||||
GroupName = name;
|
||||
Options.AddRange(options);
|
||||
Options.AddRange(groups.SelectMany(x=>x.Options));
|
||||
}
|
||||
}
|
||||
@@ -27,8 +27,7 @@ public class ModdedEnumOption : ModdedOption<int>
|
||||
/// <param name="defaultValue">The default value as an int.</param>
|
||||
/// <param name="enumType">The Enum type.</param>
|
||||
/// <param name="values">An option list of string values to use in place of the enum name.</param>
|
||||
/// <param name="roleType">An optional role type to specify for a specific role.</param>
|
||||
public ModdedEnumOption(string title, int defaultValue, Type enumType, string[]? values = null, Type? roleType = null) : base(title, defaultValue, roleType)
|
||||
public ModdedEnumOption(string title, int defaultValue, Type enumType, string[]? values = null) : base(title, defaultValue)
|
||||
{
|
||||
Values = values ?? Enum.GetNames(enumType);
|
||||
Data = ScriptableObject.CreateInstance<StringGameSetting>();
|
||||
@@ -101,7 +100,6 @@ public class ModdedEnumOption : ModdedOption<int>
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// An option for selecting an enum value.
|
||||
/// </summary>
|
||||
@@ -118,10 +116,8 @@ public class ModdedEnumOption<T> : ModdedOption<T> where T : Enum
|
||||
/// </summary>
|
||||
/// <param name="title">The title of the option.</param>
|
||||
/// <param name="defaultValue">The default value as an int.</param>
|
||||
/// <param name="enumType">The Enum type.</param>
|
||||
/// <param name="values">An option list of string values to use in place of the enum name.</param>
|
||||
/// <param name="roleType">An optional role type to specify for a specific role.</param>
|
||||
public ModdedEnumOption(string title, T defaultValue, string[]? values = null, Type? roleType = null) : base(title, defaultValue, roleType)
|
||||
public ModdedEnumOption(string title, T defaultValue, string[]? values = null) : base(title, defaultValue)
|
||||
{
|
||||
Values = values ?? Enum.GetNames(typeof(T));
|
||||
Data = ScriptableObject.CreateInstance<StringGameSetting>();
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using AmongUs.GameOptions;
|
||||
using System;
|
||||
using AmongUs.GameOptions;
|
||||
using MiraAPI.Networking;
|
||||
using MiraAPI.Utilities;
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
@@ -48,7 +48,6 @@ public class ModdedNumberOption : ModdedOption<float>
|
||||
/// <param name="suffixType">The suffix type.</param>
|
||||
/// <param name="formatString">Optional format string for the option screen.</param>
|
||||
/// <param name="zeroInfinity">Whether zero is infinity or not.</param>
|
||||
/// <param name="roleType">An optional role type.</param>
|
||||
public ModdedNumberOption(
|
||||
string title,
|
||||
float defaultValue,
|
||||
@@ -57,8 +56,7 @@ public class ModdedNumberOption : ModdedOption<float>
|
||||
float increment,
|
||||
MiraNumberSuffixes suffixType,
|
||||
string? formatString = null,
|
||||
bool zeroInfinity = false,
|
||||
Type? roleType = null) : base(title, defaultValue, roleType)
|
||||
bool zeroInfinity = false) : base(title, defaultValue)
|
||||
{
|
||||
Min = min;
|
||||
Max = max;
|
||||
@@ -77,11 +75,11 @@ public class ModdedNumberOption : ModdedOption<float>
|
||||
data.Increment = Increment;
|
||||
data.ValidRange = new FloatRange(Min, Max);
|
||||
data.FormatString = formatString ??
|
||||
(!Mathf.Approximately(defaultValue, 0) ||
|
||||
!Mathf.Approximately(Increment % 1, 0) ||
|
||||
!Mathf.Approximately(Value % 1, 0) ||
|
||||
!Mathf.Approximately(Min % 1, 0) ||
|
||||
!Mathf.Approximately(Max % 1, 0) ? "0.0" : "0");
|
||||
(defaultValue.IsInteger() &&
|
||||
Increment.IsInteger() &&
|
||||
Value.IsInteger() &&
|
||||
Min.IsInteger() &&
|
||||
Max.IsInteger() ? "0" : "0.0");
|
||||
|
||||
data.ZeroIsInfinity = ZeroInfinity;
|
||||
data.SuffixType = (NumberSuffixes)SuffixType;
|
||||
@@ -144,7 +142,7 @@ public class ModdedNumberOption : ModdedOption<float>
|
||||
Value = Mathf.Clamp(newValue, Min, Max);
|
||||
HudManager.Instance.Notifier.AddSettingsChangeMessage(
|
||||
StringName,
|
||||
Data?.GetValueString(Value),
|
||||
Data.GetValueString(Value),
|
||||
false);
|
||||
|
||||
if (OptionBehaviour is NumberOption opt)
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
using BepInEx.Configuration;
|
||||
using System;
|
||||
using BepInEx.Configuration;
|
||||
using MiraAPI.Networking;
|
||||
using MiraAPI.PluginLoading;
|
||||
using MiraAPI.Roles;
|
||||
using Reactor.Localization.Utilities;
|
||||
using Reactor.Networking.Rpc;
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace MiraAPI.GameOptions.OptionTypes;
|
||||
@@ -72,11 +71,6 @@ public abstract class ModdedOption<T> : IModdedOption
|
||||
/// </summary>
|
||||
public Func<bool> Visible { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the advanced role of the option.
|
||||
/// </summary>
|
||||
public Type? AdvancedRole { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the option behaviour of the option.
|
||||
/// </summary>
|
||||
@@ -102,8 +96,7 @@ public abstract class ModdedOption<T> : IModdedOption
|
||||
/// </summary>
|
||||
/// <param name="title">The option title.</param>
|
||||
/// <param name="defaultValue">The default value.</param>
|
||||
/// <param name="roleType">The Role Type or null if it doesn't belong to a role.</param>
|
||||
protected ModdedOption(string title, T defaultValue, Type? roleType)
|
||||
protected ModdedOption(string title, T defaultValue)
|
||||
{
|
||||
Id = ModdedOptionsManager.NextId;
|
||||
Title = title;
|
||||
@@ -111,11 +104,6 @@ public abstract class ModdedOption<T> : IModdedOption
|
||||
Value = defaultValue;
|
||||
StringName = CustomStringName.CreateAndRegister(Title);
|
||||
Visible = () => true;
|
||||
|
||||
if (roleType is not null && roleType.IsAssignableTo(typeof(ICustomRole)))
|
||||
{
|
||||
AdvancedRole = roleType;
|
||||
}
|
||||
}
|
||||
|
||||
internal void ValueChanged(OptionBehaviour optionBehaviour)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
using MiraAPI.Networking;
|
||||
using System;
|
||||
using System;
|
||||
using MiraAPI.Networking;
|
||||
using UnityEngine;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
@@ -15,8 +15,7 @@ public class ModdedToggleOption : ModdedOption<bool>
|
||||
/// </summary>
|
||||
/// <param name="title">The option title.</param>
|
||||
/// <param name="defaultValue">The default value.</param>
|
||||
/// <param name="roleType">An optional role type.</param>
|
||||
public ModdedToggleOption(string title, bool defaultValue, Type? roleType = null) : base(title, defaultValue, roleType)
|
||||
public ModdedToggleOption(string title, bool defaultValue) : base(title, defaultValue)
|
||||
{
|
||||
Data = ScriptableObject.CreateInstance<CheckboxGameSetting>();
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
using MiraAPI.Events;
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using MiraAPI.Events;
|
||||
using MiraAPI.Events.Mira;
|
||||
using MiraAPI.Patches;
|
||||
using MiraAPI.Utilities.Assets;
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
using UnityEngine.UI;
|
||||
@@ -46,6 +46,11 @@ public abstract class CustomActionButton
|
||||
/// </summary>
|
||||
public virtual int MaxUses => 0;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the button's text outline color.
|
||||
/// </summary>
|
||||
public virtual Color TextOutlineColor => Color.clear;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the location of the button on the screen.
|
||||
/// </summary>
|
||||
@@ -114,6 +119,11 @@ public abstract class CustomActionButton
|
||||
Button.SetInfiniteUses();
|
||||
}
|
||||
|
||||
if (TextOutlineColor != Color.clear)
|
||||
{
|
||||
SetTextOutline(TextOutlineColor);
|
||||
}
|
||||
|
||||
var pb = Button.GetComponent<PassiveButton>();
|
||||
pb.OnClick = new Button.ButtonClickedEvent();
|
||||
pb.OnClick.AddListener((UnityAction)(() =>
|
||||
@@ -207,6 +217,16 @@ public abstract class CustomActionButton
|
||||
EffectActive = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A utility function to change the outline color of the button's text.
|
||||
/// </summary>
|
||||
/// <param name="color">The new color.</param>
|
||||
/// <param name="thickness">The thickness of the outline. Set to 0 if you want to remove it.</param>
|
||||
public virtual void SetTextOutline(Color color)
|
||||
{
|
||||
Button?.buttonLabelText.SetOutlineColor(color);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A utility function to override the sprite of the button.
|
||||
/// </summary>
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
using MiraAPI.Events.Mira;
|
||||
using MiraAPI.PluginLoading;
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Reflection;
|
||||
using MiraAPI.Events.Mira;
|
||||
using MiraAPI.PluginLoading;
|
||||
|
||||
namespace MiraAPI.Hud;
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
using AmongUs.GameOptions;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using AmongUs.GameOptions;
|
||||
using Il2CppInterop.Runtime.Attributes;
|
||||
using MiraAPI.Patches.Stubs;
|
||||
using Reactor.Utilities.Attributes;
|
||||
using Reactor.Utilities.Extensions;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
namespace MiraAPI.Modifiers;
|
||||
|
||||
/// <summary>
|
||||
/// Represents the assignment configuration for a game modifier.
|
||||
/// </summary>
|
||||
/// <param name="DefaultAmount">The default amount of players that can have this modifier in a game.</param>
|
||||
/// <param name="DefaultChance">The default chance of the modifier being assigned to a player.</param>
|
||||
/// <param name="CreateAmountOption">Whether Mira should create an amount option for the modifier.</param>
|
||||
/// <param name="CreateChanceOption">Whether Mira should create a chance option for the modifier.</param>
|
||||
public record struct AssignmentConfiguration(int DefaultAmount, int DefaultChance, bool CreateAmountOption, bool CreateChanceOption);
|
||||
@@ -1,11 +1,13 @@
|
||||
using System;
|
||||
using MiraAPI.GameOptions;
|
||||
using MiraAPI.PluginLoading;
|
||||
|
||||
namespace MiraAPI.Modifiers;
|
||||
|
||||
/// <summary>
|
||||
/// Base class for all modifiers.
|
||||
/// </summary>
|
||||
public abstract class BaseModifier
|
||||
public abstract class BaseModifier : IOptionable
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the player that the modifier is attached to.
|
||||
@@ -32,6 +34,14 @@ public abstract class BaseModifier
|
||||
/// </summary>
|
||||
public uint TypeId => ModifierManager.GetModifierTypeId(GetType()) ?? throw new InvalidOperationException("Modifier is not registered.");
|
||||
|
||||
/// <summary>
|
||||
/// Gets the parent mod of the modifier.
|
||||
/// </summary>
|
||||
public MiraPluginInfo ParentMod => Array.Find(
|
||||
MiraPluginManager.Instance.RegisteredPlugins(),
|
||||
x => x.Modifiers.Exists(y => y.TypeId == TypeId)
|
||||
) ?? throw new InvalidOperationException("Modifier is not registered.");
|
||||
|
||||
/// <summary>
|
||||
/// Gets the modifier name.
|
||||
/// </summary>
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
using Il2CppInterop.Runtime.Attributes;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Il2CppInterop.Runtime.Attributes;
|
||||
using MiraAPI.Modifiers.Types;
|
||||
using MiraAPI.Utilities;
|
||||
using Reactor.Utilities;
|
||||
using Reactor.Utilities.Attributes;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
|
||||
@@ -168,7 +169,7 @@ public class ModifierComponent(IntPtr cppPtr) : MonoBehaviour(cppPtr)
|
||||
/// <typeparam name="T">The Type of the Modifier.</typeparam>
|
||||
/// <returns>True if the modifier was found, false otherwise.</returns>
|
||||
[HideFromIl2Cpp]
|
||||
public bool TryGetModifier<T>(out T? modifier, Func<T, bool>? predicate = null) where T : BaseModifier
|
||||
public bool TryGetModifier<T>([NotNullWhen(true)] out T? modifier, Func<T, bool>? predicate = null) where T : BaseModifier
|
||||
{
|
||||
modifier = GetModifier(predicate);
|
||||
return modifier != null;
|
||||
@@ -182,7 +183,7 @@ public class ModifierComponent(IntPtr cppPtr) : MonoBehaviour(cppPtr)
|
||||
/// <param name="predicate">The predicate to check the modifier by.</param>
|
||||
/// <returns>True if the modifier was found, false otherwise.</returns>
|
||||
[HideFromIl2Cpp]
|
||||
public bool TryGetModifier(Type type, out BaseModifier? modifier, Func<BaseModifier, bool>? predicate = null)
|
||||
public bool TryGetModifier(Type type, [NotNullWhen(true)] out BaseModifier? modifier, Func<BaseModifier, bool>? predicate = null)
|
||||
{
|
||||
modifier = GetModifier(type, predicate);
|
||||
return modifier != null;
|
||||
@@ -196,7 +197,7 @@ public class ModifierComponent(IntPtr cppPtr) : MonoBehaviour(cppPtr)
|
||||
/// <param name="predicate">The predicate to check the modifier by.</param>
|
||||
/// <returns>True if the modifier was found, false otherwise.</returns>
|
||||
[HideFromIl2Cpp]
|
||||
public bool TryGetModifier(uint id, out BaseModifier? modifier, Func<BaseModifier, bool>? predicate = null)
|
||||
public bool TryGetModifier(uint id, [NotNullWhen(true)] out BaseModifier? modifier, Func<BaseModifier, bool>? predicate = null)
|
||||
{
|
||||
modifier = GetModifier(id, predicate);
|
||||
return modifier != null;
|
||||
@@ -209,7 +210,7 @@ public class ModifierComponent(IntPtr cppPtr) : MonoBehaviour(cppPtr)
|
||||
/// <param name="modifier">The modifier or null.</param>
|
||||
/// <returns>True if the modifier was found, false otherwise.</returns>
|
||||
[HideFromIl2Cpp]
|
||||
public bool TryGetModifier(Guid modifierGuid, out BaseModifier? modifier)
|
||||
public bool TryGetModifier(Guid modifierGuid, [NotNullWhen(true)] out BaseModifier? modifier)
|
||||
{
|
||||
modifier = GetModifier(modifierGuid);
|
||||
return modifier != null;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using MiraAPI.Networking;
|
||||
using MiraAPI.Networking.Modifiers;
|
||||
using Reactor.Networking.Attributes;
|
||||
@@ -190,6 +191,57 @@ public static class ModifierExtensions
|
||||
return player.GetModifierComponent().HasModifier(uniqueId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to get a modifier by its type.
|
||||
/// </summary>
|
||||
/// <param name="player">The PlayerControl instance.</param>
|
||||
/// <param name="modifier">The modifier or null.</param>
|
||||
/// <param name="predicate">The predicate to check the modifier by.</param>
|
||||
/// <typeparam name="T">The Type of the Modifier.</typeparam>
|
||||
/// <returns>True if the modifier was found, false otherwise.</returns>
|
||||
public static bool TryGetModifier<T>(this PlayerControl player, [NotNullWhen(true)] out T? modifier, Func<T, bool>? predicate = null) where T : BaseModifier
|
||||
{
|
||||
return player.GetModifierComponent().TryGetModifier(out modifier, predicate);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to get a modifier by its type.
|
||||
/// </summary>
|
||||
/// <param name="player">The PlayerControl instance.</param>
|
||||
/// <param name="type">The modifier type.</param>
|
||||
/// <param name="modifier">The modifier or null.</param>
|
||||
/// <param name="predicate">The predicate to check the modifier by.</param>
|
||||
/// <returns>True if the modifier was found, false otherwise.</returns>
|
||||
public static bool TryGetModifier(this PlayerControl player, Type type, [NotNullWhen(true)] out BaseModifier? modifier, Func<BaseModifier, bool>? predicate = null)
|
||||
{
|
||||
return player.GetModifierComponent().TryGetModifier(type, out modifier, predicate);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to get a modifier by its type ID.
|
||||
/// </summary>
|
||||
/// <param name="player">The PlayerControl instance.</param>
|
||||
/// <param name="id">The modifier type ID.</param>
|
||||
/// <param name="modifier">The modifier or null.</param>
|
||||
/// <param name="predicate">The predicate to check the modifier by.</param>
|
||||
/// <returns>True if the modifier was found, false otherwise.</returns>
|
||||
public static bool TryGetModifier(this PlayerControl player, uint id, [NotNullWhen(true)] out BaseModifier? modifier, Func<BaseModifier, bool>? predicate = null)
|
||||
{
|
||||
return player.GetModifierComponent().TryGetModifier(id, out modifier, predicate);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to get a modifier by its unique ID.
|
||||
/// </summary>
|
||||
/// <param name="player">The PlayerControl instance.</param>
|
||||
/// <param name="modifierGuid">The modifier unique ID.</param>
|
||||
/// <param name="modifier">The modifier or null.</param>
|
||||
/// <returns>True if the modifier was found, false otherwise.</returns>
|
||||
public static bool TryGetModifier(this PlayerControl player, Guid modifierGuid, [NotNullWhen(true)] out BaseModifier? modifier)
|
||||
{
|
||||
return player.GetModifierComponent().TryGetModifier(modifierGuid, out modifier);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a specific modifier from the player.
|
||||
/// </summary>
|
||||
|
||||
@@ -63,16 +63,32 @@ public static class ModifierManager
|
||||
|
||||
IdToTypeModifierMap.Add(GetNextTypeId(), modifierType);
|
||||
TypeToIdModifierMap.Add(modifierType, _nextTypeId);
|
||||
var bm = (BaseModifier)FormatterServices.GetUninitializedObject(modifierType); // this probably isn't a great idea
|
||||
info.Modifiers.Add(bm);
|
||||
|
||||
if (!typeof(GameModifier).IsAssignableFrom(modifierType))
|
||||
BaseModifier modifier;
|
||||
if (modifierType.GetConstructor(Type.EmptyTypes) != null)
|
||||
{
|
||||
modifier = (BaseModifier)Activator.CreateInstance(modifierType)!;
|
||||
}
|
||||
else
|
||||
{
|
||||
// this is probably terrible but its good enough for now.
|
||||
modifier = (BaseModifier)FormatterServices.GetUninitializedObject(modifierType);
|
||||
}
|
||||
|
||||
info.Modifiers.Add(modifier);
|
||||
|
||||
if (modifier is not GameModifier gameModifier)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
var mod = Activator.CreateInstance(modifierType) as GameModifier;
|
||||
var priority = mod!.Priority();
|
||||
if (modifierType.GetConstructor(Type.EmptyTypes) == null)
|
||||
{
|
||||
Logger<MiraApiPlugin>.Error($"Game Modifier {modifierType.FullName} does not have a parameterless constructor!");
|
||||
return false;
|
||||
}
|
||||
|
||||
var priority = gameModifier.Priority();
|
||||
|
||||
if (!PrioritiesToIdsMap.TryGetValue(priority, out var list))
|
||||
{
|
||||
|
||||
@@ -48,11 +48,17 @@ public class CustomGameOverRpc(MiraApiPlugin plugin, uint id) : PlayerCustomRpc<
|
||||
{
|
||||
if (GameOverManager.TryGetGameOver(data.Reason, out var gameOver))
|
||||
{
|
||||
if (!gameOver.VerifyCondition(innerNetObject, [.. data.Winners]))
|
||||
{
|
||||
Logger<MiraApiPlugin>.Info($"Game over condition not met for {gameOver.GetType().Name}");
|
||||
return;
|
||||
}
|
||||
|
||||
CustomGameOver.Instance = gameOver;
|
||||
|
||||
if (AmongUsClient.Instance.AmHost)
|
||||
{
|
||||
GameManager.Instance.RpcEndGame(gameOver!, false);
|
||||
GameManager.Instance.RpcEndGame(gameOver, false);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
using AmongUs.GameOptions;
|
||||
using System.Collections;
|
||||
using System.Linq;
|
||||
using AmongUs.GameOptions;
|
||||
using Assets.CoreScripts;
|
||||
using BepInEx.Unity.IL2CPP.Utils;
|
||||
using MiraAPI.Events;
|
||||
@@ -6,8 +8,6 @@ using MiraAPI.Events.Vanilla.Gameplay;
|
||||
using Reactor.Networking.Attributes;
|
||||
using Reactor.Networking.Rpc;
|
||||
using Reactor.Utilities.Extensions;
|
||||
using System.Collections;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
|
||||
namespace MiraAPI.Networking;
|
||||
|
||||
@@ -35,6 +35,6 @@ public class ModifierConverter : MessageConverter<BaseModifier>
|
||||
{
|
||||
var player = reader.ReadNetObject<PlayerControl>();
|
||||
var guid = new Guid(reader.ReadBytesAndSize());
|
||||
return player.GetModifier(guid) ?? throw new InvalidOperationException($"Modifier with GUID {guid} not found for player {player.NetId}.");
|
||||
return player.GetModifier(guid) ?? throw new InvalidOperationException($"Modifier with GUID {guid} not found for player with ID: {player.PlayerId}");
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
using HarmonyLib;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using HarmonyLib;
|
||||
using MiraAPI.Events;
|
||||
using MiraAPI.Events.Vanilla.Usables;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
|
||||
namespace MiraAPI.Patches.Events;
|
||||
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
using HarmonyLib;
|
||||
using MiraAPI.Events;
|
||||
using MiraAPI.Events.Vanilla.Meeting;
|
||||
using MiraAPI.Utilities;
|
||||
|
||||
namespace MiraAPI.Patches.Events;
|
||||
|
||||
[HarmonyPatch(typeof(PlayerControl), nameof(PlayerControl.CmdReportDeadBody))]
|
||||
public static class ReportBodyEventPatch
|
||||
{
|
||||
public static bool Prefix(PlayerControl __instance, NetworkedPlayerInfo? target)
|
||||
{
|
||||
var body = target != null ? Helpers.GetBodyById(target.PlayerId) : null;
|
||||
|
||||
var @event = new ReportBodyEvent(__instance, target, body);
|
||||
MiraEventManager.InvokeEvent(@event);
|
||||
return !@event.IsCancelled;
|
||||
}
|
||||
}
|
||||
@@ -1,21 +1,15 @@
|
||||
using HarmonyLib;
|
||||
using MiraAPI.Events;
|
||||
using MiraAPI.Events.Vanilla.Meeting;
|
||||
using MiraAPI.Utilities;
|
||||
|
||||
namespace MiraAPI.Patches.Events;
|
||||
|
||||
[HarmonyPatch]
|
||||
[HarmonyPatch(typeof(MeetingHud), nameof(MeetingHud.Start))]
|
||||
public static class StartMeetingEventPatch
|
||||
{
|
||||
[HarmonyPrefix]
|
||||
[HarmonyPatch(typeof(PlayerControl), nameof(PlayerControl.CmdReportDeadBody))]
|
||||
public static bool PlayerControlCmdReportDeadBodyPrefix(PlayerControl __instance, NetworkedPlayerInfo? target)
|
||||
public static void Postfix(MeetingHud __instance)
|
||||
{
|
||||
var body = target != null ? Helpers.GetBodyById(target.PlayerId) : null;
|
||||
|
||||
var @event = new StartMeetingEvent(__instance, target, body);
|
||||
var @event = new StartMeetingEvent(__instance);
|
||||
MiraEventManager.InvokeEvent(@event);
|
||||
return !@event.IsCancelled;
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
using HarmonyLib;
|
||||
using MiraAPI.Events;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using HarmonyLib;
|
||||
using MiraAPI.Events;
|
||||
using MiraAPI.Events.Vanilla.Usables;
|
||||
|
||||
namespace MiraAPI.Patches.Events;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using HarmonyLib;
|
||||
using System.Linq;
|
||||
using HarmonyLib;
|
||||
using MiraAPI.Events;
|
||||
using MiraAPI.Events.Vanilla.Usables;
|
||||
using System.Linq;
|
||||
|
||||
namespace MiraAPI.Patches.Events;
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@ using MiraAPI.Events;
|
||||
using MiraAPI.Events.Vanilla.Gameplay;
|
||||
using MiraAPI.Roles;
|
||||
using MiraAPI.Utilities;
|
||||
using UnityEngine;
|
||||
|
||||
namespace MiraAPI.Patches;
|
||||
|
||||
|
||||
@@ -1,12 +1,16 @@
|
||||
using HarmonyLib;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using HarmonyLib;
|
||||
using MiraAPI.GameOptions;
|
||||
using MiraAPI.Modifiers;
|
||||
using MiraAPI.Utilities;
|
||||
using MiraAPI.Utilities.Assets;
|
||||
using Reactor.Localization.Utilities;
|
||||
using Reactor.Utilities.Extensions;
|
||||
using System.Linq;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
namespace MiraAPI.Patches.Options;
|
||||
|
||||
@@ -30,64 +34,98 @@ public static class GameOptionsMenuPatch
|
||||
}
|
||||
|
||||
var num = 2.1f;
|
||||
var filteredGroups =
|
||||
GameSettingMenuPatches.SelectedMod?.OptionGroups.Where(
|
||||
x => x.AdvancedRole is null) ?? [];
|
||||
|
||||
foreach (var group in filteredGroups)
|
||||
if (__instance.name == "MODIFIERS TAB")
|
||||
{
|
||||
if (group.Options.Count == 0 || group.Header is null)
|
||||
ModifiersUpdate(ref num);
|
||||
}
|
||||
else
|
||||
{
|
||||
var filteredGroups =
|
||||
GameSettingMenuPatches.SelectedMod?.OptionGroups
|
||||
.Where(x => x.OptionableType == null) ?? [];
|
||||
|
||||
foreach (var group in filteredGroups)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!group.GroupVisible.Invoke())
|
||||
{
|
||||
group.Header.gameObject.SetActive(false);
|
||||
foreach (var option in group.Options)
|
||||
{
|
||||
option.OptionBehaviour?.gameObject.SetActive(false);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
group.Header.gameObject.SetActive(true);
|
||||
group.Header.transform.localScale = Vector3.one * 0.63f;
|
||||
group.Header.transform.localPosition = new Vector3(-0.903f, num, -2f);
|
||||
|
||||
num -= 0.58f;
|
||||
|
||||
foreach (var opt in group.Options)
|
||||
{
|
||||
var newOpt = opt.OptionBehaviour;
|
||||
|
||||
if (newOpt is null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!opt.Visible.Invoke())
|
||||
{
|
||||
newOpt.gameObject.SetActive(false);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!group.AllOptionsHidden)
|
||||
{
|
||||
newOpt.gameObject.SetActive(true);
|
||||
newOpt.transform.localPosition = new Vector3(0.952f, num, -2f);
|
||||
num -= 0.45f;
|
||||
}
|
||||
else
|
||||
{
|
||||
newOpt.gameObject.SetActive(false);
|
||||
}
|
||||
UpdateGroup(group, ref num);
|
||||
}
|
||||
}
|
||||
|
||||
__instance.scrollBar.SetYBoundsMax(-num - 1.65f);
|
||||
}
|
||||
|
||||
private static void UpdateGroup(AbstractOptionGroup group, ref float num)
|
||||
{
|
||||
if (group.Options.Count == 0 || group.Header is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!group.GroupVisible.Invoke())
|
||||
{
|
||||
group.Header.gameObject.SetActive(false);
|
||||
foreach (var option in group.Options)
|
||||
{
|
||||
option.OptionBehaviour?.gameObject.SetActive(false);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
group.Header.gameObject.SetActive(true);
|
||||
group.Header.transform.localScale = Vector3.one * 0.63f;
|
||||
group.Header.transform.localPosition = new Vector3(-0.903f, num, -2f);
|
||||
|
||||
num -= 0.58f;
|
||||
|
||||
foreach (var opt in group.Options)
|
||||
{
|
||||
var newOpt = opt.OptionBehaviour;
|
||||
|
||||
if (newOpt is null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!opt.Visible.Invoke())
|
||||
{
|
||||
newOpt.gameObject.SetActive(false);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!group.AllOptionsHidden)
|
||||
{
|
||||
newOpt.gameObject.SetActive(true);
|
||||
newOpt.transform.localPosition = new Vector3(0.952f, num, -2f);
|
||||
num -= 0.45f;
|
||||
}
|
||||
else
|
||||
{
|
||||
newOpt.gameObject.SetActive(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void ModifiersUpdate(ref float num)
|
||||
{
|
||||
var groups = GameSettingMenuPatches.SelectedMod?.OptionGroups
|
||||
.Where(x => x.ShowInModifiersMenu || x.OptionableType?.IsAssignableTo(typeof(BaseModifier))==true) ?? [];
|
||||
|
||||
foreach (var modGroup in groups)
|
||||
{
|
||||
UpdateGroup(modGroup, ref num);
|
||||
}
|
||||
}
|
||||
|
||||
private static void ModifiersCreate(GameOptionsMenu menu)
|
||||
{
|
||||
var groups = GameSettingMenuPatches.SelectedMod?.OptionGroups
|
||||
.Where(x => x.ShowInModifiersMenu || x.OptionableType?.IsAssignableTo(typeof(BaseModifier))==true) ?? [];
|
||||
foreach (var group in groups)
|
||||
{
|
||||
CreateGroup(menu, group);
|
||||
}
|
||||
}
|
||||
|
||||
[HarmonyPrefix]
|
||||
[HarmonyPatch(nameof(GameOptionsMenu.CreateSettings))]
|
||||
public static bool SettingsPatch(GameOptionsMenu __instance)
|
||||
@@ -99,106 +137,18 @@ public static class GameOptionsMenuPatch
|
||||
|
||||
__instance.MapPicker.gameObject.SetActive(false);
|
||||
|
||||
var filteredGroups = GameSettingMenuPatches.SelectedMod?.OptionGroups.Where(x => x.AdvancedRole is null) ?? [];
|
||||
if (__instance.name == "MODIFIERS TAB")
|
||||
{
|
||||
ModifiersCreate(__instance);
|
||||
return false;
|
||||
}
|
||||
|
||||
var filteredGroups = GameSettingMenuPatches.SelectedMod?.OptionGroups
|
||||
.Where(x => x.OptionableType == null) ?? [];
|
||||
|
||||
foreach (var group in filteredGroups)
|
||||
{
|
||||
var categoryHeaderMasked = Object.Instantiate(
|
||||
__instance.categoryHeaderOrigin,
|
||||
Vector3.zero,
|
||||
Quaternion.identity,
|
||||
__instance.settingsContainer);
|
||||
categoryHeaderMasked.SetHeader(CustomStringName.CreateAndRegister(group.GroupName), 20);
|
||||
if (group.GroupColor != Color.clear)
|
||||
{
|
||||
categoryHeaderMasked.Background.color = group.GroupColor;
|
||||
categoryHeaderMasked.Divider.color = group.GroupColor;
|
||||
categoryHeaderMasked.Title.color = group.GroupColor.GetAlternateColor();
|
||||
}
|
||||
|
||||
categoryHeaderMasked.Background.size = new Vector2(
|
||||
categoryHeaderMasked.Background.size.x + 1.5f,
|
||||
categoryHeaderMasked.Background.size.y);
|
||||
categoryHeaderMasked.gameObject.SetActive(false);
|
||||
group.Header = categoryHeaderMasked;
|
||||
|
||||
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 options = group.Options.Select(
|
||||
opt => opt.CreateOption(
|
||||
__instance.checkboxOrigin,
|
||||
__instance.numberOptionOrigin,
|
||||
__instance.stringOptionOrigin,
|
||||
__instance.settingsContainer));
|
||||
|
||||
foreach (var newOpt in options)
|
||||
{
|
||||
newOpt.SetClickMask(__instance.ButtonClickMask);
|
||||
|
||||
SpriteRenderer[] componentsInChildren = newOpt.GetComponentsInChildren<SpriteRenderer>(true);
|
||||
foreach (var renderer in componentsInChildren)
|
||||
{
|
||||
if (group.GroupColor != Color.clear)
|
||||
{
|
||||
renderer.color = group.GroupColor.GetAlternateColor();
|
||||
if (renderer.transform.parent.TryGetComponent<GameOptionButton>(out var btn))
|
||||
{
|
||||
btn.interactableColor = group.GroupColor.GetAlternateColor();
|
||||
btn.interactableHoveredColor = Color.white;
|
||||
}
|
||||
}
|
||||
|
||||
renderer.material.SetInt(PlayerMaterial.MaskLayer, 20);
|
||||
}
|
||||
|
||||
foreach (var textMeshPro in newOpt.GetComponentsInChildren<TextMeshPro>(true))
|
||||
{
|
||||
if (group.GroupColor != Color.clear)
|
||||
{
|
||||
textMeshPro.color = group.GroupColor;
|
||||
}
|
||||
|
||||
textMeshPro.fontMaterial.SetFloat(ShaderID.StencilComp, 3f);
|
||||
textMeshPro.fontMaterial.SetFloat(ShaderID.Stencil, 20);
|
||||
}
|
||||
|
||||
if (newOpt is ToggleOption toggle)
|
||||
{
|
||||
toggle.CheckMark.sprite = MiraAssets.Checkmark.LoadAsset();
|
||||
toggle.CheckMark.color =
|
||||
group.GroupColor != Color.clear ? group.GroupColor : MiraAssets.AcceptedTeal;
|
||||
var rend = toggle.CheckMark.transform.parent.FindChild("ActiveSprite")
|
||||
.GetComponent<SpriteRenderer>();
|
||||
rend.sprite = MiraAssets.CheckmarkBox.LoadAsset();
|
||||
rend.color = group.GroupColor != Color.clear ? group.GroupColor : MiraAssets.AcceptedTeal;
|
||||
}
|
||||
|
||||
__instance.Children.Add(newOpt);
|
||||
|
||||
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 = __instance.BackButton.GetComponent<PassiveButton>().ClickSound;
|
||||
headerBtn.OnMouseOver = new UnityEvent();
|
||||
headerBtn.OnMouseOut = new UnityEvent();
|
||||
headerBtn.OnClick.AddListener(
|
||||
(UnityAction)(() =>
|
||||
{
|
||||
group.AllOptionsHidden = !group.AllOptionsHidden;
|
||||
newText.text = group.AllOptionsHidden
|
||||
? "<size=70%>(Click to open)</size>"
|
||||
: "<size=70%>(Click to close)</size>";
|
||||
}));
|
||||
headerBtn.SetButtonEnableState(true);
|
||||
CreateGroup(__instance, group);
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -233,9 +183,110 @@ public static class GameOptionsMenuPatch
|
||||
continue;
|
||||
}
|
||||
|
||||
optionBehaviour.OnValueChanged = new System.Action<OptionBehaviour>(__instance.ValueChanged);
|
||||
optionBehaviour.OnValueChanged = new Action<OptionBehaviour>(__instance.ValueChanged);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static void CreateGroup(GameOptionsMenu menu, AbstractOptionGroup group)
|
||||
{
|
||||
var categoryHeaderMasked = Object.Instantiate(
|
||||
menu.categoryHeaderOrigin,
|
||||
Vector3.zero,
|
||||
Quaternion.identity,
|
||||
menu.settingsContainer);
|
||||
|
||||
categoryHeaderMasked.SetHeader(CustomStringName.CreateAndRegister(group.GroupName), 20);
|
||||
if (group.GroupColor != Color.clear)
|
||||
{
|
||||
categoryHeaderMasked.Background.color = group.GroupColor;
|
||||
categoryHeaderMasked.Divider.color = group.GroupColor;
|
||||
categoryHeaderMasked.Title.color = group.GroupColor.GetAlternateColor();
|
||||
}
|
||||
|
||||
categoryHeaderMasked.Background.size = new Vector2(
|
||||
categoryHeaderMasked.Background.size.x + 1.5f,
|
||||
categoryHeaderMasked.Background.size.y);
|
||||
categoryHeaderMasked.gameObject.SetActive(false);
|
||||
group.Header = categoryHeaderMasked;
|
||||
|
||||
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 options = group.Options.Select(
|
||||
opt => opt.CreateOption(
|
||||
menu.checkboxOrigin,
|
||||
menu.numberOptionOrigin,
|
||||
menu.stringOptionOrigin,
|
||||
menu.settingsContainer));
|
||||
|
||||
foreach (var newOpt in options)
|
||||
{
|
||||
newOpt.SetClickMask(menu.ButtonClickMask);
|
||||
|
||||
SpriteRenderer[] componentsInChildren = newOpt.GetComponentsInChildren<SpriteRenderer>(true);
|
||||
foreach (var renderer in componentsInChildren)
|
||||
{
|
||||
if (group.GroupColor != Color.clear)
|
||||
{
|
||||
renderer.color = group.GroupColor.GetAlternateColor();
|
||||
if (renderer.transform.parent.TryGetComponent<GameOptionButton>(out var btn))
|
||||
{
|
||||
btn.interactableColor = group.GroupColor.GetAlternateColor();
|
||||
btn.interactableHoveredColor = Color.white;
|
||||
}
|
||||
}
|
||||
|
||||
renderer.material.SetInt(PlayerMaterial.MaskLayer, 20);
|
||||
}
|
||||
|
||||
foreach (var textMeshPro in newOpt.GetComponentsInChildren<TextMeshPro>(true))
|
||||
{
|
||||
if (group.GroupColor != Color.clear)
|
||||
{
|
||||
textMeshPro.color = group.GroupColor;
|
||||
}
|
||||
|
||||
textMeshPro.fontMaterial.SetFloat(ShaderID.StencilComp, 3f);
|
||||
textMeshPro.fontMaterial.SetFloat(ShaderID.Stencil, 20);
|
||||
}
|
||||
|
||||
if (newOpt is ToggleOption toggle)
|
||||
{
|
||||
toggle.CheckMark.sprite = MiraAssets.Checkmark.LoadAsset();
|
||||
toggle.CheckMark.color =
|
||||
group.GroupColor != Color.clear ? group.GroupColor : MiraAssets.AcceptedTeal;
|
||||
var rend = toggle.CheckMark.transform.parent.FindChild("ActiveSprite")
|
||||
.GetComponent<SpriteRenderer>();
|
||||
rend.sprite = MiraAssets.CheckmarkBox.LoadAsset();
|
||||
rend.color = group.GroupColor != Color.clear ? group.GroupColor : MiraAssets.AcceptedTeal;
|
||||
}
|
||||
|
||||
menu.Children.Add(newOpt);
|
||||
|
||||
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)(() =>
|
||||
{
|
||||
group.AllOptionsHidden = !group.AllOptionsHidden;
|
||||
newText.text = group.AllOptionsHidden
|
||||
? "<size=70%>(Click to open)</size>"
|
||||
: "<size=70%>(Click to close)</size>";
|
||||
}));
|
||||
headerBtn.SetButtonEnableState(true);
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
using HarmonyLib;
|
||||
using System;
|
||||
using HarmonyLib;
|
||||
using MiraAPI.Modifiers;
|
||||
using MiraAPI.PluginLoading;
|
||||
using MiraAPI.Utilities.Assets;
|
||||
using Reactor.Utilities.Extensions;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
@@ -12,26 +12,41 @@ using Object = UnityEngine.Object;
|
||||
|
||||
namespace MiraAPI.Patches.Options;
|
||||
|
||||
/// <summary>
|
||||
/// Patches for the <see cref="GameSettingMenu"/> to add support for custom options.
|
||||
/// </summary>
|
||||
[HarmonyPatch(typeof(GameSettingMenu))]
|
||||
public static class GameSettingMenuPatches
|
||||
internal static class GameSettingMenuPatches
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the currently selected mod index.
|
||||
/// </summary>
|
||||
public static int SelectedModIdx { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the currently selected mod.
|
||||
/// </summary>
|
||||
public static MiraPluginInfo? SelectedMod { get; private set; }
|
||||
|
||||
private static TextMeshPro? _text;
|
||||
|
||||
private static Vector3 _roleBtnOgPos;
|
||||
|
||||
private static GameOptionsMenu? _modifiersTab;
|
||||
private static PassiveButton? _modifiersButton;
|
||||
private static PassiveButton? _smallRolesButton;
|
||||
|
||||
[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);
|
||||
_modifiersButton?.SelectButton(tabNum == 3);
|
||||
_smallRolesButton?.SelectButton(tabNum == 2);
|
||||
}
|
||||
|
||||
if (previewOnly)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_modifiersButton?.SelectButton(tabNum == 3);
|
||||
_smallRolesButton?.SelectButton(tabNum == 2);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Prefix for the <see cref="GameSettingMenu.Start"/> method. Sets up the custom options.
|
||||
/// </summary>
|
||||
@@ -54,43 +69,116 @@ public static class GameSettingMenuPatches
|
||||
_text.fontSizeMax = 3.2f;
|
||||
_text.overflowMode = TextOverflowModes.Overflow;
|
||||
|
||||
UpdateText(__instance, __instance.GameSettingsTab, __instance.RoleSettingsTab);
|
||||
|
||||
_text.alignment = TextAlignmentOptions.Center;
|
||||
|
||||
var nextButton = Object.Instantiate(__instance.BackButton, __instance.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.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 passiveButton = nextButton.gameObject.GetComponent<PassiveButton>();
|
||||
passiveButton.OnClick = new ButtonClickedEvent();
|
||||
passiveButton.OnClick.AddListener((UnityAction)(() =>
|
||||
{
|
||||
SelectedModIdx += 1;
|
||||
if (SelectedModIdx > MiraPluginManager.Instance.RegisteredPlugins().Length)
|
||||
passiveButton.OnClick.AddListener(
|
||||
(UnityAction)(() =>
|
||||
{
|
||||
SelectedModIdx = 0;
|
||||
}
|
||||
UpdateText(__instance, __instance.GameSettingsTab, __instance.RoleSettingsTab);
|
||||
}));
|
||||
SelectedModIdx += 1;
|
||||
if (SelectedModIdx > MiraPluginManager.Instance.RegisteredPlugins().Length)
|
||||
{
|
||||
SelectedModIdx = 0;
|
||||
}
|
||||
|
||||
UpdateText(__instance, __instance.GameSettingsTab, __instance.RoleSettingsTab);
|
||||
}));
|
||||
|
||||
var backButton = Object.Instantiate(nextButton, __instance.BackButton.transform.parent).gameObject;
|
||||
backButton.transform.localPosition = new Vector3(-4.4209f, 1.5272f, -25f);
|
||||
backButton.name = "LeftArrowButton";
|
||||
backButton.gameObject.GetComponent<CloseButtonConsoleBehaviour>().Destroy();
|
||||
backButton.transform.FindChild("Active").gameObject.GetComponent<SpriteRenderer>().flipX = backButton.transform.FindChild("Inactive").gameObject.GetComponent<SpriteRenderer>().flipX = true;
|
||||
backButton.gameObject.GetComponent<PassiveButton>().OnClick.AddListener((UnityAction)(() =>
|
||||
{
|
||||
SelectedModIdx -= 1;
|
||||
if (SelectedModIdx < 0)
|
||||
backButton.transform.FindChild("Active").gameObject.GetComponent<SpriteRenderer>().flipX =
|
||||
backButton.transform.FindChild("Inactive").gameObject.GetComponent<SpriteRenderer>().flipX = true;
|
||||
backButton.gameObject.GetComponent<PassiveButton>().OnClick.AddListener(
|
||||
(UnityAction)(() =>
|
||||
{
|
||||
SelectedModIdx = MiraPluginManager.Instance.RegisteredPlugins().Length;
|
||||
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";
|
||||
|
||||
// create button for modifiers
|
||||
__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);
|
||||
}));
|
||||
|
||||
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)
|
||||
{
|
||||
if (collider.TryCast<BoxCollider2D>() is { } col)
|
||||
{
|
||||
col.size = new Vector2(col.size.x / 2, col.size.y);
|
||||
}
|
||||
UpdateText(__instance, __instance.GameSettingsTab, __instance.RoleSettingsTab);
|
||||
}));
|
||||
}
|
||||
|
||||
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";
|
||||
|
||||
UpdateText(__instance, __instance.GameSettingsTab, __instance.RoleSettingsTab);
|
||||
}
|
||||
|
||||
private static void UpdateText(GameSettingMenu menu, GameOptionsMenu settings, RolesSettingsMenu roles)
|
||||
@@ -109,10 +197,30 @@ public static class GameSettingMenuPatches
|
||||
_text.text = name[..Math.Min(name.Length, 25)];
|
||||
}
|
||||
|
||||
menu.RoleSettingsButton.transform.localPosition = _roleBtnOgPos;
|
||||
menu.GameSettingsButton.gameObject.SetActive(true);
|
||||
menu.RoleSettingsButton.gameObject.SetActive(true);
|
||||
_modifiersButton.gameObject.SetActive(false);
|
||||
_smallRolesButton.gameObject.SetActive(false);
|
||||
menu.RoleSettingsButton.gameObject.SetActive(false);
|
||||
if (SelectedModIdx != 0 &&
|
||||
SelectedMod?.OptionGroups.Exists(x => x.ShowInModifiersMenu || x.OptionableType?.IsAssignableTo(typeof(BaseModifier)) == true) == true)
|
||||
{
|
||||
_modifiersButton.gameObject.SetActive(true);
|
||||
_smallRolesButton.gameObject.SetActive(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
menu.RoleSettingsButton.gameObject.SetActive(true);
|
||||
if (SelectedModIdx == 0 && _modifiersTab.gameObject.active)
|
||||
{
|
||||
menu.ChangeTab(0, false);
|
||||
}
|
||||
}
|
||||
|
||||
//menu.RoleSettingsButton.transform.localPosition = _roleBtnOgPos;
|
||||
//menu.GameSettingsButton.gameObject.SetActive(true);
|
||||
//menu.RoleSettingsButton.gameObject.SetActive(true);
|
||||
|
||||
// TODO: reimplement this
|
||||
/*
|
||||
if (SelectedModIdx != 0)
|
||||
{
|
||||
if (SelectedMod?.Options.Where(x=>x.AdvancedRole==null).ToList().Count == 0)
|
||||
@@ -129,7 +237,7 @@ public static class GameSettingMenuPatches
|
||||
{
|
||||
menu.RoleSettingsButton.transform.localPosition = menu.GameSettingsButton.transform.localPosition;
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
if (roles.roleChances != null && SelectedMod != null && SelectedMod.CustomRoles.Count != 0)
|
||||
{
|
||||
@@ -139,11 +247,13 @@ public static class GameSettingMenuPatches
|
||||
{
|
||||
child.gameObject.DestroyImmediate();
|
||||
}
|
||||
|
||||
roles.advancedSettingChildren.Clear();
|
||||
roles.advancedSettingChildren = null;
|
||||
}
|
||||
|
||||
foreach (var header in roles.RoleChancesSettings.transform.GetComponentsInChildren<CategoryHeaderEditRole>())
|
||||
foreach (var header in roles.RoleChancesSettings.transform
|
||||
.GetComponentsInChildren<CategoryHeaderEditRole>())
|
||||
{
|
||||
header.gameObject.DestroyImmediate();
|
||||
}
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
using HarmonyLib;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using HarmonyLib;
|
||||
using MiraAPI.GameOptions;
|
||||
using MiraAPI.Modifiers;
|
||||
using MiraAPI.PluginLoading;
|
||||
using MiraAPI.Roles;
|
||||
using MiraAPI.Utilities;
|
||||
using MiraAPI.Utilities.Assets;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Reactor.Localization.Utilities;
|
||||
using Reactor.Utilities.Extensions;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
using UnityEngine.UI;
|
||||
@@ -17,17 +20,38 @@ namespace MiraAPI.Patches.Options;
|
||||
[HarmonyPatch(typeof(LobbyViewSettingsPane))]
|
||||
public static class LobbyViewPanePatches
|
||||
{
|
||||
private static int CurrentSelectedMod { get; set; }
|
||||
private static int SelectedModIdx { get; set; }
|
||||
|
||||
private static MiraPluginInfo? SelectedMod => CurrentSelectedMod == 0
|
||||
private static MiraPluginInfo? SelectedMod => SelectedModIdx == 0
|
||||
? null
|
||||
: MiraPluginManager.Instance.RegisteredPlugins()[CurrentSelectedMod - 1];
|
||||
: MiraPluginManager.Instance.RegisteredPlugins()[SelectedModIdx - 1];
|
||||
|
||||
private static PassiveButton? ModifiersTabButton { get; set; }
|
||||
|
||||
private static StringNames ModifiersTabName { get; } = CustomStringName.CreateAndRegister("ModifiersTab");
|
||||
|
||||
[HarmonyPostfix]
|
||||
[HarmonyPatch(nameof(LobbyViewSettingsPane.Awake))]
|
||||
public static void AwakePatch(LobbyViewSettingsPane __instance)
|
||||
{
|
||||
__instance.gameModeText.transform.localPosition = new Vector3(-2.3f, 2.4f, -2);
|
||||
__instance.gameModeText.GetComponent<TextTranslatorTMP>().Destroy();
|
||||
|
||||
// create modifiers button
|
||||
ModifiersTabButton = Object.Instantiate(__instance.rolesTabButton, __instance.rolesTabButton.transform.parent);
|
||||
ModifiersTabButton.buttonText.gameObject.GetComponent<TextTranslatorTMP>().Destroy();
|
||||
ModifiersTabButton.name = "ModifiersTabButton";
|
||||
var pos = ModifiersTabButton.transform.localPosition;
|
||||
pos.x = 2.1f;
|
||||
ModifiersTabButton.transform.localPosition = pos;
|
||||
ModifiersTabButton.buttonText.text = "Modifiers";
|
||||
ModifiersTabButton.OnClick = new Button.ButtonClickedEvent();
|
||||
ModifiersTabButton.OnClick.AddListener(
|
||||
(UnityAction)(() =>
|
||||
{
|
||||
__instance.ChangeTab(ModifiersTabName);
|
||||
}));
|
||||
ModifiersTabButton.gameObject.SetActive(SelectedModIdx!=0);
|
||||
|
||||
// Create the next button
|
||||
var nextButton = Object.Instantiate(__instance.BackButton, __instance.BackButton.transform.parent).gameObject;
|
||||
@@ -49,14 +73,13 @@ public static class LobbyViewPanePatches
|
||||
passiveButton.OnClick.AddListener(
|
||||
(UnityAction)(() =>
|
||||
{
|
||||
CurrentSelectedMod += 1;
|
||||
if (CurrentSelectedMod > MiraPluginManager.Instance.RegisteredPlugins().Length)
|
||||
SelectedModIdx += 1;
|
||||
if (SelectedModIdx > MiraPluginManager.Instance.RegisteredPlugins().Length)
|
||||
{
|
||||
CurrentSelectedMod = 0;
|
||||
SelectedModIdx = 0;
|
||||
}
|
||||
|
||||
__instance.RefreshTab();
|
||||
__instance.scrollBar.ScrollToTop();
|
||||
Refresh(__instance);
|
||||
}));
|
||||
|
||||
// Create the back button
|
||||
@@ -72,34 +95,56 @@ public static class LobbyViewPanePatches
|
||||
passiveButton2.OnClick.AddListener(
|
||||
(UnityAction)(() =>
|
||||
{
|
||||
CurrentSelectedMod -= 1;
|
||||
if (CurrentSelectedMod < 0)
|
||||
SelectedModIdx -= 1;
|
||||
if (SelectedModIdx < 0)
|
||||
{
|
||||
CurrentSelectedMod = MiraPluginManager.Instance.RegisteredPlugins().Length;
|
||||
SelectedModIdx = MiraPluginManager.Instance.RegisteredPlugins().Length;
|
||||
}
|
||||
|
||||
__instance.RefreshTab();
|
||||
__instance.scrollBar.ScrollToTop();
|
||||
Refresh(__instance);
|
||||
}));
|
||||
}
|
||||
|
||||
[HarmonyPostfix]
|
||||
[HarmonyPatch(nameof(LobbyViewSettingsPane.Update))]
|
||||
public static void UpdatePatch(LobbyViewSettingsPane __instance)
|
||||
private static void Refresh(LobbyViewSettingsPane menu)
|
||||
{
|
||||
__instance.gameModeText.text = SelectedMod?.PluginInfo.Metadata.Name ?? "Default";
|
||||
ModifiersTabButton?.gameObject.SetActive(SelectedModIdx != 0);
|
||||
menu.gameModeText.text = SelectedMod?.PluginInfo.Metadata.Name ?? "Default";
|
||||
menu.RefreshTab();
|
||||
menu.scrollBar.ScrollToTop();
|
||||
}
|
||||
|
||||
[HarmonyPrefix]
|
||||
[HarmonyPatch(nameof(LobbyViewSettingsPane.SetTab))]
|
||||
public static bool SetTabPatch(LobbyViewSettingsPane __instance)
|
||||
{
|
||||
if (__instance.currentTab != ModifiersTabName || SelectedMod == null)
|
||||
{
|
||||
ModifiersTabButton?.SelectButton(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
__instance.taskTabButton.SelectButton(false);
|
||||
__instance.rolesTabButton.SelectButton(false);
|
||||
|
||||
ModifiersTabButton?.SelectButton(true);
|
||||
var filteredGroups = SelectedMod.OptionGroups
|
||||
.Where(x => x.GroupVisible() && (x.ShowInModifiersMenu || x.OptionableType?.IsAssignableTo(typeof(BaseModifier))==true));
|
||||
DrawOptions(__instance, filteredGroups);
|
||||
return false;
|
||||
}
|
||||
|
||||
[HarmonyPrefix]
|
||||
[HarmonyPatch(nameof(LobbyViewSettingsPane.DrawNormalTab))]
|
||||
public static bool DrawNormalTabPatch(LobbyViewSettingsPane __instance)
|
||||
{
|
||||
if (CurrentSelectedMod == 0)
|
||||
if (SelectedModIdx == 0 || SelectedMod == null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
DrawOptionsTab(__instance);
|
||||
var filteredGroups = SelectedMod.OptionGroups
|
||||
.Where(x => x.OptionableType == null && x.GroupVisible.Invoke());
|
||||
DrawOptions(__instance, filteredGroups);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -107,7 +152,7 @@ public static class LobbyViewPanePatches
|
||||
[HarmonyPatch(nameof(LobbyViewSettingsPane.DrawRolesTab))]
|
||||
public static bool DrawRolesTabPatch(LobbyViewSettingsPane __instance)
|
||||
{
|
||||
if (CurrentSelectedMod == 0)
|
||||
if (SelectedModIdx == 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@@ -116,29 +161,22 @@ public static class LobbyViewPanePatches
|
||||
return false;
|
||||
}
|
||||
|
||||
private static void DrawOptionsTab(LobbyViewSettingsPane instance)
|
||||
private static void DrawOptions(LobbyViewSettingsPane menu, IEnumerable<AbstractOptionGroup> groups)
|
||||
{
|
||||
if (SelectedMod == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var num = 1.44f;
|
||||
|
||||
var filteredGroups = SelectedMod.OptionGroups.Where(x => x.GroupVisible.Invoke() && x.AdvancedRole is null);
|
||||
|
||||
foreach (var group in filteredGroups)
|
||||
foreach (var group in groups)
|
||||
{
|
||||
var categoryHeaderMasked = Object.Instantiate(
|
||||
instance.categoryHeaderOrigin,
|
||||
instance.settingsContainer,
|
||||
menu.categoryHeaderOrigin,
|
||||
menu.settingsContainer,
|
||||
true);
|
||||
categoryHeaderMasked.SetHeader(StringNames.Name, 61);
|
||||
categoryHeaderMasked.Title.text = group.GroupName;
|
||||
categoryHeaderMasked.transform.localScale = Vector3.one;
|
||||
categoryHeaderMasked.transform.localPosition = new Vector3(-9.77f, num, -2f);
|
||||
instance.settingsInfo.Add(categoryHeaderMasked.gameObject);
|
||||
num -= 0.85f;
|
||||
menu.settingsInfo.Add(categoryHeaderMasked.gameObject);
|
||||
num -= 1.05f;
|
||||
|
||||
var i = 0;
|
||||
|
||||
@@ -150,8 +188,8 @@ public static class LobbyViewPanePatches
|
||||
}
|
||||
|
||||
var viewSettingsInfoPanel = Object.Instantiate(
|
||||
instance.infoPanelOrigin,
|
||||
instance.settingsContainer,
|
||||
menu.infoPanelOrigin,
|
||||
menu.settingsContainer,
|
||||
true);
|
||||
viewSettingsInfoPanel.transform.localScale = Vector3.one;
|
||||
float num2;
|
||||
@@ -160,7 +198,7 @@ public static class LobbyViewPanePatches
|
||||
num2 = -8.95f;
|
||||
if (i > 0)
|
||||
{
|
||||
num -= 0.59f;
|
||||
num -= 0.85f;
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -184,14 +222,14 @@ public static class LobbyViewPanePatches
|
||||
viewSettingsInfoPanel.SetInfo(data.Title, data.GetValueString(option.GetFloatData()), 61);
|
||||
}
|
||||
|
||||
instance.settingsInfo.Add(viewSettingsInfoPanel.gameObject);
|
||||
menu.settingsInfo.Add(viewSettingsInfoPanel.gameObject);
|
||||
i++;
|
||||
}
|
||||
|
||||
num -= 0.59f;
|
||||
num -= 0.85f;
|
||||
}
|
||||
|
||||
instance.scrollBar.CalculateAndSetYBounds(instance.settingsInfo.Count + 10, 2f, 6f, 0.59f);
|
||||
menu.scrollBar.CalculateAndSetYBounds(menu.settingsInfo.Count + 10, 2f, 6f, 0.85f);
|
||||
}
|
||||
|
||||
private static void DrawRolesTab(LobbyViewSettingsPane instance)
|
||||
@@ -277,8 +315,9 @@ public static class LobbyViewPanePatches
|
||||
viewSettingsInfoPanelRoleVariant.transform.localScale = Vector3.one;
|
||||
viewSettingsInfoPanelRoleVariant.transform.localPosition = new Vector3(num2, num, -2f);
|
||||
|
||||
var advancedRoleOptions = SelectedMod.Options
|
||||
.Where(x => x.AdvancedRole == customRole.GetType())
|
||||
var advancedRoleOptions = SelectedMod.OptionGroups
|
||||
.Where(x => x.OptionableType == customRole.GetType())
|
||||
.SelectMany(x => x.Options)
|
||||
.ToList();
|
||||
|
||||
if (numPerGame > 0 && advancedRoleOptions.Count > 0)
|
||||
@@ -386,8 +425,9 @@ public static class LobbyViewPanePatches
|
||||
var num = viewPanel.yPosStart;
|
||||
var num2 = 1.08f;
|
||||
|
||||
var filteredOptions = SelectedMod.Options
|
||||
.Where(x => x.AdvancedRole == roleType)
|
||||
var filteredOptions = SelectedMod.OptionGroups
|
||||
.Where(x => x.OptionableType == roleType)
|
||||
.SelectMany(x=>x.Options)
|
||||
.ToList();
|
||||
|
||||
for (var i = 0; i < filteredOptions.Count; i++)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using HarmonyLib;
|
||||
using System.Linq;
|
||||
using HarmonyLib;
|
||||
using Il2CppSystem;
|
||||
using MiraAPI.Roles;
|
||||
using System.Linq;
|
||||
|
||||
namespace MiraAPI.Patches.Options;
|
||||
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
using HarmonyLib;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using HarmonyLib;
|
||||
using Il2CppInterop.Runtime.InteropTypes.Arrays;
|
||||
using MiraAPI.Networking;
|
||||
using MiraAPI.Roles;
|
||||
@@ -8,9 +11,6 @@ using Reactor.Localization.Utilities;
|
||||
using Reactor.Networking.Rpc;
|
||||
using Reactor.Utilities;
|
||||
using Reactor.Utilities.Extensions;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
@@ -304,15 +304,14 @@ public static class RoleSettingMenuPatches
|
||||
var hasImage = role.RoleScreenshot != null;
|
||||
var num = hasImage ? -0.872f : -1;
|
||||
|
||||
var filteredOptions = GameSettingMenuPatches.SelectedMod?.Options.Where(x => x.AdvancedRole == role.GetType()) ?? [];
|
||||
// TODO: create sub groups under the role settings.
|
||||
var filteredOptions = GameSettingMenuPatches.SelectedMod?.OptionGroups
|
||||
.Where(x=> x.OptionableType == role.GetType())
|
||||
.SelectMany(x=>x.Options)
|
||||
.ToList() ?? [];
|
||||
|
||||
foreach (var option in filteredOptions)
|
||||
{
|
||||
if (option.AdvancedRole is not null && option.AdvancedRole != role.GetType())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var newOpt = option.CreateOption(
|
||||
__instance.checkboxOrigin,
|
||||
__instance.numberOptionOrigin,
|
||||
@@ -470,8 +469,8 @@ public static class RoleSettingMenuPatches
|
||||
roleOptionSetting.titleText.horizontalAlignment = HorizontalAlignmentOptions.Left;
|
||||
|
||||
if (GameSettingMenuPatches.SelectedMod is null ||
|
||||
GameSettingMenuPatches.SelectedMod.Options.Exists(
|
||||
x => x.AdvancedRole != null && x.AdvancedRole.IsInstanceOfType(role)))
|
||||
GameSettingMenuPatches.SelectedMod.OptionGroups
|
||||
.Exists(x => x.OptionableType == role.GetType()))
|
||||
{
|
||||
var newButton = Object.Instantiate(roleOptionSetting.buttons[0], roleOptionSetting.transform);
|
||||
newButton.name = "ConfigButton";
|
||||
@@ -504,7 +503,7 @@ public static class RoleSettingMenuPatches
|
||||
|
||||
if (index < GameSettingMenuPatches.SelectedMod?.CustomRoles.Count - 1)
|
||||
{
|
||||
ScrollerNum += -0.43f;
|
||||
ScrollerNum -= 0.43f;
|
||||
}
|
||||
|
||||
return roleOptionSetting;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using HarmonyLib;
|
||||
using System.Linq;
|
||||
using HarmonyLib;
|
||||
using MiraAPI.Events;
|
||||
using MiraAPI.Events.Vanilla.Gameplay;
|
||||
using MiraAPI.Events.Vanilla.Player;
|
||||
@@ -6,7 +7,6 @@ using MiraAPI.Hud;
|
||||
using MiraAPI.Modifiers;
|
||||
using MiraAPI.Roles;
|
||||
using Reactor.Utilities.Extensions;
|
||||
using System.Linq;
|
||||
|
||||
namespace MiraAPI.Patches;
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
using AmongUs.GameOptions;
|
||||
using System.Linq;
|
||||
using AmongUs.GameOptions;
|
||||
using HarmonyLib;
|
||||
using MiraAPI.Events;
|
||||
using MiraAPI.Events.Vanilla.Gameplay;
|
||||
using MiraAPI.Modifiers;
|
||||
using MiraAPI.Roles;
|
||||
using System.Linq;
|
||||
|
||||
namespace MiraAPI.Patches.Roles;
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
using BepInEx;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using BepInEx;
|
||||
using BepInEx.Configuration;
|
||||
using MiraAPI.GameModes;
|
||||
using MiraAPI.GameOptions;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using MiraAPI.Hud;
|
||||
using MiraAPI.Modifiers;
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using BepInEx.Unity.IL2CPP;
|
||||
@@ -49,6 +50,23 @@ public sealed class MiraPluginManager
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach (var method in type.GetMethods(BindingFlags.Static | BindingFlags.Public))
|
||||
{
|
||||
var eventAttribute = method.GetCustomAttribute<RegisterEventAttribute>();
|
||||
if (eventAttribute != null)
|
||||
{
|
||||
var parameters = method.GetParameters();
|
||||
if (parameters.Length != 1 || !parameters[0].ParameterType.IsSubclassOf(typeof(MiraEvent)))
|
||||
{
|
||||
Logger<MiraApiPlugin>.Error($"Invalid event registration method {method.Name} in {type.Name}");
|
||||
continue;
|
||||
}
|
||||
|
||||
var paramType = parameters[0].ParameterType;
|
||||
MiraEventManager.RegisterEventHandler(paramType, method, eventAttribute.Priority);
|
||||
}
|
||||
}
|
||||
|
||||
if (RegisterModifier(type, info))
|
||||
{
|
||||
continue;
|
||||
@@ -61,7 +79,7 @@ public sealed class MiraPluginManager
|
||||
|
||||
if (RegisterRoleAttribute(type, info, out var role))
|
||||
{
|
||||
roles.Add(role!);
|
||||
roles.Add(role);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -155,7 +173,7 @@ public sealed class MiraPluginManager
|
||||
return false;
|
||||
}
|
||||
|
||||
private static bool RegisterRoleAttribute(Type type, MiraPluginInfo pluginInfo, out Type? role)
|
||||
private static bool RegisterRoleAttribute(Type type, MiraPluginInfo pluginInfo, [NotNullWhen(true)] out Type? role)
|
||||
{
|
||||
role = null;
|
||||
try
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
using AmongUs.GameOptions;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using AmongUs.GameOptions;
|
||||
using Il2CppInterop.Runtime;
|
||||
using Il2CppInterop.Runtime.Injection;
|
||||
using MiraAPI.Networking;
|
||||
@@ -8,9 +11,6 @@ using Reactor.Localization.Utilities;
|
||||
using Reactor.Networking.Rpc;
|
||||
using Reactor.Utilities;
|
||||
using Reactor.Utilities.Extensions;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
using BepInEx.Configuration;
|
||||
using System.Text;
|
||||
using BepInEx.Configuration;
|
||||
using MiraAPI.GameOptions;
|
||||
using MiraAPI.Modifiers;
|
||||
using MiraAPI.PluginLoading;
|
||||
using MiraAPI.Utilities;
|
||||
using Reactor.Utilities;
|
||||
using System.Text;
|
||||
using UnityEngine;
|
||||
|
||||
namespace MiraAPI.Roles;
|
||||
@@ -11,7 +12,7 @@ namespace MiraAPI.Roles;
|
||||
/// <summary>
|
||||
/// Interface for custom roles.
|
||||
/// </summary>
|
||||
public interface ICustomRole
|
||||
public interface ICustomRole : IOptionable
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the name of the role.
|
||||
@@ -46,7 +47,7 @@ public interface ICustomRole
|
||||
/// <summary>
|
||||
/// Gets the role options group.
|
||||
/// </summary>
|
||||
public RoleOptionsGroup RoleOptionsGroup => Team switch
|
||||
RoleOptionsGroup RoleOptionsGroup => Team switch
|
||||
{
|
||||
ModdedRoleTeams.Crewmate => RoleOptionsGroup.Crewmate,
|
||||
ModdedRoleTeams.Impostor => RoleOptionsGroup.Impostor,
|
||||
@@ -57,7 +58,7 @@ public interface ICustomRole
|
||||
/// <summary>
|
||||
/// Gets the role's TeamIntroCutscene configuration.
|
||||
/// </summary>
|
||||
public TeamIntroConfiguration? IntroConfiguration => Team switch
|
||||
TeamIntroConfiguration? IntroConfiguration => Team switch
|
||||
{
|
||||
ModdedRoleTeams.Custom => TeamIntroConfiguration.Neutral,
|
||||
_ => null,
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using HarmonyLib;
|
||||
using MiraAPI.GameOptions;
|
||||
using MiraAPI.Networking;
|
||||
using MiraAPI.Roles;
|
||||
using Reactor.Utilities;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
|
||||
@@ -39,6 +39,16 @@ public static class Extensions
|
||||
BitConverter.GetBytes(count.Value).AddRangeToArray(BitConverter.GetBytes(chance.Value)));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines if a float is an integer.
|
||||
/// </summary>
|
||||
/// <param name="number">The float number.</param>
|
||||
/// <returns>True if the float is an integer, false otherwise.</returns>
|
||||
public static bool IsInteger(this float number)
|
||||
{
|
||||
return Mathf.Approximately(number, Mathf.Round(number));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the best constructor for a type based on the specified arguments.
|
||||
/// </summary>
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
using MiraAPI.Roles;
|
||||
using System.Collections;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using MiraAPI.Roles;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
Reference in new issue
Block a user