Exemple #1
0
        /// <inheritdoc/>
        public async Task<bool> SetAsync(Point position, TileInfo tileInfo)
        {
            // TODO: Handle concurrency
            var chunk = await ChunkLoader.GetAsync(position / Chunk.Size);
            var oldTileInfo = chunk[position % Chunk.Size];

            if (!Equals(oldTileInfo, tileInfo))
            {
                // Update chunk
                chunk[position % Chunk.Size] = tileInfo;

                // Update dependencies
                Dependencies.RemoveDependenciesOf(oldTileInfo.Tile, position);
                Dependencies.AddDependenciesOf(tileInfo.Tile, position);

                return true;
            }

            return false;
        }
Exemple #2
0
        /// <inheritdoc/>
        public async Task<ResetResult> ResetRegionAsync(Point position, ITransactionWithMoveSupport transaction)
        {
            // TOOD: Do not modify map directly, collect changes in a transaction
            // instead of 'bool' return 'ResetResult' containing the transaction

            var tileMeta = await GetMetadataAsync(position);
            var region = Metadata.Regions[tileMeta.RegionId];
            var regionPoints = await this.GetCoherentPositionsAsync(position);
            var playersInRegion = new List<PlayerEntity>();

            // Despawn all players within region
            foreach (var p in regionPoints)
            {
                var tileInfo = await GetAsync(p);
                var player = tileInfo.Tile.Entity as PlayerEntity;

                if (player != null)
                {
                    playersInRegion.Add(player);
                    var despawnResult = await DespawnAsync(p, transaction);
                    if (!despawnResult.IsSuccessful)
                        return new ResetResult(transaction, false, Enumerable.Empty<FollowUpEvent>()); // If we can't despawn a player in the region, we can't reset
                }
            }

            // Replace tiles with their templates
            foreach (var p in regionPoints)
            {
                var meta = await GetMetadataAsync(p);
                var oldTileInfo = await GetAsync(p);
                var newTileInfo = new TileInfo(meta.TileTemplate, oldTileInfo.Version); // Version will be set during commit

                var hasChanged = transaction.Set(p, oldTileInfo, newTileInfo);

                if (hasChanged && oldTileInfo.Tile.Entity != Entity.None)
                    transaction.Emit(new EntityDespawnEvent(p, oldTileInfo.Tile.Entity));

                if (hasChanged && newTileInfo.Tile.Entity != Entity.None)
                    transaction.Emit(new EntitySpawnEvent(p, newTileInfo.Tile.Entity));
            }

            // Respawn players at spawn position
            var spawnPoints = await this.GetCoherentPositionsAsync(region.SpawnPosition);
            var availableSpawnPoints = spawnPoints.Shuffle().ToQueue();

            if (availableSpawnPoints.Count < playersInRegion.Count)
                return new ResetResult(transaction, false, Enumerable.Empty<FollowUpEvent>()); // Spawn region is too small to respawn all players

            foreach (var player in playersInRegion)
            {
                var success = false;
                var spawnPosition = Point.Zero;

                while (!success && availableSpawnPoints.Any())
                {
                    transaction.IsSealed = false; // If the last spawn failed the transaction is sealed which would prevent any other spawns
                    spawnPosition = availableSpawnPoints.Dequeue();
                    var spawnResult = await SpawnAsync(player, spawnPosition, transaction);
                    success = spawnResult.IsSuccessful;
                }

                if (success)
                {
                    // Update player position in map metadata
                    Metadata.Players[player.PlayerId] = Metadata.Players[player.PlayerId].WithPosition(spawnPosition);
                }
                else
                {
                    // We ran out of available spawn positions and could not spawn the player
                    // => we can't fully reset the region
                    return new ResetResult(transaction, false, Enumerable.Empty<FollowUpEvent>());
                }
            }

            // Notify changed tiles and tiles that directly or indirectly depend on changed tiles
            var affectedTiles = transaction.Changes.Select(kvp => kvp.Key);
            var followUpEvents = await UpdateTilesAsync(affectedTiles, transaction);
            return new ResetResult(transaction, true, followUpEvents);
        }