Jump to content

Recommended Posts

Posted

I'm currently making a mob that eats crops. I've got it kind of working, but the behavior isn't quite the way I want it to be. My goal is to get the mob to eat all crops nearby without stopping. Currently, my mob will move up to a crop, eat it, and then be idle for awhile as neither the move to crop goal nor eat crop goal are being started. Is there a way to get make these goals fire more often?

MoveToCropGoal:

public class MoveToCropGoal extends MoveToBlockGoal {
    private static final int GIVE_UP_TICKS = 600;
    private boolean shouldStop;

    public MoveToCropGoal(PathfinderMob mob) {
        super(mob, 1.0, 100);
    }

    @Override
    protected boolean isValidTarget(LevelReader levelReader, BlockPos blockPos) {
        return levelReader.getBlockState(blockPos).getBlock() instanceof CropBlock;
    }

    @Override
    public boolean shouldRecalculatePath() {
        return this.tryTicks % 10 == 0;
    }

    @Override
    public void start() {
        super.start();
        Main.LOGGER.info("Starting to move towards crop");
        shouldStop = false;
    }

    @Override
    public void stop() {
        this.shouldStop = true;
    }

    @Override
    protected boolean isReachedTarget() {
        return super.isReachedTarget() || Utils.getSurroundingBlockPoses(this.mob).stream().anyMatch(blockPos -> Utils.blockPosIsCrop(this.mob.level, blockPos));
    }

    @Override
    public boolean canContinueToUse() {
        boolean canContinue = !shouldStop && !this.isReachedTarget() && this.tryTicks <= GIVE_UP_TICKS && this.isValidTarget(this.mob.level, this.blockPos);
        Main.LOGGER.info("Can continue to move towards crop: " + canContinue);
        return canContinue;
    }
}

EatCropGoal:

public class EatCropGoal extends EatBlockGoal {
    protected final Mob mob;
    protected final Level level;
    private final int MAX_TICKS = 10;
    private int ticks;
    private boolean hasEaten;

    public EatCropGoal(Mob mob) {
        super(mob);
        this.mob = mob;
        this.level = mob.level;
    }

    @Override
    public boolean canUse() {
        for (BlockPos blockPos : Utils.getSurroundingBlockPoses(this.mob)) {
            if (Utils.blockPosIsCrop(this.level, blockPos)) {
                return true;
            }
        }

        return false;
    }

    @Override
    public boolean canContinueToUse() {
        return !this.hasEaten || this.ticks < MAX_TICKS;
    }

    @Override
    public void start() {
        super.start();
        Main.LOGGER.info("Eating crops");
        this.ticks = 0;
        this.hasEaten = false;
    }

    @Override
    public void stop() {
        this.hasEaten = true;
    }

    @Override
    public void tick() {
        ++this.ticks;
        List<BlockPos> cropsToEat = Utils.getSurroundingBlockPoses(this.mob).stream()
                .filter(blockPos -> Utils.blockPosIsCrop(this.level, blockPos)).toList();
        if (this.level.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) {
            for (BlockPos cropToEat : cropsToEat) {
                this.level.destroyBlock(cropToEat, false);
                this.mob.ate();
                this.mob.gameEvent(GameEvent.EAT, this.mob.eyeBlockPosition());
            }
            if (cropsToEat.size() > 0) {
                this.hasEaten = true;
            }
        }
    }
}

registerGoals:

    @Override
    protected void registerGoals() {
        this.goalSelector.addGoal(0, new FloatGoal(this));
        this.goalSelector.addGoal(15, new WaterAvoidingRandomStrollGoal(this, 1.0, 0f));
        this.goalSelector.addGoal(1, new HurtByTargetGoal(this));
        this.goalSelector.addGoal(1, new MeleeAttackGoal(this, 1d, false));
        this.goalSelector.addGoal(2, new MoveToCropGoal(this));
        this.goalSelector.addGoal(2, new EatCropGoal(this));
    }

 

Posted (edited)

I took a look at MoveToBlockGoal's canUse method and noticed that it has a nextStartTick that it uses in determining if it can be used. I'll try playing with that to see if it makes a difference.

Edited by yeetsche420
spelling
Posted

I managed to get something I like. Here's my code:

MoveToCropGoal:

public class MoveToCropGoal extends MoveToBlockGoal {
    private static final int GIVE_UP_TICKS = 600;
    private boolean shouldStop;
    private boolean isNearCrop;
    private int timesRun;

    public MoveToCropGoal(PathfinderMob mob) {
        super(mob, 1.0, 100, 20);
        timesRun = 0;
    }

    @Override
    protected boolean isValidTarget(LevelReader levelReader, BlockPos blockPos) {
        return levelReader.getBlockState(blockPos).getBlock() instanceof CropBlock;
    }

    @Override
    public boolean shouldRecalculatePath() {
        return this.tryTicks % 10 == 0;
    }

    @Override
    public void start() {
        super.start();
        shouldStop = false;
        isNearCrop = true;
        ++timesRun;
    }

    @Override
    protected int nextStartTick(PathfinderMob pathfinderMob) {
        return (isNearCrop || timesRun == 0) ? 3 : super.nextStartTick(pathfinderMob);
    }

    @Override
    public void stop() {
        shouldStop = true;
    }

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

    @Override
    protected boolean isReachedTarget() {
        return super.isReachedTarget() || Utils.getSurroundingBlockPoses(mob).stream().anyMatch(blockPos -> Utils.blockPosIsCrop(mob.level, blockPos));
    }

    @Override
    public boolean canContinueToUse() {
        boolean canContinue = !shouldStop && !this.isReachedTarget() && tryTicks <= GIVE_UP_TICKS && isValidTarget(mob.level, blockPos);
        if (!canContinue) {
            isNearCrop = findNearestBlock();
        }
        return canContinue;
    }
}

EatCropGoal:

public class EatCropGoal extends EatBlockGoal {
    protected final Mob mob;
    protected final Level level;
    private final int MAX_TICKS = 10;
    private int ticks;
    private boolean hasEaten;

    public EatCropGoal(Mob mob) {
        super(mob);
        this.mob = mob;
        this.level = mob.level;
    }

    @Override
    public boolean canUse() {
        return Utils.getSurroundingBlockPoses(this.mob).stream()
                .anyMatch(blockPos -> Utils.blockPosIsCrop(this.level, blockPos));
    }

    @Override
    public boolean canContinueToUse() {
        return !this.hasEaten && this.ticks < MAX_TICKS;
    }

    @Override
    public void start() {
        super.start();
        this.ticks = 0;
        this.hasEaten = false;
    }

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

    @Override
    public void stop() {
        this.hasEaten = true;
    }

    @Override
    public void tick() {
        ++this.ticks;
        if (this.level.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) {
            List<BlockPos> cropsToEat = Utils.getSurroundingBlockPoses(this.mob).stream()
                    .filter(blockPos -> Utils.blockPosIsCrop(this.level, blockPos)).toList();
            for (BlockPos cropToEat : cropsToEat) {
                this.level.destroyBlock(cropToEat, false);
                this.mob.ate();
                this.mob.gameEvent(GameEvent.EAT, this.mob.eyeBlockPosition());
            }
            if (cropsToEat.size() > 0) {
                this.hasEaten = true;
            }
        }
    }
}

 

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Announcements



×
×
  • Create New...

Important Information

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