From a130761fa8523b0510a9d6f7624ed4491336d08a Mon Sep 17 00:00:00 2001 From: Maxence Simon <32517160+Maxlego08@users.noreply.github.com> Date: Sun, 17 Aug 2025 13:35:59 +0200 Subject: [PATCH] Add NMS modules for 1.21.5-1.21.7 --- NMS/V1_21_5/build.gradle.kts | 20 +++ .../essentials/nms/v1_21_5/CraftHologram.java | 163 ++++++++++++++++++ .../essentials/nms/v1_21_5/PlayerUtils.java | 43 +++++ .../nms/v1_21_5/WayPointPacket.java | 91 ++++++++++ .../enderchest/CraftPlayerManager.java | 24 +++ NMS/V1_21_6/build.gradle.kts | 20 +++ .../essentials/nms/v1_21_6/CraftHologram.java | 163 ++++++++++++++++++ .../essentials/nms/v1_21_6/PlayerUtils.java | 43 +++++ .../nms/v1_21_6/WayPointPacket.java | 91 ++++++++++ .../enderchest/CraftPlayerManager.java | 24 +++ NMS/V1_21_7/build.gradle.kts | 20 +++ .../essentials/nms/v1_21_7/CraftHologram.java | 163 ++++++++++++++++++ .../essentials/nms/v1_21_7/PlayerUtils.java | 43 +++++ .../nms/v1_21_7/WayPointPacket.java | 91 ++++++++++ .../enderchest/CraftPlayerManager.java | 24 +++ build.gradle.kts | 5 +- settings.gradle.kts | 3 + 17 files changed, 1030 insertions(+), 1 deletion(-) create mode 100644 NMS/V1_21_5/build.gradle.kts create mode 100644 NMS/V1_21_5/src/main/java/fr/maxlego08/essentials/nms/v1_21_5/CraftHologram.java create mode 100644 NMS/V1_21_5/src/main/java/fr/maxlego08/essentials/nms/v1_21_5/PlayerUtils.java create mode 100644 NMS/V1_21_5/src/main/java/fr/maxlego08/essentials/nms/v1_21_5/WayPointPacket.java create mode 100644 NMS/V1_21_5/src/main/java/fr/maxlego08/essentials/nms/v1_21_5/enderchest/CraftPlayerManager.java create mode 100644 NMS/V1_21_6/build.gradle.kts create mode 100644 NMS/V1_21_6/src/main/java/fr/maxlego08/essentials/nms/v1_21_6/CraftHologram.java create mode 100644 NMS/V1_21_6/src/main/java/fr/maxlego08/essentials/nms/v1_21_6/PlayerUtils.java create mode 100644 NMS/V1_21_6/src/main/java/fr/maxlego08/essentials/nms/v1_21_6/WayPointPacket.java create mode 100644 NMS/V1_21_6/src/main/java/fr/maxlego08/essentials/nms/v1_21_6/enderchest/CraftPlayerManager.java create mode 100644 NMS/V1_21_7/build.gradle.kts create mode 100644 NMS/V1_21_7/src/main/java/fr/maxlego08/essentials/nms/v1_21_7/CraftHologram.java create mode 100644 NMS/V1_21_7/src/main/java/fr/maxlego08/essentials/nms/v1_21_7/PlayerUtils.java create mode 100644 NMS/V1_21_7/src/main/java/fr/maxlego08/essentials/nms/v1_21_7/WayPointPacket.java create mode 100644 NMS/V1_21_7/src/main/java/fr/maxlego08/essentials/nms/v1_21_7/enderchest/CraftPlayerManager.java diff --git a/NMS/V1_21_5/build.gradle.kts b/NMS/V1_21_5/build.gradle.kts new file mode 100644 index 00000000..5aed0f27 --- /dev/null +++ b/NMS/V1_21_5/build.gradle.kts @@ -0,0 +1,20 @@ +plugins { + id("io.papermc.paperweight.userdev") +} + +group "NMS:V1_21_5" + +dependencies { + compileOnly(project(":API")) + paperweight.paperDevBundle("1.21.5-R0.1-SNAPSHOT") +} + +paperweight.reobfArtifactConfiguration = io.papermc.paperweight.userdev.ReobfArtifactConfiguration.REOBF_PRODUCTION + +java { + toolchain.languageVersion = JavaLanguageVersion.of(21) +} + +tasks.assemble { + dependsOn(tasks.reobfJar) +} diff --git a/NMS/V1_21_5/src/main/java/fr/maxlego08/essentials/nms/v1_21_5/CraftHologram.java b/NMS/V1_21_5/src/main/java/fr/maxlego08/essentials/nms/v1_21_5/CraftHologram.java new file mode 100644 index 00000000..0a821cfb --- /dev/null +++ b/NMS/V1_21_5/src/main/java/fr/maxlego08/essentials/nms/v1_21_5/CraftHologram.java @@ -0,0 +1,163 @@ +package fr.maxlego08.essentials.nms.v1_21_5; + +import com.mojang.math.Transformation; +import fr.maxlego08.essentials.api.EssentialsPlugin; +import fr.maxlego08.essentials.api.hologram.Hologram; +import fr.maxlego08.essentials.api.hologram.HologramType; +import fr.maxlego08.essentials.api.hologram.configuration.BlockHologramConfiguration; +import fr.maxlego08.essentials.api.hologram.configuration.HologramConfiguration; +import fr.maxlego08.essentials.api.hologram.configuration.ItemHologramConfiguration; +import fr.maxlego08.essentials.api.hologram.configuration.TextHologramConfiguration; +import fr.maxlego08.essentials.api.utils.ReflectionUtils; +import fr.maxlego08.essentials.api.utils.SafeLocation; +import io.papermc.paper.adventure.PaperAdventure; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.network.protocol.Packet; +import net.minecraft.network.protocol.game.ClientboundAddEntityPacket; +import net.minecraft.network.protocol.game.ClientboundRemoveEntitiesPacket; +import net.minecraft.network.protocol.game.ClientboundSetEntityDataPacket; +import net.minecraft.network.protocol.game.ClientboundTeleportEntityPacket; +import net.minecraft.network.syncher.EntityDataAccessor; +import net.minecraft.network.syncher.SynchedEntityData; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.level.ServerEntity; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.util.Brightness; +import net.minecraft.world.entity.Display; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.PositionMoveRotation; +import net.minecraft.world.item.ItemDisplayContext; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.Block; +import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.craftbukkit.entity.CraftPlayer; +import org.bukkit.entity.Player; +import org.joml.Quaternionf; + +import java.util.ArrayList; +import java.util.Set; + +public class CraftHologram extends Hologram { + + private Display display = null; + + public CraftHologram(EssentialsPlugin plugin, HologramType hologramType, HologramConfiguration configuration, String fileName, String name, SafeLocation location) { + super(plugin, hologramType, name, fileName, location, configuration); + } + + @Override + public void create(Player player) { + ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle(); + ServerEntity serverEntity = new ServerEntity(serverPlayer.level(), display, 0, false, packet -> { + }, (a, b) -> { + }, Set.of()); + send(player, new ClientboundAddEntityPacket(display, serverEntity)); + + this.update(player); + } + + @Override + public void delete(Player player) { + this.send(player, new ClientboundRemoveEntitiesPacket(display.getId())); + } + + @Override + public void update(Player player) { + + send(player, new ClientboundTeleportEntityPacket(display.getId(), PositionMoveRotation.of(display), Set.of(), display.onGround)); + + if (display instanceof Display.TextDisplay textDisplay) { + textDisplay.setText(PaperAdventure.asVanilla(getComponentText(player))); + } + + final var values = new ArrayList>(); + for (final var item : ((SynchedEntityData.DataItem[]) ReflectionUtils.getValue(display.getEntityData(), "itemsById"))) { + values.add(item.value()); + } + send(player, new ClientboundSetEntityDataPacket(display.getId(), values)); + } + + @Override + public void create() { + ServerLevel serverLevel = ((CraftWorld) location.getLocation().getWorld()).getHandle(); + switch (hologramType) { + case BLOCK -> this.display = new Display.BlockDisplay(EntityType.BLOCK_DISPLAY, serverLevel); + case ITEM -> this.display = new Display.ItemDisplay(EntityType.ITEM_DISPLAY, serverLevel); + case TEXT -> this.display = new Display.TextDisplay(EntityType.TEXT_DISPLAY, serverLevel); + } + + display.getEntityData().set((EntityDataAccessor) ReflectionUtils.getStaticValue(Display.class, "DATA_TRANSFORMATION_INTERPOLATION_DURATION_ID"), 1); // Transformation duration + display.getEntityData().set((EntityDataAccessor) ReflectionUtils.getStaticValue(Display.class, "DATA_TRANSFORMATION_INTERPOLATION_START_DELTA_TICKS_ID"), 0); // Interpolation start + + this.updateLocation(); + this.update(); + } + + @Override + public void updateLocation() { + display.setPosRaw(location.getX(), location.getY(), location.getZ()); + display.setYRot(location.getYaw()); + display.setXRot(location.getPitch()); + } + + @Override + public void update() { + + display.setBillboardConstraints(switch (this.configuration.getBillboard()) { + case FIXED -> Display.BillboardConstraints.FIXED; + case VERTICAL -> Display.BillboardConstraints.VERTICAL; + case HORIZONTAL -> Display.BillboardConstraints.HORIZONTAL; + case CENTER -> Display.BillboardConstraints.CENTER; + }); + + if (display instanceof Display.TextDisplay textDisplay && configuration instanceof TextHologramConfiguration textHologramConfiguration) { + + display.getEntityData().set((EntityDataAccessor) ReflectionUtils.getStaticValue(Display.TextDisplay.class, "DATA_LINE_WIDTH_ID"), Hologram.LINE_WIDTH); + + var backgroundColor = (EntityDataAccessor) ReflectionUtils.getStaticValue(Display.TextDisplay.class, "DATA_BACKGROUND_COLOR_ID"); + var background = textHologramConfiguration.getBackground(); + int backgroundValue = (background == null) ? Display.TextDisplay.INITIAL_BACKGROUND : (background == Hologram.TRANSPARENT) ? 0 : background.value() | 0xC8000000; + display.getEntityData().set(backgroundColor, backgroundValue); + + byte flags = textDisplay.getFlags(); + flags = (byte) (textHologramConfiguration.isTextShadow() ? (flags | Display.TextDisplay.FLAG_SHADOW) : (flags & ~Display.TextDisplay.FLAG_SHADOW)); + flags = (byte) (textHologramConfiguration.getTextAlignment() == org.bukkit.entity.TextDisplay.TextAlignment.LEFT ? (flags | Display.TextDisplay.FLAG_ALIGN_LEFT) : (flags & ~Display.TextDisplay.FLAG_ALIGN_LEFT)); + flags = (byte) (textHologramConfiguration.isSeeThrough() ? (flags | Display.TextDisplay.FLAG_SEE_THROUGH) : (flags & ~Display.TextDisplay.FLAG_SEE_THROUGH)); + flags = (byte) (textHologramConfiguration.getTextAlignment() == org.bukkit.entity.TextDisplay.TextAlignment.RIGHT ? (flags | Display.TextDisplay.FLAG_ALIGN_RIGHT) : (flags & ~Display.TextDisplay.FLAG_ALIGN_RIGHT)); + textDisplay.setFlags(flags); + } else if (display instanceof Display.ItemDisplay itemDisplay && configuration instanceof ItemHologramConfiguration itemHologramConfiguration) { + + var context = switch (itemHologramConfiguration.getItemDisplayTransform()) { + case THIRDPERSON_LEFTHAND -> ItemDisplayContext.THIRD_PERSON_LEFT_HAND; + case THIRDPERSON_RIGHTHAND -> ItemDisplayContext.THIRD_PERSON_RIGHT_HAND; + case FIRSTPERSON_LEFTHAND -> ItemDisplayContext.FIRST_PERSON_LEFT_HAND; + case FIRSTPERSON_RIGHTHAND -> ItemDisplayContext.FIRST_PERSON_RIGHT_HAND; + default -> ItemDisplayContext.valueOf(itemHologramConfiguration.getItemDisplayTransform().name()); + }; + itemDisplay.setItemTransform(context); + itemDisplay.setItemStack(ItemStack.fromBukkitCopy(itemHologramConfiguration.getItemStack())); + } else if (display instanceof Display.BlockDisplay blockDisplay && configuration instanceof BlockHologramConfiguration blockData) { + + var optional = BuiltInRegistries.BLOCK.get(ResourceLocation.parse(blockData.getMaterial().name().toLowerCase())); + if (optional.isPresent()) { + Block block = optional.get().value(); + blockDisplay.setBlockState(block.defaultBlockState()); + } + } + + if (this.configuration.getBrightness() != null) { + display.setBrightnessOverride(new Brightness(this.configuration.getBrightness().getBlockLight(), this.configuration.getBrightness().getSkyLight())); + } + + display.setTransformation(new Transformation(this.configuration.getTranslation(), new Quaternionf(), this.configuration.getScale(), new Quaternionf())); + + display.setShadowRadius(this.configuration.getShadowRadius()); + display.setShadowStrength(this.configuration.getShadowStrength()); + } + + private void send(Player player, Packet packet) { + ((CraftPlayer) player).getHandle().connection.send(packet); + } + +} diff --git a/NMS/V1_21_5/src/main/java/fr/maxlego08/essentials/nms/v1_21_5/PlayerUtils.java b/NMS/V1_21_5/src/main/java/fr/maxlego08/essentials/nms/v1_21_5/PlayerUtils.java new file mode 100644 index 00000000..9e22be80 --- /dev/null +++ b/NMS/V1_21_5/src/main/java/fr/maxlego08/essentials/nms/v1_21_5/PlayerUtils.java @@ -0,0 +1,43 @@ +package fr.maxlego08.essentials.nms.v1_21_5; + +import fr.maxlego08.essentials.api.EssentialsPlugin; +import fr.maxlego08.essentials.api.nms.PlayerUtil; +import org.bukkit.OfflinePlayer; +import org.bukkit.entity.Player; + +public class PlayerUtils implements PlayerUtil { + + private final EssentialsPlugin plugin; + + public PlayerUtils(EssentialsPlugin plugin) { + this.plugin = plugin; + } + + @Override + public boolean openEnderChest(Player player, OfflinePlayer offlinePlayer) { + + /*CraftPlayerManager craftPlayerManager = new CraftPlayerManager(plugin.getLogger()); + var loadPlayer = craftPlayerManager.loadPlayer(offlinePlayer); + + if (loadPlayer != null) { + EnderChestHolder enderChestHolder = new EnderChestHolder(loadPlayer); + player.openInventory(enderChestHolder.getInventory()); + return true; + }*/ + return false; + } + + @Override + public boolean openPlayerInventory(Player player, OfflinePlayer offlinePlayer) { + /*CraftPlayerManager craftPlayerManager = new CraftPlayerManager(plugin.getLogger()); + var loadPlayer = craftPlayerManager.loadPlayer(offlinePlayer); + + if (loadPlayer != null) { + PlayerInventoryHolder enderChestHolder = new PlayerInventoryHolder(loadPlayer); + player.openInventory(enderChestHolder.getInventory()); + return true; + }*/ + return false; + } + +} diff --git a/NMS/V1_21_5/src/main/java/fr/maxlego08/essentials/nms/v1_21_5/WayPointPacket.java b/NMS/V1_21_5/src/main/java/fr/maxlego08/essentials/nms/v1_21_5/WayPointPacket.java new file mode 100644 index 00000000..6156ca60 --- /dev/null +++ b/NMS/V1_21_5/src/main/java/fr/maxlego08/essentials/nms/v1_21_5/WayPointPacket.java @@ -0,0 +1,91 @@ +package fr.maxlego08.essentials.nms.v1_21_5; + +import fr.maxlego08.essentials.api.waypoint.WayPointHelper; +import fr.maxlego08.essentials.api.waypoint.WayPointIcon; +import net.minecraft.core.BlockPos; +import net.minecraft.network.protocol.Packet; +import net.minecraft.network.protocol.game.ClientboundTrackedWaypointPacket; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.waypoints.Waypoint; +import net.minecraft.world.waypoints.WaypointStyleAssets; +import org.bukkit.Chunk; +import org.bukkit.Location; +import org.bukkit.craftbukkit.entity.CraftPlayer; +import org.bukkit.entity.Player; + +import java.util.Optional; +import java.util.UUID; + +public class WayPointPacket implements WayPointHelper { + + @Override + public void addWayPoint(Player player, UUID uniqueId, Location location, WayPointIcon wayPointIcon) { + + var icon = toIcon(wayPointIcon); + var blockPos = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + var packet = ClientboundTrackedWaypointPacket.addWaypointPosition(uniqueId, icon, blockPos); + + sendPacket(player, packet); + } + + @Override + public void updateWayPointPosition(Player player, UUID uniqueId, Location location, WayPointIcon wayPointIcon) { + + var icon = toIcon(wayPointIcon); + var blockPos = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + var packet = ClientboundTrackedWaypointPacket.updateWaypointPosition(uniqueId, icon, blockPos); + + sendPacket(player, packet); + } + + @Override + public void addWayPoint(Player player, UUID uniqueId, Chunk chunk, WayPointIcon wayPointIcon) { + + var icon = toIcon(wayPointIcon); + var chunkPos = new ChunkPos(chunk.getX(), chunk.getZ()); + var packet = ClientboundTrackedWaypointPacket.addWaypointChunk(uniqueId, icon, chunkPos); + + sendPacket(player, packet); + } + + @Override + public void updateWayPointPosition(Player player, UUID uniqueId, Chunk chunk, WayPointIcon wayPointIcon) { + + var icon = toIcon(wayPointIcon); + var chunkPos = new ChunkPos(chunk.getX(), chunk.getZ()); + var packet = ClientboundTrackedWaypointPacket.updateWaypointChunk(uniqueId, icon, chunkPos); + + sendPacket(player, packet); + } + + @Override + public void removeWayPoint(Player player, UUID uniqueId) { + + var packet = ClientboundTrackedWaypointPacket.removeWaypoint(uniqueId); + sendPacket(player, packet); + } + + private void sendPacket(Player player, Packet packet) { + ((CraftPlayer) player).getHandle().connection.send(packet); + } + + /** + * Converts a {@link WayPointIcon} to a {@link Waypoint.Icon}. + *

+ * If the given {@link WayPointIcon} has a texture, then the style of the resulting icon will be set to the + * death waypoint style. Otherwise, the style will be left unchanged. + *

+ * The color of the resulting icon will be set to the color of the given {@link WayPointIcon}. + * + * @param wayPointIcon the icon to convert + * @return the converted icon + */ + private Waypoint.Icon toIcon(WayPointIcon wayPointIcon) { + var icon = new Waypoint.Icon(); + if (wayPointIcon.texture() != null) { + icon.style = WaypointStyleAssets.createId(wayPointIcon.texture()); + } + icon.color = Optional.of(wayPointIcon.color().getRGB() & 0xFFFFFF); + return icon; + } +} diff --git a/NMS/V1_21_5/src/main/java/fr/maxlego08/essentials/nms/v1_21_5/enderchest/CraftPlayerManager.java b/NMS/V1_21_5/src/main/java/fr/maxlego08/essentials/nms/v1_21_5/enderchest/CraftPlayerManager.java new file mode 100644 index 00000000..d0dfed5a --- /dev/null +++ b/NMS/V1_21_5/src/main/java/fr/maxlego08/essentials/nms/v1_21_5/enderchest/CraftPlayerManager.java @@ -0,0 +1,24 @@ +package fr.maxlego08.essentials.nms.v1_21_5.enderchest; + +import org.apache.commons.lang3.NotImplementedException; +import org.bukkit.OfflinePlayer; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * Based on: OpenInv + */ +public class CraftPlayerManager implements fr.maxlego08.essentials.api.nms.PlayerManager { + + + @Override + public @Nullable Player loadPlayer(@NotNull OfflinePlayer offline) { + throw new NotImplementedException(); + } + + @Override + public @NotNull Player inject(@NotNull Player player) { + throw new NotImplementedException(); + } +} diff --git a/NMS/V1_21_6/build.gradle.kts b/NMS/V1_21_6/build.gradle.kts new file mode 100644 index 00000000..058d3dea --- /dev/null +++ b/NMS/V1_21_6/build.gradle.kts @@ -0,0 +1,20 @@ +plugins { + id("io.papermc.paperweight.userdev") +} + +group "NMS:V1_21_6" + +dependencies { + compileOnly(project(":API")) + paperweight.paperDevBundle("1.21.6-R0.1-SNAPSHOT") +} + +paperweight.reobfArtifactConfiguration = io.papermc.paperweight.userdev.ReobfArtifactConfiguration.REOBF_PRODUCTION + +java { + toolchain.languageVersion = JavaLanguageVersion.of(21) +} + +tasks.assemble { + dependsOn(tasks.reobfJar) +} diff --git a/NMS/V1_21_6/src/main/java/fr/maxlego08/essentials/nms/v1_21_6/CraftHologram.java b/NMS/V1_21_6/src/main/java/fr/maxlego08/essentials/nms/v1_21_6/CraftHologram.java new file mode 100644 index 00000000..c2d8743c --- /dev/null +++ b/NMS/V1_21_6/src/main/java/fr/maxlego08/essentials/nms/v1_21_6/CraftHologram.java @@ -0,0 +1,163 @@ +package fr.maxlego08.essentials.nms.v1_21_6; + +import com.mojang.math.Transformation; +import fr.maxlego08.essentials.api.EssentialsPlugin; +import fr.maxlego08.essentials.api.hologram.Hologram; +import fr.maxlego08.essentials.api.hologram.HologramType; +import fr.maxlego08.essentials.api.hologram.configuration.BlockHologramConfiguration; +import fr.maxlego08.essentials.api.hologram.configuration.HologramConfiguration; +import fr.maxlego08.essentials.api.hologram.configuration.ItemHologramConfiguration; +import fr.maxlego08.essentials.api.hologram.configuration.TextHologramConfiguration; +import fr.maxlego08.essentials.api.utils.ReflectionUtils; +import fr.maxlego08.essentials.api.utils.SafeLocation; +import io.papermc.paper.adventure.PaperAdventure; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.network.protocol.Packet; +import net.minecraft.network.protocol.game.ClientboundAddEntityPacket; +import net.minecraft.network.protocol.game.ClientboundRemoveEntitiesPacket; +import net.minecraft.network.protocol.game.ClientboundSetEntityDataPacket; +import net.minecraft.network.protocol.game.ClientboundTeleportEntityPacket; +import net.minecraft.network.syncher.EntityDataAccessor; +import net.minecraft.network.syncher.SynchedEntityData; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.level.ServerEntity; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.util.Brightness; +import net.minecraft.world.entity.Display; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.PositionMoveRotation; +import net.minecraft.world.item.ItemDisplayContext; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.Block; +import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.craftbukkit.entity.CraftPlayer; +import org.bukkit.entity.Player; +import org.joml.Quaternionf; + +import java.util.ArrayList; +import java.util.Set; + +public class CraftHologram extends Hologram { + + private Display display = null; + + public CraftHologram(EssentialsPlugin plugin, HologramType hologramType, HologramConfiguration configuration, String fileName, String name, SafeLocation location) { + super(plugin, hologramType, name, fileName, location, configuration); + } + + @Override + public void create(Player player) { + ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle(); + ServerEntity serverEntity = new ServerEntity(serverPlayer.level(), display, 0, false, packet -> { + }, (a, b) -> { + }, Set.of()); + send(player, new ClientboundAddEntityPacket(display, serverEntity)); + + this.update(player); + } + + @Override + public void delete(Player player) { + this.send(player, new ClientboundRemoveEntitiesPacket(display.getId())); + } + + @Override + public void update(Player player) { + + send(player, new ClientboundTeleportEntityPacket(display.getId(), PositionMoveRotation.of(display), Set.of(), display.onGround)); + + if (display instanceof Display.TextDisplay textDisplay) { + textDisplay.setText(PaperAdventure.asVanilla(getComponentText(player))); + } + + final var values = new ArrayList>(); + for (final var item : ((SynchedEntityData.DataItem[]) ReflectionUtils.getValue(display.getEntityData(), "itemsById"))) { + values.add(item.value()); + } + send(player, new ClientboundSetEntityDataPacket(display.getId(), values)); + } + + @Override + public void create() { + ServerLevel serverLevel = ((CraftWorld) location.getLocation().getWorld()).getHandle(); + switch (hologramType) { + case BLOCK -> this.display = new Display.BlockDisplay(EntityType.BLOCK_DISPLAY, serverLevel); + case ITEM -> this.display = new Display.ItemDisplay(EntityType.ITEM_DISPLAY, serverLevel); + case TEXT -> this.display = new Display.TextDisplay(EntityType.TEXT_DISPLAY, serverLevel); + } + + display.getEntityData().set((EntityDataAccessor) ReflectionUtils.getStaticValue(Display.class, "DATA_TRANSFORMATION_INTERPOLATION_DURATION_ID"), 1); // Transformation duration + display.getEntityData().set((EntityDataAccessor) ReflectionUtils.getStaticValue(Display.class, "DATA_TRANSFORMATION_INTERPOLATION_START_DELTA_TICKS_ID"), 0); // Interpolation start + + this.updateLocation(); + this.update(); + } + + @Override + public void updateLocation() { + display.setPosRaw(location.getX(), location.getY(), location.getZ()); + display.setYRot(location.getYaw()); + display.setXRot(location.getPitch()); + } + + @Override + public void update() { + + display.setBillboardConstraints(switch (this.configuration.getBillboard()) { + case FIXED -> Display.BillboardConstraints.FIXED; + case VERTICAL -> Display.BillboardConstraints.VERTICAL; + case HORIZONTAL -> Display.BillboardConstraints.HORIZONTAL; + case CENTER -> Display.BillboardConstraints.CENTER; + }); + + if (display instanceof Display.TextDisplay textDisplay && configuration instanceof TextHologramConfiguration textHologramConfiguration) { + + display.getEntityData().set((EntityDataAccessor) ReflectionUtils.getStaticValue(Display.TextDisplay.class, "DATA_LINE_WIDTH_ID"), Hologram.LINE_WIDTH); + + var backgroundColor = (EntityDataAccessor) ReflectionUtils.getStaticValue(Display.TextDisplay.class, "DATA_BACKGROUND_COLOR_ID"); + var background = textHologramConfiguration.getBackground(); + int backgroundValue = (background == null) ? Display.TextDisplay.INITIAL_BACKGROUND : (background == Hologram.TRANSPARENT) ? 0 : background.value() | 0xC8000000; + display.getEntityData().set(backgroundColor, backgroundValue); + + byte flags = textDisplay.getFlags(); + flags = (byte) (textHologramConfiguration.isTextShadow() ? (flags | Display.TextDisplay.FLAG_SHADOW) : (flags & ~Display.TextDisplay.FLAG_SHADOW)); + flags = (byte) (textHologramConfiguration.getTextAlignment() == org.bukkit.entity.TextDisplay.TextAlignment.LEFT ? (flags | Display.TextDisplay.FLAG_ALIGN_LEFT) : (flags & ~Display.TextDisplay.FLAG_ALIGN_LEFT)); + flags = (byte) (textHologramConfiguration.isSeeThrough() ? (flags | Display.TextDisplay.FLAG_SEE_THROUGH) : (flags & ~Display.TextDisplay.FLAG_SEE_THROUGH)); + flags = (byte) (textHologramConfiguration.getTextAlignment() == org.bukkit.entity.TextDisplay.TextAlignment.RIGHT ? (flags | Display.TextDisplay.FLAG_ALIGN_RIGHT) : (flags & ~Display.TextDisplay.FLAG_ALIGN_RIGHT)); + textDisplay.setFlags(flags); + } else if (display instanceof Display.ItemDisplay itemDisplay && configuration instanceof ItemHologramConfiguration itemHologramConfiguration) { + + var context = switch (itemHologramConfiguration.getItemDisplayTransform()) { + case THIRDPERSON_LEFTHAND -> ItemDisplayContext.THIRD_PERSON_LEFT_HAND; + case THIRDPERSON_RIGHTHAND -> ItemDisplayContext.THIRD_PERSON_RIGHT_HAND; + case FIRSTPERSON_LEFTHAND -> ItemDisplayContext.FIRST_PERSON_LEFT_HAND; + case FIRSTPERSON_RIGHTHAND -> ItemDisplayContext.FIRST_PERSON_RIGHT_HAND; + default -> ItemDisplayContext.valueOf(itemHologramConfiguration.getItemDisplayTransform().name()); + }; + itemDisplay.setItemTransform(context); + itemDisplay.setItemStack(ItemStack.fromBukkitCopy(itemHologramConfiguration.getItemStack())); + } else if (display instanceof Display.BlockDisplay blockDisplay && configuration instanceof BlockHologramConfiguration blockData) { + + var optional = BuiltInRegistries.BLOCK.get(ResourceLocation.parse(blockData.getMaterial().name().toLowerCase())); + if (optional.isPresent()) { + Block block = optional.get().value(); + blockDisplay.setBlockState(block.defaultBlockState()); + } + } + + if (this.configuration.getBrightness() != null) { + display.setBrightnessOverride(new Brightness(this.configuration.getBrightness().getBlockLight(), this.configuration.getBrightness().getSkyLight())); + } + + display.setTransformation(new Transformation(this.configuration.getTranslation(), new Quaternionf(), this.configuration.getScale(), new Quaternionf())); + + display.setShadowRadius(this.configuration.getShadowRadius()); + display.setShadowStrength(this.configuration.getShadowStrength()); + } + + private void send(Player player, Packet packet) { + ((CraftPlayer) player).getHandle().connection.send(packet); + } + +} diff --git a/NMS/V1_21_6/src/main/java/fr/maxlego08/essentials/nms/v1_21_6/PlayerUtils.java b/NMS/V1_21_6/src/main/java/fr/maxlego08/essentials/nms/v1_21_6/PlayerUtils.java new file mode 100644 index 00000000..427924e6 --- /dev/null +++ b/NMS/V1_21_6/src/main/java/fr/maxlego08/essentials/nms/v1_21_6/PlayerUtils.java @@ -0,0 +1,43 @@ +package fr.maxlego08.essentials.nms.v1_21_6; + +import fr.maxlego08.essentials.api.EssentialsPlugin; +import fr.maxlego08.essentials.api.nms.PlayerUtil; +import org.bukkit.OfflinePlayer; +import org.bukkit.entity.Player; + +public class PlayerUtils implements PlayerUtil { + + private final EssentialsPlugin plugin; + + public PlayerUtils(EssentialsPlugin plugin) { + this.plugin = plugin; + } + + @Override + public boolean openEnderChest(Player player, OfflinePlayer offlinePlayer) { + + /*CraftPlayerManager craftPlayerManager = new CraftPlayerManager(plugin.getLogger()); + var loadPlayer = craftPlayerManager.loadPlayer(offlinePlayer); + + if (loadPlayer != null) { + EnderChestHolder enderChestHolder = new EnderChestHolder(loadPlayer); + player.openInventory(enderChestHolder.getInventory()); + return true; + }*/ + return false; + } + + @Override + public boolean openPlayerInventory(Player player, OfflinePlayer offlinePlayer) { + /*CraftPlayerManager craftPlayerManager = new CraftPlayerManager(plugin.getLogger()); + var loadPlayer = craftPlayerManager.loadPlayer(offlinePlayer); + + if (loadPlayer != null) { + PlayerInventoryHolder enderChestHolder = new PlayerInventoryHolder(loadPlayer); + player.openInventory(enderChestHolder.getInventory()); + return true; + }*/ + return false; + } + +} diff --git a/NMS/V1_21_6/src/main/java/fr/maxlego08/essentials/nms/v1_21_6/WayPointPacket.java b/NMS/V1_21_6/src/main/java/fr/maxlego08/essentials/nms/v1_21_6/WayPointPacket.java new file mode 100644 index 00000000..c5ea01b2 --- /dev/null +++ b/NMS/V1_21_6/src/main/java/fr/maxlego08/essentials/nms/v1_21_6/WayPointPacket.java @@ -0,0 +1,91 @@ +package fr.maxlego08.essentials.nms.v1_21_6; + +import fr.maxlego08.essentials.api.waypoint.WayPointHelper; +import fr.maxlego08.essentials.api.waypoint.WayPointIcon; +import net.minecraft.core.BlockPos; +import net.minecraft.network.protocol.Packet; +import net.minecraft.network.protocol.game.ClientboundTrackedWaypointPacket; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.waypoints.Waypoint; +import net.minecraft.world.waypoints.WaypointStyleAssets; +import org.bukkit.Chunk; +import org.bukkit.Location; +import org.bukkit.craftbukkit.entity.CraftPlayer; +import org.bukkit.entity.Player; + +import java.util.Optional; +import java.util.UUID; + +public class WayPointPacket implements WayPointHelper { + + @Override + public void addWayPoint(Player player, UUID uniqueId, Location location, WayPointIcon wayPointIcon) { + + var icon = toIcon(wayPointIcon); + var blockPos = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + var packet = ClientboundTrackedWaypointPacket.addWaypointPosition(uniqueId, icon, blockPos); + + sendPacket(player, packet); + } + + @Override + public void updateWayPointPosition(Player player, UUID uniqueId, Location location, WayPointIcon wayPointIcon) { + + var icon = toIcon(wayPointIcon); + var blockPos = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + var packet = ClientboundTrackedWaypointPacket.updateWaypointPosition(uniqueId, icon, blockPos); + + sendPacket(player, packet); + } + + @Override + public void addWayPoint(Player player, UUID uniqueId, Chunk chunk, WayPointIcon wayPointIcon) { + + var icon = toIcon(wayPointIcon); + var chunkPos = new ChunkPos(chunk.getX(), chunk.getZ()); + var packet = ClientboundTrackedWaypointPacket.addWaypointChunk(uniqueId, icon, chunkPos); + + sendPacket(player, packet); + } + + @Override + public void updateWayPointPosition(Player player, UUID uniqueId, Chunk chunk, WayPointIcon wayPointIcon) { + + var icon = toIcon(wayPointIcon); + var chunkPos = new ChunkPos(chunk.getX(), chunk.getZ()); + var packet = ClientboundTrackedWaypointPacket.updateWaypointChunk(uniqueId, icon, chunkPos); + + sendPacket(player, packet); + } + + @Override + public void removeWayPoint(Player player, UUID uniqueId) { + + var packet = ClientboundTrackedWaypointPacket.removeWaypoint(uniqueId); + sendPacket(player, packet); + } + + private void sendPacket(Player player, Packet packet) { + ((CraftPlayer) player).getHandle().connection.send(packet); + } + + /** + * Converts a {@link WayPointIcon} to a {@link Waypoint.Icon}. + *

+ * If the given {@link WayPointIcon} has a texture, then the style of the resulting icon will be set to the + * death waypoint style. Otherwise, the style will be left unchanged. + *

+ * The color of the resulting icon will be set to the color of the given {@link WayPointIcon}. + * + * @param wayPointIcon the icon to convert + * @return the converted icon + */ + private Waypoint.Icon toIcon(WayPointIcon wayPointIcon) { + var icon = new Waypoint.Icon(); + if (wayPointIcon.texture() != null) { + icon.style = WaypointStyleAssets.createId(wayPointIcon.texture()); + } + icon.color = Optional.of(wayPointIcon.color().getRGB() & 0xFFFFFF); + return icon; + } +} diff --git a/NMS/V1_21_6/src/main/java/fr/maxlego08/essentials/nms/v1_21_6/enderchest/CraftPlayerManager.java b/NMS/V1_21_6/src/main/java/fr/maxlego08/essentials/nms/v1_21_6/enderchest/CraftPlayerManager.java new file mode 100644 index 00000000..5b21ddec --- /dev/null +++ b/NMS/V1_21_6/src/main/java/fr/maxlego08/essentials/nms/v1_21_6/enderchest/CraftPlayerManager.java @@ -0,0 +1,24 @@ +package fr.maxlego08.essentials.nms.v1_21_6.enderchest; + +import org.apache.commons.lang3.NotImplementedException; +import org.bukkit.OfflinePlayer; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * Based on: OpenInv + */ +public class CraftPlayerManager implements fr.maxlego08.essentials.api.nms.PlayerManager { + + + @Override + public @Nullable Player loadPlayer(@NotNull OfflinePlayer offline) { + throw new NotImplementedException(); + } + + @Override + public @NotNull Player inject(@NotNull Player player) { + throw new NotImplementedException(); + } +} diff --git a/NMS/V1_21_7/build.gradle.kts b/NMS/V1_21_7/build.gradle.kts new file mode 100644 index 00000000..b1e206df --- /dev/null +++ b/NMS/V1_21_7/build.gradle.kts @@ -0,0 +1,20 @@ +plugins { + id("io.papermc.paperweight.userdev") +} + +group "NMS:V1_21_7" + +dependencies { + compileOnly(project(":API")) + paperweight.paperDevBundle("1.21.7-R0.1-SNAPSHOT") +} + +paperweight.reobfArtifactConfiguration = io.papermc.paperweight.userdev.ReobfArtifactConfiguration.REOBF_PRODUCTION + +java { + toolchain.languageVersion = JavaLanguageVersion.of(21) +} + +tasks.assemble { + dependsOn(tasks.reobfJar) +} diff --git a/NMS/V1_21_7/src/main/java/fr/maxlego08/essentials/nms/v1_21_7/CraftHologram.java b/NMS/V1_21_7/src/main/java/fr/maxlego08/essentials/nms/v1_21_7/CraftHologram.java new file mode 100644 index 00000000..1ac17d53 --- /dev/null +++ b/NMS/V1_21_7/src/main/java/fr/maxlego08/essentials/nms/v1_21_7/CraftHologram.java @@ -0,0 +1,163 @@ +package fr.maxlego08.essentials.nms.v1_21_7; + +import com.mojang.math.Transformation; +import fr.maxlego08.essentials.api.EssentialsPlugin; +import fr.maxlego08.essentials.api.hologram.Hologram; +import fr.maxlego08.essentials.api.hologram.HologramType; +import fr.maxlego08.essentials.api.hologram.configuration.BlockHologramConfiguration; +import fr.maxlego08.essentials.api.hologram.configuration.HologramConfiguration; +import fr.maxlego08.essentials.api.hologram.configuration.ItemHologramConfiguration; +import fr.maxlego08.essentials.api.hologram.configuration.TextHologramConfiguration; +import fr.maxlego08.essentials.api.utils.ReflectionUtils; +import fr.maxlego08.essentials.api.utils.SafeLocation; +import io.papermc.paper.adventure.PaperAdventure; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.network.protocol.Packet; +import net.minecraft.network.protocol.game.ClientboundAddEntityPacket; +import net.minecraft.network.protocol.game.ClientboundRemoveEntitiesPacket; +import net.minecraft.network.protocol.game.ClientboundSetEntityDataPacket; +import net.minecraft.network.protocol.game.ClientboundTeleportEntityPacket; +import net.minecraft.network.syncher.EntityDataAccessor; +import net.minecraft.network.syncher.SynchedEntityData; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.level.ServerEntity; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.util.Brightness; +import net.minecraft.world.entity.Display; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.PositionMoveRotation; +import net.minecraft.world.item.ItemDisplayContext; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.Block; +import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.craftbukkit.entity.CraftPlayer; +import org.bukkit.entity.Player; +import org.joml.Quaternionf; + +import java.util.ArrayList; +import java.util.Set; + +public class CraftHologram extends Hologram { + + private Display display = null; + + public CraftHologram(EssentialsPlugin plugin, HologramType hologramType, HologramConfiguration configuration, String fileName, String name, SafeLocation location) { + super(plugin, hologramType, name, fileName, location, configuration); + } + + @Override + public void create(Player player) { + ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle(); + ServerEntity serverEntity = new ServerEntity(serverPlayer.level(), display, 0, false, packet -> { + }, (a, b) -> { + }, Set.of()); + send(player, new ClientboundAddEntityPacket(display, serverEntity)); + + this.update(player); + } + + @Override + public void delete(Player player) { + this.send(player, new ClientboundRemoveEntitiesPacket(display.getId())); + } + + @Override + public void update(Player player) { + + send(player, new ClientboundTeleportEntityPacket(display.getId(), PositionMoveRotation.of(display), Set.of(), display.onGround)); + + if (display instanceof Display.TextDisplay textDisplay) { + textDisplay.setText(PaperAdventure.asVanilla(getComponentText(player))); + } + + final var values = new ArrayList>(); + for (final var item : ((SynchedEntityData.DataItem[]) ReflectionUtils.getValue(display.getEntityData(), "itemsById"))) { + values.add(item.value()); + } + send(player, new ClientboundSetEntityDataPacket(display.getId(), values)); + } + + @Override + public void create() { + ServerLevel serverLevel = ((CraftWorld) location.getLocation().getWorld()).getHandle(); + switch (hologramType) { + case BLOCK -> this.display = new Display.BlockDisplay(EntityType.BLOCK_DISPLAY, serverLevel); + case ITEM -> this.display = new Display.ItemDisplay(EntityType.ITEM_DISPLAY, serverLevel); + case TEXT -> this.display = new Display.TextDisplay(EntityType.TEXT_DISPLAY, serverLevel); + } + + display.getEntityData().set((EntityDataAccessor) ReflectionUtils.getStaticValue(Display.class, "DATA_TRANSFORMATION_INTERPOLATION_DURATION_ID"), 1); // Transformation duration + display.getEntityData().set((EntityDataAccessor) ReflectionUtils.getStaticValue(Display.class, "DATA_TRANSFORMATION_INTERPOLATION_START_DELTA_TICKS_ID"), 0); // Interpolation start + + this.updateLocation(); + this.update(); + } + + @Override + public void updateLocation() { + display.setPosRaw(location.getX(), location.getY(), location.getZ()); + display.setYRot(location.getYaw()); + display.setXRot(location.getPitch()); + } + + @Override + public void update() { + + display.setBillboardConstraints(switch (this.configuration.getBillboard()) { + case FIXED -> Display.BillboardConstraints.FIXED; + case VERTICAL -> Display.BillboardConstraints.VERTICAL; + case HORIZONTAL -> Display.BillboardConstraints.HORIZONTAL; + case CENTER -> Display.BillboardConstraints.CENTER; + }); + + if (display instanceof Display.TextDisplay textDisplay && configuration instanceof TextHologramConfiguration textHologramConfiguration) { + + display.getEntityData().set((EntityDataAccessor) ReflectionUtils.getStaticValue(Display.TextDisplay.class, "DATA_LINE_WIDTH_ID"), Hologram.LINE_WIDTH); + + var backgroundColor = (EntityDataAccessor) ReflectionUtils.getStaticValue(Display.TextDisplay.class, "DATA_BACKGROUND_COLOR_ID"); + var background = textHologramConfiguration.getBackground(); + int backgroundValue = (background == null) ? Display.TextDisplay.INITIAL_BACKGROUND : (background == Hologram.TRANSPARENT) ? 0 : background.value() | 0xC8000000; + display.getEntityData().set(backgroundColor, backgroundValue); + + byte flags = textDisplay.getFlags(); + flags = (byte) (textHologramConfiguration.isTextShadow() ? (flags | Display.TextDisplay.FLAG_SHADOW) : (flags & ~Display.TextDisplay.FLAG_SHADOW)); + flags = (byte) (textHologramConfiguration.getTextAlignment() == org.bukkit.entity.TextDisplay.TextAlignment.LEFT ? (flags | Display.TextDisplay.FLAG_ALIGN_LEFT) : (flags & ~Display.TextDisplay.FLAG_ALIGN_LEFT)); + flags = (byte) (textHologramConfiguration.isSeeThrough() ? (flags | Display.TextDisplay.FLAG_SEE_THROUGH) : (flags & ~Display.TextDisplay.FLAG_SEE_THROUGH)); + flags = (byte) (textHologramConfiguration.getTextAlignment() == org.bukkit.entity.TextDisplay.TextAlignment.RIGHT ? (flags | Display.TextDisplay.FLAG_ALIGN_RIGHT) : (flags & ~Display.TextDisplay.FLAG_ALIGN_RIGHT)); + textDisplay.setFlags(flags); + } else if (display instanceof Display.ItemDisplay itemDisplay && configuration instanceof ItemHologramConfiguration itemHologramConfiguration) { + + var context = switch (itemHologramConfiguration.getItemDisplayTransform()) { + case THIRDPERSON_LEFTHAND -> ItemDisplayContext.THIRD_PERSON_LEFT_HAND; + case THIRDPERSON_RIGHTHAND -> ItemDisplayContext.THIRD_PERSON_RIGHT_HAND; + case FIRSTPERSON_LEFTHAND -> ItemDisplayContext.FIRST_PERSON_LEFT_HAND; + case FIRSTPERSON_RIGHTHAND -> ItemDisplayContext.FIRST_PERSON_RIGHT_HAND; + default -> ItemDisplayContext.valueOf(itemHologramConfiguration.getItemDisplayTransform().name()); + }; + itemDisplay.setItemTransform(context); + itemDisplay.setItemStack(ItemStack.fromBukkitCopy(itemHologramConfiguration.getItemStack())); + } else if (display instanceof Display.BlockDisplay blockDisplay && configuration instanceof BlockHologramConfiguration blockData) { + + var optional = BuiltInRegistries.BLOCK.get(ResourceLocation.parse(blockData.getMaterial().name().toLowerCase())); + if (optional.isPresent()) { + Block block = optional.get().value(); + blockDisplay.setBlockState(block.defaultBlockState()); + } + } + + if (this.configuration.getBrightness() != null) { + display.setBrightnessOverride(new Brightness(this.configuration.getBrightness().getBlockLight(), this.configuration.getBrightness().getSkyLight())); + } + + display.setTransformation(new Transformation(this.configuration.getTranslation(), new Quaternionf(), this.configuration.getScale(), new Quaternionf())); + + display.setShadowRadius(this.configuration.getShadowRadius()); + display.setShadowStrength(this.configuration.getShadowStrength()); + } + + private void send(Player player, Packet packet) { + ((CraftPlayer) player).getHandle().connection.send(packet); + } + +} diff --git a/NMS/V1_21_7/src/main/java/fr/maxlego08/essentials/nms/v1_21_7/PlayerUtils.java b/NMS/V1_21_7/src/main/java/fr/maxlego08/essentials/nms/v1_21_7/PlayerUtils.java new file mode 100644 index 00000000..8f79b1bf --- /dev/null +++ b/NMS/V1_21_7/src/main/java/fr/maxlego08/essentials/nms/v1_21_7/PlayerUtils.java @@ -0,0 +1,43 @@ +package fr.maxlego08.essentials.nms.v1_21_7; + +import fr.maxlego08.essentials.api.EssentialsPlugin; +import fr.maxlego08.essentials.api.nms.PlayerUtil; +import org.bukkit.OfflinePlayer; +import org.bukkit.entity.Player; + +public class PlayerUtils implements PlayerUtil { + + private final EssentialsPlugin plugin; + + public PlayerUtils(EssentialsPlugin plugin) { + this.plugin = plugin; + } + + @Override + public boolean openEnderChest(Player player, OfflinePlayer offlinePlayer) { + + /*CraftPlayerManager craftPlayerManager = new CraftPlayerManager(plugin.getLogger()); + var loadPlayer = craftPlayerManager.loadPlayer(offlinePlayer); + + if (loadPlayer != null) { + EnderChestHolder enderChestHolder = new EnderChestHolder(loadPlayer); + player.openInventory(enderChestHolder.getInventory()); + return true; + }*/ + return false; + } + + @Override + public boolean openPlayerInventory(Player player, OfflinePlayer offlinePlayer) { + /*CraftPlayerManager craftPlayerManager = new CraftPlayerManager(plugin.getLogger()); + var loadPlayer = craftPlayerManager.loadPlayer(offlinePlayer); + + if (loadPlayer != null) { + PlayerInventoryHolder enderChestHolder = new PlayerInventoryHolder(loadPlayer); + player.openInventory(enderChestHolder.getInventory()); + return true; + }*/ + return false; + } + +} diff --git a/NMS/V1_21_7/src/main/java/fr/maxlego08/essentials/nms/v1_21_7/WayPointPacket.java b/NMS/V1_21_7/src/main/java/fr/maxlego08/essentials/nms/v1_21_7/WayPointPacket.java new file mode 100644 index 00000000..195f8513 --- /dev/null +++ b/NMS/V1_21_7/src/main/java/fr/maxlego08/essentials/nms/v1_21_7/WayPointPacket.java @@ -0,0 +1,91 @@ +package fr.maxlego08.essentials.nms.v1_21_7; + +import fr.maxlego08.essentials.api.waypoint.WayPointHelper; +import fr.maxlego08.essentials.api.waypoint.WayPointIcon; +import net.minecraft.core.BlockPos; +import net.minecraft.network.protocol.Packet; +import net.minecraft.network.protocol.game.ClientboundTrackedWaypointPacket; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.waypoints.Waypoint; +import net.minecraft.world.waypoints.WaypointStyleAssets; +import org.bukkit.Chunk; +import org.bukkit.Location; +import org.bukkit.craftbukkit.entity.CraftPlayer; +import org.bukkit.entity.Player; + +import java.util.Optional; +import java.util.UUID; + +public class WayPointPacket implements WayPointHelper { + + @Override + public void addWayPoint(Player player, UUID uniqueId, Location location, WayPointIcon wayPointIcon) { + + var icon = toIcon(wayPointIcon); + var blockPos = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + var packet = ClientboundTrackedWaypointPacket.addWaypointPosition(uniqueId, icon, blockPos); + + sendPacket(player, packet); + } + + @Override + public void updateWayPointPosition(Player player, UUID uniqueId, Location location, WayPointIcon wayPointIcon) { + + var icon = toIcon(wayPointIcon); + var blockPos = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + var packet = ClientboundTrackedWaypointPacket.updateWaypointPosition(uniqueId, icon, blockPos); + + sendPacket(player, packet); + } + + @Override + public void addWayPoint(Player player, UUID uniqueId, Chunk chunk, WayPointIcon wayPointIcon) { + + var icon = toIcon(wayPointIcon); + var chunkPos = new ChunkPos(chunk.getX(), chunk.getZ()); + var packet = ClientboundTrackedWaypointPacket.addWaypointChunk(uniqueId, icon, chunkPos); + + sendPacket(player, packet); + } + + @Override + public void updateWayPointPosition(Player player, UUID uniqueId, Chunk chunk, WayPointIcon wayPointIcon) { + + var icon = toIcon(wayPointIcon); + var chunkPos = new ChunkPos(chunk.getX(), chunk.getZ()); + var packet = ClientboundTrackedWaypointPacket.updateWaypointChunk(uniqueId, icon, chunkPos); + + sendPacket(player, packet); + } + + @Override + public void removeWayPoint(Player player, UUID uniqueId) { + + var packet = ClientboundTrackedWaypointPacket.removeWaypoint(uniqueId); + sendPacket(player, packet); + } + + private void sendPacket(Player player, Packet packet) { + ((CraftPlayer) player).getHandle().connection.send(packet); + } + + /** + * Converts a {@link WayPointIcon} to a {@link Waypoint.Icon}. + *

+ * If the given {@link WayPointIcon} has a texture, then the style of the resulting icon will be set to the + * death waypoint style. Otherwise, the style will be left unchanged. + *

+ * The color of the resulting icon will be set to the color of the given {@link WayPointIcon}. + * + * @param wayPointIcon the icon to convert + * @return the converted icon + */ + private Waypoint.Icon toIcon(WayPointIcon wayPointIcon) { + var icon = new Waypoint.Icon(); + if (wayPointIcon.texture() != null) { + icon.style = WaypointStyleAssets.createId(wayPointIcon.texture()); + } + icon.color = Optional.of(wayPointIcon.color().getRGB() & 0xFFFFFF); + return icon; + } +} diff --git a/NMS/V1_21_7/src/main/java/fr/maxlego08/essentials/nms/v1_21_7/enderchest/CraftPlayerManager.java b/NMS/V1_21_7/src/main/java/fr/maxlego08/essentials/nms/v1_21_7/enderchest/CraftPlayerManager.java new file mode 100644 index 00000000..fd7ee264 --- /dev/null +++ b/NMS/V1_21_7/src/main/java/fr/maxlego08/essentials/nms/v1_21_7/enderchest/CraftPlayerManager.java @@ -0,0 +1,24 @@ +package fr.maxlego08.essentials.nms.v1_21_7.enderchest; + +import org.apache.commons.lang3.NotImplementedException; +import org.bukkit.OfflinePlayer; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * Based on: OpenInv + */ +public class CraftPlayerManager implements fr.maxlego08.essentials.api.nms.PlayerManager { + + + @Override + public @Nullable Player loadPlayer(@NotNull OfflinePlayer offline) { + throw new NotImplementedException(); + } + + @Override + public @NotNull Player inject(@NotNull Player player) { + throw new NotImplementedException(); + } +} diff --git a/build.gradle.kts b/build.gradle.kts index 647afff0..7dc18363 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -77,6 +77,9 @@ dependencies { api(project(":NMS:V1_21_1", configuration = "reobf")) api(project(":NMS:V1_21_3", configuration = "reobf")) api(project(":NMS:V1_21_4", configuration = "reobf")) + api(project(":NMS:V1_21_5", configuration = "reobf")) + api(project(":NMS:V1_21_6", configuration = "reobf")) + api(project(":NMS:V1_21_7", configuration = "reobf")) api(project(":NMS:V1_21_8", configuration = "reobf")) rootProject.subprojects.filter { it.path.startsWith(":Hooks:") }.forEach { subproject -> @@ -116,4 +119,4 @@ tasks { expand("version" to project.version) } } -} \ No newline at end of file +} diff --git a/settings.gradle.kts b/settings.gradle.kts index ad7e41bb..ab9e62f4 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -31,5 +31,8 @@ include("NMS:V1_21") include("NMS:V1_21_1") include("NMS:V1_21_3") include("NMS:V1_21_4") +include("NMS:V1_21_5") +include("NMS:V1_21_6") +include("NMS:V1_21_7") include("NMS:V1_21_8")