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 cef65288e..b45e8c83b 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 @@ -710,52 +710,76 @@ public class PacketConsumers { @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))); + boolean changed = false; - if (hasChange.get()) { - event.setCancelled(true); - Object newPacket = Reflections.constructor$ServerboundEditBookPacket.newInstance( - Reflections.field$ServerboundEditBookPacket$slot.get(packet), - newPages, - newTitle - ); - user.receivePacket(newPacket); + List pages = (List) Reflections.field$ServerboundEditBookPacket$pages.get(packet); + List newPages = new ArrayList<>(pages.size()); + Optional title = (Optional) Reflections.field$ServerboundEditBookPacket$title.get(packet); + Optional newTitle; + + if (title.isPresent()) { + String titleStr = title.get(); + Pair result = processClientString(titleStr, manager); + newTitle = Optional.of(result.right()); + if (result.left()) { + changed = true; + } + } else { + newTitle = Optional.empty(); + } + + for (String page : pages) { + Pair result = processClientString(page, manager); + newPages.add(result.right()); + if (result.left()) { + changed = true; + } + } + + if (changed) { + if (VersionHelper.isVersionNewerThan1_20_5()) { + event.setCancelled(true); + Object newPacket = Reflections.constructor$ServerboundEditBookPacket.newInstance( + Reflections.field$ServerboundEditBookPacket$slot.get(packet), + newPages, + newTitle + ); + user.receivePacket(newPacket); + } else { + Reflections.field$ServerboundEditBookPacket$pages.set(packet, newPages); + Reflections.field$ServerboundEditBookPacket$title.set(packet, newTitle); + } } } 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 Pair processClientString(String original, ImageManager manager) { + if (original.isEmpty()) { + return Pair.of(false, original); + } + int[] codepoints = CharacterUtils.charsToCodePoints(original.toCharArray()); + int[] newCodepoints = new int[codepoints.length]; + boolean hasIllegal = false; + for (int i = 0; i < codepoints.length; i++) { + int codepoint = codepoints[i]; + if (manager.isIllegalCharacter(codepoint)) { + newCodepoints[i] = '*'; + hasIllegal = true; + } else { + newCodepoints[i] = codepoint; + } + } + return hasIllegal ? Pair.of(true, new String(newCodepoints, 0, newCodepoints.length)) : Pair.of(false, original); } private static void runIfContainsIllegalCharacter(String string, ImageManager manager, Consumer callback) { - //noinspection DuplicatedCode - char[] chars = string.toCharArray(); - int[] codepoints = CharacterUtils.charsToCodePoints(chars); + if (string.isEmpty()) return; + int[] codepoints = CharacterUtils.charsToCodePoints(string.toCharArray()); int[] newCodepoints = new int[codepoints.length]; boolean hasIllegal = false; for (int i = 0; i < codepoints.length; i++) {