67 lines
2.3 KiB
JavaScript
67 lines
2.3 KiB
JavaScript
// cache.js
|
|
|
|
export class Cache {
|
|
constructor(root, onResolve) {
|
|
this.root = root;
|
|
this.onResolve = onResolve || (() => {
|
|
});
|
|
|
|
this.handlers = new Map();
|
|
this.promises = new Map();
|
|
this.data = new Map();
|
|
}
|
|
|
|
register(kind, handler) {
|
|
this.handlers.set(kind, handler);
|
|
}
|
|
|
|
// Used by internal loaders (like models loading parent models)
|
|
getAsync(id, kind) {
|
|
this.getSync(id, kind); // Triggers the load if it hasn't started
|
|
|
|
const [namespace, resource] = id.includes(':') ? id.split(':', 2) : ["minecraft", id];
|
|
const key = `${kind}:${namespace}:${resource}`;
|
|
|
|
if (this.promises.has(key)) {
|
|
return this.promises.get(key);
|
|
}
|
|
|
|
return Promise.resolve(this.data.get(key));
|
|
}
|
|
|
|
// Used by the Engine for immediate, non-blocking rendering
|
|
getSync(id, kind) {
|
|
const [namespace, resource] = id.includes(':') ? id.split(':', 2) : ["minecraft", id];
|
|
const normalizedId = `${namespace}:${resource}`;
|
|
const key = `${kind}:${normalizedId}`;
|
|
const url = `${this.root}/${namespace}/${kind}/${resource}`;
|
|
|
|
// 1. If we already have the real data, return it instantly
|
|
if (this.data.has(key)) return this.data.get(key);
|
|
|
|
// 2. If we haven't even started loading it yet, kick off the fetch
|
|
if (!this.promises.has(key)) {
|
|
const handler = this.handlers.get(kind);
|
|
if (!handler) throw new Error(`No handler registered for resource kind: ${kind}`);
|
|
|
|
if (handler.prepare) handler.prepare(this, normalizedId, url);
|
|
|
|
const promise = handler.process(this, normalizedId, url).then(result => {
|
|
this.data.set(key, result);
|
|
this.onResolve(); // Ping the engine to re-render!
|
|
return result;
|
|
}).catch(err => {
|
|
console.warn(`Failed to load ${key}:`, err);
|
|
const fallback = handler.getFallback(normalizedId);
|
|
this.data.set(key, fallback);
|
|
this.onResolve();
|
|
return fallback;
|
|
});
|
|
|
|
this.promises.set(key, promise);
|
|
}
|
|
|
|
// 3. Always return the synchronous fallback while the promise resolves in the background
|
|
return this.handlers.get(kind).getFallback(normalizedId);
|
|
}
|
|
} |