blob: f440150a12d0edeb86fd22ba04b360a1ce9a6c24 [file] [log] [blame]
/*******************************************************************************
* Copyright 2011 See AUTHORS file.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
package com.badlogic.gdx.assets;
import java.util.Stack;
import com.badlogic.gdx.Application;
import com.badlogic.gdx.assets.loaders.AssetLoader;
import com.badlogic.gdx.assets.loaders.BitmapFontLoader;
import com.badlogic.gdx.assets.loaders.FileHandleResolver;
import com.badlogic.gdx.assets.loaders.I18NBundleLoader;
import com.badlogic.gdx.assets.loaders.MusicLoader;
import com.badlogic.gdx.assets.loaders.ParticleEffectLoader;
import com.badlogic.gdx.assets.loaders.PixmapLoader;
import com.badlogic.gdx.assets.loaders.SkinLoader;
import com.badlogic.gdx.assets.loaders.SoundLoader;
import com.badlogic.gdx.assets.loaders.TextureAtlasLoader;
import com.badlogic.gdx.assets.loaders.TextureLoader;
import com.badlogic.gdx.assets.loaders.resolvers.InternalFileHandleResolver;
import com.badlogic.gdx.audio.Music;
import com.badlogic.gdx.audio.Sound;
import com.badlogic.gdx.graphics.Pixmap;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.ParticleEffect;
import com.badlogic.gdx.graphics.g2d.PolygonRegion;
import com.badlogic.gdx.graphics.g2d.PolygonRegionLoader;
import com.badlogic.gdx.graphics.g2d.TextureAtlas;
import com.badlogic.gdx.graphics.g3d.Model;
import com.badlogic.gdx.graphics.g3d.loader.G3dModelLoader;
import com.badlogic.gdx.graphics.g3d.loader.ObjLoader;
import com.badlogic.gdx.scenes.scene2d.ui.Skin;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.Disposable;
import com.badlogic.gdx.utils.GdxRuntimeException;
import com.badlogic.gdx.utils.I18NBundle;
import com.badlogic.gdx.utils.JsonReader;
import com.badlogic.gdx.utils.Logger;
import com.badlogic.gdx.utils.ObjectIntMap;
import com.badlogic.gdx.utils.ObjectMap;
import com.badlogic.gdx.utils.ObjectSet;
import com.badlogic.gdx.utils.TimeUtils;
import com.badlogic.gdx.utils.UBJsonReader;
import com.badlogic.gdx.utils.async.AsyncExecutor;
import com.badlogic.gdx.utils.async.ThreadUtils;
import com.badlogic.gdx.utils.reflect.ClassReflection;
/** Loads and stores assets like textures, bitmapfonts, tile maps, sounds, music and so on.
* @author mzechner */
public class AssetManager implements Disposable {
final ObjectMap<Class, ObjectMap<String, RefCountedContainer>> assets = new ObjectMap();
final ObjectMap<String, Class> assetTypes = new ObjectMap();
final ObjectMap<String, Array<String>> assetDependencies = new ObjectMap();
final ObjectSet<String> injected = new ObjectSet();
final ObjectMap<Class, ObjectMap<String, AssetLoader>> loaders = new ObjectMap();
final Array<AssetDescriptor> loadQueue = new Array();
final AsyncExecutor executor;
final Stack<AssetLoadingTask> tasks = new Stack();
AssetErrorListener listener = null;
int loaded = 0;
int toLoad = 0;
final FileHandleResolver resolver;
Logger log = new Logger("AssetManager", Application.LOG_NONE);
/** Creates a new AssetManager with all default loaders. */
public AssetManager () {
this(new InternalFileHandleResolver());
}
/** Creates a new AssetManager with all default loaders. */
public AssetManager (FileHandleResolver resolver) {
this(resolver, true);
}
/** Creates a new AssetManager with optionally all default loaders. If you don't add the default loaders then you do have to
* manually add the loaders you need, including any loaders they might depend on.
* @param defaultLoaders whether to add the default loaders */
public AssetManager (FileHandleResolver resolver, boolean defaultLoaders) {
this.resolver = resolver;
if (defaultLoaders) {
setLoader(BitmapFont.class, new BitmapFontLoader(resolver));
setLoader(Music.class, new MusicLoader(resolver));
setLoader(Pixmap.class, new PixmapLoader(resolver));
setLoader(Sound.class, new SoundLoader(resolver));
setLoader(TextureAtlas.class, new TextureAtlasLoader(resolver));
setLoader(Texture.class, new TextureLoader(resolver));
setLoader(Skin.class, new SkinLoader(resolver));
setLoader(ParticleEffect.class, new ParticleEffectLoader(resolver));
setLoader(com.badlogic.gdx.graphics.g3d.particles.ParticleEffect.class,
new com.badlogic.gdx.graphics.g3d.particles.ParticleEffectLoader(resolver));
setLoader(PolygonRegion.class, new PolygonRegionLoader(resolver));
setLoader(I18NBundle.class, new I18NBundleLoader(resolver));
setLoader(Model.class, ".g3dj", new G3dModelLoader(new JsonReader(), resolver));
setLoader(Model.class, ".g3db", new G3dModelLoader(new UBJsonReader(), resolver));
setLoader(Model.class, ".obj", new ObjLoader(resolver));
}
executor = new AsyncExecutor(1);
}
/** Returns the {@link FileHandleResolver} for which this AssetManager
* was loaded with.
* @return the file handle resolver which this AssetManager uses */
public FileHandleResolver getFileHandleResolver () {
return resolver;
}
/** @param fileName the asset file name
* @return the asset */
public synchronized <T> T get (String fileName) {
Class<T> type = assetTypes.get(fileName);
if (type == null) throw new GdxRuntimeException("Asset not loaded: " + fileName);
ObjectMap<String, RefCountedContainer> assetsByType = assets.get(type);
if (assetsByType == null) throw new GdxRuntimeException("Asset not loaded: " + fileName);
RefCountedContainer assetContainer = assetsByType.get(fileName);
if (assetContainer == null) throw new GdxRuntimeException("Asset not loaded: " + fileName);
T asset = assetContainer.getObject(type);
if (asset == null) throw new GdxRuntimeException("Asset not loaded: " + fileName);
return asset;
}
/** @param fileName the asset file name
* @param type the asset type
* @return the asset */
public synchronized <T> T get (String fileName, Class<T> type) {
ObjectMap<String, RefCountedContainer> assetsByType = assets.get(type);
if (assetsByType == null) throw new GdxRuntimeException("Asset not loaded: " + fileName);
RefCountedContainer assetContainer = assetsByType.get(fileName);
if (assetContainer == null) throw new GdxRuntimeException("Asset not loaded: " + fileName);
T asset = assetContainer.getObject(type);
if (asset == null) throw new GdxRuntimeException("Asset not loaded: " + fileName);
return asset;
}
/** @param type the asset type
* @return all the assets matching the specified type */
public synchronized <T> Array<T> getAll (Class<T> type, Array<T> out) {
ObjectMap<String, RefCountedContainer> assetsByType = assets.get(type);
if (assetsByType != null) {
for (ObjectMap.Entry<String, RefCountedContainer> asset : assetsByType.entries()) {
out.add(asset.value.getObject(type));
}
}
return out;
}
/** @param assetDescriptor the asset descriptor
* @return the asset */
public synchronized <T> T get (AssetDescriptor<T> assetDescriptor) {
return get(assetDescriptor.fileName, assetDescriptor.type);
}
/** Removes the asset and all its dependencies, if they are not used by other assets.
* @param fileName the file name */
public synchronized void unload (String fileName) {
// check if it's currently processed (and the first element in the stack, thus not a dependency)
// and cancel if necessary
if (tasks.size() > 0) {
AssetLoadingTask currAsset = tasks.firstElement();
if (currAsset.assetDesc.fileName.equals(fileName)) {
currAsset.cancel = true;
log.debug("Unload (from tasks): " + fileName);
return;
}
}
// check if it's in the queue
int foundIndex = -1;
for (int i = 0; i < loadQueue.size; i++) {
if (loadQueue.get(i).fileName.equals(fileName)) {
foundIndex = i;
break;
}
}
if (foundIndex != -1) {
toLoad--;
loadQueue.removeIndex(foundIndex);
log.debug("Unload (from queue): " + fileName);
return;
}
// get the asset and its type
Class type = assetTypes.get(fileName);
if (type == null) throw new GdxRuntimeException("Asset not loaded: " + fileName);
RefCountedContainer assetRef = assets.get(type).get(fileName);
// if it is reference counted, decrement ref count and check if we can really get rid of it.
assetRef.decRefCount();
if (assetRef.getRefCount() <= 0) {
log.debug("Unload (dispose): " + fileName);
// if it is disposable dispose it
if (assetRef.getObject(Object.class) instanceof Disposable) ((Disposable)assetRef.getObject(Object.class)).dispose();
// remove the asset from the manager.
assetTypes.remove(fileName);
assets.get(type).remove(fileName);
} else {
log.debug("Unload (decrement): " + fileName);
}
// remove any dependencies (or just decrement their ref count).
Array<String> dependencies = assetDependencies.get(fileName);
if (dependencies != null) {
for (String dependency : dependencies) {
if (isLoaded(dependency)) unload(dependency);
}
}
// remove dependencies if ref count < 0
if (assetRef.getRefCount() <= 0) {
assetDependencies.remove(fileName);
}
}
/** @param asset the asset
* @return whether the asset is contained in this manager */
public synchronized <T> boolean containsAsset (T asset) {
ObjectMap<String, RefCountedContainer> typedAssets = assets.get(asset.getClass());
if (typedAssets == null) return false;
for (String fileName : typedAssets.keys()) {
T otherAsset = (T)typedAssets.get(fileName).getObject(Object.class);
if (otherAsset == asset || asset.equals(otherAsset)) return true;
}
return false;
}
/** @param asset the asset
* @return the filename of the asset or null */
public synchronized <T> String getAssetFileName (T asset) {
for (Class assetType : assets.keys()) {
ObjectMap<String, RefCountedContainer> typedAssets = assets.get(assetType);
for (String fileName : typedAssets.keys()) {
T otherAsset = (T)typedAssets.get(fileName).getObject(Object.class);
if (otherAsset == asset || asset.equals(otherAsset)) return fileName;
}
}
return null;
}
/** @param fileName the file name of the asset
* @return whether the asset is loaded */
public synchronized boolean isLoaded (String fileName) {
if (fileName == null) return false;
return assetTypes.containsKey(fileName);
}
/** @param fileName the file name of the asset
* @return whether the asset is loaded */
public synchronized boolean isLoaded (String fileName, Class type) {
ObjectMap<String, RefCountedContainer> assetsByType = assets.get(type);
if (assetsByType == null) return false;
RefCountedContainer assetContainer = assetsByType.get(fileName);
if (assetContainer == null) return false;
return assetContainer.getObject(type) != null;
}
/** Returns the default loader for the given type
* @param type The type of the loader to get
* @return The loader capable of loading the type, or null if none exists */
public <T> AssetLoader getLoader (final Class<T> type) {
return getLoader(type, null);
}
/** Returns the loader for the given type and the specified filename. If no loader exists for the specific filename, the default
* loader for that type is returned.
* @param type The type of the loader to get
* @param fileName The filename of the asset to get a loader for, or null to get the default loader
* @return The loader capable of loading the type and filename, or null if none exists */
public <T> AssetLoader getLoader (final Class<T> type, final String fileName) {
final ObjectMap<String, AssetLoader> loaders = this.loaders.get(type);
if (loaders == null || loaders.size < 1) return null;
if (fileName == null) return loaders.get("");
AssetLoader result = null;
int l = -1;
for (ObjectMap.Entry<String, AssetLoader> entry : loaders.entries()) {
if (entry.key.length() > l && fileName.endsWith(entry.key)) {
result = entry.value;
l = entry.key.length();
}
}
return result;
}
/** Adds the given asset to the loading queue of the AssetManager.
* @param fileName the file name (interpretation depends on {@link AssetLoader})
* @param type the type of the asset. */
public synchronized <T> void load (String fileName, Class<T> type) {
load(fileName, type, null);
}
/** Adds the given asset to the loading queue of the AssetManager.
* @param fileName the file name (interpretation depends on {@link AssetLoader})
* @param type the type of the asset.
* @param parameter parameters for the AssetLoader. */
public synchronized <T> void load (String fileName, Class<T> type, AssetLoaderParameters<T> parameter) {
AssetLoader loader = getLoader(type, fileName);
if (loader == null) throw new GdxRuntimeException("No loader for type: " + ClassReflection.getSimpleName(type));
// reset stats
if (loadQueue.size == 0) {
loaded = 0;
toLoad = 0;
}
// check if an asset with the same name but a different type has already been added.
// check preload queue
for (int i = 0; i < loadQueue.size; i++) {
AssetDescriptor desc = loadQueue.get(i);
if (desc.fileName.equals(fileName) && !desc.type.equals(type))
throw new GdxRuntimeException("Asset with name '" + fileName
+ "' already in preload queue, but has different type (expected: " + ClassReflection.getSimpleName(type)
+ ", found: " + ClassReflection.getSimpleName(desc.type) + ")");
}
// check task list
for (int i = 0; i < tasks.size(); i++) {
AssetDescriptor desc = tasks.get(i).assetDesc;
if (desc.fileName.equals(fileName) && !desc.type.equals(type))
throw new GdxRuntimeException("Asset with name '" + fileName
+ "' already in task list, but has different type (expected: " + ClassReflection.getSimpleName(type) + ", found: "
+ ClassReflection.getSimpleName(desc.type) + ")");
}
// check loaded assets
Class otherType = assetTypes.get(fileName);
if (otherType != null && !otherType.equals(type))
throw new GdxRuntimeException("Asset with name '" + fileName + "' already loaded, but has different type (expected: "
+ ClassReflection.getSimpleName(type) + ", found: " + ClassReflection.getSimpleName(otherType) + ")");
toLoad++;
AssetDescriptor assetDesc = new AssetDescriptor(fileName, type, parameter);
loadQueue.add(assetDesc);
log.debug("Queued: " + assetDesc);
}
/** Adds the given asset to the loading queue of the AssetManager.
* @param desc the {@link AssetDescriptor} */
public synchronized void load (AssetDescriptor desc) {
load(desc.fileName, desc.type, desc.params);
}
/** Updates the AssetManager, keeping it loading any assets in the preload queue.
* @return true if all loading is finished. */
public synchronized boolean update () {
try {
if (tasks.size() == 0) {
// loop until we have a new task ready to be processed
while (loadQueue.size != 0 && tasks.size() == 0) {
nextTask();
}
// have we not found a task? We are done!
if (tasks.size() == 0) return true;
}
return updateTask() && loadQueue.size == 0 && tasks.size() == 0;
} catch (Throwable t) {
handleTaskError(t);
return loadQueue.size == 0;
}
}
/** Updates the AssetManager continuously for the specified number of milliseconds, yielding the CPU to the loading thread
* between updates. This may block for less time if all loading tasks are complete. This may block for more time if the portion
* of a single task that happens in the GL thread takes a long time.
* @return true if all loading is finished. */
public boolean update (int millis) {
long endTime = TimeUtils.millis() + millis;
while (true) {
boolean done = update();
if (done || TimeUtils.millis() > endTime) return done;
ThreadUtils.yield();
}
}
/** Blocks until all assets are loaded. */
public void finishLoading () {
log.debug("Waiting for loading to complete...");
while (!update())
ThreadUtils.yield();
log.debug("Loading complete.");
}
/** Blocks until the specified asset is loaded.
* @param fileName the file name (interpretation depends on {@link AssetLoader}) */
public void finishLoadingAsset (String fileName) {
log.debug("Waiting for asset to be loaded: " + fileName);
while (!isLoaded(fileName)) {
update();
ThreadUtils.yield();
}
log.debug("Asset loaded: " + fileName);
}
synchronized void injectDependencies (String parentAssetFilename, Array<AssetDescriptor> dependendAssetDescs) {
ObjectSet<String> injected = this.injected;
for (AssetDescriptor desc : dependendAssetDescs) {
if (injected.contains(desc.fileName)) continue; // Ignore subsequent dependencies if there are duplicates.
injected.add(desc.fileName);
injectDependency(parentAssetFilename, desc);
}
injected.clear();
}
private synchronized void injectDependency (String parentAssetFilename, AssetDescriptor dependendAssetDesc) {
// add the asset as a dependency of the parent asset
Array<String> dependencies = assetDependencies.get(parentAssetFilename);
if (dependencies == null) {
dependencies = new Array();
assetDependencies.put(parentAssetFilename, dependencies);
}
dependencies.add(dependendAssetDesc.fileName);
// if the asset is already loaded, increase its reference count.
if (isLoaded(dependendAssetDesc.fileName)) {
log.debug("Dependency already loaded: " + dependendAssetDesc);
Class type = assetTypes.get(dependendAssetDesc.fileName);
RefCountedContainer assetRef = assets.get(type).get(dependendAssetDesc.fileName);
assetRef.incRefCount();
incrementRefCountedDependencies(dependendAssetDesc.fileName);
}
// else add a new task for the asset.
else {
log.info("Loading dependency: " + dependendAssetDesc);
addTask(dependendAssetDesc);
}
}
/** Removes a task from the loadQueue and adds it to the task stack. If the asset is already loaded (which can happen if it was
* a dependency of a previously loaded asset) its reference count will be increased. */
private void nextTask () {
AssetDescriptor assetDesc = loadQueue.removeIndex(0);
// if the asset not meant to be reloaded and is already loaded, increase its reference count
if (isLoaded(assetDesc.fileName)) {
log.debug("Already loaded: " + assetDesc);
Class type = assetTypes.get(assetDesc.fileName);
RefCountedContainer assetRef = assets.get(type).get(assetDesc.fileName);
assetRef.incRefCount();
incrementRefCountedDependencies(assetDesc.fileName);
if (assetDesc.params != null && assetDesc.params.loadedCallback != null) {
assetDesc.params.loadedCallback.finishedLoading(this, assetDesc.fileName, assetDesc.type);
}
loaded++;
} else {
// else add a new task for the asset.
log.info("Loading: " + assetDesc);
addTask(assetDesc);
}
}
/** Adds a {@link AssetLoadingTask} to the task stack for the given asset.
* @param assetDesc */
private void addTask (AssetDescriptor assetDesc) {
AssetLoader loader = getLoader(assetDesc.type, assetDesc.fileName);
if (loader == null) throw new GdxRuntimeException("No loader for type: " + ClassReflection.getSimpleName(assetDesc.type));
tasks.push(new AssetLoadingTask(this, assetDesc, loader, executor));
}
/** Adds an asset to this AssetManager */
protected <T> void addAsset (final String fileName, Class<T> type, T asset) {
// add the asset to the filename lookup
assetTypes.put(fileName, type);
// add the asset to the type lookup
ObjectMap<String, RefCountedContainer> typeToAssets = assets.get(type);
if (typeToAssets == null) {
typeToAssets = new ObjectMap<String, RefCountedContainer>();
assets.put(type, typeToAssets);
}
typeToAssets.put(fileName, new RefCountedContainer(asset));
}
/** Updates the current task on the top of the task stack.
* @return true if the asset is loaded or the task was cancelled. */
private boolean updateTask () {
AssetLoadingTask task = tasks.peek();
boolean complete = true;
try {
complete = task.cancel || task.update();
} catch (RuntimeException ex) {
task.cancel = true;
taskFailed(task.assetDesc, ex);
}
// if the task has been cancelled or has finished loading
if (complete) {
// increase the number of loaded assets and pop the task from the stack
if (tasks.size() == 1) loaded++;
tasks.pop();
if (task.cancel) return true;
addAsset(task.assetDesc.fileName, task.assetDesc.type, task.getAsset());
// otherwise, if a listener was found in the parameter invoke it
if (task.assetDesc.params != null && task.assetDesc.params.loadedCallback != null) {
task.assetDesc.params.loadedCallback.finishedLoading(this, task.assetDesc.fileName, task.assetDesc.type);
}
long endTime = TimeUtils.nanoTime();
log.debug("Loaded: " + (endTime - task.startTime) / 1000000f + "ms " + task.assetDesc);
return true;
}
return false;
}
/** Called when a task throws an exception during loading. The default implementation rethrows the exception. A subclass may
* supress the default implementation when loading assets where loading failure is recoverable. */
protected void taskFailed (AssetDescriptor assetDesc, RuntimeException ex) {
throw ex;
}
private void incrementRefCountedDependencies (String parent) {
Array<String> dependencies = assetDependencies.get(parent);
if (dependencies == null) return;
for (String dependency : dependencies) {
Class type = assetTypes.get(dependency);
RefCountedContainer assetRef = assets.get(type).get(dependency);
assetRef.incRefCount();
incrementRefCountedDependencies(dependency);
}
}
/** Handles a runtime/loading error in {@link #update()} by optionally invoking the {@link AssetErrorListener}.
* @param t */
private void handleTaskError (Throwable t) {
log.error("Error loading asset.", t);
if (tasks.isEmpty()) throw new GdxRuntimeException(t);
// pop the faulty task from the stack
AssetLoadingTask task = tasks.pop();
AssetDescriptor assetDesc = task.assetDesc;
// remove all dependencies
if (task.dependenciesLoaded && task.dependencies != null) {
for (AssetDescriptor desc : task.dependencies) {
unload(desc.fileName);
}
}
// clear the rest of the stack
tasks.clear();
// inform the listener that something bad happened
if (listener != null) {
listener.error(assetDesc, t);
} else {
throw new GdxRuntimeException(t);
}
}
/** Sets a new {@link AssetLoader} for the given type.
* @param type the type of the asset
* @param loader the loader */
public synchronized <T, P extends AssetLoaderParameters<T>> void setLoader (Class<T> type, AssetLoader<T, P> loader) {
setLoader(type, null, loader);
}
/** Sets a new {@link AssetLoader} for the given type.
* @param type the type of the asset
* @param suffix the suffix the filename must have for this loader to be used or null to specify the default loader.
* @param loader the loader */
public synchronized <T, P extends AssetLoaderParameters<T>> void setLoader (Class<T> type, String suffix,
AssetLoader<T, P> loader) {
if (type == null) throw new IllegalArgumentException("type cannot be null.");
if (loader == null) throw new IllegalArgumentException("loader cannot be null.");
log.debug("Loader set: " + ClassReflection.getSimpleName(type) + " -> " + ClassReflection.getSimpleName(loader.getClass()));
ObjectMap<String, AssetLoader> loaders = this.loaders.get(type);
if (loaders == null) this.loaders.put(type, loaders = new ObjectMap<String, AssetLoader>());
loaders.put(suffix == null ? "" : suffix, loader);
}
/** @return the number of loaded assets */
public synchronized int getLoadedAssets () {
return assetTypes.size;
}
/** @return the number of currently queued assets */
public synchronized int getQueuedAssets () {
return loadQueue.size + tasks.size();
}
/** @return the progress in percent of completion. */
public synchronized float getProgress () {
if (toLoad == 0) return 1;
return Math.min(1, loaded / (float)toLoad);
}
/** Sets an {@link AssetErrorListener} to be invoked in case loading an asset failed.
* @param listener the listener or null */
public synchronized void setErrorListener (AssetErrorListener listener) {
this.listener = listener;
}
/** Disposes all assets in the manager and stops all asynchronous loading. */
@Override
public synchronized void dispose () {
log.debug("Disposing.");
clear();
executor.dispose();
}
/** Clears and disposes all assets and the preloading queue. */
public synchronized void clear () {
loadQueue.clear();
while (!update())
;
ObjectIntMap<String> dependencyCount = new ObjectIntMap<String>();
while (assetTypes.size > 0) {
// for each asset, figure out how often it was referenced
dependencyCount.clear();
Array<String> assets = assetTypes.keys().toArray();
for (String asset : assets) {
dependencyCount.put(asset, 0);
}
for (String asset : assets) {
Array<String> dependencies = assetDependencies.get(asset);
if (dependencies == null) continue;
for (String dependency : dependencies) {
int count = dependencyCount.get(dependency, 0);
count++;
dependencyCount.put(dependency, count);
}
}
// only dispose of assets that are root assets (not referenced)
for (String asset : assets) {
if (dependencyCount.get(asset, 0) == 0) {
unload(asset);
}
}
}
this.assets.clear();
this.assetTypes.clear();
this.assetDependencies.clear();
this.loaded = 0;
this.toLoad = 0;
this.loadQueue.clear();
this.tasks.clear();
}
/** @return the {@link Logger} used by the {@link AssetManager} */
public Logger getLogger () {
return log;
}
public void setLogger (Logger logger) {
log = logger;
}
/** Returns the reference count of an asset.
* @param fileName */
public synchronized int getReferenceCount (String fileName) {
Class type = assetTypes.get(fileName);
if (type == null) throw new GdxRuntimeException("Asset not loaded: " + fileName);
return assets.get(type).get(fileName).getRefCount();
}
/** Sets the reference count of an asset.
* @param fileName */
public synchronized void setReferenceCount (String fileName, int refCount) {
Class type = assetTypes.get(fileName);
if (type == null) throw new GdxRuntimeException("Asset not loaded: " + fileName);
assets.get(type).get(fileName).setRefCount(refCount);
}
/** @return a string containing ref count and dependency information for all assets. */
public synchronized String getDiagnostics () {
StringBuffer buffer = new StringBuffer();
for (String fileName : assetTypes.keys()) {
buffer.append(fileName);
buffer.append(", ");
Class type = assetTypes.get(fileName);
RefCountedContainer assetRef = assets.get(type).get(fileName);
Array<String> dependencies = assetDependencies.get(fileName);
buffer.append(ClassReflection.getSimpleName(type));
buffer.append(", refs: ");
buffer.append(assetRef.getRefCount());
if (dependencies != null) {
buffer.append(", deps: [");
for (String dep : dependencies) {
buffer.append(dep);
buffer.append(",");
}
buffer.append("]");
}
buffer.append("\n");
}
return buffer.toString();
}
/** @return the file names of all loaded assets. */
public synchronized Array<String> getAssetNames () {
return assetTypes.keys().toArray();
}
/** @return the dependencies of an asset or null if the asset has no dependencies. */
public synchronized Array<String> getDependencies (String fileName) {
return assetDependencies.get(fileName);
}
/** @return the type of a loaded asset. */
public synchronized Class getAssetType (String fileName) {
return assetTypes.get(fileName);
}
}