mirror of
https://github.com/Xiao-MoMi/craft-engine.git
synced 2025-12-19 15:09:15 +00:00
添加玩家聊天标签解析
This commit is contained in:
@@ -121,6 +121,7 @@ import org.jetbrains.annotations.Nullable;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.time.Instant;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.function.BiFunction;
|
import java.util.function.BiFunction;
|
||||||
@@ -433,6 +434,11 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes
|
|||||||
new SetObjectiveListener1_20(),
|
new SetObjectiveListener1_20(),
|
||||||
this.packetIds.clientboundSetObjectivePacket(), "ClientboundSetObjectivePacket"
|
this.packetIds.clientboundSetObjectivePacket(), "ClientboundSetObjectivePacket"
|
||||||
);
|
);
|
||||||
|
registerS2CGamePacketListener(
|
||||||
|
VersionHelper.isOrAbove1_20_3() ?
|
||||||
|
new PlayerChatListener_1_20_3() :
|
||||||
|
new PlayerChatListener_1_20(),
|
||||||
|
this.packetIds.clientboundPlayerChatPacket(), "ClientboundPlayerChatPacket");
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler(priority = EventPriority.LOWEST)
|
@EventHandler(priority = EventPriority.LOWEST)
|
||||||
@@ -4206,4 +4212,193 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class PlayerChatListener_1_20 implements ByteBufferPacketListener {
|
||||||
|
|
||||||
|
public void onPacketSend(NetWorkUser user, ByteBufPacketEvent event) {
|
||||||
|
if (!Config.interceptPlayerChat()) return;
|
||||||
|
FriendlyByteBuf buf = event.getBuffer();
|
||||||
|
boolean changed = false;
|
||||||
|
UUID sender = buf.readUUID();
|
||||||
|
int index = buf.readVarInt();
|
||||||
|
byte @Nullable [] messageSignature = buf.readNullable(b -> {
|
||||||
|
byte[] bs = new byte[256];
|
||||||
|
buf.readBytes(bs);
|
||||||
|
return bs;
|
||||||
|
});
|
||||||
|
// SignedMessageBody.Packed start
|
||||||
|
String content = buf.readUtf(256);
|
||||||
|
Instant timeStamp = buf.readInstant();
|
||||||
|
long salt = buf.readLong();
|
||||||
|
// LastSeenMessages.Packed start
|
||||||
|
ArrayList<Pair<Integer, byte[]>> lastSeen = buf.readCollection(FriendlyByteBuf.limitValue(ArrayList::new, 20), b -> {
|
||||||
|
int i = b.readVarInt() - 1;
|
||||||
|
if (i == -1) {
|
||||||
|
byte[] bs = new byte[256];
|
||||||
|
buf.readBytes(bs);
|
||||||
|
return Pair.of(-1, bs);
|
||||||
|
} else {
|
||||||
|
return Pair.of(i, null);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// LastSeenMessages.Packed end
|
||||||
|
// SignedMessageBody.Packed end
|
||||||
|
@Nullable String unsignedContent = buf.readNullable(FriendlyByteBuf::readUtf);
|
||||||
|
if (unsignedContent != null) {
|
||||||
|
Map<String, ComponentProvider> unsignedContentTokens = CraftEngine.instance().fontManager().matchTags(unsignedContent);
|
||||||
|
if (!unsignedContentTokens.isEmpty()) {
|
||||||
|
Tag tag = MRegistryOps.JSON.convertTo(MRegistryOps.SPARROW_NBT, GsonHelper.get().fromJson(unsignedContent, JsonElement.class));
|
||||||
|
Component component = AdventureHelper.nbtToComponent(tag);
|
||||||
|
component = AdventureHelper.replaceText(component, unsignedContentTokens, NetworkTextReplaceContext.of((BukkitServerPlayer) user));
|
||||||
|
unsignedContent = MRegistryOps.SPARROW_NBT.convertTo(MRegistryOps.JSON, AdventureHelper.componentToNbt(component)).toString();
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// FilterMask start
|
||||||
|
int type = buf.readVarInt();
|
||||||
|
BitSet mask = type == 2 /* PARTIALLY_FILTERED */ ? buf.readBitSet() : null;
|
||||||
|
// FilterMask end
|
||||||
|
// ChatType.BoundNetwork start
|
||||||
|
int chatType = buf.readVarInt();
|
||||||
|
String name = buf.readUtf();
|
||||||
|
Map<String, ComponentProvider> nameTokens = CraftEngine.instance().fontManager().matchTags(name);
|
||||||
|
if (!nameTokens.isEmpty()) {
|
||||||
|
Tag tag = MRegistryOps.JSON.convertTo(MRegistryOps.SPARROW_NBT, GsonHelper.get().fromJson(name, JsonElement.class));
|
||||||
|
Component component = AdventureHelper.nbtToComponent(tag);
|
||||||
|
component = AdventureHelper.replaceText(component, nameTokens, NetworkTextReplaceContext.of((BukkitServerPlayer) user));
|
||||||
|
name = MRegistryOps.SPARROW_NBT.convertTo(MRegistryOps.JSON, AdventureHelper.componentToNbt(component)).toString();
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
@Nullable String targetName = buf.readNullable(FriendlyByteBuf::readUtf);
|
||||||
|
if (targetName != null) {
|
||||||
|
Map<String, ComponentProvider> targetNameTokens = CraftEngine.instance().fontManager().matchTags(targetName);
|
||||||
|
if (!targetNameTokens.isEmpty()) {
|
||||||
|
Tag tag = MRegistryOps.JSON.convertTo(MRegistryOps.SPARROW_NBT, GsonHelper.get().fromJson(targetName, JsonElement.class));
|
||||||
|
Component component = AdventureHelper.nbtToComponent(tag);
|
||||||
|
component = AdventureHelper.replaceText(component, targetNameTokens, NetworkTextReplaceContext.of((BukkitServerPlayer) user));
|
||||||
|
targetName = MRegistryOps.SPARROW_NBT.convertTo(MRegistryOps.JSON, AdventureHelper.componentToNbt(component)).toString();
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ChatType.BoundNetwork end
|
||||||
|
if (changed) {
|
||||||
|
event.setChanged(true);
|
||||||
|
buf.clear();
|
||||||
|
buf.writeVarInt(event.packetID());
|
||||||
|
buf.writeUUID(sender);
|
||||||
|
buf.writeVarInt(index);
|
||||||
|
buf.writeNullable(messageSignature, (b, bs) -> buf.writeBytes(bs));
|
||||||
|
buf.writeUtf(content);
|
||||||
|
buf.writeInstant(timeStamp);
|
||||||
|
buf.writeLong(salt);
|
||||||
|
buf.writeCollection(lastSeen, (b, pair) -> {
|
||||||
|
b.writeVarInt(pair.left() + 1);
|
||||||
|
if (pair.right() != null) {
|
||||||
|
b.writeBytes(pair.right());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
buf.writeNullable(unsignedContent, FriendlyByteBuf::writeUtf);
|
||||||
|
buf.writeVarInt(type);
|
||||||
|
if (type == 2) buf.writeBitSet(mask);
|
||||||
|
buf.writeVarInt(chatType);
|
||||||
|
buf.writeUtf(name);
|
||||||
|
buf.writeNullable(targetName, FriendlyByteBuf::writeUtf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class PlayerChatListener_1_20_3 implements ByteBufferPacketListener {
|
||||||
|
|
||||||
|
public void onPacketSend(NetWorkUser user, ByteBufPacketEvent event) {
|
||||||
|
if (!Config.interceptPlayerChat()) return;
|
||||||
|
FriendlyByteBuf buf = event.getBuffer();
|
||||||
|
boolean changed = false;
|
||||||
|
int globalIndex = VersionHelper.isOrAbove1_21_5() ? buf.readVarInt() : -1;
|
||||||
|
UUID sender = buf.readUUID();
|
||||||
|
int index = buf.readVarInt();
|
||||||
|
byte @Nullable [] messageSignature = buf.readNullable(b -> {
|
||||||
|
byte[] bs = new byte[256];
|
||||||
|
buf.readBytes(bs);
|
||||||
|
return bs;
|
||||||
|
});
|
||||||
|
// SignedMessageBody.Packed start
|
||||||
|
String content = buf.readUtf(256);
|
||||||
|
Instant timeStamp = buf.readInstant();
|
||||||
|
long salt = buf.readLong();
|
||||||
|
// LastSeenMessages.Packed start
|
||||||
|
ArrayList<Pair<Integer, byte[]>> lastSeen = buf.readCollection(FriendlyByteBuf.limitValue(ArrayList::new, 20), b -> {
|
||||||
|
int i = b.readVarInt() - 1;
|
||||||
|
if (i == -1) {
|
||||||
|
byte[] bs = new byte[256];
|
||||||
|
buf.readBytes(bs);
|
||||||
|
return Pair.of(-1, bs);
|
||||||
|
} else {
|
||||||
|
return Pair.of(i, null);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// LastSeenMessages.Packed end
|
||||||
|
// SignedMessageBody.Packed end
|
||||||
|
@Nullable Tag unsignedContent = buf.readNullable(b -> b.readNbt(false));
|
||||||
|
if (unsignedContent != null) {
|
||||||
|
Map<String, ComponentProvider> tokens = CraftEngine.instance().fontManager().matchTags(unsignedContent);
|
||||||
|
if (!tokens.isEmpty()) {
|
||||||
|
Component component = AdventureHelper.tagToComponent(unsignedContent);
|
||||||
|
component = AdventureHelper.replaceText(component, tokens, NetworkTextReplaceContext.of((BukkitServerPlayer) user));
|
||||||
|
unsignedContent = AdventureHelper.componentToTag(component);
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// FilterMask start
|
||||||
|
int type = buf.readVarInt();
|
||||||
|
BitSet mask = type == 2 /* PARTIALLY_FILTERED */ ? buf.readBitSet() : null;
|
||||||
|
// FilterMask end
|
||||||
|
// ChatType.Bound start
|
||||||
|
int chatType = buf.readVarInt();
|
||||||
|
Tag name = buf.readNbt(false);
|
||||||
|
if (name != null) {
|
||||||
|
Map<String, ComponentProvider> tokens = CraftEngine.instance().fontManager().matchTags(name);
|
||||||
|
if (!tokens.isEmpty()) {
|
||||||
|
Component component = AdventureHelper.tagToComponent(name);
|
||||||
|
component = AdventureHelper.replaceText(component, tokens, NetworkTextReplaceContext.of((BukkitServerPlayer) user));
|
||||||
|
name = AdventureHelper.componentToTag(component);
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@Nullable Tag targetName = buf.readNullable(b -> b.readNbt(false));
|
||||||
|
if (targetName != null) {
|
||||||
|
Map<String, ComponentProvider> tokens = CraftEngine.instance().fontManager().matchTags(targetName);
|
||||||
|
if (!tokens.isEmpty()) {
|
||||||
|
Component component = AdventureHelper.tagToComponent(targetName);
|
||||||
|
component = AdventureHelper.replaceText(component, tokens, NetworkTextReplaceContext.of((BukkitServerPlayer) user));
|
||||||
|
targetName = AdventureHelper.componentToTag(component);
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ChatType.Bound end
|
||||||
|
if (changed) {
|
||||||
|
event.setChanged(true);
|
||||||
|
buf.clear();
|
||||||
|
buf.writeVarInt(event.packetID());
|
||||||
|
if (VersionHelper.isOrAbove1_21_5()) buf.writeVarInt(globalIndex);
|
||||||
|
buf.writeUUID(sender);
|
||||||
|
buf.writeVarInt(index);
|
||||||
|
buf.writeNullable(messageSignature, (b, bs) -> buf.writeBytes(bs));
|
||||||
|
buf.writeUtf(content);
|
||||||
|
buf.writeInstant(timeStamp);
|
||||||
|
buf.writeLong(salt);
|
||||||
|
buf.writeCollection(lastSeen, (b, pair) -> {
|
||||||
|
b.writeVarInt(pair.left() + 1);
|
||||||
|
if (pair.right() != null) {
|
||||||
|
b.writeBytes(pair.right());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
buf.writeNullable(unsignedContent, (b, tag) -> b.writeNbt(tag, false));
|
||||||
|
buf.writeVarInt(type);
|
||||||
|
if (type == 2) buf.writeBitSet(mask);
|
||||||
|
buf.writeVarInt(chatType);
|
||||||
|
buf.writeNbt(name, false);
|
||||||
|
buf.writeNullable(targetName, (b, tag) -> b.writeNbt(tag, false));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -75,4 +75,6 @@ public interface PacketIds {
|
|||||||
int clientboundForgetLevelChunkPacket();
|
int clientboundForgetLevelChunkPacket();
|
||||||
|
|
||||||
int serverboundCustomPayloadPacket();
|
int serverboundCustomPayloadPacket();
|
||||||
|
|
||||||
|
int clientboundPlayerChatPacket();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -190,4 +190,9 @@ public class PacketIds1_20 implements PacketIds {
|
|||||||
public int serverboundCustomPayloadPacket() {
|
public int serverboundCustomPayloadPacket() {
|
||||||
return PlayPacketIdHelper.byClazz(NetworkReflections.clazz$ServerboundCustomPayloadPacket, PacketFlow.SERVERBOUND);
|
return PlayPacketIdHelper.byClazz(NetworkReflections.clazz$ServerboundCustomPayloadPacket, PacketFlow.SERVERBOUND);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int clientboundPlayerChatPacket() {
|
||||||
|
return PlayPacketIdHelper.byClazz(NetworkReflections.clazz$ClientboundPlayerChatPacket, PacketFlow.CLIENTBOUND);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -189,4 +189,9 @@ public class PacketIds1_20_5 implements PacketIds {
|
|||||||
public int serverboundCustomPayloadPacket() {
|
public int serverboundCustomPayloadPacket() {
|
||||||
return PlayPacketIdHelper.byName("minecraft:custom_payload", PacketFlow.SERVERBOUND);
|
return PlayPacketIdHelper.byName("minecraft:custom_payload", PacketFlow.SERVERBOUND);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int clientboundPlayerChatPacket() {
|
||||||
|
return PlayPacketIdHelper.byName("minecraft:player_chat", PacketFlow.CLIENTBOUND);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1726,4 +1726,10 @@ public final class NetworkReflections {
|
|||||||
clazz$ClientboundUpdateTagsPacket, Map.class, 0
|
clazz$ClientboundUpdateTagsPacket, Map.class, 0
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
public static final Class<?> clazz$ClientboundPlayerChatPacket = requireNonNull(
|
||||||
|
ReflectionUtils.getClazz(
|
||||||
|
BukkitReflectionUtils.assembleMCClass("network.protocol.game.ClientboundPlayerChatPacket")
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -403,6 +403,7 @@ network:
|
|||||||
text-display: true # Modern Holograms
|
text-display: true # Modern Holograms
|
||||||
item: true
|
item: true
|
||||||
advancement: true
|
advancement: true
|
||||||
|
player-chat: true
|
||||||
|
|
||||||
recipe:
|
recipe:
|
||||||
# Master switch for custom recipes
|
# Master switch for custom recipes
|
||||||
|
|||||||
@@ -175,6 +175,7 @@ public class Config {
|
|||||||
protected boolean network$intercept_packets$set_score;
|
protected boolean network$intercept_packets$set_score;
|
||||||
protected boolean network$intercept_packets$item;
|
protected boolean network$intercept_packets$item;
|
||||||
protected boolean network$intercept_packets$advancement;
|
protected boolean network$intercept_packets$advancement;
|
||||||
|
protected boolean network$intercept_packets$player_chat;
|
||||||
protected boolean network$disable_item_operations;
|
protected boolean network$disable_item_operations;
|
||||||
|
|
||||||
protected boolean item$client_bound_model;
|
protected boolean item$client_bound_model;
|
||||||
@@ -546,6 +547,7 @@ public class Config {
|
|||||||
network$intercept_packets$set_score = config.getBoolean("network.intercept-packets.set-score", true);
|
network$intercept_packets$set_score = config.getBoolean("network.intercept-packets.set-score", true);
|
||||||
network$intercept_packets$item = config.getBoolean("network.intercept-packets.item", true);
|
network$intercept_packets$item = config.getBoolean("network.intercept-packets.item", true);
|
||||||
network$intercept_packets$advancement = config.getBoolean("network.intercept-packets.advancement", true);
|
network$intercept_packets$advancement = config.getBoolean("network.intercept-packets.advancement", true);
|
||||||
|
network$intercept_packets$player_chat = config.getBoolean("network.intercept-packets.player-chat", true);
|
||||||
|
|
||||||
// emoji
|
// emoji
|
||||||
emoji$contexts$chat = config.getBoolean("emoji.contexts.chat", true);
|
emoji$contexts$chat = config.getBoolean("emoji.contexts.chat", true);
|
||||||
@@ -980,6 +982,10 @@ public class Config {
|
|||||||
return instance.network$intercept_packets$advancement;
|
return instance.network$intercept_packets$advancement;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean interceptPlayerChat() {
|
||||||
|
return instance.network$intercept_packets$player_chat;
|
||||||
|
}
|
||||||
|
|
||||||
public static boolean predictBreaking() {
|
public static boolean predictBreaking() {
|
||||||
return instance.block$predict_breaking;
|
return instance.block$predict_breaking;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -74,6 +74,16 @@ public class FriendlyByteBuf extends ByteBuf {
|
|||||||
this.writeLong(instant.toEpochMilli());
|
this.writeLong(instant.toEpochMilli());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static <T> IntFunction<T> limitValue(IntFunction<T> applier, int max) {
|
||||||
|
return (j) -> {
|
||||||
|
if (j > max) {
|
||||||
|
throw new DecoderException("Value " + j + " is larger than limit " + max);
|
||||||
|
} else {
|
||||||
|
return applier.apply(j);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
public <T, C extends Collection<T>> C readCollection(IntFunction<C> collectionFactory, Reader<T> reader) {
|
public <T, C extends Collection<T>> C readCollection(IntFunction<C> collectionFactory, Reader<T> reader) {
|
||||||
int i = this.readVarInt();
|
int i = this.readVarInt();
|
||||||
C collection = collectionFactory.apply(i);
|
C collection = collectionFactory.apply(i);
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ org.gradle.jvmargs=-Xmx1G
|
|||||||
# Project settings
|
# Project settings
|
||||||
# Rule: [major update].[feature update].[bug fix]
|
# Rule: [major update].[feature update].[bug fix]
|
||||||
project_version=0.0.65.6
|
project_version=0.0.65.6
|
||||||
config_version=53
|
config_version=54
|
||||||
lang_version=38
|
lang_version=38
|
||||||
project_group=net.momirealms
|
project_group=net.momirealms
|
||||||
latest_supported_version=1.21.10
|
latest_supported_version=1.21.10
|
||||||
|
|||||||
Reference in New Issue
Block a user