diff --git a/Main.cs b/Main.cs index b26ec4e31..f2c3de98f 100644 --- a/Main.cs +++ b/Main.cs @@ -931,6 +931,7 @@ public class Main : BasePlugin BanManager.Init(); TemplateManager.Init(); SpamManager.Init(); + AmciRegistration.Apply(); IRandom.SetInstance(new NetRandomWrapper()); diff --git a/Modules/AmciRegistration.cs b/Modules/AmciRegistration.cs new file mode 100644 index 000000000..719f6d4d3 --- /dev/null +++ b/Modules/AmciRegistration.cs @@ -0,0 +1,69 @@ +using System; +using AmongUs.GameOptions; +using HarmonyLib; +using Hazel; +using InnerNet; + +namespace EHR.Modules; + +/// +/// Handles AU MCI (Among Us Modded Client Identification) registration for EHR. +/// See: https://github.com/Innersloth-LLC/AmongUsModdingInformation +/// +/// On startup, EHR's GUID is written into the game's mod registration slot. +/// The matchmaker picks this up automatically and injects a mod filter into +/// every lobby search, so Find Game exclusively returns EHR lobbies to EHR clients. +/// +/// The hosting side is handled by , which appends +/// EHR's GUID to the host packet so Innersloth's servers register the lobby +/// as modded and remove it from the vanilla matchmaking pool. +/// +public static class AmciRegistration +{ + /// + /// EHR's AMCI mod GUID. Do not change this after it ships to players or they won't be able + /// to find EHR lobbies until they update. + /// + private const string ModGuidString = "446420cc-ce35-4c2f-8f5d-b14f84354421"; + + /// + /// Writes EHR's GUID into the game's mod registration slot so the matchmaker + /// can filter lobby searches to EHR lobbies only. + /// Call once from + /// + public static void Apply() + { + CurrentModRegistration.ModRegistrationGuidString = ModGuidString; + Logger.Info($"AMCI mod GUID registered: {ModGuidString}", nameof(AmciRegistration)); + } + + /// + /// Replaces the standard HostGame packet with the modded variant and appends + /// EHR's GUID, so Innersloth's servers register this lobby as a modded EHR + /// lobby and remove it from vanilla matchmaking. + /// + [HarmonyPatch(typeof(InnerNetClient), nameof(InnerNetClient.HostGame))] + public static class HostGamePatch + { + public static bool Prefix(InnerNetClient __instance, IGameOptions settings, GameFilterOptions filterOpts) + { + if (!Guid.TryParse(ModGuidString, out Guid guid)) + { + Logger.Warn("Failed to parse AMCI mod GUID, falling back to standard HostGame", nameof(AmciRegistration)); + return true; + } + + MessageWriter msg = MessageWriter.Get(SendOption.Reliable); + msg.StartMessage(Tags.HostModdedGame); + msg.WriteBytesAndSize(__instance.gameOptionsFactory.ToBytes(settings, AprilFoolsMode.IsAprilFoolsModeToggledOn)); + msg.Write(CrossplayMode.GetCrossplayFlags()); + filterOpts.Serialize(msg); + msg.Write(guid.ToByteArray()); + msg.EndMessage(); + __instance.SendOrDisconnect(msg); + msg.Recycle(); + + return false; + } + } +}