mirror of
https://github.com/All-Of-Us-Mods/MiraAPI.git
synced 2026-10-21 21:43:26 +00:00
Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bc188191de |
No files matched your search
+2
-2
@@ -1,8 +1,8 @@
|
|||||||
<Project>
|
<Project>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Reactor" Version="2.3.1" />
|
<PackageReference Include="Reactor" Version="2.3.1" />
|
||||||
<PackageReference Include="BepInEx.Unity.IL2CPP" Version="6.0.0-be.735" Private="false" ExcludeAssets="runtime;native" />
|
<PackageReference Include="BepInEx.Unity.IL2CPP" Version="6.0.0-be.697" Private="false" ExcludeAssets="runtime;native" />
|
||||||
<PackageReference Include="AmongUs.GameLibs.Steam" Version="2025.4.15" PrivateAssets="all" />
|
<PackageReference Include="AmongUs.GameLibs.Steam" Version="2025.3.25" PrivateAssets="all" />
|
||||||
|
|
||||||
<PackageReference Include="BepInEx.AutoPlugin" Version="1.1.0" PrivateAssets="all" />
|
<PackageReference Include="BepInEx.AutoPlugin" Version="1.1.0" PrivateAssets="all" />
|
||||||
<PackageReference Include="BepInEx.IL2CPP.MSBuild" Version="2.1.0-rc.1" PrivateAssets="all" ExcludeAssets="runtime" />
|
<PackageReference Include="BepInEx.IL2CPP.MSBuild" Version="2.1.0-rc.1" PrivateAssets="all" ExcludeAssets="runtime" />
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
<RestorePackagesWithLockFile>true</RestorePackagesWithLockFile>
|
<RestorePackagesWithLockFile>true</RestorePackagesWithLockFile>
|
||||||
|
|
||||||
<VersionPrefix>0.2.1</VersionPrefix>
|
<VersionPrefix>0.2.0</VersionPrefix>
|
||||||
<VersionSuffix>dev</VersionSuffix>
|
<VersionSuffix>dev</VersionSuffix>
|
||||||
|
|
||||||
<Authors>All Of Us, XtraCube, Angxl</Authors>
|
<Authors>All Of Us, XtraCube, Angxl</Authors>
|
||||||
|
|||||||
+5
-5
@@ -1,19 +1,19 @@
|
|||||||
using MiraAPI.Example.GameOver;
|
using MiraAPI.Example.Extension.GameOver;
|
||||||
using MiraAPI.Example.Roles;
|
using MiraAPI.Example.Extension.Roles;
|
||||||
using MiraAPI.GameEnd;
|
using MiraAPI.GameEnd;
|
||||||
using MiraAPI.Hud;
|
using MiraAPI.Hud;
|
||||||
using MiraAPI.Keybinds;
|
|
||||||
using MiraAPI.Utilities.Assets;
|
using MiraAPI.Utilities.Assets;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
||||||
namespace MiraAPI.Example.Buttons;
|
namespace MiraAPI.Example.Extension.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;
|
||||||
public override MiraKeybind Keybind => ExampleKeybinds.NeutralWinKeybind;
|
|
||||||
|
|
||||||
protected override void OnClick()
|
protected override void OnClick()
|
||||||
{
|
{
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
+2
-2
@@ -1,9 +1,9 @@
|
|||||||
using MiraAPI.Example.Roles;
|
using MiraAPI.Example.Extension.Roles;
|
||||||
using MiraAPI.GameEnd;
|
using MiraAPI.GameEnd;
|
||||||
using MiraAPI.Utilities;
|
using MiraAPI.Utilities;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
||||||
namespace MiraAPI.Example.GameOver;
|
namespace MiraAPI.Example.Extension.GameOver;
|
||||||
|
|
||||||
public class NeutralKillerGameOver : CustomGameOver
|
public class NeutralKillerGameOver : CustomGameOver
|
||||||
{
|
{
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
<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>
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
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;
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
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;
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
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;
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
+7
-3
@@ -1,16 +1,20 @@
|
|||||||
using MiraAPI.Example.GameOver;
|
using MiraAPI.Example.Extension.GameOver;
|
||||||
using MiraAPI.GameEnd;
|
using MiraAPI.GameEnd;
|
||||||
using MiraAPI.Roles;
|
using MiraAPI.Roles;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
||||||
namespace MiraAPI.Example.Roles;
|
namespace MiraAPI.Example.Extension.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)
|
||||||
@@ -3,7 +3,6 @@ using MiraAPI.Example.Options.Roles;
|
|||||||
using MiraAPI.Example.Roles;
|
using MiraAPI.Example.Roles;
|
||||||
using MiraAPI.GameOptions;
|
using MiraAPI.GameOptions;
|
||||||
using MiraAPI.Hud;
|
using MiraAPI.Hud;
|
||||||
using MiraAPI.Keybinds;
|
|
||||||
using MiraAPI.Modifiers;
|
using MiraAPI.Modifiers;
|
||||||
using MiraAPI.Utilities;
|
using MiraAPI.Utilities;
|
||||||
using MiraAPI.Utilities.Assets;
|
using MiraAPI.Utilities.Assets;
|
||||||
@@ -16,10 +15,10 @@ public class FreezeButton : CustomActionButton<PlayerControl>
|
|||||||
public override string Name => "Freeze";
|
public override string Name => "Freeze";
|
||||||
|
|
||||||
public override float Cooldown => OptionGroupSingleton<FreezerRoleSettings>.Instance.FreezeDuration;
|
public override float Cooldown => OptionGroupSingleton<FreezerRoleSettings>.Instance.FreezeDuration;
|
||||||
public override bool PauseTimerInVent => true;
|
|
||||||
|
public override int MaxUses => 1;
|
||||||
|
|
||||||
public override LoadableAsset<Sprite> Sprite => ExampleAssets.ExampleButton;
|
public override LoadableAsset<Sprite> Sprite => ExampleAssets.ExampleButton;
|
||||||
public override MiraKeybind? Keybind => MiraGlobalKeybinds.PrimaryAbility;
|
|
||||||
|
|
||||||
protected override void OnClick()
|
protected override void OnClick()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
using MiraAPI.Example.Modifiers;
|
using MiraAPI.Example.Modifiers;
|
||||||
using MiraAPI.Hud;
|
using MiraAPI.Hud;
|
||||||
using MiraAPI.Keybinds;
|
|
||||||
using MiraAPI.Modifiers;
|
using MiraAPI.Modifiers;
|
||||||
using MiraAPI.Utilities.Assets;
|
using MiraAPI.Utilities.Assets;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
@@ -16,7 +15,6 @@ public class MeetingButton : CustomActionButton
|
|||||||
public override int MaxUses => 3;
|
public override int MaxUses => 3;
|
||||||
|
|
||||||
public override LoadableAsset<Sprite> Sprite => ExampleAssets.ExampleButton;
|
public override LoadableAsset<Sprite> Sprite => ExampleAssets.ExampleButton;
|
||||||
public override MiraKeybind? Keybind => MiraGlobalKeybinds.ModifierPrimaryAbility;
|
|
||||||
|
|
||||||
public override bool Enabled(RoleBehaviour? role)
|
public override bool Enabled(RoleBehaviour? role)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ using MiraAPI.Example.Options.Roles;
|
|||||||
using MiraAPI.Example.Roles;
|
using MiraAPI.Example.Roles;
|
||||||
using MiraAPI.GameOptions;
|
using MiraAPI.GameOptions;
|
||||||
using MiraAPI.Hud;
|
using MiraAPI.Hud;
|
||||||
using MiraAPI.Keybinds;
|
|
||||||
using MiraAPI.Utilities.Assets;
|
using MiraAPI.Utilities.Assets;
|
||||||
using Reactor.Utilities;
|
using Reactor.Utilities;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
@@ -22,7 +21,6 @@ public class TeleportButton : CustomActionButton
|
|||||||
public override LoadableAsset<Sprite> Sprite => ExampleAssets.TeleportButton;
|
public override LoadableAsset<Sprite> Sprite => ExampleAssets.TeleportButton;
|
||||||
public override Color TextOutlineColor => new Color32(221, 176, 152, 255);
|
public override Color TextOutlineColor => new Color32(221, 176, 152, 255);
|
||||||
public static bool IsZoom { get; private set; }
|
public static bool IsZoom { get; private set; }
|
||||||
public override MiraKeybind? Keybind => MiraGlobalKeybinds.PrimaryAbility;
|
|
||||||
|
|
||||||
public override bool Enabled(RoleBehaviour? role)
|
public override bool Enabled(RoleBehaviour? role)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,35 +0,0 @@
|
|||||||
using MiraAPI.Hud;
|
|
||||||
using MiraAPI.Utilities.Assets;
|
|
||||||
using UnityEngine;
|
|
||||||
|
|
||||||
namespace MiraAPI.Example.Buttons;
|
|
||||||
|
|
||||||
public class ThinkButton : CustomActionButton
|
|
||||||
{
|
|
||||||
public override string Name => "Think";
|
|
||||||
public override float Cooldown => 15f;
|
|
||||||
public override float EffectDuration => 10f;
|
|
||||||
public override int MaxUses => 1;
|
|
||||||
public override ButtonUsesMode UsesMode => ButtonUsesMode.PerRound;
|
|
||||||
public override LoadableAsset<Sprite> Sprite => ExampleAssets.ExampleButton;
|
|
||||||
protected override void OnClick()
|
|
||||||
{
|
|
||||||
// This button does absolutely nothing besides changing its text
|
|
||||||
Button!.OverrideText("Thinking...");
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void OnEffectEnd()
|
|
||||||
{
|
|
||||||
Button!.OverrideText("Think");
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool IsEffectCancellable()
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool Enabled(RoleBehaviour? role)
|
|
||||||
{
|
|
||||||
return role != null && role.IsImpostor;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -6,10 +6,7 @@ namespace MiraAPI.Example;
|
|||||||
[RegisterCustomColors]
|
[RegisterCustomColors]
|
||||||
public static class ExampleColors
|
public static class ExampleColors
|
||||||
{
|
{
|
||||||
public static CustomColor Cerulean { get; } = new("Cerulean", new Color(0.0f, 0.48f, 0.65f))
|
public static CustomColor Cerulean { get; } = new("Cerulean", new Color(0.0f, 0.48f, 0.65f));
|
||||||
{
|
|
||||||
ColorBrightness = CustomColorBrightness.Lighter,
|
|
||||||
};
|
|
||||||
|
|
||||||
public static CustomColor Rose { get; } = new("Rose", new Color(0.98f, 0.26f, 0.62f));
|
public static CustomColor Rose { get; } = new("Rose", new Color(0.98f, 0.26f, 0.62f));
|
||||||
|
|
||||||
|
|||||||
@@ -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 NeutralKillerRole) return;
|
if (@event.VoteData.Owner.Data.Role is not FreezerRole) return;
|
||||||
|
|
||||||
@event.VoteData.SetRemainingVotes(0);
|
@event.VoteData.SetRemainingVotes(0);
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +0,0 @@
|
|||||||
using MiraAPI.Keybinds;
|
|
||||||
using Rewired;
|
|
||||||
|
|
||||||
namespace MiraAPI.Example;
|
|
||||||
|
|
||||||
[RegisterCustomKeybinds]
|
|
||||||
public static class ExampleKeybinds
|
|
||||||
{
|
|
||||||
public static MiraKeybind NeutralWinKeybind { get; } = new("Neutral Win", KeyboardKeyCode.C, [ModifierKey.Shift]);
|
|
||||||
}
|
|
||||||
@@ -1,53 +0,0 @@
|
|||||||
using BepInEx.Configuration;
|
|
||||||
using MiraAPI.LocalSettings;
|
|
||||||
using MiraAPI.LocalSettings.Attributes;
|
|
||||||
using MiraAPI.Utilities;
|
|
||||||
using UnityEngine;
|
|
||||||
|
|
||||||
namespace MiraAPI.Example;
|
|
||||||
|
|
||||||
public class ExampleLocalSettings(ConfigFile config) : LocalSettingsTab(config)
|
|
||||||
{
|
|
||||||
public override string TabName => "Mira Example";
|
|
||||||
protected override bool ShouldCreateLabels => false;
|
|
||||||
|
|
||||||
public override LocalSettingTabAppearance TabAppearance => new()
|
|
||||||
{
|
|
||||||
ToggleActiveColor = Color.blue,
|
|
||||||
ToggleInactiveColor = Color.red,
|
|
||||||
};
|
|
||||||
|
|
||||||
[LocalSettingsButton]
|
|
||||||
public LocalSettingsButton ExampleButton { get; private set; } = new("Example Button", OnExampleButtonClick);
|
|
||||||
|
|
||||||
[LocalToggleSetting]
|
|
||||||
public ConfigEntry<bool> ExampleToggle { get; private set; } = config.Bind("General", "Example Bool", true);
|
|
||||||
|
|
||||||
[LocalToggleSetting]
|
|
||||||
public ConfigEntry<bool> ExampleToggle2 { get; private set; } = config.Bind("General", "Example Bool 2", false);
|
|
||||||
|
|
||||||
[LocalSliderSetting(suffixType: MiraNumberSuffixes.Percent, formatString: "0", roundValue: true)]
|
|
||||||
public ConfigEntry<float> ExampleSlider { get; private set; } = config.Bind("General", "Slider", 50f);
|
|
||||||
|
|
||||||
[LocalNumberSetting]
|
|
||||||
public ConfigEntry<float> ExampleNumber { get; private set; } = config.Bind("General", "Example Number", 4f);
|
|
||||||
|
|
||||||
[LocalNumberSetting(min: 0.1f, max: 2.5f, increment: 0.1f, formatString: "0.0", suffixType: MiraNumberSuffixes.Multiplier)]
|
|
||||||
public ConfigEntry<float> ExampleFloatNumber { get; private set; } = config.Bind("General", "Example Multplier", 1f);
|
|
||||||
|
|
||||||
[LocalEnumSetting]
|
|
||||||
public ConfigEntry<ExampleEnumSetting> ExampleEnum { get; private set; } = config.Bind("General", "Example Enum", ExampleEnumSetting.Fries);
|
|
||||||
|
|
||||||
private static void OnExampleButtonClick()
|
|
||||||
{
|
|
||||||
LocalSettingsTabSingleton<MiraApiSettings>.Instance.Open();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum ExampleEnumSetting
|
|
||||||
{
|
|
||||||
Cheeseburger,
|
|
||||||
Sandwich,
|
|
||||||
Fries,
|
|
||||||
ChickenNuggets,
|
|
||||||
}
|
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
using System.Linq;
|
using BepInEx;
|
||||||
using BepInEx;
|
|
||||||
using BepInEx.Configuration;
|
using BepInEx.Configuration;
|
||||||
using BepInEx.Unity.IL2CPP;
|
using BepInEx.Unity.IL2CPP;
|
||||||
using HarmonyLib;
|
using HarmonyLib;
|
||||||
|
|||||||
@@ -10,8 +10,6 @@ public class ExampleOptions2 : AbstractOptionGroup
|
|||||||
|
|
||||||
public override uint GroupPriority => 0; // This group will be displayed first. The default value is uint.MaxValue.
|
public override uint GroupPriority => 0; // This group will be displayed first. The default value is uint.MaxValue.
|
||||||
|
|
||||||
public ModdedPlayerOption PlayerOption2 { get; } = new("YOU MUST CHOSE A PLAYER", false);
|
|
||||||
public ModdedPlayerOption PlayerOption { get; } = new("Eh whatever");
|
|
||||||
public ModdedToggleOption ToggleOpt1 { get; } = new("Toggle Option 1", false);
|
public ModdedToggleOption ToggleOpt1 { get; } = new("Toggle Option 1", false);
|
||||||
|
|
||||||
public ModdedToggleOption ToggleOpt2 { get; } = new("Toggle Option 2", false)
|
public ModdedToggleOption ToggleOpt2 { get; } = new("Toggle Option 2", false)
|
||||||
|
|||||||
@@ -11,7 +11,4 @@ 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;
|
|
||||||
}
|
}
|
||||||
@@ -7,6 +7,8 @@ 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
|
||||||
@@ -21,6 +23,10 @@ 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
|
||||||
|
|||||||
@@ -13,24 +13,19 @@ namespace MiraAPI.Colors;
|
|||||||
public sealed class CustomColor(StringNames name, Color32 mainColor, Color32 shadowColor)
|
public sealed class CustomColor(StringNames name, Color32 mainColor, Color32 shadowColor)
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the main color.
|
/// Gets the main color.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Color32 MainColor { get; set; } = mainColor;
|
public Color32 MainColor { get; } = mainColor;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the shadow color.
|
/// Gets the shadow color.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Color32 ShadowColor { get; set; } = shadowColor;
|
public Color32 ShadowColor { get; } = shadowColor;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the name of the color.
|
/// Gets the name of the color.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public StringNames Name { get; set; } = name;
|
public StringNames Name { get; } = name;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets whether the color is lighter or darker. Can be used to help with colorblind stuff.
|
|
||||||
/// </summary>
|
|
||||||
public CustomColorBrightness ColorBrightness { get; set; } = CustomColorBrightness.Darker;
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public CustomColor(StringNames name, Color32 mainColor) : this(name, mainColor, mainColor.GetShadowColor(60))
|
public CustomColor(StringNames name, Color32 mainColor) : this(name, mainColor, mainColor.GetShadowColor(60))
|
||||||
@@ -47,19 +42,3 @@ public sealed class CustomColor(StringNames name, Color32 mainColor, Color32 sha
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Can be used to help with colorblind stuff.
|
|
||||||
/// </summary>
|
|
||||||
public enum CustomColorBrightness
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// A lighter color.
|
|
||||||
/// </summary>
|
|
||||||
Lighter,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// A darker color.
|
|
||||||
/// </summary>
|
|
||||||
Darker,
|
|
||||||
}
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
namespace MiraAPI.Events.Vanilla.Gameplay;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Invoked before RpcEndGame is called, allowing cancellation of the game end entirely.
|
|
||||||
/// </summary>
|
|
||||||
public class BeforeGameEndEvent : MiraCancelableEvent
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the reason for the game end.
|
|
||||||
/// </summary>
|
|
||||||
public GameOverReason Reason { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="BeforeGameEndEvent"/> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="reason">The reason for the game end.</param>
|
|
||||||
public BeforeGameEndEvent(GameOverReason reason)
|
|
||||||
{
|
|
||||||
Reason = reason;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
namespace MiraAPI.Events.Vanilla.Gameplay;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Event invoked on IntroCutscene.OnDestroy and ExileController.WrapUp to determine if it should run the round event or not.
|
|
||||||
/// </summary>
|
|
||||||
public class BeforeRoundStartEvent : MiraCancelableEvent
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Gets a value indicating whether the event was triggered by the IntroCutscene or ExileController.
|
|
||||||
/// </summary>
|
|
||||||
public bool TriggeredByIntro { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="BeforeRoundStartEvent"/> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="triggeredByIntro">Whether the event was triggered by the intro or not.</param>
|
|
||||||
public BeforeRoundStartEvent(bool triggeredByIntro)
|
|
||||||
{
|
|
||||||
TriggeredByIntro = triggeredByIntro;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
namespace MiraAPI.Events.Vanilla.Gameplay;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The event that is invoked when the player's role is shown on the intro cutscene. Non cancelable.
|
|
||||||
/// </summary>
|
|
||||||
public class IntroRoleRevealEvent : MiraEvent
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the instance of the IntroCutscene.
|
|
||||||
/// </summary>
|
|
||||||
public IntroCutscene IntroCutscene { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="IntroRoleRevealEvent"/> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="introCutscene">The intro cutscene.</param>
|
|
||||||
public IntroRoleRevealEvent(IntroCutscene introCutscene)
|
|
||||||
{
|
|
||||||
IntroCutscene = introCutscene;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
namespace MiraAPI.Events.Vanilla.Gameplay;
|
namespace MiraAPI.Events.Vanilla.Gameplay;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Start Round event, invoked on IntroCutscene.OnDestroy and ExileController.WrapUp if the event isn't cancelled.
|
/// Start Round event, invoked on IntroCutscene.OnDestroy and ExileController.WrapUp.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class RoundStartEvent : MiraEvent
|
public class RoundStartEvent : MiraEvent
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,30 +0,0 @@
|
|||||||
using MiraAPI.Voting;
|
|
||||||
|
|
||||||
namespace MiraAPI.Events.Vanilla.Meeting.Voting;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Event that is invoked after the local player successfully votes a player or skips. This event is not cancelable.
|
|
||||||
/// </summary>
|
|
||||||
public class AfterVoteEvent : MiraEvent
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the instance of the voter's vote data.
|
|
||||||
/// </summary>
|
|
||||||
public PlayerVoteArea VoteArea { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the player who voted.
|
|
||||||
/// </summary>
|
|
||||||
public PlayerControl Player { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="AfterVoteEvent"/> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="playerVoteArea">The player vote area that was voted on.</param>
|
|
||||||
/// <param name="voter">The player who voted.</param>
|
|
||||||
public AfterVoteEvent(PlayerVoteArea playerVoteArea, PlayerControl voter)
|
|
||||||
{
|
|
||||||
VoteArea = playerVoteArea;
|
|
||||||
Player = voter;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
using MiraAPI.Voting;
|
|
||||||
|
|
||||||
namespace MiraAPI.Events.Vanilla.Meeting.Voting;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Event that is invoked before the local player confirms a vote on a player or when skipping. This event is cancelable.
|
|
||||||
/// </summary>
|
|
||||||
public class BeforeVoteEvent : MiraCancelableEvent
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the instance of the voter's vote data.
|
|
||||||
/// </summary>
|
|
||||||
public PlayerVoteArea VoteArea { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the player who voted.
|
|
||||||
/// </summary>
|
|
||||||
public PlayerControl Player { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="BeforeVoteEvent"/> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="playerVoteArea">The player vote area that was voted on.</param>
|
|
||||||
/// <param name="voter">The player who voted.</param>
|
|
||||||
public BeforeVoteEvent(PlayerVoteArea playerVoteArea, PlayerControl voter)
|
|
||||||
{
|
|
||||||
VoteArea = playerVoteArea;
|
|
||||||
Player = voter;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
using System;
|
|
||||||
using MiraAPI.Utilities;
|
|
||||||
using MiraAPI.Voting;
|
|
||||||
|
|
||||||
namespace MiraAPI.Events.Vanilla.Meeting.Voting;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Invoked before the dummy selects their vote. If canceled, the dummy won't vote.
|
|
||||||
/// </summary>
|
|
||||||
public class DummyVoteEvent : MiraCancelableEvent
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the dummy that needs to vote.
|
|
||||||
/// </summary>
|
|
||||||
public DummyBehaviour Dummy { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the instance of the dummy's vote data.
|
|
||||||
/// </summary>
|
|
||||||
public PlayerVoteData VoteData { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets a value indicating whether the dummy can vote to skip the meeting.
|
|
||||||
/// </summary>
|
|
||||||
public bool CanSkip { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets a predicate for validating whether the dummy can vote on a player.
|
|
||||||
/// By default, excludes dead and disconnected players.
|
|
||||||
/// </summary>
|
|
||||||
public Predicate<PlayerControl> PlayerIsValid { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="DummyVoteEvent"/> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="dummy">The voting dummy.</param>
|
|
||||||
public DummyVoteEvent(DummyBehaviour dummy)
|
|
||||||
{
|
|
||||||
Dummy = dummy;
|
|
||||||
VoteData = dummy.myPlayer.GetVoteData();
|
|
||||||
CanSkip = true;
|
|
||||||
PlayerIsValid = x => !x.Data.IsDead && !x.Data.Disconnected;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
[*.cs]
|
|
||||||
dotnet_diagnostic.CS1591.severity = none
|
|
||||||
@@ -46,11 +46,6 @@ 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>
|
||||||
@@ -62,10 +57,9 @@ public interface IModdedOption
|
|||||||
/// <param name="toggleOpt">The ToggleOption template.</param>
|
/// <param name="toggleOpt">The ToggleOption template.</param>
|
||||||
/// <param name="numberOpt">The NumberOption template.</param>
|
/// <param name="numberOpt">The NumberOption template.</param>
|
||||||
/// <param name="stringOpt">The StringOption template.</param>
|
/// <param name="stringOpt">The StringOption template.</param>
|
||||||
/// <param name="playerOpt">The PlayerOption template.</param>
|
|
||||||
/// <param name="container">>The Transform container for the option.</param>
|
/// <param name="container">>The Transform container for the option.</param>
|
||||||
/// <returns>>The created OptionBehaviour object.</returns>
|
/// <returns>>The created OptionBehaviour object.</returns>
|
||||||
OptionBehaviour CreateOption(ToggleOption toggleOpt, NumberOption numberOpt, StringOption stringOpt, PlayerOption playerOpt, Transform container);
|
OptionBehaviour CreateOption(ToggleOption toggleOpt, NumberOption numberOpt, StringOption stringOpt, Transform container);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the value as a float.
|
/// Gets the value as a float.
|
||||||
@@ -84,23 +78,4 @@ 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);
|
|
||||||
}
|
}
|
||||||
@@ -1,12 +1,10 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics.CodeAnalysis;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using BepInEx.Configuration;
|
using BepInEx.Configuration;
|
||||||
using HarmonyLib;
|
using HarmonyLib;
|
||||||
using MiraAPI.GameOptions.Attributes;
|
using MiraAPI.GameOptions.Attributes;
|
||||||
using MiraAPI.GameOptions.OptionTypes;
|
|
||||||
using MiraAPI.Networking;
|
using MiraAPI.Networking;
|
||||||
using MiraAPI.PluginLoading;
|
using MiraAPI.PluginLoading;
|
||||||
using MiraAPI.Utilities;
|
using MiraAPI.Utilities;
|
||||||
@@ -23,7 +21,6 @@ public static class ModdedOptionsManager
|
|||||||
private static readonly Dictionary<PropertyInfo, ModdedOptionAttribute> OptionAttributes = [];
|
private static readonly Dictionary<PropertyInfo, ModdedOptionAttribute> OptionAttributes = [];
|
||||||
private static readonly Dictionary<Type, AbstractOptionGroup> TypeToGroup = [];
|
private static readonly Dictionary<Type, AbstractOptionGroup> TypeToGroup = [];
|
||||||
|
|
||||||
internal static readonly Dictionary<OptionBehaviour, ModdedPlayerOption> CreatedPlayerOptions = [];
|
|
||||||
internal static readonly Dictionary<uint, IModdedOption> ModdedOptions = [];
|
internal static readonly Dictionary<uint, IModdedOption> ModdedOptions = [];
|
||||||
internal static readonly List<AbstractOptionGroup> Groups = [];
|
internal static readonly List<AbstractOptionGroup> Groups = [];
|
||||||
|
|
||||||
@@ -45,7 +42,7 @@ public static class ModdedOptionsManager
|
|||||||
|
|
||||||
Groups.Add(group);
|
Groups.Add(group);
|
||||||
TypeToGroup.Add(type, group);
|
TypeToGroup.Add(type, group);
|
||||||
pluginInfo.InternalOptionGroups.Add(group);
|
pluginInfo.OptionGroups.Add(group);
|
||||||
|
|
||||||
typeof(OptionGroupSingleton<>).MakeGenericType(type)
|
typeof(OptionGroupSingleton<>).MakeGenericType(type)
|
||||||
#pragma warning disable S3011
|
#pragma warning disable S3011
|
||||||
@@ -124,7 +121,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.InternalOptions.Add(option);
|
pluginInfo.Options.Add(option);
|
||||||
ModdedOptions.Add(option.Id, option);
|
ModdedOptions.Add(option.Id, option);
|
||||||
group.Options.Add(option);
|
group.Options.Add(option);
|
||||||
}
|
}
|
||||||
@@ -145,7 +142,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;
|
||||||
@@ -161,7 +158,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];
|
||||||
@@ -178,10 +175,8 @@ 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>
|
||||||
#pragma warning disable CA1707
|
// ReSharper disable InconsistentNaming
|
||||||
[SuppressMessage("ReSharper", "InconsistentNaming", Justification = "Harmony naming convention")]
|
|
||||||
public static void PropertySetterPatch(MethodBase __originalMethod, object value)
|
public static void PropertySetterPatch(MethodBase __originalMethod, object value)
|
||||||
#pragma warning restore CA1707
|
|
||||||
{
|
{
|
||||||
var attribute = OptionAttributes.First(pair => pair.Key.GetSetMethod() == __originalMethod).Value;
|
var attribute = OptionAttributes.First(pair => pair.Key.GetSetMethod() == __originalMethod).Value;
|
||||||
attribute.SetValue(value);
|
attribute.SetValue(value);
|
||||||
@@ -193,10 +188,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>
|
||||||
#pragma warning disable CA1707
|
|
||||||
[SuppressMessage("ReSharper", "InconsistentNaming", Justification = "Harmony naming convention")]
|
|
||||||
public static bool PropertyGetterPatch(MethodBase __originalMethod, ref object __result)
|
public static bool PropertyGetterPatch(MethodBase __originalMethod, ref object __result)
|
||||||
#pragma warning restore CA1707
|
// 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();
|
||||||
|
|||||||
@@ -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,8 +27,7 @@ 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>
|
||||||
/// <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) : base(title, defaultValue)
|
||||||
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>();
|
||||||
@@ -38,13 +37,13 @@ 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)];
|
: values.Select(CustomStringName.CreateAndRegister).ToArray();
|
||||||
|
|
||||||
data.Index = Value;
|
data.Index = Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override OptionBehaviour CreateOption(ToggleOption toggleOpt, NumberOption numberOpt, StringOption stringOpt, PlayerOption playerOpt, Transform container)
|
public override OptionBehaviour CreateOption(ToggleOption toggleOpt, NumberOption numberOpt, StringOption stringOpt, Transform container)
|
||||||
{
|
{
|
||||||
var stringOption = Object.Instantiate(stringOpt, container);
|
var stringOption = Object.Instantiate(stringOpt, container);
|
||||||
|
|
||||||
@@ -88,7 +87,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;
|
||||||
@@ -110,7 +109,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.
|
||||||
@@ -118,8 +117,7 @@ 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>
|
||||||
/// <param name="includeInPreset">Whether to include this option in the preset or not.</param>
|
public ModdedEnumOption(string title, T defaultValue, string[]? values = null) : base(title, defaultValue)
|
||||||
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>();
|
||||||
@@ -129,13 +127,13 @@ 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)];
|
: values.Select(CustomStringName.CreateAndRegister).ToArray();
|
||||||
|
|
||||||
data.Index = Convert.ToInt32(Value, NumberFormatInfo.InvariantInfo);
|
data.Index = Convert.ToInt32(Value, NumberFormatInfo.InvariantInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override OptionBehaviour CreateOption(ToggleOption toggleOpt, NumberOption numberOpt, StringOption stringOpt, PlayerOption playerOpt, Transform container)
|
public override OptionBehaviour CreateOption(ToggleOption toggleOpt, NumberOption numberOpt, StringOption stringOpt, Transform container)
|
||||||
{
|
{
|
||||||
var stringOption = Object.Instantiate(stringOpt, container);
|
var stringOption = Object.Instantiate(stringOpt, container);
|
||||||
|
|
||||||
|
|||||||
@@ -48,7 +48,6 @@ 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,
|
||||||
@@ -57,8 +56,7 @@ public class ModdedNumberOption : ModdedOption<float>
|
|||||||
float increment,
|
float increment,
|
||||||
MiraNumberSuffixes suffixType,
|
MiraNumberSuffixes suffixType,
|
||||||
string? formatString = null,
|
string? formatString = null,
|
||||||
bool zeroInfinity = false,
|
bool zeroInfinity = false) : base(title, defaultValue)
|
||||||
bool includeInPreset = true) : base(title, defaultValue, includeInPreset)
|
|
||||||
{
|
{
|
||||||
Min = min;
|
Min = min;
|
||||||
Max = max;
|
Max = max;
|
||||||
@@ -93,7 +91,6 @@ public class ModdedNumberOption : ModdedOption<float>
|
|||||||
ToggleOption toggleOpt,
|
ToggleOption toggleOpt,
|
||||||
NumberOption numberOpt,
|
NumberOption numberOpt,
|
||||||
StringOption stringOpt,
|
StringOption stringOpt,
|
||||||
PlayerOption playerOpt,
|
|
||||||
Transform container)
|
Transform container)
|
||||||
{
|
{
|
||||||
var numberOption = Object.Instantiate(numberOpt, Vector3.zero, Quaternion.identity, container);
|
var numberOption = Object.Instantiate(numberOpt, Vector3.zero, Quaternion.identity, container);
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ 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;
|
||||||
@@ -17,19 +16,29 @@ public abstract class ModdedOption<T> : IModdedOption
|
|||||||
{
|
{
|
||||||
private IMiraPlugin? _parentMod;
|
private IMiraPlugin? _parentMod;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <summary>
|
||||||
|
/// Gets the unique identifier of the option.
|
||||||
|
/// </summary>
|
||||||
public uint Id { get; }
|
public uint Id { get; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <summary>
|
||||||
|
/// Gets the title of the option.
|
||||||
|
/// </summary>
|
||||||
public string Title { get; }
|
public string Title { get; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <summary>
|
||||||
|
/// Gets the StringName object of the option.
|
||||||
|
/// </summary>
|
||||||
public StringNames StringName { get; }
|
public StringNames StringName { get; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <summary>
|
||||||
|
/// Gets or sets the BaseGameSetting data of the option.
|
||||||
|
/// </summary>
|
||||||
public BaseGameSetting Data { get; protected set; } = null!;
|
public BaseGameSetting Data { get; protected set; } = null!;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <summary>
|
||||||
|
/// Gets or sets the parent mod of the option.
|
||||||
|
/// </summary>
|
||||||
public IMiraPlugin? ParentMod
|
public IMiraPlugin? ParentMod
|
||||||
{
|
{
|
||||||
get => _parentMod;
|
get => _parentMod;
|
||||||
@@ -37,7 +46,6 @@ public abstract class ModdedOption<T> : IModdedOption
|
|||||||
{
|
{
|
||||||
if (_parentMod != null || value == null) return;
|
if (_parentMod != null || value == null) return;
|
||||||
_parentMod = value;
|
_parentMod = value;
|
||||||
|
|
||||||
var entry = _parentMod.GetConfigFile().Bind(ConfigDefinition, DefaultValue);
|
var entry = _parentMod.GetConfigFile().Bind(ConfigDefinition, DefaultValue);
|
||||||
Value = entry.Value;
|
Value = entry.Value;
|
||||||
}
|
}
|
||||||
@@ -58,16 +66,19 @@ public abstract class ModdedOption<T> : IModdedOption
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public Action<T>? ChangedEvent { get; set; }
|
public Action<T>? ChangedEvent { get; set; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <summary>
|
||||||
|
/// Gets or sets the visibility of the option.
|
||||||
|
/// </summary>
|
||||||
public Func<bool> Visible { get; set; }
|
public Func<bool> Visible { get; set; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <summary>
|
||||||
public bool IncludeInPreset { get; set; }
|
/// Gets or sets the option behaviour of the option.
|
||||||
|
/// </summary>
|
||||||
/// <inheritdoc />
|
|
||||||
public OptionBehaviour? OptionBehaviour { get; protected set; }
|
public OptionBehaviour? OptionBehaviour { get; protected set; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <summary>
|
||||||
|
/// Gets or sets the config definition of the option.
|
||||||
|
/// </summary>
|
||||||
public ConfigDefinition? ConfigDefinition { get; set; }
|
public ConfigDefinition? ConfigDefinition { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -75,8 +86,7 @@ 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>
|
||||||
/// <param name="includeInPreset">Whether to include the option in the preset.</param>
|
protected ModdedOption(string title, T defaultValue)
|
||||||
protected ModdedOption(string title, T defaultValue, bool includeInPreset = true)
|
|
||||||
{
|
{
|
||||||
Id = ModdedOptionsManager.NextId;
|
Id = ModdedOptionsManager.NextId;
|
||||||
Title = title;
|
Title = title;
|
||||||
@@ -84,7 +94,6 @@ 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)
|
||||||
@@ -96,8 +105,7 @@ 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>
|
||||||
/// <param name="sendRpc">Whether to send the value to other players.</param>
|
public void SetValue(T newValue)
|
||||||
public void SetValue(T newValue, bool sendRpc = true)
|
|
||||||
{
|
{
|
||||||
var oldVal = Value;
|
var oldVal = Value;
|
||||||
Value = newValue;
|
Value = newValue;
|
||||||
@@ -107,7 +115,7 @@ public abstract class ModdedOption<T> : IModdedOption
|
|||||||
ChangedEvent?.Invoke(Value);
|
ChangedEvent?.Invoke(Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sendRpc && AmongUsClient.Instance.AmHost)
|
if (AmongUsClient.Instance.AmHost)
|
||||||
{
|
{
|
||||||
if (ParentMod?.GetConfigFile().TryGetEntry<T>(ConfigDefinition, out var entry) == true)
|
if (ParentMod?.GetConfigFile().TryGetEntry<T>(ConfigDefinition, out var entry) == true)
|
||||||
{
|
{
|
||||||
@@ -120,44 +128,22 @@ public abstract class ModdedOption<T> : IModdedOption
|
|||||||
OnValueChanged(newValue);
|
OnValueChanged(newValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <summary>
|
||||||
public void SaveToPreset(ConfigFile presetConfig, bool saveDefault=false)
|
/// Gets the float data of the option.
|
||||||
{
|
/// </summary>
|
||||||
if (ConfigDefinition is null)
|
/// <returns>A float object representing the option's value.</returns>
|
||||||
{
|
|
||||||
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();
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <summary>
|
||||||
|
/// 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();
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <summary>
|
||||||
|
/// 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>
|
||||||
@@ -173,12 +159,18 @@ 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);
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <summary>
|
||||||
|
/// 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,
|
||||||
StringOption stringOpt,
|
StringOption stringOpt,
|
||||||
PlayerOption playerOpt,
|
|
||||||
Transform container);
|
Transform container);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -1,138 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Linq;
|
|
||||||
using Il2CppSystem.Collections.Generic;
|
|
||||||
using MiraAPI.Networking;
|
|
||||||
using MiraAPI.Utilities;
|
|
||||||
using UnityEngine;
|
|
||||||
using Object = UnityEngine.Object;
|
|
||||||
|
|
||||||
namespace MiraAPI.GameOptions.OptionTypes;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// An option for selecting an ingame player. It returns an index of the values list, NOT A PLAYER ID. To get a player out of this, index the Values list.
|
|
||||||
/// </summary>
|
|
||||||
public class ModdedPlayerOption : ModdedOption<int>
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets the included players.
|
|
||||||
/// </summary>
|
|
||||||
public List<NetworkedPlayerInfo> Values { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets a filter for the players included in the option.
|
|
||||||
/// </summary>
|
|
||||||
public Func<NetworkedPlayerInfo, bool>? PlayerFilter { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets a value indicating whether the option includes a "None" option. If None is selected, value will return -1.
|
|
||||||
/// </summary>
|
|
||||||
public bool AllowNone { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="ModdedPlayerOption"/> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="title">The title of the option.</param>
|
|
||||||
/// <param name="allowNone">Whether the option includes a none option. If None is selected, value will return -1.</param>
|
|
||||||
public ModdedPlayerOption(string title, bool allowNone = true) : base(title, allowNone ? -1 : 0, false)
|
|
||||||
{
|
|
||||||
Data = ScriptableObject.CreateInstance<PlayerSelectionGameSetting>();
|
|
||||||
var data = (PlayerSelectionGameSetting)Data;
|
|
||||||
|
|
||||||
data.Title = StringName;
|
|
||||||
data.Type = global::OptionTypes.Player;
|
|
||||||
|
|
||||||
Values = new List<NetworkedPlayerInfo>();
|
|
||||||
AllowNone = allowNone;
|
|
||||||
Value = DefaultValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public override OptionBehaviour CreateOption(
|
|
||||||
ToggleOption toggleOpt,
|
|
||||||
NumberOption numberOpt,
|
|
||||||
StringOption stringOpt,
|
|
||||||
PlayerOption playerOpt,
|
|
||||||
Transform container)
|
|
||||||
{
|
|
||||||
var playerOption = Object.Instantiate(playerOpt, container);
|
|
||||||
|
|
||||||
var filteredList = GetFilteredPlayers();
|
|
||||||
Values = filteredList.ToIl2CppList();
|
|
||||||
|
|
||||||
playerOption.SetUpFromData(Data, 20);
|
|
||||||
playerOption.OnValueChanged = (Il2CppSystem.Action<OptionBehaviour>)ValueChanged;
|
|
||||||
|
|
||||||
playerOption.Title = StringName;
|
|
||||||
playerOption.TitleText.text = TranslationController.Instance.GetString(StringName);
|
|
||||||
playerOption.Values = Values;
|
|
||||||
playerOption.Value = Value;
|
|
||||||
playerOption.playerIndex = filteredList.FindIndex(p => p.PlayerId == Value);
|
|
||||||
|
|
||||||
OptionBehaviour = playerOption;
|
|
||||||
ModdedOptionsManager.CreatedPlayerOptions.TryAdd(playerOption, this);
|
|
||||||
|
|
||||||
playerOption.SetValueText();
|
|
||||||
playerOption.AdjustButtonsActiveState();
|
|
||||||
|
|
||||||
return playerOption;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns a player ran through the filter.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>A list of filtered players.</returns>
|
|
||||||
public System.Collections.Generic.List<NetworkedPlayerInfo> GetFilteredPlayers()
|
|
||||||
{
|
|
||||||
return GameData.Instance.AllPlayers.ToArray()
|
|
||||||
.Where(x => PlayerFilter?.Invoke(x) ?? true)
|
|
||||||
.ToList();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns a player from the value. If AllowNone is enabled and none is enabled this will return null.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>A player or null if chosen none.</returns>
|
|
||||||
public NetworkedPlayerInfo? GetPlayerValue()
|
|
||||||
{
|
|
||||||
return Value < 0 ? null : Values[Value];
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public override float GetFloatData()
|
|
||||||
{
|
|
||||||
return Value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public override NetData GetNetData()
|
|
||||||
{
|
|
||||||
return new NetData(Id, BitConverter.GetBytes(Value));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public override void HandleNetData(byte[] data)
|
|
||||||
{
|
|
||||||
SetValue(BitConverter.ToInt32(data));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public override int GetValueFromOptionBehaviour(OptionBehaviour optionBehaviour)
|
|
||||||
{
|
|
||||||
return optionBehaviour.GetInt();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
protected override void OnValueChanged(int newValue)
|
|
||||||
{
|
|
||||||
HudManager.Instance.Notifier.AddSettingsChangeMessage(StringName, Data.GetValueString(newValue), false);
|
|
||||||
if (!OptionBehaviour)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (OptionBehaviour is PlayerOption opt)
|
|
||||||
{
|
|
||||||
opt.Value = newValue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -15,8 +15,7 @@ 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>
|
||||||
/// <param name="includeInPreset">Whether to include this option in the preset or not.</param>
|
public ModdedToggleOption(string title, bool defaultValue) : base(title, defaultValue)
|
||||||
public ModdedToggleOption(string title, bool defaultValue, bool includeInPreset=true) : base(title, defaultValue, includeInPreset)
|
|
||||||
{
|
{
|
||||||
Data = ScriptableObject.CreateInstance<CheckboxGameSetting>();
|
Data = ScriptableObject.CreateInstance<CheckboxGameSetting>();
|
||||||
|
|
||||||
@@ -26,7 +25,7 @@ public class ModdedToggleOption : ModdedOption<bool>
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override OptionBehaviour CreateOption(ToggleOption toggleOpt, NumberOption numberOpt, StringOption stringOpt, PlayerOption playerOpt, Transform container)
|
public override OptionBehaviour CreateOption(ToggleOption toggleOpt, NumberOption numberOpt, StringOption stringOpt, Transform container)
|
||||||
{
|
{
|
||||||
var toggleOption = Object.Instantiate(toggleOpt, Vector3.zero, Quaternion.identity, container);
|
var toggleOption = Object.Instantiate(toggleOpt, Vector3.zero, Quaternion.identity, container);
|
||||||
|
|
||||||
|
|||||||
@@ -1,17 +0,0 @@
|
|||||||
namespace MiraAPI.Hud;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The uses mode for custom buttons.
|
|
||||||
/// </summary>
|
|
||||||
public enum ButtonUsesMode
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Uses per game.
|
|
||||||
/// </summary>
|
|
||||||
PerGame,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Uses per round.
|
|
||||||
/// </summary>
|
|
||||||
PerRound,
|
|
||||||
}
|
|
||||||
@@ -2,14 +2,8 @@
|
|||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using MiraAPI.Events;
|
using MiraAPI.Events;
|
||||||
using MiraAPI.Events.Mira;
|
using MiraAPI.Events.Mira;
|
||||||
using MiraAPI.Keybinds;
|
|
||||||
using MiraAPI.LocalSettings;
|
|
||||||
using MiraAPI.Patches;
|
using MiraAPI.Patches;
|
||||||
using MiraAPI.Utilities;
|
|
||||||
using MiraAPI.Utilities.Assets;
|
using MiraAPI.Utilities.Assets;
|
||||||
using Reactor.Utilities;
|
|
||||||
using Rewired;
|
|
||||||
using TMPro;
|
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEngine.Events;
|
using UnityEngine.Events;
|
||||||
using UnityEngine.UI;
|
using UnityEngine.UI;
|
||||||
@@ -37,29 +31,13 @@ public abstract class CustomActionButton
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract float Cooldown { get; }
|
public abstract float Cooldown { get; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets a value indicating whether the timer should stop decreasing when the player is venting.
|
|
||||||
/// Note that both cooldown decrease and effect timer decrease is disabled.
|
|
||||||
/// </summary>
|
|
||||||
public virtual bool PauseTimerInVent => false;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the sprite of the button. Use <see cref="LoadableResourceAsset"/> to load a sprite from a resource path. Use <see cref="LoadableBundleAsset{T}"/> to load a sprite from an asset bundle.
|
/// Gets the sprite of the button. Use <see cref="LoadableResourceAsset"/> to load a sprite from a resource path. Use <see cref="LoadableBundleAsset{T}"/> to load a sprite from an asset bundle.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract LoadableAsset<Sprite> Sprite { get; }
|
public abstract LoadableAsset<Sprite> Sprite { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the format string for the cooldown timer.
|
/// Gets the button's effect duration in seconds. If the button has no effect, set to 0.
|
||||||
/// </summary>
|
|
||||||
public virtual string CooldownTimerFormatString => "0";
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets a value indicating whether the button has an effect ability. By default true if <see cref="EffectDuration"/> is greater than 0.
|
|
||||||
/// </summary>
|
|
||||||
public virtual bool HasEffect => EffectDuration > 0;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the button's effect duration in seconds. If 0, the effect needs to be ended manually.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual float EffectDuration => 0;
|
public virtual float EffectDuration => 0;
|
||||||
|
|
||||||
@@ -68,16 +46,6 @@ public abstract class CustomActionButton
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual int MaxUses => 0;
|
public virtual int MaxUses => 0;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the value indicating uses mode.
|
|
||||||
/// </summary>
|
|
||||||
public virtual ButtonUsesMode UsesMode => ButtonUsesMode.PerGame;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the keybind for this button. If null, no keybind will be added.
|
|
||||||
/// </summary>
|
|
||||||
public virtual BaseKeybind? Keybind => null;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the button's text outline color.
|
/// Gets the button's text outline color.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -88,6 +56,11 @@ public abstract class CustomActionButton
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual ButtonLocation Location { get; set; } = ButtonLocation.BottomLeft;
|
public virtual ButtonLocation Location { get; set; } = ButtonLocation.BottomLeft;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a value indicating whether the button has an effect ability.
|
||||||
|
/// </summary>
|
||||||
|
public bool HasEffect => EffectDuration > 0;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a value indicating whether the button has limited uses.
|
/// Gets a value indicating whether the button has limited uses.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -118,16 +91,6 @@ public abstract class CustomActionButton
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public ActionButton? Button { get; set; }
|
public ActionButton? Button { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the gameObject used for the keybind icon.
|
|
||||||
/// </summary>
|
|
||||||
public GameObject? KeybindIcon { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets the keybind icon text.
|
|
||||||
/// </summary>
|
|
||||||
private TextMeshPro? KeybindText { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The method used to create the button.
|
/// The method used to create the button.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -199,26 +162,6 @@ public abstract class CustomActionButton
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
if (Keybind != null)
|
|
||||||
{
|
|
||||||
Keybind.OnActivate(() =>
|
|
||||||
{
|
|
||||||
if (Enabled(PlayerControl.LocalPlayer.Data.Role))
|
|
||||||
{
|
|
||||||
ClickHandler();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
KeybindIcon =
|
|
||||||
Helpers.CreateKeybindIcon(
|
|
||||||
Button.gameObject,
|
|
||||||
Keybind.CurrentKey,
|
|
||||||
new Vector3(MaxUses <= 0 ? -0.4f : 0.4f, 0.45f, -9f)
|
|
||||||
);
|
|
||||||
KeybindText = KeybindIcon.transform.GetChild(0).GetComponent<TextMeshPro>();
|
|
||||||
Button.usesRemainingSprite.transform.localPosition = new(-0.341f, 0.45f, -0.1f);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -235,10 +178,7 @@ public abstract class CustomActionButton
|
|||||||
|
|
||||||
this.Location = location;
|
this.Location = location;
|
||||||
|
|
||||||
if (!moveButton)
|
if (!moveButton) return;
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (HudManagerPatches.BottomLeft == null || HudManagerPatches.BottomRight == null)
|
if (HudManagerPatches.BottomLeft == null || HudManagerPatches.BottomRight == null)
|
||||||
{
|
{
|
||||||
@@ -405,13 +345,6 @@ public abstract class CustomActionButton
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns a value indicating whether the effect can be ended early by the player.
|
|
||||||
/// Always false by default.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>Can the effect be canceled.</returns>
|
|
||||||
public virtual bool IsEffectCancellable() => false;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// When the button is usable, this method is called to determine if the button can be clicked.
|
/// When the button is usable, this method is called to determine if the button can be clicked.
|
||||||
/// By default, it takes into account the timer, effect, and uses.
|
/// By default, it takes into account the timer, effect, and uses.
|
||||||
@@ -420,7 +353,7 @@ public abstract class CustomActionButton
|
|||||||
/// <returns>A value that represents whether the button can be clicked or not.</returns>
|
/// <returns>A value that represents whether the button can be clicked or not.</returns>
|
||||||
public virtual bool CanClick()
|
public virtual bool CanClick()
|
||||||
{
|
{
|
||||||
return (EffectActive ? IsEffectCancellable() : Timer <= 0) && CanUse();
|
return Timer <= 0 && !EffectActive && CanUse();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -430,8 +363,7 @@ public abstract class CustomActionButton
|
|||||||
/// <returns>A value that represents whether the button should light up or not.</returns>
|
/// <returns>A value that represents whether the button should light up or not.</returns>
|
||||||
public virtual bool CanUse()
|
public virtual bool CanUse()
|
||||||
{
|
{
|
||||||
return PlayerControl.LocalPlayer.moveable &&
|
return PlayerControl.LocalPlayer.moveable && (!LimitedUses || UsesLeft > 0);
|
||||||
((EffectActive && IsEffectCancellable()) || (!EffectActive && (!LimitedUses || UsesLeft > 0)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -453,12 +385,6 @@ public abstract class CustomActionButton
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual void ClickHandler()
|
public virtual void ClickHandler()
|
||||||
{
|
{
|
||||||
if (EffectActive && IsEffectCancellable())
|
|
||||||
{
|
|
||||||
ResetCooldownAndOrEffect();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!CanClick())
|
if (!CanClick())
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
@@ -491,22 +417,14 @@ public abstract class CustomActionButton
|
|||||||
/// <param name="playerControl">The local PlayerControl.</param>
|
/// <param name="playerControl">The local PlayerControl.</param>
|
||||||
public virtual void FixedUpdateHandler(PlayerControl playerControl)
|
public virtual void FixedUpdateHandler(PlayerControl playerControl)
|
||||||
{
|
{
|
||||||
if (Keybind != null && KeybindText != null)
|
|
||||||
{
|
|
||||||
KeybindText.text = Keybind.CurrentKey.ToString();
|
|
||||||
KeybindIcon?.SetActive(ActiveInputManager.currentControlType == ActiveInputManager.InputType.Keyboard &&
|
|
||||||
LocalSettingsTabSingleton<MiraApiSettings>.Instance.ShowKeybinds.Value &&
|
|
||||||
Keybind.CurrentKey != KeyboardKeyCode.None);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Timer >= 0)
|
if (Timer >= 0)
|
||||||
{
|
{
|
||||||
if (!TimerPaused && (!PauseTimerInVent || !playerControl.inVent))
|
if (!TimerPaused)
|
||||||
{
|
{
|
||||||
Timer -= Time.deltaTime;
|
Timer -= Time.deltaTime;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (HasEffect && EffectActive && EffectDuration > 0)
|
else if (HasEffect && EffectActive)
|
||||||
{
|
{
|
||||||
EffectActive = false;
|
EffectActive = false;
|
||||||
Timer = Cooldown;
|
Timer = Cooldown;
|
||||||
@@ -524,16 +442,16 @@ public abstract class CustomActionButton
|
|||||||
Button!.SetDisabled();
|
Button!.SetDisabled();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (EffectActive && EffectDuration > 0)
|
if (EffectActive)
|
||||||
{
|
{
|
||||||
Button.SetFillUp(Timer, EffectDuration);
|
Button.SetFillUp(Timer, EffectDuration);
|
||||||
|
|
||||||
Button.cooldownTimerText.text = Timer.ToString(CooldownTimerFormatString, NumberFormatInfo.InvariantInfo);
|
Button.cooldownTimerText.text = Mathf.CeilToInt(Timer).ToString(NumberFormatInfo.InvariantInfo);
|
||||||
Button.cooldownTimerText.gameObject.SetActive(true);
|
Button.cooldownTimerText.gameObject.SetActive(true);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Button.SetCooldownFormat(Timer, Cooldown, CooldownTimerFormatString);
|
Button.SetCoolDown(Timer, Cooldown);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ using System.Collections.ObjectModel;
|
|||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using MiraAPI.Events.Mira;
|
using MiraAPI.Events.Mira;
|
||||||
using MiraAPI.PluginLoading;
|
using MiraAPI.PluginLoading;
|
||||||
using UnityEngine;
|
|
||||||
|
|
||||||
namespace MiraAPI.Hud;
|
namespace MiraAPI.Hud;
|
||||||
|
|
||||||
@@ -30,7 +29,7 @@ public static class CustomButtonManager
|
|||||||
}
|
}
|
||||||
|
|
||||||
CustomButtons.Add(button);
|
CustomButtons.Add(button);
|
||||||
pluginInfo.InternalButtons.Add(button);
|
pluginInfo.Buttons.Add(button);
|
||||||
typeof(CustomButtonSingleton<>).MakeGenericType(buttonType)
|
typeof(CustomButtonSingleton<>).MakeGenericType(buttonType)
|
||||||
#pragma warning disable S3011
|
#pragma warning disable S3011
|
||||||
.GetField("_instance", BindingFlags.Static | BindingFlags.NonPublic)!
|
.GetField("_instance", BindingFlags.Static | BindingFlags.NonPublic)!
|
||||||
|
|||||||
@@ -1,78 +0,0 @@
|
|||||||
using System.Linq;
|
|
||||||
using HarmonyLib;
|
|
||||||
using Reactor.Utilities.Extensions;
|
|
||||||
using UnityEngine;
|
|
||||||
|
|
||||||
namespace MiraAPI.Hud;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Custom action button that has multiple target objects.
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="T">The type of the target objects.</typeparam>
|
|
||||||
public abstract class MultiTargetButton<T> : CustomActionButton where T : MonoBehaviour
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets the list of targets of the button.
|
|
||||||
/// </summary>
|
|
||||||
public T[] Targets { get; protected set; } = [];
|
|
||||||
|
|
||||||
/// <inheritdoc cref="CustomActionButton{T}.Distance"/>
|
|
||||||
public virtual float Distance => PlayerControl.LocalPlayer.Data.Role.GetAbilityDistance();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the maximum amount of targets the button can have.
|
|
||||||
/// </summary>
|
|
||||||
public virtual int MaxTargets { get; } = int.MaxValue;
|
|
||||||
|
|
||||||
/// <inheritdoc cref="CustomActionButton{T}.IsTargetValid"/>
|
|
||||||
public virtual bool IsTargetValid(T target)
|
|
||||||
{
|
|
||||||
return target != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The method used to get the target objects.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>The list of target objects.</returns>
|
|
||||||
public abstract T[] GetTargets();
|
|
||||||
|
|
||||||
/// <inheritdoc cref="CustomActionButton{T}.SetOutline"/>
|
|
||||||
/// <param name="target">The target object to set the oultine.</param>
|
|
||||||
public abstract void SetOutline(T target, bool active);
|
|
||||||
|
|
||||||
/// <inheritdoc cref="CustomActionButton{T}.CanUse"/>
|
|
||||||
public override bool CanUse()
|
|
||||||
{
|
|
||||||
var newTargets = GetTargets();
|
|
||||||
foreach (var target in Targets)
|
|
||||||
{
|
|
||||||
if (!newTargets.Contains(target))
|
|
||||||
{
|
|
||||||
SetOutline(target, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Targets = newTargets
|
|
||||||
.Where(IsTargetValid)
|
|
||||||
.Take(MaxTargets)
|
|
||||||
.ToArray();
|
|
||||||
Targets.Do(t => SetOutline(t, true));
|
|
||||||
|
|
||||||
return base.CanUse() && Targets.Length > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc cref="CustomActionButton{T}.CanClick"/>
|
|
||||||
public override bool CanClick()
|
|
||||||
{
|
|
||||||
return base.CanClick() && Targets.Length > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Use this to reset the button's targets after used.
|
|
||||||
/// </summary>
|
|
||||||
public virtual void ResetTarget()
|
|
||||||
{
|
|
||||||
Targets.Do(t => SetOutline(t, false));
|
|
||||||
Targets = [];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,72 +0,0 @@
|
|||||||
using System;
|
|
||||||
using Rewired;
|
|
||||||
|
|
||||||
namespace MiraAPI.Keybinds;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Base keybind class.
|
|
||||||
/// </summary>
|
|
||||||
public class BaseKeybind
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the Rewired <see cref="InputAction"/> assinged for this keybind.
|
|
||||||
/// </summary>
|
|
||||||
public InputAction? RewiredInputAction { get; internal set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the unique identifier for this keybind. Used in Rewired.
|
|
||||||
/// </summary>
|
|
||||||
public string Id { get; protected set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the currently assigned keycode.
|
|
||||||
/// </summary>
|
|
||||||
public KeyboardKeyCode CurrentKey => KeybindUtils.GetKeycodeByKeybind(this);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets the handler of the keybind. Invoked when the keybind is activated.
|
|
||||||
/// </summary>
|
|
||||||
protected Action Handler { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="BaseKeybind"/> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="id">The unique identifier for this keybind.</param>
|
|
||||||
public BaseKeybind(string id)
|
|
||||||
{
|
|
||||||
Id = id;
|
|
||||||
Handler = () => { };
|
|
||||||
}
|
|
||||||
|
|
||||||
public BaseKeybind()
|
|
||||||
{
|
|
||||||
Handler = () => { };
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Triggers the keybind, invoking its handler.
|
|
||||||
/// </summary>
|
|
||||||
public void Invoke()
|
|
||||||
{
|
|
||||||
Handler.Invoke();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Adds an <see cref="Action"/> that will be invoked when the keybind is used.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="action">The <see cref="Action"/> to add.</param>
|
|
||||||
public void OnActivate(Action action)
|
|
||||||
{
|
|
||||||
Handler += action;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Removes an <see cref="Action"/> that would be invoked when the keybind is used.
|
|
||||||
/// Not recommended to use - add checks in the method added in <see cref="OnActivate"/> itself rather than removing it from the keybind.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="action">The <see cref="Action"/> to remove.</param>
|
|
||||||
public void RemoveOnActivate(Action action)
|
|
||||||
{
|
|
||||||
Handler -= action;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,98 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using Il2CppInterop.Runtime.Attributes;
|
|
||||||
using MiraAPI.Utilities;
|
|
||||||
using Reactor.Utilities;
|
|
||||||
using Rewired;
|
|
||||||
|
|
||||||
namespace MiraAPI.Keybinds;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Lets you register and manage mod keybinds with conflict checks and rebinding support.
|
|
||||||
/// </summary>
|
|
||||||
public static class KeybindManager
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Gets a list of all registered keybinds.
|
|
||||||
/// </summary>
|
|
||||||
public static List<MiraKeybind> Keybinds { get; } = new();
|
|
||||||
|
|
||||||
[HideFromIl2Cpp]
|
|
||||||
internal static Dictionary<Type, VanillaKeybind> VanillaKeybinds { get; set; } = [];
|
|
||||||
|
|
||||||
internal static void RewiredInit()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var instance = KeybindUtils.RewiredInputManager!;
|
|
||||||
foreach (var keybind in KeybindManager.Keybinds)
|
|
||||||
{
|
|
||||||
if (instance.userData.actions.ToArray().Any(x => x.name == keybind.Id))
|
|
||||||
{
|
|
||||||
Logger<MiraApiPlugin>.Warning($"Keybind of id {keybind.Id} already exists. Skipping it");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
keybind.RewiredInputAction = instance.userData.RegisterModBind(
|
|
||||||
keybind.Id,
|
|
||||||
keybind.Name,
|
|
||||||
keybind.SourcePluginName,
|
|
||||||
keybind.DefaultKey,
|
|
||||||
modifiers: keybind.ModifierKeys);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
Logger<MiraApiPlugin>.Error($"Error while registering keybinds in Rewired: {e}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns all conflicts where keybinds use the same key.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>A list of pairs of keybinds that conflict.</returns>
|
|
||||||
public static Dictionary<KeyboardKeyCode, List<MiraKeybind>> GetConflicts()
|
|
||||||
{
|
|
||||||
var conflicts = new Dictionary<KeyboardKeyCode, List<MiraKeybind>>();
|
|
||||||
foreach (var keybind in Keybinds)
|
|
||||||
{
|
|
||||||
var all = GetKeybindsForKey(keybind.CurrentKey, true);
|
|
||||||
if (all.Length > 1)
|
|
||||||
{
|
|
||||||
if (!conflicts.TryGetValue(keybind.CurrentKey, out var group))
|
|
||||||
{
|
|
||||||
conflicts.Add(keybind.CurrentKey, new List<MiraKeybind>());
|
|
||||||
group = conflicts[keybind.CurrentKey];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!group.Contains(keybind))
|
|
||||||
{
|
|
||||||
group.Add(keybind);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return conflicts;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns all keybinds for a specified keycode.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="keyCode">The key to look for.</param>
|
|
||||||
/// /// <param name="exclusiveCheck">Should only exlusive keybinds be present.</param>
|
|
||||||
/// <returns>The list of keybinds.</returns>
|
|
||||||
public static MiraKeybind[] GetKeybindsForKey(KeyboardKeyCode keyCode, bool exclusiveCheck = false)
|
|
||||||
{
|
|
||||||
var all = new List<MiraKeybind>();
|
|
||||||
foreach (var keybind in Keybinds)
|
|
||||||
{
|
|
||||||
if (keybind.CurrentKey == keyCode && (keybind.Exclusive || !exclusiveCheck))
|
|
||||||
{
|
|
||||||
all.Add(keybind);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return all.ToArray();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,80 +0,0 @@
|
|||||||
using System;
|
|
||||||
using Rewired;
|
|
||||||
|
|
||||||
namespace MiraAPI.Keybinds;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Collection of keybind-related utility classes.
|
|
||||||
/// </summary>
|
|
||||||
public static class KeybindUtils
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the Rewired <see cref="InputManager_Base"/> instance.
|
|
||||||
/// </summary>
|
|
||||||
public static InputManager_Base? RewiredInputManager { get; internal set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns the currently assigned keycode of a keybind.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="keybind">The keybind to get the keycode from.</param>
|
|
||||||
/// <returns>The currently assigned keycode.</returns>
|
|
||||||
public static KeyboardKeyCode GetKeycodeByKeybind(BaseKeybind keybind)
|
|
||||||
{
|
|
||||||
if (keybind.RewiredInputAction == null)
|
|
||||||
{
|
|
||||||
return KeyboardKeyCode.None;
|
|
||||||
}
|
|
||||||
|
|
||||||
return GetKeycodeByActionId(keybind.RewiredInputAction.id);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the keycode for an action with ReInput.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="actionId">The action ID.</param>
|
|
||||||
/// <returns>The keyboard keycode.</returns>
|
|
||||||
public static KeyboardKeyCode GetKeycodeByActionId(int actionId)
|
|
||||||
{
|
|
||||||
return GetActionElementMap(actionId)?.keyboardKeyCode ?? KeyboardKeyCode.None;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets a <see cref="ActionElementMap"/> by id with ReInput.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="actionId">The action ID.</param>
|
|
||||||
/// <returns>The keyboard keycode.</returns>
|
|
||||||
public static ActionElementMap? GetActionElementMap(int actionId)
|
|
||||||
{
|
|
||||||
var player = ReInput.players.GetPlayer(0);
|
|
||||||
return player.controllers.maps.GetFirstElementMapWithAction(ControllerType.Keyboard, actionId, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets an <see cref="InputAction"/> by id.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="id">The action identifier name.</param>
|
|
||||||
/// <returns>The keyboard keycode.</returns>
|
|
||||||
public static InputAction? GetInputActionById(int id)
|
|
||||||
{
|
|
||||||
return RewiredInputManager?.userData?.GetActionById(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Finds and returns an unused KeyCode that is not equal to the excluded key.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="exclude">The KeyCode to skip during the search.</param>
|
|
||||||
/// <returns>
|
|
||||||
/// The first available KeyCode not currently used by any registered keybind,
|
|
||||||
/// or KeyCode.None if none are available.
|
|
||||||
/// </returns>
|
|
||||||
public static KeyboardKeyCode FindAvailableKey(KeyboardKeyCode exclude)
|
|
||||||
{
|
|
||||||
foreach (KeyboardKeyCode key in Enum.GetValues<KeyboardKeyCode>())
|
|
||||||
{
|
|
||||||
if (key == exclude) continue;
|
|
||||||
bool used = KeybindManager.Keybinds.Exists(e => e.DefaultKey == key);
|
|
||||||
if (!used) return key;
|
|
||||||
}
|
|
||||||
return KeyboardKeyCode.None;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
using Rewired;
|
|
||||||
|
|
||||||
namespace MiraAPI.Keybinds;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Class containing all default keybinds.
|
|
||||||
/// Recommended for cross-mod compatibility.
|
|
||||||
/// </summary>
|
|
||||||
[RegisterCustomKeybinds]
|
|
||||||
public static class MiraGlobalKeybinds
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the keybind for primary abilities.
|
|
||||||
/// </summary>
|
|
||||||
public static MiraKeybind PrimaryAbility { get; } = new("Primary Ability", KeyboardKeyCode.T);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the keybind for secondary abilities.
|
|
||||||
/// </summary>
|
|
||||||
public static MiraKeybind SecondaryAbility { get; } = new("Secondary Ability", KeyboardKeyCode.Y);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the keybind for Tetiary abilities.
|
|
||||||
/// </summary>
|
|
||||||
public static MiraKeybind TertiaryAbility { get; } = new("Tertiary Ability", KeyboardKeyCode.U);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the keybind for primary modifier abilities.
|
|
||||||
/// </summary>
|
|
||||||
public static MiraKeybind ModifierPrimaryAbility { get; } = new("Modifier Primary Ability", KeyboardKeyCode.I);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the keybind for secondary modifier abilities.
|
|
||||||
/// </summary>
|
|
||||||
public static MiraKeybind ModifierSecondaryAbility { get; } = new("Modifier Secondary Ability", KeyboardKeyCode.O);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the keybind for Tetiary modifier abilities.
|
|
||||||
/// </summary>
|
|
||||||
public static MiraKeybind ModifierTertiaryAbility { get; } = new("Modifier Tertiary Ability", KeyboardKeyCode.P);
|
|
||||||
}
|
|
||||||
@@ -1,58 +0,0 @@
|
|||||||
using System.Globalization;
|
|
||||||
using Rewired;
|
|
||||||
|
|
||||||
namespace MiraAPI.Keybinds;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Represents a registered keybind.
|
|
||||||
/// </summary>
|
|
||||||
public class MiraKeybind : BaseKeybind
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Gets name of the keybind
|
|
||||||
/// </summary>
|
|
||||||
public string Name { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the default keycode of this keybind.
|
|
||||||
/// </summary>
|
|
||||||
public KeyboardKeyCode DefaultKey { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the modifier keys assigned to this keybind.
|
|
||||||
/// Due to Rewired limitations, there can only be 3 modifier keys.
|
|
||||||
/// </summary>
|
|
||||||
public ModifierKey[] ModifierKeys { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets a value indicating whether this keybind should be checked for conflicts with other exclusive keybinds using the same key.
|
|
||||||
/// </summary>
|
|
||||||
public bool Exclusive { get; }
|
|
||||||
|
|
||||||
internal string? SourcePluginName { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="MiraKeybind"/> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="name">The name of the keybind.</param>
|
|
||||||
/// <param name="defaultKeycode">The default keycode.</param>
|
|
||||||
/// <param name="modifierKeys">Up to 3 optional modifier keys.</param>
|
|
||||||
/// <param name="exclusive">Is exclusive.</param>
|
|
||||||
public MiraKeybind(
|
|
||||||
string name,
|
|
||||||
KeyboardKeyCode? defaultKeycode,
|
|
||||||
ModifierKey[]? modifierKeys = null,
|
|
||||||
bool exclusive = true) : base(name.ToLower(CultureInfo.InvariantCulture).Replace(' ', '_'))
|
|
||||||
{
|
|
||||||
Name = name;
|
|
||||||
DefaultKey = defaultKeycode ?? KeyboardKeyCode.None;
|
|
||||||
ModifierKeys = modifierKeys ?? [];
|
|
||||||
Exclusive = exclusive;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public override string ToString()
|
|
||||||
{
|
|
||||||
return $"{Name} ({Id})";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
using System;
|
|
||||||
|
|
||||||
namespace MiraAPI.Keybinds;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Used to mark a class for custom keybinds registration.
|
|
||||||
/// </summary>
|
|
||||||
[AttributeUsage(AttributeTargets.Class)]
|
|
||||||
public class RegisterCustomKeybindsAttribute : Attribute;
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
using Rewired;
|
|
||||||
|
|
||||||
namespace MiraAPI.Keybinds;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Represents a vanilla keybind.
|
|
||||||
/// </summary>
|
|
||||||
public class VanillaKeybind : BaseKeybind
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the <see cref="ActionButton"/> this keybind is binded to.
|
|
||||||
/// </summary>
|
|
||||||
public ActionButton? Button { get; internal set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="VanillaKeybind"/> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="id">The keybind id.</param>
|
|
||||||
public VanillaKeybind(int id)
|
|
||||||
{
|
|
||||||
RewiredInputAction = KeybindUtils.GetInputActionById(id);
|
|
||||||
Id = RewiredInputAction?.name;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
namespace MiraAPI.Keybinds;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Singleton for getting a vanilla keybind by <see cref="ActionButton"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="T">ActionButton type.</typeparam>
|
|
||||||
public static class VanillaKeybinding<T> where T : ActionButton
|
|
||||||
{
|
|
||||||
private static VanillaKeybind? _instance;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the instance of the option group.
|
|
||||||
/// </summary>
|
|
||||||
#pragma warning disable CA1000
|
|
||||||
public static VanillaKeybind Instance => _instance ??= KeybindManager.VanillaKeybinds[typeof(T)];
|
|
||||||
#pragma warning restore CA1000
|
|
||||||
}
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
using System;
|
|
||||||
using BepInEx.Configuration;
|
|
||||||
using MiraAPI.LocalSettings.SettingTypes;
|
|
||||||
|
|
||||||
namespace MiraAPI.LocalSettings.Attributes;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates an enum setting for the <see cref="ConfigEntry{T}"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="names">Optional custom enum names.</param>
|
|
||||||
/// <inheritdoc/>
|
|
||||||
[AttributeUsage(AttributeTargets.Property)]
|
|
||||||
public class LocalEnumSettingAttribute(
|
|
||||||
string? name = null,
|
|
||||||
string? description = null,
|
|
||||||
string[]? names = null
|
|
||||||
) : LocalSettingAttribute(name, description)
|
|
||||||
{
|
|
||||||
private readonly string? _name = name;
|
|
||||||
private readonly string? _description = description;
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
internal override LocalEnumSetting CreateSetting(Type tab, ConfigEntryBase configEntryBase)
|
|
||||||
{
|
|
||||||
return new LocalEnumSetting(tab, configEntryBase, configEntryBase.SettingType, _name, _description, names);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
using System;
|
|
||||||
using BepInEx.Configuration;
|
|
||||||
using MiraAPI.LocalSettings.SettingTypes;
|
|
||||||
using MiraAPI.Utilities;
|
|
||||||
|
|
||||||
namespace MiraAPI.LocalSettings.Attributes;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates a number setting for the <see cref="ConfigEntry{T}"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="min">Minimum range.</param>
|
|
||||||
/// <param name="max">Maximum range.</param>
|
|
||||||
/// <param name="increment">Increment per use.</param>
|
|
||||||
/// <param name="suffixType">Suffix for the value.</param>
|
|
||||||
/// <param name="formatString">Format string used when formating.</param>
|
|
||||||
/// <inheritdoc/>
|
|
||||||
[AttributeUsage(AttributeTargets.Property)]
|
|
||||||
public class LocalNumberSettingAttribute(
|
|
||||||
string? name = null,
|
|
||||||
string? description = null,
|
|
||||||
float min = 1,
|
|
||||||
float max = 5,
|
|
||||||
float increment = 1,
|
|
||||||
MiraNumberSuffixes suffixType = MiraNumberSuffixes.None,
|
|
||||||
string? formatString = null
|
|
||||||
) : LocalSettingAttribute(name, description)
|
|
||||||
{
|
|
||||||
private readonly string? _name = name;
|
|
||||||
private readonly string? _description = description;
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
internal override LocalNumberSetting CreateSetting(Type tab, ConfigEntryBase configEntryBase)
|
|
||||||
{
|
|
||||||
return new LocalNumberSetting(tab, configEntryBase, _name, _description, new FloatRange(min, max), increment, suffixType, formatString);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
using System;
|
|
||||||
using BepInEx.Configuration;
|
|
||||||
|
|
||||||
namespace MiraAPI.LocalSettings.Attributes;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Base class for all local settings attributes.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="name">The name of the setting. Defaults to entry key.</param>
|
|
||||||
/// <param name="description">The description of the setting. Defalts to entry description.</param>
|
|
||||||
[AttributeUsage(AttributeTargets.Property)]
|
|
||||||
public abstract class LocalSettingAttribute(
|
|
||||||
string? name = null,
|
|
||||||
string? description = null
|
|
||||||
) : Attribute
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Returns the created setting object.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="tab">Gets the tab where the setting is located.</param>
|
|
||||||
/// <param name="configEntryBase">Gets the config entry the setting is attached to.</param>
|
|
||||||
/// <returns>The created class.</returns>
|
|
||||||
internal abstract ILocalSetting CreateSetting(Type tab, ConfigEntryBase configEntryBase);
|
|
||||||
}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
using System;
|
|
||||||
using BepInEx.Configuration;
|
|
||||||
|
|
||||||
namespace MiraAPI.LocalSettings.Attributes;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Attribute for local setting buttons.
|
|
||||||
/// </summary>
|
|
||||||
[AttributeUsage(AttributeTargets.Property)]
|
|
||||||
public class LocalSettingsButtonAttribute : Attribute
|
|
||||||
{
|
|
||||||
}
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
using System;
|
|
||||||
using BepInEx.Configuration;
|
|
||||||
using MiraAPI.LocalSettings.SettingTypes;
|
|
||||||
using MiraAPI.Utilities;
|
|
||||||
|
|
||||||
namespace MiraAPI.LocalSettings.Attributes;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates a slider setting for the <see cref="ConfigEntry{T}"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <inheritdoc/>
|
|
||||||
/// <param name="min">Minimum range.</param>
|
|
||||||
/// <param name="max">Maximum range.</param>
|
|
||||||
/// <param name="roundValue">Should the value be rounded.</param>
|
|
||||||
/// <param name="suffixType">Suffix for the value.</param>
|
|
||||||
[AttributeUsage(AttributeTargets.Property)]
|
|
||||||
public class LocalSliderSettingAttribute(
|
|
||||||
string? name = null,
|
|
||||||
float min = 0,
|
|
||||||
float max = 100,
|
|
||||||
string? description = null,
|
|
||||||
bool displayValue = false,
|
|
||||||
string? formatString = null,
|
|
||||||
bool roundValue = false,
|
|
||||||
MiraNumberSuffixes suffixType = MiraNumberSuffixes.None
|
|
||||||
) : LocalSettingAttribute(name, description)
|
|
||||||
{
|
|
||||||
private readonly string? _name = name;
|
|
||||||
private readonly string? _description = description;
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
internal override LocalSliderSetting CreateSetting(Type tab, ConfigEntryBase configEntryBase)
|
|
||||||
{
|
|
||||||
return new LocalSliderSetting(tab, configEntryBase, _name, _description, new FloatRange(min, max), displayValue, suffixType, formatString, roundValue);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
using System;
|
|
||||||
using BepInEx.Configuration;
|
|
||||||
using MiraAPI.LocalSettings.SettingTypes;
|
|
||||||
|
|
||||||
namespace MiraAPI.LocalSettings.Attributes;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates a toggle setting for the <see cref="ConfigEntry{T}"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <inheritdoc/>
|
|
||||||
[AttributeUsage(AttributeTargets.Property)]
|
|
||||||
public class LocalToggleSettingAttribute(
|
|
||||||
string? name = null,
|
|
||||||
string? description = null
|
|
||||||
) : LocalSettingAttribute(name, description)
|
|
||||||
{
|
|
||||||
private readonly string? _name = name;
|
|
||||||
private readonly string? _description = description;
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
internal override LocalToggleSetting CreateSetting(Type tab, ConfigEntryBase configEntryBase)
|
|
||||||
{
|
|
||||||
return new LocalToggleSetting(tab, configEntryBase, _name, _description);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
using BepInEx.Configuration;
|
|
||||||
using UnityEngine;
|
|
||||||
|
|
||||||
namespace MiraAPI.LocalSettings;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Interface for all local settings.
|
|
||||||
/// </summary>
|
|
||||||
public interface ILocalSetting
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the preferred name of a setting.
|
|
||||||
/// </summary>
|
|
||||||
string Name { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the description of a setting.
|
|
||||||
/// </summary>
|
|
||||||
string Description { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the setting's gameobject.
|
|
||||||
/// </summary>
|
|
||||||
GameObject? Setting { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the setting's config entry.
|
|
||||||
/// </summary>
|
|
||||||
ConfigEntryBase ConfigEntry { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Used to create the setting.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="toggle">Toggle template.</param>
|
|
||||||
/// <param name="slider">Slider template.</param>
|
|
||||||
/// <param name="parent">The parent of the setting.</param>
|
|
||||||
/// <param name="offset">The offset.</param>
|
|
||||||
/// <param name="order">The order.</param>
|
|
||||||
/// <param name="last">Whether it's the last on the row.</param>
|
|
||||||
/// <returns>The created setting.</returns>
|
|
||||||
GameObject? CreateOption(ToggleButtonBehaviour toggle, SlideBar slider, Transform parent, ref float offset, ref int order, bool last);
|
|
||||||
}
|
|
||||||
@@ -1,78 +0,0 @@
|
|||||||
using System;
|
|
||||||
using MiraAPI.Utilities;
|
|
||||||
using Reactor.Localization.Utilities;
|
|
||||||
using Reactor.Utilities.Extensions;
|
|
||||||
using TMPro;
|
|
||||||
using UnityEngine;
|
|
||||||
using UnityEngine.Events;
|
|
||||||
using Object = UnityEngine.Object;
|
|
||||||
|
|
||||||
namespace MiraAPI.LocalSettings;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Represents a local settings button.
|
|
||||||
/// </summary>
|
|
||||||
public class LocalSettingsButton(string text, Action onClick)
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets the button text.
|
|
||||||
/// </summary>
|
|
||||||
public string Text { get; set; } = text;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets the button on-click action.
|
|
||||||
/// </summary>
|
|
||||||
public Action OnClick { get; set; } = onClick;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the tab instance this button belongs to.
|
|
||||||
/// </summary>
|
|
||||||
public LocalSettingsTab? Tab { get; internal set; }
|
|
||||||
|
|
||||||
internal GameObject CreateButton(ToggleButtonBehaviour toggle, Transform parent, ref float offset, ref int order, bool last)
|
|
||||||
{
|
|
||||||
var button = Object.Instantiate(toggle, parent).GetComponent<PassiveButton>();
|
|
||||||
var tmp = button.transform.FindChild("Text_TMP").GetComponent<TextMeshPro>();
|
|
||||||
var rollover = button.GetComponent<ButtonRolloverHandler>();
|
|
||||||
tmp.GetComponent<TextTranslatorTMP>().Destroy();
|
|
||||||
button.gameObject.SetActive(true);
|
|
||||||
|
|
||||||
var toggleComp = button.GetComponent<ToggleButtonBehaviour>();
|
|
||||||
var background = toggleComp.Background;
|
|
||||||
button.transform.FindChild("ButtonHighlight")?.gameObject.DestroyImmediate();
|
|
||||||
toggleComp.Destroy();
|
|
||||||
|
|
||||||
if (last && order == 1)
|
|
||||||
{
|
|
||||||
// Button in the middle
|
|
||||||
button.transform.localPosition = new Vector3(0, 1.85f - offset, -7);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
button.transform.localPosition = new Vector3(order == 1 ? -1.185f : 1.185f, 1.85f - offset, -7);
|
|
||||||
}
|
|
||||||
|
|
||||||
tmp.text = Text;
|
|
||||||
button.name = Text;
|
|
||||||
button.OnClick = new UnityEngine.UI.Button.ButtonClickedEvent();
|
|
||||||
rollover.OutColor = Tab!.TabAppearance.ButtonColor;
|
|
||||||
rollover.OverColor = Tab!.TabAppearance.ButtonHoverColor;
|
|
||||||
rollover.Target = background;
|
|
||||||
background.color = Tab!.TabAppearance.ButtonColor;
|
|
||||||
button.OnClick.AddListener((UnityAction)OnClick);
|
|
||||||
|
|
||||||
background.transform.localScale = new Vector3(1, 1.25f, 1);
|
|
||||||
Helpers.DivideSize(button.gameObject, 1.1f);
|
|
||||||
|
|
||||||
order++;
|
|
||||||
if (order > 2 && !last)
|
|
||||||
{
|
|
||||||
offset += 0.5f;
|
|
||||||
order = 1;
|
|
||||||
}
|
|
||||||
if (last)
|
|
||||||
offset += 0.6f;
|
|
||||||
|
|
||||||
return button.gameObject;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Reflection;
|
|
||||||
using BepInEx.Unity.IL2CPP;
|
|
||||||
using MiraAPI.GameOptions;
|
|
||||||
using Reactor.Utilities;
|
|
||||||
|
|
||||||
namespace MiraAPI.LocalSettings;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Manages local settings.
|
|
||||||
/// </summary>
|
|
||||||
public static class LocalSettingsManager
|
|
||||||
{
|
|
||||||
internal static readonly Dictionary<Type, LocalSettingsTab> TypeToTab = [];
|
|
||||||
internal static readonly List<LocalSettingsTab> Tabs = [];
|
|
||||||
|
|
||||||
internal static bool RegisterTab(Type type, BasePlugin pluginInfo)
|
|
||||||
{
|
|
||||||
if (Activator.CreateInstance(type, pluginInfo.Config) is not LocalSettingsTab tab)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (TypeToTab.ContainsKey(type))
|
|
||||||
{
|
|
||||||
Logger<MiraApiPlugin>.Error($"Local settings tab {type.Name} already exists.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
Tabs.Add(tab);
|
|
||||||
TypeToTab.Add(type, tab);
|
|
||||||
|
|
||||||
typeof(LocalSettingsTabSingleton<>).MakeGenericType(type)
|
|
||||||
#pragma warning disable S3011
|
|
||||||
.GetField("_instance", BindingFlags.Static | BindingFlags.NonPublic)!
|
|
||||||
#pragma warning restore S3011
|
|
||||||
.SetValue(null, tab);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,297 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using BepInEx.Configuration;
|
|
||||||
using HarmonyLib;
|
|
||||||
using MiraAPI.Patches.LocalSettings;
|
|
||||||
using MiraAPI.Utilities;
|
|
||||||
using Reactor.Utilities.Extensions;
|
|
||||||
using TMPro;
|
|
||||||
using UnityEngine;
|
|
||||||
using UnityEngine.Events;
|
|
||||||
using Object = UnityEngine.Object;
|
|
||||||
|
|
||||||
namespace MiraAPI.LocalSettings;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Represents a local settings tab. Gets a button by default.
|
|
||||||
/// </summary>
|
|
||||||
public abstract class LocalSettingsTab(ConfigFile config)
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the name of the tab.
|
|
||||||
/// </summary>
|
|
||||||
public abstract string TabName { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the tab appearance.
|
|
||||||
/// </summary>
|
|
||||||
public virtual LocalSettingTabAppearance TabAppearance { get; } = new();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets a value indicating whether a button should be created for the tab.
|
|
||||||
/// </summary>
|
|
||||||
public virtual bool ShouldCreateButton => true;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets a value indicating whether the tab should have category labels.
|
|
||||||
/// </summary>
|
|
||||||
protected virtual bool ShouldCreateLabels => true;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the mod's config file. Automatically found in the plugin loader.
|
|
||||||
/// </summary>
|
|
||||||
public ConfigFile Config { get; } = config ?? throw new ArgumentNullException(nameof(config));
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the tab button instance.
|
|
||||||
/// </summary>
|
|
||||||
public TabGroup? TabButton { get; internal set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the list of settings.
|
|
||||||
/// </summary>
|
|
||||||
public List<ILocalSetting> Settings { get; } = [];
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the list of buttons.
|
|
||||||
/// </summary>
|
|
||||||
public List<LocalSettingsButton> Buttons { get; } = [];
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the index of this tab.
|
|
||||||
/// </summary>
|
|
||||||
protected int TabIndex => LocalSettingsManager.Tabs.IndexOf(this) + 10;
|
|
||||||
|
|
||||||
private Scroller? Scroller { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Invoked when an option value is changed.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="configEntry">The config entry which was changed.</param>
|
|
||||||
public virtual void OnOptionChanged(ConfigEntryBase configEntry)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Attempts to open the tab.
|
|
||||||
/// Override for custom behavior.
|
|
||||||
/// </summary>
|
|
||||||
public virtual void Open()
|
|
||||||
{
|
|
||||||
OptionsMenuPatches.Instance?.OpenTabGroup(TabIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates the tab <see cref="GameObject"/> and it's content.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="instance">The <see cref="OptionsMenuBehaviour"/> instace.</param>
|
|
||||||
/// <returns>The created tab <see cref="GameObject"/>.</returns>
|
|
||||||
public virtual GameObject CreateTab(OptionsMenuBehaviour instance)
|
|
||||||
{
|
|
||||||
var tab = Object.Instantiate(instance.transform.FindChild("GeneralTab").gameObject, instance.transform);
|
|
||||||
tab.name = $"{TabName}Tab";
|
|
||||||
tab.transform.DestroyChildren();
|
|
||||||
tab.gameObject.SetActive(false);
|
|
||||||
|
|
||||||
if (Scroller == null)
|
|
||||||
{
|
|
||||||
Scroller = Helpers.CreateScroller(tab.transform, OptionsMenuPatches.MaskCollider);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (TabButton != null)
|
|
||||||
{
|
|
||||||
TabButton.Content = tab.gameObject;
|
|
||||||
}
|
|
||||||
|
|
||||||
var generalLabel = instance.transform.FindChild("GeneralTab").FindChild("ControlGroup")
|
|
||||||
.FindChild("ControlText_TMP").gameObject;
|
|
||||||
var toggle = instance.transform.FindChild("GeneralTab").FindChild("ChatGroup").FindChild("CensorChatButton").GetComponent<ToggleButtonBehaviour>();
|
|
||||||
var slider = instance.transform.FindChild("GeneralTab").FindChild("SoundGroup").FindChild("SFXSlider").GetComponent<SlideBar>();
|
|
||||||
|
|
||||||
Dictionary<string, List<ILocalSetting>> entriesByGroup = new();
|
|
||||||
foreach (var entry in Settings)
|
|
||||||
{
|
|
||||||
var group = entry.ConfigEntry.Definition.Section;
|
|
||||||
if (!entriesByGroup.ContainsKey(group))
|
|
||||||
entriesByGroup.Add(group, []);
|
|
||||||
|
|
||||||
entriesByGroup[group].Add(entry);
|
|
||||||
}
|
|
||||||
|
|
||||||
float contentOffset = 0;
|
|
||||||
var contentOrder = 1;
|
|
||||||
var contentIndex = 1;
|
|
||||||
|
|
||||||
foreach (var pair in entriesByGroup)
|
|
||||||
{
|
|
||||||
if (ShouldCreateLabels)
|
|
||||||
{
|
|
||||||
CreateLabel(generalLabel, Scroller.Inner, pair.Key, ref contentOffset);
|
|
||||||
contentOrder = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var setting in pair.Value)
|
|
||||||
{
|
|
||||||
var obj = setting.CreateOption(
|
|
||||||
toggle,
|
|
||||||
slider,
|
|
||||||
Scroller.Inner,
|
|
||||||
ref contentOffset,
|
|
||||||
ref contentOrder,
|
|
||||||
contentIndex == pair.Value.Count);
|
|
||||||
|
|
||||||
obj!.GetComponentsInChildren<SpriteRenderer>(true).Do(x =>
|
|
||||||
{
|
|
||||||
x.maskInteraction = SpriteMaskInteraction.VisibleInsideMask;
|
|
||||||
x.sortingOrder = 150;
|
|
||||||
x.sortingLayerName = "Default";
|
|
||||||
});
|
|
||||||
|
|
||||||
obj.GetComponentsInChildren<MeshRenderer>(true).Do(x =>
|
|
||||||
{
|
|
||||||
x.sortingOrder = 151;
|
|
||||||
x.sortingLayerName = "Default";
|
|
||||||
});
|
|
||||||
|
|
||||||
obj.GetComponentsInChildren<PassiveButton>().Do(x => { x.ClickMask = OptionsMenuPatches.MaskCollider; });
|
|
||||||
|
|
||||||
contentIndex++;
|
|
||||||
}
|
|
||||||
|
|
||||||
contentOrder = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
contentIndex = 1;
|
|
||||||
contentOrder = 1;
|
|
||||||
foreach (var button in Buttons)
|
|
||||||
{
|
|
||||||
var obj = button.CreateButton(
|
|
||||||
toggle,
|
|
||||||
Scroller.Inner,
|
|
||||||
ref contentOffset,
|
|
||||||
ref contentOrder,
|
|
||||||
contentIndex == Buttons.Count);
|
|
||||||
|
|
||||||
obj!.GetComponentsInChildren<SpriteRenderer>(true).Do(x =>
|
|
||||||
{
|
|
||||||
x.maskInteraction = SpriteMaskInteraction.VisibleInsideMask;
|
|
||||||
x.sortingOrder = 150;
|
|
||||||
x.sortingLayerName = "Default";
|
|
||||||
});
|
|
||||||
|
|
||||||
obj.GetComponentsInChildren<MeshRenderer>(true).Do(x =>
|
|
||||||
{
|
|
||||||
x.sortingOrder = 151;
|
|
||||||
x.sortingLayerName = "Default";
|
|
||||||
});
|
|
||||||
|
|
||||||
obj.GetComponentsInChildren<PassiveButton>().Do(x => { x.ClickMask = OptionsMenuPatches.MaskCollider; });
|
|
||||||
|
|
||||||
contentIndex++;
|
|
||||||
}
|
|
||||||
|
|
||||||
Scroller.SetBounds(new FloatRange(0, (Settings.Count + Buttons.Count) * 0.5f - 5f), new FloatRange(0, 0));
|
|
||||||
return tab;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates the tab button.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="instance">The <see cref="OptionsMenuBehaviour"/> instance.</param>
|
|
||||||
/// <param name="tabIdx">The tab index.</param>
|
|
||||||
/// <param name="offset">The current button offset.</param>
|
|
||||||
/// <returns>The created button <see cref="GameObject"/>.</returns>
|
|
||||||
public virtual GameObject CreateTabButton(OptionsMenuBehaviour instance, ref int tabIdx, ref float offset)
|
|
||||||
{
|
|
||||||
var tabButtonObject = Object.Instantiate(instance.Tabs[0], instance.transform);
|
|
||||||
tabButtonObject.name = $"{TabName} Button";
|
|
||||||
tabButtonObject.transform.localPosition = new Vector3(2.4f, 2.1f - offset, 5.5f);
|
|
||||||
tabButtonObject.transform.localScale = new Vector3(1.25f, 1.25f, 1);
|
|
||||||
tabButtonObject.Button.color = TabAppearance.TabButtonColor;
|
|
||||||
TabButton = tabButtonObject;
|
|
||||||
|
|
||||||
var tabButtonText = tabButtonObject.transform.FindChild("Text_TMP").GetComponent<TextMeshPro>();
|
|
||||||
tabButtonText.GetComponent<TextTranslatorTMP>().Destroy(); // i hate text translators
|
|
||||||
tabButtonText.transform.localPosition = new Vector3(0.078f, 0, 0);
|
|
||||||
tabButtonText.transform.localScale = new Vector3(0.9f, 0.9f);
|
|
||||||
tabButtonText.alignment = TextAlignmentOptions.Right;
|
|
||||||
tabButtonText.text = $"<b>{GetShortName(TabName)}</b>";
|
|
||||||
|
|
||||||
var tabButton = tabButtonObject.GetComponent<PassiveButton>();
|
|
||||||
var rollover = tabButtonObject.Rollover;
|
|
||||||
rollover.OverColor = TabAppearance.TabButtonHoverColor;
|
|
||||||
rollover.OutColor = TabAppearance.TabButtonColor;
|
|
||||||
|
|
||||||
SpriteRenderer? tabButtonRend = null;
|
|
||||||
if (TabAppearance.TabIcon != null)
|
|
||||||
{
|
|
||||||
tabButtonRend = new GameObject("sprite").AddComponent<SpriteRenderer>();
|
|
||||||
tabButtonRend.gameObject.layer = 5; // ui layer
|
|
||||||
tabButtonRend.transform.SetParent(tabButtonObject.transform);
|
|
||||||
tabButtonRend.transform.localPosition = new Vector3(0.5f, 0, -2);
|
|
||||||
tabButtonRend.transform.localScale = new Vector3(0.2f, 0.2f, 1);
|
|
||||||
tabButtonRend.sprite = TabAppearance.TabIcon.LoadAsset();
|
|
||||||
tabButtonText.gameObject.SetActive(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
var tabIndex = tabIdx; // Local copies of the tab variables so we can use them in the lambdas
|
|
||||||
var tabOffset = offset;
|
|
||||||
tabButton.OnClick.AddListener((UnityAction)(() => { instance.OpenTabGroup(tabIndex + 10); }));
|
|
||||||
tabButton.OnMouseOver.AddListener((UnityAction)(() =>
|
|
||||||
{
|
|
||||||
tabButton.transform.localPosition = new Vector3(3.55f, 2.1f - tabOffset, 5.5f);
|
|
||||||
tabButtonText.gameObject.SetActive(true);
|
|
||||||
tabButtonText.transform.localPosition = new Vector3(-0.024f, 0, 0);
|
|
||||||
tabButtonText.maxVisibleCharacters = int.MaxValue;
|
|
||||||
tabButtonText.text = TabName;
|
|
||||||
tabButtonText.alignment = TextAlignmentOptions.Left;
|
|
||||||
}));
|
|
||||||
tabButton.OnMouseOut.AddListener((UnityAction)(() =>
|
|
||||||
{
|
|
||||||
if (!tabButtonObject.Content.gameObject.activeSelf)
|
|
||||||
{
|
|
||||||
//tabButtonObject.Button.color = TabColor;
|
|
||||||
//tabButtonObject.Rollover.OutColor = TabColor;
|
|
||||||
}
|
|
||||||
|
|
||||||
tabButton.transform.localPosition = new Vector3(2.4f, 2.1f - tabOffset, 5.5f);
|
|
||||||
tabButtonText.alignment = TextAlignmentOptions.Right;
|
|
||||||
if (tabButtonRend != null)
|
|
||||||
{
|
|
||||||
tabButtonRend.gameObject.SetActive(true);
|
|
||||||
tabButtonText.gameObject.SetActive(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
tabButtonText.transform.localPosition = new Vector3(0.1f, 0, 0);
|
|
||||||
tabButtonText.maxVisibleCharacters = 4;
|
|
||||||
tabButtonText.text = $"<b>{GetShortName(TabName)}</b>";
|
|
||||||
}));
|
|
||||||
|
|
||||||
return tabButtonObject.gameObject;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void CreateLabel(GameObject template, Transform parent, string text, ref float offset)
|
|
||||||
{
|
|
||||||
var label = Object.Instantiate(template, parent);
|
|
||||||
label.transform.localPosition = new Vector3(0, 1.85f - offset);
|
|
||||||
label.GetComponent<TextTranslatorTMP>().Destroy();
|
|
||||||
label.name = text;
|
|
||||||
|
|
||||||
var tmp = label.GetComponent<TextMeshPro>();
|
|
||||||
tmp.text = $"<font=\"LiberationSans SDF\" material=\"LiberationSans SDF - Chat Message Masked\"><b>{text}</b></font>";
|
|
||||||
tmp.alignment = TextAlignmentOptions.Center;
|
|
||||||
|
|
||||||
var meshRend = label.GetComponent<MeshRenderer>();
|
|
||||||
meshRend.sortingLayerName = "Default";
|
|
||||||
meshRend.sortingOrder = 151;
|
|
||||||
|
|
||||||
offset += 0.5f;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string GetShortName(string name)
|
|
||||||
{
|
|
||||||
var shortName = string.Empty;
|
|
||||||
name.Split(' ').Do(x => shortName += x[0]);
|
|
||||||
return shortName;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,91 +0,0 @@
|
|||||||
using MiraAPI.Utilities.Assets;
|
|
||||||
using UnityEngine;
|
|
||||||
|
|
||||||
namespace MiraAPI.LocalSettings;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Struct for modyfing tab apparance.
|
|
||||||
/// Defines how the settings look.
|
|
||||||
/// </summary>
|
|
||||||
public record struct LocalSettingTabAppearance()
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets main color of the tab.
|
|
||||||
/// </summary>
|
|
||||||
public Color TabColor { get; set; } = Color.white;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets tab button icon. No icon by default.
|
|
||||||
/// </summary>
|
|
||||||
public LoadableAsset<Sprite>? TabIcon { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets color of the tab button.
|
|
||||||
/// </summary>
|
|
||||||
public Color TabButtonColor { get; set; } = Color.white;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets hover color of the tab button.
|
|
||||||
/// </summary>
|
|
||||||
public Color TabButtonHoverColor { get; set; } = Palette.AcceptedGreen;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets active color of the tab button.
|
|
||||||
/// </summary>
|
|
||||||
public Color TabButtonActiveColor { get; set; } = Palette.AcceptedGreen;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets hover color of toggles.
|
|
||||||
/// </summary>
|
|
||||||
public Color ToggleHoverColor { get; set; } = Palette.AcceptedGreen;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets active color of toggles.
|
|
||||||
/// </summary>
|
|
||||||
public Color ToggleActiveColor { get; set; } = Palette.AcceptedGreen;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets inactive color of toggles.
|
|
||||||
/// </summary>
|
|
||||||
public Color ToggleInactiveColor { get; set; } = Color.red;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets color of number buttons.
|
|
||||||
/// </summary>
|
|
||||||
public Color NumberColor { get; set; } = Color.white;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets hover color of number buttons.
|
|
||||||
/// </summary>
|
|
||||||
public Color NumberHoverColor { get; set; } = Palette.AcceptedGreen;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets color of sliders.
|
|
||||||
/// </summary>
|
|
||||||
public Color SliderColor { get; set; } = Color.white;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets hover color of sliders.
|
|
||||||
/// </summary>
|
|
||||||
public Color SliderHoverColor { get; set; } = Palette.AcceptedGreen;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets color of enum buttons.
|
|
||||||
/// </summary>
|
|
||||||
public Color EnumColor { get; set; } = Color.white;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets hover color of enum buttons.
|
|
||||||
/// </summary>
|
|
||||||
public Color EnumHoverColor { get; set; } = Palette.AcceptedGreen;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets color of buttons.
|
|
||||||
/// </summary>
|
|
||||||
public Color ButtonColor { get; set; } = Color.white;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets hover color of buttons.
|
|
||||||
/// </summary>
|
|
||||||
public Color ButtonHoverColor { get; set; } = Palette.AcceptedGreen;
|
|
||||||
}
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
using System.Linq;
|
|
||||||
|
|
||||||
namespace MiraAPI.LocalSettings;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Singleton for local settings tabs.
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="T">The settings tab type.</typeparam>
|
|
||||||
public static class LocalSettingsTabSingleton<T> where T : LocalSettingsTab
|
|
||||||
{
|
|
||||||
private static T? _instance;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the instance of the setting tab.
|
|
||||||
/// </summary>
|
|
||||||
#pragma warning disable CA1000
|
|
||||||
public static T Instance => _instance ??= LocalSettingsManager.Tabs.OfType<T>().Single();
|
|
||||||
#pragma warning restore CA1000
|
|
||||||
}
|
|
||||||
@@ -1,132 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Linq;
|
|
||||||
using BepInEx.Configuration;
|
|
||||||
using MiraAPI.Utilities;
|
|
||||||
using Reactor.Utilities.Extensions;
|
|
||||||
using TMPro;
|
|
||||||
using UnityEngine;
|
|
||||||
using UnityEngine.Events;
|
|
||||||
using Object = UnityEngine.Object;
|
|
||||||
|
|
||||||
namespace MiraAPI.LocalSettings.SettingTypes;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Local setting class for enums.
|
|
||||||
/// </summary>
|
|
||||||
public class LocalEnumSetting : LocalSettingBase<int>
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the enum type of the setting.
|
|
||||||
/// </summary>
|
|
||||||
public Type EnumType { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the enum values.
|
|
||||||
/// </summary>
|
|
||||||
public string[] Values { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="LocalEnumSetting"/> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <inheritdoc/>
|
|
||||||
/// <param name="enumType">The enum type.</param>
|
|
||||||
/// <param name="values">The optional values array to replace the enum names.</param>
|
|
||||||
public LocalEnumSetting(
|
|
||||||
Type tab,
|
|
||||||
ConfigEntryBase configEntry,
|
|
||||||
Type enumType,
|
|
||||||
string? name = null,
|
|
||||||
string? description = null,
|
|
||||||
string[]? values = null)
|
|
||||||
: base(tab, configEntry, name, description)
|
|
||||||
{
|
|
||||||
EnumType = enumType;
|
|
||||||
Values = values ?? Enum
|
|
||||||
.GetValues(configEntry.SettingType)
|
|
||||||
.Cast<Enum>()
|
|
||||||
.Select(x => x.ToDisplayString())
|
|
||||||
.ToArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public override GameObject CreateOption(ToggleButtonBehaviour toggle, SlideBar slider, Transform parent, ref float offset, ref int order, bool last)
|
|
||||||
{
|
|
||||||
var button = Object.Instantiate(toggle, parent).GetComponent<PassiveButton>();
|
|
||||||
var tmp = button.transform.FindChild("Text_TMP").GetComponent<TextMeshPro>();
|
|
||||||
var rollover = button.GetComponent<ButtonRolloverHandler>();
|
|
||||||
tmp.GetComponent<TextTranslatorTMP>().Destroy();
|
|
||||||
button.gameObject.SetActive(true);
|
|
||||||
|
|
||||||
var toggleComp = button.GetComponent<ToggleButtonBehaviour>();
|
|
||||||
var background = toggleComp.Background;
|
|
||||||
var highlight = button.transform.FindChild("ButtonHighlight")?.GetComponent<SpriteRenderer>();
|
|
||||||
if (highlight != null)
|
|
||||||
{
|
|
||||||
highlight.color = Tab!.TabAppearance.EnumHoverColor;
|
|
||||||
highlight.gameObject.SetActive(false);
|
|
||||||
}
|
|
||||||
toggleComp.Destroy();
|
|
||||||
|
|
||||||
if (last && order == 1)
|
|
||||||
{
|
|
||||||
// Button in the middle
|
|
||||||
button.transform.localPosition = new Vector3(0, 1.85f - offset, -7);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
button.transform.localPosition = new Vector3(order == 1 ? -1.185f : 1.185f, 1.85f - offset, -7);
|
|
||||||
}
|
|
||||||
|
|
||||||
tmp.text = GetValueText();
|
|
||||||
button.name = Name;
|
|
||||||
button.OnClick = new UnityEngine.UI.Button.ButtonClickedEvent();
|
|
||||||
rollover.OutColor = Tab!.TabAppearance.EnumColor;
|
|
||||||
rollover.OverColor = Tab!.TabAppearance.EnumHoverColor;
|
|
||||||
background.color = Tab!.TabAppearance.EnumColor;
|
|
||||||
|
|
||||||
button.OnClick.AddListener((UnityAction)(() =>
|
|
||||||
{
|
|
||||||
int value = GetValue();
|
|
||||||
value++;
|
|
||||||
if (value >= Values.Length)
|
|
||||||
{
|
|
||||||
value = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
SetValue(value);
|
|
||||||
tmp.text = GetValueText();
|
|
||||||
}));
|
|
||||||
button.OnMouseOver.AddListener((UnityAction)(() =>
|
|
||||||
{
|
|
||||||
if (!Description.IsNullOrWhiteSpace())
|
|
||||||
{
|
|
||||||
tmp.text = Description;
|
|
||||||
}
|
|
||||||
highlight?.gameObject.SetActive(true);
|
|
||||||
}));
|
|
||||||
button.OnMouseOut.AddListener((UnityAction)(() =>
|
|
||||||
{
|
|
||||||
tmp.text = GetValueText();
|
|
||||||
highlight?.gameObject.SetActive(false);
|
|
||||||
}));
|
|
||||||
|
|
||||||
Helpers.DivideSize(button.gameObject, 1.1f);
|
|
||||||
|
|
||||||
order++;
|
|
||||||
if (order > 2 && !last)
|
|
||||||
{
|
|
||||||
offset += 0.5f;
|
|
||||||
order = 1;
|
|
||||||
}
|
|
||||||
if (last)
|
|
||||||
offset += 0.6f;
|
|
||||||
|
|
||||||
return button.gameObject;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
protected override string GetValueText()
|
|
||||||
{
|
|
||||||
return $"<font=\"LiberationSans SDF\" material=\"LiberationSans SDF - Chat Message Masked\">{Name}: <b>{Values[GetValue()]}</font></b>";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,145 +0,0 @@
|
|||||||
using System;
|
|
||||||
using BepInEx.Configuration;
|
|
||||||
using MiraAPI.Utilities;
|
|
||||||
using Reactor.Utilities.Extensions;
|
|
||||||
using TMPro;
|
|
||||||
using UnityEngine;
|
|
||||||
using UnityEngine.Events;
|
|
||||||
using Object = UnityEngine.Object;
|
|
||||||
|
|
||||||
namespace MiraAPI.LocalSettings.SettingTypes;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Local setting class for numbers.
|
|
||||||
/// </summary>
|
|
||||||
public class LocalNumberSetting : LocalSettingBase<float>
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the range of the button.
|
|
||||||
/// </summary>
|
|
||||||
public FloatRange NumberRange { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the increment of the value when button is pressed.
|
|
||||||
/// </summary>
|
|
||||||
public float Increment { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets a format for the text to use to format the number.
|
|
||||||
/// </summary>
|
|
||||||
public string FormatString { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the suffix for the number value.
|
|
||||||
/// </summary>
|
|
||||||
public MiraNumberSuffixes SuffixType { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="LocalNumberSetting"/> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <inheritdoc/>
|
|
||||||
/// <param name="numberRange">The value range.</param>
|
|
||||||
/// <param name="increment">The increment per click.</param>
|
|
||||||
/// <param name="suffixType">The suffix used for formating.</param>
|
|
||||||
/// <param name="formatString">The format string used for formating.</param>
|
|
||||||
public LocalNumberSetting(
|
|
||||||
Type tab,
|
|
||||||
ConfigEntryBase configEntry,
|
|
||||||
string? name = null,
|
|
||||||
string? description = null,
|
|
||||||
FloatRange? numberRange = null,
|
|
||||||
float? increment = null,
|
|
||||||
MiraNumberSuffixes? suffixType = null,
|
|
||||||
string? formatString = null)
|
|
||||||
: base(tab, configEntry, name, description)
|
|
||||||
{
|
|
||||||
SuffixType = suffixType ?? MiraNumberSuffixes.None;
|
|
||||||
NumberRange = numberRange ?? new FloatRange(1, 5);
|
|
||||||
Increment = increment ?? 1;
|
|
||||||
FormatString = formatString ?? "0";
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public override GameObject CreateOption(ToggleButtonBehaviour toggle, SlideBar slider, Transform parent, ref float offset, ref int order, bool last)
|
|
||||||
{
|
|
||||||
var button = Object.Instantiate(toggle, parent).GetComponent<PassiveButton>();
|
|
||||||
var tmp = button.transform.FindChild("Text_TMP").GetComponent<TextMeshPro>();
|
|
||||||
var rollover = button.GetComponent<ButtonRolloverHandler>();
|
|
||||||
tmp.GetComponent<TextTranslatorTMP>().Destroy();
|
|
||||||
button.gameObject.SetActive(true);
|
|
||||||
|
|
||||||
var toggleComp = button.GetComponent<ToggleButtonBehaviour>();
|
|
||||||
var background = toggleComp.Background;
|
|
||||||
var highlight = button.transform.FindChild("ButtonHighlight")?.GetComponent<SpriteRenderer>();
|
|
||||||
if (highlight != null)
|
|
||||||
{
|
|
||||||
highlight.color = Tab!.TabAppearance.NumberHoverColor;
|
|
||||||
highlight.gameObject.SetActive(false);
|
|
||||||
}
|
|
||||||
toggleComp.Destroy();
|
|
||||||
|
|
||||||
if (last && order == 1)
|
|
||||||
{
|
|
||||||
// Button in the middle
|
|
||||||
button.transform.localPosition = new Vector3(0, 1.85f - offset, -7);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
button.transform.localPosition = new Vector3(order == 1 ? -1.185f : 1.185f, 1.85f - offset, -7);
|
|
||||||
}
|
|
||||||
|
|
||||||
tmp.text = GetValueText();
|
|
||||||
button.name = Name;
|
|
||||||
button.OnClick = new UnityEngine.UI.Button.ButtonClickedEvent();
|
|
||||||
rollover.OutColor = Tab!.TabAppearance.NumberColor;
|
|
||||||
rollover.OverColor = Tab!.TabAppearance.NumberHoverColor;
|
|
||||||
background.color = Tab!.TabAppearance.NumberColor;
|
|
||||||
|
|
||||||
button.OnClick.AddListener((UnityAction)(() =>
|
|
||||||
{
|
|
||||||
float value = GetValue();
|
|
||||||
value += Increment;
|
|
||||||
if (value > NumberRange.max)
|
|
||||||
{
|
|
||||||
value = NumberRange.min;
|
|
||||||
}
|
|
||||||
|
|
||||||
SetValue(value);
|
|
||||||
tmp.text = GetValueText();
|
|
||||||
}));
|
|
||||||
button.OnMouseOver.AddListener((UnityAction)(() =>
|
|
||||||
{
|
|
||||||
if (!Description.IsNullOrWhiteSpace())
|
|
||||||
{
|
|
||||||
tmp.text = Description;
|
|
||||||
}
|
|
||||||
highlight?.gameObject.SetActive(true);
|
|
||||||
}));
|
|
||||||
button.OnMouseOut.AddListener((UnityAction)(() =>
|
|
||||||
{
|
|
||||||
tmp.text = GetValueText();
|
|
||||||
highlight?.gameObject.SetActive(false);
|
|
||||||
}));
|
|
||||||
|
|
||||||
Helpers.DivideSize(button.gameObject, 1.1f);
|
|
||||||
|
|
||||||
order++;
|
|
||||||
if (order > 2 && !last)
|
|
||||||
{
|
|
||||||
offset += 0.5f;
|
|
||||||
order = 1;
|
|
||||||
}
|
|
||||||
if (last)
|
|
||||||
offset += 0.6f;
|
|
||||||
|
|
||||||
return button.gameObject;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
protected override string GetValueText()
|
|
||||||
{
|
|
||||||
var value = GetValue();
|
|
||||||
var formated = Helpers.FormatValue(value, SuffixType, FormatString);
|
|
||||||
return $"<font=\"LiberationSans SDF\" material=\"LiberationSans SDF - Chat Message Masked\">{Name}: <b>{formated}</font></b>";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,73 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Linq;
|
|
||||||
using BepInEx.Configuration;
|
|
||||||
using UnityEngine;
|
|
||||||
|
|
||||||
namespace MiraAPI.LocalSettings.SettingTypes;
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public abstract class LocalSettingBase<T> : ILocalSetting
|
|
||||||
{
|
|
||||||
/// <inheritdoc />
|
|
||||||
public string Name { get; }
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public string Description { get; }
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public GameObject? Setting { get; } = null!;
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public ConfigEntryBase ConfigEntry { get; }
|
|
||||||
|
|
||||||
internal LocalSettingsTab? Tab => LocalSettingsManager.Tabs.FirstOrDefault(x => x.Settings.Contains(this));
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="LocalSettingBase{T}"/> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="tab">The tab to create the setting in.</param>
|
|
||||||
/// <param name="configEntry">The config entry.</param>
|
|
||||||
/// <param name="name">The name of the setting.</param>
|
|
||||||
/// <param name="description">The description of the setting.</param>
|
|
||||||
protected LocalSettingBase(Type tab, ConfigEntryBase configEntry, string? name = null, string? description = null)
|
|
||||||
{
|
|
||||||
ConfigEntry = configEntry;
|
|
||||||
Name = name ?? ConfigEntry.Definition.Key;
|
|
||||||
Description = description ?? ConfigEntry.Description.Description;
|
|
||||||
LocalSettingsManager.TypeToTab[tab].Settings.Add(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates an instance of the setting.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>The created setting.</returns>
|
|
||||||
public abstract GameObject CreateOption(ToggleButtonBehaviour toggle, SlideBar slider, Transform parent, ref float offset, ref int order, bool last);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns the formated string to use in the text of the setting.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>The value text.</returns>
|
|
||||||
protected virtual string GetValueText()
|
|
||||||
{
|
|
||||||
return string.Empty;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the value of the config entry, casted to the setting type.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>The value.</returns>
|
|
||||||
public virtual T GetValue()
|
|
||||||
{
|
|
||||||
return (T)ConfigEntry.BoxedValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Sets the value of the config entry.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="value">The value to set to.</param>
|
|
||||||
public virtual void SetValue(T value)
|
|
||||||
{
|
|
||||||
ConfigEntry.BoxedValue = value;
|
|
||||||
Tab?.OnOptionChanged(ConfigEntry);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,120 +0,0 @@
|
|||||||
using System;
|
|
||||||
using BepInEx.Configuration;
|
|
||||||
using MiraAPI.Utilities;
|
|
||||||
using Reactor.Utilities.Extensions;
|
|
||||||
using TMPro;
|
|
||||||
using UnityEngine;
|
|
||||||
using UnityEngine.Events;
|
|
||||||
using Object = UnityEngine.Object;
|
|
||||||
|
|
||||||
namespace MiraAPI.LocalSettings.SettingTypes;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Local setting class for sliders.
|
|
||||||
/// </summary>
|
|
||||||
public class LocalSliderSetting : LocalSettingBase<float>
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the range of the slider.
|
|
||||||
/// </summary>
|
|
||||||
public FloatRange SliderRange { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets a value indicating whether the value should be displayed next to name.
|
|
||||||
/// </summary>
|
|
||||||
public bool DisplayValue { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets a format for the text to use to format the number.
|
|
||||||
/// </summary>
|
|
||||||
public string FormatString { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets a value indicating whether the value should be rounded.
|
|
||||||
/// </summary>
|
|
||||||
public bool RoundValue { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the suffix for the number value.
|
|
||||||
/// </summary>
|
|
||||||
public MiraNumberSuffixes SuffixType { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="LocalSliderSetting"/> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <inheritdoc/>
|
|
||||||
/// <param name="sliderRange">The value range.</param>
|
|
||||||
/// <param name="suffixType">The suffix used for formating.</param>
|
|
||||||
/// <param name="formatString">The format string used for formating.</param>
|
|
||||||
/// <param name="roundValue">Should the value be rounded.</param>
|
|
||||||
public LocalSliderSetting(
|
|
||||||
Type tab,
|
|
||||||
ConfigEntryBase configEntry,
|
|
||||||
string? name = null,
|
|
||||||
string? description = null,
|
|
||||||
FloatRange? sliderRange = null,
|
|
||||||
bool displayValue = false,
|
|
||||||
MiraNumberSuffixes? suffixType = null,
|
|
||||||
string? formatString = null,
|
|
||||||
bool roundValue = false)
|
|
||||||
: base(tab, configEntry, name, description)
|
|
||||||
{
|
|
||||||
SliderRange = sliderRange ?? new FloatRange(0, 100);
|
|
||||||
DisplayValue = displayValue;
|
|
||||||
SuffixType = suffixType ?? MiraNumberSuffixes.None;
|
|
||||||
FormatString = formatString ?? "0.0";
|
|
||||||
RoundValue = roundValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public override GameObject CreateOption(ToggleButtonBehaviour toggle, SlideBar slider, Transform parent, ref float offset, ref int order, bool last)
|
|
||||||
{
|
|
||||||
var newSlider = Object.Instantiate(slider, parent).GetComponent<SlideBar>();
|
|
||||||
var rollover = newSlider.GetComponent<ButtonRolloverHandler>();
|
|
||||||
newSlider.Title = newSlider.transform.FindChild("Text_TMP").GetComponent<TextMeshPro>(); // Why the hell slider has a title property that is not even assigned???
|
|
||||||
newSlider.Title.GetComponent<TextTranslatorTMP>().Destroy();
|
|
||||||
newSlider.gameObject.SetActive(true);
|
|
||||||
newSlider.Bar.color = Tab!.TabAppearance.SliderColor;
|
|
||||||
|
|
||||||
if (order == 2)
|
|
||||||
offset += 0.5f;
|
|
||||||
|
|
||||||
newSlider.Bar.transform.localPosition = new Vector3(2.85f, 0, 0);
|
|
||||||
newSlider.transform.localPosition = new Vector3(-2.12f, 1.85f - offset, -7);
|
|
||||||
newSlider.name = Name;
|
|
||||||
newSlider.Range = new FloatRange(-1.5f, 1.5f);
|
|
||||||
newSlider.SetValue(Mathf.InverseLerp(SliderRange.min, SliderRange.max, GetValue()));
|
|
||||||
rollover.OutColor = Tab!.TabAppearance.SliderColor;
|
|
||||||
rollover.OverColor = Tab!.TabAppearance.SliderHoverColor;
|
|
||||||
newSlider.Title.transform.localPosition = new Vector3(0.5f, 0, -1f);
|
|
||||||
newSlider.Title.horizontalAlignment = DisplayValue ? HorizontalAlignmentOptions.Left : HorizontalAlignmentOptions.Center;
|
|
||||||
newSlider.Title.text = GetValueText();
|
|
||||||
|
|
||||||
newSlider.OnValueChange.AddListener((UnityAction)(() =>
|
|
||||||
{
|
|
||||||
SetValue(RoundValue
|
|
||||||
? Mathf.Round(Mathf.Lerp(SliderRange.min, SliderRange.max, newSlider.Value))
|
|
||||||
: Mathf.Lerp(SliderRange.min, SliderRange.max, newSlider.Value));
|
|
||||||
|
|
||||||
newSlider.Title.text = GetValueText();
|
|
||||||
}));
|
|
||||||
|
|
||||||
order = 1;
|
|
||||||
offset += 0.5f;
|
|
||||||
return newSlider.gameObject;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
protected override string GetValueText()
|
|
||||||
{
|
|
||||||
if (DisplayValue)
|
|
||||||
{
|
|
||||||
var value = GetValue();
|
|
||||||
var formated = Helpers.FormatValue(value, SuffixType, FormatString);
|
|
||||||
var maxFormated = Helpers.FormatValue(SliderRange.max, SuffixType, FormatString);
|
|
||||||
return $"<font=\"LiberationSans SDF\" material=\"LiberationSans SDF - Chat Message Masked\">{Name}: <b>{formated} / {maxFormated}</font></b>";
|
|
||||||
}
|
|
||||||
|
|
||||||
return $"<font=\"LiberationSans SDF\" material=\"LiberationSans SDF - Chat Message Masked\">{Name}</font></b>";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,88 +0,0 @@
|
|||||||
using System;
|
|
||||||
using BepInEx.Configuration;
|
|
||||||
using MiraAPI.Utilities;
|
|
||||||
using Reactor.Localization.Utilities;
|
|
||||||
using TMPro;
|
|
||||||
using UnityEngine;
|
|
||||||
using UnityEngine.Events;
|
|
||||||
using Object = UnityEngine.Object;
|
|
||||||
|
|
||||||
namespace MiraAPI.LocalSettings.SettingTypes;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Local setting class for toggles.
|
|
||||||
/// </summary>
|
|
||||||
public class LocalToggleSetting : LocalSettingBase<bool>
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="LocalToggleSetting"/> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public LocalToggleSetting(
|
|
||||||
Type tab,
|
|
||||||
ConfigEntryBase configEntry,
|
|
||||||
string? name = null,
|
|
||||||
string? description = null
|
|
||||||
) : base(tab, configEntry, name, description)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public override GameObject CreateOption(ToggleButtonBehaviour toggle, SlideBar slider, Transform parent, ref float offset, ref int order, bool last)
|
|
||||||
{
|
|
||||||
var toggleObject = Object.Instantiate(toggle, parent).GetComponent<ToggleButtonBehaviour>();
|
|
||||||
var tmp = toggleObject.transform.FindChild("Text_TMP").GetComponent<TextMeshPro>();
|
|
||||||
var passiveButton = toggleObject.GetComponent<PassiveButton>();
|
|
||||||
var rollover = toggleObject.GetComponent<ButtonRolloverHandler>();
|
|
||||||
toggleObject.gameObject.SetActive(true);
|
|
||||||
|
|
||||||
if (last && order == 1)
|
|
||||||
{
|
|
||||||
// Toggle in the middle
|
|
||||||
toggleObject.transform.localPosition = new Vector3(0, 1.85f - offset, -7);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
toggleObject.transform.localPosition = new Vector3(order == 1 ? -1.185f : 1.185f, 1.85f - offset, -7);
|
|
||||||
}
|
|
||||||
|
|
||||||
toggleObject.BaseText = CustomStringName.CreateAndRegister(Name);
|
|
||||||
toggleObject.UpdateText(GetValue());
|
|
||||||
toggleObject.name = Name;
|
|
||||||
toggleObject.Background.color = GetValue() ? Tab!.TabAppearance.ToggleActiveColor : Tab!.TabAppearance.ToggleInactiveColor;
|
|
||||||
passiveButton.OnClick = new UnityEngine.UI.Button.ButtonClickedEvent();
|
|
||||||
rollover.OverColor = Tab!.TabAppearance.ToggleHoverColor;
|
|
||||||
|
|
||||||
passiveButton.OnClick.AddListener((UnityAction)(() =>
|
|
||||||
{
|
|
||||||
SetValue(!GetValue());
|
|
||||||
toggleObject.UpdateText(GetValue());
|
|
||||||
toggleObject.Background.color = GetValue() ? Tab!.TabAppearance.ToggleActiveColor : Tab!.TabAppearance.ToggleInactiveColor;
|
|
||||||
}));
|
|
||||||
passiveButton.OnMouseOver.AddListener((UnityAction)(() =>
|
|
||||||
{
|
|
||||||
if (!Description.IsNullOrWhiteSpace())
|
|
||||||
{
|
|
||||||
tmp.text = Description;
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
passiveButton.OnMouseOut.AddListener((UnityAction)(() =>
|
|
||||||
{
|
|
||||||
toggleObject.UpdateText(GetValue());
|
|
||||||
toggleObject.Background.color = GetValue() ? Tab!.TabAppearance.ToggleActiveColor : Tab!.TabAppearance.ToggleInactiveColor;
|
|
||||||
}));
|
|
||||||
|
|
||||||
Helpers.DivideSize(toggleObject.gameObject, 1.1f);
|
|
||||||
|
|
||||||
order++;
|
|
||||||
if (order > 2 && !last)
|
|
||||||
{
|
|
||||||
offset += 0.5f;
|
|
||||||
order = 1;
|
|
||||||
}
|
|
||||||
if (last)
|
|
||||||
offset += 0.6f;
|
|
||||||
|
|
||||||
return toggleObject.gameObject;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,52 +0,0 @@
|
|||||||
using BepInEx.Configuration;
|
|
||||||
using MiraAPI.LocalSettings;
|
|
||||||
using MiraAPI.LocalSettings.Attributes;
|
|
||||||
using MiraAPI.Utilities;
|
|
||||||
using MiraAPI.Utilities.Assets;
|
|
||||||
|
|
||||||
namespace MiraAPI;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Mira API Config File Handler
|
|
||||||
/// </summary>
|
|
||||||
public class MiraApiSettings(ConfigFile config) : LocalSettingsTab(config)
|
|
||||||
{
|
|
||||||
/// <inheritdoc />
|
|
||||||
public override string TabName => "Mira API";
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public override LocalSettingTabAppearance TabAppearance => new()
|
|
||||||
{
|
|
||||||
TabButtonHoverColor = MiraApiPlugin.MiraColor,
|
|
||||||
TabIcon = MiraAssets.SettingsIcon,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets whether the modifiers hud should be on the left side of the screen (under roles/task tab). Recommended for streamers.
|
|
||||||
/// </summary>
|
|
||||||
[LocalToggleSetting]
|
|
||||||
public ConfigEntry<bool> ModifiersHudLeftSide { get; private set; } = config.Bind("Displays", "Show Modifiers HUD on Left Side", false);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets whether vents and their connections appear on the map.
|
|
||||||
/// </summary>
|
|
||||||
[LocalToggleSetting]
|
|
||||||
public ConfigEntry<bool> ShowVentsOnMap { get; private set; } = config.Bind("Displays", "Show Vent Layout on Map", true);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets whether cooldowns for buttons below 10 seconds appear with decimals.
|
|
||||||
/// </summary>
|
|
||||||
[LocalToggleSetting]
|
|
||||||
public ConfigEntry<bool> PreciseCooldowns { get; private set; } = config.Bind("Buttons", "Precise Button Cooldowns Under 10s", false);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the size of ability buttons in-game.
|
|
||||||
/// </summary>
|
|
||||||
[LocalSliderSetting(min: 0.5f, max: 1.5f, displayValue: true, formatString: "0.00", suffixType: MiraNumberSuffixes.Multiplier)]
|
|
||||||
public ConfigEntry<float> ButtonUiScale { get; private set; } = config.Bind("Buttons", "Button Scale Factor", 0.8f);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets whether to show keybinds in the control mapper.
|
|
||||||
/// </summary>
|
|
||||||
public ConfigEntry<bool> ShowKeybinds { get; private set; } = config.Bind("Keybinds", "Show Keybinds in Control Mapper", true);
|
|
||||||
}
|
|
||||||
@@ -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.InternalModifiers.Exists(y => y.TypeId == TypeId)
|
x => x.Modifiers.Exists(y => y.TypeId == TypeId)
|
||||||
) ?? throw new InvalidOperationException("Modifier is not registered.");
|
) ?? throw new InvalidOperationException("Modifier is not registered.");
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -64,11 +64,6 @@ public abstract class BaseModifier : IOptionable
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual bool ShowInFreeplay => false;
|
public virtual bool ShowInFreeplay => false;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets a value indicating the color that should be used for the modifier within freeplay.
|
|
||||||
/// </summary>
|
|
||||||
public virtual Color FreeplayFileColor => Color.gray;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a value indicating whether the modifier is unique. If true, the player can only have one instance of this modifier.
|
/// Gets a value indicating whether the modifier is unique. If true, the player can only have one instance of this modifier.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -4,10 +4,8 @@ using System.Collections.Immutable;
|
|||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Il2CppInterop.Runtime.Attributes;
|
using Il2CppInterop.Runtime.Attributes;
|
||||||
using MiraAPI.LocalSettings;
|
|
||||||
using MiraAPI.Modifiers.ModifierDisplay;
|
using MiraAPI.Modifiers.ModifierDisplay;
|
||||||
using MiraAPI.Modifiers.Types;
|
using MiraAPI.Modifiers.Types;
|
||||||
using MiraAPI.Patches.Roles;
|
|
||||||
using Reactor.Utilities;
|
using Reactor.Utilities;
|
||||||
using Reactor.Utilities.Attributes;
|
using Reactor.Utilities.Attributes;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
@@ -128,18 +126,7 @@ public class ModifierComponent(IntPtr cppPtr) : MonoBehaviour(cppPtr)
|
|||||||
|
|
||||||
if (_player.AmOwner && ModifierDisplay && HudManager.InstanceExists)
|
if (_player.AmOwner && ModifierDisplay && HudManager.InstanceExists)
|
||||||
{
|
{
|
||||||
var taskPanelOpen = HudManager.Instance.TaskPanel.open;
|
ModifierDisplay!.gameObject.SetActive(MeetingHud.Instance || HudManager.Instance.TaskPanel.isActiveAndEnabled);
|
||||||
var roleTabOpen = HudManagerPatches.RoleTab != null && HudManagerPatches.RoleTab.open;
|
|
||||||
var leftSideHud = LocalSettingsTabSingleton<MiraApiSettings>.Instance.ModifiersHudLeftSide.Value;
|
|
||||||
|
|
||||||
if (leftSideHud && (taskPanelOpen || roleTabOpen))
|
|
||||||
{
|
|
||||||
ModifierDisplay!.gameObject.SetActive(false);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ModifierDisplay!.gameObject.SetActive(MeetingHud.Instance || HudManager.Instance.TaskPanel.isActiveAndEnabled);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ using System.Collections.ObjectModel;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using HarmonyLib;
|
using HarmonyLib;
|
||||||
using Il2CppInterop.Runtime.Attributes;
|
using Il2CppInterop.Runtime.Attributes;
|
||||||
using MiraAPI.LocalSettings;
|
|
||||||
using MiraAPI.Utilities.Assets;
|
using MiraAPI.Utilities.Assets;
|
||||||
using Reactor.Utilities.Attributes;
|
using Reactor.Utilities.Attributes;
|
||||||
using Reactor.Utilities.Extensions;
|
using Reactor.Utilities.Extensions;
|
||||||
@@ -95,16 +94,6 @@ public class ModifierDisplayComponent(nint cppPtr) : MonoBehaviour(cppPtr)
|
|||||||
|
|
||||||
IsOpen = false;
|
IsOpen = false;
|
||||||
_children.gameObject.SetActive(false);
|
_children.gameObject.SetActive(false);
|
||||||
|
|
||||||
if (LocalSettingsTabSingleton<MiraApiSettings>.Instance.ModifiersHudLeftSide.Value)
|
|
||||||
{
|
|
||||||
var aspect = GetComponent<AspectPosition>();
|
|
||||||
_toggleButton.transform.localPosition = new Vector3(-1f, 2.7f, 0f);
|
|
||||||
_children.transform.localPosition = new Vector3(-0.2f, -0.05f, 0f);
|
|
||||||
aspect.Alignment = AspectPosition.EdgeAlignments.LeftTop;
|
|
||||||
aspect.DistanceFromEdge = new Vector3(1.8f, 2.55f, -20f);
|
|
||||||
aspect.AdjustPosition();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -120,16 +109,7 @@ public class ModifierDisplayComponent(nint cppPtr) : MonoBehaviour(cppPtr)
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public void ToggleTab()
|
public void ToggleTab()
|
||||||
{
|
{
|
||||||
SetOpened(!IsOpen);
|
IsOpen = !IsOpen;
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Use this to set the visibility of the modifiers tab.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="val">Whether it should be visible or not.</param>
|
|
||||||
public void SetOpened(bool val)
|
|
||||||
{
|
|
||||||
IsOpen = val;
|
|
||||||
_children.gameObject.SetActive(IsOpen);
|
_children.gameObject.SetActive(IsOpen);
|
||||||
RefreshModifiers();
|
RefreshModifiers();
|
||||||
}
|
}
|
||||||
@@ -138,6 +118,7 @@ public class ModifierDisplayComponent(nint cppPtr) : MonoBehaviour(cppPtr)
|
|||||||
{
|
{
|
||||||
_modifiers.Remove(component.Modifier!);
|
_modifiers.Remove(component.Modifier!);
|
||||||
component.gameObject.DestroyImmediate();
|
component.gameObject.DestroyImmediate();
|
||||||
|
|
||||||
RefreshModifiers();
|
RefreshModifiers();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -213,7 +194,13 @@ public class ModifierDisplayComponent(nint cppPtr) : MonoBehaviour(cppPtr)
|
|||||||
|
|
||||||
_toggleBtnText.text = $"Modifiers ({filteredModifiers.Count})";
|
_toggleBtnText.text = $"Modifiers ({filteredModifiers.Count})";
|
||||||
|
|
||||||
_toggleButton.gameObject.SetActive(filteredModifiers.Count != 0);
|
if (filteredModifiers.Count == 0)
|
||||||
|
{
|
||||||
|
_toggleButton.gameObject.SetActive(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_toggleButton.gameObject.SetActive(true);
|
||||||
|
|
||||||
foreach (var mod in modifiersToAdd)
|
foreach (var mod in modifiersToAdd)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ public static class ModifierExtensions
|
|||||||
_ = ModifierManager.GetModifierType(typeId) ?? throw new InvalidOperationException(
|
_ = ModifierManager.GetModifierType(typeId) ?? throw new InvalidOperationException(
|
||||||
$"Modifier with ID {typeId} is not registered.");
|
$"Modifier with ID {typeId} is not registered.");
|
||||||
|
|
||||||
Rpc<AddModifierRpc>.Instance.Send(target, new ModifierData(typeId, Guid.NewGuid(), args), true);
|
Rpc<AddModifierRpc>.Instance.Send(target, new ModifierData(typeId, Guid.NewGuid(), args));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ 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;
|
||||||
@@ -17,18 +16,6 @@ namespace MiraAPI.Modifiers;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static class ModifierManager
|
public static class ModifierManager
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets a value indicating whether modifiers should be assigned to players.
|
|
||||||
/// </summary>
|
|
||||||
public static bool MiraAssignsModifiers { get; set; } = true;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the list of all registered modifiers.
|
|
||||||
/// </summary>
|
|
||||||
public static IReadOnlyList<BaseModifier> Modifiers { get; internal set; } = [];
|
|
||||||
|
|
||||||
internal static List<BaseModifier> InternalModifiers { get; } = [];
|
|
||||||
|
|
||||||
private static readonly Dictionary<uint, Type> IdToTypeModifierMap = [];
|
private static readonly Dictionary<uint, Type> IdToTypeModifierMap = [];
|
||||||
private static readonly Dictionary<Type, uint> TypeToIdModifierMap = [];
|
private static readonly Dictionary<Type, uint> TypeToIdModifierMap = [];
|
||||||
private static readonly Dictionary<int, List<uint>> PrioritiesToIdsMap = [];
|
private static readonly Dictionary<int, List<uint>> PrioritiesToIdsMap = [];
|
||||||
@@ -87,8 +74,7 @@ public static class ModifierManager
|
|||||||
modifier = (BaseModifier)FormatterServices.GetUninitializedObject(modifierType);
|
modifier = (BaseModifier)FormatterServices.GetUninitializedObject(modifierType);
|
||||||
}
|
}
|
||||||
|
|
||||||
info.InternalModifiers.Add(modifier);
|
info.Modifiers.Add(modifier);
|
||||||
InternalModifiers.Add(modifier);
|
|
||||||
|
|
||||||
if (modifier is not GameModifier gameModifier)
|
if (modifier is not GameModifier gameModifier)
|
||||||
{
|
{
|
||||||
@@ -112,11 +98,7 @@ public static class ModifierManager
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
internal static void AssignModifiers(List<PlayerControl> plrs)
|
||||||
/// Assigns modifiers to players. ONLY CALL THIS METHOD IF YOU KNOW WHAT YOU ARE DOING.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="plrs">The players to assign modifiers to.</param>
|
|
||||||
public static void AssignModifiers(List<PlayerControl> plrs)
|
|
||||||
{
|
{
|
||||||
var rand = new Random();
|
var rand = new Random();
|
||||||
|
|
||||||
@@ -126,7 +108,6 @@ public static class ModifierManager
|
|||||||
.Select(x => Activator.CreateInstance(x.Value) as GameModifier)
|
.Select(x => Activator.CreateInstance(x.Value) as GameModifier)
|
||||||
.OfType<GameModifier>()
|
.OfType<GameModifier>()
|
||||||
.Where(x => x.GetAmountPerGame() > 0 && x.GetAssignmentChance() > 0)
|
.Where(x => x.GetAmountPerGame() > 0 && x.GetAssignmentChance() > 0)
|
||||||
.Shuffle()
|
|
||||||
.OrderByDescending(x => x.Priority())
|
.OrderByDescending(x => x.Priority())
|
||||||
.ToArray();
|
.ToArray();
|
||||||
|
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ public static class CustomMurderRpc
|
|||||||
/// <param name="teleportMurderer">Should the killer be snapped to the dead player.</param>
|
/// <param name="teleportMurderer">Should the killer be snapped to the dead player.</param>
|
||||||
/// <param name="showKillAnim">Should the kill animation be shown.</param>
|
/// <param name="showKillAnim">Should the kill animation be shown.</param>
|
||||||
/// <param name="playKillSound">Should the kill sound be played.</param>
|
/// <param name="playKillSound">Should the kill sound be played.</param>
|
||||||
[MethodRpc((uint)MiraRpc.CustomMurder, LocalHandling = RpcLocalHandling.Before)]
|
[MethodRpc((uint)MiraRpc.CustomMurder, LocalHandling = RpcLocalHandling.Before, SendImmediately = true)]
|
||||||
public static void RpcCustomMurder(
|
public static void RpcCustomMurder(
|
||||||
this PlayerControl source,
|
this PlayerControl source,
|
||||||
PlayerControl target,
|
PlayerControl target,
|
||||||
|
|||||||
@@ -1,35 +0,0 @@
|
|||||||
using HarmonyLib;
|
|
||||||
using UnityEngine;
|
|
||||||
|
|
||||||
namespace MiraAPI.Patches;
|
|
||||||
|
|
||||||
#pragma warning disable SA1629
|
|
||||||
/// <summary>
|
|
||||||
/// Allows players to paste text into chat.
|
|
||||||
/// Source: https://github.com/CallOfCreator/NewMod/blob/main/NewMod/Patches/ClipboardPatch.cs
|
|
||||||
/// </summary>
|
|
||||||
#pragma warning restore SA1629
|
|
||||||
[HarmonyPatch(typeof(ChatController), nameof(ChatController.Update))]
|
|
||||||
public static class ChatControllerPatch
|
|
||||||
{
|
|
||||||
public static void Prefix(ChatController __instance)
|
|
||||||
{
|
|
||||||
if (!HudManager.Instance.Chat.IsOpenOrOpening) return;
|
|
||||||
|
|
||||||
var ctrlPressed = Input.GetKey(KeyCode.LeftControl) || Input.GetKey(KeyCode.RightControl);
|
|
||||||
|
|
||||||
if (!ctrlPressed || !Input.GetKeyDown(KeyCode.V)) return;
|
|
||||||
|
|
||||||
var clipboard = GUIUtility.systemCopyBuffer;
|
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(clipboard)) return;
|
|
||||||
clipboard = clipboard.Replace("<", string.Empty)
|
|
||||||
.Replace(">", string.Empty)
|
|
||||||
.Replace("\r", string.Empty);
|
|
||||||
|
|
||||||
if (!Input.GetKey(KeyCode.LeftShift) && !Input.GetKey(KeyCode.RightShift))
|
|
||||||
clipboard = clipboard.Replace("\n", string.Empty);
|
|
||||||
|
|
||||||
__instance.freeChatField.textArea.SetText(__instance.freeChatField.textArea.text + clipboard);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -12,16 +12,14 @@ public static class CanUsePatches
|
|||||||
public static IEnumerable<MethodBase> TargetMethods()
|
public static IEnumerable<MethodBase> TargetMethods()
|
||||||
{
|
{
|
||||||
yield return AccessTools.Method(typeof(Console), nameof(Console.CanUse));
|
yield return AccessTools.Method(typeof(Console), nameof(Console.CanUse));
|
||||||
yield return AccessTools.Method(typeof(DeconControl), nameof(DeconControl.CanUse));
|
|
||||||
yield return AccessTools.Method(typeof(DoorConsole), nameof(DoorConsole.CanUse));
|
|
||||||
yield return AccessTools.Method(typeof(Ladder), nameof(Ladder.CanUse));
|
|
||||||
yield return AccessTools.Method(typeof(MapConsole), nameof(MapConsole.CanUse));
|
yield return AccessTools.Method(typeof(MapConsole), nameof(MapConsole.CanUse));
|
||||||
yield return AccessTools.Method(typeof(OpenDoorConsole), nameof(OpenDoorConsole.CanUse));
|
|
||||||
yield return AccessTools.Method(typeof(OptionsConsole), nameof(OptionsConsole.CanUse));
|
|
||||||
yield return AccessTools.Method(typeof(PlatformConsole), nameof(PlatformConsole.CanUse));
|
|
||||||
yield return AccessTools.Method(typeof(SystemConsole), nameof(SystemConsole.CanUse));
|
yield return AccessTools.Method(typeof(SystemConsole), nameof(SystemConsole.CanUse));
|
||||||
|
yield return AccessTools.Method(typeof(Ladder), nameof(Ladder.CanUse));
|
||||||
|
yield return AccessTools.Method(typeof(PlatformConsole), nameof(PlatformConsole.CanUse));
|
||||||
|
yield return AccessTools.Method(typeof(OpenDoorConsole), nameof(OpenDoorConsole.CanUse));
|
||||||
|
yield return AccessTools.Method(typeof(DoorConsole), nameof(DoorConsole.CanUse));
|
||||||
|
yield return AccessTools.Method(typeof(OptionsConsole), nameof(OptionsConsole.CanUse));
|
||||||
yield return AccessTools.Method(typeof(ZiplineConsole), nameof(ZiplineConsole.CanUse));
|
yield return AccessTools.Method(typeof(ZiplineConsole), nameof(ZiplineConsole.CanUse));
|
||||||
// vent is not necessary as it has its own patch
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[HarmonyPriority(Priority.Last)]
|
[HarmonyPriority(Priority.Last)]
|
||||||
|
|||||||
@@ -5,44 +5,29 @@ using MiraAPI.GameEnd;
|
|||||||
|
|
||||||
namespace MiraAPI.Patches.Events;
|
namespace MiraAPI.Patches.Events;
|
||||||
|
|
||||||
|
[HarmonyPatch(typeof(EndGameManager), nameof(EndGameManager.SetEverythingUp))]
|
||||||
internal static class EndGamePatches
|
internal static class EndGamePatches
|
||||||
{
|
{
|
||||||
[HarmonyPatch(typeof(GameManager), nameof(GameManager.RpcEndGame))]
|
public static bool Prefix(EndGameManager __instance)
|
||||||
public static class GameManagerPatches
|
|
||||||
{
|
{
|
||||||
public static bool Prefix(GameOverReason endReason)
|
if (CustomGameOver.Instance is not { } gameOver)
|
||||||
{
|
{
|
||||||
var @event = new BeforeGameEndEvent(endReason);
|
return true;
|
||||||
MiraEventManager.InvokeEvent(@event);
|
|
||||||
|
|
||||||
return !@event.IsCancelled;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var result = gameOver.BeforeEndGameSetup(__instance);
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
[HarmonyPatch(typeof(EndGameManager), nameof(EndGameManager.SetEverythingUp))]
|
public static void Postfix(EndGameManager __instance)
|
||||||
public static class EndGameManagerPatches
|
|
||||||
{
|
{
|
||||||
public static bool Prefix(EndGameManager __instance)
|
if (CustomGameOver.Instance is { } gameOver)
|
||||||
{
|
{
|
||||||
if (CustomGameOver.Instance is not { } gameOver)
|
gameOver.AfterEndGameSetup(__instance);
|
||||||
{
|
CustomGameOver.Instance = null;
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
var result = gameOver.BeforeEndGameSetup(__instance);
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Postfix(EndGameManager __instance)
|
var @event = new GameEndEvent(__instance);
|
||||||
{
|
MiraEventManager.InvokeEvent(@event);
|
||||||
if (CustomGameOver.Instance is { } gameOver)
|
|
||||||
{
|
|
||||||
gameOver.AfterEndGameSetup(__instance);
|
|
||||||
CustomGameOver.Instance = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
var @event = new GameEndEvent(__instance);
|
|
||||||
MiraEventManager.InvokeEvent(@event);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
using HarmonyLib;
|
|
||||||
using MiraAPI.Events;
|
|
||||||
using MiraAPI.Events.Vanilla.Gameplay;
|
|
||||||
|
|
||||||
namespace MiraAPI.Patches.Events;
|
|
||||||
|
|
||||||
[HarmonyPatch(typeof(TutorialManager._RunTutorial_d__3), nameof(TutorialManager._RunTutorial_d__3.MoveNext))]
|
|
||||||
public static class FreeplayRoundStartPatch
|
|
||||||
{
|
|
||||||
public static void Postfix(TutorialManager._RunTutorial_d__3 __instance, ref bool __result)
|
|
||||||
{
|
|
||||||
if (!__result)
|
|
||||||
{
|
|
||||||
MiraEventManager.InvokeEvent(new RoundStartEvent(true));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -14,17 +14,13 @@ public static class KillAnimationPatches
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Used to trigger the <see cref="AfterMurderEvent"/>.
|
/// Used to trigger the <see cref="AfterMurderEvent"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <param name="source">The killer.</param>
|
||||||
|
/// <param name="target">The target.</param>
|
||||||
[HarmonyPostfix]
|
[HarmonyPostfix]
|
||||||
[HarmonyPatch(typeof(KillAnimation._CoPerformKill_d__2), nameof(KillAnimation._CoPerformKill_d__2.MoveNext))]
|
[HarmonyPatch(typeof(KillAnimation), nameof(KillAnimation.CoPerformKill))]
|
||||||
public static void KillAnimPostfix(KillAnimation._CoPerformKill_d__2 __instance)
|
public static void KillAnimPostfix(PlayerControl source, PlayerControl target)
|
||||||
{
|
{
|
||||||
// Checking if state is -1 to wait for the end of coroutine.
|
var afterMurderEvent = new AfterMurderEvent(source, target, Helpers.GetBodyById(target.PlayerId));
|
||||||
if (__instance.__1__state != -1)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var afterMurderEvent = new AfterMurderEvent(__instance.source, __instance.target, Helpers.GetBodyById(__instance.target.PlayerId));
|
|
||||||
MiraEventManager.InvokeEvent(afterMurderEvent);
|
MiraEventManager.InvokeEvent(afterMurderEvent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,52 +1,21 @@
|
|||||||
using AmongUs.InnerNet.GameDataMessages;
|
using HarmonyLib;
|
||||||
using HarmonyLib;
|
|
||||||
using InnerNet;
|
|
||||||
using MiraAPI.Events;
|
using MiraAPI.Events;
|
||||||
using MiraAPI.Events.Vanilla.Meeting;
|
using MiraAPI.Events.Vanilla.Meeting;
|
||||||
using MiraAPI.Utilities;
|
using MiraAPI.Utilities;
|
||||||
using Reactor.Utilities;
|
|
||||||
|
|
||||||
namespace MiraAPI.Patches.Events;
|
namespace MiraAPI.Patches.Events;
|
||||||
|
|
||||||
[HarmonyPatch]
|
[HarmonyPatch]
|
||||||
public static class ReportBodyEventPatch
|
public static class ReportBodyEventPatch
|
||||||
{
|
{
|
||||||
private static bool ReportBodyEventHook(PlayerControl source, NetworkedPlayerInfo? target)
|
[HarmonyPrefix]
|
||||||
|
[HarmonyPatch(typeof(PlayerControl), nameof(PlayerControl.CmdReportDeadBody))]
|
||||||
|
public static bool PlayerControlCmdReportDeadBodyPrefix(PlayerControl __instance, NetworkedPlayerInfo? target)
|
||||||
{
|
{
|
||||||
var body = target != null ? Helpers.GetBodyById(target.PlayerId) : null;
|
var body = target != null ? Helpers.GetBodyById(target.PlayerId) : null;
|
||||||
|
|
||||||
var @event = new ReportBodyEvent(source, target, body);
|
var @event = new ReportBodyEvent(__instance, target, body);
|
||||||
MiraEventManager.InvokeEvent(@event);
|
MiraEventManager.InvokeEvent(@event);
|
||||||
return !@event.IsCancelled;
|
return !@event.IsCancelled;
|
||||||
}
|
}
|
||||||
|
|
||||||
[HarmonyPrefix]
|
|
||||||
[HarmonyPatch(typeof(PlayerControl), nameof(PlayerControl.ReportDeadBody))]
|
|
||||||
public static bool PlayerControlCmdReportDeadBodyPrefix(PlayerControl __instance, NetworkedPlayerInfo? target)
|
|
||||||
{
|
|
||||||
return ReportBodyEventHook(__instance, target);
|
|
||||||
}
|
|
||||||
|
|
||||||
[HarmonyPrefix]
|
|
||||||
[HarmonyPatch(typeof(InnerNetClient), nameof(InnerNetClient.LateBroadcastReliableMessage))]
|
|
||||||
public static bool LateBroadcastReliableMessagePrefix(IGameDataMessage rpcMessage)
|
|
||||||
{
|
|
||||||
var reportBodyMessage = rpcMessage.TryCast<RpcReportDeadBodyMessage>();
|
|
||||||
|
|
||||||
if (reportBodyMessage == null)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
var source = AmongUsClient.Instance.FindObjectByNetId<PlayerControl>(reportBodyMessage.rpcObjectNetId);
|
|
||||||
if (source == null)
|
|
||||||
{
|
|
||||||
Logger<MiraApiPlugin>.Error("Failed to find source player for RpcReportDeadBodyMessage with NetId: " + reportBodyMessage.rpcObjectNetId);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
var target = GameData.Instance.GetPlayerById(reportBodyMessage.targetPlayerId);
|
|
||||||
|
|
||||||
return ReportBodyEventHook(source, target);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -9,12 +9,7 @@ internal static class SpawnInMinigamePatch
|
|||||||
{
|
{
|
||||||
public static void Postfix()
|
public static void Postfix()
|
||||||
{
|
{
|
||||||
var @event = new BeforeRoundStartEvent(false);
|
var @event = new RoundStartEvent(false);
|
||||||
MiraEventManager.InvokeEvent(@event);
|
MiraEventManager.InvokeEvent(@event);
|
||||||
|
|
||||||
if (@event.IsCancelled) return;
|
|
||||||
|
|
||||||
var @event2 = new RoundStartEvent(false);
|
|
||||||
MiraEventManager.InvokeEvent(@event2);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -25,12 +25,7 @@ internal static class SubmergedSpawnGamePatch
|
|||||||
|
|
||||||
public static void Postfix()
|
public static void Postfix()
|
||||||
{
|
{
|
||||||
var @event = new BeforeRoundStartEvent(false);
|
var @event = new RoundStartEvent(false);
|
||||||
MiraEventManager.InvokeEvent(@event);
|
MiraEventManager.InvokeEvent(@event);
|
||||||
|
|
||||||
if (@event.IsCancelled) return;
|
|
||||||
|
|
||||||
var @event2 = new RoundStartEvent(false);
|
|
||||||
MiraEventManager.InvokeEvent(@event2);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -23,10 +23,10 @@ public static class VentEventPatches
|
|||||||
|
|
||||||
[HarmonyPrefix]
|
[HarmonyPrefix]
|
||||||
[HarmonyPatch(typeof(PlayerPhysics), nameof(PlayerPhysics.RpcEnterVent))]
|
[HarmonyPatch(typeof(PlayerPhysics), nameof(PlayerPhysics.RpcEnterVent))]
|
||||||
public static bool PlayerPhysicsRpcEnterVentPrefix(PlayerPhysics __instance, int ventId)
|
public static bool PlayerPhysicsRpcEnterVentPrefix(PlayerPhysics __instance, int id)
|
||||||
{
|
{
|
||||||
var pc = __instance.myPlayer;
|
var pc = __instance.myPlayer;
|
||||||
var vent = ShipStatus.Instance.AllVents.FirstOrDefault(v => v.Id == ventId);
|
var vent = ShipStatus.Instance.AllVents.FirstOrDefault(v => v.Id == id);
|
||||||
|
|
||||||
var @event = new EnterVentEvent(pc, vent);
|
var @event = new EnterVentEvent(pc, vent);
|
||||||
MiraEventManager.InvokeEvent(@event);
|
MiraEventManager.InvokeEvent(@event);
|
||||||
@@ -40,10 +40,10 @@ public static class VentEventPatches
|
|||||||
|
|
||||||
[HarmonyPrefix]
|
[HarmonyPrefix]
|
||||||
[HarmonyPatch(typeof(PlayerPhysics), nameof(PlayerPhysics.RpcExitVent))]
|
[HarmonyPatch(typeof(PlayerPhysics), nameof(PlayerPhysics.RpcExitVent))]
|
||||||
public static bool PlayerPhysicsRpcExitVentPrefix(PlayerPhysics __instance, int ventId)
|
public static bool PlayerPhysicsRpcExitVentPrefix(PlayerPhysics __instance, int id)
|
||||||
{
|
{
|
||||||
var pc = __instance.myPlayer;
|
var pc = __instance.myPlayer;
|
||||||
var vent = ShipStatus.Instance.AllVents.First(v => v.Id == ventId);
|
var vent = ShipStatus.Instance.AllVents.First(v => v.Id == id);
|
||||||
|
|
||||||
var @event = new ExitVentEvent(pc, vent);
|
var @event = new ExitVentEvent(pc, vent);
|
||||||
MiraEventManager.InvokeEvent(@event);
|
MiraEventManager.InvokeEvent(@event);
|
||||||
|
|||||||
@@ -22,4 +22,15 @@ internal static class TaskAddButtonPatches
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[HarmonyPostfix]
|
||||||
|
[HarmonyPatch(nameof(TaskAddButton.Role), MethodType.Setter)]
|
||||||
|
public static void RoleGetterPatch(TaskAddButton __instance)
|
||||||
|
{
|
||||||
|
if (__instance.role is ICustomRole { Team: ModdedRoleTeams.Custom } customRole)
|
||||||
|
{
|
||||||
|
__instance.FileImage.color = customRole.IntroConfiguration?.IntroTeamColor ?? Color.gray;
|
||||||
|
}
|
||||||
|
__instance.RolloverHandler.OutColor = __instance.FileImage.color;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,17 +1,15 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using AmongUs.GameOptions;
|
using AmongUs.GameOptions;
|
||||||
using HarmonyLib;
|
using HarmonyLib;
|
||||||
using MiraAPI.Modifiers;
|
using MiraAPI.Modifiers;
|
||||||
using MiraAPI.Modifiers.Types;
|
|
||||||
using MiraAPI.PluginLoading;
|
using MiraAPI.PluginLoading;
|
||||||
using MiraAPI.Roles;
|
using MiraAPI.Roles;
|
||||||
using MiraAPI.Utilities;
|
using MiraAPI.Utilities;
|
||||||
using MiraAPI.Utilities.Assets;
|
using MiraAPI.Utilities.Assets;
|
||||||
using TMPro;
|
using TMPro;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEngine.Events;
|
|
||||||
using UnityEngine.UI;
|
using UnityEngine.UI;
|
||||||
using Object = UnityEngine.Object;
|
using Object = UnityEngine.Object;
|
||||||
|
|
||||||
@@ -21,6 +19,7 @@ namespace MiraAPI.Patches.Freeplay;
|
|||||||
internal static class TaskAdderPatches
|
internal static class TaskAdderPatches
|
||||||
{
|
{
|
||||||
private static Scroller _scroller = null!;
|
private static Scroller _scroller = null!;
|
||||||
|
|
||||||
[HarmonyPostfix]
|
[HarmonyPostfix]
|
||||||
[HarmonyPatch(nameof(TaskAdderGame.Begin))]
|
[HarmonyPatch(nameof(TaskAdderGame.Begin))]
|
||||||
public static void AddRolesFolder(TaskAdderGame __instance)
|
public static void AddRolesFolder(TaskAdderGame __instance)
|
||||||
@@ -33,11 +32,6 @@ internal static class TaskAdderPatches
|
|||||||
_scroller.allowY = true;
|
_scroller.allowY = true;
|
||||||
_scroller.Inner = inner.transform;
|
_scroller.Inner = inner.transform;
|
||||||
|
|
||||||
var scrollerHelper = __instance.TaskParent.gameObject.AddComponent<ManualScrollHelper>();
|
|
||||||
scrollerHelper.scroller = _scroller;
|
|
||||||
scrollerHelper.verticalAxis = RewiredConstsEnum.Action.TaskRVertical;
|
|
||||||
scrollerHelper.scrollSpeed = 10f;
|
|
||||||
|
|
||||||
GameObject hitbox = new("Hitbox")
|
GameObject hitbox = new("Hitbox")
|
||||||
{
|
{
|
||||||
layer = 5,
|
layer = 5,
|
||||||
@@ -73,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.InternalRoles.Any(x => x.Value is ICustomRole { Configuration.ShowInFreeplay: true }))
|
if (plugin.CustomRoles.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";
|
||||||
@@ -84,7 +78,7 @@ internal static class TaskAdderPatches
|
|||||||
rolesFolder.SubFolders.Add(newFolder);
|
rolesFolder.SubFolders.Add(newFolder);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (plugin.InternalModifiers.Exists(x => x.ShowInFreeplay))
|
if (plugin.Modifiers.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";
|
||||||
@@ -301,7 +295,7 @@ internal static class TaskAdderPatches
|
|||||||
|
|
||||||
if (_scroller)
|
if (_scroller)
|
||||||
{
|
{
|
||||||
_scroller.CalculateAndSetYBounds(__instance.ActiveItems.Count, 6, 4.5f, 1.65f);
|
_scroller.CalculateAndSetYBounds(__instance.ActiveItems.Count, 6, 5, 1.4f);
|
||||||
_scroller.SetYBoundsMin(0.0f);
|
_scroller.SetYBoundsMin(0.0f);
|
||||||
_scroller.ScrollToTop();
|
_scroller.ScrollToTop();
|
||||||
}
|
}
|
||||||
@@ -323,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.InternalModifiers.Count; m++)
|
for (var m = 0; m < plugin.Modifiers.Count; m++)
|
||||||
{
|
{
|
||||||
var modifier = plugin.InternalModifiers[m];
|
var modifier = plugin.Modifiers[m];
|
||||||
if (!modifier.ShowInFreeplay)
|
if (!modifier.ShowInFreeplay)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
@@ -337,10 +331,8 @@ internal static class TaskAdderPatches
|
|||||||
taskAddButton.MyTask = null;
|
taskAddButton.MyTask = null;
|
||||||
taskAddButton.SafePositionWorld = instance.SafePositionWorld;
|
taskAddButton.SafePositionWorld = instance.SafePositionWorld;
|
||||||
taskAddButton.Text.text = modifier.ModifierName;
|
taskAddButton.Text.text = modifier.ModifierName;
|
||||||
taskAddButton.Text.fontSizeMin = 1;
|
|
||||||
taskAddButton.Text.EnableMasking();
|
taskAddButton.Text.EnableMasking();
|
||||||
taskAddButton.FileImage.color = modifier.FreeplayFileColor;
|
|
||||||
taskAddButton.RolloverHandler.OutColor = modifier.FreeplayFileColor;
|
|
||||||
taskAddButton.Button.OnClick = new Button.ButtonClickedEvent();
|
taskAddButton.Button.OnClick = new Button.ButtonClickedEvent();
|
||||||
taskAddButton.Button.OnClick.AddListener((UnityEngine.Events.UnityAction)(() =>
|
taskAddButton.Button.OnClick.AddListener((UnityEngine.Events.UnityAction)(() =>
|
||||||
{
|
{
|
||||||
@@ -357,12 +349,6 @@ internal static class TaskAdderPatches
|
|||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
if (modifier is TimedModifier timed)
|
|
||||||
{
|
|
||||||
taskAddButton.FileImage.sprite = MiraAssets.TimedModifierFile.LoadAsset();
|
|
||||||
taskAddButton.Text.text += $"({timed.Duration}s)";
|
|
||||||
}
|
|
||||||
|
|
||||||
instance.AddFileAsChildCustom(taskAddButton, ref num, ref num2, ref num3);
|
instance.AddFileAsChildCustom(taskAddButton, ref num, ref num2, ref num3);
|
||||||
|
|
||||||
ControllerManager.Instance.AddSelectableUiElement(taskAddButton.Button);
|
ControllerManager.Instance.AddSelectableUiElement(taskAddButton.Button);
|
||||||
@@ -382,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.InternalRoles.Count; m++)
|
for (var m = 0; m < plugin.CustomRoles.Count; m++)
|
||||||
{
|
{
|
||||||
var roleBehaviour = plugin.InternalRoles.ElementAt(m).Value;
|
var roleBehaviour = plugin.CustomRoles.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 })
|
||||||
{
|
{
|
||||||
@@ -398,20 +384,6 @@ internal static class TaskAdderPatches
|
|||||||
|
|
||||||
instance.AddFileAsChildCustom(taskAddButton2, ref num, ref num2, ref num3);
|
instance.AddFileAsChildCustom(taskAddButton2, ref num, ref num2, ref num3);
|
||||||
taskAddButton2.Role = roleBehaviour;
|
taskAddButton2.Role = roleBehaviour;
|
||||||
if (roleBehaviour is ICustomRole custom)
|
|
||||||
{
|
|
||||||
var customColor = custom.IntroConfiguration?.IntroTeamColor ?? Color.gray;
|
|
||||||
if (custom.Team is ModdedRoleTeams.Crewmate)
|
|
||||||
{
|
|
||||||
customColor = Palette.CrewmateBlue;
|
|
||||||
}
|
|
||||||
else if (custom.Team is ModdedRoleTeams.Impostor)
|
|
||||||
{
|
|
||||||
customColor = Palette.ImpostorRed;
|
|
||||||
}
|
|
||||||
taskAddButton2.FileImage.color = customColor;
|
|
||||||
taskAddButton2.RolloverHandler.OutColor = customColor;
|
|
||||||
}
|
|
||||||
if (taskAddButton2.Button == null)
|
if (taskAddButton2.Button == null)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
|
|||||||
@@ -1,2 +0,0 @@
|
|||||||
[*.cs]
|
|
||||||
dotnet_diagnostic.S125.severity = none
|
|
||||||
@@ -1,30 +1,37 @@
|
|||||||
using HarmonyLib;
|
using HarmonyLib;
|
||||||
using MiraAPI.Hud;
|
using MiraAPI.Hud;
|
||||||
using Reactor.Utilities;
|
|
||||||
|
|
||||||
namespace MiraAPI.Patches.Hud;
|
namespace MiraAPI.Patches.Hud;
|
||||||
|
|
||||||
[HarmonyPatch(typeof(MeetingHud), nameof(MeetingHud.Start))]
|
/// <summary>
|
||||||
[HarmonyPatch(typeof(ExileController), nameof(ExileController.ReEnableGameplay))]
|
/// Reset button patches.
|
||||||
|
/// </summary>
|
||||||
|
[HarmonyPatch]
|
||||||
public static class ButtonResetPatches
|
public static class ButtonResetPatches
|
||||||
{
|
{
|
||||||
public static void Postfix()
|
/// <summary>
|
||||||
|
/// Resets the cooldown and effect of all custom buttons when the meeting starts.
|
||||||
|
/// </summary>
|
||||||
|
[HarmonyPostfix]
|
||||||
|
[HarmonyPatch(typeof(MeetingHud), nameof(MeetingHud.Start))]
|
||||||
|
public static void MeetingHudStartPostfix()
|
||||||
{
|
{
|
||||||
foreach (var customActionButton in CustomButtonManager.CustomButtons)
|
foreach (var customActionButton in CustomButtonManager.CustomButtons)
|
||||||
{
|
{
|
||||||
try
|
customActionButton.ResetCooldownAndOrEffect();
|
||||||
{
|
}
|
||||||
customActionButton.ResetCooldownAndOrEffect();
|
}
|
||||||
}
|
|
||||||
catch (System.Exception ex)
|
|
||||||
{
|
|
||||||
Logger<MiraApiPlugin>.Error($"Error resetting cooldown and effect for button {customActionButton.GetType().Name}: {ex}");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (customActionButton.UsesMode == ButtonUsesMode.PerRound)
|
/// <summary>
|
||||||
{
|
/// Resets the cooldown and effect of all custom buttons after the exile screen is closed.
|
||||||
customActionButton.SetUses(customActionButton.MaxUses);
|
/// </summary>
|
||||||
}
|
[HarmonyPostfix]
|
||||||
|
[HarmonyPatch(typeof(ExileController), nameof(ExileController.ReEnableGameplay))]
|
||||||
|
public static void ExileControllerReEnableGameplayPostfix()
|
||||||
|
{
|
||||||
|
foreach (var customActionButton in CustomButtonManager.CustomButtons)
|
||||||
|
{
|
||||||
|
customActionButton.ResetCooldownAndOrEffect();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,14 +1,6 @@
|
|||||||
using System.Collections.Generic;
|
using HarmonyLib;
|
||||||
using System.Linq;
|
|
||||||
using HarmonyLib;
|
|
||||||
using MiraAPI.Hud;
|
using MiraAPI.Hud;
|
||||||
using MiraAPI.Keybinds;
|
|
||||||
using MiraAPI.LocalSettings;
|
|
||||||
using MiraAPI.Utilities;
|
|
||||||
using Reactor.Utilities;
|
|
||||||
using Reactor.Utilities.Extensions;
|
using Reactor.Utilities.Extensions;
|
||||||
using Rewired;
|
|
||||||
using TMPro;
|
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using Object = UnityEngine.Object;
|
using Object = UnityEngine.Object;
|
||||||
|
|
||||||
@@ -25,8 +17,6 @@ public static class HudManagerPatches
|
|||||||
public static Transform? BottomRight { get; private set; }
|
public static Transform? BottomRight { get; private set; }
|
||||||
public static Transform? Buttons { get; private set; }
|
public static Transform? Buttons { get; private set; }
|
||||||
|
|
||||||
private static Dictionary<TextMeshPro, int> vanillaKeybindIcons = new();
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Trigger hudstart on current custom gamemode
|
/// Trigger hudstart on current custom gamemode
|
||||||
@@ -87,47 +77,13 @@ public static class HudManagerPatches
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
button.CreateButton(location);
|
||||||
{
|
|
||||||
button.CreateButton(location);
|
|
||||||
}
|
|
||||||
catch (System.Exception e)
|
|
||||||
{
|
|
||||||
Logger<MiraApiPlugin>.Error($"Failed to create custom button {button.GetType().Name}: {e}");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
gridArrange.Start();
|
gridArrange.Start();
|
||||||
gridArrange.ArrangeChilds();
|
gridArrange.ArrangeChilds();
|
||||||
|
|
||||||
aspectPosition.AdjustPosition();
|
aspectPosition.AdjustPosition();
|
||||||
|
|
||||||
vanillaKeybindIcons = [];
|
|
||||||
var keybindIconPos = new Vector3(-0.4f, 0.4f, -9.5f);
|
|
||||||
var vanillaButtons = new Dictionary<GameObject, int>
|
|
||||||
{
|
|
||||||
{ __instance.KillButton.gameObject, 8 },
|
|
||||||
{ __instance.UseButton.gameObject, 6 },
|
|
||||||
{ __instance.ReportButton.gameObject, 7 },
|
|
||||||
{ __instance.ImpostorVentButton.gameObject, 50 },
|
|
||||||
{ __instance.SabotageButton.gameObject, 4 },
|
|
||||||
{ __instance.AbilityButton.gameObject, 49 },
|
|
||||||
};
|
|
||||||
|
|
||||||
foreach (var kvp in vanillaButtons)
|
|
||||||
{
|
|
||||||
var buttonObj = kvp.Key;
|
|
||||||
var actionId = kvp.Value;
|
|
||||||
|
|
||||||
var key = KeybindUtils.GetKeycodeByActionId(actionId);
|
|
||||||
if (key == KeyboardKeyCode.None)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
var icon = Helpers.CreateKeybindIcon(buttonObj, key, keybindIconPos);
|
|
||||||
vanillaKeybindIcons.Add(icon.transform.GetChild(0).GetComponent<TextMeshPro>(), actionId);
|
|
||||||
var comp = buttonObj.GetComponent<ActionButton>();
|
|
||||||
KeybindManager.VanillaKeybinds[comp.GetType()].Button = comp;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -149,45 +105,7 @@ public static class HudManagerPatches
|
|||||||
|
|
||||||
foreach (var button in CustomButtonManager.CustomButtons)
|
foreach (var button in CustomButtonManager.CustomButtons)
|
||||||
{
|
{
|
||||||
try
|
button.SetActive(isActive, role);
|
||||||
{
|
|
||||||
button.SetActive(isActive, role);
|
|
||||||
}
|
|
||||||
catch (System.Exception e)
|
|
||||||
{
|
|
||||||
Logger<MiraApiPlugin>.Error($"Failed to set custom button {button.GetType().Name} active: {e}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[HarmonyPatch(nameof(HudManager.Update))]
|
|
||||||
[HarmonyPostfix]
|
|
||||||
public static void UpdatePostfix()
|
|
||||||
{
|
|
||||||
foreach (var btnIcon in vanillaKeybindIcons)
|
|
||||||
{
|
|
||||||
btnIcon.Key.text = KeybindUtils.GetKeycodeByActionId(btnIcon.Value).ToString();
|
|
||||||
btnIcon.Key.transform.parent.gameObject.SetActive(ActiveInputManager.currentControlType == ActiveInputManager.InputType.Keyboard &&
|
|
||||||
LocalSettingsTabSingleton<MiraApiSettings>.Instance.ShowKeybinds.Value);
|
|
||||||
}
|
|
||||||
|
|
||||||
var player = ReInput.players.GetPlayer(0);
|
|
||||||
foreach (var entry in KeybindManager.Keybinds)
|
|
||||||
{
|
|
||||||
var keyboard = player.controllers.Keyboard;
|
|
||||||
bool modifierKeysPressed = entry.ModifierKeys.All(k => keyboard.GetModifierKey(k)) ||
|
|
||||||
entry.ModifierKeys.Length <= 0;
|
|
||||||
if (player.GetButtonDown(entry.Id) && modifierKeysPressed)
|
|
||||||
{
|
|
||||||
entry.Invoke();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
foreach (var entry in KeybindManager.VanillaKeybinds.Values)
|
|
||||||
{
|
|
||||||
if (player.GetButtonDown(entry.Id))
|
|
||||||
{
|
|
||||||
entry.Invoke();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -29,16 +29,6 @@ public static class IntroCutscenePatches
|
|||||||
MiraEventManager.InvokeEvent(@event);
|
MiraEventManager.InvokeEvent(@event);
|
||||||
}
|
}
|
||||||
|
|
||||||
[HarmonyPostfix]
|
|
||||||
[HarmonyPatch(typeof(IntroCutscene._ShowRole_d__41), nameof(IntroCutscene._ShowRole_d__41.MoveNext))]
|
|
||||||
[HarmonyPriority(Priority.Last)]
|
|
||||||
public static void ShowRolePatch(IntroCutscene._ShowRole_d__41 __instance)
|
|
||||||
{
|
|
||||||
var realInstance = __instance.__4__this;
|
|
||||||
var @event = new IntroRoleRevealEvent(realInstance);
|
|
||||||
MiraEventManager.InvokeEvent(@event);
|
|
||||||
}
|
|
||||||
|
|
||||||
[HarmonyPrefix]
|
[HarmonyPrefix]
|
||||||
[HarmonyPatch(nameof(IntroCutscene.BeginImpostor))]
|
[HarmonyPatch(nameof(IntroCutscene.BeginImpostor))]
|
||||||
[HarmonyPatch(nameof(IntroCutscene.BeginCrewmate))]
|
[HarmonyPatch(nameof(IntroCutscene.BeginCrewmate))]
|
||||||
@@ -71,11 +61,6 @@ public static class IntroCutscenePatches
|
|||||||
public static void GameBeginPatch(IntroCutscene __instance)
|
public static void GameBeginPatch(IntroCutscene __instance)
|
||||||
{
|
{
|
||||||
MiraEventManager.InvokeEvent(new IntroEndEvent(__instance));
|
MiraEventManager.InvokeEvent(new IntroEndEvent(__instance));
|
||||||
|
|
||||||
var @event = new BeforeRoundStartEvent(true);
|
|
||||||
MiraEventManager.InvokeEvent(@event);
|
|
||||||
|
|
||||||
if (@event.IsCancelled) return;
|
|
||||||
MiraEventManager.InvokeEvent(new RoundStartEvent(true));
|
MiraEventManager.InvokeEvent(new RoundStartEvent(true));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,67 +0,0 @@
|
|||||||
using System.Linq;
|
|
||||||
using HarmonyLib;
|
|
||||||
using MiraAPI.Keybinds;
|
|
||||||
using MiraAPI.LocalSettings;
|
|
||||||
using Reactor.Utilities;
|
|
||||||
using Reactor.Utilities.Extensions;
|
|
||||||
using Rewired.UI.ControlMapper;
|
|
||||||
using TMPro;
|
|
||||||
using UnityEngine;
|
|
||||||
using UnityEngine.Events;
|
|
||||||
using UnityEngine.UI;
|
|
||||||
|
|
||||||
namespace MiraAPI.Patches.Keybinds;
|
|
||||||
|
|
||||||
[HarmonyPatch(typeof(ControlMapper))]
|
|
||||||
public static class ControlMapperPatches
|
|
||||||
{
|
|
||||||
[HarmonyPrefix]
|
|
||||||
[HarmonyPatch(nameof(ControlMapper.Start))]
|
|
||||||
private static void StartPrefix(ControlMapper __instance)
|
|
||||||
{
|
|
||||||
var doneButton = GameObject.Find("DoneButton")?.GetComponent<CustomButton>();
|
|
||||||
if (doneButton == null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var toggle = Object.Instantiate(doneButton, doneButton.transform.parent);
|
|
||||||
var text = toggle.GetComponentInChildren<TextMeshProUGUI>();
|
|
||||||
var entry = LocalSettingsTabSingleton<MiraApiSettings>.Instance.ShowKeybinds;
|
|
||||||
toggle.gameObject.name = "KeybindsVisibleToggle";
|
|
||||||
text.text = $"Show Keybinds: {(entry.Value ? "On" : "Off")}";
|
|
||||||
toggle.onClick.RemoveAllListeners();
|
|
||||||
toggle.GetComponent<ButtonInfo>().identifier = "KeybindsVisibleToggle";
|
|
||||||
toggle.onClick.AddListener((UnityAction)(() =>
|
|
||||||
{
|
|
||||||
entry.Value = !entry.Value;
|
|
||||||
text.text = $"Show Keybinds: {(entry.Value ? "On" : "Off")}";
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
[HarmonyPrefix]
|
|
||||||
[HarmonyPatch(nameof(ControlMapper.Update))]
|
|
||||||
private static void UpdatePrefix(ControlMapper __instance)
|
|
||||||
{
|
|
||||||
foreach (var element in __instance.themedElements)
|
|
||||||
{
|
|
||||||
var info = element.GetComponent<InputFieldInfo>();
|
|
||||||
if (info == null)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
var key = info.glyphOrText?.actionElementMap?.keyboardKeyCode;
|
|
||||||
if (key == null)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
var conflicts = KeybindManager.GetConflicts();
|
|
||||||
if (conflicts.Any(x => x.Key.ToString() == key.ToString()))
|
|
||||||
{
|
|
||||||
element.GetComponent<Image>().color = Color.red;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
using HarmonyLib;
|
|
||||||
using MiraAPI.Keybinds;
|
|
||||||
using MonoMod.Utils;
|
|
||||||
using Rewired;
|
|
||||||
|
|
||||||
namespace MiraAPI.Patches.Keybinds;
|
|
||||||
|
|
||||||
[HarmonyPatch(typeof(InputManager_Base), nameof(InputManager_Base.Awake))]
|
|
||||||
public static class KeybindMenuPatch
|
|
||||||
{
|
|
||||||
private static bool _registered;
|
|
||||||
|
|
||||||
[HarmonyPrefix]
|
|
||||||
private static void AwakePrefix(InputManager_Base __instance)
|
|
||||||
{
|
|
||||||
if (_registered)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
KeybindUtils.RewiredInputManager = __instance;
|
|
||||||
KeybindManager.RewiredInit();
|
|
||||||
_registered = true;
|
|
||||||
|
|
||||||
// Set these here right after input manager initializes
|
|
||||||
KeybindManager.VanillaKeybinds = new()
|
|
||||||
{
|
|
||||||
{ typeof(KillButton), new VanillaKeybind(8) },
|
|
||||||
{ typeof(UseButton), new VanillaKeybind(6) },
|
|
||||||
{ typeof(ReportButton), new VanillaKeybind(7) },
|
|
||||||
{ typeof(VentButton), new VanillaKeybind(50) },
|
|
||||||
{ typeof(SabotageButton), new VanillaKeybind(4) },
|
|
||||||
{ typeof(AbilityButton), new VanillaKeybind(49) },
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
using HarmonyLib;
|
|
||||||
using MiraAPI.Keybinds;
|
|
||||||
using UnityEngine;
|
|
||||||
|
|
||||||
namespace MiraAPI.Patches.Keybinds;
|
|
||||||
|
|
||||||
[HarmonyPatch(typeof(OptionsMenuBehaviour))]
|
|
||||||
public static class OptionsMenuBehaviourPatch
|
|
||||||
{
|
|
||||||
private static ButtonRolloverHandler? _remap_rollover;
|
|
||||||
private static SpriteRenderer? _remap_background;
|
|
||||||
private static bool _conflicts => KeybindManager.GetConflicts().Count > 0;
|
|
||||||
|
|
||||||
[HarmonyPostfix]
|
|
||||||
[HarmonyPatch(nameof(OptionsMenuBehaviour.Open))]
|
|
||||||
private static void OpenPostfix(OptionsMenuBehaviour __instance)
|
|
||||||
{
|
|
||||||
_remap_rollover = GameObject.Find("Remap Controls")?.GetComponent<ButtonRolloverHandler>()!;
|
|
||||||
_remap_background = _remap_rollover.transform.FindChild("Background").GetComponent<SpriteRenderer>();
|
|
||||||
_remap_background.color = _conflicts ? Color.red : Color.white;
|
|
||||||
}
|
|
||||||
|
|
||||||
[HarmonyPostfix]
|
|
||||||
[HarmonyPatch(nameof(OptionsMenuBehaviour.Update))]
|
|
||||||
private static void UpdatePostfix(OptionsMenuBehaviour __instance)
|
|
||||||
{
|
|
||||||
if (_remap_rollover == null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (_remap_background == null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_remap_rollover.OutColor = _conflicts ? Color.red : Color.white;
|
|
||||||
_remap_rollover.UnselectedColor = _conflicts ? Color.red : Color.white;
|
|
||||||
_remap_rollover.OverColor = _conflicts ? new Color32(255, 55, 55, 255) : Palette.AcceptedGreen;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,232 +0,0 @@
|
|||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using HarmonyLib;
|
|
||||||
using MiraAPI.LocalSettings;
|
|
||||||
using MiraAPI.Utilities.Assets;
|
|
||||||
using Reactor.Utilities;
|
|
||||||
using Reactor.Utilities.Extensions;
|
|
||||||
using UnityEngine;
|
|
||||||
using UnityEngine.Events;
|
|
||||||
using UnityEngine.UI;
|
|
||||||
|
|
||||||
namespace MiraAPI.Patches.LocalSettings;
|
|
||||||
|
|
||||||
[HarmonyPatch(typeof(OptionsMenuBehaviour))]
|
|
||||||
public static class OptionsMenuPatches
|
|
||||||
{
|
|
||||||
internal static OptionsMenuBehaviour? Instance { get; private set; }
|
|
||||||
internal static BoxCollider2D MaskCollider;
|
|
||||||
private static SpriteRenderer? background;
|
|
||||||
|
|
||||||
private static int currentPage = 1;
|
|
||||||
private static Dictionary<int, List<GameObject>> tabButtons = new();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates the tabs and their content
|
|
||||||
/// </summary>
|
|
||||||
[HarmonyPostfix]
|
|
||||||
[HarmonyPatch(nameof(OptionsMenuBehaviour.Start))]
|
|
||||||
public static void StartPostfix(OptionsMenuBehaviour __instance)
|
|
||||||
{
|
|
||||||
Instance = __instance;
|
|
||||||
// Fix for tabs not being clickable in the main menu
|
|
||||||
if (!AmongUsClient.Instance.IsInGame)
|
|
||||||
{
|
|
||||||
__instance.Background.GetComponent<BoxCollider2D>().enabled = false;
|
|
||||||
__instance.transform.FindChild("Tint").SetLocalZ(5.6f);
|
|
||||||
}
|
|
||||||
|
|
||||||
background = __instance.Background;
|
|
||||||
|
|
||||||
var maskObj = new GameObject
|
|
||||||
{
|
|
||||||
layer = 5,
|
|
||||||
name = "SpriteMask",
|
|
||||||
};
|
|
||||||
maskObj.transform.SetParent(__instance.transform);
|
|
||||||
maskObj.transform.localPosition = new Vector3(0, -0.3f, 0);
|
|
||||||
maskObj.transform.localScale = new Vector3(500, 120, 1);
|
|
||||||
|
|
||||||
var blank = Sprite.Create(
|
|
||||||
Texture2D.whiteTexture,
|
|
||||||
new Rect(0, 0, Texture2D.whiteTexture.width, Texture2D.whiteTexture.height),
|
|
||||||
new Vector2(0.5f, 0.5f));
|
|
||||||
|
|
||||||
var mask = maskObj.AddComponent<SpriteMask>();
|
|
||||||
mask.sprite = blank;
|
|
||||||
mask.isCustomRangeActive = true;
|
|
||||||
mask.sortingLayerName = "Default";
|
|
||||||
mask.backSortingOrder = 100;
|
|
||||||
mask.frontSortingOrder = 500;
|
|
||||||
|
|
||||||
MaskCollider = maskObj.AddComponent<BoxCollider2D>();
|
|
||||||
MaskCollider.size = new Vector2(0.01f, 0.1f);
|
|
||||||
MaskCollider.isTrigger = true;
|
|
||||||
MaskCollider.enabled = true;
|
|
||||||
|
|
||||||
currentPage = 1;
|
|
||||||
tabButtons.Clear();
|
|
||||||
float yOffset = 0;
|
|
||||||
int i = 0;
|
|
||||||
int tabIdx = 0;
|
|
||||||
int page = 1;
|
|
||||||
foreach (var settings in LocalSettingsManager.Tabs)
|
|
||||||
{
|
|
||||||
var tab = settings.CreateTab(__instance);
|
|
||||||
if (settings.ShouldCreateButton)
|
|
||||||
{
|
|
||||||
var button = settings.CreateTabButton(__instance, ref tabIdx, ref yOffset);
|
|
||||||
button.GetComponent<TabGroup>().Content = tab;
|
|
||||||
button.SetActive(page == currentPage);
|
|
||||||
|
|
||||||
if (!tabButtons.TryGetValue(page, out var list))
|
|
||||||
{
|
|
||||||
tabButtons.Add(page, new());
|
|
||||||
list = tabButtons[page];
|
|
||||||
}
|
|
||||||
list.Add(button);
|
|
||||||
yOffset += 0.6f;
|
|
||||||
tabIdx++;
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
if (i > 7)
|
|
||||||
{
|
|
||||||
i = 0;
|
|
||||||
yOffset = 0;
|
|
||||||
page++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ChangePage(int increase)
|
|
||||||
{
|
|
||||||
currentPage += increase;
|
|
||||||
if (currentPage > tabButtons.Count)
|
|
||||||
{
|
|
||||||
currentPage = 1;
|
|
||||||
}
|
|
||||||
if (currentPage < 1)
|
|
||||||
{
|
|
||||||
currentPage = tabButtons.Count;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create page buttons
|
|
||||||
// TODO: In-game menu has no close button. I tried making one from scratch but failed. Add one later plz
|
|
||||||
if (tabButtons.Count <= 1)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var nextButton = Object.Instantiate(__instance.BackButton, __instance.transform).GetComponent<PassiveButton>();
|
|
||||||
nextButton.transform.localPosition = new Vector3(3.2f, 2.6f, -10);
|
|
||||||
nextButton.transform.localScale = new Vector2(0.25f, 0.25f);
|
|
||||||
var nextRend = nextButton.GetComponent<SpriteRenderer>();
|
|
||||||
nextRend.sprite = MiraAssets.NextButton.LoadAsset();
|
|
||||||
nextButton.gameObject.GetComponent<CloseButtonConsoleBehaviour>().DestroyImmediate();
|
|
||||||
|
|
||||||
var nextRollover = nextButton.gameObject.AddComponent<ButtonRolloverHandler>();
|
|
||||||
nextRollover.Target = nextRend;
|
|
||||||
nextRollover.OverColor = Palette.AcceptedGreen;
|
|
||||||
|
|
||||||
nextButton.OnClick = new Button.ButtonClickedEvent();
|
|
||||||
nextButton.OnClick.AddListener(
|
|
||||||
(UnityAction)(() =>
|
|
||||||
{
|
|
||||||
ChangePage(1);
|
|
||||||
UpdatePages();
|
|
||||||
}));
|
|
||||||
|
|
||||||
var backButton = Object.Instantiate(__instance.BackButton, __instance.transform).GetComponent<PassiveButton>();
|
|
||||||
backButton.transform.localPosition = new Vector3(2.9f, 2.6f, -10);
|
|
||||||
backButton.transform.localScale = new Vector2(0.25f, 0.25f);
|
|
||||||
var backRend = backButton.GetComponent<SpriteRenderer>();
|
|
||||||
backRend.sprite = MiraAssets.NextButton.LoadAsset();
|
|
||||||
backRend.flipX = true;
|
|
||||||
backButton.gameObject.GetComponent<CloseButtonConsoleBehaviour>().DestroyImmediate();
|
|
||||||
|
|
||||||
var backRollover = backButton.gameObject.AddComponent<ButtonRolloverHandler>();
|
|
||||||
backRollover.Target = backRend;
|
|
||||||
backRollover.OverColor = Palette.AcceptedGreen;
|
|
||||||
|
|
||||||
backButton.OnClick = new Button.ButtonClickedEvent();
|
|
||||||
backButton.OnClick.AddListener(
|
|
||||||
(UnityAction)(() =>
|
|
||||||
{
|
|
||||||
ChangePage(-1);
|
|
||||||
UpdatePages();
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Modifies how opening tabs is handled for the custom ones to work.
|
|
||||||
/// </summary>
|
|
||||||
[HarmonyPrefix]
|
|
||||||
[HarmonyPatch(nameof(OptionsMenuBehaviour.OpenTabGroup))]
|
|
||||||
public static bool OpenTabGroupPrefix(OptionsMenuBehaviour __instance, ref int index)
|
|
||||||
{
|
|
||||||
__instance.Tabs.ToList().ForEach(x => x.Close()); // Close all vanilla tabs
|
|
||||||
LocalSettingsManager.Tabs.ForEach(CustomClose); // Close all mod tabs
|
|
||||||
|
|
||||||
// Tabs with index 10 and above are the mod settings tabs
|
|
||||||
if (index >= 10)
|
|
||||||
{
|
|
||||||
CustomOpen(LocalSettingsManager.Tabs[index - 10]);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Makes the custom tabs close when opening the options menu and resets pages.
|
|
||||||
/// </summary>
|
|
||||||
[HarmonyPostfix]
|
|
||||||
[HarmonyPatch(nameof(OptionsMenuBehaviour.Open))]
|
|
||||||
public static void OpenPostfix(OptionsMenuBehaviour __instance)
|
|
||||||
{
|
|
||||||
LocalSettingsManager.Tabs.ForEach(CustomClose);
|
|
||||||
currentPage = 1;
|
|
||||||
UpdatePages();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void UpdatePages()
|
|
||||||
{
|
|
||||||
foreach (var pages in tabButtons)
|
|
||||||
{
|
|
||||||
pages.Value?
|
|
||||||
.Where(x => x != null)
|
|
||||||
.Do(
|
|
||||||
x => x?.SetActive(
|
|
||||||
pages.Key == currentPage));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void CustomOpen(LocalSettingsTab tab)
|
|
||||||
{
|
|
||||||
if (tab.TabButton?.Button)
|
|
||||||
tab.TabButton!.Button.color = tab.TabAppearance.TabButtonHoverColor;
|
|
||||||
|
|
||||||
if (tab.TabButton?.Rollover)
|
|
||||||
tab.TabButton!.Rollover.OutColor = tab.TabAppearance.TabButtonHoverColor;
|
|
||||||
|
|
||||||
if (tab.TabButton?.Content)
|
|
||||||
tab.TabButton!.Content.SetActive(true);
|
|
||||||
|
|
||||||
if (background != null)
|
|
||||||
background.color = tab.TabAppearance.TabColor;
|
|
||||||
}
|
|
||||||
private static void CustomClose(LocalSettingsTab tab)
|
|
||||||
{
|
|
||||||
if (tab.TabButton?.Button)
|
|
||||||
tab.TabButton!.Button.color = tab.TabAppearance.TabButtonColor;
|
|
||||||
|
|
||||||
if (tab.TabButton?.Rollover)
|
|
||||||
tab.TabButton!.Rollover.OutColor = tab.TabAppearance.TabButtonColor;
|
|
||||||
|
|
||||||
if (tab.TabButton?.Content)
|
|
||||||
tab.TabButton!.Content.SetActive(false);
|
|
||||||
|
|
||||||
if (background != null)
|
|
||||||
background.color = Color.white;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
using HarmonyLib;
|
|
||||||
using UnityEngine;
|
|
||||||
|
|
||||||
namespace MiraAPI.Patches.LocalSettings;
|
|
||||||
|
|
||||||
[HarmonyPatch(typeof(ToggleButtonBehaviour))]
|
|
||||||
public static class ToggleBehaviourPatch
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// ResetText was inlined ofc.
|
|
||||||
/// Skill issue
|
|
||||||
/// </summary>
|
|
||||||
[HarmonyPrefix]
|
|
||||||
[HarmonyPatch(nameof(ToggleButtonBehaviour.UpdateText))]
|
|
||||||
public static bool UpdateTextPrefix(ToggleButtonBehaviour __instance, bool on)
|
|
||||||
{
|
|
||||||
var color = on ? new Color(0f, 1f, 0.16470589f, 1f) : Color.white;
|
|
||||||
__instance.onState = on;
|
|
||||||
__instance.Background.color = color;
|
|
||||||
|
|
||||||
// Used to mask the text
|
|
||||||
__instance.Text.richText = true;
|
|
||||||
__instance.Text.text = $"<font=\"LiberationSans SDF\" material=\"LiberationSans SDF - Chat Message Masked\">" +
|
|
||||||
$"{DestroyableSingleton<TranslationController>.Instance.GetString(__instance.BaseText)}: <b>" +
|
|
||||||
$"{DestroyableSingleton<TranslationController>.Instance.GetString(__instance.onState ? StringNames.SettingsOn : StringNames.SettingsOff)}</b></font>";
|
|
||||||
__instance.Text.sortingOrder = 151;
|
|
||||||
__instance.Text.renderer.sortingLayerName = "Default";
|
|
||||||
__instance.Text.renderer.sortingOrder = 151;
|
|
||||||
|
|
||||||
if (__instance.Rollover)
|
|
||||||
{
|
|
||||||
__instance.Rollover.ChangeOutColor(color);
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -84,7 +84,7 @@ public static class HatsTabPatches
|
|||||||
text.gameObject.transform.localScale = Vector3.one;
|
text.gameObject.transform.localScale = Vector3.one;
|
||||||
text.GetComponent<TextTranslatorTMP>().Destroy();
|
text.GetComponent<TextTranslatorTMP>().Destroy();
|
||||||
text.EnableStencilMasking();
|
text.EnableStencilMasking();
|
||||||
text.text = $"{groupName} ({currentPage + 1}/{sortedHats.Count})\nPress Ctrl or Tab to cycle pages";
|
text.text = $"{groupName}\nPress Ctrl or Tab to cycle pages";
|
||||||
text.alignment = TextAlignmentOptions.Center;
|
text.alignment = TextAlignmentOptions.Center;
|
||||||
text.fontSize = 3f;
|
text.fontSize = 3f;
|
||||||
text.fontSizeMax = 3f;
|
text.fontSizeMax = 3f;
|
||||||
@@ -114,7 +114,7 @@ public static class HatsTabPatches
|
|||||||
yield return null;
|
yield return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
__instance.SetScrollerBounds();
|
__instance.scroller.ContentYBounds.max = -(__instance.YStart - (hatIndex + 1) / __instance.NumPerRow * __instance.YOffset) - 3f;
|
||||||
yield return new WaitForSeconds(0.01f);
|
yield return new WaitForSeconds(0.01f);
|
||||||
}
|
}
|
||||||
__instance.currentHatIsEquipped = true;
|
__instance.currentHatIsEquipped = true;
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ public static class NameplatesTabPatches
|
|||||||
text.gameObject.transform.localScale = Vector3.one;
|
text.gameObject.transform.localScale = Vector3.one;
|
||||||
text.GetComponent<TextTranslatorTMP>().Destroy();
|
text.GetComponent<TextTranslatorTMP>().Destroy();
|
||||||
text.EnableStencilMasking();
|
text.EnableStencilMasking();
|
||||||
text.text = $"{groupName} ({currentPage + 1}/{SortedNameplates.Count})\nPress Ctrl or Tab to cycle pages";
|
text.text = $"{groupName}\nPress Ctrl or Tab to cycle pages";
|
||||||
text.alignment = TextAlignmentOptions.Center;
|
text.alignment = TextAlignmentOptions.Center;
|
||||||
text.fontSize = 3f;
|
text.fontSize = 3f;
|
||||||
text.fontSizeMax = 3f;
|
text.fontSizeMax = 3f;
|
||||||
@@ -91,7 +91,7 @@ public static class NameplatesTabPatches
|
|||||||
hatIndex += 1;
|
hatIndex += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
__instance.SetScrollerBounds();
|
__instance.scroller.ContentYBounds.max = -(__instance.YStart - (hatIndex + 1) / __instance.NumPerRow * __instance.YOffset) - 3f;
|
||||||
__instance.currentNameplateIsEquipped = true;
|
__instance.currentNameplateIsEquipped = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ public static class SkinsTabPatches
|
|||||||
text.gameObject.transform.localScale = Vector3.one;
|
text.gameObject.transform.localScale = Vector3.one;
|
||||||
text.GetComponent<TextTranslatorTMP>().Destroy();
|
text.GetComponent<TextTranslatorTMP>().Destroy();
|
||||||
text.EnableStencilMasking();
|
text.EnableStencilMasking();
|
||||||
text.text = $"{groupName} ({currentPage + 1}/{sortedSkins.Count})\nPress Ctrl or Tab to cycle pages";
|
text.text = $"{groupName}\nPress Ctrl or Tab to cycle pages";
|
||||||
text.alignment = TextAlignmentOptions.Center;
|
text.alignment = TextAlignmentOptions.Center;
|
||||||
text.fontSize = 3f;
|
text.fontSize = 3f;
|
||||||
text.fontSizeMax = 3f;
|
text.fontSizeMax = 3f;
|
||||||
@@ -94,7 +94,7 @@ public static class SkinsTabPatches
|
|||||||
hatIndex += 1;
|
hatIndex += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
__instance.SetScrollerBounds();
|
__instance.scroller.ContentYBounds.max = -(__instance.YStart - (hatIndex + 1) / __instance.NumPerRow * __instance.YOffset) - 3f;
|
||||||
__instance.currentSkinIsEquipped = true;
|
__instance.currentSkinIsEquipped = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ public static class VisorsTabPatches
|
|||||||
text.gameObject.transform.localScale = Vector3.one;
|
text.gameObject.transform.localScale = Vector3.one;
|
||||||
text.GetComponent<TextTranslatorTMP>().Destroy();
|
text.GetComponent<TextTranslatorTMP>().Destroy();
|
||||||
text.EnableStencilMasking();
|
text.EnableStencilMasking();
|
||||||
text.text = $"{groupName} ({currentPage + 1}/{SortedVisors.Count})\nPress Ctrl or Tab to cycle pages";
|
text.text = $"{groupName}\nPress Ctrl or Tab to cycle pages";
|
||||||
text.alignment = TextAlignmentOptions.Center;
|
text.alignment = TextAlignmentOptions.Center;
|
||||||
text.fontSize = 3f;
|
text.fontSize = 3f;
|
||||||
text.fontSizeMax = 3f;
|
text.fontSizeMax = 3f;
|
||||||
@@ -90,7 +90,7 @@ public static class VisorsTabPatches
|
|||||||
hatIndex += 1;
|
hatIndex += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
__instance.SetScrollerBounds();
|
__instance.scroller.ContentYBounds.max = -(__instance.YStart - (hatIndex + 1) / __instance.NumPerRow * __instance.YOffset) - 3f;
|
||||||
__instance.currentVisorIsEquipped = true;
|
__instance.currentVisorIsEquipped = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -14,12 +14,18 @@ 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))]
|
||||||
internal static class GameOptionsMenuPatch
|
public 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)
|
||||||
@@ -35,7 +41,7 @@ internal static class GameOptionsMenuPatch
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
var filteredGroups =
|
var filteredGroups =
|
||||||
GameSettingMenuPatches.SelectedMod?.InternalOptionGroups
|
GameSettingMenuPatches.SelectedMod?.OptionGroups
|
||||||
.Where(x => x.OptionableType == null && !x.ShowInModifiersMenu) ?? [];
|
.Where(x => x.OptionableType == null && !x.ShowInModifiersMenu) ?? [];
|
||||||
|
|
||||||
foreach (var group in filteredGroups)
|
foreach (var group in filteredGroups)
|
||||||
@@ -101,7 +107,7 @@ internal static class GameOptionsMenuPatch
|
|||||||
|
|
||||||
private static void ModifiersUpdate(ref float num)
|
private static void ModifiersUpdate(ref float num)
|
||||||
{
|
{
|
||||||
var groups = GameSettingMenuPatches.SelectedMod?.InternalOptionGroups
|
var groups = GameSettingMenuPatches.SelectedMod?.OptionGroups
|
||||||
.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)
|
||||||
@@ -112,7 +118,7 @@ internal static class GameOptionsMenuPatch
|
|||||||
|
|
||||||
private static void ModifiersCreate(GameOptionsMenu menu)
|
private static void ModifiersCreate(GameOptionsMenu menu)
|
||||||
{
|
{
|
||||||
var groups = GameSettingMenuPatches.SelectedMod?.InternalOptionGroups
|
var groups = GameSettingMenuPatches.SelectedMod?.OptionGroups
|
||||||
.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)
|
||||||
{
|
{
|
||||||
@@ -122,7 +128,6 @@ internal 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)
|
||||||
@@ -138,7 +143,7 @@ internal static class GameOptionsMenuPatch
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
var filteredGroups = GameSettingMenuPatches.SelectedMod?.InternalOptionGroups
|
var filteredGroups = GameSettingMenuPatches.SelectedMod?.OptionGroups
|
||||||
.Where(x => x.OptionableType == null && !x.ShowInModifiersMenu) ?? [];
|
.Where(x => x.OptionableType == null && !x.ShowInModifiersMenu) ?? [];
|
||||||
|
|
||||||
foreach (var group in filteredGroups)
|
foreach (var group in filteredGroups)
|
||||||
@@ -151,7 +156,6 @@ internal 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)
|
||||||
@@ -220,7 +224,6 @@ internal static class GameOptionsMenuPatch
|
|||||||
menu.checkboxOrigin,
|
menu.checkboxOrigin,
|
||||||
menu.numberOptionOrigin,
|
menu.numberOptionOrigin,
|
||||||
menu.stringOptionOrigin,
|
menu.stringOptionOrigin,
|
||||||
menu.playerOptionOrigin,
|
|
||||||
menu.settingsContainer));
|
menu.settingsContainer));
|
||||||
|
|
||||||
foreach (var newOpt in options)
|
foreach (var newOpt in options)
|
||||||
|
|||||||
Loaded 100 of 140 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user