diff --git a/src/data/bedrock/block/upgrade/BlockStateUpgradeSchema.php b/src/data/bedrock/block/upgrade/BlockStateUpgradeSchema.php index 44c56e6ca..36960383e 100644 --- a/src/data/bedrock/block/upgrade/BlockStateUpgradeSchema.php +++ b/src/data/bedrock/block/upgrade/BlockStateUpgradeSchema.php @@ -69,14 +69,18 @@ final class BlockStateUpgradeSchema{ public int $maxVersionMinor, public int $maxVersionPatch, public int $maxVersionRevision, - private int $priority + private int $schemaId ){} + /** + * @deprecated This is defined by Mojang, and therefore cannot be relied on. Use getSchemaId() instead for + * internal version management. + */ public function getVersionId() : int{ return ($this->maxVersionMajor << 24) | ($this->maxVersionMinor << 16) | ($this->maxVersionPatch << 8) | $this->maxVersionRevision; } - public function getPriority() : int{ return $this->priority; } + public function getSchemaId() : int{ return $this->schemaId; } public function isEmpty() : bool{ foreach([ diff --git a/src/data/bedrock/block/upgrade/BlockStateUpgradeSchemaUtils.php b/src/data/bedrock/block/upgrade/BlockStateUpgradeSchemaUtils.php index 27aa5b510..64f79663e 100644 --- a/src/data/bedrock/block/upgrade/BlockStateUpgradeSchemaUtils.php +++ b/src/data/bedrock/block/upgrade/BlockStateUpgradeSchemaUtils.php @@ -110,13 +110,13 @@ final class BlockStateUpgradeSchemaUtils{ }; } - public static function fromJsonModel(BlockStateUpgradeSchemaModel $model, int $priority) : BlockStateUpgradeSchema{ + public static function fromJsonModel(BlockStateUpgradeSchemaModel $model, int $schemaId) : BlockStateUpgradeSchema{ $result = new BlockStateUpgradeSchema( $model->maxVersionMajor, $model->maxVersionMinor, $model->maxVersionPatch, $model->maxVersionRevision, - $priority + $schemaId ); $result->renamedIds = $model->renamedIds ?? []; $result->renamedProperties = $model->renamedProperties ?? []; @@ -250,11 +250,11 @@ final class BlockStateUpgradeSchemaUtils{ } /** - * Returns a list of schemas ordered by priority. Oldest schemas appear first. + * Returns a list of schemas ordered by schema ID. Oldest schemas appear first. * * @return BlockStateUpgradeSchema[] */ - public static function loadSchemas(string $path, int $currentVersion) : array{ + public static function loadSchemas(string $path, int $maxSchemaId) : array{ $iterator = new \RegexIterator( new \FilesystemIterator( $path, @@ -270,32 +270,30 @@ final class BlockStateUpgradeSchemaUtils{ /** @var string[] $matches */ foreach($iterator as $matches){ $filename = $matches[0]; - $priority = (int) $matches[1]; + $schemaId = (int) $matches[1]; + + if($schemaId > $maxSchemaId){ + continue; + } $fullPath = Path::join($path, $filename); $raw = Filesystem::fileGetContents($fullPath); try{ - $schema = self::loadSchemaFromString($raw, $priority); + $schema = self::loadSchemaFromString($raw, $schemaId); }catch(\RuntimeException $e){ throw new \RuntimeException("Loading schema file $fullPath: " . $e->getMessage(), 0, $e); } - if($schema->getVersionId() > $currentVersion){ - //this might be a beta schema which shouldn't be applicable - //TODO: why do we load the whole schema just to throw it away if it's too new? ... - continue; - } - - $result[$priority] = $schema; + $result[$schemaId] = $schema; } ksort($result, SORT_NUMERIC); return $result; } - public static function loadSchemaFromString(string $raw, int $priority) : BlockStateUpgradeSchema{ + public static function loadSchemaFromString(string $raw, int $schemaId) : BlockStateUpgradeSchema{ try{ $json = json_decode($raw, false, flags: JSON_THROW_ON_ERROR); }catch(\JsonException $e){ @@ -312,6 +310,6 @@ final class BlockStateUpgradeSchemaUtils{ throw new \RuntimeException($e->getMessage(), 0, $e); } - return self::fromJsonModel($model, $priority); + return self::fromJsonModel($model, $schemaId); } } diff --git a/src/data/bedrock/block/upgrade/BlockStateUpgrader.php b/src/data/bedrock/block/upgrade/BlockStateUpgrader.php index 637674a26..b7fd5a422 100644 --- a/src/data/bedrock/block/upgrade/BlockStateUpgrader.php +++ b/src/data/bedrock/block/upgrade/BlockStateUpgrader.php @@ -31,7 +31,7 @@ use function ksort; use const SORT_NUMERIC; final class BlockStateUpgrader{ - /** @var BlockStateUpgradeSchema[][] */ + /** @var BlockStateUpgradeSchema[] */ private array $upgradeSchemas = []; /** @@ -45,59 +45,54 @@ final class BlockStateUpgrader{ } public function addSchema(BlockStateUpgradeSchema $schema) : void{ - $schemaList = $this->upgradeSchemas[$schema->getVersionId()] ?? []; - - $priority = $schema->getPriority(); - if(isset($schemaList[$priority])){ - throw new \InvalidArgumentException("Cannot add two schemas to the same version with the same priority"); + $schemaId = $schema->getSchemaId(); + if(isset($this->upgradeSchemas[$schemaId])){ + throw new \InvalidArgumentException("Cannot add two schemas with the same schema ID"); } - $schemaList[$priority] = $schema; - ksort($schemaList, SORT_NUMERIC); - $this->upgradeSchemas[$schema->getVersionId()] = $schemaList; + $this->upgradeSchemas[$schemaId] = $schema; ksort($this->upgradeSchemas, SORT_NUMERIC); } public function upgrade(BlockStateData $blockStateData) : BlockStateData{ $version = $blockStateData->getVersion(); - foreach($this->upgradeSchemas as $resultVersion => $schemas){ + foreach($this->upgradeSchemas as $schema){ + $resultVersion = $schema->getVersionId(); if($version > $resultVersion){ //even if this is actually the same version, we have to apply it anyway because mojang are dumb and //didn't always bump the blockstate version when changing it :( continue; } - foreach($schemas as $schema){ - $oldName = $blockStateData->getName(); - $oldState = $blockStateData->getStates(); - if(isset($schema->remappedStates[$oldName])){ - foreach($schema->remappedStates[$oldName] as $remap){ - if(count($oldState) !== count($remap->oldState)){ - continue; //try next state - } - foreach(Utils::stringifyKeys($oldState) as $k => $v){ - if(!isset($remap->oldState[$k]) || !$remap->oldState[$k]->equals($v)){ - continue 2; //try next state - } - } - - $blockStateData = new BlockStateData($remap->newName, $remap->newState, $resultVersion); - continue 2; //try next schema + $oldName = $blockStateData->getName(); + $oldState = $blockStateData->getStates(); + if(isset($schema->remappedStates[$oldName])){ + foreach($schema->remappedStates[$oldName] as $remap){ + if(count($oldState) !== count($remap->oldState)){ + continue; //try next state } + foreach(Utils::stringifyKeys($oldState) as $k => $v){ + if(!isset($remap->oldState[$k]) || !$remap->oldState[$k]->equals($v)){ + continue 2; //try next state + } + } + + $blockStateData = new BlockStateData($remap->newName, $remap->newState, $resultVersion); + continue 2; //try next schema } - $newName = $schema->renamedIds[$oldName] ?? null; + } + $newName = $schema->renamedIds[$oldName] ?? null; - $stateChanges = 0; - $states = $blockStateData->getStates(); + $stateChanges = 0; + $states = $blockStateData->getStates(); - $states = $this->applyPropertyAdded($schema, $oldName, $states, $stateChanges); - $states = $this->applyPropertyRemoved($schema, $oldName, $states, $stateChanges); - $states = $this->applyPropertyRenamedOrValueChanged($schema, $oldName, $states, $stateChanges); - $states = $this->applyPropertyValueChanged($schema, $oldName, $states, $stateChanges); + $states = $this->applyPropertyAdded($schema, $oldName, $states, $stateChanges); + $states = $this->applyPropertyRemoved($schema, $oldName, $states, $stateChanges); + $states = $this->applyPropertyRenamedOrValueChanged($schema, $oldName, $states, $stateChanges); + $states = $this->applyPropertyValueChanged($schema, $oldName, $states, $stateChanges); - if($newName !== null || $stateChanges > 0){ - $blockStateData = new BlockStateData($newName ?? $oldName, $states, $resultVersion); - //don't break out; we may need to further upgrade the state - } + if($newName !== null || $stateChanges > 0){ + $blockStateData = new BlockStateData($newName ?? $oldName, $states, $resultVersion); + //don't break out; we may need to further upgrade the state } } diff --git a/src/world/format/io/GlobalBlockStateHandlers.php b/src/world/format/io/GlobalBlockStateHandlers.php index d22eb368b..bd983dea8 100644 --- a/src/world/format/io/GlobalBlockStateHandlers.php +++ b/src/world/format/io/GlobalBlockStateHandlers.php @@ -43,6 +43,7 @@ use const pocketmine\BEDROCK_BLOCK_UPGRADE_SCHEMA_PATH; * benefits for now. */ final class GlobalBlockStateHandlers{ + public const MAX_BLOCKSTATE_UPGRADE_SCHEMA_ID = 151; //https://github.com/pmmp/BedrockBlockUpgradeSchema/blob/b0cc441e029cf5a6de5b05dd0f5657208855232b/nbt_upgrade_schema/0151_1.19.0.34_beta_to_1.19.20.json private static ?BlockObjectToStateSerializer $blockStateSerializer = null; @@ -64,7 +65,7 @@ final class GlobalBlockStateHandlers{ if(self::$blockDataUpgrader === null){ $blockStateUpgrader = new BlockStateUpgrader(BlockStateUpgradeSchemaUtils::loadSchemas( Path::join(BEDROCK_BLOCK_UPGRADE_SCHEMA_PATH, 'nbt_upgrade_schema'), - BlockStateData::CURRENT_VERSION + self::MAX_BLOCKSTATE_UPGRADE_SCHEMA_ID )); self::$blockDataUpgrader = new BlockDataUpgrader( BlockIdMetaUpgrader::loadFromString(