Jump to content

[1.20.1] My custom entity can't attack players


btuh

Recommended Posts

I don't know why my entity can attack any entity but players

This is the entity's code

package mymod.entities.chicken;

import com.google.common.collect.ImmutableList;
import com.google.errorprone.annotations.Immutable;
import net.minecraft.advancements.CriteriaTriggers;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.Tag;
import net.minecraft.network.syncher.EntityDataAccessor;
import net.minecraft.network.syncher.EntityDataSerializers;
import net.minecraft.network.syncher.SynchedEntityData;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.sounds.SoundEvent;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.stats.Stats;
import net.minecraft.util.RandomSource;
import net.minecraft.util.TimeUtil;
import net.minecraft.util.valueproviders.UniformInt;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.world.entity.*;
import net.minecraft.world.entity.ai.attributes.AttributeSupplier;
import net.minecraft.world.entity.ai.attributes.Attributes;
import net.minecraft.world.entity.ai.goal.*;
import net.minecraft.world.entity.ai.goal.target.HurtByTargetGoal;
import net.minecraft.world.entity.ai.goal.target.NearestAttackableTargetGoal;
import net.minecraft.world.entity.ai.goal.target.ResetUniversalAngerTargetGoal;
import net.minecraft.world.entity.animal.*;
import net.minecraft.world.entity.monster.Zombie;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import net.minecraft.world.level.GameRules;
import net.minecraft.world.level.ItemLike;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.phys.Vec3;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import oshi.util.tuples.Pair;
import mymod._Entities;
import mymod._EntityDataSerializers;
import mymod._Items;
import mymod._Sounds;
import mymod.ai.ZombieAttackChickenEggGoal;
import mymod.entities.BredWithMobStorable;
import mymod.util.delayedtask.DelayedTask;
import mymod.util.delayedtask.DelayedTasksHolder;

import java.util.EnumSet;
import java.util.Optional;
import java.util.UUID;
import java.util.function.Supplier;

public class Rooster extends AbstractChicken implements NeutralMob, BredWithMobStorable,
        DelayedTasksHolder<Rooster> {

    private static final UniformInt PERSISTENT_ANGER_TIME
            = TimeUtil.rangeOfSeconds(60, 1800);

    private int remainingPersistentAngerTime;
    private UUID persistentAngerTarget;


    private boolean crowing;
    private int crowTicks;


    private int diggingAnimTicks;

    private int featherDropCoolDown;

    private static final EntityDataAccessor<FourFeathers> DATA_FEATHERS
            = SynchedEntityData.defineId(Rooster.class, _EntityDataSerializers.ROOSTER_FEATHERS.get());

    private static final EntityDataAccessor<Optional<UUID>> DATA_MOB_BRED_WITH
            = SynchedEntityData.defineId(Rooster.class, EntityDataSerializers.OPTIONAL_UUID);


    public Rooster(EntityType<? extends Rooster> entityType, Level world) {
        super(entityType, world);
    }

    @Override
    public int getRemainingPersistentAngerTime() {
        return remainingPersistentAngerTime;
    }

    @Override
    public void setRemainingPersistentAngerTime(int remainingPersistentAngerTime) {
        this.remainingPersistentAngerTime = remainingPersistentAngerTime;
    }

    @Nullable
    @Override
    public UUID getPersistentAngerTarget() {
        return persistentAngerTarget;
    }

    @Override
    public void setPersistentAngerTarget(@Nullable UUID persistentAngerTarget) {
        this.persistentAngerTarget = persistentAngerTarget;
    }

    @Override
    public void startPersistentAngerTimer() {
        setRemainingPersistentAngerTime(PERSISTENT_ANGER_TIME.sample(random));
    }

    @Override
    protected void defineSynchedData() {
        super.defineSynchedData();
        entityData.define(DATA_FEATHERS,
                new FourFeathers((byte) random.nextInt(3),
                        (byte) random.nextInt(3),
                        (byte) random.nextInt(3),
                        (byte) random.nextInt(3)));
        entityData.define(DATA_MOB_BRED_WITH, Optional.empty());

    }


    public FourFeathers getFeatherData() {
        return entityData.get(DATA_FEATHERS);
    }

    public void setFeatherData(FourFeathers featherData) {
        entityData.set(DATA_FEATHERS, featherData);
    }

    @Override
    public void addAdditionalSaveData(@NotNull CompoundTag nbt) {
        super.addAdditionalSaveData(nbt);
        addPersistentAngerSaveData(nbt);
        nbt.put("FeatherData", getFeatherData().writeTag());
        nbt.putBoolean("isCrowing", crowing);
    }

    @Override
    public void readAdditionalSaveData(@NotNull CompoundTag nbt) {
        super.readAdditionalSaveData(nbt);
        readPersistentAngerSaveData(level(), nbt);
        if (nbt.contains("FeatherData", Tag.TAG_COMPOUND))
            setFeatherData(FourFeathers.readTag(nbt.getCompound("FeatherData")));
        else
            setFeatherData(FourFeathers.NONE);

        crowing = nbt.contains("isCrowing", Tag.TAG_BYTE) && nbt.getBoolean("isCrowing");
    }

    @Override
    protected void registerGoals() {
        goalSelector.addGoal(0, new FloatGoal(this));
        goalSelector.addGoal(1, new MeleeAttackGoal(this, 1.4, true)); // I even have a MeleeAttackGoal, rooster just runs to player but not hurting him
        goalSelector.addGoal(1, new RoosterRandomTryFindFoodGoal());
        goalSelector.addGoal(2, new RoosterBreedGoal());
        goalSelector.addGoal(3, new TemptGoal(this, 1, FOOD_ITEMS, false));
        goalSelector.addGoal(5, new WaterAvoidingRandomStrollGoal(this, 1));
        goalSelector.addGoal(6, new LookAtPlayerGoal(this, Player.class, 6));
        goalSelector.addGoal(7, new RandomLookAroundGoal(this));
        targetSelector.addGoal(4, new RoosterRandomAttackNearbyRoosterGoal());
        targetSelector.addGoal(1, new NearestAttackableTargetGoal<>(this, LivingEntity.class,
                true, entity -> entity instanceof Fox
                                || (entity instanceof Ocelot ocelot && !ocelot.isBaby())
                                || (entity instanceof Cat cat && !cat.isBaby() && !cat.isTame())
                                || (entity instanceof Zombie zombie && zombie.goalSelector
                .getRunningGoals().anyMatch(wrappedGoal -> wrappedGoal.getGoal() instanceof ZombieAttackChickenEggGoal))
                                || isAngryAt(entity)));
        targetSelector.addGoal(2, new HurtByTargetGoal(this));
        targetSelector.addGoal(3, new ResetUniversalAngerTargetGoal<>(this, false));
    }

    @Override
    public void setMobBredWith(@Nullable UUID uuid) {
        entityData.set(DATA_MOB_BRED_WITH, Optional.ofNullable(uuid));
    }

    @Override
    @Nullable
    public UUID getMobBredWith() {
        return entityData.get(DATA_MOB_BRED_WITH).orElse(null);
    }

    // Goals
    class RoosterRandomAttackNearbyRoosterGoal extends NearestAttackableTargetGoal<Rooster> {
        RoosterRandomAttackNearbyRoosterGoal() {
            super(Rooster.this, Rooster.class, true);
        }

        @Override
        public boolean canUse() {
            return super.canUse() && random.nextInt(300) == 0;
        }

        @Override
        public boolean canContinueToUse() {
            return super.canContinueToUse() && mob.getLastHurtMob() != targetMob;
        }
    }

    class RoosterBreedGoal extends BreedGoal {

        RoosterBreedGoal() {
            super(Rooster.this, 1, Chicken.class);
        }

        @Override
        protected void breed() {
            ServerPlayer serverplayer = animal.getLoveCause();
            if (serverplayer == null && this.partner.getLoveCause() != null) {
                serverplayer = this.partner.getLoveCause();
            }

            if (serverplayer != null) {
                serverplayer.awardStat(Stats.ANIMALS_BRED);
                CriteriaTriggers.BRED_ANIMALS.trigger(serverplayer, this.animal, this.partner, null);
            }

            ((BredWithMobStorable) partner).setMobBredWith(animal.getUUID());
            ((BredWithMobStorable) animal).setMobBredWith(partner.getUUID());
            animal.setAge(6000);
            partner.setAge(6000);
            animal.resetLove();
            partner.resetLove();
            RandomSource randomsource = animal.getRandom();
            if (this.level.getGameRules().getBoolean(GameRules.RULE_DOMOBLOOT)) {
                this.level.addFreshEntity(new ExperienceOrb(this.level,
                        this.animal.getX(),
                        this.animal.getY(),
                        this.animal.getZ(),
                        randomsource.nextInt(7) + 1));
            }
        }
    }

    private static final DelayedTask<Rooster> CROW_LATER = new DelayedTask<>(30) {
        @Override
        protected void execute() {
            entity.crow();
        }
    };
    private static final DelayedTask<Rooster> ANGRY_CLUCK_LATER = new DelayedTask<>(30) {
        @Override
        protected void execute() {
            entity.playSound(_Sounds.ROOSTER_ANGRY_CLUCK.get());
        }
    };

    @Override
    public ImmutableList<DelayedTask<Rooster>> getTasks() {
        return ImmutableList.of(CROW_LATER, ANGRY_CLUCK_LATER);
    }


    class RoosterRandomTryFindFoodGoal extends Goal {

        private final Rooster rooster;
        private int tickCount;
        private int maxTickCount;
        private int lastDugTicks;
        private int roosterLastHurtByMobTimestamp;

        private double lookAtXOld,
                lookAtYOld,
                lookAtZOld;

        private Vec3 pos;

        private boolean didEndSuccessfully;

        private Vec3 lookingAtPos;


        private static final UniformInt POSSIBLE_MAX_TICK_COUNT
                = TimeUtil.rangeOfSeconds(4, 10);

        RoosterRandomTryFindFoodGoal() {
            super();
            this.rooster = Rooster.this;
            setFlags(EnumSet.of(Flag.LOOK));
        }

        @Override
        public boolean canUse() {
            return (isStandingOn(Blocks.GRASS_BLOCK)
                    || isStandingOn(Blocks.DIRT)
                    || isStandingOn(Blocks.PODZOL))
                   && rooster.random.nextInt(3000) == 20;
        }

        @Override
        public boolean canContinueToUse() {
            if (rooster.getLastHurtByMobTimestamp() != roosterLastHurtByMobTimestamp) {
                didEndSuccessfully = false;
                return false;
            } else if (tickCount >= maxTickCount) {
                didEndSuccessfully = true;
                return false;
            }
            return true;
        }

        @Override
        public boolean requiresUpdateEveryTick() {
            return true;
        }

        @Override
        public void start() {
            lastDugTicks = 20;
            roosterLastHurtByMobTimestamp = rooster.getLastHurtByMobTimestamp();
            lookAtXOld = rooster.getLookControl().getWantedX();
            lookAtYOld = rooster.getLookControl().getWantedY();
            lookAtZOld = rooster.getLookControl().getWantedZ();
            pos = new Vec3(rooster.position().toVector3f());
            lookingAtPos = rooster.position().subtract(0, 1, 0);
            rooster.getLookControl().setLookAt(lookingAtPos);
            maxTickCount = POSSIBLE_MAX_TICK_COUNT.sample(rooster.random);
        }

        @Override
        public void stop() {
            rooster.getLookControl().setLookAt(lookAtXOld, lookAtYOld, lookAtZOld);
            if (didEndSuccessfully) {
                int resultItemPercentage = rooster.random.nextInt(100);
                if (resultItemPercentage <= 1) {
                    rooster.spawnAtLocation(Items.DIAMOND, -1);
                    Rooster.ANGRY_CLUCK_LATER.startExecution(rooster);
                } else if (resultItemPercentage <= 5) {
                    rooster.spawnAtLocation(Items.GOLD_NUGGET, -1);
                    Rooster.ANGRY_CLUCK_LATER.startExecution(rooster);
                } else if (resultItemPercentage <= 20) {
                    Rooster.ANGRY_CLUCK_LATER.startExecution(rooster);
                } else {
                    rooster.spawnAtLocation(FOOD_ITEMS.getItems()[rooster.random.nextInt(
                            FOOD_ITEMS.getItems().length)], -1);
                    Rooster.CROW_LATER.startExecution(rooster);
                }
            }
        }

        @Override
        public void tick() {
            ++tickCount;
            rooster.getLookControl().setLookAt(lookingAtPos);
            rooster.getMoveControl().setWantedPosition(pos.x, pos.y, pos.z, rooster.getMoveControl().getSpeedModifier());
            if (lastDugTicks <= 0) {
                lastDugTicks = 20;
                rooster.diggingAnimTicks = 10;
                rooster.playSound(rooster.level().getBlockState(rooster.blockPosition().below())
                        .getSoundType(rooster.level(), rooster.blockPosition().below(), rooster)
                        .getHitSound());
            } else lastDugTicks--;
        }

        private boolean isStandingOn(Block block) {
            return rooster.level().getBlockState(rooster.blockPosition().below()).is(block);
        }
    }


    // Feather data storage
    @Immutable
    public record FourFeathers(@NotNull FeatherType first,
                               @NotNull FeatherType second, @NotNull FeatherType third, @NotNull FeatherType forth) {
        public static final FourFeathers NONE = new FourFeathers(FeatherType.NONE, FeatherType.NONE,
                FeatherType.NONE, FeatherType.NONE);

        public FourFeathers(byte first, byte second, byte third, byte forth) {
            this(FeatherType.fromByte(first),
                    FeatherType.fromByte(second),
                    FeatherType.fromByte(third),
                    FeatherType.fromByte(forth));
        }


        public @NotNull Pair<ItemStack, FourFeathers> removeRandom(RandomSource randomSource) {
            if (NONE.equals(this)) return new Pair<>(ItemStack.EMPTY, this);
            int randomNum = randomSource.nextInt(4);
            while (get(randomNum) == null) randomNum = randomSource.nextInt(4);
            ItemStack retVal0 = get(randomNum).getDefaultInstance();
            FourFeathers retVal1 = switch (randomNum) {
                case 0 -> new FourFeathers(FeatherType.NONE, second, third, forth);
                case 1 -> new FourFeathers(first, FeatherType.NONE, third, forth);
                case 2 -> new FourFeathers(first, second, FeatherType.NONE, forth);
                case 3 -> new FourFeathers(first, second, third, FeatherType.NONE);
                default -> null; // unreachable
            };
            return new Pair<>(retVal0, retVal1);
        }


        @Nullable
        public Item get(int i) {
            return (switch (i) {
                case 0 -> first;
                case 1 -> second;
                case 2 -> third;
                case 3 -> forth;
                default -> throw new IllegalStateException("Unexpected value: " + i);
            }).asItem();
        }


        // NBT Utils
        @NotNull
        public CompoundTag writeTag() {
            CompoundTag nbt = new CompoundTag();
            nbt.putString("first", first.name().toLowerCase());
            nbt.putString("second", second.name().toLowerCase());
            nbt.putString("third", third.name().toLowerCase());
            nbt.putString("forth", forth.name().toLowerCase());
            return nbt;
        }

        @NotNull
        public static FourFeathers readTag(@NotNull CompoundTag nbt) {
            return new FourFeathers(tryRead(nbt, "first"),
                    tryRead(nbt, "second"),
                    tryRead(nbt, "third"),
                    tryRead(nbt, "forth"));
        }

        private static FeatherType tryRead(CompoundTag tag, String toRead) {
            if (tag.contains(toRead, Tag.TAG_STRING)) {
                try {
                    return FeatherType.valueOf(tag.getString(toRead).toUpperCase());
                } catch (IllegalArgumentException e) {
                    return FeatherType.NONE;
                }
            }
            return FeatherType.NONE;
        }
    }

    public enum FeatherType implements ItemLike {
        RED(_Items.RED_FEATHER, (byte) 0),
        YELLOW(_Items.YELLOW_FEATHER, (byte) 1),
        GREEN(_Items.GREEN_FEATHER, (byte) 2),
        BLUE(_Items.BLUE_FEATHER, (byte) 3),
        NONE(() -> null, (byte) -1);

        private final Supplier<Item> itemSup;
        private final byte byteVal;

        FeatherType(Supplier<Item> itemSup, byte byteVal) {
            this.itemSup = itemSup;
            this.byteVal = byteVal;
        }

        public static FeatherType fromByte(byte item) {
            return switch (item) {
                case -1 -> NONE;
                case 0 -> RED;
                case 1 -> YELLOW;
                case 2 -> GREEN;
                case 3 -> BLUE;
                default -> throw new IllegalArgumentException("item: " + item);
            };
        }

        @Override
        public @Nullable Item asItem() {
            return itemSup.get();
        }

        public byte asByte() {
            return byteVal;
        }
    }

    // Sounds

    @Override
    protected SoundEvent getAmbientSound() {
        return _Sounds.ROOSTER_AMBIENT.get();
    }

    @Override
    protected SoundEvent getHurtSound(@NotNull DamageSource damageSource) {
        return _Sounds.ROOSTER_HURT.get();
    }

    @Override
    protected SoundEvent getDeathSound() {
        return _Sounds.ROOSTER_DEATH.get();
    }

    public static AttributeSupplier.Builder createAttributes() { // Maybe something's missing here?
        return createMobAttributes()
                .add(Attributes.ATTACK_DAMAGE, 2)
                .add(Attributes.MAX_HEALTH, 8)
                .add(Attributes.MOVEMENT_SPEED, .3);
    }


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

    @Override
    public boolean canMate(@NotNull Animal other) {
        if (this == other) return false;
        else if (!(other instanceof Chicken)) return false;
        else return isInLove() && other.isInLove();
    }

    @Override
    protected void doAIStep() {
        if (!level().isClientSide) {
            updatePersistentAnger((ServerLevel) level(), true);
        }
    }

    @Override
    public void setBaby(boolean baby) {
        if (baby) {
            Chick me = convertTo(_Entities.CHICK.get(), false);
            if (me != null) {
                me.setBoy(true);
            }
        }
    }

    @Override
    public @NotNull InteractionResult mobInteract(@NotNull Player player, @NotNull InteractionHand hand) {
        if (isFood(player.getItemInHand(hand))) {
            return super.mobInteract(player, hand);
        } else if (player.getItemInHand(hand) == ItemStack.EMPTY) {
            dropFeather(player);
            return InteractionResult.CONSUME;
        }
        return InteractionResult.PASS;
    }

    private void dropFeather(LivingEntity target) {
        Pair<ItemStack, FourFeathers> resFeathers = getFeatherData().removeRandom(random);
        setFeatherData(resFeathers.getB());
        if (resFeathers.getA() != null && featherDropCoolDown == 0) {
            spawnAtLocation(resFeathers.getA());
            playSound(SoundEvents.ITEM_PICKUP);
            setTarget(target);
            featherDropCoolDown = random.nextIntBetweenInclusive(20, 30);
        }
    }

    @Override
    public void setTarget(@Nullable LivingEntity target) {
        super.setTarget(target);
        if (target != null) {
            setPersistentAngerTarget(target.getUUID());
            startPersistentAngerTimer();
        }
    }


    public void crow() {
        if (!crowing) {
            crowing = true;
            crowTicks = 70;
            var lookControl = getLookControl();
            lookControl.setLookAt(lookControl.getWantedX(), position().y + .2, lookControl.getWantedZ());
            playSound(_Sounds.ROOSTER_CROW.get());
            level().getEntitiesOfClass(Chicken.class, getBoundingBox().inflate(20))
                    .forEach(chicken -> chicken.setTarget(this));
        }
    }

    public boolean isCrowing() {
        return crowing;
    }

    @Override
    public void tick() {
        super.tick();
        if (!level().isClientSide) {
            if (level().getDayTime() == 0L || level().getDayTime() % 24000L == 13000L)
                crow();
        }

        if (crowing && --crowTicks <= 0) {
            crowing = false;
        }
        if (diggingAnimTicks > 0) --diggingAnimTicks;
        if (featherDropCoolDown > 0) --featherDropCoolDown;
        tickTasks();
    }


    public int getDiggingAnimTicks() {
        return diggingAnimTicks;
    }

    @Override
    public boolean isBoy() {
        return true;
    }

}

 

Link to comment
Share on other sites

13 hours ago, LeeCrafts said:

While I cannot pinpoint what is preventing the rooster from damaging the player, try using a debugger and set a breakpoint in the MeleeAttackGoal class--in the tick() and/or checkAndPerformAttack() methods.

is the breakpoint saved when I create a .jar?

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



  • Recently Browsing

    • No registered users viewing this page.
  • Posts

    • I'm using Modrinth as a launcher for a forge modpack on 1.20.1, and can't diagnose the issue on the crash log myself. Have tried repairing the Minecraft instillation as well as removing a few mods that have been problematic for me in the past to no avail. Crash log is below, if any further information is necessary let me know. Thank you! https://paste.ee/p/k6xnS
    • Hey folks. I am working on a custom "Mecha" entity (extended from LivingEntity) that the player builds up from blocks that should get modular stats depending on the used blocks. e.g. depending on what will be used for the legs, the entity will have a different jump strength. However, something unexpected is happening when trying to override a few of LivingEntity's functions and using my new own "Mecha" specific fields: instead of their actual instance-specific value, the default value is used (0f for a float, null for an object...) This is especially strange as when executing with the same entity from a point in the code specific to the mecha entity, the correct value is used. Here are some code snippets to better illustrate what I mean: /* The main Mecha class, cut down for brevity */ public class Mecha extends LivingEntity { protected float jumpMultiplier; //somewhere later during the code when spawning the entity, jumpMultiplier is set to something like 1.5f //changing the access to public didn't help @Override //Overridden from LivingEntity, this function is only used in the jumpFromGround() function, used in the aiStep() function, used in the LivingEntity tick() function protected float getJumpPower() { //something is wrong with this function //for some reason I can't correctly access the fields and methods from the instanciated entity when I am in one of those overridden protected functions. this is very annoying LogUtils.getLogger().info(String.valueOf(this.jumpMultiplier))) //will print 0f return this.jumpMultiplier * super.getJumpPower(); } //The code above does not operate properly. Written as is, the entity will not jump, and adding debug logs shows that when executing the code, the value of this.jumpMultiplier is 0f //in contrast, it will be the correct value when done here: @Override public void tick() { super.tick(); //inherited LivingEntity logic //Custom logic LogUtils.getLogger().info(String.valueOf(this.jumpMultiplier))) //will print 1.5f } } My actual code is slightly different, as the jumpMuliplier is stored in another object (so I am calling "this.legModule.getJumpPower()" instead of the float), but even using a simple float exactly like in the code above didn't help. When running my usual code, the object I try to use is found to be null instead, leading to a crash from a nullPointerException. Here is the stacktrace of said crash: The full code can be viewed here. I have found a workaround in the case of jump strength, but have already found the same problem for another parameter I want to do, and I do not understand why the code is behaving as such, and I would very much like to be able to override those methods as intended - they seemed to work just fine like that for vanilla mobs... Any clues as to what may be happening here?
    • Please delete post. Had not noticed the newest edition for 1.20.6 which resolves the issue.
    • https://paste.ee/p/GTgAV Here's my debug log, I'm on 1.18.2 with forge 40.2.4 and I just want to get it to work!! I cant find any mod names in the error part and I would like some help from the pros!! I have 203 mods at the moment.
  • Topics

×
×
  • Create New...

Important Information

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