mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-07-04 00:59:51 +00:00
RuntimeBlockMapping: use new data, item frames & doors fixed
floor & ceiling item frames not supported though
This commit is contained in:
parent
124e60301a
commit
8e984a1bc3
@ -284,7 +284,7 @@ class StartGamePacket extends DataPacket{
|
|||||||
if($this->blockTable === null){
|
if($this->blockTable === null){
|
||||||
if(self::$blockTableCache === null){
|
if(self::$blockTableCache === null){
|
||||||
//this is a really nasty hack, but it'll do for now
|
//this is a really nasty hack, but it'll do for now
|
||||||
self::$blockTableCache = (new NetworkLittleEndianNBTStream())->write(RuntimeBlockMapping::generateBlockTable());
|
self::$blockTableCache = (new NetworkLittleEndianNBTStream())->write(new ListTag("", RuntimeBlockMapping::getBedrockKnownStates()));
|
||||||
}
|
}
|
||||||
$this->put(self::$blockTableCache);
|
$this->put(self::$blockTableCache);
|
||||||
}else{
|
}else{
|
||||||
|
@ -24,7 +24,8 @@ declare(strict_types=1);
|
|||||||
namespace pocketmine\network\mcpe\protocol\types;
|
namespace pocketmine\network\mcpe\protocol\types;
|
||||||
|
|
||||||
use pocketmine\block\BlockIds;
|
use pocketmine\block\BlockIds;
|
||||||
use pocketmine\nbt\BigEndianNBTStream;
|
use pocketmine\nbt\NBT;
|
||||||
|
use pocketmine\nbt\NetworkLittleEndianNBTStream;
|
||||||
use pocketmine\nbt\tag\CompoundTag;
|
use pocketmine\nbt\tag\CompoundTag;
|
||||||
use pocketmine\nbt\tag\ListTag;
|
use pocketmine\nbt\tag\ListTag;
|
||||||
use pocketmine\nbt\tag\StringTag;
|
use pocketmine\nbt\tag\StringTag;
|
||||||
@ -45,7 +46,7 @@ final class RuntimeBlockMapping{
|
|||||||
private static $legacyToRuntimeMap = [];
|
private static $legacyToRuntimeMap = [];
|
||||||
/** @var int[] */
|
/** @var int[] */
|
||||||
private static $runtimeToLegacyMap = [];
|
private static $runtimeToLegacyMap = [];
|
||||||
/** @var mixed[]|null */
|
/** @var CompoundTag[]|null */
|
||||||
private static $bedrockKnownStates = null;
|
private static $bedrockKnownStates = null;
|
||||||
|
|
||||||
private function __construct(){
|
private function __construct(){
|
||||||
@ -53,36 +54,57 @@ final class RuntimeBlockMapping{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static function init() : void{
|
public static function init() : void{
|
||||||
|
$tag = (new NetworkLittleEndianNBTStream())->read(file_get_contents(\pocketmine\RESOURCE_PATH . "vanilla/required_block_states.nbt"));
|
||||||
|
if(!($tag instanceof ListTag) or $tag->getTagType() !== NBT::TAG_Compound){ //this is a little redundant currently, but good for auto complete and makes phpstan happy
|
||||||
|
throw new \RuntimeException("Invalid blockstates table, expected TAG_List<TAG_Compound> root");
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @var CompoundTag[] $list */
|
||||||
|
$list = $tag->getValue();
|
||||||
|
self::$bedrockKnownStates = self::randomizeTable($list);
|
||||||
|
|
||||||
|
self::setupLegacyMappings();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function setupLegacyMappings() : void{
|
||||||
$legacyIdMap = json_decode(file_get_contents(\pocketmine\RESOURCE_PATH . "vanilla/block_id_map.json"), true);
|
$legacyIdMap = json_decode(file_get_contents(\pocketmine\RESOURCE_PATH . "vanilla/block_id_map.json"), true);
|
||||||
$tag = (new BigEndianNBTStream())->read(file_get_contents(\pocketmine\RESOURCE_PATH . "vanilla/runtime_block_states.dat"));
|
$legacyStateMap = (new NetworkLittleEndianNBTStream())->read(file_get_contents(\pocketmine\RESOURCE_PATH . "vanilla/r12_to_current_block_map.nbt"));
|
||||||
if(!($tag instanceof CompoundTag)){ //this is a little redundant currently, but good for auto complete and makes phpstan happy
|
if(!($legacyStateMap instanceof ListTag) or $legacyStateMap->getTagType() !== NBT::TAG_Compound){
|
||||||
throw new \RuntimeException("Invalid blockstates table, expected CompoundTag root");
|
throw new \RuntimeException("Invalid legacy states mapping table, expected TAG_List<TAG_Compound> root");
|
||||||
}
|
}
|
||||||
|
|
||||||
$decompressed = [];
|
/**
|
||||||
|
* @var int[][] $idToStatesMap string id -> int[] list of candidate state indices
|
||||||
$states = $tag->getListTag("Palette");
|
*/
|
||||||
/** @var CompoundTag $state */
|
$idToStatesMap = [];
|
||||||
foreach($states as $state){
|
foreach(self::$bedrockKnownStates as $k => $state){
|
||||||
$block = $state->getCompoundTag("block");
|
$idToStatesMap[$state->getCompoundTag("block")->getString("name")][] = $k;
|
||||||
$name = $block->getString("name");
|
|
||||||
$decompressed[] = [
|
|
||||||
"name" => $name,
|
|
||||||
"states" => $block->getCompoundTag("states"),
|
|
||||||
"data" => $state->getShort("meta"),
|
|
||||||
"legacy_id" => $legacyIdMap[$name]
|
|
||||||
];
|
|
||||||
|
|
||||||
}
|
}
|
||||||
self::$bedrockKnownStates = self::randomizeTable($decompressed);
|
/** @var CompoundTag $pair */
|
||||||
|
foreach($legacyStateMap as $pair){
|
||||||
foreach(self::$bedrockKnownStates as $k => $obj){
|
$oldState = $pair->getCompoundTag("old");
|
||||||
if($obj["data"] > 15){
|
$id = $legacyIdMap[$oldState->getString("name")];
|
||||||
//TODO: in 1.12 they started using data values bigger than 4 bits which we can't handle right now
|
$data = $oldState->getShort("val");
|
||||||
|
if($data > 15){
|
||||||
|
//we can't handle metadata with more than 4 bits
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
//this has to use the json offset to make sure the mapping is consistent with what we send over network, even though we aren't using all the entries
|
$mappedState = $pair->getCompoundTag("new");
|
||||||
self::registerMapping($k, $obj["legacy_id"], $obj["data"]);
|
|
||||||
|
//TODO HACK: idiotic NBT compare behaviour on 3.x compares keys which are stored by values
|
||||||
|
$mappedState->setName("block");
|
||||||
|
$mappedName = $mappedState->getString("name");
|
||||||
|
if(!isset($idToStatesMap[$mappedName])){
|
||||||
|
throw new \RuntimeException("Mapped new state does not appear in network table");
|
||||||
|
}
|
||||||
|
foreach($idToStatesMap[$mappedName] as $k){
|
||||||
|
$networkState = self::$bedrockKnownStates[$k];
|
||||||
|
if($mappedState->equals($networkState->getCompoundTag("block"))){
|
||||||
|
self::registerMapping($k, $id, $data);
|
||||||
|
continue 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new \RuntimeException("Mapped new state does not appear in network table");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -97,9 +119,9 @@ final class RuntimeBlockMapping{
|
|||||||
* Plugins shouldn't use this stuff anyway, but plugin devs have an irritating habit of ignoring what they
|
* Plugins shouldn't use this stuff anyway, but plugin devs have an irritating habit of ignoring what they
|
||||||
* aren't supposed to do, so we have to deliberately break it to make them stop.
|
* aren't supposed to do, so we have to deliberately break it to make them stop.
|
||||||
*
|
*
|
||||||
* @param array $table
|
* @param CompoundTag[] $table
|
||||||
*
|
*
|
||||||
* @return array
|
* @return CompoundTag[]
|
||||||
*/
|
*/
|
||||||
private static function randomizeTable(array $table) : array{
|
private static function randomizeTable(array $table) : array{
|
||||||
$postSeed = mt_rand(); //save a seed to set afterwards, to avoid poor quality randoms
|
$postSeed = mt_rand(); //save a seed to set afterwards, to avoid poor quality randoms
|
||||||
@ -141,19 +163,11 @@ final class RuntimeBlockMapping{
|
|||||||
self::$runtimeToLegacyMap[$staticRuntimeId] = ($legacyId << 4) | $legacyMeta;
|
self::$runtimeToLegacyMap[$staticRuntimeId] = ($legacyId << 4) | $legacyMeta;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function generateBlockTable() : ListTag{
|
/**
|
||||||
|
* @return CompoundTag[]
|
||||||
|
*/
|
||||||
|
public static function getBedrockKnownStates() : array{
|
||||||
self::lazyInit();
|
self::lazyInit();
|
||||||
$states = new ListTag();
|
return self::$bedrockKnownStates;
|
||||||
//TODO: this assoc array mess really doesn't make sense anymore, we can store NBT directly
|
|
||||||
foreach(self::$bedrockKnownStates as $v){
|
|
||||||
$state = new CompoundTag();
|
|
||||||
$state->setTag(new CompoundTag("block", [
|
|
||||||
new StringTag("name", $v["name"]),
|
|
||||||
$v["states"]
|
|
||||||
]));
|
|
||||||
$state->setShort("id", $v["legacy_id"]);
|
|
||||||
$states->push($state);
|
|
||||||
}
|
|
||||||
return $states;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user