package carpet.patches; import carpet.CarpetSettings; import com.mojang.authlib.GameProfile; import net.minecraft.block.entity.SkullBlockEntity; import net.minecraft.entity.Entity; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.item.ItemStack; import net.minecraft.network.packet.s2c.play.EntityPositionS2CPacket; import net.minecraft.network.packet.s2c.play.EntitySetHeadYawS2CPacket; import net.minecraft.network.packet.s2c.play.PlayerListS2CPacket; import net.minecraft.entity.damage.DamageSource; import net.minecraft.entity.player.HungerManager; import net.minecraft.network.NetworkSide; import net.minecraft.text.Text; import net.minecraft.text.TranslatableText; import net.minecraft.server.MinecraftServer; import net.minecraft.server.ServerTask; import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.server.world.ServerWorld; import net.minecraft.util.UserCache; import net.minecraft.util.registry.RegistryKey; import net.minecraft.world.GameMode; import net.minecraft.world.World; import carpet.fakes.ServerPlayerEntityInterface; import carpet.utils.Messenger; import java.util.concurrent.atomic.AtomicReference; @SuppressWarnings("EntityConstructor") public class EntityPlayerMPFake extends ServerPlayerEntity { public Runnable fixStartingPosition = () -> {}; public boolean isAShadow; public static EntityPlayerMPFake createFake(String username, MinecraftServer server, double d0, double d1, double d2, double yaw, double pitch, RegistryKey dimensionId, GameMode gamemode, boolean flying) { //prolly half of that crap is not necessary, but it works ServerWorld worldIn = server.getWorld(dimensionId); UserCache.setUseRemote(false); GameProfile gameprofile; try { gameprofile = server.getUserCache().findByName(username).orElse(null); //findByName .orElse(null) } finally { UserCache.setUseRemote(server.isDedicated() && server.isOnlineMode()); } if (gameprofile == null) { if (!CarpetSettings.allowSpawningOfflinePlayers) { return null; } else { gameprofile = new GameProfile(PlayerEntity.getOfflinePlayerUuid(username), username); } } if (gameprofile.getProperties().containsKey("textures")) { AtomicReference result = new AtomicReference<>(); SkullBlockEntity.loadProperties(gameprofile, result::set); gameprofile = result.get(); } EntityPlayerMPFake instance = new EntityPlayerMPFake(server, worldIn, gameprofile, false); instance.fixStartingPosition = () -> instance.refreshPositionAndAngles(d0, d1, d2, (float) yaw, (float) pitch); server.getPlayerManager().onPlayerConnect(new NetworkManagerFake(NetworkSide.SERVERBOUND), instance); instance.teleport(worldIn, d0, d1, d2, (float)yaw, (float)pitch); instance.setHealth(20.0F); instance.unsetRemoved(); instance.stepHeight = 0.6F; instance.interactionManager.changeGameMode(gamemode); server.getPlayerManager().sendToDimension(new EntitySetHeadYawS2CPacket(instance, (byte) (instance.headYaw * 256 / 360)), dimensionId);//instance.dimension); server.getPlayerManager().sendToDimension(new EntityPositionS2CPacket(instance), dimensionId);//instance.dimension); //instance.world.getChunkManager(). updatePosition(instance); instance.dataTracker.set(PLAYER_MODEL_PARTS, (byte) 0x7f); // show all model layers (incl. capes) instance.getAbilities().flying = flying; return instance; } public static EntityPlayerMPFake createShadow(MinecraftServer server, ServerPlayerEntity player) { player.getServer().getPlayerManager().remove(player); player.networkHandler.disconnect(new TranslatableText("multiplayer.disconnect.duplicate_login")); ServerWorld worldIn = player.getWorld();//.getWorld(player.dimension); GameProfile gameprofile = player.getGameProfile(); EntityPlayerMPFake playerShadow = new EntityPlayerMPFake(server, worldIn, gameprofile, true); server.getPlayerManager().onPlayerConnect(new NetworkManagerFake(NetworkSide.SERVERBOUND), playerShadow); playerShadow.setHealth(player.getHealth()); playerShadow.networkHandler.requestTeleport(player.getX(), player.getY(), player.getZ(), player.getYaw(), player.getPitch()); playerShadow.interactionManager.changeGameMode(player.interactionManager.getGameMode()); ((ServerPlayerEntityInterface) playerShadow).getActionPack().copyFrom(((ServerPlayerEntityInterface) player).getActionPack()); playerShadow.stepHeight = 0.6F; playerShadow.dataTracker.set(PLAYER_MODEL_PARTS, player.getDataTracker().get(PLAYER_MODEL_PARTS)); server.getPlayerManager().sendToDimension(new EntitySetHeadYawS2CPacket(playerShadow, (byte) (player.headYaw * 256 / 360)), playerShadow.world.getRegistryKey()); server.getPlayerManager().sendToAll(new PlayerListS2CPacket(PlayerListS2CPacket.Action.ADD_PLAYER, playerShadow)); //player.world.getChunkManager().updatePosition(playerShadow); playerShadow.getAbilities().flying = player.getAbilities().flying; return playerShadow; } private EntityPlayerMPFake(MinecraftServer server, ServerWorld worldIn, GameProfile profile, boolean shadow) { super(server, worldIn, profile); isAShadow = shadow; } @Override protected void onEquipStack(ItemStack stack) { if (!isUsingItem()) super.onEquipStack(stack); } @Override public void kill() { kill(Messenger.s("Killed")); } public void kill(Text reason) { shakeOff(); this.server.send(new ServerTask(this.server.getTicks(), () -> { this.networkHandler.onDisconnected(reason); })); } @Override public void tick() { if (this.getServer().getTicks() % 10 == 0) { this.networkHandler.syncWithPlayerPosition(); //this.world.getChunkManager().updatePosition(this); onTeleportationDone(); //<- causes hard crash but would need to be done to enable portals // not as of 1.17 } try { super.tick(); this.playerTick(); } catch (NullPointerException ignored) { // happens with that paper port thingy - not sure what that would fix, but hey // the game not gonna crash violently. } } private void shakeOff() { if (getVehicle() instanceof PlayerEntity) stopRiding(); for (Entity passenger : getPassengersDeep()) { if (passenger instanceof PlayerEntity) passenger.stopRiding(); } } @Override public void onDeath(DamageSource cause) { shakeOff(); super.onDeath(cause); setHealth(20); this.hungerManager = new HungerManager(); kill(this.getDamageTracker().getDeathMessage()); } @Override public String getIp() { return "127.0.0.1"; } }