diff --git a/Azurite1.18/libs/1.18.jar b/Azurite1.18/libs/1.18.jar new file mode 100644 index 0000000..780ee31 Binary files /dev/null and b/Azurite1.18/libs/1.18.jar differ diff --git a/Azurite1.18/pom.xml b/Azurite1.18/pom.xml new file mode 100644 index 0000000..bd71b1d --- /dev/null +++ b/Azurite1.18/pom.xml @@ -0,0 +1,44 @@ + + + 4.0.0 + + me.keano.azurite + Azurite1.18 + 1.0 + + + 17 + 17 + UTF-8 + + + + + org.projectlombok + lombok + 1.18.24 + provided + + + org.spigotmc + spigot-1.18 + 1.18 + system + ${project.basedir}/libs/1.18.jar + + + com.google.guava + guava + 31.1-jre + compile + + + me.keano.azurite + Azurite + 1.0-SNAPSHOT + provided + + + \ No newline at end of file diff --git a/Azurite1.18/src/main/java/me/keano/azurite/modules/nametags/packet/type/NametagPacketV1_18_R2.java b/Azurite1.18/src/main/java/me/keano/azurite/modules/nametags/packet/type/NametagPacketV1_18_R2.java new file mode 100644 index 0000000..b6590ce --- /dev/null +++ b/Azurite1.18/src/main/java/me/keano/azurite/modules/nametags/packet/type/NametagPacketV1_18_R2.java @@ -0,0 +1,145 @@ +package me.keano.azurite.modules.nametags.packet.type; + +import lombok.SneakyThrows; +import me.keano.azurite.modules.nametags.NametagManager; +import me.keano.azurite.modules.nametags.extra.NameInfo; +import me.keano.azurite.modules.nametags.extra.NameVisibility; +import me.keano.azurite.modules.nametags.packet.NametagPacket; +import me.keano.azurite.utils.ReflectionUtils; +import net.minecraft.EnumChatFormat; +import net.minecraft.network.protocol.Packet; +import net.minecraft.network.protocol.game.PacketPlayOutScoreboardTeam; +import net.minecraft.world.scores.Scoreboard; +import net.minecraft.world.scores.ScoreboardTeam; +import net.minecraft.world.scores.ScoreboardTeamBase; +import org.bukkit.craftbukkit.v1_18_R2.entity.CraftPlayer; +import org.bukkit.craftbukkit.v1_18_R2.util.CraftChatMessage; +import org.bukkit.entity.Player; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.util.Arrays; +import java.util.Collections; +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Collectors; + +/** + * Copyright (c) 2023. Keano + * Use or redistribution of source or file is + * only permitted if given explicit permission. + */ +@SuppressWarnings("unused") +public class NametagPacketV1_18_R2 extends NametagPacket { + + private static final Field a = ReflectionUtils.accessField(PacketPlayOutScoreboardTeam.b.class, "a"); + private static final Field b = ReflectionUtils.accessField(PacketPlayOutScoreboardTeam.b.class, "b"); + private static final Field c = ReflectionUtils.accessField(PacketPlayOutScoreboardTeam.b.class, "c"); + private static final Field d = ReflectionUtils.accessField(PacketPlayOutScoreboardTeam.b.class, "d"); + private static final Field e = ReflectionUtils.accessField(PacketPlayOutScoreboardTeam.b.class, "e"); + private static final Field f = ReflectionUtils.accessField(PacketPlayOutScoreboardTeam.b.class, "f"); + private static final Field g = ReflectionUtils.accessField(PacketPlayOutScoreboardTeam.b.class, "g"); + private static final Constructor PACKET_SCORE_BOARD_CONSTRUCTOR = ReflectionUtils.accessConstructor(PacketPlayOutScoreboardTeam.class, 1); + private static final ScoreboardTeam EMPTY_TEAM = new ScoreboardTeam(new Scoreboard(), "empty"); + + private static final Map FORMATS = Arrays + .stream(EnumChatFormat.values()) + .collect(Collectors.toMap(EnumChatFormat::toString, e -> e)); + + private final Map teams; + private final Map teamsByPlayer; + + public NametagPacketV1_18_R2(NametagManager manager, Player player) { + super(manager, player); + this.teams = new ConcurrentHashMap<>(); + this.teamsByPlayer = new ConcurrentHashMap<>(); + } + + private void sendPacket(Packet packet) { // Packet type is unknown 1.8+ + ((CraftPlayer) player).getHandle().b.a(packet); + } + + @Override + public void addToTeam(Player player, String name) { + String currentTeam = teamsByPlayer.get(player.getName()); + NameInfo info = teams.get(name); + + if (currentTeam != null && currentTeam.equals(name)) return; + if (info == null) return; + + teamsByPlayer.put(player.getName(), name); + sendPacket(new ScoreboardPacket(info, 3, player).toPacket()); + } + + @Override + public void delete() { + for (NameInfo info : teams.values()) { + sendPacket(new ScoreboardPacket(info, 1).toPacket()); + } + + teams.clear(); + teamsByPlayer.clear(); + } + + @Override + public void create(String name, String color, String prefix, String suffix, boolean friendlyInvis, NameVisibility visibility) { + NameInfo current = teams.get(name); + + if (current != null) { + if (!current.getColor().equals(color) || !current.getPrefix().equals(prefix) || !current.getSuffix().equals(suffix)) { + NameInfo newInfo = new NameInfo(name, color, prefix, suffix, visibility, friendlyInvis); + teams.put(name, newInfo); + sendPacket(new ScoreboardPacket(newInfo, 2).toPacket()); + } + return; + } + + NameInfo info = new NameInfo(name, color, prefix, suffix, visibility, friendlyInvis); + teams.put(name, info); + sendPacket(new ScoreboardPacket(info, 0).toPacket()); + } + + private static class ScoreboardPacket { + + private final NameInfo info; + private final Player target; + private final int action; + + public ScoreboardPacket(NameInfo info, int action) { + this.info = info; + this.action = action; + this.target = null; + } + + public ScoreboardPacket(NameInfo info, int action, Player target) { + this.info = info; + this.action = action; + this.target = target; + } + + @SneakyThrows + public PacketPlayOutScoreboardTeam toPacket() { + PacketPlayOutScoreboardTeam.b subPacket = new PacketPlayOutScoreboardTeam.b(EMPTY_TEAM); + + a.set(subPacket, CraftChatMessage.fromString(info.getName())[0]); + b.set(subPacket, CraftChatMessage.fromString(info.getPrefix())[0]); + c.set(subPacket, CraftChatMessage.fromString(info.getSuffix())[0]); + d.set(subPacket, info.getVisibility().getName()); + e.set(subPacket, ScoreboardTeamBase.EnumTeamPush.b.e); + f.set(subPacket, getFormat(info.getColor())); + g.set(subPacket, info.isFriendlyInvis() ? 3 : 0); + + return (PacketPlayOutScoreboardTeam) PACKET_SCORE_BOARD_CONSTRUCTOR.newInstance( + info.getName(), action, + Optional.of(subPacket), + (target != null ? Collections.singleton(target.getName()) : Collections.emptySet()) + ); + } + + public EnumChatFormat getFormat(String string) { + EnumChatFormat format = FORMATS.get(string); + return format == null ? EnumChatFormat.v : format; + } + } +} \ No newline at end of file diff --git a/Azurite1.18/src/main/java/me/keano/azurite/modules/tablist/packet/type/TablistPacketV1_18_R2.java b/Azurite1.18/src/main/java/me/keano/azurite/modules/tablist/packet/type/TablistPacketV1_18_R2.java new file mode 100644 index 0000000..c7d0e05 --- /dev/null +++ b/Azurite1.18/src/main/java/me/keano/azurite/modules/tablist/packet/type/TablistPacketV1_18_R2.java @@ -0,0 +1,145 @@ +package me.keano.azurite.modules.tablist.packet.type; + +import com.google.common.collect.HashBasedTable; +import com.google.common.collect.Table; +import com.mojang.authlib.GameProfile; +import com.mojang.authlib.properties.Property; +import me.keano.azurite.modules.tablist.Tablist; +import me.keano.azurite.modules.tablist.TablistManager; +import me.keano.azurite.modules.tablist.extra.TablistEntry; +import me.keano.azurite.modules.tablist.extra.TablistSkin; +import me.keano.azurite.modules.tablist.packet.TablistPacket; +import me.keano.azurite.utils.Utils; +import net.minecraft.network.protocol.Packet; +import net.minecraft.network.protocol.game.PacketPlayOutPlayerInfo; +import net.minecraft.network.protocol.game.PacketPlayOutPlayerListHeaderFooter; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.EntityPlayer; +import net.minecraft.server.level.WorldServer; +import net.minecraft.server.network.PlayerConnection; +import org.bukkit.craftbukkit.v1_18_R2.entity.CraftPlayer; +import org.bukkit.craftbukkit.v1_18_R2.util.CraftChatMessage; +import org.bukkit.entity.Player; + +import java.util.UUID; + +/** + * Copyright (c) 2023. Keano + * Use or redistribution of source or file is + * only permitted if given explicit permission. + */ +@SuppressWarnings({"unused", "deprecation"}) +public class TablistPacketV1_18_R2 extends TablistPacket { + + // These can be used for all the players since we can use teams to modify how each player sees them. + private final Table fakePlayers; + private final int maxColumns; + + // Cache them to see if we don't have to send a packet again. + private String header; + private String footer; + + public TablistPacketV1_18_R2(TablistManager manager, Player player) { + super(manager, player); + + this.fakePlayers = HashBasedTable.create(); + this.header = ""; + this.footer = ""; + this.maxColumns = (Utils.getProtocolVersion(player) <= 5 ? 3 : 4); + + this.loadFakes(); + this.init(); + } + + @Override + public void update() { + this.sendHeaderFooter(); + + Tablist tablist = getManager().getAdapter().getInfo(player); + + for (int row = 0; row < 20; row++) { + for (int col = 0; col < maxColumns; col++) { + TablistEntry entry = tablist.getEntry(col, row); + TablistSkin newSkin = entry.getSkin(); + EntityPlayer fake = fakePlayers.get(col, row); + + if (fake == null) continue; + + if (fake.e != entry.getPing()) { + fake.e = entry.getPing(); + sendPacket(new PacketPlayOutPlayerInfo(PacketPlayOutPlayerInfo.EnumPlayerInfoAction.c, fake)); + } + + if (newSkin == null) { + newSkin = getManager().getDefaultSkins().get(col, row); + } + + updateSkin(fake, newSkin); + handleTeams(fake.getBukkitEntity(), entry.getText(), calcSlot(col, row)); + } + } + } + + private void updateSkin(EntityPlayer fake, TablistSkin skin) { + GameProfile profile = fake.fq(); + Property old = profile.getProperties().get("textures").stream().findFirst().orElse(null); + + // Verify if we should update + if (old != null && old.getValue().equals(skin.getValue()) && old.getSignature().equals(skin.getSignature())) { + return; + } + + profile.getProperties().clear(); + profile.getProperties().put("textures", new Property("textures", skin.getValue(), skin.getSignature())); + + sendPacket(new PacketPlayOutPlayerInfo(PacketPlayOutPlayerInfo.EnumPlayerInfoAction.b, fake)); + sendPacket(new PacketPlayOutPlayerInfo(PacketPlayOutPlayerInfo.EnumPlayerInfoAction.a, fake)); + } + + private void loadFakes() { + MinecraftServer server = MinecraftServer.getServer(); + WorldServer worldServer = server.F().iterator().next(); + + for (int row = 0; row < 20; row++) { + for (int col = 0; col < 4; col++) { + GameProfile profile = new GameProfile(UUID.randomUUID(), getName(col, row)); + EntityPlayer fake = new EntityPlayer(server, worldServer, profile); + TablistSkin skin = getManager().getDefaultSkins().get(col, row); + profile.getProperties().put("textures", new Property("textures", skin.getValue(), skin.getSignature())); + fakePlayers.put(col, row, fake); + } + } + } + + private void init() { + for (int row = 0; row < 20; row++) { + for (int col = 0; col < maxColumns; col++) { + EntityPlayer fake = fakePlayers.get(col, row); + sendPacket(new PacketPlayOutPlayerInfo(PacketPlayOutPlayerInfo.EnumPlayerInfoAction.a, fake)); + } + } + } + + private void sendPacket(Packet packet) { + PlayerConnection connection = ((CraftPlayer) player).getHandle().b; + connection.a(packet); + } + + private void sendHeaderFooter() { + String headerJoined = String.join("\n", getManager().getAdapter().getHeader(player)); + String footerJoined = String.join("\n", getManager().getAdapter().getFooter(player)); + + // Refrain sending a packet again if same. + if (footer.equals(headerJoined) && header.equals(headerJoined)) return; + + this.header = headerJoined; + this.footer = footerJoined; + + PacketPlayOutPlayerListHeaderFooter packet = new PacketPlayOutPlayerListHeaderFooter( + CraftChatMessage.fromJSONOrString(headerJoined, true), + CraftChatMessage.fromJSONOrString(footerJoined, true) + ); + + sendPacket(packet); + } +} \ No newline at end of file diff --git a/Azurite1.18/src/main/java/me/keano/azurite/modules/versions/type/Version1_18_R2.java b/Azurite1.18/src/main/java/me/keano/azurite/modules/versions/type/Version1_18_R2.java new file mode 100644 index 0000000..a7ced77 --- /dev/null +++ b/Azurite1.18/src/main/java/me/keano/azurite/modules/versions/type/Version1_18_R2.java @@ -0,0 +1,338 @@ +package me.keano.azurite.modules.versions.type; + +import com.google.common.io.ByteArrayDataOutput; +import com.google.common.io.ByteStreams; +import com.mojang.authlib.GameProfile; +import com.mojang.authlib.properties.Property; +import com.mojang.datafixers.util.Pair; +import io.netty.channel.ChannelDuplexHandler; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelPipeline; +import io.netty.channel.ChannelPromise; +import lombok.SneakyThrows; +import me.keano.azurite.modules.ability.AbilityManager; +import me.keano.azurite.modules.ability.type.InvisibilityAbility; +import me.keano.azurite.modules.framework.Config; +import me.keano.azurite.modules.framework.Module; +import me.keano.azurite.modules.loggers.Logger; +import me.keano.azurite.modules.nametags.Nametag; +import me.keano.azurite.modules.nametags.extra.NameVisibility; +import me.keano.azurite.modules.pvpclass.type.ghost.GhostClass; +import me.keano.azurite.modules.tablist.extra.TablistSkin; +import me.keano.azurite.modules.versions.Version; +import me.keano.azurite.modules.versions.VersionManager; +import me.keano.azurite.utils.ReflectionUtils; +import net.minecraft.core.BlockPosition; +import net.minecraft.network.protocol.game.ClientboundSetActionBarTextPacket; +import net.minecraft.network.protocol.game.PacketPlayOutEntityEquipment; +import net.minecraft.network.protocol.game.PacketPlayOutPlayerInfo; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.EntityPlayer; +import net.minecraft.server.level.PlayerChunkMap; +import net.minecraft.server.level.WorldServer; +import net.minecraft.server.network.ServerPlayerConnection; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EnumItemSlot; +import net.minecraft.world.level.block.entity.TileEntity; +import net.minecraft.world.level.block.state.IBlockData; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.Particle; +import org.bukkit.block.Block; +import org.bukkit.command.CommandMap; +import org.bukkit.craftbukkit.v1_18_R2.CraftServer; +import org.bukkit.craftbukkit.v1_18_R2.CraftWorld; +import org.bukkit.craftbukkit.v1_18_R2.entity.CraftPlayer; +import org.bukkit.craftbukkit.v1_18_R2.inventory.CraftItemStack; +import org.bukkit.craftbukkit.v1_18_R2.util.CraftChatMessage; +import org.bukkit.enchantments.Enchantment; +import org.bukkit.entity.Player; +import org.bukkit.event.entity.EntityPotionEffectEvent; +import org.bukkit.inventory.ItemFlag; +import org.bukkit.inventory.ItemStack; + +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.*; +import java.util.stream.Collectors; + +/** + * Copyright (c) 2023. Keano + * Use or redistribution of source or file is + * only permitted if given explicit permission. + */ +@SuppressWarnings("all") +public class Version1_18_R2 extends Module implements Version { + + private static final Field ENTITY_ID = ReflectionUtils.accessField(PacketPlayOutEntityEquipment.class, "b"); + private static final Field SLOT = ReflectionUtils.accessField(PacketPlayOutEntityEquipment.class, "c"); + private static final Field ACTION = ReflectionUtils.accessField(PacketPlayOutPlayerInfo.class, "a"); + private static final Field DATA = ReflectionUtils.accessField(PacketPlayOutPlayerInfo.class, "b"); + + private static final Method SPAWN_PARTICLE = ReflectionUtils.accessMethod( + CraftWorld.class, "spawnParticle", Particle.class, Location.class, int.class, Object.class + ); + + public Version1_18_R2(VersionManager manager) { + super(manager); + } + + @Override + public CommandMap getCommandMap() { + try { + + CraftServer server = (CraftServer) Bukkit.getServer(); + Method method = server.getClass().getMethod("getCommandMap"); + return (CommandMap) method.invoke(server); + + } catch (IllegalAccessException | NoSuchMethodException | InvocationTargetException e) { + e.printStackTrace(); + return null; + } + } + + @Override + @SneakyThrows + public Set getTrackedPlayers(Player player) { + EntityPlayer entityPlayer = ((CraftPlayer) player).getHandle(); + PlayerChunkMap.EntityTracker tracker = entityPlayer.tracker; + + if (tracker != null) { + Set players = new HashSet<>(); + + for (ServerPlayerConnection connection : tracker.f) { + players.add(connection.e().getBukkitEntity()); + } + + return players; + } + + return Collections.emptySet(); + } + + @Override + public boolean isNotGapple(ItemStack item) { + return item.getType() != Material.ENCHANTED_GOLDEN_APPLE; + } + + @Override + public int getPing(Player player) { + CraftPlayer craftPlayer = (CraftPlayer) player; + return craftPlayer.getHandle().e; + } + + @Override + public ItemStack getItemInHand(Player player) { + try { + + Method method = player.getInventory().getClass().getMethod("getItemInMainHand"); + return (ItemStack) method.invoke(player.getInventory()); + + } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) { + e.printStackTrace(); + return null; + } + } + + @Override + public ItemStack addGlow(ItemStack itemStack) { + itemStack.addUnsafeEnchantment(Enchantment.WATER_WORKER, 1); + itemStack.addItemFlags(ItemFlag.HIDE_ENCHANTS); + return itemStack; + } + + @Override + public void setItemInHand(Player player, ItemStack item) { + player.getInventory().setItemInMainHand(item); + } + + @Override + public void handleLoggerDeath(Logger logger) { + EntityPlayer player = ((CraftPlayer) logger.getPlayer()).getHandle(); + player.getBukkitEntity().getInventory().clear(); + player.getBukkitEntity().getInventory().setArmorContents(null); + player.getBukkitEntity().setHealth(0); + player.getBukkitEntity().setExp(0.0F); + player.removeAllEffects(EntityPotionEffectEvent.Cause.DEATH); + player.getBukkitEntity().saveData(); // Save the inventory and everything we just modified + } + + @Override + public void playEffect(Location location, String name, Object data) { + try { + + Particle particle = Particle.valueOf(name); + SPAWN_PARTICLE.invoke(location.getWorld(), particle, location, 1, data); + + } catch (IllegalArgumentException e) { + throw new IllegalArgumentException("Particle " + name + " does not exist."); + + } catch (InvocationTargetException | IllegalAccessException e) { + e.printStackTrace(); + } + } + + @Override + public String getTPSColored() { + double tps = MinecraftServer.getServer().recentTps[0]; + String color = (tps > 18 ? "§a" : tps > 16 ? "§e" : "§c"); + String asterisk = (tps > 20 ? "*" : ""); + return color + asterisk + Math.min(Math.round(tps * 100.0) / 100.0, 20.0); + } + + @Override + public void hideArmor(Player player) { + EntityPlayer entityPlayer = ((CraftPlayer) player).getHandle(); + PlayerChunkMap.EntityTracker tracker = entityPlayer.tracker; + + if (tracker != null) { + List> items = new ArrayList<>(); + + items.add(new Pair<>(EnumItemSlot.c, CraftItemStack.asNMSCopy(null))); + items.add(new Pair<>(EnumItemSlot.d, CraftItemStack.asNMSCopy(null))); + items.add(new Pair<>(EnumItemSlot.e, CraftItemStack.asNMSCopy(null))); + items.add(new Pair<>(EnumItemSlot.f, CraftItemStack.asNMSCopy(null))); + + tracker.a(new PacketPlayOutEntityEquipment(player.getEntityId(), items)); + } + } + + @Override + public void showArmor(Player player) { + EntityPlayer entityPlayer = ((CraftPlayer) player).getHandle(); + PlayerChunkMap.EntityTracker tracker = entityPlayer.tracker; + + if (tracker != null) { + org.bukkit.inventory.PlayerInventory inventory = player.getInventory(); + List> items = new ArrayList<>(); + + items.add(new Pair<>(EnumItemSlot.c, CraftItemStack.asNMSCopy(inventory.getBoots()))); + items.add(new Pair<>(EnumItemSlot.d, CraftItemStack.asNMSCopy(inventory.getLeggings()))); + items.add(new Pair<>(EnumItemSlot.e, CraftItemStack.asNMSCopy(inventory.getChestplate()))); + items.add(new Pair<>(EnumItemSlot.f, CraftItemStack.asNMSCopy(inventory.getHelmet()))); + + tracker.a(new PacketPlayOutEntityEquipment(player.getEntityId(), items)); + } + } + + @Override + public void handleNettyListener(Player player) { + EntityPlayer entityPlayer = ((CraftPlayer) player).getHandle(); + ChannelPipeline pipeline = entityPlayer.b.a.m.pipeline(); + AbilityManager abilityManager = getInstance().getAbilityManager(); + InvisibilityAbility ability = (InvisibilityAbility) abilityManager.getAbility("Invisibility"); + GhostClass ghostClass = getInstance().getClassManager().getGhostClass(); + + if (pipeline.get("packet_handler") == null) { + player.kickPlayer(Config.COULD_NOT_LOAD_DATA); + return; + } + + pipeline.addBefore("packet_handler", "Azurite", new ChannelDuplexHandler() { + @Override + public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception { + if (msg instanceof PacketPlayOutEntityEquipment packet) { + Entity entity = ((CraftWorld) player.getWorld()).getHandle().O.d().a((int) ENTITY_ID.get(packet)); + + if (entity != null) { + if (ghostClass != null && ghostClass.getInvisible().contains(entity.getBukkitEntity().getUniqueId())) { + List> slot = + (List>) SLOT.get(packet); + + Iterator> iterator = slot.iterator(); + + while (iterator.hasNext()) { + Pair pair = iterator.next(); + + if (pair.getFirst().a() == EnumItemSlot.Function.b) { + iterator.remove(); + } + } + } + + if (ability.getInvisible().contains(entity.getBukkitEntity().getUniqueId())) { + List> slot = + (List>) SLOT.get(packet); + + Iterator> iterator = slot.iterator(); + + while (iterator.hasNext()) { + Pair pair = iterator.next(); + + if (pair.getFirst().a() == EnumItemSlot.Function.b) { + iterator.remove(); + } + } + } + } + } else if (msg instanceof PacketPlayOutPlayerInfo) { + PacketPlayOutPlayerInfo packet = (PacketPlayOutPlayerInfo) msg; + PacketPlayOutPlayerInfo.EnumPlayerInfoAction action = (PacketPlayOutPlayerInfo.EnumPlayerInfoAction) ACTION.get(packet); + Nametag nametag = getInstance().getNametagManager().getNametags().get(player.getUniqueId()); + + if (action == PacketPlayOutPlayerInfo.EnumPlayerInfoAction.a && nametag != null) { + List data = (List) DATA.get(packet); + + for (PacketPlayOutPlayerInfo.PlayerInfoData info : data) { + Player targetPlayer = Bukkit.getPlayer(info.a().getId()); + + if (targetPlayer == null) continue; + + // Make tablist sort instantly + nametag.getPacket().create("tablist", "", "", "", false, NameVisibility.ALWAYS); + nametag.getPacket().addToTeam(targetPlayer, "tablist"); + } + } + } + + super.write(ctx, msg, promise); + } + }); + } + + @Override + public void sendActionBar(Player player, String string) { + ClientboundSetActionBarTextPacket packet = new ClientboundSetActionBarTextPacket(CraftChatMessage.fromJSONOrString(string, true)); + ((CraftPlayer) player).getHandle().b.a(packet); + } + + @Override + public void sendToServer(Player player, String server) { + ByteArrayDataOutput out = ByteStreams.newDataOutput(); + out.writeUTF("Connect"); + out.writeUTF(server); + player.sendPluginMessage(getInstance(), "BungeeCord", out.toByteArray()); + } + + @Override + public void clearArrows(Player player) { + ((CraftPlayer) player).getHandle().setArrowCount(0, false); + } + + @Override + public List getBlockDrops(Player pl, Block bl, ItemStack hand) { + EntityPlayer serverPlayer = ((CraftPlayer) pl).getHandle(); + WorldServer serverLevel = serverPlayer.s.getMinecraftWorld(); + BlockPosition blockPos = new BlockPosition(bl.getX(), bl.getY(), bl.getZ()); + IBlockData blockState = serverLevel.a_(blockPos); + TileEntity blockEntity = serverLevel.c_(blockPos); + + return net.minecraft.world.level.block.Block.a(blockState, serverLevel, blockPos, blockEntity, serverPlayer, serverPlayer.es()) + .stream().map(CraftItemStack::asBukkitCopy).collect(Collectors.toList()); + } + + @Override + public TablistSkin getSkinData(Player player) { + EntityPlayer entityPlayer = ((CraftPlayer) player).getHandle(); + GameProfile profile = entityPlayer.bc.cs; + + if (profile.getProperties().get("textures").size() == 0) { + return null; + } + + Property property = profile.getProperties().get("textures").iterator().next(); + return new TablistSkin(property.getValue(), property.getSignature()); + } +} \ No newline at end of file diff --git a/Azurite1.19/libs/1.19.jar b/Azurite1.19/libs/1.19.jar new file mode 100644 index 0000000..51afa18 Binary files /dev/null and b/Azurite1.19/libs/1.19.jar differ