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

Merge pull request #337 from jhqwqmc/dev

feat(entity): 补充含有方块状态的实体处理并重构部分代码逻辑
This commit is contained in:
XiaoMoMi
2025-08-17 15:35:57 +08:00
committed by GitHub
26 changed files with 500 additions and 31 deletions

View File

@@ -0,0 +1,26 @@
package net.momirealms.craftengine.bukkit.entity.data;
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MBlocks;
import net.momirealms.craftengine.bukkit.util.BlockStateUtils;
import net.momirealms.craftengine.core.util.VersionHelper;
import java.util.Optional;
public class AbstractMinecartData<T> extends VehicleEntityData<T> {
// 1.20~1.21.2
public static final AbstractMinecartData<Integer> DisplayBlock = of(AbstractMinecartData.class, EntityDataValue.Serializers$INT, BlockStateUtils.blockStateToId(MBlocks.AIR$defaultState), !VersionHelper.isOrAbove1_21_3());
// 1.21.3+
public static final AbstractMinecartData<Optional<Object>> CustomDisplayBlock = of(AbstractMinecartData.class, EntityDataValue.Serializers$OPTIONAL_BLOCK_STATE, Optional.empty(), VersionHelper.isOrAbove1_21_3());
public static final AbstractMinecartData<Integer> DisplayOffset = of(AbstractMinecartData.class, EntityDataValue.Serializers$INT, 6, true);
// 1.20~1.21.2
public static final AbstractMinecartData<Boolean> CustomDisplay = of(AbstractMinecartData.class, EntityDataValue.Serializers$BOOLEAN, false, !VersionHelper.isOrAbove1_21_3());
public static <T> AbstractMinecartData<T> of(final Class<?> clazz, final Object serializer, T defaultValue, boolean condition) {
if (!condition) return null;
return new AbstractMinecartData<>(clazz, serializer, defaultValue);
}
public AbstractMinecartData(Class<?> clazz, Object serializer, T defaultValue) {
super(clazz, serializer, defaultValue);
}
}

View File

@@ -0,0 +1,8 @@
package net.momirealms.craftengine.bukkit.entity.data;
public class BlockAttachedEntityData<T> extends BaseEntityData<T> {
public BlockAttachedEntityData(Class<?> clazz, Object serializer, T defaultValue) {
super(clazz, serializer, defaultValue);
}
}

View File

@@ -4,7 +4,7 @@ import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MBlocks;
public class BlockDisplayEntityData<T> extends DisplayEntityData<T> {
// Block display only
public static final DisplayEntityData<Object> DisplayedBlock = new BlockDisplayEntityData<>(BlockDisplayEntityData.class, EntityDataValue.Serializers$BLOCK_STATE, MBlocks.AIR$defaultState);
public static final BlockDisplayEntityData<Object> DisplayedBlock = new BlockDisplayEntityData<>(BlockDisplayEntityData.class, EntityDataValue.Serializers$BLOCK_STATE, MBlocks.AIR$defaultState);
public BlockDisplayEntityData(Class<?> clazz, Object serializer, T defaultValue) {
super(clazz, serializer, defaultValue);

View File

@@ -0,0 +1,13 @@
package net.momirealms.craftengine.bukkit.entity.data;
import java.util.Optional;
public class EnderManData<T> extends MonsterData<T> {
public static final EnderManData<Optional<Object>> CarryState = new EnderManData<>(EnderManData.class, EntityDataValue.Serializers$OPTIONAL_BLOCK_STATE, Optional.empty());
public static final EnderManData<Boolean> Creepy = new EnderManData<>(EnderManData.class, EntityDataValue.Serializers$BOOLEAN, false);
public static final EnderManData<Boolean> StaredAt = new EnderManData<>(EnderManData.class, EntityDataValue.Serializers$BOOLEAN, false);
public EnderManData(Class<?> clazz, Object serializer, T defaultValue) {
super(clazz, serializer, defaultValue);
}
}

View File

@@ -0,0 +1,8 @@
package net.momirealms.craftengine.bukkit.entity.data;
public class GlowItemFrameData<T> extends ItemFrameData<T> {
public GlowItemFrameData(Class<?> clazz, Object serializer, T defaultValue) {
super(clazz, serializer, defaultValue);
}
}

View File

@@ -0,0 +1,18 @@
package net.momirealms.craftengine.bukkit.entity.data;
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections;
import net.momirealms.craftengine.core.util.VersionHelper;
public class HangingEntityData<T> extends BlockAttachedEntityData<T> {
// 1.21.6+
public static final HangingEntityData<Object> Direction = of(HangingEntityData.class, EntityDataValue.Serializers$DIRECTION, CoreReflections.instance$Direction$SOUTH, VersionHelper.isOrAbove1_21_6());
public static <T> HangingEntityData<T> of(final Class<?> clazz, final Object serializer, T defaultValue, boolean condition) {
if (!condition) return null;
return new HangingEntityData<>(clazz, serializer, defaultValue);
}
public HangingEntityData(Class<?> clazz, Object serializer, T defaultValue) {
super(clazz, serializer, defaultValue);
}
}

View File

@@ -4,7 +4,7 @@ import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflect
public class ItemDisplayEntityData<T> extends DisplayEntityData<T> {
// Item display only
public static final DisplayEntityData<Object> DisplayedItem = new ItemDisplayEntityData<>(ItemDisplayEntityData.class, EntityDataValue.Serializers$ITEM_STACK, CoreReflections.instance$ItemStack$EMPTY);
public static final ItemDisplayEntityData<Object> DisplayedItem = new ItemDisplayEntityData<>(ItemDisplayEntityData.class, EntityDataValue.Serializers$ITEM_STACK, CoreReflections.instance$ItemStack$EMPTY);
/**
* Display type:
* 0 = NONE
@@ -17,7 +17,7 @@ public class ItemDisplayEntityData<T> extends DisplayEntityData<T> {
* 7 = GROUND
* 8 = FIXED
*/
public static final DisplayEntityData<Byte> DisplayType = new ItemDisplayEntityData<>(ItemDisplayEntityData.class, EntityDataValue.Serializers$BYTE, (byte) 0);
public static final ItemDisplayEntityData<Byte> DisplayType = new ItemDisplayEntityData<>(ItemDisplayEntityData.class, EntityDataValue.Serializers$BYTE, (byte) 0);
public ItemDisplayEntityData(Class<?> clazz, Object serializer, T defaultValue) {
super(clazz, serializer, defaultValue);

View File

@@ -0,0 +1,12 @@
package net.momirealms.craftengine.bukkit.entity.data;
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections;
public class ItemFrameData<T> extends HangingEntityData<T> {
public static final ItemFrameData<Object> Item = new ItemFrameData<>(ItemFrameData.class, EntityDataValue.Serializers$ITEM_STACK, CoreReflections.instance$ItemStack$EMPTY);
public static final ItemFrameData<Integer> Rotation = new ItemFrameData<>(ItemFrameData.class, EntityDataValue.Serializers$INT, 0);
public ItemFrameData(Class<?> clazz, Object serializer, T defaultValue) {
super(clazz, serializer, defaultValue);
}
}

View File

@@ -0,0 +1,8 @@
package net.momirealms.craftengine.bukkit.entity.data;
public class MonsterData<T> extends PathfinderMobData<T> {
public MonsterData(Class<?> clazz, Object serializer, T defaultValue) {
super(clazz, serializer, defaultValue);
}
}

View File

@@ -0,0 +1,19 @@
package net.momirealms.craftengine.bukkit.entity.data;
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MBlocks;
import net.momirealms.craftengine.core.util.VersionHelper;
public class PrimedTntData<T> extends BaseEntityData<T> {
public static final PrimedTntData<Integer> Fuse = of(PrimedTntData.class, EntityDataValue.Serializers$INT, 80, true);
// 1.20.3+
public static final PrimedTntData<Object> BlockState = of(PrimedTntData.class, EntityDataValue.Serializers$BLOCK_STATE, MBlocks.TNT$defaultState, VersionHelper.isOrAbove1_20_3());
public static <T> PrimedTntData<T> of(final Class<?> clazz, final Object serializer, T defaultValue, boolean condition) {
if (!condition) return null;
return new PrimedTntData<>(clazz, serializer, defaultValue);
}
public PrimedTntData(Class<?> clazz, Object serializer, T defaultValue) {
super(clazz, serializer, defaultValue);
}
}

View File

@@ -3,11 +3,11 @@ package net.momirealms.craftengine.bukkit.entity.data;
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections;
public class TextDisplayEntityData<T> extends DisplayEntityData<T> {
public static final DisplayEntityData<Object> Text = new TextDisplayEntityData<>(TextDisplayEntityData.class, EntityDataValue.Serializers$COMPONENT, CoreReflections.instance$Component$empty);
public static final DisplayEntityData<Integer> LineWidth = new TextDisplayEntityData<>(TextDisplayEntityData.class, EntityDataValue.Serializers$INT, 200);
public static final DisplayEntityData<Integer> BackgroundColor = new TextDisplayEntityData<>(TextDisplayEntityData.class, EntityDataValue.Serializers$INT, 0x40000000);
public static final DisplayEntityData<Byte> TextOpacity = new TextDisplayEntityData<>(TextDisplayEntityData.class, EntityDataValue.Serializers$BYTE, (byte) -1);
public static final DisplayEntityData<Byte> TextDisplayMasks = new TextDisplayEntityData<>(TextDisplayEntityData.class, EntityDataValue.Serializers$BYTE, (byte) 0);
public static final TextDisplayEntityData<Object> Text = new TextDisplayEntityData<>(TextDisplayEntityData.class, EntityDataValue.Serializers$COMPONENT, CoreReflections.instance$Component$empty);
public static final TextDisplayEntityData<Integer> LineWidth = new TextDisplayEntityData<>(TextDisplayEntityData.class, EntityDataValue.Serializers$INT, 200);
public static final TextDisplayEntityData<Integer> BackgroundColor = new TextDisplayEntityData<>(TextDisplayEntityData.class, EntityDataValue.Serializers$INT, 0x40000000);
public static final TextDisplayEntityData<Byte> TextOpacity = new TextDisplayEntityData<>(TextDisplayEntityData.class, EntityDataValue.Serializers$BYTE, (byte) -1);
public static final TextDisplayEntityData<Byte> TextDisplayMasks = new TextDisplayEntityData<>(TextDisplayEntityData.class, EntityDataValue.Serializers$BYTE, (byte) 0);
public TextDisplayEntityData(Class<?> clazz, Object serializer, T defaultValue) {
super(clazz, serializer, defaultValue);

View File

@@ -0,0 +1,11 @@
package net.momirealms.craftengine.bukkit.entity.data;
public class VehicleEntityData<T> extends BaseEntityData<T> {
public static final VehicleEntityData<Integer> Hurt = new VehicleEntityData<>(VehicleEntityData.class, EntityDataValue.Serializers$INT, 0);
public static final VehicleEntityData<Integer> HurtDir = new VehicleEntityData<>(VehicleEntityData.class, EntityDataValue.Serializers$INT, 1);
public static final VehicleEntityData<Float> Damage = new VehicleEntityData<>(VehicleEntityData.class, EntityDataValue.Serializers$FLOAT, 0.0F);
public VehicleEntityData(Class<?> clazz, Object serializer, T defaultValue) {
super(clazz, serializer, defaultValue);
}
}

View File

@@ -1,11 +1,26 @@
package net.momirealms.craftengine.bukkit.plugin.command.feature;
import net.momirealms.craftengine.bukkit.plugin.command.BukkitCommandFeature;
import net.momirealms.craftengine.bukkit.util.BlockStateUtils;
import net.momirealms.craftengine.core.block.ImmutableBlockState;
import net.momirealms.craftengine.core.block.parser.BlockStateParser;
import net.momirealms.craftengine.core.plugin.CraftEngine;
import net.momirealms.craftengine.core.plugin.command.CraftEngineCommandManager;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.entity.Minecart;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.incendo.cloud.Command;
import org.incendo.cloud.bukkit.parser.location.LocationParser;
import org.incendo.cloud.context.CommandContext;
import org.incendo.cloud.context.CommandInput;
import org.incendo.cloud.parser.standard.StringParser;
import org.incendo.cloud.suggestion.Suggestion;
import org.incendo.cloud.suggestion.SuggestionProvider;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;
public class TestCommand extends BukkitCommandFeature<CommandSender> {
@@ -16,8 +31,20 @@ public class TestCommand extends BukkitCommandFeature<CommandSender> {
@Override
public Command.Builder<? extends CommandSender> assembleCommand(org.incendo.cloud.CommandManager<CommandSender> manager, Command.Builder<CommandSender> builder) {
return builder
.senderType(Player.class)
.required("location", LocationParser.locationParser())
.required("id", 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(BlockStateParser.fillSuggestions(input.input(), input.cursor()).stream().map(Suggestion::suggestion).collect(Collectors.toList()));
}
}))
.handler(context -> {
String data = context.get("id");
Location location = context.get("location");
ImmutableBlockState state = BlockStateParser.deserialize(data);
if (state == null) return;
Minecart minecart = location.getWorld().spawn(location, Minecart.class);
minecart.setDisplayBlockData(BlockStateUtils.fromBlockData(state.customBlockState().handle()));
});
}

View File

@@ -18,6 +18,7 @@ import net.momirealms.craftengine.bukkit.api.event.FurnitureAttemptBreakEvent;
import net.momirealms.craftengine.bukkit.api.event.FurnitureBreakEvent;
import net.momirealms.craftengine.bukkit.api.event.FurnitureInteractEvent;
import net.momirealms.craftengine.bukkit.block.BukkitBlockManager;
import net.momirealms.craftengine.bukkit.entity.data.BaseEntityData;
import net.momirealms.craftengine.bukkit.entity.furniture.BukkitFurniture;
import net.momirealms.craftengine.bukkit.entity.furniture.BukkitFurnitureManager;
import net.momirealms.craftengine.bukkit.entity.projectile.BukkitProjectileManager;
@@ -137,6 +138,14 @@ public class PacketConsumers {
ADD_ENTITY_HANDLERS[MEntityTypes.ITEM$registryId] = simpleAddEntityHandler(CommonItemPacketHandler.INSTANCE);
ADD_ENTITY_HANDLERS[MEntityTypes.ITEM_FRAME$registryId] = simpleAddEntityHandler(ItemFramePacketHandler.INSTANCE);
ADD_ENTITY_HANDLERS[MEntityTypes.GLOW_ITEM_FRAME$registryId] = simpleAddEntityHandler(ItemFramePacketHandler.INSTANCE);
ADD_ENTITY_HANDLERS[MEntityTypes.ENDERMAN$registryId] = simpleAddEntityHandler(EndermanPacketHandler.INSTANCE);
ADD_ENTITY_HANDLERS[MEntityTypes.CHEST_MINECART$registryId] = simpleAddEntityHandler(AbstractMinecartPacketHandler.INSTANCE);
ADD_ENTITY_HANDLERS[MEntityTypes.COMMAND_BLOCK_MINECART$registryId] = simpleAddEntityHandler(AbstractMinecartPacketHandler.INSTANCE);
ADD_ENTITY_HANDLERS[MEntityTypes.FURNACE_MINECART$registryId] = simpleAddEntityHandler(AbstractMinecartPacketHandler.INSTANCE);
ADD_ENTITY_HANDLERS[MEntityTypes.HOPPER_MINECART$registryId] = simpleAddEntityHandler(AbstractMinecartPacketHandler.INSTANCE);
ADD_ENTITY_HANDLERS[MEntityTypes.MINECART$registryId] = simpleAddEntityHandler(AbstractMinecartPacketHandler.INSTANCE);
ADD_ENTITY_HANDLERS[MEntityTypes.SPAWNER_MINECART$registryId] = simpleAddEntityHandler(AbstractMinecartPacketHandler.INSTANCE);
ADD_ENTITY_HANDLERS[MEntityTypes.TNT_MINECART$registryId] = simpleAddEntityHandler(AbstractMinecartPacketHandler.INSTANCE);
ADD_ENTITY_HANDLERS[MEntityTypes.FIREBALL$registryId] = createOptionalCustomProjectileEntityHandler(true);
ADD_ENTITY_HANDLERS[MEntityTypes.EYE_OF_ENDER$registryId] = createOptionalCustomProjectileEntityHandler(true);
ADD_ENTITY_HANDLERS[MEntityTypes.FIREWORK_ROCKET$registryId] = createOptionalCustomProjectileEntityHandler(true);
@@ -149,6 +158,9 @@ public class PacketConsumers {
ADD_ENTITY_HANDLERS[MEntityTypes.TRIDENT$registryId] = createOptionalCustomProjectileEntityHandler(false);
ADD_ENTITY_HANDLERS[MEntityTypes.ARROW$registryId] = createOptionalCustomProjectileEntityHandler(false);
ADD_ENTITY_HANDLERS[MEntityTypes.SPECTRAL_ARROW$registryId] = createOptionalCustomProjectileEntityHandler(false);
if (VersionHelper.isOrAbove1_20_3()) {
ADD_ENTITY_HANDLERS[MEntityTypes.TNT$registryId] = simpleAddEntityHandler(PrimedTNTPacketHandler.INSTANCE);
}
if (VersionHelper.isOrAbove1_20_5()) {
ADD_ENTITY_HANDLERS[MEntityTypes.OMINOUS_ITEM_SPAWNER$registryId] = simpleAddEntityHandler(CommonItemPacketHandler.INSTANCE);
}
@@ -236,10 +248,12 @@ public class PacketConsumers {
}
public static int remap(int stateId) {
// if (true) return 0;
return mappings[stateId];
}
public static int remapMOD(int stateId) {
// if (true) return 0;
return mappingsMOD[stateId];
}
@@ -1945,7 +1959,7 @@ public class PacketConsumers {
for (int i = 0; i < packedItems.size(); i++) {
Object packedItem = packedItems.get(i);
int entityDataId = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$id(packedItem);
if (entityDataId != EntityDataUtils.CUSTOM_NAME_DATA_ID) continue;
if (entityDataId != BaseEntityData.CustomName.id()) continue;
Optional<Object> optionalTextComponent = (Optional<Object>) FastNMS.INSTANCE.field$SynchedEntityData$DataValue$value(packedItem);
if (optionalTextComponent.isEmpty()) continue;
Object textComponent = optionalTextComponent.get();

View File

@@ -0,0 +1,114 @@
package net.momirealms.craftengine.bukkit.plugin.network.handler;
import net.kyori.adventure.text.Component;
import net.momirealms.craftengine.bukkit.entity.data.AbstractMinecartData;
import net.momirealms.craftengine.bukkit.entity.data.BaseEntityData;
import net.momirealms.craftengine.bukkit.nms.FastNMS;
import net.momirealms.craftengine.bukkit.plugin.network.PacketConsumers;
import net.momirealms.craftengine.bukkit.util.BlockStateUtils;
import net.momirealms.craftengine.bukkit.util.ComponentUtils;
import net.momirealms.craftengine.core.plugin.CraftEngine;
import net.momirealms.craftengine.core.plugin.config.Config;
import net.momirealms.craftengine.core.plugin.network.ByteBufPacketEvent;
import net.momirealms.craftengine.core.plugin.network.EntityPacketHandler;
import net.momirealms.craftengine.core.plugin.network.NetWorkUser;
import net.momirealms.craftengine.core.util.AdventureHelper;
import net.momirealms.craftengine.core.util.FriendlyByteBuf;
import net.momirealms.craftengine.core.util.VersionHelper;
import java.util.List;
import java.util.Map;
import java.util.Optional;
public class AbstractMinecartPacketHandler implements EntityPacketHandler {
public static final AbstractMinecartPacketHandler INSTANCE = new AbstractMinecartPacketHandler();
private static final BlockStateHandler HANDLER = VersionHelper.isOrAbove1_21_3() ? BlockStateHandler_1_21_3.INSTANCE : BlockStateHandler_1_20.INSTANCE;
@Override
public void handleSetEntityData(NetWorkUser user, ByteBufPacketEvent event) {
FriendlyByteBuf buf = event.getBuffer();
int id = buf.readVarInt();
boolean isChanged = false;
List<Object> packedItems = FastNMS.INSTANCE.method$ClientboundSetEntityDataPacket$unpack(buf);
for (int i = 0; i < packedItems.size(); i++) {
Object packedItem = packedItems.get(i);
int entityDataId = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$id(packedItem);
Object blockState = HANDLER.handle(user, packedItem, entityDataId);
if (blockState != null) {
packedItems.set(i, blockState);
isChanged = true;
} else if (Config.interceptEntityName() && entityDataId == BaseEntityData.CustomName.id()) {
@SuppressWarnings("unchecked")
Optional<Object> optionalTextComponent = (Optional<Object>) FastNMS.INSTANCE.field$SynchedEntityData$DataValue$value(packedItem);
if (optionalTextComponent.isEmpty()) continue;
Object textComponent = optionalTextComponent.get();
String json = ComponentUtils.minecraftToJson(textComponent);
Map<String, Component> tokens = CraftEngine.instance().fontManager().matchTags(json);
if (tokens.isEmpty()) continue;
Component component = AdventureHelper.jsonToComponent(json);
for (Map.Entry<String, Component> token : tokens.entrySet()) {
component = component.replaceText(b -> b.matchLiteral(token.getKey()).replacement(token.getValue()));
}
Object serializer = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$serializer(packedItem);
packedItems.set(i, FastNMS.INSTANCE.constructor$SynchedEntityData$DataValue(
entityDataId, serializer, Optional.of(ComponentUtils.adventureToMinecraft(component))
));
isChanged = true;
}
}
if (isChanged) {
event.setChanged(true);
buf.clear();
buf.writeVarInt(event.packetID());
buf.writeVarInt(id);
FastNMS.INSTANCE.method$ClientboundSetEntityDataPacket$pack(packedItems, buf);
}
}
interface BlockStateHandler {
Object handle(NetWorkUser user, Object packedItem, int entityDataId);
}
static class BlockStateHandler_1_21_3 implements BlockStateHandler {
protected static final BlockStateHandler INSTANCE = new BlockStateHandler_1_21_3();
@Override
public Object handle(NetWorkUser user, Object packedItem, int entityDataId) {
if (entityDataId != AbstractMinecartData.CustomDisplayBlock.id()) return null;
@SuppressWarnings("unchecked")
Optional<Object> blockState = (Optional<Object>) FastNMS.INSTANCE.field$SynchedEntityData$DataValue$value(packedItem);
if (blockState.isEmpty()) return null;
int stateId = BlockStateUtils.blockStateToId(blockState.get());
int newStateId;
if (!user.clientModEnabled()) {
newStateId = PacketConsumers.remap(stateId);
} else {
newStateId = PacketConsumers.remapMOD(stateId);
}
if (newStateId == stateId) return null;
Object serializer = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$serializer(packedItem);
return FastNMS.INSTANCE.constructor$SynchedEntityData$DataValue(
entityDataId, serializer, Optional.of(BlockStateUtils.idToBlockState(newStateId))
);
}
}
static class BlockStateHandler_1_20 implements BlockStateHandler {
protected static final BlockStateHandler INSTANCE = new BlockStateHandler_1_20();
@Override
public Object handle(NetWorkUser user, Object packedItem, int entityDataId) {
if (entityDataId != AbstractMinecartData.DisplayBlock.id()) return null;
int stateId = (int) FastNMS.INSTANCE.field$SynchedEntityData$DataValue$value(packedItem);
int newStateId;
if (!user.clientModEnabled()) {
newStateId = PacketConsumers.remap(stateId);
} else {
newStateId = PacketConsumers.remapMOD(stateId);
}
if (newStateId == stateId) return null;
Object serializer = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$serializer(packedItem);
return FastNMS.INSTANCE.constructor$SynchedEntityData$DataValue(entityDataId, serializer, newStateId);
}
}
}

View File

@@ -1,9 +1,9 @@
package net.momirealms.craftengine.bukkit.plugin.network.handler;
import net.kyori.adventure.text.Component;
import net.momirealms.craftengine.bukkit.entity.data.BaseEntityData;
import net.momirealms.craftengine.bukkit.nms.FastNMS;
import net.momirealms.craftengine.bukkit.util.ComponentUtils;
import net.momirealms.craftengine.bukkit.util.EntityDataUtils;
import net.momirealms.craftengine.core.plugin.CraftEngine;
import net.momirealms.craftengine.core.plugin.config.Config;
import net.momirealms.craftengine.core.plugin.network.ByteBufPacketEvent;
@@ -32,7 +32,7 @@ public class ArmorStandPacketHandler implements EntityPacketHandler {
for (int i = 0; i < packedItems.size(); i++) {
Object packedItem = packedItems.get(i);
int entityDataId = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$id(packedItem);
if (entityDataId != EntityDataUtils.CUSTOM_NAME_DATA_ID) continue;
if (entityDataId != BaseEntityData.CustomName.id()) continue;
@SuppressWarnings("unchecked")
Optional<Object> optionalTextComponent = (Optional<Object>) FastNMS.INSTANCE.field$SynchedEntityData$DataValue$value(packedItem);
if (optionalTextComponent.isEmpty()) continue;

View File

@@ -1,11 +1,12 @@
package net.momirealms.craftengine.bukkit.plugin.network.handler;
import net.kyori.adventure.text.Component;
import net.momirealms.craftengine.bukkit.entity.data.BaseEntityData;
import net.momirealms.craftengine.bukkit.entity.data.BlockDisplayEntityData;
import net.momirealms.craftengine.bukkit.nms.FastNMS;
import net.momirealms.craftengine.bukkit.plugin.network.PacketConsumers;
import net.momirealms.craftengine.bukkit.util.BlockStateUtils;
import net.momirealms.craftengine.bukkit.util.ComponentUtils;
import net.momirealms.craftengine.bukkit.util.EntityDataUtils;
import net.momirealms.craftengine.core.plugin.CraftEngine;
import net.momirealms.craftengine.core.plugin.config.Config;
import net.momirealms.craftengine.core.plugin.network.ByteBufPacketEvent;
@@ -30,7 +31,7 @@ public class BlockDisplayPacketHandler implements EntityPacketHandler {
for (int i = 0; i < packedItems.size(); i++) {
Object packedItem = packedItems.get(i);
int entityDataId = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$id(packedItem);
if (entityDataId == EntityDataUtils.BLOCK_STATE_DATA_ID) {
if (entityDataId == BlockDisplayEntityData.DisplayedBlock.id()) {
Object blockState = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$value(packedItem);
int stateId = BlockStateUtils.blockStateToId(blockState);
int newStateId;
@@ -39,12 +40,13 @@ public class BlockDisplayPacketHandler implements EntityPacketHandler {
} else {
newStateId = PacketConsumers.remapMOD(stateId);
}
if (newStateId == stateId) continue;
Object serializer = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$serializer(packedItem);
packedItems.set(i, FastNMS.INSTANCE.constructor$SynchedEntityData$DataValue(
entityDataId, serializer, BlockStateUtils.idToBlockState(newStateId)
));
isChanged = true;
} else if (Config.interceptEntityName() && entityDataId == EntityDataUtils.CUSTOM_NAME_DATA_ID) {
} else if (Config.interceptEntityName() && entityDataId == BaseEntityData.CustomName.id()) {
@SuppressWarnings("unchecked")
Optional<Object> optionalTextComponent = (Optional<Object>) FastNMS.INSTANCE.field$SynchedEntityData$DataValue$value(packedItem);
if (optionalTextComponent.isEmpty()) continue;

View File

@@ -28,7 +28,7 @@ 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);
if (entityDataId != EntityDataUtils.ITEM_DATA_ID) continue;
if (entityDataId != EntityDataUtils.UNSAFE_ITEM_DATA_ID) continue;
Object nmsItemStack = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$value(packedItem);
if (!CoreReflections.clazz$ItemStack.isInstance(nmsItemStack)) {
long time = System.currentTimeMillis();

View File

@@ -0,0 +1,79 @@
package net.momirealms.craftengine.bukkit.plugin.network.handler;
import net.kyori.adventure.text.Component;
import net.momirealms.craftengine.bukkit.entity.data.BaseEntityData;
import net.momirealms.craftengine.bukkit.entity.data.EnderManData;
import net.momirealms.craftengine.bukkit.nms.FastNMS;
import net.momirealms.craftengine.bukkit.plugin.network.PacketConsumers;
import net.momirealms.craftengine.bukkit.util.BlockStateUtils;
import net.momirealms.craftengine.bukkit.util.ComponentUtils;
import net.momirealms.craftengine.core.plugin.CraftEngine;
import net.momirealms.craftengine.core.plugin.config.Config;
import net.momirealms.craftengine.core.plugin.network.ByteBufPacketEvent;
import net.momirealms.craftengine.core.plugin.network.EntityPacketHandler;
import net.momirealms.craftengine.core.plugin.network.NetWorkUser;
import net.momirealms.craftengine.core.util.AdventureHelper;
import net.momirealms.craftengine.core.util.FriendlyByteBuf;
import java.util.List;
import java.util.Map;
import java.util.Optional;
public class EndermanPacketHandler implements EntityPacketHandler {
public static final EndermanPacketHandler INSTANCE = new EndermanPacketHandler();
@Override
public void handleSetEntityData(NetWorkUser user, ByteBufPacketEvent event) {
FriendlyByteBuf buf = event.getBuffer();
int id = buf.readVarInt();
boolean isChanged = false;
List<Object> packedItems = FastNMS.INSTANCE.method$ClientboundSetEntityDataPacket$unpack(buf);
for (int i = 0; i < packedItems.size(); i++) {
Object packedItem = packedItems.get(i);
int entityDataId = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$id(packedItem);
if (entityDataId == EnderManData.CarryState.id()) {
@SuppressWarnings("unchecked")
Optional<Object> blockState = (Optional<Object>) FastNMS.INSTANCE.field$SynchedEntityData$DataValue$value(packedItem);
if (blockState.isEmpty()) continue;
int stateId = BlockStateUtils.blockStateToId(blockState.get());
int newStateId;
if (!user.clientModEnabled()) {
newStateId = PacketConsumers.remap(stateId);
} else {
newStateId = PacketConsumers.remapMOD(stateId);
}
if (newStateId == stateId) continue;
Object serializer = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$serializer(packedItem);
packedItems.set(i, FastNMS.INSTANCE.constructor$SynchedEntityData$DataValue(
entityDataId, serializer, Optional.of(BlockStateUtils.idToBlockState(newStateId))
));
isChanged = true;
} else if (Config.interceptEntityName() && entityDataId == BaseEntityData.CustomName.id()) {
@SuppressWarnings("unchecked")
Optional<Object> optionalTextComponent = (Optional<Object>) FastNMS.INSTANCE.field$SynchedEntityData$DataValue$value(packedItem);
if (optionalTextComponent.isEmpty()) continue;
Object textComponent = optionalTextComponent.get();
String json = ComponentUtils.minecraftToJson(textComponent);
Map<String, Component> tokens = CraftEngine.instance().fontManager().matchTags(json);
if (tokens.isEmpty()) continue;
Component component = AdventureHelper.jsonToComponent(json);
for (Map.Entry<String, Component> token : tokens.entrySet()) {
component = component.replaceText(b -> b.matchLiteral(token.getKey()).replacement(token.getValue()));
}
Object serializer = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$serializer(packedItem);
packedItems.set(i, FastNMS.INSTANCE.constructor$SynchedEntityData$DataValue(
entityDataId, serializer, Optional.of(ComponentUtils.adventureToMinecraft(component))
));
isChanged = true;
}
}
if (isChanged) {
event.setChanged(true);
buf.clear();
buf.writeVarInt(event.packetID());
buf.writeVarInt(id);
FastNMS.INSTANCE.method$ClientboundSetEntityDataPacket$pack(packedItems, buf);
}
}
}

View File

@@ -1,9 +1,9 @@
package net.momirealms.craftengine.bukkit.plugin.network.handler;
import net.momirealms.craftengine.bukkit.entity.data.ItemDisplayEntityData;
import net.momirealms.craftengine.bukkit.item.BukkitItemManager;
import net.momirealms.craftengine.bukkit.nms.FastNMS;
import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer;
import net.momirealms.craftengine.bukkit.util.EntityDataUtils;
import net.momirealms.craftengine.core.plugin.network.ByteBufPacketEvent;
import net.momirealms.craftengine.core.plugin.network.EntityPacketHandler;
import net.momirealms.craftengine.core.plugin.network.NetWorkUser;
@@ -25,7 +25,7 @@ public class ItemDisplayPacketHandler implements EntityPacketHandler {
for (int i = 0; i < packedItems.size(); i++) {
Object packedItem = packedItems.get(i);
int entityDataId = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$id(packedItem);
if (entityDataId != EntityDataUtils.DISPLAYED_ITEM_DATA_ID) continue;
if (entityDataId != ItemDisplayEntityData.DisplayedItem.id()) continue;
Object nmsItemStack = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$value(packedItem);
ItemStack itemStack = FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(nmsItemStack);
Optional<ItemStack> optional = BukkitItemManager.instance().s2c(itemStack, (BukkitServerPlayer) user);

View File

@@ -1,10 +1,10 @@
package net.momirealms.craftengine.bukkit.plugin.network.handler;
import net.momirealms.craftengine.bukkit.entity.data.ItemFrameData;
import net.momirealms.craftengine.bukkit.item.BukkitItemManager;
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;
@@ -28,7 +28,7 @@ public class ItemFramePacketHandler implements EntityPacketHandler {
for (int i = 0; i < packedItems.size(); i++) {
Object packedItem = packedItems.get(i);
int entityDataId = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$id(packedItem);
if (entityDataId != EntityDataUtils.ITEM_FRAME_DATA_ID) continue;
if (entityDataId != ItemFrameData.Item.id()) continue;
Object nmsItemStack = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$value(packedItem);
if (!CoreReflections.clazz$ItemStack.isInstance(nmsItemStack)) {
long time = System.currentTimeMillis();

View File

@@ -0,0 +1,77 @@
package net.momirealms.craftengine.bukkit.plugin.network.handler;
import net.kyori.adventure.text.Component;
import net.momirealms.craftengine.bukkit.entity.data.BaseEntityData;
import net.momirealms.craftengine.bukkit.entity.data.BlockDisplayEntityData;
import net.momirealms.craftengine.bukkit.entity.data.PrimedTntData;
import net.momirealms.craftengine.bukkit.nms.FastNMS;
import net.momirealms.craftengine.bukkit.plugin.network.PacketConsumers;
import net.momirealms.craftengine.bukkit.util.BlockStateUtils;
import net.momirealms.craftengine.bukkit.util.ComponentUtils;
import net.momirealms.craftengine.core.plugin.CraftEngine;
import net.momirealms.craftengine.core.plugin.config.Config;
import net.momirealms.craftengine.core.plugin.network.ByteBufPacketEvent;
import net.momirealms.craftengine.core.plugin.network.EntityPacketHandler;
import net.momirealms.craftengine.core.plugin.network.NetWorkUser;
import net.momirealms.craftengine.core.util.AdventureHelper;
import net.momirealms.craftengine.core.util.FriendlyByteBuf;
import java.util.List;
import java.util.Map;
import java.util.Optional;
public class PrimedTNTPacketHandler implements EntityPacketHandler {
public static final PrimedTNTPacketHandler INSTANCE = new PrimedTNTPacketHandler();
@Override
public void handleSetEntityData(NetWorkUser user, ByteBufPacketEvent event) {
FriendlyByteBuf buf = event.getBuffer();
int id = buf.readVarInt();
boolean isChanged = false;
List<Object> packedItems = FastNMS.INSTANCE.method$ClientboundSetEntityDataPacket$unpack(buf);
for (int i = 0; i < packedItems.size(); i++) {
Object packedItem = packedItems.get(i);
int entityDataId = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$id(packedItem);
if (entityDataId == PrimedTntData.BlockState.id()) {
Object blockState = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$value(packedItem);
int stateId = BlockStateUtils.blockStateToId(blockState);
int newStateId;
if (!user.clientModEnabled()) {
newStateId = PacketConsumers.remap(stateId);
} else {
newStateId = PacketConsumers.remapMOD(stateId);
}
if (newStateId == stateId) continue;
Object serializer = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$serializer(packedItem);
packedItems.set(i, FastNMS.INSTANCE.constructor$SynchedEntityData$DataValue(
entityDataId, serializer, BlockStateUtils.idToBlockState(newStateId)
));
isChanged = true;
} else if (Config.interceptEntityName() && entityDataId == BaseEntityData.CustomName.id()) {
@SuppressWarnings("unchecked")
Optional<Object> optionalTextComponent = (Optional<Object>) FastNMS.INSTANCE.field$SynchedEntityData$DataValue$value(packedItem);
if (optionalTextComponent.isEmpty()) continue;
Object textComponent = optionalTextComponent.get();
String json = ComponentUtils.minecraftToJson(textComponent);
Map<String, Component> tokens = CraftEngine.instance().fontManager().matchTags(json);
if (tokens.isEmpty()) continue;
Component component = AdventureHelper.jsonToComponent(json);
for (Map.Entry<String, Component> token : tokens.entrySet()) {
component = component.replaceText(b -> b.matchLiteral(token.getKey()).replacement(token.getValue()));
}
Object serializer = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$serializer(packedItem);
packedItems.set(i, FastNMS.INSTANCE.constructor$SynchedEntityData$DataValue(
entityDataId, serializer, Optional.of(ComponentUtils.adventureToMinecraft(component))
));
isChanged = true;
}
}
if (isChanged) {
event.setChanged(true);
buf.clear();
buf.writeVarInt(event.packetID());
buf.writeVarInt(id);
FastNMS.INSTANCE.method$ClientboundSetEntityDataPacket$pack(packedItems, buf);
}
}
}

View File

@@ -1,10 +1,10 @@
package net.momirealms.craftengine.bukkit.plugin.network.handler;
import net.kyori.adventure.text.Component;
import net.momirealms.craftengine.bukkit.entity.data.TextDisplayEntityData;
import net.momirealms.craftengine.bukkit.nms.FastNMS;
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections;
import net.momirealms.craftengine.bukkit.util.ComponentUtils;
import net.momirealms.craftengine.bukkit.util.EntityDataUtils;
import net.momirealms.craftengine.core.plugin.CraftEngine;
import net.momirealms.craftengine.core.plugin.config.Config;
import net.momirealms.craftengine.core.plugin.network.ByteBufPacketEvent;
@@ -31,7 +31,7 @@ public class TextDisplayPacketHandler implements EntityPacketHandler {
for (int i = 0; i < packedItems.size(); i++) {
Object packedItem = packedItems.get(i);
int entityDataId = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$id(packedItem);
if (entityDataId != EntityDataUtils.TEXT_DATA_ID) continue;
if (entityDataId != TextDisplayEntityData.Text.id()) continue;
Object textComponent = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$value(packedItem);
if (textComponent == CoreReflections.instance$Component$empty) break;
String json = ComponentUtils.minecraftToJson(textComponent);

View File

@@ -20,6 +20,8 @@ public final class MBlocks {
public static final Object SNOW;
public static final Object WATER;
public static final Object WATER$defaultState;
public static final Object TNT;
public static final Object TNT$defaultState;
private static Object getById(String id) {
Object rl = FastNMS.INSTANCE.method$ResourceLocation$fromNamespaceAndPath("minecraft", id);
@@ -41,5 +43,7 @@ public final class MBlocks {
SNOW = getById("snow");
WATER = getById("water");
WATER$defaultState = FastNMS.INSTANCE.method$Block$defaultState(WATER);
TNT = getById("tnt");
TNT$defaultState = FastNMS.INSTANCE.method$Block$defaultState(TNT);
}
}

View File

@@ -58,6 +58,24 @@ public final class MEntityTypes {
public static final int HAPPY_GHAST$registryId;
public static final Object PLAYER;
public static final int PLAYER$registryId;
public static final Object ENDERMAN;
public static final int ENDERMAN$registryId;
public static final Object TNT;
public static final int TNT$registryId;
public static final Object CHEST_MINECART;
public static final int CHEST_MINECART$registryId;
public static final Object COMMAND_BLOCK_MINECART;
public static final int COMMAND_BLOCK_MINECART$registryId;
public static final Object FURNACE_MINECART;
public static final int FURNACE_MINECART$registryId;
public static final Object HOPPER_MINECART;
public static final int HOPPER_MINECART$registryId;
public static final Object MINECART;
public static final int MINECART$registryId;
public static final Object SPAWNER_MINECART;
public static final int SPAWNER_MINECART$registryId;
public static final Object TNT_MINECART;
public static final int TNT_MINECART$registryId;
private static Object getById(String id) {
Object rl = FastNMS.INSTANCE.method$ResourceLocation$fromNamespaceAndPath("minecraft", id);
@@ -122,5 +140,23 @@ public final class MEntityTypes {
ARROW$registryId = getRegistryId(ARROW);
SPECTRAL_ARROW = getById("spectral_arrow");
SPECTRAL_ARROW$registryId = getRegistryId(SPECTRAL_ARROW);
ENDERMAN = getById("enderman");
ENDERMAN$registryId = getRegistryId(ENDERMAN);
TNT = getById("tnt");
TNT$registryId = getRegistryId(TNT);
CHEST_MINECART = getById("chest_minecart");
CHEST_MINECART$registryId = getRegistryId(CHEST_MINECART);
COMMAND_BLOCK_MINECART = getById("command_block_minecart");
COMMAND_BLOCK_MINECART$registryId = getRegistryId(COMMAND_BLOCK_MINECART);
FURNACE_MINECART = getById("furnace_minecart");
FURNACE_MINECART$registryId = getRegistryId(FURNACE_MINECART);
HOPPER_MINECART = getById("hopper_minecart");
HOPPER_MINECART$registryId = getRegistryId(HOPPER_MINECART);
MINECART = getById("minecart");
MINECART$registryId = getRegistryId(MINECART);
SPAWNER_MINECART = getById("spawner_minecart");
SPAWNER_MINECART$registryId = getRegistryId(SPAWNER_MINECART);
TNT_MINECART = getById("tnt_minecart");
TNT_MINECART$registryId = getRegistryId(TNT_MINECART);
}
}

View File

@@ -1,7 +1,5 @@
package net.momirealms.craftengine.bukkit.util;
import net.momirealms.craftengine.core.util.VersionHelper;
public final class EntityDataUtils {
private EntityDataUtils() {}
@@ -11,12 +9,7 @@ public final class EntityDataUtils {
private static final int USE_DEFAULT_BACKGROUND = 0x04; // 4
private static final int LEFT_ALIGNMENT = 0x08; // 8
private static final int RIGHT_ALIGNMENT = 0x10; // 16
public static final int BLOCK_STATE_DATA_ID = VersionHelper.isOrAbove1_20_2() ? 23 : 22;
public static final int TEXT_DATA_ID = VersionHelper.isOrAbove1_20_2() ? 23 : 22;
public static final int DISPLAYED_ITEM_DATA_ID = VersionHelper.isOrAbove1_20_2() ? 23 : 22;
public static final int CUSTOM_NAME_DATA_ID = 2;
public static final int ITEM_DATA_ID = 8;
public static final int ITEM_FRAME_DATA_ID = VersionHelper.isOrAbove1_21_6() ? 9 : 8;
public static final int UNSAFE_ITEM_DATA_ID = 8; // 正常来说应该通过定义 Data 获取 id 这样的做法未经验证可能不安全
public static byte encodeTextDisplayMask(boolean hasShadow, boolean isSeeThrough, boolean useDefaultBackground, int alignment) {
int bitMask = 0;