From: linmeideli <2558527373@qq.com> Date: Wed, 19 Aug 2026 04:27:18 +0000 (+0800) Subject: Basically support AMCI X-Git-Tag: v1.10.8~4 X-Git-Url: https://git.deb.at/?a=commitdiff_plain;h=510ed07389a63d091b43fe2de73499a316b6333a;p=rhonda%2Fimpostor.git Basically support AMCI --- diff --git a/src/Impostor.Api.Innersloth.Generator/packages.lock.json b/src/Impostor.Api.Innersloth.Generator/packages.lock.json index 4448822..fd80d2f 100644 --- a/src/Impostor.Api.Innersloth.Generator/packages.lock.json +++ b/src/Impostor.Api.Innersloth.Generator/packages.lock.json @@ -151,6 +151,7 @@ "System.Runtime.CompilerServices.Unsafe": "4.5.3" } } - } + }, + ".NETStandard,Version=v2.0/win-x64": {} } } \ No newline at end of file diff --git a/src/Impostor.Api/Games/IGame.cs b/src/Impostor.Api/Games/IGame.cs index 71c764a..e1bdc21 100644 --- a/src/Impostor.Api/Games/IGame.cs +++ b/src/Impostor.Api/Games/IGame.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Net; using System.Threading.Tasks; using Impostor.Api.Innersloth; @@ -47,6 +48,11 @@ namespace Impostor.Api.Games /// bool IsHostAuthoritive { get; } + /// + /// Gets the mod GUID that the game was registered with through the AMCI. + /// + Guid? ModGuid { get; } + IClientPlayer? GetClientPlayer(int clientId); T? FindObjectByNetId(uint netId) diff --git a/src/Impostor.Api/Innersloth/GameFilters/GameFilter.cs b/src/Impostor.Api/Innersloth/GameFilters/GameFilter.cs index 43e7c91..7357f5f 100644 --- a/src/Impostor.Api/Innersloth/GameFilters/GameFilter.cs +++ b/src/Impostor.Api/Innersloth/GameFilters/GameFilter.cs @@ -73,6 +73,9 @@ namespace Impostor.Api.Innersloth.GameFilters case "bool": return JsonSerializer.Deserialize(filterString) ?? throw new InvalidOperationException("Deserialization returned null for BoolGameFilter"); + case "mod": + return JsonSerializer.Deserialize(filterString) + ?? throw new InvalidOperationException("Deserialization returned null for ModFilter"); default: throw new InvalidOperationException("No type matches subfilter"); } diff --git a/src/Impostor.Api/Innersloth/GameFilters/ModFilter.cs b/src/Impostor.Api/Innersloth/GameFilters/ModFilter.cs new file mode 100644 index 0000000..71e282d --- /dev/null +++ b/src/Impostor.Api/Innersloth/GameFilters/ModFilter.cs @@ -0,0 +1,16 @@ +using System; +using System.Text.Json.Serialization; + +// https://github.com/Innersloth-LLC/AmongUsModdingInformation +namespace Impostor.Api.Innersloth.GameFilters +{ + [Serializable] + public class ModFilter : ISubFilter + { + [JsonPropertyName("FilterType")] + public string FilterType { get; } = "mod"; + + [JsonPropertyName("AcceptedValues")] + public required Guid AcceptedValues { get; set; } + } +} diff --git a/src/Impostor.Api/Net/Messages/C2S/Message00HostGameC2S.cs b/src/Impostor.Api/Net/Messages/C2S/Message00HostGameC2S.cs index 8b802c2..6bc1758 100644 --- a/src/Impostor.Api/Net/Messages/C2S/Message00HostGameC2S.cs +++ b/src/Impostor.Api/Net/Messages/C2S/Message00HostGameC2S.cs @@ -1,4 +1,4 @@ -using Impostor.Api.Innersloth; +using Impostor.Api.Innersloth; using Impostor.Api.Innersloth.GameOptions; namespace Impostor.Api.Net.Messages.C2S @@ -20,5 +20,11 @@ namespace Impostor.Api.Net.Messages.C2S crossplayFlags = (CrossplayFlags)reader.ReadInt32(); gameFilterOptions = GameFilterOptions.Deserialize(reader); } + + public static void DeserializeModded(IMessageReader reader, out IGameOptions gameOptions, out CrossplayFlags crossplayFlags, out GameFilterOptions gameFilterOptions, out Guid modGuid) + { + Deserialize(reader, out gameOptions, out crossplayFlags, out gameFilterOptions); + modGuid = new Guid(reader.ReadBytes(16).Span); + } } } diff --git a/src/Impostor.Api/Net/Messages/MessageFlags.cs b/src/Impostor.Api/Net/Messages/MessageFlags.cs index 4faba36..a822fbd 100644 --- a/src/Impostor.Api/Net/Messages/MessageFlags.cs +++ b/src/Impostor.Api/Net/Messages/MessageFlags.cs @@ -29,6 +29,7 @@ namespace Impostor.Api.Net.Messages public const byte QueryPlatformIds = 22; public const byte QueryLobbyInfo = 23; public const byte EndGameHostMigration = 24; + public const byte HostModdedGame = 25; public const byte PackedGameDataTo = 26; private static readonly Dictionary FlagCache; diff --git a/src/Impostor.Api/packages.lock.json b/src/Impostor.Api/packages.lock.json index c209cfa..ab47122 100644 --- a/src/Impostor.Api/packages.lock.json +++ b/src/Impostor.Api/packages.lock.json @@ -40,6 +40,12 @@ "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0" } }, + "Microsoft.NET.ILLink.Tasks": { + "type": "Direct", + "requested": "[8.0.30, )", + "resolved": "8.0.30", + "contentHash": "SfmwuZjUPBTEoBMAsXZ/hWkaEK9oL+Y/UtAx7N6RyWHfcMt9J0ExrNPuOgTyPbCXIyiTBFsxFNrPLEZNPmJcvA==" + }, "StyleCop.Analyzers": { "type": "Direct", "requested": "[1.2.0-beta.556, )", @@ -117,6 +123,7 @@ "resolved": "4.5.0", "contentHash": "Xg4G4Indi4dqP1iuAiMSwpiWS54ZghzR644OtsRCm/m/lBMG8dUBhLVN7hLm8NNrNTR+iGbshCPTwrvxZPlm4g==" } - } + }, + "net8.0/win-x64": {} } } \ No newline at end of file diff --git a/src/Impostor.Server/Http/ListingManager.cs b/src/Impostor.Server/Http/ListingManager.cs index 0221d3d..f92b373 100644 --- a/src/Impostor.Server/Http/ListingManager.cs +++ b/src/Impostor.Server/Http/ListingManager.cs @@ -59,6 +59,10 @@ public sealed class ListingManager { continue; } + if (game.ModGuid != null) + { + continue; + } if (!_compatibilityConfig.AllowVersionMixing && game.Host != null && @@ -137,6 +141,10 @@ public sealed class ListingManager { continue; } + if (game.ModGuid != null && !filterSet.Filters.Any(f => f.OptionType == "mod")) + { + continue; + } var matchesAllFilters = true; @@ -191,6 +199,13 @@ public sealed class ListingManager } } + break; + case "mod": + if (filter.SubFilter is ModFilter modFilter && game.ModGuid != modFilter.AcceptedValues) + { + matchesAllFilters = false; + } + break; } diff --git a/src/Impostor.Server/Net/Client.cs b/src/Impostor.Server/Net/Client.cs index 97bb7c2..6d83016 100644 --- a/src/Impostor.Server/Net/Client.cs +++ b/src/Impostor.Server/Net/Client.cs @@ -5,6 +5,7 @@ using Impostor.Api; using Impostor.Api.Config; using Impostor.Api.Games; using Impostor.Api.Innersloth; +using Impostor.Api.Innersloth.GameOptions; using Impostor.Api.Net; using Impostor.Api.Net.Custom; using Impostor.Api.Net.Messages; @@ -41,6 +42,11 @@ namespace Impostor.Server.Net { return false; } + + if (Player != null && Player.Game.ModGuid != null) + { + return false; + } if (Player != null && Player.IsHost) { @@ -124,12 +130,25 @@ namespace Impostor.Server.Net switch (flag) { case MessageFlags.HostGame: + case MessageFlags.HostModdedGame: { - // Read game settings. - Message00HostGameC2S.Deserialize(reader, out var gameOptions, out _, out var gameFilterOptions); + IGameOptions gameOptions; + GameFilterOptions gameFilterOptions; + Guid? modGuid = null; + + if (flag == MessageFlags.HostModdedGame) + { + Message00HostGameC2S.DeserializeModded(reader, out gameOptions, out _, out gameFilterOptions, out var parsedModGuid); + modGuid = parsedModGuid; + } + else + { + // Read game settings. + Message00HostGameC2S.Deserialize(reader, out gameOptions, out _, out gameFilterOptions); + } // Create game. - var game = await _gameManager.CreateAsync(this, gameOptions, gameFilterOptions); + var game = await _gameManager.CreateAsync(this, gameOptions, gameFilterOptions, modGuid); if (game == null) { @@ -137,6 +156,11 @@ namespace Impostor.Server.Net return; } + if (modGuid != null) + { + _logger.LogInformation("Client {Name} ({Id}) hosted a modded game with mod GUID {ModGuid}.", Name, Id, modGuid); + } + // Code in the packet below will be used in JoinGame. using (var writer = MessageWriter.Get(MessageType.Reliable)) { diff --git a/src/Impostor.Server/Net/Manager/GameManager.cs b/src/Impostor.Server/Net/Manager/GameManager.cs index d8d5e97..19d5f33 100644 --- a/src/Impostor.Server/Net/Manager/GameManager.cs +++ b/src/Impostor.Server/Net/Manager/GameManager.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; @@ -85,7 +85,7 @@ namespace Impostor.Server.Net.Manager await _eventManager.CallAsync(new GameDestroyedEvent(game)); } - public async ValueTask CreateAsync(IClient? owner, IGameOptions options, GameFilterOptions filterOptions) + public async ValueTask CreateAsync(IClient? owner, IGameOptions options, GameFilterOptions filterOptions, Guid? modGuid = null) { if (owner != null && !_gamesCreatedBy.TryAdd(owner, null)) { @@ -101,11 +101,11 @@ namespace Impostor.Server.Net.Manager return null; } - var (success, game) = await TryCreateAsync(options, filterOptions, owner, @event.GameCode); + var (success, game) = await TryCreateAsync(options, filterOptions, owner, @event.GameCode, modGuid); for (var i = 0; i < 10 && !success; i++) { - (success, game) = await TryCreateAsync(options, filterOptions, owner); + (success, game) = await TryCreateAsync(options, filterOptions, owner, modGuid: modGuid); } if (owner != null) @@ -126,10 +126,12 @@ namespace Impostor.Server.Net.Manager return CreateAsync(null, options, filterOptions); } - private async ValueTask<(bool Success, Game? Game)> TryCreateAsync(IGameOptions options, GameFilterOptions filterOptions, IClient? owner, GameCode? desiredGameCode = null) + private async ValueTask<(bool Success, Game? Game)> TryCreateAsync(IGameOptions options, GameFilterOptions filterOptions, IClient? owner, GameCode? desiredGameCode = null, Guid? modGuid = null) { var gameCode = desiredGameCode ?? _gameCodeFactory.Create(); - var game = ActivatorUtilities.CreateInstance(_serviceProvider, _publicIp, gameCode, options, filterOptions); + var game = modGuid.HasValue + ? ActivatorUtilities.CreateInstance(_serviceProvider, _publicIp, gameCode, options, filterOptions, modGuid.Value) + : ActivatorUtilities.CreateInstance(_serviceProvider, _publicIp, gameCode, options, filterOptions); if (!_games.TryAdd(gameCode, game)) { diff --git a/src/Impostor.Server/Net/State/Game.cs b/src/Impostor.Server/Net/State/Game.cs index 07fd480..9fec3c8 100644 --- a/src/Impostor.Server/Net/State/Game.cs +++ b/src/Impostor.Server/Net/State/Game.cs @@ -47,7 +47,8 @@ namespace Impostor.Server.Net.State IEventManager eventManager, ICompatibilityManager compatibilityManager, IOptions compatibilityConfig, - IOptions timeoutConfig) + IOptions timeoutConfig, + Guid? modGuid = null) { _logger = logger; _serviceProvider = serviceProvider; @@ -62,6 +63,7 @@ namespace Impostor.Server.Net.State GameNet = new GameNet(); Options = options; FilterOptions = filterOptions; + ModGuid = modGuid; _clientManager = clientManager; _eventManager = eventManager; _compatibilityManager = compatibilityManager; @@ -96,6 +98,8 @@ namespace Impostor.Server.Net.State public bool IsHostAuthoritive => Host != null && Host.Client.GameVersion.HasDisableServerAuthorityFlag; + public Guid? ModGuid { get; } + internal GameNet GameNet { get; } public bool TryGetPlayer(int id, [MaybeNullWhen(false)] out ClientPlayer player) diff --git a/src/Impostor.Server/Recorder/ClientRecorder.cs b/src/Impostor.Server/Recorder/ClientRecorder.cs index 4671dd3..428b1fd 100644 --- a/src/Impostor.Server/Recorder/ClientRecorder.cs +++ b/src/Impostor.Server/Recorder/ClientRecorder.cs @@ -1,4 +1,4 @@ -using System.Threading.Tasks; +using System.Threading.Tasks; using Impostor.Api.Config; using Impostor.Api.Innersloth; using Impostor.Api.Net.Custom; @@ -52,7 +52,7 @@ namespace Impostor.Server.Recorder await base.HandleMessageAsync(reader, messageType); // Player created a game. - if (reader.Tag == MessageFlags.HostGame) + if (reader.Tag is MessageFlags.HostGame or MessageFlags.HostModdedGame) { _createdGame = true; } diff --git a/src/Impostor.Server/packages.lock.json b/src/Impostor.Server/packages.lock.json index e4565d7..6cd84f2 100644 --- a/src/Impostor.Server/packages.lock.json +++ b/src/Impostor.Server/packages.lock.json @@ -56,6 +56,12 @@ "resolved": "8.0.1", "contentHash": "X21b8D6z58EG34OMLH955750mFaEaGs5xLGe9Vyi3059Cgb3sk+p2k/JlQXaieEBRrk+SVlFzDei3Q6PdVzJOA==" }, + "Microsoft.NET.ILLink.Tasks": { + "type": "Direct", + "requested": "[8.0.30, )", + "resolved": "8.0.30", + "contentHash": "SfmwuZjUPBTEoBMAsXZ/hWkaEK9oL+Y/UtAx7N6RyWHfcMt9J0ExrNPuOgTyPbCXIyiTBFsxFNrPLEZNPmJcvA==" + }, "Serilog.Extensions.Hosting": { "type": "Direct", "requested": "[8.0.0, )",