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:
@@ -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);
|
||||||
|
|||||||
@@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user