diff --git a/Subsurface/Barotrauma.csproj b/Subsurface/Barotrauma.csproj
index cc27f9265..1d4fa3d64 100644
--- a/Subsurface/Barotrauma.csproj
+++ b/Subsurface/Barotrauma.csproj
@@ -157,7 +157,10 @@
+
+
+
diff --git a/Subsurface/Source/Characters/Character.cs b/Subsurface/Source/Characters/Character.cs
index 7c4f171c3..55e535e02 100644
--- a/Subsurface/Source/Characters/Character.cs
+++ b/Subsurface/Source/Characters/Character.cs
@@ -1911,7 +1911,7 @@ namespace Barotrauma
if (AnimController != null) AnimController.Remove();
}
- public virtual void ClientWrite(NetOutgoingMessage msg)
+ public virtual void ClientWrite(NetBuffer msg)
{
if (GameMain.Server != null) return;
@@ -1972,7 +1972,7 @@ namespace Barotrauma
}
}
- public virtual void ServerWrite(NetOutgoingMessage msg, Client c)
+ public virtual void ServerWrite(NetBuffer msg, Client c)
{
if (GameMain.Server == null) return;
@@ -2037,7 +2037,7 @@ namespace Barotrauma
memPos.Insert(index, posInfo);
}
- public void WriteSpawnData(NetOutgoingMessage msg)
+ public void WriteSpawnData(NetBuffer msg)
{
if (GameMain.Server == null) return;
diff --git a/Subsurface/Source/Items/Components/DockingPort.cs b/Subsurface/Source/Items/Components/DockingPort.cs
index d663b7d81..f1acb40ed 100644
--- a/Subsurface/Source/Items/Components/DockingPort.cs
+++ b/Subsurface/Source/Items/Components/DockingPort.cs
@@ -648,7 +648,7 @@ namespace Barotrauma.Items.Components
}
}
- public override void ServerWrite(Lidgren.Network.NetOutgoingMessage msg, Barotrauma.Networking.Client c)
+ public override void ServerWrite(Lidgren.Network.NetBuffer msg, Barotrauma.Networking.Client c)
{
msg.Write(docked);
diff --git a/Subsurface/Source/Items/Components/Door.cs b/Subsurface/Source/Items/Components/Door.cs
index f2f66c538..a3fe6d03a 100644
--- a/Subsurface/Source/Items/Components/Door.cs
+++ b/Subsurface/Source/Items/Components/Door.cs
@@ -493,7 +493,7 @@ namespace Barotrauma.Items.Components
}
}
- public override void ServerWrite(Lidgren.Network.NetOutgoingMessage msg, Barotrauma.Networking.Client c)
+ public override void ServerWrite(Lidgren.Network.NetBuffer msg, Barotrauma.Networking.Client c)
{
msg.Write(isOpen);
msg.WriteRangedSingle(stuck, 0.0f, 100.0f, 8);
diff --git a/Subsurface/Source/Items/Components/ItemComponent.cs b/Subsurface/Source/Items/Components/ItemComponent.cs
index d052621a3..dd6c9c652 100644
--- a/Subsurface/Source/Items/Components/ItemComponent.cs
+++ b/Subsurface/Source/Items/Components/ItemComponent.cs
@@ -662,10 +662,10 @@ namespace Barotrauma.Items.Components
}
}
- public virtual void ClientWrite(NetOutgoingMessage msg) { }
+ public virtual void ClientWrite(NetBuffer msg) { }
public virtual void ServerRead(NetIncomingMessage msg, Client c) { }
- public virtual void ServerWrite(NetOutgoingMessage msg, Client c) { }
+ public virtual void ServerWrite(NetBuffer msg, Client c) { }
public virtual void ClientRead(NetIncomingMessage msg, float sendingTime) { }
public virtual XElement Save(XElement parentElement)
diff --git a/Subsurface/Source/Items/Components/Machines/Pump.cs b/Subsurface/Source/Items/Components/Machines/Pump.cs
index a9707373f..2ea3985f9 100644
--- a/Subsurface/Source/Items/Components/Machines/Pump.cs
+++ b/Subsurface/Source/Items/Components/Machines/Pump.cs
@@ -196,7 +196,7 @@ namespace Barotrauma.Items.Components
if (!IsActive) currPowerConsumption = 0.0f;
}
- public override void ClientWrite(Lidgren.Network.NetOutgoingMessage msg)
+ public override void ClientWrite(Lidgren.Network.NetBuffer msg)
{
//flowpercentage can only be adjusted at 10% intervals -> no need for more accuracy than this
msg.WriteRangedInteger(-10, 10, (int)(flowPercentage / 10.0f));
@@ -209,7 +209,7 @@ namespace Barotrauma.Items.Components
IsActive = msg.ReadBoolean();
}
- public override void ServerWrite(Lidgren.Network.NetOutgoingMessage msg, Barotrauma.Networking.Client c)
+ public override void ServerWrite(Lidgren.Network.NetBuffer msg, Barotrauma.Networking.Client c)
{
//flowpercentage can only be adjusted at 10% intervals -> no need for more accuracy than this
msg.WriteRangedInteger(-10, 10, (int)(flowPercentage / 10.0f));
diff --git a/Subsurface/Source/Items/Components/Machines/Radar.cs b/Subsurface/Source/Items/Components/Machines/Radar.cs
index 82702c46a..97e5a136e 100644
--- a/Subsurface/Source/Items/Components/Machines/Radar.cs
+++ b/Subsurface/Source/Items/Components/Machines/Radar.cs
@@ -411,7 +411,7 @@ namespace Barotrauma.Items.Components
if (screenOverlay != null) screenOverlay.Remove();
}
- public override void ClientWrite(Lidgren.Network.NetOutgoingMessage msg)
+ public override void ClientWrite(Lidgren.Network.NetBuffer msg)
{
msg.Write(IsActive);
}
@@ -422,7 +422,7 @@ namespace Barotrauma.Items.Components
isActiveTickBox.Selected = IsActive;
}
- public override void ServerWrite(Lidgren.Network.NetOutgoingMessage msg, Barotrauma.Networking.Client c)
+ public override void ServerWrite(Lidgren.Network.NetBuffer msg, Barotrauma.Networking.Client c)
{
msg.Write(IsActive);
}
diff --git a/Subsurface/Source/Items/Components/Machines/Reactor.cs b/Subsurface/Source/Items/Components/Machines/Reactor.cs
index 5664ec018..6915abf0b 100644
--- a/Subsurface/Source/Items/Components/Machines/Reactor.cs
+++ b/Subsurface/Source/Items/Components/Machines/Reactor.cs
@@ -538,7 +538,7 @@ namespace Barotrauma.Items.Components
}
}
- public override void ClientWrite(NetOutgoingMessage msg)
+ public override void ClientWrite(NetBuffer msg)
{
msg.Write(autoTemp);
msg.WriteRangedSingle(shutDownTemp, 0.0f, 10000.0f, 8);
@@ -556,7 +556,7 @@ namespace Barotrauma.Items.Components
FissionRate = msg.ReadRangedSingle(0.0f, 100.0f, 8);
}
- public override void ServerWrite(NetOutgoingMessage msg, Client c)
+ public override void ServerWrite(NetBuffer msg, Client c)
{
msg.WriteRangedSingle(temperature, 0.0f, 10000.0f, 16);
diff --git a/Subsurface/Source/Items/Components/Machines/Steering.cs b/Subsurface/Source/Items/Components/Machines/Steering.cs
index d4b564723..417d14718 100644
--- a/Subsurface/Source/Items/Components/Machines/Steering.cs
+++ b/Subsurface/Source/Items/Components/Machines/Steering.cs
@@ -443,7 +443,7 @@ namespace Barotrauma.Items.Components
}
}
- public override void ClientWrite(Lidgren.Network.NetOutgoingMessage msg)
+ public override void ClientWrite(Lidgren.Network.NetBuffer msg)
{
msg.Write(autoPilot);
@@ -503,7 +503,7 @@ namespace Barotrauma.Items.Components
}
}
- public override void ServerWrite(Lidgren.Network.NetOutgoingMessage msg, Barotrauma.Networking.Client c)
+ public override void ServerWrite(Lidgren.Network.NetBuffer msg, Barotrauma.Networking.Client c)
{
msg.Write(autoPilot);
diff --git a/Subsurface/Source/Items/Components/Power/PowerContainer.cs b/Subsurface/Source/Items/Components/Power/PowerContainer.cs
index d6f9633f1..1d10c4ca1 100644
--- a/Subsurface/Source/Items/Components/Power/PowerContainer.cs
+++ b/Subsurface/Source/Items/Components/Power/PowerContainer.cs
@@ -249,7 +249,7 @@ namespace Barotrauma.Items.Components
GuiFrame.Update(1.0f / 60.0f);
}
- public override void ClientWrite(Lidgren.Network.NetOutgoingMessage msg)
+ public override void ClientWrite(Lidgren.Network.NetBuffer msg)
{
float chargeSpeed = MathHelper.Clamp(rechargeSpeed / MaxRechargeSpeed, 0.0f, 1.0f);
msg.WriteRangedSingle(chargeSpeed, 0.0f, 1.0f, 8);
@@ -260,7 +260,7 @@ namespace Barotrauma.Items.Components
RechargeSpeed = msg.ReadRangedSingle(0.0f, 1.0f, 8) * maxRechargeSpeed;
}
- public override void ServerWrite(Lidgren.Network.NetOutgoingMessage msg, Barotrauma.Networking.Client c)
+ public override void ServerWrite(Lidgren.Network.NetBuffer msg, Barotrauma.Networking.Client c)
{
float chargeSpeed = MathHelper.Clamp(rechargeSpeed / MaxRechargeSpeed, 0.0f, 1.0f);
msg.WriteRangedSingle(chargeSpeed, 0.0f, 1.0f, 8);
diff --git a/Subsurface/Source/Items/Components/Signal/Wire.cs b/Subsurface/Source/Items/Components/Signal/Wire.cs
index 0240050dc..c511abcde 100644
--- a/Subsurface/Source/Items/Components/Signal/Wire.cs
+++ b/Subsurface/Source/Items/Components/Signal/Wire.cs
@@ -532,7 +532,7 @@ namespace Barotrauma.Items.Components
base.RemoveComponentSpecific();
}
- public override void ClientWrite(Lidgren.Network.NetOutgoingMessage msg)
+ public override void ClientWrite(Lidgren.Network.NetBuffer msg)
{
msg.Write((byte)Math.Min(Nodes.Count, 255));
for (int i = 0; i < Math.Min(Nodes.Count, 255); i++)
diff --git a/Subsurface/Source/Items/Item.cs b/Subsurface/Source/Items/Item.cs
index d1f52bcdf..b1d66f3bf 100644
--- a/Subsurface/Source/Items/Item.cs
+++ b/Subsurface/Source/Items/Item.cs
@@ -1579,11 +1579,11 @@ namespace Barotrauma
return element;
}
-
- public void ServerWrite(NetOutgoingMessage msg, Client c) { }
+
+ public void ServerWrite(NetBuffer msg, Client c) { }
public void ClientRead(NetIncomingMessage msg, float sendingTime) { }
- public void WriteSpawnData(NetOutgoingMessage msg)
+ public void WriteSpawnData(NetBuffer msg)
{
if (GameMain.Server == null) return;
diff --git a/Subsurface/Source/Map/Structure.cs b/Subsurface/Source/Map/Structure.cs
index 067902cf9..a33b131e8 100644
--- a/Subsurface/Source/Map/Structure.cs
+++ b/Subsurface/Source/Map/Structure.cs
@@ -845,7 +845,7 @@ namespace Barotrauma
return newBody;
}
- public void ServerWrite(NetOutgoingMessage msg, Client c)
+ public void ServerWrite(NetBuffer msg, Client c)
{
for (int i = 0; i < sections.Length; i++)
{
diff --git a/Subsurface/Source/Map/Submarine.cs b/Subsurface/Source/Map/Submarine.cs
index 8f08fbb4f..a5e1e56d9 100644
--- a/Subsurface/Source/Map/Submarine.cs
+++ b/Subsurface/Source/Map/Submarine.cs
@@ -1163,7 +1163,7 @@ namespace Barotrauma
DockedTo.Clear();
}
- public void ServerWrite(NetOutgoingMessage msg, Client c)
+ public void ServerWrite(NetBuffer msg, Client c)
{
msg.Write(ID);
//length in bytes
diff --git a/Subsurface/Source/Networking/Client.cs b/Subsurface/Source/Networking/Client.cs
index 754158eb9..6f7e75df3 100644
--- a/Subsurface/Source/Networking/Client.cs
+++ b/Subsurface/Source/Networking/Client.cs
@@ -35,6 +35,7 @@ namespace Barotrauma.Networking
public bool hasLobbyData = false;
public UInt32 lastSentChatMsgID = 0; //last msg this client said
public UInt32 lastRecvChatMsgID = 0; //last msg this client knows about
+ public UInt32 lastRecvEntityEventID = 0;
public UInt32 lastRecvEntitySpawnID = 0;
diff --git a/Subsurface/Source/Networking/EntitySpawner.cs b/Subsurface/Source/Networking/EntitySpawner.cs
index 7b7755241..f7224bd76 100644
--- a/Subsurface/Source/Networking/EntitySpawner.cs
+++ b/Subsurface/Source/Networking/EntitySpawner.cs
@@ -152,7 +152,7 @@ namespace Barotrauma
NetStateID = (UInt32)spawnHistory.Count;
}
- public void ServerWrite(Lidgren.Network.NetOutgoingMessage message, Client client)
+ public void ServerWrite(Lidgren.Network.NetBuffer message, Client client)
{
if (GameMain.Server == null) return;
diff --git a/Subsurface/Source/Networking/GameClient.cs b/Subsurface/Source/Networking/GameClient.cs
index 635af34e6..764f66131 100644
--- a/Subsurface/Source/Networking/GameClient.cs
+++ b/Subsurface/Source/Networking/GameClient.cs
@@ -39,6 +39,8 @@ namespace Barotrauma.Networking
private UInt32 lastQueueChatMsgID = 0; //last message added to the queue
private List chatMsgQueue = new List();
+ public UInt32 LastSentEntityEventID;
+
public byte ID
{
get { return myID; }
diff --git a/Subsurface/Source/Networking/INetSerializable.cs b/Subsurface/Source/Networking/INetSerializable.cs
index 0d51ca02b..75db0fc8a 100644
--- a/Subsurface/Source/Networking/INetSerializable.cs
+++ b/Subsurface/Source/Networking/INetSerializable.cs
@@ -3,25 +3,27 @@ using Lidgren.Network;
namespace Barotrauma.Networking
{
+ interface INetSerializable { }
+
///
/// Interface for entities that the clients can send information of to the server
///
- interface IClientSerializable
+ interface IClientSerializable : INetSerializable
{
UInt32 NetStateID { get; }
- void ClientWrite(NetOutgoingMessage msg);
+ void ClientWrite(NetBuffer msg);
void ServerRead(NetIncomingMessage msg, Client c);
}
///
/// Interface for entities that the server can send information of to the clients
///
- interface IServerSerializable
+ interface IServerSerializable : INetSerializable
{
UInt32 NetStateID { get; }
- void ServerWrite(NetOutgoingMessage msg, Client c);
+ void ServerWrite(NetBuffer msg, Client c);
void ClientRead(NetIncomingMessage msg, float sendingTime);
}
}
diff --git a/Subsurface/Source/Networking/NetEntityEvent/ClientEntityEventManager.cs b/Subsurface/Source/Networking/NetEntityEvent/ClientEntityEventManager.cs
new file mode 100644
index 000000000..c7dcfddf1
--- /dev/null
+++ b/Subsurface/Source/Networking/NetEntityEvent/ClientEntityEventManager.cs
@@ -0,0 +1,56 @@
+using Lidgren.Network;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Barotrauma.Networking
+{
+ class ClientEntityEventManager : NetEntityEventManager
+ {
+ private List events;
+
+ private UInt32 ID;
+
+ private GameClient thisClient;
+
+ public ClientEntityEventManager(GameClient client) { }
+
+ public void CreateEvent(IClientSerializable entity)
+ {
+ if (!(entity is Entity))
+ {
+ DebugConsole.ThrowError("Can't create an entity event for " + entity + "!");
+ return;
+ }
+
+ ID++;
+ events.Add(new ClientEntityEvent(entity, ID));
+ }
+
+ public void Write(NetOutgoingMessage msg)
+ {
+ var eventsToSync = events.SkipWhile(e => e.ID >= thisClient.LastSentEntityEventID).ToList();
+ if (eventsToSync.Count == 0) return;
+
+ Write(msg, eventsToSync.Cast().ToList());
+ }
+
+ protected override void WriteEvent(NetBuffer buffer, NetEntityEvent entityEvent, Client recipient = null)
+ {
+ var clientEvent = entityEvent as ClientEntityEvent;
+ if (clientEvent == null) return;
+
+ clientEvent.Write(buffer);
+ }
+
+ protected override void ReadEvent(NetIncomingMessage buffer, INetSerializable entity, float sendingTime, Client sender = null)
+ {
+ var clientEntity = entity as IClientSerializable;
+ if (clientEntity == null) return;
+
+ clientEntity.ServerRead(buffer, sender);
+ }
+ }
+}
diff --git a/Subsurface/Source/Networking/NetEntityEvent/NetEntityEvent.cs b/Subsurface/Source/Networking/NetEntityEvent/NetEntityEvent.cs
new file mode 100644
index 000000000..3d0626a8b
--- /dev/null
+++ b/Subsurface/Source/Networking/NetEntityEvent/NetEntityEvent.cs
@@ -0,0 +1,54 @@
+using Lidgren.Network;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Barotrauma.Networking
+{
+ abstract class NetEntityEvent
+ {
+ public readonly Entity Entity;
+ public readonly UInt32 ID;
+
+ protected NetEntityEvent(INetSerializable entity, UInt32 id)
+ {
+ this.ID = id;
+ this.Entity = entity as Entity;
+ }
+ }
+
+ class ServerEntityEvent : NetEntityEvent
+ {
+ private IServerSerializable serializable;
+
+ public ServerEntityEvent(IServerSerializable entity, UInt32 id)
+ : base(entity, id)
+ {
+ serializable = entity;
+ }
+
+ public void Write(NetBuffer msg, Client recipient)
+ {
+ serializable.ServerWrite(msg, recipient);
+ }
+ }
+
+ class ClientEntityEvent : NetEntityEvent
+ {
+ private IClientSerializable serializable;
+
+ public ClientEntityEvent(IClientSerializable entity, UInt32 id)
+ : base(entity, id)
+ {
+ serializable = entity;
+ }
+
+ public void Write(NetBuffer msg)
+ {
+ serializable.ClientWrite(msg);
+ }
+ }
+
+}
diff --git a/Subsurface/Source/Networking/NetEntityEvent/NetEntityEventManager.cs b/Subsurface/Source/Networking/NetEntityEvent/NetEntityEventManager.cs
new file mode 100644
index 000000000..761cf8349
--- /dev/null
+++ b/Subsurface/Source/Networking/NetEntityEvent/NetEntityEventManager.cs
@@ -0,0 +1,89 @@
+using Lidgren.Network;
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Barotrauma.Networking
+{
+ abstract class NetEntityEventManager
+ {
+ const int MaxEventsPerWrite = 255;
+
+ private UInt32 lastReceivedEntityEventID;
+
+ ///
+ /// Write the events to the outgoing message. The recipient parameter is only needed for ServerEntityEventManager
+ ///
+ protected void Write(NetOutgoingMessage msg, List eventsToSync, Client recipient = null)
+ {
+ //too many events for one packet
+ if (eventsToSync.Count > MaxEventsPerWrite)
+ {
+ eventsToSync.RemoveRange(MaxEventsPerWrite, eventsToSync.Count - MaxEventsPerWrite);
+ }
+
+ msg.Write((byte)ServerNetObject.ENTITY_STATE);
+
+ msg.Write(eventsToSync[0].ID);
+ msg.Write((byte)eventsToSync.Count);
+
+ foreach (NetEntityEvent e in eventsToSync)
+ {
+ //write into a temporary buffer so we can write the length before the actual data
+ NetBuffer tempBuffer = new NetBuffer();
+ WriteEvent(tempBuffer, e, recipient);
+ tempBuffer.WritePadBits();
+
+ Debug.Assert(
+ tempBuffer.LengthBytes < 256,
+ "Maximum EntityEvent size exceeded when serializing \""+e.Entity+"\"!");
+
+ msg.Write((UInt16)e.Entity.ID);
+ msg.Write((byte)tempBuffer.LengthBytes);
+ msg.Write(tempBuffer);
+ }
+ }
+
+ ///
+ /// Read the events from the message, ignoring ones we've already received
+ ///
+ public void Read(NetIncomingMessage msg, float sendingTime)
+ {
+ UInt32 firstEventID = msg.ReadUInt32();
+ byte eventCount = msg.ReadByte();
+
+ for (int i = 0; i < eventCount; i++)
+ {
+ UInt32 thisEventID = firstEventID + (UInt32)i;
+ UInt16 entityID = msg.ReadUInt16();
+ byte msgLength = msg.ReadByte();
+
+ INetSerializable entity = Entity.FindEntityByID(entityID) as INetSerializable;
+
+ //skip the event if we've already received it or if the entity isn't found
+ if (thisEventID <= lastReceivedEntityEventID || entity == null)
+ {
+ msg.Position += msgLength * 8;
+ }
+ else
+ {
+ ReadEvent(msg, entity, sendingTime);
+ lastReceivedEntityEventID = thisEventID;
+ }
+ }
+ }
+
+ protected virtual void WriteEvent(NetBuffer buffer, NetEntityEvent entityEvent, Client recipient = null)
+ {
+ throw new NotImplementedException();
+ }
+
+ protected virtual void ReadEvent(NetIncomingMessage buffer, INetSerializable entity, float sendingTime, Client sender = null)
+ {
+ throw new NotImplementedException();
+ }
+ }
+}
diff --git a/Subsurface/Source/Networking/NetEntityEvent/ServerEntityEventManager.cs b/Subsurface/Source/Networking/NetEntityEvent/ServerEntityEventManager.cs
new file mode 100644
index 000000000..cb3fda394
--- /dev/null
+++ b/Subsurface/Source/Networking/NetEntityEvent/ServerEntityEventManager.cs
@@ -0,0 +1,57 @@
+using Lidgren.Network;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Barotrauma.Networking
+{
+ class ServerEntityEventManager : NetEntityEventManager
+ {
+ private List events;
+
+ private UInt32 ID;
+
+ public ServerEntityEventManager(GameServer server) { }
+
+ public void CreateEvent(IServerSerializable entity)
+ {
+ if (!(entity is Entity))
+ {
+ DebugConsole.ThrowError("Can't create an entity event for " + entity + "!");
+ return;
+ }
+
+ ID++;
+ events.Add(new ServerEntityEvent(entity, ID));
+ }
+
+ ///
+ /// Writes all the events that the client hasn't received yet into the outgoing message
+ ///
+ public void Write(Client client, NetOutgoingMessage msg)
+ {
+ var eventsToSync = events.SkipWhile(e => e.ID >= client.lastRecvEntityEventID).ToList();
+ if (eventsToSync.Count == 0) return;
+
+ Write(msg, eventsToSync.Cast().ToList(), client);
+ }
+
+ protected override void WriteEvent(NetBuffer buffer, NetEntityEvent entityEvent, Client recipient = null)
+ {
+ var serverEvent = entityEvent as ServerEntityEvent;
+ if (serverEvent == null) return;
+
+ serverEvent.Write(buffer, recipient);
+ }
+
+ protected override void ReadEvent(NetIncomingMessage buffer, INetSerializable entity, float sendingTime, Client sender = null)
+ {
+ var clientEntity = entity as IClientSerializable;
+ if (clientEntity == null) return;
+
+ clientEntity.ServerRead(buffer, sender);
+ }
+ }
+}
diff --git a/Subsurface/Source/Networking/NetworkMember.cs b/Subsurface/Source/Networking/NetworkMember.cs
index eb37a276b..92a7c5e1a 100644
--- a/Subsurface/Source/Networking/NetworkMember.cs
+++ b/Subsurface/Source/Networking/NetworkMember.cs
@@ -45,7 +45,7 @@ namespace Barotrauma.Networking
CHAT_MESSAGE,
VOTE,
ENTITY_POSITION,
- ITEM_STATE,
+ ENTITY_STATE,
ENTITY_SPAWN
}