Require footing for descriptive book travel
Build / build (push) Canceled after 0s

This commit is contained in:
dnorberg committed 2026-09-21 09:31:41 -04:00
1 parent e30c0a25cc
commit 67ce69e8b2
6 files changed
+43 -7

No files matched your search

@@ -4,6 +4,7 @@ import java.util.Comparator;
import java.util.Optional;
import java.util.stream.Stream;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.tags.BlockTags;
@@ -19,12 +20,21 @@ public final class LinkingService {
}
public static LinkResult travel(ServerPlayer player, LinkTarget target) {
return travel(player, target, false);
}
/** Travels to an Age-style destination, which must have solid footing. */
public static LinkResult travelWithFooting(ServerPlayer player, LinkTarget target) {
return travel(player, target, true);
}
private static LinkResult travel(ServerPlayer player, LinkTarget target, boolean requiresFooting) {
ServerLevel destinationLevel = player.getServer().getLevel(target.location().dimension());
if (destinationLevel == null) {
return LinkResult.MISSING_DIMENSION;
}
Optional<Vec3> destination = findSafeDestination(destinationLevel, target.location().pos());
Optional<Vec3> destination = findSafeDestination(destinationLevel, target.location().pos(), requiresFooting);
if (destination.isEmpty()) {
return LinkResult.NO_SAFE_DESTINATION;
}
@@ -43,11 +53,15 @@ public final class LinkingService {
}
static Optional<Vec3> findSafeDestination(ServerLevel level, BlockPos origin) {
return findSafeDestination(level, origin, false);
}
private static Optional<Vec3> findSafeDestination(ServerLevel level, BlockPos origin, boolean requiresFooting) {
WorldBorder border = level.getWorldBorder();
return candidates(origin)
.filter(level::isInWorldBounds)
.filter(border::isWithinBounds)
.filter(position -> isSafe(level, position))
.filter(position -> isSafe(level, position, requiresFooting))
.map(position -> Vec3.atBottomCenterOf(position))
.findFirst();
}
@@ -61,9 +75,11 @@ public final class LinkingService {
.sorted(Comparator.comparingDouble(position -> position.distSqr(origin)));
}
private static boolean isSafe(ServerLevel level, BlockPos feet) {
private static boolean isSafe(ServerLevel level, BlockPos feet, boolean requiresFooting) {
BlockPos head = feet.above();
return isPassableSpawnSpace(level, feet) && isPassableSpawnSpace(level, head);
return isPassableSpawnSpace(level, feet)
&& isPassableSpawnSpace(level, head)
&& (!requiresFooting || level.getBlockState(feet.below()).isFaceSturdy(level, feet.below(), Direction.UP));
}
private static boolean isPassableSpawnSpace(ServerLevel level, BlockPos position) {
@@ -83,6 +83,22 @@ public final class LinkingGameTests {
helper.succeed();
}
@GameTest(template = "empty")
public static void descriptiveTravelRequiresFooting(GameTestHelper helper) {
BlockPos absoluteOrigin = helper.absolutePos(ORIGIN);
for (BlockPos position : BlockPos.betweenClosed(
absoluteOrigin.offset(-4, -3, -4), absoluteOrigin.offset(4, 3, 4))) {
helper.getLevel().setBlock(position, Blocks.AIR.defaultBlockState(), 2);
}
ServerPlayer player = helper.makeMockServerPlayerInLevel();
LinkTarget target = new LinkTarget(GlobalPos.of(helper.getLevel().dimension(), absoluteOrigin), 0.0F, 0.0F);
helper.assertValueEqual(LinkingService.travelWithFooting(player, target), LinkingService.LinkResult.NO_SAFE_DESTINATION,
"Descriptive Book travel must not place players without solid footing");
helper.succeed();
}
@GameTest(template = "empty")
public static void travelRejectsBlockedDestination(GameTestHelper helper) {
BlockPos absoluteOrigin = helper.absolutePos(ORIGIN);
@@ -49,7 +49,7 @@ public final class DescriptiveBookItem extends Item {
return false;
}
LinkingService.LinkResult result = LinkingService.travel(player, ageTarget);
LinkingService.LinkResult result = LinkingService.travelWithFooting(player, ageTarget);
if (result != LinkingService.LinkResult.SUCCESS) {
player.displayClientMessage(Component.translatable("message.rivencraft.descriptive_book.unsafe"), true);
return false;