9
0
mirror of https://github.com/Xiao-MoMi/craft-engine.git synced 2025-12-19 15:09:15 +00:00

prevent illegal chars in anvil

This commit is contained in:
XiaoMoMi
2025-03-22 17:17:59 +08:00
parent b1e4339b4f
commit 951a9c321e
8 changed files with 116 additions and 5 deletions

View File

@@ -29,6 +29,7 @@ import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.block.Action;
import org.bukkit.event.player.PlayerChatEvent;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.inventory.EquipmentSlot;
import org.bukkit.inventory.ItemStack;
@@ -157,8 +158,6 @@ public class ItemEventListener implements Listener {
}
for (ItemBehavior itemBehavior : optionalItemBehaviors.get()) {
InteractionResult result = itemBehavior.useOnBlock(new UseOnContext(player, hand, hitResult));
if (result == InteractionResult.SUCCESS_AND_CANCEL) {
event.setCancelled(true);

View File

@@ -125,6 +125,8 @@ public class BukkitNetworkManager implements NetworkManager, Listener {
registerNMSPacketConsumer(PacketConsumers.MOVE_ENTITY, Reflections.clazz$ClientboundMoveEntityPacket$Pos);
registerNMSPacketConsumer(PacketConsumers.PICK_ITEM_FROM_ENTITY, Reflections.clazz$ServerboundPickItemFromEntityPacket);
registerNMSPacketConsumer(PacketConsumers.SOUND, Reflections.clazz$ClientboundSoundPacket);
registerNMSPacketConsumer(PacketConsumers.CHAT, Reflections.clazz$ServerboundChatPacket);
registerNMSPacketConsumer(PacketConsumers.RENAME_ITEM, Reflections.clazz$ServerboundRenameItemPacket);
registerByteBufPacketConsumer(PacketConsumers.SECTION_BLOCK_UPDATE, this.packetIds.clientboundSectionBlocksUpdatePacket());
registerByteBufPacketConsumer(PacketConsumers.BLOCK_UPDATE, this.packetIds.clientboundBlockUpdatePacket());
registerByteBufPacketConsumer(PacketConsumers.LEVEL_PARTICLE, this.packetIds.clientboundLevelParticlesPacket());

View File

@@ -14,6 +14,7 @@ import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer;
import net.momirealms.craftengine.bukkit.util.*;
import net.momirealms.craftengine.core.block.ImmutableBlockState;
import net.momirealms.craftengine.core.entity.player.InteractionHand;
import net.momirealms.craftengine.core.font.ImageManager;
import net.momirealms.craftengine.core.plugin.CraftEngine;
import net.momirealms.craftengine.core.plugin.config.ConfigManager;
import net.momirealms.craftengine.core.plugin.network.ConnectionState;
@@ -32,9 +33,7 @@ import org.bukkit.util.RayTraceResult;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Map;
import java.util.Objects;
import java.util.*;
import java.util.function.BiConsumer;
public class PacketConsumers {
@@ -661,4 +660,57 @@ public class PacketConsumers {
CraftEngine.instance().logger().warn("Failed to handle ClientboundSoundPacket", e);
}
};
// we handle it on packet level to prevent it from being captured by plugins (most are chat plugins)
public static final TriConsumer<NetWorkUser, NMSPacketEvent, Object> CHAT = (user, event, packet) -> {
try {
String message = (String) Reflections.field$ServerboundChatPacket$message.get(packet);
if (message != null && !message.isEmpty()) {
ImageManager manager = CraftEngine.instance().imageManager();
if (!manager.isDefaultFontInUse()) return;
char[] chars = message.toCharArray();
try {
int[] codepoints = CharacterUtils.charsToCodePoints(chars);
for (int codepoint : codepoints) {
if (manager.isIllegalCharacter(codepoint)) {
event.setCancelled(true);
return;
}
}
} catch (Exception ignore) {
}
}
} catch (Exception e) {
CraftEngine.instance().logger().warn("Failed to handle ServerboundChatPacket", e);
}
};
// we handle it on packet level to prevent it from being captured by plugins
public static final TriConsumer<NetWorkUser, NMSPacketEvent, Object> RENAME_ITEM = (user, event, packet) -> {
try {
String message = (String) Reflections.field$ServerboundRenameItemPacket$name.get(packet);
if (message != null && !message.isEmpty()) {
ImageManager manager = CraftEngine.instance().imageManager();
if (!manager.isDefaultFontInUse()) return;
char[] chars = message.toCharArray();
try {
int[] codepoints = CharacterUtils.charsToCodePoints(chars);
int[] newCodepoints = new int[codepoints.length];
for (int i = 0; i < codepoints.length; i++) {
int codepoint = codepoints[i];
if (!manager.isIllegalCharacter(codepoint)) {
newCodepoints[i] = codepoint;
} else {
newCodepoints[i] = '*';
}
}
String str = new String(newCodepoints, 0, newCodepoints.length);
Reflections.field$ServerboundRenameItemPacket$name.set(packet, str);
} catch (Exception ignore) {
}
}
} catch (Exception e) {
CraftEngine.instance().logger().warn("Failed to handle ServerboundRenameItemPacket", e);
}
};
}

View File

@@ -5114,4 +5114,30 @@ public class Reflections {
clazz$HitResult, clazz$Vec3, 0
)
);
public static final Class<?> clazz$ServerboundChatPacket = requireNonNull(
ReflectionUtils.getClazz(
BukkitReflectionUtils.assembleMCClass("network.protocol.game.ServerboundChatPacket"),
BukkitReflectionUtils.assembleMCClass("network.protocol.game.PacketPlayInChat")
)
);
public static final Field field$ServerboundChatPacket$message = requireNonNull(
ReflectionUtils.getDeclaredField(
clazz$ServerboundChatPacket, String.class, 0
)
);
public static final Class<?> clazz$ServerboundRenameItemPacket = requireNonNull(
ReflectionUtils.getClazz(
BukkitReflectionUtils.assembleMCClass("network.protocol.game.ServerboundRenameItemPacket"),
BukkitReflectionUtils.assembleMCClass("network.protocol.game.PacketPlayInItemName")
)
);
public static final Field field$ServerboundRenameItemPacket$name = requireNonNull(
ReflectionUtils.getDeclaredField(
clazz$ServerboundRenameItemPacket, String.class, 0
)
);
}

View File

@@ -3,6 +3,7 @@ package net.momirealms.craftengine.core.font;
import net.momirealms.craftengine.core.util.Key;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
@@ -19,6 +20,10 @@ public class Font {
return this.idToCodepoint.containsKey(codepoint);
}
public Collection<Integer> codepointsInUse() {
return Collections.unmodifiableCollection(this.idToCodepoint.keySet());
}
public BitmapImage getImageByCodepoint(int codepoint) {
return this.idToCodepoint.get(codepoint);
}

View File

@@ -13,11 +13,18 @@ import java.util.function.BiFunction;
public interface ImageManager extends Reloadable, ConfigSectionParser {
String CONFIG_SECTION_NAME = "images";
Key DEFAULT_FONT = Key.of("minecraft:default");
default String sectionId() {
return CONFIG_SECTION_NAME;
}
void delayedLoad();
boolean isDefaultFontInUse();
boolean isIllegalCharacter(int codepoint);
Collection<Font> fontsInUse();
Optional<BitmapImage> bitmapImageByCodepoint(Key font, int codepoint);

View File

@@ -18,6 +18,7 @@ public class ImageManagerImpl implements ImageManager {
private final HashMap<Key, Font> fonts = new HashMap<>();
// namespace:id image
private final HashMap<Key, BitmapImage> images = new HashMap<>();
private final Set<Integer> illegalChars = new HashSet<>();
private OffsetFont offsetFont;
@@ -36,6 +37,24 @@ public class ImageManagerImpl implements ImageManager {
public void unload() {
this.fonts.clear();
this.images.clear();
this.illegalChars.clear();
}
@Override
public void delayedLoad() {
Optional.ofNullable(this.fonts.get(DEFAULT_FONT)).ifPresent(font -> {
this.illegalChars.addAll(font.codepointsInUse());
});
}
@Override
public boolean isDefaultFontInUse() {
return !this.illegalChars.isEmpty();
}
@Override
public boolean isIllegalCharacter(int codepoint) {
return this.illegalChars.contains(codepoint);
}
@Override

View File

@@ -106,6 +106,7 @@ public abstract class CraftEngine implements Plugin {
this.blockManager.delayedLoad();
this.itemBrowserManager.delayedLoad();
this.soundManager.delayedLoad();
this.imageManager.delayedLoad();
if (ConfigManager.debug()) {
this.debugger = (s) -> logger.info("[Debug] " + s.get());
} else {