Compare commits

..
2 Commits
Author SHA1 Message Date
Sameer Umar 11e894a29a Add NuGet login step and update push command 2026-10-19 17:20:30 +00:00
Atony 94affd8bf3 Merge pull request #113 from All-Of-Us-Mods/dev
Next MiraAPI release
2026-10-18 18:00:39 -05:00
22 changed files with 123 additions and 466 deletions

No files matched your search

+12 -3
View File
@@ -5,6 +5,8 @@ on: ["workflow_dispatch", "push", "pull_request"]
jobs:
build:
runs-on: ubuntu-22.04
permissions:
id-token: write
steps:
- uses: actions/checkout@v4
with:
@@ -38,14 +40,21 @@ jobs:
with:
name: AllOfUs.MiraAPI.nupkg
path: MiraAPI/bin/Release/AllOfUs.MiraAPI.*.nupkg
- uses: softprops/action-gh-release@v2
if: github.ref_type == 'tag'
with:
draft: true
files: MiraAPI/bin/Release/net6.0/MiraAPI.dll
- name: NuGet login
if: github.ref_type == 'tag'
uses: NuGet/login@v1
id: login
with:
user: xtracube
- name: Push NuGet package
if: github.ref_type == 'tag'
run: |
dotnet nuget push MiraAPI/bin/Release/AllOfUs.MiraAPI.*.nupkg --source https://api.nuget.org/v3/index.json --api-key ${{ secrets.NUGET_API_KEY }}
dotnet nuget push MiraAPI/bin/Release/AllOfUs.MiraAPI.*.nupkg --source https://api.nuget.org/v3/index.json --api-key ${{ steps.login.outputs.NUGET_API_KEY }}
-5
View File
@@ -77,11 +77,6 @@ public interface IModdedOption
/// </summary>
bool IncludeInPreset { get; set; }
/// <summary>
/// Gets or sets a value indicating whether the option should show a notification, toggled on by an overall option synchronization.
/// </summary>
public bool ShowNotification { get; set; }
/// <summary>
/// Gets or sets the <see cref="BepInEx.Configuration.ConfigDefinition"/> for the option, used for BepInEx configuration.
/// </summary>
+3 -4
View File
@@ -365,11 +365,11 @@ public static class ModdedOptionsManager
while (chunks.Count > 0)
{
Rpc<SyncOptionsRpc>.Instance.SendTo(PlayerControl.LocalPlayer, targetId, new MiraOptionNetData(false, chunks.Dequeue()));
Rpc<SyncOptionsRpc>.Instance.SendTo(PlayerControl.LocalPlayer, targetId, chunks.Dequeue());
}
}
internal static void HandleSyncOptions(bool showNotifs, NetData[] data)
internal static void HandleSyncOptions(NetData[] data)
{
// necessary to disable then re-enable this setting
// we don't know how other plugins handle their configs
@@ -388,7 +388,6 @@ public static class ModdedOptionsManager
continue;
}
option.ShowNotification = showNotifs;
option.HandleNetData(netData.Data);
}
@@ -398,7 +397,7 @@ public static class ModdedOptionsManager
plugin.PluginConfig.SaveOnConfigSet = oldConfigSetting[plugin];
}
if (LobbyInfoPane.InstanceExists)
if (LobbyInfoPane.Instance)
{
LobbyInfoPane.Instance.RefreshPane();
}
@@ -4,7 +4,6 @@ using System.Linq;
using System.Text;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using MiraAPI.Networking;
using MiraAPI.PluginLoading;
using MiraAPI.Translation;
using UnityEngine;
using Object = UnityEngine.Object;
@@ -37,7 +36,7 @@ public class ModdedEnumOption : ModdedOption<int>
var data = ScriptableObject.CreateInstance<StringGameSetting>();
data.Title = StringName;
data.Type = global::OptionTypes.String;
data.Values = Values.Select(x => MiraLocaleManager.GetOrCreateLocaleString(ParentMod!.IdBuilder.CreateEnumOptionId(x, enumType))).ToArray();
data.Values = Values.Select(MiraLocaleManager.GetOrCreateLocaleString).ToArray();
data.Index = Value;
Data = data;
@@ -94,17 +93,13 @@ public class ModdedEnumOption : ModdedOption<int>
/// <inheritdoc />
protected override void OnValueChanged(int newValue)
{
if (ShowNotification)
{
ModdedOptionsManager.AddSettingsChangeMessage(
HudManager.Instance.Notifier,
StringName,
Data.GetValueString(newValue),
Configuration.PopUpTextColor,
Configuration.PopUpIconTmp,
false);
}
ModdedOptionsManager.AddSettingsChangeMessage(
HudManager.Instance.Notifier,
StringName,
Data.GetValueString(newValue),
Configuration.PopUpTextColor,
Configuration.PopUpIconTmp,
false);
if (!OptionBehaviour)
{
return;
@@ -144,18 +139,12 @@ public class ModdedEnumOption<T> : ModdedOption<T>
var data = ScriptableObject.CreateInstance<StringGameSetting>();
data.Title = StringName;
data.Type = global::OptionTypes.String;
data.Values = Values.Select(MiraLocaleManager.GetOrCreateLocaleString).ToArray();
data.Index = Convert.ToInt32(Value, NumberFormatInfo.InvariantInfo);
Data = data;
}
/// <inheritdoc />
protected override void OnParentModSet(IMiraPlugin plugin)
{
base.OnParentModSet(plugin);
((StringGameSetting)Data).Values = Values.Select(x => MiraLocaleManager.GetOrCreateLocaleString(ParentMod!.IdBuilder.CreateEnumOptionId<T>(x))).ToArray();
}
/// <inheritdoc />
public override OptionBehaviour CreateOption(ToggleOption toggleOpt, NumberOption numberOpt, StringOption stringOpt, PlayerOption playerOpt, Transform container)
{
@@ -207,17 +196,13 @@ public class ModdedEnumOption<T> : ModdedOption<T>
/// <inheritdoc />
protected override void OnValueChanged(T newValue)
{
if (ShowNotification)
{
ModdedOptionsManager.AddSettingsChangeMessage(
HudManager.Instance.Notifier,
StringName,
Data.GetValueString(Convert.ToInt32(newValue, NumberFormatInfo.InvariantInfo)),
Configuration.PopUpTextColor,
Configuration.PopUpIconTmp,
false);
}
ModdedOptionsManager.AddSettingsChangeMessage(
HudManager.Instance.Notifier,
StringName,
Data.GetValueString(Convert.ToInt32(newValue, NumberFormatInfo.InvariantInfo)),
Configuration.PopUpTextColor,
Configuration.PopUpIconTmp,
false);
if (!OptionBehaviour)
{
return;
@@ -199,16 +199,13 @@ public class ModdedNumberOption : ModdedOption<float>
protected override void OnValueChanged(float newValue)
{
Value = Mathf.Clamp(newValue, Min, Max);
if (ShowNotification)
{
ModdedOptionsManager.AddSettingsChangeMessage(
HudManager.Instance.Notifier,
StringName,
Data.GetValueString(newValue),
Configuration.PopUpTextColor,
Configuration.PopUpIconTmp,
false);
}
ModdedOptionsManager.AddSettingsChangeMessage(
HudManager.Instance.Notifier,
StringName,
Data.GetValueString(newValue),
Configuration.PopUpTextColor,
Configuration.PopUpIconTmp,
false);
if (OptionBehaviour is NumberOption opt)
{
+27 -26
View File
@@ -4,6 +4,7 @@ using BepInEx.Configuration;
using MiraAPI.Networking;
using MiraAPI.PluginLoading;
using MiraAPI.Translation;
using MiraAPI.Utilities;
using Reactor.Networking.Rpc;
using UnityEngine;
@@ -13,19 +14,16 @@ namespace MiraAPI.GameOptions.OptionTypes;
/// Represents a modded option.
/// </summary>
/// <typeparam name="T">The value type.</typeparam>
/// <param name="title">The option title.</param>
/// <param name="defaultValue">The default value.</param>
/// <param name="includeInPreset">Whether to include the option in the preset.</param>
public abstract class ModdedOption<T>(string title, T defaultValue, bool includeInPreset = true) : IModdedOption
public abstract class ModdedOption<T> : IModdedOption
{
/// <inheritdoc />
public uint Id { get; } = ModdedOptionsManager.NextId;
public uint Id { get; }
/// <inheritdoc />
public string Title { get; set; } = title;
public string Title { get; set; }
/// <inheritdoc />
public StringNames StringName { get; private set; }
public StringNames StringName { get; }
/// <inheritdoc />
public BaseGameSetting Data { get; protected set; } = null!;
@@ -38,7 +36,6 @@ public abstract class ModdedOption<T>(string title, T defaultValue, bool include
{
if (field != null || value == null) return;
field = value;
OnParentModSet(value);
var entry = field.GetConfigFile().Bind(ConfigDefinition, DefaultValue);
Value = entry.Value;
@@ -60,12 +57,12 @@ public abstract class ModdedOption<T>(string title, T defaultValue, bool include
}
}
private T _value = defaultValue;
private T _value;
/// <summary>
/// Gets the default value of the option.
/// </summary>
public T DefaultValue { get; } = defaultValue;
public T DefaultValue { get; }
/// <inheritdoc cref="IModdedOption.Getter"/>
public Func<T, T>? Getter { get; set; }
@@ -77,13 +74,10 @@ public abstract class ModdedOption<T>(string title, T defaultValue, bool include
public Action<T>? ChangedEvent { get; set; }
/// <inheritdoc />
public Func<bool> Visible { get; set; } = () => true;
public Func<bool> Visible { get; set; }
/// <inheritdoc />
public bool IncludeInPreset { get; set; } = includeInPreset;
/// <inheritdoc />
public bool ShowNotification { get; set; } = true;
public bool IncludeInPreset { get; set; }
/// <inheritdoc />
public OptionBehaviour? OptionBehaviour { get; protected set; }
@@ -118,6 +112,23 @@ public abstract class ModdedOption<T>(string title, T defaultValue, bool include
set => ChangedEvent = value as Action<T>;
}
/// <summary>
/// Initializes a new instance of the <see cref="ModdedOption{T}"/> class.
/// </summary>
/// <param name="title">The option title.</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, bool includeInPreset = true)
{
Id = ModdedOptionsManager.NextId;
Title = title.Translate();
DefaultValue = defaultValue;
Value = defaultValue;
StringName = MiraLocaleManager.GetOrCreateLocaleString(Title);
Visible = DelegateUtilities.AlwaysTrue;
IncludeInPreset = includeInPreset;
}
internal void ValueChanged(OptionBehaviour optionBehaviour)
{
SetValue(GetValueFromOptionBehaviour(optionBehaviour));
@@ -145,11 +156,10 @@ public abstract class ModdedOption<T>(string title, T defaultValue, bool include
entry.Value = _value;
}
Rpc<SyncOptionsRpc>.Instance.Send(PlayerControl.LocalPlayer, new MiraOptionNetData(true, [GetNetData()]), true);
Rpc<SyncOptionsRpc>.Instance.Send(PlayerControl.LocalPlayer, [GetNetData()], true);
}
OnValueChanged(_value);
ShowNotification = true;
}
/// <inheritdoc />
@@ -184,15 +194,6 @@ public abstract class ModdedOption<T>(string title, T defaultValue, bool include
}
}
/// <summary>
/// An event that is invoked when the option's parent mod as been assigned to the option.
/// </summary>
/// <param name="plugin">The plugin that was assigned.</param>
protected virtual void OnParentModSet(IMiraPlugin plugin)
{
StringName = MiraLocaleManager.GetOrCreateLocaleString(plugin.IdBuilder.CreateOptionTitleId(Title));
}
/// <inheritdoc />
public Type GetValueType()
{
@@ -4,7 +4,6 @@ using System.Linq;
using System.Text;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using MiraAPI.Networking;
using MiraAPI.PluginLoading;
using MiraAPI.Translation;
using UnityEngine;
using Object = UnityEngine.Object;
@@ -80,7 +79,7 @@ public class ModdedStringOption : ModdedOption<string>
newVals.Insert(index, value);
Values = [.. newVals];
var newStrVals = StringNameValues.ToList();
newStrVals.Insert(index, MiraLocaleManager.GetOrCreateLocaleString(ParentMod!.IdBuilder.CreateStringOptionId(value)));
newStrVals.Insert(index, MiraLocaleManager.GetOrCreateLocaleString(value));
StringNameValues = [.. newStrVals];
}
@@ -102,9 +101,10 @@ public class ModdedStringOption : ModdedOption<string>
return;
}
Warning("OptionBehaviour is valid");
var strOpt = OptionBehaviour.TryCast<StringOption>();
Warning("OptionBehaviour is valid");
if (strOpt == null)
{
Error("StringOption is null.");
@@ -114,16 +114,6 @@ public class ModdedStringOption : ModdedOption<string>
strOpt.Values = StringNameValues;
strOpt.Value = GetIndex(Value);
Warning("StringOption is valid");
return;
}
/// <inheritdoc />
protected override void OnParentModSet(IMiraPlugin plugin)
{
base.OnParentModSet(plugin);
StringNameValues = [.. Values.Select(x => MiraLocaleManager.GetOrCreateLocaleString(plugin.IdBuilder.CreateStringOptionId(x)))];
((StringGameSetting)Data).Values = StringNameValues;
}
/// <inheritdoc />
@@ -99,17 +99,13 @@ public class ModdedToggleOption : ModdedOption<bool>
/// <inheritdoc />
protected override void OnValueChanged(bool newValue)
{
if (ShowNotification)
{
ModdedOptionsManager.AddSettingsChangeMessage(
HudManager.Instance.Notifier,
StringName,
(newValue ? OnValue : OffValue).Translate(),
Configuration.PopUpTextColor,
Configuration.PopUpIconTmp,
false);
}
ModdedOptionsManager.AddSettingsChangeMessage(
HudManager.Instance.Notifier,
StringName,
(newValue ? OnValue : OffValue).Translate(),
Configuration.PopUpTextColor,
Configuration.PopUpIconTmp,
false);
if (!OptionBehaviour)
{
return;
+1 -1
View File
@@ -36,7 +36,7 @@ public partial class MiraApiPlugin : BasePlugin, IMiraPlugin
public static CultureInfo Culture { get; internal set; } = new("en-US");
/// <inheritdoc />
public string OptionsTitleText { get; } = "MiraAPI";
public string OptionsTitleText => "MiraAPI";
/// <inheritdoc />
public bool DisplayOnOptionsMenu => false;
-43
View File
@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using Il2CppInterop.Runtime.Attributes;
using MiraAPI.GameOptions;
using MiraAPI.PluginLoading;
@@ -97,48 +96,6 @@ public abstract class BaseModifier : IOptionable
/// </summary>
public virtual string ModifierCategoryTitle => MiraLocaleManager.Get("Modifier");
/// <summary>
/// Gets a value indicating whether to exclude the "amount" from the displayed amount text within the role guide.
/// </summary>
public virtual bool ShowModifierAsUnique => false;
/// <summary>
/// Gets the displayed amount and chance of the modifier. Used in the role guide.
/// By default, 0 amount or chance results in a complete 0 amount and chance, so override if necessary.
/// </summary>
/// <param name="amount">The amount of the modifier.</param>
/// <param name="chance">The chance of the modifier.</param>
/// <param name="source">The mod source of the modifier.</param>
/// <returns>The <see cref="string"/> result.</returns>
public virtual string GetAmountText(int amount, int chance, string source)
{
if (amount == 0)
{
chance = 0;
}
if (ShowModifierAsUnique)
{
return string.Format(
CultureInfo.InvariantCulture,
"{0}% ({1})",
chance.ToString(CultureInfo.InvariantCulture),
source);
}
if (chance == 0)
{
amount = 0;
}
return string.Format(
CultureInfo.InvariantCulture,
"{0} at {1}% ({2})",
amount.ToString(CultureInfo.InvariantCulture),
chance.ToString(CultureInfo.InvariantCulture),
source);
}
/// <summary>
/// Gets whether the modifier is forcibly shown or disabled in the wiki screen.
/// </summary>
+1 -2
View File
@@ -1,5 +1,4 @@
using System.Globalization;
using MiraAPI.GameModes;
using MiraAPI.GameModes;
using MiraAPI.PluginLoading;
namespace MiraAPI.Modifiers.Types;
+10 -13
View File
@@ -9,32 +9,29 @@ namespace MiraAPI.Networking;
[RegisterCustomRpc((uint)MiraRpc.SyncGameOptions)]
#pragma warning disable SA1515 // Single-line comment should be preceded by blank line (Justification: ReSharper suppression.)
// ReSharper disable once ClassNeverInstantiated.Global (Justification: Instantiated by Reactor.)
internal sealed class SyncOptionsRpc(MiraApiPlugin plugin, uint id) : PlayerCustomRpc<MiraApiPlugin, MiraOptionNetData>(plugin, id)
internal sealed class SyncOptionsRpc(MiraApiPlugin plugin, uint id) : PlayerCustomRpc<MiraApiPlugin, NetData[]>(plugin, id)
#pragma warning restore SA1515 // Single-line comment should be preceded by blank line
{
public override RpcLocalHandling LocalHandling => RpcLocalHandling.None;
public override void Write(MessageWriter writer, MiraOptionNetData data)
public override void Write(MessageWriter writer, NetData[]? data)
{
/*if (data == null)
if (data == null)
{
writer.WritePacked(0U);
return;
}*/
}
var info = data.Data;
writer.Write(data.ShouldShowNotifications);
writer.WritePacked((uint)info.Length);
foreach (var netData in info)
writer.WritePacked((uint)data.Length);
foreach (var netData in data)
{
writer.WritePacked(netData.Id);
writer.WriteBytesAndSize(netData.Data);
}
}
public override MiraOptionNetData Read(MessageReader reader)
public override NetData[] Read(MessageReader reader)
{
var shouldShowNotif = reader.ReadBoolean();
var length = reader.ReadPackedUInt32();
var data = new NetData[length];
for (var i = 0; i < length; i++)
@@ -44,16 +41,16 @@ internal sealed class SyncOptionsRpc(MiraApiPlugin plugin, uint id) : PlayerCust
data[i] = new NetData(dataId, bytes);
}
return new MiraOptionNetData(shouldShowNotif, data);
return data;
}
public override void Handle(PlayerControl playerControl, MiraOptionNetData data)
public override void Handle(PlayerControl playerControl, NetData[]? data)
{
if (AmongUsClient.Instance.HostId != playerControl.OwnerId)
{
return;
}
ModdedOptionsManager.HandleSyncOptions(data.ShouldShowNotifications, data.Data ?? []);
ModdedOptionsManager.HandleSyncOptions(data ?? []);
}
}
+10 -19
View File
@@ -5,41 +5,32 @@ using Reactor.Networking.Rpc;
namespace MiraAPI.Networking;
internal readonly struct MiraOptionNetData(bool showNotif, NetData[] data)
{
public bool ShouldShowNotifications { get; } = showNotif;
public NetData[] Data { get; } = data;
}
[RegisterCustomRpc((uint)MiraRpc.SyncRoleOptions)]
#pragma warning disable SA1515 // Single-line comment should be preceded by blank line (Justification: ReSharper suppression.)
// ReSharper disable once ClassNeverInstantiated.Global (Justification: Instantiated by Reactor.)
internal sealed class SyncRoleOptionsRpc(MiraApiPlugin plugin, uint id) : PlayerCustomRpc<MiraApiPlugin, MiraOptionNetData>(plugin, id)
internal sealed class SyncRoleOptionsRpc(MiraApiPlugin plugin, uint id) : PlayerCustomRpc<MiraApiPlugin, NetData[]>(plugin, id)
#pragma warning restore SA1515 // Single-line comment should be preceded by blank line
{
public override RpcLocalHandling LocalHandling => RpcLocalHandling.None;
public override void Write(MessageWriter writer, MiraOptionNetData data)
public override void Write(MessageWriter writer, NetData[]? data)
{
/*if (data == null)
if (data == null)
{
writer.WritePacked(0U);
return;
}*/
}
var info = data.Data;
writer.Write(data.ShouldShowNotifications);
writer.WritePacked((uint)info.Length);
foreach (var netData in info)
writer.WritePacked((uint)data.Length);
foreach (var netData in data)
{
writer.WritePacked(netData.Id);
writer.WriteBytesAndSize(netData.Data);
}
}
public override MiraOptionNetData Read(MessageReader reader)
public override NetData[] Read(MessageReader reader)
{
var shouldShowNotif = reader.ReadBoolean();
var length = reader.ReadPackedUInt32();
var data = new NetData[length];
for (var i = 0; i < length; i++)
@@ -49,16 +40,16 @@ internal sealed class SyncRoleOptionsRpc(MiraApiPlugin plugin, uint id) : Player
data[i] = new NetData(dataId, bytes);
}
return new MiraOptionNetData(shouldShowNotif, data);
return data;
}
public override void Handle(PlayerControl playerControl, MiraOptionNetData data)
public override void Handle(PlayerControl playerControl, NetData[]? data)
{
if (AmongUsClient.Instance.HostId != playerControl.OwnerId)
{
return;
}
CustomRoleManager.HandleSyncRoleOptions(data.ShouldShowNotifications, data.Data ?? []);
CustomRoleManager.HandleSyncRoleOptions(data ?? []);
}
}
@@ -1,7 +1,5 @@
using HarmonyLib;
using MiraAPI.GameModes;
using MiraAPI.GameOptions;
using MiraAPI.Roles;
namespace MiraAPI.Patches.GameModes;
@@ -57,17 +55,4 @@ internal static class GameStartManagerPatches
__instance.MinPlayers = 1;
}
}
[HarmonyPrefix, HarmonyPatch(nameof(GameStartManager.BeginGame))]
public static void Prefix(GameStartManager __instance)
{
if (!AmongUsClient.Instance.AmHost)
{
return;
}
ModdedOptionsManager.SyncAllOptions();
CustomRoleManager.SyncAllRoleSettings();
GameModeOption.RpcSyncGamemode(PlayerControl.LocalPlayer, GameModeOption.Value);
}
}
+1 -1
View File
@@ -29,7 +29,7 @@ public static class HudManagerPatches
public static IEnumerator CoResizeUI()
{
while (!HudManager.InstanceExists) yield return null;
while (!HudManager.Instance) yield return null;
yield return new WaitForSeconds(0.01f);
ResizeUI(LocalSettingsTabSingleton<MiraApiSettings>.Instance.ButtonUIFactorSlider.Value);
@@ -495,7 +495,7 @@ public static class RoleSettingMenuPatches
if (AmongUsClient.Instance.AmHost)
{
Rpc<SyncRoleOptionsRpc>.Instance.Send(PlayerControl.LocalPlayer, new MiraOptionNetData(true, [role.GetNetData()]), true);
Rpc<SyncRoleOptionsRpc>.Instance.Send(PlayerControl.LocalPlayer, [role.GetNetData()], true);
}
GameOptionsManager.Instance.GameHostOptions = GameOptionsManager.Instance.CurrentGameOptions;
+21 -100
View File
@@ -754,8 +754,7 @@ public static class RoleGuidePatches
modifier.ModifierCategoryTitle,
modifier.ParentMod.MiraPlugin.GetAbbreviatedModName(),
null,
modifier,
modifier.TypeId));
modifier));
}
}
@@ -791,8 +790,7 @@ public static class RoleGuidePatches
roleBehaviour.GetCategoryTitle(),
modId,
roleBehaviour,
null,
(uint)roleBehaviour.Role));
null));
}
_roleEntriesMode = activeModeType;
@@ -930,7 +928,7 @@ public static class RoleGuidePatches
}
}
private sealed class DetailedPanel(string title, string category, string modId, RoleBehaviour? role, GameModifier? modifier, uint typeId)
private sealed class DetailedPanel(string title, string category, string modId, RoleBehaviour? role, GameModifier? modifier)
{
public MatchInfoRolePanel? Panel { get; set; }
public string Title { get; } = title;
@@ -938,7 +936,6 @@ public static class RoleGuidePatches
public string ModId { get; } = modId;
public RoleBehaviour? Role { get; } = role;
public GameModifier? Modifier { get; } = modifier;
public uint TypeId { get; } = typeId;
public int Amount { get; set; }
public int Chance { get; set; }
public float Likelihood { get; set; }
@@ -1160,9 +1157,7 @@ public static class RoleGuidePatches
entry.Visible = entry.CanShow && MatchesSearch(entry, searchText);
if (entry.Panel)
{
dynamic entryType = entry.Modifier != null ? entry.Modifier : entry.Role!;
var text = GetPanelCountText(entryType, entry.Amount, entry.Chance, entry.ModId);
SetPanelCount(entry.Panel!, text);
SetPanelCount(entry.Panel!, entry.Amount, entry.Chance, entry.ModId);
if (!entry.Visible && entry.Panel!.gameObject.activeSelf)
{
entry.Panel.gameObject.SetActive(false);
@@ -1187,58 +1182,16 @@ public static class RoleGuidePatches
return shown;
}
public static IEnumerable<GameModifier> GetActiveModifiers()
{
return PlayerControl.LocalPlayer.GetModifiers<GameModifier>();
}
public static IEnumerable<RoleBehaviour> GetActiveRoles()
{
IEnumerable<RoleBehaviour> comparisons = [];
var curRole = PlayerControl.LocalPlayer.Data.Role;
comparisons = comparisons.AddItem(curRole);
if (PlayerControl.LocalPlayer && PlayerControl.LocalPlayer.Data && PlayerControl.LocalPlayer.Data.IsDead &&
!comparisons.Any(x => x.Role == PlayerControl.LocalPlayer.Data.RoleWhenAlive.Value))
{
comparisons = comparisons.AddItem(RoleManager.Instance.GetRole(PlayerControl.LocalPlayer.Data.RoleWhenAlive.Value));
}
return comparisons;
}
public static List<uint> GetActiveIds()
{
var activeModifiers = GetActiveModifiers();
List<uint> comparisons = activeModifiers.Select(x => x.TypeId).ToList();
comparisons.AddRange(GetActiveRoles().Select(x => (uint)x.Role));
return comparisons;
}
private static List<DetailedPanel> SortEntries(List<DetailedPanel> entries, string searchText)
{
var activeModifiers = PlayerControl.LocalPlayer.GetModifiers<GameModifier>().Select(x => x.TypeId);
var roles = GetActiveRoles().Select(x => (uint)x.Role).ToList();
List<uint> comparisons = activeModifiers.ToList();
comparisons.AddRange(roles);
var comparer = new BasicGuideComparer(comparisons);
var sorted = entries.Where(p => p.Visible)
.OrderByDescending(p => p.Title.Equals(searchText, StringComparison.OrdinalIgnoreCase))
.ThenByDescending(p =>
p.Title.Contains(searchText, StringComparison.OrdinalIgnoreCase) ||
p.Category.Contains(searchText, StringComparison.OrdinalIgnoreCase))
.ThenBy(x => x.Modifier != null ? x.Modifier.TypeId : (uint)x.Role!.Role, comparer);
return
[
.. _sortMethod is SortingMethod.Alphabetical
p.Category.Contains(searchText, StringComparison.OrdinalIgnoreCase));
return [.. _sortMethod is SortingMethod.Alphabetical
? sorted.ThenBy(p => p.GetSortKey(_sortGrouping))
: sorted.ThenByDescending(p => p.GetSortKey(_sortGrouping))
];
: sorted.ThenByDescending(p => p.GetSortKey(_sortGrouping))];
}
private static bool MatchesSearch(DetailedPanel entry, string searchText)
@@ -1698,15 +1651,10 @@ public static class RoleGuidePatches
public static Sprite GetRandomRoleIcon()
{
var roles = GetActiveRoles().Shuffle().ToList();
foreach (var role in roles)
var aliveRole = PlayerControl.LocalPlayer.Data?.Role;
if (aliveRole != null && aliveRole.RoleIconSolid != null)
{
if (role.RoleIconSolid == null)
{
continue;
}
return role.RoleIconSolid;
return aliveRole.RoleIconSolid;
}
return GetRandomFactionIcon();
@@ -1845,22 +1793,21 @@ public static class RoleGuidePatches
return false;
}
__instance.roleCount.text = string.Format(
CultureInfo.InvariantCulture,
"{0} at {1}%",
numPerGame.ToString(CultureInfo.InvariantCulture),
chancePerGame);
if (role is ICustomRole customRole)
{
__instance.roleName.text = customRole.RoleName;
__instance.roleDescription.text =
$"<size=60%>{role.GetCategoryTitle()}</size>\n" + customRole.RoleMedDescription;
__instance.roleIcon.sprite = customRole.Configuration.Icon?.LoadAsset();
var text = GetCustomRolePanelCountText(customRole, numPerGame, chancePerGame, customRole.ParentMod.MiraPlugin.GetAbbreviatedModName());
SetPanelCount(__instance, text);
__instance.roleCount.text += $" ({customRole.ParentMod.MiraPlugin.GetAbbreviatedModName()})";
}
else
{
__instance.roleCount.text = string.Format(
CultureInfo.InvariantCulture,
"{0} at {1}%",
numPerGame.ToString(CultureInfo.InvariantCulture),
chancePerGame);
__instance.roleName.text = role.NiceName;
__instance.roleDescription.text = $"<size=60%>{role.GetCategoryTitle()}</size>\n" + role.BlurbMed;
__instance.roleIcon.sprite = role.RoleIconColor;
@@ -1876,20 +1823,9 @@ public static class RoleGuidePatches
return false;
}
// NOTE: This is specifically meant to be a different method name as to not have the game check this method and the GetPanelCountText method made for roles overall.
private static string GetCustomRolePanelCountText(ICustomRole custom, int amount, int chance, string modId)
private static void SetPanelCount(MatchInfoRolePanel panel, int amount, int chance, string modId)
{
return custom.GetAmountText(amount, chance, modId);
}
private static string GetPanelCountText(RoleBehaviour role, int amount, int chance, string modId)
{
if (role is ICustomRole custom)
{
return custom.GetAmountText(amount, chance, modId);
}
return string.Format(
panel.roleCount.text = string.Format(
CultureInfo.InvariantCulture,
"{0} at {1}% ({2})",
amount.ToString(CultureInfo.InvariantCulture),
@@ -1897,18 +1833,6 @@ public static class RoleGuidePatches
modId);
}
private static string GetPanelCountText(BaseModifier modifier, int amount, int chance, string modId)
{
return modifier.GetAmountText(amount, chance, modId);
}
private static void SetPanelCount(MatchInfoRolePanel panel, string amountChanceText)
{
panel.roleCount.text = string.Format(
CultureInfo.InvariantCulture,
amountChanceText);
}
public static void SetRolePanel(
this MatchInfoRolePanel instance,
RoleBehaviour role,
@@ -1921,16 +1845,14 @@ public static class RoleGuidePatches
instance.roleDescription.text =
$"<size=60%>{role.GetCategoryTitle()}</size>\n" + customRole.RoleMedDescription;
instance.roleIcon.sprite = customRole.Configuration.Icon?.LoadAsset();
var text = GetCustomRolePanelCountText(customRole, numPerGame, chancePerGame, customRole.ParentMod.MiraPlugin.GetAbbreviatedModName());
SetPanelCount(instance, text);
SetPanelCount(instance, numPerGame, chancePerGame, customRole.ParentMod.MiraPlugin.GetAbbreviatedModName());
}
else
{
instance.roleName.text = role.NiceName;
instance.roleDescription.text = $"<size=60%>{role.GetCategoryTitle()}</size>\n" + role.BlurbMed;
instance.roleIcon.sprite = role.RoleIconColor;
var text = GetPanelCountText(role, numPerGame, chancePerGame, "AU");
SetPanelCount(instance, text);
SetPanelCount(instance, numPerGame, chancePerGame, "AU");
}
instance.roleIcon.SetSizeLimit(0.13f);
@@ -1951,8 +1873,7 @@ public static class RoleGuidePatches
instance.roleDescription.text =
$"<size=60%>{modifier.ModifierCategoryTitle}</size>\n" + modifier.ModifierMedDescription;
instance.roleIcon.sprite = modifier.ModifierIcon?.LoadAsset();
var text = GetPanelCountText(modifier, numPerGame, chancePerGame, modifier.ParentMod.MiraPlugin.GetAbbreviatedModName());
SetPanelCount(instance, text);
SetPanelCount(instance, numPerGame, chancePerGame, modifier.ParentMod.MiraPlugin.GetAbbreviatedModName());
instance.roleIcon.SetSizeLimit(0.13f);
instance.roleIcon.material.SetInt(PlayerMaterial.MaskLayer, 50);
-6
View File
@@ -1,7 +1,6 @@
using System.Globalization;
using System.Linq;
using BepInEx.Configuration;
using MiraAPI.Translation;
namespace MiraAPI.PluginLoading;
@@ -59,11 +58,6 @@ public interface IMiraPlugin
/// </summary>
string CustomOptionMenuTwoDescription => "Apply game settings for this mod!";
/// <summary>
/// Gets the translation id builder for this mod.
/// </summary>
TranslationIdBuilder IdBuilder => TranslationIdBuilder.Default;
/// <summary>
/// Gets the <see cref="ConfigFile"/> for the plugin.
/// </summary>
+3 -6
View File
@@ -280,11 +280,11 @@ public static class CustomRoleManager
while (data.Count > 0)
{
Rpc<SyncRoleOptionsRpc>.Instance.SendTo(PlayerControl.LocalPlayer, targetId, new MiraOptionNetData(false, data.Dequeue()));
Rpc<SyncRoleOptionsRpc>.Instance.SendTo(PlayerControl.LocalPlayer, targetId, data.Dequeue());
}
}
internal static void HandleSyncRoleOptions(bool showNotifs, NetData[] data)
internal static void HandleSyncRoleOptions(NetData[] data)
{
// necessary to disable then re-enable this setting
// we don't know how other plugins handle their configs
@@ -312,10 +312,7 @@ public static class CustomRoleManager
var num = BitConverter.ToInt32(netData.Data, 0);
var chance = BitConverter.ToInt32(netData.Data, 4);
if (showNotifs)
{
HudManager.Instance.Notifier.AddRoleSettingsChangeMessage(role.StringName, num, chance, role.TeamType, false);
}
HudManager.Instance.Notifier.AddRoleSettingsChangeMessage(role.StringName, num, chance, role.TeamType, false);
try
{
-43
View File
@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Text;
using BepInEx.Configuration;
using Il2CppInterop.Runtime.Attributes;
@@ -93,48 +92,6 @@ public interface ICustomRole : IOptionable
_ => MiraLocaleManager.Get("MiraApi.RoleTeam.Other"),
};
/// <summary>
/// Gets a value indicating whether to exclude the "amount" from the displayed amount text within the role guide.
/// </summary>
public virtual bool ShowRoleAsUnique => Configuration.MaxRoleCount == 1;
/// <summary>
/// Gets the displayed amount and chance of the role. Used in the role guide.
/// By default, 0 amount or chance results in a complete 0 amount and chance, so override if necessary.
/// </summary>
/// <param name="amount">The amount of the role.</param>
/// <param name="chance">The chance of the role.</param>
/// <param name="source">The mod source of the role.</param>
/// <returns>The <see cref="string"/> result.</returns>
public virtual string GetAmountText(int amount, int chance, string source)
{
if (amount == 0)
{
chance = 0;
}
if (ShowRoleAsUnique)
{
return string.Format(
CultureInfo.InvariantCulture,
"{0}% ({1})",
chance.ToString(CultureInfo.InvariantCulture),
source);
}
if (chance == 0)
{
amount = 0;
}
return string.Format(
CultureInfo.InvariantCulture,
"{0} at {1}% ({2})",
amount.ToString(CultureInfo.InvariantCulture),
chance.ToString(CultureInfo.InvariantCulture),
source);
}
/// <summary>
/// Gets the <see cref="Color"/> of the role.
/// </summary>
@@ -1,82 +0,0 @@
using System;
using System.Diagnostics.CodeAnalysis;
namespace MiraAPI.Translation;
/// <summary>
/// A utility class that can build ids based on the provided id part.
/// </summary>
public class TranslationIdBuilder
{
/// <summary>
/// Gets an instance of <see cref="TranslationIdBuilder"/> that has default behaviour.
/// </summary>
public static TranslationIdBuilder Default { get; } = new();
/// <summary>
/// Constructs a translation id for a provided enum option value.
/// </summary>
/// <typeparam name="T">The type of the enum.</typeparam>
/// <param name="value">The enum option value.</param>
/// <returns>The constructed translation id.</returns>
public virtual string CreateEnumOptionId<T>(T value)
where T : Enum
{
return CreateEnumOptionId<T>(value.ToString());
}
/// <summary>
/// Constructs a translation id for a provided enum option value.
/// </summary>
/// <typeparam name="T">The type of the enum.</typeparam>
/// <param name="value">The enum option value.</param>
/// <returns>The constructed translation id.</returns>
public virtual string CreateEnumOptionId<T>(string value)
where T : Enum
{
return CreateEnumOptionId(value, typeof(T));
}
/// <summary>
/// Constructs a translation id for a provided enum option value.
/// </summary>
/// <param name="value">The enum option value.</param>
/// <param name="enumType">The type of the enum.</param>
/// <returns>The constructed translation id.</returns>
public virtual string CreateEnumOptionId(object value, Type enumType)
{
return CreateEnumOptionId(value.ToString()!, enumType);
}
/// <summary>
/// Constructs a translation id for a provided enum option value.
/// </summary>
/// <param name="value">The enum option value.</param>
/// <param name="enumType">The type of the enum.</param>
/// <returns>The constructed translation id.</returns>
public virtual string CreateEnumOptionId(string value, Type enumType)
{
return value;
}
/// <summary>
/// Constructs a translation id for a string option.
/// </summary>
/// <param name="option">The id part.</param>
/// <returns>The constructed translation id.</returns>
[SuppressMessage("Naming", "CA1716:Identifiers should not match keywords", Justification = "Just confusing.")]
public virtual string CreateStringOptionId(string option)
{
return option;
}
/// <summary>
/// Constructs a translation id for an option's title.
/// </summary>
/// <param name="title">The id part.</param>
/// <returns>The constructed translation id.</returns>
public virtual string CreateOptionTitleId(string title)
{
return title;
}
}
-31
View File
@@ -1,31 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace MiraAPI.Utilities;
/// <summary>
/// A comparer used to sort role/modifier IDs based on which ones are currently active.
/// </summary>
/// <param name="activeIds">The collection of currently active IDs.</param>
public class BasicGuideComparer(IEnumerable<uint> activeIds) : IComparer<uint>
{
/// <inheritdoc/>
public int Compare(uint x, uint y)
{
var xActive = activeIds.Contains(x);
var yActive = activeIds.Contains(y);
if (xActive && !yActive)
{
return -1;
}
if (!xActive && yActive)
{
return 1;
}
return 0;
}
}