Jump to content

Recommended Posts

Posted

Hello. I am currently writing a mod which includes pipes.

My pipes have a tree-like structure, with one root node to which all pipes directly point. The root node saves all data (which pipes are connected, which machines are adjacent, ...)

To save the current state of the pipes and keep it even when reopening the world, I saved all the data to an NBT tag:

@Nonnull
@Override
public NBTTagCompound writeToNBT(@Nonnull final NBTTagCompound compound) {
    if (!world.isRemote) {
		if (network != null) {
			NBTTagCompound networkTag = new NBTTagCompound();
			networkTag.setTag("root", NBTHelper.writeBlockPosToTag(network.getRoot().getPos()));
			if (this.equals(network.getRoot())) {
				networkTag.setTag("data", network.rootCompound());
			}
			compound.setTag("network", networkTag);
			System.out.println("wrote " + compound);
		}
	}
	return super.writeToNBT(compound);
}

Which works:

wrote {network:{data:{moduleList:[],pipeList:[{a:{x:194,y:64,z:167},b:{x:194,y:64,z:168}},{a:{x:194,y:64,z:168},b:{x:194,y:64,z:169}}]},root:{x:194,y:64,z:167}}}

 

Now I want to read this data and re-create the network:

@Override
public void readFromNBT(@Nonnull final NBTTagCompound compound) {
	if (!world.isRemote()) {
		if (compound.hasKey("network")) {
			System.out.println("read " + compound);
			NBTTagCompound networkTag = compound.getCompoundTag("network");
			NBTTagCompound networkRootTag = networkTag.getCompoundTag("root");
          
			BlockPos rootPos = NBTHelper.readTagToBlockPos(networkRootTag);
			TileEntity root = world.getTileEntity(rootPos);
          
          	// ...

		}
		super.readFromNBT(compound);
	}
}

 

However, this throws an NPE because world seems to be null when the nbt is read. I also tried those methods:

System.out.println(getWorld() == null); // true
System.out.println(world == null); // true
System.out.println(Minecraft.getMinecraft().world == null); // true
System.out.println(FMLClientHandler.instance().getWorldClient() == null); // true and should be for client only anyways

 

My first idea to fix this was to override setWorld() and call the readFromNBT method when the world is set, but that seems a bit weird. What am I missing?

 

Thanks for any help in advance :)

Posted

Okay, so as I just found out there is a TileEntity#create(World, NBTTagCompound) static method which should do what I want.

 

But how do override it? How do I make my TE class known to the create method?

Posted
8 minutes ago, scrouthtv said:

But how do override it?

You cannot override static methods, that is basic Java, it doesn't make any sense.

It's sad how much time mods spend saying "x is no longer supported on this forum. Please update to a modern version of Minecraft to receive support".

Posted (edited)
3 minutes ago, scrouthtv said:

That's the reason I asked

That method cannot be what you're looking for, it's static and you can't override static methods, look for another method.

Edited by Novârch

It's sad how much time mods spend saying "x is no longer supported on this forum. Please update to a modern version of Minecraft to receive support".

Posted (edited)

Okay I halfway fixed it:

 

The method is exactly what I'm looking for. I just don't have to override, but use it. It reads the id from the nbt data and instantiates a new TileEntity with the id as ResourceLocation. 

 

net.minecraft.tileentity.TileEntity:

@Nullable
public static TileEntity create(World worldIn, NBTTagCompound compound) {
	String s = compound.getString("id");
	Class <? extends TileEntity > oclass = null;
	oclass = (Class)REGISTRY.getObject(new ResourceLocation(s));
	tileentity = oclass.newInstance();
	// ...
	tileentity.setWorldCreate(worldIn);
	tileentity.readFromNBT(compound);
	// ...
	return tileentity;
}

 

The only thing I still have to do is figure out what #setWorldCreate means, since there is 0 documentation on it.

 

I think I will simply override setWorldCreate in my TE and use that world to do everything.

Edited by scrouthtv
Posted (edited)

You are not supposed to access the World in readFromNBT. The world is can be uninitialized at that time.

Like the name suggests, you should only read data from NBT during that time.

If you want to get another tile entity during initialization, you can make it a lazy value and initialize (when first used/first tick in world depending on how you want to use it) based on the BlockPos (which is read from NBT).

Edited by DavidM
  • Like 1

Some tips:

Spoiler

Modder Support:

Spoiler

1. Do not follow tutorials on YouTube, especially TechnoVision (previously called Loremaster) and HarryTalks, due to their promotion of bad practice and usage of outdated code.

2. Always post your code.

3. Never copy and paste code. You won't learn anything from doing that.

4. 

Quote

Programming via Eclipse's hotfixes will get you nowhere

5. Learn to use your IDE, especially the debugger.

6.

Quote

The "picture that's worth 1000 words" only works if there's an obvious problem or a freehand red circle around it.

Support & Bug Reports:

Spoiler

1. Read the EAQ before asking for help. Remember to provide the appropriate log(s).

2. Versions below 1.11 are no longer supported due to their age. Update to a modern version of Minecraft to receive support.

 

 

  • scrouthtv changed the title to [SOLVED] [1.12.2] world is null when reading NBT
  • Guest locked this topic
Guest
This topic is now closed to further replies.

Announcements



×
×
  • Create New...

Important Information

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