From e22032e1fbe2d0cf56b65ace0b83a045fc7b327f Mon Sep 17 00:00:00 2001
From: XtraCube <72575280+XtraCube@users.noreply.github.com>
Date: Sun, 1 Sep 2024 15:53:09 -0400
Subject: [PATCH 01/36] fix neutral naming from outcast
---
MiraAPI/Patches/IntroCutscenePatches.cs | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/MiraAPI/Patches/IntroCutscenePatches.cs b/MiraAPI/Patches/IntroCutscenePatches.cs
index 01066c3..3dab1ed 100644
--- a/MiraAPI/Patches/IntroCutscenePatches.cs
+++ b/MiraAPI/Patches/IntroCutscenePatches.cs
@@ -19,7 +19,7 @@ public static void BeginImpostorPatch(IntroCutscene __instance)
__instance.TeamTitle.text = $"{mode.Name}\n{mode.Description}";
}
}*/
-
+
[HarmonyPrefix]
[HarmonyPatch(nameof(IntroCutscene.BeginCrewmate))]
public static bool BeginCrewmatePatch(IntroCutscene __instance)
@@ -37,9 +37,9 @@ public static bool BeginCrewmatePatch(IntroCutscene __instance)
barTransform.position = position;
__instance.BackgroundBar.material.SetColor(ShaderID.Color, Color.gray);
- __instance.TeamTitle.text = "OUTCAST";
+ __instance.TeamTitle.text = "NEUTRAL";
__instance.impostorScale = 1f;
- __instance.ImpostorText.text = "You are an Outcast. You do not have a team.";
+ __instance.ImpostorText.text = "You are Neutral. You do not have a team.";
__instance.TeamTitle.color = Color.gray;
__instance.ourCrewmate = __instance.CreatePlayer(0, Mathf.CeilToInt(7.5f), PlayerControl.LocalPlayer.Data, false);
From 2b71438cd02c71ed1e7f8c42deaef6e477a08617 Mon Sep 17 00:00:00 2001
From: XtraCube <72575280+XtraCube@users.noreply.github.com>
Date: Sun, 1 Sep 2024 15:53:33 -0400
Subject: [PATCH 02/36] fix button reset after meeting
---
.../ButtonResetPatches.cs} | 18 +++++++++---------
1 file changed, 9 insertions(+), 9 deletions(-)
rename MiraAPI/Patches/{MeetingHudPatches.cs => Hud/ButtonResetPatches.cs} (56%)
diff --git a/MiraAPI/Patches/MeetingHudPatches.cs b/MiraAPI/Patches/Hud/ButtonResetPatches.cs
similarity index 56%
rename from MiraAPI/Patches/MeetingHudPatches.cs
rename to MiraAPI/Patches/Hud/ButtonResetPatches.cs
index 6abe4c0..b9756ce 100644
--- a/MiraAPI/Patches/MeetingHudPatches.cs
+++ b/MiraAPI/Patches/Hud/ButtonResetPatches.cs
@@ -1,20 +1,20 @@
using HarmonyLib;
using MiraAPI.Hud;
-namespace MiraAPI.Patches;
+namespace MiraAPI.Patches.Hud;
///
-/// Harmony patches for the MeetingHud class.
+/// Reset button patches
///
-[HarmonyPatch(typeof(MeetingHud))]
-public static class MeetingHudPatches
+[HarmonyPatch]
+public static class ButtonResetPatches
{
///
/// Resets the cooldown and effect of all custom buttons when the meeting starts.
///
[HarmonyPostfix]
- [HarmonyPatch(nameof(MeetingHud.Start))]
- public static void StartPostfix()
+ [HarmonyPatch(typeof(MeetingHud), nameof(MeetingHud.Start))]
+ public static void MeetingHudStartPostfix()
{
foreach (var customActionButton in CustomButtonManager.CustomButtons)
{
@@ -23,11 +23,11 @@ public static void StartPostfix()
}
///
- /// Resets the cooldown and effect of all custom buttons when the voting is complete.
+ /// Resets the cooldown and effect of all custom buttons after the exile screen is closed.
///
[HarmonyPostfix]
- [HarmonyPatch(nameof(MeetingHud.VotingComplete))]
- public static void VotingCompletePostfix()
+ [HarmonyPatch(typeof(ExileController), nameof(ExileController.ReEnableGameplay))]
+ public static void ExileControllerReEnableGameplayPostfix()
{
foreach (var customActionButton in CustomButtonManager.CustomButtons)
{
From aa72770bfc864d43f77d452d24773e512d209d3a Mon Sep 17 00:00:00 2001
From: XtraCube <72575280+XtraCube@users.noreply.github.com>
Date: Sun, 1 Sep 2024 16:06:35 -0400
Subject: [PATCH 03/36] change vent color for custom roles
---
MiraAPI/Patches/Roles/VentOutlinePatch.cs | 24 +++++++++++++++++++++++
1 file changed, 24 insertions(+)
create mode 100644 MiraAPI/Patches/Roles/VentOutlinePatch.cs
diff --git a/MiraAPI/Patches/Roles/VentOutlinePatch.cs b/MiraAPI/Patches/Roles/VentOutlinePatch.cs
new file mode 100644
index 0000000..401d450
--- /dev/null
+++ b/MiraAPI/Patches/Roles/VentOutlinePatch.cs
@@ -0,0 +1,24 @@
+using HarmonyLib;
+using MiraAPI.Roles;
+using MiraAPI.Utilities;
+using UnityEngine;
+
+namespace MiraAPI.Patches.Roles;
+
+[HarmonyPatch(typeof(Vent), nameof(Vent.SetOutline))]
+public static class VentOutlinePatch
+{
+ public static void Postfix(Vent __instance, bool on, bool mainTarget)
+ {
+ if (PlayerControl.LocalPlayer.Data.Role is not ICustomRole customRole)
+ {
+ return;
+ }
+
+ var color = customRole.RoleColor;
+
+ __instance.myRend.material.SetFloat(ShaderID.Outline, on ? 1 : 0);
+ __instance.myRend.material.SetColor(ShaderID.OutlineColor, color);
+ __instance.myRend.material.SetColor(ShaderID.AddColor, mainTarget ? color : Color.clear);
+ }
+}
From 74ab8c5581fddc9d07ab5ea63d4a6968546c9a8e Mon Sep 17 00:00:00 2001
From: XtraCube <72575280+XtraCube@users.noreply.github.com>
Date: Sun, 1 Sep 2024 16:06:41 -0400
Subject: [PATCH 04/36] oops
---
MiraAPI/Roles/RoleHintType.cs | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/MiraAPI/Roles/RoleHintType.cs b/MiraAPI/Roles/RoleHintType.cs
index 8994016..f3d5cc6 100644
--- a/MiraAPI/Roles/RoleHintType.cs
+++ b/MiraAPI/Roles/RoleHintType.cs
@@ -1,6 +1,4 @@
-// Copyright (c) PlaceholderCompany. All rights reserved.
-
-namespace MiraAPI.Roles;
+namespace MiraAPI.Roles;
///
/// The type of hint style for a role to use.
From a07c332dce2e22e6ef04e9e4d9b82c91af762c41 Mon Sep 17 00:00:00 2001
From: XtraCube <72575280+XtraCube@users.noreply.github.com>
Date: Sun, 1 Sep 2024 16:07:22 -0400
Subject: [PATCH 05/36] add DeathReason to modifier OnDeath method
---
MiraAPI/Modifiers/BaseModifier.cs | 3 ++-
MiraAPI/Patches/PlayerControlPatches.cs | 4 ++--
2 files changed, 4 insertions(+), 3 deletions(-)
diff --git a/MiraAPI/Modifiers/BaseModifier.cs b/MiraAPI/Modifiers/BaseModifier.cs
index af9b491..b91c078 100644
--- a/MiraAPI/Modifiers/BaseModifier.cs
+++ b/MiraAPI/Modifiers/BaseModifier.cs
@@ -62,7 +62,8 @@ public virtual void FixedUpdate()
///
/// Called when the player dies.
///
- public virtual void OnDeath()
+ /// The Death Reason.
+ public virtual void OnDeath(DeathReason reason)
{
}
diff --git a/MiraAPI/Patches/PlayerControlPatches.cs b/MiraAPI/Patches/PlayerControlPatches.cs
index 7d4d97a..b9bc0f2 100644
--- a/MiraAPI/Patches/PlayerControlPatches.cs
+++ b/MiraAPI/Patches/PlayerControlPatches.cs
@@ -32,13 +32,13 @@ public static void PlayerControlStartPostfix(PlayerControl __instance)
///
[HarmonyPostfix]
[HarmonyPatch(nameof(PlayerControl.Die))]
- public static void PlayerControlDiePostfix(PlayerControl __instance)
+ public static void PlayerControlDiePostfix(PlayerControl __instance, DeathReason reason)
{
var modifiersComponent = __instance.GetComponent();
if (modifiersComponent)
{
- modifiersComponent.ActiveModifiers.ForEach(x=>x.OnDeath());
+ modifiersComponent.ActiveModifiers.ForEach(x=>x.OnDeath(reason));
}
}
From 0f26cadd9af89e7fe89932efbabe262f8618c7c6 Mon Sep 17 00:00:00 2001
From: XtraCube <72575280+XtraCube@users.noreply.github.com>
Date: Sun, 1 Sep 2024 16:07:36 -0400
Subject: [PATCH 06/36] clean up OptionGroupSingleton.cs
---
MiraAPI/GameOptions/OptionGroupSingleton.cs | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/MiraAPI/GameOptions/OptionGroupSingleton.cs b/MiraAPI/GameOptions/OptionGroupSingleton.cs
index 03a11fa..8c7e2af 100644
--- a/MiraAPI/GameOptions/OptionGroupSingleton.cs
+++ b/MiraAPI/GameOptions/OptionGroupSingleton.cs
@@ -1,5 +1,4 @@
-using System;
-using System.Linq;
+using System.Linq;
namespace MiraAPI.GameOptions;
@@ -7,13 +6,12 @@ namespace MiraAPI.GameOptions;
/// Singleton for option groups.
///
/// The option group type.
-public class OptionGroupSingleton where T : AbstractOptionGroup
+public static class OptionGroupSingleton where T : AbstractOptionGroup
{
private static T? _instance;
///
/// Gets the instance of the option group.
///
- /// Can't
public static T Instance => _instance ??= ModdedOptionsManager.Groups.OfType().Single();
}
From b0536842355d1ecd3efeec18e15e8118410d8be0 Mon Sep 17 00:00:00 2001
From: XtraCube <72575280+XtraCube@users.noreply.github.com>
Date: Sun, 1 Sep 2024 16:08:01 -0400
Subject: [PATCH 07/36] formatting
---
MiraAPI/GameOptions/ModdedOptionsManager.cs | 6 +++---
MiraAPI/Patches/Roles/EjectionPatches.cs | 11 +++++++----
2 files changed, 10 insertions(+), 7 deletions(-)
diff --git a/MiraAPI/GameOptions/ModdedOptionsManager.cs b/MiraAPI/GameOptions/ModdedOptionsManager.cs
index b57528e..1300d61 100644
--- a/MiraAPI/GameOptions/ModdedOptionsManager.cs
+++ b/MiraAPI/GameOptions/ModdedOptionsManager.cs
@@ -18,10 +18,10 @@ namespace MiraAPI.GameOptions;
///
public static class ModdedOptionsManager
{
- private static readonly Dictionary OptionAttributes = new();
- private static readonly Dictionary TypeToGroup = new();
+ private static readonly Dictionary OptionAttributes = [];
+ private static readonly Dictionary TypeToGroup = [];
- internal static readonly Dictionary ModdedOptions = new();
+ internal static readonly Dictionary ModdedOptions = [];
internal static readonly List Groups = [];
internal static uint NextId => _nextId++;
diff --git a/MiraAPI/Patches/Roles/EjectionPatches.cs b/MiraAPI/Patches/Roles/EjectionPatches.cs
index bbea1e8..9f85872 100644
--- a/MiraAPI/Patches/Roles/EjectionPatches.cs
+++ b/MiraAPI/Patches/Roles/EjectionPatches.cs
@@ -3,15 +3,18 @@
namespace MiraAPI.Patches.Roles;
+///
+/// Patches for custom ejection messages.
+///
[HarmonyPatch(typeof(ExileController))]
public static class EjectionPatches
{
-
[HarmonyPostfix]
[HarmonyPatch(nameof(ExileController.Begin))]
- public static void Begin(ExileController __instance)
+ public static void BeginPostfix(ExileController __instance)
{
- if (!__instance.initData.networkedPlayer || !__instance.initData.networkedPlayer.Role || __instance.initData.networkedPlayer.Role is not ICustomRole role)
+ if (!__instance.initData.networkedPlayer || !__instance.initData.networkedPlayer.Role ||
+ __instance.initData.networkedPlayer.Role is not ICustomRole role)
{
return;
}
@@ -23,4 +26,4 @@ public static void Begin(ExileController __instance)
__instance.completeString = role.GetCustomEjectionMessage(__instance.initData.networkedPlayer);
}
-}
\ No newline at end of file
+}
From d1c469746e7ed091014f62e2507f311c4394612c Mon Sep 17 00:00:00 2001
From: XtraCube <72575280+XtraCube@users.noreply.github.com>
Date: Sun, 1 Sep 2024 16:08:18 -0400
Subject: [PATCH 08/36] fix poor documentation in ICustomRole
---
MiraAPI/Roles/ICustomRole.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/MiraAPI/Roles/ICustomRole.cs b/MiraAPI/Roles/ICustomRole.cs
index ffe2327..08875f9 100644
--- a/MiraAPI/Roles/ICustomRole.cs
+++ b/MiraAPI/Roles/ICustomRole.cs
@@ -41,7 +41,7 @@ public interface ICustomRole
ModdedRoleTeams Team { get; }
///
- /// Gets the **maximum amount** of players that can have this role at a time. This is not the same as the **number** of players that can have this role in a game.
+ /// Gets the hard limit of players that can have this role. This property is used to set a limit in the Role Options menu.
///
int MaxPlayers => 15;
From f17089f4355de4140736836ebc76a1d77f1efee8 Mon Sep 17 00:00:00 2001
From: XtraCube <72575280+XtraCube@users.noreply.github.com>
Date: Sun, 1 Sep 2024 16:14:30 -0400
Subject: [PATCH 09/36] split HudManager patches
---
MiraAPI/Patches/HudManagerPatches.cs | 68 +-------------------
MiraAPI/Patches/Roles/HudManagerPatches.cs | 74 ++++++++++++++++++++++
2 files changed, 75 insertions(+), 67 deletions(-)
create mode 100644 MiraAPI/Patches/Roles/HudManagerPatches.cs
diff --git a/MiraAPI/Patches/HudManagerPatches.cs b/MiraAPI/Patches/HudManagerPatches.cs
index c3ee9e8..45bd114 100644
--- a/MiraAPI/Patches/HudManagerPatches.cs
+++ b/MiraAPI/Patches/HudManagerPatches.cs
@@ -17,62 +17,6 @@ public static class HudManagerPatches
// Custom buttons parent.
private static GameObject? _bottomLeft;
- // Custom role tab.
- private static TaskPanelBehaviour? _roleTab;
-
- ///
- /// Update custom role tab and custom role hud elements.
- ///
- /// The HudManager instance.
- [HarmonyPostfix]
- [HarmonyPatch(nameof(HudManager.Update))]
- public static void UpdatePostfix(HudManager __instance)
- {
- var local = PlayerControl.LocalPlayer;
-
- if (AmongUsClient.Instance.GameState != InnerNetClient.GameStates.Started && !ShipStatus.Instance)
- {
- return;
- }
-
- // CustomGameModeManager.ActiveMode?.HudUpdate(__instance);
-
- switch (local?.Data?.Role)
- {
- case null:
- return;
-
- case ICustomRole customRole:
- {
- customRole.HudUpdate(__instance);
-
- if (customRole.RoleHintType != RoleHintType.RoleTab)
- {
- _roleTab?.gameObject.Destroy();
- return;
- }
-
- if (_roleTab == null)
- {
- _roleTab = CustomRoleManager.CreateRoleTab(customRole);
- }
- else
- {
- CustomRoleManager.UpdateRoleTab(_roleTab, customRole);
- }
-
- break;
- }
-
- default:
- if (_roleTab != null)
- {
- _roleTab.gameObject.Destroy();
- }
- break;
- }
- }
-
/*
///
/// Trigger hudstart on current custom gamemode
@@ -136,7 +80,7 @@ public static void StartPostfix(HudManager __instance)
}
///
- /// Set the custom role tab and custom buttons active when the hud is active.
+ /// Set the custom buttons active when the hud is active.
///
/// HudManager instance.
/// The local PlayerControl.
@@ -151,19 +95,9 @@ public static void SetHudActivePostfix(HudManager __instance, PlayerControl loca
return;
}
- if (_roleTab)
- {
- _roleTab?.gameObject.SetActive(isActive);
- }
-
foreach (var button in CustomButtonManager.CustomButtons)
{
button.SetActive(isActive, role);
}
-
- if (role is ICustomRole customRole)
- {
- __instance.ImpostorVentButton.gameObject.SetActive(isActive && customRole.CanUseVent);
- }
}
}
diff --git a/MiraAPI/Patches/Roles/HudManagerPatches.cs b/MiraAPI/Patches/Roles/HudManagerPatches.cs
new file mode 100644
index 0000000..34f0bb9
--- /dev/null
+++ b/MiraAPI/Patches/Roles/HudManagerPatches.cs
@@ -0,0 +1,74 @@
+using HarmonyLib;
+using InnerNet;
+using MiraAPI.Roles;
+using Reactor.Utilities.Extensions;
+
+namespace MiraAPI.Patches.Roles;
+
+///
+/// HudManager patches for roles.
+///
+[HarmonyPatch(typeof(HudManager))]
+public static class HudManagerPatches
+{
+ // Custom role tab.
+ private static TaskPanelBehaviour? _roleTab;
+
+ ///
+ /// Fixes Kill Button not showing for Neutral killing role.
+ ///
+ [HarmonyPostfix]
+ [HarmonyPatch(nameof(HudManager.SetHudActive), typeof(PlayerControl), typeof(RoleBehaviour), typeof(bool))]
+ public static void SetHudActivePostfix(
+ HudManager __instance,
+ PlayerControl localPlayer,
+ RoleBehaviour role,
+ bool isActive)
+ {
+ var flag = localPlayer.Data != null && localPlayer.Data.IsDead;
+
+ if (role is ICustomRole)
+ {
+ __instance.KillButton.ToggleVisible(isActive && role.CanUseKillButton && !flag);
+ __instance.ImpostorVentButton.ToggleVisible(isActive && role.CanVent && !flag);
+ }
+
+ if (_roleTab)
+ {
+ _roleTab?.gameObject.SetActive(isActive);
+ }
+ }
+
+ ///
+ /// Update custom role tab and custom role hud elements.
+ ///
+ [HarmonyPostfix]
+ [HarmonyPatch(nameof(HudManager.Update))]
+ public static void UpdatePostfix(HudManager __instance)
+ {
+ var local = PlayerControl.LocalPlayer;
+
+ if (AmongUsClient.Instance.GameState != InnerNetClient.GameStates.Started && !ShipStatus.Instance)
+ {
+ return;
+ }
+
+ var role = local?.Data?.Role;
+
+ if (role is ICustomRole { RoleHintType: RoleHintType.RoleTab } customRole)
+ {
+ customRole.HudUpdate(__instance);
+
+ if (_roleTab == null)
+ {
+ _roleTab = CustomRoleManager.CreateRoleTab(customRole);
+ }
+
+ CustomRoleManager.UpdateRoleTab(_roleTab, customRole);
+ }
+ else if (_roleTab)
+ {
+ _roleTab?.gameObject.Destroy();
+ }
+ }
+}
From a3dd4acf43c83439735a1b278f385b3b9acaf8f3 Mon Sep 17 00:00:00 2001
From: XtraCube <72575280+XtraCube@users.noreply.github.com>
Date: Sun, 1 Sep 2024 16:29:42 -0400
Subject: [PATCH 10/36] code document custom murder RPCs
---
MiraAPI/Networking/CustomMurderRpc.cs | 271 +++++++++++++++++++++++++
MiraAPI/Networking/CustomMurderRpcs.cs | 186 -----------------
2 files changed, 271 insertions(+), 186 deletions(-)
create mode 100644 MiraAPI/Networking/CustomMurderRpc.cs
delete mode 100644 MiraAPI/Networking/CustomMurderRpcs.cs
diff --git a/MiraAPI/Networking/CustomMurderRpc.cs b/MiraAPI/Networking/CustomMurderRpc.cs
new file mode 100644
index 0000000..b36810a
--- /dev/null
+++ b/MiraAPI/Networking/CustomMurderRpc.cs
@@ -0,0 +1,271 @@
+using AmongUs.GameOptions;
+using Assets.CoreScripts;
+using Reactor.Networking.Attributes;
+using Reactor.Utilities;
+using Reactor.Utilities.Extensions;
+using System.Collections;
+using System.Linq;
+using UnityEngine;
+
+namespace MiraAPI.Networking;
+
+///
+/// Custom murder RPCs to fix issues with default ones.
+///
+public static class CustomMurderRpc
+{
+ ///
+ /// Networked Custom Murder method.
+ ///
+ /// The killer.
+ /// The player to murder.
+ /// Whether the murder was successful or not.
+ /// Should the kill timer be reset.
+ /// Should a dead body be created.
+ /// Should the killer be snapped to the dead player.
+ /// Should the kill animation be shown.
+ /// Should the kill sound be played.
+ [MethodRpc((uint)MiraRpc.CustomMurder)]
+ public static void RpcCustomMurder(
+ this PlayerControl source,
+ PlayerControl target,
+ bool didSucceed = true,
+ bool resetKillTimer = true,
+ bool createDeadBody = true,
+ bool teleportMurderer = true,
+ bool showKillAnim = true,
+ bool playKillSound = true)
+ {
+ var murderResultFlags = didSucceed ? MurderResultFlags.Succeeded : MurderResultFlags.FailedError;
+ var murderResultFlags2 = MurderResultFlags.DecisionByHost | murderResultFlags;
+
+ source.CustomMurder(
+ target,
+ murderResultFlags2,
+ resetKillTimer,
+ createDeadBody,
+ teleportMurderer,
+ showKillAnim,
+ playKillSound);
+ }
+
+ ///
+ /// Custom Murder method without networking. If you need a networked version, use .
+ ///
+ /// The killer.
+ /// The player to murder.
+ /// Murder result flags.
+ /// Should the kill timer be reset.
+ /// Should a dead body be created.
+ /// Should the killer be snapped to the dead player.
+ /// Should the kill animation be shown.
+ /// Should the kill sound be played.
+ public static void CustomMurder(
+ this PlayerControl source,
+ PlayerControl target,
+ MurderResultFlags resultFlags,
+ bool resetKillTimer = true,
+ bool createDeadBody = true,
+ bool teleportMurderer = true,
+ bool showKillAnim = true,
+ bool playKillSound = true)
+ {
+ source.isKilling = false;
+ Logger.Debug($"{source.PlayerId} trying to murder {target.PlayerId}");
+ var data = target.Data;
+ if (resultFlags.HasFlag(MurderResultFlags.FailedError))
+ {
+ return;
+ }
+
+ if (resultFlags.HasFlag(MurderResultFlags.FailedProtected) ||
+ (resultFlags.HasFlag(MurderResultFlags.DecisionByHost) && target.protectedByGuardianId > -1))
+ {
+ target.protectedByGuardianThisRound = true;
+ var flag = PlayerControl.LocalPlayer.Data.Role.Role == RoleTypes.GuardianAngel;
+ if (flag && PlayerControl.LocalPlayer.Data.PlayerId == target.protectedByGuardianId)
+ {
+ StatsManager.Instance.IncrementStat(StringNames.StatsGuardianAngelCrewmatesProtected);
+ DestroyableSingleton.Instance.OnProtectACrewmate();
+ }
+
+ if (source.AmOwner || flag)
+ {
+ target.ShowFailedMurder();
+
+ if (resetKillTimer)
+ {
+ source.SetKillTimer(
+ GameOptionsManager.Instance.CurrentGameOptions.GetFloat(FloatOptionNames.KillCooldown) / 2f);
+ }
+ }
+ else
+ {
+ target.RemoveProtection();
+ }
+
+ Logger.Debug($"{source.PlayerId} failed to murder {target.PlayerId} due to guardian angel protection");
+ return;
+ }
+
+ if (!resultFlags.HasFlag(MurderResultFlags.Succeeded) &&
+ !resultFlags.HasFlag(MurderResultFlags.DecisionByHost))
+ {
+ return;
+ }
+
+ DestroyableSingleton.Instance.Analytics.Kill(target.Data, source.Data);
+ if (source.AmOwner)
+ {
+ StatsManager.Instance.IncrementStat(
+ GameManager.Instance.IsHideAndSeek()
+ ? StringNames.StatsImpostorKills_HideAndSeek
+ : StringNames.StatsImpostorKills);
+
+ if (source.CurrentOutfitType == PlayerOutfitType.Shapeshifted)
+ {
+ StatsManager.Instance.IncrementStat(StringNames.StatsShapeshifterShiftedKills);
+ }
+
+ if (Constants.ShouldPlaySfx() && playKillSound)
+ {
+ SoundManager.Instance.PlaySound(source.KillSfx, false, 0.8f);
+ }
+
+ if (resetKillTimer)
+ {
+ source.SetKillTimer(
+ GameOptionsManager.Instance.CurrentGameOptions.GetFloat(FloatOptionNames.KillCooldown));
+ }
+ }
+
+ DestroyableSingleton.Instance.WriteMurder();
+ target.gameObject.layer = LayerMask.NameToLayer("Ghost");
+ if (target.AmOwner)
+ {
+ StatsManager.Instance.IncrementStat(StringNames.StatsTimesMurdered);
+ if (Minigame.Instance)
+ {
+ try
+ {
+ Minigame.Instance.Close();
+ Minigame.Instance.Close();
+ }
+ catch
+ {
+ // ignored
+ }
+ }
+
+ if (showKillAnim)
+ {
+ DestroyableSingleton.Instance.KillOverlay.ShowKillAnimation(source.Data, data);
+ }
+
+ target.cosmetics.SetNameMask(false);
+ target.RpcSetScanner(false);
+ }
+
+ DestroyableSingleton.Instance.OnMurder(
+ source.AmOwner,
+ target.AmOwner,
+ source.CurrentOutfitType == PlayerOutfitType.Shapeshifted,
+ source.shapeshiftTargetPlayerId,
+ target.PlayerId);
+ Coroutines.Start(source.KillAnimations.Random()?.CoPerformCustomKill(source, target, createDeadBody, teleportMurderer));
+ Logger.Debug($"{source.PlayerId} succeeded in murdering {target.PlayerId}");
+ }
+
+ ///
+ /// Perform a custom kill animation.
+ ///
+ /// The kill animation.
+ /// The murderer.
+ /// The murdered player.
+ /// Should a dead body be created.
+ /// Should the murder be teleported.
+ /// Coroutine.
+ public static IEnumerator CoPerformCustomKill(
+ this KillAnimation anim,
+ PlayerControl source,
+ PlayerControl target,
+ bool createDeadBody = true,
+ bool teleportMurderer = true)
+ {
+ var cam = Camera.main?.GetComponent();
+ var isParticipant = PlayerControl.LocalPlayer == source || PlayerControl.LocalPlayer == target;
+ var sourcePhys = source.MyPhysics;
+
+ if (teleportMurderer)
+ {
+ KillAnimation.SetMovement(source, false);
+ }
+
+ KillAnimation.SetMovement(target, false);
+
+ if (isParticipant)
+ {
+ PlayerControl.LocalPlayer.isKilling = true;
+ source.isKilling = true;
+ }
+
+ DeadBody? deadBody = null;
+
+ if (createDeadBody)
+ {
+ deadBody = Object.Instantiate(GameManager.Instance.DeadBodyPrefab);
+ deadBody.enabled = false;
+ deadBody.ParentId = target.PlayerId;
+ deadBody.bodyRenderers.ToList().ForEach(target.SetPlayerMaterialColors);
+
+ target.SetPlayerMaterialColors(deadBody.bloodSplatter);
+ var vector = target.transform.position + anim.BodyOffset;
+ vector.z = vector.y / 1000f;
+ deadBody.transform.position = vector;
+ }
+
+ if (isParticipant)
+ {
+ if (cam != null)
+ {
+ cam.Locked = true;
+ }
+
+ ConsoleJoystick.SetMode_Task();
+ if (PlayerControl.LocalPlayer.AmOwner)
+ {
+ PlayerControl.LocalPlayer.MyPhysics.inputHandler.enabled = true;
+ }
+ }
+
+ target.Die(DeathReason.Kill, true);
+ yield return source.MyPhysics.Animations.CoPlayCustomAnimation(anim.BlurAnim);
+ sourcePhys.Animations.PlayIdleAnimation();
+
+ if (teleportMurderer)
+ {
+ source.NetTransform.SnapTo(target.transform.position);
+ KillAnimation.SetMovement(source, true);
+ }
+
+ KillAnimation.SetMovement(target, true);
+
+ if (deadBody != null)
+ {
+ deadBody.enabled = true;
+ }
+
+ if (!isParticipant)
+ {
+ yield break;
+ }
+
+ if (cam != null)
+ {
+ cam.Locked = true;
+ }
+
+ PlayerControl.LocalPlayer.isKilling = false;
+ source.isKilling = false;
+ }
+}
diff --git a/MiraAPI/Networking/CustomMurderRpcs.cs b/MiraAPI/Networking/CustomMurderRpcs.cs
deleted file mode 100644
index 17fb4ae..0000000
--- a/MiraAPI/Networking/CustomMurderRpcs.cs
+++ /dev/null
@@ -1,186 +0,0 @@
-using AmongUs.GameOptions;
-using Assets.CoreScripts;
-using Reactor.Networking.Attributes;
-using Reactor.Utilities;
-using Reactor.Utilities.Extensions;
-using System.Collections;
-using System.Linq;
-using UnityEngine;
-
-namespace MiraAPI.Networking;
-public static class CustomMurderRpcs
-{
- [MethodRpc((uint)MiraRpc.CustomMurder)]
- public static void RpcCustomMurder(this PlayerControl source, PlayerControl target, bool didSucceed = true,
- bool resetKillTimer = true, bool createDeadBody = true, bool teleportMurderer = true, bool showKillAnim = true, bool playKillSound = true)
- {
- var murderResultFlags = didSucceed ? MurderResultFlags.Succeeded : MurderResultFlags.FailedError;
- var murderResultFlags2 = MurderResultFlags.DecisionByHost | murderResultFlags;
-
- source.CustomMurder(target, murderResultFlags2, resetKillTimer, createDeadBody, teleportMurderer, showKillAnim, playKillSound);
- }
-
- public static void CustomMurder(this PlayerControl source, PlayerControl target, MurderResultFlags resultFlags,
- bool resetKillTimer = true, bool createDeadBody = true, bool teleportMurderer = true, bool showKillAnim = true, bool playKillSound = true)
- {
- source.isKilling = false;
- source.logger.Debug(string.Format("{0} trying to murder {1}", source.PlayerId, target.PlayerId), null);
- var data = target.Data;
- if (resultFlags.HasFlag(MurderResultFlags.FailedError))
- {
- return;
- }
- if (resultFlags.HasFlag(MurderResultFlags.FailedProtected) || (resultFlags.HasFlag(MurderResultFlags.DecisionByHost) && target.protectedByGuardianId > -1))
- {
- target.protectedByGuardianThisRound = true;
- var flag = PlayerControl.LocalPlayer.Data.Role.Role == RoleTypes.GuardianAngel;
- if (flag && PlayerControl.LocalPlayer.Data.PlayerId == target.protectedByGuardianId)
- {
- StatsManager.Instance.IncrementStat(StringNames.StatsGuardianAngelCrewmatesProtected);
- DestroyableSingleton.Instance.OnProtectACrewmate();
- }
- if (source.AmOwner || flag)
- {
- target.ShowFailedMurder();
-
- if (resetKillTimer)
- {
- source.SetKillTimer(GameOptionsManager.Instance.CurrentGameOptions.GetFloat(FloatOptionNames.KillCooldown) / 2f);
- }
- }
- else
- {
- target.RemoveProtection();
- }
- source.logger.Debug(string.Format("{0} failed to murder {1} due to guardian angel protection", source.PlayerId, target.PlayerId), null);
- return;
- }
- if (resultFlags.HasFlag(MurderResultFlags.Succeeded) || resultFlags.HasFlag(MurderResultFlags.DecisionByHost))
- {
- DestroyableSingleton.Instance.Analytics.Kill(target.Data, source.Data);
- if (source.AmOwner)
- {
- if (GameManager.Instance.IsHideAndSeek())
- {
- StatsManager.Instance.IncrementStat(StringNames.StatsImpostorKills_HideAndSeek);
- }
- else
- {
- StatsManager.Instance.IncrementStat(StringNames.StatsImpostorKills);
- }
- if (source.CurrentOutfitType == PlayerOutfitType.Shapeshifted)
- {
- StatsManager.Instance.IncrementStat(StringNames.StatsShapeshifterShiftedKills);
- }
- if (Constants.ShouldPlaySfx() && playKillSound)
- {
- SoundManager.Instance.PlaySound(source.KillSfx, false, 0.8f, null);
- }
-
- if (resetKillTimer)
- {
- source.SetKillTimer(GameOptionsManager.Instance.CurrentGameOptions.GetFloat(FloatOptionNames.KillCooldown));
- }
- }
- DestroyableSingleton.Instance.WriteMurder();
- target.gameObject.layer = LayerMask.NameToLayer("Ghost");
- if (target.AmOwner)
- {
- StatsManager.Instance.IncrementStat(StringNames.StatsTimesMurdered);
- if (Minigame.Instance)
- {
- try
- {
- Minigame.Instance.Close();
- Minigame.Instance.Close();
- }
- catch
- {
- }
- }
-
- if (showKillAnim)
- {
- DestroyableSingleton.Instance.KillOverlay.ShowKillAnimation(source.Data, data);
- }
-
- target.cosmetics.SetNameMask(false);
- target.RpcSetScanner(false);
- }
- DestroyableSingleton.Instance.OnMurder(source.AmOwner, target.AmOwner, source.CurrentOutfitType == PlayerOutfitType.Shapeshifted, source.shapeshiftTargetPlayerId, (int)target.PlayerId);
- Coroutines.Start(source.KillAnimations.Random().CoPerformCustomKill(source, target, createDeadBody, teleportMurderer));
- source.logger.Debug(string.Format("{0} succeeded in murdering {1}", source.PlayerId, target.PlayerId), null);
- }
- }
-
- public static IEnumerator CoPerformCustomKill(this KillAnimation anim, PlayerControl source, PlayerControl target,
- bool createDeadBody = true, bool teleportMurderer = true)
- {
- var cam = Camera.main.GetComponent();
- var isParticipant = PlayerControl.LocalPlayer == source || PlayerControl.LocalPlayer == target;
- var sourcePhys = source.MyPhysics;
-
- if (teleportMurderer)
- {
- KillAnimation.SetMovement(source, false);
- }
-
- KillAnimation.SetMovement(target, false);
-
- if (isParticipant)
- {
- PlayerControl.LocalPlayer.isKilling = true;
- source.isKilling = true;
- }
-
- DeadBody deadBody = null;
-
- if (createDeadBody)
- {
- deadBody = Object.Instantiate(GameManager.Instance.DeadBodyPrefab);
- deadBody.enabled = false;
- deadBody.ParentId = target.PlayerId;
- deadBody.bodyRenderers.ToArray().ToList().ForEach(target.SetPlayerMaterialColors);
-
- target.SetPlayerMaterialColors(deadBody.bloodSplatter);
- var vector = target.transform.position + anim.BodyOffset;
- vector.z = vector.y / 1000f;
- deadBody.transform.position = vector;
- }
-
- if (isParticipant)
- {
- cam.Locked = true;
- ConsoleJoystick.SetMode_Task();
- if (PlayerControl.LocalPlayer.AmOwner)
- {
- PlayerControl.LocalPlayer.MyPhysics.inputHandler.enabled = true;
- }
- }
-
- target.Die(DeathReason.Kill, true);
- yield return source.MyPhysics.Animations.CoPlayCustomAnimation(anim.BlurAnim);
- sourcePhys.Animations.PlayIdleAnimation();
-
- if (teleportMurderer)
- {
- source.NetTransform.SnapTo(target.transform.position);
- KillAnimation.SetMovement(source, true);
- }
- KillAnimation.SetMovement(target, true);
-
- if (deadBody)
- {
- deadBody.enabled = true;
- }
-
- if (isParticipant)
- {
- cam.Locked = false;
- PlayerControl.LocalPlayer.isKilling = false;
- source.isKilling = false;
- }
-
- yield break;
- }
-}
\ No newline at end of file
From f8bb63483fbacf6ed836cc013e849d3d0d2e7854 Mon Sep 17 00:00:00 2001
From: XtraCube <72575280+XtraCube@users.noreply.github.com>
Date: Sun, 1 Sep 2024 20:54:35 -0400
Subject: [PATCH 11/36] fixing possible issues with ghost roles
---
MiraAPI/Roles/CustomRoleManager.cs | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/MiraAPI/Roles/CustomRoleManager.cs b/MiraAPI/Roles/CustomRoleManager.cs
index ca34213..a3d36ec 100644
--- a/MiraAPI/Roles/CustomRoleManager.cs
+++ b/MiraAPI/Roles/CustomRoleManager.cs
@@ -35,6 +35,11 @@ private static ushort GetNextRoleId()
internal static void RegisterInRoleManager()
{
RoleManager.Instance.AllRoles = RoleManager.Instance.AllRoles.Concat(CustomRoles.Values).ToArray();
+
+ foreach (var role in CustomRoles.Values.Where(x=>x.IsDead))
+ {
+ RoleManager.GhostRoles.Add(role.Role);
+ }
}
internal static void RegisterRoleTypes(List roles, MiraPluginInfo pluginInfo)
@@ -81,8 +86,8 @@ internal static void RegisterRoleTypes(List roles, MiraPluginInfo pluginIn
roleBehaviour.BlurbNameLong = CustomStringName.CreateAndRegister(customRole.RoleLongDescription);
roleBehaviour.AffectedByLightAffectors = customRole.AffectedByLight;
roleBehaviour.CanBeKilled = customRole.CanGetKilled;
- roleBehaviour.CanUseKillButton = customRole.CanKill;
- roleBehaviour.TasksCountTowardProgress = customRole.TasksCount;
+ roleBehaviour.CanUseKillButton = customRole.CanUseKill;
+ roleBehaviour.TasksCountTowardProgress = customRole.TasksCountForProgress;
roleBehaviour.CanVent = customRole.CanUseVent;
roleBehaviour.DefaultGhostRole = customRole.GhostRole;
roleBehaviour.MaxCount = customRole.MaxPlayers;
From f207849e5efbcc654c7cf189f92401a08f647645 Mon Sep 17 00:00:00 2001
From: XtraCube <72575280+XtraCube@users.noreply.github.com>
Date: Mon, 2 Sep 2024 00:12:50 -0400
Subject: [PATCH 12/36] fix neutral killing issues and rename some properties
in ICustomRole to clear confusion
---
MiraAPI.Example/Roles/NeutralKillerRole.cs | 27 +++++++++
MiraAPI/Networking/CustomMurderRpc.cs | 20 +++----
MiraAPI/Patches/HudManagerPatches.cs | 2 -
MiraAPI/Patches/Roles/KillButtonPatches.cs | 65 ++++++++++++++++++++++
MiraAPI/Roles/CustomRoleManager.cs | 2 +-
MiraAPI/Roles/ICustomRole.cs | 8 +--
6 files changed, 107 insertions(+), 17 deletions(-)
create mode 100644 MiraAPI.Example/Roles/NeutralKillerRole.cs
create mode 100644 MiraAPI/Patches/Roles/KillButtonPatches.cs
diff --git a/MiraAPI.Example/Roles/NeutralKillerRole.cs b/MiraAPI.Example/Roles/NeutralKillerRole.cs
new file mode 100644
index 0000000..0cbc6fd
--- /dev/null
+++ b/MiraAPI.Example/Roles/NeutralKillerRole.cs
@@ -0,0 +1,27 @@
+using MiraAPI.Roles;
+using UnityEngine;
+
+namespace MiraAPI.Example.Roles;
+
+[RegisterCustomRole]
+public class NeutralKillerRole : ImpostorRole, ICustomRole
+{
+ public string RoleName => "Neutral Killer";
+ public string RoleDescription => "Neutral who can kill.";
+ public string RoleLongDescription => RoleDescription;
+ public Color RoleColor => Color.magenta;
+ public ModdedRoleTeams Team => ModdedRoleTeams.Neutral;
+ public bool CanUseKill => true;
+ public bool CanGetKilled => true;
+ public bool CanUseVent => true;
+
+ public override void SpawnTaskHeader(PlayerControl playerControl)
+ {
+ // remove existing task header.
+ }
+
+ public override bool DidWin(GameOverReason gameOverReason)
+ {
+ return GameManager.Instance.DidHumansWin(gameOverReason);
+ }
+}
diff --git a/MiraAPI/Networking/CustomMurderRpc.cs b/MiraAPI/Networking/CustomMurderRpc.cs
index b36810a..619a0ab 100644
--- a/MiraAPI/Networking/CustomMurderRpc.cs
+++ b/MiraAPI/Networking/CustomMurderRpc.cs
@@ -1,10 +1,11 @@
-using AmongUs.GameOptions;
+using System.Collections;
+using System.Linq;
+using AmongUs.GameOptions;
using Assets.CoreScripts;
+using BepInEx.Unity.IL2CPP.Utils;
using Reactor.Networking.Attributes;
using Reactor.Utilities;
using Reactor.Utilities.Extensions;
-using System.Collections;
-using System.Linq;
using UnityEngine;
namespace MiraAPI.Networking;
@@ -71,7 +72,7 @@ public static void CustomMurder(
bool playKillSound = true)
{
source.isKilling = false;
- Logger.Debug($"{source.PlayerId} trying to murder {target.PlayerId}");
+ Logger.Error($"{source.PlayerId} trying to murder {target.PlayerId}");
var data = target.Data;
if (resultFlags.HasFlag(MurderResultFlags.FailedError))
{
@@ -104,7 +105,7 @@ public static void CustomMurder(
target.RemoveProtection();
}
- Logger.Debug($"{source.PlayerId} failed to murder {target.PlayerId} due to guardian angel protection");
+ Logger.Error($"{source.PlayerId} failed to murder {target.PlayerId} due to guardian angel protection");
return;
}
@@ -134,8 +135,7 @@ public static void CustomMurder(
if (resetKillTimer)
{
- source.SetKillTimer(
- GameOptionsManager.Instance.CurrentGameOptions.GetFloat(FloatOptionNames.KillCooldown));
+ source.SetKillTimer(GameOptionsManager.Instance.CurrentGameOptions.GetFloat(FloatOptionNames.KillCooldown));
}
}
@@ -172,8 +172,8 @@ public static void CustomMurder(
source.CurrentOutfitType == PlayerOutfitType.Shapeshifted,
source.shapeshiftTargetPlayerId,
target.PlayerId);
- Coroutines.Start(source.KillAnimations.Random()?.CoPerformCustomKill(source, target, createDeadBody, teleportMurderer));
- Logger.Debug($"{source.PlayerId} succeeded in murdering {target.PlayerId}");
+ source.MyPhysics.StartCoroutine(source.KillAnimations.Random()?.CoPerformCustomKill(source, target, createDeadBody, teleportMurderer));
+ Logger.Error($"{source.PlayerId} succeeded in murdering {target.PlayerId}");
}
///
@@ -262,7 +262,7 @@ public static IEnumerator CoPerformCustomKill(
if (cam != null)
{
- cam.Locked = true;
+ cam.Locked = false;
}
PlayerControl.LocalPlayer.isKilling = false;
diff --git a/MiraAPI/Patches/HudManagerPatches.cs b/MiraAPI/Patches/HudManagerPatches.cs
index 45bd114..cdef7cc 100644
--- a/MiraAPI/Patches/HudManagerPatches.cs
+++ b/MiraAPI/Patches/HudManagerPatches.cs
@@ -1,7 +1,5 @@
using HarmonyLib;
-using InnerNet;
using MiraAPI.Hud;
-using MiraAPI.Roles;
using Reactor.Utilities.Extensions;
using UnityEngine;
using Object = UnityEngine.Object;
diff --git a/MiraAPI/Patches/Roles/KillButtonPatches.cs b/MiraAPI/Patches/Roles/KillButtonPatches.cs
new file mode 100644
index 0000000..52b5cba
--- /dev/null
+++ b/MiraAPI/Patches/Roles/KillButtonPatches.cs
@@ -0,0 +1,65 @@
+using HarmonyLib;
+using Il2CppSystem;
+using MiraAPI.Networking;
+using MiraAPI.Roles;
+using UnityEngine;
+
+namespace MiraAPI.Patches.Roles;
+
+///
+/// Fix kill button issues for neutral killers.
+///
+[HarmonyPatch(typeof(KillButton))]
+public static class KillButtonPatches
+{
+ [HarmonyPrefix]
+ [HarmonyPatch(nameof(KillButton.SetTarget))]
+ public static bool SetTargetPrefix(KillButton __instance, PlayerControl target)
+ {
+ if (!PlayerControl.LocalPlayer || PlayerControl.LocalPlayer.Data == null || !PlayerControl.LocalPlayer.Data.Role)
+ {
+ return false;
+ }
+
+ if (PlayerControl.LocalPlayer.Data.Role is not ICustomRole customRole)
+ {
+ return true;
+ }
+
+ if (__instance.currentTarget && __instance.currentTarget != target)
+ {
+ __instance.currentTarget.cosmetics.SetOutline(false, new Nullable(Color.clear));
+ }
+ __instance.currentTarget = target;
+ if (__instance.currentTarget)
+ {
+ __instance.currentTarget.cosmetics.SetOutline(true, new Nullable(customRole.RoleColor));
+ __instance.SetEnabled();
+ return false;
+ }
+ __instance.SetDisabled();
+
+ return false;
+ }
+
+ [HarmonyPrefix]
+ [HarmonyPatch(nameof(KillButton.DoClick))]
+ public static bool DoClickPrefix(KillButton __instance)
+ {
+ if (PlayerControl.LocalPlayer.Data.Role is not ICustomRole)
+ {
+ return true;
+ }
+
+ if (!__instance.isActiveAndEnabled || !__instance.currentTarget || __instance.isCoolingDown ||
+ PlayerControl.LocalPlayer.Data.IsDead || !PlayerControl.LocalPlayer.CanMove)
+ {
+ return false;
+ }
+
+ PlayerControl.LocalPlayer.RpcCustomMurder(__instance.currentTarget);
+ __instance.SetTarget(null);
+
+ return false;
+ }
+}
diff --git a/MiraAPI/Roles/CustomRoleManager.cs b/MiraAPI/Roles/CustomRoleManager.cs
index a3d36ec..7fad146 100644
--- a/MiraAPI/Roles/CustomRoleManager.cs
+++ b/MiraAPI/Roles/CustomRoleManager.cs
@@ -84,7 +84,7 @@ internal static void RegisterRoleTypes(List roles, MiraPluginInfo pluginIn
roleBehaviour.StringName = CustomStringName.CreateAndRegister(customRole.RoleName);
roleBehaviour.BlurbName = CustomStringName.CreateAndRegister(customRole.RoleDescription);
roleBehaviour.BlurbNameLong = CustomStringName.CreateAndRegister(customRole.RoleLongDescription);
- roleBehaviour.AffectedByLightAffectors = customRole.AffectedByLight;
+ roleBehaviour.AffectedByLightAffectors = customRole.AffectedByLightOnAirship;
roleBehaviour.CanBeKilled = customRole.CanGetKilled;
roleBehaviour.CanUseKillButton = customRole.CanUseKill;
roleBehaviour.TasksCountTowardProgress = customRole.TasksCountForProgress;
diff --git a/MiraAPI/Roles/ICustomRole.cs b/MiraAPI/Roles/ICustomRole.cs
index 08875f9..0ac41bb 100644
--- a/MiraAPI/Roles/ICustomRole.cs
+++ b/MiraAPI/Roles/ICustomRole.cs
@@ -68,9 +68,9 @@ public interface ICustomRole
ConfigDefinition ChanceConfigDefinition => new("Roles", $"Chance {GetType().FullName}");
///
- /// Gets a value indicating whether the role is affected by light sabotages.
+ /// Gets a value indicating whether the role is affected by light affectors on Airship.
///
- bool AffectedByLight => Team == ModdedRoleTeams.Crewmate;
+ bool AffectedByLightOnAirship => Team == ModdedRoleTeams.Crewmate;
///
/// Gets a value indicating whether the role can be killed by others.
@@ -80,7 +80,7 @@ public interface ICustomRole
///
/// Gets a value indicating whether the role can kill others.
///
- bool CanKill => Team == ModdedRoleTeams.Impostor;
+ bool CanUseKill => Team == ModdedRoleTeams.Impostor;
///
/// Gets a value indicating whether the role can use vents.
@@ -90,7 +90,7 @@ public interface ICustomRole
///
/// Gets a value indicating whether the role's tasks count towards task progress.
///
- bool TasksCount => Team == ModdedRoleTeams.Crewmate;
+ bool TasksCountForProgress => Team == ModdedRoleTeams.Crewmate;
///
/// Gets a value indicating whether the role is a Ghost.
From 97ded2fc3270d58627e780442bc81ab03162c3f2 Mon Sep 17 00:00:00 2001
From: XtraCube <72575280+XtraCube@users.noreply.github.com>
Date: Mon, 2 Sep 2024 12:53:08 -0400
Subject: [PATCH 13/36] some updates to example mod
---
.../Buttons/Freezer/FreezeButton.cs | 8 +++++---
.../Buttons/Teleporter/TeleportButton.cs | 4 ++--
.../Options/Roles/CustomRole2Settings.cs | 16 ---------------
.../Options/Roles/FreezerRoleSettings.cs | 20 +++++++++++++++++++
.../Options/Roles/TeleporterOptions.cs | 8 ++++----
5 files changed, 31 insertions(+), 25 deletions(-)
delete mode 100644 MiraAPI.Example/Options/Roles/CustomRole2Settings.cs
create mode 100644 MiraAPI.Example/Options/Roles/FreezerRoleSettings.cs
diff --git a/MiraAPI.Example/Buttons/Freezer/FreezeButton.cs b/MiraAPI.Example/Buttons/Freezer/FreezeButton.cs
index f8de0ab..d357932 100644
--- a/MiraAPI.Example/Buttons/Freezer/FreezeButton.cs
+++ b/MiraAPI.Example/Buttons/Freezer/FreezeButton.cs
@@ -1,5 +1,7 @@
using MiraAPI.Example.Modifiers.Freezer;
+using MiraAPI.Example.Options.Roles;
using MiraAPI.Example.Roles;
+using MiraAPI.GameOptions;
using MiraAPI.Hud;
using MiraAPI.Utilities;
using MiraAPI.Utilities.Assets;
@@ -11,9 +13,9 @@ namespace MiraAPI.Example.Buttons.Freezer;
public class FreezeButton : CustomActionButton
{
public override string Name => "Freeze";
- public override float Cooldown => 5f;
+ public override float Cooldown => OptionGroupSingleton.Instance.FreezeDuration;
public override float EffectDuration => 0f;
- public override int MaxUses => 0;
+ public override int MaxUses => (int)OptionGroupSingleton.Instance.FreezeUses;
public override LoadableAsset Sprite => ExampleAssets.ExampleButton;
protected override void OnClick()
@@ -23,7 +25,7 @@ protected override void OnClick()
public override PlayerControl? GetTarget()
{
- return PlayerControl.LocalPlayer.GetClosestPlayer(true, Distance, false);
+ return PlayerControl.LocalPlayer.GetClosestPlayer(true, Distance);
}
public override void SetOutline(bool active)
diff --git a/MiraAPI.Example/Buttons/Teleporter/TeleportButton.cs b/MiraAPI.Example/Buttons/Teleporter/TeleportButton.cs
index 99199b8..3a8d810 100644
--- a/MiraAPI.Example/Buttons/Teleporter/TeleportButton.cs
+++ b/MiraAPI.Example/Buttons/Teleporter/TeleportButton.cs
@@ -13,7 +13,7 @@ public class TeleportButton : CustomActionButton
{
public override string Name => "Teleport";
- public override float Cooldown => OptionGroupSingleton.Instance.TeleportCooldown;
+ public override float Cooldown => OptionGroupSingleton.Instance.TeleportCooldown.Value;
public override float EffectDuration => OptionGroupSingleton.Instance.TeleportDuration;
@@ -22,7 +22,7 @@ public class TeleportButton : CustomActionButton
public override LoadableAsset Sprite => ExampleAssets.TeleportButton;
public static bool IsZoom { get; private set; }
- public override bool Enabled(RoleBehaviour role)
+ public override bool Enabled(RoleBehaviour? role)
{
return role is TeleporterRole;
}
diff --git a/MiraAPI.Example/Options/Roles/CustomRole2Settings.cs b/MiraAPI.Example/Options/Roles/CustomRole2Settings.cs
deleted file mode 100644
index e10931b..0000000
--- a/MiraAPI.Example/Options/Roles/CustomRole2Settings.cs
+++ /dev/null
@@ -1,16 +0,0 @@
-using MiraAPI.Example.Roles;
-using MiraAPI.GameOptions;
-using MiraAPI.GameOptions.Attributes;
-using System;
-
-namespace MiraAPI.Example.Options.Roles;
-
-public class CustomRole2Settings : AbstractOptionGroup
-{
- public override string GroupName => "Custom Role";
-
- public override Type AdvancedRole => typeof(FreezerRole);
-
- [ModdedToggleOption("Teleportation ability")] public bool Teleport { get; set; } = true;
-
-}
\ No newline at end of file
diff --git a/MiraAPI.Example/Options/Roles/FreezerRoleSettings.cs b/MiraAPI.Example/Options/Roles/FreezerRoleSettings.cs
new file mode 100644
index 0000000..0e26665
--- /dev/null
+++ b/MiraAPI.Example/Options/Roles/FreezerRoleSettings.cs
@@ -0,0 +1,20 @@
+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 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;
+
+ [ModdedNumberOption("Freeze Uses", 1, 5)]
+ public float FreezeUses { get; set; } = 1;
+}
diff --git a/MiraAPI.Example/Options/Roles/TeleporterOptions.cs b/MiraAPI.Example/Options/Roles/TeleporterOptions.cs
index b8bb823..34ccb94 100644
--- a/MiraAPI.Example/Options/Roles/TeleporterOptions.cs
+++ b/MiraAPI.Example/Options/Roles/TeleporterOptions.cs
@@ -1,8 +1,9 @@
-using MiraAPI.Example.Roles;
+using System;
+using MiraAPI.Example.Roles;
using MiraAPI.GameOptions;
using MiraAPI.GameOptions.Attributes;
+using MiraAPI.GameOptions.OptionTypes;
using MiraAPI.Utilities;
-using System;
namespace MiraAPI.Example.Options.Roles;
@@ -12,8 +13,7 @@ public class TeleporterOptions : AbstractOptionGroup
public override Type AdvancedRole => typeof(TeleporterRole);
- [ModdedNumberOption("Teleport Cooldown", 5, 60, 2.5f, MiraNumberSuffixes.Seconds)]
- public float TeleportCooldown { get; set; } = 5;
+ public ModdedNumberOption TeleportCooldown { get; set; } = new("Teleport Cooldown", 10, 5, 60, 2.5f, MiraNumberSuffixes.Seconds);
[ModdedNumberOption("Teleport Duration", 5, 25, 1, MiraNumberSuffixes.Seconds)]
public float TeleportDuration { get; set; } = 10;
From 3cada4cb3d0b8df6d25beb5b920ba3b67213d647 Mon Sep 17 00:00:00 2001
From: XtraCube <72575280+XtraCube@users.noreply.github.com>
Date: Mon, 2 Sep 2024 12:57:25 -0400
Subject: [PATCH 14/36] fix problem with TimedModifier using RPC on every
client, despite being replicated
---
MiraAPI/Modifiers/BaseModifier.cs | 5 +++++
MiraAPI/Modifiers/ModifierComponent.cs | 1 +
MiraAPI/Modifiers/Types/TimedModifier.cs | 2 +-
3 files changed, 7 insertions(+), 1 deletion(-)
diff --git a/MiraAPI/Modifiers/BaseModifier.cs b/MiraAPI/Modifiers/BaseModifier.cs
index b91c078..9d6e82c 100644
--- a/MiraAPI/Modifiers/BaseModifier.cs
+++ b/MiraAPI/Modifiers/BaseModifier.cs
@@ -10,6 +10,11 @@ public abstract class BaseModifier
///
public PlayerControl? Player { get; internal set; }
+ ///
+ /// Gets the modifier component that the modifier is attached to.
+ ///
+ public ModifierComponent? ModifierComponent { get; internal set; }
+
///
/// Gets the modifier id.
///
diff --git a/MiraAPI/Modifiers/ModifierComponent.cs b/MiraAPI/Modifiers/ModifierComponent.cs
index eecda1a..9517711 100644
--- a/MiraAPI/Modifiers/ModifierComponent.cs
+++ b/MiraAPI/Modifiers/ModifierComponent.cs
@@ -213,6 +213,7 @@ public void RemoveModifier(BaseModifier modifier)
_toAdd.Add(modifier);
modifier.Player = _player;
+ modifier.ModifierComponent = this;
modifier.ModifierId = modifierId.Value;
return modifier;
}
diff --git a/MiraAPI/Modifiers/Types/TimedModifier.cs b/MiraAPI/Modifiers/Types/TimedModifier.cs
index f18b136..99a6361 100644
--- a/MiraAPI/Modifiers/Types/TimedModifier.cs
+++ b/MiraAPI/Modifiers/Types/TimedModifier.cs
@@ -71,7 +71,7 @@ public override void FixedUpdate()
if (RemoveOnComplete)
{
- Player?.RpcRemoveModifier(ModifierId);
+ ModifierComponent?.RemoveModifier(ModifierId);
}
}
}
From b032e91e089bddf33a462ad6ddb5a9a2e1af0fa9 Mon Sep 17 00:00:00 2001
From: XtraCube <72575280+XtraCube@users.noreply.github.com>
Date: Mon, 2 Sep 2024 12:57:32 -0400
Subject: [PATCH 15/36] using statements
---
MiraAPI/GameOptions/OptionTypes/ModdedEnumOption.cs | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/MiraAPI/GameOptions/OptionTypes/ModdedEnumOption.cs b/MiraAPI/GameOptions/OptionTypes/ModdedEnumOption.cs
index c3f0f5e..7a01f19 100644
--- a/MiraAPI/GameOptions/OptionTypes/ModdedEnumOption.cs
+++ b/MiraAPI/GameOptions/OptionTypes/ModdedEnumOption.cs
@@ -1,8 +1,8 @@
-using MiraAPI.Networking;
-using Reactor.Localization.Utilities;
-using System;
+using System;
using System.Linq;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
+using MiraAPI.Networking;
+using Reactor.Localization.Utilities;
using UnityEngine;
using Object = UnityEngine.Object;
From 3d9bbc0833f450aea8cdf58df327974ddd2eb80a Mon Sep 17 00:00:00 2001
From: XtraCube <72575280+XtraCube@users.noreply.github.com>
Date: Mon, 2 Sep 2024 13:01:34 -0400
Subject: [PATCH 16/36] comments
---
.../Modifiers/RegisterModifierAttribute.cs | 5 +++-
MiraAPI/Networking/MiraRpc.cs | 28 ++++++++++++++++++-
MiraAPI/Networking/NetData.cs | 19 ++++++++++++-
3 files changed, 49 insertions(+), 3 deletions(-)
diff --git a/MiraAPI/Modifiers/RegisterModifierAttribute.cs b/MiraAPI/Modifiers/RegisterModifierAttribute.cs
index 4c2fb56..4858b96 100644
--- a/MiraAPI/Modifiers/RegisterModifierAttribute.cs
+++ b/MiraAPI/Modifiers/RegisterModifierAttribute.cs
@@ -2,5 +2,8 @@
namespace MiraAPI.Modifiers;
+///
+/// Marks a class as a modifier that can be registered with the .
+///
[AttributeUsage(AttributeTargets.Class)]
-public class RegisterModifierAttribute : Attribute;
\ No newline at end of file
+public class RegisterModifierAttribute : Attribute;
diff --git a/MiraAPI/Networking/MiraRpc.cs b/MiraAPI/Networking/MiraRpc.cs
index 40861ce..5126dea 100644
--- a/MiraAPI/Networking/MiraRpc.cs
+++ b/MiraAPI/Networking/MiraRpc.cs
@@ -1,11 +1,37 @@
namespace MiraAPI.Networking;
+///
+/// Mira RPCs.
+///
public enum MiraRpc : uint
{
+ ///
+ /// Syncs the game options.
+ ///
SyncGameOptions,
+
+ ///
+ /// Syncs the role options.
+ ///
SyncRoleOptions,
+
+ ///
+ /// Adds a modifier to a player.
+ ///
AddModifier,
+
+ ///
+ /// Removes a modifier from a player.
+ ///
RemoveModifier,
+
+ ///
+ /// Syncs all modifiers at once.
+ ///
SyncModifiers,
+
+ ///
+ /// Custom Murder RPC.
+ ///
CustomMurder,
-}
\ No newline at end of file
+}
diff --git a/MiraAPI/Networking/NetData.cs b/MiraAPI/Networking/NetData.cs
index 083a9d2..ce5de46 100644
--- a/MiraAPI/Networking/NetData.cs
+++ b/MiraAPI/Networking/NetData.cs
@@ -1,8 +1,25 @@
namespace MiraAPI.Networking;
+///
+/// Used to network data and mark it with an ID.
+///
+/// The ID of the data.
+/// The byte[] data.
public readonly struct NetData(uint id, byte[] data)
{
+ ///
+ /// Gets the ID of the data.
+ ///
public uint Id { get; } = id;
+
+ ///
+ /// Gets the byte[] data.
+ ///
public byte[] Data { get; } = data;
+
+ ///
+ /// Gets the length of the data in bytes.
+ ///
+ /// An int representing the number of bytes this NetData takes up.
public int GetLength() => 4 + Data.Length;
-}
\ No newline at end of file
+}
From dc483adc1c7a564ed8ccca3b6471814a841b4992 Mon Sep 17 00:00:00 2001
From: XtraCube <72575280+XtraCube@users.noreply.github.com>
Date: Mon, 2 Sep 2024 13:04:20 -0400
Subject: [PATCH 17/36] more comments + nullable stuff
---
MiraAPI/Networking/SyncModifiersRpc.cs | 18 ++++++++++++------
MiraAPI/Networking/SyncOptionsRpc.cs | 20 +++++++++++++-------
MiraAPI/Networking/SyncRoleOptionsRpc.cs | 19 ++++++++++++-------
3 files changed, 37 insertions(+), 20 deletions(-)
diff --git a/MiraAPI/Networking/SyncModifiersRpc.cs b/MiraAPI/Networking/SyncModifiersRpc.cs
index 69154f9..9598f0f 100644
--- a/MiraAPI/Networking/SyncModifiersRpc.cs
+++ b/MiraAPI/Networking/SyncModifiersRpc.cs
@@ -10,8 +10,14 @@ internal class SyncModifiersRpc(MiraApiPlugin plugin, uint id) : PlayerCustomRpc
{
public override RpcLocalHandling LocalHandling => RpcLocalHandling.None;
- public override void Write(MessageWriter writer, NetData[] data)
+ public override void Write(MessageWriter writer, NetData[]? data)
{
+ if (data == null)
+ {
+ writer.WritePacked(0U);
+ return;
+ }
+
writer.WritePacked((uint)data.Length);
foreach (var netData in data)
{
@@ -26,21 +32,21 @@ public override NetData[] Read(MessageReader reader)
var data = new NetData[length];
for (var i = 0; i < length; i++)
{
- var id = reader.ReadPackedUInt32();
+ var dataId = reader.ReadPackedUInt32();
var bytes = reader.ReadBytesAndSize();
- data[i] = new NetData(id, bytes);
+ data[i] = new NetData(dataId, bytes);
}
return data;
}
- public override void Handle(PlayerControl playerControl, NetData[] data)
+ public override void Handle(PlayerControl playerControl, NetData[]? data)
{
if (AmongUsClient.Instance.HostId != playerControl.OwnerId)
{
return;
}
- ModifierManager.HandleSyncModifiers(data);
+ ModifierManager.HandleSyncModifiers(data ?? []);
}
-}
\ No newline at end of file
+}
diff --git a/MiraAPI/Networking/SyncOptionsRpc.cs b/MiraAPI/Networking/SyncOptionsRpc.cs
index 98efc70..288c690 100644
--- a/MiraAPI/Networking/SyncOptionsRpc.cs
+++ b/MiraAPI/Networking/SyncOptionsRpc.cs
@@ -10,9 +10,15 @@ namespace MiraAPI.Networking;
internal class SyncOptionsRpc(MiraApiPlugin plugin, uint id) : PlayerCustomRpc(plugin, id)
{
public override RpcLocalHandling LocalHandling => RpcLocalHandling.None;
-
- public override void Write(MessageWriter writer, NetData[] data)
+
+ public override void Write(MessageWriter writer, NetData[]? data)
{
+ if (data == null)
+ {
+ writer.WritePacked(0U);
+ return;
+ }
+
writer.WritePacked((uint)data.Length);
foreach (var netData in data)
{
@@ -27,21 +33,21 @@ public override NetData[] Read(MessageReader reader)
var data = new NetData[length];
for (var i = 0; i < length; i++)
{
- var id = reader.ReadPackedUInt32();
+ var dataId = reader.ReadPackedUInt32();
var bytes = reader.ReadBytesAndSize();
- data[i] = new NetData(id, bytes);
+ data[i] = new NetData(dataId, bytes);
}
return data;
}
- public override void Handle(PlayerControl playerControl, NetData[] data)
+ public override void Handle(PlayerControl playerControl, NetData[]? data)
{
if (AmongUsClient.Instance.HostId != playerControl.OwnerId)
{
return;
}
- ModdedOptionsManager.HandleSyncOptions(data);
+ ModdedOptionsManager.HandleSyncOptions(data ?? []);
}
-}
\ No newline at end of file
+}
diff --git a/MiraAPI/Networking/SyncRoleOptionsRpc.cs b/MiraAPI/Networking/SyncRoleOptionsRpc.cs
index 7160912..290fc0f 100644
--- a/MiraAPI/Networking/SyncRoleOptionsRpc.cs
+++ b/MiraAPI/Networking/SyncRoleOptionsRpc.cs
@@ -8,11 +8,16 @@ namespace MiraAPI.Networking;
[RegisterCustomRpc((uint)MiraRpc.SyncRoleOptions)]
internal class SyncRoleOptionsRpc(MiraApiPlugin plugin, uint id) : PlayerCustomRpc(plugin, id)
{
-
public override RpcLocalHandling LocalHandling => RpcLocalHandling.None;
- public override void Write(MessageWriter writer, NetData[] data)
+ public override void Write(MessageWriter writer, NetData[]? data)
{
+ if (data == null)
+ {
+ writer.WritePacked(0U);
+ return;
+ }
+
writer.WritePacked((uint)data.Length);
foreach (var netData in data)
{
@@ -27,21 +32,21 @@ public override NetData[] Read(MessageReader reader)
var data = new NetData[length];
for (var i = 0; i < length; i++)
{
- var id = reader.ReadPackedUInt32();
+ var dataId = reader.ReadPackedUInt32();
var bytes = reader.ReadBytesAndSize();
- data[i] = new NetData(id, bytes);
+ data[i] = new NetData(dataId, bytes);
}
return data;
}
- public override void Handle(PlayerControl playerControl, NetData[] data)
+ public override void Handle(PlayerControl playerControl, NetData[]? data)
{
if (AmongUsClient.Instance.HostId != playerControl.OwnerId)
{
return;
}
- CustomRoleManager.HandleSyncRoleOptions(data);
+ CustomRoleManager.HandleSyncRoleOptions(data ?? []);
}
-}
\ No newline at end of file
+}
From cb943c2173fa2ea8bfb93e391e881ab0e086d1bc Mon Sep 17 00:00:00 2001
From: XtraCube <72575280+XtraCube@users.noreply.github.com>
Date: Mon, 2 Sep 2024 13:37:45 -0400
Subject: [PATCH 18/36] CanKill -> UseVanillaKillButton ICustomRole changes to
clear up confusion Add KillButtonOutlineColor to ICustomRole
---
MiraAPI.Example/Roles/NeutralKillerRole.cs | 2 +-
MiraAPI/Patches/Roles/KillButtonPatches.cs | 8 ++++-
MiraAPI/Roles/CustomRoleManager.cs | 2 +-
MiraAPI/Roles/ICustomRole.cs | 36 ++++++++++++++--------
4 files changed, 32 insertions(+), 16 deletions(-)
diff --git a/MiraAPI.Example/Roles/NeutralKillerRole.cs b/MiraAPI.Example/Roles/NeutralKillerRole.cs
index 0cbc6fd..820c334 100644
--- a/MiraAPI.Example/Roles/NeutralKillerRole.cs
+++ b/MiraAPI.Example/Roles/NeutralKillerRole.cs
@@ -11,7 +11,7 @@ public class NeutralKillerRole : ImpostorRole, ICustomRole
public string RoleLongDescription => RoleDescription;
public Color RoleColor => Color.magenta;
public ModdedRoleTeams Team => ModdedRoleTeams.Neutral;
- public bool CanUseKill => true;
+ public bool UseVanillaKillButton => true;
public bool CanGetKilled => true;
public bool CanUseVent => true;
diff --git a/MiraAPI/Patches/Roles/KillButtonPatches.cs b/MiraAPI/Patches/Roles/KillButtonPatches.cs
index 52b5cba..7b7010a 100644
--- a/MiraAPI/Patches/Roles/KillButtonPatches.cs
+++ b/MiraAPI/Patches/Roles/KillButtonPatches.cs
@@ -12,6 +12,9 @@ namespace MiraAPI.Patches.Roles;
[HarmonyPatch(typeof(KillButton))]
public static class KillButtonPatches
{
+ ///
+ /// SetTarget for custom roles.
+ ///
[HarmonyPrefix]
[HarmonyPatch(nameof(KillButton.SetTarget))]
public static bool SetTargetPrefix(KillButton __instance, PlayerControl target)
@@ -33,7 +36,7 @@ public static bool SetTargetPrefix(KillButton __instance, PlayerControl target)
__instance.currentTarget = target;
if (__instance.currentTarget)
{
- __instance.currentTarget.cosmetics.SetOutline(true, new Nullable(customRole.RoleColor));
+ __instance.currentTarget.cosmetics.SetOutline(true, new Nullable(customRole.KillButtonOutlineColor));
__instance.SetEnabled();
return false;
}
@@ -42,6 +45,9 @@ public static bool SetTargetPrefix(KillButton __instance, PlayerControl target)
return false;
}
+ ///
+ /// Use Custom Murder if player is custom role.
+ ///
[HarmonyPrefix]
[HarmonyPatch(nameof(KillButton.DoClick))]
public static bool DoClickPrefix(KillButton __instance)
diff --git a/MiraAPI/Roles/CustomRoleManager.cs b/MiraAPI/Roles/CustomRoleManager.cs
index 7fad146..f63a5c8 100644
--- a/MiraAPI/Roles/CustomRoleManager.cs
+++ b/MiraAPI/Roles/CustomRoleManager.cs
@@ -86,7 +86,7 @@ internal static void RegisterRoleTypes(List roles, MiraPluginInfo pluginIn
roleBehaviour.BlurbNameLong = CustomStringName.CreateAndRegister(customRole.RoleLongDescription);
roleBehaviour.AffectedByLightAffectors = customRole.AffectedByLightOnAirship;
roleBehaviour.CanBeKilled = customRole.CanGetKilled;
- roleBehaviour.CanUseKillButton = customRole.CanUseKill;
+ roleBehaviour.CanUseKillButton = customRole.UseVanillaKillButton;
roleBehaviour.TasksCountTowardProgress = customRole.TasksCountForProgress;
roleBehaviour.CanVent = customRole.CanUseVent;
roleBehaviour.DefaultGhostRole = customRole.GhostRole;
diff --git a/MiraAPI/Roles/ICustomRole.cs b/MiraAPI/Roles/ICustomRole.cs
index 0ac41bb..3087dbe 100644
--- a/MiraAPI/Roles/ICustomRole.cs
+++ b/MiraAPI/Roles/ICustomRole.cs
@@ -57,30 +57,20 @@ public interface ICustomRole
[HideFromIl2Cpp]
LoadableAsset Icon => MiraAssets.Empty;
- ///
- /// Gets the BepInEx ConfigDefinition for the amount of players that can have this role.
- ///
- ConfigDefinition NumConfigDefinition => new("Roles", $"Num {GetType().FullName}");
-
- ///
- /// Gets the BepInEx ConfigDefinition for the chance of this role being selected.
- ///
- ConfigDefinition ChanceConfigDefinition => new("Roles", $"Chance {GetType().FullName}");
-
///
/// Gets a value indicating whether the role is affected by light affectors on Airship.
///
bool AffectedByLightOnAirship => Team == ModdedRoleTeams.Crewmate;
///
- /// Gets a value indicating whether the role can be killed by others.
+ /// Gets a value indicating whether the role can be killed by vanilla murder system.
///
bool CanGetKilled => Team == ModdedRoleTeams.Crewmate;
///
- /// Gets a value indicating whether the role can kill others.
+ /// Gets a value indicating whether the role should use the vanilla kill button.
///
- bool CanUseKill => Team == ModdedRoleTeams.Impostor;
+ bool UseVanillaKillButton => Team == ModdedRoleTeams.Impostor;
///
/// Gets a value indicating whether the role can use vents.
@@ -102,6 +92,16 @@ public interface ICustomRole
///
bool HideSettings => IsGhostRole;
+ ///
+ /// Gets the outline color for the KillButton if is true.
+ ///
+ Color KillButtonOutlineColor => Team switch
+ {
+ ModdedRoleTeams.Impostor => Palette.ImpostorRed,
+ ModdedRoleTeams.Crewmate => Palette.CrewmateBlue,
+ _ => RoleColor,
+ };
+
///
/// Gets the role hint style. See enum for all options.
///
@@ -112,6 +112,16 @@ public interface ICustomRole
///
RoleTypes GhostRole => Team == ModdedRoleTeams.Impostor ? RoleTypes.ImpostorGhost : RoleTypes.CrewmateGhost;
+ ///
+ /// Gets the BepInEx ConfigDefinition for the amount of players that can have this role.
+ ///
+ ConfigDefinition NumConfigDefinition => new("Roles", $"Num {GetType().FullName}");
+
+ ///
+ /// Gets the BepInEx ConfigDefinition for the chance of this role being selected.
+ ///
+ ConfigDefinition ChanceConfigDefinition => new("Roles", $"Chance {GetType().FullName}");
+
///
/// Gets the parent mod of this role.
///
From 9665188a18461b50e1a46ec9f5e4978e06868f72 Mon Sep 17 00:00:00 2001
From: XtraCube <72575280+XtraCube@users.noreply.github.com>
Date: Mon, 2 Sep 2024 13:46:10 -0400
Subject: [PATCH 19/36] various adjustments to code style
---
MiraAPI/GameOptions/IModdedOption.cs | 2 +-
MiraAPI/Patches/Modifiers/VentPatches.cs | 4 +-
.../Options/NotificationPopperPatch.cs | 34 ++---
.../Patches/Options/RoleSettingMenuPatches.cs | 118 +++++++++++++-----
4 files changed, 107 insertions(+), 51 deletions(-)
diff --git a/MiraAPI/GameOptions/IModdedOption.cs b/MiraAPI/GameOptions/IModdedOption.cs
index 4f7e950..544d64b 100644
--- a/MiraAPI/GameOptions/IModdedOption.cs
+++ b/MiraAPI/GameOptions/IModdedOption.cs
@@ -17,7 +17,7 @@ internal interface IModdedOption
OptionBehaviour? OptionBehaviour { get; }
Func Visible { get; set; }
ConfigDefinition? ConfigDefinition { get; set; }
- OptionBehaviour? CreateOption(ToggleOption toggleOpt, NumberOption numberOpt, StringOption stringOpt, Transform container);
+ OptionBehaviour CreateOption(ToggleOption toggleOpt, NumberOption numberOpt, StringOption stringOpt, Transform container);
float GetFloatData();
NetData GetNetData();
void HandleNetData(byte[] data);
diff --git a/MiraAPI/Patches/Modifiers/VentPatches.cs b/MiraAPI/Patches/Modifiers/VentPatches.cs
index 6894848..4aeea09 100644
--- a/MiraAPI/Patches/Modifiers/VentPatches.cs
+++ b/MiraAPI/Patches/Modifiers/VentPatches.cs
@@ -23,10 +23,10 @@ public static void CanUseVentPatch(Vent __instance, ref float __result, [Harmony
switch (role.CanVent)
{
- case true when modifiers.Any(x => !x.CanVent()):
+ case true when modifiers.Exists(x => !x.CanVent()):
couldUse = canUse = false;
return;
- case false when modifiers.Any(x => x.CanVent()):
+ case false when modifiers.Exists(x => x.CanVent()):
couldUse = true;
break;
}
diff --git a/MiraAPI/Patches/Options/NotificationPopperPatch.cs b/MiraAPI/Patches/Options/NotificationPopperPatch.cs
index 0a8fc57..faa24eb 100644
--- a/MiraAPI/Patches/Options/NotificationPopperPatch.cs
+++ b/MiraAPI/Patches/Options/NotificationPopperPatch.cs
@@ -6,34 +6,38 @@
namespace MiraAPI.Patches.Options;
[HarmonyPatch(typeof(NotificationPopper))]
-public class NotificationPopperPatch
+public static class NotificationPopperPatch
{
[HarmonyPrefix]
[HarmonyPatch(nameof(NotificationPopper.AddRoleSettingsChangeMessage))]
- public static bool RoleChangeMsgPatch(NotificationPopper __instance,
- [HarmonyArgument(0)] StringNames key, [HarmonyArgument(1)] int roleCount, [HarmonyArgument(2)] int roleChance, [HarmonyArgument(3)] RoleTeamTypes teamType,
+ public static bool RoleChangeMsgPatch(
+ NotificationPopper __instance,
+ [HarmonyArgument(0)] StringNames key,
+ [HarmonyArgument(1)] int roleCount,
+ [HarmonyArgument(2)] int roleChance,
+ [HarmonyArgument(3)] RoleTeamTypes teamType,
[HarmonyArgument(4)] bool playSound)
{
if (CustomRoleManager.CustomRoles.Values.Any(role => role.StringName == key))
{
- var item = string.Empty;
- var text = (teamType == RoleTeamTypes.Crewmate) ? Palette.CrewmateSettingChangeText.ToTextColor() : Palette.ImpostorRed.ToTextColor();
- item = DestroyableSingleton.Instance.GetString(StringNames.LobbyChangeSettingNotificationRole, new Object[]
- {
- string.Concat(
- [
+ var text = teamType == RoleTeamTypes.Crewmate
+ ? Palette.CrewmateSettingChangeText.ToTextColor()
+ : Palette.ImpostorRed.ToTextColor();
+
+ var item = DestroyableSingleton.Instance.GetString(
+ StringNames.LobbyChangeSettingNotificationRole,
"",
text,
DestroyableSingleton.Instance.GetString(key, Array.Empty"
- ]),
- "" + roleCount.ToString() + "",
- "" + roleChance.ToString() + "%"
- });
+ "",
+ "" + roleCount + "",
+ "" + roleChance + "%"
+ );
+
__instance.SettingsChangeMessageLogic(key, item, playSound);
return false;
}
return true;
}
-}
\ No newline at end of file
+}
diff --git a/MiraAPI/Patches/Options/RoleSettingMenuPatches.cs b/MiraAPI/Patches/Options/RoleSettingMenuPatches.cs
index 420fff8..8ba2c93 100644
--- a/MiraAPI/Patches/Options/RoleSettingMenuPatches.cs
+++ b/MiraAPI/Patches/Options/RoleSettingMenuPatches.cs
@@ -54,58 +54,72 @@ public static bool PatchStart(RolesSettingsMenu __instance)
var num3 = 0;
- var crewRoles = GameSettingMenuPatches.SelectedMod.CustomRoles.Values
+ var crewRoles = GameSettingMenuPatches.SelectedMod?.CustomRoles.Values
.OfType()
- .Where(role => role.Team == ModdedRoleTeams.Crewmate && !role.HideSettings)
+ .Where(role => role is { Team: ModdedRoleTeams.Crewmate, HideSettings: false })
.ToList();
- if (crewRoles.Count > 0)
+ if (crewRoles is { Count: > 0 })
{
-
- var categoryHeaderEditRole = Object.Instantiate(__instance.categoryHeaderEditRoleOrigin, Vector3.zero, Quaternion.identity, __instance.RoleChancesSettings.transform);
+ var categoryHeaderEditRole = Object.Instantiate(
+ __instance.categoryHeaderEditRoleOrigin,
+ Vector3.zero,
+ Quaternion.identity,
+ __instance.RoleChancesSettings.transform);
categoryHeaderEditRole.SetHeader(StringNames.CrewmateRolesHeader, 20);
categoryHeaderEditRole.transform.localPosition = new Vector3(4.986f, num, -2f);
num -= 0.522f;
foreach (var role in crewRoles)
{
- CreateQuotaOption(__instance, role as RoleBehaviour, ref num, num3);
+ if (role is RoleBehaviour roleBehaviour)
+ {
+ CreateQuotaOption(__instance, roleBehaviour, ref num, num3);
+ }
num3++;
}
}
- var impRoles = GameSettingMenuPatches.SelectedMod.CustomRoles.Values
+ var impRoles = GameSettingMenuPatches.SelectedMod?.CustomRoles.Values
.OfType()
- .Where(role => role.Team == ModdedRoleTeams.Impostor && !role.HideSettings)
+ .Where(role => role is { Team: ModdedRoleTeams.Impostor, HideSettings: false })
.ToList();
- if (impRoles.Count > 0)
+ if (impRoles is { Count: > 0 })
{
num -= 0.4f;
- var categoryHeaderEditRole2 = Object.Instantiate(__instance.categoryHeaderEditRoleOrigin,
- Vector3.zero, Quaternion.identity, __instance.RoleChancesSettings.transform);
+ var categoryHeaderEditRole2 = Object.Instantiate(
+ __instance.categoryHeaderEditRoleOrigin,
+ Vector3.zero,
+ Quaternion.identity,
+ __instance.RoleChancesSettings.transform);
categoryHeaderEditRole2.SetHeader(StringNames.ImpostorRolesHeader, 20);
categoryHeaderEditRole2.transform.localPosition = new Vector3(4.986f, num, -2f);
num -= 0.522f;
-
foreach (var role in impRoles)
{
- CreateQuotaOption(__instance, role as RoleBehaviour, ref num, num3);
+ if (role is RoleBehaviour roleBehaviour)
+ {
+ CreateQuotaOption(__instance, roleBehaviour, ref num, num3);
+ }
num3++;
}
}
- var neutRoles = GameSettingMenuPatches.SelectedMod.CustomRoles.Values
+ var neutRoles = GameSettingMenuPatches.SelectedMod?.CustomRoles.Values
.OfType()
- .Where(role => role.Team == ModdedRoleTeams.Neutral && !role.HideSettings)
+ .Where(role => role is { Team: ModdedRoleTeams.Neutral, HideSettings: false })
.ToList();
- if (neutRoles.Count > 0)
+ if (neutRoles is { Count: > 0 })
{
num -= 0.4f;
- var categoryHeaderEditRole3 = Object.Instantiate(__instance.categoryHeaderEditRoleOrigin,
- Vector3.zero, Quaternion.identity, __instance.RoleChancesSettings.transform);
+ var categoryHeaderEditRole3 = Object.Instantiate(
+ __instance.categoryHeaderEditRoleOrigin,
+ Vector3.zero,
+ Quaternion.identity,
+ __instance.RoleChancesSettings.transform);
categoryHeaderEditRole3.SetHeader(StringNames.None, 20);
categoryHeaderEditRole3.Title.text = "Neutral Roles";
categoryHeaderEditRole3.Background.color = Color.gray;
@@ -115,7 +129,10 @@ public static bool PatchStart(RolesSettingsMenu __instance)
foreach (var role in neutRoles)
{
- CreateQuotaOption(__instance, role as RoleBehaviour, ref num, num3);
+ if (role is RoleBehaviour roleBehaviour)
+ {
+ CreateQuotaOption(__instance, roleBehaviour, ref num, num3);
+ }
num3++;
}
}
@@ -161,12 +178,18 @@ private static void ValueChanged(OptionBehaviour obj)
}
roleSetting.UpdateValuesAndText(GameOptionsManager.Instance.CurrentGameOptions.RoleOptions);
- DestroyableSingleton.Instance.Notifier.AddRoleSettingsChangeMessage(roleSetting.Role.StringName, roleSetting.RoleMaxCount, roleSetting.RoleChance, roleSetting.Role.TeamType, false);
+ DestroyableSingleton.Instance.Notifier.AddRoleSettingsChangeMessage(
+ roleSetting.Role.StringName,
+ roleSetting.RoleMaxCount,
+ roleSetting.RoleChance,
+ roleSetting.Role.TeamType,
+ false);
if (AmongUsClient.Instance.AmHost)
{
Rpc.Instance.Send(PlayerControl.LocalPlayer, [role.GetNetData()], true);
}
+
GameOptionsManager.Instance.GameHostOptions = GameOptionsManager.Instance.CurrentGameOptions;
}
@@ -181,7 +204,7 @@ private static void CreateAdvancedSettings(RolesSettingsMenu __instance, RoleBeh
var num = -0.872f;
- var filteredOptions = GameSettingMenuPatches.SelectedMod.Options.Where(x => x.AdvancedRole == role.GetType());
+ var filteredOptions = GameSettingMenuPatches.SelectedMod?.Options.Where(x => x.AdvancedRole == role.GetType()) ?? [];
foreach (var option in filteredOptions)
{
@@ -190,7 +213,12 @@ private static void CreateAdvancedSettings(RolesSettingsMenu __instance, RoleBeh
continue;
}
- var newOpt = option.CreateOption(__instance.checkboxOrigin, __instance.numberOptionOrigin, __instance.stringOptionOrigin, __instance.AdvancedRolesSettings.transform);
+ var newOpt = option.CreateOption(
+ __instance.checkboxOrigin,
+ __instance.numberOptionOrigin,
+ __instance.stringOptionOrigin,
+ __instance.AdvancedRolesSettings.transform);
+
newOpt.transform.localPosition = new Vector3(2.17f, num, -2f);
newOpt.SetClickMask(__instance.ButtonClickMask);
@@ -199,10 +227,11 @@ private static void CreateAdvancedSettings(RolesSettingsMenu __instance, RoleBeh
{
renderer.material.SetInt(PlayerMaterial.MaskLayer, 20);
}
- foreach (var textMeshPro in newOpt.GetComponentsInChildren(true))
+
+ foreach (var fontMat in newOpt.GetComponentsInChildren(true).Select(x=>x.fontMaterial))
{
- textMeshPro.fontMaterial.SetFloat(ShaderID.StencilComp, 3f);
- textMeshPro.fontMaterial.SetFloat(ShaderID.Stencil, 20);
+ fontMat.SetFloat(ShaderID.StencilComp, 3f);
+ fontMat.SetFloat(ShaderID.Stencil, 20);
}
newOpt.LabelBackground.enabled = false;
@@ -215,12 +244,24 @@ private static void CreateAdvancedSettings(RolesSettingsMenu __instance, RoleBeh
__instance.scrollBar.CalculateAndSetYBounds(__instance.advancedSettingChildren.Count + 3, 1f, 6f, 0.45f);
__instance.scrollBar.ScrollToTop();
}
+
private static void ChangeTab(RoleBehaviour role, RolesSettingsMenu __instance)
{
- var customRole = role as ICustomRole;
+ if (role is not ICustomRole customRole)
+ {
+ Logger.Error($"Role {role.NiceName} is not a custom role.");
+ return;
+ }
+
__instance.roleDescriptionText.text = customRole.RoleLongDescription;
- __instance.roleTitleText.text = DestroyableSingleton.Instance.GetString(role.StringName, new Il2CppReferenceArray(0));
- __instance.roleScreenshot.sprite = Sprite.Create(customRole.OptionsScreenshot.LoadAsset().texture, new Rect(0, 0, 370, 230), Vector2.one / 2, 100);
+ __instance.roleTitleText.text = DestroyableSingleton.Instance.GetString(
+ role.StringName,
+ new Il2CppReferenceArray(0));
+ __instance.roleScreenshot.sprite = Sprite.Create(
+ customRole.OptionsScreenshot.LoadAsset().texture,
+ new Rect(0, 0, 370, 230),
+ Vector2.one / 2,
+ 100);
__instance.roleScreenshot.drawMode = SpriteDrawMode.Sliced;
__instance.roleHeaderSprite.color = customRole.RoleColor;
__instance.roleHeaderText.color = customRole.RoleColor.GetAlternateColor();
@@ -244,15 +285,25 @@ private static void ChangeTab(RoleBehaviour role, RolesSettingsMenu __instance)
optionBehaviour.SetAsPlayer();
}
}
+
__instance.RoleChancesSettings.SetActive(false);
__instance.AdvancedRolesSettings.SetActive(true);
__instance.RefreshChildren();
}
- public static void CreateQuotaOption(RolesSettingsMenu __instance, RoleBehaviour role, ref float yPos, int index)
+ private static void CreateQuotaOption(RolesSettingsMenu __instance, RoleBehaviour role, ref float yPos, int index)
{
- var customRole = role as ICustomRole;
- var roleOptionSetting = Object.Instantiate(__instance.roleOptionSettingOrigin, Vector3.zero, Quaternion.identity, __instance.RoleChancesSettings.transform);
+ if (role is not ICustomRole customRole)
+ {
+ Logger.Error($"Role {role.NiceName} is not a custom role.");
+ return;
+ }
+
+ var roleOptionSetting = Object.Instantiate(
+ __instance.roleOptionSettingOrigin,
+ Vector3.zero,
+ Quaternion.identity,
+ __instance.RoleChancesSettings.transform);
roleOptionSetting.transform.localPosition = new Vector3(-0.15f, yPos, -2f);
roleOptionSetting.SetRole(GameOptionsManager.Instance.CurrentGameOptions.RoleOptions, role, 20);
roleOptionSetting.labelSprite.color = customRole.RoleColor;
@@ -265,7 +316,8 @@ public static void CreateQuotaOption(RolesSettingsMenu __instance, RoleBehaviour
roleOptionSetting.titleText.horizontalAlignment = HorizontalAlignmentOptions.Left;
if (GameSettingMenuPatches.SelectedMod is null ||
- GameSettingMenuPatches.SelectedMod.Options.Any(x => x.AdvancedRole != null && x.AdvancedRole.IsInstanceOfType(role)))
+ GameSettingMenuPatches.SelectedMod.Options.Exists(
+ x => x.AdvancedRole != null && x.AdvancedRole.IsInstanceOfType(role)))
{
var newButton = Object.Instantiate(roleOptionSetting.buttons[0], roleOptionSetting.transform);
newButton.name = "ConfigButton";
@@ -289,4 +341,4 @@ public static void CreateQuotaOption(RolesSettingsMenu __instance, RoleBehaviour
yPos += -0.43f;
}
}
-}
\ No newline at end of file
+}
From 812cef5f2b18ce3e532f3f71954b1f1b7e6ef6e5 Mon Sep 17 00:00:00 2001
From: XtraCube <72575280+XtraCube@users.noreply.github.com>
Date: Mon, 2 Sep 2024 14:10:44 -0400
Subject: [PATCH 20/36] fix loadable asset code docs and rework logic slightly
---
MiraAPI/Utilities/Assets/LoadableAsset.cs | 14 ++++++-------
.../Utilities/Assets/LoadableBundleAsset.cs | 20 +++++++++----------
.../Utilities/Assets/LoadableResourceAsset.cs | 20 ++++++++-----------
3 files changed, 25 insertions(+), 29 deletions(-)
diff --git a/MiraAPI/Utilities/Assets/LoadableAsset.cs b/MiraAPI/Utilities/Assets/LoadableAsset.cs
index 464da65..798dfc9 100644
--- a/MiraAPI/Utilities/Assets/LoadableAsset.cs
+++ b/MiraAPI/Utilities/Assets/LoadableAsset.cs
@@ -5,17 +5,17 @@
/// Mira uses the pattern in various locations.
/// You can create your own implementation of this class to load assets in different ways.
///
-/// The type of the asset to be loaded
+/// The type of the asset to be loaded.
public abstract class LoadableAsset where T : UnityEngine.Object
{
///
- /// A reference to the loaded asset. Intended to be used for caching purposes.
+ /// Gets or sets reference to the loaded asset. Intended to be used for caching purposes.
///
- protected T LoadedAsset;
-
+ protected T? LoadedAsset { get; set; }
+
///
- /// The method that loads the asset.
+ /// Loads the asset from the source.
///
- /// The loaded asset
+ /// The loaded asset.
public abstract T LoadAsset();
-}
\ No newline at end of file
+}
diff --git a/MiraAPI/Utilities/Assets/LoadableBundleAsset.cs b/MiraAPI/Utilities/Assets/LoadableBundleAsset.cs
index 8ce1b07..6f46eef 100644
--- a/MiraAPI/Utilities/Assets/LoadableBundleAsset.cs
+++ b/MiraAPI/Utilities/Assets/LoadableBundleAsset.cs
@@ -7,30 +7,30 @@ namespace MiraAPI.Utilities.Assets;
///
/// A utility class for loading assets from an asset bundle.
///
-/// The name of the asset
-/// The AssetBundle that contains the asset
-/// The type of the asset to be loaded
+/// The name of the asset.
+/// The AssetBundle that contains the asset.
+/// The type of the asset to be loaded.
public class LoadableBundleAsset(string name, AssetBundle bundle) : LoadableAsset where T : UnityEngine.Object
{
///
/// Loads the asset from the asset bundle.
///
- /// The asset
+ /// The asset.
/// The asset did not load properly.
public override T LoadAsset()
{
- if (LoadedAsset)
+ if (LoadedAsset != null)
{
return LoadedAsset;
}
LoadedAsset = bundle.LoadAsset(name);
-
- if (!LoadedAsset)
+
+ if (LoadedAsset == null)
{
- throw new Exception($"INVALID ASSET: {name}");
+ throw new InvalidOperationException($"INVALID ASSET: {name}");
}
-
+
return LoadedAsset;
}
-}
\ No newline at end of file
+}
diff --git a/MiraAPI/Utilities/Assets/LoadableResourceAsset.cs b/MiraAPI/Utilities/Assets/LoadableResourceAsset.cs
index 29ce7ad..1dfda4a 100644
--- a/MiraAPI/Utilities/Assets/LoadableResourceAsset.cs
+++ b/MiraAPI/Utilities/Assets/LoadableResourceAsset.cs
@@ -1,28 +1,24 @@
using System.Reflection;
-using Reactor.Utilities;
using UnityEngine;
namespace MiraAPI.Utilities.Assets;
+///
+/// A utility class for loading assets from embedded resources.
+///
+/// The path to the embedded resource.
public class LoadableResourceAsset(string path) : LoadableAsset
{
private readonly Assembly _assembly = Assembly.GetCallingAssembly();
+ ///
public override Sprite LoadAsset()
{
- if (LoadedAsset)
+ if (LoadedAsset != null)
{
return LoadedAsset;
}
- try
- {
- return LoadedAsset = SpriteTools.LoadSpriteFromPath(path, _assembly);
- }
- catch
- {
- Logger.Error($"Not loading, invalid asset: {path}");
- return null;
- }
+ return LoadedAsset = SpriteTools.LoadSpriteFromPath(path, _assembly);
}
-}
\ No newline at end of file
+}
From 74055b8a175e90f05e6926a7120157e49f05811f Mon Sep 17 00:00:00 2001
From: XtraCube <72575280+XtraCube@users.noreply.github.com>
Date: Mon, 2 Sep 2024 14:11:10 -0400
Subject: [PATCH 21/36] various code alterations to patches to fix warnings
---
MiraAPI/Modifiers/Types/TimedModifier.cs | 1 -
MiraAPI/Patches/AmongUsClientSyncPatch.cs | 5 +-
MiraAPI/Patches/IntroCutscenePatches.cs | 47 +--
MiraAPI/Patches/Modifiers/VentPatches.cs | 1 -
.../Patches/Options/GameOptionsMenuPatch.cs | 56 +++-
.../Patches/Options/LobbyViewPanePatches.cs | 300 ++++++++++--------
.../Options/NotificationPopperPatch.cs | 34 +-
MiraAPI/Patches/Options/OptionsPatches.cs | 15 +-
.../Patches/Options/RoleSettingMenuPatches.cs | 6 +-
MiraAPI/Patches/Options/SettingPatches.cs | 31 +-
MiraAPI/Patches/Roles/NameTagPatch.cs | 2 +-
MiraAPI/Patches/Roles/RoleBehaviourPatches.cs | 2 +-
MiraAPI/Patches/Roles/RoleManagerPatches.cs | 9 +-
.../Roles/RoleOptionsCollectionPatch.cs | 8 +-
MiraAPI/Patches/Roles/TaskAdderPatch.cs | 194 ++++++-----
MiraAPI/Patches/Roles/TaskPanelPatch.cs | 39 ++-
MiraAPI/Patches/Roles/VentOutlinePatch.cs | 3 +
17 files changed, 438 insertions(+), 315 deletions(-)
diff --git a/MiraAPI/Modifiers/Types/TimedModifier.cs b/MiraAPI/Modifiers/Types/TimedModifier.cs
index 99a6361..b189b47 100644
--- a/MiraAPI/Modifiers/Types/TimedModifier.cs
+++ b/MiraAPI/Modifiers/Types/TimedModifier.cs
@@ -1,5 +1,4 @@
using System;
-using MiraAPI.Utilities;
using Reactor.Utilities;
using UnityEngine;
diff --git a/MiraAPI/Patches/AmongUsClientSyncPatch.cs b/MiraAPI/Patches/AmongUsClientSyncPatch.cs
index a25dc3f..3034b42 100644
--- a/MiraAPI/Patches/AmongUsClientSyncPatch.cs
+++ b/MiraAPI/Patches/AmongUsClientSyncPatch.cs
@@ -6,6 +6,9 @@
namespace MiraAPI.Patches;
+///
+/// Sync all options, role settings, and modifiers to the player when they join the game.
+///
[HarmonyPatch(typeof(AmongUsClient), nameof(AmongUsClient.CreatePlayer))]
public static class AmongUsClientSyncPatch
{
@@ -25,4 +28,4 @@ public static void Postfix(ClientData clientData)
CustomRoleManager.SyncAllRoleSettings(clientData.Id);
ModifierManager.SyncAllModifiers(clientData.Id);
}
-}
\ No newline at end of file
+}
diff --git a/MiraAPI/Patches/IntroCutscenePatches.cs b/MiraAPI/Patches/IntroCutscenePatches.cs
index 3dab1ed..2250d3d 100644
--- a/MiraAPI/Patches/IntroCutscenePatches.cs
+++ b/MiraAPI/Patches/IntroCutscenePatches.cs
@@ -24,28 +24,33 @@ public static void BeginImpostorPatch(IntroCutscene __instance)
[HarmonyPatch(nameof(IntroCutscene.BeginCrewmate))]
public static bool BeginCrewmatePatch(IntroCutscene __instance)
{
- if (PlayerControl.LocalPlayer.Data.Role is ICustomRole customRole)
+ if (PlayerControl.LocalPlayer.Data.Role is not ICustomRole customRole)
{
- if (customRole.Team is not ModdedRoleTeams.Neutral)
- {
- return true;
- }
-
- var barTransform = __instance.BackgroundBar.transform;
- var position = barTransform.position;
- position.y -= 0.25f;
- barTransform.position = position;
-
- __instance.BackgroundBar.material.SetColor(ShaderID.Color, Color.gray);
- __instance.TeamTitle.text = "NEUTRAL";
- __instance.impostorScale = 1f;
- __instance.ImpostorText.text = "You are Neutral. You do not have a team.";
- __instance.TeamTitle.color = Color.gray;
-
- __instance.ourCrewmate = __instance.CreatePlayer(0, Mathf.CeilToInt(7.5f), PlayerControl.LocalPlayer.Data, false);
- return false;
+ return true;
}
- return true;
+
+ if (customRole.Team is not ModdedRoleTeams.Neutral)
+ {
+ return true;
+ }
+
+ var barTransform = __instance.BackgroundBar.transform;
+ var position = barTransform.position;
+ position.y -= 0.25f;
+ barTransform.position = position;
+
+ __instance.BackgroundBar.material.SetColor(ShaderID.Color, Color.gray);
+ __instance.TeamTitle.text = "NEUTRAL";
+ __instance.impostorScale = 1f;
+ __instance.ImpostorText.text = "You are Neutral. You do not have a team.";
+ __instance.TeamTitle.color = Color.gray;
+
+ __instance.ourCrewmate = __instance.CreatePlayer(
+ 0,
+ Mathf.CeilToInt(7.5f),
+ PlayerControl.LocalPlayer.Data,
+ false);
+ return false;
}
/*
@@ -55,4 +60,4 @@ public static void GameBeginPatch()
{
CustomGameModeManager.ActiveMode?.Initialize();
}*/
-}
\ No newline at end of file
+}
diff --git a/MiraAPI/Patches/Modifiers/VentPatches.cs b/MiraAPI/Patches/Modifiers/VentPatches.cs
index 4aeea09..6646336 100644
--- a/MiraAPI/Patches/Modifiers/VentPatches.cs
+++ b/MiraAPI/Patches/Modifiers/VentPatches.cs
@@ -1,6 +1,5 @@
using HarmonyLib;
using MiraAPI.Utilities;
-using System.Linq;
using UnityEngine;
namespace MiraAPI.Patches.Modifiers;
diff --git a/MiraAPI/Patches/Options/GameOptionsMenuPatch.cs b/MiraAPI/Patches/Options/GameOptionsMenuPatch.cs
index 4c47865..a51b2f9 100644
--- a/MiraAPI/Patches/Options/GameOptionsMenuPatch.cs
+++ b/MiraAPI/Patches/Options/GameOptionsMenuPatch.cs
@@ -30,12 +30,14 @@ public static void UpdatePatch(GameOptionsMenu __instance)
}
var num = 2.1f;
- var filteredGroups = GameSettingMenuPatches.SelectedMod.OptionGroups.Where(x => x.GroupVisible.Invoke() && x.AdvancedRole is null);
+ var filteredGroups =
+ GameSettingMenuPatches.SelectedMod?.OptionGroups.Where(
+ x => x.GroupVisible.Invoke() && x.AdvancedRole is null) ?? [];
foreach (var group in filteredGroups)
{
var filteredOpts = group.Options.Where(x => x.Visible.Invoke()).ToList();
- if (filteredOpts.Count == 0)
+ if (filteredOpts.Count == 0 || group.Header is null)
{
continue;
}
@@ -50,7 +52,12 @@ public static void UpdatePatch(GameOptionsMenu __instance)
{
var newOpt = opt.OptionBehaviour;
- if (opt.Visible.Invoke() == false)
+ if (newOpt is null)
+ {
+ continue;
+ }
+
+ if (!opt.Visible.Invoke())
{
newOpt.gameObject.SetActive(false);
continue;
@@ -70,7 +77,6 @@ public static void UpdatePatch(GameOptionsMenu __instance)
}
__instance.scrollBar.SetYBoundsMax(-num - 1.65f);
-
}
[HarmonyPrefix]
@@ -84,11 +90,15 @@ public static bool SettingsPatch(GameOptionsMenu __instance)
__instance.MapPicker.gameObject.SetActive(false);
- var filteredGroups = GameSettingMenuPatches.SelectedMod.OptionGroups.Where(x => x.AdvancedRole is null);
+ var filteredGroups = GameSettingMenuPatches.SelectedMod?.OptionGroups.Where(x => x.AdvancedRole is null) ?? [];
foreach (var group in filteredGroups)
{
- var categoryHeaderMasked = Object.Instantiate(__instance.categoryHeaderOrigin, Vector3.zero, Quaternion.identity, __instance.settingsContainer);
+ var categoryHeaderMasked = Object.Instantiate(
+ __instance.categoryHeaderOrigin,
+ Vector3.zero,
+ Quaternion.identity,
+ __instance.settingsContainer);
categoryHeaderMasked.SetHeader(CustomStringName.CreateAndRegister(group.GroupName), 20);
if (group.GroupColor != Color.clear)
{
@@ -96,7 +106,10 @@ public static bool SettingsPatch(GameOptionsMenu __instance)
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.Background.size = new Vector2(
+ categoryHeaderMasked.Background.size.x + 1.5f,
+ categoryHeaderMasked.Background.size.y);
categoryHeaderMasked.gameObject.SetActive(false);
group.Header = categoryHeaderMasked;
@@ -105,8 +118,12 @@ public static bool SettingsPatch(GameOptionsMenu __instance)
newText.transform.localPosition = new Vector3(2.6249f, -0.165f, 0f);
newText.gameObject.GetComponent().Destroy();
- var options = group.Options.Select(opt => opt.CreateOption(__instance.checkboxOrigin,
- __instance.numberOptionOrigin, __instance.stringOptionOrigin, __instance.settingsContainer));
+ var options = group.Options.Select(
+ opt => opt.CreateOption(
+ __instance.checkboxOrigin,
+ __instance.numberOptionOrigin,
+ __instance.stringOptionOrigin,
+ __instance.settingsContainer));
foreach (var newOpt in options)
{
@@ -142,8 +159,10 @@ public static bool SettingsPatch(GameOptionsMenu __instance)
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();
+ toggle.CheckMark.color =
+ group.GroupColor != Color.clear ? group.GroupColor : MiraAssets.AcceptedTeal;
+ var rend = toggle.CheckMark.transform.parent.FindChild("ActiveSprite")
+ .GetComponent();
rend.sprite = MiraAssets.CheckmarkBox.LoadAsset();
rend.color = group.GroupColor != Color.clear ? group.GroupColor : MiraAssets.AcceptedTeal;
}
@@ -162,11 +181,14 @@ public static bool SettingsPatch(GameOptionsMenu __instance)
headerBtn.ClickSound = __instance.BackButton.GetComponent().ClickSound;
headerBtn.OnMouseOver = new UnityEvent();
headerBtn.OnMouseOut = new UnityEvent();
- headerBtn.OnClick.AddListener((UnityAction)(() =>
- {
- group.AllOptionsHidden = !group.AllOptionsHidden;
- newText.text = group.AllOptionsHidden ? "(Click to open)" : "(Click to close)";
- }));
+ headerBtn.OnClick.AddListener(
+ (UnityAction)(() =>
+ {
+ group.AllOptionsHidden = !group.AllOptionsHidden;
+ newText.text = group.AllOptionsHidden
+ ? "(Click to open)"
+ : "(Click to close)";
+ }));
headerBtn.SetButtonEnableState(true);
}
@@ -207,4 +229,4 @@ public static bool InitPatch(GameOptionsMenu __instance)
return false;
}
-}
\ No newline at end of file
+}
diff --git a/MiraAPI/Patches/Options/LobbyViewPanePatches.cs b/MiraAPI/Patches/Options/LobbyViewPanePatches.cs
index a74588e..01c844b 100644
--- a/MiraAPI/Patches/Options/LobbyViewPanePatches.cs
+++ b/MiraAPI/Patches/Options/LobbyViewPanePatches.cs
@@ -16,10 +16,11 @@ namespace MiraAPI.Patches.Options;
[HarmonyPatch(typeof(LobbyViewSettingsPane))]
public static class LobbyViewPanePatches
{
- public static int CurrentSelectedMod { get; private set; }
-
- public static MiraPluginInfo? SelectedMod => CurrentSelectedMod == 0 ? null : MiraPluginManager.Instance.RegisteredPlugins()[CurrentSelectedMod-1];
+ private static int CurrentSelectedMod { get; set; }
+ private static MiraPluginInfo? SelectedMod => CurrentSelectedMod == 0
+ ? null
+ : MiraPluginManager.Instance.RegisteredPlugins()[CurrentSelectedMod - 1];
[HarmonyPostfix]
[HarmonyPatch(nameof(LobbyViewSettingsPane.Awake))]
@@ -33,92 +34,96 @@ public static void AwakePatch(LobbyViewSettingsPane __instance)
nextButton.transform.localPosition = new Vector3(-5.4f, 2.4f, -2f);
nextButton.transform.localScale = new Vector3(3, 3, 2);
nextButton.name = "RightArrowButton";
-
+
var normal = nextButton.transform.FindChild("Normal").GetComponentInChildren();
normal.transform.localPosition = new Vector3(0, 0f, 0.3f);
normal.sprite = MiraAssets.NextButton.LoadAsset();
-
+
var hover = nextButton.transform.FindChild("Hover").GetComponentInChildren();
hover.transform.localPosition = new Vector3(0, 0f, 0.3f);
hover.sprite = MiraAssets.NextButtonActive.LoadAsset();
-
+
var passiveButton = nextButton.gameObject.GetComponent();
passiveButton.OnClick = new Button.ButtonClickedEvent();
- passiveButton.OnClick.AddListener((UnityAction)(() =>
- {
- CurrentSelectedMod += 1;
- if (CurrentSelectedMod > MiraPluginManager.Instance.RegisteredPlugins().Length)
+ passiveButton.OnClick.AddListener(
+ (UnityAction)(() =>
{
- CurrentSelectedMod = 0;
- }
- __instance.RefreshTab();
- __instance.scrollBar.ScrollToTop();
- }));
+ CurrentSelectedMod += 1;
+ if (CurrentSelectedMod > MiraPluginManager.Instance.RegisteredPlugins().Length)
+ {
+ CurrentSelectedMod = 0;
+ }
+
+ __instance.RefreshTab();
+ __instance.scrollBar.ScrollToTop();
+ }));
// Create the back button
var backButton = Object.Instantiate(nextButton, __instance.BackButton.transform.parent).gameObject;
backButton.transform.localPosition = new Vector3(-6.3f, 2.4f, -2f);
backButton.name = "LeftArrowButton";
backButton.transform.FindChild("Normal").gameObject.GetComponentInChildren().flipX
- = backButton.transform.FindChild("Hover").gameObject.GetComponentInChildren().flipX
+ = backButton.transform.FindChild("Hover").gameObject.GetComponentInChildren().flipX
= true;
-
+
var passiveButton2 = backButton.gameObject.GetComponent();
passiveButton2.OnClick = new Button.ButtonClickedEvent();
- passiveButton2.OnClick.AddListener((UnityAction)(() =>
- {
- CurrentSelectedMod -= 1;
- if (CurrentSelectedMod < 0)
+ passiveButton2.OnClick.AddListener(
+ (UnityAction)(() =>
{
- CurrentSelectedMod = MiraPluginManager.Instance.RegisteredPlugins().Length;
- }
- __instance.RefreshTab();
- __instance.scrollBar.ScrollToTop();
- }));
+ CurrentSelectedMod -= 1;
+ if (CurrentSelectedMod < 0)
+ {
+ CurrentSelectedMod = MiraPluginManager.Instance.RegisteredPlugins().Length;
+ }
+
+ __instance.RefreshTab();
+ __instance.scrollBar.ScrollToTop();
+ }));
}
-
+
[HarmonyPostfix]
[HarmonyPatch(nameof(LobbyViewSettingsPane.Update))]
public static void UpdatePatch(LobbyViewSettingsPane __instance)
{
__instance.gameModeText.text = SelectedMod?.PluginInfo.Metadata.Name ?? "Default";
}
-
+
[HarmonyPrefix]
[HarmonyPatch(nameof(LobbyViewSettingsPane.DrawNormalTab))]
public static bool DrawNormalTabPatch(LobbyViewSettingsPane __instance)
{
- if (CurrentSelectedMod == 0)
- {
- return true;
- }
-
- DrawOptionsTab(__instance);
- return false;
+ if (CurrentSelectedMod == 0)
+ {
+ return true;
+ }
+
+ DrawOptionsTab(__instance);
+ return false;
}
-
+
[HarmonyPrefix]
[HarmonyPatch(nameof(LobbyViewSettingsPane.DrawRolesTab))]
public static bool DrawRolesTabPatch(LobbyViewSettingsPane __instance)
{
- if (CurrentSelectedMod == 0)
- {
- return true;
- }
-
- DrawRolesTab(__instance);
- return false;
+ if (CurrentSelectedMod == 0)
+ {
+ return true;
+ }
+
+ DrawRolesTab(__instance);
+ return false;
}
-
+
private static void DrawOptionsTab(LobbyViewSettingsPane instance)
{
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)
@@ -127,8 +132,11 @@ private static void DrawOptionsTab(LobbyViewSettingsPane instance)
{
continue;
}
-
- var categoryHeaderMasked = Object.Instantiate(instance.categoryHeaderOrigin, instance.settingsContainer, true);
+
+ var categoryHeaderMasked = Object.Instantiate(
+ instance.categoryHeaderOrigin,
+ instance.settingsContainer,
+ true);
categoryHeaderMasked.SetHeader(StringNames.Name, 61);
categoryHeaderMasked.Title.text = group.GroupName;
categoryHeaderMasked.transform.localScale = Vector3.one;
@@ -144,8 +152,11 @@ private static void DrawOptionsTab(LobbyViewSettingsPane instance)
{
continue;
}
-
- var viewSettingsInfoPanel = Object.Instantiate(instance.infoPanelOrigin, instance.settingsContainer, true);
+
+ var viewSettingsInfoPanel = Object.Instantiate(
+ instance.infoPanelOrigin,
+ instance.settingsContainer,
+ true);
viewSettingsInfoPanel.transform.localScale = Vector3.one;
float num2;
if (i % 2 == 0)
@@ -160,25 +171,35 @@ private static void DrawOptionsTab(LobbyViewSettingsPane instance)
{
num2 = -3f;
}
+
viewSettingsInfoPanel.transform.localPosition = new Vector3(num2, num, -2f);
var data = option.Data;
-
+
+ if (data == null)
+ {
+ continue;
+ }
+
if (data.Type == OptionTypes.Checkbox)
{
- viewSettingsInfoPanel.SetInfoCheckbox(data.Title, 61, Mathf.Approximately(option.GetFloatData(), 1));
+ viewSettingsInfoPanel.SetInfoCheckbox(
+ data.Title,
+ 61,
+ Mathf.Approximately(option.GetFloatData(), 1));
}
else
{
viewSettingsInfoPanel.SetInfo(data.Title, data.GetValueString(option.GetFloatData()), 61);
}
-
+
instance.settingsInfo.Add(viewSettingsInfoPanel.gameObject);
i++;
}
-
+
num -= 0.59f;
}
+
instance.scrollBar.CalculateAndSetYBounds(instance.settingsInfo.Count + 10, 2f, 6f, 0.59f);
}
@@ -188,7 +209,7 @@ private static void DrawRolesTab(LobbyViewSettingsPane instance)
{
return;
}
-
+
var num = 0.95f;
var num2 = -6.53f;
var categoryHeaderMasked =
@@ -197,7 +218,7 @@ private static void DrawRolesTab(LobbyViewSettingsPane instance)
categoryHeaderMasked.transform.localScale = Vector3.one;
categoryHeaderMasked.transform.localPosition = new Vector3(-9.77f, 1.26f, -2f);
instance.settingsInfo.Add(categoryHeaderMasked.gameObject);
-
+
var list = new List();
foreach (var team in Enum.GetValues())
@@ -205,12 +226,12 @@ private static void DrawRolesTab(LobbyViewSettingsPane instance)
var filteredRoles = SelectedMod.CustomRoles.Values
.OfType()
.Where(x => !x.HideSettings && x.Team == team).ToList();
-
+
if (filteredRoles.Count == 0)
{
continue;
}
-
+
var categoryHeaderRoleVariant =
Object.Instantiate(instance.categoryHeaderRoleOrigin, instance.settingsContainer, true);
@@ -229,7 +250,7 @@ private static void DrawRolesTab(LobbyViewSettingsPane instance)
categoryHeaderRoleVariant.Title.color = Color.white;
break;
}
-
+
categoryHeaderRoleVariant.transform.localScale = Vector3.one;
categoryHeaderRoleVariant.transform.localPosition = new Vector3(0.09f, num, -2f);
instance.settingsInfo.Add(categoryHeaderRoleVariant.gameObject);
@@ -242,42 +263,48 @@ private static void DrawRolesTab(LobbyViewSettingsPane instance)
{
continue;
}
-
+
var chancePerGame =
GameOptionsManager.Instance.CurrentGameOptions.RoleOptions.GetChancePerGame(roleBehaviour.Role);
var numPerGame =
GameOptionsManager.Instance.CurrentGameOptions.RoleOptions.GetNumPerGame(roleBehaviour.Role);
-
+
var flag = numPerGame == 0;
-
+
var viewSettingsInfoPanelRoleVariant =
Object.Instantiate(
- instance.infoPanelRoleOrigin, instance.settingsContainer, true);
+ instance.infoPanelRoleOrigin,
+ instance.settingsContainer,
+ true);
viewSettingsInfoPanelRoleVariant.transform.localScale = Vector3.one;
viewSettingsInfoPanelRoleVariant.transform.localPosition = new Vector3(num2, num, -2f);
-
+
var advancedRoleOptions = SelectedMod.Options
.Where(x => x.AdvancedRole == customRole.GetType())
.ToList();
-
+
if (!flag && advancedRoleOptions.Count > 0)
{
list.Add(customRole.GetType());
}
- viewSettingsInfoPanelRoleVariant.SetInfo(roleBehaviour.NiceName, numPerGame, chancePerGame,
- 61, customRole.RoleColor, customRole.Icon.LoadAsset(), true);
-
- viewSettingsInfoPanelRoleVariant.titleText.color =
- viewSettingsInfoPanelRoleVariant.chanceTitle.color =
- viewSettingsInfoPanelRoleVariant.chanceBackground.color =
- viewSettingsInfoPanelRoleVariant.background.color =
+ viewSettingsInfoPanelRoleVariant.SetInfo(
+ roleBehaviour.NiceName,
+ numPerGame,
+ chancePerGame,
+ 61,
+ customRole.RoleColor,
+ customRole.Icon.LoadAsset(),
+ true);
+
+ viewSettingsInfoPanelRoleVariant.titleText.color =
+ viewSettingsInfoPanelRoleVariant.chanceTitle.color =
+ viewSettingsInfoPanelRoleVariant.chanceBackground.color =
+ viewSettingsInfoPanelRoleVariant.background.color =
customRole.RoleColor.GetAlternateColor();
instance.settingsInfo.Add(viewSettingsInfoPanelRoleVariant.gameObject);
num -= 0.664f;
}
-
-
}
if (list.Count > 0)
@@ -312,7 +339,7 @@ private static void DrawRolesTab(LobbyViewSettingsPane instance)
advancedRoleViewPanel.transform.localScale = Vector3.one;
advancedRoleViewPanel.transform.localPosition = new Vector3(num4, num, -2f);
var num5 = SetUpAdvancedRoleViewPanel(advancedRoleViewPanel, list[k], 0.59f, 61);
-
+
if (num5 > num3)
{
num3 = num5;
@@ -325,59 +352,74 @@ private static void DrawRolesTab(LobbyViewSettingsPane instance)
instance.scrollBar.SetYBoundsMax(-num);
}
- private static float SetUpAdvancedRoleViewPanel(AdvancedRoleViewPanel viewPanel, Type roleType, float spacingY, int maskLayer)
+ private static float SetUpAdvancedRoleViewPanel(
+ AdvancedRoleViewPanel viewPanel,
+ Type roleType,
+ float spacingY,
+ int maskLayer)
{
- if (SelectedMod == null)
- {
- return 0;
- }
-
- var role = SelectedMod.CustomRoles.Values.FirstOrDefault(x => x.GetType() == roleType);
-
- if (role == null)
- {
- return 0;
- }
-
- if (role is not ICustomRole customRole)
- {
- return 0;
- }
-
- viewPanel.header.SetHeader(role.StringName, maskLayer, role.TeamType == RoleTeamTypes.Crewmate, customRole.Icon.LoadAsset());
- viewPanel.divider.material.SetInt(PlayerMaterial.MaskLayer, maskLayer);
-
- var num = viewPanel.yPosStart;
- var num2 = 1.08f;
-
- var filteredOptions = SelectedMod.Options
- .Where(x => x.AdvancedRole == roleType)
- .ToList();
-
- for (var i = 0; i < filteredOptions.Count; i++)
- {
- var option = filteredOptions[i];
- var baseGameSetting = option.Data;
- var viewSettingsInfoPanel = Object.Instantiate(viewPanel.infoPanelOrigin, viewPanel.transform, true);
- viewSettingsInfoPanel.transform.localScale = Vector3.one;
- viewSettingsInfoPanel.transform.localPosition = new Vector3(viewPanel.xPosStart, num, -2f);
-
- var value = option.GetFloatData();
-
- if (baseGameSetting.Type == OptionTypes.Checkbox)
- {
- viewSettingsInfoPanel.SetInfoCheckbox(baseGameSetting.Title, maskLayer, value > 0f);
- }
- else
- {
- viewSettingsInfoPanel.SetInfo(baseGameSetting.Title, baseGameSetting.GetValueString(value), maskLayer);
- }
- num -= spacingY;
- if (i > 0)
- {
- num2 += 0.8f;
- }
- }
- return num2;
+ if (SelectedMod == null)
+ {
+ return 0;
+ }
+
+ var role = SelectedMod.CustomRoles.Values.FirstOrDefault(x => x.GetType() == roleType);
+
+ if (role == null)
+ {
+ return 0;
+ }
+
+ if (role is not ICustomRole customRole)
+ {
+ return 0;
+ }
+
+ viewPanel.header.SetHeader(
+ role.StringName,
+ maskLayer,
+ role.TeamType == RoleTeamTypes.Crewmate,
+ customRole.Icon.LoadAsset());
+ viewPanel.divider.material.SetInt(PlayerMaterial.MaskLayer, maskLayer);
+
+ var num = viewPanel.yPosStart;
+ var num2 = 1.08f;
+
+ var filteredOptions = SelectedMod.Options
+ .Where(x => x.AdvancedRole == roleType)
+ .ToList();
+
+ for (var i = 0; i < filteredOptions.Count; i++)
+ {
+ var option = filteredOptions[i];
+ var baseGameSetting = option.Data;
+ var viewSettingsInfoPanel = Object.Instantiate(viewPanel.infoPanelOrigin, viewPanel.transform, true);
+ viewSettingsInfoPanel.transform.localScale = Vector3.one;
+ viewSettingsInfoPanel.transform.localPosition = new Vector3(viewPanel.xPosStart, num, -2f);
+
+ var value = option.GetFloatData();
+
+ if (baseGameSetting == null)
+ {
+ continue;
+ }
+
+ if (baseGameSetting.Type == OptionTypes.Checkbox)
+ {
+ viewSettingsInfoPanel.SetInfoCheckbox(baseGameSetting.Title, maskLayer, value > 0f);
+ }
+ else
+ {
+ viewSettingsInfoPanel.SetInfo(baseGameSetting.Title, baseGameSetting.GetValueString(value), maskLayer);
+ }
+
+ num -= spacingY;
+ if (i > 0)
+ {
+ num2 += 0.8f;
+ }
+ }
+
+ return num2;
}
-}
\ No newline at end of file
+}
diff --git a/MiraAPI/Patches/Options/NotificationPopperPatch.cs b/MiraAPI/Patches/Options/NotificationPopperPatch.cs
index faa24eb..d13b854 100644
--- a/MiraAPI/Patches/Options/NotificationPopperPatch.cs
+++ b/MiraAPI/Patches/Options/NotificationPopperPatch.cs
@@ -18,26 +18,26 @@ public static bool RoleChangeMsgPatch(
[HarmonyArgument(3)] RoleTeamTypes teamType,
[HarmonyArgument(4)] bool playSound)
{
- if (CustomRoleManager.CustomRoles.Values.Any(role => role.StringName == key))
+ if (CustomRoleManager.CustomRoles.Values.All(role => role.StringName != key))
{
- var text = teamType == RoleTeamTypes.Crewmate
- ? Palette.CrewmateSettingChangeText.ToTextColor()
- : Palette.ImpostorRed.ToTextColor();
+ return true;
+ }
- var item = DestroyableSingleton.Instance.GetString(
- StringNames.LobbyChangeSettingNotificationRole,
- "",
- text,
- DestroyableSingleton.Instance.GetString(key, Array.Empty",
- "" + roleCount + "",
- "" + roleChance + "%"
- );
+ var text = teamType == RoleTeamTypes.Crewmate
+ ? Palette.CrewmateSettingChangeText.ToTextColor()
+ : Palette.ImpostorRed.ToTextColor();
- __instance.SettingsChangeMessageLogic(key, item, playSound);
- return false;
- }
+ var item = DestroyableSingleton.Instance.GetString(
+ StringNames.LobbyChangeSettingNotificationRole,
+ "",
+ text,
+ DestroyableSingleton.Instance.GetString(key, Array.Empty",
+ "" + roleCount + "",
+ "" + roleChance + "%"
+ );
- return true;
+ __instance.SettingsChangeMessageLogic(key, item, playSound);
+ return false;
}
}
diff --git a/MiraAPI/Patches/Options/OptionsPatches.cs b/MiraAPI/Patches/Options/OptionsPatches.cs
index de7da75..a3be128 100644
--- a/MiraAPI/Patches/Options/OptionsPatches.cs
+++ b/MiraAPI/Patches/Options/OptionsPatches.cs
@@ -16,7 +16,8 @@ public static bool ToggleInit(ToggleOption __instance)
return true;
}
- __instance.TitleText.text = DestroyableSingleton.Instance.GetString(__instance.Title, Array.Empty
[HarmonyPatch]
-public class SettingPatches
+public static class SettingPatches
{
///
/// Prefix for the method. Adds support for custom number suffixes.
@@ -25,33 +25,24 @@ public static bool ValueStringPatch(
ref string __result,
[HarmonyArgument(0)] float value)
{
- var result = string.Empty;
+ string result;
var suffix = (MiraNumberSuffixes)__instance.SuffixType;
if (__instance.ZeroIsInfinity && Mathf.Abs(value) < 0.0001f)
{
result = "∞";
}
- else if (suffix == MiraNumberSuffixes.None)
- {
- result = value.ToString(__instance.FormatString);
- }
- else if (suffix == MiraNumberSuffixes.Multiplier)
- {
- result = value.ToString(__instance.FormatString) + "x";
- }
- else if (suffix == MiraNumberSuffixes.Percent)
- {
- result = value.ToString(__instance.FormatString) + "%";
- }
else
{
- result = DestroyableSingleton.Instance.GetString(
- StringNames.GameSecondsAbbrev,
- (Il2CppSystem.Object[])
- [
- value.ToString(__instance.FormatString, CultureInfo.InvariantCulture)
- ]);
+ result = suffix switch
+ {
+ MiraNumberSuffixes.None => value.ToString(__instance.FormatString, NumberFormatInfo.InvariantInfo),
+ MiraNumberSuffixes.Multiplier => value.ToString(__instance.FormatString, NumberFormatInfo.InvariantInfo) + "x",
+ MiraNumberSuffixes.Percent => value.ToString(__instance.FormatString, NumberFormatInfo.InvariantInfo) + "%",
+ _ => DestroyableSingleton.Instance.GetString(
+ StringNames.GameSecondsAbbrev,
+ (Il2CppSystem.Object[]) [value.ToString(__instance.FormatString, CultureInfo.InvariantCulture)]),
+ };
}
__result = result;
diff --git a/MiraAPI/Patches/Roles/NameTagPatch.cs b/MiraAPI/Patches/Roles/NameTagPatch.cs
index b427112..821db1c 100644
--- a/MiraAPI/Patches/Roles/NameTagPatch.cs
+++ b/MiraAPI/Patches/Roles/NameTagPatch.cs
@@ -32,4 +32,4 @@ public static bool GetPatch([HarmonyArgument(0)] RoleBehaviour otherPlayerRole,
return false;
}
-}
\ No newline at end of file
+}
diff --git a/MiraAPI/Patches/Roles/RoleBehaviourPatches.cs b/MiraAPI/Patches/Roles/RoleBehaviourPatches.cs
index 5879df8..98cb5e6 100644
--- a/MiraAPI/Patches/Roles/RoleBehaviourPatches.cs
+++ b/MiraAPI/Patches/Roles/RoleBehaviourPatches.cs
@@ -22,4 +22,4 @@ public static bool PrefixTeamColorGetter(RoleBehaviour __instance, ref Color __r
__result = behaviour.RoleColor;
return false;
}
-}
\ No newline at end of file
+}
diff --git a/MiraAPI/Patches/Roles/RoleManagerPatches.cs b/MiraAPI/Patches/Roles/RoleManagerPatches.cs
index 350767f..4f75a16 100644
--- a/MiraAPI/Patches/Roles/RoleManagerPatches.cs
+++ b/MiraAPI/Patches/Roles/RoleManagerPatches.cs
@@ -18,7 +18,9 @@ public static void ModifierSelectionPatches(RoleManager __instance)
return;
}
- ModifierManager.AssignModifiers(PlayerControl.AllPlayerControls.ToArray().Where(plr => !plr.Data.IsDead && !plr.Data.Disconnected).ToList());
+ ModifierManager.AssignModifiers(
+ PlayerControl.AllPlayerControls.ToArray().Where(plr => !plr.Data.IsDead && !plr.Data.Disconnected)
+ .ToList());
}
[HarmonyPrefix]
@@ -39,9 +41,8 @@ public static bool AssignRoleOnDeath(RoleManager __instance, [HarmonyArgument(0)
{
return true;
}
-
+
plr.RpcSetRole(role.GhostRole);
return false;
-
}
-}
\ No newline at end of file
+}
diff --git a/MiraAPI/Patches/Roles/RoleOptionsCollectionPatch.cs b/MiraAPI/Patches/Roles/RoleOptionsCollectionPatch.cs
index c146b8a..ed4f7b7 100644
--- a/MiraAPI/Patches/Roles/RoleOptionsCollectionPatch.cs
+++ b/MiraAPI/Patches/Roles/RoleOptionsCollectionPatch.cs
@@ -14,13 +14,14 @@ public static class RoleOptionsCollectionPatch
[HarmonyPatch(nameof(RoleOptionsCollectionV08.GetChancePerGame))]
public static bool GetChancePrefix([HarmonyArgument(0)] RoleTypes roleType, ref int __result)
{
- if (!CustomRoleManager.GetCustomRoleBehaviour(roleType, out var customRole))
+ if (!CustomRoleManager.GetCustomRoleBehaviour(roleType, out var customRole) || customRole == null)
{
return true;
}
if (customRole.HideSettings)
{
+ __result = 0;
return false;
}
@@ -36,18 +37,19 @@ public static bool GetChancePrefix([HarmonyArgument(0)] RoleTypes roleType, ref
[HarmonyPatch(nameof(RoleOptionsCollectionV08.GetNumPerGame))]
public static bool GetNumPrefix([HarmonyArgument(0)] RoleTypes roleType, ref int __result)
{
- if (!CustomRoleManager.GetCustomRoleBehaviour(roleType, out var customRole))
+ if (!CustomRoleManager.GetCustomRoleBehaviour(roleType, out var customRole) || customRole == null)
{
return true;
}
+
if (customRole.HideSettings)
{
+ __result = 0;
return false;
}
customRole.ParentMod.PluginConfig.TryGetEntry(customRole.NumConfigDefinition, out var entry);
__result = entry.Value;
return false;
-
}
}
diff --git a/MiraAPI/Patches/Roles/TaskAdderPatch.cs b/MiraAPI/Patches/Roles/TaskAdderPatch.cs
index 9db0f92..8a3ae90 100644
--- a/MiraAPI/Patches/Roles/TaskAdderPatch.cs
+++ b/MiraAPI/Patches/Roles/TaskAdderPatch.cs
@@ -15,9 +15,8 @@ namespace MiraAPI.Patches.Roles;
[HarmonyPatch]
public static class TaskAdderPatch
{
- private static TaskFolder _rolesFolder;
- private static readonly System.Collections.Generic.Dictionary ModsFolders = new();
- private static Scroller _scroller;
+ private static readonly System.Collections.Generic.Dictionary ModsFolders = [];
+ private static Scroller? _scroller;
[HarmonyPostfix]
[HarmonyPatch(typeof(TaskAdderGame), nameof(TaskAdderGame.Begin))]
@@ -56,18 +55,17 @@ public static void AddRolesFolder(TaskAdderGame __instance)
__instance.TaskParent = inner.transform;
- _rolesFolder = Object.Instantiate(__instance.RootFolderPrefab, _scroller.Inner);
- _rolesFolder = Object.Instantiate(__instance.RootFolderPrefab, _scroller.Inner);
- _rolesFolder.gameObject.SetActive(false);
- _rolesFolder.FolderName = "Roles";
- _rolesFolder.name = "RolesFolder";
+ var rolesFolder = Object.Instantiate(__instance.RootFolderPrefab, _scroller.Inner);
+ rolesFolder.gameObject.SetActive(false);
+ rolesFolder.FolderName = "Roles";
+ rolesFolder.name = "RolesFolder";
foreach (var plugin in MiraPluginManager.Instance.RegisteredPlugins())
{
var newFolder = Object.Instantiate(__instance.RootFolderPrefab, _scroller.Inner);
newFolder.FolderName = newFolder.name = plugin.PluginInfo.Metadata.Name;
newFolder.gameObject.SetActive(false);
- _rolesFolder.SubFolders.Add(newFolder);
+ rolesFolder.SubFolders.Add(newFolder);
if (!ModsFolders.ContainsKey(plugin.PluginInfo.Metadata.Name))
{
@@ -75,7 +73,7 @@ public static void AddRolesFolder(TaskAdderGame __instance)
}
}
- __instance.Root.SubFolders.Add(_rolesFolder);
+ __instance.Root.SubFolders.Add(rolesFolder);
__instance.GoToRoot();
}
@@ -92,7 +90,12 @@ public static void RoleGetterPatch(TaskAddButton __instance)
__instance.RolloverHandler.OutColor = __instance.FileImage.color;
}
- private static void AddFileAsChildCustom(this TaskAdderGame instance, TaskFolder taskFolder, TaskAddButton item, ref float xCursor, ref float yCursor, ref float maxHeight)
+ private static void AddFileAsChildCustom(
+ this TaskAdderGame instance,
+ TaskAddButton item,
+ ref float xCursor,
+ ref float yCursor,
+ ref float maxHeight)
{
item.transform.SetParent(instance.TaskParent);
item.transform.localPosition = new Vector3(xCursor, yCursor, 0f);
@@ -105,9 +108,9 @@ private static void AddFileAsChildCustom(this TaskAdderGame instance, TaskFolder
yCursor -= maxHeight;
maxHeight = 0f;
}
+
instance.ActiveItems.Add(item.transform);
}
-
// yes it might be crazy patching the entire method, but i tried so many other methods and only this works :cry:
[HarmonyPrefix]
@@ -121,11 +124,13 @@ public static bool ShowPatch(TaskAdderGame __instance, [HarmonyArgument(0)] Task
stringBuilder.Append(__instance.Hierarchy.ToArray()[i].FolderName);
stringBuilder.Append("\\");
}
+
__instance.PathText.text = stringBuilder.ToString();
for (var j = 0; j < __instance.ActiveItems.Count; j++)
{
Object.Destroy(__instance.ActiveItems.ToArray()[j].gameObject);
}
+
__instance.ActiveItems.Clear();
var num = 0f;
var num2 = 0f;
@@ -148,6 +153,7 @@ public static bool ShowPatch(TaskAdderGame __instance, [HarmonyArgument(0)] Task
num2 -= num3;
num3 = 0f;
}
+
__instance.ActiveItems.Add(folderTransform);
if (!taskFolder2 || !taskFolder2.Button)
{
@@ -155,7 +161,8 @@ public static bool ShowPatch(TaskAdderGame __instance, [HarmonyArgument(0)] Task
}
ControllerManager.Instance.AddSelectableUiElement(taskFolder2.Button);
- if (!string.IsNullOrEmpty(__instance.restorePreviousSelectionByFolderName) && taskFolder2.FolderName.Equals(__instance.restorePreviousSelectionByFolderName))
+ if (!string.IsNullOrEmpty(__instance.restorePreviousSelectionByFolderName) &&
+ taskFolder2.FolderName.Equals(__instance.restorePreviousSelectionByFolderName, System.StringComparison.Ordinal))
{
__instance.restorePreviousSelectionFound = taskFolder2.Button;
}
@@ -173,63 +180,90 @@ public static bool ShowPatch(TaskAdderGame __instance, [HarmonyArgument(0)] Task
{
var taskAddButton = Object.Instantiate(__instance.TaskPrefab);
taskAddButton.MyTask = list.ToArray()[l];
- if (taskAddButton.MyTask.TaskType == TaskTypes.DivertPower)
+ switch (taskAddButton.MyTask.TaskType)
{
- var targetSystem = taskAddButton.MyTask.Cast().TargetSystem;
- taskAddButton.Text.text = DestroyableSingleton.Instance.GetString(StringNames.DivertPowerTo, DestroyableSingleton.Instance.GetString(targetSystem));
+ case TaskTypes.DivertPower:
+ {
+ var targetSystem = taskAddButton.MyTask.Cast().TargetSystem;
+ taskAddButton.Text.text = DestroyableSingleton.Instance.GetString(
+ StringNames.DivertPowerTo,
+ DestroyableSingleton.Instance.GetString(targetSystem));
+ break;
+ }
+ case TaskTypes.FixWeatherNode:
+ {
+ var nodeId = ((WeatherNodeTask)taskAddButton.MyTask).NodeId;
+ taskAddButton.Text.text =
+ DestroyableSingleton.Instance.GetString(
+ StringNames.FixWeatherNode,
+ Array.Empty()) + " " +
+ DestroyableSingleton.Instance.GetString(
+ WeatherSwitchGame.ControlNames[nodeId],
+ Array.Empty());
+ break;
+ }
+ default:
+ taskAddButton.Text.text =
+ DestroyableSingleton.Instance.GetString(taskAddButton.MyTask.TaskType);
+ break;
}
- else if (taskAddButton.MyTask.TaskType == TaskTypes.FixWeatherNode)
+
+ __instance.AddFileAsChildCustom(taskAddButton, ref num, ref num2, ref num3);
+ if (taskAddButton.Button == null)
{
- var nodeId = ((WeatherNodeTask)taskAddButton.MyTask).NodeId;
- taskAddButton.Text.text = DestroyableSingleton.Instance.GetString(StringNames.FixWeatherNode, Array.Empty()) + " " + DestroyableSingleton.Instance.GetString(WeatherSwitchGame.ControlNames[nodeId],
- Array.Empty());
+ continue;
}
- else
+
+ ControllerManager.Instance.AddSelectableUiElement(taskAddButton.Button);
+ if (__instance.Hierarchy.Count == 1 || flag)
{
- taskAddButton.Text.text = DestroyableSingleton.Instance.GetString(taskAddButton.MyTask.TaskType);
+ continue;
}
- __instance.AddFileAsChildCustom(taskFolder, taskAddButton, ref num, ref num2, ref num3);
- if (taskAddButton != null && taskAddButton.Button != null)
+
+ var component =
+ ControllerManager.Instance.CurrentUiState.CurrentSelection.GetComponent();
+ if (component != null)
{
- ControllerManager.Instance.AddSelectableUiElement(taskAddButton.Button);
- if (__instance.Hierarchy.Count != 1 && !flag)
- {
- var component = ControllerManager.Instance.CurrentUiState.CurrentSelection.GetComponent();
- if (component != null)
- {
- __instance.restorePreviousSelectionByFolderName = component.FolderName;
- }
- ControllerManager.Instance.SetDefaultSelection(taskAddButton.Button);
- flag = true;
- }
+ __instance.restorePreviousSelectionByFolderName = component.FolderName;
}
+
+ ControllerManager.Instance.SetDefaultSelection(taskAddButton.Button);
+ flag = true;
}
+
if (taskFolder.FolderName == "Roles")
{
for (var m = 0; m < DestroyableSingleton.Instance.AllRoles.Length; m++)
{
var roleBehaviour = DestroyableSingleton.Instance.AllRoles[m];
- if (roleBehaviour.Role != RoleTypes.ImpostorGhost && roleBehaviour.Role != RoleTypes.CrewmateGhost && !CustomRoleManager.CustomRoles.ContainsKey((ushort)roleBehaviour.Role))
+ if (roleBehaviour.Role == RoleTypes.ImpostorGhost || roleBehaviour.Role == RoleTypes.CrewmateGhost ||
+ CustomRoleManager.CustomRoles.ContainsKey((ushort)roleBehaviour.Role))
+ {
+ continue;
+ }
+
+ var taskAddButton2 = Object.Instantiate(__instance.RoleButton);
+ taskAddButton2.SafePositionWorld = __instance.SafePositionWorld;
+ taskAddButton2.Text.text = "Be_" + roleBehaviour.NiceName + ".exe";
+ __instance.AddFileAsChildCustom(taskAddButton2, ref num, ref num2, ref num3);
+ taskAddButton2.Role = roleBehaviour;
+
+ if (taskAddButton2.Button == null)
+ {
+ continue;
+ }
+
+ ControllerManager.Instance.AddSelectableUiElement(taskAddButton2.Button);
+ switch (m)
{
- var taskAddButton2 = Object.Instantiate(__instance.RoleButton);
- taskAddButton2.SafePositionWorld = __instance.SafePositionWorld;
- taskAddButton2.Text.text = "Be_" + roleBehaviour.NiceName + ".exe";
- __instance.AddFileAsChildCustom(_rolesFolder, taskAddButton2, ref num, ref num2, ref num3);
- taskAddButton2.Role = roleBehaviour;
- if (taskAddButton2 != null && taskAddButton2.Button != null)
- {
- ControllerManager.Instance.AddSelectableUiElement(taskAddButton2.Button);
- if (m == 0 && __instance.restorePreviousSelectionFound != null)
- {
- ControllerManager.Instance.SetDefaultSelection(__instance.restorePreviousSelectionFound);
- __instance.restorePreviousSelectionByFolderName = string.Empty;
- __instance.restorePreviousSelectionFound = null;
- }
- else if (m == 0)
- {
- ControllerManager.Instance.SetDefaultSelection(taskAddButton2.Button);
- }
- }
+ case 0 when __instance.restorePreviousSelectionFound != null:
+ ControllerManager.Instance.SetDefaultSelection(__instance.restorePreviousSelectionFound);
+ __instance.restorePreviousSelectionByFolderName = string.Empty;
+ __instance.restorePreviousSelectionFound = null;
+ break;
+ case 0:
+ ControllerManager.Instance.SetDefaultSelection(taskAddButton2.Button);
+ break;
}
}
}
@@ -240,27 +274,33 @@ public static bool ShowPatch(TaskAdderGame __instance, [HarmonyArgument(0)] Task
for (var m = 0; m < plugin.CustomRoles.Count; m++)
{
var roleBehaviour = plugin.CustomRoles.ElementAt(m).Value;
- if (roleBehaviour.Role != RoleTypes.ImpostorGhost && roleBehaviour.Role != RoleTypes.CrewmateGhost && !roleBehaviour.IsDead)
+ if (roleBehaviour.Role == RoleTypes.ImpostorGhost || roleBehaviour.Role == RoleTypes.CrewmateGhost ||
+ roleBehaviour.IsDead)
{
- var taskAddButton2 = Object.Instantiate(__instance.RoleButton);
- taskAddButton2.SafePositionWorld = __instance.SafePositionWorld;
- taskAddButton2.Text.text = "Be_" + roleBehaviour.NiceName + ".exe";
- __instance.AddFileAsChildCustom(_rolesFolder, taskAddButton2, ref num, ref num2, ref num3);
- taskAddButton2.Role = roleBehaviour;
- if (taskAddButton2 != null && taskAddButton2.Button != null)
- {
- ControllerManager.Instance.AddSelectableUiElement(taskAddButton2.Button);
- if (m == 0 && __instance.restorePreviousSelectionFound != null)
- {
- ControllerManager.Instance.SetDefaultSelection(__instance.restorePreviousSelectionFound);
- __instance.restorePreviousSelectionByFolderName = string.Empty;
- __instance.restorePreviousSelectionFound = null;
- }
- else if (m == 0)
- {
- ControllerManager.Instance.SetDefaultSelection(taskAddButton2.Button);
- }
- }
+ continue;
+ }
+
+ var taskAddButton2 = Object.Instantiate(__instance.RoleButton);
+ taskAddButton2.SafePositionWorld = __instance.SafePositionWorld;
+ taskAddButton2.Text.text = "Be_" + roleBehaviour.NiceName + ".exe";
+ __instance.AddFileAsChildCustom(taskAddButton2, ref num, ref num2, ref num3);
+ taskAddButton2.Role = roleBehaviour;
+ if (taskAddButton2.Button == null)
+ {
+ continue;
+ }
+
+ ControllerManager.Instance.AddSelectableUiElement(taskAddButton2.Button);
+ switch (m)
+ {
+ case 0 when __instance.restorePreviousSelectionFound != null:
+ ControllerManager.Instance.SetDefaultSelection(__instance.restorePreviousSelectionFound);
+ __instance.restorePreviousSelectionByFolderName = string.Empty;
+ __instance.restorePreviousSelectionFound = null;
+ break;
+ case 0:
+ ControllerManager.Instance.SetDefaultSelection(taskAddButton2.Button);
+ break;
}
}
}
@@ -271,17 +311,19 @@ public static bool ShowPatch(TaskAdderGame __instance, [HarmonyArgument(0)] Task
chip.GetComponent().maskInteraction = SpriteMaskInteraction.VisibleInsideMask;
}
- if (_scroller)
+ if (_scroller && _scroller != null)
{
_scroller.CalculateAndSetYBounds(__instance.ActiveItems.Count, 6, 3, 1f);
_scroller.SetYBoundsMin(0.0f);
_scroller.ScrollToTop();
}
+
if (__instance.Hierarchy.Count == 1)
{
ControllerManager.Instance.SetBackButton(__instance.BackButton);
return false;
}
+
ControllerManager.Instance.SetBackButton(__instance.FolderBackButton);
return false;
}
diff --git a/MiraAPI/Patches/Roles/TaskPanelPatch.cs b/MiraAPI/Patches/Roles/TaskPanelPatch.cs
index e93ab10..3d4ae14 100644
--- a/MiraAPI/Patches/Roles/TaskPanelPatch.cs
+++ b/MiraAPI/Patches/Roles/TaskPanelPatch.cs
@@ -24,7 +24,12 @@ public static bool UpdatePrefix(TaskPanelBehaviour __instance)
var vector = __instance.background.sprite.bounds.extents;
var vector2 = __instance.tab.sprite.bounds.extents;
- transform.localScale = __instance.taskText.textBounds.size.x > 0f ? new Vector3(__instance.taskText.textBounds.size.x + 0.4f, __instance.taskText.textBounds.size.y + 0.3f, 1f) : Vector3.zero;
+ transform.localScale = __instance.taskText.textBounds.size.x > 0f
+ ? new Vector3(
+ __instance.taskText.textBounds.size.x + 0.4f,
+ __instance.taskText.textBounds.size.y + 0.3f,
+ 1f)
+ : Vector3.zero;
vector.y = -vector.y;
vector = vector.Mul(transform.localScale);
@@ -39,20 +44,24 @@ public static bool UpdatePrefix(TaskPanelBehaviour __instance)
{
return false;
}
- var closePosition = new Vector3(-__instance.background.sprite.bounds.size.x * __instance.background.transform.localScale.x, __instance.closedPosition.y, __instance.closedPosition.z);
+
+ var closePosition = new Vector3(
+ -__instance.background.sprite.bounds.size.x * __instance.background.transform.localScale.x,
+ __instance.closedPosition.y,
+ __instance.closedPosition.z);
__instance.closedPosition = closePosition;
- if (__instance.open)
- {
- __instance.timer = Mathf.Min(1f, __instance.timer + Time.deltaTime / __instance.animationTimeSeconds);
- }
- else
- {
- __instance.timer = Mathf.Max(0f, __instance.timer - Time.deltaTime / __instance.animationTimeSeconds);
- }
- Vector3 relativePos;
- relativePos = new Vector3(Mathf.SmoothStep(__instance.closedPosition.x, __instance.openPosition.x, __instance.timer), Mathf.SmoothStep(__instance.closedPosition.y, __instance.openPosition.y, __instance.timer), __instance.openPosition.z);
- __instance.transform.localPosition = AspectPosition.ComputePosition(AspectPosition.EdgeAlignments.LeftTop, relativePos);
+
+ __instance.timer = __instance.open
+ ? Mathf.Min(1f, __instance.timer + Time.deltaTime / __instance.animationTimeSeconds)
+ : Mathf.Max(0f, __instance.timer - Time.deltaTime / __instance.animationTimeSeconds);
+
+ var relativePos = new Vector3(
+ Mathf.SmoothStep(__instance.closedPosition.x, __instance.openPosition.x, __instance.timer),
+ Mathf.SmoothStep(__instance.closedPosition.y, __instance.openPosition.y, __instance.timer),
+ __instance.openPosition.z);
+ __instance.transform.localPosition = AspectPosition.ComputePosition(
+ AspectPosition.EdgeAlignments.LeftTop,
+ relativePos);
return false;
}
-
-}
\ No newline at end of file
+}
diff --git a/MiraAPI/Patches/Roles/VentOutlinePatch.cs b/MiraAPI/Patches/Roles/VentOutlinePatch.cs
index 401d450..5e50e96 100644
--- a/MiraAPI/Patches/Roles/VentOutlinePatch.cs
+++ b/MiraAPI/Patches/Roles/VentOutlinePatch.cs
@@ -5,6 +5,9 @@
namespace MiraAPI.Patches.Roles;
+///
+/// Set vent outline color based on the player's role.
+///
[HarmonyPatch(typeof(Vent), nameof(Vent.SetOutline))]
public static class VentOutlinePatch
{
From 0e56a30c5c7057cf0ae0bb1b54602cc263d5d7de Mon Sep 17 00:00:00 2001
From: XtraCube <72575280+XtraCube@users.noreply.github.com>
Date: Mon, 2 Sep 2024 15:19:32 -0400
Subject: [PATCH 22/36] fix most non-documentation warnings
---
.editorconfig | 2 +
MiraAPI.Example/ExampleAssets.cs | 4 +-
MiraAPI.Example/ExampleColors.cs | 6 +--
MiraAPI.Example/MiraDebugWindow.cs | 18 +++-----
MiraAPI/GameModes/CustomGameModeManager.cs | 18 ++++----
MiraAPI/GameModes/DefaultMode.cs | 2 +-
.../GameModes/RegisterGameModeAttribute.cs | 2 +-
MiraAPI/GameOptions/OptionGroupSingleton.cs | 2 +
MiraAPI/Hud/CustomButtonSingleton.cs | 2 +
MiraAPI/Hud/RegisterButtonAttribute.cs | 2 +-
MiraAPI/MiraApiPlugin.cs | 6 +--
MiraAPI/Modifiers/ModifierComponent.cs | 2 +-
MiraAPI/Networking/SyncModifiersRpc.cs | 2 +-
MiraAPI/Networking/SyncOptionsRpc.cs | 2 +-
MiraAPI/Networking/SyncRoleOptionsRpc.cs | 2 +-
.../Patches/Colors/ScrollingColorsPatch.cs | 10 ++---
MiraAPI/Patches/GameModes/ConsolePatches.cs | 5 +--
MiraAPI/Patches/GameModes/DeadBodyPatch.cs | 6 +--
MiraAPI/Patches/GameModes/GameLogicPatches.cs | 6 +--
.../Patches/GameModes/ImpostorTargetPatch.cs | 8 ++--
.../Patches/GameModes/MapBehaviourPatch.cs | 6 +--
MiraAPI/Patches/GameModes/OnDeathPatch.cs | 6 +--
MiraAPI/Patches/GameModes/VentPatches.cs | 8 +---
MiraAPI/Patches/Modifiers/VentPatches.cs | 2 +-
.../Patches/Options/GameSettingMenuPatches.cs | 1 -
MiraAPI/Patches/Roles/TaskPanelPatch.cs | 4 +-
MiraAPI/PluginLoading/IMiraPlugin.cs | 2 +-
MiraAPI/PluginLoading/MiraPluginManager.cs | 2 +-
MiraAPI/Roles/ModdedRoleTeams.cs | 4 +-
MiraAPI/Roles/RegisterCustomRoleAttribute.cs | 2 +-
MiraAPI/Roles/RoleId.cs | 4 +-
MiraAPI/Utilities/Assets/MiraAssets.cs | 6 +--
MiraAPI/Utilities/Assets/SpriteTools.cs | 24 ++++------
MiraAPI/Utilities/MiraNumberSuffixes.cs | 4 +-
MiraAPI/Utilities/ShaderID.cs | 45 +++++++++----------
35 files changed, 102 insertions(+), 125 deletions(-)
create mode 100644 .editorconfig
diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000..017cd3a
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,2 @@
+[*.{cs,vb}]
+dotnet_diagnostic.CA1707.severity = none
\ No newline at end of file
diff --git a/MiraAPI.Example/ExampleAssets.cs b/MiraAPI.Example/ExampleAssets.cs
index a96dfc8..732d9f7 100644
--- a/MiraAPI.Example/ExampleAssets.cs
+++ b/MiraAPI.Example/ExampleAssets.cs
@@ -6,7 +6,7 @@ public static class ExampleAssets
{
public static LoadableResourceAsset ExampleButton { get; } = new("MiraAPI.Example.Resources.ExampleButton.png");
- // Credit to EpicHorrors for the teleport button asset.
+ // Credit to EpicHorrors for the teleport button asset.
public static LoadableResourceAsset TeleportButton { get; } = new("MiraAPI.Example.Resources.TeleportButton.png");
public static LoadableResourceAsset Banner { get; } = new("MiraAPI.Example.Resources.FortniteBanner.jpeg");
-}
\ No newline at end of file
+}
diff --git a/MiraAPI.Example/ExampleColors.cs b/MiraAPI.Example/ExampleColors.cs
index 3212093..6833d3c 100644
--- a/MiraAPI.Example/ExampleColors.cs
+++ b/MiraAPI.Example/ExampleColors.cs
@@ -6,9 +6,9 @@ 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));
public static CustomColor Rose { get; } = new("Rose", new Color(0.98f, 0.26f, 0.62f));
-
+
public static CustomColor Gold { get; } = new("Gold", new Color(1.0f, 0.84f, 0.0f));
-}
\ No newline at end of file
+}
diff --git a/MiraAPI.Example/MiraDebugWindow.cs b/MiraAPI.Example/MiraDebugWindow.cs
index 9b0fa7e..13a41d4 100644
--- a/MiraAPI.Example/MiraDebugWindow.cs
+++ b/MiraAPI.Example/MiraDebugWindow.cs
@@ -4,20 +4,16 @@
using UnityEngine;
namespace MiraAPI.Example;
+
[RegisterInIl2Cpp]
-public class MiraDebugWindow(IntPtr ptr) : MonoBehaviour(ptr)
+public class MiraDebugWindow(IntPtr cppPtr) : MonoBehaviour(cppPtr)
{
- public readonly DragWindow DebuggingWindow = new(new Rect(10, 10, 0, 0), "MIRA API DEBUGGING", () =>
- {
- if (GUILayout.Button("Test modifier"))
- {
- //PlayerControl.LocalPlayer.AddModifier();
- }
- if (GUILayout.Button("Remove modifier"))
+ public DragWindow DebuggingWindow { get; } = new(
+ new Rect(10, 10, 0, 0),
+ "MIRA API DEBUGGING",
+ () =>
{
- //PlayerControl.LocalPlayer.RemoveModifier();
- }
- })
+ })
{
Enabled = true,
};
diff --git a/MiraAPI/GameModes/CustomGameModeManager.cs b/MiraAPI/GameModes/CustomGameModeManager.cs
index 028eb94..388eb5d 100644
--- a/MiraAPI/GameModes/CustomGameModeManager.cs
+++ b/MiraAPI/GameModes/CustomGameModeManager.cs
@@ -6,12 +6,12 @@
namespace MiraAPI.GameModes;
///
-/// Manages custom gamemodes
+/// Manages custom gamemodes.
///
public static class CustomGameModeManager
{
///
- /// List of registered gamemodes
+ /// List of registered gamemodes.
///
internal static readonly Dictionary GameModes = [];
@@ -21,14 +21,14 @@ public static bool IsDefault()
}
///
- /// Current gamemode
+ /// Current gamemode.
///
public static CustomGameMode? ActiveMode { get; internal set; } = new DefaultMode();
///
- /// Set current gamemode
+ /// Set current gamemode.
///
- /// gamemode ID
+ /// gamemode ID.
public static void SetGameMode(int id)
{
if (GameModes.TryGetValue(id, out var gameMode))
@@ -41,9 +41,9 @@ public static void SetGameMode(int id)
}
///
- /// Register gamemode from type
+ /// Register gamemode from type.
///
- /// Type of gamemode class, should inherit from
+ /// Type of gamemode class, should inherit from .
internal static void RegisterGameMode(Type gameModeType)
{
if (!typeof(CustomGameMode).IsAssignableFrom(gameModeType))
@@ -59,7 +59,7 @@ internal static void RegisterGameMode(Type gameModeType)
Logger.Error($"Failed to create instance of {gameModeType.Name}");
return;
}
-
+
if (GameModes.Any(x => x.Key == gameMode.Id))
{
Logger.Error($"ID for gamemode {gameMode.Name} already exists!");
@@ -68,4 +68,4 @@ internal static void RegisterGameMode(Type gameModeType)
GameModes.Add(gameMode.Id, gameMode);
}
-}
\ No newline at end of file
+}
diff --git a/MiraAPI/GameModes/DefaultMode.cs b/MiraAPI/GameModes/DefaultMode.cs
index 2e7fcb0..73c4ca8 100644
--- a/MiraAPI/GameModes/DefaultMode.cs
+++ b/MiraAPI/GameModes/DefaultMode.cs
@@ -6,4 +6,4 @@ public class DefaultMode : CustomGameMode
public override string Name => "Default";
public override string Description => "Default Among Us GameMode";
public override int Id => 0;
-}
\ No newline at end of file
+}
diff --git a/MiraAPI/GameModes/RegisterGameModeAttribute.cs b/MiraAPI/GameModes/RegisterGameModeAttribute.cs
index b329d53..4c66c35 100644
--- a/MiraAPI/GameModes/RegisterGameModeAttribute.cs
+++ b/MiraAPI/GameModes/RegisterGameModeAttribute.cs
@@ -25,4 +25,4 @@ internal static void Register(Assembly assembly)
}
}
}
-}
\ No newline at end of file
+}
diff --git a/MiraAPI/GameOptions/OptionGroupSingleton.cs b/MiraAPI/GameOptions/OptionGroupSingleton.cs
index 8c7e2af..53b2029 100644
--- a/MiraAPI/GameOptions/OptionGroupSingleton.cs
+++ b/MiraAPI/GameOptions/OptionGroupSingleton.cs
@@ -13,5 +13,7 @@ public static class OptionGroupSingleton where T : AbstractOptionGroup
///
/// Gets the instance of the option group.
///
+#pragma warning disable CA1000
public static T Instance => _instance ??= ModdedOptionsManager.Groups.OfType().Single();
+#pragma warning restore CA1000
}
diff --git a/MiraAPI/Hud/CustomButtonSingleton.cs b/MiraAPI/Hud/CustomButtonSingleton.cs
index 3e732be..b338e61 100644
--- a/MiraAPI/Hud/CustomButtonSingleton.cs
+++ b/MiraAPI/Hud/CustomButtonSingleton.cs
@@ -13,5 +13,7 @@ public static class CustomButtonSingleton where T : CustomActionButton
///
/// Gets the instance of the button.
///
+#pragma warning disable CA1000
public static T Instance => _instance ??= CustomButtonManager.CustomButtons.OfType().Single();
+#pragma warning restore CA1000
}
diff --git a/MiraAPI/Hud/RegisterButtonAttribute.cs b/MiraAPI/Hud/RegisterButtonAttribute.cs
index feda3a8..82e0ca5 100644
--- a/MiraAPI/Hud/RegisterButtonAttribute.cs
+++ b/MiraAPI/Hud/RegisterButtonAttribute.cs
@@ -6,4 +6,4 @@ namespace MiraAPI.Hud;
/// Attribute to register a button in the HUD. Necessary for the button to be recognized by Mira.
///
[AttributeUsage(AttributeTargets.Class)]
-public class RegisterButtonAttribute : Attribute;
\ No newline at end of file
+public class RegisterButtonAttribute : Attribute;
diff --git a/MiraAPI/MiraApiPlugin.cs b/MiraAPI/MiraApiPlugin.cs
index b928565..cfe314d 100644
--- a/MiraAPI/MiraApiPlugin.cs
+++ b/MiraAPI/MiraApiPlugin.cs
@@ -16,10 +16,10 @@ namespace MiraAPI;
[ReactorModFlags(ModFlags.RequireOnAllClients)]
public partial class MiraApiPlugin : BasePlugin
{
- public Harmony Harmony { get; } = new(Id);
- private static MiraPluginManager PluginManager { get; set; }
+ private static MiraPluginManager? PluginManager { get; set; }
- public static Color MiraColor = new Color32(238, 154, 112, 255);
+ public Harmony Harmony { get; } = new(Id);
+ public static Color MiraColor { get; } = new Color32(238, 154, 112, 255);
public override void Load()
{
diff --git a/MiraAPI/Modifiers/ModifierComponent.cs b/MiraAPI/Modifiers/ModifierComponent.cs
index 9517711..8b32dc2 100644
--- a/MiraAPI/Modifiers/ModifierComponent.cs
+++ b/MiraAPI/Modifiers/ModifierComponent.cs
@@ -18,7 +18,7 @@ namespace MiraAPI.Modifiers;
/// The component for handling modifiers.
///
[RegisterInIl2Cpp]
-public class ModifierComponent(IntPtr ptr) : MonoBehaviour(ptr)
+public class ModifierComponent(IntPtr cppPtr) : MonoBehaviour(cppPtr)
{
///
/// Gets the active modifiers on the player.
diff --git a/MiraAPI/Networking/SyncModifiersRpc.cs b/MiraAPI/Networking/SyncModifiersRpc.cs
index 9598f0f..288e2c1 100644
--- a/MiraAPI/Networking/SyncModifiersRpc.cs
+++ b/MiraAPI/Networking/SyncModifiersRpc.cs
@@ -6,7 +6,7 @@
namespace MiraAPI.Networking;
[RegisterCustomRpc((uint)MiraRpc.SyncModifiers)]
-internal class SyncModifiersRpc(MiraApiPlugin plugin, uint id) : PlayerCustomRpc(plugin, id)
+internal sealed class SyncModifiersRpc(MiraApiPlugin plugin, uint id) : PlayerCustomRpc(plugin, id)
{
public override RpcLocalHandling LocalHandling => RpcLocalHandling.None;
diff --git a/MiraAPI/Networking/SyncOptionsRpc.cs b/MiraAPI/Networking/SyncOptionsRpc.cs
index 288c690..a80ace3 100644
--- a/MiraAPI/Networking/SyncOptionsRpc.cs
+++ b/MiraAPI/Networking/SyncOptionsRpc.cs
@@ -7,7 +7,7 @@ namespace MiraAPI.Networking;
// METHOD RPC DOESNT WORK WITH THE ARRAYS AND STUFF SO THIS IS HOW WE WILL DO IT FOR NOW
[RegisterCustomRpc((uint)MiraRpc.SyncGameOptions)]
-internal class SyncOptionsRpc(MiraApiPlugin plugin, uint id) : PlayerCustomRpc(plugin, id)
+internal sealed class SyncOptionsRpc(MiraApiPlugin plugin, uint id) : PlayerCustomRpc(plugin, id)
{
public override RpcLocalHandling LocalHandling => RpcLocalHandling.None;
diff --git a/MiraAPI/Networking/SyncRoleOptionsRpc.cs b/MiraAPI/Networking/SyncRoleOptionsRpc.cs
index 290fc0f..adfe537 100644
--- a/MiraAPI/Networking/SyncRoleOptionsRpc.cs
+++ b/MiraAPI/Networking/SyncRoleOptionsRpc.cs
@@ -6,7 +6,7 @@
namespace MiraAPI.Networking;
[RegisterCustomRpc((uint)MiraRpc.SyncRoleOptions)]
-internal class SyncRoleOptionsRpc(MiraApiPlugin plugin, uint id) : PlayerCustomRpc(plugin, id)
+internal sealed class SyncRoleOptionsRpc(MiraApiPlugin plugin, uint id) : PlayerCustomRpc(plugin, id)
{
public override RpcLocalHandling LocalHandling => RpcLocalHandling.None;
diff --git a/MiraAPI/Patches/Colors/ScrollingColorsPatch.cs b/MiraAPI/Patches/Colors/ScrollingColorsPatch.cs
index 9fdc6d4..e89de23 100644
--- a/MiraAPI/Patches/Colors/ScrollingColorsPatch.cs
+++ b/MiraAPI/Patches/Colors/ScrollingColorsPatch.cs
@@ -7,8 +7,8 @@ namespace MiraAPI.Patches.Colors;
[HarmonyPatch(typeof(PlayerTab))]
public static class ScrollingColorsPatch
{
- /// Collider
- private static BoxCollider2D _collider;
+ // Collider
+ private static BoxCollider2D? _collider;
///
/// Add scrolling to the colors tab
@@ -20,7 +20,7 @@ public static void AddScrollingToColorsTabPatch(PlayerTab __instance)
{
return;
}
-
+
var tab = PlayerCustomizationMenu.Instance.Tabs[1].Tab;
if (__instance.scroller == null)
@@ -31,7 +31,7 @@ public static void AddScrollingToColorsTabPatch(PlayerTab __instance)
var maskObj = new GameObject
{
layer = 5,
- name = "SpriteMask"
+ name = "SpriteMask",
};
maskObj.transform.SetParent(__instance.transform);
maskObj.transform.localPosition = new Vector3(0, 0, 0);
@@ -55,4 +55,4 @@ public static void AddScrollingToColorsTabPatch(PlayerTab __instance)
__instance.SetScrollerBounds();
}
-}
\ No newline at end of file
+}
diff --git a/MiraAPI/Patches/GameModes/ConsolePatches.cs b/MiraAPI/Patches/GameModes/ConsolePatches.cs
index 50248e7..e2f24b2 100644
--- a/MiraAPI/Patches/GameModes/ConsolePatches.cs
+++ b/MiraAPI/Patches/GameModes/ConsolePatches.cs
@@ -1,5 +1,4 @@
-
-/*
+/*
[HarmonyPatch]
public static class ConsolePatches
{
@@ -69,4 +68,4 @@ public static bool MapCanUsePatch(MapConsole __instance, [HarmonyArgument(0)] Ne
canUse = couldUse = true;
return true;
}
-}*/
\ No newline at end of file
+}*/
diff --git a/MiraAPI/Patches/GameModes/DeadBodyPatch.cs b/MiraAPI/Patches/GameModes/DeadBodyPatch.cs
index edd4e58..07a2899 100644
--- a/MiraAPI/Patches/GameModes/DeadBodyPatch.cs
+++ b/MiraAPI/Patches/GameModes/DeadBodyPatch.cs
@@ -1,6 +1,4 @@
-
-
-/*
+/*
[HarmonyPatch(typeof(DeadBody))]
public static class DeadBodyPatch
{
@@ -10,4 +8,4 @@ public static bool OnClickPatch(DeadBody __instance)
{
return CustomGameModeManager.ActiveMode == null || CustomGameModeManager.ActiveMode.CanReport(__instance);
}
-}*/
\ No newline at end of file
+}*/
diff --git a/MiraAPI/Patches/GameModes/GameLogicPatches.cs b/MiraAPI/Patches/GameModes/GameLogicPatches.cs
index 77eca63..a62be83 100644
--- a/MiraAPI/Patches/GameModes/GameLogicPatches.cs
+++ b/MiraAPI/Patches/GameModes/GameLogicPatches.cs
@@ -1,6 +1,4 @@
-
-
-/*
+/*
[HarmonyPatch]
public static class GameLogicPatches
{
@@ -19,4 +17,4 @@ public static bool AssignRolesPatch(LogicRoleSelectionNormal __instance)
CustomGameModeManager.ActiveMode?.AssignRoles(out runOriginal, __instance);
return runOriginal;
}
-}*/
\ No newline at end of file
+}*/
diff --git a/MiraAPI/Patches/GameModes/ImpostorTargetPatch.cs b/MiraAPI/Patches/GameModes/ImpostorTargetPatch.cs
index 58f1187..ad0d9e0 100644
--- a/MiraAPI/Patches/GameModes/ImpostorTargetPatch.cs
+++ b/MiraAPI/Patches/GameModes/ImpostorTargetPatch.cs
@@ -1,6 +1,4 @@
-
-
-/*
+/*
///
/// Allow Impostors to kill each other if can kill is enabled in gamemode or friendly fire is toggled on
///
@@ -16,11 +14,11 @@ public static bool Prefix(ImpostorRole __instance, [HarmonyArgument(0)] Networke
{
return true;
}
-
+
__result = target is { Disconnected: false, IsDead: false } &&
target.PlayerId != __instance.Player.PlayerId && !(target.Role == null) &&
!(target.Object == null) && !target.Object.inVent && !target.Object.inMovingPlat;
return false;
}
-}*/
\ No newline at end of file
+}*/
diff --git a/MiraAPI/Patches/GameModes/MapBehaviourPatch.cs b/MiraAPI/Patches/GameModes/MapBehaviourPatch.cs
index 8f17b99..9a4bd8b 100644
--- a/MiraAPI/Patches/GameModes/MapBehaviourPatch.cs
+++ b/MiraAPI/Patches/GameModes/MapBehaviourPatch.cs
@@ -1,6 +1,4 @@
-
-
-/*
+/*
[HarmonyPatch(typeof(MapBehaviour))]
public static class MapBehaviourPatch
{
@@ -17,4 +15,4 @@ public static bool ShowSabotagePatch(MapBehaviour __instance)
return true;
}
-}*/
\ No newline at end of file
+}*/
diff --git a/MiraAPI/Patches/GameModes/OnDeathPatch.cs b/MiraAPI/Patches/GameModes/OnDeathPatch.cs
index 275321d..99f9211 100644
--- a/MiraAPI/Patches/GameModes/OnDeathPatch.cs
+++ b/MiraAPI/Patches/GameModes/OnDeathPatch.cs
@@ -1,6 +1,4 @@
-
-
-/*
+/*
[HarmonyPatch(typeof(KillAnimation))]
public static class OnDeathPatch
{
@@ -10,4 +8,4 @@ public static void OnDeathPostfix([HarmonyArgument(0)] PlayerControl source, [Ha
{
CustomGameModeManager.ActiveMode?.OnDeath(target);
}
-}*/
\ No newline at end of file
+}*/
diff --git a/MiraAPI/Patches/GameModes/VentPatches.cs b/MiraAPI/Patches/GameModes/VentPatches.cs
index a86aa46..597c40a 100644
--- a/MiraAPI/Patches/GameModes/VentPatches.cs
+++ b/MiraAPI/Patches/GameModes/VentPatches.cs
@@ -1,10 +1,7 @@
-
-
-/*
+/*
[HarmonyPatch(typeof(Vent))]
public static class VentPatches
{
-
[HarmonyPrefix]
[HarmonyPatch(nameof(Vent.CanUse))]
public static bool CanUseVentPatch(Vent __instance, ref float __result, [HarmonyArgument(0)] NetworkedPlayerInfo pc, [HarmonyArgument(1)] ref bool canUse, [HarmonyArgument(2)] ref bool couldUse)
@@ -47,5 +44,4 @@ public static bool SetOutlinePatch(Vent __instance, [HarmonyArgument(0)] bool on
return false;
}
-
-}*/
\ No newline at end of file
+}*/
diff --git a/MiraAPI/Patches/Modifiers/VentPatches.cs b/MiraAPI/Patches/Modifiers/VentPatches.cs
index 6646336..8c6c26a 100644
--- a/MiraAPI/Patches/Modifiers/VentPatches.cs
+++ b/MiraAPI/Patches/Modifiers/VentPatches.cs
@@ -42,4 +42,4 @@ public static void CanUseVentPatch(Vent __instance, ref float __result, [Harmony
}
__result = num;
}
-}
\ No newline at end of file
+}
diff --git a/MiraAPI/Patches/Options/GameSettingMenuPatches.cs b/MiraAPI/Patches/Options/GameSettingMenuPatches.cs
index 13c9036..a44b35c 100644
--- a/MiraAPI/Patches/Options/GameSettingMenuPatches.cs
+++ b/MiraAPI/Patches/Options/GameSettingMenuPatches.cs
@@ -154,7 +154,6 @@ private static void UpdateText(GameSettingMenu menu, GameOptionsMenu settings, R
}
roles.roleChances.Clear();
- roles.roleChances = null;
roles.AdvancedRolesSettings.gameObject.SetActive(false);
roles.RoleChancesSettings.gameObject.SetActive(true);
roles.SetQuotaTab();
diff --git a/MiraAPI/Patches/Roles/TaskPanelPatch.cs b/MiraAPI/Patches/Roles/TaskPanelPatch.cs
index 3d4ae14..431d47b 100644
--- a/MiraAPI/Patches/Roles/TaskPanelPatch.cs
+++ b/MiraAPI/Patches/Roles/TaskPanelPatch.cs
@@ -7,9 +7,9 @@ namespace MiraAPI.Patches.Roles;
public static class TaskPanelPatch
{
///
- /// This patch is to override the automatic updating of the y position on the tab (which is in base game),
+ /// This patch is to override the automatic updating of the y position on the tab (which is in base game)
/// because I can't change the custom tab y pos if it's being overriden every frame.
- /// Im sure there is an easier/better way, but this is the fix that worked for me
+ /// Im sure there is an easier/better way, but this is the fix that worked for me.
///
[HarmonyPrefix]
[HarmonyPatch(nameof(TaskPanelBehaviour.Update))]
diff --git a/MiraAPI/PluginLoading/IMiraPlugin.cs b/MiraAPI/PluginLoading/IMiraPlugin.cs
index 9a71645..07928da 100644
--- a/MiraAPI/PluginLoading/IMiraPlugin.cs
+++ b/MiraAPI/PluginLoading/IMiraPlugin.cs
@@ -6,4 +6,4 @@ public interface IMiraPlugin
{
string OptionsTitleText { get; }
public ConfigFile GetConfigFile();
-}
\ No newline at end of file
+}
diff --git a/MiraAPI/PluginLoading/MiraPluginManager.cs b/MiraAPI/PluginLoading/MiraPluginManager.cs
index 794d74e..423cb09 100644
--- a/MiraAPI/PluginLoading/MiraPluginManager.cs
+++ b/MiraAPI/PluginLoading/MiraPluginManager.cs
@@ -15,7 +15,7 @@
namespace MiraAPI.PluginLoading;
-internal class MiraPluginManager
+internal sealed class MiraPluginManager
{
private readonly Dictionary _registeredPlugins = [];
diff --git a/MiraAPI/Roles/ModdedRoleTeams.cs b/MiraAPI/Roles/ModdedRoleTeams.cs
index ca7adad..e599cd7 100644
--- a/MiraAPI/Roles/ModdedRoleTeams.cs
+++ b/MiraAPI/Roles/ModdedRoleTeams.cs
@@ -4,5 +4,5 @@ public enum ModdedRoleTeams
{
Crewmate,
Impostor,
- Neutral
-}
\ No newline at end of file
+ Neutral,
+}
diff --git a/MiraAPI/Roles/RegisterCustomRoleAttribute.cs b/MiraAPI/Roles/RegisterCustomRoleAttribute.cs
index db9a0e7..a6352f1 100644
--- a/MiraAPI/Roles/RegisterCustomRoleAttribute.cs
+++ b/MiraAPI/Roles/RegisterCustomRoleAttribute.cs
@@ -3,4 +3,4 @@
namespace MiraAPI.Roles;
[AttributeUsage(AttributeTargets.Class)]
-public class RegisterCustomRoleAttribute : Attribute;
\ No newline at end of file
+public class RegisterCustomRoleAttribute : Attribute;
diff --git a/MiraAPI/Roles/RoleId.cs b/MiraAPI/Roles/RoleId.cs
index 9970d62..05f9cd0 100644
--- a/MiraAPI/Roles/RoleId.cs
+++ b/MiraAPI/Roles/RoleId.cs
@@ -13,7 +13,7 @@ public static ushort Get() where T : RoleBehaviour
return roleId;
}
-
+
public static ushort Get(Type type)
{
if (!CustomRoleManager.RoleIds.TryGetValue(type, out var roleId))
@@ -23,4 +23,4 @@ public static ushort Get(Type type)
return roleId;
}
-}
\ No newline at end of file
+}
diff --git a/MiraAPI/Utilities/Assets/MiraAssets.cs b/MiraAPI/Utilities/Assets/MiraAssets.cs
index 527fadb..514bd25 100644
--- a/MiraAPI/Utilities/Assets/MiraAssets.cs
+++ b/MiraAPI/Utilities/Assets/MiraAssets.cs
@@ -11,7 +11,5 @@ public static class MiraAssets
public static readonly LoadableResourceAsset Cog = new("MiraAPI.Resources.Cog.png");
public static readonly LoadableResourceAsset Checkmark = new("MiraAPI.Resources.Checkmark.png");
public static readonly LoadableResourceAsset CheckmarkBox = new("MiraAPI.Resources.CheckMarkBox.png");
-
-
- public static readonly Color32 AcceptedTeal = new Color32(43, 233, 198, 255);
-}
\ No newline at end of file
+ public static readonly Color32 AcceptedTeal = new(43, 233, 198, 255);
+}
diff --git a/MiraAPI/Utilities/Assets/SpriteTools.cs b/MiraAPI/Utilities/Assets/SpriteTools.cs
index d086a9e..bf79182 100644
--- a/MiraAPI/Utilities/Assets/SpriteTools.cs
+++ b/MiraAPI/Utilities/Assets/SpriteTools.cs
@@ -1,9 +1,9 @@
-using Il2CppInterop.Runtime;
-using Il2CppInterop.Runtime.InteropTypes.Arrays;
-using Reactor.Utilities.Extensions;
-using System;
+using System;
using System.Reflection;
+using Il2CppInterop.Runtime;
+using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Reactor.Utilities;
+using Reactor.Utilities.Extensions;
using UnityEngine;
namespace MiraAPI.Utilities.Assets;
@@ -13,15 +13,9 @@ namespace MiraAPI.Utilities.Assets;
///
public static class SpriteTools
{
- ///
- /// Delegate for LoadImage.
- ///
- public delegate bool DLoadImage(IntPtr tex, IntPtr data, bool markNonReadable);
+ private delegate bool DLoadImage(IntPtr tex, IntPtr data, bool markNonReadable);
- ///
- /// The ICall for LoadImage.
- ///
- public static DLoadImage? ICallLoadImage;
+ private static DLoadImage? _iCallLoadImage;
///
/// Load an image into a texture.
@@ -32,18 +26,18 @@ public static class SpriteTools
/// True if succeeded.
public static bool LoadImage(Texture2D tex, byte[] data, bool markNonReadable)
{
- ICallLoadImage ??= IL2CPP.ResolveICall("UnityEngine.ImageConversion::LoadImage");
+ _iCallLoadImage ??= IL2CPP.ResolveICall("UnityEngine.ImageConversion::LoadImage");
var il2CPPArray = (Il2CppStructArray)data;
- return ICallLoadImage.Invoke(tex.Pointer, il2CPPArray.Pointer, markNonReadable);
+ return _iCallLoadImage.Invoke(tex.Pointer, il2CPPArray.Pointer, markNonReadable);
}
///
/// Load a sprite from a resource path.
///
/// The path to the resource.
- /// A sprite made from the resource
+ /// A sprite made from the resource.
/// The resource cannot be found.
public static Sprite LoadSpriteFromPath(string resourcePath, Assembly assembly)
{
diff --git a/MiraAPI/Utilities/MiraNumberSuffixes.cs b/MiraAPI/Utilities/MiraNumberSuffixes.cs
index 3682e2b..20ed21c 100644
--- a/MiraAPI/Utilities/MiraNumberSuffixes.cs
+++ b/MiraAPI/Utilities/MiraNumberSuffixes.cs
@@ -4,5 +4,5 @@ public enum MiraNumberSuffixes
None,
Multiplier,
Seconds,
- Percent
-}
\ No newline at end of file
+ Percent,
+}
diff --git a/MiraAPI/Utilities/ShaderID.cs b/MiraAPI/Utilities/ShaderID.cs
index 08775bf..d250336 100644
--- a/MiraAPI/Utilities/ShaderID.cs
+++ b/MiraAPI/Utilities/ShaderID.cs
@@ -5,8 +5,8 @@ namespace MiraAPI.Utilities;
public static class ShaderID
{
- private static readonly Dictionary Cache = new();
-
+ private static readonly Dictionary Cache = [];
+
public static int Get(string name)
{
if (Cache.TryGetValue(name, out var id))
@@ -18,74 +18,74 @@ public static int Get(string name)
Cache[name] = id;
return id;
}
-
+
// For player shader
public static readonly int BodyColor = Shader.PropertyToID("_BodyColor");
public static readonly int BackColor = Shader.PropertyToID("_BackColor");
public static readonly int VisorColor = Shader.PropertyToID("_VisorColor");
-
+
// Main texture, very obviously used in any shader with a texture
public static readonly int MainTex = Shader.PropertyToID("_MainTex");
-
+
// Any masking stuff, like MeetingHud bubbles
public static readonly int Mask = Shader.PropertyToID("_Mask");
public static readonly int MaskComp = Shader.PropertyToID("_MaskComp");
public static readonly int MaskLayer = Shader.PropertyToID("_MaskLayer");
public static readonly int Stencil = Shader.PropertyToID("_Stencil");
public static readonly int StencilComp = Shader.PropertyToID("_StencilComp");
-
+
// Used in many tasks
public static readonly int Color = Shader.PropertyToID("_Color");
-
+
// Has 2 uses in the game, provided for convenience
public static readonly int Opacity = Shader.PropertyToID("_Opacity");
-
+
// Used once in CooldownHelpers, once in PowerBarMining
public static readonly int NormalizedUvs = Shader.PropertyToID("_NormalizedUvs");
-
+
// Used in many consoles
public static readonly int Outline = Shader.PropertyToID("_Outline");
public static readonly int OutlineColor = Shader.PropertyToID("_OutlineColor");
-
+
// Used in some consoles
public static readonly int AddColor = Shader.PropertyToID("_AddColor");
-
+
// Has some uses in various locations
public static readonly int Percent = Shader.PropertyToID("_Percent");
public static readonly int PercentY = Shader.PropertyToID("_PercentY");
public static readonly int Desat = Shader.PropertyToID("_Desat");
-
+
// Used in LightSource
public static readonly int PlayerRadius = Shader.PropertyToID("_PlayerRadius");
public static readonly int LightRadius = Shader.PropertyToID("_LightRadius");
public static readonly int LightOffset = Shader.PropertyToID("_LightOffset");
public static readonly int FlashlightSize = Shader.PropertyToID("_FlashlightSize");
public static readonly int FlashlightAngle = Shader.PropertyToID("_FlashlightAngle");
-
+
// Used once for LightSourceGpuRenderer
public static readonly int DepthCompressionValue = Shader.PropertyToID("_DepthCompressionValue");
-
+
// Used in ProgressTracker
public static readonly int Buckets = Shader.PropertyToID("_Buckets");
public static readonly int FullBuckets = Shader.PropertyToID("_FullBuckets");
-
+
// Used once in IntroCutscene and EndGameManager
public static readonly int Rad = Shader.PropertyToID("_Rad");
-
+
// Used only once for Quick Chat
public static readonly int FaceColor = Shader.PropertyToID("_FaceColor");
-
+
// Used for NavigationMinigame
public static readonly int CrossHair = Shader.PropertyToID("_CrossHair");
public static readonly int CrossColor = Shader.PropertyToID("_CrossColor");
-
+
// Used for both SurveillanceMinigame (Planet and Normal)
public static readonly int Center = Shader.PropertyToID("_Center");
public static readonly int Color2 = Shader.PropertyToID("_Color2");
-
+
// Used in ReactorShipRoom
public static readonly int Speed = Shader.PropertyToID("_Speed");
-
+
// Used only once in CourseMinigame
public static readonly int AltTex = Shader.PropertyToID("_AltTex");
public static readonly int Perc = Shader.PropertyToID("_Perc");
@@ -93,8 +93,7 @@ public static int Get(string name)
// Used once in TextMarquee
public static readonly int VertexOffsetX = Shader.PropertyToID("_VertexOffsetX");
public static readonly int VertexOffsetY = Shader.PropertyToID("_VertexOffsetY");
-
+
// Used in VertLineBehaviour
public static readonly int Fade = Shader.PropertyToID("_Fade");
-
-}
\ No newline at end of file
+}
From 51d08bb168569780524adff742717a0edb40dadb Mon Sep 17 00:00:00 2001
From: XtraCube <72575280+XtraCube@users.noreply.github.com>
Date: Mon, 2 Sep 2024 15:22:50 -0400
Subject: [PATCH 23/36] hide mod in TaskAdder if it has no roles
---
MiraAPI/Patches/Roles/TaskAdderPatch.cs | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/MiraAPI/Patches/Roles/TaskAdderPatch.cs b/MiraAPI/Patches/Roles/TaskAdderPatch.cs
index 8a3ae90..0f3037f 100644
--- a/MiraAPI/Patches/Roles/TaskAdderPatch.cs
+++ b/MiraAPI/Patches/Roles/TaskAdderPatch.cs
@@ -62,6 +62,11 @@ public static void AddRolesFolder(TaskAdderGame __instance)
foreach (var plugin in MiraPluginManager.Instance.RegisteredPlugins())
{
+ if (plugin.CustomRoles.Count == 0)
+ {
+ continue;
+ }
+
var newFolder = Object.Instantiate(__instance.RootFolderPrefab, _scroller.Inner);
newFolder.FolderName = newFolder.name = plugin.PluginInfo.Metadata.Name;
newFolder.gameObject.SetActive(false);
From ae10917f2a45fd9abd4318739277b796e90f1090 Mon Sep 17 00:00:00 2001
From: XtraCube <72575280+XtraCube@users.noreply.github.com>
Date: Mon, 2 Sep 2024 15:22:56 -0400
Subject: [PATCH 24/36] hidefromil2cpp
---
MiraAPI.Example/MiraDebugWindow.cs | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/MiraAPI.Example/MiraDebugWindow.cs b/MiraAPI.Example/MiraDebugWindow.cs
index 13a41d4..d0726e7 100644
--- a/MiraAPI.Example/MiraDebugWindow.cs
+++ b/MiraAPI.Example/MiraDebugWindow.cs
@@ -1,6 +1,7 @@
-using Reactor.Utilities.Attributes;
+using System;
+using Il2CppInterop.Runtime.Attributes;
+using Reactor.Utilities.Attributes;
using Reactor.Utilities.ImGui;
-using System;
using UnityEngine;
namespace MiraAPI.Example;
@@ -8,6 +9,7 @@ namespace MiraAPI.Example;
[RegisterInIl2Cpp]
public class MiraDebugWindow(IntPtr cppPtr) : MonoBehaviour(cppPtr)
{
+ [HideFromIl2Cpp]
public DragWindow DebuggingWindow { get; } = new(
new Rect(10, 10, 0, 0),
"MIRA API DEBUGGING",
From f92d08b825b2c961b9986f3ea550ba15c466e0b8 Mon Sep 17 00:00:00 2001
From: Rubyboat <52091447+Rubyboat1207@users.noreply.github.com>
Date: Mon, 2 Sep 2024 15:37:53 -0500
Subject: [PATCH 25/36] Added Loadable Audio Resource Asset
---
.../Assets/LoadableAudioResourceAsset.cs | 66 +++++++++++++++++++
1 file changed, 66 insertions(+)
create mode 100644 MiraAPI/Utilities/Assets/LoadableAudioResourceAsset.cs
diff --git a/MiraAPI/Utilities/Assets/LoadableAudioResourceAsset.cs b/MiraAPI/Utilities/Assets/LoadableAudioResourceAsset.cs
new file mode 100644
index 0000000..7e4decf
--- /dev/null
+++ b/MiraAPI/Utilities/Assets/LoadableAudioResourceAsset.cs
@@ -0,0 +1,66 @@
+using System;
+using System.IO;
+using System.Reflection;
+using System.Text;
+using Cpp2IL.Core.Extensions;
+using MiraAPI.Utilities.Assets;
+using Reactor.Utilities.Extensions;
+using UnityEngine;
+
+namespace MiraAPI.Utilities.Assets;
+
+///
+/// A utility class for loading .WAV audio assets from the DLL's embedded resources.
+///
+/// The path of the wave file
+public class LoadableAudioResourceAsset(string path) : LoadableAsset
+{
+ private readonly Assembly _assembly = Assembly.GetCallingAssembly();
+
+ ///
+ /// Loads the asset from embedded resources.
+ ///
+ /// The asset to load.
+ /// Attempted to load an Audio file in non WAV format.
+ /// Stream failed to load. Check if the name of your asset was correct.
+ public override AudioClip LoadAsset()
+ {
+ var assetStream = _assembly.GetManifestResourceStream(path);
+
+ if (assetStream != null)
+ {
+ var audioBytes = assetStream.ReadFully();
+
+ string riffHeader = Encoding.ASCII.GetString(audioBytes.SubArray(0, 4));
+ string waveHeader = Encoding.ASCII.GetString(audioBytes.SubArray(8, 4));
+
+ if (riffHeader != "RIFF" || waveHeader != "WAVE")
+ {
+ throw new NotSupportedException($"Attempted to load an Audio file in non WAV format '{path}'.");
+ }
+
+ int channels = BitConverter.ToInt16(audioBytes, 22);
+ int sampleRate = BitConverter.ToInt32(audioBytes, 24);
+ int dataSize = BitConverter.ToInt32(audioBytes, 40);
+
+ float[] audioData = new float[dataSize / 2];
+ for (int i = 0; i < audioData.Length; i++)
+ {
+ audioData[i] = BitConverter.ToInt16(audioBytes, 44 + i * 2) / 32768.0f;
+ }
+
+ AudioClip audioClip = AudioClip.Create(
+ "WavClip",
+ audioData.Length,
+ channels,
+ sampleRate,
+ false
+ );
+ audioClip.SetData(audioData, 0);
+
+ return audioClip;
+ }
+
+ throw new FileNotFoundException("Stream failed to load. Check if the name of your asset was correct.");
+ }
+}
From 9c14db0321942caa91dec77a4ff65c5447355ec4 Mon Sep 17 00:00:00 2001
From: XtraCube <72575280+XtraCube@users.noreply.github.com>
Date: Tue, 3 Sep 2024 18:39:03 -0400
Subject: [PATCH 26/36] slight fix to options Click To Close text
---
MiraAPI/Patches/Options/GameOptionsMenuPatch.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/MiraAPI/Patches/Options/GameOptionsMenuPatch.cs b/MiraAPI/Patches/Options/GameOptionsMenuPatch.cs
index a51b2f9..517f7d0 100644
--- a/MiraAPI/Patches/Options/GameOptionsMenuPatch.cs
+++ b/MiraAPI/Patches/Options/GameOptionsMenuPatch.cs
@@ -114,7 +114,7 @@ public static bool SettingsPatch(GameOptionsMenu __instance)
group.Header = categoryHeaderMasked;
var newText = Object.Instantiate(categoryHeaderMasked.Title, categoryHeaderMasked.transform);
- newText.text = $"(Click to open)";
+ newText.text = "(Click to close)";
newText.transform.localPosition = new Vector3(2.6249f, -0.165f, 0f);
newText.gameObject.GetComponent().Destroy();
From f83dce99ef5ec69527ee5e2263a70c86517afca6 Mon Sep 17 00:00:00 2001
From: XtraCube <72575280+XtraCube@users.noreply.github.com>
Date: Tue, 3 Sep 2024 20:59:26 -0400
Subject: [PATCH 27/36] add group priorities for ordering groups
---
MiraAPI.Example/Options/ExampleOptions2.cs | 2 ++
MiraAPI/GameOptions/AbstractOptionGroup.cs | 6 ++++++
MiraAPI/PluginLoading/MiraPluginManager.cs | 2 ++
3 files changed, 10 insertions(+)
diff --git a/MiraAPI.Example/Options/ExampleOptions2.cs b/MiraAPI.Example/Options/ExampleOptions2.cs
index c521ea8..56dd209 100644
--- a/MiraAPI.Example/Options/ExampleOptions2.cs
+++ b/MiraAPI.Example/Options/ExampleOptions2.cs
@@ -8,6 +8,8 @@ public class ExampleOptions2 : AbstractOptionGroup
{
public override string GroupName => "Example Options 2";
+ public override uint GroupPriority => 0; // This group will be displayed first. The default value is uint.MaxValue.
+
public ModdedToggleOption ToggleOpt1 { get; } = new("Toggle Option 1", false);
public ModdedToggleOption ToggleOpt2 { get; } = new("Toggle Option 2", false)
diff --git a/MiraAPI/GameOptions/AbstractOptionGroup.cs b/MiraAPI/GameOptions/AbstractOptionGroup.cs
index aeae257..418f25b 100644
--- a/MiraAPI/GameOptions/AbstractOptionGroup.cs
+++ b/MiraAPI/GameOptions/AbstractOptionGroup.cs
@@ -26,6 +26,12 @@ public abstract class AbstractOptionGroup
///
public virtual Color GroupColor => Color.clear;
+ ///
+ /// Gets the group priority. This is used to determine the order in which groups are displayed in the options menu.
+ /// Zero is the highest priority, and the default value is the max uint value.
+ ///
+ public virtual uint GroupPriority => uint.MaxValue;
+
///
/// Gets the role the group is associated with. This is used for the advanced role options menu.
///
diff --git a/MiraAPI/PluginLoading/MiraPluginManager.cs b/MiraAPI/PluginLoading/MiraPluginManager.cs
index 423cb09..2a735b8 100644
--- a/MiraAPI/PluginLoading/MiraPluginManager.cs
+++ b/MiraAPI/PluginLoading/MiraPluginManager.cs
@@ -83,6 +83,8 @@ private static void RegisterAllOptions(Assembly assembly, MiraPluginInfo pluginI
ModdedOptionsManager.RegisterAttributeOption(type, attribute, property, pluginInfo);
}
}
+
+ pluginInfo.OptionGroups.Sort((x, y) => x.GroupPriority.CompareTo(y.GroupPriority));
}
private static void RegisterRoleAttribute(Assembly assembly, MiraPluginInfo pluginInfo)
From 4e474dc5b2b8a5bad345dd2572e6893009241420 Mon Sep 17 00:00:00 2001
From: XtraCube <72575280+XtraCube@users.noreply.github.com>
Date: Tue, 3 Sep 2024 21:05:32 -0400
Subject: [PATCH 28/36] formatting
---
.../Assets/LoadableAudioResourceAsset.cs | 59 +++++++++----------
1 file changed, 27 insertions(+), 32 deletions(-)
diff --git a/MiraAPI/Utilities/Assets/LoadableAudioResourceAsset.cs b/MiraAPI/Utilities/Assets/LoadableAudioResourceAsset.cs
index 7e4decf..25640e4 100644
--- a/MiraAPI/Utilities/Assets/LoadableAudioResourceAsset.cs
+++ b/MiraAPI/Utilities/Assets/LoadableAudioResourceAsset.cs
@@ -3,7 +3,6 @@
using System.Reflection;
using System.Text;
using Cpp2IL.Core.Extensions;
-using MiraAPI.Utilities.Assets;
using Reactor.Utilities.Extensions;
using UnityEngine;
@@ -25,42 +24,38 @@ public class LoadableAudioResourceAsset(string path) : LoadableAsset
/// Stream failed to load. Check if the name of your asset was correct.
public override AudioClip LoadAsset()
{
- var assetStream = _assembly.GetManifestResourceStream(path);
+ var assetStream = _assembly.GetManifestResourceStream(path) ??
+ throw new FileNotFoundException(
+ "Stream failed to load. Check if the name of your asset was correct.");
+ var audioBytes = assetStream.ReadFully();
- if (assetStream != null)
- {
- var audioBytes = assetStream.ReadFully();
-
- string riffHeader = Encoding.ASCII.GetString(audioBytes.SubArray(0, 4));
- string waveHeader = Encoding.ASCII.GetString(audioBytes.SubArray(8, 4));
-
- if (riffHeader != "RIFF" || waveHeader != "WAVE")
- {
- throw new NotSupportedException($"Attempted to load an Audio file in non WAV format '{path}'.");
- }
-
- int channels = BitConverter.ToInt16(audioBytes, 22);
- int sampleRate = BitConverter.ToInt32(audioBytes, 24);
- int dataSize = BitConverter.ToInt32(audioBytes, 40);
+ var riffHeader = Encoding.ASCII.GetString(audioBytes.SubArray(0, 4));
+ var waveHeader = Encoding.ASCII.GetString(audioBytes.SubArray(8, 4));
- float[] audioData = new float[dataSize / 2];
- for (int i = 0; i < audioData.Length; i++)
- {
- audioData[i] = BitConverter.ToInt16(audioBytes, 44 + i * 2) / 32768.0f;
- }
+ if (riffHeader != "RIFF" || waveHeader != "WAVE")
+ {
+ throw new NotSupportedException($"Attempted to load an Audio file in non WAV format '{path}'.");
+ }
- AudioClip audioClip = AudioClip.Create(
- "WavClip",
- audioData.Length,
- channels,
- sampleRate,
- false
- );
- audioClip.SetData(audioData, 0);
+ int channels = BitConverter.ToInt16(audioBytes, 22);
+ var sampleRate = BitConverter.ToInt32(audioBytes, 24);
+ var dataSize = BitConverter.ToInt32(audioBytes, 40);
- return audioClip;
+ var audioData = new float[dataSize / 2];
+ for (var i = 0; i < audioData.Length; i++)
+ {
+ audioData[i] = BitConverter.ToInt16(audioBytes, 44 + i * 2) / 32768.0f;
}
- throw new FileNotFoundException("Stream failed to load. Check if the name of your asset was correct.");
+ var audioClip = AudioClip.Create(
+ "WavClip",
+ audioData.Length,
+ channels,
+ sampleRate,
+ false
+ );
+ audioClip.SetData(audioData, 0);
+
+ return audioClip;
}
}
From 08a4dc75f28ffca567a17553ab0e98c2c9d3bcee Mon Sep 17 00:00:00 2001
From: XtraCube <72575280+XtraCube@users.noreply.github.com>
Date: Tue, 3 Sep 2024 21:05:55 -0400
Subject: [PATCH 29/36] fix period oops
---
MiraAPI/Utilities/Assets/LoadableAudioResourceAsset.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/MiraAPI/Utilities/Assets/LoadableAudioResourceAsset.cs b/MiraAPI/Utilities/Assets/LoadableAudioResourceAsset.cs
index 25640e4..be32627 100644
--- a/MiraAPI/Utilities/Assets/LoadableAudioResourceAsset.cs
+++ b/MiraAPI/Utilities/Assets/LoadableAudioResourceAsset.cs
@@ -11,7 +11,7 @@ namespace MiraAPI.Utilities.Assets;
///
/// A utility class for loading .WAV audio assets from the DLL's embedded resources.
///
-/// The path of the wave file
+/// The path of the wave file.
public class LoadableAudioResourceAsset(string path) : LoadableAsset
{
private readonly Assembly _assembly = Assembly.GetCallingAssembly();
From 24dca63df11eb9c462b601f3f81611d738b047b7 Mon Sep 17 00:00:00 2001
From: Rubyboat <52091447+Rubyboat1207@users.noreply.github.com>
Date: Tue, 3 Sep 2024 20:17:50 -0500
Subject: [PATCH 30/36] File name more descriptive
---
MiraAPI/Utilities/Assets/LoadableAudioResourceAsset.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/MiraAPI/Utilities/Assets/LoadableAudioResourceAsset.cs b/MiraAPI/Utilities/Assets/LoadableAudioResourceAsset.cs
index be32627..381e9bc 100644
--- a/MiraAPI/Utilities/Assets/LoadableAudioResourceAsset.cs
+++ b/MiraAPI/Utilities/Assets/LoadableAudioResourceAsset.cs
@@ -48,7 +48,7 @@ public override AudioClip LoadAsset()
}
var audioClip = AudioClip.Create(
- "WavClip",
+ path,
audioData.Length,
channels,
sampleRate,
From 75dd5e8a35576f2a8e6e0c9efbfc0628cee574a3 Mon Sep 17 00:00:00 2001
From: CallOfCreator
Date: Wed, 4 Sep 2024 16:27:57 +0000
Subject: [PATCH 31/36] Add CanUseSabotage support in ICustomRole
---
MiraAPI/Patches/HudManagerPatches.cs | 35 ++++++++++++++++++++++++++++
MiraAPI/Roles/ICustomRole.cs | 5 ++++
2 files changed, 40 insertions(+)
diff --git a/MiraAPI/Patches/HudManagerPatches.cs b/MiraAPI/Patches/HudManagerPatches.cs
index cdef7cc..ddd31f8 100644
--- a/MiraAPI/Patches/HudManagerPatches.cs
+++ b/MiraAPI/Patches/HudManagerPatches.cs
@@ -1,5 +1,6 @@
using HarmonyLib;
using MiraAPI.Hud;
+using MiraAPI.Roles;
using Reactor.Utilities.Extensions;
using UnityEngine;
using Object = UnityEngine.Object;
@@ -92,10 +93,44 @@ public static void SetHudActivePostfix(HudManager __instance, PlayerControl loca
{
return;
}
+ if (CustomRoleManager.GetCustomRoleBehaviour(role.Role, out var customRole))
+ {
+ if (customRole.CanUseSabotage)
+ {
+ __instance.SabotageButton.gameObject.SetActive(true);
+ }
+ else
+ {
+ __instance.SabotageButton.gameObject.SetActive(role.IsImpostor && isActive);
+ }
+ }
foreach (var button in CustomButtonManager.CustomButtons)
{
button.SetActive(isActive, role);
}
}
+
+ ///
+ /// Patches the Sabotage button to check if the player's custom role can use sabotage.
+ ///
+ [HarmonyPatch(typeof(SabotageButton), nameof(SabotageButton.DoClick))]
+ [HarmonyPrefix]
+ public static bool StartPrefix(SabotageButton __instance)
+ {
+
+ var player = PlayerControl.LocalPlayer;
+
+ if (CustomRoleManager.GetCustomRoleBehaviour(player.Data.Role.Role, out var customRole))
+ {
+ if (!customRole.CanUseSabotage) return false;
+
+ DestroyableSingleton.Instance.ToggleMapVisible(new MapOptions()
+ {
+ Mode = MapOptions.Modes.Sabotage
+ });
+ return false;
+ }
+ return true;
+ }
}
diff --git a/MiraAPI/Roles/ICustomRole.cs b/MiraAPI/Roles/ICustomRole.cs
index 3087dbe..9fc2b61 100644
--- a/MiraAPI/Roles/ICustomRole.cs
+++ b/MiraAPI/Roles/ICustomRole.cs
@@ -77,6 +77,11 @@ public interface ICustomRole
///
bool CanUseVent => Team == ModdedRoleTeams.Impostor;
+ ///
+ /// Gets a value indicating whether the role can use the sabotage button.
+ ///
+ bool CanUseSabotage => Team == ModdedRoleTeams.Impostor;
+
///
/// Gets a value indicating whether the role's tasks count towards task progress.
///
From fa8fdfc4f66fba2cec46b8135214f6183a2228e2 Mon Sep 17 00:00:00 2001
From: ang-xd
Date: Wed, 4 Sep 2024 17:30:08 -0400
Subject: [PATCH 32/36] Create ChameleonRole.cs
---
MiraAPI.Example/Roles/ChameleonRole.cs | 46 ++++++++++++++++++++++++++
1 file changed, 46 insertions(+)
create mode 100644 MiraAPI.Example/Roles/ChameleonRole.cs
diff --git a/MiraAPI.Example/Roles/ChameleonRole.cs b/MiraAPI.Example/Roles/ChameleonRole.cs
new file mode 100644
index 0000000..4c10d55
--- /dev/null
+++ b/MiraAPI.Example/Roles/ChameleonRole.cs
@@ -0,0 +1,46 @@
+using MiraAPI.Roles;
+using MiraAPI.Utilities.Assets;
+using TMPro;
+using UnityEngine;
+
+namespace MiraAPI.Example.Roles;
+
+[RegisterCustomRole]
+public class ChameloenRole : CrewmateRole, ICustomRole
+{
+ public string RoleName => "Chamelon";
+ public string RoleLongDescription => "Stay invisible while not moving.";
+ public string RoleDescription => RoleLongDescription;
+ public Color RoleColor => Palette.AcceptedGreen;
+ public ModdedRoleTeams Team => ModdedRoleTeams.Crewmate;
+ public LoadableAsset OptionsScreenshot => ExampleAssets.Banner;
+ public int MaxPlayers => 2;
+
+ public void PlayerControlFixedUpdate(PlayerControl playerControl)
+ {
+ if (playerControl.MyPhysics.Velocity.magnitude > 0)
+ {
+ SpriteRenderer rend = playerControl.cosmetics.currentBodySprite.BodySprite;
+ TextMeshPro tmp = playerControl.cosmetics.nameText;
+ tmp.color = Color.Lerp(tmp.color, new Color(tmp.color.r, tmp.color.g, tmp.color.b, 1), Time.deltaTime * 4f);
+ rend.color = Color.Lerp(rend.color, new Color(1, 1, 1, 1), Time.deltaTime * 4f);
+
+ foreach (var cosmetic in playerControl.cosmetics.transform.GetComponentsInChildren())
+ {
+ cosmetic.color = Color.Lerp(cosmetic.color, new Color(1, 1, 1, 1), Time.deltaTime * 4f);
+ }
+ }
+ else
+ {
+ SpriteRenderer rend = playerControl.cosmetics.currentBodySprite.BodySprite;
+ TextMeshPro tmp = playerControl.cosmetics.nameText;
+ tmp.color = Color.Lerp(tmp.color, new Color(tmp.color.r, tmp.color.g, tmp.color.b, playerControl.AmOwner ? 0.3f : 0), Time.deltaTime * 4f);
+ rend.color = Color.Lerp(rend.color, new Color(1, 1, 1, playerControl.AmOwner ? 0.3f : 0), Time.deltaTime * 4f);
+
+ foreach (var cosmetic in playerControl.cosmetics.transform.GetComponentsInChildren())
+ {
+ cosmetic.color = Color.Lerp(cosmetic.color, new Color(1, 1, 1, playerControl.AmOwner ? 0.3f : 0), Time.deltaTime * 4f);
+ }
+ }
+ }
+}
\ No newline at end of file
From 17da5942070497ad37824db9ae81aa53e9063c48 Mon Sep 17 00:00:00 2001
From: XtraCube <72575280+XtraCube@users.noreply.github.com>
Date: Wed, 4 Sep 2024 18:34:36 -0400
Subject: [PATCH 33/36] fix notif popper issue
---
MiraAPI/Patches/Options/NotificationPopperPatch.cs | 12 +++++++-----
1 file changed, 7 insertions(+), 5 deletions(-)
diff --git a/MiraAPI/Patches/Options/NotificationPopperPatch.cs b/MiraAPI/Patches/Options/NotificationPopperPatch.cs
index d13b854..fa78e8c 100644
--- a/MiraAPI/Patches/Options/NotificationPopperPatch.cs
+++ b/MiraAPI/Patches/Options/NotificationPopperPatch.cs
@@ -18,7 +18,7 @@ public static bool RoleChangeMsgPatch(
[HarmonyArgument(3)] RoleTeamTypes teamType,
[HarmonyArgument(4)] bool playSound)
{
- if (CustomRoleManager.CustomRoles.Values.All(role => role.StringName != key))
+ if (CustomRoleManager.CustomRoles.Values.FirstOrDefault(x=>x.StringName==key) is not ICustomRole customRole)
{
return true;
}
@@ -29,10 +29,12 @@ public static bool RoleChangeMsgPatch(
var item = DestroyableSingleton.Instance.GetString(
StringNames.LobbyChangeSettingNotificationRole,
- "",
- text,
- DestroyableSingleton.Instance.GetString(key, Array.Empty()),
- "",
+ string.Concat(
+ "",
+ text,
+ DestroyableSingleton.Instance.GetString(key, Array.Empty()),
+ ""
+ ),
"" + roleCount + "",
"" + roleChance + "%"
);
From 7f65f2d5bb7340eda7a993e625e913bf0f3a6740 Mon Sep 17 00:00:00 2001
From: XtraCube <72575280+XtraCube@users.noreply.github.com>
Date: Wed, 4 Sep 2024 18:34:45 -0400
Subject: [PATCH 34/36] remove warning from example build
---
MiraAPI.Example/Roles/ChameleonRole.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/MiraAPI.Example/Roles/ChameleonRole.cs b/MiraAPI.Example/Roles/ChameleonRole.cs
index 4c10d55..a7d5a5d 100644
--- a/MiraAPI.Example/Roles/ChameleonRole.cs
+++ b/MiraAPI.Example/Roles/ChameleonRole.cs
@@ -43,4 +43,4 @@ public void PlayerControlFixedUpdate(PlayerControl playerControl)
}
}
}
-}
\ No newline at end of file
+}
From b2651adcabe6ca31c5bcc00b95694f91c3134703 Mon Sep 17 00:00:00 2001
From: XtraCube <72575280+XtraCube@users.noreply.github.com>
Date: Thu, 5 Sep 2024 07:18:20 -0400
Subject: [PATCH 35/36] adjustments
---
MiraAPI/Patches/HudManagerPatches.cs | 34 -----------
MiraAPI/Patches/Roles/HudManagerPatches.cs | 3 +-
MiraAPI/Patches/Roles/SabotageButtonPatch.cs | 62 ++++++++++++++++++++
3 files changed, 64 insertions(+), 35 deletions(-)
create mode 100644 MiraAPI/Patches/Roles/SabotageButtonPatch.cs
diff --git a/MiraAPI/Patches/HudManagerPatches.cs b/MiraAPI/Patches/HudManagerPatches.cs
index ddd31f8..50e248b 100644
--- a/MiraAPI/Patches/HudManagerPatches.cs
+++ b/MiraAPI/Patches/HudManagerPatches.cs
@@ -93,44 +93,10 @@ public static void SetHudActivePostfix(HudManager __instance, PlayerControl loca
{
return;
}
- if (CustomRoleManager.GetCustomRoleBehaviour(role.Role, out var customRole))
- {
- if (customRole.CanUseSabotage)
- {
- __instance.SabotageButton.gameObject.SetActive(true);
- }
- else
- {
- __instance.SabotageButton.gameObject.SetActive(role.IsImpostor && isActive);
- }
- }
foreach (var button in CustomButtonManager.CustomButtons)
{
button.SetActive(isActive, role);
}
}
-
- ///
- /// Patches the Sabotage button to check if the player's custom role can use sabotage.
- ///
- [HarmonyPatch(typeof(SabotageButton), nameof(SabotageButton.DoClick))]
- [HarmonyPrefix]
- public static bool StartPrefix(SabotageButton __instance)
- {
-
- var player = PlayerControl.LocalPlayer;
-
- if (CustomRoleManager.GetCustomRoleBehaviour(player.Data.Role.Role, out var customRole))
- {
- if (!customRole.CanUseSabotage) return false;
-
- DestroyableSingleton.Instance.ToggleMapVisible(new MapOptions()
- {
- Mode = MapOptions.Modes.Sabotage
- });
- return false;
- }
- return true;
- }
}
diff --git a/MiraAPI/Patches/Roles/HudManagerPatches.cs b/MiraAPI/Patches/Roles/HudManagerPatches.cs
index 34f0bb9..f833651 100644
--- a/MiraAPI/Patches/Roles/HudManagerPatches.cs
+++ b/MiraAPI/Patches/Roles/HudManagerPatches.cs
@@ -27,10 +27,11 @@ public static void SetHudActivePostfix(
{
var flag = localPlayer.Data != null && localPlayer.Data.IsDead;
- if (role is ICustomRole)
+ if (role is ICustomRole customRole)
{
__instance.KillButton.ToggleVisible(isActive && role.CanUseKillButton && !flag);
__instance.ImpostorVentButton.ToggleVisible(isActive && role.CanVent && !flag);
+ __instance.SabotageButton.gameObject.SetActive(isActive && customRole.CanUseSabotage);
}
if (_roleTab)
diff --git a/MiraAPI/Patches/Roles/SabotageButtonPatch.cs b/MiraAPI/Patches/Roles/SabotageButtonPatch.cs
new file mode 100644
index 0000000..49c5190
--- /dev/null
+++ b/MiraAPI/Patches/Roles/SabotageButtonPatch.cs
@@ -0,0 +1,62 @@
+using HarmonyLib;
+using MiraAPI.Roles;
+
+namespace MiraAPI.Patches.Roles;
+
+[HarmonyPatch(typeof(SabotageButton))]
+public class SabotageButtonPatch
+{
+ ///
+ /// Patches the Sabotage button to check if the player's custom role can use sabotage.
+ ///
+ [HarmonyPatch(nameof(SabotageButton.DoClick))]
+ [HarmonyPrefix]
+ public static bool DoClickPrefix(SabotageButton __instance)
+ {
+ var player = PlayerControl.LocalPlayer;
+
+ if (player.Data.Role is not ICustomRole customRole)
+ {
+ return true;
+ }
+
+ if (!customRole.CanUseSabotage || PlayerControl.LocalPlayer.inVent || !GameManager.Instance.SabotagesEnabled())
+ {
+ return false;
+ }
+
+ DestroyableSingleton.Instance.ToggleMapVisible(
+ new MapOptions
+ {
+ Mode = MapOptions.Modes.Sabotage,
+ });
+ return false;
+ }
+
+ [HarmonyPrefix]
+ [HarmonyPatch(nameof(SabotageButton.Refresh))]
+ public static bool RefreshPrefix(SabotageButton __instance)
+ {
+ var player = PlayerControl.LocalPlayer;
+ if (GameManager.Instance == null || player == null)
+ {
+ __instance.ToggleVisible(false);
+ __instance.SetDisabled();
+ return false;
+ }
+
+ if (player.Data.Role is not ICustomRole customRole)
+ {
+ return true;
+ }
+
+ if (player.inVent || !GameManager.Instance.SabotagesEnabled() || player.petting)
+ {
+ __instance.ToggleVisible(customRole.CanUseSabotage && GameManager.Instance.SabotagesEnabled());
+ __instance.SetDisabled();
+ return false;
+ }
+ __instance.SetEnabled();
+ return false;
+ }
+}
From 400ad535a4fce6ac3c44f28a009c8ab49511f5a4 Mon Sep 17 00:00:00 2001
From: XtraCube <72575280+XtraCube@users.noreply.github.com>
Date: Thu, 5 Sep 2024 18:09:50 -0400
Subject: [PATCH 36/36] bump version
---
Directory.Build.props | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Directory.Build.props b/Directory.Build.props
index 2431ce4..974f974 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -8,7 +8,7 @@
true
- 0.1.4
+ 0.1.5
dev
All Of Us, XtraCube, Angxl