mirror of
https://github.com/Xiao-MoMi/craft-engine.git
synced 2025-12-30 12:29:15 +00:00
fix(bukkit): 修复1.21.5+的物品手感问题
This commit is contained in:
@@ -15,6 +15,7 @@ import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine;
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections;
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MBuiltInRegistries;
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MRegistries;
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MRegistryOps;
|
||||
import net.momirealms.craftengine.bukkit.util.ItemStackUtils;
|
||||
import net.momirealms.craftengine.bukkit.util.KeyUtils;
|
||||
import net.momirealms.craftengine.core.entity.player.Player;
|
||||
@@ -39,6 +40,7 @@ import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.*;
|
||||
import java.util.function.Function;
|
||||
|
||||
public class BukkitItemManager extends AbstractItemManager<ItemStack> {
|
||||
static {
|
||||
@@ -56,8 +58,10 @@ public class BukkitItemManager extends AbstractItemManager<ItemStack> {
|
||||
private final Object bedrockItemHolder;
|
||||
private final Item<ItemStack> emptyItem;
|
||||
private final UniqueIdItem<ItemStack> emptyUniqueItem;
|
||||
private final Function<Object, Integer> decoratedHashOpsGenerator;
|
||||
private Set<Key> lastRegisteredPatterns = Set.of();
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public BukkitItemManager(BukkitCraftEngine plugin) {
|
||||
super(plugin);
|
||||
instance = this;
|
||||
@@ -68,13 +72,14 @@ public class BukkitItemManager extends AbstractItemManager<ItemStack> {
|
||||
this.armorEventListener = new ArmorEventListener();
|
||||
this.networkItemHandler = VersionHelper.isOrAbove1_20_5() ? new ModernNetworkItemHandler() : new LegacyNetworkItemHandler();
|
||||
this.registerAllVanillaItems();
|
||||
this.bedrockItemHolder = FastNMS.INSTANCE.method$Registry$getHolderByResourceKey(MBuiltInRegistries.ITEM, FastNMS.INSTANCE.method$ResourceKey$create(MRegistries.ITEM, KeyUtils.toResourceLocation(Key.of("minecraft:bedrock")))).get();;
|
||||
this.bedrockItemHolder = FastNMS.INSTANCE.method$Registry$getHolderByResourceKey(MBuiltInRegistries.ITEM, FastNMS.INSTANCE.method$ResourceKey$create(MRegistries.ITEM, KeyUtils.toResourceLocation(Key.of("minecraft:bedrock")))).get();
|
||||
this.registerCustomTrimMaterial();
|
||||
this.loadLastRegisteredPatterns();
|
||||
|
||||
ItemStack emptyStack = FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(CoreReflections.instance$ItemStack$EMPTY);
|
||||
this.emptyItem = this.wrap(emptyStack);
|
||||
this.emptyUniqueItem = new UniqueIdItem<>(UniqueKey.AIR, this.emptyItem);
|
||||
this.decoratedHashOpsGenerator = VersionHelper.isOrAbove1_21_5() ? (Function<Object, Integer>) FastNMS.INSTANCE.createDecoratedHashOpsGenerator(MRegistryOps.HASHCODE) : null;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@@ -452,4 +457,9 @@ public class BukkitItemManager extends AbstractItemManager<ItemStack> {
|
||||
}
|
||||
return this.emptyItem;
|
||||
}
|
||||
|
||||
@Nullable("在 1.21.5+ 才有")
|
||||
public Function<Object, Integer> decoratedHashOpsGenerator() {
|
||||
return decoratedHashOpsGenerator;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2124,23 +2124,6 @@ public class PacketConsumers {
|
||||
FriendlyByteBuf buf = event.getBuffer();
|
||||
Object friendlyBuf = FastNMS.INSTANCE.constructor$FriendlyByteBuf(buf);
|
||||
ItemStack itemStack = FastNMS.INSTANCE.method$FriendlyByteBuf$readItem(friendlyBuf);
|
||||
if (VersionHelper.isOrAbove1_21_5()) {
|
||||
Item<ItemStack> wrapped = BukkitItemManager.instance().wrap(itemStack);
|
||||
if (!wrapped.isEmpty() && wrapped.isCustomItem()) {
|
||||
Object containerMenu = FastNMS.INSTANCE.field$Player$containerMenu(serverPlayer.serverPlayer());
|
||||
if (containerMenu != null) {
|
||||
ItemStack carried = FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(FastNMS.INSTANCE.method$AbstractContainerMenu$getCarried(containerMenu));
|
||||
if (ItemStackUtils.isEmpty(carried)) {
|
||||
event.setChanged(true);
|
||||
buf.clear();
|
||||
buf.writeVarInt(event.packetID());
|
||||
Object newFriendlyBuf = FastNMS.INSTANCE.constructor$FriendlyByteBuf(buf);
|
||||
FastNMS.INSTANCE.method$FriendlyByteBuf$writeItem(newFriendlyBuf, carried);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
BukkitItemManager.instance().s2c(itemStack, serverPlayer).ifPresent((newItemStack) -> {
|
||||
event.setChanged(true);
|
||||
buf.clear();
|
||||
@@ -2247,7 +2230,64 @@ public class PacketConsumers {
|
||||
|
||||
public static final BiConsumer<NetWorkUser, ByteBufPacketEvent> CONTAINER_CLICK_1_20 = (user, event) -> {
|
||||
try {
|
||||
if (VersionHelper.isOrAbove1_21_5()) return; // 1.21.5+需要其他办法解决同步问题
|
||||
if (VersionHelper.isOrAbove1_21_5()) {
|
||||
FriendlyByteBuf buf = event.getBuffer();
|
||||
boolean changed = false;
|
||||
Object friendlyBuf = FastNMS.INSTANCE.constructor$FriendlyByteBuf(buf);
|
||||
Object inventory = FastNMS.INSTANCE.method$Player$getInventory(user.serverPlayer());
|
||||
int containerId = buf.readContainerId();
|
||||
int stateId = buf.readVarInt();
|
||||
short slotNum = buf.readShort();
|
||||
byte buttonNum = buf.readByte();
|
||||
int clickType = buf.readVarInt();
|
||||
int i = buf.readVarInt();
|
||||
Int2ObjectMap<Object> changedSlots = new Int2ObjectOpenHashMap<>(i);
|
||||
for (int j = 0; j < i; ++j) {
|
||||
int k = buf.readShort();
|
||||
Object hashedStack = FastNMS.INSTANCE.method$StreamDecoder$decode(NetworkReflections.instance$HashedStack$STREAM_CODEC, friendlyBuf);
|
||||
Object serverSideItemStack = FastNMS.INSTANCE.method$Container$getItem(inventory, k);
|
||||
Optional<ItemStack> optional = BukkitItemManager.instance().s2c(FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(serverSideItemStack), ((net.momirealms.craftengine.core.entity.player.Player) user));
|
||||
if (optional.isPresent()) {
|
||||
Object clientSideItemStack = FastNMS.INSTANCE.field$CraftItemStack$handle(optional.get());
|
||||
boolean isSync = FastNMS.INSTANCE.method$HashedStack$matches(hashedStack, clientSideItemStack, BukkitItemManager.instance().decoratedHashOpsGenerator());
|
||||
if (isSync) {
|
||||
changed = true;
|
||||
hashedStack = FastNMS.INSTANCE.method$HashedStack$create(clientSideItemStack, null);
|
||||
}
|
||||
}
|
||||
changedSlots.put(k, hashedStack);
|
||||
}
|
||||
Object carriedHashedStack = FastNMS.INSTANCE.method$StreamDecoder$decode(NetworkReflections.instance$HashedStack$STREAM_CODEC, friendlyBuf);
|
||||
Object containerMenu = FastNMS.INSTANCE.field$Player$containerMenu(user.serverPlayer());
|
||||
Object serverSideCarriedItemStack = FastNMS.INSTANCE.method$AbstractContainerMenu$getCarried(containerMenu);
|
||||
Optional<ItemStack> optional = BukkitItemManager.instance().s2c(FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(serverSideCarriedItemStack), ((net.momirealms.craftengine.core.entity.player.Player) user));
|
||||
if (optional.isPresent()) {
|
||||
Object clientSideCarriedItemStack = FastNMS.INSTANCE.field$CraftItemStack$handle(optional.get());
|
||||
boolean isSync = FastNMS.INSTANCE.method$HashedStack$matches(carriedHashedStack, clientSideCarriedItemStack, BukkitItemManager.instance().decoratedHashOpsGenerator());
|
||||
if (isSync) {
|
||||
changed = true;
|
||||
carriedHashedStack = FastNMS.INSTANCE.method$HashedStack$create(clientSideCarriedItemStack, BukkitItemManager.instance().decoratedHashOpsGenerator());
|
||||
}
|
||||
}
|
||||
if (changed) {
|
||||
event.setChanged(true);
|
||||
buf.clear();
|
||||
buf.writeVarInt(event.packetID());
|
||||
buf.writeContainerId(containerId);
|
||||
buf.writeVarInt(stateId);
|
||||
buf.writeShort(slotNum);
|
||||
buf.writeByte(buttonNum);
|
||||
buf.writeVarInt(clickType);
|
||||
buf.writeVarInt(changedSlots.size());
|
||||
Object newFriendlyBuf = FastNMS.INSTANCE.constructor$FriendlyByteBuf(buf);
|
||||
changedSlots.forEach((k, v) -> {
|
||||
buf.writeShort(k);
|
||||
FastNMS.INSTANCE.method$StreamEncoder$encode(NetworkReflections.instance$HashedStack$STREAM_CODEC, newFriendlyBuf, v);
|
||||
});
|
||||
FastNMS.INSTANCE.method$StreamEncoder$encode(NetworkReflections.instance$HashedStack$STREAM_CODEC, newFriendlyBuf, carriedHashedStack);
|
||||
}
|
||||
return;
|
||||
}
|
||||
FriendlyByteBuf buf = event.getBuffer();
|
||||
boolean changed = false;
|
||||
Object friendlyBuf = FastNMS.INSTANCE.constructor$FriendlyByteBuf(buf);
|
||||
|
||||
@@ -3850,4 +3850,27 @@ public final class CoreReflections {
|
||||
CoreReflections.clazz$BlockHitResult, CoreReflections.clazz$Vec3, CoreReflections.clazz$Direction, CoreReflections.clazz$BlockPos, boolean.class
|
||||
)
|
||||
);
|
||||
|
||||
public static final Class<?> clazz$HashOps = MiscUtils.requireNonNullIf(
|
||||
ReflectionUtils.getClazz(BukkitReflectionUtils.assembleMCClass("util.HashOps")),
|
||||
VersionHelper.isOrAbove1_21_5()
|
||||
);
|
||||
|
||||
public static final Field field$HashOps$CRC32C_INSTANCE = Optional.ofNullable(clazz$HashOps)
|
||||
.map(it -> ReflectionUtils.getDeclaredField(it, it, 0))
|
||||
.orElse(null);
|
||||
|
||||
public static final Object instance$HashOps$CRC32C_INSTANCE;
|
||||
|
||||
static {
|
||||
try {
|
||||
if (VersionHelper.isOrAbove1_21_5()) {
|
||||
instance$HashOps$CRC32C_INSTANCE = field$HashOps$CRC32C_INSTANCE.get(null);
|
||||
} else {
|
||||
instance$HashOps$CRC32C_INSTANCE = null;
|
||||
}
|
||||
} catch (ReflectiveOperationException e) {
|
||||
throw new ReflectionInitException("Failed to initialize HashOps", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package net.momirealms.craftengine.bukkit.plugin.reflection.minecraft;
|
||||
|
||||
import com.google.common.hash.HashCode;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.mojang.serialization.DynamicOps;
|
||||
import com.mojang.serialization.JsonOps;
|
||||
@@ -12,6 +13,7 @@ import net.momirealms.sparrow.nbt.Tag;
|
||||
import net.momirealms.sparrow.nbt.codec.LegacyJavaOps;
|
||||
import net.momirealms.sparrow.nbt.codec.LegacyNBTOps;
|
||||
import net.momirealms.sparrow.nbt.codec.NBTOps;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
@@ -21,6 +23,7 @@ public final class MRegistryOps {
|
||||
public static final DynamicOps<Tag> SPARROW_NBT;
|
||||
public static final DynamicOps<Object> JAVA;
|
||||
public static final DynamicOps<JsonElement> JSON;
|
||||
public static final @Nullable("仅在 1.21.5+ 有") DynamicOps<HashCode> HASHCODE;
|
||||
|
||||
// 1.20.5+
|
||||
public static final Class<?> clazz$JavaOps = ReflectionUtils.getClazz("com.mojang.serialization.JavaOps");
|
||||
@@ -47,6 +50,7 @@ public final class MRegistryOps {
|
||||
NBT = (DynamicOps<Object>) CoreReflections.method$RegistryOps$create.invoke(null, ReflectionUtils.getDeclaredField(clazz$NbtOps, clazz$NbtOps, 0).get(null), FastNMS.INSTANCE.registryAccess());
|
||||
JSON = (DynamicOps<JsonElement>) CoreReflections.method$RegistryOps$create.invoke(null, JsonOps.INSTANCE, FastNMS.INSTANCE.registryAccess());
|
||||
SPARROW_NBT = (DynamicOps<Tag>) CoreReflections.method$RegistryOps$create.invoke(null, VersionHelper.isOrAbove1_20_5() ? NBTOps.INSTANCE : LegacyNBTOps.INSTANCE, FastNMS.INSTANCE.registryAccess());
|
||||
HASHCODE = VersionHelper.isOrAbove1_21_5() ? (DynamicOps<HashCode>) CoreReflections.method$RegistryOps$create.invoke(null, CoreReflections.instance$HashOps$CRC32C_INSTANCE, FastNMS.INSTANCE.registryAccess()) : null;
|
||||
} catch (ReflectiveOperationException e) {
|
||||
throw new ReflectionInitException("Failed to init DynamicOps", e);
|
||||
}
|
||||
|
||||
@@ -1594,4 +1594,31 @@ public final class NetworkReflections {
|
||||
List.of("network.protocol.common.ClientboundUpdateTagsPacket", "network.protocol.game.ClientboundUpdateTagsPacket")
|
||||
)
|
||||
);
|
||||
|
||||
// 1.21.5+
|
||||
public static final Class<?> clazz$HashedStack = MiscUtils.requireNonNullIf(
|
||||
ReflectionUtils.getClazz(
|
||||
BukkitReflectionUtils.assembleMCClass("network.HashedStack")
|
||||
),
|
||||
VersionHelper.isOrAbove1_21_5()
|
||||
);
|
||||
|
||||
// 1.21.5+
|
||||
public static final Field field$HashedStack$STREAM_CODEC = Optional.ofNullable(clazz$HashedStack)
|
||||
.map(it -> ReflectionUtils.getDeclaredField(it, clazz$StreamCodec, 0))
|
||||
.orElse(null);
|
||||
|
||||
public static final Object instance$HashedStack$STREAM_CODEC;
|
||||
|
||||
static {
|
||||
try {
|
||||
if (VersionHelper.isOrAbove1_21_5()) {
|
||||
instance$HashedStack$STREAM_CODEC = field$HashedStack$STREAM_CODEC.get(null);
|
||||
} else {
|
||||
instance$HashedStack$STREAM_CODEC = null;
|
||||
}
|
||||
} catch (ReflectiveOperationException e) {
|
||||
throw new ReflectionInitException("Failed to initialize HashedStack$STREAM_CODEC", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user