mirror of
https://github.com/D1GQ/BetterAmongUs.git
synced 2026-10-20 01:46:19 +00:00
22 files changed
+677
-120
No files matched your search
+111
-25
@@ -1,6 +1,8 @@
|
||||
using AmongUs.GameOptions;
|
||||
using HarmonyLib;
|
||||
using Hazel;
|
||||
using InnerNet;
|
||||
using UnityEngine;
|
||||
|
||||
namespace BetterAmongUs;
|
||||
|
||||
@@ -11,6 +13,50 @@ class AntiCheat
|
||||
public static Dictionary<string, string> AUMData = []; // HashPuid, FriendCode
|
||||
private static bool IsEnabled = true;
|
||||
|
||||
public static void Update()
|
||||
{
|
||||
if (GameStates.IsInGame)
|
||||
{
|
||||
foreach (var kvp in ExtendedPlayerControl.TimeSinceKill)
|
||||
{
|
||||
ExtendedPlayerControl.TimeSinceKill[kvp.Key] += Time.deltaTime;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ExtendedPlayerControl.TimeSinceKill.Any())
|
||||
{
|
||||
ExtendedPlayerControl.TimeSinceKill.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
if (GameStates.IsHost && GameStates.IsInGame)
|
||||
{
|
||||
RPC.SyncAllNames(isBetterHost: false);
|
||||
|
||||
foreach (var player in Main.AllPlayerControls)
|
||||
{
|
||||
var hashPuid = Utils.GetHashPuid(player);
|
||||
|
||||
if (SickoData.ContainsKey(hashPuid))
|
||||
{
|
||||
player.RpcSetName($"<color=#ffea00>{player.Data.PlayerName}</color> Has been banned by <color=#4f92ff>Anti-Cheat</color>, Reason: Known Sicko Menu User<size=0%>");
|
||||
AmongUsClient.Instance.KickPlayer(player.GetClientId(), true);
|
||||
}
|
||||
else if (AUMData.ContainsKey(hashPuid))
|
||||
{
|
||||
player.RpcSetName($"<color=#ffea00>{player.Data.PlayerName}</color> Has been banned by <color=#4f92ff>Anti-Cheat</color>, Reason: Known AUM User<size=0%>");
|
||||
AmongUsClient.Instance.KickPlayer(player.GetClientId(), true);
|
||||
}
|
||||
else if (PlayerData.ContainsKey(hashPuid))
|
||||
{
|
||||
player.RpcSetName($"<color=#ffea00>{player.Data.PlayerName}</color> Has been banned by <color=#4f92ff>Anti-Cheat</color>, Reason: Known Cheater<size=0%>");
|
||||
AmongUsClient.Instance.KickPlayer(player.GetClientId(), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void PauseAntiCheat()
|
||||
{
|
||||
float time = 2f;
|
||||
@@ -25,10 +71,44 @@ class AntiCheat
|
||||
}
|
||||
}
|
||||
|
||||
[HarmonyPatch(typeof(PlatformSpecificData))]
|
||||
class PlatformSpecificDataPatch
|
||||
{
|
||||
[HarmonyPatch(nameof(PlatformSpecificData.Deserialize))]
|
||||
[HarmonyPostfix]
|
||||
public static void Deserialize_Postfix(PlatformSpecificData __instance)
|
||||
{
|
||||
_ = new LateTask(() =>
|
||||
{
|
||||
var player = Main.AllPlayerControls.FirstOrDefault(pc => pc.GetClient().PlatformData == __instance);
|
||||
|
||||
if (player != null)
|
||||
{
|
||||
if (__instance.Platform is Platforms.StandaloneWin10 or Platforms.Xbox)
|
||||
{
|
||||
if (__instance.XboxPlatformId == 0)
|
||||
{
|
||||
BetterNotificationManager.NotifyCheat(player, $"Platform Spoofer", newText: "Has been detected with a cheat");
|
||||
}
|
||||
}
|
||||
|
||||
if (__instance.Platform is Platforms.Playstation)
|
||||
{
|
||||
if (__instance.PsnPlatformId == 0)
|
||||
{
|
||||
BetterNotificationManager.NotifyCheat(player, $"Platform Spoofer", newText: "Has been detected with a cheat");
|
||||
}
|
||||
}
|
||||
}
|
||||
}, 1.5f, shoudLog: false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Handle RPC before anti cheat detection
|
||||
public static void HandleRPCBeforeCheck(PlayerControl player, byte callId, MessageReader Oldreader)
|
||||
{
|
||||
MessageReader reader = Oldreader;
|
||||
MessageReader reader = MessageReader.Get(Oldreader);
|
||||
|
||||
if (player == PlayerControl.LocalPlayer || PlayerControl.LocalPlayer == null || player == null || !IsEnabled) return;
|
||||
|
||||
@@ -41,11 +121,9 @@ class AntiCheat
|
||||
if (reader.BytesRemaining == 0 && !flag)
|
||||
{
|
||||
AmongUsClient.Instance.ReportPlayer(player.GetClientId(), ReportReasons.Cheating_Hacking);
|
||||
BetterNotificationManager.NotifyCheat(player, $"Sicko Menu", newText: "Has been detected with a cheat client");
|
||||
PlayerData[Utils.GetHashPuid(player)] = player.FriendCode;
|
||||
SickoData[Utils.GetHashPuid(player)] = player.FriendCode;
|
||||
BetterDataManager.SaveCheatData(Utils.GetHashPuid(player), player.Data.FriendCode, player.Data.PlayerName, "cheatData", "Sicko Menu RPC");
|
||||
BetterDataManager.SaveCheatData(Utils.GetHashPuid(player), player.Data.FriendCode, player.Data.PlayerName, "sickoData", "Sicko Menu RPC");
|
||||
BetterNotificationManager.NotifyCheat(player, $"Sicko Menu", newText: "Has been detected with a cheat client");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,11 +143,9 @@ class AntiCheat
|
||||
if (!flag)
|
||||
{
|
||||
AmongUsClient.Instance.ReportPlayer(player.GetClientId(), ReportReasons.Cheating_Hacking);
|
||||
BetterNotificationManager.NotifyCheat(player, $"AUM", newText: "Has been detected with a cheat client");
|
||||
PlayerData[Utils.GetHashPuid(player)] = player.FriendCode;
|
||||
AUMData[Utils.GetHashPuid(player)] = player.FriendCode;
|
||||
BetterDataManager.SaveCheatData(Utils.GetHashPuid(player), player.Data.FriendCode, player.Data.PlayerName, "cheatData", "AUM RPC");
|
||||
BetterDataManager.SaveCheatData(Utils.GetHashPuid(player), player.Data.FriendCode, player.Data.PlayerName, "aumData", "AUM RPC");
|
||||
BetterNotificationManager.NotifyCheat(player, $"AUM", newText: "Has been detected with a cheat client");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -98,11 +174,9 @@ class AntiCheat
|
||||
if (!flag && !flag2)
|
||||
{
|
||||
AmongUsClient.Instance.ReportPlayer(player.GetClientId(), ReportReasons.Cheating_Hacking);
|
||||
BetterNotificationManager.NotifyCheat(AUMPlayer, $"AUM", newText: "Has been detected with a cheat client");
|
||||
PlayerData[Utils.GetHashPuid(AUMPlayer)] = AUMPlayer.FriendCode;
|
||||
AUMData[Utils.GetHashPuid(AUMPlayer)] = AUMPlayer.FriendCode;
|
||||
BetterDataManager.SaveCheatData(Utils.GetHashPuid(player), player.Data.FriendCode, player.Data.PlayerName, "cheatData", "AUM Chat RPC");
|
||||
BetterDataManager.SaveCheatData(Utils.GetHashPuid(player), player.Data.FriendCode, player.Data.PlayerName, "aumData", "AUM Chat RPC");
|
||||
BetterNotificationManager.NotifyCheat(AUMPlayer, $"AUM", newText: "Has been detected with a cheat client");
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
@@ -114,10 +188,11 @@ class AntiCheat
|
||||
// Check and notify for invalid rpcs
|
||||
public static void CheckRPC(PlayerControl player, byte callId, MessageReader Oldreader)
|
||||
{
|
||||
MessageReader reader = Oldreader;
|
||||
try
|
||||
{
|
||||
if (PlayerControl.LocalPlayer == null || player == null || player == PlayerControl.LocalPlayer || reader == null || !IsEnabled || !Main.AntiCheat.Value) return;
|
||||
MessageReader reader = MessageReader.Get(Oldreader);
|
||||
|
||||
if (PlayerControl.LocalPlayer == null || player == null || player == PlayerControl.LocalPlayer || player.GetIsBetterHost() || reader == null || !IsEnabled || !Main.AntiCheat.Value) return;
|
||||
|
||||
RoleTypes? Role = player?.Data?.RoleType;
|
||||
Role ??= RoleTypes.Crewmate;
|
||||
@@ -125,6 +200,14 @@ class AntiCheat
|
||||
bool IsCrewmate = !player.IsImpostorTeam();
|
||||
string hashPuid = Utils.GetHashPuid(player);
|
||||
|
||||
if (callId is (byte)RpcCalls.SendChat or (byte)RpcCalls.SendQuickChat)
|
||||
{
|
||||
if (player.IsAlive() && GameStates.IsInGamePlay && !GameStates.IsMeeting && !GameStates.IsExilling)
|
||||
BetterNotificationManager.NotifyCheat(player, $"Invalid Action RPC: {Enum.GetName((RpcCalls)callId)}");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (callId is (byte)RpcCalls.EnterVent or (byte)RpcCalls.ExitVent)
|
||||
{
|
||||
if ((IsCrewmate && Role != RoleTypes.Engineer) || player.Data.IsDead)
|
||||
@@ -149,24 +232,17 @@ class AntiCheat
|
||||
|
||||
if (target != null)
|
||||
{
|
||||
if (IsCrewmate || !player.IsAlive() || player.IsInVanish() || !target.IsAlive() || target.IsImpostorTeam())
|
||||
if (IsCrewmate || !player.IsAlive() || player.IsInVanish() || !target.IsAlive() || target.IsImpostorTeam()
|
||||
|| ExtendedPlayerControl.TimeSinceKill.TryGetValue(player, out var value) && value < (float)GameOptionsManager.Instance.currentNormalGameOptions.KillCooldown)
|
||||
{
|
||||
BetterNotificationManager.NotifyCheat(player, $"Invalid Action RPC: {Enum.GetName((RpcCalls)callId)}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
if (callId is (byte)RpcCalls.SendChat or (byte)RpcCalls.SendQuickChat)
|
||||
{
|
||||
if (player.IsAlive() && GameStates.IsInGamePlay && !GameStates.IsMeeting && !GameStates.IsExilling)
|
||||
BetterNotificationManager.NotifyCheat(player, $"Invalid Action RPC: {Enum.GetName((RpcCalls)callId)}");
|
||||
|
||||
return;
|
||||
}
|
||||
*/
|
||||
|
||||
if (callId is (byte)RpcCalls.SetLevel)
|
||||
{
|
||||
if (reader.BytesRemaining > 0)
|
||||
@@ -239,10 +315,11 @@ class AntiCheat
|
||||
// Check notify and cancel out request for invalid rpcs
|
||||
public static bool CheckCancelRPC(PlayerControl player, byte callId, MessageReader Oldreader)
|
||||
{
|
||||
MessageReader reader = Oldreader;
|
||||
try
|
||||
{
|
||||
if (PlayerControl.LocalPlayer == null || player == null || player == PlayerControl.LocalPlayer || reader == null || !IsEnabled || !Main.AntiCheat.Value) return true;
|
||||
MessageReader reader = MessageReader.Get(Oldreader);
|
||||
|
||||
if (PlayerControl.LocalPlayer == null || player == null || player == PlayerControl.LocalPlayer || player.GetIsBetterHost() || reader == null || !IsEnabled || !Main.AntiCheat.Value) return true;
|
||||
|
||||
RoleTypes Role = player.Data.RoleType;
|
||||
bool IsImpostor = player.IsImpostorTeam();
|
||||
@@ -254,6 +331,15 @@ class AntiCheat
|
||||
return false;
|
||||
}
|
||||
|
||||
if (callId is (byte)RpcCalls.StartMeeting or (byte)RpcCalls.ReportDeadBody)
|
||||
{
|
||||
if (GameStates.IsMeeting || GameStates.IsExilling)
|
||||
{
|
||||
BetterNotificationManager.NotifyCheat(player, $"Invalid Action RPC: {Enum.GetName((RpcCalls)callId)}");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (callId is (byte)RpcCalls.Shapeshift)
|
||||
{
|
||||
var flag = reader.ReadBoolean();
|
||||
|
||||
@@ -1,13 +1,67 @@
|
||||
using AmongUs.GameOptions;
|
||||
using Hazel;
|
||||
using InnerNet;
|
||||
using UnityEngine;
|
||||
using System.Text;
|
||||
|
||||
namespace BetterAmongUs;
|
||||
|
||||
class BetterHostManager
|
||||
{
|
||||
public static Dictionary<byte, Dictionary<byte, string>> LastPlayerName = []; // Targetid, Playerid, Name
|
||||
private static Dictionary<byte, Dictionary<byte, string>> LastPlayerName = []; // Targetid, Playerid, Name
|
||||
private static List<PlayerControl> VentStuck = [];
|
||||
|
||||
public static void Update(PlayerControl player)
|
||||
{
|
||||
if (!Main.BetterHost.Value) return;
|
||||
|
||||
// Lock up player vent button if it's invalid vent
|
||||
if (!VentStuck.Contains(player) && player.inVent && !player.Is(RoleTypes.Engineer) && !player.IsImpostorTeam())
|
||||
{
|
||||
player.MyPhysics.RpcEnterVent(player.GetPlayerVentId());
|
||||
player.MyPhysics.RpcBootFromVent(player.GetPlayerVentId());
|
||||
VentStuck.Add(player);
|
||||
}
|
||||
}
|
||||
|
||||
public static bool IsSpeedExceeding(float currentSpeed)
|
||||
{
|
||||
float leniency = 1.8f;
|
||||
float thresholdSpeed = GetAverageSpeed() + leniency;
|
||||
bool isExceeding = currentSpeed > thresholdSpeed;
|
||||
return isExceeding;
|
||||
}
|
||||
|
||||
public static float GetAverageSpeed()
|
||||
{
|
||||
float speedMod = GameStates.IsHideNSeek
|
||||
? GameOptionsManager.Instance.currentHideNSeekGameOptions.PlayerSpeedMod
|
||||
: GameOptionsManager.Instance.currentNormalGameOptions.PlayerSpeedMod;
|
||||
|
||||
// Data points
|
||||
float[] mods = { 0.5f, 1.5f, 2.0f }; // Add more as needed
|
||||
float[] avgSpeeds = { 1.3f, 3.75f, 5.0f }; // Add corresponding speeds
|
||||
|
||||
int n = mods.Length;
|
||||
float sumMod = 0, sumAvgSpeed = 0, sumModAvgSpeed = 0, sumModSquared = 0;
|
||||
|
||||
for (int i = 0; i < n; i++)
|
||||
{
|
||||
sumMod += mods[i];
|
||||
sumAvgSpeed += avgSpeeds[i];
|
||||
sumModAvgSpeed += mods[i] * avgSpeeds[i];
|
||||
sumModSquared += mods[i] * mods[i];
|
||||
}
|
||||
|
||||
float m = (n * sumModAvgSpeed - sumMod * sumAvgSpeed) / (n * sumModSquared - sumMod * sumMod);
|
||||
float c = (sumAvgSpeed - m * sumMod) / n;
|
||||
|
||||
float estimatedAverageSpeed = m * speedMod + c;
|
||||
|
||||
return estimatedAverageSpeed;
|
||||
}
|
||||
|
||||
public static bool CheckRange(Vector2 pos1, Vector2 pos2, float range) => Vector2.Distance(pos1, pos2) <= range;
|
||||
|
||||
public static bool CheckRPCAsHost(PlayerControl player, byte callId, MessageReader reader, ref bool canceled)
|
||||
{
|
||||
@@ -22,7 +76,10 @@ class BetterHostManager
|
||||
PlayerControl target = reader.ReadNetObject<PlayerControl>();
|
||||
if (target != null)
|
||||
{
|
||||
if (player.Data.Role is GuardianAngelRole && player.IsAlive() && !player.IsImpostorTeam())
|
||||
if (player.Is(RoleTypes.GuardianAngel)
|
||||
&& !player.IsAlive()
|
||||
&& !player.IsImpostorTeam()
|
||||
&& CheckRange(player.GetCustomPosition(), target.GetCustomPosition(), 3f))
|
||||
{
|
||||
if (target.IsAlive())
|
||||
{
|
||||
@@ -39,11 +96,26 @@ class BetterHostManager
|
||||
case (byte)RpcCalls.CheckMurder:
|
||||
{
|
||||
PlayerControl target = reader.ReadNetObject<PlayerControl>();
|
||||
|
||||
if (target != null)
|
||||
{
|
||||
if (player.IsAlive() && player.IsImpostorTeam() && !player.inMovingPlat && !player.IsInVent() && !player.IsInVanish() && !player.shapeshifting && !player.MyPhysics.Animations.IsPlayingAnyLadderAnimation())
|
||||
if (player.IsAlive()
|
||||
&& player.IsImpostorTeam()
|
||||
&& !player.inMovingPlat
|
||||
&& !player.IsInVent()
|
||||
&& !player.IsInVanish()
|
||||
&& !player.shapeshifting
|
||||
&& !player.onLadder
|
||||
&& !player.MyPhysics.Animations.IsPlayingAnyLadderAnimation()
|
||||
&& ExtendedPlayerControl.TimeSinceKill.TryGetValue(player, out var value) && value >= (float)GameOptionsManager.Instance.currentNormalGameOptions.KillCooldown
|
||||
&& CheckRange(player.GetCustomPosition(), target.GetCustomPosition(), 3f))
|
||||
{
|
||||
if (target.IsAlive() && !target.IsImpostorTeam() && !target.inMovingPlat && !target.IsInVent() && !target.MyPhysics.Animations.IsPlayingAnyLadderAnimation())
|
||||
if (target.IsAlive()
|
||||
&& !target.IsImpostorTeam()
|
||||
&& !target.inMovingPlat
|
||||
&& !target.IsInVent()
|
||||
&& !target.onLadder
|
||||
&& !target.MyPhysics.Animations.IsPlayingAnyLadderAnimation())
|
||||
{
|
||||
player.RpcMurderPlayer(target, true);
|
||||
break;
|
||||
@@ -62,7 +134,13 @@ class BetterHostManager
|
||||
|
||||
if (target != null)
|
||||
{
|
||||
if (player.Data.RoleType == RoleTypes.Shapeshifter && player.IsAlive() && player.IsImpostorTeam() && !player.inMovingPlat && !player.shapeshifting && !player.MyPhysics.Animations.IsPlayingAnyLadderAnimation())
|
||||
if (player.Is(RoleTypes.Shapeshifter)
|
||||
&& player.IsAlive()
|
||||
&& player.IsImpostorTeam()
|
||||
&& !player.inMovingPlat
|
||||
&& !player.shapeshifting
|
||||
&& !player.onLadder
|
||||
&& !player.MyPhysics.Animations.IsPlayingAnyLadderAnimation())
|
||||
{
|
||||
if (!target.IsInVent() && flag == false)
|
||||
{
|
||||
@@ -80,7 +158,13 @@ class BetterHostManager
|
||||
|
||||
case (byte)RpcCalls.CheckVanish:
|
||||
{
|
||||
if (player.Data.RoleType == RoleTypes.Phantom && player.IsAlive() && player.IsImpostorTeam() && !player.IsInVent() && !player.inMovingPlat && !player.MyPhysics.Animations.IsPlayingAnyLadderAnimation())
|
||||
if (player.Is(RoleTypes.Phantom)
|
||||
&& player.IsAlive()
|
||||
&& player.IsImpostorTeam()
|
||||
&& !player.IsInVent()
|
||||
&& !player.inMovingPlat
|
||||
&& !player.onLadder
|
||||
&& !player.MyPhysics.Animations.IsPlayingAnyLadderAnimation())
|
||||
{
|
||||
|
||||
if (AmongUsClient.Instance.AmClient)
|
||||
@@ -100,7 +184,11 @@ class BetterHostManager
|
||||
{
|
||||
bool flag = reader.ReadBoolean();
|
||||
|
||||
if (player.Data.RoleType == RoleTypes.Phantom && player.IsAlive() && player.IsImpostorTeam() && !player.inMovingPlat && !player.MyPhysics.Animations.IsPlayingAnyLadderAnimation())
|
||||
if (player.Is(RoleTypes.Phantom)
|
||||
&& player.IsAlive() && player.IsImpostorTeam()
|
||||
&& !player.inMovingPlat
|
||||
&& !player.onLadder
|
||||
&& !player.MyPhysics.Animations.IsPlayingAnyLadderAnimation())
|
||||
{
|
||||
if (!player.IsInVent() && flag == false)
|
||||
{
|
||||
@@ -159,6 +247,9 @@ class BetterHostManager
|
||||
{
|
||||
NewName = player.Data.PlayerName;
|
||||
|
||||
if (player.IsHost())
|
||||
NewName = player.GetPlayerNameAndColor();
|
||||
|
||||
if (player.IsDev())
|
||||
sbTopTag.Append("<color=#6e6e6e>(<color=#0088ff>Dev</color>)</color>+++");
|
||||
|
||||
|
||||
@@ -72,7 +72,7 @@ class BetterNotificationManager
|
||||
BAUNotificationManagerObj.transform.position = AspectPosition.ComputeWorldPosition(localCamera, AspectPosition.EdgeAlignments.Bottom, new Vector3(-1.3f, 0.7f, localCamera.nearClipPlane + 0.1f));
|
||||
|
||||
showTime -= Time.deltaTime;
|
||||
if (showTime <= 0f)
|
||||
if (showTime <= 0f && GameStates.IsInGame)
|
||||
{
|
||||
BAUNotificationManagerObj.transform.Find("Sizer/ChatText (TMP)").GetComponent<TextMeshPro>().text = "";
|
||||
BAUNotificationManagerObj.SetActive(false);
|
||||
|
||||
@@ -0,0 +1,200 @@
|
||||
using Hazel;
|
||||
using InnerNet;
|
||||
using HarmonyLib;
|
||||
using UnityEngine;
|
||||
|
||||
// Code from: https://github.com/0xDrMoe/TownofHost-Enhanced
|
||||
|
||||
namespace BetterAmongUs;
|
||||
|
||||
[HarmonyPatch(typeof(InnerNetClient))]
|
||||
public class InnerNetClientPatch
|
||||
{
|
||||
[HarmonyPatch(typeof(InnerNetClient), nameof(InnerNetClient.SendInitialData))]
|
||||
[HarmonyPrefix]
|
||||
public static bool SendInitialDataPrefix(InnerNetClient __instance, int clientId)
|
||||
{
|
||||
if (!Constants.IsVersionModded() || __instance.NetworkMode != NetworkModes.OnlineGame) return true;
|
||||
// We make sure other stuffs like playercontrol and Lobby behavior is spawned properly
|
||||
// Then we spawn networked data for new clients
|
||||
MessageWriter messageWriter = MessageWriter.Get(SendOption.Reliable);
|
||||
messageWriter.StartMessage(6);
|
||||
messageWriter.Write(__instance.GameId);
|
||||
messageWriter.WritePacked(clientId);
|
||||
Il2CppSystem.Collections.Generic.List<InnerNetObject> obj = __instance.allObjects;
|
||||
lock (obj)
|
||||
{
|
||||
HashSet<GameObject> hashSet = new HashSet<GameObject>();
|
||||
for (int i = 0; i < __instance.allObjects.Count; i++)
|
||||
{
|
||||
InnerNetObject innerNetObject = __instance.allObjects[i];
|
||||
if (innerNetObject && (innerNetObject.OwnerId != -4 || __instance.AmModdedHost) && hashSet.Add(innerNetObject.gameObject))
|
||||
{
|
||||
GameManager gameManager = innerNetObject as GameManager;
|
||||
if (gameManager != null)
|
||||
{
|
||||
__instance.SendGameManager(clientId, gameManager);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (innerNetObject is not NetworkedPlayerInfo)
|
||||
__instance.WriteSpawnMessage(innerNetObject, innerNetObject.OwnerId, innerNetObject.SpawnFlags, messageWriter);
|
||||
}
|
||||
}
|
||||
}
|
||||
messageWriter.EndMessage();
|
||||
__instance.SendOrDisconnect(messageWriter);
|
||||
messageWriter.Recycle();
|
||||
}
|
||||
DelaySpawnPlayerInfo(__instance, clientId);
|
||||
return false;
|
||||
}
|
||||
|
||||
private static void DelaySpawnPlayerInfo(InnerNetClient __instance, int clientId)
|
||||
{
|
||||
List<NetworkedPlayerInfo> players = GameData.Instance.AllPlayers.ToArray().ToList();
|
||||
|
||||
// We send 5 players at a time to prevent too huge packet
|
||||
while (players.Count > 0)
|
||||
{
|
||||
var batch = players.Take(5).ToList();
|
||||
|
||||
MessageWriter messageWriter = MessageWriter.Get(SendOption.Reliable);
|
||||
messageWriter.StartMessage(6);
|
||||
messageWriter.Write(__instance.GameId);
|
||||
messageWriter.WritePacked(clientId);
|
||||
|
||||
foreach (var player in batch)
|
||||
{
|
||||
if (messageWriter.Length > 1600) break;
|
||||
if (player != null && player.ClientId != clientId && !player.Disconnected)
|
||||
{
|
||||
__instance.WriteSpawnMessage(player, player.OwnerId, player.SpawnFlags, messageWriter);
|
||||
}
|
||||
players.Remove(player);
|
||||
}
|
||||
messageWriter.EndMessage();
|
||||
// Logger.Info($"send delayed network data to {clientId} , size is {messageWriter.Length}", "SendInitialDataPrefix");
|
||||
__instance.SendOrDisconnect(messageWriter);
|
||||
messageWriter.Recycle();
|
||||
}
|
||||
}
|
||||
|
||||
[HarmonyPatch(typeof(InnerNetClient), nameof(InnerNetClient.SendAllStreamedObjects))]
|
||||
[HarmonyPrefix]
|
||||
public static bool SendAllStreamedObjectsPrefix(InnerNetClient __instance, ref bool __result)
|
||||
{
|
||||
if (!Constants.IsVersionModded() || __instance.NetworkMode != NetworkModes.OnlineGame) return true;
|
||||
// Bypass all NetworkedData here.
|
||||
__result = false;
|
||||
Il2CppSystem.Collections.Generic.List<InnerNetObject> obj = __instance.allObjects;
|
||||
lock (obj)
|
||||
{
|
||||
for (int i = 0; i < __instance.allObjects.Count; i++)
|
||||
{
|
||||
InnerNetObject innerNetObject = __instance.allObjects[i];
|
||||
if (innerNetObject && innerNetObject is not NetworkedPlayerInfo && innerNetObject.IsDirty && (innerNetObject.AmOwner || (innerNetObject.OwnerId == -2 && __instance.AmHost)))
|
||||
{
|
||||
MessageWriter messageWriter = __instance.Streams[(int)innerNetObject.sendMode];
|
||||
messageWriter.StartMessage(1);
|
||||
messageWriter.WritePacked(innerNetObject.NetId);
|
||||
try
|
||||
{
|
||||
if (innerNetObject.Serialize(messageWriter, false))
|
||||
{
|
||||
messageWriter.EndMessage();
|
||||
}
|
||||
else
|
||||
{
|
||||
messageWriter.CancelMessage();
|
||||
}
|
||||
if (innerNetObject.Chunked && innerNetObject.IsDirty)
|
||||
{
|
||||
__result = true;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Error(ex.ToString());
|
||||
messageWriter.CancelMessage();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int j = 0; j < __instance.Streams.Length; j++)
|
||||
{
|
||||
MessageWriter messageWriter2 = __instance.Streams[j];
|
||||
if (messageWriter2.HasBytes(7))
|
||||
{
|
||||
messageWriter2.EndMessage();
|
||||
__instance.SendOrDisconnect(messageWriter2);
|
||||
messageWriter2.Clear((SendOption)j);
|
||||
messageWriter2.StartMessage(5);
|
||||
messageWriter2.Write(__instance.GameId);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static byte timer = 0;
|
||||
[HarmonyPatch(typeof(InnerNetClient), nameof(InnerNetClient.FixedUpdate))]
|
||||
[HarmonyPostfix]
|
||||
public static void FixedUpdatePostfix(InnerNetClient __instance)
|
||||
{
|
||||
// Send a networked data pre 2 fixed update should be a good practice?
|
||||
if (!Constants.IsVersionModded() || __instance.NetworkMode != NetworkModes.OnlineGame) return;
|
||||
if (!__instance.AmHost || __instance.Streams == null) return;
|
||||
|
||||
if (timer == 0)
|
||||
{
|
||||
timer = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
var player = GameData.Instance.AllPlayers.ToArray().FirstOrDefault(x => x.IsDirty);
|
||||
if (player != null)
|
||||
{
|
||||
timer = 0;
|
||||
MessageWriter messageWriter = MessageWriter.Get(SendOption.Reliable);
|
||||
messageWriter.StartMessage(5);
|
||||
messageWriter.Write(__instance.GameId);
|
||||
messageWriter.StartMessage(1);
|
||||
messageWriter.WritePacked(player.NetId);
|
||||
try
|
||||
{
|
||||
if (player.Serialize(messageWriter, false))
|
||||
{
|
||||
messageWriter.EndMessage();
|
||||
}
|
||||
else
|
||||
{
|
||||
messageWriter.CancelMessage();
|
||||
player.ClearDirtyBits();
|
||||
return;
|
||||
}
|
||||
messageWriter.EndMessage();
|
||||
__instance.SendOrDisconnect(messageWriter);
|
||||
messageWriter.Recycle();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Error(ex.ToString());
|
||||
messageWriter.CancelMessage();
|
||||
player.ClearDirtyBits();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[HarmonyPatch(typeof(GameData), nameof(GameData.DirtyAllData))]
|
||||
internal class DirtyAllDataPatch
|
||||
{
|
||||
// Currently this function only occurs in CreatePlayer
|
||||
// It's believed to lag host, delay the playercontrol spawn mesasge & blackout new client
|
||||
// & send huge packets to all clients & completely no need to run
|
||||
// Temporarily disable it until Innersloth get a better fix.
|
||||
public static bool Prefix()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
using Hazel;
|
||||
using InnerNet;
|
||||
namespace BetterAmongUs;
|
||||
|
||||
static class ExtendedInnerNetClient
|
||||
{
|
||||
/// <summary>
|
||||
/// Starts the RPC desynchronization process for the given player, call ID, and send option.
|
||||
/// </summary>
|
||||
/// <param name="client">The InnerNetClient instance.</param>
|
||||
/// <param name="playerNetId">The network ID of the player.</param>
|
||||
/// <param name="callId">The RPC call ID.</param>
|
||||
/// <param name="option">The send option for the RPC.</param>
|
||||
/// <param name="ignoreClientId">The client ID to ignore. Default is -1, which means no client is ignored.</param>
|
||||
/// <returns>A list of MessageWriter instances for the RPC calls.</returns>
|
||||
/// <example>
|
||||
/// <code>
|
||||
/// List<MessageWriter> messageWriter = AmongUsClient.Instance.StartRpcDesync(PlayerNetId, (byte)RpcCalls, SendOption, ClientId);
|
||||
/// messageWriter.ForEach(mW => mW.Write("RPC TEST"));
|
||||
/// AmongUsClient.Instance.FinishRpcDesync(messageWriter);
|
||||
/// </code>
|
||||
/// </example>
|
||||
/*
|
||||
List<MessageWriter> messageWriter = AmongUsClient.Instance.StartRpcDesync(PlayerNetId, (byte)RpcCalls, SendOption, ClientId);
|
||||
messageWriter.ForEach(mW => mW.Write("RPC TEST"));
|
||||
AmongUsClient.Instance.FinishRpcDesync(messageWriter);
|
||||
*/
|
||||
public static List<MessageWriter> StartRpcDesync(this InnerNetClient client, uint playerNetId, byte callId, SendOption option, int ignoreClientId = -1)
|
||||
{
|
||||
List<MessageWriter> messageWriters = [];
|
||||
|
||||
if (ignoreClientId < 0)
|
||||
{
|
||||
messageWriters.Add(client.StartRpcImmediately(playerNetId, callId, option, -1));
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var allClients in AmongUsClient.Instance.allClients.ToArray().Where(c => c.Id != ignoreClientId))
|
||||
{
|
||||
messageWriters.Add(client.StartRpcImmediately(playerNetId, callId, option, allClients.Id));
|
||||
}
|
||||
}
|
||||
|
||||
return messageWriters;
|
||||
}
|
||||
|
||||
public static void FinishRpcDesync(this InnerNetClient client, List<MessageWriter> messageWriters)
|
||||
{
|
||||
foreach (var msg in messageWriters)
|
||||
{
|
||||
msg.EndMessage();
|
||||
msg.EndMessage();
|
||||
client.SendOrDisconnect(msg);
|
||||
msg.Recycle();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,12 +1,15 @@
|
||||
using AmongUs.GameOptions;
|
||||
using Hazel;
|
||||
using InnerNet;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using static Il2CppSystem.Net.Http.Headers.Parser;
|
||||
|
||||
namespace BetterAmongUs;
|
||||
|
||||
static class ExtendedPlayerControl
|
||||
{
|
||||
public static Dictionary<PlayerControl, float> TimeSinceKill = [];
|
||||
// Get players client
|
||||
public static ClientData? GetClient(this PlayerControl player)
|
||||
{
|
||||
@@ -27,6 +30,8 @@ static class ExtendedPlayerControl
|
||||
var client = player.GetClient();
|
||||
return client == null ? -1 : client.Id;
|
||||
}
|
||||
// Get player name with outfit color
|
||||
public static string GetPlayerNameAndColor(this PlayerControl player) => $"<color={Utils.Color32ToHex(Palette.PlayerColors[player.CurrentOutfit.ColorId])}>{player.Data.PlayerName}</color>";
|
||||
// Set players over head text
|
||||
public static void SetPlayerTextInfo(this PlayerControl player, string text, bool isBottom = false, bool isInfo = false)
|
||||
{
|
||||
@@ -150,6 +155,8 @@ static class ExtendedPlayerControl
|
||||
return "#8cffff";
|
||||
}
|
||||
}
|
||||
// Check if player is role type
|
||||
public static bool Is(this PlayerControl player, RoleTypes role) => player?.Data?.RoleType == role;
|
||||
// Check if player is on imposter team
|
||||
public static bool IsImpostorTeam(this PlayerControl player) => player?.Data != null && (player.Data.RoleType is RoleTypes.Impostor or RoleTypes.ImpostorGhost or RoleTypes.Shapeshifter or RoleTypes.Phantom);
|
||||
// Check if player is a imposter teammate
|
||||
|
||||
@@ -16,7 +16,7 @@ static class ExtendedPlayerInfo
|
||||
|
||||
public static bool GetIsBetterHost(this PlayerControl player)
|
||||
{
|
||||
if (IsBetterHost.ContainsKey(player))
|
||||
if (player.IsHost() && IsBetterHost.ContainsKey(player))
|
||||
return IsBetterHost[player];
|
||||
else
|
||||
return false;
|
||||
|
||||
@@ -20,6 +20,11 @@ class FileChecker
|
||||
{
|
||||
if (Enabled == false) return;
|
||||
|
||||
if (GameStates.IsDev)
|
||||
{
|
||||
HasTrySpoofFriendCode = false;
|
||||
}
|
||||
|
||||
GameObject PlayButton = GameObject.Find("Main Buttons/PlayButton");
|
||||
|
||||
// Disable play button
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using AmongUs.GameOptions;
|
||||
using BetterAmongUs.Patches;
|
||||
|
||||
namespace BetterAmongUs;
|
||||
|
||||
@@ -7,7 +8,7 @@ namespace BetterAmongUs;
|
||||
public static class GameStates
|
||||
{
|
||||
/**********Check Game Status***********/
|
||||
public static bool IsDev => Main.DevUser.Contains(Utils.GetHashPuid(EOSManager.Instance.ProductUserId));
|
||||
public static bool IsDev => EOSManager.Instance?.userId != null && Main.DevUser.Contains(Utils.GetHashPuid(EOSManager.Instance.userId.ToString()));
|
||||
public static bool InGame => Main.AllPlayerControls.Any();
|
||||
public static bool IsNormalGame => GameOptionsManager.Instance.CurrentGameOptions.GameMode is GameModes.Normal or GameModes.NormalFools;
|
||||
public static bool IsHideNSeek => GameOptionsManager.Instance.CurrentGameOptions.GameMode is GameModes.HideNSeek or GameModes.SeekFools;
|
||||
@@ -20,7 +21,7 @@ public static class GameStates
|
||||
public static bool IsInGame => InGame;
|
||||
public static bool IsLobby => AmongUsClient.Instance?.GameState == InnerNet.InnerNetClient.GameStates.Joined;
|
||||
public static bool IsInIntro => IntroCutscene.Instance != null;
|
||||
public static bool IsInGamePlay => (InGame && !IsLobby && !IsInIntro) || IsFreePlay;
|
||||
public static bool IsInGamePlay => (InGame && IsShip && !IsLobby && !IsInIntro) || IsFreePlay;
|
||||
public static bool IsEnded => AmongUsClient.Instance?.GameState == InnerNet.InnerNetClient.GameStates.Ended;
|
||||
public static bool IsNotJoined => AmongUsClient.Instance?.GameState == InnerNet.InnerNetClient.GameStates.NotJoined;
|
||||
public static bool IsOnlineGame => AmongUsClient.Instance?.NetworkMode == NetworkModes.OnlineGame;
|
||||
@@ -42,9 +43,9 @@ public static class GameStates
|
||||
public static bool IsProceeding => IsMeeting && MeetingHud.Instance?.state is MeetingHud.VoteStates.Proceeding;
|
||||
public static bool IsExilling => ExileController.Instance != null && !(AirshipIsActive && Minigame.Instance != null && Minigame.Instance.isActiveAndEnabled);
|
||||
public static bool IsCountDown => GameStartManager.InstanceExists && GameStartManager.Instance.startState == GameStartManager.StartingStates.Countdown;
|
||||
/**********TOP ZOOM.cs***********/
|
||||
public static bool IsShip => ShipStatus.Instance != null;
|
||||
public static bool IsHost => AmongUsClient.Instance.AmHost;
|
||||
public static bool IsHost => AmongUsClient.Instance != null && AmongUsClient.Instance.AmHost;
|
||||
public static bool IsBetterHostLobby => Main.BetterHost.Value || Main.AllPlayerControls.Any(pc => pc.GetIsBetterHost());
|
||||
public static bool IsCanMove => PlayerControl.LocalPlayer?.CanMove is true;
|
||||
public static bool IsDead => PlayerControl.LocalPlayer?.Data?.IsDead is true;
|
||||
}
|
||||
+48
-30
@@ -41,14 +41,16 @@ internal class RPCHandlerPatch
|
||||
Logger.LogCheat($"RPC canceled by Host: {Enum.GetName((RpcCalls)callId)}{Enum.GetName((CustomRPC)callId)} - {callId}");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
AntiCheat.CheckRPC(__instance, callId, reader);
|
||||
RPC.HandleRPC(__instance, callId, reader);
|
||||
|
||||
return true;
|
||||
}
|
||||
public static void Postfix(PlayerControl __instance, [HarmonyArgument(0)] byte callId, [HarmonyArgument(1)] MessageReader reader)
|
||||
{
|
||||
AntiCheat.CheckRPC(__instance, callId, reader);
|
||||
RPC.HandleRPC(__instance, callId, reader);
|
||||
{
|
||||
RPC.HandleCustomRPC(__instance, callId, reader);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,15 +79,7 @@ internal static class RPC
|
||||
player.Exiled();
|
||||
}
|
||||
|
||||
public static async Task WaitForChatCooldown()
|
||||
{
|
||||
while (3f - HudManager.Instance.Chat.timeSinceLastMessage > 0f)
|
||||
{
|
||||
await Task.Delay(100);
|
||||
}
|
||||
}
|
||||
|
||||
public static async void SendHostChatToPlayer(PlayerControl player, string text, string? title = "", bool sendToBetterUser = true)
|
||||
public static void SendHostChatToPlayer(PlayerControl player, string text, string? title = "", bool sendToBetterUser = true)
|
||||
{
|
||||
if (!GameStates.IsHost) return;
|
||||
|
||||
@@ -102,10 +96,7 @@ internal static class RPC
|
||||
return;
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
await WaitForChatCooldown();
|
||||
|
||||
/*
|
||||
PlayerControl asPlayer = Main.AllPlayerControls.Where(pc => pc.IsAlive()).OrderBy(pc => pc == PlayerControl.LocalPlayer ? 0 : 1).First();
|
||||
|
||||
var oldName = asPlayer.CurrentOutfit.PlayerName;
|
||||
@@ -121,46 +112,73 @@ internal static class RPC
|
||||
messageWriter.Write(text);
|
||||
AmongUsClient.Instance.FinishRpcImmediately(messageWriter);
|
||||
|
||||
MessageWriter writer2 = AmongUsClient.Instance.StartRpcImmediately(asPlayer.NetId, (byte)RpcCalls.SetName, SendOption.None, player.GetClientId());
|
||||
writer2.Write(asPlayer.Data.NetId);
|
||||
writer2.Write(oldName);
|
||||
AmongUsClient.Instance.FinishRpcImmediately(writer2);
|
||||
_ = new LateTask(() =>
|
||||
{
|
||||
MessageWriter writer2 = AmongUsClient.Instance.StartRpcImmediately(asPlayer.NetId, (byte)RpcCalls.SetName, SendOption.None, player.GetClientId());
|
||||
writer2.Write(asPlayer.Data.NetId);
|
||||
writer2.Write(oldName);
|
||||
AmongUsClient.Instance.FinishRpcImmediately(writer2);
|
||||
|
||||
SyncAllNames();
|
||||
SyncAllNames(force: true);
|
||||
}, 0.08f, shoudLog: false);
|
||||
*/
|
||||
}
|
||||
|
||||
public static void HandleRPC(PlayerControl player, byte callId, MessageReader reader)
|
||||
public static void HandleCustomRPC(PlayerControl player, byte callId, MessageReader oldReader)
|
||||
{
|
||||
if (PlayerControl.LocalPlayer == null || player == null || player == PlayerControl.LocalPlayer || player.Data == null) return;
|
||||
|
||||
if (!Enum.IsDefined(typeof(CustomRPC), (int)unchecked(callId))) return;
|
||||
|
||||
MessageReader reader = MessageReader.Get(oldReader);
|
||||
|
||||
switch (callId)
|
||||
{
|
||||
case (byte)CustomRPC.BetterCheck:
|
||||
if (reader.ReadByte() == player.Data.NetId)
|
||||
{
|
||||
var IsBetterHost = reader.ReadBoolean();
|
||||
|
||||
if (!player.IsHost() && IsBetterHost)
|
||||
{
|
||||
BetterNotificationManager.NotifyCheat(player, $"Invalid Action RPC: {Enum.GetName((RpcCalls)callId)} called as BetterHost");
|
||||
break;
|
||||
}
|
||||
|
||||
player.SetIsBetterUser(true);
|
||||
player.SetIsBetterHost(reader.ReadBoolean());
|
||||
player.SetIsBetterHost(IsBetterHost);
|
||||
}
|
||||
break;
|
||||
case (byte)CustomRPC.AddChat:
|
||||
Utils.AddChatPrivate(reader.ReadString(), reader.ReadString());
|
||||
break;
|
||||
case (byte)CustomRPC.VersionCheck:
|
||||
case (byte)CustomRPC.VersionCheck or (byte)CustomRPC.RequestRetryVersionCheck:
|
||||
if (player.IsHost())
|
||||
{
|
||||
var BAU = "<color=#278720>♻</color><color=#0ed400><b>BetterAmongUs</b></color><color=#278720>♻</color>";
|
||||
Utils.DisconnectSelf($"{BAU} does not support <color=#ff9cdc><b>TOHE</b></color>");
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public static void HandleRPC(PlayerControl player, byte callId, MessageReader oldReader)
|
||||
{
|
||||
if (PlayerControl.LocalPlayer == null || player == null || player == PlayerControl.LocalPlayer || player.Data == null) return;
|
||||
|
||||
MessageReader reader = MessageReader.Get(oldReader);
|
||||
|
||||
switch (callId)
|
||||
{
|
||||
case (byte)RpcCalls.SendChat:
|
||||
var text = reader.ReadString();
|
||||
|
||||
if (player.IsHost() && player != PlayerControl.LocalPlayer)
|
||||
{
|
||||
if (reader.BytesRemaining > 0)
|
||||
if (text.ToLower() == "/allow")
|
||||
{
|
||||
if (reader.ReadString().ToLower() == "/allow")
|
||||
{
|
||||
CommandsPatch.Permission = player;
|
||||
}
|
||||
CommandsPatch.Permission = player;
|
||||
BetterNotificationManager.Notify($"{player.GetPlayerNameAndColor()} has granted permission!");
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
+3
-3
@@ -1,4 +1,5 @@
|
||||
using HarmonyLib;
|
||||
using AmongUs.GameOptions;
|
||||
using HarmonyLib;
|
||||
using UnityEngine;
|
||||
|
||||
namespace BetterAmongUs;
|
||||
@@ -11,8 +12,7 @@ public static class Zoom
|
||||
|
||||
public static void Postfix()
|
||||
{
|
||||
if ((GameStates.IsShip && !GameStates.IsMeeting && GameStates.IsCanMove && PlayerControl.LocalPlayer.Data.IsDead) ||
|
||||
(GameStates.IsLobby && GameStates.IsCanMove))
|
||||
if (GameStates.IsCanMove && !PlayerControl.LocalPlayer.Is(RoleTypes.GuardianAngel) && (!GameStates.IsInGamePlay || !PlayerControl.LocalPlayer.IsAlive()))
|
||||
{
|
||||
if (Camera.main.orthographicSize > 3.0f)
|
||||
resetButtons = true;
|
||||
|
||||
+48
-1
@@ -1,6 +1,9 @@
|
||||
using AmongUs.Data;
|
||||
using Assets.CoreScripts;
|
||||
using HarmonyLib;
|
||||
using Hazel;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
|
||||
@@ -13,6 +16,39 @@ class ChatPatch
|
||||
public static List<string> ChatHistory = [];
|
||||
public static int CurrentHistorySelection = -1;
|
||||
|
||||
[HarmonyPatch(typeof(PlayerControl), nameof(PlayerControl.RpcSendChat))]
|
||||
class RpcSendChatPatch
|
||||
{
|
||||
public static bool Prefix(PlayerControl __instance, string chatText, ref bool __result)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(chatText))
|
||||
{
|
||||
__result = false;
|
||||
return false;
|
||||
}
|
||||
if (!GameStates.IsBetterHostLobby)
|
||||
{
|
||||
__result = false;
|
||||
return true;
|
||||
}
|
||||
chatText = Regex.Replace(chatText, "<.*?>", string.Empty);
|
||||
if (AmongUsClient.Instance.AmClient && DestroyableSingleton<HudManager>.Instance)
|
||||
{
|
||||
DestroyableSingleton<HudManager>.Instance.Chat.AddChat(__instance, chatText, true);
|
||||
}
|
||||
if (chatText.IndexOf("who", StringComparison.OrdinalIgnoreCase) >= 0)
|
||||
{
|
||||
DestroyableSingleton<UnityTelemetry>.Instance.SendWho();
|
||||
}
|
||||
chatText = "\n" + chatText;
|
||||
MessageWriter messageWriter = AmongUsClient.Instance.StartRpc(__instance.NetId, 13, SendOption.Reliable);
|
||||
messageWriter.Write(chatText);
|
||||
messageWriter.EndMessage();
|
||||
__result = true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
[HarmonyPatch(typeof(ChatController))]
|
||||
class ChatControllerPatch
|
||||
{
|
||||
@@ -24,8 +60,16 @@ class ChatPatch
|
||||
{
|
||||
GameObject chatItem = __instance.scroller.Inner.transform.GetChild(i).gameObject;
|
||||
|
||||
chatItem.transform.Find("Background").GetComponent<SpriteRenderer>().color = new Color(0.05f, 0.05f, 0.05f, 1f);
|
||||
chatItem.transform.Find("ChatText (TMP)").GetComponent<TextMeshPro>().color = new Color(1f, 1f, 1f, 1f);
|
||||
chatItem.transform.Find("Background").GetComponent<SpriteRenderer>().color = new Color(0.05f, 0.05f, 0.05f, 1f);
|
||||
|
||||
if (chatItem.transform.Find("PoolablePlayer/xMark") != null)
|
||||
{
|
||||
if (chatItem.transform.Find("PoolablePlayer/xMark").GetComponent<SpriteRenderer>().enabled == true)
|
||||
{
|
||||
chatItem.transform.Find("Background").GetComponent<SpriteRenderer>().color = new Color(0.05f, 0.05f, 0.05f, 0.5f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Free chat color
|
||||
@@ -37,6 +81,9 @@ class ChatPatch
|
||||
__instance.quickChatField.background.color = new Color32(40, 40, 40, byte.MaxValue);
|
||||
__instance.quickChatField.text.color = Color.white;
|
||||
|
||||
__instance.quickChatButton.transform.Find("QuickChatIcon").GetComponent<SpriteRenderer>().color = new Color(0.5f, 0.5f, 0.5f, 1f);
|
||||
__instance.openKeyboardButton.transform.Find("OpenKeyboardIcon").GetComponent<SpriteRenderer>().color = new Color(0.5f, 0.5f, 0.5f, 1f);
|
||||
|
||||
if ((Input.GetKey(KeyCode.LeftControl) || Input.GetKey(KeyCode.RightControl)) && Input.GetKeyDown(KeyCode.X))
|
||||
{
|
||||
ClipboardHelper.PutClipboardString(__instance.freeChatField.textArea.text);
|
||||
|
||||
@@ -22,9 +22,17 @@ public static class OptionsMenuBehaviourPatch
|
||||
[HarmonyPrefix]
|
||||
public static void Start_Postfix(OptionsMenuBehaviour __instance)
|
||||
{
|
||||
static bool toggleCheckInGame(string buttonName)
|
||||
static bool toggleCheckInGamePlay(string buttonName)
|
||||
{
|
||||
bool flag = GameStates.IsInGame && !GameStates.IsLobby || GameStates.IsFreePlay;
|
||||
if (flag)
|
||||
BetterNotificationManager.Notify($"Unable to toggle {buttonName} while in gameplay!", 2.5f);
|
||||
|
||||
return flag;
|
||||
}
|
||||
static bool toggleCheckInGame(string buttonName)
|
||||
{
|
||||
bool flag = GameStates.IsInGame;
|
||||
if (flag)
|
||||
BetterNotificationManager.Notify($"Unable to toggle {buttonName} while in game!", 2.5f);
|
||||
|
||||
@@ -40,7 +48,7 @@ public static class OptionsMenuBehaviourPatch
|
||||
|
||||
if (BetterHost == null || BetterHost.ToggleButton == null)
|
||||
{
|
||||
BetterHost = ClientOptionItem.Create("<color=#4f92ff>Better Host</color>", Main.BetterHost, __instance, BetterHostButtonToggle, () => !toggleCheckInGame("<color=#4f92ff>Better Host</color>"));
|
||||
BetterHost = ClientOptionItem.Create("<color=#4f92ff>Better Host</color>", Main.BetterHost, __instance, BetterHostButtonToggle, () => !toggleCheckInGamePlay("<color=#4f92ff>Better Host</color>"));
|
||||
static void BetterHostButtonToggle()
|
||||
{
|
||||
var flag = GameStates.IsHost && Main.BetterHost.Value;
|
||||
@@ -55,7 +63,7 @@ public static class OptionsMenuBehaviourPatch
|
||||
|
||||
if (BetterRoleAlgorithma == null || BetterRoleAlgorithma.ToggleButton == null)
|
||||
{
|
||||
BetterRoleAlgorithma = ClientOptionItem.Create("<color=#4f92ff>Better Role Algorithma</color>", Main.BetterRoleAlgorithma, __instance, toggleCheck: () => !toggleCheckInGame("<color=#4f92ff>Better Role Algorithma</color>"));
|
||||
BetterRoleAlgorithma = ClientOptionItem.Create("<color=#4f92ff>Better Role Algorithma</color>", Main.BetterRoleAlgorithma, __instance, toggleCheck: () => !toggleCheckInGamePlay("<color=#4f92ff>Better Role Algorithma</color>"));
|
||||
}
|
||||
|
||||
if (LobbyPlayerInfo == null || LobbyPlayerInfo.ToggleButton == null)
|
||||
|
||||
+13
-11
@@ -125,7 +125,7 @@ class CommandsPatch
|
||||
{
|
||||
Directory.CreateDirectory(logFolderPath);
|
||||
}
|
||||
string logFileName = "log-" + DateTime.Now.ToString("yyyy.MM.dd-HH.mm.ss") + ".log";
|
||||
string logFileName = "log-" + Main.GetVersionText().Replace(' ', '-').ToLower() + "-" + DateTime.Now.ToString("yyyy.MM.dd-HH.mm.ss") + ".log";
|
||||
string newLogFilePath = Path.Combine(logFolderPath, logFileName);
|
||||
File.WriteAllText(newLogFilePath, newLog);
|
||||
System.Diagnostics.Process.Start(new System.Diagnostics.ProcessStartInfo()
|
||||
@@ -140,6 +140,8 @@ class CommandsPatch
|
||||
UseShellExecute = true,
|
||||
Verb = "open"
|
||||
});
|
||||
|
||||
Utils.AddChatPrivate($"Dump logs at <color=#b1b1b1>'{newLogFilePath}'</color>");
|
||||
break;
|
||||
case "player":
|
||||
if (HandlePlayerArgument(command, subArgs) == true)
|
||||
@@ -150,10 +152,10 @@ class CommandsPatch
|
||||
var format2 = "├ •";
|
||||
var format3 = "└ •";
|
||||
sb.Append($"<size=150%><color={hexColor}><b>{player?.Data?.PlayerName}</color> Info:</b></size>\n");
|
||||
sb.Append($"{format1} <color=#525252>ID: {player?.Data?.PlayerId}</color>\n");
|
||||
sb.Append($"{format2} <color=#525252>HashPUID: {Utils.GetHashPuid($"{player?.Data?.Puid}")}</color>\n");
|
||||
sb.Append($"{format2} <color=#525252>Platform: {Utils.GetPlatformName(player)}</color>\n");
|
||||
sb.Append($"{format3} <color=#525252>FriendCode: {player?.Data?.FriendCode}</color>");
|
||||
sb.Append($"{format1} <color=#c1c1c1>ID: {player?.Data?.PlayerId}</color>\n");
|
||||
sb.Append($"{format2} <color=#c1c1c1>HashPUID: {Utils.GetHashPuid($"{player?.Data?.Puid}")}</color>\n");
|
||||
sb.Append($"{format2} <color=#c1c1c1>Platform: {Utils.GetPlatformName(player)}</color>\n");
|
||||
sb.Append($"{format3} <color=#c1c1c1>FriendCode: {player?.Data?.FriendCode}</color>");
|
||||
Utils.AddChatPrivate(sb.ToString());
|
||||
}
|
||||
break;
|
||||
@@ -162,10 +164,10 @@ class CommandsPatch
|
||||
{
|
||||
var hexColor = Utils.Color32ToHex(Palette.PlayerColors[player.CurrentOutfit.ColorId]);
|
||||
sb.Append($"<color={hexColor}><b>{player?.Data?.PlayerName}</color> Info:</b>\n");
|
||||
sb.Append($"<color=#525252>{player?.Data?.PlayerId}</color> - ");
|
||||
sb.Append($"<color=#525252>{Utils.GetHashPuid($"{player?.Data?.Puid}")}</color> - ");
|
||||
sb.Append($"<color=#525252>{Utils.GetPlatformName(player)}</color> - ");
|
||||
sb.Append($"<color=#525252>{player?.Data?.FriendCode}</color>");
|
||||
sb.Append($"<color=#c1c1c1>{player?.Data?.PlayerId}</color> - ");
|
||||
sb.Append($"<color=#c1c1c1>{Utils.GetHashPuid($"{player?.Data?.Puid}")}</color> - ");
|
||||
sb.Append($"<color=#c1c1c1>{Utils.GetPlatformName(player)}</color> - ");
|
||||
sb.Append($"<color=#c1c1c1>{player?.Data?.FriendCode}</color>");
|
||||
sb.Append("\n\n");
|
||||
}
|
||||
Utils.AddChatPrivate(sb.ToString());
|
||||
@@ -176,12 +178,11 @@ class CommandsPatch
|
||||
if (UseCommandInGame() == true)
|
||||
{
|
||||
var player = cmdTarget;
|
||||
var hexColor = Utils.Color32ToHex(Palette.PlayerColors[player.CurrentOutfit.ColorId]);
|
||||
|
||||
MessageWriter messageWriter = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)RpcCalls.SendChat, SendOption.None, player.GetClientId());
|
||||
messageWriter.Write(string.Join(" ", command[2..].ToArray()));
|
||||
AmongUsClient.Instance.FinishRpcImmediately(messageWriter);
|
||||
Utils.AddChatPrivate($"{string.Join(" ", command[2..].ToArray())}", overrideName: $"<color=#696969>Sent Private Message to</color> <color={hexColor}><b>{player.Data.PlayerName}</b></color>");
|
||||
Utils.AddChatPrivate($"{string.Join(" ", command[2..].ToArray())}", overrideName: $"<color=#696969>Sent Private Message to</color> <b>{player.GetPlayerNameAndColor()}</b>");
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -373,6 +374,7 @@ class CommandsPatch
|
||||
if (HandleIsHost(command) == true)
|
||||
{
|
||||
RPC.SyncAllNames(force: true);
|
||||
Utils.AddChatPrivate("<color=#0dff00>All player names have been updated and synced!</color>");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
||||
@@ -10,7 +10,7 @@ class GamePlayManager
|
||||
{
|
||||
[HarmonyPatch(nameof(LobbyBehaviour.OnDestroy))]
|
||||
[HarmonyPrefix]
|
||||
private static void Prefix(/*LobbyBehaviour __instance*/)
|
||||
private static void OnDestroy_Prefix(/*LobbyBehaviour __instance*/)
|
||||
{
|
||||
if (GameStates.IsInGame)
|
||||
{
|
||||
@@ -19,7 +19,7 @@ class GamePlayManager
|
||||
}
|
||||
[HarmonyPatch(nameof(LobbyBehaviour.Start))]
|
||||
[HarmonyPostfix]
|
||||
private static void Postfix(/*LobbyBehaviour __instance*/)
|
||||
private static void Start_Postfix(/*LobbyBehaviour __instance*/)
|
||||
{
|
||||
_ = new LateTask(() =>
|
||||
{
|
||||
@@ -29,6 +29,15 @@ class GamePlayManager
|
||||
}
|
||||
}, 1.5f, "LobbyBehaviourPatch SyncAllNames");
|
||||
}
|
||||
|
||||
// Disabled annoying music
|
||||
[HarmonyPatch(nameof(LobbyBehaviour.Update))]
|
||||
[HarmonyPostfix]
|
||||
public static void Update_Postfix(/*LobbyBehaviour __instance*/)
|
||||
{
|
||||
if (Main.DisableLobbyTheme.Value)
|
||||
SoundManager.instance.StopSound(LobbyBehaviour.Instance.MapTheme);
|
||||
}
|
||||
}
|
||||
|
||||
[HarmonyPatch(typeof(GameManager))]
|
||||
@@ -55,7 +64,10 @@ class GamePlayManager
|
||||
[HarmonyPrefix]
|
||||
private static void Prefix(GameStartManager __instance)
|
||||
{
|
||||
__instance.MinPlayers = 1;
|
||||
if (GameStates.IsDev)
|
||||
{
|
||||
__instance.MinPlayers = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
using HarmonyLib;
|
||||
|
||||
namespace BetterAmongUs.Patches;
|
||||
|
||||
public class LobbyPatch
|
||||
{
|
||||
[HarmonyPatch(typeof(LobbyBehaviour))]
|
||||
internal class LobbyBehaviourPatch
|
||||
{
|
||||
// Disabled annoying music
|
||||
[HarmonyPatch(nameof(LobbyBehaviour.Update))]
|
||||
[HarmonyPostfix]
|
||||
public static void Postfix(PingTracker __instance)
|
||||
{
|
||||
if (Main.DisableLobbyTheme.Value)
|
||||
SoundManager.instance.StopSound(LobbyBehaviour.Instance.MapTheme);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,6 +15,7 @@ public class ModManagerPatch
|
||||
if (__instance.ModStamp.gameObject.active == true)
|
||||
__instance.ModStamp.GetComponent<SpriteRenderer>().sprite = Utils.LoadSprite("BetterAmongUs.Resources.Images.BetterAmongUs-Mod.png", 250f);
|
||||
|
||||
AntiCheat.Update();
|
||||
FileChecker.UpdateUnauthorizedFiles();
|
||||
LateTask.Update(Time.deltaTime);
|
||||
BetterNotificationManager.Update();
|
||||
|
||||
@@ -40,8 +40,7 @@ public class PingTrackerPatch
|
||||
// Add Host Info if not in lobby
|
||||
if (GameStates.IsInGamePlay && Host != null)
|
||||
{
|
||||
string hostColor = Utils.Color32ToHex(Palette.PlayerColors[Host.CurrentOutfit.ColorId]);
|
||||
sb.AppendFormat("<size=75%>Host: <color={0}>{1}</color></size>\n", hostColor, Host.CurrentOutfit.PlayerName);
|
||||
sb.AppendFormat("<size=75%>Host: {0}</size>\n", Host.GetPlayerNameAndColor());
|
||||
}
|
||||
|
||||
__instance.aspectPosition.DistanceFromEdge = new Vector3(4f, 0.1f, -5);
|
||||
|
||||
@@ -14,8 +14,8 @@ class PlayerControlPatch
|
||||
{
|
||||
public static float infotime = 0f;
|
||||
[HarmonyPatch(nameof(PlayerControl.FixedUpdate))]
|
||||
[HarmonyPostfix]
|
||||
public static void FixedUpdate_Postfix(PlayerControl __instance)
|
||||
[HarmonyPrefix]
|
||||
public static void FixedUpdate_Prefix(PlayerControl __instance)
|
||||
{
|
||||
// Set up player text info
|
||||
var NameText = GameObject.Find($"{__instance.gameObject.transform.name}/Names/NameText_TMP");
|
||||
@@ -59,11 +59,13 @@ class PlayerControlPatch
|
||||
if (infotime <= 0)
|
||||
{
|
||||
SetPlayerInfo(__instance);
|
||||
infotime = 0.4f;
|
||||
infotime = 0.6f;
|
||||
}
|
||||
|
||||
if (GameStates.IsInGame && GameStates.IsHost)
|
||||
RPC.SyncAllNames(isBetterHost: false);
|
||||
{
|
||||
BetterHostManager.Update(__instance);
|
||||
}
|
||||
}
|
||||
|
||||
public static void SetPlayerInfo(PlayerControl player)
|
||||
@@ -144,8 +146,7 @@ class PlayerControlPatch
|
||||
{
|
||||
if (Main.LobbyPlayerInfo.Value == true)
|
||||
{
|
||||
string hexColor = Utils.Color32ToHex(Palette.PlayerColors[Host.CurrentOutfit.ColorId]);
|
||||
NewName = $"<color={hexColor}>{player.Data.PlayerName}</color>";
|
||||
NewName = player.GetPlayerNameAndColor();
|
||||
}
|
||||
}
|
||||
if (player.IsImpostorTeammate() && player != PlayerControl.LocalPlayer)
|
||||
@@ -185,7 +186,7 @@ class PlayerControlPatch
|
||||
}
|
||||
}
|
||||
|
||||
if (!GameStates.IsInGamePlay)
|
||||
if (GameStates.IsLobby)
|
||||
{
|
||||
if (Main.LobbyPlayerInfo.Value == true)
|
||||
{
|
||||
@@ -226,6 +227,7 @@ class PlayerControlPatch
|
||||
if (PlayerControl.LocalPlayer.IsImpostorTeam() && GameStates.IsInGamePlay && !GameStates.IsHideNSeek && HudManager.Instance.CrewmatesKilled.isActiveAndEnabled)
|
||||
HudManager.Instance?.NotifyOfDeath();
|
||||
|
||||
ExtendedPlayerControl.TimeSinceKill[__instance] = 0f;
|
||||
|
||||
Logger.LogPrivate($"{__instance.Data.PlayerName} Has killed {target.Data.PlayerName} as {Utils.GetRoleName(__instance.Data.RoleType)}", "EventLog");
|
||||
}
|
||||
|
||||
@@ -65,7 +65,7 @@ public static class OnPlayerJoinedPatch
|
||||
if (Main.BetterHost.Value)
|
||||
client.Character.RpcSendHostChat(HudManagerPatch.WelcomeMessage, sendToBetterUser: false);
|
||||
}
|
||||
}, 1.5f, "OnPlayerJoinedPatch", false);
|
||||
}, 2.5f, "OnPlayerJoinedPatch", false);
|
||||
}
|
||||
}
|
||||
[HarmonyPatch(typeof(AmongUsClient), nameof(AmongUsClient.OnPlayerLeft))]
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
using HarmonyLib;
|
||||
|
||||
namespace BetterAmongUs.Patches;
|
||||
|
||||
[HarmonyPatch(typeof(Constants), nameof(Constants.GetBroadcastVersion))]
|
||||
class ServerUpdatePatch
|
||||
{
|
||||
static void Postfix(ref int __result)
|
||||
{
|
||||
var region = ServerManager.Instance.CurrentRegion.Name;
|
||||
|
||||
if (GameStates.IsLocalGame)
|
||||
{
|
||||
}
|
||||
if (GameStates.IsOnlineGame)
|
||||
{
|
||||
if (region.Contains("MNA") || region.Contains("MEU") || region.Contains("MAS"))
|
||||
{
|
||||
__result += 25;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
[HarmonyPatch(typeof(Constants), nameof(Constants.IsVersionModded))]
|
||||
public static class IsVersionModdedPatch
|
||||
{
|
||||
public static bool Prefix(ref bool __result)
|
||||
{
|
||||
var region = ServerManager.Instance.CurrentRegion.Name;
|
||||
|
||||
if (region.Contains("MNA") || region.Contains("MEU") || region.Contains("MAS"))
|
||||
{
|
||||
__result = true;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
using BepInEx.Configuration;
|
||||
using BepInEx.Logging;
|
||||
using BepInEx.Unity.IL2CPP;
|
||||
using BetterAmongUs.Patches;
|
||||
using HarmonyLib;
|
||||
using Il2CppInterop.Runtime.Injection;
|
||||
using Innersloth.IO;
|
||||
@@ -21,12 +22,12 @@ public enum ReleaseTypes : int
|
||||
public class Main : BasePlugin
|
||||
{
|
||||
public const ReleaseTypes ReleaseBuildType = ReleaseTypes.Canary;
|
||||
public const string CanaryNum = "4";
|
||||
public const string CanaryNum = "5";
|
||||
public const string HotfixNum = "0";
|
||||
public const bool IsHotFix = false;
|
||||
public const string PluginGuid = "com.d1gq.betteramongus";
|
||||
public const string PluginVersion = "1.0.0";
|
||||
public const string ReleaseDate = "07.29.2024"; // dd/mm/yyyy
|
||||
public const string ReleaseDate = "08.01.2024"; // mm/dd/yyyy
|
||||
public const string Github = "https://github.com/D1GQ/BetterAmongUs";
|
||||
public const string Discord = "https://discord.gg/";
|
||||
|
||||
|
||||
Reference in new issue
Block a user