2014-12-28 04:10:54 +00:00
|
|
|
package net.minecraftforge.client.model;
|
|
|
|
|
2015-04-01 13:06:03 +00:00
|
|
|
import java.awt.Color;
|
|
|
|
import java.awt.Graphics2D;
|
2015-02-17 00:36:08 +00:00
|
|
|
import java.awt.image.BufferedImage;
|
2016-01-16 22:51:50 +00:00
|
|
|
import java.io.FileNotFoundException;
|
2014-12-28 04:10:54 +00:00
|
|
|
import java.io.IOException;
|
|
|
|
import java.util.ArrayList;
|
|
|
|
import java.util.Collection;
|
|
|
|
import java.util.Collections;
|
2016-01-16 22:51:50 +00:00
|
|
|
import java.util.Comparator;
|
2015-05-20 09:54:33 +00:00
|
|
|
import java.util.Iterator;
|
2014-12-28 04:10:54 +00:00
|
|
|
import java.util.List;
|
|
|
|
import java.util.Map;
|
|
|
|
import java.util.Map.Entry;
|
|
|
|
import java.util.Set;
|
|
|
|
|
2015-02-04 06:45:23 +00:00
|
|
|
import net.minecraft.block.Block;
|
2014-12-28 04:10:54 +00:00
|
|
|
import net.minecraft.block.state.IBlockState;
|
2015-02-17 00:36:08 +00:00
|
|
|
import net.minecraft.client.Minecraft;
|
2014-12-28 04:10:54 +00:00
|
|
|
import net.minecraft.client.renderer.BlockModelShapes;
|
2015-02-04 06:45:23 +00:00
|
|
|
import net.minecraft.client.renderer.ItemMeshDefinition;
|
|
|
|
import net.minecraft.client.renderer.ItemModelMesher;
|
2015-05-20 09:54:33 +00:00
|
|
|
import net.minecraft.client.renderer.block.model.BlockPart;
|
|
|
|
import net.minecraft.client.renderer.block.model.BlockPartFace;
|
2014-12-28 04:10:54 +00:00
|
|
|
import net.minecraft.client.renderer.block.model.ItemCameraTransforms;
|
2015-12-03 19:38:08 +00:00
|
|
|
import net.minecraft.client.renderer.block.model.ItemCameraTransforms.TransformType;
|
2014-12-28 04:10:54 +00:00
|
|
|
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.ModelBlockDefinition.Variant;
|
|
|
|
import net.minecraft.client.renderer.block.model.ModelBlockDefinition.Variants;
|
2015-02-04 06:45:23 +00:00
|
|
|
import net.minecraft.client.renderer.block.statemap.IStateMapper;
|
2014-12-28 04:10:54 +00:00
|
|
|
import net.minecraft.client.renderer.texture.IIconCreator;
|
|
|
|
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
|
|
|
import net.minecraft.client.renderer.texture.TextureMap;
|
2015-06-28 22:19:10 +00:00
|
|
|
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
|
2014-12-28 04:10:54 +00:00
|
|
|
import net.minecraft.client.renderer.vertex.VertexFormat;
|
|
|
|
import net.minecraft.client.resources.IResourceManager;
|
|
|
|
import net.minecraft.client.resources.model.BuiltInModel;
|
2015-11-13 14:23:37 +00:00
|
|
|
import net.minecraft.client.resources.model.IBakedModel;
|
2014-12-28 04:10:54 +00:00
|
|
|
import net.minecraft.client.resources.model.ModelBakery;
|
|
|
|
import net.minecraft.client.resources.model.ModelResourceLocation;
|
|
|
|
import net.minecraft.client.resources.model.ModelRotation;
|
2015-06-23 13:52:42 +00:00
|
|
|
import net.minecraft.client.resources.model.SimpleBakedModel;
|
2014-12-28 04:10:54 +00:00
|
|
|
import net.minecraft.client.resources.model.WeightedBakedModel;
|
2015-12-15 21:19:04 +00:00
|
|
|
import net.minecraft.init.Items;
|
2014-12-28 04:10:54 +00:00
|
|
|
import net.minecraft.item.Item;
|
2015-12-15 21:19:04 +00:00
|
|
|
import net.minecraft.item.ItemStack;
|
2015-05-20 09:54:33 +00:00
|
|
|
import net.minecraft.util.EnumFacing;
|
2014-12-28 04:10:54 +00:00
|
|
|
import net.minecraft.util.IRegistry;
|
|
|
|
import net.minecraft.util.ResourceLocation;
|
2015-12-15 21:19:04 +00:00
|
|
|
import net.minecraftforge.common.ForgeModContainer;
|
|
|
|
import net.minecraftforge.fluids.Fluid;
|
|
|
|
import net.minecraftforge.fluids.FluidContainerRegistry;
|
|
|
|
import net.minecraftforge.fluids.FluidRegistry;
|
|
|
|
import net.minecraftforge.fluids.FluidStack;
|
2014-12-28 04:10:54 +00:00
|
|
|
import net.minecraftforge.fml.common.FMLLog;
|
2016-01-06 19:53:34 +00:00
|
|
|
import net.minecraftforge.fml.common.ProgressManager;
|
|
|
|
import net.minecraftforge.fml.common.ProgressManager.ProgressBar;
|
2014-12-28 04:10:54 +00:00
|
|
|
import net.minecraftforge.fml.common.registry.GameData;
|
2015-02-04 06:45:23 +00:00
|
|
|
import net.minecraftforge.fml.common.registry.RegistryDelegate;
|
2014-12-28 04:10:54 +00:00
|
|
|
|
2015-02-04 06:45:23 +00:00
|
|
|
import org.apache.commons.lang3.tuple.Pair;
|
2014-12-28 04:10:54 +00:00
|
|
|
|
|
|
|
import com.google.common.base.Function;
|
2015-12-03 19:38:08 +00:00
|
|
|
import com.google.common.base.Optional;
|
2015-06-16 23:03:10 +00:00
|
|
|
import com.google.common.base.Throwables;
|
2014-12-28 04:10:54 +00:00
|
|
|
import com.google.common.collect.ImmutableList;
|
|
|
|
import com.google.common.collect.ImmutableMap;
|
|
|
|
import com.google.common.collect.ImmutableSet;
|
|
|
|
import com.google.common.collect.Lists;
|
2015-02-04 06:45:23 +00:00
|
|
|
import com.google.common.collect.Maps;
|
|
|
|
import com.google.common.collect.Sets;
|
2014-12-28 04:10:54 +00:00
|
|
|
|
2015-11-27 03:38:21 +00:00
|
|
|
@SuppressWarnings("deprecation")
|
2014-12-28 04:10:54 +00:00
|
|
|
public class ModelLoader extends ModelBakery
|
|
|
|
{
|
2016-01-16 22:51:50 +00:00
|
|
|
private final Map<ModelResourceLocation, IModel> stateModels = Maps.newHashMap();
|
|
|
|
private final Set<ResourceLocation> textures = Sets.newHashSet();
|
|
|
|
private final Set<ResourceLocation> loadingModels = Sets.newHashSet();
|
2015-02-04 06:45:23 +00:00
|
|
|
private final Set<ModelResourceLocation> missingVariants = Sets.newHashSet();
|
2016-01-19 22:19:38 +00:00
|
|
|
private final Map<ResourceLocation, Exception> loadingExceptions = Maps.newHashMap();
|
2015-06-16 23:03:10 +00:00
|
|
|
private IModel missingModel = null;
|
2015-10-27 15:34:25 +00:00
|
|
|
private IModel itemModel = new ItemLayerModel(MODEL_GENERATED);
|
2015-02-04 06:45:23 +00:00
|
|
|
|
2016-01-06 19:53:34 +00:00
|
|
|
private ProgressBar blockBar;
|
|
|
|
private ProgressBar itemBar;
|
|
|
|
|
2015-02-04 06:45:23 +00:00
|
|
|
private boolean isLoading = false;
|
|
|
|
public boolean isLoading()
|
|
|
|
{
|
|
|
|
return isLoading;
|
|
|
|
}
|
2014-12-28 04:10:54 +00:00
|
|
|
|
|
|
|
public ModelLoader(IResourceManager manager, TextureMap map, BlockModelShapes shapes)
|
|
|
|
{
|
|
|
|
super(manager, map, shapes);
|
|
|
|
VanillaLoader.instance.setLoader(this);
|
|
|
|
ModelLoaderRegistry.clearModelCache();
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2015-11-13 14:23:37 +00:00
|
|
|
public IRegistry<ModelResourceLocation, IBakedModel> setupModelRegistry()
|
2014-12-28 04:10:54 +00:00
|
|
|
{
|
2015-02-04 06:45:23 +00:00
|
|
|
isLoading = true;
|
2014-12-28 04:10:54 +00:00
|
|
|
loadBlocks();
|
|
|
|
loadItems();
|
2015-06-16 23:03:10 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
stateModels.put(MODEL_MISSING, missingModel);
|
2014-12-28 04:10:54 +00:00
|
|
|
textures.remove(TextureMap.LOCATION_MISSING_TEXTURE);
|
|
|
|
textures.addAll(LOCATIONS_BUILTIN_TEXTURES);
|
|
|
|
textureMap.loadSprites(resourceManager, new IIconCreator()
|
|
|
|
{
|
|
|
|
public void registerSprites(TextureMap map)
|
|
|
|
{
|
|
|
|
for(ResourceLocation t : textures)
|
|
|
|
{
|
2015-06-23 13:52:42 +00:00
|
|
|
map.registerSprite(t);
|
2014-12-28 04:10:54 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
2015-06-18 11:14:46 +00:00
|
|
|
Function<ResourceLocation, TextureAtlasSprite> textureGetter = new Function<ResourceLocation, TextureAtlasSprite>()
|
|
|
|
{
|
|
|
|
public TextureAtlasSprite apply(ResourceLocation location)
|
|
|
|
{
|
|
|
|
return Minecraft.getMinecraft().getTextureMapBlocks().getAtlasSprite(location.toString());
|
|
|
|
}
|
|
|
|
};
|
2015-06-28 22:19:10 +00:00
|
|
|
IFlexibleBakedModel missingBaked = missingModel.bake(missingModel.getDefaultState(), DefaultVertexFormats.ITEM, textureGetter);
|
2015-06-16 23:03:10 +00:00
|
|
|
for (Entry<ModelResourceLocation, IModel> e : stateModels.entrySet())
|
2014-12-28 04:10:54 +00:00
|
|
|
{
|
2015-06-04 15:07:03 +00:00
|
|
|
if(e.getValue() == getMissingModel())
|
|
|
|
{
|
|
|
|
bakedRegistry.putObject(e.getKey(), missingBaked);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2015-06-28 22:19:10 +00:00
|
|
|
bakedRegistry.putObject(e.getKey(), e.getValue().bake(e.getValue().getDefaultState(), DefaultVertexFormats.ITEM, textureGetter));
|
2015-06-04 15:07:03 +00:00
|
|
|
}
|
2014-12-28 04:10:54 +00:00
|
|
|
}
|
|
|
|
return bakedRegistry;
|
|
|
|
}
|
|
|
|
|
|
|
|
private void loadBlocks()
|
|
|
|
{
|
|
|
|
Map<IBlockState, ModelResourceLocation> stateMap = blockModelShapes.getBlockStateMapper().putAllStateModelLocations();
|
2016-01-16 22:51:50 +00:00
|
|
|
List<ModelResourceLocation> variants = Lists.newArrayList(stateMap.values());
|
2015-02-02 21:06:57 +00:00
|
|
|
variants.add(new ModelResourceLocation("minecraft:item_frame", "normal")); //Vanilla special cases item_frames so must we
|
|
|
|
variants.add(new ModelResourceLocation("minecraft:item_frame", "map"));
|
2016-01-16 22:51:50 +00:00
|
|
|
Collections.sort(variants, new Comparator<ModelResourceLocation>()
|
|
|
|
{
|
|
|
|
public int compare(ModelResourceLocation v1, ModelResourceLocation v2)
|
|
|
|
{
|
|
|
|
return v1.toString().compareTo(v2.toString());
|
|
|
|
}
|
|
|
|
});
|
2016-01-06 23:09:29 +00:00
|
|
|
blockBar = ProgressManager.push("ModelLoader: blocks", variants.size());
|
2016-01-16 22:51:50 +00:00
|
|
|
for(ModelResourceLocation variant : variants)
|
|
|
|
{
|
|
|
|
loadVariants(ImmutableList.of(variant));
|
|
|
|
blockBar.step(variant.toString());
|
|
|
|
}
|
2016-01-06 19:53:34 +00:00
|
|
|
ProgressManager.pop(blockBar);
|
2014-12-28 04:10:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
protected void registerVariant(ModelBlockDefinition definition, ModelResourceLocation location)
|
|
|
|
{
|
2016-01-06 23:09:29 +00:00
|
|
|
Variants variants = null;
|
2016-01-06 19:53:34 +00:00
|
|
|
try
|
2014-12-28 04:10:54 +00:00
|
|
|
{
|
2016-01-06 23:09:29 +00:00
|
|
|
variants = definition.getVariants(location.getVariant());
|
|
|
|
}
|
|
|
|
catch(MissingVariantException e)
|
|
|
|
{
|
|
|
|
missingVariants.add(location);
|
|
|
|
}
|
|
|
|
if (variants != null && !variants.getVariants().isEmpty())
|
|
|
|
{
|
2014-12-28 04:10:54 +00:00
|
|
|
try
|
|
|
|
{
|
2016-01-06 23:09:29 +00:00
|
|
|
stateModels.put(location, new WeightedRandomModel(location, variants));
|
2016-01-06 19:53:34 +00:00
|
|
|
}
|
2016-01-06 23:09:29 +00:00
|
|
|
catch(Throwable e)
|
2016-01-06 19:53:34 +00:00
|
|
|
{
|
2016-01-06 23:09:29 +00:00
|
|
|
throw new RuntimeException(e);
|
2014-12-28 04:10:54 +00:00
|
|
|
}
|
2016-01-06 19:53:34 +00:00
|
|
|
}
|
2014-12-28 04:10:54 +00:00
|
|
|
}
|
|
|
|
|
2016-01-19 22:19:38 +00:00
|
|
|
private void storeException(ResourceLocation location, Exception exception)
|
2016-01-16 22:51:50 +00:00
|
|
|
{
|
|
|
|
loadingExceptions.put(location, exception);
|
|
|
|
}
|
|
|
|
|
2016-01-19 22:19:38 +00:00
|
|
|
@Override
|
|
|
|
protected ModelBlockDefinition getModelBlockDefinition(ResourceLocation location)
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
return super.getModelBlockDefinition(location);
|
|
|
|
}
|
|
|
|
catch (Exception exception)
|
|
|
|
{
|
|
|
|
storeException(location, new Exception("Could not load model definition for variant " + location, exception));
|
|
|
|
}
|
|
|
|
return new ModelBlockDefinition(new ArrayList<ModelBlockDefinition>());
|
|
|
|
}
|
|
|
|
|
2014-12-28 04:10:54 +00:00
|
|
|
private void loadItems()
|
|
|
|
{
|
|
|
|
registerVariantNames();
|
2016-01-16 22:51:50 +00:00
|
|
|
List<String> itemVariants = Lists.newArrayList();
|
|
|
|
for(Item item : GameData.getItemRegistry().typeSafeIterable())
|
2016-01-06 19:53:34 +00:00
|
|
|
{
|
2016-01-16 22:51:50 +00:00
|
|
|
itemVariants.addAll(getVariantNames(item));
|
2016-01-06 19:53:34 +00:00
|
|
|
}
|
2016-01-16 22:51:50 +00:00
|
|
|
Collections.sort(itemVariants);
|
|
|
|
itemBar = ProgressManager.push("ModelLoader: items", itemVariants.size());
|
|
|
|
for(String s : itemVariants)
|
2014-12-28 04:10:54 +00:00
|
|
|
{
|
2016-01-16 22:51:50 +00:00
|
|
|
ResourceLocation file = getItemLocation(s);
|
|
|
|
ModelResourceLocation memory = getInventoryVariant(s);
|
|
|
|
itemBar.step(memory.toString());
|
|
|
|
IModel model = null;
|
|
|
|
try
|
2014-12-28 04:10:54 +00:00
|
|
|
{
|
2016-01-16 22:51:50 +00:00
|
|
|
// default loading
|
|
|
|
model = getModel(file);
|
|
|
|
if (model == null)
|
2015-02-04 06:45:23 +00:00
|
|
|
{
|
2016-01-16 22:51:50 +00:00
|
|
|
model = getMissingModel();
|
2015-06-16 23:03:10 +00:00
|
|
|
}
|
2016-01-16 22:51:50 +00:00
|
|
|
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
|
2015-06-16 23:03:10 +00:00
|
|
|
{
|
2016-01-16 22:51:50 +00:00
|
|
|
registerVariant(getModelBlockDefinition(memory), memory);
|
2015-06-16 23:03:10 +00:00
|
|
|
}
|
2016-01-16 22:51:50 +00:00
|
|
|
catch (Exception exception)
|
2015-06-16 23:03:10 +00:00
|
|
|
{
|
2016-01-16 22:51:50 +00:00
|
|
|
storeException(memory, new Exception("Could not load item model either from the normal location " + file + " or from the blockstate", exception));
|
2015-02-04 06:45:23 +00:00
|
|
|
}
|
2014-12-28 04:10:54 +00:00
|
|
|
}
|
2016-01-16 22:51:50 +00:00
|
|
|
catch (Exception exception)
|
|
|
|
{
|
|
|
|
storeException(memory, exception);
|
|
|
|
}
|
2014-12-28 04:10:54 +00:00
|
|
|
}
|
2016-01-06 19:53:34 +00:00
|
|
|
ProgressManager.pop(itemBar);
|
2015-12-15 21:19:04 +00:00
|
|
|
|
|
|
|
// replace vanilla bucket models if desired. done afterwards for performance reasons
|
|
|
|
if(ForgeModContainer.replaceVanillaBucketModel)
|
|
|
|
{
|
2015-12-29 12:20:36 +00:00
|
|
|
// ensure the bucket model is loaded
|
|
|
|
if(!stateModels.containsKey(ModelDynBucket.LOCATION))
|
|
|
|
{
|
|
|
|
// load forges blockstate json for it
|
2016-01-18 18:35:23 +00:00
|
|
|
try
|
|
|
|
{
|
|
|
|
registerVariant(getModelBlockDefinition(ModelDynBucket.LOCATION), ModelDynBucket.LOCATION);
|
|
|
|
}
|
|
|
|
catch (Exception exception)
|
|
|
|
{
|
|
|
|
FMLLog.getLogger().error("Could not load the forge bucket model from the blockstate", exception);
|
|
|
|
return;
|
|
|
|
}
|
2015-12-29 12:20:36 +00:00
|
|
|
}
|
|
|
|
|
2015-12-15 21:19:04 +00:00
|
|
|
// empty bucket
|
|
|
|
for(String s : getVariantNames(Items.bucket))
|
|
|
|
{
|
2015-12-24 03:06:38 +00:00
|
|
|
ModelResourceLocation memory = getInventoryVariant(s);
|
2015-12-15 21:19:04 +00:00
|
|
|
try
|
|
|
|
{
|
|
|
|
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);
|
|
|
|
setBucketModel(Items.lava_bucket);
|
|
|
|
// milk bucket only replaced if some mod adds milk
|
|
|
|
if(FluidRegistry.isFluidRegistered("milk"))
|
|
|
|
{
|
|
|
|
// can the milk be put into a bucket?
|
|
|
|
Fluid milk = FluidRegistry.getFluid("milk");
|
|
|
|
FluidStack milkStack = new FluidStack(milk, FluidContainerRegistry.BUCKET_VOLUME);
|
|
|
|
if(FluidContainerRegistry.getContainerCapacity(milkStack, new ItemStack(Items.bucket)) == FluidContainerRegistry.BUCKET_VOLUME)
|
|
|
|
{
|
|
|
|
setBucketModel(Items.milk_bucket);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// milk bucket if no milk fluid is present
|
|
|
|
for(String s : getVariantNames(Items.milk_bucket))
|
|
|
|
{
|
2015-12-24 03:06:38 +00:00
|
|
|
ModelResourceLocation memory = getInventoryVariant(s);
|
2015-12-15 21:19:04 +00:00
|
|
|
try
|
|
|
|
{
|
|
|
|
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
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void setBucketModel(Item item)
|
|
|
|
{
|
|
|
|
for(String s : getVariantNames(item))
|
|
|
|
{
|
2015-12-24 03:06:38 +00:00
|
|
|
ModelResourceLocation memory = getInventoryVariant(s);
|
2015-12-15 21:19:04 +00:00
|
|
|
IModel model = stateModels.get(ModelDynBucket.LOCATION);
|
2015-12-29 12:20:36 +00:00
|
|
|
if(model != null)
|
|
|
|
{
|
|
|
|
stateModels.put(memory, model);
|
|
|
|
}
|
2015-12-15 21:19:04 +00:00
|
|
|
}
|
2014-12-28 04:10:54 +00:00
|
|
|
}
|
|
|
|
|
2015-12-24 03:06:38 +00:00
|
|
|
public static ModelResourceLocation getInventoryVariant(String s)
|
|
|
|
{
|
|
|
|
if(s.contains("#"))
|
|
|
|
{
|
|
|
|
return new ModelResourceLocation(s);
|
|
|
|
}
|
|
|
|
return new ModelResourceLocation(s, "inventory");
|
|
|
|
}
|
|
|
|
|
2015-06-16 23:03:10 +00:00
|
|
|
public IModel getModel(ResourceLocation location) throws IOException
|
2014-12-28 04:10:54 +00:00
|
|
|
{
|
|
|
|
if(!ModelLoaderRegistry.loaded(location)) loadAnyModel(location);
|
|
|
|
return ModelLoaderRegistry.getModel(location);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
protected ResourceLocation getModelLocation(ResourceLocation model)
|
|
|
|
{
|
|
|
|
return new ResourceLocation(model.getResourceDomain(), model.getResourcePath() + ".json");
|
|
|
|
}
|
2015-10-27 14:40:05 +00:00
|
|
|
|
2015-06-16 23:03:10 +00:00
|
|
|
private void loadAnyModel(ResourceLocation location) throws IOException
|
2014-12-28 04:10:54 +00:00
|
|
|
{
|
|
|
|
if(loadingModels.contains(location))
|
|
|
|
{
|
|
|
|
throw new IllegalStateException("circular model dependencies involving model " + location);
|
|
|
|
}
|
|
|
|
loadingModels.add(location);
|
2015-08-19 21:09:01 +00:00
|
|
|
try
|
|
|
|
{
|
|
|
|
IModel model = ModelLoaderRegistry.getModel(location);
|
2015-12-17 01:40:34 +00:00
|
|
|
resolveDependencies(model);
|
2015-08-19 21:09:01 +00:00
|
|
|
}
|
|
|
|
finally
|
2014-12-28 04:10:54 +00:00
|
|
|
{
|
2015-08-19 21:09:01 +00:00
|
|
|
loadingModels.remove(location);
|
2014-12-28 04:10:54 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-01-06 19:06:36 +00:00
|
|
|
IModel getVariantModel(ModelResourceLocation location)
|
2016-01-06 19:00:43 +00:00
|
|
|
{
|
|
|
|
loadVariants(ImmutableList.of(location));
|
|
|
|
IModel model = stateModels.get(location);
|
|
|
|
if(model == null) model = getMissingModel();
|
|
|
|
return model;
|
|
|
|
}
|
|
|
|
|
2015-12-17 01:40:34 +00:00
|
|
|
private void resolveDependencies(IModel model) throws IOException
|
|
|
|
{
|
|
|
|
for (ResourceLocation dep : model.getDependencies())
|
|
|
|
{
|
|
|
|
if(dep instanceof ModelResourceLocation)
|
|
|
|
{
|
2016-01-06 19:00:43 +00:00
|
|
|
getVariantModel((ModelResourceLocation)dep);
|
2015-12-17 01:40:34 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
getModel(dep);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
textures.addAll(model.getTextures());
|
|
|
|
}
|
|
|
|
|
2015-05-20 09:54:33 +00:00
|
|
|
private class VanillaModelWrapper implements IRetexturableModel
|
2014-12-28 04:10:54 +00:00
|
|
|
{
|
|
|
|
private final ResourceLocation location;
|
|
|
|
private final ModelBlock model;
|
|
|
|
|
|
|
|
public VanillaModelWrapper(ResourceLocation location, ModelBlock model)
|
|
|
|
{
|
|
|
|
this.location = location;
|
|
|
|
this.model = model;
|
|
|
|
}
|
|
|
|
|
|
|
|
public Collection<ResourceLocation> getDependencies()
|
|
|
|
{
|
|
|
|
if(model.getParentLocation() == null || model.getParentLocation().getResourcePath().startsWith("builtin/")) return Collections.emptyList();
|
|
|
|
return Collections.singletonList(model.getParentLocation());
|
|
|
|
}
|
|
|
|
|
|
|
|
public Collection<ResourceLocation> getTextures()
|
|
|
|
{
|
|
|
|
// setting parent here to make textures resolve properly
|
|
|
|
if(model.getParentLocation() != null)
|
|
|
|
{
|
2015-10-27 15:34:25 +00:00
|
|
|
if(model.getParentLocation().getResourcePath().equals("builtin/generated"))
|
2014-12-28 04:10:54 +00:00
|
|
|
{
|
2015-10-27 15:34:25 +00:00
|
|
|
model.parent = MODEL_GENERATED;
|
2014-12-28 04:10:54 +00:00
|
|
|
}
|
2015-10-27 15:34:25 +00:00
|
|
|
else
|
2014-12-28 04:10:54 +00:00
|
|
|
{
|
2015-10-27 15:34:25 +00:00
|
|
|
try
|
2015-06-16 23:03:10 +00:00
|
|
|
{
|
2015-10-27 15:34:25 +00:00
|
|
|
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");
|
|
|
|
}
|
2015-06-16 23:03:10 +00:00
|
|
|
}
|
2015-10-27 15:34:25 +00:00
|
|
|
catch (IOException e)
|
2015-06-16 23:03:10 +00:00
|
|
|
{
|
2015-10-27 15:34:25 +00:00
|
|
|
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");
|
|
|
|
}
|
2015-06-16 23:03:10 +00:00
|
|
|
}
|
2014-12-28 04:10:54 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ImmutableSet.Builder<ResourceLocation> builder = ImmutableSet.builder();
|
|
|
|
|
|
|
|
if(hasItemModel(model))
|
|
|
|
{
|
|
|
|
for(String s : (List<String>)ItemModelGenerator.LAYERS)
|
|
|
|
{
|
|
|
|
String r = model.resolveTextureName(s);
|
|
|
|
ResourceLocation loc = new ResourceLocation(r);
|
|
|
|
if(!r.equals(s))
|
|
|
|
{
|
|
|
|
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());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2015-02-08 12:24:30 +00:00
|
|
|
for(String s : (Iterable<String>)model.textures.values())
|
2014-12-28 04:10:54 +00:00
|
|
|
{
|
2015-02-08 12:24:30 +00:00
|
|
|
if(!s.startsWith("#"))
|
|
|
|
{
|
|
|
|
builder.add(new ResourceLocation(s));
|
|
|
|
}
|
2014-12-28 04:10:54 +00:00
|
|
|
}
|
|
|
|
return builder.build();
|
|
|
|
}
|
|
|
|
|
|
|
|
public IFlexibleBakedModel bake(IModelState state, VertexFormat format, Function<ResourceLocation, TextureAtlasSprite> bakedTextureGetter)
|
|
|
|
{
|
|
|
|
if(!Attributes.moreSpecific(format, Attributes.DEFAULT_BAKED_FORMAT))
|
|
|
|
{
|
|
|
|
throw new IllegalArgumentException("can't bake vanilla models to the format that doesn't fit into the default one: " + format);
|
|
|
|
}
|
|
|
|
ModelBlock model = this.model;
|
2015-12-03 19:38:08 +00:00
|
|
|
if(model == null) return getMissingModel().bake(getMissingModel().getDefaultState(), format, bakedTextureGetter);
|
|
|
|
|
|
|
|
List<TRSRTransformation> newTransforms = Lists.newArrayList();
|
|
|
|
for(int i = 0; i < model.getElements().size(); i++)
|
|
|
|
{
|
|
|
|
newTransforms.add(null);
|
|
|
|
}
|
|
|
|
|
2015-11-09 21:03:39 +00:00
|
|
|
ItemCameraTransforms transforms = model.func_181682_g();
|
2015-10-27 14:40:05 +00:00
|
|
|
boolean uvlock = false;
|
|
|
|
if(state instanceof UVLock)
|
|
|
|
{
|
|
|
|
uvlock = true;
|
|
|
|
state = ((UVLock)state).getParent();
|
|
|
|
}
|
2015-12-03 19:38:08 +00:00
|
|
|
Map<TransformType, TRSRTransformation> tMap = Maps.newHashMap();
|
|
|
|
tMap.putAll(IPerspectiveAwareModel.MapWrapper.getTransforms(transforms));
|
|
|
|
tMap.putAll(IPerspectiveAwareModel.MapWrapper.getTransforms(state));
|
|
|
|
IModelState perState = new SimpleModelState(ImmutableMap.copyOf(tMap));
|
|
|
|
|
2015-06-22 22:03:16 +00:00
|
|
|
if(hasItemModel(model))
|
|
|
|
{
|
|
|
|
return new ItemLayerModel(model).bake(perState, format, bakedTextureGetter);
|
|
|
|
}
|
2015-06-23 12:55:58 +00:00
|
|
|
if(isCustomRenderer(model)) return new IFlexibleBakedModel.Wrapper(new BuiltInModel(transforms), format);
|
2015-12-03 19:38:08 +00:00
|
|
|
return bakeNormal(model, perState, state.apply(Optional.<IModelPart>absent()).or(TRSRTransformation.identity()), newTransforms, format, bakedTextureGetter, uvlock);
|
2015-06-23 13:52:42 +00:00
|
|
|
}
|
|
|
|
|
2015-12-03 19:38:08 +00:00
|
|
|
private IFlexibleBakedModel bakeNormal(ModelBlock model, IModelState perState, final TRSRTransformation modelState, List<TRSRTransformation> newTransforms, VertexFormat format, Function<ResourceLocation, TextureAtlasSprite> bakedTextureGetter, boolean uvLocked)
|
2015-06-23 13:52:42 +00:00
|
|
|
{
|
|
|
|
TextureAtlasSprite particle = bakedTextureGetter.apply(new ResourceLocation(model.resolveTextureName("particle")));
|
|
|
|
SimpleBakedModel.Builder builder = (new SimpleBakedModel.Builder(model)).setTexture(particle);
|
2015-12-03 19:38:08 +00:00
|
|
|
for(int i = 0; i < model.getElements().size(); i++)
|
2015-06-23 13:52:42 +00:00
|
|
|
{
|
2015-12-03 19:38:08 +00:00
|
|
|
BlockPart part = model.getElements().get(i);
|
|
|
|
TRSRTransformation transformation = modelState;
|
|
|
|
if(newTransforms.get(i) != null)
|
|
|
|
{
|
|
|
|
transformation = transformation.compose(newTransforms.get(i));
|
|
|
|
}
|
2015-06-23 13:52:42 +00:00
|
|
|
for(Map.Entry<EnumFacing, BlockPartFace> e : (Iterable<Map.Entry<EnumFacing, BlockPartFace>>)part.mapFaces.entrySet())
|
|
|
|
{
|
|
|
|
TextureAtlasSprite textureatlassprite1 = bakedTextureGetter.apply(new ResourceLocation(model.resolveTextureName(e.getValue().texture)));
|
|
|
|
|
2015-12-03 19:38:08 +00:00
|
|
|
if (e.getValue().cullFace == null || !TRSRTransformation.isInteger(transformation.getMatrix()))
|
2015-06-23 13:52:42 +00:00
|
|
|
{
|
2015-12-03 19:38:08 +00:00
|
|
|
builder.addGeneralQuad(makeBakedQuad(part, e.getValue(), textureatlassprite1, e.getKey(), transformation, uvLocked));
|
2015-06-23 13:52:42 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2015-12-03 19:38:08 +00:00
|
|
|
builder.addFaceQuad(modelState.rotate(e.getValue().cullFace), makeBakedQuad(part, e.getValue(), textureatlassprite1, e.getKey(), transformation, uvLocked));
|
2015-06-23 13:52:42 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-12-03 19:38:08 +00:00
|
|
|
return new ISmartBlockModel.PerspectiveWrapper(new IPerspectiveAwareModel.MapWrapper(new IFlexibleBakedModel.Wrapper(builder.makeBakedModel(), format), perState))
|
|
|
|
{
|
|
|
|
public IBakedModel handleBlockState(IBlockState state)
|
|
|
|
{
|
|
|
|
return VanillaModelWrapper.this.handleBlockState(parent, modelState, state);
|
|
|
|
}
|
|
|
|
};
|
2014-12-28 04:10:54 +00:00
|
|
|
}
|
|
|
|
|
2015-12-03 19:38:08 +00:00
|
|
|
private IBakedModel handleBlockState(IFlexibleBakedModel model, TRSRTransformation modelState, IBlockState state)
|
2014-12-28 04:10:54 +00:00
|
|
|
{
|
2015-12-03 19:38:08 +00:00
|
|
|
return model;
|
2014-12-28 04:10:54 +00:00
|
|
|
}
|
2015-05-20 09:54:33 +00:00
|
|
|
|
|
|
|
@Override
|
|
|
|
public IModel retexture(ImmutableMap<String, String> textures)
|
|
|
|
{
|
|
|
|
if (textures.isEmpty())
|
|
|
|
return this;
|
2015-06-09 19:36:36 +00:00
|
|
|
|
2015-05-20 09:54:33 +00:00
|
|
|
List<BlockPart> elements = Lists.newArrayList(); //We have to duplicate this so we can edit it below.
|
|
|
|
for (BlockPart part : (List<BlockPart>)this.model.getElements())
|
|
|
|
{
|
|
|
|
elements.add(new BlockPart(part.positionFrom, part.positionTo, Maps.newHashMap(part.mapFaces), part.partRotation, part.shade));
|
|
|
|
}
|
|
|
|
|
|
|
|
ModelBlock neweModel = new ModelBlock(this.model.getParentLocation(), elements,
|
|
|
|
Maps.newHashMap(this.model.textures), this.model.isAmbientOcclusion(), this.model.isGui3d(), //New Textures man VERY IMPORTANT
|
2015-11-09 21:03:39 +00:00
|
|
|
model.func_181682_g());
|
2015-05-20 09:54:33 +00:00
|
|
|
neweModel.name = this.model.name;
|
|
|
|
neweModel.parent = this.model.parent;
|
|
|
|
|
|
|
|
Set<String> removed = Sets.newHashSet();
|
2015-06-09 19:36:36 +00:00
|
|
|
|
2015-05-20 09:54:33 +00:00
|
|
|
for (Entry<String, String> e : textures.entrySet())
|
|
|
|
{
|
2015-06-09 19:36:36 +00:00
|
|
|
if ("".equals(e.getValue()))
|
2015-05-20 09:54:33 +00:00
|
|
|
{
|
|
|
|
removed.add(e.getKey());
|
|
|
|
neweModel.textures.remove(e.getKey());
|
|
|
|
}
|
|
|
|
else
|
|
|
|
neweModel.textures.put(e.getKey(), e.getValue());
|
|
|
|
}
|
|
|
|
|
|
|
|
// Map the model's texture references as if it was the parent of a model with the retexture map as its textures.
|
|
|
|
Map<String, String> remapped = Maps.newHashMap();
|
2015-06-09 19:36:36 +00:00
|
|
|
|
2015-05-20 09:54:33 +00:00
|
|
|
for (Entry<String, String> e : (Set<Entry<String, String>>)neweModel.textures.entrySet())
|
|
|
|
{
|
|
|
|
if (e.getValue().startsWith("#"))
|
|
|
|
{
|
|
|
|
String key = e.getValue().substring(1);
|
|
|
|
if (neweModel.textures.containsKey(key))
|
|
|
|
remapped.put(e.getKey(), (String)neweModel.textures.get(key));
|
|
|
|
}
|
|
|
|
}
|
2015-06-09 19:36:36 +00:00
|
|
|
|
2015-05-20 09:54:33 +00:00
|
|
|
neweModel.textures.putAll(remapped);
|
2015-06-09 19:36:36 +00:00
|
|
|
|
2015-05-20 09:54:33 +00:00
|
|
|
//Remove any faces that use a null texture, this is for performance reasons, also allows some cool layering stuff.
|
|
|
|
for (BlockPart part : (List<BlockPart>)neweModel.getElements())
|
|
|
|
{
|
|
|
|
Iterator<Entry<EnumFacing, BlockPartFace>> itr = part.mapFaces.entrySet().iterator();
|
|
|
|
while (itr.hasNext())
|
|
|
|
{
|
|
|
|
Entry<EnumFacing, BlockPartFace> entry = itr.next();
|
|
|
|
if (removed.contains(entry.getValue().texture))
|
|
|
|
itr.remove();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return new VanillaModelWrapper(location, neweModel);
|
|
|
|
}
|
2015-12-03 19:38:08 +00:00
|
|
|
|
|
|
|
public IModelState getDefaultState()
|
|
|
|
{
|
|
|
|
return ModelRotation.X0_Y0;
|
|
|
|
}
|
2014-12-28 04:10:54 +00:00
|
|
|
}
|
|
|
|
|
2015-02-03 07:33:32 +00:00
|
|
|
public static class UVLock implements IModelState
|
|
|
|
{
|
2015-10-27 14:40:05 +00:00
|
|
|
private final IModelState parent;
|
|
|
|
|
|
|
|
public UVLock(IModelState parent)
|
|
|
|
{
|
|
|
|
this.parent = parent;
|
|
|
|
}
|
2015-02-03 07:33:32 +00:00
|
|
|
|
2015-10-27 14:40:05 +00:00
|
|
|
public IModelState getParent()
|
2015-02-03 07:33:32 +00:00
|
|
|
{
|
2015-10-27 14:40:05 +00:00
|
|
|
return parent;
|
2015-02-03 07:33:32 +00:00
|
|
|
}
|
|
|
|
|
2015-12-03 19:38:08 +00:00
|
|
|
public Optional<TRSRTransformation> apply(Optional<? extends IModelPart> part)
|
2015-02-03 07:33:32 +00:00
|
|
|
{
|
2015-10-27 14:40:05 +00:00
|
|
|
return parent.apply(part);
|
2015-02-03 07:33:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-12-28 04:10:54 +00:00
|
|
|
private class WeightedRandomModel implements IModel
|
|
|
|
{
|
|
|
|
private final List<Variant> variants;
|
|
|
|
private final List<ResourceLocation> locations = new ArrayList<ResourceLocation>();
|
|
|
|
private final List<IModel> models = new ArrayList<IModel>();
|
|
|
|
private final IModelState defaultState;
|
|
|
|
|
2015-06-16 23:03:10 +00:00
|
|
|
public WeightedRandomModel(ModelResourceLocation parent, Variants variants)
|
2014-12-28 04:10:54 +00:00
|
|
|
{
|
|
|
|
this.variants = variants.getVariants();
|
2016-01-06 19:00:43 +00:00
|
|
|
ImmutableList.Builder<Pair<IModel, IModelState>> builder = ImmutableList.builder();
|
2015-06-16 23:03:10 +00:00
|
|
|
for (Variant v : (List<Variant>)variants.getVariants())
|
2014-12-28 04:10:54 +00:00
|
|
|
{
|
|
|
|
ResourceLocation loc = v.getModelLocation();
|
|
|
|
locations.add(loc);
|
2015-05-20 09:54:33 +00:00
|
|
|
|
2015-06-16 23:03:10 +00:00
|
|
|
IModel model = null;
|
|
|
|
try
|
|
|
|
{
|
|
|
|
model = getModel(loc);
|
|
|
|
}
|
|
|
|
catch (Exception e)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Vanilla eats this, which makes it only show variants that have models.
|
|
|
|
* 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();
|
|
|
|
}
|
|
|
|
|
2015-05-20 09:54:33 +00:00
|
|
|
if (v instanceof ISmartVariant)
|
|
|
|
{
|
|
|
|
model = ((ISmartVariant)v).process(model, ModelLoader.this);
|
2015-12-17 01:40:34 +00:00
|
|
|
try
|
|
|
|
{
|
|
|
|
resolveDependencies(model);
|
|
|
|
}
|
|
|
|
catch (IOException e)
|
|
|
|
{
|
|
|
|
FMLLog.getLogger().error("Exception resolving indirect dependencies for model" + loc, e);
|
|
|
|
}
|
2015-05-20 09:54:33 +00:00
|
|
|
textures.addAll(model.getTextures()); // Kick this, just in case.
|
|
|
|
}
|
|
|
|
|
2014-12-28 04:10:54 +00:00
|
|
|
models.add(model);
|
2016-01-06 19:00:43 +00:00
|
|
|
builder.add(Pair.of(model, v.getState()));
|
2014-12-28 04:10:54 +00:00
|
|
|
}
|
2015-06-16 23:03:10 +00:00
|
|
|
|
|
|
|
if (models.size() == 0) //If all variants are missing, add one with the missing model and default rotation.
|
|
|
|
{
|
|
|
|
IModel missing = getMissingModel();
|
|
|
|
models.add(missing);
|
2016-01-06 19:00:43 +00:00
|
|
|
builder.add(Pair.<IModel, IModelState>of(missing, TRSRTransformation.identity()));
|
2015-06-16 23:03:10 +00:00
|
|
|
}
|
|
|
|
|
2016-01-06 19:00:43 +00:00
|
|
|
defaultState = new MultiModelState(builder.build());
|
2014-12-28 04:10:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public Collection<ResourceLocation> getDependencies()
|
|
|
|
{
|
|
|
|
return ImmutableList.copyOf(locations);
|
|
|
|
}
|
|
|
|
|
|
|
|
public Collection<ResourceLocation> getTextures()
|
|
|
|
{
|
|
|
|
return Collections.emptyList();
|
|
|
|
}
|
|
|
|
|
2015-02-03 07:33:32 +00:00
|
|
|
private IModelState addUV(boolean uv, IModelState state)
|
|
|
|
{
|
|
|
|
if(uv) return new UVLock(state);
|
|
|
|
return state;
|
|
|
|
}
|
|
|
|
|
2014-12-28 04:10:54 +00:00
|
|
|
public IFlexibleBakedModel bake(IModelState state, VertexFormat format, Function<ResourceLocation, TextureAtlasSprite> bakedTextureGetter)
|
|
|
|
{
|
|
|
|
if(!Attributes.moreSpecific(format, Attributes.DEFAULT_BAKED_FORMAT))
|
|
|
|
{
|
|
|
|
throw new IllegalArgumentException("can't bake vanilla weighted models to the format that doesn't fit into the default one: " + format);
|
|
|
|
}
|
|
|
|
if(variants.size() == 1)
|
|
|
|
{
|
|
|
|
Variant v = variants.get(0);
|
|
|
|
IModel model = models.get(0);
|
2016-01-06 19:00:43 +00:00
|
|
|
return model.bake(addUV(v.isUvLocked(), MultiModelState.getPartState(state, model, 0)), format, bakedTextureGetter);
|
2014-12-28 04:10:54 +00:00
|
|
|
}
|
|
|
|
WeightedBakedModel.Builder builder = new WeightedBakedModel.Builder();
|
|
|
|
for(int i = 0; i < variants.size(); i++)
|
|
|
|
{
|
|
|
|
IModel model = models.get(i);
|
2015-02-03 07:33:32 +00:00
|
|
|
Variant v = variants.get(i);
|
2016-01-06 19:00:43 +00:00
|
|
|
builder.add(model.bake(addUV(v.isUvLocked(), MultiModelState.getPartState(state, model, i)), format, bakedTextureGetter), variants.get(i).getWeight());
|
2014-12-28 04:10:54 +00:00
|
|
|
}
|
2015-02-13 21:23:03 +00:00
|
|
|
return new FlexibleWeightedBakedModel(builder.build(), Attributes.DEFAULT_BAKED_FORMAT);
|
2014-12-28 04:10:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public IModelState getDefaultState()
|
|
|
|
{
|
|
|
|
return defaultState;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-02-13 21:23:03 +00:00
|
|
|
private static class FlexibleWeightedBakedModel extends WeightedBakedModel implements IFlexibleBakedModel
|
|
|
|
{
|
|
|
|
private final VertexFormat format;
|
|
|
|
|
|
|
|
public FlexibleWeightedBakedModel(WeightedBakedModel parent, VertexFormat format)
|
|
|
|
{
|
|
|
|
super(parent.models);
|
|
|
|
this.format = format;
|
|
|
|
}
|
|
|
|
|
|
|
|
public VertexFormat getFormat()
|
|
|
|
{
|
|
|
|
return format;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-12-28 04:10:54 +00:00
|
|
|
public IModel getMissingModel()
|
|
|
|
{
|
2015-06-16 23:03:10 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return missingModel;
|
2014-12-28 04:10:54 +00:00
|
|
|
}
|
|
|
|
|
2015-10-27 15:34:25 +00:00
|
|
|
public IModel getItemModel()
|
|
|
|
{
|
|
|
|
return itemModel;
|
|
|
|
}
|
|
|
|
|
2014-12-28 04:10:54 +00:00
|
|
|
static enum VanillaLoader implements ICustomModelLoader
|
|
|
|
{
|
|
|
|
instance;
|
|
|
|
|
|
|
|
private ModelLoader loader;
|
|
|
|
|
|
|
|
void setLoader(ModelLoader loader)
|
|
|
|
{
|
|
|
|
this.loader = loader;
|
|
|
|
}
|
|
|
|
|
|
|
|
ModelLoader getLoader()
|
|
|
|
{
|
|
|
|
return loader;
|
|
|
|
}
|
|
|
|
|
|
|
|
public void onResourceManagerReload(IResourceManager resourceManager)
|
|
|
|
{
|
|
|
|
// do nothing, cause loader will store the reference to the resourceManager
|
|
|
|
}
|
|
|
|
|
|
|
|
public boolean accepts(ResourceLocation modelLocation)
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2015-06-16 23:03:10 +00:00
|
|
|
public IModel loadModel(ResourceLocation modelLocation) throws IOException
|
2014-12-28 04:10:54 +00:00
|
|
|
{
|
2015-06-16 23:03:10 +00:00
|
|
|
return loader.new VanillaModelWrapper(modelLocation, loader.loadModel(modelLocation));
|
2014-12-28 04:10:54 +00:00
|
|
|
}
|
|
|
|
}
|
2015-02-04 06:45:23 +00:00
|
|
|
|
2015-02-17 00:36:08 +00:00
|
|
|
public static class White extends TextureAtlasSprite
|
|
|
|
{
|
|
|
|
public static ResourceLocation loc = new ResourceLocation("white");
|
|
|
|
public static White instance = new White();
|
|
|
|
|
|
|
|
protected White()
|
|
|
|
{
|
|
|
|
super(loc.toString());
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public boolean hasCustomLoader(IResourceManager manager, ResourceLocation location)
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public boolean load(IResourceManager manager, ResourceLocation location)
|
|
|
|
{
|
2015-04-01 13:06:03 +00:00
|
|
|
BufferedImage image = new BufferedImage(16, 16, BufferedImage.TYPE_INT_ARGB);
|
|
|
|
Graphics2D graphics = image.createGraphics();
|
|
|
|
graphics.setBackground(Color.WHITE);
|
|
|
|
graphics.clearRect(0, 0, 16, 16);
|
2015-02-17 00:36:08 +00:00
|
|
|
BufferedImage[] images = new BufferedImage[Minecraft.getMinecraft().gameSettings.mipmapLevels + 1];
|
|
|
|
images[0] = image;
|
2015-11-09 21:03:39 +00:00
|
|
|
try
|
|
|
|
{
|
|
|
|
loadSprite(images, null);
|
|
|
|
}
|
|
|
|
catch(IOException e)
|
|
|
|
{
|
|
|
|
throw new RuntimeException(e);
|
|
|
|
}
|
2015-02-17 00:36:08 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-02-17 18:20:14 +00:00
|
|
|
public void register(TextureMap map)
|
2015-02-17 00:36:08 +00:00
|
|
|
{
|
2015-02-17 18:20:14 +00:00
|
|
|
map.setTextureEntry(White.loc.toString(), White.instance);
|
2015-02-17 00:36:08 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-11-13 14:23:37 +00:00
|
|
|
public void onPostBakeEvent(IRegistry<ModelResourceLocation, IBakedModel> modelRegistry)
|
2015-02-04 06:45:23 +00:00
|
|
|
{
|
2015-11-13 14:23:37 +00:00
|
|
|
IBakedModel missingModel = modelRegistry.getObject(MODEL_MISSING);
|
2016-01-19 22:19:38 +00:00
|
|
|
Map<String, Integer> modelErrors = Maps.newHashMap();
|
|
|
|
for(Map.Entry<ResourceLocation, Exception> entry : loadingExceptions.entrySet())
|
2016-01-16 22:51:50 +00:00
|
|
|
{
|
2016-01-19 22:19:38 +00:00
|
|
|
// ignoring pure ResourceLocation arguments, all things we care about pass ModelResourceLocation
|
|
|
|
if(entry.getKey() instanceof ModelResourceLocation)
|
2016-01-16 22:51:50 +00:00
|
|
|
{
|
2016-01-19 22:19:38 +00:00
|
|
|
ModelResourceLocation location = (ModelResourceLocation)entry.getKey();
|
|
|
|
IBakedModel model = modelRegistry.getObject(location);
|
|
|
|
if(model == null || model == missingModel)
|
|
|
|
{
|
|
|
|
String domain = entry.getKey().getResourceDomain();
|
|
|
|
Integer errorCountBox = modelErrors.get(domain);
|
|
|
|
int errorCount = errorCountBox == null ? 0 : errorCountBox;
|
|
|
|
errorCount++;
|
|
|
|
if(errorCount < 5)
|
|
|
|
{
|
|
|
|
FMLLog.getLogger().error("Exception loading model for variant " + entry.getKey(), entry.getValue());
|
|
|
|
}
|
|
|
|
modelErrors.put(domain, errorCount);
|
|
|
|
}
|
|
|
|
if(model == null)
|
|
|
|
{
|
|
|
|
modelRegistry.putObject(location, missingModel);
|
|
|
|
}
|
2016-01-16 22:51:50 +00:00
|
|
|
}
|
|
|
|
}
|
2015-02-04 06:45:23 +00:00
|
|
|
for(ModelResourceLocation missing : missingVariants)
|
|
|
|
{
|
2015-11-13 14:23:37 +00:00
|
|
|
IBakedModel model = modelRegistry.getObject(missing);
|
2015-06-04 15:07:03 +00:00
|
|
|
if(model == null || model == missingModel)
|
2015-02-04 06:45:23 +00:00
|
|
|
{
|
2016-01-19 22:19:38 +00:00
|
|
|
String domain = missing.getResourceDomain();
|
|
|
|
Integer errorCountBox = modelErrors.get(domain);
|
|
|
|
int errorCount = errorCountBox == null ? 0 : errorCountBox;
|
|
|
|
errorCount++;
|
|
|
|
if(errorCount < 5)
|
|
|
|
{
|
|
|
|
FMLLog.severe("Model definition for location %s not found", missing);
|
|
|
|
}
|
|
|
|
modelErrors.put(domain, errorCount);
|
2015-02-04 06:45:23 +00:00
|
|
|
}
|
2016-01-16 22:51:50 +00:00
|
|
|
if(model == null)
|
|
|
|
{
|
|
|
|
modelRegistry.putObject(missing, missingModel);
|
|
|
|
}
|
2015-02-04 06:45:23 +00:00
|
|
|
}
|
2016-01-19 22:19:38 +00:00
|
|
|
for(Map.Entry<String, Integer> e : modelErrors.entrySet())
|
|
|
|
{
|
|
|
|
if(e.getValue() >= 5)
|
|
|
|
{
|
|
|
|
FMLLog.severe("Supressed additional %s model loading errors for domain %s", e.getValue(), e.getKey());
|
|
|
|
}
|
|
|
|
}
|
2015-02-04 06:45:23 +00:00
|
|
|
isLoading = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
private static final Map<RegistryDelegate<Block>, IStateMapper> customStateMappers = Maps.newHashMap();
|
|
|
|
|
2015-12-24 03:06:38 +00:00
|
|
|
/**
|
|
|
|
* Adds a custom IBlockState -> model variant logic.
|
|
|
|
*/
|
2015-02-04 06:45:23 +00:00
|
|
|
public static void setCustomStateMapper(Block block, IStateMapper mapper)
|
|
|
|
{
|
|
|
|
customStateMappers.put(block.delegate, mapper);
|
|
|
|
}
|
|
|
|
|
|
|
|
public static void onRegisterAllBlocks(BlockModelShapes shapes)
|
|
|
|
{
|
|
|
|
for (Entry<RegistryDelegate<Block>, IStateMapper> e : customStateMappers.entrySet())
|
|
|
|
{
|
|
|
|
shapes.registerBlockWithStateMapper(e.getKey().get(), e.getValue());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private static final Map<RegistryDelegate<Item>, ItemMeshDefinition> customMeshDefinitions = com.google.common.collect.Maps.newHashMap();
|
2015-02-09 14:18:18 +00:00
|
|
|
private static final Map<Pair<RegistryDelegate<Item>, Integer>, ModelResourceLocation> customModels = com.google.common.collect.Maps.newHashMap();
|
2015-02-04 06:45:23 +00:00
|
|
|
|
2015-12-24 03:06:38 +00:00
|
|
|
/**
|
|
|
|
* Adds a simple mapping from Item + metadata to the model variant.
|
|
|
|
* Registers the variant with the ModelBakery too.
|
|
|
|
*/
|
2015-02-04 06:45:23 +00:00
|
|
|
public static void setCustomModelResourceLocation(Item item, int metadata, ModelResourceLocation model)
|
|
|
|
{
|
2015-02-09 14:18:18 +00:00
|
|
|
customModels.put(Pair.of(item.delegate, metadata), model);
|
2015-12-24 03:06:38 +00:00
|
|
|
ModelBakery.registerItemVariants(item, model);
|
2015-02-04 06:45:23 +00:00
|
|
|
}
|
|
|
|
|
2015-12-24 03:06:38 +00:00
|
|
|
/**
|
|
|
|
* Adds generic ItemStack -> model variant logic.
|
|
|
|
* You still need to manually call ModelBakery.registerItemVariants with all values that meshDefinition can return.
|
|
|
|
*/
|
2015-02-04 06:45:23 +00:00
|
|
|
public static void setCustomMeshDefinition(Item item, ItemMeshDefinition meshDefinition)
|
|
|
|
{
|
|
|
|
customMeshDefinitions.put(item.delegate, meshDefinition);
|
|
|
|
}
|
|
|
|
|
2015-12-29 12:20:36 +00:00
|
|
|
public static void setBucketModelDefinition(Item item) {
|
|
|
|
ModelLoader.setCustomMeshDefinition(item, new ItemMeshDefinition()
|
|
|
|
{
|
|
|
|
@Override
|
|
|
|
public ModelResourceLocation getModelLocation(ItemStack stack)
|
|
|
|
{
|
|
|
|
return ModelDynBucket.LOCATION;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
ModelBakery.registerItemVariants(item, ModelDynBucket.LOCATION);
|
|
|
|
}
|
|
|
|
|
2015-02-04 06:45:23 +00:00
|
|
|
public static void onRegisterItems(ItemModelMesher mesher)
|
|
|
|
{
|
|
|
|
for (Map.Entry<RegistryDelegate<Item>, ItemMeshDefinition> e : customMeshDefinitions.entrySet())
|
|
|
|
{
|
|
|
|
mesher.register(e.getKey().get(), e.getValue());
|
|
|
|
}
|
2015-02-09 14:18:18 +00:00
|
|
|
for (Entry<Pair<RegistryDelegate<Item>, Integer>, ModelResourceLocation> e : customModels.entrySet())
|
2015-02-04 06:45:23 +00:00
|
|
|
{
|
2015-02-09 14:18:18 +00:00
|
|
|
mesher.register(e.getKey().getLeft().get(), e.getKey().getRight(), e.getValue());
|
2015-02-04 06:45:23 +00:00
|
|
|
}
|
|
|
|
}
|
2014-12-28 04:10:54 +00:00
|
|
|
}
|