Major Refactoring of Bootstrap Code (#75)
- Refactored boostrap code: * Completely reworked item/block/tile registration. * Fixed server side startup. * Fixed server side startup. * More documentation. * More heavy cleanup * More cleanups. * Major refactoring of state mapping and fixes a lot of other issue related to item rendering. * Fixes sky chest item models (no item TESR). * Only use CachingRotatingBakedModel for tile entities automatically. Fix default rotation of quartz pillar for item model. * Used method reference instead of lambda for ItemMeshDefinition for multiparts. * Removed unnecessary IHasSpecialItemModel * Removed unused IconReg class. * Updated resource pack version.
This commit is contained in:
committed by
Sebastian Hartte
parent
66df324ef0
commit
6f2bbfab4c
@@ -0,0 +1,216 @@
|
||||
package appeng.bootstrap;
|
||||
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.creativetab.CreativeTabs;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemBlock;
|
||||
import net.minecraftforge.fml.common.registry.GameRegistry;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||
|
||||
import appeng.api.definitions.IBlockDefinition;
|
||||
import appeng.block.AEBaseBlock;
|
||||
import appeng.block.AEBaseItemBlock;
|
||||
import appeng.block.AEBaseTileBlock;
|
||||
import appeng.core.AEConfig;
|
||||
import appeng.core.AppEng;
|
||||
import appeng.core.CreativeTab;
|
||||
import appeng.core.features.AEFeature;
|
||||
import appeng.core.features.ActivityState;
|
||||
import appeng.core.features.BlockDefinition;
|
||||
import appeng.core.features.BlockStackSrc;
|
||||
import appeng.core.features.TileDefinition;
|
||||
import appeng.tile.AEBaseTile;
|
||||
import appeng.util.Platform;
|
||||
|
||||
|
||||
class BlockDefinitionBuilder implements IBlockBuilder
|
||||
{
|
||||
|
||||
private final FeatureFactory factory;
|
||||
|
||||
private final String registryName;
|
||||
|
||||
private final Supplier<? extends Block> blockSupplier;
|
||||
|
||||
private final List<BiConsumer<Block, Item>> preInitCallbacks = new ArrayList<>();
|
||||
|
||||
private final List<BiConsumer<Block, Item>> initCallbacks = new ArrayList<>();
|
||||
|
||||
private final List<BiConsumer<Block, Item>> postInitCallbacks = new ArrayList<>();
|
||||
|
||||
private final EnumSet<AEFeature> features = EnumSet.noneOf( AEFeature.class );
|
||||
|
||||
private CreativeTabs creativeTab = CreativeTab.instance;
|
||||
|
||||
private Function<Block, ItemBlock> itemFactory;
|
||||
|
||||
@SideOnly( Side.CLIENT )
|
||||
private BlockRendering blockRendering;
|
||||
|
||||
@SideOnly( Side.CLIENT )
|
||||
private ItemRendering itemRendering;
|
||||
|
||||
BlockDefinitionBuilder( FeatureFactory factory, String id, Supplier<? extends Block> blockSupplier )
|
||||
{
|
||||
this.factory = factory;
|
||||
this.registryName = id;
|
||||
this.blockSupplier = blockSupplier;
|
||||
|
||||
if( Platform.isClient() )
|
||||
{
|
||||
blockRendering = new BlockRendering();
|
||||
itemRendering = new ItemRendering();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockDefinitionBuilder preInit( BiConsumer<Block, Item> callback )
|
||||
{
|
||||
preInitCallbacks.add( callback );
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockDefinitionBuilder init( BiConsumer<Block, Item> callback )
|
||||
{
|
||||
initCallbacks.add( callback );
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockDefinitionBuilder postInit( BiConsumer<Block, Item> callback )
|
||||
{
|
||||
postInitCallbacks.add( callback );
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBlockBuilder features( AEFeature... features )
|
||||
{
|
||||
this.features.clear();
|
||||
addFeatures( features );
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBlockBuilder addFeatures( AEFeature... features )
|
||||
{
|
||||
Collections.addAll( this.features, features );
|
||||
return this;
|
||||
}
|
||||
|
||||
public BlockDefinitionBuilder rendering( BlockRenderingCustomizer callback )
|
||||
{
|
||||
if( Platform.isClient() )
|
||||
{
|
||||
customizeForClient( callback );
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBlockBuilder item( Function<Block, ItemBlock> factory )
|
||||
{
|
||||
this.itemFactory = factory;
|
||||
return this;
|
||||
}
|
||||
|
||||
@SideOnly( Side.CLIENT )
|
||||
private void customizeForClient( BlockRenderingCustomizer callback )
|
||||
{
|
||||
callback.customize( blockRendering, itemRendering );
|
||||
}
|
||||
|
||||
@SuppressWarnings( "unchecked" )
|
||||
@Override
|
||||
public <T extends IBlockDefinition> T build()
|
||||
{
|
||||
if( !AEConfig.instance.areFeaturesEnabled( features ) )
|
||||
{
|
||||
return (T) new TileDefinition( registryName, null, null );
|
||||
}
|
||||
|
||||
// Create block and matching item, and set factory name of both
|
||||
Block block = blockSupplier.get();
|
||||
block.setRegistryName( AppEng.MOD_ID, registryName );
|
||||
|
||||
ItemBlock item = constructItemFromBlock( block );
|
||||
item.setRegistryName( AppEng.MOD_ID, registryName );
|
||||
|
||||
// Register the item and block with the game
|
||||
factory.addPreInit( side ->
|
||||
{
|
||||
GameRegistry.register( block );
|
||||
GameRegistry.register( item );
|
||||
} );
|
||||
|
||||
block.setCreativeTab( creativeTab );
|
||||
block.setUnlocalizedName( "appliedenergistics2." + registryName );
|
||||
|
||||
// Register all extra handlers
|
||||
preInitCallbacks.forEach( consumer -> factory.addPreInit( side -> consumer.accept( block, item ) ) );
|
||||
initCallbacks.forEach( consumer -> factory.addInit( side -> consumer.accept( block, item ) ) );
|
||||
postInitCallbacks.forEach( consumer -> factory.addPostInit( side -> consumer.accept( block, item ) ) );
|
||||
|
||||
if( Platform.isClient() )
|
||||
{
|
||||
if( block instanceof AEBaseTileBlock )
|
||||
{
|
||||
AEBaseTileBlock tileBlock = (AEBaseTileBlock) block;
|
||||
blockRendering.apply( factory, block, tileBlock.getTileEntityClass() );
|
||||
}
|
||||
else
|
||||
{
|
||||
blockRendering.apply( factory, block, null );
|
||||
}
|
||||
|
||||
itemRendering.apply( factory, item );
|
||||
}
|
||||
|
||||
if( block instanceof AEBaseTileBlock )
|
||||
{
|
||||
AEBaseTileBlock tileBlock = (AEBaseTileBlock) block;
|
||||
|
||||
factory.addPreInit( side ->
|
||||
{
|
||||
Class<? extends AEBaseTile> tileEntityClass = tileBlock.getTileEntityClass();
|
||||
AEBaseTile.registerTileItem( tileEntityClass, new BlockStackSrc( block, 0, ActivityState.Enabled ) );
|
||||
|
||||
GameRegistry.registerTileEntity( tileEntityClass, registryName );
|
||||
} );
|
||||
|
||||
return (T) new TileDefinition( registryName, (AEBaseTileBlock) block, item );
|
||||
}
|
||||
else
|
||||
{
|
||||
return (T) new BlockDefinition( registryName, block, item );
|
||||
}
|
||||
}
|
||||
|
||||
private ItemBlock constructItemFromBlock( Block block )
|
||||
{
|
||||
if( itemFactory != null )
|
||||
{
|
||||
return itemFactory.apply( block );
|
||||
}
|
||||
else if( block instanceof AEBaseBlock )
|
||||
{
|
||||
return new AEBaseItemBlock( block );
|
||||
}
|
||||
else
|
||||
{
|
||||
return new ItemBlock( block );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
package appeng.bootstrap;
|
||||
|
||||
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.client.renderer.block.model.IBakedModel;
|
||||
import net.minecraft.client.renderer.block.model.ModelResourceLocation;
|
||||
import net.minecraft.client.renderer.block.statemap.IStateMapper;
|
||||
import net.minecraft.client.renderer.color.IBlockColor;
|
||||
import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||
|
||||
import appeng.block.AEBaseTileBlock;
|
||||
import appeng.bootstrap.components.BlockColorComponent;
|
||||
import appeng.bootstrap.components.StateMapperComponent;
|
||||
import appeng.bootstrap.components.TesrComponent;
|
||||
import appeng.client.render.model.CachingRotatingBakedModel;
|
||||
|
||||
|
||||
class BlockRendering implements IBlockRendering
|
||||
{
|
||||
|
||||
@SideOnly( Side.CLIENT )
|
||||
private BiFunction<ModelResourceLocation, IBakedModel, IBakedModel> modelCustomizer;
|
||||
|
||||
@SideOnly( Side.CLIENT )
|
||||
private IBlockColor blockColor;
|
||||
|
||||
@SideOnly( Side.CLIENT )
|
||||
private TileEntitySpecialRenderer<?> tesr;
|
||||
|
||||
@SideOnly( Side.CLIENT )
|
||||
private IStateMapper stateMapper;
|
||||
|
||||
@SideOnly( Side.CLIENT )
|
||||
public IBlockRendering modelCustomizer( BiFunction<ModelResourceLocation, IBakedModel, IBakedModel> customizer )
|
||||
{
|
||||
modelCustomizer = customizer;
|
||||
return this;
|
||||
}
|
||||
|
||||
@SideOnly( Side.CLIENT )
|
||||
@Override
|
||||
public IBlockRendering blockColor( IBlockColor blockColor )
|
||||
{
|
||||
this.blockColor = blockColor;
|
||||
return this;
|
||||
}
|
||||
|
||||
@SideOnly( Side.CLIENT )
|
||||
@Override
|
||||
public IBlockRendering tesr( TileEntitySpecialRenderer<?> tesr )
|
||||
{
|
||||
this.tesr = tesr;
|
||||
return this;
|
||||
}
|
||||
|
||||
@SideOnly( Side.CLIENT )
|
||||
@Override
|
||||
public IBlockRendering stateMapper( IStateMapper mapper )
|
||||
{
|
||||
this.stateMapper = mapper;
|
||||
return this;
|
||||
}
|
||||
|
||||
void apply( FeatureFactory registry, Block block, Class<?> tileEntityClass )
|
||||
{
|
||||
if( tesr != null )
|
||||
{
|
||||
if( tileEntityClass == null )
|
||||
{
|
||||
throw new IllegalStateException( "Tried to register a TESR for " + block + " even though no tile entity has been specified." );
|
||||
}
|
||||
registry.addBootstrapComponent( new TesrComponent( tileEntityClass, tesr ) );
|
||||
}
|
||||
|
||||
if( modelCustomizer != null )
|
||||
{
|
||||
registry.modelOverrideComponent.addOverride( block.getRegistryName().getResourcePath(), modelCustomizer );
|
||||
}
|
||||
else if ( block instanceof AEBaseTileBlock )
|
||||
{
|
||||
// This is a default rotating model if the base-block uses an AE tile entity which exposes UP/FRONT as extended props
|
||||
registry.modelOverrideComponent.addOverride( block.getRegistryName().getResourcePath(), ( l, m ) -> new CachingRotatingBakedModel( m ) );
|
||||
}
|
||||
|
||||
if( blockColor != null )
|
||||
{
|
||||
registry.addBootstrapComponent( new BlockColorComponent( block, blockColor ) );
|
||||
}
|
||||
|
||||
if( stateMapper != null )
|
||||
{
|
||||
registry.addBootstrapComponent( new StateMapperComponent( block, stateMapper ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package appeng.bootstrap;
|
||||
|
||||
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||
|
||||
|
||||
/**
|
||||
* A callback that allows the rendering of a block to be customized. Sadly this class is required and no lambdas can be used
|
||||
* due to them not being able to be annotated with @SideOnly(CLIENT).
|
||||
*/
|
||||
public abstract class BlockRenderingCustomizer
|
||||
{
|
||||
|
||||
@SideOnly( Side.CLIENT )
|
||||
public abstract void customize( IBlockRendering rendering, IItemRendering itemRendering );
|
||||
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
package appeng.bootstrap;
|
||||
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||
|
||||
import appeng.api.definitions.IItemDefinition;
|
||||
import appeng.api.util.AEColor;
|
||||
import appeng.api.util.AEColoredItemDefinition;
|
||||
import appeng.bootstrap.components.InitComponent;
|
||||
import appeng.bootstrap.components.ModelOverrideComponent;
|
||||
import appeng.bootstrap.components.PostInitComponent;
|
||||
import appeng.bootstrap.components.PreInitComponent;
|
||||
import appeng.core.features.AEFeature;
|
||||
import appeng.core.features.ActivityState;
|
||||
import appeng.core.features.ColoredItemDefinition;
|
||||
import appeng.core.features.ItemStackSrc;
|
||||
import appeng.util.Platform;
|
||||
|
||||
|
||||
public class FeatureFactory
|
||||
{
|
||||
|
||||
private final AEFeature[] defaultFeatures;
|
||||
|
||||
private final List<IBootstrapComponent> bootstrapComponents;
|
||||
|
||||
@SideOnly( Side.CLIENT )
|
||||
ModelOverrideComponent modelOverrideComponent;
|
||||
|
||||
public FeatureFactory()
|
||||
{
|
||||
this.defaultFeatures = new AEFeature[] { AEFeature.Core };
|
||||
this.bootstrapComponents = new ArrayList<>();
|
||||
|
||||
if( Platform.isClient() )
|
||||
{
|
||||
modelOverrideComponent = new ModelOverrideComponent();
|
||||
this.bootstrapComponents.add( modelOverrideComponent );
|
||||
}
|
||||
}
|
||||
|
||||
private FeatureFactory( FeatureFactory parent, AEFeature... defaultFeatures )
|
||||
{
|
||||
this.defaultFeatures = defaultFeatures.clone();
|
||||
this.bootstrapComponents = parent.bootstrapComponents;
|
||||
if( Platform.isClient() )
|
||||
{
|
||||
this.modelOverrideComponent = parent.modelOverrideComponent;
|
||||
}
|
||||
}
|
||||
|
||||
public IBlockBuilder block( String id, Supplier<Block> block )
|
||||
{
|
||||
return new BlockDefinitionBuilder( this, id, block ).features( defaultFeatures );
|
||||
}
|
||||
|
||||
public IItemBuilder item( String id, Supplier<Item> item )
|
||||
{
|
||||
return new ItemDefinitionBuilder( this, id, item ).features( defaultFeatures );
|
||||
}
|
||||
|
||||
public AEColoredItemDefinition colored( IItemDefinition target, int offset )
|
||||
{
|
||||
final ColoredItemDefinition definition = new ColoredItemDefinition();
|
||||
|
||||
for( final Item targetItem : target.maybeItem().asSet() )
|
||||
{
|
||||
for( final AEColor color : AEColor.VALID_COLORS )
|
||||
{
|
||||
final ActivityState state = ActivityState.from( target.isEnabled() );
|
||||
|
||||
definition.add( color, new ItemStackSrc( targetItem, offset + color.ordinal(), state ) );
|
||||
}
|
||||
}
|
||||
|
||||
return definition;
|
||||
}
|
||||
|
||||
public FeatureFactory features( AEFeature... features )
|
||||
{
|
||||
return new FeatureFactory( this, features );
|
||||
}
|
||||
|
||||
void addBootstrapComponent( IBootstrapComponent component )
|
||||
{
|
||||
this.bootstrapComponents.add( component );
|
||||
}
|
||||
|
||||
void addPreInit( PreInitComponent component )
|
||||
{
|
||||
this.bootstrapComponents.add( component );
|
||||
}
|
||||
|
||||
void addInit( InitComponent component )
|
||||
{
|
||||
this.bootstrapComponents.add( component );
|
||||
}
|
||||
|
||||
void addPostInit( PostInitComponent component )
|
||||
{
|
||||
this.bootstrapComponents.add( component );
|
||||
}
|
||||
|
||||
public List<IBootstrapComponent> getBootstrapComponents()
|
||||
{
|
||||
return bootstrapComponents;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package appeng.bootstrap;
|
||||
|
||||
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Function;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemBlock;
|
||||
|
||||
import appeng.api.definitions.IBlockDefinition;
|
||||
import appeng.core.features.AEFeature;
|
||||
|
||||
|
||||
public interface IBlockBuilder
|
||||
{
|
||||
|
||||
IBlockBuilder preInit( BiConsumer<Block, Item> callback );
|
||||
|
||||
IBlockBuilder init( BiConsumer<Block, Item> callback );
|
||||
|
||||
IBlockBuilder postInit( BiConsumer<Block, Item> callback );
|
||||
|
||||
IBlockBuilder features( AEFeature... features );
|
||||
|
||||
IBlockBuilder addFeatures( AEFeature... features );
|
||||
|
||||
IBlockBuilder rendering( BlockRenderingCustomizer callback );
|
||||
|
||||
IBlockBuilder item( Function<Block, ItemBlock> factory );
|
||||
|
||||
<T extends IBlockDefinition> T build();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package appeng.bootstrap;
|
||||
|
||||
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
import net.minecraft.client.renderer.block.model.IBakedModel;
|
||||
import net.minecraft.client.renderer.block.model.ModelResourceLocation;
|
||||
import net.minecraft.client.renderer.block.statemap.IStateMapper;
|
||||
import net.minecraft.client.renderer.color.IBlockColor;
|
||||
import net.minecraft.client.renderer.color.IItemColor;
|
||||
import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||
|
||||
|
||||
/**
|
||||
* Allows for client-side rendering to be customized in the context of block/item registration.
|
||||
*/
|
||||
public interface IBlockRendering
|
||||
{
|
||||
|
||||
@SideOnly( Side.CLIENT )
|
||||
IBlockRendering modelCustomizer( BiFunction<ModelResourceLocation, IBakedModel, IBakedModel> customizer );
|
||||
|
||||
@SideOnly( Side.CLIENT )
|
||||
IBlockRendering blockColor( IBlockColor blockColor );
|
||||
|
||||
@SideOnly( Side.CLIENT )
|
||||
IBlockRendering stateMapper( IStateMapper mapper );
|
||||
|
||||
@SideOnly( Side.CLIENT )
|
||||
IBlockRendering tesr( TileEntitySpecialRenderer<?> tesr );
|
||||
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package appeng.bootstrap;
|
||||
|
||||
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
|
||||
|
||||
/**
|
||||
* Bootstrap components can be registered to take part in the various initialization phases of Forge.
|
||||
*/
|
||||
public interface IBootstrapComponent
|
||||
{
|
||||
|
||||
default void preInitialize( Side side )
|
||||
{
|
||||
}
|
||||
|
||||
default void initialize( Side side )
|
||||
{
|
||||
}
|
||||
|
||||
default void postInitialize( Side side )
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package appeng.bootstrap;
|
||||
|
||||
|
||||
import net.minecraft.creativetab.CreativeTabs;
|
||||
|
||||
import appeng.core.features.AEFeature;
|
||||
import appeng.core.features.ItemDefinition;
|
||||
import appeng.util.Platform;
|
||||
|
||||
|
||||
/**
|
||||
* Allows an item to be defined and registered with the game.
|
||||
* The item is only registered once build is called.
|
||||
*/
|
||||
public interface IItemBuilder
|
||||
{
|
||||
|
||||
IItemBuilder features( AEFeature... features );
|
||||
|
||||
IItemBuilder addFeatures( AEFeature... features );
|
||||
|
||||
IItemBuilder creativeTab( CreativeTabs tab );
|
||||
|
||||
IItemBuilder rendering( ItemRenderingCustomizer callback );
|
||||
|
||||
ItemDefinition build();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
package appeng.bootstrap;
|
||||
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
|
||||
import net.minecraft.client.renderer.ItemMeshDefinition;
|
||||
import net.minecraft.client.renderer.block.model.ModelResourceLocation;
|
||||
import net.minecraft.client.renderer.color.IItemColor;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||
|
||||
|
||||
/**
|
||||
* Allows the rendering of an item to be customized.
|
||||
*/
|
||||
public interface IItemRendering
|
||||
{
|
||||
|
||||
/**
|
||||
* Registers a custom item mesh definition that will be used to dynamically determine the
|
||||
* item model to be used for rendering by inspecting the item stack (i.e. for NBT data).
|
||||
* Please
|
||||
*/
|
||||
@SideOnly( Side.CLIENT )
|
||||
IItemRendering meshDefinition( ItemMeshDefinition meshDefinition );
|
||||
|
||||
/**
|
||||
* Registers an item model for meta=0, see {@link #model(int, ModelResourceLocation)}.
|
||||
*/
|
||||
@SideOnly( Side.CLIENT )
|
||||
default IItemRendering model( ModelResourceLocation model )
|
||||
{
|
||||
return model( 0, model );
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers an item model for a given meta.
|
||||
*/
|
||||
@SideOnly( Side.CLIENT )
|
||||
IItemRendering model( int meta, ModelResourceLocation model );
|
||||
|
||||
/**
|
||||
* Convenient override for {@link #variants(Collection)}.
|
||||
*/
|
||||
@SideOnly( Side.CLIENT )
|
||||
default IItemRendering variants( ResourceLocation... resources )
|
||||
{
|
||||
return variants( Arrays.asList( resources ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the item variants of this item. This are all models that need to be loaded for this item.
|
||||
* This has no direct effect on rendering, but is used to load models that are used for example by
|
||||
* the ItemMeshDefinition.
|
||||
*
|
||||
* Models registered via {@link #model(int, ModelResourceLocation)} are automatically added here.
|
||||
*/
|
||||
@SideOnly( Side.CLIENT )
|
||||
IItemRendering variants( Collection<ResourceLocation> resources );
|
||||
|
||||
/**
|
||||
* Registers a custom item color definition that inspects an item stack and tint and
|
||||
* returns a color multiplier.
|
||||
*/
|
||||
@SideOnly( Side.CLIENT )
|
||||
IItemRendering color( IItemColor itemColor );
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
package appeng.bootstrap;
|
||||
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.EnumSet;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import net.minecraft.creativetab.CreativeTabs;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraftforge.fml.common.registry.GameRegistry;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||
|
||||
import appeng.core.AEConfig;
|
||||
import appeng.core.AppEng;
|
||||
import appeng.core.CreativeTab;
|
||||
import appeng.core.features.AEFeature;
|
||||
import appeng.core.features.ItemDefinition;
|
||||
import appeng.util.Platform;
|
||||
|
||||
|
||||
class ItemDefinitionBuilder implements IItemBuilder
|
||||
{
|
||||
|
||||
private final FeatureFactory factory;
|
||||
|
||||
private final String registryName;
|
||||
|
||||
private final Supplier<Item> itemSupplier;
|
||||
|
||||
private final EnumSet<AEFeature> features = EnumSet.noneOf( AEFeature.class );
|
||||
|
||||
@SideOnly( Side.CLIENT )
|
||||
private ItemRendering itemRendering;
|
||||
|
||||
private CreativeTabs creativeTab = CreativeTab.instance;
|
||||
|
||||
ItemDefinitionBuilder( FeatureFactory factory, String registryName, Supplier<Item> itemSupplier )
|
||||
{
|
||||
this.factory = factory;
|
||||
this.registryName = registryName;
|
||||
this.itemSupplier = itemSupplier;
|
||||
if( Platform.isClient() )
|
||||
{
|
||||
itemRendering = new ItemRendering();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public IItemBuilder features( AEFeature... features )
|
||||
{
|
||||
this.features.clear();
|
||||
addFeatures( features );
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IItemBuilder addFeatures( AEFeature... features )
|
||||
{
|
||||
Collections.addAll( this.features, features );
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IItemBuilder creativeTab( CreativeTabs tab )
|
||||
{
|
||||
this.creativeTab = tab;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IItemBuilder rendering( ItemRenderingCustomizer callback )
|
||||
{
|
||||
if( Platform.isClient() )
|
||||
{
|
||||
customizeForClient( callback );
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@SideOnly( Side.CLIENT )
|
||||
private void customizeForClient( ItemRenderingCustomizer callback )
|
||||
{
|
||||
callback.customize( itemRendering );
|
||||
}
|
||||
|
||||
public ItemDefinition build()
|
||||
{
|
||||
if( !AEConfig.instance.areFeaturesEnabled( features ) )
|
||||
{
|
||||
return new ItemDefinition( registryName, null );
|
||||
}
|
||||
|
||||
Item item = itemSupplier.get();
|
||||
item.setRegistryName( AppEng.MOD_ID, registryName );
|
||||
|
||||
ItemDefinition definition = new ItemDefinition( registryName, item );
|
||||
|
||||
item.setUnlocalizedName( "appliedenergistics2." + registryName );
|
||||
item.setCreativeTab( creativeTab );
|
||||
|
||||
factory.addPreInit( side -> GameRegistry.register( item ) );
|
||||
|
||||
if( Platform.isClient() )
|
||||
{
|
||||
itemRendering.apply( factory, item );
|
||||
}
|
||||
|
||||
return definition;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
package appeng.bootstrap;
|
||||
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.state.IBlockState;
|
||||
import net.minecraft.client.renderer.ItemMeshDefinition;
|
||||
import net.minecraft.client.renderer.block.model.ModelResourceLocation;
|
||||
import net.minecraft.client.renderer.block.statemap.StateMapperBase;
|
||||
import net.minecraft.client.renderer.color.IItemColor;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemBlock;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||
|
||||
import appeng.bootstrap.components.ItemColorComponent;
|
||||
import appeng.bootstrap.components.ItemMeshDefinitionComponent;
|
||||
import appeng.bootstrap.components.ItemModelComponent;
|
||||
import appeng.bootstrap.components.ItemVariantsComponent;
|
||||
|
||||
|
||||
class ItemRendering implements IItemRendering
|
||||
{
|
||||
|
||||
@SideOnly( Side.CLIENT )
|
||||
private IItemColor itemColor;
|
||||
|
||||
@SideOnly( Side.CLIENT )
|
||||
private ItemMeshDefinition itemMeshDefinition;
|
||||
|
||||
@SideOnly( Side.CLIENT )
|
||||
private Map<Integer, ModelResourceLocation> itemModels = new HashMap<>();
|
||||
|
||||
@SideOnly( Side.CLIENT )
|
||||
private Set<ResourceLocation> variants = new HashSet<>();
|
||||
|
||||
@Override
|
||||
@SideOnly( Side.CLIENT )
|
||||
public IItemRendering meshDefinition( ItemMeshDefinition meshDefinition )
|
||||
{
|
||||
this.itemMeshDefinition = meshDefinition;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SideOnly( Side.CLIENT )
|
||||
public IItemRendering model( int meta, ModelResourceLocation model )
|
||||
{
|
||||
this.itemModels.put( meta, model );
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IItemRendering variants( Collection<ResourceLocation> resources )
|
||||
{
|
||||
this.variants.addAll( resources );
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SideOnly( Side.CLIENT )
|
||||
public IItemRendering color( IItemColor itemColor )
|
||||
{
|
||||
this.itemColor = itemColor;
|
||||
return this;
|
||||
}
|
||||
|
||||
void apply( FeatureFactory factory, Item item )
|
||||
{
|
||||
if( this.itemMeshDefinition != null )
|
||||
{
|
||||
factory.addBootstrapComponent( new ItemMeshDefinitionComponent( item, itemMeshDefinition ) );
|
||||
}
|
||||
|
||||
if( !this.itemModels.isEmpty() )
|
||||
{
|
||||
factory.addBootstrapComponent( new ItemModelComponent( item, this.itemModels ) );
|
||||
}
|
||||
|
||||
Set<ResourceLocation> resources = new HashSet<>( variants );
|
||||
|
||||
// Register a default item model if neither items by meta nor an item mesh definition exist
|
||||
if( this.itemMeshDefinition == null && this.itemModels.isEmpty() )
|
||||
{
|
||||
ModelResourceLocation model;
|
||||
|
||||
// For block items, the default will try to use the default state of the associated block
|
||||
if( item instanceof ItemBlock )
|
||||
{
|
||||
Block block = ( (ItemBlock) item ).getBlock();
|
||||
|
||||
// We can only do this once the blocks are actually registered...
|
||||
StateMapperHelper helper = new StateMapperHelper( block.getRegistryName() );
|
||||
model = helper.getModelResourceLocation( block.getDefaultState() );
|
||||
}
|
||||
else
|
||||
{
|
||||
model = new ModelResourceLocation( item.getRegistryName(), "inventory" );
|
||||
}
|
||||
|
||||
factory.addBootstrapComponent( new ItemModelComponent( item, ImmutableMap.of( 0, model ) ) );
|
||||
resources.add( model );
|
||||
}
|
||||
|
||||
if( !resources.isEmpty() )
|
||||
{
|
||||
factory.addBootstrapComponent( new ItemVariantsComponent( item, resources ) );
|
||||
}
|
||||
|
||||
if( itemColor != null )
|
||||
{
|
||||
factory.addBootstrapComponent( new ItemColorComponent( item, itemColor ) );
|
||||
}
|
||||
}
|
||||
|
||||
private static class StateMapperHelper extends StateMapperBase
|
||||
{
|
||||
|
||||
private final ResourceLocation registryName;
|
||||
|
||||
public StateMapperHelper( ResourceLocation registryName )
|
||||
{
|
||||
this.registryName = registryName;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ModelResourceLocation getModelResourceLocation( IBlockState state )
|
||||
{
|
||||
return new ModelResourceLocation( registryName, getPropertyString( state.getProperties() ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package appeng.bootstrap;
|
||||
|
||||
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||
|
||||
|
||||
/**
|
||||
* A callback that allows the rendering of a item to be customized. Sadly this class is required and no lambdas can be used
|
||||
* due to them not being able to be annotated with @SideOnly(CLIENT).
|
||||
*/
|
||||
public abstract class ItemRenderingCustomizer
|
||||
{
|
||||
|
||||
@SideOnly( Side.CLIENT )
|
||||
public abstract void customize( IItemRendering rendering );
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package appeng.bootstrap.components;
|
||||
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.color.IBlockColor;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
|
||||
|
||||
public class BlockColorComponent implements InitComponent
|
||||
{
|
||||
|
||||
private final Block block;
|
||||
|
||||
private final IBlockColor blockColor;
|
||||
|
||||
public BlockColorComponent( Block block, IBlockColor blockColor )
|
||||
{
|
||||
this.block = block;
|
||||
this.blockColor = blockColor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize( Side side )
|
||||
{
|
||||
Minecraft.getMinecraft().getBlockColors().registerBlockColorHandler( blockColor, block );
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package appeng.bootstrap.components;
|
||||
|
||||
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
|
||||
import appeng.bootstrap.IBootstrapComponent;
|
||||
|
||||
|
||||
@FunctionalInterface
|
||||
public interface InitComponent extends IBootstrapComponent
|
||||
{
|
||||
|
||||
@Override
|
||||
void initialize( Side side );
|
||||
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package appeng.bootstrap.components;
|
||||
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.color.IItemColor;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
|
||||
|
||||
public class ItemColorComponent implements InitComponent
|
||||
{
|
||||
|
||||
private final Item item;
|
||||
|
||||
private final IItemColor itemColor;
|
||||
|
||||
public ItemColorComponent( Item item, IItemColor itemColor )
|
||||
{
|
||||
this.item = item;
|
||||
this.itemColor = itemColor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize( Side side )
|
||||
{
|
||||
Minecraft.getMinecraft().getItemColors().registerItemColorHandler( itemColor, item );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package appeng.bootstrap.components;
|
||||
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.ItemMeshDefinition;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
|
||||
|
||||
/**
|
||||
* Registers a custom item mesh definition that can be used to dynamically determine the item model based on
|
||||
* item stack properties.
|
||||
*/
|
||||
public class ItemMeshDefinitionComponent implements InitComponent
|
||||
{
|
||||
|
||||
private final Item item;
|
||||
|
||||
private final ItemMeshDefinition meshDefinition;
|
||||
|
||||
public ItemMeshDefinitionComponent( @Nonnull Item item, @Nonnull ItemMeshDefinition meshDefinition )
|
||||
{
|
||||
this.item = item;
|
||||
this.meshDefinition = meshDefinition;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize( Side side )
|
||||
{
|
||||
Minecraft.getMinecraft().getRenderItem().getItemModelMesher().register( item, meshDefinition );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package appeng.bootstrap.components;
|
||||
|
||||
|
||||
import java.util.Map;
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.ItemModelMesher;
|
||||
import net.minecraft.client.renderer.block.model.ModelResourceLocation;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
|
||||
|
||||
/**
|
||||
* Registers the models that should by used for an item, including the ability to
|
||||
* distinguish by meta.
|
||||
*/
|
||||
public class ItemModelComponent implements InitComponent
|
||||
{
|
||||
|
||||
private final Item item;
|
||||
|
||||
private final Map<Integer, ModelResourceLocation> modelsByMeta;
|
||||
|
||||
public ItemModelComponent( @Nonnull Item item, @Nonnull Map<Integer, ModelResourceLocation> modelsByMeta )
|
||||
{
|
||||
this.item = item;
|
||||
this.modelsByMeta = modelsByMeta;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize( Side side )
|
||||
{
|
||||
ItemModelMesher itemMesher = Minecraft.getMinecraft().getRenderItem().getItemModelMesher();
|
||||
|
||||
modelsByMeta.forEach( ( meta, model ) ->
|
||||
{
|
||||
itemMesher.register( item, meta, model );
|
||||
} );
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package appeng.bootstrap.components;
|
||||
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import net.minecraft.client.renderer.block.model.ModelBakery;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
|
||||
import appeng.bootstrap.IBootstrapComponent;
|
||||
|
||||
|
||||
public class ItemVariantsComponent implements IBootstrapComponent
|
||||
{
|
||||
|
||||
private final Item item;
|
||||
|
||||
private final Collection<ResourceLocation> resources;
|
||||
|
||||
public ItemVariantsComponent( Item item, Collection<ResourceLocation> resources )
|
||||
{
|
||||
this.item = item;
|
||||
this.resources = resources;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preInitialize( Side side )
|
||||
{
|
||||
ResourceLocation[] resourceArr = resources.toArray( new ResourceLocation[0] );
|
||||
ModelBakery.registerItemVariants( item, resourceArr );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
package appeng.bootstrap.components;
|
||||
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
import com.google.common.collect.Sets;
|
||||
|
||||
import net.minecraft.client.renderer.block.model.IBakedModel;
|
||||
import net.minecraft.client.renderer.block.model.ModelResourceLocation;
|
||||
import net.minecraft.util.registry.IRegistry;
|
||||
import net.minecraftforge.client.event.ModelBakeEvent;
|
||||
import net.minecraftforge.common.MinecraftForge;
|
||||
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
|
||||
import appeng.core.AppEng;
|
||||
|
||||
|
||||
public class ModelOverrideComponent implements PreInitComponent
|
||||
{
|
||||
|
||||
// Maps from resource path to customizer
|
||||
private final Map<String, BiFunction<ModelResourceLocation, IBakedModel, IBakedModel>> customizer = new HashMap<>();
|
||||
|
||||
public void addOverride( String resourcePath, BiFunction<ModelResourceLocation, IBakedModel, IBakedModel> customizer )
|
||||
{
|
||||
this.customizer.put( resourcePath, customizer );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preInitialize( Side side )
|
||||
{
|
||||
MinecraftForge.EVENT_BUS.register( this );
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public void onModelBakeEvent( final ModelBakeEvent event )
|
||||
{
|
||||
IRegistry<ModelResourceLocation, IBakedModel> modelRegistry = event.getModelRegistry();
|
||||
Set<ModelResourceLocation> keys = Sets.newHashSet( modelRegistry.getKeys() );
|
||||
|
||||
for( ModelResourceLocation location : keys )
|
||||
{
|
||||
if( !location.getResourceDomain().equals( AppEng.MOD_ID ) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
BiFunction<ModelResourceLocation, IBakedModel, IBakedModel> customizer = this.customizer.get( location.getResourcePath() );
|
||||
if( customizer != null )
|
||||
{
|
||||
IBakedModel orgModel = modelRegistry.getObject( location );
|
||||
IBakedModel newModel = customizer.apply( location, orgModel );
|
||||
|
||||
if( newModel != orgModel )
|
||||
{
|
||||
modelRegistry.putObject( location, newModel );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package appeng.bootstrap.components;
|
||||
|
||||
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
|
||||
import appeng.bootstrap.IBootstrapComponent;
|
||||
|
||||
|
||||
@FunctionalInterface
|
||||
public interface PostInitComponent extends IBootstrapComponent
|
||||
{
|
||||
|
||||
@Override
|
||||
void postInitialize( Side side );
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package appeng.bootstrap.components;
|
||||
|
||||
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
|
||||
import appeng.bootstrap.IBootstrapComponent;
|
||||
|
||||
@FunctionalInterface
|
||||
public interface PreInitComponent extends IBootstrapComponent
|
||||
{
|
||||
|
||||
@Override
|
||||
void preInitialize( Side side );
|
||||
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package appeng.bootstrap.components;
|
||||
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.block.statemap.IStateMapper;
|
||||
import net.minecraft.client.resources.IReloadableResourceManager;
|
||||
import net.minecraft.client.resources.IResourceManagerReloadListener;
|
||||
import net.minecraftforge.client.model.ModelLoader;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
|
||||
|
||||
/**
|
||||
* Registers a custom state mapper for a given block.
|
||||
*/
|
||||
public class StateMapperComponent implements InitComponent
|
||||
{
|
||||
|
||||
private final Block block;
|
||||
|
||||
private final IStateMapper stateMapper;
|
||||
|
||||
public StateMapperComponent( Block block, IStateMapper stateMapper )
|
||||
{
|
||||
this.block = block;
|
||||
this.stateMapper = stateMapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize( Side side )
|
||||
{
|
||||
ModelLoader.setCustomStateMapper( block, stateMapper );
|
||||
if( stateMapper instanceof IResourceManagerReloadListener )
|
||||
{
|
||||
( (IReloadableResourceManager) Minecraft.getMinecraft().getResourceManager() ).registerReloadListener( (IResourceManagerReloadListener) stateMapper );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package appeng.bootstrap.components;
|
||||
|
||||
|
||||
import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer;
|
||||
import net.minecraftforge.fml.client.registry.ClientRegistry;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
|
||||
import appeng.tile.AEBaseTile;
|
||||
|
||||
|
||||
/**
|
||||
* Registers a TESR for a given tile entity class.
|
||||
*
|
||||
* @param <T>
|
||||
*/
|
||||
public class TesrComponent<T extends AEBaseTile> implements PreInitComponent
|
||||
{
|
||||
|
||||
private final Class<T> tileEntityClass;
|
||||
|
||||
private final TileEntitySpecialRenderer<? super T> tesr;
|
||||
|
||||
public TesrComponent( Class<T> tileEntityClass, TileEntitySpecialRenderer<? super T> tesr )
|
||||
{
|
||||
this.tileEntityClass = tileEntityClass;
|
||||
this.tesr = tesr;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preInitialize( Side side )
|
||||
{
|
||||
ClientRegistry.bindTileEntitySpecialRenderer( tileEntityClass, tesr );
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user