diff --git a/Azurite1.19/pom.xml b/Azurite1.19/pom.xml new file mode 100644 index 0000000..03e36d1 --- /dev/null +++ b/Azurite1.19/pom.xml @@ -0,0 +1,44 @@ + + + 4.0.0 + + me.keano.azurite + Azurite1.19 + 1.0 + + + 17 + 17 + UTF-8 + + + + + org.projectlombok + lombok + 1.18.24 + provided + + + org.spigotmc + spigot-1.19 + 1.19 + system + ${project.basedir}/libs/1.19.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.19/src/main/java/me/keano/azurite/modules/nametags/packet/type/NametagPacketV1_19_R3.java b/Azurite1.19/src/main/java/me/keano/azurite/modules/nametags/packet/type/NametagPacketV1_19_R3.java new file mode 100644 index 0000000..79d1e67 --- /dev/null +++ b/Azurite1.19/src/main/java/me/keano/azurite/modules/nametags/packet/type/NametagPacketV1_19_R3.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_19_R3.entity.CraftPlayer; +import org.bukkit.craftbukkit.v1_19_R3.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_19_R3 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, 0); + 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_19_R3(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.19/src/main/java/me/keano/azurite/modules/tablist/packet/type/TablistPacketV1_19_R3.java b/Azurite1.19/src/main/java/me/keano/azurite/modules/tablist/packet/type/TablistPacketV1_19_R3.java new file mode 100644 index 0000000..cae45f6 --- /dev/null +++ b/Azurite1.19/src/main/java/me/keano/azurite/modules/tablist/packet/type/TablistPacketV1_19_R3.java @@ -0,0 +1,151 @@ +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.ClientboundPlayerInfoRemovePacket; +import net.minecraft.network.protocol.game.ClientboundPlayerInfoUpdatePacket; +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_19_R3.entity.CraftPlayer; +import org.bukkit.craftbukkit.v1_19_R3.util.CraftChatMessage; +import org.bukkit.entity.Player; + +import java.util.Collections; +import java.util.UUID; + +/** + * Copyright (c) 2023. Keano + * Use or redistribution of source or file is + * only permitted if given explicit permission. + */ +@SuppressWarnings("unused") +public class TablistPacketV1_19_R3 extends TablistPacket { + + 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_19_R3(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 ClientboundPlayerInfoUpdatePacket(ClientboundPlayerInfoUpdatePacket.a.e, 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.fI(); + 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 ClientboundPlayerInfoRemovePacket(Collections.singletonList(profile.getId()))); + sendPacket(new ClientboundPlayerInfoUpdatePacket(ClientboundPlayerInfoUpdatePacket.a.a, fake)); + sendPacket(new ClientboundPlayerInfoUpdatePacket(ClientboundPlayerInfoUpdatePacket.a.d, fake)); + sendPacket(new ClientboundPlayerInfoUpdatePacket(ClientboundPlayerInfoUpdatePacket.a.e, 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); + if (fake == null) continue; + // Some reason u have to send an add_packet and then following it with update display name. + sendPacket(new ClientboundPlayerInfoUpdatePacket(ClientboundPlayerInfoUpdatePacket.a.a, fake)); + sendPacket(new ClientboundPlayerInfoUpdatePacket(ClientboundPlayerInfoUpdatePacket.a.d, 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.19/src/main/java/me/keano/azurite/modules/versions/type/Version1_19_R3.java b/Azurite1.19/src/main/java/me/keano/azurite/modules/versions/type/Version1_19_R3.java new file mode 100644 index 0000000..654e289 --- /dev/null +++ b/Azurite1.19/src/main/java/me/keano/azurite/modules/versions/type/Version1_19_R3.java @@ -0,0 +1,367 @@ +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.ClientboundPlayerInfoUpdatePacket; +import net.minecraft.network.protocol.game.ClientboundSetActionBarTextPacket; +import net.minecraft.network.protocol.game.PacketPlayOutEntityEquipment; +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_19_R3.CraftServer; +import org.bukkit.craftbukkit.v1_19_R3.CraftWorld; +import org.bukkit.craftbukkit.v1_19_R3.entity.CraftPlayer; +import org.bukkit.craftbukkit.v1_19_R3.inventory.CraftItemStack; +import org.bukkit.craftbukkit.v1_19_R3.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 org.bukkit.inventory.meta.ItemMeta; + +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_19_R3 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(ClientboundPlayerInfoUpdatePacket.class, "a"); + private static final Field DATA = ReflectionUtils.accessField(ClientboundPlayerInfoUpdatePacket.class, "b"); + private static final Field ENTITY_LOOKUP = ReflectionUtils.accessField(WorldServer.class, "entityLookup"); + + private static final Method ENTITY_GET = ReflectionUtils.accessMethod( + ReflectionUtils.getClass("io.papermc.paper.chunk.system.entity.EntityLookup"), "get", int.class); + + private static final Method SPAWN_PARTICLE = ReflectionUtils.accessMethod( + CraftWorld.class, "spawnParticle", Particle.class, Location.class, int.class, Object.class + ); + + public Version1_19_R3(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.f().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); + ItemMeta meta = itemStack.getItemMeta(); + meta.addItemFlags(ItemFlag.HIDE_ENCHANTS); + itemStack.setItemMeta(meta); + return itemStack; + } + + @Override + public void setItemInHand(Player player, ItemStack item) { + try { + + Method method = player.getInventory().getClass().getMethod("setItemInMainHand", ItemStack.class); + method.invoke(player.getInventory(), item); + + } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) { + e.printStackTrace(); + } + } + + @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.h.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) { + WorldServer server = ((CraftWorld) player.getWorld()).getHandle(); + Entity entity = (Entity) ENTITY_GET.invoke(ENTITY_LOOKUP.get(server), (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().e()) { + iterator.remove(); + } + } + + SLOT.set(packet, slot); // update it in packet + + if (slot.isEmpty()) { + return; // Don't send the packet. + } + } + + 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().e()) { + iterator.remove(); + } + } + + SLOT.set(packet, slot); // update it in packet + + if (slot.isEmpty()) { + return; // Don't send the packet. + } + } + } + } else if (msg instanceof ClientboundPlayerInfoUpdatePacket) { + ClientboundPlayerInfoUpdatePacket packet = (ClientboundPlayerInfoUpdatePacket) msg; + EnumSet actions = (EnumSet) ACTION.get(packet); + Nametag nametag = getInstance().getNametagManager().getNametags().get(player.getUniqueId()); + + for (ClientboundPlayerInfoUpdatePacket.a action : actions) { + if (action == ClientboundPlayerInfoUpdatePacket.a.a && nametag != null) { + List data = (List) DATA.get(packet); + + for (ClientboundPlayerInfoUpdatePacket.b info : data) { + Player targetPlayer = Bukkit.getPlayer(info.a()); + + 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.cG().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.fJ().f()) + .stream().map(CraftItemStack::asBukkitCopy).collect(Collectors.toList()); + } + + @Override + public TablistSkin getSkinData(Player player) { + EntityPlayer entityPlayer = ((CraftPlayer) player).getHandle(); + GameProfile profile = entityPlayer.fI(); + + 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.20/libs/1.20.jar b/Azurite1.20/libs/1.20.jar new file mode 100644 index 0000000..e79a4f6 Binary files /dev/null and b/Azurite1.20/libs/1.20.jar differ diff --git a/Azurite1.20/pom.xml b/Azurite1.20/pom.xml new file mode 100644 index 0000000..a804fdf --- /dev/null +++ b/Azurite1.20/pom.xml @@ -0,0 +1,44 @@ + + + 4.0.0 + + me.keano.azurite + Azurite1.20 + 1.0 + + + 17 + 17 + UTF-8 + + + + + org.projectlombok + lombok + 1.18.24 + provided + + + org.spigotmc + spigot-1.20 + 1.20 + system + ${project.basedir}/libs/1.20.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.20/src/main/java/me/keano/azurite/modules/nametags/packet/type/NametagPacketV1_20_R1.java b/Azurite1.20/src/main/java/me/keano/azurite/modules/nametags/packet/type/NametagPacketV1_20_R1.java new file mode 100644 index 0000000..76ec409 --- /dev/null +++ b/Azurite1.20/src/main/java/me/keano/azurite/modules/nametags/packet/type/NametagPacketV1_20_R1.java @@ -0,0 +1,155 @@ +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_20_R1.entity.CraftPlayer; +import org.bukkit.craftbukkit.v1_20_R1.util.CraftChatMessage; +import org.bukkit.entity.Player; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.util.*; +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_20_R1 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 ScoreboardTeam EMPTY_TEAM = new ScoreboardTeam(new Scoreboard(), "empty"); + private static final Constructor PACKET_SCORE_BOARD_CONSTRUCTOR; + + private static final Map FORMATS = Arrays + .stream(EnumChatFormat.values()) + .collect(Collectors.toMap(EnumChatFormat::toString, e -> e)); + + private final Map teams; + private final Map teamsByPlayer; + + static { + try { + + PACKET_SCORE_BOARD_CONSTRUCTOR = PacketPlayOutScoreboardTeam.class.getDeclaredConstructor( + String.class, int.class, Optional.class, Collection.class + ); + PACKET_SCORE_BOARD_CONSTRUCTOR.setAccessible(true); + + } catch (NoSuchMethodException ex) { + throw new RuntimeException(ex); + } + } + + public NametagPacketV1_20_R1(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().c.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.20/src/main/java/me/keano/azurite/modules/tablist/packet/type/TablistPacketV1_20_R1.java b/Azurite1.20/src/main/java/me/keano/azurite/modules/tablist/packet/type/TablistPacketV1_20_R1.java new file mode 100644 index 0000000..76be43b --- /dev/null +++ b/Azurite1.20/src/main/java/me/keano/azurite/modules/tablist/packet/type/TablistPacketV1_20_R1.java @@ -0,0 +1,150 @@ +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.ClientboundPlayerInfoRemovePacket; +import net.minecraft.network.protocol.game.ClientboundPlayerInfoUpdatePacket; +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_20_R1.entity.CraftPlayer; +import org.bukkit.craftbukkit.v1_20_R1.util.CraftChatMessage; +import org.bukkit.entity.Player; + +import java.util.Collections; +import java.util.UUID; + +/** + * Copyright (c) 2023. Keano + * Use or redistribution of source or file is + * only permitted if given explicit permission. + */ +@SuppressWarnings("unused") +public class TablistPacketV1_20_R1 extends TablistPacket { + + 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_20_R1(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.f != entry.getPing()) { + fake.f = entry.getPing(); + sendPacket(new ClientboundPlayerInfoUpdatePacket(ClientboundPlayerInfoUpdatePacket.a.e, 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.fM(); + 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 ClientboundPlayerInfoRemovePacket(Collections.singletonList(profile.getId()))); + sendPacket(new ClientboundPlayerInfoUpdatePacket(ClientboundPlayerInfoUpdatePacket.a.a, fake)); + sendPacket(new ClientboundPlayerInfoUpdatePacket(ClientboundPlayerInfoUpdatePacket.a.d, 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); + if (fake == null) continue; + // Some reason u have to send an add_packet and then following it with update display name. + sendPacket(new ClientboundPlayerInfoUpdatePacket(ClientboundPlayerInfoUpdatePacket.a.a, fake)); + sendPacket(new ClientboundPlayerInfoUpdatePacket(ClientboundPlayerInfoUpdatePacket.a.d, fake)); + } + } + } + + private void sendPacket(Packet packet) { + PlayerConnection connection = ((CraftPlayer) player).getHandle().c; + 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.20/src/main/java/me/keano/azurite/modules/versions/type/Version1_20_R1.java b/Azurite1.20/src/main/java/me/keano/azurite/modules/versions/type/Version1_20_R1.java new file mode 100644 index 0000000..fb8bc91 --- /dev/null +++ b/Azurite1.20/src/main/java/me/keano/azurite/modules/versions/type/Version1_20_R1.java @@ -0,0 +1,362 @@ +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.NetworkManager; +import net.minecraft.network.protocol.game.ClientboundPlayerInfoUpdatePacket; +import net.minecraft.network.protocol.game.ClientboundSetActionBarTextPacket; +import net.minecraft.network.protocol.game.PacketPlayOutEntityEquipment; +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.PlayerConnection; +import net.minecraft.server.network.ServerPlayerConnection; +import net.minecraft.world.EnumHand; +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_20_R1.CraftServer; +import org.bukkit.craftbukkit.v1_20_R1.CraftWorld; +import org.bukkit.craftbukkit.v1_20_R1.entity.CraftPlayer; +import org.bukkit.craftbukkit.v1_20_R1.inventory.CraftItemStack; +import org.bukkit.craftbukkit.v1_20_R1.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 org.bukkit.inventory.meta.ItemMeta; + +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_20_R1 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(ClientboundPlayerInfoUpdatePacket.class, "a"); + private static final Field DATA = ReflectionUtils.accessField(ClientboundPlayerInfoUpdatePacket.class, "b"); + private static final Field NETWORK_MANAGER = ReflectionUtils.accessField(PlayerConnection.class, "h"); + private static final Field ENTITY_LOOKUP = ReflectionUtils.accessField(WorldServer.class, "entityLookup"); + + private static final Method ENTITY_GET = ReflectionUtils.accessMethod( + ReflectionUtils.getClass("io.papermc.paper.chunk.system.entity.EntityLookup"), "get", int.class); + + private static final Method SPAWN_PARTICLE = ReflectionUtils.accessMethod( + CraftWorld.class, "spawnParticle", Particle.class, Location.class, int.class, Object.class + ); + + public Version1_20_R1(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 + public Set getTrackedPlayers(Player player) { + EntityPlayer entityPlayer = ((CraftPlayer) player).getHandle(); + PlayerChunkMap.EntityTracker tracker = ((WorldServer) entityPlayer.dI()).k().a.K.get(player.getEntityId()); + + if (tracker != null) { + Set players = new HashSet<>(); + + for (ServerPlayerConnection connection : tracker.f) { + players.add(connection.f().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().f; + } + + @Override + public ItemStack getItemInHand(Player player) { + return player.getInventory().getItemInMainHand(); + } + + @Override + public ItemStack addGlow(ItemStack itemStack) { + itemStack.addUnsafeEnchantment(Enchantment.WATER_WORKER, 1); + ItemMeta meta = itemStack.getItemMeta(); + meta.addItemFlags(ItemFlag.HIDE_ENCHANTS); + itemStack.setItemMeta(meta); + return itemStack; + } + + @Override + public void setItemInHand(Player player, ItemStack item) { + try { + + Method method = player.getInventory().getClass().getMethod("setItemInMainHand", ItemStack.class); + method.invoke(player.getInventory(), item); + + } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) { + e.printStackTrace(); + } + } + + @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 = ((WorldServer) entityPlayer.dI()).k().a.K.get(player.getEntityId()); + + 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 = ((WorldServer) entityPlayer.dI()).k().a.K.get(player.getEntityId()); + + 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 + @SneakyThrows + public void handleNettyListener(Player player) { + EntityPlayer entityPlayer = ((CraftPlayer) player).getHandle(); + ChannelPipeline pipeline = ((NetworkManager) NETWORK_MANAGER.get(entityPlayer.c)).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) { + WorldServer server = ((CraftWorld) player.getWorld()).getHandle(); + Entity entity = (Entity) ENTITY_GET.invoke(ENTITY_LOOKUP.get(server), (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(); + } + } + + SLOT.set(packet, slot); // update it in packet + + if (slot.isEmpty()) { + return; // Don't send the packet. + } + } + + 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(); + } + } + + SLOT.set(packet, slot); // update it in packet + + if (slot.isEmpty()) { + return; // Don't send the packet. + } + } + } + } else if (msg instanceof ClientboundPlayerInfoUpdatePacket) { + ClientboundPlayerInfoUpdatePacket packet = (ClientboundPlayerInfoUpdatePacket) msg; + EnumSet actions = (EnumSet) ACTION.get(packet); + Nametag nametag = getInstance().getNametagManager().getNametags().get(player.getUniqueId()); + + for (ClientboundPlayerInfoUpdatePacket.a action : actions) { + if (action == ClientboundPlayerInfoUpdatePacket.a.a && nametag != null) { + List data = (List) DATA.get(packet); + + for (ClientboundPlayerInfoUpdatePacket.b info : data) { + Player targetPlayer = Bukkit.getPlayer(info.a()); + + 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().c.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.x().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.b(EnumHand.a)) + .stream().map(CraftItemStack::asBukkitCopy).collect(Collectors.toList()); + } + + @Override + public TablistSkin getSkinData(Player player) { + EntityPlayer entityPlayer = ((CraftPlayer) player).getHandle(); + GameProfile profile = entityPlayer.fM(); + + 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/how-to.txt b/how-to.txt new file mode 100644 index 0000000..a7bf2df --- /dev/null +++ b/how-to.txt @@ -0,0 +1,156 @@ +Commands: +- azurite.resetreclaim +- azurite.reload +- azurite.ecomanage +- azurite.livesmanage +- azurite.setend +- azurite.strengthnerf +- azurite.broadcast +- azurite.clearchat +- azurite.clear +- azurite.craft +- azurite.feed +- azurite.gamemode +- azurite.gmc +- azurite.gms +- azurite.heal +- azurite.kill +- azurite.rename +- azurite.repair +- azurite.top +- azurite.tpall +- azurite.teleport +- azurite.teleporthere +- azurite.tploc +- azurite.tprandom +- azurite.world +- azurite.abilities +- azurite.ability +- azurite.deathban +- azurite.spawner +- azurite.freeze +- azurite.staffbuild +- azurite.staff +- azurite.crowbar +- azurite.purge +- azurite.resetredeem +- azurite.managefalltraptoken +- azurite.managebasetoken +- azurite.vanish +- azurite.timer +- azurite.keyall + +- azurite.eotw +- azurite.customtimer +- azurite.sotw.admin +- azurite.spawn.admin +- azurite.pvptimer.admin +- azurite.spawner.bypass + +Team Commands: +- azurite.team.teleport +- azurite.team.setregen +- azurite.team.setpoints +- azurite.team.setleader +- azurite.team.setdtr +- azurite.team.setcaps +- azurite.team.setbal +- azurite.systeam +- azurite.mountain +- azurite.citadel + +Miscellaneous: +- azurite.deathban.bypass +- azurite.eotw.bypass +- azurite.claim.nomoney +- azurite.claim.bypass +- azurite.freeze.bypass +- azurite.customsigns +- azurite.donor +- azurite.autosmelt +- azurite.chat.bypass +- azurite.repair.all +- azurite.abilitymenu.click +- azurite.citadel.entry +- azurite.event.entry +- azurite.potionlimit.bypass + +How to claim spawn: +- /st create SAFEZONE +- /st claim +- /st sethq (shows in /f info) + +How to claim koths +- /koth create +- Color has to be color coded, &9, &5, etc. +- /koth claimzone +- /st create EVENT +- /st claim +- /st sethq (shows in /f info) + +How to claim glowstone +- /st create GLOWSTONE +- /st claim +- /st sethq (shows in /f info and waypoint) +- After all the glowstone is placed, run /mountain reload to save the glowstone blocks +- Give it some time to store all the blocks, after a few seconds break a glowstone and type /mountain respawn to see if it works. + +How to claim ore mountain +- /st create ORE_MOUNTAIN +- /st claim +- /st sethq (shows in /f info and waypoint) +- After all the chests and valuables are placed, run /mountain reload to save the chests and blocks +- Give it some time to store all the blocks, after a few seconds break an ore and type /mountain respawn to see if it works. +- Check the chests and some loot should have spawned. + +How to setup deathban arena +- /deathban setarenaspawn (Where the player spawns when they die) +- /kit edit deathban (Edit to your liking, kit is created already) +- Create your kit sign where you would like with the kit name as "Deathban" +- Create a sign with [lives] on the first line to create the lives sign (click to revive) +- Create a sign with [deathlocsign] on the first line to create the death location info sign. +- Create a sign with [killedbysign] on the first line to create the killed by info sign. + +How to setup a keyall +- Run /keyall create