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

This reverts commit b172c93e45e60ee3dbfd8a2efbede60b894673a3.

I made a significant mistake with this change: the scaling factor of
batch-by-chunk is O(nSendBytes), while the scaling factor of sending
directly to players is O(nSendBytes * nActivePlayers). It seems like the
real problem is that this system isn't getting enough usage.

While it does reduce compression efficiency in some cases, it falls back
to letting the sessions do individual compression when the amount of
data is less than 256 bytes anyway (compression-threshold in
pocketmine.yml).

My motivation for scrapping this system was to reduce the broadcast
system's complexity to make it easier to thread the living shit out of
compression, but it seems like this change was a step in the wrong
direction for performance.

A few steps can be taken to improve the usefulness of this system (and
also improve output bandwidth):
- Make general entity updates use this system. Movement and velocity
  already kinda used this system, but crucially, players did not,
  because we couldn't prevent the player from receiving its own movement
  updates if we did that, which caused all kinds of problems.
  - Therefore, we need to reintroduce static "self" entity IDs, like we
    had in the shoghi days when entity ID 0 referred to the "self"
    player.
  - However, since entity ID 0 has a variety of interesting bugs since
    it usually refers to "no entity" in MCPE, it would be better to use
    1 (or 2, like MiNET does).
  - The fixed ID used should be close to zero to maximize varint
    encoding efficiency.
  - We assumed that changes to player's position and velocity would be
    ignored by the client. This assumption depends on the client and
    could be broken at any time, so it's best not to rely on it.
- Make block updates use this system (when chunk updates are not sent).
  Currently, block updates use a separate mechanism which creates a
  second batch for every active chunk, which wastes CPU, and decreases
  bandwidth efficiency on multiple fronts (reduced compression
  efficiency, more cross-thread interactions, more bytes wasted on
  RakNet packet headers).
This commit is contained in:
Dylan K. Taylor 2020-10-11 14:55:54 +01:00
parent 2e3940e8f5
commit bd3bf3d0ce

View File

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