2016-06-23 03:49:47 +00:00
/ *
* Minecraft Forge
2018-07-01 21:17:28 +00:00
* Copyright ( c ) 2016 - 2018 .
2016-06-23 03:49:47 +00:00
*
* This library is free software ; you can redistribute it and / or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation version 2 . 1
* of the License .
*
* This library is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
* Lesser General Public License for more details .
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library ; if not , write to the Free Software
* Foundation , Inc . , 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 USA
* /
2014-12-28 04:10:54 +00:00
package net.minecraftforge.client.model ;
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 ;
2014-12-28 04:10:54 +00:00
import java.util.ArrayList ;
import java.util.Collection ;
2016-03-16 02:00:44 +00:00
import java.util.Comparator ;
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 ;
2017-01-06 23:58:36 +00:00
import java.util.concurrent.TimeUnit ;
2014-12-28 04:10:54 +00:00
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 ;
2016-03-05 23:51:39 +00:00
import net.minecraft.client.renderer.block.model.BakedQuad ;
2015-05-20 09:54:33 +00:00
import net.minecraft.client.renderer.block.model.BlockPart ;
import net.minecraft.client.renderer.block.model.BlockPartFace ;
2016-01-01 15:15:48 +00:00
import net.minecraft.client.renderer.block.model.BlockPartRotation ;
2016-03-15 22:42:01 +00:00
import net.minecraft.client.renderer.block.model.BuiltInModel ;
import net.minecraft.client.renderer.block.model.IBakedModel ;
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 ;
2016-03-21 06:15:39 +00:00
import net.minecraft.client.renderer.block.model.ItemOverrideList ;
2016-03-15 22:42:01 +00:00
import net.minecraft.client.renderer.block.model.ModelBakery ;
2014-12-28 04:10:54 +00:00
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 ;
2016-03-15 22:42:01 +00:00
import net.minecraft.client.renderer.block.model.ModelResourceLocation ;
2016-03-13 13:16:25 +00:00
import net.minecraft.client.renderer.block.model.MultipartBakedModel ;
2016-03-15 22:42:01 +00:00
import net.minecraft.client.renderer.block.model.SimpleBakedModel ;
2016-03-05 02:02:34 +00:00
import net.minecraft.client.renderer.block.model.Variant ;
import net.minecraft.client.renderer.block.model.VariantList ;
2016-03-15 22:42:01 +00:00
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 ;
2016-03-16 02:00:44 +00:00
import net.minecraft.client.renderer.block.statemap.BlockStateMapper ;
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.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.item.Item ;
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.ResourceLocation ;
2016-03-15 22:42:01 +00:00
import net.minecraft.util.registry.IRegistry ;
2016-03-21 06:15:39 +00:00
import net.minecraftforge.client.model.animation.AnimationItemOverrideList ;
2016-01-01 15:15:48 +00:00
import net.minecraftforge.client.model.animation.ModelBlockAnimation ;
2018-06-21 19:37:32 +00:00
import net.minecraftforge.common.ForgeMod ;
2016-03-21 07:01:30 +00:00
import net.minecraftforge.common.model.IModelState ;
2016-05-29 22:20:43 +00:00
import net.minecraftforge.common.model.Models ;
2016-03-21 07:01:30 +00:00
import net.minecraftforge.common.model.TRSRTransformation ;
import net.minecraftforge.common.model.animation.IClip ;
2016-01-01 15:15:48 +00:00
import net.minecraftforge.common.property.IExtendedBlockState ;
import net.minecraftforge.common.property.Properties ;
2018-06-06 15:37:56 +00:00
import net.minecraftforge.fluids.FluidRegistry ;
2018-06-11 01:12:46 +00:00
import net.minecraftforge.fml.client.ClientModLoader ;
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 ;
2018-06-06 15:37:56 +00:00
import net.minecraftforge.logging.ModelLoaderErrorMessage ;
2017-06-19 22:02:18 +00:00
import net.minecraftforge.registries.IRegistryDelegate ;
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
2017-06-25 01:08:20 +00:00
import java.util.function.Function ;
2016-03-15 22:42:01 +00:00
import com.google.common.base.Joiner ;
2017-01-06 23:58:36 +00:00
import com.google.common.base.Objects ;
2017-12-26 23:16:32 +00:00
import com.google.common.base.Preconditions ;
2017-06-25 01:08:20 +00:00
import java.util.Optional ;
2018-01-13 07:54:29 +00:00
import java.util.stream.Collectors ;
import java.util.stream.StreamSupport ;
2017-01-06 23:58:36 +00:00
import com.google.common.cache.CacheBuilder ;
import com.google.common.cache.CacheLoader ;
import com.google.common.cache.LoadingCache ;
2016-03-15 22:42:01 +00:00
import com.google.common.collect.HashMultimap ;
import com.google.common.collect.ImmutableList ;
import com.google.common.collect.ImmutableMap ;
import com.google.common.collect.ImmutableSet ;
import com.google.common.collect.Lists ;
import com.google.common.collect.Maps ;
2016-03-16 02:00:44 +00:00
import com.google.common.collect.Multimaps ;
2016-03-15 22:42:01 +00:00
import com.google.common.collect.Sets ;
2018-08-27 17:10:07 +00:00
import org.apache.logging.log4j.LogManager ;
import org.apache.logging.log4j.Logger ;
2016-03-15 22:42:01 +00:00
2017-01-11 23:17:56 +00:00
import javax.annotation.Nonnull ;
2017-06-25 01:08:20 +00:00
import javax.annotation.Nullable ;
2017-01-11 23:17:56 +00:00
2018-06-06 15:37:56 +00:00
import static net.minecraftforge.fml.Logging.MODELLOADING ;
2016-03-15 22:42:01 +00:00
public final class ModelLoader extends ModelBakery
2014-12-28 04:10:54 +00:00
{
2018-08-27 17:10:07 +00:00
private static final Logger LOGGER = LogManager . getLogger ( ) ;
2016-01-16 22:51:50 +00:00
private final Map < ModelResourceLocation , IModel > stateModels = Maps . newHashMap ( ) ;
2018-05-20 03:50:57 +00:00
private final Map < ModelResourceLocation , ModelBlockDefinition > multipartDefinitions = Maps . newHashMap ( ) ;
private final Map < ModelBlockDefinition , IModel > multipartModels = Maps . newHashMap ( ) ;
2017-06-26 05:13:58 +00:00
// TODO: nothing adds to missingVariants, remove it?
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-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 ) ;
2016-03-21 07:23:27 +00:00
VanillaLoader . INSTANCE . setLoader ( this ) ;
VariantLoader . INSTANCE . setLoader ( this ) ;
2016-03-21 07:01:30 +00:00
ModelLoaderRegistry . clearModelCache ( manager ) ;
2014-12-28 04:10:54 +00:00
}
2017-06-26 05:13:58 +00:00
@Nonnull
2014-12-28 04:10:54 +00:00
@Override
2015-11-13 14:23:37 +00:00
public IRegistry < ModelResourceLocation , IBakedModel > setupModelRegistry ( )
2014-12-28 04:10:54 +00:00
{
2018-06-11 01:12:46 +00:00
if ( ClientModLoader . isErrored ( ) ) // skip loading models if we're just going to show a fatal error screen
2017-04-07 23:48:00 +00:00
return bakedRegistry ;
2015-02-04 06:45:23 +00:00
isLoading = true ;
2014-12-28 04:10:54 +00:00
loadBlocks ( ) ;
2016-03-13 09:10:50 +00:00
loadVariantItemModels ( ) ;
2016-03-15 22:42:01 +00:00
missingModel = ModelLoaderRegistry . getMissingModel ( ) ;
2015-06-16 23:03:10 +00:00
stateModels . put ( MODEL_MISSING , missingModel ) ;
2016-03-13 13:16:25 +00:00
final Set < ResourceLocation > textures = Sets . newHashSet ( ModelLoaderRegistry . getTextures ( ) ) ;
2014-12-28 04:10:54 +00:00
textures . remove ( TextureMap . LOCATION_MISSING_TEXTURE ) ;
textures . addAll ( LOCATIONS_BUILTIN_TEXTURES ) ;
2016-03-13 13:16:25 +00:00
2017-06-25 01:08:20 +00:00
textureMap . loadSprites ( resourceManager , map - > textures . forEach ( map : : registerSprite ) ) ;
2016-03-13 13:16:25 +00:00
2016-03-21 07:23:27 +00:00
IBakedModel missingBaked = missingModel . bake ( missingModel . getDefaultState ( ) , DefaultVertexFormats . ITEM , DefaultTextureGetter . INSTANCE ) ;
2016-03-13 13:16:25 +00:00
Map < IModel , IBakedModel > bakedModels = Maps . newHashMap ( ) ;
2016-03-16 02:00:44 +00:00
HashMultimap < IModel , ModelResourceLocation > models = HashMultimap . create ( ) ;
Multimaps . invertFrom ( Multimaps . forMap ( stateModels ) , models ) ;
ProgressBar bakeBar = ProgressManager . push ( " ModelLoader: baking " , models . keySet ( ) . size ( ) ) ;
for ( IModel model : models . keySet ( ) )
2014-12-28 04:10:54 +00:00
{
2018-01-18 21:14:33 +00:00
String modelLocations = " [ " + Joiner . on ( " , " ) . join ( models . get ( model ) ) + " ] " ;
bakeBar . step ( modelLocations ) ;
2016-03-13 13:16:25 +00:00
if ( model = = getMissingModel ( ) )
2015-06-04 15:07:03 +00:00
{
2016-03-13 13:16:25 +00:00
bakedModels . put ( model , missingBaked ) ;
2015-06-04 15:07:03 +00:00
}
else
{
2018-01-18 21:14:33 +00:00
try
{
bakedModels . put ( model , model . bake ( model . getDefaultState ( ) , DefaultVertexFormats . ITEM , DefaultTextureGetter . INSTANCE ) ) ;
}
catch ( Exception e )
{
FMLLog . log . error ( " Exception baking model for location(s) {}: " , modelLocations , e ) ;
bakedModels . put ( model , missingBaked ) ;
}
2015-06-04 15:07:03 +00:00
}
2014-12-28 04:10:54 +00:00
}
2016-03-16 02:00:44 +00:00
ProgressManager . pop ( bakeBar ) ;
2016-03-13 13:16:25 +00:00
for ( Entry < ModelResourceLocation , IModel > e : stateModels . entrySet ( ) )
{
bakedRegistry . putObject ( e . getKey ( ) , bakedModels . get ( e . getValue ( ) ) ) ;
}
2014-12-28 04:10:54 +00:00
return bakedRegistry ;
}
2016-03-13 09:10:50 +00:00
// NOOP, replaced by dependency resolution
@Override
protected void loadVariantModels ( ) { }
// NOOP, replaced by dependency resolution
@Override
protected void loadMultipartVariantModels ( ) { }
2016-03-16 02:00:44 +00:00
@Override
protected void loadBlocks ( )
2014-12-28 04:10:54 +00:00
{
2018-01-13 07:54:29 +00:00
List < Block > blocks = StreamSupport . stream ( Block . REGISTRY . spliterator ( ) , false )
. filter ( block - > block . getRegistryName ( ) ! = null )
. sorted ( Comparator . comparing ( b - > b . getRegistryName ( ) . toString ( ) ) )
. collect ( Collectors . toList ( ) ) ;
2016-03-16 02:00:44 +00:00
ProgressBar blockBar = ProgressManager . push ( " ModelLoader: blocks " , blocks . size ( ) ) ;
BlockStateMapper mapper = this . blockModelShapes . getBlockStateMapper ( ) ;
for ( Block block : blocks )
2016-01-16 22:51:50 +00:00
{
2016-04-01 21:13:06 +00:00
blockBar . step ( block . getRegistryName ( ) . toString ( ) ) ;
2016-03-16 02:00:44 +00:00
for ( ResourceLocation location : mapper . getBlockstateLocations ( block ) )
{
loadBlock ( mapper , block , location ) ;
}
2016-01-16 22:51:50 +00:00
}
2016-01-06 19:53:34 +00:00
ProgressManager . pop ( blockBar ) ;
2016-03-16 02:00:44 +00:00
}
2014-12-28 04:10:54 +00:00
2016-03-13 13:16:25 +00:00
@Override
2017-06-25 01:08:20 +00:00
protected void registerVariant ( @Nullable ModelBlockDefinition definition , ModelResourceLocation location )
2016-03-05 23:51:39 +00:00
{
2016-03-15 22:42:01 +00:00
IModel model ;
try
{
model = ModelLoaderRegistry . getModel ( location ) ;
}
catch ( Exception e )
{
storeException ( location , e ) ;
2017-01-19 09:57:37 +00:00
model = ModelLoaderRegistry . getMissingModel ( location , e ) ;
2016-03-15 22:42:01 +00:00
}
stateModels . put ( location , model ) ;
2016-03-05 23:51:39 +00:00
}
2014-12-28 04:10:54 +00:00
@Override
2016-03-13 13:16:25 +00:00
protected void registerMultipartVariant ( ModelBlockDefinition definition , Collection < ModelResourceLocation > locations )
2014-12-28 04:10:54 +00:00
{
2016-03-13 13:16:25 +00:00
for ( ModelResourceLocation location : locations )
2016-01-06 23:09:29 +00:00
{
2018-05-20 03:50:57 +00:00
multipartDefinitions . put ( location , definition ) ;
2016-03-15 22:42:01 +00:00
registerVariant ( null , location ) ;
2016-03-13 09:10:50 +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 ) ) ;
}
2017-06-25 01:08:20 +00:00
return new ModelBlockDefinition ( new ArrayList < > ( ) ) ;
2016-01-19 22:19:38 +00:00
}
2016-03-13 09:10:50 +00:00
@Override
protected void loadItemModels ( )
2014-12-28 04:10:54 +00:00
{
2016-02-19 10:17:23 +00:00
registerVariantNames ( ) ;
2016-03-09 22:11:56 +00:00
2018-01-13 07:54:29 +00:00
List < Item > items = StreamSupport . stream ( Item . REGISTRY . spliterator ( ) , false )
. filter ( item - > item . getRegistryName ( ) ! = null )
. sorted ( Comparator . comparing ( i - > i . getRegistryName ( ) . toString ( ) ) )
. collect ( Collectors . toList ( ) ) ;
2016-03-16 02:00:44 +00:00
ProgressBar itemBar = ProgressManager . push ( " ModelLoader: items " , items . size ( ) ) ;
for ( Item item : items )
{
2016-04-01 21:13:06 +00:00
itemBar . step ( item . getRegistryName ( ) . toString ( ) ) ;
2016-03-16 02:00:44 +00:00
for ( String s : getVariantNames ( item ) )
2016-03-15 22:42:01 +00:00
{
2016-03-16 02:00:44 +00:00
ResourceLocation file = getItemLocation ( s ) ;
ModelResourceLocation memory = getInventoryVariant ( s ) ;
IModel model = ModelLoaderRegistry . getMissingModel ( ) ;
Exception exception = null ;
2016-03-15 22:42:01 +00:00
try
2015-02-04 06:45:23 +00:00
{
2018-06-27 18:08:38 +00:00
model = ModelLoaderRegistry . getModel ( memory ) ;
2016-03-15 22:42:01 +00:00
}
2018-06-27 18:08:38 +00:00
catch ( Exception blockstateException )
2016-03-15 22:42:01 +00:00
{
2016-03-16 02:00:44 +00:00
try
{
2018-06-27 18:08:38 +00:00
model = ModelLoaderRegistry . getModel ( file ) ;
2018-08-16 20:21:21 +00:00
ModelLoaderRegistry . addAlias ( memory , file ) ;
2016-03-16 02:00:44 +00:00
}
2018-06-27 18:08:38 +00:00
catch ( Exception normalException )
2016-03-16 02:00:44 +00:00
{
2016-04-04 15:07:06 +00:00
exception = new ItemLoadingException ( " Could not load item model either from the normal location " + file + " or from the blockstate " , normalException , blockstateException ) ;
2016-03-16 02:00:44 +00:00
}
}
2018-06-27 18:08:38 +00:00
if ( exception ! = null )
2016-03-16 02:00:44 +00:00
{
storeException ( memory , exception ) ;
2017-01-19 09:57:37 +00:00
model = ModelLoaderRegistry . getMissingModel ( memory , exception ) ;
2015-06-16 23:03:10 +00:00
}
2017-01-19 09:57:37 +00:00
stateModels . put ( memory , model ) ;
2016-01-16 22:51:50 +00:00
}
2014-12-28 04:10:54 +00:00
}
2016-01-06 19:53:34 +00:00
ProgressManager . pop ( itemBar ) ;
2014-12-28 04:10:54 +00:00
}
2016-03-16 02:17:33 +00:00
/ * *
* Hooked from ModelBakery , allows using MRLs that don ' t end with " inventory " for items .
* /
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 " ) ;
}
2014-12-28 04:10:54 +00:00
@Override
protected ResourceLocation getModelLocation ( ResourceLocation model )
{
return new ResourceLocation ( model . getResourceDomain ( ) , model . getResourcePath ( ) + " .json " ) ;
}
2015-10-27 14:40:05 +00:00
2017-06-25 01:08:20 +00:00
private final class VanillaModelWrapper implements IModel
2014-12-28 04:10:54 +00:00
{
private final ResourceLocation location ;
private final ModelBlock model ;
2016-03-05 23:51:39 +00:00
private final boolean uvlock ;
2016-01-01 15:15:48 +00:00
private final ModelBlockAnimation animation ;
2014-12-28 04:10:54 +00:00
2016-03-05 23:51:39 +00:00
public VanillaModelWrapper ( ResourceLocation location , ModelBlock model , boolean uvlock , ModelBlockAnimation animation )
2014-12-28 04:10:54 +00:00
{
this . location = location ;
this . model = model ;
2016-03-05 23:51:39 +00:00
this . uvlock = uvlock ;
2016-01-01 15:15:48 +00:00
this . animation = animation ;
2014-12-28 04:10:54 +00:00
}
2017-06-18 01:24:17 +00:00
@Override
2014-12-28 04:10:54 +00:00
public Collection < ResourceLocation > getDependencies ( )
{
2016-03-13 09:10:50 +00:00
Set < ResourceLocation > set = Sets . newHashSet ( ) ;
2016-03-13 13:16:25 +00:00
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
2016-03-15 22:42:01 +00:00
stateModels . put ( getInventoryVariant ( dep . toString ( ) ) , ModelLoaderRegistry . getModelOrLogError ( dep , " Could not load override model " + dep + " for model " + location ) ) ;
2016-03-13 13:16:25 +00:00
}
}
2016-03-13 09:10:50 +00:00
if ( model . getParentLocation ( ) ! = null & & ! model . getParentLocation ( ) . getResourcePath ( ) . startsWith ( " builtin/ " ) )
{
set . add ( model . getParentLocation ( ) ) ;
}
return ImmutableSet . copyOf ( set ) ;
2014-12-28 04:10:54 +00:00
}
2017-06-18 01:24:17 +00:00
@Override
2014-12-28 04:10:54 +00:00
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
{
2016-03-15 22:42:01 +00:00
IModel parent = ModelLoaderRegistry . getModelOrLogError ( model . getParentLocation ( ) , " Could not load vanilla model parent ' " + model . getParentLocation ( ) + " ' for ' " + model ) ;
2016-03-13 13:16:25 +00:00
if ( parent instanceof VanillaModelWrapper )
2015-06-16 23:03:10 +00:00
{
2016-03-13 13:16:25 +00:00
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
}
2014-12-28 04:10:54 +00:00
}
}
ImmutableSet . Builder < ResourceLocation > builder = ImmutableSet . builder ( ) ;
if ( hasItemModel ( model ) )
{
2016-02-22 00:53:26 +00:00
for ( String s : ItemModelGenerator . LAYERS )
2014-12-28 04:10:54 +00:00
{
String r = model . resolveTextureName ( s ) ;
ResourceLocation loc = new ResourceLocation ( r ) ;
if ( ! r . equals ( s ) )
{
builder . add ( loc ) ;
}
}
}
2016-02-22 00:53:26 +00:00
for ( String s : 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 ( ) ;
}
2017-06-18 01:24:17 +00:00
@Override
2017-01-06 23:58:36 +00:00
public IBakedModel bake ( IModelState state , VertexFormat format , Function < ResourceLocation , TextureAtlasSprite > bakedTextureGetter )
{
return VanillaLoader . INSTANCE . modelCache . getUnchecked ( new BakedModelCacheKey ( this , state , format , bakedTextureGetter ) ) ;
}
public IBakedModel bakeImpl ( IModelState state , final VertexFormat format , Function < ResourceLocation , TextureAtlasSprite > bakedTextureGetter )
2014-12-28 04:10:54 +00:00
{
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 + + )
{
2016-01-01 15:15:48 +00:00
BlockPart part = model . getElements ( ) . get ( i ) ;
newTransforms . add ( animation . getPartTransform ( state , part , i ) ) ;
2015-12-03 19:38:08 +00:00
}
2016-03-13 01:40:03 +00:00
ItemCameraTransforms transforms = model . getAllTransforms ( ) ;
2018-04-01 07:24:37 +00:00
Map < TransformType , TRSRTransformation > tMap = Maps . newEnumMap ( TransformType . class ) ;
2017-06-25 01:08:20 +00:00
tMap . putAll ( PerspectiveMapWrapper . getTransforms ( transforms ) ) ;
tMap . putAll ( PerspectiveMapWrapper . getTransforms ( state ) ) ;
2015-12-03 19:38:08 +00:00
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 ) ;
}
2016-03-13 01:40:03 +00:00
if ( isCustomRenderer ( model ) ) return new BuiltInModel ( transforms , model . createOverrides ( ) ) ;
2016-03-21 06:15:39 +00:00
return bakeNormal ( model , perState , state , newTransforms , format , bakedTextureGetter , uvlock ) ;
2015-06-23 13:52:42 +00:00
}
2016-03-21 06:15:39 +00:00
private IBakedModel bakeNormal ( ModelBlock model , IModelState perState , final IModelState modelState , List < TRSRTransformation > newTransforms , final VertexFormat format , final Function < ResourceLocation , TextureAtlasSprite > bakedTextureGetter , boolean uvLocked )
2015-06-23 13:52:42 +00:00
{
2017-06-25 01:08:20 +00:00
final TRSRTransformation baseState = modelState . apply ( Optional . empty ( ) ) . orElse ( TRSRTransformation . identity ( ) ) ;
2015-06-23 13:52:42 +00:00
TextureAtlasSprite particle = bakedTextureGetter . apply ( new ResourceLocation ( model . resolveTextureName ( " particle " ) ) ) ;
2016-03-13 01:40:03 +00:00
SimpleBakedModel . Builder builder = ( new SimpleBakedModel . Builder ( model , model . createOverrides ( ) ) ) . 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
{
2016-05-29 22:20:43 +00:00
if ( modelState . apply ( Optional . of ( Models . getHiddenModelPart ( ImmutableList . of ( Integer . toString ( i ) ) ) ) ) . isPresent ( ) )
{
continue ;
}
2015-12-03 19:38:08 +00:00
BlockPart part = model . getElements ( ) . get ( i ) ;
2016-03-21 06:15:39 +00:00
TRSRTransformation transformation = baseState ;
2015-12-03 19:38:08 +00:00
if ( newTransforms . get ( i ) ! = null )
{
transformation = transformation . compose ( newTransforms . get ( i ) ) ;
2016-01-01 15:15:48 +00:00
BlockPartRotation rot = part . partRotation ;
if ( rot = = null ) rot = new BlockPartRotation ( new org . lwjgl . util . vector . Vector3f ( ) , EnumFacing . Axis . Y , 0 , false ) ;
part = new BlockPart ( part . positionFrom , part . positionTo , part . mapFaces , rot , part . shade ) ;
2015-12-03 19:38:08 +00:00
}
2016-02-22 00:53:26 +00:00
for ( Map . Entry < EnumFacing , BlockPartFace > e : part . mapFaces . entrySet ( ) )
2015-06-23 13:52:42 +00:00
{
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
{
2016-03-21 06:15:39 +00:00
builder . addFaceQuad ( baseState . rotate ( e . getValue ( ) . cullFace ) , makeBakedQuad ( part , e . getValue ( ) , textureatlassprite1 , e . getKey ( ) , transformation , uvLocked ) ) ;
2015-06-23 13:52:42 +00:00
}
}
}
2017-06-25 01:08:20 +00:00
return new PerspectiveMapWrapper ( builder . makeBakedModel ( ) , perState )
2016-01-01 15:15:48 +00:00
{
2016-03-21 06:15:39 +00:00
private final ItemOverrideList overrides = new AnimationItemOverrideList ( VanillaModelWrapper . this , modelState , format , bakedTextureGetter , super . getOverrides ( ) ) ;
2016-03-05 23:51:39 +00:00
@Override
2017-06-25 01:08:20 +00:00
public List < BakedQuad > getQuads ( @Nullable IBlockState state , @Nullable EnumFacing side , long rand )
2016-01-01 15:15:48 +00:00
{
2016-03-05 23:51:39 +00:00
if ( state instanceof IExtendedBlockState )
2016-01-01 15:15:48 +00:00
{
2016-03-05 23:51:39 +00:00
IExtendedBlockState exState = ( IExtendedBlockState ) state ;
if ( exState . getUnlistedNames ( ) . contains ( Properties . AnimationProperty ) )
{
IModelState newState = exState . getValue ( Properties . AnimationProperty ) ;
IExtendedBlockState newExState = exState . withProperty ( Properties . AnimationProperty , null ) ;
if ( newState ! = null )
{
2016-03-13 01:40:03 +00:00
return VanillaModelWrapper . this . bake ( new ModelStateComposition ( modelState , newState ) , format , bakedTextureGetter ) . getQuads ( newExState , side , rand ) ;
2016-03-05 23:51:39 +00:00
}
}
2016-01-01 15:15:48 +00:00
}
2016-03-13 01:40:03 +00:00
return super . getQuads ( state , side , rand ) ;
2016-04-04 15:07:06 +00:00
}
2016-03-21 06:15:39 +00:00
@Override
public ItemOverrideList getOverrides ( )
{
return overrides ;
}
2016-03-05 23:51:39 +00:00
} ;
2014-12-28 04:10:54 +00:00
}
2015-05-20 09:54:33 +00:00
@Override
2016-03-05 02:02:34 +00:00
public VanillaModelWrapper retexture ( ImmutableMap < String , String > textures )
2015-05-20 09:54:33 +00:00
{
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.
2016-02-22 00:53:26 +00:00
for ( BlockPart part : this . model . getElements ( ) )
2015-05-20 09:54:33 +00:00
{
elements . add ( new BlockPart ( part . positionFrom , part . positionTo , Maps . newHashMap ( part . mapFaces ) , part . partRotation , part . shade ) ) ;
}
2016-02-22 00:53:26 +00:00
ModelBlock newModel = new ModelBlock ( this . model . getParentLocation ( ) , elements ,
2015-05-20 09:54:33 +00:00
Maps . newHashMap ( this . model . textures ) , this . model . isAmbientOcclusion ( ) , this . model . isGui3d ( ) , //New Textures man VERY IMPORTANT
2016-03-13 01:40:03 +00:00
model . getAllTransforms ( ) , Lists . newArrayList ( model . getOverrides ( ) ) ) ;
2016-02-22 00:53:26 +00:00
newModel . name = this . model . name ;
newModel . parent = this . model . parent ;
2015-05-20 09:54:33 +00:00
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 ( ) ) ;
2016-02-22 00:53:26 +00:00
newModel . textures . remove ( e . getKey ( ) ) ;
2015-05-20 09:54:33 +00:00
}
else
2016-02-22 00:53:26 +00:00
newModel . textures . put ( e . getKey ( ) , e . getValue ( ) ) ;
2015-05-20 09:54:33 +00:00
}
// 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
2016-02-22 00:53:26 +00:00
for ( Entry < String , String > e : newModel . textures . entrySet ( ) )
2015-05-20 09:54:33 +00:00
{
if ( e . getValue ( ) . startsWith ( " # " ) )
{
String key = e . getValue ( ) . substring ( 1 ) ;
2016-02-22 00:53:26 +00:00
if ( newModel . textures . containsKey ( key ) )
remapped . put ( e . getKey ( ) , newModel . textures . get ( key ) ) ;
2015-05-20 09:54:33 +00:00
}
}
2015-06-09 19:36:36 +00:00
2016-02-22 00:53:26 +00:00
newModel . 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.
2016-02-22 00:53:26 +00:00
for ( BlockPart part : newModel . getElements ( ) )
2015-05-20 09:54:33 +00:00
{
2017-06-28 07:14:10 +00:00
part . mapFaces . entrySet ( ) . removeIf ( entry - > removed . contains ( entry . getValue ( ) . texture ) ) ;
2015-05-20 09:54:33 +00:00
}
2016-03-05 23:51:39 +00:00
return new VanillaModelWrapper ( location , newModel , uvlock , animation ) ;
2016-01-01 15:15:48 +00:00
}
@Override
public Optional < ? extends IClip > getClip ( String name )
{
if ( animation . getClips ( ) . containsKey ( name ) )
{
2017-06-25 01:08:20 +00:00
return Optional . ofNullable ( animation . getClips ( ) . get ( name ) ) ;
2016-01-01 15:15:48 +00:00
}
2017-06-25 01:08:20 +00:00
return Optional . empty ( ) ;
2015-12-03 19:38:08 +00:00
}
2016-02-02 09:22:06 +00:00
@Override
public VanillaModelWrapper smoothLighting ( boolean value )
{
if ( model . ambientOcclusion = = value )
{
return this ;
}
2016-03-13 01:40:03 +00:00
ModelBlock newModel = new ModelBlock ( model . getParentLocation ( ) , model . getElements ( ) , model . textures , value , model . isGui3d ( ) , model . getAllTransforms ( ) , Lists . newArrayList ( model . getOverrides ( ) ) ) ;
2016-02-02 09:22:06 +00:00
newModel . parent = model . parent ;
newModel . name = model . name ;
2016-03-05 23:51:39 +00:00
return new VanillaModelWrapper ( location , newModel , uvlock , animation ) ;
2016-02-02 09:22:06 +00:00
}
@Override
public VanillaModelWrapper gui3d ( boolean value )
{
if ( model . isGui3d ( ) = = value )
{
return this ;
}
2016-03-13 01:40:03 +00:00
ModelBlock newModel = new ModelBlock ( model . getParentLocation ( ) , model . getElements ( ) , model . textures , model . ambientOcclusion , value , model . getAllTransforms ( ) , Lists . newArrayList ( model . getOverrides ( ) ) ) ;
2016-02-02 09:22:06 +00:00
newModel . parent = model . parent ;
newModel . name = model . name ;
2016-03-05 23:51:39 +00:00
return new VanillaModelWrapper ( location , newModel , uvlock , animation ) ;
2015-02-03 07:33:32 +00:00
}
2016-03-05 23:51:39 +00:00
@Override
public IModel uvlock ( boolean value )
2015-02-03 07:33:32 +00:00
{
2016-03-05 23:51:39 +00:00
if ( uvlock = = value )
{
return this ;
}
return new VanillaModelWrapper ( location , model , value , animation ) ;
2015-02-03 07:33:32 +00:00
}
}
2016-03-15 22:42:01 +00:00
private static final class WeightedRandomModel implements IModel
2014-12-28 04:10:54 +00:00
{
private final List < Variant > variants ;
2017-08-09 20:18:35 +00:00
private final List < ResourceLocation > locations ;
private final Set < ResourceLocation > textures ;
private final List < IModel > models ;
2014-12-28 04:10:54 +00:00
private final IModelState defaultState ;
2016-03-15 22:42:01 +00:00
public WeightedRandomModel ( ResourceLocation parent , VariantList variants ) throws Exception
2014-12-28 04:10:54 +00:00
{
2016-03-13 01:40:03 +00:00
this . variants = variants . getVariantList ( ) ;
2017-08-09 20:18:35 +00:00
this . locations = new ArrayList < > ( ) ;
this . textures = Sets . newHashSet ( ) ;
this . models = new ArrayList < > ( ) ;
2016-01-06 19:00:43 +00:00
ImmutableList . Builder < Pair < IModel , IModelState > > builder = ImmutableList . builder ( ) ;
2016-03-05 02:02:34 +00:00
for ( Variant v : this . variants )
2014-12-28 04:10:54 +00:00
{
2016-03-13 01:40:03 +00:00
ResourceLocation loc = v . getModelLocation ( ) ;
2014-12-28 04:10:54 +00:00
locations . add ( loc ) ;
2015-05-20 09:54:33 +00:00
2016-03-15 22:42:01 +00:00
/ *
* Vanilla eats this , which makes it only show variants that have models .
* But that doesn ' t help debugging , so throw the exception
* /
2016-03-29 12:34:10 +00:00
IModel model ;
if ( loc . equals ( MODEL_MISSING ) )
{
// explicit missing location, happens if blockstate has "model"=null
model = ModelLoaderRegistry . getMissingModel ( ) ;
}
else
{
model = ModelLoaderRegistry . getModel ( loc ) ;
}
2015-06-16 23:03:10 +00:00
2016-03-13 13:16:25 +00:00
// FIXME: is this the place? messes up dependency and texture resolution
2016-03-23 14:34:48 +00:00
model = v . process ( model ) ;
for ( ResourceLocation location : model . getDependencies ( ) )
2015-05-20 09:54:33 +00:00
{
2016-03-23 14:34:48 +00:00
ModelLoaderRegistry . getModelOrMissing ( location ) ;
2015-05-20 09:54:33 +00:00
}
2016-03-23 14:34:48 +00:00
//FMLLog.getLogger().error("Exception resolving indirect dependencies for model" + loc, e);
textures . addAll ( model . getTextures ( ) ) ; // Kick this, just in case.
2015-05-20 09:54:33 +00:00
2014-12-28 04:10:54 +00:00
models . add ( model ) ;
2017-12-26 23:16:32 +00:00
IModelState modelDefaultState = model . getDefaultState ( ) ;
Preconditions . checkNotNull ( modelDefaultState , " Model %s returned null as default state " , loc ) ;
builder . add ( Pair . of ( model , new ModelStateComposition ( v . getState ( ) , modelDefaultState ) ) ) ;
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.
{
2016-03-15 22:42:01 +00:00
// FIXME: log this?
2016-03-13 13:16:25 +00:00
IModel missing = ModelLoaderRegistry . getMissingModel ( ) ;
2015-06-16 23:03:10 +00:00
models . add ( missing ) ;
2017-06-25 01:08:20 +00:00
builder . add ( Pair . 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
}
2017-08-09 20:18:35 +00:00
private WeightedRandomModel ( List < Variant > variants , List < ResourceLocation > locations , Set < ResourceLocation > textures , List < IModel > models , IModelState defaultState )
{
this . variants = variants ;
this . locations = locations ;
this . textures = textures ;
this . models = models ;
this . defaultState = defaultState ;
}
2017-06-18 01:24:17 +00:00
@Override
2014-12-28 04:10:54 +00:00
public Collection < ResourceLocation > getDependencies ( )
{
return ImmutableList . copyOf ( locations ) ;
}
2017-06-18 01:24:17 +00:00
@Override
2014-12-28 04:10:54 +00:00
public Collection < ResourceLocation > getTextures ( )
{
2016-03-13 13:16:25 +00:00
return ImmutableSet . copyOf ( textures ) ;
2014-12-28 04:10:54 +00:00
}
2017-06-18 01:24:17 +00:00
@Override
2016-03-05 02:02:34 +00:00
public IBakedModel bake ( IModelState state , VertexFormat format , Function < ResourceLocation , TextureAtlasSprite > bakedTextureGetter )
2014-12-28 04:10:54 +00:00
{
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 )
{
IModel model = models . get ( 0 ) ;
2016-03-05 23:51:39 +00:00
return model . bake ( 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 ) ;
2016-03-13 01:40:03 +00:00
builder . add ( model . bake ( MultiModelState . getPartState ( state , model , i ) , format , bakedTextureGetter ) , variants . get ( i ) . getWeight ( ) ) ;
2014-12-28 04:10:54 +00:00
}
2016-03-05 02:02:34 +00:00
return builder . build ( ) ;
2014-12-28 04:10:54 +00:00
}
2017-06-18 01:24:17 +00:00
@Override
2014-12-28 04:10:54 +00:00
public IModelState getDefaultState ( )
{
return defaultState ;
}
2017-08-09 20:18:35 +00:00
@Override
public WeightedRandomModel retexture ( ImmutableMap < String , String > textures )
{
if ( textures . isEmpty ( ) )
return this ;
// rebuild the texture list taking into account new textures
Set < ResourceLocation > modelTextures = Sets . newHashSet ( ) ;
// also recreate the MultiModelState so IModelState data is properly applied to the retextured model
ImmutableList . Builder < Pair < IModel , IModelState > > builder = ImmutableList . builder ( ) ;
List < IModel > retexturedModels = Lists . newArrayList ( ) ;
for ( int i = 0 ; i < this . variants . size ( ) ; i + + )
{
IModel retextured = this . models . get ( i ) . retexture ( textures ) ;
modelTextures . addAll ( retextured . getTextures ( ) ) ;
retexturedModels . add ( retextured ) ;
builder . add ( Pair . of ( retextured , this . variants . get ( i ) . getState ( ) ) ) ;
}
return new WeightedRandomModel ( this . variants , this . locations , modelTextures , retexturedModels , new MultiModelState ( builder . build ( ) ) ) ;
}
2014-12-28 04:10:54 +00:00
}
2016-03-16 02:17:33 +00:00
protected IModel getMissingModel ( )
2014-12-28 04:10:54 +00:00
{
2015-06-16 23:03:10 +00:00
if ( missingModel = = null )
{
2016-03-15 22:42:01 +00:00
try
{
2016-03-21 07:23:27 +00:00
missingModel = VanillaLoader . INSTANCE . loadModel ( new ResourceLocation ( MODEL_MISSING . getResourceDomain ( ) , MODEL_MISSING . getResourcePath ( ) ) ) ;
2016-03-15 22:42:01 +00:00
}
catch ( Exception e )
{
throw new RuntimeException ( " Missing the missing model, this should never happen " ) ;
}
2015-06-16 23:03:10 +00:00
}
return missingModel ;
2014-12-28 04:10:54 +00:00
}
2017-01-06 23:58:36 +00:00
protected final class BakedModelCacheKey
{
private final VanillaModelWrapper model ;
private final IModelState state ;
private final VertexFormat format ;
private final Function < ResourceLocation , TextureAtlasSprite > bakedTextureGetter ;
public BakedModelCacheKey ( VanillaModelWrapper model , IModelState state , VertexFormat format , Function < ResourceLocation , TextureAtlasSprite > bakedTextureGetter )
{
this . model = model ;
this . state = state ;
this . format = format ;
this . bakedTextureGetter = bakedTextureGetter ;
}
@Override
public boolean equals ( Object o )
{
if ( this = = o )
{
return true ;
}
if ( o = = null | | getClass ( ) ! = o . getClass ( ) )
{
return false ;
}
BakedModelCacheKey that = ( BakedModelCacheKey ) o ;
return Objects . equal ( model , that . model ) & & Objects . equal ( state , that . state ) & & Objects . equal ( format , that . format ) & & Objects . equal ( bakedTextureGetter , that . bakedTextureGetter ) ;
}
@Override
public int hashCode ( )
{
return Objects . hashCode ( model , state , format , bakedTextureGetter ) ;
}
}
2016-03-15 22:42:01 +00:00
protected static enum VanillaLoader implements ICustomModelLoader
2014-12-28 04:10:54 +00:00
{
2016-03-21 07:23:27 +00:00
INSTANCE ;
2014-12-28 04:10:54 +00:00
2017-06-25 01:08:20 +00:00
@Nullable
2014-12-28 04:10:54 +00:00
private ModelLoader loader ;
2017-01-06 23:58:36 +00:00
private LoadingCache < BakedModelCacheKey , IBakedModel > modelCache = CacheBuilder . newBuilder ( ) . maximumSize ( 50 ) . expireAfterWrite ( 100 , TimeUnit . MILLISECONDS ) . build ( new CacheLoader < BakedModelCacheKey , IBakedModel > ( ) {
@Override
public IBakedModel load ( BakedModelCacheKey key ) throws Exception
{
return key . model . bakeImpl ( key . state , key . format , key . bakedTextureGetter ) ;
}
} ) ;
2014-12-28 04:10:54 +00:00
void setLoader ( ModelLoader loader )
{
this . loader = loader ;
}
2017-06-25 01:08:20 +00:00
@Nullable
2014-12-28 04:10:54 +00:00
ModelLoader getLoader ( )
{
return loader ;
}
2016-03-16 02:17:33 +00:00
// NOOP, handled in loader
2017-06-18 01:24:17 +00:00
@Override
2016-03-16 02:17:33 +00:00
public void onResourceManagerReload ( IResourceManager resourceManager ) { }
2014-12-28 04:10:54 +00:00
2017-06-18 01:24:17 +00:00
@Override
2014-12-28 04:10:54 +00:00
public boolean accepts ( ResourceLocation modelLocation )
{
return true ;
}
2017-06-18 01:24:17 +00:00
@Override
2016-03-15 22:42:01 +00:00
public IModel loadModel ( ResourceLocation modelLocation ) throws Exception
2014-12-28 04:10:54 +00:00
{
2016-03-29 12:34:10 +00:00
if ( modelLocation . equals ( MODEL_MISSING ) & & loader . missingModel ! = null )
2016-03-29 09:05:59 +00:00
{
return loader . getMissingModel ( ) ;
}
2016-01-01 15:15:48 +00:00
String modelPath = modelLocation . getResourcePath ( ) ;
if ( modelLocation . getResourcePath ( ) . startsWith ( " models/ " ) )
{
modelPath = modelPath . substring ( " models/ " . length ( ) ) ;
}
ResourceLocation armatureLocation = new ResourceLocation ( modelLocation . getResourceDomain ( ) , " armatures/ " + modelPath + " .json " ) ;
2016-03-21 07:01:30 +00:00
ModelBlockAnimation animation = ModelBlockAnimation . loadVanillaAnimation ( loader . resourceManager , armatureLocation ) ;
2016-03-15 22:42:01 +00:00
ModelBlock model = loader . loadModel ( modelLocation ) ;
2016-03-29 12:34:10 +00:00
IModel iModel = loader . new VanillaModelWrapper ( modelLocation , model , false , animation ) ;
if ( loader . missingModel = = null & & modelLocation . equals ( MODEL_MISSING ) )
{
loader . missingModel = iModel ;
}
return iModel ;
2016-03-13 13:16:25 +00:00
}
@Override
public String toString ( )
{
2016-03-21 07:23:27 +00:00
return " VanillaLoader.INSTANCE " ;
2014-12-28 04:10:54 +00:00
}
}
2015-02-04 06:45:23 +00:00
2016-03-16 02:17:33 +00:00
/ * *
* 16x16 pure white sprite .
* /
2016-03-15 22:42:01 +00:00
public static final class White extends TextureAtlasSprite
2015-02-17 00:36:08 +00:00
{
2016-03-24 10:14:39 +00:00
public static final ResourceLocation LOCATION = new ResourceLocation ( " white " ) ;
public static final White INSTANCE = new White ( ) ;
2015-02-17 00:36:08 +00:00
2016-03-16 02:17:33 +00:00
private White ( )
2015-02-17 00:36:08 +00:00
{
2016-03-21 07:23:27 +00:00
super ( LOCATION . toString ( ) ) ;
2016-06-24 04:49:15 +00:00
this . width = this . height = 16 ;
2015-02-17 00:36:08 +00:00
}
@Override
public boolean hasCustomLoader ( IResourceManager manager , ResourceLocation location )
{
return true ;
}
@Override
2017-06-26 03:58:19 +00:00
public boolean load ( IResourceManager manager , ResourceLocation location , Function < ResourceLocation , TextureAtlasSprite > textureGetter )
2015-02-17 00:36:08 +00:00
{
2016-06-24 04:49:15 +00:00
BufferedImage image = new BufferedImage ( this . getIconWidth ( ) , this . getIconHeight ( ) , BufferedImage . TYPE_INT_ARGB ) ;
2015-04-01 13:06:03 +00:00
Graphics2D graphics = image . createGraphics ( ) ;
graphics . setBackground ( Color . WHITE ) ;
2016-06-24 04:49:15 +00:00
graphics . clearRect ( 0 , 0 , this . getIconWidth ( ) , this . getIconHeight ( ) ) ;
2016-03-05 23:51:39 +00:00
int [ ] [ ] pixels = new int [ Minecraft . getMinecraft ( ) . gameSettings . mipmapLevels + 1 ] [ ] ;
pixels [ 0 ] = new int [ image . getWidth ( ) * image . getHeight ( ) ] ;
image . getRGB ( 0 , 0 , image . getWidth ( ) , image . getHeight ( ) , pixels [ 0 ] , 0 , image . getWidth ( ) ) ;
2016-03-15 22:42:01 +00:00
this . clearFramesTextureData ( ) ;
2016-03-05 23:51:39 +00:00
this . framesTextureData . add ( pixels ) ;
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
{
2016-12-02 04:49:23 +00:00
map . setTextureEntry ( White . INSTANCE ) ;
2015-02-17 00:36:08 +00:00
}
}
2018-06-06 15:37:56 +00:00
public static class ItemLoadingException extends ModelLoaderRegistry . LoaderException
2016-04-04 15:07:06 +00:00
{
private final Exception normalException ;
private final Exception blockstateException ;
public ItemLoadingException ( String message , Exception normalException , Exception blockstateException )
{
super ( message ) ;
this . normalException = normalException ;
this . blockstateException = blockstateException ;
}
}
2016-03-16 02:17:33 +00:00
/ * *
* Internal , do not use .
* /
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
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
{
2018-08-27 17:10:07 +00:00
LOGGER . debug ( MODELLOADING , ( ) - > new ModelLoaderErrorMessage ( ( ModelResourceLocation ) entry . getKey ( ) , entry . getValue ( ) , modelRegistry , this . blockModelShapes , this : : getVariantNames ) ) ;
2018-06-06 15:37:56 +00:00
final ModelResourceLocation location = ( ModelResourceLocation ) entry . getKey ( ) ;
final IBakedModel model = modelRegistry . getObject ( location ) ;
2016-01-19 22:19:38 +00:00
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
{
2018-08-27 17:10:07 +00:00
LOGGER . debug ( MODELLOADING , ( ) - > new ModelLoaderErrorMessage ( missing , null , modelRegistry , this . blockModelShapes , this : : getVariantNames ) ) ;
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
}
2018-06-24 07:18:13 +00:00
loadingExceptions . clear ( ) ;
missingVariants . clear ( ) ;
2015-02-04 06:45:23 +00:00
isLoading = false ;
}
2017-06-19 22:02:18 +00:00
private static final Map < IRegistryDelegate < Block > , IStateMapper > customStateMappers = Maps . newHashMap ( ) ;
2015-02-04 06:45:23 +00:00
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 ) ;
}
2016-03-16 02:17:33 +00:00
/ * *
* Internal , do not use .
* /
2015-02-04 06:45:23 +00:00
public static void onRegisterAllBlocks ( BlockModelShapes shapes )
{
2017-06-19 22:02:18 +00:00
for ( Entry < IRegistryDelegate < Block > , IStateMapper > e : customStateMappers . entrySet ( ) )
2015-02-04 06:45:23 +00:00
{
shapes . registerBlockWithStateMapper ( e . getKey ( ) . get ( ) , e . getValue ( ) ) ;
}
}
2017-06-19 22:02:18 +00:00
private static final Map < IRegistryDelegate < Item > , ItemMeshDefinition > customMeshDefinitions = com . google . common . collect . Maps . newHashMap ( ) ;
private static final Map < Pair < IRegistryDelegate < 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 ) ;
}
2016-03-16 02:17:33 +00:00
/ * *
* Helper method for registering all itemstacks for given item to map to universal bucket model .
* /
2015-12-29 12:20:36 +00:00
public static void setBucketModelDefinition ( Item item ) {
2017-06-28 06:18:09 +00:00
ModelLoader . setCustomMeshDefinition ( item , stack - > ModelDynBucket . LOCATION ) ;
2015-12-29 12:20:36 +00:00
ModelBakery . registerItemVariants ( item , ModelDynBucket . LOCATION ) ;
}
2016-03-16 02:17:33 +00:00
/ * *
* Internal , do not use .
* /
2015-02-04 06:45:23 +00:00
public static void onRegisterItems ( ItemModelMesher mesher )
{
2017-06-19 22:02:18 +00:00
for ( Map . Entry < IRegistryDelegate < Item > , ItemMeshDefinition > e : customMeshDefinitions . entrySet ( ) )
2015-02-04 06:45:23 +00:00
{
mesher . register ( e . getKey ( ) . get ( ) , e . getValue ( ) ) ;
}
2017-06-19 22:02:18 +00:00
for ( Entry < Pair < IRegistryDelegate < 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
}
}
2016-01-01 15:15:48 +00:00
private static enum DefaultTextureGetter implements Function < ResourceLocation , TextureAtlasSprite >
{
2016-03-21 07:23:27 +00:00
INSTANCE ;
2016-01-01 15:15:48 +00:00
2017-06-18 01:24:17 +00:00
@Override
2016-01-01 15:15:48 +00:00
public TextureAtlasSprite apply ( ResourceLocation location )
{
return Minecraft . getMinecraft ( ) . getTextureMapBlocks ( ) . getAtlasSprite ( location . toString ( ) ) ;
}
}
2016-03-16 02:17:33 +00:00
/ * *
* Get the default texture getter the models will be baked with .
* /
2016-01-01 15:15:48 +00:00
public static Function < ResourceLocation , TextureAtlasSprite > defaultTextureGetter ( )
{
2016-03-21 07:23:27 +00:00
return DefaultTextureGetter . INSTANCE ;
2016-01-01 15:15:48 +00:00
}
2016-03-13 13:16:25 +00:00
protected static enum VariantLoader implements ICustomModelLoader
{
2016-03-21 07:23:27 +00:00
INSTANCE ;
2016-03-13 13:16:25 +00:00
private ModelLoader loader ;
void setLoader ( ModelLoader loader )
{
this . loader = loader ;
}
2016-03-16 02:17:33 +00:00
// NOOP, handled in loader
2016-03-13 13:16:25 +00:00
@Override
2016-03-16 02:17:33 +00:00
public void onResourceManagerReload ( IResourceManager resourceManager ) { }
2016-03-13 13:16:25 +00:00
@Override
public boolean accepts ( ResourceLocation modelLocation )
{
return modelLocation instanceof ModelResourceLocation ;
}
@Override
2016-03-15 22:42:01 +00:00
public IModel loadModel ( ResourceLocation modelLocation ) throws Exception
2016-03-13 13:16:25 +00:00
{
ModelResourceLocation variant = ( ModelResourceLocation ) modelLocation ;
ModelBlockDefinition definition = loader . getModelBlockDefinition ( variant ) ;
2018-05-20 03:50:57 +00:00
2016-03-13 13:16:25 +00:00
try
{
VariantList variants = definition . getVariant ( variant . getVariant ( ) ) ;
return new WeightedRandomModel ( variant , variants ) ;
}
2018-05-20 03:50:57 +00:00
catch ( MissingVariantException e )
2016-03-13 13:16:25 +00:00
{
2018-05-20 03:50:57 +00:00
if ( definition . equals ( loader . multipartDefinitions . get ( variant ) ) )
2016-03-13 13:16:25 +00:00
{
2018-05-20 03:50:57 +00:00
IModel model = loader . multipartModels . get ( definition ) ;
if ( model = = null )
{
model = new MultipartModel ( new ResourceLocation ( variant . getResourceDomain ( ) , variant . getResourcePath ( ) ) , definition . getMultipartData ( ) ) ;
loader . multipartModels . put ( definition , model ) ;
}
return model ;
2016-03-13 13:16:25 +00:00
}
2016-03-15 22:42:01 +00:00
throw e ;
2016-03-13 13:16:25 +00:00
}
}
@Override
public String toString ( )
{
2016-03-21 07:23:27 +00:00
return " VariantLoader.INSTANCE " ;
2016-03-13 13:16:25 +00:00
}
}
private static class MultipartModel implements IModel
{
private final ResourceLocation location ;
private final Multipart multipart ;
private final ImmutableMap < Selector , IModel > partModels ;
2016-03-15 22:42:01 +00:00
public MultipartModel ( ResourceLocation location , Multipart multipart ) throws Exception
2016-03-13 13:16:25 +00:00
{
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 ( ) ;
}
2017-08-09 20:18:35 +00:00
private MultipartModel ( ResourceLocation location , Multipart multipart , ImmutableMap < Selector , IModel > partModels )
{
this . location = location ;
this . multipart = multipart ;
this . partModels = partModels ;
}
2016-03-13 13:16:25 +00:00
// FIXME: represent selectors as dependencies?
// 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 ;
}
2017-08-09 20:18:35 +00:00
@Override
public IModel retexture ( ImmutableMap < String , String > textures )
{
if ( textures . isEmpty ( ) )
return this ;
ImmutableMap . Builder < Selector , IModel > builder = ImmutableMap . builder ( ) ;
for ( Entry < Selector , IModel > partModel : this . partModels . entrySet ( ) )
{
builder . put ( partModel . getKey ( ) , partModel . getValue ( ) . retexture ( textures ) ) ;
}
return new MultipartModel ( location , multipart , builder . build ( ) ) ;
}
2016-03-13 13:16:25 +00:00
}
2014-12-28 04:10:54 +00:00
}