diff --git a/src/command/defaults/TeleportCommand.php b/src/command/defaults/TeleportCommand.php index 9d0a5fe46..ed86dd413 100644 --- a/src/command/defaults/TeleportCommand.php +++ b/src/command/defaults/TeleportCommand.php @@ -26,12 +26,12 @@ namespace pocketmine\command\defaults; use pocketmine\command\Command; use pocketmine\command\CommandSender; use pocketmine\command\utils\InvalidCommandSyntaxException; +use pocketmine\entity\Location; use pocketmine\lang\TranslationContainer; -use pocketmine\math\Vector3; use pocketmine\player\Player; +use pocketmine\utils\AssumptionFailedError; use pocketmine\utils\TextFormat; -use function array_filter; -use function array_values; +use function array_shift; use function count; use function round; @@ -47,84 +47,83 @@ class TeleportCommand extends VanillaCommand{ $this->setPermission("pocketmine.command.teleport"); } + private function findPlayer(CommandSender $sender, string $playerName) : ?Player{ + $subject = $sender->getServer()->getPlayer($playerName); + if($subject === null){ + $sender->sendMessage(TextFormat::RED . "Can't find player " . $playerName); + return null; + } + return $subject; + } + public function execute(CommandSender $sender, string $commandLabel, array $args){ if(!$this->testPermission($sender)){ return true; } - $args = array_values(array_filter($args, function(string $arg) : bool{ - return $arg !== ""; - })); - if(count($args) < 1 or count($args) > 6){ - throw new InvalidCommandSyntaxException(); - } - - $target = null; - $origin = $sender; - - if(count($args) === 1 or count($args) === 3){ - if($sender instanceof Player){ - $target = $sender; - }else{ - $sender->sendMessage(TextFormat::RED . "Please provide a player!"); - - return true; - } - if(count($args) === 1){ - $target = $sender->getServer()->getPlayer($args[0]); - if($target === null){ - $sender->sendMessage(TextFormat::RED . "Can't find player " . $args[0]); - + switch(count($args)){ + case 1: // /tp targetPlayer + case 3: // /tp x y z + case 5: // /tp x y z yaw pitch - TODO: 5 args could be target x y z yaw :( + if(!($sender instanceof Player)){ + $sender->sendMessage(TextFormat::RED . "Please provide a player!"); return true; } - } - }else{ - $target = $sender->getServer()->getPlayer($args[0]); - if($target === null){ - $sender->sendMessage(TextFormat::RED . "Can't find player " . $args[0]); - - return true; - } - if(count($args) === 2){ - $origin = $target; - $target = $sender->getServer()->getPlayer($args[1]); - if($target === null){ - $sender->sendMessage(TextFormat::RED . "Can't find player " . $args[1]); + $subject = $sender; + $targetArgs = $args; + break; + case 2: // /tp player1 player2 + case 4: // /tp player1 x y z - TODO: 4 args could be x y z yaw :( + case 6: // /tp player1 x y z yaw pitch + $subject = $this->findPlayer($sender, $args[0]); + if($subject === null){ return true; } - } + $targetArgs = $args; + array_shift($targetArgs); + break; + default: + throw new InvalidCommandSyntaxException(); } - $targetLocation = $target->getLocation(); + switch(count($targetArgs)){ + case 1: + $targetPlayer = $this->findPlayer($sender, $targetArgs[0]); + if($targetPlayer === null){ + return true; + } - if(count($args) < 3){ - $origin->teleport($targetLocation); - Command::broadcastCommandMessage($sender, new TranslationContainer("commands.tp.success", [$origin->getName(), $target->getName()])); + $subject->teleport($targetPlayer->getLocation()); + Command::broadcastCommandMessage($sender, new TranslationContainer("commands.tp.success", [$subject->getName(), $targetPlayer->getName()])); - return true; - }else{ - if(count($args) === 4 or count($args) === 6){ - $pos = 1; - }else{ - $pos = 0; - } + return true; + case 3: + case 5: + $base = $subject->getLocation(); + if(count($targetArgs) === 5){ + $yaw = (float) $targetArgs[3]; + $pitch = (float) $targetArgs[4]; + }else{ + $yaw = $base->yaw; + $pitch = $base->pitch; + } - $x = $this->getRelativeDouble($targetLocation->x, $sender, $args[$pos++]); - $y = $this->getRelativeDouble($targetLocation->y, $sender, $args[$pos++], 0, 256); - $z = $this->getRelativeDouble($targetLocation->z, $sender, $args[$pos++]); - $yaw = $targetLocation->getYaw(); - $pitch = $targetLocation->getPitch(); + $x = $this->getRelativeDouble($base->x, $sender, $targetArgs[0]); + $y = $this->getRelativeDouble($base->y, $sender, $targetArgs[1], 0, 256); + $z = $this->getRelativeDouble($base->z, $sender, $targetArgs[2]); + $targetLocation = new Location($x, $y, $z, $yaw, $pitch, $base->getWorldNonNull()); - if(count($args) === 6 or (count($args) === 5 and $pos === 3)){ - $yaw = (float) $args[$pos++]; - $pitch = (float) $args[$pos++]; - } - - $target->teleport(new Vector3($x, $y, $z), $yaw, $pitch); - Command::broadcastCommandMessage($sender, new TranslationContainer("commands.tp.success.coordinates", [$target->getName(), round($x, 2), round($y, 2), round($z, 2)])); - - return true; + $subject->teleport($targetLocation); + Command::broadcastCommandMessage($sender, new TranslationContainer("commands.tp.success.coordinates", [ + $subject->getName(), + round($targetLocation->x, 2), + round($targetLocation->y, 2), + round($targetLocation->z, 2) + ])); + return true; + default: + throw new AssumptionFailedError("This branch should be unreachable (for now)"); } } } diff --git a/src/command/defaults/TimingsCommand.php b/src/command/defaults/TimingsCommand.php index d005fdb1d..c953438f1 100644 --- a/src/command/defaults/TimingsCommand.php +++ b/src/command/defaults/TimingsCommand.php @@ -176,6 +176,8 @@ class TimingsCommand extends VanillaCommand{ fclose($fileTimings); Command::broadcastCommandMessage($sender, new TranslationContainer("pocketmine.command.timings.timingsWrite", [$timings])); } + }else{ + throw new InvalidCommandSyntaxException(); } return true; diff --git a/src/command/defaults/WhitelistCommand.php b/src/command/defaults/WhitelistCommand.php index 6b80cfe4c..622f69bde 100644 --- a/src/command/defaults/WhitelistCommand.php +++ b/src/command/defaults/WhitelistCommand.php @@ -49,10 +49,6 @@ class WhitelistCommand extends VanillaCommand{ return true; } - if(count($args) === 0 or count($args) > 2){ - throw new InvalidCommandSyntaxException(); - } - if(count($args) === 1){ if($this->badPerm($sender, strtolower($args[0]))){ return false; @@ -112,7 +108,7 @@ class WhitelistCommand extends VanillaCommand{ } } - return true; + throw new InvalidCommandSyntaxException(); } private function badPerm(CommandSender $sender, string $subcommand) : bool{ diff --git a/src/event/entity/EntityBlockChangeEvent.php b/src/event/entity/EntityBlockChangeEvent.php index b6c28fd07..f73da94ec 100644 --- a/src/event/entity/EntityBlockChangeEvent.php +++ b/src/event/entity/EntityBlockChangeEvent.php @@ -30,6 +30,7 @@ use pocketmine\event\CancellableTrait; /** * Called when an Entity, excluding players, changes a block directly + * @phpstan-extends EntityEvent */ class EntityBlockChangeEvent extends EntityEvent implements Cancellable{ use CancellableTrait; diff --git a/src/event/entity/EntityCombustEvent.php b/src/event/entity/EntityCombustEvent.php index d45296ca7..442c25f9b 100644 --- a/src/event/entity/EntityCombustEvent.php +++ b/src/event/entity/EntityCombustEvent.php @@ -27,6 +27,9 @@ use pocketmine\entity\Entity; use pocketmine\event\Cancellable; use pocketmine\event\CancellableTrait; +/** + * @phpstan-extends EntityEvent + */ class EntityCombustEvent extends EntityEvent implements Cancellable{ use CancellableTrait; diff --git a/src/event/entity/EntityDamageEvent.php b/src/event/entity/EntityDamageEvent.php index fda9e5de3..79775e489 100644 --- a/src/event/entity/EntityDamageEvent.php +++ b/src/event/entity/EntityDamageEvent.php @@ -31,6 +31,7 @@ use function max; /** * Called when an entity takes damage. + * @phpstan-extends EntityEvent */ class EntityDamageEvent extends EntityEvent implements Cancellable{ use CancellableTrait; diff --git a/src/event/entity/EntityDeathEvent.php b/src/event/entity/EntityDeathEvent.php index 4eb9953ab..65aef71d0 100644 --- a/src/event/entity/EntityDeathEvent.php +++ b/src/event/entity/EntityDeathEvent.php @@ -26,6 +26,9 @@ namespace pocketmine\event\entity; use pocketmine\entity\Living; use pocketmine\item\Item; +/** + * @phpstan-extends EntityEvent + */ class EntityDeathEvent extends EntityEvent{ /** @var Item[] */ private $drops = []; diff --git a/src/event/entity/EntityDespawnEvent.php b/src/event/entity/EntityDespawnEvent.php index 7e5272575..0fd0da8a0 100644 --- a/src/event/entity/EntityDespawnEvent.php +++ b/src/event/entity/EntityDespawnEvent.php @@ -27,6 +27,7 @@ use pocketmine\entity\Entity; /** * Called when a entity is despawned + * @phpstan-extends EntityEvent */ class EntityDespawnEvent extends EntityEvent{ diff --git a/src/event/entity/EntityEffectEvent.php b/src/event/entity/EntityEffectEvent.php index 724944335..f93e06b72 100644 --- a/src/event/entity/EntityEffectEvent.php +++ b/src/event/entity/EntityEffectEvent.php @@ -28,6 +28,9 @@ use pocketmine\entity\Entity; use pocketmine\event\Cancellable; use pocketmine\event\CancellableTrait; +/** + * @phpstan-extends EntityEvent + */ class EntityEffectEvent extends EntityEvent implements Cancellable{ use CancellableTrait; diff --git a/src/event/entity/EntityEvent.php b/src/event/entity/EntityEvent.php index 2799441f2..0a13ff0eb 100644 --- a/src/event/entity/EntityEvent.php +++ b/src/event/entity/EntityEvent.php @@ -29,12 +29,19 @@ namespace pocketmine\event\entity; use pocketmine\entity\Entity; use pocketmine\event\Event; +/** + * @phpstan-template TEntity of Entity + */ abstract class EntityEvent extends Event{ - /** @var Entity */ + /** + * @var Entity + * @phpstan-var TEntity + */ protected $entity; /** * @return Entity + * @phpstan-return TEntity */ public function getEntity(){ return $this->entity; diff --git a/src/event/entity/EntityExplodeEvent.php b/src/event/entity/EntityExplodeEvent.php index 19e14f589..e9b6bc3ad 100644 --- a/src/event/entity/EntityExplodeEvent.php +++ b/src/event/entity/EntityExplodeEvent.php @@ -31,6 +31,7 @@ use pocketmine\world\Position; /** * Called when a entity explodes + * @phpstan-extends EntityEvent */ class EntityExplodeEvent extends EntityEvent implements Cancellable{ use CancellableTrait; diff --git a/src/event/entity/EntityMotionEvent.php b/src/event/entity/EntityMotionEvent.php index 1519fcf16..dc90e2b96 100644 --- a/src/event/entity/EntityMotionEvent.php +++ b/src/event/entity/EntityMotionEvent.php @@ -28,6 +28,9 @@ use pocketmine\event\Cancellable; use pocketmine\event\CancellableTrait; use pocketmine\math\Vector3; +/** + * @phpstan-extends EntityEvent + */ class EntityMotionEvent extends EntityEvent implements Cancellable{ use CancellableTrait; diff --git a/src/event/entity/EntityRegainHealthEvent.php b/src/event/entity/EntityRegainHealthEvent.php index c063ea196..cb37ee612 100644 --- a/src/event/entity/EntityRegainHealthEvent.php +++ b/src/event/entity/EntityRegainHealthEvent.php @@ -27,6 +27,9 @@ use pocketmine\entity\Entity; use pocketmine\event\Cancellable; use pocketmine\event\CancellableTrait; +/** + * @phpstan-extends EntityEvent + */ class EntityRegainHealthEvent extends EntityEvent implements Cancellable{ use CancellableTrait; diff --git a/src/event/entity/EntityShootBowEvent.php b/src/event/entity/EntityShootBowEvent.php index d4da02e7f..32f4f4d70 100644 --- a/src/event/entity/EntityShootBowEvent.php +++ b/src/event/entity/EntityShootBowEvent.php @@ -31,6 +31,9 @@ use pocketmine\event\CancellableTrait; use pocketmine\item\Item; use function count; +/** + * @phpstan-extends EntityEvent + */ class EntityShootBowEvent extends EntityEvent implements Cancellable{ use CancellableTrait; diff --git a/src/event/entity/EntitySpawnEvent.php b/src/event/entity/EntitySpawnEvent.php index 7a21a5346..89e660a42 100644 --- a/src/event/entity/EntitySpawnEvent.php +++ b/src/event/entity/EntitySpawnEvent.php @@ -27,6 +27,7 @@ use pocketmine\entity\Entity; /** * Called when a entity is spawned + * @phpstan-extends EntityEvent */ class EntitySpawnEvent extends EntityEvent{ diff --git a/src/event/entity/EntityTeleportEvent.php b/src/event/entity/EntityTeleportEvent.php index 3c7eee6fd..33f1d8de6 100644 --- a/src/event/entity/EntityTeleportEvent.php +++ b/src/event/entity/EntityTeleportEvent.php @@ -28,6 +28,9 @@ use pocketmine\event\Cancellable; use pocketmine\event\CancellableTrait; use pocketmine\world\Position; +/** + * @phpstan-extends EntityEvent + */ class EntityTeleportEvent extends EntityEvent implements Cancellable{ use CancellableTrait; diff --git a/src/event/entity/ExplosionPrimeEvent.php b/src/event/entity/ExplosionPrimeEvent.php index a37aec131..68bec6fa4 100644 --- a/src/event/entity/ExplosionPrimeEvent.php +++ b/src/event/entity/ExplosionPrimeEvent.php @@ -29,6 +29,7 @@ use pocketmine\event\CancellableTrait; /** * Called when a entity decides to explode + * @phpstan-extends EntityEvent */ class ExplosionPrimeEvent extends EntityEvent implements Cancellable{ use CancellableTrait; diff --git a/src/event/entity/ItemDespawnEvent.php b/src/event/entity/ItemDespawnEvent.php index 3e3965706..6942fcf1b 100644 --- a/src/event/entity/ItemDespawnEvent.php +++ b/src/event/entity/ItemDespawnEvent.php @@ -27,6 +27,9 @@ use pocketmine\entity\object\ItemEntity; use pocketmine\event\Cancellable; use pocketmine\event\CancellableTrait; +/** + * @phpstan-extends EntityEvent + */ class ItemDespawnEvent extends EntityEvent implements Cancellable{ use CancellableTrait; diff --git a/src/event/entity/ItemSpawnEvent.php b/src/event/entity/ItemSpawnEvent.php index 367555037..59154f029 100644 --- a/src/event/entity/ItemSpawnEvent.php +++ b/src/event/entity/ItemSpawnEvent.php @@ -25,6 +25,9 @@ namespace pocketmine\event\entity; use pocketmine\entity\object\ItemEntity; +/** + * @phpstan-extends EntityEvent + */ class ItemSpawnEvent extends EntityEvent{ public function __construct(ItemEntity $item){ diff --git a/src/event/entity/ProjectileHitEvent.php b/src/event/entity/ProjectileHitEvent.php index b5a800d1c..70230f3fa 100644 --- a/src/event/entity/ProjectileHitEvent.php +++ b/src/event/entity/ProjectileHitEvent.php @@ -28,6 +28,7 @@ use pocketmine\math\RayTraceResult; /** * @allowHandle + * @phpstan-extends EntityEvent */ abstract class ProjectileHitEvent extends EntityEvent{ /** @var RayTraceResult */ diff --git a/src/event/entity/ProjectileLaunchEvent.php b/src/event/entity/ProjectileLaunchEvent.php index eaf2dcef3..9ccbaa009 100644 --- a/src/event/entity/ProjectileLaunchEvent.php +++ b/src/event/entity/ProjectileLaunchEvent.php @@ -27,6 +27,9 @@ use pocketmine\entity\projectile\Projectile; use pocketmine\event\Cancellable; use pocketmine\event\CancellableTrait; +/** + * @phpstan-extends EntityEvent + */ class ProjectileLaunchEvent extends EntityEvent implements Cancellable{ use CancellableTrait; diff --git a/src/event/player/PlayerExhaustEvent.php b/src/event/player/PlayerExhaustEvent.php index 0002d8d82..42408a7b2 100644 --- a/src/event/player/PlayerExhaustEvent.php +++ b/src/event/player/PlayerExhaustEvent.php @@ -28,6 +28,9 @@ use pocketmine\event\Cancellable; use pocketmine\event\CancellableTrait; use pocketmine\event\entity\EntityEvent; +/** + * @phpstan-extends EntityEvent + */ class PlayerExhaustEvent extends EntityEvent implements Cancellable{ use CancellableTrait; diff --git a/src/event/player/PlayerExperienceChangeEvent.php b/src/event/player/PlayerExperienceChangeEvent.php index 86d0b085b..f1569d79d 100644 --- a/src/event/player/PlayerExperienceChangeEvent.php +++ b/src/event/player/PlayerExperienceChangeEvent.php @@ -30,6 +30,7 @@ use pocketmine\event\entity\EntityEvent; /** * Called when a player gains or loses XP levels and/or progress. + * @phpstan-extends EntityEvent */ class PlayerExperienceChangeEvent extends EntityEvent implements Cancellable{ use CancellableTrait; diff --git a/tests/phpstan/configs/actual-problems.neon b/tests/phpstan/configs/actual-problems.neon index 492dce500..e7d66f59a 100644 --- a/tests/phpstan/configs/actual-problems.neon +++ b/tests/phpstan/configs/actual-problems.neon @@ -35,46 +35,11 @@ parameters: count: 1 path: ../../../src/block/inventory/DoubleChestInventory.php - - - message: "#^Call to an undefined method pocketmine\\\\command\\\\CommandSender\\:\\:teleport\\(\\)\\.$#" - count: 1 - path: ../../../src/command/defaults/TeleportCommand.php - - - - message: "#^Method pocketmine\\\\event\\\\entity\\\\EntityDeathEvent\\:\\:getEntity\\(\\) should return pocketmine\\\\entity\\\\Living but returns pocketmine\\\\entity\\\\Entity\\.$#" - count: 1 - path: ../../../src/event/entity/EntityDeathEvent.php - - - - message: "#^Method pocketmine\\\\event\\\\entity\\\\EntityShootBowEvent\\:\\:getEntity\\(\\) should return pocketmine\\\\entity\\\\Living but returns pocketmine\\\\entity\\\\Entity\\.$#" - count: 1 - path: ../../../src/event/entity/EntityShootBowEvent.php - - message: "#^Property pocketmine\\\\event\\\\entity\\\\EntityShootBowEvent\\:\\:\\$projectile \\(pocketmine\\\\entity\\\\projectile\\\\Projectile\\) does not accept pocketmine\\\\entity\\\\Entity\\.$#" count: 1 path: ../../../src/event/entity/EntityShootBowEvent.php - - - message: "#^Method pocketmine\\\\event\\\\entity\\\\ItemDespawnEvent\\:\\:getEntity\\(\\) should return pocketmine\\\\entity\\\\object\\\\ItemEntity but returns pocketmine\\\\entity\\\\Entity\\.$#" - count: 1 - path: ../../../src/event/entity/ItemDespawnEvent.php - - - - message: "#^Method pocketmine\\\\event\\\\entity\\\\ItemSpawnEvent\\:\\:getEntity\\(\\) should return pocketmine\\\\entity\\\\object\\\\ItemEntity but returns pocketmine\\\\entity\\\\Entity\\.$#" - count: 1 - path: ../../../src/event/entity/ItemSpawnEvent.php - - - - message: "#^Method pocketmine\\\\event\\\\entity\\\\ProjectileHitEvent\\:\\:getEntity\\(\\) should return pocketmine\\\\entity\\\\projectile\\\\Projectile but returns pocketmine\\\\entity\\\\Entity\\.$#" - count: 1 - path: ../../../src/event/entity/ProjectileHitEvent.php - - - - message: "#^Method pocketmine\\\\event\\\\entity\\\\ProjectileLaunchEvent\\:\\:getEntity\\(\\) should return pocketmine\\\\entity\\\\projectile\\\\Projectile but returns pocketmine\\\\entity\\\\Entity\\.$#" - count: 1 - path: ../../../src/event/entity/ProjectileLaunchEvent.php - - message: "#^Cannot instantiate interface pocketmine\\\\world\\\\format\\\\io\\\\WritableWorldProvider\\.$#" count: 1