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); }