public void OnLoop() { while (running) { try { while (entityThreadRepository.EntitiesChannelReader.TryRead(out var entityQueueResult)) { var(entityToChange, state) = entityQueueResult; switch (state) { case 0: spatialPartition.Add(entityToChange); foreach (var(key, _) in entityToChange.ThreadLocalData) { entityToChange.DataSnapshot.Update(key); } break; case 1: spatialPartition.Remove(entityToChange); foreach (var client in entityToChange.GetClients()) { client.RemoveEntity(threadIndex, entityToChange); onEntityRemove(client, entityToChange); } // We don't have to do this, but we do for for consistency because entity gets garbage collected anyway //entityToChange.GetClients().Clear(); foreach (var client in entityToChange.DataSnapshot.GetLastClients()) { onEntityClearCache(client, entityToChange); } break; case 2: // Check if position state is new position so we can set the new position to the entity internal position var(hasNewPosition, hasNewRange, hasNewDimension) = entityToChange.TrySetPropertiesComputing( out var newPosition, out var newRange, out var newDimension); if (hasNewPosition) { spatialPartition.UpdateEntityPosition(entityToChange, newPosition); foreach (var entityClient in entityToChange.GetClients()) { onEntityPositionChange(entityClient, entityToChange, newPosition); } } if (hasNewRange) { spatialPartition.UpdateEntityRange(entityToChange, newRange); } if (hasNewDimension) { spatialPartition.UpdateEntityDimension(entityToChange, newDimension); } break; } } while (entityThreadRepository.EntitiesDataChannelReader.TryRead(out var entityDataQueueResult)) { var(entityWithChangedData, changedDataKey, changedDataValue, notDeleted) = entityDataQueueResult; entityWithChangedData.DataSnapshot.Update(changedDataKey); if (notDeleted) { entityWithChangedData.SetThreadLocalData(changedDataKey, changedDataValue); } else { entityWithChangedData.ResetData(changedDataKey); } } //TODO: when the id provider add / remove doesn't work use the idprovider inside this loop only lock (clientThreadRepository.Mutex) { if (clientThreadRepository.ClientsToRemove.Count != 0) { while (clientThreadRepository.ClientsToRemove.TryDequeue(out var clientToRemove)) { clientToRemove.Snapshot.CleanupEntities(threadIndex, clientToRemove); foreach (var entityFromRemovedClient in clientToRemove.GetEntities(threadIndex)) { entityFromRemovedClient.RemoveClient(clientToRemove); } } } foreach (var(_, client) in clientThreadRepository.Clients) { if (!client.TryGetDimensionAndPosition(out var dimension, ref clientPosition)) { continue; } var foundEntities = spatialPartition.Find(clientPosition, dimension); var lastCheckedEntities = client.GetLastCheckedEntities(threadIndex); if (lastCheckedEntities.Count != 0) { foreach (var(lastCheckedEntity, lastChecked) in lastCheckedEntities) { if (lastChecked) { entitiesToResetFromClient.AddLast(lastCheckedEntity); } else { entitiesToRemoveFromClient.AddLast(lastCheckedEntity); onEntityRemove(client, lastCheckedEntity); } } if (entitiesToResetFromClient.Count != 0) { var currEntity = entitiesToResetFromClient.First; while (currEntity != null) { client.RemoveCheck(threadIndex, currEntity.Value); currEntity = currEntity.Next; } entitiesToResetFromClient.Clear(); } if (entitiesToRemoveFromClient.Count != 0) { var currEntity = entitiesToRemoveFromClient.First; while (currEntity != null) { client.RemoveEntity(threadIndex, currEntity.Value); currEntity = currEntity.Next; } entitiesToRemoveFromClient.Clear(); } } if (foundEntities != null) { for (int i = 0, length = foundEntities.Count; i < length; i++) { var foundEntity = foundEntities[i]; client.AddCheck(threadIndex, foundEntity); foundEntity.DataSnapshot.CompareWithClient(threadIndex, changedEntityDataKeys, client); // We add client to entity here so we can remove it from the client when the entity got removed foundEntity.TryAddClient(client); if (client.TryAddEntity(threadIndex, foundEntity)) { if (changedEntityDataKeys.Count == 0) { onEntityCreate(client, foundEntity, null); } else { onEntityCreate(client, foundEntity, changedEntityDataKeys); changedEntityDataKeys.Clear(); } } else if (changedEntityDataKeys.Count != 0) { onEntityDataChange(client, foundEntity, changedEntityDataKeys); changedEntityDataKeys.Clear(); } } } } } } catch (Exception exception) { Console.WriteLine(exception); } Thread.Sleep(syncRate); } }
private void OnLoop() { while (running) { try { while (entityThreadRepository.EntitiesChannelReader.TryRead(out var entityQueueResult)) { var(entityToChange, state) = entityQueueResult; switch (state) { case 0: entityToChange.SetExistsInternal(true); spatialPartition.Add(entityToChange); foreach (var(key, _) in entityToChange.ThreadLocalData) { entityToChange.DataSnapshot.Update(key); } break; case 1: entityToChange.SetExistsInternal(false); spatialPartition.Remove(entityToChange); foreach (var client in entityToChange.GetClients()) { client.RemoveEntityFully(threadIndex, entityToChange); onEntityRemove(client, entityToChange); } // We don't have to do this, but we do for for consistency because entity gets garbage collected anyway //entityToChange.GetClients().Clear(); foreach (var client in entityToChange.DataSnapshot.GetLastClients()) { onEntityClearCache(client, entityToChange); } break; case 2: if (entityToChange.Exists) { // Check if position state is new position so we can set the new position to the entity internal position var(hasNewPosition, hasNewRange, hasNewDimension) = entityToChange.TrySetPropertiesComputing( out var oldPosition, out var oldRange, out var oldDimension, out var newPosition, out var newRange, out var newDimension); if (hasNewPosition) { spatialPartition.UpdateEntityPosition(entityToChange, oldPosition, newPosition); foreach (var entityClient in entityToChange.GetClients()) { onEntityPositionChange(entityClient, entityToChange, newPosition); } } if (hasNewRange) { spatialPartition.UpdateEntityRange(entityToChange, oldRange, newRange); } if (hasNewDimension) { spatialPartition.UpdateEntityDimension(entityToChange, oldDimension, newDimension); } } break; } } while (entityThreadRepository.EntitiesDataChannelReader.TryRead(out var entityDataQueueResult)) { var(entityWithChangedData, changedDataKey, changedDataValue, notDeleted) = entityDataQueueResult; entityWithChangedData.DataSnapshot.Update(changedDataKey); if (notDeleted) { entityWithChangedData.SetThreadLocalData(changedDataKey, changedDataValue); } else { entityWithChangedData.ResetThreadLocalData(changedDataKey); } } //TODO: when the id provider add / remove doesn't work use the idprovider inside this loop only lock (clientThreadRepository.Mutex) { if (clientThreadRepository.ClientsToRemove.Count != 0) { while (clientThreadRepository.ClientsToRemove.TryDequeue(out var clientToRemove)) { foreach (var snapshot in clientToRemove.Snapshot.GetSnapshot(threadIndex)) { var entityFromRemovedClient = snapshot.Key; entityFromRemovedClient.DataSnapshot.RemoveClient(clientToRemove); } foreach (var(entityFromRemovedClient, _) in clientToRemove.GetEntities(threadIndex)) { entityFromRemovedClient.RemoveClient(clientToRemove); if (!netOwnerEvents) { continue; } if (entityFromRemovedClient.NetOwner == clientToRemove) { entityFromRemovedClient.NetOwner = null; entityFromRemovedClient.NetOwnerRange = float.MaxValue; } if (entityFromRemovedClient.TempNetOwner == clientToRemove) { entityFromRemovedClient.TempNetOwner = null; entityFromRemovedClient.TempNetOwnerRange = float.MaxValue; } } } } foreach (var(_, client) in clientThreadRepository.Clients) { if (!client.TryGetDimensionAndPosition(out var dimension, ref clientPosition)) { continue; } var foundEntities = spatialPartition.Find(clientPosition, dimension); var lastCheckedEntities = client.GetLastCheckedEntities(threadIndex); if (lastCheckedEntities.Count != 0) { foreach (var(lastCheckedEntity, lastChecked) in lastCheckedEntities) { if (lastChecked) { entitiesToResetFromClient.AddLast(lastCheckedEntity); } else { entitiesToRemoveFromClient.AddLast(lastCheckedEntity); onEntityRemove(client, lastCheckedEntity); if (!netOwnerEvents) { continue; } if (lastCheckedEntity.NetOwner == client) { lastCheckedEntity.NetOwner = null; lastCheckedEntity.NetOwnerRange = float.MaxValue; } if (lastCheckedEntity.TempNetOwner == client) { lastCheckedEntity.TempNetOwner = null; lastCheckedEntity.TempNetOwnerRange = float.MaxValue; } } } if (entitiesToResetFromClient.Count != 0) { var currEntity = entitiesToResetFromClient.First; while (currEntity != null) { client.RemoveCheck(threadIndex, currEntity.Value); currEntity = currEntity.Next; } entitiesToResetFromClient.Clear(); } if (entitiesToRemoveFromClient.Count != 0) { var currEntity = entitiesToRemoveFromClient.First; while (currEntity != null) { client.RemoveEntity(threadIndex, currEntity.Value); currEntity.Value.RemoveClient(client); // not in range anymore so remove currEntity = currEntity.Next; } entitiesToRemoveFromClient.Clear(); } } if (foundEntities != null) { for (int i = 0, length = foundEntities.Count; i < length; i++) { var foundEntity = foundEntities[i]; client.AddCheck(threadIndex, foundEntity); foundEntity.DataSnapshot.CompareWithClient(threadIndex, changedEntityDataKeys, client); // We add client to entity here so we can remove it from the client when the entity got removed foundEntity.TryAddClient(client); if (client.TryAddEntity(threadIndex, foundEntity)) { if (changedEntityDataKeys.Count == 0) { onEntityCreate(client, foundEntity, null); } else { onEntityCreate(client, foundEntity, changedEntityDataKeys); changedEntityDataKeys.Clear(); } } else { if (changedEntityDataKeys.Count != 0) { onEntityDataChange(client, foundEntity, changedEntityDataKeys); changedEntityDataKeys.Clear(); } if (!netOwnerEvents) { continue; } // Net Owner var lastStreamInRange = foundEntity.LastStreamInRange; if (foundEntity.NetOwner == null) { // If net owner is null, we need closest player if (foundEntity.TempNetOwner == client) { var lastNetOwner = foundEntity.NetOwner; if (lastNetOwner != null) { onEntityNetOwnerChange(foundEntity.NetOwner, foundEntity, false); } foundEntity.NetOwner = client; foundEntity.NetOwnerRange = lastStreamInRange; foundEntity.TempNetOwnerRange = float.MaxValue; foundEntity.TempNetOwner = null; onEntityNetOwnerChange(client, foundEntity, true); } else if (foundEntity.TempNetOwnerRange > lastStreamInRange) { foundEntity.TempNetOwner = client; foundEntity.TempNetOwnerRange = lastStreamInRange; } } else { // If net owner is not null, we need closest player but with migration distance // And we need to update own range to entity if (foundEntity.NetOwner == client) { foundEntity.NetOwnerRange = lastStreamInRange; if (foundEntity.TempNetOwnerRange > lastStreamInRange) { foundEntity.TempNetOwner = client; foundEntity.TempNetOwnerRange = lastStreamInRange; } } else if (foundEntity.TempNetOwner == client) { var lastNetOwner = foundEntity.NetOwner; if (lastNetOwner != null) { onEntityNetOwnerChange(foundEntity.NetOwner, foundEntity, false); } foundEntity.NetOwner = client; foundEntity.NetOwnerRange = lastStreamInRange; foundEntity.TempNetOwnerRange = float.MaxValue; foundEntity.TempNetOwner = null; onEntityNetOwnerChange(client, foundEntity, true); } else if (foundEntity.NetOwnerRange > foundEntity.MigrationDistance && foundEntity.TempNetOwnerRange > lastStreamInRange) { foundEntity.TempNetOwner = client; foundEntity.TempNetOwnerRange = lastStreamInRange; } } } } } } } } catch (Exception exception) { Console.WriteLine(exception); } Thread.Sleep(syncRate); } }
public void OnLoop() { while (running) { try { lock (entityThreadRepository.Mutex) { foreach (var(_, entity) in entityThreadRepository.Entities) { var lastCheckedClients = entity.GetLastCheckedClients(); if (lastCheckedClients.Count == 0) { continue; } foreach (var(client, lastChecked) in lastCheckedClients) { if (lastChecked) { clientsToResetFromEntity.AddLast(client); } else { clientsToRemoveFromEntity.AddLast(client); onEntityRemove(client, entity); } } if (clientsToResetFromEntity.Count != 0) { var currClient = clientsToResetFromEntity.First; while (currClient != null) { entity.RemoveCheck(currClient.Value); currClient = currClient.Next; } clientsToResetFromEntity.Clear(); } if (clientsToRemoveFromEntity.Count != 0) { var currClient = clientsToRemoveFromEntity.First; while (currClient != null) { entity.RemoveClient(currClient.Value); currClient = currClient.Next; } clientsToRemoveFromEntity.Clear(); } } if (entityThreadRepository.EntitiesQueue.Count != 0) { while (entityThreadRepository.EntitiesQueue.TryDequeue(out var entityQueueResult)) { var(entityToChange, state) = entityQueueResult; switch (state) { case 0: spatialPartition.Add(entityToChange); break; case 1: spatialPartition.Remove(entityToChange); foreach (var client in entityToChange.GetClients()) { onEntityRemove(client, entityToChange); } foreach (var client in entityToChange.DataSnapshot.GetLastClients()) { onEntityClearCache(client, entityToChange); } break; case 2: // Check if position state is new position so we can set the new position to the entity internal position var(hasNewPosition, hasNewRange, hasNewDimension) = entityToChange.TrySetPropertiesComputing( out var newPosition, out var newRange, out var newDimension); if (hasNewPosition) { spatialPartition.UpdateEntityPosition(entityToChange, newPosition); foreach (var entityClient in entityToChange.GetClients()) { onEntityPositionChange(entityClient, entityToChange, newPosition); } } if (hasNewRange) { spatialPartition.UpdateEntityRange(entityToChange, newRange); } if (hasNewDimension) { spatialPartition.UpdateEntityDimension(entityToChange, newDimension); } break; } } } //TODO: when the id provider add / remove doesn't work use the idprovider inside this loop only } lock (clientThreadRepository.Mutex) { if (clientThreadRepository.ClientsToRemove.Count != 0) { var clientToRemove = clientThreadRepository.ClientsToRemove.First; while (clientToRemove != null) { clientToRemove.Value.Snapshot.CleanupEntities(clientToRemove.Value); clientToRemove = clientToRemove.Next; } clientThreadRepository.ClientsToRemove.Clear(); } foreach (var(_, client) in clientThreadRepository.Clients) { if (!client.TryGetDimensionAndPosition(out var dimension, ref clientPosition)) { continue; } var foundEntities = spatialPartition.Find(clientPosition, dimension); if (foundEntities != null) { for (int i = 0, length = foundEntities.Count; i < length; i++) { var foundEntity = foundEntities[i]; foundEntity.AddCheck(client); foundEntity.DataSnapshot.CompareWithClient(changedEntityDataKeys, client); if (foundEntity.TryAddClient(client)) { if (changedEntityDataKeys.Count == 0) { onEntityCreate(client, foundEntity, null); } else { onEntityCreate(client, foundEntity, changedEntityDataKeys); changedEntityDataKeys.Clear(); } } else if (changedEntityDataKeys.Count != 0) { onEntityDataChange(client, foundEntity, changedEntityDataKeys); changedEntityDataKeys.Clear(); } } } } } } catch (Exception exception) { Console.WriteLine(exception); } Thread.Sleep(syncRate); } }