9
0
mirror of https://github.com/Xiao-MoMi/craft-engine.git synced 2025-12-22 16:39:28 +00:00

Merge pull request #173 from jhqwqmc/dev

fix(network): 解决set实体包报错问题
This commit is contained in:
XiaoMoMi
2025-05-11 14:59:24 +08:00
committed by GitHub
4 changed files with 105 additions and 16 deletions

View File

@@ -2,6 +2,7 @@ package net.momirealms.craftengine.bukkit.plugin.command.feature;
import net.momirealms.craftengine.bukkit.item.BukkitItemManager;
import net.momirealms.craftengine.bukkit.plugin.command.BukkitCommandFeature;
import net.momirealms.craftengine.bukkit.util.BlockTags;
import net.momirealms.craftengine.core.item.Item;
import net.momirealms.craftengine.core.plugin.CraftEngine;
import net.momirealms.craftengine.core.plugin.command.CraftEngineCommandManager;
@@ -13,47 +14,51 @@ import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.incendo.cloud.Command;
import org.incendo.cloud.bukkit.data.BlockPredicate;
import org.incendo.cloud.bukkit.parser.BlockPredicateParser;
import org.incendo.cloud.bukkit.parser.NamespacedKeyParser;
import org.incendo.cloud.context.CommandContext;
import org.incendo.cloud.context.CommandInput;
import org.incendo.cloud.parser.standard.BooleanParser;
import org.incendo.cloud.parser.standard.ByteParser;
import org.incendo.cloud.parser.standard.StringParser;
import org.incendo.cloud.suggestion.Suggestion;
import org.incendo.cloud.suggestion.SuggestionProvider;
import java.util.Optional;
import java.util.*;
import java.util.concurrent.CompletableFuture;
public class TestCommand extends BukkitCommandFeature<CommandSender> {
public static final Collection<Suggestion> TARGET_BLOCK_SUGGESTIONS = new HashSet<>();
static {
for (Material material : Material.values()) {
TARGET_BLOCK_SUGGESTIONS.add(Suggestion.suggestion(material.getKey().toString()));
}
}
public TestCommand(CraftEngineCommandManager<CommandSender> commandManager, CraftEngine plugin) {
super(commandManager, plugin);
}
@Override
@SuppressWarnings("deprecation")
public Command.Builder<? extends CommandSender> assembleCommand(org.incendo.cloud.CommandManager<CommandSender> manager, Command.Builder<CommandSender> builder) {
return builder
.senderType(Player.class)
.required("id", NamespacedKeyParser.namespacedKeyComponent().suggestionProvider(new SuggestionProvider<>() {
.required("reset", BooleanParser.booleanParser())
.required("setTag", NamespacedKeyParser.namespacedKeyParser())
.required("targetBlock", StringParser.stringComponent(StringParser.StringMode.GREEDY_FLAG_YIELDING).suggestionProvider(new SuggestionProvider<>() {
@Override
public @NonNull CompletableFuture<? extends @NonNull Iterable<? extends @NonNull Suggestion>> suggestionsFuture(@NonNull CommandContext<Object> context, @NonNull CommandInput input) {
return CompletableFuture.completedFuture(plugin().itemManager().cachedSuggestions());
return CompletableFuture.completedFuture(TARGET_BLOCK_SUGGESTIONS);
}
}))
.required("displayType", ByteParser.byteParser((byte) 0, (byte) 8))
.required("translation", StringParser.stringParser())
.required("rotation", StringParser.stringParser())
.handler(context -> {
Player player = context.sender();
NamespacedKey namespacedKey = context.get("id");
ItemStack item = new ItemStack(Material.TRIDENT);
item.editMeta((meta) -> {
Item<ItemStack> ceItem = BukkitItemManager.instance().createWrappedItem(Key.of(namespacedKey.asString()), null);
Optional<Integer> customModelData = ceItem.customModelData();
customModelData.ifPresent(meta::setCustomModelData);
});
player.getInventory().addItem(item);
player.sendMessage("开始测试");
NamespacedKey key = context.get("setTag");
BlockTags.test(plugin().adapt(player), context.get("reset"), context.get("targetBlock"), key.asString());
player.sendMessage("结束测试");
});
}

View File

@@ -1998,6 +1998,7 @@ public class PacketConsumers {
EntityPacketHandler handler = user.entityPacketHandlers().get(id);
if (handler != null) {
handler.handleSetEntityData(user, event);
return;
}
if (Config.interceptEntityName()) {
boolean isChanged = false;

View File

@@ -1,9 +1,16 @@
package net.momirealms.craftengine.bukkit.util;
import io.netty.buffer.Unpooled;
import it.unimi.dsi.fastutil.ints.IntArrayList;
import it.unimi.dsi.fastutil.ints.IntList;
import net.momirealms.craftengine.bukkit.nms.FastNMS;
import net.momirealms.craftengine.core.entity.player.Player;
import net.momirealms.craftengine.core.util.FriendlyByteBuf;
import net.momirealms.craftengine.core.util.Key;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
public class BlockTags {
private static final Map<Key, Object> CACHE = new HashMap<>();
@@ -24,4 +31,80 @@ public class BlockTags {
return value;
}
}
/**
* 用于测试下面的 buildFakeUpdateTagsPacket 方法
*
* @param player CraftEngine玩家对象
* @param reset 是否重置标签
* @param targetBlock 测试添加标签的目标方块
* @param setTag 测试添加的标签
*/
public static void test(Player player, boolean reset, String targetBlock, String setTag) {
Map<Object, Map<String, IntList>> addTags = new HashMap<>();
if (!reset) {
Object registries = Reflections.instance$BuiltInRegistries$BLOCK;
Object key = FastNMS.INSTANCE.method$Registry$key(registries);
Map<String, IntList> blockTags = new HashMap<>();
IntList blockId = new IntArrayList();
Object blockKey = KeyUtils.toResourceLocation(Key.of(targetBlock));
Object block = FastNMS.INSTANCE.method$Registry$get(registries, blockKey);
Optional<Integer> optionalBlockId = FastNMS.INSTANCE.method$BuiltInRegistries$getId(registries, block);
optionalBlockId.ifPresent(integer -> blockId.add(integer.intValue()));
blockTags.put(setTag, blockId);
addTags.put(key, blockTags);
}
Object packet = buildFakeUpdateTagsPacket(addTags);
player.sendPacket(packet, true);
}
/**
* 构建模拟标签更新数据包(用于向客户端添加虚拟标签)
*
* @param addTags 需要添加的标签数据,结构为嵌套映射:
* <pre>{@code
* Map结构示例:
* {
* 注册表键1 (如BuiltInRegistries.ITEM.key) -> {
* "命名空间:值1" -> IntList.of(1, 2, 3), // 该命名空间下生效的物品ID列表
* "命名空间:值2" -> IntList.of(5, 7)
* },
* 注册表键2 (如BuiltInRegistries.BLOCK.key) -> {
* "minecraft:beacon_base_blocks" -> IntList.of(1024, 2048)
* },
* ....
* }
* }</pre>
* 其中:</br>
* - 外层键:注册表对象(如物品/方块注册表)</br>
* - 中间层键:标签的命名空间:值(字符串)</br>
* - 值包含注册表内项目数字ID的IntList
*
* @return 可发送给客户端的 ClientboundUpdateTagsPacket 数据包对象
*/
@SuppressWarnings("unchecked")
public static Object buildFakeUpdateTagsPacket(Map<Object, Map<String, IntList>> addTags) {
Map<Object, Object> registriesNetworkPayload = (Map<Object, Object>) FastNMS.INSTANCE.method$TagNetworkSerialization$serializeTagsToNetwork();
for (Map.Entry<Object, Map<String, IntList>> entry : addTags.entrySet()) {
Object registryKey = entry.getKey();
Map<String, IntList> tagsToAdd = entry.getValue();
Object existingPayload = registriesNetworkPayload.get(registryKey);
if (existingPayload == null) continue;
FriendlyByteBuf deserializeBuf = new FriendlyByteBuf(Unpooled.buffer());
FastNMS.INSTANCE.method$TagNetworkSerialization$NetworkPayload$write(existingPayload, deserializeBuf);
Map<String, IntList> combinedTags = deserializeBuf.readMap(
FriendlyByteBuf::readUtf,
FriendlyByteBuf::readIntIdList
);
combinedTags.putAll(tagsToAdd);
FriendlyByteBuf serializeBuf = new FriendlyByteBuf(Unpooled.buffer());
serializeBuf.writeMap(combinedTags,
FriendlyByteBuf::writeUtf,
FriendlyByteBuf::writeIntIdList
);
Object mergedPayload = FastNMS.INSTANCE.method$TagNetworkSerialization$NetworkPayload$read(serializeBuf);
registriesNetworkPayload.put(registryKey, mergedPayload);
}
return FastNMS.INSTANCE.constructor$ClientboundUpdateTagsPacket(registriesNetworkPayload);
}
}

View File

@@ -50,7 +50,7 @@ byte_buddy_version=1.17.5
ahocorasick_version=0.6.3
snake_yaml_version=2.4
anti_grief_version=0.15
nms_helper_version=0.65.19
nms_helper_version=0.65.20
evalex_version=3.5.0
reactive_streams_version=1.0.4
amazon_awssdk_version=2.31.23