9
0
mirror of https://github.com/HibiscusMC/HibiscusCommons.git synced 2025-12-19 15:09:26 +00:00

feat: move towards easily overrideable methods in sub plugins rather than each plugin needing their own channel

This commit is contained in:
LoJoSho
2025-06-26 11:52:05 -05:00
parent a693c4e6bc
commit 9f6f0f19bf
12 changed files with 364 additions and 4 deletions

View File

@@ -11,7 +11,7 @@ plugins {
} }
group = "me.lojosho" group = "me.lojosho"
version = "0.6.5${getGitCommitHash()}" version = "0.7.0${getGitCommitHash()}"
allprojects { allprojects {
apply(plugin = "java") apply(plugin = "java")
@@ -144,11 +144,11 @@ tasks {
runServer { runServer {
dependsOn(shadowJar) dependsOn(shadowJar)
dependsOn(jar) dependsOn(jar)
minecraftVersion("1.21.5") minecraftVersion("1.21.6")
downloadPlugins { downloadPlugins {
hangar("PlaceholderAPI", "2.11.6") 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")
} }
} }

View File

@@ -2,6 +2,7 @@ package me.lojosho.hibiscuscommons;
import lombok.Getter; import lombok.Getter;
import me.lojosho.hibiscuscommons.hooks.Hooks; import me.lojosho.hibiscuscommons.hooks.Hooks;
import me.lojosho.hibiscuscommons.listener.PlayerConnectionEvent;
import me.lojosho.hibiscuscommons.nms.NMSHandlers; import me.lojosho.hibiscuscommons.nms.NMSHandlers;
import me.lojosho.hibiscuscommons.util.ServerUtils; import me.lojosho.hibiscuscommons.util.ServerUtils;
import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.ApiStatus;
@@ -42,6 +43,8 @@ public final class HibiscusCommonsPlugin extends HibiscusPlugin {
return; return;
} }
getServer().getPluginManager().registerEvents(new PlayerConnectionEvent(), this);
// Plugin startup logic // Plugin startup logic
Hooks.setup(); Hooks.setup();
} }

View File

@@ -3,6 +3,10 @@ package me.lojosho.hibiscuscommons;
import com.jeff_media.updatechecker.UpdateCheckSource; import com.jeff_media.updatechecker.UpdateCheckSource;
import com.jeff_media.updatechecker.UpdateChecker; import com.jeff_media.updatechecker.UpdateChecker;
import lombok.Getter; 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.bstats.bukkit.Metrics;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.plugin.Plugin; import org.bukkit.plugin.Plugin;
@@ -20,6 +24,8 @@ public abstract class HibiscusPlugin extends JavaPlugin {
private boolean onLatestVersion = true; private boolean onLatestVersion = true;
@Getter @Getter
private boolean disabled = false; private boolean disabled = false;
@Getter @Setter
private PacketInterface packetInterface = new DefaultPacketInterface();
protected HibiscusPlugin() { protected HibiscusPlugin() {
this(-1); this(-1);
@@ -47,6 +53,8 @@ public abstract class HibiscusPlugin extends JavaPlugin {
return; return;
} }
SubPlugins.addSubPlugin(this);
if (bstats > 0) { if (bstats > 0) {
Metrics metrics = new Metrics(this, bstats); Metrics metrics = new Metrics(this, bstats);
} }
@@ -88,6 +96,7 @@ public abstract class HibiscusPlugin extends JavaPlugin {
@Override @Override
public final void onDisable() { public final void onDisable() {
disabled = true; disabled = true;
SubPlugins.removeSubPlugin(this);
onEnd(); onEnd();
} }

View File

@@ -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());
}
}

View File

@@ -2,6 +2,7 @@ package me.lojosho.hibiscuscommons.nms;
import org.bukkit.Color; import org.bukkit.Color;
import org.bukkit.entity.Entity; import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@@ -18,4 +19,8 @@ public interface NMSUtils {
ItemStack setColor(@NotNull ItemStack itemStack, Color color); ItemStack setColor(@NotNull ItemStack itemStack, Color color);
default void handleChannelOpen(@NotNull Player player) {
}
} }

View File

@@ -0,0 +1,5 @@
package me.lojosho.hibiscuscommons.packets;
public class DefaultPacketInterface implements PacketInterface {
// Overrides nothing
}

View File

@@ -0,0 +1,7 @@
package me.lojosho.hibiscuscommons.packets;
public enum PacketAction {
NOTHING,
CHANGED,
CANCELLED,
}

View File

@@ -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<ItemStack> 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<EquipmentSlot, ItemStack> armor) {
return PacketAction.NOTHING;
}
default PacketAction writePassengerContent(@NotNull Player player, Integer owner, List<Integer> 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
}
}

View File

@@ -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<HibiscusPlugin> SUB_PLUGINS = new ArrayList<>();
@NotNull
public static List<HibiscusPlugin> 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);
}
}

View File

@@ -13,5 +13,4 @@ public class NMSCommon {
ServerPlayerConnection connection = serverPlayer.connection; ServerPlayerConnection connection = serverPlayer.connection;
connection.send(packet); connection.send(packet);
} }
} }

View File

@@ -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<ItemStack> slotData = NonNullList.create();
slotData.addAll(packet.items());
List<org.bukkit.inventory.ItemStack> bukkitItems = slotData.stream().map(CraftItemStack::asBukkitCopy).toList();
AtomicReference<PacketAction> 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<ItemStack> 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<PacketAction> 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<Pair<net.minecraft.world.entity.EquipmentSlot, ItemStack>> armor = packet.getSlots();
final HashMap<EquipmentSlot, org.bukkit.inventory.ItemStack> bukkitArmor = new HashMap<>();
for (Pair<net.minecraft.world.entity.EquipmentSlot, ItemStack> piece : armor) {
EquipmentSlot slot = CraftEquipmentSlot.getSlot(piece.getFirst());
org.bukkit.inventory.ItemStack itemStack = CraftItemStack.asBukkitCopy(piece.getSecond());
bukkitArmor.put(slot, itemStack);
}
AtomicReference<PacketAction> 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<Pair<net.minecraft.world.entity.EquipmentSlot, ItemStack>> newArmor = new ArrayList<>();
for (Map.Entry<EquipmentSlot, org.bukkit.inventory.ItemStack> 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<Integer> passengers = Arrays.stream(packet.getPassengers()).boxed().collect(Collectors.toList());
MessagesUtil.sendDebugMessages("Mount Packet Sent - Read - EntityID: " + ownerId);
AtomicReference<PacketAction> 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<PacketAction> 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<PacketAction> 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<PacketAction> 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<PacketAction> 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;
}
}

View File

@@ -1,12 +1,17 @@
package me.lojosho.hibiscuscommons.nms.v1_21_R5; 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.core.component.DataComponents;
import net.minecraft.network.Connection;
import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.item.component.DyedItemColor; import net.minecraft.world.item.component.DyedItemColor;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Color; import org.bukkit.Color;
import org.bukkit.craftbukkit.CraftServer; import org.bukkit.craftbukkit.CraftServer;
import org.bukkit.craftbukkit.entity.CraftPlayer;
import org.bukkit.craftbukkit.inventory.CraftItemStack; import org.bukkit.craftbukkit.inventory.CraftItemStack;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
@@ -51,4 +56,16 @@ public class NMSUtils extends NMSCommon implements me.lojosho.hibiscuscommons.nm
} }
return null; 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);
}
}
} }