@minecraft/creator-tools
Version:
Minecraft Creator Tools command line and libraries.
177 lines (176 loc) • 5.57 kB
JavaScript
"use strict";
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
Object.defineProperty(exports, "__esModule", { value: true });
/**
* LRU (Least Recently Used) cache for WorldChunk objects.
*
* Manages memory by evicting least recently used chunks when the cache
* exceeds its maximum size. This enables viewing of very large worlds
* without loading all chunks into memory simultaneously.
*
* When a chunk is evicted, its cached/parsed data is cleared but the
* chunk object itself remains in the world's chunks Map. This allows
* the chunk to be re-parsed on demand from its raw LevelKeyValue data.
*/
class WorldChunkCache {
/** Maximum number of chunks to keep parsed data for */
_maxChunks;
/** Ordered list of chunk keys, oldest first (LRU tracking) */
_accessOrder = [];
/** Set of chunks currently in the cache */
_cachedChunks = new Set();
/** Callback to get a chunk by its key */
_getChunk;
/**
* Create a new chunk cache.
* @param maxChunks Maximum number of chunks to keep parsed data for
*/
constructor(maxChunks = 20000) {
this._maxChunks = maxChunks;
}
/** Get the maximum number of cached chunks */
get maxChunks() {
return this._maxChunks;
}
/** Set the maximum number of cached chunks */
set maxChunks(value) {
this._maxChunks = value;
this._evictIfNeeded();
}
/** Get the current number of cached chunks */
get size() {
return this._cachedChunks.size;
}
/**
* Set the callback to retrieve chunks by key.
* The key format should be "dim_x_z" (e.g., "0_10_-5").
*/
setChunkProvider(provider) {
this._getChunk = provider;
}
/**
* Generate a cache key for a chunk.
*/
static makeKey(dim, x, z) {
return `${dim}_${x}_${z}`;
}
/**
* Parse a cache key back into coordinates.
*/
static parseKey(key) {
const parts = key.split("_");
if (parts.length !== 3)
return undefined;
return {
dim: parseInt(parts[0], 10),
x: parseInt(parts[1], 10),
z: parseInt(parts[2], 10),
};
}
/**
* Record access to a chunk, marking it as recently used.
* Call this whenever a chunk is accessed for rendering or data retrieval.
*/
access(dim, x, z) {
const key = WorldChunkCache.makeKey(dim, x, z);
this.accessByKey(key);
}
/**
* Record access to a chunk by key.
*/
accessByKey(key) {
// Remove from old position if exists
const existingIndex = this._accessOrder.indexOf(key);
if (existingIndex >= 0) {
this._accessOrder.splice(existingIndex, 1);
}
// Add to end (most recently used)
this._accessOrder.push(key);
this._cachedChunks.add(key);
// Evict old chunks if over limit
this._evictIfNeeded();
}
/**
* Evict least recently used chunks if over the limit.
*/
_evictIfNeeded() {
if (this._cachedChunks.size <= this._maxChunks) {
return;
}
// Evict to 80% of max to avoid frequent evictions
const targetSize = Math.floor(this._maxChunks * 0.8);
const chunksToEvict = this._cachedChunks.size - targetSize;
for (let i = 0; i < chunksToEvict && this._accessOrder.length > 0; i++) {
const oldestKey = this._accessOrder.shift();
if (oldestKey) {
this._evictChunk(oldestKey);
}
}
}
/**
* Evict a specific chunk, clearing its cached data.
*/
_evictChunk(key) {
this._cachedChunks.delete(key);
if (this._getChunk) {
const chunk = this._getChunk(key);
if (chunk) {
// Clear cached/parsed data but keep raw LevelKeyValue data
// This allows the chunk to be re-parsed on demand
chunk.clearCachedData();
}
}
}
/**
* Check if a chunk is in the cache (has parsed data available).
*/
isInCache(dim, x, z) {
const key = WorldChunkCache.makeKey(dim, x, z);
return this._cachedChunks.has(key);
}
/**
* Clear all cached chunks.
*/
clear() {
// Clear all cached chunk data
if (this._getChunk) {
for (const key of this._cachedChunks) {
const chunk = this._getChunk(key);
if (chunk) {
chunk.clearCachedData();
}
}
}
this._accessOrder = [];
this._cachedChunks.clear();
}
/**
* Prefetch chunks in a region, loading them into the cache.
* Useful for ensuring a viewport's worth of chunks are available.
*
* @param dim Dimension index
* @param minX Minimum chunk X coordinate
* @param maxX Maximum chunk X coordinate
* @param minZ Minimum chunk Z coordinate
* @param maxZ Maximum chunk Z coordinate
*/
prefetchRegion(dim, minX, maxX, minZ, maxZ) {
for (let x = minX; x <= maxX; x++) {
for (let z = minZ; z <= maxZ; z++) {
this.access(dim, x, z);
}
}
}
/**
* Get statistics about cache usage.
*/
getStats() {
return {
size: this._cachedChunks.size,
maxSize: this._maxChunks,
hitRate: 0, // TODO: Track hit/miss for debugging
};
}
}
exports.default = WorldChunkCache;