Added support for using and generating blockstate upgrade schemas using newFlattenedName rules

see pmmp/BedrockBlockUpgradeSchema@f426fccbee
This commit is contained in:
Dylan K. Taylor
2023-06-26 16:17:00 +01:00
parent 882d50b14e
commit c165670e0a
7 changed files with 264 additions and 58 deletions

View File

@ -24,6 +24,9 @@ declare(strict_types=1);
namespace pocketmine\data\bedrock\block\upgrade;
use pocketmine\nbt\tag\Tag;
use pocketmine\utils\Utils;
use function array_diff;
use function count;
final class BlockStateUpgradeSchemaBlockRemap{
/**
@ -37,8 +40,43 @@ final class BlockStateUpgradeSchemaBlockRemap{
*/
public function __construct(
public array $oldState,
public string $newName,
public string|BlockStateUpgradeSchemaFlattenedName $newName,
public array $newState,
public array $copiedState
){}
public function equals(self $that) : bool{
$sameName = $this->newName === $that->newName ||
(
$this->newName instanceof BlockStateUpgradeSchemaFlattenedName &&
$that->newName instanceof BlockStateUpgradeSchemaFlattenedName &&
$this->newName->equals($that->newName)
);
if(!$sameName){
return false;
}
if(
count($this->oldState) !== count($that->oldState) ||
count($this->newState) !== count($that->newState) ||
count($this->copiedState) !== count($that->copiedState) ||
count(array_diff($this->copiedState, $that->copiedState)) !== 0
){
return false;
}
foreach(Utils::stringifyKeys($this->oldState) as $propertyName => $propertyValue){
if(!isset($that->oldState[$propertyName]) || !$that->oldState[$propertyName]->equals($propertyValue)){
//different filter value
return false;
}
}
foreach(Utils::stringifyKeys($this->newState) as $propertyName => $propertyValue){
if(!isset($that->newState[$propertyName]) || !$that->newState[$propertyName]->equals($propertyValue)){
//different replacement value
return false;
}
}
return true;
}
}

View File

@ -0,0 +1,39 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\data\bedrock\block\upgrade;
final class BlockStateUpgradeSchemaFlattenedName{
public function __construct(
public string $prefix,
public string $flattenedProperty,
public string $suffix
){}
public function equals(self $that) : bool{
return $this->prefix === $that->prefix &&
$this->flattenedProperty === $that->flattenedProperty &&
$this->suffix === $that->suffix;
}
}

View File

@ -25,6 +25,7 @@ namespace pocketmine\data\bedrock\block\upgrade;
use pocketmine\data\bedrock\block\upgrade\model\BlockStateUpgradeSchemaModel;
use pocketmine\data\bedrock\block\upgrade\model\BlockStateUpgradeSchemaModelBlockRemap;
use pocketmine\data\bedrock\block\upgrade\model\BlockStateUpgradeSchemaModelFlattenedName;
use pocketmine\data\bedrock\block\upgrade\model\BlockStateUpgradeSchemaModelTag;
use pocketmine\data\bedrock\block\upgrade\model\BlockStateUpgradeSchemaModelValueRemap;
use pocketmine\nbt\tag\ByteTag;
@ -43,12 +44,14 @@ use function get_debug_type;
use function gettype;
use function implode;
use function is_object;
use function is_string;
use function json_decode;
use function json_encode;
use function ksort;
use function sort;
use function str_pad;
use function strval;
use function usort;
use const JSON_THROW_ON_ERROR;
use const SORT_NUMERIC;
use const STR_PAD_LEFT;
@ -154,9 +157,17 @@ final class BlockStateUpgradeSchemaUtils{
foreach(Utils::stringifyKeys($model->remappedStates ?? []) as $oldBlockName => $remaps){
foreach($remaps as $remap){
if(isset($remap->newName) === isset($remap->newFlattenedName)){
throw new \UnexpectedValueException("Expected exactly one of 'newName' or 'newFlattenedName' properties to be set");
}
$result->remappedStates[$oldBlockName][] = new BlockStateUpgradeSchemaBlockRemap(
array_map(fn(BlockStateUpgradeSchemaModelTag $tag) => self::jsonModelToTag($tag), $remap->oldState ?? []),
$remap->newName,
$remap->newName ?? new BlockStateUpgradeSchemaFlattenedName(
$remap->newFlattenedName->prefix,
$remap->newFlattenedName->flattenedProperty,
$remap->newFlattenedName->suffix
),
array_map(fn(BlockStateUpgradeSchemaModelTag $tag) => self::jsonModelToTag($tag), $remap->newState ?? []),
$remap->copiedState ?? []
);
@ -285,7 +296,13 @@ final class BlockStateUpgradeSchemaUtils{
foreach($remaps as $remap){
$modelRemap = new BlockStateUpgradeSchemaModelBlockRemap(
array_map(fn(Tag $tag) => self::tagToJsonModel($tag), $remap->oldState),
$remap->newName,
is_string($remap->newName) ?
$remap->newName :
new BlockStateUpgradeSchemaModelFlattenedName(
$remap->newName->prefix,
$remap->newName->flattenedProperty,
$remap->newName->suffix
),
array_map(fn(Tag $tag) => self::tagToJsonModel($tag), $remap->newState),
$remap->copiedState
);
@ -299,7 +316,15 @@ final class BlockStateUpgradeSchemaUtils{
}
$keyedRemaps[$key] = $modelRemap;
}
ksort($keyedRemaps);
usort($keyedRemaps, function(BlockStateUpgradeSchemaModelBlockRemap $a, BlockStateUpgradeSchemaModelBlockRemap $b) : int{
//remaps with more specific criteria must come first
$filterSizeCompare = count($b->oldState ?? []) <=> count($a->oldState ?? []);
if($filterSizeCompare !== 0){
return $filterSizeCompare;
}
//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);
}
if(isset($result->remappedStates)){

View File

@ -24,11 +24,14 @@ declare(strict_types=1);
namespace pocketmine\data\bedrock\block\upgrade;
use pocketmine\data\bedrock\block\BlockStateData;
use pocketmine\nbt\tag\StringTag;
use pocketmine\nbt\tag\Tag;
use pocketmine\utils\Utils;
use function count;
use function is_string;
use function ksort;
use function max;
use function sprintf;
use const SORT_NUMERIC;
final class BlockStateUpgrader{
@ -79,6 +82,20 @@ final class BlockStateUpgrader{
continue 2; //try next state
}
}
if(is_string($remap->newName)){
$newName = $remap->newName;
}else{
$flattenedValue = $oldState[$remap->newName->flattenedProperty];
if($flattenedValue instanceof StringTag){
$newName = sprintf("%s%s%s", $remap->newName->prefix, $flattenedValue->getValue(), $remap->newName->suffix);
unset($oldState[$remap->newName->flattenedProperty]);
}else{
//flattened property is not a TAG_String, so this transformation is not applicable
continue;
}
}
$newState = $remap->newState;
foreach($remap->copiedState as $stateName){
if(isset($oldState[$stateName])){
@ -86,7 +103,7 @@ final class BlockStateUpgrader{
}
}
$blockStateData = new BlockStateData($remap->newName, $newState, $resultVersion);
$blockStateData = new BlockStateData($newName, $newState, $resultVersion);
continue 2; //try next schema
}
}

View File

@ -34,8 +34,16 @@ final class BlockStateUpgradeSchemaModelBlockRemap{
*/
public ?array $oldState;
/** @required */
/**
* Either this or newFlattenedName must be present
* Due to technical limitations of jsonmapper, we can't use a union type here
*/
public string $newName;
/**
* Either this or newName must be present
* Due to technical limitations of jsonmapper, we can't use a union type here
*/
public BlockStateUpgradeSchemaModelFlattenedName $newFlattenedName;
/**
* @var BlockStateUpgradeSchemaModelTag[]|null
@ -59,9 +67,13 @@ final class BlockStateUpgradeSchemaModelBlockRemap{
* @phpstan-param array<string, BlockStateUpgradeSchemaModelTag> $newState
* @phpstan-param list<string> $copiedState
*/
public function __construct(array $oldState, string $newName, array $newState, array $copiedState){
public function __construct(array $oldState, string|BlockStateUpgradeSchemaModelFlattenedName $newNameRule, array $newState, array $copiedState){
$this->oldState = count($oldState) === 0 ? null : $oldState;
$this->newName = $newName;
if($newNameRule instanceof BlockStateUpgradeSchemaModelFlattenedName){
$this->newFlattenedName = $newNameRule;
}else{
$this->newName = $newNameRule;
}
$this->newState = count($newState) === 0 ? null : $newState;
$this->copiedState = $copiedState;
}

View File

@ -0,0 +1,40 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\data\bedrock\block\upgrade\model;
final class BlockStateUpgradeSchemaModelFlattenedName{
/** @required */
public string $prefix;
/** @required */
public string $flattenedProperty;
/** @required */
public string $suffix;
public function __construct(string $prefix, string $flattenedProperty, string $suffix){
$this->prefix = $prefix;
$this->flattenedProperty = $flattenedProperty;
$this->suffix = $suffix;
}
}