mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-04-21 08:17:34 +00:00
world IO: fixed crashes when garbage data found in tile/entity NBT data
This commit is contained in:
parent
9a4b72add5
commit
37a8d95464
@ -26,6 +26,7 @@ namespace pocketmine\level\format\io\leveldb;
|
||||
use pocketmine\level\format\Chunk;
|
||||
use pocketmine\level\format\io\BaseLevelProvider;
|
||||
use pocketmine\level\format\io\ChunkUtils;
|
||||
use pocketmine\level\format\io\exception\CorruptedChunkException;
|
||||
use pocketmine\level\format\io\exception\UnsupportedChunkFormatException;
|
||||
use pocketmine\level\format\SubChunk;
|
||||
use pocketmine\level\generator\Flat;
|
||||
@ -414,24 +415,27 @@ class LevelDB extends BaseLevelProvider{
|
||||
/** @var CompoundTag[] $entities */
|
||||
$entities = [];
|
||||
if(($entityData = $this->db->get($index . self::TAG_ENTITY)) !== false and $entityData !== ""){
|
||||
$entities = $nbt->read($entityData, true);
|
||||
if(!is_array($entities)){
|
||||
$entities = [$entities];
|
||||
}
|
||||
}
|
||||
|
||||
/** @var CompoundTag $entityNBT */
|
||||
foreach($entities as $entityNBT){
|
||||
if($entityNBT->hasTag("id", IntTag::class)){
|
||||
$entityNBT->setInt("id", $entityNBT->getInt("id") & 0xff); //remove type flags - TODO: use these instead of removing them)
|
||||
$entityTags = $nbt->read($entityData, true);
|
||||
foreach((is_array($entityTags) ? $entityTags : [$entityTags]) as $entityTag){
|
||||
if(!($entityTag instanceof CompoundTag)){
|
||||
throw new CorruptedChunkException("Entity root tag should be TAG_Compound");
|
||||
}
|
||||
if($entityTag->hasTag("id", IntTag::class)){
|
||||
$entityTag->setInt("id", $entityTag->getInt("id") & 0xff); //remove type flags - TODO: use these instead of removing them)
|
||||
}
|
||||
$entities[] = $entityTag;
|
||||
}
|
||||
}
|
||||
|
||||
/** @var CompoundTag[] $tiles */
|
||||
$tiles = [];
|
||||
if(($tileData = $this->db->get($index . self::TAG_BLOCK_ENTITY)) !== false and $tileData !== ""){
|
||||
$tiles = $nbt->read($tileData, true);
|
||||
if(!is_array($tiles)){
|
||||
$tiles = [$tiles];
|
||||
$tileTags = $nbt->read($tileData, true);
|
||||
foreach((is_array($tileTags) ? $tileTags : [$tileTags]) as $tileTag){
|
||||
if(!($tileTag instanceof CompoundTag)){
|
||||
throw new CorruptedChunkException("Tile root tag should be TAG_Compound");
|
||||
}
|
||||
$tiles[] = $tileTag;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -122,8 +122,8 @@ class Anvil extends McRegion{
|
||||
$chunk->getInt("xPos"),
|
||||
$chunk->getInt("zPos"),
|
||||
$subChunks,
|
||||
$chunk->hasTag("Entities", ListTag::class) ? $chunk->getListTag("Entities")->getValue() : [],
|
||||
$chunk->hasTag("TileEntities", ListTag::class) ? $chunk->getListTag("TileEntities")->getValue() : [],
|
||||
$chunk->hasTag("Entities", ListTag::class) ? self::getCompoundList("Entities", $chunk->getListTag("Entities")) : [],
|
||||
$chunk->hasTag("TileEntities", ListTag::class) ? self::getCompoundList("TileEntities", $chunk->getListTag("TileEntities")) : [],
|
||||
$biomeIds,
|
||||
$chunk->getIntArray("HeightMap", [])
|
||||
);
|
||||
|
@ -194,8 +194,8 @@ class McRegion extends BaseLevelProvider{
|
||||
$chunk->getInt("xPos"),
|
||||
$chunk->getInt("zPos"),
|
||||
$subChunks,
|
||||
$chunk->hasTag("Entities", ListTag::class) ? $chunk->getListTag("Entities")->getValue() : [],
|
||||
$chunk->hasTag("TileEntities", ListTag::class) ? $chunk->getListTag("TileEntities")->getValue() : [],
|
||||
$chunk->hasTag("Entities", ListTag::class) ? self::getCompoundList("Entities", $chunk->getListTag("Entities")) : [],
|
||||
$chunk->hasTag("TileEntities", ListTag::class) ? self::getCompoundList("TileEntities", $chunk->getListTag("TileEntities")) : [],
|
||||
$biomeIds,
|
||||
$heightMap
|
||||
);
|
||||
@ -205,6 +205,31 @@ class McRegion extends BaseLevelProvider{
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $context
|
||||
* @param ListTag $list
|
||||
*
|
||||
* @return CompoundTag[]
|
||||
* @throws CorruptedChunkException
|
||||
*/
|
||||
protected static function getCompoundList(string $context, ListTag $list) : array{
|
||||
if($list->count() === 0){ //empty lists might have wrong types, we don't care
|
||||
return [];
|
||||
}
|
||||
if($list->getTagType() !== NBT::TAG_Compound){
|
||||
throw new CorruptedChunkException("Expected TAG_List<TAG_Compound> for '$context'");
|
||||
}
|
||||
$result = [];
|
||||
foreach($list as $tag){
|
||||
if(!($tag instanceof CompoundTag)){
|
||||
//this should never happen, but it's still possible due to lack of native type safety
|
||||
throw new CorruptedChunkException("Expected TAG_List<TAG_Compound> for '$context'");
|
||||
}
|
||||
$result[] = $tag;
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
public static function getProviderName() : string{
|
||||
return "mcregion";
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user