Files
BetterAmongUs/Patches/PlayerControlPatch.cs
T
2024-11-17 19:59:49 -06:00

364 lines
14 KiB
C#

using AmongUs.Data;
using AmongUs.GameOptions;
using BetterAmongUs.Helpers;
using BetterAmongUs.Managers;
using BetterAmongUs.Modules;
using HarmonyLib;
using Il2CppSystem.Linq;
using System.Text;
using System.Text.RegularExpressions;
using TMPro;
using UnityEngine;
namespace BetterAmongUs.Patches;
[HarmonyPatch(typeof(PlayerControl))]
class PlayerControlPatch
{
public static Dictionary<byte, float> time = [];
[HarmonyPatch(nameof(PlayerControl.FixedUpdate))]
[HarmonyPrefix]
public static void FixedUpdate_Prefix(PlayerControl __instance)
{
// Set up player text info
var nameTextTransform = __instance.gameObject.transform.Find("Names/NameText_TMP");
var nameText = nameTextTransform?.gameObject;
var infoText = nameTextTransform?.Find("InfoText_T_TMP");
if (nameText != null && infoText == null)
{
void InstantiatePlayerInfoText(string name, Vector3 positionOffset)
{
var newTextObject = UnityEngine.Object.Instantiate(nameText, nameTextTransform);
newTextObject.name = name;
newTextObject.transform.DestroyChildren();
newTextObject.transform.position += positionOffset;
var textMesh = newTextObject.GetComponent<TextMeshPro>();
if (textMesh != null)
{
textMesh.text = string.Empty;
}
newTextObject.SetActive(true);
}
InstantiatePlayerInfoText("InfoText_Info_TMP", new Vector3(0f, 0.25f));
InstantiatePlayerInfoText("InfoText_T_TMP", new Vector3(0f, 0.15f));
InstantiatePlayerInfoText("InfoText_B_TMP", new Vector3(0f, -0.15f));
}
// Set color blind text on player
if (__instance.DataIsCollected() && !__instance.shapeshifting)
{
__instance.cosmetics.SetColorBlindColor(__instance.CurrentOutfit.ColorId);
}
else
{
__instance.cosmetics.colorBlindText.text = string.Empty;
}
if (GameState.IsInGame && GameState.IsHost && Main.BetterHost.Value)
{
BetterHostManager.PlayerUpdate(__instance);
}
// Set text info
if (!time.ContainsKey(__instance.PlayerId))
{
time[__instance.PlayerId] = 0f;
}
time[__instance.PlayerId] -= Time.deltaTime;
if (time[__instance.PlayerId] <= 0)
{
SetPlayerInfo(__instance);
time[__instance.PlayerId] = 0.6f;
}
}
public static void SetPlayerInfo(PlayerControl player)
{
try
{
if (player?.Data == null) return;
var betterData = player.BetterData();
if (GameState.IsTOHEHostLobby) return;
var nameText = player.gameObject.transform.Find("Names/NameText_TMP").GetComponent<TextMeshPro>();
if (!player.DataIsCollected())
{
nameText.text = Translator.GetString("Player.Loading");
return;
}
if (!Main.LobbyPlayerInfo.Value && GameState.IsLobby)
{
player.ResetAllPlayerTextInfo();
player.RawSetName(player.Data.PlayerName);
return;
}
string newName = player.Data.PlayerName;
string hashPuid = Utils.GetHashPuid(player);
string platform = Utils.GetPlatformName(player, useTag: true);
string friendCode = ValidateFriendCode(player, out string friendCodeColor);
if (DataManager.Settings.Gameplay.StreamerMode)
{
platform = Translator.GetString("Player.PlatformHidden");
}
// Set Tags
var sbTag = new StringBuilder();
var sbTagTop = new StringBuilder();
var sbTagBottom = new StringBuilder();
SetPlayerOutline(player, hashPuid, friendCode, sbTag);
if (GameState.IsInGame && GameState.IsLobby && !GameState.IsFreePlay)
{
SetLobbyInfo(player, ref newName, betterData, sbTag);
sbTagTop.Append($"<color=#9e9e9e>{platform}</color>+++")
.Append($"<color=#ffd829>Lv: {player.Data.PlayerLevel + 1}</color>+++");
sbTagBottom.Append($"<color={friendCodeColor}>{friendCode}</color>+++");
}
else if ((GameState.IsInGame || GameState.IsFreePlay) && !GameState.IsHideNSeek)
{
SetInGameInfo(player, sbTagTop);
}
if (!player.IsInShapeshift())
{
player.RawSetName(newName);
}
else
{
var targetData = Utils.PlayerDataFromPlayerId(player.shapeshiftTargetPlayerId);
if (targetData != null) player.RawSetName(targetData.BetterData().RealName);
}
player.SetPlayerTextInfo(FormatInfo(sbTagTop));
player.SetPlayerTextInfo(FormatInfo(sbTagBottom), isBottom: true);
player.SetPlayerTextInfo(FormatInfo(sbTag), isInfo: true);
}
catch (Exception ex)
{
Logger.Error(ex);
}
}
private static string ValidateFriendCode(PlayerControl player, out string color)
{
void TryKick()
{
if (GameState.IsHost)
{
if (BetterGameSettings.InvalidFriendCode.GetBool())
{
string kickMessage = string.Format(Translator.GetString("AntiCheat.KickMessage"), Translator.GetString("AntiCheat.ByAntiCheat"), Translator.GetString("AntiCheat.Reason.InvalidFriendCode"));
player.Kick(true, kickMessage, true);
}
}
}
string pattern = @"^[a-zA-Z0-9#]+$";
string hashtagPattern = @"^#[0-9]{4}$";
string friendCode = player.Data.FriendCode;
color = (Regex.Replace(friendCode, hashtagPattern, string.Empty).Length is > 10 or < 5
|| !Regex.IsMatch(friendCode, pattern)
|| !Regex.IsMatch(friendCode, hashtagPattern)
|| friendCode.Contains(' ')) ? "#00f7ff" : "#ff0000";
if (string.IsNullOrEmpty(friendCode) || friendCode == "")
{
friendCode = Translator.GetString("Player.NoFriendCode");
color = "#ff0000";
TryKick();
return friendCode;
}
else if (color == "#ff0000")
{
TryKick();
}
if (DataManager.Settings.Gameplay.StreamerMode)
{
friendCode = new string('*', friendCode.Length);
}
return friendCode;
}
private static void SetPlayerOutline(PlayerControl player, string hashPuid, string friendCode, StringBuilder sbTag)
{
if (AntiCheat.SickoData.ContainsKey(hashPuid) || AntiCheat.SickoData.ContainsValue(friendCode))
{
sbTag.Append($"<color=#00f583>{Translator.GetString("Player.SickoUser")}</color>+++");
player.SetOutlineByHex(true, "#00f583");
}
else if (AntiCheat.AUMData.ContainsKey(hashPuid) || AntiCheat.AUMData.ContainsValue(friendCode))
{
sbTag.Append($"<color=#4f0000>{Translator.GetString("Player.AUMUser")}</color>+++");
player.SetOutlineByHex(true, "#4f0000");
}
else if (AntiCheat.KNData.ContainsKey(hashPuid) || AntiCheat.KNData.ContainsValue(friendCode))
{
sbTag.Append($"<color=#8731e7>{Translator.GetString("Player.KNUser")}</color>+++");
player.SetOutlineByHex(true, "#8731e7");
}
else if (AntiCheat.PlayerData.ContainsKey(hashPuid) || AntiCheat.PlayerData.ContainsValue(friendCode))
{
sbTag.Append($"<color=#fc0000>{Translator.GetString("Player.KnownCheater")}</color>+++");
player.SetOutlineByHex(true, "#fc0000");
}
else
{
player.SetOutline(false, null);
}
}
private static void SetLobbyInfo(PlayerControl player, ref string newName, ExtendedPlayerInfo betterData, StringBuilder sbTag)
{
if (player.IsHost() && Main.LobbyPlayerInfo.Value)
newName = player.GetPlayerNameAndColor();
if (player.IsDev() && !GameState.IsInGamePlay)
sbTag.Append($"<color=#6e6e6e>(<color=#0088ff>{Translator.GetString("Player.Dev")}</color>)</color>+++");
if ((player.IsLocalPlayer() && GameState.IsHost && Main.BetterHost.Value) ||
(betterData.IsBetterHost && player.IsHost()) && !GameState.IsInGamePlay)
{
sbTag.AppendFormat("<color=#0dff00>{1}{0}</color>+++", Translator.GetString("Player.BetterHost"),
betterData.IsVerifiedBetterUser || player.IsLocalPlayer() ? "✓ " : "");
}
else if ((player.IsLocalPlayer() || betterData.IsBetterUser) && !GameState.IsInGamePlay)
{
sbTag.AppendFormat("<color=#0dff00>{1}{0}</color>+++", Translator.GetString("Player.BetterUser"),
betterData.IsVerifiedBetterUser || player.IsLocalPlayer() ? "✓ " : "");
}
sbTag.Append($"<color=#b554ff>ID: {player.PlayerId}</color>+++");
}
private static void SetInGameInfo(PlayerControl player, StringBuilder sbTagTop)
{
if (player.IsImpostorTeammate() || player.IsLocalPlayer() || !PlayerControl.LocalPlayer.IsAlive() && !PlayerControl.LocalPlayer.Is(RoleTypes.GuardianAngel) || DebugMenu.RevealRoles)
{
string roleInfo = $"<color={player.GetTeamHexColor()}>{player.GetRoleName()}</color>";
if (!player.IsImpostorTeam() && player.myTasks.Count > 0)
{
roleInfo += $" <color=#cbcbcb>({player.Data.Tasks.ToArray().Where(task => task.Complete).Count()}/{player.Data.Tasks.Count})</color>";
}
sbTagTop.Append(roleInfo + "+++");
}
}
private static string FormatInfo(StringBuilder source)
{
if (source.Length == 0) return string.Empty;
var sb = new StringBuilder();
foreach (var part in source.ToString().Split("+++"))
{
if (!string.IsNullOrEmpty(Utils.RemoveHtmlText(part)))
{
sb.Append(part).Append(" - ");
}
}
return sb.ToString().TrimEnd(" - ".ToCharArray());
}
[HarmonyPatch(nameof(PlayerControl.RpcSetName))]
[HarmonyPrefix]
public static bool RpcSetName_Prefix(PlayerControl __instance, [HarmonyArgument(0)] string name)
{
if (!GameState.IsVanillaServer && Utils.IsHtmlText(name))
{
return false;
}
return true;
}
[HarmonyPatch(nameof(PlayerControl.SetColor))]
[HarmonyPostfix]
public static void SetColor_Postfix()
{
if (Main.BetterHost.Value && GameState.IsLobby)
{
_ = new LateTask(() =>
{
RPC.SyncAllNames(force: true);
}, 0.25f, shoudLog: false);
}
}
[HarmonyPatch(nameof(PlayerControl.MurderPlayer))]
[HarmonyPostfix]
public static void MurderPlayer_Postfix(PlayerControl __instance, [HarmonyArgument(0)] PlayerControl target)
{
if (target == null) return;
Logger.LogPrivate($"{__instance.Data.PlayerName} Has killed {target.Data.PlayerName} as {Utils.GetRoleName(__instance.Data.RoleType)}", "EventLog");
__instance.BetterData().RoleInfo.Kills += 1;
}
[HarmonyPatch(nameof(PlayerControl.Shapeshift))]
[HarmonyPostfix]
public static void Shapeshift_Postfix(PlayerControl __instance, [HarmonyArgument(0)] PlayerControl target, [HarmonyArgument(1)] bool animate)
{
if (target == null) return;
if (GameState.IsHost)
{
RPC.SyncAllNames();
}
if (__instance != target)
Logger.LogPrivate($"{__instance.Data.PlayerName} Has Shapeshifted into {target.Data.PlayerName}, did animate: {animate}", "EventLog");
else
Logger.LogPrivate($"{__instance.Data.PlayerName} Has Un-Shapeshifted, did animate: {animate}", "EventLog");
}
[HarmonyPatch(nameof(PlayerControl.SetRoleInvisibility))]
[HarmonyPostfix]
public static void SetRoleInvisibility_Postfix(PlayerControl __instance, [HarmonyArgument(0)] bool isActive, [HarmonyArgument(1)] bool animate)
{
if (isActive)
Logger.LogPrivate($"{__instance.Data.PlayerName} Has Vanished as Phantom, did animate: {animate}", "EventLog");
else
Logger.LogPrivate($"{__instance.Data.PlayerName} Has Appeared as Phantom, did animate: {animate}", "EventLog");
}
}
[HarmonyPatch(typeof(PlayerPhysics))]
public class PlayerPhysicsPatch
{
[HarmonyPatch(nameof(PlayerPhysics.BootFromVent))]
[HarmonyPostfix]
private static void BootFromVent_Postfix(PlayerPhysics __instance, [HarmonyArgument(0)] int ventId)
{
Logger.LogPrivate($"{__instance.myPlayer.Data.PlayerName} Has been booted from vent: {ventId}, as {Utils.GetRoleName(__instance.myPlayer.Data.RoleType)}", "EventLog");
}
[HarmonyPatch(nameof(PlayerPhysics.CoEnterVent))]
[HarmonyPostfix]
private static void CoEnterVent_Postfix(PlayerPhysics __instance, [HarmonyArgument(0)] int ventId)
{
Logger.LogPrivate($"{__instance.myPlayer.Data.PlayerName} Has entered vent: {ventId}, as {Utils.GetRoleName(__instance.myPlayer.Data.RoleType)}", "EventLog");
}
[HarmonyPatch(nameof(PlayerPhysics.CoExitVent))]
[HarmonyPostfix]
private static void CoExitVent_Postfix(PlayerPhysics __instance, [HarmonyArgument(0)] int ventId)
{
Logger.LogPrivate($"{__instance.myPlayer.Data.PlayerName} Has exit vent: {ventId}, as {Utils.GetRoleName(__instance.myPlayer.Data.RoleType)}", "EventLog");
}
}