New way to spawn entities/tiles using a global register table, allow overriding default entity/tile classes via classes

This commit is contained in:
Shoghi Cervantes 2014-10-28 13:09:27 +01:00
parent a5b85c549a
commit 34ae760def
18 changed files with 154 additions and 94 deletions

View File

@ -24,7 +24,7 @@ namespace pocketmine;
use pocketmine\block\Block; use pocketmine\block\Block;
use pocketmine\command\CommandSender; use pocketmine\command\CommandSender;
use pocketmine\entity\Arrow; use pocketmine\entity\Arrow;
use pocketmine\entity\DroppedItem; use pocketmine\entity\Item as DroppedItem;
use pocketmine\entity\Entity; use pocketmine\entity\Entity;
use pocketmine\entity\Human; use pocketmine\entity\Human;
use pocketmine\entity\Living; use pocketmine\entity\Living;
@ -1650,7 +1650,7 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{
]); ]);
$f = 1.5; $f = 1.5;
$snowball = new Snowball($this->chunk, $nbt, $this); $snowball = Entity::createEntity("Snowball", $this->chunk, $nbt, $this);
$snowball->setMotion($snowball->getMotion()->multiply($f)); $snowball->setMotion($snowball->getMotion()->multiply($f));
if($this->isSurvival()){ if($this->isSurvival()){
$this->inventory->removeItem(Item::get(Item::SNOWBALL, 0, 1)); $this->inventory->removeItem(Item::get(Item::SNOWBALL, 0, 1));
@ -1709,7 +1709,7 @@ class Player extends Human implements CommandSender, InventoryHolder, IPlayer{
]); ]);
$f = 1.5; $f = 1.5;
$ev = EntityShootBowEvent::createEvent($this, $bow, new Arrow($this->chunk, $nbt, $this), $f); $ev = EntityShootBowEvent::createEvent($this, $bow, Entity::createEntity("Arrow", $this->chunk, $nbt, $this), $f);
$this->server->getPluginManager()->callEvent($ev); $this->server->getPluginManager()->callEvent($ev);

View File

@ -31,12 +31,21 @@ use pocketmine\command\CommandSender;
use pocketmine\command\ConsoleCommandSender; use pocketmine\command\ConsoleCommandSender;
use pocketmine\command\PluginIdentifiableCommand; use pocketmine\command\PluginIdentifiableCommand;
use pocketmine\command\SimpleCommandMap; use pocketmine\command\SimpleCommandMap;
use pocketmine\entity\Arrow;
use pocketmine\entity\Entity;
use pocketmine\entity\FallingSand;
use pocketmine\entity\Human;
use pocketmine\entity\PrimedTNT;
use pocketmine\entity\Snowball;
use pocketmine\entity\Villager;
use pocketmine\entity\Zombie;
use pocketmine\event\Event; use pocketmine\event\Event;
use pocketmine\event\HandlerList; use pocketmine\event\HandlerList;
use pocketmine\event\level\LevelInitEvent; use pocketmine\event\level\LevelInitEvent;
use pocketmine\event\level\LevelLoadEvent; use pocketmine\event\level\LevelLoadEvent;
use pocketmine\event\server\ServerCommandEvent; use pocketmine\event\server\ServerCommandEvent;
use pocketmine\event\Timings; use pocketmine\event\Timings;
use pocketmine\entity\Item as DroppedItem;
use pocketmine\event\TimingsHandler; use pocketmine\event\TimingsHandler;
use pocketmine\inventory\CraftingManager; use pocketmine\inventory\CraftingManager;
use pocketmine\inventory\InventoryType; use pocketmine\inventory\InventoryType;
@ -82,6 +91,10 @@ use pocketmine\plugin\PluginManager;
use pocketmine\scheduler\CallbackTask; use pocketmine\scheduler\CallbackTask;
use pocketmine\scheduler\SendUsageTask; use pocketmine\scheduler\SendUsageTask;
use pocketmine\scheduler\ServerScheduler; use pocketmine\scheduler\ServerScheduler;
use pocketmine\tile\Chest;
use pocketmine\tile\Furnace;
use pocketmine\tile\Sign;
use pocketmine\tile\Tile;
use pocketmine\updater\AutoUpdater; use pocketmine\updater\AutoUpdater;
use pocketmine\utils\Binary; use pocketmine\utils\Binary;
use pocketmine\utils\Cache; use pocketmine\utils\Cache;
@ -1553,6 +1566,9 @@ class Server{
$this->consoleSender = new ConsoleCommandSender(); $this->consoleSender = new ConsoleCommandSender();
$this->commandMap = new SimpleCommandMap($this); $this->commandMap = new SimpleCommandMap($this);
$this->registerEntities();
$this->registerTiles();
InventoryType::init(); InventoryType::init();
Block::init(); Block::init();
Item::init(); Item::init();
@ -2142,4 +2158,22 @@ class Server{
return true; return true;
} }
private function registerEntities(){
Entity::registerEntity(Arrow::class);
Entity::registerEntity(DroppedItem::class);
Entity::registerEntity(FallingSand::class);
Entity::registerEntity(PrimedTNT::class);
Entity::registerEntity(Snowball::class);
Entity::registerEntity(Villager::class);
Entity::registerEntity(Zombie::class);
Entity::registerEntity(Human::class, true);
}
private function registerTiles(){
Tile::registerTile(Chest::class);
Tile::registerTile(Furnace::class);
Tile::registerTile(Sign::class);
}
} }

View File

@ -55,7 +55,7 @@ class BurningFurnace extends Solid{
new Int("z", $this->z) new Int("z", $this->z)
]); ]);
$nbt->Items->setTagType(NBT::TAG_Compound); $nbt->Items->setTagType(NBT::TAG_Compound);
new Furnace($this->getLevel()->getChunk($this->x >> 4, $this->z >> 4), $nbt); Tile::createTile("Furnace", $this->getLevel()->getChunk($this->x >> 4, $this->z >> 4), $nbt);
return true; return true;
} }
@ -81,7 +81,7 @@ class BurningFurnace extends Solid{
new Int("z", $this->z) new Int("z", $this->z)
]); ]);
$nbt->Items->setTagType(NBT::TAG_Compound); $nbt->Items->setTagType(NBT::TAG_Compound);
$furnace = new Furnace($this->getLevel()->getChunk($this->x >> 4, $this->z >> 4), $nbt); $furnace = Tile::createTile("Furnace", $this->getLevel()->getChunk($this->x >> 4, $this->z >> 4), $nbt);
} }
if(($player->getGamemode() & 0x01) === 0x01){ if(($player->getGamemode() & 0x01) === 0x01){

View File

@ -90,9 +90,9 @@ class Chest extends Transparent{
new Int("z", $this->z) new Int("z", $this->z)
]); ]);
$nbt->Items->setTagType(NBT::TAG_Compound); $nbt->Items->setTagType(NBT::TAG_Compound);
$tile = new TileChest($this->getLevel()->getChunk($this->x >> 4, $this->z >> 4), $nbt); $tile = Tile::createTile("Chest", $this->getLevel()->getChunk($this->x >> 4, $this->z >> 4), $nbt);
if($chest instanceof TileChest){ if($chest instanceof TileChest and $tile instanceof TileChest){
$chest->pairWith($tile); $chest->pairWith($tile);
$tile->pairWith($chest); $tile->pairWith($chest);
} }

View File

@ -21,7 +21,8 @@
namespace pocketmine\block; namespace pocketmine\block;
use pocketmine\entity\FallingBlock; use pocketmine\entity\Entity;
use pocketmine\entity\FallingSand;
use pocketmine\item\Item; use pocketmine\item\Item;
use pocketmine\level\Level; use pocketmine\level\Level;
use pocketmine\nbt\tag\Byte; use pocketmine\nbt\tag\Byte;
@ -46,7 +47,7 @@ abstract class Fallable extends Solid{
if($this->hasPhysics === true and $type === Level::BLOCK_UPDATE_NORMAL){ if($this->hasPhysics === true and $type === Level::BLOCK_UPDATE_NORMAL){
$down = $this->getSide(0); $down = $this->getSide(0);
if($down->getID() === self::AIR or ($down instanceof Liquid)){ if($down->getID() === self::AIR or ($down instanceof Liquid)){
$fall = new FallingBlock($this->getLevel()->getChunk($this->x >> 4, $this->z >> 4), new Compound("", [ $fall = Entity::createEntity("FallingSand", $this->getLevel()->getChunk($this->x >> 4, $this->z >> 4), new Compound("", [
"Pos" => new Enum("Pos", [ "Pos" => new Enum("Pos", [
new Double("", $this->x + 0.5), new Double("", $this->x + 0.5),
new Double("", $this->y), new Double("", $this->y),
@ -67,8 +68,6 @@ abstract class Fallable extends Solid{
$fall->spawnToAll(); $fall->spawnToAll();
} }
return false;
} }
} }
} }

View File

@ -21,6 +21,7 @@
namespace pocketmine\block; namespace pocketmine\block;
use pocketmine\entity\Entity;
use pocketmine\entity\PrimedTNT; use pocketmine\entity\PrimedTNT;
use pocketmine\item\Item; use pocketmine\item\Item;
use pocketmine\nbt\tag\Byte; use pocketmine\nbt\tag\Byte;
@ -44,7 +45,7 @@ class TNT extends Solid{
$this->getLevel()->setBlock($this, new Air(), true); $this->getLevel()->setBlock($this, new Air(), true);
$mot = (new Random())->nextSignedFloat() * M_PI * 2; $mot = (new Random())->nextSignedFloat() * M_PI * 2;
$tnt = new PrimedTNT($this->getLevel()->getChunk($this->x >> 4, $this->z >> 4), new Compound("", [ $tnt = Entity::createEntity("PrimedTNT", $this->getLevel()->getChunk($this->x >> 4, $this->z >> 4), new Compound("", [
"Pos" => new Enum("Pos", [ "Pos" => new Enum("Pos", [
new Double("", $this->x + 0.5), new Double("", $this->x + 0.5),
new Double("", $this->y), new Double("", $this->y),

View File

@ -62,9 +62,12 @@ use pocketmine\Server;
abstract class Entity extends Location implements Metadatable{ abstract class Entity extends Location implements Metadatable{
const NETWORK_ID = -1; const NETWORK_ID = -1;
public static $entityCount = 1; public static $entityCount = 1;
/** @var Entity[] */
private static $knownEntities = [];
/** /**
* @var Player[] * @var Player[]
@ -219,6 +222,39 @@ abstract class Entity extends Location implements Metadatable{
} }
/**
* @param int|string $type
* @param FullChunk $chunk
* @param Compound $nbt
* @param $args
*
* @return Entity
*/
public static function createEntity($type, FullChunk $chunk, Compound $nbt, ...$args){
if(isset(self::$knownEntities[$type])){
$class = self::$knownEntities[$type];
return new $class($chunk, $nbt, ...$args);
}
return null;
}
public static function registerEntity($className, $force = false){
$class = new \ReflectionClass($className);
if(is_a($className, Entity::class, true) and !$class->isAbstract()){
if($className::NETWORK_ID !== -1){
self::$knownEntities[$className::NETWORK_ID] = $className;
}elseif(!$force){
return false;
}
self::$knownEntities[$class->getShortName()] = $className;
return true;
}
return false;
}
public function saveNBT(){ public function saveNBT(){
$this->namedtag->Pos = new Enum("Pos", [ $this->namedtag->Pos = new Enum("Pos", [
new Double(0, $this->x), new Double(0, $this->x),

View File

@ -35,8 +35,7 @@ use pocketmine\network\protocol\AddEntityPacket;
use pocketmine\network\protocol\SetEntityMotionPacket; use pocketmine\network\protocol\SetEntityMotionPacket;
use pocketmine\Player; use pocketmine\Player;
class FallingBlock extends Entity{ class FallingSand extends Entity{
const NETWORK_ID = 66; const NETWORK_ID = 66;
public $width = 0.98; public $width = 0.98;
@ -54,8 +53,7 @@ class FallingBlock extends Entity{
$this->namedtag->id = new String("id", "FallingSand"); $this->namedtag->id = new String("id", "FallingSand");
if(isset($this->namedtag->TileID)){ if(isset($this->namedtag->TileID)){
$this->blockId = $this->namedtag["TileID"]; $this->blockId = $this->namedtag["TileID"];
} }elseif(isset($this->namedtag->Tile)){
elseif(isset($this->namedtag->Tile)){
$this->blockId = $this->namedtag["Tile"]; $this->blockId = $this->namedtag["Tile"];
$this->namedtag["TileID"] = new Int("TileID", $this->blockId); $this->namedtag["TileID"] = new Int("TileID", $this->blockId);
} }
@ -151,7 +149,7 @@ class FallingBlock extends Entity{
public function spawnTo(Player $player){ public function spawnTo(Player $player){
$pk = AddEntityPacket::getFromPool(); $pk = AddEntityPacket::getFromPool();
$pk->type = FallingBlock::NETWORK_ID; $pk->type = FallingSand::NETWORK_ID;
$pk->eid = $this->getID(); $pk->eid = $this->getID();
$pk->x = $this->x; $pk->x = $this->x;
$pk->y = $this->y; $pk->y = $this->y;

View File

@ -25,7 +25,7 @@ use pocketmine\event\entity\EntityDamageEvent;
use pocketmine\event\entity\EntityRegainHealthEvent; use pocketmine\event\entity\EntityRegainHealthEvent;
use pocketmine\event\entity\ItemDespawnEvent; use pocketmine\event\entity\ItemDespawnEvent;
use pocketmine\event\entity\ItemSpawnEvent; use pocketmine\event\entity\ItemSpawnEvent;
use pocketmine\item\Item; use pocketmine\item\Item as ItemItem;
use pocketmine\math\Vector3; use pocketmine\math\Vector3;
use pocketmine\nbt\tag\Byte; use pocketmine\nbt\tag\Byte;
use pocketmine\nbt\tag\Compound; use pocketmine\nbt\tag\Compound;
@ -35,12 +35,13 @@ use pocketmine\network\protocol\AddItemEntityPacket;
use pocketmine\network\protocol\SetEntityMotionPacket; use pocketmine\network\protocol\SetEntityMotionPacket;
use pocketmine\Player; use pocketmine\Player;
class DroppedItem extends Entity{ class Item extends Entity{
const NETWORK_ID = 64;
protected $owner = null; protected $owner = null;
protected $thrower = null; protected $thrower = null;
protected $pickupDelay = 0; protected $pickupDelay = 0;
/** @var Item */ /** @var ItemItem */
protected $item; protected $item;
public $width = 0.25; public $width = 0.25;
@ -67,7 +68,7 @@ class DroppedItem extends Entity{
if(isset($this->namedtag->Thrower)){ if(isset($this->namedtag->Thrower)){
$this->thrower = $this->namedtag["Thrower"]; $this->thrower = $this->namedtag["Thrower"];
} }
$this->item = Item::get($this->namedtag->Item["id"], $this->namedtag->Item["Damage"], $this->namedtag->Item["Count"]); $this->item = ItemItem::get($this->namedtag->Item["id"], $this->namedtag->Item["Damage"], $this->namedtag->Item["Count"]);
$this->server->getPluginManager()->callEvent(ItemSpawnEvent::createEvent($this)); $this->server->getPluginManager()->callEvent(ItemSpawnEvent::createEvent($this));
@ -166,7 +167,7 @@ class DroppedItem extends Entity{
} }
/** /**
* @return Item * @return ItemItem
*/ */
public function getItem(){ public function getItem(){
return $this->item; return $this->item;

View File

@ -22,7 +22,7 @@
namespace pocketmine\event\entity; namespace pocketmine\event\entity;
use pocketmine\entity\Creature; use pocketmine\entity\Creature;
use pocketmine\entity\DroppedItem; use pocketmine\entity\Item;
use pocketmine\entity\Entity; use pocketmine\entity\Entity;
use pocketmine\entity\Human; use pocketmine\entity\Human;
use pocketmine\entity\Projectile; use pocketmine\entity\Projectile;
@ -85,7 +85,7 @@ class EntityDespawnEvent extends EntityEvent{
* @return bool * @return bool
*/ */
public function isItem(){ public function isItem(){
return $this->entity instanceof DroppedItem; return $this->entity instanceof Item;
} }
} }

View File

@ -22,7 +22,7 @@
namespace pocketmine\event\entity; namespace pocketmine\event\entity;
use pocketmine\entity\Creature; use pocketmine\entity\Creature;
use pocketmine\entity\DroppedItem; use pocketmine\entity\Item;
use pocketmine\entity\Entity; use pocketmine\entity\Entity;
use pocketmine\entity\Human; use pocketmine\entity\Human;
use pocketmine\entity\Projectile; use pocketmine\entity\Projectile;
@ -92,7 +92,7 @@ class EntitySpawnEvent extends EntityEvent{
* @return bool * @return bool
*/ */
public function isItem(){ public function isItem(){
return $this->entity instanceof DroppedItem; return $this->entity instanceof Item;
} }
} }

View File

@ -21,7 +21,7 @@
namespace pocketmine\event\entity; namespace pocketmine\event\entity;
use pocketmine\entity\DroppedItem; use pocketmine\entity\Item;
use pocketmine\event\Cancellable; use pocketmine\event\Cancellable;
class ItemDespawnEvent extends EntityEvent implements Cancellable{ class ItemDespawnEvent extends EntityEvent implements Cancellable{
@ -30,15 +30,15 @@ class ItemDespawnEvent extends EntityEvent implements Cancellable{
public static $nextEvent = 0; public static $nextEvent = 0;
/** /**
* @param DroppedItem $item * @param Item $item
*/ */
public function __construct(DroppedItem $item){ public function __construct(Item $item){
$this->entity = $item; $this->entity = $item;
} }
/** /**
* @return DroppedItem * @return Item
*/ */
public function getEntity(){ public function getEntity(){
return $this->entity; return $this->entity;

View File

@ -21,7 +21,7 @@
namespace pocketmine\event\entity; namespace pocketmine\event\entity;
use pocketmine\entity\DroppedItem; use pocketmine\entity\Item;
class ItemSpawnEvent extends EntityEvent{ class ItemSpawnEvent extends EntityEvent{
public static $handlerList = null; public static $handlerList = null;
@ -29,15 +29,15 @@ class ItemSpawnEvent extends EntityEvent{
public static $nextEvent = 0; public static $nextEvent = 0;
/** /**
* @param DroppedItem $item * @param Item $item
*/ */
public function __construct(DroppedItem $item){ public function __construct(Item $item){
$this->entity = $item; $this->entity = $item;
} }
/** /**
* @return DroppedItem * @return Item
*/ */
public function getEntity(){ public function getEntity(){
return $this->entity; return $this->entity;

View File

@ -66,37 +66,10 @@ class SpawnEgg extends Item{
]), ]),
]); ]);
switch($this->meta){ $entity = Entity::createEntity($this->meta, $chunk, $nbt);
case Villager::NETWORK_ID:
$nbt->Health = new Short("Health", 20);
$entity = new Villager($chunk, $nbt);
break;
case Zombie::NETWORK_ID:
$nbt->Health = new Short("Health", 20);
$entity = new Zombie($chunk, $nbt);
break;
/*
//TODO: use entity constants
case 10:
case 11:
case 12:
case 13:
$data = array(
"x" => $block->x + 0.5,
"y" => $block->y,
"z" => $block->z + 0.5,
);
//$e = Server::getInstance()->api->entity->add($block->level, ENTITY_MOB, $this->meta, $data);
//Server::getInstance()->api->entity->spawnToAll($e);
if(($player->gamemode & 0x01) === 0){
--$this->count;
}
return true;*/
}
if($entity instanceof Entity){ if($entity instanceof Entity){
if(($player->gamemode & 0x01) === 0){ if($player->isSurvival()){
--$this->count; --$this->count;
} }
$entity->spawnToAll(); $entity->spawnToAll();

View File

@ -191,7 +191,7 @@ class Explosion{
if($block instanceof TNT){ if($block instanceof TNT){
$mot = (new Random())->nextSignedFloat() * M_PI * 2; $mot = (new Random())->nextSignedFloat() * M_PI * 2;
$tnt = new PrimedTNT($this->level->getChunk($block->x >> 4, $block->z >> 4), new Compound("", [ $tnt = Entity::createEntity("PrimedTNT", $this->level->getChunk($block->x >> 4, $block->z >> 4), new Compound("", [
"Pos" => new Enum("Pos", [ "Pos" => new Enum("Pos", [
new Double("", $block->x + 0.5), new Double("", $block->x + 0.5),
new Double("", $block->y), new Double("", $block->y),

View File

@ -45,7 +45,7 @@ use pocketmine\block\SnowLayer;
use pocketmine\block\Sugarcane; use pocketmine\block\Sugarcane;
use pocketmine\block\Wheat; use pocketmine\block\Wheat;
use pocketmine\entity\Arrow; use pocketmine\entity\Arrow;
use pocketmine\entity\DroppedItem; use pocketmine\entity\Item as DroppedItem;
use pocketmine\entity\Entity; use pocketmine\entity\Entity;
use pocketmine\event\block\BlockBreakEvent; use pocketmine\event\block\BlockBreakEvent;
use pocketmine\event\block\BlockPlaceEvent; use pocketmine\event\block\BlockPlaceEvent;
@ -1000,7 +1000,7 @@ class Level implements ChunkManager, Metadatable{
public function dropItem(Vector3 $source, Item $item, Vector3 $motion = null, $delay = 10){ public function dropItem(Vector3 $source, Item $item, Vector3 $motion = null, $delay = 10){
$motion = $motion === null ? Vector3::createVector(lcg_value() * 0.2 - 0.1, 0.2, lcg_value() * 0.2 - 0.1) : $motion; $motion = $motion === null ? Vector3::createVector(lcg_value() * 0.2 - 0.1, 0.2, lcg_value() * 0.2 - 0.1) : $motion;
if($item->getID() > 0 and $item->getCount() > 0){ if($item->getID() > 0 and $item->getCount() > 0){
$itemEntity = new DroppedItem($this->getChunk($source->getX() >> 4, $source->getZ() >> 4), new Compound("", [ $itemEntity = Entity::createEntity("Item", $this->getChunk($source->getX() >> 4, $source->getZ() >> 4), new Compound("", [
"Pos" => new Enum("Pos", [ "Pos" => new Enum("Pos", [
new Double("", $source->getX()), new Double("", $source->getX()),
new Double("", $source->getY()), new Double("", $source->getY()),
@ -1233,7 +1233,7 @@ class Level implements ChunkManager, Metadatable{
} }
if($hand->getID() === Item::SIGN_POST or $hand->getID() === Item::WALL_SIGN){ if($hand->getID() === Item::SIGN_POST or $hand->getID() === Item::WALL_SIGN){
$tile = new Sign($this->getChunk($block->x >> 4, $block->z >> 4), new Compound(false, [ $tile = Tile::createTile("Sign", $this->getChunk($block->x >> 4, $block->z >> 4), new Compound(false, [
"id" => new String("id", Tile::SIGN), "id" => new String("id", Tile::SIGN),
"x" => new Int("x", $block->x), "x" => new Int("x", $block->x),
"y" => new Int("y", $block->y), "y" => new Int("y", $block->y),

View File

@ -21,10 +21,7 @@
namespace pocketmine\level\format\generic; namespace pocketmine\level\format\generic;
use pocketmine\entity\Arrow;
use pocketmine\entity\DroppedItem;
use pocketmine\entity\Entity; use pocketmine\entity\Entity;
use pocketmine\entity\FallingBlock;
use pocketmine\level\format\FullChunk; use pocketmine\level\format\FullChunk;
use pocketmine\level\format\LevelProvider; use pocketmine\level\format\LevelProvider;
use pocketmine\nbt\tag\Compound; use pocketmine\nbt\tag\Compound;
@ -116,27 +113,20 @@ abstract class BaseFullChunk implements FullChunk{
foreach($this->NBTentities as $nbt){ foreach($this->NBTentities as $nbt){
if($nbt instanceof Compound){ if($nbt instanceof Compound){
if(!isset($nbt->id)){ if(!isset($nbt->id)){
$this->setChanged();
continue; continue;
} }
if(($nbt["Pos"][0] >> 4) !== $this->x or ($nbt["Pos"][2] >> 4) !== $this->z){ if(($nbt["Pos"][0] >> 4) !== $this->x or ($nbt["Pos"][2] >> 4) !== $this->z){
$this->setChanged();
continue; //Fixes entities allocated in wrong chunks. continue; //Fixes entities allocated in wrong chunks.
} }
//TODO: add all entities if(($entity = Entity::createEntity($nbt["id"], $this, $nbt)) instanceof Entity){
switch($nbt["id"]){ $entity->spawnToAll();
case DroppedItem::NETWORK_ID: }else{
case "Item": $this->setChanged();
(new DroppedItem($this, $nbt))->spawnToAll(); continue;
break;
case Arrow::NETWORK_ID:
case "Arrow":
(new Arrow($this, $nbt))->spawnToAll();
break;
case FallingBlock::NETWORK_ID:
case "FallingSand":
(new FallingBlock($this, $nbt))->spawnToAll();
break;
} }
} }
} }
@ -155,16 +145,9 @@ abstract class BaseFullChunk implements FullChunk{
continue; //Fixes tiles allocated in wrong chunks. continue; //Fixes tiles allocated in wrong chunks.
} }
switch($nbt["id"]){ if(Tile::createTile($nbt["id"], $this, $nbt) === null){
case Tile::CHEST: $this->setChanged();
new Chest($this, $nbt); continue;
break;
case Tile::FURNACE:
new Furnace($this, $nbt);
break;
case Tile::SIGN:
new Sign($this, $nbt);
break;
} }
} }
} }

View File

@ -40,6 +40,9 @@ abstract class Tile extends Position{
public static $tileCount = 1; public static $tileCount = 1;
/** @var Tile[] */
private static $knownTiles = [];
/** @var Chunk */ /** @var Chunk */
public $chunk; public $chunk;
public $name; public $name;
@ -58,6 +61,38 @@ abstract class Tile extends Position{
/** @var \pocketmine\event\TimingsHandler */ /** @var \pocketmine\event\TimingsHandler */
public $tickTimer; public $tickTimer;
/**
* @param string $type
* @param FullChunk $chunk
* @param Compound $nbt
* @param $args
*
* @return Tile
*/
public static function createTile($type, FullChunk $chunk, Compound $nbt, ...$args){
if(isset(self::$knownTiles[$type])){
$class = self::$knownTiles[$type];
return new $class($chunk, $nbt, ...$args);
}
return null;
}
/**
* @param $className
*
* @return bool
*/
public static function registerTile($className){
$class = new \ReflectionClass($className);
if(is_a($className, Tile::class, true) and !$class->isAbstract()){
self::$knownTiles[$class->getShortName()] = $className;
return true;
}
return false;
}
public function __construct(FullChunk $chunk, Compound $nbt){ public function __construct(FullChunk $chunk, Compound $nbt){
if($chunk === null or $chunk->getProvider() === null){ if($chunk === null or $chunk->getProvider() === null){
throw new \Exception("Invalid garbage Chunk given to Tile"); throw new \Exception("Invalid garbage Chunk given to Tile");