diff options
author | chai <chaifix@163.com> | 2020-12-30 20:59:04 +0800 |
---|---|---|
committer | chai <chaifix@163.com> | 2020-12-30 20:59:04 +0800 |
commit | e9ea621b93fbb58d9edfca8375918791637bbd52 (patch) | |
tree | 19ce3b1c1f2d51eda6878c9d0f2c9edc27f13650 /Impostor-dev/src/Impostor.Api/Games |
+init
Diffstat (limited to 'Impostor-dev/src/Impostor.Api/Games')
8 files changed, 332 insertions, 0 deletions
diff --git a/Impostor-dev/src/Impostor.Api/Games/Extensions/GameExtensions.cs b/Impostor-dev/src/Impostor.Api/Games/Extensions/GameExtensions.cs new file mode 100644 index 0000000..a736978 --- /dev/null +++ b/Impostor-dev/src/Impostor.Api/Games/Extensions/GameExtensions.cs @@ -0,0 +1,42 @@ +using System; +using System.Threading.Tasks; +using Impostor.Api.Net; +using Impostor.Api.Net.Messages; + +namespace Impostor.Api.Games +{ + public static class GameExtensions + { + public static ValueTask SendToAllExceptAsync(this IGame game, IMessageWriter writer, LimboStates states, int? id) + { + return id.HasValue + ? game.SendToAllExceptAsync(writer, id.Value, states) + : game.SendToAllAsync(writer, states); + } + + public static ValueTask SendToAllExceptAsync(this IGame game, IMessageWriter writer, LimboStates states, IClient client) + { + if (client == null) + { + throw new ArgumentNullException(nameof(client)); + } + + return game.SendToAllExceptAsync(writer, client.Id, states); + } + + public static ValueTask SendToAsync(this IGame game, IMessageWriter writer, IClient client) + { + if (client == null) + { + throw new ArgumentNullException(nameof(client)); + } + + return game.SendToAsync(writer, client.Id); + } + + public static ValueTask SendToAsync(this IGame game, IMessageWriter writer, IClientPlayer player) + { + return game.SendToAsync(writer, player.Client); + } + } +}
\ No newline at end of file diff --git a/Impostor-dev/src/Impostor.Api/Games/Extensions/GameManagerExtensions.cs b/Impostor-dev/src/Impostor.Api/Games/Extensions/GameManagerExtensions.cs new file mode 100644 index 0000000..9a5a2b4 --- /dev/null +++ b/Impostor-dev/src/Impostor.Api/Games/Extensions/GameManagerExtensions.cs @@ -0,0 +1,14 @@ +using System.Linq; +using Impostor.Api.Games.Managers; +using Impostor.Api.Innersloth; + +namespace Impostor.Api.Games +{ + public static class GameManagerExtensions + { + public static int GetGameCount(this IGameManager manager, MapFlags map) + { + return manager.Games.Count(game => map.HasFlag((MapFlags)(1 << game.Options.MapId))); + } + } +}
\ No newline at end of file diff --git a/Impostor-dev/src/Impostor.Api/Games/GameCode.cs b/Impostor-dev/src/Impostor.Api/Games/GameCode.cs new file mode 100644 index 0000000..2c30e7e --- /dev/null +++ b/Impostor-dev/src/Impostor.Api/Games/GameCode.cs @@ -0,0 +1,74 @@ +using System; +using Impostor.Api.Innersloth; + +namespace Impostor.Api.Games +{ + public readonly struct GameCode : IEquatable<GameCode> + { + public GameCode(int value) + { + Value = value; + Code = GameCodeParser.IntToGameName(value); + } + + public GameCode(string code) + { + Value = GameCodeParser.GameNameToInt(code); + Code = code; + } + + public string Code { get; } + + public int Value { get; } + + public static implicit operator string(GameCode code) => code.Code; + + public static implicit operator int(GameCode code) => code.Value; + + public static implicit operator GameCode(string code) => From(code); + + public static implicit operator GameCode(int value) => From(value); + + public static bool operator ==(GameCode left, GameCode right) + { + return left.Equals(right); + } + + public static bool operator !=(GameCode left, GameCode right) + { + return !left.Equals(right); + } + + public static GameCode Create() + { + return new GameCode(GameCodeParser.GenerateCode(6)); + } + + public static GameCode From(int value) => new GameCode(value); + + public static GameCode From(string value) => new GameCode(value); + + /// <inheritdoc/> + public bool Equals(GameCode other) + { + return Code == other.Code && Value == other.Value; + } + + /// <inheritdoc/> + public override bool Equals(object? obj) + { + return obj is GameCode other && Equals(other); + } + + /// <inheritdoc/> + public override int GetHashCode() + { + return HashCode.Combine(Code, Value); + } + + public override string ToString() + { + return Code; + } + } +}
\ No newline at end of file diff --git a/Impostor-dev/src/Impostor.Api/Games/GameJoinError.cs b/Impostor-dev/src/Impostor.Api/Games/GameJoinError.cs new file mode 100644 index 0000000..4889ea9 --- /dev/null +++ b/Impostor-dev/src/Impostor.Api/Games/GameJoinError.cs @@ -0,0 +1,48 @@ +namespace Impostor.Api.Games +{ + public enum GameJoinError + { + /// <summary> + /// No error occured while joining the game. + /// </summary> + None, + + /// <summary> + /// The client is not registered in the client manager. + /// </summary> + InvalidClient, + + /// <summary> + /// The client has been banned from the game. + /// </summary> + Banned, + + /// <summary> + /// The game is full. + /// </summary> + GameFull, + + /// <summary> + /// The limbo state of the player is incorrect. + /// </summary> + InvalidLimbo, + + /// <summary> + /// The game is already started. + /// </summary> + GameStarted, + + /// <summary> + /// The game has been destroyed. + /// </summary> + GameDestroyed, + + /// <summary> + /// Custom error by a plugin. + /// </summary> + /// <remarks> + /// A custom message can be set in <see cref="GameJoinResult.Message"/>. + /// </remarks> + Custom, + } +}
\ No newline at end of file diff --git a/Impostor-dev/src/Impostor.Api/Games/GameJoinResult.cs b/Impostor-dev/src/Impostor.Api/Games/GameJoinResult.cs new file mode 100644 index 0000000..b33a2b6 --- /dev/null +++ b/Impostor-dev/src/Impostor.Api/Games/GameJoinResult.cs @@ -0,0 +1,48 @@ +using System; +using System.Diagnostics.CodeAnalysis; +using Impostor.Api.Net; + +namespace Impostor.Api.Games +{ + public readonly struct GameJoinResult + { + private GameJoinResult(GameJoinError error, string? message = null, IClientPlayer? player = null) + { + Error = error; + Message = message; + Player = player; + } + + public GameJoinError Error { get; } + + public bool IsSuccess => Error == GameJoinError.None; + + public bool IsCustomError => Error == GameJoinError.Custom; + + [MemberNotNullWhen(true, nameof(IsCustomError))] + public string? Message { get; } + + [MemberNotNullWhen(true, nameof(IsSuccess))] + public IClientPlayer? Player { get; } + + public static GameJoinResult CreateCustomError(string message) + { + return new GameJoinResult(GameJoinError.Custom, message); + } + + public static GameJoinResult CreateSuccess(IClientPlayer player) + { + return new GameJoinResult(GameJoinError.None, player: player); + } + + public static GameJoinResult FromError(GameJoinError error) + { + if (error == GameJoinError.Custom) + { + throw new InvalidOperationException($"Custom errors should provide a message, use {nameof(CreateCustomError)} instead."); + } + + return new GameJoinResult(error); + } + } +}
\ No newline at end of file diff --git a/Impostor-dev/src/Impostor.Api/Games/IGame.cs b/Impostor-dev/src/Impostor.Api/Games/IGame.cs new file mode 100644 index 0000000..ad71986 --- /dev/null +++ b/Impostor-dev/src/Impostor.Api/Games/IGame.cs @@ -0,0 +1,88 @@ +using System.Collections.Generic; +using System.Net; +using System.Threading.Tasks; +using Impostor.Api.Innersloth; +using Impostor.Api.Net; +using Impostor.Api.Net.Inner; +using Impostor.Api.Net.Inner.Objects; +using Impostor.Api.Net.Messages; + +namespace Impostor.Api.Games +{ + public interface IGame + { + GameOptionsData Options { get; } + + GameCode Code { get; } + + GameStates GameState { get; } + + IGameNet GameNet { get; } + + IEnumerable<IClientPlayer> Players { get; } + + IPEndPoint PublicIp { get; } + + int PlayerCount { get; } + + IClientPlayer Host { get; } + + bool IsPublic { get; } + + IDictionary<object, object> Items { get; } + + int HostId { get; } + + IClientPlayer GetClientPlayer(int clientId); + + /// <summary> + /// Adds an <see cref="IPAddress"/> to the ban list of this game. + /// Prevents all future joins from this <see cref="IPAddress"/>. + /// + /// This does not kick the player with that <see cref="IPAddress"/> from the lobby. + /// </summary> + /// <param name="ipAddress"> + /// The <see cref="IPAddress"/> to ban. + /// </param> + void BanIp(IPAddress ipAddress); + + /// <summary> + /// Syncs the internal <see cref="GameOptionsData"/> to all players. + /// Necessary to do if you modified it, otherwise it won't be used. + /// </summary> + /// <returns>A <see cref="ValueTask"/> representing the asynchronous operation.</returns> + ValueTask SyncSettingsAsync(); + + /// <summary> + /// Sets the specified list as Impostor on all connected players. + /// </summary> + /// <param name="players">List of players to be Impostor.</param> + /// <returns>A <see cref="ValueTask"/> representing the asynchronous operation.</returns> + ValueTask SetInfectedAsync(IEnumerable<IInnerPlayerControl> players); + + /// <summary> + /// Send the message to all players. + /// </summary> + /// <param name="writer">Message to send.</param> + /// <param name="states">Required limbo state of the player.</param> + /// <returns>A <see cref="ValueTask"/> representing the asynchronous operation.</returns> + ValueTask SendToAllAsync(IMessageWriter writer, LimboStates states = LimboStates.NotLimbo); + + /// <summary> + /// Send the message to all players except one. + /// </summary> + /// <param name="writer">Message to send.</param> + /// <param name="senderId">The player to exclude from sending the message.</param> + /// <param name="states">Required limbo state of the player.</param> + /// <returns>A <see cref="ValueTask"/> representing the asynchronous operation.</returns> + ValueTask SendToAllExceptAsync(IMessageWriter writer, int senderId, LimboStates states = LimboStates.NotLimbo); + + /// <summary> + /// Send a message to a specific player. + /// </summary> + /// <param name="writer">Message to send.</param> + /// <param name="id">ID of the client.</param> + /// <returns>A <see cref="ValueTask"/> representing the asynchronous operation.</returns> + ValueTask SendToAsync(IMessageWriter writer, int id); + } +} diff --git a/Impostor-dev/src/Impostor.Api/Games/IGameCodeFactory.cs b/Impostor-dev/src/Impostor.Api/Games/IGameCodeFactory.cs new file mode 100644 index 0000000..f264fe0 --- /dev/null +++ b/Impostor-dev/src/Impostor.Api/Games/IGameCodeFactory.cs @@ -0,0 +1,7 @@ +namespace Impostor.Api.Games +{ + public interface IGameCodeFactory + { + GameCode Create(); + } +}
\ No newline at end of file diff --git a/Impostor-dev/src/Impostor.Api/Games/Managers/IGameManager.cs b/Impostor-dev/src/Impostor.Api/Games/Managers/IGameManager.cs new file mode 100644 index 0000000..10a05f0 --- /dev/null +++ b/Impostor-dev/src/Impostor.Api/Games/Managers/IGameManager.cs @@ -0,0 +1,11 @@ +using System.Collections.Generic; + +namespace Impostor.Api.Games.Managers +{ + public interface IGameManager + { + IEnumerable<IGame> Games { get; } + + IGame? Find(GameCode code); + } +}
\ No newline at end of file |