BlockStateUpgrader: do not use blockstate version to manage internal schemas

these are no longer reliable.
This commit is contained in:
Dylan K. Taylor 2023-02-01 22:35:59 +00:00
parent d3fff4e0b2
commit 0e15a8698a
No known key found for this signature in database
GPG Key ID: 8927471A91CAFD3D
4 changed files with 53 additions and 55 deletions

View File

@ -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([

View File

@ -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);
}
}

View File

@ -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
}
}

View File

@ -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(