make Role Tab optional

This commit is contained in:
XtraCube committed 2024-08-30 12:28:02 -04:00
1 parent 9f975c8263
commit a52f46972e
12 files changed
+146 -94

No files matched your search

+1 -2
View File
@@ -13,5 +13,4 @@ public class TeleporterRole : CrewmateRole, ICustomRole
public Color RoleColor => new Color32(221, 176, 152, 255);
public ModdedRoleTeams Team => ModdedRoleTeams.Crewmate;
public LoadableAsset<Sprite> OptionsScreenshot => ExampleAssets.Banner;
}
}
+6 -8
View File
@@ -311,23 +311,20 @@ public abstract class CustomActionButton
public abstract class CustomActionButton<T> : CustomActionButton where T : MonoBehaviour
{
/// <summary>
/// The target object of the button.
/// Gets the target object of the button.
/// </summary>
public T? Target { get; private set; }
/// <summary>
/// The distance the player must be from the target object to use the button.
/// Gets the distance the player must be from the target object to use the button.
/// </summary>
public virtual float Distance => PlayerControl.LocalPlayer.Data.Role.GetAbilityDistance();
/// <summary>
/// An optional collider tag to filter the target object by.
/// </summary>
public virtual string? ColliderTag => null;
/// <summary>
/// Determines if the target object is valid.
/// </summary>
/// <param name="target">The target object being checked.</param>
/// <returns>True if the target object is valid, false otherwise.</returns>
public virtual bool IsTargetValid(T? target)
{
return target;
@@ -336,6 +333,7 @@ public abstract class CustomActionButton<T> : CustomActionButton where T : MonoB
/// <summary>
/// The method used to get the target object.
/// </summary>
/// <returns>The target object or null if it isn't found.</returns>
public abstract T? GetTarget();
/// <summary>
@@ -344,7 +342,7 @@ public abstract class CustomActionButton<T> : CustomActionButton where T : MonoB
/// <param name="active">Should the outline be active</param>
public abstract void SetOutline(bool active);
/// <inheritdoc />
public override bool CanUse()
{
var newTarget = GetTarget();
+8 -8
View File
@@ -14,8 +14,8 @@ public static class CustomMurderRpcs
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)
{
MurderResultFlags murderResultFlags = didSucceed ? MurderResultFlags.Succeeded : MurderResultFlags.FailedError;
MurderResultFlags murderResultFlags2 = MurderResultFlags.DecisionByHost | murderResultFlags;
var murderResultFlags = didSucceed ? MurderResultFlags.Succeeded : MurderResultFlags.FailedError;
var murderResultFlags2 = MurderResultFlags.DecisionByHost | murderResultFlags;
source.CustomMurder(target, murderResultFlags2, resetKillTimer, createDeadBody, teleportMurderer, showKillAnim, playKillSound);
}
@@ -25,7 +25,7 @@ public static class CustomMurderRpcs
{
source.isKilling = false;
source.logger.Debug(string.Format("{0} trying to murder {1}", source.PlayerId, target.PlayerId), null);
NetworkedPlayerInfo data = target.Data;
var data = target.Data;
if (resultFlags.HasFlag(MurderResultFlags.FailedError))
{
return;
@@ -33,7 +33,7 @@ public static class CustomMurderRpcs
if (resultFlags.HasFlag(MurderResultFlags.FailedProtected) || (resultFlags.HasFlag(MurderResultFlags.DecisionByHost) && target.protectedByGuardianId > -1))
{
target.protectedByGuardianThisRound = true;
bool flag = PlayerControl.LocalPlayer.Data.Role.Role == RoleTypes.GuardianAngel;
var flag = PlayerControl.LocalPlayer.Data.Role.Role == RoleTypes.GuardianAngel;
if (flag && PlayerControl.LocalPlayer.Data.PlayerId == target.protectedByGuardianId)
{
StatsManager.Instance.IncrementStat(StringNames.StatsGuardianAngelCrewmatesProtected);
@@ -116,9 +116,9 @@ public static class CustomMurderRpcs
public static IEnumerator CoPerformCustomKill(this KillAnimation anim, PlayerControl source, PlayerControl target,
bool createDeadBody = true, bool teleportMurderer = true)
{
FollowerCamera cam = Camera.main.GetComponent<FollowerCamera>();
bool isParticipant = PlayerControl.LocalPlayer == source || PlayerControl.LocalPlayer == target;
PlayerPhysics sourcePhys = source.MyPhysics;
var cam = Camera.main.GetComponent<FollowerCamera>();
var isParticipant = PlayerControl.LocalPlayer == source || PlayerControl.LocalPlayer == target;
var sourcePhys = source.MyPhysics;
if (teleportMurderer)
{
@@ -143,7 +143,7 @@ public static class CustomMurderRpcs
deadBody.bodyRenderers.ToArray().ToList().ForEach(target.SetPlayerMaterialColors);
target.SetPlayerMaterialColors(deadBody.bloodSplatter);
Vector3 vector = target.transform.position + anim.BodyOffset;
var vector = target.transform.position + anim.BodyOffset;
vector.z = vector.y / 1000f;
deadBody.transform.position = vector;
}
+50 -39
View File
@@ -8,15 +8,22 @@ using Object = UnityEngine.Object;
namespace MiraAPI.Patches;
/// <summary>
/// General patches for the HudManager class.
/// </summary>
[HarmonyPatch(typeof(HudManager))]
public static class HudManagerPatches
{
/// Custom buttons parent
private static GameObject _bottomLeft;
// Custom buttons parent
private static GameObject? _bottomLeft;
/// Custom role tab
private static TaskPanelBehaviour _roleTab;
// 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)
@@ -27,21 +34,25 @@ public static class HudManagerPatches
{
return;
}
//CustomGameModeManager.ActiveMode?.HudUpdate(__instance);
if (local?.Data?.Role is null)
// CustomGameModeManager.ActiveMode?.HudUpdate(__instance);
switch (local?.Data?.Role)
{
return;
}
case null:
return;
if (local.Data.Role is ICustomRole customRole)
{
customRole.HudUpdate(__instance);
if (customRole.SetTabText() != null)
case ICustomRole customRole:
{
if (!_roleTab)
customRole.HudUpdate(__instance);
if (customRole.RoleHintType != RoleHintType.RoleTab)
{
_roleTab?.gameObject.Destroy();
return;
}
if (_roleTab == null)
{
_roleTab = CustomRoleManager.CreateRoleTab(customRole);
}
@@ -49,15 +60,13 @@ public static class HudManagerPatches
{
CustomRoleManager.UpdateRoleTab(_roleTab, customRole);
}
break;
}
else if (customRole.SetTabText() == null && _roleTab)
{
_roleTab.gameObject.Destroy();
}
}
else if (_roleTab)
{
_roleTab.gameObject.Destroy();
default:
_roleTab?.gameObject.Destroy();
break;
}
}
@@ -73,16 +82,17 @@ public static class HudManagerPatches
}*/
/// <summary>
/// Create custom buttons parent
/// Create custom buttons and arrange them on the hud
/// </summary>
/// <param name="__instance">The HudManager instance.</param>
[HarmonyPostfix]
[HarmonyPatch(nameof(HudManager.Start))]
public static void StartPostfix(HudManager __instance)
{
var buttons = __instance.transform.Find("Buttons");
var bottomRight = buttons.Find("BottomRight");
if (!_bottomLeft)
if (_bottomLeft == null)
{
_bottomLeft = Object.Instantiate(bottomRight.gameObject, buttons);
}
@@ -105,14 +115,14 @@ public static class HudManagerPatches
{
ButtonLocation.BottomLeft => _bottomLeft.transform,
ButtonLocation.BottomRight => bottomRight,
_ => null
_ => null,
};
if (location is null)
{
continue;
}
button.CreateButton(location);
}
@@ -123,30 +133,31 @@ public static class HudManagerPatches
}
/// <summary>
/// Make sure all launchpad hud elements are inactive/active when appropriate
/// Set the custom role tab and custom buttons active when the hud is active
/// </summary>
/// <param name="__instance">HudManager instance.</param>
/// <param name="localPlayer">The local PlayerControl.</param>
/// <param name="role">The player's RoleBehaviour.</param>
/// <param name="isActive">Whether the Hud should be set active or not.</param>
[HarmonyPostfix]
[HarmonyPatch(nameof(HudManager.SetHudActive), typeof(PlayerControl), typeof(RoleBehaviour), typeof(bool))]
public static void SetHudActivePostfix(HudManager __instance, [HarmonyArgument(0)] PlayerControl player, [HarmonyArgument(1)] RoleBehaviour roleBehaviour, [HarmonyArgument(2)] bool isActive)
public static void SetHudActivePostfix(HudManager __instance, PlayerControl localPlayer, RoleBehaviour role, bool isActive)
{
if (!player.Data)
if (!localPlayer.Data)
{
return;
}
if (_roleTab)
{
_roleTab.gameObject.SetActive(isActive);
}
_roleTab?.gameObject.SetActive(isActive);
foreach (var button in CustomButtonManager.CustomButtons)
{
button.SetActive(isActive, roleBehaviour);
button.SetActive(isActive, role);
}
if (roleBehaviour is ICustomRole role)
if (role is ICustomRole customRole)
{
__instance.ImpostorVentButton.gameObject.SetActive(isActive && role.CanUseVent);
__instance.ImpostorVentButton.gameObject.SetActive(isActive && customRole.CanUseVent);
}
}
}
}
@@ -16,8 +16,8 @@ public class NotificationPopperPatch
{
if (CustomRoleManager.CustomRoles.Values.Any(role => role.StringName == key))
{
string item = string.Empty;
string text = (teamType == RoleTeamTypes.Crewmate) ? Palette.CrewmateSettingChangeText.ToTextColor() : Palette.ImpostorRed.ToTextColor();
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(
+2 -2
View File
@@ -10,8 +10,8 @@ public class SettingPatches
[HarmonyPatch(typeof(FloatGameSetting), nameof(FloatGameSetting.GetValueString))]
public static bool ValueStringPatch(FloatGameSetting __instance, ref string __result, [HarmonyArgument(0)] float value)
{
string result = string.Empty;
MiraNumberSuffixes suffix = (MiraNumberSuffixes)__instance.SuffixType;
var result = string.Empty;
var suffix = (MiraNumberSuffixes)__instance.SuffixType;
if (__instance.ZeroIsInfinity && Mathf.Abs(value) < 0.0001f)
{
+5 -6
View File
@@ -29,26 +29,25 @@ public static class PlayerControlPatches
{
customRole.PlayerControlFixedUpdate(__instance);
}
if (!__instance.AmOwner)
{
return;
}
foreach (var button in CustomButtonManager.CustomButtons)
{
if (__instance.Data?.Role == null)
{
continue;
}
if (!button.Enabled(__instance.Data?.Role))
{
continue;
}
button.FixedUpdateHandler(__instance);
}
}
}
}
@@ -18,7 +18,7 @@ public static class RoleOptionsCollectionPatch
{
return true;
}
if (customRole.HideSettings)
{
return false;
@@ -27,7 +27,6 @@ public static class RoleOptionsCollectionPatch
customRole.ParentMod.PluginConfig.TryGetEntry<int>(customRole.ChanceConfigDefinition, out var entry);
__result = entry.Value;
return false;
}
/// <summary>
+8 -8
View File
@@ -34,17 +34,17 @@ public static class TaskAdderPatch
GameObject hitbox = new("Hitbox")
{
layer = 5
layer = 5,
};
hitbox.transform.SetParent(__instance.TaskParent.transform, false);
hitbox.transform.localScale = new Vector3(7.5f, 6.5f, 1);
hitbox.transform.localPosition = new Vector3(2.8f, -2.2f, 0);
SpriteMask mask = hitbox.AddComponent<SpriteMask>();
var mask = hitbox.AddComponent<SpriteMask>();
mask.sprite = MiraAssets.NextButton.LoadAsset();
mask.alphaCutoff = 0.0f;
BoxCollider2D collider = hitbox.AddComponent<BoxCollider2D>();
var collider = hitbox.AddComponent<BoxCollider2D>();
collider.size = new Vector2(1f, 1f);
collider.enabled = true;
@@ -54,7 +54,7 @@ public static class TaskAdderPatch
__instance.RoleButton.GetComponent<PassiveButton>().ClickMask = collider;
__instance.RootFolderPrefab.GetComponent<PassiveButton>().ClickMask = collider;
__instance.RootFolderPrefab.gameObject.SetActive(false);
__instance.TaskParent = inner.transform;
_rolesFolder = Object.Instantiate(__instance.RootFolderPrefab, _scroller.Inner);
@@ -115,7 +115,7 @@ public static class TaskAdderPatch
[HarmonyPatch(typeof(TaskAdderGame), nameof(TaskAdderGame.ShowFolder))]
public static bool ShowPatch(TaskAdderGame __instance, [HarmonyArgument(0)] TaskFolder taskFolder)
{
var stringBuilder = new StringBuilder(64);
var stringBuilder = new Il2CppSystem.Text.StringBuilder(64);
__instance.Hierarchy.Add(taskFolder);
for (var i = 0; i < __instance.Hierarchy.Count; i++)
{
@@ -286,4 +286,4 @@ public static class TaskAdderPatch
ControllerManager.Instance.SetBackButton(__instance.FolderBackButton);
return false;
}
}
}
+34 -11
View File
@@ -17,11 +17,13 @@ using Object = UnityEngine.Object;
namespace MiraAPI.Roles;
/// <summary>
/// Custom role manager for handling custom roles.
/// </summary>
public static class CustomRoleManager
{
public static readonly Dictionary<ushort, RoleBehaviour> CustomRoles = new();
public static readonly Dictionary<Type, ushort> RoleIds = new();
internal static readonly Dictionary<ushort, RoleBehaviour> CustomRoles = [];
internal static readonly Dictionary<Type, ushort> RoleIds = [];
private static ushort _roleId = 100;
@@ -35,7 +37,7 @@ public static class CustomRoleManager
RoleManager.Instance.AllRoles = RoleManager.Instance.AllRoles.Concat(CustomRoles.Values).ToArray();
}
public static void RegisterRoleTypes(List<Type> roles, MiraPluginInfo pluginInfo)
internal static void RegisterRoleTypes(List<Type> roles, MiraPluginInfo pluginInfo)
{
roles.ForEach(x => RoleIds.Add(x, GetNextRoleId()));
@@ -53,11 +55,11 @@ public static class CustomRoleManager
}
}
private static RoleBehaviour RegisterRole(Type roleType, MiraPluginInfo parentMod)
private static RoleBehaviour? RegisterRole(Type roleType, MiraPluginInfo parentMod)
{
if (!(typeof(RoleBehaviour).IsAssignableFrom(roleType) && typeof(ICustomRole).IsAssignableFrom(roleType)))
{
Logger<MiraApiPlugin>.Error($"{roleType?.Name} does not inherit from RoleBehaviour or ICustomRole.");
Logger<MiraApiPlugin>.Error($"{roleType.Name} does not inherit from RoleBehaviour or ICustomRole.");
return null;
}
@@ -91,6 +93,14 @@ public static class CustomRoleManager
RoleManager.GhostRoles.Add(roleBehaviour.Role);
}
var useTaskHint = customRole.RoleHintType is RoleHintType.TaskHint;
var overridesTaskText = customRole.GetType().GetMethod("SpawnTaskHeader")?.DeclaringType == customRole.GetType();
if (useTaskHint && !overridesTaskText)
{
Logger<MiraApiPlugin>.Error($"Role {customRole.RoleName} is using RoleHintType.TaskHint but does not override SpawnTaskHeader!");
}
CustomRoles.Add(roleId, roleBehaviour);
if (customRole.HideSettings)
@@ -105,12 +115,23 @@ public static class CustomRoleManager
return roleBehaviour;
}
/// <summary>
/// Finds the parent mod of a custom role.
/// </summary>
/// <param name="role">The ICustomRole object.</param>
/// <returns>A MiraPluginInfo object representing the parent mod of the role.</returns>
public static MiraPluginInfo FindParentMod(ICustomRole role)
{
return MiraPluginManager.Instance.RegisteredPlugins.First(plugin => plugin.Value.CustomRoles.ContainsValue(role as RoleBehaviour)).Value;
return MiraPluginManager.Instance.RegisteredPlugins.First(plugin => plugin.Value.CustomRoles.ContainsValue(role as RoleBehaviour ?? throw new InvalidOperationException())).Value;
}
public static bool GetCustomRoleBehaviour(RoleTypes roleType, out ICustomRole result)
/// <summary>
/// Gets a custom role behaviour by role type.
/// </summary>
/// <param name="roleType">The role type enum.</param>
/// <param name="result">The ICustomRole result.</param>
/// <returns>True if the role was found.</returns>
public static bool GetCustomRoleBehaviour(RoleTypes roleType, out ICustomRole? result)
{
CustomRoles.TryGetValue((ushort)roleType, out var temp);
if (temp)
@@ -202,9 +223,11 @@ public static class CustomRoleManager
try
{
customRole.ParentMod.PluginConfig.TryGetEntry<int>(customRole.NumConfigDefinition,
customRole.ParentMod.PluginConfig.TryGetEntry<int>(
customRole.NumConfigDefinition,
out var numEntry);
customRole.ParentMod.PluginConfig.TryGetEntry<int>(customRole.ChanceConfigDefinition,
customRole.ParentMod.PluginConfig.TryGetEntry<int>(
customRole.ChanceConfigDefinition,
out var chanceEntry);
numEntry.Value = num;
@@ -227,4 +250,4 @@ public static class CustomRoleManager
LobbyInfoPane.Instance.RefreshPane();
}
}
}
}
+5 -6
View File
@@ -94,17 +94,16 @@ public interface ICustomRole
/// </summary>
bool IsGhostRole => false;
/// <summary>
/// Unused for some reason.
/// </summary>
// TODO: change this to an enum
bool CreateCustomTab => true;
/// <summary>
/// Gets a value indicating whether the role should show up in the Role Options menu.
/// </summary>
bool HideSettings => IsGhostRole;
/// <summary>
/// Gets the role hint style. See <see cref="RoleHintType"/> enum for all options.
/// </summary>
RoleHintType RoleHintType => RoleHintType.RoleTab;
/// <summary>
/// Gets the Ghost role that is applied when the player is killed.
/// </summary>
+24
View File
@@ -0,0 +1,24 @@
// Copyright (c) PlaceholderCompany. All rights reserved.
namespace MiraAPI.Roles;
/// <summary>
/// The type of hint style for a role to use.
/// </summary>
public enum RoleHintType
{
/// <summary>
/// No hint.
/// </summary>
None,
/// <summary>
/// Original game style (hint above tasks).
/// </summary>
TaskHint,
/// <summary>
/// Use custom role tab.
/// </summary>
RoleTab,
}