mirror of
https://github.com/Creators-of-Create/Create.git
synced 2025-03-04 06:44:40 +01:00
woe, API status be upon ye
- make portal track behavior API - some cleanup while I'm at it
This commit is contained in:
parent
381a0ae3bd
commit
0d013c8806
3 changed files with 116 additions and 107 deletions
|
@ -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<Block, PortalTrackProvider> 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<Level> firstDimension,
|
||||
ResourceKey<Level> secondDimension, Function<ServerLevel, ITeleporter> 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<Level> firstDimension,
|
||||
ResourceKey<Level> secondDimension, BiFunction<ServerLevel, SuperGlueEntity, PortalInfo> portalInfoProvider) {
|
||||
return AllPortalTracks.fromProbe(level, face, firstDimension, secondDimension, portalInfoProvider);
|
||||
}
|
||||
|
||||
record Exit(ServerLevel level, BlockFace face) {
|
||||
}
|
||||
}
|
|
@ -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;
|
|||
* </p>
|
||||
*/
|
||||
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<Pair<ServerLevel, BlockFace>> {}
|
||||
|
||||
/**
|
||||
* Registry mapping portal blocks to their respective {@link PortalTrackProvider}s.
|
||||
*/
|
||||
public static final SimpleRegistry<Block, PortalTrackProvider> 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<ServerLevel, BlockFace> 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<ServerLevel, BlockFace> nether(Pair<ServerLevel, BlockFace> 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<ServerLevel, BlockFace> aether(Pair<ServerLevel, BlockFace> inbound) {
|
||||
ResourceKey<Level> 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<Level> 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<ServerLevel, BlockFace> betterend(Pair<ServerLevel, BlockFace> 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<ServerLevel, BlockFace> standardPortalProvider(
|
||||
Pair<ServerLevel, BlockFace> inbound,
|
||||
public static PortalTrackProvider.Exit fromTeleporter(
|
||||
ServerLevel level, BlockFace inboundTrack,
|
||||
ResourceKey<Level> firstDimension,
|
||||
ResourceKey<Level> secondDimension,
|
||||
Function<ServerLevel, ITeleporter> 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<ServerLevel, BlockFace> portalProvider(
|
||||
Pair<ServerLevel, BlockFace> inbound,
|
||||
public static PortalTrackProvider.Exit fromProbe(
|
||||
ServerLevel level, BlockFace inboundTrack,
|
||||
ResourceKey<Level> firstDimension,
|
||||
ResourceKey<Level> secondDimension,
|
||||
BiFunction<ServerLevel, SuperGlueEntity, PortalInfo> portalInfoProvider
|
||||
) {
|
||||
ServerLevel level = inbound.getFirst();
|
||||
ResourceKey<Level> 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()));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<ServerLevel, BlockFace> 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();
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue