diff --git a/build.gradle.kts b/build.gradle.kts index b56bad9..a4022bd 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -11,7 +11,7 @@ plugins { } group = "me.lojosho" -version = "0.6.5${getGitCommitHash()}" +version = "0.7.0${getGitCommitHash()}" allprojects { apply(plugin = "java") @@ -144,11 +144,11 @@ tasks { runServer { dependsOn(shadowJar) dependsOn(jar) - minecraftVersion("1.21.5") + minecraftVersion("1.21.6") downloadPlugins { hangar("PlaceholderAPI", "2.11.6") - url("https://download.luckperms.net/1567/bukkit/loader/LuckPerms-Bukkit-5.4.150.jar") + url("https://download.luckperms.net/1593/bukkit/loader/LuckPerms-Bukkit-5.5.8.jar") } } diff --git a/common/src/main/java/me/lojosho/hibiscuscommons/HibiscusCommonsPlugin.java b/common/src/main/java/me/lojosho/hibiscuscommons/HibiscusCommonsPlugin.java index 6713406..c233775 100644 --- a/common/src/main/java/me/lojosho/hibiscuscommons/HibiscusCommonsPlugin.java +++ b/common/src/main/java/me/lojosho/hibiscuscommons/HibiscusCommonsPlugin.java @@ -2,6 +2,7 @@ package me.lojosho.hibiscuscommons; import lombok.Getter; import me.lojosho.hibiscuscommons.hooks.Hooks; +import me.lojosho.hibiscuscommons.listener.PlayerConnectionEvent; import me.lojosho.hibiscuscommons.nms.NMSHandlers; import me.lojosho.hibiscuscommons.util.ServerUtils; import org.jetbrains.annotations.ApiStatus; @@ -42,6 +43,8 @@ public final class HibiscusCommonsPlugin extends HibiscusPlugin { return; } + getServer().getPluginManager().registerEvents(new PlayerConnectionEvent(), this); + // Plugin startup logic Hooks.setup(); } diff --git a/common/src/main/java/me/lojosho/hibiscuscommons/HibiscusPlugin.java b/common/src/main/java/me/lojosho/hibiscuscommons/HibiscusPlugin.java index f56c3cc..3d11590 100644 --- a/common/src/main/java/me/lojosho/hibiscuscommons/HibiscusPlugin.java +++ b/common/src/main/java/me/lojosho/hibiscuscommons/HibiscusPlugin.java @@ -3,6 +3,10 @@ package me.lojosho.hibiscuscommons; import com.jeff_media.updatechecker.UpdateCheckSource; import com.jeff_media.updatechecker.UpdateChecker; import lombok.Getter; +import lombok.Setter; +import me.lojosho.hibiscuscommons.packets.DefaultPacketInterface; +import me.lojosho.hibiscuscommons.packets.PacketInterface; +import me.lojosho.hibiscuscommons.plugins.SubPlugins; import org.bstats.bukkit.Metrics; import org.bukkit.Bukkit; import org.bukkit.plugin.Plugin; @@ -20,6 +24,8 @@ public abstract class HibiscusPlugin extends JavaPlugin { private boolean onLatestVersion = true; @Getter private boolean disabled = false; + @Getter @Setter + private PacketInterface packetInterface = new DefaultPacketInterface(); protected HibiscusPlugin() { this(-1); @@ -47,6 +53,8 @@ public abstract class HibiscusPlugin extends JavaPlugin { return; } + SubPlugins.addSubPlugin(this); + if (bstats > 0) { Metrics metrics = new Metrics(this, bstats); } @@ -88,6 +96,7 @@ public abstract class HibiscusPlugin extends JavaPlugin { @Override public final void onDisable() { disabled = true; + SubPlugins.removeSubPlugin(this); onEnd(); } diff --git a/common/src/main/java/me/lojosho/hibiscuscommons/listener/PlayerConnectionEvent.java b/common/src/main/java/me/lojosho/hibiscuscommons/listener/PlayerConnectionEvent.java new file mode 100644 index 0000000..cdc5636 --- /dev/null +++ b/common/src/main/java/me/lojosho/hibiscuscommons/listener/PlayerConnectionEvent.java @@ -0,0 +1,15 @@ +package me.lojosho.hibiscuscommons.listener; + +import me.lojosho.hibiscuscommons.nms.NMSHandlers; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerJoinEvent; + +public class PlayerConnectionEvent implements Listener { + + @EventHandler(ignoreCancelled = false, priority = EventPriority.LOW) + public void onPlayerJoin(PlayerJoinEvent event) { + NMSHandlers.getHandler().getUtilHandler().handleChannelOpen(event.getPlayer()); + } +} diff --git a/common/src/main/java/me/lojosho/hibiscuscommons/nms/NMSUtils.java b/common/src/main/java/me/lojosho/hibiscuscommons/nms/NMSUtils.java index 87ef60e..d21a566 100644 --- a/common/src/main/java/me/lojosho/hibiscuscommons/nms/NMSUtils.java +++ b/common/src/main/java/me/lojosho/hibiscuscommons/nms/NMSUtils.java @@ -2,6 +2,7 @@ package me.lojosho.hibiscuscommons.nms; import org.bukkit.Color; import org.bukkit.entity.Entity; +import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.NotNull; @@ -18,4 +19,8 @@ public interface NMSUtils { ItemStack setColor(@NotNull ItemStack itemStack, Color color); + default void handleChannelOpen(@NotNull Player player) { + + } + } diff --git a/common/src/main/java/me/lojosho/hibiscuscommons/packets/DefaultPacketInterface.java b/common/src/main/java/me/lojosho/hibiscuscommons/packets/DefaultPacketInterface.java new file mode 100644 index 0000000..a63f9b2 --- /dev/null +++ b/common/src/main/java/me/lojosho/hibiscuscommons/packets/DefaultPacketInterface.java @@ -0,0 +1,5 @@ +package me.lojosho.hibiscuscommons.packets; + +public class DefaultPacketInterface implements PacketInterface { + // Overrides nothing +} diff --git a/common/src/main/java/me/lojosho/hibiscuscommons/packets/PacketAction.java b/common/src/main/java/me/lojosho/hibiscuscommons/packets/PacketAction.java new file mode 100644 index 0000000..3ec1098 --- /dev/null +++ b/common/src/main/java/me/lojosho/hibiscuscommons/packets/PacketAction.java @@ -0,0 +1,7 @@ +package me.lojosho.hibiscuscommons.packets; + +public enum PacketAction { + NOTHING, + CHANGED, + CANCELLED, +} diff --git a/common/src/main/java/me/lojosho/hibiscuscommons/packets/PacketInterface.java b/common/src/main/java/me/lojosho/hibiscuscommons/packets/PacketInterface.java new file mode 100644 index 0000000..df16073 --- /dev/null +++ b/common/src/main/java/me/lojosho/hibiscuscommons/packets/PacketInterface.java @@ -0,0 +1,48 @@ +package me.lojosho.hibiscuscommons.packets; + +import org.bukkit.entity.Player; +import org.bukkit.inventory.EquipmentSlot; +import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; + +import java.util.List; +import java.util.Map; + +public interface PacketInterface { + + default PacketAction writeContainerContent(@NotNull Player player, Integer windowId, @NotNull List slotData) { + return PacketAction.NOTHING; + } + + default PacketAction writeSlotContent(@NotNull Player player, Integer windowId, Integer slot, @NotNull ItemStack itemStack) { + return PacketAction.NOTHING; + } + + default PacketAction writeEquipmentContent(@NotNull Player player, @NotNull Map armor) { + return PacketAction.NOTHING; + } + + default PacketAction writePassengerContent(@NotNull Player player, Integer owner, List passengers) { + return PacketAction.NOTHING; + } + + default PacketAction readInventoryClick(@NotNull Player player, Integer clickType, Integer slotNumber) { + return PacketAction.NOTHING; + // Override + } + + default PacketAction readPlayerAction(@NotNull Player player, Integer actionType) { + return PacketAction.NOTHING; + // Override + } + + default PacketAction readPlayerArm(@NotNull Player player) { + return PacketAction.NOTHING; + // Override + } + + default PacketAction readEntityHandle(@NotNull Player player) { + return PacketAction.NOTHING; + // Override + } +} diff --git a/common/src/main/java/me/lojosho/hibiscuscommons/plugins/SubPlugins.java b/common/src/main/java/me/lojosho/hibiscuscommons/plugins/SubPlugins.java new file mode 100644 index 0000000..a4ca256 --- /dev/null +++ b/common/src/main/java/me/lojosho/hibiscuscommons/plugins/SubPlugins.java @@ -0,0 +1,29 @@ +package me.lojosho.hibiscuscommons.plugins; + +import com.google.common.collect.ImmutableList; +import me.lojosho.hibiscuscommons.HibiscusPlugin; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.List; + +public class SubPlugins { + + private static final List SUB_PLUGINS = new ArrayList<>(); + + @NotNull + public static List getSubPlugins() { + return ImmutableList.copyOf(SUB_PLUGINS); + } + + @ApiStatus.Internal + public static void addSubPlugin(@NotNull HibiscusPlugin plugin) { + SUB_PLUGINS.add(plugin); + } + + @ApiStatus.Internal + public static void removeSubPlugin(@NotNull HibiscusPlugin plugin) { + SUB_PLUGINS.remove(plugin); + } +} 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 index 0043389..124c5a5 100644 --- 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 @@ -13,5 +13,4 @@ public class NMSCommon { ServerPlayerConnection connection = serverPlayer.connection; connection.send(packet); } - } diff --git a/v1_21_R5/src/main/java/me/lojosho/hibiscuscommons/nms/v1_21_R5/NMSPacketChannel.java b/v1_21_R5/src/main/java/me/lojosho/hibiscuscommons/nms/v1_21_R5/NMSPacketChannel.java new file mode 100644 index 0000000..0282afa --- /dev/null +++ b/v1_21_R5/src/main/java/me/lojosho/hibiscuscommons/nms/v1_21_R5/NMSPacketChannel.java @@ -0,0 +1,223 @@ +package me.lojosho.hibiscuscommons.nms.v1_21_R5; + +import com.mojang.datafixers.util.Pair; +import io.netty.channel.ChannelDuplexHandler; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelPromise; +import lombok.Getter; +import me.lojosho.hibiscuscommons.nms.NMSHandlers; +import me.lojosho.hibiscuscommons.packets.PacketAction; +import me.lojosho.hibiscuscommons.plugins.SubPlugins; +import me.lojosho.hibiscuscommons.util.MessagesUtil; +import net.minecraft.core.NonNullList; +import net.minecraft.network.protocol.Packet; +import net.minecraft.network.protocol.game.*; +import net.minecraft.world.inventory.ClickType; +import net.minecraft.world.item.ItemStack; +import org.bukkit.craftbukkit.CraftEquipmentSlot; +import org.bukkit.craftbukkit.inventory.CraftItemStack; +import org.bukkit.entity.Player; +import org.bukkit.inventory.EquipmentSlot; +import org.jetbrains.annotations.NotNull; + +import java.util.*; +import java.util.concurrent.atomic.AtomicReference; +import java.util.stream.Collectors; + +public class NMSPacketChannel extends ChannelDuplexHandler { + + @Getter + private final Player player; + + public NMSPacketChannel(Player player) { + this.player = player; + } + + @Override + public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception { + if (!(msg instanceof Packet packet)) { + super.write(ctx, msg, promise); + return; + } + + switch (packet) { + case ClientboundContainerSetContentPacket setContentPacket -> msg = handleMenuChange(setContentPacket); + case ClientboundContainerSetSlotPacket setSlotPacket -> msg = handleSlotChange(setSlotPacket); + case ClientboundSetEquipmentPacket equipmentPacket -> msg = handlePlayerEquipment(equipmentPacket); + case ClientboundSetPassengersPacket passengerPacket -> msg = handlePassengerSet(passengerPacket); + default -> {} + } + + if (msg == null) return; + else super.write(ctx, msg, promise); + } + + private Packet handleMenuChange(@NotNull ClientboundContainerSetContentPacket packet) { + MessagesUtil.sendDebugMessages("Menu Initial "); + + Integer windowId = packet.containerId(); + NonNullList slotData = NonNullList.create(); + slotData.addAll(packet.items()); + + List bukkitItems = slotData.stream().map(CraftItemStack::asBukkitCopy).toList(); + + AtomicReference action = new AtomicReference<>(PacketAction.NOTHING); + SubPlugins.getSubPlugins().forEach(plugin -> { + + PacketAction pluginAction = plugin.getPacketInterface().writeContainerContent(player, windowId, bukkitItems); + if (pluginAction != PacketAction.NOTHING) action.set(PacketAction.CANCELLED); + + }); + + List nmsItems = bukkitItems.stream().map(CraftItemStack::asNMSCopy).toList(); + + if (action.get() == PacketAction.CANCELLED) return null; + if (action.get() == PacketAction.NOTHING) return packet; + return new ClientboundContainerSetContentPacket(0, packet.stateId(), nmsItems, packet.carriedItem()); + } + + private Packet handleSlotChange(@NotNull ClientboundContainerSetSlotPacket packet) { + MessagesUtil.sendDebugMessages("SetSlot Initial "); + + Integer windowId = packet.getContainerId(); + Integer slot = packet.getSlot(); + ItemStack item = packet.getItem(); + + org.bukkit.inventory.ItemStack bukkitItem = CraftItemStack.asBukkitCopy(item); + + AtomicReference action = new AtomicReference<>(PacketAction.NOTHING); + SubPlugins.getSubPlugins().forEach(plugin -> { + + PacketAction pluginAction = plugin.getPacketInterface().writeSlotContent(player, windowId, slot, bukkitItem); + if (pluginAction != PacketAction.NOTHING) action.set(PacketAction.CANCELLED); + + }); + + if (action.get() == PacketAction.CANCELLED) return null; + if (action.get() == PacketAction.NOTHING) return packet; + + final ItemStack nmsItem = CraftItemStack.asNMSCopy(bukkitItem); + + return new ClientboundContainerSetSlotPacket(0, packet.getStateId(), slot, nmsItem); + } + + private Packet handlePlayerEquipment(@NotNull ClientboundSetEquipmentPacket packet) { + final List> armor = packet.getSlots(); + final HashMap bukkitArmor = new HashMap<>(); + for (Pair piece : armor) { + EquipmentSlot slot = CraftEquipmentSlot.getSlot(piece.getFirst()); + org.bukkit.inventory.ItemStack itemStack = CraftItemStack.asBukkitCopy(piece.getSecond()); + bukkitArmor.put(slot, itemStack); + } + + AtomicReference action = new AtomicReference<>(PacketAction.NOTHING); + SubPlugins.getSubPlugins().forEach(plugin -> { + + PacketAction pluginAction = plugin.getPacketInterface().writeEquipmentContent(player, bukkitArmor); + if (pluginAction != PacketAction.NOTHING) action.set(PacketAction.CANCELLED); + + }); + + if (action.get() == PacketAction.CANCELLED) return null; + if (action.get() == PacketAction.NOTHING) return packet; + + List> newArmor = new ArrayList<>(); + for (Map.Entry entry : bukkitArmor.entrySet()) { + net.minecraft.world.entity.EquipmentSlot slot = CraftEquipmentSlot.getNMS(entry.getKey()); + ItemStack itemStack = CraftItemStack.asNMSCopy(entry.getValue()); + newArmor.add(new Pair<>(slot, itemStack)); + } + + return new ClientboundSetEquipmentPacket(packet.getEntity(), newArmor); + } + + private Packet handlePassengerSet(@NotNull ClientboundSetPassengersPacket packet) { + Integer ownerId = packet.getVehicle(); + List passengers = Arrays.stream(packet.getPassengers()).boxed().collect(Collectors.toList()); + MessagesUtil.sendDebugMessages("Mount Packet Sent - Read - EntityID: " + ownerId); + + AtomicReference action = new AtomicReference<>(PacketAction.NOTHING); + SubPlugins.getSubPlugins().forEach(plugin -> { + + PacketAction pluginAction = plugin.getPacketInterface().writePassengerContent(player, ownerId, passengers); + if (pluginAction != PacketAction.NOTHING) action.set(PacketAction.CANCELLED); + + }); + + if (action.get() == PacketAction.CANCELLED) return null; + if (action.get() == PacketAction.NOTHING) return packet; + return (Packet) NMSHandlers.getHandler().getPacketHandler().createMountPacket(ownerId, passengers.stream().mapToInt(Integer::intValue).toArray()); + } + + @Override + public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { + if (!(msg instanceof Packet packet)) { + super.channelRead(ctx, msg); + return; + } + + switch (packet) { + case ServerboundContainerClickPacket clickPacket -> msg = handleInventoryClick(clickPacket); + case ServerboundPlayerActionPacket playerActionPacket -> msg = handlePlayerAction(playerActionPacket); + case ServerboundSwingPacket swingPacket -> msg = handlePlayerArm(swingPacket); + case ServerboundUseItemOnPacket useItemOnPacket -> msg = handleEntityUse(useItemOnPacket); + default -> {} + } + + if (msg == null) return; + else super.channelRead(ctx, msg); + } + + private Packet handleInventoryClick(@NotNull ServerboundContainerClickPacket packet) { + ClickType clickType = packet.clickType(); + int slotClicked = packet.slotNum(); + + AtomicReference action = new AtomicReference<>(PacketAction.NOTHING); + SubPlugins.getSubPlugins().forEach(plugin -> { + + PacketAction pluginAction = plugin.getPacketInterface().readInventoryClick(player, clickType.id(), slotClicked); + if (pluginAction != PacketAction.NOTHING) action.set(PacketAction.CANCELLED); + + }); + if (action.get() == PacketAction.CANCELLED) return null; + return packet; + } + + private Packet handlePlayerAction(ServerboundPlayerActionPacket packet) { + ServerboundPlayerActionPacket.Action playerAction = packet.getAction(); + + AtomicReference action = new AtomicReference<>(PacketAction.NOTHING); + SubPlugins.getSubPlugins().forEach(plugin -> { + + PacketAction pluginAction = plugin.getPacketInterface().readPlayerAction(player, playerAction.ordinal()); + if (pluginAction != PacketAction.NOTHING) action.set(PacketAction.CANCELLED); + + }); + if (action.get() == PacketAction.CANCELLED) return null; + return packet; + } + + private Packet handlePlayerArm(ServerboundSwingPacket packet) { + AtomicReference action = new AtomicReference<>(PacketAction.NOTHING); + SubPlugins.getSubPlugins().forEach(plugin -> { + + PacketAction pluginAction = plugin.getPacketInterface().readPlayerArm(player); + if (pluginAction != PacketAction.NOTHING) action.set(PacketAction.CANCELLED); + + }); + if (action.get() == PacketAction.CANCELLED) return null; + return packet; + } + + private Packet handleEntityUse(ServerboundUseItemOnPacket packet) { + AtomicReference action = new AtomicReference<>(PacketAction.NOTHING); + SubPlugins.getSubPlugins().forEach(plugin -> { + + PacketAction pluginAction = plugin.getPacketInterface().readEntityHandle(player); + if (pluginAction != PacketAction.NOTHING) action.set(PacketAction.CANCELLED); + + }); + if (action.get() == PacketAction.CANCELLED) return null; + return packet; + } +} \ No newline at end of file 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 index c7bdce4..ac20859 100644 --- 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 @@ -1,12 +1,17 @@ package me.lojosho.hibiscuscommons.nms.v1_21_R5; +import io.netty.channel.Channel; +import io.netty.channel.ChannelPipeline; import net.minecraft.core.component.DataComponents; +import net.minecraft.network.Connection; 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.entity.CraftPlayer; import org.bukkit.craftbukkit.inventory.CraftItemStack; +import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -51,4 +56,16 @@ public class NMSUtils extends NMSCommon implements me.lojosho.hibiscuscommons.nm } return null; } + + @Override + public void handleChannelOpen(@NotNull Player player) { + Channel channel = ((CraftPlayer) player).getHandle().connection.connection.channel; + ChannelPipeline pipeline = channel.pipeline(); + + NMSPacketChannel channelHandler = new NMSPacketChannel(player); + for (String key : pipeline.toMap().keySet()) { + if (!(pipeline.get(key) instanceof Connection)) continue; + pipeline.addBefore(key, "hibiscus_channel_handler", channelHandler); + } + } }