public async Task OnUpdate(ClientUpdate e) { foreach (var change in e.TileUpdates) { await Map.SetAsync(change.Position, change.TileInfo); } foreach (var ev in e.Events) { var moveEvent = ev as EntityMoveEvent; if (moveEvent != null && !Map.ChunkLoader.IsLoadedOrLoading(moveEvent.SourcePosition / Chunk.Size)) { // The entity comes from a chunk we have not loaded => spawn it first Map.Emit(new EntitySpawnEvent(moveEvent.SourcePosition, moveEvent.Target.Entity)); } Map.Emit(ev); if (moveEvent != null && !Map.ChunkLoader.IsLoadedOrLoading(moveEvent.TargetPosition / Chunk.Size)) { // The entity moves into an area we have not loaded => despawn it after the move Map.Emit(new EntityDespawnEvent(moveEvent.TargetPosition, moveEvent.Source.Entity)); } } AnalyzeEvents(e.Events); }
/// <summary> /// Sends a subset of the changes and events of the specified transaction to the /// clients depending on which chunks each client has currently loaded. /// </summary> /// <param name="transaction">The transaction that contains the changes that are broadcasted</param> /// <param name="newVersion">The version to be used for the updates tiles</param> /// <param name="excludedConnection">An optional connection that is excluded and does not receive the tile updates</param> /// <returns></returns> private async Task BroadcastChangesAsync(ITransactionWithMoveSupport transaction, int newVersion, ClientConnection excludedConnection = null) { // Check which players have moved and update their positions in map metadata var playerMoveEvents = transaction.Events .OfType<EntityMoveEvent>() .Where(e => e.Source.Entity is PlayerEntity) .Select(e => new { PlayerId = (e.Source.Entity as PlayerEntity)?.PlayerId, NewPosition = e.TargetPosition }); foreach (var move in playerMoveEvents) Map.Metadata.Players[move.PlayerId] = Map.Metadata.Players[move.PlayerId].WithPosition(move.NewPosition); // Notify clients that have loaded the affected chunks foreach (var conn in _clients.Values) { if (conn == excludedConnection) continue; // Skip calling client var relevantChanges = transaction.Changes .Where(change => conn.LoadedChunks.Contains(change.Key / Chunk.Size)) .Select(change => new TileUpdate(change.Key, change.Value.WithVersion(newVersion))) .ToArray(); var relevantEvents = transaction.Events .OfType<ILocatedGameEvent>() .Where(ev => ev.GetPositions().Any(p => conn.LoadedChunks.Contains(p / Chunk.Size)) || ((ev as EntitySpawnEvent)?.Entity as PlayerEntity)?.PlayerId == conn.ClientInfo.PlayerId) .ToArray(); if (relevantChanges.Any() || relevantEvents.Any()) { // If there are any tile changes or any events that are of interest // to the client, push them to the client. var update = new ClientUpdate(relevantChanges, relevantEvents); await conn.ClientStub.OnUpdate(update); } } }