diff --git a/src/main/java/ru/betterend/blocks/EndPortalBlock.java b/src/main/java/ru/betterend/blocks/EndPortalBlock.java index 9255f46f..69fcf6c7 100644 --- a/src/main/java/ru/betterend/blocks/EndPortalBlock.java +++ b/src/main/java/ru/betterend/blocks/EndPortalBlock.java @@ -73,8 +73,7 @@ public class EndPortalBlock extends NetherPortalBlock implements IRenderTypeable if (exitPos == null) return; if (entity instanceof ServerPlayerEntity) { ServerPlayerEntity player = (ServerPlayerEntity) entity; - teleportPlayer(player, destination, exitPos); - + this.teleportPlayer(player, destination, exitPos); } else { TeleportingEntity teleEntity = (TeleportingEntity) entity; teleEntity.beSetExitPos(exitPos); @@ -85,32 +84,14 @@ public class EndPortalBlock extends NetherPortalBlock implements IRenderTypeable } } } - - private void teleportPlayer(ServerPlayerEntity player, ServerWorld destination, BlockPos pos) { - ((TeleportingEntity) player).beSetExitPos(pos); + + private void teleportPlayer(ServerPlayerEntity player, ServerWorld destination, BlockPos exitPos) { if (player.isCreative()) { - player.teleport(destination, pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5, player.yaw, player.pitch); - } - else { - if (destination.getRegistryKey() == World.OVERWORLD) { - //player.teleport(destination, pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5, player.yaw, player.pitch); - //player.updatePositionAndAngles(pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5, player.yaw, player.pitch); - //player.moveToWorld(destination); - //player.teleport(pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5); - //player.updatePositionAndAngles(pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5, player.yaw, player.pitch); - //player.teleport(pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5); - - //player.teleport(pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5); - - // The most safe way - player.moveToWorld(destination); - - //player.teleport(pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5); - } - else { - player.moveToWorld(destination); - player.teleport(pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5); - } + player.teleport(destination, exitPos.getX() + 0.5, exitPos.getY(), exitPos.getZ() + 0.5, player.yaw, player.pitch); + } else { + TeleportingEntity teleEntity = (TeleportingEntity) player; + teleEntity.beSetExitPos(exitPos); + player.moveToWorld(destination); } player.resetNetherPortalCooldown(); } diff --git a/src/main/java/ru/betterend/interfaces/TeleportingEntity.java b/src/main/java/ru/betterend/interfaces/TeleportingEntity.java index 8e9caa0f..76cf8c24 100644 --- a/src/main/java/ru/betterend/interfaces/TeleportingEntity.java +++ b/src/main/java/ru/betterend/interfaces/TeleportingEntity.java @@ -4,6 +4,6 @@ import net.minecraft.util.math.BlockPos; public interface TeleportingEntity { void beSetExitPos(BlockPos pos); - + void beResetExitPos(); boolean beCanTeleport(); } diff --git a/src/main/java/ru/betterend/mixin/common/EntityMixin.java b/src/main/java/ru/betterend/mixin/common/EntityMixin.java index 466e34aa..de405742 100644 --- a/src/main/java/ru/betterend/mixin/common/EntityMixin.java +++ b/src/main/java/ru/betterend/mixin/common/EntityMixin.java @@ -18,8 +18,7 @@ import ru.betterend.interfaces.TeleportingEntity; @Mixin(Entity.class) public abstract class EntityMixin implements TeleportingEntity { - private BlockPos exitPos; - + @Shadow public float yaw; @Shadow @@ -41,10 +40,11 @@ public abstract class EntityMixin implements TeleportingEntity { @Shadow protected abstract TeleportTarget getTeleportTarget(ServerWorld destination); - + + private BlockPos exitPos; + @Inject(method = "moveToWorld", at = @At("HEAD"), cancellable = true) public void be_moveToWorld(ServerWorld destination, CallbackInfoReturnable info) { - Entity entity = (Entity) (Object) this; if (!removed && beCanTeleport() && world instanceof ServerWorld) { this.detach(); this.world.getProfiler().push("changeDimension"); @@ -52,7 +52,7 @@ public abstract class EntityMixin implements TeleportingEntity { TeleportTarget teleportTarget = this.getTeleportTarget(destination); if (teleportTarget != null) { this.world.getProfiler().swap("reloading"); - entity = this.getType().create(destination); + Entity entity = this.getType().create(destination); if (entity != null) { entity.copyFrom(Entity.class.cast(this)); entity.refreshPositionAndAngles(teleportTarget.position.x, teleportTarget.position.y, teleportTarget.position.z, teleportTarget.yaw, entity.pitch); @@ -64,9 +64,8 @@ public abstract class EntityMixin implements TeleportingEntity { ((ServerWorld) world).resetIdleTimeout(); destination.resetIdleTimeout(); this.world.getProfiler().pop(); - beResetTeleport(); + this.beResetExitPos(); info.setReturnValue(entity); - info.cancel(); } } } @@ -75,29 +74,21 @@ public abstract class EntityMixin implements TeleportingEntity { protected void be_getTeleportTarget(ServerWorld destination, CallbackInfoReturnable info) { if (beCanTeleport()) { info.setReturnValue(new TeleportTarget(new Vec3d(exitPos.getX() + 0.5, exitPos.getY(), exitPos.getZ() + 0.5), getVelocity(), yaw, pitch)); - beResetTeleport(); - info.cancel(); } } - - @Shadow - protected void setRotation(float yaw, float pitch) {} @Override public void beSetExitPos(BlockPos pos) { - exitPos = pos.toImmutable(); + this.exitPos = pos.toImmutable(); } - - public void beResetTeleport() { - exitPos = null; + + @Override + public void beResetExitPos() { + this.exitPos = null; } - + @Override public boolean beCanTeleport() { - return exitPos != null; + return this.exitPos != null; } - - public BlockPos beGetExit() { - return exitPos; - }; } diff --git a/src/main/java/ru/betterend/mixin/common/ServerPlayNetworkHandlerMixin.java b/src/main/java/ru/betterend/mixin/common/ServerPlayNetworkHandlerMixin.java index 1df58138..d0644012 100644 --- a/src/main/java/ru/betterend/mixin/common/ServerPlayNetworkHandlerMixin.java +++ b/src/main/java/ru/betterend/mixin/common/ServerPlayNetworkHandlerMixin.java @@ -1,13 +1,5 @@ package ru.betterend.mixin.common; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; -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 net.minecraft.block.BlockState; import net.minecraft.block.entity.BlockEntity; import net.minecraft.network.NetworkThreadUtils; @@ -18,6 +10,13 @@ import net.minecraft.server.world.ServerWorld; import net.minecraft.text.LiteralText; import net.minecraft.util.Formatting; import net.minecraft.util.math.BlockPos; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +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 ru.betterend.blocks.entities.ESignBlockEntity; @Mixin(ServerPlayNetworkHandler.class) @@ -30,7 +29,7 @@ public class ServerPlayNetworkHandlerMixin { @Inject(method = "onSignUpdate", at = @At(value = "HEAD"), cancellable = true) private void be_signUpdate(UpdateSignC2SPacket packet, CallbackInfo info) { - NetworkThreadUtils.forceMainThread(packet, (ServerPlayNetworkHandler) (Object) this, (ServerWorld) this.player.getServerWorld()); + NetworkThreadUtils.forceMainThread(packet, ServerPlayNetworkHandler.class.cast(this), player.getServerWorld()); this.player.updateLastActionTime(); ServerWorld serverWorld = this.player.getServerWorld(); BlockPos blockPos = packet.getPos(); diff --git a/src/main/java/ru/betterend/mixin/common/ServerPlayerEntityMixin.java b/src/main/java/ru/betterend/mixin/common/ServerPlayerEntityMixin.java index 0ee31988..ed57ad0a 100644 --- a/src/main/java/ru/betterend/mixin/common/ServerPlayerEntityMixin.java +++ b/src/main/java/ru/betterend/mixin/common/ServerPlayerEntityMixin.java @@ -1,6 +1,22 @@ package ru.betterend.mixin.common; +import com.mojang.authlib.GameProfile; +import net.minecraft.entity.Entity; +import net.minecraft.entity.effect.StatusEffectInstance; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.network.packet.s2c.play.*; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.PlayerManager; +import net.minecraft.server.network.ServerPlayNetworkHandler; +import net.minecraft.server.network.ServerPlayerInteractionManager; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.TeleportTarget; +import net.minecraft.world.World; +import net.minecraft.world.WorldProperties; +import net.minecraft.world.biome.source.BiomeAccess; +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; @@ -8,13 +24,115 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.server.world.ServerWorld; import net.minecraft.util.math.BlockPos; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; +import ru.betterend.interfaces.TeleportingEntity; @Mixin(ServerPlayerEntity.class) -public class ServerPlayerEntityMixin { +public abstract class ServerPlayerEntityMixin extends PlayerEntity implements TeleportingEntity { + + @Shadow + public ServerPlayNetworkHandler networkHandler; + @Final + @Shadow + public ServerPlayerInteractionManager interactionManager; + @Final + @Shadow + public MinecraftServer server; + @Shadow + private boolean inTeleportationState; + @Shadow + private float syncedHealth; + @Shadow + private int syncedFoodLevel; + @Shadow + private int syncedExperience; + + private BlockPos exitPos; + + public ServerPlayerEntityMixin(World world, BlockPos pos, float yaw, GameProfile profile) { + super(world, pos, yaw, profile); + } + @Inject(method = "createEndSpawnPlatform", at = @At("HEAD"), cancellable = true) private void be_createEndSpawnPlatform(ServerWorld world, BlockPos centerPos, CallbackInfo info) { - if (!centerPos.equals(world.getSpawnPos())) { + if (!centerPos.equals(world.getSpawnPos()) || beCanTeleport()) { info.cancel(); } } + + @Inject(method = "getTeleportTarget", at = @At("HEAD"), cancellable = true) + protected void be_getTeleportTarget(ServerWorld destination, CallbackInfoReturnable info) { + if (beCanTeleport()) { + info.setReturnValue(new TeleportTarget(new Vec3d(exitPos.getX() + 0.5, exitPos.getY(), exitPos.getZ() + 0.5), getVelocity(), yaw, pitch)); + } + } + + @Inject(method = "moveToWorld", at = @At("HEAD"), cancellable = true) + public void be_moveToWorld(ServerWorld destination, CallbackInfoReturnable info) { + if (beCanTeleport() && world instanceof ServerWorld) { + this.inTeleportationState = true; + ServerWorld serverWorld = this.getServerWorld(); + WorldProperties worldProperties = destination.getLevelProperties(); + ServerPlayerEntity player = ServerPlayerEntity.class.cast(this); + this.networkHandler.sendPacket(new PlayerRespawnS2CPacket(destination.getDimension(), destination.getRegistryKey(), BiomeAccess.hashSeed(destination.getSeed()), + interactionManager.getGameMode(),interactionManager.getPreviousGameMode(), destination.isDebugWorld(), destination.isFlat(), true)); + this.networkHandler.sendPacket(new DifficultyS2CPacket(worldProperties.getDifficulty(), worldProperties.isDifficultyLocked())); + PlayerManager playerManager = this.server.getPlayerManager(); + playerManager.sendCommandTree(player); + serverWorld.removePlayer(player); + this.removed = false; + TeleportTarget teleportTarget = this.getTeleportTarget(destination); + if (teleportTarget != null) { + serverWorld.getProfiler().push("moving"); + serverWorld.getProfiler().pop(); + serverWorld.getProfiler().push("placing"); + this.setWorld(destination); + destination.onPlayerChangeDimension(player); + this.setRotation(teleportTarget.yaw, teleportTarget.pitch); + this.refreshPositionAfterTeleport(teleportTarget.position.x, teleportTarget.position.y, teleportTarget.position.z); + serverWorld.getProfiler().pop(); + this.worldChanged(serverWorld); + this.interactionManager.setWorld(destination); + this.networkHandler.sendPacket(new PlayerAbilitiesS2CPacket(this.abilities)); + playerManager.sendWorldInfo(player, destination); + playerManager.sendPlayerStatus(player); + + for (StatusEffectInstance statusEffectInstance : this.getStatusEffects()) { + this.networkHandler.sendPacket(new EntityStatusEffectS2CPacket(getEntityId(), statusEffectInstance)); + } + + this.networkHandler.sendPacket(new WorldEventS2CPacket(1032, BlockPos.ORIGIN, 0, false)); + this.syncedExperience = -1; + this.syncedHealth = -1.0F; + this.syncedFoodLevel = -1; + } + this.beResetExitPos(); + info.setReturnValue(player); + } + } + + @Shadow + abstract ServerWorld getServerWorld(); + + @Shadow + abstract void worldChanged(ServerWorld origin); + + @Shadow + @Override + protected abstract TeleportTarget getTeleportTarget(ServerWorld destination); + + @Override + public void beSetExitPos(BlockPos pos) { + this.exitPos = pos.toImmutable(); + } + + @Override + public void beResetExitPos() { + this.exitPos = null; + } + + @Override + public boolean beCanTeleport() { + return this.exitPos != null; + } }