43 private static array $instances = [];
49 $worldId = spl_object_id($world);
50 $compressorId = spl_object_id($compressor);
51 if(!isset(self::$instances[$worldId])){
52 self::$instances[$worldId] = [];
54 foreach(self::$instances[$worldId] as $cache){
57 unset(self::$instances[$worldId]);
58 \GlobalLogger::get()->debug(
"Destroyed chunk packet caches for world#$worldId");
61 if(!isset(self::$instances[$worldId][$compressorId])){
62 \GlobalLogger::get()->debug(
"Created new chunk packet cache (world#$worldId, compressor#$compressorId)");
63 self::$instances[$worldId][$compressorId] =
new self($world, $compressor);
65 return self::$instances[$worldId][$compressorId];
68 public static function pruneCaches() : void{
69 foreach(self::$instances as $compressorMap){
70 foreach($compressorMap as $chunkCache){
71 foreach($chunkCache->caches as $chunkHash => $promise){
72 if($promise->hasResult()){
74 unset($chunkCache->caches[$chunkHash]);
85 private array $caches = [];
87 private int $hits = 0;
88 private int $misses = 0;
90 private function __construct(
92 private Compressor $compressor
101 $this->world->registerChunkListener($this, $chunkX, $chunkZ);
102 $chunk = $this->world->getChunk($chunkX, $chunkZ);
104 throw new \InvalidArgumentException(
"Cannot request an unloaded chunk");
106 $chunkHash = World::chunkHash($chunkX, $chunkZ);
108 if(isset($this->caches[$chunkHash])){
110 return $this->caches[$chunkHash];
115 $this->world->timings->syncChunkSendPrepare->startTiming();
119 $this->world->getServer()->getAsyncPool()->submitTask(
123 DimensionIds::OVERWORLD,
125 $this->caches[$chunkHash],
130 return $this->caches[$chunkHash];
132 $this->world->timings->syncChunkSendPrepare->stopTiming();
136 private function destroy(
int $chunkX,
int $chunkZ) : bool{
137 $chunkHash = World::chunkHash($chunkX, $chunkZ);
138 $existing = $this->caches[$chunkHash] ??
null;
139 unset($this->caches[$chunkHash]);
141 return $existing !==
null;
147 private function destroyOrRestart(
int $chunkX,
int $chunkZ) : void{
148 $chunkPosHash = World::chunkHash($chunkX, $chunkZ);
149 $cache = $this->caches[$chunkPosHash] ??
null;
151 if(!$cache->hasResult()){
154 unset($this->caches[$chunkPosHash]);
156 $this->request($chunkX, $chunkZ)->onResolve(...$cache->getResolveCallbacks());
159 $this->destroy($chunkX, $chunkZ);
164 use ChunkListenerNoOpTrait {
166 onChunkChanged as
private;
167 onBlockChanged as
private;
168 onChunkUnloaded as
private;
175 $this->destroyOrRestart($chunkX, $chunkZ);
184 $this->destroy($block->getFloorX() >>
Chunk::COORD_BIT_SIZE, $block->getFloorZ() >>
Chunk::COORD_BIT_SIZE);
191 $this->destroy($chunkX, $chunkZ);
192 $this->world->unregisterChunkListener($this, $chunkX, $chunkZ);
201 foreach($this->caches as $cache){
202 if($cache->hasResult()){
203 $result += strlen($cache->getResult());
213 $total = $this->hits + $this->misses;
214 return $total > 0 ? $this->hits / $total : 0.0;