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

Merge pull request #229 from jhqwqmc/dev

feat(bukkit): 实现#157
This commit is contained in:
XiaoMoMi
2025-06-18 17:05:45 +08:00
committed by GitHub
24 changed files with 267 additions and 94 deletions

View File

@@ -116,7 +116,7 @@ public final class CraftEngineBlocks {
if (success) {
FastNMS.INSTANCE.method$BlockStateBase$onPlace(blockState, worldServer, blockPos, oldBlockState, false);
if (playSound) {
location.getWorld().playSound(location, block.sounds().placeSound().toString(), SoundCategory.BLOCKS, block.sounds().placeSound().volume(), block.sounds().placeSound().pitch());
location.getWorld().playSound(location, block.sounds().placeSound().id().toString(), SoundCategory.BLOCKS, block.sounds().placeSound().volume(), block.sounds().placeSound().pitch());
}
}
return success;

View File

@@ -21,6 +21,8 @@ public class BukkitBlockBehaviors extends BlockBehaviors {
public static final Key LAMP_BLOCK = Key.from("craftengine:lamp_block");
public static final Key TRAPDOOR_BLOCK = Key.from("craftengine:trapdoor_block");
public static final Key DOOR_BLOCK = Key.from("craftengine:door_block");
public static final Key STACKABLE_BLOCK = Key.from("craftengine:stackable_block");
public static final Key STURDY_BASE_BLOCK = Key.from("craftengine:sturdy_base_block");
public static void init() {
register(EMPTY, (block, args) -> EmptyBlockBehavior.INSTANCE);
@@ -40,5 +42,7 @@ public class BukkitBlockBehaviors extends BlockBehaviors {
register(LAMP_BLOCK, LampBlockBehavior.FACTORY);
register(TRAPDOOR_BLOCK, TrapDoorBlockBehavior.FACTORY);
register(DOOR_BLOCK, DoorBlockBehavior.FACTORY);
register(STACKABLE_BLOCK, StackableBlockBehavior.FACTORY);
register(STURDY_BASE_BLOCK, SturdyBaseBlockBehavior.FACTORY);
}
}

View File

@@ -0,0 +1,87 @@
package net.momirealms.craftengine.bukkit.block.behavior;
import net.momirealms.craftengine.bukkit.api.CraftEngineBlocks;
import net.momirealms.craftengine.bukkit.nms.FastNMS;
import net.momirealms.craftengine.core.block.BlockBehavior;
import net.momirealms.craftengine.core.block.CustomBlock;
import net.momirealms.craftengine.core.block.ImmutableBlockState;
import net.momirealms.craftengine.core.block.UpdateOption;
import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory;
import net.momirealms.craftengine.core.block.properties.Property;
import net.momirealms.craftengine.core.entity.player.InteractionResult;
import net.momirealms.craftengine.core.entity.player.Player;
import net.momirealms.craftengine.core.item.Item;
import net.momirealms.craftengine.core.item.context.UseOnContext;
import net.momirealms.craftengine.core.sound.SoundData;
import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.core.util.ResourceConfigUtils;
import net.momirealms.craftengine.core.world.BlockPos;
import net.momirealms.craftengine.core.world.World;
import org.bukkit.Location;
import org.bukkit.SoundCategory;
import org.bukkit.inventory.ItemStack;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class StackableBlockBehavior extends BukkitBlockBehavior {
public static final Factory FACTORY = new Factory();
private final Property<Integer> amountProperty;
private final Set<Key> items;
private final SoundData soundData;
public StackableBlockBehavior(CustomBlock block,Property<Integer> amountProperty, Set<Key> items, SoundData soundData) {
super(block);
this.amountProperty = amountProperty;
this.items = items;
this.soundData = soundData;
}
@Override
@SuppressWarnings("unchecked")
public InteractionResult useOnBlock(UseOnContext context, ImmutableBlockState state) {
Player player = context.getPlayer();
if (player.isSecondaryUseActive()) {
return InteractionResult.PASS;
}
Item<ItemStack> item = (Item<ItemStack>) context.getItem();
if (item == null) {
return InteractionResult.PASS;
}
if (this.items.contains(item.id()) && state.get(this.amountProperty) < this.amountProperty.possibleValues().getLast()) {
ImmutableBlockState nextStage = state.cycle(this.amountProperty);
World world = context.getLevel();
BlockPos pos = context.getClickedPos();
Location location = new Location((org.bukkit.World) world.platformWorld(), pos.x(), pos.y(), pos.z());
if (CraftEngineBlocks.place(location, nextStage, UpdateOption.UPDATE_NONE, false)) {
if (soundData != null) {
location.getWorld().playSound(location, soundData.id().toString(), SoundCategory.BLOCKS, soundData.volume(), soundData.pitch());
}
FastNMS.INSTANCE.method$ItemStack$consume(item.getLiteralObject(), 1, player.serverPlayer());
player.swingHand(context.getHand());
}
return InteractionResult.SUCCESS_AND_CANCEL;
}
return InteractionResult.PASS;
}
public static class Factory implements BlockBehaviorFactory {
@Override
@SuppressWarnings("unchecked")
public BlockBehavior create(CustomBlock block, Map<String, Object> arguments) {
Property<Integer> amount = (Property<Integer>) ResourceConfigUtils.requireNonNullOrThrow(block.getProperty("amount"), "warning.config.block.behavior.stackable.missing_amount");
SoundData soundData = arguments.containsKey("sound") ? SoundData.create(arguments.get("sound"), 1f, 0.8f) : null;
Set<Key> items = new HashSet<>();
if (arguments.get("items") instanceof List<?> list) {
for (Object obj : list) {
if (obj == null) continue;
items.add(Key.of(obj.toString()));
}
}
return new StackableBlockBehavior(block, amount, items, soundData);
}
}
}

View File

@@ -0,0 +1,46 @@
package net.momirealms.craftengine.bukkit.block.behavior;
import net.momirealms.craftengine.bukkit.nms.FastNMS;
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections;
import net.momirealms.craftengine.bukkit.util.DirectionUtils;
import net.momirealms.craftengine.core.block.BlockBehavior;
import net.momirealms.craftengine.core.block.CustomBlock;
import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory;
import net.momirealms.craftengine.core.util.Direction;
import net.momirealms.craftengine.core.util.ResourceConfigUtils;
import java.util.Locale;
import java.util.Map;
public class SturdyBaseBlockBehavior extends AbstractCanSurviveBlockBehavior {
public static final Factory FACTORY = new Factory();
private final Direction direction;
public SturdyBaseBlockBehavior(CustomBlock block, int delay, Direction direction) {
super(block, delay);
this.direction = direction;
}
@Override
protected boolean canSurvive(Object thisBlock, Object state, Object world, Object blockPos) throws Exception {
int x = FastNMS.INSTANCE.field$Vec3i$x(blockPos) + this.direction.stepX();
int y = FastNMS.INSTANCE.field$Vec3i$y(blockPos) + this.direction.stepY();
int z = FastNMS.INSTANCE.field$Vec3i$z(blockPos) + this.direction.stepZ();
Object targetPos = FastNMS.INSTANCE.constructor$BlockPos(x, y, z);
Object blockState = FastNMS.INSTANCE.method$BlockGetter$getBlockState(world, targetPos);
return (boolean) CoreReflections.method$BlockStateBase$isFaceSturdy.invoke(
blockState, world, blockPos, DirectionUtils.toNMSDirection(this.direction.opposite()),
CoreReflections.instance$SupportType$FULL
);
}
public static class Factory implements BlockBehaviorFactory {
@Override
public BlockBehavior create(CustomBlock block, Map<String, Object> arguments) {
int delay = ResourceConfigUtils.getAsInt(arguments.getOrDefault("delay", 0), "delay");
Direction direction = Direction.valueOf(arguments.getOrDefault("direction", "down").toString().toUpperCase(Locale.ROOT));
return new SturdyBaseBlockBehavior(block, delay, direction);
}
}
}

View File

@@ -1,9 +1,9 @@
package net.momirealms.craftengine.bukkit.entity.data;
public class AgeableMobData<T> extends PathfinderMobData<T> {
public static final MobData<Boolean> Baby = new AgeableMobData<>(16, EntityDataValue.Serializers$BOOLEAN, false);
public static final MobData<Boolean> Baby = new AgeableMobData<>(AgeableMobData.class, EntityDataValue.Serializers$BOOLEAN, false);
public AgeableMobData(int id, Object serializer, T defaultValue) {
super(id, serializer, defaultValue);
public AgeableMobData(Class<?> clazz, Object serializer, T defaultValue) {
super(clazz, serializer, defaultValue);
}
}

View File

@@ -2,7 +2,7 @@ package net.momirealms.craftengine.bukkit.entity.data;
public class AnimalData<T> extends AgeableMobData<T> {
public AnimalData(int id, Object serializer, T defaultValue) {
super(id, serializer, defaultValue);
public AnimalData(Class<?> clazz, Object serializer, T defaultValue) {
super(clazz, serializer, defaultValue);
}
}

View File

@@ -5,16 +5,16 @@ import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflect
import java.util.Optional;
public class BaseEntityData<T> extends SimpleEntityData<T> {
public static final BaseEntityData<Byte> SharedFlags = new BaseEntityData<>(0, EntityDataValue.Serializers$BYTE, (byte) 0);
public static final BaseEntityData<Integer> AirSupply = new BaseEntityData<>(1, EntityDataValue.Serializers$INT, 300);
public static final BaseEntityData<Optional<Object>> CustomName = new BaseEntityData<>(2, EntityDataValue.Serializers$OPTIONAL_COMPONENT, Optional.empty());
public static final BaseEntityData<Boolean> CustomNameVisible = new BaseEntityData<>(3, EntityDataValue.Serializers$BOOLEAN, false);
public static final BaseEntityData<Boolean> Silent = new BaseEntityData<>(4, EntityDataValue.Serializers$BOOLEAN, false);
public static final BaseEntityData<Boolean> NoGravity = new BaseEntityData<>(5, EntityDataValue.Serializers$BOOLEAN, false);
public static final BaseEntityData<Object> Pose = new BaseEntityData<>(6, EntityDataValue.Serializers$POSE, CoreReflections.instance$Pose$STANDING);
public static final BaseEntityData<Integer> TicksFrozen = new BaseEntityData<>(7, EntityDataValue.Serializers$INT, 0);
public static final BaseEntityData<Byte> SharedFlags = new BaseEntityData<>(BaseEntityData.class, EntityDataValue.Serializers$BYTE, (byte) 0);
public static final BaseEntityData<Integer> AirSupply = new BaseEntityData<>(BaseEntityData.class, EntityDataValue.Serializers$INT, 300);
public static final BaseEntityData<Optional<Object>> CustomName = new BaseEntityData<>(BaseEntityData.class, EntityDataValue.Serializers$OPTIONAL_COMPONENT, Optional.empty());
public static final BaseEntityData<Boolean> CustomNameVisible = new BaseEntityData<>(BaseEntityData.class, EntityDataValue.Serializers$BOOLEAN, false);
public static final BaseEntityData<Boolean> Silent = new BaseEntityData<>(BaseEntityData.class, EntityDataValue.Serializers$BOOLEAN, false);
public static final BaseEntityData<Boolean> NoGravity = new BaseEntityData<>(BaseEntityData.class, EntityDataValue.Serializers$BOOLEAN, false);
public static final BaseEntityData<Object> Pose = new BaseEntityData<>(BaseEntityData.class, EntityDataValue.Serializers$POSE, CoreReflections.instance$Pose$STANDING);
public static final BaseEntityData<Integer> TicksFrozen = new BaseEntityData<>(BaseEntityData.class, EntityDataValue.Serializers$INT, 0);
public BaseEntityData(int id, Object serializer, T defaultValue) {
super(id, serializer, defaultValue);
public BaseEntityData(Class<?> clazz, Object serializer, T defaultValue) {
super(clazz, serializer, defaultValue);
}
}

View File

@@ -4,9 +4,9 @@ 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 = of(23, EntityDataValue.Serializers$BLOCK_STATE, MBlocks.AIR$defaultState);
public static final DisplayEntityData<Object> DisplayedBlock = new BlockDisplayEntityData<>(BlockDisplayEntityData.class, EntityDataValue.Serializers$BLOCK_STATE, MBlocks.AIR$defaultState);
public BlockDisplayEntityData(int id, Object serializer, T defaultValue) {
super(id, serializer, defaultValue);
public BlockDisplayEntityData(Class<?> clazz, Object serializer, T defaultValue) {
super(clazz, serializer, defaultValue);
}
}

View File

@@ -6,39 +6,40 @@ import org.joml.Vector3f;
public class DisplayEntityData<T> extends BaseEntityData<T> {
// Display only
public static final DisplayEntityData<Integer> InterpolationDelay = of(8, EntityDataValue.Serializers$INT, 0);
public static final DisplayEntityData<Integer> InterpolationDelay = of(DisplayEntityData.class, EntityDataValue.Serializers$INT, 0, true);
// 1.19.4-1.20.1
public static final DisplayEntityData<Integer> InterpolationDuration = of(9, EntityDataValue.Serializers$INT, 0);
public static final DisplayEntityData<Integer> InterpolationDuration = of(DisplayEntityData.class, EntityDataValue.Serializers$INT, 0, !VersionHelper.isOrAbove1_20_2());
// 1.20.2+
public static final DisplayEntityData<Integer> TransformationInterpolationDuration = of(9, EntityDataValue.Serializers$INT, 0);
public static final DisplayEntityData<Integer> PositionRotationInterpolationDuration = of(10, EntityDataValue.Serializers$INT, 0);
public static final DisplayEntityData<Integer> TransformationInterpolationDuration = of(DisplayEntityData.class, EntityDataValue.Serializers$INT, 0, VersionHelper.isOrAbove1_20_2());
public static final DisplayEntityData<Integer> PositionRotationInterpolationDuration = of(DisplayEntityData.class, EntityDataValue.Serializers$INT, 0, VersionHelper.isOrAbove1_20_2());
public static final DisplayEntityData<Object> Translation = of(11, EntityDataValue.Serializers$VECTOR3, new Vector3f(0f));
public static final DisplayEntityData<Object> Scale = of(12, EntityDataValue.Serializers$VECTOR3, new Vector3f(1f));
public static final DisplayEntityData<Object> RotationLeft = of(13, EntityDataValue.Serializers$QUATERNION, new Quaternionf(0f, 0f, 0f, 1f));
public static final DisplayEntityData<Object> RotationRight = of(14, EntityDataValue.Serializers$QUATERNION, new Quaternionf(0f, 0f, 0f, 1f));
public static final DisplayEntityData<Object> Translation = of(DisplayEntityData.class, EntityDataValue.Serializers$VECTOR3, new Vector3f(0f), true);
public static final DisplayEntityData<Object> Scale = of(DisplayEntityData.class, EntityDataValue.Serializers$VECTOR3, new Vector3f(1f), true);
public static final DisplayEntityData<Object> RotationLeft = of(DisplayEntityData.class, EntityDataValue.Serializers$QUATERNION, new Quaternionf(0f, 0f, 0f, 1f), true);
public static final DisplayEntityData<Object> RotationRight = of(DisplayEntityData.class, EntityDataValue.Serializers$QUATERNION, new Quaternionf(0f, 0f, 0f, 1f), true);
/**
* Billboard Constraints (0 = FIXED, 1 = VERTICAL, 2 = HORIZONTAL, 3 = CENTER)
*/
public static final DisplayEntityData<Byte> BillboardConstraints = of(15, EntityDataValue.Serializers$BYTE, (byte) 0);
public static final DisplayEntityData<Byte> BillboardConstraints = of(DisplayEntityData.class, EntityDataValue.Serializers$BYTE, (byte) 0, true);
/**
* Brightness override (blockLight << 4 | skyLight << 20)
*/
public static final DisplayEntityData<Integer> BrightnessOverride = of(16, EntityDataValue.Serializers$INT, -1);
public static final DisplayEntityData<Float> ViewRange = of(17, EntityDataValue.Serializers$FLOAT, 1f);
public static final DisplayEntityData<Float> ShadowRadius = of(18, EntityDataValue.Serializers$FLOAT, 0f);
public static final DisplayEntityData<Float> ShadowStrength = of(19, EntityDataValue.Serializers$FLOAT, 0f);
public static final DisplayEntityData<Float> Width = of(20, EntityDataValue.Serializers$FLOAT, 0f);
public static final DisplayEntityData<Float> Height = of(21, EntityDataValue.Serializers$FLOAT, 0f);
public static final DisplayEntityData<Integer> GlowColorOverride = of(22, EntityDataValue.Serializers$INT, -1);
public static final DisplayEntityData<Integer> BrightnessOverride = of(DisplayEntityData.class, EntityDataValue.Serializers$INT, -1, true);
public static final DisplayEntityData<Float> ViewRange = of(DisplayEntityData.class, EntityDataValue.Serializers$FLOAT, 1f, true);
public static final DisplayEntityData<Float> ShadowRadius = of(DisplayEntityData.class, EntityDataValue.Serializers$FLOAT, 0f, true);
public static final DisplayEntityData<Float> ShadowStrength = of(DisplayEntityData.class, EntityDataValue.Serializers$FLOAT, 0f, true);
public static final DisplayEntityData<Float> Width = of(DisplayEntityData.class, EntityDataValue.Serializers$FLOAT, 0f, true);
public static final DisplayEntityData<Float> Height = of(DisplayEntityData.class, EntityDataValue.Serializers$FLOAT, 0f, true);
public static final DisplayEntityData<Integer> GlowColorOverride = of(DisplayEntityData.class, EntityDataValue.Serializers$INT, -1, true);
public static <T> DisplayEntityData<T> of(final int id, final Object serializer, T defaultValue) {
return new DisplayEntityData<>(id, serializer, defaultValue);
public static <T> DisplayEntityData<T> of(final Class<?> clazz, final Object serializer, T defaultValue, boolean condition) {
if (!condition) return null;
return new DisplayEntityData<>(clazz, serializer, defaultValue);
}
public DisplayEntityData(int id, Object serializer, T defaultValue) {
super(!VersionHelper.isOrAbove1_20_2() && id >= 11 ? id - 1 : id, serializer, defaultValue);
public DisplayEntityData(Class<?> clazz, Object serializer, T defaultValue) {
super(clazz, serializer, defaultValue);
}
}

View File

@@ -24,7 +24,7 @@ public interface EntityData<T> {
list.add(EntityDataValue.create(id(), serializer(), entityDataAccessor(), value));
}
static <T> EntityData<T> of(int id, Object serializer, T defaultValue) {
return new SimpleEntityData<>(id, serializer, defaultValue);
static <T> EntityData<T> of(Class<?> clazz, Object serializer, T defaultValue) {
return new SimpleEntityData<>(clazz, serializer, defaultValue);
}
}

View File

@@ -1,10 +1,10 @@
package net.momirealms.craftengine.bukkit.entity.data;
public class HappyGhastData<T> extends AnimalData<T> {
public static final HappyGhastData<Boolean> IsLeashHolder = new HappyGhastData<>(17, EntityDataValue.Serializers$BOOLEAN, false);
public static final BaseEntityData<Boolean> StaysStill = new HappyGhastData<>(18, EntityDataValue.Serializers$BOOLEAN, false);
public static final HappyGhastData<Boolean> IsLeashHolder = new HappyGhastData<>(HappyGhastData.class, EntityDataValue.Serializers$BOOLEAN, false);
public static final BaseEntityData<Boolean> StaysStill = new HappyGhastData<>(HappyGhastData.class, EntityDataValue.Serializers$BOOLEAN, false);
public HappyGhastData(int id, Object serializer, T defaultValue) {
super(id, serializer, defaultValue);
public HappyGhastData(Class<?> clazz, Object serializer, T defaultValue) {
super(clazz, serializer, defaultValue);
}
}

View File

@@ -1,17 +1,11 @@
package net.momirealms.craftengine.bukkit.entity.data;
import net.momirealms.craftengine.core.util.VersionHelper;
public class InteractionEntityData<T> extends BaseEntityData<T> {
public static final InteractionEntityData<Float> Width = of(8, EntityDataValue.Serializers$FLOAT, 1F);
public static final InteractionEntityData<Float> Height = of(9, EntityDataValue.Serializers$FLOAT, 1F);
public static final InteractionEntityData<Boolean> Responsive = of(10, EntityDataValue.Serializers$BOOLEAN, false);
public static final InteractionEntityData<Float> Width = new InteractionEntityData<>(InteractionEntityData.class, EntityDataValue.Serializers$FLOAT, 1F);
public static final InteractionEntityData<Float> Height = new InteractionEntityData<>(InteractionEntityData.class, EntityDataValue.Serializers$FLOAT, 1F);
public static final InteractionEntityData<Boolean> Responsive = new InteractionEntityData<>(InteractionEntityData.class, EntityDataValue.Serializers$BOOLEAN, false);
public static <T> InteractionEntityData<T> of(final int id, final Object serializer, T defaultValue) {
return new InteractionEntityData<>(id, serializer, defaultValue);
}
public InteractionEntityData(int id, Object serializer, T defaultValue) {
super(!VersionHelper.isOrAbove1_20_2() && id >= 11 ? id - 1 : id, serializer, defaultValue);
public InteractionEntityData(Class<?> clazz, Object serializer, T defaultValue) {
super(clazz, serializer, defaultValue);
}
}

View File

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

View File

@@ -4,15 +4,15 @@ import java.util.List;
import java.util.Optional;
public class LivingEntityData<T> extends BaseEntityData<T> {
public static final LivingEntityData<Byte> LivingEntityFlags = new LivingEntityData<>(8, EntityDataValue.Serializers$BYTE, (byte) 0);
public static final LivingEntityData<Float> Health = new LivingEntityData<>(9, EntityDataValue.Serializers$FLOAT, 1.0f);
public static final LivingEntityData<List<Object>> EffectParticles = new LivingEntityData<>(10, EntityDataValue.Serializers$PARTICLES, List.of());
public static final LivingEntityData<Boolean> EffectAmbience = new LivingEntityData<>(11, EntityDataValue.Serializers$BOOLEAN, false);
public static final LivingEntityData<Integer> ArrowCount = new LivingEntityData<>(12, EntityDataValue.Serializers$INT, 0);
public static final LivingEntityData<Integer> StingerCount = new LivingEntityData<>(13, EntityDataValue.Serializers$INT, 0);
public static final LivingEntityData<Optional<Object>> SleepingPos = new LivingEntityData<>(14, EntityDataValue.Serializers$OPTIONAL_BLOCK_POS, Optional.empty());
public static final LivingEntityData<Byte> LivingEntityFlags = new LivingEntityData<>(LivingEntityData.class, EntityDataValue.Serializers$BYTE, (byte) 0);
public static final LivingEntityData<Float> Health = new LivingEntityData<>(LivingEntityData.class, EntityDataValue.Serializers$FLOAT, 1.0f);
public static final LivingEntityData<List<Object>> EffectParticles = new LivingEntityData<>(LivingEntityData.class, EntityDataValue.Serializers$PARTICLES, List.of());
public static final LivingEntityData<Boolean> EffectAmbience = new LivingEntityData<>(LivingEntityData.class, EntityDataValue.Serializers$BOOLEAN, false);
public static final LivingEntityData<Integer> ArrowCount = new LivingEntityData<>(LivingEntityData.class, EntityDataValue.Serializers$INT, 0);
public static final LivingEntityData<Integer> StingerCount = new LivingEntityData<>(LivingEntityData.class, EntityDataValue.Serializers$INT, 0);
public static final LivingEntityData<Optional<Object>> SleepingPos = new LivingEntityData<>(LivingEntityData.class, EntityDataValue.Serializers$OPTIONAL_BLOCK_POS, Optional.empty());
public LivingEntityData(int id, Object serializer, T defaultValue) {
super(id, serializer, defaultValue);
public LivingEntityData(Class<?> clazz, Object serializer, T defaultValue) {
super(clazz, serializer, defaultValue);
}
}

View File

@@ -1,9 +1,9 @@
package net.momirealms.craftengine.bukkit.entity.data;
public class MobData<T> extends LivingEntityData<T> {
public static final MobData<Byte> MobFlags = new MobData<>(15, EntityDataValue.Serializers$BYTE, (byte) 0);
public static final MobData<Byte> MobFlags = new MobData<>(MobData.class, EntityDataValue.Serializers$BYTE, (byte) 0);
public MobData(int id, Object serializer, T defaultValue) {
super(id, serializer, defaultValue);
public MobData(Class<?> clazz, Object serializer, T defaultValue) {
super(clazz, serializer, defaultValue);
}
}

View File

@@ -2,7 +2,7 @@ package net.momirealms.craftengine.bukkit.entity.data;
public class PathfinderMobData<T> extends MobData<T> {
public PathfinderMobData(int id, Object serializer, T defaultValue) {
super(id, serializer, defaultValue);
public PathfinderMobData(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 ShulkerData<T> extends MobData<T> {
public static final ShulkerData<Object> AttachFace = new ShulkerData<>(16, EntityDataValue.Serializers$DIRECTION, CoreReflections.instance$Direction$DOWN);
public static final ShulkerData<Byte> Peek = new ShulkerData<>(17, EntityDataValue.Serializers$BYTE, (byte) 0);
public static final ShulkerData<Byte> Color = new ShulkerData<>(18, EntityDataValue.Serializers$BYTE, (byte) 16);
public static final ShulkerData<Object> AttachFace = new ShulkerData<>(ShulkerData.class, EntityDataValue.Serializers$DIRECTION, CoreReflections.instance$Direction$DOWN);
public static final ShulkerData<Byte> Peek = new ShulkerData<>(ShulkerData.class, EntityDataValue.Serializers$BYTE, (byte) 0);
public static final ShulkerData<Byte> Color = new ShulkerData<>(ShulkerData.class, EntityDataValue.Serializers$BYTE, (byte) 16);
public ShulkerData(int id, Object serializer, T defaultValue) {
super(id, serializer, defaultValue);
public ShulkerData(Class<?> clazz, Object serializer, T defaultValue) {
super(clazz, serializer, defaultValue);
}
}

View File

@@ -1,15 +1,17 @@
package net.momirealms.craftengine.bukkit.entity.data;
import net.momirealms.craftengine.bukkit.nms.FastNMS;
import net.momirealms.craftengine.core.entity.data.ClassTreeIdRegistry;
public class SimpleEntityData<T> implements EntityData<T> {
public static final ClassTreeIdRegistry ID_REGISTRY = new ClassTreeIdRegistry();
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;
public SimpleEntityData(Class<?> clazz, Object serializer, T defaultValue) {
this.id = ID_REGISTRY.define(clazz);
this.serializer = serializer;
this.defaultValue = defaultValue;
this.entityDataAccessor = FastNMS.INSTANCE.constructor$EntityDataAccessor(id, serializer);

View File

@@ -3,13 +3,13 @@ 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 = of(23, EntityDataValue.Serializers$COMPONENT, CoreReflections.instance$Component$empty);
public static final DisplayEntityData<Integer> LineWidth = of(24, EntityDataValue.Serializers$INT, 200);
public static final DisplayEntityData<Integer> BackgroundColor = of(25, EntityDataValue.Serializers$INT, 0x40000000);
public static final DisplayEntityData<Byte> TextOpacity = of(26, EntityDataValue.Serializers$BYTE, (byte) -1);
public static final DisplayEntityData<Byte> TextDisplayMasks = of(27, EntityDataValue.Serializers$BYTE, (byte) 0);
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 TextDisplayEntityData(int id, Object serializer, T defaultValue) {
super(id, serializer, defaultValue);
public TextDisplayEntityData(Class<?> clazz, Object serializer, T defaultValue) {
super(clazz, serializer, defaultValue);
}
}

View File

@@ -3,9 +3,9 @@ package net.momirealms.craftengine.bukkit.entity.data;
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MItems;
public class ThrowableItemProjectileData<T> extends BaseEntityData<T> {
public static final ThrowableItemProjectileData<Object> ItemStack = new ThrowableItemProjectileData<>(8, EntityDataValue.Serializers$ITEM_STACK, MItems.Air$ItemStack);
public static final ThrowableItemProjectileData<Object> ItemStack = new ThrowableItemProjectileData<>(ThrowableItemProjectileData.class, EntityDataValue.Serializers$ITEM_STACK, MItems.Air$ItemStack);
public ThrowableItemProjectileData(int id, Object serializer, T defaultValue) {
super(id, serializer, defaultValue);
public ThrowableItemProjectileData(Class<?> clazz, Object serializer, T defaultValue) {
super(clazz, serializer, defaultValue);
}
}

View File

@@ -1,10 +1,9 @@
package net.momirealms.craftengine.bukkit.item.listener;
import com.saicone.rtag.RtagItem;
import net.kyori.adventure.text.Component;
import net.momirealms.craftengine.bukkit.api.CraftEngineBlocks;
import net.momirealms.craftengine.bukkit.block.BukkitBlockManager;
import net.momirealms.craftengine.bukkit.item.LegacyItemWrapper;
import net.momirealms.craftengine.bukkit.item.BukkitItemManager;
import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine;
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.NetworkReflections;
import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer;
@@ -14,6 +13,7 @@ import net.momirealms.craftengine.core.block.CustomBlock;
import net.momirealms.craftengine.core.block.ImmutableBlockState;
import net.momirealms.craftengine.core.block.UpdateOption;
import net.momirealms.craftengine.core.block.properties.Property;
import net.momirealms.craftengine.core.item.Item;
import net.momirealms.craftengine.core.util.MCUtils;
import net.momirealms.craftengine.core.util.MiscUtils;
import org.bukkit.Material;
@@ -73,7 +73,7 @@ public class DebugStickListener implements Listener {
ComponentUtils.adventureToMinecraft(Component.translatable("item.minecraft.debug_stick.empty").arguments(Component.text(blockId))), true);
player.sendPacket(systemChatPacket, false);
} else {
LegacyItemWrapper wrapped = new LegacyItemWrapper(new RtagItem(itemInHand));
Item<ItemStack> wrapped = BukkitItemManager.instance().wrap(itemInHand);
Object storedData = wrapped.getJavaTag("craftengine:debug_stick_state");
if (storedData == null) storedData = new HashMap<>();
if (storedData instanceof Map<?,?> map) {

View File

@@ -256,6 +256,7 @@ warning.config.block.behavior.trapdoor.missing_half: "<yellow>Issue found in fil
warning.config.block.behavior.trapdoor.missing_facing: "<yellow>Issue found in file <arg:0> - The block '<arg:1>' is missing the required 'facing' property for 'trapdoor_block' behavior.</yellow>"
warning.config.block.behavior.trapdoor.missing_open: "<yellow>Issue found in file <arg:0> - The block '<arg:1>' is missing the required 'open' property for 'trapdoor_block' behavior.</yellow>"
warning.config.block.behavior.trapdoor.missing_powered: "<yellow>Issue found in file <arg:0> - The block '<arg:1>' is missing the required 'powered' property for 'trapdoor_block' behavior.</yellow>"
warning.config.block.behavior.stackable.missing_amount: "<yellow>Issue found in file <arg:0> - The block '<arg:1>' is missing the required 'amount' property for 'stackable_block' behavior.</yellow>"
warning.config.model.generation.missing_parent: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' is missing the required 'parent' argument in 'generation' section.</yellow>"
warning.config.model.generation.invalid_display_position: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' is using an invalid display position '<arg:2>' in 'generation.display' section. Allowed display positions: [<arg:3>]</yellow>"
warning.config.model.generation.invalid_gui_light: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' is using an invalid gui-light option '<arg:2>' in 'generation' section. Allowed gui light options: [<arg:3>]</yellow>"

View File

@@ -256,6 +256,7 @@ warning.config.block.behavior.trapdoor.missing_half: "<yellow>在文件 <arg:0>
warning.config.block.behavior.trapdoor.missing_facing: "<yellow>在文件 <arg:0> 发现问题 - 方块 '<arg:1>' 的 'trapdoor_block' 行为缺少必需的 'facing' 属性</yellow>"
warning.config.block.behavior.trapdoor.missing_open: "<yellow>在文件 <arg:0> 发现问题 - 方块 '<arg:1>' 的 'trapdoor_block' 行为缺少必需的 'open' 属性</yellow>"
warning.config.block.behavior.trapdoor.missing_powered: "<yellow>在文件 <arg:0> 发现问题 - 方块 '<arg:1>' 的 'trapdoor_block' 行为缺少必需的 'powered' 属性</yellow>"
warning.config.block.behavior.stackable.missing_amount: "<yellow>在文件 <arg:0> 发现问题 - 方块 '<arg:1>' 的 'stackable_block' 行为缺少必需的 'amount' 属性</yellow>"
warning.config.model.generation.missing_parent: "<yellow>在文件 <arg:0> 发现问题 - 配置项 '<arg:1>' 的 'generation' 段落缺少必需的 'parent' 参数</yellow>"
warning.config.model.generation.conflict: "<yellow>在文件 <arg:0> 发现问题 - 无法为 '<arg:1>' 生成模型 存在多个配置尝试使用相同路径 '<arg:2>' 生成不同的 JSON 模型</yellow>"
warning.config.model.generation.invalid_display_position: "<yellow>在文件 <arg:0> 发现问题 - 配置项 '<arg:1>' 在 'generation.display' 区域使用了无效的 display 位置类型 '<arg:2>'. 可用展示类型: [<arg:3>]</yellow>"

View File

@@ -0,0 +1,37 @@
package net.momirealms.craftengine.core.entity.data;
import it.unimi.dsi.fastutil.objects.Object2IntMap;
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
import net.momirealms.craftengine.core.plugin.CraftEngine;
public class ClassTreeIdRegistry {
private final Object2IntMap<Class<?>> classToLastIdCache = new Object2IntOpenHashMap<>();
public ClassTreeIdRegistry() {
classToLastIdCache.defaultReturnValue(-1);
}
public int getLastIdFor(Class<?> clazz) {
int cachedId = this.classToLastIdCache.getInt(clazz);
if (cachedId == -1) {
Class<?> currentClass = clazz;
while ((currentClass = currentClass.getSuperclass()) != Object.class) {
int parentCachedId = this.classToLastIdCache.getInt(currentClass);
if (parentCachedId != -1) {
return parentCachedId;
}
}
return -1;
} else {
return cachedId;
}
}
public int define(Class<?> clazz) {
int lastId = this.getLastIdFor(clazz);
int nextId = lastId == -1 ? 0 : lastId + 1;
this.classToLastIdCache.put(clazz, nextId);
CraftEngine.instance().debug(() -> "Defined " + clazz.getSimpleName() + " with id " + nextId);
return nextId;
}
}