Throw proper exceptions for serialize/deserialize failures

this allows them to be caught and properly reported in tests.
This commit is contained in:
Dylan K. Taylor 2022-05-24 14:46:18 +01:00
parent 901a51a9dd
commit 5ce5e1d2b0
No known key found for this signature in database
GPG Key ID: 8927471A91CAFD3D
5 changed files with 89 additions and 20 deletions

View File

@ -188,6 +188,8 @@ final class BlockObjectToBlockStateSerializer implements BlockStateSerializer{
/**
* @phpstan-template TBlockType of Block
* @phpstan-param TBlockType $blockState
*
* @throws BlockStateSerializeException
*/
public function serializeBlock(Block $blockState) : BlockStateData{
$typeId = $blockState->getTypeId();

View File

@ -35,7 +35,6 @@ use pocketmine\data\bedrock\EntityLegacyIds;
use pocketmine\data\bedrock\item\ItemTypeIds as Ids;
use pocketmine\data\bedrock\item\SavedItemData as Data;
use pocketmine\data\bedrock\PotionTypeIdMap;
use pocketmine\data\SavedDataLoadingException;
use pocketmine\item\Item;
use pocketmine\item\PotionType;
use pocketmine\item\VanillaItems as Items;
@ -64,13 +63,16 @@ final class ItemDeserializer{
$this->deserializers[$id] = $deserializer;
}
/**
* @throws ItemTypeDeserializeException
*/
public function deserialize(Data $data) : Item{
if(($blockData = $data->getBlock()) !== null){
//TODO: this is rough duct tape; we need a better way to deal with this
try{
$block = GlobalBlockStateHandlers::getDeserializer()->deserialize($blockData);
}catch(BlockStateDeserializeException $e){
throw new SavedDataLoadingException("Failed to deserialize item data: " . $e->getMessage(), 0, $e);
throw new ItemTypeDeserializeException("Failed to deserialize item data: " . $e->getMessage(), 0, $e);
}
//TODO: worth caching this or not?
@ -78,7 +80,7 @@ final class ItemDeserializer{
}
$id = $data->getName();
if(!isset($this->deserializers[$id])){
throw new SavedDataLoadingException("No deserializer found for ID $id");
throw new ItemTypeDeserializeException("No deserializer found for ID $id");
}
return ($this->deserializers[$id])($data);
@ -97,7 +99,7 @@ final class ItemDeserializer{
if($data->getMeta() === 0){
return Items::ARROW();
}
throw new SavedDataLoadingException("Tipped arrows are not implemented yet");
throw new ItemTypeDeserializeException("Tipped arrows are not implemented yet");
});
//TODO: minecraft:axolotl_bucket
//TODO: minecraft:axolotl_spawn_egg
@ -107,7 +109,7 @@ final class ItemDeserializer{
$meta = $data->getMeta();
$color = DyeColorIdMap::getInstance()->fromInvertedId($meta);
if($color === null){
throw new SavedDataLoadingException("Unknown banner meta $meta");
throw new ItemTypeDeserializeException("Unknown banner meta $meta");
}
return Items::BANNER()->setColor($color);
});
@ -117,7 +119,7 @@ final class ItemDeserializer{
$meta = $data->getMeta();
$color = DyeColorIdMap::getInstance()->fromId($meta);
if($color === null){
throw new SavedDataLoadingException("Unknown bed meta $meta");
throw new ItemTypeDeserializeException("Unknown bed meta $meta");
}
return Blocks::BED()->setColor($color)->asItem();
});
@ -139,7 +141,7 @@ final class ItemDeserializer{
try{
$treeType = TreeType::fromMagicNumber($data->getMeta());
}catch(\InvalidArgumentException $e){
throw new SavedDataLoadingException($e->getMessage(), 0, $e);
throw new ItemTypeDeserializeException($e->getMessage(), 0, $e);
}
return match($treeType->id()){
TreeType::OAK()->id() => Items::OAK_BOAT(),
@ -229,7 +231,7 @@ final class ItemDeserializer{
CompoundTypeIds::HYDROGEN_PEROXIDE => Items::CHEMICAL_HYDROGEN_PEROXIDE(),
CompoundTypeIds::AMMONIA => Items::CHEMICAL_AMMONIA(),
CompoundTypeIds::SODIUM_HYPOCHLORITE => Items::CHEMICAL_SODIUM_HYPOCHLORITE(),
default => throw new SavedDataLoadingException("Unknown chemical meta " . $data->getMeta())
default => throw new ItemTypeDeserializeException("Unknown chemical meta " . $data->getMeta())
});
$this->map(Ids::COOKED_BEEF, fn() => Items::STEAK());
$this->map(Ids::COOKED_CHICKEN, fn() => Items::COOKED_CHICKEN());
@ -284,7 +286,7 @@ final class ItemDeserializer{
}
$dyeColor = DyeColorIdMap::getInstance()->fromInvertedId($meta);
if($dyeColor === null){
throw new SavedDataLoadingException("Unknown dye meta $meta");
throw new ItemTypeDeserializeException("Unknown dye meta $meta");
}
return match($dyeColor->id()){
DyeColor::CYAN()->id() => Items::CYAN_DYE(),
@ -475,7 +477,7 @@ final class ItemDeserializer{
$meta = $data->getMeta();
$potionType = PotionTypeIdMap::getInstance()->fromId($meta);
if($potionType === null){
throw new SavedDataLoadingException("Unknown potion type ID $meta");
throw new ItemTypeDeserializeException("Unknown potion type ID $meta");
}
return match($potionType->id()){
PotionType::WATER()->id() => Items::WATER_POTION(),
@ -520,7 +522,7 @@ final class ItemDeserializer{
PotionType::STRONG_TURTLE_MASTER()->id() => Items::STRONG_TURTLE_MASTER_POTION(),
PotionType::SLOW_FALLING()->id() => Items::SLOW_FALLING_POTION(),
PotionType::LONG_SLOW_FALLING()->id() => Items::LONG_SLOW_FALLING_POTION(),
default => throw new SavedDataLoadingException("Unhandled potion type " . $potionType->getDisplayName())
default => throw new ItemTypeDeserializeException("Unhandled potion type " . $potionType->getDisplayName())
};
});
//TODO: minecraft:powder_snow_bucket
@ -565,7 +567,7 @@ final class ItemDeserializer{
try{
$skullType = SkullType::fromMagicNumber($meta);
}catch(\InvalidArgumentException $e){
throw new SavedDataLoadingException($e->getMessage(), 0, $e);
throw new ItemTypeDeserializeException($e->getMessage(), 0, $e);
}
return match($skullType->id()) {
SkullType::SKELETON()->id() => Items::SKELETON_SKULL(),
@ -574,7 +576,7 @@ final class ItemDeserializer{
SkullType::CREEPER()->id() => Items::CREEPER_HEAD(),
SkullType::PLAYER()->id() => Items::PLAYER_HEAD(),
SkullType::DRAGON()->id() => Items::DRAGON_HEAD(),
default => throw new SavedDataLoadingException("Unexpected skull type " . $skullType->getDisplayName())
default => throw new ItemTypeDeserializeException("Unexpected skull type " . $skullType->getDisplayName())
};
});
//TODO: minecraft:skull_banner_pattern
@ -587,7 +589,7 @@ final class ItemDeserializer{
EntityLegacyIds::ZOMBIE => Items::ZOMBIE_SPAWN_EGG(),
EntityLegacyIds::SQUID => Items::SQUID_SPAWN_EGG(),
EntityLegacyIds::VILLAGER => Items::VILLAGER_SPAWN_EGG(),
default => throw new SavedDataLoadingException("Unhandled spawn egg meta " . $data->getMeta())
default => throw new ItemTypeDeserializeException("Unhandled spawn egg meta " . $data->getMeta())
});
$this->map(Ids::SPIDER_EYE, fn() => Items::SPIDER_EYE());
//TODO: minecraft:spider_spawn_egg
@ -595,7 +597,7 @@ final class ItemDeserializer{
$meta = $data->getMeta();
$potionType = PotionTypeIdMap::getInstance()->fromId($meta);
if($potionType === null){
throw new SavedDataLoadingException("Unknown potion type ID $meta");
throw new ItemTypeDeserializeException("Unknown potion type ID $meta");
}
return match($potionType->id()){
PotionType::WATER()->id() => Items::WATER_SPLASH_POTION(),
@ -640,7 +642,7 @@ final class ItemDeserializer{
PotionType::STRONG_TURTLE_MASTER()->id() => Items::STRONG_TURTLE_MASTER_SPLASH_POTION(),
PotionType::SLOW_FALLING()->id() => Items::SLOW_FALLING_SPLASH_POTION(),
PotionType::LONG_SLOW_FALLING()->id() => Items::LONG_SLOW_FALLING_SPLASH_POTION(),
default => throw new SavedDataLoadingException("Unhandled potion type " . $potionType->getDisplayName())
default => throw new ItemTypeDeserializeException("Unhandled potion type " . $potionType->getDisplayName())
};
});
$this->map(Ids::SPRUCE_BOAT, fn() => Items::SPRUCE_BOAT());

View File

@ -27,6 +27,7 @@ use pocketmine\block\Block;
use pocketmine\block\utils\DyeColor;
use pocketmine\block\utils\SkullType;
use pocketmine\data\bedrock\BlockItemIdMap;
use pocketmine\data\bedrock\blockstate\BlockStateSerializeException;
use pocketmine\data\bedrock\CompoundTypeIds;
use pocketmine\data\bedrock\DyeColorIdMap;
use pocketmine\data\bedrock\item\ItemTypeIds as Ids;
@ -78,6 +79,8 @@ final class ItemSerializer{
/**
* @phpstan-template TItemType of Item
* @phpstan-param TItemType $item
*
* @throws ItemTypeSerializeException
*/
public function serialize(Item $item) : Data{
if($item->isNull()){
@ -102,8 +105,7 @@ final class ItemSerializer{
}
if($locatedSerializer === null){
//TODO: proper exceptions
throw new \LogicException("No serializer registered for " . get_class($item) . " " . $item->getName());
throw new ItemTypeSerializeException("No serializer registered for " . get_class($item) . " " . $item->getName());
}
/**
@ -119,15 +121,22 @@ final class ItemSerializer{
return $data;
}
/**
* @throws ItemTypeSerializeException
*/
private static function standardBlock(Block $block) : Data{
$blockStateData = GlobalBlockStateHandlers::getSerializer()->serialize($block->getFullId());
try{
$blockStateData = GlobalBlockStateHandlers::getSerializer()->serialize($block->getFullId());
}catch(BlockStateSerializeException $e){
throw new ItemTypeSerializeException($e->getMessage(), 0, $e);
}
$itemNameId = BlockItemIdMap::getInstance()->lookupItemId($blockStateData->getName());
if($itemNameId === null){
//TODO: this might end up being a hassle for custom blocks, since it'll force providing an item
//serializer for every custom block
//it would probably be better if we allow adding custom item <-> block ID mappings for this
throw new \LogicException("No blockitem serializer or blockitem ID mapping registered for block " . $blockStateData->getName());
throw new ItemTypeSerializeException("No blockitem serializer or blockitem ID mapping registered for block " . $blockStateData->getName());
}
return new Data($itemNameId, 0, $blockStateData);

View File

@ -0,0 +1,28 @@
<?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\item;
final class ItemTypeDeserializeException extends \RuntimeException{
}

View File

@ -0,0 +1,28 @@
<?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\item;
final class ItemTypeSerializeException extends \LogicException{
}