Jump to content

[1.20.1] Why my custom entity thinks that air is food


Recommended Posts

Posted (edited)

I checked my isFood() method:

@Override
public boolean isFood(@NotNull ItemStack item) {
    return FOOD_ITEMS.test(item);
}

the FOOD_ITEMS:

protected static final Ingredient FOOD_ITEMS // sorry for protected static lol
            = Ingredient.of(Items.WHEAT_SEEDS,
            Items.MELON_SEEDS, Items.PUMPKIN_SEEDS,
            Items.BEETROOT_SEEDS, Items.TORCHFLOWER_SEEDS, Items.PITCHER_POD);

and the Ingredient class, but nothing seems to tell Minecraft that air is a food item. 

Tell me if you need full entity code

Edited by btuh
Posted

Because air is good! :D Jokes aside, how can you tell that your mob is eating air? Like, there's an actual action in game that you can observe? Also show the full entity code, maybe there's something weird going on there as well

 

PS: don't bump posts, someone will eventually show up :D You should also consider asking questions in the discord server, wherre is more likely that you'll get a quick response

Don't blame me if i always ask for your help. I just want to learn to be better :)

Posted
37 minutes ago, JimiIT92 said:

Because air is good! :D Jokes aside, how can you tell that your mob is eating air? Like, there's an actual action in game that you can observe? Also show the full entity code, maybe there's something weird going on there as well

 

PS: don't bump posts, someone will eventually show up :D You should also consider asking questions in the discord server, wherre is more likely that you'll get a quick response

I created a temp command with this syntax:

/isfood <entity to check> <player to check the item in main hand or off hand>

It outputs either string respiration of an ItemStack (<count of items> <item name>) that player holds in his hand if it's a food item for specified entity, or "none" if specified player isn't holding an item which is a food item for the specified entity.

Command's code if you didn't understand:

event.getDispatcher().register(Commands.literal("isfood").then(Commands.argument("animal", EntityArgument.entity())
                        .then(Commands.argument("player",
                                EntityArgument.player()).executes(context -> {
                            Entity entity = EntityArgument.getEntity(context, "animal");
                            Player player = EntityArgument.getPlayer(context, "player");
                            if (entity instanceof Animal mob) {
                                if (mob.isFood(player.getItemInHand(InteractionHand.MAIN_HAND)))
                                    context.getSource().sendSuccess(() ->
                                                    Component.literal(String.valueOf(
                                                            player.getItemInHand(InteractionHand.MAIN_HAND))),
                                            true);
                                else if (mob.isFood(player.getItemInHand(InteractionHand.OFF_HAND)))
                                    context.getSource().sendSuccess(() ->
                                            Component.literal(String.valueOf(
                                                    player.getItemInHand(InteractionHand.OFF_HAND)
                                            )), true);
                                else
                                    context.getSource().sendSuccess(() ->
                                            Component.literal("none"), true);
                            }
                            return 1;
                        }))));

So, I tested it on my entity, and command output was:

0 air

(also want to say that it happens only if I play Minecraft for a long time)

Anyways, the entity code:

package mymod.entities.chicken;

import net.minecraft.core.BlockPos;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.sounds.SoundEvent;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.util.Mth;
import net.minecraft.util.RandomSource;
import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.world.entity.*;
import net.minecraft.world.entity.animal.Animal;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import net.minecraft.world.item.crafting.Ingredient;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.pathfinder.BlockPathTypes;
import net.minecraft.world.phys.Vec3;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import mymod._Entities;


public abstract class AbstractChicken extends Animal implements IAbstractChicken {

    protected static final Ingredient FOOD_ITEMS
            = Ingredient.of(Items.WHEAT_SEEDS,
            Items.MELON_SEEDS, Items.PUMPKIN_SEEDS,
            Items.BEETROOT_SEEDS, Items.TORCHFLOWER_SEEDS, Items.PITCHER_POD);

    public float flap;
    public float flapSpeed;
    public float oFlapSpeed;
    public float oFlap;
    public float flapping = 1.0F;
    protected float nextFlap = 1.0F;

    protected AbstractChicken(EntityType<? extends AbstractChicken> entityType, Level world) {
        super(entityType, world);
        setPathfindingMalus(BlockPathTypes.WATER, 0.0F);
    }

    protected SoundEvent getAmbientSound() {
        return SoundEvents.CHICKEN_AMBIENT;
    }

    protected SoundEvent getHurtSound(@NotNull DamageSource damageSource) {
        return SoundEvents.CHICKEN_HURT;
    }

    protected SoundEvent getDeathSound() {
        return SoundEvents.CHICKEN_DEATH;
    }

    @Override
    protected void playStepSound(@NotNull BlockPos atPos,
                                 @NotNull BlockState atState) {
        playSound(SoundEvents.CHICKEN_STEP, .15f, 1);
    }

    @Nullable
    @Override
    public AgeableMob getBreedOffspring(@NotNull ServerLevel level,
                                        @NotNull AgeableMob mobBredWith) {
        return null;
    }

    @Override
    protected abstract void registerGoals();

    @Override
    public abstract boolean isBaby();

    @Override
    public abstract boolean canMate(@NotNull Animal other);

    @Override
    public final void aiStep() {
        super.aiStep();
        this.oFlap = flap;
        this.oFlapSpeed = flapSpeed;
        this.flapSpeed += (this.onGround() ? -1.0F : 4.0F) * 0.3F;
        this.flapSpeed = Mth.clamp(this.flapSpeed, 0.0F, 1.0F);
        if (!this.onGround() && this.flapping < 1.0F) {
            this.flapping = 1.0F;
        }
        this.flapping *= 0.9F;
        Vec3 vec3 = this.getDeltaMovement();
        if (!this.onGround() && vec3.y < 0.0D) {
            this.setDeltaMovement(vec3.multiply(1.0D, 0.6D, 1.0D));
        }
        this.flap += this.flapping * 2.0F;
        doAIStep();
    }

    protected abstract void doAIStep();


    @Override
    protected float getStandingEyeHeight(@NotNull Pose pose, @NotNull EntityDimensions dimensions) {
        return this.isBaby() ? dimensions.height * 0.85F : dimensions.height * 0.92F;
    }

    @Override
    public abstract void setBaby(boolean baby);


    @Override
    @Nullable
    public <T extends Mob> T convertTo(@NotNull EntityType<T> toType, boolean copyInventory) {
        if (isRemoved()) {
            return null;
        } else {
            T t = toType.create(level());
            if (t == null) {
                return null;
            } else {
                t.copyPosition(this);
                t.setNoAi(isNoAi());
                if (!(toType == EntityType.CHICKEN
                      || toType == _Entities.ROOSTER.get()
                      || toType == _Entities.CHICK.get())) t.setBaby(isBaby());
                if (hasCustomName()) {
                    t.setCustomName(getCustomName());
                    t.setCustomNameVisible(isCustomNameVisible());
                }

                if (isPersistenceRequired()) {
                    t.setPersistenceRequired();
                }

                t.setInvulnerable(isInvulnerable());
                if (copyInventory) {
                    t.setCanPickUpLoot(canPickUpLoot());

                    for (EquipmentSlot equipmentslot : EquipmentSlot.values()) {
                        ItemStack itemstack = self().getItemBySlot(equipmentslot);
                        if (!itemstack.isEmpty()) {
                            t.setItemSlot(equipmentslot, itemstack.copyAndClear());
                            t.setDropChance(equipmentslot, getEquipmentDropChance(equipmentslot));
                        }
                    }
                }

                level().addFreshEntity(t);
                if (isPassenger()) {
                    Entity entity = getVehicle();
                    stopRiding();
                    t.startRiding(entity, true);
                }

                discard();
                return t;
            }
        }
    }

    public abstract boolean isBoy();

    @Override
    public boolean isFood(@NotNull ItemStack item) {
        return FOOD_ITEMS.test(item);
    }


    @Override
    protected boolean isFlapping() {
        return flyDist > nextFlap;
    }

    @Override
    protected void onFlap() {
        nextFlap = flyDist + flapSpeed / 2f;
    }

    public static boolean canSpawn(EntityType<? extends AbstractChicken> entityType,
                                   LevelAccessor level,
                                   MobSpawnType spawnType,
                                   BlockPos pos,
                                   RandomSource random) {
        return entityType != _Entities.CHICK.get()
               && Animal.checkAnimalSpawnRules(entityType, level, spawnType, pos, random);
    }
}
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.DifficultyInstance;
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.ServerLevelAccessor;
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 ru.fokinatorr.chickenmod._Entities;
import ru.fokinatorr.chickenmod._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() {
        this.remainingPersistentAngerTime = PERSISTENT_ANGER_TIME.sample(random);
    }

    @Override
    protected void defineSynchedData() {
        super.defineSynchedData();
        entityData.define(DATA_FEATHERS, FourFeathers.NONE);
        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 RoosterMeleeAttackGoal());
        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 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 RoosterMeleeAttackGoal extends MeleeAttackGoal {

        RoosterMeleeAttackGoal() {
            super(Rooster.this, 1.4, true);
        }

        @Override
        public void tick() {
            super.tick();
            if (mob.getTarget() != null && mob.distanceToSqr(mob.getTarget()) <= 4) mob.getJumpControl().jump();
        }
    }

    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 fourth)
    {
        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, fourth);
                case 1 -> new FourFeathers(first, FeatherType.NONE, third, fourth);
                case 2 -> new FourFeathers(first, second, FeatherType.NONE, fourth);
                case 3 -> new FourFeathers(first, second, third, FeatherType.NONE);
                default -> null; // unreachable
            };
            return new Pair<>(retVal0, retVal1);
        }

        public void dropAll(Rooster asRooster) {
            asRooster.setFeatherData(FourFeathers.NONE);
            if (first != FeatherType.NONE) asRooster.spawnAtLocation(first);
            if (second != FeatherType.NONE) asRooster.spawnAtLocation(second);
            if (third != FeatherType.NONE) asRooster.spawnAtLocation(third);
            if (fourth != FeatherType.NONE) asRooster.spawnAtLocation(fourth);
        }


        @Nullable
        public Item get(int i) {
            return (switch (i) {
                case 0 -> first;
                case 1 -> second;
                case 2 -> third;
                case 3 -> fourth;
                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("fourth", fourth.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, "fourth"));
        }

        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 FourFeathers copy() {
            return new FourFeathers(first, second, third, fourth);
        }
    }

    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;
        }
    }

    @Override
    protected void dropCustomDeathLoot(@NotNull DamageSource damageSource, int what, boolean idk) {
        super.dropCustomDeathLoot(damageSource, what, idk);
        getFeatherData().dropAll(this);
    }


    // 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() {
        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
    @Nullable
    public SpawnGroupData finalizeSpawn(@NotNull ServerLevelAccessor worldAccessor,
                                        @NotNull DifficultyInstance difficulty,
                                        @NotNull MobSpawnType mobSpawnType,
                                        @Nullable SpawnGroupData retVal,
                                        @Nullable CompoundTag nbt) {
        if (nbt == null) {
            setFeatherData(new FourFeathers((byte) random.nextIntBetweenInclusive(-1, 3),
                    (byte) random.nextIntBetweenInclusive(-1, 3),
                    (byte) random.nextIntBetweenInclusive(-1, 3),
                    (byte) random.nextIntBetweenInclusive(-1, 3)));
        } else {
            if (nbt.contains("FeatherData", Tag.TAG_COMPOUND)) {
                setFeatherData(FourFeathers.readTag(nbt.getCompound("FeatherData")));
            }
        }
        return super.finalizeSpawn(worldAccessor, difficulty, mobSpawnType, retVal, nbt);
    }

    @Override
    protected void doAIStep() {
        if (crowing && --crowTicks <= 0) {
            crowing = false;
        }
        if (!level().isClientSide) {
            updatePersistentAnger((ServerLevel) level(), true);
            if (level().getDayTime() % 24000L == 0L || level().getDayTime() % 24000L == 13000L)
                crow();
        }
    }

    @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(@Nullable LivingEntity target) {
        Pair<ItemStack, FourFeathers> resFeathers = getFeatherData().removeRandom(random);
        setFeatherData(resFeathers.getB());
        if (resFeathers.getA() != null && featherDropCoolDown == 0 && target != null) {
            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 (diggingAnimTicks > 0) --diggingAnimTicks;
        if (featherDropCoolDown > 0) --featherDropCoolDown;
        tickTasks();
    }


    public int getDiggingAnimTicks() {
        return diggingAnimTicks;
    }

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

}
package mymod.entities.chicken;

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.sounds.SoundEvent;
import net.minecraft.world.DifficultyInstance;
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.animal.Animal;
import net.minecraft.world.entity.animal.Chicken;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.ServerLevelAccessor;
import net.minecraft.world.phys.AABB;
import org.jetbrains.annotations.NotNull;
import mymod._Entities;
import mymod._Sounds;

import org.jetbrains.annotations.Nullable;

import java.util.ArrayList;
import java.util.List;

public class Chick extends AbstractChicken {


    private static final EntityDataAccessor<Boolean> DATA_IS_BOY
            = SynchedEntityData.defineId(Chick.class, EntityDataSerializers.BOOLEAN);

    private final boolean initializedIsBoy;


    public Chick(EntityType<? extends Chick> entityType, Level world) {
        super(entityType, world);
        setAge(-24000);
        initializedIsBoy = false;
    }


    public Chick(EntityType<? extends Chick> entityType, Level world, boolean isBoy) {
        super(entityType, world);
        setAge(-24000);
        setBoy(isBoy);
        initializedIsBoy = true;
    }


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

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


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

    @Override
    public float getVoicePitch() {
        return (this.random.nextFloat() - this.random.nextFloat()) * 0.2F + 1.0F;
    }

    @Override
    protected void defineSynchedData() {
        super.defineSynchedData();
        entityData.define(DATA_IS_BOY, false);
    }

    @Override
    public void addAdditionalSaveData(@NotNull CompoundTag nbt) {
        super.addAdditionalSaveData(nbt);
        nbt.putBoolean("IsBoy", isBoy());
    }


    @Override
    public void readAdditionalSaveData(@NotNull CompoundTag nbt) {
        super.readAdditionalSaveData(nbt);
        if (nbt.contains("IsBoy", Tag.TAG_BYTE)) setBoy(nbt.getBoolean("IsBoy"));
    }

    @Override
    protected void registerGoals() {
        goalSelector.addGoal(0, new FloatGoal(this));
        goalSelector.addGoal(1, new PanicGoal(this, 1.4));
        goalSelector.addGoal(2, new TemptGoal(this, 1, FOOD_ITEMS, false));
        goalSelector.addGoal(3, new ChickFollowParentGoal());
        goalSelector.addGoal(5, new WaterAvoidingRandomStrollGoal(this, 1));
        goalSelector.addGoal(6, new LookAtPlayerGoal(this, Player.class, 6));
        goalSelector.addGoal(7, new RandomLookAroundGoal(this));
    }


    @Override
    public void setLastHurtByMob(LivingEntity hurtByMob) {
        super.setLastHurtByMob(hurtByMob);
        if (getType() == _Entities.CHICK.get() && hurtByMob != null) {
            level().getEntitiesOfClass(Rooster.class,
                            new AABB(blockPosition().below(20).north(20).west(20),
                                    blockPosition().above(20).south(20).east(20)))
                    .stream()
                    .filter(r -> r.getPersistentAngerTarget() == null && r.getTarget() == null)
                    .forEach(r -> r.setTarget(hurtByMob));
        }
    }


    @Override
    public SpawnGroupData finalizeSpawn(@NotNull ServerLevelAccessor worldAccessor,
                                        @NotNull DifficultyInstance difficulty,
                                        @NotNull MobSpawnType mobSpawnType,
                                        @Nullable SpawnGroupData retVal,
                                        @Nullable CompoundTag nbt) {
        if (!initializedIsBoy) {
            if (nbt != null && nbt.contains("IsBoy", Tag.TAG_BYTE))
                setBoy(nbt.getBoolean("IsBoy"));
            else
                setBoy(random.nextBoolean());
        }
        return super.finalizeSpawn(worldAccessor, difficulty, mobSpawnType, retVal, nbt);
    }

    class ChickFollowParentGoal extends Goal {

        private Animal parent;
        private int timeToRecalculatePath;

        @Override
        public boolean canUse() {
            List<Animal> list = new ArrayList<>();
            list.addAll(level().getEntitiesOfClass(Chicken.class,
                    getBoundingBox().inflate(8, 4, 8)));
            list.addAll(level().getEntitiesOfClass(Rooster.class,
                    getBoundingBox().inflate(8, 4, 8)));
            Animal animal = null;
            double d0 = Double.MAX_VALUE;

            for (Animal animal1 : list) {
                if (animal1.getAge() >= 0) {
                    double d1 = distanceToSqr(animal1);
                    if (!(d1 > d0)) {
                        d0 = d1;
                        animal = animal1;
                    }
                }
            }

            if (animal == null) {
                return false;
            } else if (d0 < 9.0D) {
                return false;
            } else {
                parent = animal;
                return true;
            }
        }

        @Override
        public boolean canContinueToUse() {
            if (!parent.isAlive()) return false;
            double d = distanceToSqr(parent);
            return !(d < 9) && !(d > 256);
        }


        @Override
        public void start() {
            timeToRecalculatePath = 0;
        }

        @Override
        public void stop() {
            parent = null;
        }

        @Override
        public void tick() {
            if (--timeToRecalculatePath <= 0) {
                timeToRecalculatePath = adjustedTickDelay(10);
                getNavigation().moveTo(parent, 1.1);
            }
        }
    }


    public static AttributeSupplier.Builder createAttributes() {
        return createMobAttributes()
                .add(Attributes.MAX_HEALTH, 4)
                .add(Attributes.MOVEMENT_SPEED, .25);
    }

    @Override
    public void ageBoundaryReached() {
        super.ageBoundaryReached();
        if (getAge() >= 0) {
            if (isBoy())
                convertTo(_Entities.ROOSTER.get(), false);
            else
                convertTo(EntityType.CHICKEN, false);
        }
    }

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

    @Override
    public boolean canMate(@NotNull Animal other) {
        return false;
    }

    @Override
    public void setBoy(boolean newBoolean) {
        entityData.set(DATA_IS_BOY, newBoolean);
    }

    @Override
    protected void doAIStep() {

    }

    @Override
    public void setBaby(boolean baby) {
        if (!baby) {
            if (isBoy()) {
                convertTo(_Entities.ROOSTER.get(), false);
            } else {
                convertTo(EntityType.CHICKEN, false);
            }
        }
    }

    @Override
    public boolean isBoy() {
        return entityData.get(DATA_IS_BOY);
    }
}

sorry for too long post lol

Posted (edited)

It might just be a misleading log, if you run the command while debugging what's the outcome? 
I've tried checking the item inside the RightClickBlock event and it works just fine

private static final Ingredient FOOD_ITEMS = Ingredient.of(Items.WHEAT_SEEDS, Items.MELON_SEEDS, Items.PUMPKIN_SEEDS, Items.BEETROOT_SEEDS, Items.TORCHFLOWER_SEEDS, Items.PITCHER_POD);

@SubscribeEvent
public static void onRightClickBlock(final PlayerInteractEvent.RightClickBlock event) {
	final ItemStack itemStack = event.getItemStack();
    LOGGER.info(FOOD_ITEMS.test(itemStack) + "");
}

When I right click a block with an Item it checks if is one of the ingredients of FOOD_ITEMS. Clicking with an empty hand (air) logs false, as expected.

Tip: please use the "spoiler" tags for long code snippets and don't merge all your classes into one code snippet

EDIT: just noticed you are on 1.20.1. Maybe is just a bug with the Forge version? Try update to the latest Forge 1.20.2 and see if it still occurs

Edited by JimiIT92

Don't blame me if i always ask for your help. I just want to learn to be better :)

Posted (edited)
23 hours ago, JimiIT92 said:

It might just be a misleading log, if you run the command while debugging what's the outcome? 
I've tried checking the item inside the RightClickBlock event and it works just fine

private static final Ingredient FOOD_ITEMS = Ingredient.of(Items.WHEAT_SEEDS, Items.MELON_SEEDS, Items.PUMPKIN_SEEDS, Items.BEETROOT_SEEDS, Items.TORCHFLOWER_SEEDS, Items.PITCHER_POD);

@SubscribeEvent
public static void onRightClickBlock(final PlayerInteractEvent.RightClickBlock event) {
	final ItemStack itemStack = event.getItemStack();
    LOGGER.info(FOOD_ITEMS.test(itemStack) + "");
}

When I right click a block with an Item it checks if is one of the ingredients of FOOD_ITEMS. Clicking with an empty hand (air) logs false, as expected.

Tip: please use the "spoiler" tags for long code snippets and don't merge all your classes into one code snippet

EDIT: just noticed you are on 1.20.1. Maybe is just a bug with the Forge version? Try update to the latest Forge 1.20.2 and see if it still occurs

I didn't yet see this happening on 1.20.2 forge, but sadly, I noticed that my mod is incompatible with this version because of this event handler:

@SubscribeEvent
    public static void onPlayerRightClickItem(PlayerInteractEvent.RightClickItem e) {
        if (e.getItemStack().getItem() instanceof EggItem) {
            List<ThrownEgg> eggs = e.getLevel().getEntitiesOfClass(ThrownEgg.class,
                    new AABB(e.getEntity().blockPosition().immutable()
                            .below(5)
                            .north(5)
                            .west(5),
                            e.getEntity().blockPosition().immutable()
                                    .above(10)
                                    .south(5)
                                    .east(5)));
            if (!eggs.isEmpty()) {
                eggs.forEach(ThrownEgg::discard);
                if (!e.getEntity().getAbilities().instabuild)
                    e.getItemStack().grow(1);
            }


            if (!e.getEntity().level().isClientSide) {
                ((ServerPlayer) e.getEntity()).connection.send(
                        new ClientboundStopSoundPacket(SoundEvents.EGG_THROW.getLocation(),
                                SoundSource.PLAYERS)); // Minecraft Forge 1.20.2 crashes because of NoSuchMethodError here
            }
            e.setCancellationResult(InteractionResult.SUCCESS);
            e.setCanceled(true);
        }
    }

 

Edited by btuh
Posted

Also why roosters don't spawn naturally

Shouldn't this do the thing?

// CommonModEvents
@SubscribeEvent
public static void registerSpawnPlacements(SpawnPlacementRegisterEvent e) {
    e.register(_Entities.ROOSTER.get(), ON_GROUND, WORLD_SURFACE, AbstractChicken::canSpawn, AND);
}

 

public static boolean canSpawn(EntityType<? extends AbstractChicken> entityType,
                               LevelAccessor level,
                               MobSpawnType spawnType,
                               BlockPos pos,
                               RandomSource random) {
    return entityType != _Entities.CHICK.get()
           && Animal.checkAnimalSpawnRules(entityType, level, spawnType, pos, random);
}

 

 

 

Posted (edited)
On 12/5/2023 at 2:13 PM, JimiIT92 said:

It might just be a misleading log, if you run the command while debugging what's the outcome? 
I've tried checking the item inside the RightClickBlock event and it works just fine

private static final Ingredient FOOD_ITEMS = Ingredient.of(Items.WHEAT_SEEDS, Items.MELON_SEEDS, Items.PUMPKIN_SEEDS, Items.BEETROOT_SEEDS, Items.TORCHFLOWER_SEEDS, Items.PITCHER_POD);

@SubscribeEvent
public static void onRightClickBlock(final PlayerInteractEvent.RightClickBlock event) {
	final ItemStack itemStack = event.getItemStack();
    LOGGER.info(FOOD_ITEMS.test(itemStack) + "");
}

When I right click a block with an Item it checks if is one of the ingredients of FOOD_ITEMS. Clicking with an empty hand (air) logs false, as expected.

Tip: please use the "spoiler" tags for long code snippets and don't merge all your classes into one code snippet

EDIT: just noticed you are on 1.20.1. Maybe is just a bug with the Forge version? Try update to the latest Forge 1.20.2 and see if it still occurs

Okay it doesn't happen anymore I think, but now I have two more problems that I posted before this one

Edited by btuh
Posted
On 12/5/2023 at 12:45 PM, btuh said:
((ServerPlayer) e.getEntity()).connection.send(
                        new ClientboundStopSoundPacket(SoundEvents.EGG_THROW.getLocation(),
                                SoundSource.PLAYERS)); // Minecraft Forge 1.20.2 crashes because of NoSuchMethodError here

Why are you doing this instead of just playing the sound using the level or the player method? 

Don't blame me if i always ask for your help. I just want to learn to be better :)

Posted
On 12/8/2023 at 2:22 AM, JimiIT92 said:

Why are you doing this instead of just playing the sound using the level or the player method? 

I'm stopping it (as it's done it StopsoundCommand class)

Posted
On 12/5/2023 at 2:13 PM, JimiIT92 said:

It might just be a misleading log, if you run the command while debugging what's the outcome? 
I've tried checking the item inside the RightClickBlock event and it works just fine

private static final Ingredient FOOD_ITEMS = Ingredient.of(Items.WHEAT_SEEDS, Items.MELON_SEEDS, Items.PUMPKIN_SEEDS, Items.BEETROOT_SEEDS, Items.TORCHFLOWER_SEEDS, Items.PITCHER_POD);

@SubscribeEvent
public static void onRightClickBlock(final PlayerInteractEvent.RightClickBlock event) {
	final ItemStack itemStack = event.getItemStack();
    LOGGER.info(FOOD_ITEMS.test(itemStack) + "");
}

When I right click a block with an Item it checks if is one of the ingredients of FOOD_ITEMS. Clicking with an empty hand (air) logs false, as expected.

Tip: please use the "spoiler" tags for long code snippets and don't merge all your classes into one code snippet

EDIT: just noticed you are on 1.20.1. Maybe is just a bug with the Forge version? Try update to the latest Forge 1.20.2 and see if it still occurs

I tried it, and when roosters started following me, I clicked a block with empty hand and it logged (air false). So the Ingredient class is totally not the issue, I guess so.

Posted
22 hours ago, btuh said:

I'm stopping it (as it's done it StopsoundCommand class)

Ah I see, haven't noticed that 😅

Don't blame me if i always ask for your help. I just want to learn to be better :)

Posted
On 12/5/2023 at 7:11 PM, btuh said:

Also why roosters don't spawn naturally

Shouldn't this do the thing?

// CommonModEvents
@SubscribeEvent
public static void registerSpawnPlacements(SpawnPlacementRegisterEvent e) {
    e.register(_Entities.ROOSTER.get(), ON_GROUND, WORLD_SURFACE, AbstractChicken::canSpawn, AND);
}

 

public static boolean canSpawn(EntityType<? extends AbstractChicken> entityType,
                               LevelAccessor level,
                               MobSpawnType spawnType,
                               BlockPos pos,
                               RandomSource random) {
    return entityType != _Entities.CHICK.get()
           && Animal.checkAnimalSpawnRules(entityType, level, spawnType, pos, random);
}

 

 

 

Have you ever had issues with this?

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

    • New users at Temureceive a 40 Off discount on orders over 40 Off Use the code [acx318439] during checkout to get TemuDiscount 40 Off For New Users. You n save 40 Off off your first order with the Promo Code available for a limited time only. Extra 30% off for new and existing customers + Up to $40 Off % off & more. Temu Promo Codes for New users- [acx318439] Temudiscount code for New customers- [acx318439] Temu $40 Off Promo Code- [acx318439] what are Temu codes- acx318439 does Temu give you $40 Off - [acx318439] Yes Verified Temu Promo Code january 2025- {acx318439} TemuNew customer offer {acx318439} Temudiscount codejanuary 2025 {acx318439} 40 off Promo Code Temu {acx318439} Temu 40% off any order {acx318439} 40 dollar off Temu code {acx318439} TemuCoupon $40 Off off for New customers There are a number of discounts and deals shoppers n take advantage of with the Teemu Coupon Bundle [acx318439]. TemuCoupon $40 Off off for New customers [acx318439] will save you $40 Off on your order. To get a discount, click on the item to purchase and enter the code. You n think of it as a supercharged savings pack for all your shopping needs Temu Promo Code 80% off – [acx318439] Free Temu codes 50% off – [acx318439] TemuCoupon $40 Off off – [acx318439] Temu buy to get ₱39 – [acx318439] Temu 129 coupon bundle – [acx318439] Temu buy 3 to get €99 – [acx318439] Exclusive $40 Off Off TemuDiscount Code Temu $40 Off Off Promo Code : (acx318439) Temu Discount Code $40 Off Bundle acx318439) acx318439 Temu $40 Off off Promo Code for Exsting users : acx318439) Temu Promo Code $40 Off off Temu 40 Off coupon code (acx318439) will save you 40 Off on your order. To get a discount, click on the item to purchase and enter the code. Yes, Temu offers 40 Off Coupon Code “acx318439” for Existing Customers.  You can get a 40 Off bonus plus 30% off any purchase at Temu with the 40 Off Coupon Bundle at Temu if you sign up with the referral code [acx318439] and make a first purchase of $40 Off or more. Temu Promo Code 40 off-{acx318439} Temu Promo Code -{acx318439} Temu Promo Code $40 Off off-{acx318439} kubonus code -{acx318439} Get ready to unlock a world of savings with our free Temu UK coupons! We’ve got you covered with a wide range of Temu UK coupon code options that will help you maximize your shopping experience.30% Off Temu UK Coupons, Promo Codes + 25% Cash Back [ acx318439]   Yes, Temu offers 40 off coupon code {acx318439} for first-time users. You can get a $40 bonus plus 40% off any purchase at Temu with the $40 Coupon Bundle if you sign up with the referral code [acx318439] and make a first purchase of $40 or more. If you are who wish to join Temu, then you should use this exclusive TemuCoupon code 40 off (acx318439) and get 40 off on your purchase with Temu. You can get a 40% discount with TemuCoupon code {acx318439}. This exclusive offer is for existing customers and can be used for a 40 reduction on your total purchase. Enter coupon code {acx318439} at checkout to avail of the discount. You can use the code {acx318439} to get a 40 off TemuCoupon as a new customer. Apply this TemuCoupon code $40 off (acx318439) to get a $40 discount on your shopping with Temu. If you’re a first-time user and looking for a TemuCoupon code $40 first time user(acx318439) then using this code will give you a flat $40 Off and a 90% discount on your Temu shopping.     •    acx318439: Enjoy flat 40% off on your first Temu order.     •    acx318439: Download the Temu app and get an additional 40% off.     •    acx318439: Celebrate spring with up to 90% discount on selected items.     •    acx318439: Score up to 90% off on clearance items.     •    acx318439: Beat the heat with hot summer savings of up to 90% off.     •    acx318439: Temu UK Coupon Code to 40% off on Appliances at Temu. How to Apply Temu Coupon Code? Using the TemuCoupon code $40 off is a breeze. All you need to do is follow these simple steps:     1    Visit the Temu website or app and browse through the vast collection of products.     2    Once you’ve added the items you wish to purchase to your cart, proceed to the checkout page.     3    During the checkout process, you’ll be prompted to enter a coupon code or promo code.     4    Type in the coupon code: [acx318439] and click “Apply.”     5    Voila! You’ll instantly see the $40 discount reflected in your total purchase amount. Temu New User Coupon: Up To 90% OFF For Existing Customers Temu Existing customer’s coupon codes are designed just for new customers, offering the biggest discounts 90% and the best deals currently available on Temu. To maximize your savings, download the Temu app and apply our Temu new user coupon during checkout.     •    acx318439: New users can get up to 80% extra off.     •    acx318439: Get a massive 40% off your first order!     •    acx318439: Get 20% off on your first order; no minimum spending required.     •    acx318439: Take an extra 15% off your first order on top of existing discounts.     •    acx318439: Temu UK Enjoy a 40% discount on your entire first purchase.  
    • New users at Temureceive a 40 Off discount on orders over 40 Off Use the code [acx318439] during checkout to get TemuDiscount 40 Off For New Users. You n save 40 Off off your first order with the Promo Code available for a limited time only. Extra 30% off for new and existing customers + Up to $40 Off % off & more. Temu Promo Codes for New users- [acx318439] Temudiscount code for New customers- [acx318439] Temu $40 Off Promo Code- [acx318439] what are Temu codes- acx318439 does Temu give you $40 Off - [acx318439] Yes Verified Temu Promo Code january 2025- {acx318439} TemuNew customer offer {acx318439} Temudiscount codejanuary 2025 {acx318439} 40 off Promo Code Temu {acx318439} Temu 40% off any order {acx318439} 40 dollar off Temu code {acx318439} TemuCoupon $40 Off off for New customers There are a number of discounts and deals shoppers n take advantage of with the Teemu Coupon Bundle [acx318439]. TemuCoupon $40 Off off for New customers [acx318439] will save you $40 Off on your order. To get a discount, click on the item to purchase and enter the code. You n think of it as a supercharged savings pack for all your shopping needs Temu Promo Code 80% off – [acx318439] Free Temu codes 50% off – [acx318439] TemuCoupon $40 Off off – [acx318439] Temu buy to get ₱39 – [acx318439] Temu 129 coupon bundle – [acx318439] Temu buy 3 to get €99 – [acx318439] Exclusive $40 Off Off TemuDiscount Code Temu $40 Off Off Promo Code : (acx318439) Temu Discount Code $40 Off Bundle acx318439) acx318439 Temu $40 Off off Promo Code for Exsting users : acx318439) Temu Promo Code $40 Off off Temu 40 Off coupon code (acx318439) will save you 40 Off on your order. To get a discount, click on the item to purchase and enter the code. Yes, Temu offers 40 Off Coupon Code “acx318439” for Existing Customers.  You can get a 40 Off bonus plus 30% off any purchase at Temu with the 40 Off Coupon Bundle at Temu if you sign up with the referral code [acx318439] and make a first purchase of $40 Off or more. Temu Promo Code 40 off-{acx318439} Temu Promo Code -{acx318439} Temu Promo Code $40 Off off-{acx318439} kubonus code -{acx318439} Get ready to unlock a world of savings with our free Temu UK coupons! We’ve got you covered with a wide range of Temu UK coupon code options that will help you maximize your shopping experience.30% Off Temu UK Coupons, Promo Codes + 25% Cash Back [ acx318439]   Yes, Temu offers 40 off coupon code {acx318439} for first-time users. You can get a $40 bonus plus 40% off any purchase at Temu with the $40 Coupon Bundle if you sign up with the referral code [acx318439] and make a first purchase of $40 or more. If you are who wish to join Temu, then you should use this exclusive TemuCoupon code 40 off (acx318439) and get 40 off on your purchase with Temu. You can get a 40% discount with TemuCoupon code {acx318439}. This exclusive offer is for existing customers and can be used for a 40 reduction on your total purchase. Enter coupon code {acx318439} at checkout to avail of the discount. You can use the code {acx318439} to get a 40 off TemuCoupon as a new customer. Apply this TemuCoupon code $40 off (acx318439) to get a $40 discount on your shopping with Temu. If you’re a first-time user and looking for a TemuCoupon code $40 first time user(acx318439) then using this code will give you a flat $40 Off and a 90% discount on your Temu shopping.     •    acx318439: Enjoy flat 40% off on your first Temu order.     •    acx318439: Download the Temu app and get an additional 40% off.     •    acx318439: Celebrate spring with up to 90% discount on selected items.     •    acx318439: Score up to 90% off on clearance items.     •    acx318439: Beat the heat with hot summer savings of up to 90% off.     •    acx318439: Temu UK Coupon Code to 40% off on Appliances at Temu. How to Apply Temu Coupon Code? Using the TemuCoupon code $40 off is a breeze. All you need to do is follow these simple steps:     1    Visit the Temu website or app and browse through the vast collection of products.     2    Once you’ve added the items you wish to purchase to your cart, proceed to the checkout page.     3    During the checkout process, you’ll be prompted to enter a coupon code or promo code.     4    Type in the coupon code: [acx318439] and click “Apply.”     5    Voila! You’ll instantly see the $40 discount reflected in your total purchase amount. Temu New User Coupon: Up To 90% OFF For Existing Customers Temu Existing customer’s coupon codes are designed just for new customers, offering the biggest discounts 90% and the best deals currently available on Temu. To maximize your savings, download the Temu app and apply our Temu new user coupon during checkout.     •    acx318439: New users can get up to 80% extra off.     •    acx318439: Get a massive 40% off your first order!     •    acx318439: Get 20% off on your first order; no minimum spending required.     •    acx318439: Take an extra 15% off your first order on top of existing discounts.     •    acx318439: Temu UK Enjoy a 40% discount on your entire first purchase.  
    • New users at Temureceive a 40 Off discount on orders over 40 Off Use the code [acx318439] during checkout to get TemuDiscount 40 Off For New Users. You n save 40 Off off your first order with the Promo Code available for a limited time only. Extra 30% off for new and existing customers + Up to $40 Off % off & more. Temu Promo Codes for New users- [acx318439] Temudiscount code for New customers- [acx318439] Temu $40 Off Promo Code- [acx318439] what are Temu codes- acx318439 does Temu give you $40 Off - [acx318439] Yes Verified Temu Promo Code january 2025- {acx318439} TemuNew customer offer {acx318439} Temudiscount codejanuary 2025 {acx318439} 40 off Promo Code Temu {acx318439} Temu 40% off any order {acx318439} 40 dollar off Temu code {acx318439} TemuCoupon $40 Off off for New customers There are a number of discounts and deals shoppers n take advantage of with the Teemu Coupon Bundle [acx318439]. TemuCoupon $40 Off off for New customers [acx318439] will save you $40 Off on your order. To get a discount, click on the item to purchase and enter the code. You n think of it as a supercharged savings pack for all your shopping needs Temu Promo Code 80% off – [acx318439] Free Temu codes 50% off – [acx318439] TemuCoupon $40 Off off – [acx318439] Temu buy to get ₱39 – [acx318439] Temu 129 coupon bundle – [acx318439] Temu buy 3 to get €99 – [acx318439] Exclusive $40 Off Off TemuDiscount Code Temu $40 Off Off Promo Code : (acx318439) Temu Discount Code $40 Off Bundle acx318439) acx318439 Temu $40 Off off Promo Code for Exsting users : acx318439) Temu Promo Code $40 Off off Temu 40 Off coupon code (acx318439) will save you 40 Off on your order. To get a discount, click on the item to purchase and enter the code. Yes, Temu offers 40 Off Coupon Code “acx318439” for Existing Customers.  You can get a 40 Off bonus plus 30% off any purchase at Temu with the 40 Off Coupon Bundle at Temu if you sign up with the referral code [acx318439] and make a first purchase of $40 Off or more. Temu Promo Code 40 off-{acx318439} Temu Promo Code -{acx318439} Temu Promo Code $40 Off off-{acx318439} kubonus code -{acx318439} Get ready to unlock a world of savings with our free Temu UK coupons! We’ve got you covered with a wide range of Temu UK coupon code options that will help you maximize your shopping experience.30% Off Temu UK Coupons, Promo Codes + 25% Cash Back [ acx318439]   Yes, Temu offers 40 off coupon code {acx318439} for first-time users. You can get a $40 bonus plus 40% off any purchase at Temu with the $40 Coupon Bundle if you sign up with the referral code [acx318439] and make a first purchase of $40 or more. If you are who wish to join Temu, then you should use this exclusive TemuCoupon code 40 off (acx318439) and get 40 off on your purchase with Temu. You can get a 40% discount with TemuCoupon code {acx318439}. This exclusive offer is for existing customers and can be used for a 40 reduction on your total purchase. Enter coupon code {acx318439} at checkout to avail of the discount. You can use the code {acx318439} to get a 40 off TemuCoupon as a new customer. Apply this TemuCoupon code $40 off (acx318439) to get a $40 discount on your shopping with Temu. If you’re a first-time user and looking for a TemuCoupon code $40 first time user(acx318439) then using this code will give you a flat $40 Off and a 90% discount on your Temu shopping.     •    acx318439: Enjoy flat 40% off on your first Temu order.     •    acx318439: Download the Temu app and get an additional 40% off.     •    acx318439: Celebrate spring with up to 90% discount on selected items.     •    acx318439: Score up to 90% off on clearance items.     •    acx318439: Beat the heat with hot summer savings of up to 90% off.     •    acx318439: Temu UK Coupon Code to 40% off on Appliances at Temu. How to Apply Temu Coupon Code? Using the TemuCoupon code $40 off is a breeze. All you need to do is follow these simple steps:     1    Visit the Temu website or app and browse through the vast collection of products.     2    Once you’ve added the items you wish to purchase to your cart, proceed to the checkout page.     3    During the checkout process, you’ll be prompted to enter a coupon code or promo code.     4    Type in the coupon code: [acx318439] and click “Apply.”     5    Voila! You’ll instantly see the $40 discount reflected in your total purchase amount. Temu New User Coupon: Up To 90% OFF For Existing Customers Temu Existing customer’s coupon codes are designed just for new customers, offering the biggest discounts 90% and the best deals currently available on Temu. To maximize your savings, download the Temu app and apply our Temu new user coupon during checkout.     •    acx318439: New users can get up to 80% extra off.     •    acx318439: Get a massive 40% off your first order!     •    acx318439: Get 20% off on your first order; no minimum spending required.     •    acx318439: Take an extra 15% off your first order on top of existing discounts.     •    acx318439: Temu UK Enjoy a 40% discount on your entire first purchase.  
    • New users at Temureceive a 40 Off discount on orders over 40 Off Use the code [acx318439] during checkout to get TemuDiscount 40 Off For New Users. You n save 40 Off off your first order with the Promo Code available for a limited time only. Extra 30% off for new and existing customers + Up to $40 Off % off & more. Temu Promo Codes for New users- [acx318439] Temudiscount code for New customers- [acx318439] Temu $40 Off Promo Code- [acx318439] what are Temu codes- acx318439 does Temu give you $40 Off - [acx318439] Yes Verified Temu Promo Code january 2025- {acx318439} TemuNew customer offer {acx318439} Temudiscount codejanuary 2025 {acx318439} 40 off Promo Code Temu {acx318439} Temu 40% off any order {acx318439} 40 dollar off Temu code {acx318439} TemuCoupon $40 Off off for New customers There are a number of discounts and deals shoppers n take advantage of with the Teemu Coupon Bundle [acx318439]. TemuCoupon $40 Off off for New customers [acx318439] will save you $40 Off on your order. To get a discount, click on the item to purchase and enter the code. You n think of it as a supercharged savings pack for all your shopping needs Temu Promo Code 80% off – [acx318439] Free Temu codes 50% off – [acx318439] TemuCoupon $40 Off off – [acx318439] Temu buy to get ₱39 – [acx318439] Temu 129 coupon bundle – [acx318439] Temu buy 3 to get €99 – [acx318439] Exclusive $40 Off Off TemuDiscount Code Temu $40 Off Off Promo Code : (acx318439) Temu Discount Code $40 Off Bundle acx318439) acx318439 Temu $40 Off off Promo Code for Exsting users : acx318439) Temu Promo Code $40 Off off Temu 40 Off coupon code (acx318439) will save you 40 Off on your order. To get a discount, click on the item to purchase and enter the code. Yes, Temu offers 40 Off Coupon Code “acx318439” for Existing Customers.  You can get a 40 Off bonus plus 30% off any purchase at Temu with the 40 Off Coupon Bundle at Temu if you sign up with the referral code [acx318439] and make a first purchase of $40 Off or more. Temu Promo Code 40 off-{acx318439} Temu Promo Code -{acx318439} Temu Promo Code $40 Off off-{acx318439} kubonus code -{acx318439} Get ready to unlock a world of savings with our free Temu UK coupons! We’ve got you covered with a wide range of Temu UK coupon code options that will help you maximize your shopping experience.30% Off Temu UK Coupons, Promo Codes + 25% Cash Back [ acx318439]   Yes, Temu offers 40 off coupon code {acx318439} for first-time users. You can get a $40 bonus plus 40% off any purchase at Temu with the $40 Coupon Bundle if you sign up with the referral code [acx318439] and make a first purchase of $40 or more. If you are who wish to join Temu, then you should use this exclusive TemuCoupon code 40 off (acx318439) and get 40 off on your purchase with Temu. You can get a 40% discount with TemuCoupon code {acx318439}. This exclusive offer is for existing customers and can be used for a 40 reduction on your total purchase. Enter coupon code {acx318439} at checkout to avail of the discount. You can use the code {acx318439} to get a 40 off TemuCoupon as a new customer. Apply this TemuCoupon code $40 off (acx318439) to get a $40 discount on your shopping with Temu. If you’re a first-time user and looking for a TemuCoupon code $40 first time user(acx318439) then using this code will give you a flat $40 Off and a 90% discount on your Temu shopping.     •    acx318439: Enjoy flat 40% off on your first Temu order.     •    acx318439: Download the Temu app and get an additional 40% off.     •    acx318439: Celebrate spring with up to 90% discount on selected items.     •    acx318439: Score up to 90% off on clearance items.     •    acx318439: Beat the heat with hot summer savings of up to 90% off.     •    acx318439: Temu UK Coupon Code to 40% off on Appliances at Temu. How to Apply Temu Coupon Code? Using the TemuCoupon code $40 off is a breeze. All you need to do is follow these simple steps:     1    Visit the Temu website or app and browse through the vast collection of products.     2    Once you’ve added the items you wish to purchase to your cart, proceed to the checkout page.     3    During the checkout process, you’ll be prompted to enter a coupon code or promo code.     4    Type in the coupon code: [acx318439] and click “Apply.”     5    Voila! You’ll instantly see the $40 discount reflected in your total purchase amount. Temu New User Coupon: Up To 90% OFF For Existing Customers Temu Existing customer’s coupon codes are designed just for new customers, offering the biggest discounts 90% and the best deals currently available on Temu. To maximize your savings, download the Temu app and apply our Temu new user coupon during checkout.     •    acx318439: New users can get up to 80% extra off.     •    acx318439: Get a massive 40% off your first order!     •    acx318439: Get 20% off on your first order; no minimum spending required.     •    acx318439: Take an extra 15% off your first order on top of existing discounts.     •    acx318439: Temu UK Enjoy a 40% discount on your entire first purchase.  
    • New users at Temureceive a 40 Off discount on orders over 40 Off Use the code [acx318439] during checkout to get TemuDiscount 40 Off For New Users. You n save 40 Off off your first order with the Promo Code available for a limited time only. Extra 30% off for new and existing customers + Up to $40 Off % off & more. Temu Promo Codes for New users- [acx318439] Temudiscount code for New customers- [acx318439] Temu $40 Off Promo Code- [acx318439] what are Temu codes- acx318439 does Temu give you $40 Off - [acx318439] Yes Verified Temu Promo Code january 2025- {acx318439} TemuNew customer offer {acx318439} Temudiscount codejanuary 2025 {acx318439} 40 off Promo Code Temu {acx318439} Temu 40% off any order {acx318439} 40 dollar off Temu code {acx318439} TemuCoupon $40 Off off for New customers There are a number of discounts and deals shoppers n take advantage of with the Teemu Coupon Bundle [acx318439]. TemuCoupon $40 Off off for New customers [acx318439] will save you $40 Off on your order. To get a discount, click on the item to purchase and enter the code. You n think of it as a supercharged savings pack for all your shopping needs Temu Promo Code 80% off – [acx318439] Free Temu codes 50% off – [acx318439] TemuCoupon $40 Off off – [acx318439] Temu buy to get ₱39 – [acx318439] Temu 129 coupon bundle – [acx318439] Temu buy 3 to get €99 – [acx318439] Exclusive $40 Off Off TemuDiscount Code Temu $40 Off Off Promo Code : (acx318439) Temu Discount Code $40 Off Bundle acx318439) acx318439 Temu $40 Off off Promo Code for Exsting users : acx318439) Temu Promo Code $40 Off off Temu 40 Off coupon code (acx318439) will save you 40 Off on your order. To get a discount, click on the item to purchase and enter the code. Yes, Temu offers 40 Off Coupon Code “acx318439” for Existing Customers.  You can get a 40 Off bonus plus 30% off any purchase at Temu with the 40 Off Coupon Bundle at Temu if you sign up with the referral code [acx318439] and make a first purchase of $40 Off or more. Temu Promo Code 40 off-{acx318439} Temu Promo Code -{acx318439} Temu Promo Code $40 Off off-{acx318439} kubonus code -{acx318439} Get ready to unlock a world of savings with our free Temu UK coupons! We’ve got you covered with a wide range of Temu UK coupon code options that will help you maximize your shopping experience.30% Off Temu UK Coupons, Promo Codes + 25% Cash Back [ acx318439]   Yes, Temu offers 40 off coupon code {acx318439} for first-time users. You can get a $40 bonus plus 40% off any purchase at Temu with the $40 Coupon Bundle if you sign up with the referral code [acx318439] and make a first purchase of $40 or more. If you are who wish to join Temu, then you should use this exclusive TemuCoupon code 40 off (acx318439) and get 40 off on your purchase with Temu. You can get a 40% discount with TemuCoupon code {acx318439}. This exclusive offer is for existing customers and can be used for a 40 reduction on your total purchase. Enter coupon code {acx318439} at checkout to avail of the discount. You can use the code {acx318439} to get a 40 off TemuCoupon as a new customer. Apply this TemuCoupon code $40 off (acx318439) to get a $40 discount on your shopping with Temu. If you’re a first-time user and looking for a TemuCoupon code $40 first time user(acx318439) then using this code will give you a flat $40 Off and a 90% discount on your Temu shopping.     •    acx318439: Enjoy flat 40% off on your first Temu order.     •    acx318439: Download the Temu app and get an additional 40% off.     •    acx318439: Celebrate spring with up to 90% discount on selected items.     •    acx318439: Score up to 90% off on clearance items.     •    acx318439: Beat the heat with hot summer savings of up to 90% off.     •    acx318439: Temu UK Coupon Code to 40% off on Appliances at Temu. How to Apply Temu Coupon Code? Using the TemuCoupon code $40 off is a breeze. All you need to do is follow these simple steps:     1    Visit the Temu website or app and browse through the vast collection of products.     2    Once you’ve added the items you wish to purchase to your cart, proceed to the checkout page.     3    During the checkout process, you’ll be prompted to enter a coupon code or promo code.     4    Type in the coupon code: [acx318439] and click “Apply.”     5    Voila! You’ll instantly see the $40 discount reflected in your total purchase amount. Temu New User Coupon: Up To 90% OFF For Existing Customers Temu Existing customer’s coupon codes are designed just for new customers, offering the biggest discounts 90% and the best deals currently available on Temu. To maximize your savings, download the Temu app and apply our Temu new user coupon during checkout.     •    acx318439: New users can get up to 80% extra off.     •    acx318439: Get a massive 40% off your first order!     •    acx318439: Get 20% off on your first order; no minimum spending required.     •    acx318439: Take an extra 15% off your first order on top of existing discounts.     •    acx318439: Temu UK Enjoy a 40% discount on your entire first purchase.  
  • Topics

×
×
  • Create New...

Important Information

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