Merge branch 'minor-next' into major-next

This commit is contained in:
Dylan K. Taylor
2025-01-08 15:25:12 +00:00
46 changed files with 978 additions and 435 deletions

View File

@@ -139,6 +139,7 @@ use function file_put_contents;
use function filemtime;
use function fopen;
use function get_class;
use function gettype;
use function ini_set;
use function is_array;
use function is_dir;
@@ -923,6 +924,7 @@ class Server{
TimingsHandler::getCollectCallbacks()->add(function() : array{
$promises = [];
foreach($this->asyncPool->getRunningWorkers() as $workerId){
/** @phpstan-var PromiseResolver<list<string>> $resolver */
$resolver = new PromiseResolver();
$this->asyncPool->submitTaskToWorker(new TimingsCollectionTask($resolver), $workerId);
@@ -1018,7 +1020,11 @@ class Server{
copy(Path::join(\pocketmine\RESOURCE_PATH, 'plugin_list.yml'), $graylistFile);
}
try{
$pluginGraylist = PluginGraylist::fromArray(yaml_parse(Filesystem::fileGetContents($graylistFile)));
$array = yaml_parse(Filesystem::fileGetContents($graylistFile));
if(!is_array($array)){
throw new \InvalidArgumentException("Expected array for root, but have " . gettype($array));
}
$pluginGraylist = PluginGraylist::fromArray($array);
}catch(\InvalidArgumentException $e){
$this->logger->emergency("Failed to load $graylistFile: " . $e->getMessage());
$this->forceShutdownExit();
@@ -1180,7 +1186,7 @@ class Server{
if($this->worldManager->getDefaultWorld() === null){
$default = $this->configGroup->getConfigString(ServerProperties::DEFAULT_WORLD_NAME, "world");
if(trim($default) == ""){
if(trim($default) === ""){
$this->logger->warning("level-name cannot be null, using default");
$default = "world";
$this->configGroup->setConfigString(ServerProperties::DEFAULT_WORLD_NAME, "world");

View File

@@ -51,9 +51,8 @@ final class CommandStringHelper{
foreach($matches[0] as $k => $_){
for($i = 1; $i <= 2; ++$i){
if($matches[$i][$k] !== ""){
/** @var string $match */ //phpstan can't understand preg_match and friends by itself :(
$match = $matches[$i][$k];
$args[(int) $k] = preg_replace('/\\\\([\\\\"])/u', '$1', $match) ?? throw new AssumptionFailedError(preg_last_error_msg());
$args[] = preg_replace('/\\\\([\\\\"])/u', '$1', $match) ?? throw new AssumptionFailedError(preg_last_error_msg());
break;
}
}

View File

@@ -110,7 +110,6 @@ class CraftingManager{
/**
* @param Item[] $items
* @phpstan-param list<Item> $items
*
* @return Item[]
* @phpstan-return list<Item>
@@ -135,7 +134,6 @@ class CraftingManager{
/**
* @param Item[] $outputs
* @phpstan-param list<Item> $outputs
*/
private static function hashOutputs(array $outputs) : string{
$outputs = self::pack($outputs);

View File

@@ -37,7 +37,6 @@ use pocketmine\utils\Utils;
use Symfony\Component\Filesystem\Path;
use function array_key_last;
use function array_map;
use function array_values;
use function assert;
use function count;
use function get_debug_type;
@@ -138,8 +137,8 @@ final class BlockStateUpgradeSchemaUtils{
$convertedRemappedValuesIndex = [];
foreach(Utils::stringifyKeys($model->remappedPropertyValuesIndex ?? []) as $mappingKey => $mappingValues){
foreach($mappingValues as $k => $oldNew){
$convertedRemappedValuesIndex[$mappingKey][$k] = new BlockStateUpgradeSchemaValueRemap(
foreach($mappingValues as $oldNew){
$convertedRemappedValuesIndex[$mappingKey][] = new BlockStateUpgradeSchemaValueRemap(
self::jsonModelToTag($oldNew->old),
self::jsonModelToTag($oldNew->new)
);
@@ -361,7 +360,7 @@ final class BlockStateUpgradeSchemaUtils{
//remaps with the same number of criteria should be sorted alphabetically, but this is not strictly necessary
return json_encode($a->oldState ?? []) <=> json_encode($b->oldState ?? []);
});
$result->remappedStates[$oldBlockName] = array_values($keyedRemaps);
$result->remappedStates[$oldBlockName] = $keyedRemaps; //usort strips keys, so this is already a list
}
if(isset($result->remappedStates)){
ksort($result->remappedStates);

View File

@@ -23,7 +23,6 @@ declare(strict_types=1);
namespace pocketmine\data\runtime;
use function array_values;
use function ceil;
use function count;
use function log;
@@ -60,7 +59,7 @@ final class RuntimeEnumMetadata{
usort($members, fn(\UnitEnum $a, \UnitEnum $b) => $a->name <=> $b->name); //sort by name to ensure consistent ordering (and thus consistent bit assignments)
$this->bits = (int) ceil(log(count($members), 2));
$this->intToEnum = array_values($members);
$this->intToEnum = $members; //usort strips keys so this is already a list
$reversed = [];
foreach($this->intToEnum as $int => $enum){

View File

@@ -44,7 +44,6 @@ use pocketmine\nbt\tag\CompoundTag;
use pocketmine\nbt\tag\IntTag;
use pocketmine\nbt\tag\ListTag;
use pocketmine\timings\Timings;
use function assert;
use function atan2;
use function ceil;
use function count;
@@ -170,8 +169,6 @@ abstract class Projectile extends Entity{
$start = $this->location->asVector3();
$end = $start->add($dx, $dy, $dz);
$blockHit = null;
$entityHit = null;
$hitResult = null;
$world = $this->getWorld();
@@ -181,8 +178,7 @@ abstract class Projectile extends Entity{
$blockHitResult = $this->calculateInterceptWithBlock($block, $start, $end);
if($blockHitResult !== null){
$end = $blockHitResult->hitVector;
$blockHit = $block;
$hitResult = $blockHitResult;
$hitResult = [$block, $blockHitResult];
break;
}
}
@@ -206,8 +202,7 @@ abstract class Projectile extends Entity{
if($distance < $entityDistance){
$entityDistance = $distance;
$entityHit = $entity;
$hitResult = $entityHitResult;
$hitResult = [$entity, $entityHitResult];
$end = $entityHitResult->hitVector;
}
}
@@ -223,26 +218,18 @@ abstract class Projectile extends Entity{
$this->recalculateBoundingBox();
if($hitResult !== null){
/** @var ProjectileHitEvent|null $ev */
$ev = null;
if($entityHit !== null){
$ev = new ProjectileHitEntityEvent($this, $hitResult, $entityHit);
}elseif($blockHit !== null){
$ev = new ProjectileHitBlockEvent($this, $hitResult, $blockHit);
[$objectHit, $rayTraceResult] = $hitResult;
if($objectHit instanceof Entity){
$ev = new ProjectileHitEntityEvent($this, $rayTraceResult, $objectHit);
$specificHitFunc = fn() => $this->onHitEntity($objectHit, $rayTraceResult);
}else{
assert(false, "unknown hit type");
$ev = new ProjectileHitBlockEvent($this, $rayTraceResult, $objectHit);
$specificHitFunc = fn() => $this->onHitBlock($objectHit, $rayTraceResult);
}
if($ev !== null){
$ev->call();
$this->onHit($ev);
if($ev instanceof ProjectileHitEntityEvent){
$this->onHitEntity($ev->getEntityHit(), $ev->getRayTraceResult());
}elseif($ev instanceof ProjectileHitBlockEvent){
$this->onHitBlock($ev->getBlockHit(), $ev->getRayTraceResult());
}
}
$ev->call();
$this->onHit($ev);
$specificHitFunc();
$this->isCollided = $this->onGround = true;
$this->motion = Vector3::zero();
@@ -290,10 +277,11 @@ abstract class Projectile extends Entity{
$damage = $this->getResultDamage();
if($damage >= 0){
if($this->getOwningEntity() === null){
$owner = $this->getOwningEntity();
if($owner === null){
$ev = new EntityDamageByEntityEvent($this, $entityHit, EntityDamageEvent::CAUSE_PROJECTILE, $damage);
}else{
$ev = new EntityDamageByChildEntityEvent($this->getOwningEntity(), $this, $entityHit, EntityDamageEvent::CAUSE_PROJECTILE, $damage);
$ev = new EntityDamageByChildEntityEvent($owner, $this, $entityHit, EntityDamageEvent::CAUSE_PROJECTILE, $damage);
}
$entityHit->attack($ev);

View File

@@ -119,7 +119,7 @@ class HandlerListManager{
public function getHandlersFor(string $event) : array{
$cache = $this->handlerCaches[$event] ?? null;
//getListFor() will populate the cache for the next call
return $cache?->list ?? $this->getListFor($event)->getListenerList();
return $cache->list ?? $this->getListFor($event)->getListenerList();
}
/**

View File

@@ -52,9 +52,15 @@ class PlayerPreLoginEvent extends Event{
self::KICK_FLAG_BANNED
];
/** @var Translatable[]|string[] reason const => associated message */
/**
* @var Translatable[]|string[] reason const => associated message
* @phpstan-var array<int, Translatable|string>
*/
protected array $disconnectReasons = [];
/** @var Translatable[]|string[] */
/**
* @var Translatable[]|string[]
* @phpstan-var array<int, Translatable|string>
*/
protected array $disconnectScreenMessages = [];
public function __construct(
@@ -93,6 +99,7 @@ class PlayerPreLoginEvent extends Event{
* Returns an array of kick flags currently assigned.
*
* @return int[]
* @phpstan-return list<int>
*/
public function getKickFlags() : array{
return array_keys($this->disconnectReasons);

View File

@@ -231,7 +231,7 @@ class InventoryTransaction{
/**
* @param SlotChangeAction[] $possibleActions
* @phpstan-param list<SlotChangeAction> $possibleActions
* @phpstan-param array<int, SlotChangeAction> $possibleActions
*/
protected function findResultItem(Item $needOrigin, array $possibleActions) : ?Item{
assert(count($possibleActions) > 0);

View File

@@ -101,8 +101,9 @@ abstract class WritableBookBase extends Item{
* @return $this
*/
public function deletePage(int $pageId) : self{
unset($this->pages[$pageId]);
$this->pages = array_values($this->pages);
$newPages = $this->pages;
unset($newPages[$pageId]);
$this->pages = array_values($newPages);
return $this;
}

View File

@@ -32,6 +32,7 @@ use function array_merge;
use function array_search;
use function array_shift;
use function array_unique;
use function array_values;
use function count;
/**
@@ -103,7 +104,8 @@ final class ItemEnchantmentTagRegistry{
foreach(Utils::stringifyKeys($this->tagMap) as $key => $nestedTags){
if(($nestedKey = array_search($tag, $nestedTags, true)) !== false){
unset($this->tagMap[$key][$nestedKey]);
unset($nestedTags[$nestedKey]);
$this->tagMap[$key] = array_values($nestedTags);
}
}
}
@@ -115,7 +117,7 @@ final class ItemEnchantmentTagRegistry{
*/
public function removeNested(string $tag, array $nestedTags) : void{
$this->assertNotInternalTag($tag);
$this->tagMap[$tag] = array_diff($this->tagMap[$tag], $nestedTags);
$this->tagMap[$tag] = array_values(array_diff($this->tagMap[$tag], $nestedTags));
}
/**

View File

@@ -25,18 +25,22 @@ namespace pocketmine\item\enchantment;
use pocketmine\event\entity\EntityDamageEvent;
use pocketmine\lang\Translatable;
use function array_flip;
use function array_fill_keys;
use function floor;
class ProtectionEnchantment extends Enchantment{
protected float $typeModifier;
/** @var int[]|null */
/**
* @var true[]|null
* @phpstan-var array<int, true>
*/
protected ?array $applicableDamageTypes = null;
/**
* ProtectionEnchantment constructor.
*
* @phpstan-param null|(\Closure(int $level) : int) $minEnchantingPower
* @phpstan-param list<int>|null $applicableDamageTypes
*
* @param int[]|null $applicableDamageTypes EntityDamageEvent::CAUSE_* constants which this enchantment type applies to, or null if it applies to all types of damage.
* @param int $enchantingPowerRange Value used to calculate the maximum enchanting power (minEnchantingPower + enchantingPowerRange)
@@ -46,7 +50,7 @@ class ProtectionEnchantment extends Enchantment{
$this->typeModifier = $typeModifier;
if($applicableDamageTypes !== null){
$this->applicableDamageTypes = array_flip($applicableDamageTypes);
$this->applicableDamageTypes = array_fill_keys($applicableDamageTypes, true);
}
}

View File

@@ -101,11 +101,12 @@ class BanEntry{
}
public function getString() : string{
$expires = $this->getExpires();
return implode("|", [
$this->getName(),
$this->getCreated()->format(self::$format),
$this->getSource(),
$this->getExpires() === null ? "Forever" : $this->getExpires()->format(self::$format),
$expires === null ? "Forever" : $expires->format(self::$format),
$this->getReason()
]);
}

View File

@@ -148,7 +148,6 @@ use function count;
use function explode;
use function floor;
use function get_class;
use function is_int;
use function max;
use function mb_strlen;
use function microtime;
@@ -831,7 +830,6 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{
$X = null;
$Z = null;
World::getXZ($index, $X, $Z);
assert(is_int($X) && is_int($Z));
++$count;
@@ -1351,7 +1349,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{
$this->nextChunkOrderRun = 0;
}
if(!$revert && $distanceSquared != 0){
if(!$revert && $distanceSquared !== 0.0){
$dx = $newPos->x - $oldPos->x;
$dy = $newPos->y - $oldPos->y;
$dz = $newPos->z - $oldPos->z;
@@ -2324,7 +2322,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{
$ev = new PlayerQuitEvent($this, $quitMessage ?? $this->getLeaveMessage(), $reason);
$ev->call();
if(($quitMessage = $ev->getQuitMessage()) != ""){
if(($quitMessage = $ev->getQuitMessage()) !== ""){
$this->server->broadcastMessage($quitMessage);
}
$this->save();
@@ -2465,7 +2463,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{
$this->xpManager->setXpAndProgress(0, 0.0);
}
if($ev->getDeathMessage() != ""){
if($ev->getDeathMessage() !== ""){
$this->server->broadcastMessage($ev->getDeathMessage());
}

View File

@@ -24,7 +24,8 @@ declare(strict_types=1);
namespace pocketmine\plugin;
use pocketmine\utils\Utils;
use function array_flip;
use function array_fill_keys;
use function array_keys;
use function is_array;
use function is_float;
use function is_int;
@@ -32,23 +33,28 @@ use function is_string;
class PluginGraylist{
/** @var string[] */
/**
* @var true[]
* @phpstan-var array<string, true>
*/
private array $plugins;
private bool $isWhitelist = false;
/**
* @param string[] $plugins
* @phpstan-param list<string> $plugins
*/
public function __construct(array $plugins = [], bool $whitelist = false){
$this->plugins = array_flip($plugins);
$this->plugins = array_fill_keys($plugins, true);
$this->isWhitelist = $whitelist;
}
/**
* @return string[]
* @phpstan-return list<string>
*/
public function getPlugins() : array{
return array_flip($this->plugins);
return array_keys($this->plugins);
}
public function isWhitelist() : bool{

View File

@@ -47,10 +47,16 @@ class ResourcePackManager{
private string $path;
private bool $serverForceResources = false;
/** @var ResourcePack[] */
/**
* @var ResourcePack[]
* @phpstan-var list<ResourcePack>
*/
private array $resourcePacks = [];
/** @var ResourcePack[] */
/**
* @var ResourcePack[]
* @phpstan-var array<string, ResourcePack>
*/
private array $uuidList = [];
/**
@@ -165,6 +171,7 @@ class ResourcePackManager{
/**
* Returns an array of resource packs in use, sorted in order of priority.
* @return ResourcePack[]
* @phpstan-return list<ResourcePack>
*/
public function getResourceStack() : array{
return $this->resourcePacks;

View File

@@ -100,7 +100,7 @@ class ZippedResourcePack implements ResourcePack{
try{
$manifest = (new CommentedJsonDecoder())->decode($manifestData);
}catch(\RuntimeException $e){
throw new ResourcePackException("Failed to parse manifest.json: " . $e->getMessage(), $e->getCode(), $e);
throw new ResourcePackException("Failed to parse manifest.json: " . $e->getMessage(), 0, $e);
}
if(!($manifest instanceof \stdClass)){
throw new ResourcePackException("manifest.json should contain a JSON object, not " . gettype($manifest));

View File

@@ -77,7 +77,10 @@ class BulkCurlTask extends AsyncTask{
* @phpstan-var \Closure(list<InternetRequestResult|InternetException>) : void
*/
$callback = $this->fetchLocal(self::TLS_KEY_COMPLETION_CALLBACK);
/** @var InternetRequestResult[]|InternetException[] $results */
/**
* @var InternetRequestResult[]|InternetException[] $results
* @phpstan-var list<InternetRequestResult|InternetException> $results
*/
$results = $this->getResult();
$callback($results);
}

View File

@@ -123,6 +123,7 @@ class TimingsHandler{
/**
* @return string[]
* @phpstan-return list<string>
*/
private static function printFooter() : array{
$result = [];
@@ -160,6 +161,7 @@ class TimingsHandler{
}
}
/** @phpstan-var PromiseResolver<list<string>> $resolver */
$resolver = new PromiseResolver();
Promise::all($otherThreadRecordPromises)->onCompletion(
function(array $promisedRecords) use ($resolver, $thisThreadRecords) : void{

View File

@@ -131,7 +131,7 @@ final class TimingsRecord{
}
public function stopTiming(int $now) : void{
if($this->start == 0){
if($this->start === 0){
return;
}
if(self::$currentRecord !== $this){

View File

@@ -167,6 +167,7 @@ final class Utils{
/**
* @phpstan-return \Closure(object) : object
* @deprecated
*/
public static function cloneCallback() : \Closure{
return static function(object $o){
@@ -179,15 +180,13 @@ final class Utils{
* @phpstan-template TValue of object
*
* @param object[] $array
* @phpstan-param array<TKey, TValue> $array
* @phpstan-param array<TKey, TValue>|list<TValue> $array
*
* @return object[]
* @phpstan-return array<TKey, TValue>
* @phpstan-return ($array is list<TValue> ? list<TValue> : array<TKey, TValue>)
*/
public static function cloneObjectArray(array $array) : array{
/** @phpstan-var \Closure(TValue) : TValue $callback */
$callback = self::cloneCallback();
return array_map($callback, $array);
return array_map(fn(object $o) => clone $o, $array);
}
/**
@@ -406,6 +405,7 @@ final class Utils{
/**
* @param mixed[][] $trace
* @phpstan-param list<array<string, mixed>>|null $trace
* @return string[]
*/
public static function printableExceptionInfo(\Throwable $e, $trace = null) : array{
@@ -469,7 +469,15 @@ final class Utils{
}
$params = implode(", ", $paramsList);
}
$messages[] = "#$i " . (isset($trace[$i]["file"]) ? Filesystem::cleanPath($trace[$i]["file"]) : "") . "(" . (isset($trace[$i]["line"]) ? $trace[$i]["line"] : "") . "): " . (isset($trace[$i]["class"]) ? $trace[$i]["class"] . (($trace[$i]["type"] === "dynamic" || $trace[$i]["type"] === "->") ? "->" : "::") : "") . $trace[$i]["function"] . "(" . Utils::printable($params) . ")";
$messages[] = "#$i " .
(isset($trace[$i]["file"]) ? Filesystem::cleanPath($trace[$i]["file"]) : "") .
"(" . (isset($trace[$i]["line"]) ? $trace[$i]["line"] : "") . "): " .
(isset($trace[$i]["class"]) ?
$trace[$i]["class"] . (($trace[$i]["type"] === "dynamic" || $trace[$i]["type"] === "->") ? "->" : "::") :
""
) .
$trace[$i]["function"] .
"(" . Utils::printable($params) . ")";
}
return $messages;
}

View File

@@ -113,6 +113,7 @@ use function array_keys;
use function array_map;
use function array_merge;
use function array_sum;
use function array_values;
use function assert;
use function cos;
use function count;
@@ -678,7 +679,6 @@ class World implements ChunkManager{
* Used for broadcasting sounds and particles with specific targets.
*
* @param Player[] $allowed
* @phpstan-param list<Player> $allowed
*
* @return array<int, Player>
*/
@@ -1089,7 +1089,6 @@ class World implements ChunkManager{
/**
* @param Vector3[] $blocks
* @phpstan-param list<Vector3> $blocks
*
* @return ClientboundPacket[]
* @phpstan-return list<ClientboundPacket>
@@ -1456,8 +1455,8 @@ class World implements ChunkManager{
$this->provider->saveChunk($chunkX, $chunkZ, new ChunkData(
$chunk->getSubChunks(),
$chunk->isPopulated(),
array_map(fn(Entity $e) => $e->saveNBT(), array_filter($this->getChunkEntities($chunkX, $chunkZ), fn(Entity $e) => $e->canSaveWithChunk())),
array_map(fn(Tile $t) => $t->saveNBT(), $chunk->getTiles()),
array_map(fn(Entity $e) => $e->saveNBT(), array_values(array_filter($this->getChunkEntities($chunkX, $chunkZ), fn(Entity $e) => $e->canSaveWithChunk()))),
array_map(fn(Tile $t) => $t->saveNBT(), array_values($chunk->getTiles())),
), $chunk->getTerrainDirtyFlags());
$chunk->clearTerrainDirtyFlags();
}
@@ -3000,8 +2999,8 @@ class World implements ChunkManager{
$this->provider->saveChunk($x, $z, new ChunkData(
$chunk->getSubChunks(),
$chunk->isPopulated(),
array_map(fn(Entity $e) => $e->saveNBT(), array_filter($this->getChunkEntities($x, $z), fn(Entity $e) => $e->canSaveWithChunk())),
array_map(fn(Tile $t) => $t->saveNBT(), $chunk->getTiles()),
array_map(fn(Entity $e) => $e->saveNBT(), array_values(array_filter($this->getChunkEntities($x, $z), fn(Entity $e) => $e->canSaveWithChunk()))),
array_map(fn(Tile $t) => $t->saveNBT(), array_values($chunk->getTiles())),
), $chunk->getTerrainDirtyFlags());
}finally{
$this->timings->syncChunkSave->stopTiming();

View File

@@ -83,11 +83,11 @@ abstract class BaseWorldProvider implements WorldProvider{
}
try{
$newPalette[$k] = $this->blockStateDeserializer->deserialize($newStateData);
$newPalette[] = $this->blockStateDeserializer->deserialize($newStateData);
}catch(BlockStateDeserializeException $e){
//this should never happen anyway - if the upgrader returned an invalid state, we have bigger problems
$blockDecodeErrors[] = "Palette offset $k / Failed to deserialize upgraded state $id:$meta: " . $e->getMessage();
$newPalette[$k] = $this->blockStateDeserializer->deserialize(GlobalBlockStateHandlers::getUnknownBlockStateData());
$newPalette[] = $this->blockStateDeserializer->deserialize(GlobalBlockStateHandlers::getUnknownBlockStateData());
}
}

View File

@@ -711,7 +711,6 @@ class LevelDB extends BaseWorldProvider implements WritableWorldProvider{
$nbt = new LittleEndianNbtSerializer();
/** @var CompoundTag[] $entities */
$entities = [];
if(($entityData = $this->db->get($index . ChunkDataKey::ENTITIES)) !== false && $entityData !== ""){
try{
@@ -721,7 +720,6 @@ class LevelDB extends BaseWorldProvider implements WritableWorldProvider{
}
}
/** @var CompoundTag[] $tiles */
$tiles = [];
if(($tileData = $this->db->get($index . ChunkDataKey::BLOCK_ENTITIES)) !== false && $tileData !== ""){
try{

View File

@@ -33,10 +33,8 @@ use pocketmine\world\format\io\exception\CorruptedChunkException;
use pocketmine\world\format\io\LoadedChunkData;
use pocketmine\world\format\io\WorldData;
use Symfony\Component\Filesystem\Path;
use function assert;
use function file_exists;
use function is_dir;
use function is_int;
use function morton2d_encode;
use function rename;
use function scandir;
@@ -60,7 +58,12 @@ abstract class RegionWorldProvider extends BaseWorldProvider{
public static function isValid(string $path) : bool{
if(file_exists(Path::join($path, "level.dat")) && is_dir($regionPath = Path::join($path, "region"))){
foreach(scandir($regionPath, SCANDIR_SORT_NONE) as $file){
$files = scandir($regionPath, SCANDIR_SORT_NONE);
if($files === false){
//we can't tell the type if we don't have read perms
return false;
}
foreach($files as $file){
$extPos = strrpos($file, ".");
if($extPos !== false && substr($file, $extPos + 1) === static::getRegionFileExtension()){
//we don't care if other region types exist, we only care if this format is possible
@@ -199,7 +202,6 @@ abstract class RegionWorldProvider extends BaseWorldProvider{
public function loadChunk(int $chunkX, int $chunkZ) : ?LoadedChunkData{
$regionX = $regionZ = null;
self::getRegionIndex($chunkX, $chunkZ, $regionX, $regionZ);
assert(is_int($regionX) && is_int($regionZ));
if(!file_exists($this->pathToRegion($regionX, $regionZ))){
return null;
@@ -213,6 +215,9 @@ abstract class RegionWorldProvider extends BaseWorldProvider{
return null;
}
/**
* @phpstan-return \RegexIterator<mixed, string, \FilesystemIterator>
*/
private function createRegionIterator() : \RegexIterator{
return new \RegexIterator(
new \FilesystemIterator(

View File

@@ -27,7 +27,6 @@ use pocketmine\data\bedrock\BiomeIds;
use pocketmine\item\LegacyStringToItemParser;
use pocketmine\item\LegacyStringToItemParserException;
use function array_map;
use function count;
use function explode;
use function preg_match;
use function preg_match_all;
@@ -75,8 +74,7 @@ final class FlatGeneratorOptions{
$y = 0;
$itemParser = LegacyStringToItemParser::getInstance();
foreach($split as $line){
preg_match('#^(?:(\d+)[x|*])?(.+)$#', $line, $matches);
if(count($matches) !== 3){
if(preg_match('#^(?:(\d+)[x|*])?(.+)$#', $line, $matches) !== 1){
throw new InvalidGeneratorOptionsException("Invalid preset layer \"$line\"");
}
@@ -119,7 +117,7 @@ final class FlatGeneratorOptions{
}
}
}
$options[(string) $option] = $params;
$options[$option] = $params;
}
return new self($structure, $biomeId, $options);
}

View File

@@ -126,10 +126,10 @@ class Normal extends Generator{
$hash = (int) $hash;
$xNoise = $hash >> 20 & 3;
$zNoise = $hash >> 22 & 3;
if($xNoise == 3){
if($xNoise === 3){
$xNoise = 1;
}
if($zNoise == 3){
if($zNoise === 3){
$zNoise = 1;
}