World: do not group broadcasted packets by chunk, broadcast directly instead

Grouping packets to batch by chunk instead of by player reduces bandwidth efficiency, because the number of active chunks is almost always larger than the number of active players.
With the old mechanism, a batch of packets for each active chunk (which could be dozens, or hundreds... or thousands) would be created once, and then sent to many players. This makes the compression load factor O(nActiveChunks). Broadcasting directly is simpler and changes the load factor to O(nActivePlayers), which usually means a smaller number of larger batches are created, achieving better compression ratios for approximately the same cost (the same amount of data is being compressed, just in a different way).
This commit is contained in:
Dylan K. Taylor 2020-10-06 17:27:17 +01:00
parent 78bddac823
commit b172c93e45

View File

@ -172,9 +172,6 @@ class World implements ChunkManager{
/** @var Player[][] */ /** @var Player[][] */
private $playerChunkListeners = []; private $playerChunkListeners = [];
/** @var ClientboundPacket[][] */
private $chunkPackets = [];
/** @var float[] */ /** @var float[] */
private $unloadQueue = []; private $unloadQueue = [];
@ -525,11 +522,7 @@ class World implements ChunkManager{
* Broadcasts a packet to every player who has the target position within their view distance. * Broadcasts a packet to every player who has the target position within their view distance.
*/ */
public function broadcastPacketToViewers(Vector3 $pos, ClientboundPacket $packet) : void{ public function broadcastPacketToViewers(Vector3 $pos, ClientboundPacket $packet) : void{
if(!isset($this->chunkPackets[$index = World::chunkHash($pos->getFloorX() >> 4, $pos->getFloorZ() >> 4)])){ $this->server->broadcastPackets($this->getChunkPlayers($pos->getFloorX() >> 4, $pos->getFloorZ() >> 4), [$packet]);
$this->chunkPackets[$index] = [$packet];
}else{
$this->chunkPackets[$index][] = $packet;
}
} }
public function registerChunkLoader(ChunkLoader $loader, int $chunkX, int $chunkZ, bool $autoLoad = true) : void{ public function registerChunkLoader(ChunkLoader $loader, int $chunkX, int $chunkZ, bool $autoLoad = true) : void{
@ -775,16 +768,6 @@ class World implements ChunkManager{
if($this->sleepTicks > 0 and --$this->sleepTicks <= 0){ if($this->sleepTicks > 0 and --$this->sleepTicks <= 0){
$this->checkSleep(); $this->checkSleep();
} }
foreach($this->chunkPackets as $index => $entries){
World::getXZ($index, $chunkX, $chunkZ);
$chunkPlayers = $this->getChunkPlayers($chunkX, $chunkZ);
if(count($chunkPlayers) > 0){
$this->server->broadcastPackets($chunkPlayers, $entries);
}
}
$this->chunkPackets = [];
} }
public function checkSleep() : void{ public function checkSleep() : void{