Example #1
0
        private async Task<bool> MoveCoreAsync(Point sourcePosition, Point targetPosition, ITransactionWithMoveSupport transaction)
        {
            var source = await GetAsync(sourcePosition);
            var target = await GetAsync(targetPosition);

            var oldSource = source;
            var oldTarget = target;

            source.Tile.EnsureNotNull();
            target.Tile.EnsureNotNull();

            if (source.Tile.Entity == Entity.None)
            {
                // Cancel if there's no entity to move
                transaction.IsSealed = true;
                return false;
            }

            var move = new EntityMoveInfo(source.Tile.Entity, sourcePosition, targetPosition);
            transaction.Moves.Push(move);

            IBeginMoveArgs beginMoveArgs = new GameplayArgs(transaction, this);
            IDetachArgs detachArgs = new GameplayArgs(transaction, this);
            IAttachArgs attachArgs = new GameplayArgs(transaction, this);

            // OnBeginMove: Notify entity that a move has been initiated
            await source.Tile.Entity.BeginMoveAsync(beginMoveArgs);
            beginMoveArgs.ValidateResult();
            if (transaction.IsSealed) return false;

            var newSource = source.WithTile(Tile.Compose(source.Tile, beginMoveArgs.ResultingEntity));
            if (transaction.Set(sourcePosition, source, newSource))
                source = newSource;

            move.Entity = beginMoveArgs.ResultingEntity;

            // Detach: Remove the entity from the source tile
            await source.Tile.DetachEntityAsync(detachArgs);
            detachArgs.ValidateResult();
            if (transaction.IsSealed) return false;

            // Attach: Add the entity to the target tile
            await target.Tile.AttachEntityAsync(attachArgs);
            attachArgs.ValidateResult();
            if (transaction.IsSealed) return false;

            // Detach from old tile, attach to new tile have succeeded
            // => Apply changes to transaction
            var newSource2 = source.WithTile(detachArgs.Result);
            if (transaction.Set(sourcePosition, source, newSource2))
                source = newSource2;

            var newTarget = target.WithTile(attachArgs.Result);
            if (transaction.Set(targetPosition, target, newTarget))
                target = newTarget;

            // Emit events
            var moveEvent = new EntityMoveEvent(sourcePosition, targetPosition, oldSource.Tile, target.Tile);
            transaction.Emit(moveEvent);

            if (source.Tile.Entity != Entity.None)
            {
                // A new entity has been created at source position
                var spawnEvent = new EntitySpawnEvent(sourcePosition, source.Tile.Entity);
                transaction.Emit(spawnEvent);
            }

            if (oldTarget.Tile.Entity != Entity.None)
            {
                // The entity at target position has either been replaced
                // or it has been moved/collected/... during a nested move
                var oldTargetEntityOverwritten =
                    !(transaction.Events.OfType<EntityDespawnEvent>().Any(ev => ev.Position == targetPosition) ||
                    transaction.Events.OfType<EntityMoveEvent>().Any(ev => ev.SourcePosition == targetPosition));

                if (oldTargetEntityOverwritten)
                {
                    // If replaced, emit despawn event
                    var despawnEvent = new EntityDespawnEvent(targetPosition, oldTarget.Tile.Entity);
                    transaction.Emit(despawnEvent);
                }
            }

            transaction.Moves.Pop();
            return true;
        }
Example #2
0
        private async void OnChunkLoaded(KeyValuePair<Point, IChunk> kvp)
        {
            for (var y = 0; y < Chunk.Size; y++)
            {
                for (var x = 0; x < Chunk.Size; x++)
                {
                    var localPosition = new Point(x, y);
                    var globalPosition = kvp.Key * Chunk.Size + localPosition;
                    var tileInfo = kvp.Value[localPosition];
                    Dependencies.AddDependenciesOf(tileInfo.Tile, globalPosition);

                    // For entities emit a spawn event
                    if (tileInfo.Tile.Entity != Entity.None)
                    {
                        var spawnEvent = new EntitySpawnEvent(globalPosition, tileInfo.Tile.Entity);
                        _eventSource.OnNext(spawnEvent);
                    }
                }
            }

            // Properly initialize the chunk.
            // Example scenarios: On chunk loading...
            // - a button should be activated immediately if there's an entity pressing it
            // - a balloon should be popped immediately if it is on a pin
            var chunkPoints = new Rectangle(kvp.Key.X * Chunk.Size, kvp.Key.Y * Chunk.Size, Chunk.Size - 1, Chunk.Size - 1);
            var transaction = new TransactionWithMoveSupport(MoveInitiator.Empty);
            await UpdateTilesAsync(chunkPoints, transaction);
            _eventSource.OnNext(new ChunkAddedEvent(kvp.Value));

            // TODO: This is problematic! A commit is done directly on the map
            // bypassing the GameServer. We might have to forward the new chunk
            // to some of the players.
            // On client side we can't just invent some new version numbers.
            await transaction.CommitAsync(this, Metadata?.NextTileVersion() ?? 0);
        }
        private void OnEntitySpawned(EntitySpawnEvent e)
        {
            var entityInfo = new EntityInfo(e.Entity, e.Position, Map.Events);

            lock (_entitiesLock)
                _entities.Add(entityInfo);

            if ((e.Entity as PlayerEntity)?.PlayerId == FollowedPlayerId && FollowedPlayerId != null)
                CameraPosition = e.Position.ToVector2() + new Vector2(.5f, -.5f);
        }