mirror of
https://github.com/All-Of-Us-Mods/MiraAPI.git
synced 2026-10-28 09:39:08 +00:00
Compare commits
38
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cf0bd6ec38 | ||
|
|
130236e899 | ||
|
|
3b7b247ac0 | ||
|
|
52de9a22de | ||
|
|
b94472ee07 | ||
|
|
f8056c29da | ||
|
|
8d4f2baf1e | ||
|
|
11ba3dae64 | ||
|
|
86145f94f4 | ||
|
|
e0da386567 | ||
|
|
6f1da2de9f | ||
|
|
b85358e304 | ||
|
|
2c901bb9b9 | ||
|
|
68f40a96b7 | ||
|
|
a96ffc42f2 | ||
|
|
0907b14893 | ||
|
|
32a44d646d | ||
|
|
8f590b94a8 | ||
|
|
2e769d79f2 | ||
|
|
41305ad0e2 | ||
|
|
2418e17af6 | ||
|
|
6fb0afe14e | ||
|
|
ab0063dd99 | ||
|
|
a35bf60870 | ||
|
|
692b9d7180 | ||
|
|
b99efaa420 | ||
|
|
2ecfa267d6 | ||
|
|
9afe821b0f | ||
|
|
a8d076656d | ||
|
|
429b64fc03 | ||
|
|
bf5dadc6a0 | ||
|
|
b2137230da | ||
|
|
9e8c05f21d | ||
|
|
2f56c95b39 | ||
|
|
38f72c42a3 | ||
|
|
5b608f5b3a | ||
|
|
2248726450 | ||
|
|
c60537cbd1 |
No files matched your search
+2
-1
@@ -1 +1,2 @@
|
|||||||
[*.{cs,vb}]
|
[*.{cs,vb}]
|
||||||
|
dotnet_diagnostic.CA1707.severity = none
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
using System;
|
|
||||||
using BepInEx;
|
|
||||||
using BepInEx.Unity.IL2CPP;
|
|
||||||
using HarmonyLib;
|
|
||||||
using MiraAPI.PluginLoading;
|
|
||||||
using Reactor;
|
|
||||||
using Reactor.Networking;
|
|
||||||
using Reactor.Networking.Attributes;
|
|
||||||
|
|
||||||
namespace MiraAPI.Example.Extension;
|
|
||||||
|
|
||||||
[BepInAutoPlugin("mira.example.extension", "MiraExampleExtensionMod")]
|
|
||||||
[BepInProcess("Among Us.exe")]
|
|
||||||
[BepInDependency(ReactorPlugin.Id)]
|
|
||||||
[BepInDependency(MiraApiPlugin.Id)]
|
|
||||||
[BepInDependency(ExamplePlugin.Id)]
|
|
||||||
[ReactorModFlags(ModFlags.RequireOnAllClients)]
|
|
||||||
public partial class ExampleExtensionPlugin : BasePlugin, IMiraExtension
|
|
||||||
{
|
|
||||||
public Harmony Harmony { get; } = new(Id);
|
|
||||||
|
|
||||||
public override void Load()
|
|
||||||
{
|
|
||||||
Harmony.PatchAll();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Type GetBasePluginType()
|
|
||||||
{
|
|
||||||
return typeof(ExamplePlugin);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
|
||||||
<PropertyGroup>
|
|
||||||
<Version>1.0.0</Version>
|
|
||||||
<Description>Example extension for Mira API</Description>
|
|
||||||
<Authors>Angxl, XtraCube</Authors>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<ProjectReference Include="..\MiraAPI\MiraAPI.csproj" />
|
|
||||||
<ProjectReference Include="..\MiraAPI.Example\MiraAPI.Example.csproj" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<Import Project="..\AmongUs.props" />
|
|
||||||
</Project>
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
using MiraAPI.Example.Extension.Options;
|
|
||||||
using MiraAPI.GameOptions;
|
|
||||||
using MiraAPI.Modifiers.Types;
|
|
||||||
|
|
||||||
namespace MiraAPI.Example.Extension.Modifiers;
|
|
||||||
|
|
||||||
public class ExtensionModifier : GameModifier
|
|
||||||
{
|
|
||||||
public override string ModifierName => "Extension Modifier";
|
|
||||||
|
|
||||||
public override string GetDescription() => "This is from the extension mod!";
|
|
||||||
|
|
||||||
public override int GetAssignmentChance() => (int)OptionGroupSingleton<ExtensionModifierOptions>.Instance.ModifierChance;
|
|
||||||
|
|
||||||
public override int GetAmountPerGame() => (int)OptionGroupSingleton<ExtensionModifierOptions>.Instance.ModifierLimit;
|
|
||||||
}
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
using MiraAPI.Example.Roles;
|
|
||||||
using MiraAPI.GameOptions;
|
|
||||||
using MiraAPI.GameOptions.Attributes;
|
|
||||||
|
|
||||||
namespace MiraAPI.Example.Extension.Options;
|
|
||||||
|
|
||||||
public class ExtendedFreezerOptions : AbstractOptionGroup<FreezerRole>
|
|
||||||
{
|
|
||||||
public override string GroupName => "Extended Freezer Role Options";
|
|
||||||
|
|
||||||
[ModdedNumberOption("Freeze Uses", 1, 5)]
|
|
||||||
public float FreezeUses { get; set; } = 1;
|
|
||||||
}
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
using MiraAPI.Example.Extension.Modifiers;
|
|
||||||
using MiraAPI.GameOptions;
|
|
||||||
using MiraAPI.GameOptions.Attributes;
|
|
||||||
using MiraAPI.Utilities;
|
|
||||||
|
|
||||||
namespace MiraAPI.Example.Extension.Options;
|
|
||||||
|
|
||||||
public class ExtensionModifierOptions : AbstractOptionGroup<ExtensionModifier>
|
|
||||||
{
|
|
||||||
public override string GroupName => "Extension Modifier Options";
|
|
||||||
|
|
||||||
[ModdedNumberOption("Modifier Chance", 0, 100, 10, MiraNumberSuffixes.Percent)]
|
|
||||||
public float ModifierChance { get; set; } = 100f;
|
|
||||||
|
|
||||||
[ModdedNumberOption("Modifier Limit", 0, 10)]
|
|
||||||
public float ModifierLimit { get; set; } = 0;
|
|
||||||
}
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
using HarmonyLib;
|
|
||||||
using MiraAPI.Example.Buttons.Freezer;
|
|
||||||
using MiraAPI.Example.Extension.Options;
|
|
||||||
using MiraAPI.GameOptions;
|
|
||||||
|
|
||||||
namespace MiraAPI.Example.Extension.Patches;
|
|
||||||
|
|
||||||
[HarmonyPatch(typeof(FreezeButton), nameof(FreezeButton.MaxUses), MethodType.Getter)]
|
|
||||||
public static class FreezeButtonPatch
|
|
||||||
{
|
|
||||||
public static void Postfix(ref int __result)
|
|
||||||
{
|
|
||||||
__result = (int)OptionGroupSingleton<ExtendedFreezerOptions>.Instance.FreezeUses;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -16,7 +16,7 @@ public class FreezeButton : CustomActionButton<PlayerControl>
|
|||||||
|
|
||||||
public override float Cooldown => OptionGroupSingleton<FreezerRoleSettings>.Instance.FreezeDuration;
|
public override float Cooldown => OptionGroupSingleton<FreezerRoleSettings>.Instance.FreezeDuration;
|
||||||
|
|
||||||
public override int MaxUses => 1;
|
public override int MaxUses => (int)OptionGroupSingleton<FreezerRoleSettings>.Instance.FreezeUses;
|
||||||
|
|
||||||
public override LoadableAsset<Sprite> Sprite => ExampleAssets.ExampleButton;
|
public override LoadableAsset<Sprite> Sprite => ExampleAssets.ExampleButton;
|
||||||
|
|
||||||
|
|||||||
+3
-6
@@ -1,20 +1,17 @@
|
|||||||
using MiraAPI.Example.Extension.GameOver;
|
using MiraAPI.Example.GameOver;
|
||||||
using MiraAPI.Example.Extension.Roles;
|
using MiraAPI.Example.Roles;
|
||||||
using MiraAPI.GameEnd;
|
using MiraAPI.GameEnd;
|
||||||
using MiraAPI.Hud;
|
using MiraAPI.Hud;
|
||||||
using MiraAPI.Utilities.Assets;
|
using MiraAPI.Utilities.Assets;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
||||||
namespace MiraAPI.Example.Extension.Buttons;
|
namespace MiraAPI.Example.Buttons;
|
||||||
|
|
||||||
public class NeutralKillerButton : CustomActionButton
|
public class NeutralKillerButton : CustomActionButton
|
||||||
{
|
{
|
||||||
public override string Name => "Win Game";
|
public override string Name => "Win Game";
|
||||||
|
|
||||||
public override float Cooldown => 0f;
|
public override float Cooldown => 0f;
|
||||||
|
|
||||||
public override LoadableAsset<Sprite> Sprite => ExampleAssets.ExampleButton;
|
public override LoadableAsset<Sprite> Sprite => ExampleAssets.ExampleButton;
|
||||||
|
|
||||||
protected override void OnClick()
|
protected override void OnClick()
|
||||||
{
|
{
|
||||||
CustomGameOver.Trigger<NeutralKillerGameOver>([PlayerControl.LocalPlayer.Data]);
|
CustomGameOver.Trigger<NeutralKillerGameOver>([PlayerControl.LocalPlayer.Data]);
|
||||||
@@ -9,7 +9,10 @@ using MiraAPI.Events.Vanilla.Player;
|
|||||||
using MiraAPI.Example.Buttons.Freezer;
|
using MiraAPI.Example.Buttons.Freezer;
|
||||||
using MiraAPI.Example.Roles;
|
using MiraAPI.Example.Roles;
|
||||||
using MiraAPI.Utilities;
|
using MiraAPI.Utilities;
|
||||||
|
using MiraAPI.Utilities.Assets;
|
||||||
using Reactor.Utilities;
|
using Reactor.Utilities;
|
||||||
|
using TMPro;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
namespace MiraAPI.Example;
|
namespace MiraAPI.Example;
|
||||||
|
|
||||||
@@ -18,7 +21,7 @@ public static class ExampleEventHandlers
|
|||||||
public static void Initialize()
|
public static void Initialize()
|
||||||
{
|
{
|
||||||
// You can register event handlers with the MiraEventManager class.
|
// You can register event handlers with the MiraEventManager class.
|
||||||
var handle = MiraEventManager.RegisterEventHandler<BeforeMurderEvent>(@event =>
|
MiraEventManager.RegisterEventHandler<BeforeMurderEvent>(@event =>
|
||||||
{
|
{
|
||||||
Logger<ExamplePlugin>.Info($"{@event.Source.Data.PlayerName} is about to kill {@event.Target.Data.PlayerName}");
|
Logger<ExamplePlugin>.Info($"{@event.Source.Data.PlayerName} is about to kill {@event.Target.Data.PlayerName}");
|
||||||
});
|
});
|
||||||
@@ -32,9 +35,6 @@ public static class ExampleEventHandlers
|
|||||||
{
|
{
|
||||||
Logger<ExamplePlugin>.Info($"{@event.Player.Data.PlayerName} completed {@event.Task.TaskType.ToString()}");
|
Logger<ExamplePlugin>.Info($"{@event.Player.Data.PlayerName} completed {@event.Task.TaskType.ToString()}");
|
||||||
});
|
});
|
||||||
|
|
||||||
// You can also unregister event handlers using the handle returned from RegisterEventHandler.
|
|
||||||
MiraEventManager.UnregisterEventHandler(handle);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If you want to add extra votes to a player, do something like this.
|
// If you want to add extra votes to a player, do something like this.
|
||||||
@@ -51,7 +51,7 @@ public static class ExampleEventHandlers
|
|||||||
[RegisterEvent(15)]
|
[RegisterEvent(15)]
|
||||||
public static void HandleVoteEvent(HandleVoteEvent @event)
|
public static void HandleVoteEvent(HandleVoteEvent @event)
|
||||||
{
|
{
|
||||||
if (@event.VoteData.Owner.Data.Role is not FreezerRole) return;
|
if (@event.VoteData.Owner.Data.Role is not NeutralKillerRole) return;
|
||||||
|
|
||||||
@event.VoteData.SetRemainingVotes(0);
|
@event.VoteData.SetRemainingVotes(0);
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -1,9 +1,9 @@
|
|||||||
using MiraAPI.Example.Extension.Roles;
|
using MiraAPI.Example.Roles;
|
||||||
using MiraAPI.GameEnd;
|
using MiraAPI.GameEnd;
|
||||||
using MiraAPI.Utilities;
|
using MiraAPI.Utilities;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
||||||
namespace MiraAPI.Example.Extension.GameOver;
|
namespace MiraAPI.Example.GameOver;
|
||||||
|
|
||||||
public class NeutralKillerGameOver : CustomGameOver
|
public class NeutralKillerGameOver : CustomGameOver
|
||||||
{
|
{
|
||||||
@@ -1,9 +1,12 @@
|
|||||||
using MiraAPI.Example.Options.Modifiers;
|
using Il2CppSystem.Collections.Generic;
|
||||||
|
using MiraAPI.Example.Options.Modifiers;
|
||||||
using MiraAPI.GameOptions;
|
using MiraAPI.GameOptions;
|
||||||
using MiraAPI.Modifiers;
|
using MiraAPI.Modifiers;
|
||||||
using MiraAPI.Modifiers.Types;
|
using MiraAPI.Modifiers.Types;
|
||||||
using MiraAPI.Utilities.Assets;
|
using MiraAPI.Utilities.Assets;
|
||||||
|
using Reactor.Utilities.Extensions;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
using Random = System.Random;
|
||||||
|
|
||||||
namespace MiraAPI.Example.Modifiers;
|
namespace MiraAPI.Example.Modifiers;
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
using MiraAPI.Modifiers.Types;
|
using MiraAPI.Modifiers.Types;
|
||||||
|
using MiraAPI.Utilities.Assets;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
namespace MiraAPI.Example.Modifiers;
|
namespace MiraAPI.Example.Modifiers;
|
||||||
|
|
||||||
|
|||||||
@@ -11,4 +11,7 @@ public class FreezerRoleSettings : AbstractOptionGroup<FreezerRole>
|
|||||||
|
|
||||||
[ModdedNumberOption("Freeze Duration", 1, 15, 1, MiraNumberSuffixes.Seconds)]
|
[ModdedNumberOption("Freeze Duration", 1, 15, 1, MiraNumberSuffixes.Seconds)]
|
||||||
public float FreezeDuration { get; set; } = 5;
|
public float FreezeDuration { get; set; } = 5;
|
||||||
|
|
||||||
|
[ModdedNumberOption("Freeze Uses", 1, 5)]
|
||||||
|
public float FreezeUses { get; set; } = 1;
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
using AmongUs.GameOptions;
|
using AmongUs.GameOptions;
|
||||||
using MiraAPI.Patches.Stubs;
|
|
||||||
using MiraAPI.Roles;
|
using MiraAPI.Roles;
|
||||||
using Reactor.Utilities;
|
using Reactor.Utilities;
|
||||||
using TMPro;
|
using TMPro;
|
||||||
@@ -15,8 +14,6 @@ public class ChameloenRole : CrewmateRole, ICustomRole
|
|||||||
public Color RoleColor => Palette.AcceptedGreen;
|
public Color RoleColor => Palette.AcceptedGreen;
|
||||||
public ModdedRoleTeams Team => ModdedRoleTeams.Crewmate;
|
public ModdedRoleTeams Team => ModdedRoleTeams.Crewmate;
|
||||||
|
|
||||||
private bool _shouldHide;
|
|
||||||
|
|
||||||
public CustomRoleConfiguration Configuration => new(this)
|
public CustomRoleConfiguration Configuration => new(this)
|
||||||
{
|
{
|
||||||
OptionsScreenshot = ExampleAssets.Banner,
|
OptionsScreenshot = ExampleAssets.Banner,
|
||||||
@@ -25,54 +22,35 @@ public class ChameloenRole : CrewmateRole, ICustomRole
|
|||||||
|
|
||||||
public override void Initialize(PlayerControl player)
|
public override void Initialize(PlayerControl player)
|
||||||
{
|
{
|
||||||
Logger<ExamplePlugin>.Info("Initializing ChamelonRole for player: " + player.PlayerId);
|
Player = player;
|
||||||
RoleBehaviourStubs.Initialize(this, player);
|
Logger<ExamplePlugin>.Error("Initializing ChamelonRole for player: " + player.PlayerId);
|
||||||
_shouldHide = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void FixedUpdate()
|
public void PlayerControlFixedUpdate(PlayerControl playerControl)
|
||||||
{
|
{
|
||||||
if (!Player || !_shouldHide)
|
if (playerControl.MyPhysics.Velocity.magnitude > 0)
|
||||||
{
|
{
|
||||||
return;
|
SpriteRenderer rend = playerControl.cosmetics.currentBodySprite.BodySprite;
|
||||||
}
|
TextMeshPro tmp = playerControl.cosmetics.nameText;
|
||||||
|
|
||||||
if (Player.MyPhysics.Velocity.magnitude > 0)
|
|
||||||
{
|
|
||||||
var rend = Player.cosmetics.currentBodySprite.BodySprite;
|
|
||||||
var tmp = Player.cosmetics.nameText;
|
|
||||||
tmp.color = Color.Lerp(tmp.color, new Color(tmp.color.r, tmp.color.g, tmp.color.b, 1), Time.deltaTime * 4f);
|
tmp.color = Color.Lerp(tmp.color, new Color(tmp.color.r, tmp.color.g, tmp.color.b, 1), Time.deltaTime * 4f);
|
||||||
rend.color = Color.Lerp(rend.color, new Color(1, 1, 1, 1), Time.deltaTime * 4f);
|
rend.color = Color.Lerp(rend.color, new Color(1, 1, 1, 1), Time.deltaTime * 4f);
|
||||||
|
|
||||||
foreach (var cosmetic in Player.cosmetics.transform.GetComponentsInChildren<SpriteRenderer>())
|
foreach (var cosmetic in playerControl.cosmetics.transform.GetComponentsInChildren<SpriteRenderer>())
|
||||||
{
|
{
|
||||||
cosmetic.color = Color.Lerp(cosmetic.color, new Color(1, 1, 1, 1), Time.deltaTime * 4f);
|
cosmetic.color = Color.Lerp(cosmetic.color, new Color(1, 1, 1, 1), Time.deltaTime * 4f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
SpriteRenderer rend = Player.cosmetics.currentBodySprite.BodySprite;
|
SpriteRenderer rend = playerControl.cosmetics.currentBodySprite.BodySprite;
|
||||||
TextMeshPro tmp = Player.cosmetics.nameText;
|
TextMeshPro tmp = playerControl.cosmetics.nameText;
|
||||||
tmp.color = Color.Lerp(tmp.color, new Color(tmp.color.r, tmp.color.g, tmp.color.b, Player.AmOwner ? 0.3f : 0), Time.deltaTime * 4f);
|
tmp.color = Color.Lerp(tmp.color, new Color(tmp.color.r, tmp.color.g, tmp.color.b, playerControl.AmOwner ? 0.3f : 0), Time.deltaTime * 4f);
|
||||||
rend.color = Color.Lerp(rend.color, new Color(1, 1, 1, Player.AmOwner ? 0.3f : 0), Time.deltaTime * 4f);
|
rend.color = Color.Lerp(rend.color, new Color(1, 1, 1, playerControl.AmOwner ? 0.3f : 0), Time.deltaTime * 4f);
|
||||||
|
|
||||||
foreach (var cosmetic in Player.cosmetics.transform.GetComponentsInChildren<SpriteRenderer>())
|
foreach (var cosmetic in playerControl.cosmetics.transform.GetComponentsInChildren<SpriteRenderer>())
|
||||||
{
|
{
|
||||||
cosmetic.color = Color.Lerp(cosmetic.color, new Color(1, 1, 1, Player.AmOwner ? 0.3f : 0), Time.deltaTime * 4f);
|
cosmetic.color = Color.Lerp(cosmetic.color, new Color(1, 1, 1, playerControl.AmOwner ? 0.3f : 0), Time.deltaTime * 4f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Deinitialize(PlayerControl targetPlayer)
|
|
||||||
{
|
|
||||||
Logger<ExamplePlugin>.Info("Deinitializing ChamelonRole for player: " + targetPlayer.PlayerId);
|
|
||||||
RoleBehaviourStubs.Deinitialize(this, targetPlayer);
|
|
||||||
_shouldHide = false;
|
|
||||||
foreach (var cosmetic in Player.cosmetics.transform.GetComponentsInChildren<SpriteRenderer>(true))
|
|
||||||
{
|
|
||||||
cosmetic.color = Color.white;
|
|
||||||
}
|
|
||||||
Player.cosmetics.currentBodySprite.BodySprite.color = Color.white;
|
|
||||||
Player.cosmetics.nameText.color = Color.white;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
+3
-7
@@ -1,20 +1,16 @@
|
|||||||
using MiraAPI.Example.Extension.GameOver;
|
using MiraAPI.Example.GameOver;
|
||||||
using MiraAPI.GameEnd;
|
using MiraAPI.GameEnd;
|
||||||
using MiraAPI.Roles;
|
using MiraAPI.Roles;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
||||||
namespace MiraAPI.Example.Extension.Roles;
|
namespace MiraAPI.Example.Roles;
|
||||||
|
|
||||||
public class NeutralKillerRole : ImpostorRole, ICustomRole
|
public class NeutralKillerRole : ImpostorRole, ICustomRole
|
||||||
{
|
{
|
||||||
public string RoleName => "Outcast Killer";
|
public string RoleName => "Outcast Killer";
|
||||||
|
|
||||||
public string RoleDescription => "Outcast who can kill.";
|
public string RoleDescription => "Outcast who can kill.";
|
||||||
|
public string RoleLongDescription => RoleDescription;
|
||||||
public string RoleLongDescription => this.RoleDescription;
|
|
||||||
|
|
||||||
public Color RoleColor => Color.magenta;
|
public Color RoleColor => Color.magenta;
|
||||||
|
|
||||||
public ModdedRoleTeams Team => ModdedRoleTeams.Custom;
|
public ModdedRoleTeams Team => ModdedRoleTeams.Custom;
|
||||||
|
|
||||||
public CustomRoleConfiguration Configuration => new(this)
|
public CustomRoleConfiguration Configuration => new(this)
|
||||||
@@ -7,8 +7,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MiraAPI", "MiraAPI\MiraAPI.
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MiraAPI.Example", "MiraAPI.Example\MiraAPI.Example.csproj", "{19B76855-16CC-43CC-A0A6-5A7FFB43F077}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MiraAPI.Example", "MiraAPI.Example\MiraAPI.Example.csproj", "{19B76855-16CC-43CC-A0A6-5A7FFB43F077}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MiraAPI.Example.Extension", "MiraAPI.Example.Extension\MiraAPI.Example.Extension.csproj", "{526FF017-80E1-4094-804D-741AF35AA226}"
|
|
||||||
EndProject
|
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
@@ -23,10 +21,6 @@ Global
|
|||||||
{19B76855-16CC-43CC-A0A6-5A7FFB43F077}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{19B76855-16CC-43CC-A0A6-5A7FFB43F077}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{19B76855-16CC-43CC-A0A6-5A7FFB43F077}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{19B76855-16CC-43CC-A0A6-5A7FFB43F077}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{19B76855-16CC-43CC-A0A6-5A7FFB43F077}.Release|Any CPU.Build.0 = Release|Any CPU
|
{19B76855-16CC-43CC-A0A6-5A7FFB43F077}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
{526FF017-80E1-4094-804D-741AF35AA226}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{526FF017-80E1-4094-804D-741AF35AA226}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{526FF017-80E1-4094-804D-741AF35AA226}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{526FF017-80E1-4094-804D-741AF35AA226}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
|||||||
@@ -1,22 +0,0 @@
|
|||||||
using System;
|
|
||||||
|
|
||||||
namespace MiraAPI.Events;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Event handle to use when unregistering an event.
|
|
||||||
/// </summary>
|
|
||||||
public class MiraEventHandle
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the type of event.
|
|
||||||
/// </summary>
|
|
||||||
public Type EventType { get; }
|
|
||||||
|
|
||||||
internal MiraEventWrapper EventWrapper { get; }
|
|
||||||
|
|
||||||
internal MiraEventHandle(Type type, MiraEventWrapper eventWrapper)
|
|
||||||
{
|
|
||||||
EventType = type;
|
|
||||||
EventWrapper = eventWrapper;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -28,14 +28,7 @@ public static class MiraEventManager
|
|||||||
|
|
||||||
foreach (var handler in handlers)
|
foreach (var handler in handlers)
|
||||||
{
|
{
|
||||||
try
|
((Action<T>)handler.EventHandler).Invoke(eventInstance);
|
||||||
{
|
|
||||||
((Action<T>)handler.EventHandler).Invoke(eventInstance);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Logger<MiraApiPlugin>.Error($"Error invoking event handler for {typeof(T).Name}: {ex.ToString()}");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -57,14 +50,7 @@ public static class MiraEventManager
|
|||||||
|
|
||||||
foreach (var handler in handlers)
|
foreach (var handler in handlers)
|
||||||
{
|
{
|
||||||
try
|
handler.EventHandler.DynamicInvoke(eventInstance);
|
||||||
{
|
|
||||||
handler.EventHandler.DynamicInvoke(eventInstance);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Logger<MiraApiPlugin>.Error($"Error invoking event handler for {type.Name}: {ex.ToString()}");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -76,12 +62,12 @@ public static class MiraEventManager
|
|||||||
/// <param name="type">The type of event.</param>
|
/// <param name="type">The type of event.</param>
|
||||||
/// <param name="methodInfo">The MethodInfo of the event handler.</param>
|
/// <param name="methodInfo">The MethodInfo of the event handler.</param>
|
||||||
/// <param name="priority">The priority of the event handler. Lower values are called first.</param>
|
/// <param name="priority">The priority of the event handler. Lower values are called first.</param>
|
||||||
/// <returns>An event handle to use when unregistering the event.</returns>
|
public static void RegisterEventHandler(Type type, MethodInfo methodInfo, int priority = 0)
|
||||||
public static MiraEventHandle RegisterEventHandler(Type type, MethodInfo methodInfo, int priority = 0)
|
|
||||||
{
|
{
|
||||||
if (!type.IsSubclassOf(typeof(MiraEvent)))
|
if (!type.IsSubclassOf(typeof(MiraEvent)))
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException($"Type must be a subclass of MiraEvent: {type.FullName}");
|
Logger<MiraApiPlugin>.Error($"Type must be a subclass of MiraEvent: {type.FullName}");
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
EventWrappers.TryAdd(type, []);
|
EventWrappers.TryAdd(type, []);
|
||||||
@@ -98,7 +84,6 @@ public static class MiraEventManager
|
|||||||
}
|
}
|
||||||
|
|
||||||
handlers.Insert(index, eventWrapper);
|
handlers.Insert(index, eventWrapper);
|
||||||
return new MiraEventHandle(type, eventWrapper);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -107,8 +92,7 @@ public static class MiraEventManager
|
|||||||
/// <param name="handler">The callback method/handler for the event.</param>
|
/// <param name="handler">The callback method/handler for the event.</param>
|
||||||
/// <param name="priority">The priority of the event handler. Lower values are called first.</param>
|
/// <param name="priority">The priority of the event handler. Lower values are called first.</param>
|
||||||
/// <typeparam name="T">Type of event.</typeparam>
|
/// <typeparam name="T">Type of event.</typeparam>
|
||||||
/// <returns>An event handle to use when unregistering the event.</returns>
|
public static void RegisterEventHandler<T>(Action<T> handler, int priority = 0) where T : MiraEvent
|
||||||
public static MiraEventHandle RegisterEventHandler<T>(Action<T> handler, int priority = 0) where T : MiraEvent
|
|
||||||
{
|
{
|
||||||
EventWrappers.TryAdd(typeof(T), []);
|
EventWrappers.TryAdd(typeof(T), []);
|
||||||
|
|
||||||
@@ -123,30 +107,5 @@ public static class MiraEventManager
|
|||||||
}
|
}
|
||||||
|
|
||||||
handlers.Insert(index, eventWrapper);
|
handlers.Insert(index, eventWrapper);
|
||||||
return new MiraEventHandle(typeof(T), eventWrapper);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Unregister an event using the event handle.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="eventHandle">A handle to the event.</param>
|
|
||||||
/// <returns>True if the event was unregistered successfully, false otherwise.</returns>
|
|
||||||
public static bool UnregisterEventHandler(MiraEventHandle eventHandle)
|
|
||||||
{
|
|
||||||
if (!EventWrappers.TryGetValue(eventHandle.EventType, out var handlers))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!handlers.Remove(eventHandle.EventWrapper))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (handlers.Count == 0)
|
|
||||||
{
|
|
||||||
EventWrappers.Remove(eventHandle.EventType);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -15,21 +15,14 @@ public class AfterMurderEvent : MiraEvent
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public PlayerControl Target { get; }
|
public PlayerControl Target { get; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the player's body, if it exists.
|
|
||||||
/// </summary>
|
|
||||||
public DeadBody? DeadBody { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="AfterMurderEvent"/> class.
|
/// Initializes a new instance of the <see cref="AfterMurderEvent"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="source">The killer.</param>
|
/// <param name="source">The killer.</param>
|
||||||
/// <param name="target">The killed player.</param>
|
/// <param name="target">The killed player.</param>
|
||||||
/// <param name="deadBody">The player's vody, if it exists.</param>
|
public AfterMurderEvent(PlayerControl source, PlayerControl target)
|
||||||
public AfterMurderEvent(PlayerControl source, PlayerControl target, DeadBody? deadBody)
|
|
||||||
{
|
{
|
||||||
Source = source;
|
Source = source;
|
||||||
Target = target;
|
Target = target;
|
||||||
DeadBody = deadBody;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -24,7 +24,6 @@ public class UpdateSystemEvent : MiraCancelableEvent
|
|||||||
/// Initializes a new instance of the <see cref="UpdateSystemEvent"/> class.
|
/// Initializes a new instance of the <see cref="UpdateSystemEvent"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="systemType">The SystemType being updated.</param>
|
/// <param name="systemType">The SystemType being updated.</param>
|
||||||
/// <param name="player">The player that is updating the system.</param>
|
|
||||||
/// <param name="amount">Amount to update System to.</param>
|
/// <param name="amount">Amount to update System to.</param>
|
||||||
public UpdateSystemEvent(SystemTypes systemType, PlayerControl player, byte amount)
|
public UpdateSystemEvent(SystemTypes systemType, PlayerControl player, byte amount)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -15,21 +15,14 @@ public class PlayerDeathEvent : MiraEvent
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public DeathReason DeathReason { get; }
|
public DeathReason DeathReason { get; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the dead body associated with the player, if any.
|
|
||||||
/// </summary>
|
|
||||||
public DeadBody? DeadBody { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="PlayerDeathEvent"/> class.
|
/// Initializes a new instance of the <see cref="PlayerDeathEvent"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="player">The player who died.</param>
|
/// <param name="player">The player who died.</param>
|
||||||
/// <param name="reason">The reason the player died.</param>
|
/// <param name="reason">The reason the player died.</param>
|
||||||
/// <param name="deadBody">The player's body, if it exists.</param>
|
public PlayerDeathEvent(PlayerControl player, DeathReason reason)
|
||||||
public PlayerDeathEvent(PlayerControl player, DeathReason reason, DeadBody? deadBody)
|
|
||||||
{
|
{
|
||||||
Player = player;
|
Player = player;
|
||||||
DeathReason = reason;
|
DeathReason = reason;
|
||||||
DeadBody = deadBody;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -21,7 +21,7 @@ public static class CustomGameModeManager
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the current gamemode.
|
/// Current gamemode.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static CustomGameMode? ActiveMode { get; internal set; } = new DefaultMode();
|
public static CustomGameMode? ActiveMode { get; internal set; } = new DefaultMode();
|
||||||
|
|
||||||
|
|||||||
@@ -46,6 +46,11 @@ public interface IModdedOption
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
Func<bool> Visible { get; set; }
|
Func<bool> Visible { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets a value indicating whether the option should be included with presets.
|
||||||
|
/// </summary>
|
||||||
|
bool IncludeInPreset { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the ConfigDefinition for the option, used for BepInEx configuration.
|
/// Gets or sets the ConfigDefinition for the option, used for BepInEx configuration.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -78,4 +83,23 @@ public interface IModdedOption
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="data">>The byte array representing the network data.</param>
|
/// <param name="data">>The byte array representing the network data.</param>
|
||||||
void HandleNetData(byte[] data);
|
void HandleNetData(byte[] data);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Saves the option to a preset configuration file.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="presetConfig">The ConfigFile representing the preset configuration.</param>
|
||||||
|
/// <param name="saveDefault">Indicates whether to save the default value instead of the current value.</param>
|
||||||
|
void SaveToPreset(ConfigFile presetConfig, bool saveDefault = false);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Binds the option to a configuration file.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="config">The ConfigFile to bind the option to.</param>
|
||||||
|
void Bind(ConfigFile config);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Loads the option from a preset configuration file, applying the values to the option's configuration.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="presetConfig">The ConfigFile representing the preset configuration.</param>
|
||||||
|
void LoadFromPreset(ConfigFile presetConfig);
|
||||||
}
|
}
|
||||||
@@ -42,12 +42,10 @@ public static class ModdedOptionsManager
|
|||||||
|
|
||||||
Groups.Add(group);
|
Groups.Add(group);
|
||||||
TypeToGroup.Add(type, group);
|
TypeToGroup.Add(type, group);
|
||||||
pluginInfo.OptionGroups.Add(group);
|
pluginInfo.InternalOptionGroups.Add(group);
|
||||||
|
|
||||||
typeof(OptionGroupSingleton<>).MakeGenericType(type)
|
typeof(OptionGroupSingleton<>).MakeGenericType(type)
|
||||||
#pragma warning disable S3011
|
|
||||||
.GetField("_instance", BindingFlags.Static | BindingFlags.NonPublic)!
|
.GetField("_instance", BindingFlags.Static | BindingFlags.NonPublic)!
|
||||||
#pragma warning restore S3011
|
|
||||||
.SetValue(null, group);
|
.SetValue(null, group);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -121,7 +119,7 @@ public static class ModdedOptionsManager
|
|||||||
option.ConfigDefinition = new ConfigDefinition(groupName, propertyName);
|
option.ConfigDefinition = new ConfigDefinition(groupName, propertyName);
|
||||||
|
|
||||||
option.ParentMod = pluginInfo.MiraPlugin;
|
option.ParentMod = pluginInfo.MiraPlugin;
|
||||||
pluginInfo.Options.Add(option);
|
pluginInfo.InternalOptions.Add(option);
|
||||||
ModdedOptions.Add(option.Id, option);
|
ModdedOptions.Add(option.Id, option);
|
||||||
group.Options.Add(option);
|
group.Options.Add(option);
|
||||||
}
|
}
|
||||||
@@ -142,7 +140,7 @@ public static class ModdedOptionsManager
|
|||||||
// we dont know how other plugins handle their configs
|
// we dont know how other plugins handle their configs
|
||||||
// this way, all the options are saved at once, instead of one by one
|
// this way, all the options are saved at once, instead of one by one
|
||||||
var oldConfigSetting = new Dictionary<MiraPluginInfo, bool>();
|
var oldConfigSetting = new Dictionary<MiraPluginInfo, bool>();
|
||||||
foreach (var plugin in MiraPluginManager.Instance.RegisteredPlugins())
|
foreach (var plugin in MiraPluginManager.Instance.RegisteredPlugins)
|
||||||
{
|
{
|
||||||
oldConfigSetting.Add(plugin, plugin.PluginConfig.SaveOnConfigSet);
|
oldConfigSetting.Add(plugin, plugin.PluginConfig.SaveOnConfigSet);
|
||||||
plugin.PluginConfig.SaveOnConfigSet = false;
|
plugin.PluginConfig.SaveOnConfigSet = false;
|
||||||
@@ -158,7 +156,7 @@ public static class ModdedOptionsManager
|
|||||||
option.HandleNetData(netData.Data);
|
option.HandleNetData(netData.Data);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var plugin in MiraPluginManager.Instance.RegisteredPlugins())
|
foreach (var plugin in MiraPluginManager.Instance.RegisteredPlugins)
|
||||||
{
|
{
|
||||||
plugin.PluginConfig.Save();
|
plugin.PluginConfig.Save();
|
||||||
plugin.PluginConfig.SaveOnConfigSet = oldConfigSetting[plugin];
|
plugin.PluginConfig.SaveOnConfigSet = oldConfigSetting[plugin];
|
||||||
@@ -175,7 +173,7 @@ public static class ModdedOptionsManager
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="__originalMethod">The original setter method.</param>
|
/// <param name="__originalMethod">The original setter method.</param>
|
||||||
/// <param name="value">The new object value.</param>
|
/// <param name="value">The new object value.</param>
|
||||||
// ReSharper disable InconsistentNaming
|
// ReSharper disable once InconsistentNaming
|
||||||
public static void PropertySetterPatch(MethodBase __originalMethod, object value)
|
public static void PropertySetterPatch(MethodBase __originalMethod, object value)
|
||||||
{
|
{
|
||||||
var attribute = OptionAttributes.First(pair => pair.Key.GetSetMethod() == __originalMethod).Value;
|
var attribute = OptionAttributes.First(pair => pair.Key.GetSetMethod() == __originalMethod).Value;
|
||||||
@@ -188,8 +186,8 @@ public static class ModdedOptionsManager
|
|||||||
/// <param name="__originalMethod">The original getter method.</param>
|
/// <param name="__originalMethod">The original getter method.</param>
|
||||||
/// <param name="__result">The result of the property getter.</param>
|
/// <param name="__result">The result of the property getter.</param>
|
||||||
/// <returns>False so the original getter gets skipped.</returns>
|
/// <returns>False so the original getter gets skipped.</returns>
|
||||||
|
// ReSharper disable InconsistentNaming
|
||||||
public static bool PropertyGetterPatch(MethodBase __originalMethod, ref object __result)
|
public static bool PropertyGetterPatch(MethodBase __originalMethod, ref object __result)
|
||||||
// ReSharper restore InconsistentNaming
|
|
||||||
{
|
{
|
||||||
var attribute = OptionAttributes.First(pair => pair.Key.GetGetMethod() == __originalMethod).Value;
|
var attribute = OptionAttributes.First(pair => pair.Key.GetGetMethod() == __originalMethod).Value;
|
||||||
__result = attribute.GetValue();
|
__result = attribute.GetValue();
|
||||||
|
|||||||
@@ -2,9 +2,7 @@
|
|||||||
|
|
||||||
namespace MiraAPI.GameOptions;
|
namespace MiraAPI.GameOptions;
|
||||||
|
|
||||||
#pragma warning disable CA1852
|
|
||||||
internal class ModifierOptionGroup : AbstractOptionGroup
|
internal class ModifierOptionGroup : AbstractOptionGroup
|
||||||
#pragma warning restore CA1852
|
|
||||||
{
|
{
|
||||||
public override string GroupName { get; }
|
public override string GroupName { get; }
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ public class ModdedEnumOption : ModdedOption<int>
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the string values of the enum.
|
/// Gets the string values of the enum.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string[]? Values { get; }
|
public string[] Values { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="ModdedEnumOption"/> class.
|
/// Initializes a new instance of the <see cref="ModdedEnumOption"/> class.
|
||||||
@@ -27,7 +27,8 @@ public class ModdedEnumOption : ModdedOption<int>
|
|||||||
/// <param name="defaultValue">The default value as an int.</param>
|
/// <param name="defaultValue">The default value as an int.</param>
|
||||||
/// <param name="enumType">The Enum type.</param>
|
/// <param name="enumType">The Enum type.</param>
|
||||||
/// <param name="values">An option list of string values to use in place of the enum name.</param>
|
/// <param name="values">An option list of string values to use in place of the enum name.</param>
|
||||||
public ModdedEnumOption(string title, int defaultValue, Type enumType, string[]? values = null) : base(title, defaultValue)
|
/// <param name="includeInPreset">Whether to include this option in the preset or not.</param>
|
||||||
|
public ModdedEnumOption(string title, int defaultValue, Type enumType, string[]? values = null, bool includeInPreset=true) : base(title, defaultValue, includeInPreset)
|
||||||
{
|
{
|
||||||
Values = values ?? Enum.GetNames(enumType);
|
Values = values ?? Enum.GetNames(enumType);
|
||||||
Data = ScriptableObject.CreateInstance<StringGameSetting>();
|
Data = ScriptableObject.CreateInstance<StringGameSetting>();
|
||||||
@@ -37,7 +38,7 @@ public class ModdedEnumOption : ModdedOption<int>
|
|||||||
data.Type = global::OptionTypes.String;
|
data.Type = global::OptionTypes.String;
|
||||||
data.Values = values is null ?
|
data.Values = values is null ?
|
||||||
Enum.GetNames(enumType).Select(CustomStringName.CreateAndRegister).ToArray()
|
Enum.GetNames(enumType).Select(CustomStringName.CreateAndRegister).ToArray()
|
||||||
: values.Select(CustomStringName.CreateAndRegister).ToArray();
|
: [.. values.Select(CustomStringName.CreateAndRegister)];
|
||||||
|
|
||||||
data.Index = Value;
|
data.Index = Value;
|
||||||
}
|
}
|
||||||
@@ -87,7 +88,7 @@ public class ModdedEnumOption : ModdedOption<int>
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
protected override void OnValueChanged(int newValue)
|
protected override void OnValueChanged(int newValue)
|
||||||
{
|
{
|
||||||
HudManager.Instance.Notifier.AddSettingsChangeMessage(StringName, Data?.GetValueString(newValue), false);
|
HudManager.Instance.Notifier.AddSettingsChangeMessage(StringName, Data.GetValueString(newValue), false);
|
||||||
if (!OptionBehaviour)
|
if (!OptionBehaviour)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
@@ -109,7 +110,7 @@ public class ModdedEnumOption<T> : ModdedOption<T> where T : Enum
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the string values of the enum.
|
/// Gets the string values of the enum.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string[]? Values { get; }
|
public string[] Values { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="ModdedEnumOption{T}"/> class.
|
/// Initializes a new instance of the <see cref="ModdedEnumOption{T}"/> class.
|
||||||
@@ -117,7 +118,8 @@ public class ModdedEnumOption<T> : ModdedOption<T> where T : Enum
|
|||||||
/// <param name="title">The title of the option.</param>
|
/// <param name="title">The title of the option.</param>
|
||||||
/// <param name="defaultValue">The default value as an int.</param>
|
/// <param name="defaultValue">The default value as an int.</param>
|
||||||
/// <param name="values">An option list of string values to use in place of the enum name.</param>
|
/// <param name="values">An option list of string values to use in place of the enum name.</param>
|
||||||
public ModdedEnumOption(string title, T defaultValue, string[]? values = null) : base(title, defaultValue)
|
/// <param name="includeInPreset">Whether to include this option in the preset or not.</param>
|
||||||
|
public ModdedEnumOption(string title, T defaultValue, string[]? values = null, bool includeInPreset=true) : base(title, defaultValue, includeInPreset)
|
||||||
{
|
{
|
||||||
Values = values ?? Enum.GetNames(typeof(T));
|
Values = values ?? Enum.GetNames(typeof(T));
|
||||||
Data = ScriptableObject.CreateInstance<StringGameSetting>();
|
Data = ScriptableObject.CreateInstance<StringGameSetting>();
|
||||||
@@ -127,7 +129,7 @@ public class ModdedEnumOption<T> : ModdedOption<T> where T : Enum
|
|||||||
data.Type = global::OptionTypes.String;
|
data.Type = global::OptionTypes.String;
|
||||||
data.Values = values is null ?
|
data.Values = values is null ?
|
||||||
Enum.GetNames(typeof(T)).Select(CustomStringName.CreateAndRegister).ToArray()
|
Enum.GetNames(typeof(T)).Select(CustomStringName.CreateAndRegister).ToArray()
|
||||||
: values.Select(CustomStringName.CreateAndRegister).ToArray();
|
: [.. values.Select(CustomStringName.CreateAndRegister)];
|
||||||
|
|
||||||
data.Index = Convert.ToInt32(Value, NumberFormatInfo.InvariantInfo);
|
data.Index = Convert.ToInt32(Value, NumberFormatInfo.InvariantInfo);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ public class ModdedNumberOption : ModdedOption<float>
|
|||||||
/// <param name="suffixType">The suffix type.</param>
|
/// <param name="suffixType">The suffix type.</param>
|
||||||
/// <param name="formatString">Optional format string for the option screen.</param>
|
/// <param name="formatString">Optional format string for the option screen.</param>
|
||||||
/// <param name="zeroInfinity">Whether zero is infinity or not.</param>
|
/// <param name="zeroInfinity">Whether zero is infinity or not.</param>
|
||||||
|
/// <param name="includeInPreset">Whether to include this option in the preset or not.</param>
|
||||||
public ModdedNumberOption(
|
public ModdedNumberOption(
|
||||||
string title,
|
string title,
|
||||||
float defaultValue,
|
float defaultValue,
|
||||||
@@ -56,7 +57,8 @@ public class ModdedNumberOption : ModdedOption<float>
|
|||||||
float increment,
|
float increment,
|
||||||
MiraNumberSuffixes suffixType,
|
MiraNumberSuffixes suffixType,
|
||||||
string? formatString = null,
|
string? formatString = null,
|
||||||
bool zeroInfinity = false) : base(title, defaultValue)
|
bool zeroInfinity = false,
|
||||||
|
bool includeInPreset = true) : base(title, defaultValue, includeInPreset)
|
||||||
{
|
{
|
||||||
Min = min;
|
Min = min;
|
||||||
Max = max;
|
Max = max;
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ using MiraAPI.Networking;
|
|||||||
using MiraAPI.PluginLoading;
|
using MiraAPI.PluginLoading;
|
||||||
using Reactor.Localization.Utilities;
|
using Reactor.Localization.Utilities;
|
||||||
using Reactor.Networking.Rpc;
|
using Reactor.Networking.Rpc;
|
||||||
|
using Reactor.Utilities;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
||||||
namespace MiraAPI.GameOptions.OptionTypes;
|
namespace MiraAPI.GameOptions.OptionTypes;
|
||||||
@@ -16,29 +17,19 @@ public abstract class ModdedOption<T> : IModdedOption
|
|||||||
{
|
{
|
||||||
private IMiraPlugin? _parentMod;
|
private IMiraPlugin? _parentMod;
|
||||||
|
|
||||||
/// <summary>
|
/// <inheritdoc />
|
||||||
/// Gets the unique identifier of the option.
|
|
||||||
/// </summary>
|
|
||||||
public uint Id { get; }
|
public uint Id { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <inheritdoc />
|
||||||
/// Gets the title of the option.
|
|
||||||
/// </summary>
|
|
||||||
public string Title { get; }
|
public string Title { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <inheritdoc />
|
||||||
/// Gets the StringName object of the option.
|
|
||||||
/// </summary>
|
|
||||||
public StringNames StringName { get; }
|
public StringNames StringName { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <inheritdoc />
|
||||||
/// Gets or sets the BaseGameSetting data of the option.
|
|
||||||
/// </summary>
|
|
||||||
public BaseGameSetting Data { get; protected set; } = null!;
|
public BaseGameSetting Data { get; protected set; } = null!;
|
||||||
|
|
||||||
/// <summary>
|
/// <inheritdoc />
|
||||||
/// Gets or sets the parent mod of the option.
|
|
||||||
/// </summary>
|
|
||||||
public IMiraPlugin? ParentMod
|
public IMiraPlugin? ParentMod
|
||||||
{
|
{
|
||||||
get => _parentMod;
|
get => _parentMod;
|
||||||
@@ -66,19 +57,16 @@ public abstract class ModdedOption<T> : IModdedOption
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public Action<T>? ChangedEvent { get; set; }
|
public Action<T>? ChangedEvent { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <inheritdoc />
|
||||||
/// Gets or sets the visibility of the option.
|
|
||||||
/// </summary>
|
|
||||||
public Func<bool> Visible { get; set; }
|
public Func<bool> Visible { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <inheritdoc />
|
||||||
/// Gets or sets the option behaviour of the option.
|
public bool IncludeInPreset { get; set; }
|
||||||
/// </summary>
|
|
||||||
|
/// <inheritdoc />
|
||||||
public OptionBehaviour? OptionBehaviour { get; protected set; }
|
public OptionBehaviour? OptionBehaviour { get; protected set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <inheritdoc />
|
||||||
/// Gets or sets the config definition of the option.
|
|
||||||
/// </summary>
|
|
||||||
public ConfigDefinition? ConfigDefinition { get; set; }
|
public ConfigDefinition? ConfigDefinition { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -86,7 +74,8 @@ public abstract class ModdedOption<T> : IModdedOption
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="title">The option title.</param>
|
/// <param name="title">The option title.</param>
|
||||||
/// <param name="defaultValue">The default value.</param>
|
/// <param name="defaultValue">The default value.</param>
|
||||||
protected ModdedOption(string title, T defaultValue)
|
/// <param name="includeInPreset">Whether to include the option in the preset.</param>
|
||||||
|
protected ModdedOption(string title, T defaultValue, bool includeInPreset = true)
|
||||||
{
|
{
|
||||||
Id = ModdedOptionsManager.NextId;
|
Id = ModdedOptionsManager.NextId;
|
||||||
Title = title;
|
Title = title;
|
||||||
@@ -94,6 +83,7 @@ public abstract class ModdedOption<T> : IModdedOption
|
|||||||
Value = defaultValue;
|
Value = defaultValue;
|
||||||
StringName = CustomStringName.CreateAndRegister(Title);
|
StringName = CustomStringName.CreateAndRegister(Title);
|
||||||
Visible = () => true;
|
Visible = () => true;
|
||||||
|
IncludeInPreset = includeInPreset;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void ValueChanged(OptionBehaviour optionBehaviour)
|
internal void ValueChanged(OptionBehaviour optionBehaviour)
|
||||||
@@ -105,7 +95,8 @@ public abstract class ModdedOption<T> : IModdedOption
|
|||||||
/// Sets the value of the option.
|
/// Sets the value of the option.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="newValue">The new value.</param>
|
/// <param name="newValue">The new value.</param>
|
||||||
public void SetValue(T newValue)
|
/// <param name="sendRpc">Whether to send the value to other players.</param>
|
||||||
|
public void SetValue(T newValue, bool sendRpc = true)
|
||||||
{
|
{
|
||||||
var oldVal = Value;
|
var oldVal = Value;
|
||||||
Value = newValue;
|
Value = newValue;
|
||||||
@@ -115,7 +106,7 @@ public abstract class ModdedOption<T> : IModdedOption
|
|||||||
ChangedEvent?.Invoke(Value);
|
ChangedEvent?.Invoke(Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (AmongUsClient.Instance.AmHost)
|
if (sendRpc && AmongUsClient.Instance.AmHost)
|
||||||
{
|
{
|
||||||
if (ParentMod?.GetConfigFile().TryGetEntry<T>(ConfigDefinition, out var entry) == true)
|
if (ParentMod?.GetConfigFile().TryGetEntry<T>(ConfigDefinition, out var entry) == true)
|
||||||
{
|
{
|
||||||
@@ -128,22 +119,44 @@ public abstract class ModdedOption<T> : IModdedOption
|
|||||||
OnValueChanged(newValue);
|
OnValueChanged(newValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <inheritdoc />
|
||||||
/// Gets the float data of the option.
|
public void SaveToPreset(ConfigFile presetConfig, bool saveDefault=false)
|
||||||
/// </summary>
|
{
|
||||||
/// <returns>A float object representing the option's value.</returns>
|
if (ConfigDefinition is null)
|
||||||
|
{
|
||||||
|
Logger<MiraApiPlugin>.Error($"Attempted to save {Title} to preset, but ConfigDefinition is null.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Bind(presetConfig);
|
||||||
|
presetConfig[ConfigDefinition].BoxedValue = saveDefault ? DefaultValue : Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public void Bind(ConfigFile config)
|
||||||
|
{
|
||||||
|
config.Bind(ConfigDefinition, DefaultValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public void LoadFromPreset(ConfigFile presetConfig)
|
||||||
|
{
|
||||||
|
if (presetConfig.TryGetEntry(ConfigDefinition, out ConfigEntry<T> entry))
|
||||||
|
{
|
||||||
|
SetValue(entry.Value, false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Logger<MiraApiPlugin>.Error($"Attempted to load {Title} from preset, but ConfigDefinition is not found in preset.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
public abstract float GetFloatData();
|
public abstract float GetFloatData();
|
||||||
|
|
||||||
/// <summary>
|
/// <inheritdoc />
|
||||||
/// Gets the net data of the option.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>A NetData object representing this option's data.</returns>
|
|
||||||
public abstract NetData GetNetData();
|
public abstract NetData GetNetData();
|
||||||
|
|
||||||
/// <summary>
|
/// <inheritdoc />
|
||||||
/// Handles incoming net data.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="data">The NetData's byte array.</param>
|
|
||||||
public abstract void HandleNetData(byte[] data);
|
public abstract void HandleNetData(byte[] data);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -159,14 +172,7 @@ public abstract class ModdedOption<T> : IModdedOption
|
|||||||
/// <returns>The value.</returns>
|
/// <returns>The value.</returns>
|
||||||
public abstract T GetValueFromOptionBehaviour(OptionBehaviour optionBehaviour);
|
public abstract T GetValueFromOptionBehaviour(OptionBehaviour optionBehaviour);
|
||||||
|
|
||||||
/// <summary>
|
/// <inheritdoc />
|
||||||
/// Creates the option behaviour.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="toggleOpt">The ToggleOption prefab.</param>
|
|
||||||
/// <param name="numberOpt">The NumberOption prefab.</param>
|
|
||||||
/// <param name="stringOpt">The StringOption prefab.</param>
|
|
||||||
/// <param name="container">The options container.</param>
|
|
||||||
/// <returns>A new OptionBehaviour for this modded option.</returns>
|
|
||||||
public abstract OptionBehaviour CreateOption(
|
public abstract OptionBehaviour CreateOption(
|
||||||
ToggleOption toggleOpt,
|
ToggleOption toggleOpt,
|
||||||
NumberOption numberOpt,
|
NumberOption numberOpt,
|
||||||
|
|||||||
@@ -15,7 +15,8 @@ public class ModdedToggleOption : ModdedOption<bool>
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="title">The option title.</param>
|
/// <param name="title">The option title.</param>
|
||||||
/// <param name="defaultValue">The default value.</param>
|
/// <param name="defaultValue">The default value.</param>
|
||||||
public ModdedToggleOption(string title, bool defaultValue) : base(title, defaultValue)
|
/// <param name="includeInPreset">Whether to include this option in the preset or not.</param>
|
||||||
|
public ModdedToggleOption(string title, bool defaultValue, bool includeInPreset=true) : base(title, defaultValue, includeInPreset)
|
||||||
{
|
{
|
||||||
Data = ScriptableObject.CreateInstance<CheckboxGameSetting>();
|
Data = ScriptableObject.CreateInstance<CheckboxGameSetting>();
|
||||||
|
|
||||||
|
|||||||
@@ -180,7 +180,7 @@ public abstract class CustomActionButton
|
|||||||
|
|
||||||
if (!moveButton) return;
|
if (!moveButton) return;
|
||||||
|
|
||||||
if (HudManagerPatches.BottomLeft == null || HudManagerPatches.BottomRight == null)
|
if (HudManagerPatches._bottomLeft == null || HudManagerPatches._bottomRight == null)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -188,17 +188,17 @@ public abstract class CustomActionButton
|
|||||||
switch (location)
|
switch (location)
|
||||||
{
|
{
|
||||||
case ButtonLocation.BottomLeft:
|
case ButtonLocation.BottomLeft:
|
||||||
var gridArrange = HudManagerPatches.BottomLeft.GetComponent<GridArrange>();
|
var gridArrange = HudManagerPatches._bottomLeft.GetComponent<GridArrange>();
|
||||||
var aspectPosition = HudManagerPatches.BottomLeft.GetComponent<AspectPosition>();
|
var aspectPosition = HudManagerPatches._bottomLeft.GetComponent<AspectPosition>();
|
||||||
|
|
||||||
Button.transform.SetParent(HudManagerPatches.BottomLeft.transform);
|
Button.transform.SetParent(HudManagerPatches._bottomLeft.transform);
|
||||||
|
|
||||||
gridArrange.Start();
|
gridArrange.Start();
|
||||||
gridArrange.ArrangeChilds();
|
gridArrange.ArrangeChilds();
|
||||||
aspectPosition.AdjustPosition();
|
aspectPosition.AdjustPosition();
|
||||||
break;
|
break;
|
||||||
case ButtonLocation.BottomRight:
|
case ButtonLocation.BottomRight:
|
||||||
Button.transform.SetParent(HudManagerPatches.BottomRight);
|
Button.transform.SetParent(HudManagerPatches._bottomRight);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -435,11 +435,11 @@ public abstract class CustomActionButton
|
|||||||
{
|
{
|
||||||
if (CanUse())
|
if (CanUse())
|
||||||
{
|
{
|
||||||
Button!.SetEnabled();
|
Button.SetEnabled();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Button!.SetDisabled();
|
Button.SetDisabled();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (EffectActive)
|
if (EffectActive)
|
||||||
|
|||||||
@@ -29,11 +29,9 @@ public static class CustomButtonManager
|
|||||||
}
|
}
|
||||||
|
|
||||||
CustomButtons.Add(button);
|
CustomButtons.Add(button);
|
||||||
pluginInfo.Buttons.Add(button);
|
pluginInfo.InternalButtons.Add(button);
|
||||||
typeof(CustomButtonSingleton<>).MakeGenericType(buttonType)
|
typeof(CustomButtonSingleton<>).MakeGenericType(buttonType)
|
||||||
#pragma warning disable S3011
|
|
||||||
.GetField("_instance", BindingFlags.Static | BindingFlags.NonPublic)!
|
.GetField("_instance", BindingFlags.Static | BindingFlags.NonPublic)!
|
||||||
#pragma warning restore S3011
|
|
||||||
.SetValue(null, button);
|
.SetValue(null, button);
|
||||||
|
|
||||||
ButtonEventTypes.Add(buttonType, typeof(MiraButtonClickEvent<>).MakeGenericType(buttonType));
|
ButtonEventTypes.Add(buttonType, typeof(MiraButtonClickEvent<>).MakeGenericType(buttonType));
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Linq;
|
||||||
using System.Linq;
|
|
||||||
|
|
||||||
namespace MiraAPI.Hud;
|
namespace MiraAPI.Hud;
|
||||||
|
|
||||||
@@ -14,6 +13,7 @@ public static class CustomButtonSingleton<T> where T : CustomActionButton
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the instance of the button.
|
/// Gets the instance of the button.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[SuppressMessage("Design", "CA1000:Do not declare static members on generic types", Justification = "This is a utility class to get the instance of a custom action button.")]
|
#pragma warning disable CA1000
|
||||||
public static T Instance => _instance ??= CustomButtonManager.CustomButtons.OfType<T>().Single();
|
public static T Instance => _instance ??= CustomButtonManager.CustomButtons.OfType<T>().Single();
|
||||||
|
#pragma warning restore CA1000
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,114 @@
|
|||||||
|
using System;
|
||||||
|
using MiraAPI.Utilities.Assets;
|
||||||
|
using Reactor.Utilities.Attributes;
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEngine.Events;
|
||||||
|
using UnityEngine.UI;
|
||||||
|
|
||||||
|
namespace MiraAPI.Hud;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Simple input box for user input.
|
||||||
|
/// </summary>
|
||||||
|
[RegisterInIl2Cpp]
|
||||||
|
public class InputBox : MonoBehaviour
|
||||||
|
{
|
||||||
|
public InputField inputField = null!;
|
||||||
|
|
||||||
|
public void CreateDialog(string title, string placeholder, string submitText, Action<string> onSubmit)
|
||||||
|
{
|
||||||
|
var canvasObj = new GameObject("DialogCanvas");
|
||||||
|
canvasObj.transform.SetParent(transform);
|
||||||
|
canvasObj.layer = LayerMask.NameToLayer("UI");
|
||||||
|
|
||||||
|
var canvas = canvasObj.AddComponent<Canvas>();
|
||||||
|
canvas.renderMode = RenderMode.ScreenSpaceOverlay;
|
||||||
|
canvas.overrideSorting = true;
|
||||||
|
canvas.sortingOrder = 1000; // Ensure the canvas is on top of other UI elements
|
||||||
|
|
||||||
|
canvasObj.AddComponent<CanvasScaler>().uiScaleMode = CanvasScaler.ScaleMode.ScaleWithScreenSize;
|
||||||
|
canvasObj.AddComponent<GraphicRaycaster>();
|
||||||
|
|
||||||
|
var panelObj = new GameObject("DialogPanel");
|
||||||
|
panelObj.transform.SetParent(canvasObj.transform);
|
||||||
|
var panelRect = panelObj.AddComponent<RectTransform>();
|
||||||
|
var img = panelObj.AddComponent<Image>();
|
||||||
|
|
||||||
|
img.color = new Color(1, 1, 1, 0.9f);
|
||||||
|
img.raycastTarget = true;
|
||||||
|
img.sprite = MiraAssets.RoundedBox.LoadAsset();
|
||||||
|
img.type = Image.Type.Sliced;
|
||||||
|
|
||||||
|
panelRect.sizeDelta = new Vector2(300, 200);
|
||||||
|
panelRect.anchoredPosition = Vector2.zero;
|
||||||
|
|
||||||
|
var titleText = CreateText(panelObj, title);
|
||||||
|
titleText.alignment = TextAnchor.MiddleCenter;
|
||||||
|
titleText.fontSize = 26;
|
||||||
|
titleText.fontStyle = FontStyle.Bold;
|
||||||
|
titleText.color = Color.white;
|
||||||
|
|
||||||
|
var titleRect = titleText.GetComponent<RectTransform>();
|
||||||
|
titleRect.sizeDelta = new Vector2(280, 50);
|
||||||
|
titleRect.anchoredPosition = new Vector2(0, 70);
|
||||||
|
|
||||||
|
var inputObj = new GameObject("InputField");
|
||||||
|
inputObj.transform.SetParent(panelObj.transform);
|
||||||
|
var inputRect = inputObj.AddComponent<RectTransform>();
|
||||||
|
inputRect.sizeDelta = new Vector2(220, 40);
|
||||||
|
inputRect.anchoredPosition = new Vector2(0, 20);
|
||||||
|
|
||||||
|
var inputBg = inputObj.AddComponent<Image>();
|
||||||
|
inputBg.color = new Color(1, 1, 1, 0.8f);
|
||||||
|
|
||||||
|
inputField = inputObj.AddComponent<InputField>();
|
||||||
|
inputField.textComponent = CreateText(inputObj, string.Empty, 18, Color.black);
|
||||||
|
inputField.placeholder = CreateText(inputObj, placeholder, 18, new Color(0.5f, 0.5f, 0.5f));
|
||||||
|
|
||||||
|
var buttonObj = new GameObject("SubmitButton");
|
||||||
|
buttonObj.transform.SetParent(panelObj.transform);
|
||||||
|
var button = buttonObj.AddComponent<Button>();
|
||||||
|
var buttonRect = buttonObj.AddComponent<RectTransform>();
|
||||||
|
buttonRect.sizeDelta = new Vector2(150, 50);
|
||||||
|
buttonRect.anchoredPosition = new Vector2(0, -50);
|
||||||
|
|
||||||
|
var buttonImg = buttonObj.AddComponent<Image>();
|
||||||
|
buttonImg.color = new Color(1f, 1f, 1f, 1f);
|
||||||
|
buttonImg.sprite = MiraAssets.RoundedBox.LoadAsset();
|
||||||
|
buttonImg.type = Image.Type.Sliced;
|
||||||
|
|
||||||
|
var buttonText = CreateText(buttonObj, submitText, 20, Color.white);
|
||||||
|
buttonText.alignment = TextAnchor.MiddleCenter;
|
||||||
|
|
||||||
|
var colors = button.colors;
|
||||||
|
colors.highlightedColor = Color.green;
|
||||||
|
colors.pressedColor = MiraAssets.AcceptedTeal;
|
||||||
|
button.colors = colors;
|
||||||
|
|
||||||
|
button.onClick.AddListener((UnityAction)(() =>
|
||||||
|
{
|
||||||
|
onSubmit(inputField.text);
|
||||||
|
DestroyImmediate(canvasObj);
|
||||||
|
}));
|
||||||
|
|
||||||
|
inputField.ActivateInputField();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Text CreateText(GameObject parent, string textContent = "", int fontSize = 20, Color? textColor = null, Font? font = null)
|
||||||
|
{
|
||||||
|
var textObj = new GameObject("Text");
|
||||||
|
textObj.transform.SetParent(parent.transform);
|
||||||
|
|
||||||
|
var text = textObj.AddComponent<Text>();
|
||||||
|
text.font = font ?? Resources.GetBuiltinResource<Font>("Arial.ttf");
|
||||||
|
text.text = textContent;
|
||||||
|
text.color = textColor ?? Color.white;
|
||||||
|
text.fontSize = fontSize;
|
||||||
|
text.alignment = TextAnchor.MiddleCenter;
|
||||||
|
|
||||||
|
var rect = textObj.GetComponent<RectTransform>();
|
||||||
|
rect.sizeDelta = new Vector2(200, 40);
|
||||||
|
rect.anchoredPosition = Vector2.zero;
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -40,8 +40,8 @@ public abstract class BaseModifier : IOptionable
|
|||||||
/// Gets the parent mod of the modifier.
|
/// Gets the parent mod of the modifier.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public MiraPluginInfo ParentMod => Array.Find(
|
public MiraPluginInfo ParentMod => Array.Find(
|
||||||
MiraPluginManager.Instance.RegisteredPlugins(),
|
MiraPluginManager.Instance.RegisteredPlugins,
|
||||||
x => x.Modifiers.Exists(y => y.TypeId == TypeId)
|
x => x.InternalModifiers.Exists(y => y.TypeId == TypeId)
|
||||||
) ?? throw new InvalidOperationException("Modifier is not registered.");
|
) ?? throw new InvalidOperationException("Modifier is not registered.");
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -3,11 +3,14 @@ using System.Collections.Generic;
|
|||||||
using System.Collections.Immutable;
|
using System.Collections.Immutable;
|
||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
using Il2CppInterop.Runtime.Attributes;
|
using Il2CppInterop.Runtime.Attributes;
|
||||||
using MiraAPI.Modifiers.ModifierDisplay;
|
using MiraAPI.Modifiers.ModifierDisplay;
|
||||||
using MiraAPI.Modifiers.Types;
|
using MiraAPI.Modifiers.Types;
|
||||||
|
using MiraAPI.Utilities;
|
||||||
using Reactor.Utilities;
|
using Reactor.Utilities;
|
||||||
using Reactor.Utilities.Attributes;
|
using Reactor.Utilities.Attributes;
|
||||||
|
using TMPro;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
||||||
namespace MiraAPI.Modifiers;
|
namespace MiraAPI.Modifiers;
|
||||||
@@ -69,15 +72,7 @@ public class ModifierComponent(IntPtr cppPtr) : MonoBehaviour(cppPtr)
|
|||||||
foreach (var modifier in _toRemove.ToArray())
|
foreach (var modifier in _toRemove.ToArray())
|
||||||
{
|
{
|
||||||
_toRemove.Remove(modifier);
|
_toRemove.Remove(modifier);
|
||||||
try
|
modifier.OnDeactivate();
|
||||||
{
|
|
||||||
modifier.OnDeactivate();
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
Logger<MiraApiPlugin>.Error($"Error while deactivating modifier {modifier.ModifierName}: {e.ToString()}");
|
|
||||||
}
|
|
||||||
|
|
||||||
Modifiers.Remove(modifier);
|
Modifiers.Remove(modifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -87,14 +82,7 @@ public class ModifierComponent(IntPtr cppPtr) : MonoBehaviour(cppPtr)
|
|||||||
_toAdd.Remove(modifier);
|
_toAdd.Remove(modifier);
|
||||||
Modifiers.Add(modifier);
|
Modifiers.Add(modifier);
|
||||||
modifier.Initialized = true;
|
modifier.Initialized = true;
|
||||||
try
|
modifier.OnActivate();
|
||||||
{
|
|
||||||
modifier.OnActivate();
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
Logger<MiraApiPlugin>.Error($"Error while activating modifier {modifier.ModifierName}: {e.ToString()}");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (modifier is TimedModifier { AutoStart: true } timer)
|
if (modifier is TimedModifier { AutoStart: true } timer)
|
||||||
{
|
{
|
||||||
@@ -114,14 +102,7 @@ public class ModifierComponent(IntPtr cppPtr) : MonoBehaviour(cppPtr)
|
|||||||
|
|
||||||
foreach (var modifier in ActiveModifiers)
|
foreach (var modifier in ActiveModifiers)
|
||||||
{
|
{
|
||||||
try
|
modifier.FixedUpdate();
|
||||||
{
|
|
||||||
modifier.FixedUpdate();
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
Logger<MiraApiPlugin>.Error($"Error while (fixed) updating modifier {modifier.ModifierName}: {e.ToString()}");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_player.AmOwner && ModifierDisplay && HudManager.InstanceExists)
|
if (_player.AmOwner && ModifierDisplay && HudManager.InstanceExists)
|
||||||
@@ -134,14 +115,7 @@ public class ModifierComponent(IntPtr cppPtr) : MonoBehaviour(cppPtr)
|
|||||||
{
|
{
|
||||||
foreach (var modifier in ActiveModifiers)
|
foreach (var modifier in ActiveModifiers)
|
||||||
{
|
{
|
||||||
try
|
modifier.Update();
|
||||||
{
|
|
||||||
modifier.Update();
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
Logger<MiraApiPlugin>.Error($"Error while updating modifier {modifier.ModifierName}: {e.ToString()}");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ namespace MiraAPI.Modifiers.ModifierDisplay;
|
|||||||
/// The code used to display Mira modifiers.
|
/// The code used to display Mira modifiers.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[RegisterInIl2Cpp]
|
[RegisterInIl2Cpp]
|
||||||
public class ModifierDisplayComponent(nint cppPtr) : MonoBehaviour(cppPtr)
|
public class ModifierDisplayComponent(nint ptr) : MonoBehaviour(ptr)
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the instance of the Modifier Display.
|
/// Gets the instance of the Modifier Display.
|
||||||
@@ -34,8 +34,8 @@ public class ModifierDisplayComponent(nint cppPtr) : MonoBehaviour(cppPtr)
|
|||||||
private PassiveButton _nextButton = null!;
|
private PassiveButton _nextButton = null!;
|
||||||
private PassiveButton _backButton = null!;
|
private PassiveButton _backButton = null!;
|
||||||
|
|
||||||
private int _currentPage;
|
private int _currentPage = 0;
|
||||||
private const int ItemsPerPage = 3;
|
private const int _itemsPerPage = 3;
|
||||||
|
|
||||||
private readonly Dictionary<BaseModifier, ModifierUiComponent> _modifiers = [];
|
private readonly Dictionary<BaseModifier, ModifierUiComponent> _modifiers = [];
|
||||||
|
|
||||||
@@ -142,10 +142,10 @@ public class ModifierDisplayComponent(nint cppPtr) : MonoBehaviour(cppPtr)
|
|||||||
|
|
||||||
private void UpdatePage()
|
private void UpdatePage()
|
||||||
{
|
{
|
||||||
var totalPages = Mathf.CeilToInt((float)_modifiers.Count / ItemsPerPage);
|
var totalPages = Mathf.CeilToInt((float)_modifiers.Count / _itemsPerPage);
|
||||||
_currentPage = Mathf.Clamp(_currentPage, 0, Mathf.Max(0, totalPages - 1));
|
_currentPage = Mathf.Clamp(_currentPage, 0, Mathf.Max(0, totalPages - 1));
|
||||||
|
|
||||||
if (_modifiers.Count <= ItemsPerPage)
|
if (_modifiers.Count <= _itemsPerPage)
|
||||||
{
|
{
|
||||||
_modifiers.Do(x => x.Value.gameObject.SetActive(true));
|
_modifiers.Do(x => x.Value.gameObject.SetActive(true));
|
||||||
_pagination.gameObject.SetActive(false);
|
_pagination.gameObject.SetActive(false);
|
||||||
@@ -162,8 +162,8 @@ public class ModifierDisplayComponent(nint cppPtr) : MonoBehaviour(cppPtr)
|
|||||||
_backButton.gameObject.SetActive(true);
|
_backButton.gameObject.SetActive(true);
|
||||||
|
|
||||||
_modifiers.Do(x => x.Value.gameObject.SetActive(false));
|
_modifiers.Do(x => x.Value.gameObject.SetActive(false));
|
||||||
var start = _currentPage * ItemsPerPage;
|
var start = _currentPage * _itemsPerPage;
|
||||||
var end = Mathf.Min(start + ItemsPerPage, _modifiers.Count);
|
var end = Mathf.Min(start + _itemsPerPage, _modifiers.Count);
|
||||||
var modifiers = _modifiers.ToArray();
|
var modifiers = _modifiers.ToArray();
|
||||||
|
|
||||||
for (var i = start; i < end; i++)
|
for (var i = start; i < end; i++)
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ namespace MiraAPI.Modifiers.ModifierDisplay;
|
|||||||
/// The code placed on every Modifier HUD object. Used to handle updating.
|
/// The code placed on every Modifier HUD object. Used to handle updating.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[RegisterInIl2Cpp]
|
[RegisterInIl2Cpp]
|
||||||
public class ModifierUiComponent(nint cppPtr) : MonoBehaviour(cppPtr)
|
public class ModifierUiComponent(nint ptr) : MonoBehaviour(ptr)
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the modifier which this component is for.
|
/// Gets the modifier which this component is for.
|
||||||
@@ -17,13 +17,12 @@ public class ModifierUiComponent(nint cppPtr) : MonoBehaviour(cppPtr)
|
|||||||
[HideFromIl2Cpp]
|
[HideFromIl2Cpp]
|
||||||
public BaseModifier? Modifier { get; internal set; }
|
public BaseModifier? Modifier { get; internal set; }
|
||||||
|
|
||||||
// ReSharper disable InconsistentNaming
|
|
||||||
private SpriteRenderer modBg = null!;
|
private SpriteRenderer modBg = null!;
|
||||||
private TextMeshPro desc = null!;
|
private TextMeshPro desc = null!;
|
||||||
private SpriteRenderer icon = null!;
|
private SpriteRenderer icon = null!;
|
||||||
private TextMeshPro nameText = null!;
|
private TextMeshPro nameText = null!;
|
||||||
private RectTransform descRect = null!;
|
private RectTransform descRect = null!;
|
||||||
// ReSharper restore InconsistentNaming
|
|
||||||
private void Awake()
|
private void Awake()
|
||||||
{
|
{
|
||||||
if (Modifier == null) return;
|
if (Modifier == null) return;
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics.CodeAnalysis;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Linq.Expressions;
|
using System.Linq.Expressions;
|
||||||
using MiraAPI.Utilities;
|
using MiraAPI.Utilities;
|
||||||
@@ -12,7 +11,7 @@ namespace MiraAPI.Modifiers;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static class ModifierFactory
|
public static class ModifierFactory
|
||||||
{
|
{
|
||||||
private static readonly Dictionary<(Type, Type[]), Func<object[], BaseModifier>> ConstructorCache = [];
|
private static readonly Dictionary<(Type, Type[]), Func<object[], BaseModifier>> _constructorCache = [];
|
||||||
|
|
||||||
private static Func<object[], BaseModifier> CreateConstructor(Type type, params object[] args)
|
private static Func<object[], BaseModifier> CreateConstructor(Type type, params object[] args)
|
||||||
{
|
{
|
||||||
@@ -46,13 +45,13 @@ public static class ModifierFactory
|
|||||||
/// <returns>An instance of the modifier.</returns>
|
/// <returns>An instance of the modifier.</returns>
|
||||||
public static BaseModifier CreateInstance(Type type, params object[] args)
|
public static BaseModifier CreateInstance(Type type, params object[] args)
|
||||||
{
|
{
|
||||||
var argTypes = args.Select(arg => arg.GetType()).ToArray();
|
var argTypes = args.Select(arg => arg?.GetType() ?? typeof(object)).ToArray();
|
||||||
var key = (type, argTypes);
|
var key = (type, argTypes);
|
||||||
|
|
||||||
if (!ConstructorCache.TryGetValue(key, out var constructor))
|
if (!_constructorCache.TryGetValue(key, out var constructor))
|
||||||
{
|
{
|
||||||
constructor = CreateConstructor(type, args);
|
constructor = CreateConstructor(type, args);
|
||||||
ConstructorCache[key] = constructor;
|
_constructorCache[key] = constructor;
|
||||||
}
|
}
|
||||||
|
|
||||||
return constructor(args);
|
return constructor(args);
|
||||||
@@ -96,7 +95,6 @@ public static class ModifierFactory<T> where T : BaseModifier
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="args">Parameters for the constructor.</param>
|
/// <param name="args">Parameters for the constructor.</param>
|
||||||
/// <returns>An instance of the modifier.</returns>
|
/// <returns>An instance of the modifier.</returns>
|
||||||
[SuppressMessage("Design", "CA1000:Do not declare static members on generic types", Justification = "This is a factory class.")]
|
|
||||||
public static T CreateInstance(params object[] args)
|
public static T CreateInstance(params object[] args)
|
||||||
{
|
{
|
||||||
return Constructor(args);
|
return Constructor(args);
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ using System.Runtime.Serialization;
|
|||||||
using MiraAPI.Modifiers.Types;
|
using MiraAPI.Modifiers.Types;
|
||||||
using MiraAPI.PluginLoading;
|
using MiraAPI.PluginLoading;
|
||||||
using MiraAPI.Roles;
|
using MiraAPI.Roles;
|
||||||
|
using MiraAPI.Utilities;
|
||||||
using Reactor.Utilities;
|
using Reactor.Utilities;
|
||||||
using Reactor.Utilities.Extensions;
|
using Reactor.Utilities.Extensions;
|
||||||
using Random = System.Random;
|
using Random = System.Random;
|
||||||
@@ -74,7 +75,7 @@ public static class ModifierManager
|
|||||||
modifier = (BaseModifier)FormatterServices.GetUninitializedObject(modifierType);
|
modifier = (BaseModifier)FormatterServices.GetUninitializedObject(modifierType);
|
||||||
}
|
}
|
||||||
|
|
||||||
info.Modifiers.Add(modifier);
|
info.InternalModifiers.Add(modifier);
|
||||||
|
|
||||||
if (modifier is not GameModifier gameModifier)
|
if (modifier is not GameModifier gameModifier)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -264,7 +264,7 @@ public static class CustomMurderRpc
|
|||||||
deadBody.enabled = true;
|
deadBody.enabled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
var afterMurderEvent = new AfterMurderEvent(source, target, deadBody);
|
var afterMurderEvent = new AfterMurderEvent(source, target);
|
||||||
MiraEventManager.InvokeEvent(afterMurderEvent);
|
MiraEventManager.InvokeEvent(afterMurderEvent);
|
||||||
|
|
||||||
if (!isParticipant)
|
if (!isParticipant)
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ public enum MiraRpc : uint
|
|||||||
RemoveVote,
|
RemoveVote,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Custom RPC to replace Among Us CastVote.
|
/// Custom RPC to replace Among Us CastVote
|
||||||
/// </summary>
|
/// </summary>
|
||||||
CastVote,
|
CastVote,
|
||||||
}
|
}
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
[*.{cs,vb}]
|
|
||||||
dotnet_diagnostic.CA1707.severity = none
|
|
||||||
dotnet_diagnostic.CS1591.severity = none
|
|
||||||
dotnet_diagnostic.SA1611.severity = none
|
|
||||||
dotnet_diagnostic.SA1615.severity = none
|
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
using HarmonyLib;
|
using HarmonyLib;
|
||||||
using MiraAPI.Events;
|
using MiraAPI.Events;
|
||||||
using MiraAPI.Events.Vanilla.Gameplay;
|
using MiraAPI.Events.Vanilla.Gameplay;
|
||||||
using MiraAPI.Utilities;
|
|
||||||
|
|
||||||
namespace MiraAPI.Patches.Events;
|
namespace MiraAPI.Patches.Events;
|
||||||
|
|
||||||
@@ -20,7 +19,7 @@ public static class KillAnimationPatches
|
|||||||
[HarmonyPatch(typeof(KillAnimation), nameof(KillAnimation.CoPerformKill))]
|
[HarmonyPatch(typeof(KillAnimation), nameof(KillAnimation.CoPerformKill))]
|
||||||
public static void KillAnimPostfix(PlayerControl source, PlayerControl target)
|
public static void KillAnimPostfix(PlayerControl source, PlayerControl target)
|
||||||
{
|
{
|
||||||
var afterMurderEvent = new AfterMurderEvent(source, target, Helpers.GetBodyById(target.PlayerId));
|
var afterMurderEvent = new AfterMurderEvent(source, target);
|
||||||
MiraEventManager.InvokeEvent(afterMurderEvent);
|
MiraEventManager.InvokeEvent(afterMurderEvent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -67,9 +67,9 @@ internal static class TaskAdderPatches
|
|||||||
modifiersFolder.FolderName = "Modifiers";
|
modifiersFolder.FolderName = "Modifiers";
|
||||||
modifiersFolder.name = "ModifiersFolder";
|
modifiersFolder.name = "ModifiersFolder";
|
||||||
|
|
||||||
foreach (var plugin in MiraPluginManager.Instance.RegisteredPlugins())
|
foreach (var plugin in MiraPluginManager.Instance.RegisteredPlugins)
|
||||||
{
|
{
|
||||||
if (plugin.CustomRoles.Any(x => x.Value is ICustomRole { Configuration.ShowInFreeplay: true }))
|
if (plugin.InternalRoles.Any(x => x.Value is ICustomRole { Configuration.ShowInFreeplay: true }))
|
||||||
{
|
{
|
||||||
var newFolder = Object.Instantiate(__instance.RootFolderPrefab, _scroller.Inner);
|
var newFolder = Object.Instantiate(__instance.RootFolderPrefab, _scroller.Inner);
|
||||||
newFolder.name = plugin.PluginId+":Roles";
|
newFolder.name = plugin.PluginId+":Roles";
|
||||||
@@ -78,7 +78,7 @@ internal static class TaskAdderPatches
|
|||||||
rolesFolder.SubFolders.Add(newFolder);
|
rolesFolder.SubFolders.Add(newFolder);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (plugin.Modifiers.Exists(x => x.ShowInFreeplay))
|
if (plugin.InternalModifiers.Exists(x => x.ShowInFreeplay))
|
||||||
{
|
{
|
||||||
var newFolder = Object.Instantiate(__instance.RootFolderPrefab, _scroller.Inner);
|
var newFolder = Object.Instantiate(__instance.RootFolderPrefab, _scroller.Inner);
|
||||||
newFolder.name = plugin.PluginId+":Modifiers";
|
newFolder.name = plugin.PluginId+":Modifiers";
|
||||||
@@ -317,9 +317,9 @@ internal static class TaskAdderPatches
|
|||||||
ref float num2,
|
ref float num2,
|
||||||
ref float num3)
|
ref float num3)
|
||||||
{
|
{
|
||||||
for (var m = 0; m < plugin.Modifiers.Count; m++)
|
for (var m = 0; m < plugin.InternalModifiers.Count; m++)
|
||||||
{
|
{
|
||||||
var modifier = plugin.Modifiers[m];
|
var modifier = plugin.InternalModifiers[m];
|
||||||
if (!modifier.ShowInFreeplay)
|
if (!modifier.ShowInFreeplay)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
@@ -368,9 +368,9 @@ internal static class TaskAdderPatches
|
|||||||
|
|
||||||
private static void PluginRoles(TaskAdderGame instance, MiraPluginInfo plugin, ref float num, ref float num2, ref float num3)
|
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++)
|
for (var m = 0; m < plugin.InternalRoles.Count; m++)
|
||||||
{
|
{
|
||||||
var roleBehaviour = plugin.CustomRoles.ElementAt(m).Value;
|
var roleBehaviour = plugin.InternalRoles.ElementAt(m).Value;
|
||||||
if (roleBehaviour.Role == RoleTypes.ImpostorGhost || roleBehaviour.Role == RoleTypes.CrewmateGhost ||
|
if (roleBehaviour.Role == RoleTypes.ImpostorGhost || roleBehaviour.Role == RoleTypes.CrewmateGhost ||
|
||||||
roleBehaviour is ICustomRole { Configuration.ShowInFreeplay: false })
|
roleBehaviour is ICustomRole { Configuration.ShowInFreeplay: false })
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ using MiraAPI.Hud;
|
|||||||
namespace MiraAPI.Patches.Hud;
|
namespace MiraAPI.Patches.Hud;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Reset button patches.
|
/// Reset button patches
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[HarmonyPatch]
|
[HarmonyPatch]
|
||||||
public static class ButtonResetPatches
|
public static class ButtonResetPatches
|
||||||
|
|||||||
@@ -13,9 +13,9 @@ namespace MiraAPI.Patches;
|
|||||||
public static class HudManagerPatches
|
public static class HudManagerPatches
|
||||||
{
|
{
|
||||||
// Custom buttons parent.
|
// Custom buttons parent.
|
||||||
public static GameObject? BottomLeft { get; private set; }
|
internal static GameObject? _bottomLeft;
|
||||||
public static Transform? BottomRight { get; private set; }
|
internal static Transform? _bottomRight;
|
||||||
public static Transform? Buttons { get; private set; }
|
internal static Transform? _buttons;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -36,30 +36,30 @@ public static class HudManagerPatches
|
|||||||
[HarmonyPatch(nameof(HudManager.Start))]
|
[HarmonyPatch(nameof(HudManager.Start))]
|
||||||
public static void StartPostfix(HudManager __instance)
|
public static void StartPostfix(HudManager __instance)
|
||||||
{
|
{
|
||||||
if (Buttons == null)
|
if (_buttons == null)
|
||||||
{
|
{
|
||||||
Buttons = __instance.transform.Find("Buttons");
|
_buttons = __instance.transform.Find("Buttons");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (BottomRight == null)
|
if (_bottomRight == null)
|
||||||
{
|
{
|
||||||
BottomRight = Buttons.Find("BottomRight");
|
_bottomRight = _buttons.Find("BottomRight");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (BottomLeft == null)
|
if (_bottomLeft == null)
|
||||||
{
|
{
|
||||||
BottomLeft = Object.Instantiate(BottomRight.gameObject, Buttons);
|
_bottomLeft = Object.Instantiate(_bottomRight.gameObject, _buttons);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var t in BottomLeft.GetComponentsInChildren<ActionButton>(true))
|
foreach (var t in _bottomLeft.GetComponentsInChildren<ActionButton>(true))
|
||||||
{
|
{
|
||||||
t.gameObject.Destroy();
|
t.gameObject.Destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
var gridArrange = BottomLeft.GetComponent<GridArrange>();
|
var gridArrange = _bottomLeft.GetComponent<GridArrange>();
|
||||||
var aspectPosition = BottomLeft.GetComponent<AspectPosition>();
|
var aspectPosition = _bottomLeft.GetComponent<AspectPosition>();
|
||||||
|
|
||||||
BottomLeft.name = "BottomLeft";
|
_bottomLeft.name = "BottomLeft";
|
||||||
gridArrange.Alignment = GridArrange.StartAlign.Right;
|
gridArrange.Alignment = GridArrange.StartAlign.Right;
|
||||||
aspectPosition.Alignment = AspectPosition.EdgeAlignments.LeftBottom;
|
aspectPosition.Alignment = AspectPosition.EdgeAlignments.LeftBottom;
|
||||||
|
|
||||||
@@ -67,8 +67,8 @@ public static class HudManagerPatches
|
|||||||
{
|
{
|
||||||
var location = button.Location switch
|
var location = button.Location switch
|
||||||
{
|
{
|
||||||
ButtonLocation.BottomLeft => BottomLeft.transform,
|
ButtonLocation.BottomLeft => _bottomLeft.transform,
|
||||||
ButtonLocation.BottomRight => BottomRight,
|
ButtonLocation.BottomRight => _bottomRight,
|
||||||
_ => null,
|
_ => null,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -108,7 +108,7 @@ public static class NameplatesTabPatches
|
|||||||
var x = (NamePlateViewData viewdata) =>
|
var x = (NamePlateViewData viewdata) =>
|
||||||
{
|
{
|
||||||
colorChip.transform.GetChild(1).GetComponent<SpriteRenderer>().sprite = viewdata?.Image;
|
colorChip.transform.GetChild(1).GetComponent<SpriteRenderer>().sprite = viewdata?.Image;
|
||||||
// (colorChip as NameplateChip).image.sprite = viewdata?.Image;
|
//(colorChip as NameplateChip).image.sprite = viewdata?.Image;
|
||||||
};
|
};
|
||||||
__instance.StartCoroutine(AddressableAssetExtensions.CoLoadAssetAsync<NamePlateViewData>(__instance, namePlate.GetAssetReference(), x));
|
__instance.StartCoroutine(AddressableAssetExtensions.CoLoadAssetAsync<NamePlateViewData>(__instance, namePlate.GetAssetReference(), x));
|
||||||
colorChip.transform.localPosition = new Vector3(position.x, position.y, -1f);
|
colorChip.transform.localPosition = new Vector3(position.x, position.y, -1f);
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
namespace MiraAPI.Patches;
|
namespace MiraAPI.Patches;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Used to fix the Minigame crash errors (credits Submerged/PH Gaming for the fix).
|
/// Used to fix the Minigame crash errors (credits Submerged/PH Gaming for the fix)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[HarmonyPatch]
|
[HarmonyPatch]
|
||||||
public static class MinigameBeginErrorPatch
|
public static class MinigameBeginErrorPatch
|
||||||
|
|||||||
@@ -14,18 +14,12 @@ using Object = UnityEngine.Object;
|
|||||||
|
|
||||||
namespace MiraAPI.Patches.Options;
|
namespace MiraAPI.Patches.Options;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Patches the GameOptionsMenu to add custom options.
|
|
||||||
/// </summary>
|
|
||||||
[HarmonyPatch(typeof(GameOptionsMenu))]
|
[HarmonyPatch(typeof(GameOptionsMenu))]
|
||||||
public static class GameOptionsMenuPatch
|
internal static class GameOptionsMenuPatch
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Update patch for the GameOptionsMenu.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="__instance">The GameOptionsMenu instance.</param>
|
|
||||||
[HarmonyPostfix]
|
[HarmonyPostfix]
|
||||||
[HarmonyPatch(nameof(GameOptionsMenu.Update))]
|
[HarmonyPatch(nameof(GameOptionsMenu.Update))]
|
||||||
|
// ReSharper disable once InconsistentNaming
|
||||||
public static void UpdatePatch(GameOptionsMenu __instance)
|
public static void UpdatePatch(GameOptionsMenu __instance)
|
||||||
{
|
{
|
||||||
if (GameSettingMenuPatches.SelectedModIdx == 0)
|
if (GameSettingMenuPatches.SelectedModIdx == 0)
|
||||||
@@ -41,7 +35,7 @@ public static class GameOptionsMenuPatch
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
var filteredGroups =
|
var filteredGroups =
|
||||||
GameSettingMenuPatches.SelectedMod?.OptionGroups
|
GameSettingMenuPatches.SelectedMod?.InternalOptionGroups
|
||||||
.Where(x => x.OptionableType == null && !x.ShowInModifiersMenu) ?? [];
|
.Where(x => x.OptionableType == null && !x.ShowInModifiersMenu) ?? [];
|
||||||
|
|
||||||
foreach (var group in filteredGroups)
|
foreach (var group in filteredGroups)
|
||||||
@@ -107,7 +101,7 @@ public static class GameOptionsMenuPatch
|
|||||||
|
|
||||||
private static void ModifiersUpdate(ref float num)
|
private static void ModifiersUpdate(ref float num)
|
||||||
{
|
{
|
||||||
var groups = GameSettingMenuPatches.SelectedMod?.OptionGroups
|
var groups = GameSettingMenuPatches.SelectedMod?.InternalOptionGroups
|
||||||
.Where(x => x.ShowInModifiersMenu || x.OptionableType?.IsAssignableTo(typeof(BaseModifier))==true) ?? [];
|
.Where(x => x.ShowInModifiersMenu || x.OptionableType?.IsAssignableTo(typeof(BaseModifier))==true) ?? [];
|
||||||
|
|
||||||
foreach (var modGroup in groups)
|
foreach (var modGroup in groups)
|
||||||
@@ -118,7 +112,7 @@ public static class GameOptionsMenuPatch
|
|||||||
|
|
||||||
private static void ModifiersCreate(GameOptionsMenu menu)
|
private static void ModifiersCreate(GameOptionsMenu menu)
|
||||||
{
|
{
|
||||||
var groups = GameSettingMenuPatches.SelectedMod?.OptionGroups
|
var groups = GameSettingMenuPatches.SelectedMod?.InternalOptionGroups
|
||||||
.Where(x => x.ShowInModifiersMenu || x.OptionableType?.IsAssignableTo(typeof(BaseModifier))==true) ?? [];
|
.Where(x => x.ShowInModifiersMenu || x.OptionableType?.IsAssignableTo(typeof(BaseModifier))==true) ?? [];
|
||||||
foreach (var group in groups)
|
foreach (var group in groups)
|
||||||
{
|
{
|
||||||
@@ -128,6 +122,7 @@ public static class GameOptionsMenuPatch
|
|||||||
|
|
||||||
[HarmonyPrefix]
|
[HarmonyPrefix]
|
||||||
[HarmonyPatch(nameof(GameOptionsMenu.CreateSettings))]
|
[HarmonyPatch(nameof(GameOptionsMenu.CreateSettings))]
|
||||||
|
// ReSharper disable once InconsistentNaming
|
||||||
public static bool SettingsPatch(GameOptionsMenu __instance)
|
public static bool SettingsPatch(GameOptionsMenu __instance)
|
||||||
{
|
{
|
||||||
if (GameSettingMenuPatches.SelectedModIdx == 0)
|
if (GameSettingMenuPatches.SelectedModIdx == 0)
|
||||||
@@ -143,7 +138,7 @@ public static class GameOptionsMenuPatch
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
var filteredGroups = GameSettingMenuPatches.SelectedMod?.OptionGroups
|
var filteredGroups = GameSettingMenuPatches.SelectedMod?.InternalOptionGroups
|
||||||
.Where(x => x.OptionableType == null && !x.ShowInModifiersMenu) ?? [];
|
.Where(x => x.OptionableType == null && !x.ShowInModifiersMenu) ?? [];
|
||||||
|
|
||||||
foreach (var group in filteredGroups)
|
foreach (var group in filteredGroups)
|
||||||
@@ -156,6 +151,7 @@ public static class GameOptionsMenuPatch
|
|||||||
|
|
||||||
[HarmonyPrefix]
|
[HarmonyPrefix]
|
||||||
[HarmonyPatch(nameof(GameOptionsMenu.Initialize))]
|
[HarmonyPatch(nameof(GameOptionsMenu.Initialize))]
|
||||||
|
// ReSharper disable once InconsistentNaming
|
||||||
public static bool InitPatch(GameOptionsMenu __instance)
|
public static bool InitPatch(GameOptionsMenu __instance)
|
||||||
{
|
{
|
||||||
if (__instance.Children != null && __instance.Children.Count != 0)
|
if (__instance.Children != null && __instance.Children.Count != 0)
|
||||||
|
|||||||
@@ -0,0 +1,348 @@
|
|||||||
|
using System.Diagnostics;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using BepInEx.Configuration;
|
||||||
|
using HarmonyLib;
|
||||||
|
using MiraAPI.PluginLoading;
|
||||||
|
using MiraAPI.Presets;
|
||||||
|
using MiraAPI.Roles;
|
||||||
|
using MiraAPI.Utilities.Assets;
|
||||||
|
using Reactor.Utilities;
|
||||||
|
using Reactor.Utilities.Extensions;
|
||||||
|
using TMPro;
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEngine.Events;
|
||||||
|
using UnityEngine.UI;
|
||||||
|
using Object = UnityEngine.Object;
|
||||||
|
|
||||||
|
namespace MiraAPI.Patches.Options;
|
||||||
|
|
||||||
|
internal static class GamePresetsTabPatches
|
||||||
|
{
|
||||||
|
private static GameObject _saveButton = null!;
|
||||||
|
private static GameObject _refreshButton = null!;
|
||||||
|
private static GameObject _folderButton = null!;
|
||||||
|
private static GameObject _newDivider = null!;
|
||||||
|
private static GameObject _presetHolder = null!;
|
||||||
|
private static GridArrange _arrange = null!;
|
||||||
|
|
||||||
|
private static readonly object Lock = new();
|
||||||
|
|
||||||
|
public static void DivideSize(GameObject obj, float amount)
|
||||||
|
{
|
||||||
|
foreach (var collider in obj.GetComponentsInChildren<Collider2D>(true))
|
||||||
|
{
|
||||||
|
if (collider.TryCast<BoxCollider2D>() is { } col)
|
||||||
|
{
|
||||||
|
col.size = new Vector2(col.size.x / amount, col.size.y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var rend in obj.GetComponentsInChildren<SpriteRenderer>(true))
|
||||||
|
{
|
||||||
|
rend.size = new Vector2(rend.size.x / amount, rend.size.y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HarmonyPatch(typeof(GamePresetsTab), nameof(GamePresetsTab.OnEnable))]
|
||||||
|
public static class GamePresetsOnEnablePatch
|
||||||
|
{
|
||||||
|
// ReSharper disable once InconsistentNaming
|
||||||
|
public static void Postfix(GamePresetsTab __instance)
|
||||||
|
{
|
||||||
|
if (!GameSettingMenu.Instance)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
CreatePresetMenu(__instance);
|
||||||
|
|
||||||
|
__instance.StandardPresetButton.gameObject.SetActive(GameSettingMenuPatches.SelectedModIdx == 0);
|
||||||
|
__instance.SecondPresetButton.gameObject.SetActive(GameSettingMenuPatches.SelectedModIdx == 0);
|
||||||
|
|
||||||
|
if (GameSettingMenuPatches.SelectedModIdx != 0)
|
||||||
|
{
|
||||||
|
__instance.PresetDescriptionText.text = "Select or create an options preset for this mod";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
__instance.SetSelectedText();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Show the save and refresh buttons
|
||||||
|
if (_saveButton)
|
||||||
|
{
|
||||||
|
_saveButton.SetActive(GameSettingMenuPatches.SelectedModIdx != 0);
|
||||||
|
}
|
||||||
|
if (_refreshButton)
|
||||||
|
{
|
||||||
|
_refreshButton.SetActive(GameSettingMenuPatches.SelectedModIdx != 0);
|
||||||
|
}
|
||||||
|
if (_folderButton)
|
||||||
|
{
|
||||||
|
_folderButton.SetActive(GameSettingMenuPatches.SelectedModIdx != 0);
|
||||||
|
}
|
||||||
|
if (_newDivider)
|
||||||
|
{
|
||||||
|
_newDivider.SetActive(GameSettingMenuPatches.SelectedModIdx != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
var prefab = GameSettingMenu.Instance.GameSettingsButton;
|
||||||
|
|
||||||
|
foreach (var preset in MiraPluginManager.Instance.RegisteredPlugins.SelectMany(x => x.Presets))
|
||||||
|
{
|
||||||
|
var button = Object.Instantiate(prefab, _presetHolder.transform);
|
||||||
|
button.buttonText.text = preset.Name;
|
||||||
|
if (button.buttonText.TryGetComponent<TextTranslatorTMP>(out var tmp))
|
||||||
|
{
|
||||||
|
tmp.DestroyImmediate();
|
||||||
|
}
|
||||||
|
|
||||||
|
button.buttonText.alignment = TextAlignmentOptions.Center;
|
||||||
|
|
||||||
|
button.OnClick = new Button.ButtonClickedEvent();
|
||||||
|
button.OnClick.AddListener(
|
||||||
|
(UnityAction)(() =>
|
||||||
|
{
|
||||||
|
preset.LoadPreset();
|
||||||
|
}));
|
||||||
|
button.gameObject.SetActive(false);
|
||||||
|
preset.PresetButton = button.gameObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var mod in MiraPluginManager.Instance.RegisteredPlugins)
|
||||||
|
{
|
||||||
|
foreach (var button in mod.Presets.Select(x => x.PresetButton))
|
||||||
|
{
|
||||||
|
if (button != null)
|
||||||
|
{
|
||||||
|
button.SetActive(mod == GameSettingMenuPatches.SelectedMod);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_arrange.Start();
|
||||||
|
_arrange.ArrangeChilds();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HarmonyPatch(typeof(GamePresetsTab), nameof(GamePresetsTab.OnDisable))]
|
||||||
|
public static class GamePresetsOnDisablePatch
|
||||||
|
{
|
||||||
|
// ReSharper disable once InconsistentNaming
|
||||||
|
public static void Postfix()
|
||||||
|
{
|
||||||
|
Logger<MiraApiPlugin>.Error("OnDisable called");
|
||||||
|
|
||||||
|
if (_saveButton)
|
||||||
|
{
|
||||||
|
_saveButton.SetActive(false);
|
||||||
|
}
|
||||||
|
if (_refreshButton)
|
||||||
|
{
|
||||||
|
_refreshButton.SetActive(false);
|
||||||
|
}
|
||||||
|
if (_folderButton)
|
||||||
|
{
|
||||||
|
_folderButton.SetActive(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_newDivider)
|
||||||
|
{
|
||||||
|
_newDivider.SetActive(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var mod in MiraPluginManager.Instance.RegisteredPlugins)
|
||||||
|
{
|
||||||
|
foreach (var button in mod.Presets.Select(x => x.PresetButton))
|
||||||
|
{
|
||||||
|
if (button != null)
|
||||||
|
{
|
||||||
|
button.SetActive(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void CreatePresetMenu(GamePresetsTab presetTab)
|
||||||
|
{
|
||||||
|
var prefab = GameSettingMenu.Instance.GameSettingsButton;
|
||||||
|
if (prefab == null)
|
||||||
|
{
|
||||||
|
Logger<MiraApiPlugin>.Error("GameSettingsButton prefab is null");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var tmpTranslator = presetTab.PresetDescriptionText.gameObject.GetComponent<TextTranslatorTMP>();
|
||||||
|
if (tmpTranslator)
|
||||||
|
{
|
||||||
|
tmpTranslator.Destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_newDivider)
|
||||||
|
{
|
||||||
|
var oldDiv = presetTab.transform.FindChild("DividerImage");
|
||||||
|
_newDivider = Object.Instantiate(oldDiv.gameObject, oldDiv.transform.parent);
|
||||||
|
_newDivider.transform.localPosition = new Vector3(1.85f, 0.13f, 0f);
|
||||||
|
_newDivider.transform.localScale = new Vector3(1.13f, 1, 1);
|
||||||
|
_newDivider.transform.localRotation = Quaternion.Euler(new Vector3(0, 0, 90));
|
||||||
|
}
|
||||||
|
|
||||||
|
PassiveButton saveButton;
|
||||||
|
if (!_saveButton)
|
||||||
|
{
|
||||||
|
saveButton = Object.Instantiate(prefab, presetTab.transform);
|
||||||
|
_saveButton = saveButton.gameObject;
|
||||||
|
_saveButton.gameObject.name = "SaveButton";
|
||||||
|
_saveButton.transform.localPosition = new Vector3(3.2f, 1.7f, -2);
|
||||||
|
|
||||||
|
// set the button text and alignment
|
||||||
|
var saveText = saveButton.buttonText;
|
||||||
|
saveText.text = "Save";
|
||||||
|
saveText.GetComponent<TextTranslatorTMP>().Destroy();
|
||||||
|
saveText.alignment = TextAlignmentOptions.Center;
|
||||||
|
saveText.transform.parent.localPosition = new Vector3(
|
||||||
|
-.525f,
|
||||||
|
saveText.transform.parent.localPosition.y,
|
||||||
|
saveText.transform.parent.localPosition.z);
|
||||||
|
|
||||||
|
DivideSize(saveButton.gameObject, 2f);
|
||||||
|
|
||||||
|
saveButton.OnClick = new Button.ButtonClickedEvent();
|
||||||
|
saveButton.OnClick.AddListener(
|
||||||
|
(UnityAction)(() =>
|
||||||
|
{
|
||||||
|
if (GameSettingMenuPatches.SelectedModIdx == 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SavePresetPopup.CreatePopup(
|
||||||
|
name =>
|
||||||
|
{
|
||||||
|
if (GameSettingMenuPatches.SelectedMod == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (name == string.Empty)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var presetFile = new ConfigFile(
|
||||||
|
Path.Combine(
|
||||||
|
PresetManager.PresetDirectory,
|
||||||
|
GameSettingMenuPatches.SelectedMod.PluginId,
|
||||||
|
$"{name}.cfg"),
|
||||||
|
false)
|
||||||
|
{
|
||||||
|
SaveOnConfigSet = false,
|
||||||
|
};
|
||||||
|
|
||||||
|
foreach (var option in GameSettingMenuPatches.SelectedMod.InternalOptions.Where(x => x.IncludeInPreset))
|
||||||
|
{
|
||||||
|
option.SaveToPreset(presetFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var role in GameSettingMenuPatches.SelectedMod.InternalRoles.Values.OfType<ICustomRole>().Where(x=>!x.Configuration.HideSettings))
|
||||||
|
{
|
||||||
|
role.SaveToPreset(presetFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
presetFile.Save();
|
||||||
|
Refresh();
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
saveButton = _saveButton.GetComponent<PassiveButton>();
|
||||||
|
|
||||||
|
PassiveButton refreshButton;
|
||||||
|
if (!_refreshButton)
|
||||||
|
{
|
||||||
|
refreshButton = Object.Instantiate(saveButton, presetTab.transform);
|
||||||
|
_refreshButton = refreshButton.gameObject;
|
||||||
|
_refreshButton.name = "RefreshButton";
|
||||||
|
_refreshButton.transform.localPosition = new Vector3(2.85f, 1.1f, -2);
|
||||||
|
|
||||||
|
var icon = new GameObject("Sprite");
|
||||||
|
icon.transform.SetParent(refreshButton.transform);
|
||||||
|
icon.transform.localPosition = new Vector3(-0.47f, -0.08f, -5f);
|
||||||
|
icon.transform.localScale = new Vector3(0.5f, 0.5f, 1);
|
||||||
|
icon.layer = refreshButton.gameObject.layer;
|
||||||
|
|
||||||
|
var iconSpriteRend = icon.AddComponent<SpriteRenderer>();
|
||||||
|
iconSpriteRend.sprite = MiraAssets.RefreshIcon.LoadAsset();
|
||||||
|
|
||||||
|
DivideSize(refreshButton.gameObject, 2f);
|
||||||
|
refreshButton.buttonText.gameObject.Destroy();
|
||||||
|
|
||||||
|
refreshButton.OnClick = new Button.ButtonClickedEvent();
|
||||||
|
refreshButton.OnClick.AddListener((UnityAction)Refresh);
|
||||||
|
}
|
||||||
|
refreshButton = _refreshButton.GetComponent<PassiveButton>();
|
||||||
|
|
||||||
|
if (!_folderButton)
|
||||||
|
{
|
||||||
|
var openFolderButton = Object.Instantiate(refreshButton, presetTab.transform);
|
||||||
|
_folderButton = openFolderButton.gameObject;
|
||||||
|
_folderButton.name = "OpenFolderButton";
|
||||||
|
_folderButton.transform.localPosition = new Vector3(3.55f, 1.1f, -2);
|
||||||
|
|
||||||
|
var folderRend = openFolderButton.transform.FindChild("Sprite").gameObject.GetComponent<SpriteRenderer>();
|
||||||
|
folderRend.sprite = MiraAssets.FolderIcon.LoadAsset();
|
||||||
|
folderRend.transform.localScale = new Vector3(0.4f, 0.4f, 1);
|
||||||
|
|
||||||
|
openFolderButton.OnClick = new Button.ButtonClickedEvent();
|
||||||
|
openFolderButton.OnClick.AddListener(
|
||||||
|
(UnityAction)(() =>
|
||||||
|
{
|
||||||
|
var directory = Path.Combine(
|
||||||
|
PresetManager.PresetDirectory,
|
||||||
|
GameSettingMenuPatches.SelectedMod?.PluginId ?? string.Empty);
|
||||||
|
Directory.CreateDirectory(directory);
|
||||||
|
Process.Start(
|
||||||
|
new ProcessStartInfo
|
||||||
|
{
|
||||||
|
FileName = directory,
|
||||||
|
UseShellExecute = true,
|
||||||
|
Verb = "open",
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
_saveButton.SetActive(false);
|
||||||
|
_refreshButton.SetActive(false);
|
||||||
|
_folderButton.SetActive(false);
|
||||||
|
_newDivider.SetActive(false);
|
||||||
|
|
||||||
|
if (!_presetHolder)
|
||||||
|
{
|
||||||
|
_presetHolder = new GameObject("PresetHolder");
|
||||||
|
_presetHolder.transform.SetParent(presetTab.transform, false);
|
||||||
|
_presetHolder.transform.localScale = new Vector3(0.9f, 0.9f, 1);
|
||||||
|
_presetHolder.transform.localPosition = new Vector3(-1.9f, 1.7f, 0);
|
||||||
|
_arrange = _presetHolder.AddComponent<GridArrange>();
|
||||||
|
_arrange.Alignment = GridArrange.StartAlign.Right;
|
||||||
|
_arrange.CellSize = new Vector2(2.15f, -.55f);
|
||||||
|
_arrange.MaxColumns = 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void Refresh()
|
||||||
|
{
|
||||||
|
Logger<MiraApiPlugin>.Error("Refreshing presets");
|
||||||
|
if (GameSettingMenuPatches.SelectedMod == null)
|
||||||
|
{
|
||||||
|
Logger<MiraApiPlugin>.Error("Selected mod is null, cannot refresh presets");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
lock (Lock)
|
||||||
|
{
|
||||||
|
PresetManager.LoadPresets(GameSettingMenuPatches.SelectedMod);
|
||||||
|
}
|
||||||
|
GameSettingMenu.Instance.ChangeTab(0, false); // refresh the tab
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,6 +4,7 @@ using System.Linq;
|
|||||||
using HarmonyLib;
|
using HarmonyLib;
|
||||||
using MiraAPI.Modifiers;
|
using MiraAPI.Modifiers;
|
||||||
using MiraAPI.PluginLoading;
|
using MiraAPI.PluginLoading;
|
||||||
|
using MiraAPI.Presets;
|
||||||
using MiraAPI.Utilities.Assets;
|
using MiraAPI.Utilities.Assets;
|
||||||
using Reactor.Utilities.Extensions;
|
using Reactor.Utilities.Extensions;
|
||||||
using TMPro;
|
using TMPro;
|
||||||
@@ -31,15 +32,20 @@ internal static class GameSettingMenuPatches
|
|||||||
private static PassiveButton? _modifiersButton;
|
private static PassiveButton? _modifiersButton;
|
||||||
private static PassiveButton? _smallRolesButton;
|
private static PassiveButton? _smallRolesButton;
|
||||||
|
|
||||||
private static Dictionary<int, Vector3> OptionsPositions { get; } = [];
|
private static Dictionary<int, Vector3> OptionScrolls = [];
|
||||||
|
|
||||||
[HarmonyPostfix]
|
[HarmonyPostfix]
|
||||||
[HarmonyPatch(nameof(GameSettingMenu.ChangeTab))]
|
[HarmonyPatch(nameof(GameSettingMenu.ChangeTab))]
|
||||||
|
// ReSharper disable once InconsistentNaming
|
||||||
public static void ChangeTabPostfix(GameSettingMenu __instance, int tabNum, bool previewOnly)
|
public static void ChangeTabPostfix(GameSettingMenu __instance, int tabNum, bool previewOnly)
|
||||||
{
|
{
|
||||||
if ((previewOnly && Controller.currentTouchType == Controller.TouchType.Joystick) || !previewOnly)
|
if ((previewOnly && Controller.currentTouchType == Controller.TouchType.Joystick) || !previewOnly)
|
||||||
{
|
{
|
||||||
if (_modifiersTab) _modifiersTab!.gameObject.SetActive(tabNum == 3);
|
if (_modifiersTab)
|
||||||
|
{
|
||||||
|
_modifiersTab!.gameObject.SetActive(tabNum == 3);
|
||||||
|
}
|
||||||
|
|
||||||
_modifiersButton?.SelectButton(tabNum == 3);
|
_modifiersButton?.SelectButton(tabNum == 3);
|
||||||
_smallRolesButton?.SelectButton(tabNum == 2);
|
_smallRolesButton?.SelectButton(tabNum == 2);
|
||||||
if (tabNum == 3)
|
if (tabNum == 3)
|
||||||
@@ -63,7 +69,10 @@ internal static class GameSettingMenuPatches
|
|||||||
_modifiersButton?.SelectButton(tabNum == 3);
|
_modifiersButton?.SelectButton(tabNum == 3);
|
||||||
_smallRolesButton?.SelectButton(tabNum == 2);
|
_smallRolesButton?.SelectButton(tabNum == 2);
|
||||||
|
|
||||||
if (tabNum != 3) return;
|
if (tabNum != 3)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (__instance.RoleSettingsButton.gameObject.active)
|
if (__instance.RoleSettingsButton.gameObject.active)
|
||||||
{
|
{
|
||||||
@@ -81,6 +90,7 @@ internal static class GameSettingMenuPatches
|
|||||||
/// <param name="__instance">The GameSettingMenu instance.</param>
|
/// <param name="__instance">The GameSettingMenu instance.</param>
|
||||||
[HarmonyPrefix]
|
[HarmonyPrefix]
|
||||||
[HarmonyPatch(nameof(GameSettingMenu.Start))]
|
[HarmonyPatch(nameof(GameSettingMenu.Start))]
|
||||||
|
// ReSharper disable once InconsistentNaming
|
||||||
public static void StartPrefix(GameSettingMenu __instance)
|
public static void StartPrefix(GameSettingMenu __instance)
|
||||||
{
|
{
|
||||||
_roleBtnOgPos = __instance.RoleSettingsButton.transform.localPosition;
|
_roleBtnOgPos = __instance.RoleSettingsButton.transform.localPosition;
|
||||||
@@ -113,13 +123,13 @@ internal static class GameSettingMenuPatches
|
|||||||
passiveButton.OnClick.AddListener(
|
passiveButton.OnClick.AddListener(
|
||||||
(UnityAction)(() =>
|
(UnityAction)(() =>
|
||||||
{
|
{
|
||||||
if (!__instance.RoleSettingsTab.AdvancedRolesSettings.active)
|
RoleSettingMenuPatches.Scrolls[SelectedModIdx] =
|
||||||
{
|
__instance.RoleSettingsTab.scrollBar.Inner.localPosition;
|
||||||
RoleSettingMenuPatches.RolePositions[SelectedModIdx] = __instance.RoleSettingsTab.scrollBar.Inner.localPosition;
|
OptionScrolls[SelectedModIdx] =
|
||||||
}
|
__instance.GameSettingsTab.scrollBar.Inner.localPosition;
|
||||||
OptionsPositions[SelectedModIdx] = __instance.GameSettingsTab.scrollBar.Inner.localPosition;
|
|
||||||
SelectedModIdx += 1;
|
SelectedModIdx += 1;
|
||||||
if (SelectedModIdx > MiraPluginManager.Instance.RegisteredPlugins().Length)
|
if (SelectedModIdx > MiraPluginManager.Instance.RegisteredPlugins.Length)
|
||||||
{
|
{
|
||||||
SelectedModIdx = 0;
|
SelectedModIdx = 0;
|
||||||
}
|
}
|
||||||
@@ -136,15 +146,15 @@ internal static class GameSettingMenuPatches
|
|||||||
backButton.gameObject.GetComponent<PassiveButton>().OnClick.AddListener(
|
backButton.gameObject.GetComponent<PassiveButton>().OnClick.AddListener(
|
||||||
(UnityAction)(() =>
|
(UnityAction)(() =>
|
||||||
{
|
{
|
||||||
if (!__instance.RoleSettingsTab.AdvancedRolesSettings.active)
|
RoleSettingMenuPatches.Scrolls[SelectedModIdx] =
|
||||||
{
|
__instance.RoleSettingsTab.scrollBar.Inner.localPosition;
|
||||||
RoleSettingMenuPatches.RolePositions[SelectedModIdx] = __instance.RoleSettingsTab.scrollBar.Inner.localPosition;
|
OptionScrolls[SelectedModIdx] =
|
||||||
}
|
__instance.GameSettingsTab.scrollBar.Inner.localPosition;
|
||||||
OptionsPositions[SelectedModIdx] = __instance.GameSettingsTab.scrollBar.Inner.localPosition;
|
|
||||||
SelectedModIdx -= 1;
|
SelectedModIdx -= 1;
|
||||||
if (SelectedModIdx < 0)
|
if (SelectedModIdx < 0)
|
||||||
{
|
{
|
||||||
SelectedModIdx = MiraPluginManager.Instance.RegisteredPlugins().Length;
|
SelectedModIdx = MiraPluginManager.Instance.RegisteredPlugins.Length;
|
||||||
}
|
}
|
||||||
|
|
||||||
UpdateText(__instance, __instance.GameSettingsTab, __instance.RoleSettingsTab);
|
UpdateText(__instance, __instance.GameSettingsTab, __instance.RoleSettingsTab);
|
||||||
@@ -221,54 +231,61 @@ internal static class GameSettingMenuPatches
|
|||||||
|
|
||||||
_modifierBtnOgPos = _modifiersButton.transform.localPosition;
|
_modifierBtnOgPos = _modifiersButton.transform.localPosition;
|
||||||
|
|
||||||
|
foreach (var plugin in MiraPluginManager.Instance.RegisteredPlugins)
|
||||||
|
{
|
||||||
|
PresetManager.LoadPresets(plugin);
|
||||||
|
}
|
||||||
|
|
||||||
UpdateText(__instance, __instance.GameSettingsTab, __instance.RoleSettingsTab);
|
UpdateText(__instance, __instance.GameSettingsTab, __instance.RoleSettingsTab);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void ChangeRoleSettingButton(bool replace, GameSettingMenu __instance)
|
private static void ChangeRoleSettingButton(bool replace, GameSettingMenu menu)
|
||||||
{
|
{
|
||||||
__instance.RoleSettingsButton.OnClick = new ButtonClickedEvent();
|
menu.RoleSettingsButton.OnClick = new ButtonClickedEvent();
|
||||||
__instance.RoleSettingsButton.OnMouseOver = new UnityEvent();
|
menu.RoleSettingsButton.OnMouseOver = new UnityEvent();
|
||||||
|
|
||||||
if (replace)
|
if (replace)
|
||||||
{
|
{
|
||||||
__instance.RoleSettingsButton.buttonText.text = "Modifiers Settings";
|
menu.RoleSettingsButton.buttonText.text = "Modifiers Settings";
|
||||||
__instance.RoleSettingsButton.OnClick.AddListener(
|
menu.RoleSettingsButton.OnClick.AddListener(
|
||||||
(UnityAction)(() =>
|
(UnityAction)(() =>
|
||||||
{
|
{
|
||||||
__instance.ChangeTab(3, false);
|
menu.ChangeTab(3, false);
|
||||||
}));
|
}));
|
||||||
__instance.RoleSettingsButton.OnMouseOver.AddListener(
|
menu.RoleSettingsButton.OnMouseOver.AddListener(
|
||||||
(UnityAction)(() =>
|
(UnityAction)(() =>
|
||||||
{
|
{
|
||||||
__instance.ChangeTab(3, true);
|
menu.ChangeTab(3, true);
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
__instance.RoleSettingsButton.buttonText.text = "Roles Settings";
|
menu.RoleSettingsButton.buttonText.text = "Roles Settings";
|
||||||
__instance.RoleSettingsButton.OnClick.AddListener(
|
menu.RoleSettingsButton.OnClick.AddListener(
|
||||||
(UnityAction)(() =>
|
(UnityAction)(() =>
|
||||||
{
|
{
|
||||||
__instance.ChangeTab(2, false);
|
menu.ChangeTab(2, false);
|
||||||
}));
|
}));
|
||||||
__instance.RoleSettingsButton.OnMouseOver.AddListener(
|
menu.RoleSettingsButton.OnMouseOver.AddListener(
|
||||||
(UnityAction)(() =>
|
(UnityAction)(() =>
|
||||||
{
|
{
|
||||||
__instance.ChangeTab(2, true);
|
menu.ChangeTab(2, true);
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void UpdateText(GameSettingMenu menu, GameOptionsMenu settings, RolesSettingsMenu roles)
|
private static void UpdateText(GameSettingMenu menu, GameOptionsMenu settings, RolesSettingsMenu roles)
|
||||||
{
|
{
|
||||||
if (_text is not null && SelectedModIdx == 0)
|
if (_text is not null && SelectedModIdx == 0)
|
||||||
{
|
{
|
||||||
_text.text = "Default";
|
_text.text = "Default";
|
||||||
_text.fontSizeMax = 3.2f;
|
_text.fontSizeMax = 3.2f;
|
||||||
|
SelectedMod = null;
|
||||||
}
|
}
|
||||||
else if (_text is not null)
|
else if (_text is not null)
|
||||||
{
|
{
|
||||||
_text.fontSizeMax = 2.3f;
|
_text.fontSizeMax = 2.3f;
|
||||||
SelectedMod = MiraPluginManager.Instance.RegisteredPlugins()[SelectedModIdx - 1];
|
SelectedMod = MiraPluginManager.Instance.RegisteredPlugins[SelectedModIdx - 1];
|
||||||
|
|
||||||
var name = SelectedMod.MiraPlugin.OptionsTitleText;
|
var name = SelectedMod.MiraPlugin.OptionsTitleText;
|
||||||
_text.text = name[..Math.Min(name.Length, 25)];
|
_text.text = name[..Math.Min(name.Length, 25)];
|
||||||
@@ -281,9 +298,11 @@ internal static class GameSettingMenuPatches
|
|||||||
|
|
||||||
if (SelectedModIdx != 0)
|
if (SelectedModIdx != 0)
|
||||||
{
|
{
|
||||||
var modHasRoles = SelectedMod!.CustomRoles.Count != 0;
|
var modHasRoles = SelectedMod!.InternalRoles.Count != 0;
|
||||||
var modHasModifiers = SelectedMod.OptionGroups.Exists(x => x.ShowInModifiersMenu || x.OptionableType?.IsAssignableTo(typeof(BaseModifier)) == true);
|
var modHasModifiers = SelectedMod.InternalOptionGroups.Exists(
|
||||||
var modHasOptions = SelectedMod.OptionGroups.Exists(x => x.OptionableType == null && !x.ShowInModifiersMenu);
|
x => x.ShowInModifiersMenu || x.OptionableType?.IsAssignableTo(typeof(BaseModifier)) == true);
|
||||||
|
var modHasOptions =
|
||||||
|
SelectedMod.InternalOptionGroups.Exists(x => x.OptionableType == null && !x.ShowInModifiersMenu);
|
||||||
|
|
||||||
_modifiersButton.gameObject.SetActive(true);
|
_modifiersButton.gameObject.SetActive(true);
|
||||||
_smallRolesButton.gameObject.SetActive(true);
|
_smallRolesButton.gameObject.SetActive(true);
|
||||||
@@ -323,6 +342,7 @@ internal static class GameSettingMenuPatches
|
|||||||
{
|
{
|
||||||
menu.ChangeTab(0, false);
|
menu.ChangeTab(0, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the mod has roles, we can enable the bigger role button and disable the small one.
|
// If the mod has roles, we can enable the bigger role button and disable the small one.
|
||||||
if (modHasRoles)
|
if (modHasRoles)
|
||||||
{
|
{
|
||||||
@@ -379,6 +399,11 @@ internal static class GameSettingMenuPatches
|
|||||||
ChangeRoleSettingButton(replaceWithModifiers, menu);
|
ChangeRoleSettingButton(replaceWithModifiers, menu);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (menu.PresetsTab.gameObject.active)
|
||||||
|
{
|
||||||
|
menu.ChangeTab(0, false);
|
||||||
|
}
|
||||||
|
|
||||||
CleanupTab(settings, roles);
|
CleanupTab(settings, roles);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -390,13 +415,52 @@ internal static class GameSettingMenuPatches
|
|||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
child.gameObject.DestroyImmediate();
|
child.gameObject.DestroyImmediate();
|
||||||
}
|
}
|
||||||
|
|
||||||
options.Clear();
|
options.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void CleanupTab(GameOptionsMenu settings, RolesSettingsMenu roles)
|
private static void CleanupTab(GameOptionsMenu settings, RolesSettingsMenu roles)
|
||||||
{
|
{
|
||||||
|
if (roles.roleChances != null)
|
||||||
|
{
|
||||||
|
CleanupRoleSettings(roles);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (settings.Children != null)
|
||||||
|
{
|
||||||
|
CleanupSettings(settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_modifiersTab?.Children?.Count > 0)
|
||||||
|
{
|
||||||
|
CleanupSettings(_modifiersTab);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CleanupSettings(GameOptionsMenu gameOptMenu)
|
||||||
|
{
|
||||||
|
ClearOptions(gameOptMenu.Children);
|
||||||
|
gameOptMenu.Children = null;
|
||||||
|
|
||||||
|
gameOptMenu.settingsContainer
|
||||||
|
.GetComponentsInChildren<CategoryHeaderMasked>()
|
||||||
|
.ToList()
|
||||||
|
.ForEach(header => header.gameObject.DestroyImmediate());
|
||||||
|
|
||||||
|
gameOptMenu.Initialize();
|
||||||
|
if (OptionScrolls.TryGetValue(SelectedModIdx, out var pos))
|
||||||
|
{
|
||||||
|
gameOptMenu.scrollBar.Inner.localPosition = pos;
|
||||||
|
gameOptMenu.scrollBar.UpdateScrollBars();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
gameOptMenu.scrollBar.ScrollToTop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void CleanupRoleSettings(RolesSettingsMenu rolesMenu)
|
void CleanupRoleSettings(RolesSettingsMenu rolesMenu)
|
||||||
{
|
{
|
||||||
if (rolesMenu.advancedSettingChildren != null)
|
if (rolesMenu.advancedSettingChildren != null)
|
||||||
@@ -415,57 +479,24 @@ internal static class GameSettingMenuPatches
|
|||||||
{
|
{
|
||||||
role.gameObject.DestroyImmediate();
|
role.gameObject.DestroyImmediate();
|
||||||
}
|
}
|
||||||
|
|
||||||
rolesMenu.roleChances?.Clear();
|
rolesMenu.roleChances?.Clear();
|
||||||
|
|
||||||
rolesMenu.AdvancedRolesSettings.gameObject.SetActive(false);
|
rolesMenu.AdvancedRolesSettings.gameObject.SetActive(false);
|
||||||
rolesMenu.RoleChancesSettings.gameObject.SetActive(true);
|
rolesMenu.RoleChancesSettings.gameObject.SetActive(true);
|
||||||
rolesMenu.SetQuotaTab();
|
rolesMenu.SetQuotaTab();
|
||||||
if (RoleSettingMenuPatches.RolePositions.TryGetValue(SelectedModIdx, out var pos))
|
if (SelectedModIdx == 0)
|
||||||
{
|
{
|
||||||
rolesMenu.scrollBar.Inner.localPosition = pos;
|
if (RoleSettingMenuPatches.Scrolls.TryGetValue(0, out var pos))
|
||||||
rolesMenu.scrollBar.UpdateScrollBars();
|
{
|
||||||
|
rolesMenu.scrollBar.Inner.localPosition = pos;
|
||||||
|
rolesMenu.scrollBar.UpdateScrollBars();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rolesMenu.scrollBar.ScrollToTop();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
rolesMenu.scrollBar.ScrollToTop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void CleanupSettings(GameOptionsMenu gameOptMenu)
|
|
||||||
{
|
|
||||||
ClearOptions(gameOptMenu.Children);
|
|
||||||
gameOptMenu.Children = null;
|
|
||||||
|
|
||||||
gameOptMenu.settingsContainer
|
|
||||||
.GetComponentsInChildren<CategoryHeaderMasked>()
|
|
||||||
.ToList()
|
|
||||||
.ForEach(header => header.gameObject.DestroyImmediate());
|
|
||||||
|
|
||||||
gameOptMenu.Initialize();
|
|
||||||
if (OptionsPositions.TryGetValue(SelectedModIdx, out var pos))
|
|
||||||
{
|
|
||||||
gameOptMenu.scrollBar.Inner.localPosition = pos;
|
|
||||||
gameOptMenu.scrollBar.UpdateScrollBars();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
gameOptMenu.scrollBar.ScrollToTop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (roles.roleChances != null && SelectedMod?.CustomRoles.Count > 0)
|
|
||||||
{
|
|
||||||
CleanupRoleSettings(roles);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (settings.Children != null && SelectedMod?.OptionGroups.Count > 0)
|
|
||||||
{
|
|
||||||
CleanupSettings(settings);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_modifiersTab?.Children?.Count > 0)
|
|
||||||
{
|
|
||||||
CleanupSettings(_modifiersTab);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -24,7 +24,7 @@ public static class LobbyViewPanePatches
|
|||||||
|
|
||||||
private static MiraPluginInfo? SelectedMod => SelectedModIdx == 0
|
private static MiraPluginInfo? SelectedMod => SelectedModIdx == 0
|
||||||
? null
|
? null
|
||||||
: MiraPluginManager.Instance.RegisteredPlugins()[SelectedModIdx - 1];
|
: MiraPluginManager.Instance.RegisteredPlugins[SelectedModIdx - 1];
|
||||||
|
|
||||||
private static PassiveButton? ModifiersTabButton { get; set; }
|
private static PassiveButton? ModifiersTabButton { get; set; }
|
||||||
|
|
||||||
@@ -74,7 +74,7 @@ public static class LobbyViewPanePatches
|
|||||||
(UnityAction)(() =>
|
(UnityAction)(() =>
|
||||||
{
|
{
|
||||||
SelectedModIdx += 1;
|
SelectedModIdx += 1;
|
||||||
if (SelectedModIdx > MiraPluginManager.Instance.RegisteredPlugins().Length)
|
if (SelectedModIdx > MiraPluginManager.Instance.RegisteredPlugins.Length)
|
||||||
{
|
{
|
||||||
SelectedModIdx = 0;
|
SelectedModIdx = 0;
|
||||||
}
|
}
|
||||||
@@ -98,7 +98,7 @@ public static class LobbyViewPanePatches
|
|||||||
SelectedModIdx -= 1;
|
SelectedModIdx -= 1;
|
||||||
if (SelectedModIdx < 0)
|
if (SelectedModIdx < 0)
|
||||||
{
|
{
|
||||||
SelectedModIdx = MiraPluginManager.Instance.RegisteredPlugins().Length;
|
SelectedModIdx = MiraPluginManager.Instance.RegisteredPlugins.Length;
|
||||||
}
|
}
|
||||||
|
|
||||||
Refresh(__instance);
|
Refresh(__instance);
|
||||||
@@ -127,7 +127,7 @@ public static class LobbyViewPanePatches
|
|||||||
__instance.rolesTabButton.SelectButton(false);
|
__instance.rolesTabButton.SelectButton(false);
|
||||||
|
|
||||||
ModifiersTabButton?.SelectButton(true);
|
ModifiersTabButton?.SelectButton(true);
|
||||||
var filteredGroups = SelectedMod.OptionGroups
|
var filteredGroups = SelectedMod.InternalOptionGroups
|
||||||
.Where(x => x.GroupVisible() && (x.ShowInModifiersMenu || x.OptionableType?.IsAssignableTo(typeof(BaseModifier))==true));
|
.Where(x => x.GroupVisible() && (x.ShowInModifiersMenu || x.OptionableType?.IsAssignableTo(typeof(BaseModifier))==true));
|
||||||
DrawOptions(__instance, filteredGroups);
|
DrawOptions(__instance, filteredGroups);
|
||||||
return false;
|
return false;
|
||||||
@@ -142,7 +142,7 @@ public static class LobbyViewPanePatches
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
var filteredGroups = SelectedMod.OptionGroups
|
var filteredGroups = SelectedMod.InternalOptionGroups
|
||||||
.Where(x => x.OptionableType == null && x.GroupVisible.Invoke());
|
.Where(x => x.OptionableType == null && x.GroupVisible.Invoke());
|
||||||
DrawOptions(__instance, filteredGroups);
|
DrawOptions(__instance, filteredGroups);
|
||||||
return false;
|
return false;
|
||||||
@@ -250,7 +250,7 @@ public static class LobbyViewPanePatches
|
|||||||
|
|
||||||
var list = new List<Type>();
|
var list = new List<Type>();
|
||||||
|
|
||||||
var roleGroups = SelectedMod.CustomRoles.Values.OfType<ICustomRole>()
|
var roleGroups = SelectedMod.InternalRoles.Values.OfType<ICustomRole>()
|
||||||
.ToLookup(x => x.RoleOptionsGroup);
|
.ToLookup(x => x.RoleOptionsGroup);
|
||||||
|
|
||||||
// sort the groups by priority
|
// sort the groups by priority
|
||||||
@@ -315,7 +315,7 @@ public static class LobbyViewPanePatches
|
|||||||
viewSettingsInfoPanelRoleVariant.transform.localScale = Vector3.one;
|
viewSettingsInfoPanelRoleVariant.transform.localScale = Vector3.one;
|
||||||
viewSettingsInfoPanelRoleVariant.transform.localPosition = new Vector3(num2, num, -2f);
|
viewSettingsInfoPanelRoleVariant.transform.localPosition = new Vector3(num2, num, -2f);
|
||||||
|
|
||||||
var advancedRoleOptions = SelectedMod.OptionGroups
|
var advancedRoleOptions = SelectedMod.InternalOptionGroups
|
||||||
.Where(x => x.OptionableType == customRole.GetType())
|
.Where(x => x.OptionableType == customRole.GetType())
|
||||||
.SelectMany(x => x.Options)
|
.SelectMany(x => x.Options)
|
||||||
.ToList();
|
.ToList();
|
||||||
@@ -402,7 +402,7 @@ public static class LobbyViewPanePatches
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
var role = SelectedMod.CustomRoles.Values.FirstOrDefault(x => x.GetType() == roleType);
|
var role = SelectedMod.InternalRoles.Values.FirstOrDefault(x => x.GetType() == roleType);
|
||||||
|
|
||||||
if (role == null)
|
if (role == null)
|
||||||
{
|
{
|
||||||
@@ -425,7 +425,7 @@ public static class LobbyViewPanePatches
|
|||||||
var num = viewPanel.yPosStart;
|
var num = viewPanel.yPosStart;
|
||||||
var num2 = 1.08f;
|
var num2 = 1.08f;
|
||||||
|
|
||||||
var filteredOptions = SelectedMod.OptionGroups
|
var filteredOptions = SelectedMod.InternalOptionGroups
|
||||||
.Where(x => x.OptionableType == roleType)
|
.Where(x => x.OptionableType == roleType)
|
||||||
.SelectMany(x=>x.Options)
|
.SelectMany(x=>x.Options)
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|||||||
@@ -2,8 +2,6 @@
|
|||||||
using HarmonyLib;
|
using HarmonyLib;
|
||||||
using Il2CppSystem;
|
using Il2CppSystem;
|
||||||
using MiraAPI.Roles;
|
using MiraAPI.Roles;
|
||||||
using UnityEngine;
|
|
||||||
using Object = Il2CppSystem.Object;
|
|
||||||
|
|
||||||
namespace MiraAPI.Patches.Options;
|
namespace MiraAPI.Patches.Options;
|
||||||
|
|
||||||
@@ -25,13 +23,15 @@ public static class NotificationPopperPatch
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
var textColor = customRole.OptionsMenuColor.ToTextColor();
|
var text = teamType == RoleTeamTypes.Crewmate
|
||||||
|
? Palette.CrewmateSettingChangeText.ToTextColor()
|
||||||
|
: Palette.ImpostorRed.ToTextColor();
|
||||||
|
|
||||||
var item = TranslationController.Instance.GetString(
|
var item = TranslationController.Instance.GetString(
|
||||||
StringNames.LobbyChangeSettingNotificationRole,
|
StringNames.LobbyChangeSettingNotificationRole,
|
||||||
string.Concat(
|
string.Concat(
|
||||||
"<font=\"Barlow-Black SDF\" material=\"Barlow-Black Outline\">",
|
"<font=\"Barlow-Black SDF\" material=\"Barlow-Black Outline\">",
|
||||||
textColor,
|
text,
|
||||||
TranslationController.Instance.GetString(key, Array.Empty<Object>()),
|
TranslationController.Instance.GetString(key, Array.Empty<Object>()),
|
||||||
"</color></font>"
|
"</color></font>"
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -22,17 +22,16 @@ namespace MiraAPI.Patches.Options;
|
|||||||
[HarmonyPatch(typeof(RolesSettingsMenu))]
|
[HarmonyPatch(typeof(RolesSettingsMenu))]
|
||||||
public static class RoleSettingMenuPatches
|
public static class RoleSettingMenuPatches
|
||||||
{
|
{
|
||||||
public static Dictionary<int, Vector3> RolePositions { get; set; } = [];
|
public static Dictionary<int, Vector3> Scrolls { get; } = [];
|
||||||
|
private static Dictionary<RoleOptionsGroup, bool> RoleGroupHidden { get; } = [];
|
||||||
private static Dictionary<RoleOptionsGroup, bool> RoleGroupHidden { get; set; } = [];
|
private static List<GameObject> Headers { get; } = [];
|
||||||
private static List<GameObject> Headers { get; set; } = [];
|
private static List<RoleOptionSetting> RoleOptionSettings { get; } = [];
|
||||||
private static List<RoleOptionSetting> RoleOptionSettings { get; set; } = [];
|
|
||||||
|
|
||||||
private static float ScrollerNum { get; set; } = 0.522f;
|
private static float ScrollerNum { get; set; } = 0.522f;
|
||||||
|
|
||||||
[HarmonyPrefix]
|
[HarmonyPrefix]
|
||||||
[HarmonyPatch(nameof(RolesSettingsMenu.SetQuotaTab))]
|
[HarmonyPatch(nameof(RolesSettingsMenu.SetQuotaTab))]
|
||||||
public static bool PatchStart(RolesSettingsMenu __instance)
|
public static bool SetQuotaTabPatch(RolesSettingsMenu __instance)
|
||||||
{
|
{
|
||||||
Headers.ForEach(Object.Destroy);
|
Headers.ForEach(Object.Destroy);
|
||||||
RoleOptionSettings.ForEach(Object.Destroy);
|
RoleOptionSettings.ForEach(Object.Destroy);
|
||||||
@@ -69,7 +68,7 @@ public static class RoleSettingMenuPatches
|
|||||||
|
|
||||||
var num3 = 0;
|
var num3 = 0;
|
||||||
|
|
||||||
var roleGroups = GameSettingMenuPatches.SelectedMod?.CustomRoles.Values.OfType<ICustomRole>()
|
var roleGroups = GameSettingMenuPatches.SelectedMod?.InternalRoles.Values.OfType<ICustomRole>()
|
||||||
.ToLookup(x => x.RoleOptionsGroup);
|
.ToLookup(x => x.RoleOptionsGroup);
|
||||||
|
|
||||||
if (roleGroups is null)
|
if (roleGroups is null)
|
||||||
@@ -234,7 +233,7 @@ public static class RoleSettingMenuPatches
|
|||||||
private static void SetScrollBounds(this Scroller scroller)
|
private static void SetScrollBounds(this Scroller scroller)
|
||||||
{
|
{
|
||||||
scroller.CalculateAndSetYBounds(1 + 1.5f * Headers.Count + RoleOptionSettings.Count, 1f, 6f, 0.43f);
|
scroller.CalculateAndSetYBounds(1 + 1.5f * Headers.Count + RoleOptionSettings.Count, 1f, 6f, 0.43f);
|
||||||
if (RolePositions.TryGetValue(GameSettingMenuPatches.SelectedModIdx, out var scroll))
|
if (Scrolls.TryGetValue(GameSettingMenuPatches.SelectedModIdx, out var scroll))
|
||||||
{
|
{
|
||||||
scroller.Inner.localPosition = scroll;
|
scroller.Inner.localPosition = scroll;
|
||||||
scroller.UpdateScrollBars();
|
scroller.UpdateScrollBars();
|
||||||
@@ -256,7 +255,7 @@ public static class RoleSettingMenuPatches
|
|||||||
[HarmonyPatch(nameof(RolesSettingsMenu.OpenChancesTab))]
|
[HarmonyPatch(nameof(RolesSettingsMenu.OpenChancesTab))]
|
||||||
public static void OpenChancesTabPostfix(RolesSettingsMenu __instance)
|
public static void OpenChancesTabPostfix(RolesSettingsMenu __instance)
|
||||||
{
|
{
|
||||||
if (GameSettingMenuPatches.SelectedModIdx == 0 || !__instance.scrollBar)
|
if (GameSettingMenuPatches.SelectedModIdx == 0)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -319,7 +318,7 @@ public static class RoleSettingMenuPatches
|
|||||||
var num = hasImage ? -0.872f : -1;
|
var num = hasImage ? -0.872f : -1;
|
||||||
|
|
||||||
// TODO: create sub groups under the role settings.
|
// TODO: create sub groups under the role settings.
|
||||||
var filteredOptions = GameSettingMenuPatches.SelectedMod?.OptionGroups
|
var filteredOptions = GameSettingMenuPatches.SelectedMod?.InternalOptionGroups
|
||||||
.Where(x=> x.OptionableType == role.GetType())
|
.Where(x=> x.OptionableType == role.GetType())
|
||||||
.SelectMany(x=>x.Options)
|
.SelectMany(x=>x.Options)
|
||||||
.ToList() ?? [];
|
.ToList() ?? [];
|
||||||
@@ -354,6 +353,7 @@ public static class RoleSettingMenuPatches
|
|||||||
newOpt.Initialize();
|
newOpt.Initialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Scrolls[GameSettingMenuPatches.SelectedModIdx] = __instance.scrollBar.Inner.localPosition;
|
||||||
__instance.scrollBar.CalculateAndSetYBounds(__instance.advancedSettingChildren.Count + 3, 1f, 6f, 0.45f);
|
__instance.scrollBar.CalculateAndSetYBounds(__instance.advancedSettingChildren.Count + 3, 1f, 6f, 0.45f);
|
||||||
__instance.scrollBar.ScrollToTop();
|
__instance.scrollBar.ScrollToTop();
|
||||||
}
|
}
|
||||||
@@ -366,7 +366,7 @@ public static class RoleSettingMenuPatches
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
RolePositions[GameSettingMenuPatches.SelectedModIdx] = __instance.scrollBar.Inner.localPosition;
|
Scrolls[GameSettingMenuPatches.SelectedModIdx] = __instance.scrollBar.Inner.localPosition;
|
||||||
|
|
||||||
__instance.roleDescriptionText.text = customRole.RoleLongDescription;
|
__instance.roleDescriptionText.text = customRole.RoleLongDescription;
|
||||||
__instance.roleTitleText.text = TranslationController.Instance.GetString(
|
__instance.roleTitleText.text = TranslationController.Instance.GetString(
|
||||||
@@ -485,7 +485,7 @@ public static class RoleSettingMenuPatches
|
|||||||
roleOptionSetting.titleText.horizontalAlignment = HorizontalAlignmentOptions.Left;
|
roleOptionSetting.titleText.horizontalAlignment = HorizontalAlignmentOptions.Left;
|
||||||
|
|
||||||
if (GameSettingMenuPatches.SelectedMod is null ||
|
if (GameSettingMenuPatches.SelectedMod is null ||
|
||||||
GameSettingMenuPatches.SelectedMod.OptionGroups
|
GameSettingMenuPatches.SelectedMod.InternalOptionGroups
|
||||||
.Exists(x => x.OptionableType == role.GetType()))
|
.Exists(x => x.OptionableType == role.GetType()))
|
||||||
{
|
{
|
||||||
var newButton = Object.Instantiate(roleOptionSetting.buttons[0], roleOptionSetting.transform);
|
var newButton = Object.Instantiate(roleOptionSetting.buttons[0], roleOptionSetting.transform);
|
||||||
@@ -517,7 +517,7 @@ public static class RoleSettingMenuPatches
|
|||||||
roleOptionSetting.ChancePlusBtn.gameObject.SetActive(false);
|
roleOptionSetting.ChancePlusBtn.gameObject.SetActive(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (index < GameSettingMenuPatches.SelectedMod?.CustomRoles.Count - 1)
|
if (index < GameSettingMenuPatches.SelectedMod?.InternalRoles.Count - 1)
|
||||||
{
|
{
|
||||||
ScrollerNum -= 0.43f;
|
ScrollerNum -= 0.43f;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ using MiraAPI.Events.Vanilla.Gameplay;
|
|||||||
using MiraAPI.Events.Vanilla.Player;
|
using MiraAPI.Events.Vanilla.Player;
|
||||||
using MiraAPI.Hud;
|
using MiraAPI.Hud;
|
||||||
using MiraAPI.Modifiers;
|
using MiraAPI.Modifiers;
|
||||||
using MiraAPI.Utilities;
|
using MiraAPI.Roles;
|
||||||
using MiraAPI.Voting;
|
using MiraAPI.Voting;
|
||||||
using Reactor.Utilities.Extensions;
|
using Reactor.Utilities.Extensions;
|
||||||
|
|
||||||
@@ -41,7 +41,7 @@ internal static class PlayerControlPatches
|
|||||||
// ReSharper disable once InconsistentNaming
|
// ReSharper disable once InconsistentNaming
|
||||||
public static void PlayerControlDiePostfix(PlayerControl __instance, DeathReason reason)
|
public static void PlayerControlDiePostfix(PlayerControl __instance, DeathReason reason)
|
||||||
{
|
{
|
||||||
var deathEvent = new PlayerDeathEvent(__instance, reason, Helpers.GetBodyById(__instance.PlayerId));
|
var deathEvent = new PlayerDeathEvent(__instance, reason);
|
||||||
MiraEventManager.InvokeEvent(deathEvent);
|
MiraEventManager.InvokeEvent(deathEvent);
|
||||||
|
|
||||||
var modifiersComponent = __instance.GetComponent<ModifierComponent>();
|
var modifiersComponent = __instance.GetComponent<ModifierComponent>();
|
||||||
@@ -81,6 +81,11 @@ internal static class PlayerControlPatches
|
|||||||
// ReSharper disable once InconsistentNaming
|
// ReSharper disable once InconsistentNaming
|
||||||
public static void PlayerControlFixedUpdatePostfix(PlayerControl __instance)
|
public static void PlayerControlFixedUpdatePostfix(PlayerControl __instance)
|
||||||
{
|
{
|
||||||
|
if (__instance.Data?.Role is ICustomRole customRole)
|
||||||
|
{
|
||||||
|
customRole.PlayerControlFixedUpdate(__instance);
|
||||||
|
}
|
||||||
|
|
||||||
if (!__instance.AmOwner)
|
if (!__instance.AmOwner)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
using HarmonyLib;
|
using System.Collections.Generic;
|
||||||
|
using System.Reflection;
|
||||||
|
using HarmonyLib;
|
||||||
using MiraAPI.Events;
|
using MiraAPI.Events;
|
||||||
using MiraAPI.Events.Vanilla.Gameplay;
|
using MiraAPI.Events.Vanilla.Gameplay;
|
||||||
using MiraAPI.Events.Vanilla.Meeting;
|
using MiraAPI.Events.Vanilla.Meeting;
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ public static class GameStartupPatch
|
|||||||
private static bool _runOnce;
|
private static bool _runOnce;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// This is used for registering roles when the game opens, might be a janky solution, but it works.
|
/// This is used for registering roles when the game opens, might be a janky solution, but it works
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[HarmonyPostfix]
|
[HarmonyPostfix]
|
||||||
[HarmonyPatch(nameof(MainMenuManager.Start))]
|
[HarmonyPatch(nameof(MainMenuManager.Start))]
|
||||||
|
|||||||
@@ -24,4 +24,4 @@ public static class HauntMenuMinigamePatch
|
|||||||
__instance.FilterText.text = role.NiceName;
|
__instance.FilterText.text = role.NiceName;
|
||||||
__instance.FilterText.color = color;
|
__instance.FilterText.color = color;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -62,6 +62,8 @@ public static class HudManagerPatches
|
|||||||
|
|
||||||
if (role is ICustomRole { Configuration.RoleHintType: RoleHintType.RoleTab } customRole)
|
if (role is ICustomRole { Configuration.RoleHintType: RoleHintType.RoleTab } customRole)
|
||||||
{
|
{
|
||||||
|
customRole.HudUpdate(__instance);
|
||||||
|
|
||||||
if (_roleTab == null)
|
if (_roleTab == null)
|
||||||
{
|
{
|
||||||
_roleTab = CustomRoleManager.CreateRoleTab(customRole);
|
_roleTab = CustomRoleManager.CreateRoleTab(customRole);
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ namespace MiraAPI.Patches.Roles;
|
|||||||
public static class RoleOptionsCollectionPatch
|
public static class RoleOptionsCollectionPatch
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Set the role chance for custom Launchpad roles based on config.
|
/// Set the role chance for custom Launchpad roles based on config
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>Return false to skip original method, true to not.</returns>
|
/// <returns>Return false to skip original method, true to not.</returns>
|
||||||
[HarmonyPrefix]
|
[HarmonyPrefix]
|
||||||
@@ -42,7 +42,7 @@ public static class RoleOptionsCollectionPatch
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Set the amount for custom Launchpad roles based on config.
|
/// Set the amount for custom Launchpad roles based on config
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>Return false to skip original method, true to not.</returns>
|
/// <returns>Return false to skip original method, true to not.</returns>
|
||||||
[HarmonyPrefix]
|
[HarmonyPrefix]
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ using MiraAPI.Roles;
|
|||||||
namespace MiraAPI.Patches.Roles;
|
namespace MiraAPI.Patches.Roles;
|
||||||
|
|
||||||
[HarmonyPatch(typeof(SabotageButton))]
|
[HarmonyPatch(typeof(SabotageButton))]
|
||||||
public static class SabotageButtonPatch
|
public class SabotageButtonPatch
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Patches the Sabotage button to check if the player's custom role can use sabotage.
|
/// Patches the Sabotage button to check if the player's custom role can use sabotage.
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ using MiraAPI.Events.Vanilla.Meeting.Voting;
|
|||||||
using MiraAPI.Modifiers;
|
using MiraAPI.Modifiers;
|
||||||
using MiraAPI.Utilities;
|
using MiraAPI.Utilities;
|
||||||
using MiraAPI.Voting;
|
using MiraAPI.Voting;
|
||||||
|
using Reactor.Utilities;
|
||||||
|
|
||||||
namespace MiraAPI.Patches.Voting;
|
namespace MiraAPI.Patches.Voting;
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +0,0 @@
|
|||||||
using System;
|
|
||||||
|
|
||||||
namespace MiraAPI.PluginLoading;
|
|
||||||
|
|
||||||
public interface IMiraExtension
|
|
||||||
{
|
|
||||||
public Type GetBasePluginType();
|
|
||||||
}
|
|
||||||
@@ -6,7 +6,9 @@ using MiraAPI.GameModes;
|
|||||||
using MiraAPI.GameOptions;
|
using MiraAPI.GameOptions;
|
||||||
using MiraAPI.Hud;
|
using MiraAPI.Hud;
|
||||||
using MiraAPI.Modifiers;
|
using MiraAPI.Modifiers;
|
||||||
|
using MiraAPI.Presets;
|
||||||
|
|
||||||
|
// ReSharper disable UnusedAutoPropertyAccessor.Global
|
||||||
namespace MiraAPI.PluginLoading;
|
namespace MiraAPI.PluginLoading;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -23,61 +25,58 @@ public class MiraPluginInfo
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Get a read only collection of this plugin's modifiers. This is probably not safe because they are uninitialized.
|
/// Gets a read only collection of this plugin's modifiers. This is not safe for modifiers with constructors.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>Readonly collection of modifiers.</returns>
|
public IReadOnlyCollection<BaseModifier> Modifiers { get; private set; } = null!;
|
||||||
public IReadOnlyCollection<BaseModifier> GetModifiers()
|
|
||||||
{
|
|
||||||
return Modifiers.AsReadOnly();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Get a read only collection of this plugin's Option Groups.
|
/// Gets a read only collection of this plugin's Option Groups.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>Readonly collection of option groups.</returns>
|
public IReadOnlyCollection<AbstractOptionGroup> OptionGroups { get; private set; } = null!;
|
||||||
public IReadOnlyCollection<AbstractOptionGroup> GetOptionGroups()
|
|
||||||
{
|
|
||||||
return OptionGroups.AsReadOnly();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a read only collection of this plugin's options.
|
/// Gets a read only collection of this plugin's options.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>Read only collection of options.</returns>
|
public IReadOnlyCollection<IModdedOption> Options { get; private set; } = null!;
|
||||||
public IReadOnlyCollection<IModdedOption> GetOptions()
|
|
||||||
{
|
|
||||||
return Options.AsReadOnly();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a read only dictionary of Role IDs and the RoleBehaviour object they are associated with.
|
/// Gets a read only dictionary of Role IDs and the RoleBehaviour object they are associated with.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>Read only dictionary of IDs and Roles.</returns>
|
public ReadOnlyDictionary<ushort, RoleBehaviour> Roles { get; private set; } = null!;
|
||||||
public ReadOnlyDictionary<ushort, RoleBehaviour> GetRoles()
|
|
||||||
{
|
|
||||||
return new ReadOnlyDictionary<ushort, RoleBehaviour>(CustomRoles);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a read only collection of this plugin's custom buttons.
|
/// Gets a read only collection of this plugin's custom buttons.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>Read only collection of buttons.</returns>
|
public IReadOnlyCollection<CustomActionButton> Buttons { get; private set; } = null!;
|
||||||
public IReadOnlyCollection<CustomActionButton> GetButtons()
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a read only dictionary of this plugin's custom game modes.
|
||||||
|
/// </summary>
|
||||||
|
public IReadOnlyCollection<OptionPreset> Presets { get; internal set; } = null!;
|
||||||
|
|
||||||
|
internal void SavePublicCollections()
|
||||||
{
|
{
|
||||||
return Buttons.AsReadOnly();
|
Presets = [..InternalPresets];
|
||||||
|
Modifiers = [..InternalModifiers];
|
||||||
|
OptionGroups = [..InternalOptionGroups];
|
||||||
|
Options = [..InternalOptions];
|
||||||
|
Roles = new ReadOnlyDictionary<ushort, RoleBehaviour>(InternalRoles);
|
||||||
|
Buttons = [..InternalButtons];
|
||||||
}
|
}
|
||||||
|
|
||||||
internal List<AbstractOptionGroup> OptionGroups { get; } = [];
|
internal List<OptionPreset> InternalPresets { get; } = [];
|
||||||
|
|
||||||
internal List<IModdedOption> Options { get; } = [];
|
internal List<AbstractOptionGroup> InternalOptionGroups { get; } = [];
|
||||||
|
|
||||||
internal List<BaseModifier> Modifiers { get; } = [];
|
internal List<IModdedOption> InternalOptions { get; } = [];
|
||||||
|
|
||||||
internal Dictionary<ushort, RoleBehaviour> CustomRoles { get; } = [];
|
internal List<BaseModifier> InternalModifiers { get; } = [];
|
||||||
|
|
||||||
internal Dictionary<int, CustomGameMode> GameModes { get; } = [];
|
internal Dictionary<ushort, RoleBehaviour> InternalRoles { get; } = [];
|
||||||
|
|
||||||
internal List<CustomActionButton> Buttons { get; } = [];
|
internal Dictionary<int, CustomGameMode> InternalGameModes { get; } = [];
|
||||||
|
|
||||||
|
internal List<CustomActionButton> InternalButtons { get; } = [];
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the plugin's ID, as defined in the plugin's BepInEx metadata.
|
/// Gets the plugin's ID, as defined in the plugin's BepInEx metadata.
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ using System.Collections.ObjectModel;
|
|||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using BepInEx;
|
|
||||||
using BepInEx.Unity.IL2CPP;
|
using BepInEx.Unity.IL2CPP;
|
||||||
using MiraAPI.Colors;
|
using MiraAPI.Colors;
|
||||||
using MiraAPI.Events;
|
using MiraAPI.Events;
|
||||||
@@ -13,6 +12,7 @@ using MiraAPI.GameOptions;
|
|||||||
using MiraAPI.GameOptions.Attributes;
|
using MiraAPI.GameOptions.Attributes;
|
||||||
using MiraAPI.Hud;
|
using MiraAPI.Hud;
|
||||||
using MiraAPI.Modifiers;
|
using MiraAPI.Modifiers;
|
||||||
|
using MiraAPI.Presets;
|
||||||
using MiraAPI.Roles;
|
using MiraAPI.Roles;
|
||||||
using MiraAPI.Utilities;
|
using MiraAPI.Utilities;
|
||||||
using Reactor.Networking;
|
using Reactor.Networking;
|
||||||
@@ -27,8 +27,9 @@ public sealed class MiraPluginManager
|
|||||||
{
|
{
|
||||||
private readonly Dictionary<Assembly, MiraPluginInfo> _registeredPlugins = [];
|
private readonly Dictionary<Assembly, MiraPluginInfo> _registeredPlugins = [];
|
||||||
|
|
||||||
internal MiraPluginInfo[] RegisteredPlugins() => [.. _registeredPlugins.Values];
|
internal MiraPluginInfo[] RegisteredPlugins { get; private set; } = null!;
|
||||||
internal Dictionary<MiraPluginInfo, List<Type>> QueuedRoleRegistrations { get; } = new();
|
|
||||||
|
internal Dictionary<MiraPluginInfo, List<Type>> QueuedRoleRegistrations { get; } = [];
|
||||||
internal static MiraPluginManager Instance { get; private set; } = new();
|
internal static MiraPluginManager Instance { get; private set; } = new();
|
||||||
|
|
||||||
internal void Initialize()
|
internal void Initialize()
|
||||||
@@ -36,29 +37,91 @@ public sealed class MiraPluginManager
|
|||||||
Instance = this;
|
Instance = this;
|
||||||
IL2CPPChainloader.Instance.PluginLoad += (pluginInfo, assembly, plugin) =>
|
IL2CPPChainloader.Instance.PluginLoad += (pluginInfo, assembly, plugin) =>
|
||||||
{
|
{
|
||||||
if (plugin is IMiraPlugin miraPlugin)
|
if (plugin is not IMiraPlugin miraPlugin)
|
||||||
{
|
{
|
||||||
var miraInfo = new MiraPluginInfo(miraPlugin, pluginInfo);
|
return;
|
||||||
RegisterPlugin(miraInfo, assembly);
|
|
||||||
_registeredPlugins.Add(assembly, miraInfo);
|
|
||||||
}
|
}
|
||||||
if (plugin is IMiraExtension miraExtension)
|
|
||||||
|
var info = new MiraPluginInfo(miraPlugin, pluginInfo);
|
||||||
|
var roles = new List<Type>();
|
||||||
|
|
||||||
|
var oldConfigSetting = info.PluginConfig.SaveOnConfigSet;
|
||||||
|
info.PluginConfig.SaveOnConfigSet = false;
|
||||||
|
|
||||||
|
foreach (var type in assembly.GetTypes())
|
||||||
{
|
{
|
||||||
var basePlugin = miraExtension.GetBasePluginType();
|
if (type.GetCustomAttribute<MiraIgnoreAttribute>() != null)
|
||||||
var basePluginInfo = _registeredPlugins.Values.FirstOrDefault(x => x.MiraPlugin.GetType() == basePlugin);
|
|
||||||
if (basePluginInfo == null)
|
|
||||||
{
|
{
|
||||||
Logger<MiraApiPlugin>.Error($"Base plugin {basePlugin.Name} not found for extension {pluginInfo.Metadata.GUID}.");
|
continue;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
RegisterPlugin(basePluginInfo, assembly);
|
foreach (var method in type.GetMethods(BindingFlags.Static | BindingFlags.Public))
|
||||||
|
{
|
||||||
|
var eventAttribute = method.GetCustomAttribute<RegisterEventAttribute>();
|
||||||
|
if (eventAttribute != null)
|
||||||
|
{
|
||||||
|
var parameters = method.GetParameters();
|
||||||
|
if (parameters.Length != 1 || !parameters[0].ParameterType.IsSubclassOf(typeof(MiraEvent)))
|
||||||
|
{
|
||||||
|
Logger<MiraApiPlugin>.Error($"Invalid event registration method {method.Name} in {type.Name}");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var paramType = parameters[0].ParameterType;
|
||||||
|
MiraEventManager.RegisterEventHandler(paramType, method, eventAttribute.Priority);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (RegisterModifier(type, info))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (RegisterOptions(type, info))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (RegisterRoleAttribute(type, info, out var role))
|
||||||
|
{
|
||||||
|
roles.Add(role);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (RegisterButtonAttribute(type, info))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (RegisterGameOver(type))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
RegisterColorClasses(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
info.PluginConfig.Save();
|
||||||
|
info.PluginConfig.SaveOnConfigSet = oldConfigSetting;
|
||||||
|
|
||||||
|
info.InternalOptionGroups.Sort((x, y) => x.GroupPriority.CompareTo(y.GroupPriority));
|
||||||
|
QueuedRoleRegistrations.Add(info, roles);
|
||||||
|
|
||||||
|
_registeredPlugins.Add(assembly, info);
|
||||||
|
|
||||||
|
info.SavePublicCollections();
|
||||||
|
PresetManager.CreateDefaultPreset(info);
|
||||||
|
PresetManager.LoadPresets(info);
|
||||||
|
Logger<MiraApiPlugin>.Info($"Registering mod {pluginInfo.Metadata.GUID} with Mira API.");
|
||||||
};
|
};
|
||||||
IL2CPPChainloader.Instance.Finished += PaletteManager.RegisterAllColors;
|
IL2CPPChainloader.Instance.Finished += PaletteManager.RegisterAllColors;
|
||||||
IL2CPPChainloader.Instance.Finished += () =>
|
IL2CPPChainloader.Instance.Finished += () =>
|
||||||
{
|
{
|
||||||
|
// Save all buttons into a read-only collection for easy access
|
||||||
CustomButtonManager.Buttons = new ReadOnlyCollection<CustomActionButton>(CustomButtonManager.CustomButtons);
|
CustomButtonManager.Buttons = new ReadOnlyCollection<CustomActionButton>(CustomButtonManager.CustomButtons);
|
||||||
|
|
||||||
|
// Cache all the registered plugins into an array for easy access
|
||||||
|
RegisteredPlugins = [.._registeredPlugins.Values];
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -72,84 +135,6 @@ public sealed class MiraPluginManager
|
|||||||
return Instance._registeredPlugins.Values.FirstOrDefault(plugin => plugin.PluginId == pluginId);
|
return Instance._registeredPlugins.Values.FirstOrDefault(plugin => plugin.PluginId == pluginId);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RegisterPlugin(MiraPluginInfo info, Assembly assembly)
|
|
||||||
{
|
|
||||||
var roles = new List<Type>();
|
|
||||||
|
|
||||||
var oldConfigSetting = info.PluginConfig.SaveOnConfigSet;
|
|
||||||
info.PluginConfig.SaveOnConfigSet = false;
|
|
||||||
|
|
||||||
foreach (var type in assembly.GetTypes())
|
|
||||||
{
|
|
||||||
if (type.GetCustomAttribute<MiraIgnoreAttribute>() != null)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var method in type.GetMethods())
|
|
||||||
{
|
|
||||||
var eventAttribute = method.GetCustomAttribute<RegisterEventAttribute>();
|
|
||||||
if (eventAttribute == null)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!method.IsStatic)
|
|
||||||
{
|
|
||||||
Logger<MiraApiPlugin>.Error($"Event method {method.Name} in {type.Name} must be static.");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
var parameters = method.GetParameters();
|
|
||||||
if (parameters.Length != 1 || !parameters[0].ParameterType.IsSubclassOf(typeof(MiraEvent)))
|
|
||||||
{
|
|
||||||
Logger<MiraApiPlugin>.Error($"Invalid event registration method {method.Name} in {type.Name}");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
var paramType = parameters[0].ParameterType;
|
|
||||||
MiraEventManager.RegisterEventHandler(paramType, method, eventAttribute.Priority);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (RegisterModifier(type, info))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (RegisterOptions(type, info))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (RegisterRole(type, info, out var role))
|
|
||||||
{
|
|
||||||
roles.Add(role);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (RegisterButton(type, info))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (RegisterGameOver(type))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
RegisterColorClasses(type);
|
|
||||||
}
|
|
||||||
|
|
||||||
info.PluginConfig.Save();
|
|
||||||
info.PluginConfig.SaveOnConfigSet = oldConfigSetting;
|
|
||||||
|
|
||||||
info.OptionGroups.Sort((x, y) => x.GroupPriority.CompareTo(y.GroupPriority));
|
|
||||||
QueuedRoleRegistrations.TryAdd(info, []);
|
|
||||||
QueuedRoleRegistrations[info].AddRange(roles);
|
|
||||||
|
|
||||||
Logger<MiraApiPlugin>.Info($"Registering mod {info.PluginId} with Mira API.");
|
|
||||||
}
|
|
||||||
|
|
||||||
private static bool RegisterGameOver(Type type)
|
private static bool RegisterGameOver(Type type)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@@ -179,12 +164,6 @@ public sealed class MiraPluginManager
|
|||||||
|
|
||||||
foreach (var property in type.GetProperties())
|
foreach (var property in type.GetProperties())
|
||||||
{
|
{
|
||||||
if (property.GetMethod?.IsStatic == true)
|
|
||||||
{
|
|
||||||
Logger<MiraApiPlugin>.Error($"Option property {property.Name} in {type.Name} must not be static.");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (property.PropertyType.IsAssignableTo(typeof(IModdedOption)))
|
if (property.PropertyType.IsAssignableTo(typeof(IModdedOption)))
|
||||||
{
|
{
|
||||||
ModdedOptionsManager.RegisterPropertyOption(type, property, pluginInfo);
|
ModdedOptionsManager.RegisterPropertyOption(type, property, pluginInfo);
|
||||||
@@ -200,21 +179,16 @@ public sealed class MiraPluginManager
|
|||||||
ModdedOptionsManager.RegisterAttributeOption(type, attribute, property, pluginInfo);
|
ModdedOptionsManager.RegisterAttributeOption(type, attribute, property, pluginInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var field in type.GetFields().Where(f=>f.FieldType.IsAssignableTo(typeof(IModdedOption))))
|
|
||||||
{
|
|
||||||
Logger<MiraApiPlugin>.Error($"{field.Name} is a field, not a property. Use properties for options.");
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
Logger<MiraApiPlugin>.Error($"Failed to register options for {type.Name}: {e.ToString()}");
|
Logger<MiraApiPlugin>.Error($"Failed to register options for {type.Name}: {e}");
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool RegisterRole(Type type, MiraPluginInfo pluginInfo, [NotNullWhen(true)] out Type? role)
|
private static bool RegisterRoleAttribute(Type type, MiraPluginInfo pluginInfo, [NotNullWhen(true)] out Type? role)
|
||||||
{
|
{
|
||||||
role = null;
|
role = null;
|
||||||
try
|
try
|
||||||
@@ -270,11 +244,6 @@ public sealed class MiraPluginManager
|
|||||||
|
|
||||||
PaletteManager.CustomColors.Add(color);
|
PaletteManager.CustomColors.Add(color);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var field in type.GetFields().Where(f=>f.FieldType.IsAssignableTo(typeof(CustomColor))))
|
|
||||||
{
|
|
||||||
Logger<MiraApiPlugin>.Error($"{field.Name} is a field, not a property. Use properties for colors.");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
@@ -295,7 +264,7 @@ public sealed class MiraPluginManager
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool RegisterButton(Type type, MiraPluginInfo pluginInfo)
|
private static bool RegisterButtonAttribute(Type type, MiraPluginInfo pluginInfo)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -0,0 +1,74 @@
|
|||||||
|
using System.Linq;
|
||||||
|
using BepInEx.Configuration;
|
||||||
|
using MiraAPI.GameOptions;
|
||||||
|
using MiraAPI.PluginLoading;
|
||||||
|
using MiraAPI.Roles;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace MiraAPI.Presets;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a preset of game options that can be applied to the game.
|
||||||
|
/// </summary>
|
||||||
|
public class OptionPreset
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the name of the preset.
|
||||||
|
/// </summary>
|
||||||
|
public string Name { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the plugin associated with the preset.
|
||||||
|
/// </summary>
|
||||||
|
public MiraPluginInfo Plugin { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the configuration file of the plugin associated with the preset.
|
||||||
|
/// </summary>
|
||||||
|
public ConfigFile PluginConfig { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the configuration file for the preset.
|
||||||
|
/// </summary>
|
||||||
|
public ConfigFile PresetConfig { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the button associated with the preset in the UI.
|
||||||
|
/// </summary>
|
||||||
|
public GameObject? PresetButton { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="OptionPreset"/> class with the specified name and configuration file.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">>The name of the preset.</param>
|
||||||
|
/// <param name="plugin">The plugin associated with the preset.</param>
|
||||||
|
/// <param name="presetConfig">>The configuration file for the preset.</param>
|
||||||
|
public OptionPreset(string name, MiraPluginInfo plugin, ConfigFile presetConfig)
|
||||||
|
{
|
||||||
|
Name = name;
|
||||||
|
Plugin = plugin;
|
||||||
|
PluginConfig = plugin.PluginConfig;
|
||||||
|
PresetConfig = presetConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Loads the preset by applying the values from the preset configuration to the plugin configuration.
|
||||||
|
/// </summary>
|
||||||
|
public void LoadPreset()
|
||||||
|
{
|
||||||
|
PresetConfig.Reload();
|
||||||
|
foreach (var option in Plugin.InternalOptions)
|
||||||
|
{
|
||||||
|
option.LoadFromPreset(PresetConfig);
|
||||||
|
}
|
||||||
|
|
||||||
|
ModdedOptionsManager.SyncAllOptions();
|
||||||
|
|
||||||
|
foreach (var role in Plugin.InternalRoles.Values.OfType<ICustomRole>())
|
||||||
|
{
|
||||||
|
role.LoadFromPreset(PresetConfig);
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomRoleManager.SyncAllRoleSettings();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,95 @@
|
|||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using BepInEx.Configuration;
|
||||||
|
using MiraAPI.PluginLoading;
|
||||||
|
using MiraAPI.Roles;
|
||||||
|
using Reactor.Utilities;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace MiraAPI.Presets;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Provides functionality to manage and load game option presets for plugins.
|
||||||
|
/// </summary>
|
||||||
|
public static class PresetManager
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the directory where the presets are stored.
|
||||||
|
/// </summary>
|
||||||
|
public static string PresetDirectory { get; } = Path.GetFullPath("mira_presets", Application.persistentDataPath);
|
||||||
|
|
||||||
|
internal static void CreateDefaultPreset(MiraPluginInfo plugin)
|
||||||
|
{
|
||||||
|
var presetPath = Path.Combine(PresetDirectory, plugin.PluginId);
|
||||||
|
if (!Directory.Exists(presetPath))
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory(presetPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
var presetConfig = new ConfigFile(Path.Combine(presetPath, "Default.cfg"), false);
|
||||||
|
|
||||||
|
foreach (var option in plugin.InternalOptions.Where(x => x.IncludeInPreset))
|
||||||
|
{
|
||||||
|
option.SaveToPreset(presetConfig, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var role in plugin.InternalRoles.Values.OfType<ICustomRole>())
|
||||||
|
{
|
||||||
|
role.SaveToPreset(presetConfig);
|
||||||
|
}
|
||||||
|
|
||||||
|
presetConfig.Save();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Loads the presets for the specified plugin by reading the configuration files from the preset directory.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="plugin">>The plugin for which the presets should be loaded.</param>
|
||||||
|
public static void LoadPresets(MiraPluginInfo plugin)
|
||||||
|
{
|
||||||
|
foreach (var btn in plugin.InternalPresets.Select(x=>x.PresetButton))
|
||||||
|
{
|
||||||
|
if (btn != null)
|
||||||
|
{
|
||||||
|
Object.DestroyImmediate(btn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
plugin.InternalPresets.Clear();
|
||||||
|
if (!Directory.Exists(PresetDirectory))
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory(PresetDirectory);
|
||||||
|
}
|
||||||
|
|
||||||
|
var pluginPresetPath = Path.Combine(PresetDirectory, plugin.PluginId);
|
||||||
|
if (!Directory.Exists(pluginPresetPath))
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory(pluginPresetPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var file in Directory.GetFiles(pluginPresetPath, "*.cfg"))
|
||||||
|
{
|
||||||
|
Logger<MiraApiPlugin>.Info($"Loading preset file {file}");
|
||||||
|
var presetName = Path.GetFileNameWithoutExtension(file);
|
||||||
|
var presetConfig = new ConfigFile(file, false)
|
||||||
|
{
|
||||||
|
SaveOnConfigSet = false,
|
||||||
|
};
|
||||||
|
|
||||||
|
foreach (var option in plugin.InternalOptions.Where(x=>x.IncludeInPreset))
|
||||||
|
{
|
||||||
|
option.Bind(presetConfig);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var role in plugin.InternalRoles.Values.OfType<ICustomRole>().Where(x=>!x.Configuration.HideSettings))
|
||||||
|
{
|
||||||
|
role.BindConfig(presetConfig);
|
||||||
|
}
|
||||||
|
|
||||||
|
presetConfig.Save();
|
||||||
|
|
||||||
|
plugin.InternalPresets.Add(new OptionPreset(presetName, plugin, presetConfig));
|
||||||
|
}
|
||||||
|
plugin.Presets = [.. plugin.InternalPresets];
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,91 @@
|
|||||||
|
using System;
|
||||||
|
using Il2CppInterop.Runtime.InteropTypes.Fields;
|
||||||
|
using MiraAPI.Modifiers.ModifierDisplay;
|
||||||
|
using MiraAPI.Utilities;
|
||||||
|
using MiraAPI.Utilities.Assets;
|
||||||
|
using Reactor.Utilities.Attributes;
|
||||||
|
using Reactor.Utilities.Extensions;
|
||||||
|
using TMPro;
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEngine.Events;
|
||||||
|
using UnityEngine.UI;
|
||||||
|
|
||||||
|
[RegisterInIl2Cpp]
|
||||||
|
public class SavePresetPopup(nint ptr) : Minigame(ptr)
|
||||||
|
{
|
||||||
|
private PassiveButton saveButton;
|
||||||
|
private PassiveButton closeButton;
|
||||||
|
private TextMeshPro textBoxText;
|
||||||
|
private TextBoxTMP textBox;
|
||||||
|
|
||||||
|
private Action<string> onSave;
|
||||||
|
|
||||||
|
// Cleanup holder object
|
||||||
|
public void OnDestroy()
|
||||||
|
{
|
||||||
|
transform.parent.gameObject.Destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Close()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Awake()
|
||||||
|
{
|
||||||
|
var textboxHolder = transform.GetChild(1).GetChild(1);
|
||||||
|
saveButton = transform.FindChild("SaveButton").GetComponent<PassiveButton>();
|
||||||
|
closeButton = transform.FindChild("CloseButton").GetComponent<PassiveButton>();
|
||||||
|
textBox = textboxHolder.GetChild(0).GetComponent<TextBoxTMP>();
|
||||||
|
textBoxText = textBox.transform.GetChild(0).GetComponent<TextMeshPro>();
|
||||||
|
|
||||||
|
saveButton.OnClick = new Button.ButtonClickedEvent();
|
||||||
|
saveButton.OnClick.AddListener((UnityAction)(() =>
|
||||||
|
{
|
||||||
|
onSave.Invoke(textBoxText.text);
|
||||||
|
this.BaseClose();
|
||||||
|
}));
|
||||||
|
|
||||||
|
closeButton.OnClick = new Button.ButtonClickedEvent();
|
||||||
|
closeButton.OnClick.AddListener((UnityAction)(() =>
|
||||||
|
{
|
||||||
|
this.BaseClose();
|
||||||
|
}));
|
||||||
|
|
||||||
|
textBox.OnChange = new Button.ButtonClickedEvent();
|
||||||
|
textBox.OnChange.AddListener((UnityAction)(() =>
|
||||||
|
{
|
||||||
|
textBoxText.text = textBoxText.text.Replace(" ", string.Empty);
|
||||||
|
}));
|
||||||
|
|
||||||
|
textBox.GetComponent<PassiveButton>().OnClick.AddListener((UnityAction)(() =>
|
||||||
|
{
|
||||||
|
textBox.GiveFocus();
|
||||||
|
}));
|
||||||
|
|
||||||
|
foreach (var tmp in gameObject.GetComponentsInChildren<TextMeshPro>())
|
||||||
|
{
|
||||||
|
if (tmp.gameObject.transform.parent.name == "Textbox") continue;
|
||||||
|
var text = tmp.text;
|
||||||
|
tmp.text = $"<font=\"LiberationSans SDF\" material=\"LiberationSans SDF RadialMenu Material\">{text}</font>";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void CreatePopup(Action<string> saveAction)
|
||||||
|
{
|
||||||
|
// Because innerscuff doesnt account for Z value in Close animation
|
||||||
|
var holder = new GameObject("PopupHolder")
|
||||||
|
{
|
||||||
|
transform =
|
||||||
|
{
|
||||||
|
parent = Camera.main!.transform,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
holder.transform.localPosition = new Vector3(0, -1f, -500);
|
||||||
|
|
||||||
|
var gameObject = Instantiate(MiraAssets.PresetSavePopup.LoadAsset(), holder.transform);
|
||||||
|
var popup = gameObject.GetComponent<SavePresetPopup>();
|
||||||
|
popup.onSave = saveAction;
|
||||||
|
popup.Begin(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 2.0 KiB |
Binary file not shown.
@@ -72,7 +72,7 @@ public static class CustomRoleManager
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
pluginInfo.CustomRoles.Add((ushort)role.Role, role);
|
pluginInfo.InternalRoles.Add((ushort)role.Role, role);
|
||||||
}
|
}
|
||||||
|
|
||||||
pluginInfo.PluginConfig.Save();
|
pluginInfo.PluginConfig.Save();
|
||||||
@@ -161,7 +161,7 @@ public static class CustomRoleManager
|
|||||||
/// <returns>A MiraPluginInfo object representing the parent mod of the role.</returns>
|
/// <returns>A MiraPluginInfo object representing the parent mod of the role.</returns>
|
||||||
public static MiraPluginInfo FindParentMod(ICustomRole role)
|
public static MiraPluginInfo FindParentMod(ICustomRole role)
|
||||||
{
|
{
|
||||||
return MiraPluginManager.Instance.RegisteredPlugins().First(plugin => plugin.CustomRoles.ContainsValue(role as RoleBehaviour ?? throw new InvalidOperationException()));
|
return MiraPluginManager.Instance.RegisteredPlugins.First(plugin => plugin.InternalRoles.ContainsValue(role as RoleBehaviour ?? throw new InvalidOperationException()));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -236,7 +236,7 @@ public static class CustomRoleManager
|
|||||||
// we dont know how other plugins handle their configs
|
// we dont know how other plugins handle their configs
|
||||||
// this way, all the options are saved at once, instead of one by one
|
// this way, all the options are saved at once, instead of one by one
|
||||||
var oldConfigSetting = new Dictionary<MiraPluginInfo, bool>();
|
var oldConfigSetting = new Dictionary<MiraPluginInfo, bool>();
|
||||||
foreach (var plugin in MiraPluginManager.Instance.RegisteredPlugins())
|
foreach (var plugin in MiraPluginManager.Instance.RegisteredPlugins)
|
||||||
{
|
{
|
||||||
oldConfigSetting.Add(plugin, plugin.PluginConfig.SaveOnConfigSet);
|
oldConfigSetting.Add(plugin, plugin.PluginConfig.SaveOnConfigSet);
|
||||||
plugin.PluginConfig.SaveOnConfigSet = false;
|
plugin.PluginConfig.SaveOnConfigSet = false;
|
||||||
@@ -271,7 +271,7 @@ public static class CustomRoleManager
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var plugin in MiraPluginManager.Instance.RegisteredPlugins())
|
foreach (var plugin in MiraPluginManager.Instance.RegisteredPlugins)
|
||||||
{
|
{
|
||||||
plugin.PluginConfig.Save();
|
plugin.PluginConfig.Save();
|
||||||
plugin.PluginConfig.SaveOnConfigSet = oldConfigSetting[plugin];
|
plugin.PluginConfig.SaveOnConfigSet = oldConfigSetting[plugin];
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Linq;
|
||||||
using System.Linq;
|
|
||||||
|
|
||||||
namespace MiraAPI.Roles;
|
namespace MiraAPI.Roles;
|
||||||
|
|
||||||
@@ -9,11 +8,12 @@ namespace MiraAPI.Roles;
|
|||||||
/// <typeparam name="T">The role you are trying to access.</typeparam>
|
/// <typeparam name="T">The role you are trying to access.</typeparam>
|
||||||
public static class CustomRoleSingleton<T> where T : ICustomRole
|
public static class CustomRoleSingleton<T> where T : ICustomRole
|
||||||
{
|
{
|
||||||
private static T? _instance;
|
private static ICustomRole? _instance;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the instance of the role.
|
/// Gets the instance of the role.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[SuppressMessage("Design", "CA1000:Do not declare static members on generic types", Justification = "This is a utility class to get the instance of a custom role.")]
|
#pragma warning disable CA1000
|
||||||
public static T Instance => _instance ??= CustomRoleManager.CustomRoles.Values.OfType<T>().Single();
|
public static ICustomRole Instance => _instance ??= CustomRoleManager.CustomRoles.Values.OfType<T>().Single();
|
||||||
|
#pragma warning restore CA1000
|
||||||
}
|
}
|
||||||
@@ -73,9 +73,56 @@ public interface ICustomRole : IOptionable
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
MiraPluginInfo ParentMod => CustomRoleManager.FindParentMod(this);
|
MiraPluginInfo ParentMod => CustomRoleManager.FindParentMod(this);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This method runs on the PlayerControl.FixedUpdate method for ALL players with this role.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="playerControl">The PlayerControl that has this role.</param>
|
||||||
|
void PlayerControlFixedUpdate(PlayerControl playerControl)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
internal ConfigDefinition NumConfigDefinition => new("Roles", $"Num {GetType().FullName}");
|
internal ConfigDefinition NumConfigDefinition => new("Roles", $"Num {GetType().FullName}");
|
||||||
internal ConfigDefinition ChanceConfigDefinition => new("Roles", $"Chance {GetType().FullName}");
|
internal ConfigDefinition ChanceConfigDefinition => new("Roles", $"Chance {GetType().FullName}");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Binds the configuration options for this role to the provided ConfigFile.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="config">The ConfigFile to bind the options to.</param>
|
||||||
|
public virtual void BindConfig(ConfigFile config)
|
||||||
|
{
|
||||||
|
config.Bind(NumConfigDefinition, Configuration.DefaultRoleCount);
|
||||||
|
config.Bind(ChanceConfigDefinition, Configuration.DefaultChance);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Saves the role's configuration to a preset ConfigFile.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="presetConfig">The ConfigFile to save the preset configuration to.</param>
|
||||||
|
/// <param name="useDefault">Whether to use the default values for the configuration.</param>
|
||||||
|
public virtual void SaveToPreset(ConfigFile presetConfig, bool useDefault=false)
|
||||||
|
{
|
||||||
|
BindConfig(presetConfig);
|
||||||
|
presetConfig[NumConfigDefinition].BoxedValue = useDefault ? Configuration.DefaultRoleCount : GetCount();
|
||||||
|
presetConfig[ChanceConfigDefinition].BoxedValue = useDefault ? Configuration.DefaultChance : GetChance();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Loads the role's configuration from a preset ConfigFile.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="presetConfig">The ConfigFile containing the preset configuration.</param>
|
||||||
|
public virtual void LoadFromPreset(ConfigFile presetConfig)
|
||||||
|
{
|
||||||
|
if (presetConfig.TryGetEntry(NumConfigDefinition, out ConfigEntry<int> numEntry))
|
||||||
|
{
|
||||||
|
SetCount(numEntry.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (presetConfig.TryGetEntry(ChanceConfigDefinition, out ConfigEntry<int> chanceEntry))
|
||||||
|
{
|
||||||
|
SetChance(chanceEntry.Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the role chance option.
|
/// Gets the role chance option.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -175,6 +222,14 @@ public interface ICustomRole : IOptionable
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This method runs on the HudManager.Update method ONLY when the LOCAL player has this role.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="hudManager">Reference to HudManager instance.</param>
|
||||||
|
void HudUpdate(HudManager hudManager)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a custom ejection message for the role. Return null to use the default message.
|
/// Gets a custom ejection message for the role. Return null to use the default message.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -1,22 +1,8 @@
|
|||||||
namespace MiraAPI.Roles;
|
namespace MiraAPI.Roles;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Enum for modded role teams.
|
|
||||||
/// </summary>
|
|
||||||
public enum ModdedRoleTeams
|
public enum ModdedRoleTeams
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// The crewmate team.
|
|
||||||
/// </summary>
|
|
||||||
Crewmate,
|
Crewmate,
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The impostor team.
|
|
||||||
/// </summary>
|
|
||||||
Impostor,
|
Impostor,
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Custom team, catchall for any other teams.
|
|
||||||
/// </summary>
|
|
||||||
Custom,
|
Custom,
|
||||||
}
|
}
|
||||||
+1
-16
@@ -2,18 +2,9 @@
|
|||||||
|
|
||||||
namespace MiraAPI.Roles;
|
namespace MiraAPI.Roles;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Utility class to get the ID of a role.
|
|
||||||
/// </summary>
|
|
||||||
public static class RoleId
|
public static class RoleId
|
||||||
{
|
{
|
||||||
/// <summary>
|
public static ushort Get<T>() where T : RoleBehaviour
|
||||||
/// Gets the ID of a role.
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="T">The type of the role.</typeparam>
|
|
||||||
/// <returns>The role ID as a ushort.</returns>
|
|
||||||
/// <exception cref="InvalidOperationException">Thrown when the role is not registered.</exception>
|
|
||||||
public static ushort Get<T>() where T : ICustomRole
|
|
||||||
{
|
{
|
||||||
if (!CustomRoleManager.RoleIds.TryGetValue(typeof(T), out var roleId))
|
if (!CustomRoleManager.RoleIds.TryGetValue(typeof(T), out var roleId))
|
||||||
{
|
{
|
||||||
@@ -23,12 +14,6 @@ public static class RoleId
|
|||||||
return roleId;
|
return roleId;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the ID of a role.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="type">The type of the role.</param>
|
|
||||||
/// <returns>The ID as a ushort.</returns>
|
|
||||||
/// <exception cref="InvalidOperationException">Thrown when the role is not registered.</exception>
|
|
||||||
public static ushort Get(Type type)
|
public static ushort Get(Type type)
|
||||||
{
|
{
|
||||||
if (!CustomRoleManager.RoleIds.TryGetValue(type, out var roleId))
|
if (!CustomRoleManager.RoleIds.TryGetValue(type, out var roleId))
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
using Reactor.Utilities.Extensions;
|
||||||
|
|
||||||
|
namespace MiraAPI.Utilities.Assets;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Wrapper class to turn any UnityEngine.Object into a <see cref="LoadableAsset{T}"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of the asset to be loaded. Must be a subclass of <see cref="UnityEngine.Object"/>.</typeparam>
|
||||||
|
public class LoadableAssetWrapper<T> : LoadableAsset<T> where T : UnityEngine.Object
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="LoadableAssetWrapper{T}"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="asset">The asset to wrap. This should be a reference to a UnityEngine.Object.</param>
|
||||||
|
public LoadableAssetWrapper(T asset)
|
||||||
|
{
|
||||||
|
LoadedAsset = asset.DontDestroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override T LoadAsset()
|
||||||
|
{
|
||||||
|
return LoadedAsset ?? throw new System.InvalidOperationException("The asset could not be loaded!");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,7 +7,6 @@ namespace MiraAPI.Utilities.Assets;
|
|||||||
/// A utility class for loading assets from embedded resources.
|
/// A utility class for loading assets from embedded resources.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="path">The path to the embedded resource.</param>
|
/// <param name="path">The path to the embedded resource.</param>
|
||||||
/// <param name="pixelsPerUnit">The pixels per unit for the loaded sprite.</param>
|
|
||||||
public class LoadableResourceAsset(string path, float pixelsPerUnit=100f) : LoadableAsset<Sprite>
|
public class LoadableResourceAsset(string path, float pixelsPerUnit=100f) : LoadableAsset<Sprite>
|
||||||
{
|
{
|
||||||
private readonly Assembly _assembly = Assembly.GetCallingAssembly();
|
private readonly Assembly _assembly = Assembly.GetCallingAssembly();
|
||||||
@@ -15,9 +14,9 @@ public class LoadableResourceAsset(string path, float pixelsPerUnit=100f) : Load
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override Sprite LoadAsset()
|
public override Sprite LoadAsset()
|
||||||
{
|
{
|
||||||
if (LoadedAsset)
|
if (LoadedAsset != null)
|
||||||
{
|
{
|
||||||
return LoadedAsset!;
|
return LoadedAsset;
|
||||||
}
|
}
|
||||||
|
|
||||||
return LoadedAsset = SpriteTools.LoadSpriteFromPath(path, _assembly, pixelsPerUnit);
|
return LoadedAsset = SpriteTools.LoadSpriteFromPath(path, _assembly, pixelsPerUnit);
|
||||||
|
|||||||
@@ -4,57 +4,75 @@ using UnityEngine;
|
|||||||
namespace MiraAPI.Utilities.Assets;
|
namespace MiraAPI.Utilities.Assets;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A static class that contains various assets used in the Mira API.
|
/// Various assets used throughout Mira API.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static class MiraAssets
|
public static class MiraAssets
|
||||||
{
|
{
|
||||||
|
static MiraAssets()
|
||||||
|
{
|
||||||
|
var boxTex = SpriteTools.LoadTextureFromResourcePath(
|
||||||
|
"MiraAPI.Resources.RoundedBox.png",
|
||||||
|
System.Reflection.Assembly.GetCallingAssembly());
|
||||||
|
var boxSprite = Sprite.Create(
|
||||||
|
boxTex,
|
||||||
|
new Rect(0, 0, boxTex.width, boxTex.height),
|
||||||
|
new Vector2(0.5f, 0.5f),
|
||||||
|
100f,
|
||||||
|
0U,
|
||||||
|
SpriteMeshType.Tight,
|
||||||
|
new Vector4(20, 20, 20, 20));
|
||||||
|
|
||||||
|
RoundedBox = new LoadableAssetWrapper<Sprite>(boxSprite);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static readonly AssetBundle MiraAssetBundle = AssetBundleManager.Load("mirabundle");
|
||||||
|
internal static readonly LoadableAsset<GameObject> ModifierDisplay = new LoadableBundleAsset<GameObject>("Modifiers", MiraAssetBundle);
|
||||||
|
internal static readonly LoadableAsset<GameObject> PresetSavePopup = new LoadableBundleAsset<GameObject>("PresetSavePopup", MiraAssetBundle);
|
||||||
|
internal static readonly LoadableAsset<Sprite> RefreshIcon = new LoadableBundleAsset<Sprite>("refresh", MiraAssetBundle);
|
||||||
|
internal static readonly LoadableAsset<Sprite> FolderIcon = new LoadableBundleAsset<Sprite>("freePlay_folderTaskRoom", MiraAssetBundle);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the color used for teal highlighting in UI.
|
/// Gets the accepted teal color used for various selections in the UI.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static Color32 AcceptedTeal { get; } = new(43, 233, 198, 255);
|
public static Color32 AcceptedTeal { get; } = new(43, 233, 198, 255);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the Mira API asset bundle.
|
/// Gets the empty sprite.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static AssetBundle MiraAssetBundle { get; } = AssetBundleManager.Load("mirabundle");
|
public static LoadableAsset<Sprite> Empty { get; } = new LoadableResourceAsset("MiraAPI.Resources.Empty.png");
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the ModifierDisplay prefab.
|
/// Gets the RoundedBox sprite, which is a rounded rectangle used for UI elements.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static LoadableAsset<GameObject> ModifierDisplay { get; } = new LoadableBundleAsset<GameObject>("Modifiers", MiraAssetBundle);
|
public static LoadableAsset<Sprite> RoundedBox { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the empty sprite asset.
|
/// Gets the NextButton sprite.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static LoadableResourceAsset Empty { get; } = new("MiraAPI.Resources.Empty.png");
|
public static LoadableAsset<Sprite> NextButton { get; } = new LoadableResourceAsset("MiraAPI.Resources.NextButton.png");
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the Next Button sprite.
|
/// Gets the active variant of the NextButton sprite.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static LoadableResourceAsset NextButton { get; } = new("MiraAPI.Resources.NextButton.png");
|
public static LoadableAsset<Sprite> NextButtonActive { get; } = new LoadableResourceAsset("MiraAPI.Resources.NextButtonActive.png");
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the highlighted Next Button sprite.
|
/// Gets the Cog icon sprite.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static LoadableResourceAsset NextButtonActive { get; } = new("MiraAPI.Resources.NextButtonActive.png");
|
public static LoadableAsset<Sprite> Cog { get; } = new LoadableResourceAsset("MiraAPI.Resources.Cog.png");
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the Cog icon used in Role Settings Menu.
|
/// Gets the Checkmark icon sprite.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static LoadableResourceAsset Cog { get; } = new("MiraAPI.Resources.Cog.png");
|
public static LoadableAsset<Sprite> Checkmark { get; } = new LoadableResourceAsset("MiraAPI.Resources.Checkmark.png");
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the Checkmark Box used in the Settings Menu.
|
/// Gets the Checkmark Box sprite.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static LoadableResourceAsset CheckmarkBox { get; } = new("MiraAPI.Resources.CheckMarkBox.png");
|
public static LoadableAsset<Sprite> CheckmarkBox { get; } = new LoadableResourceAsset("MiraAPI.Resources.CheckMarkBox.png");
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the Checkmark used in the Settings Menu.
|
/// Gets the custom category header sprite used in the options menu.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static LoadableResourceAsset Checkmark { get; } = new("MiraAPI.Resources.Checkmark.png");
|
public static LoadableAsset<Sprite> CategoryHeader { get; } = new LoadableResourceAsset("MiraAPI.Resources.CategoryHeader.png");
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the white CategoryHeader used in the Settings Menu.
|
|
||||||
/// </summary>
|
|
||||||
public static LoadableResourceAsset CategoryHeader { get; } = new("MiraAPI.Resources.CategoryHeader.png");
|
|
||||||
}
|
}
|
||||||
@@ -11,14 +11,13 @@ namespace MiraAPI.Utilities.Assets;
|
|||||||
public static class SpriteTools
|
public static class SpriteTools
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Load a sprite from a resource path.
|
/// Loads and returns a texture from a resource path using the specified assembly.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="resourcePath">The path to the resource.</param>
|
/// <param name="resourcePath">The path to the resource within the assembly.</param>
|
||||||
/// <param name="assembly">The assembly containing the resource.</param>
|
/// <param name="assembly">The assembly from which to load the resource.</param>
|
||||||
/// <param name="pixelsPerUnit">The pixels per unit for the loaded sprite.</param>
|
/// <returns>A <see cref="Texture2D"/> object loaded from the specified resource path.</returns>
|
||||||
/// <returns>A sprite made from the resource.</returns>
|
/// <exception cref="ArgumentException">Thrown when the resource cannot be found in the specified assembly.</exception>
|
||||||
/// <exception cref="Exception">The resource cannot be found.</exception>
|
public static Texture2D LoadTextureFromResourcePath(string resourcePath, Assembly assembly)
|
||||||
public static Sprite LoadSpriteFromPath(string resourcePath, Assembly assembly, float pixelsPerUnit)
|
|
||||||
{
|
{
|
||||||
var tex = new Texture2D(1, 1, TextureFormat.ARGB32, false);
|
var tex = new Texture2D(1, 1, TextureFormat.ARGB32, false);
|
||||||
var myStream = assembly.GetManifestResourceStream(resourcePath);
|
var myStream = assembly.GetManifestResourceStream(resourcePath);
|
||||||
@@ -33,6 +32,19 @@ public static class SpriteTools
|
|||||||
}
|
}
|
||||||
|
|
||||||
tex.name = resourcePath;
|
tex.name = resourcePath;
|
||||||
|
return tex;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Loads and returns a <see cref="Sprite"/> from a resource path using the specified assembly.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="resourcePath">The path to the resource within the assembly.</param>
|
||||||
|
/// <param name="assembly">The assembly from which to load the resource.</param>
|
||||||
|
/// <param name="pixelsPerUnit">The number of pixels per unit for the sprite.</param>
|
||||||
|
/// <returns>A <see cref="Sprite"/> object created from the texture loaded from the specified resource path.</returns>
|
||||||
|
public static Sprite LoadSpriteFromPath(string resourcePath, Assembly assembly, float pixelsPerUnit)
|
||||||
|
{
|
||||||
|
var tex = LoadTextureFromResourcePath(resourcePath, assembly);
|
||||||
var sprite = Sprite.Create(tex, new Rect(0, 0, tex.width, tex.height), new Vector2(0.5f, 0.5f), pixelsPerUnit);
|
var sprite = Sprite.Create(tex, new Rect(0, 0, tex.width, tex.height), new Vector2(0.5f, 0.5f), pixelsPerUnit);
|
||||||
sprite.name = resourcePath;
|
sprite.name = resourcePath;
|
||||||
return sprite;
|
return sprite;
|
||||||
|
|||||||
@@ -41,6 +41,49 @@ public static class Extensions
|
|||||||
BitConverter.GetBytes(count.Value).AddRangeToArray(BitConverter.GetBytes(chance.Value)));
|
BitConverter.GetBytes(count.Value).AddRangeToArray(BitConverter.GetBytes(chance.Value)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Used if you override Minigame.Close.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="self">The minigame.</param>
|
||||||
|
public static void BaseClose(this Minigame self)
|
||||||
|
{
|
||||||
|
bool isComplete;
|
||||||
|
if (self.amClosing == Minigame.CloseState.Closing)
|
||||||
|
{
|
||||||
|
UnityEngine.Object.Destroy(self.gameObject);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (self.CloseSound && Constants.ShouldPlaySfx())
|
||||||
|
{
|
||||||
|
SoundManager.Instance.PlaySound(self.CloseSound, false, 1f, null);
|
||||||
|
}
|
||||||
|
if (PlayerControl.LocalPlayer.Data.Role.TeamType == RoleTeamTypes.Crewmate)
|
||||||
|
{
|
||||||
|
GameManager.Instance.LogicMinigame.OnMinigameClose();
|
||||||
|
}
|
||||||
|
if (PlayerControl.LocalPlayer)
|
||||||
|
{
|
||||||
|
PlayerControl.HideCursorTemporarily();
|
||||||
|
}
|
||||||
|
self.amClosing = Minigame.CloseState.Closing;
|
||||||
|
self.logger.Info(string.Concat("Closing minigame ", self.GetType().Name));
|
||||||
|
IAnalyticsReporter analytics = DestroyableSingleton<DebugAnalytics>.Instance.Analytics;
|
||||||
|
NetworkedPlayerInfo data = PlayerControl.LocalPlayer.Data;
|
||||||
|
TaskTypes taskType = self.TaskType;
|
||||||
|
float realtimeSinceStartup = Time.realtimeSinceStartup - self.timeOpened;
|
||||||
|
PlayerTask myTask = self.MyTask;
|
||||||
|
if (myTask != null)
|
||||||
|
{
|
||||||
|
isComplete = myTask.IsComplete;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
isComplete = false;
|
||||||
|
}
|
||||||
|
analytics.MinigameClosed(data, taskType, realtimeSinceStartup, isComplete);
|
||||||
|
self.StartCoroutine(self.CoDestroySelf());
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a PlayerControl from their PlayerVoteArea in a meeting.
|
/// Gets a PlayerControl from their PlayerVoteArea in a meeting.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -1,27 +1,8 @@
|
|||||||
namespace MiraAPI.Utilities;
|
namespace MiraAPI.Utilities;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Suffixes used for options numbers.
|
|
||||||
/// </summary>
|
|
||||||
public enum MiraNumberSuffixes
|
public enum MiraNumberSuffixes
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// No suffix.
|
|
||||||
/// </summary>
|
|
||||||
None,
|
None,
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Multiplier suffix (x).
|
|
||||||
/// </summary>
|
|
||||||
Multiplier,
|
Multiplier,
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Seconds suffix (s).
|
|
||||||
/// </summary>
|
|
||||||
Seconds,
|
Seconds,
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Percentage suffix (%).
|
|
||||||
/// </summary>
|
|
||||||
Percent,
|
Percent,
|
||||||
}
|
}
|
||||||
Reference in new issue
Block a user