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

Hi there,

 

For my mod I want an inventory like an Ender Chest that is shared between all players. Whereever anyone is accessing this inventory it is the same.

In previous versions I did this by saving a "per world inventory" NBT to the world save file. Aditionally I want to save all positions of these "chests", so I always know where they are.

 

With saving the data I have some Issues:

1) My onWorldLoaded and onWorldSaved events do not get called, even though I registered them in my mod's constructor. (The onClientSetupEvent gets called, so I assume the basic setup is ok).

2) How do I store my NBT data to the world save file? In previous versions I used a class extending WorldSavedData. I looked at https://mcforge.readthedocs.io/en/latest/datastorage/worldsaveddata/. But I can't figure out why

MapStorage storage = world.getMapStorage();

does not work. It seems neither MapStorage nor getMapStorage() exist...

3) May be related to Problem 1): The WorldEvent.Load::getWorld only returns an IWorld. My old MySavedData::forWorld required a World. Is that a problem at all? If yes, where do I get my World from?

 

This is my main mod class (For demonstration purposes I stripped all unnecessary stuff like Blocks and Items, they are working fine):

package de.tetopia.question;

import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.world.World;
import net.minecraftforge.event.world.WorldEvent;
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

// The value here should match an entry in the META-INF/mods.toml file
@Mod(ModQuestion.MODID)
public class ModQuestion
{
    public static final String MODID = "questionmod";
	private static final Logger LOGGER = LogManager.getLogger();

    public ModQuestion() 
    {
    	FMLJavaModLoadingContext.get().getModEventBus().addListener(this::onClientSetupEvent);
    	FMLJavaModLoadingContext.get().getModEventBus().addListener(this::onWorldLoaded);
    	FMLJavaModLoadingContext.get().getModEventBus().addListener(this::onWorldSaved);
    }
    
    private void onClientSetupEvent(final FMLClientSetupEvent event) 
    {
    	LOGGER.debug("Hello from the Client Setup!");
    }
    
	public void onWorldLoaded(WorldEvent.Load event)
	{
		LOGGER.debug("Hello from World Loading!");
		
		World world = null; //Where do I get my world from? event.getWorld() returns an IWorld
		if (!world.isRemote()) 
		{
			//Get the data from the world save file
			CompoundNBT tag = new CompoundNBT();
			
			CompoundNBT tagCompound = new CompoundNBT();
			MySavedData saver = MySavedData.forWorld(world);
			tag = saver.data;
			
			if(tagCompound.contains("MyTagName"))
			{
				//Do Stuff with the data
			}
		}
	}
	
	public void onWorldSaved(WorldEvent.Save event)
	{
		LOGGER.debug("Hello from World Saving!");
		
		World world = null; //Where do I get my world from? event.getWorld() returns an IWorld
		
		if (!world.isRemote())
		{
			CompoundNBT dataToSave = new CompoundNBT();
			
			//Store some data in dataToSave
			//dataToSave.put("MyTagName", ...);
					
			MySavedData saver = MySavedData.forWorld(world);
			saver.data = dataToSave;
			saver.markDirty();
		}
	}
}

 

And this is my custom WorldSavedData class:

package de.tetopia.question;

import net.minecraft.nbt.CompoundNBT;
import net.minecraft.world.World;
import net.minecraft.world.storage.WorldSavedData;

public class MySavedData extends WorldSavedData
{
	public CompoundNBT data = new CompoundNBT();
	
	public MySavedData()
	{
		super(ModQuestion.MODID);
	}
	
	public MySavedData(String name)
	{
		super(name);
	}

	@Override
	public void read(CompoundNBT nbt)
	{
		data = nbt.getCompound("MyTagName");
	}

	@Override
	public CompoundNBT write(CompoundNBT nbt)
	{
		nbt.put("MyTagName", data);
		return nbt;
	}
	
	public static MySavedData forWorld(World world)
	{
		MapStorage storage = world.getMapStorage(); //PROBLEM: What is the 1.15 way of doing this?
		MySavedData saver = (MySavedData) storage.getOrLoadData(MySavedData.class, ModQuestion.MODID);

		if (saver == null) 
		{
			saver = new MySavedData();
			storage.setData(ModQuestion.MODID, saver);
		}
		return saver;
	}
}

 

Edited by Roxane
Solved Issue

7 minutes ago, Roxane said:

FMLJavaModLoadingContext.get().getModEventBus().addListener(this::onWorldLoaded); FMLJavaModLoadingContext.get().getModEventBus().addListener(this::onWorldSaved);

The WorldEvent.Load and WorldEvent.Save do not fire on the mod event bus. They instead fire on the MinecraftForge.EVENT_BUS. The mod event bus is only for life-cycle events such as FMLCommonSetupEvent.

 

10 minutes ago, Roxane said:

But I can't figure out why

It seems to have been renamed to World::getMapData or ServerWorld::getSavedData()::getOrCreate

 

At the moment I'm not fully aware of how the WorldSavedData system has changed, however you can use a Capability that is attached to the World.

13 minutes ago, Roxane said:

If yes, where do I get my World from?

instanceof and cast.

VANILLA MINECRAFT CLASSES ARE THE BEST RESOURCES WHEN MODDING

I will be posting 1.15.2 modding tutorials on this channel. If you want to be notified of it do the normal YouTube stuff like subscribing, ect.

Forge and vanilla BlockState generator.

  • Author
21 minutes ago, Animefan8888 said:

The WorldEvent.Load and WorldEvent.Save do not fire on the mod event bus. They instead fire on the MinecraftForge.EVENT_BUS. The mod event bus is only for life-cycle events such as FMLCommonSetupEvent.

Thanks! Calling "MinecraftForge.EVENT_BUS.addListener(this::onWorldLoaded);" did the trick ?

 

21 minutes ago, Animefan8888 said:

It seems to have been renamed to World::getMapData or ServerWorld::getSavedData()::getOrCreate

Hmm... I can't find the World::getMapData. And ServerWorld::getSavedData()::getOrCreate want's a Supplier <T> as parameter. Where do I get that from?

 

21 minutes ago, Animefan8888 said:

however you can use a Capability that is attached to the World.

Thanks for that tip, I'll look into that direction.

 

 

 

Edited by Roxane

2 minutes ago, Roxane said:

Where do I get that from?

You create one. A Supplier is just a functional interface that returns an instance of type T. In this case I believe it would be an instance of your WorldSavedData class.

 

3 minutes ago, Roxane said:

Is it only the Capability you mentioned? Or is there something else?

It's the only forge provided way of doing it yes. There's three ways to do this. WorldSavedData(which has apparently changed a little bit), Capabilities(which to my knowledge are still the same as when they were first introduced), and of course you can write the file to disk yourself(not really the best option because the first two already exist).

VANILLA MINECRAFT CLASSES ARE THE BEST RESOURCES WHEN MODDING

I will be posting 1.15.2 modding tutorials on this channel. If you want to be notified of it do the normal YouTube stuff like subscribing, ect.

Forge and vanilla BlockState generator.

  • Author

Thank you very much! With your Information I could get it to work ?

 

For anybody interested, this is my code now.

Mod class:

import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.world.server.ServerWorld;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.event.world.WorldEvent;
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

// The value here should match an entry in the META-INF/mods.toml file
@Mod(ModQuestion.MODID)
public class ModQuestion
{
    public static final String MODID = "questionmod";
	private static final Logger LOGGER = LogManager.getLogger();

    public ModQuestion() 
    {
    	FMLJavaModLoadingContext.get().getModEventBus().addListener(this::onClientSetupEvent);
    	MinecraftForge.EVENT_BUS.addListener(this::onWorldLoaded);
    	MinecraftForge.EVENT_BUS.addListener(this::onWorldSaved);
    }
    
    private void onClientSetupEvent(final FMLClientSetupEvent event) 
    {
    	//LOGGER.debug("Hello from the Client Setup!");
    }
    
	public void onWorldLoaded(WorldEvent.Load event)
	{
		if (!event.getWorld().isRemote() && event.getWorld() instanceof ServerWorld)
		{
			MySavedData saver = MySavedData.forWorld((ServerWorld) event.getWorld());
   			
			if(saver.data.contains("MyData"))
			{
				LOGGER.debug("Found my data: " + saver.data.get("MyData"));
				//Do whatever you want to do with the data
			}
		}
	}
	
	public void onWorldSaved(WorldEvent.Save event)
	{
		if (!event.getWorld().isRemote() && event.getWorld() instanceof ServerWorld)
		{
			MySavedData saver = MySavedData.forWorld((ServerWorld) event.getWorld());
			CompoundNBT myData = new CompoundNBT();
			myData.putInt("MyData", 0); //Put in whatever you want with myData.put
			saver.data = myData;
			saver.markDirty();
			LOGGER.debug("Put my data in!");
		}
	}
}

 

WorldSaverData class:

import java.util.function.Supplier;

import net.minecraft.nbt.CompoundNBT;
import net.minecraft.world.server.ServerWorld;
import net.minecraft.world.storage.DimensionSavedDataManager;
import net.minecraft.world.storage.WorldSavedData;

public class MySavedData extends WorldSavedData implements Supplier
{
	public CompoundNBT data = new CompoundNBT();
	
	public MySavedData()
	{
		super(ModQuestion.MODID);
	}
	
	public MySavedData(String name)
	{
		super(name);
	}

	@Override
	public void read(CompoundNBT nbt)
	{
		data = nbt.getCompound("MyCompound");
	}

	@Override
	public CompoundNBT write(CompoundNBT nbt)
	{
		nbt.put("MyCompound", data);
		return nbt;
	}
	
	public static MySavedData forWorld(ServerWorld world)
	{
		DimensionSavedDataManager storage = world.getSavedData();
		Supplier<MySavedData> sup = new MySavedData();
		MySavedData saver = (MySavedData) storage.getOrCreate(sup, ModQuestion.MODID);

		if (saver == null) 
		{
			saver = new MySavedData();
			storage.set(saver);
		}
		return saver;
	}
	
	@Override
	public Object get()
	{
		return this;
	}
}

 

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.