Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,22 @@ archivesBaseName = project.archives_base_name
version = project.mod_version
group = project.maven_group


repositories {
maven { url = "https://mvn.devos.one/snapshots/" } // Create, Porting Lib, Forge Tags, Milk Lib, Registrate
maven { url = "https://raw.githubusercontent.com/Fuzss/modresources/main/maven/" } // Forge Config API Port
maven { url = "https://jitpack.io/" } // Mixin Extras, Fabric ASM
maven { url = "https://maven.tterrag.com/" } // Flywheel
maven { url = "https://maven.jamieswhiteshirt.com/libs-release" } // Reach Entity Attributes
maven { url = "https://api.modrinth.com/maven" } // LazyDFU
}

dependencies {
minecraft "com.mojang:minecraft:${project.minecraft_version}"
//mappings minecraft.officialMojangMappings()
mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2"
modImplementation "net.fabricmc:fabric-loader:${project.loader_version}"
modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}"
modCompileOnly "com.simibubi.create:create-fabric-${minecraft_version}:${create_version}"
}

processResources {
Expand Down
6 changes: 5 additions & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,8 @@ fabric_version=0.47.8+1.18.2
# Mod Properties
mod_version=0.0.1-beta52-1.18
maven_group=net.kyrptonaught
archives_base_name=customportalapi
archives_base_name=customportalapi

# Create
# https://modrinth.com/mod/create-fabric/versions
create_version = 0.5.1-f-build.1415+mc1.18.2
Original file line number Diff line number Diff line change
Expand Up @@ -99,13 +99,15 @@ public void randomDisplayTick(BlockState state, World world, BlockPos pos, Rando

@Override
public void onEntityCollision(BlockState state, World world, BlockPos pos, Entity entity) {
EntityInCustomPortal entityInPortal = (EntityInCustomPortal) entity;
entityInPortal.tickInPortal(pos.toImmutable());
if (!entityInPortal.didTeleport()) {
if (entityInPortal.getTimeInPortal() >= entity.getMaxNetherPortalTime()) {
entityInPortal.setDidTP(true);
if (!world.isClient)
CustomTeleporter.TPToDim(world, entity, getPortalBase(world, pos), pos);
if (!entity.hasVehicle() && !entity.hasPassengers()) {
EntityInCustomPortal entityInPortal = (EntityInCustomPortal) entity;
entityInPortal.tickInPortal(pos.toImmutable());
if (!entityInPortal.didTeleport()) {
if (entityInPortal.getTimeInPortal() >= entity.getMaxNetherPortalTime()) {
entityInPortal.setDidTP(true);
if (!world.isClient)
CustomTeleporter.TPToDim(world, entity, getPortalBase(world, pos), pos);
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ public void onInitialize() {
return TypedActionResult.pass(stack);
}));

//CustomPortalBuilder.beginPortal().frameBlock(Blocks.GLOWSTONE).destDimID(new Identifier("the_nether")).lightWithWater().tintColor(46, 5, 25).registerPortal();
//CustomPortalBuilder.beginPortal().frameBlock(Blocks.BEDROCK).destDimID(new Identifier("the_end")).lightWithWater().tintColor(46, 5, 25).registerPortal();
//CustomPortalBuilder.beginPortal().frameBlock(Blocks.OBSIDIAN).destDimID(new Identifier("the_end")).tintColor(66, 135, 245).registerPortalForced();
// CustomPortalBuilder.beginPortal().frameBlock(Blocks.COBBLESTONE).lightWithItem(Items.STICK).destDimID(new Identifier("the_end")).tintColor(45, 24, 45).flatPortal().registerPortal();
//CustomPortalBuilder.beginPortal().frameBlock(Blocks.EMERALD_BLOCK).lightWithWater().destDimID(new Identifier("the_end")).tintColor(25, 76, 156).flatPortal().registerPortal();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package net.kyrptonaught.customportalapi.compat.create;

import com.google.common.collect.ImmutableMap;
import net.fabricmc.loader.api.FabricLoader;
import org.objectweb.asm.tree.ClassNode;
import org.spongepowered.asm.mixin.extensibility.IMixinConfigPlugin;
import org.spongepowered.asm.mixin.extensibility.IMixinInfo;

import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Supplier;

// file structure based off of https://github.com/Juuxel/Adorn/blob/bd70a2955640897bc68ff1f4f201fe5e6c10bc32/fabric/src/main/java/juuxel/adorn/AdornMixinPlugin.java
// and by "based off of", haha, well. let's justr say. ctrl c

/**
* Conditionally applies the TrackBlockMixin mixin only when create is loaded.
*/
public final class CreateMixinPlugin implements IMixinConfigPlugin {
private static final Supplier<Boolean> TRUE = () -> true;

private static final Map<String, Supplier<Boolean>> CONDITIONS = ImmutableMap.of(
"net.kyrptonaught.customportalapi.mixin.TrackBlockMixin", () -> FabricLoader.getInstance().isModLoaded("create"),
"net.kyrptonaught.customportalapi.mixin.DCEntityMixin", () -> FabricLoader.getInstance().isModLoaded("create")
);

@Override
public boolean shouldApplyMixin(String targetClassName, String mixinClassName) {
return CONDITIONS.getOrDefault(mixinClassName, TRUE).get();
}

// Boilerplate

@Override
public void onLoad(String mixinPackage) {

}

@Override
public String getRefMapperConfig() {
return null;
}

@Override
public void acceptTargets(Set<String> myTargets, Set<String> otherTargets) {

}

@Override
public List<String> getMixins() {
return null;
}

@Override
public void preApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) {

}

@Override
public void postApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) {

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package net.kyrptonaught.customportalapi.mixin;

import com.simibubi.create.content.trains.entity.Carriage.DimensionalCarriageEntity;
import net.kyrptonaught.customportalapi.interfaces.EntityInCustomPortal;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.server.world.ServerWorld;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;

@Mixin(DimensionalCarriageEntity.class)
public abstract class DCEntityMixin {
@Inject(method = "dismountPlayer", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/network/ServerPlayerEntity;resetNetherPortalCooldown()V"))
public void CPAPortalCooldown(ServerWorld sLevel, ServerPlayerEntity sp, Integer seat, boolean capture, CallbackInfo ci) {
((EntityInCustomPortal)(Object)sp).setDidTP(true);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,220 @@
package net.kyrptonaught.customportalapi.mixin;

import java.util.Random;

import com.google.common.base.Predicates;
import com.simibubi.create.content.contraptions.glue.SuperGlueEntity;
import com.simibubi.create.content.trains.track.TrackBlock;
import com.simibubi.create.content.trains.track.TrackBlockEntity;
import com.simibubi.create.foundation.utility.BlockFace;
import com.simibubi.create.foundation.utility.Components;
import com.simibubi.create.foundation.utility.Iterate;

import com.simibubi.create.foundation.utility.Lang;
import com.simibubi.create.foundation.utility.Pair;

import net.kyrptonaught.customportalapi.CustomPortalApiRegistry;
import net.kyrptonaught.customportalapi.CustomPortalBlock;
import net.kyrptonaught.customportalapi.CustomPortalsMod;
import net.kyrptonaught.customportalapi.util.CustomPortalHelper;
import net.kyrptonaught.customportalapi.util.CustomTeleporter;
import net.kyrptonaught.customportalapi.util.PortalLink;
import net.minecraft.util.Formatting;
import net.minecraft.util.math.Direction;
import net.minecraft.util.math.Direction.Axis;
import net.minecraft.text.MutableText;
import net.minecraft.util.registry.RegistryKey;
import net.minecraft.server.MinecraftServer;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.world.World;
import net.minecraft.block.NetherPortalBlock;

import net.minecraft.block.entity.BlockEntity;

import net.minecraft.state.property.BooleanProperty;
import net.minecraft.world.PortalForcer;
import net.minecraft.world.TeleportTarget;
import net.minecraft.util.math.Box;

import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;

import com.simibubi.create.content.trains.track.TrackPropagator;
import com.simibubi.create.content.trains.track.TrackShape;

import net.minecraft.util.math.BlockPos;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.block.BlockState;
import net.minecraft.state.property.EnumProperty;


/**
* Mixin applied to the TrackBlock class in the Create mod so that it can recognize and use customportalapi portals.
*/
@Mixin(TrackBlock.class)
public abstract class TrackBlockMixin {


@Shadow
protected abstract void connectToNether(ServerWorld level, BlockPos pos, BlockState state);

@Shadow
@Final
public static final EnumProperty<TrackShape> SHAPE = EnumProperty.of("shape", TrackShape.class);

@Shadow
@Final
public static final BooleanProperty HAS_BE = BooleanProperty.of("turn");

protected void connectToOtherDimension(ServerWorld level, BlockPos pos, BlockState state) {
TrackShape shape = state.get(TrackBlock.SHAPE);
Axis portalTest = shape == TrackShape.XO ? Axis.X : shape == TrackShape.ZO ? Axis.Z : null;
if (portalTest == null)
return;

boolean pop = false;
String fail = null;
BlockPos failPos = null;

for(Direction d : Iterate.directionsInAxis(portalTest)) {
BlockPos portalPos = pos.offset(d);
BlockState portalState = level.getBlockState(portalPos);
if (!(portalState.getBlock() instanceof NetherPortalBlock) && !(portalState.getBlock() instanceof CustomPortalBlock))
continue;

if(portalState.getBlock() instanceof NetherPortalBlock) {
connectToNether(level, pos, state);
}
if(portalState.getBlock() instanceof CustomPortalBlock) {
connectToCustomPortal(level, pos, state);
}
}
}

protected void connectToCustomPortal(ServerWorld level, BlockPos pos, BlockState state) {
TrackShape shape = state.get(TrackBlock.SHAPE);
Axis portalTest = shape == TrackShape.XO ? Axis.X : shape == TrackShape.ZO ? Axis.Z : null;
if (portalTest == null)
return;

boolean pop = false;
String fail = null;
BlockPos failPos = null;

for(Direction d : Iterate.directionsInAxis(portalTest)) {
BlockPos portalPos = pos.offset(d);
BlockState portalState = level.getBlockState(portalPos);
if (!(portalState.getBlock() instanceof CustomPortalBlock))
continue;

pop = true;
Pair<ServerWorld, BlockFace> otherSide = getOtherSide(level, new BlockFace(pos, d));
if (otherSide == null) {
fail = "missing";
continue;
}

ServerWorld otherLevel = otherSide.getFirst();
BlockFace otherTrack = otherSide.getSecond();
BlockPos otherTrackPos = otherTrack.getPos();
BlockState existing = otherLevel.getBlockState(otherTrackPos);
if(!existing.getMaterial()
.isReplaceable()) {
fail = "blocked";
failPos = otherTrackPos;
continue;
}

level.setBlockState(pos, state.with(SHAPE, TrackShape.asPortal(d))
.with(HAS_BE, true), 3);
BlockEntity be = level.getBlockEntity(pos);
if (be instanceof TrackBlockEntity tbe)
tbe.bind(otherLevel.getRegistryKey(), otherTrackPos);

otherLevel.setBlockState(otherTrackPos, state.with(SHAPE, TrackShape.asPortal(otherTrack.getFace()))
.with(HAS_BE, true), 3);
BlockEntity otherBE = otherLevel.getBlockEntity(otherTrackPos);
if (otherBE instanceof TrackBlockEntity tbe)
tbe.bind(level.getRegistryKey(), pos);

pop = false;
}

if (!pop)
return;

level.breakBlock(pos, true);

if (fail == null)
return;
PlayerEntity player = level.getClosestPlayer(pos.getX(), pos.getY(), pos.getZ(), 10, Predicates.alwaysTrue());
if (player == null)
return;
player.sendMessage(Components.literal("<!> ").append(Lang.translateDirect("portal_track.failed"))
.formatted(Formatting.GOLD), false);
MutableText component =
failPos != null ? Lang.translateDirect("portal_track." + fail, failPos.getX(), failPos.getY(), failPos.getZ())
: Lang.translateDirect("portal_track." + fail);
player.sendMessage(Components.literal(" - ").formatted(Formatting.GRAY)
.append(component.styled(st -> st.withColor(0xFFD3B4))), false);
}

@Inject(method = "scheduledTick", at = @At("HEAD"), cancellable = true)
private void CPAtrackBlockTick(BlockState state, ServerWorld level, BlockPos pos, Random p_60465_, CallbackInfo ci) {
TrackPropagator.onRailAdded(level, pos, state);
if (!state.get(SHAPE)
.isPortal())
connectToOtherDimension(level, pos, state);
ci.cancel();
}

protected Pair<ServerWorld, BlockFace> getOtherSide(ServerWorld level, BlockFace inboundTrack) {
BlockPos portalPos = inboundTrack.getConnectedPos();
BlockState portalState = level.getBlockState(portalPos);
if (!(portalState.getBlock() instanceof NetherPortalBlock) && !(portalState.getBlock() instanceof CustomPortalBlock))
return null;

MinecraftServer minecraftserver = level.getServer();
ServerWorld otherLevel = null;
if(portalState.getBlock() instanceof NetherPortalBlock) {
RegistryKey<World> resourcekey = level.getRegistryKey() == World.NETHER ? World.OVERWORLD : World.NETHER;
otherLevel = minecraftserver.getWorld(resourcekey);
} else {
PortalLink link = CustomPortalApiRegistry.getPortalLinkFromBase(((CustomPortalBlock)portalState.getBlock()).getPortalBase(level, portalPos));
RegistryKey<World> resourcekey = level.getRegistryKey() == CustomPortalsMod.dims.get(link.dimID) ? CustomPortalsMod.dims.get(link.returnDimID) : CustomPortalsMod.dims.get(link.dimID);;
otherLevel = minecraftserver.getWorld(resourcekey);
}
if (otherLevel == null)
return null;

PortalForcer teleporter = otherLevel.getPortalForcer();
TeleportTarget portalinfo = null;
SuperGlueEntity probe = new SuperGlueEntity(level, new Box(portalPos));
probe.setYaw(inboundTrack.getFace()
.asRotation());
if(portalState.getBlock() instanceof NetherPortalBlock) {
portalinfo = probe.getTeleportTarget(otherLevel);
} else {
PortalLink link = CustomPortalApiRegistry.getPortalLinkFromBase(((CustomPortalBlock)portalState.getBlock()).getPortalBase(level, portalPos));
portalinfo = CustomTeleporter.customTPTarget(otherLevel, probe, portalPos, ((CustomPortalBlock)portalState.getBlock()).getPortalBase(level, portalPos), link.getFrameTester());
}
if (portalinfo == null)
return null;

BlockPos otherPortalPos = new BlockPos(portalinfo.position);
BlockState otherPortalState = otherLevel.getBlockState(otherPortalPos);
if (!(otherPortalState.getBlock() instanceof NetherPortalBlock) && !(otherPortalState.getBlock() instanceof CustomPortalBlock))
return null;

Direction targetDirection = inboundTrack.getFace();
if (targetDirection.getAxis() == CustomPortalHelper.getAxisFrom(otherPortalState)) {
targetDirection = targetDirection.rotateYClockwise();
}
BlockPos otherPos = otherPortalPos.offset(targetDirection);
return Pair.of(otherLevel, new BlockFace(otherPos, targetDirection.getOpposite()));
}
}
5 changes: 4 additions & 1 deletion src/main/resources/customportalapi.mixins.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,15 @@
"minVersion": "0.8",
"package": "net.kyrptonaught.customportalapi.mixin",
"compatibilityLevel": "JAVA_16",
"plugin": "net.kyrptonaught.customportalapi.compat.create.CreateMixinPlugin",
"mixins": [
"DCEntityMixin",
"EntityMixin",
"ServerPlayerMixin",
"portalLighters.AbstractFireMixin",
"portalLighters.FluidBlockPlacedMixin",
"portalLighters.PotionEntityMixin"
"portalLighters.PotionEntityMixin",
"TrackBlockMixin"
],
"client": [
"client.ChunkRendererRegionAccessor",
Expand Down