package com.thebrokenrail.energonrelics.block.portal; import com.mojang.brigadier.exceptions.CommandSyntaxException; import com.thebrokenrail.energonrelics.config.HardcodedConfig; import com.thebrokenrail.energonrelics.mixin.ServerPlayerEntityAccessor; import net.minecraft.block.Block; import net.minecraft.block.BlockState; import net.minecraft.block.Blocks; import net.minecraft.entity.Entity; import net.minecraft.network.packet.s2c.play.PlayerPositionLookS2CPacket; import net.minecraft.server.command.TeleportCommand; import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.server.world.ServerWorld; import net.minecraft.sound.SoundCategory; import net.minecraft.sound.SoundEvents; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Vec3d; import net.minecraft.util.registry.RegistryKey; import net.minecraft.world.Heightmap; import net.minecraft.world.World; import java.util.EnumSet; class EnergyTeleporter { private static void teleport(Entity entity, ServerWorld to, Vec3d pos) { if (entity instanceof ServerPlayerEntity) { ((ServerPlayerEntityAccessor) entity).setInTeleportationState(true); } try { TeleportCommand.teleport(null, entity, to, pos.getX(), pos.getY(), pos.getZ(), EnumSet.noneOf(PlayerPositionLookS2CPacket.Flag.class), entity.yaw, entity.pitch, null); } catch (CommandSyntaxException e) { throw new RuntimeException(e); } if (entity instanceof ServerPlayerEntity) { ((ServerPlayerEntity) entity).networkHandler.syncWithPlayerPosition(); } } static void teleport(ServerWorld world, Vec3d pos, BlockPos blockPos, Entity entity) { BlockPos center = EnergyPortalBlock.getCenterPos(world, blockPos); Vec3d offset = pos.subtract(Vec3d.ofBottomCenter(center)); RegistryKey worldKey = world.getRegistryKey(); if (worldKey == World.OVERWORLD) { teleportWithMultiplier(world, entity, center, offset, World.NETHER, 1d / HardcodedConfig.ENERGY_PORTAL_MULTIPLIER); } else if (worldKey == World.NETHER) { teleportWithMultiplier(world, entity, center, offset, World.OVERWORLD, HardcodedConfig.ENERGY_PORTAL_MULTIPLIER); } else { teleportToWorldSpawn(world, entity); } if (entity instanceof ServerPlayerEntity) { ((ServerPlayerEntity) entity).playSound(SoundEvents.BLOCK_PORTAL_TRAVEL, SoundCategory.PLAYERS, 0.25f, world.random.nextFloat() * 0.4f + 0.8f); } } private static int convertY(int y, int oldHeight, int newHeight) { int newY = (int) (((float) newHeight / (float) oldHeight) * (float) y); int bottomY = HardcodedConfig.ENERGY_PORTAL_Y_PADDING; int topY = newHeight - (bottomY + HardcodedConfig.ENERGY_PORTAL_Y_PADDING_EXTRA_TOP); newY = Math.max(bottomY, Math.min(topY, newY)); return newY; } private static void teleportWithMultiplier(ServerWorld world, Entity entity, BlockPos center, Vec3d offset, RegistryKey toKey, double multiplier) { ServerWorld to = world.getServer().getWorld(toKey); assert to != null; int y = convertY(center.getY(), world.getDimensionHeight(), to.getDimensionHeight()); int x = (int) (center.getX() * multiplier); int z = (int) (center.getZ() * multiplier); BlockPos targetBlock = new BlockPos(x, y, z); BlockPos start = targetBlock.add(-1, -1, -1); for (int xPos = 0; xPos < 3; xPos++) { for (int yPos = 0; yPos < 4; yPos++) { for (int zPos = 0; zPos < 3; zPos++) { BlockPos pos = start.add(xPos, yPos, zPos); BlockState oldState = to.getBlockState(pos); if (oldState.getHardness(world, pos) >= 0) { Block block = yPos == 0 ? Blocks.OBSIDIAN : Blocks.AIR; BlockState state = block.getDefaultState(); to.setBlockState(pos, state); } } } } offset = new Vec3d(offset.getX(), Math.max(0, offset.getY()), offset.getZ()); Vec3d target = Vec3d.ofBottomCenter(targetBlock).add(offset); teleport(entity, to, target); } private static void teleportToWorldSpawn(ServerWorld world, Entity entity) { ServerWorld to = world.getServer().getWorld(World.OVERWORLD); assert to != null; BlockPos dest = to.getTopPosition(Heightmap.Type.MOTION_BLOCKING_NO_LEAVES, to.getSpawnPos()); teleport(entity, to, Vec3d.ofBottomCenter(dest)); } }