Jump to content

Recommended Posts

Posted

Help, I created an Entity which summonable by right-clicking an item but when i spawn it, it dies instantly and i dont know why, this just happened after i added something and changed a part of the code, before it worked fine and the entity didn't died.

 

 

here the summon code in the item class:

 

/**
     * Called whenever this item is equipped and the right mouse button is pressed. Args: itemStack, world, entityPlayer
     */
    public ItemStack onItemRightClick(ItemStack itemStackIn, World world, EntityPlayer player)
    {	
    	NBTTagCompound nbtTagCompound = itemStackIn.getTagCompound();
    	if (!world.isRemote)
        {	
    		/*if (nbtTagCompound != null && nbtTagCompound.hasKey("IS_SUMMONED") && nbtTagCompound.getBoolean("IS_SUMMONED") == true ) { 
    			EntityNikora entitynikora = new EntityNikora(world, player); 
        		player.addChatComponentMessage(new ChatComponentText(EnumChatFormatting.RED +"You de-summoned Nikora."));
    			entitynikora.spawnExplosionParticle();
    			entitynikora.setDead();
    			setIsSummoned(itemStackIn, false);
    		}*/
    		
    		if (nbtTagCompound != null && nbtTagCompound.hasKey("IS_SUMMONED") && nbtTagCompound.getBoolean("IS_SUMMONED") == false ) { 
    		//PacketDispatcher.sendToServer(new SpellToServer(10, 10));
    			EntityNikora entitynikora = new EntityNikora(world, player); 
    			entitynikora.setPosition(player.posX, player.posY+1,player.posZ-2); 
    			world.spawnEntityInWorld(entitynikora);
    			player.addChatComponentMessage(new ChatComponentText(EnumChatFormatting.GREEN + "You summoned Nikora!"));
    		}
        }
	return itemStackIn;
    }

 

 

the entity:

 

public class EntityNikora extends EntityTameable implements IEntityOwnable
{
private int tick;
private int manacost = 5;

private double spirit_damage = 2.0D;
private double spirit_health = 20.0D;

    public EntityNikora(World w)
    {
    	this(w, null);
    	
    }
    
    public EntityNikora(World world, Entity caster)
    {
        super(world);
    this.setSize(1, 1);
    ((PathNavigateGround)this.getNavigator()).func_179690_a(true);
        this.tasks.addTask(1, new EntityAISwimming(this));
        this.tasks.addTask(3, new EntityAILeapAtTarget(this, 0.4F));
        this.tasks.addTask(4, new EntityAIAttackOnCollide(this, 1.0D, true));
        this.tasks.addTask(5, new EntityAIFollowOwner(this, 1.0D, 2F, 5F));
        this.tasks.addTask(6, new EntityAIMate(this, 1.0D));
        this.tasks.addTask(7, new EntityAIWander(this, 1.0D));
        this.tasks.addTask(9, new EntityAIWatchClosest(this, EntityPlayer.class, 8.0F));
        this.tasks.addTask(9, new EntityAILookIdle(this));
        this.targetTasks.addTask(1, new EntityAIOwnerHurtByTarget(this));
        this.targetTasks.addTask(2, new EntityAIOwnerHurtTarget(this));
        this.targetTasks.addTask(3, new EntityAINearestAttackableTarget(this, EntityMob.class, true));
        this.targetTasks.addTask(3, new EntityAIHurtByTarget(this, true, new Class[0]));

    if (caster != null)
    {
        this.setTamed(true);
		this.setAttackTarget((EntityLivingBase)null);
		this.setOwnerId(caster.getUniqueID().toString());
		this.worldObj.setEntityState(this, (byte)7);
    }
    }
    
    /**
     * Returns true if the newer Entity AI code should be run
     */
    public boolean isAIEnabled()
    {
        return true;
    }

    protected void applyEntityAttributes()
    {
        super.applyEntityAttributes();
        this.getEntityAttribute(SharedMonsterAttributes.maxHealth).setBaseValue(this.spirit_health);
        this.getEntityAttribute(SharedMonsterAttributes.movementSpeed).setBaseValue(this.spirit_damage);
    }
    
    @Override
    public void onLivingUpdate() {
    	
    	if(getOwner() != null){
     	EntityPlayer player = (EntityPlayer)getOwner();
     	ExtendedPlayer props = ExtendedPlayer.get(player);
     	tick++;
     	if(!worldObj.isRemote){
     	if(tick > 300){
     	if(props.getCurrentMana() >= manacost){
     		props.consumeMana(manacost);
     		tick = 0;
     	}
     	
     	if(props.getCurrentMana() < manacost){
     		player.addChatComponentMessage(new ChatComponentText(EnumChatFormatting.RED + "You have not enough Mana, your Celestial Spirit was desummoned."));
     		this.worldObj.spawnParticle(EnumParticleTypes.SMOKE_NORMAL, this.posX, this.posY, this.posZ, 0, 0, 0, 0);
     		this.setDead();	
     	}
     	}
     	}
     	super.onLivingUpdate();
    	}
    	
     }

    /**
     * Called frequently so the entity can update its state every tick as required. For example, zombies and skeletons
     * use this to react to sunlight and start to burn.
     * @param entity 
     */
    public void onLivingUpdate(EntityPlayer entity)
    {
        super.onLivingUpdate();

        if(!(entity instanceof EntityPlayer))
	{
		this.setAttackTarget(entity);
	}
    }
    


    protected Item getDropItem()
    {
        return (null);
    }

@Override
public EntityAgeable createChild(EntityAgeable ageable)
{
	return (null);
}
}

 

 

note no error, but it dies by his self. thanks for any help!

"My Crew is World Wide." 「ヤング • エルトウ」

Posted

EntityNikora entitynikora = new EntityNikora(world, player); 
player.addChatComponentMessage(new ChatComponentText(EnumChatFormatting.RED +"You de-summoned Nikora."));
entitynikora.spawnExplosionParticle();
entitynikora.setDead();

 

what exactly are you triing to do there

Posted

EntityNikora entitynikora = new EntityNikora(world, player); 
player.addChatComponentMessage(new ChatComponentText(EnumChatFormatting.RED +"You de-summoned Nikora."));
entitynikora.spawnExplosionParticle();
entitynikora.setDead();

 

what exactly are you triing to do there

 

That part is commented out.

 

But back to topic.

 

Sure about getCurrentMana() is over manacost?

Not all things in the world are red, there are round objects too!

Posted

EntityNikora entitynikora = new EntityNikora(world, player); 
player.addChatComponentMessage(new ChatComponentText(EnumChatFormatting.RED +"You de-summoned Nikora."));
entitynikora.spawnExplosionParticle();
entitynikora.setDead();

 

what exactly are you triing to do there

 

That part is commented out.

 

But back to topic.

 

Sure about getCurrentMana() is over manacost?

 

Yes im sure, when the current mana is lower than the manacost it will send a Chat Message and a System out print but it doesnt do.

 

"My Crew is World Wide." 「ヤング • エルトウ」

Posted

Tried to debug and breakpoint to trace where the entity dies?

 

By the way which difficulty level are you running the game in?

Not all things in the world are red, there are round objects too!

Posted

First, make sure you are not in peaceful mode.

 

Second:

if(props.getCurrentMana() >= manacost){
     		props.consumeMana(manacost);
     		tick = 0;
     	}
     	
     	if(props.getCurrentMana() < manacost){
     		player.addChatComponentMessage(new ChatComponentText(EnumChatFormatting.RED + "You have not enough Mana, your Celestial Spirit was desummoned."));
     		this.worldObj.spawnParticle(EnumParticleTypes.SMOKE_NORMAL, this.posX, this.posY, this.posZ, 0, 0, 0, 0);
     		this.setDead();	
     	}

Let's follow that logic. I don't know your current mana at that point, but let's say you have 6 mana. You have manacost = 5.

 

-

if(props.getCurrentMana() >= manacost)

  Your current mana is 6, and manacost is 5, so that condition is true.

---

props.consumeMana(manacost)

  I suspect

consumeMana

is reducing your current mana with the manacost, leaving you with only 1 mana left.

-

if(props.getCurrentMana() < manacost)

  Your current mana is 1 at this point, and manacost is 5, so that is indeed less and that condition is true.

--- Kill the entity

 

Have you figured it out yet? If you don't have atleast 2*manacost when you start, the entity instantly dies because the second if-statement is true because you already removed the mana from the player. You have to add

else

to the second if-statement.

Don't PM me with questions. They will be ignored! Make a thread on the appropriate board for support.

 

1.12 -> 1.13 primer by williewillus.

 

1.7.10 and older versions of Minecraft are no longer supported due to it's age! Update to the latest version for support.

 

http://www.howoldisminecraft1710.today/

Posted

First, make sure you are not in peaceful mode.

 

Second:

if(props.getCurrentMana() >= manacost){
     		props.consumeMana(manacost);
     		tick = 0;
     	}
     	
     	if(props.getCurrentMana() < manacost){
     		player.addChatComponentMessage(new ChatComponentText(EnumChatFormatting.RED + "You have not enough Mana, your Celestial Spirit was desummoned."));
     		this.worldObj.spawnParticle(EnumParticleTypes.SMOKE_NORMAL, this.posX, this.posY, this.posZ, 0, 0, 0, 0);
     		this.setDead();	
     	}

Let's follow that logic. I don't know your current mana at that point, but let's say you have 6 mana. You have manacost = 5.

 

-

if(props.getCurrentMana() >= manacost)

  Your current mana is 6, and manacost is 5, so that condition is true.

---

props.consumeMana(manacost)

  I suspect

consumeMana

is reducing your current mana with the manacost, leaving you with only 1 mana left.

-

if(props.getCurrentMana() < manacost)

  Your current mana is 1 at this point, and manacost is 5, so that is indeed less and that condition is true.

--- Kill the entity

 

Have you figured it out yet? If you don't have atleast 2*manacost when you start, the entity instantly dies because the second if-statement is true because you already removed the mana from the player. You have to add

else

to the second if-statement.

 

It seems logical what you mean but i found out that this two variables are the problem, i can fix that with replacing them at applyEntityAttributes with there value, but why i can't use them as variables?

 

private double spirit_damage = 2.0D;
private double spirit_health = 20D;

protected void applyEntityAttributes()
    {
        super.applyEntityAttributes();
this.getEntityAttribute(SharedMonsterAttributes.maxHealth).setBaseValue(spirit_health);}

 

The Entity is dying because the health is 0 seems logical, but i would like to know why i can't use this 2 variables that i created. thanks for any help!

"My Crew is World Wide." 「ヤング • エルトウ」

Posted

1. Read about how Java creates instances.

2. Notice that applyEntityAttributes() is called from super-constructor of your entity.

3. Think about what is happening and say: "Oh, shit, those 2 globals "spirit_damage" and "spirit_health" are not yet initialized! Therefore, generic data in java is set to default 0.0 for doubles!

4. Ahh... so that's why my entity dies!

EDIT

 

What you need:

Use "static" keyword to make it shared between all entities.

If you need different entities have different health you CANNOT use "SharedMonsterAttributes" - notice word "Shared".

To achieve different values (and make them sync automatically) for different you need to apply AttributeModifier to entity after it's been spawned.

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

Posted

1. Read about how Java creates instances.

2. Notice that applyEntityAttributes() is called from super-constructor of your entity.

3. Think about what is happening and say: "Oh, shit, those 2 globals "spirit_damage" and "spirit_health" are not yet initialized! Therefore, generic data in java is set to default 0.0 for doubles!

4. Ahh... so that's why my entity dies!

 

thanks!  ;D

"My Crew is World Wide." 「ヤング • エルトウ」

Posted

1. Read about how Java creates instances.

2. Notice that applyEntityAttributes() is called from super-constructor of your entity.

3. Think about what is happening and say: "Oh, shit, those 2 globals "spirit_damage" and "spirit_health" are not yet initialized! Therefore, generic data in java is set to default 0.0 for doubles!

4. Ahh... so that's why my entity dies!

EDIT

 

What you need:

Use "static" keyword to make it shared between all entities.

If you need different entities have different health you CANNOT use "SharedMonsterAttributes" - notice word "Shared".

To achieve different values (and make them sync automatically) for different you need to apply AttributeModifier to entity after it's been spawned.

 

Thanks Ernio you're the best, it works, thanks for your help! And thanks to you guys for helping me too.

"My Crew is World Wide." 「ヤング • エルトウ」

Posted

I have one last question, how can i get the summoned Entity that if i right-click again the item, the summoned Entity will disappear?

"My Crew is World Wide." 「ヤング • エルトウ」

Posted

Should be noted:

If you don't know yet - Item is singleton, logically speaking "a description of what you are holding". The thing you are actually holding is ItemStack and only ItemStack can hold per-stack data. To save reference to entity in ItemStack you need to use entity.getUniqueId() which can then be saved in ItemStack's NBT as 2 longs (UUID#getMost/LeastSignificantBits()).

Then you can re-reference entity by getting it from saved UUID - World#getEntityById (or similar method, i don't remember).

Do note that entity might not be found (unloaded), might only be found on server (client is too far to see entity) or other expected or not behaviours - that all needs to be handled properly.

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

Posted

Or.. If im reading you right there could only be one summoned entity, then tell all entities that have the player as caster to disappear?

Not all things in the world are red, there are round objects too!

Posted

Should be noted:

If you don't know yet - Item is singleton, logically speaking "a description of what you are holding". The thing you are actually holding is ItemStack and only ItemStack can hold per-stack data. To save reference to entity in ItemStack you need to use entity.getUniqueId() which can then be saved in ItemStack's NBT as 2 longs (UUID#getMost/LeastSignificantBits()).

Then you can re-reference entity by getting it from saved UUID - World#getEntityById (or similar method, i don't remember).

Do note that entity might not be found (unloaded), might only be found on server (client is too far to see entity) or other expected or not behaviours - that all needs to be handled properly.

 

getEntityByID needs a Int but UUID is a String, so i can't use it.

is there any method to get a Entity by his UUID?

because there is just a method for player UUID, i changed the item class now its saving the UUID of the Entity but i can't do anything with the UUID, when there is no Method for it.

"My Crew is World Wide." 「ヤング • エルトウ」

Posted

Ah, I used bad naming, getEntityByID uses "network" IDs used to sync server and client entity data.

It's just that I have my own utilitiy method that does it for UUID (thus, my confusion).

 

Anyway:

World isntance has "loadedEntityList".

You need to make utility method that will take UUID and return Entity.

Then in that method you will iterate through all entities ("loadedEntityList") and check if entity.getUniqueId().equals(paramUUID), if so - return entity.

 

As one could expect - retrieving UUID from ItemStack's NBT, converting it from 2 longs to "new UUID(least, most)" and then comparing it to list of ALL entities (until found) MIGHT be a little overhead if not used with care - so if you'd ever use it in future to manage per-tick actions - try caching refernce at all cost (not quite possible with ItemStacks).

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

Posted

WorldServer has a method getEntityFromUuid.

 

yes, but the problem is, that the UUID that i save into the Item NBT-Tag, is a String, and getEntityFromUuid needs a UUID, so how can i check that?

"My Crew is World Wide." 「ヤング • エルトウ」

Posted

Ah, I used bad naming, getEntityByID uses "network" IDs used to sync server and client entity data.

It's just that I have my own utilitiy method that does it for UUID (thus, my confusion).

 

Anyway:

World isntance has "loadedEntityList".

You need to make utility method that will take UUID and return Entity.

Then in that method you will iterate through all entities ("loadedEntityList") and check if entity.getUniqueId().equals(paramUUID), if so - return entity.

 

As one could expect - retrieving UUID from ItemStack's NBT, converting it from 2 longs to "new UUID(least, most)" and then comparing it to list of ALL entities (until found) MIGHT be a little overhead if not used with care - so if you'd ever use it in future to manage per-tick actions - try caching refernce at all cost (not quite possible with ItemStacks).

 

i tried to make a method how you said but im getting errors could you give me an example how you did that?

"My Crew is World Wide." 「ヤング • エルトウ」

Posted

UUID#fromString and UUID#toString? Or, using long values instead:

// Writing to NBT:
compound.setLong("YourUUIDMost", uuid.getMostSignificantBits());
compound.setLong("YourUUIDLeast", uuid.getLeastSignificantBits());

// Recreating from NBT:
UUID uuid = new UUID(compound.getLong("YourUUIDMost"), compound.getLong("YourUUIDLeast"));

Posted

UUID#fromString and UUID#toString? Or, using long values instead:

// Writing to NBT:
compound.setLong("YourUUIDMost", uuid.getMostSignificantBits());
compound.setLong("YourUUIDLeast", uuid.getLeastSignificantBits());

// Recreating from NBT:
UUID uuid = new UUID(compound.getLong("YourUUIDMost"), compound.getLong("YourUUIDLeast"));

 

i made an method to return the entity when the UUID is the same with the one that is saved to the NBT, but it seems that its not working it seems that the UUID is not the same with the saved UUID.

 

public static Entity getSummonedEntity(){

    World world = Minecraft.getMinecraft().theWorld;

    int i = 0;

    ItemStack stack = Minecraft.getMinecraft().thePlayer.getCurrentEquippedItem();

    //Entity entity2 = (Entity)world.loadedEntityList.get();

    if(world.loadedEntityList != null){

    for (i = 0; i < world.loadedEntityList.size(); i++)

    {

    if (((Entity)world.loadedEntityList.get(i)) instanceof EntityNikora)

    {

    System.out.println("NIKORA FOUND");

    if (((Entity)world.loadedEntityList.get(i)).getUniqueID().toString().equals(getUUID(stack)))

    {

    System.out.println("NIKORA UUID CHECKED");

    Entity entity = (Entity)world.loadedEntityList.get(i);

    return entity;

    }

    }

    }

    }

return (Entity)world.loadedEntityList.get(i);

    }

 

 

This line isn't called, so it seems that the EntityUUID is not the same, could somebody tell me why?

System.out.println("NIKORA UUID CHECKED");

 

and here the getUUID method:

public static String getUUID(ItemStack stack){
    	NBTTagCompound nbtTagCompound = stack.getTagCompound();
    	if (nbtTagCompound != null){
    	return nbtTagCompound.getString("UUID");
    	}
    	else return "";
    }

 

"My Crew is World Wide." 「ヤング • エルトウ」

Posted

No, No, No, No...

 

Minecraft is client-only class. Everything there is a display stuff - You cannot edit it, it won't do shit to actual data on server.

 

public static UUID getUUID(ItemStack stack)
{
    NBTTagCompound nbt = stack.getTagCompound();
    if (nbtTagCompound != null)
    {
        return new UUID(nbt.getLong("MSB"), nbt.getLong("LSB")); // most and least significant bits
    }
    return null;
}

In your Item class you need to write data to NBT on usage:

UUID uuid = entity.getUniqueId(); // entity is some entity you want to save ref to.
nbt.setLong("MSB", uuid.getMostSignificantBits()); // nbt of itemstack.
nbt.setLong("LSB", uuid.getLeastSignificantBits());

 

Getting actual ref:

@Override
public ItemStack onItemRightClick(ItemStack itemStack, World world, EntityPlayer player)
{
if (!world.isRemote) // UUIDs ONLY exist on server (not counting players)
{
	UUID uuid = getUUID(itemStack); // 1st method in post
	Entity entity = ((WorldServer) world).getEntityFromUuid(uuid);

 

Do note that srcs above are unsafe and need null handling for NBT/entity/uuid.

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

Posted

No, No, No, No...

 

Minecraft is client-only class. Everything there is a display stuff - You cannot edit it, it won't do shit to actual data on server.

 

public static UUID getUUID(ItemStack stack)
{
    NBTTagCompound nbt = stack.getTagCompound();
    if (nbtTagCompound != null)
    {
        return new UUID(nbt.getLong("MSB"), nbt.getLong("LSB")); // most and least significant bits
    }
    return null;
}

In your Item class you need to write data to NBT on usage:

UUID uuid = entity.getUniqueId(); // entity is some entity you want to save ref to.
nbt.setLong("MSB", uuid.getMostSignificantBits()); // nbt of itemstack.
nbt.setLong("LSB", uuid.getLeastSignificantBits());

 

Getting actual ref:

@Override
public ItemStack onItemRightClick(ItemStack itemStack, World world, EntityPlayer player)
{
if (!world.isRemote) // UUIDs ONLY exist on server (not counting players)
{
	UUID uuid = getUUID(itemStack); // 1st method in post
	Entity entity = ((WorldServer) world).getEntityFromUuid(uuid);

 

Do note that srcs above are unsafe and need null handling for NBT/entity/uuid.

 

Thanks, i understand what you mean, i'll try that.

"My Crew is World Wide." 「ヤング • エルトウ」

Posted

No, No, No, No...

 

Minecraft is client-only class. Everything there is a display stuff - You cannot edit it, it won't do shit to actual data on server.

 

public static UUID getUUID(ItemStack stack)
{
    NBTTagCompound nbt = stack.getTagCompound();
    if (nbtTagCompound != null)
    {
        return new UUID(nbt.getLong("MSB"), nbt.getLong("LSB")); // most and least significant bits
    }
    return null;
}

In your Item class you need to write data to NBT on usage:

UUID uuid = entity.getUniqueId(); // entity is some entity you want to save ref to.
nbt.setLong("MSB", uuid.getMostSignificantBits()); // nbt of itemstack.
nbt.setLong("LSB", uuid.getLeastSignificantBits());

 

Getting actual ref:

@Override
public ItemStack onItemRightClick(ItemStack itemStack, World world, EntityPlayer player)
{
if (!world.isRemote) // UUIDs ONLY exist on server (not counting players)
{
	UUID uuid = getUUID(itemStack); // 1st method in post
	Entity entity = ((WorldServer) world).getEntityFromUuid(uuid);

 

Do note that srcs above are unsafe and need null handling for NBT/entity/uuid.

 

THANKS ERNIO, it works perfectly!

It wasn't that hard to understand, but im wondering what uuid.getMostSignificantBits() &  uuid.getLeastSignificantBits() means, does a UUID have this 2 long variables? Can anyone explain me that? :)

"My Crew is World Wide." 「ヤング • エルトウ」

Guest
This topic is now closed to further replies.
×
×
  • Create New...

Important Information

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