Jump to content
View in the app

A better way to browse. Learn more.

Forge Forums

A full-screen app on your home screen with push notifications, badges and more.

To install this app on iOS and iPadOS
  1. Tap the Share icon in Safari
  2. Scroll the menu and tap Add to Home Screen.
  3. Tap Add in the top-right corner.
To install this app on Android
  1. Tap the 3-dot menu (⋮) in the top-right corner of the browser.
  2. Tap Add to Home screen or Install app.
  3. Confirm by tapping Install.

Featured Replies

Posted

Hey guys,

I am trying to save a custom class in my tile entity`s NBT data.

I think I figured out how to save it, but I don't know how to load it.

 

Ingame Server class (Class that should be saved to nbt)

Spoiler
public class Server implements INBTSerializable {

    public enum ServerType{
        CUSTOM
    }

    private boolean isOn = false;
    private ServerType serverType;
    private String ip;
    private BlockPos pos;
    private Database db;

    public Server(ServerType serverType, String ip, BlockPos pos, Database db){
        this.serverType = serverType;
        this.ip = ip;
        this.pos = pos;
        this.db = db;
    }
  
    @Override
    public INBT serializeNBT() {
        CompoundNBT nbt = new CompoundNBT();

        nbt.putBoolean("isOn", this.isOn);
        nbt.putInt("serverType", this.serverType.ordinal());
        nbt.putString("ip", this.ip);
        nbt.put("pos", NBTUtil.writeBlockPos(this.pos));
        nbt.put("db", this.db.serializeNBT());

        return nbt;
    }

    @Override
    public void deserializeNBT(INBT compound) {
        CompoundNBT nbt = (CompoundNBT) compound;

        this.isOn = nbt.getBoolean("isOn");
        this.serverType = ServerType.values()[nbt.getInt("")];
        this.ip = nbt.getString("name");
        this.pos = NBTUtil.readBlockPos(nbt);
        this.db = (Database) nbt.get("db");
    }

 

 

My tile entity class

Spoiler
public class ServerTile extends TileEntity {

    private Server server;

    public ServerTile(TileEntityType<?> tileEntityType) {
        super(tileEntityType);
    }

    public ServerTile(){
        this(ModTileEntities.SERVER_TILE.get());
    }


    @Override
    public void read(BlockState state, CompoundNBT nbt) {

        this.server = ...

        super.read(state, nbt);
    }

    @Override
    public CompoundNBT write(CompoundNBT nbt) {
        nbt.put("server", this.server.serializeNBT());

        return super.write(nbt);
    }

 

 

Thanks for your help :)

you can create a constructor with a CompoundNBT as parameter, inside the constructor you read the data and set the fields
in this case your fields can be final (if you want that they are), then you can simply create a new instance
the other option would be to add an empty constructor and then call Server#serializeNBT

i personally prefer the first option but you could choose the option you want
i would also recommend you to specify the INBT type in the type arguments of INBTSerializable

last but not least i would recommend you to update to 1.18 since 1.16.5 will fall out of support in the next 2-3 days

Edited by Luis_ST

  • Author
Quote

This doesn't look right.

Thanks. I forgot to add the key ^^

 

Quote

INBTSerializable only really works if you have a no-argument constructor, so you can create the instance. I would recommend to instead make a static factory method and not use INBTSerializable.

Do you have an example?

5 minutes ago, J3ramy said:

Do you have an example?

Spoiler
	public void save() {
		Foo foo = new Foo(10);
		CompoundTag tag = foo.serializeNBT();
		// do stuff
	}
	
	public void load(CompoundTag tag) {
		Foo foo = new Foo();
		foo.deserializeNBT(tag);
	}
	
	public class Foo implements INBTSerializable<CompoundTag> {
		
		protected int data;
		
		public Foo() {
			
		}
		
		public Foo(int data) {
			this.data = data;
		}
		
		@Override
		public CompoundTag serializeNBT() {
			CompoundTag tag = new CompoundTag();
			tag.putInt("data", this.data);
			return tag;
		}

		@Override
		public void deserializeNBT(CompoundTag tag) {
			this.data = tag.getInt("data");
		}
		
	}

this is a simply example, but i would recommend to use a factory method or a constructor instead

Note: create with mojang mappings

  • Author

Thank you.

 

I decided for the constructor way and changed the class to

Spoiler

public class Server {

    public enum ServerType{
        CUSTOM
    }

    private boolean isOn = false;
    private boolean isSet = false;
    private final ServerType serverType;
    private final String ip;
    private final BlockPos pos;
    private final Database db;

    public Server(CompoundNBT nbt){
        this.isOn = nbt.getBoolean("isOn");
        this.isSet = nbt.getBoolean("isSet");
        this.serverType = ServerType.valueOf(nbt.getString("serverType"));
        this.ip = nbt.getString("name");
        this.pos = NBTUtil.readBlockPos(nbt);
        this.db = (Database) nbt.get("db");
    }

}

 

But how am I supposed to save/load this in the tile entity write and read method?

 

EDIT:

I created a getData method in Server which returns a CompoundNBT containing the class data.

Now, I do this in my tile entity:

Spoiler
 @Override
    public void read(BlockState state, CompoundNBT nbt) {

        this.server = new Server(nbt);

        super.read(state, nbt);
    }

    @Override
    public CompoundNBT write(CompoundNBT nbt) {

        nbt.put("server", this.server.getData());

        return super.write(nbt);
    }

 

 

Edited by J3ramy

   public void read(BlockState state, CompoundNBT nbt) {

        this.server = new Server(nbt.getCompound("server");

        super.read(state, nbt);
    }

You need to retrieve the subtag of the tile's nbt. The place where you put it.

 

The read/write happens automatically. Except, if you change data for the tile, you need to call setChanged() so minecraft knows it needs to save it.

Edited by warjort

Boilerplate:

If you don't post your logs/debug.log we can't help you. For curseforge you need to enable the forge debug.log in its minecraft settings. You should also post your crash report if you have one.

If there is no error in the log file and you don't have a crash report then post the launcher_log.txt from the minecraft folder. Again for curseforge this will be in your curseforge/minecraft/Install

Large files should be posted to a file sharing site like https://gist.github.com  You should also read the support forum sticky post.

Quote

Except, if you change data for the tile, you need to call setChanged() so minecraft knows it needs to save it.

This also notifies neighbouring blocks they may need to do stuff.

e.g. if you output a redstone signal any redstone would recalculate its signal strength.

Edited by warjort

Boilerplate:

If you don't post your logs/debug.log we can't help you. For curseforge you need to enable the forge debug.log in its minecraft settings. You should also post your crash report if you have one.

If there is no error in the log file and you don't have a crash report then post the launcher_log.txt from the minecraft folder. Again for curseforge this will be in your curseforge/minecraft/Install

Large files should be posted to a file sharing site like https://gist.github.com  You should also read the support forum sticky post.

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...

Important Information

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

Configure browser push notifications

Chrome (Android)
  1. Tap the lock icon next to the address bar.
  2. Tap Permissions → Notifications.
  3. Adjust your preference.
Chrome (Desktop)
  1. Click the padlock icon in the address bar.
  2. Select Site settings.
  3. Find Notifications and adjust your preference.