Public Access
This commit is contained in:
1 parent
67ce69e8b2
commit
a9390c3e4c
5 files changed
+70
-7
No files matched your search
@@ -2,6 +2,7 @@ package net.dnorberg.rivencraft.book;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.IntStream;
|
||||
import java.util.stream.Stream;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
@@ -9,12 +10,14 @@ import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.tags.BlockTags;
|
||||
import net.minecraft.world.level.border.WorldBorder;
|
||||
import net.minecraft.world.level.levelgen.Heightmap;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
|
||||
/** Server-side validation and execution for book travel. */
|
||||
public final class LinkingService {
|
||||
private static final int HORIZONTAL_SEARCH_RADIUS = 4;
|
||||
private static final int VERTICAL_SEARCH_RADIUS = 2;
|
||||
private static final int AGE_ARRIVAL_SEARCH_RADIUS = 64;
|
||||
|
||||
private LinkingService() {
|
||||
}
|
||||
@@ -25,7 +28,20 @@ public final class LinkingService {
|
||||
|
||||
/** Travels to an Age-style destination, which must have solid footing. */
|
||||
public static LinkResult travelWithFooting(ServerPlayer player, LinkTarget target) {
|
||||
return travel(player, target, true);
|
||||
ServerLevel destinationLevel = player.getServer().getLevel(target.location().dimension());
|
||||
if (destinationLevel == null) {
|
||||
return LinkResult.MISSING_DIMENSION;
|
||||
}
|
||||
|
||||
Optional<Vec3> destination = findFootedAgeDestination(destinationLevel, target.location().pos());
|
||||
if (destination.isEmpty()) {
|
||||
return LinkResult.NO_SAFE_DESTINATION;
|
||||
}
|
||||
|
||||
Vec3 position = destination.get();
|
||||
player.teleportTo(destinationLevel, position.x, position.y, position.z, target.yaw(), target.pitch());
|
||||
player.resetFallDistance();
|
||||
return LinkResult.SUCCESS;
|
||||
}
|
||||
|
||||
private static LinkResult travel(ServerPlayer player, LinkTarget target, boolean requiresFooting) {
|
||||
@@ -66,6 +82,42 @@ public final class LinkingService {
|
||||
.findFirst();
|
||||
}
|
||||
|
||||
/** Finds a footed arrival near an unsafe Age spawn without scanning the whole dimension. */
|
||||
private static Optional<Vec3> findFootedAgeDestination(ServerLevel level, BlockPos origin) {
|
||||
Optional<Vec3> localDestination = findSafeDestination(level, origin, true);
|
||||
if (localDestination.isPresent()) {
|
||||
return localDestination;
|
||||
}
|
||||
|
||||
WorldBorder border = level.getWorldBorder();
|
||||
return ageArrivalColumns(origin)
|
||||
.flatMap(column -> surfaceCandidates(level, column))
|
||||
.filter(level::isInWorldBounds)
|
||||
.filter(border::isWithinBounds)
|
||||
.filter(position -> isSafe(level, position, true))
|
||||
.map(Vec3::atBottomCenterOf)
|
||||
.findFirst();
|
||||
}
|
||||
|
||||
private static Stream<BlockPos> ageArrivalColumns(BlockPos origin) {
|
||||
return IntStream.rangeClosed(1, AGE_ARRIVAL_SEARCH_RADIUS)
|
||||
.boxed()
|
||||
.flatMap(radius -> BlockPos.betweenClosedStream(
|
||||
origin.offset(-radius, 0, -radius),
|
||||
origin.offset(radius, 0, radius)
|
||||
)
|
||||
.filter(position -> Math.max(Math.abs(position.getX() - origin.getX()),
|
||||
Math.abs(position.getZ() - origin.getZ())) == radius)
|
||||
)
|
||||
.map(BlockPos::immutable);
|
||||
}
|
||||
|
||||
private static Stream<BlockPos> surfaceCandidates(ServerLevel level, BlockPos column) {
|
||||
int surfaceY = level.getHeight(Heightmap.Types.MOTION_BLOCKING, column.getX(), column.getZ());
|
||||
BlockPos surface = new BlockPos(column.getX(), surfaceY, column.getZ());
|
||||
return Stream.of(surface, surface.above(), surface.below(), surface.above(2), surface.below(2));
|
||||
}
|
||||
|
||||
private static Stream<BlockPos> candidates(BlockPos origin) {
|
||||
return BlockPos.betweenClosedStream(
|
||||
origin.offset(-HORIZONTAL_SEARCH_RADIUS, -VERTICAL_SEARCH_RADIUS, -HORIZONTAL_SEARCH_RADIUS),
|
||||
|
||||
@@ -7,6 +7,7 @@ import net.dnorberg.rivencraft.item.DescriptiveBookItem;
|
||||
import net.dnorberg.rivencraft.registry.ModDataComponents;
|
||||
import net.dnorberg.rivencraft.registry.ModItems;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.core.GlobalPos;
|
||||
import net.minecraft.gametest.framework.GameTest;
|
||||
import net.minecraft.gametest.framework.GameTestHelper;
|
||||
@@ -84,18 +85,24 @@ public final class LinkingGameTests {
|
||||
}
|
||||
|
||||
@GameTest(template = "empty")
|
||||
public static void descriptiveTravelRequiresFooting(GameTestHelper helper) {
|
||||
public static void descriptiveTravelFindsAlternateFooting(GameTestHelper helper) {
|
||||
BlockPos absoluteOrigin = helper.absolutePos(ORIGIN);
|
||||
for (BlockPos position : BlockPos.betweenClosed(
|
||||
absoluteOrigin.offset(-4, -3, -4), absoluteOrigin.offset(4, 3, 4))) {
|
||||
absoluteOrigin.offset(-6, -3, -6), absoluteOrigin.offset(6, 3, 6))) {
|
||||
helper.getLevel().setBlock(position, Blocks.AIR.defaultBlockState(), 2);
|
||||
}
|
||||
BlockPos alternateDestination = absoluteOrigin.offset(6, 0, 0);
|
||||
helper.getLevel().setBlock(alternateDestination.below(), Blocks.STONE.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.assertValueEqual(LinkingService.travelWithFooting(player, target), LinkingService.LinkResult.SUCCESS,
|
||||
"Descriptive Book travel must find an alternate grounded arrival");
|
||||
BlockPos landing = player.blockPosition();
|
||||
helper.assertTrue(helper.getLevel().getBlockState(landing.below()).isFaceSturdy(
|
||||
helper.getLevel(), landing.below(), Direction.UP),
|
||||
"The alternate arrival must have sturdy footing");
|
||||
helper.succeed();
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user