Added static create() functions for many packets

There are a few motivations here:
1) Less boilerplate code (this can be written inline)
2) It's possible to provide multiple constructors for different packet variations to reduce the chance of errors.
3) It makes things catch fire on updates in ways that static analysers can understand.
This commit is contained in:
Dylan K. Taylor 2019-06-05 15:00:08 +01:00
parent 09afb8e772
commit 287c8c2dd4
51 changed files with 481 additions and 247 deletions

View File

@ -874,11 +874,7 @@ abstract class Entity extends Location implements Metadatable, EntityIds{
}
protected function broadcastMotion() : void{
$pk = new SetEntityMotionPacket();
$pk->entityRuntimeId = $this->id;
$pk->motion = $this->getMotion();
$this->world->broadcastPacketToViewers($this, $pk);
$this->world->broadcastPacketToViewers($this, SetEntityMotionPacket::create($this->id, $this->getMotion()));
}
public function hasGravity() : bool{
@ -1649,9 +1645,7 @@ abstract class Entity extends Location implements Metadatable, EntityIds{
$id = spl_object_id($player);
if(isset($this->hasSpawned[$id])){
if($send){
$pk = new RemoveEntityPacket();
$pk->entityUniqueId = $this->id;
$player->sendDataPacket($pk);
$player->sendDataPacket(RemoveEntityPacket::create($this->id));
}
unset($this->hasSpawned[$id]);
}
@ -1778,9 +1772,7 @@ abstract class Entity extends Location implements Metadatable, EntityIds{
$player = [$player];
}
$pk = new SetEntityDataPacket();
$pk->entityRuntimeId = $this->getId();
$pk->metadata = $data ?? $this->propertyManager->getAll();
$pk = SetEntityDataPacket::create($this->getId(), $data ?? $this->propertyManager->getAll());
foreach($player as $p){
if($p === $this){
@ -1795,19 +1787,11 @@ abstract class Entity extends Location implements Metadatable, EntityIds{
}
public function broadcastEntityEvent(int $eventId, ?int $eventData = null, ?array $players = null) : void{
$pk = new EntityEventPacket();
$pk->entityRuntimeId = $this->id;
$pk->event = $eventId;
$pk->data = $eventData ?? 0;
$this->server->broadcastPacket($players ?? $this->getViewers(), $pk);
$this->server->broadcastPacket($players ?? $this->getViewers(), EntityEventPacket::create($this->id, $eventId, $eventData ?? 0));
}
public function broadcastAnimation(?array $players, int $animationId) : void{
$pk = new AnimatePacket();
$pk->entityRuntimeId = $this->id;
$pk->action = $animationId;
$this->server->broadcastPacket($players ?? $this->getViewers(), $pk);
$this->server->broadcastPacket($players ?? $this->getViewers(), AnimatePacket::create($this->id, $animationId));
}
public function __destruct(){

View File

@ -829,10 +829,7 @@ class Human extends Creature implements ProjectileSource, InventoryHolder{
protected function sendSpawnPacket(Player $player) : void{
if(!($this instanceof Player)){
/* we don't use Server->updatePlayerListData() because that uses batches, which could cause race conditions in async compression mode */
$pk = new PlayerListPacket();
$pk->type = PlayerListPacket::TYPE_ADD;
$pk->entries = [PlayerListEntry::createAdditionEntry($this->uuid, $this->id, $this->getName(), $this->skin)];
$player->sendDataPacket($pk);
$player->sendDataPacket(PlayerListPacket::add([PlayerListEntry::createAdditionEntry($this->uuid, $this->id, $this->getName(), $this->skin)]));
}
$pk = new AddPlayerPacket();
@ -853,10 +850,7 @@ class Human extends Creature implements ProjectileSource, InventoryHolder{
$player->getNetworkSession()->onMobArmorChange($this);
if(!($this instanceof Player)){
$pk = new PlayerListPacket();
$pk->type = PlayerListPacket::TYPE_REMOVE;
$pk->entries = [PlayerListEntry::createRemovalEntry($this->uuid)];
$player->sendDataPacket($pk);
$player->sendDataPacket(PlayerListPacket::remove([PlayerListEntry::createRemovalEntry($this->uuid)]));
}
}

View File

@ -268,10 +268,7 @@ class ItemEntity extends Entity{
$player->awardAchievement("diamond");
}
$pk = new TakeItemEntityPacket();
$pk->eid = $player->getId();
$pk->target = $this->getId();
$this->server->broadcastPacket($this->getViewers(), $pk);
$this->server->broadcastPacket($this->getViewers(), TakeItemEntityPacket::create($player->getId(), $this->getId()));
$playerInventory->addItem(clone $item);
$this->flagForDespawn();

View File

@ -194,10 +194,7 @@ class Arrow extends Projectile{
return;
}
$pk = new TakeItemEntityPacket();
$pk->eid = $player->getId();
$pk->target = $this->getId();
$this->server->broadcastPacket($this->getViewers(), $pk);
$this->server->broadcastPacket($this->getViewers(), TakeItemEntityPacket::create($player->getId(), $this->getId()));
$playerInventory->addItem(clone $item);
$this->flagForDespawn();

View File

@ -40,31 +40,20 @@ abstract class ContainerInventory extends BaseInventory{
protected function onOpen(Player $who) : void{
parent::onOpen($who);
$pk = new ContainerOpenPacket();
$pk->windowId = $who->getWindowId($this);
$pk->type = $this->getNetworkType();
$windowId = $who->getWindowId($this);
$holder = $this->getHolder();
$pk->x = $pk->y = $pk->z = 0;
$pk->entityUniqueId = -1;
if($holder instanceof Entity){
$pk->entityUniqueId = $holder->getId();
$who->sendDataPacket(ContainerOpenPacket::entityInv($windowId, $this->getNetworkType(), $holder->getId()));
}elseif($holder instanceof Vector3){
$pk->x = $holder->getFloorX();
$pk->y = $holder->getFloorY();
$pk->z = $holder->getFloorZ();
$who->sendDataPacket(ContainerOpenPacket::blockInv($windowId, $this->getNetworkType(), $holder->getFloorX(), $holder->getFloorY(), $holder->getFloorZ()));
}
$who->sendDataPacket($pk);
$this->sendContents($who);
}
protected function onClose(Player $who) : void{
$pk = new ContainerClosePacket();
$pk->windowId = $who->getWindowId($this);
$who->sendDataPacket($pk);
$who->sendDataPacket(ContainerClosePacket::create($who->getWindowId($this)));
parent::onClose($who);
}

View File

@ -133,11 +133,7 @@ class PlayerInventory extends BaseInventory{
public function sendHeldItem($target) : void{
$item = $this->getItemInHand();
$pk = new MobEquipmentPacket();
$pk->entityRuntimeId = $this->getHolder()->getId();
$pk->item = $item;
$pk->inventorySlot = $pk->hotbarSlot = $this->getHeldItemIndex();
$pk->windowId = ContainerIds::INVENTORY;
$pk = MobEquipmentPacket::create($this->getHolder()->getId(), $item, $this->getHeldItemIndex(), ContainerIds::INVENTORY);
if(!is_array($target)){
$target->sendDataPacket($pk);
@ -166,16 +162,15 @@ class PlayerInventory extends BaseInventory{
if(!($holder instanceof Player)){
throw new \LogicException("Cannot send creative inventory contents to non-player inventory holder");
}
$pk = new InventoryContentPacket();
$pk->windowId = ContainerIds::CREATIVE;
$items = [];
if(!$holder->isSpectator()){ //fill it for all gamemodes except spectator
foreach(Item::getCreativeItems() as $i => $item){
$pk->items[$i] = clone $item;
$items[$i] = clone $item;
}
}
$holder->sendDataPacket($pk);
$holder->sendDataPacket(InventoryContentPacket::create(ContainerIds::CREATIVE, $items));
}
/**

View File

@ -152,9 +152,7 @@ class CraftingTransaction extends InventoryTransaction{
* So people don't whine about messy desync issues when someone cancels CraftItemEvent, or when a crafting
* transaction goes wrong.
*/
$pk = new ContainerClosePacket();
$pk->windowId = ContainerIds::NONE;
$this->source->sendDataPacket($pk);
$this->source->sendDataPacket(ContainerClosePacket::create(ContainerIds::NONE));
}
public function execute() : bool{

View File

@ -23,9 +23,9 @@ declare(strict_types=1);
namespace pocketmine\network\mcpe;
use pocketmine\world\format\Chunk;
use pocketmine\network\mcpe\protocol\FullChunkDataPacket;
use pocketmine\scheduler\AsyncTask;
use pocketmine\world\format\Chunk;
class ChunkRequestTask extends AsyncTask{
private const TLS_KEY_PROMISE = "promise";
@ -52,12 +52,7 @@ class ChunkRequestTask extends AsyncTask{
}
public function onRun() : void{
$pk = new FullChunkDataPacket();
$pk->chunkX = $this->chunkX;
$pk->chunkZ = $this->chunkZ;
$pk->data = $this->chunk;
$this->setResult(NetworkCompression::compress(PacketBatch::fromPackets($pk)->getBuffer(), $this->compressionLevel));
$this->setResult(NetworkCompression::compress(PacketBatch::fromPackets(FullChunkDataPacket::create($this->chunkX, $this->chunkZ, $this->chunk))->getBuffer(), $this->compressionLevel));
}
public function onError() : void{

View File

@ -79,6 +79,7 @@ use pocketmine\timings\Timings;
use pocketmine\utils\BinaryDataException;
use pocketmine\utils\Utils;
use pocketmine\world\Position;
use function array_map;
use function bin2hex;
use function count;
use function get_class;
@ -460,10 +461,7 @@ class NetworkSession{
*/
public function transfer(string $ip, int $port, string $reason = "transfer") : void{
$this->tryDisconnect(function() use($ip, $port, $reason){
$pk = new TransferPacket();
$pk->address = $ip;
$pk->port = $port;
$this->sendDataPacket($pk, true);
$this->sendDataPacket(TransferPacket::create($ip, $port), true);
$this->disconnect($reason, false);
if($this->player !== null){
$this->player->disconnect($reason, null, false);
@ -492,10 +490,7 @@ class NetworkSession{
*/
private function doServerDisconnect(string $reason, bool $notify = true) : void{
if($notify){
$pk = new DisconnectPacket();
$pk->message = $reason;
$pk->hideDisconnectionScreen = $reason === "";
$this->sendDataPacket($pk, true);
$this->sendDataPacket($reason === "" ? DisconnectPacket::silent() : DisconnectPacket::message($reason), true);
}
$this->interface->close($this, $notify ? $reason : "");
@ -544,9 +539,7 @@ class NetworkSession{
}
public function enableEncryption(string $encryptionKey, string $handshakeJwt) : void{
$pk = new ServerToClientHandshakePacket();
$pk->jwt = $handshakeJwt;
$this->sendDataPacket($pk, true); //make sure this gets sent before encryption is enabled
$this->sendDataPacket(ServerToClientHandshakePacket::create($handshakeJwt), true); //make sure this gets sent before encryption is enabled
$this->cipher = new NetworkCipher($encryptionKey);
@ -557,9 +550,7 @@ class NetworkSession{
public function onLoginSuccess() : void{
$this->loggedIn = true;
$pk = new PlayStatusPacket();
$pk->status = PlayStatusPacket::LOGIN_SUCCESS;
$this->sendDataPacket($pk);
$this->sendDataPacket(PlayStatusPacket::create(PlayStatusPacket::LOGIN_SUCCESS));
$this->setHandler(new ResourcePacksSessionHandler($this, $this->server->getResourcePackManager()));
}
@ -571,9 +562,7 @@ class NetworkSession{
}
public function onTerrainReady() : void{
$pk = new PlayStatusPacket();
$pk->status = PlayStatusPacket::PLAYER_SPAWN;
$this->sendDataPacket($pk);
$this->sendDataPacket(PlayStatusPacket::create(PlayStatusPacket::PLAYER_SPAWN));
}
public function onSpawn() : void{
@ -604,34 +593,19 @@ class NetworkSession{
}
public function syncViewAreaRadius(int $distance) : void{
$pk = new ChunkRadiusUpdatedPacket();
$pk->radius = $distance;
$this->sendDataPacket($pk);
$this->sendDataPacket(ChunkRadiusUpdatedPacket::create($distance));
}
public function syncViewAreaCenterPoint(Vector3 $newPos, int $viewDistance) : void{
$pk = new NetworkChunkPublisherUpdatePacket();
$pk->x = $newPos->getFloorX();
$pk->y = $newPos->getFloorY();
$pk->z = $newPos->getFloorZ();
$pk->radius = $viewDistance * 16; //blocks, not chunks >.>
$this->sendDataPacket($pk);
$this->sendDataPacket(NetworkChunkPublisherUpdatePacket::create($newPos->getFloorX(), $newPos->getFloorY(), $newPos->getFloorZ(), $viewDistance * 16)); //blocks, not chunks >.>
}
public function syncPlayerSpawnPoint(Position $newSpawn) : void{
$pk = new SetSpawnPositionPacket();
$pk->x = $newSpawn->getFloorX();
$pk->y = $newSpawn->getFloorY();
$pk->z = $newSpawn->getFloorZ();
$pk->spawnType = SetSpawnPositionPacket::TYPE_PLAYER_SPAWN;
$pk->spawnForced = false;
$this->sendDataPacket($pk);
$this->sendDataPacket(SetSpawnPositionPacket::playerSpawn($newSpawn->getFloorX(), $newSpawn->getFloorY(), $newSpawn->getFloorZ(), false)); //TODO: spawn forced
}
public function syncGameMode(GameMode $mode) : void{
$pk = new SetPlayerGameTypePacket();
$pk->gamemode = self::getClientFriendlyGamemode($mode);
$this->sendDataPacket($pk);
$this->sendDataPacket(SetPlayerGameTypePacket::create(self::getClientFriendlyGamemode($mode)));
}
/**
@ -661,10 +635,7 @@ class NetworkSession{
public function syncAttributes(Living $entity, bool $sendAll = false){
$entries = $sendAll ? $entity->getAttributeMap()->getAll() : $entity->getAttributeMap()->needSend();
if(count($entries) > 0){
$pk = new UpdateAttributesPacket();
$pk->entityRuntimeId = $entity->getId();
$pk->entries = $entries;
$this->sendDataPacket($pk);
$this->sendDataPacket(UpdateAttributesPacket::create($entity->getId(), $entries));
foreach($entries as $entry){
$entry->markSynchronized();
}
@ -672,24 +643,11 @@ class NetworkSession{
}
public function onEntityEffectAdded(Living $entity, EffectInstance $effect, bool $replacesOldEffect) : void{
$pk = new MobEffectPacket();
$pk->entityRuntimeId = $entity->getId();
$pk->eventId = $replacesOldEffect ? MobEffectPacket::EVENT_MODIFY : MobEffectPacket::EVENT_ADD;
$pk->effectId = $effect->getId();
$pk->amplifier = $effect->getAmplifier();
$pk->particles = $effect->isVisible();
$pk->duration = $effect->getDuration();
$this->sendDataPacket($pk);
$this->sendDataPacket(MobEffectPacket::add($entity->getId(), $replacesOldEffect, $effect->getId(), $effect->getAmplifier(), $effect->isVisible(), $effect->getDuration()));
}
public function onEntityEffectRemoved(Living $entity, EffectInstance $effect) : void{
$pk = new MobEffectPacket();
$pk->entityRuntimeId = $entity->getId();
$pk->eventId = MobEffectPacket::EVENT_REMOVE;
$pk->effectId = $effect->getId();
$this->sendDataPacket($pk);
$this->sendDataPacket(MobEffectPacket::remove($entity->getId(), $effect->getId()));
}
public function syncAvailableCommands() : void{
@ -730,43 +688,27 @@ class NetworkSession{
}
public function onRawChatMessage(string $message) : void{
$pk = new TextPacket();
$pk->type = TextPacket::TYPE_RAW;
$pk->message = $message;
$this->sendDataPacket($pk);
$this->sendDataPacket(TextPacket::raw($message));
}
public function onTranslatedChatMessage(string $key, array $parameters) : void{
$pk = new TextPacket();
$pk->type = TextPacket::TYPE_TRANSLATION;
$pk->needsTranslation = true;
$pk->message = $key;
$pk->parameters = $parameters;
$this->sendDataPacket($pk);
$this->sendDataPacket(TextPacket::translation($key, $parameters));
}
public function onPopup(string $message) : void{
$pk = new TextPacket();
$pk->type = TextPacket::TYPE_POPUP;
$pk->message = $message;
$this->sendDataPacket($pk);
$this->sendDataPacket(TextPacket::popup($message));
}
public function onTip(string $message) : void{
$pk = new TextPacket();
$pk->type = TextPacket::TYPE_TIP;
$pk->message = $message;
$this->sendDataPacket($pk);
$this->sendDataPacket(TextPacket::tip($message));
}
public function onFormSent(int $id, Form $form) : bool{
$pk = new ModalFormRequestPacket();
$pk->formId = $id;
$pk->formData = json_encode($form);
if($pk->formData === false){
$formData = json_encode($form);
if($formData === false){
throw new \InvalidArgumentException("Failed to encode form JSON: " . json_last_error_msg());
}
return $this->sendDataPacket($pk);
return $this->sendDataPacket(ModalFormRequestPacket::create($id, $formData));
}
/**
@ -803,21 +745,14 @@ class NetworkSession{
public function syncInventorySlot(Inventory $inventory, int $slot) : void{
$windowId = $this->player->getWindowId($inventory);
if($windowId !== ContainerIds::NONE){
$pk = new InventorySlotPacket();
$pk->inventorySlot = $slot;
$pk->item = $inventory->getItem($slot);
$pk->windowId = $windowId;
$this->sendDataPacket($pk);
$this->sendDataPacket(InventorySlotPacket::create($windowId, $slot, $inventory->getItem($slot)));
}
}
public function syncInventoryContents(Inventory $inventory) : void{
$windowId = $this->player->getWindowId($inventory);
if($windowId !== ContainerIds::NONE){
$pk = new InventoryContentPacket();
$pk->items = $inventory->getContents(true);
$pk->windowId = $windowId;
$this->sendDataPacket($pk);
$this->sendDataPacket(InventoryContentPacket::create($windowId, $inventory->getContents(true)));
}
}
@ -830,48 +765,28 @@ class NetworkSession{
public function syncInventoryData(Inventory $inventory, int $propertyId, int $value) : void{
$windowId = $this->player->getWindowId($inventory);
if($windowId !== ContainerIds::NONE){
$pk = new ContainerSetDataPacket();
$pk->property = $propertyId;
$pk->value = $value;
$pk->windowId = $windowId;
$this->sendDataPacket($pk);
$this->sendDataPacket(ContainerSetDataPacket::create($windowId, $propertyId, $value));
}
}
public function onMobArmorChange(Living $mob) : void{
$pk = new MobArmorEquipmentPacket();
$pk->entityRuntimeId = $mob->getId();
$inv = $mob->getArmorInventory();
$pk->head = $inv->getHelmet();
$pk->chest = $inv->getChestplate();
$pk->legs = $inv->getLeggings();
$pk->feet = $inv->getBoots();
$this->sendDataPacket($pk);
$this->sendDataPacket(MobArmorEquipmentPacket::create($mob->getId(), $inv->getHelmet(), $inv->getChestplate(), $inv->getLeggings(), $inv->getBoots()));
}
public function syncPlayerList() : void{
$pk = new PlayerListPacket();
$pk->type = PlayerListPacket::TYPE_ADD;
foreach($this->server->getOnlinePlayers() as $player){
$pk->entries[] = PlayerListEntry::createAdditionEntry($player->getUniqueId(), $player->getId(), $player->getDisplayName(), $player->getSkin(), $player->getXuid());
}
$this->sendDataPacket($pk);
$this->sendDataPacket(PlayerListPacket::add(array_map(function(Player $player){
return PlayerListEntry::createAdditionEntry($player->getUniqueId(), $player->getId(), $player->getDisplayName(), $player->getSkin(), $player->getXuid());
}, $this->server->getOnlinePlayers())));
}
public function onPlayerAdded(Player $p) : void{
$pk = new PlayerListPacket();
$pk->type = PlayerListPacket::TYPE_ADD;
$pk->entries[] = PlayerListEntry::createAdditionEntry($p->getUniqueId(), $p->getId(), $p->getName(), $p->getSkin(), $p->getXuid());
$this->sendDataPacket($pk);
$this->sendDataPacket(PlayerListPacket::add([PlayerListEntry::createAdditionEntry($p->getUniqueId(), $p->getId(), $p->getName(), $p->getSkin(), $p->getXuid())]));
}
public function onPlayerRemoved(Player $p) : void{
if($p !== $this->player){
$pk = new PlayerListPacket();
$pk->type = PlayerListPacket::TYPE_REMOVE;
$pk->entries[] = PlayerListEntry::createRemovalEntry($p->getUniqueId());
$this->sendDataPacket($pk);
$this->sendDataPacket(PlayerListPacket::remove([PlayerListEntry::createRemovalEntry($p->getUniqueId())]));
}
}

View File

@ -41,9 +41,7 @@ class DeathSessionHandler extends SessionHandler{
}
public function setUp() : void{
$pk = new RespawnPacket();
$pk->position = $this->player->getOffsetPosition($this->player->getSpawn());
$this->session->sendDataPacket($pk);
$this->session->sendDataPacket(RespawnPacket::create($this->player->getOffsetPosition($this->player->getSpawn())));
}
public function handlePlayerAction(PlayerActionPacket $packet) : bool{

View File

@ -55,10 +55,7 @@ class LoginSessionHandler extends SessionHandler{
public function handleLogin(LoginPacket $packet) : bool{
if(!$this->isCompatibleProtocol($packet->protocol)){
$pk = new PlayStatusPacket();
$pk->status = $packet->protocol < ProtocolInfo::CURRENT_PROTOCOL ?
PlayStatusPacket::LOGIN_FAILED_CLIENT : PlayStatusPacket::LOGIN_FAILED_SERVER;
$this->session->sendDataPacket($pk, true);
$this->session->sendDataPacket(PlayStatusPacket::create($packet->protocol < ProtocolInfo::CURRENT_PROTOCOL ? PlayStatusPacket::LOGIN_FAILED_CLIENT : PlayStatusPacket::LOGIN_FAILED_SERVER), true);
//This pocketmine disconnect message will only be seen by the console (PlayStatusPacket causes the messages to be shown for the client)
$this->session->disconnect(

View File

@ -59,10 +59,7 @@ class ResourcePacksSessionHandler extends SessionHandler{
}
public function setUp() : void{
$pk = new ResourcePacksInfoPacket();
$pk->resourcePackEntries = $this->resourcePackManager->getResourceStack();
$pk->mustAccept = $this->resourcePackManager->resourcePacksRequired();
$this->session->sendDataPacket($pk);
$this->session->sendDataPacket(ResourcePacksInfoPacket::create($this->resourcePackManager->getResourceStack(), [], $this->resourcePackManager->resourcePacksRequired(), false));
}
private function disconnectWithError(string $error) : void{
@ -91,21 +88,18 @@ class ResourcePacksSessionHandler extends SessionHandler{
return false;
}
$pk = new ResourcePackDataInfoPacket();
$pk->packId = $pack->getPackId();
$pk->maxChunkSize = self::PACK_CHUNK_SIZE; //1MB
$pk->chunkCount = (int) ceil($pack->getPackSize() / self::PACK_CHUNK_SIZE);
$pk->compressedPackSize = $pack->getPackSize();
$pk->sha256 = $pack->getSha256();
$this->session->sendDataPacket($pk);
$this->session->sendDataPacket(ResourcePackDataInfoPacket::create(
$pack->getPackId(),
self::PACK_CHUNK_SIZE,
(int) ceil($pack->getPackSize() / self::PACK_CHUNK_SIZE),
$pack->getPackSize(),
$pack->getSha256()
));
}
break;
case ResourcePackClientResponsePacket::STATUS_HAVE_ALL_PACKS:
$pk = new ResourcePackStackPacket();
$pk->resourcePackStack = $this->resourcePackManager->getResourceStack();
$pk->mustAccept = $this->resourcePackManager->resourcePacksRequired();
$this->session->sendDataPacket($pk);
$this->session->sendDataPacket(ResourcePackStackPacket::create($this->resourcePackManager->getResourceStack(), [], $this->resourcePackManager->resourcePacksRequired(), false));
break;
case ResourcePackClientResponsePacket::STATUS_COMPLETED:
$this->session->onResourcePacksDone();
@ -143,12 +137,7 @@ class ResourcePacksSessionHandler extends SessionHandler{
$this->downloadedChunks[$packId][$packet->chunkIndex] = true;
}
$pk = new ResourcePackChunkDataPacket();
$pk->packId = $packId;
$pk->chunkIndex = $packet->chunkIndex;
$pk->data = $pack->getPackChunk($offset, self::PACK_CHUNK_SIZE);
$pk->progress = $offset;
$this->session->sendDataPacket($pk);
$this->session->sendDataPacket(ResourcePackChunkDataPacket::create($packId, $packet->chunkIndex, $offset, $pack->getPackChunk($offset, self::PACK_CHUNK_SIZE)));
return true;
}

View File

@ -43,6 +43,19 @@ class AnimatePacket extends DataPacket implements ClientboundPacket, Serverbound
/** @var float */
public $float = 0.0; //TODO (Boat rowing time?)
public static function create(int $entityRuntimeId, int $actionId) : self{
$result = new self;
$result->entityRuntimeId = $entityRuntimeId;
$result->action = $actionId;
return $result;
}
public static function boatHack(int $entityRuntimeId, int $actionId, float $data) : self{
$result = self::create($entityRuntimeId, $actionId);
$result->float = $data;
return $result;
}
protected function decodePayload() : void{
$this->action = $this->getVarInt();
$this->entityRuntimeId = $this->getEntityRuntimeId();

View File

@ -40,6 +40,13 @@ class BlockEntityDataPacket extends DataPacket implements ClientboundPacket, Ser
/** @var string */
public $namedtag;
public static function create(int $x, int $y, int $z, string $nbt) : self{
$result = new self;
[$result->x, $result->y, $result->z] = [$x, $y, $z];
$result->namedtag = $nbt;
return $result;
}
protected function decodePayload() : void{
$this->getBlockPosition($this->x, $this->y, $this->z);
$this->namedtag = $this->getRemaining();

View File

@ -34,6 +34,12 @@ class ChunkRadiusUpdatedPacket extends DataPacket implements ClientboundPacket{
/** @var int */
public $radius;
public static function create(int $radius) : self{
$result = new self;
$result->radius = $radius;
return $result;
}
protected function decodePayload() : void{
$this->radius = $this->getVarInt();
}

View File

@ -34,6 +34,12 @@ class ContainerClosePacket extends DataPacket implements ClientboundPacket, Serv
/** @var int */
public $windowId;
public static function create(int $windowId) : self{
$result = new self;
$result->windowId = $windowId;
return $result;
}
protected function decodePayload() : void{
$this->windowId = $this->getByte();
}

View File

@ -44,6 +44,22 @@ class ContainerOpenPacket extends DataPacket implements ClientboundPacket{
/** @var int */
public $entityUniqueId = -1;
public static function blockInv(int $windowId, int $windowType, int $x, int $y, int $z) : self{
$result = new self;
$result->windowId = $windowId;
$result->type = $windowType;
[$result->x, $result->y, $result->z] = [$x, $y, $z];
return $result;
}
public static function entityInv(int $windowId, int $windowType, int $entityUniqueId) : self{
$result = new self;
$result->windowId = $windowId;
$result->type = $windowType;
$result->entityUniqueId = $entityUniqueId;
return $result;
}
protected function decodePayload() : void{
$this->windowId = $this->getByte();
$this->type = $this->getByte();

View File

@ -48,6 +48,14 @@ class ContainerSetDataPacket extends DataPacket implements ClientboundPacket{
/** @var int */
public $value;
public static function create(int $windowId, int $propertyId, int $value) : self{
$result = new self;
$result->property = $propertyId;
$result->value = $value;
$result->windowId = $windowId;
return $result;
}
protected function decodePayload() : void{
$this->windowId = $this->getByte();
$this->property = $this->getVarInt();

View File

@ -36,6 +36,19 @@ class DisconnectPacket extends DataPacket implements ClientboundPacket, Serverbo
/** @var string */
public $message = "";
public static function silent() : self{
$result = new self;
$result->hideDisconnectionScreen = true;
return $result;
}
public static function message(string $message) : self{
$result = new self;
$result->hideDisconnectionScreen = false;
$result->message = $message;
return $result;
}
public function canBeSentBeforeLogin() : bool{
return true;
}

View File

@ -90,6 +90,14 @@ class EntityEventPacket extends DataPacket implements ClientboundPacket, Serverb
/** @var int */
public $data = 0;
public static function create(int $entityRuntimeId, int $eventId, int $eventData) : self{
$result = new self;
$result->entityRuntimeId = $entityRuntimeId;
$result->event = $eventId;
$result->data = $eventData;
return $result;
}
protected function decodePayload() : void{
$this->entityRuntimeId = $this->getEntityRuntimeId();
$this->event = $this->getByte();

View File

@ -40,6 +40,22 @@ class ExplodePacket extends DataPacket implements ClientboundPacket{
/** @var Vector3[] */
public $records = [];
/**
* @param Vector3 $center
* @param float $radius
* @param Vector3[] $records
*
* @return ExplodePacket
*/
public static function create(Vector3 $center, float $radius, array $records) : self{
(function(Vector3 ...$_){})($records);
$result = new self;
$result->position = $center;
$result->radius = $radius;
$result->records = $records;
return $result;
}
protected function decodePayload() : void{
$this->position = $this->getVector3();
$this->radius = (float) ($this->getVarInt() / 32);

View File

@ -38,6 +38,14 @@ class FullChunkDataPacket extends DataPacket implements ClientboundPacket{
/** @var string */
public $data;
public static function create(int $chunkX, int $chunkZ, string $payload) : self{
$result = new self;
$result->chunkX = $chunkX;
$result->chunkZ = $chunkZ;
$result->data = $payload;
return $result;
}
protected function decodePayload() : void{
$this->chunkX = $this->getVarInt();
$this->chunkZ = $this->getVarInt();

View File

@ -37,6 +37,20 @@ class InventoryContentPacket extends DataPacket implements ClientboundPacket{
/** @var Item[] */
public $items = [];
/**
* @param int $windowId
* @param Item[] $items
*
* @return InventoryContentPacket
*/
public static function create(int $windowId, array $items) : self{
(function(Item ...$items){})(...$items); //type check
$result = new self;
$result->windowId = $windowId;
$result->items = $items;
return $result;
}
protected function decodePayload() : void{
$this->windowId = $this->getUnsignedVarInt();
$count = $this->getUnsignedVarInt();

View File

@ -38,6 +38,14 @@ class InventorySlotPacket extends DataPacket implements ClientboundPacket{
/** @var Item */
public $item;
public static function create(int $windowId, int $slot, Item $item) : self{
$result = new self;
$result->inventorySlot = $slot;
$result->item = $item;
$result->windowId = $windowId;
return $result;
}
protected function decodePayload() : void{
$this->windowId = $this->getUnsignedVarInt();
$this->inventorySlot = $this->getUnsignedVarInt();

View File

@ -46,6 +46,16 @@ class MobArmorEquipmentPacket extends DataPacket implements ClientboundPacket, S
/** @var Item */
public $feet;
public static function create(int $entityRuntimeId, Item $head, Item $chest, Item $legs, Item $feet) : self{
$result = new self;
$result->entityRuntimeId = $entityRuntimeId;
$result->head = $head;
$result->chest = $chest;
$result->legs = $legs;
$result->feet = $feet;
return $result;
}
protected function decodePayload() : void{
$this->entityRuntimeId = $this->getEntityRuntimeId();
$this->head = $this->getSlot();

View File

@ -48,6 +48,25 @@ class MobEffectPacket extends DataPacket implements ClientboundPacket{
/** @var int */
public $duration = 0;
public static function add(int $entityRuntimeId, bool $replace, int $effectId, int $amplifier, bool $particles, int $duration) : self{
$result = new self;
$result->eventId = $replace ? self::EVENT_MODIFY : self::EVENT_ADD;
$result->entityRuntimeId = $entityRuntimeId;
$result->effectId = $effectId;
$result->amplifier = $amplifier;
$result->particles = $particles;
$result->duration = $duration;
return $result;
}
public static function remove(int $entityRuntimeId, int $effectId) : self{
$pk = new self;
$pk->eventId = self::EVENT_REMOVE;
$pk->entityRuntimeId = $entityRuntimeId;
$pk->effectId = $effectId;
return $pk;
}
protected function decodePayload() : void{
$this->entityRuntimeId = $this->getEntityRuntimeId();
$this->eventId = $this->getByte();

View File

@ -43,6 +43,16 @@ class MobEquipmentPacket extends DataPacket implements ClientboundPacket, Server
/** @var int */
public $windowId = 0;
public static function create(int $entityRuntimeId, Item $item, int $inventorySlot, int $windowId) : self{
$result = new self;
$result->entityRuntimeId = $entityRuntimeId;
$result->item = $item;
$result->inventorySlot = $inventorySlot;
$result->hotbarSlot = $inventorySlot;
$result->windowId = $windowId;
return $result;
}
protected function decodePayload() : void{
$this->entityRuntimeId = $this->getEntityRuntimeId();
$this->item = $this->getSlot();

View File

@ -35,6 +35,13 @@ class ModalFormRequestPacket extends DataPacket implements ClientboundPacket{
/** @var string */
public $formData; //json
public static function create(int $formId, string $formData) : self{
$result = new self;
$result->formId = $formId;
$result->formData = $formData;
return $result;
}
protected function decodePayload() : void{
$this->formId = $this->getUnsignedVarInt();
$this->formData = $this->getString();

View File

@ -39,6 +39,15 @@ class NetworkChunkPublisherUpdatePacket extends DataPacket implements Clientboun
/** @var int */
public $radius;
public static function create(int $x, int $y, int $z, int $blockRadius) : self{
$result = new self;
$result->x = $x;
$result->y = $y;
$result->z = $z;
$result->radius = $blockRadius;
return $result;
}
protected function decodePayload() : void{
$this->getSignedBlockPosition($this->x, $this->y, $this->z);
$this->radius = $this->getUnsignedVarInt();

View File

@ -43,6 +43,12 @@ class PlayStatusPacket extends DataPacket implements ClientboundPacket{
/** @var int */
public $status;
public static function create(int $status) : self{
$result = new self;
$result->status = $status;
return $result;
}
protected function decodePayload() : void{
$this->status = $this->getInt();
}

View File

@ -43,6 +43,22 @@ class PlayerListPacket extends DataPacket implements ClientboundPacket{
/** @var int */
public $type;
public static function add(array $entries) : self{
(function(PlayerListEntry ...$_){})($entries);
$result = new self;
$result->type = self::TYPE_ADD;
$result->entries = $entries;
return $result;
}
public static function remove(array $entries) : self{
(function(PlayerListEntry ...$_){})($entries);
$result = new self;
$result->type = self::TYPE_REMOVE;
$result->entries = $entries;
return $result;
}
protected function decodePayload() : void{
$this->type = $this->getByte();
$count = $this->getUnsignedVarInt();

View File

@ -34,6 +34,12 @@ class RemoveEntityPacket extends DataPacket implements ClientboundPacket{
/** @var int */
public $entityUniqueId;
public static function create(int $entityUniqueId) : self{
$result = new self;
$result->entityUniqueId = $entityUniqueId;
return $result;
}
protected function decodePayload() : void{
$this->entityUniqueId = $this->getEntityUniqueId();
}

View File

@ -42,6 +42,15 @@ class ResourcePackChunkDataPacket extends DataPacket implements ClientboundPacke
/** @var string */
public $data;
public static function create(string $packId, int $chunkIndex, int $chunkOffset, string $data) : self{
$result = new self;
$result->packId = $packId;
$result->chunkIndex = $chunkIndex;
$result->progress = $chunkOffset;
$result->data = $data;
return $result;
}
protected function decodePayload() : void{
$this->packId = $this->getString();
$this->chunkIndex = $this->getLInt();

View File

@ -43,6 +43,16 @@ class ResourcePackDataInfoPacket extends DataPacket implements ClientboundPacket
/** @var string */
public $sha256;
public static function create(string $packId, int $maxChunkSize, int $chunkCount, int $compressedPackSize, string $sha256sum) : self{
$result = new self;
$result->packId = $packId;
$result->maxChunkSize = $maxChunkSize;
$result->chunkCount = $chunkCount;
$result->compressedPackSize = $compressedPackSize;
$result->sha256 = $sha256sum;
return $result;
}
protected function decodePayload() : void{
$this->packId = $this->getString();
$this->maxChunkSize = $this->getLInt();

View File

@ -45,6 +45,25 @@ class ResourcePackStackPacket extends DataPacket implements ClientboundPacket{
/** @var bool */
public $isExperimental = false;
/**
* @param ResourcePack[] $resourcePacks
* @param ResourcePack[] $behaviorPacks
* @param bool $mustAccept
* @param bool $isExperimental
*
* @return ResourcePackStackPacket
*/
public static function create(array $resourcePacks, array $behaviorPacks, bool $mustAccept, bool $isExperimental = false) : self{
(function(ResourcePack ...$_){})($resourcePacks);
(function(ResourcePack ...$_){})($behaviorPacks);
$result = new self;
$result->mustAccept = $mustAccept;
$result->resourcePackStack = $resourcePacks;
$result->behaviorPackStack = $behaviorPacks;
$result->isExperimental = $isExperimental;
return $result;
}
protected function decodePayload() : void{
$this->mustAccept = $this->getBool();
$behaviorPackCount = $this->getUnsignedVarInt();

View File

@ -42,6 +42,25 @@ class ResourcePacksInfoPacket extends DataPacket implements ClientboundPacket{
/** @var ResourcePack[] */
public $resourcePackEntries = [];
/**
* @param ResourcePack[] $resourcePacks
* @param ResourcePack[] $behaviorPacks
* @param bool $mustAccept
* @param bool $hasScripts
*
* @return ResourcePacksInfoPacket
*/
public static function create(array $resourcePacks, array $behaviorPacks, bool $mustAccept, bool $hasScripts = false) : self{
(function(ResourcePack ...$_){})($resourcePacks);
(function(ResourcePack ...$_){})($behaviorPacks);
$result = new self;
$result->mustAccept = $mustAccept;
$result->hasScripts = $hasScripts;
$result->resourcePackEntries = $resourcePacks;
$result->behaviorPackEntries = $behaviorPacks;
return $result;
}
protected function decodePayload() : void{
$this->mustAccept = $this->getBool();
$this->hasScripts = $this->getBool();

View File

@ -35,6 +35,12 @@ class RespawnPacket extends DataPacket implements ClientboundPacket{
/** @var Vector3 */
public $position;
public static function create(Vector3 $position) : self{
$result = new self;
$result->position = $position->asVector3();
return $result;
}
protected function decodePayload() : void{
$this->position = $this->getVector3();
}

View File

@ -37,6 +37,12 @@ class ServerToClientHandshakePacket extends DataPacket implements ClientboundPac
*/
public $jwt;
public static function create(string $jwt) : self{
$result = new self;
$result->jwt = $jwt;
return $result;
}
public function canBeSentBeforeLogin() : bool{
return true;
}

View File

@ -36,6 +36,13 @@ class SetEntityDataPacket extends DataPacket implements ClientboundPacket, Serve
/** @var array */
public $metadata;
public static function create(int $entityRuntimeId, array $metadata) : self{
$result = new self;
$result->entityRuntimeId = $entityRuntimeId;
$result->metadata = $metadata;
return $result;
}
protected function decodePayload() : void{
$this->entityRuntimeId = $this->getEntityRuntimeId();
$this->metadata = $this->getEntityMetadata();

View File

@ -37,6 +37,13 @@ class SetEntityMotionPacket extends DataPacket implements ClientboundPacket{
/** @var Vector3 */
public $motion;
public static function create(int $entityRuntimeId, Vector3 $motion) : self{
$result = new self;
$result->entityRuntimeId = $entityRuntimeId;
$result->motion = $motion->asVector3();
return $result;
}
protected function decodePayload() : void{
$this->entityRuntimeId = $this->getEntityRuntimeId();
$this->motion = $this->getVector3();

View File

@ -34,6 +34,12 @@ class SetPlayerGameTypePacket extends DataPacket implements ClientboundPacket, S
/** @var int */
public $gamemode;
public static function create(int $gamemode) : self{
$pk = new self;
$pk->gamemode = $gamemode;
return $pk;
}
protected function decodePayload() : void{
$this->gamemode = $this->getVarInt();
}

View File

@ -45,6 +45,21 @@ class SetSpawnPositionPacket extends DataPacket implements ClientboundPacket{
/** @var bool */
public $spawnForced;
public static function playerSpawn(int $x, int $y, int $z, bool $forced) : self{
$result = new self;
$result->spawnType = self::TYPE_PLAYER_SPAWN;
[$result->x, $result->y, $result->z] = [$x, $y, $z];
$result->spawnForced = $forced;
return $result;
}
public static function worldSpawn(int $x, int $y, int $z) : self{
$result = new self;
$result->spawnType = self::TYPE_WORLD_SPAWN;
[$result->x, $result->y, $result->z] = [$x, $y, $z];
return $result;
}
protected function decodePayload() : void{
$this->spawnType = $this->getVarInt();
$this->getBlockPosition($this->x, $this->y, $this->z);

View File

@ -33,6 +33,12 @@ class SetTimePacket extends DataPacket implements ClientboundPacket{
/** @var int */
public $time;
public static function create(int $time) : self{
$result = new self;
$result->time = $time;
return $result;
}
protected function decodePayload() : void{
$this->time = $this->getVarInt();
}

View File

@ -36,6 +36,13 @@ class TakeItemEntityPacket extends DataPacket implements ClientboundPacket{
/** @var int */
public $eid;
public static function create(int $takerEntityRuntimeId, int $itemEntityRuntimeId) : self{
$result = new self;
$result->target = $takerEntityRuntimeId;
$result->eid = $itemEntityRuntimeId;
return $result;
}
protected function decodePayload() : void{
$this->target = $this->getEntityRuntimeId();
$this->eid = $this->getEntityRuntimeId();

View File

@ -58,6 +58,65 @@ class TextPacket extends DataPacket implements ClientboundPacket, ServerboundPac
/** @var string */
public $platformChatId = "";
private static function messageOnly(int $type, string $message) : self{
$result = new self;
$result->type = $type;
$result->message = $message;
return $result;
}
private static function baseTranslation(int $type, string $key, array $parameters) : self{
(function(string ...$_){})(...$parameters);
$result = new self;
$result->type = $type;
$result->needsTranslation = true;
$result->message = $key;
$result->parameters = $parameters;
return $result;
}
public static function raw(string $message) : self{
return self::messageOnly(self::TYPE_RAW, $message);
}
/**
* @param string $key
* @param string[] $parameters
*
* @return TextPacket
*/
public static function translation(string $key, array $parameters = []) : self{
return self::baseTranslation(self::TYPE_TRANSLATION, $key, $parameters);
}
public static function popup(string $message) : self{
return self::messageOnly(self::TYPE_POPUP, $message);
}
/**
* @param string $key
* @param string[] $parameters
*
* @return TextPacket
*/
public static function translatedPopup(string $key, array $parameters = []) : self{
return self::baseTranslation(self::TYPE_POPUP, $key, $parameters);
}
/**
* @param string $key
* @param string[] $parameters
*
* @return TextPacket
*/
public static function jukeboxPopup(string $key, array $parameters = []) : self{
return self::baseTranslation(self::TYPE_JUKEBOX_POPUP, $key, $parameters);
}
public static function tip(string $message) : self{
return self::messageOnly(self::TYPE_TIP, $message);
}
protected function decodePayload() : void{
$this->type = $this->getByte();
$this->needsTranslation = $this->getBool();

View File

@ -35,6 +35,13 @@ class TransferPacket extends DataPacket implements ClientboundPacket{
/** @var int */
public $port = 19132;
public static function create(string $address, int $port) : self{
$result = new self;
$result->address = $address;
$result->port = $port;
return $result;
}
protected function decodePayload() : void{
$this->address = $this->getString();
$this->port = $this->getLShort();

View File

@ -38,6 +38,20 @@ class UpdateAttributesPacket extends DataPacket implements ClientboundPacket{
/** @var Attribute[] */
public $entries = [];
/**
* @param int $entityRuntimeId
* @param Attribute[] $attributes
*
* @return UpdateAttributesPacket
*/
public static function create(int $entityRuntimeId, array $attributes) : self{
(function(Attribute ...$attributes){})(...$attributes);
$result = new self;
$result->entityRuntimeId = $entityRuntimeId;
$result->entries = $attributes;
return $result;
}
protected function decodePayload() : void{
$this->entityRuntimeId = $this->getEntityRuntimeId();
$this->entries = $this->getAttributeList();

View File

@ -51,6 +51,14 @@ class UpdateBlockPacket extends DataPacket implements ClientboundPacket{
/** @var int */
public $dataLayerId = self::DATA_LAYER_NORMAL;
public static function create(int $x, int $y, int $z, int $blockRuntimeId, int $dataLayerId = self::DATA_LAYER_NORMAL) : self{
$result = new self;
[$result->x, $result->y, $result->z] = [$x, $y, $z];
$result->blockRuntimeId = $blockRuntimeId;
$result->dataLayerId = $dataLayerId;
return $result;
}
protected function decodePayload() : void{
$this->getBlockPosition($this->x, $this->y, $this->z);
$this->blockRuntimeId = $this->getUnsignedVarInt();

View File

@ -240,11 +240,7 @@ class Explosion{
$send[] = new Vector3($block->x - $source->x, $block->y - $source->y, $block->z - $source->z);
}
$pk = new ExplodePacket();
$pk->position = $this->source->asVector3();
$pk->radius = $this->size;
$pk->records = $send;
$this->world->broadcastPacketToViewers($source, $pk);
$this->world->broadcastPacketToViewers($source, ExplodePacket::create($this->source->asVector3(), $this->size, $send));
$this->world->addParticle($source, new HugeExplodeSeedParticle());
$this->world->addSound($source, new ExplodeSound());

View File

@ -715,8 +715,7 @@ class World implements ChunkManager, Metadatable{
* @param Player ...$targets If empty, will send to all players in the world.
*/
public function sendTime(Player ...$targets){
$pk = new SetTimePacket();
$pk->time = $this->time & 0xffffffff; //avoid overflowing the field, since the packet uses an int32
$pk = SetTimePacket::create($this->time & 0xffffffff); //avoid overflowing the field, since the packet uses an int32
if(empty($targets)){
$this->broadcastGlobalPacket($pk);
@ -934,28 +933,17 @@ class World implements ChunkManager, Metadatable{
if(!($b instanceof Vector3)){
throw new \TypeError("Expected Vector3 in blocks array, got " . (is_object($b) ? get_class($b) : gettype($b)));
}
$pk = new UpdateBlockPacket();
$pk->x = $b->x;
$pk->y = $b->y;
$pk->z = $b->z;
if($b instanceof Block){
$pk->blockRuntimeId = $b->getRuntimeId();
$packets[] = UpdateBlockPacket::create($b->x, $b->y, $b->z, $b->getRuntimeId());
}else{
$fullBlock = $this->getFullBlock($b->x, $b->y, $b->z);
$pk->blockRuntimeId = RuntimeBlockMapping::toStaticRuntimeId($fullBlock >> 4, $fullBlock & 0xf);
$packets[] = UpdateBlockPacket::create($b->x, $b->y, $b->z, RuntimeBlockMapping::toStaticRuntimeId($fullBlock >> 4, $fullBlock & 0xf));
}
$packets[] = $pk;
$tile = $this->getTileAt($b->x, $b->y, $b->z);
if($tile instanceof Spawnable){
$tilepk = new BlockEntityDataPacket();
$tilepk->x = $tile->x;
$tilepk->y = $tile->y;
$tilepk->z = $tile->z;
$tilepk->namedtag = $tile->getSerializedSpawnCompound();
$packets[] = $tilepk;
$packets[] = BlockEntityDataPacket::create($tile->x, $tile->y, $tile->z, $tile->getSerializedSpawnCompound());
}
}

View File

@ -84,20 +84,14 @@ class FloatingTextParticle implements Particle{
if($this->entityId === null){
$this->entityId = EntityFactory::nextRuntimeId();
}else{
$pk0 = new RemoveEntityPacket();
$pk0->entityUniqueId = $this->entityId;
$p[] = $pk0;
$p[] = RemoveEntityPacket::create($this->entityId);
}
if(!$this->invisible){
$uuid = UUID::fromRandom();
$name = $this->title . ($this->text !== "" ? "\n" . $this->text : "");
$add = new PlayerListPacket();
$add->type = PlayerListPacket::TYPE_ADD;
$add->entries = [PlayerListEntry::createAdditionEntry($uuid, $this->entityId, $name, new Skin("Standard_Custom", str_repeat("\x00", 8192)))];
$p[] = $add;
$p[] = PlayerListPacket::add([PlayerListEntry::createAdditionEntry($uuid, $this->entityId, $name, new Skin("Standard_Custom", str_repeat("\x00", 8192)))]);
$pk = new AddPlayerPacket();
$pk->uuid = $uuid;
@ -116,10 +110,7 @@ class FloatingTextParticle implements Particle{
$p[] = $pk;
$remove = new PlayerListPacket();
$remove->type = PlayerListPacket::TYPE_REMOVE;
$remove->entries = [PlayerListEntry::createRemovalEntry($uuid)];
$p[] = $remove;
$p[] = PlayerListPacket::remove([PlayerListEntry::createRemovalEntry($uuid)]);
}
return $p;