diff --git a/API/src/main/java/net/seyarada/pandeloot/nms/NMSManager.java b/API/src/main/java/net/seyarada/pandeloot/nms/NMSManager.java index 14a93bc..edc23fc 100644 --- a/API/src/main/java/net/seyarada/pandeloot/nms/NMSManager.java +++ b/API/src/main/java/net/seyarada/pandeloot/nms/NMSManager.java @@ -1,7 +1,6 @@ package net.seyarada.pandeloot.nms; import org.bukkit.Bukkit; -import org.bukkit.ChatColor; import java.util.List; import java.util.Map; @@ -19,13 +18,9 @@ public final class NMSManager { static NMSMethods nms; static { - String packageName = Bukkit.getServer().getClass().getPackage().getName(); - // Get full package string of CraftServer. - // org.bukkit.craftbukkit.version - String version = packageName.substring(packageName.lastIndexOf('.') + 1); - // Get the last element of the package - try { + String version = getNMSVersion(); + final Class clazz = Class.forName("net.seyarada.pandeloot.nms." + version + "." + version.toUpperCase()); // Check if we have a NMSHandler class at that location. if (NMSMethods.class.isAssignableFrom(clazz)) { // Make sure it actually implements NMS @@ -38,6 +33,24 @@ public final class NMSManager { } } + public static String getNMSVersion() { + String mcVersion = Bukkit.getBukkitVersion().substring(0, Bukkit.getBukkitVersion().indexOf('-')); + return switch (mcVersion){ // blame paper + case "1.17.1" -> "v1_17_R1"; + case "1.18", "1.18.1" -> "v1_18_R1"; + case "1.18.2" -> "v1_18_R2"; + case "1.19", "1.19.1", "1.19.2" -> "v1_19_R1"; + case "1.19.3" -> "v1_19_R2"; + case "1.19.4" -> "v1_19_R3"; + case "1.20", "1.20.1" -> "v1_20_R1"; + case "1.20.2" -> "v1_20_R2"; + case "1.20.3", "1.20.4" -> "v1_20_R3"; + case "1.21", "1.21.1" -> "v1_21_R1"; + + default -> throw new RuntimeException("Unknown NMS version for MC " + mcVersion); + }; + } + public static void addHiddenItem(int id, List players) { hiddenItems.put(id, players); diff --git a/Plugin/pom.xml b/Plugin/pom.xml index df36c6f..7e312b1 100644 --- a/Plugin/pom.xml +++ b/Plugin/pom.xml @@ -129,6 +129,13 @@ jar compile + + net.seyarada + pandeloot-v1_21 + v1_21 + jar + compile + net.seyarada pandeloot-api diff --git a/Plugin/src/main/java/net/seyarada/pandeloot/nms/NMSHelper.java b/Plugin/src/main/java/net/seyarada/pandeloot/nms/NMSHelper.java index da83b9b..9cc7cd0 100644 --- a/Plugin/src/main/java/net/seyarada/pandeloot/nms/NMSHelper.java +++ b/Plugin/src/main/java/net/seyarada/pandeloot/nms/NMSHelper.java @@ -1,15 +1,12 @@ package net.seyarada.pandeloot.nms; -import org.bukkit.Bukkit; - public class NMSHelper { static Boolean isOlderThanPlayerTrackEntityEventCache; public static boolean isOlderThanPlayerTrackEntityEvent() { if(isOlderThanPlayerTrackEntityEventCache!=null) return isOlderThanPlayerTrackEntityEventCache; - String packageName = Bukkit.getServer().getClass().getPackage().getName(); - String version = packageName.substring(packageName.lastIndexOf('.') + 1) + String version = NMSManager.getNMSVersion() .substring(3) .replace("_R", "."); double numericVersion = Double.parseDouble(version); diff --git a/pom.xml b/pom.xml index 5560b4b..66de3af 100644 --- a/pom.xml +++ b/pom.xml @@ -24,6 +24,7 @@ v1_20 v1_20_2 v1_20_3 + v1_21 Plugin diff --git a/v1_21/pom.xml b/v1_21/pom.xml new file mode 100644 index 0000000..451aca0 --- /dev/null +++ b/v1_21/pom.xml @@ -0,0 +1,87 @@ + + 4.0.0 + pandeloot-v1_21 + jar + PandeLoot v1_21 + v1_21 + + + UTF-8 + 21 + 21 + + + + net.seyarada + pandeloot-parent + parent + + + + + + org.spigotmc + spigot-api + 1.21.1-R0.1-SNAPSHOT + shaded + provided + + + + + org.spigotmc + spigot + 1.21.1-R0.1-SNAPSHOT + remapped-mojang + provided + + + + net.seyarada + pandeloot-api + API + jar + + + + + + + + net.md-5 + specialsource-maven-plugin + 2.0.3 + + + package + + remap + + remap-obf + + org.spigotmc:minecraft-server:1.21.1-R0.1-SNAPSHOT:txt:maps-mojang + true + org.spigotmc:spigot:1.21.1-R0.1-SNAPSHOT:jar:remapped-mojang + true + remapped-obf + + + + package + + remap + + remap-spigot + + ${project.build.directory}/${project.artifactId}-${project.version}-remapped-obf.jar + org.spigotmc:minecraft-server:1.21.1-R0.1-SNAPSHOT:csrg:maps-spigot + org.spigotmc:spigot:1.21.1-R0.1-SNAPSHOT:jar:remapped-obf + + + + + + + + \ No newline at end of file diff --git a/v1_21/src/main/java/net/seyarada/pandeloot/nms/v1_21_R1/V1_21_R1.java b/v1_21/src/main/java/net/seyarada/pandeloot/nms/v1_21_R1/V1_21_R1.java new file mode 100644 index 0000000..d5f10a5 --- /dev/null +++ b/v1_21/src/main/java/net/seyarada/pandeloot/nms/v1_21_R1/V1_21_R1.java @@ -0,0 +1,175 @@ +package net.seyarada.pandeloot.nms.v1_21_R1; + +import com.mojang.authlib.GameProfile; +import com.mojang.authlib.properties.Property; +import net.minecraft.advancements.*; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.network.protocol.game.*; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.network.ServerGamePacketListenerImpl; +import net.minecraft.world.entity.Display; +import net.minecraft.world.entity.EntityType; +import net.seyarada.pandeloot.nms.NMSMethods; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.craftbukkit.v1_21_R1.CraftWorld; +import org.bukkit.craftbukkit.v1_21_R1.entity.CraftPlayer; +import org.bukkit.craftbukkit.v1_21_R1.entity.CraftTextDisplay; +import org.bukkit.craftbukkit.v1_21_R1.inventory.CraftItemStack; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.SkullMeta; +import org.bukkit.plugin.java.JavaPlugin; + +import java.lang.reflect.Field; +import java.util.*; +import java.util.stream.Collectors; + +public class V1_21_R1 implements NMSMethods { + + @Override + public List hologram(int duration, Location location, Player player, List text, JavaPlugin plugin) { + final ServerLevel wS = ((CraftWorld) location.getWorld()).getHandle(); + double lX = location.getX(); + double lY = location.getY() + 1.2; + double lZ = location.getZ(); + + + + List holograms = new ArrayList<>(); + + Collections.reverse(text); + + for (String msg : text) { + if(msg == null) continue; + if(msg.isEmpty()) { + lY += 0.22; + holograms.add(null); + continue; + } + lY += 0.22; + + Display.TextDisplay displayEntity = new Display.TextDisplay(EntityType.TEXT_DISPLAY, wS); + displayEntity.setPos(lX, lY, lZ); + displayEntity.setCustomName(Component.literal(msg)); + displayEntity.setCustomNameVisible(true); + ((CraftTextDisplay) displayEntity.getBukkitEntity()).setInterpolationDuration(20); + ((CraftTextDisplay) displayEntity.getBukkitEntity()).setInterpolationDelay(0); + holograms.add(displayEntity); + int id = displayEntity.getId(); + ClientboundAddEntityPacket packetPlayOutSpawnEntity = new ClientboundAddEntityPacket(displayEntity, 1, displayEntity.blockPosition()); + ClientboundSetEntityDataPacket metadata = new ClientboundSetEntityDataPacket(id, displayEntity.getEntityData().packDirty()); + + final ServerGamePacketListenerImpl connection = ((CraftPlayer) player).getHandle().connection; + connection.send(packetPlayOutSpawnEntity); + connection.send(metadata); + + if(duration>0) { + Bukkit.getScheduler().runTaskLater(plugin, () -> { + if (player.isOnline()) { + ClientboundRemoveEntitiesPacket destroy = new ClientboundRemoveEntitiesPacket(id); + connection.send(destroy); + } + }, duration); + } + } + return holograms.stream().filter(Objects::nonNull).map(s -> (Entity) s.getBukkitEntity()).collect(Collectors.toCollection(ArrayList::new)); + } + + @Override + public void destroyEntity(int toBeDestroyed, Entity player) { + ClientboundRemoveEntitiesPacket packet = new ClientboundRemoveEntitiesPacket(toBeDestroyed); + ((CraftPlayer) player).getHandle().connection.send(packet); + } + + @Override + public void displayToast(Player player, String title, String frame, org.bukkit.inventory.ItemStack icon) { + ResourceLocation minecraftKey = ResourceLocation.fromNamespaceAndPath("pandeloot", "notification"); + HashMap> criteria = new HashMap<>(); + + criteria.put("for_free", new Criterion(CriteriaTriggers.TICK, criterionValidator -> {})); + + MutableComponent chatTitle = Component.translatable(title); + //IChatBaseComponent chatDescription = new ChatMessage(description); + AdvancementType advancementFrame = AdvancementType.valueOf(frame.toUpperCase()); + net.minecraft.world.item.ItemStack craftIcon = CraftItemStack.asNMSCopy(icon); + + DisplayInfo display = new DisplayInfo(craftIcon, chatTitle, null, null, advancementFrame, true, true, true); + AdvancementRewards reward = new AdvancementRewards(0, List.of(), List.of(), null); + Advancement advancement = new Advancement(Optional.empty(), Optional.of(display), reward, criteria, AdvancementRequirements.EMPTY, true); + + HashMap progressMap = new HashMap<>(); + AdvancementProgress progress = new AdvancementProgress(); + progress.update(AdvancementRequirements.EMPTY); + progress.getCriterion("for_free").grant(); // NMS: Criterion progress + progressMap.put(minecraftKey, progress); + AdvancementHolder holder = new AdvancementHolder(minecraftKey, advancement); + + ClientboundUpdateAdvancementsPacket packet + = new ClientboundUpdateAdvancementsPacket(false, Collections.singletonList(holder), new HashSet<>(), progressMap); + ((CraftPlayer) player).getHandle().connection.send(packet); + + // Remove the advancement + HashSet remove = new HashSet<>(); + remove.add(minecraftKey); + progressMap.clear(); + packet = new ClientboundUpdateAdvancementsPacket(false, new ArrayList<>(), remove, progressMap); + ((CraftPlayer) player).getHandle().connection.send(packet); + } + + @Override + public void injectPlayer(Player player) {} + + @Override + public void removePlayer(Player player) {} + + @Override + public void updateHologramPosition(double x, double y, double z, Entity hologram, Player player) { + if (player == null) return; + Display.TextDisplay stand = ((CraftTextDisplay) hologram).getHandle(); + stand.setPos(x, y, z); + + ServerGamePacketListenerImpl connection = ((CraftPlayer) player).getHandle().connection; + connection.send(new ClientboundTeleportEntityPacket(stand)); + } + + @Override + public ItemStack getCustomTextureHead(ItemStack head, String value) { + SkullMeta meta = (SkullMeta) head.getItemMeta(); + + if(value==null) { + meta.setOwner("PandemoniumHK"); + head.setItemMeta(meta); + return head; + } + + GameProfile profile = new GameProfile(UUID.randomUUID(), ""); + profile.getProperties().put("textures", new Property("textures", value)); + Field profileField; + try { + profileField = meta.getClass().getDeclaredField("profile"); + profileField.setAccessible(true); + profileField.set(meta, profile); + } catch (IllegalArgumentException | IllegalAccessException | NoSuchFieldException | SecurityException e) { + e.printStackTrace(); + } + head.setItemMeta(meta); + return head; + } + + net.minecraft.network.Connection getConnectionWithReflection(Player player) { + // Why did Nokanj made this variable private ?? + try { + // "e" is the "connection" variable + Field connectionField = ((CraftPlayer) player).getHandle().connection.getClass().getDeclaredField("e"); + connectionField.setAccessible(true); + return (net.minecraft.network.Connection) connectionField.get(((CraftPlayer) player).getHandle().connection); + } catch (NoSuchFieldException | IllegalAccessException e) { + throw new RuntimeException(e); + } + } + +}