cosmicpe/blockdata

此包最新版本(0.0.3)没有可用的许可证信息。

0.0.3 2023-09-03 12:32 UTC

This package is auto-updated.

Last update: 2024-09-03 14:52:51 UTC


README

A PocketMine-MP 病毒,允许插件将任意数据设置到方块中。

BlockData 有什么特别之处?

  1. 多个插件可以在不覆盖彼此数据的情况下,将数据存储在同一个方块中。
  2. 除非调用 BlockDataWorld::getBlockDataAt(),否则 BlockData 从不读取数据库。因此,在加载区块时,方块数据不会自动缓存。
  3. yeahh..

为什么不在瓦片上存储数据?

只要可以保持加载瓦片数量的适度,存储在瓦片上的数据就没有问题。当加载区块时,服务器会从数据库中读取所有瓦片并缓存它们。如果你使用瓦片为区块中的每个方块存储数据,那将是 65536 个瓦片实例在 RAM 中!为了避免这种情况,BlockData 只在显式请求时加载方块数据。

有没有缺点?

  1. 由于病毒对缓存的严格策略,对 BlockDataWorld::getBlockDataAt() 的新调用将同步读取数据库。如果你担心这个问题,BlockData 由 LevelDB 支持,并使用 snappy 压缩。调用 LevelDB::get() 几乎只需要一毫秒。病毒创建的 BlockData 实例一旦创建就会缓存,直到区块卸载。
  2. 在删除方块和删除数据之间存在不一致性。这是因为方块可以通过多种不同的方式设置,但直接监听方块变化的方式数量并不相同。方块可以通过 World::setBlockAt()World::setChunk() 或者在使用此病毒的插件被禁用时进行更改,而插件永远不会知道方块已被删除,因此在这种情况下,BlockData 将在方块被删除后长时间存在。
  3. 由于 BlockData 不与区块自动加载(与瓦片不同),因此您不能有效地编写始终在滴答的 BlockData。

开发者文档

使用病毒 3 标准安装

$ composer require cosmicpe/blockdata

您的插件要访问此病毒的 API,首先必须请求一个 BlockDataWorldManager 实例。BlockDataWorldManagerBlockDataWorld 映射到 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