Jump to content

[1.8][SOLVED] Need help with changing blockmodel (via blockstate)from tileentity


Recommended Posts

Posted

I'm working on a block that faces a direction and has five levels of water... so i can't store all that in a byte of meta. I just tried to save the water level in NBT, which worked, then I changed the shouldRefresh() to return false and added a statement to remove the TE in it's update method. After I started debugging, I saw that, no matter what is saved in NBT, the water level will always be set to 4 (the max) and even when i hardcoded the TE to set the value of the water level in the blockstate to 0, it was still debugged as 4 one line later! I have no idea.... any help is greatly appreciated!

 

Source (GitHub):

 

https://github.com/Kant0sh/MD/blob/master/src/main/java/com/kant0sh/md/tileEntities/BigCauldronTileEntity.java --> TileEntity class

 

https://github.com/Kant0sh/MD/blob/master/src/main/java/com/kant0sh/md/blocks/BigCauldronBlock.java --> Block class

 

https://github.com/Kant0sh/MD/blob/master/src/main/resources/assets/md/blockstates/bigCauldron.json --> Blockstates .json

 

Quick Source!

 

Essential parts of TE class:

 

if(!(worldObj.getBlockState(pos).getBlock() instanceof BigCauldronBlock)){

worldObj.setTileEntity(pos, null);

return;

}

 

worldObj.setBlockState(pos, worldObj.getBlockState(pos).withProperty(((BigCauldronBlock) worldObj.getBlockState(pos).getBlock()).LEVEL, this.getWaterLevel()));

worldObj.scheduleUpdate(pos, worldObj.getBlockState(pos).getBlock(), 0);

 

@Override

public boolean shouldRefresh(World world, BlockPos pos, IBlockState oldState, IBlockState newSate) {

return false;

}

 

// NBT read and write

 

public int getWaterLevel() {

return waterLevel;

}

 

public void setWaterLevel(int waterLevel) {

this.waterLevel = waterLevel;

}

 

public int getMaxWaterLevel() {

return 4;

}

 

Essential parts of Block class:

 

public static final PropertyDirection FACING = PropertyDirection.create("facing", EnumFacing.Plane.HORIZONTAL);

public static final PropertyInteger LEVEL = PropertyInteger.create("level", 0, 4);

 

public BigCauldronBlock() {

super("bigCauldron");

setDefaultState(this.blockState.getBaseState().withProperty(FACING, EnumFacing.NORTH).withProperty(LEVEL, 0));

}

 

@Override

public IBlockState getStateForEntityRender(IBlockState state) {

return this.getDefaultState().withProperty(FACING, EnumFacing.SOUTH).withProperty(LEVEL, 0);

}

 

@Override

public IBlockState getStateFromMeta(int meta) {

 

EnumFacing enumFacing = EnumFacing.getFront(meta);

 

if(enumFacing.getAxis() == EnumFacing.Axis.Y){

enumFacing = enumFacing.NORTH;

}

 

return this.getDefaultState().withProperty(FACING, enumFacing);

}

 

@Override

public int getMetaFromState(IBlockState state) {

return ((EnumFacing) state.getValue(FACING)).getIndex();

}

 

@Override

protected BlockState createBlockState() {

return new BlockState(this, new IProperty[]{FACING, LEVEL});

}

 

@Override

public TileEntity createTileEntity(World world, IBlockState state) {

return new BigCauldronTileEntity();

}

 

@Override

public IBlockState onBlockPlaced(World worldIn, BlockPos pos, EnumFacing facing, float hitX, float hitY, float hitZ, int meta, EntityLivingBase placer) {

return this.getDefaultState().withProperty(FACING, placer.getHorizontalFacing().getOpposite());

}

 

Blockstate .json:

 

{

   

    "variants": {

   

        "facing=north,level=0": { "model": "md:bigCauldronEmpty" },

        "facing=north,level=1": { "model": "md:bigCauldronLevel1" },

        "facing=north,level=2": { "model": "md:bigCauldronLevel2" },

        "facing=north,level=3": { "model": "md:bigCauldronLevel3" },

        "facing=north,level=4": { "model": "md:bigCauldronLevel4" },

       

        "facing=south,level=0": { "model": "md:bigCauldronEmpty", "y": 180 },

        "facing=south,level=1": { "model": "md:bigCauldronLevel1", "y": 180 },

        "facing=south,level=2": { "model": "md:bigCauldronLevel2", "y": 180 },

        "facing=south,level=3": { "model": "md:bigCauldronLevel3", "y": 180 },

        "facing=south,level=4": { "model": "md:bigCauldronLevel4", "y": 180 },

       

        "facing=west,level=0": { "model": "md:bigCauldronEmpty", "y": 270 },

        "facing=west,level=1": { "model": "md:bigCauldronLevel1", "y": 270 },

        "facing=west,level=2": { "model": "md:bigCauldronLevel2", "y": 270 },

        "facing=west,level=3": { "model": "md:bigCauldronLevel3", "y": 270 },

        "facing=west,level=4": { "model": "md:bigCauldronLevel4", "y": 270 },

       

        "facing=east,level=0": { "model": "md:bigCauldronEmpty", "y": 90 },

        "facing=east,level=1": { "model": "md:bigCauldronLevel1", "y": 90 },

        "facing=east,level=2": { "model": "md:bigCauldronLevel2", "y": 90 },

        "facing=east,level=3": { "model": "md:bigCauldronLevel3", "y": 90 },

        "facing=east,level=4": { "model": "md:bigCauldronLevel4", "y": 90 }

       

    }

   

}

Thanks for helping me <3

Posted

I tried to apply it via the TileEntity with the first "Oh god why"... but even if I'm not applying anything, why would it always jump to 4? I edited the write to NBT to seve 0, and after reloading the world it still was immediately changed to 4

 

PS: btw most of the stuff you mentioned is left over from code i tampered with previously and just trial and error.... i left in what worked :D

Thanks for helping me <3

Posted

I need help with one more thing... the blockstate now changes to the correct values and responds correctly, but the model that's rendered doesn't change. Do i have to call some kind of update manually?

Thanks for helping me <3

Posted

I now have the correct state over in my Block class in the client side of the onBlockActivated! but how do i get it to update from there? just setting the state variable doesn't work and the blockState field is final :/

Thanks for helping me <3

Posted

public void setWaterLevel(int waterLevel) {

this.waterLevel = waterLevel;

}

 

I created this setter alongside with a field in the Block class. I call this function in the Runnable in onMessage, as you described in your tutorial. Now i have a section in the onBlockActivated() method where world.isRemote is true and was trying to set the blockState of the class appropriately there. is there a method to do so or how do i tell the renderengine to render another model?

 

state = (IBlockState) getDefaultState().withProperty(FACING, state.getValue(FACING)).withProperty(LEVEL, waterLevel);

 

that is my try to use a field already in the minecraft.block.Block class.

Thanks for helping me <3

Posted

I'm honestly sorry for bothering you for so long but i can't seem to get anywhere... I have used the getActualState method to get the data from the TE to my block, then i've sent the packet with basically the same data to the client (or as the method is called, sendToAll) and now i have  gotten the data basically everywhere i could possibly work with it. Still, i don't know how to effectively "change" or "update" my BlockState so that it tells minecraft to use the correct variant specified in the blockstate json....  what ive seen by googling just said use packets and then it works, but I'm missing an essential piece of code here :|

Thanks for helping me <3

Posted

Rendering works fine, but needs a block update... which i cant figure out how to do because even after a few ticks of delay, the metchods google brought up dont work. also, when i break the block the TE is removed and everything is as usual, but when i replace a Cauldron in the exact same spot, its waterLevel is back...? even if there was another block there (wll air is going to be there anyway). And if i place a chest there, it does not render and the waterLevel is still maintained. I will push again if you want to have another look

Thanks for helping me <3

Posted

1. I want to render a changing water level in the cauldron upon filling it with buckets. After right clicking it with a bucket, the cauldron needs a manual blockupdate, and i dont know how to do that in the code.

 

2. After breaking the cauldron block, it removes the block and its tileentity from the world like usual, but as soon as i place a cauldron back in the same spot, it gets the water back, the previous one had in it.

 

3. when placing a chest in the spot where a filled cauldron was, the chest does not render at all, but behaves normally. still, the water level is somehow retained when removing the chest and placing a cauldron back... weird, is it not?

 

might put up some screenshots if i get good ones

Thanks for helping me <3

Posted

2. & 3.: so in shouldRefresh i check if the block is still there and if not return true? i thought that

 

if(!(worldObj.getBlockState(pos).getBlock() instanceof BigCauldronBlock)){

worldObj.setTileEntity(pos, null);

return;

}

 

would do it... derp :P

 

1. do you mean in onMessage? because in the TE update (the place that calls after changing the waterlevel) i did that already even with a few ticks delay...

Thanks for helping me <3

Posted

I have this:

 

@Override

public boolean shouldRefresh(World world, BlockPos pos, IBlockState oldState, IBlockState newSate) {

return oldState.getBlock() != newSate.getBlock();

}

 

i removed the crap...

 

this:

 

Minecraft.getMinecraft().theWorld.markBlockForUpdate(new BlockPos(message.x, message.y, message.z));

 

in the onMessage run method

 

AND EVERYTHING WORKS!!!!!!! Thanks sooo much man!

Thanks for helping me <3

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



  • Recently Browsing

    • No registered users viewing this page.
  • Posts

    • Decompiling minecraft indev, infdev, alpha, beta or whichever legacy version is really easy. I'm not a plug, I just also got interested in modding legacy versions (Infdev to be specific). Use https://github.com/MCPHackers/RetroMCP-Java Once you install their client and the Zulu Architecture that they say they recommend (or use your own Java). I encountered some problems, so I run it with: "java -jar RetroMCP-Java-CLI.jar". You should run it in a seperate folder (not in downloads), otherwise the files and folders will go all over the place. How to use RetroMCP: Type setup (every time you want change version), copy-paste the version number from their list (they support indev), write "decompile" and done! The code will now be deobfuscated and filenames will be normal, instead of "a", "b" and "c"! Hope I helped you, but I don't expect you to reply, as this discussion is 9 years old! What a piece of history!  
    • I know that this may be a basic question, but I am very new to modding. I am trying to have it so that I can create modified Vanilla loot tables that use a custom enchantment as a condition (i.e. enchantment present = item). However, I am having trouble trying to implement this; the LootItemRandomChanceWithEnchantedBonusCondition constructor needs a Holder<Enchantment> and I am unable to use the getOrThrow() method on the custom enchantment declared in my mod's enchantments class. Here is what I have so far in the GLM:   protected void start(HolderLookup.Provider registries) { HolderLookup.RegistryLookup<Enchantment> registrylookup = registries.lookupOrThrow(Registries.ENCHANTMENT); LootItemRandomChanceWithEnchantedBonusCondition lootItemRandomChanceWithEnchantedBonusCondition = new LootItemRandomChanceWithEnchantedBonusCondition(0.0f, LevelBasedValue.perLevel(0.07f), registrylookup.getOrThrow(*enchantment here*)); this.add("nebu_from_deepslate", new AddItemModifier(new LootItemCondition[]{ LootItemBlockStatePropertyCondition.hasBlockStateProperties(Blocks.DEEPSLATE).build(), LootItemRandomChanceCondition.randomChance(0.25f).build(), lootItemRandomChanceWithEnchantedBonusCondition }, OrichalcumItems.NEBU.get())); }   Inserting Enchantments.[vanilla enchantment here] actually works but trying to declare an enchantment from my custom enchantments class as [mod enchantment class].[custom enchantment] does not work even though they are both a ResourceKey and are registered in Registries.ENCHANTMENT. Basically, how would I go about making it so that a custom enchantment declared as a ResourceKey<Enchantment> of value ResourceKey.create(Registries.ENCHANTMENT, ResourceLocation.fromNamespaceAndPath([modid], [name])), declared in a seperate enchantments class, can be used in the LootItemRandomChanceWithEnchantedBonusCondition constructor as a Holder? I can't use getOrThrow() because there is no level or block entity/entity in the start() method and it is running as datagen. It's driving me nuts.
    • Hi here is an update. I was able to fix the code so my mod does not crash Minecraft. Please understand that I am new to modding but I honestly am having a hard time understanding how anyone can get this to work without having extensive programming and debugging experience as well as searching across the Internet, multiple gen AI bots (claude, grok, openai), and examining source code hidden in the gradle directory and in various github repositories. I guess I am wrong because clearly there are thousands of mods so maybe I am just a newbie. Ok, rant over, here is a step by step summary so others can save the 3 days it took me to figure this out.   1. First, I am using forge 54.1.0 and Minecraft 1.21.4 2. I am creating a mod to add a shotgun to Minecraft 3. After creating the mod and compiling it, I installed the .jar file to the proper directory in Minecraft and used 1.21.4-forge-54.1.0 4. The mod immediately crashed with the error: Caused by: java.lang.NullPointerException: Item id not set 5. Using the stack trace, I determined that the Exception was being thrown from the net.minecraft.world.item.Item.Properties class 6. It seems that there are no javadocs for this class, so I used IntelliJ which was able to provide a decompiled version of the class, which I then examined to see the source of the error. Side question: Are there javadocs? 7. This method, specifically, was the culprit: protected String effectiveDescriptionId() {      return this.descriptionId.get(Objects.requireNonNull(this.id, "Item id not set"));  } 8. Now my quest was to determine how to set this.id. Looking at the same source file, I determined there was another method:  public Item.Properties setId(ResourceKey<Item> pId) {             this.id = pId;             return this;   } 9. So now, I need to figure out how to call setId(). This required working backwards a bit. Starting from the constructor, I stubbed out the variable p which is of type Item.Properties public static final RegistryObject<Item> SHOTGUN = ITEMS.register("shotgun", () -> new ShotgunItem(p)); Rather than putting this all on one line, I split it up for readability like this: private static final Item.Properties p = new Item.Properties().useItemDescriptionPrefix().setId(rk); Here is was the missing function, setId(), which takes a type of ResourceKey<Item>. My next problem is that due to the apparent lack of documentation (I tried searching the docs on this site) I could not determine the full import path to ResourceKey. I did some random searching on the Internet and stumbled across a Github repository which gave two clues: import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; Then I created the rk variable like this: private static ResourceKey<Item> rk = ResourceKey.create(Registries.ITEM, ResourceLocation.parse("modid:shotgunmod")); And now putting it all together in order: private static ResourceKey<Item> rk = ResourceKey.create(Registries.ITEM, ResourceLocation.parse("modid:shotgunmod")); private static final Item.Properties p = new Item.Properties().useItemDescriptionPrefix().setId(rk); public static final RegistryObject<Item> SHOTGUN = ITEMS.register("shotgun", () -> new ShotgunItem(p)); This compiled and the mod no longer crashes. I still have more to do on it, but hopefully this will save someone hours. I welcome any feedback and if I missed some obvious modding resource or tutorial that has this information. If not, I might suggest we add it somewhere for people trying to write a mod that doesn't crash. Thank you !!!  
    • I will keep adding to this thread with more information in case anyone can help, or at the very least I can keep my troubleshooting organized. I decided to downgrade to 54.1.0 in the hopes that this would fix the issue but it didn't. At least now I am on a "recommended" version. The crash report did confirm my earlier post that the Exception is coming from effectiveDescriptionId(). I'll continue to see if I can find a way to set the ID manually.   Caused by: java.lang.NullPointerException: Item id not set         at java.base/java.util.Objects.requireNonNull(Objects.java:259) ~[?:?]         at TRANSFORMER/[email protected]/net.minecraft.world.item.Item$Properties.effectiveDescriptionId(Item.java:465) ~[forge-1.21.4-54.1.0-client.jar!/:?]         at TRANSFORMER/[email protected]/net.minecraft.world.item.Item.<init>(Item.java:111) ~[forge-1.21.4-54.1.0-client.jar!/:?]         at TRANSFORMER/[email protected]/com.example.shotgunmod.ShotgunItem.<init>(ShotgunItem.java:19) ~[shotgunmod-1.0.0.jar!/:1.0.0]         at TRANSFORMER/[email protected]/com.example.shotgunmod.ModItems.lambda$static$0(ModItems.java:15) ~[shotgunmod-1.0.0.jar!/:1.0.0]         at TRANSFORMER/[email protected]/net.minecraftforge.registries.DeferredRegister$EventDispatcher.lambda$handleEvent      
  • Topics

×
×
  • Create New...

Important Information

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