cosmicpe / blockdata
此包最新版本(0.0.3)没有可用的许可证信息。
0.0.3
2023-09-03 12:32 UTC
Requires
- pocketmine/pocketmine-mp: ^5.0.0
This package is auto-updated.
Last update: 2024-09-03 14:52:51 UTC
README
A PocketMine-MP 病毒,允许插件将任意数据设置到方块中。
BlockData 有什么特别之处?
- 多个插件可以在不覆盖彼此数据的情况下,将数据存储在同一个方块中。
- 除非调用
BlockDataWorld::getBlockDataAt()
,否则 BlockData 从不读取数据库。因此,在加载区块时,方块数据不会自动缓存。 - yeahh..
为什么不在瓦片上存储数据?
只要可以保持加载瓦片数量的适度,存储在瓦片上的数据就没有问题。当加载区块时,服务器会从数据库中读取所有瓦片并缓存它们。如果你使用瓦片为区块中的每个方块存储数据,那将是 65536 个瓦片实例在 RAM 中!为了避免这种情况,BlockData 只在显式请求时加载方块数据。
有没有缺点?
- 由于病毒对缓存的严格策略,对
BlockDataWorld::getBlockDataAt()
的新调用将同步读取数据库。如果你担心这个问题,BlockData 由 LevelDB 支持,并使用 snappy 压缩。调用LevelDB::get()
几乎只需要一毫秒。病毒创建的 BlockData 实例一旦创建就会缓存,直到区块卸载。 - 在删除方块和删除数据之间存在不一致性。这是因为方块可以通过多种不同的方式设置,但直接监听方块变化的方式数量并不相同。方块可以通过
World::setBlockAt()
、World::setChunk()
或者在使用此病毒的插件被禁用时进行更改,而插件永远不会知道方块已被删除,因此在这种情况下,BlockData 将在方块被删除后长时间存在。 - 由于 BlockData 不与区块自动加载(与瓦片不同),因此您不能有效地编写始终在滴答的 BlockData。
开发者文档
使用病毒 3 标准安装
$ composer require cosmicpe/blockdata
您的插件要访问此病毒的 API,首先必须请求一个 BlockDataWorldManager
实例。BlockDataWorldManager
将 BlockDataWorld
映射到 pocketmine 的世界中。BlockDataWorld
提供了一个获取和设置 BlockData
的 API。
final class MyPlugin extends PluginBase{ /** @var BlockDataWorldManager */ private $manager; protected function onEnable() : void{ $this->manager = BlockDataWorldManager::create($this); } }
现在让我们创建一个 BlockData 类!BlockData 由 nbt 支持。(说实话,可能会切换到 JSON,但不清楚这是否值得牺牲二进制安全的存储)。
class BlockHistoryData extends BlockData{ // stores when block was placed and by whom. public static function nbtDeserialize(CompoundTag $nbt) : BlockData{ return new BlockHistoryData($nbt->getString("placer"), $nbt->getLong("timestamp")); } /** @var string */ private $placer; /** @var int */ private $timestamp; public function __construct(string $placer, ?int $timestamp = null){ $this->placer = $placer; $this->timestamp = $timestamp ?? time(); } public function getPlacer() : string{ return $this->placer; } public function getTimestamp() : int{ return $this->timestamp; } public function nbtSerialize() : CompoundTag{ return CompoundTag::create() ->setString("placer", $this->placer) ->setLong("timestamp", $this->timestamp); } }
并将其映射到一个字符串标识符。
const BLOCK_HISTORY_DATA = "blockhistory"; BlockDataFactory::register(self::BLOCK_HISTORY_DATA, BlockHistoryData::class);
好了,现在剩下的就是事件处理了!
public function onBlockPlace(BlockPlaceEvent $event) : void{ $block = $event->getBlock(); $pos = $block->getPos(); $data = new BlockHistoryData($event->getPlayer()->getName()); $this->manager->getWorld($pos->getWorld())->setBlockDataAt($pos->x, $pos->y, $pos->z, $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(); $data = $this->manager->get($pos->getWorld())->getBlockDataAt($pos->x, $pos->y, $pos->z); 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())); } } }
还可以查看 BlockData-Example-Plugin。