protected override int PerformInternal()
        {
            //lock is done already
            if (Block.Undefined == _prevBlock)            //created out of bounds, dont continue
            {
                return(0);
            }
            //fix for portal gun
            if (_owner.orangePortal.Count > 0)
            {
                if (_pos == _owner.orangePortal[0] || _pos == _owner.orangePortal[1])
                {
                    return(0);
                }
            }
            if (_owner.bluePortal.Count > 0)
            {
                if (_pos == _owner.bluePortal[0] || _pos == _owner.bluePortal[1])
                {
                    return(0);
                }
            }

            //delete at the previous position, restore water unconditionally, lava only when bullet is still there to prevent restoration of explosion lava
            if (_prevBlock != Block.Water)
            {
                _prevBlock = _map.GetBlock(_pos) == _block ?                     //is the bullet still here
                             (_prevBlock == Block.Lava ? Block.Lava : Block.Air) //yes, then either restore lava or set air
                                        : Block.Undefined;                       //no, it was removed by some other process, do nothing then
            }
            if (Block.Undefined != _prevBlock)
            {
                UpdateMap(new BlockUpdate(null, _pos, _prevBlock));
            }

            List <BlockUpdate> updates = new List <BlockUpdate>();

            for (int i = 0; i < _behavior.MovesPerProcessingStep && _restDistance > 0; ++i)
            {
                _pos       = Move();
                _prevBlock = _map.GetBlock(_pos);

                if (Block.Undefined == _prevBlock)
                {
                    _restDistance = 0;
                    break;
                }

                _behavior.ModifyDirection(ref _direction, _prevBlock);                 //e.g. if you want it to be dependent on gravity or change direction depending on current block etc

                if (_behavior.VisitBlock(_world, _pos, _prevBlock, _owner, ref _restDistance, updates, _block) && _behavior.CanKillPlayer)
                {
                    CheckHitPlayers(updates);
                }
            }

            bool cont = _restDistance > 0;

            if (cont)            //check if the last update was for the current position and replace it with the particle
            {
                int idx = updates.Count - 1;
                if (idx >= 0 && updates[idx].X == _pos.X &&
                    updates[idx].Y == _pos.Y &&
                    updates[idx].Z == _pos.Z)
                {
                    updates[idx] = new BlockUpdate(null, _pos, _block);
                }
                else
                {
                    updates.Add(new BlockUpdate(null, _pos, _block));
                }
            }

            for (int i = 0; i < updates.Count; ++i)
            {
                UpdateMap(updates[i]);
            }

            return(cont ? _stepDelay : 0);
        }