Jump to content

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


Jipthechip

Recommended Posts

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 by Jipthechip
Link to comment
Share on other sites

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 by Jipthechip
Link to comment
Share on other sites

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.

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.

Link to comment
Share on other sites

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?

Link to comment
Share on other sites

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.

Link to comment
Share on other sites

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 by Jipthechip
Link to comment
Share on other sites

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?

Link to comment
Share on other sites

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.

Link to comment
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.
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.