Jump to content

[1.8][SOLVED]Custom entity : saving new fields


Shuyin76

Recommended Posts

Hello every body ! I'm using forge 11.14.1.1354 and I would like to create a custom entity. I already succeeded in that but I just can't save any new attribute !

I'm using a class implementing IExtendedEntityProperties to save the new fields but it doesn't seem to work.

Here is my Custom entity class: I want to save the career field.

 

 

import java.util.ArrayList;

import java.util.Random;

 

import net.minecraft.client.Minecraft;

import net.minecraft.entity.EntityLiving;

import net.minecraft.entity.ai.EntityAIVillagerInteract;

import net.minecraft.entity.ai.EntityAIWander;

import net.minecraft.entity.ai.EntityAIWatchClosest;

import net.minecraft.entity.ai.EntityAIWatchClosest2;

import net.minecraft.entity.monster.EntityMob;

import net.minecraft.entity.player.EntityPlayer;

import net.minecraft.entity.player.EntityPlayerMP;

import net.minecraft.init.Items;

import net.minecraft.item.ItemStack;

import net.minecraft.nbt.NBTTagCompound;

import net.minecraft.nbt.NBTTagList;

import net.minecraft.stats.StatList;

import net.minecraft.util.ChatComponentText;

import net.minecraft.village.MerchantRecipeList;

import net.minecraft.world.World;

import net.minecraftforge.fml.relauncher.Side;

import net.minecraftforge.fml.relauncher.SideOnly;

 

public class EntityNPCM extends EntityMob{

protected short careerId;

 

public EntityNPCM(World par1World) {

super(par1World);

this.tasks.addTask(9, new EntityAIWatchClosest2(this, EntityPlayer.class, 3.0F, 1.0F));

        this.tasks.addTask(9, new EntityAIWander(this, 0.6D));

        this.tasks.addTask(10, new EntityAIWatchClosest(this, EntityLiving.class, 8.0F));

        this.setCanPickUpLoot(false);

       

        if(this.getCustomNameTag().isEmpty())

this.setCustomNameTag("NPC");

}

 

@Override

public int getTalkInterval()

    {

        return 200;

    }

 

@Override

protected boolean canDespawn()

    {

        return false;

    }

   

public short getCarrerId()

{

return this.careerId;

}

 

public void setCarrerId(short id)

{

this.careerId = id;

}

 

@Override

    protected String getHurtSound()

    {

return "shuyintestmod:hurtM";

    }

 

@Override

protected String getDeathSound()

    {

return "shuyintestmod:deathM";

    }

 

@Override

protected String getLivingSound()

    {

return "shuyintestmod:livingM";

    }

 

@Override

public boolean interact(EntityPlayer player)

    {

        ItemStack itemstack = player.inventory.getCurrentItem();

        boolean flag = itemstack != null && (itemstack.getItem() == Items.spawn_egg || itemstack.getItem() == Items.name_tag);

        if (!flag && this.isEntityAlive())

    {

        if(this.worldObj.isRemote)

        {

        if(itemstack.getItem() instanceof ItemTest)

            {

            this.setDead();

            return true;

            }

        if(player.capabilities.isCreativeMode && player.isSneaking())

    {

    this.careerId++;

            if(careerId > 5)

            careerId = 0;

    }

        else

        {

        player.addChatMessage(new ChatComponentText(this.getCustomNameTag() + " : Mon ID = "+ this.careerId + " : "  + getUniqueID().toString()));

        }

        }

   

            return true;

    }

        else

        {

            return super.interact(player);

        }

    }

}

 

And here is my ExtendedProperties class :

package com.shuyin.test;

 

import net.minecraft.entity.Entity;

import net.minecraft.nbt.NBTTagCompound;

import net.minecraft.world.World;

import net.minecraftforge.common.IExtendedEntityProperties;

 

public class NPCExtendedProperties implements IExtendedEntityProperties {

 

public final static String extendedPropertiesName = "extendedPropertiesNPC";

    protected EntityNPCM entity;

    protected World theWorld;

   

@Override

public void saveNBTData(NBTTagCompound compound) {

// TODO Auto-generated method stub

System.out.println("sauvegarde NPC :" + entity.getCarrerId() +" " + entity.getCustomNameTag() + " : " + entity.getUniqueID().toString());

NBTTagCompound subCompound = new NBTTagCompound();

compound.setTag(extendedPropertiesName, subCompound);

 

subCompound.setShort("career", entity.getCarrerId());

//compound.setShort("career", entity.getCarrerId());

}

 

@Override

public void loadNBTData(NBTTagCompound compound) {

// TODO Auto-generated method stub

NBTTagCompound subcompound = (NBTTagCompound) compound.getTag(extendedPropertiesName);

entity.setCarrerId(subcompound.getShort("career"));

System.out.println("charge NPC :" + entity.getCarrerId()+" " + entity.getCustomNameTag() + " : " + entity.getUniqueID().toString());

}

 

@Override

public void init(Entity entity, World world) {

// TODO Auto-generated method stub

this.entity = (EntityNPCM)entity;

        theWorld = world;

}

 

 

}

My entity can spawn, send me a message when I right click, It's career lvl change when I shift+right click but it don't save.

With the log I can see the custom save and custom load happening but they just always take 0 when they save the field.

 

 

I'm sorry I juste can't use the code balise. If someone can say me how to use it, I don't understand...

Link to comment
Share on other sites

Change

 

      compound.setTag(extendedPropertiesName, subCompound);
      
      subCompound.setShort("career", entity.getCarrerId());

To

      subCompound.setShort("career", entity.getCarrerId());
      
      compound.setTag(extendedPropertiesName, subCompound);

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.

Link to comment
Share on other sites

OK, I changed it but it don't work. I'm not sure but It seems to save correctly but when saving, it got 0 from career but have the good CustomName.(I changed the career level during the game and I'm sure the entity have a career lvl different than 0.

Link to comment
Share on other sites

Few things:

1. Why are you using IEEP when you have your own Entity class - there is ONLY ONE explanation that is good enough to do that and that is - compatibility between all entities on server.

- Followin above - you can save fields inside entity, IEEP is mandatory and rather used for vanilla mobs.

2. When using IEEP - you sure you are registering it?

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

Link to comment
Share on other sites

OK, you suggest I make something like that ?

in my custom entity class

@Override

public void writeEntityToNBT(NBTTagCompound tagCompound)

    {

        super.writeEntityToNBT(tagCompound);

        tagCompound.setInteger("Career", this.careerId);

    }

 

    @Override

    public void readEntityFromNBT(NBTTagCompound tagCompund)

    {

        super.readEntityFromNBT(tagCompund);

        this.careerId = tagCompund.getInteger("Career");

    }

 

I already tried this and it don't work :(

 

And I'm sure I registered my IEEP because I can see my logs when loading and saving nbt.

Link to comment
Share on other sites

So I'm testing the save with the two methods and a debug in each :

 

[23:21:48] [server thread/INFO] [sTDOUT/]: [com.shuyin.test.NPCExtendedProperties:loadNBTData:31]: charge NPC :0 POupoule : 3892f46a-f22c-4720-b2ce-41bacbcaf0dc

[23:21:48] [server thread/INFO] [sTDOUT/]: [com.shuyin.test.EntityNPCM:func_70037_a:83]: charge NBT NPC :0 POupoule : 3892f46a-f22c-4720-b2ce-41bacbcaf0dc

[23:21:50] [server thread/INFO] [sTDOUT/]: [com.shuyin.test.NPCExtendedProperties:loadNBTData:31]: charge NPC :0 NPC : b5b17f2a-b5fc-4b3e-a380-27905785a363

[23:21:50] [server thread/INFO] [sTDOUT/]: [com.shuyin.test.EntityNPCM:func_70037_a:83]: charge NBT NPC :0 NPC : b5b17f2a-b5fc-4b3e-a380-27905785a363

 

 

-- Here, I suppose I'm playing, and I set the careerId to 2 for the NPC POupoule and 1 for the other --

 

 

[23:22:01] [server thread/INFO] [sTDOUT/]: [com.shuyin.test.NPCExtendedProperties:saveNBTData:17]: sauvegarde NPC :0 POupoule : 3892f46a-f22c-4720-b2ce-41bacbcaf0dc

[23:22:01] [server thread/INFO] [sTDOUT/]: [com.shuyin.test.EntityNPCM:func_70014_b:71]: sauvegarde NBT NPC :0 POupoule : 3892f46a-f22c-4720-b2ce-41bacbcaf0dc

[23:22:01] [server thread/INFO] [sTDOUT/]: [com.shuyin.test.NPCExtendedProperties:saveNBTData:17]: sauvegarde NPC :0 NPC : b5b17f2a-b5fc-4b3e-a380-27905785a363

[23:22:01] [server thread/INFO] [sTDOUT/]: [com.shuyin.test.EntityNPCM:func_70014_b:71]: sauvegarde NBT NPC :0 NPC : b5b17f2a-b5fc-4b3e-a380-27905785a363

 

But you can see, the custom name of the entity can be read but not the careerId.(always 0)

 

If I set the careerId to 3 for example during the save, It will load 3 but the careerId will be 0 on my real Entity.

 

EDIT : I noticed that the UUID of the Entity wasn't the same that the UUID showed in the log.

 

In the custom entity class, do you have to specify  a serverSide for the Write/read to NBT method ? And for the IEEP, do you have to register them in server side only ?

Link to comment
Share on other sites

OK here is my commonProxy class I register my two entities here (both client and server side) I need to register them only server side ?

 

public class CommonProxy {

 

public static Item testItem;

public static Item itemProtectedDoor;

public static Block protectedDoor;

 

public static void registerEntity(Class entityClass, String name)

    {

    int entityID = EntityRegistry.findGlobalUniqueEntityId();

    long seed = name.hashCode();

    Random rand = new Random(seed);

    int primaryColor = rand.nextInt() * 16777215;

    int secondaryColor = rand.nextInt() * 16777215;

 

    EntityRegistry.registerGlobalEntityID(entityClass, name, entityID,primaryColor,secondaryColor);

    EntityRegistry.registerModEntity(entityClass, name, entityID, Test.instance, 64, 1, true);

    }

 

public void preInit(FMLPreInitializationEvent e) {

testItem = new ItemTest();

protectedDoor = new ProtectedDoor();

itemProtectedDoor = new ItemProtectedDoor(protectedDoor);

 

registerEntity(EntityNPCM.class, "entityNPCM");

    registerEntity(EntityNPCF.class, "entityNPCF");

    }

 

    public void init(FMLInitializationEvent e) {

   

    registerEventListeners();

    registerRenderers();

    }

 

    public void postInit(FMLPostInitializationEvent e) {

 

    }

   

public void registerEventListeners()

{

    MinecraftForge.EVENT_BUS.register(new EventHandlerTest());

}

 

    public void registerRenderers()

    {

    }

}

 

(both client and server proxy extends to this method. I override the registerRenderers only client side)

 

in my custom entity class, I need to modify my interact method like this ?

 

@Override

public boolean interact(EntityPlayer player)

    {

        ItemStack itemstack = player.inventory.getCurrentItem();

        boolean flag = itemstack != null && (itemstack.getItem() == Items.spawn_egg || itemstack.getItem() == Items.name_tag);

        if (!flag && this.isEntityAlive())

    {

        if(!this.worldObj.isRemote)

        {

        if(itemstack != null)

        {

        if(itemstack.getItem() instanceof ItemTest)

                {

                this.setDead();

                return true;

                }

        }

       

        if(player.capabilities.isCreativeMode && player.isSneaking())

    {

    this.careerId++;

            if(careerId > 5)

            careerId = 0;

    }

        else

        {

        player.addChatMessage(new ChatComponentText(this.getCustomNameTag() + " : Mon ID = "+ this.careerId + " : "  + getUniqueID().toString()));

        }

        }

   

            return true;

    }

        else

        {

            return super.interact(player);

        }

    }

Link to comment
Share on other sites

OK what should I use instead of RegsiterGlobal EntityID ? It tried without but I can't see my spawn egg anymore (it's obvious I know) but even with adding

EntityList.entityEggs.put(entityID, new EntityList.EntityEggInfo(entityID, primaryColor, secondaryColor)); at the end of my register, I can only see an egg that can't spawn anything !

Link to comment
Share on other sites

You cannot use a vanilla spawn egg. Make your own.

This is such a shame, since so many mods add entities, and they all have to write their own implementation - I keep hoping one of these days Forge will provide a way to hook into the vanilla spawn egg / summon command.

 

That said, it's not too difficult. I wrote an implementation that involves a custom entity list and a single item to handle all of those.

 

I just really wish that this type of compatibility layer were already available / standard.

Link to comment
Share on other sites

OK I can spawn my custom entity. But.. should I spawn it Server side, client side or both ?

I tried all the solution :

    - serveur side : spawn the correct entity but I can't interract with it

    -Client side : spawn an herited entity and I can interract with it but not saving anything

  -both : spawn the two entities

Link to comment
Share on other sites

OK It works server side fine now, thank you very much ! But I have a problem : my entities don't render correctly !

They have the default skin but normally when I shift + right click on them, they have to change skin(switch the careerId). It worked before but wasn't saved. Here, the careerId is saved but the entities don't change their skins.

Here is my Render class :

 

public class RenderNPC extends RenderLiving {

 

 

public RenderNPC(ModelBiped model, float shadowSize) {

super(Minecraft.getMinecraft().getRenderManager(), model, shadowSize);

 

}

 

@Override

protected boolean canRenderName(Entity Entity)

{

return true;

}

 

@Override

protected ResourceLocation getEntityTexture(Entity par1Entity)

{

if(par1Entity instanceof EntityNPCM)

{

ResourceLocation textureLocation;

EntityNPCM entity = (EntityNPCM) par1Entity;

if(entity.getCarrerId()<0 || entity.getCarrerId()>5 )

textureLocation = new ResourceLocation(Test.MODID + ":" + "textures/models/entityNPC" + (par1Entity instanceof EntityNPCF ? "F" : "M") + "0.png");

else

textureLocation = new ResourceLocation(Test.MODID + ":" + "textures/models/entityNPC" + (par1Entity instanceof EntityNPCF ? "F" : "M") + entity.getCarrerId()+ ".png");

return textureLocation;

}

else

return null;

}

}

 

which is called client side only

RenderingRegistry.registerEntityRenderingHandler(EntityNPCM.class, new RenderNPC(new ModelBiped(), 0.5F));

RenderingRegistry.registerEntityRenderingHandler(EntityNPCF.class, new RenderNPC(new ModelBiped(), 0.5F));

Link to comment
Share on other sites

First things 1st:

Do not declare Resource with every render pass, save those as static files somewhere and just reference them.

 

Secondly - print out your getCarrerId() - do they change on client side?

 

Post updated entity code.

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

Link to comment
Share on other sites

OK, Client side the getcarrerId returns always 0.

Here is my Updated entity class :

public class EntityNPCM extends EntityMob{
protected short careerId;

public EntityNPCM(World par1World) {
	super(par1World);
	this.tasks.addTask(9, new EntityAIWatchClosest2(this, EntityPlayer.class, 3.0F, 1.0F));
        this.tasks.addTask(9, new EntityAIWander(this, 0.6D));
        this.tasks.addTask(10, new EntityAIWatchClosest(this, EntityLiving.class, 8.0F));
        this.setCanPickUpLoot(false);
        
        if(this.getCustomNameTag().isEmpty())
		this.setCustomNameTag("NPC");
}

@Override
public int getTalkInterval()
    {
        return 200;
    }

@Override
protected boolean canDespawn()
    {
        return false;
    }
    
public short getCarrerId()
{
	if(this.worldObj.isRemote)
	{
		System.out.println("getting careerId in Client :" + this.careerId);
	}
	else
	{
		System.out.println("getting careerId in Server :" + this.careerId);
	}
	return this.careerId;
}

public void setCarrerId(short id)
{
	this.careerId = id;
}

/**
     * (abstract) Protected helper method to write subclass entity data to NBT.
     */
@Override
    public void writeEntityToNBT(NBTTagCompound tagCompound)
    {
        super.writeEntityToNBT(tagCompound);
        tagCompound.setShort("Career", this.careerId);
        System.out.println("sauvegarde NBT NPC :" + this.careerId +" " + getCustomNameTag() + " : " + getUniqueID().toString());

    }

    /**
     * (abstract) Protected helper method to read subclass entity data from NBT.
     */
@Override
    public void readEntityFromNBT(NBTTagCompound tagCompund)
    {
        super.readEntityFromNBT(tagCompund);
        this.careerId = tagCompund.getShort("Career");
        System.out.println("charge NBT NPC :" + this.careerId+" " + getCustomNameTag() + " : " + getUniqueID().toString());
    }
    
@Override
    protected String getHurtSound()
    {
	return "shuyintestmod:hurtM";
    }

@Override
protected String getDeathSound()
    {
	return "shuyintestmod:deathM";
    }

@Override
protected String getLivingSound()
    {
	return "shuyintestmod:livingM";
    }

@Override
public boolean interact(EntityPlayer player)
    {
        ItemStack itemstack = player.inventory.getCurrentItem();
        boolean flag = itemstack != null && (itemstack.getItem() == Items.spawn_egg || itemstack.getItem() == Items.name_tag);
        if (!flag && this.isEntityAlive())
    	{
        	if(!this.worldObj.isRemote)
        	{
        		if(itemstack != null)
        		{
        			if(itemstack.getItem() instanceof ItemTest)
                	{
                		this.setDead();
                		return true;
                	}
        		}
        		
        		if(player.capabilities.isCreativeMode && player.isSneaking())
    			{
    				this.careerId++;
            		if(careerId > 5)
            			careerId = 0;
    			}
        		else
        		{
        			player.addChatMessage(new ChatComponentText(this.getCustomNameTag() + " : Mon ID = "+ this.careerId + " : "   + getUniqueID().toString()));
        		}
        	}
    		
            return true;
    	}
        else
        {
            return super.interact(player);
        }
    }
}

Link to comment
Share on other sites

Aand... It works ! Thank you very much for your precious help ! AAahh if only I knew about datawatcher sooner !

Ernio, "Do not declare Resource with every render pass, save those as static files somewhere and just reference them."

Do I have to create a list of strings and create the new Resource location in the getEntityTexture Method or It's best to create a list of ResourceLocation directly ?

 

I will post my custom Entity class later for help

Link to comment
Share on other sites

It really doesn't matter how you do it, it can even be ResourceLocation[] that would be accessed with your numbers (carrer).

 

It's more of an optimization stuff - "new" makes new object which is pointless to do in anything that is involved in ticking operations, especially render passes.

 

Simply have static Map<Integer, RL> or RL[] or whatever else, jsut don't call "new" all the time. (RL = ResoLoc)

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

Link to comment
Share on other sites

OK I'll do that !

 

Here is my custom Entity class, I hope this will help someone for the dataWatcher or simply create a custom entity !

 

public class EntityNPCM extends EntityMob{
protected int careerId;
protected boolean canWander;

public EntityNPCM(World par1World) {
	super(par1World);
	canWander = false;

	updateTasks();
        this.setCanPickUpLoot(false);
        
        if(this.getCustomNameTag().isEmpty())
		this.setCustomNameTag("MALE_NPC");
}

private void updateTasks()
{
	this.tasks.taskEntries.clear();

	this.tasks.addTask(1, new EntityAISwimming(this));
	this.tasks.addTask(2, new EntityAIWatchClosest2(this, EntityPlayer.class, 3.0F, 1.0F));
        this.tasks.addTask(3, new EntityAIWatchClosest(this, EntityLiving.class, 8.0F));
        if(canWander)
        	this.tasks.addTask(9, new EntityAIWander(this, 0.4D));
}

@Override
protected void entityInit()
    {
        super.entityInit();
        this.dataWatcher.addObject(16, 0);
        this.dataWatcher.addObject(17, 0);
    }

@Override
public int getTalkInterval()
    {
        return 200;
    }

@Override
protected boolean canDespawn()
    {
        return false;
    }
    
//function used in my render class to get the good careerId
@SideOnly(Side.CLIENT)
public int getClientCarrerId()
{
	return this.dataWatcher.getWatchableObjectInt(16);
}

@SideOnly(Side.CLIENT)
public boolean isClientMale()
{

	return this.dataWatcher.getWatchableObjectInt(17) == 0;
}

public void setCarrerId(short id)
{
	this.careerId = id;
}

/**
     * (abstract) Protected helper method to write subclass entity data to NBT.
     */
@Override
    public void writeEntityToNBT(NBTTagCompound tagCompound)
    {
        super.writeEntityToNBT(tagCompound);
        tagCompound.setInteger("Career", this.careerId);
        tagCompound.setBoolean("Wander", canWander);

    }

    /**
     * (abstract) Protected helper method to read subclass entity data from NBT.
     */
@Override
    public void readEntityFromNBT(NBTTagCompound tagCompund)
    {
        super.readEntityFromNBT(tagCompund);
        this.canWander = tagCompund.getBoolean("Wander");
        this.careerId = tagCompund.getInteger("Career");
        this.dataWatcher.updateObject(16, this.careerId);
        
        updateTasks();
    }
    
@Override
    protected String getHurtSound()
    {
	return "shuyintestmod:hurtM";
    }

@Override
protected String getDeathSound()
    {
	return "shuyintestmod:deathM";
    }

@Override
protected String getLivingSound()
    {
	return "shuyintestmod:livingM";
    }

@Override
public boolean interact(EntityPlayer player)
    {
        ItemStack itemstack = player.inventory.getCurrentItem();
        boolean flag = itemstack != null && (itemstack.getItem() == Items.spawn_egg || itemstack.getItem() == Items.name_tag);
        if (!flag && this.isEntityAlive() && !this.worldObj.isRemote)
    	{
    		if(itemstack != null)
    		{
    			if(itemstack.getItem() instanceof ItemTest)
            	{
    				if(player.isSneaking())
    				{
    					this.setDead();
    				}
    				else
    				{
    					canWander = !canWander;
    					if(canWander)
    						player.addChatMessage(new ChatComponentText(this.getCustomNameTag() + " will now be wandering."));
    					else
    						player.addChatMessage(new ChatComponentText(this.getCustomNameTag() + " will stand still."));
    					updateTasks();
    				}
            		
            		return true;
            	}
    		}
    		
    		if(player.capabilities.isCreativeMode && player.isSneaking())
		{
			this.careerId++;
        		if(this.careerId > 5)
        			this.careerId = 0;
        		this.dataWatcher.updateObject(16, this.careerId);
		}
    		else
    		{
    			player.addChatMessage(new ChatComponentText(this.getCustomNameTag() + " : Mon ID = "+ this.careerId + " : "   + getUniqueID().toString()));
    		}
    		
            return true;
    	}
        else
        {
            return super.interact(player);
        }
    }
}

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.