using System.Reflection; using ABI_RC.API; using ABI_RC.Core.Networking; using ABI_RC.Core.Networking.API.Responses; using ABI_RC.Systems.GameEventSystem; using HarmonyLib; using MelonLoader; using Random = UnityEngine.Random; namespace NAK.ScriptingSpoofer; public class ScriptingSpoofer : MelonMod { private static readonly MelonPreferences_Category Category = MelonPreferences.CreateCategory(nameof(ScriptingSpoofer)); private static readonly MelonPreferences_Entry EntryEnabled = Category.CreateEntry("mod_enabled", true, "Enabled", description: "Toggle scripting spoofer."); private static readonly MelonPreferences_Entry EntryCensorUsername = Category.CreateEntry("censor_username", true, "Censor Username", description: "Censor username. Toggle to randomize username instead."); private static string spoofedUsername; private static string spoofedUserId; private static readonly char[] CensorChars = {'!', '@', '#', '$', '%', '^', '&', '*'}; public override void OnInitializeMelon() { ApplyPatches(typeof(PlayerApiPatches)); // Regenerate spoofed data on login CVRGameEventSystem.Authentication.OnLogin.AddListener(GenerateRandomSpoofedData); } private void ApplyPatches(Type type) { try { HarmonyInstance.PatchAll(type); } catch (Exception e) { LoggerInstance.Msg($"Failed while patching {type.Name}!"); LoggerInstance.Error(e); } } private static void GenerateRandomSpoofedData(UserAuthResponse _) // we get manually { spoofedUsername = EntryCensorUsername.Value ? GenerateCensoredUsername() : GenerateRandomUsername(); spoofedUserId = Guid.NewGuid().ToString(); } private static string GenerateCensoredUsername() { var originalUsername = AuthManager.Username; var usernameArray = originalUsername.ToCharArray(); for (var i = 0; i < usernameArray.Length; i++) if (Random.value > 0.7f) usernameArray[i] = CensorChars[Random.Range(0, CensorChars.Length)]; var modifiedUsername = new string(usernameArray); string[] prefixes = { "xX", "_", Random.Range(10, 99).ToString() }; string[] suffixes = { "Xx", "_", Random.Range(10, 99).ToString() }; var prefix = prefixes[Random.Range(0, prefixes.Length)]; var suffix = suffixes[Random.Range(0, suffixes.Length)]; return prefix + modifiedUsername + suffix; } private static string GenerateRandomUsername() { const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; char[] username = new char[Random.Range(5, 15)]; for (int i = 0; i < username.Length; i++) username[i] = chars[Random.Range(0, chars.Length)]; return new string(username); } private static class PlayerApiPatches { [HarmonyPrefix] [HarmonyPatch(typeof(LocalPlayerAPI), nameof(LocalPlayerAPI.Username), MethodType.Getter)] [HarmonyPatch(typeof(PlayerAPIBase), nameof(PlayerAPIBase.Username), MethodType.Getter)] private static bool GetSpoofedUsername(ref PlayerAPIBase __instance, ref string __result) { if (__instance.IsRemote) return true; if (!EntryEnabled.Value) return true; __result = spoofedUsername; return false; } [HarmonyPrefix] [HarmonyPatch(typeof(LocalPlayerAPI), nameof(LocalPlayerAPI.UserID), MethodType.Getter)] [HarmonyPatch(typeof(PlayerAPIBase), nameof(PlayerAPIBase.UserID), MethodType.Getter)] private static bool GetSpoofedUserId(ref PlayerAPIBase __instance, ref string __result) { if (__instance.IsRemote) return true; if (!EntryEnabled.Value) return true; __result = spoofedUserId; return false; } } }