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

feat(network): 实现阻止玩家在游戏内直接使用自定义默认字体

This commit is contained in:
jhqwqmc
2025-03-23 00:28:52 +08:00
parent 332642d529
commit c09b987733
5 changed files with 142 additions and 30 deletions

View File

@@ -127,6 +127,7 @@ public class BukkitNetworkManager implements NetworkManager, Listener {
registerNMSPacketConsumer(PacketConsumers.SOUND, Reflections.clazz$ClientboundSoundPacket); registerNMSPacketConsumer(PacketConsumers.SOUND, Reflections.clazz$ClientboundSoundPacket);
registerNMSPacketConsumer(PacketConsumers.CHAT, Reflections.clazz$ServerboundChatPacket); registerNMSPacketConsumer(PacketConsumers.CHAT, Reflections.clazz$ServerboundChatPacket);
registerNMSPacketConsumer(PacketConsumers.RENAME_ITEM, Reflections.clazz$ServerboundRenameItemPacket); registerNMSPacketConsumer(PacketConsumers.RENAME_ITEM, Reflections.clazz$ServerboundRenameItemPacket);
registerNMSPacketConsumer(PacketConsumers.SIGN_UPDATE, Reflections.clazz$ServerboundSignUpdatePacket);
registerByteBufPacketConsumer(PacketConsumers.SECTION_BLOCK_UPDATE, this.packetIds.clientboundSectionBlocksUpdatePacket()); registerByteBufPacketConsumer(PacketConsumers.SECTION_BLOCK_UPDATE, this.packetIds.clientboundSectionBlocksUpdatePacket());
registerByteBufPacketConsumer(PacketConsumers.BLOCK_UPDATE, this.packetIds.clientboundBlockUpdatePacket()); registerByteBufPacketConsumer(PacketConsumers.BLOCK_UPDATE, this.packetIds.clientboundBlockUpdatePacket());
registerByteBufPacketConsumer(PacketConsumers.LEVEL_PARTICLE, this.packetIds.clientboundLevelParticlesPacket()); registerByteBufPacketConsumer(PacketConsumers.LEVEL_PARTICLE, this.packetIds.clientboundLevelParticlesPacket());
@@ -267,6 +268,20 @@ public class BukkitNetworkManager implements NetworkManager, Listener {
this.packetsConsumer.accept(player.serverPlayer(), packet); this.packetsConsumer.accept(player.serverPlayer(), packet);
} }
public void receivePacket(@NotNull NetWorkUser player, Object packet) {
Channel channel = player.nettyChannel();
List<String> handlerNames = channel.pipeline().names();
if (handlerNames.contains("decompress")) {
channel.pipeline().context("decompress").fireChannelRead(packet);
} else {
if (handlerNames.contains("decrypt")) {
channel.pipeline().context("decrypt").fireChannelRead(packet);
} else {
channel.pipeline().context("splitter").fireChannelRead(packet);
}
}
}
private void injectServerChannel(Channel serverChannel) { private void injectServerChannel(Channel serverChannel) {
ChannelPipeline pipeline = serverChannel.pipeline(); ChannelPipeline pipeline = serverChannel.pipeline();
ChannelHandler connectionHandler = pipeline.get(CONNECTION_HANDLER_NAME); ChannelHandler connectionHandler = pipeline.get(CONNECTION_HANDLER_NAME);

View File

@@ -3,6 +3,8 @@ package net.momirealms.craftengine.bukkit.plugin.network;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled; import io.netty.buffer.Unpooled;
import it.unimi.dsi.fastutil.ints.IntList; import it.unimi.dsi.fastutil.ints.IntList;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.minimessage.MiniMessage;
import net.momirealms.craftengine.bukkit.api.CraftEngineFurniture; import net.momirealms.craftengine.bukkit.api.CraftEngineFurniture;
import net.momirealms.craftengine.bukkit.api.event.FurnitureBreakEvent; import net.momirealms.craftengine.bukkit.api.event.FurnitureBreakEvent;
import net.momirealms.craftengine.bukkit.api.event.FurnitureInteractEvent; import net.momirealms.craftengine.bukkit.api.event.FurnitureInteractEvent;
@@ -33,9 +35,8 @@ import org.bukkit.util.RayTraceResult;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.Arrays; import java.time.Instant;
import java.util.Map; import java.util.*;
import java.util.Objects;
import java.util.function.BiConsumer; import java.util.function.BiConsumer;
public class PacketConsumers { public class PacketConsumers {
@@ -670,17 +671,19 @@ public class PacketConsumers {
if (message != null && !message.isEmpty()) { if (message != null && !message.isEmpty()) {
ImageManager manager = CraftEngine.instance().imageManager(); ImageManager manager = CraftEngine.instance().imageManager();
if (!manager.isDefaultFontInUse()) return; if (!manager.isDefaultFontInUse()) return;
char[] chars = message.toCharArray();
try { try {
int[] codepoints = CharacterUtils.charsToCodePoints(chars); String str = replaceIllegalString(message, manager);
for (int codepoint : codepoints) { if (message.equals(str)) return;
if (manager.isIllegalCharacter(codepoint)) { event.setCancelled(true);
event.setCancelled(true); Object newPacket = Reflections.constructor$ServerboundChatPacket.newInstance(
return; str,
} Reflections.field$ServerboundChatPacket$timeStamp.get(packet),
} Reflections.field$ServerboundChatPacket$salt.get(packet),
} catch (Exception ignore) { Reflections.field$ServerboundChatPacket$signature.get(packet),
} Reflections.field$ServerboundChatPacket$lastSeenMessages.get(packet)
);
user.receivePacket(newPacket);
} catch (Exception ignore) {}
} }
} catch (Exception e) { } catch (Exception e) {
CraftEngine.instance().logger().warn("Failed to handle ServerboundChatPacket", e); CraftEngine.instance().logger().warn("Failed to handle ServerboundChatPacket", e);
@@ -694,25 +697,49 @@ public class PacketConsumers {
if (message != null && !message.isEmpty()) { if (message != null && !message.isEmpty()) {
ImageManager manager = CraftEngine.instance().imageManager(); ImageManager manager = CraftEngine.instance().imageManager();
if (!manager.isDefaultFontInUse()) return; if (!manager.isDefaultFontInUse()) return;
char[] chars = message.toCharArray();
try { try {
int[] codepoints = CharacterUtils.charsToCodePoints(chars); String str = replaceIllegalString(message, manager);
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); Reflections.field$ServerboundRenameItemPacket$name.set(packet, str);
} catch (Exception ignore) { } catch (Exception ignore) {}
}
} }
} catch (Exception e) { } catch (Exception e) {
CraftEngine.instance().logger().warn("Failed to handle ServerboundRenameItemPacket", e); CraftEngine.instance().logger().warn("Failed to handle ServerboundRenameItemPacket", e);
} }
}; };
// we handle it on packet level to prevent it from being captured by plugins
public static final TriConsumer<NetWorkUser, NMSPacketEvent, Object> SIGN_UPDATE = (user, event, packet) -> {
try {
String[] lines = (String[]) Reflections.field$ServerboundSignUpdatePacket$lines.get(packet);
ImageManager manager = CraftEngine.instance().imageManager();
for (int i = 0; i < lines.length; i++) {
String line = lines[i];
if (line != null && !line.isEmpty()) {
if (!manager.isDefaultFontInUse()) return;
try {
String str = replaceIllegalString(line, manager);
if (line.equals(str)) continue;
lines[i] = str;
} catch (Exception ignore){}
}
}
} catch (Exception e) {
CraftEngine.instance().logger().warn("Failed to handle ServerboundSignUpdatePacket", e);
}
};
private static String replaceIllegalString(String string, ImageManager manager) {
char[] chars = string.toCharArray();
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] = '*';
}
}
return new String(newCodepoints, 0, newCodepoints.length);
}
} }

View File

@@ -231,6 +231,11 @@ public class BukkitServerPlayer extends Player {
this.plugin.networkManager().sendPacket(this, packet, immediately); this.plugin.networkManager().sendPacket(this, packet, immediately);
} }
@Override
public void receivePacket(Object packet) {
this.plugin.networkManager().receivePacket(this, packet);
}
@Override @Override
public ConnectionState decoderState() { public ConnectionState decoderState() {
return decoderState; return decoderState;

View File

@@ -7,6 +7,7 @@ import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder; import io.netty.handler.codec.ByteToMessageDecoder;
import io.netty.handler.codec.MessageToByteEncoder; import io.netty.handler.codec.MessageToByteEncoder;
import net.kyori.adventure.text.Component;
import net.momirealms.craftengine.core.util.ReflectionUtils; import net.momirealms.craftengine.core.util.ReflectionUtils;
import net.momirealms.craftengine.core.util.VersionHelper; import net.momirealms.craftengine.core.util.VersionHelper;
import org.bukkit.Location; import org.bukkit.Location;
@@ -26,6 +27,7 @@ import sun.misc.Unsafe;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.lang.reflect.*; import java.lang.reflect.*;
import java.time.Instant;
import java.util.*; import java.util.*;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
@@ -134,9 +136,9 @@ public class Reflections {
); );
public static final Constructor<?> constructor$ClientboundSystemChatPacket = requireNonNull( public static final Constructor<?> constructor$ClientboundSystemChatPacket = requireNonNull(
ReflectionUtils.getConstructor( VersionHelper.isVersionNewerThan1_20_4()
clazz$ClientboundSystemChatPacket, clazz$Component, boolean.class ? ReflectionUtils.getConstructor(clazz$ClientboundSystemChatPacket, clazz$Component, boolean.class)
) : ReflectionUtils.getConstructor(clazz$ClientboundSystemChatPacket, Component.class, String.class, boolean.class)
); );
public static final Field field$ClientboundSystemChatPacket$overlay = requireNonNull( public static final Field field$ClientboundSystemChatPacket$overlay = requireNonNull(
@@ -189,6 +191,11 @@ public class Reflections {
clazz$ClientboundSystemChatPacket, clazz$Component, 0 clazz$ClientboundSystemChatPacket, clazz$Component, 0
); );
public static final Field field$ClientboundSystemChatPacket$adventure$content =
ReflectionUtils.getDeclaredField(
clazz$ClientboundSystemChatPacket, Component.class, 0
);
public static final Field field$ClientboundSystemChatPacket$text = public static final Field field$ClientboundSystemChatPacket$text =
ReflectionUtils.getDeclaredField( ReflectionUtils.getDeclaredField(
clazz$ClientboundSystemChatPacket, String.class, 0 clazz$ClientboundSystemChatPacket, String.class, 0
@@ -5115,6 +5122,19 @@ public class Reflections {
) )
); );
public static final Class<?> clazz$MessageSignature = requireNonNull(
ReflectionUtils.getClazz(
BukkitReflectionUtils.assembleMCClass("network.chat.MessageSignature")
)
);
public static final Class<?> clazz$LastSeenMessages$Update = requireNonNull(
ReflectionUtils.getClazz(
BukkitReflectionUtils.assembleMCClass("network.chat.LastSeenMessages$Update"),
BukkitReflectionUtils.assembleMCClass("network.chat.LastSeenMessages$b")
)
);
public static final Class<?> clazz$ServerboundChatPacket = requireNonNull( public static final Class<?> clazz$ServerboundChatPacket = requireNonNull(
ReflectionUtils.getClazz( ReflectionUtils.getClazz(
BukkitReflectionUtils.assembleMCClass("network.protocol.game.ServerboundChatPacket"), BukkitReflectionUtils.assembleMCClass("network.protocol.game.ServerboundChatPacket"),
@@ -5122,12 +5142,42 @@ public class Reflections {
) )
); );
public static final Constructor<?> constructor$ServerboundChatPacket = requireNonNull(
ReflectionUtils.getConstructor(
clazz$ServerboundChatPacket, String.class, Instant.class, long.class, clazz$MessageSignature, clazz$LastSeenMessages$Update
)
);
public static final Field field$ServerboundChatPacket$message = requireNonNull( public static final Field field$ServerboundChatPacket$message = requireNonNull(
ReflectionUtils.getDeclaredField( ReflectionUtils.getDeclaredField(
clazz$ServerboundChatPacket, String.class, 0 clazz$ServerboundChatPacket, String.class, 0
) )
); );
public static final Field field$ServerboundChatPacket$timeStamp = requireNonNull(
ReflectionUtils.getDeclaredField(
clazz$ServerboundChatPacket, Instant.class, 0
)
);
public static final Field field$ServerboundChatPacket$salt = requireNonNull(
ReflectionUtils.getDeclaredField(
clazz$ServerboundChatPacket, long.class, 0
)
);
public static final Field field$ServerboundChatPacket$signature = requireNonNull(
ReflectionUtils.getDeclaredField(
clazz$ServerboundChatPacket, clazz$MessageSignature, 0
)
);
public static final Field field$ServerboundChatPacket$lastSeenMessages = requireNonNull(
ReflectionUtils.getDeclaredField(
clazz$ServerboundChatPacket, clazz$LastSeenMessages$Update, 0
)
);
public static final Class<?> clazz$ServerboundRenameItemPacket = requireNonNull( public static final Class<?> clazz$ServerboundRenameItemPacket = requireNonNull(
ReflectionUtils.getClazz( ReflectionUtils.getClazz(
BukkitReflectionUtils.assembleMCClass("network.protocol.game.ServerboundRenameItemPacket"), BukkitReflectionUtils.assembleMCClass("network.protocol.game.ServerboundRenameItemPacket"),
@@ -5140,4 +5190,17 @@ public class Reflections {
clazz$ServerboundRenameItemPacket, String.class, 0 clazz$ServerboundRenameItemPacket, String.class, 0
) )
); );
public static final Class<?> clazz$ServerboundSignUpdatePacket = requireNonNull(
ReflectionUtils.getClazz(
BukkitReflectionUtils.assembleMCClass("network.protocol.game.ServerboundSignUpdatePacket"),
BukkitReflectionUtils.assembleMCClass("network.protocol.game.PacketPlayInUpdateSign")
)
);
public static final Field field$ServerboundSignUpdatePacket$lines = requireNonNull(
ReflectionUtils.getDeclaredField(
clazz$ServerboundSignUpdatePacket, String[].class, 0
)
);
} }

View File

@@ -16,6 +16,8 @@ public interface NetWorkUser {
void sendPacket(Object packet, boolean immediately); void sendPacket(Object packet, boolean immediately);
void receivePacket(Object packet);
@ApiStatus.Internal @ApiStatus.Internal
ConnectionState decoderState(); ConnectionState decoderState();