simplify + partial unscuff

This commit is contained in:
XtraCube committed 2025-03-03 17:10:14 -05:00
1 parent f2add2a65b
commit 68304a5eb8
15 files changed
+144 -177

No files matched your search

+13 -1
View File
@@ -1,8 +1,20 @@
using MiraAPI.Modifiers.Types;
using MiraAPI.Example.Options.Modifiers;
using MiraAPI.GameOptions;
using MiraAPI.Modifiers.Types;
namespace MiraAPI.Example.Modifiers;
public class CaptainModifier : GameModifier
{
public override string ModifierName => "Captain";
public override int GetAssignmentChance()
{
return (int)OptionGroupSingleton<CaptainModifierSettings>.Instance.Chance;
}
public override int GetAmountPerGame()
{
return (int)OptionGroupSingleton<CaptainModifierSettings>.Instance.Amount;
}
}
@@ -1,4 +1,5 @@
using MiraAPI.Modifiers.Types;
using MiraAPI.GameOptions;
using MiraAPI.Modifiers.Types;
namespace MiraAPI.Example.Modifiers;
@@ -6,6 +7,16 @@ public class HighPriorityModifier : GameModifier
{
public override string ModifierName => "High Priority";
public override int GetAssignmentChance()
{
return 100;
}
public override int GetAmountPerGame()
{
return 1;
}
public override int Priority()
{
return 100;
@@ -8,6 +8,12 @@ public class CaptainModifierSettings : AbstractOptionGroup<CaptainModifier>
{
public override string GroupName => "Captain Settings";
[ModdedNumberOption("Amount", 0, 5)]
public float Amount { get; set; } = 1;
[ModdedNumberOption("Chance", 0, 100, 10)]
public float Chance { get; set; } = 50;
[ModdedNumberOption("Uses", 1, 5)]
public float NumUses { get; set; } = 3;
}
+8 -5
View File
@@ -16,6 +16,11 @@ public abstract class AbstractOptionGroup
/// </summary>
public abstract string GroupName { get; }
/// <summary>
/// Gets the Optionable type of the group.
/// </summary>
public virtual Type? OptionableType => null;
/// <summary>
/// Gets the function that determines whether the group should be visible or not.
/// </summary>
@@ -41,10 +46,8 @@ public abstract class AbstractOptionGroup
/// Base class for option groups. An option group is a collection of options that are displayed together in the options menu.
/// </summary>
/// <typeparam name="T">The type of the optionable that this group contains.</typeparam>
public abstract class AbstractOptionGroup<T> : AbstractOptionGroup, IOptionableGroup where T : IOptionable
public abstract class AbstractOptionGroup<T> : AbstractOptionGroup where T : IOptionable
{
/// <summary>
/// Gets the Optionable type of the group.
/// </summary>
public Type OptionableType => typeof(T);
/// <inheritdoc />
public override Type OptionableType => typeof(T);
}
-14
View File
@@ -1,14 +0,0 @@
using System;
namespace MiraAPI.GameOptions;
/// <summary>
/// Interface for groups that have some type of "Optionable" class.
/// </summary>
public interface IOptionableGroup
{
/// <summary>
/// Gets the type of the Optionable class.
/// </summary>
Type OptionableType { get; }
}
+1 -1
View File
@@ -108,7 +108,7 @@ public static class ModdedOptionsManager
RegisterOption(option, group, property.Name, pluginInfo);
}
private static void RegisterOption(
internal static void RegisterOption(
IModdedOption option,
AbstractOptionGroup group,
string propertyName,
-2
View File
@@ -42,8 +42,6 @@ public abstract class BaseModifier : IOptionable
x => x.Modifiers.Exists(y => y.TypeId == TypeId)
) ?? throw new InvalidOperationException("Modifier is not registered.");
internal ModifierOptionGroup? ModifierOptionsGroup { get; set; }
/// <summary>
/// Gets the modifier name.
/// </summary>
+16 -16
View File
@@ -63,32 +63,32 @@ public static class ModifierManager
IdToTypeModifierMap.Add(GetNextTypeId(), modifierType);
TypeToIdModifierMap.Add(modifierType, _nextTypeId);
var bm = (BaseModifier)FormatterServices.GetUninitializedObject(modifierType); // this probably isn't a great idea
info.Modifiers.Add(bm);
if (!typeof(GameModifier).IsAssignableFrom(modifierType))
BaseModifier modifier;
if (modifierType.GetConstructor(Type.EmptyTypes) != null)
{
modifier = (BaseModifier)Activator.CreateInstance(modifierType)!;
}
else
{
// this is probably terrible but its good enough for now.
modifier = (BaseModifier)FormatterServices.GetUninitializedObject(modifierType);
}
info.Modifiers.Add(modifier);
if (modifier is not GameModifier gameModifier)
{
return true;
}
if (modifierType.GetConstructor(Type.EmptyTypes) == null)
{
Logger<MiraApiPlugin>.Error($"Modifier {modifierType.FullName} does not have a parameterless constructor!");
Logger<MiraApiPlugin>.Error($"Game Modifier {modifierType.FullName} does not have a parameterless constructor!");
return false;
}
if (Activator.CreateInstance(modifierType) is not GameModifier mod)
{
Logger<MiraApiPlugin>.Error($"Modifier {modifierType.FullName} could not be cast to GameModifier!");
return false;
}
info.GameModifiers.Add(mod);
info.PluginConfig.Bind(mod.AmountDefinition, 0);
info.PluginConfig.Bind(mod.ChanceDefinition, 0);
var priority = mod!.Priority();
var priority = gameModifier.Priority();
if (!PrioritiesToIdsMap.TryGetValue(priority, out var list))
{
+3 -64
View File
@@ -1,10 +1,4 @@
using System;
using BepInEx.Configuration;
using MiraAPI.GameOptions.OptionTypes;
using MiraAPI.Utilities;
using Reactor.Utilities;
namespace MiraAPI.Modifiers.Types;
namespace MiraAPI.Modifiers.Types;
/// <summary>
/// The base class for a game modifier. Game modifiers are applied at the start of the game on top of the player's role.
@@ -14,72 +8,17 @@ public abstract class GameModifier : BaseModifier
/// <inheritdoc />
public override bool ShowInFreeplay => true;
/// <summary>
/// Gets the assignment configuration for the modifier.
/// </summary>
public virtual AssignmentConfiguration AssignmentConfiguration => new(0, 0, true, true);
internal ConfigDefinition AmountDefinition => new("Modifiers", $"Amount {GetType().FullName}");
internal ConfigDefinition ChanceDefinition => new("Modifiers", $"Chance {GetType().FullName}");
internal ModdedNumberOption AmountOption { get; } = new("Amount", 0, 0, 15, 1, MiraNumberSuffixes.None);
internal ModdedNumberOption ChanceOption { get; } = new("Chance", 0, 0, 100, 1, MiraNumberSuffixes.Percent);
/// <summary>
/// Gets the chance of the modifier being assigned to a player.
/// </summary>
/// <returns>An int value between 0 and 100 representing percent.</returns>
public virtual int GetAssignmentChance()
{
return AssignmentConfiguration.CreateChanceOption &&
ParentMod.PluginConfig.TryGetEntry(ChanceDefinition, out ConfigEntry<int> entry)
? entry.Value
: AssignmentConfiguration.DefaultChance;
}
public abstract int GetAssignmentChance();
/// <summary>
/// Gets the amount of players that can have this modifier in a game.
/// </summary>
/// <returns>An int value greater than or equal to zero.</returns>
public virtual int GetAmountPerGame()
{
return AssignmentConfiguration.CreateAmountOption &&
ParentMod.PluginConfig.TryGetEntry(AmountDefinition, out ConfigEntry<int> entry)
? entry.Value
: AssignmentConfiguration.DefaultAmount;
}
/// <summary>
/// Sets the chance of the modifier being assigned to a player.
/// </summary>
/// <param name="chance">The chance between 0 and 100.</param>
public virtual void SetAssignmentChance(int chance)
{
if (ParentMod.PluginConfig.TryGetEntry(ChanceDefinition, out ConfigEntry<int> entry))
{
entry.Value = Math.Clamp(chance, 0, 100);
return;
}
Logger<MiraApiPlugin>.Error($"Error getting chance configuration for modifier: {ModifierName}");
}
/// <summary>
/// Sets the amount of players that can have this modifier in a game.
/// </summary>
/// <param name="amount">The amount of players between zero and the max player count.</param>
public virtual void SetAmountPerGame(int amount)
{
if (ParentMod.PluginConfig.TryGetEntry(AmountDefinition, out ConfigEntry<int> entry))
{
entry.Value = Math.Max(amount, 0);
return;
}
Logger<MiraApiPlugin>.Error($"Error getting amount configuration for modifier: {ModifierName}");
}
public abstract int GetAmountPerGame();
/// <summary>
/// Gets the priority at which the modifier will spawn. The higher the value, the higher up on the assignment list.
+11 -24
View File
@@ -2,6 +2,7 @@
using System.Linq;
using HarmonyLib;
using MiraAPI.GameOptions;
using MiraAPI.Modifiers;
using MiraAPI.Modifiers.Types;
using MiraAPI.Roles;
using MiraAPI.Utilities;
@@ -44,7 +45,7 @@ public static class GameOptionsMenuPatch
{
var filteredGroups =
GameSettingMenuPatches.SelectedMod?.OptionGroups
.Where(x => x is not IOptionableGroup) ?? [];
.Where(x => x.OptionableType == null) ?? [];
foreach (var group in filteredGroups)
{
@@ -109,36 +110,22 @@ public static class GameOptionsMenuPatch
private static void ModifiersUpdate(ref float num)
{
var modifiers = GameSettingMenuPatches.SelectedMod?.Modifiers.Select(x=>x.ModifierOptionsGroup) ?? [];
var groups = GameSettingMenuPatches.SelectedMod?.OptionGroups
.Where(x => x.OptionableType?.IsAssignableTo(typeof(BaseModifier)) == true) ?? [];
foreach (var modGroup in modifiers)
foreach (var modGroup in groups)
{
if (modGroup != null)
{
UpdateGroup(modGroup, ref num);
}
UpdateGroup(modGroup, ref num);
}
}
private static void ModifiersCreate(GameOptionsMenu menu)
{
var modifiers = GameSettingMenuPatches.SelectedMod?.Modifiers ?? [];
var optLookup = GameSettingMenuPatches.SelectedMod?.OptionGroups
.OfType<IOptionableGroup>()
.ToLookup(x => x.OptionableType);
foreach (var mod in modifiers)
var groups = GameSettingMenuPatches.SelectedMod?.OptionGroups
.Where(x => x.OptionableType?.IsAssignableTo(typeof(BaseModifier))==true) ?? [];
foreach (var group in groups)
{
IModdedOption[] opts = mod is GameModifier gm ? [gm.AmountOption, gm.ChanceOption] : [];
if (optLookup?[mod.GetType()].Any() == false && opts.Length == 0)
{
continue;
}
var groups = optLookup?[mod.GetType()] ?? [];
mod.ModifierOptionsGroup = new ModifierOptionGroup(mod.ModifierName, opts, [.. groups.OfType<AbstractOptionGroup>()]);
CreateGroup(menu, mod.ModifierOptionsGroup);
CreateGroup(menu, group);
}
}
@@ -161,7 +148,7 @@ public static class GameOptionsMenuPatch
}
var filteredGroups = GameSettingMenuPatches.SelectedMod?.OptionGroups
.Where(x => x is not IOptionableGroup) ?? [];
.Where(x => x.OptionableType == null) ?? [];
foreach (var group in filteredGroups)
{
@@ -1,5 +1,8 @@
using System;
using System.Linq;
using HarmonyLib;
using MiraAPI.Modifiers;
using MiraAPI.Modifiers.Types;
using MiraAPI.PluginLoading;
using MiraAPI.Utilities.Assets;
using Reactor.Utilities.Extensions;
@@ -73,36 +76,43 @@ internal static class GameSettingMenuPatches
var nextButton = Object.Instantiate(__instance.BackButton, __instance.BackButton.transform.parent).gameObject;
nextButton.transform.localPosition = new Vector3(-2.2663f, 1.5272f, -25f);
nextButton.name = "RightArrowButton";
nextButton.transform.FindChild("Inactive").gameObject.GetComponent<SpriteRenderer>().sprite = MiraAssets.NextButton.LoadAsset();
nextButton.transform.FindChild("Active").gameObject.GetComponent<SpriteRenderer>().sprite = MiraAssets.NextButtonActive.LoadAsset();
nextButton.transform.FindChild("Inactive").gameObject.GetComponent<SpriteRenderer>().sprite =
MiraAssets.NextButton.LoadAsset();
nextButton.transform.FindChild("Active").gameObject.GetComponent<SpriteRenderer>().sprite =
MiraAssets.NextButtonActive.LoadAsset();
nextButton.gameObject.GetComponent<CloseButtonConsoleBehaviour>().DestroyImmediate();
var passiveButton = nextButton.gameObject.GetComponent<PassiveButton>();
passiveButton.OnClick = new ButtonClickedEvent();
passiveButton.OnClick.AddListener((UnityAction)(() =>
{
SelectedModIdx += 1;
if (SelectedModIdx > MiraPluginManager.Instance.RegisteredPlugins().Length)
passiveButton.OnClick.AddListener(
(UnityAction)(() =>
{
SelectedModIdx = 0;
}
UpdateText(__instance, __instance.GameSettingsTab, __instance.RoleSettingsTab);
}));
SelectedModIdx += 1;
if (SelectedModIdx > MiraPluginManager.Instance.RegisteredPlugins().Length)
{
SelectedModIdx = 0;
}
UpdateText(__instance, __instance.GameSettingsTab, __instance.RoleSettingsTab);
}));
var backButton = Object.Instantiate(nextButton, __instance.BackButton.transform.parent).gameObject;
backButton.transform.localPosition = new Vector3(-4.4209f, 1.5272f, -25f);
backButton.name = "LeftArrowButton";
backButton.gameObject.GetComponent<CloseButtonConsoleBehaviour>().Destroy();
backButton.transform.FindChild("Active").gameObject.GetComponent<SpriteRenderer>().flipX = backButton.transform.FindChild("Inactive").gameObject.GetComponent<SpriteRenderer>().flipX = true;
backButton.gameObject.GetComponent<PassiveButton>().OnClick.AddListener((UnityAction)(() =>
{
SelectedModIdx -= 1;
if (SelectedModIdx < 0)
backButton.transform.FindChild("Active").gameObject.GetComponent<SpriteRenderer>().flipX =
backButton.transform.FindChild("Inactive").gameObject.GetComponent<SpriteRenderer>().flipX = true;
backButton.gameObject.GetComponent<PassiveButton>().OnClick.AddListener(
(UnityAction)(() =>
{
SelectedModIdx = MiraPluginManager.Instance.RegisteredPlugins().Length;
}
UpdateText(__instance, __instance.GameSettingsTab, __instance.RoleSettingsTab);
}));
SelectedModIdx -= 1;
if (SelectedModIdx < 0)
{
SelectedModIdx = MiraPluginManager.Instance.RegisteredPlugins().Length;
}
UpdateText(__instance, __instance.GameSettingsTab, __instance.RoleSettingsTab);
}));
// clone game settings tab for modifiers
_modifiersTab = Object.Instantiate(__instance.GameSettingsTab, __instance.GameSettingsTab.transform.parent);
@@ -110,23 +120,33 @@ internal static class GameSettingMenuPatches
// create button for modifiers
__instance.RoleSettingsButton.gameObject.SetActive(false);
_smallRolesButton = Object.Instantiate(__instance.RoleSettingsButton, __instance.RoleSettingsButton.transform.parent);
var pos = new Vector3(-3.65f, _smallRolesButton.transform.localPosition.y, _smallRolesButton.transform.localPosition.z);
_smallRolesButton = Object.Instantiate(
__instance.RoleSettingsButton,
__instance.RoleSettingsButton.transform.parent);
var pos = new Vector3(
-3.65f,
_smallRolesButton.transform.localPosition.y,
_smallRolesButton.transform.localPosition.z);
_smallRolesButton.transform.localPosition = pos;
_smallRolesButton.OnClick.AddListener((UnityAction)(() =>
{
__instance.ChangeTab(2, false);
}));
_smallRolesButton.OnMouseOver.AddListener((UnityAction)(() =>
{
__instance.ChangeTab(2, true);
}));
_smallRolesButton.OnClick.AddListener(
(UnityAction)(() =>
{
__instance.ChangeTab(2, false);
}));
_smallRolesButton.OnMouseOver.AddListener(
(UnityAction)(() =>
{
__instance.ChangeTab(2, true);
}));
var roleText = _smallRolesButton.buttonText;
roleText.text = "Roles";
roleText.GetComponent<TextTranslatorTMP>().Destroy();
roleText.alignment = TextAlignmentOptions.Center;
roleText.transform.parent.localPosition = new Vector3(-.525f, roleText.transform.parent.localPosition.y, roleText.transform.parent.localPosition.z);
roleText.transform.parent.localPosition = new Vector3(
-.525f,
roleText.transform.parent.localPosition.y,
roleText.transform.parent.localPosition.z);
foreach (var collider in _smallRolesButton.Colliders)
{
@@ -135,6 +155,7 @@ internal static class GameSettingMenuPatches
col.size = new Vector2(col.size.x / 2, col.size.y);
}
}
foreach (var rend in _smallRolesButton.GetComponentsInChildren<SpriteRenderer>(true))
{
rend.size = new Vector2(rend.size.x / 2, rend.size.y);
@@ -142,15 +163,17 @@ internal static class GameSettingMenuPatches
_modifiersButton = Object.Instantiate(_smallRolesButton, _smallRolesButton.transform.parent);
_modifiersButton.OnClick = new ButtonClickedEvent();
_modifiersButton.OnClick.AddListener((UnityAction)(() =>
{
__instance.ChangeTab(3, false);
}));
_modifiersButton.OnClick.AddListener(
(UnityAction)(() =>
{
__instance.ChangeTab(3, false);
}));
_modifiersButton.OnMouseOver = new UnityEvent();
_modifiersButton.OnMouseOver.AddListener((UnityAction)(() =>
{
__instance.ChangeTab(3, true);
}));
_modifiersButton.OnMouseOver.AddListener(
(UnityAction)(() =>
{
__instance.ChangeTab(3, true);
}));
_modifiersButton.buttonText.text = "Modifiers";
pos.x = -2.27f;
@@ -179,7 +202,8 @@ internal static class GameSettingMenuPatches
_modifiersButton.gameObject.SetActive(false);
_smallRolesButton.gameObject.SetActive(false);
menu.RoleSettingsButton.gameObject.SetActive(false);
if (SelectedModIdx != 0 && SelectedMod?.GameModifiers.Count != 0)
if (SelectedModIdx != 0 &&
SelectedMod?.OptionGroups.Exists(x => x.OptionableType?.IsAssignableTo(typeof(BaseModifier)) == true) == true)
{
_modifiersButton.gameObject.SetActive(true);
_smallRolesButton.gameObject.SetActive(true);
@@ -225,11 +249,13 @@ internal static class GameSettingMenuPatches
{
child.gameObject.DestroyImmediate();
}
roles.advancedSettingChildren.Clear();
roles.advancedSettingChildren = null;
}
foreach (var header in roles.RoleChancesSettings.transform.GetComponentsInChildren<CategoryHeaderEditRole>())
foreach (var header in roles.RoleChancesSettings.transform
.GetComponentsInChildren<CategoryHeaderEditRole>())
{
header.gameObject.DestroyImmediate();
}
@@ -127,7 +127,7 @@ public static class LobbyViewPanePatches
var num = 1.44f;
var filteredGroups = SelectedMod.OptionGroups
.Where(x => x.GroupVisible.Invoke() && x is not IOptionableGroup);
.Where(x => x.OptionableType == null && x.GroupVisible.Invoke());
foreach (var group in filteredGroups)
{
@@ -280,7 +280,7 @@ public static class LobbyViewPanePatches
viewSettingsInfoPanelRoleVariant.transform.localPosition = new Vector3(num2, num, -2f);
var advancedRoleOptions = SelectedMod.OptionGroups
.Where(x => x is IOptionableGroup optionGroup && optionGroup.OptionableType == customRole.GetType())
.Where(x => x.OptionableType == customRole.GetType())
.SelectMany(x => x.Options)
.ToList();
@@ -390,7 +390,7 @@ public static class LobbyViewPanePatches
var num2 = 1.08f;
var filteredOptions = SelectedMod.OptionGroups
.Where(x => x is IOptionableGroup optionGroup && optionGroup.OptionableType == roleType)
.Where(x => x.OptionableType == roleType)
.SelectMany(x=>x.Options)
.ToList();
@@ -307,7 +307,7 @@ public static class RoleSettingMenuPatches
// TODO: create sub groups under the role settings.
var filteredOptions = GameSettingMenuPatches.SelectedMod?.OptionGroups
.Where(x=> x is IOptionableGroup optionableGroup && optionableGroup.OptionableType == role.GetType())
.Where(x=> x.OptionableType == role.GetType())
.SelectMany(x=>x.Options)
.ToList() ?? [];
@@ -471,7 +471,7 @@ public static class RoleSettingMenuPatches
if (GameSettingMenuPatches.SelectedMod is null ||
GameSettingMenuPatches.SelectedMod.OptionGroups
.Exists(x => x is IOptionableGroup optionGroup && optionGroup.OptionableType == role.GetType()))
.Exists(x => x.OptionableType == role.GetType()))
{
var newButton = Object.Instantiate(roleOptionSetting.buttons[0], roleOptionSetting.transform);
newButton.name = "ConfigButton";
-2
View File
@@ -74,8 +74,6 @@ public class MiraPluginInfo
internal List<BaseModifier> Modifiers { get; } = [];
internal List<GameModifier> GameModifiers { get; } = [];
internal Dictionary<ushort, RoleBehaviour> CustomRoles { get; } = [];
internal Dictionary<int, CustomGameMode> GameModes { get; } = [];
+3 -2
View File
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Reflection;
using BepInEx.Unity.IL2CPP;
@@ -78,7 +79,7 @@ public sealed class MiraPluginManager
if (RegisterRoleAttribute(type, info, out var role))
{
roles.Add(role!);
roles.Add(role);
continue;
}
@@ -172,7 +173,7 @@ public sealed class MiraPluginManager
return false;
}
private static bool RegisterRoleAttribute(Type type, MiraPluginInfo pluginInfo, out Type? role)
private static bool RegisterRoleAttribute(Type type, MiraPluginInfo pluginInfo, [NotNullWhen(true)] out Type? role)
{
role = null;
try