Jump to content

[1.11.2] Using WorldSavedData


lukas2005

Recommended Posts

Hello i want to save some data to world and i have the WorldSavedData implementation but i am not sure what i shloud fill in those functions and how to add data docs are not really too clear about that all they say is "The existing data can be obtained using MapStorage#getOrLoadData, and new data can be attached using MapStorage#setData". Wich does not really tell me much i have this code:

package io.github.lukas2005.spymod;

import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.world.World;
import net.minecraft.world.WorldSavedData;
import net.minecraft.world.storage.MapStorage;

public class MyWorldSavedData extends WorldSavedData {
	private static final String DATA_NAME = Reference.MOD_ID + "_MyWorldSavedData";
	
	
	public MyWorldSavedData() {
		super(DATA_NAME);
	}


	@Override
	public void readFromNBT(NBTTagCompound nbt) {
	}


	@Override
	public NBTTagCompound writeToNBT(NBTTagCompound compound) {
		return null;
	}

	public static MyWorldSavedData get(World world) {
		MapStorage storage = world.getMapStorage();
		MyWorldSavedData instance = (MyWorldSavedData) storage.getOrLoadData(MyWorldSavedData.class, DATA_NAME);

		if (instance == null) {
			instance = new MyWorldSavedData();
			storage.setData(DATA_NAME, instance);
		}
		return instance;
	}	

}

 

Link to comment
Share on other sites

You mean readFromNBT and writeToNBT? That's simple.

readFromNBT: read from nbt to fill up the fields of WorldSavedData.

writeToNBT: write to nbt with the fields of WorldSavedData.

 

So basically, you save your fields to NBT using writeToNBT, and load it later using readFromNBT.

I. Stellarium for Minecraft: Configurable Universe for Minecraft! (WIP)

II. Stellar Sky, Better Star Rendering&Sky Utility mod, had separated from Stellarium.

Link to comment
Share on other sites

Ok now i have those classes now the only thing i am wondering about is to where but markDirty calls. The goal is to make a hashmap of all cameras in all dimensions in world that is synced to all clients and server and is saved to world file

MyWorldSavedData:

package io.github.lukas2005.spymod;

import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import net.minecraft.world.World;
import net.minecraft.world.WorldSavedData;
import net.minecraft.world.storage.MapStorage;

public class MyWorldSavedData extends WorldSavedData {
	private static final String DATA_NAME = Reference.MOD_ID + "_MyWorldSavedData";
	
	
	public MyWorldSavedData() {
		super(DATA_NAME);
	}


	@Override
	public void readFromNBT(NBTTagCompound nbt) {
		Camera.REGISTRY.clear();
		NBTTagList list = (NBTTagList) nbt.getTag("CameraRegistry");
		for (int i=0;i < list.tagCount();i++) {
			NBTTagCompound camnbt = (NBTTagCompound) list.get(0);
			Camera.registerCamera(new Camera(camnbt.getUniqueId("UUID")).readFromNBT(camnbt));
		}
	}


	@Override
	public NBTTagCompound writeToNBT(NBTTagCompound nbt) {
		NBTTagList list = new NBTTagList(); 
		for (Camera cam : Camera.REGISTRY.values()) {
			NBTTagCompound camnbt = new NBTTagCompound();
			camnbt.setUniqueId("UUID", cam.getUUID());
			cam.writeToNBT(camnbt);
			list.appendTag(camnbt);
		}
		nbt.setTag("CameraRegistry", list);
		Camera.REGISTRY.clear();
		return nbt;
	}

	public static MyWorldSavedData get(World world) {
		MapStorage storage = world.getMapStorage();
		MyWorldSavedData instance = (MyWorldSavedData) storage.getOrLoadData(MyWorldSavedData.class, DATA_NAME);

		if (instance == null) {
			instance = new MyWorldSavedData();
			storage.setData(DATA_NAME, instance);
		}
		return instance;
	}	

}

 

Camera:

package io.github.lukas2005.spymod;

import java.util.HashMap;
import java.util.UUID;

import io.github.lukas2005.spymod.Network.CameraRegistryChangeMessage;
import io.github.lukas2005.spymod.Network.CameraRegistryChangeMessage.Type;
import io.github.lukas2005.spymod.Network.NetworkManager;
import io.netty.buffer.ByteBuf;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraftforge.fml.common.network.ByteBufUtils;

public class Camera {

	public static HashMap<UUID, Camera> REGISTRY = new HashMap<UUID, Camera>();
	
	private final UUID uuid;
	private String name;
	private UUID attachment;
	
	public Camera() {
		this.uuid = UUID.randomUUID();
	}
	
	public Camera(UUID uuid) {
		this.uuid = uuid;
	}
	
	public Camera(UUID uuid, Object...data) {
		this.uuid = uuid;
		this.name = (String) data[0];
		this.attachment = (UUID) data[1];
	}
	
	public static Camera getCamera(UUID uuid) {
		return REGISTRY.get(uuid);
	}
	
	public static void registerCamera(Camera cam) {
		
		REGISTRY.put(cam.getUUID(), cam);
		NetworkManager.INSTANCE.sendToServer(new CameraRegistryChangeMessage(Type.ADD_CAMERA, cam.uuid));
		
	}

	public static void registerCameraNoUpdate(Camera cam) {
		
		REGISTRY.put(cam.getUUID(), cam);
		
	}
	
	public static void unRegisterCamera(Camera cam) {
		
		REGISTRY.remove(cam.getUUID());
		NetworkManager.INSTANCE.sendToServer(new CameraRegistryChangeMessage(Type.REMOVE_CAMERA, cam.uuid));
		
	}
	
	public static void unRegisterCameraNoUpdate(Camera cam) {
		
		REGISTRY.remove(cam.getUUID());
		
	}
	
	public static void unRegisterCamera(UUID cam) {
		
		REGISTRY.remove(cam);
		NetworkManager.INSTANCE.sendToServer(new CameraRegistryChangeMessage(Type.REMOVE_CAMERA, cam));
		
	}
	
	public static void unRegisterCameraNoUpdate(UUID cam) {
		
		REGISTRY.remove(cam);
		
	}
	
	public String getName() {
		return name;
	}

	public Camera setName(String name) {
		this.name = name;
		NetworkManager.INSTANCE.sendToServer(new CameraRegistryChangeMessage(Type.UPDATE_CAMERA, getUUID(), name, null));
		return this;
	}
	
	public Camera setNameNoUpdate(String name) {
		this.name = name;
		return this;
	}

	public UUID getAttachment() {
		return attachment;
	}

	public Camera setAttachment(UUID attachment) {
		this.attachment = attachment;
		NetworkManager.INSTANCE.sendToServer(new CameraRegistryChangeMessage(Type.UPDATE_CAMERA, getUUID(), null, attachment));
		return this;
	}

	public Camera setAttachmentNoUpdate(UUID attachment) {
		this.attachment = attachment;
		return this;
	}
	
	public UUID getUUID() {
		return uuid;
	}
	
	public Camera writeToNBT(NBTTagCompound nbt) {
		nbt.setString("Name", getName());
		nbt.setUniqueId("Attach", getAttachment());
		return this;
	}
	
	public Camera readFromNBT(NBTTagCompound nbt) {
		setName(nbt.getString("Name"));
		setAttachment(nbt.getUniqueId("Attach"));
		return this;
	}

	public void writeToByteBuf(ByteBuf buf) {
		ByteBufUtils.writeUTF8String(buf, getName()); // New camera name
		ByteBufUtils.writeUTF8String(buf, ((UUID)getAttachment()).toString()); 	
	}
	
	public Camera readFromByteBuf(ByteBuf buf) {
		setName(ByteBufUtils.readUTF8String(buf)); // New camera name
		setAttachment(UUID.fromString(ByteBufUtils.readUTF8String(buf))); //New camera block pos attachment
		return this;
	}
	
}

CameraRegistryChangeMessage:

package io.github.lukas2005.spymod.Network;

import java.util.UUID;

import io.github.lukas2005.spymod.Camera;
import io.netty.buffer.ByteBuf;
import net.minecraftforge.fml.common.network.ByteBufUtils;
import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
import net.minecraftforge.fml.common.network.simpleimpl.IMessageHandler;
import net.minecraftforge.fml.common.network.simpleimpl.MessageContext;

public class CameraRegistryChangeMessage implements IMessage {

	int type = 0;
	Type etype;
	Object[] data;
	
	public CameraRegistryChangeMessage() {}
	
	public CameraRegistryChangeMessage(Type type, Object...data) {
		switch(type) {
		case ADD_CAMERA:
			this.type = 0;
			break;
		case REMOVE_CAMERA:
			this.type = 1;
			break;
		case UPDATE_CAMERA:
			this.type = 2;
			break;
		}
		this.etype = type;
		this.data = data;
	}
	
	@Override
	public void fromBytes(ByteBuf buf) {
		switch(buf.readInt()) {
		case 0:
			this.etype = Type.ADD_CAMERA;
			data = new Object[1];
			data[0] = UUID.fromString(ByteBufUtils.readUTF8String(buf));
			break;
		case 1:
			this.etype = Type.REMOVE_CAMERA;
			data = new Object[1];
			data[0] = UUID.fromString(ByteBufUtils.readUTF8String(buf)); // UUID of camera to remove
			break;
		case 2:
			this.etype = Type.UPDATE_CAMERA;
			data = new Object[3];
			data[0] = UUID.fromString(ByteBufUtils.readUTF8String(buf));
			Camera cam = new Camera((UUID) data[0]).readFromByteBuf(buf);
			data[1] = cam.getName();
			data[2] = cam.getAttachment();
			break;
		}
	}

	@Override
	public void toBytes(ByteBuf buf) {
		buf.writeInt(type);
		switch(etype) {
		case ADD_CAMERA:
			ByteBufUtils.writeUTF8String(buf, ((UUID)data[0]).toString());
			break;
		case REMOVE_CAMERA:
			ByteBufUtils.writeUTF8String(buf, ((UUID)data[0]).toString());
			break;
		case UPDATE_CAMERA:
			ByteBufUtils.writeUTF8String(buf, ((UUID)data[0]).toString()); //UUID of camera to update
			new Camera((UUID)data[0], (String)data[1], data[2]).writeToByteBuf(buf);
			break;
		}
	}
	
	public static class Handler implements IMessageHandler<CameraRegistryChangeMessage, IMessage> {
		@Override
		public IMessage onMessage(final CameraRegistryChangeMessage message, MessageContext ctx) {	
			UUID uuid = (UUID)message.data[0];
			switch(message.etype) {
			case ADD_CAMERA:
				if (!Camera.REGISTRY.containsKey(uuid)) {
					Camera.registerCameraNoUpdate(new Camera(uuid));
				}
				break;
			case REMOVE_CAMERA:
				if (Camera.REGISTRY.containsKey(uuid)) {
					Camera.unRegisterCameraNoUpdate(uuid);
				}
				break;
			case UPDATE_CAMERA:
				if (Camera.REGISTRY.containsKey(uuid)) {
					String name = (String) message.data[1];
					UUID attachment = (UUID) message.data[2];
					Camera cam = Camera.REGISTRY.get(uuid);
					if (name != null) cam.setNameNoUpdate(name);
					if (attachment != null) cam.setAttachmentNoUpdate(attachment);
				}
				break;
			}
			NetworkManager.INSTANCE.sendToAll(message);
			return null;
		}
	}
	
	public static enum Type {
		
		ADD_CAMERA,
		REMOVE_CAMERA,
		UPDATE_CAMERA
		
	}
	
}

 

Link to comment
Share on other sites

18 minutes ago, lukas2005 said:

camnbt = (NBTTagCompound) list.get(0);

You got something wrong here. 0 seems to be i instead

Oh, and about markDirty, I forgot that! You should call it whereever you change WorldSavedData field value. In your case, it's whereever a camera changes.

I. Stellarium for Minecraft: Configurable Universe for Minecraft! (WIP)

II. Stellar Sky, Better Star Rendering&Sky Utility mod, had separated from Stellarium.

Link to comment
Share on other sites

2 minutes ago, lukas2005 said:

Ok one thing how shloud i get world instance from my Camera class?

You can't. If you really need it, provide it on WorldEvent.Load .

I. Stellarium for Minecraft: Configurable Universe for Minecraft! (WIP)

II. Stellar Sky, Better Star Rendering&Sky Utility mod, had separated from Stellarium.

Link to comment
Share on other sites

Interesting that the MySavedWorldData constructor can take no parameters. Forge complains when I try that.

 

What works for me is: Message sent from client -> Message received on Server -> onMessage calls a method in MySavedWorldData that updates your HashMap.

markDirty(); should be placed at the end of that last method.

Link to comment
Share on other sites

Strange. Would you update your code?

Just in case you don't know: markDirty calls should be on server side.

I. Stellarium for Minecraft: Configurable Universe for Minecraft! (WIP)

II. Stellar Sky, Better Star Rendering&Sky Utility mod, had separated from Stellarium.

Link to comment
Share on other sites

Don't remove it from all methods; just try putting it at the end of the method that updates your HashMap.

Edit: Oh well if you can call markDirty on the MyWorldSavedData instance from the message handler, then I think we should see your code as it is now

Edited by FredTargaryen
Link to comment
Share on other sites

1. For the worldsaveddata on map storage, you should only register it once(it's shared throughout worlds(. WorldEvent.Load is called every time the world is loaded, so you should find another event or check to allow only one world to load the data.

 Same for WorldEvent.Unload.

2. Why did you register the packet to both server and client? The logic should be on the server side. Client is only for the rendering and sending input to the server.

I. Stellarium for Minecraft: Configurable Universe for Minecraft! (WIP)

II. Stellar Sky, Better Star Rendering&Sky Utility mod, had separated from Stellarium.

Link to comment
Share on other sites

Just now, Abastro said:

2. Why did you register the packet to both server and client? The logic should be on the server side. Client is only for the rendering and sending input to the server.

Because i need data about cameras on both server and client

Link to comment
Share on other sites

1 minute ago, lukas2005 said:

Because i need data about cameras on both server and client

Just sync it from the server to the client, otherwise by editing client plauers could cheat.

Client to server packet is mostly for sending the user input to the server.

I. Stellarium for Minecraft: Configurable Universe for Minecraft! (WIP)

II. Stellar Sky, Better Star Rendering&Sky Utility mod, had separated from Stellarium.

Link to comment
Share on other sites

1. Don't reference Minecraft in the packet - it will crash on dedicated server.

2. Why bidirectional packet? No need to send it from client to server. Just move all non-rendeing logics to the server, and only send packet from client to server.

3. So you have the item ItemCamera to represent the camera. Why to have separate registry.

4. Certainly this is not the way to go; don't put the registry as WorldSavedData. Also don't make static reference of it. (It means it won't be loaded on time. Also WorldEvent are only called on server. So client-side one won't exist. Try running dedicated server to try this)

5. What's the supposed function of the camera and the monitor?

I. Stellarium for Minecraft: Configurable Universe for Minecraft! (WIP)

II. Stellar Sky, Better Star Rendering&Sky Utility mod, had separated from Stellarium.

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



  • Recently Browsing

    • No registered users viewing this page.
  • Posts

    • Hello everyone, I'm making this post to seek help for my modded block, It's a special block called FrozenBlock supposed to take the place of an old block, then after a set amount of ticks, it's supposed to revert its Block State, Entity, data... to the old block like this :  The problem I have is that the system breaks when handling multi blocks (I tried some fix but none of them worked) :  The bug I have identified is that the function "setOldBlockFields" in the item's "setFrozenBlock" function gets called once for the 1st block of multiblock getting frozen (as it should), but gets called a second time BEFORE creating the first FrozenBlock with the data of the 1st block, hence giving the same data to the two FrozenBlock :   Old Block Fields set BlockState : Block{minecraft:black_bed}[facing=east,occupied=false,part=head] BlockEntity : net.minecraft.world.level.block.entity.BedBlockEntity@73681674 BlockEntityData : id:"minecraft:bed",x:3,y:-60,z:-6} Old Block Fields set BlockState : Block{minecraft:black_bed}[facing=east,occupied=false,part=foot] BlockEntity : net.minecraft.world.level.block.entity.BedBlockEntity@6d1aa3da BlockEntityData : {id:"minecraft:bed",x:2,y:-60,z:-6} Frozen Block Entity set BlockState : Block{minecraft:black_bed}[facing=east,occupied=false,part=foot] BlockPos{x=3, y=-60, z=-6} BlockEntity : net.minecraft.world.level.block.entity.BedBlockEntity@6d1aa3da BlockEntityData : {id:"minecraft:bed",x:2,y:-60,z:-6} Frozen Block Entity set BlockState : Block{minecraft:black_bed}[facing=east,occupied=false,part=foot] BlockPos{x=2, y=-60, z=-6} BlockEntity : net.minecraft.world.level.block.entity.BedBlockEntity@6d1aa3da BlockEntityData : {id:"minecraft:bed",x:2,y:-60,z:-6} here is the code inside my custom "freeze" item :    @Override     public @NotNull InteractionResult useOn(@NotNull UseOnContext pContext) {         if (!pContext.getLevel().isClientSide() && pContext.getHand() == InteractionHand.MAIN_HAND) {             BlockPos blockPos = pContext.getClickedPos();             BlockPos secondBlockPos = getMultiblockPos(blockPos, pContext.getLevel().getBlockState(blockPos));             if (secondBlockPos != null) {                 createFrozenBlock(pContext, secondBlockPos);             }             createFrozenBlock(pContext, blockPos);             return InteractionResult.SUCCESS;         }         return super.useOn(pContext);     }     public static void createFrozenBlock(UseOnContext pContext, BlockPos blockPos) {         BlockState oldState = pContext.getLevel().getBlockState(blockPos);         BlockEntity oldBlockEntity = oldState.hasBlockEntity() ? pContext.getLevel().getBlockEntity(blockPos) : null;         CompoundTag oldBlockEntityData = oldState.hasBlockEntity() ? oldBlockEntity.serializeNBT() : null;         if (oldBlockEntity != null) {             pContext.getLevel().removeBlockEntity(blockPos);         }         BlockState FrozenBlock = setFrozenBlock(oldState, oldBlockEntity, oldBlockEntityData);         pContext.getLevel().setBlockAndUpdate(blockPos, FrozenBlock);     }     public static BlockState setFrozenBlock(BlockState blockState, @Nullable BlockEntity blockEntity, @Nullable CompoundTag blockEntityData) {         BlockState FrozenBlock = BlockRegister.FROZEN_BLOCK.get().defaultBlockState();         ((FrozenBlock) FrozenBlock.getBlock()).setOldBlockFields(blockState, blockEntity, blockEntityData);         return FrozenBlock;     }  
    • It is an issue with quark - update it to this build: https://www.curseforge.com/minecraft/mc-mods/quark/files/3642325
    • Remove Instant Massive Structures Mod from your server     Add new crash-reports with sites like https://paste.ee/  
    • Update your drivers: https://www.amd.com/en/support/graphics/amd-radeon-r9-series/amd-radeon-r9-200-series/amd-radeon-r9-280x
  • Topics

×
×
  • Create New...

Important Information

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