Big model loader refactoring: simplified a lot of things, broke some error reporting. Still generally works.

This commit is contained in:
RainWarrior 2016-03-13 16:16:25 +03:00
parent a799bbad2d
commit 5d352bda6c
16 changed files with 346 additions and 346 deletions

View file

@ -1,17 +1,6 @@
--- ../src-base/minecraft/net/minecraft/client/renderer/block/model/ItemOverrideList.java
+++ ../src-work/minecraft/net/minecraft/client/renderer/block/model/ItemOverrideList.java
@@ -1,7 +1,10 @@
package net.minecraft.client.renderer.block.model;
import com.google.common.collect.Lists;
+
import java.util.List;
+
+import net.minecraft.client.Minecraft;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.item.ItemStack;
import net.minecraft.util.ResourceLocation;
@@ -27,6 +30,7 @@
@@ -27,6 +27,7 @@
}
}
@ -19,7 +8,7 @@
public ResourceLocation func_188021_a(ItemStack p_188021_1_, World p_188021_2_, EntityLivingBase p_188021_3_)
{
if (!this.field_188023_b.isEmpty())
@@ -42,4 +46,18 @@
@@ -42,4 +43,18 @@
return null;
}
@ -32,7 +21,7 @@
+ ResourceLocation location = func_188021_a(stack, world, entity);
+ if (location != null)
+ {
+ return Minecraft.func_71410_x().func_175599_af().func_175037_a().func_178083_a().func_174953_a(new ModelResourceLocation(location, "inventory"));
+ return net.minecraft.client.Minecraft.func_71410_x().func_175599_af().func_175037_a().func_178083_a().func_174953_a(net.minecraftforge.client.model.ModelLoader.getInventoryVariant(location.toString()));
+ }
+ }
+ return originalModel;

View file

@ -1,5 +1,14 @@
--- ../src-base/minecraft/net/minecraft/client/renderer/block/model/ModelBakery.java
+++ ../src-work/minecraft/net/minecraft/client/renderer/block/model/ModelBakery.java
@@ -109,7 +109,7 @@
{
Collection<ModelResourceLocation> collection = Sets.newHashSet(map.values());
modelblockdefinition.func_188001_c().func_188138_a(block.func_176194_O());
- this.field_188642_k.put(modelblockdefinition, Lists.newArrayList(Iterables.filter(collection, new Predicate<ModelResourceLocation>()
+ registerMultipartVariant(modelblockdefinition, Lists.newArrayList(Iterables.filter(collection, new Predicate<ModelResourceLocation>()
{
public boolean apply(ModelResourceLocation p_apply_1_)
{
@@ -126,13 +126,13 @@
{
try
@ -98,11 +107,16 @@
private void func_177597_h()
{
this.func_177574_i();
@@ -878,4 +893,18 @@
@@ -878,4 +893,23 @@
field_177606_o.field_178317_b = "generation marker";
field_177616_r.field_178317_b = "block entity marker";
}
+
+ protected void registerMultipartVariant(ModelBlockDefinition definition, Collection<ModelResourceLocation> locations)
+ {
+ this.field_188642_k.put(definition, locations);
+ }
+
+ private static Map<net.minecraftforge.fml.common.registry.RegistryDelegate<Item>, Set<String>> customVariantNames = Maps.newHashMap();
+
+ public static void registerItemVariants(Item item, ResourceLocation... names)

View file

@ -160,10 +160,10 @@ public class BlockStateLoader
* Used to replace the base model with a retextured model containing submodels.
*/
@Override
public IModel process(IModel base, ModelLoader loader)
public IModel process(IModel base)
{
int size = parts.size();
boolean hasBase = base != loader.getMissingModel();
boolean hasBase = base != ModelLoaderRegistry.getMissingModel();
if (hasBase)
{
@ -182,16 +182,7 @@ public class BlockStateLoader
{
SubModel part = entry.getValue();
IModel model = null;
try
{
model = loader.getModel(part.getModelLocation());
}
catch (IOException e)
{
FMLLog.warning("Unable to load block sub-model: \'" + part.getModelLocation() /*+ "\' for variant: \'" + parent*/ + "\': " + e.toString());
model = loader.getMissingModel(); // Will make it look weird, but that is good.
}
IModel model = ModelLoaderRegistry.getModel(part.getModelLocation());
IModelState partState = new ModelStateComposition(baseTr, part.getState());

View file

@ -1,7 +1,5 @@
package net.minecraftforge.client.model;
import java.io.IOException;
import net.minecraft.client.resources.IResourceManagerReloadListener;
import net.minecraft.util.ResourceLocation;
@ -16,5 +14,5 @@ public interface ICustomModelLoader extends IResourceManagerReloadListener
/*
* loads (or reloads) specified model
*/
public IModel loadModel(ResourceLocation modelLocation) throws IOException;
public IModel loadModel(ResourceLocation modelLocation);
}

View file

@ -3,5 +3,5 @@ package net.minecraftforge.client.model;
public interface ISmartVariant
{
IModel process(IModel base, ModelLoader loader);
IModel process(IModel base);
}

View file

@ -34,15 +34,22 @@ public class ItemLayerModel implements IRetexturableModel
public static final ItemLayerModel instance = new ItemLayerModel(ImmutableList.<ResourceLocation>of());
private final ImmutableList<ResourceLocation> textures;
private final ItemOverrideList overrides;
public ItemLayerModel(ImmutableList<ResourceLocation> textures)
{
this(textures, ItemOverrideList.NONE);
}
public ItemLayerModel(ImmutableList<ResourceLocation> textures, ItemOverrideList overrides)
{
this.textures = textures;
this.overrides = overrides;
}
public ItemLayerModel(ModelBlock model)
{
this(getTextures(model));
this(getTextures(model), model.createOverrides());
}
private static ImmutableList<ResourceLocation> getTextures(ModelBlock model)
@ -84,7 +91,7 @@ public class ItemLayerModel implements IRetexturableModel
builder.add(this.textures.get(i));
}
}
return new ItemLayerModel(builder.build());
return new ItemLayerModel(builder.build(), overrides);
}
public IBakedModel bake(IModelState state, final VertexFormat format, Function<ResourceLocation, TextureAtlasSprite> bakedTextureGetter)
@ -98,7 +105,7 @@ public class ItemLayerModel implements IRetexturableModel
}
TextureAtlasSprite particle = bakedTextureGetter.apply(textures.isEmpty() ? new ResourceLocation("missingno") : textures.get(0));
ImmutableMap<TransformType, TRSRTransformation> map = IPerspectiveAwareModel.MapWrapper.getTransforms(state);
return new BakedItemModel(builder.build(), particle, map, null);
return new BakedItemModel(builder.build(), particle, map, overrides, null);
}
private static class BakedItemModel implements IPerspectiveAwareModel
@ -108,12 +115,14 @@ public class ItemLayerModel implements IRetexturableModel
private final ImmutableMap<TransformType, TRSRTransformation> transforms;
private final IBakedModel otherModel;
private final boolean isCulled;
private final ItemOverrideList overrides;
public BakedItemModel(ImmutableList<BakedQuad> quads, TextureAtlasSprite particle, ImmutableMap<TransformType, TRSRTransformation> transforms, IBakedModel otherModel)
public BakedItemModel(ImmutableList<BakedQuad> quads, TextureAtlasSprite particle, ImmutableMap<TransformType, TRSRTransformation> transforms, ItemOverrideList overrides, IBakedModel otherModel)
{
this.quads = quads;
this.particle = particle;
this.transforms = transforms;
this.overrides = overrides;
if(otherModel != null)
{
this.otherModel = otherModel;
@ -129,7 +138,7 @@ public class ItemLayerModel implements IRetexturableModel
builder.add(quad);
}
}
this.otherModel = new BakedItemModel(builder.build(), particle, transforms, this);
this.otherModel = new BakedItemModel(builder.build(), particle, transforms, overrides, this);
isCulled = false;
}
}
@ -139,7 +148,7 @@ public class ItemLayerModel implements IRetexturableModel
public boolean isBuiltInRenderer() { return false; }
public TextureAtlasSprite getParticleTexture() { return particle; }
public ItemCameraTransforms getItemCameraTransforms() { return ItemCameraTransforms.DEFAULT; }
public ItemOverrideList getOverrides() { return ItemOverrideList.NONE; }
public ItemOverrideList getOverrides() { return overrides; }
public List<BakedQuad> getQuads(IBlockState state, EnumFacing side, long rand)
{
if(side == null) return quads;

View file

@ -1,6 +1,5 @@
package net.minecraftforge.client.model;
import java.io.IOException;
import java.util.Collection;
import java.util.List;
import java.util.Map;
@ -212,7 +211,7 @@ public class ModelDynBucket implements IModel, IModelCustomData, IRetexturableMo
}
@Override
public IModel loadModel(ResourceLocation modelLocation) throws IOException
public IModel loadModel(ResourceLocation modelLocation)
{
return MODEL;
}

View file

@ -3,8 +3,6 @@ package net.minecraftforge.client.model;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@ -12,6 +10,7 @@ import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Queue;
import java.util.Set;
import com.google.common.base.Joiner;
@ -33,6 +32,7 @@ import net.minecraft.client.renderer.block.model.ItemModelGenerator;
import net.minecraft.client.renderer.block.model.ModelBlock;
import net.minecraft.client.renderer.block.model.ModelBlockDefinition;
import net.minecraft.client.renderer.block.model.ModelBlockDefinition.MissingVariantException;
import net.minecraft.client.renderer.block.model.MultipartBakedModel;
import net.minecraft.client.renderer.block.model.Variant;
import net.minecraft.client.renderer.block.model.VariantList;
import net.minecraft.client.renderer.block.statemap.IStateMapper;
@ -49,6 +49,8 @@ import net.minecraft.client.renderer.block.model.ModelResourceLocation;
import net.minecraft.client.renderer.block.model.ModelRotation;
import net.minecraft.client.renderer.block.model.SimpleBakedModel;
import net.minecraft.client.renderer.block.model.WeightedBakedModel;
import net.minecraft.client.renderer.block.model.multipart.Multipart;
import net.minecraft.client.renderer.block.model.multipart.Selector;
import net.minecraft.init.Items;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
@ -77,13 +79,10 @@ import org.apache.commons.lang3.tuple.Pair;
import com.google.common.base.Function;
import com.google.common.base.Optional;
import com.google.common.base.Throwables;
public class ModelLoader extends ModelBakery
{
private final Map<ModelResourceLocation, IModel> stateModels = Maps.newHashMap();
private final Set<ResourceLocation> textures = Sets.newHashSet();
private final Set<ResourceLocation> loadingModels = Sets.newHashSet();
private final Set<ModelResourceLocation> missingVariants = Sets.newHashSet();
private final Map<ResourceLocation, Exception> loadingExceptions = Maps.newHashMap();
private IModel missingModel = null;
@ -101,6 +100,7 @@ public class ModelLoader extends ModelBakery
{
super(manager, map, shapes);
VanillaLoader.instance.setLoader(this);
VariantLoader.instance.setLoader(this);
ModelLoaderRegistry.clearModelCache();
}
@ -110,18 +110,13 @@ public class ModelLoader extends ModelBakery
isLoading = true;
loadBlocks();
loadVariantItemModels();
try
{
missingModel = getModel(new ResourceLocation(MODEL_MISSING.getResourceDomain(), MODEL_MISSING.getResourcePath()));
}
catch (IOException e)
{
// If this ever happens things are bad. Should never NOT be able to load the missing model.
Throwables.propagate(e);
}
missingModel = ModelLoaderRegistry.getModel(new ResourceLocation(MODEL_MISSING.getResourceDomain(), MODEL_MISSING.getResourcePath()));
stateModels.put(MODEL_MISSING, missingModel);
final Set<ResourceLocation> textures = Sets.newHashSet(ModelLoaderRegistry.getTextures());
textures.remove(TextureMap.LOCATION_MISSING_TEXTURE);
textures.addAll(LOCATIONS_BUILTIN_TEXTURES);
textureMap.loadSprites(resourceManager, new IIconCreator()
{
public void registerSprites(TextureMap map)
@ -132,18 +127,24 @@ public class ModelLoader extends ModelBakery
}
}
});
IBakedModel missingBaked = missingModel.bake(missingModel.getDefaultState(), DefaultVertexFormats.ITEM, DefaultTextureGetter.instance);
for (Entry<ModelResourceLocation, IModel> e : stateModels.entrySet())
Map<IModel, IBakedModel> bakedModels = Maps.newHashMap();
for(IModel model : stateModels.values())
{
if(e.getValue() == getMissingModel())
if(model == getMissingModel())
{
bakedRegistry.putObject(e.getKey(), missingBaked);
bakedModels.put(model, missingBaked);
}
else
{
bakedRegistry.putObject(e.getKey(), e.getValue().bake(e.getValue().getDefaultState(), DefaultVertexFormats.ITEM, DefaultTextureGetter.instance));
bakedModels.put(model, model.bake(model.getDefaultState(), DefaultVertexFormats.ITEM, DefaultTextureGetter.instance));
}
}
for (Entry<ModelResourceLocation, IModel> e : stateModels.entrySet())
{
bakedRegistry.putObject(e.getKey(), bakedModels.get(e.getValue()));
}
return bakedRegistry;
}
@ -177,52 +178,18 @@ public class ModelLoader extends ModelBakery
ProgressManager.pop(blockBar);
}*/
// FIXME: all the new shiny multipart things
@Deprecated
private void loadVariant(ModelResourceLocation variant)
{
try
{
ModelBlockDefinition modelblockdefinition = this.getModelBlockDefinition(variant);
try
{
this.registerVariant(modelblockdefinition, variant);
}
catch (Exception ex)
{
FMLLog.getLogger().warn("Unable to load variant: " + variant.getVariant() + " from " + variant, ex);
}
}
catch (Exception ex)
{
FMLLog.getLogger().warn("Unable to load definition " + variant, ex);
}
}
@Override
protected void registerVariant(ModelBlockDefinition definition, ModelResourceLocation location)
{
// TODO loader?
VariantList variants = null;
try
stateModels.put(location, ModelLoaderRegistry.getModel(location));
}
@Override
protected void registerMultipartVariant(ModelBlockDefinition definition, Collection<ModelResourceLocation> locations)
{
for (ModelResourceLocation location : locations)
{
variants = definition.getVariant(location.getVariant());
}
catch(MissingVariantException e)
{
missingVariants.add(location);
}
if (variants != null && !variants.getVariantList().isEmpty())
{
try
{
stateModels.put(location, new WeightedRandomModel(location, variants));
}
catch(Throwable e)
{
throw new RuntimeException(e);
}
stateModels.put(location, ModelLoaderRegistry.getModel(location));
}
}
@ -268,30 +235,24 @@ public class ModelLoader extends ModelBakery
ResourceLocation file = getItemLocation(s);
ModelResourceLocation memory = getInventoryVariant(s);
itemBar.step(memory.toString());
IModel model = null;
try
{
// default loading
model = getModel(file);
if (model == null)
IModel model = ModelLoaderRegistry.getModel(file);
if(model == getMissingModel())
{
model = getMissingModel();
// try blockstate json if the item model is missing
FMLLog.fine("Item json isn't found for '" + memory + "', trying to load the variant from the blockstate json");
try
{
model = ModelLoaderRegistry.getModel(memory);
}
catch (Exception exception)
{
storeException(memory, new Exception("Could not load item model either from the normal location " + file + " or from the blockstate", exception));
}
}
stateModels.put(memory, model);
}
catch (FileNotFoundException e)
{
// try blockstate json if the item model is missing
FMLLog.fine("Item json isn't found for '" + memory + "', trying to load the variant from the blockstate json");
try
{
registerVariant(getModelBlockDefinition(memory), memory);
}
catch (Exception exception)
{
storeException(memory, new Exception("Could not load item model either from the normal location " + file + " or from the blockstate", exception));
}
}
catch (Exception exception)
{
storeException(memory, exception);
@ -321,16 +282,12 @@ public class ModelLoader extends ModelBakery
for(String s : getVariantNames(Items.bucket))
{
ModelResourceLocation memory = getInventoryVariant(s);
try
IModel model = ModelLoaderRegistry.getModel(new ResourceLocation("forge", "item/bucket"));
// only on successful load, otherwise continue using the old model
if(model != getMissingModel())
{
IModel model = getModel(new ResourceLocation("forge", "item/bucket"));
// only on successful load, otherwise continue using the old model
stateModels.put(memory, model);
}
catch(IOException e)
{
// use the original vanilla model
}
}
setBucketModel(Items.water_bucket);
@ -352,16 +309,12 @@ public class ModelLoader extends ModelBakery
for(String s : getVariantNames(Items.milk_bucket))
{
ModelResourceLocation memory = getInventoryVariant(s);
try
IModel model = ModelLoaderRegistry.getModel(new ResourceLocation("forge", "item/bucket_milk"));
// only on successful load, otherwise continue using the old model
if(model != getMissingModel())
{
IModel model = getModel(new ResourceLocation("forge", "item/bucket_milk"));
// only on successful load, otherwise continue using the old model
stateModels.put(memory, model);
}
catch(IOException e)
{
// use the original vanilla model
}
}
}
}
@ -389,60 +342,12 @@ public class ModelLoader extends ModelBakery
return new ModelResourceLocation(s, "inventory");
}
public IModel getModel(ResourceLocation location) throws IOException
{
if(!ModelLoaderRegistry.loaded(location)) loadAnyModel(location);
return ModelLoaderRegistry.getModel(location);
}
@Override
protected ResourceLocation getModelLocation(ResourceLocation model)
{
return new ResourceLocation(model.getResourceDomain(), model.getResourcePath() + ".json");
}
private void loadAnyModel(ResourceLocation location) throws IOException
{
if(loadingModels.contains(location))
{
throw new IllegalStateException("circular model dependencies involving model " + location);
}
loadingModels.add(location);
try
{
IModel model = ModelLoaderRegistry.getModel(location);
resolveDependencies(model);
}
finally
{
loadingModels.remove(location);
}
}
IModel getVariantModel(ModelResourceLocation location)
{
loadVariant(location);
IModel model = stateModels.get(location);
if(model == null) model = getMissingModel();
return model;
}
private void resolveDependencies(IModel model) throws IOException
{
for (ResourceLocation dep : model.getDependencies())
{
if(dep instanceof ModelResourceLocation)
{
getVariantModel((ModelResourceLocation)dep);
}
else
{
getModel(dep);
}
}
textures.addAll(model.getTextures());
}
private class VanillaModelWrapper implements IRetexturableModel, IModelSimpleProperties, IModelUVLock, IAnimatedModel
{
private final ResourceLocation location;
@ -461,7 +366,15 @@ public class ModelLoader extends ModelBakery
public Collection<ResourceLocation> getDependencies()
{
Set<ResourceLocation> set = Sets.newHashSet();
set.addAll(model.getOverrideLocations());
for(ResourceLocation dep : model.getOverrideLocations())
{
if(!location.equals(dep))
{
set.add(dep);
// TODO: check if this can go somewhere else, random access to global things is bad
stateModels.put(getInventoryVariant(dep.toString()), ModelLoaderRegistry.getModel(dep));
}
}
if(model.getParentLocation() != null && !model.getParentLocation().getResourcePath().startsWith("builtin/"))
{
set.add(model.getParentLocation());
@ -480,30 +393,18 @@ public class ModelLoader extends ModelBakery
}
else
{
try
IModel parent = ModelLoaderRegistry.getModel(model.getParentLocation());
if(parent == getMissingModel())
{
IModel parent = getModel(model.getParentLocation());
if(parent instanceof VanillaModelWrapper)
{
model.parent = ((VanillaModelWrapper) parent).model;
}
else
{
throw new IllegalStateException("vanilla model '" + model + "' can't have non-vanilla parent");
}
FMLLog.warning("Could not load vanilla model parent '" + model.getParentLocation() + "' for '" + model);
}
catch (IOException e)
if(parent instanceof VanillaModelWrapper)
{
FMLLog.warning("Could not load vanilla model parent '" + model.getParentLocation() + "' for '" + model + "': " + e.toString());
IModel missing = ModelLoader.this.getMissingModel();
if (missing instanceof VanillaModelWrapper)
{
model.parent = ((VanillaModelWrapper)missing).model;
}
else
{
throw new IllegalStateException("vanilla model '" + model + "' has missing parent, and missing model is not a vanilla model");
}
model.parent = ((VanillaModelWrapper) parent).model;
}
else
{
throw new IllegalStateException("vanilla model '" + model + "' can't have non-vanilla parent");
}
}
}
@ -520,15 +421,6 @@ public class ModelLoader extends ModelBakery
{
builder.add(loc);
}
/*// mojang hardcode
if(model.getRootModel() == MODEL_COMPASS && !loc.equals(TextureMap.LOCATION_MISSING_TEXTURE))
{
TextureAtlasSprite.setLocationNameCompass(loc.toString());
}
else if(model.getRootModel() == MODEL_CLOCK && !loc.equals(TextureMap.LOCATION_MISSING_TEXTURE))
{
TextureAtlasSprite.setLocationNameClock(loc.toString());
}*/
}
}
for(String s : model.textures.values())
@ -737,14 +629,15 @@ public class ModelLoader extends ModelBakery
}
}
private class WeightedRandomModel implements IModel
private static class WeightedRandomModel implements IModel
{
private final List<Variant> variants;
private final List<ResourceLocation> locations = new ArrayList<ResourceLocation>();
private final Set<ResourceLocation> textures = Sets.newHashSet();
private final List<IModel> models = new ArrayList<IModel>();
private final IModelState defaultState;
public WeightedRandomModel(ModelResourceLocation parent, VariantList variants)
public WeightedRandomModel(ResourceLocation parent, VariantList variants)
{
this.variants = variants.getVariantList();
ImmutableList.Builder<Pair<IModel, IModelState>> builder = ImmutableList.builder();
@ -756,7 +649,7 @@ public class ModelLoader extends ModelBakery
IModel model = null;
try
{
model = getModel(loc);
model = ModelLoaderRegistry.getModel(loc);
}
catch (Exception e)
{
@ -765,21 +658,19 @@ public class ModelLoader extends ModelBakery
* But that doesn't help debugging, so we maintain the missing model
* so that resource pack makers have a hint that their states are broken.
*/
FMLLog.warning("Unable to load block model: \'" + loc + "\' for variant: \'" + parent + "\': " + e.toString());
model = getMissingModel();
FMLLog.getLogger().error("Unable to load block model: \'" + loc + "\' for variant: \'" + parent, e);
model = ModelLoaderRegistry.getMissingModel();
}
// FIXME: is this the place? messes up dependency and texture resolution
if (v instanceof ISmartVariant)
{
model = ((ISmartVariant)v).process(model, ModelLoader.this);
try
model = ((ISmartVariant)v).process(model);
for(ResourceLocation location : model.getDependencies())
{
resolveDependencies(model);
}
catch (IOException e)
{
FMLLog.getLogger().error("Exception resolving indirect dependencies for model" + loc, e);
ModelLoaderRegistry.getModel(location);
}
//FMLLog.getLogger().error("Exception resolving indirect dependencies for model" + loc, e);
textures.addAll(model.getTextures()); // Kick this, just in case.
}
@ -789,7 +680,7 @@ public class ModelLoader extends ModelBakery
if (models.size() == 0) //If all variants are missing, add one with the missing model and default rotation.
{
IModel missing = getMissingModel();
IModel missing = ModelLoaderRegistry.getMissingModel();
models.add(missing);
builder.add(Pair.<IModel, IModelState>of(missing, TRSRTransformation.identity()));
}
@ -804,7 +695,7 @@ public class ModelLoader extends ModelBakery
public Collection<ResourceLocation> getTextures()
{
return Collections.emptyList();
return ImmutableSet.copyOf(textures);
}
public IBakedModel bake(IModelState state, VertexFormat format, Function<ResourceLocation, TextureAtlasSprite> bakedTextureGetter)
@ -815,7 +706,6 @@ public class ModelLoader extends ModelBakery
}
if(variants.size() == 1)
{
Variant v = variants.get(0);
IModel model = models.get(0);
return model.bake(MultiModelState.getPartState(state, model, 0), format, bakedTextureGetter);
}
@ -823,7 +713,6 @@ public class ModelLoader extends ModelBakery
for(int i = 0; i < variants.size(); i++)
{
IModel model = models.get(i);
Variant v = variants.get(i);
builder.add(model.bake(MultiModelState.getPartState(state, model, i), format, bakedTextureGetter), variants.get(i).getWeight());
}
return builder.build();
@ -839,15 +728,7 @@ public class ModelLoader extends ModelBakery
{
if (missingModel == null)
{
try
{
missingModel = getModel(new ResourceLocation(MODEL_MISSING.getResourceDomain(), MODEL_MISSING.getResourcePath()));
}
catch (IOException e)
{
// If this ever happens things are bad. Should never NOT be able to load the missing model.
Throwables.propagate(e);
}
missingModel = VanillaLoader.instance.loadModel(new ResourceLocation(MODEL_MISSING.getResourceDomain(), MODEL_MISSING.getResourcePath()));
}
return missingModel;
}
@ -883,7 +764,7 @@ public class ModelLoader extends ModelBakery
return true;
}
public IModel loadModel(ResourceLocation modelLocation) throws IOException
public IModel loadModel(ResourceLocation modelLocation)
{
String modelPath = modelLocation.getResourcePath();
if(modelLocation.getResourcePath().startsWith("models/"))
@ -892,7 +773,27 @@ public class ModelLoader extends ModelBakery
}
ResourceLocation armatureLocation = new ResourceLocation(modelLocation.getResourceDomain(), "armatures/" + modelPath + ".json");
ModelBlockAnimation animation = Animation.INSTANCE.loadVanillaAnimation(armatureLocation);
return loader.new VanillaModelWrapper(modelLocation, loader.loadModel(modelLocation), false, animation);
ModelBlock model = null;
try
{
model = loader.loadModel(modelLocation);
}
catch(Exception e)
{
// FIXME better error reporting?
FMLLog.getLogger().error("Unable to load vanilla model " + modelLocation, e);
}
if(model != null)
{
return loader.new VanillaModelWrapper(modelLocation, model, false, animation);
}
return ModelLoaderRegistry.getMissingModel();
}
@Override
public String toString()
{
return "VanillaLoader.instance";
}
}
@ -1119,4 +1020,108 @@ public class ModelLoader extends ModelBakery
{
return DefaultTextureGetter.instance;
}
protected static enum VariantLoader implements ICustomModelLoader
{
instance;
private ModelLoader loader;
void setLoader(ModelLoader loader)
{
this.loader = loader;
}
@Override
public void onResourceManagerReload(IResourceManager resourceManager)
{
// TODO Auto-generated method stub
}
@Override
public boolean accepts(ResourceLocation modelLocation)
{
return modelLocation instanceof ModelResourceLocation;
}
@Override
public IModel loadModel(ResourceLocation modelLocation)
{
ModelResourceLocation variant = (ModelResourceLocation) modelLocation;
ModelBlockDefinition definition = loader.getModelBlockDefinition(variant);
try
{
VariantList variants = definition.getVariant(variant.getVariant());
return new WeightedRandomModel(variant, variants);
}
catch(MissingVariantException e)
{
if(definition.hasMultipartData())
{
return new MultipartModel(new ResourceLocation(variant.getResourceDomain(), variant.getResourcePath()), definition.getMultipartData());
}
// FIXME log missing model?
}
return ModelLoaderRegistry.getMissingModel();
}
@Override
public String toString()
{
return "VariantLoader.instance";
}
}
private static class MultipartModel implements IModel
{
private final ResourceLocation location;
private final Multipart multipart;
private final ImmutableMap<Selector, IModel> partModels;
public MultipartModel(ResourceLocation location, Multipart multipart)
{
this.location = location;
this.multipart = multipart;
ImmutableMap.Builder<Selector, IModel> builder = ImmutableMap.builder();
for (Selector selector : multipart.getSelectors())
{
builder.put(selector, new WeightedRandomModel(location, selector.getVariantList()));
}
partModels = builder.build();
}
// FIXME: represent selectors as dependencies?
@Override
public Collection<ResourceLocation> getDependencies()
{
return ImmutableSet.of();
}
@Override
public Collection<ResourceLocation> getTextures()
{
return ImmutableSet.of();
}
// FIXME
@Override
public IBakedModel bake(IModelState state, VertexFormat format, Function<ResourceLocation, TextureAtlasSprite> bakedTextureGetter)
{
MultipartBakedModel.Builder builder = new MultipartBakedModel.Builder();
for (Selector selector : multipart.getSelectors())
{
builder.putModel(selector.getPredicate(multipart.getStateContainer()), partModels.get(selector).bake(partModels.get(selector).getDefaultState(), format, bakedTextureGetter));
}
IBakedModel bakedModel = builder.makeMultipartModel();
return bakedModel;
}
@Override
public IModelState getDefaultState()
{
return TRSRTransformation.identity();
}
}
}

View file

@ -1,8 +1,6 @@
package net.minecraftforge.client.model;
import java.io.IOException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Deque;
import java.util.Map;
import java.util.Set;
@ -11,19 +9,27 @@ import net.minecraft.client.renderer.block.model.ModelResourceLocation;
import net.minecraft.client.resources.IReloadableResourceManager;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.client.model.ModelLoader.VanillaLoader;
import net.minecraftforge.client.model.ModelLoader.VariantLoader;
import net.minecraftforge.client.model.b3d.B3DLoader;
import net.minecraftforge.client.model.obj.OBJLoader;
import net.minecraftforge.fml.common.FMLLog;
import org.apache.logging.log4j.Level;
import com.google.common.base.Joiner;
import com.google.common.collect.Maps;
import com.google.common.collect.Queues;
import com.google.common.collect.Sets;
/*
* Central hub for custom model loaders.
*/
public class ModelLoaderRegistry
{
private static final Set<ICustomModelLoader> loaders = new HashSet<ICustomModelLoader>();
private static final Map<ResourceLocation, IModel> cache = new HashMap<ResourceLocation, IModel>();
private static final Set<ICustomModelLoader> loaders = Sets.newHashSet();
private static final Map<ResourceLocation, IModel> cache = Maps.newHashMap();
private static final Deque<ResourceLocation> loadingModels = Queues.newArrayDeque();
private static final Set<ResourceLocation> textures = Sets.newHashSet();
// Forge built-in loaders
static
@ -53,6 +59,7 @@ public class ModelLoaderRegistry
public static ResourceLocation getActualLocation(ResourceLocation location)
{
if(location instanceof ModelResourceLocation) return location;
if(location.getResourcePath().startsWith("builtin/")) return location;
return new ResourceLocation(location.getResourceDomain(), "models/" + location.getResourcePath());
}
@ -62,25 +69,20 @@ public class ModelLoaderRegistry
* ResourceLocation argument will be passed directly to the custom model loaders,
* ModelResourceLocation argument will be loaded through the blockstate system.
*/
public static IModel getModel(ResourceLocation location) throws IOException
public static IModel getModel(ResourceLocation location)
{
IModel model;
if(location instanceof ModelResourceLocation)
if(cache.containsKey(location)) return cache.get(location);
for(ResourceLocation loading : loadingModels)
{
ModelLoader loader = ModelLoader.VanillaLoader.instance.getLoader();
if(loader != null)
if(location.getClass() == loading.getClass() && location.equals(loading))
{
model = loader.getVariantModel((ModelResourceLocation)location);
}
else
{
FMLLog.log(Level.ERROR, "Loading model too early, skipping: %s", location);
model = getMissingModel();
throw new IllegalStateException("circular model dependencies, stack: [" + Joiner.on(", ").join(loadingModels) + "]");
}
}
else
loadingModels.addLast(location);
try
{
if(cache.containsKey(location)) return cache.get(location);
ResourceLocation actual = getActualLocation(location);
ICustomModelLoader accepted = null;
for(ICustomModelLoader loader : loaders)
@ -103,10 +105,17 @@ public class ModelLoaderRegistry
}
}
// no custom loaders found, try vanilla one
// no custom loaders found, try vanilla ones
if(accepted == null)
{
if(VanillaLoader.instance.accepts(actual)) accepted = VanillaLoader.instance;
if(VariantLoader.instance.accepts(actual))
{
accepted = VariantLoader.instance;
}
else if(VanillaLoader.instance.accepts(actual))
{
accepted = VanillaLoader.instance;
}
}
if(accepted == null)
@ -120,18 +129,36 @@ public class ModelLoaderRegistry
{
model = accepted.loadModel(actual);
}
catch (IOException e)
{
throw e;
}
catch(Exception e)
{
FMLLog.log(Level.ERROR, e, "Exception loading model %s with loader %s, skipping", location, accepted);
model = getMissingModel();
}
if(model == getMissingModel())
{
FMLLog.log(Level.ERROR, "Loader %s returned missing model while loading model %s", accepted, location);
}
if(model == null)
{
FMLLog.log(Level.ERROR, "Loader %s returned null while loading model %s", accepted, location);
model = getMissingModel();
}
textures.addAll(model.getTextures());
}
}
finally
{
ResourceLocation popLoc = loadingModels.removeLast();
if(popLoc != location)
{
throw new IllegalStateException("Corrupted loading model stack: " + popLoc + " != " + location);
}
}
cache.put(location, model);
for (ResourceLocation dep : model.getDependencies())
{
getModel(dep);
}
return model;
}
@ -148,4 +175,9 @@ public class ModelLoaderRegistry
cache.put(new ResourceLocation("minecraft:block/builtin/generated"), ModelLoader.VanillaLoader.instance.getLoader().getItemModel());
cache.put(new ResourceLocation("minecraft:item/builtin/generated"), ModelLoader.VanillaLoader.instance.getLoader().getItemModel());
}
static Iterable<ResourceLocation> getTextures()
{
return textures;
}
}

View file

@ -1,6 +1,5 @@
package net.minecraftforge.client.model;
import java.io.IOException;
import java.util.Collection;
import java.util.List;
@ -23,7 +22,6 @@ import net.minecraftforge.client.MinecraftForgeClient;
import net.minecraftforge.fml.common.FMLLog;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.logging.log4j.Level;
import com.google.common.base.Function;
import com.google.common.base.Optional;
@ -60,16 +58,7 @@ public class MultiLayerModel implements IModelCustomData
ImmutableMap.Builder<Optional<BlockRenderLayer>, IBakedModel> builder = ImmutableMap.builder();
for(Optional<BlockRenderLayer> key : models.keySet())
{
IModel model;
try
{
model = ModelLoaderRegistry.getModel(models.get(key));
}
catch (IOException e)
{
FMLLog.log(Level.ERROR, e, "Couldn't load MultiLayerModel dependency: %s", models.get(key));
model = ModelLoaderRegistry.getMissingModel();
}
IModel model = ModelLoaderRegistry.getModel(models.get(key));
builder.put(key, model.bake(new ModelStateComposition(state, model.getDefaultState()), format, bakedTextureGetter));
}
return builder.build();

View file

@ -62,23 +62,15 @@ public final class Clips
*/
public static IClip getModelClipNode(ResourceLocation modelLocation, String clipName)
{
IModel model;
try
IModel model = ModelLoaderRegistry.getModel(modelLocation);
if(model instanceof IAnimatedModel)
{
model = ModelLoaderRegistry.getModel(modelLocation);
if(model instanceof IAnimatedModel)
Optional<? extends IClip> clip = ((IAnimatedModel)model).getClip(clipName);
if(clip.isPresent())
{
Optional<? extends IClip> clip = ((IAnimatedModel)model).getClip(clipName);
if(clip.isPresent())
{
return new ModelClip(clip.get(), modelLocation, clipName);
}
FMLLog.getLogger().error("Unable to find clip " + clipName + " in the model " + modelLocation);
return new ModelClip(clip.get(), modelLocation, clipName);
}
}
catch (IOException e)
{
FMLLog.getLogger().error("Unable to load model" + modelLocation + " while loading clip " + clipName, e);
FMLLog.getLogger().error("Unable to find clip " + clipName + " in the model " + modelLocation);
}
// FIXME: missing clip?
return new ModelClip(IdentityClip.instance, modelLocation, clipName);

View file

@ -48,6 +48,7 @@ import net.minecraftforge.fml.common.FMLLog;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.commons.lang3.tuple.Triple;
import org.apache.logging.log4j.Level;
import com.google.common.base.Function;
import com.google.common.base.Objects;
@ -94,7 +95,7 @@ public class B3DLoader implements ICustomModelLoader
}
@SuppressWarnings("unchecked")
public IModel loadModel(ResourceLocation modelLocation) throws IOException
public IModel loadModel(ResourceLocation modelLocation)
{
ResourceLocation file = new ResourceLocation(modelLocation.getResourceDomain(), modelLocation.getResourcePath());
if(!cache.containsKey(file))
@ -120,9 +121,8 @@ public class B3DLoader implements ICustomModelLoader
}
catch(IOException e)
{
//FMLLog.log(Level.ERROR, e, "Exception loading model %s with B3D loader, skipping", modelLocation);
FMLLog.log(Level.ERROR, e, "Exception loading model %s with B3D loader, skipping", modelLocation);
cache.put(file, null);
throw e;
}
}
B3DModel model = cache.get(file);

View file

@ -45,7 +45,7 @@ public class OBJLoader implements ICustomModelLoader {
return enabledDomains.contains(modelLocation.getResourceDomain()) && modelLocation.getResourcePath().endsWith(".obj");
}
public IModel loadModel(ResourceLocation modelLocation) throws IOException
public IModel loadModel(ResourceLocation modelLocation)
{
ResourceLocation file = new ResourceLocation(modelLocation.getResourceDomain(), modelLocation.getResourcePath());
if (!cache.containsKey(file))
@ -78,8 +78,7 @@ public class OBJLoader implements ICustomModelLoader {
}
catch (IOException e)
{
// FMLLog.log(Level.ERROR, e, "Exception loading model '%s' with OBJ loader, skipping", modelLocation);
throw e;
cache.put(modelLocation, null);
}
}
OBJModel model = cache.get(file);

View file

@ -194,54 +194,47 @@ public class ModelAnimationDebug
{
public Render<EntityChest> createRenderFor(RenderManager manager)
{
try
/*model = ModelLoaderRegistry.getModel(new ResourceLocation(ModelLoaderRegistryDebug.MODID, "block/chest.b3d"));
if(model instanceof IRetexturableModel)
{
/*model = ModelLoaderRegistry.getModel(new ResourceLocation(ModelLoaderRegistryDebug.MODID, "block/chest.b3d"));
if(model instanceof IRetexturableModel)
model = ((IRetexturableModel)model).retexture(ImmutableMap.of("#chest", "entity/chest/normal"));
}
if(model instanceof IModelCustomData)
{
model = ((IModelCustomData)model).process(ImmutableMap.of("mesh", "[\"Base\", \"Lid\"]"));
}*/
IModel base = ModelLoaderRegistry.getModel(new ResourceLocation(ModelAnimationDebug.MODID, "block/engine"));
IModel ring = ModelLoaderRegistry.getModel(new ResourceLocation(ModelAnimationDebug.MODID, "block/engine_ring"));
ImmutableMap<String, String> textures = ImmutableMap.of(
"base", "blocks/stone",
"front", "blocks/log_oak",
"chamber", "blocks/redstone_block",
"trunk", "blocks/end_stone"
);
base = ModelProcessingHelper.retexture(base, textures);
ring = ModelProcessingHelper.retexture(base, textures);
IModel model = new MultiModel(
new ResourceLocation(ModelAnimationDebug.MODID, "builtin/engine"),
ring,
TRSRTransformation.identity(),
ImmutableMap.of(
"base", Pair.<IModel, IModelState>of(base, TRSRTransformation.identity())
)
);
return new RenderLiving<EntityChest>(manager, new AnimationModelBase<EntityChest>(model, new VertexLighterSmoothAo(Minecraft.getMinecraft().getBlockColors()))
{
model = ((IRetexturableModel)model).retexture(ImmutableMap.of("#chest", "entity/chest/normal"));
}
if(model instanceof IModelCustomData)
{
model = ((IModelCustomData)model).process(ImmutableMap.of("mesh", "[\"Base\", \"Lid\"]"));
}*/
IModel base = ModelLoaderRegistry.getModel(new ResourceLocation(ModelAnimationDebug.MODID, "block/engine"));
IModel ring = ModelLoaderRegistry.getModel(new ResourceLocation(ModelAnimationDebug.MODID, "block/engine_ring"));
ImmutableMap<String, String> textures = ImmutableMap.of(
"base", "blocks/stone",
"front", "blocks/log_oak",
"chamber", "blocks/redstone_block",
"trunk", "blocks/end_stone"
);
base = ModelProcessingHelper.retexture(base, textures);
ring = ModelProcessingHelper.retexture(base, textures);
IModel model = new MultiModel(
new ResourceLocation(ModelAnimationDebug.MODID, "builtin/engine"),
ring,
TRSRTransformation.identity(),
ImmutableMap.of(
"base", Pair.<IModel, IModelState>of(base, TRSRTransformation.identity())
)
);
return new RenderLiving<EntityChest>(manager, new AnimationModelBase<EntityChest>(model, new VertexLighterSmoothAo(Minecraft.getMinecraft().getBlockColors()))
@Override
public void handleEvents(EntityChest chest, float time, Iterable<Event> pastEvents)
{
@Override
public void handleEvents(EntityChest chest, float time, Iterable<Event> pastEvents)
{
chest.handleEvents(time, pastEvents);
}
}, 0.5f)
{
protected ResourceLocation getEntityTexture(EntityChest entity)
{
return TextureMap.locationBlocksTexture;
chest.handleEvents(time, pastEvents);
}
};
}
catch(IOException e)
}, 0.5f)
{
throw new RuntimeException(e);
}
protected ResourceLocation getEntityTexture(EntityChest entity)
{
return TextureMap.locationBlocksTexture;
}
};
}
});
}

View file

@ -255,15 +255,7 @@ public class ModelLoaderRegistryDebug
{
if (world.getTileEntity(pos) == null) world.setTileEntity(pos, new OBJTesseractTileEntity());
OBJTesseractTileEntity tileEntity = (OBJTesseractTileEntity) world.getTileEntity(pos);
IModel model = ModelLoaderRegistry.getMissingModel();
try
{
model = ModelLoaderRegistry.getModel(new ResourceLocation(MODID.toLowerCase() + ":" + "block/tesseract.obj"));
}
catch (IOException e)
{
model = ModelLoaderRegistry.getMissingModel();
}
IModel model = ModelLoaderRegistry.getModel(new ResourceLocation(MODID.toLowerCase() + ":" + "block/tesseract.obj"));
if (player.isSneaking())
{

View file

@ -1,5 +1,3 @@
// vanilla json model, no modifications
{
"elements": [
{