9
0
mirror of https://github.com/Xiao-MoMi/craft-engine.git synced 2026-01-04 15:41:38 +00:00

feat(bukkit): 进一步完善

- 1.20 ~ 1.21.1 可以正常移动 1.21.2+ 需要补包
- 附魔的三叉戟和世界上有的三叉戟玩家离开再回来无法显示
This commit is contained in:
jhqwqmc
2025-05-08 06:21:06 +08:00
parent d15397bcb5
commit 33f96267b3
5 changed files with 150 additions and 25 deletions

View File

@@ -1,8 +1,11 @@
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.core.item.Item;
import net.momirealms.craftengine.core.plugin.CraftEngine;
import net.momirealms.craftengine.core.plugin.command.CraftEngineCommandManager;
import net.momirealms.craftengine.core.util.Key;
import org.bukkit.Material;
import org.bukkit.NamespacedKey;
import org.bukkit.command.CommandSender;
@@ -14,12 +17,12 @@ import org.incendo.cloud.Command;
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.ByteParser;
import org.incendo.cloud.parser.standard.IntegerParser;
import org.incendo.cloud.suggestion.Suggestion;
import org.incendo.cloud.suggestion.SuggestionProvider;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
public class TestCommand extends BukkitCommandFeature<CommandSender> {
@@ -29,6 +32,7 @@ public class TestCommand extends BukkitCommandFeature<CommandSender> {
}
@Override
@SuppressWarnings("deprecation")
public Command.Builder<? extends CommandSender> assembleCommand(org.incendo.cloud.CommandManager<CommandSender> manager, Command.Builder<CommandSender> builder) {
return builder
.senderType(Player.class)
@@ -41,22 +45,37 @@ public class TestCommand extends BukkitCommandFeature<CommandSender> {
.required("interpolationDelay", IntegerParser.integerParser())
.required("transformationInterpolationDuration", IntegerParser.integerParser())
.required("positionRotationInterpolationDuration", IntegerParser.integerParser())
.required("displayType", ByteParser.byteParser())
// .required("displayType", ByteParser.byteParser())
// .required("x", FloatParser.floatParser())
// .required("y", FloatParser.floatParser())
// .required("z", FloatParser.floatParser())
// .required("w", FloatParser.floatParser())
.handler(context -> {
Player player = context.sender();
NamespacedKey namespacedKey = context.get("id");
var item = ItemStack.of(Material.TRIDENT);
ItemStack item = new ItemStack(Material.TRIDENT);
NamespacedKey customTridentKey = Objects.requireNonNull(NamespacedKey.fromString("craftengine:custom_trident"));
NamespacedKey interpolationDelayKey = Objects.requireNonNull(NamespacedKey.fromString("craftengine:interpolation_delay"));
NamespacedKey transformationInterpolationDurationaKey = Objects.requireNonNull(NamespacedKey.fromString("craftengine:transformation_interpolation_duration"));
NamespacedKey positionRotationInterpolationDurationKey = Objects.requireNonNull(NamespacedKey.fromString("craftengine:position_rotation_interpolation_duration"));
NamespacedKey displayTypeKey = Objects.requireNonNull(NamespacedKey.fromString("craftengine:display_type"));
item.editPersistentDataContainer(container -> {
container.set(customTridentKey, PersistentDataType.STRING, namespacedKey.asString());
container.set(interpolationDelayKey, PersistentDataType.INTEGER, context.get("interpolationDelay"));
container.set(transformationInterpolationDurationaKey, PersistentDataType.INTEGER, context.get("transformationInterpolationDuration"));
container.set(positionRotationInterpolationDurationKey, PersistentDataType.INTEGER, context.get("positionRotationInterpolationDuration"));
container.set(displayTypeKey, PersistentDataType.BYTE, context.get("displayType"));
// NamespacedKey displayTypeKey = Objects.requireNonNull(NamespacedKey.fromString("craftengine:display_type"));
// NamespacedKey customTridentX = Objects.requireNonNull(NamespacedKey.fromString("craftengine:custom_trident_x"));
// NamespacedKey customTridentY = Objects.requireNonNull(NamespacedKey.fromString("craftengine:custom_trident_y"));
// NamespacedKey customTridentZ = Objects.requireNonNull(NamespacedKey.fromString("craftengine:custom_trident_z"));
// NamespacedKey customTridentW = Objects.requireNonNull(NamespacedKey.fromString("craftengine:custom_trident_w"));
item.editMeta(meta -> {
meta.getPersistentDataContainer().set(customTridentKey, PersistentDataType.STRING, namespacedKey.asString());
meta.getPersistentDataContainer().set(interpolationDelayKey, PersistentDataType.INTEGER, context.get("interpolationDelay"));
meta.getPersistentDataContainer().set(transformationInterpolationDurationaKey, PersistentDataType.INTEGER, context.get("transformationInterpolationDuration"));
meta.getPersistentDataContainer().set(positionRotationInterpolationDurationKey, PersistentDataType.INTEGER, context.get("positionRotationInterpolationDuration"));
// container.set(displayTypeKey, PersistentDataType.BYTE, context.get("displayType"));
// container.set(customTridentX, PersistentDataType.FLOAT, context.get("x"));
// container.set(customTridentY, PersistentDataType.FLOAT, context.get("y"));
// container.set(customTridentZ, PersistentDataType.FLOAT, context.get("z"));
// container.set(customTridentW, PersistentDataType.FLOAT, context.get("w"));
Item<ItemStack> ceItem = BukkitItemManager.instance().createWrappedItem(Key.of(namespacedKey.asString()), null);
Optional<Integer> customModelData = ceItem.customModelData();
customModelData.ifPresent(meta::setCustomModelData);
});
player.getInventory().addItem(item);
});

View File

@@ -153,6 +153,7 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes
registerNMSPacketConsumer(PacketConsumers.RESOURCE_PACK_RESPONSE, Reflections.clazz$ServerboundResourcePackPacket);
registerNMSPacketConsumer(PacketConsumers.ENTITY_EVENT, Reflections.clazz$ClientboundEntityEventPacket);
registerNMSPacketConsumer(PacketConsumers.SET_ENTITY_DATA, Reflections.clazz$ClientboundSetEntityDataPacket);
registerNMSPacketConsumer(PacketConsumers.MOVE_ENTITY_ALL, Reflections.clazz$ClientboundMoveEntityPacket$PosRot);
registerByteBufPacketConsumer(PacketConsumers.LEVEL_CHUNK_WITH_LIGHT, this.packetIds.clientboundLevelChunkWithLightPacket());
registerByteBufPacketConsumer(PacketConsumers.SECTION_BLOCK_UPDATE, this.packetIds.clientboundSectionBlocksUpdatePacket());
registerByteBufPacketConsumer(PacketConsumers.BLOCK_UPDATE, this.packetIds.clientboundBlockUpdatePacket());

View File

@@ -3,7 +3,6 @@ package net.momirealms.craftengine.bukkit.plugin.network;
import com.mojang.datafixers.util.Either;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.papermc.paper.persistence.PersistentDataContainerView;
import it.unimi.dsi.fastutil.ints.IntList;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.TranslationArgument;
@@ -56,10 +55,13 @@ import org.bukkit.entity.Player;
import org.bukkit.entity.Trident;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.PlayerInventory;
import org.bukkit.persistence.PersistentDataContainer;
import org.bukkit.persistence.PersistentDataType;
import org.bukkit.util.RayTraceResult;
import org.bukkit.util.Vector;
import org.jetbrains.annotations.Nullable;
import org.joml.Quaternionf;
import org.joml.Vector3f;
import java.lang.reflect.InvocationTargetException;
import java.nio.charset.StandardCharsets;
@@ -1616,23 +1618,28 @@ public class PacketConsumers {
int entityId = FastNMS.INSTANCE.field$ClientboundAddEntityPacket$entityId(packet);
Player player = (Player) user.platformPlayer();
Trident trident = (Trident) FastNMS.INSTANCE.getBukkitEntityById(player.getWorld(), entityId);
PersistentDataContainerView container = trident.getItemStack().getPersistentDataContainer();
PersistentDataContainer container = trident.getItemStack().getItemMeta().getPersistentDataContainer();
NamespacedKey customTridentKey = Objects.requireNonNull(NamespacedKey.fromString("craftengine:custom_trident"));
String customTrident = container.get(customTridentKey, PersistentDataType.STRING);
if (customTrident == null) return;
user.tridentView().put(entityId, List.of());
NamespacedKey interpolationDelayKey = Objects.requireNonNull(NamespacedKey.fromString("craftengine:interpolation_delay"));
NamespacedKey transformationInterpolationDurationaKey = Objects.requireNonNull(NamespacedKey.fromString("craftengine:transformation_interpolation_duration"));
NamespacedKey positionRotationInterpolationDurationKey = Objects.requireNonNull(NamespacedKey.fromString("craftengine:position_rotation_interpolation_duration"));
NamespacedKey displayTypeKey = Objects.requireNonNull(NamespacedKey.fromString("craftengine:display_type"));
String customTrident = container.get(customTridentKey, PersistentDataType.STRING);
Integer interpolationDelay = container.get(interpolationDelayKey, PersistentDataType.INTEGER);
Integer transformationInterpolationDuration = container.get(transformationInterpolationDurationaKey, PersistentDataType.INTEGER);
Integer positionRotationInterpolationDuration = container.get(positionRotationInterpolationDurationKey, PersistentDataType.INTEGER);
Byte displayType = container.get(displayTypeKey, PersistentDataType.BYTE);
if (customTrident == null) return;
float yRot = MCUtils.unpackDegrees(Reflections.field$ClientboundAddEntityPacket$yRot.getByte(packet));
float xRot = MCUtils.unpackDegrees(Reflections.field$ClientboundAddEntityPacket$xRot.getByte(packet));
player.sendMessage("加载自定义三叉戟实体1: " + packet);
Reflections.field$ClientboundAddEntityPacket$type.set(packet, Reflections.instance$EntityType$ITEM_DISPLAY);
// System.out.println(packet);
Reflections.field$ClientboundAddEntityPacket$yRot.setByte(packet, MCUtils.packDegrees(-yRot));
Reflections.field$ClientboundAddEntityPacket$xRot.setByte(packet, MCUtils.packDegrees(Math.clamp(-xRot, -90.0F, 90.0F)));
List<Object> itemDisplayValues = new ArrayList<>();
Item<ItemStack> item = BukkitItemManager.instance().createWrappedItem(Key.of(customTrident), null);
ItemDisplayEntityData.InterpolationDelay.addEntityDataIfNotDefaultValue(interpolationDelay, itemDisplayValues);
ItemDisplayEntityData.Translation.addEntityDataIfNotDefaultValue(new Vector3f(0, 0, -2), itemDisplayValues);
ItemDisplayEntityData.RotationLeft.addEntityDataIfNotDefaultValue(new Quaternionf(1, 1, 1, 1), itemDisplayValues);
if (VersionHelper.isOrAbove1_20_2()) {
ItemDisplayEntityData.TransformationInterpolationDuration.addEntityDataIfNotDefaultValue(transformationInterpolationDuration, itemDisplayValues);
ItemDisplayEntityData.PositionRotationInterpolationDuration.addEntityDataIfNotDefaultValue(positionRotationInterpolationDuration, itemDisplayValues);
@@ -1640,10 +1647,12 @@ public class PacketConsumers {
ItemDisplayEntityData.InterpolationDuration.addEntityDataIfNotDefaultValue(transformationInterpolationDuration, itemDisplayValues);
}
ItemDisplayEntityData.DisplayedItem.addEntityDataIfNotDefaultValue(item.getLiteralObject(), itemDisplayValues);
ItemDisplayEntityData.DisplayType.addEntityDataIfNotDefaultValue(displayType, itemDisplayValues);
ItemDisplayEntityData.DisplayType.addEntityDataIfNotDefaultValue((byte) 0, itemDisplayValues);
user.tridentView().put(entityId, itemDisplayValues);
player.sendMessage("加载自定义三叉戟实体2: " + entityId);
event.addDelayedTask(() -> {
user.sendPacket(FastNMS.INSTANCE.constructor$ClientboundSetEntityDataPacket(entityId, itemDisplayValues), true);
player.sendMessage("加载自定义三叉戟实体3: " + itemDisplayValues);
});
}
} catch (Exception e) {
@@ -1651,14 +1660,22 @@ public class PacketConsumers {
}
};
// 1.21.3+
// 1.21.2+
public static final TriConsumer<NetWorkUser, NMSPacketEvent, Object> SYNC_ENTITY_POSITION = (user, event, packet) -> {
try {
int entityId = FastNMS.INSTANCE.method$ClientboundEntityPositionSyncPacket$id(packet);
if (user.tridentView().containsKey(entityId)) {
if (!VersionHelper.isOrAbove1_21_3()) return;
Object values = Reflections.field$ClientboundEntityPositionSyncPacket$values.get(packet);
// Bukkit.getOnlinePlayers().forEach(player -> player.sendMessage("Sync entity position: " + values));
Player player = (Player) user.platformPlayer();
player.sendMessage("同步三叉戟实体位置: " + packet);
Object positionMoveRotation = Reflections.field$ClientboundEntityPositionSyncPacket$values.get(packet);
boolean onGround = Reflections.field$ClientboundEntityPositionSyncPacket$onGround.getBoolean(packet);
Object position = Reflections.field$PositionMoveRotation$position.get(positionMoveRotation);
Object deltaMovement = Reflections.field$PositionMoveRotation$deltaMovement.get(positionMoveRotation);
float yRot = Reflections.field$PositionMoveRotation$yRot.getFloat(positionMoveRotation);
float xRot = Reflections.field$PositionMoveRotation$xRot.getFloat(positionMoveRotation);
Object newPositionMoveRotation = Reflections.constructor$PositionMoveRotation.newInstance(position, deltaMovement, -yRot, Math.clamp(-xRot, -90.0F, 90.0F));
event.replacePacket(Reflections.constructor$ClientboundEntityPositionSyncPacket.newInstance(entityId, newPositionMoveRotation, onGround));
return;
}
if (BukkitFurnitureManager.instance().isFurnitureRealEntity(entityId)) {
event.setCancelled(true);
@@ -1688,7 +1705,11 @@ public class PacketConsumers {
int entityId = intList.getInt(i);
user.entityView().remove(entityId);
List<Integer> entities = user.furnitureView().remove(entityId);
user.tridentView().remove(entityId);
var removeTrident = user.tridentView().remove(entityId);
if (removeTrident != null && !removeTrident.isEmpty()) {
Player player = (Player) user.platformPlayer();
player.sendMessage("移除三叉戟实体: " + removeTrident);
}
if (entities == null) continue;
for (int subEntityId : entities) {
isChange = true;
@@ -2367,10 +2388,29 @@ public class PacketConsumers {
try {
int entityId = Reflections.field$clazz$ClientboundSetEntityDataPacket$id.getInt(packet);
if (user.tridentView().containsKey(entityId)) {
event.replacePacket(FastNMS.INSTANCE.constructor$ClientboundSetEntityDataPacket(entityId, user.tridentView().get(entityId)));
Player player = (Player) user.platformPlayer();
Object newPacket = FastNMS.INSTANCE.constructor$ClientboundSetEntityDataPacket(entityId, user.tridentView().get(entityId));
player.sendMessage("设置三叉戟实体数据: " + newPacket);
event.replacePacket(newPacket);
}
} catch (Exception e) {
CraftEngine.instance().logger().warn("Failed to handle ClientboundSetEntityDataPacket", e);
}
};
public static final TriConsumer<NetWorkUser, NMSPacketEvent, Object> MOVE_ENTITY_ALL = (user, event, packet) -> {
try {
int entityId = BukkitInjector.internalFieldAccessor().field$ClientboundMoveEntityPacket$entityId(packet);
if (user.tridentView().containsKey(entityId)) {
float xRot = MCUtils.unpackDegrees(Reflections.field$ClientboundMoveEntityPacket$xRot.getByte(packet));
float yRot = MCUtils.unpackDegrees(Reflections.field$ClientboundMoveEntityPacket$yRot.getByte(packet));
Reflections.field$ClientboundMoveEntityPacket$xRot.setByte(packet, MCUtils.packDegrees(Math.clamp(-xRot, -90.0F, 90.0F)));
Reflections.field$ClientboundMoveEntityPacket$yRot.setByte(packet, MCUtils.packDegrees(-yRot));
Player player = (Player) user.platformPlayer();
player.sendMessage("同步三叉戟实体位置: " + Math.clamp(-xRot, -90.0F, 90.0F) + ", " + -yRot);
}
} catch (Exception e) {
CraftEngine.instance().logger().warn("Failed to handle ClientboundMoveEntityPacket$PosRot", e);
}
};
}

View File

@@ -3984,7 +3984,7 @@ public class Reflections {
)
);
// 1.21.3+
// 1.21.2+
public static final Class<?> clazz$ClientboundEntityPositionSyncPacket =
ReflectionUtils.getClazz(
BukkitReflectionUtils.assembleMCClass("network.protocol.game.ClientboundEntityPositionSyncPacket")
@@ -6635,16 +6635,68 @@ public class Reflections {
BukkitReflectionUtils.assembleMCClass("world.entity.PositionMoveRotation")
);
public static final Constructor<?> constructor$PositionMoveRotation = Optional.ofNullable(clazz$PositionMoveRotation)
.map(it -> ReflectionUtils.getTheOnlyConstructor(it))
.orElse(null);
public static final Field field$ClientboundEntityPositionSyncPacket$values = Optional.ofNullable(clazz$ClientboundEntityPositionSyncPacket)
.map(it -> ReflectionUtils.getInstanceDeclaredField(it, clazz$PositionMoveRotation, 0))
.orElse(null);
public static final Field field$ClientboundEntityPositionSyncPacket$onGround = Optional.ofNullable(clazz$ClientboundEntityPositionSyncPacket)
.map(it -> ReflectionUtils.getInstanceDeclaredField(it, boolean.class, 0))
.orElse(null);
public static final Field field$PositionMoveRotation$position = Optional.ofNullable(clazz$PositionMoveRotation)
.map(it -> ReflectionUtils.getInstanceDeclaredField(it, clazz$Vec3, 0))
.orElse(null);
public static final Field field$PositionMoveRotation$deltaMovement = Optional.ofNullable(clazz$PositionMoveRotation)
.map(it -> ReflectionUtils.getInstanceDeclaredField(it, clazz$Vec3, 1))
.orElse(null);
public static final Field field$PositionMoveRotation$yRot = Optional.ofNullable(clazz$PositionMoveRotation)
.map(it -> ReflectionUtils.getInstanceDeclaredField(it, float.class, 0))
.orElse(null);
public static final Field field$PositionMoveRotation$xRot = Optional.ofNullable(clazz$PositionMoveRotation)
.map(it -> ReflectionUtils.getInstanceDeclaredField(it, float.class, 1))
.orElse(null);
public static final Class<?> clazz$ClientboundTeleportEntityPacket = requireNonNull(
BukkitReflectionUtils.findReobfOrMojmapClass(
"network.protocol.game.PacketPlayOutEntityTeleport",
"network.protocol.game.ClientboundTeleportEntityPacket"
)
);
public static final Constructor<?> constructor$ClientboundEntityPositionSyncPacket = Optional.ofNullable(clazz$ClientboundEntityPositionSyncPacket)
.map(it -> ReflectionUtils.getTheOnlyConstructor(it))
.orElse(null);
public static final Field field$ClientboundAddEntityPacket$xRot = requireNonNull(
ReflectionUtils.getDeclaredField(
clazz$ClientboundAddEntityPacket, byte.class, 0
)
);
public static final Field field$ClientboundAddEntityPacket$yRot = requireNonNull(
ReflectionUtils.getDeclaredField(
clazz$ClientboundAddEntityPacket, byte.class, 1
)
);
public static final Field field$ClientboundMoveEntityPacket$xRot = requireNonNull(
ReflectionUtils.getDeclaredField(
clazz$ClientboundMoveEntityPacket, byte.class, 1
)
);
public static final Field field$ClientboundMoveEntityPacket$yRot = requireNonNull(
ReflectionUtils.getDeclaredField(
clazz$ClientboundMoveEntityPacket, byte.class, 0
)
);
//
// /**
// * 实体移动数据包