diff --git a/build.gradle.kts b/build.gradle.kts index 20ae0d7..1ad5703 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -11,7 +11,7 @@ plugins { } group = "me.lojosho" -version = "0.6.4${getGitCommitHash()}" +version = "0.6.5${getGitCommitHash()}" allprojects { apply(plugin = "java") @@ -137,6 +137,7 @@ dependencies { implementation(project(path = ":v1_21_R2", configuration = "reobf")) implementation(project(path = ":v1_21_R3", configuration = "reobf")) implementation(project(path = ":v1_21_R4", configuration = "reobf")) + implementation(project(path = ":v1_21_R5", configuration = "reobf")) } tasks { @@ -172,6 +173,7 @@ tasks { dependsOn(":v1_21_R2:reobfJar") dependsOn(":v1_21_R3:reobfJar") dependsOn(":v1_21_R4:reobfJar") + dependsOn(":v1_21_R5:reobfJar") mergeServiceFiles() relocate("org.bstats", "me.lojosho.shaded.bstats") diff --git a/common/src/main/java/me/lojosho/hibiscuscommons/nms/MinecraftVersion.java b/common/src/main/java/me/lojosho/hibiscuscommons/nms/MinecraftVersion.java index 34d04c6..73d85c5 100644 --- a/common/src/main/java/me/lojosho/hibiscuscommons/nms/MinecraftVersion.java +++ b/common/src/main/java/me/lojosho/hibiscuscommons/nms/MinecraftVersion.java @@ -10,6 +10,7 @@ public enum MinecraftVersion { v1_21_3, v1_21_4, v1_21_5, + v1_21_6, ; public boolean isHigher(MinecraftVersion other) { diff --git a/common/src/main/java/me/lojosho/hibiscuscommons/nms/NMSHandlers.java b/common/src/main/java/me/lojosho/hibiscuscommons/nms/NMSHandlers.java index 2cefd24..81e1a0f 100644 --- a/common/src/main/java/me/lojosho/hibiscuscommons/nms/NMSHandlers.java +++ b/common/src/main/java/me/lojosho/hibiscuscommons/nms/NMSHandlers.java @@ -19,6 +19,7 @@ public class NMSHandlers { put(MinecraftVersion.v1_21_3, "v1_21_R2"); put(MinecraftVersion.v1_21_4, "v1_21_R3"); put(MinecraftVersion.v1_21_5, "v1_21_R4"); + put(MinecraftVersion.v1_21_6, "v1_21_R5"); }}; private static NMSHandler handler; diff --git a/settings.gradle.kts b/settings.gradle.kts index 83f2f2f..6a2b5e5 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -18,4 +18,5 @@ include( "v1_21_R2", "v1_21_R3", "v1_21_R4", + "v1_21_R5", ) \ No newline at end of file diff --git a/v1_21_R5/build.gradle.kts b/v1_21_R5/build.gradle.kts new file mode 100644 index 0000000..7673d17 --- /dev/null +++ b/v1_21_R5/build.gradle.kts @@ -0,0 +1,30 @@ +plugins { + id("java") + id("io.papermc.paperweight.userdev") +} + +dependencies { + paperweight.paperDevBundle("1.21.6-R0.1-SNAPSHOT") + implementation(project(":common")) +} + +tasks { + + build { + dependsOn(reobfJar) + } + + compileJava { + options.encoding = Charsets.UTF_8.name() + } + java { + toolchain.languageVersion.set(JavaLanguageVersion.of(21)); + } + + javadoc { + options.encoding = Charsets.UTF_8.name() + } + processResources { + filteringCharset = Charsets.UTF_8.name() + } +} \ No newline at end of file diff --git a/v1_21_R5/src/main/java/me/lojosho/hibiscuscommons/nms/v1_21_R5/NMSCommon.java b/v1_21_R5/src/main/java/me/lojosho/hibiscuscommons/nms/v1_21_R5/NMSCommon.java new file mode 100644 index 0000000..0043389 --- /dev/null +++ b/v1_21_R5/src/main/java/me/lojosho/hibiscuscommons/nms/v1_21_R5/NMSCommon.java @@ -0,0 +1,17 @@ +package me.lojosho.hibiscuscommons.nms.v1_21_R5; + +import net.minecraft.network.protocol.Packet; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.server.network.ServerPlayerConnection; +import org.bukkit.craftbukkit.entity.CraftPlayer; +import org.bukkit.entity.Player; + +public class NMSCommon { + + public void sendPacket(Player player, Packet packet) { + ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle(); + ServerPlayerConnection connection = serverPlayer.connection; + connection.send(packet); + } + +} diff --git a/v1_21_R5/src/main/java/me/lojosho/hibiscuscommons/nms/v1_21_R5/NMSPackets.java b/v1_21_R5/src/main/java/me/lojosho/hibiscuscommons/nms/v1_21_R5/NMSPackets.java new file mode 100644 index 0000000..5a43ee4 --- /dev/null +++ b/v1_21_R5/src/main/java/me/lojosho/hibiscuscommons/nms/v1_21_R5/NMSPackets.java @@ -0,0 +1,396 @@ +package me.lojosho.hibiscuscommons.nms.v1_21_R5; + +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import com.mojang.datafixers.util.Pair; +import com.mojang.serialization.JsonOps; +import io.netty.buffer.Unpooled; +import it.unimi.dsi.fastutil.ints.IntList; +import me.lojosho.hibiscuscommons.HibiscusCommonsPlugin; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer; +import net.minecraft.advancements.*; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.protocol.Packet; +import net.minecraft.network.protocol.game.*; +import net.minecraft.network.syncher.EntityDataSerializers; +import net.minecraft.network.syncher.SynchedEntityData; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.entity.EquipmentSlot; +import net.minecraft.world.entity.PositionMoveRotation; +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.level.portal.TeleportTransition; +import net.minecraft.world.phys.Vec3; +import net.minecraft.world.scores.PlayerTeam; +import net.minecraft.world.scores.Team; +import org.bukkit.Bukkit; +import org.bukkit.Color; +import org.bukkit.Location; +import org.bukkit.craftbukkit.CraftEquipmentSlot; +import org.bukkit.craftbukkit.entity.CraftEntityType; +import org.bukkit.craftbukkit.entity.CraftPlayer; +import org.bukkit.craftbukkit.inventory.CraftItemStack; +import org.bukkit.craftbukkit.scoreboard.CraftScoreboard; +import org.bukkit.entity.Display; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.ItemDisplay; +import org.bukkit.entity.Player; +import org.bukkit.event.player.PlayerTeleportEvent; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; +import org.bukkit.inventory.meta.components.CustomModelDataComponent; +import org.joml.Quaternionf; +import org.joml.Vector3f; + +import java.lang.reflect.Constructor; +import java.util.*; + +public class NMSPackets extends NMSCommon implements me.lojosho.hibiscuscommons.nms.NMSPackets { + + static Constructor passengerConstructor; + static Constructor linkConstructor; + static Constructor cameraConstructor; + static Constructor lookAtConstructor; + + static { + try { + passengerConstructor = ClientboundSetPassengersPacket.class.getDeclaredConstructor(FriendlyByteBuf.class); + passengerConstructor.setAccessible(true); + } catch (Exception e) { + e.printStackTrace(); + } + try { + linkConstructor = ClientboundSetEntityLinkPacket.class.getDeclaredConstructor(FriendlyByteBuf.class); + linkConstructor.setAccessible(true); + } catch (Exception e) { + e.printStackTrace(); + } + try { + cameraConstructor = ClientboundSetCameraPacket.class.getDeclaredConstructor(FriendlyByteBuf.class); + cameraConstructor.setAccessible(true); + } catch (Exception e) { + e.printStackTrace(); + } + try { + lookAtConstructor = ClientboundPlayerLookAtPacket.class.getDeclaredConstructor(FriendlyByteBuf.class); + lookAtConstructor.setAccessible(true); + } catch (Exception e) { + e.printStackTrace(); + } + } + + @Override + public void sendEquipmentSlotUpdate( + int entityId, + org.bukkit.inventory.EquipmentSlot slot, + ItemStack item, + List sendTo + ) { + + EquipmentSlot nmsSlot = null; + net.minecraft.world.item.ItemStack nmsItem = null; + + // Converting EquipmentSlot and ItemStack to NMS ones. + nmsSlot = CraftEquipmentSlot.getNMS(slot); + nmsItem = CraftItemStack.asNMSCopy(item); + + if (nmsSlot == null) return; + + Pair pair = new Pair<>(nmsSlot, nmsItem); + + List> pairs = Collections.singletonList(pair); + + ClientboundSetEquipmentPacket packet = new ClientboundSetEquipmentPacket(entityId, pairs); + for (Player p : sendTo) sendPacket(p, packet); + } + + @Override + public void sendEquipmentSlotUpdate( + int entityId, + HashMap equipment, + List sendTo + ) { + + List> pairs = new ArrayList<>(); + + for (org.bukkit.inventory.EquipmentSlot slot : equipment.keySet()) { + EquipmentSlot nmsSlot = CraftEquipmentSlot.getNMS(slot); + net.minecraft.world.item.ItemStack nmsItem = CraftItemStack.asNMSCopy(equipment.get(slot)); + + Pair pair = new Pair<>(nmsSlot, nmsItem); + pairs.add(pair); + } + + ClientboundSetEquipmentPacket packet = new ClientboundSetEquipmentPacket(entityId, pairs); + for (Player p : sendTo) sendPacket(p, packet); + } + + + @Override + public void sendSlotUpdate( + Player player, + int slot + ) { + int index = 0; + + ServerPlayer player1 = ((CraftPlayer) player).getHandle(); + + if (index < Inventory.getSelectionSize()) { + index += 36; + } else if (index > 39) { + index += 5; // Off hand + } else if (index > 35) { + index = 8 - (index - 36); + } + ItemStack item = player.getInventory().getItem(slot); + + Packet packet = new ClientboundContainerSetSlotPacket(player1.inventoryMenu.containerId, player1.inventoryMenu.incrementStateId(), index, CraftItemStack.asNMSCopy(item)); + sendPacket(player, packet); + } + + @Override + public void sendScoreboardHideNamePacket(Player player, String name) { + //Creating the team + PlayerTeam team = new PlayerTeam(((CraftScoreboard) Bukkit.getScoreboardManager().getMainScoreboard()).getHandle(), name); + + //Setting name visibility + team.setNameTagVisibility(Team.Visibility.NEVER); + + //Remove the Team (i assume so if it exists) + ClientboundSetPlayerTeamPacket removeTeamPacket = ClientboundSetPlayerTeamPacket.createRemovePacket(team); + sendPacket(player, removeTeamPacket); + //Creating the Team + ClientboundSetPlayerTeamPacket createTeamPacket = ClientboundSetPlayerTeamPacket.createAddOrModifyPacket(team, true); + sendPacket(player, createTeamPacket); + //Adding players to the team (You have to use the NPC's name, and add it to a list) + ClientboundSetPlayerTeamPacket createPlayerTeamPacket = ClientboundSetPlayerTeamPacket.createMultiplePlayerPacket(team, new ArrayList() {{ + add(name); + }}, ClientboundSetPlayerTeamPacket.Action.ADD); + sendPacket(player, createPlayerTeamPacket); + } + + + @Override + public void sendMountPacket(int mountId, int[] passengerIds, List sendTo) { + FriendlyByteBuf byteBuf = new FriendlyByteBuf(Unpooled.buffer()); + byteBuf.writeVarInt(mountId); + byteBuf.writeVarIntArray(passengerIds); + try { + ClientboundSetPassengersPacket packet = passengerConstructor.newInstance(byteBuf); + for (Player p : sendTo) sendPacket(p, packet); + } catch (Exception e) { + e.printStackTrace(); + } + } + + @Override + public void sendLeashPacket(int leashEntity, int entityId, List sendTo) { + FriendlyByteBuf byteBuf = new FriendlyByteBuf(Unpooled.buffer()); + byteBuf.writeInt(leashEntity); + byteBuf.writeInt(entityId); + try { + ClientboundSetEntityLinkPacket packet = linkConstructor.newInstance(byteBuf); + for (Player p : sendTo) sendPacket(p, packet); + } catch (Exception e) { + e.printStackTrace(); + } + } + + @Override + public void sendTeleportPacket( + int entityId, + double x, + double y, + double z, + float yaw, + float pitch, + boolean onGround, + List sendTo + ) { + try { + ClientboundTeleportEntityPacket packet = ClientboundTeleportEntityPacket.teleport(entityId, new PositionMoveRotation(new Vec3(x, y, z), Vec3.ZERO, yaw, pitch), java.util.Set.of(), onGround); + for (Player p : sendTo) sendPacket(p, packet); + } catch (Exception e) { + e.printStackTrace(); + } + } + + @Override + public void sendRotationPacket(int entityId, float yaw, boolean onGround, List sendTo) { + FriendlyByteBuf byteBuf = new FriendlyByteBuf(Unpooled.buffer()); + byteBuf.writeVarInt(entityId); + byteBuf.writeFloat(yaw); + byteBuf.writeBoolean(onGround); + try { + ClientboundPlayerLookAtPacket packet = lookAtConstructor.newInstance(byteBuf); + for (Player p : sendTo) sendPacket(p, packet); + } catch (Exception e) { + e.printStackTrace(); + } + } + + @Override + public void sendCameraPacket(int entityId, List sendTo) { + FriendlyByteBuf byteBuf = new FriendlyByteBuf(Unpooled.buffer()); + byteBuf.writeVarInt(entityId); + try { + ClientboundSetCameraPacket packet = cameraConstructor.newInstance(byteBuf); + for (Player p : sendTo) sendPacket(p, packet); + } catch (Exception e) { + e.printStackTrace(); + } + } + + + @Override + public void sendSpawnEntityPacket(int entityId, UUID uuid, EntityType entityType, Location location, List sendTo) { + net.minecraft.world.entity.EntityType nmsEntityType = CraftEntityType.bukkitToMinecraft(entityType); + double x = location.getX(); + double y = location.getY(); + double z = location.getZ(); + float yaw = location.getYaw(); + float pitch = location.getPitch(); + Vec3 velocity = Vec3.ZERO; + float headYaw = 0f; + + ClientboundAddEntityPacket packet = new ClientboundAddEntityPacket(entityId, uuid, x, y, z, yaw, pitch, nmsEntityType, 0, velocity, headYaw); + for (Player p : sendTo) sendPacket(p, packet); + } + + @Override + public void sendEntityDestroyPacket(IntList entityIds, List sendTo) { + ClientboundRemoveEntitiesPacket packet = new ClientboundRemoveEntitiesPacket(entityIds); + for (Player p : sendTo) sendPacket(p, packet); + } + + @Override + public void sendItemDisplayMetadata(int entityId, + Vector3f translation, + Vector3f scale, + Quaternionf rotationLeft, + Quaternionf rotationRight, + Display.Billboard billboard, + int blockLight, int skyLight, float viewRange, float width, float height, + ItemDisplay.ItemDisplayTransform transform, ItemStack itemStack, + List sendTo) { + + List> dataValues = new ArrayList<>(); + dataValues.add(new SynchedEntityData.DataValue<>(10, EntityDataSerializers.INT, POSITION_INTERPOLATION_DURATION)); + dataValues.add(new SynchedEntityData.DataValue<>(11, EntityDataSerializers.VECTOR3, translation)); + dataValues.add(new SynchedEntityData.DataValue<>(12, EntityDataSerializers.VECTOR3, scale)); + dataValues.add(new SynchedEntityData.DataValue<>(13, EntityDataSerializers.QUATERNION, rotationLeft)); + dataValues.add(new SynchedEntityData.DataValue<>(14, EntityDataSerializers.QUATERNION, rotationRight)); + dataValues.add(new SynchedEntityData.DataValue<>(15, EntityDataSerializers.BYTE, (byte) billboard.ordinal())); + dataValues.add(new SynchedEntityData.DataValue<>(16, EntityDataSerializers.INT, (blockLight << 4 | skyLight << 20))); + dataValues.add(new SynchedEntityData.DataValue<>(17, EntityDataSerializers.FLOAT, viewRange)); + dataValues.add(new SynchedEntityData.DataValue<>(20, EntityDataSerializers.FLOAT, width)); + dataValues.add(new SynchedEntityData.DataValue<>(21, EntityDataSerializers.FLOAT, height)); + dataValues.add(new SynchedEntityData.DataValue<>(23, EntityDataSerializers.ITEM_STACK, CraftItemStack.asNMSCopy(itemStack))); + dataValues.add(new SynchedEntityData.DataValue<>(24, EntityDataSerializers.BYTE, (byte) transform.ordinal())); + + ClientboundSetEntityDataPacket packet = new ClientboundSetEntityDataPacket(entityId, dataValues); + for (Player p : sendTo) sendPacket(p, packet); + } + + public void sendToastPacket(Player player, ItemStack icon, Component title, Component description) { + final var key = ResourceLocation.fromNamespaceAndPath("hibiscuscommons", UUID.randomUUID().toString()); + + JsonObject json = new JsonObject(); + + // Creating the "criteria" object + JsonObject impossibleCriteria = new JsonObject(); + JsonObject impossible = new JsonObject(); + impossible.addProperty("trigger", "minecraft:impossible"); + impossibleCriteria.add("impossible", impossible); + json.add("criteria", impossibleCriteria); + + // Creating the "display" object + JsonObject display = new JsonObject(); + JsonObject iconObj = new JsonObject(); + iconObj.addProperty("id", icon.getType().getKey().toString()); + + if (icon.hasItemMeta()) { + ItemMeta meta = icon.getItemMeta(); + JsonObject components = new JsonObject(); + + if (!meta.getEnchants().isEmpty()) { + components.addProperty("minecraft:enchantment_glint_override", true); + } + + if (meta.hasCustomModelData()) { + CustomModelDataComponent customModelDataComponent = meta.getCustomModelDataComponent(); + JsonObject customModelDataComponentJson = new JsonObject(); + + List floats = customModelDataComponent.getFloats(); + if (!floats.isEmpty()) { + JsonArray floatsArray = new JsonArray(); + floats.forEach(floatsArray::add); + customModelDataComponentJson.add("floats", floatsArray); + } + + List flags = customModelDataComponent.getFlags(); + if (!flags.isEmpty()) { + JsonArray flagsArray = new JsonArray(); + flags.forEach(flagsArray::add); + customModelDataComponentJson.add("flags", flagsArray); + } + + List strings = customModelDataComponent.getStrings(); + if (!strings.isEmpty()) { + JsonArray stringsArray = new JsonArray(); + strings.forEach(stringsArray::add); + customModelDataComponentJson.add("strings", stringsArray); + } + + List colors = customModelDataComponent.getColors(); + if (!colors.isEmpty()) { + JsonArray colorsArray = new JsonArray(); + colors.forEach(color -> colorsArray.add(color.asRGB())); + customModelDataComponentJson.add("colors", colorsArray); + } + + components.add("minecraft:custom_model_data", customModelDataComponentJson); + } + + iconObj.add("components", components); + } + + display.add("icon", iconObj); + display.add("title", GsonComponentSerializer.gson().serializeToTree(title)); + display.add("description", GsonComponentSerializer.gson().serializeToTree(description)); + display.addProperty("description", "Toast Description"); + display.addProperty("frame", "task"); + display.addProperty("announce_to_chat", false); + display.addProperty("show_toast", true); + display.addProperty("hidden", true); + + json.add("display", display); + + final var advancement = Advancement.CODEC.parse(MinecraftServer.getServer().registryAccess().createSerializationContext(JsonOps.INSTANCE), json); + final var advancementHolder = new AdvancementHolder(key, advancement.result().orElseThrow()); + + final var nmsPlayer = ((CraftPlayer) player).getHandle(); + final var progress = nmsPlayer.getAdvancements().getOrStartProgress(advancementHolder); + MinecraftServer.getServer().getAdvancements().tree().addAll(Set.of(advancementHolder)); + progress.getRemainingCriteria().forEach(criteria -> nmsPlayer.getAdvancements().award(advancementHolder, criteria)); + + Bukkit.getScheduler().runTaskLater(HibiscusCommonsPlugin.getInstance(), () -> { + progress.getRemainingCriteria().forEach(criteria -> nmsPlayer.getAdvancements().revoke(advancementHolder, criteria)); + MinecraftServer.getServer().getAdvancements().tree().remove(Set.of(key)); + + // Remove the advancement from the player's client to prevent it from being displayed again + // Was not working without this? + ClientboundUpdateAdvancementsPacket removePacket = new ClientboundUpdateAdvancementsPacket( + false, + Collections.emptyList(), + Set.of(key), + Map.of(), + false + ); + + sendPacket(player, removePacket); + }, 2L); + } +} diff --git a/v1_21_R5/src/main/java/me/lojosho/hibiscuscommons/nms/v1_21_R5/NMSUtils.java b/v1_21_R5/src/main/java/me/lojosho/hibiscuscommons/nms/v1_21_R5/NMSUtils.java new file mode 100644 index 0000000..c7bdce4 --- /dev/null +++ b/v1_21_R5/src/main/java/me/lojosho/hibiscuscommons/nms/v1_21_R5/NMSUtils.java @@ -0,0 +1,54 @@ +package me.lojosho.hibiscuscommons.nms.v1_21_R5; + +import net.minecraft.core.component.DataComponents; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.item.component.DyedItemColor; +import org.bukkit.Bukkit; +import org.bukkit.Color; +import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.craftbukkit.inventory.CraftItemStack; +import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class NMSUtils extends NMSCommon implements me.lojosho.hibiscuscommons.nms.NMSUtils { + + @Override + public int getNextEntityId() { + return net.minecraft.world.entity.Entity.nextEntityId(); + } + + @Override + public org.bukkit.entity.Entity getEntity(int entityId) { + net.minecraft.world.entity.Entity entity = getNMSEntity(entityId); + if (entity == null) return null; + return entity.getBukkitEntity(); + } + + @Override + public @Nullable Color getColor(ItemStack itemStack) { + if (itemStack == null) return null; + net.minecraft.world.item.ItemStack nmsItem = CraftItemStack.asNMSCopy(itemStack); + if (nmsItem == null) return null; + + DyedItemColor color = nmsItem.get(DataComponents.DYED_COLOR); + if (color == null) return null; + return Color.fromRGB(color.rgb()); + } + + @Override + public ItemStack setColor(@NotNull ItemStack itemStack, Color color) { + net.minecraft.world.item.ItemStack nmsStack = CraftItemStack.asNMSCopy(itemStack); + nmsStack.set(DataComponents.DYED_COLOR, new DyedItemColor(color.asRGB())); + return CraftItemStack.asBukkitCopy(nmsStack); + } + + private net.minecraft.world.entity.Entity getNMSEntity(int entityId) { + for (ServerLevel world : ((CraftServer) Bukkit.getServer()).getHandle().getServer().getAllLevels()) { + net.minecraft.world.entity.Entity entity = world.getEntity(entityId); + if (entity == null) continue; + return entity; + } + return null; + } +}