From 5f922f5f83c92628c04ce5d0f869404261b34dbc Mon Sep 17 00:00:00 2001 From: AeonLucid Date: Fri, 16 Oct 2020 05:00:49 +0200 Subject: [PATCH] Added GameData spawn --- src/Impostor.Server/GameData/GameObject.cs | 29 +++ .../GameData/InnerNetObject.cs | 19 ++ .../Components/InnerCustomNetworkTransform.cs | 22 +++ .../Objects/Components/InnerPlayerPhysics.cs | 22 +++ .../Objects/Components/InnerVoteBanSystem.cs | 22 +++ .../GameData/Objects/InnerGameData.cs | 34 ++++ .../GameData/Objects/InnerLobbyBehaviour.cs | 32 +++ .../GameData/Objects/InnerMeetingHud.cs | 32 +++ .../GameData/Objects/InnerPlayerControl.cs | 35 ++++ .../GameData/Objects/InnerShipStatus.cs | 32 +++ src/Impostor.Server/GameData/SpawnFlags.cs | 11 ++ src/Impostor.Server/Impostor.Server.csproj | 14 +- src/Impostor.Server/Net/Client.cs | 5 +- src/Impostor.Server/Net/State/Game.Data.cs | 187 ++++++++++++++++++ .../Net/State/Game.Incoming.cs | 78 +------- src/Impostor.Server/Net/State/Game.cs | 6 +- 16 files changed, 492 insertions(+), 88 deletions(-) create mode 100644 src/Impostor.Server/GameData/GameObject.cs create mode 100644 src/Impostor.Server/GameData/InnerNetObject.cs create mode 100644 src/Impostor.Server/GameData/Objects/Components/InnerCustomNetworkTransform.cs create mode 100644 src/Impostor.Server/GameData/Objects/Components/InnerPlayerPhysics.cs create mode 100644 src/Impostor.Server/GameData/Objects/Components/InnerVoteBanSystem.cs create mode 100644 src/Impostor.Server/GameData/Objects/InnerGameData.cs create mode 100644 src/Impostor.Server/GameData/Objects/InnerLobbyBehaviour.cs create mode 100644 src/Impostor.Server/GameData/Objects/InnerMeetingHud.cs create mode 100644 src/Impostor.Server/GameData/Objects/InnerPlayerControl.cs create mode 100644 src/Impostor.Server/GameData/Objects/InnerShipStatus.cs create mode 100644 src/Impostor.Server/GameData/SpawnFlags.cs create mode 100644 src/Impostor.Server/Net/State/Game.Data.cs diff --git a/src/Impostor.Server/GameData/GameObject.cs b/src/Impostor.Server/GameData/GameObject.cs new file mode 100644 index 0000000..c78dee0 --- /dev/null +++ b/src/Impostor.Server/GameData/GameObject.cs @@ -0,0 +1,29 @@ +using System.Collections.Generic; + +namespace Impostor.Server.GameData +{ + public class GameObject + { + public GameObject() + { + Components = new List(); + } + + protected List Components { get; } + + public List GetComponentsInChildren() + { + var result = new List(); + + foreach (var component in Components) + { + if (component.GetType().IsAssignableTo(typeof(T))) + { + result.Add((T) component); + } + } + + return result; + } + } +} \ No newline at end of file diff --git a/src/Impostor.Server/GameData/InnerNetObject.cs b/src/Impostor.Server/GameData/InnerNetObject.cs new file mode 100644 index 0000000..6f153ed --- /dev/null +++ b/src/Impostor.Server/GameData/InnerNetObject.cs @@ -0,0 +1,19 @@ +using Impostor.Server.Net.Messages; + +namespace Impostor.Server.GameData +{ + public abstract class InnerNetObject : GameObject + { + public uint NetId { get; set; } + + public int OwnerId { get; set; } + + public SpawnFlags SpawnFlags { get; internal set; } + + public abstract void HandleRpc(byte callId, IMessageReader reader); + + public abstract bool Serialize(IMessageWriter writer, bool initialState); + + public abstract void Deserialize(IMessageReader reader, bool initialState); + } +} \ No newline at end of file diff --git a/src/Impostor.Server/GameData/Objects/Components/InnerCustomNetworkTransform.cs b/src/Impostor.Server/GameData/Objects/Components/InnerCustomNetworkTransform.cs new file mode 100644 index 0000000..1591903 --- /dev/null +++ b/src/Impostor.Server/GameData/Objects/Components/InnerCustomNetworkTransform.cs @@ -0,0 +1,22 @@ +using Impostor.Server.Net.Messages; + +namespace Impostor.Server.GameData.Objects.Components +{ + public class InnerCustomNetworkTransform : InnerNetObject + { + public override void HandleRpc(byte callId, IMessageReader reader) + { + throw new System.NotImplementedException(); + } + + public override bool Serialize(IMessageWriter writer, bool initialState) + { + throw new System.NotImplementedException(); + } + + public override void Deserialize(IMessageReader reader, bool initialState) + { + throw new System.NotImplementedException(); + } + } +} \ No newline at end of file diff --git a/src/Impostor.Server/GameData/Objects/Components/InnerPlayerPhysics.cs b/src/Impostor.Server/GameData/Objects/Components/InnerPlayerPhysics.cs new file mode 100644 index 0000000..edc01e0 --- /dev/null +++ b/src/Impostor.Server/GameData/Objects/Components/InnerPlayerPhysics.cs @@ -0,0 +1,22 @@ +using Impostor.Server.Net.Messages; + +namespace Impostor.Server.GameData.Objects.Components +{ + public class InnerPlayerPhysics : InnerNetObject + { + public override void HandleRpc(byte callId, IMessageReader reader) + { + throw new System.NotImplementedException(); + } + + public override bool Serialize(IMessageWriter writer, bool initialState) + { + throw new System.NotImplementedException(); + } + + public override void Deserialize(IMessageReader reader, bool initialState) + { + throw new System.NotImplementedException(); + } + } +} \ No newline at end of file diff --git a/src/Impostor.Server/GameData/Objects/Components/InnerVoteBanSystem.cs b/src/Impostor.Server/GameData/Objects/Components/InnerVoteBanSystem.cs new file mode 100644 index 0000000..c63cd09 --- /dev/null +++ b/src/Impostor.Server/GameData/Objects/Components/InnerVoteBanSystem.cs @@ -0,0 +1,22 @@ +using Impostor.Server.Net.Messages; + +namespace Impostor.Server.GameData.Objects.Components +{ + public class InnerVoteBanSystem : InnerNetObject + { + public override void HandleRpc(byte callId, IMessageReader reader) + { + throw new System.NotImplementedException(); + } + + public override bool Serialize(IMessageWriter writer, bool initialState) + { + throw new System.NotImplementedException(); + } + + public override void Deserialize(IMessageReader reader, bool initialState) + { + throw new System.NotImplementedException(); + } + } +} \ No newline at end of file diff --git a/src/Impostor.Server/GameData/Objects/InnerGameData.cs b/src/Impostor.Server/GameData/Objects/InnerGameData.cs new file mode 100644 index 0000000..a25202c --- /dev/null +++ b/src/Impostor.Server/GameData/Objects/InnerGameData.cs @@ -0,0 +1,34 @@ +using Impostor.Server.GameData.Objects.Components; +using Impostor.Server.Games; +using Impostor.Server.Net.Messages; + +namespace Impostor.Server.GameData.Objects +{ + public class InnerGameData : InnerNetObject + { + private readonly IGame _game; + + public InnerGameData(IGame game) + { + _game = game; + + Components.Add(this); + Components.Add(new InnerVoteBanSystem()); + } + + public override void HandleRpc(byte callId, IMessageReader reader) + { + throw new System.NotImplementedException(); + } + + public override bool Serialize(IMessageWriter writer, bool initialState) + { + throw new System.NotImplementedException(); + } + + public override void Deserialize(IMessageReader reader, bool initialState) + { + throw new System.NotImplementedException(); + } + } +} \ No newline at end of file diff --git a/src/Impostor.Server/GameData/Objects/InnerLobbyBehaviour.cs b/src/Impostor.Server/GameData/Objects/InnerLobbyBehaviour.cs new file mode 100644 index 0000000..d2533fa --- /dev/null +++ b/src/Impostor.Server/GameData/Objects/InnerLobbyBehaviour.cs @@ -0,0 +1,32 @@ +using Impostor.Server.Games; +using Impostor.Server.Net.Messages; + +namespace Impostor.Server.GameData.Objects +{ + public class InnerLobbyBehaviour : InnerNetObject + { + private readonly IGame _game; + + public InnerLobbyBehaviour(IGame game) + { + _game = game; + + Components.Add(this); + } + + public override void HandleRpc(byte callId, IMessageReader reader) + { + throw new System.NotImplementedException(); + } + + public override bool Serialize(IMessageWriter writer, bool initialState) + { + throw new System.NotImplementedException(); + } + + public override void Deserialize(IMessageReader reader, bool initialState) + { + throw new System.NotImplementedException(); + } + } +} \ No newline at end of file diff --git a/src/Impostor.Server/GameData/Objects/InnerMeetingHud.cs b/src/Impostor.Server/GameData/Objects/InnerMeetingHud.cs new file mode 100644 index 0000000..12c1054 --- /dev/null +++ b/src/Impostor.Server/GameData/Objects/InnerMeetingHud.cs @@ -0,0 +1,32 @@ +using Impostor.Server.Games; +using Impostor.Server.Net.Messages; + +namespace Impostor.Server.GameData.Objects +{ + public class InnerMeetingHud : InnerNetObject + { + private readonly IGame _game; + + public InnerMeetingHud(IGame game) + { + _game = game; + + Components.Add(this); + } + + public override void HandleRpc(byte callId, IMessageReader reader) + { + throw new System.NotImplementedException(); + } + + public override bool Serialize(IMessageWriter writer, bool initialState) + { + throw new System.NotImplementedException(); + } + + public override void Deserialize(IMessageReader reader, bool initialState) + { + throw new System.NotImplementedException(); + } + } +} \ No newline at end of file diff --git a/src/Impostor.Server/GameData/Objects/InnerPlayerControl.cs b/src/Impostor.Server/GameData/Objects/InnerPlayerControl.cs new file mode 100644 index 0000000..049b2be --- /dev/null +++ b/src/Impostor.Server/GameData/Objects/InnerPlayerControl.cs @@ -0,0 +1,35 @@ +using Impostor.Server.GameData.Objects.Components; +using Impostor.Server.Games; +using Impostor.Server.Net.Messages; + +namespace Impostor.Server.GameData.Objects +{ + public class InnerPlayerControl : InnerNetObject + { + private readonly IGame _game; + + public InnerPlayerControl(IGame game) + { + _game = game; + + Components.Add(this); + Components.Add(new InnerPlayerPhysics()); + Components.Add(new InnerCustomNetworkTransform()); + } + + public override void HandleRpc(byte callId, IMessageReader reader) + { + throw new System.NotImplementedException(); + } + + public override bool Serialize(IMessageWriter writer, bool initialState) + { + throw new System.NotImplementedException(); + } + + public override void Deserialize(IMessageReader reader, bool initialState) + { + throw new System.NotImplementedException(); + } + } +} \ No newline at end of file diff --git a/src/Impostor.Server/GameData/Objects/InnerShipStatus.cs b/src/Impostor.Server/GameData/Objects/InnerShipStatus.cs new file mode 100644 index 0000000..8662983 --- /dev/null +++ b/src/Impostor.Server/GameData/Objects/InnerShipStatus.cs @@ -0,0 +1,32 @@ +using Impostor.Server.Games; +using Impostor.Server.Net.Messages; + +namespace Impostor.Server.GameData.Objects +{ + public class InnerShipStatus : InnerNetObject + { + private readonly IGame _game; + + public InnerShipStatus(IGame game) + { + _game = game; + + Components.Add(this); + } + + public override void HandleRpc(byte callId, IMessageReader reader) + { + throw new System.NotImplementedException(); + } + + public override bool Serialize(IMessageWriter writer, bool initialState) + { + throw new System.NotImplementedException(); + } + + public override void Deserialize(IMessageReader reader, bool initialState) + { + throw new System.NotImplementedException(); + } + } +} \ No newline at end of file diff --git a/src/Impostor.Server/GameData/SpawnFlags.cs b/src/Impostor.Server/GameData/SpawnFlags.cs new file mode 100644 index 0000000..f91b378 --- /dev/null +++ b/src/Impostor.Server/GameData/SpawnFlags.cs @@ -0,0 +1,11 @@ +using System; + +namespace Impostor.Server.GameData +{ + [Flags] + public enum SpawnFlags : byte + { + None = 0, + IsClientCharacter = 1, + } +} \ No newline at end of file diff --git a/src/Impostor.Server/Impostor.Server.csproj b/src/Impostor.Server/Impostor.Server.csproj index 4bf452f..2f44e1d 100644 --- a/src/Impostor.Server/Impostor.Server.csproj +++ b/src/Impostor.Server/Impostor.Server.csproj @@ -21,16 +21,16 @@ - - - + + + - - - - + + + + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/src/Impostor.Server/Net/Client.cs b/src/Impostor.Server/Net/Client.cs index d82da6e..8293540 100644 --- a/src/Impostor.Server/Net/Client.cs +++ b/src/Impostor.Server/Net/Client.cs @@ -1,11 +1,8 @@ using System; -using System.Runtime.InteropServices; using System.Threading.Tasks; -using Hazel; using Impostor.Server.Data; using Impostor.Server.Games; using Impostor.Server.Games.Managers; -using Impostor.Server.Hazel.Messages; using Impostor.Server.Net.Manager; using Impostor.Server.Net.Messages; using Impostor.Shared.Innersloth; @@ -149,6 +146,8 @@ namespace Impostor.Server.Net // Handle packet. var readerCopy = reader.Slice(reader.Position); + + // TODO: Return value, either a bool (to cancel) or a writer (to cancel (null) or modify/overwrite). await Player.Game.HandleGameData(readerCopy, Player, toPlayer); // Broadcast packet to all other players. diff --git a/src/Impostor.Server/Net/State/Game.Data.cs b/src/Impostor.Server/Net/State/Game.Data.cs new file mode 100644 index 0000000..13bc040 --- /dev/null +++ b/src/Impostor.Server/Net/State/Game.Data.cs @@ -0,0 +1,187 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Impostor.Server.GameData; +using Impostor.Server.GameData.Objects; +using Impostor.Server.Net.Messages; +using Impostor.Shared.Innersloth.GameData; +using Microsoft.Extensions.DependencyInjection; + +namespace Impostor.Server.Net.State +{ + internal partial class Game + { + private static readonly Type[] SpawnableObjects = + { + typeof(InnerShipStatus), // ShipStatus + typeof(InnerMeetingHud), + typeof(InnerLobbyBehaviour), + typeof(InnerGameData), + typeof(InnerPlayerControl), + typeof(InnerShipStatus), // HeadQuarters + typeof(InnerShipStatus), // PlanetMap + typeof(InnerShipStatus), // AprilShipStatus + }; + + private readonly List _allObjects = new List(); + private readonly Dictionary _allObjectsFast = new Dictionary(); + + public async ValueTask HandleGameData(IMessageReader parent, IClientPlayer sender, bool toPlayer) + { + // Find target player. + IClientPlayer target = null; + + if (toPlayer) + { + var targetId = parent.ReadPackedInt32(); + if (!TryGetPlayer(targetId, out target)) + { + // Invalid target. + return; + } + } + + // Parse GameData messages. + while (parent.Position < parent.Length) + { + var reader = parent.ReadMessage(); + + switch (reader.Tag) + { + case GameDataTag.DataFlag: + { + var objectNetId = reader.ReadPackedUInt32(); + Logger.Verbose("> Update {0}", objectNetId); + break; + } + + case GameDataTag.RpcFlag: + { + var objectNetId = reader.ReadPackedUInt32(); + var callId = reader.ReadByte(); + Logger.Verbose("> RPC {0} {1}", objectNetId, callId); + break; + } + + case GameDataTag.SpawnFlag: + { + var objectId = reader.ReadPackedUInt32(); + if (objectId < SpawnableObjects.Length) + { + var innerNetObject = (InnerNetObject) ActivatorUtilities.CreateInstance(_serviceProvider, SpawnableObjects[objectId], this); + var id = reader.ReadPackedInt32(); + + innerNetObject.SpawnFlags = (SpawnFlags) reader.ReadByte(); + + var components = innerNetObject.GetComponentsInChildren(); + var componentsCount = reader.ReadPackedInt32(); + + if (componentsCount != components.Count) + { + Logger.Error( + "Children didn't match for spawnable {0}, name {1} ({2} != {3})", + objectId, + innerNetObject.GetType().Name, + componentsCount, + components.Count); + continue; + } + + for (var i = 0; i < componentsCount; i++) + { + var obj = components[i]; + + obj.NetId = reader.ReadPackedUInt32(); + obj.OwnerId = id; + + if (!AddNetObject(obj)) + { + Logger.Verbose("Failed to AddNetObject."); + + obj.NetId = uint.MaxValue; + break; + } + + var readerSub = reader.ReadMessage(); + if (readerSub.Length > 0) + { + obj.Deserialize(readerSub, true); + } + } + + if ((innerNetObject.SpawnFlags & SpawnFlags.IsClientCharacter) != SpawnFlags.None) + { + if (TryGetPlayer(id, out var clientById)) + { + Logger.Verbose("Spawn character"); + } + else + { + Logger.Verbose("Spawn unowned character"); + } + } + + continue; + } + + Logger.Error("Couldn't find spawnable object {0}.", objectId); + break; + } + + case GameDataTag.DespawnFlag: + { + var objectNetId = reader.ReadPackedUInt32(); + Logger.Verbose("> Destroy {0}", objectNetId); + break; + } + + case GameDataTag.SceneChangeFlag: + { + var clientId = reader.ReadPackedInt32(); + var targetScene = reader.ReadString(); + Logger.Verbose("> Scene {0} to {1}", clientId, targetScene); + break; + } + + case GameDataTag.ReadyFlag: + { + var clientId = reader.ReadPackedInt32(); + Logger.Verbose("> IsReady {0}", clientId); + break; + } + + default: + { + Logger.Debug("Bad GameData tag {0}", reader.Tag); + break; + } + } + } + } + + private bool AddNetObject(InnerNetObject obj) + { + if (_allObjectsFast.ContainsKey(obj.NetId)) + { + return false; + } + + _allObjects.Add(obj); + _allObjectsFast.Add(obj.NetId, obj); + return true; + } + + private void RemoveNetObject(InnerNetObject obj) + { + var index = _allObjects.IndexOf(obj); + if (index > -1) + { + _allObjects.RemoveAt(index); + } + + _allObjectsFast.Remove(obj.NetId); + + obj.NetId = uint.MaxValue; + } + } +} \ No newline at end of file diff --git a/src/Impostor.Server/Net/State/Game.Incoming.cs b/src/Impostor.Server/Net/State/Game.Incoming.cs index 45f820f..f439995 100644 --- a/src/Impostor.Server/Net/State/Game.Incoming.cs +++ b/src/Impostor.Server/Net/State/Game.Incoming.cs @@ -1,5 +1,4 @@ -using System; -using System.Threading.Tasks; +using System.Threading.Tasks; using Impostor.Server.Games; using Impostor.Server.Net.Messages; using Impostor.Shared.Innersloth.Data; @@ -195,80 +194,5 @@ namespace Impostor.Server.Net.State await BroadcastJoinMessage(packet, true, sender); } - - public async ValueTask HandleGameData(IMessageReader parent, IClientPlayer sender, bool toPlayer) - { - // Find target player. - IClientPlayer target = null; - - if (toPlayer) - { - var targetId = parent.ReadPackedInt32(); - if (!TryGetPlayer(targetId, out target)) - { - // Invalid target. - return; - } - } - - // Parse GameData messages. - while (parent.Position < parent.Length) - { - var reader = parent.ReadMessage(); - - switch (reader.Tag) - { - case GameDataTag.DataFlag: - { - var objectNetId = reader.ReadPackedUInt32(); - Logger.Verbose("> Update {0}", objectNetId); - break; - } - - case GameDataTag.RpcFlag: - { - var objectNetId = reader.ReadPackedUInt32(); - var callId = reader.ReadByte(); - Logger.Verbose("> RPC {0} {1}", objectNetId, callId); - break; - } - - case GameDataTag.SpawnFlag: - { - var objectId = reader.ReadPackedUInt32(); - Logger.Verbose("> Spawn {0}", objectId); - break; - } - - case GameDataTag.DespawnFlag: - { - var objectNetId = reader.ReadPackedUInt32(); - Logger.Verbose("> Destroy {0}", objectNetId); - break; - } - - case GameDataTag.SceneChangeFlag: - { - var clientId = reader.ReadPackedInt32(); - var targetScene = reader.ReadString(); - Logger.Verbose("> Scene {0} to {1}", clientId, targetScene); - break; - } - - case GameDataTag.ReadyFlag: - { - var clientId = reader.ReadPackedInt32(); - Logger.Verbose("> IsReady {0}", clientId); - break; - } - - default: - { - Logger.Debug("Bad GameData tag {0}", reader.Tag); - break; - } - } - } - } } } \ No newline at end of file diff --git a/src/Impostor.Server/Net/State/Game.cs b/src/Impostor.Server/Net/State/Game.cs index c20ecdd..ca68fa7 100644 --- a/src/Impostor.Server/Net/State/Game.cs +++ b/src/Impostor.Server/Net/State/Game.cs @@ -1,4 +1,5 @@ -using System.Collections.Concurrent; +using System; +using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Net; @@ -19,6 +20,7 @@ namespace Impostor.Server.Net.State { private static readonly ILogger Logger = Log.ForContext(); + private readonly IServiceProvider _serviceProvider; private readonly IGameManager _gameManager; private readonly IClientManager _clientManager; private readonly IMatchmaker _matchmaker; @@ -26,6 +28,7 @@ namespace Impostor.Server.Net.State private readonly HashSet _bannedIps; public Game( + IServiceProvider serviceProvider, IGameManager gameManager, INodeLocator nodeLocator, IPEndPoint publicIp, @@ -34,6 +37,7 @@ namespace Impostor.Server.Net.State IMatchmaker matchmaker, IClientManager clientManager) { + _serviceProvider = serviceProvider; _gameManager = gameManager; _players = new ConcurrentDictionary(); _bannedIps = new HashSet(); -- 2.39.5