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;
}
}