2016-06-23 03:49:47 +00:00
|
|
|
/*
|
|
|
|
* Minecraft Forge
|
2018-07-01 21:17:28 +00:00
|
|
|
* Copyright (c) 2016-2018.
|
2016-06-23 03:49:47 +00:00
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License as published by the Free Software Foundation version 2.1
|
|
|
|
* of the License.
|
|
|
|
*
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* Lesser General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
|
|
* License along with this library; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
|
|
*/
|
|
|
|
|
2014-12-28 04:10:54 +00:00
|
|
|
package net.minecraftforge.client.model;
|
|
|
|
|
2016-03-13 13:16:25 +00:00
|
|
|
import java.util.Deque;
|
2018-09-08 20:34:59 +00:00
|
|
|
import java.util.HashSet;
|
2014-12-28 04:10:54 +00:00
|
|
|
import java.util.Map;
|
|
|
|
import java.util.Set;
|
|
|
|
|
2018-09-08 20:34:59 +00:00
|
|
|
import org.apache.logging.log4j.LogManager;
|
|
|
|
import org.apache.logging.log4j.Logger;
|
|
|
|
|
|
|
|
import com.google.common.base.Joiner;
|
|
|
|
import com.google.common.collect.ImmutableMap;
|
|
|
|
import com.google.common.collect.Maps;
|
|
|
|
import com.google.common.collect.Queues;
|
|
|
|
import com.google.common.collect.Sets;
|
|
|
|
|
2014-12-28 04:10:54 +00:00
|
|
|
import net.minecraft.client.Minecraft;
|
2018-09-08 20:34:59 +00:00
|
|
|
import net.minecraft.client.renderer.block.model.IUnbakedModel;
|
2016-03-01 12:58:03 +00:00
|
|
|
import net.minecraft.client.renderer.block.model.ModelResourceLocation;
|
2018-09-08 20:34:59 +00:00
|
|
|
import net.minecraft.resources.IReloadableResourceManager;
|
|
|
|
import net.minecraft.resources.IResourceManager;
|
2014-12-28 04:10:54 +00:00
|
|
|
import net.minecraft.util.ResourceLocation;
|
|
|
|
import net.minecraftforge.client.model.ModelLoader.VanillaLoader;
|
2016-03-13 13:16:25 +00:00
|
|
|
import net.minecraftforge.client.model.ModelLoader.VariantLoader;
|
2015-06-18 11:14:46 +00:00
|
|
|
import net.minecraftforge.client.model.b3d.B3DLoader;
|
2015-07-28 21:23:34 +00:00
|
|
|
import net.minecraftforge.client.model.obj.OBJLoader;
|
2016-03-21 07:01:30 +00:00
|
|
|
import net.minecraftforge.common.animation.ITimeValue;
|
|
|
|
import net.minecraftforge.common.model.animation.AnimationStateMachine;
|
|
|
|
import net.minecraftforge.common.model.animation.IAnimationStateMachine;
|
2016-03-13 13:16:25 +00:00
|
|
|
|
2014-12-28 04:10:54 +00:00
|
|
|
/*
|
|
|
|
* Central hub for custom model loaders.
|
|
|
|
*/
|
|
|
|
public class ModelLoaderRegistry
|
|
|
|
{
|
2018-09-08 20:34:59 +00:00
|
|
|
private static final Logger LOGGER = LogManager.getLogger();
|
|
|
|
|
2016-03-13 13:16:25 +00:00
|
|
|
private static final Set<ICustomModelLoader> loaders = Sets.newHashSet();
|
2018-09-08 20:34:59 +00:00
|
|
|
private static final Map<ResourceLocation, IUnbakedModel> cache = Maps.newHashMap();
|
2016-03-13 13:16:25 +00:00
|
|
|
private static final Deque<ResourceLocation> loadingModels = Queues.newArrayDeque();
|
|
|
|
private static final Set<ResourceLocation> textures = Sets.newHashSet();
|
2018-08-16 20:21:21 +00:00
|
|
|
private static final Map<ResourceLocation, ResourceLocation> aliases = Maps.newHashMap();
|
|
|
|
|
2016-03-21 07:01:30 +00:00
|
|
|
private static IResourceManager manager;
|
2014-12-28 04:10:54 +00:00
|
|
|
|
2015-06-18 11:14:46 +00:00
|
|
|
// Forge built-in loaders
|
|
|
|
static
|
|
|
|
{
|
2016-03-21 07:23:27 +00:00
|
|
|
registerLoader(B3DLoader.INSTANCE);
|
|
|
|
registerLoader(OBJLoader.INSTANCE);
|
|
|
|
registerLoader(ModelFluid.FluidLoader.INSTANCE);
|
|
|
|
registerLoader(ItemLayerModel.Loader.INSTANCE);
|
|
|
|
registerLoader(MultiLayerModel.Loader.INSTANCE);
|
|
|
|
registerLoader(ModelDynBucket.LoaderDynBucket.INSTANCE);
|
2015-06-18 11:14:46 +00:00
|
|
|
}
|
|
|
|
|
2014-12-28 04:10:54 +00:00
|
|
|
/*
|
|
|
|
* Makes system aware of your loader.
|
|
|
|
*/
|
|
|
|
public static void registerLoader(ICustomModelLoader loader)
|
|
|
|
{
|
|
|
|
loaders.add(loader);
|
2018-09-22 10:40:22 +00:00
|
|
|
((IReloadableResourceManager) Minecraft.getInstance().getResourceManager()).addReloadListener(loader);
|
2014-12-28 04:10:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public static boolean loaded(ResourceLocation location)
|
|
|
|
{
|
|
|
|
return cache.containsKey(location);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public static ResourceLocation getActualLocation(ResourceLocation location)
|
|
|
|
{
|
2016-03-13 13:16:25 +00:00
|
|
|
if(location instanceof ModelResourceLocation) return location;
|
2018-09-08 20:34:59 +00:00
|
|
|
if(location.getPath().startsWith("builtin/")) return location;
|
|
|
|
return new ResourceLocation(location.getNamespace(), "models/" + location.getPath());
|
2014-12-28 04:10:54 +00:00
|
|
|
}
|
|
|
|
|
2016-01-06 19:00:43 +00:00
|
|
|
/**
|
|
|
|
* Primary method to get IModel instances.
|
|
|
|
* ResourceLocation argument will be passed directly to the custom model loaders,
|
|
|
|
* ModelResourceLocation argument will be loaded through the blockstate system.
|
|
|
|
*/
|
2018-09-08 20:34:59 +00:00
|
|
|
public static IUnbakedModel getModel(ResourceLocation location) throws Exception
|
2014-12-28 04:10:54 +00:00
|
|
|
{
|
2018-09-08 20:34:59 +00:00
|
|
|
IUnbakedModel model;
|
2018-08-16 20:21:21 +00:00
|
|
|
|
2018-09-08 20:34:59 +00:00
|
|
|
IUnbakedModel cached = cache.get(location);
|
2018-08-16 20:21:21 +00:00
|
|
|
if (cached != null) return cached;
|
|
|
|
|
2016-03-13 13:16:25 +00:00
|
|
|
for(ResourceLocation loading : loadingModels)
|
2014-12-28 04:10:54 +00:00
|
|
|
{
|
2016-03-13 13:16:25 +00:00
|
|
|
if(location.getClass() == loading.getClass() && location.equals(loading))
|
2014-12-28 04:10:54 +00:00
|
|
|
{
|
2016-03-15 22:42:01 +00:00
|
|
|
throw new LoaderException("circular model dependencies, stack: [" + Joiner.on(", ").join(loadingModels) + "]");
|
2014-12-28 04:10:54 +00:00
|
|
|
}
|
|
|
|
}
|
2016-03-13 13:16:25 +00:00
|
|
|
loadingModels.addLast(location);
|
|
|
|
try
|
2014-12-28 04:10:54 +00:00
|
|
|
{
|
2018-08-16 20:21:21 +00:00
|
|
|
ResourceLocation aliased = aliases.get(location);
|
|
|
|
if (aliased != null) return getModel(aliased);
|
|
|
|
|
2016-01-06 19:00:43 +00:00
|
|
|
ResourceLocation actual = getActualLocation(location);
|
|
|
|
ICustomModelLoader accepted = null;
|
|
|
|
for(ICustomModelLoader loader : loaders)
|
2015-06-16 23:03:10 +00:00
|
|
|
{
|
2016-01-06 19:00:43 +00:00
|
|
|
try
|
|
|
|
{
|
|
|
|
if(loader.accepts(actual))
|
|
|
|
{
|
|
|
|
if(accepted != null)
|
|
|
|
{
|
2016-03-15 22:42:01 +00:00
|
|
|
throw new LoaderException(String.format("2 loaders (%s and %s) want to load the same model %s", accepted, loader, location));
|
2016-01-06 19:00:43 +00:00
|
|
|
}
|
|
|
|
accepted = loader;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
catch(Exception e)
|
|
|
|
{
|
2016-03-15 22:42:01 +00:00
|
|
|
throw new LoaderException(String.format("Exception checking if model %s can be loaded with loader %s, skipping", location, loader), e);
|
2016-01-06 19:00:43 +00:00
|
|
|
}
|
2015-06-16 23:03:10 +00:00
|
|
|
}
|
2016-01-06 19:00:43 +00:00
|
|
|
|
2016-03-13 13:16:25 +00:00
|
|
|
// no custom loaders found, try vanilla ones
|
2016-01-06 19:00:43 +00:00
|
|
|
if(accepted == null)
|
2015-06-16 23:03:10 +00:00
|
|
|
{
|
2016-03-21 07:23:27 +00:00
|
|
|
if(VariantLoader.INSTANCE.accepts(actual))
|
2016-03-13 13:16:25 +00:00
|
|
|
{
|
2016-03-21 07:23:27 +00:00
|
|
|
accepted = VariantLoader.INSTANCE;
|
2016-03-13 13:16:25 +00:00
|
|
|
}
|
2016-03-21 07:23:27 +00:00
|
|
|
else if(VanillaLoader.INSTANCE.accepts(actual))
|
2016-03-13 13:16:25 +00:00
|
|
|
{
|
2016-03-21 07:23:27 +00:00
|
|
|
accepted = VanillaLoader.INSTANCE;
|
2016-03-13 13:16:25 +00:00
|
|
|
}
|
2015-06-16 23:03:10 +00:00
|
|
|
}
|
2016-01-06 19:00:43 +00:00
|
|
|
|
|
|
|
if(accepted == null)
|
2015-06-16 23:03:10 +00:00
|
|
|
{
|
2016-03-15 22:42:01 +00:00
|
|
|
throw new LoaderException("no suitable loader found for the model " + location + ", skipping");
|
2015-06-16 23:03:10 +00:00
|
|
|
}
|
2016-03-15 22:42:01 +00:00
|
|
|
try
|
2016-01-06 19:00:43 +00:00
|
|
|
{
|
2016-03-15 22:42:01 +00:00
|
|
|
model = accepted.loadModel(actual);
|
|
|
|
}
|
|
|
|
catch(Exception e)
|
|
|
|
{
|
|
|
|
throw new LoaderException(String.format("Exception loading model %s with loader %s, skipping", location, accepted), e);
|
2016-03-13 13:16:25 +00:00
|
|
|
}
|
2016-03-15 22:42:01 +00:00
|
|
|
if(model == getMissingModel())
|
|
|
|
{
|
|
|
|
throw new LoaderException(String.format("Loader %s returned missing model while loading model %s", accepted, location));
|
|
|
|
}
|
|
|
|
if(model == null)
|
|
|
|
{
|
|
|
|
throw new LoaderException(String.format("Loader %s returned null while loading model %s", accepted, location));
|
|
|
|
}
|
2018-09-22 10:40:22 +00:00
|
|
|
textures.addAll(model.getTextures(ModelLoader.defaultModelGetter(), new HashSet<>()));
|
2016-03-13 13:16:25 +00:00
|
|
|
}
|
|
|
|
finally
|
|
|
|
{
|
|
|
|
ResourceLocation popLoc = loadingModels.removeLast();
|
|
|
|
if(popLoc != location)
|
|
|
|
{
|
|
|
|
throw new IllegalStateException("Corrupted loading model stack: " + popLoc + " != " + location);
|
2016-01-06 19:00:43 +00:00
|
|
|
}
|
2014-12-28 04:10:54 +00:00
|
|
|
}
|
|
|
|
cache.put(location, model);
|
2018-09-08 20:34:59 +00:00
|
|
|
for (ResourceLocation dep : model.getOverrideLocations())
|
2016-03-13 13:16:25 +00:00
|
|
|
{
|
2016-03-15 22:42:01 +00:00
|
|
|
getModelOrMissing(dep);
|
2016-03-13 13:16:25 +00:00
|
|
|
}
|
2014-12-28 04:10:54 +00:00
|
|
|
return model;
|
|
|
|
}
|
|
|
|
|
2016-03-15 22:42:01 +00:00
|
|
|
/**
|
|
|
|
* Use this if you don't care about the exception and want some model anyway.
|
|
|
|
*/
|
2018-09-08 20:34:59 +00:00
|
|
|
public static IUnbakedModel getModelOrMissing(ResourceLocation location)
|
2016-03-15 22:42:01 +00:00
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
return getModel(location);
|
|
|
|
}
|
|
|
|
catch(Exception e)
|
|
|
|
{
|
2017-01-19 09:57:37 +00:00
|
|
|
return getMissingModel(location, e);
|
2016-03-15 22:42:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Use this if you want the model, but need to log the error.
|
|
|
|
*/
|
2018-09-08 20:34:59 +00:00
|
|
|
public static IUnbakedModel getModelOrLogError(ResourceLocation location, String error)
|
2016-03-15 22:42:01 +00:00
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
return getModel(location);
|
|
|
|
}
|
|
|
|
catch(Exception e)
|
|
|
|
{
|
2018-09-08 20:34:59 +00:00
|
|
|
LOGGER.error(error, e);
|
2017-01-19 09:57:37 +00:00
|
|
|
return getMissingModel(location, e);
|
2016-03-15 22:42:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-09-08 20:34:59 +00:00
|
|
|
public static IUnbakedModel getMissingModel()
|
2014-12-28 04:10:54 +00:00
|
|
|
{
|
2017-06-25 01:08:20 +00:00
|
|
|
final ModelLoader loader = VanillaLoader.INSTANCE.getLoader();
|
|
|
|
if(loader == null)
|
2016-03-23 05:08:15 +00:00
|
|
|
{
|
|
|
|
throw new IllegalStateException("Using ModelLoaderRegistry too early.");
|
|
|
|
}
|
2017-06-25 01:08:20 +00:00
|
|
|
return loader.getMissingModel();
|
2014-12-28 04:10:54 +00:00
|
|
|
}
|
|
|
|
|
2018-09-08 20:34:59 +00:00
|
|
|
static IUnbakedModel getMissingModel(ResourceLocation location, Throwable cause)
|
2017-01-19 09:57:37 +00:00
|
|
|
{
|
|
|
|
//IModel model = new FancyMissingModel(ExceptionUtils.getStackTrace(cause).replaceAll("\\t", " "));
|
2018-09-08 20:34:59 +00:00
|
|
|
IUnbakedModel model = new FancyMissingModel(getMissingModel(), location.toString());
|
2018-09-22 10:40:22 +00:00
|
|
|
textures.addAll(model.getTextures(null, null));
|
2017-01-19 09:57:37 +00:00
|
|
|
return model;
|
|
|
|
}
|
|
|
|
|
2018-08-16 20:21:21 +00:00
|
|
|
static void addAlias(ResourceLocation from, ResourceLocation to)
|
|
|
|
{
|
|
|
|
aliases.put(from, to);
|
|
|
|
}
|
|
|
|
|
2016-03-21 07:01:30 +00:00
|
|
|
public static void clearModelCache(IResourceManager manager)
|
2014-12-28 04:10:54 +00:00
|
|
|
{
|
2016-03-21 07:01:30 +00:00
|
|
|
ModelLoaderRegistry.manager = manager;
|
2018-08-16 20:21:21 +00:00
|
|
|
aliases.clear();
|
|
|
|
textures.clear();
|
2014-12-28 04:10:54 +00:00
|
|
|
cache.clear();
|
2015-10-27 15:34:25 +00:00
|
|
|
// putting the builtin models in
|
2016-03-21 07:23:27 +00:00
|
|
|
cache.put(new ResourceLocation("minecraft:builtin/generated"), ItemLayerModel.INSTANCE);
|
|
|
|
cache.put(new ResourceLocation("minecraft:block/builtin/generated"), ItemLayerModel.INSTANCE);
|
|
|
|
cache.put(new ResourceLocation("minecraft:item/builtin/generated"), ItemLayerModel.INSTANCE);
|
2014-12-28 04:10:54 +00:00
|
|
|
}
|
2016-03-13 13:16:25 +00:00
|
|
|
|
|
|
|
static Iterable<ResourceLocation> getTextures()
|
|
|
|
{
|
|
|
|
return textures;
|
|
|
|
}
|
2016-03-15 22:42:01 +00:00
|
|
|
|
|
|
|
public static class LoaderException extends Exception
|
|
|
|
{
|
|
|
|
public LoaderException(String message)
|
|
|
|
{
|
|
|
|
super(message);
|
|
|
|
}
|
|
|
|
|
|
|
|
public LoaderException(String message, Throwable cause)
|
|
|
|
{
|
|
|
|
super(message, cause);
|
|
|
|
}
|
|
|
|
|
|
|
|
private static final long serialVersionUID = 1L;
|
|
|
|
}
|
2016-03-21 07:01:30 +00:00
|
|
|
|
|
|
|
public static IAnimationStateMachine loadASM(ResourceLocation location, ImmutableMap<String, ITimeValue> customParameters)
|
|
|
|
{
|
|
|
|
return AnimationStateMachine.load(manager, location, customParameters);
|
|
|
|
}
|
2014-12-28 04:10:54 +00:00
|
|
|
}
|