diff --git a/composer.json b/composer.json index 5ad75593d..ba334459b 100644 --- a/composer.json +++ b/composer.json @@ -54,7 +54,7 @@ "webmozart/path-util": "^2.3" }, "require-dev": { - "phpstan/phpstan": "1.8.8", + "phpstan/phpstan": "1.8.9", "phpstan/phpstan-phpunit": "^1.1.0", "phpstan/phpstan-strict-rules": "^1.2.0", "phpunit/phpunit": "^9.2" diff --git a/composer.lock b/composer.lock index daa8ca40c..ede3e8afe 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "2c6e95f77e3aa27ede46bd06716e178b", + "content-hash": "f652fc7867f7fd3d183df26e44658cd0", "packages": [ { "name": "adhocore/json-comment", @@ -1822,16 +1822,16 @@ }, { "name": "phpstan/phpstan", - "version": "1.8.8", + "version": "1.8.9", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "08310ce271984587e2a4cda94e1ac66510a6ea07" + "reference": "3a72d9d9f2528fbd50c2d8fcf155fd9f74ade3f2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/08310ce271984587e2a4cda94e1ac66510a6ea07", - "reference": "08310ce271984587e2a4cda94e1ac66510a6ea07", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/3a72d9d9f2528fbd50c2d8fcf155fd9f74ade3f2", + "reference": "3a72d9d9f2528fbd50c2d8fcf155fd9f74ade3f2", "shasum": "" }, "require": { @@ -1861,7 +1861,7 @@ ], "support": { "issues": "https://github.com/phpstan/phpstan/issues", - "source": "https://github.com/phpstan/phpstan/tree/1.8.8" + "source": "https://github.com/phpstan/phpstan/tree/1.8.9" }, "funding": [ { @@ -1877,7 +1877,7 @@ "type": "tidelift" } ], - "time": "2022-10-06T12:51:57+00:00" + "time": "2022-10-13T13:40:18+00:00" }, { "name": "phpstan/phpstan-phpunit", diff --git a/src/entity/object/FallingBlock.php b/src/entity/object/FallingBlock.php index 5d3018d4b..b9af0237c 100644 --- a/src/entity/object/FallingBlock.php +++ b/src/entity/object/FallingBlock.php @@ -117,7 +117,6 @@ class FallingBlock extends Entity{ $block = $world->getBlock($pos); if(!$block->canBeReplaced() || !$world->isInWorld($pos->getFloorX(), $pos->getFloorY(), $pos->getFloorZ()) || ($this->onGround && abs($this->location->y - $this->location->getFloorY()) > 0.001)){ - //FIXME: anvils are supposed to destroy torches $world->dropItem($this->location, $this->block->asItem()); }else{ $ev = new EntityBlockChangeEvent($this, $block, $blockTarget ?? $this->block); diff --git a/src/world/World.php b/src/world/World.php index 7c8522ae2..0071f221f 100644 --- a/src/world/World.php +++ b/src/world/World.php @@ -129,6 +129,11 @@ use const PHP_INT_MIN; #include +/** + * @phpstan-type ChunkPosHash int + * @phpstan-type BlockPosHash int + * @phpstan-type ChunkBlockPosHash int + */ class World implements ChunkManager{ private static int $worldIdCounter = 1; @@ -152,28 +157,40 @@ class World implements ChunkManager{ public const DEFAULT_TICKED_BLOCKS_PER_SUBCHUNK_PER_TICK = 3; - /** @var Player[] */ + /** + * @var Player[] entity runtime ID => Player + * @phpstan-var array + */ private array $players = []; - /** @var Entity[] */ + /** + * @var Entity[] entity runtime ID => Entity + * @phpstan-var array + */ private array $entities = []; /** - * @var Vector3[] + * @var Vector3[] entity runtime ID => Vector3 * @phpstan-var array */ private array $entityLastKnownPositions = []; /** - * @var Entity[][] - * @phpstan-var array> + * @var Entity[][] chunkHash => [entity runtime ID => Entity] + * @phpstan-var array> */ private array $entitiesByChunk = []; - /** @var Entity[] */ + /** + * @var Entity[] entity runtime ID => Entity + * @phpstan-var array + */ public $updateEntities = []; private bool $inDynamicStateRecalculation = false; - /** @var Block[][] */ + /** + * @var Block[][] chunkHash => [relativeBlockHash => Block] + * @phpstan-var array> + */ private array $blockCache = []; private int $sendTimeTicker = 0; @@ -185,22 +202,43 @@ class World implements ChunkManager{ private int $minY; private int $maxY; - /** @var TickingChunkLoader[] */ + /** + * @var TickingChunkLoader[] spl_object_id => TickingChunkLoader + * @phpstan-var array + */ private array $tickingLoaders = []; - /** @var int[] */ + /** + * @var int[] spl_object_id => number of chunks + * @phpstan-var array + */ private array $tickingLoaderCounter = []; - /** @var ChunkLoader[][] */ + /** + * @var ChunkLoader[][] chunkHash => [spl_object_id => ChunkLoader] + * @phpstan-var array> + */ private array $chunkLoaders = []; - /** @var ChunkListener[][] */ + /** + * @var ChunkListener[][] chunkHash => [spl_object_id => ChunkListener] + * @phpstan-var array> + */ private array $chunkListeners = []; - /** @var Player[][] */ + /** + * @var Player[][] chunkHash => [spl_object_id => Player] + * @phpstan-var array> + */ private array $playerChunkListeners = []; - /** @var ClientboundPacket[][] */ + /** + * @var ClientboundPacket[][] + * @phpstan-var array> + */ private array $packetBuffersByChunk = []; - /** @var float[] */ + /** + * @var float[] chunkHash => timestamp of request + * @phpstan-var array + */ private array $unloadQueue = []; private int $time; @@ -213,44 +251,65 @@ class World implements ChunkManager{ private string $folderName; private string $displayName; - /** @var Chunk[] */ + /** + * @var Chunk[] + * @phpstan-var array + */ private array $chunks = []; - /** @var Vector3[][] */ + /** + * @var Vector3[][] chunkHash => [relativeBlockHash => Vector3] + * @phpstan-var array> + */ private array $changedBlocks = []; /** @phpstan-var ReversePriorityQueue */ private ReversePriorityQueue $scheduledBlockUpdateQueue; - /** @var int[] */ + /** + * @var int[] blockHash => tick delay + * @phpstan-var array + */ private array $scheduledBlockUpdateQueueIndex = []; /** @phpstan-var \SplQueue */ private \SplQueue $neighbourBlockUpdateQueue; - /** @var bool[] blockhash => dummy */ + /** + * @var true[] blockhash => dummy + * @phpstan-var array + */ private array $neighbourBlockUpdateQueueIndex = []; - /** @var bool[] */ + /** + * @var bool[] chunkHash => isValid + * @phpstan-var array + */ private array $activeChunkPopulationTasks = []; - /** @var ChunkLockId[] */ + /** + * @var ChunkLockId[] + * @phpstan-var array + */ private array $chunkLock = []; private int $maxConcurrentChunkPopulationTasks = 2; /** * @var PromiseResolver[] chunkHash => promise - * @phpstan-var array> + * @phpstan-var array> */ private array $chunkPopulationRequestMap = []; /** * @var \SplQueue (queue of chunkHashes) - * @phpstan-var \SplQueue + * @phpstan-var \SplQueue */ private \SplQueue $chunkPopulationRequestQueue; /** * @var true[] chunkHash => dummy - * @phpstan-var array + * @phpstan-var array */ private array $chunkPopulationRequestQueueIndex = []; - /** @var bool[] */ + /** + * @var true[] + * @phpstan-var array + */ private array $generatorRegisteredWorkers = []; private bool $autoSave = true; @@ -260,7 +319,10 @@ class World implements ChunkManager{ private int $chunkTickRadius; private int $chunksPerTick; private int $tickedBlocksPerSubchunkPerTick = self::DEFAULT_TICKED_BLOCKS_PER_SUBCHUNK_PER_TICK; - /** @var bool[] */ + /** + * @var true[] + * @phpstan-var array + */ private array $randomTickBlocks = []; /** @var WorldTimings */ @@ -286,6 +348,9 @@ class World implements ChunkManager{ private \Logger $logger; + /** + * @phpstan-return ChunkPosHash + */ public static function chunkHash(int $x, int $z) : int{ return morton2d_encode($x, $z); } @@ -302,6 +367,9 @@ class World implements ChunkManager{ private const BLOCKHASH_X_SHIFT = self::BLOCKHASH_Y_BITS; private const BLOCKHASH_Z_SHIFT = self::BLOCKHASH_X_SHIFT + self::BLOCKHASH_XZ_EXTRA_BITS; + /** + * @phpstan-return BlockPosHash + */ public static function blockHash(int $x, int $y, int $z) : int{ $shiftedY = $y + self::BLOCKHASH_Y_OFFSET; if(($shiftedY & (~0 << self::BLOCKHASH_Y_BITS)) !== 0){ @@ -326,6 +394,9 @@ class World implements ChunkManager{ return morton3d_encode($x, $y, $z); } + /** + * @phpstan-param BlockPosHash $hash + */ public static function getBlockXYZ(int $hash, ?int &$x, ?int &$y, ?int &$z) : void{ [$baseX, $baseY, $baseZ] = morton3d_decode($hash); @@ -337,6 +408,9 @@ class World implements ChunkManager{ $z = (($baseZ & self::BLOCKHASH_XZ_MASK) | $extraZ) << self::BLOCKHASH_XZ_SIGN_SHIFT >> self::BLOCKHASH_XZ_SIGN_SHIFT; } + /** + * @phpstan-param ChunkPosHash $hash + */ public static function getXZ(int $hash, ?int &$x, ?int &$z) : void{ [$x, $z] = morton2d_decode($hash); } @@ -556,6 +630,28 @@ class World implements ChunkManager{ unset($this->unloadCallbacks[spl_object_id($callback)]); } + /** + * Returns a list of players who are in the given filter and also using the chunk containing the target position. + * Used for broadcasting sounds and particles with specific targets. + * + * @param Player[] $allowed + * @phpstan-param list $allowed + * + * @return array + */ + private function filterViewersForPosition(Vector3 $pos, array $allowed) : array{ + $candidates = $this->getViewersForPosition($pos); + $filtered = []; + foreach($allowed as $player){ + $k = spl_object_id($player); + if(isset($candidates[$k])){ + $filtered[$k] = $candidates[$k]; + } + } + + return $filtered; + } + /** * @param Player[]|null $players */ @@ -567,7 +663,7 @@ class World implements ChunkManager{ $this->broadcastPacketToViewers($pos, $e); } }else{ - $this->server->broadcastPackets($players, $pk); + $this->server->broadcastPackets($this->filterViewersForPosition($pos, $players), $pk); } } } @@ -583,7 +679,7 @@ class World implements ChunkManager{ $this->broadcastPacketToViewers($pos, $e); } }else{ - $this->server->broadcastPackets($players, $pk); + $this->server->broadcastPackets($this->filterViewersForPosition($pos, $players), $pk); } } } @@ -602,7 +698,8 @@ class World implements ChunkManager{ * * Returns a list of players who have the target chunk within their view distance. * - * @return Player[] + * @return Player[] spl_object_id => Player + * @phpstan-return array */ public function getChunkPlayers(int $chunkX, int $chunkZ) : array{ return $this->playerChunkListeners[World::chunkHash($chunkX, $chunkZ)] ?? []; @@ -612,6 +709,7 @@ class World implements ChunkManager{ * Gets the chunk loaders being used in a specific chunk * * @return ChunkLoader[] + * @phpstan-return array */ public function getChunkLoaders(int $chunkX, int $chunkZ) : array{ return $this->chunkLoaders[World::chunkHash($chunkX, $chunkZ)] ?? []; @@ -620,7 +718,8 @@ class World implements ChunkManager{ /** * Returns an array of players who have the target position within their view distance. * - * @return Player[] + * @return Player[] spl_object_id => Player + * @phpstan-return array */ public function getViewersForPosition(Vector3 $pos) : array{ return $this->getChunkPlayers($pos->getFloorX() >> Chunk::COORD_BIT_SIZE, $pos->getFloorZ() >> Chunk::COORD_BIT_SIZE); @@ -735,6 +834,7 @@ class World implements ChunkManager{ * Returns all the listeners attached to this chunk. * * @return ChunkListener[] + * @phpstan-return array */ public function getChunkListeners(int $chunkX, int $chunkZ) : array{ return $this->chunkListeners[World::chunkHash($chunkX, $chunkZ)] ?? []; @@ -928,8 +1028,10 @@ class World implements ChunkManager{ /** * @param Vector3[] $blocks + * @phpstan-param list $blocks * * @return ClientboundPacket[] + * @phpstan-return list */ public function createBlockUpdatePackets(array $blocks) : array{ $packets = []; @@ -975,7 +1077,8 @@ class World implements ChunkManager{ } /** - * @return bool[] fullID => bool + * @return true[] fullID => dummy + * @phpstan-return array */ public function getRandomTickedBlocks() : array{ return $this->randomTickBlocks; @@ -1197,6 +1300,7 @@ class World implements ChunkManager{ /** * @return Block[] + * @phpstan-return list */ public function getCollisionBlocks(AxisAlignedBB $bb, bool $targetFirst = false) : array{ $minX = (int) floor($bb->minX - 1); @@ -1237,6 +1341,7 @@ class World implements ChunkManager{ /** * @return AxisAlignedBB[] + * @phpstan-return list */ public function getCollisionBoxes(Entity $entity, AxisAlignedBB $bb, bool $entities = true) : array{ $minX = (int) floor($bb->minX - 1); @@ -1636,6 +1741,7 @@ class World implements ChunkManager{ * Drops XP orbs into the world for the specified amount, splitting the amount into several orbs if necessary. * * @return ExperienceOrb[] + * @phpstan-return list */ public function dropExperience(Vector3 $pos, int $amount) : array{ /** @var ExperienceOrb[] $orbs */ @@ -1888,18 +1994,24 @@ class World implements ChunkManager{ } /** - * Gets the list of all the entities in this world + * Returns a list of all the entities in this world, indexed by their entity runtime IDs * * @return Entity[] + * @phpstan-return array */ public function getEntities() : array{ return $this->entities; } /** - * Returns the entities colliding the current one inside the AxisAlignedBB + * Returns all collidable entities whose bounding boxes intersect the given bounding box. + * If an entity is given, it will be excluded from the result. + * If a non-collidable entity is given, the result will be empty. + * + * This function is the same as {@link World::getNearbyEntities()}, but with additional collidability filters. * * @return Entity[] + * @phpstan-return array */ public function getCollidingEntities(AxisAlignedBB $bb, ?Entity $entity = null) : array{ $nearby = []; @@ -1916,9 +2028,10 @@ class World implements ChunkManager{ } /** - * Returns the entities near the current one inside the AxisAlignedBB + * Returns all entities whose bounding boxes intersect the given bounding box, excluding the given entity. * * @return Entity[] + * @phpstan-return array */ public function getNearbyEntities(AxisAlignedBB $bb, ?Entity $entity = null) : array{ $nearby = []; @@ -1995,7 +2108,8 @@ class World implements ChunkManager{ /** * Returns a list of the players in this world * - * @return Player[] + * @return Player[] entity runtime ID => Player + * @phpstan-return array */ public function getPlayers() : array{ return $this->players; @@ -2042,7 +2156,8 @@ class World implements ChunkManager{ } /** - * @return Chunk[] + * @return Chunk[] chunkHash => Chunk + * @phpstan-return array */ public function getLoadedChunks() : array{ return $this->chunks; @@ -2053,7 +2168,8 @@ class World implements ChunkManager{ } /** - * @return Entity[] + * @return Entity[] entity runtime ID => Entity + * @phpstan-return array */ public function getChunkEntities(int $chunkX, int $chunkZ) : array{ return $this->entitiesByChunk[World::chunkHash($chunkX, $chunkZ)] ?? []; @@ -2069,7 +2185,8 @@ class World implements ChunkManager{ /** * Returns the chunks adjacent to the specified chunk. * - * @return Chunk[]|null[] + * @return Chunk[]|null[] chunkHash => Chunk|null + * @phpstan-return array */ public function getAdjacentChunks(int $x, int $z) : array{ $result = [];