Jump to content

[1.7.10] [solved] How would you get an entities UUID to persist after setDead


Thornack

Recommended Posts

Hi everyone

 

I have an entity that I create and then set dead at various times determined by the player. Then I create a new instance of this entities class with blank NBT and populate the NBT with my custom entity data (stats, and other things etc...) I need to be able to give this entity something like a UUID that persists between each setdead/ creation of a new instance of the entities class with blank nbt data so that I can get this entity using this id at a later time. I was wondering if there is anything in minecraft that I could use to achieve this. I checked and my entities id changes after each call to set the entity to dead. What I need is a way to get each specific instance of my entity whenever it is not dead based on its unique identifier after it has been set dead at some previous time. But i cannot do this because the .getEntityId() method returns a different id each time. I could create my own system and store it as NBT data along side my other data that I am already populating but I feel like minecraft already has some sort of "label" that I could use to accomplish this.

Link to comment
Share on other sites

Setting entity dead means that this entity instance will be removed from all references (world's entity list) at start of next tick.

Entity removed from memory that way is no longer saved into world's data and all data that was assigned to it is lost.

 

I am trying REALLY hard to understand what you are after, please share what exacly you are after, there might be other way.

 

EntityId is assigned whenever an entity is constructed, therefore it will ALWAYS be different for newly spawned.

Attempting to save any entity references outside place they should be saved (world entity list) or save them to NBT without proper handling will most likely cause either memory leaks or corrupted/overloaded data files.

 

What you can do is NOT allow entity to die and when reaching 0.0 health value make it stop being updated (onUpdate or other method). This way entity will still be inside world list and still saved to NBT so after reloading world you will be able to load it.

As to saving which entity is which - they alredy have their uuids when saved to NBT - you can use WorldSaveData to hold list of those uuids which you want to access.

1.7.10 is no longer supported by forge, you are on your own.

Link to comment
Share on other sites

I agree with Ernio.  I think you need a way to make your entity "act dead" rather than actually set dead.  You can just create a boolean field in your custom entity called actDead.  Then in your attack entity from method you should override it and change the code so setDead() is not called when health goes below 0 but rather your actDead field should be set to true.

 

Then, like Ernio says you can use that actDead field to control it.  For example, in the onUpdate() method you can check it and change what happens.  So you can prevent movement for example, and if you want it to stay visible you can continue to render it (probably rotated so it is fallen on the ground).

 

That's probably how I'd try to do it.

Check out my tutorials here: http://jabelarminecraft.blogspot.com/

Link to comment
Share on other sites

Ok so without making this too confusing here is the info you requested. In my mod I have an entity that can capture other entities (it can only capture one entity at a time though and works perfectly atm). This entity has a method where if it hits another entities hitbox, it gets the hit entity and passes it to a placeholder entity - (that plays an animation and stores the entity as NBT then it sets the impacted entity to dead and generates an itemstack that contains the entities data). The resultant itemstack is dropped into the world and stays in world until a player picks it up and this item works like a monster egg that spawns a new entity with the same data as the impacted entity that was set to dead previously. If this entity is hit again by the first entity (mentioned above) then the same process occurs. I need a way of preserving some sort of entity id for the captured entity throughout the process so that it is retrievable at a later time.

 

I dont think it would work if I used the actDead solution you suggested since if i spawn an entity with the same data as the impacted entity and the impacted entity is still "alive" and in the world somewhere) then eventually there will be too many entities in world and this would be a bad thing. And I dont think I could get the exact instance of the entity i want, so that it exists first in world then moves to exist inside the capturing entity when it is hit by it then moves to exist inside the animating entity and then moves to exist inside the itemstack until a player picks it up and uses it then it moves back to exist inside the world when the itemstack is used again. Currently I accomplish this "existing" by using NBT to essentially clone the entity that was impacted and setting the impacted entity in world to dead. But since I am then creating a new instance of the entity when the itemstack is used the UUID changes and i need it to stay the same.

Link to comment
Share on other sites

One thing to note that i have noticed. With the current setup that I have, if i try

 

caughtEntity.readEntityFromNBT(caughtEntityNBT);
int id = caughtEntity.getEntityId(); 
list.add(EnumChatFormatting.DARK_PURPLE+"UUID: "+id);

 

inside my method that adds information about the itemstack, then the entity id seems to increment each tick also i tried to add

UUID id = caughtEntity.getUniqueID(); 

instead of the

int id = caughtEntity.getEntityId();

line and upon doing so the UUID also seemed to change everytick when i placed my mouse over the itemstack to display the information about it.

Link to comment
Share on other sites

Are the entities you're capturing custom entities too, or vanilla entities?

 

In either case, I think you need to create your own ID system.  If you're only capturing custom entities you could have a field in the entity for your custom ID, but if you're capturing vanilla entities then you will need to create some sort of map in your main mod class that maps your custom id with the latest actual entity ID.

 

I don't think you should use UUID at all -- I don't think those are the same between client and server.  Instead use the getEntityID() method for the entity -- that will be the same on both side.  That gives you the ID for an entity, and to look up the entity from the ID I usually use a method like this.

public static Entity getEntityByID(int entityID, World world)       

{       

    for(Object o: world.getLoadedEntityList())               

    {                       

        if(((Entity)o).getEntityId() == entityID)                       

        { 

        // DEBUG

            // System.out.println("Found the entity");                               

            return ((Entity)o);                       

        }               

    }               

    return null;       

}

 

Check out my tutorials here: http://jabelarminecraft.blogspot.com/

Link to comment
Share on other sites

so currently i use the following to save my entity inside the itemstack I had to remove alot of code as this class is large

 

//called back from the AnimationEntity class when the catch animation finishes to generate the itemstack
public void onEntityCaught(){
ItemStack itemstack = this.generateCustomItemstack(this.hitEntity, this.getCustomEggItemType(), this.impactEntityName);
EntityItem customEggItem = new EntityItem(this.worldObj, this.posX, this.posY, this.posZ, itemstack);
	customEggItem.motionX = customEggItem.motionY = customEggItem.motionZ = 0;
	this.worldObj.spawnEntityInWorld(customEggItem);
	this.setDead();
}

       //generates an itemStack containing the caught entity
private ItemStack generateCustomItemstack(EntityCustom hitEntity, CustomItem customItemType, String impactEntityName){
	return CustomItemStackFactory.generateCustomItemStack(hitEntity, customItemType, impactEntityName);
}

@Override
protected void readEntityFromNBT(NBTTagCompound nbtTagCompound) {	
	NBTTagCompound hitEntityNBT = nbtTagCompound.getCompoundTag("hitEntity");
	this.wasCaught = nbtTagCompound.getBoolean("wasCaught");
}

@Override
protected void writeEntityToNBT(NBTTagCompound nbtTagCompound) {
	NBTTagCompound hitEntityNBT = new NBTTagCompound();
	this.hitEntity.writeEntityToNBT(hitEntityNBT);

	nbtTagCompound.setTag("hitEntity", hitEntityNBT);
	nbtTagCompound.setString("impactEntityName", this.impactEntityName);
	nbtTagCompound.setBoolean("wasCaught", this.wasCaught);
}

 

This is where the actual item stack NBT data is saved in the new itemstack

CustomItemStackFactory

public class CustomItemStackFactory {
public static ItemStack generateCustomItemStack(EntityCustom hitEntity, CustomItem customItemType, String impactEntityName){

	ItemStack customItem = new ItemStack(customItemType);
	if(customItem.stackTagCompound == null){
		customItem.stackTagCompound = new NBTTagCompound();
	}
	NBTTagCompound entityCustomNBTCompound = new NBTTagCompound();
	hitEntity.writeEntityToNBT(entityCustomNBTCompound);

	customItem.stackTagCompound.setTag("hitEntity", entityCustomNBTCompound);
	customItem.stackTagCompound.setString("impactEntityName", impactEntityName);

	return customItem;
}
}

EDIT - Diesieben07, Im not sure how I would implement that (kinda my original question actually as how one would go about doing that)

You don't need any custom IDs.

For saving to disk use UUIDs. For client-server communication use getEntityID. Done.

 

would I get the UUID and save it using NBT?

Link to comment
Share on other sites

ok ya I am writing the entity using the NBT but why does it change each tick when I do inside my item class

 

caughtEntity.readEntityFromNBT(caughtEntityNBT);
int id = caughtEntity.getEntityId(); 
list.add(EnumChatFormatting.DARK_PURPLE+"UUID: "+id);

 

I can see the entityid incrementing each tick when i mouse over my item

 

EDIT[]

 

in my CustomHitEntity class I have the following NBT methods

@Override
public void readEntityFromNBT(NBTTagCompound nbtCompound)
{   
	super.readEntityFromNBT(nbtCompound);

	nbtCompound.getString("hitEntityName");
	stats.impactEntityName = nbtCompound.getString("impactEntityName");
	stats.level = nbtCompound.getInteger("Level");
	stats.hp = nbtCompound.getInteger("MaxHP");
	stats.currentHp = nbtCompound.getInteger("CurrentHP");
	stats.att = nbtCompound.getInteger("MaxAtt");
	stats.currentAtt = nbtCompound.getInteger("CurrentAtt");
	stats.def = nbtCompound.getInteger("MaxDef");
	stats.spd = nbtCompound.getInteger("MaxSpd");
	stats.currentSpd = nbtCompound.getInteger("CurrentSpd");
}

@Override
public void writeEntityToNBT(NBTTagCompound nbtCompound)
{ 
	super.writeEntityToNBT(nbtCompound);

	nbtCompound.setString("hitEntityName", EntityList.getEntityString(this));
	nbtCompound.setString("impactEntityName", this.getImpactEntityName());
	nbtCompound.setInteger("Level",stats.level);
	nbtCompound.setInteger("MaxHP",stats.hp);
	nbtCompound.setInteger("MaxAtt",stats.att);
	nbtCompound.setInteger("MaxDef",stats.def);
	nbtCompound.setInteger("MaxSpd",stats.spd);

	nbtCompound.setInteger("CurrentHP",stats.currentHp);
	nbtCompound.setInteger("CurrentAtt",stats.currentAtt);
	nbtCompound.setInteger("CurrentDef",stats.currentDef);
	nbtCompound.setInteger("CurrentSpd",stats.currentSpd);
}

Link to comment
Share on other sites

woops my mistake I meant to paste the following into that last post

caughtEntity.readEntityFromNBT(caughtEntityNBT);
UUID id = caughtEntity.getUniqueId(); //this should be the UUID right
list.add(EnumChatFormatting.DARK_PURPLE+"UUID: "+id);
[code]

the id changes if I do that

Link to comment
Share on other sites

that code is located inside my

@Override

public void addInformation(ItemStack itemStack, EntityPlayer player, List list, boolean par4){} method inside my CustomItem class

 

[EDIT]

I am trying to save the Entity UUID directly as a variable inside my entity class and maybe accomplish what I want that way. Inside the NBT methods in my CustomHitEntity (shown above)

I have added the following

in the Entity class I added

 

public Long UUIDMost;

 

in the readNBT method

UUIDMost = nbtCompound.getLong("UUIDMost");

 

in the writeNBT method

nbtCompound.setLong("UUIDMost", getUniqueID().getMostSignificantBits());

 

Im going to try and get these instead and see if they persist

Link to comment
Share on other sites

I need to be able to check whether or not my entities UUID is actually persisting throughout me setting it dead and creating a dummy instance of it where I then populate the dummy instance with my entities data on spawning the dummy instance to achieve the effect of "storing the entity" inside the itemstack and inside the other entity. My goal is to get the entity by its unique identifier based on an event. But i cannot get it if i dont know how to access the identifier.

Link to comment
Share on other sites

Using my entities onUpdate method

 

@Override
public void onUpdate(){
	super.onUpdate();
	if (!this.worldObj.isRemote)
	{
	System.out.println("UUID is:" + this.getUniqueID().getMostSignificantBits());
	}
	}

 

UUID is:-2866414455432394955 - when the entity is first spawned into the world (before capture process)

 

UUID is:-2028361691453110800 - after the capture process and after i release it from my itemstack

 

UUID is:5188495526038618792 - after recapture and rerelease

 

so the UUID is not being preserved like I said - I tried it both on client and on server (changed the worldObj.isRemote) to be true and to be false and I get the same result for both, the UUID changes.

 

Link to comment
Share on other sites

After looking into this further, my stats are based off of a random number generator and they persist throughout the entire capture/item/spawn process I described above. As such do you think it would work if I created my own UUID as part of my stats generation class and save that as NBT and then each time I create my new instance of my custom entity would it be possible to set my ID to be the id of the newly spawned entity (replace them somehow). Is this possible?

Link to comment
Share on other sites

everytime I set the entity to dead it gets deleted from NBT.

The statement should be other way around: When entity is setDead() the instance is being removed and it's NBT won't be saved to world's data.

 

Could you please provide FULL code. Github would be nice.

SAving data to something that won't be saved is radical and will not work.

1.7.10 is no longer supported by forge, you are on your own.

Link to comment
Share on other sites

I did some more debugging by insterting System.out.println("Entity write UUID" + this.getUniqueID().getMostSignificantBits()); to every NBT method right after the entity is written to NBT and I also inserted System.out.println("Entity read UUID" + this.getUniqueID().getMostSignificantBits()); after every read method. I found that the entityUUID persists right up until the point where the itemstack is used as a spawn egg to "respawn" the entity at which point it changes. Furthermore for some reason when I mouse over the item in the inventory I get

 

Entity read UUID-2590020052499871580

Entity read UUID230231760567025764

Entity read UUID5738625593234114913 ... and so on

 

where it seems that the read Entity from NBT method is called on mouse over for some reason.


@Override
public void readEntityFromNBT(NBTTagCompound nbtCompound)
{   
	super.readEntityFromNBT(nbtCompound);
	System.out.println("Entity read UUID" + this.getUniqueID().getMostSignificantBits());

	//I read stats here

}

@Override
public void writeEntityToNBT(NBTTagCompound nbtCompound)
{ 
	super.writeEntityToNBT(nbtCompound);
	System.out.println("Entity write UUID" + this.getUniqueID().getMostSignificantBits());

	//I write stats here	

}

 

This is what is out printed to the consol from the moment I use a spawn egg to spawn my custom entity into the world for the first time to the moment I release the entity into the wild after it has been hit by my impactEntity ,captured, and converted into an itemstack and the UUID persists until I use the item that was generated to release the entity into the world. I included the methods I use to spawn the entity. Once these methods are called the uuid stops persisting and I am not sure why, or what the problem is.

 

 

[19:12:53] [server thread/INFO] [sTDOUT]: [custommod.entity.customEntity.CustomEntity:addBaseStatsInformation:281]: Stats Have been added to Entity

[19:12:56] [server thread/INFO] [sTDOUT]: [custommod.entity.customEntity. CustomEntity:writeEntityToNBT:219]: Entity write UUID7685169787008731756

Calling entitiesCollideCalculation(18, 100, 4, "Monster")N1=300, N2=3800, N3=17000

[19:13:00] [server thread/INFO]: [CHAT] §7DEBUG: animationCount: 3 captureSuccess: true

[19:13:00] [server thread/INFO] [sTDOUT]: [custommod.animation.Animation:<init>:36]: CONSTRUCT: animationCount: 3 captureSuccess: true

[19:13:00] [server thread/INFO] [sTDOUT]: [custommod.entity.item.ImpactEntity:onImpact:159]: ImpactEntity getAnimatedImpactEntity UUID7685169787008731756

[19:13:05] [server thread/INFO] [sTDOUT]: [custommod.entity.customEntity. CustomEntity:writeEntityToNBT:219]: Entity write UUID7685169787008731756

[19:13:05] [server thread/INFO] [sTDOUT]: [custommod.entity.item. ItemStackFactory:generateCustomEntityItemStack:19]: CustomEntityItemstackFactory write UUID7685169787008731756

[19:13:05] [server thread/INFO]: [CHAT] §aCongratulations! The Entity was caught!

//When I release the entity this happens. Before this point the UUID persists

[19:25:44] [Client thread/INFO] [sTDOUT]: [custommod.entity. customEntity. CustomEntity:readEntityFromNBT:187]: Entity read UUID218021918924623543

[19:25:44] [server thread/INFO] [sTDOUT]: [custommod.entity. customEntity. CustomEntity:addBaseStatsInformation:281]: Stats Have been added to Entity

[19:25:44] [server thread/INFO] [sTDOUT]: [custommod.entity. customEntity. CustomEntity:readEntityFromNBT:187]: Entity read UUID-7970982183583070147

 

These are the methods I use to spawn the entity into the world after the itemstack has been created. For some reason the UUID seems to stop persisting in NBT when these methods are called and Im not sure why

@Override
public boolean onItemUse(ItemStack itemStack, EntityPlayer player, World world, int x, int y, int z, int par7, float par8, float par9, float par10)
    {	

	//if the impactEntity contains a customEntity already, then release it on right click
	if (itemStack.stackTagCompound != null && itemStack.stackTagCompound.hasKey("caughtCustomEntity")) {
		int customDataID = itemStack.stackTagCompound.getInteger("customDataID");
		CustomEntity customEntity = null;
		//System.out.println("Here");
		try{
			customEntity = CustomEntityRegistry.getCustomEntityClass(customDataID).getDeclaredConstructor(World.class).newInstance(world);
		}
		catch(Exception e){
			System.out.println("custommod: "+e.toString());
		}
		if(customEntity != null){
			customEntity.readEntityFromNBT(itemStack.stackTagCompound.getCompoundTag("caughtCustomEntity"));
			customEntity.setPosition(x,y+1.5,z);
			customEntity.isDead = false;
			customEntity.deathTime = 0;
			String impactEntityName = itemStack.stackTagCompound.getString("impactEntityName");
			customEntity.setImpactEntity(impactEntityName);

			if(!world.isRemote){
				world.spawnEntityInWorld(customEntity);
			}
			}

		// customEntity has been released, don't allow user to release same customEntity multiple times
		itemStack.stackTagCompound = null;
		}

		return true;
    }

@Override
public ItemStack onItemRightClick(ItemStack itemStack, World world, EntityPlayer player) {

	boolean impactEntityHasmob = false;
	world.playSoundAtEntity(player, "random.bow", 0.5F,	0.4F / (itemRand.nextFloat() * 0.4F + 0.8F));
	MovingObjectPosition mop = player.rayTrace(5, 1.0F);

	if (!world.isRemote) {
		if(!(itemStack.stackTagCompound != null && itemStack.stackTagCompound.hasKey("caughtCustomEntity"))){
			impactEntityHasmob = false;
			tossImpactEntity(world, player);
		}
		else if ((itemStack.stackTagCompound != null && itemStack.stackTagCompound.hasKey("caughtCustomEntity"))){
			impactEntityHasmob = true;	
			int customDataID = itemStack.stackTagCompound.getInteger("customDataID");
				CustomEntity customEntity = null;
				//System.out.println("Here");
				try{
					customEntity = CustomEntityRegistry.getCustomEntityClass(customDataID).getDeclaredConstructor(World.class).newInstance(world);
				}
				catch(Exception e){
					System.out.println("custommod: "+e.toString());
				}
				if(customEntity != null){
					customEntity.readEntityFromNBT(itemStack.stackTagCompound.getCompoundTag("caughtCustomEntity"));

					customEntity.setPosition(mop.blockX,mop.blockY +1, mop.blockZ);
					customEntity.isDead = false;
					customEntity.deathTime = 0;
					String impactEntityName = itemStack.stackTagCompound.getString("impactEntityName");
					customEntity.setImpactEntity(impactEntityName);
			         	}
				 releaseCustomEntityIntoWorld(world,customEntity);  
				// customEntity has been released, don't allow user to release same customEntity multiple times
					itemStack.stackTagCompound = null;
			}
	}


	if (!player.capabilities.isCreativeMode && impactEntityHasmob == false) {
		--itemStack.stackSize;
	}
	return itemStack;
}

 

 

 

 

Link to comment
Share on other sites

THANK YOU THANK YOU THANK YOU That did the trick the UUID now persists!!!!!

[EDIT] Also, that fixed the problem where the UUID was changing when I hovered over the itemStack with the mouse. Now the same UUID is displayed to the consol every tick the mouse is over the item

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



×
×
  • Create New...

Important Information

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