![](https://forums.minecraftforge.net/uploads/set_resources_2/84c1e40ea0e759e3f1505eb1788ddf3c_pattern.png)
SnowyEgret
-
Posts
112 -
Joined
-
Last visited
Posts posted by SnowyEgret
-
-
The block in place should look the same as when in inventory, tossed, and in hand.
Here are #handleBlockState and #handleItemState:
@Override public IBakedModel handleBlockState(IBlockState state) { String name = ((IExtendedBlockState) state).getValue(BlockMaquette.PROP_NAME); Iterable<Selection> selections = ((IExtendedBlockState) state).getValue(BlockMaquette.PROP_SELECTIONS); EnumFacing facing = (EnumFacing) state.getValue(BlockMaquette.PROP_FACING); generateQuads(name, selections, facing); return this; } @Override public IBakedModel handleItemState(ItemStack stack) { // Instanciating te just to read from tag BlockMaquetteTileEntity te = new BlockMaquetteTileEntity(); te.readFromNBT(stack.getTagCompound()); String name = te.getName(); Iterable<Selection> selections = te.getSelections(); EnumFacing facing = te.getFacing(); generateQuads(name, selections, facing); return this; }
This is all working fine. Each method generates the same quads.
When I debug with a breakpoint in ItemModelMesher#getItemModel, stack.getItem() is still not returning an ISmartItemModel and this if statement evaluates false:
if(ibakedmodel instanceof net.minecraftforge.client.model.ISmartItemModel) { ibakedmodel = ((net.minecraftforge.client.model.ISmartItemModel)ibakedmodel).handleItemState(stack); }
Now that my smart model implements both ISmartModel and ISmartItemModel, what should my ModelBakeEvent handler look like? Which ModelResourceLocation should be registered? or should both be registered?
public void onModelBake(ModelBakeEvent event) { event.modelRegistry.putObject(new ModelResourceLocation("mojo:block_maquette"), new BlockMaquetteSmartModel()); event.modelRegistry.putObject(new ModelResourceLocation("mojo:block_maquette", "inventory"), new BlockMaquetteSmartModel());
-
Ok, I understand.
My smart model must implement both ISmartModel and ISmartItemModel. ISmartItemModel adds one method #handleItemState.
Giving it a try...
-
What should the ModelResourceLocator look like?
I have already registered an ISmartModel for my block with mrl=mojo:block_maquette.
When I register the ISmartItemModel should the mrl be mojo:block_maquette#inventory?
Also, and this is a question for TGG, MB04 seems to suggest that an ISmartItemModel is not necessary and all we have to do is the extra work during the init stage on the client side. Have I misunderstood?
public static void initClientOnly() { // This is currently necessary in order to make your block render properly when it is an item (i.e. in the inventory // or in your hand or thrown on the ground). // Minecraft knows to look for the item model based on the GameRegistry.registerBlock. However the registration of // the model for each item is normally done by RenderItem.registerItems(), and this is not currently aware // of any extra items you have created. Hence you have to do it manually. This will probably change in future. // It must be done in the init phase, not preinit, and must be done on client only. Item itemBlockCamouflage = GameRegistry.findItem("minecraftbyexample", "mbe04_block_camouflage"); ModelResourceLocation itemModelResourceLocation = new ModelResourceLocation("minecraftbyexample:mbe04_block_camouflage", "inventory"); final int DEFAULT_ITEM_SUBTYPE = 0; Minecraft.getMinecraft().getRenderItem().getItemModelMesher().register(itemBlockCamouflage, DEFAULT_ITEM_SUBTYPE, itemModelResourceLocation); }
-
A line from the player's eyes to the cursor will pass through many air blocks. If you could somehow get a list of all of them, then you could choose the air block at the depth you want.
A non-air hit will be the first non air block encountered along the line from the player's eyes to the maximum hit depth.
-
Thanks Sir Ghost for getting back to me
I've got a breakpoint in ItemModelMesher.getItemModel(). For reference here is the method:
public IBakedModel getItemModel(ItemStack stack) { Item item = stack.getItem(); IBakedModel ibakedmodel = this.getItemModel(item, this.getMetadata(stack)); if (ibakedmodel == null) { ItemMeshDefinition itemmeshdefinition = (ItemMeshDefinition)this.shapers.get(item); if (itemmeshdefinition != null) { ibakedmodel = this.modelManager.getModel(itemmeshdefinition.getModelLocation(stack)); } } if(ibakedmodel instanceof net.minecraftforge.client.model.ISmartItemModel) { ibakedmodel = ((net.minecraftforge.client.model.ISmartItemModel)ibakedmodel).handleItemState(stack); } if (ibakedmodel == null) { ibakedmodel = this.modelManager.getMissingModel(); } return ibakedmodel; }
item is an ItemBlock as expected, but ibakedmodel is an IFlexibleBakedModel. Seems I want it to be and ISmartItemModel.
In MB04 there is no mention of an ISmartItemModel, only the block's ISmartModel. What do I need to do so that this.getItemModel(item, this.getMetadata(stack)) returns an ISmartItemModel? Do I need an implementation of ISmartItemModel? If so, how do I register it in my ModelBakeEvent handler?
Here is my ModelBakeEvent handler:
public void onModelBake(ModelBakeEvent event) { IRegistry r = event.modelRegistry; r.putObject(ModelResourceLocations.forClass(BlockHighlight.class), new BlockHighlightSmartModel()); // From MBE04 ModelBakeEventHandler: // IBakedModel existingModel = (IBakedModel)object; // CamouflageISmartBlockModelFactory customModel = new CamouflageISmartBlockModelFactory(existingModel); // event.modelRegistry.putObject(CamouflageISmartBlockModelFactory.modelResourceLocation, customModel); // From MBEO4 CamouflageISmartBlockModelFactory: // public static final ModelResourceLocation modelResourceLocation = new ModelResourceLocation( // "minecraftbyexample:mbe04_block_camouflage"); r.putObject(new ModelResourceLocation("mojo:block_maquette"), new BlockMaquetteSmartModel()); [/spoiler]
-
Has anyone got advice? From someone who's been there, done that - things that I absolutely must do, things that I must never, never do?
Distribution, versioning, bug tracking, logo, github, videos, Minecraft Forum, Adfly, CurseForge, beta testing, personal website, etc.
(Hoping this is this the right place for a question like this)
-
Can someone suggest where I can put a breakpoint to debug my problem?
TGG, in MBE04, you suggest overriding #getActualState
@Override public IBlockState getActualState(IBlockState state, IBlockAccess worldIn, BlockPos pos) { return state; //for debugging - useful spot for a breakpoint. Not necessary. }
but this doesn't help me. It is not being called when the item model is being rendered.
-
Raflex, onBlockPlacedBy is called after the block has been placed which is why DirtyDan can get his tile entity at pos. If you look at super#onBlockPlacedBy, it is an empty method.
Is there another method which can be overridden to change how the block is set?
-
I have a block with an ISmartModel that renders fine when placed. When in inventory, tossed, or in hand, it is being rendered as a block with a texture (with its .png in the textures folder). It is my understanding that if I want my smart model to render as an item, I have to do this (#initClientOnly):
Here is my implementation:
public void registerItemBlockModels() { System.out.println("Registering ItemBlock models..."); ItemModelMesher mesher = Minecraft.getMinecraft().getRenderItem().getItemModelMesher(); String name = StringUtils.underscoreNameFor(BlockMaquette.class); Item item = GameRegistry.findItem(MoJo.MODID, name); ModelResourceLocation mrl = new ModelResourceLocation(MoJo.MODID + ":" + name, "inventory"); mesher.register(item, 0, mrl); System.out.println("item=" + item); System.out.println("mrl=" + mrl); System.out.println("model=" + mesher.getModelManager().getModel(mrl)); }
And here is the console:
[17:46:13] [Client thread/INFO] [sTDOUT]: [org.snowyegret.mojo.MoJo:init:46]: Intializing------------------------------------------------------------------------------------------------------------ [17:46:13] [Client thread/INFO] [sTDOUT]: [org.snowyegret.mojo.CommonProxy:registerGuiHandler:206]: Registering gui handler... [17:46:13] [Client thread/INFO] [sTDOUT]: [org.snowyegret.mojo.CommonProxy:registerEventHandlers:132]: Registering event handlers... [17:46:13] [Client thread/INFO] [sTDOUT]: [org.snowyegret.mojo.CommonProxy:registerTileEntities:140]: Registering tile entities... [17:46:13] [Client thread/INFO] [sTDOUT]: [org.snowyegret.mojo.ClientProxy:registerItemModels:30]: Registering Item models... [17:46:13] [Client thread/INFO] [sTDOUT]: [org.snowyegret.mojo.ClientProxy:registerItemBlockModels:49]: Registering ItemBlock models... [17:46:13] [Client thread/INFO] [sTDOUT]: [org.snowyegret.mojo.ClientProxy:registerItemBlockModels:56]: item=net.minecraft.item.ItemBlock@158f0af4 [17:46:13] [Client thread/INFO] [sTDOUT]: [org.snowyegret.mojo.ClientProxy:registerItemBlockModels:57]: mrl=mojo:block_maquette#inventory [17:46:13] [Client thread/INFO] [sTDOUT]: [org.snowyegret.mojo.ClientProxy:registerItemBlockModels:58]: model=net.minecraftforge.client.model.IFlexibleBakedModel$Wrapper@3edea9e6
As you can see, the model is being registered in init and on the client side as instructed. I am assuming the json is set up properly because it is rendering with a texture in inventory, tossed, and in hand. The ISmartModel is rendering fine when placed.
Is there something I have missed?
Where can I insert printlns or breakpoints to debug this?
-
Finally
Got it working like this:
private BakedQuad scaleAndTranslateQuad(BakedQuad q, Vec3i t, float s) { int[] v = q.getVertexData().clone(); // leftRigh, upDown, frontBack int lr, ud, fb; // A quad has four verticies // indices of x values of vertices are 0, 7, 14, 21 // indices of y values of vertices are 1, 8, 15, 22 // indices of z values of vertices are 2, 9, 16, 23 // east: x // south: z // up: y switch (q.getFace()) { case UP: // Quad up is towards north lr = t.getX(); ud = t.getZ(); fb = t.getY(); v[0] = transform(v[0], lr, s); v[7] = transform(v[7], lr, s); v[14] = transform(v[14], lr, s); v[21] = transform(v[21], lr, s); v[1] = transform(v[1], fb, s); v[8] = transform(v[8], fb, s); v[15] = transform(v[15], fb, s); v[22] = transform(v[22], fb, s); v[2] = transform(v[2], ud, s); v[9] = transform(v[9], ud, s); v[16] = transform(v[16], ud, s); v[23] = transform(v[23], ud, s); break; case DOWN: // Quad up is towards south lr = t.getX(); ud = t.getZ(); fb = t.getY(); v[0] = transform(v[0], lr, s); v[7] = transform(v[7], lr, s); v[14] = transform(v[14], lr, s); v[21] = transform(v[21], lr, s); v[1] = transform(v[1], fb, s); v[8] = transform(v[8], fb, s); v[15] = transform(v[15], fb, s); v[22] = transform(v[22], fb, s); v[2] = transform(v[2], -ud, s); v[9] = transform(v[9], -ud, s); v[16] = transform(v[16], -ud, s); v[23] = transform(v[23], -ud, s); break; case WEST: lr = t.getZ(); ud = t.getY(); fb = t.getX(); v[0] = transform(v[0], fb, s); v[7] = transform(v[7], fb, s); v[14] = transform(v[14], fb, s); v[21] = transform(v[21], fb, s); v[1] = transform(v[1], ud, s); v[8] = transform(v[8], ud, s); v[15] = transform(v[15], ud, s); v[22] = transform(v[22], ud, s); v[2] = transform(v[2], lr, s); v[9] = transform(v[9], lr, s); v[16] = transform(v[16], lr, s); v[23] = transform(v[23], lr, s); break; case EAST: lr = t.getZ(); ud = t.getY(); fb = t.getX(); v[0] = transform(v[0], fb, s); v[7] = transform(v[7], fb, s); v[14] = transform(v[14], fb, s); v[21] = transform(v[21], fb, s); v[1] = transform(v[1], ud, s); v[8] = transform(v[8], ud, s); v[15] = transform(v[15], ud, s); v[22] = transform(v[22], ud, s); v[2] = transform(v[2], lr, s); v[9] = transform(v[9], lr, s); v[16] = transform(v[16], lr, s); v[23] = transform(v[23], lr, s); break; case NORTH: lr = t.getX(); ud = t.getY(); fb = t.getZ(); v[0] = transform(v[0], lr, s); v[7] = transform(v[7], lr, s); v[14] = transform(v[14], lr, s); v[21] = transform(v[21], lr, s); v[1] = transform(v[1], ud, s); v[8] = transform(v[8], ud, s); v[15] = transform(v[15], ud, s); v[22] = transform(v[22], ud, s); v[2] = transform(v[2], fb, s); v[9] = transform(v[9], fb, s); v[16] = transform(v[16], fb, s); v[23] = transform(v[23], fb, s); break; case SOUTH: // Case where quad is aligned with world coordinates lr = t.getX(); ud = t.getY(); fb = t.getZ(); v[0] = transform(v[0], lr, s); v[7] = transform(v[7], lr, s); v[14] = transform(v[14], lr, s); v[21] = transform(v[21], lr, s); v[1] = transform(v[1], ud, s); v[8] = transform(v[8], ud, s); v[15] = transform(v[15], ud, s); v[22] = transform(v[22], ud, s); v[2] = transform(v[2], fb, s); v[9] = transform(v[9], fb, s); v[16] = transform(v[16], fb, s); v[23] = transform(v[23], fb, s); break; default: System.out.println("Unexpected face=" + q.getFace()); break; } return new BakedQuad(v, q.getTintIndex(), q.getFace()); } private int transform(int i, int t, float s) { float f = Float.intBitsToFloat(i); f = (f + t) * s; return Float.floatToRawIntBits(f); }
Please contribute any suggestions to abbreviate the code
-
Here is what I have based on http://greyminecraftcoder.blogspot.com.au/2014/12/block-models-texturing-quads-faces.html.
I've screwed something up somewhere. It's close but not quite right. translation is t and scale is s. Any advice?
private BakedQuad scaleAndTranslateQuad(BakedQuad q, Vec3i t, float s) { int[] v = q.getVertexData().clone(); int x = t.getX(); int y = t.getY(); int z = t.getZ(); switch (q.getFace()) { case UP: v[0] = transform(v[0], x, s); v[7] = transform(v[7], x, s); v[14] = transform(v[14], x, s); v[21] = transform(v[21], x, s); v[1] = transform(v[1], -z, s); v[8] = transform(v[8], -z, s); v[15] = transform(v[15], -z, s); v[22] = transform(v[22], -z, s); v[2] = transform(v[2], y, s); v[9] = transform(v[9], y, s); v[16] = transform(v[16], y, s); v[23] = transform(v[23], y, s); break; case DOWN: v[0] = transform(v[0], x, s); v[7] = transform(v[7], x, s); v[14] = transform(v[14], x, s); v[21] = transform(v[21], x, s); v[1] = transform(v[1], z, s); v[8] = transform(v[8], z, s); v[15] = transform(v[15], z, s); v[22] = transform(v[22], z, s); v[2] = transform(v[2], -y, s); v[9] = transform(v[9], -y, s); v[16] = transform(v[16], -y, s); v[23] = transform(v[23], -y, s); break; case EAST: v[0] = transform(v[0], z, s); v[7] = transform(v[7], z, s); v[14] = transform(v[14], z, s); v[21] = transform(v[21], z, s); v[1] = transform(v[1], y, s); v[8] = transform(v[8], y, s); v[15] = transform(v[15], y, s); v[22] = transform(v[22], y, s); v[2] = transform(v[2], x, s); v[9] = transform(v[9], x, s); v[16] = transform(v[16], x, s); v[23] = transform(v[23], x, s); break; case WEST: v[0] = transform(v[0], z, s); v[7] = transform(v[7], z, s); v[14] = transform(v[14], z, s); v[21] = transform(v[21], z, s); v[1] = transform(v[1], y, s); v[8] = transform(v[8], y, s); v[15] = transform(v[15], y, s); v[22] = transform(v[22], y, s); v[2] = transform(v[2], -x, s); v[9] = transform(v[9], -x, s); v[16] = transform(v[16], -x, s); v[23] = transform(v[23], -x, s); break; case NORTH: v[0] = transform(v[0], -x, s); v[7] = transform(v[7], -x, s); v[14] = transform(v[14], -x, s); v[21] = transform(v[21], -x, s); v[1] = transform(v[1], y, s); v[8] = transform(v[8], y, s); v[15] = transform(v[15], y, s); v[22] = transform(v[22], y, s); v[2] = transform(v[2], -z, s); v[9] = transform(v[9], -z, s); v[16] = transform(v[16], -z, s); v[23] = transform(v[23], -z, s); break; case SOUTH: // Case where quad coordinates are aligned with world coordinates v[0] = transform(v[0], x, s); v[7] = transform(v[7], x, s); v[14] = transform(v[14], x, s); v[21] = transform(v[21], x, s); v[1] = transform(v[1], y, s); v[8] = transform(v[8], y, s); v[15] = transform(v[15], y, s); v[22] = transform(v[22], y, s); v[2] = transform(v[2], z, s); v[9] = transform(v[9], z, s); v[16] = transform(v[16], z, s); v[23] = transform(v[23], z, s); break; default: break; } return new BakedQuad(v, q.getTintIndex(), q.getFace()); } private int transform(int i, int t, float s) { float f = Float.intBitsToFloat(i); f = (f + t) * s; return Float.floatToRawIntBits(f); }
Edit:
A model generated from two stone bricks slabs:
-
I am trying to create a model from another model at runtime. I need to translate and scale BakedQuads. Is there a method somewhere that does this, or do I have to manipulate the vertex data directly?
-
Thanks!
@Override public boolean removedByPlayer(World world, BlockPos pos, EntityPlayer player, boolean willHarvest) { if (willHarvest) { // Delay deletion of the block until after getDrops return true; } if (player.capabilities.isCreativeMode) { harvestBlock(world, player, pos, this.getDefaultState(), null); } return super.removedByPlayer(world, pos, player, willHarvest); }
-
1
-
-
My mod is on GitHub, repository is mo-jo. The Block is named BlockSaved. Please have a look if you are interested.
But this is really a generic problem. How do you make a block, any block, drop in creative?
-
Thanks for the reply
Not sure what you mean by " item id of the item you broke".
I am breaking a Block. My understanding is that once it is in the player's inventory it is an ItemBlock.
Method onBlockBreak is on which class?
-
I have a block which replaces a selection of blocks and stores the path to a file with the saved selections on its tile entity. In survival, the player picks up the block after breaking and puts it in his inventory to place it at some other time and place and restore the original blocks from file. I would like the same behavior in creative
-
How can I make my block provide drops when broken in creative mode?
-
Opposite corners are enough to define a quad which is axis-aligned.
BakedQuad's constructor is public. An example of constructing BakedQuads is here:
Not sure why TGG doesn't use FaceBakery. Maybe because #makeBakedQuad wants a BlockPartRotation and BlockPartFace, which in turn wants a BlockFaceUV ...
-
I have a block with a ISmartModel which renders fine when placed. When I break the block, the drop does not render, nor does it render when in the player's inventory. Is there a way I can render with the same ISmartModel in these cases?
-
I am building a BakedQuad and need a texture.
-
Is there some convenient way to get a TextureAtlasSprite from an IBlockState?
state.toString()=minecraft:diamond_block needs to be minecraft:blocks/diamond_block
TextureAtlasSprite#getAtlasSprite(String) seems to be the only way to get a sprite
-
Solves my problem. Thanks!
-
I have tried returning true, false, and super.removedByPlayer when world.isRemote, all with no effect (still two drops).
-
Hi. I posted a couple of days ago about delaying the deletion of a block and its tile entity until after the drops were picked up by the player. Diesieben pointed me in the right direction (thanks).
The solution has created a small problem for me: I am getting two drops when I break the block. When I comment out removedByPlayer, I get only one. Printlns indicate removedByPlayer is being called once on the server side with willHarvest = true, and once on the client side with willHarvest = false.
Here is my getDrops, removedByPlayer, and harvestBlock:
@Override public List<ItemStack> getDrops(IBlockAccess world, BlockPos pos, IBlockState state, int fortune) { List<ItemStack> itemStacks = super.getDrops(world, pos, state, fortune); TileEntity te = world.getTileEntity(pos); if (te == null) { System.out.println("Could not write path to tag. te=" + te); return itemStacks; } if (!(te instanceof BlockSavedTileEntity)) { System.out.println("Could not write path to tag. TileEntity not a BlockSavedTileEntity. te=" + te); return itemStacks; } String path = ((BlockSavedTileEntity) te).getPath(); ItemStack stack = new ItemStack(this); NBTTagCompound tag = new NBTTagCompound(); stack.setTagCompound(tag); ((BlockSavedTileEntity) te).writeToNBT(tag); itemStacks.add(stack); return itemStacks; } // FIXME creates two drops @Override public boolean removedByPlayer(World world, BlockPos pos, EntityPlayer player, boolean willHarvest) { System.out.println("world=" + world); System.out.println("willHarvest=" + willHarvest); if (willHarvest) { // Delay deletion of the block until after getDrops return true; } return super.removedByPlayer(world, pos, player, willHarvest); } @Override public void harvestBlock(World world, EntityPlayer player, BlockPos pos, IBlockState state, TileEntity te) { super.harvestBlock(world, player, pos, state, te); world.setBlockToAir(pos); }
Here is my console:
[10:30:53] [Client thread/INFO] [sTDOUT]: [org.snowyegret.mojo.block.BlockSaved:removedByPlayer:132]: world=net.minecraft.client.multiplayer.WorldClient@77e55368 [10:30:53] [Client thread/INFO] [sTDOUT]: [org.snowyegret.mojo.block.BlockSaved:removedByPlayer:133]: willHarvest=false [10:30:53] [server thread/INFO] [sTDOUT]: [org.snowyegret.mojo.block.BlockSaved:removedByPlayer:132]: world=net.minecraft.world.WorldServer@6caed19b [10:30:53] [server thread/INFO] [sTDOUT]: [org.snowyegret.mojo.block.BlockSaved:removedByPlayer:133]: willHarvest=true
For reference, here are BlockFlowerPot's overrides of the three methods:
/*============================FORGE START=====================================*/ @Override public java.util.List<ItemStack> getDrops(IBlockAccess world, BlockPos pos, IBlockState state, int fortune) { java.util.List<ItemStack> ret = super.getDrops(world, pos, state, fortune); TileEntityFlowerPot te = world.getTileEntity(pos) instanceof TileEntityFlowerPot ? (TileEntityFlowerPot)world.getTileEntity(pos) : null; if (te != null && te.getFlowerPotItem() != null) ret.add(new ItemStack(te.getFlowerPotItem(), 1, te.getFlowerPotData())); return ret; } @Override public boolean removedByPlayer(World world, BlockPos pos, EntityPlayer player, boolean willHarvest) { if (willHarvest) return true; //If it will harvest, delay deletion of the block until after getDrops return super.removedByPlayer(world, pos, player, willHarvest); } @Override public void harvestBlock(World world, EntityPlayer player, BlockPos pos, IBlockState state, TileEntity te) { super.harvestBlock(world, player, pos, state, te); world.setBlockToAir(pos); } /*===========================FORGE END==========================================*/
[1.8] [Solved] Block with ISmartModel not rendering as Item (TGG?)
in Modder Support
Posted
Finally, got it working.
I'll submit an issue to the MBE Github repository with notes about the additional interface needed to render the block as an item.
Thanks for the help, TGG.