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);
            }
        }
Beispiel #2
0
        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);
            }
        }
Beispiel #3
0
        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);
            }
        }