diff --git a/patches/minecraft/net/minecraft/client/renderer/block/model/ItemOverrideList.java.patch b/patches/minecraft/net/minecraft/client/renderer/block/model/ItemOverrideList.java.patch index 6f23a6d7b..c6a455d28 100644 --- a/patches/minecraft/net/minecraft/client/renderer/block/model/ItemOverrideList.java.patch +++ b/patches/minecraft/net/minecraft/client/renderer/block/model/ItemOverrideList.java.patch @@ -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; diff --git a/patches/minecraft/net/minecraft/client/renderer/block/model/ModelBakery.java.patch b/patches/minecraft/net/minecraft/client/renderer/block/model/ModelBakery.java.patch index bdacc607f..f3b09c438 100644 --- a/patches/minecraft/net/minecraft/client/renderer/block/model/ModelBakery.java.patch +++ b/patches/minecraft/net/minecraft/client/renderer/block/model/ModelBakery.java.patch @@ -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 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() ++ registerMultipartVariant(modelblockdefinition, Lists.newArrayList(Iterables.filter(collection, new Predicate() + { + 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 locations) ++ { ++ this.field_188642_k.put(definition, locations); ++ } ++ + private static Map, Set> customVariantNames = Maps.newHashMap(); + + public static void registerItemVariants(Item item, ResourceLocation... names) diff --git a/src/main/java/net/minecraftforge/client/model/BlockStateLoader.java b/src/main/java/net/minecraftforge/client/model/BlockStateLoader.java index 9ee47e39f..4700d2033 100644 --- a/src/main/java/net/minecraftforge/client/model/BlockStateLoader.java +++ b/src/main/java/net/minecraftforge/client/model/BlockStateLoader.java @@ -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()); diff --git a/src/main/java/net/minecraftforge/client/model/ICustomModelLoader.java b/src/main/java/net/minecraftforge/client/model/ICustomModelLoader.java index beeaecbaa..6dd74668f 100644 --- a/src/main/java/net/minecraftforge/client/model/ICustomModelLoader.java +++ b/src/main/java/net/minecraftforge/client/model/ICustomModelLoader.java @@ -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); } diff --git a/src/main/java/net/minecraftforge/client/model/ISmartVariant.java b/src/main/java/net/minecraftforge/client/model/ISmartVariant.java index 8a03b4a3f..5a1a9185d 100644 --- a/src/main/java/net/minecraftforge/client/model/ISmartVariant.java +++ b/src/main/java/net/minecraftforge/client/model/ISmartVariant.java @@ -3,5 +3,5 @@ package net.minecraftforge.client.model; public interface ISmartVariant { - IModel process(IModel base, ModelLoader loader); + IModel process(IModel base); } diff --git a/src/main/java/net/minecraftforge/client/model/ItemLayerModel.java b/src/main/java/net/minecraftforge/client/model/ItemLayerModel.java index df577e336..b8946e100 100644 --- a/src/main/java/net/minecraftforge/client/model/ItemLayerModel.java +++ b/src/main/java/net/minecraftforge/client/model/ItemLayerModel.java @@ -34,15 +34,22 @@ public class ItemLayerModel implements IRetexturableModel public static final ItemLayerModel instance = new ItemLayerModel(ImmutableList.of()); private final ImmutableList textures; + private final ItemOverrideList overrides; public ItemLayerModel(ImmutableList textures) + { + this(textures, ItemOverrideList.NONE); + } + + public ItemLayerModel(ImmutableList textures, ItemOverrideList overrides) { this.textures = textures; + this.overrides = overrides; } public ItemLayerModel(ModelBlock model) { - this(getTextures(model)); + this(getTextures(model), model.createOverrides()); } private static ImmutableList 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 bakedTextureGetter) @@ -98,7 +105,7 @@ public class ItemLayerModel implements IRetexturableModel } TextureAtlasSprite particle = bakedTextureGetter.apply(textures.isEmpty() ? new ResourceLocation("missingno") : textures.get(0)); ImmutableMap 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 transforms; private final IBakedModel otherModel; private final boolean isCulled; + private final ItemOverrideList overrides; - public BakedItemModel(ImmutableList quads, TextureAtlasSprite particle, ImmutableMap transforms, IBakedModel otherModel) + public BakedItemModel(ImmutableList quads, TextureAtlasSprite particle, ImmutableMap 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 getQuads(IBlockState state, EnumFacing side, long rand) { if(side == null) return quads; diff --git a/src/main/java/net/minecraftforge/client/model/ModelDynBucket.java b/src/main/java/net/minecraftforge/client/model/ModelDynBucket.java index c0cf212ef..6b4303126 100644 --- a/src/main/java/net/minecraftforge/client/model/ModelDynBucket.java +++ b/src/main/java/net/minecraftforge/client/model/ModelDynBucket.java @@ -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; } diff --git a/src/main/java/net/minecraftforge/client/model/ModelLoader.java b/src/main/java/net/minecraftforge/client/model/ModelLoader.java index 7607f133e..781bafbe2 100644 --- a/src/main/java/net/minecraftforge/client/model/ModelLoader.java +++ b/src/main/java/net/minecraftforge/client/model/ModelLoader.java @@ -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 stateModels = Maps.newHashMap(); - private final Set textures = Sets.newHashSet(); - private final Set loadingModels = Sets.newHashSet(); private final Set missingVariants = Sets.newHashSet(); private final Map 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 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 e : stateModels.entrySet()) + Map 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 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 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 getDependencies() { Set 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 variants; private final List locations = new ArrayList(); + private final Set textures = Sets.newHashSet(); private final List models = new ArrayList(); private final IModelState defaultState; - public WeightedRandomModel(ModelResourceLocation parent, VariantList variants) + public WeightedRandomModel(ResourceLocation parent, VariantList variants) { this.variants = variants.getVariantList(); ImmutableList.Builder> 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.of(missing, TRSRTransformation.identity())); } @@ -804,7 +695,7 @@ public class ModelLoader extends ModelBakery public Collection getTextures() { - return Collections.emptyList(); + return ImmutableSet.copyOf(textures); } public IBakedModel bake(IModelState state, VertexFormat format, Function 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 partModels; + + public MultipartModel(ResourceLocation location, Multipart multipart) + { + this.location = location; + this.multipart = multipart; + ImmutableMap.Builder 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 getDependencies() + { + return ImmutableSet.of(); + } + + @Override + public Collection getTextures() + { + return ImmutableSet.of(); + } + + // FIXME + @Override + public IBakedModel bake(IModelState state, VertexFormat format, Function 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(); + } + } } diff --git a/src/main/java/net/minecraftforge/client/model/ModelLoaderRegistry.java b/src/main/java/net/minecraftforge/client/model/ModelLoaderRegistry.java index 1342d7ed3..13089f744 100644 --- a/src/main/java/net/minecraftforge/client/model/ModelLoaderRegistry.java +++ b/src/main/java/net/minecraftforge/client/model/ModelLoaderRegistry.java @@ -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 loaders = new HashSet(); - private static final Map cache = new HashMap(); + private static final Set loaders = Sets.newHashSet(); + private static final Map cache = Maps.newHashMap(); + private static final Deque loadingModels = Queues.newArrayDeque(); + private static final Set 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 getTextures() + { + return textures; + } } diff --git a/src/main/java/net/minecraftforge/client/model/MultiLayerModel.java b/src/main/java/net/minecraftforge/client/model/MultiLayerModel.java index 8f16b6765..b8ae6d431 100644 --- a/src/main/java/net/minecraftforge/client/model/MultiLayerModel.java +++ b/src/main/java/net/minecraftforge/client/model/MultiLayerModel.java @@ -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, IBakedModel> builder = ImmutableMap.builder(); for(Optional 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(); diff --git a/src/main/java/net/minecraftforge/client/model/animation/Clips.java b/src/main/java/net/minecraftforge/client/model/animation/Clips.java index 6e760694e..2b5d910c2 100644 --- a/src/main/java/net/minecraftforge/client/model/animation/Clips.java +++ b/src/main/java/net/minecraftforge/client/model/animation/Clips.java @@ -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 clip = ((IAnimatedModel)model).getClip(clipName); + if(clip.isPresent()) { - Optional 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); diff --git a/src/main/java/net/minecraftforge/client/model/b3d/B3DLoader.java b/src/main/java/net/minecraftforge/client/model/b3d/B3DLoader.java index c3e52742b..0424343d6 100644 --- a/src/main/java/net/minecraftforge/client/model/b3d/B3DLoader.java +++ b/src/main/java/net/minecraftforge/client/model/b3d/B3DLoader.java @@ -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); diff --git a/src/main/java/net/minecraftforge/client/model/obj/OBJLoader.java b/src/main/java/net/minecraftforge/client/model/obj/OBJLoader.java index 6d71fe722..935f3ecba 100644 --- a/src/main/java/net/minecraftforge/client/model/obj/OBJLoader.java +++ b/src/main/java/net/minecraftforge/client/model/obj/OBJLoader.java @@ -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); diff --git a/src/test/java/net/minecraftforge/debug/ModelAnimationDebug.java b/src/test/java/net/minecraftforge/debug/ModelAnimationDebug.java index 1951cfbc0..a554c07b9 100644 --- a/src/test/java/net/minecraftforge/debug/ModelAnimationDebug.java +++ b/src/test/java/net/minecraftforge/debug/ModelAnimationDebug.java @@ -194,54 +194,47 @@ public class ModelAnimationDebug { public Render 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 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.of(base, TRSRTransformation.identity()) + ) + ); + return new RenderLiving(manager, new AnimationModelBase(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 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.of(base, TRSRTransformation.identity()) - ) - ); - return new RenderLiving(manager, new AnimationModelBase(model, new VertexLighterSmoothAo(Minecraft.getMinecraft().getBlockColors())) + @Override + public void handleEvents(EntityChest chest, float time, Iterable pastEvents) { - @Override - public void handleEvents(EntityChest chest, float time, Iterable 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; + } + }; } }); } diff --git a/src/test/java/net/minecraftforge/debug/ModelLoaderRegistryDebug.java b/src/test/java/net/minecraftforge/debug/ModelLoaderRegistryDebug.java index caac6a978..8d4147548 100644 --- a/src/test/java/net/minecraftforge/debug/ModelLoaderRegistryDebug.java +++ b/src/test/java/net/minecraftforge/debug/ModelLoaderRegistryDebug.java @@ -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()) { diff --git a/src/test/resources/assets/forgedebugmodelanimation/models/block/engine.json b/src/test/resources/assets/forgedebugmodelanimation/models/block/engine.json index d7ef2789f..a8d0b8ce9 100644 --- a/src/test/resources/assets/forgedebugmodelanimation/models/block/engine.json +++ b/src/test/resources/assets/forgedebugmodelanimation/models/block/engine.json @@ -1,5 +1,3 @@ -// vanilla json model, no modifications - { "elements": [ {