Merge 'minor-next' into 'major-next'

Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/12643390650
This commit is contained in:
pmmp-admin-bot[bot] 2025-01-07 01:24:48 +00:00
commit 708784b0a2
74 changed files with 156 additions and 230 deletions

View File

@ -253,12 +253,12 @@ final class MemoryDump{
}
/**
* @param object[] $objects reference parameter
* @param int[] $refCounts reference parameter
* @param object[]|true[] $objects reference parameter
* @param int[] $refCounts reference parameter
*
* @phpstan-param array<string, object> $objects
* @phpstan-param array<string, object|true> $objects
* @phpstan-param array<string, int> $refCounts
* @phpstan-param-out array<string, object> $objects
* @phpstan-param-out array<string, object|true> $objects
* @phpstan-param-out array<string, int> $refCounts
*/
private static function continueDump(mixed $from, array &$objects, array &$refCounts, int $recursion, int $maxNesting, int $maxStringSize) : mixed{

View File

@ -70,9 +70,6 @@ class Anvil extends Transparent implements Fallable{
return $this;
}
/**
* @return AxisAlignedBB[]
*/
protected function recalculateCollisionBoxes() : array{
return [AxisAlignedBB::one()->squash(Facing::axis(Facing::rotateY($this->facing, false)), 1 / 8)];
}

View File

@ -87,9 +87,6 @@ class Bamboo extends Transparent{
return $this;
}
/**
* @return AxisAlignedBB[]
*/
protected function recalculateCollisionBoxes() : array{
//this places the BB at the northwest corner, not the center
$inset = 1 - (($this->thick ? 3 : 2) / 16);

View File

@ -30,7 +30,6 @@ use pocketmine\block\utils\SupportType;
use pocketmine\item\Banner as ItemBanner;
use pocketmine\item\Item;
use pocketmine\item\VanillaItems;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Vector3;
use pocketmine\player\Player;
use pocketmine\world\BlockTransaction;
@ -97,9 +96,6 @@ abstract class BaseBanner extends Transparent{
return $this;
}
/**
* @return AxisAlignedBB[]
*/
protected function recalculateCollisionBoxes() : array{
return [];
}

View File

@ -34,7 +34,6 @@ use pocketmine\event\block\SignChangeEvent;
use pocketmine\item\Dye;
use pocketmine\item\Item;
use pocketmine\item\ItemTypeIds;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Vector3;
use pocketmine\player\Player;
use pocketmine\utils\TextFormat;
@ -95,9 +94,6 @@ abstract class BaseSign extends Transparent{
return 16;
}
/**
* @return AxisAlignedBB[]
*/
protected function recalculateCollisionBoxes() : array{
return [];
}

View File

@ -76,9 +76,6 @@ class Bed extends Transparent{
}
}
/**
* @return AxisAlignedBB[]
*/
protected function recalculateCollisionBoxes() : array{
return [AxisAlignedBB::one()->trim(Facing::UP, 7 / 16)];
}

View File

@ -75,7 +75,10 @@ class Block{
protected BlockTypeInfo $typeInfo;
protected Position $position;
/** @var AxisAlignedBB[]|null */
/**
* @var AxisAlignedBB[]|null
* @phpstan-var list<AxisAlignedBB>|null
*/
protected ?array $collisionBoxes = null;
private int $requiredBlockItemStateDataBits;
@ -907,6 +910,7 @@ class Block{
* - anti-cheat checks in plugins
*
* @return AxisAlignedBB[]
* @phpstan-return list<AxisAlignedBB>
*/
final public function getCollisionBoxes() : array{
if($this->collisionBoxes === null){
@ -931,6 +935,7 @@ class Block{
/**
* @return AxisAlignedBB[]
* @phpstan-return list<AxisAlignedBB>
*/
protected function recalculateCollisionBoxes() : array{
return [AxisAlignedBB::one()];

View File

@ -95,7 +95,7 @@ class BlockBreakInfo{
* Returns whether this block can be instantly broken.
*/
public function breaksInstantly() : bool{
return $this->hardness == 0.0;
return $this->hardness === 0.0;
}
/**

View File

@ -43,9 +43,6 @@ class Cactus extends Transparent{
return true;
}
/**
* @return AxisAlignedBB[]
*/
protected function recalculateCollisionBoxes() : array{
$shrinkSize = 1 / 16;
return [AxisAlignedBB::one()->contract($shrinkSize, 0, $shrinkSize)->trim(Facing::UP, $shrinkSize)];

View File

@ -40,9 +40,6 @@ class Cake extends BaseCake{
$w->boundedIntAuto(0, self::MAX_BITES, $this->bites);
}
/**
* @return AxisAlignedBB[]
*/
protected function recalculateCollisionBoxes() : array{
return [
AxisAlignedBB::one()

View File

@ -36,9 +36,6 @@ class CakeWithCandle extends BaseCake{
onInteract as onInteractCandle;
}
/**
* @return AxisAlignedBB[]
*/
protected function recalculateCollisionBoxes() : array{
return [
AxisAlignedBB::one()

View File

@ -36,9 +36,6 @@ class Carpet extends Flowable{
return true;
}
/**
* @return AxisAlignedBB[]
*/
protected function recalculateCollisionBoxes() : array{
return [AxisAlignedBB::one()->trim(Facing::UP, 15 / 16)];
}

View File

@ -36,9 +36,6 @@ use pocketmine\player\Player;
class Chest extends Transparent{
use FacesOppositePlacingPlayerTrait;
/**
* @return AxisAlignedBB[]
*/
protected function recalculateCollisionBoxes() : array{
//these are slightly bigger than in PC
return [AxisAlignedBB::one()->contract(0.025, 0, 0.025)->trim(Facing::UP, 0.05)];

View File

@ -50,9 +50,6 @@ class CocoaBlock extends Flowable{
$w->boundedIntAuto(0, self::MAX_AGE, $this->age);
}
/**
* @return AxisAlignedBB[]
*/
protected function recalculateCollisionBoxes() : array{
return [
AxisAlignedBB::one()

View File

@ -62,9 +62,6 @@ class DaylightSensor extends Transparent{
return 300;
}
/**
* @return AxisAlignedBB[]
*/
protected function recalculateCollisionBoxes() : array{
return [AxisAlignedBB::one()->trim(Facing::UP, 10 / 16)];
}

View File

@ -95,9 +95,6 @@ class Door extends Transparent{
return false;
}
/**
* @return AxisAlignedBB[]
*/
protected function recalculateCollisionBoxes() : array{
//TODO: doors are 0.1825 blocks thick, instead of 0.1875 like JE (https://bugs.mojang.com/browse/MCPE-19214)
return [AxisAlignedBB::one()->trim($this->open ? Facing::rotateY($this->facing, !$this->hingeRight) : $this->facing, 327 / 400)];

View File

@ -33,9 +33,6 @@ use pocketmine\player\Player;
class EnchantingTable extends Transparent{
/**
* @return AxisAlignedBB[]
*/
protected function recalculateCollisionBoxes() : array{
return [AxisAlignedBB::one()->trim(Facing::UP, 0.25)];
}

View File

@ -50,9 +50,6 @@ class EndPortalFrame extends Opaque{
return 1;
}
/**
* @return AxisAlignedBB[]
*/
protected function recalculateCollisionBoxes() : array{
return [AxisAlignedBB::one()->trim(Facing::UP, 3 / 16)];
}

View File

@ -52,9 +52,6 @@ class EndRod extends Flowable{
return 14;
}
/**
* @return AxisAlignedBB[]
*/
protected function recalculateCollisionBoxes() : array{
$myAxis = Facing::axis($this->facing);

View File

@ -40,9 +40,6 @@ class EnderChest extends Transparent{
return 7;
}
/**
* @return AxisAlignedBB[]
*/
protected function recalculateCollisionBoxes() : array{
//these are slightly bigger than in PC
return [AxisAlignedBB::one()->contract(0.025, 0, 0.025)->trim(Facing::UP, 0.05)];

View File

@ -94,9 +94,6 @@ class Farmland extends Transparent{
return $this;
}
/**
* @return AxisAlignedBB[]
*/
protected function recalculateCollisionBoxes() : array{
return [AxisAlignedBB::one()->trim(Facing::UP, 1 / 16)];
}

View File

@ -54,13 +54,9 @@ class Fence extends Transparent{
return $this;
}
/**
* @return AxisAlignedBB[]
*/
protected function recalculateCollisionBoxes() : array{
$inset = 0.5 - $this->getThickness() / 2;
/** @var AxisAlignedBB[] $bbs */
$bbs = [];
$connectWest = isset($this->connections[Facing::WEST]);

View File

@ -64,9 +64,6 @@ class FenceGate extends Transparent{
return $this;
}
/**
* @return AxisAlignedBB[]
*/
protected function recalculateCollisionBoxes() : array{
return $this->open ? [] : [AxisAlignedBB::one()->extend(Facing::UP, 0.5)->squash(Facing::axis($this->facing), 6 / 16)];
}

View File

@ -24,7 +24,6 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\utils\SupportType;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Vector3;
/**
@ -46,9 +45,6 @@ abstract class Flowable extends Transparent{
parent::canBePlacedAt($blockReplace, $clickVector, $face, $isClickedBlock);
}
/**
* @return AxisAlignedBB[]
*/
protected function recalculateCollisionBoxes() : array{
return [];
}

View File

@ -83,9 +83,6 @@ class FlowerPot extends Flowable{
return $block->hasTypeTag(BlockTypeTags::POTTABLE_PLANTS);
}
/**
* @return AxisAlignedBB[]
*/
protected function recalculateCollisionBoxes() : array{
return [AxisAlignedBB::one()->contract(3 / 16, 0, 3 / 16)->trim(Facing::UP, 5 / 8)];
}

View File

@ -28,7 +28,6 @@ use pocketmine\block\utils\MultiAnySupportTrait;
use pocketmine\block\utils\SupportType;
use pocketmine\item\Fertilizer;
use pocketmine\item\Item;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Facing;
use pocketmine\math\Vector3;
use pocketmine\player\Player;
@ -47,9 +46,6 @@ class GlowLichen extends Transparent{
return false;
}
/**
* @return AxisAlignedBB[]
*/
protected function recalculateCollisionBoxes() : array{
return [];
}

View File

@ -29,9 +29,6 @@ use pocketmine\math\Facing;
class GrassPath extends Transparent{
/**
* @return AxisAlignedBB[]
*/
protected function recalculateCollisionBoxes() : array{
return [AxisAlignedBB::one()->trim(Facing::UP, 1 / 16)];
}

View File

@ -58,9 +58,6 @@ class Ladder extends Transparent{
return true;
}
/**
* @return AxisAlignedBB[]
*/
protected function recalculateCollisionBoxes() : array{
return [AxisAlignedBB::one()->trim($this->facing, 13 / 16)];
}

View File

@ -59,9 +59,6 @@ class Lantern extends Transparent{
return $this->lightLevel;
}
/**
* @return AxisAlignedBB[]
*/
protected function recalculateCollisionBoxes() : array{
return [
AxisAlignedBB::one()

View File

@ -30,7 +30,6 @@ use pocketmine\data\runtime\RuntimeDataDescriber;
use pocketmine\entity\Entity;
use pocketmine\event\block\BlockSpreadEvent;
use pocketmine\item\Item;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Facing;
use pocketmine\math\Vector3;
use pocketmine\utils\Utils;
@ -89,9 +88,6 @@ abstract class Liquid extends Transparent{
return false;
}
/**
* @return AxisAlignedBB[]
*/
protected function recalculateCollisionBoxes() : array{
return [];
}

View File

@ -104,9 +104,6 @@ class MobHead extends Flowable{
return $this;
}
/**
* @return AxisAlignedBB[]
*/
protected function recalculateCollisionBoxes() : array{
$collisionBox = AxisAlignedBB::one()
->contract(0.25, 0, 0.25)

View File

@ -28,7 +28,6 @@ use pocketmine\data\runtime\RuntimeDataDescriber;
use pocketmine\entity\Entity;
use pocketmine\item\Item;
use pocketmine\math\Axis;
use pocketmine\math\AxisAlignedBB;
class NetherPortal extends Transparent{
@ -62,9 +61,6 @@ class NetherPortal extends Transparent{
return false;
}
/**
* @return AxisAlignedBB[]
*/
protected function recalculateCollisionBoxes() : array{
return [];
}

View File

@ -79,9 +79,6 @@ class RedstoneComparator extends Flowable{
return $this;
}
/**
* @return AxisAlignedBB[]
*/
protected function recalculateCollisionBoxes() : array{
return [AxisAlignedBB::one()->trim(Facing::UP, 7 / 8)];
}

View File

@ -62,9 +62,6 @@ class RedstoneRepeater extends Flowable{
return $this;
}
/**
* @return AxisAlignedBB[]
*/
protected function recalculateCollisionBoxes() : array{
return [AxisAlignedBB::one()->trim(Facing::UP, 7 / 8)];
}

View File

@ -26,7 +26,6 @@ namespace pocketmine\block;
use pocketmine\block\utils\SupportType;
use pocketmine\data\runtime\RuntimeDataDescriber;
use pocketmine\item\Item;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Vector3;
use pocketmine\player\Player;
use pocketmine\world\BlockTransaction;
@ -70,9 +69,6 @@ class SeaPickle extends Transparent{
return $this->underwater ? ($this->count + 1) * 3 : 0;
}
/**
* @return AxisAlignedBB[]
*/
protected function recalculateCollisionBoxes() : array{
return [];
}

View File

@ -93,9 +93,6 @@ class Slab extends Transparent{
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
}
/**
* @return AxisAlignedBB[]
*/
protected function recalculateCollisionBoxes() : array{
if($this->slabType === SlabType::DOUBLE){
return [AxisAlignedBB::one()];

View File

@ -65,9 +65,6 @@ class SnowLayer extends Flowable implements Fallable{
return $this->layers < self::MAX_LAYERS;
}
/**
* @return AxisAlignedBB[]
*/
protected function recalculateCollisionBoxes() : array{
//TODO: this zero-height BB is intended to stay in lockstep with a MCPE bug
return [AxisAlignedBB::one()->trim(Facing::UP, $this->layers >= 4 ? 0.5 : 1)];

View File

@ -28,9 +28,6 @@ use pocketmine\math\Facing;
class SoulSand extends Opaque{
/**
* @return AxisAlignedBB[]
*/
protected function recalculateCollisionBoxes() : array{
return [AxisAlignedBB::one()->trim(Facing::UP, 1 / 8)];
}

View File

@ -56,7 +56,6 @@ class Thin extends Transparent{
protected function recalculateCollisionBoxes() : array{
$inset = 7 / 16;
/** @var AxisAlignedBB[] $bbs */
$bbs = [];
if(isset($this->connections[Facing::WEST]) || isset($this->connections[Facing::EAST])){

View File

@ -62,9 +62,6 @@ class Trapdoor extends Transparent{
return $this;
}
/**
* @return AxisAlignedBB[]
*/
protected function recalculateCollisionBoxes() : array{
return [AxisAlignedBB::one()->trim($this->open ? $this->facing : ($this->top ? Facing::DOWN : Facing::UP), 13 / 16)];
}

View File

@ -33,9 +33,6 @@ class WaterLily extends Flowable{
canBePlacedAt as supportedWhenPlacedAt;
}
/**
* @return AxisAlignedBB[]
*/
protected function recalculateCollisionBoxes() : array{
return [AxisAlignedBB::one()->contract(1 / 16, 0, 1 / 16)->trim(Facing::UP, 63 / 64)];
}

View File

@ -43,7 +43,10 @@ trait CandleTrait{
return $this->lit ? 3 : 0;
}
/** @see Block::onInteract() */
/**
* @param Item[] &$returnedItems
* @see Block::onInteract()
*/
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
if($item->getTypeId() === ItemTypeIds::FIRE_CHARGE || $item->getTypeId() === ItemTypeIds::FLINT_AND_STEEL || $item->hasEnchantment(VanillaEnchantments::FIRE_ASPECT())){
if($this->lit){

View File

@ -23,6 +23,7 @@ declare(strict_types=1);
namespace pocketmine\block\utils;
use pocketmine\block\Block;
use pocketmine\data\runtime\RuntimeDataDescriber;
use pocketmine\item\Axe;
use pocketmine\item\Item;
@ -58,6 +59,10 @@ trait CopperTrait{
return $this;
}
/**
* @param Item[] &$returnedItems
* @see Block::onInteract()
*/
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
if(!$this->waxed && $item->getTypeId() === ItemTypeIds::HONEYCOMB){
$this->waxed = true;

View File

@ -33,6 +33,7 @@ use pocketmine\permission\PermissionManager;
use pocketmine\Server;
use pocketmine\utils\BroadcastLoggerForwarder;
use pocketmine\utils\TextFormat;
use function array_values;
use function explode;
use function implode;
use function str_replace;
@ -80,6 +81,7 @@ abstract class Command{
/**
* @param string[] $args
* @phpstan-param list<string> $args
*
* @return mixed
* @throws CommandException
@ -213,6 +215,7 @@ abstract class Command{
* @phpstan-param list<string> $aliases
*/
public function setAliases(array $aliases) : void{
$aliases = array_values($aliases); //because plugins can and will pass crap
$this->aliases = $aliases;
if(!$this->isRegistered()){
$this->activeAliases = $aliases;

View File

@ -121,6 +121,7 @@ class FormattedCommandAlias extends Command{
/**
* @param string[] $args
* @phpstan-param list<string> $args
*/
private function buildCommand(string $formatString, array $args) : ?string{
$index = 0;

View File

@ -73,6 +73,7 @@ use pocketmine\timings\Timings;
use pocketmine\utils\TextFormat;
use pocketmine\utils\Utils;
use function array_shift;
use function array_values;
use function count;
use function implode;
use function str_contains;
@ -163,7 +164,7 @@ class SimpleCommandMap implements CommandMap{
unset($aliases[$index]);
}
}
$command->setAliases($aliases);
$command->setAliases(array_values($aliases));
if(!$registered){
$command->setLabel($fallbackPrefix . ":" . $label);

View File

@ -46,6 +46,8 @@ use function fwrite;
use function http_build_query;
use function implode;
use function is_array;
use function is_int;
use function is_string;
use function json_decode;
use function mkdir;
use function strtolower;
@ -178,7 +180,7 @@ class TimingsCommand extends VanillaCommand{
return;
}
$response = json_decode($result->getBody(), true);
if(is_array($response) && isset($response["id"])){
if(is_array($response) && isset($response["id"]) && (is_int($response["id"]) || is_string($response["id"]))){
Command::broadcastCommandMessage($sender, KnownTranslationFactory::pocketmine_command_timings_timingsRead(
"https://" . $host . "/?id=" . $response["id"]));
}else{

View File

@ -76,7 +76,7 @@ class Attribute{
throw new \InvalidArgumentException("Minimum $minValue is greater than the maximum $max");
}
if($this->minValue != $minValue){
if($this->minValue !== $minValue){
$this->desynchronized = true;
$this->minValue = $minValue;
}
@ -95,7 +95,7 @@ class Attribute{
throw new \InvalidArgumentException("Maximum $maxValue is less than the minimum $min");
}
if($this->maxValue != $maxValue){
if($this->maxValue !== $maxValue){
$this->desynchronized = true;
$this->maxValue = $maxValue;
}
@ -140,7 +140,7 @@ class Attribute{
$value = min(max($value, $this->getMinValue()), $this->getMaxValue());
}
if($this->currentValue != $value){
if($this->currentValue !== $value){
$this->desynchronized = true;
$this->currentValue = $value;
}elseif($forceSend){

View File

@ -72,6 +72,7 @@ use function assert;
use function cos;
use function count;
use function deg2rad;
use function floatval;
use function floor;
use function fmod;
use function get_class;
@ -591,7 +592,7 @@ abstract class Entity{
* Sets the health of the Entity. This won't send any update to the players
*/
public function setHealth(float $amount) : void{
if($amount == $this->health){
if($amount === $this->health){
return;
}
@ -760,8 +761,8 @@ abstract class Entity{
$diffMotion = $this->motion->subtractVector($this->lastMotion)->lengthSquared();
$still = $this->motion->lengthSquared() == 0.0;
$wasStill = $this->lastMotion->lengthSquared() == 0.0;
$still = $this->motion->lengthSquared() === 0.0;
$wasStill = $this->lastMotion->lengthSquared() === 0.0;
if($wasStill !== $still){
//TODO: hack for client-side AI interference: prevent client sided movement when motion is 0
$this->setNoClientPredictions($still);
@ -1004,7 +1005,7 @@ abstract class Entity{
abs($this->motion->z) <= self::MOTION_THRESHOLD ? 0 : null
);
if($this->motion->x != 0 || $this->motion->y != 0 || $this->motion->z != 0){
if(floatval($this->motion->x) !== 0.0 || floatval($this->motion->y) !== 0.0 || floatval($this->motion->z) !== 0.0){
$this->move($this->motion->x, $this->motion->y, $this->motion->z);
}
@ -1058,9 +1059,9 @@ abstract class Entity{
public function hasMovementUpdate() : bool{
return (
$this->forceMovementUpdate ||
$this->motion->x != 0 ||
$this->motion->y != 0 ||
$this->motion->z != 0 ||
floatval($this->motion->x) !== 0.0 ||
floatval($this->motion->y) !== 0.0 ||
floatval($this->motion->z) !== 0.0 ||
!$this->onGround
);
}
@ -1163,7 +1164,7 @@ abstract class Entity{
$moveBB->offset(0, $dy, 0);
$fallingFlag = ($this->onGround || ($dy != $wantedY && $wantedY < 0));
$fallingFlag = ($this->onGround || ($dy !== $wantedY && $wantedY < 0));
foreach($list as $bb){
$dx = $bb->calculateXOffset($moveBB, $dx);
@ -1177,7 +1178,7 @@ abstract class Entity{
$moveBB->offset(0, 0, $dz);
if($this->stepHeight > 0 && $fallingFlag && ($wantedX != $dx || $wantedZ != $dz)){
if($this->stepHeight > 0 && $fallingFlag && ($wantedX !== $dx || $wantedZ !== $dz)){
$cx = $dx;
$cy = $dy;
$cz = $dz;
@ -1242,9 +1243,9 @@ abstract class Entity{
$postFallVerticalVelocity = $this->updateFallState($dy, $this->onGround);
$this->motion = $this->motion->withComponents(
$wantedX != $dx ? 0 : null,
$postFallVerticalVelocity ?? ($wantedY != $dy ? 0 : null),
$wantedZ != $dz ? 0 : null
$wantedX !== $dx ? 0 : null,
$postFallVerticalVelocity ?? ($wantedY !== $dy ? 0 : null),
$wantedZ !== $dz ? 0 : null
);
//TODO: vehicle collision events (first we need to spawn them!)
@ -1253,10 +1254,10 @@ abstract class Entity{
}
protected function checkGroundState(float $wantedX, float $wantedY, float $wantedZ, float $dx, float $dy, float $dz) : void{
$this->isCollidedVertically = $wantedY != $dy;
$this->isCollidedHorizontally = ($wantedX != $dx || $wantedZ != $dz);
$this->isCollidedVertically = $wantedY !== $dy;
$this->isCollidedHorizontally = ($wantedX !== $dx || $wantedZ !== $dz);
$this->isCollided = ($this->isCollidedHorizontally || $this->isCollidedVertically);
$this->onGround = ($wantedY != $dy && $wantedY < 0);
$this->onGround = ($wantedY !== $dy && $wantedY < 0);
}
/**

View File

@ -66,7 +66,7 @@ class Location extends Position{
public function equals(Vector3 $v) : bool{
if($v instanceof Location){
return parent::equals($v) && $v->yaw == $this->yaw && $v->pitch == $this->pitch;
return parent::equals($v) && $v->yaw === $this->yaw && $v->pitch === $this->pitch;
}
return parent::equals($v);
}

View File

@ -118,7 +118,6 @@ use pocketmine\world\Position;
use pocketmine\world\World;
use pocketmine\YmlServerProperties;
use function array_map;
use function array_values;
use function base64_encode;
use function bin2hex;
use function count;
@ -164,7 +163,10 @@ class NetworkSession{
private ?EncryptionContext $cipher = null;
/** @var string[] */
/**
* @var string[]
* @phpstan-var list<string>
*/
private array $sendBuffer = [];
/**
* @var PromiseResolver[]
@ -544,6 +546,7 @@ class NetworkSession{
* @phpstan-return Promise<true>
*/
public function sendDataPacketWithReceipt(ClientboundPacket $packet, bool $immediate = false) : Promise{
/** @phpstan-var PromiseResolver<true> $resolver */
$resolver = new PromiseResolver();
if(!$this->sendDataPacketInternal($packet, $immediate, $resolver)){
@ -1106,7 +1109,7 @@ class NetworkSession{
//work around a client bug which makes the original name not show when aliases are used
$aliases[] = $lname;
}
$aliasObj = new CommandEnum(ucfirst($command->getLabel()) . "Aliases", array_values($aliases));
$aliasObj = new CommandEnum(ucfirst($command->getLabel()) . "Aliases", $aliases);
}
$description = $command->getDescription();

View File

@ -416,7 +416,7 @@ class InGamePacketHandler extends PacketHandler{
$droppedCount = null;
foreach($data->getActions() as $networkInventoryAction){
if($networkInventoryAction->sourceType === NetworkInventoryAction::SOURCE_WORLD && $networkInventoryAction->inventorySlot == NetworkInventoryAction::ACTION_MAGIC_SLOT_DROP_ITEM){
if($networkInventoryAction->sourceType === NetworkInventoryAction::SOURCE_WORLD && $networkInventoryAction->inventorySlot === NetworkInventoryAction::ACTION_MAGIC_SLOT_DROP_ITEM){
$droppedCount = $networkInventoryAction->newItem->getItemStack()->getCount();
if($droppedCount <= 0){
throw new PacketHandlingException("Expected positive count for dropped item");
@ -578,7 +578,7 @@ class InGamePacketHandler extends PacketHandler{
private function handleReleaseItemTransaction(ReleaseItemTransactionData $data) : bool{
$this->player->selectHotbarSlot($data->getHotbarSlot());
if($data->getActionType() == ReleaseItemTransactionData::ACTION_RELEASE){
if($data->getActionType() === ReleaseItemTransactionData::ACTION_RELEASE){
$this->player->releaseHeldItem();
return true;
}

View File

@ -84,11 +84,20 @@ class PluginDescription{
* @phpstan-var array<string, list<string>>
*/
private array $extensions = [];
/** @var string[] */
/**
* @var string[]
* @phpstan-var list<string>
*/
private array $depend = [];
/** @var string[] */
/**
* @var string[]
* @phpstan-var list<string>
*/
private array $softDepend = [];
/** @var string[] */
/**
* @var string[]
* @phpstan-var list<string>
*/
private array $loadBefore = [];
private string $version;
/**
@ -173,7 +182,7 @@ class PluginDescription{
}
if(isset($plugin[self::KEY_DEPEND])){
$this->depend = (array) $plugin[self::KEY_DEPEND];
$this->depend = array_values((array) $plugin[self::KEY_DEPEND]);
}
if(isset($plugin[self::KEY_EXTENSIONS])){
$extensions = (array) $plugin[self::KEY_EXTENSIONS];
@ -183,13 +192,13 @@ class PluginDescription{
$k = $v;
$v = "*";
}
$this->extensions[(string) $k] = array_map('strval', is_array($v) ? $v : [$v]);
$this->extensions[(string) $k] = array_values(array_map('strval', is_array($v) ? $v : [$v]));
}
}
$this->softDepend = (array) ($plugin[self::KEY_SOFTDEPEND] ?? $this->softDepend);
$this->softDepend = array_values((array) ($plugin[self::KEY_SOFTDEPEND] ?? $this->softDepend));
$this->loadBefore = (array) ($plugin[self::KEY_LOADBEFORE] ?? $this->loadBefore);
$this->loadBefore = array_values((array) ($plugin[self::KEY_LOADBEFORE] ?? $this->loadBefore));
$this->website = (string) ($plugin[self::KEY_WEBSITE] ?? $this->website);
@ -210,7 +219,7 @@ class PluginDescription{
$this->authors = [];
if(isset($plugin[self::KEY_AUTHOR])){
if(is_array($plugin[self::KEY_AUTHOR])){
$this->authors = $plugin[self::KEY_AUTHOR];
$this->authors = array_values($plugin[self::KEY_AUTHOR]);
}else{
$this->authors[] = $plugin[self::KEY_AUTHOR];
}
@ -284,6 +293,7 @@ class PluginDescription{
/**
* @return string[]
* @phpstan-return list<string>
*/
public function getDepend() : array{
return $this->depend;
@ -295,6 +305,7 @@ class PluginDescription{
/**
* @return string[]
* @phpstan-return list<string>
*/
public function getLoadBefore() : array{
return $this->loadBefore;
@ -324,6 +335,7 @@ class PluginDescription{
/**
* @return string[]
* @phpstan-return list<string>
*/
public function getSoftDepend() : array{
return $this->softDepend;

View File

@ -31,12 +31,12 @@ final class PluginLoadTriage{
public array $plugins = [];
/**
* @var string[][]
* @phpstan-var array<string, list<string>>
* @phpstan-var array<string, array<string>>
*/
public array $dependencies = [];
/**
* @var string[][]
* @phpstan-var array<string, list<string>>
* @phpstan-var array<string, array<string>>
*/
public array $softDependencies = [];
}

View File

@ -327,12 +327,12 @@ class PluginManager{
* @param string[][] $dependencyLists
* @param Plugin[] $loadedPlugins
*
* @phpstan-param array<string, list<string>> $dependencyLists
* @phpstan-param-out array<string, list<string>> $dependencyLists
* @phpstan-param array<string, array<string>> $dependencyLists
* @phpstan-param-out array<string, array<string>> $dependencyLists
*/
private function checkDepsForTriage(string $pluginName, string $dependencyType, array &$dependencyLists, array $loadedPlugins, PluginLoadTriage $triage) : void{
if(isset($dependencyLists[$pluginName])){
foreach($dependencyLists[$pluginName] as $key => $dependency){
foreach(Utils::promoteKeys($dependencyLists[$pluginName]) as $key => $dependency){
if(isset($loadedPlugins[$dependency]) || $this->getPlugin($dependency) instanceof Plugin){
$this->server->getLogger()->debug("Successfully resolved $dependencyType dependency \"$dependency\" for plugin \"$pluginName\"");
unset($dependencyLists[$pluginName][$key]);
@ -399,7 +399,7 @@ class PluginManager{
//check for skippable soft dependencies first, in case the dependents could resolve hard dependencies
foreach(Utils::stringifyKeys($triage->plugins) as $name => $file){
if(isset($triage->softDependencies[$name]) && !isset($triage->dependencies[$name])){
foreach($triage->softDependencies[$name] as $k => $dependency){
foreach(Utils::promoteKeys($triage->softDependencies[$name]) as $k => $dependency){
if($this->getPlugin($dependency) === null && !array_key_exists($dependency, $triage->plugins)){
$this->server->getLogger()->debug("Skipping resolution of missing soft dependency \"$dependency\" for plugin \"$name\"");
unset($triage->softDependencies[$name][$k]);
@ -416,7 +416,7 @@ class PluginManager{
if(isset($triage->dependencies[$name])){
$unknownDependencies = [];
foreach($triage->dependencies[$name] as $k => $dependency){
foreach($triage->dependencies[$name] as $dependency){
if($this->getPlugin($dependency) === null && !array_key_exists($dependency, $triage->plugins)){
//assume that the plugin is never going to be loaded
//by this point all soft dependencies have been ignored if they were able to be, so

View File

@ -72,7 +72,7 @@ class Config{
/**
* @var mixed[]
* @phpstan-var array<string, mixed>
* @phpstan-var array<mixed, mixed>
*/
private array $config = [];
@ -450,7 +450,7 @@ class Config{
/**
* @return mixed[]
* @phpstan-return list<string>|array<string, mixed>
* @phpstan-return list<mixed>|array<mixed, mixed>
*/
public function getAll(bool $keys = false) : array{
return ($keys ? array_keys($this->config) : $this->config);
@ -458,7 +458,6 @@ class Config{
/**
* @param mixed[] $defaults
* @phpstan-param array<string, mixed> $defaults
*/
public function setDefaults(array $defaults) : void{
$this->fillDefaults($defaults, $this->config);
@ -467,13 +466,11 @@ class Config{
/**
* @param mixed[] $default
* @param mixed[] $data reference parameter
* @phpstan-param array<string, mixed> $default
* @phpstan-param array<string, mixed> $data
* @phpstan-param-out array<string, mixed> $data
* @phpstan-param-out array<mixed, mixed> $data
*/
private function fillDefaults(array $default, array &$data) : int{
$changed = 0;
foreach(Utils::stringifyKeys($default) as $k => $v){
foreach(Utils::promoteKeys($default) as $k => $v){
if(is_array($v)){
if(!isset($data[$k]) || !is_array($data[$k])){
$data[$k] = [];
@ -509,8 +506,8 @@ class Config{
}
/**
* @param string[] $entries
* @phpstan-param list<string> $entries
* @param string[]|int[] $entries
* @phpstan-param list<int|string> $entries
*/
public static function writeList(array $entries) : string{
return implode("\n", $entries);
@ -518,11 +515,11 @@ class Config{
/**
* @param string[]|int[]|float[]|bool[] $config
* @phpstan-param array<string, string|int|float|bool> $config
* @phpstan-param array<int|string, string|int|float|bool> $config
*/
public static function writeProperties(array $config) : string{
$content = "#Properties Config file\r\n#" . date("D M j H:i:s T Y") . "\r\n";
foreach(Utils::stringifyKeys($config) as $k => $v){
foreach(Utils::promoteKeys($config) as $k => $v){
if(is_bool($v)){
$v = $v ? "on" : "off";
}
@ -534,7 +531,7 @@ class Config{
/**
* @return string[]|int[]|float[]|bool[]
* @phpstan-return array<string, string|int|float|bool>
* @phpstan-return array<int|string, string|int|float|bool>
*/
public static function parseProperties(string $content) : array{
$result = [];
@ -560,7 +557,7 @@ class Config{
};
break;
}
$result[(string) $k] = $v;
$result[$k] = $v;
}
}

View File

@ -39,7 +39,7 @@ final class Git{
* @param bool $dirty reference parameter, set to whether the repo has local changes
*/
public static function getRepositoryState(string $dir, bool &$dirty) : ?string{
if(Process::execute("git -C \"$dir\" rev-parse HEAD", $out) === 0 && $out !== false && strlen($out = trim($out)) === 40){
if(Process::execute("git -C \"$dir\" rev-parse HEAD", $out) === 0 && strlen($out = trim($out)) === 40){
if(Process::execute("git -C \"$dir\" diff --quiet") === 1 || Process::execute("git -C \"$dir\" diff --cached --quiet") === 1){ //Locally-modified
$dirty = true;
}

View File

@ -100,7 +100,7 @@ class Internet{
}
$ip = self::getURL("http://ifconfig.me/ip");
if($ip !== null && ($addr = trim($ip->getBody())) != ""){
if($ip !== null && ($addr = trim($ip->getBody())) !== ""){
return self::$ip = $addr;
}
@ -157,22 +157,21 @@ class Internet{
* POSTs data to an URL
* NOTE: This is a blocking operation and can take a significant amount of time. It is inadvisable to use this method on the main thread.
*
* @phpstan-template TErrorVar of mixed
*
* @param string[]|string $args
* @param string[] $extraHeaders
* @param string|null $err reference parameter, will be set to the output of curl_error(). Use this to retrieve errors that occurred during the operation.
* @phpstan-param string|array<string, string> $args
* @phpstan-param list<string> $extraHeaders
* @phpstan-param TErrorVar $err
* @phpstan-param-out TErrorVar|string $err
* @phpstan-param-out string|null $err
*/
public static function postURL(string $page, array|string $args, int $timeout = 10, array $extraHeaders = [], &$err = null) : ?InternetRequestResult{
try{
return self::simpleCurl($page, $timeout, $extraHeaders, [
$result = self::simpleCurl($page, $timeout, $extraHeaders, [
CURLOPT_POST => 1,
CURLOPT_POSTFIELDS => $args
]);
$err = null;
return $result;
}catch(InternetException $ex){
$err = $ex->getMessage();
return null;

View File

@ -174,8 +174,17 @@ final class Process{
return -1;
}
$stdout = stream_get_contents($pipes[1]);
$stderr = stream_get_contents($pipes[2]);
$out = stream_get_contents($pipes[1]);
if($out === false){
throw new AssumptionFailedError("Presume this can't happen for proc_open ... ???");
}
$stdout = $out;
$err = stream_get_contents($pipes[2]);
if($err === false){
throw new AssumptionFailedError("Presume this can't happen for proc_open ... ???");
}
$stderr = $err;
foreach($pipes as $p){
fclose($p);

View File

@ -24,7 +24,7 @@ declare(strict_types=1);
namespace pocketmine\utils;
/**
* @phpstan-template TPriority
* @phpstan-template TPriority of numeric
* @phpstan-template TValue
* @phpstan-extends \SplPriorityQueue<TPriority, TValue>
*/

View File

@ -36,14 +36,12 @@ use const SIGTERM;
final class SignalHandler{
/** @phpstan-var (\Closure(int) : void)|null */
private ?\Closure $interruptCallback;
private ?\Closure $interruptCallback = null;
/**
* @phpstan-param \Closure() : void $interruptCallback
*/
public function __construct(\Closure $interruptCallback){
$this->interruptCallback = $interruptCallback;
if(function_exists('sapi_windows_set_ctrl_handler')){
sapi_windows_set_ctrl_handler($this->interruptCallback = function(int $signo) use ($interruptCallback) : void{
if($signo === PHP_WINDOWS_EVENT_CTRL_C || $signo === PHP_WINDOWS_EVENT_CTRL_BREAK){

View File

@ -134,7 +134,7 @@ abstract class Timezone{
$offset = $matches[2];
if($offset == ""){
if($offset === ""){
return "UTC";
}
@ -156,7 +156,7 @@ abstract class Timezone{
$offset = trim(exec('date +%:z'));
if($offset == "+00:00"){
if($offset === "+00:00"){
return "UTC";
}
@ -195,7 +195,7 @@ abstract class Timezone{
$offset = $parsed['hour'] * 3600 + $parsed['minute'] * 60 + $parsed['second'];
//After date_parse is done, put the sign back
if($negative_offset == true){
if($negative_offset){
$offset = -abs($offset);
}
@ -204,7 +204,7 @@ abstract class Timezone{
//That's been a bug in PHP since 2008!
foreach(timezone_abbreviations_list() as $zones){
foreach($zones as $timezone){
if($timezone['timezone_id'] !== null && $timezone['offset'] == $offset){
if($timezone['timezone_id'] !== null && $timezone['offset'] === $offset){
return $timezone['timezone_id'];
}
}

View File

@ -220,7 +220,7 @@ final class Utils{
$mac = implode("\n", $mac);
if(preg_match_all("#Physical Address[. ]{1,}: ([0-9A-F\\-]{17})#", $mac, $matches) > 0){
foreach($matches[1] as $i => $v){
if($v == "00-00-00-00-00-00"){
if($v === "00-00-00-00-00-00"){
unset($matches[1][$i]);
}
}
@ -234,7 +234,7 @@ final class Utils{
$mac = implode("\n", $mac);
if(preg_match_all("#HWaddr[ \t]{1,}([0-9a-f:]{17})#", $mac, $matches) > 0){
foreach($matches[1] as $i => $v){
if($v == "00:00:00:00:00:00"){
if($v === "00:00:00:00:00:00"){
unset($matches[1][$i]);
}
}

View File

@ -1364,7 +1364,7 @@ class World implements ChunkManager{
* TODO: phpstan can't infer these types yet :(
* @phpstan-var array<int, LightArray> $blockLight
* @phpstan-var array<int, LightArray> $skyLight
* @phpstan-var array<int, int> $heightMap
* @phpstan-var non-empty-list<int> $heightMap
*/
if($this->unloaded || ($chunk = $this->getChunk($chunkX, $chunkZ)) === null || $chunk->isLightPopulated() === true){
return;
@ -1562,6 +1562,7 @@ class World implements ChunkManager{
* Larger AABBs (>= 2 blocks on any axis) are not accounted for.
*
* @return AxisAlignedBB[]
* @phpstan-return list<AxisAlignedBB>
*/
private function getBlockCollisionBoxesForCell(int $x, int $y, int $z) : array{
$block = $this->getBlockAt($x, $y, $z);
@ -2021,7 +2022,6 @@ class World implements ChunkManager{
* @phpstan-return list<ExperienceOrb>
*/
public function dropExperience(Vector3 $pos, int $amount) : array{
/** @var ExperienceOrb[] $orbs */
$orbs = [];
foreach(ExperienceOrb::splitIntoOrbSizes($amount) as $split){
@ -3064,6 +3064,7 @@ class World implements ChunkManager{
* @phpstan-return Promise<Position>
*/
public function requestSafeSpawn(?Vector3 $spawn = null) : Promise{
/** @phpstan-var PromiseResolver<Position> $resolver */
$resolver = new PromiseResolver();
$spawn ??= $this->getSpawnLocation();
/*
@ -3235,6 +3236,7 @@ class World implements ChunkManager{
private function enqueuePopulationRequest(int $chunkX, int $chunkZ, ?ChunkLoader $associatedChunkLoader) : Promise{
$chunkHash = World::chunkHash($chunkX, $chunkZ);
$this->addChunkHashToPopulationRequestQueue($chunkHash);
/** @phpstan-var PromiseResolver<Chunk> $resolver */
$resolver = $this->chunkPopulationRequestMap[$chunkHash] = new PromiseResolver();
if($associatedChunkLoader === null){
$temporaryLoader = new class implements ChunkLoader{};

View File

@ -57,7 +57,10 @@ class Chunk{
*/
protected \SplFixedArray $subChunks;
/** @var Tile[] */
/**
* @var Tile[]
* @phpstan-var array<int, Tile>
*/
protected array $tiles = [];
protected HeightArray $heightMap;
@ -210,6 +213,7 @@ class Chunk{
/**
* @return Tile[]
* @phpstan-return array<int, Tile>
*/
public function getTiles() : array{
return $this->tiles;
@ -237,6 +241,7 @@ class Chunk{
/**
* @return int[]
* @phpstan-return non-empty-list<int>
*/
public function getHeightMapArray() : array{
return $this->heightMap->getValues();
@ -244,6 +249,7 @@ class Chunk{
/**
* @param int[] $values
* @phpstan-param non-empty-list<int> $values
*/
public function setHeightMapArray(array $values) : void{
$this->heightMap = new HeightArray($values);

View File

@ -36,7 +36,7 @@ final class HeightArray{
/**
* @param int[] $values ZZZZXXXX key bit order
* @phpstan-param list<int> $values
* @phpstan-param non-empty-list<int> $values
*/
public function __construct(array $values){
if(count($values) !== 256){
@ -66,7 +66,7 @@ final class HeightArray{
/**
* @return int[] ZZZZXXXX key bit order
* @phpstan-return list<int>
* @phpstan-return non-empty-list<int>
*/
public function getValues() : array{
return $this->array->toArray();

View File

@ -112,7 +112,6 @@ final class FastChunkSerializer{
$y = Binary::signByte($stream->getByte());
$airBlockId = $stream->getInt();
/** @var PalettedBlockArray[] $layers */
$layers = [];
for($i = 0, $layerCount = $stream->getByte(); $i < $layerCount; ++$i){
$layers[] = self::deserializePalettedArray($stream);

View File

@ -93,10 +93,12 @@ abstract class RegionWorldProvider extends BaseWorldProvider{
}
/**
* @param int $regionX reference parameter
* @param int $regionZ reference parameter
* @param int|null $regionX reference parameter
* @param int|null $regionZ reference parameter
* @phpstan-param-out int $regionX
* @phpstan-param-out int $regionZ
*
* TODO: make this private
*/
public static function getRegionIndex(int $chunkX, int $chunkZ, &$regionX, &$regionZ) : void{
$regionX = $chunkX >> 5;
@ -154,6 +156,8 @@ abstract class RegionWorldProvider extends BaseWorldProvider{
/**
* @return CompoundTag[]
* @phpstan-return list<CompoundTag>
*
* @throws CorruptedChunkException
*/
protected static function getCompoundList(string $context, ListTag $list) : array{

View File

@ -44,7 +44,7 @@ class LightPopulationTask extends AsyncTask{
private string $resultBlockLightArrays;
/**
* @phpstan-param \Closure(array<int, LightArray> $blockLight, array<int, LightArray> $skyLight, array<int, int> $heightMap) : void $onCompletion
* @phpstan-param \Closure(array<int, LightArray> $blockLight, array<int, LightArray> $skyLight, non-empty-list<int> $heightMap) : void $onCompletion
*/
public function __construct(Chunk $chunk, \Closure $onCompletion){
$this->chunk = FastChunkSerializer::serializeTerrain($chunk);
@ -80,7 +80,10 @@ class LightPopulationTask extends AsyncTask{
}
public function onCompletion() : void{
/** @var int[] $heightMapArray */
/**
* @var int[] $heightMapArray
* @phpstan-var non-empty-list<int> $heightMapArray
*/
$heightMapArray = igbinary_unserialize($this->resultHeightMap);
/** @var LightArray[] $skyLightArrays */
@ -90,7 +93,7 @@ class LightPopulationTask extends AsyncTask{
/**
* @var \Closure
* @phpstan-var \Closure(array<int, LightArray> $blockLight, array<int, LightArray> $skyLight, array<int, int> $heightMap) : void
* @phpstan-var \Closure(array<int, LightArray> $blockLight, array<int, LightArray> $skyLight, non-empty-list<int> $heightMap) : void
*/
$callback = $this->fetchLocal(self::TLS_KEY_COMPLETION_CALLBACK);
$callback($blockLightArrays, $skyLightArrays, $heightMapArray);

View File

@ -791,7 +791,7 @@ parameters:
path: ../../../src/utils/Config.php
-
message: "#^Parameter \\#1 \\$config of static method pocketmine\\\\utils\\\\Config\\:\\:writeProperties\\(\\) expects array\\<string, bool\\|float\\|int\\|string\\>, array\\<string, mixed\\> given\\.$#"
message: "#^Parameter \\#1 \\$config of static method pocketmine\\\\utils\\\\Config\\:\\:writeProperties\\(\\) expects array\\<int\\|string, bool\\|float\\|int\\|string\\>, array\\<int\\|string, mixed\\> given\\.$#"
count: 1
path: ../../../src/utils/Config.php

View File

@ -1,20 +1,5 @@
parameters:
ignoreErrors:
-
message: "#^Method pocketmine\\\\block\\\\CakeWithCandle\\:\\:onInteractCandle\\(\\) has parameter \\$returnedItems with no value type specified in iterable type array\\.$#"
count: 1
path: ../../../src/block/CakeWithCandle.php
-
message: "#^Method pocketmine\\\\block\\\\CopperDoor\\:\\:onInteractCopper\\(\\) has parameter \\$returnedItems with no value type specified in iterable type array\\.$#"
count: 1
path: ../../../src/block/CopperDoor.php
-
message: "#^Method pocketmine\\\\block\\\\CopperTrapdoor\\:\\:onInteractCopper\\(\\) has parameter \\$returnedItems with no value type specified in iterable type array\\.$#"
count: 1
path: ../../../src/block/CopperTrapdoor.php
-
message: "#^Method pocketmine\\\\block\\\\DoubleTallGrass\\:\\:traitGetDropsForIncompatibleTool\\(\\) return type has no value type specified in iterable type array\\.$#"
count: 1

View File

@ -16,7 +16,7 @@ parameters:
path: ../../../src/world/format/Chunk.php
-
message: "#^Method pocketmine\\\\world\\\\format\\\\HeightArray\\:\\:getValues\\(\\) should return array\\<int, int\\> but returns array\\<int, int\\|null\\>\\.$#"
message: "#^Method pocketmine\\\\world\\\\format\\\\HeightArray\\:\\:getValues\\(\\) should return non\\-empty\\-array\\<int, int\\> but returns array\\<int, int\\|null\\>\\.$#"
count: 1
path: ../../../src/world/format/HeightArray.php

View File

@ -35,8 +35,12 @@ class BlockTypeIdsTest extends TestCase{
$constants = $reflect->getConstants();
unset($constants['FIRST_UNUSED_BLOCK_ID']);
self::assertNotEmpty($constants, "We should never have zero type IDs");
self::assertSame($reflect->getConstant('FIRST_UNUSED_BLOCK_ID'), max($constants) + 1, "FIRST_UNUSED_BLOCK_ID must be one higher than the highest fixed type ID");
$max = max($constants);
self::assertIsInt($max, "Max type ID should always be an integer");
self::assertSame($reflect->getConstant('FIRST_UNUSED_BLOCK_ID'), $max + 1, "FIRST_UNUSED_BLOCK_ID must be one higher than the highest fixed type ID");
}
public function testNoDuplicates() : void{

View File

@ -35,8 +35,12 @@ class ItemTypeIdsTest extends TestCase{
$constants = $reflect->getConstants();
unset($constants['FIRST_UNUSED_ITEM_ID']);
self::assertNotEmpty($constants, "We should never have zero type IDs");
self::assertSame($reflect->getConstant('FIRST_UNUSED_ITEM_ID'), max($constants) + 1, "FIRST_UNUSED_ITEM_ID must be one higher than the highest fixed type ID");
$max = max($constants);
self::assertIsInt($max, "Max type ID should always be an integer");
self::assertSame($reflect->getConstant('FIRST_UNUSED_ITEM_ID'), $max + 1, "FIRST_UNUSED_ITEM_ID must be one higher than the highest fixed type ID");
}
public function testNoDuplicates() : void{