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/Net |
+init
Diffstat (limited to 'Impostor-dev/src/Impostor.Api/Net')
39 files changed, 1126 insertions, 0 deletions
diff --git a/Impostor-dev/src/Impostor.Api/Net/IClient.cs b/Impostor-dev/src/Impostor.Api/Net/IClient.cs new file mode 100644 index 0000000..48efeda --- /dev/null +++ b/Impostor-dev/src/Impostor.Api/Net/IClient.cs @@ -0,0 +1,76 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using Impostor.Api.Innersloth; +using Impostor.Api.Net.Messages; + +namespace Impostor.Api.Net +{ + /// <summary> + /// Represents a connected game client. + /// </summary> + public interface IClient + { + /// <summary> + /// Gets or sets the unique ID of the client. + /// </summary> + /// <remarks> + /// This ID is generated when the client is registered in the client manager and should not be used + /// to store persisted data. + /// </remarks> + int Id { get; set; } + + /// <summary> + /// Gets the name that was provided by the player in the client. + /// </summary> + /// <remarks> + /// The name is provided by the player and should not be used to store persisted data. + /// </remarks> + string Name { get; } + + /// <summary> + /// Gets the connection of the client. + /// </summary> + /// <remarks> + /// Null when the client was not registered by the matchmaker. + /// </remarks> + IHazelConnection? Connection { get; } + + /// <summary> + /// Gets a key/value collection that can be used to share data between messages. + /// </summary> + /// <remarks> + /// <para> + /// The stored data will not be saved. + /// After the connection has been closed all data will be lost. + /// </para> + /// <para> + /// Note that the values will not be disposed after the connection has been closed. + /// This has to be implemented by the plugin. + /// </para> + /// </remarks> + IDictionary<object, object> Items { get; } + + /// <summary> + /// Gets or sets the current game data of the <see cref="IClient"/>. + /// </summary> + IClientPlayer? Player { get; } + + ValueTask HandleMessageAsync(IMessageReader message, MessageType messageType); + + ValueTask HandleDisconnectAsync(string reason); + + /// <summary> + /// Disconnect the client with a <see cref="DisconnectReason"/>. + /// </summary> + /// <param name="reason"> + /// The message to show to the player. + /// </param> + /// <param name="message"> + /// Only used when <see cref="reason"/> is set to <see cref="DisconnectReason.Custom"/>. + /// </param> + /// <returns> + /// A <see cref="ValueTask"/> representing the asynchronous operation. + /// </returns> + ValueTask DisconnectAsync(DisconnectReason reason, string? message = null); + } +} diff --git a/Impostor-dev/src/Impostor.Api/Net/IClientPlayer.cs b/Impostor-dev/src/Impostor.Api/Net/IClientPlayer.cs new file mode 100644 index 0000000..6070210 --- /dev/null +++ b/Impostor-dev/src/Impostor.Api/Net/IClientPlayer.cs @@ -0,0 +1,43 @@ +using System.Threading.Tasks; +using Impostor.Api.Games; +using Impostor.Api.Net.Inner; +using Impostor.Api.Net.Inner.Objects; + +namespace Impostor.Api.Net +{ + /// <summary> + /// Represents a player in <see cref="IGame"/>. + /// </summary> + public interface IClientPlayer + { + /// <summary> + /// Gets the client that belongs to the player. + /// </summary> + IClient Client { get; } + + /// <summary> + /// Gets the game where the <see cref="IClientPlayer"/> belongs to. + /// </summary> + IGame Game { get; } + + /// <summary> + /// Gets or sets the current limbo state of the player. + /// </summary> + LimboStates Limbo { get; set; } + + IInnerPlayerControl? Character { get; } + + public bool IsHost { get; } + + /// <summary> + /// Checks if the specified <see cref="IInnerNetObject"/> is owned by <see cref="IClientPlayer"/>. + /// </summary> + /// <param name="netObject">The <see cref="IInnerNetObject"/>.</param> + /// <returns>Returns true if owned by <see cref="IClientPlayer"/>.</returns> + bool IsOwner(IInnerNetObject netObject); + + ValueTask KickAsync(); + + ValueTask BanAsync(); + } +} diff --git a/Impostor-dev/src/Impostor.Api/Net/IConnection.cs b/Impostor-dev/src/Impostor.Api/Net/IConnection.cs new file mode 100644 index 0000000..94f9b8b --- /dev/null +++ b/Impostor-dev/src/Impostor.Api/Net/IConnection.cs @@ -0,0 +1,7 @@ +namespace Impostor.Api.Net +{ + public interface IConnection + { + + } +}
\ No newline at end of file diff --git a/Impostor-dev/src/Impostor.Api/Net/IHazelConnection.cs b/Impostor-dev/src/Impostor.Api/Net/IHazelConnection.cs new file mode 100644 index 0000000..4e6c4b3 --- /dev/null +++ b/Impostor-dev/src/Impostor.Api/Net/IHazelConnection.cs @@ -0,0 +1,41 @@ +using System.Net; +using System.Threading.Tasks; +using Impostor.Api.Net.Messages; + +namespace Impostor.Api.Net +{ + /// <summary> + /// Represents the connection of the client. + /// </summary> + public interface IHazelConnection + { + /// <summary> + /// Gets the IP endpoint of the client. + /// </summary> + IPEndPoint EndPoint { get; } + + /// <summary> + /// Gets a value indicating whether the client is connected to the server. + /// </summary> + bool IsConnected { get; } + + /// <summary> + /// Gets the client of the connection. + /// </summary> + IClient? Client { get; set; } + + /// <summary> + /// Sends a message writer to the connection. + /// </summary> + /// <param name="writer">The message.</param> + /// <returns></returns> + ValueTask SendAsync(IMessageWriter writer); + + /// <summary> + /// Disconnects the client and invokes the disconnect handler. + /// </summary> + /// <param name="reason">A reason.</param> + /// <returns></returns> + ValueTask DisconnectAsync(string? reason); + } +}
\ No newline at end of file diff --git a/Impostor-dev/src/Impostor.Api/Net/Inner/IGameNet.cs b/Impostor-dev/src/Impostor.Api/Net/Inner/IGameNet.cs new file mode 100644 index 0000000..933a4de --- /dev/null +++ b/Impostor-dev/src/Impostor.Api/Net/Inner/IGameNet.cs @@ -0,0 +1,18 @@ +using Impostor.Api.Net.Inner.Objects; + +namespace Impostor.Api.Net.Inner +{ + /// <summary> + /// Holds all data that is serialized over the network through GameData packets. + /// </summary> + public interface IGameNet + { + IInnerLobbyBehaviour LobbyBehaviour { get; } + + IInnerGameData GameData { get; } + + IInnerVoteBanSystem VoteBan { get; } + + IInnerShipStatus ShipStatus { get; } + } +}
\ No newline at end of file diff --git a/Impostor-dev/src/Impostor.Api/Net/Inner/IInnerNetObject.cs b/Impostor-dev/src/Impostor.Api/Net/Inner/IInnerNetObject.cs new file mode 100644 index 0000000..c171377 --- /dev/null +++ b/Impostor-dev/src/Impostor.Api/Net/Inner/IInnerNetObject.cs @@ -0,0 +1,9 @@ +namespace Impostor.Api.Net.Inner +{ + public interface IInnerNetObject + { + public uint NetId { get; } + + public int OwnerId { get; } + } +}
\ No newline at end of file diff --git a/Impostor-dev/src/Impostor.Api/Net/Inner/Objects/Components/IInnerCustomNetworkTransform.cs b/Impostor-dev/src/Impostor.Api/Net/Inner/Objects/Components/IInnerCustomNetworkTransform.cs new file mode 100644 index 0000000..6d867e7 --- /dev/null +++ b/Impostor-dev/src/Impostor.Api/Net/Inner/Objects/Components/IInnerCustomNetworkTransform.cs @@ -0,0 +1,15 @@ +using System.Numerics; +using System.Threading.Tasks; + +namespace Impostor.Api.Net.Inner.Objects.Components +{ + public interface IInnerCustomNetworkTransform : IInnerNetObject + { + /// <summary> + /// Snaps the current to the given position <see cref="IInnerPlayerControl"/>. + /// </summary> + /// <param name="position">The target position.</param> + /// <returns>Task that must be awaited.</returns> + ValueTask SnapToAsync(Vector2 position); + } +} diff --git a/Impostor-dev/src/Impostor.Api/Net/Inner/Objects/Components/IInnerPlayerPhysics.cs b/Impostor-dev/src/Impostor.Api/Net/Inner/Objects/Components/IInnerPlayerPhysics.cs new file mode 100644 index 0000000..9378c5b --- /dev/null +++ b/Impostor-dev/src/Impostor.Api/Net/Inner/Objects/Components/IInnerPlayerPhysics.cs @@ -0,0 +1,6 @@ +namespace Impostor.Api.Net.Inner.Objects.Components +{ + public interface IInnerPlayerPhysics : IInnerNetObject + { + } +} diff --git a/Impostor-dev/src/Impostor.Api/Net/Inner/Objects/IInnerGameData.cs b/Impostor-dev/src/Impostor.Api/Net/Inner/Objects/IInnerGameData.cs new file mode 100644 index 0000000..6e41020 --- /dev/null +++ b/Impostor-dev/src/Impostor.Api/Net/Inner/Objects/IInnerGameData.cs @@ -0,0 +1,6 @@ +namespace Impostor.Api.Net.Inner.Objects +{ + public interface IInnerGameData : IInnerNetObject + { + } +} diff --git a/Impostor-dev/src/Impostor.Api/Net/Inner/Objects/IInnerLobbyBehaviour.cs b/Impostor-dev/src/Impostor.Api/Net/Inner/Objects/IInnerLobbyBehaviour.cs new file mode 100644 index 0000000..f05f4cf --- /dev/null +++ b/Impostor-dev/src/Impostor.Api/Net/Inner/Objects/IInnerLobbyBehaviour.cs @@ -0,0 +1,6 @@ +namespace Impostor.Api.Net.Inner.Objects +{ + public interface IInnerLobbyBehaviour : IInnerNetObject + { + } +} diff --git a/Impostor-dev/src/Impostor.Api/Net/Inner/Objects/IInnerMeetingHud.cs b/Impostor-dev/src/Impostor.Api/Net/Inner/Objects/IInnerMeetingHud.cs new file mode 100644 index 0000000..9c89d05 --- /dev/null +++ b/Impostor-dev/src/Impostor.Api/Net/Inner/Objects/IInnerMeetingHud.cs @@ -0,0 +1,6 @@ +namespace Impostor.Api.Net.Inner.Objects +{ + public interface IInnerMeetingHud + { + } +} diff --git a/Impostor-dev/src/Impostor.Api/Net/Inner/Objects/IInnerPlayerControl.cs b/Impostor-dev/src/Impostor.Api/Net/Inner/Objects/IInnerPlayerControl.cs new file mode 100644 index 0000000..04558b9 --- /dev/null +++ b/Impostor-dev/src/Impostor.Api/Net/Inner/Objects/IInnerPlayerControl.cs @@ -0,0 +1,116 @@ +using System.Threading.Tasks; +using Impostor.Api.Innersloth.Customization; +using Impostor.Api.Net.Inner.Objects.Components; + +namespace Impostor.Api.Net.Inner.Objects +{ + public interface IInnerPlayerControl : IInnerNetObject + { + /// <summary> + /// Gets the <see cref="PlayerId"/> assigned by the client of the host of the game. + /// </summary> + byte PlayerId { get; } + + /// <summary> + /// Gets the <see cref="IInnerPlayerPhysics"/> of the <see cref="IInnerPlayerControl"/>. + /// Contains vent logic. + /// </summary> + IInnerPlayerPhysics Physics { get; } + + /// <summary> + /// Gets the <see cref="IInnerCustomNetworkTransform"/> of the <see cref="IInnerPlayerControl"/>. + /// Contains position data about the player. + /// </summary> + IInnerCustomNetworkTransform NetworkTransform { get; } + + /// <summary> + /// Gets the <see cref="IInnerPlayerInfo"/> of the <see cref="IInnerPlayerControl"/>. + /// Contains metadata about the player. + /// </summary> + IInnerPlayerInfo PlayerInfo { get; } + + /// <summary> + /// Sets the name of the current <see cref="IInnerPlayerControl"/>. + /// Visible to all players. + /// </summary> + /// <param name="name">A name for the player.</param> + /// <returns>Task that must be awaited.</returns> + ValueTask SetNameAsync(string name); + + /// <summary> + /// Sets the color of the current <see cref="IInnerPlayerControl"/>. + /// Visible to all players. + /// </summary> + /// <param name="colorId">A color for the player.</param> + /// <returns>Task that must be awaited.</returns> + ValueTask SetColorAsync(byte colorId); + + /// <param name="colorType">A color for the player.</param> + /// <inheritdoc cref="SetColorAsync(byte)" /> + ValueTask SetColorAsync(ColorType colorType); + + /// <summary> + /// Sets the hat of the current <see cref="IInnerPlayerControl"/>. + /// Visible to all players. + /// </summary> + /// <param name="hatId">An hat for the player.</param> + /// <returns>Task that must be awaited.</returns> + ValueTask SetHatAsync(uint hatId); + + /// <param name="hatType">An hat for the player.</param> + /// <inheritdoc cref="SetHatAsync(uint)" /> + ValueTask SetHatAsync(HatType hatType); + + /// <summary> + /// Sets the pet of the current <see cref="IInnerPlayerControl"/>. + /// Visible to all players. + /// </summary> + /// <param name="petId">A pet for the player.</param> + /// <returns>Task that must be awaited.</returns> + ValueTask SetPetAsync(uint petId); + + /// <param name="petType">A pet for the player.</param> + /// <inheritdoc cref="SetPetAsync(uint)" /> + ValueTask SetPetAsync(PetType petType); + + /// <summary> + /// Sets the skin of the current <see cref="IInnerPlayerControl"/>. + /// Visible to all players. + /// </summary> + /// <param name="skinId">A skin for the player.</param> + /// <returns>Task that must be awaited.</returns> + ValueTask SetSkinAsync(uint skinId); + + /// <param name="skinType">A skin for the player.</param> + /// <inheritdoc cref="SetSkinAsync(uint)" /> + ValueTask SetSkinAsync(SkinType skinType); + + /// <summary> + /// Send a chat message as the current <see cref="IInnerPlayerControl"/>. + /// Visible to all players. + /// </summary> + /// <param name="text">The message to send.</param> + /// <returns>Task that must be awaited.</returns> + ValueTask SendChatAsync(string text); + + /// <summary> + /// Send a chat message as the current <see cref="IInnerPlayerControl"/>. + /// Visible to only the current. + /// </summary> + /// <param name="text">The message to send.</param> + /// <param name="player"> + /// The player that should receive this chat message. + /// When left as null, will send message to self. + /// </param> + /// <returns>Task that must be awaited.</returns> + ValueTask SendChatToPlayerAsync(string text, IInnerPlayerControl? player = null); + + /// <summary> + /// Sets the current to be murdered by an impostor <see cref="IInnerPlayerControl"/>. + /// Visible to all players. + /// </summary> + /// /// <param name="impostor">The Impostor who kill.</param> + /// <returns>Task that must be awaited.</returns> + ValueTask SetMurderedByAsync(IClientPlayer impostor); + } +} diff --git a/Impostor-dev/src/Impostor.Api/Net/Inner/Objects/IInnerPlayerInfo.cs b/Impostor-dev/src/Impostor.Api/Net/Inner/Objects/IInnerPlayerInfo.cs new file mode 100644 index 0000000..6cb3302 --- /dev/null +++ b/Impostor-dev/src/Impostor.Api/Net/Inner/Objects/IInnerPlayerInfo.cs @@ -0,0 +1,53 @@ +using System; +using System.Collections.Generic; +using Impostor.Api.Innersloth; + +namespace Impostor.Api.Net.Inner.Objects +{ + public interface IInnerPlayerInfo + { + /// <summary> + /// Gets the name of the player as decided by the host. + /// </summary> + string PlayerName { get; } + + /// <summary> + /// Gets the color of the player. + /// </summary> + byte ColorId { get; } + + /// <summary> + /// Gets the hat of the player. + /// </summary> + uint HatId { get; } + + /// <summary> + /// Gets the pet of the player. + /// </summary> + uint PetId { get; } + + /// <summary> + /// Gets the skin of the player. + /// </summary> + uint SkinId { get; } + + /// <summary> + /// Gets a value indicating whether the player is an impostor. + /// </summary> + bool IsImpostor { get; } + + /// <summary> + /// Gets a value indicating whether the player is a dead in the current game. + /// </summary> + bool IsDead { get; } + + /// <summary> + /// Gets the reason why the player is dead in the current game. + /// </summary> + DeathReason LastDeathReason { get; } + + IEnumerable<ITaskInfo> Tasks { get; } + + DateTimeOffset LastMurder { get; } + } +} diff --git a/Impostor-dev/src/Impostor.Api/Net/Inner/Objects/IInnerShipStatus.cs b/Impostor-dev/src/Impostor.Api/Net/Inner/Objects/IInnerShipStatus.cs new file mode 100644 index 0000000..c0a05ae --- /dev/null +++ b/Impostor-dev/src/Impostor.Api/Net/Inner/Objects/IInnerShipStatus.cs @@ -0,0 +1,7 @@ +namespace Impostor.Api.Net.Inner.Objects +{ + public interface IInnerShipStatus : IInnerNetObject + { + + } +}
\ No newline at end of file diff --git a/Impostor-dev/src/Impostor.Api/Net/Inner/Objects/IInnerVoteBanSystem.cs b/Impostor-dev/src/Impostor.Api/Net/Inner/Objects/IInnerVoteBanSystem.cs new file mode 100644 index 0000000..d0a816d --- /dev/null +++ b/Impostor-dev/src/Impostor.Api/Net/Inner/Objects/IInnerVoteBanSystem.cs @@ -0,0 +1,7 @@ +namespace Impostor.Api.Net.Inner.Objects +{ + public interface IInnerVoteBanSystem : IInnerNetObject + { + + } +}
\ No newline at end of file diff --git a/Impostor-dev/src/Impostor.Api/Net/Inner/Objects/ITaskInfo.cs b/Impostor-dev/src/Impostor.Api/Net/Inner/Objects/ITaskInfo.cs new file mode 100644 index 0000000..2b6dd86 --- /dev/null +++ b/Impostor-dev/src/Impostor.Api/Net/Inner/Objects/ITaskInfo.cs @@ -0,0 +1,14 @@ +using Impostor.Api.Innersloth; +using Impostor.Api.Net.Messages; + +namespace Impostor.Api.Net.Inner.Objects +{ + public interface ITaskInfo + { + uint Id { get; } + + TaskTypes Type { get; } + + bool Complete { get; } + } +} diff --git a/Impostor-dev/src/Impostor.Api/Net/LimboStates.cs b/Impostor-dev/src/Impostor.Api/Net/LimboStates.cs new file mode 100644 index 0000000..44c493e --- /dev/null +++ b/Impostor-dev/src/Impostor.Api/Net/LimboStates.cs @@ -0,0 +1,13 @@ +using System; + +namespace Impostor.Api.Net +{ + [Flags] + public enum LimboStates + { + PreSpawn = 1, + NotLimbo = 2, + WaitingForHost = 4, + All = PreSpawn | NotLimbo | WaitingForHost, + } +}
\ No newline at end of file diff --git a/Impostor-dev/src/Impostor.Api/Net/Manager/IClientManager.cs b/Impostor-dev/src/Impostor.Api/Net/Manager/IClientManager.cs new file mode 100644 index 0000000..92bf89f --- /dev/null +++ b/Impostor-dev/src/Impostor.Api/Net/Manager/IClientManager.cs @@ -0,0 +1,9 @@ +using System.Collections.Generic; + +namespace Impostor.Api.Net.Manager +{ + public interface IClientManager + { + IEnumerable<IClient> Clients { get; } + } +}
\ No newline at end of file diff --git a/Impostor-dev/src/Impostor.Api/Net/Messages/C2S/Message00HostGameC2S.cs b/Impostor-dev/src/Impostor.Api/Net/Messages/C2S/Message00HostGameC2S.cs new file mode 100644 index 0000000..4f5b39c --- /dev/null +++ b/Impostor-dev/src/Impostor.Api/Net/Messages/C2S/Message00HostGameC2S.cs @@ -0,0 +1,27 @@ +using System.IO; +using Impostor.Api.Innersloth; + +namespace Impostor.Api.Net.Messages.C2S +{ + public static class Message00HostGameC2S + { + public static void Serialize(IMessageWriter writer, GameOptionsData gameOptionsData) + { + writer.StartMessage(MessageFlags.HostGame); + + using (var memory = new MemoryStream()) + using (var writerBin = new BinaryWriter(memory)) + { + gameOptionsData.Serialize(writerBin, GameOptionsData.LatestVersion); + writer.WriteBytesAndSize(memory.ToArray()); + } + + writer.EndMessage(); + } + + public static GameOptionsData Deserialize(IMessageReader reader) + { + return GameOptionsData.DeserializeCreate(reader); + } + } +}
\ No newline at end of file diff --git a/Impostor-dev/src/Impostor.Api/Net/Messages/C2S/Message01JoinGameC2S.cs b/Impostor-dev/src/Impostor.Api/Net/Messages/C2S/Message01JoinGameC2S.cs new file mode 100644 index 0000000..f121b97 --- /dev/null +++ b/Impostor-dev/src/Impostor.Api/Net/Messages/C2S/Message01JoinGameC2S.cs @@ -0,0 +1,20 @@ +using System; + +namespace Impostor.Api.Net.Messages.C2S +{ + public static class Message01JoinGameC2S + { + public static void Serialize(IMessageWriter writer) + { + throw new System.NotImplementedException(); + } + + public static void Deserialize(IMessageReader reader, out int gameCode, out byte unknown) + { + var slice = reader.ReadBytes(sizeof(Int32) + sizeof(byte)).Span; + + gameCode = slice.ReadInt32(); + unknown = slice.ReadByte(); + } + } +}
\ No newline at end of file diff --git a/Impostor-dev/src/Impostor.Api/Net/Messages/C2S/Message04RemovePlayerC2S.cs b/Impostor-dev/src/Impostor.Api/Net/Messages/C2S/Message04RemovePlayerC2S.cs new file mode 100644 index 0000000..99cdcfa --- /dev/null +++ b/Impostor-dev/src/Impostor.Api/Net/Messages/C2S/Message04RemovePlayerC2S.cs @@ -0,0 +1,16 @@ +namespace Impostor.Api.Net.Messages.C2S +{ + public class Message04RemovePlayerC2S + { + public static void Serialize(IMessageWriter writer) + { + throw new System.NotImplementedException(); + } + + public static void Deserialize(IMessageReader reader, out int playerId, out byte reason) + { + playerId = reader.ReadPackedInt32(); + reason = reader.ReadByte(); + } + } +}
\ No newline at end of file diff --git a/Impostor-dev/src/Impostor.Api/Net/Messages/C2S/Message08EndGameC2S.cs b/Impostor-dev/src/Impostor.Api/Net/Messages/C2S/Message08EndGameC2S.cs new file mode 100644 index 0000000..7ca5e3a --- /dev/null +++ b/Impostor-dev/src/Impostor.Api/Net/Messages/C2S/Message08EndGameC2S.cs @@ -0,0 +1,18 @@ +using Impostor.Api.Innersloth; + +namespace Impostor.Api.Net.Messages.C2S +{ + public class Message08EndGameC2S + { + public static void Serialize(IMessageWriter writer) + { + throw new System.NotImplementedException(); + } + + public static void Deserialize(IMessageReader reader, out GameOverReason gameOverReason) + { + gameOverReason = (GameOverReason)reader.ReadByte(); + reader.ReadBoolean(); // showAd + } + } +}
\ No newline at end of file diff --git a/Impostor-dev/src/Impostor.Api/Net/Messages/C2S/Message10AlterGameC2S.cs b/Impostor-dev/src/Impostor.Api/Net/Messages/C2S/Message10AlterGameC2S.cs new file mode 100644 index 0000000..330f3b5 --- /dev/null +++ b/Impostor-dev/src/Impostor.Api/Net/Messages/C2S/Message10AlterGameC2S.cs @@ -0,0 +1,20 @@ +using Impostor.Api.Innersloth; + +namespace Impostor.Api.Net.Messages.C2S +{ + public class Message10AlterGameC2S + { + public static void Serialize(IMessageWriter writer) + { + throw new System.NotImplementedException(); + } + + public static void Deserialize(IMessageReader reader, out AlterGameTags gameTag, out bool isPublic) + { + var slice = reader.ReadBytes(sizeof(byte) + sizeof(byte)).Span; + + gameTag = (AlterGameTags)slice.ReadByte(); + isPublic = slice.ReadBoolean(); + } + } +}
\ No newline at end of file diff --git a/Impostor-dev/src/Impostor.Api/Net/Messages/C2S/Message11KickPlayerC2S.cs b/Impostor-dev/src/Impostor.Api/Net/Messages/C2S/Message11KickPlayerC2S.cs new file mode 100644 index 0000000..7c5b8b9 --- /dev/null +++ b/Impostor-dev/src/Impostor.Api/Net/Messages/C2S/Message11KickPlayerC2S.cs @@ -0,0 +1,16 @@ +namespace Impostor.Api.Net.Messages.C2S +{ + public class Message11KickPlayerC2S + { + public static void Serialize(IMessageWriter writer) + { + throw new System.NotImplementedException(); + } + + public static void Deserialize(IMessageReader reader, out int playerId, out bool isBan) + { + playerId = reader.ReadPackedInt32(); + isBan = reader.ReadBoolean(); + } + } +}
\ No newline at end of file diff --git a/Impostor-dev/src/Impostor.Api/Net/Messages/C2S/Message16GetGameListC2S.cs b/Impostor-dev/src/Impostor.Api/Net/Messages/C2S/Message16GetGameListC2S.cs new file mode 100644 index 0000000..2b7e12a --- /dev/null +++ b/Impostor-dev/src/Impostor.Api/Net/Messages/C2S/Message16GetGameListC2S.cs @@ -0,0 +1,18 @@ +using Impostor.Api.Innersloth; + +namespace Impostor.Api.Net.Messages.C2S +{ + public class Message16GetGameListC2S + { + public static void Serialize(IMessageWriter writer) + { + throw new System.NotImplementedException(); + } + + public static void Deserialize(IMessageReader reader, out GameOptionsData options) + { + reader.ReadPackedInt32(); // Hardcoded 0. + options = GameOptionsData.DeserializeCreate(reader); + } + } +}
\ No newline at end of file diff --git a/Impostor-dev/src/Impostor.Api/Net/Messages/IMessageReader.cs b/Impostor-dev/src/Impostor.Api/Net/Messages/IMessageReader.cs new file mode 100644 index 0000000..87c06c4 --- /dev/null +++ b/Impostor-dev/src/Impostor.Api/Net/Messages/IMessageReader.cs @@ -0,0 +1,68 @@ +using System; + +namespace Impostor.Api.Net.Messages +{ + public interface IMessageReader : IDisposable + { + /// <summary> + /// Gets the tag of the message. + /// </summary> + byte Tag { get; } + + /// <summary> + /// Gets the buffer of the message. + /// </summary> + byte[] Buffer { get; } + + /// <summary> + /// Gets the offset of our current <see cref="IMessageReader"/> in the entire <see cref="Buffer"/>. + /// </summary> + int Offset { get; } + + /// <summary> + /// Gets the current position of the reader. + /// </summary> + int Position { get; } + + /// <summary> + /// Gets the length of the buffer. + /// </summary> + int Length { get; } + + IMessageReader ReadMessage(); + + bool ReadBoolean(); + + sbyte ReadSByte(); + + byte ReadByte(); + + ushort ReadUInt16(); + + short ReadInt16(); + + uint ReadUInt32(); + + int ReadInt32(); + + float ReadSingle(); + + string ReadString(); + + ReadOnlyMemory<byte> ReadBytesAndSize(); + + ReadOnlyMemory<byte> ReadBytes(int length); + + int ReadPackedInt32(); + + uint ReadPackedUInt32(); + + void CopyTo(IMessageWriter writer); + + void Seek(int position); + + void RemoveMessage(IMessageReader message); + + IMessageReader Copy(int offset = 0); + } +} diff --git a/Impostor-dev/src/Impostor.Api/Net/Messages/IMessageWriter.cs b/Impostor-dev/src/Impostor.Api/Net/Messages/IMessageWriter.cs new file mode 100644 index 0000000..4f6765b --- /dev/null +++ b/Impostor-dev/src/Impostor.Api/Net/Messages/IMessageWriter.cs @@ -0,0 +1,127 @@ +using System; +using System.Net; +using Impostor.Api.Games; + +namespace Impostor.Api.Net.Messages +{ + /// <summary> + /// Base message writer. + /// </summary> + public interface IMessageWriter : IDisposable + { + public byte[] Buffer { get; } + + public int Length { get; set; } + + public int Position { get; set; } + + public MessageType SendOption { get; } + + /// <summary> + /// Writes a boolean to the message. + /// </summary> + /// <param name="value">Value to write.</param> + void Write(bool value); + + /// <summary> + /// Writes a sbyte to the message. + /// </summary> + /// <param name="value">Value to write.</param> + void Write(sbyte value); + + /// <summary> + /// Writes a byte to the message. + /// </summary> + /// <param name="value">Value to write.</param> + void Write(byte value); + + /// <summary> + /// Writes a short to the message. + /// </summary> + /// <param name="value">Value to write.</param> + void Write(short value); + + /// <summary> + /// Writes an ushort to the message. + /// </summary> + /// <param name="value">Value to write.</param> + void Write(ushort value); + + /// <summary> + /// Writes an uint to the message. + /// </summary> + /// <param name="value">Value to write.</param> + void Write(uint value); + + /// <summary> + /// Writes an int to the message. + /// </summary> + /// <param name="value">Value to write.</param> + void Write(int value); + + /// <summary> + /// Writes a float to the message. + /// </summary> + /// <param name="value">Value to write.</param> + void Write(float value); + + /// <summary> + /// Writes a string to the message. + /// </summary> + /// <param name="value">Value to write.</param> + void Write(string value); + + /// <summary> + /// Writes a <see cref="IPAddress"/> to the message. + /// </summary> + /// <param name="value">Value to write.</param> + void Write(IPAddress value); + + /// <summary> + /// Writes an packed int to the message. + /// </summary> + /// <param name="value">Value to write.</param> + void WritePacked(int value); + + /// <summary> + /// Writes an packed uint to the message. + /// </summary> + /// <param name="value">Value to write.</param> + void WritePacked(uint value); + + /// <summary> + /// Writes raw bytes to the message. + /// </summary> + /// <param name="data">Bytes to write.</param> + void Write(ReadOnlyMemory<byte> data); + + /// <summary> + /// Writes a game code to the message. + /// </summary> + /// <param name="value">Value to write.</param> + void Write(GameCode value); + + void WriteBytesAndSize(byte[] bytes); + + void WriteBytesAndSize(byte[] bytes, int length); + + void WriteBytesAndSize(byte[] bytes, int offset, int length); + + /// <summary> + /// Starts a new message. + /// </summary> + /// <param name="typeFlag">Message flag header.</param> + void StartMessage(byte typeFlag); + + /// <summary> + /// Mark the end of the message. + /// </summary> + void EndMessage(); + + /// <summary> + /// Clear the message writer. + /// </summary> + /// <param name="type">New type of the message.</param> + void Clear(MessageType type); + } +}
\ No newline at end of file diff --git a/Impostor-dev/src/Impostor.Api/Net/Messages/IMessageWriterProvider.cs b/Impostor-dev/src/Impostor.Api/Net/Messages/IMessageWriterProvider.cs new file mode 100644 index 0000000..f398939 --- /dev/null +++ b/Impostor-dev/src/Impostor.Api/Net/Messages/IMessageWriterProvider.cs @@ -0,0 +1,16 @@ +namespace Impostor.Api.Net.Messages +{ + public interface IMessageWriterProvider + { + /// <summary> + /// Retrieves a <see cref="IMessageWriter"/> from the internal pool. + /// Make sure to call <see cref="IMessageWriter.Dispose"/> when you are done! + /// </summary> + /// <param name="sendOption"> + /// Whether to send the message as <see cref="MessageType.Reliable"/> or <see cref="MessageType.Unreliable"/>. + /// Reliable packets will ensure delivery while unreliable packets may be lost. + /// </param> + /// <returns>A <see cref="IMessageWriter"/> from the pool.</returns> + IMessageWriter Get(MessageType sendOption = MessageType.Unreliable); + } +} diff --git a/Impostor-dev/src/Impostor.Api/Net/Messages/MessageFlags.cs b/Impostor-dev/src/Impostor.Api/Net/Messages/MessageFlags.cs new file mode 100644 index 0000000..aea0c60 --- /dev/null +++ b/Impostor-dev/src/Impostor.Api/Net/Messages/MessageFlags.cs @@ -0,0 +1,22 @@ +namespace Impostor.Api.Net.Messages +{ + public static class MessageFlags + { + public const byte HostGame = 0; + public const byte JoinGame = 1; + public const byte StartGame = 2; + public const byte RemoveGame = 3; + public const byte RemovePlayer = 4; + public const byte GameData = 5; + public const byte GameDataTo = 6; + public const byte JoinedGame = 7; + public const byte EndGame = 8; + public const byte AlterGame = 10; + public const byte KickPlayer = 11; + public const byte WaitForHost = 12; + public const byte Redirect = 13; + public const byte ReselectServer = 14; + public const byte GetGameList = 9; + public const byte GetGameListV2 = 16; + } +}
\ No newline at end of file diff --git a/Impostor-dev/src/Impostor.Api/Net/Messages/MessageType.cs b/Impostor-dev/src/Impostor.Api/Net/Messages/MessageType.cs new file mode 100644 index 0000000..1604358 --- /dev/null +++ b/Impostor-dev/src/Impostor.Api/Net/Messages/MessageType.cs @@ -0,0 +1,32 @@ +using System; + +namespace Impostor.Api.Net.Messages +{ + /// <summary> + /// Specifies how a message should be sent between connections. + /// </summary> + [Flags] + public enum MessageType : byte + { + /// <summary> + /// Requests unreliable delivery with no fragmentation. + /// </summary> + /// <remarks> + /// Sending data using unreliable delivery means that data is not guaranteed to arrive at it's destination nor is + /// it guaranteed to arrive only once. However, unreliable delivery can be faster than other methods and it + /// typically requires a smaller number of protocol bytes than other methods. There is also typically less + /// processing involved and less memory needed as packets are not stored once sent. + /// </remarks> + Unreliable, + + /// <summary> + /// Requests data be sent reliably but with no fragmentation. + /// </summary> + /// <remarks> + /// Sending data reliably means that data is guaranteed to arrive and to arrive only once. Reliable delivery + /// typically requires more processing, more memory (as packets need to be stored in case they need resending), + /// a larger number of protocol bytes and can be slower than unreliable delivery. + /// </remarks> + Reliable, + } +}
\ No newline at end of file diff --git a/Impostor-dev/src/Impostor.Api/Net/Messages/S2C/Message00HostGameS2C.cs b/Impostor-dev/src/Impostor.Api/Net/Messages/S2C/Message00HostGameS2C.cs new file mode 100644 index 0000000..8402d10 --- /dev/null +++ b/Impostor-dev/src/Impostor.Api/Net/Messages/S2C/Message00HostGameS2C.cs @@ -0,0 +1,20 @@ +using System; +using Impostor.Api.Innersloth; + +namespace Impostor.Api.Net.Messages.S2C +{ + public static class Message00HostGameS2C + { + public static void Serialize(IMessageWriter writer, int gameCode) + { + writer.StartMessage(MessageFlags.HostGame); + writer.Write(gameCode); + writer.EndMessage(); + } + + public static GameOptionsData Deserialize(IMessageReader reader) + { + throw new NotImplementedException(); + } + } +}
\ No newline at end of file diff --git a/Impostor-dev/src/Impostor.Api/Net/Messages/S2C/Message01JoinGameS2C.cs b/Impostor-dev/src/Impostor.Api/Net/Messages/S2C/Message01JoinGameS2C.cs new file mode 100644 index 0000000..c455201 --- /dev/null +++ b/Impostor-dev/src/Impostor.Api/Net/Messages/S2C/Message01JoinGameS2C.cs @@ -0,0 +1,50 @@ +using System; +using Impostor.Api.Innersloth; + +namespace Impostor.Api.Net.Messages.S2C +{ + public class Message01JoinGameS2C + { + public static void SerializeJoin(IMessageWriter writer, bool clear, int gameCode, int playerId, int hostId) + { + if (clear) + { + writer.Clear(MessageType.Reliable); + } + + writer.StartMessage(MessageFlags.JoinGame); + writer.Write(gameCode); + writer.Write(playerId); + writer.Write(hostId); + writer.EndMessage(); + } + + public static void SerializeError(IMessageWriter writer, bool clear, DisconnectReason reason, string? message = null) + { + if (clear) + { + writer.Clear(MessageType.Reliable); + } + + writer.StartMessage(MessageFlags.JoinGame); + writer.Write((int)reason); + + if (reason == DisconnectReason.Custom) + { + if (message == null) + { + throw new ArgumentNullException(nameof(message)); + } + + writer.Write(message); + } + + writer.EndMessage(); + } + + public static void Deserialize(IMessageReader reader) + { + throw new System.NotImplementedException(); + } + } +}
\ No newline at end of file diff --git a/Impostor-dev/src/Impostor.Api/Net/Messages/S2C/Message04RemovePlayerS2C.cs b/Impostor-dev/src/Impostor.Api/Net/Messages/S2C/Message04RemovePlayerS2C.cs new file mode 100644 index 0000000..77b447d --- /dev/null +++ b/Impostor-dev/src/Impostor.Api/Net/Messages/S2C/Message04RemovePlayerS2C.cs @@ -0,0 +1,29 @@ +using Impostor.Api.Innersloth; + +namespace Impostor.Api.Net.Messages.S2C +{ + public class Message04RemovePlayerS2C + { + public static void Serialize(IMessageWriter writer, bool clear, int gameCode, int playerId, int hostId, DisconnectReason reason) + { + // Only a subset of DisconnectReason shows an unique message. + // ExitGame, Banned and Kicked. + if (clear) + { + writer.Clear(MessageType.Reliable); + } + + writer.StartMessage(MessageFlags.RemovePlayer); + writer.Write(gameCode); + writer.Write(playerId); + writer.Write(hostId); + writer.Write((byte)reason); + writer.EndMessage(); + } + + public static void Deserialize(IMessageReader reader) + { + throw new System.NotImplementedException(); + } + } +}
\ No newline at end of file diff --git a/Impostor-dev/src/Impostor.Api/Net/Messages/S2C/Message07JoinedGameS2C.cs b/Impostor-dev/src/Impostor.Api/Net/Messages/S2C/Message07JoinedGameS2C.cs new file mode 100644 index 0000000..da6eb40 --- /dev/null +++ b/Impostor-dev/src/Impostor.Api/Net/Messages/S2C/Message07JoinedGameS2C.cs @@ -0,0 +1,31 @@ +namespace Impostor.Api.Net.Messages.S2C +{ + public static class Message07JoinedGameS2C + { + public static void Serialize(IMessageWriter writer, bool clear, int gameCode, int playerId, int hostId, int[] otherPlayerIds) + { + if (clear) + { + writer.Clear(MessageType.Reliable); + } + + writer.StartMessage(MessageFlags.JoinedGame); + writer.Write(gameCode); + writer.Write(playerId); + writer.Write(hostId); + writer.WritePacked(otherPlayerIds.Length); + + foreach (var id in otherPlayerIds) + { + writer.WritePacked(id); + } + + writer.EndMessage(); + } + + public static void Deserialize(IMessageReader reader) + { + throw new System.NotImplementedException(); + } + } +}
\ No newline at end of file diff --git a/Impostor-dev/src/Impostor.Api/Net/Messages/S2C/Message10AlterGameS2C.cs b/Impostor-dev/src/Impostor.Api/Net/Messages/S2C/Message10AlterGameS2C.cs new file mode 100644 index 0000000..fa155df --- /dev/null +++ b/Impostor-dev/src/Impostor.Api/Net/Messages/S2C/Message10AlterGameS2C.cs @@ -0,0 +1,26 @@ +using Impostor.Api.Innersloth; + +namespace Impostor.Api.Net.Messages.S2C +{ + public static class Message10AlterGameS2C + { + public static void Serialize(IMessageWriter writer, bool clear, int gameCode, bool isPublic) + { + if (clear) + { + writer.Clear(MessageType.Reliable); + } + + writer.StartMessage(MessageFlags.AlterGame); + writer.Write(gameCode); + writer.Write((byte)AlterGameTags.ChangePrivacy); + writer.Write(isPublic); + writer.EndMessage(); + } + + public static void Deserialize(IMessageReader reader) + { + throw new System.NotImplementedException(); + } + } +}
\ No newline at end of file diff --git a/Impostor-dev/src/Impostor.Api/Net/Messages/S2C/Message11KickPlayerS2C.cs b/Impostor-dev/src/Impostor.Api/Net/Messages/S2C/Message11KickPlayerS2C.cs new file mode 100644 index 0000000..1e2b6ef --- /dev/null +++ b/Impostor-dev/src/Impostor.Api/Net/Messages/S2C/Message11KickPlayerS2C.cs @@ -0,0 +1,24 @@ +namespace Impostor.Api.Net.Messages.S2C +{ + public class Message11KickPlayerS2C + { + public static void Serialize(IMessageWriter writer, bool clear, int gameCode, int playerId, bool isBan) + { + if (clear) + { + writer.Clear(MessageType.Reliable); + } + + writer.StartMessage(MessageFlags.KickPlayer); + writer.Write(gameCode); + writer.WritePacked(playerId); + writer.Write(isBan); + writer.EndMessage(); + } + + public static void Deserialize(IMessageReader reader) + { + throw new System.NotImplementedException(); + } + } +}
\ No newline at end of file diff --git a/Impostor-dev/src/Impostor.Api/Net/Messages/S2C/Message12WaitForHostS2C.cs b/Impostor-dev/src/Impostor.Api/Net/Messages/S2C/Message12WaitForHostS2C.cs new file mode 100644 index 0000000..5964b1c --- /dev/null +++ b/Impostor-dev/src/Impostor.Api/Net/Messages/S2C/Message12WaitForHostS2C.cs @@ -0,0 +1,23 @@ +namespace Impostor.Api.Net.Messages.S2C +{ + public class Message12WaitForHostS2C + { + public static void Serialize(IMessageWriter writer, bool clear, int gameCode, int playerId) + { + if (clear) + { + writer.Clear(MessageType.Reliable); + } + + writer.StartMessage(MessageFlags.WaitForHost); + writer.Write(gameCode); + writer.Write(playerId); + writer.EndMessage(); + } + + public static void Deserialize(IMessageReader reader) + { + throw new System.NotImplementedException(); + } + } +}
\ No newline at end of file diff --git a/Impostor-dev/src/Impostor.Api/Net/Messages/S2C/Message13RedirectS2C.cs b/Impostor-dev/src/Impostor.Api/Net/Messages/S2C/Message13RedirectS2C.cs new file mode 100644 index 0000000..4b93b0e --- /dev/null +++ b/Impostor-dev/src/Impostor.Api/Net/Messages/S2C/Message13RedirectS2C.cs @@ -0,0 +1,25 @@ +using System.Net; + +namespace Impostor.Api.Net.Messages.S2C +{ + public class Message13RedirectS2C + { + public static void Serialize(IMessageWriter writer, bool clear, IPEndPoint ipEndPoint) + { + if (clear) + { + writer.Clear(MessageType.Reliable); + } + + writer.StartMessage(MessageFlags.Redirect); + writer.Write(ipEndPoint.Address); + writer.Write((ushort)ipEndPoint.Port); + writer.EndMessage(); + } + + public static void Deserialize(IMessageReader reader) + { + throw new System.NotImplementedException(); + } + } +}
\ No newline at end of file diff --git a/Impostor-dev/src/Impostor.Api/Net/Messages/S2C/Message16GetGameListS2C.cs b/Impostor-dev/src/Impostor.Api/Net/Messages/S2C/Message16GetGameListS2C.cs new file mode 100644 index 0000000..93386d7 --- /dev/null +++ b/Impostor-dev/src/Impostor.Api/Net/Messages/S2C/Message16GetGameListS2C.cs @@ -0,0 +1,46 @@ +using System.Collections.Generic; +using Impostor.Api.Games; + +namespace Impostor.Api.Net.Messages.S2C +{ + public class Message16GetGameListS2C + { + public static void Serialize(IMessageWriter writer, int skeldGameCount, int miraHqGameCount, int polusGameCount, IEnumerable<IGame> games) + { + writer.StartMessage(MessageFlags.GetGameListV2); + + // Count + writer.StartMessage(1); + writer.Write(skeldGameCount); // The Skeld + writer.Write(miraHqGameCount); // Mira HQ + writer.Write(polusGameCount); // Polus + writer.EndMessage(); + + // Listing + writer.StartMessage(0); + + foreach (var game in games) + { + writer.StartMessage(0); + writer.Write(game.PublicIp.Address); + writer.Write((ushort)game.PublicIp.Port); + writer.Write(game.Code); + writer.Write(game.Host.Client.Name); + writer.Write((byte)game.PlayerCount); + writer.WritePacked(1); // TODO: What does Age do? + writer.Write((byte)game.Options.MapId); + writer.Write((byte)game.Options.NumImpostors); + writer.Write((byte)game.Options.MaxPlayers); + writer.EndMessage(); + } + + writer.EndMessage(); + writer.EndMessage(); + } + + public static void Deserialize(IMessageReader reader) + { + throw new System.NotImplementedException(); + } + } +}
\ No newline at end of file |