Merge branch 'minor-next' into major-next

This commit is contained in:
Dylan K. Taylor 2023-03-15 23:02:41 +00:00
commit abd4ef01eb
No known key found for this signature in database
GPG Key ID: 8927471A91CAFD3D
19 changed files with 554 additions and 241 deletions

View File

@ -25,13 +25,25 @@ jobs:
- name: Download new release information
run: curl -f -L ${{ github.server_url }}/${{ github.repository }}/releases/download/${{ steps.tag-name.outputs.TAG_NAME }}/build_info.json -o new_build_info.json
- name: Detect channel
- name: Detect channels
id: channel
run: echo CHANNEL=$(jq -r '.channel' new_build_info.json) >> $GITHUB_OUTPUT
- name: Copy release information
run: |
cp new_build_info.json channels/${{ steps.channel.outputs.CHANNEL }}.json
CHANNEL=$(jq -r '.channel' new_build_info.json)
VERSION=${{ steps.tag-name.outputs.TAG_NAME }}
echo CHANNEL=$CHANNEL >> $GITHUB_OUTPUT
if [ "$CHANNEL" == "stable" ]; then
echo MAJOR=$(echo $VERSION | cut -d. -f1) >> $GITHUB_OUTPUT
echo MINOR=$(echo $VERSION | cut -d. -f1-2) >> $GITHUB_OUTPUT
else
echo MAJOR=$(echo $VERSION | cut -d. -f1)-$CHANNEL >> $GITHUB_OUTPUT
echo MINOR=$(echo $VERSION | cut -d. -f1-2)-$CHANNEL >> $GITHUB_OUTPUT
fi
- name: Update channel info
run: |
cp new_build_info.json "channels/${{ steps.channel.outputs.CHANNEL }}.json"
cp new_build_info.json "channels/${{ steps.channel.outputs.MAJOR }}.json"
cp new_build_info.json "channels/${{ steps.channel.outputs.MINOR }}.json"
rm new_build_info.json
- name: Commit changes

View File

@ -38,7 +38,6 @@ use function is_string;
use function max;
use function preg_match;
use function preg_replace;
use function sleep;
use function sprintf;
use function str_pad;
use function strlen;
@ -160,9 +159,6 @@ function main() : void{
replaceVersion($versionInfoPath, $nextVer->getBaseVersion(), true, $channel);
systemWrapper('git add "' . $versionInfoPath . '"', "failed to stage changes for post-release commit");
systemWrapper('git commit -m "' . $nextVer->getBaseVersion() . ' is next" --include "' . $versionInfoPath . '"', "failed to create post-release commit");
echo "pushing changes in 5 seconds\n";
sleep(5);
systemWrapper('git push origin HEAD ' . $currentVer->getBaseVersion(), "failed to push changes to remote");
}
main();

@ -1 +1 @@
Subproject commit 71b9f9d2d7b3ee45d9475803b96c080f5f22f373
Subproject commit a464454d1ed946baabd32a02ddcf66361374b99c

View File

@ -43,7 +43,6 @@ use pocketmine\event\player\PlayerCreationEvent;
use pocketmine\event\player\PlayerDataSaveEvent;
use pocketmine\event\player\PlayerLoginEvent;
use pocketmine\event\server\CommandEvent;
use pocketmine\event\server\DataPacketSendEvent;
use pocketmine\event\server\QueryRegenerateEvent;
use pocketmine\lang\KnownTranslationFactory;
use pocketmine\lang\Language;
@ -54,13 +53,19 @@ use pocketmine\network\mcpe\compression\CompressBatchPromise;
use pocketmine\network\mcpe\compression\CompressBatchTask;
use pocketmine\network\mcpe\compression\Compressor;
use pocketmine\network\mcpe\compression\ZlibCompressor;
use pocketmine\network\mcpe\convert\GlobalItemTypeDictionary;
use pocketmine\network\mcpe\encryption\EncryptionContext;
use pocketmine\network\mcpe\EntityEventBroadcaster;
use pocketmine\network\mcpe\NetworkBroadcastUtils;
use pocketmine\network\mcpe\NetworkSession;
use pocketmine\network\mcpe\PacketBroadcaster;
use pocketmine\network\mcpe\protocol\ClientboundPacket;
use pocketmine\network\mcpe\protocol\ProtocolInfo;
use pocketmine\network\mcpe\protocol\serializer\PacketBatch;
use pocketmine\network\mcpe\protocol\serializer\PacketSerializerContext;
use pocketmine\network\mcpe\raklib\RakLibInterface;
use pocketmine\network\mcpe\StandardEntityEventBroadcaster;
use pocketmine\network\mcpe\StandardPacketBroadcaster;
use pocketmine\network\Network;
use pocketmine\network\NetworkInterfaceStartException;
use pocketmine\network\query\DedicatedQueryNetworkInterface;
@ -1165,10 +1170,18 @@ class Server{
return !$anyWorldFailedToLoad;
}
private function startupPrepareConnectableNetworkInterfaces(string $ip, int $port, bool $ipV6, bool $useQuery) : bool{
private function startupPrepareConnectableNetworkInterfaces(
string $ip,
int $port,
bool $ipV6,
bool $useQuery,
PacketBroadcaster $packetBroadcaster,
EntityEventBroadcaster $entityEventBroadcaster,
PacketSerializerContext $packetSerializerContext
) : bool{
$prettyIp = $ipV6 ? "[$ip]" : $ip;
try{
$rakLibRegistered = $this->network->registerInterface(new RakLibInterface($this, $ip, $port, $ipV6));
$rakLibRegistered = $this->network->registerInterface(new RakLibInterface($this, $ip, $port, $ipV6, $packetBroadcaster, $entityEventBroadcaster, $packetSerializerContext));
}catch(NetworkInterfaceStartException $e){
$this->logger->emergency($this->language->translate(KnownTranslationFactory::pocketmine_server_networkStartFailed(
$ip,
@ -1194,11 +1207,15 @@ class Server{
private function startupPrepareNetworkInterfaces() : bool{
$useQuery = $this->configGroup->getConfigBool("enable-query", true);
$packetSerializerContext = new PacketSerializerContext(GlobalItemTypeDictionary::getInstance()->getDictionary());
$packetBroadcaster = new StandardPacketBroadcaster($this, $packetSerializerContext);
$entityEventBroadcaster = new StandardEntityEventBroadcaster($packetBroadcaster);
if(
!$this->startupPrepareConnectableNetworkInterfaces($this->getIp(), $this->getPort(), false, $useQuery) ||
!$this->startupPrepareConnectableNetworkInterfaces($this->getIp(), $this->getPort(), false, $useQuery, $packetBroadcaster, $entityEventBroadcaster, $packetSerializerContext) ||
(
$this->configGroup->getConfigBool("enable-ipv6", true) &&
!$this->startupPrepareConnectableNetworkInterfaces($this->getIpV6(), $this->getPortV6(), true, $useQuery)
!$this->startupPrepareConnectableNetworkInterfaces($this->getIpV6(), $this->getPortV6(), true, $useQuery, $packetBroadcaster, $entityEventBroadcaster, $packetSerializerContext)
)
){
return false;
@ -1330,47 +1347,10 @@ class Server{
/**
* @param Player[] $players
* @param ClientboundPacket[] $packets
* @deprecated
*/
public function broadcastPackets(array $players, array $packets) : bool{
if(count($packets) === 0){
throw new \InvalidArgumentException("Cannot broadcast empty list of packets");
}
return Timings::$broadcastPackets->time(function() use ($players, $packets) : bool{
/** @var NetworkSession[] $recipients */
$recipients = [];
foreach($players as $player){
if($player->isConnected()){
$recipients[] = $player->getNetworkSession();
}
}
if(count($recipients) === 0){
return false;
}
$ev = new DataPacketSendEvent($recipients, $packets);
$ev->call();
if($ev->isCancelled()){
return false;
}
$recipients = $ev->getTargets();
$packets = $ev->getPackets();
/** @var PacketBroadcaster[] $broadcasters */
$broadcasters = [];
/** @var NetworkSession[][] $broadcasterTargets */
$broadcasterTargets = [];
foreach($recipients as $recipient){
$broadcaster = $recipient->getBroadcaster();
$broadcasters[spl_object_id($broadcaster)] = $broadcaster;
$broadcasterTargets[spl_object_id($broadcaster)][] = $recipient;
}
foreach($broadcasters as $broadcaster){
$broadcaster->broadcastPackets($broadcasterTargets[spl_object_id($broadcaster)], $packets);
}
return true;
});
return NetworkBroadcastUtils::broadcastPackets($players, $packets);
}
/**

View File

@ -44,6 +44,8 @@ use pocketmine\nbt\tag\DoubleTag;
use pocketmine\nbt\tag\FloatTag;
use pocketmine\nbt\tag\ListTag;
use pocketmine\nbt\tag\StringTag;
use pocketmine\network\mcpe\EntityEventBroadcaster;
use pocketmine\network\mcpe\NetworkBroadcastUtils;
use pocketmine\network\mcpe\protocol\AddActorPacket;
use pocketmine\network\mcpe\protocol\MoveActorAbsolutePacket;
use pocketmine\network\mcpe\protocol\SetActorMotionPacket;
@ -756,7 +758,7 @@ abstract class Entity{
$this->spawnTo($player);
}
}else{
$this->server->broadcastPackets($this->hasSpawned, [MoveActorAbsolutePacket::create(
NetworkBroadcastUtils::broadcastPackets($this->hasSpawned, [MoveActorAbsolutePacket::create(
$this->id,
$this->getOffsetPosition($this->location),
$this->location->pitch,
@ -771,7 +773,7 @@ abstract class Entity{
}
protected function broadcastMotion() : void{
$this->server->broadcastPackets($this->hasSpawned, [SetActorMotionPacket::create($this->id, $this->getMotion())]);
NetworkBroadcastUtils::broadcastPackets($this->hasSpawned, [SetActorMotionPacket::create($this->id, $this->getMotion())]);
}
public function getGravity() : float{
@ -1508,7 +1510,7 @@ abstract class Entity{
$id = spl_object_id($player);
if(isset($this->hasSpawned[$id])){
if($send){
$player->getNetworkSession()->onEntityRemoved($this);
$player->getNetworkSession()->getEntityEventBroadcaster()->onEntityRemoved([$player->getNetworkSession()], $this);
}
unset($this->hasSpawned[$id]);
}
@ -1519,9 +1521,11 @@ abstract class Entity{
* player moves, viewers will once again be able to see the entity.
*/
public function despawnFromAll() : void{
foreach($this->hasSpawned as $player){
$this->despawnFrom($player);
}
NetworkBroadcastUtils::broadcastEntityEvent(
$this->hasSpawned,
fn(EntityEventBroadcaster $broadcaster, array $recipients) => $broadcaster->onEntityRemoved($recipients, $this)
);
$this->hasSpawned = [];
}
/**
@ -1595,9 +1599,7 @@ abstract class Entity{
$targets = $targets ?? $this->hasSpawned;
$data = $data ?? $this->getAllNetworkData();
foreach($targets as $p){
$p->getNetworkSession()->syncActorData($this, $data);
}
NetworkBroadcastUtils::broadcastEntityEvent($targets, fn(EntityEventBroadcaster $broadcaster, array $recipients) => $broadcaster->syncActorData($recipients, $this, $data));
}
/**
@ -1651,7 +1653,7 @@ abstract class Entity{
* @param Player[]|null $targets
*/
public function broadcastAnimation(Animation $animation, ?array $targets = null) : void{
$this->server->broadcastPackets($targets ?? $this->getViewers(), $animation->encode());
NetworkBroadcastUtils::broadcastPackets($targets ?? $this->getViewers(), $animation->encode());
}
/**
@ -1660,7 +1662,7 @@ abstract class Entity{
*/
public function broadcastSound(Sound $sound, ?array $targets = null) : void{
if(!$this->silent){
$this->server->broadcastPackets($targets ?? $this->getViewers(), $sound->encode($this->location));
NetworkBroadcastUtils::broadcastPackets($targets ?? $this->getViewers(), $sound->encode($this->location));
}
}

View File

@ -48,6 +48,8 @@ use pocketmine\nbt\tag\ListTag;
use pocketmine\nbt\tag\StringTag;
use pocketmine\network\mcpe\convert\SkinAdapterSingleton;
use pocketmine\network\mcpe\convert\TypeConverter;
use pocketmine\network\mcpe\EntityEventBroadcaster;
use pocketmine\network\mcpe\NetworkBroadcastUtils;
use pocketmine\network\mcpe\protocol\AddPlayerPacket;
use pocketmine\network\mcpe\protocol\PlayerListPacket;
use pocketmine\network\mcpe\protocol\PlayerSkinPacket;
@ -165,7 +167,7 @@ class Human extends Living implements ProjectileSource, InventoryHolder{
* @param Player[]|null $targets
*/
public function sendSkin(?array $targets = null) : void{
$this->server->broadcastPackets($targets ?? $this->hasSpawned, [
NetworkBroadcastUtils::broadcastPackets($targets ?? $this->hasSpawned, [
PlayerSkinPacket::create($this->getUniqueId(), "", "", SkinAdapterSingleton::get()->toSkinData($this->skin))
]);
}
@ -180,9 +182,10 @@ class Human extends Living implements ProjectileSource, InventoryHolder{
}
public function emote(string $emoteId) : void{
foreach($this->getViewers() as $player){
$player->getNetworkSession()->onEmote($this, $emoteId);
}
NetworkBroadcastUtils::broadcastEntityEvent(
$this->getViewers(),
fn(EntityEventBroadcaster $broadcaster, array $recipients) => $broadcaster->onEmote($recipients, $this, $emoteId)
);
}
public function getHungerManager() : HungerManager{
@ -258,11 +261,10 @@ class Human extends Living implements ProjectileSource, InventoryHolder{
$this->xpManager = new ExperienceManager($this);
$this->inventory = new PlayerInventory($this);
$syncHeldItem = function() : void{
foreach($this->getViewers() as $viewer){
$viewer->getNetworkSession()->onMobMainHandItemChange($this);
}
};
$syncHeldItem = fn() => NetworkBroadcastUtils::broadcastEntityEvent(
$this->getViewers(),
fn(EntityEventBroadcaster $broadcaster, array $recipients) => $broadcaster->onMobMainHandItemChange($recipients, $this)
);
$this->inventory->getListeners()->add(new CallbackInventoryListener(
function(Inventory $unused, int $slot, Item $unused2) use ($syncHeldItem) : void{
if($slot === $this->inventory->getHeldItemIndex()){
@ -303,11 +305,10 @@ class Human extends Living implements ProjectileSource, InventoryHolder{
if($offHand !== null){
$this->offHandInventory->setItem(0, Item::nbtDeserialize($offHand));
}
$this->offHandInventory->getListeners()->add(CallbackInventoryListener::onAnyChange(function() : void{
foreach($this->getViewers() as $viewer){
$viewer->getNetworkSession()->onMobOffHandItemChange($this);
}
}));
$this->offHandInventory->getListeners()->add(CallbackInventoryListener::onAnyChange(fn() => NetworkBroadcastUtils::broadcastEntityEvent(
$this->getViewers(),
fn(EntityEventBroadcaster $broadcaster, array $recipients) => $broadcaster->onMobOffHandItemChange($recipients, $this)
)));
$enderChestInventoryTag = $nbt->getListTag(self::TAG_ENDER_CHEST_INVENTORY);
if($enderChestInventoryTag !== null){
@ -321,11 +322,10 @@ class Human extends Living implements ProjectileSource, InventoryHolder{
}
$this->inventory->setHeldItemIndex($nbt->getInt(self::TAG_SELECTED_INVENTORY_SLOT, 0));
$this->inventory->getHeldItemIndexChangeListeners()->add(function(int $oldIndex) : void{
foreach($this->getViewers() as $viewer){
$viewer->getNetworkSession()->onMobMainHandItemChange($this);
}
});
$this->inventory->getHeldItemIndexChangeListeners()->add(fn() => NetworkBroadcastUtils::broadcastEntityEvent(
$this->getViewers(),
fn(EntityEventBroadcaster $broadcaster, array $recipients) => $broadcaster->onMobMainHandItemChange($recipients, $this)
));
$this->hungerManager->setFood((float) $nbt->getInt(self::TAG_FOOD_LEVEL, (int) $this->hungerManager->getFood()));
$this->hungerManager->setExhaustion($nbt->getFloat(self::TAG_FOOD_EXHAUSTION_LEVEL, $this->hungerManager->getExhaustion()));
@ -474,11 +474,12 @@ class Human extends Living implements ProjectileSource, InventoryHolder{
}
protected function sendSpawnPacket(Player $player) : void{
$networkSession = $player->getNetworkSession();
if(!($this instanceof Player)){
$player->getNetworkSession()->sendDataPacket(PlayerListPacket::add([PlayerListEntry::createAdditionEntry($this->uuid, $this->id, $this->getName(), SkinAdapterSingleton::get()->toSkinData($this->skin))]));
$networkSession->sendDataPacket(PlayerListPacket::add([PlayerListEntry::createAdditionEntry($this->uuid, $this->id, $this->getName(), SkinAdapterSingleton::get()->toSkinData($this->skin))]));
}
$player->getNetworkSession()->sendDataPacket(AddPlayerPacket::create(
$networkSession->sendDataPacket(AddPlayerPacket::create(
$this->getUniqueId(),
$this->getName(),
$this->getId(),
@ -508,11 +509,12 @@ class Human extends Living implements ProjectileSource, InventoryHolder{
//TODO: Hack for MCPE 1.2.13: DATA_NAMETAG is useless in AddPlayerPacket, so it has to be sent separately
$this->sendData([$player], [EntityMetadataProperties::NAMETAG => new StringMetadataProperty($this->getNameTag())]);
$player->getNetworkSession()->onMobArmorChange($this);
$player->getNetworkSession()->onMobOffHandItemChange($this);
$entityEventBroadcaster = $networkSession->getEntityEventBroadcaster();
$entityEventBroadcaster->onMobArmorChange([$networkSession], $this);
$entityEventBroadcaster->onMobOffHandItemChange([$networkSession], $this);
if(!($this instanceof Player)){
$player->getNetworkSession()->sendDataPacket(PlayerListPacket::remove([PlayerListEntry::createRemovalEntry($this->uuid)]));
$networkSession->sendDataPacket(PlayerListPacket::remove([PlayerListEntry::createRemovalEntry($this->uuid)]));
}
}

View File

@ -50,6 +50,8 @@ use pocketmine\nbt\tag\CompoundTag;
use pocketmine\nbt\tag\FloatTag;
use pocketmine\nbt\tag\ListTag;
use pocketmine\nbt\tag\ShortTag;
use pocketmine\network\mcpe\EntityEventBroadcaster;
use pocketmine\network\mcpe\NetworkBroadcastUtils;
use pocketmine\network\mcpe\protocol\types\entity\EntityMetadataCollection;
use pocketmine\network\mcpe\protocol\types\entity\EntityMetadataFlags;
use pocketmine\network\mcpe\protocol\types\entity\EntityMetadataProperties;
@ -127,13 +129,10 @@ abstract class Living extends Entity{
$this->armorInventory = new ArmorInventory($this);
//TODO: load/save armor inventory contents
$this->armorInventory->getListeners()->add(CallbackInventoryListener::onAnyChange(
function(Inventory $unused) : void{
foreach($this->getViewers() as $viewer){
$viewer->getNetworkSession()->onMobArmorChange($this);
}
}
));
$this->armorInventory->getListeners()->add(CallbackInventoryListener::onAnyChange(fn() => NetworkBroadcastUtils::broadcastEntityEvent(
$this->getViewers(),
fn(EntityEventBroadcaster $broadcaster, array $recipients) => $broadcaster->onMobArmorChange($recipients, $this)
)));
$health = $this->getMaxHealth();
@ -831,7 +830,8 @@ abstract class Living extends Entity{
protected function sendSpawnPacket(Player $player) : void{
parent::sendSpawnPacket($player);
$player->getNetworkSession()->onMobArmorChange($this);
$networkSession = $player->getNetworkSession();
$networkSession->getEntityEventBroadcaster()->onMobArmorChange([$networkSession], $this);
}
protected function syncNetworkData(EntityMetadataCollection $properties) : void{

View File

@ -35,6 +35,8 @@ use pocketmine\item\Item;
use pocketmine\math\Vector3;
use pocketmine\nbt\tag\CompoundTag;
use pocketmine\network\mcpe\convert\TypeConverter;
use pocketmine\network\mcpe\EntityEventBroadcaster;
use pocketmine\network\mcpe\NetworkBroadcastUtils;
use pocketmine\network\mcpe\protocol\AddItemActorPacket;
use pocketmine\network\mcpe\protocol\types\entity\EntityIds;
use pocketmine\network\mcpe\protocol\types\inventory\ItemStackWrapper;
@ -321,9 +323,10 @@ class ItemEntity extends Entity{
return;
}
foreach($this->getViewers() as $viewer){
$viewer->getNetworkSession()->onPlayerPickUpItem($player, $this);
}
NetworkBroadcastUtils::broadcastEntityEvent(
$this->getViewers(),
fn(EntityEventBroadcaster $broadcaster, array $recipients) => $broadcaster->onPickUpItem($recipients, $player, $this)
);
$inventory = $ev->getInventory();
if($inventory !== null){

View File

@ -33,6 +33,8 @@ use pocketmine\event\entity\ProjectileHitEvent;
use pocketmine\item\VanillaItems;
use pocketmine\math\RayTraceResult;
use pocketmine\nbt\tag\CompoundTag;
use pocketmine\network\mcpe\EntityEventBroadcaster;
use pocketmine\network\mcpe\NetworkBroadcastUtils;
use pocketmine\network\mcpe\protocol\types\entity\EntityIds;
use pocketmine\network\mcpe\protocol\types\entity\EntityMetadataCollection;
use pocketmine\network\mcpe\protocol\types\entity\EntityMetadataFlags;
@ -188,9 +190,10 @@ class Arrow extends Projectile{
return;
}
foreach($this->getViewers() as $viewer){
$viewer->getNetworkSession()->onPlayerPickUpItem($player, $this);
}
NetworkBroadcastUtils::broadcastEntityEvent(
$this->getViewers(),
fn(EntityEventBroadcaster $broadcaster, array $recipients) => $broadcaster->onPickUpItem($recipients, $player, $this)
);
$ev->getInventory()?->addItem($ev->getItem());
$this->flagForDespawn();

View File

@ -0,0 +1,54 @@
<?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 PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\event\server;
use pocketmine\event\Cancellable;
use pocketmine\event\CancellableTrait;
use pocketmine\network\mcpe\NetworkSession;
/**
* Called before a packet is decoded and handled by the network session.
* Cancelling this event will drop the packet without decoding it, minimizing wasted CPU time.
*/
class DataPacketPreReceiveEvent extends ServerEvent implements Cancellable{
use CancellableTrait;
public function __construct(
private NetworkSession $origin,
private int $packetId,
private string $packetBuffer
){}
public function getOrigin() : NetworkSession{
return $this->origin;
}
public function getPacketId() : int{
return $this->packetId;
}
public function getPacketBuffer() : string{
return $this->packetBuffer;
}
}

View File

@ -0,0 +1,93 @@
<?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 PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\network\mcpe;
use pocketmine\entity\Attribute;
use pocketmine\entity\effect\EffectInstance;
use pocketmine\entity\Entity;
use pocketmine\entity\Human;
use pocketmine\entity\Living;
use pocketmine\network\mcpe\protocol\types\entity\MetadataProperty;
/**
* This class allows broadcasting entity events to many viewers on the server network.
*/
interface EntityEventBroadcaster{
/**
* @param NetworkSession[] $recipients
* @param Attribute[] $attributes
*/
public function syncAttributes(array $recipients, Living $entity, array $attributes) : void;
/**
* @param NetworkSession[] $recipients
* @param MetadataProperty[] $properties
*
* @phpstan-param array<int, MetadataProperty> $properties
*/
public function syncActorData(array $recipients, Entity $entity, array $properties) : void;
/**
* @param NetworkSession[] $recipients
*/
public function onEntityEffectAdded(array $recipients, Living $entity, EffectInstance $effect, bool $replacesOldEffect) : void;
/**
* @param NetworkSession[] $recipients
*/
public function onEntityEffectRemoved(array $recipients, Living $entity, EffectInstance $effect) : void;
/**
* @param NetworkSession[] $recipients
*/
public function onEntityRemoved(array $recipients, Entity $entity) : void;
/**
* TODO: expand this to more than just humans
*
* @param NetworkSession[] $recipients
*/
public function onMobMainHandItemChange(array $recipients,Human $mob) : void;
/**
* @param NetworkSession[] $recipients
*/
public function onMobOffHandItemChange(array $recipients, Human $mob) : void;
/**
* @param NetworkSession[] $recipients
*/
public function onMobArmorChange(array $recipients, Living $mob) : void;
/**
* @param NetworkSession[] $recipients
*/
public function onPickUpItem(array $recipients, Entity $collector, Entity $pickedUp) : void;
/**
* @param NetworkSession[] $recipients
*/
public function onEmote(array $recipients, Human $from, string $emoteId) : void;
}

View File

@ -0,0 +1,104 @@
<?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 PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\network\mcpe;
use pocketmine\event\server\DataPacketSendEvent;
use pocketmine\network\mcpe\protocol\ClientboundPacket;
use pocketmine\player\Player;
use pocketmine\timings\Timings;
use function count;
use function spl_object_id;
final class NetworkBroadcastUtils{
private function __construct(){
//NOOP
}
/**
* @param Player[] $recipients
* @param ClientboundPacket[] $packets
*/
public static function broadcastPackets(array $recipients, array $packets) : bool{
if(count($packets) === 0){
throw new \InvalidArgumentException("Cannot broadcast empty list of packets");
}
return Timings::$broadcastPackets->time(function() use ($recipients, $packets) : bool{
/** @var NetworkSession[] $sessions */
$sessions = [];
foreach($recipients as $player){
if($player->isConnected()){
$sessions[] = $player->getNetworkSession();
}
}
if(count($sessions) === 0){
return false;
}
$ev = new DataPacketSendEvent($sessions, $packets);
$ev->call();
if($ev->isCancelled()){
return false;
}
$sessions = $ev->getTargets();
$packets = $ev->getPackets();
/** @var PacketBroadcaster[] $uniqueBroadcasters */
$uniqueBroadcasters = [];
/** @var NetworkSession[][] $broadcasterTargets */
$broadcasterTargets = [];
foreach($sessions as $recipient){
$broadcaster = $recipient->getBroadcaster();
$uniqueBroadcasters[spl_object_id($broadcaster)] = $broadcaster;
$broadcasterTargets[spl_object_id($broadcaster)][spl_object_id($recipient)] = $recipient;
}
foreach($uniqueBroadcasters as $broadcaster){
$broadcaster->broadcastPackets($broadcasterTargets[spl_object_id($broadcaster)], $packets);
}
return true;
});
}
/**
* @param Player[] $recipients
* @phpstan-param \Closure(EntityEventBroadcaster, array<int, NetworkSession>) : void $callback
*/
public static function broadcastEntityEvent(array $recipients, \Closure $callback) : void{
$uniqueBroadcasters = [];
$broadcasterTargets = [];
foreach($recipients as $recipient){
$session = $recipient->getNetworkSession();
$broadcaster = $session->getEntityEventBroadcaster();
$uniqueBroadcasters[spl_object_id($broadcaster)] = $broadcaster;
$broadcasterTargets[spl_object_id($broadcaster)][spl_object_id($session)] = $session;
}
foreach($uniqueBroadcasters as $k => $broadcaster){
$callback($broadcaster, $broadcasterTargets[$k]);
}
}
}

View File

@ -23,13 +23,9 @@ declare(strict_types=1);
namespace pocketmine\network\mcpe;
use pocketmine\data\bedrock\EffectIdMap;
use pocketmine\entity\Attribute;
use pocketmine\entity\effect\EffectInstance;
use pocketmine\entity\Entity;
use pocketmine\entity\Human;
use pocketmine\entity\Living;
use pocketmine\event\player\PlayerDuplicateLoginEvent;
use pocketmine\event\server\DataPacketPreReceiveEvent;
use pocketmine\event\server\DataPacketReceiveEvent;
use pocketmine\event\server\DataPacketSendEvent;
use pocketmine\form\Form;
@ -60,10 +56,6 @@ use pocketmine\network\mcpe\protocol\AvailableCommandsPacket;
use pocketmine\network\mcpe\protocol\ChunkRadiusUpdatedPacket;
use pocketmine\network\mcpe\protocol\ClientboundPacket;
use pocketmine\network\mcpe\protocol\DisconnectPacket;
use pocketmine\network\mcpe\protocol\EmotePacket;
use pocketmine\network\mcpe\protocol\MobArmorEquipmentPacket;
use pocketmine\network\mcpe\protocol\MobEffectPacket;
use pocketmine\network\mcpe\protocol\MobEquipmentPacket;
use pocketmine\network\mcpe\protocol\ModalFormRequestPacket;
use pocketmine\network\mcpe\protocol\MovePlayerPacket;
use pocketmine\network\mcpe\protocol\NetworkChunkPublisherUpdatePacket;
@ -73,19 +65,16 @@ use pocketmine\network\mcpe\protocol\PacketPool;
use pocketmine\network\mcpe\protocol\PlayerListPacket;
use pocketmine\network\mcpe\protocol\PlayStatusPacket;
use pocketmine\network\mcpe\protocol\ProtocolInfo;
use pocketmine\network\mcpe\protocol\RemoveActorPacket;
use pocketmine\network\mcpe\protocol\serializer\PacketBatch;
use pocketmine\network\mcpe\protocol\serializer\PacketSerializer;
use pocketmine\network\mcpe\protocol\serializer\PacketSerializerContext;
use pocketmine\network\mcpe\protocol\ServerboundPacket;
use pocketmine\network\mcpe\protocol\ServerToClientHandshakePacket;
use pocketmine\network\mcpe\protocol\SetActorDataPacket;
use pocketmine\network\mcpe\protocol\SetDifficultyPacket;
use pocketmine\network\mcpe\protocol\SetPlayerGameTypePacket;
use pocketmine\network\mcpe\protocol\SetSpawnPositionPacket;
use pocketmine\network\mcpe\protocol\SetTimePacket;
use pocketmine\network\mcpe\protocol\SetTitlePacket;
use pocketmine\network\mcpe\protocol\TakeItemActorPacket;
use pocketmine\network\mcpe\protocol\TextPacket;
use pocketmine\network\mcpe\protocol\ToastRequestPacket;
use pocketmine\network\mcpe\protocol\TransferPacket;
@ -97,16 +86,10 @@ use pocketmine\network\mcpe\protocol\types\command\CommandEnum;
use pocketmine\network\mcpe\protocol\types\command\CommandParameter;
use pocketmine\network\mcpe\protocol\types\command\CommandPermissions;
use pocketmine\network\mcpe\protocol\types\DimensionIds;
use pocketmine\network\mcpe\protocol\types\entity\Attribute as NetworkAttribute;
use pocketmine\network\mcpe\protocol\types\entity\MetadataProperty;
use pocketmine\network\mcpe\protocol\types\entity\PropertySyncData;
use pocketmine\network\mcpe\protocol\types\inventory\ContainerIds;
use pocketmine\network\mcpe\protocol\types\inventory\ItemStackWrapper;
use pocketmine\network\mcpe\protocol\types\PlayerListEntry;
use pocketmine\network\mcpe\protocol\types\PlayerPermissions;
use pocketmine\network\mcpe\protocol\UpdateAbilitiesPacket;
use pocketmine\network\mcpe\protocol\UpdateAdventureSettingsPacket;
use pocketmine\network\mcpe\protocol\UpdateAttributesPacket;
use pocketmine\network\NetworkSessionManager;
use pocketmine\network\PacketHandlingException;
use pocketmine\permission\DefaultPermissionNames;
@ -134,7 +117,6 @@ use function hrtime;
use function in_array;
use function intdiv;
use function json_encode;
use function ksort;
use function min;
use function random_bytes;
use function strcasecmp;
@ -144,7 +126,6 @@ use function substr;
use function time;
use function ucfirst;
use const JSON_THROW_ON_ERROR;
use const SORT_NUMERIC;
class NetworkSession{
private const INCOMING_PACKET_BATCH_PER_TICK = 2; //usually max 1 per tick, but transactions may arrive separately
@ -203,6 +184,7 @@ class NetworkSession{
private PacketSerializerContext $packetSerializerContext,
private PacketSender $sender,
private PacketBroadcaster $broadcaster,
private EntityEventBroadcaster $entityEventBroadcaster,
private Compressor $compressor,
private string $ip,
private int $port
@ -275,10 +257,10 @@ class NetworkSession{
$effectManager = $this->player->getEffects();
$effectManager->getEffectAddHooks()->add($effectAddHook = function(EffectInstance $effect, bool $replacesOldEffect) : void{
$this->onEntityEffectAdded($this->player, $effect, $replacesOldEffect);
$this->entityEventBroadcaster->onEntityEffectAdded([$this], $this->player, $effect, $replacesOldEffect);
});
$effectManager->getEffectRemoveHooks()->add($effectRemoveHook = function(EffectInstance $effect) : void{
$this->onEntityEffectRemoved($this->player, $effect);
$this->entityEventBroadcaster->onEntityEffectRemoved([$this], $this->player, $effect);
});
$this->disposeHooks->add(static function() use ($effectManager, $effectAddHook, $effectRemoveHook) : void{
$effectManager->getEffectAddHooks()->remove($effectAddHook);
@ -432,6 +414,12 @@ class NetworkSession{
$timings->startTiming();
try{
$ev = new DataPacketPreReceiveEvent($this, $packet->pid(), $buffer);
$ev->call();
if($ev->isCancelled()){
return;
}
$decodeTimings = Timings::getDecodeDataPacketTimings($packet);
$decodeTimings->startTiming();
try{
@ -449,18 +437,18 @@ class NetworkSession{
$decodeTimings->stopTiming();
}
$handlerTimings = Timings::getHandleDataPacketTimings($packet);
$handlerTimings->startTiming();
try{
//TODO: I'm not sure DataPacketReceiveEvent should be included in the handler timings, but it needs to be
//included for now to ensure the receivePacket timings are counted the way they were before
$ev = new DataPacketReceiveEvent($this, $packet);
$ev->call();
if(!$ev->isCancelled() && ($this->handler === null || !$packet->handle($this->handler))){
$this->logger->debug("Unhandled " . $packet->getName() . ": " . base64_encode($stream->getBuffer()));
$ev = new DataPacketReceiveEvent($this, $packet);
$ev->call();
if(!$ev->isCancelled()){
$handlerTimings = Timings::getHandleDataPacketTimings($packet);
$handlerTimings->startTiming();
try{
if($this->handler === null || !$packet->handle($this->handler)){
$this->logger->debug("Unhandled " . $packet->getName() . ": " . base64_encode($stream->getBuffer()));
}
}finally{
$handlerTimings->stopTiming();
}
}finally{
$handlerTimings->stopTiming();
}
}finally{
$timings->stopTiming();
@ -552,6 +540,8 @@ class NetworkSession{
public function getBroadcaster() : PacketBroadcaster{ return $this->broadcaster; }
public function getEntityEventBroadcaster() : EntityEventBroadcaster{ return $this->entityEventBroadcaster; }
public function getCompressor() : Compressor{
return $this->compressor;
}
@ -849,7 +839,7 @@ class NetworkSession{
}
public function onServerRespawn() : void{
$this->syncAttributes($this->player, $this->player->getAttributeMap()->getAll());
$this->entityEventBroadcaster->syncAttributes([$this], $this->player, $this->player->getAttributeMap()->getAll());
$this->player->sendData(null);
$this->syncAbilities($this->player);
@ -958,41 +948,6 @@ class NetworkSession{
));
}
/**
* @param Attribute[] $attributes
*/
public function syncAttributes(Living $entity, array $attributes) : void{
if(count($attributes) > 0){
$this->sendDataPacket(UpdateAttributesPacket::create($entity->getId(), array_map(function(Attribute $attr) : NetworkAttribute{
return new NetworkAttribute($attr->getId(), $attr->getMinValue(), $attr->getMaxValue(), $attr->getValue(), $attr->getDefaultValue(), []);
}, $attributes), 0));
}
}
/**
* @param MetadataProperty[] $properties
* @phpstan-param array<int, MetadataProperty> $properties
*/
public function syncActorData(Entity $entity, array $properties) : void{
//TODO: HACK! as of 1.18.10, the client responds differently to the same data ordered in different orders - for
//example, sending HEIGHT in the list before FLAGS when unsetting the SWIMMING flag results in a hitbox glitch
ksort($properties, SORT_NUMERIC);
$this->sendDataPacket(SetActorDataPacket::create($entity->getId(), $properties, new PropertySyncData([], []), 0));
}
public function onEntityEffectAdded(Living $entity, EffectInstance $effect, bool $replacesOldEffect) : void{
//TODO: we may need yet another effect <=> ID map in the future depending on protocol changes
$this->sendDataPacket(MobEffectPacket::add($entity->getId(), $replacesOldEffect, EffectIdMap::getInstance()->toId($effect->getType()), $effect->getAmplifier(), $effect->isVisible(), $effect->getDuration()));
}
public function onEntityEffectRemoved(Living $entity, EffectInstance $effect) : void{
$this->sendDataPacket(MobEffectPacket::remove($entity->getId(), EffectIdMap::getInstance()->toId($effect->getType())));
}
public function onEntityRemoved(Entity $entity) : void{
$this->sendDataPacket(RemoveActorPacket::create($entity->getId()));
}
public function syncAvailableCommands() : void{
$commandData = [];
foreach($this->server->getCommandMap()->getCommands() as $name => $command){
@ -1141,36 +1096,6 @@ class NetworkSession{
return $this->invManager;
}
/**
* TODO: expand this to more than just humans
*/
public function onMobMainHandItemChange(Human $mob) : void{
//TODO: we could send zero for slot here because remote players don't need to know which slot was selected
$inv = $mob->getInventory();
$this->sendDataPacket(MobEquipmentPacket::create($mob->getId(), ItemStackWrapper::legacy(TypeConverter::getInstance()->coreItemStackToNet($inv->getItemInHand())), $inv->getHeldItemIndex(), $inv->getHeldItemIndex(), ContainerIds::INVENTORY));
}
public function onMobOffHandItemChange(Human $mob) : void{
$inv = $mob->getOffHandInventory();
$this->sendDataPacket(MobEquipmentPacket::create($mob->getId(), ItemStackWrapper::legacy(TypeConverter::getInstance()->coreItemStackToNet($inv->getItem(0))), 0, 0, ContainerIds::OFFHAND));
}
public function onMobArmorChange(Living $mob) : void{
$inv = $mob->getArmorInventory();
$converter = TypeConverter::getInstance();
$this->sendDataPacket(MobArmorEquipmentPacket::create(
$mob->getId(),
ItemStackWrapper::legacy($converter->coreItemStackToNet($inv->getHelmet())),
ItemStackWrapper::legacy($converter->coreItemStackToNet($inv->getChestplate())),
ItemStackWrapper::legacy($converter->coreItemStackToNet($inv->getLeggings())),
ItemStackWrapper::legacy($converter->coreItemStackToNet($inv->getBoots()))
));
}
public function onPlayerPickUpItem(Player $collector, Entity $pickedUp) : void{
$this->sendDataPacket(TakeItemActorPacket::create($collector->getId(), $pickedUp->getId()));
}
/**
* @param Player[] $players
*/
@ -1214,10 +1139,6 @@ class NetworkSession{
$this->sendDataPacket(SetTitlePacket::setAnimationTimes($fadeIn, $stay, $fadeOut));
}
public function onEmote(Human $from, string $emoteId) : void{
$this->sendDataPacket(EmotePacket::create($from->getId(), $emoteId, EmotePacket::FLAG_SERVER));
}
public function onToastNotification(string $title, string $body) : void{
$this->sendDataPacket(ToastRequestPacket::create($title, $body));
}
@ -1257,7 +1178,7 @@ class NetworkSession{
$this->player->doChunkRequests();
$dirtyAttributes = $this->player->getAttributeMap()->needSend();
$this->syncAttributes($this->player, $dirtyAttributes);
$this->entityEventBroadcaster->syncAttributes([$this], $this->player, $dirtyAttributes);
foreach($dirtyAttributes as $attribute){
//TODO: we might need to send these to other players in the future
//if that happens, this will need to become more complex than a flag on the attribute itself

View File

@ -0,0 +1,143 @@
<?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 PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\network\mcpe;
use pocketmine\data\bedrock\EffectIdMap;
use pocketmine\entity\Attribute;
use pocketmine\entity\effect\EffectInstance;
use pocketmine\entity\Entity;
use pocketmine\entity\Human;
use pocketmine\entity\Living;
use pocketmine\network\mcpe\convert\TypeConverter;
use pocketmine\network\mcpe\protocol\ClientboundPacket;
use pocketmine\network\mcpe\protocol\EmotePacket;
use pocketmine\network\mcpe\protocol\MobArmorEquipmentPacket;
use pocketmine\network\mcpe\protocol\MobEffectPacket;
use pocketmine\network\mcpe\protocol\MobEquipmentPacket;
use pocketmine\network\mcpe\protocol\RemoveActorPacket;
use pocketmine\network\mcpe\protocol\SetActorDataPacket;
use pocketmine\network\mcpe\protocol\TakeItemActorPacket;
use pocketmine\network\mcpe\protocol\types\entity\Attribute as NetworkAttribute;
use pocketmine\network\mcpe\protocol\types\entity\PropertySyncData;
use pocketmine\network\mcpe\protocol\types\inventory\ContainerIds;
use pocketmine\network\mcpe\protocol\types\inventory\ItemStackWrapper;
use pocketmine\network\mcpe\protocol\UpdateAttributesPacket;
use function array_map;
use function count;
use function ksort;
use const SORT_NUMERIC;
final class StandardEntityEventBroadcaster implements EntityEventBroadcaster{
public function __construct(
private StandardPacketBroadcaster $broadcaster
){}
/**
* @param NetworkSession[] $recipients
*/
private function sendDataPacket(array $recipients, ClientboundPacket $packet) : void{
$this->broadcaster->broadcastPackets($recipients, [$packet]);
}
public function syncAttributes(array $recipients, Living $entity, array $attributes) : void{
if(count($attributes) > 0){
$this->sendDataPacket($recipients, UpdateAttributesPacket::create(
$entity->getId(),
array_map(fn(Attribute $attr) => new NetworkAttribute($attr->getId(), $attr->getMinValue(), $attr->getMaxValue(), $attr->getValue(), $attr->getDefaultValue(), []), $attributes),
0
));
}
}
public function syncActorData(array $recipients, Entity $entity, array $properties) : void{
//TODO: HACK! as of 1.18.10, the client responds differently to the same data ordered in different orders - for
//example, sending HEIGHT in the list before FLAGS when unsetting the SWIMMING flag results in a hitbox glitch
ksort($properties, SORT_NUMERIC);
$this->sendDataPacket($recipients, SetActorDataPacket::create($entity->getId(), $properties, new PropertySyncData([], []), 0));
}
public function onEntityEffectAdded(array $recipients, Living $entity, EffectInstance $effect, bool $replacesOldEffect) : void{
//TODO: we may need yet another effect <=> ID map in the future depending on protocol changes
$this->sendDataPacket($recipients, MobEffectPacket::add(
$entity->getId(),
$replacesOldEffect,
EffectIdMap::getInstance()->toId($effect->getType()),
$effect->getAmplifier(),
$effect->isVisible(),
$effect->getDuration()
));
}
public function onEntityEffectRemoved(array $recipients, Living $entity, EffectInstance $effect) : void{
$this->sendDataPacket($recipients, MobEffectPacket::remove($entity->getId(), EffectIdMap::getInstance()->toId($effect->getType())));
}
public function onEntityRemoved(array $recipients, Entity $entity) : void{
$this->sendDataPacket($recipients, RemoveActorPacket::create($entity->getId()));
}
public function onMobMainHandItemChange(array $recipients, Human $mob) : void{
//TODO: we could send zero for slot here because remote players don't need to know which slot was selected
$inv = $mob->getInventory();
$this->sendDataPacket($recipients, MobEquipmentPacket::create(
$mob->getId(),
ItemStackWrapper::legacy(TypeConverter::getInstance()->coreItemStackToNet($inv->getItemInHand())),
$inv->getHeldItemIndex(),
$inv->getHeldItemIndex(),
ContainerIds::INVENTORY
));
}
public function onMobOffHandItemChange(array $recipients, Human $mob) : void{
$inv = $mob->getOffHandInventory();
$this->sendDataPacket($recipients, MobEquipmentPacket::create(
$mob->getId(),
ItemStackWrapper::legacy(TypeConverter::getInstance()->coreItemStackToNet($inv->getItem(0))),
0,
0,
ContainerIds::OFFHAND
));
}
public function onMobArmorChange(array $recipients, Living $mob) : void{
$inv = $mob->getArmorInventory();
$converter = TypeConverter::getInstance();
$this->sendDataPacket($recipients, MobArmorEquipmentPacket::create(
$mob->getId(),
ItemStackWrapper::legacy($converter->coreItemStackToNet($inv->getHelmet())),
ItemStackWrapper::legacy($converter->coreItemStackToNet($inv->getChestplate())),
ItemStackWrapper::legacy($converter->coreItemStackToNet($inv->getLeggings())),
ItemStackWrapper::legacy($converter->coreItemStackToNet($inv->getBoots()))
));
}
public function onPickUpItem(array $recipients, Entity $collector, Entity $pickedUp) : void{
$this->sendDataPacket($recipients, TakeItemActorPacket::create($collector->getId(), $pickedUp->getId()));
}
public function onEmote(array $recipients, Human $from, string $emoteId) : void{
$this->sendDataPacket($recipients, EmotePacket::create($from->getId(), $emoteId, EmotePacket::FLAG_SERVER));
}
}

View File

@ -30,6 +30,7 @@ use pocketmine\Server;
use pocketmine\timings\Timings;
use pocketmine\utils\BinaryStream;
use function count;
use function log;
use function spl_object_id;
use function strlen;
@ -60,7 +61,8 @@ final class StandardPacketBroadcaster implements PacketBroadcaster{
$packetBuffers = [];
foreach($packets as $packet){
$buffer = NetworkSession::encodePacketTimed(PacketSerializer::encoder($this->protocolContext), $packet);
$totalLength += strlen($buffer);
//varint length prefix + packet buffer
$totalLength += (((int) log(strlen($buffer), 128)) + 1) + strlen($buffer);
$packetBuffers[] = $buffer;
}

View File

@ -114,7 +114,7 @@ class PreSpawnPacketHandler extends PacketHandler{
$this->session->sendDataPacket(StaticPacketCache::getInstance()->getBiomeDefs());
$this->session->getLogger()->debug("Sending attributes");
$this->session->syncAttributes($this->player, $this->player->getAttributeMap()->getAll());
$this->session->getEntityEventBroadcaster()->syncAttributes([$this->session], $this->player, $this->player->getAttributeMap()->getAll());
$this->session->getLogger()->debug("Sending available commands");
$this->session->syncAvailableCommands();
@ -125,7 +125,7 @@ class PreSpawnPacketHandler extends PacketHandler{
$this->session->getLogger()->debug("Sending effects");
foreach($this->player->getEffects()->all() as $effect){
$this->session->onEntityEffectAdded($this->player, $effect, false);
$this->session->getEntityEventBroadcaster()->onEntityEffectAdded([$this->session], $this->player, $effect, false);
}
$this->session->getLogger()->debug("Sending actor metadata");

View File

@ -26,14 +26,13 @@ namespace pocketmine\network\mcpe\raklib;
use pocketmine\lang\KnownTranslationFactory;
use pocketmine\network\AdvancedNetworkInterface;
use pocketmine\network\mcpe\compression\ZlibCompressor;
use pocketmine\network\mcpe\convert\GlobalItemTypeDictionary;
use pocketmine\network\mcpe\convert\TypeConverter;
use pocketmine\network\mcpe\EntityEventBroadcaster;
use pocketmine\network\mcpe\NetworkSession;
use pocketmine\network\mcpe\PacketBroadcaster;
use pocketmine\network\mcpe\protocol\PacketPool;
use pocketmine\network\mcpe\protocol\ProtocolInfo;
use pocketmine\network\mcpe\protocol\serializer\PacketSerializerContext;
use pocketmine\network\mcpe\StandardPacketBroadcaster;
use pocketmine\network\Network;
use pocketmine\network\NetworkInterfaceStartException;
use pocketmine\network\PacketHandlingException;
@ -80,11 +79,16 @@ class RakLibInterface implements ServerEventListener, AdvancedNetworkInterface{
private SleeperNotifier $sleeper;
private PacketBroadcaster $broadcaster;
private PacketBroadcaster $packetBroadcaster;
private EntityEventBroadcaster $entityEventBroadcaster;
private PacketSerializerContext $packetSerializerContext;
public function __construct(Server $server, string $ip, int $port, bool $ipV6){
public function __construct(Server $server, string $ip, int $port, bool $ipV6, PacketBroadcaster $packetBroadcaster, EntityEventBroadcaster $entityEventBroadcaster, PacketSerializerContext $packetSerializerContext){
$this->server = $server;
$this->packetBroadcaster = $packetBroadcaster;
$this->packetSerializerContext = $packetSerializerContext;
$this->entityEventBroadcaster = $entityEventBroadcaster;
$this->rakServerId = mt_rand(0, PHP_INT_MAX);
$this->sleeper = new SleeperNotifier();
@ -110,9 +114,6 @@ class RakLibInterface implements ServerEventListener, AdvancedNetworkInterface{
$this->interface = new UserToRakLibThreadMessageSender(
new PthreadsChannelWriter($mainToThreadBuffer)
);
$this->packetSerializerContext = new PacketSerializerContext(GlobalItemTypeDictionary::getInstance()->getDictionary());
$this->broadcaster = new StandardPacketBroadcaster($this->server, $this->packetSerializerContext);
}
public function start() : void{
@ -179,7 +180,8 @@ class RakLibInterface implements ServerEventListener, AdvancedNetworkInterface{
PacketPool::getInstance(),
$this->packetSerializerContext,
new RakLibPacketSender($sessionId, $this),
$this->broadcaster,
$this->packetBroadcaster,
$this->entityEventBroadcaster,
ZlibCompressor::getInstance(), //TODO: this shouldn't be hardcoded, but we might need the RakNet protocol version to select it
$address,
$port

View File

@ -66,6 +66,7 @@ use pocketmine\math\Vector3;
use pocketmine\nbt\tag\IntTag;
use pocketmine\nbt\tag\StringTag;
use pocketmine\network\mcpe\convert\RuntimeBlockMapping;
use pocketmine\network\mcpe\NetworkBroadcastUtils;
use pocketmine\network\mcpe\protocol\BlockActorDataPacket;
use pocketmine\network\mcpe\protocol\ClientboundPacket;
use pocketmine\network\mcpe\protocol\types\BlockPosition;
@ -689,7 +690,7 @@ class World implements ChunkManager{
$this->broadcastPacketToViewers($pos, $e);
}
}else{
$this->server->broadcastPackets($this->filterViewersForPosition($pos, $players), $pk);
NetworkBroadcastUtils::broadcastPackets($this->filterViewersForPosition($pos, $players), $pk);
}
}
}
@ -715,7 +716,7 @@ class World implements ChunkManager{
$this->broadcastPacketToViewers($pos, $e);
}
}else{
$this->server->broadcastPackets($this->filterViewersForPosition($pos, $ev->getRecipients()), $pk);
NetworkBroadcastUtils::broadcastPackets($this->filterViewersForPosition($pos, $ev->getRecipients()), $pk);
}
}
}
@ -1029,7 +1030,7 @@ class World implements ChunkManager{
World::getXZ($index, $chunkX, $chunkZ);
$chunkPlayers = $this->getChunkPlayers($chunkX, $chunkZ);
if(count($chunkPlayers) > 0){
$this->server->broadcastPackets($chunkPlayers, $entries);
NetworkBroadcastUtils::broadcastPackets($chunkPlayers, $entries);
}
}

View File

@ -485,11 +485,6 @@ parameters:
count: 1
path: ../../../src/command/defaults/TimingsCommand.php
-
message: "#^Call to function is_resource\\(\\) with resource will always evaluate to true\\.$#"
count: 2
path: ../../../src/console/ConsoleReader.php
-
message: "#^Parameter \\#1 \\$path of static method pocketmine\\\\utils\\\\Filesystem\\:\\:cleanPath\\(\\) expects string, mixed given\\.$#"
count: 1
@ -645,21 +640,6 @@ parameters:
count: 1
path: ../../../src/network/mcpe/NetworkSession.php
-
message: "#^Parameter \\#1 \\$entity of method pocketmine\\\\network\\\\mcpe\\\\NetworkSession\\:\\:onEntityEffectAdded\\(\\) expects pocketmine\\\\entity\\\\Living, pocketmine\\\\player\\\\Player\\|null given\\.$#"
count: 1
path: ../../../src/network/mcpe/NetworkSession.php
-
message: "#^Parameter \\#1 \\$entity of method pocketmine\\\\network\\\\mcpe\\\\NetworkSession\\:\\:onEntityEffectRemoved\\(\\) expects pocketmine\\\\entity\\\\Living, pocketmine\\\\player\\\\Player\\|null given\\.$#"
count: 1
path: ../../../src/network/mcpe/NetworkSession.php
-
message: "#^Parameter \\#1 \\$entity of method pocketmine\\\\network\\\\mcpe\\\\NetworkSession\\:\\:syncAttributes\\(\\) expects pocketmine\\\\entity\\\\Living, pocketmine\\\\player\\\\Player\\|null given\\.$#"
count: 1
path: ../../../src/network/mcpe/NetworkSession.php
-
message: "#^Parameter \\#1 \\$for of method pocketmine\\\\network\\\\mcpe\\\\NetworkSession\\:\\:syncAbilities\\(\\) expects pocketmine\\\\player\\\\Player, pocketmine\\\\player\\\\Player\\|null given\\.$#"
count: 2
@ -680,6 +660,21 @@ parameters:
count: 1
path: ../../../src/network/mcpe/NetworkSession.php
-
message: "#^Parameter \\#2 \\$entity of method pocketmine\\\\network\\\\mcpe\\\\EntityEventBroadcaster\\:\\:onEntityEffectAdded\\(\\) expects pocketmine\\\\entity\\\\Living, pocketmine\\\\player\\\\Player\\|null given\\.$#"
count: 1
path: ../../../src/network/mcpe/NetworkSession.php
-
message: "#^Parameter \\#2 \\$entity of method pocketmine\\\\network\\\\mcpe\\\\EntityEventBroadcaster\\:\\:onEntityEffectRemoved\\(\\) expects pocketmine\\\\entity\\\\Living, pocketmine\\\\player\\\\Player\\|null given\\.$#"
count: 1
path: ../../../src/network/mcpe/NetworkSession.php
-
message: "#^Parameter \\#2 \\$entity of method pocketmine\\\\network\\\\mcpe\\\\EntityEventBroadcaster\\:\\:syncAttributes\\(\\) expects pocketmine\\\\entity\\\\Living, pocketmine\\\\player\\\\Player\\|null given\\.$#"
count: 1
path: ../../../src/network/mcpe/NetworkSession.php
-
message: "#^Parameter \\#2 \\$player of class pocketmine\\\\network\\\\mcpe\\\\handler\\\\PreSpawnPacketHandler constructor expects pocketmine\\\\player\\\\Player, pocketmine\\\\player\\\\Player\\|null given\\.$#"
count: 1