Merge branch 'refs/heads/dev' into fork/Rubyboat1207/audio-resource

This commit is contained in:
XtraCube committed 2024-09-03 21:02:00 -04:00
commit 3deffb701f
79 files changed
+1341 -869

No files matched your search

+2
View File
@@ -0,0 +1,2 @@
[*.{cs,vb}]
dotnet_diagnostic.CA1707.severity = none
@@ -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<PlayerControl>
{
public override string Name => "Freeze";
public override float Cooldown => 5f;
public override float Cooldown => OptionGroupSingleton<FreezerRoleSettings>.Instance.FreezeDuration;
public override float EffectDuration => 0f;
public override int MaxUses => 0;
public override int MaxUses => (int)OptionGroupSingleton<FreezerRoleSettings>.Instance.FreezeUses;
public override LoadableAsset<Sprite> Sprite => ExampleAssets.ExampleButton;
protected override void OnClick()
@@ -23,7 +25,7 @@ public class FreezeButton : CustomActionButton<PlayerControl>
public override PlayerControl? GetTarget()
{
return PlayerControl.LocalPlayer.GetClosestPlayer(true, Distance, false);
return PlayerControl.LocalPlayer.GetClosestPlayer(true, Distance);
}
public override void SetOutline(bool active)
@@ -13,7 +13,7 @@ public class TeleportButton : CustomActionButton
{
public override string Name => "Teleport";
public override float Cooldown => OptionGroupSingleton<TeleporterOptions>.Instance.TeleportCooldown;
public override float Cooldown => OptionGroupSingleton<TeleporterOptions>.Instance.TeleportCooldown.Value;
public override float EffectDuration => OptionGroupSingleton<TeleporterOptions>.Instance.TeleportDuration;
@@ -22,7 +22,7 @@ public class TeleportButton : CustomActionButton
public override LoadableAsset<Sprite> 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;
}
+2 -2
View File
@@ -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");
}
}
+3 -3
View File
@@ -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));
}
}
+11 -13
View File
@@ -1,23 +1,21 @@
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;
[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"))
[HideFromIl2Cpp]
public DragWindow DebuggingWindow { get; } = new(
new Rect(10, 10, 0, 0),
"MIRA API DEBUGGING",
() =>
{
//PlayerControl.LocalPlayer.AddModifier<ModifierTimerExample>();
}
if (GUILayout.Button("Remove modifier"))
{
//PlayerControl.LocalPlayer.RemoveModifier<ModifierTimerExample>();
}
})
})
{
Enabled = true,
};
@@ -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)
@@ -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;
}
@@ -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;
}
@@ -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;
@@ -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 UseVanillaKillButton => 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);
}
}
+9 -9
View File
@@ -6,12 +6,12 @@ using System.Linq;
namespace MiraAPI.GameModes;
/// <summary>
/// Manages custom gamemodes
/// Manages custom gamemodes.
/// </summary>
public static class CustomGameModeManager
{
/// <summary>
/// List of registered gamemodes
/// List of registered gamemodes.
/// </summary>
internal static readonly Dictionary<int, CustomGameMode> GameModes = [];
@@ -21,14 +21,14 @@ public static class CustomGameModeManager
}
/// <summary>
/// Current gamemode
/// Current gamemode.
/// </summary>
public static CustomGameMode? ActiveMode { get; internal set; } = new DefaultMode();
/// <summary>
/// Set current gamemode
/// Set current gamemode.
/// </summary>
/// <param name="id">gamemode ID</param>
/// <param name="id">gamemode ID.</param>
public static void SetGameMode(int id)
{
if (GameModes.TryGetValue(id, out var gameMode))
@@ -41,9 +41,9 @@ public static class CustomGameModeManager
}
/// <summary>
/// Register gamemode from type
/// Register gamemode from type.
/// </summary>
/// <param name="gameModeType">Type of gamemode class, should inherit from <see cref="CustomGameMode"/></param>
/// <param name="gameModeType">Type of gamemode class, should inherit from <see cref="CustomGameMode"/>.</param>
internal static void RegisterGameMode(Type gameModeType)
{
if (!typeof(CustomGameMode).IsAssignableFrom(gameModeType))
@@ -59,7 +59,7 @@ public static class CustomGameModeManager
Logger<MiraApiPlugin>.Error($"Failed to create instance of {gameModeType.Name}");
return;
}
if (GameModes.Any(x => x.Key == gameMode.Id))
{
Logger<MiraApiPlugin>.Error($"ID for gamemode {gameMode.Name} already exists!");
@@ -68,4 +68,4 @@ public static class CustomGameModeManager
GameModes.Add(gameMode.Id, gameMode);
}
}
}
+1 -1
View File
@@ -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;
}
}
@@ -25,4 +25,4 @@ public class RegisterGameModeAttribute : Attribute
}
}
}
}
}
@@ -26,6 +26,12 @@ public abstract class AbstractOptionGroup
/// </summary>
public virtual Color GroupColor => Color.clear;
/// <summary>
/// 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.
/// </summary>
public virtual uint GroupPriority => uint.MaxValue;
/// <summary>
/// Gets the role the group is associated with. This is used for the advanced role options menu.
/// </summary>
+1 -1
View File
@@ -17,7 +17,7 @@ internal interface IModdedOption
OptionBehaviour? OptionBehaviour { get; }
Func<bool> 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);
+3 -3
View File
@@ -18,10 +18,10 @@ namespace MiraAPI.GameOptions;
/// </summary>
public static class ModdedOptionsManager
{
private static readonly Dictionary<PropertyInfo, ModdedOptionAttribute> OptionAttributes = new();
private static readonly Dictionary<Type, AbstractOptionGroup> TypeToGroup = new();
private static readonly Dictionary<PropertyInfo, ModdedOptionAttribute> OptionAttributes = [];
private static readonly Dictionary<Type, AbstractOptionGroup> TypeToGroup = [];
internal static readonly Dictionary<uint, IModdedOption> ModdedOptions = new();
internal static readonly Dictionary<uint, IModdedOption> ModdedOptions = [];
internal static readonly List<AbstractOptionGroup> Groups = [];
internal static uint NextId => _nextId++;
+4 -4
View File
@@ -1,5 +1,4 @@
using System;
using System.Linq;
using System.Linq;
namespace MiraAPI.GameOptions;
@@ -7,13 +6,14 @@ namespace MiraAPI.GameOptions;
/// Singleton for option groups.
/// </summary>
/// <typeparam name="T">The option group type.</typeparam>
public class OptionGroupSingleton<T> where T : AbstractOptionGroup
public static class OptionGroupSingleton<T> where T : AbstractOptionGroup
{
private static T? _instance;
/// <summary>
/// Gets the instance of the option group.
/// </summary>
/// <exception cref="InvalidOperationException">Can't</exception>
#pragma warning disable CA1000
public static T Instance => _instance ??= ModdedOptionsManager.Groups.OfType<T>().Single();
#pragma warning restore CA1000
}
@@ -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;
+2
View File
@@ -13,5 +13,7 @@ public static class CustomButtonSingleton<T> where T : CustomActionButton
/// <summary>
/// Gets the instance of the button.
/// </summary>
#pragma warning disable CA1000
public static T Instance => _instance ??= CustomButtonManager.CustomButtons.OfType<T>().Single();
#pragma warning restore CA1000
}
+1 -1
View File
@@ -6,4 +6,4 @@ namespace MiraAPI.Hud;
/// Attribute to register a button in the HUD. Necessary for the button to be recognized by Mira.
/// </summary>
[AttributeUsage(AttributeTargets.Class)]
public class RegisterButtonAttribute : Attribute;
public class RegisterButtonAttribute : Attribute;
+3 -3
View File
@@ -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()
{
+7 -1
View File
@@ -10,6 +10,11 @@ public abstract class BaseModifier
/// </summary>
public PlayerControl? Player { get; internal set; }
/// <summary>
/// Gets the modifier component that the modifier is attached to.
/// </summary>
public ModifierComponent? ModifierComponent { get; internal set; }
/// <summary>
/// Gets the modifier id.
/// </summary>
@@ -62,7 +67,8 @@ public abstract class BaseModifier
/// <summary>
/// Called when the player dies.
/// </summary>
public virtual void OnDeath()
/// <param name="reason">The Death Reason.</param>
public virtual void OnDeath(DeathReason reason)
{
}
+2 -1
View File
@@ -18,7 +18,7 @@ namespace MiraAPI.Modifiers;
/// The component for handling modifiers.
/// </summary>
[RegisterInIl2Cpp]
public class ModifierComponent(IntPtr ptr) : MonoBehaviour(ptr)
public class ModifierComponent(IntPtr cppPtr) : MonoBehaviour(cppPtr)
{
/// <summary>
/// Gets the active modifiers on the player.
@@ -213,6 +213,7 @@ public class ModifierComponent(IntPtr ptr) : MonoBehaviour(ptr)
_toAdd.Add(modifier);
modifier.Player = _player;
modifier.ModifierComponent = this;
modifier.ModifierId = modifierId.Value;
return modifier;
}
@@ -2,5 +2,8 @@
namespace MiraAPI.Modifiers;
/// <summary>
/// Marks a class as a modifier that can be registered with the <see cref="ModifierManager"/>.
/// </summary>
[AttributeUsage(AttributeTargets.Class)]
public class RegisterModifierAttribute : Attribute;
public class RegisterModifierAttribute : Attribute;
+1 -2
View File
@@ -1,5 +1,4 @@
using System;
using MiraAPI.Utilities;
using Reactor.Utilities;
using UnityEngine;
@@ -71,7 +70,7 @@ public abstract class TimedModifier : BaseModifier
if (RemoveOnComplete)
{
Player?.RpcRemoveModifier(ModifierId);
ModifierComponent?.RemoveModifier(ModifierId);
}
}
}
+271
View File
@@ -0,0 +1,271 @@
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 UnityEngine;
namespace MiraAPI.Networking;
/// <summary>
/// Custom murder RPCs to fix issues with default ones.
/// </summary>
public static class CustomMurderRpc
{
/// <summary>
/// Networked Custom Murder method.
/// </summary>
/// <param name="source">The killer.</param>
/// <param name="target">The player to murder.</param>
/// <param name="didSucceed">Whether the murder was successful or not.</param>
/// <param name="resetKillTimer">Should the kill timer be reset.</param>
/// <param name="createDeadBody">Should a dead body be created.</param>
/// <param name="teleportMurderer">Should the killer be snapped to the dead player.</param>
/// <param name="showKillAnim">Should the kill animation be shown.</param>
/// <param name="playKillSound">Should the kill sound be played.</param>
[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);
}
/// <summary>
/// Custom Murder method without networking. If you need a networked version, use <see cref="RpcCustomMurder"/>.
/// </summary>
/// <param name="source">The killer.</param>
/// <param name="target">The player to murder.</param>
/// <param name="resultFlags">Murder result flags.</param>
/// <param name="resetKillTimer">Should the kill timer be reset.</param>
/// <param name="createDeadBody">Should a dead body be created.</param>
/// <param name="teleportMurderer">Should the killer be snapped to the dead player.</param>
/// <param name="showKillAnim">Should the kill animation be shown.</param>
/// <param name="playKillSound">Should the kill sound be played.</param>
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<MiraApiPlugin>.Error($"{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<AchievementManager>.Instance.OnProtectACrewmate();
}
if (source.AmOwner || flag)
{
target.ShowFailedMurder();
if (resetKillTimer)
{
source.SetKillTimer(
GameOptionsManager.Instance.CurrentGameOptions.GetFloat(FloatOptionNames.KillCooldown) / 2f);
}
}
else
{
target.RemoveProtection();
}
Logger<MiraApiPlugin>.Error($"{source.PlayerId} failed to murder {target.PlayerId} due to guardian angel protection");
return;
}
if (!resultFlags.HasFlag(MurderResultFlags.Succeeded) &&
!resultFlags.HasFlag(MurderResultFlags.DecisionByHost))
{
return;
}
DestroyableSingleton<DebugAnalytics>.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<UnityTelemetry>.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<HudManager>.Instance.KillOverlay.ShowKillAnimation(source.Data, data);
}
target.cosmetics.SetNameMask(false);
target.RpcSetScanner(false);
}
DestroyableSingleton<AchievementManager>.Instance.OnMurder(
source.AmOwner,
target.AmOwner,
source.CurrentOutfitType == PlayerOutfitType.Shapeshifted,
source.shapeshiftTargetPlayerId,
target.PlayerId);
source.MyPhysics.StartCoroutine(source.KillAnimations.Random()?.CoPerformCustomKill(source, target, createDeadBody, teleportMurderer));
Logger<MiraApiPlugin>.Error($"{source.PlayerId} succeeded in murdering {target.PlayerId}");
}
/// <summary>
/// Perform a custom kill animation.
/// </summary>
/// <param name="anim">The kill animation.</param>
/// <param name="source">The murderer.</param>
/// <param name="target">The murdered player.</param>
/// <param name="createDeadBody">Should a dead body be created.</param>
/// <param name="teleportMurderer">Should the murder be teleported.</param>
/// <returns>Coroutine.</returns>
public static IEnumerator CoPerformCustomKill(
this KillAnimation anim,
PlayerControl source,
PlayerControl target,
bool createDeadBody = true,
bool teleportMurderer = true)
{
var cam = Camera.main?.GetComponent<FollowerCamera>();
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 = false;
}
PlayerControl.LocalPlayer.isKilling = false;
source.isKilling = false;
}
}
-186
View File
@@ -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<AchievementManager>.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<DebugAnalytics>.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<UnityTelemetry>.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<HudManager>.Instance.KillOverlay.ShowKillAnimation(source.Data, data);
}
target.cosmetics.SetNameMask(false);
target.RpcSetScanner(false);
}
DestroyableSingleton<AchievementManager>.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<FollowerCamera>();
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;
}
}
+27 -1
View File
@@ -1,11 +1,37 @@
namespace MiraAPI.Networking;
/// <summary>
/// Mira RPCs.
/// </summary>
public enum MiraRpc : uint
{
/// <summary>
/// Syncs the game options.
/// </summary>
SyncGameOptions,
/// <summary>
/// Syncs the role options.
/// </summary>
SyncRoleOptions,
/// <summary>
/// Adds a modifier to a player.
/// </summary>
AddModifier,
/// <summary>
/// Removes a modifier from a player.
/// </summary>
RemoveModifier,
/// <summary>
/// Syncs all modifiers at once.
/// </summary>
SyncModifiers,
/// <summary>
/// Custom Murder RPC.
/// </summary>
CustomMurder,
}
}
+18 -1
View File
@@ -1,8 +1,25 @@
namespace MiraAPI.Networking;
/// <summary>
/// Used to network data and mark it with an ID.
/// </summary>
/// <param name="id">The ID of the data.</param>
/// <param name="data">The byte[] data.</param>
public readonly struct NetData(uint id, byte[] data)
{
/// <summary>
/// Gets the ID of the data.
/// </summary>
public uint Id { get; } = id;
/// <summary>
/// Gets the byte[] data.
/// </summary>
public byte[] Data { get; } = data;
/// <summary>
/// Gets the length of the data in bytes.
/// </summary>
/// <returns>An int representing the number of bytes this NetData takes up.</returns>
public int GetLength() => 4 + Data.Length;
}
}
+13 -7
View File
@@ -6,12 +6,18 @@ using Reactor.Networking.Rpc;
namespace MiraAPI.Networking;
[RegisterCustomRpc((uint)MiraRpc.SyncModifiers)]
internal class SyncModifiersRpc(MiraApiPlugin plugin, uint id) : PlayerCustomRpc<MiraApiPlugin, NetData[]>(plugin, id)
internal sealed class SyncModifiersRpc(MiraApiPlugin plugin, uint id) : PlayerCustomRpc<MiraApiPlugin, NetData[]>(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)
{
@@ -26,21 +32,21 @@ internal class SyncModifiersRpc(MiraApiPlugin plugin, uint id) : PlayerCustomRpc
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 ?? []);
}
}
}
+14 -8
View File
@@ -7,12 +7,18 @@ 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<MiraApiPlugin, NetData[]>(plugin, id)
internal sealed class SyncOptionsRpc(MiraApiPlugin plugin, uint id) : PlayerCustomRpc<MiraApiPlugin, NetData[]>(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 @@ internal class SyncOptionsRpc(MiraApiPlugin plugin, uint id) : PlayerCustomRpc<M
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 ?? []);
}
}
}
+13 -8
View File
@@ -6,13 +6,18 @@ using Reactor.Networking.Rpc;
namespace MiraAPI.Networking;
[RegisterCustomRpc((uint)MiraRpc.SyncRoleOptions)]
internal class SyncRoleOptionsRpc(MiraApiPlugin plugin, uint id) : PlayerCustomRpc<MiraApiPlugin, NetData[]>(plugin, id)
internal sealed class SyncRoleOptionsRpc(MiraApiPlugin plugin, uint id) : PlayerCustomRpc<MiraApiPlugin, NetData[]>(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 @@ internal class SyncRoleOptionsRpc(MiraApiPlugin plugin, uint id) : PlayerCustomR
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 ?? []);
}
}
}
+4 -1
View File
@@ -6,6 +6,9 @@ using MiraAPI.Roles;
namespace MiraAPI.Patches;
/// <summary>
/// Sync all options, role settings, and modifiers to the player when they join the game.
/// </summary>
[HarmonyPatch(typeof(AmongUsClient), nameof(AmongUsClient.CreatePlayer))]
public static class AmongUsClientSyncPatch
{
@@ -25,4 +28,4 @@ public static class AmongUsClientSyncPatch
CustomRoleManager.SyncAllRoleSettings(clientData.Id);
ModifierManager.SyncAllModifiers(clientData.Id);
}
}
}
@@ -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;
/// <summary>
/// Add scrolling to the colors tab
@@ -20,7 +20,7 @@ public static class ScrollingColorsPatch
{
return;
}
var tab = PlayerCustomizationMenu.Instance.Tabs[1].Tab;
if (__instance.scroller == null)
@@ -31,7 +31,7 @@ public static class ScrollingColorsPatch
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 class ScrollingColorsPatch
__instance.SetScrollerBounds();
}
}
}
+2 -3
View File
@@ -1,5 +1,4 @@
/*
/*
[HarmonyPatch]
public static class ConsolePatches
{
@@ -69,4 +68,4 @@ public static class ConsolePatches
canUse = couldUse = true;
return true;
}
}*/
}*/
+2 -4
View File
@@ -1,6 +1,4 @@
/*
/*
[HarmonyPatch(typeof(DeadBody))]
public static class DeadBodyPatch
{
@@ -10,4 +8,4 @@ public static class DeadBodyPatch
{
return CustomGameModeManager.ActiveMode == null || CustomGameModeManager.ActiveMode.CanReport(__instance);
}
}*/
}*/
@@ -1,6 +1,4 @@
/*
/*
[HarmonyPatch]
public static class GameLogicPatches
{
@@ -19,4 +17,4 @@ public static class GameLogicPatches
CustomGameModeManager.ActiveMode?.AssignRoles(out runOriginal, __instance);
return runOriginal;
}
}*/
}*/
@@ -1,6 +1,4 @@
/*
/*
/// <summary>
/// Allow Impostors to kill each other if can kill is enabled in gamemode or friendly fire is toggled on
/// </summary>
@@ -16,11 +14,11 @@ public static class ImpostorTargetPatch
{
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;
}
}*/
}*/
@@ -1,6 +1,4 @@
/*
/*
[HarmonyPatch(typeof(MapBehaviour))]
public static class MapBehaviourPatch
{
@@ -17,4 +15,4 @@ public static class MapBehaviourPatch
return true;
}
}*/
}*/
+2 -4
View File
@@ -1,6 +1,4 @@
/*
/*
[HarmonyPatch(typeof(KillAnimation))]
public static class OnDeathPatch
{
@@ -10,4 +8,4 @@ public static class OnDeathPatch
{
CustomGameModeManager.ActiveMode?.OnDeath(target);
}
}*/
}*/
+2 -6
View File
@@ -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 class VentPatches
return false;
}
}*/
}*/
@@ -1,20 +1,20 @@
using HarmonyLib;
using MiraAPI.Hud;
namespace MiraAPI.Patches;
namespace MiraAPI.Patches.Hud;
/// <summary>
/// Harmony patches for the MeetingHud class.
/// Reset button patches
/// </summary>
[HarmonyPatch(typeof(MeetingHud))]
public static class MeetingHudPatches
[HarmonyPatch]
public static class ButtonResetPatches
{
/// <summary>
/// Resets the cooldown and effect of all custom buttons when the meeting starts.
/// </summary>
[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 class MeetingHudPatches
}
/// <summary>
/// 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.
/// </summary>
[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)
{
+1 -69
View File
@@ -1,7 +1,5 @@
using HarmonyLib;
using InnerNet;
using MiraAPI.Hud;
using MiraAPI.Roles;
using Reactor.Utilities.Extensions;
using UnityEngine;
using Object = UnityEngine.Object;
@@ -17,62 +15,6 @@ public static class HudManagerPatches
// Custom buttons parent.
private static GameObject? _bottomLeft;
// Custom role tab.
private static TaskPanelBehaviour? _roleTab;
/// <summary>
/// Update custom role tab and custom role hud elements.
/// </summary>
/// <param name="__instance">The HudManager instance.</param>
[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;
}
}
/*
/// <summary>
/// Trigger hudstart on current custom gamemode
@@ -136,7 +78,7 @@ public static class HudManagerPatches
}
/// <summary>
/// Set the custom role tab and custom buttons active when the hud is active.
/// Set the custom buttons active when the hud is active.
/// </summary>
/// <param name="__instance">HudManager instance.</param>
/// <param name="localPlayer">The local PlayerControl.</param>
@@ -151,19 +93,9 @@ public static class HudManagerPatches
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);
}
}
}
+27 -22
View File
@@ -19,33 +19,38 @@ public static class IntroCutscenePatches
__instance.TeamTitle.text = $"<size=70%>{mode.Name}</size>\n<size=20%>{mode.Description}</size>";
}
}*/
[HarmonyPrefix]
[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 = "OUTCAST";
__instance.impostorScale = 1f;
__instance.ImpostorText.text = "You are an Outcast. 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 class IntroCutscenePatches
{
CustomGameModeManager.ActiveMode?.Initialize();
}*/
}
}
+3 -4
View File
@@ -1,6 +1,5 @@
using HarmonyLib;
using MiraAPI.Utilities;
using System.Linq;
using UnityEngine;
namespace MiraAPI.Patches.Modifiers;
@@ -23,10 +22,10 @@ public static class VentPatches
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;
}
@@ -43,4 +42,4 @@ public static class VentPatches
}
__result = num;
}
}
}
+40 -18
View File
@@ -30,12 +30,14 @@ public static class GameOptionsMenuPatch
}
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 class GameOptionsMenuPatch
{
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 class GameOptionsMenuPatch
}
__instance.scrollBar.SetYBoundsMax(-num - 1.65f);
}
[HarmonyPrefix]
@@ -84,11 +90,15 @@ public static class GameOptionsMenuPatch
__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,17 +106,24 @@ public static class GameOptionsMenuPatch
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;
var newText = Object.Instantiate(categoryHeaderMasked.Title, categoryHeaderMasked.transform);
newText.text = $"<size=70%>(Click to open)</size>";
newText.text = "<size=70%>(Click to close)</size>";
newText.transform.localPosition = new Vector3(2.6249f, -0.165f, 0f);
newText.gameObject.GetComponent<TextTranslatorTMP>().Destroy();
var options = group.Options.Select(opt => opt.CreateOption(__instance.checkboxOrigin,
__instance.numberOptionOrigin, __instance.stringOptionOrigin, __instance.settingsContainer));
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 class GameOptionsMenuPatch
if (newOpt is ToggleOption toggle)
{
toggle.CheckMark.sprite = MiraAssets.Checkmark.LoadAsset();
toggle.CheckMark.color = group.GroupColor != Color.clear ? group.GroupColor : MiraAssets.AcceptedTeal;
var rend = toggle.CheckMark.transform.parent.FindChild("ActiveSprite").GetComponent<SpriteRenderer>();
toggle.CheckMark.color =
group.GroupColor != Color.clear ? group.GroupColor : MiraAssets.AcceptedTeal;
var rend = toggle.CheckMark.transform.parent.FindChild("ActiveSprite")
.GetComponent<SpriteRenderer>();
rend.sprite = MiraAssets.CheckmarkBox.LoadAsset();
rend.color = group.GroupColor != Color.clear ? group.GroupColor : MiraAssets.AcceptedTeal;
}
@@ -162,11 +181,14 @@ public static class GameOptionsMenuPatch
headerBtn.ClickSound = __instance.BackButton.GetComponent<PassiveButton>().ClickSound;
headerBtn.OnMouseOver = new UnityEvent();
headerBtn.OnMouseOut = new UnityEvent();
headerBtn.OnClick.AddListener((UnityAction)(() =>
{
group.AllOptionsHidden = !group.AllOptionsHidden;
newText.text = group.AllOptionsHidden ? "<size=70%>(Click to open)</size>" : "<size=70%>(Click to close)</size>";
}));
headerBtn.OnClick.AddListener(
(UnityAction)(() =>
{
group.AllOptionsHidden = !group.AllOptionsHidden;
newText.text = group.AllOptionsHidden
? "<size=70%>(Click to open)</size>"
: "<size=70%>(Click to close)</size>";
}));
headerBtn.SetButtonEnableState(true);
}
@@ -207,4 +229,4 @@ public static class GameOptionsMenuPatch
return false;
}
}
}
@@ -154,7 +154,6 @@ public static class GameSettingMenuPatches
}
roles.roleChances.Clear();
roles.roleChances = null;
roles.AdvancedRolesSettings.gameObject.SetActive(false);
roles.RoleChancesSettings.gameObject.SetActive(true);
roles.SetQuotaTab();
+169 -127
View File
@@ -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 class LobbyViewPanePatches
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<SpriteRenderer>();
normal.transform.localPosition = new Vector3(0, 0f, 0.3f);
normal.sprite = MiraAssets.NextButton.LoadAsset();
var hover = nextButton.transform.FindChild("Hover").GetComponentInChildren<SpriteRenderer>();
hover.transform.localPosition = new Vector3(0, 0f, 0.3f);
hover.sprite = MiraAssets.NextButtonActive.LoadAsset();
var passiveButton = nextButton.gameObject.GetComponent<PassiveButton>();
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<SpriteRenderer>().flipX
= backButton.transform.FindChild("Hover").gameObject.GetComponentInChildren<SpriteRenderer>().flipX
= backButton.transform.FindChild("Hover").gameObject.GetComponentInChildren<SpriteRenderer>().flipX
= true;
var passiveButton2 = backButton.gameObject.GetComponent<PassiveButton>();
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 @@ public static class LobbyViewPanePatches
{
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 @@ public static class LobbyViewPanePatches
{
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 @@ public static class LobbyViewPanePatches
{
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 @@ public static class LobbyViewPanePatches
{
return;
}
var num = 0.95f;
var num2 = -6.53f;
var categoryHeaderMasked =
@@ -197,7 +218,7 @@ public static class LobbyViewPanePatches
categoryHeaderMasked.transform.localScale = Vector3.one;
categoryHeaderMasked.transform.localPosition = new Vector3(-9.77f, 1.26f, -2f);
instance.settingsInfo.Add(categoryHeaderMasked.gameObject);
var list = new List<Type>();
foreach (var team in Enum.GetValues<ModdedRoleTeams>())
@@ -205,12 +226,12 @@ public static class LobbyViewPanePatches
var filteredRoles = SelectedMod.CustomRoles.Values
.OfType<ICustomRole>()
.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 @@ public static class LobbyViewPanePatches
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 @@ public static class LobbyViewPanePatches
{
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 @@ public static class LobbyViewPanePatches
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 @@ public static class LobbyViewPanePatches
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 (SelectedMod == null)
{
return 0;
}
if (role == null)
{
return 0;
}
var role = SelectedMod.CustomRoles.Values.FirstOrDefault(x => x.GetType() == roleType);
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 (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;
}
}
}
@@ -6,34 +6,38 @@ using System.Linq;
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))
if (CustomRoleManager.CustomRoles.Values.All(role => role.StringName != key))
{
var item = string.Empty;
var text = (teamType == RoleTeamTypes.Crewmate) ? Palette.CrewmateSettingChangeText.ToTextColor() : Palette.ImpostorRed.ToTextColor();
item = DestroyableSingleton<TranslationController>.Instance.GetString(StringNames.LobbyChangeSettingNotificationRole, new Object[]
{
string.Concat(
[
"<font=\"Barlow-Black SDF\" material=\"Barlow-Black Outline\">",
text,
DestroyableSingleton<TranslationController>.Instance.GetString(key, Array.Empty<Object>()),
"</color></font>"
]),
"<font=\"Barlow-Black SDF\" material=\"Barlow-Black Outline\">" + roleCount.ToString() + "</font>",
"<font=\"Barlow-Black SDF\" material=\"Barlow-Black Outline\">" + roleChance.ToString() + "%"
});
__instance.SettingsChangeMessageLogic(key, item, playSound);
return false;
return true;
}
return true;
var text = teamType == RoleTeamTypes.Crewmate
? Palette.CrewmateSettingChangeText.ToTextColor()
: Palette.ImpostorRed.ToTextColor();
var item = DestroyableSingleton<TranslationController>.Instance.GetString(
StringNames.LobbyChangeSettingNotificationRole,
"<font=\"Barlow-Black SDF\" material=\"Barlow-Black Outline\">",
text,
DestroyableSingleton<TranslationController>.Instance.GetString(key, Array.Empty<Object>()),
"</color></font>",
"<font=\"Barlow-Black SDF\" material=\"Barlow-Black Outline\">" + roleCount + "</font>",
"<font=\"Barlow-Black SDF\" material=\"Barlow-Black Outline\">" + roleChance + "%"
);
__instance.SettingsChangeMessageLogic(key, item, playSound);
return false;
}
}
}
+10 -5
View File
@@ -16,7 +16,8 @@ public static class OptionsPatches
return true;
}
__instance.TitleText.text = DestroyableSingleton<TranslationController>.Instance.GetString(__instance.Title, Array.Empty<Object>());
__instance.TitleText.text =
DestroyableSingleton<TranslationController>.Instance.GetString(__instance.Title, Array.Empty<Object>());
return false;
}
@@ -37,7 +38,8 @@ public static class OptionsPatches
return true;
}
__instance.TitleText.text = DestroyableSingleton<TranslationController>.Instance.GetString(__instance.Title, Array.Empty<Object>());
__instance.TitleText.text =
DestroyableSingleton<TranslationController>.Instance.GetString(__instance.Title, Array.Empty<Object>());
return false;
}
@@ -58,8 +60,11 @@ public static class OptionsPatches
return true;
}
__instance.TitleText.text = DestroyableSingleton<TranslationController>.Instance.GetString(__instance.Title, Array.Empty<Object>());
__instance.ValueText.text = DestroyableSingleton<TranslationController>.Instance.GetString(__instance.Values[__instance.Value], Array.Empty<Object>());
__instance.TitleText.text =
DestroyableSingleton<TranslationController>.Instance.GetString(__instance.Title, Array.Empty<Object>());
__instance.ValueText.text = DestroyableSingleton<TranslationController>.Instance.GetString(
__instance.Values[__instance.Value],
Array.Empty<Object>());
return false;
}
@@ -70,4 +75,4 @@ public static class OptionsPatches
{
return !__instance.IsCustom();
}
}
}
@@ -54,58 +54,72 @@ public static class RoleSettingMenuPatches
var num3 = 0;
var crewRoles = GameSettingMenuPatches.SelectedMod.CustomRoles.Values
var crewRoles = GameSettingMenuPatches.SelectedMod?.CustomRoles.Values
.OfType<ICustomRole>()
.Where(role => role.Team == ModdedRoleTeams.Crewmate && !role.HideSettings)
.ToList();
.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<ICustomRole>()
.Where(role => role.Team == ModdedRoleTeams.Impostor && !role.HideSettings)
.ToList();
.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<ICustomRole>()
.Where(role => role.Team == ModdedRoleTeams.Neutral && !role.HideSettings)
.ToList();
.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 class RoleSettingMenuPatches
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 @@ public static class RoleSettingMenuPatches
}
roleSetting.UpdateValuesAndText(GameOptionsManager.Instance.CurrentGameOptions.RoleOptions);
DestroyableSingleton<HudManager>.Instance.Notifier.AddRoleSettingsChangeMessage(roleSetting.Role.StringName, roleSetting.RoleMaxCount, roleSetting.RoleChance, roleSetting.Role.TeamType, false);
DestroyableSingleton<HudManager>.Instance.Notifier.AddRoleSettingsChangeMessage(
roleSetting.Role.StringName,
roleSetting.RoleMaxCount,
roleSetting.RoleChance,
roleSetting.Role.TeamType,
false);
if (AmongUsClient.Instance.AmHost)
{
Rpc<SyncRoleOptionsRpc>.Instance.Send(PlayerControl.LocalPlayer, [role.GetNetData()], true);
}
GameOptionsManager.Instance.GameHostOptions = GameOptionsManager.Instance.CurrentGameOptions;
}
@@ -181,7 +204,7 @@ public static class RoleSettingMenuPatches
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 @@ public static class RoleSettingMenuPatches
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 @@ public static class RoleSettingMenuPatches
{
renderer.material.SetInt(PlayerMaterial.MaskLayer, 20);
}
foreach (var textMeshPro in newOpt.GetComponentsInChildren<TextMeshPro>(true))
foreach (var fontMat in newOpt.GetComponentsInChildren<TextMeshPro>(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 @@ public static class RoleSettingMenuPatches
__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<MiraApiPlugin>.Error($"Role {role.NiceName} is not a custom role.");
return;
}
__instance.roleDescriptionText.text = customRole.RoleLongDescription;
__instance.roleTitleText.text = DestroyableSingleton<TranslationController>.Instance.GetString(role.StringName, new Il2CppReferenceArray<Il2CppSystem.Object>(0));
__instance.roleScreenshot.sprite = Sprite.Create(customRole.OptionsScreenshot.LoadAsset().texture, new Rect(0, 0, 370, 230), Vector2.one / 2, 100);
__instance.roleTitleText.text = DestroyableSingleton<TranslationController>.Instance.GetString(
role.StringName,
new Il2CppReferenceArray<Il2CppSystem.Object>(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 @@ public static class RoleSettingMenuPatches
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<MiraApiPlugin>.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 class RoleSettingMenuPatches
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 class RoleSettingMenuPatches
yPos += -0.43f;
}
}
}
}
+11 -20
View File
@@ -9,7 +9,7 @@ namespace MiraAPI.Patches.Options;
/// Patches for the various game settings.
/// </summary>
[HarmonyPatch]
public class SettingPatches
public static class SettingPatches
{
/// <summary>
/// Prefix for the <see cref="FloatGameSetting.GetValueString"/> method. Adds support for custom number suffixes.
@@ -25,33 +25,24 @@ public class SettingPatches
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 = "<b>∞</b>";
}
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<TranslationController>.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<TranslationController>.Instance.GetString(
StringNames.GameSecondsAbbrev,
(Il2CppSystem.Object[]) [value.ToString(__instance.FormatString, CultureInfo.InvariantCulture)]),
};
}
__result = result;
+2 -2
View File
@@ -32,13 +32,13 @@ public static class PlayerControlPatches
/// </summary>
[HarmonyPostfix]
[HarmonyPatch(nameof(PlayerControl.Die))]
public static void PlayerControlDiePostfix(PlayerControl __instance)
public static void PlayerControlDiePostfix(PlayerControl __instance, DeathReason reason)
{
var modifiersComponent = __instance.GetComponent<ModifierComponent>();
if (modifiersComponent)
{
modifiersComponent.ActiveModifiers.ForEach(x=>x.OnDeath());
modifiersComponent.ActiveModifiers.ForEach(x=>x.OnDeath(reason));
}
}
+7 -4
View File
@@ -3,15 +3,18 @@ using MiraAPI.Roles;
namespace MiraAPI.Patches.Roles;
/// <summary>
/// Patches for custom ejection messages.
/// </summary>
[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 class EjectionPatches
__instance.completeString = role.GetCustomEjectionMessage(__instance.initData.networkedPlayer);
}
}
}
@@ -0,0 +1,74 @@
using HarmonyLib;
using InnerNet;
using MiraAPI.Roles;
using Reactor.Utilities.Extensions;
namespace MiraAPI.Patches.Roles;
/// <summary>
/// HudManager patches for roles.
/// </summary>
[HarmonyPatch(typeof(HudManager))]
public static class HudManagerPatches
{
// Custom role tab.
private static TaskPanelBehaviour? _roleTab;
/// <summary>
/// Fixes Kill Button not showing for Neutral killing role.
/// </summary>
[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);
}
}
/// <summary>
/// Update custom role tab and custom role hud elements.
/// </summary>
[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();
}
}
}
@@ -0,0 +1,71 @@
using HarmonyLib;
using Il2CppSystem;
using MiraAPI.Networking;
using MiraAPI.Roles;
using UnityEngine;
namespace MiraAPI.Patches.Roles;
/// <summary>
/// Fix kill button issues for neutral killers.
/// </summary>
[HarmonyPatch(typeof(KillButton))]
public static class KillButtonPatches
{
/// <summary>
/// SetTarget for custom roles.
/// </summary>
[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>(Color.clear));
}
__instance.currentTarget = target;
if (__instance.currentTarget)
{
__instance.currentTarget.cosmetics.SetOutline(true, new Nullable<Color>(customRole.KillButtonOutlineColor));
__instance.SetEnabled();
return false;
}
__instance.SetDisabled();
return false;
}
/// <summary>
/// Use Custom Murder if player is custom role.
/// </summary>
[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;
}
}
+1 -1
View File
@@ -32,4 +32,4 @@ public static class NameTagPatch
return false;
}
}
}
@@ -22,4 +22,4 @@ public static class RoleBehaviourPatches
__result = behaviour.RoleColor;
return false;
}
}
}
+5 -4
View File
@@ -18,7 +18,9 @@ public static class RoleManagerPatches
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 class RoleManagerPatches
{
return true;
}
plr.RpcSetRole(role.GhostRole);
return false;
}
}
}
@@ -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 class RoleOptionsCollectionPatch
[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<int>(customRole.NumConfigDefinition, out var entry);
__result = entry.Value;
return false;
}
}
+127 -80
View File
@@ -15,9 +15,8 @@ namespace MiraAPI.Patches.Roles;
[HarmonyPatch]
public static class TaskAdderPatch
{
private static TaskFolder _rolesFolder;
private static readonly System.Collections.Generic.Dictionary<string, string> ModsFolders = new();
private static Scroller _scroller;
private static readonly System.Collections.Generic.Dictionary<string, string> ModsFolders = [];
private static Scroller? _scroller;
[HarmonyPostfix]
[HarmonyPatch(typeof(TaskAdderGame), nameof(TaskAdderGame.Begin))]
@@ -56,18 +55,22 @@ public static class TaskAdderPatch
__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())
{
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);
_rolesFolder.SubFolders.Add(newFolder);
rolesFolder.SubFolders.Add(newFolder);
if (!ModsFolders.ContainsKey(plugin.PluginInfo.Metadata.Name))
{
@@ -75,7 +78,7 @@ public static class TaskAdderPatch
}
}
__instance.Root.SubFolders.Add(_rolesFolder);
__instance.Root.SubFolders.Add(rolesFolder);
__instance.GoToRoot();
}
@@ -92,7 +95,12 @@ public static class TaskAdderPatch
__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 +113,9 @@ public static class TaskAdderPatch
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 +129,13 @@ public static class TaskAdderPatch
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 +158,7 @@ public static class TaskAdderPatch
num2 -= num3;
num3 = 0f;
}
__instance.ActiveItems.Add(folderTransform);
if (!taskFolder2 || !taskFolder2.Button)
{
@@ -155,7 +166,8 @@ public static class TaskAdderPatch
}
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 +185,90 @@ public static class TaskAdderPatch
{
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<DivertPowerTask>().TargetSystem;
taskAddButton.Text.text = DestroyableSingleton<TranslationController>.Instance.GetString(StringNames.DivertPowerTo, DestroyableSingleton<TranslationController>.Instance.GetString(targetSystem));
}
else if (taskAddButton.MyTask.TaskType == TaskTypes.FixWeatherNode)
{
var nodeId = ((WeatherNodeTask)taskAddButton.MyTask).NodeId;
taskAddButton.Text.text = DestroyableSingleton<TranslationController>.Instance.GetString(StringNames.FixWeatherNode, Array.Empty<Il2CppSystem.Object>()) + " " + DestroyableSingleton<TranslationController>.Instance.GetString(WeatherSwitchGame.ControlNames[nodeId],
Array.Empty<Il2CppSystem.Object>());
}
else
{
taskAddButton.Text.text = DestroyableSingleton<TranslationController>.Instance.GetString(taskAddButton.MyTask.TaskType);
}
__instance.AddFileAsChildCustom(taskFolder, taskAddButton, ref num, ref num2, ref num3);
if (taskAddButton != null && taskAddButton.Button != null)
{
ControllerManager.Instance.AddSelectableUiElement(taskAddButton.Button);
if (__instance.Hierarchy.Count != 1 && !flag)
case TaskTypes.DivertPower:
{
var component = ControllerManager.Instance.CurrentUiState.CurrentSelection.GetComponent<TaskFolder>();
if (component != null)
{
__instance.restorePreviousSelectionByFolderName = component.FolderName;
}
ControllerManager.Instance.SetDefaultSelection(taskAddButton.Button);
flag = true;
var targetSystem = taskAddButton.MyTask.Cast<DivertPowerTask>().TargetSystem;
taskAddButton.Text.text = DestroyableSingleton<TranslationController>.Instance.GetString(
StringNames.DivertPowerTo,
DestroyableSingleton<TranslationController>.Instance.GetString(targetSystem));
break;
}
case TaskTypes.FixWeatherNode:
{
var nodeId = ((WeatherNodeTask)taskAddButton.MyTask).NodeId;
taskAddButton.Text.text =
DestroyableSingleton<TranslationController>.Instance.GetString(
StringNames.FixWeatherNode,
Array.Empty<Il2CppSystem.Object>()) + " " +
DestroyableSingleton<TranslationController>.Instance.GetString(
WeatherSwitchGame.ControlNames[nodeId],
Array.Empty<Il2CppSystem.Object>());
break;
}
default:
taskAddButton.Text.text =
DestroyableSingleton<TranslationController>.Instance.GetString(taskAddButton.MyTask.TaskType);
break;
}
__instance.AddFileAsChildCustom(taskAddButton, ref num, ref num2, ref num3);
if (taskAddButton.Button == null)
{
continue;
}
ControllerManager.Instance.AddSelectableUiElement(taskAddButton.Button);
if (__instance.Hierarchy.Count == 1 || flag)
{
continue;
}
var component =
ControllerManager.Instance.CurrentUiState.CurrentSelection.GetComponent<TaskFolder>();
if (component != null)
{
__instance.restorePreviousSelectionByFolderName = component.FolderName;
}
ControllerManager.Instance.SetDefaultSelection(taskAddButton.Button);
flag = true;
}
if (taskFolder.FolderName == "Roles")
{
for (var m = 0; m < DestroyableSingleton<RoleManager>.Instance.AllRoles.Length; m++)
{
var roleBehaviour = DestroyableSingleton<RoleManager>.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))
{
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;
}
}
}
@@ -240,27 +279,33 @@ public static class TaskAdderPatch
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 +316,19 @@ public static class TaskAdderPatch
chip.GetComponent<SpriteRenderer>().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;
}
+26 -17
View File
@@ -7,9 +7,9 @@ namespace MiraAPI.Patches.Roles;
public static class TaskPanelPatch
{
/// <summary>
/// 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.
/// </summary>
[HarmonyPrefix]
[HarmonyPatch(nameof(TaskPanelBehaviour.Update))]
@@ -24,7 +24,12 @@ public static class TaskPanelPatch
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 class TaskPanelPatch
{
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;
}
}
}
+27
View File
@@ -0,0 +1,27 @@
using HarmonyLib;
using MiraAPI.Roles;
using MiraAPI.Utilities;
using UnityEngine;
namespace MiraAPI.Patches.Roles;
/// <summary>
/// Set vent outline color based on the player's role.
/// </summary>
[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);
}
}
+1 -1
View File
@@ -6,4 +6,4 @@ public interface IMiraPlugin
{
string OptionsTitleText { get; }
public ConfigFile GetConfigFile();
}
}
+3 -1
View File
@@ -15,7 +15,7 @@ using Reactor.Utilities;
namespace MiraAPI.PluginLoading;
internal class MiraPluginManager
internal sealed class MiraPluginManager
{
private readonly Dictionary<Assembly, MiraPluginInfo> _registeredPlugins = [];
@@ -83,6 +83,8 @@ internal class MiraPluginManager
ModdedOptionsManager.RegisterAttributeOption(type, attribute, property, pluginInfo);
}
}
pluginInfo.OptionGroups.Sort((x, y) => x.GroupPriority.CompareTo(y.GroupPriority));
}
private static void RegisterRoleAttribute(Assembly assembly, MiraPluginInfo pluginInfo)
+8 -3
View File
@@ -35,6 +35,11 @@ public static class CustomRoleManager
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<Type> roles, MiraPluginInfo pluginInfo)
@@ -79,10 +84,10 @@ public static class CustomRoleManager
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.CanKill;
roleBehaviour.TasksCountTowardProgress = customRole.TasksCount;
roleBehaviour.CanUseKillButton = customRole.UseVanillaKillButton;
roleBehaviour.TasksCountTowardProgress = customRole.TasksCountForProgress;
roleBehaviour.CanVent = customRole.CanUseVent;
roleBehaviour.DefaultGhostRole = customRole.GhostRole;
roleBehaviour.MaxCount = customRole.MaxPlayers;
+27 -17
View File
@@ -41,7 +41,7 @@ public interface ICustomRole
ModdedRoleTeams Team { get; }
/// <summary>
/// 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.
/// </summary>
int MaxPlayers => 15;
@@ -58,29 +58,19 @@ public interface ICustomRole
LoadableAsset<Sprite> Icon => MiraAssets.Empty;
/// <summary>
/// Gets the BepInEx ConfigDefinition for the amount of players that can have this role.
/// Gets a value indicating whether the role is affected by light affectors on Airship.
/// </summary>
ConfigDefinition NumConfigDefinition => new("Roles", $"Num {GetType().FullName}");
bool AffectedByLightOnAirship => Team == ModdedRoleTeams.Crewmate;
/// <summary>
/// Gets the BepInEx ConfigDefinition for the chance of this role being selected.
/// </summary>
ConfigDefinition ChanceConfigDefinition => new("Roles", $"Chance {GetType().FullName}");
/// <summary>
/// Gets a value indicating whether the role is affected by light sabotages.
/// </summary>
bool AffectedByLight => Team == ModdedRoleTeams.Crewmate;
/// <summary>
/// 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.
/// </summary>
bool CanGetKilled => Team == ModdedRoleTeams.Crewmate;
/// <summary>
/// Gets a value indicating whether the role can kill others.
/// Gets a value indicating whether the role should use the vanilla kill button.
/// </summary>
bool CanKill => Team == ModdedRoleTeams.Impostor;
bool UseVanillaKillButton => Team == ModdedRoleTeams.Impostor;
/// <summary>
/// Gets a value indicating whether the role can use vents.
@@ -90,7 +80,7 @@ public interface ICustomRole
/// <summary>
/// Gets a value indicating whether the role's tasks count towards task progress.
/// </summary>
bool TasksCount => Team == ModdedRoleTeams.Crewmate;
bool TasksCountForProgress => Team == ModdedRoleTeams.Crewmate;
/// <summary>
/// Gets a value indicating whether the role is a Ghost.
@@ -102,6 +92,16 @@ public interface ICustomRole
/// </summary>
bool HideSettings => IsGhostRole;
/// <summary>
/// Gets the outline color for the KillButton if <see cref="UseVanillaKillButton"/> is true.
/// </summary>
Color KillButtonOutlineColor => Team switch
{
ModdedRoleTeams.Impostor => Palette.ImpostorRed,
ModdedRoleTeams.Crewmate => Palette.CrewmateBlue,
_ => RoleColor,
};
/// <summary>
/// Gets the role hint style. See <see cref="RoleHintType"/> enum for all options.
/// </summary>
@@ -112,6 +112,16 @@ public interface ICustomRole
/// </summary>
RoleTypes GhostRole => Team == ModdedRoleTeams.Impostor ? RoleTypes.ImpostorGhost : RoleTypes.CrewmateGhost;
/// <summary>
/// Gets the BepInEx ConfigDefinition for the amount of players that can have this role.
/// </summary>
ConfigDefinition NumConfigDefinition => new("Roles", $"Num {GetType().FullName}");
/// <summary>
/// Gets the BepInEx ConfigDefinition for the chance of this role being selected.
/// </summary>
ConfigDefinition ChanceConfigDefinition => new("Roles", $"Chance {GetType().FullName}");
/// <summary>
/// Gets the parent mod of this role.
/// </summary>
+2 -2
View File
@@ -4,5 +4,5 @@ public enum ModdedRoleTeams
{
Crewmate,
Impostor,
Neutral
}
Neutral,
}
+1 -1
View File
@@ -3,4 +3,4 @@
namespace MiraAPI.Roles;
[AttributeUsage(AttributeTargets.Class)]
public class RegisterCustomRoleAttribute : Attribute;
public class RegisterCustomRoleAttribute : Attribute;
+1 -3
View File
@@ -1,6 +1,4 @@
// Copyright (c) PlaceholderCompany. All rights reserved.
namespace MiraAPI.Roles;
namespace MiraAPI.Roles;
/// <summary>
/// The type of hint style for a role to use.
+2 -2
View File
@@ -13,7 +13,7 @@ public static class RoleId
return roleId;
}
public static ushort Get(Type type)
{
if (!CustomRoleManager.RoleIds.TryGetValue(type, out var roleId))
@@ -23,4 +23,4 @@ public static class RoleId
return roleId;
}
}
}
+7 -7
View File
@@ -5,17 +5,17 @@
/// Mira uses the <see cref="LoadableAsset{T}"/> pattern in various locations.
/// You can create your own implementation of this class to load assets in different ways.
/// </summary>
/// <typeparam name="T">The type of the asset to be loaded</typeparam>
/// <typeparam name="T">The type of the asset to be loaded.</typeparam>
public abstract class LoadableAsset<T> where T : UnityEngine.Object
{
/// <summary>
/// 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.
/// </summary>
protected T LoadedAsset;
protected T? LoadedAsset { get; set; }
/// <summary>
/// The method that loads the asset.
/// Loads the asset from the source.
/// </summary>
/// <returns>The loaded asset</returns>
/// <returns>The loaded asset.</returns>
public abstract T LoadAsset();
}
}
+10 -10
View File
@@ -7,30 +7,30 @@ namespace MiraAPI.Utilities.Assets;
/// <summary>
/// A utility class for loading assets from an asset bundle.
/// </summary>
/// <param name="name">The name of the asset</param>
/// <param name="bundle">The AssetBundle that contains the asset</param>
/// <typeparam name="T">The type of the asset to be loaded</typeparam>
/// <param name="name">The name of the asset.</param>
/// <param name="bundle">The AssetBundle that contains the asset.</param>
/// <typeparam name="T">The type of the asset to be loaded.</typeparam>
public class LoadableBundleAsset<T>(string name, AssetBundle bundle) : LoadableAsset<T> where T : UnityEngine.Object
{
/// <summary>
/// Loads the asset from the asset bundle.
/// </summary>
/// <returns>The asset</returns>
/// <returns>The asset.</returns>
/// <exception cref="Exception">The asset did not load properly.</exception>
public override T LoadAsset()
{
if (LoadedAsset)
if (LoadedAsset != null)
{
return LoadedAsset;
}
LoadedAsset = bundle.LoadAsset<T>(name);
if (!LoadedAsset)
if (LoadedAsset == null)
{
throw new Exception($"INVALID ASSET: {name}");
throw new InvalidOperationException($"INVALID ASSET: {name}");
}
return LoadedAsset;
}
}
}
@@ -1,28 +1,24 @@
using System.Reflection;
using Reactor.Utilities;
using UnityEngine;
namespace MiraAPI.Utilities.Assets;
/// <summary>
/// A utility class for loading assets from embedded resources.
/// </summary>
/// <param name="path">The path to the embedded resource.</param>
public class LoadableResourceAsset(string path) : LoadableAsset<Sprite>
{
private readonly Assembly _assembly = Assembly.GetCallingAssembly();
/// <inheritdoc />
public override Sprite LoadAsset()
{
if (LoadedAsset)
if (LoadedAsset != null)
{
return LoadedAsset;
}
try
{
return LoadedAsset = SpriteTools.LoadSpriteFromPath(path, _assembly);
}
catch
{
Logger<MiraApiPlugin>.Error($"Not loading, invalid asset: {path}");
return null;
}
return LoadedAsset = SpriteTools.LoadSpriteFromPath(path, _assembly);
}
}
}
+2 -4
View File
@@ -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);
}
public static readonly Color32 AcceptedTeal = new(43, 233, 198, 255);
}
+9 -15
View File
@@ -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;
/// </summary>
public static class SpriteTools
{
/// <summary>
/// Delegate for LoadImage.
/// </summary>
public delegate bool DLoadImage(IntPtr tex, IntPtr data, bool markNonReadable);
private delegate bool DLoadImage(IntPtr tex, IntPtr data, bool markNonReadable);
/// <summary>
/// The ICall for LoadImage.
/// </summary>
public static DLoadImage? ICallLoadImage;
private static DLoadImage? _iCallLoadImage;
/// <summary>
/// Load an image into a texture.
@@ -32,18 +26,18 @@ public static class SpriteTools
/// <returns>True if succeeded.</returns>
public static bool LoadImage(Texture2D tex, byte[] data, bool markNonReadable)
{
ICallLoadImage ??= IL2CPP.ResolveICall<DLoadImage>("UnityEngine.ImageConversion::LoadImage");
_iCallLoadImage ??= IL2CPP.ResolveICall<DLoadImage>("UnityEngine.ImageConversion::LoadImage");
var il2CPPArray = (Il2CppStructArray<byte>)data;
return ICallLoadImage.Invoke(tex.Pointer, il2CPPArray.Pointer, markNonReadable);
return _iCallLoadImage.Invoke(tex.Pointer, il2CPPArray.Pointer, markNonReadable);
}
/// <summary>
/// Load a sprite from a resource path.
/// </summary>
/// <param name="resourcePath">The path to the resource.</param>
/// <returns>A sprite made from the resource</returns>
/// <returns>A sprite made from the resource.</returns>
/// <exception cref="Exception">The resource cannot be found.</exception>
public static Sprite LoadSpriteFromPath(string resourcePath, Assembly assembly)
{
+2 -2
View File
@@ -4,5 +4,5 @@ public enum MiraNumberSuffixes
None,
Multiplier,
Seconds,
Percent
}
Percent,
}
+22 -23
View File
@@ -5,8 +5,8 @@ namespace MiraAPI.Utilities;
public static class ShaderID
{
private static readonly Dictionary<string, int> Cache = new();
private static readonly Dictionary<string, int> Cache = [];
public static int Get(string name)
{
if (Cache.TryGetValue(name, out var id))
@@ -18,74 +18,74 @@ public static class ShaderID
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 class ShaderID
// 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");
}
}