44    private static array $instances = [];
 
   50        $worldId = spl_object_id($world);
 
   51        $compressorId = spl_object_id($compressor);
 
   52        if(!isset(self::$instances[$worldId])){
 
   53            self::$instances[$worldId] = [];
 
   55                foreach(self::$instances[$worldId] as $cache){
 
   58                unset(self::$instances[$worldId]);
 
   59                \GlobalLogger::get()->debug(
"Destroyed chunk packet caches for world#$worldId");
 
   62        if(!isset(self::$instances[$worldId][$compressorId])){
 
   63            \GlobalLogger::get()->debug(
"Created new chunk packet cache (world#$worldId, compressor#$compressorId)");
 
   64            self::$instances[$worldId][$compressorId] = 
new self($world, $compressor);
 
   66        return self::$instances[$worldId][$compressorId];
 
 
   69    public static function pruneCaches() : void{
 
   70        foreach(self::$instances as $compressorMap){
 
   71            foreach($compressorMap as $chunkCache){
 
   72                foreach($chunkCache->caches as $chunkHash => $promise){
 
   73                    if(is_string($promise)){
 
   75                        unset($chunkCache->caches[$chunkHash]);
 
   86    private array $caches = [];
 
   88    private int $hits = 0;
 
   89    private int $misses = 0;
 
   94    private function __construct(
 
   96        private Compressor $compressor,
 
   97        private int $dimensionId = DimensionIds::OVERWORLD
 
  100    private function prepareChunkAsync(
int $chunkX, 
int $chunkZ, 
int $chunkHash) : CompressBatchPromise{
 
  101        $this->world->registerChunkListener($this, $chunkX, $chunkZ);
 
  102        $chunk = $this->world->getChunk($chunkX, $chunkZ);
 
  104            throw new \InvalidArgumentException(
"Cannot request an unloaded chunk");
 
  108        $this->world->timings->syncChunkSendPrepare->startTiming();
 
  110            $promise = 
new CompressBatchPromise();
 
  112            $this->world->getServer()->getAsyncPool()->submitTask(
 
  113                new ChunkRequestTask(
 
  122            $this->caches[$chunkHash] = $promise;
 
  123            $promise->onResolve(
function(CompressBatchPromise $promise) use ($chunkHash) : 
void{
 
  125                if(($this->caches[$chunkHash] ?? 
null) === $promise){
 
  126                    $this->caches[$chunkHash] = $promise->getResult();
 
  132            $this->world->timings->syncChunkSendPrepare->stopTiming();
 
  142        $chunkHash = 
World::chunkHash($chunkX, $chunkZ);
 
  143        if(isset($this->caches[$chunkHash])){
 
  145            return $this->caches[$chunkHash];
 
  148        return $this->prepareChunkAsync($chunkX, $chunkZ, $chunkHash);
 
 
  151    private function destroy(
int $chunkX, 
int $chunkZ) : bool{
 
  152        $chunkHash = 
World::chunkHash($chunkX, $chunkZ);
 
  153        $existing = $this->caches[$chunkHash] ?? 
null;
 
  154        unset($this->caches[$chunkHash]);
 
  156        return $existing !== 
null;
 
  162    private function destroyOrRestart(
int $chunkX, 
int $chunkZ) : void{
 
  163        $chunkPosHash = 
World::chunkHash($chunkX, $chunkZ);
 
  164        $cache = $this->caches[$chunkPosHash] ?? 
null;
 
  166            if(!is_string($cache)){
 
  169                unset($this->caches[$chunkPosHash]);
 
  171                $this->prepareChunkAsync($chunkX, $chunkZ, $chunkPosHash)->onResolve(...$cache->getResolveCallbacks());
 
  174                $this->destroy($chunkX, $chunkZ);
 
  179    use ChunkListenerNoOpTrait {
 
  181        onChunkChanged as 
private;
 
  182        onBlockChanged as 
private;
 
  183        onChunkUnloaded as 
private;
 
  190        $this->destroyOrRestart($chunkX, $chunkZ);
 
 
  199        $this->destroy($block->getFloorX() >> 
Chunk::COORD_BIT_SIZE, $block->getFloorZ() >> 
Chunk::COORD_BIT_SIZE);
 
 
  206        $this->destroy($chunkX, $chunkZ);
 
  207        $this->world->unregisterChunkListener($this, $chunkX, $chunkZ);
 
 
  216        foreach($this->caches as $cache){
 
  217            if(is_string($cache)){
 
  218                $result += strlen($cache);
 
 
  228        $total = $this->hits + $this->misses;
 
  229        return $total > 0 ? $this->hits / $total : 0.0;