public bool TryAddOrUpdate(TEntity entity, out IEnumerable <TEntity> entitiesToAdd, out IEnumerable <TEntity> entitiesToRemove) { var newCellHash = this.GetHash(entity); SpatialGridCell oldCell = null; entitiesToAdd = Enumerable.Empty <TEntity>(); entitiesToRemove = Enumerable.Empty <TEntity>(); var regInfo = this.entities.AddOrUpdate( entity.Id, (id) => new EntityRegistrationInfo(entity, this.GetCell(newCellHash)), (id, oldRegInfo) => { oldCell = oldRegInfo.Cell; if (newCellHash != oldCell.Hash) { oldRegInfo.Cell = this.GetCell(newCellHash); } return(oldRegInfo); }); // At this point we have three possible states: // 1. Entity was registered on the grid for the first time // 2. Entity remains on the same cell // 3. Entity moved to the other cell if (oldCell != null && oldCell.Hash == newCellHash) { // Entity stays on the same cell, no need to update return(false); } IEnumerable <SpatialGridCell> newCellBlock = this.GetCellWithNeighbors(newCellHash).ToList(); if (oldCell != null) { // Entity moved to the other cell oldCell.Remove(entity); var oldCellBlock = this.GetCellWithNeighbors(oldCell.Hash).ToList(); entitiesToRemove = oldCellBlock.Except(newCellBlock).SelectMany(cell => cell.Entities).ToList(); newCellBlock = newCellBlock.Except(oldCellBlock); } entitiesToAdd = newCellBlock.SelectMany(cell => cell.Entities).ToList(); regInfo.Cell.Register(entity); if (oldCell == null) { // New entity registered on the grid this.EntityRegistered?.Invoke(this, new EntityEventArgs <TEntityId, TEntity>(entity)); } return(true); }
public EntityRegistrationInfo(TEntity entity, SpatialGridCell cell) { this.Entity = entity; this.Cell = cell; }