private void SendSnapshot()
{
var players = GetPlayerList();
if (players == null) return;
foreach (var player in players)
{
var playerComp = player.GetComponent<PlayerComponent>();
List<DeltaLookup> deltaState = new List<DeltaLookup>();
var node = playerComp.NetworkNode;
if (node == null) continue;
List<NetworkObject> fullProcList = new List<NetworkObject>();
List<DeltaWrapper> _stateSendList = new List<DeltaWrapper>();
List<DeltaWrapper> _defSendList = new List<DeltaWrapper>();
List<DeltaLookup> deltaLookups = new List<DeltaLookup>();
Dictionary<int, DeltaWrapper> packetBaseState = new Dictionary<int, DeltaWrapper>();
foreach (Entity nobj in ObjectMapper.GetEntityCache())
{
if (nobj != player &&
nobj.HasComponent<Physics2dComponent>() &&
!CanPlayerSee(player, nobj))
{
continue;
}
playerComp.trackEntity(nobj);
#region DefinitionSync
var defObjList = ObjectMapper.GetNetObjects(nobj, typeof(DefinitionNetworkObject));
if (defObjList != null)
{
foreach (DefinitionNetworkObject obj in defObjList)
{
fullProcList.Add(obj);
if (!playerComp.IsObjectKnown(obj))
{
playerComp.AddKnownObject(obj, (uint)nobj.UniqueId);
_defSendList.Add(new DeltaWrapper()
{
Lookup = (uint)nobj.UniqueId,
Object = obj
});
}
}
}
#endregion
}
#region StateSync
var syncEntityList = playerComp.GetTrackedEntitiesByScore(10);
foreach (var nobj in syncEntityList)
{
var objList = ObjectMapper.GetNetObjects(nobj, typeof(StateSyncNetworkObject));
if (objList == null) continue;
foreach (var obj in objList)
{
var clone = obj.NetworkClone();
//quick hack to not send net sync data for the player controlled entity
//a different lag comp system is used.
if (clone is NetPhysicsObject)
{
//(clone as NetPhysicsObject).PlayerControlled = false;
var pComp = nobj.GetComponent<PlayerComponent>();
if (pComp != null)
{
if (pComp.NetworkNode == node)
{
(clone as NetPhysicsObject).PlayerControlled = true;
}
else
{
(clone as NetPhysicsObject).SimTick = 0; //don't send this to other clients
}
}
else
{
int ack = 0;
}
}
var baseline = playerComp.FindBaseline(obj);
deltaState.Add(new DeltaLookup()
{
Lookup = obj.GetHashCode(),
Object = clone
});
packetBaseState.Add(clone.GetHashCode(), baseline);
_stateSendList.Add(new DeltaWrapper()
{
Lookup = (uint)nobj.UniqueId,
Object = clone
});
}
}
#endregion
#region send packets
if (_stateSendList.Count > 0)
{
var packet = new DataObjectPacket();
packet.Objects = _stateSendList;
packet.Method = NetDeliveryMethod.UnreliableSequenced;
packet.BaselineId = NetTime.SimTick;
packet.SetBaseline(packetBaseState);
_bifrost.Send(packet, node);
}
if (_defSendList.Count > 0)
{
var packet = new DataObjectPacket();
packet.Method = NetDeliveryMethod.ReliableOrdered;
packet.Objects = _defSendList;
_bifrost.Send(packet, node, 3);
}
#endregion
#region handle removed DefinitionNetworkObjects
_defSendList.Clear();
//cross check the fullproc list against the known def obj list of this player
//this will tell us if the player is tracking an object that has been deleted
var deletedItems = playerComp.FindDeletedObjects(fullProcList);
foreach(var delObjItem in deletedItems)
{
var delObj = delObjItem.Item1 as DefinitionNetworkObject;
var nobjId = delObjItem.Item2;
var marked = delObj.Destroy;
var ent = EntityManager.GetEntityByUniqueId(nobjId);
if (ent != null)
{
playerComp.UntrackEntity(ent);
var comps = EntityManager.GetComponents(ent);
foreach(var comp in comps)
{
var stateSyncComp = comp as StateSyncNetworkObject;
if (stateSyncComp != null)
{
playerComp.RemoveDeltaTrack(stateSyncComp);
}
}
}
delObj.Destroy = true;
playerComp.RemoveKnownObject(delObj);
_defSendList.Add(new DeltaWrapper()
{
Lookup = nobjId,
Object = delObj
});
if (!marked)
delObj.Destroy = false;
}
if (_defSendList.Count > 0)
{
var packet = new DataObjectPacket();
packet.Method = NetDeliveryMethod.ReliableOrdered;
packet.Objects = _defSendList;
_bifrost.Send(packet, node, 3);
}
#endregion
playerComp.AddDeltaState(deltaState);
}
}