Changed ItemSpawner to EntitySpawner, used for syncing both item and character spawning

This commit is contained in:
Regalis
2016-10-12 19:25:01 +03:00
parent ac3539da63
commit 60b36e020c
12 changed files with 227 additions and 181 deletions

View File

@@ -36,7 +36,7 @@ namespace Barotrauma.Networking
public UInt32 lastSentChatMsgID = 0; //last msg this client said
public UInt32 lastRecvChatMsgID = 0; //last msg this client knows about
public UInt32 lastRecvItemSpawnID = 0;
public UInt32 lastRecvEntitySpawnID = 0;
public UInt32 lastRecvItemRemoveID = 0;
@@ -63,7 +63,7 @@ namespace Barotrauma.Networking
lastSentChatMsgID = 0;
lastRecvChatMsgID = ChatMessage.LastID;
lastRecvItemSpawnID = 0;
lastRecvEntitySpawnID = 0;
lastRecvItemRemoveID = 0;
}

View File

@@ -0,0 +1,269 @@
using Microsoft.Xna.Framework;
using System.Collections.Generic;
using System.Linq;
using Barotrauma.Networking;
using System;
namespace Barotrauma
{
class EntitySpawner : IServerSerializable
{
private enum SpawnableType { Item, Character };
public UInt32 NetStateID
{
get;
private set;
}
interface IEntitySpawnInfo
{
Entity Spawn();
}
class ItemSpawnInfo : IEntitySpawnInfo
{
public readonly ItemPrefab Prefab;
public readonly Vector2 Position;
public readonly Inventory Inventory;
public readonly Submarine Submarine;
public ItemSpawnInfo(ItemPrefab prefab, Vector2 worldPosition)
{
Prefab = prefab;
Position = worldPosition;
}
public ItemSpawnInfo(ItemPrefab prefab, Vector2 position, Submarine sub)
{
Prefab = prefab;
Position = position;
Submarine = sub;
}
public ItemSpawnInfo(ItemPrefab prefab, Inventory inventory)
{
Prefab = prefab;
Inventory = inventory;
}
public Entity Spawn()
{
Item spawnedItem = null;
if (Inventory != null)
{
spawnedItem = new Item(Prefab, Vector2.Zero, null);
Inventory.TryPutItem(spawnedItem, spawnedItem.AllowedSlots);
}
else
{
spawnedItem = new Item(Prefab, Position, Submarine);
}
return spawnedItem;
}
}
private readonly Queue<IEntitySpawnInfo> spawnQueue;
private List<Entity> spawnedEntities = new List<Entity>();
public EntitySpawner()
{
spawnQueue = new Queue<IEntitySpawnInfo>();
}
public void QueueItem(ItemPrefab itemPrefab, Vector2 worldPosition, bool isNetworkMessage = false)
{
//clients aren't allowed to spawn new items unless the server says so
if (!isNetworkMessage && GameMain.Client != null) return;
spawnQueue.Enqueue(new ItemSpawnInfo(itemPrefab, worldPosition));
}
public void QueueItem(ItemPrefab itemPrefab, Vector2 position, Submarine sub, bool isNetworkMessage = false)
{
//clients aren't allowed to spawn new items unless the server says so
if (!isNetworkMessage && GameMain.Client != null) return;
spawnQueue.Enqueue(new ItemSpawnInfo(itemPrefab, position, sub));
}
public void QueueItem(ItemPrefab itemPrefab, Inventory inventory, bool isNetworkMessage = false)
{
//clients aren't allowed to spawn new items unless the server says so
if (!isNetworkMessage && GameMain.Client != null) return;
spawnQueue.Enqueue(new ItemSpawnInfo(itemPrefab, inventory));
}
public void Update()
{
if (!spawnQueue.Any()) return;
//List<Inventory> inventories = new List<Inventory>();
while (spawnQueue.Count>0)
{
var entitySpawnInfo = spawnQueue.Dequeue();
var spawnedEntity = entitySpawnInfo.Spawn();
if (spawnedEntity!= null) AddToSpawnedList(spawnedEntity);
}
//if (GameMain.Server != null) GameMain.Server.SendItemSpawnMessage(items);
}
public void AddToSpawnedList(Entity entity)
{
if (GameMain.Server == null) return;
if (entity == null) return;
spawnedEntities.Add(entity);
NetStateID = (UInt32)spawnedEntities.Count;
}
public void ServerWrite(Lidgren.Network.NetOutgoingMessage message, Client client)
{
if (GameMain.Server == null) return;
//skip items that the client already knows about
List<Entity> entities = spawnedEntities.Skip((int)client.lastRecvEntitySpawnID).ToList();
message.Write((UInt32)spawnedEntities.Count);
message.Write((byte)entities.Count);
for (int i = 0; i < entities.Count; i++)
{
if (entities[i] is Item)
{
message.Write((byte)SpawnableType.Item);
((Item)entities[i]).WriteSpawnData(message);
}
else if (entities[i] is Character)
{
message.Write((byte)SpawnableType.Character);
((Character)entities[i]).WriteSpawnData(message);
}
}
}
public void ClientRead(Lidgren.Network.NetIncomingMessage message)
{
if (GameMain.Server != null) return;
UInt32 ID = message.ReadUInt32();
var entityCount = message.ReadByte();
for (int i = 0; i < entityCount; i++)
{
switch (message.ReadByte())
{
case (byte)SpawnableType.Item:
Item.ReadSpawnData(message, ID - entityCount + i >= NetStateID);
break;
case (byte)SpawnableType.Character:
Character.ReadSpawnData(message, ID - entityCount + i >= NetStateID);
break;
default:
DebugConsole.ThrowError("Received invalid entity spawn message (unknown spawnable type)");
break;
}
}
NetStateID = Math.Max(ID, NetStateID);
}
public void Clear()
{
NetStateID = 0;
spawnQueue.Clear();
spawnedEntities.Clear();
}
}
//todo: turn into a generic EntityRemover class + sync
class ItemRemover : IServerSerializable
{
public UInt32 NetStateID
{
get;
private set;
}
private readonly Queue<Item> removeQueue;
public List<Item> removedItems = new List<Item>();
public ItemRemover()
{
removeQueue = new Queue<Item>();
}
public void QueueItem(Item item, bool isNetworkMessage = false)
{
if (!isNetworkMessage && GameMain.Client != null)
{
//clients aren't allowed to remove items unless the server says so
return;
}
removeQueue.Enqueue(item);
}
public void Update()
{
if (!removeQueue.Any()) return;
List<Item> items = new List<Item>();
while (removeQueue.Count > 0)
{
var item = removeQueue.Dequeue();
removedItems.Add(item);
item.Remove();
items.Add(item);
}
//if (GameMain.Server != null) GameMain.Server.SendItemRemoveMessage(items);
}
public void ServerWrite(Lidgren.Network.NetOutgoingMessage message, Client client)
{
//message.Write((byte)items.Count);
//foreach (Item item in items)
//{
// message.Write(item.ID);
//}
}
public void ClientRead(Lidgren.Network.NetIncomingMessage message)
{
var itemCount = message.ReadByte();
for (int i = 0; i<itemCount; i++)
{
ushort itemId = message.ReadUInt16();
var item = MapEntity.FindEntityByID(itemId) as Item;
if (item == null) continue;
item.Remove();
}
}
public void Clear()
{
NetStateID = 0;
removeQueue.Clear();
removedItems.Clear();
}
}
}

View File

@@ -44,6 +44,13 @@ namespace Barotrauma.Networking
get { return myID; }
}
public ushort MyCharacterID
{
get;
private set;
}
public override List<Client> ConnectedClients
{
get
@@ -570,6 +577,8 @@ namespace Barotrauma.Networking
bool respawnAllowed = inc.ReadBoolean();
bool loadSecondSub = inc.ReadBoolean();
MyCharacterID = inc.ReadUInt16();
GameModePreset gameMode = GameModePreset.list.Find(gm => gm.Name == modeName);
if (gameMode == null)
@@ -595,16 +604,16 @@ namespace Barotrauma.Networking
if (respawnAllowed) respawnManager = new RespawnManager(this, GameMain.NetLobbyScreen.SelectedShuttle);
int characterCount = inc.ReadByte();
for (int i = 0; i < characterCount; i++)
{
var character = Character.ReadSpawnData(inc);
if (inc.ReadBoolean())
{
myCharacter = character;
Character.Controlled = character;
}
}
//int characterCount = inc.ReadByte();
//for (int i = 0; i < characterCount; i++)
//{
// var character = Character.ReadSpawnData(inc);
// if (inc.ReadBoolean())
// {
// myCharacter = character;
// Character.Controlled = character;
// }
//}
gameStarted = true;
@@ -704,7 +713,7 @@ namespace Barotrauma.Networking
case ServerNetObject.CHAT_MESSAGE:
ChatMessage.ClientRead(inc);
break;
case ServerNetObject.ITEM_SPAWN:
case ServerNetObject.ENTITY_SPAWN:
Item.Spawner.ClientRead(inc);
break;
}

View File

@@ -601,7 +601,7 @@ namespace Barotrauma.Networking
c.lastRecvGeneralUpdate = Math.Max(c.lastRecvGeneralUpdate, inc.ReadUInt32());
c.lastRecvChatMsgID = Math.Max(c.lastRecvChatMsgID, inc.ReadUInt32());
c.lastRecvItemSpawnID = Math.Max(c.lastRecvItemSpawnID, inc.ReadUInt32());
c.lastRecvEntitySpawnID = Math.Max(c.lastRecvEntitySpawnID, inc.ReadUInt32());
break;
case ClientNetObject.CHAT_MESSAGE:
@@ -656,9 +656,9 @@ namespace Barotrauma.Networking
outmsg.WritePadBits();
}
if (Item.Spawner.NetStateID > c.lastRecvItemSpawnID)
if (Item.Spawner.NetStateID > c.lastRecvEntitySpawnID)
{
outmsg.Write((byte)ServerNetObject.ITEM_SPAWN);
outmsg.Write((byte)ServerNetObject.ENTITY_SPAWN);
Item.Spawner.ServerWrite(outmsg, c);
outmsg.WritePadBits();
}
@@ -893,7 +893,9 @@ namespace Barotrauma.Networking
foreach (Character c in GameMain.GameSession.CrewManager.characters)
{
Item.Spawner.AddToSpawnedList(c.SpawnItems);
Entity.Spawner.AddToSpawnedList(c);
c.SpawnItems.ForEach(item => Entity.Spawner.AddToSpawnedList(item));
}
SendStartMessage(roundStartSeed, Submarine.MainSub, GameMain.GameSession.gameMode.Preset, connectedClients);
@@ -947,23 +949,7 @@ namespace Barotrauma.Networking
msg.Write(AllowRespawn);
msg.Write(Submarine.MainSubs[1] != null); //loadSecondSub
var clientsWithCharacter = clients.FindAll(c => c.Character != null);
int characterCount = clientsWithCharacter.Count;
if (myCharacter != null) characterCount++;
msg.Write((byte)characterCount);
foreach (Client c in clientsWithCharacter)
{
c.Character.WriteSpawnData(msg);
msg.Write(c == client);
}
if (myCharacter != null)
{
myCharacter.WriteSpawnData(msg);
msg.Write(false);
}
msg.Write(client.Character.ID);
server.SendMessage(msg, client.Connection, NetDeliveryMethod.ReliableUnordered);
}

View File

@@ -47,7 +47,7 @@ namespace Barotrauma.Networking
CHARACTER_POSITION,
ITEM_STATE,
ITEM_SPAWN
ENTITY_SPAWN
}
enum VoteType