9
0
mirror of https://github.com/Xiao-MoMi/craft-engine.git synced 2025-12-19 15:09:15 +00:00

Merge pull request #212 from jhqwqmc/dev

perf(entity): 优化网络包处理
This commit is contained in:
XiaoMoMi
2025-06-09 02:28:26 +08:00
committed by GitHub
24 changed files with 439 additions and 113 deletions

View File

@@ -7,20 +7,21 @@ public interface EntityData<T> {
Object serializer();
int id();
T defaultValue();
Object entityDataAccessor();
default Object createEntityDataIfNotDefaultValue(T value) {
if (defaultValue().equals(value)) return null;
return EntityDataValue.create(id(), serializer(), value);
return EntityDataValue.create(id(), serializer(), entityDataAccessor(), value);
}
default void addEntityDataIfNotDefaultValue(T value, List<Object> list) {
if (!defaultValue().equals(value)) {
list.add(EntityDataValue.create(id(), serializer(), value));
list.add(EntityDataValue.create(id(), serializer(), entityDataAccessor(), value));
}
}
default void addEntityData(T value, List<Object> list) {
list.add(EntityDataValue.create(id(), serializer(), value));
list.add(EntityDataValue.create(id(), serializer(), entityDataAccessor(), value));
}
static <T> EntityData<T> of(int id, Object serializer, T defaultValue) {

View File

@@ -98,8 +98,7 @@ public class EntityDataValue {
throw new IllegalAccessError("Utility class");
}
public static Object create(int id, Object serializer, Object value) {
Object entityDataAccessor = FastNMS.INSTANCE.constructor$EntityDataAccessor(id, serializer);
public static Object create(int id, Object serializer, Object entityDataAccessor, Object value) {
return FastNMS.INSTANCE.method$SynchedEntityData$DataValue$create(entityDataAccessor, value);
}
}

View File

@@ -1,14 +1,18 @@
package net.momirealms.craftengine.bukkit.entity.data;
import net.momirealms.craftengine.bukkit.nms.FastNMS;
public class SimpleEntityData<T> implements EntityData<T> {
private final int id;
private final Object serializer;
private final T defaultValue;
private final Object entityDataAccessor;
public SimpleEntityData(int id, Object serializer, T defaultValue) {
this.id = id;
this.serializer = serializer;
this.defaultValue = defaultValue;
this.entityDataAccessor = FastNMS.INSTANCE.constructor$EntityDataAccessor(id, serializer);
}
@Override
@@ -25,4 +29,9 @@ public class SimpleEntityData<T> implements EntityData<T> {
public T defaultValue() {
return defaultValue;
}
@Override
public Object entityDataAccessor() {
return entityDataAccessor;
}
}

View File

@@ -28,6 +28,7 @@ import org.joml.Vector3f;
import java.io.IOException;
import java.lang.ref.WeakReference;
import java.util.*;
import java.util.function.Consumer;
public class BukkitFurniture implements Furniture {
private final Key id;
@@ -130,6 +131,7 @@ public class BukkitFurniture implements Furniture {
Object world = FastNMS.INSTANCE.field$CraftWorld$ServerLevel(this.location.getWorld());
for (Collider entity : this.colliderEntities) {
FastNMS.INSTANCE.method$LevelWriter$addFreshEntity(world, entity.handle());
injectFurnitureEntity(entity.handle());
Entity bukkitEntity = FastNMS.INSTANCE.method$Entity$getBukkitEntity(entity.handle());
bukkitEntity.getPersistentDataContainer().set(BukkitFurnitureManager.FURNITURE_COLLISION, PersistentDataType.BYTE, (byte) 1);
}
@@ -359,4 +361,24 @@ public class BukkitFurniture implements Furniture {
newLocation.add(offset.x, offset.y + 0.6, -offset.z);
return newLocation;
}
public static void injectFurnitureEntity(Object nmsEntity) {
try {
Object trackedEntity = FastNMS.INSTANCE.field$Entity$trackedEntity(nmsEntity);
Object serverEntity = FastNMS.INSTANCE.filed$ChunkMap$TrackedEntity$serverEntity(trackedEntity);
CoreReflections.handle$ServerEntity$broadcastSetter.invokeExact(serverEntity, Handlers.DO_NOTHING);
CoreReflections.handle$ServerEntity$updateIntervalSetter.invokeExact(serverEntity, Integer.MAX_VALUE);
} catch (Throwable e) {
CraftEngine.instance().logger().warn("Failed to inject collider", e);
}
}
@FunctionalInterface
public interface Handlers extends Consumer<Object> {
Consumer<Object> DO_NOTHING = doNothing();
static Handlers doNothing() {
return (packet) -> {};
}
}
}

View File

@@ -86,6 +86,7 @@ public class BukkitFurnitureManager extends AbstractFurnitureManager {
SoundData data = furniture.settings().sounds().placeSound();
location.getWorld().playSound(location, data.id().toString(), SoundCategory.BLOCKS, data.volume(), data.pitch());
}
BukkitFurniture.injectFurnitureEntity(FastNMS.INSTANCE.method$CraftEntity$getHandle(furnitureEntity));
return loadedFurnitureByRealEntityId(furnitureEntity.getEntityId());
}
@@ -101,6 +102,7 @@ public class BukkitFurnitureManager extends AbstractFurnitureManager {
for (Entity entity : entities) {
if (entity instanceof ItemDisplay display) {
handleBaseEntityLoadEarly(display);
BukkitFurniture.injectFurnitureEntity(FastNMS.INSTANCE.method$CraftEntity$getHandle(display));
} else if (entity instanceof Interaction interaction) {
handleCollisionEntityLoadOnEntitiesLoad(interaction);
} else if (entity instanceof Boat boat) {
@@ -208,6 +210,7 @@ public class BukkitFurnitureManager extends AbstractFurnitureManager {
furniture.initializeColliders();
}
}
BukkitFurniture.injectFurnitureEntity(FastNMS.INSTANCE.method$CraftEntity$getHandle(display));
if (depth > 2) return;
this.plugin.scheduler().sync().runLater(() -> handleBaseEntityLoadLate(display, depth + 1), 1, location.getWorld(), location.getBlockX() >> 4, location.getBlockZ() >> 4);
}

View File

@@ -2,6 +2,7 @@ package net.momirealms.craftengine.bukkit.entity.furniture;
import com.destroystokyo.paper.event.entity.EntityAddToWorldEvent;
import com.destroystokyo.paper.event.entity.EntityRemoveFromWorldEvent;
import net.momirealms.craftengine.bukkit.nms.FastNMS;
import org.bukkit.entity.ArmorStand;
import org.bukkit.entity.Entity;
import org.bukkit.entity.ItemDisplay;
@@ -36,6 +37,7 @@ public class FurnitureEventListener implements Listener {
for (Entity entity : entities) {
if (entity instanceof ItemDisplay itemDisplay) {
this.manager.handleBaseEntityLoadEarly(itemDisplay);
BukkitFurniture.injectFurnitureEntity(FastNMS.INSTANCE.method$CraftEntity$getHandle(itemDisplay));
} else if (BukkitFurnitureManager.COLLISION_ENTITY_CLASS.isInstance(entity)) {
this.manager.handleCollisionEntityLoadOnEntitiesLoad(entity);
}
@@ -48,6 +50,7 @@ public class FurnitureEventListener implements Listener {
for (Entity entity : entities) {
if (entity instanceof ItemDisplay itemDisplay) {
this.manager.handleBaseEntityLoadEarly(itemDisplay);
BukkitFurniture.injectFurnitureEntity(FastNMS.INSTANCE.method$CraftEntity$getHandle(itemDisplay));
} else if (BukkitFurnitureManager.COLLISION_ENTITY_CLASS.isInstance(entity)) {
this.manager.handleCollisionEntityLoadOnEntitiesLoad(entity);
}

View File

@@ -161,7 +161,10 @@ public class BukkitProjectileManager implements Listener, ProjectileManager {
public class ProjectileInjectTask implements Runnable {
private final Projectile projectile;
private final SchedulerTask task;
private Object cachedServerEntity;
private boolean injected;
private int lastInjectedInterval = -1;
private boolean wasInGround;
public ProjectileInjectTask(Projectile projectile) {
this.projectile = projectile;
@@ -180,30 +183,49 @@ public class BukkitProjectileManager implements Listener, ProjectileManager {
}
Object nmsEntity = FastNMS.INSTANCE.method$CraftEntity$getHandle(this.projectile);
if (!this.injected) {
Object trackedEntity = FastNMS.INSTANCE.field$Entity$trackedEntity(nmsEntity);
if (trackedEntity == null) {
return;
}
Object serverEntity = FastNMS.INSTANCE.filed$ChunkMap$TrackedEntity$serverEntity(trackedEntity);
if (serverEntity == null) {
return;
}
try {
CoreReflections.field$ServerEntity$updateInterval.set(serverEntity, 1);
this.injected = true;
} catch (ReflectiveOperationException e) {
plugin.logger().warn("Failed to update server entity tracking interval", e);
}
injectProjectile(nmsEntity, 1);
this.injected = true;
this.lastInjectedInterval = 1;
}
if (canSpawnParticle(nmsEntity)) {
boolean inGround = FastNMS.INSTANCE.method$AbstractArrow$isInGround(nmsEntity);
if (canSpawnParticle(nmsEntity, inGround)) {
this.projectile.getWorld().spawnParticle(ParticleUtils.BUBBLE, this.projectile.getLocation(), 3, 0.1, 0.1, 0.1, 0);
}
projectileByEntityId(this.projectile.getEntityId()).ifPresent(customProjectile -> {
customProjectile.setInGroundTime(inGround ? customProjectile.inGroundTime() + 1 : 0);
if (customProjectile.inGroundTime() > 5) {
if (lastInjectedInterval != Integer.MAX_VALUE) {
injectProjectile(nmsEntity, Integer.MAX_VALUE);
}
} else if (!inGround && wasInGround) {
if (lastInjectedInterval != 1) {
injectProjectile(nmsEntity, 1);
}
}
this.wasInGround = inGround;
});
}
private void injectProjectile(Object entity, int updateInterval) {
if (this.cachedServerEntity == null) {
Object trackedEntity = FastNMS.INSTANCE.field$Entity$trackedEntity(entity);
if (trackedEntity == null) return;
Object serverEntity = FastNMS.INSTANCE.filed$ChunkMap$TrackedEntity$serverEntity(trackedEntity);
if (serverEntity == null) return;
this.cachedServerEntity = serverEntity;
}
try {
CoreReflections.handle$ServerEntity$updateIntervalSetter.invokeExact(this.cachedServerEntity, updateInterval);
this.lastInjectedInterval = updateInterval;
} catch (Throwable e) {
plugin.logger().warn("Failed to update server entity tracking interval", e);
}
}
private static boolean canSpawnParticle(Object nmsEntity) {
private static boolean canSpawnParticle(Object nmsEntity, boolean inGround) {
if (!FastNMS.INSTANCE.field$Entity$wasTouchingWater(nmsEntity)) return false;
if (CoreReflections.clazz$AbstractArrow.isInstance(nmsEntity)) {
return !FastNMS.INSTANCE.method$AbstractArrow$isInGround(nmsEntity);
return !inGround;
}
return true;
}

View File

@@ -8,6 +8,7 @@ import net.momirealms.craftengine.bukkit.nms.FastNMS;
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections;
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MRegistryOps;
import net.momirealms.craftengine.core.item.ItemWrapper;
import net.momirealms.craftengine.core.plugin.locale.TranslationManager;
import net.momirealms.craftengine.core.util.Key;
import net.momirealms.sparrow.nbt.Tag;
import org.bukkit.inventory.ItemStack;
@@ -111,6 +112,10 @@ public class ComponentItemWrapper implements ItemWrapper<ItemStack> {
private void setComponentInternal(Object type, DynamicOps ops, Object value) {
if (value == null) return;
Object componentType = ensureDataComponentType(type);
if (componentType == null) {
TranslationManager.instance().log("warning.config.item.component_notfound", type.toString());
return;
}
Codec codec = FastNMS.INSTANCE.method$DataComponentType$codec(componentType);
try {
DataResult<Object> result = codec.parse(ops, value);

View File

@@ -48,6 +48,7 @@ public class BukkitCommandManager extends AbstractCommandManager<CommandSender>
new DebugSpawnFurnitureCommand(this, plugin),
new DebugTargetBlockCommand(this, plugin),
new DebugIsSectionInjectedCommand(this, plugin),
new DebugEntityId2UUIDCommand(this, plugin),
new TotemAnimationCommand(this, plugin),
new EnableResourceCommand(this, plugin),
new DisableResourceCommand(this, plugin),

View File

@@ -0,0 +1,59 @@
package net.momirealms.craftengine.bukkit.plugin.command.feature;
import net.momirealms.craftengine.bukkit.nms.FastNMS;
import net.momirealms.craftengine.bukkit.plugin.command.BukkitCommandFeature;
import net.momirealms.craftengine.core.plugin.CraftEngine;
import net.momirealms.craftengine.core.plugin.command.CraftEngineCommandManager;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Entity;
import org.incendo.cloud.Command;
import org.incendo.cloud.CommandManager;
import org.incendo.cloud.bukkit.parser.WorldParser;
import org.incendo.cloud.parser.standard.IntegerParser;
public class DebugEntityId2UUIDCommand extends BukkitCommandFeature<CommandSender> {
public DebugEntityId2UUIDCommand(CraftEngineCommandManager<CommandSender> commandManager, CraftEngine plugin) {
super(commandManager, plugin);
}
@Override
public Command.Builder<? extends CommandSender> assembleCommand(CommandManager<CommandSender> manager, Command.Builder<CommandSender> builder) {
return builder
.required("world", WorldParser.worldParser())
.required("entityId", IntegerParser.integerParser())
.handler(context -> {
World world = context.get("world");
int entityId = context.get("entityId");
Entity entity = FastNMS.INSTANCE.getBukkitEntityById(world, entityId);
if (entity == null) {
context.sender().sendMessage("entity not found");
return;
}
Location location = entity.getLocation();
context.sender().sendMessage(
String.format(
"""
===========================
uuid: %s
name: %s
location: %s,%s,%s
type: %s
===========================
""",
entity.getUniqueId(),
entity.getName(),
location.x(), location.y(), location.z(),
entity.getType()
)
);
});
}
@Override
public String getFeatureID() {
return "debug_entity_id_to_uuid";
}
}

View File

@@ -148,7 +148,6 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes
registerNMSPacketConsumer(PacketConsumers.LOGIN, NetworkReflections.clazz$ClientboundLoginPacket);
registerNMSPacketConsumer(PacketConsumers.RESPAWN, NetworkReflections.clazz$ClientboundRespawnPacket);
registerNMSPacketConsumer(PacketConsumers.SYNC_ENTITY_POSITION, NetworkReflections.clazz$ClientboundEntityPositionSyncPacket);
registerNMSPacketConsumer(PacketConsumers.MOVE_POS_ENTITY, NetworkReflections.clazz$ClientboundMoveEntityPacket$Pos);
registerNMSPacketConsumer(PacketConsumers.PICK_ITEM_FROM_ENTITY, NetworkReflections.clazz$ServerboundPickItemFromEntityPacket);
registerNMSPacketConsumer(PacketConsumers.RENAME_ITEM, NetworkReflections.clazz$ServerboundRenameItemPacket);
registerNMSPacketConsumer(PacketConsumers.SIGN_UPDATE, NetworkReflections.clazz$ServerboundSignUpdatePacket);
@@ -176,7 +175,7 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes
registerS2CByteBufPacketConsumer(VersionHelper.isOrAbove1_20_3() ? PacketConsumers.SET_OBJECTIVE_1_20_3 : PacketConsumers.SET_OBJECTIVE_1_20, this.packetIds.clientboundSetObjectivePacket());
registerS2CByteBufPacketConsumer(PacketConsumers.SET_SCORE_1_20_3, VersionHelper.isOrAbove1_20_3() ? this.packetIds.clientboundSetScorePacket() : -1);
registerS2CByteBufPacketConsumer(PacketConsumers.REMOVE_ENTITY, this.packetIds.clientboundRemoveEntitiesPacket());
registerS2CByteBufPacketConsumer(PacketConsumers.ADD_ENTITY_BYTEBUFFER, this.packetIds.clientboundAddEntityPacket());
registerS2CByteBufPacketConsumer(PacketConsumers.ADD_ENTITY, this.packetIds.clientboundAddEntityPacket());
registerS2CByteBufPacketConsumer(PacketConsumers.SOUND, this.packetIds.clientboundSoundPacket());
registerS2CByteBufPacketConsumer(PacketConsumers.SET_ENTITY_DATA, this.packetIds.clientboundSetEntityDataPacket());
registerS2CByteBufPacketConsumer(PacketConsumers.CONTAINER_SET_CONTENT, this.packetIds.clientboundContainerSetContentPacket());

View File

@@ -70,7 +70,6 @@ import org.bukkit.util.RayTraceResult;
import org.bukkit.util.Vector;
import org.jetbrains.annotations.Nullable;
import java.lang.reflect.InvocationTargetException;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.function.BiConsumer;
@@ -163,7 +162,6 @@ public class PacketConsumers {
BukkitFurniture furniture = BukkitFurnitureManager.instance().loadedFurnitureByRealEntityId(id);
if (furniture != null) {
event.setCancelled(true);
user.entityPacketHandlers().put(id, FurnitureCollisionPacketHandler.INSTANCE);
}
};
ADD_ENTITY_HANDLERS[MEntityTypes.OAK_BOAT$registryId] = (user, event) -> {
@@ -174,7 +172,6 @@ public class PacketConsumers {
BukkitFurniture furniture = BukkitFurnitureManager.instance().loadedFurnitureByRealEntityId(id);
if (furniture != null) {
event.setCancelled(true);
user.entityPacketHandlers().put(id, FurnitureCollisionPacketHandler.INSTANCE);
}
};
}
@@ -1172,21 +1169,21 @@ public class PacketConsumers {
public static final TriConsumer<NetWorkUser, NMSPacketEvent, Object> HELLO_C2S = (user, event, packet) -> {
try {
BukkitServerPlayer player = (BukkitServerPlayer) user;
String name = (String) NetworkReflections.field$ServerboundHelloPacket$name.get(packet);
String name = (String) NetworkReflections.handle$ServerboundHelloPacket$nameGetter.invokeExact(packet);
player.setName(name);
if (VersionHelper.isOrAbove1_20_2()) {
UUID uuid = (UUID) NetworkReflections.field$ServerboundHelloPacket$uuid.get(packet);
UUID uuid = (UUID) NetworkReflections.handle$ServerboundHelloPacket$uuidGetter.invokeExact(packet);
player.setUUID(uuid);
} else {
@SuppressWarnings("unchecked")
Optional<UUID> uuid = (Optional<UUID>) NetworkReflections.field$ServerboundHelloPacket$uuid.get(packet);
Optional<UUID> uuid = (Optional<UUID>) NetworkReflections.handle$ServerboundHelloPacket$uuidGetter.invokeExact(packet);
if (uuid.isPresent()) {
player.setUUID(uuid.get());
} else {
player.setUUID(UUID.nameUUIDFromBytes(("OfflinePlayer:" + name).getBytes(StandardCharsets.UTF_8)));
}
}
} catch (Exception e) {
} catch (Throwable e) {
CraftEngine.instance().logger().warn("Failed to handle ServerboundHelloPacket", e);
}
};
@@ -1223,10 +1220,10 @@ public class PacketConsumers {
player.clearView();
Object dimensionKey;
if (!VersionHelper.isOrAbove1_20_2()) {
dimensionKey = NetworkReflections.field$ClientboundRespawnPacket$dimension.get(packet);
dimensionKey = NetworkReflections.handle$ClientboundRespawnPacket$dimensionGetter.invokeExact(packet);
} else {
Object commonInfo = NetworkReflections.field$ClientboundRespawnPacket$commonPlayerSpawnInfo.get(packet);
dimensionKey = NetworkReflections.field$CommonPlayerSpawnInfo$dimension.get(commonInfo);
Object commonInfo = NetworkReflections.handle$ClientboundRespawnPacket$commonPlayerSpawnInfoGetter.invokeExact(packet);
dimensionKey = NetworkReflections.handle$CommonPlayerSpawnInfo$dimensionGetter.invokeExact(commonInfo);
}
Object location = FastNMS.INSTANCE.field$ResourceKey$location(dimensionKey);
World world = Bukkit.getWorld(Objects.requireNonNull(NamespacedKey.fromString(location.toString())));
@@ -1237,7 +1234,7 @@ public class PacketConsumers {
} else {
CraftEngine.instance().logger().warn("Failed to handle ClientboundRespawnPacket: World " + location + " does not exist");
}
} catch (Exception e) {
} catch (Throwable e) {
CraftEngine.instance().logger().warn("Failed to handle ClientboundRespawnPacket", e);
}
};
@@ -1251,10 +1248,10 @@ public class PacketConsumers {
if (BukkitNetworkManager.hasViaVersion()) {
user.setProtocolVersion(CraftEngine.instance().compatibilityManager().getPlayerProtocolVersion(player.uuid()));
}
dimensionKey = NetworkReflections.field$ClientboundLoginPacket$dimension.get(packet);
dimensionKey = NetworkReflections.handle$ClientboundLoginPacket$dimensionGetter.invokeExact(packet);
} else {
Object commonInfo = NetworkReflections.field$ClientboundLoginPacket$commonPlayerSpawnInfo.get(packet);
dimensionKey = NetworkReflections.field$CommonPlayerSpawnInfo$dimension.get(commonInfo);
Object commonInfo = NetworkReflections.handle$ClientboundLoginPacket$commonPlayerSpawnInfoGetter.invokeExact(packet);
dimensionKey = NetworkReflections.handle$CommonPlayerSpawnInfo$dimensionGetter.invokeExact(commonInfo);
}
Object location = FastNMS.INSTANCE.field$ResourceKey$location(dimensionKey);
World world = Bukkit.getWorld(Objects.requireNonNull(NamespacedKey.fromString(location.toString())));
@@ -1265,7 +1262,7 @@ public class PacketConsumers {
} else {
CraftEngine.instance().logger().warn("Failed to handle ClientboundLoginPacket: World " + location + " does not exist");
}
} catch (Exception e) {
} catch (Throwable e) {
CraftEngine.instance().logger().warn("Failed to handle ClientboundLoginPacket", e);
}
};
@@ -1282,25 +1279,25 @@ public class PacketConsumers {
player.platformPlayer().getScheduler().run(BukkitCraftEngine.instance().javaPlugin(), (t) -> {
try {
handleSetCreativeSlotPacketOnMainThread(player, packet);
} catch (Exception e) {
} catch (Throwable e) {
CraftEngine.instance().logger().warn("Failed to handle ServerboundSetCreativeModeSlotPacket", e);
}
}, () -> {});
} else {
handleSetCreativeSlotPacketOnMainThread(player, packet);
}
} catch (Exception e) {
} catch (Throwable e) {
CraftEngine.instance().logger().warn("Failed to handle ServerboundSetCreativeModeSlotPacket", e);
}
};
private static void handleSetCreativeSlotPacketOnMainThread(BukkitServerPlayer player, Object packet) throws Exception {
private static void handleSetCreativeSlotPacketOnMainThread(BukkitServerPlayer player, Object packet) throws Throwable {
Player bukkitPlayer = player.platformPlayer();
if (bukkitPlayer == null) return;
if (bukkitPlayer.getGameMode() != GameMode.CREATIVE) return;
int slot = VersionHelper.isOrAbove1_20_5() ? NetworkReflections.field$ServerboundSetCreativeModeSlotPacket$slotNum.getShort(packet) : NetworkReflections.field$ServerboundSetCreativeModeSlotPacket$slotNum.getInt(packet);
int slot = VersionHelper.isOrAbove1_20_5() ? (short) NetworkReflections.handle$ServerboundSetCreativeModeSlotPacket$slotNumGetter.invokeExact(packet) : (int) NetworkReflections.handle$ServerboundSetCreativeModeSlotPacket$slotNumGetter.invokeExact(packet);
if (slot < 36 || slot > 44) return;
ItemStack item = FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(NetworkReflections.field$ServerboundSetCreativeModeSlotPacket$itemStack.get(packet));
ItemStack item = FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(NetworkReflections.handle$ServerboundSetCreativeModeSlotPacket$itemStackGetter.invokeExact(packet));
if (ItemUtils.isEmpty(item)) return;
if (slot - 36 != bukkitPlayer.getInventory().getHeldItemSlot()) {
return;
@@ -1373,14 +1370,14 @@ public class PacketConsumers {
if (!user.isOnline()) return;
Player player = (Player) user.platformPlayer();
if (player == null) return;
Object pos = NetworkReflections.field$ServerboundPickItemFromBlockPacket$pos.get(packet);
Object pos = NetworkReflections.handle$ServerboundPickItemFromBlockPacket$posGetter.invokeExact(packet);
if (VersionHelper.isFolia()) {
int x = FastNMS.INSTANCE.field$Vec3i$x(pos);
int z = FastNMS.INSTANCE.field$Vec3i$z(pos);
BukkitCraftEngine.instance().scheduler().sync().run(() -> {
try {
handlePickItemFromBlockPacketOnMainThread(player, pos);
} catch (Exception e) {
} catch (Throwable e) {
CraftEngine.instance().logger().warn("Failed to handle ServerboundPickItemFromBlockPacket", e);
}
}, player.getWorld(), x >> 4, z >> 4);
@@ -1388,17 +1385,17 @@ public class PacketConsumers {
BukkitCraftEngine.instance().scheduler().sync().run(() -> {
try {
handlePickItemFromBlockPacketOnMainThread(player, pos);
} catch (Exception e) {
} catch (Throwable e) {
CraftEngine.instance().logger().warn("Failed to handle ServerboundPickItemFromBlockPacket", e);
}
});
}
} catch (Exception e) {
} catch (Throwable e) {
CraftEngine.instance().logger().warn("Failed to handle ServerboundPickItemFromBlockPacket", e);
}
};
private static void handlePickItemFromBlockPacketOnMainThread(Player player, Object pos) throws Exception {
private static void handlePickItemFromBlockPacketOnMainThread(Player player, Object pos) throws Throwable {
Object serverLevel = FastNMS.INSTANCE.field$CraftWorld$ServerLevel(player.getWorld());
Object blockState = FastNMS.INSTANCE.method$BlockGetter$getBlockState(serverLevel, pos);
ImmutableBlockState state = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(blockState));
@@ -1411,7 +1408,7 @@ public class PacketConsumers {
// 1.21.4+
public static final TriConsumer<NetWorkUser, NMSPacketEvent, Object> PICK_ITEM_FROM_ENTITY = (user, event, packet) -> {
try {
int entityId = (int) NetworkReflections.field$ServerboundPickItemFromEntityPacket$id.get(packet);
int entityId = (int) NetworkReflections.handle$ServerboundPickItemFromEntityPacket$idGetter.invokeExact(packet);
BukkitFurniture furniture = BukkitFurnitureManager.instance().loadedFurnitureByEntityId(entityId);
if (furniture == null) return;
Player player = (Player) user.platformPlayer();
@@ -1420,7 +1417,7 @@ public class PacketConsumers {
player.getScheduler().run(BukkitCraftEngine.instance().javaPlugin(), (t) -> {
try {
handlePickItemFromEntityOnMainThread(player, furniture);
} catch (Exception e) {
} catch (Throwable e) {
CraftEngine.instance().logger().warn("Failed to handle ServerboundPickItemFromEntityPacket", e);
}
}, () -> {});
@@ -1428,23 +1425,23 @@ public class PacketConsumers {
BukkitCraftEngine.instance().scheduler().sync().run(() -> {
try {
handlePickItemFromEntityOnMainThread(player, furniture);
} catch (Exception e) {
} catch (Throwable e) {
CraftEngine.instance().logger().warn("Failed to handle ServerboundPickItemFromEntityPacket", e);
}
});
}
} catch (Exception e) {
} catch (Throwable e) {
CraftEngine.instance().logger().warn("Failed to handle ServerboundPickItemFromEntityPacket", e);
}
};
private static void handlePickItemFromEntityOnMainThread(Player player, BukkitFurniture furniture) throws Exception {
private static void handlePickItemFromEntityOnMainThread(Player player, BukkitFurniture furniture) throws Throwable {
Key itemId = furniture.config().settings().itemId();
if (itemId == null) return;
pickItem(player, itemId, null, FastNMS.INSTANCE.method$CraftEntity$getHandle(furniture.baseEntity()));
}
private static void pickItem(Player player, Key itemId, @Nullable Object blockPos, @Nullable Object entity) throws IllegalAccessException, InvocationTargetException {
private static void pickItem(Player player, Key itemId, @Nullable Object blockPos, @Nullable Object entity) throws Throwable {
ItemStack itemStack = BukkitCraftEngine.instance().itemManager().buildCustomItemStack(itemId, BukkitCraftEngine.instance().adapt(player));
if (itemStack == null) {
CraftEngine.instance().logger().warn("Item: " + itemId + " is not a valid item");
@@ -1453,15 +1450,15 @@ public class PacketConsumers {
assert CoreReflections.method$ServerGamePacketListenerImpl$tryPickItem != null;
if (VersionHelper.isOrAbove1_21_5()) {
CoreReflections.method$ServerGamePacketListenerImpl$tryPickItem.invoke(
CoreReflections.field$ServerPlayer$connection.get(FastNMS.INSTANCE.method$CraftPlayer$getHandle(player)),
CoreReflections.handle$ServerPlayer$connectionGetter.invokeExact(FastNMS.INSTANCE.method$CraftPlayer$getHandle(player)),
FastNMS.INSTANCE.method$CraftItemStack$asNMSCopy(itemStack), blockPos, entity, true);
} else {
CoreReflections.method$ServerGamePacketListenerImpl$tryPickItem.invoke(
CoreReflections.field$ServerPlayer$connection.get(FastNMS.INSTANCE.method$CraftPlayer$getHandle(player)), FastNMS.INSTANCE.method$CraftItemStack$asNMSCopy(itemStack));
CoreReflections.handle$ServerPlayer$connectionGetter.invokeExact(FastNMS.INSTANCE.method$CraftPlayer$getHandle(player)), FastNMS.INSTANCE.method$CraftItemStack$asNMSCopy(itemStack));
}
}
public static final BiConsumer<NetWorkUser, ByteBufPacketEvent> ADD_ENTITY_BYTEBUFFER = (user, event) -> {
public static final BiConsumer<NetWorkUser, ByteBufPacketEvent> ADD_ENTITY = (user, event) -> {
try {
FriendlyByteBuf buf = event.getBuffer();
buf.readVarInt();
@@ -1665,7 +1662,7 @@ public class PacketConsumers {
} else {
BukkitCraftEngine.instance().scheduler().executeSync(mainThreadTask);
}
} catch (Exception e) {
} catch (Throwable e) {
CraftEngine.instance().logger().warn("Failed to handle ServerboundInteractPacket", e);
}
};
@@ -1750,20 +1747,20 @@ public class PacketConsumers {
if (((BukkitServerPlayer) user).hasPermission(FontManager.BYPASS_ANVIL)) {
return;
}
String message = (String) NetworkReflections.field$ServerboundRenameItemPacket$name.get(packet);
String message = (String) NetworkReflections.handle$ServerboundRenameItemPacket$nameGetter.invokeExact(packet);
if (message != null && !message.isEmpty()) {
// check bypass
FontManager manager = CraftEngine.instance().fontManager();
IllegalCharacterProcessResult result = manager.processIllegalCharacters(message);
if (result.has()) {
try {
NetworkReflections.field$ServerboundRenameItemPacket$name.set(packet, result.text());
NetworkReflections.handle$ServerboundRenameItemPacket$nameSetter.invokeExact(packet, result.text());
} catch (ReflectiveOperationException e) {
CraftEngine.instance().logger().warn("Failed to replace chat", e);
}
}
}
} catch (Exception e) {
} catch (Throwable e) {
CraftEngine.instance().logger().warn("Failed to handle ServerboundRenameItemPacket", e);
}
};
@@ -1776,7 +1773,7 @@ public class PacketConsumers {
if (((BukkitServerPlayer) user).hasPermission(FontManager.BYPASS_SIGN)) {
return;
}
String[] lines = (String[]) NetworkReflections.field$ServerboundSignUpdatePacket$lines.get(packet);
String[] lines = (String[]) NetworkReflections.handle$ServerboundSignUpdatePacket$linesGetter.invokeExact(packet);
FontManager manager = CraftEngine.instance().fontManager();
if (!manager.isDefaultFontInUse()) return;
for (int i = 0; i < lines.length; i++) {
@@ -1788,7 +1785,7 @@ public class PacketConsumers {
}
}
}
} catch (Exception e) {
} catch (Throwable e) {
CraftEngine.instance().logger().warn("Failed to handle ServerboundSignUpdatePacket", e);
}
};
@@ -1807,9 +1804,9 @@ public class PacketConsumers {
boolean changed = false;
List<String> pages = (List<String>) NetworkReflections.field$ServerboundEditBookPacket$pages.get(packet);
List<String> pages = (List<String>) NetworkReflections.handleServerboundEditBookPacket$pagesGetter.invokeExact(packet);
List<String> newPages = new ArrayList<>(pages.size());
Optional<String> title = (Optional<String>) NetworkReflections.field$ServerboundEditBookPacket$title.get(packet);
Optional<String> title = (Optional<String>) NetworkReflections.handle$ServerboundEditBookPacket$titleGetter.invokeExact(packet);
Optional<String> newTitle;
if (title.isPresent()) {
@@ -1833,13 +1830,13 @@ public class PacketConsumers {
if (changed) {
Object newPacket = NetworkReflections.constructor$ServerboundEditBookPacket.newInstance(
NetworkReflections.field$ServerboundEditBookPacket$slot.get(packet),
(int) NetworkReflections.handle$ServerboundEditBookPacket$slotGetter.invokeExact(packet),
newPages,
newTitle
);
event.replacePacket(newPacket);
}
} catch (Exception e) {
} catch (Throwable e) {
CraftEngine.instance().logger().warn("Failed to handle ServerboundEditBookPacket", e);
}
};
@@ -1866,7 +1863,7 @@ public class PacketConsumers {
public static final TriConsumer<NetWorkUser, NMSPacketEvent, Object> CUSTOM_PAYLOAD = (user, event, packet) -> {
try {
if (!VersionHelper.isOrAbove1_20_5()) return;
Object payload = NetworkReflections.field$ServerboundCustomPayloadPacket$payload.get(packet);
Object payload = NetworkReflections.handle$ServerboundCustomPayloadPacket$payloadGetter.invokeExact(packet);
if (NetworkReflections.clazz$DiscardedPayload.isInstance(payload)) {
Payload discardedPayload = DiscardedPayload.from(payload);
if (discardedPayload == null || !discardedPayload.channel().equals(NetworkManager.MOD_CHANNEL_KEY))
@@ -1895,7 +1892,7 @@ public class PacketConsumers {
}
}
}
} catch (Exception e) {
} catch (Throwable e) {
CraftEngine.instance().logger().warn("Failed to handle ServerboundCustomPayloadPacket", e);
}
};
@@ -2285,9 +2282,9 @@ public class PacketConsumers {
public static final TriConsumer<NetWorkUser, NMSPacketEvent, Object> HANDSHAKE_C2S = (user, event, packet) -> {
try {
if (BukkitNetworkManager.hasViaVersion()) return;
int protocolVersion = NetworkReflections.field$ClientIntentionPacket$protocolVersion.getInt(packet);
int protocolVersion = (int) NetworkReflections.handle$ClientIntentionPacket$protocolVersionGetter.invokeExact(packet);
user.setProtocolVersion(protocolVersion);
} catch (Exception e) {
} catch (Throwable e) {
CraftEngine.instance().logger().warn("Failed to handle ClientIntentionPacket", e);
}
};
@@ -2305,7 +2302,7 @@ public class PacketConsumers {
public static final TriConsumer<NetWorkUser, NMSPacketEvent, Object> RESOURCE_PACK_RESPONSE = (user, event, packet) -> {
try {
if (user.sentResourcePack() || !Config.sendPackOnJoin() || !Config.kickOnDeclined()) return;
Object action = NetworkReflections.field$ServerboundResourcePackPacket$action.get(packet);
Object action = NetworkReflections.handle$ServerboundResourcePackPacket$actionGetter.invokeExact(packet);
if (action == null) return;
if (action == NetworkReflections.instance$ServerboundResourcePackPacket$Action$DECLINED
|| action == NetworkReflections.instance$ServerboundResourcePackPacket$Action$FAILED_DOWNLOAD) {
@@ -2318,7 +2315,7 @@ public class PacketConsumers {
if (action == NetworkReflections.instance$ServerboundResourcePackPacket$Action$SUCCESSFULLY_LOADED) {
user.setSentResourcePack(true);
}
} catch (Exception e) {
} catch (Throwable e) {
CraftEngine.instance().logger().warn("Failed to handle ServerboundResourcePackPacket", e);
}
};
@@ -2327,28 +2324,17 @@ public class PacketConsumers {
try {
Object player = user.serverPlayer();
if (player == null) return;
int entityId = NetworkReflections.field$ClientboundEntityEventPacket$entityId.getInt(packet);
int entityId = (int) NetworkReflections.handle$ClientboundEntityEventPacket$entityIdGetter.invokeExact(packet);
if (entityId != FastNMS.INSTANCE.method$Entity$getId(player)) return;
byte eventId = NetworkReflections.field$ClientboundEntityEventPacket$eventId.getByte(packet);
byte eventId = (byte) NetworkReflections.handle$ClientboundEntityEventPacket$eventIdGetter.invokeExact(packet);
if (eventId >= 24 && eventId <= 28) {
CraftEngine.instance().fontManager().refreshEmojiSuggestions(user.uuid());
}
} catch (Exception e) {
} catch (Throwable e) {
CraftEngine.instance().logger().warn("Failed to handle ClientboundEntityEventPacket", e);
}
};
public static final TriConsumer<NetWorkUser, NMSPacketEvent, Object> MOVE_POS_ENTITY = (user, event, packet) -> {
try {
int entityId = ProtectedFieldVisitor.get().field$ClientboundMoveEntityPacket$entityId(packet);
if (BukkitFurnitureManager.instance().isFurnitureRealEntity(entityId)) {
event.setCancelled(true);
}
} catch (Exception e) {
CraftEngine.instance().logger().warn("Failed to handle ClientboundMoveEntityPacket", e);
}
};
public static final TriConsumer<NetWorkUser, NMSPacketEvent, Object> MOVE_POS_AND_ROTATE_ENTITY = (user, event, packet) -> {
try {
int entityId = ProtectedFieldVisitor.get().field$ClientboundMoveEntityPacket$entityId(packet);

View File

@@ -5,6 +5,7 @@ import net.momirealms.craftengine.bukkit.nms.FastNMS;
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections;
import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer;
import net.momirealms.craftengine.bukkit.util.EntityDataUtils;
import net.momirealms.craftengine.core.plugin.CraftEngine;
import net.momirealms.craftengine.core.plugin.network.ByteBufPacketEvent;
import net.momirealms.craftengine.core.plugin.network.EntityPacketHandler;
import net.momirealms.craftengine.core.plugin.network.NetWorkUser;
@@ -26,9 +27,13 @@ public class CommonItemPacketHandler implements EntityPacketHandler {
for (int i = 0; i < packedItems.size(); i++) {
Object packedItem = packedItems.get(i);
int entityDataId = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$id(packedItem);
// TODO 检查为什么会导致问题难道是其他插件乱发entity id
if (entityDataId == EntityDataUtils.ITEM_DATA_ID && CoreReflections.clazz$ItemStack.isInstance(packedItem)) {
if (entityDataId == EntityDataUtils.ITEM_DATA_ID) {
Object nmsItemStack = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$value(packedItem);
// TODO 检查为什么会导致问题难道是其他插件乱发entity id
if (!CoreReflections.clazz$ItemStack.isInstance(nmsItemStack)) {
CraftEngine.instance().logger().warn("Invalid item data for entity " + id);
continue;
}
ItemStack itemStack = FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(nmsItemStack);
Optional<ItemStack> optional = BukkitItemManager.instance().s2c(itemStack, (BukkitServerPlayer) user);
if (optional.isPresent()) {

View File

@@ -1,14 +0,0 @@
package net.momirealms.craftengine.bukkit.plugin.network.handler;
import net.momirealms.craftengine.core.plugin.network.EntityPacketHandler;
import net.momirealms.craftengine.core.plugin.network.NMSPacketEvent;
import net.momirealms.craftengine.core.plugin.network.NetWorkUser;
public class FurnitureCollisionPacketHandler implements EntityPacketHandler {
public static final FurnitureCollisionPacketHandler INSTANCE = new FurnitureCollisionPacketHandler();
@Override
public void handleSyncEntityPosition(NetWorkUser user, NMSPacketEvent event, Object packet) {
event.setCancelled(true);
}
}

View File

@@ -2,8 +2,6 @@ package net.momirealms.craftengine.bukkit.plugin.network.handler;
import it.unimi.dsi.fastutil.ints.IntList;
import net.momirealms.craftengine.core.plugin.network.EntityPacketHandler;
import net.momirealms.craftengine.core.plugin.network.NMSPacketEvent;
import net.momirealms.craftengine.core.plugin.network.NetWorkUser;
import java.util.List;
@@ -19,9 +17,4 @@ public class FurniturePacketHandler implements EntityPacketHandler {
entityIds.addAll(this.fakeEntities);
return true;
}
@Override
public void handleSyncEntityPosition(NetWorkUser user, NMSPacketEvent event, Object packet) {
event.setCancelled(true);
}
}

View File

@@ -11,6 +11,8 @@ import net.momirealms.craftengine.core.util.ReflectionUtils;
import net.momirealms.craftengine.core.util.VersionHelper;
import java.io.BufferedReader;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodType;
import java.lang.invoke.VarHandle;
import java.lang.reflect.*;
import java.util.*;
@@ -3265,4 +3267,33 @@ public final class CoreReflections {
public static final Method method$Registry$asLookup = ReflectionUtils.getMethod(
clazz$Registry, clazz$HolderLookup$RegistryLookup, new String[]{"asLookup", "p"}
);
public static final Field field$ServerEntity$broadcast = requireNonNull(
ReflectionUtils.getDeclaredField(
clazz$ServerEntity, Consumer.class, 0
)
);
public static final MethodHandle handle$ServerEntity$broadcastSetter;
public static final MethodHandle handle$ServerEntity$updateIntervalSetter;
public static final MethodHandle handle$ServerPlayer$connectionGetter;
static {
try {
handle$ServerEntity$broadcastSetter = requireNonNull(
ReflectionUtils.unreflectSetter(field$ServerEntity$broadcast)
.asType(MethodType.methodType(void.class, Object.class, Consumer.class))
);
handle$ServerEntity$updateIntervalSetter = requireNonNull(
ReflectionUtils.unreflectSetter(field$ServerEntity$updateInterval)
.asType(MethodType.methodType(void.class, Object.class, int.class))
);
handle$ServerPlayer$connectionGetter = requireNonNull(
ReflectionUtils.unreflectGetter(field$ServerPlayer$connection)
.asType(MethodType.methodType(Object.class, Object.class))
);
} catch (IllegalAccessException e) {
throw new ReflectionInitException("Failed to initialize reflection", e);
}
}
}

View File

@@ -1,10 +1,13 @@
package net.momirealms.craftengine.bukkit.plugin.reflection.minecraft;
import io.netty.buffer.ByteBuf;
import net.momirealms.craftengine.bukkit.plugin.reflection.ReflectionInitException;
import net.momirealms.craftengine.bukkit.util.BukkitReflectionUtils;
import net.momirealms.craftengine.core.util.ReflectionUtils;
import net.momirealms.craftengine.core.util.VersionHelper;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodType;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
@@ -968,7 +971,7 @@ public final class NetworkReflections {
);
public static final Field field$ServerboundEditBookPacket$slot = requireNonNull(
ReflectionUtils.getDeclaredField(clazz$ServerboundEditBookPacket, int.class, 0)
ReflectionUtils.getDeclaredField(clazz$ServerboundEditBookPacket, int.class, VersionHelper.isOrAbove1_20_5() ? 0 : 4)
);
public static final Field field$ServerboundEditBookPacket$pages = requireNonNull(
@@ -1300,4 +1303,170 @@ public final class NetworkReflections {
"network.protocol.game.ClientboundBlockEventPacket"
)
);
public static final MethodHandle handle$ServerboundRenameItemPacket$nameGetter;
public static final MethodHandle handle$ServerboundRenameItemPacket$nameSetter;
public static final MethodHandle handle$ServerboundHelloPacket$nameGetter;
public static final MethodHandle handle$ServerboundHelloPacket$uuidGetter;
public static final MethodHandle handle$ServerboundSetCreativeModeSlotPacket$itemStackGetter;
public static final MethodHandle handle$ServerboundSetCreativeModeSlotPacket$slotNumGetter;
public static final MethodHandle handle$ServerboundInteractPacket$actionGetter;
public static final MethodHandle handle$ServerboundInteractPacket$InteractionAtLocationAction$handGetter;
public static final MethodHandle handle$ServerboundInteractPacket$InteractionAtLocationAction$locationGetter;
public static final MethodHandle handle$ServerboundSignUpdatePacket$linesGetter;
public static final MethodHandle handleServerboundEditBookPacket$pagesGetter;
public static final MethodHandle handle$ServerboundEditBookPacket$titleGetter;
public static final MethodHandle handle$ServerboundEditBookPacket$slotGetter;
public static final MethodHandle handle$ServerboundResourcePackPacket$actionGetter;
public static final MethodHandle handle$ClientboundEntityEventPacket$entityIdGetter;
public static final MethodHandle handle$ClientboundEntityEventPacket$eventIdGetter;
public static final MethodHandle handle$ClientIntentionPacket$protocolVersionGetter;
public static final MethodHandle handle$ClientboundRespawnPacket$dimensionGetter;
public static final MethodHandle handle$ClientboundRespawnPacket$commonPlayerSpawnInfoGetter;
public static final MethodHandle handle$CommonPlayerSpawnInfo$dimensionGetter;
public static final MethodHandle handle$ClientboundLoginPacket$dimensionGetter;
public static final MethodHandle handle$ClientboundLoginPacket$commonPlayerSpawnInfoGetter;
public static final MethodHandle handle$ServerboundPickItemFromBlockPacket$posGetter;
public static final MethodHandle handle$ServerboundPickItemFromEntityPacket$idGetter;
public static final MethodHandle handle$ServerboundCustomPayloadPacket$payloadGetter;
static {
try {
handle$ServerboundRenameItemPacket$nameGetter = requireNonNull(
ReflectionUtils.unreflectGetter(field$ServerboundRenameItemPacket$name)
.asType(MethodType.methodType(String.class, Object.class))
);
handle$ServerboundRenameItemPacket$nameSetter = requireNonNull(
ReflectionUtils.unreflectSetter(field$ServerboundRenameItemPacket$name)
.asType(MethodType.methodType(void.class, Object.class, String.class))
);
handle$ServerboundHelloPacket$nameGetter = requireNonNull(
ReflectionUtils.unreflectGetter(field$ServerboundHelloPacket$name)
.asType(MethodType.methodType(String.class, Object.class))
);
handle$ServerboundHelloPacket$uuidGetter = requireNonNull(
ReflectionUtils.unreflectGetter(field$ServerboundHelloPacket$uuid)
.asType(MethodType.methodType(VersionHelper.isOrAbove1_20_2() ? UUID.class : Optional.class, Object.class))
);
handle$ServerboundSetCreativeModeSlotPacket$itemStackGetter = requireNonNull(
ReflectionUtils.unreflectGetter(field$ServerboundSetCreativeModeSlotPacket$itemStack)
.asType(MethodType.methodType(Object.class, Object.class))
);
handle$ServerboundSetCreativeModeSlotPacket$slotNumGetter = requireNonNull(
ReflectionUtils.unreflectGetter(field$ServerboundSetCreativeModeSlotPacket$slotNum)
.asType(MethodType.methodType(VersionHelper.isOrAbove1_20_5() ? short.class : int.class, Object.class))
);
handle$ServerboundInteractPacket$actionGetter = requireNonNull(
ReflectionUtils.unreflectGetter(field$ServerboundInteractPacket$action)
.asType(MethodType.methodType(Object.class, Object.class))
);
handle$ServerboundInteractPacket$InteractionAtLocationAction$handGetter = requireNonNull(
ReflectionUtils.unreflectGetter(field$ServerboundInteractPacket$InteractionAtLocationAction$hand)
.asType(MethodType.methodType(Object.class, Object.class))
);
handle$ServerboundInteractPacket$InteractionAtLocationAction$locationGetter = requireNonNull(
ReflectionUtils.unreflectGetter(field$ServerboundInteractPacket$InteractionAtLocationAction$location)
.asType(MethodType.methodType(Object.class, Object.class))
);
handle$ServerboundSignUpdatePacket$linesGetter = requireNonNull(
ReflectionUtils.unreflectGetter(field$ServerboundSignUpdatePacket$lines)
.asType(MethodType.methodType(String[].class, Object.class))
);
handleServerboundEditBookPacket$pagesGetter = requireNonNull(
ReflectionUtils.unreflectGetter(field$ServerboundEditBookPacket$pages)
.asType(MethodType.methodType(List.class, Object.class))
);
handle$ServerboundEditBookPacket$titleGetter = requireNonNull(
ReflectionUtils.unreflectGetter(field$ServerboundEditBookPacket$title)
.asType(MethodType.methodType(Optional.class, Object.class))
);
handle$ServerboundEditBookPacket$slotGetter = requireNonNull(
ReflectionUtils.unreflectGetter(field$ServerboundEditBookPacket$slot)
.asType(MethodType.methodType(int.class, Object.class))
);
handle$ServerboundResourcePackPacket$actionGetter = requireNonNull(
ReflectionUtils.unreflectGetter(field$ServerboundResourcePackPacket$action)
.asType(MethodType.methodType(Object.class, Object.class))
);
handle$ClientboundEntityEventPacket$entityIdGetter = requireNonNull(
ReflectionUtils.unreflectGetter(field$ClientboundEntityEventPacket$entityId)
.asType(MethodType.methodType(int.class, Object.class))
);
handle$ClientboundEntityEventPacket$eventIdGetter = requireNonNull(
ReflectionUtils.unreflectGetter(field$ClientboundEntityEventPacket$eventId)
.asType(MethodType.methodType(byte.class, Object.class))
);
handle$ClientIntentionPacket$protocolVersionGetter = requireNonNull(
ReflectionUtils.unreflectGetter(field$ClientIntentionPacket$protocolVersion)
.asType(MethodType.methodType(int.class, Object.class))
);
if (field$ServerboundCustomPayloadPacket$payload != null) {
handle$ServerboundCustomPayloadPacket$payloadGetter = requireNonNull(
ReflectionUtils.unreflectGetter(field$ServerboundCustomPayloadPacket$payload)
.asType(MethodType.methodType(Object.class, Object.class))
);
} else {
handle$ServerboundCustomPayloadPacket$payloadGetter = null;
}
if (field$ServerboundPickItemFromEntityPacket$id != null) {
handle$ServerboundPickItemFromEntityPacket$idGetter = requireNonNull(
ReflectionUtils.unreflectGetter(field$ServerboundPickItemFromEntityPacket$id)
.asType(MethodType.methodType(int.class, Object.class))
);
} else {
handle$ServerboundPickItemFromEntityPacket$idGetter = null;
}
if (field$ServerboundPickItemFromBlockPacket$pos != null) {
handle$ServerboundPickItemFromBlockPacket$posGetter = requireNonNull(
ReflectionUtils.unreflectGetter(field$ServerboundPickItemFromBlockPacket$pos)
.asType(MethodType.methodType(Object.class, Object.class))
);
} else {
handle$ServerboundPickItemFromBlockPacket$posGetter = null;
}
if (field$ClientboundLoginPacket$commonPlayerSpawnInfo != null) {
handle$ClientboundLoginPacket$commonPlayerSpawnInfoGetter = requireNonNull(
ReflectionUtils.unreflectGetter(field$ClientboundLoginPacket$commonPlayerSpawnInfo)
.asType(MethodType.methodType(Object.class, Object.class))
);
} else {
handle$ClientboundLoginPacket$commonPlayerSpawnInfoGetter = null;
}
if (field$ClientboundLoginPacket$dimension != null) {
handle$ClientboundLoginPacket$dimensionGetter = requireNonNull(
ReflectionUtils.unreflectGetter(field$ClientboundLoginPacket$dimension)
.asType(MethodType.methodType(Object.class, Object.class))
);
} else {
handle$ClientboundLoginPacket$dimensionGetter = null;
}
if (field$CommonPlayerSpawnInfo$dimension != null) {
handle$CommonPlayerSpawnInfo$dimensionGetter = requireNonNull(
ReflectionUtils.unreflectGetter(field$CommonPlayerSpawnInfo$dimension)
.asType(MethodType.methodType(Object.class, Object.class))
);
} else {
handle$CommonPlayerSpawnInfo$dimensionGetter = null;
}
if (field$ClientboundRespawnPacket$commonPlayerSpawnInfo != null) {
handle$ClientboundRespawnPacket$commonPlayerSpawnInfoGetter = requireNonNull(
ReflectionUtils.unreflectGetter(field$ClientboundRespawnPacket$commonPlayerSpawnInfo)
.asType(MethodType.methodType(Object.class, Object.class))
);
} else {
handle$ClientboundRespawnPacket$commonPlayerSpawnInfoGetter = null;
}
if (field$ClientboundRespawnPacket$dimension != null) {
handle$ClientboundRespawnPacket$dimensionGetter = requireNonNull(
ReflectionUtils.unreflectGetter(field$ClientboundRespawnPacket$dimension)
.asType(MethodType.methodType(Object.class, Object.class))
);
} else {
handle$ClientboundRespawnPacket$dimensionGetter = null;
}
} catch (Throwable e) {
throw new ReflectionInitException("Failed to initialize reflection", e);
}
}
}

View File

@@ -182,6 +182,13 @@ debug_clear_cooldown:
- /craftengine debug clear-cooldown
- /ce debug clear-cooldown
debug_entity_id_to_uuid:
enable: true
permission: ce.command.debug.entity_id_to_uuid
usage:
- /craftengine debug entity-id-to-uuid
- /ce debug entity-id-to-uuid
debug_test:
enable: true
permission: ce.command.debug.test

View File

@@ -156,6 +156,7 @@ warning.config.item.invalid_material: "<yellow>Issue found in file <arg:0> - The
warning.config.item.invalid_custom_model_data: "<yellow>Issue found in file <arg:0> - The item '<arg:1>' is using a negative custom model data '<arg:2>' which is invalid.</yellow>"
warning.config.item.bad_custom_model_data: "<yellow>Issue found in file <arg:0> - The item '<arg:1>' is using a custom model data '<arg:2>' that is too large. It's recommended to use a value lower than 16,777,216.</yellow>"
warning.config.item.custom_model_data_conflict: "<yellow>Issue found in file <arg:0> - The item '<arg:1>' is using a custom model data '<arg:2>' that has been occupied by item '<arg:3>'.</yellow>"
warning.config.item.component_notfound: "<yellow>Issue found - Have item using a component '<arg:0>' that does not exist.</yellow>"
warning.config.item.missing_model_id: "<yellow>Issue found in file <arg:0> - The item '<arg:1>' is missing the required 'custom-model-data' or 'item-model' argument.</yellow>"
warning.config.item.missing_model: "<yellow>Issue found in file <arg:0> - The item '<arg:1>' is missing the required 'model' section for 1.21.4+ resource pack support.</yellow>"
warning.config.item.behavior.missing_type: "<yellow>Issue found in file <arg:0> - The item '<arg:1>' is missing the required 'type' argument for its item behavior.</yellow>"

View File

@@ -156,6 +156,7 @@ warning.config.item.invalid_material: "<yellow>在文件 <arg:0> 发现问题 -
warning.config.item.invalid_custom_model_data: "<yellow>在文件 <arg:0> 发现问题 - 物品 '<arg:1>' 使用了无效的负数模型值 '<arg:2>'.</yellow>"
warning.config.item.bad_custom_model_data: "<yellow>在文件 <arg:0> 发现问题 - 物品 '<arg:1>' 使用的自定义模型数据 '<arg:2>' 数值过大 建议使用小于 16,777,216 的值</yellow>"
warning.config.item.custom_model_data_conflict: "<yellow>在文件 <arg:0> 发现问题 - 物品 '<arg:1>' 使用的自定义模型数据 '<arg:2>' 已被物品 '<arg:3>' 占用</yellow>"
warning.config.item.component_notfound: "<yellow>发现问题 - 有物品使用了未知的组件 '<arg:0>'</yellow>"
warning.config.item.missing_model_id: "<yellow>在文件 <arg:0> 发现问题 - 物品 '<arg:1>' 缺少必需的 'custom-model-data' 或 'item-model' 参数</yellow>"
warning.config.item.missing_model: "<yellow>在文件 <arg:0> 中发现问题 - 物品 '<arg:1>' 缺少支持 1.21.4+ 资源包必需的 'model' 配置项</yellow>"
warning.config.item.behavior.missing_type: "<yellow>在文件 <arg:0> 发现问题 - 物品 '<arg:1>' 的行为配置缺少必需的 'type' 参数</yellow>"

View File

@@ -6,6 +6,7 @@ public abstract class AbstractCustomProjectile implements CustomProjectile {
protected final ProjectileMeta meta;
protected final Projectile projectile;
protected final Item<?> item;
private int inGroundTime;
protected AbstractCustomProjectile(ProjectileMeta meta, Projectile projectile, Item<?> item) {
this.meta = meta;
@@ -27,4 +28,14 @@ public abstract class AbstractCustomProjectile implements CustomProjectile {
public Item<?> item() {
return item;
}
@Override
public int inGroundTime() {
return inGroundTime;
}
@Override
public void setInGroundTime(int inGroundTime) {
this.inGroundTime = inGroundTime;
}
}

View File

@@ -9,4 +9,8 @@ public interface CustomProjectile {
Projectile projectile();
Item<?> item();
int inGroundTime();
void setInGroundTime(int inGroundTime);
}

View File

@@ -494,6 +494,15 @@ public class ReflectionUtils {
}
}
public static MethodHandle unreflectSetter(Field field) throws IllegalAccessException {
try {
return LOOKUP.unreflectSetter(field);
} catch (IllegalAccessException e) {
field.setAccessible(true);
return LOOKUP.unreflectSetter(field);
}
}
public static MethodHandle unreflectMethod(Method method) throws IllegalAccessException {
try {
return LOOKUP.unreflect(method);

View File

@@ -3,7 +3,7 @@ org.gradle.jvmargs=-Xmx1G
# Project settings
# Rule: [major update].[feature update].[bug fix]
project_version=0.0.56.3
config_version=34
config_version=35
lang_version=15
project_group=net.momirealms
latest_supported_version=1.21.5