diff --git a/src/pocketmine/Server.php b/src/pocketmine/Server.php index ddf6f4ac5..acdc1bc4b 100644 --- a/src/pocketmine/Server.php +++ b/src/pocketmine/Server.php @@ -1677,7 +1677,6 @@ class Server{ Entity::init(); Tile::init(); BlockFactory::init(); - BlockFactory::registerStaticRuntimeIdMappings(); Enchantment::init(); ItemFactory::init(); Item::initCreativeItems(); diff --git a/src/pocketmine/block/Block.php b/src/pocketmine/block/Block.php index 9fc9e0d85..5646c8af1 100644 --- a/src/pocketmine/block/Block.php +++ b/src/pocketmine/block/Block.php @@ -36,6 +36,7 @@ use pocketmine\math\RayTraceResult; use pocketmine\math\Vector3; use pocketmine\metadata\Metadatable; use pocketmine\metadata\MetadataValue; +use pocketmine\network\mcpe\protocol\types\RuntimeBlockMapping; use pocketmine\Player; use pocketmine\plugin\Plugin; use function array_merge; @@ -117,7 +118,7 @@ class Block extends Position implements BlockIds, Metadatable{ * @return int */ public function getRuntimeId() : int{ - return BlockFactory::toStaticRuntimeId($this->getId(), $this->getDamage()); + return RuntimeBlockMapping::toStaticRuntimeId($this->getId(), $this->getDamage()); } /** diff --git a/src/pocketmine/block/BlockFactory.php b/src/pocketmine/block/BlockFactory.php index 5f0427a85..99c29bbf0 100644 --- a/src/pocketmine/block/BlockFactory.php +++ b/src/pocketmine/block/BlockFactory.php @@ -25,9 +25,7 @@ namespace pocketmine\block; use pocketmine\item\Item; use pocketmine\level\Position; -use function file_get_contents; -use function json_decode; -use function max; +use pocketmine\network\mcpe\protocol\types\RuntimeBlockMapping; use function min; /** @@ -52,15 +50,6 @@ class BlockFactory{ /** @var \SplFixedArray */ public static $blastResistance = null; - /** @var int[] */ - public static $staticRuntimeIdMap = []; - - /** @var int[] */ - public static $legacyIdMap = []; - - /** @var int */ - private static $lastRuntimeId = 0; - /** * Initializes the block factory. By default this is called only once on server start, however you may wish to use * this if you need to reset the block factory back to its original defaults for whatever reason. @@ -427,21 +416,9 @@ class BlockFactory{ return $b !== null and !($b instanceof UnknownBlock); } - public static function registerStaticRuntimeIdMappings() : void{ - /** @var mixed[] $runtimeIdMap */ - $runtimeIdMap = json_decode(file_get_contents(\pocketmine\RESOURCE_PATH . "runtimeid_table.json"), true); - $legacyIdMap = json_decode(file_get_contents(\pocketmine\RESOURCE_PATH . "legacy_id_map.json"), true); - foreach($runtimeIdMap as $k => $obj){ - //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 - if(!isset($legacyIdMap[$obj["name"]])){ - continue; - } - self::registerMapping($k, $legacyIdMap[$obj["name"]], $obj["data"]); - } - } - /** * @internal + * @deprecated * * @param int $id * @param int $meta @@ -449,15 +426,11 @@ class BlockFactory{ * @return int */ public static function toStaticRuntimeId(int $id, int $meta = 0) : int{ - /* - * try id+meta first - * if not found, try id+0 (strip meta) - * if still not found, return update! block - */ - return self::$staticRuntimeIdMap[($id << 4) | $meta] ?? self::$staticRuntimeIdMap[$id << 4] ?? self::$staticRuntimeIdMap[BlockIds::INFO_UPDATE << 4]; + return RuntimeBlockMapping::toStaticRuntimeId($id, $meta); } /** + * @deprecated * @internal * * @param int $runtimeId @@ -465,13 +438,6 @@ class BlockFactory{ * @return int[] [id, meta] */ public static function fromStaticRuntimeId(int $runtimeId) : array{ - $v = self::$legacyIdMap[$runtimeId]; - return [$v >> 4, $v & 0xf]; - } - - private static function registerMapping(int $staticRuntimeId, int $legacyId, int $legacyMeta) : void{ - self::$staticRuntimeIdMap[($legacyId << 4) | $legacyMeta] = $staticRuntimeId; - self::$legacyIdMap[$staticRuntimeId] = ($legacyId << 4) | $legacyMeta; - self::$lastRuntimeId = max(self::$lastRuntimeId, $staticRuntimeId); + return RuntimeBlockMapping::fromStaticRuntimeId($runtimeId); } } diff --git a/src/pocketmine/level/Level.php b/src/pocketmine/level/Level.php index bde1fb9ab..306733035 100644 --- a/src/pocketmine/level/Level.php +++ b/src/pocketmine/level/Level.php @@ -78,6 +78,7 @@ use pocketmine\network\mcpe\protocol\LevelEventPacket; use pocketmine\network\mcpe\protocol\LevelSoundEventPacket; use pocketmine\network\mcpe\protocol\SetDifficultyPacket; use pocketmine\network\mcpe\protocol\SetTimePacket; +use pocketmine\network\mcpe\protocol\types\RuntimeBlockMapping; use pocketmine\network\mcpe\protocol\UpdateBlockPacket; use pocketmine\Player; use pocketmine\plugin\Plugin; @@ -982,7 +983,7 @@ class Level implements ChunkManager, Metadatable{ $pk->blockRuntimeId = $b->getRuntimeId(); }else{ $fullBlock = $this->getFullBlock($b->x, $b->y, $b->z); - $pk->blockRuntimeId = BlockFactory::toStaticRuntimeId($fullBlock >> 4, $fullBlock & 0xf); + $pk->blockRuntimeId = RuntimeBlockMapping::toStaticRuntimeId($fullBlock >> 4, $fullBlock & 0xf); } $pk->flags = $first ? $flags : UpdateBlockPacket::FLAG_NONE; @@ -1004,7 +1005,7 @@ class Level implements ChunkManager, Metadatable{ $pk->blockRuntimeId = $b->getRuntimeId(); }else{ $fullBlock = $this->getFullBlock($b->x, $b->y, $b->z); - $pk->blockRuntimeId = BlockFactory::toStaticRuntimeId($fullBlock >> 4, $fullBlock & 0xf); + $pk->blockRuntimeId = RuntimeBlockMapping::toStaticRuntimeId($fullBlock >> 4, $fullBlock & 0xf); } $pk->flags = $flags; diff --git a/src/pocketmine/network/mcpe/protocol/StartGamePacket.php b/src/pocketmine/network/mcpe/protocol/StartGamePacket.php index d3812c295..e8bf765d5 100644 --- a/src/pocketmine/network/mcpe/protocol/StartGamePacket.php +++ b/src/pocketmine/network/mcpe/protocol/StartGamePacket.php @@ -30,9 +30,8 @@ use pocketmine\math\Vector3; use pocketmine\network\mcpe\NetworkBinaryStream; use pocketmine\network\mcpe\NetworkSession; use pocketmine\network\mcpe\protocol\types\PlayerPermissions; +use pocketmine\network\mcpe\protocol\types\RuntimeBlockMapping; use function count; -use function file_get_contents; -use function json_decode; class StartGamePacket extends DataPacket{ public const NETWORK_ID = ProtocolInfo::START_GAME_PACKET; @@ -251,7 +250,7 @@ class StartGamePacket extends DataPacket{ if(self::$runtimeIdTable === null){ //this is a really nasty hack, but it'll do for now $stream = new NetworkBinaryStream(); - $data = json_decode(file_get_contents(\pocketmine\RESOURCE_PATH . "runtimeid_table.json"), true); + $data = RuntimeBlockMapping::getBedrockKnownStates(); $stream->putUnsignedVarInt(count($data)); foreach($data as $v){ $stream->putString($v["name"]); diff --git a/src/pocketmine/network/mcpe/protocol/types/RuntimeBlockMapping.php b/src/pocketmine/network/mcpe/protocol/types/RuntimeBlockMapping.php new file mode 100644 index 000000000..a56cfb721 --- /dev/null +++ b/src/pocketmine/network/mcpe/protocol/types/RuntimeBlockMapping.php @@ -0,0 +1,118 @@ + $obj){ + //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 + if(!isset($legacyIdMap[$obj["name"]])){ + continue; + } + self::registerMapping($k, $legacyIdMap[$obj["name"]], $obj["data"]); + } + } + + /** + * Randomizes the order of the runtimeID table to prevent plugins relying on them. + * 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. + * + * @param array $table + * + * @return array + */ + private static function randomizeTable(array $table) : array{ + $postSeed = mt_rand(); //save a seed to set afterwards, to avoid poor quality randoms + mt_srand(getmypid() ?: 0); //Use a seed which is the same on all threads. This isn't a secure seed, but we don't care. + shuffle($table); + mt_srand($postSeed); //restore a good quality seed that isn't dependent on PID + return $table; + } + + /** + * @param int $id + * @param int $meta + * + * @return int + */ + public static function toStaticRuntimeId(int $id, int $meta = 0) : int{ + /* + * try id+meta first + * if not found, try id+0 (strip meta) + * if still not found, return update! block + */ + return self::$legacyToRuntimeMap[($id << 4) | $meta] ?? self::$legacyToRuntimeMap[$id << 4] ?? self::$legacyToRuntimeMap[BlockIds::INFO_UPDATE << 4]; + } + + /** + * @param int $runtimeId + * + * @return int[] [id, meta] + */ + public static function fromStaticRuntimeId(int $runtimeId) : array{ + $v = self::$runtimeToLegacyMap[$runtimeId]; + return [$v >> 4, $v & 0xf]; + } + + private static function registerMapping(int $staticRuntimeId, int $legacyId, int $legacyMeta) : void{ + self::$legacyToRuntimeMap[($legacyId << 4) | $legacyMeta] = $staticRuntimeId; + self::$runtimeToLegacyMap[$staticRuntimeId] = ($legacyId << 4) | $legacyMeta; + } + + /** + * @return array + */ + public static function getBedrockKnownStates() : array{ + return self::$bedrockKnownStates; + } +} +RuntimeBlockMapping::init();