Skip to content
Draft
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
29 changes: 25 additions & 4 deletions src/NhanAZ/BlockData/BlockData.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,12 @@ final class BlockData{

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

private function __construct(
private string $dataPath,
private bool $autoCleanup
){}

/**
Expand All @@ -51,11 +54,11 @@ public static function create(PluginBase $plugin, bool $autoCleanup = false, ?st
);
}

$instance = new self($dataPath ?? Path::join($plugin->getDataFolder(), "blockdata"));
$instance = new self($dataPath ?? Path::join($plugin->getDataFolder(), "blockdata"), $autoCleanup);
$server = $plugin->getServer();

$server->getPluginManager()->registerEvents(
new BlockDataListener($instance, $plugin, $autoCleanup),
new BlockDataListener($instance, $plugin),
$plugin
);

Expand Down Expand Up @@ -151,13 +154,24 @@ public function removeAt(World $world, int $x, int $y, int $z) : void{
public function loadWorld(World $world) : void{
if(!isset($this->worlds[$world->getId()])){
$this->worlds[$world->getId()] = new BlockDataWorld($this->dataPath, $world);
if($this->autoCleanup){
$listener = ($this->chunk_listeners[$world->getId()] ??= new BlockDataChunkListener($this, $world));
foreach($world->getLoadedChunks() as $hash => $_){
World::getXZ($hash, $x, $z);
$world->registerChunkListener($listener, $x, $z);
}
}
}
}

/** @internal */
public function unloadWorld(World $world) : void{
$id = $world->getId();
if(isset($this->worlds[$id])){
if($this->autoCleanup && isset($this->chunk_listeners[$id])){
$world->unregisterChunkListenerFromAll($this->chunk_listeners[$id]);
unset($this->chunk_listeners[$id]);
}
$this->worlds[$id]->close();
unset($this->worlds[$id]);
}
Expand All @@ -173,15 +187,22 @@ public function saveWorld(World $world) : void{

/** @internal */
public function onChunkLoad(World $world, int $chunkX, int $chunkZ) : void{
if(isset($this->worlds[$world->getId()])){
$this->worlds[$world->getId()]->loadChunk($chunkX, $chunkZ);
$id = $world->getId();
if(isset($this->worlds[$id])){
if($this->autoCleanup && isset($this->chunk_listeners[$id])){
$world->registerChunkListener($this->chunk_listeners[$id], $chunkX, $chunkZ);
}
$this->worlds[$id]->loadChunk($chunkX, $chunkZ);
}
}

/** @internal */
public function onChunkUnload(World $world, int $chunkX, int $chunkZ) : void{
$id = $world->getId();
if(isset($this->worlds[$id])){
if($this->autoCleanup && isset($this->chunk_listeners[$id])){
$world->unregisterChunkListener($this->chunk_listeners[$id], $chunkX, $chunkZ);
}
$this->worlds[$id]->unloadChunk($chunkX, $chunkZ);
}
}
Expand Down
37 changes: 37 additions & 0 deletions src/NhanAZ/BlockData/BlockDataChunkListener.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?php
/*
* Copyright (C) 2020 kostamax27
*/

declare(strict_types=1);

namespace NhanAZ\BlockData;

use pocketmine\math\Vector3;
use pocketmine\world\ChunkListener;
use pocketmine\world\ChunkListenerNoOpTrait;
use pocketmine\world\format\Chunk;
use pocketmine\world\World;

class BlockDataChunkListener implements ChunkListener{
use ChunkListenerNoOpTrait;

public function __construct(
private readonly BlockData $blockData,
private readonly World $world,
){}

public function onChunkChanged(int $chunkX, int $chunkZ, Chunk $chunk) : void{
//TODO: ...
}

public function onBlockChanged(Vector3 $block) : void{
//TODO: strict block modification checking???
$this->blockData->removeAt(
$this->world,
$block->getFloorX(),
$block->getFloorY(),
$block->getFloorZ(),
);
}
}
57 changes: 0 additions & 57 deletions src/NhanAZ/BlockData/BlockDataListener.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,6 @@

namespace NhanAZ\BlockData;

use pocketmine\event\block\BlockBreakEvent;
use pocketmine\event\block\BlockBurnEvent;
use pocketmine\event\block\LeavesDecayEvent;
use pocketmine\event\entity\EntityExplodeEvent;
use pocketmine\event\Listener;
use pocketmine\event\plugin\PluginDisableEvent;
use pocketmine\event\world\ChunkLoadEvent;
Expand All @@ -25,7 +21,6 @@ final class BlockDataListener implements Listener{
public function __construct(
private BlockData $blockData,
private PluginBase $plugin,
private bool $autoCleanup,
){}

// ── World & Chunk Lifecycle ──────────────────────────────────────
Expand Down Expand Up @@ -89,56 +84,4 @@ public function onPluginDisable(PluginDisableEvent $event) : void{
$this->blockData->closeAll();
}
}

// ── Auto Cleanup (only active when $autoCleanup is true) ─────────

/**
* Removes block data when a player breaks the block.
*
* @param BlockBreakEvent $event
* @priority MONITOR
*/
public function onBlockBreak(BlockBreakEvent $event) : void{
if($this->autoCleanup){
$this->blockData->remove($event->getBlock());
}
}

/**
* Removes block data for all blocks destroyed by an explosion.
*
* @param EntityExplodeEvent $event
* @priority MONITOR
*/
public function onEntityExplode(EntityExplodeEvent $event) : void{
if($this->autoCleanup){
foreach($event->getBlockList() as $block){
$this->blockData->remove($block);
}
}
}

/**
* Removes block data when a block is burned by fire.
*
* @param BlockBurnEvent $event
* @priority MONITOR
*/
public function onBlockBurn(BlockBurnEvent $event) : void{
if($this->autoCleanup){
$this->blockData->remove($event->getBlock());
}
}

/**
* Removes block data when leaves decay naturally.
*
* @param LeavesDecayEvent $event
* @priority MONITOR
*/
public function onLeavesDecay(LeavesDecayEvent $event) : void{
if($this->autoCleanup){
$this->blockData->remove($event->getBlock());
}
}
}
11 changes: 7 additions & 4 deletions src/NhanAZ/BlockData/BlockDataWorld.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ final class BlockDataWorld{
private LevelDB $db;

/**
* In-memory cache: blockHash => stored data (or null if confirmed empty).
* Entries are populated on first read and evicted on chunk unload.
* In-memory cache: blockHash => stored data.
* Only non-null values are cached; cache entries are evicted on chunk unload.
* @var array<int, mixed>
*/
private array $cache = [];
Expand Down Expand Up @@ -79,8 +79,11 @@ public function get(int $x, int $y, int $z) : mixed{
$data = null;
}

$this->cache[$hash] = $data;
$this->trackBlock($x, $z, $hash);
// Only cache non-null values to avoid unbounded "dead cache" growth
if($data !== null){
$this->cache[$hash] = $data;
$this->trackBlock($x, $z, $hash);
}

return $data;
}
Expand Down