From: AeonLucid Date: Sat, 24 Oct 2020 23:07:36 +0000 (+0200) Subject: Add more events and missing SnapTo check X-Git-Tag: v1.2.2~96^2~3 X-Git-Url: https://git.deb.at/?a=commitdiff_plain;h=49269c33c9ccc55e7bcbb33d923d9f9bc7ab57fd;p=rhonda%2Fimpostor.git Add more events and missing SnapTo check --- diff --git a/src/Impostor.Api/Events/Game/GameEndedEvent.cs b/src/Impostor.Api/Events/Game/GameEndedEvent.cs new file mode 100644 index 0000000..0628fcf --- /dev/null +++ b/src/Impostor.Api/Events/Game/GameEndedEvent.cs @@ -0,0 +1,14 @@ +using Impostor.Api.Games; + +namespace Impostor.Api.Events +{ + public class GameEndedEvent : IGameEvent + { + public GameEndedEvent(IGame game) + { + Game = game; + } + + public IGame Game { get; } + } +} \ No newline at end of file diff --git a/src/Impostor.Api/Events/Game/GameStartedEvent.cs b/src/Impostor.Api/Events/Game/GameStartedEvent.cs new file mode 100644 index 0000000..12311a3 --- /dev/null +++ b/src/Impostor.Api/Events/Game/GameStartedEvent.cs @@ -0,0 +1,17 @@ +using Impostor.Api.Games; + +namespace Impostor.Api.Events +{ + /// + /// The game is started here and players have been initialized. + /// + public class GameStartedEvent : IGameEvent + { + public GameStartedEvent(IGame game) + { + Game = game; + } + + public IGame Game { get; } + } +} \ No newline at end of file diff --git a/src/Impostor.Api/Events/Game/GameStartingEvent.cs b/src/Impostor.Api/Events/Game/GameStartingEvent.cs new file mode 100644 index 0000000..b60d007 --- /dev/null +++ b/src/Impostor.Api/Events/Game/GameStartingEvent.cs @@ -0,0 +1,19 @@ +using Impostor.Api.Games; + +namespace Impostor.Api.Events +{ + /// + /// Called when the game is going to start. + /// When this is called, not all players are initialized properly yet. + /// If you want to get correct player states, use . + /// + public class GameStartingEvent : IGameEvent + { + public GameStartingEvent(IGame game) + { + Game = game; + } + + public IGame Game { get; } + } +} \ No newline at end of file diff --git a/src/Impostor.Api/Events/Game/Net/PlayerChatEvent.cs b/src/Impostor.Api/Events/Game/Net/PlayerChatEvent.cs deleted file mode 100644 index cac481c..0000000 --- a/src/Impostor.Api/Events/Game/Net/PlayerChatEvent.cs +++ /dev/null @@ -1,21 +0,0 @@ -using Impostor.Api.Games; -using Impostor.Api.Net.Inner.Objects; - -namespace Impostor.Api.Events.Net -{ - public class PlayerChatEvent : IGameEvent - { - public PlayerChatEvent(IGame game, IInnerPlayerControl playerControl, string message) - { - Game = game; - PlayerControl = playerControl; - Message = message; - } - - public IGame Game { get; } - - public IInnerPlayerControl PlayerControl { get; } - - public string Message { get; } - } -} \ No newline at end of file diff --git a/src/Impostor.Api/Events/Game/Net/PlayerDestroyedEvent.cs b/src/Impostor.Api/Events/Game/Net/PlayerDestroyedEvent.cs deleted file mode 100644 index 6d5d8c4..0000000 --- a/src/Impostor.Api/Events/Game/Net/PlayerDestroyedEvent.cs +++ /dev/null @@ -1,18 +0,0 @@ -using Impostor.Api.Games; -using Impostor.Api.Net.Inner.Objects; - -namespace Impostor.Api.Events.Net -{ - public class PlayerDestroyedEvent : IGameEvent - { - public PlayerDestroyedEvent(IGame game, IInnerPlayerControl playerControl) - { - Game = game; - PlayerControl = playerControl; - } - - public IGame Game { get; } - - public IInnerPlayerControl PlayerControl { get; } - } -} \ No newline at end of file diff --git a/src/Impostor.Api/Events/Game/Net/PlayerSpawnedEvent.cs b/src/Impostor.Api/Events/Game/Net/PlayerSpawnedEvent.cs deleted file mode 100644 index 9b1664a..0000000 --- a/src/Impostor.Api/Events/Game/Net/PlayerSpawnedEvent.cs +++ /dev/null @@ -1,18 +0,0 @@ -using Impostor.Api.Games; -using Impostor.Api.Net.Inner.Objects; - -namespace Impostor.Api.Events.Net -{ - public class PlayerSpawnedEvent : IGameEvent - { - public PlayerSpawnedEvent(IGame game, IInnerPlayerControl playerControl) - { - Game = game; - PlayerControl = playerControl; - } - - public IGame Game { get; } - - public IInnerPlayerControl PlayerControl { get; } - } -} \ No newline at end of file diff --git a/src/Impostor.Api/Events/Game/PlayerChatEvent.cs b/src/Impostor.Api/Events/Game/PlayerChatEvent.cs new file mode 100644 index 0000000..1d70536 --- /dev/null +++ b/src/Impostor.Api/Events/Game/PlayerChatEvent.cs @@ -0,0 +1,21 @@ +using Impostor.Api.Games; +using Impostor.Api.Net.Inner.Objects; + +namespace Impostor.Api.Events +{ + public class PlayerChatEvent : IGameEvent + { + public PlayerChatEvent(IGame game, IInnerPlayerControl playerControl, string message) + { + Game = game; + PlayerControl = playerControl; + Message = message; + } + + public IGame Game { get; } + + public IInnerPlayerControl PlayerControl { get; } + + public string Message { get; } + } +} \ No newline at end of file diff --git a/src/Impostor.Api/Events/Game/PlayerDestroyedEvent.cs b/src/Impostor.Api/Events/Game/PlayerDestroyedEvent.cs new file mode 100644 index 0000000..6d5d8c4 --- /dev/null +++ b/src/Impostor.Api/Events/Game/PlayerDestroyedEvent.cs @@ -0,0 +1,18 @@ +using Impostor.Api.Games; +using Impostor.Api.Net.Inner.Objects; + +namespace Impostor.Api.Events.Net +{ + public class PlayerDestroyedEvent : IGameEvent + { + public PlayerDestroyedEvent(IGame game, IInnerPlayerControl playerControl) + { + Game = game; + PlayerControl = playerControl; + } + + public IGame Game { get; } + + public IInnerPlayerControl PlayerControl { get; } + } +} \ No newline at end of file diff --git a/src/Impostor.Api/Events/Game/PlayerMovementEvent.cs b/src/Impostor.Api/Events/Game/PlayerMovementEvent.cs new file mode 100644 index 0000000..fd9238a --- /dev/null +++ b/src/Impostor.Api/Events/Game/PlayerMovementEvent.cs @@ -0,0 +1,14 @@ +using Impostor.Api.Games; + +namespace Impostor.Api.Events +{ + public class PlayerMovementEvent : IGameEvent + { + public PlayerMovementEvent(IGame game) + { + Game = game; + } + + public IGame Game { get; } + } +} \ No newline at end of file diff --git a/src/Impostor.Api/Events/Game/PlayerSpawnedEvent.cs b/src/Impostor.Api/Events/Game/PlayerSpawnedEvent.cs new file mode 100644 index 0000000..9b1664a --- /dev/null +++ b/src/Impostor.Api/Events/Game/PlayerSpawnedEvent.cs @@ -0,0 +1,18 @@ +using Impostor.Api.Games; +using Impostor.Api.Net.Inner.Objects; + +namespace Impostor.Api.Events.Net +{ + public class PlayerSpawnedEvent : IGameEvent + { + public PlayerSpawnedEvent(IGame game, IInnerPlayerControl playerControl) + { + Game = game; + PlayerControl = playerControl; + } + + public IGame Game { get; } + + public IInnerPlayerControl PlayerControl { get; } + } +} \ No newline at end of file diff --git a/src/Impostor.Api/Innersloth/GameStates.cs b/src/Impostor.Api/Innersloth/GameStates.cs index 8abc8c7..f5aaa9c 100644 --- a/src/Impostor.Api/Innersloth/GameStates.cs +++ b/src/Impostor.Api/Innersloth/GameStates.cs @@ -3,8 +3,9 @@ public enum GameStates : byte { NotStarted = 0, - Started = 1, - Ended = 2, - Destroyed = 3 + Starting = 1, + Started = 2, + Ended = 3, + Destroyed = 4, } } \ No newline at end of file diff --git a/src/Impostor.Api/Net/Inner/Objects/IInnerPlayerControl.cs b/src/Impostor.Api/Net/Inner/Objects/IInnerPlayerControl.cs index 45b949a..4d53d2c 100644 --- a/src/Impostor.Api/Net/Inner/Objects/IInnerPlayerControl.cs +++ b/src/Impostor.Api/Net/Inner/Objects/IInnerPlayerControl.cs @@ -1,7 +1,13 @@ -namespace Impostor.Api.Net.Inner.Objects +using System.Threading.Tasks; + +namespace Impostor.Api.Net.Inner.Objects { public interface IInnerPlayerControl { IInnerPlayerInfo PlayerInfo { get; } + + ValueTask SetNameAsync(string name); + + ValueTask SendChatAsync(string text); } } \ No newline at end of file diff --git a/src/Impostor.Api/Net/Inner/Objects/IInnerPlayerInfo.cs b/src/Impostor.Api/Net/Inner/Objects/IInnerPlayerInfo.cs index e1de18b..2715d2d 100644 --- a/src/Impostor.Api/Net/Inner/Objects/IInnerPlayerInfo.cs +++ b/src/Impostor.Api/Net/Inner/Objects/IInnerPlayerInfo.cs @@ -1,10 +1,47 @@ -namespace Impostor.Api.Net.Inner.Objects +using Impostor.Api.Innersloth; + +namespace Impostor.Api.Net.Inner.Objects { public interface IInnerPlayerInfo { /// /// Gets the name of the player as decided by the host. /// - public string PlayerName { get; } + string PlayerName { get; } + + /// + /// Gets the color of the player. + /// + byte ColorId { get; } + + /// + /// Gets the hat of the player. + /// + uint HatId { get; } + + /// + /// Gets the pet of the player. + /// + uint PetId { get; } + + /// + /// Gets the skin of the player. + /// + uint SkinId { get; } + + /// + /// Gets a value indicating whether the player is an impostor. + /// + bool IsImpostor { get; } + + /// + /// Gets a value indicating whether the player is a dead in the current game. + /// + bool IsDead { get; } + + /// + /// Gets the reason why the player is dead in the current game. + /// + DeathReason LastDeathReason { get; } } } \ No newline at end of file diff --git a/src/Impostor.Plugins.Example/Handlers/GameEventListener.cs b/src/Impostor.Plugins.Example/Handlers/GameEventListener.cs index 29c3c98..19d9bc4 100644 --- a/src/Impostor.Plugins.Example/Handlers/GameEventListener.cs +++ b/src/Impostor.Plugins.Example/Handlers/GameEventListener.cs @@ -8,13 +8,38 @@ namespace Impostor.Plugins.Example.Handlers [EventListener] public void OnGameCreated(GameCreatedEvent e) { - Console.WriteLine("Game was created."); + Console.WriteLine("Game > created"); + } + + [EventListener] + public void OnGameStarting(GameStartingEvent e) + { + Console.WriteLine("Game > starting"); + } + + [EventListener] + public void OnGameStarted(GameStartedEvent e) + { + Console.WriteLine("Game > started"); + + foreach (var player in e.Game.Players) + { + var info = player.Character.PlayerInfo; + + Console.WriteLine($"- {info.PlayerName} {info.IsImpostor}"); + } + } + + [EventListener] + public void OnGameEnded(GameEndedEvent e) + { + Console.WriteLine("Game > ended"); } [EventListener] public void OnGameDestroyed(GameDestroyedEvent e) { - Console.WriteLine("Game was destroyed."); + Console.WriteLine("Game > destroyed"); } [EventListener] diff --git a/src/Impostor.Plugins.Example/Handlers/PlayerEventListener.cs b/src/Impostor.Plugins.Example/Handlers/PlayerEventListener.cs index 590ad71..9d16229 100644 --- a/src/Impostor.Plugins.Example/Handlers/PlayerEventListener.cs +++ b/src/Impostor.Plugins.Example/Handlers/PlayerEventListener.cs @@ -1,4 +1,5 @@ using System; +using System.Threading.Tasks; using Impostor.Api.Events; using Impostor.Api.Events.Net; @@ -19,9 +20,12 @@ namespace Impostor.Plugins.Example.Handlers } [EventListener] - public void OnPlayerChat(PlayerChatEvent e) + public async ValueTask OnPlayerChat(PlayerChatEvent e) { Console.WriteLine(e.PlayerControl.PlayerInfo.PlayerName + " said " + e.Message); + + await e.PlayerControl.SetNameAsync(e.Message); + await e.PlayerControl.SendChatAsync(e.Message); } } } \ No newline at end of file diff --git a/src/Impostor.Server/Net/Inner/Objects/Components/InnerCustomNetworkTransform.cs b/src/Impostor.Server/Net/Inner/Objects/Components/InnerCustomNetworkTransform.cs index 75e331e..c621add 100644 --- a/src/Impostor.Server/Net/Inner/Objects/Components/InnerCustomNetworkTransform.cs +++ b/src/Impostor.Server/Net/Inner/Objects/Components/InnerCustomNetworkTransform.cs @@ -1,4 +1,5 @@ -using System.Numerics; +using System; +using System.Numerics; using System.Threading.Tasks; using Impostor.Api; using Impostor.Api.Innersloth; @@ -15,14 +16,18 @@ namespace Impostor.Server.Net.Inner.Objects.Components private static readonly FloatRange YRange = new FloatRange(-40f, 40f); private readonly ILogger _logger; + private readonly InnerPlayerControl _playerControl; + private readonly Game _game; private ushort _lastSequenceId; private Vector2 _targetSyncPosition; private Vector2 _targetSyncVelocity; - public InnerCustomNetworkTransform(ILogger logger) + public InnerCustomNetworkTransform(ILogger logger, InnerPlayerControl playerControl, Game game) { _logger = logger; + _playerControl = playerControl; + _game = game; } private static bool SidGreaterThan(ushort newSid, ushort prevSid) @@ -48,18 +53,31 @@ namespace Impostor.Server.Net.Inner.Objects.Components return new Vector2(XRange.Lerp(v1), YRange.Lerp(v2)); } - public override ValueTask HandleRpc(ClientPlayer sender, ClientPlayer? target, RpcCalls call, IMessageReader reader) + public override async ValueTask HandleRpc(ClientPlayer sender, ClientPlayer? target, RpcCalls call, IMessageReader reader) { if (call == RpcCalls.SnapTo) { + if (!sender.IsOwner(this)) + { + throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.SnapTo)} to an unowned {nameof(InnerPlayerControl)}"); + } + + if (target != null) + { + throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.SnapTo)} to a specific player instead of broadcast"); + } + + if (!sender.Character.PlayerInfo.IsImpostor) + { + throw new ImpostorCheatException($"Client sent {nameof(RpcCalls.SnapTo)} as crewmate"); + } + SnapTo(ReadVector2(reader), reader.ReadUInt16()); } else { _logger.LogWarning("{0}: Unknown rpc call {1}", nameof(InnerCustomNetworkTransform), call); } - - return default; } public override bool Serialize(IMessageWriter writer, bool initialState) diff --git a/src/Impostor.Server/Net/Inner/Objects/Components/InnerPlayerPhysics.cs b/src/Impostor.Server/Net/Inner/Objects/Components/InnerPlayerPhysics.cs index 08738f7..50c3a06 100644 --- a/src/Impostor.Server/Net/Inner/Objects/Components/InnerPlayerPhysics.cs +++ b/src/Impostor.Server/Net/Inner/Objects/Components/InnerPlayerPhysics.cs @@ -11,10 +11,12 @@ namespace Impostor.Server.Net.Inner.Objects.Components internal class InnerPlayerPhysics : InnerNetObject { private readonly ILogger _logger; + private readonly InnerPlayerControl _playerControl; - public InnerPlayerPhysics(ILogger logger) + public InnerPlayerPhysics(ILogger logger, InnerPlayerControl playerControl) { _logger = logger; + _playerControl = playerControl; } public override ValueTask HandleRpc(ClientPlayer sender, ClientPlayer? target, RpcCalls call, IMessageReader reader) diff --git a/src/Impostor.Server/Net/Inner/Objects/InnerPlayerControl.Api.cs b/src/Impostor.Server/Net/Inner/Objects/InnerPlayerControl.Api.cs index 225d78f..6a9fa45 100644 --- a/src/Impostor.Server/Net/Inner/Objects/InnerPlayerControl.Api.cs +++ b/src/Impostor.Server/Net/Inner/Objects/InnerPlayerControl.Api.cs @@ -1,9 +1,28 @@ -using Impostor.Api.Net.Inner.Objects; +using System.Threading.Tasks; +using Impostor.Api.Net.Inner.Objects; namespace Impostor.Server.Net.Inner.Objects { internal partial class InnerPlayerControl : IInnerPlayerControl { IInnerPlayerInfo IInnerPlayerControl.PlayerInfo => PlayerInfo; + + public async ValueTask SetNameAsync(string name) + { + using (var writer = _game.StartRpc(NetId, RpcCalls.SetName)) + { + writer.Write(name); + await _game.FinishRpcAsync(writer); + } + } + + public async ValueTask SendChatAsync(string text) + { + using (var writer = _game.StartRpc(NetId, RpcCalls.SendChat)) + { + writer.Write(text); + await _game.FinishRpcAsync(writer); + } + } } } \ No newline at end of file diff --git a/src/Impostor.Server/Net/Inner/Objects/InnerPlayerControl.cs b/src/Impostor.Server/Net/Inner/Objects/InnerPlayerControl.cs index 4d3576c..0d6f39b 100644 --- a/src/Impostor.Server/Net/Inner/Objects/InnerPlayerControl.cs +++ b/src/Impostor.Server/Net/Inner/Objects/InnerPlayerControl.cs @@ -1,6 +1,7 @@ using System; using System.Threading.Tasks; using Impostor.Api; +using Impostor.Api.Events; using Impostor.Api.Events.Managers; using Impostor.Api.Events.Net; using Impostor.Api.Innersloth; @@ -26,9 +27,12 @@ namespace Impostor.Server.Net.Inner.Objects _eventManager = eventManager; _game = game; + Physics = ActivatorUtilities.CreateInstance(serviceProvider, this); + NetworkTransform = ActivatorUtilities.CreateInstance(serviceProvider, this, _game); + Components.Add(this); - Components.Add(ActivatorUtilities.CreateInstance(serviceProvider)); - Components.Add(ActivatorUtilities.CreateInstance(serviceProvider)); + Components.Add(Physics); + Components.Add(NetworkTransform); PlayerId = byte.MaxValue; } @@ -37,6 +41,10 @@ namespace Impostor.Server.Net.Inner.Objects public byte PlayerId { get; private set; } + public InnerPlayerPhysics Physics { get; } + + public InnerCustomNetworkTransform NetworkTransform { get; } + public InnerPlayerInfo PlayerInfo { get; internal set; } public override async ValueTask HandleRpc(ClientPlayer sender, ClientPlayer? target, RpcCalls call, IMessageReader reader) @@ -103,8 +111,15 @@ namespace Impostor.Server.Net.Inner.Objects { var playerId = reader.ReadByte(); var player = _game.GameNet.GameData.GetPlayerById(playerId); + if (player != null) + { + player.IsImpostor = true; + } + } - player.IsImpostor = true; + if (_game.GameState == GameStates.Starting) + { + await _game.StartedAsync(); } break; diff --git a/src/Impostor.Server/Net/State/Game.Incoming.cs b/src/Impostor.Server/Net/State/Game.Incoming.cs index 4d1342b..7d81b36 100644 --- a/src/Impostor.Server/Net/State/Game.Incoming.cs +++ b/src/Impostor.Server/Net/State/Game.Incoming.cs @@ -1,6 +1,7 @@ using System; using System.Threading; using System.Threading.Tasks; +using Impostor.Api.Events; using Impostor.Api.Games; using Impostor.Api.Innersloth; using Impostor.Api.Net; @@ -17,11 +18,13 @@ namespace Impostor.Server.Net.State public async ValueTask HandleStartGame(IMessageReader message) { - GameState = GameStates.Started; + GameState = GameStates.Starting; using var packet = MessageWriter.Get(MessageType.Reliable); message.CopyTo(packet); await SendToAllAsync(packet); + + await _eventManager.CallAsync(new GameStartingEvent(this)); } public async ValueTask AddClientAsync(ClientBase client) @@ -66,7 +69,7 @@ namespace Impostor.Server.Net.State return GameJoinResult.FromError(GameJoinError.GameFull); } - if (GameState == GameStates.Started) + if (GameState == GameStates.Starting || GameState == GameStates.Started) { return GameJoinResult.FromError(GameJoinError.GameStarted); } @@ -124,6 +127,8 @@ namespace Impostor.Server.Net.State { player.Value.Limbo = LimboStates.PreSpawn; } + + await _eventManager.CallAsync(new GameEndedEvent(this)); } public async ValueTask HandleAlterGame(IMessageReader message, IClientPlayer sender, bool isPublic) diff --git a/src/Impostor.Server/Net/State/Game.Outgoing.cs b/src/Impostor.Server/Net/State/Game.Outgoing.cs index 3f2ef68..555216a 100644 --- a/src/Impostor.Server/Net/State/Game.Outgoing.cs +++ b/src/Impostor.Server/Net/State/Game.Outgoing.cs @@ -4,6 +4,9 @@ using Impostor.Api.Innersloth; using Impostor.Api.Net; using Impostor.Api.Net.Messages; using Impostor.Api.Net.Messages.S2C; +using Impostor.Hazel; +using Impostor.Hazel.Udp; +using Impostor.Server.Net.Inner; namespace Impostor.Server.Net.State { @@ -35,6 +38,37 @@ namespace Impostor.Server.Net.State } } + internal IMessageWriter StartRpc(uint targetNetId, RpcCalls callId, int targetClientId = -1, MessageType type = MessageType.Reliable) + { + var writer = MessageWriter.Get(type); + + if (targetClientId < 0) + { + writer.StartMessage(MessageFlags.GameData); + writer.Write(Code); + } + else + { + writer.StartMessage(MessageFlags.GameDataTo); + writer.Write(Code); + writer.WritePacked(targetClientId); + } + + writer.StartMessage(GameDataTag.RpcFlag); + writer.WritePacked(targetNetId); + writer.Write((byte) callId); + + return writer; + } + + internal ValueTask FinishRpcAsync(IMessageWriter writer) + { + writer.EndMessage(); + writer.EndMessage(); + + return SendToAllAsync(writer); + } + private void WriteRemovePlayerMessage(IMessageWriter message, bool clear, int playerId, DisconnectReason reason) { Message04RemovePlayerS2C.Serialize(message, clear, Code, playerId, HostId, reason); diff --git a/src/Impostor.Server/Net/State/Game.State.cs b/src/Impostor.Server/Net/State/Game.State.cs index 27b65a8..8b22030 100644 --- a/src/Impostor.Server/Net/State/Game.State.cs +++ b/src/Impostor.Server/Net/State/Game.State.cs @@ -40,7 +40,7 @@ namespace Impostor.Server.Net.State _logger.LogInformation("{0} - Player {1} ({2}) has left.", Code, player.Client.Name, playerId); - if (GameState == GameStates.Started) + if (GameState == GameStates.Starting || GameState == GameStates.Started) { if (player.Character?.PlayerInfo != null) { diff --git a/src/Impostor.Server/Net/State/Game.cs b/src/Impostor.Server/Net/State/Game.cs index b48a5b2..7462cd6 100644 --- a/src/Impostor.Server/Net/State/Game.cs +++ b/src/Impostor.Server/Net/State/Game.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Linq; using System.Net; using System.Threading.Tasks; +using Impostor.Api.Events; using Impostor.Api.Events.Managers; using Impostor.Api.Games; using Impostor.Api.Innersloth; @@ -91,6 +92,18 @@ namespace Impostor.Server.Net.State return _players.TryGetValue(clientId, out var clientPlayer) ? clientPlayer : null; } + internal ValueTask StartedAsync() + { + if (GameState == GameStates.Starting) + { + GameState = GameStates.Started; + + return _eventManager.CallAsync(new GameStartedEvent(this)); + } + + return default; + } + public ValueTask EndAsync() { return _gameManager.RemoveAsync(Code);