Jump to content
  • Home
  • Files
  • Docs
Topics
  • All Content

  • This Topic
  • This Forum

  • Advanced Search
  • Existing user? Sign In  

    Sign In



    • Not recommended on shared computers


    • Forgot your password?

  • Sign Up
  • All Activity
  • Home
  • Mod Developer Central
  • Modder Support
  • [1.6.4] Confusion on Reading and Writing TileEntity data to the world
Currently Supported: 1.16.X (Latest) and 1.15.X (LTS)
Sign in to follow this  
Followers 1
Jipthechip

[1.6.4] Confusion on Reading and Writing TileEntity data to the world

By Jipthechip, November 14, 2020 in Modder Support

  • Reply to this topic
  • Start new topic

Recommended Posts

Jipthechip    0

Jipthechip

Jipthechip    0

  • Tree Puncher
  • Jipthechip
  • Members
  • 0
  • 27 posts
Posted November 14, 2020 (edited)

I'm trying to save the data of a custom TileEntity, but it doesn't seem to be working properly because after unloading and reloading the chunk, the data is no longer there. Here is my TileEntity class:

package com.jipthechip.fermentationmod.Entities;

import mcp.MethodsReturnNonnullByDefault;
import net.minecraft.block.BlockState;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.IStringSerializable;

import java.util.Arrays;

@MethodsReturnNonnullByDefault
public class MasherBowlTileEntity extends TileEntity {

    public enum FoodType implements IStringSerializable {
        apple,
        baked_potato,
        beetroot,
        bread,
        carrot,
        chorus_fruit,
        dried_kelp,
        kelp,
        honey_bottle,
        melon_slice,
        potato,
        poisonous_potato,
        pumpkin,
        sweet_berries,
        nothing;

        @Override
        public String getString() {
            return this.name();
        }
    }

    private FoodType[] ingredients = new FoodType[4];

    public MasherBowlTileEntity(){
        super(TileEntitiesList.masher_bowl);
        clearFoods();
    }

    @Override
    public void read(BlockState state, CompoundNBT compound) {
        super.read(state, compound);
        int [] arr = compound.getIntArray("foodarr");
        if(arr.length == 0) System.out.println("no ingredients read!");
        else System.out.print("reading ingredients: "+ arr[0] + "," + arr[1]+ "," + arr[2]+ "," + arr[3]+ "\n");
        for(int i = 0; i < arr.length; i++){
            ingredients[i] = FoodType.values()[arr[i]];
        }
    }

    private int[] foodToIntArray(FoodType[] arr){
        int[] result = new int[arr.length];
        for(int i = 0; i < arr.length; i++){
            result[i] = arr[i].ordinal();
        }
        return result;
    }

    @Override
    public CompoundNBT write(CompoundNBT compound) {
        super.write(compound);
        int [] arr = foodToIntArray(ingredients);
        compound.putIntArray("foodarr", arr);
        System.out.print("writing ingredients: "+ arr[0] + "," + arr[1]+ "," + arr[2]+ "," + arr[3]+ "\n");
        return compound;
    }

    public boolean addFood(FoodType food){
        for(int i = 0; i < ingredients.length; i++){
            if(ingredients[i] == FoodType.nothing){
                markDirty();
                ingredients[i] = food;
                return true;
            }
        }
        return false;
    }

    public void clearFoods(){
        markDirty();
        Arrays.fill(ingredients, FoodType.nothing);
    }

    public FoodType getIngredient(int index) {
        return ingredients[index];
    }
}

 

In order to have TileEntity data saved to the world, you use the read() and write() methods of the TileEntity class to read and write NBT's, correct? And when exactly are read() and write() called?

Edited November 14, 2020 by Jipthechip
  • Quote

Share this post


Link to post
Share on other sites

ChampionAsh5357    162

ChampionAsh5357

ChampionAsh5357    162

  • World Shaper
  • ChampionAsh5357
  • Members
  • 162
  • 1024 posts
Posted November 14, 2020
2 hours ago, Jipthechip said:

the data is no longer there

How are you verifying this claim? This works fine if I'm not mistaken.

  • Quote

Share this post


Link to post
Share on other sites

poopoodice    114

poopoodice

poopoodice    114

  • Dragon Slayer
  • poopoodice
  • Members
  • 114
  • 904 posts
Posted November 14, 2020

May not be the problem but are you clearing the data and mark it dirty in the constructor?

  • Quote

Share this post


Link to post
Share on other sites

Jipthechip    0

Jipthechip

Jipthechip    0

  • Tree Puncher
  • Jipthechip
  • Members
  • 0
  • 27 posts
Posted November 14, 2020 (edited)
22 minutes ago, ChampionAsh5357 said:

How are you verifying this claim? This works fine if I'm not mistaken.

My bad, I can tell it's no longer there because I have an IBlockColor class setting the color of one of the submodels of the TileEntity, and the color depends on data within my custom TileEntity class. When I reload the chunk, the color goes back to its default blue and the TileEntity accepts 4 ingredients again even though it should be full.

 

Also here is my custom IBlockColor class in case this helps:

 

package com.jipthechip.fermentationmod.Blocks;

import com.jipthechip.fermentationmod.Entities.MasherBowlTileEntity;
import net.minecraft.block.BlockState;
import net.minecraft.block.material.MaterialColor;
import net.minecraft.client.renderer.color.IBlockColor;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.IBlockDisplayReader;

import javax.annotation.Nullable;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import net.minecraft.world.World;

import static com.jipthechip.fermentationmod.Entities.MasherBowlTileEntity.FoodType;

public class MasherWaterColor implements IBlockColor {

    private final Map<FoodType, Integer> foodColors = Stream.of(new Object[][] {
            {FoodType.apple, 0xffffe063},
            {FoodType.baked_potato, 0xfffff8ad},
            {FoodType.beetroot, 0xffa4272b},
            {FoodType.bread, 0xffe8d697},
            {FoodType.carrot, 0xffff8e09},
            {FoodType.chorus_fruit, 0xff8E678D},
            {FoodType.dried_kelp, 0xff3C3324},
            {FoodType.kelp, 0xff5C8332},
            {FoodType.honey_bottle, 0xffFFD32D},
            {FoodType.melon_slice, 0xffBF3123},
            {FoodType.potato, 0xfffff8ad},
            {FoodType.poisonous_potato, 0xffefffad},
            {FoodType.pumpkin, 0xffE38A1D},
            {FoodType.sweet_berries, 0xffDF467E},
            {FoodType.nothing, MaterialColor.WATER.colorValue}
    }).collect(Collectors.toMap(data -> (FoodType) data[0], data -> (Integer) data[1]));

    @Override
    public int getColor(BlockState state, @Nullable IBlockDisplayReader blockDisplayReader, @Nullable BlockPos pos, int tintIndex) {

        assert blockDisplayReader != null;
        assert pos != null;

        MasherBowlTileEntity tileEntity = (MasherBowlTileEntity) blockDisplayReader.getTileEntity(pos);

        assert tileEntity != null;
        // mix the colors of the 4 ingredients together
        int ingredients = mixColors(1, foodColors.get(tileEntity.getIngredient(0)),
                          mixColors(1, foodColors.get(tileEntity.getIngredient(1)),
                          mixColors(1, foodColors.get(tileEntity.getIngredient(2)), foodColors.get(tileEntity.getIngredient(3)))));

        return mixColors(10-state.get(MasherBowlBlock.STIR_PROGRESS), MaterialColor.WATER.colorValue, ingredients);
    }

    private int mixColors(int weight, int color1, int color2){

        if(weight == 0){
            return color2;
        }

        int color1_a = (color1 & 0xff000000) >> 24;
        int color1_r = (color1 & 0x00ff0000) >> 16;
        int color1_g = (color1 & 0x0000ff00) >> 8;
        int color1_b = color1 & 0x000000ff;

        int color2_a = (color2 & 0xff000000) >> 24;
        int color2_r = (color2 & 0x00ff0000) >> 16;
        int color2_g = (color2 & 0x0000ff00) >> 8;
        int color2_b = color2 & 0x000000ff;

        int result_a = color2_a;
        int result_r = color2_r;
        int result_g = color2_g;
        int result_b = color2_b;

        for(int i = 0; i < weight; i++){
            result_a = (result_a + color1_a)/2;
            result_r = (result_r + color1_r)/2;
            result_g = (result_g + color1_g)/2;
            result_b = (result_b + color1_b)/2;
        }
        result_a = result_a << 24;
        result_r = result_r << 16;
        result_g = result_g << 8;

        return result_a + result_r + result_g + result_b;
    }
}

 

Edited November 14, 2020 by Jipthechip
  • Quote

Share this post


Link to post
Share on other sites

Draco18s    2407

Draco18s

Draco18s    2407

  • Reality Controller
  • Draco18s
  • Members
  • 2407
  • 15945 posts
Posted November 14, 2020

That means that the TE data wasn't sync'd to the client. Server has no fucking clue about color and your client-side TE doesn't know diddly about the server side copy.

  • Quote

Apparently I'm a complete and utter jerk and come to this forum just like to make fun of people, be confrontational, and make your personal life miserable.  If you think this is the case, JUST REPORT ME.  Otherwise you're just going to get reported when you reply to my posts and point it out, because odds are, I was trying to be nice.

 

Exception: If you do not understand Java, I WILL NOT HELP YOU and your thread will get locked.

 

DO NOT PM ME WITH PROBLEMS. No help will be given.

Share this post


Link to post
Share on other sites

Jipthechip    0

Jipthechip

Jipthechip    0

  • Tree Puncher
  • Jipthechip
  • Members
  • 0
  • 27 posts
Posted November 14, 2020
18 minutes ago, poopoodice said:

May not be the problem but are you clearing the data and mark it dirty in the constructor?

Tried that, no luck.

  • Quote

Share this post


Link to post
Share on other sites

Jipthechip    0

Jipthechip

Jipthechip    0

  • Tree Puncher
  • Jipthechip
  • Members
  • 0
  • 27 posts
Posted November 14, 2020
2 minutes ago, Draco18s said:

That means that the TE data wasn't sync'd to the client. Server has no fucking clue about color and your client-side TE doesn't know diddly about the server side copy.

So you're saying that the NBT data is being written and the server has it, but the client for some reason isn't receiving it when the chunk is loaded? If so, how do I make sure that the client and server are synchronized?

  • Quote

Share this post


Link to post
Share on other sites

ChampionAsh5357    162

ChampionAsh5357

ChampionAsh5357    162

  • World Shaper
  • ChampionAsh5357
  • Members
  • 162
  • 1024 posts
Posted November 14, 2020
18 minutes ago, Jipthechip said:

because I have an IBlockColor class setting the color of one of the submodels of the TileEntity

Aha! So you are doing a bit of an assumption. The data is still present on the server as it should be; however, whenever the chunk is reloaded, you need to sync the value back to the client. Please see this section.

  • Quote

Share this post


Link to post
Share on other sites

Jipthechip    0

Jipthechip

Jipthechip    0

  • Tree Puncher
  • Jipthechip
  • Members
  • 0
  • 27 posts
Posted November 14, 2020 (edited)
43 minutes ago, ChampionAsh5357 said:

Aha! So you are doing a bit of an assumption. The data is still present on the server as it should be; however, whenever the chunk is reloaded, you need to sync the value back to the client. Please see this section.

Ohhh ok that makes a lot of sense now. I didn't think I'd need to learn about packets so soon, but I guess I have no choice now.

 

But there's one thing I'm still confused about. So I'm guessing write() is a function that is called serverside to save the NBT data whenever the server decides to save the chunk that the TileEntity is in. But when is read() called? When I was testing, it was called at seemingly random times and I'm still confused where it fits in.

Edited November 14, 2020 by Jipthechip
  • Quote

Share this post


Link to post
Share on other sites

ChampionAsh5357    162

ChampionAsh5357

ChampionAsh5357    162

  • World Shaper
  • ChampionAsh5357
  • Members
  • 162
  • 1024 posts
Posted November 14, 2020
4 minutes ago, Jipthechip said:

But when is read() called?

It's called whenever a te is loaded. Sometimes it's also called whenever synchronizing from server to client.

  • Quote

Share this post


Link to post
Share on other sites

Jipthechip    0

Jipthechip

Jipthechip    0

  • Tree Puncher
  • Jipthechip
  • Members
  • 0
  • 27 posts
Posted November 14, 2020
4 minutes ago, ChampionAsh5357 said:

It's called whenever a te is loaded. Sometimes it's also called whenever synchronizing from server to client.

During testing I noticed it usually wasn't being called when I loaded in my TileEntity, so I'm assuming the client has to tell the server it needs the data, then the server calls read() and sends the data to the client?

  • Quote

Share this post


Link to post
Share on other sites

ChampionAsh5357    162

ChampionAsh5357

ChampionAsh5357    162

  • World Shaper
  • ChampionAsh5357
  • Members
  • 162
  • 1024 posts
Posted November 14, 2020
Just now, Jipthechip said:

During testing I noticed it usually wasn't being called when I loaded in my TileEntity, so I'm assuming the client has to tell the server it needs the data, then the server calls read() and sends the data to the client?

For the client yes, the server will grab the data when initially loaded if I'm not mistaken.

  • Quote

Share this post


Link to post
Share on other sites

diesieben07    7618

diesieben07

diesieben07    7618

  • Reality Controller
  • diesieben07
  • Forum Team
  • 7618
  • 55237 posts
Posted November 14, 2020

This is how the client syncing works (from an old post of mine):

On 1/9/2018 at 10:29 PM, diesieben07 said:
  • getUpdateTag - Returns the data that should be sent to the client on initial chunk load (i.e. when it gets into render distance, etc.). Call super here and put whatever data you need to have available on the client in the NBTTagCompound returned from super. Then return it.
  • handleUpdateTag - Called on the client with whatever tag was returned from getUpdateTag. By default this calls readFromNbt, which is a terrible default, but oh well.
  • getUpdatePacket - Called to produce a subsequent update packet. You should return a SPacketUpdateTileEntity here if you need the data on the client to be updated from time to time. In theory you can return a partial update here, but usually it is best to just call getUpdateTag and pass that NBTTagCompound to the packet. The int parameter of the packet constructor can be set to whatever unsigned byte you like best.
  • onDataPacket - Called on the client when the packet produced by getUpdatePacket is received. Usually you just need to call handleUpdateTag with the NBT data from the packet (SPacketUpdateTileEntity::getNbtCompound).
  • Quote

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  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.

    • Insert image from URL
×
  • Desktop
  • Tablet
  • Phone
Sign in to follow this  
Followers 1
Go To Topic Listing



  • Recently Browsing

    No registered users viewing this page.

  • Posts

    • diesieben07
      Unable to install forge 1.16.5

      By diesieben07 · Posted 34 minutes ago

      Do not extract it. It is not an archive.   Some zip managers like to take control of the .jar file extension away from Java. Make sure you have Java installed and try running Jarfix once, then try the installer again.
    • gtf7dvygiduivtd
      I have a crash message with error code: 0

      By gtf7dvygiduivtd · Posted 57 minutes ago

      it only happens in 1.15+   logs.txt
    • IchBinEinToast
      Task :runClient FAILED | FAILURE: Build failed with an exception.

      By IchBinEinToast · Posted 1 hour ago

      Oh I solved it  Thank you @diesieben07
    • domi0908
      fix hitbox red baby mobs version forge

      By domi0908 · Posted 1 hour ago

      fix bug 
    • Tavi007
      Need help with modifying some vanilla rendering [1.16.4]

      By Tavi007 · Posted 1 hour ago

      Hello! I'm modifying the damage calculation by subscribing to LivingHurtEvent and scaling the damage value. This works fine, but now I also want to change the rendering a bit. My current LivingHurtEvent looks like this (I removed some unnecessary stuff) @SubscribeEvent public static void elementifyLivingHurtEvent(LivingHurtEvent event) { // compute new damage value .... // heals the target, if damage is lower than 0. This can happen with my modification if(damageAmount <= 0) { target.heal(-damageAmount); event.setCanceled(true); //does this even do something? damageAmount = 0; } event.setAmount(damageAmount); }   1. I want to change the red texture (an OverlayTexture?) to a green one, if the targets is healed. But I don't really know, where I should start with this task. I couldn't even find the code, that applies the red texture. So which Event do I need to hook in, so I can change this texture? Is it RenderLivingEvent? I also would like to read the vanilla code. I'm assuming, that the red overlayTexture is applied as long as hurttime>0, and that I might need to work around this with capabilities. 2. I also would like to reduce the screen shake (or at least disable it, when no damage has been dealt). Here I got the same question as 1. As you can see, I'm not really experienced with all the render stuff. It's my first time working with it.   3. Not really a question about rendering, but I didn't want to create a new thread for a single problem. I would also like to prevent the hurt-sound from firing, if no damage has been dealt and instead play another sound. Again I have no idea, where I would have to start looking in the vanilla code or which event I should use.   So yeah, I'm quite clueless and I hope you can help me out. Here is my repository, if you need more informations: https://github.com/Tavi007/ElementalCombat
  • Topics

    • Tyrone117
      3
      Unable to install forge 1.16.5

      By Tyrone117
      Started 10 hours ago

    • gtf7dvygiduivtd
      0
      I have a crash message with error code: 0

      By gtf7dvygiduivtd
      Started 53 minutes ago

    • IchBinEinToast
      5
      Task :runClient FAILED | FAILURE: Build failed with an exception.

      By IchBinEinToast
      Started 2 hours ago

    • domi0908
      1
      fix hitbox red baby mobs version forge

      By domi0908
      Started 22 hours ago

    • Tavi007
      0
      Need help with modifying some vanilla rendering [1.16.4]

      By Tavi007
      Started 1 hour ago

  • Who's Online (See full list)

    • Ottercorn
    • Zemelua
    • GGanze
    • VelioK
    • Tavi007
    • diesieben07
    • AzizD
    • PacketNarc
  • All Activity
  • Home
  • Mod Developer Central
  • Modder Support
  • [1.6.4] Confusion on Reading and Writing TileEntity data to the world
  • Theme

Copyright © 2019 ForgeDevelopment LLC · Ads by Longitude Ads LLC Powered by Invision Community