mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-09-06 09:56:06 +00:00
First look at shared EntityEventBroadcaster,
this improves performance in PvP servers and other areas where lots of players or entities exist in one space. fixes #5622
This commit is contained in:
@ -23,12 +23,7 @@ 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\DataPacketReceiveEvent;
|
||||
use pocketmine\event\server\DataPacketSendEvent;
|
||||
@ -61,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 +64,16 @@ use pocketmine\network\mcpe\protocol\PacketDecodeException;
|
||||
use pocketmine\network\mcpe\protocol\PacketPool;
|
||||
use pocketmine\network\mcpe\protocol\PlayerListPacket;
|
||||
use pocketmine\network\mcpe\protocol\PlayStatusPacket;
|
||||
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 +85,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 +116,6 @@ use function hrtime;
|
||||
use function in_array;
|
||||
use function intdiv;
|
||||
use function json_encode;
|
||||
use function ksort;
|
||||
use function min;
|
||||
use function strcasecmp;
|
||||
use function strlen;
|
||||
@ -143,7 +124,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
|
||||
@ -202,6 +182,7 @@ class NetworkSession{
|
||||
private PacketSerializerContext $packetSerializerContext,
|
||||
private PacketSender $sender,
|
||||
private PacketBroadcaster $broadcaster,
|
||||
private EntityEventBroadcaster $entityEventBroadcaster,
|
||||
private Compressor $compressor,
|
||||
private string $ip,
|
||||
private int $port
|
||||
@ -223,6 +204,7 @@ class NetworkSession{
|
||||
|
||||
$this->manager->add($this);
|
||||
$this->logger->info("Session opened");
|
||||
$this->entityEventBroadcaster = $entityEventBroadcaster;
|
||||
}
|
||||
|
||||
private function getLogPrefix() : string{
|
||||
@ -273,10 +255,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);
|
||||
@ -547,6 +529,8 @@ class NetworkSession{
|
||||
|
||||
public function getBroadcaster() : PacketBroadcaster{ return $this->broadcaster; }
|
||||
|
||||
public function getEntityEventBroadcaster() : EntityEventBroadcaster{ return $this->entityEventBroadcaster; }
|
||||
|
||||
public function getCompressor() : Compressor{
|
||||
return $this->compressor;
|
||||
}
|
||||
@ -817,7 +801,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);
|
||||
@ -926,41 +910,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){
|
||||
@ -1096,36 +1045,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
|
||||
*/
|
||||
@ -1169,10 +1088,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));
|
||||
}
|
||||
@ -1212,7 +1127,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
|
||||
|
Reference in New Issue
Block a user