.
675 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 | 🔓Unlock Among Us: cosmetics, account, chat and more!🎉
22 |
23 | # 🎉 Features
24 | - 🎭 Unlock Cosmetics[*](/README.md#️-disclaimer) (Hats, Visors, Skins, Pets, Nameplates, Cosmicubes, Bundles)
25 | - 🌐 Account Features
26 | - Removes the following restrictions that apply to guest accounts:
27 | - Not being able to set a custom name
28 | - Quick Chat Only
29 | - Not being able to use the friend list
30 | - Removes the following restrictions that apply to minor accounts:
31 | - Not being able to play online
32 | - Removes the time penalty after disconnecting from too many lobbies
33 | - 💬 Chat Features
34 | - Use `Ctrl + C` and `Ctrl + V` to copy-paste chat messages
35 | - Be able to send URLs and Email addresses
36 | - Increase the character limit from 100 to 120
37 | - ✨ Other Features
38 | - Remove the 60 FPS cap
39 | - Prevent the game from collecting analytics and sending them to Innersloth
40 | - Be able to activate the April Fools Mode (Long Boi and Horse Mode)
41 | - Show more information when finding a game: host name, lobby code, host platform, and lobby age
42 | - Show the task panel (contains a list of your tasks) during meetings
43 | - 💣 Unsafe
44 | - Be able to send any character in chat
45 | - No character limit in chat
46 | - No 3s cooldown between chat messages
47 |
48 | > [!NOTE]
49 | > Features can be individually enabled & disabled by editing the file `[YOUR_AMONG_US_FOLDER]/BepInEx/config/AUnlocker.cfg`
50 | >
51 | > `💣 Unsafe` Features can get you kicked by the anti-cheat. Use them with caution.
52 |
53 | # 🔥 Releases
54 | Before you download anything, make sure your platform is supported:
55 | - ✅ PC / Desktop (Steam, itch.io, Epic Games, Microsoft Store, Xbox App)
56 | - ❌ Mobile (Google Play & App Store)
57 | - ❌ Console (Playstation, Nintendo Switch, Xbox)
58 |
59 | The table below lists the most recent AUnlocker release for each Among Us version. Release notes can be found below each new [release](../../releases).
60 |
61 | | Among Us Version | AUnlocker Version |
62 | |:-----------------------:|:-----------------------------------:|
63 | | `16.0.5` (`2025.5.20`) | [v1.2.0](../../releases/tag/v1.2.0) |
64 | | `16.0.2` (`2025.3.31`) | [v1.1.8](../../releases/tag/v1.1.8) |
65 | | `16.0.0` (`2025.3.25`) | [v1.1.8](../../releases/tag/v1.1.8) |
66 | | `2024.11.26` | [v1.1.7](../../releases/tag/v1.1.7) |
67 | | `2024.10.29` | [v1.1.7](../../releases/tag/v1.1.7) |
68 | | `2024.9.4` | [v1.1.7](../../releases/tag/v1.1.7) |
69 | | `2024.8.13` | [v1.1.6](../../releases/tag/v1.1.6) |
70 | | `2024.6.18` | [v1.1.5](../../releases/tag/v1.1.5) |
71 | | `2024.3.05` | [v1.1.4](../../releases/tag/v1.1.4) |
72 | | `2023.11.28` | [v1.1.3](../../releases/tag/v1.1.3) |
73 | | `2023.10.24` | [v1.1.0](../../releases/tag/v1.1.0) |
74 |
75 | # 💾 Installation
76 | ## 🪟 Windows
77 | - [Download](../../releases/latest) either `AUnlocker_v*_Steam_Itch.zip` or `AUnlocker_v*_EpicGames_MicrosoftStore_XboxApp.zip` depending on your edition of Among Us.
78 | - Extract the contents of the zip into your Among Us folder. You can find your Among Us folder like this:
79 | - **Steam:** Right-click Among Us in your library → `Manage` → `Browse local files`
80 | - **Epic Games:** Right-click Among Us in your library → `Manage` → click the small folder icon next to `Installation`
81 | - **Itch.io:** Open the Itch.io app → Right-click Among Us in your library → `Manage` → `Open folder in Explorer`.
82 | - **Xbox App:** Open the Xbox app → Right-click Among Us in your library → `Manage` → `Files` → `Browse...`
83 | - **Microsoft Store:** Check [this support article](https://answers.microsoft.com/en-us/xbox/forum/all/where-can-i-find-the-gamefiles-of-a-game/5cb9a0c3-7948-4316-abc5-f27d1767b932) on how to find and access your Among Us folder.
84 | - Your game folder should look like this after installation:
85 |
86 |
87 | - Launch Among Us. The first launch will take **MUCH** longer, so don't worry if you have to wait a few minutes.
88 |
89 | ## 🐧 Linux
90 | - Make sure you are running Among Us under Proton (or Wine). On Steam you can check this by right-clicking Among Us in your library → `Properties` → `Compatibility` → `Force the use of a specific Steam Play compatibility tool`. Test different Proton versions if you're having issues launching the game.
91 | - Check out [this guide](https://docs.bepinex.dev/articles/advanced/proton_wine.html) to get BepInEx (the framework AUnlocker is built upon) working. Alternatively, if you are using Proton with Steam, you can specify the DLL override in the launch options (right-click Among Us in your library → `Properties` → `General` → `Launch Options`): `WINEDLLOVERRIDES="winhttp.dll=n,b" %command%` Then follow the steps for Windows.
92 | - If you are experiencing crashes or errors like `Unable to execute IL2CPP chainloader`, set your launch options (right-click Among Us in your library → `Properties` → `General` → `Launch Options`) to `PROTON_NO_ESYNC=1 PROTON_USE_WINED3D=1 WINEDLLOVERRIDES="winhttp.dll=n,b" %command%`
93 |
94 |
95 |
96 | 👾 If you are already using other mods or already have BepInEx installed:
97 | - You should see a folder called `BepInEx` inside your Among Us folder.
98 | - Download `AUnlocker_v*.dll` from the [latest release](../../releases/latest), put it into `BepInEx/plugins` and launch Among Us.
99 |
100 | 👷♂️ If you don't want to download the pre-compiled DLL, you can build AUnlocker from source by following these steps:
101 | - Make sure you have the [Microsoft .NET SDK](https://dotnet.microsoft.com/en-us/download) and [git](https://git-scm.com/downloads) installed.
102 | - Download the necessary files with `git clone https://github.com/astra1dev/AUnlocker`
103 | - Run the command `dotnet build` from the AUnlocker folder (where `AUnlocker.sln` is located)
104 | - The compiled DLL will be located here: `src/bin/Debug/net6.0/AUnlocker.dll`. Put it into `BepInEx/plugins` and launch Among Us.
105 |
106 | # 👨💻 Contributing
107 | General contribution:
108 | - For bug reports and feature requests, [open a new issue](/issues/new)
109 | - If you want to add a new feature or edit / improve existing code, fork this repo and create a pull request with your changes. ([how?](https://docs.github.com/en/get-started/exploring-projects-on-github/contributing-to-a-project))
110 |
111 | Getting started modding Among Us:
112 | - Learn [C#](https://en.wikipedia.org/wiki/C_Sharp_(programming_language)) and [Unity](https://unity.com), as well as [BepInEx](https://github.com/BepInEx/BepInEx) and [HarmonyX](https://github.com/BepInEx/HarmonyX)
113 | - Read the [docs](https://docs.reactor.gg) for [Reactor](https://github.com/NuclearPowered/Reactor), a modding API for Among Us. \
114 | Join their [discord](https://reactor.gg/discord) for the latest `Assembly-CSharp.dll` files. Open them using [dnSpy](https://github.com/dnSpy/dnSpy) to view the game's decompiled client code.
115 | - Take a look at [sus.wiki](https://github.com/roobscoob/among-us-protocol) to learn more about the Among Us network protocol
116 |
117 | For more detailed contribution guidelines, read [CONTRIBUTING.md](/.github/CONTRIBUTING.md)
118 |
119 | # ⚠️ Disclaimer
120 | AUnlocker does not unlock all cosmetics **permanently**, so it does **not** add them to your account. This is because your progress is stored on the Innersloth servers. If you uninstall this mod, the cosmetics will be locked again. The cosmetics you have already unlocked, e.g. through buying a cosmicube, are **untouched** by this mod.
121 |
122 | This mod is not affiliated with Among Us or Innersloth LLC, and the content contained therein is not endorsed or otherwise sponsored by Innersloth LLC. Portions of the materials contained herein are property of Innersloth LLC. © Innersloth LLC.
123 |
--------------------------------------------------------------------------------
/build.cake:
--------------------------------------------------------------------------------
1 | var target = Argument("target", "Build");
2 |
3 | var workflow = BuildSystem.GitHubActions.Environment.Workflow;
4 | var buildId = workflow.RunNumber;
5 | var tag = workflow.RefType == GitHubActionsRefType.Tag ? workflow.RefName : null;
6 |
7 | Task("Build")
8 | .Does(() =>
9 | {
10 | var settings = new DotNetBuildSettings
11 | {
12 | Configuration = "Release",
13 | MSBuildSettings = new DotNetMSBuildSettings()
14 | };
15 |
16 | if (tag != null)
17 | {
18 | settings.MSBuildSettings.Version = tag;
19 | }
20 | else if (buildId != 0)
21 | {
22 | settings.MSBuildSettings.VersionSuffix = "ci." + buildId;
23 | }
24 |
25 | DotNetBuild(".", settings);
26 | });
27 |
28 | RunTarget(target);
29 |
--------------------------------------------------------------------------------
/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/astra1dev/AUnlocker/1dc7f4be29b6be3378452a905a65a47bf99e10a0/icon.png
--------------------------------------------------------------------------------
/nuget.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/src/AUnlocker.cs:
--------------------------------------------------------------------------------
1 | using BepInEx;
2 | using BepInEx.Unity.IL2CPP;
3 | using HarmonyLib;
4 | using BepInEx.Configuration;
5 | using UnityEngine.Analytics;
6 | using UnityEngine.CrashReportHandler;
7 |
8 | namespace AUnlocker;
9 |
10 | [BepInAutoPlugin]
11 | [BepInProcess("Among Us.exe")]
12 | public partial class AUnlocker : BasePlugin
13 | {
14 | public Harmony Harmony { get; } = new(Id);
15 |
16 | // Account
17 | public static ConfigEntry UnlockGuest;
18 | public static ConfigEntry UnlockMinor;
19 | public static ConfigEntry RemovePenalty;
20 |
21 | // Chat
22 | public static ConfigEntry PatchChat;
23 |
24 | // Cosmetics
25 | public static ConfigEntry UnlockCosmetics;
26 |
27 | // Other
28 | public static ConfigEntry UnlockFPS;
29 | public static ConfigEntry DisableTelemetry;
30 | public static ConfigEntry UnlockAprilFoolsMode;
31 | public static ConfigEntry EnableHorseMode;
32 | public static ConfigEntry MoreLobbyInfo;
33 | public static ConfigEntry ShowTaskPanelInMeetings;
34 |
35 | // Unsafe
36 | public static ConfigEntry AllowAllCharacters;
37 | public static ConfigEntry NoCharacterLimit;
38 | public static ConfigEntry NoChatCooldown;
39 |
40 | ///
41 | /// Initialize the plugin, set up configuration entries and apply patches.
42 | ///
43 | public override void Load()
44 | {
45 | // Account
46 | UnlockGuest = Config.Bind("Account", "RemoveGuestStatus", false, "Remove guest restrictions (no custom name, no free chat, no friend list)");
47 | UnlockMinor = Config.Bind("Account", "RemoveMinorStatus", false, "Remove minor status and restrictions (no online play)");
48 | RemovePenalty = Config.Bind("Account", "NoDisconnectPenalty", true, "Remove the penalty after disconnecting from too many lobbies");
49 | // Chat
50 | PatchChat = Config.Bind("Chat", "Enabled", true, "Allow Ctrl+C and Ctrl+V (copy-pasting)\nBe able to send URLs and Email addresses\nIncrease the character limit from 100 to 120");
51 | // Cosmetics
52 | UnlockCosmetics = Config.Bind("Cosmetics", "UnlockAll", true, "Unlock all cosmetics");
53 | // Other
54 | UnlockFPS = Config.Bind("Other", "FPS", 60, "Set the game's FPS cap to this value");
55 | DisableTelemetry = Config.Bind("Other", "DisableTelemetry", true, "Prevent the game from collecting analytics and sending them to Innersloth");
56 | UnlockAprilFoolsMode = Config.Bind("Other", "UnlockAprilFoolsMode", false, "Add the ability to enable Long Boi Mode (only client-side)");
57 | EnableHorseMode = Config.Bind("Other", "EnableHorseMode", false, "Enable Horse Mode (only client-side)");
58 | MoreLobbyInfo = Config.Bind("Other", "MoreLobbyInfo", false, "Show more information when finding a game: host name (e.g. Astral), lobby code (e.g. KLHCEG), host platform (e.g. Epic), and lobby age in minutes (e.g. 4:20)");
59 | ShowTaskPanelInMeetings = Config.Bind("Other", "ShowTaskPanelInMeetings", false, "Show the task panel (contains a list of your tasks) during meetings");
60 | // Unsafe
61 | AllowAllCharacters = Config.Bind("Unsafe", "AllowAllCharacters", false, "THESE ARE UNSAFE AND CAN GET YOU KICKED BY ANTI-CHEAT, USE WITH CAUTION\n\nBe able to send any character in chat");
62 | NoCharacterLimit = Config.Bind("Unsafe", "NoCharacterLimit", false, "No character limit in chat");
63 | NoChatCooldown = Config.Bind("Unsafe", "NoChatCooldown", false, "No 3s cooldown between chat messages");
64 |
65 | Harmony.PatchAll();
66 |
67 | if (!DisableTelemetry.Value) return;
68 | Analytics.deviceStatsEnabled = false;
69 | Analytics.enabled = false;
70 | Analytics.initializeOnStartup = false;
71 | Analytics.limitUserTracking = true;
72 | CrashReportHandler.enableCaptureExceptions = false;
73 | PerformanceReporting.enabled = false;
74 |
75 | // If Among Us updates their IAP / Analytics system, we will need to use this:
76 | // using Unity.Services.Analytics;
77 | // using Unity.Services.Core;
78 | // AnalyticsService.Instance.OptOut();
79 | // More Info: https://discussions.unity.com/t/iap-privacy-issue/881743
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/src/AUnlocker.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | net6.0
4 | latest
5 | embedded
6 |
7 | 1.1.8
8 |
9 | Unlock Among Us: cosmetics, account, chat and more!
10 | Astral
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/src/AccountPatches.cs:
--------------------------------------------------------------------------------
1 | using AmongUs.Data.Player;
2 | using HarmonyLib;
3 |
4 | namespace AUnlocker;
5 |
6 | // Some of the below patches are from https://github.com/scp222thj/MalumMenu/
7 |
8 | [HarmonyPatch(typeof(EOSManager), nameof(EOSManager.IsFreechatAllowed))]
9 | public static class UnlockFreechat_EOSManager_IsFreechatAllowed_Postfix
10 | {
11 | ///
12 | /// Allow creating and joining free chat lobbies instead of quick chat only.
13 | ///
14 | /// Original return value of IsFreechatAllowed.
15 | public static void Postfix(ref bool __result)
16 | {
17 | if (AUnlocker.UnlockGuest.Value)
18 | {
19 | __result = true;
20 | }
21 | }
22 | }
23 |
24 | [HarmonyPatch(typeof(EOSManager), nameof(EOSManager.IsFriendsListAllowed))]
25 | public static class UnlockFriendlist_EOSManager_IsFriendsListAllowed_Postfix
26 | {
27 | ///
28 | /// Allow using the friends list.
29 | ///
30 | /// Original return value of IsFriendsListAllowed.
31 | public static void Postfix(ref bool __result)
32 | {
33 | if (AUnlocker.UnlockGuest.Value)
34 | {
35 | __result = true;
36 | }
37 | }
38 | }
39 |
40 | [HarmonyPatch(typeof(FullAccount), nameof(FullAccount.CanSetCustomName))]
41 | public static class CustomNameEnabled_FullAccount_CanSetCustomName_Prefix
42 | {
43 | ///
44 | /// Allow setting a custom name.
45 | ///
46 | /// Original return value of CanSetCustomName.
47 | public static void Prefix(ref bool canSetName)
48 | {
49 | if (AUnlocker.UnlockGuest.Value)
50 | {
51 | canSetName = true;
52 | }
53 | }
54 | }
55 |
56 | [HarmonyPatch(typeof(EOSManager), nameof(EOSManager.IsMinorOrWaiting))]
57 | public static class RemoveMinorStatus_EOSManager_IsMinorOrWaiting_Postfix
58 | {
59 | ///
60 | /// Remove "minor" status.
61 | ///
62 | /// Original return value of IsMinorOrWaiting.
63 | public static void Postfix(ref bool __result)
64 | {
65 | if (AUnlocker.UnlockMinor.Value)
66 | {
67 | __result = false;
68 | }
69 | }
70 | }
71 |
72 | [HarmonyPatch(typeof(EOSManager), nameof(EOSManager.IsAllowedOnline))]
73 | public static class OnlineGameplay_EOSManager_IsAllowedOnline_Prefix
74 | {
75 | ///
76 | /// Allow creating and joining online lobbies.
77 | ///
78 | /// Original return value of IsAllowedOnline.
79 | public static void Prefix(ref bool canOnline)
80 | {
81 | if (AUnlocker.UnlockMinor.Value)
82 | {
83 | canOnline = true;
84 | }
85 | }
86 | }
87 |
88 | [HarmonyPatch(typeof(AccountManager), nameof(AccountManager.CanPlayOnline))]
89 | public static class OnlineGameplay_AccountManager_CanPlayOnline_Postfix
90 | {
91 | ///
92 | /// Allow creating and joining online lobbies.
93 | ///
94 | /// Original return value of CanPlayOnline.
95 | public static void Postfix(ref bool __result)
96 | {
97 | if (AUnlocker.UnlockMinor.Value)
98 | {
99 | __result = true;
100 | }
101 | }
102 | }
103 |
104 | [HarmonyPatch(typeof(InnerNet.InnerNetClient), nameof(InnerNet.InnerNetClient.JoinGame))]
105 | public static class SetLoggedIn_InnerNetClient_JoinGame_Prefix
106 | {
107 | ///
108 | /// Set the login status to "logged in" to allow joining public games.
109 | ///
110 | public static void Prefix()
111 | {
112 | if (AUnlocker.UnlockMinor.Value)
113 | {
114 | AmongUs.Data.DataManager.Player.Account.LoginStatus = EOSManager.AccountLoginStatus.LoggedIn;
115 | }
116 | }
117 | }
118 |
119 | [HarmonyPatch(typeof(PlayerBanData), nameof(PlayerBanData.BanPoints), MethodType.Setter)]
120 | public static class RemoveDisconnectPenalty_PlayerBanData_BanPoints_Prefix
121 | {
122 | ///
123 | /// Remove the time penalty after disconnecting from too many lobbies.
124 | ///
125 | /// The PlayerBanData instance.
126 | /// The value being set to BanPoints.
127 | /// false to skip the original method, true to allow the original method to run.
128 | public static bool Prefix(PlayerBanData __instance, ref float value)
129 | {
130 | if (!AUnlocker.RemovePenalty.Value) return true;
131 | if (!(bool) (UnityEngine.Object) AmongUsClient.Instance || AmongUsClient.Instance.NetworkMode != NetworkModes.OnlineGame)
132 | return true;
133 |
134 | value = 0f;
135 | //__instance.BanPoints = 0f; // Remove all BanPoints
136 | return false;
137 | }
138 | }
139 |
--------------------------------------------------------------------------------
/src/ChatPatches.cs:
--------------------------------------------------------------------------------
1 | using HarmonyLib;
2 | using UnityEngine;
3 |
4 | namespace AUnlocker;
5 |
6 | [HarmonyPatch(typeof(ChatController), nameof(ChatController.Update))]
7 | public static class ChatJailbreak_ChatController_Update_Postfix
8 | {
9 | ///
10 | /// Remove the chat cooldown and the character limit.
11 | ///
12 | /// The ChatController instance.
13 | public static void Postfix(ChatController __instance)
14 | {
15 | // [UNSAFE] No Chat Cooldown
16 | if (AUnlocker.NoChatCooldown.Value)
17 | {
18 | // if (!__instance.freeChatField.textArea.hasFocus) return;
19 | __instance.timeSinceLastMessage = 3f;
20 | }
21 |
22 | // [UNSAFE] No Character Limit
23 | if (AUnlocker.NoCharacterLimit.Value)
24 | {
25 | __instance.freeChatField.textArea.characterLimit = int.MaxValue;
26 | }
27 |
28 | else if (AUnlocker.PatchChat.Value)
29 | {
30 | __instance.freeChatField.textArea.AllowPaste = true;
31 | __instance.freeChatField.textArea.AllowSymbols = true;
32 | __instance.freeChatField.textArea.AllowEmail = true;
33 | __instance.freeChatField.textArea.allowAllCharacters = true;
34 | __instance.freeChatField.textArea.characterLimit = 120; // above 120 characters anti-cheat will kick you
35 | }
36 | }
37 | }
38 |
39 | [HarmonyPatch(typeof(FreeChatInputField), nameof(FreeChatInputField.UpdateCharCount))]
40 | public static class EditColorIndicators_FreeChatInputField_UpdateCharCount_Postfix
41 | {
42 | ///
43 | /// Update the character count color indicator based on the current text length.
44 | ///
45 | /// The FreeChatInputField instance.
46 | public static void Postfix(FreeChatInputField __instance)
47 | {
48 | if (AUnlocker.NoCharacterLimit.Value)
49 | {
50 | var length = __instance.textArea.text.Length;
51 | // Show new character limit below text field
52 | __instance.charCountText.SetText($"{length}/{__instance.textArea.characterLimit}");
53 |
54 | __instance.charCountText.color = length switch
55 | {
56 | // Black if not close to limit (under 75%)
57 | < 1610612735 => Color.black,
58 | // Yellow if close to limit (under 100%)
59 | < 2147483647 => new Color(1f, 1f, 0f, 1f),
60 | _ => Color.red
61 | };
62 | }
63 |
64 | else if (AUnlocker.PatchChat.Value)
65 | {
66 | var length = __instance.textArea.text.Length;
67 | // Show new character limit below text field
68 | __instance.charCountText.SetText($"{length}/{__instance.textArea.characterLimit}");
69 |
70 | __instance.charCountText.color = length switch
71 | {
72 | // Black if not close to limit (under 75%)
73 | < 90 => Color.black,
74 | // Yellow if close to limit (under 100%)
75 | < 120 => new Color(1f, 1f, 0f, 1f),
76 | _ => Color.red
77 | };
78 | }
79 | }
80 | }
81 |
82 | [HarmonyPatch(typeof(ChatController), nameof(ChatController.SendFreeChat))]
83 | public static class AllowURLS_ChatController_SendFreeChat_Prefix
84 | {
85 | ///
86 | /// Remove the URL filtering when sending a chat message.
87 | ///
88 | /// The ChatController instance.
89 | /// false to skip the original method, true to allow the original method to run.
90 | public static bool Prefix(ChatController __instance)
91 | {
92 | if (!AUnlocker.PatchChat.Value) return true;
93 |
94 | var text = __instance.freeChatField.Text;
95 | ChatController.Logger.Debug($"SendFreeChat() :: Sending message: '{text}'");
96 | PlayerControl.LocalPlayer.RpcSendChat(text);
97 | return false;
98 | }
99 | }
100 |
101 | [HarmonyPatch(typeof(TextBoxTMP), nameof(TextBoxTMP.IsCharAllowed))]
102 | public static class AllowAllCharacters_TextBoxTMP_IsCharAllowed_Prefix
103 | {
104 | ///
105 | /// Allow any character to be typed into the chatbox.
106 | ///
107 | /// The TextBoxTMP instance.
108 | /// Original return value of IsCharAllowed.
109 | /// The character to check.
110 | /// false to skip the original method, true to allow the original method to run.
111 | public static bool Prefix(TextBoxTMP __instance, ref bool __result, char i)
112 | {
113 | // Original game code:
114 | // public bool IsCharAllowed(char i)
115 | // {
116 | // return this.IpMode ? i >= '0' && i <= '9' || i == '.' : i == ' ' || i >= 'A' && i <= 'Z' || i >= 'a' && i <= 'z' || i >= '0' && i <= '9' || i >= 'À' && i <= 'ÿ' || i >= 'Ѐ' && i <= 'џ' || i >= '\u3040' && i <= '㆟' || i >= 'ⱡ' && i <= '힣' || this.AllowSymbols && TextBoxTMP.SymbolChars.Contains(i) || this.AllowEmail && TextBoxTMP.EmailChars.Contains(i);
117 | // }
118 |
119 | if (!AUnlocker.AllowAllCharacters.Value) return true;
120 |
121 | if (i is >= 'À' and <= 'ÿ')
122 | {
123 | __result = true;
124 | return false;
125 | }
126 | if (i is >= 'Ѐ' and <= 'џ')
127 | {
128 | __result = true;
129 | return false;
130 | }
131 | if (i is >= '\u3040' and <= '㆟')
132 | {
133 | __result = true;
134 | return false;
135 | }
136 | if (i is >= 'ⱡ' and <= '힣')
137 | {
138 | __result = true;
139 | return false;
140 | }
141 | if (TextBoxTMP.SymbolChars.Contains(i))
142 | {
143 | __result = true;
144 | return false;
145 | }
146 | if (TextBoxTMP.EmailChars.Contains(i))
147 | {
148 | __result = true;
149 | return false;
150 | }
151 | // Bugfix: backspace messing with chat message;
152 | // newline / "enter" to prevent message sending "randomly" (see issue #25)
153 | if (i is '\b' or '\n' or '\r')
154 | {
155 | __result = false;
156 | return false;
157 | }
158 |
159 | // // logging
160 | // string charRepresentation = i switch
161 | // {
162 | // '\b' => "\\b",
163 | // '\n' => "\\n",
164 | // '\r' => "\\r",
165 | // _ => i.ToString()
166 | // };
167 |
168 | // Debug.Log($"IsCharAllowed({charRepresentation}) (Unicode: {(int)i}) = {__result}");
169 |
170 | // accept any other character by default (including emojis, special characters, etc.)
171 | // this can cause issues where we would have to deny certain characters
172 | // that are messing with the chatbox (like we saw in issues #25 and #31)
173 | __result = true;
174 | return false;
175 | }
176 | }
177 |
178 | [HarmonyPatch(typeof(TextBoxTMP), nameof(TextBoxTMP.Start))]
179 | public static class AllowPaste_TextBoxTMP_Start_Postfix
180 | {
181 | ///
182 | /// Allow email symbols to be typed into the chatbox and enables pasting text with CTRL + V.
183 | ///
184 | /// The TextBoxTMP instance.
185 | public static void Postfix(TextBoxTMP __instance)
186 | {
187 | if (!AUnlocker.PatchChat.Value) return;
188 |
189 | __instance.allowAllCharacters = true; // not used by game's code, but I include it anyway
190 | __instance.AllowEmail = true;
191 | __instance.AllowPaste = true;
192 | __instance.AllowSymbols = true;
193 | }
194 | }
195 |
196 | [HarmonyPatch(typeof(TextBoxTMP), nameof(TextBoxTMP.Update))]
197 | public static class AllowCopy_TextBoxTMP_Update_Postfix
198 | {
199 | ///
200 | /// Allow copying text from the chatbox to the device's clipboard when pressing CTRL + C.
201 | ///
202 | /// The TextBoxTMP instance.
203 | public static void Postfix(TextBoxTMP __instance)
204 | {
205 | if (!AUnlocker.PatchChat.Value || !__instance.hasFocus) return;
206 |
207 | if ((Input.GetKey(KeyCode.LeftControl) || Input.GetKey(KeyCode.RightControl)) && Input.GetKeyDown(KeyCode.C))
208 | {
209 | ClipboardHelper.PutClipboardString(__instance.text);
210 | }
211 | }
212 | }
213 |
--------------------------------------------------------------------------------
/src/CosmeticsPatches.cs:
--------------------------------------------------------------------------------
1 | using HarmonyLib;
2 |
3 | namespace AUnlocker;
4 |
5 | [HarmonyPatch(typeof(HatManager), nameof(HatManager.Initialize))]
6 | public static class UnlockCosmetics_HatManager_Initialize_Postfix
7 | {
8 | // https://github.com/scp222thj/MalumMenu/blob/main/src/Cheats/CosmeticsUnlocker.cs
9 |
10 | ///
11 | /// Unlock all cosmetics by setting their price to 0 and marking them as free.
12 | ///
13 | /// The HatManager instance.
14 | public static void Postfix(HatManager __instance)
15 | {
16 | if (!AUnlocker.UnlockCosmetics.Value) return;
17 |
18 | foreach (var bundle in __instance.allBundles)
19 | { bundle.Free = true; }
20 |
21 | foreach (var featuredBundle in __instance.allFeaturedBundles)
22 | { featuredBundle.Free = true; }
23 |
24 | foreach (var featuredCube in __instance.allFeaturedCubes)
25 | { featuredCube.Free = true; }
26 |
27 | foreach (var featuredItem in __instance.allFeaturedItems)
28 | { featuredItem.Free = true; }
29 |
30 | foreach (var hat in __instance.allHats)
31 | { hat.Free = true; }
32 |
33 | foreach (var nameplate in __instance.allNamePlates)
34 | { nameplate.Free = true; }
35 |
36 | foreach (var pet in __instance.allPets)
37 | { pet.Free = true; }
38 |
39 | foreach (var skin in __instance.allSkins)
40 | { skin.Free = true; }
41 |
42 | foreach (var starBundle in __instance.allStarBundles)
43 | { starBundle.price = 0; }
44 |
45 | foreach (var visor in __instance.allVisors)
46 | { visor.Free = true; }
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/src/OtherPatches.cs:
--------------------------------------------------------------------------------
1 | using UnityEngine;
2 | using HarmonyLib;
3 | using InnerNet;
4 |
5 | namespace AUnlocker;
6 |
7 | [HarmonyPatch(typeof(MainMenuManager), nameof(MainMenuManager.Start))]
8 | public static class UnlockFPS_MainMenuManager_Start_Postfix
9 | {
10 | ///
11 | /// Set the target frame rate based on the config setting.
12 | ///
13 | public static void Postfix()
14 | {
15 | Application.targetFrameRate = AUnlocker.UnlockFPS.Value;
16 | }
17 | }
18 |
19 | [HarmonyPatch(typeof(AprilFoolsMode), nameof(AprilFoolsMode.ShouldShowAprilFoolsToggle))]
20 | public static class UnlockAprilFoolsMode_AprilFoolsMode_ShouldShowAprilFoolsToggle_Postfix
21 | {
22 | ///
23 | /// Force the "April Fools' Mode (Limited Cosmetics)" banner to be visible.
24 | /// Enabling it activates long boi mode (client-side only).
25 | ///
26 | /// Original return value of ShouldShowAprilFoolsToggle.
27 | public static void Postfix(ref bool __result)
28 | {
29 | if (AUnlocker.UnlockAprilFoolsMode.Value)
30 | {
31 | // Remove check if the current server time is within the first week of april
32 | __result = true;
33 | }
34 | }
35 | }
36 |
37 | // maybe remove the below patch and patch ShouldHorseAround instead
38 | // this will probably allow horse mode to work in HnS properly
39 |
40 | // maybe also remove the above patch and patch ShouldLongAround instead
41 | [HarmonyPatch(typeof(NormalGameManager), nameof(NormalGameManager.GetBodyType))]
42 | public static class EnableHorseMode_NormalGameManager_GetBodyType_Postfix
43 | {
44 | ///
45 | /// Set the player's body type to Horse when the horse mode config setting is enabled. (client-side only)
46 | ///
47 | /// Original return value of GetBodyType.
48 | public static void Postfix(ref PlayerBodyTypes __result)
49 | {
50 | if (!AUnlocker.EnableHorseMode.Value) return;
51 | __result = PlayerBodyTypes.Horse;
52 | }
53 | }
54 |
55 | // https://github.com/g0aty/SickoMenu/blob/main/hooks/LobbyBehaviour.cpp
56 | [HarmonyPatch(typeof(GameContainer), nameof(GameContainer.SetupGameInfo))]
57 | public static class MoreLobbyInfo_GameContainer_SetupGameInfo_Postfix
58 | {
59 | ///
60 | /// Show more information when finding a game:
61 | /// host name (e.g. Astral), lobby code (e.g. KLHCEG), host platform (e.g. Epic), and lobby age in minutes (e.g. 4:20)
62 | ///
63 | /// The GameContainer instance.
64 | public static void Postfix(GameContainer __instance)
65 | {
66 | if (!AUnlocker.MoreLobbyInfo.Value) return;
67 |
68 | var trueHostName = __instance.gameListing.TrueHostName;
69 |
70 | // The Crewmate icon gets aligned properly with this
71 | const string separator = "<#0000>000000000000000";
72 |
73 | var age = __instance.gameListing.Age;
74 | var lobbyTime = $"Age: {age / 60}:{(age % 60 < 10 ? "0" : "")}{age % 60}";
75 |
76 | var platformId = __instance.gameListing.Platform switch
77 | {
78 | Platforms.StandaloneEpicPC => "Epic",
79 | Platforms.StandaloneSteamPC => "Steam",
80 | Platforms.StandaloneMac => "Mac",
81 | Platforms.StandaloneWin10 => "Microsoft Store",
82 | Platforms.StandaloneItch => "Itch.io",
83 | Platforms.IPhone => "iPhone / iPad",
84 | Platforms.Android => "Android",
85 | Platforms.Switch => "Nintendo Switch",
86 | Platforms.Xbox => "Xbox",
87 | Platforms.Playstation => "PlayStation",
88 | _ => "Unknown"
89 | };
90 | // Set the text of the capacity field to include the new information
91 | __instance.capacity.text = $"{separator}\n{trueHostName}\n{__instance.capacity.text}\n" +
92 | $"<#fb0>{GameCode.IntToGameName(__instance.gameListing.GameId)}\n" +
93 | $"<#b0f>{platformId}\n{lobbyTime}\n{separator}";
94 | }
95 | }
96 |
97 | [HarmonyPatch(typeof(HudManager))]
98 | [HarmonyPatch("SetHudActive", typeof(PlayerControl), typeof(RoleBehaviour), typeof(bool))]
99 | public static class ShowTaskPanelInMeetings_HudManager_SetHudActive
100 | {
101 | ///
102 | /// Show the task panel (contains a list of your tasks) during meetings.
103 | ///
104 | /// The HudManager instance.
105 | /// The role of the player.
106 | /// Whether to set the Hud to active or inactive.
107 | public static void Postfix(HudManager __instance, RoleBehaviour role, bool isActive)
108 | {
109 | if (!AUnlocker.ShowTaskPanelInMeetings.Value) return;
110 | if (!MeetingHud.Instance) return;
111 |
112 | // Modify openPosition so the task panel appears on top of the meeting screen
113 | var openPosition = __instance.TaskPanel.openPosition;
114 | openPosition.z = -20f;
115 | __instance.TaskPanel.openPosition = openPosition;
116 |
117 | __instance.TaskPanel.gameObject.SetActive(true);
118 | }
119 | }
120 |
--------------------------------------------------------------------------------