]> git.deb.at Git - rhonda/impostor.git/commitdiff
Added GameData spawn
authorAeonLucid <aeonlucid@gmail.com>
Fri, 16 Oct 2020 03:00:49 +0000 (05:00 +0200)
committerAeonLucid <aeonlucid@gmail.com>
Sun, 18 Oct 2020 19:17:41 +0000 (21:17 +0200)
16 files changed:
src/Impostor.Server/GameData/GameObject.cs [new file with mode: 0644]
src/Impostor.Server/GameData/InnerNetObject.cs [new file with mode: 0644]
src/Impostor.Server/GameData/Objects/Components/InnerCustomNetworkTransform.cs [new file with mode: 0644]
src/Impostor.Server/GameData/Objects/Components/InnerPlayerPhysics.cs [new file with mode: 0644]
src/Impostor.Server/GameData/Objects/Components/InnerVoteBanSystem.cs [new file with mode: 0644]
src/Impostor.Server/GameData/Objects/InnerGameData.cs [new file with mode: 0644]
src/Impostor.Server/GameData/Objects/InnerLobbyBehaviour.cs [new file with mode: 0644]
src/Impostor.Server/GameData/Objects/InnerMeetingHud.cs [new file with mode: 0644]
src/Impostor.Server/GameData/Objects/InnerPlayerControl.cs [new file with mode: 0644]
src/Impostor.Server/GameData/Objects/InnerShipStatus.cs [new file with mode: 0644]
src/Impostor.Server/GameData/SpawnFlags.cs [new file with mode: 0644]
src/Impostor.Server/Impostor.Server.csproj
src/Impostor.Server/Net/Client.cs
src/Impostor.Server/Net/State/Game.Data.cs [new file with mode: 0644]
src/Impostor.Server/Net/State/Game.Incoming.cs
src/Impostor.Server/Net/State/Game.cs

diff --git a/src/Impostor.Server/GameData/GameObject.cs b/src/Impostor.Server/GameData/GameObject.cs
new file mode 100644 (file)
index 0000000..c78dee0
--- /dev/null
@@ -0,0 +1,29 @@
+using System.Collections.Generic;
+
+namespace Impostor.Server.GameData
+{
+    public class GameObject
+    {
+        public GameObject()
+        {
+            Components = new List<object>();
+        }
+
+        protected List<object> Components { get; }
+
+        public List<T> GetComponentsInChildren<T>()
+        {
+            var result = new List<T>();
+
+            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 (file)
index 0000000..6f153ed
--- /dev/null
@@ -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 (file)
index 0000000..1591903
--- /dev/null
@@ -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 (file)
index 0000000..edc01e0
--- /dev/null
@@ -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 (file)
index 0000000..c63cd09
--- /dev/null
@@ -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 (file)
index 0000000..a25202c
--- /dev/null
@@ -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 (file)
index 0000000..d2533fa
--- /dev/null
@@ -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 (file)
index 0000000..12c1054
--- /dev/null
@@ -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 (file)
index 0000000..049b2be
--- /dev/null
@@ -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 (file)
index 0000000..8662983
--- /dev/null
@@ -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 (file)
index 0000000..f91b378
--- /dev/null
@@ -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
index 4bf452f89103e0cdc140e392827f7e4bd1065428..2f44e1d5de7ec5003d6a94fbb4e79df7413ace16 100644 (file)
     </PropertyGroup>
 
     <ItemGroup>
-        <ProjectReference Include="..\Impostor.Server.Api\Impostor.Server.Api.csproj"/>
-        <ProjectReference Include="..\Impostor.Server.Hazel\Impostor.Server.Hazel.csproj"/>
-        <ProjectReference Include="..\Impostor.Shared\Impostor.Shared.csproj"/>
+        <ProjectReference Include="..\Impostor.Server.Api\Impostor.Server.Api.csproj" />
+        <ProjectReference Include="..\Impostor.Server.Hazel\Impostor.Server.Hazel.csproj" />
+        <ProjectReference Include="..\Impostor.Shared\Impostor.Shared.csproj" />
     </ItemGroup>
 
     <ItemGroup>
-        <PackageReference Include="Microsoft.Extensions.Caching.StackExchangeRedis" Version="5.0.0-rc.1.20451.7"/>
-        <PackageReference Include="Microsoft.Extensions.Hosting" Version="5.0.0-rc.1.20451.14"/>
-        <PackageReference Include="Serilog.Extensions.Hosting" Version="3.1.0"/>
-        <PackageReference Include="Serilog.Sinks.Console" Version="3.1.1"/>
+        <PackageReference Include="Microsoft.Extensions.Caching.StackExchangeRedis" Version="5.0.0-rc.1.20451.7" />
+        <PackageReference Include="Microsoft.Extensions.Hosting" Version="5.0.0-rc.1.20451.14" />
+        <PackageReference Include="Serilog.Extensions.Hosting" Version="3.1.0" />
+        <PackageReference Include="Serilog.Sinks.Console" Version="3.1.1" />
         <PackageReference Include="StyleCop.Analyzers" Version="1.1.118">
             <PrivateAssets>all</PrivateAssets>
             <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
index d82da6ecf84517b079712bdfde759564c9d786b0..8293540c4755e481a06f00998dc863982bcd4c7e 100644 (file)
@@ -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 (file)
index 0000000..13bc040
--- /dev/null
@@ -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<InnerNetObject> _allObjects = new List<InnerNetObject>();
+        private readonly Dictionary<uint, InnerNetObject> _allObjectsFast = new Dictionary<uint, InnerNetObject>();
+
+        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<InnerNetObject>();
+                            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
index 45f820f68fb909c235a12ece7d0c3c2ab7fbc325..f4399956181d540d1e2ca9edd242cc41fb8cf8a6 100644 (file)
@@ -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
index c20ecdde29012b57adcb0af0da07af6f6b816fa2..ca68fa7d0cec142766d7919dbdfbb90cd7fea1d7 100644 (file)
@@ -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<Game>();
 
+        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<IPAddress> _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<int, IClientPlayer>();
             _bannedIps = new HashSet<IPAddress>();