Jump to content

[1.18.2] How to make horse run along the four points


Kitoglavch

Recommended Posts

Hello, I'm doing block similar to grindstone from Horse Power and I have a question. How can I change horse navigation to move like this?

28RFwHJ.png

ZHIhDVq.png

Now i'm doing it like this: 

horse.goalSelector.addGoal(0, new HorseWalkGoal(horse)); // at BlockEntity#tick, don't know if it's correct

Goal class:

public class HorseWalkGoal extends Goal {
  public final Horse horse;
  public Path path;

  public HorseWalkGoal(Horse horse) {
    this.horse = horse;
    //points from picture
    this.path = horse.getNavigation().createPath(Set.of(
      horse.getLeashHolder().blockPosition().offset(3, -1, 3), 	//point 1
      horse.getLeashHolder().blockPosition().offset(3, -1, -3), //point 2
      horse.getLeashHolder().blockPosition().offset(-3, -1, -3), //point 3
      horse.getLeashHolder().blockPosition().offset(-3, -1, 3)), 0); //point 4
    this.setFlags(EnumSet.of(Flag.MOVE));
  }

  @Override
  public boolean canUse() {
    return horse.isLeashed() && this.isValid();
  }

  public boolean isValid() {
    Optional<HorseCrankBlockEntity> blockentity = horse.level.getBlockEntity(horse.getLeashHolder().blockPosition(), ModBlockEntities.HORSECRANK.get());
    return blockentity.isPresent() && blockentity.get().valid;
  }

  @Override
  public void stop() {
    horse.getNavigation().stop();
  }

  @Override
  public void tick() {
    if (this.horse.getNavigation().isDone()) {
      this.horse.getNavigation().moveTo(this.path, 1.5);
    }
  }

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

  @Override
  public void start() {
    this.horse.getNavigation().moveTo(this.path, 1.5);
  }
}

I guess I use NavigationPath#createPath wrong. But how i must to?

 

Edited by Kitoglavch
Link to comment
Share on other sites

2 hours ago, Kitoglavch said:
// at BlockEntity#tick, don't know if it's correct

Do not add this goal each tick, once is enough

2 hours ago, Kitoglavch said:

Hello, I'm doing block similar to grindstone from Horse Power and I have a question. How can I change horse navigation to move like this?

Calculate the positions (1, 2, 3, 4, ...) then call PathNavigation#moveTo for the first position,
wait until the horse has reached the position then continue with the same logic for the next position and repeat this step until you at the last position

Edited by Luis_ST
Link to comment
Share on other sites

4 minutes ago, Kitoglavch said:

I think it hepled. But anyway, there is a problem with Path. Horse still act strange and just move to the nearest point

are you sure the positions of the Path are correct
and you could use debugger to check how the goal is handled/called

Edit: try to place the Horse at a different spot

Edited by Luis_ST
Link to comment
Share on other sites

Just now, Luis_ST said:

are you sure the positions of the Path are correct

i don't know if Path#createPath works as I suppose, but console logs me [BlockPos{x=58, y=-60, z=-457}, BlockPos{x=58, y=-60, z=-451}, BlockPos{x=64, y=-60, z=-457}, BlockPos{x=64, y=-60, z=-451}] from Set<BlockPos>, and it is what should be.

 

3 minutes ago, Luis_ST said:

and you could use debugger to check how the goal is handled/called

i put System.out.println in Goal#start, Goal#stop. It should work properly and add new goal once at the same time 

Link to comment
Share on other sites

when the PathNavigation#isDone returns false in the corner you can try something like this:

if (!this.horse.getNavigation().isDone()) {
	this.horse.getNavigation().moveTo(this.path, 1.5);
} else {
	this.path = // create a new path
}

you also could try this, if the Path does not work correctly:

1 hour ago, Luis_ST said:

Calculate the positions (1, 2, 3, 4, ...) then call PathNavigation#moveTo for the first position,
wait until the horse has reached the position then continue with the same logic for the next position and repeat this step until you at the last position

Link to comment
Share on other sites

13 hours ago, Luis_ST said:

you also could try this, if the Path does not work correctly:

sadly it didn't work. horse did the same

13 hours ago, Luis_ST said:

Calculate the positions (1, 2, 3, 4, ...) then call PathNavigation#moveTo for the first position,
wait until the horse has reached the position then continue with the same logic for the next position and repeat this step until you at the last position

I try this way now, but horse still acts not as supposed to (but much better than it was)

public class HorseWalkGoal extends Goal {
  public final Horse horse;
  public int goalStatus;
  public BlockPos horseCrankPos;
  public static int[][] offsets = new int[][] {{3, -1, 3}, {3, -1, -3}, {-3, -1, -3}, {-3, -1, 3}};

  public HorseWalkGoal(Horse horse, BlockPos pos) {
    this.horse = horse;
    this.horseCrankPos = pos;
    this.setFlags(EnumSet.of(Flag.MOVE));
  }

  @Override
  public boolean canUse() {
    return this.horse.isLeashed() && this.isValid();
  }

  public boolean isValid() {
    Optional<HorseCrankBlockEntity> blockentity = this.horse.level.getBlockEntity(this.horseCrankPos, ModBlockEntities.HORSECRANK.get());
    return blockentity.isPresent() && blockentity.get().valid;
  }

  @Override
  public void start() {
    this.horse.getNavigation().stop();
    if (this.horse.getNavigation().isDone()) {
      BlockPos pos = calculatePos(this.horseCrankPos, goalStatus);
      this.horse.getNavigation().moveTo(pos.getX(), pos.getY(), pos.getZ(), 1.5);
    }
  }

  @Override
  public void stop() {
    this.horse.getNavigation().stop();
  }

  @Override
  public void tick() {
    if (this.horse.getNavigation().isDone()) {
      this.incrementGoalStatus();
      BlockPos pos = calculatePos(this.horseCrankPos, goalStatus);
      this.horse.getNavigation().moveTo(pos.getX(), pos.getY(), pos.getZ(), 1.5);
    }
  }

  private void incrementGoalStatus() {
    this.goalStatus = (this.goalStatus + 1) % 4;
  }

  private BlockPos calculatePos(BlockPos pos, int goalStatus) {
    return pos.offset(offsets[goalStatus][0], offsets[goalStatus][1], offsets[goalStatus][2]);
  }

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

https://i.imgur.com/GGC5tG7.mp4

Edited by Kitoglavch
Link to comment
Share on other sites

Ok I decided to use the same way like in Horse Power (1.12.2) in BlockEntity tick. It looks like horse slightly understand what it need to do, but this way still doesn't work properly. What can be wrong here?

  public static double[][] offsetsXZ = {{-1.5, -1.5}, {0, -1.5}, {1, -1.5}, {1, 0}, {1, 1}, {0, 1}, {-1.5, 1}, {-1.5, 0}};
  public AABB[] searchAreas = new AABB[8];
  public int origin = -1, target = origin;
  @Override
  public void load(CompoundTag tag) {
	// ^ other load
    this.origin = tag.getInt("origin");
    this.target = tag.getInt("target");
  }

  @Override
  protected void saveAdditional(CompoundTag tag) {
	// ^ other save
    tag.putInt("origin", this.origin);
    tag.putInt("target", this.target);
  }

public static <T extends BlockEntity> void tick(Level p_155253_, BlockPos p_155254_, BlockState p_155255_, T p_155256_) {
    if (!p_155253_.isClientSide) {
      HorseCrankBlockEntity blockentity = (HorseCrankBlockEntity) p_155256_;
      int oldPower = blockentity.power, oldHorseId = blockentity.horseId, oldLeashId = blockentity.leashId;
      boolean oldValid = blockentity.valid;
      Horse horse = blockentity.getHorse();
      blockentity.verifyIntegrity();
      blockentity.calculatePower();
      if (horse != null && blockentity.valid) {
        if (oldValid != blockentity.valid) {
          blockentity.target = blockentity.findClosestPoint();
        }
        Vector3d pos = blockentity.calculatePos(blockentity.target);
        double x = pos.x;
        double y = pos.y;
        double z = pos.z;
        if (blockentity.searchAreas[blockentity.target] == null)
          blockentity.searchAreas[blockentity.target] = new AABB(x - 0.5, y - 0.5, z - 0.5, x + 0.5, y + 0.5, z + 0.5);
        if (horse.getBoundingBox().intersects(blockentity.searchAreas[blockentity.target])) {
          int next = blockentity.target + 1;
          int previous = blockentity.target - 1;
          if (next >= offsetsXZ.length)
            next = 0;
          if (previous < 0)
            previous = offsetsXZ.length - 1;
          if (blockentity.origin != blockentity.target && blockentity.target != previous) {
            blockentity.origin = blockentity.target;
          }
          blockentity.target = next;
        }
        if (blockentity.target != -1 && !horse.getNavigation().isDone()) {
          pos = blockentity.calculatePos(blockentity.target);
          x = pos.x;
          y = pos.y;
          z = pos.z;
          horse.getNavigation().moveTo(x, y, z, 1D);
          System.out.println(String.format("%f;%f;%f;%d;%s", x, y, z, blockentity.target, horse.getNavigation().getPath()));
        }
      }
      if (oldPower != blockentity.power || oldValid != blockentity.valid || oldHorseId != blockentity.horseId || oldLeashId != blockentity.leashId) {
        p_155253_.sendBlockUpdated(p_155254_, p_155255_, p_155255_, 2);
      }
      p_155256_.setChanged();
    }
  }

  private int findClosestPoint() {
    if (horseId != -1) {
      double distance = Double.MAX_VALUE;
      int closest = 0;
      for (int i = 0; i < offsetsXZ.length; i++) {
        double tmp = distanceToPoint(i);
        if (tmp < distance) {
          distance = tmp;
          closest = i;
        }
      }
      return closest;
    }
    return 0;
  }

  private double distanceToPoint(int point) {
    Vector3d pos = calculatePos(point);
    return this.getHorse().distanceToSqr(pos.x, pos.y, pos.z);
  }

  private Vector3d calculatePos(int point) {
    double x = this.getBlockPos().getX() + offsetsXZ[point][0] * 2;
    double y = this.getBlockPos().getY() - 1;
    double z = this.getBlockPos().getZ() + offsetsXZ[point][1] * 2;
    return new Vector3d(x, y, z);
  }

https://imgur.com/loLgEAu

Edited by Kitoglavch
video
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.



×
×
  • Create New...

Important Information

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