Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 7 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,7 @@ The first thing your plugin will have to do to gain access to this virion's API
```php
final class MyPlugin extends PluginBase{

/** @var BlockDataWorldManager */
private $manager;
private BlockDataWorldManager $manager;

protected function onEnable() : void{
$this->manager = BlockDataWorldManager::create($this);
Expand All @@ -47,11 +46,9 @@ class BlockHistoryData extends BlockData{ // stores when block was placed and by
return new BlockHistoryData($nbt->getString("placer"), $nbt->getLong("timestamp"));
}

/** @var string */
private $placer;
private string $placer;

/** @var int */
private $timestamp;
private int $timestamp;

public function __construct(string $placer, ?int $timestamp = null){
$this->placer = $placer;
Expand Down Expand Up @@ -84,17 +81,17 @@ Wew, now all that's remaining is event handling!
```php
public function onBlockPlace(BlockPlaceEvent $event) : void{
$block = $event->getBlock();
$pos = $block->getPos();
$pos = $block->getPosition();
$data = new BlockHistoryData($event->getPlayer()->getName());
$this->manager->getWorld($pos->getWorld())->setBlockDataAt($pos->x, $pos->y, $pos->z, $data);
$this->manager->getWorld($pos->getWorld())->setBlockData($pos, $data);
}

public function onPlayerInteract(PlayerInteractEvent $event) : void{
if($event->getAction() === PlayerInteractEvent::RIGHT_CLICK_BLOCK && $event->getItem()->getId() === ItemIds::STICK){
$block = $event->getBlock();
$pos = $block->getPos();
$pos = $block->getPosition();

$data = $this->manager->get($pos->getWorld())->getBlockDataAt($pos->x, $pos->y, $pos->z);
$data = $this->manager->get($pos->getWorld())->getBlockData($pos);
if($data instanceof BlockHistoryData){
$event->getPlayer()->sendMessage(TextFormat::LIGHT_PURPLE . "This block was placed by " . TextFormat::WHITE . $data->getPlacer() . TextFormat::LIGHT_PURPLE . " on " . TextFormat::WHITE . gmdate("d-m-Y H:i:s", $data->getTimestamp()));
}
Expand Down
19 changes: 14 additions & 5 deletions src/cosmicpe/blockdata/BlockDataFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,26 @@

namespace cosmicpe\blockdata;

use InvalidArgumentException;
use pocketmine\nbt\tag\CompoundTag;
use pocketmine\utils\Utils;

final class BlockDataFactory{

private const TAG_BLOCK_TYPE = "Type";
private const TAG_BLOCK_DATA = "Data";

/** @var BlockData[]|string[] */
private static $types = [];
/** @phpstan-var array<string, class-string<BlockData>> */
private static array $types = [];

/** @var string[] */
private static $class_types = [];
/** @phpstan-var array<class-string<BlockData>, string> */
private static array $class_types = [];

/**
* @phpstan-param class-string<BlockData> $class
*/
public static function register(string $type, string $class) : void{
Utils::testValidInstance($class, BlockData::class);
self::$types[$type] = $class;
self::$class_types[$class] = $type;
}
Expand All @@ -27,8 +33,11 @@ public static function nbtDeserialize(CompoundTag $tag) : ?BlockData{
}

public static function nbtSerialize(BlockData $data) : CompoundTag{
if(!isset(self::$class_types[$class = get_class($data)])){
throw new InvalidArgumentException("BlockData type " . $class . " is not registered");
}
return CompoundTag::create()
->setString(self::TAG_BLOCK_TYPE, self::$class_types[get_class($data)])
->setString(self::TAG_BLOCK_TYPE, self::$class_types[$class])
->setTag(self::TAG_BLOCK_DATA, $data->nbtSerialize());
}
}
17 changes: 7 additions & 10 deletions src/cosmicpe/blockdata/world/BlockDataChunk.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,27 +8,24 @@
use cosmicpe\blockdata\BlockDataFactory;
use LevelDB;
use LevelDBWriteBatch;
use pocketmine\nbt\BaseNbtSerializer;
use pocketmine\nbt\BigEndianNbtSerializer;
use pocketmine\nbt\TreeRoot;
use pocketmine\world\World;
use function array_key_exists;

final class BlockDataChunk{

/** @var LevelDB */
private $database;
private LevelDB $database;

/** @var BigEndianNbtSerializer */
private $serializer;
private BigEndianNbtSerializer $serializer;

/** @var BlockData[]|null[] */
private $block_cache = [];
/** @var array<int, BlockData|null> */
private array $block_cache = [];

/** @var BlockData[]|null[] */
private $update_queue = [];
/** @var array<int, BlockData|null> */
private array $update_queue = [];

public function __construct(LevelDB $database, BaseNbtSerializer $serializer){
public function __construct(LevelDB $database, BigEndianNbtSerializer $serializer){
$this->database = $database;
$this->serializer = $serializer;
}
Expand Down
39 changes: 20 additions & 19 deletions src/cosmicpe/blockdata/world/BlockDataWorld.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,35 +6,28 @@

use cosmicpe\blockdata\BlockData;
use LevelDB;
use pocketmine\math\Vector3;
use pocketmine\nbt\BigEndianNbtSerializer;
use pocketmine\plugin\Plugin;
use pocketmine\world\format\Chunk;
use pocketmine\world\World;
use Symfony\Component\Filesystem\Path;

final class BlockDataWorld{

/** @var BigEndianNbtSerializer */
private $serializer;
private BigEndianNbtSerializer $serializer;

/** @var World */
private $world;
private World $world;

/** @var LevelDB */
private $database;
private LevelDB $database;

/** @var BlockDataChunk[] */
private $chunks = [];
/** @var array<int, BlockDataChunk> */
private array $chunks = [];

public function __construct(Plugin $plugin, World $world){
public function __construct(string $directory, World $world){
$this->serializer = new BigEndianNbtSerializer();
$this->world = $world;

$directory = $plugin->getDataFolder() . "blockdata/";
if(!is_dir($directory)){
/** @noinspection MkdirRaceConditionInspection */
mkdir($directory);
}

$this->database = new LevelDB($directory . $world->getFolderName(), [
$this->database = new LevelDB(Path::join($directory, $world->getFolderName()), [
"compression" => LEVELDB_SNAPPY_COMPRESSION,
"block_size" => 64 * 1024
]);
Expand All @@ -44,12 +37,20 @@ public function getWorld() : World{
return $this->world;
}

public function getBlockData(Vector3 $pos) : ?BlockData{
return $this->getBlockDataAt($pos->getFloorX(), $pos->getFloorY(), $pos->getFloorZ());
}

public function getBlockDataAt(int $x, int $y, int $z) : ?BlockData{
return $this->chunks[World::chunkHash($x >> 4, $z >> 4)]->getBlockDataAt($x, $y, $z);
return $this->chunks[World::chunkHash($x >> Chunk::COORD_BIT_SIZE, $z >> Chunk::COORD_BIT_SIZE)]->getBlockDataAt($x, $y, $z);
}

public function setBlockData(Vector3 $pos, ?BlockData $data) : void{
$this->setBlockDataAt($pos->getFloorX(), $pos->getFloorY(), $pos->getFloorZ(), $data);
}

public function setBlockDataAt(int $x, int $y, int $z, ?BlockData $data) : void{
$this->chunks[World::chunkHash($x >> 4, $z >> 4)]->setBlockDataAt($x, $y, $z, $data);
$this->chunks[World::chunkHash($x >> Chunk::COORD_BIT_SIZE, $z >> Chunk::COORD_BIT_SIZE)]->setBlockDataAt($x, $y, $z, $data);
}

public function loadChunk(int $chunkX, int $chunkZ) : void{
Expand Down
6 changes: 2 additions & 4 deletions src/cosmicpe/blockdata/world/BlockDataWorldListener.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,9 @@

final class BlockDataWorldListener implements Listener{

/** @var Plugin */
private $plugin;
private Plugin $plugin;

/** @var BlockDataWorldManager */
private $manager;
private BlockDataWorldManager $manager;

public function __construct(Plugin $plugin, BlockDataWorldManager $manager){
$this->plugin = $plugin;
Expand Down
21 changes: 9 additions & 12 deletions src/cosmicpe/blockdata/world/BlockDataWorldManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,34 +10,31 @@

final class BlockDataWorldManager{

public static function create(Plugin $plugin) : BlockDataWorldManager{
public static function create(Plugin $plugin, ?string $directory = null) : BlockDataWorldManager{
static $created = [];
if(isset($created[$name = $plugin->getName()])){
throw new BadMethodCallException("Tried to create BlockDataWorldManager twice as " . $name);
}

$created[$name] = true;
$instance = new self($plugin);
$instance = new self($directory ?? $plugin->getDataFolder());
$plugin->getServer()->getPluginManager()->registerEvents(new BlockDataWorldListener($plugin, $instance), $plugin);
return $instance;
}

/** @var Plugin */
private $plugin;
/** @var array<int, BlockDataWorld> */
private array $worlds = [];

/** @var BlockDataWorld[] */
private $worlds = [];

private function __construct(Plugin $plugin){
$this->plugin = $plugin;
}
private function __construct(
private string $directory,
){}

public function isLoaded(World $world) : bool{
return isset($this->worlds[$world->getId()]);
}

public function load(World $world) : void{
$this->worlds[$world->getId()] = new BlockDataWorld($this->plugin, $world);
public function load(World $world) : BlockDataWorld{
return $this->worlds[$world->getId()] ??= new BlockDataWorld($this->directory, $world);
}

public function unload(World $world) : void{
Expand Down
2 changes: 1 addition & 1 deletion virion.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name: BlockData
antigen: cosmicpe\blockdata
api: 5.0.0
version: 0.0.3
version: 0.0.4
author: Muqsit