Skip to content
This repository has been archived by the owner on Jun 20, 2024. It is now read-only.

Commit

Permalink
creation of the ds blockcustom and itemcustom api
Browse files Browse the repository at this point in the history
  • Loading branch information
SenseiTarzan committed Dec 4, 2023
1 parent 0113fa9 commit 56879c5
Show file tree
Hide file tree
Showing 21 changed files with 1,454 additions and 0 deletions.
5 changes: 5 additions & 0 deletions src/Server.php
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@
use pocketmine\YmlServerProperties as Yml;
use Ramsey\Uuid\UuidInterface;
use Symfony\Component\Filesystem\Path;
use symply\behavior\AsyncRegisterBlocksTask;
use symply\YmlSymplyProperties;
use function array_fill;
use function array_sum;
Expand Down Expand Up @@ -1055,6 +1056,10 @@ public function __construct(
return;
}

$this->asyncPool->addWorkerStartHook(function(int $worker) : void{
$this->asyncPool->submitTaskToWorker(new AsyncRegisterBlocksTask(), $worker);
});

if($this->configGroup->getPropertyBool(Yml::ANONYMOUS_STATISTICS_ENABLED, true)){
$this->sendUsageTicker = self::TICKS_PER_STATS_REPORT;
$this->sendUsage(SendUsageTask::TYPE_OPEN);
Expand Down
56 changes: 56 additions & 0 deletions symply/behavior/AsyncRegisterBlocksTask.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<?php

/*
*
* _____ _
* / ___| | |
* \ `--. _ _ _ __ ___ _ __ | |_ _
* `--. \ | | | '_ ` _ \| '_ \| | | | |
* /\__/ / |_| | | | | | | |_) | | |_| |
* \____/ \__, |_| |_| |_| .__/|_|\__, |
* __/ | | | __/ |
* |___/ |_| |___/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author Symply Team
* @link http://www.symplymc.com/
*
*
*/

declare(strict_types=1);

namespace symply\behavior;

use pmmp\thread\ThreadSafeArray;
use pocketmine\scheduler\AsyncTask;
use ReflectionException;

class AsyncRegisterBlocksTask extends AsyncTask
{

private ThreadSafeArray $asyncTransmitter;
public function __construct()
{
$this->asyncTransmitter = new ThreadSafeArray();

foreach (SymplyBlockFactory::getInstance()->getAsyncTransmitter() as $closure){
$this->asyncTransmitter[] = $closure;
}
}

/**
* @inheritDoc
* @throws ReflectionException
*/
public function onRun() : void
{
foreach ($this->asyncTransmitter as $closure){
SymplyBlockFactory::getInstanceModeAsync()->register($closure);
}
}
}
165 changes: 165 additions & 0 deletions symply/behavior/SymplyBlockFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
<?php

/*
*
* _____ _
* / ___| | |
* \ `--. _ _ _ __ ___ _ __ | |_ _
* `--. \ | | | '_ ` _ \| '_ \| | | | |
* /\__/ / |_| | | | | | | |_) | | |_| |
* \____/ \__, |_| |_| |_| .__/|_|\__, |
* __/ | | | __/ |
* |___/ |_| |___/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author Symply Team
* @link http://www.symplymc.com/
*
*
*/

declare(strict_types=1);

namespace symply\behavior;

use Closure;
use pocketmine\block\Block;
use pocketmine\block\RuntimeBlockStateRegistry;
use pocketmine\data\bedrock\block\convert\BlockStateReader;
use pocketmine\data\bedrock\block\convert\BlockStateWriter;
use pocketmine\network\mcpe\convert\BlockStateDictionary;
use pocketmine\network\mcpe\convert\BlockTranslator;
use pocketmine\network\mcpe\convert\TypeConverter;
use pocketmine\network\mcpe\protocol\types\BlockPaletteEntry;
use pocketmine\network\mcpe\protocol\types\CacheableNbt;
use pocketmine\utils\SingletonTrait;
use pocketmine\world\format\io\GlobalBlockStateHandlers;
use ReflectionException;
use symply\behavior\block\BlockCustom;
use symply\behavior\block\Permutation;
use function array_values;
use function assert;
use function hash;
use function ksort;

class SymplyBlockFactory
{
use SingletonTrait;

public function __construct(private readonly bool $asyncMode = false)
{
}

/** @var array<string, BlockCustom> */
private array $blocks = [];

/** @var BlockPaletteEntry[] */
private array $blockPaletteEntries = [];

/** @var Closure[] */
private array $asyncTransmitter = [];

/**
* @param Closure(): BlockCustom $blockClosure
* @throws ReflectionException
*/
public function register(Closure $blockClosure) : void
{
$blockCustom = $blockClosure();
$identifier = $blockCustom->getIdInfo()->getNamespaceId();
if (isset($this->blocks[$identifier])){
throw new \InvalidArgumentException("Block ID {$blockCustom->getIdInfo()->getNamespaceId()} is already used by another block");
}
RuntimeBlockStateRegistry::getInstance()->register($blockCustom);
$this->blocks[$identifier] = $blockCustom;
if ($blockCustom instanceof Permutation){
$serializer = static function() use ($blockCustom) : BlockStateWriter{
$writer = BlockStateWriter::create($blockCustom->getIdInfo()->getNamespaceId());
$blockCustom->serializeState($writer);
return $writer;
};
$deserializer = static function(BlockStateReader $reader) use($identifier) : Block{
$block = SymplyBlockFactory::getInstance()->getBlock($reader->readString($identifier));
assert($block instanceof Permutation);
$block->deserializeState($reader);
return $block;
};
}else{
$serializer = static fn() => BlockStateWriter::create($blockCustom->getIdInfo()->getNamespaceId());
$deserializer = static fn() => $blockCustom;
}
GlobalBlockStateHandlers::getSerializer()->map($blockCustom, $serializer);
GlobalBlockStateHandlers::getDeserializer()->map($blockCustom->getIdInfo()->getNamespaceId(), $deserializer);
if (!$this->asyncMode) {
$this->blockPaletteEntries[] = new BlockPaletteEntry($identifier, new CacheableNbt($blockCustom->toPacket()));
$this->asyncTransmitter[] = $blockClosure;
}
$this->initializePalette($blockCustom);
}

/**
* @throws ReflectionException
*/
private function initializePalette(BlockCustom $blockCustom) : void
{
$typeConverter = TypeConverter::getInstance();
$identifier = $blockCustom->getIdInfo()->getNamespaceId();
$tags = array_values($typeConverter->getBlockTranslator()->getBlockStateDictionary()->getStates());

$oldBlockId = $blockCustom->getIdInfo()->getOldBlockId();
foreach ($blockCustom->toBlockStateDictionaryEntry() as $blockStateData){
GlobalBlockStateHandlers::getUpgrader()->getBlockIdMetaUpgrader()->addIdMetaToStateMapping($identifier, $blockStateData->getMeta(), $blockStateData->generateStateData());
GlobalBlockStateHandlers::getUpgrader()->getBlockIdMetaUpgrader()->addIntIdToStringIdMapping($oldBlockId, $identifier);
$tags[] = $blockStateData;
}
foreach ($tags as $state) {
$listStates[hash("fnv164", $state->getStateName(), true)][] = $state;
}
ksort($listStates);
$sortedStates = [];
$n = 0;
foreach ($listStates as $states) {
foreach ($states as $state) {
$sortedStates[$n++] = $state;
}
}
$blockTranslatorProperty = new \ReflectionProperty($typeConverter, "blockTranslator");
$blockTranslatorProperty->setValue($typeConverter, new BlockTranslator(
new BlockStateDictionary($sortedStates),
GlobalBlockStateHandlers::getSerializer()
));
}

/**
* @return Closure[]
*/
public function getAsyncTransmitter() : array
{
return $this->asyncTransmitter;
}

public function getBlocks() : array
{
return $this->blocks;
}

public function getBlock(string $identifier) : ?BlockCustom{
return $this->blocks[$identifier] ?? null;
}

public static function getInstanceModeAsync() : self{
return self::getInstance(true);
}

public static function getInstance(bool $asyncMode = false) : self
{
if (self::$instance === null){
self::$instance = new self($asyncMode);
}
return self::$instance;
}
}
148 changes: 148 additions & 0 deletions symply/behavior/block/BlockCustom.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
<?php

/*
*
* _____ _
* / ___| | |
* \ `--. _ _ _ __ ___ _ __ | |_ _
* `--. \ | | | '_ ` _ \| '_ \| | | | |
* /\__/ / |_| | | | | | | |_) | | |_| |
* \____/ \__, |_| |_| |_| .__/|_|\__, |
* __/ | | | __/ |
* |___/ |_| |___/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author Symply Team
* @link http://www.symplymc.com/
*
*
*/

declare(strict_types=1);

namespace symply\behavior\block;

use Generator;
use pocketmine\block\Block;
use pocketmine\block\BlockTypeInfo;
use pocketmine\math\Vector3;
use pocketmine\nbt\tag\CompoundTag;
use pocketmine\network\mcpe\convert\BlockStateDictionaryEntry;
use symply\behavior\block\component\IComponent;
use symply\behavior\block\component\ModelComponent;
use symply\behavior\block\component\sub\HitBoxSubComponent;
use symply\behavior\block\component\sub\MaterialSubComponent;
use symply\behavior\block\component\TransformationComponent;
use symply\behavior\commun\info\CreativeInfo;
use function assert;

abstract class BlockCustom extends Block
{

/** @var IComponent[] */
private array $components = [];

private CreativeInfo $creativeInfo;

public function __construct(
BlockCustomIdentifier $idInfo,
CreativeInfo $creativeInfo,
string $name,
BlockTypeInfo $typeInfo
)
{
$this->creativeInfo = $creativeInfo;
parent::__construct($idInfo, $name, $typeInfo);
}

public function getIdInfo() : BlockCustomIdentifier
{
$idInfo = parent::getIdInfo();
assert($idInfo instanceof BlockCustomIdentifier);
return $idInfo;
}

public function getCreativeCategory() : CreativeInfo
{
return $this->creativeInfo;
}

public function setCreativeCategory(CreativeInfo $creativeInfo) : self
{
$this->creativeInfo = $creativeInfo;
return $this;
}

public function getComponents() : array
{
return $this->components;
}

public function addComponent(IComponent $component) : self
{
$this->components[] = $component;
return $this;
}

/**
* @param MaterialSubComponent[] $materials
* @return $this
*/
public function setModalComponent(array $materials, ?string $geometry = null, ?HitBoxSubComponent $collisionBox = null, ?HitBoxSubComponent $selectionBox = null) : self
{
return $this->addComponent(new ModelComponent($materials, $geometry, $collisionBox, $selectionBox));
}

public function setTransformationComponent(?Vector3 $rotation = null, ?Vector3 $scale = null, ?Vector3 $translation = null) : self{
return $this->addComponent(new TransformationComponent($rotation ?? Vector3::zero(), $scale ?? Vector3::zero(), $translation ?? Vector3::zero()));
}

public function setComponents(array $components) : self
{
$this->components = $components;
return $this;
}

public function toPacket() : CompoundTag
{
return $this->getPropertiesTag()->setTag('components', $this->getComponentsTag())->setInt("molangVersion", 1);
}

public function getPropertiesTag() : CompoundTag
{
$property = CompoundTag::create();
return $property->merge($this->getCreativeCategory()->toNbt());
}

public function getComponentsTag() : CompoundTag
{
$componentsTags = CompoundTag::create()
->setTag("minecraft:light_emission", CompoundTag::create()
->setByte("emission", $this->getLightLevel()))
->setTag("minecraft:light_dampening", CompoundTag::create()
->setByte("lightLevel", $this->getLightFilter()))
->setTag("minecraft:destructible_by_mining", CompoundTag::create()
->setFloat("value", $this->getBreakInfo()->getHardness()))
->setTag("minecraft:friction", CompoundTag::create()
->setFloat("value", 1 - $this->getFrictionFactor()));
foreach ($this->components as $component) {
$componentsTags->merge($component->toNbt());
}
foreach ($this->getTypeTags() as $tag){
$componentsTags->setTag("tag:$tag", CompoundTag::create());
}
return $componentsTags;
}

/**
* @return Generator<BlockStateDictionaryEntry>
*/
public function toBlockStateDictionaryEntry() : Generator
{
yield new BlockStateDictionaryEntry($this->getIdInfo()->getNamespaceId(), [], 0);
}
}
Loading

0 comments on commit 56879c5

Please sign in to comment.