playcanvas
Version:
PlayCanvas WebGL game engine
214 lines (212 loc) • 6.57 kB
JavaScript
class BundleRegistry {
_onAssetAdd(asset) {
if (asset.type === 'bundle') {
this._idToBundle.set(asset.id, asset);
this._assets.on("load:start:" + asset.id, this._onBundleLoadStart, this);
this._assets.on("load:" + asset.id, this._onBundleLoad, this);
this._assets.on("error:" + asset.id, this._onBundleError, this);
var assetIds = asset.data.assets;
for(var i = 0; i < assetIds.length; i++){
this._indexAssetInBundle(assetIds[i], asset);
}
} else {
if (this._assetToBundles.has(asset.id)) {
this._indexAssetFileUrls(asset);
}
}
}
_unbindAssetEvents(id) {
this._assets.off("load:start:" + id, this._onBundleLoadStart, this);
this._assets.off("load:" + id, this._onBundleLoad, this);
this._assets.off("error:" + id, this._onBundleError, this);
}
_indexAssetInBundle(id, bundle) {
var bundles = this._assetToBundles.get(id);
if (!bundles) {
bundles = new Set();
this._assetToBundles.set(id, bundles);
}
bundles.add(bundle);
var asset = this._assets.get(id);
if (asset) this._indexAssetFileUrls(asset);
}
_indexAssetFileUrls(asset) {
var urls = this._getAssetFileUrls(asset);
if (!urls) return;
for(var i = 0; i < urls.length; i++){
var bundles = this._assetToBundles.get(asset.id);
if (!bundles) continue;
this._urlsToBundles.set(urls[i], bundles);
}
}
_getAssetFileUrls(asset) {
var url = asset.getFileUrl();
if (!url) return null;
url = url.split('?')[0];
var urls = [
url
];
if (asset.type === 'font') {
var numFiles = asset.data.info.maps.length;
for(var i = 1; i < numFiles; i++){
urls.push(url.replace('.png', "" + i + ".png"));
}
}
return urls;
}
_onAssetRemove(asset) {
if (asset.type === 'bundle') {
this._idToBundle.delete(asset.id);
this._unbindAssetEvents(asset.id);
var assetIds = asset.data.assets;
for(var i = 0; i < assetIds.length; i++){
var bundles = this._assetToBundles.get(assetIds[i]);
if (!bundles) continue;
bundles.delete(asset);
if (bundles.size === 0) {
this._assetToBundles.delete(assetIds[i]);
for (var [url, otherBundles] of this._urlsToBundles){
if (otherBundles !== bundles) {
continue;
}
this._urlsToBundles.delete(url);
}
}
}
this._onBundleError("Bundle " + asset.id + " was removed");
} else {
var bundles1 = this._assetToBundles.get(asset.id);
if (!bundles1) return;
this._assetToBundles.delete(asset.id);
var urls = this._getAssetFileUrls(asset);
if (!urls) return;
for(var i1 = 0; i1 < urls.length; i1++){
this._urlsToBundles.delete(urls[i1]);
}
}
}
_onBundleLoadStart(asset) {
asset.resource.on('add', (url, data)=>{
var callbacks = this._fileRequests.get(url);
if (!callbacks) return;
for(var i = 0; i < callbacks.length; i++){
callbacks[i](null, data);
}
this._fileRequests.delete(url);
});
}
_onBundleLoad(asset) {
if (!asset.resource) {
this._onBundleError("Bundle " + asset.id + " failed to load");
return;
}
if (!this._fileRequests) {
return;
}
for (var [url, requests] of this._fileRequests){
var bundles = this._urlsToBundles.get(url);
if (!bundles || !bundles.has(asset)) continue;
var decodedUrl = decodeURIComponent(url);
var err = void 0, data = void 0;
if (asset.resource.has(decodedUrl)) {
data = asset.resource.get(decodedUrl);
} else if (asset.resource.loaded) {
err = "Bundle " + asset.id + " does not contain URL " + url;
} else {
continue;
}
for(var i = 0; i < requests.length; i++){
requests[i](err, err || data);
}
this._fileRequests.delete(url);
}
}
_onBundleError(err) {
for (var [url, requests] of this._fileRequests){
var bundle = this._findLoadedOrLoadingBundleForUrl(url);
if (!bundle) {
for(var i = 0; i < requests.length; i++){
requests[i](err);
}
this._fileRequests.delete(url);
}
}
}
_findLoadedOrLoadingBundleForUrl(url) {
var bundles = this._urlsToBundles.get(url);
if (!bundles) return null;
var candidate = null;
for (var bundle of bundles){
if (bundle.loaded && bundle.resource) {
return bundle;
} else if (bundle.loading) {
candidate = bundle;
}
}
return candidate;
}
listBundlesForAsset(asset) {
var bundles = this._assetToBundles.get(asset.id);
if (bundles) return Array.from(bundles);
return null;
}
list() {
return Array.from(this._idToBundle.values());
}
hasUrl(url) {
return this._urlsToBundles.has(url);
}
urlIsLoadedOrLoading(url) {
return !!this._findLoadedOrLoadingBundleForUrl(url);
}
loadUrl(url, callback) {
var bundle = this._findLoadedOrLoadingBundleForUrl(url);
if (!bundle) {
callback("URL " + url + " not found in any bundles");
return;
}
if (bundle.loaded) {
var decodedUrl = decodeURIComponent(url);
if (bundle.resource.has(decodedUrl)) {
callback(null, bundle.resource.get(decodedUrl));
return;
} else if (bundle.resource.loaded) {
callback("Bundle " + bundle.id + " does not contain URL " + url);
return;
}
}
var callbacks = this._fileRequests.get(url);
if (!callbacks) {
callbacks = [];
this._fileRequests.set(url, callbacks);
}
callbacks.push(callback);
}
destroy() {
this._assets.off('add', this._onAssetAdd, this);
this._assets.off('remove', this._onAssetRemove, this);
for (var id of this._idToBundle.keys()){
this._unbindAssetEvents(id);
}
this._assets = null;
this._idToBundle.clear();
this._idToBundle = null;
this._assetToBundles.clear();
this._assetToBundles = null;
this._urlsToBundles.clear();
this._urlsToBundles = null;
this._fileRequests.clear();
this._fileRequests = null;
}
constructor(assets){
this._idToBundle = new Map();
this._assetToBundles = new Map();
this._urlsToBundles = new Map();
this._fileRequests = new Map();
this._assets = assets;
this._assets.bundles = this;
this._assets.on('add', this._onAssetAdd, this);
this._assets.on('remove', this._onAssetRemove, this);
}
}
export { BundleRegistry };