From 3cba870980ec253b41341808ad74b1044a2c2c42 Mon Sep 17 00:00:00 2001 From: XtraCube <72575280+XtraCube@users.noreply.github.com> Date: Wed, 12 Mar 2025 22:30:54 -0400 Subject: [PATCH] add ProcessVotesEvent.cs and remove "weighting" --- .../Vanilla/Meeting/Voting/HandleVoteEvent.cs | 2 +- .../Meeting/Voting/ProcessVotesEvent.cs | 48 +++++++++++++++++++ MiraAPI/Patches/Voting/MeetingHudPatches.cs | 18 ++++--- MiraAPI/Voting/CustomVote.cs | 3 +- MiraAPI/Voting/PlayerVoteData.cs | 5 +- MiraAPI/Voting/PopulateResultsRpc.cs | 3 +- MiraAPI/Voting/VotingUtils.cs | 26 ++++++++-- 7 files changed, 88 insertions(+), 17 deletions(-) create mode 100644 MiraAPI/Events/Vanilla/Meeting/Voting/ProcessVotesEvent.cs diff --git a/MiraAPI/Events/Vanilla/Meeting/Voting/HandleVoteEvent.cs b/MiraAPI/Events/Vanilla/Meeting/Voting/HandleVoteEvent.cs index a0c7f75..93005de 100644 --- a/MiraAPI/Events/Vanilla/Meeting/Voting/HandleVoteEvent.cs +++ b/MiraAPI/Events/Vanilla/Meeting/Voting/HandleVoteEvent.cs @@ -17,7 +17,7 @@ public class HandleVoteEvent : MiraCancelableEvent /// /// Gets the player who voted. /// - public PlayerControl? Player { get; } + public PlayerControl Player { get; } /// /// Gets the player id of the target. diff --git a/MiraAPI/Events/Vanilla/Meeting/Voting/ProcessVotesEvent.cs b/MiraAPI/Events/Vanilla/Meeting/Voting/ProcessVotesEvent.cs new file mode 100644 index 0000000..9ecaab0 --- /dev/null +++ b/MiraAPI/Events/Vanilla/Meeting/Voting/ProcessVotesEvent.cs @@ -0,0 +1,48 @@ +using System.Collections.Generic; +using System.Linq; +using MiraAPI.Voting; + +namespace MiraAPI.Events.Vanilla.Meeting.Voting; + +/// +/// Ran after calculating votes and before displaying the results. Only ran on the host. +/// +/// +/// Initializes a new instance of the class. +/// +/// >The list of votes that are being processed. +/// The player to be exiled. Will be null if no player is to be exiled. +public class ProcessVotesEvent(List votes, NetworkedPlayerInfo? exiledPlayer = null) : MiraEvent +{ + private readonly List _originalVotes = [.. votes]; + + private NetworkedPlayerInfo? _exiledPlayer = exiledPlayer; + + /// + /// Gets a value indicating whether the exiled player has been modified by the event. + /// + public bool ExiledPlayerModified { get; private set; } + + /// + /// Gets a value indicating whether the votes have been modified by the event. + /// + public bool VotesModified => !Votes.SequenceEqual(_originalVotes); + + /// + /// Gets the list of votes that are being processed. + /// + public List Votes { get; } = votes; + + /// + /// Gets or sets the player to be exiled. Will be null if no player is to be exiled. + /// + public NetworkedPlayerInfo? ExiledPlayer + { + get => _exiledPlayer; + set + { + _exiledPlayer = value; + ExiledPlayerModified = true; + } + } +} diff --git a/MiraAPI/Patches/Voting/MeetingHudPatches.cs b/MiraAPI/Patches/Voting/MeetingHudPatches.cs index c437b36..c7babda 100644 --- a/MiraAPI/Patches/Voting/MeetingHudPatches.cs +++ b/MiraAPI/Patches/Voting/MeetingHudPatches.cs @@ -173,23 +173,29 @@ internal static class MeetingHudPatches [HarmonyPatch(nameof(MeetingHud.CheckForEndVoting))] public static bool EndCheck(MeetingHud __instance) { - if (Helpers.GetAlivePlayers().Exists(plr => plr.GetVoteData()!.VotesRemaining > 0)) + if (Helpers.GetAlivePlayers().Exists(plr => plr.GetVoteData().VotesRemaining > 0)) { return false; } var votes = VotingUtils.CalculateVotes(); + var exiled = VotingUtils.GetExiled(votes, out var isTie); - var max = VotingUtils.CalculateNumVotes(votes).MaxPair(out var isTie); - var exiled = GameData.Instance.AllPlayers.ToArray().FirstOrDefault(v => !isTie && v.PlayerId == max.Key); + var @event = new ProcessVotesEvent(votes, exiled); + MiraEventManager.InvokeEvent(@event); - if (exiled is null || exiled.IsDead || exiled.Disconnected) + if (@event.VotesModified) { - exiled = null; + votes = @event.Votes; + exiled = VotingUtils.GetExiled(votes, out isTie); + } + + if (@event.ExiledPlayerModified) + { + exiled = @event.ExiledPlayer; } __instance.RpcVotingComplete(new MeetingHud.VoterState[__instance.playerStates.Length], exiled, isTie); - return false; } diff --git a/MiraAPI/Voting/CustomVote.cs b/MiraAPI/Voting/CustomVote.cs index fdb0a07..b36796a 100644 --- a/MiraAPI/Voting/CustomVote.cs +++ b/MiraAPI/Voting/CustomVote.cs @@ -5,5 +5,4 @@ /// /// The player that voted. /// The suspect being voted for. -/// The weight of the vote for calculations. -public record struct CustomVote(byte Voter, byte Suspect, float Weight = 1f); +public record struct CustomVote(byte Voter, byte Suspect); diff --git a/MiraAPI/Voting/PlayerVoteData.cs b/MiraAPI/Voting/PlayerVoteData.cs index 023c83e..b7a1b84 100644 --- a/MiraAPI/Voting/PlayerVoteData.cs +++ b/MiraAPI/Voting/PlayerVoteData.cs @@ -56,10 +56,9 @@ public class PlayerVoteData(nint cppPtr) : MonoBehaviour(cppPtr) /// Adds the voted player to the list. /// /// The target's playerId. - /// The weight of the vote. - public void VoteForPlayer(byte playerId, float weight=1f) + public void VoteForPlayer(byte playerId) { - Votes.Add(new CustomVote(Owner.PlayerId, playerId, weight)); + Votes.Add(new CustomVote(Owner.PlayerId, playerId)); } /// diff --git a/MiraAPI/Voting/PopulateResultsRpc.cs b/MiraAPI/Voting/PopulateResultsRpc.cs index 042fb43..24d21ff 100644 --- a/MiraAPI/Voting/PopulateResultsRpc.cs +++ b/MiraAPI/Voting/PopulateResultsRpc.cs @@ -28,7 +28,6 @@ public class PopulateResultsRpc(MiraApiPlugin plugin, uint id) : PlayerCustomRpc { writer.Write(t.Voter); writer.Write(t.Suspect); - writer.Write(t.Weight); } } @@ -39,7 +38,7 @@ public class PopulateResultsRpc(MiraApiPlugin plugin, uint id) : PlayerCustomRpc for (var i = 0; i < votes.Length; i++) { - votes[i] = new CustomVote(reader.ReadByte(), reader.ReadByte(), reader.ReadSingle()); + votes[i] = new CustomVote(reader.ReadByte(), reader.ReadByte()); } return votes; diff --git a/MiraAPI/Voting/VotingUtils.cs b/MiraAPI/Voting/VotingUtils.cs index d152589..56833a6 100644 --- a/MiraAPI/Voting/VotingUtils.cs +++ b/MiraAPI/Voting/VotingUtils.cs @@ -16,6 +16,26 @@ public static class VotingUtils { private const byte SkipVoteId = 253; + /// + /// Gets the exiled player from the list of votes. Returns null if no player is to be exiled. + /// + /// >The list of votes to check. + /// Whether the vote is a tie. + /// The player to be exiled. Will be null if no player is to be exiled. + public static NetworkedPlayerInfo? GetExiled(List votes, out bool isTie) + { + var max = CalculateNumVotes(votes).MaxPair(out var tie); + isTie = tie; + var exiled = GameData.Instance.AllPlayers.ToArray().FirstOrDefault(v => !tie && v.PlayerId == max.Key); + + if (exiled is null || exiled.IsDead || exiled.Disconnected) + { + exiled = null; + } + + return exiled; + } + /// /// Handles when a vote is added and allows for other mods to override/modify. /// @@ -83,11 +103,11 @@ public static class VotingUtils { var dictionary = new Dictionary(); - foreach (var vote in votes) + foreach (var vote in votes.Select(v=>v.Suspect)) { - if (!dictionary.TryAdd(vote.Suspect, vote.Weight)) + if (!dictionary.TryAdd(vote, 1)) { - dictionary[vote.Suspect] += vote.Weight; + dictionary[vote] += 1; } }