Jump to content

Recommended Posts

Posted

Hi there!

In the mod I am working on there is a class (lowercase c) of items deemed 'legendary'.

In practice, this means they are utterly indestructible once created, and only one of them can ever exist in the game.

 

I've got this working to a degree - whenever an itemstack is created it checks whether it already exists by referring to a hashset in a serverside singleton. If not, it is created and puts itself in. If it is, it cancels its own creation.

 

Problem comes in when restarting the game: All data is gone (of course) because the singleton got recreated.

 

That leads me to my question: How can I write the hashset to permanent world data, and load it as well? Or is there a better way entirely to do what I am trying?

If anyone has a comprehensive, visual guide to GUIs - don't hesitate to message me. They make my head spin.

Posted

You can create a class extending WorldSavedData and add your information to that, though it sounds like you're creating new Item instances on the fly which is a big no-no (they need to be registered and all that during FML pre-init).

 

How will players receive these items? In chests? Because if you are, you can create the items beforehand and then control how they generate, e.g. by making a List of possible items and removing one at random each time a chest generates until none remain, and save the remaining contents (or lack thereof) in your world saved data class.

 

You may want to check out Draco's Artifacts mod (don't have the link atm) - it creates unique items using the ItemStack NBT and is really damn good at it.

Posted

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.

Posted

I'm not creating Item instances on the fly. Just making sure only one ItemStack can exist of each at any time. I want these items to be craftable, and the way I do it right now simply makes the recipe fail if an ItemStack (or EntityItem) of such already exists.

 

Because they are (virtually) indestructible, I figured this was a very easy way to do it.

If anyone has a comprehensive, visual guide to GUIs - don't hesitate to message me. They make my head spin.

  • 2 weeks later...
Posted

After ALOT of trying to find implementations of WorldSavedData extensions and coming up empty, I turn back to this topic. Mostly because I'm very sure I'm using it very wrongly.

 

import java.util.ArrayList;
import java.util.List;

import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import net.minecraft.world.WorldSavedData;

public class WorldDataHandler extends WorldSavedData {
public List<Item> itemUnique = new ArrayList<Item>();
private static final WorldDataHandler INSTANCE = new WorldDataHandler("");

private WorldDataHandler(String string) {
	super(string);
}

@Override
public void readFromNBT(NBTTagCompound nbt) {
	itemUnique = new ArrayList<Item>();
    NBTTagList list = nbt.getTagList("Items", 10);
    for (int i = 0; i < list.tagCount(); ++i) {
        NBTTagCompound stackTag = list.getCompoundTagAt(i);
        int slot = stackTag.getByte("Slot") & 255;
        itemUnique.add(ItemStack.loadItemStackFromNBT(stackTag).getItem());
    }
}
@Override
public void writeToNBT(NBTTagCompound nbt) {
	NBTTagList list = new NBTTagList();
    for (int i = 0; i < itemUnique.size(); ++i) {
    		NBTTagCompound stackTag = new NBTTagCompound();
    		stackTag.setByte("Slot", (byte) i);
         	new ItemStack(itemUnique.get(i),1).writeToNBT(stackTag);
            list.appendTag(stackTag);
    }
    nbt.setTag("UniqueItems", list);		
}

public boolean checkUnique(Item item, boolean doAdd){
	if (itemUnique.contains(item)) return false;
	if (doAdd) itemUnique.add(item);
	markDirty();
	return true;
}

public static WorldDataHandler getInstance(){
	return INSTANCE;
}
}

 

It works - within a session. That is, the data is stored and retrieved properly, but the NBT data is never accessed. Don't quite know how to trigger that.

Also, switching between saves of course doesn't clear that list.

 

In other words: I'm doing something majorly wrong and probably shouldn't even be attempting this. But I am anyway.

If anyone has a comprehensive, visual guide to GUIs - don't hesitate to message me. They make my head spin.

Posted

There's a little dance you have to do to make sure your extra data actually loads from the save file:

// where 'saveData' is an instance of YourSaveDataClass that extends WorldSavedData
/**
 * If saveData is null, it is loaded from world storage if available or a new one is created
 */
protected final void loadOrCreateData(World world) {
	if (saveData == null) {
		// where #getTagName() simply returns a unique name for your storage
		saveData = (YourSaveDataClass) world.getPerWorldStorage().loadData(YourSaveDataClass.class, getTagName());
		if (saveData == null) {
			saveData = new YourSaveDataClass(getTagName());
			world.getPerWorldStorage().setData(getTagName(), saveData );
		} else {
			// saveData should have all of its NBT data now, but you'll probably want to translate
			// that into a useful form e.g. populating your Maps, Lists, etc. from the stored data
		}
	}
}

You can put that method in the same class and make sure you call it every time before you try to access your saved data, or create a wrapper class with public-facing methods that call it for you, e.g.:

public abstract class ZSSMapGenBase
{
/** Saved and loaded world data */
private YourSaveDataClass saveData;

private Map<String, String> someMapThatIsActuallyUseful = Maps.newHashMap();

public String getSomethingFromMyMap(World world, String key) {
	loadOrCreateData(world); // this should populate the 'actually useful' map with data
	return someMapThatIsActuallyUseful.get(key);
}

// #loadOrCreateData, as described above, should be included here
}

Posted

I see how that would retrieve the data, but how exactly does that force the storage again? Or is the Dirty declaration enough for that?

 

getPerWorldStorage() also doesn't seem to exist for World...

 

EDIT: So, I got the code working a little better, to the point where loading a new world will clear the data from the old world. It still tries to create a new perWorldStorage data tag every time, though.

 

...I'm also noticing that the data it is TRYING to save is being saved per dimension.... ugh... But I guess there's no harm in just loading the data at world load, therefore always getting all the data from the first world loaded (presumably the overworld)...

 

public class WorldDataHandler extends WorldSavedData {
public List<Item> itemUnique = new ArrayList<Item>();
private static WorldDataHandler INSTANCE;

public WorldDataHandler(String string) {
	super(string);
}
@Override
public void readFromNBT(NBTTagCompound nbt) {
	itemUnique = new ArrayList<Item>();
	NBTTagList list = nbt.getTagList("Items", 10);
	for (int i = 0; i < list.tagCount(); ++i) {
		NBTTagCompound stackTag = list.getCompoundTagAt(i);
		int slot = stackTag.getByte("Slot") & 255;
		itemUnique.add(ItemStack.loadItemStackFromNBT(stackTag).getItem());
	}
}
@Override
public void writeToNBT(NBTTagCompound nbt) {
	NBTTagList list = new NBTTagList();
	for (int i = 0; i < itemUnique.size(); ++i) {
		NBTTagCompound stackTag = new NBTTagCompound();
		stackTag.setByte("Slot", (byte) i);
		new ItemStack(itemUnique.get(i),1).writeToNBT(stackTag);
		list.appendTag(stackTag);
	}
	nbt.setTag("UniqueItems", list);		
}

public boolean checkUnique(Item item, boolean doAdd){
	if (itemUnique.contains(item)) return false;
	if (doAdd) itemUnique.add(item);
	markDirty();
	return true;
}

public static WorldDataHandler getInstance() {
	return INSTANCE;
}
public static void setInstance(World world) {
	String tagname = "MEUNIQUE";
	MapStorage storage = world.perWorldStorage;
	LogHelper.info(world.perWorldStorage.toString());
	WorldDataHandler result = (WorldDataHandler)storage.loadData(WorldDataHandler.class, tagname);
	if (result == null) {
		result = new WorldDataHandler(tagname);
		storage.setData(tagname, result);
	}
	INSTANCE = result;
}
public static void resetInstance() {
	INSTANCE = null;
}
}

setInstance() and resetInstance() are called by the first triggered world load and unload events respectively.

If anyone has a comprehensive, visual guide to GUIs - don't hesitate to message me. They make my head spin.

Posted

OKay, so I am getting closer. It's reading and writing the NBT when appropriate. Unfortunately, my logging tells me that the NBT data isn't actually being STORED when it is written...

 

	@Override
public void readFromNBT(NBTTagCompound nbt) {
	itemUnique = new ArrayList<Item>();
	NBTTagList list = nbt.getTagList("Items", 10);
	for (int i = 0; i < list.tagCount(); ++i) {
		NBTTagCompound stackTag = list.getCompoundTagAt(i);
		itemUnique.add(ItemStack.loadItemStackFromNBT(stackTag).getItem());
	}
}
@Override
public void writeToNBT(NBTTagCompound nbt) {
	NBTTagList list = new NBTTagList();
	for (int i = 0; i < itemUnique.size(); ++i) {
		NBTTagCompound stackTag = new NBTTagCompound();
		new ItemStack(itemUnique.get(i),1).writeToNBT(stackTag);
		list.appendTag(stackTag);
	}
	nbt.setTag("UniqueItems", list);
}

I've been trying to simplify my code as I go.

 

EDIT: I DID IT!!! Re-reading your code as you post really seems to help in a weird way. Let's just say UniqueItems and Items.... aren't the same tag...

If anyone has a comprehensive, visual guide to GUIs - don't hesitate to message me. They make my head spin.

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.

×
×
  • Create New...

Important Information

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