From 0d013c88063f132db7eb80538a579c58f47a0c1f Mon Sep 17 00:00:00 2001
From: TropheusJ
Date: Wed, 19 Feb 2025 12:40:55 -0500
Subject: [PATCH] woe, API status be upon ye - make portal track behavior API -
some cleanup while I'm at it
---
.../train/PortalTrackProvider.java | 91 +++++++++++++
.../content/trains/track/AllPortalTracks.java | 120 +++---------------
.../content/trains/track/TrackBlock.java | 12 +-
3 files changed, 116 insertions(+), 107 deletions(-)
create mode 100644 src/main/java/com/simibubi/create/api/contraption/train/PortalTrackProvider.java
diff --git a/src/main/java/com/simibubi/create/api/contraption/train/PortalTrackProvider.java b/src/main/java/com/simibubi/create/api/contraption/train/PortalTrackProvider.java
new file mode 100644
index 0000000000..39b2beadd5
--- /dev/null
+++ b/src/main/java/com/simibubi/create/api/contraption/train/PortalTrackProvider.java
@@ -0,0 +1,91 @@
+package com.simibubi.create.api.contraption.train;
+
+import java.util.function.BiFunction;
+import java.util.function.Function;
+
+import org.jetbrains.annotations.Nullable;
+
+import com.simibubi.create.api.registry.SimpleRegistry;
+import com.simibubi.create.content.contraptions.glue.SuperGlueEntity;
+import com.simibubi.create.content.trains.track.AllPortalTracks;
+
+import net.createmod.catnip.math.BlockFace;
+import net.minecraft.core.BlockPos;
+import net.minecraft.resources.ResourceKey;
+import net.minecraft.server.level.ServerLevel;
+import net.minecraft.world.level.Level;
+import net.minecraft.world.level.block.Block;
+import net.minecraft.world.level.block.state.BlockState;
+import net.minecraft.world.level.portal.PortalInfo;
+
+import net.minecraftforge.common.util.ITeleporter;
+
+/**
+ * A provider for portal track connections.
+ * Takes a track inbound through a portal and finds the exit location for the outbound track.
+ */
+@FunctionalInterface
+public interface PortalTrackProvider {
+ SimpleRegistry REGISTRY = SimpleRegistry.create();
+
+ /**
+ * Find the exit location for a track going through a portal.
+ * @param level the level of the inbound track
+ * @param face the face of the inbound track
+ */
+ Exit findExit(ServerLevel level, BlockFace face);
+
+ /**
+ * Checks if a given {@link BlockState} represents a supported portal block.
+ * @param state The block state to check.
+ * @return {@code true} if the block state represents a supported portal; {@code false} otherwise.
+ */
+ static boolean isSupportedPortal(BlockState state) {
+ return REGISTRY.get(state) != null;
+ }
+
+ /**
+ * Retrieves the corresponding outbound track on the other side of a portal.
+ * @param level The current {@link ServerLevel}.
+ * @param inboundTrack The inbound track {@link BlockFace}.
+ * @return the found outbound track, or null if one wasn't found.
+ */
+ @Nullable
+ static Exit getOtherSide(ServerLevel level, BlockFace inboundTrack) {
+ BlockPos portalPos = inboundTrack.getConnectedPos();
+ BlockState portalState = level.getBlockState(portalPos);
+ PortalTrackProvider provider = REGISTRY.get(portalState);
+ return provider == null ? null : provider.findExit(level, inboundTrack);
+ }
+
+ /**
+ * Find an exit location by using an {@link ITeleporter} instance.
+ * @param level The level of the inbound track
+ * @param face The face of the inbound track
+ * @param firstDimension The first dimension (typically the Overworld)
+ * @param secondDimension The second dimension (e.g., Nether, Aether)
+ * @param customPortalForcer A function to obtain the {@link ITeleporter} for the target level
+ * @return A found exit, or null if one wasn't found
+ */
+ static Exit fromTeleporter(ServerLevel level, BlockFace face, ResourceKey firstDimension,
+ ResourceKey secondDimension, Function customPortalForcer) {
+ return AllPortalTracks.fromTeleporter(level, face, firstDimension, secondDimension, customPortalForcer);
+ }
+
+ /**
+ * Find an exit location by teleporting a probe entity to find a {@link PortalInfo}.
+ * @param level The level of the inbound track
+ * @param face The face of the inbound track
+ * @param firstDimension The first dimension
+ * @param secondDimension The second dimension
+ * @param portalInfoProvider A function that provides the {@link PortalInfo} given the target level and probe entity.
+ * @return A found exit, or null if one wasn't found
+ */
+ static Exit fromProbe(ServerLevel level, BlockFace face, ResourceKey firstDimension,
+ ResourceKey secondDimension, BiFunction portalInfoProvider) {
+ return AllPortalTracks.fromProbe(level, face, firstDimension, secondDimension, portalInfoProvider);
+ }
+
+ record Exit(ServerLevel level, BlockFace face) {
+ }
+}
diff --git a/src/main/java/com/simibubi/create/content/trains/track/AllPortalTracks.java b/src/main/java/com/simibubi/create/content/trains/track/AllPortalTracks.java
index 125d11bdaa..b128bd4104 100644
--- a/src/main/java/com/simibubi/create/content/trains/track/AllPortalTracks.java
+++ b/src/main/java/com/simibubi/create/content/trains/track/AllPortalTracks.java
@@ -2,15 +2,13 @@ package com.simibubi.create.content.trains.track;
import java.util.function.BiFunction;
import java.util.function.Function;
-import java.util.function.UnaryOperator;
import com.simibubi.create.Create;
-import com.simibubi.create.api.registry.SimpleRegistry;
+import com.simibubi.create.api.contraption.train.PortalTrackProvider;
import com.simibubi.create.compat.Mods;
import com.simibubi.create.compat.betterend.BetterEndPortalCompat;
import com.simibubi.create.content.contraptions.glue.SuperGlueEntity;
-import net.createmod.catnip.data.Pair;
import net.createmod.catnip.math.BlockFace;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
@@ -38,19 +36,6 @@ import net.minecraftforge.registries.ForgeRegistries;
*
*/
public class AllPortalTracks {
- /**
- * Functional interface representing a provider for portal track connections.
- * It takes a pair of {@link ServerLevel} and {@link BlockFace} representing the inbound track
- * and returns a similar pair for the outbound track.
- */
- @FunctionalInterface
- public interface PortalTrackProvider extends UnaryOperator> {}
-
- /**
- * Registry mapping portal blocks to their respective {@link PortalTrackProvider}s.
- */
- public static final SimpleRegistry REGISTRY = SimpleRegistry.create();
-
/**
* Registers a portal track integration for a given block identified by its {@link ResourceLocation}, if it exists.
* If it does not, a warning will be logged.
@@ -61,37 +46,12 @@ public class AllPortalTracks {
public static void tryRegisterIntegration(ResourceLocation id, PortalTrackProvider provider) {
if (ForgeRegistries.BLOCKS.containsKey(id)) {
Block block = ForgeRegistries.BLOCKS.getValue(id);
- REGISTRY.register(block, provider);
+ PortalTrackProvider.REGISTRY.register(block, provider);
} else {
Create.LOGGER.warn("Portal for integration wasn't found: {}. Compat outdated?", id);
}
}
- /**
- * Checks if a given {@link BlockState} represents a supported portal block.
- *
- * @param state The block state to check.
- * @return {@code true} if the block state represents a supported portal; {@code false} otherwise.
- */
- public static boolean isSupportedPortal(BlockState state) {
- return REGISTRY.get(state.getBlock()) != null;
- }
-
- /**
- * Retrieves the corresponding outbound track on the other side of a portal.
- *
- * @param level The current {@link ServerLevel}.
- * @param inboundTrack The inbound track {@link BlockFace}.
- * @return A pair containing the target {@link ServerLevel} and outbound {@link BlockFace},
- * or {@code null} if no corresponding portal is found.
- */
- public static Pair getOtherSide(ServerLevel level, BlockFace inboundTrack) {
- BlockPos portalPos = inboundTrack.getConnectedPos();
- BlockState portalState = level.getBlockState(portalPos);
- PortalTrackProvider provider = REGISTRY.get(portalState.getBlock());
- return provider == null ? null : provider.apply(Pair.of(level, inboundTrack));
- }
-
// Built-in handlers
/**
@@ -99,7 +59,7 @@ public class AllPortalTracks {
* This includes the Nether and the Aether (if loaded).
*/
public static void registerDefaults() {
- REGISTRY.register(Blocks.NETHER_PORTAL, AllPortalTracks::nether);
+ PortalTrackProvider.REGISTRY.register(Blocks.NETHER_PORTAL, AllPortalTracks::nether);
if (Mods.AETHER.isLoaded()) {
tryRegisterIntegration(Mods.AETHER.rl("aether_portal"), AllPortalTracks::aether);
@@ -110,72 +70,41 @@ public class AllPortalTracks {
}
}
- /**
- * Portal track provider for the Nether portal.
- *
- * @param inbound A pair containing the current {@link ServerLevel} and inbound {@link BlockFace}.
- * @return A pair with the target {@link ServerLevel} and outbound {@link BlockFace}, or {@code null} if not applicable.
- */
- private static Pair nether(Pair inbound) {
- ServerLevel level = inbound.getFirst();
+ private static PortalTrackProvider.Exit nether(ServerLevel level, BlockFace face) {
MinecraftServer minecraftServer = level.getServer();
if (!minecraftServer.isNetherEnabled())
return null;
- return standardPortalProvider(inbound, Level.OVERWORLD, Level.NETHER, ServerLevel::getPortalForcer);
+ return PortalTrackProvider.fromTeleporter(level, face, Level.OVERWORLD, Level.NETHER, ServerLevel::getPortalForcer);
}
- /**
- * Portal track provider for the Aether mod's portal.
- *
- * @param inbound A pair containing the current {@link ServerLevel} and inbound {@link BlockFace}.
- * @return A pair with the target {@link ServerLevel} and outbound {@link BlockFace}, or {@code null} if not applicable.
- */
- private static Pair aether(Pair inbound) {
- ResourceKey aetherLevelKey =
- ResourceKey.create(Registries.DIMENSION, Mods.AETHER.rl("the_aether"));
- return standardPortalProvider(inbound, Level.OVERWORLD, aetherLevelKey, level -> {
+ private static PortalTrackProvider.Exit aether(ServerLevel level, BlockFace face) {
+ ResourceKey aetherLevelKey = ResourceKey.create(Registries.DIMENSION, Mods.AETHER.rl("the_aether"));
+ return PortalTrackProvider.fromTeleporter(level, face, Level.OVERWORLD, aetherLevelKey, serverLevel -> {
try {
return (ITeleporter) Class.forName("com.aetherteam.aether.block.portal.AetherPortalForcer")
.getDeclaredConstructor(ServerLevel.class, boolean.class)
- .newInstance(level, true);
+ .newInstance(serverLevel, true);
} catch (Exception e) {
Create.LOGGER.error("Failed to create Aether teleporter: ", e);
}
- return level.getPortalForcer();
+ return serverLevel.getPortalForcer();
});
}
- /**
- * Portal track provider for the Better End mod's portal.
- *
- * @param inbound A pair containing the current {@link ServerLevel} and inbound {@link BlockFace}.
- * @return A pair with the target {@link ServerLevel} and outbound {@link BlockFace}, or {@code null} if not applicable.
- */
- private static Pair betterend(Pair inbound) {
- return portalProvider(inbound, Level.OVERWORLD, Level.END, BetterEndPortalCompat::getBetterEndPortalInfo);
+ private static PortalTrackProvider.Exit betterend(ServerLevel level, BlockFace face) {
+ return fromProbe(level, face, Level.OVERWORLD, Level.END, BetterEndPortalCompat::getBetterEndPortalInfo);
}
- /**
- * Provides a standard portal track provider that handles portal traversal between two dimensions.
- *
- * @param inbound A pair containing the current {@link ServerLevel} and inbound {@link BlockFace}.
- * @param firstDimension The first dimension (typically the Overworld).
- * @param secondDimension The second dimension (e.g., Nether, Aether).
- * @param customPortalForcer A function to obtain the {@link ITeleporter} for the target level.
- * @return A pair with the target {@link ServerLevel} and outbound {@link BlockFace}, or {@code null} if not applicable.
- */
- public static Pair standardPortalProvider(
- Pair inbound,
+ public static PortalTrackProvider.Exit fromTeleporter(
+ ServerLevel level, BlockFace inboundTrack,
ResourceKey firstDimension,
ResourceKey secondDimension,
Function customPortalForcer
) {
- return portalProvider(
- inbound,
- firstDimension,
- secondDimension,
+ return PortalTrackProvider.fromProbe(
+ level, inboundTrack, firstDimension, secondDimension,
(otherLevel, probe) -> {
ITeleporter teleporter = customPortalForcer.apply(otherLevel);
return teleporter.getPortalInfo(probe, otherLevel, probe::findDimensionEntryPoint);
@@ -183,22 +112,12 @@ public class AllPortalTracks {
);
}
- /**
- * Generalized portal provider method that calculates the corresponding outbound track across a portal.
- *
- * @param inbound A pair containing the current {@link ServerLevel} and inbound {@link BlockFace}.
- * @param firstDimension The first dimension.
- * @param secondDimension The second dimension.
- * @param portalInfoProvider A function that provides the {@link PortalInfo} given the target level and probe entity.
- * @return A pair with the target {@link ServerLevel} and outbound {@link BlockFace}, or {@code null} if not applicable.
- */
- public static Pair portalProvider(
- Pair inbound,
+ public static PortalTrackProvider.Exit fromProbe(
+ ServerLevel level, BlockFace inboundTrack,
ResourceKey firstDimension,
ResourceKey secondDimension,
BiFunction portalInfoProvider
) {
- ServerLevel level = inbound.getFirst();
ResourceKey resourceKey = level.dimension() == secondDimension ? firstDimension : secondDimension;
MinecraftServer minecraftServer = level.getServer();
@@ -207,7 +126,6 @@ public class AllPortalTracks {
if (otherLevel == null)
return null;
- BlockFace inboundTrack = inbound.getSecond();
BlockPos portalPos = inboundTrack.getConnectedPos();
BlockState portalState = level.getBlockState(portalPos);
@@ -228,6 +146,6 @@ public class AllPortalTracks {
if (targetDirection.getAxis() == otherPortalState.getValue(BlockStateProperties.HORIZONTAL_AXIS))
targetDirection = targetDirection.getClockWise();
BlockPos otherPos = otherPortalPos.relative(targetDirection);
- return Pair.of(otherLevel, new BlockFace(otherPos, targetDirection.getOpposite()));
+ return new PortalTrackProvider.Exit(otherLevel, new BlockFace(otherPos, targetDirection.getOpposite()));
}
}
diff --git a/src/main/java/com/simibubi/create/content/trains/track/TrackBlock.java b/src/main/java/com/simibubi/create/content/trains/track/TrackBlock.java
index 6003bd5875..281d993625 100644
--- a/src/main/java/com/simibubi/create/content/trains/track/TrackBlock.java
+++ b/src/main/java/com/simibubi/create/content/trains/track/TrackBlock.java
@@ -28,6 +28,7 @@ import com.simibubi.create.AllBlocks;
import com.simibubi.create.AllPartialModels;
import com.simibubi.create.AllShapes;
import com.simibubi.create.AllTags;
+import com.simibubi.create.api.contraption.train.PortalTrackProvider;
import com.simibubi.create.api.schematic.requirement.SpecialBlockItemRequirement;
import com.simibubi.create.content.decoration.girder.GirderBlock;
import com.simibubi.create.content.equipment.wrench.IWrenchable;
@@ -50,7 +51,6 @@ import dev.engine_room.flywheel.lib.transform.TransformStack;
import it.unimi.dsi.fastutil.objects.Object2IntArrayMap;
import it.unimi.dsi.fastutil.objects.Object2IntMap;
import net.createmod.catnip.data.Iterate;
-import net.createmod.catnip.data.Pair;
import net.createmod.catnip.math.AngleHelper;
import net.createmod.catnip.math.BlockFace;
import net.createmod.catnip.math.VecHelper;
@@ -253,18 +253,18 @@ public class TrackBlock extends Block
for (Direction d : Iterate.directionsInAxis(portalTest)) {
BlockPos portalPos = pos.relative(d);
BlockState portalState = level.getBlockState(portalPos);
- if (!AllPortalTracks.isSupportedPortal(portalState))
+ if (!PortalTrackProvider.isSupportedPortal(portalState))
continue;
pop = true;
- Pair otherSide = AllPortalTracks.getOtherSide(level, new BlockFace(pos, d));
+ PortalTrackProvider.Exit otherSide = PortalTrackProvider.getOtherSide(level, new BlockFace(pos, d));
if (otherSide == null) {
fail = "missing";
continue;
}
- ServerLevel otherLevel = otherSide.getFirst();
- BlockFace otherTrack = otherSide.getSecond();
+ ServerLevel otherLevel = otherSide.level();
+ BlockFace otherTrack = otherSide.face();
BlockPos otherTrackPos = otherTrack.getPos();
BlockState existing = otherLevel.getBlockState(otherTrackPos);
if (!existing.canBeReplaced()) {
@@ -325,7 +325,7 @@ public class TrackBlock extends Block
BlockPos portalPos = pCurrentPos.relative(d);
BlockState portalState = level.getBlockState(portalPos);
- if (!AllPortalTracks.isSupportedPortal(portalState))
+ if (!PortalTrackProvider.isSupportedPortal(portalState))
return Blocks.AIR.defaultBlockState();
}