Jump to content

[1.7.10] Need to persist a static HashMap with instances of my TileEntity


Recommended Posts

Posted

How do I save that hash map? or does the game has already a map of all TileEntity instances in game (i mean instances, not classes)? If this is the case all I need is to instantiate and populate the hash map when the server starts.

WIP mods: easyautomation, easyenergy, easyelectronics, easymoney, easytrasportation, easysecurity, easymultiverse, easyfactions, easymagick, easyalchemy, easyseasons

Posted

You can probably take a similar approach to the one I recommended in this thread.

 

Looks like exactly what I need. I'll try to implement and then I'll let you know if it worked. Thanks.

WIP mods: easyautomation, easyenergy, easyelectronics, easymoney, easytrasportation, easysecurity, easymultiverse, easyfactions, easymagick, easyalchemy, easyseasons

Posted

A few doubts:

 

Block#onBlockAdded is invoked whenever a block is placed in the world, no matter by what means (during game loading, during world generation, or if a player or machine or whatever adds the block). Is this correct?

 

I need to add a TileEntity to my HashMap<String, TileEntity>. Is it correct to assume the TileEntity is already in place when Block#onBlockAdded is invoked?

WIP mods: easyautomation, easyenergy, easyelectronics, easymoney, easytrasportation, easysecurity, easymultiverse, easyfactions, easymagick, easyalchemy, easyseasons

Posted

Block#onBlockAdded is invoked whenever a block is placed in the world, no matter by what means (during game loading, during world generation, or if a player or machine or whatever adds the block). Is this correct?

Yes, it's called by

Chunk#setBlockIDWithMetadata

, which is called by

World#setBlock

. This is used to place blocks in the world by everything except the initial terrain generation (

BiomeGenBase#genTerrainBlocks

), which deals with raw

Block

and metadata arrays that later become an actual

Chunk

.

 

I need to add a TileEntity to my HashMap<String, TileEntity>. Is it correct to assume the TileEntity is already in place when Block#onBlockAdded is invoked?

No, the

TileEntity

is only created after

Block#onBlockAdded

is called. If you use per-dimension

WorldSavedData

, you can store the positions of each block instead of the

TileEntity

objects.

Please don't PM me to ask for help. Asking your question in a public thread preserves it for people who are having the same problem in the future.

Posted

I have 2 types of TileEntities: one inserts items into a nearby inventory, the other extracts from a nearby inventory and sends to the inserter so it can put the items into it's inventory. The player can configure which inserter the extractor is paired with by name: they give a name to the inserter and also tell the extractor the name of its inserter counterpart.

 

I need to keep a dictionary of inserters by name for this to work.

WIP mods: easyautomation, easyenergy, easyelectronics, easymoney, easytrasportation, easysecurity, easymultiverse, easyfactions, easymagick, easyalchemy, easyseasons

Posted

WorldSavedData would be a good approach for that, like Failender already pointed out.

Keep a record of which names point to which coordinates (not TileEntity instances!) for both sender and receiver. Then when you need to send you can go grab the coords and check if the chunk holding the remote part is loaded and if so grab the TE there.

 

Yes, that's what I thought would be the solution. Thanks everyone.

WIP mods: easyautomation, easyenergy, easyelectronics, easymoney, easytrasportation, easysecurity, easymultiverse, easyfactions, easymagick, easyalchemy, easyseasons

Posted

Is

WorldSavedData

available when

TileEntity#readFromNBT

is invoked?

WIP mods: easyautomation, easyenergy, easyelectronics, easymoney, easytrasportation, easysecurity, easymultiverse, easyfactions, easymagick, easyalchemy, easyseasons

Posted

Is

WorldSavedData

available when

TileEntity#readFromNBT

is invoked?

 

WorldSavedData

is loaded on demand and should be available as soon as the

World

has been constructed, but

TileEntity#readFromNBT

is called before the

TileEntity

exists in any

World

.

Please don't PM me to ask for help. Asking your question in a public thread preserves it for people who are having the same problem in the future.

Posted

ok. So I need to add the x,y,z position of my Block to my

HashMap<String, Position>

field in my custom

WorldSavedData

, and for that I should use

Block#onBlockAdded

. But I have no access to the user given name of each particular

TileEntity

instance. That name should serve as the key of the

HashMap

. I can't see how to make this work. I probably need to invoke

MyWorldData#add

from somewhere else, but because I don't know the inner workings of Minecraft I can't figure out where.

 

class MyWorldData extends WorldSavedData
{
        private HashMap<String, Position> map = new HashMap<>();

        public static MyWorldData get(World world)
{
	MapStorage storage = world.perWorldStorage;
	MyWorldDatainstance = (MyWorldData) storage.loadData(MyWorldData.class, "myworlddata");

	if (instance == null)
	{
		instance = new MyWorldData();
		storage.setData("myworlddata", instance);
	}
	return instance;
}

        public boolean add(String key, int x, int y, int z)
{
	if(key == null || key.length() < 1)
	{
		return false;
	}

	if(!map.containsKey(key))
	{
		map.put(key, new Position(x, y, z));
		this.markDirty();
		return true;
	}
	else
	{
		return false;
	}
}

        public boolean rename(String key, String newKey)
{
	if(key == null || key.length() < 1 || newKey == null || newKey.length() < 1)
	{
		return false;
	}

	Position pos = map.remove(key);
	if(pos == null)
	{
		return false;
	}
	else
	{
		map.put(newKey, pos);
                        this.markDirty();
		return true;
	}
}

         public Position get(String key)
{
	return map.get(key);
}

public Position remove(String key)
{
	Postition pos = map.remove(key);
                if(pos != null)
                    this.markDirty();
                return pos;
}
}

class MyBlock implements ITileEntityProvider
{
        @Override
public TileEntity createNewTileEntity(World p_149915_1_, int p_149915_2_)
{
	return new MyTileEntity();
}

@Override
public void onBlockAdded(World world, int x, int y, int z)
{
	super.onBlockAdded(world, x, y, z);
	MyWorldData  wd = MyWorldData.get(world);
                wd.add(, x, y, z);//there's no name to add
}
}

 

 

WIP mods: easyautomation, easyenergy, easyelectronics, easymoney, easytrasportation, easysecurity, easymultiverse, easyfactions, easymagick, easyalchemy, easyseasons

Posted

How is the name of a block determined?

 

The player chooses it via GUI

WIP mods: easyautomation, easyenergy, easyelectronics, easymoney, easytrasportation, easysecurity, easymultiverse, easyfactions, easymagick, easyalchemy, easyseasons

Posted

Because the player only needs to set the name once. Then it's supposed to be saved forever, unless the player wants to change it. I want to persist the

HashMap<String, Position>

through game sessions. Is there a better method I can use so I can have direct access to the TileEntity?

WIP mods: easyautomation, easyenergy, easyelectronics, easymoney, easytrasportation, easysecurity, easymultiverse, easyfactions, easymagick, easyalchemy, easyseasons

Posted

Yes but I'm not sure how it works. Currently, after what you said, I'm gonna try this approach:

 

class MyWorldData extends WorldSavedData
{
        private static final HashMap<String, Position> map = new HashMap<String, Position>();

public MyWorldData ()
{
	super("myworlddata");
}

public MyWorldData (String s)
{
	super(s);
}

        public static MyWorldData get(World world)
{
	MapStorage storage = world.perWorldStorage;
	MyWorldData instance = (MyWorldData) storage.loadData(MyWorldData .class, "myworlddata");

	if (instance == null)
	{
		instance = new MyWorldData();
		storage.setData("myworlddata", instance);
	}
	return instance;
}

@Override
public void readFromNBT(NBTTagCompound nbt)
{
	map.clear();

	NBTTagList list = nbt.getTagList("map", NBT.TAG_COMPOUND);
	int listSize = list.tagCount();

	for(int i = 0; i < listSize; ++i)
	{
		NBTTagCompound listItem = list.getCompoundTagAt(i);
		String key= listItem.getString("key");
		int x = listItem.getInteger("x");
		int y = listItem.getInteger("y");
		int z = listItem.getInteger("z");

		Position pos = new Position(x, y, z);
		map.put(name, pos);
	}
}

@Override
public void writeToNBT(NBTTagCompound nbt)
{
	NBTTagList list = new NBTTagList();
	map.forEach((name, pos) ->
	{
		NBTTagCompound listItem = new NBTTagCompound();
		listItem.setString("name", name);
		listItem.setInteger("x", pos.getX());
		listItem.setInteger("y", pos.getY());
		listItem.setInteger("z", pos.getZ());
		list.appendTag(listItem);
	});
	nbt.setTag("map", list);
}

public boolean contains(String key)
{
	return map.containsKey(key);
}

public boolean add(String key, int x, int y, int z)
{
	if(key == null || key.length() < 1)
	{
		return false;
	}

	if(!map.containsKey(key))
	{
		map.put(key, new Position(x, y, z));
		this.markDirty();
		return true;
	}
	else
	{
		return false;
	}
}

public boolean rename(String key, String newKey)
{
	if(key == null || key.length() < 1 || newKey == null || newKey.length() < 1)
	{
		return false;
	}

	Position pos = map.remove(key);
	if(pos == null)
	{
		return false;
	}
	else
	{
		map.put(newKey, pos);
		return true;
	}
}

public Position get(String key)
{
	return map.get(key);
}

public Position remove(String key)
{
	Position pos = map.remove(key);
	if(pos != null)
		this.markDirty();
	return pos;
}
}

public class MyTileEntity extends TileEntity
{	
private String key = null;

public boolean containsKey(String key)
{
	MyWorldData wd = MyWorldData.get(this.worldObj);
	return wd.contains(key);
}

public boolean setKey(String key)
{
	MyWorldData wd = MyWorldData.get(this.worldObj);
	if(wd.contains(key))
		return false;

	if(this.key == null)
	{
		this.key = key;
		return wd.add(key, xCoord, yCoord, zCoord);
	}
	else
	{
		wd.rename(this.key, key);
		this.key = key;
		return true;
	}
}

public String getKey()
{
	return this.name;
}

@Override
public boolean canUpdate()
{
	return false;
}

@Override
public Packet getDescriptionPacket()
{
	NBTTagCompound nbtTagCompound = new NBTTagCompound();
	writeToNBT(nbtTagCompound);
	int metadata = getBlockMetadata();
	return new S35PacketUpdateTileEntity(this.xCoord, this.yCoord, this.zCoord, metadata, nbtTagCompound);
}

@Override
public void onDataPacket(NetworkManager net, S35PacketUpdateTileEntity pkt)
{
	readFromNBT(pkt.func_148857_g());
}

@Override
public void readFromNBT(NBTTagCompound nbt)
{
	super.readFromNBT(nbt);
	this.key = nbt.getString("key");
}

@Override
public void writeToNBT(NBTTagCompound nbt)
{
	super.writeToNBT(nbt);
	nbt.setString("name", this.key);
}

public static MyTileEntity getByKey(String key, World world)
{
	MyWorldData wd = MyWorldData .get(world);
	Position pos = wd.get(key);

	TileEntity te = world.getTileEntity(pos.getX(), pos.getY(), pos.getZ());
	if(te instanceof MyTileEntity)
		return (MyTileEntity)te;
	else
		return null;
}
}

 

I was trying to add unnamed TileEntities to my map and this was getting really complicated. Will this version of the code work now?? I only add a

TileEntity

to the map once the player gives it a name.

 

One last thing: from where should I invoke

WorldSavedData#remove

?

Block.breakBlock

?

WIP mods: easyautomation, easyenergy, easyelectronics, easymoney, easytrasportation, easysecurity, easymultiverse, easyfactions, easymagick, easyalchemy, easyseasons

Posted

uhm sorry to intrude, but I really don't understand why you fell the need to save that data on disk and load it all back after a restart

 

If the TE chunk isn't loaded you can't do anything with the TE even if you known it should be there.. or are you also implementing some sort of chunk loading on demand?

 

Also, what do you do about "abandoned" blocks: say that a player on a server build it's sorting system with dozens of your blocks and then for some reason never use it again (he build a new base somewhere else, never log back in, etc). Are you going to keep track of his TEs forever?

 

Just keep track of the TEs that are actually loaded in the game: they are the only ones that players can actually use

 

 

 

 

 

Posted

uhm sorry to intrude, but I really don't understand why you fell the need to save that data on disk and load it all back after a restart

 

Probably because the block's functionality should persist after the player quits the game.

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

uhm sorry to intrude, but I really don't understand why you fell the need to save that data on disk and load it all back after a restart

 

Probably because the block's functionality should persist after the player quits the game.

 

and what's preventing it?

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



×
×
  • Create New...

Important Information

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