Jump to content
View in the app

A better way to browse. Learn more.

Forge Forums

A full-screen app on your home screen with push notifications, badges and more.

To install this app on iOS and iPadOS
  1. Tap the Share icon in Safari
  2. Scroll the menu and tap Add to Home Screen.
  3. Tap Add in the top-right corner.
To install this app on Android
  1. Tap the 3-dot menu (⋮) in the top-right corner of the browser.
  2. Tap Add to Home screen or Install app.
  3. Confirm by tapping Install.

Featured Replies

Posted

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

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

18 minutes ago, Kitoglavch said:
    if (this.horse.getNavigation().isDone()) {
      this.horse.getNavigation().moveTo(this.path, 1.5);
    }

ignore my first post, i think you forgot the ! there?

  • Author
11 minutes ago, Luis_ST said:

you forgot the ! there?

It should be here? I thought this method returns true if navigation has no active path. 

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

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

Edited by Kitoglavch

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

  • Author
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 

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

Maybe this is your issue, try to add only one Goal

this.horse.getNavigation().moveTo(this.path, 1.5);

Is this code in the tick method called, after the Horse is stuck in a corner?

  • Author

what you mean? this action is called every tick due to "true" in if statement. i didn't understand what should i write in else statement

  if (!this.horse.getNavigation().isDone()) { // true
      this.horse.getNavigation().moveTo(this.path, 1.5);
    }

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

  • Author
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

  • Author

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

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...

Important Information

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

Configure browser push notifications

Chrome (Android)
  1. Tap the lock icon next to the address bar.
  2. Tap Permissions → Notifications.
  3. Adjust your preference.
Chrome (Desktop)
  1. Click the padlock icon in the address bar.
  2. Select Site settings.
  3. Find Notifications and adjust your preference.