diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/BukkitNetworkManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/BukkitNetworkManager.java index 8bb11eb90..0763f2f44 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/BukkitNetworkManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/BukkitNetworkManager.java @@ -127,6 +127,7 @@ public class BukkitNetworkManager implements NetworkManager, Listener { registerNMSPacketConsumer(PacketConsumers.SOUND, Reflections.clazz$ClientboundSoundPacket); registerNMSPacketConsumer(PacketConsumers.RENAME_ITEM, Reflections.clazz$ServerboundRenameItemPacket); registerNMSPacketConsumer(PacketConsumers.SIGN_UPDATE, Reflections.clazz$ServerboundSignUpdatePacket); + registerNMSPacketConsumer(PacketConsumers.EDIT_BOOK, Reflections.clazz$ServerboundEditBookPacket); registerByteBufPacketConsumer(PacketConsumers.SECTION_BLOCK_UPDATE, this.packetIds.clientboundSectionBlocksUpdatePacket()); registerByteBufPacketConsumer(PacketConsumers.BLOCK_UPDATE, this.packetIds.clientboundBlockUpdatePacket()); registerByteBufPacketConsumer(PacketConsumers.LEVEL_PARTICLE, this.packetIds.clientboundLevelParticlesPacket()); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketConsumers.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketConsumers.java index 0ac89fa5a..cef65288e 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketConsumers.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketConsumers.java @@ -34,6 +34,8 @@ import org.bukkit.util.RayTraceResult; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.*; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicReference; import java.util.function.BiConsumer; import java.util.function.Consumer; @@ -704,6 +706,52 @@ public class PacketConsumers { } }; + // we handle it on packet level to prevent it from being captured by plugins + @SuppressWarnings("unchecked") + public static final TriConsumer EDIT_BOOK = (user, event, packet) -> { + try { + List pages = (List) Reflections.field$ServerboundEditBookPacket$pages.get(packet); + Optional title = (Optional) Reflections.field$ServerboundEditBookPacket$title.get(packet); + ImageManager manager = CraftEngine.instance().imageManager(); + if (!manager.isDefaultFontInUse()) return; + + AtomicBoolean hasChange = new AtomicBoolean(false); + List newPages = new ArrayList<>(pages.size()); + Optional newTitle = title.map(t -> processTitle(t, manager, hasChange)); + pages.forEach(page -> newPages.add(processPage(page, manager, hasChange))); + + if (hasChange.get()) { + event.setCancelled(true); + Object newPacket = Reflections.constructor$ServerboundEditBookPacket.newInstance( + Reflections.field$ServerboundEditBookPacket$slot.get(packet), + newPages, + newTitle + ); + user.receivePacket(newPacket); + } + } catch (Exception e) { + CraftEngine.instance().logger().warn("Failed to handle ServerboundEditBookPacket", e); + } + }; + + private static String processTitle(String original, ImageManager manager, AtomicBoolean hasChange) { + AtomicReference result = new AtomicReference<>(original); + runIfContainsIllegalCharacter(original, manager, modified -> { + result.set(modified); + hasChange.set(true); + }); + return result.get(); + } + + private static String processPage(String original, ImageManager manager, AtomicBoolean hasChange) { + AtomicReference result = new AtomicReference<>(original); + runIfContainsIllegalCharacter(original, manager, modified -> { + result.set(modified); + hasChange.set(true); + }); + return result.get(); + } + private static void runIfContainsIllegalCharacter(String string, ImageManager manager, Consumer callback) { //noinspection DuplicatedCode char[] chars = string.toCharArray(); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java index 7b07b6151..ca7482e16 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java @@ -5262,4 +5262,35 @@ public class Reflections { AsyncChatDecorateEvent.class, void.class, clazz$AdventureComponent ) ); + + public static final Class clazz$ServerboundEditBookPacket = requireNonNull( + ReflectionUtils.getClazz( + BukkitReflectionUtils.assembleMCClass("network.protocol.game.ServerboundEditBookPacket"), + BukkitReflectionUtils.assembleMCClass("network.protocol.game.PacketPlayInBEdit") + ) + ); + + public static final Field field$ServerboundEditBookPacket$slot = requireNonNull( + ReflectionUtils.getDeclaredField( + clazz$ServerboundEditBookPacket, int.class, 0 + ) + ); + + public static final Field field$ServerboundEditBookPacket$pages = requireNonNull( + ReflectionUtils.getDeclaredField( + clazz$ServerboundEditBookPacket, List.class, 0 + ) + ); + + public static final Field field$ServerboundEditBookPacket$title = requireNonNull( + ReflectionUtils.getDeclaredField( + clazz$ServerboundEditBookPacket, Optional.class, 0 + ) + ); + + public static final Constructor constructor$ServerboundEditBookPacket = requireNonNull( + ReflectionUtils.getConstructor( + clazz$ServerboundEditBookPacket, int.class, List.class, Optional.class + ) + ); }