Public Access
This commit is contained in:
1 parent
e30c0a25cc
commit
67ce69e8b2
6 files changed
+43
-7
No files matched your search
@@ -36,7 +36,8 @@ independently validates every link.
|
||||
Until generated Ages arrive in Milestone 3, written Descriptive Books resolve
|
||||
deterministically to the Overworld, Nether, or End according to their Age UUID.
|
||||
The Rivencraft creative tab includes one sample book for each. Linking creates
|
||||
a bound Return Link to the exact source position and orientation.
|
||||
a bound Return Link to the exact source position and orientation. Descriptive
|
||||
Book destinations additionally require solid footing beneath the player.
|
||||
|
||||
## Requirements
|
||||
|
||||
|
||||
@@ -156,6 +156,9 @@ Version 0.2.2 adds the same server-provided Ponder destination preview to
|
||||
Descriptive Books. If no snapshot is available, the left page shows an
|
||||
animated linking-panel fallback.
|
||||
|
||||
Version 0.2.3 requires Descriptive Book destinations to have a sturdy floor,
|
||||
while Linking Books continue to permit passable floorless destinations.
|
||||
|
||||
The preview code is separated behind a renderer interface and uses an isolated
|
||||
Ponder level populated from server-authoritative destination snapshots.
|
||||
|
||||
|
||||
+1
-1
@@ -33,7 +33,7 @@ mod_name=Rivencraft
|
||||
# The license of the mod. Review your options at https://choosealicense.com/. All Rights Reserved is the default.
|
||||
mod_license=LGPL-3.0-or-later
|
||||
# The mod version. See https://semver.org/
|
||||
mod_version=0.2.2
|
||||
mod_version=0.2.3
|
||||
# The group ID for the mod. It is only important when publishing as an artifact to a Maven repository.
|
||||
# This should match the base package used for the mod sources.
|
||||
# See https://maven.apache.org/guides/mini/guide-naming-conventions.html
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in new issue
Block a user