freeplay modifiers

This commit is contained in:
XtraCube committed 2025-02-22 18:54:20 -05:00
1 parent 9504862bea
commit b6dda5f970
12 files changed
+170 -53

No files matched your search

+1 -2
View File
@@ -1,5 +1,4 @@
using MiraAPI.Modifiers;
using MiraAPI.Modifiers.Types;
using MiraAPI.Modifiers.Types;
namespace MiraAPI.Example.Modifiers;
@@ -1,6 +1,5 @@
using Il2CppSystem;
using MiraAPI.Example.Roles;
using MiraAPI.Modifiers;
using MiraAPI.Modifiers.Types;
using UnityEngine;
@@ -1,5 +1,4 @@
using MiraAPI.Modifiers;
using MiraAPI.Modifiers.Types;
using MiraAPI.Modifiers.Types;
namespace MiraAPI.Example.Modifiers;
@@ -1,5 +1,4 @@
using System;
using System.Globalization;
using System.Linq;
using System.Text;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
+5
View File
@@ -30,6 +30,11 @@ public abstract class BaseModifier
/// </summary>
public virtual bool HideOnUi => false;
/// <summary>
/// Gets a value indicating whether the modifier is shown in the freeplay menu.
/// </summary>
public virtual bool ShowInFreeplay => false;
/// <summary>
/// Gets the HUD information for this modifier. Defaults to the modifier name. Does nothing if <see cref="HideOnUi"/> is true.
/// </summary>
+6 -1
View File
@@ -1,8 +1,10 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using MiraAPI.Modifiers.Types;
using MiraAPI.Networking;
using MiraAPI.PluginLoading;
using MiraAPI.Roles;
using MiraAPI.Utilities;
using Reactor.Networking.Rpc;
@@ -49,7 +51,7 @@ public static class ModifierManager
return TypeToIdModifierMap.GetValueOrDefault(type);
}
internal static bool RegisterModifier(Type modifierType)
internal static bool RegisterModifier(Type modifierType, MiraPluginInfo info)
{
if (!typeof(BaseModifier).IsAssignableFrom(modifierType))
{
@@ -58,6 +60,9 @@ public static class ModifierManager
IdToTypeModifierMap.Add(GetNextId(), modifierType);
TypeToIdModifierMap.Add(modifierType, _nextId);
var bm = (BaseModifier)FormatterServices.GetUninitializedObject(modifierType); // this probably isn't a great idea
bm.ModifierId = _nextId;
info.Modifiers.Add(bm);
if (!typeof(GameModifier).IsAssignableFrom(modifierType))
{
+3
View File
@@ -5,6 +5,9 @@
/// </summary>
public abstract class GameModifier : BaseModifier
{
/// <inheritdoc />
public override bool ShowInFreeplay => true;
/// <summary>
/// Gets the chance of the modifier being assigned to a player.
/// </summary>
@@ -0,0 +1,43 @@
using HarmonyLib;
using MiraAPI.Modifiers;
using MiraAPI.Utilities;
using UnityEngine.UI;
namespace MiraAPI.Patches.Roles;
[HarmonyPatch(typeof(TaskAddButton))]
public static class TaskAddButtonPatches
{
[HarmonyPrefix]
[HarmonyPatch(nameof(TaskAddButton.Start))]
public static bool StartPrefix(TaskAddButton __instance)
{
if (uint.TryParse(__instance.name, out var result))
{
__instance.Overlay.enabled = false;
if (PlayerControl.LocalPlayer.HasModifier(result))
{
__instance.Overlay.enabled = true;
__instance.Overlay.sprite = __instance.CheckImage;
}
__instance.Button.OnClick = new Button.ButtonClickedEvent();
__instance.Button.OnClick.AddListener((UnityEngine.Events.UnityAction)(() =>
{
if (PlayerControl.LocalPlayer.HasModifier(result))
{
PlayerControl.LocalPlayer.GetModifierComponent()!.RemoveModifier(result);
__instance.Overlay.enabled = false;
}
else
{
PlayerControl.LocalPlayer.GetModifierComponent()!.AddModifier(ModifierManager.GetModifierType(result)!);
__instance.Overlay.enabled = true;
}
}));
return false;
}
return true;
}
}
+102 -39
View File
@@ -4,7 +4,6 @@ using MiraAPI.PluginLoading;
using MiraAPI.Roles;
using MiraAPI.Utilities.Assets;
using System;
using System.Collections.Generic;
using System.Linq;
using TMPro;
using UnityEngine;
@@ -18,7 +17,6 @@ namespace MiraAPI.Patches.Roles;
[HarmonyPatch]
public static class TaskAdderPatch
{
private static readonly Dictionary<string, string> ModsFolders = [];
private static Scroller? _scroller;
/// <summary>
@@ -67,25 +65,34 @@ public static class TaskAdderPatch
rolesFolder.FolderName = "Roles";
rolesFolder.name = "RolesFolder";
var modifiersFolder = Object.Instantiate(__instance.RootFolderPrefab, _scroller.Inner);
modifiersFolder.gameObject.SetActive(false);
modifiersFolder.FolderName = "Modifiers";
modifiersFolder.name = "ModifiersFolder";
foreach (var plugin in MiraPluginManager.Instance.RegisteredPlugins())
{
if (plugin.CustomRoles.Count == 0)
if (plugin.CustomRoles.Any(x => x.Value is ICustomRole { Configuration.ShowInFreeplay: true }))
{
continue;
var newFolder = Object.Instantiate(__instance.RootFolderPrefab, _scroller.Inner);
newFolder.name = plugin.PluginId+":Roles";
newFolder.FolderName = plugin.PluginInfo.Metadata.Name;
newFolder.gameObject.SetActive(false);
rolesFolder.SubFolders.Add(newFolder);
}
var newFolder = Object.Instantiate(__instance.RootFolderPrefab, _scroller.Inner);
newFolder.FolderName = newFolder.name = plugin.PluginInfo.Metadata.Name;
newFolder.gameObject.SetActive(false);
rolesFolder.SubFolders.Add(newFolder);
if (!ModsFolders.ContainsKey(plugin.PluginInfo.Metadata.Name))
if (plugin.Modifiers.Exists(x => x.ShowInFreeplay))
{
ModsFolders.Add(plugin.PluginInfo.Metadata.Name, plugin.PluginId);
var newFolder = Object.Instantiate(__instance.RootFolderPrefab, _scroller.Inner);
newFolder.name = plugin.PluginId+":Modifiers";
newFolder.FolderName = plugin.PluginInfo.Metadata.Name;
newFolder.gameObject.SetActive(false);
modifiersFolder.SubFolders.Add(newFolder);
}
}
__instance.Root.SubFolders.Add(rolesFolder);
__instance.Root.SubFolders.Add(modifiersFolder);
__instance.GoToRoot();
}
@@ -277,39 +284,21 @@ public static class TaskAdderPatch
}
}
if (ModsFolders.TryGetValue(taskFolder.FolderName, out var guid))
var split = taskFolder.name.Split(':');
if (split.Length == 2)
{
var plugin = MiraPluginManager.GetPluginByGuid(guid);
for (var m = 0; m < plugin.CustomRoles.Count; m++)
var pluginId = split[0];
var folderName = split[1];
if (MiraPluginManager.GetPluginByGuid(pluginId) is { } plugin)
{
var roleBehaviour = plugin.CustomRoles.ElementAt(m).Value;
if (roleBehaviour.Role == RoleTypes.ImpostorGhost || roleBehaviour.Role == RoleTypes.CrewmateGhost ||
(roleBehaviour is ICustomRole customRole && !customRole.Configuration.ShowInFreeplay))
if (folderName == "Roles(Clone)")
{
continue;
PluginRoles(__instance, plugin, ref num, ref num2, ref num3);
}
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)
else if (folderName == "Modifiers(Clone)")
{
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;
PluginModifiers(__instance, plugin, ref num, ref num2, ref num3);
}
}
}
@@ -336,4 +325,78 @@ public static class TaskAdderPatch
ControllerManager.Instance.SetBackButton(__instance.FolderBackButton);
return false;
}
private static void PluginModifiers(
TaskAdderGame instance,
MiraPluginInfo plugin,
ref float num,
ref float num2,
ref float num3)
{
for (var m = 0; m < plugin.Modifiers.Count; m++)
{
var modifier = plugin.Modifiers[m];
if (!modifier.ShowInFreeplay)
{
continue;
}
var taskAddButton = Object.Instantiate(instance.RoleButton);
taskAddButton.name = modifier.ModifierId.ToString();
taskAddButton.role = null;
taskAddButton.MyTask = null;
taskAddButton.SafePositionWorld = instance.SafePositionWorld;
taskAddButton.Text.text = modifier.ModifierName;
instance.AddFileAsChildCustom(taskAddButton, ref num, ref num2, ref num3);
ControllerManager.Instance.AddSelectableUiElement(taskAddButton.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(taskAddButton.Button);
break;
}
}
}
private static void PluginRoles(TaskAdderGame instance, MiraPluginInfo plugin, ref float num, ref float num2, ref float num3)
{
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 is ICustomRole { Configuration.ShowInFreeplay: false })
{
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;
}
}
}
}
+3
View File
@@ -5,6 +5,7 @@ using MiraAPI.GameOptions;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using MiraAPI.Hud;
using MiraAPI.Modifiers;
namespace MiraAPI.PluginLoading;
@@ -61,6 +62,8 @@ public class MiraPluginInfo
internal List<IModdedOption> Options { get; } = [];
internal List<BaseModifier> Modifiers { get; } = [];
internal Dictionary<ushort, RoleBehaviour> CustomRoles { get; } = [];
internal Dictionary<int, CustomGameMode> GameModes { get; } = [];
+5 -5
View File
@@ -48,7 +48,7 @@ public sealed class MiraPluginManager
continue;
}
if (RegisterModifier(type))
if (RegisterModifier(type, info))
{
continue;
}
@@ -91,9 +91,9 @@ public sealed class MiraPluginManager
/// </summary>
/// <param name="pluginId">The plugin GUID.</param>
/// <returns>A MiraPluginInfo.</returns>
public static MiraPluginInfo GetPluginByGuid(string pluginId)
public static MiraPluginInfo? GetPluginByGuid(string pluginId)
{
return Instance._registeredPlugins.Values.First(plugin => plugin.PluginId == pluginId);
return Instance._registeredPlugins.Values.FirstOrDefault(plugin => plugin.PluginId == pluginId);
}
private static bool RegisterOptions(Type type, MiraPluginInfo pluginInfo)
@@ -199,11 +199,11 @@ public sealed class MiraPluginManager
}
}
private static bool RegisterModifier(Type type)
private static bool RegisterModifier(Type type, MiraPluginInfo info)
{
try
{
return ModifierManager.RegisterModifier(type);
return ModifierManager.RegisterModifier(type, info);
}
catch (Exception e)
{
+1 -2
View File
@@ -1,5 +1,4 @@
using System;
using BepInEx.Configuration;
using BepInEx.Configuration;
using MiraAPI.Modifiers;
using MiraAPI.PluginLoading;
using MiraAPI.Utilities;