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    160

ChampionAsh5357

ChampionAsh5357    160

  • World Shaper
  • ChampionAsh5357
  • Members
  • 160
  • 1019 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    113

poopoodice

poopoodice    113

  • Dragon Slayer
  • poopoodice
  • Members
  • 113
  • 896 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    2405

Draco18s

Draco18s    2405

  • Reality Controller
  • Draco18s
  • Members
  • 2405
  • 15930 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    160

ChampionAsh5357

ChampionAsh5357    160

  • World Shaper
  • ChampionAsh5357
  • Members
  • 160
  • 1019 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    160

ChampionAsh5357

ChampionAsh5357    160

  • World Shaper
  • ChampionAsh5357
  • Members
  • 160
  • 1019 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    160

ChampionAsh5357

ChampionAsh5357    160

  • World Shaper
  • ChampionAsh5357
  • Members
  • 160
  • 1019 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    7597

diesieben07

diesieben07    7597

  • Reality Controller
  • diesieben07
  • Forum Team
  • 7597
  • 55115 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

    • Potatoe
      Minecraft server

      By Potatoe · Posted 13 minutes ago

      ok
    • diesieben07
      Minecraft server

      By diesieben07 · Posted 17 minutes ago

      This is a Forum for Forge, I would suggest you seek help elsewhere for Vanilla Minecraft.
    • Luis_ST
      [1.16.5] Player Field of View

      By Luis_ST · Posted 23 minutes ago

      In that second I found out for myself but thanks
    • diesieben07
      [1.16.5] Player Field of View

      By diesieben07 · Posted 27 minutes ago

      getUseDuration needs to return a value > 0 for setActiveHand to work. By default it returns 0.
    • Potatoe
      Minecraft server

      By Potatoe · Posted 30 minutes ago

      Vanilla server...  
  • Topics

    • Potatoe
      4
      Minecraft server

      By Potatoe
      Started Sunday at 10:13 AM

    • Luis_ST
      4
      [1.16.5] Player Field of View

      By Luis_ST
      Started 1 hour ago

    • Klarks
      29
      [1.16.4] what difference between custom slots and EquipmentSlotType

      By Klarks
      Started Yesterday at 06:22 AM

    • tuskiomi
      11
      Forge *needs* to save textures after stitching them

      By tuskiomi
      Started March 24, 2020

    • awsfte6
      1
      core mod crash 1.7.10 JRMCore

      By awsfte6
      Started 1 hour ago

  • Who's Online (See full list)

    • hendrik
    • diesieben07
    • Novârch
    • squidlex
    • JoppeGames3
    • Luis_ST
  • 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