/*
* Copyright 2015 MovingBlocks
*
* 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 org.terasology.assets.management;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;
import org.terasology.assets.Asset;
import org.terasology.assets.AssetData;
import org.terasology.assets.AssetType;
import org.terasology.assets.ResourceUrn;
import org.terasology.module.sandbox.API;
import org.terasology.naming.Name;
import javax.annotation.concurrent.ThreadSafe;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.Set;
/**
* AssetManager provides an simplified interface for working with assets across multiple asset types.
* <p>
* To do this it uses an {@link AssetTypeManager} to obtain the AssetTypes relating to an Asset
* class of interest, and delegates down to them for actions such as obtaining and reloading assets.
* </p>
*
* @author Immortius
*/
@API
@ThreadSafe
public final class AssetManager {
private final AssetTypeManager assetTypeManager;
/**
* @param assetTypeManager the asset type manager that will be used
*/
public AssetManager(AssetTypeManager assetTypeManager) {
this.assetTypeManager = assetTypeManager;
}
/**
* @param urn The urn of the asset to check. Must not be an instance urn
* @param type The Asset class of interest
* @return whether an asset is loaded with the given urn
*/
public boolean isLoaded(ResourceUrn urn, Class<? extends Asset<?>> type) {
for (AssetType<?, ?> assetType : assetTypeManager.getAssetTypes(type)) {
if (assetType.isLoaded(urn)) {
return true;
}
}
return false;
}
/**
* Retrieves a set of the ResourceUrns for all loaded assets of the given Asset class (including subtypes)
*
* @param type The Asset class of interest
* @param <T> The Asset class
* @return A set of the ResourceUrns of all loaded assets
*/
public <T extends Asset<?>> Set<ResourceUrn> getLoadedAssetUrns(Class<T> type) {
List<AssetType<? extends T, ?>> assetTypes = assetTypeManager.getAssetTypes(type);
switch (assetTypes.size()) {
case 0:
return Collections.emptySet();
case 1:
return assetTypes.get(0).getLoadedAssetUrns();
default:
Set<ResourceUrn> result = Sets.newLinkedHashSet();
for (AssetType<? extends T, ?> assetType : assetTypes) {
result.addAll(assetType.getLoadedAssetUrns());
}
return result;
}
}
/**
* Retrieves a list of all loaded assets of the given Asset class (including subtypes)
*
* @param type The Asset class of interest
* @param <T> The Asset class
* @param <U> The AssetData class
* @return A list of all the loaded assets
*/
public <T extends Asset<U>, U extends AssetData> Set<T> getLoadedAssets(Class<T> type) {
List<AssetType<? extends T, ?>> assetTypes = assetTypeManager.getAssetTypes(type);
switch (assetTypes.size()) {
case 0:
return Collections.emptySet();
default:
ImmutableSet.Builder<T> builder = ImmutableSet.builder();
for (AssetType<? extends T, ?> assetType : assetTypes) {
builder.addAll(assetType.getLoadedAssets());
}
return builder.build();
}
}
/**
* Retrieves a set of the ResourceUrns for all available assets of the given Asset class (including subtypes). An available asset is either a loaded asset, or one
* which can be requested. The set is not necessarily complete as assets procedurally generated from their resource urn may not be included.
*
* @param type The Asset class of interest
* @param <T> The Asset class
* @return A set of the ResourceUrns of all available assets
*/
public <T extends Asset<?>> Set<ResourceUrn> getAvailableAssets(Class<T> type) {
List<AssetType<? extends T, ?>> assetTypes = assetTypeManager.getAssetTypes(type);
switch (assetTypes.size()) {
case 0:
return Collections.emptySet();
case 1:
return assetTypes.get(0).getAvailableAssetUrns();
default:
Set<ResourceUrn> result = Sets.newLinkedHashSet();
for (AssetType<? extends T, ?> assetType : assetTypes) {
result.addAll(assetType.getAvailableAssetUrns());
}
return result;
}
}
/**
* Given a string that may be a partial or full urn, resolves all possible ResourceUrns to load it as. This takes into account the current module context from
* {@link org.terasology.assets.management.ContextManager}.
*
* @param urn The full or partial urn to resolve.
* @param type The type of Asset to resolve this the urn for
* @param <T> The class of Asset
* @return A set of possible ResourceUrns that match these conditions
*/
public <T extends Asset<?>> Set<ResourceUrn> resolve(String urn, Class<T> type) {
return resolve(urn, type, ContextManager.getCurrentContext());
}
/**
* Given a string that may be a partial or full urn, resolves all possible ResourceUrns to load it as. This uses the module context given.
*
* @param urn The full or partial urn to resolve.
* @param type The type of Asset to resolve this the urn for
* @param moduleContext The module context to resolve the urn within
* @param <T> The class of Asset
* @return A set of possible ResourceUrns that match these conditions
*/
public <T extends Asset<?>> Set<ResourceUrn> resolve(String urn, Class<T> type, Name moduleContext) {
List<AssetType<? extends T, ?>> assetTypes = assetTypeManager.getAssetTypes(type);
switch (assetTypes.size()) {
case 0:
return Collections.emptySet();
case 1:
return assetTypes.get(0).resolve(urn, moduleContext);
default:
Set<ResourceUrn> result = Sets.newLinkedHashSet();
for (AssetType<? extends T, ?> assetType : assetTypes) {
result.addAll(assetType.resolve(urn, moduleContext));
}
return result;
}
}
/**
* Retrieves an asset from a full or partial urn, of the given Asset type. The urn is resolved as per {@link #resolve(String, Class)}
*
* @param urn The full or partial urn of the asset to retrieve
* @param type The type of Asset to retrieve
* @param <T> The class of Asset
* @param <U> The class of AssetData
* @return An optional containing the requested asset if successfully obtained.
*/
public <T extends Asset<U>, U extends AssetData> Optional<T> getAsset(String urn, Class<T> type) {
return getAsset(urn, type, ContextManager.getCurrentContext());
}
/**
* Retrieves an asset from a full or partial urn, of the given Asset type
*
* @param urn The full or partial urn of the asset to retrieve
* @param type The type of Asset to retrieve
* @param moduleContext The context in which to resolve the urn
* @param <T> The class of Asset
* @param <U> The class of AssetData
* @return An Optional containing the requested asset if successfully obtained
*/
public <T extends Asset<U>, U extends AssetData> Optional<T> getAsset(String urn, Class<T> type, Name moduleContext) {
Set<ResourceUrn> resourceUrns = resolve(urn, type, moduleContext);
if (resourceUrns.size() == 1) {
return getAsset(resourceUrns.iterator().next(), type);
}
return Optional.empty();
}
/**
* Retrieves an asset with the given urn and type
*
* @param urn The urn of the asset to retrieve
* @param type The type of asset to retrieve
* @param <T> The class of Asset
* @param <U> The class of AssetData
* @return An Optional containing the requested asset if successfully obtained
*/
public <T extends Asset<U>, U extends AssetData> Optional<T> getAsset(ResourceUrn urn, Class<T> type) {
List<AssetType<? extends T, ?>> assetTypes = assetTypeManager.getAssetTypes(type);
switch (assetTypes.size()) {
case 0:
return Optional.empty();
case 1: {
Optional<? extends T> result = assetTypes.get(0).getAsset(urn);
if (result.isPresent()) {
return Optional.of(result.get());
}
break;
}
default:
for (AssetType<? extends T, ?> assetType : assetTypes) {
Optional<? extends T> result = assetType.getAsset(urn);
if (result.isPresent()) {
return Optional.of(result.get());
}
}
break;
}
return Optional.empty();
}
/**
* Creates or reloads an asset with the given urn, data and type. The type must be the actual type of the asset, not a super type.
*
* @param urn The urn of the asset
* @param data The data to load the asset with
* @param type The type of the asset
* @param <T> The class of Asset
* @param <U> The class of AssetData
* @return The loaded asset
* @throws java.lang.IllegalStateException if the asset type is not managed by this AssetManager.
*/
public <T extends Asset<U>, U extends AssetData> T loadAsset(ResourceUrn urn, U data, Class<T> type) {
Optional<AssetType<T, U>> assetType = assetTypeManager.getAssetType(type);
if (assetType.isPresent()) {
return assetType.get().loadAsset(urn, data);
} else {
throw new IllegalStateException(type + " is not a supported type of asset");
}
}
}