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); } }