Added model bake event (allows mods to insert custom baked models, much like TextureStitchEvent allows to load custom textures), ISmartBlock/ItemModel (ability form models to react to block/item states), Block.getExtendedState, support for unlisted properties in block states. Includes example implementation of http://imgur.com/a/FyyJX
This commit is contained in:
parent
1fc1570663
commit
134fbaa1ff
18 changed files with 720 additions and 22 deletions
|
@ -161,7 +161,7 @@
|
|||
}
|
||||
|
||||
protected ItemStack func_180643_i(IBlockState p_180643_1_)
|
||||
@@ -971,6 +989,1011 @@
|
||||
@@ -971,6 +989,1019 @@
|
||||
return Block.EnumOffsetType.NONE;
|
||||
}
|
||||
|
||||
|
@ -1145,6 +1145,14 @@
|
|||
+ return type != null && type.equals(getHarvestTool(state));
|
||||
+ }
|
||||
+
|
||||
+ /**
|
||||
+ * Can return IExtendedBlockState
|
||||
+ */
|
||||
+ public IBlockState getExtendedState(IBlockState state, IBlockAccess world, BlockPos pos)
|
||||
+ {
|
||||
+ return func_176221_a(state, world, pos);
|
||||
+ }
|
||||
+
|
||||
+ // For Internal use only to capture droped items inside getDrops
|
||||
+ protected static ThreadLocal<Boolean> captureDrops = new ThreadLocal<Boolean>()
|
||||
+ {
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
--- ../src-base/minecraft/net/minecraft/block/state/BlockState.java
|
||||
+++ ../src-work/minecraft/net/minecraft/block/state/BlockState.java
|
||||
@@ -47,6 +47,16 @@
|
||||
|
||||
public BlockState(Block p_i45663_1_, IProperty ... p_i45663_2_)
|
||||
{
|
||||
+ this(p_i45663_1_, p_i45663_2_, null);
|
||||
+ }
|
||||
+
|
||||
+ protected StateImplementation createState(Block block, ImmutableMap properties, ImmutableMap unlistedProperties)
|
||||
+ {
|
||||
+ return new StateImplementation(block, properties);
|
||||
+ }
|
||||
+
|
||||
+ protected BlockState(Block p_i45663_1_, IProperty[] p_i45663_2_, ImmutableMap unlistedProperties)
|
||||
+ {
|
||||
this.field_177627_c = p_i45663_1_;
|
||||
Arrays.sort(p_i45663_2_, new Comparator()
|
||||
{
|
||||
@@ -70,7 +80,7 @@
|
||||
{
|
||||
List list = (List)iterator.next();
|
||||
Map map = MapPopulator.func_179400_b(this.field_177624_d, list);
|
||||
- BlockState.StateImplementation stateimplementation = new BlockState.StateImplementation(p_i45663_1_, ImmutableMap.copyOf(map), null);
|
||||
+ BlockState.StateImplementation stateimplementation = createState(p_i45663_1_, ImmutableMap.copyOf(map), unlistedProperties);
|
||||
linkedhashmap.put(map, stateimplementation);
|
||||
arraylist.add(stateimplementation);
|
||||
}
|
||||
@@ -231,5 +241,10 @@
|
||||
{
|
||||
this(p_i45661_1_, p_i45661_2_);
|
||||
}
|
||||
+
|
||||
+ public ImmutableTable<IProperty, Comparable, IBlockState> getPropertyValueTable()
|
||||
+ {
|
||||
+ return field_177238_c;
|
||||
+ }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
--- ../src-base/minecraft/net/minecraft/client/renderer/BlockRendererDispatcher.java
|
||||
+++ ../src-work/minecraft/net/minecraft/client/renderer/BlockRendererDispatcher.java
|
||||
@@ -129,6 +129,12 @@
|
||||
ibakedmodel = ((WeightedBakedModel)ibakedmodel).func_177564_a(MathHelper.func_180186_a(p_175022_3_));
|
||||
}
|
||||
|
||||
+ if(ibakedmodel instanceof net.minecraftforge.client.model.ISmartBlockModel)
|
||||
+ {
|
||||
+ IBlockState extendedState = block.getExtendedState(p_175022_1_, p_175022_2_, p_175022_3_);
|
||||
+ ibakedmodel = ((net.minecraftforge.client.model.ISmartBlockModel)ibakedmodel).handleBlockState(extendedState);
|
||||
+ }
|
||||
+
|
||||
return ibakedmodel;
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
--- ../src-base/minecraft/net/minecraft/client/renderer/ItemModelMesher.java
|
||||
+++ ../src-work/minecraft/net/minecraft/client/renderer/ItemModelMesher.java
|
||||
@@ -52,6 +52,11 @@
|
||||
}
|
||||
}
|
||||
|
||||
+ if(ibakedmodel instanceof net.minecraftforge.client.model.ISmartItemModel)
|
||||
+ {
|
||||
+ ibakedmodel = ((net.minecraftforge.client.model.ISmartItemModel)ibakedmodel).handleItemState(p_178089_1_);
|
||||
+ }
|
||||
+
|
||||
if (ibakedmodel == null)
|
||||
{
|
||||
ibakedmodel = this.field_178090_d.func_174951_a();
|
|
@ -0,0 +1,10 @@
|
|||
--- ../src-base/minecraft/net/minecraft/client/resources/model/ModelManager.java
|
||||
+++ ../src-work/minecraft/net/minecraft/client/resources/model/ModelManager.java
|
||||
@@ -28,6 +28,7 @@
|
||||
ModelBakery modelbakery = new ModelBakery(p_110549_1_, this.field_174956_b, this.field_174957_c);
|
||||
this.field_174958_a = modelbakery.func_177570_a();
|
||||
this.field_174955_d = (IBakedModel)this.field_174958_a.func_82594_a(ModelBakery.field_177604_a);
|
||||
+ net.minecraftforge.client.ForgeHooksClient.onModelBake(this, this.field_174958_a, modelbakery);
|
||||
this.field_174957_c.func_178124_c();
|
||||
}
|
||||
|
|
@ -2,41 +2,31 @@ package net.minecraftforge.client;
|
|||
|
||||
import static net.minecraftforge.common.ForgeVersion.Status.BETA;
|
||||
import static net.minecraftforge.common.ForgeVersion.Status.BETA_OUTDATED;
|
||||
import java.util.Random;
|
||||
import javax.imageio.ImageIO;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.BlockBed;
|
||||
import net.minecraft.block.BlockLiquid;
|
||||
import net.minecraft.block.state.IBlockState;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.audio.ISound;
|
||||
import net.minecraft.client.audio.SoundEventAccessorComposite;
|
||||
import net.minecraft.client.audio.SoundManager;
|
||||
import net.minecraft.client.entity.EntityPlayerSP;
|
||||
import net.minecraft.client.gui.FontRenderer;
|
||||
import net.minecraft.client.gui.GuiMainMenu;
|
||||
import net.minecraft.client.gui.GuiScreen;
|
||||
import net.minecraft.client.model.ModelBase;
|
||||
import net.minecraft.client.model.ModelBiped;
|
||||
import net.minecraft.client.renderer.EntityRenderer;
|
||||
import net.minecraft.client.renderer.GlStateManager;
|
||||
import net.minecraft.client.renderer.RenderGlobal;
|
||||
import net.minecraft.client.renderer.Tessellator;
|
||||
import net.minecraft.client.renderer.texture.TextureManager;
|
||||
import net.minecraft.client.renderer.texture.TextureMap;
|
||||
import net.minecraft.client.resources.I18n;
|
||||
import net.minecraft.client.resources.model.ModelBakery;
|
||||
import net.minecraft.client.resources.model.ModelManager;
|
||||
import net.minecraft.client.settings.GameSettings;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.entity.item.EntityItem;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.init.Blocks;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.BlockPos;
|
||||
import net.minecraft.util.ChatComponentTranslation;
|
||||
import net.minecraft.util.EnumChatFormatting;
|
||||
import net.minecraft.util.EnumFacing;
|
||||
import net.minecraft.util.MathHelper;
|
||||
import net.minecraft.util.IRegistry;
|
||||
import net.minecraft.util.MovingObjectPosition;
|
||||
import net.minecraft.world.IBlockAccess;
|
||||
import net.minecraft.world.World;
|
||||
|
@ -45,6 +35,7 @@ import net.minecraftforge.client.event.DrawBlockHighlightEvent;
|
|||
import net.minecraftforge.client.event.EntityViewRenderEvent;
|
||||
import net.minecraftforge.client.event.FOVUpdateEvent;
|
||||
import net.minecraftforge.client.event.GuiScreenEvent;
|
||||
import net.minecraftforge.client.event.ModelBakeEvent;
|
||||
import net.minecraftforge.client.event.MouseEvent;
|
||||
import net.minecraftforge.client.event.RenderHandEvent;
|
||||
import net.minecraftforge.client.event.RenderWorldLastEvent;
|
||||
|
@ -54,14 +45,9 @@ import net.minecraftforge.common.ForgeModContainer;
|
|||
import net.minecraftforge.common.ForgeVersion;
|
||||
import net.minecraftforge.common.ForgeVersion.Status;
|
||||
import net.minecraftforge.common.MinecraftForge;
|
||||
import net.minecraftforge.fluids.FluidRegistry;
|
||||
import net.minecraftforge.fml.client.FMLClientHandler;
|
||||
import net.minecraftforge.fml.client.registry.RenderingRegistry;
|
||||
import net.minecraftforge.fml.common.FMLLog;
|
||||
import org.lwjgl.LWJGLException;
|
||||
import org.lwjgl.opengl.Display;
|
||||
|
||||
import org.lwjgl.opengl.GL11;
|
||||
import org.lwjgl.opengl.PixelFormat;
|
||||
//import static net.minecraftforge.client.IItemRenderer.ItemRenderType.*;
|
||||
//import static net.minecraftforge.client.IItemRenderer.ItemRendererHelper.*;
|
||||
|
||||
|
@ -470,4 +456,9 @@ public class ForgeHooksClient
|
|||
}
|
||||
}
|
||||
*/
|
||||
|
||||
public static void onModelBake(ModelManager modelManager, IRegistry modelRegistry, ModelBakery modelBakery)
|
||||
{
|
||||
MinecraftForge.EVENT_BUS.post(new ModelBakeEvent(modelManager, modelRegistry, modelBakery));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
package net.minecraftforge.client.event;
|
||||
|
||||
import net.minecraftforge.fml.common.eventhandler.Event;
|
||||
import net.minecraft.client.resources.model.ModelBakery;
|
||||
import net.minecraft.client.resources.model.ModelManager;
|
||||
import net.minecraft.util.IRegistry;
|
||||
|
||||
/**
|
||||
* Fired when the ModelManager is notified of the resource manager reloading.
|
||||
* Called after model registry is setup, but before it's passed to BlockModelShapes.
|
||||
*/
|
||||
public class ModelBakeEvent extends Event
|
||||
{
|
||||
public final ModelManager modelManager;
|
||||
public final IRegistry modelRegistry;
|
||||
public final ModelBakery modelBakery;
|
||||
|
||||
public ModelBakeEvent(ModelManager modelManager, IRegistry modelRegistry, ModelBakery modelBakery)
|
||||
{
|
||||
this.modelManager = modelManager;
|
||||
this.modelRegistry = modelRegistry;
|
||||
this.modelBakery = modelBakery;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
package net.minecraftforge.client.model;
|
||||
|
||||
import net.minecraft.block.state.IBlockState;
|
||||
import net.minecraft.client.resources.model.IBakedModel;
|
||||
|
||||
public interface ISmartBlockModel extends IBakedModel
|
||||
{
|
||||
IBakedModel handleBlockState(IBlockState state);
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
package net.minecraftforge.client.model;
|
||||
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.client.resources.model.IBakedModel;
|
||||
|
||||
public interface ISmartItemModel extends IBakedModel
|
||||
{
|
||||
IBakedModel handleItemState(ItemStack stack);
|
||||
}
|
|
@ -0,0 +1,138 @@
|
|||
package net.minecraftforge.common.property;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.properties.IProperty;
|
||||
import net.minecraft.block.state.BlockState;
|
||||
import net.minecraft.block.state.IBlockState;
|
||||
|
||||
import com.google.common.base.Optional;
|
||||
import com.google.common.base.Predicates;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.ImmutableTable;
|
||||
import com.google.common.collect.Iterables;
|
||||
|
||||
public class ExtendedBlockState extends BlockState
|
||||
{
|
||||
private final ImmutableSet<IUnlistedProperty<?>> unlistedProperties;
|
||||
|
||||
public ExtendedBlockState(Block blockIn, IProperty[] properties, IUnlistedProperty<?>[] unlistedProperties)
|
||||
{
|
||||
super(blockIn, properties, buildUnlistedMap(unlistedProperties));
|
||||
ImmutableSet.Builder<IUnlistedProperty<?>> builder = ImmutableSet.<IUnlistedProperty<?>>builder();
|
||||
for(IUnlistedProperty<?> property : unlistedProperties)
|
||||
{
|
||||
builder.add(property);
|
||||
}
|
||||
this.unlistedProperties = builder.build();
|
||||
}
|
||||
|
||||
private static ImmutableMap<IUnlistedProperty<?>, Optional<?>> buildUnlistedMap(IUnlistedProperty<?>[] unlistedProperties)
|
||||
{
|
||||
ImmutableMap.Builder<IUnlistedProperty<?>, Optional<?>> builder = ImmutableMap.<IUnlistedProperty<?>, Optional<?>>builder();
|
||||
for(IUnlistedProperty<?> p : unlistedProperties)
|
||||
{
|
||||
builder.put(p, Optional.absent());
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected StateImplementation createState(Block block, ImmutableMap properties, ImmutableMap unlistedProperties)
|
||||
{
|
||||
return new ExtendedStateImplementation(block, properties, unlistedProperties, null);
|
||||
}
|
||||
|
||||
protected static class ExtendedStateImplementation extends StateImplementation implements IExtendedBlockState
|
||||
{
|
||||
private final ImmutableMap<IUnlistedProperty<?>, Optional<?>> unlistedProperties;
|
||||
private Map<Map<IProperty, Comparable>, IBlockState> normalMap;
|
||||
|
||||
protected ExtendedStateImplementation(Block block, ImmutableMap properties, ImmutableMap<IUnlistedProperty<?>, Optional<?>> unlistedProperties, ImmutableTable<IProperty, Comparable, IBlockState> table)
|
||||
{
|
||||
super(block, properties);
|
||||
this.unlistedProperties = unlistedProperties;
|
||||
this.propertyValueTable = table;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBlockState withProperty(IProperty property, Comparable value)
|
||||
{
|
||||
if (!this.getProperties().containsKey(property))
|
||||
{
|
||||
throw new IllegalArgumentException("Cannot set property " + property + " as it does not exist in " + getBlock().getBlockState());
|
||||
}
|
||||
else if (!property.getAllowedValues().contains(value))
|
||||
{
|
||||
throw new IllegalArgumentException("Cannot set property " + property + " to " + value + " on block " + Block.blockRegistry.getNameForObject(getBlock()) + ", it is not an allowed value");
|
||||
}
|
||||
else
|
||||
{
|
||||
if(this.getProperties().get(property) == value)
|
||||
{
|
||||
return this;
|
||||
}
|
||||
if(Iterables.all(unlistedProperties.values(), Predicates.<Optional<?>>equalTo(Optional.absent())))
|
||||
{ // no dynamic properties present, looking up in the normal table
|
||||
return super.withProperty(property, value);
|
||||
}
|
||||
Map<IProperty, Comparable> map = new HashMap<IProperty, Comparable>(getProperties());
|
||||
map.put(property, value);
|
||||
ImmutableTable<IProperty, Comparable, IBlockState> table = propertyValueTable;
|
||||
table = ((StateImplementation)table.get(property, value)).getPropertyValueTable();
|
||||
return new ExtendedStateImplementation(getBlock(), ImmutableMap.copyOf(map), unlistedProperties, table);
|
||||
}
|
||||
}
|
||||
|
||||
public <V> IExtendedBlockState withProperty(IUnlistedProperty<V> property, V value)
|
||||
{
|
||||
if(!this.unlistedProperties.containsKey(property))
|
||||
{
|
||||
throw new IllegalArgumentException("Cannot set unlisted property " + property + " as it does not exist in " + getBlock().getBlockState());
|
||||
}
|
||||
if(!property.isValid(value))
|
||||
{
|
||||
throw new IllegalArgumentException("Cannot set unlisted property " + property + " to " + value + " on block " + Block.blockRegistry.getNameForObject(getBlock()) + ", it is not an allowed value");
|
||||
}
|
||||
Map<IUnlistedProperty<?>, Optional<?>> newMap = new HashMap<IUnlistedProperty<?>, Optional<?>>(unlistedProperties);
|
||||
newMap.put(property, Optional.fromNullable(value));
|
||||
if(Iterables.all(newMap.values(), Predicates.<Optional<?>>equalTo(Optional.absent())))
|
||||
{ // no dynamic properties, lookup normal state
|
||||
return (IExtendedBlockState) normalMap.get(getProperties());
|
||||
}
|
||||
return new ExtendedStateImplementation(getBlock(), getProperties(), ImmutableMap.copyOf(newMap), propertyValueTable);
|
||||
}
|
||||
|
||||
public Collection<IUnlistedProperty<?>> getUnlistedNames()
|
||||
{
|
||||
return Collections.unmodifiableCollection(unlistedProperties.keySet());
|
||||
}
|
||||
|
||||
public <V>V getValue(IUnlistedProperty<V> property)
|
||||
{
|
||||
if(!this.unlistedProperties.containsKey(property))
|
||||
{
|
||||
throw new IllegalArgumentException("Cannot get unlisted property " + property + " as it does not exist in " + getBlock().getBlockState());
|
||||
}
|
||||
return property.getType().cast(this.unlistedProperties.get(property).orNull());
|
||||
}
|
||||
|
||||
public ImmutableMap<IUnlistedProperty<?>, Optional<?>> getUnlistedProperties()
|
||||
{
|
||||
return unlistedProperties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void buildPropertyValueTable(Map map)
|
||||
{
|
||||
this.normalMap = map;
|
||||
super.buildPropertyValueTable(map);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
package net.minecraftforge.common.property;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import net.minecraft.block.state.IBlockState;
|
||||
|
||||
import com.google.common.base.Optional;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
|
||||
public interface IExtendedBlockState extends IBlockState
|
||||
{
|
||||
Collection<IUnlistedProperty<?>> getUnlistedNames();
|
||||
|
||||
<V>V getValue(IUnlistedProperty<V> property);
|
||||
|
||||
<V>IExtendedBlockState withProperty(IUnlistedProperty<V> property, V value);
|
||||
|
||||
ImmutableMap<IUnlistedProperty<?>, Optional<?>> getUnlistedProperties();
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
package net.minecraftforge.common.property;
|
||||
|
||||
public interface IUnlistedProperty<V>
|
||||
{
|
||||
String getName();
|
||||
|
||||
boolean isValid(V value);
|
||||
|
||||
Class<V> getType();
|
||||
|
||||
String valueToString(V value);
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
package net.minecraftforge.common.property;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
|
||||
import net.minecraft.block.properties.IProperty;
|
||||
|
||||
import org.apache.commons.lang3.reflect.ConstructorUtils;
|
||||
|
||||
public class Properties
|
||||
{
|
||||
public static <P extends IProperty, V>IUnlistedProperty<V> toUnlisted(P property)
|
||||
{
|
||||
return new PropertyAdapter(property);
|
||||
}
|
||||
|
||||
public static class PropertyAdapter<V extends Comparable> implements IUnlistedProperty<V>
|
||||
{
|
||||
private final IProperty parent;
|
||||
|
||||
public PropertyAdapter(IProperty parent)
|
||||
{
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
public String getName()
|
||||
{
|
||||
return parent.getName();
|
||||
}
|
||||
|
||||
public boolean isValid(V value)
|
||||
{
|
||||
return parent.getAllowedValues().contains(value);
|
||||
}
|
||||
|
||||
public Class<V> getType()
|
||||
{
|
||||
return parent.getValueClass();
|
||||
}
|
||||
|
||||
public String valueToString(V value)
|
||||
{
|
||||
return parent.getName(value);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -27,3 +27,4 @@ net/minecraft/block/BlockSkull.getDrops(Lnet/minecraft/world/IBlockAccess;Lnet/m
|
|||
net/minecraft/item/ItemDye.applyBonemeal(Lnet/minecraft/item/ItemStack;Lnet/minecraft/world/World;Lnet/minecraft/util/BlockPos;Lnet/minecraft/entity/player/EntityPlayer;)Z=|p_179234_0_,p_179234_1_,p_179234_2_,player
|
||||
net/minecraft/server/management/ItemInWorldManager.removeBlock(Lnet/minecraft/util/BlockPos;Z)Z=|p_180235_1_,canHarvest
|
||||
net/minecraft/client/gui/GuiScreen.drawHoveringText(Ljava/util/List;IILnet/minecraft/client/gui/FontRenderer;)V=|p_146283_1_,p_146283_2_,p_146283_3_,font
|
||||
net/minecraft/block/state/BlockState.<init>(Lnet/minecraft/block/Block;[Lnet/minecraft/block/properties/IProperty;Lcom/google/common/collect/ImmutableMap;)V=|p_i45663_1_,p_i45663_2_,unlistedProperties
|
||||
|
|
|
@ -120,3 +120,6 @@ public net.minecraft.world.gen.ChunkProviderServer field_73251_h # worldObj
|
|||
protected net.minecraft.client.renderer.entity.RenderEntityItem func_177078_a(Lnet/minecraft/item/ItemStack;)I # getMiniItemCount
|
||||
public net.minecraft.item.crafting.RecipesBanners$RecipeAddPattern
|
||||
public net.minecraft.item.crafting.RecipesBanners$RecipeDuplicatePattern
|
||||
protected net.minecraft.block.state.BlockState$StateImplementation
|
||||
protected net.minecraft.block.state.BlockState$StateImplementation <init>(Lnet/minecraft/block/Block;Lcom/google/common/collect/ImmutableMap;)V
|
||||
protected net.minecraft.block.state.BlockState$StateImplementation field_177238_c # propertyValueTable
|
||||
|
|
354
src/test/java/net/minecraftforge/debug/ModelBakeEventDebug.java
Normal file
354
src/test/java/net/minecraftforge/debug/ModelBakeEventDebug.java
Normal file
|
@ -0,0 +1,354 @@
|
|||
package net.minecraftforge.debug;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import net.minecraft.block.BlockContainer;
|
||||
import net.minecraft.block.material.Material;
|
||||
import net.minecraft.block.properties.IProperty;
|
||||
import net.minecraft.block.properties.PropertyInteger;
|
||||
import net.minecraft.block.state.BlockState;
|
||||
import net.minecraft.block.state.IBlockState;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.ItemMeshDefinition;
|
||||
import net.minecraft.client.renderer.block.model.BakedQuad;
|
||||
import net.minecraft.client.renderer.block.model.ItemCameraTransforms;
|
||||
import net.minecraft.client.renderer.entity.RenderItem;
|
||||
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
||||
import net.minecraft.client.resources.model.IBakedModel;
|
||||
import net.minecraft.client.resources.model.ModelResourceLocation;
|
||||
import net.minecraft.creativetab.CreativeTabs;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.util.BlockPos;
|
||||
import net.minecraft.util.EnumFacing;
|
||||
import net.minecraft.util.Vec3;
|
||||
import net.minecraft.world.IBlockAccess;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.client.event.ModelBakeEvent;
|
||||
import net.minecraftforge.client.model.ISmartBlockModel;
|
||||
import net.minecraftforge.client.model.ISmartItemModel;
|
||||
import net.minecraftforge.common.MinecraftForge;
|
||||
import net.minecraftforge.common.property.ExtendedBlockState;
|
||||
import net.minecraftforge.common.property.IExtendedBlockState;
|
||||
import net.minecraftforge.common.property.IUnlistedProperty;
|
||||
import net.minecraftforge.common.property.Properties;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
import net.minecraftforge.fml.common.Mod.EventHandler;
|
||||
import net.minecraftforge.fml.common.SidedProxy;
|
||||
import net.minecraftforge.fml.common.event.FMLInitializationEvent;
|
||||
import net.minecraftforge.fml.common.event.FMLPostInitializationEvent;
|
||||
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
|
||||
import net.minecraftforge.fml.common.registry.GameRegistry;
|
||||
|
||||
import com.google.common.primitives.Ints;
|
||||
|
||||
@Mod(modid = ModelBakeEventDebug.MODID, version = ModelBakeEventDebug.VERSION)
|
||||
public class ModelBakeEventDebug
|
||||
{
|
||||
public static final String MODID = "ForgeDebugModelBakeEvent";
|
||||
public static final String VERSION = "1.0";
|
||||
public static final int cubeSize = 3;
|
||||
|
||||
private static String blockName = MODID.toLowerCase() + ":" + CustomModelBlock.name;
|
||||
|
||||
public static final IUnlistedProperty<Integer>[] properties = new IUnlistedProperty[6];
|
||||
|
||||
static
|
||||
{
|
||||
for(EnumFacing f : EnumFacing.values())
|
||||
{
|
||||
properties[f.ordinal()] = Properties.toUnlisted(PropertyInteger.create(f.getName(), 0, (1 << (cubeSize * cubeSize)) - 1));
|
||||
}
|
||||
}
|
||||
|
||||
@SidedProxy(serverSide = "net.minecraftforge.debug.ModelBakeEventDebug$CommonProxy", clientSide = "net.minecraftforge.debug.ModelBakeEventDebug$ClientProxy")
|
||||
public static CommonProxy proxy;
|
||||
|
||||
@EventHandler
|
||||
public void init(FMLInitializationEvent event) { proxy.init(event); }
|
||||
|
||||
@EventHandler
|
||||
public void postInit(FMLPostInitializationEvent event) { proxy.postInit(event); }
|
||||
|
||||
public static class CommonProxy
|
||||
{
|
||||
public void init(FMLInitializationEvent event)
|
||||
{
|
||||
GameRegistry.registerBlock(CustomModelBlock.instance, CustomModelBlock.name);
|
||||
GameRegistry.registerTileEntity(CustomTileEntity.class, MODID.toLowerCase() + ":custom_tile_entity");
|
||||
}
|
||||
|
||||
public void postInit(FMLPostInitializationEvent event) {}
|
||||
}
|
||||
|
||||
public static class ClientProxy extends CommonProxy
|
||||
{
|
||||
private static ModelResourceLocation modelLocation = new ModelResourceLocation(blockName, null);
|
||||
|
||||
@Override
|
||||
public void init(FMLInitializationEvent event)
|
||||
{
|
||||
super.init(event);
|
||||
MinecraftForge.EVENT_BUS.register(BakeEventHandler.instance);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postInit(FMLPostInitializationEvent event) {
|
||||
super.postInit(event);
|
||||
Item item = Item.getItemFromBlock(CustomModelBlock.instance);
|
||||
RenderItem renderItem = Minecraft.getMinecraft().getRenderItem();
|
||||
if(renderItem != null)
|
||||
{
|
||||
renderItem.getItemModelMesher().register(item, new ItemMeshDefinition() {
|
||||
public ModelResourceLocation getModelLocation(ItemStack stack)
|
||||
{
|
||||
return modelLocation;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class BakeEventHandler
|
||||
{
|
||||
public static final BakeEventHandler instance = new BakeEventHandler();
|
||||
|
||||
private BakeEventHandler() {};
|
||||
|
||||
@SubscribeEvent
|
||||
public void onModelBakeEvent(ModelBakeEvent event)
|
||||
{
|
||||
TextureAtlasSprite base = Minecraft.getMinecraft().getTextureMapBlocks().getAtlasSprite("minecraft:blocks/slime");
|
||||
TextureAtlasSprite overlay = Minecraft.getMinecraft().getTextureMapBlocks().getAtlasSprite("minecraft:blocks/redstone_block");
|
||||
event.modelRegistry.putObject(ClientProxy.modelLocation, new CustomModel(base, overlay));
|
||||
}
|
||||
}
|
||||
|
||||
public static class CustomModelBlock extends BlockContainer
|
||||
{
|
||||
public static final CustomModelBlock instance = new CustomModelBlock();
|
||||
public static final String name = "custom_model_block";
|
||||
|
||||
private CustomModelBlock()
|
||||
{
|
||||
super(Material.iron);
|
||||
setCreativeTab(CreativeTabs.tabBlock);
|
||||
setUnlocalizedName(MODID + ":" + name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRenderType() { return 3; }
|
||||
|
||||
@Override
|
||||
public boolean isOpaqueCube() { return false; }
|
||||
|
||||
@Override
|
||||
public boolean isFullCube() { return false; }
|
||||
|
||||
@Override
|
||||
public boolean isVisuallyOpaque() { return false; }
|
||||
|
||||
@Override
|
||||
public TileEntity createNewTileEntity(World world, int meta)
|
||||
{
|
||||
return new CustomTileEntity();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onBlockActivated(World world, BlockPos pos, IBlockState state, EntityPlayer player, EnumFacing side, float hitX, float hitY, float hitZ)
|
||||
{
|
||||
TileEntity te = world.getTileEntity(pos);
|
||||
if(te instanceof CustomTileEntity)
|
||||
{
|
||||
CustomTileEntity cte = (CustomTileEntity) te;
|
||||
Vec3 vec = revRotate(new Vec3(hitX - .5, hitY - .5, hitZ - .5), side).addVector(.5, .5, .5);
|
||||
IUnlistedProperty property = properties[side.ordinal()];
|
||||
Integer value = (Integer)cte.getState().getValue(property);
|
||||
if(value == null) value = 0;
|
||||
value ^= (1 << ( cubeSize * ((int)(vec.xCoord * (cubeSize - .0001))) + ((int)(vec.zCoord * (cubeSize - .0001))) ));
|
||||
cte.setState(cte.getState().withProperty(property, value));
|
||||
world.markBlockRangeForRenderUpdate(pos, pos);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBlockState getExtendedState(IBlockState state, IBlockAccess world, BlockPos pos)
|
||||
{
|
||||
TileEntity te = world.getTileEntity(pos);
|
||||
if(te instanceof CustomTileEntity)
|
||||
{
|
||||
CustomTileEntity cte = (CustomTileEntity) te;
|
||||
return cte.getState();
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected BlockState createBlockState()
|
||||
{
|
||||
return new ExtendedBlockState(this, new IProperty[0], properties);
|
||||
}
|
||||
}
|
||||
|
||||
public static class CustomTileEntity extends TileEntity
|
||||
{
|
||||
private IExtendedBlockState state;
|
||||
public CustomTileEntity() {}
|
||||
|
||||
public IExtendedBlockState getState()
|
||||
{
|
||||
if(state == null)
|
||||
{
|
||||
state = (IExtendedBlockState)getBlockType().getDefaultState();
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
public void setState(IExtendedBlockState state)
|
||||
{
|
||||
this.state = state;
|
||||
}
|
||||
}
|
||||
|
||||
public static class CustomModel implements IBakedModel, ISmartBlockModel, ISmartItemModel
|
||||
{
|
||||
private final TextureAtlasSprite base, overlay;
|
||||
private boolean hasStateSet = false;
|
||||
private final IExtendedBlockState state;
|
||||
|
||||
public CustomModel(TextureAtlasSprite base, TextureAtlasSprite overlay)
|
||||
{
|
||||
this(base, overlay, null);
|
||||
}
|
||||
|
||||
public CustomModel(TextureAtlasSprite base, TextureAtlasSprite overlay, IExtendedBlockState state)
|
||||
{
|
||||
this.base = base;
|
||||
this.overlay = overlay;
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<BakedQuad> getFaceQuads(EnumFacing side)
|
||||
{
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
private int[] vertexToInts(float x, float y, float z, int color, TextureAtlasSprite texture, float u, float v)
|
||||
{
|
||||
return new int[] {
|
||||
Float.floatToRawIntBits(x),
|
||||
Float.floatToRawIntBits(y),
|
||||
Float.floatToRawIntBits(z),
|
||||
color,
|
||||
Float.floatToRawIntBits(texture.getInterpolatedU(u)),
|
||||
Float.floatToRawIntBits(texture.getInterpolatedV(v)),
|
||||
0
|
||||
};
|
||||
}
|
||||
|
||||
private BakedQuad createSidedBakedQuad(float x1, float x2, float z1, float z2, float y, TextureAtlasSprite texture, EnumFacing side)
|
||||
{
|
||||
Vec3 v1 = rotate(new Vec3(x1 - .5, y - .5, z1 - .5), side).addVector(.5, .5, .5);
|
||||
Vec3 v2 = rotate(new Vec3(x1 - .5, y - .5, z2 - .5), side).addVector(.5, .5, .5);
|
||||
Vec3 v3 = rotate(new Vec3(x2 - .5, y - .5, z2 - .5), side).addVector(.5, .5, .5);
|
||||
Vec3 v4 = rotate(new Vec3(x2 - .5, y - .5, z1 - .5), side).addVector(.5, .5, .5);
|
||||
return new BakedQuad(Ints.concat(
|
||||
vertexToInts((float)v1.xCoord, (float)v1.yCoord, (float)v1.zCoord, -1, texture, 0, 0),
|
||||
vertexToInts((float)v2.xCoord, (float)v2.yCoord, (float)v2.zCoord, -1, texture, 0, 16),
|
||||
vertexToInts((float)v3.xCoord, (float)v3.yCoord, (float)v3.zCoord, -1, texture, 16, 16),
|
||||
vertexToInts((float)v4.xCoord, (float)v4.yCoord, (float)v4.zCoord, -1, texture, 16, 0)
|
||||
), -1, side);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<BakedQuad> getGeneralQuads()
|
||||
{
|
||||
int len = cubeSize * 5 + 1;
|
||||
List<BakedQuad> ret = new ArrayList<BakedQuad>();
|
||||
for(EnumFacing f : EnumFacing.values())
|
||||
{
|
||||
ret.add(createSidedBakedQuad(0, 1, 0, 1, 1, base, f));
|
||||
for(int i = 0; i < cubeSize; i++)
|
||||
{
|
||||
for(int j = 0; j < cubeSize; j++)
|
||||
{
|
||||
if(state != null)
|
||||
{
|
||||
Integer value = (Integer)state.getValue(properties[f.ordinal()]);
|
||||
if(value != null && (value & (1 << (i * cubeSize + j))) != 0)
|
||||
{
|
||||
ret.add(createSidedBakedQuad((float)(1 + i * 5) / len, (float)(5 + i * 5) / len, (float)(1 + j * 5) / len, (float)(5 + j * 5) / len, 1.0001f, overlay, f));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isGui3d() { return true; }
|
||||
|
||||
@Override
|
||||
public boolean isAmbientOcclusion() { return true; }
|
||||
|
||||
@Override
|
||||
public boolean isBuiltInRenderer() { return false; }
|
||||
|
||||
@Override
|
||||
public TextureAtlasSprite getTexture() { return this.base; }
|
||||
|
||||
@Override
|
||||
public ItemCameraTransforms getItemCameraTransforms()
|
||||
{
|
||||
return ItemCameraTransforms.DEFAULT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBakedModel handleBlockState(IBlockState state)
|
||||
{
|
||||
return new CustomModel(base, overlay, (IExtendedBlockState)state);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBakedModel handleItemState(ItemStack stack)
|
||||
{
|
||||
IExtendedBlockState itemState = ((IExtendedBlockState)CustomModelBlock.instance.getDefaultState()).withProperty(properties[1], (1 << (cubeSize * cubeSize)) - 1);
|
||||
return new CustomModel(base, overlay, itemState);
|
||||
}
|
||||
}
|
||||
|
||||
private static Vec3 rotate(Vec3 vec, EnumFacing side)
|
||||
{
|
||||
switch(side)
|
||||
{
|
||||
case DOWN: return new Vec3( vec.xCoord, -vec.yCoord, -vec.zCoord);
|
||||
case UP: return new Vec3( vec.xCoord, vec.yCoord, vec.zCoord);
|
||||
case NORTH: return new Vec3( vec.xCoord, vec.zCoord, -vec.yCoord);
|
||||
case SOUTH: return new Vec3( vec.xCoord, -vec.zCoord, vec.yCoord);
|
||||
case WEST: return new Vec3(-vec.yCoord, vec.xCoord, vec.zCoord);
|
||||
case EAST: return new Vec3( vec.yCoord, -vec.xCoord, vec.zCoord);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static Vec3 revRotate(Vec3 vec, EnumFacing side)
|
||||
{
|
||||
switch(side)
|
||||
{
|
||||
case DOWN: return new Vec3( vec.xCoord, -vec.yCoord, -vec.zCoord);
|
||||
case UP: return new Vec3( vec.xCoord, vec.yCoord, vec.zCoord);
|
||||
case NORTH: return new Vec3( vec.xCoord, -vec.zCoord, vec.yCoord);
|
||||
case SOUTH: return new Vec3( vec.xCoord, vec.zCoord, -vec.yCoord);
|
||||
case WEST: return new Vec3( vec.yCoord, -vec.xCoord, vec.zCoord);
|
||||
case EAST: return new Vec3(-vec.yCoord, vec.xCoord, vec.zCoord);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"variants": {
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"parent": "builtin/entity"
|
||||
}
|
Loading…
Reference in a new issue