Jump to content

Recommended Posts

Posted

I've recently been trying to make a block whose textures I can change by right clicking a side (the texture should only change on that side). I've been banging my head against the wall with this new modeling system, unable to understand how to actually create this. I've looked into TESR and IModel, and for such a simple thing it seems really stupid that I can't seem to figure out how to do it.

 

My issue with TESR is that it renders really dark unless i make it allow light to travel through the base block. I can't quite pinpoint why chests and such don't have this issue, and why they don't even have a block model which everything else does, when if I don't have a block model, I get a no texture (purple and black) block. Having both the TESR and the block model both render causes z fighting. Regardless, I've read many times that TESR isn't really intended for something like this, but rather something mainly for animations. This doesn't mean I wouldn't like to know more about it.

 

My issue with the IModel is that I've no idea how to create one, and how to use the data in it to actually render different textures. I have read that you need an ICustomModelLoader, but I've no idea how to actually implement one. The forge docs seem to say some stuff about the class but not super useful about an actual implementation. I've spent hours searching for a tutorial on an implementation of this and I can't find a single one.

 

Surely I'm missing something big here, does anyone know the answers to my questions? I feel like rendering stuff used to be so easy and now I have to rip myself apart just to figure out how to render a block with dynamic textures.

Posted

1.12 or 1.13? You want an IBakedModel not an IModel btw, the IModel is just the raw model loaded from JSON which is then baked to an IBakedModel that is used in rendering. 

About Me

Spoiler

My Discord - Cadiboo#8887

My WebsiteCadiboo.github.io

My ModsCadiboo.github.io/projects

My TutorialsCadiboo.github.io/tutorials

Versions below 1.14.4 are no longer supported on this forum. Use the latest version to receive support.

When asking support remember to include all relevant log files (logs are found in .minecraft/logs/), code if applicable and screenshots if possible.

Only download mods from trusted sites like CurseForge (minecraft.curseforge.com). A list of bad sites can be found here, with more information available at stopmodreposts.org

Edit your own signature at www.minecraftforge.net/forum/settings/signature/ (Make sure to check its compatibility with the Dark Theme)

Posted

About Me

Spoiler

My Discord - Cadiboo#8887

My WebsiteCadiboo.github.io

My ModsCadiboo.github.io/projects

My TutorialsCadiboo.github.io/tutorials

Versions below 1.14.4 are no longer supported on this forum. Use the latest version to receive support.

When asking support remember to include all relevant log files (logs are found in .minecraft/logs/), code if applicable and screenshots if possible.

Only download mods from trusted sites like CurseForge (minecraft.curseforge.com). A list of bad sites can be found here, with more information available at stopmodreposts.org

Edit your own signature at www.minecraftforge.net/forum/settings/signature/ (Make sure to check its compatibility with the Dark Theme)

Posted

This has given me a fairly good understanding but now I run into another issue. It appears that BakedQuads drive what appears on a face of a block. Finding this out, I tried to create a custom BakedQuad for use as in my custom BakedModel, but it appears to not be having the effects I would desire.

 

public class VariableTextureBakedQuad extends BakedQuad {

   public VariableTextureBakedQuad(BakedQuad quad, TextureAtlasSprite sprite) {
      super(quad.getVertexData(), quad.getTintIndex(), quad.getFace(), sprite, quad.shouldApplyDiffuseLighting(), quad.getFormat());

   }

   /**
    * Joined 4 vertex records, each stores packed data according to the VertexFormat of the quad. Vanilla minecraft
    * uses DefaultVertexFormats.BLOCK, Forge uses (usually) ITEM, use BakedQuad.getFormat() to get the correct format.
    */
// protected final int[] vertexData;
// protected final int tintIndex;
// protected final EnumFacing face;
// protected final TextureAtlasSprite sprite;

   public TextureAtlasSprite getSprite()
   {
      return this.sprite;
   }

   public int[] getVertexData()
   {
      return this.vertexData;
   }

   public boolean hasTintIndex()
   {
      return this.tintIndex != -1;
   }

   public int getTintIndex()
   {
      return this.tintIndex;
   }

   public EnumFacing getFace()
   {
      return this.face;
   }

// protected final net.minecraft.client.renderer.vertex.VertexFormat format;
// protected final boolean applyDiffuseLighting;

   @Override
   public void pipe(net.minecraftforge.client.model.pipeline.IVertexConsumer consumer)
   {
      net.minecraftforge.client.model.pipeline.LightUtil.putBakedQuad(consumer, this);
   }

   public net.minecraft.client.renderer.vertex.VertexFormat getFormat()
   {
      return format;
   }

   public boolean shouldApplyDiffuseLighting()
   {
      return applyDiffuseLighting;
   }
}

 

Which is created here:

private IBakedModel modelWhenNotCamouflaged;
private List<BakedQuad>[] quads;
private TextureAtlasSprite sprite;

public CustomBakedModel(IBakedModel unCamouflagedModel, Block yeetblock)
{
   quads = new List[6];
   modelWhenNotCamouflaged = unCamouflagedModel;
   List<BakedQuad> quadlist = new ArrayList<>();
   sprite = Minecraft.getMinecraft().getTextureMapBlocks().registerSprite(new ResourceLocation("customblock","blocks/custom_block2"));
   VariableTextureBakedQuad quad = new VariableTextureBakedQuad(modelWhenNotCamouflaged.getQuads(null,EnumFacing.UP,0).get(0),sprite);
   quadlist.add(quad);
   quads[0] = quadlist;
}

 

Quad is used here:

public List<BakedQuad> getQuads(@Nullable IBlockState state, @Nullable EnumFacing side, long rand)
{
   if(side != EnumFacing.UP)
      return modelWhenNotCamouflaged.getQuads(state, side, rand);
   else {
      return quads[0];
   }
}

 

Despite doing this, the custom sprite is not showing up on the top of the block as the quad being used should do (it is showing up as the original blocks texture). My current theory is that the sprite included in the BakedQuad class doesn't have anything to do with the actual texture rendered, as even when I tried to use reflection to change the texture of them all the quads, it didn't have any effect.

 

This leads me to believe that the TextureAtlasSprite is actually the entire texture atlas, and the only other place I can see where the texture coordinates could be stored is in the vertex data, but I've no idea how to manipulate the texture coordinates I suspect to be in there to point to another texture. Does anyone have any knowledge on this?

Posted
35 minutes ago, PoisonedPorkchop said:

My current theory is that the sprite included in the BakedQuad class doesn't have anything to do with the actual texture rendered, as even when I tried to use reflection to change the texture of them all the quads, it didn't have any effect.

That is correct.

 

36 minutes ago, PoisonedPorkchop said:

This leads me to believe that the TextureAtlasSprite is actually the entire texture atlas

TextureAtlasSprite is, well, a sprite on the atlas. It's not the atlas itself.

 

36 minutes ago, PoisonedPorkchop said:

and the only other place I can see where the texture coordinates could be stored is in the vertex data

This is correct. The vertex data contains the UV coordinates to use.

 

37 minutes ago, PoisonedPorkchop said:

sprite = Minecraft.getMinecraft().getTextureMapBlocks().registerSprite(new ResourceLocation("customblock","blocks/custom_block2"));

Don't do that here. This needs to be done in the texture stich event.

 

As for what you want to do there is a BakedQuadRetextured class already.

Posted

I've run into a small issue that I'm quite unsure what is causing it. Right clicking on the block appears to give me a blockstate that does not have my unlisted property, though everywhere else I use it, it does have the property.

 

@Override
public IBlockState getExtendedState(IBlockState state, IBlockAccess world, BlockPos pos) {
   if (state instanceof IExtendedBlockState) {  // avoid crash in case of mismatch
      IExtendedBlockState retval = (IExtendedBlockState)state;
      retval = retval.withProperty(TOP, world.getBlockState(pos.add(0,1,0)));
      ExampleMod.logger.info("ABOVE BLOCK: " + retval.getValue(TOP).getBlock().getUnlocalizedName());
      return retval;
   }
   return state;
}

@Override
public boolean onBlockActivated(World worldIn, BlockPos pos, IBlockState state, EntityPlayer playerIn, EnumHand hand, EnumFacing facing, float hitX, float hitY, float hitZ)
{
   if(worldIn.isRemote) {
      if (state instanceof IExtendedBlockState) {  // avoid crash in case of mismatch
         IExtendedBlockState estate = (IExtendedBlockState)state;
         ExampleMod.logger.info("GETTING EXTENDED STATE C: " + estate.getValue(TOP));
      }
   }
   else
   {
      if (state instanceof IExtendedBlockState) {  // avoid crash in case of mismatch
         IExtendedBlockState estate = (IExtendedBlockState)state;
         ExampleMod.logger.info("GETTING EXTENDED STATE S: " + estate.getValue(TOP));
      }
   }
   return true;
}

In the above code, the print with "ABOVE BLOCK: " prints correctly, but in the onBlockActivated method, when I right click on the block, it says the value of TOP is null. Have any idea what may be causing this? I want to change the property by right clicking the block, then update the block texture based upon the changes I make to the unlisted property in the onBlockActivated, but I need to know the previous value of TOP in order to get my next value.

Posted (edited)

Alright, and how would I go about updating the model for an existing block, making it call getQuads again? This would occur after I change some data in the tile entity after a right click, so that the resulting quad would be different

Edited by PoisonedPorkchop
Posted (edited)
@Override
public boolean onBlockActivated(World worldIn, BlockPos pos, IBlockState state, EntityPlayer playerIn, EnumHand hand, EnumFacing facing, float hitX, float hitY, float hitZ)
{
   if(!worldIn.isRemote) {
      getTileEntity(worldIn,pos).giveClick();
      ExampleMod.logger.info("CLICKS: " + getTileEntity(worldIn,pos).getTimesClicked());
      if (state instanceof IExtendedBlockState) {  // avoid crash in case of mismatch
         IExtendedBlockState retval = (IExtendedBlockState)state;
         retval = retval.withProperty(TOP, getTileEntity(worldIn,pos).getTimesClicked());
         ExampleMod.logger.info("QUAD CHANGE");
         worldIn.notifyBlockUpdate(pos,state,retval,3);
      }
   }
   return true;
}

I tried doing this, but the block isn't calling getQuads upon a right click, how do I change the quads in this case?

public List<BakedQuad> getQuads(@Nullable IBlockState state, @Nullable EnumFacing side, long rand)
{
   if(side == EnumFacing.UP) {
      if(state instanceof IExtendedBlockState)
      {
         IExtendedBlockState extendedBlockState = (IExtendedBlockState) state;
         ExampleMod.logger.info("CUSTOM QUAD ENACTED: " + extendedBlockState.getValue(TOP));
         return quads[extendedBlockState.getValue(TOP) % quads.length];
      }
   }
   return modelWhenNotCamouflaged.getQuads(state, side, rand);
}
Edited by PoisonedPorkchop
Posted (edited)
41 minutes ago, diesieben07 said:

You are still messing with IExtendedBlockState in onBlockActivated. Don't.

The reason I am is for newState in notifyBlockUpdate, which the code of is here.

/**
 * Flags are as in setBlockState
 */
public void notifyBlockUpdate(BlockPos pos, IBlockState oldState, IBlockState newState, int flags)
{
    for (int i = 0; i < this.eventListeners.size(); ++i)
    {
        ((IWorldEventListener)this.eventListeners.get(i)).notifyBlockUpdate(this, pos, oldState, newState, flags);
    }
}

I figured since it takes parameter newState, I figured calling this method would call getQuads (which does take an IExtendedBlockState which I am using an unlisted property from) from my custom IBakedModel class, but it appears that calling notifyBlockUpdate is not calling getQuads.

 

If this is not the way to change the quads of my block, what is?

Edited by PoisonedPorkchop
Posted (edited)
1 hour ago, diesieben07 said:

As far as the world is concerned the state did not change. Just use the same block state.

Ok, well how if I'm not updating the IBakedQuads via an IExtendedBlockState, how else do I update the quad?

I figured updating the block would make the game call getQuads from the IBakedModel, but this is not the case.

Edited by PoisonedPorkchop
Posted

Extended blockstates are gone in 1.13.2, use the new & better IModelAPI instead.

About Me

Spoiler

My Discord - Cadiboo#8887

My WebsiteCadiboo.github.io

My ModsCadiboo.github.io/projects

My TutorialsCadiboo.github.io/tutorials

Versions below 1.14.4 are no longer supported on this forum. Use the latest version to receive support.

When asking support remember to include all relevant log files (logs are found in .minecraft/logs/), code if applicable and screenshots if possible.

Only download mods from trusted sites like CurseForge (minecraft.curseforge.com). A list of bad sites can be found here, with more information available at stopmodreposts.org

Edit your own signature at www.minecraftforge.net/forum/settings/signature/ (Make sure to check its compatibility with the Dark Theme)

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Announcements



×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.