From 5a96b64800d261e9a0510b6b4238b5c0577599fc Mon Sep 17 00:00:00 2001 From: 50ap5ud5 <50ap5ud5125@gmail.com> Date: Fri, 29 Dec 2023 19:37:46 +1100 Subject: [PATCH] Made teleporting respect the collision shape of blocks. TODO: Handle obstructed destination -Accounted for entities with a hitbox width larger than one -Made door collision box be two blocks high. This allows entities with smaller hitboxes such as chickens or items to have a larger surface to be teleported more easily --- .../common/block/door/GlobalDoorBlock.java | 20 +- .../common/block/door/InternalDoorBlock.java | 18 +- .../common/block/shell/ShellBaseBlock.java | 21 +- .../door/AbstractDoorBlockEntity.java | 5 +- .../blockentity/door/TardisInternalDoor.java | 4 + .../shell/ShellBaseBlockEntity.java | 1 + .../common/dimension/TardisTeleportData.java | 20 +- .../common/tardis/ExteriorShell.java | 4 + .../common/util/TRTeleporter.java | 221 +++++++++++------- .../common/util/TardisHelper.java | 1 - 10 files changed, 201 insertions(+), 114 deletions(-) diff --git a/common/src/main/java/whocraft/tardis_refined/common/block/door/GlobalDoorBlock.java b/common/src/main/java/whocraft/tardis_refined/common/block/door/GlobalDoorBlock.java index 31de07a03..24552ed35 100644 --- a/common/src/main/java/whocraft/tardis_refined/common/block/door/GlobalDoorBlock.java +++ b/common/src/main/java/whocraft/tardis_refined/common/block/door/GlobalDoorBlock.java @@ -25,7 +25,10 @@ public class GlobalDoorBlock extends InternalDoorBlock{ - protected static final VoxelShape SOUTH_AABB, NORTH_AABB, WEST_AABB, EAST_AABB; + protected static final VoxelShape NORTH_AABB = Block.box(0.0D, 0.0D, 0.0D, 16.0D, 32.0D, 0.25D); + protected static final VoxelShape SOUTH_AABB = Block.box(0.0D, 0.0D, 15.75D, 16.0D, 32.0D, 16.0D); + protected static final VoxelShape EAST_AABB= Block.box(15.75D, 0.0D, 0.0D, 16.0D, 32.0D, 16.0D); + protected static final VoxelShape WEST_AABB = Block.box(0.0D, 0.0D, 0.0D, 0.25D, 32.0D, 16.0D); public GlobalDoorBlock(Properties properties) { super(properties); @@ -69,7 +72,6 @@ public BlockState getStateForPlacement(@NotNull BlockPlaceContext blockPlaceCont public InteractionResult use(BlockState blockState, Level level, BlockPos blockPos, Player player, InteractionHand interactionHand, BlockHitResult blockHitResult) { if (interactionHand == InteractionHand.MAIN_HAND) { if (level instanceof ServerLevel serverLevel) { - if (TardisLevelOperator.get(serverLevel).isPresent()) { if (serverLevel.getBlockEntity(blockPos) instanceof GlobalDoorBlockEntity entity) { entity.onRightClick(blockState, entity, player); @@ -86,22 +88,20 @@ public InteractionResult use(BlockState blockState, Level level, BlockPos blockP public VoxelShape getShape(BlockState blockState, BlockGetter blockGetter, BlockPos blockPos, CollisionContext collisionContext) { switch(blockState.getValue(FACING)) { case EAST: - default: - return EAST_AABB; + return EAST_AABB; case SOUTH: - return SOUTH_AABB ; + return SOUTH_AABB; case WEST: return WEST_AABB; case NORTH: return NORTH_AABB; } + return SOUTH_AABB; } - static { - NORTH_AABB = Block.box(0.0D, 0.0D, 0.0D, 16.0D, 16.0D, 0.25D); - SOUTH_AABB = Block.box(0.0D, 0.0D, 15.75D, 16.0D, 16.0D, 16.0D); - EAST_AABB= Block.box(15.75D, 0.0D, 0.0D, 16.0D, 16.0D, 16.0D); - WEST_AABB = Block.box(0.0D, 0.0D, 0.0D, 0.25D, 16.0D, 16.0D); + @Override + public VoxelShape getCollisionShape(BlockState blockState, BlockGetter blockGetter, BlockPos blockPos, CollisionContext collisionContext) { + return this.getShape(blockState, blockGetter, blockPos, collisionContext); } } diff --git a/common/src/main/java/whocraft/tardis_refined/common/block/door/InternalDoorBlock.java b/common/src/main/java/whocraft/tardis_refined/common/block/door/InternalDoorBlock.java index e69bd57f3..cda5e4b95 100644 --- a/common/src/main/java/whocraft/tardis_refined/common/block/door/InternalDoorBlock.java +++ b/common/src/main/java/whocraft/tardis_refined/common/block/door/InternalDoorBlock.java @@ -2,6 +2,7 @@ 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.item.context.BlockPlaceContext; import net.minecraft.world.level.BlockGetter; @@ -15,17 +16,22 @@ import net.minecraft.world.level.block.state.StateDefinition; import net.minecraft.world.level.block.state.properties.BooleanProperty; import net.minecraft.world.level.block.state.properties.DirectionProperty; +import net.minecraft.world.phys.AABB; import net.minecraft.world.phys.shapes.CollisionContext; import net.minecraft.world.phys.shapes.VoxelShape; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import whocraft.tardis_refined.common.blockentity.door.InternalDoorBlockEntity; +import whocraft.tardis_refined.common.blockentity.door.TardisInternalDoor; +import whocraft.tardis_refined.common.util.TRTeleporter; + +import java.util.List; public class InternalDoorBlock extends BaseEntityBlock { public static final DirectionProperty FACING = HorizontalDirectionalBlock.FACING; public static final BooleanProperty OPEN = BooleanProperty.create("open"); - protected static final VoxelShape COLLISION = Block.box(0, 0, 0, 16, 3, 16); + protected static final VoxelShape COLLISION = Block.box(0, 0, 0, 16, 32, 16); protected static BlockEntity blockEntity; @@ -50,7 +56,7 @@ public VoxelShape getShape(BlockState blockState, BlockGetter blockGetter, Block @Override public VoxelShape getCollisionShape(BlockState blockState, BlockGetter blockGetter, BlockPos blockPos, CollisionContext collisionContext) { - return COLLISION; + return this.getShape(blockState, blockGetter, blockPos, collisionContext); } @Nullable @@ -88,8 +94,12 @@ public BlockState getStateForPlacement(@NotNull BlockPlaceContext blockPlaceCont public void entityInside(BlockState blockState, Level level, BlockPos blockPos, Entity entity) { if (!level.isClientSide()) { - if (level.getBlockEntity(blockPos) instanceof InternalDoorBlockEntity door) { - door.onAttemptEnter(blockState, level, blockPos, entity); + ServerLevel serverLevel = (ServerLevel)level; + if (serverLevel.getBlockEntity(blockPos) instanceof TardisInternalDoor door) { + AABB teleportAABB = this.getCollisionShape(blockState, level, blockPos, CollisionContext.of(entity)).bounds().move(blockPos); + if (TRTeleporter.teleportIfCollided(serverLevel, blockPos, entity, teleportAABB)){ + door.onAttemptEnter(blockState, serverLevel, blockPos, entity); + } } } } diff --git a/common/src/main/java/whocraft/tardis_refined/common/block/shell/ShellBaseBlock.java b/common/src/main/java/whocraft/tardis_refined/common/block/shell/ShellBaseBlock.java index a4649a608..059a924e8 100644 --- a/common/src/main/java/whocraft/tardis_refined/common/block/shell/ShellBaseBlock.java +++ b/common/src/main/java/whocraft/tardis_refined/common/block/shell/ShellBaseBlock.java @@ -4,7 +4,6 @@ import net.minecraft.core.Direction; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.context.BlockPlaceContext; import net.minecraft.world.level.BlockGetter; import net.minecraft.world.level.Level; @@ -19,11 +18,15 @@ import net.minecraft.world.level.gameevent.GameEventListener; import net.minecraft.world.level.material.FluidState; import net.minecraft.world.level.material.Fluids; +import net.minecraft.world.phys.AABB; import net.minecraft.world.phys.shapes.CollisionContext; import net.minecraft.world.phys.shapes.VoxelShape; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import whocraft.tardis_refined.common.blockentity.shell.ShellBaseBlockEntity; +import whocraft.tardis_refined.common.tardis.ExteriorShell; +import whocraft.tardis_refined.common.util.TRTeleporter; + +import java.util.List; public abstract class ShellBaseBlock extends BaseEntityBlock implements SimpleWaterloggedBlock, Fallable { @@ -122,16 +125,24 @@ public VoxelShape getShape(BlockState blockState, BlockGetter blockGetter, Block return EAST_AABB; } } - return SOUTH_AABB; } + @Override + public VoxelShape getCollisionShape(BlockState blockState, BlockGetter blockGetter, BlockPos blockPos, CollisionContext collisionContext) { + return this.getShape(blockState, blockGetter, blockPos, collisionContext); + } + @Override public void entityInside(BlockState blockState, Level level, BlockPos blockPos, Entity entity) { if (!level.isClientSide()){ - if (level.getBlockEntity(blockPos) instanceof ShellBaseBlockEntity shellEntity) { - shellEntity.onAttemptEnter(blockState, level, shellEntity.getBlockPos(), entity); + ServerLevel serverLevel = (ServerLevel)level; + if (serverLevel.getBlockEntity(blockPos) instanceof ExteriorShell shellEntity) { + AABB teleportAABB = this.getCollisionShape(blockState, level, blockPos, CollisionContext.of(entity)).bounds().move(blockPos); + if (TRTeleporter.teleportIfCollided(serverLevel, blockPos, entity, teleportAABB)) { + shellEntity.onAttemptEnter(blockState, serverLevel, blockPos, entity); + } } } } diff --git a/common/src/main/java/whocraft/tardis_refined/common/blockentity/door/AbstractDoorBlockEntity.java b/common/src/main/java/whocraft/tardis_refined/common/blockentity/door/AbstractDoorBlockEntity.java index 449f2315f..e71494d7b 100644 --- a/common/src/main/java/whocraft/tardis_refined/common/blockentity/door/AbstractDoorBlockEntity.java +++ b/common/src/main/java/whocraft/tardis_refined/common/blockentity/door/AbstractDoorBlockEntity.java @@ -78,14 +78,14 @@ public BlockPos getDoorPosition() { @Override public BlockPos getEntryPosition() { - Direction direction = this.getBlockState().getValue(ShellBaseBlock.FACING); + Direction direction = this.getBlockState().getValue(InternalDoorBlock.FACING); return this.getBlockPos().offset(direction.getOpposite().getNormal()); } @Override public Direction getEntryRotation() { - return getBlockState().getValue(InternalDoorBlock.FACING).getOpposite(); + return this.getBlockState().getValue(InternalDoorBlock.FACING).getOpposite(); } @Override @@ -134,6 +134,7 @@ public void load(CompoundTag compoundTag) { this.isLocked = compoundTag.getBoolean(NbtConstants.DOOR_IS_LOCKED); } + @Override public void onAttemptEnter(BlockState blockState, Level level, BlockPos doorPos, Entity entity) { if(!entity.level().isClientSide() && level instanceof ServerLevel serverLevel){ Optional data = TardisLevelOperator.get(serverLevel); diff --git a/common/src/main/java/whocraft/tardis_refined/common/blockentity/door/TardisInternalDoor.java b/common/src/main/java/whocraft/tardis_refined/common/blockentity/door/TardisInternalDoor.java index 37ee48566..633abbb30 100644 --- a/common/src/main/java/whocraft/tardis_refined/common/blockentity/door/TardisInternalDoor.java +++ b/common/src/main/java/whocraft/tardis_refined/common/blockentity/door/TardisInternalDoor.java @@ -3,6 +3,9 @@ import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.server.level.ServerEntity; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.state.BlockState; import java.util.UUID; @@ -27,5 +30,6 @@ public interface TardisInternalDoor { void setLocked(boolean locked); boolean locked(); + void onAttemptEnter(BlockState blockState, Level level, BlockPos doorPos, Entity entity); } diff --git a/common/src/main/java/whocraft/tardis_refined/common/blockentity/shell/ShellBaseBlockEntity.java b/common/src/main/java/whocraft/tardis_refined/common/blockentity/shell/ShellBaseBlockEntity.java index 1cd4d9df8..fed584ecd 100644 --- a/common/src/main/java/whocraft/tardis_refined/common/blockentity/shell/ShellBaseBlockEntity.java +++ b/common/src/main/java/whocraft/tardis_refined/common/blockentity/shell/ShellBaseBlockEntity.java @@ -89,6 +89,7 @@ public boolean shouldSetup() { return false; } + @Override public void onAttemptEnter(BlockState blockState, Level level, BlockPos externalShellPos, Entity entity) { if (!entity.level().isClientSide() && level instanceof ServerLevel serverLevel) { if (this.TARDIS_ID == null) { diff --git a/common/src/main/java/whocraft/tardis_refined/common/dimension/TardisTeleportData.java b/common/src/main/java/whocraft/tardis_refined/common/dimension/TardisTeleportData.java index c5d495462..73255aebd 100644 --- a/common/src/main/java/whocraft/tardis_refined/common/dimension/TardisTeleportData.java +++ b/common/src/main/java/whocraft/tardis_refined/common/dimension/TardisTeleportData.java @@ -63,7 +63,7 @@ public static void tick(ServerLevel level) { if (teleports.size() != 0){ for (TeleportEntry entry : teleports) { - if (!entry.getIsCurrentTeleporting()) { + if (!entry.getIsCurrentTeleporting() && !entry.getSuccessfulTeleport()) { entry.setIsCurrentTeleporting(true); Entity entity = entry.getEntity(); @@ -74,13 +74,17 @@ public static void tick(ServerLevel level) { if (entity != null && targetWorld != null && entity.level() == level) { if (TRTeleporter.performTeleport(entity, targetWorld, entry.getX(), entry.getY(), entry.getZ(), entry.getyRot(), entry.getxRot(), teleportedEntities)) { teleportedEntities.add(entity); + entry.setIsCurrentTeleporting(true); + } + else { + entry.setSuccessfulTeleport(false); } } } } - // remove all entities that were teleported from the queue - teleports.removeIf(teleportEntry -> teleportedEntities.contains(teleportEntry.getEntity())); + // remove all entities that were successfully teleported. Also remove failed teleports to prevent a backlog from building up + teleports.removeIf(teleportEntry -> teleportedEntities.contains(teleportEntry.getEntity()) || !teleportEntry.getSuccessfulTeleport()); eventData.queuedTeleports = teleports; } @@ -113,6 +117,8 @@ private static final class TeleportEntry{ private final float yRot, xRot; private boolean isCurrentTeleporting = false; + private boolean successfulTeleport = false; + public TeleportEntry(Entity entity, ResourceKey destination, double x, double y, double z, float yRot, float xRot) { this.entity = entity; this.destination = destination; @@ -158,5 +164,13 @@ public boolean getIsCurrentTeleporting() { public void setIsCurrentTeleporting(boolean isCurrentTeleporting) { this.isCurrentTeleporting = isCurrentTeleporting; } + + public boolean getSuccessfulTeleport() { + return successfulTeleport; + } + + public void setSuccessfulTeleport(boolean successfulTeleport) { + this.isCurrentTeleporting = successfulTeleport; + } } } \ No newline at end of file diff --git a/common/src/main/java/whocraft/tardis_refined/common/tardis/ExteriorShell.java b/common/src/main/java/whocraft/tardis_refined/common/tardis/ExteriorShell.java index 7c21a30ac..3a70b6faa 100644 --- a/common/src/main/java/whocraft/tardis_refined/common/tardis/ExteriorShell.java +++ b/common/src/main/java/whocraft/tardis_refined/common/tardis/ExteriorShell.java @@ -2,7 +2,9 @@ import net.minecraft.core.BlockPos; import net.minecraft.resources.ResourceKey; +import net.minecraft.world.entity.Entity; import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.state.BlockState; import whocraft.tardis_refined.common.tardis.themes.DesktopTheme; public interface ExteriorShell { @@ -14,4 +16,6 @@ public interface ExteriorShell { void setTardisId(ResourceKey levelKey); + void onAttemptEnter(BlockState blockState, Level level, BlockPos externalShellPos, Entity entity); + } diff --git a/common/src/main/java/whocraft/tardis_refined/common/util/TRTeleporter.java b/common/src/main/java/whocraft/tardis_refined/common/util/TRTeleporter.java index 9b892b65e..d8eabd372 100644 --- a/common/src/main/java/whocraft/tardis_refined/common/util/TRTeleporter.java +++ b/common/src/main/java/whocraft/tardis_refined/common/util/TRTeleporter.java @@ -14,16 +14,14 @@ import net.minecraft.world.level.Level; import net.minecraft.world.level.pathfinder.BlockPathTypes; import net.minecraft.world.level.pathfinder.WalkNodeEvaluator; +import net.minecraft.world.phys.AABB; import net.minecraft.world.phys.Vec3; import whocraft.tardis_refined.registry.TagKeys; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; +import java.util.*; public class TRTeleporter { - private static boolean canTeleportTo(BlockPos pPos, Level level, Entity entity) { + public static boolean canTeleportTo(BlockPos pPos, Level level, Entity entity) { BlockPathTypes blockpathtypes = WalkNodeEvaluator.getBlockPathTypeStatic(level, pPos.mutable()); if (blockpathtypes != BlockPathTypes.WALKABLE) { return false; @@ -51,105 +49,32 @@ public static boolean performTeleport(Entity pEntity, ServerLevel pLevel, double public static boolean performTeleport(Entity pEntity, Entity vehicle, ServerLevel destination, double pX, double pY, double pZ, float pYaw, float pPitch, boolean safeBlockCheck, Set teleportedEntities) { if (pEntity.level() instanceof ServerLevel) { - - int xRound = (int) pX; - int yRound = (int) pY; - int zRound = (int) pZ; - BlockPos blockpos = new BlockPos(xRound, yRound, zRound); - - if (teleportedEntities.size() != 0){ - if (teleportedEntities.contains(pEntity)){ //If we are calling this method by itself such as teleporting passengers, check if we have already teleported the entity - return false; - } - } - - if (pEntity.getType().is(TagKeys.TARDIS_TELEPORT_BLACKLIST)) //Stop teleporting if the entity being teleported is blacklisted - return false; - - if (safeBlockCheck) { - if (!canTeleportTo(blockpos, destination, pEntity)) { - return false; - } - } - - if (!Level.isInSpawnableBounds(blockpos)) { - return false; - } else { + if (safetyCheck(pEntity, destination, pX, pY, pZ, pYaw, pPitch, safeBlockCheck, teleportedEntities)) { + pEntity.unRide(); Entity teleportedEntity; List passengers = pEntity.getPassengers(); - pEntity.unRide(); - float updatedYRot = Mth.wrapDegrees(pYaw); float updatedXRot = Mth.wrapDegrees(pPitch); if (pEntity instanceof ServerPlayer serverPlayer) { //Always update player data, do not create new instances of the player + teleportedEntity = teleportPlayer(serverPlayer, destination, pX, pY, pZ, updatedYRot, updatedXRot); - if (serverPlayer.isSleeping()) { - serverPlayer.stopSleepInBed(true, true); - } - - pEntity.setDeltaMovement(Vec3.ZERO); //set velocity to 0 because otherwise we will trigger the "player moved wrongly" hardcoded vanilla check which will result in the player not changing coordinates in the new dimension - - serverPlayer.connection.send(new ClientboundRespawnPacket(serverPlayer.createCommonSpawnInfo(destination), (byte)3)); - serverPlayer.connection.send(new ClientboundChangeDifficultyPacket(destination.getLevelData().getDifficulty(), destination.getLevelData().isDifficultyLocked())); - - serverPlayer.teleportTo(destination, pX, pY, pZ, updatedYRot, updatedXRot); - - serverPlayer.setPortalCooldown(); //Prevent player from being teleport by nether portal in the destination dimension - pEntity.setYHeadRot(updatedYRot); - - - //Handle player experience not getting received on client after interdimensional teleport - serverPlayer.connection.send(new ClientboundSetExperiencePacket(serverPlayer.experienceProgress, serverPlayer.totalExperience, serverPlayer.experienceLevel)); - serverPlayer.connection.send(new ClientboundPlayerAbilitiesPacket(serverPlayer.getAbilities()));//Keep abilities like creative mode flight height etc. - serverPlayer.connection.send(new ClientboundChangeDifficultyPacket(serverPlayer.level().getDifficulty(), serverPlayer.level().getLevelData().isDifficultyLocked())); - - teleportedEntity = destination.getPlayerByUUID(serverPlayer.getUUID()); - - } else { - //For non player entities, always create new instances if inter dimensional teleporting - float adjustedXRot = Mth.clamp(updatedXRot, -90.0F, 90.0F); - Vec3 oldMotion = pEntity.getDeltaMovement(); - - if (destination == pEntity.level()) { - pEntity.moveTo(pX, pY, pZ, updatedYRot, adjustedXRot); - pEntity.setYHeadRot(updatedYRot); - pEntity.setDeltaMovement(oldMotion); - pEntity.setPortalCooldown(); - teleportedEntity = pEntity; - } else { - //Get most of this logic from Entity#changeDimension which is most suitable as it has most syncing logic. However, we want to exclude the use of PortalInfo as it plays the vanilla portal sounds - Entity newEntity = pEntity; - - newEntity = newEntity.getType().create(destination); - if (newEntity == null) { - return false; - } - - newEntity.restoreFrom(pEntity); - newEntity.moveTo(pX, pY, pZ, updatedYRot, adjustedXRot); - newEntity.setDeltaMovement(oldMotion); - newEntity.setPortalCooldown(); - destination.addDuringTeleport(newEntity); - - teleportedEntity = newEntity; - - pEntity.remove(Entity.RemovalReason.CHANGED_DIMENSION); // equivalent to Entity#removeAfterChangingDimensions - - } + } else { //If not a player + teleportedEntity = teleportEntity(pEntity, destination, pX, pY, pZ, updatedYRot, updatedXRot); } if (teleportedEntity != null){ - // update set to keep track of entities teleported - teleportedEntities.add(pEntity); + // update teleported entities set to keep track of entities teleported. Check if the list already contains our entity because this will be modified by the TardisTeleportData too + if(!teleportedEntities.contains(pEntity)) + teleportedEntities.add(pEntity); ChunkPos chunkpos = new ChunkPos(BlockPos.containing(pX, pY, pZ)); - destination.getChunkSource().addRegionTicket(TicketType.POST_TELEPORT, chunkpos, 1, pEntity.getId()); + destination.getChunkSource().addRegionTicket(TicketType.POST_TELEPORT, chunkpos, 1, teleportedEntity.getId()); - //Handle Elytra flying + //Handle Elytra flying - Logic matches vanilla TeleportCommand if (!(teleportedEntity instanceof LivingEntity) || !((LivingEntity) teleportedEntity).isFallFlying()) { teleportedEntity.setDeltaMovement(teleportedEntity.getDeltaMovement().multiply(1.0D, 0.0D, 1.0D)); teleportedEntity.setOnGround(true); @@ -177,7 +102,7 @@ public static boolean performTeleport(Entity pEntity, Entity vehicle, ServerLeve } } - //Handle teleporting any entities that are riding this entity by teleporting them too + //Handle teleporting any entities that are riding this entity by teleporting them too - equivalent to Entity#teleportPassengers() but works for both same dimension and different dimension since we account for destination dimension if (passengers.size() != 0) { passengers.forEach(passenger -> performTeleport(passenger, teleportedEntity, destination, pX, pY, pZ, pYaw, pPitch, safeBlockCheck, teleportedEntities)); } @@ -192,6 +117,110 @@ public static boolean performTeleport(Entity pEntity, Entity vehicle, ServerLeve return false; } + public static boolean safetyCheck(Entity pEntity, ServerLevel destination, double pX, double pY, double pZ, float pYaw, float pPitch, boolean safeBlockCheck, Set teleportedEntities){ + int xRound = (int) pX; + int yRound = (int) pY; + int zRound = (int) pZ; + BlockPos blockpos = new BlockPos(xRound, yRound, zRound); + + if (teleportedEntities.size() != 0){ + if (teleportedEntities.contains(pEntity)){ //If we are calling this method by itself such as teleporting passengers, check if we have already teleported the entity + return false; + } + } + + if (pEntity.getType().is(TagKeys.TARDIS_TELEPORT_BLACKLIST)) //Stop teleporting if the entity being teleported is blacklisted + return false; + + if (safeBlockCheck) { + if (!canTeleportTo(blockpos, destination, pEntity)) { + return false; + } + } + + if (!Level.isInSpawnableBounds(blockpos)) { + return false; + } + + return true; + } + + private static ServerPlayer teleportPlayer(ServerPlayer serverPlayer, ServerLevel destination, double pX, double pY, double pZ, float updatedYRot, float updatedXRot){ + if (serverPlayer.isSleeping()) { + serverPlayer.stopSleepInBed(true, true); + } + + serverPlayer.setDeltaMovement(Vec3.ZERO); //set velocity to 0 because otherwise we will trigger the "player moved wrongly" hardcoded vanilla check which will result in the player not changing coordinates in the new dimension + + serverPlayer.connection.send(new ClientboundRespawnPacket(serverPlayer.createCommonSpawnInfo(destination), (byte)3)); + serverPlayer.connection.send(new ClientboundChangeDifficultyPacket(destination.getLevelData().getDifficulty(), destination.getLevelData().isDifficultyLocked())); + serverPlayer.teleportTo(destination, pX, pY, pZ, updatedYRot, updatedXRot); + + serverPlayer.setPortalCooldown(); //Prevent player from being teleport by nether portal in the destination dimension + serverPlayer.setYHeadRot(updatedYRot); + serverPlayer.setYBodyRot(updatedYRot); + + + //Handle player experience not getting received on client after interdimensional teleport + serverPlayer.connection.send(new ClientboundSetExperiencePacket(serverPlayer.experienceProgress, serverPlayer.totalExperience, serverPlayer.experienceLevel)); + serverPlayer.connection.send(new ClientboundPlayerAbilitiesPacket(serverPlayer.getAbilities()));//Keep abilities like creative mode flight height etc. + serverPlayer.connection.send(new ClientboundChangeDifficultyPacket(serverPlayer.level().getDifficulty(), serverPlayer.level().getLevelData().isDifficultyLocked())); + + return (ServerPlayer) destination.getPlayerByUUID(serverPlayer.getUUID()); + } + + private static Entity teleportEntity(Entity pEntity, ServerLevel destination, double pX, double pY, double pZ, float yRot, float xRot){ + //For non player entities, always create new instances if inter dimensional teleporting + float adjustedXRot = Mth.clamp(xRot, -90.0F, 90.0F); + Entity teleportedEntity; + + if (destination == pEntity.level()) { + teleportedEntity = teleportEntitySameDimension(pEntity, pX, pY, pZ, yRot, adjustedXRot); + } + else { + teleportedEntity = teleportEntityOtherDimension(pEntity, destination, pX, pY, pZ, yRot, adjustedXRot); + } + return teleportedEntity; + } + + private static Entity teleportEntitySameDimension(Entity pEntity, double pX, double pY, double pZ, float yRot, float xRot) { + pEntity.moveTo(pX, pY, pZ, yRot, xRot); + pEntity.setYHeadRot(yRot); + pEntity.setYBodyRot(yRot); + pEntity.setPortalCooldown(); + return pEntity; + } + + private static Entity teleportEntityOtherDimension(Entity pEntity, ServerLevel destination, double pX, double pY, double pZ, float yRot, float xRot) { + //Get most of this logic from Entity#changeDimension which is most suitable as it has most syncing logic. However, we want to exclude the use of PortalInfo as it plays the vanilla portal sounds + Entity newEntity = pEntity; + + newEntity = newEntity.getType().create(destination); + if (newEntity == null) { + return null; + } + + newEntity.restoreFrom(pEntity); + newEntity.moveTo(pX, pY, pZ, yRot, xRot); + newEntity.setYHeadRot(yRot); + newEntity.setPortalCooldown(); + + pEntity.remove(Entity.RemovalReason.CHANGED_DIMENSION); + destination.addDuringTeleport(newEntity); //DO NOT add the entity to the destination before removing them, else we will teleport them to the coordinates from the source world + return newEntity; + } + + public static boolean teleportIfCollided(ServerLevel serverLevel, BlockPos blockPos, Entity entity, AABB teleportAABB){ + AABB entityBoundingBox = TRTeleporter.getBoundingBoxWithMovement(entity); + double insideBlockExpansion = 1.0E-7D; //Hardcoded value replicates logic from Entity#checkInsideBlocks + AABB inflatedEntityBoundingBox = entityBoundingBox.inflate(insideBlockExpansion); + AABB inflatedTeleportBoundingBox = teleportAABB.inflate(insideBlockExpansion); + if (inflatedTeleportBoundingBox.intersects(inflatedEntityBoundingBox)){ + return true; + } + return false; + } + /** * Temporary fix until Mojang patches the bug that makes potion effect icons disappear when changing dimension. * To fix it ourselves, we remove the effect and re-add it to the entity. @@ -215,4 +244,18 @@ private static void reAddStatusEffectTempFix(LivingEntity livingEntity) { } } + public static AABB getBoundingBoxWithMovement(Entity entity) { + Vec3 backwardExpand = lastTickPosOf(entity).subtract(entity.position()); + Vec3 forwardExpand = entity.getDeltaMovement(); + AABB box = entity.getBoundingBox() + .expandTowards(forwardExpand.scale(1.2)) + .expandTowards(backwardExpand); + + return box; + } + + public static Vec3 lastTickPosOf(Entity entity) { + return new Vec3(entity.xo, entity.yo, entity.zo); + } + } \ No newline at end of file diff --git a/common/src/main/java/whocraft/tardis_refined/common/util/TardisHelper.java b/common/src/main/java/whocraft/tardis_refined/common/util/TardisHelper.java index cc4c45341..e2339f459 100644 --- a/common/src/main/java/whocraft/tardis_refined/common/util/TardisHelper.java +++ b/common/src/main/java/whocraft/tardis_refined/common/util/TardisHelper.java @@ -13,7 +13,6 @@ 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.chunk.ChunkAccess; import net.minecraft.world.level.material.Fluids; import net.minecraft.world.phys.Vec3; import whocraft.tardis_refined.api.event.TardisEvents;