Jump to content

Recommended Posts

Posted

I have an Entity with a RangedBow Attack and a Melee Attack. To swap between them it checks for the Item in his MainHand. If it is a Bow it uses the RangedAttack. I've wrote a custom Ai to say when it should change his equipment to a sword and a shield. To store the items he uses I made a NonNullList. My Problem is it crashes cause of Ticking Entity. It also says me it occurs at super.onUpdate in my onUpdate method and that's somehow related to my Ai. But I don't have any Idea what exactly causes this  (I'm not experienced with writing AIs)

My Code:

Entity:

package com.cruelar.cruelars_triforcemod.entities.monster;

import com.cruelar.cruelars_triforcemod.entities.IChangeWeaponAI;
import com.cruelar.cruelars_triforcemod.entities.IModRangedAttackMob;
import com.cruelar.cruelars_triforcemod.entities.ai.EntityAIChangeWeapon;
import com.cruelar.cruelars_triforcemod.entities.ai.ModAIAttackRangedBow;
import com.cruelar.cruelars_triforcemod.entities.ai.ModAINearestAttackableTarget;
import com.cruelar.cruelars_triforcemod.init.ModItems;
import com.cruelar.cruelars_triforcemod.items.Lynel_Bow;
import net.minecraft.entity.EntityLiving;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.IEntityLivingData;
import net.minecraft.entity.SharedMonsterAttributes;
import net.minecraft.entity.ai.*;
import net.minecraft.entity.item.EntityBoat;
import net.minecraft.entity.monster.EntityIronGolem;
import net.minecraft.entity.monster.EntityMob;
import net.minecraft.entity.monster.EntityPigZombie;
import net.minecraft.entity.passive.EntityVillager;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.projectile.EntityArrow;
import net.minecraft.init.Items;
import net.minecraft.init.MobEffects;
import net.minecraft.init.SoundEvents;
import net.minecraft.inventory.EntityEquipmentSlot;
import net.minecraft.item.ItemArrow;
import net.minecraft.item.ItemBow;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import net.minecraft.network.datasync.DataParameter;
import net.minecraft.network.datasync.DataSerializers;
import net.minecraft.network.datasync.EntityDataManager;
import net.minecraft.network.play.server.SPacketEntityEquipment;
import net.minecraft.util.NonNullList;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.MathHelper;
import net.minecraft.world.DifficultyInstance;
import net.minecraft.world.EnumDifficulty;
import net.minecraft.world.World;
import net.minecraft.world.WorldServer;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;

import javax.annotation.Nullable;

public class Red_Maned_Lynel extends EntityMob implements IChangeWeaponAI,IModRangedAttackMob {
    private static final DataParameter<Boolean> SWINGING_ARMS = EntityDataManager.<Boolean>createKey(Red_Maned_Lynel.class, DataSerializers.BOOLEAN);
    private final ModAIAttackRangedBow<Red_Maned_Lynel> aiArrowAttack = new ModAIAttackRangedBow<Red_Maned_Lynel>(this,1.0D,20,32F);
    private final EntityAIAttackMelee aiAttackOnCollide = new EntityAIAttackMelee(this, 1.2D, false){
        /**
         * Reset the task's internal state. Called when this task is interrupted by another one
         */
        @Override
        public void resetTask()
        {
            super.resetTask();
            Red_Maned_Lynel.this.setSwingingArms(false);
        }
        /**
         * Execute a one shot task or start executing a continuous task
         */
        @Override
        public void startExecuting()
        {
            super.startExecuting();
            Red_Maned_Lynel.this.setSwingingArms(true);
        }
    };
    public static final ResourceLocation LOOT = new ResourceLocation("cruelars_triforcemod:entities/red_maned_lynel");
    public static final ResourceLocation RESOURCE_LOCATION = new ResourceLocation("cruelars_triforcemod:textures/entity/red_maned_lynel.png");
    private final NonNullList<ItemStack> arrowInventory = NonNullList.<ItemStack>withSize(1, ItemStack.EMPTY);
    private final NonNullList<ItemStack> unusedInventory = NonNullList.<ItemStack>withSize(2,ItemStack.EMPTY);
    private static final DataParameter<Byte> STATUS = EntityDataManager.<Byte>createKey(Red_Maned_Lynel.class, DataSerializers.BYTE);
    public int tailCounter;
    private float rearingAmount;
    private float prevRearingAmount;

    public Red_Maned_Lynel(World worldIn) {
        super(worldIn);
        this.setSwingingArms(true);
        this.setSize(1.3964844F,2F);
        this.stepHeight = 1.0F;
        this.setCombatTask();
    }

    @Override
    protected void entityInit(){
        super.entityInit();
        this.dataManager.register(STATUS, Byte.valueOf((byte)0));
        this.dataManager.register(SWINGING_ARMS, Boolean.valueOf(false));
    }

    @Override
    protected void setEquipmentBasedOnDifficulty(DifficultyInstance difficulty){
        this.setItemStackToSlot(EntityEquipmentSlot.MAINHAND, new ItemStack(ModItems.lynel_bow));
        ItemStack itemStack = new ItemStack(ModItems.bomb_arrow);
        itemStack.setCount(10);
        this.arrowInventory.set(0,itemStack);
        this.unusedInventory.set(0,new ItemStack(Items.IRON_SWORD));
        this.unusedInventory.set(1,new ItemStack(Items.SHIELD));
        }
    }

    @Override
    protected void  applyEntityAttributes(){
        super.applyEntityAttributes();
        this.getEntityAttribute(SharedMonsterAttributes.MAX_HEALTH).setBaseValue(1500.0D);
        this.getEntityAttribute(SharedMonsterAttributes.MOVEMENT_SPEED).setBaseValue(0.5D);
        this.getEntityAttribute(SharedMonsterAttributes.ARMOR).setBaseValue(0.0D);
        this.getEntityAttribute(SharedMonsterAttributes.FOLLOW_RANGE).setBaseValue(32.0D);
        this.getEntityAttribute(SharedMonsterAttributes.ATTACK_DAMAGE).setBaseValue(10.0D);
        this.getEntityAttribute(SharedMonsterAttributes.KNOCKBACK_RESISTANCE).setBaseValue(100.0D);
    }

    @Override
    protected void initEntityAI(){
        this.tasks.addTask(0,new EntityAISwimming(this));
        this.tasks.addTask(2,new EntityAIAttackMelee(this,1.0D,true));
        this.tasks.addTask(5,new EntityAIMoveTowardsRestriction(this,1.0D));
        this.tasks.addTask(7,new EntityAIWander(this,1.0D));
        this.tasks.addTask(8,new EntityAIWatchClosest(this, EntityPlayer.class, 8.0F));
        this.tasks.addTask(8,new EntityAILookIdle(this));
        this.tasks.addTask(1,new EntityAIChangeWeapon<>(this));
        this.applyEntityAI();
    }

    protected void applyEntityAI() {
        this.tasks.addTask(6, new EntityAIMoveThroughVillage(this, 1.0D, false));
        this.targetTasks.addTask(1, new EntityAIHurtByTarget(this, false, EntityPigZombie.class));
        this.targetTasks.addTask(2, new ModAINearestAttackableTarget<>(this, EntityPlayer.class, true));
        this.targetTasks.addTask(3, new ModAINearestAttackableTarget<>(this, EntityVillager.class, true));
        this.targetTasks.addTask(3, new ModAINearestAttackableTarget<>(this, EntityIronGolem.class, true));
    }

    @Override
    public int getMaxSpawnedInChunk(){
        return 1;
    }

    @Override
    protected boolean isValidLightLevel(){
        return true;
    }

    @Override
    public void attackEntityWithRangedAttack(EntityLivingBase target, float distanceFactor) {
        EntityArrow entityarrow = this.getArrow(distanceFactor);
        EntityArrow entityarrow2 = this.getArrow(distanceFactor);
        EntityArrow entityarrow3 = this.getArrow(distanceFactor);
        double d0 = target.posX - this.posX;
        double d1 = target.getEntityBoundingBox().minY + (double)(target.height / 3.0F) - entityarrow.posY;
        double d2 = target.posZ - this.posZ;
        double d3 = (double) MathHelper.sqrt(d0 * d0 + d2 * d2);
        entityarrow.shoot(d0, d1 + d3 * 0.20000000298023224D, d2, 1.6F, (float)(14 - this.world.getDifficulty().getDifficultyId() * 4));
        entityarrow2.shoot(d0, d1 + d3 * 0.20000000298023224D, d2, 1.6F, (float)(14 - this.world.getDifficulty().getDifficultyId() * 4));
        entityarrow3.shoot(d0, d1 + d3 * 0.20000000298023224D, d2, 1.6F, (float)(14 - this.world.getDifficulty().getDifficultyId() * 4));
        entityarrow2.rotationYaw=entityarrow2.rotationYaw+2F;
        entityarrow3.rotationYaw=entityarrow3.rotationYaw-2F;
        this.playSound(SoundEvents.ENTITY_SKELETON_SHOOT, 1.0F, 1.0F / (this.getRNG().nextFloat() * 0.4F + 0.8F));
        this.world.spawnEntity(entityarrow);
        this.world.spawnEntity(entityarrow2);
        this.world.spawnEntity(entityarrow3);
    }

    protected EntityArrow getArrow(float p_190726_1_)
    {
        if (getArrowInInventory().getItem()!=Items.AIR) {
            EntityArrow entityarrow = ((ItemArrow) getArrowInInventory().getItem()).createArrow(world, getArrowInInventory(), this);
            entityarrow.setEnchantmentEffectsFromEntity(this, p_190726_1_);
            return entityarrow;
        }else {
            ItemStack itemStack = new ItemStack(Items.ARROW);
            ItemArrow itemArrow = (ItemArrow) itemStack.getItem();
            return itemArrow.createArrow(world,itemStack,this);
        }
    }

    private void moveTail()
    {
        this.tailCounter = 1;
    }

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

    @Override
    public void changeHeldItems() {
        ItemStack itemStackOld1 = this.getItemStackFromSlot(EntityEquipmentSlot.MAINHAND);
        ItemStack itemStackOld2 = this.getItemStackFromSlot(EntityEquipmentSlot.OFFHAND);
        ItemStack itemStackNew1 = this.unusedInventory.get(0);
        ItemStack itemStackNew2 = this.unusedInventory.get(1);
        this.unusedInventory.set(0,itemStackOld1);
        this.unusedInventory.set(1,itemStackOld2);
        this.setItemStackToSlot(EntityEquipmentSlot.MAINHAND,itemStackNew1);
        this.setItemStackToSlot(EntityEquipmentSlot.OFFHAND,itemStackNew2);
    }

    @Override
    public void setCombatTask()
    {
        if (this.world != null && !this.world.isRemote)
        {
            this.tasks.removeTask(this.aiAttackOnCollide);
            this.tasks.removeTask(this.aiArrowAttack);
            ItemStack itemstack = this.getHeldItemMainhand();
            System.out.println(itemstack.getItem());

            if (itemstack.getItem() == ModItems.lynel_bow)
            {
                int i = 20;

                if (this.world.getDifficulty() != EnumDifficulty.HARD)
                {
                    i = 40;
                }

                this.aiArrowAttack.setAttackCooldown(i);
                this.tasks.addTask(1, this.aiArrowAttack);
            }
            else
            {
                this.tasks.addTask(1, this.aiAttackOnCollide);
            }
        }
    }

    @Nullable
    @Override
    public IEntityLivingData onInitialSpawn(DifficultyInstance difficulty, @Nullable IEntityLivingData livingdata)
    {
        this.setEquipmentBasedOnDifficulty(difficulty);
        this.setEnchantmentBasedOnDifficulty(difficulty);
        this.setCombatTask();
        return livingdata;
    }

    @Override
    public void setDropChance(EntityEquipmentSlot slotIn, float chance)
    {
        switch (slotIn.getSlotType())
        {
            case HAND:
                this.inventoryHandsDropChances[slotIn.getIndex()] = 1F;
                break;
            case ARMOR:
                this.inventoryArmorDropChances[slotIn.getIndex()] = 1F;
        }
    }

    @Override
    public void setItemStackToSlot(EntityEquipmentSlot slotIn, ItemStack stack)
    {
        super.setItemStackToSlot(slotIn, stack);

        if (!this.world.isRemote && slotIn == EntityEquipmentSlot.MAINHAND)
        {
            this.setCombatTask();
        }
    }

    protected boolean getLynelWatchableBoolean(int p_110233_1_)
    {
        return (((Byte)this.dataManager.get(STATUS)).byteValue() & p_110233_1_) != 0;
    }

    protected void setLynelWatchableBoolean(int p_110208_1_, boolean p_110208_2_)
    {
        byte b0 = ((Byte)this.dataManager.get(STATUS)).byteValue();

        if (p_110208_2_)
        {
            this.dataManager.set(STATUS, Byte.valueOf((byte)(b0 | p_110208_1_)));
        }
        else
        {
            this.dataManager.set(STATUS, Byte.valueOf((byte)(b0 & ~p_110208_1_)));
        }
    }

    public void setRearing(boolean rearing)
    {
        this.setLynelWatchableBoolean(2, rearing);
    }

    public boolean isRearing()
    {
        return this.getLynelWatchableBoolean(2);
    }

    @Override
    public void onUpdate()
    {
        super.onUpdate();
        if (this.tailCounter > 0 && ++this.tailCounter > 8)
        {
            this.tailCounter = 0;
        }

        this.prevRearingAmount = this.rearingAmount;

        if (this.isRearing())
        {
            this.rearingAmount += (1.0F - this.rearingAmount) * 0.4F + 0.05F;

            if (this.rearingAmount > 1.0F)
            {
                this.rearingAmount = 1.0F;
            }
        }
        else
        {
            this.rearingAmount += (0.8F * this.rearingAmount * this.rearingAmount * this.rearingAmount - this.rearingAmount) * 0.6F - 0.05F;

            if (this.rearingAmount < 0.0F)
            {
                this.rearingAmount = 0.0F;
            }
        }
    }

    @SideOnly(Side.CLIENT)
    public float getRearingAmount(float p_110223_1_)
    {
        return this.prevRearingAmount + (this.rearingAmount - this.prevRearingAmount) * p_110223_1_;
    }

    @Override
    public void writeEntityToNBT(NBTTagCompound compound)
    {
        super.writeEntityToNBT(compound);
        NBTTagList nbttaglist = new NBTTagList();

        for (ItemStack itemstack : this.unusedInventory)
        {
            NBTTagCompound nbttagcompound = new NBTTagCompound();

            if (!itemstack.isEmpty())
            {
                itemstack.writeToNBT(nbttagcompound);
            }

            nbttaglist.appendTag(nbttagcompound);
        }
        compound.setTag("UnusedItems", nbttaglist);
        this.setCombatTask();
    }


    @Override
    public void readEntityFromNBT(NBTTagCompound compound)
    {
        super.readEntityFromNBT(compound);
        if (compound.hasKey("UnusedItems", 9))
        {
            NBTTagList nbttaglist = compound.getTagList("UnusedItems", 10);

            for (int i = 0; i < this.unusedInventory.size(); ++i)
            {
                this.unusedInventory.set(i, new ItemStack(nbttaglist.getCompoundTagAt(i)));
            }
        }
        this.setCombatTask();
    }

    @SideOnly(Side.CLIENT)
    public boolean isSwingingArms()
    {
        return ((Boolean)this.dataManager.get(SWINGING_ARMS)).booleanValue();
    }

    @Override
    public void setSwingingArms(boolean swingingArms)
    {
        this.dataManager.set(SWINGING_ARMS, Boolean.valueOf(swingingArms));
    }
}

Ai:

package com.cruelar.cruelars_triforcemod.entities.ai;

import com.cruelar.cruelars_triforcemod.entities.IChangeWeaponAI;
import net.minecraft.entity.EntityLiving;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.ai.EntityAIBase;
import net.minecraft.item.ItemBow;

public class EntityAIChangeWeapon<T extends EntityLiving & IChangeWeaponAI> extends EntityAIBase {
    private final T entity;

    public EntityAIChangeWeapon(T executer)
    {
        this.entity = executer;
        this.setMutexBits(0);
    }

    @Override
    public boolean shouldExecute() {
        return this.entity.getAttackTarget()!=null;
    }

    @Override
    public void startExecuting()
    {
        super.startExecuting();
        ((IChangeWeaponAI)this.entity).changeHeldItems();
    }

    @Override
    public boolean shouldContinueExecuting()
    {
        return (this.shouldExecute() || !this.entity.getNavigator().noPath());
    }

    @Override
    public void resetTask()
    {
        super.resetTask();
        this.entity.resetActiveHand();
    }

    protected boolean isBowInMainhand()
    {
        return !this.entity.getHeldItemMainhand().isEmpty() && this.entity.getHeldItemMainhand().getItem()instanceof ItemBow;
    }

    public void updateTask()
    {
        EntityLivingBase entitylivingbase = this.entity.getAttackTarget();

        if (entitylivingbase != null) {
            double d0 = this.entity.getDistanceSq(entitylivingbase.posX, entitylivingbase.getEntityBoundingBox().minY, entitylivingbase.posZ);
            boolean flag = this.entity.getEntitySenses().canSee(entitylivingbase);
            boolean flag1 = this.isBowInMainhand();
            if (d0>16D||!flag){
                if(!flag1) {
                    ((IChangeWeaponAI) this.entity).changeHeldItems();
                }
            }else {
                if (flag1) {
                    ((IChangeWeaponAI) this.entity).changeHeldItems();
                }
            }
        }
    }
}

Interface:

package com.cruelar.cruelars_triforcemod.entities;

public interface IChangeWeaponAI {
    
    void changeHeldItems();
    
    void setCombatTask();
}

log

  Reveal hidden contents

 

My Projects:

Cruelars Triforcemod (1.12 release; 1.14 alpha soon coming)

 

Important:

As my mod is on at least 10 different third party sites without my permission, I want to warn you about that with a link to StopModReposts

Posted

My guess is that you're somehow modifying tasks or targetTasks from within the AI task itself (e.g. by calling setCombatTask()). This is a no-no as you modify a list while that list is being iterrated over, invalidating the iteration (was the item removed already iterated over? if so, do we need to somehow "undo" it? was the item added supposed to be iterated over? The JVM can't answer these questions).

  • Thanks 1

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

Works after I moved the setCombatTask From addEquipmentBasedonDifficulty to after super.onUpdate.

Btw. wasn't a good idea to make a mod which lowers players basehealth and making high health and high attackdamage Mobs.

My Projects:

Cruelars Triforcemod (1.12 release; 1.14 alpha soon coming)

 

Important:

As my mod is on at least 10 different third party sites without my permission, I want to warn you about that with a link to StopModReposts

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.