Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Use Closures for registering blocks #37

Merged
merged 6 commits into from
Sep 28, 2022
Merged
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
2 changes: 1 addition & 1 deletion plugin.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ description: A PocketMine-MP plugin that implements support for custom blocks, i

main: customiesdevs\customies\Customies
src-namespace-prefix: customiesdevs\customies
version: 1.0.7
version: 1.1.0
api: 4.0.0

authors:
Expand Down
65 changes: 31 additions & 34 deletions src/block/CustomiesBlockFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,15 @@

namespace customiesdevs\customies\block;

use Closure;
use customiesdevs\customies\item\CreativeInventoryInfo;
use customiesdevs\customies\item\CustomiesItemFactory;
use customiesdevs\customies\task\AsyncRegisterBlocksTask;
use customiesdevs\customies\world\LegacyBlockIdToStringIdMap;
use InvalidArgumentException;
use OutOfRangeException;
use pocketmine\block\Block;
use pocketmine\block\BlockBreakInfo;
use pocketmine\block\BlockFactory;
use pocketmine\block\BlockIdentifier;
use pocketmine\inventory\CreativeInventory;
use pocketmine\nbt\tag\CompoundTag;
use pocketmine\network\mcpe\convert\GlobalItemTypeDictionary;
Expand All @@ -25,7 +24,6 @@
use pocketmine\network\mcpe\protocol\types\CacheableNbt;
use pocketmine\Server;
use pocketmine\utils\SingletonTrait;
use pocketmine\utils\Utils;
use ReflectionClass;
use RuntimeException;
use SplFixedArray;
Expand All @@ -40,10 +38,10 @@ final class CustomiesBlockFactory {
private const NEW_BLOCK_FACTORY_SIZE = 2048 << Block::INTERNAL_METADATA_BITS;

/**
* @var Block[]
* @phpstan-var array<string, Block>
* @var Closure[]
* @phpstan-var array<string, Closure(int): Block>
*/
private array $customBlocks = [];
private array $blockFuncs = [];
/** @var BlockPaletteEntry[] */
private array $blockPaletteEntries = [];
/** @var R12ToCurrentBlockMapEntry[] */
Expand All @@ -68,10 +66,10 @@ public function increaseBlockFactoryLimits(): void {
$array->setSize(self::NEW_BLOCK_FACTORY_SIZE);
$property->setValue($instance, $array);
}
$instance->light = SplFixedArray::fromArray(array_merge($instance->light->toArray(), array_fill(count($instance->light), self::NEW_BLOCK_FACTORY_SIZE, 0)));
$instance->lightFilter = SplFixedArray::fromArray(array_merge($instance->lightFilter->toArray(), array_fill(count($instance->lightFilter), self::NEW_BLOCK_FACTORY_SIZE, 1)));
$instance->blocksDirectSkyLight = SplFixedArray::fromArray(array_merge($instance->blocksDirectSkyLight->toArray(), array_fill(count($instance->blocksDirectSkyLight), self::NEW_BLOCK_FACTORY_SIZE, false)));
$instance->blastResistance = SplFixedArray::fromArray(array_merge($instance->blastResistance->toArray(), array_fill(count($instance->blastResistance), self::NEW_BLOCK_FACTORY_SIZE, 0.0)));
$instance->light = SplFixedArray::fromArray(array_merge($instance->light->toArray(), array_fill(count($instance->light), self::NEW_BLOCK_FACTORY_SIZE, 0)));
$instance->lightFilter = SplFixedArray::fromArray(array_merge($instance->lightFilter->toArray(), array_fill(count($instance->lightFilter), self::NEW_BLOCK_FACTORY_SIZE, 1)));
$instance->blocksDirectSkyLight = SplFixedArray::fromArray(array_merge($instance->blocksDirectSkyLight->toArray(), array_fill(count($instance->blocksDirectSkyLight), self::NEW_BLOCK_FACTORY_SIZE, false)));
$instance->blastResistance = SplFixedArray::fromArray(array_merge($instance->blastResistance->toArray(), array_fill(count($instance->blastResistance), self::NEW_BLOCK_FACTORY_SIZE, 0.0)));
}

/**
Expand All @@ -80,8 +78,8 @@ public function increaseBlockFactoryLimits(): void {
* can result in massive issues with almost every block showing as the wrong thing and causing lag to clients.
*/
public function addWorkerInitHook(): void {
$blocks = serialize($this->customBlocks);
$server = Server::getInstance();
$blocks = $this->blockFuncs;
$server->getAsyncPool()->addWorkerStartHook(static function (int $worker) use ($server, $blocks): void {
$server->getAsyncPool()->submitTaskToWorker(new AsyncRegisterBlocksTask($blocks), $worker);
});
Expand Down Expand Up @@ -109,16 +107,15 @@ public function getBlockPaletteEntries(): array {

/**
* Register a block to the BlockFactory and all the required mappings.
* @phpstan-param class-string $className
* @phpstan-param (Closure(int): Block) $blockFunc
*/
public function registerBlock(string $className, string $identifier, string $name, BlockBreakInfo $breakInfo, ?Model $model = null, ?CreativeInventoryInfo $creativeInfo = null): void {
if($className !== Block::class) {
Utils::testValidInstance($className, Block::class);
public function registerBlock(Closure $blockFunc, string $identifier, ?Model $model = null, ?CreativeInventoryInfo $creativeInfo = null): void {
$id = $this->getNextAvailableId();
$block = $blockFunc($id);
if(!$block instanceof Block) {
throw new InvalidArgumentException("Class returned from closure is not a Block");
}

/** @var Block $block */
$block = new $className(new BlockIdentifier($this->getNextAvailableId(), 0), $name, $breakInfo);

if(BlockFactory::getInstance()->isRegistered($block->getId())) {
throw new InvalidArgumentException("Block with ID " . $block->getId() . " is already registered");
}
Expand All @@ -131,20 +128,20 @@ public function registerBlock(string $className, string $identifier, string $nam
BlockPalette::getInstance()->insertState($blockState);

$propertiesTag = CompoundTag::create();
$components = CompoundTag::create()
->setTag("minecraft:light_emission", CompoundTag::create()
->setByte("emission", $block->getLightLevel()))
->setTag("minecraft:block_light_filter", CompoundTag::create()
->setByte("lightLevel", $block->getLightFilter()))
->setTag("minecraft:destructible_by_mining", CompoundTag::create()
->setFloat("value", $block->getBreakInfo()->getHardness()))//Says seconds_to_destroy in docs
->setTag("minecraft:destructible_by_explosion", CompoundTag::create()
->setFloat("value", $block->getBreakInfo()->getBlastResistance()))//Uses explosion_resistance in docs
->setTag("minecraft:friction", CompoundTag::create()
->setFloat("value", $block->getFrictionFactor()))
->setTag("minecraft:flammable", CompoundTag::create()
->setInt("catch_chance_modifier", $block->getFlameEncouragement())
->setInt("destroy_chance_modifier", $block->getFlammability()));
$components = CompoundTag::create()
->setTag("minecraft:light_emission", CompoundTag::create()
->setByte("emission", $block->getLightLevel()))
->setTag("minecraft:block_light_filter", CompoundTag::create()
->setByte("lightLevel", $block->getLightFilter()))
->setTag("minecraft:destructible_by_mining", CompoundTag::create()
->setFloat("value", $block->getBreakInfo()->getHardness()))//Says seconds_to_destroy in docs
->setTag("minecraft:destructible_by_explosion", CompoundTag::create()
->setFloat("value", $block->getBreakInfo()->getBlastResistance()))//Uses explosion_resistance in docs
->setTag("minecraft:friction", CompoundTag::create()
->setFloat("value", $block->getFrictionFactor()))
->setTag("minecraft:flammable", CompoundTag::create()
->setInt("catch_chance_modifier", $block->getFlameEncouragement())
->setInt("destroy_chance_modifier", $block->getFlammability()));

if($model !== null) {
foreach($model->toNBT() as $tagName => $tag){
Expand All @@ -164,15 +161,15 @@ public function registerBlock(string $className, string $identifier, string $nam

$this->blockPaletteEntries[] = new BlockPaletteEntry($identifier, new CacheableNbt($propertiesTag));

$this->customBlocks[$identifier] = $block;
$this->blockFuncs[$identifier] = $blockFunc;
LegacyBlockIdToStringIdMap::getInstance()->registerMapping($identifier, $block->getId());
}

/**
* Returns the next available custom block id, an exception will be thrown if the block factory is full.
*/
private function getNextAvailableId(): int {
$id = 1000 + count($this->customBlocks);
$id = 1000 + count($this->blockFuncs);
if($id > (self::NEW_BLOCK_FACTORY_SIZE / 16)) {
throw new OutOfRangeException("All custom block ids are used up");
}
Expand Down
14 changes: 13 additions & 1 deletion src/block/Model.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,19 @@ public function toNBT(): array {
->setTag("materials", $materials),
"minecraft:geometry" => CompoundTag::create()
->setString("value", $this->geometry),
"minecraft:pick_collision" => CompoundTag::create()
"minecraft:collision_box" => CompoundTag::create()
->setByte("enabled", 1)
->setTag("origin", new ListTag([
new FloatTag($this->origin->getX()),
new FloatTag($this->origin->getY()),
new FloatTag($this->origin->getZ())
]))
->setTag("size", new ListTag([
new FloatTag($this->size->getX()),
new FloatTag($this->size->getY()),
new FloatTag($this->size->getZ())
])),
"minecraft:selection_box" => CompoundTag::create()
->setByte("enabled", 1)
->setTag("origin", new ListTag([
new FloatTag($this->origin->getX()),
Expand Down
4 changes: 2 additions & 2 deletions src/entity/CustomiesEntityFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ class CustomiesEntityFactory {
*/
public function registerEntity(string $className, string $identifier, ?Closure $creationFunc = null): void {
EntityFactory::getInstance()->register($className, $creationFunc ?? static function (World $world, CompoundTag $nbt) use ($className): Entity {
return new $className(EntityDataHelper::parseLocation($nbt, $world), $nbt);
}, [$identifier]);
return new $className(EntityDataHelper::parseLocation($nbt, $world), $nbt);
}, [$identifier]);
$this->updateStaticPacketCache($identifier);
}

Expand Down
24 changes: 17 additions & 7 deletions src/task/AsyncRegisterBlocksTask.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,32 @@

namespace customiesdevs\customies\task;

use Closure;
use customiesdevs\customies\block\CustomiesBlockFactory;
use pocketmine\block\Block;
use pocketmine\scheduler\AsyncTask;
use Threaded;

final class AsyncRegisterBlocksTask extends AsyncTask {

public function __construct(private string $blocks) {
private Threaded $blockFuncs;

/**
* @param Closure[] $blockFuncs
* @phpstan-param array<string, Closure(int): Block> $blockFuncs
*/
public function __construct(array $blockFuncs) {
$this->blockFuncs = new Threaded();
foreach($blockFuncs as $identifier => $blockFunc){
$this->blockFuncs[$identifier] = $blockFunc;
}
}

public function onRun(): void {
/** @phpstan-var array<string, Block> $blocks */
$blocks = unserialize($this->blocks);
foreach($blocks as $identifier => $block){
/** @phpstan-var class-string $className */
$className = get_class($block);
CustomiesBlockFactory::getInstance()->registerBlock($className, $identifier, $block->getName(), $block->getBreakInfo());
foreach($this->blockFuncs as $identifier => $blockFunc){
// We do not care about the model or creative inventory data in other threads since it is unused outside of
// the main thread.
CustomiesBlockFactory::getInstance()->registerBlock($blockFunc, $identifier);
}
CustomiesBlockFactory::getInstance()->registerCustomRuntimeMappings();
}
Expand Down