diff --git a/src/Patches/Gameplay/Anticheat/VoteBanSystemPatch.cs b/src/Patches/Gameplay/Anticheat/VoteBanSystemPatch.cs
index 30f7e6e..c078ec1 100644
--- a/src/Patches/Gameplay/Anticheat/VoteBanSystemPatch.cs
+++ b/src/Patches/Gameplay/Anticheat/VoteBanSystemPatch.cs
@@ -2,6 +2,7 @@
using BetterAmongUs.Managers;
using BetterAmongUs.Modules;
using BetterAmongUs.Modules.Support;
+using BetterAmongUs.Structs;
using HarmonyLib;
namespace BetterAmongUs.Patches.Gameplay.Anticheat;
@@ -9,7 +10,7 @@ namespace BetterAmongUs.Patches.Gameplay.Anticheat;
[HarmonyPatch]
internal static class VoteBanSystemPatch
{
- private static readonly List<(int ClientId, (ushort HashPuid, string FriendCode) Voter)> _voteData = [];
+ private static readonly List<(int ClientId, TempClientData Voter)> _voteData = [];
[HarmonyPatch(typeof(VoteBanSystem), nameof(VoteBanSystem.Awake))]
[HarmonyPrefix]
@@ -21,7 +22,7 @@ internal static class VoteBanSystemPatch
[HarmonyPatch(typeof(VoteBanSystem), nameof(VoteBanSystem.AddVote))]
[HarmonyPrefix]
- private static bool VoteBanSystem_AddVote_Prefix(VoteBanSystem __instance, int srcClient, int clientId, ref bool __state)
+ private static bool VoteBanSystem_AddVote_Prefix(int srcClient, int clientId, ref bool __state)
{
__state = false;
@@ -38,8 +39,10 @@ internal static class VoteBanSystemPatch
var client = Utils.ClientFromClientId(srcClient);
if (client == null) return false;
+ var tempClient = new TempClientData(client);
+
// Allow host to vote without restrictions
- if (client.Id == AmongUsClient.Instance.GetHost().Id)
+ if (tempClient.Id == AmongUsClient.Instance.GetHost().Id)
{
return true;
}
@@ -61,25 +64,22 @@ internal static class VoteBanSystemPatch
}
// If client has no ID, allow vote but log it
- if (string.IsNullOrEmpty(client.ProductUserId) && string.IsNullOrEmpty(client.FriendCode))
+ if (string.IsNullOrEmpty(tempClient.Puid) && string.IsNullOrEmpty(tempClient.FriendCode))
{
__state = true;
return true;
}
- // Generate hash for client's ProductUserId
- var clientHash = Utils.GetHashUInt16(client.ProductUserId);
-
// Check if this client has already voted for the same target
- foreach (var (targetClientId, (existingHash, existingFriendCode)) in _voteData)
+ foreach (var (targetClientId, existingVoter) in _voteData)
{
if (targetClientId != clientId)
continue;
// Detect duplicate votes by comparing hash or friend code
- bool isDuplicateVote = existingHash == clientHash ||
- !string.IsNullOrEmpty(client.FriendCode) &&
- existingFriendCode == client.FriendCode;
+ bool isDuplicateVote = existingVoter.HashPuid == tempClient.HashPuid ||
+ !string.IsNullOrEmpty(tempClient.FriendCode) &&
+ existingVoter.FriendCode == tempClient.FriendCode;
if (isDuplicateVote)
{
@@ -89,7 +89,7 @@ internal static class VoteBanSystemPatch
}
// Record the vote
- _voteData.Add((clientId, (clientHash, client.FriendCode)));
+ _voteData.Add((clientId, tempClient));
__state = true;
return true;
}
@@ -111,11 +111,9 @@ internal static class VoteBanSystemPatch
private static void LogVote(VoteBanSystem voteBanSystem, int srcClient, int clientId)
{
- // Get source and target client info
var src = Utils.ClientFromClientId(srcClient);
var client = Utils.ClientFromClientId(clientId);
- // Calculate current votes and required votes
int currentVotes = 0;
int maxVotes = 0;
@@ -125,7 +123,6 @@ internal static class VoteBanSystemPatch
maxVotes = votes.Length; // Total possible votes
}
- // Log vote with colored player names and vote count
Logger_.InGame(
$"{src.Character?.GetPlayerNameAndColor() ?? src.PlayerName} " +
$"voted to kick {client.Character?.GetPlayerNameAndColor() ?? client.PlayerName} " +
diff --git a/src/Structs/TempClientData.cs b/src/Structs/TempClientData.cs
new file mode 100644
index 0000000..61724d9
--- /dev/null
+++ b/src/Structs/TempClientData.cs
@@ -0,0 +1,36 @@
+using BetterAmongUs.Helpers;
+using InnerNet;
+
+namespace BetterAmongUs.Structs;
+
+///
+/// Represents temporary client data for caching or snapshot purposes.
+///
+/// The client data to copy values from.
+internal readonly struct TempClientData(ClientData clientData)
+{
+ ///
+ /// Gets the unique identifier of the client.
+ ///
+ internal readonly int Id = clientData.Id;
+
+ ///
+ /// Gets the product user ID (PUID) of the client.
+ ///
+ internal readonly string Puid = clientData.ProductUserId;
+
+ ///
+ /// Gets the hashed product user ID.
+ ///
+ internal readonly string HashPuid = Utils.GetHashStr(clientData.ProductUserId);
+
+ ///
+ /// Gets the friend code of the client.
+ ///
+ internal readonly string FriendCode = clientData.FriendCode;
+
+ ///
+ /// Gets the player name of the client.
+ ///
+ internal readonly string PlayerName = clientData.PlayerName;
+}
\ No newline at end of file