Jump to content

[1.7.10] Saving Entity IDs to NBT


shultzy

Recommended Posts

I read about ways to save information to an NBT tag that identifies an entity using its UUID or Minecraft's own IDs. I tried this in my mod but I can't tell if it saved this data from the console output. I do need the UUID of my custom entity to persist after exiting the world but I am not able to get the vanilla horses to move while they should be attached to my wagon entity. I currently have my own server command to spawn and "attach" them to the wagon.

EntityWagon.addAnimal()

/**
     * assigns this animal a slot on this entity and saves custom entity data to
     * its NBT tag, animal can be referenced via the respective field.
     * 
     * @param animal
     * @param slot
     */
    public void addAnimal(EntityAnimal animal, byte slot)
    {
if (!worldObj.isRemote)
{
    ExtendedAnimal extHorse = (ExtendedAnimal) animal.getExtendedProperties("WagonAnimal");
    extHorse.setAssignToWagon(this, slot);
    WagonsMod.network.sendToAll(new SyncEntityTag(animal, animal.getEntityData()));
}

animals.add((EntityHorse) animal);

// set each entities' position and rotation
switch (slot)
{
case 0:
    animal.setPositionAndRotation(
	    posX + Math.cos((double) (rotationYaw * Math.PI / 180.0D) - 0.5D) * -2.0D,
	    posY,
	    posZ + Math.sin((double) (rotationYaw * Math.PI / 180.0D) - 0.5D) * -2.0D,
	    rotationYaw, rotationPitch);
    break;
case 1:
    animal.setPositionAndRotation(
	    posX + Math.cos((double) (rotationYaw * Math.PI / 180.0D) + 0.5D) * -2.0D,
	    posY,
	    posZ + Math.sin((double) (rotationYaw * Math.PI / 180.D) + 0.5D) * -2.0D,
	    rotationYaw, rotationPitch);
    break;
}
    }

ExtendedAnimal class

package com.shultzy88.wagonsmod.entity;

import java.util.*;

import cpw.mods.fml.common.registry.IEntityAdditionalSpawnData;
import io.netty.buffer.ByteBuf;
import net.minecraft.client.Minecraft;
import net.minecraft.entity.*;
import net.minecraft.entity.passive.*;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.server.MinecraftServer;
import net.minecraft.util.AxisAlignedBB;
import net.minecraft.world.World;
import net.minecraftforge.common.IExtendedEntityProperties;

/**
* Extends vanilla horse properties as well as other draft type animals to ensure it is properly connected to the
* wagon when this data changes (such as when the memory is released upon leaving the world). The slot helps set
* the position of the animal mob in relation to the custom entity, the string is the
* immutable entity ID for the next time a player visits a world. To maintain the link with the two entities,
* we must also have the temporary ID since it is the same on both sides. As soon as the data is saved, we send a
* packet (see {@code SyncEntityTag} for more) to any clients that require this (i.e rendering GUIs).
* - Note: The temporary ID Minecraft uses only serves to ensure both sides refer to the same entity, we can't
* use this when constructing the wagon because it changes at every game session 
* 
* @author Shultzy
*/
public class ExtendedAnimal implements IExtendedEntityProperties
{
    /** name of the tag that will be holding our data */
    private static final String EXT_ANIMAL_TAG_NAME = "WagonAnimal";
    /** the EntityHorse that our custom properties is bound to (cannot be reassigned) */
    private EntityAnimal animal;
    /** the world that our entity exists */
    private World world;
    /** slot assigned to entity (valid range is 0-3) [default: -1] */
    private byte slot;
    /** persistent ID for our wagon [default: 0-0] */
    private UUID wagonStaticID;
    /** temporary ID for our wagon */
    private int wagonDynamicID;
    
    @Override
    public void saveNBTData(NBTTagCompound compound)
    {
// We need to create a new tag that will save everything for our extended properties on the server
NBTTagCompound draftAnimalProperties = new NBTTagCompound();

draftAnimalProperties.setByte("SlotAssigned", slot);
draftAnimalProperties.setString("WagonUUID", wagonStaticID.toString()); 
draftAnimalProperties.setInteger("WagonID", wagonDynamicID);

// This sets the entity's tag to 
compound.setTag(EXT_ANIMAL_TAG_NAME, draftAnimalProperties);
    }
    
    @Override
    public void loadNBTData(NBTTagCompound compound)
    {
// After we have our NBT tag saved, we must load our extended properties client-side
NBTTagCompound draftAnimalProperties = (NBTTagCompound) compound.getTag(EXT_ANIMAL_TAG_NAME);

// assign data to what was saved on the server
slot = draftAnimalProperties.getByte("SlotAssigned");
wagonStaticID = UUID.fromString(draftAnimalProperties.getString("WagonUUID"));
wagonDynamicID = draftAnimalProperties.getInteger("WagonID");

// check that everything is working fine
System.out.println("[WagonCraft] Entity is assigned to " + slot + " to " + wagonStaticID.toString());
    }

    @Override
    public void init(Entity animal, World world)
    {
this.animal = (EntityAnimal) animal;
this.world = world;
this.slot = -1;
this.wagonStaticID = new UUID(0L, 0L);
this.wagonDynamicID = 0;
    }

    public byte getSlot()
    {
return slot;
    }
    
    public UUID getWagonStaticID()
    {
return wagonStaticID;
    }
    
    public int getWagonDynamicID()
    {
return wagonDynamicID;
    }
    
    /**
     * Sets the extended entity's properties as preparing to be saved to NBT
     */
    public void setAssignToWagon(EntityWagon wagonAssigned, byte slot)
    {
this.wagonStaticID = wagonAssigned.getPersistentID();
this.wagonDynamicID = wagonAssigned.getEntityId();
this.slot = slot;
    }
    
    public static final void register(EntityAnimal animal)
    {
animal.registerExtendedProperties(EXT_ANIMAL_TAG_NAME, new ExtendedAnimal());
    }
    
    public static final ExtendedAnimal getProperties(EntityAnimal animal)
    {
return (ExtendedAnimal) animal.getExtendedProperties(EXT_ANIMAL_TAG_NAME);
    }

    
}

SyncEntityTag class

package com.shultzy88.wagonsmod.network;

import java.util.List;
import java.util.UUID;

import com.shultzy88.wagonsmod.entity.*;
import com.shultzy88.wagonsmod.network.*;

import cpw.mods.fml.common.network.ByteBufUtils;
import cpw.mods.fml.common.network.simpleimpl.*;
import cpw.mods.fml.relauncher.Side;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.event.entity.living.LivingEvent.LivingUpdateEvent;
import io.netty.buffer.ByteBuf;
import net.minecraft.client.Minecraft;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.passive.EntityAnimal;
import net.minecraft.entity.passive.EntityHorse;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.server.MinecraftServer;
import net.minecraft.world.World;

public class SyncEntityTag implements IMessage
{
    private NBTTagCompound animalTag;
    
    /** required for automatic packet handling */
    public SyncEntityTag() { }
    
    public SyncEntityTag(EntityAnimal draftAnimal, NBTTagCompound animalTag)
    {
this.animalTag = animalTag;
ExtendedAnimal.getProperties(draftAnimal).saveNBTData(animalTag);
    }

    @Override
    public void fromBytes(ByteBuf buf)
    {
animalTag = ByteBufUtils.readTag(buf);
    }

    @Override
    public void toBytes(ByteBuf buf)
    {
ByteBufUtils.writeTag(buf, animalTag);
    }
    
    public static class Handler implements IMessageHandler<SyncEntityTag, IMessage>
    {
@Override
public IMessage onMessage(SyncEntityTag message, MessageContext ctx)
{  
    if (ctx.side == Side.CLIENT)
    {
	// We have to interate through the list of loaded entities and load the data for each since the client
	// is run on a separate thread. Which ensures that the client has the necessary custom data we have given.
	List<Entity> loadedEntities = Minecraft.getMinecraft().theWorld.getLoadedEntityList();
	for (Entity entity : loadedEntities)
	{
	    if (entity instanceof EntityHorse)
	    {
		LivingUpdateEvent evt = new LivingUpdateEvent((EntityLivingBase) entity);
		MinecraftForge.EVENT_BUS.post(evt);

		ExtendedAnimal extHorseProps = ExtendedAnimal.getProperties((EntityHorse) evt.entityLiving);
		extHorseProps.loadNBTData(evt.entityLiving.getEntityData().getCompoundTag("WagonAnimal"));
	    }
	}
	return null;
    }
    return null;
}
    }
}

Final note: I have the extended properties registered and use a LivingUpdateEvent method to intercept the vanilla horse update logic and search for the wagon it is assigned to using custom properties that is saved via this tag to the horse. I have suspected that it may not be able to find the wagon because the client and server are using different UUIDs and thought using the temporary ID would help to find it but still not sure what I am doing wrong. ???

Link to comment
Share on other sites

Thanks, at first I did try the UUID because it is immutable, but it seemed that this was inconsistent between the client and the server and so the horse would never be added to my entity. I would like to be sure this is true, since I can't find out anything about it. The way I'm thinking about it, I could in theory send a packet server side with the temporary ID, but without being saved to NBT and use that to get the ID of the entity client side.

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.