package moe.nekojimi.dimensionwalker; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.entity.Entity; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.border.WorldBorder; import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.levelgen.Heightmap; import net.minecraft.world.level.portal.PortalInfo; import net.minecraft.world.phys.Vec3; import net.minecraftforge.common.util.ITeleporter; import org.apache.http.io.SessionOutputBuffer; import org.jetbrains.annotations.Nullable; import java.util.ArrayList; import java.util.Comparator; import java.util.List; import java.util.function.Function; public class DimensionwalkerTeleporter implements ITeleporter { private static DimensionwalkerTeleporter INSTANCE = null; @Override public Entity placeEntity(Entity entity, ServerLevel currentWorld, ServerLevel destWorld, float yaw, Function repositionEntity) { return repositionEntity.apply(true); } @Override public @Nullable PortalInfo getPortalInfo(Entity entity, ServerLevel destWorld, Function defaultPortalInfo) { // return ITeleporter.super.getPortalInfo(entity, destWorld, defaultPortalInfo); BlockPos startPos = new BlockPos(entity.getBlockX(), entity.getBlockY(), entity.getBlockZ()); System.out.println("Current player position: " + startPos); // ChunkAccess chunk = destWorld.getChunk(startPos); // int maxHeight = startPos.getY(); // destWorld.get // for (Heightmap.Types type : Heightmap.Types.values()) // { // int height = chunk.getHeight(type,startPos.getX(),startPos.getZ()); // System.out.println("Heightmap type: " + type.name() + ", height: " + height); // if (height > maxHeight) // maxHeight = height; // } BlockPos blockPos = findSafePosition(destWorld,startPos); if (blockPos == null) blockPos = startPos; return new PortalInfo(new Vec3((double)blockPos.getX() + 0.5D, (double)blockPos.getY()+1.0D, (double)blockPos.getZ() + 0.5D), entity.getDeltaMovement(), entity.getYRot(), entity.getXRot()); } public @Nullable BlockPos findSafePosition(ServerLevel destWorld, BlockPos startPos) { // List candidates = new ArrayList<>(); WorldBorder worldborder = destWorld.getWorldBorder(); int worldHeight = Math.min(destWorld.getMaxBuildHeight(), destWorld.getMinBuildHeight() + destWorld.getLogicalHeight()) - 1; outer: for (BlockPos.MutableBlockPos pos : BlockPos.spiralAround(startPos, 16, Direction.EAST, Direction.SOUTH)) { if (pos == null) return null; ChunkAccess chunk = destWorld.getChunk(pos); int terrainHeight = chunk.getHeight(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES,pos.getX(),pos.getZ()); int freeBlocksAbove = 999; int startY = Math.min(worldHeight, terrainHeight); System.out.println("Starting search for safe destination at Y=" + startY); for (int y = startY; y >= destWorld.getMinBuildHeight(); y--) { pos.setY(y); // check that y is solid BlockState blockState = chunk.getBlockState(pos); if (blockState.getMaterial().isSolid()) { if (worldborder.isWithinBounds(pos) && y < worldHeight-3 && freeBlocksAbove >= 2) { System.out.println("Found safe destination! pos: " + pos + " material: " + blockState.getMaterial() + " state: " + blockState); return pos; // candidates.add(pos); // if (candidates.size() >= 16) // break outer; } freeBlocksAbove = 0; } else if (blockState.getMaterial().isLiquid() || !blockState.isAir()) { freeBlocksAbove = 0; // liquid blocks aren't free } else { freeBlocksAbove++; } } } // if (candidates.size() > 0) // { // candidates.sort(Comparator.comparingDouble(a -> a.distSqr(startPos))); // return candidates.get(0); // } return null; } public static ITeleporter instance() { if (INSTANCE == null) INSTANCE = new DimensionwalkerTeleporter(); return INSTANCE; } }