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

优化座椅机制

This commit is contained in:
XiaoMoMi
2025-11-01 20:28:18 +08:00
parent 3c3ad096f1
commit 63e038db5a
68 changed files with 998 additions and 494 deletions

View File

@@ -2,6 +2,7 @@ package net.momirealms.craftengine.bukkit.api;
import net.momirealms.craftengine.bukkit.entity.furniture.BukkitFurniture; import net.momirealms.craftengine.bukkit.entity.furniture.BukkitFurniture;
import net.momirealms.craftengine.bukkit.entity.furniture.BukkitFurnitureManager; import net.momirealms.craftengine.bukkit.entity.furniture.BukkitFurnitureManager;
import net.momirealms.craftengine.bukkit.entity.seat.BukkitSeatManager;
import net.momirealms.craftengine.bukkit.nms.CollisionEntity; import net.momirealms.craftengine.bukkit.nms.CollisionEntity;
import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.nms.FastNMS;
import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine;
@@ -18,6 +19,7 @@ import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextPar
import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.core.world.World; import net.momirealms.craftengine.core.world.World;
import net.momirealms.craftengine.core.world.WorldPosition; import net.momirealms.craftengine.core.world.WorldPosition;
import net.momirealms.sparrow.nbt.CompoundTag;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.entity.Entity; import org.bukkit.entity.Entity;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
@@ -159,8 +161,7 @@ public final class CraftEngineFurniture {
* @return is seat or not * @return is seat or not
*/ */
public static boolean isSeat(@NotNull Entity entity) { public static boolean isSeat(@NotNull Entity entity) {
Integer baseEntityId = entity.getPersistentDataContainer().get(BukkitFurnitureManager.FURNITURE_SEAT_BASE_ENTITY_KEY, PersistentDataType.INTEGER); return entity.getPersistentDataContainer().has(BukkitSeatManager.SEAT_KEY);
return baseEntityId != null;
} }
/** /**
@@ -182,9 +183,12 @@ public final class CraftEngineFurniture {
*/ */
@Nullable @Nullable
public static BukkitFurniture getLoadedFurnitureBySeat(@NotNull Entity seat) { public static BukkitFurniture getLoadedFurnitureBySeat(@NotNull Entity seat) {
Integer baseEntityId = seat.getPersistentDataContainer().get(BukkitFurnitureManager.FURNITURE_SEAT_BASE_ENTITY_KEY, PersistentDataType.INTEGER); if (isSeat(seat)) {
if (baseEntityId == null) return null; CompoundTag seatExtraData = BukkitSeatManager.instance().getSeatExtraData(seat);
return BukkitFurnitureManager.instance().loadedFurnitureByRealEntityId(baseEntityId); int entityId = seatExtraData.getInt("entity_id");
BukkitFurnitureManager.instance().loadedFurnitureByRealEntityId(entityId);
}
return null;
} }
/** /**

View File

@@ -1,6 +1,7 @@
package net.momirealms.craftengine.bukkit.api.event; package net.momirealms.craftengine.bukkit.api.event;
import net.momirealms.craftengine.bukkit.entity.furniture.BukkitFurniture; import net.momirealms.craftengine.bukkit.entity.furniture.BukkitFurniture;
import net.momirealms.craftengine.core.entity.furniture.HitBox;
import net.momirealms.craftengine.core.entity.player.InteractionHand; import net.momirealms.craftengine.core.entity.player.InteractionHand;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
@@ -15,15 +16,23 @@ public final class FurnitureInteractEvent extends PlayerEvent implements Cancell
private final BukkitFurniture furniture; private final BukkitFurniture furniture;
private final InteractionHand hand; private final InteractionHand hand;
private final Location interactionPoint; private final Location interactionPoint;
private final HitBox hitBox;
public FurnitureInteractEvent(@NotNull Player player, public FurnitureInteractEvent(@NotNull Player player,
@NotNull BukkitFurniture furniture, @NotNull BukkitFurniture furniture,
@NotNull InteractionHand hand, @NotNull InteractionHand hand,
@NotNull Location interactionPoint) { @NotNull Location interactionPoint,
@NotNull HitBox hitBox) {
super(player); super(player);
this.furniture = furniture; this.furniture = furniture;
this.hand = hand; this.hand = hand;
this.interactionPoint = interactionPoint; this.interactionPoint = interactionPoint;
this.hitBox = hitBox;
}
@NotNull
public HitBox hitBox() {
return hitBox;
} }
@NotNull @NotNull

View File

@@ -43,6 +43,7 @@ public class BukkitBlockBehaviors extends BlockBehaviors {
public static final Key ATTACHED_STEM_BLOCK = Key.from("craftengine:attached_stem_block"); public static final Key ATTACHED_STEM_BLOCK = Key.from("craftengine:attached_stem_block");
public static final Key CHIME_BLOCK = Key.from("craftengine:chime_block"); public static final Key CHIME_BLOCK = Key.from("craftengine:chime_block");
public static final Key BUDDING_BLOCK = Key.from("craftengine:budding_block"); public static final Key BUDDING_BLOCK = Key.from("craftengine:budding_block");
public static final Key SEAT_BLOCK = Key.from("craftengine:seat_block");
public static void init() { public static void init() {
register(EMPTY, (block, args) -> EmptyBlockBehavior.INSTANCE); register(EMPTY, (block, args) -> EmptyBlockBehavior.INSTANCE);
@@ -84,5 +85,6 @@ public class BukkitBlockBehaviors extends BlockBehaviors {
register(ATTACHED_STEM_BLOCK, AttachedStemBlockBehavior.FACTORY); register(ATTACHED_STEM_BLOCK, AttachedStemBlockBehavior.FACTORY);
register(CHIME_BLOCK, ChimeBlockBehavior.FACTORY); register(CHIME_BLOCK, ChimeBlockBehavior.FACTORY);
register(BUDDING_BLOCK, BuddingBlockBehavior.FACTORY); register(BUDDING_BLOCK, BuddingBlockBehavior.FACTORY);
register(SEAT_BLOCK, SeatBlockBehavior.FACTORY);
} }
} }

View File

@@ -0,0 +1,80 @@
package net.momirealms.craftengine.bukkit.block.behavior;
import net.momirealms.craftengine.bukkit.block.entity.BukkitBlockEntityTypes;
import net.momirealms.craftengine.bukkit.block.entity.SeatBlockEntity;
import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer;
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.behavior.BlockBehaviorFactory;
import net.momirealms.craftengine.core.block.behavior.EntityBlockBehavior;
import net.momirealms.craftengine.core.block.entity.BlockEntity;
import net.momirealms.craftengine.core.block.entity.BlockEntityType;
import net.momirealms.craftengine.core.block.properties.Property;
import net.momirealms.craftengine.core.entity.player.InteractionResult;
import net.momirealms.craftengine.core.entity.seat.SeatConfig;
import net.momirealms.craftengine.core.item.context.UseOnContext;
import net.momirealms.craftengine.core.util.HorizontalDirection;
import net.momirealms.craftengine.core.world.BlockPos;
import net.momirealms.craftengine.core.world.CEWorld;
import java.util.Map;
public class SeatBlockBehavior extends BukkitBlockBehavior implements EntityBlockBehavior {
public static final Factory FACTORY = new Factory();
private final Property<HorizontalDirection> directionProperty;
private final SeatConfig[] seats;
public SeatBlockBehavior(CustomBlock customBlock, Property<HorizontalDirection> directionProperty, SeatConfig[] seats) {
super(customBlock);
this.seats = seats;
this.directionProperty = directionProperty;
}
@Override
public BlockEntity createBlockEntity(BlockPos pos, ImmutableBlockState state) {
return new SeatBlockEntity(pos, state, this.seats);
}
@Override
public <T extends BlockEntity> BlockEntityType<T> blockEntityType(ImmutableBlockState state) {
return EntityBlockBehavior.blockEntityTypeHelper(BukkitBlockEntityTypes.SEAT);
}
public Property<HorizontalDirection> directionProperty() {
return this.directionProperty;
}
@Override
public InteractionResult useWithoutItem(UseOnContext context, ImmutableBlockState state) {
BukkitServerPlayer player = (BukkitServerPlayer) context.getPlayer();
if (player == null || player.isSecondaryUseActive()) {
return InteractionResult.PASS;
}
player.swingHand(context.getHand());
CEWorld world = context.getLevel().storageWorld();
BlockEntity blockEntity = world.getBlockEntityAtIfLoaded(context.getClickedPos());
if (!(blockEntity instanceof SeatBlockEntity seatBlockEntity)) {
return InteractionResult.PASS;
}
if (seatBlockEntity.spawnSeat(player)) {
return InteractionResult.SUCCESS_AND_CANCEL;
} else {
return InteractionResult.PASS;
}
}
public static class Factory implements BlockBehaviorFactory {
@SuppressWarnings("unchecked")
@Override
public BlockBehavior create(CustomBlock block, Map<String, Object> arguments) {
Property<HorizontalDirection> directionProperty = null;
Property<?> facing = block.getProperty("facing");
if (facing != null && facing.valueClass() == HorizontalDirection.class) {
directionProperty = (Property<HorizontalDirection>) facing;
}
return new SeatBlockBehavior(block, directionProperty, SeatConfig.fromObj(arguments.get("seats")));
}
}
}

View File

@@ -38,7 +38,7 @@ public class SimpleParticleBlockBehavior extends BukkitBlockBehavior implements
} }
@Override @Override
public <T extends BlockEntity> BlockEntityType<T> blockEntityType() { public <T extends BlockEntity> BlockEntityType<T> blockEntityType(ImmutableBlockState state) {
return EntityBlockBehavior.blockEntityTypeHelper(BukkitBlockEntityTypes.SIMPLE_PARTICLE); return EntityBlockBehavior.blockEntityTypeHelper(BukkitBlockEntityTypes.SIMPLE_PARTICLE);
} }

View File

@@ -116,7 +116,7 @@ public class SimpleStorageBlockBehavior extends BukkitBlockBehavior implements E
} }
@Override @Override
public <T extends BlockEntity> BlockEntityType<T> blockEntityType() { public <T extends BlockEntity> BlockEntityType<T> blockEntityType(ImmutableBlockState state) {
return EntityBlockBehavior.blockEntityTypeHelper(BukkitBlockEntityTypes.SIMPLE_STORAGE); return EntityBlockBehavior.blockEntityTypeHelper(BukkitBlockEntityTypes.SIMPLE_STORAGE);
} }

View File

@@ -1,6 +1,5 @@
package net.momirealms.craftengine.bukkit.block.behavior; package net.momirealms.craftengine.bukkit.block.behavior;
import net.momirealms.craftengine.core.block.BlockBehavior;
import net.momirealms.craftengine.core.block.CustomBlock; import net.momirealms.craftengine.core.block.CustomBlock;
import net.momirealms.craftengine.core.block.ImmutableBlockState; import net.momirealms.craftengine.core.block.ImmutableBlockState;
import net.momirealms.craftengine.core.block.behavior.AbstractBlockBehavior; import net.momirealms.craftengine.core.block.behavior.AbstractBlockBehavior;
@@ -47,7 +46,7 @@ public class UnsafeCompositeBlockBehavior extends BukkitBlockBehavior
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@Override @Override
public <T extends BlockBehavior> Optional<T> getAs(Class<T> tClass) { public <T> Optional<T> getAs(Class<T> tClass) {
for (AbstractBlockBehavior behavior : this.behaviors) { for (AbstractBlockBehavior behavior : this.behaviors) {
if (tClass.isInstance(behavior)) { if (tClass.isInstance(behavior)) {
return Optional.of((T) behavior); return Optional.of((T) behavior);

View File

@@ -47,7 +47,7 @@ public class WallTorchParticleBlockBehavior extends BukkitBlockBehavior implemen
} }
@Override @Override
public <T extends BlockEntity> BlockEntityType<T> blockEntityType() { public <T extends BlockEntity> BlockEntityType<T> blockEntityType(ImmutableBlockState state) {
return EntityBlockBehavior.blockEntityTypeHelper(BukkitBlockEntityTypes.WALL_TORCH_PARTICLE); return EntityBlockBehavior.blockEntityTypeHelper(BukkitBlockEntityTypes.WALL_TORCH_PARTICLE);
} }

View File

@@ -5,9 +5,10 @@ import net.momirealms.craftengine.core.block.entity.BlockEntityTypeKeys;
import net.momirealms.craftengine.core.block.entity.BlockEntityTypes; import net.momirealms.craftengine.core.block.entity.BlockEntityTypes;
public class BukkitBlockEntityTypes extends BlockEntityTypes { public class BukkitBlockEntityTypes extends BlockEntityTypes {
public static final BlockEntityType<SimpleStorageBlockEntity> SIMPLE_STORAGE = register(BlockEntityTypeKeys.SIMPLE_STORAGE, SimpleStorageBlockEntity::new); public static final BlockEntityType<SimpleStorageBlockEntity> SIMPLE_STORAGE = register(BlockEntityTypeKeys.SIMPLE_STORAGE);
public static final BlockEntityType<SimpleParticleBlockEntity> SIMPLE_PARTICLE = register(BlockEntityTypeKeys.SIMPLE_PARTICLE, SimpleParticleBlockEntity::new); public static final BlockEntityType<SimpleParticleBlockEntity> SIMPLE_PARTICLE = register(BlockEntityTypeKeys.SIMPLE_PARTICLE);
public static final BlockEntityType<WallTorchParticleBlockEntity> WALL_TORCH_PARTICLE = register(BlockEntityTypeKeys.WALL_TORCH_PARTICLE, WallTorchParticleBlockEntity::new); public static final BlockEntityType<WallTorchParticleBlockEntity> WALL_TORCH_PARTICLE = register(BlockEntityTypeKeys.WALL_TORCH_PARTICLE);
public static final BlockEntityType<SeatBlockEntity> SEAT = register(BlockEntityTypeKeys.SEAT);
private BukkitBlockEntityTypes() {} private BukkitBlockEntityTypes() {}
} }

View File

@@ -0,0 +1,69 @@
package net.momirealms.craftengine.bukkit.block.entity;
import net.momirealms.craftengine.bukkit.block.behavior.SeatBlockBehavior;
import net.momirealms.craftengine.bukkit.entity.seat.BukkitSeat;
import net.momirealms.craftengine.core.block.ImmutableBlockState;
import net.momirealms.craftengine.core.block.entity.BlockEntity;
import net.momirealms.craftengine.core.block.properties.Property;
import net.momirealms.craftengine.core.entity.player.Player;
import net.momirealms.craftengine.core.entity.seat.Seat;
import net.momirealms.craftengine.core.entity.seat.SeatConfig;
import net.momirealms.craftengine.core.entity.seat.SeatOwner;
import net.momirealms.craftengine.core.util.HorizontalDirection;
import net.momirealms.craftengine.core.world.BlockPos;
import net.momirealms.craftengine.core.world.WorldPosition;
import net.momirealms.sparrow.nbt.CompoundTag;
import java.util.Optional;
public class SeatBlockEntity extends BlockEntity implements SeatOwner {
private final Seat<SeatBlockEntity>[] seats;
@SuppressWarnings("unchecked")
public SeatBlockEntity(BlockPos pos, ImmutableBlockState blockState, SeatConfig[] seats) {
super(BukkitBlockEntityTypes.SEAT, pos, blockState);
this.seats = new Seat[seats.length];
for (int i = 0; i < seats.length; i++) {
this.seats[i] = new BukkitSeat<>(this, seats[i]);
}
}
@Override
public void saveCustomData(CompoundTag data) {
data.putString("type", "seat_block_entity");
}
@Override
public void preRemove() {
for (Seat<SeatBlockEntity> seat : this.seats) {
seat.destroy();
}
}
public boolean spawnSeat(Player player) {
Optional<SeatBlockBehavior> seatBehavior = super.blockState.behavior().getAs(SeatBlockBehavior.class);
if (seatBehavior.isEmpty()) {
return false;
}
float yRot = 0;
Property<HorizontalDirection> directionProperty = seatBehavior.get().directionProperty();
if (directionProperty != null) {
HorizontalDirection direction = super.blockState.get(directionProperty);
if (direction == HorizontalDirection.NORTH) {
yRot = 180;
} else if (direction == HorizontalDirection.EAST) {
yRot = -90;
} else if (direction == HorizontalDirection.WEST) {
yRot = 90;
}
}
for (Seat<SeatBlockEntity> seat : this.seats) {
if (!seat.isOccupied()) {
if (seat.spawnSeat(player, new WorldPosition(super.world.world(), super.pos.x() + 0.5, super.pos.y(), super.pos.z() + 0.5, 0, 180 - yRot))) {
return true;
}
}
}
return false;
}
}

View File

@@ -13,7 +13,7 @@ import java.lang.ref.WeakReference;
import java.util.UUID; import java.util.UUID;
public class BukkitEntity extends AbstractEntity { public class BukkitEntity extends AbstractEntity {
private final WeakReference<org.bukkit.entity.Entity> entity; protected final WeakReference<org.bukkit.entity.Entity> entity;
public BukkitEntity(org.bukkit.entity.Entity entity) { public BukkitEntity(org.bukkit.entity.Entity entity) {
this.entity = new WeakReference<>(entity); this.entity = new WeakReference<>(entity);

View File

@@ -5,20 +5,16 @@ import it.unimi.dsi.fastutil.ints.IntArrayList;
import net.momirealms.craftengine.bukkit.entity.BukkitEntity; import net.momirealms.craftengine.bukkit.entity.BukkitEntity;
import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.nms.FastNMS;
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections;
import net.momirealms.craftengine.bukkit.util.EntityUtils;
import net.momirealms.craftengine.bukkit.util.LegacyAttributeUtils;
import net.momirealms.craftengine.bukkit.util.LocationUtils; import net.momirealms.craftengine.bukkit.util.LocationUtils;
import net.momirealms.craftengine.core.entity.furniture.*; import net.momirealms.craftengine.core.entity.furniture.*;
import net.momirealms.craftengine.core.entity.seat.Seat;
import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.CraftEngine;
import net.momirealms.craftengine.core.util.ArrayUtils;
import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.core.util.QuaternionUtils; import net.momirealms.craftengine.core.util.QuaternionUtils;
import net.momirealms.craftengine.core.util.VersionHelper;
import net.momirealms.craftengine.core.world.WorldPosition; import net.momirealms.craftengine.core.world.WorldPosition;
import net.momirealms.craftengine.core.world.collision.AABB;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.attribute.Attribute; import org.bukkit.entity.Entity;
import org.bukkit.entity.*; import org.bukkit.entity.Player;
import org.bukkit.persistence.PersistentDataType; import org.bukkit.persistence.PersistentDataType;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
@@ -30,7 +26,6 @@ import java.lang.ref.WeakReference;
import java.util.*; import java.util.*;
public class BukkitFurniture implements Furniture { public class BukkitFurniture implements Furniture {
private final Key id;
private final CustomFurniture furniture; private final CustomFurniture furniture;
private final CustomFurniture.Placement placement; private final CustomFurniture.Placement placement;
private FurnitureExtraData extraData; private FurnitureExtraData extraData;
@@ -44,13 +39,10 @@ public class BukkitFurniture implements Furniture {
// cache // cache
private final List<Integer> fakeEntityIds; private final List<Integer> fakeEntityIds;
private final List<Integer> entityIds; private final List<Integer> entityIds;
private final Map<Integer, HitBox> hitBoxes = new Int2ObjectArrayMap<>(); private final Map<Integer, BukkitHitBox> hitBoxes = new Int2ObjectArrayMap<>();
private final Map<Integer, AABB> aabb = new Int2ObjectArrayMap<>(); private final Map<Integer, HitBoxPart> hitBoxParts = new Int2ObjectArrayMap<>();
private final boolean minimized; private final boolean minimized;
private final boolean hasExternalModel; private final boolean hasExternalModel;
// seats
private final Set<Vector3f> occupiedSeats = Collections.synchronizedSet(new HashSet<>());
private final Vector<WeakReference<Entity>> seats = new Vector<>();
// cached spawn packet // cached spawn packet
private Object cachedSpawnPacket; private Object cachedSpawnPacket;
private Object cachedMinimizedSpawnPacket; private Object cachedMinimizedSpawnPacket;
@@ -58,37 +50,40 @@ public class BukkitFurniture implements Furniture {
public BukkitFurniture(Entity baseEntity, public BukkitFurniture(Entity baseEntity,
CustomFurniture furniture, CustomFurniture furniture,
FurnitureExtraData extraData) { FurnitureExtraData extraData) {
this.id = furniture.id();
this.extraData = extraData; this.extraData = extraData;
this.baseEntityId = baseEntity.getEntityId(); this.baseEntityId = baseEntity.getEntityId();
this.location = baseEntity.getLocation(); this.location = baseEntity.getLocation();
this.baseEntity = new WeakReference<>(baseEntity); this.baseEntity = new WeakReference<>(baseEntity);
this.furniture = furniture; this.furniture = furniture;
this.minimized = furniture.settings().minimized(); this.minimized = furniture.settings().minimized();
this.placement = furniture.getValidPlacement(extraData.anchorType().orElseGet(furniture::getAnyAnchorType));
List<Integer> fakeEntityIds = new IntArrayList(); List<Integer> fakeEntityIds = new IntArrayList();
List<Integer> mainEntityIds = new IntArrayList(); List<Integer> mainEntityIds = new IntArrayList();
mainEntityIds.add(this.baseEntityId); mainEntityIds.add(this.baseEntityId);
this.placement = furniture.getValidPlacement(extraData.anchorType().orElseGet(furniture::getAnyAnchorType)); // 绑定外部模型
// bind external furniture
Optional<ExternalModel> optionalExternal = placement.externalModel(); Optional<ExternalModel> optionalExternal = placement.externalModel();
if (optionalExternal.isPresent()) { if (optionalExternal.isPresent()) {
try { try {
optionalExternal.get().bindModel(new BukkitEntity(baseEntity)); optionalExternal.get().bindModel(new BukkitEntity(baseEntity));
} catch (Exception e) { } catch (Exception e) {
CraftEngine.instance().logger().warn("Failed to load external model for furniture " + id, e); CraftEngine.instance().logger().warn("Failed to load external model for furniture " + id(), e);
} }
this.hasExternalModel = true; this.hasExternalModel = true;
} else { } else {
this.hasExternalModel = false; this.hasExternalModel = false;
} }
Quaternionf conjugated = QuaternionUtils.toQuaternionf(0, Math.toRadians(180 - this.location.getYaw()), 0).conjugate(); Quaternionf conjugated = QuaternionUtils.toQuaternionf(0, Math.toRadians(180 - this.location.getYaw()), 0).conjugate();
List<Object> packets = new ArrayList<>(); List<Object> packets = new ArrayList<>();
List<Object> minimizedPackets = new ArrayList<>(); List<Object> minimizedPackets = new ArrayList<>();
List<Collider> colliders = new ArrayList<>(); List<Collider> colliders = new ArrayList<>(4);
WorldPosition position = position(); WorldPosition position = position();
// 初始化家具的元素
for (FurnitureElement element : placement.elements()) { for (FurnitureElement element : placement.elements()) {
int entityId = CoreReflections.instance$Entity$ENTITY_COUNTER.incrementAndGet(); int entityId = CoreReflections.instance$Entity$ENTITY_COUNTER.incrementAndGet();
fakeEntityIds.add(entityId); fakeEntityIds.add(entityId);
@@ -97,28 +92,41 @@ public class BukkitFurniture implements Furniture {
if (this.minimized) minimizedPackets.add(packet); if (this.minimized) minimizedPackets.add(packet);
}); });
} }
for (HitBox hitBox : placement.hitBoxes()) {
int[] ids = hitBox.acquireEntityIds(CoreReflections.instance$Entity$ENTITY_COUNTER::incrementAndGet); // 初始化碰撞箱
for (HitBoxConfig hitBoxConfig : this.placement.hitBoxConfigs()) {
int[] ids = hitBoxConfig.acquireEntityIds(CoreReflections.instance$Entity$ENTITY_COUNTER::incrementAndGet);
List<HitBoxPart> aabbs = new ArrayList<>();
hitBoxConfig.initPacketsAndColliders(ids, position, conjugated, (packet, canBeMinimized) -> {
packets.add(packet);
if (this.minimized && !canBeMinimized) {
minimizedPackets.add(packet);
}
}, colliders::add, part -> {
this.hitBoxParts.put(part.entityId(), part);
aabbs.add(part);
});
BukkitHitBox hitBox = new BukkitHitBox(this, hitBoxConfig, aabbs.toArray(new HitBoxPart[0]));
for (int entityId : ids) { for (int entityId : ids) {
fakeEntityIds.add(entityId); fakeEntityIds.add(entityId);
mainEntityIds.add(entityId); mainEntityIds.add(entityId);
this.hitBoxes.put(entityId, hitBox); this.hitBoxes.put(entityId, hitBox);
} }
hitBox.initPacketsAndColliders(ids, position, conjugated, (packet, canBeMinimized) -> {
packets.add(packet);
if (this.minimized && !canBeMinimized) {
minimizedPackets.add(packet);
}
}, colliders::add, this.aabb::put);
} }
// 初始化缓存的家具包
try { try {
this.cachedSpawnPacket = FastNMS.INSTANCE.constructor$ClientboundBundlePacket(packets); this.cachedSpawnPacket = FastNMS.INSTANCE.constructor$ClientboundBundlePacket(packets);
if (this.minimized) { if (this.minimized) {
this.cachedMinimizedSpawnPacket = FastNMS.INSTANCE.constructor$ClientboundBundlePacket(minimizedPackets); this.cachedMinimizedSpawnPacket = FastNMS.INSTANCE.constructor$ClientboundBundlePacket(minimizedPackets);
} }
} catch (Exception e) { } catch (Exception e) {
CraftEngine.instance().logger().warn("Failed to init spawn packets for furniture " + id, e); CraftEngine.instance().logger().warn("Failed to init spawn packets for furniture " + id(), e);
} }
this.fakeEntityIds = fakeEntityIds; this.fakeEntityIds = fakeEntityIds;
this.entityIds = mainEntityIds; this.entityIds = mainEntityIds;
this.colliderEntities = colliders.toArray(new Collider[0]); this.colliderEntities = colliders.toArray(new Collider[0]);
@@ -186,57 +194,25 @@ public class BukkitFurniture implements Furniture {
return; return;
} }
this.baseEntity().remove(); this.baseEntity().remove();
this.destroyColliders();
this.destroySeats();
}
@Override
public void destroyColliders() {
for (Collider entity : this.colliderEntities) { for (Collider entity : this.colliderEntities) {
if (entity != null) if (entity != null)
entity.destroy(); entity.destroy();
} }
for (WeakReference<Entity> r : this.seats) {
Entity entity = r.get();
if (entity == null) continue;
for (Entity passenger : entity.getPassengers()) {
entity.removePassenger(passenger);
}
entity.remove();
}
this.seats.clear();
} }
@Override @Override
public void destroySeats() { public void destroySeats() {
for (WeakReference<Entity> entity : this.seats) { for (HitBox hitBox : this.hitBoxes.values()) {
Entity e = entity.get(); for (Seat<HitBox> seat : hitBox.seats()) {
if (e != null) { seat.destroy();
e.remove();
} }
} }
this.seats.clear();
}
@Override
public Optional<Seat> findFirstAvailableSeat(int targetEntityId) {
HitBox hitbox = hitBoxes.get(targetEntityId);
if (hitbox == null) return Optional.empty();
Seat[] seats = hitbox.seats();
if (ArrayUtils.isEmpty(seats)) return Optional.empty();
return Arrays.stream(seats)
.filter(s -> !occupiedSeats.contains(s.offset()))
.findFirst();
}
@Override
public boolean removeOccupiedSeat(Vector3f seat) {
return this.occupiedSeats.remove(seat);
}
@Override
public boolean tryOccupySeat(Seat seat) {
if (this.occupiedSeats.contains(seat.offset())) {
return false;
}
this.occupiedSeats.add(seat.offset());
return true;
} }
@Override @Override
@@ -263,14 +239,14 @@ public class BukkitFurniture implements Furniture {
return this.colliderEntities; return this.colliderEntities;
} }
@Nullable @Override
public HitBox hitBoxByEntityId(int id) { public @Nullable HitBox hitBoxByEntityId(int id) {
return this.hitBoxes.get(id); return this.hitBoxes.get(id);
} }
@Nullable @Override
public AABB aabbByEntityId(int id) { public @Nullable HitBoxPart hitBoxPartByEntityId(int id) {
return this.aabb.get(id); return this.hitBoxParts.get(id);
} }
@Override @Override
@@ -280,7 +256,7 @@ public class BukkitFurniture implements Furniture {
@Override @Override
public @NotNull Key id() { public @NotNull Key id() {
return this.id; return this.furniture.id();
} }
@Override @Override
@@ -293,11 +269,6 @@ public class BukkitFurniture implements Furniture {
return hasExternalModel; return hasExternalModel;
} }
@Override
public void spawnSeatEntityForPlayer(net.momirealms.craftengine.core.entity.player.Player player, Seat seat) {
spawnSeatEntityForPlayer((Player) player.platformPlayer(), seat);
}
@Override @Override
public FurnitureExtraData extraData() { public FurnitureExtraData extraData() {
return this.extraData; return this.extraData;
@@ -317,49 +288,4 @@ public class BukkitFurniture implements Furniture {
CraftEngine.instance().logger().warn("Failed to save furniture data.", e); CraftEngine.instance().logger().warn("Failed to save furniture data.", e);
} }
} }
private void spawnSeatEntityForPlayer(org.bukkit.entity.Player player, Seat seat) {
Location location = this.calculateSeatLocation(seat);
Entity seatEntity = seat.limitPlayerRotation() ?
EntityUtils.spawnEntity(player.getWorld(), VersionHelper.isOrAbove1_20_2() ? location.subtract(0,0.9875,0) : location.subtract(0,0.990625,0), EntityType.ARMOR_STAND, entity -> {
ArmorStand armorStand = (ArmorStand) entity;
if (VersionHelper.isOrAbove1_21_3()) {
Objects.requireNonNull(armorStand.getAttribute(Attribute.MAX_HEALTH)).setBaseValue(0.01);
} else {
LegacyAttributeUtils.setMaxHealth(armorStand);
}
armorStand.setSmall(true);
armorStand.setInvisible(true);
armorStand.setSilent(true);
armorStand.setInvulnerable(true);
armorStand.setArms(false);
armorStand.setCanTick(false);
armorStand.setAI(false);
armorStand.setGravity(false);
armorStand.setPersistent(false);
armorStand.getPersistentDataContainer().set(BukkitFurnitureManager.FURNITURE_SEAT_BASE_ENTITY_KEY, PersistentDataType.INTEGER, this.baseEntityId());
armorStand.getPersistentDataContainer().set(BukkitFurnitureManager.FURNITURE_SEAT_VECTOR_3F_KEY, PersistentDataType.STRING, seat.offset().x + ", " + seat.offset().y + ", " + seat.offset().z);
}) :
EntityUtils.spawnEntity(player.getWorld(), VersionHelper.isOrAbove1_20_2() ? location : location.subtract(0,0.25,0), EntityType.ITEM_DISPLAY, entity -> {
ItemDisplay itemDisplay = (ItemDisplay) entity;
itemDisplay.setPersistent(false);
itemDisplay.getPersistentDataContainer().set(BukkitFurnitureManager.FURNITURE_SEAT_BASE_ENTITY_KEY, PersistentDataType.INTEGER, this.baseEntityId());
itemDisplay.getPersistentDataContainer().set(BukkitFurnitureManager.FURNITURE_SEAT_VECTOR_3F_KEY, PersistentDataType.STRING, seat.offset().x + ", " + seat.offset().y + ", " + seat.offset().z);
});
this.seats.add(new WeakReference<>(seatEntity));
if (!seatEntity.addPassenger(player)) {
seatEntity.remove();
this.removeOccupiedSeat(seat.offset());
}
}
private Location calculateSeatLocation(Seat seat) {
Vector3f offset = QuaternionUtils.toQuaternionf(0, Math.toRadians(180 - this.location.getYaw()), 0).conjugate().transform(new Vector3f(seat.offset()));
double yaw = seat.yaw() + this.location.getYaw();
if (yaw < -180) yaw += 360;
Location newLocation = this.location.clone();
newLocation.setYaw((float) yaw);
newLocation.add(offset.x, offset.y + 0.6, -offset.z);
return newLocation;
}
} }

View File

@@ -1,7 +1,7 @@
package net.momirealms.craftengine.bukkit.entity.furniture; package net.momirealms.craftengine.bukkit.entity.furniture;
import net.momirealms.craftengine.bukkit.api.BukkitAdaptors; import net.momirealms.craftengine.bukkit.api.BukkitAdaptors;
import net.momirealms.craftengine.bukkit.entity.furniture.hitbox.InteractionHitBox; import net.momirealms.craftengine.bukkit.entity.furniture.hitbox.InteractionHitBoxConfig;
import net.momirealms.craftengine.bukkit.nms.CollisionEntity; import net.momirealms.craftengine.bukkit.nms.CollisionEntity;
import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.nms.FastNMS;
import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine;
@@ -15,17 +15,13 @@ import net.momirealms.craftengine.core.entity.furniture.*;
import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.plugin.config.Config;
import net.momirealms.craftengine.core.sound.SoundData; import net.momirealms.craftengine.core.sound.SoundData;
import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.core.util.ResourceConfigUtils;
import net.momirealms.craftengine.core.util.VersionHelper; import net.momirealms.craftengine.core.util.VersionHelper;
import net.momirealms.craftengine.core.world.WorldPosition; import net.momirealms.craftengine.core.world.WorldPosition;
import org.bukkit.*; import org.bukkit.*;
import org.bukkit.entity.*; import org.bukkit.entity.*;
import org.bukkit.event.HandlerList; import org.bukkit.event.HandlerList;
import org.bukkit.event.Listener;
import org.bukkit.persistence.PersistentDataType; import org.bukkit.persistence.PersistentDataType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.joml.Vector3f;
import java.io.IOException; import java.io.IOException;
import java.util.List; import java.util.List;
@@ -37,8 +33,6 @@ import java.util.function.BiConsumer;
public class BukkitFurnitureManager extends AbstractFurnitureManager { public class BukkitFurnitureManager extends AbstractFurnitureManager {
public static final NamespacedKey FURNITURE_KEY = KeyUtils.toNamespacedKey(FurnitureManager.FURNITURE_KEY); public static final NamespacedKey FURNITURE_KEY = KeyUtils.toNamespacedKey(FurnitureManager.FURNITURE_KEY);
public static final NamespacedKey FURNITURE_EXTRA_DATA_KEY = KeyUtils.toNamespacedKey(FurnitureManager.FURNITURE_EXTRA_DATA_KEY); public static final NamespacedKey FURNITURE_EXTRA_DATA_KEY = KeyUtils.toNamespacedKey(FurnitureManager.FURNITURE_EXTRA_DATA_KEY);
public static final NamespacedKey FURNITURE_SEAT_BASE_ENTITY_KEY = KeyUtils.toNamespacedKey(FurnitureManager.FURNITURE_SEAT_BASE_ENTITY_KEY);
public static final NamespacedKey FURNITURE_SEAT_VECTOR_3F_KEY = KeyUtils.toNamespacedKey(FurnitureManager.FURNITURE_SEAT_VECTOR_3F_KEY);
public static final NamespacedKey FURNITURE_COLLISION = KeyUtils.toNamespacedKey(FurnitureManager.FURNITURE_COLLISION); public static final NamespacedKey FURNITURE_COLLISION = KeyUtils.toNamespacedKey(FurnitureManager.FURNITURE_COLLISION);
public static Class<?> COLLISION_ENTITY_CLASS = Interaction.class; public static Class<?> COLLISION_ENTITY_CLASS = Interaction.class;
public static Object NMS_COLLISION_ENTITY_TYPE = MEntityTypes.INTERACTION; public static Object NMS_COLLISION_ENTITY_TYPE = MEntityTypes.INTERACTION;
@@ -48,7 +42,6 @@ public class BukkitFurnitureManager extends AbstractFurnitureManager {
private final Map<Integer, BukkitFurniture> furnitureByRealEntityId = new ConcurrentHashMap<>(256, 0.5f); private final Map<Integer, BukkitFurniture> furnitureByRealEntityId = new ConcurrentHashMap<>(256, 0.5f);
private final Map<Integer, BukkitFurniture> furnitureByEntityId = new ConcurrentHashMap<>(512, 0.5f); private final Map<Integer, BukkitFurniture> furnitureByEntityId = new ConcurrentHashMap<>(512, 0.5f);
// Event listeners // Event listeners
private final Listener dismountListener;
private final FurnitureEventListener furnitureEventListener; private final FurnitureEventListener furnitureEventListener;
public static BukkitFurnitureManager instance() { public static BukkitFurnitureManager instance() {
@@ -60,7 +53,6 @@ public class BukkitFurnitureManager extends AbstractFurnitureManager {
instance = this; instance = this;
this.plugin = plugin; this.plugin = plugin;
this.furnitureEventListener = new FurnitureEventListener(this); this.furnitureEventListener = new FurnitureEventListener(this);
this.dismountListener = VersionHelper.isOrAbove1_20_3() ? new DismountListener1_20_3(this) : new DismountListener1_20(this::handleDismount);
} }
@Override @Override
@@ -95,7 +87,6 @@ public class BukkitFurnitureManager extends AbstractFurnitureManager {
COLLISION_ENTITY_CLASS = Config.colliderType() == ColliderType.INTERACTION ? Interaction.class : Boat.class; COLLISION_ENTITY_CLASS = Config.colliderType() == ColliderType.INTERACTION ? Interaction.class : Boat.class;
NMS_COLLISION_ENTITY_TYPE = Config.colliderType() == ColliderType.INTERACTION ? MEntityTypes.INTERACTION : MEntityTypes.OAK_BOAT; NMS_COLLISION_ENTITY_TYPE = Config.colliderType() == ColliderType.INTERACTION ? MEntityTypes.INTERACTION : MEntityTypes.OAK_BOAT;
COLLISION_ENTITY_TYPE = Config.colliderType(); COLLISION_ENTITY_TYPE = Config.colliderType();
Bukkit.getPluginManager().registerEvents(this.dismountListener, this.plugin.javaPlugin());
Bukkit.getPluginManager().registerEvents(this.furnitureEventListener, this.plugin.javaPlugin()); Bukkit.getPluginManager().registerEvents(this.furnitureEventListener, this.plugin.javaPlugin());
if (VersionHelper.isFolia()) { if (VersionHelper.isFolia()) {
BiConsumer<Entity, Runnable> taskExecutor = (entity, runnable) -> entity.getScheduler().run(this.plugin.javaPlugin(), (t) -> runnable.run(), () -> {}); BiConsumer<Entity, Runnable> taskExecutor = (entity, runnable) -> entity.getScheduler().run(this.plugin.javaPlugin(), (t) -> runnable.run(), () -> {});
@@ -129,15 +120,8 @@ public class BukkitFurnitureManager extends AbstractFurnitureManager {
@Override @Override
public void disable() { public void disable() {
HandlerList.unregisterAll(this.dismountListener);
HandlerList.unregisterAll(this.furnitureEventListener); HandlerList.unregisterAll(this.furnitureEventListener);
unload(); unload();
for (Player player : Bukkit.getOnlinePlayers()) {
Entity vehicle = player.getVehicle();
if (vehicle != null) {
tryLeavingSeat(player, vehicle);
}
}
} }
@Override @Override
@@ -327,84 +311,7 @@ public class BukkitFurnitureManager extends AbstractFurnitureManager {
} }
@Override @Override
protected HitBox defaultHitBox() { protected HitBoxConfig defaultHitBox() {
return InteractionHitBox.DEFAULT; return InteractionHitBoxConfig.DEFAULT;
}
protected void handleDismount(Player player, Entity entity) {
if (!isSeatCarrierType(entity)) return;
Location location = entity.getLocation();
plugin.scheduler().sync().runDelayed(() -> tryLeavingSeat(player, entity), player.getWorld(), location.getBlockX() >> 4, location.getBlockZ() >> 4);
}
@SuppressWarnings("DuplicatedCode")
protected void tryLeavingSeat(@NotNull Player player, @NotNull Entity vehicle) {
Integer baseFurniture = vehicle.getPersistentDataContainer().get(FURNITURE_SEAT_BASE_ENTITY_KEY, PersistentDataType.INTEGER);
if (baseFurniture == null) return;
vehicle.remove();
BukkitFurniture furniture = loadedFurnitureByRealEntityId(baseFurniture);
if (furniture == null) {
return;
}
String vector3f = vehicle.getPersistentDataContainer().get(BukkitFurnitureManager.FURNITURE_SEAT_VECTOR_3F_KEY, PersistentDataType.STRING);
if (vector3f == null) {
plugin.logger().warn("Failed to get vector3f for player " + player.getName() + "'s seat");
return;
}
Vector3f seatPos = ResourceConfigUtils.getAsVector3f(vector3f, "seat");
furniture.removeOccupiedSeat(seatPos);
if (player.getVehicle() != null) return;
Location vehicleLocation = vehicle.getLocation();
Location originalLocation = vehicleLocation.clone();
originalLocation.setY(furniture.location().getY());
Location targetLocation = originalLocation.clone().add(vehicleLocation.getDirection().multiply(1.1));
if (!isSafeLocation(targetLocation)) {
targetLocation = findSafeLocationNearby(originalLocation);
if (targetLocation == null) return;
}
targetLocation.setYaw(player.getLocation().getYaw());
targetLocation.setPitch(player.getLocation().getPitch());
if (VersionHelper.isFolia()) {
player.teleportAsync(targetLocation);
} else {
player.teleport(targetLocation);
}
}
protected boolean isSeatCarrierType(Entity entity) {
return (entity instanceof ArmorStand || entity instanceof ItemDisplay);
}
@SuppressWarnings("DuplicatedCode")
private boolean isSafeLocation(Location location) {
World world = location.getWorld();
if (world == null) return false;
int x = location.getBlockX();
int y = location.getBlockY();
int z = location.getBlockZ();
if (!world.getBlockAt(x, y - 1, z).getType().isSolid()) return false;
if (!world.getBlockAt(x, y, z).isPassable()) return false;
return world.getBlockAt(x, y + 1, z).isPassable();
}
@SuppressWarnings("DuplicatedCode")
@Nullable
private Location findSafeLocationNearby(Location center) {
World world = center.getWorld();
if (world == null) return null;
int centerX = center.getBlockX();
int centerY = center.getBlockY();
int centerZ = center.getBlockZ();
for (int dx = -1; dx <= 1; dx++) {
for (int dz = -1; dz <= 1; dz++) {
if (dx == 0 && dz == 0) continue;
int x = centerX + dx;
int z = centerZ + dz;
Location nearbyLocation = new Location(world, x + 0.5, centerY, z + 0.5);
if (isSafeLocation(nearbyLocation)) return nearbyLocation;
}
}
return null;
} }
} }

View File

@@ -0,0 +1,70 @@
package net.momirealms.craftengine.bukkit.entity.furniture;
import net.momirealms.craftengine.bukkit.entity.seat.BukkitSeat;
import net.momirealms.craftengine.core.entity.furniture.Furniture;
import net.momirealms.craftengine.core.entity.furniture.HitBox;
import net.momirealms.craftengine.core.entity.furniture.HitBoxConfig;
import net.momirealms.craftengine.core.entity.furniture.HitBoxPart;
import net.momirealms.craftengine.core.entity.seat.Seat;
import net.momirealms.craftengine.core.entity.seat.SeatConfig;
import net.momirealms.craftengine.core.world.EntityHitResult;
import net.momirealms.craftengine.core.world.Vec3d;
import net.momirealms.sparrow.nbt.CompoundTag;
import java.util.Optional;
public class BukkitHitBox implements HitBox {
private final Furniture furniture;
private final HitBoxConfig config;
private final HitBoxPart[] parts;
private final Seat<HitBox>[] seats;
public BukkitHitBox(Furniture furniture, HitBoxConfig config, HitBoxPart[] parts) {
this.parts = parts;
this.config = config;
this.furniture = furniture;
this.seats = createSeats(config);
}
@SuppressWarnings("unchecked")
private Seat<HitBox>[] createSeats(HitBoxConfig config) {
SeatConfig[] seatConfigs = config.seats();
Seat<HitBox>[] seats = new Seat[seatConfigs.length];
for (int i = 0; i < seatConfigs.length; i++) {
seats[i] = new BukkitSeat<>(this, seatConfigs[i]);
}
return seats;
}
@Override
public HitBoxPart[] parts() {
return this.parts;
}
@Override
public HitBoxConfig config() {
return this.config;
}
@Override
public Seat<HitBox>[] seats() {
return this.seats;
}
@Override
public Optional<EntityHitResult> clip(Vec3d min, Vec3d max) {
for (HitBoxPart hbe : this.parts) {
Optional<EntityHitResult> result = hbe.aabb().clip(min, max);
if (result.isPresent()) {
return result;
}
}
return Optional.empty();
}
@Override
public void saveCustomData(CompoundTag data) {
data.putString("type", "furniture");
data.putInt("entity_id", this.furniture.baseEntityId());
}
}

View File

@@ -1,21 +1,24 @@
package net.momirealms.craftengine.bukkit.entity.furniture; package net.momirealms.craftengine.bukkit.entity.furniture;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener; import org.bukkit.event.Listener;
import org.bukkit.event.entity.EntityDismountEvent; import org.bukkit.event.entity.EntityDismountEvent;
public class DismountListener1_20_3 implements Listener { import java.util.function.BiConsumer;
private final BukkitFurnitureManager manager;
public DismountListener1_20_3(final BukkitFurnitureManager manager) { public class DismountListener1_20_3 implements Listener {
this.manager = manager; private final BiConsumer<Player, Entity> consumer;
public DismountListener1_20_3(final BiConsumer<Player, Entity> consumer) {
this.consumer = consumer;
} }
@EventHandler(ignoreCancelled = true) @EventHandler(ignoreCancelled = true)
public void onDismount(EntityDismountEvent event) { public void onDismount(EntityDismountEvent event) {
if (event.getEntity() instanceof Player player) { if (event.getEntity() instanceof Player player) {
this.manager.handleDismount(player, event.getDismounted()); this.consumer.accept(player, event.getDismounted());
} }
} }
} }

View File

@@ -2,21 +2,15 @@ package net.momirealms.craftengine.bukkit.entity.furniture;
import com.destroystokyo.paper.event.entity.EntityAddToWorldEvent; import com.destroystokyo.paper.event.entity.EntityAddToWorldEvent;
import com.destroystokyo.paper.event.entity.EntityRemoveFromWorldEvent; import com.destroystokyo.paper.event.entity.EntityRemoveFromWorldEvent;
import org.bukkit.entity.ArmorStand;
import org.bukkit.entity.Entity; import org.bukkit.entity.Entity;
import org.bukkit.entity.ItemDisplay; import org.bukkit.entity.ItemDisplay;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority; import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener; import org.bukkit.event.Listener;
import org.bukkit.event.entity.PlayerDeathEvent;
import org.bukkit.event.player.PlayerInteractAtEntityEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.event.world.ChunkUnloadEvent; import org.bukkit.event.world.ChunkUnloadEvent;
import org.bukkit.event.world.EntitiesLoadEvent; import org.bukkit.event.world.EntitiesLoadEvent;
import org.bukkit.event.world.WorldLoadEvent; import org.bukkit.event.world.WorldLoadEvent;
import org.bukkit.event.world.WorldUnloadEvent; import org.bukkit.event.world.WorldUnloadEvent;
import org.bukkit.persistence.PersistentDataType;
import java.util.List; import java.util.List;
@@ -100,35 +94,4 @@ public class FurnitureEventListener implements Listener {
this.manager.handleCollisionEntityUnload(entity); this.manager.handleCollisionEntityUnload(entity);
} }
} }
@EventHandler(ignoreCancelled = true)
public void onPlayerQuit(PlayerQuitEvent event) {
Player player = event.getPlayer();
Entity entity = player.getVehicle();
if (entity == null) return;
if (this.manager.isSeatCarrierType(entity)) {
this.manager.tryLeavingSeat(player, entity);
}
}
@EventHandler(ignoreCancelled = true)
public void onPlayerDeath(PlayerDeathEvent event) {
Player player = event.getPlayer();
Entity entity = player.getVehicle();
if (entity == null) return;
if (this.manager.isSeatCarrierType(entity)) {
this.manager.tryLeavingSeat(player, entity);
}
}
// do not allow players to put item on seats
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
public void onInteractArmorStand(PlayerInteractAtEntityEvent event) {
Entity clicked = event.getRightClicked();
if (clicked instanceof ArmorStand armorStand) {
Integer baseFurniture = armorStand.getPersistentDataContainer().get(BukkitFurnitureManager.FURNITURE_SEAT_BASE_ENTITY_KEY, PersistentDataType.INTEGER);
if (baseFurniture == null) return;
event.setCancelled(true);
}
}
} }

View File

@@ -7,9 +7,9 @@ public class BukkitHitBoxTypes extends HitBoxTypes {
public static void init() {} public static void init() {}
static { static {
register(INTERACTION, InteractionHitBox.FACTORY); register(INTERACTION, InteractionHitBoxConfig.FACTORY);
register(SHULKER, ShulkerHitBox.FACTORY); register(SHULKER, ShulkerHitBoxConfig.FACTORY);
register(HAPPY_GHAST, HappyGhastHitBox.FACTORY); register(HAPPY_GHAST, HappyGhastHitBoxConfig.FACTORY);
register(CUSTOM, CustomHitBox.FACTORY); register(CUSTOM, CustomHitBoxConfig.FACTORY);
} }
} }

View File

@@ -6,6 +6,7 @@ import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflect
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MAttributeHolders; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MAttributeHolders;
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.NetworkReflections; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.NetworkReflections;
import net.momirealms.craftengine.core.entity.furniture.*; import net.momirealms.craftengine.core.entity.furniture.*;
import net.momirealms.craftengine.core.entity.seat.SeatConfig;
import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException;
import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.core.util.ResourceConfigUtils; import net.momirealms.craftengine.core.util.ResourceConfigUtils;
@@ -23,13 +24,13 @@ import java.util.function.BiConsumer;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.function.Supplier; import java.util.function.Supplier;
public class CustomHitBox extends AbstractHitBox { public class CustomHitBoxConfig extends AbstractHitBoxConfig {
public static final Factory FACTORY = new Factory(); public static final Factory FACTORY = new Factory();
private final float scale; private final float scale;
private final EntityType entityType; private final EntityType entityType;
private final List<Object> cachedValues = new ArrayList<>(); private final List<Object> cachedValues = new ArrayList<>();
public CustomHitBox(Seat[] seats, Vector3f position, EntityType type, float scale, boolean blocksBuilding, boolean canBeHitByProjectile) { public CustomHitBoxConfig(SeatConfig[] seats, Vector3f position, EntityType type, float scale, boolean blocksBuilding, boolean canBeHitByProjectile) {
super(seats, position, false, blocksBuilding, canBeHitByProjectile); super(seats, position, false, blocksBuilding, canBeHitByProjectile);
this.scale = scale; this.scale = scale;
this.entityType = type; this.entityType = type;
@@ -39,11 +40,11 @@ public class CustomHitBox extends AbstractHitBox {
} }
public EntityType entityType() { public EntityType entityType() {
return entityType; return this.entityType;
} }
public float scale() { public float scale() {
return scale; return this.scale;
} }
@Override @Override
@@ -52,7 +53,7 @@ public class CustomHitBox extends AbstractHitBox {
} }
@Override @Override
public void initPacketsAndColliders(int[] entityId, WorldPosition position, Quaternionf conjugated, BiConsumer<Object, Boolean> packets, Consumer<Collider> collider, BiConsumer<Integer, AABB> aabb) { public void initPacketsAndColliders(int[] entityId, WorldPosition position, Quaternionf conjugated, BiConsumer<Object, Boolean> packets, Consumer<Collider> collider, Consumer<HitBoxPart> aabb) {
Vector3f offset = conjugated.transform(new Vector3f(position())); Vector3f offset = conjugated.transform(new Vector3f(position()));
try { try {
packets.accept(FastNMS.INSTANCE.constructor$ClientboundAddEntityPacket( packets.accept(FastNMS.INSTANCE.constructor$ClientboundAddEntityPacket(
@@ -79,10 +80,10 @@ public class CustomHitBox extends AbstractHitBox {
return new int[] {entityIdSupplier.get()}; return new int[] {entityIdSupplier.get()};
} }
public static class Factory implements HitBoxFactory { public static class Factory implements HitBoxConfigFactory {
@Override @Override
public HitBox create(Map<String, Object> arguments) { public HitBoxConfig create(Map<String, Object> arguments) {
Vector3f position = ResourceConfigUtils.getAsVector3f(arguments.getOrDefault("position", "0"), "position"); Vector3f position = ResourceConfigUtils.getAsVector3f(arguments.getOrDefault("position", "0"), "position");
float scale = ResourceConfigUtils.getAsFloat(arguments.getOrDefault("scale", 1), "scale"); float scale = ResourceConfigUtils.getAsFloat(arguments.getOrDefault("scale", 1), "scale");
String type = (String) arguments.getOrDefault("entity-type", "slime"); String type = (String) arguments.getOrDefault("entity-type", "slime");
@@ -92,7 +93,7 @@ public class CustomHitBox extends AbstractHitBox {
} }
boolean canBeHitByProjectile = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("can-be-hit-by-projectile", false), "can-be-hit-by-projectile"); boolean canBeHitByProjectile = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("can-be-hit-by-projectile", false), "can-be-hit-by-projectile");
boolean blocksBuilding = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("blocks-building", true), "blocks-building"); boolean blocksBuilding = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("blocks-building", true), "blocks-building");
return new CustomHitBox(HitBoxFactory.getSeats(arguments), position, entityType, scale, blocksBuilding, canBeHitByProjectile); return new CustomHitBoxConfig(SeatConfig.fromObj(arguments.get("seats")), position, entityType, scale, blocksBuilding, canBeHitByProjectile);
} }
} }
} }

View File

@@ -8,9 +8,11 @@ import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MAttributeH
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MEntityTypes; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MEntityTypes;
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.NetworkReflections; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.NetworkReflections;
import net.momirealms.craftengine.core.entity.furniture.*; import net.momirealms.craftengine.core.entity.furniture.*;
import net.momirealms.craftengine.core.entity.seat.SeatConfig;
import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.core.util.ResourceConfigUtils; import net.momirealms.craftengine.core.util.ResourceConfigUtils;
import net.momirealms.craftengine.core.util.VersionHelper; import net.momirealms.craftengine.core.util.VersionHelper;
import net.momirealms.craftengine.core.world.Vec3d;
import net.momirealms.craftengine.core.world.World; import net.momirealms.craftengine.core.world.World;
import net.momirealms.craftengine.core.world.WorldPosition; import net.momirealms.craftengine.core.world.WorldPosition;
import net.momirealms.craftengine.core.world.collision.AABB; import net.momirealms.craftengine.core.world.collision.AABB;
@@ -22,13 +24,13 @@ import java.util.function.BiConsumer;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.function.Supplier; import java.util.function.Supplier;
public class HappyGhastHitBox extends AbstractHitBox { public class HappyGhastHitBoxConfig extends AbstractHitBoxConfig {
public static final Factory FACTORY = new Factory(); public static final Factory FACTORY = new Factory();
private final double scale; private final double scale;
private final boolean hardCollision; private final boolean hardCollision;
private final List<Object> cachedValues = new ArrayList<>(); private final List<Object> cachedValues = new ArrayList<>();
public HappyGhastHitBox(Seat[] seats, Vector3f position, double scale, boolean canUseOn, boolean blocksBuilding, boolean canBeHitByProjectile, boolean hardCollision) { public HappyGhastHitBoxConfig(SeatConfig[] seats, Vector3f position, double scale, boolean canUseOn, boolean blocksBuilding, boolean canBeHitByProjectile, boolean hardCollision) {
super(seats, position, canUseOn, blocksBuilding, canBeHitByProjectile); super(seats, position, canUseOn, blocksBuilding, canBeHitByProjectile);
this.scale = scale; this.scale = scale;
this.hardCollision = hardCollision; this.hardCollision = hardCollision;
@@ -43,15 +45,20 @@ public class HappyGhastHitBox extends AbstractHitBox {
} }
public double scale() { public double scale() {
return scale; return this.scale;
} }
public boolean hardCollision() { public boolean hardCollision() {
return hardCollision; return this.hardCollision;
} }
@Override @Override
public void initPacketsAndColliders(int[] entityIds, WorldPosition position, Quaternionf conjugated, BiConsumer<Object, Boolean> packets, Consumer<Collider> collider, BiConsumer<Integer, AABB> aabb) { public void initPacketsAndColliders(int[] entityIds,
WorldPosition position,
Quaternionf conjugated,
BiConsumer<Object, Boolean> packets,
Consumer<Collider> collider,
Consumer<HitBoxPart> aabb) {
Vector3f offset = conjugated.transform(new Vector3f(position())); Vector3f offset = conjugated.transform(new Vector3f(position()));
try { try {
double x = position.x(); double x = position.x();
@@ -76,11 +83,11 @@ public class HappyGhastHitBox extends AbstractHitBox {
} }
} }
public Collider createCollider(World world, Vector3f offset, double x, double y, double z, int entityId, BiConsumer<Integer, AABB> aabb) { public Collider createCollider(World world, Vector3f offset, double x, double y, double z, int entityId, Consumer<HitBoxPart> aabb) {
AABB ceAABB = createAABB(offset, x, y, z); AABB ceAABB = createAABB(offset, x, y, z);
Object level = world.serverWorld(); Object level = world.serverWorld();
Object nmsAABB = FastNMS.INSTANCE.constructor$AABB(ceAABB.minX, ceAABB.minY, ceAABB.minZ, ceAABB.maxX, ceAABB.maxY, ceAABB.maxZ); Object nmsAABB = FastNMS.INSTANCE.constructor$AABB(ceAABB.minX, ceAABB.minY, ceAABB.minZ, ceAABB.maxX, ceAABB.maxY, ceAABB.maxZ);
aabb.accept(entityId, ceAABB); aabb.accept(new HitBoxPart(entityId, ceAABB, new Vec3d(x, y, z)));
return new BukkitCollider(level, nmsAABB, x, y, z, this.canBeHitByProjectile(), true, this.blocksBuilding()); return new BukkitCollider(level, nmsAABB, x, y, z, this.canBeHitByProjectile(), true, this.blocksBuilding());
} }
@@ -109,10 +116,10 @@ public class HappyGhastHitBox extends AbstractHitBox {
return new int[] {entityIdSupplier.get()}; return new int[] {entityIdSupplier.get()};
} }
public static class Factory implements HitBoxFactory { public static class Factory implements HitBoxConfigFactory {
@Override @Override
public HitBox create(Map<String, Object> arguments) { public HitBoxConfig create(Map<String, Object> arguments) {
if (!VersionHelper.isOrAbove1_21_6()) { if (!VersionHelper.isOrAbove1_21_6()) {
throw new UnsupportedOperationException("HappyGhastHitBox is only supported on 1.21.6+"); throw new UnsupportedOperationException("HappyGhastHitBox is only supported on 1.21.6+");
} }
@@ -121,8 +128,8 @@ public class HappyGhastHitBox extends AbstractHitBox {
boolean canUseOn = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("can-use-item-on", true), "can-use-item-on"); boolean canUseOn = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("can-use-item-on", true), "can-use-item-on");
boolean canBeHitByProjectile = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("can-be-hit-by-projectile", true), "can-be-hit-by-projectile"); boolean canBeHitByProjectile = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("can-be-hit-by-projectile", true), "can-be-hit-by-projectile");
boolean blocksBuilding = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("blocks-building", true), "blocks-building"); boolean blocksBuilding = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("blocks-building", true), "blocks-building");
return new HappyGhastHitBox( return new HappyGhastHitBoxConfig(
HitBoxFactory.getSeats(arguments), SeatConfig.fromObj(arguments.get("seats")),
ResourceConfigUtils.getAsVector3f(arguments.getOrDefault("position", "0"), "position"), ResourceConfigUtils.getAsVector3f(arguments.getOrDefault("position", "0"), "position"),
scale, canUseOn, blocksBuilding, canBeHitByProjectile, hardCollision scale, canUseOn, blocksBuilding, canBeHitByProjectile, hardCollision
); );

View File

@@ -6,6 +6,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.CoreReflections;
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MEntityTypes; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MEntityTypes;
import net.momirealms.craftengine.core.entity.furniture.*; import net.momirealms.craftengine.core.entity.furniture.*;
import net.momirealms.craftengine.core.entity.seat.SeatConfig;
import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.core.util.ResourceConfigUtils; import net.momirealms.craftengine.core.util.ResourceConfigUtils;
import net.momirealms.craftengine.core.world.Vec3d; import net.momirealms.craftengine.core.world.Vec3d;
@@ -22,15 +23,15 @@ import java.util.function.BiConsumer;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.function.Supplier; import java.util.function.Supplier;
public class InteractionHitBox extends AbstractHitBox { public class InteractionHitBoxConfig extends AbstractHitBoxConfig {
public static final Factory FACTORY = new Factory(); public static final Factory FACTORY = new Factory();
public static final InteractionHitBox DEFAULT = new InteractionHitBox(new Seat[0], new Vector3f(), new Vector3f(1,1,1), true, false, false, false); public static final InteractionHitBoxConfig DEFAULT = new InteractionHitBoxConfig(new SeatConfig[0], new Vector3f(), new Vector3f(1,1,1), true, false, false, false);
private final Vector3f size; private final Vector3f size;
private final boolean responsive; private final boolean responsive;
private final List<Object> cachedValues = new ArrayList<>(); private final List<Object> cachedValues = new ArrayList<>();
public InteractionHitBox(Seat[] seats, Vector3f position, Vector3f size, boolean responsive, boolean canUseOn, boolean blocksBuilding, boolean canBeHitByProjectile) { public InteractionHitBoxConfig(SeatConfig[] seats, Vector3f position, Vector3f size, boolean responsive, boolean canUseOn, boolean blocksBuilding, boolean canBeHitByProjectile) {
super(seats, position, canUseOn, blocksBuilding, canBeHitByProjectile); super(seats, position, canUseOn, blocksBuilding, canBeHitByProjectile);
this.size = size; this.size = size;
this.responsive = responsive; this.responsive = responsive;
@@ -40,11 +41,11 @@ public class InteractionHitBox extends AbstractHitBox {
} }
public boolean responsive() { public boolean responsive() {
return responsive; return this.responsive;
} }
public Vector3f size() { public Vector3f size() {
return size; return this.size;
} }
@Override @Override
@@ -53,22 +54,26 @@ public class InteractionHitBox extends AbstractHitBox {
} }
@Override @Override
public void initPacketsAndColliders(int[] entityId, WorldPosition position, Quaternionf conjugated, BiConsumer<Object, Boolean> packets, Consumer<Collider> collider, BiConsumer<Integer, AABB> aabb) { public void initPacketsAndColliders(int[] entityId,
WorldPosition position,
Quaternionf conjugated,
BiConsumer<Object, Boolean> packets,
Consumer<Collider> collider,
Consumer<HitBoxPart> aabb) {
Vector3f offset = conjugated.transform(new Vector3f(position())); Vector3f offset = conjugated.transform(new Vector3f(position()));
double x = position.x(); double x = position.x();
double y = position.y(); double y = position.y();
double z = position.z(); double z = position.z();
float yaw = position.xRot(); float yaw = position.xRot();
Vec3d vec3d = new Vec3d(x + offset.x, y + offset.y, z - offset.z);
packets.accept(FastNMS.INSTANCE.constructor$ClientboundAddEntityPacket( packets.accept(FastNMS.INSTANCE.constructor$ClientboundAddEntityPacket(
entityId[0], UUID.randomUUID(), x + offset.x, y + offset.y, z - offset.z, 0, yaw, entityId[0], UUID.randomUUID(), vec3d.x, vec3d.y, vec3d.z, 0, yaw,
MEntityTypes.INTERACTION, 0, CoreReflections.instance$Vec3$Zero, 0 MEntityTypes.INTERACTION, 0, CoreReflections.instance$Vec3$Zero, 0
), true); ), true);
packets.accept(FastNMS.INSTANCE.constructor$ClientboundSetEntityDataPacket(entityId[0], List.copyOf(this.cachedValues)), true); packets.accept(FastNMS.INSTANCE.constructor$ClientboundSetEntityDataPacket(entityId[0], List.copyOf(this.cachedValues)), true);
if (canUseItemOn()) { aabb.accept(new HitBoxPart(entityId[0], AABB.fromInteraction(vec3d, this.size.x, this.size.y), vec3d));
aabb.accept(entityId[0], AABB.fromInteraction(new Vec3d(x + offset.x, y + offset.y, z - offset.z), this.size.x, this.size.y));
}
if (blocksBuilding() || this.canBeHitByProjectile()) { if (blocksBuilding() || this.canBeHitByProjectile()) {
AABB ceAABB = AABB.fromInteraction(new Vec3d(x + offset.x, y + offset.y, z - offset.z), this.size.x, this.size.y); AABB ceAABB = AABB.fromInteraction(vec3d, this.size.x, this.size.y);
Object nmsAABB = FastNMS.INSTANCE.constructor$AABB(ceAABB.minX, ceAABB.minY, ceAABB.minZ, ceAABB.maxX, ceAABB.maxY, ceAABB.maxZ); Object nmsAABB = FastNMS.INSTANCE.constructor$AABB(ceAABB.minX, ceAABB.minY, ceAABB.minZ, ceAABB.maxX, ceAABB.maxY, ceAABB.maxZ);
collider.accept(new BukkitCollider(position.world().serverWorld(), nmsAABB, x, y, z, this.canBeHitByProjectile(), false, this.blocksBuilding())); collider.accept(new BukkitCollider(position.world().serverWorld(), nmsAABB, x, y, z, this.canBeHitByProjectile(), false, this.blocksBuilding()));
} }
@@ -88,10 +93,10 @@ public class InteractionHitBox extends AbstractHitBox {
return new int[] {entityIdSupplier.get()}; return new int[] {entityIdSupplier.get()};
} }
public static class Factory implements HitBoxFactory { public static class Factory implements HitBoxConfigFactory {
@Override @Override
public HitBox create(Map<String, Object> arguments) { public HitBoxConfig create(Map<String, Object> arguments) {
Vector3f position = ResourceConfigUtils.getAsVector3f(arguments.getOrDefault("position", "0"), "position"); Vector3f position = ResourceConfigUtils.getAsVector3f(arguments.getOrDefault("position", "0"), "position");
float width; float width;
float height; float height;
@@ -100,15 +105,15 @@ public class InteractionHitBox extends AbstractHitBox {
width = Float.parseFloat(split[0]); width = Float.parseFloat(split[0]);
height = Float.parseFloat(split[1]); height = Float.parseFloat(split[1]);
} else { } else {
width = ResourceConfigUtils.getAsFloat(arguments.getOrDefault("width", "1"), "width"); width = ResourceConfigUtils.getAsFloat(arguments.getOrDefault("width", 1), "width");
height = ResourceConfigUtils.getAsFloat(arguments.getOrDefault("height", "1"), "height"); height = ResourceConfigUtils.getAsFloat(arguments.getOrDefault("height", 1), "height");
} }
boolean canUseOn = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("can-use-item-on", false), "can-use-item-on"); boolean canUseOn = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("can-use-item-on", false), "can-use-item-on");
boolean interactive = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("interactive", true), "interactive"); boolean interactive = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("interactive", true), "interactive");
boolean canBeHitByProjectile = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("can-be-hit-by-projectile", false), "can-be-hit-by-projectile"); boolean canBeHitByProjectile = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("can-be-hit-by-projectile", false), "can-be-hit-by-projectile");
boolean blocksBuilding = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("blocks-building", true), "blocks-building"); boolean blocksBuilding = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("blocks-building", true), "blocks-building");
return new InteractionHitBox( return new InteractionHitBoxConfig(
HitBoxFactory.getSeats(arguments), SeatConfig.fromObj(arguments.get("seats")),
position, position,
new Vector3f(width, height, width), new Vector3f(width, height, width),
interactive, canUseOn, blocksBuilding, canBeHitByProjectile interactive, canUseOn, blocksBuilding, canBeHitByProjectile

View File

@@ -10,6 +10,7 @@ import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MEntityType
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.NetworkReflections; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.NetworkReflections;
import net.momirealms.craftengine.bukkit.util.DirectionUtils; import net.momirealms.craftengine.bukkit.util.DirectionUtils;
import net.momirealms.craftengine.core.entity.furniture.*; import net.momirealms.craftengine.core.entity.furniture.*;
import net.momirealms.craftengine.core.entity.seat.SeatConfig;
import net.momirealms.craftengine.core.util.*; import net.momirealms.craftengine.core.util.*;
import net.momirealms.craftengine.core.world.Vec3d; import net.momirealms.craftengine.core.world.Vec3d;
import net.momirealms.craftengine.core.world.World; import net.momirealms.craftengine.core.world.World;
@@ -23,7 +24,7 @@ import java.util.function.BiConsumer;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.function.Supplier; import java.util.function.Supplier;
public class ShulkerHitBox extends AbstractHitBox { public class ShulkerHitBoxConfig extends AbstractHitBoxConfig {
public static final Factory FACTORY = new Factory(); public static final Factory FACTORY = new Factory();
// 1.20.6+ // 1.20.6+
private final float scale; private final float scale;
@@ -35,7 +36,7 @@ public class ShulkerHitBox extends AbstractHitBox {
private final DirectionalShulkerSpawner spawner; private final DirectionalShulkerSpawner spawner;
private final AABBCreator aabbCreator; private final AABBCreator aabbCreator;
public ShulkerHitBox(Seat[] seats, Vector3f position, Direction direction, float scale, byte peek, boolean interactionEntity, boolean interactive, boolean canUseOn, boolean blocksBuilding, boolean canBeHitByProjectile) { public ShulkerHitBoxConfig(SeatConfig[] seats, Vector3f position, Direction direction, float scale, byte peek, boolean interactionEntity, boolean interactive, boolean canUseOn, boolean blocksBuilding, boolean canBeHitByProjectile) {
super(seats, position, canUseOn, blocksBuilding, canBeHitByProjectile); super(seats, position, canUseOn, blocksBuilding, canBeHitByProjectile);
this.direction = direction; this.direction = direction;
this.scale = scale; this.scale = scale;
@@ -65,7 +66,8 @@ public class ShulkerHitBox extends AbstractHitBox {
), true); ), true);
packets.accept(FastNMS.INSTANCE.constructor$ClientboundSetEntityDataPacket(entityIds[2], List.copyOf(cachedInteractionValues)), true); packets.accept(FastNMS.INSTANCE.constructor$ClientboundSetEntityDataPacket(entityIds[2], List.copyOf(cachedInteractionValues)), true);
if (canUseOn) { if (canUseOn) {
aabb.accept(entityIds[2], AABB.fromInteraction(new Vec3d(x + offset.x, y + offset.y, z - offset.z), scale, shulkerHeight)); Vec3d vec3d = new Vec3d(x + offset.x, y + offset.y, z - offset.z);
aabb.accept(new HitBoxPart(entityIds[2], AABB.fromInteraction(vec3d, scale, shulkerHeight), vec3d));
} }
} }
}; };
@@ -84,7 +86,8 @@ public class ShulkerHitBox extends AbstractHitBox {
), true); ), true);
packets.accept(FastNMS.INSTANCE.constructor$ClientboundSetEntityDataPacket(entityIds[2], List.copyOf(cachedInteractionValues)), true); packets.accept(FastNMS.INSTANCE.constructor$ClientboundSetEntityDataPacket(entityIds[2], List.copyOf(cachedInteractionValues)), true);
if (canUseOn) { if (canUseOn) {
aabb.accept(entityIds[2], AABB.fromInteraction(new Vec3d(x + offset.x, y + offset.y - shulkerHeight + scale, z - offset.z), scale, shulkerHeight)); Vec3d vec3d = new Vec3d(x + offset.x, y + offset.y - shulkerHeight + scale, z - offset.z);
aabb.accept(new HitBoxPart(entityIds[2], AABB.fromInteraction(vec3d, scale, shulkerHeight), vec3d));
} }
} }
}; };
@@ -113,8 +116,10 @@ public class ShulkerHitBox extends AbstractHitBox {
), true); ), true);
packets.accept(FastNMS.INSTANCE.constructor$ClientboundSetEntityDataPacket(entityIds[3], List.copyOf(cachedInteractionValues)), true); packets.accept(FastNMS.INSTANCE.constructor$ClientboundSetEntityDataPacket(entityIds[3], List.copyOf(cachedInteractionValues)), true);
if (canUseOn) { if (canUseOn) {
aabb.accept(entityIds[2], AABB.fromInteraction(new Vec3d(x + offset.x, y + offset.y, z - offset.z), scale, scale)); Vec3d vec3d1 = new Vec3d(x + offset.x, y + offset.y, z - offset.z);
aabb.accept(entityIds[3], AABB.fromInteraction(new Vec3d(x + offset.x + shulkerDirection.stepX() * distance, y + offset.y, z - offset.z + shulkerDirection.stepZ() * distance), scale, scale)); Vec3d vec3d2 = new Vec3d(x + offset.x + shulkerDirection.stepX() * distance, y + offset.y, z - offset.z + shulkerDirection.stepZ() * distance);
aabb.accept(new HitBoxPart(entityIds[2], AABB.fromInteraction(vec3d1, scale, scale), vec3d1));
aabb.accept(new HitBoxPart(entityIds[3], AABB.fromInteraction(vec3d2, scale, scale), vec3d2));
} }
} }
}; };
@@ -126,11 +131,11 @@ public class ShulkerHitBox extends AbstractHitBox {
} }
} }
public Collider createCollider(Direction direction, World world, Vector3f offset, double x, double y, double z, int entityId, BiConsumer<Integer, AABB> aabb) { public Collider createCollider(Direction direction, World world, Vector3f offset, double x, double y, double z, int entityId, Consumer<HitBoxPart> aabb) {
AABB ceAABB = createAABB(direction, offset, x, y, z); AABB ceAABB = createAABB(direction, offset, x, y, z);
Object level = world.serverWorld(); Object level = world.serverWorld();
Object nmsAABB = FastNMS.INSTANCE.constructor$AABB(ceAABB.minX, ceAABB.minY, ceAABB.minZ, ceAABB.maxX, ceAABB.maxY, ceAABB.maxZ); Object nmsAABB = FastNMS.INSTANCE.constructor$AABB(ceAABB.minX, ceAABB.minY, ceAABB.minZ, ceAABB.maxX, ceAABB.maxY, ceAABB.maxZ);
aabb.accept(entityId, ceAABB); aabb.accept(new HitBoxPart(entityId, ceAABB, new Vec3d(x, y, z)));
return new BukkitCollider(level, nmsAABB, x, y, z, this.canBeHitByProjectile(), true, this.blocksBuilding()); return new BukkitCollider(level, nmsAABB, x, y, z, this.canBeHitByProjectile(), true, this.blocksBuilding());
} }
@@ -200,7 +205,12 @@ public class ShulkerHitBox extends AbstractHitBox {
} }
@Override @Override
public void initPacketsAndColliders(int[] entityIds, WorldPosition position, Quaternionf conjugated, BiConsumer<Object, Boolean> packets, Consumer<Collider> collider, BiConsumer<Integer, AABB> aabb) { public void initPacketsAndColliders(int[] entityIds,
WorldPosition position,
Quaternionf conjugated,
BiConsumer<Object, Boolean> packets,
Consumer<Collider> collider,
Consumer<HitBoxPart> aabb) {
Vector3f offset = conjugated.transform(new Vector3f(position())); Vector3f offset = conjugated.transform(new Vector3f(position()));
try { try {
double x = position.x(); double x = position.x();
@@ -251,7 +261,16 @@ public class ShulkerHitBox extends AbstractHitBox {
@FunctionalInterface @FunctionalInterface
interface DirectionalShulkerSpawner { interface DirectionalShulkerSpawner {
void accept(int[] entityIds, World world, double x, double y, double z, float yaw, Vector3f offset, BiConsumer<Object, Boolean> packets, Consumer<Collider> collider, BiConsumer<Integer, AABB> aabb); void accept(int[] entityIds,
World world,
double x,
double y,
double z,
float yaw,
Vector3f offset,
BiConsumer<Object, Boolean> packets,
Consumer<Collider> collider,
Consumer<HitBoxPart> aabb);
} }
@FunctionalInterface @FunctionalInterface
@@ -276,10 +295,10 @@ public class ShulkerHitBox extends AbstractHitBox {
} }
} }
public static class Factory implements HitBoxFactory { public static class Factory implements HitBoxConfigFactory {
@Override @Override
public HitBox create(Map<String, Object> arguments) { public HitBoxConfig create(Map<String, Object> arguments) {
Vector3f position = ResourceConfigUtils.getAsVector3f(arguments.getOrDefault("position", "0"), "position"); Vector3f position = ResourceConfigUtils.getAsVector3f(arguments.getOrDefault("position", "0"), "position");
float scale = ResourceConfigUtils.getAsFloat(arguments.getOrDefault("scale", "1"), "scale"); float scale = ResourceConfigUtils.getAsFloat(arguments.getOrDefault("scale", "1"), "scale");
byte peek = (byte) ResourceConfigUtils.getAsInt(arguments.getOrDefault("peek", 0), "peek"); byte peek = (byte) ResourceConfigUtils.getAsInt(arguments.getOrDefault("peek", 0), "peek");
@@ -289,8 +308,8 @@ public class ShulkerHitBox extends AbstractHitBox {
boolean canUseItemOn = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("can-use-item-on", true), "can-use-item-on"); boolean canUseItemOn = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("can-use-item-on", true), "can-use-item-on");
boolean canBeHitByProjectile = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("can-be-hit-by-projectile", true), "can-be-hit-by-projectile"); boolean canBeHitByProjectile = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("can-be-hit-by-projectile", true), "can-be-hit-by-projectile");
boolean blocksBuilding = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("blocks-building", true), "blocks-building"); boolean blocksBuilding = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("blocks-building", true), "blocks-building");
return new ShulkerHitBox( return new ShulkerHitBoxConfig(
HitBoxFactory.getSeats(arguments), SeatConfig.fromObj(arguments.get("seats")),
position, directionEnum, position, directionEnum,
scale, peek, interactionEntity, interactive, canUseItemOn, blocksBuilding, canBeHitByProjectile scale, peek, interactionEntity, interactive, canUseItemOn, blocksBuilding, canBeHitByProjectile
); );

View File

@@ -0,0 +1,146 @@
package net.momirealms.craftengine.bukkit.entity.seat;
import net.momirealms.craftengine.bukkit.util.EntityUtils;
import net.momirealms.craftengine.bukkit.util.LegacyAttributeUtils;
import net.momirealms.craftengine.bukkit.util.LocationUtils;
import net.momirealms.craftengine.core.entity.seat.Seat;
import net.momirealms.craftengine.core.entity.seat.SeatConfig;
import net.momirealms.craftengine.core.entity.seat.SeatOwner;
import net.momirealms.craftengine.core.util.QuaternionUtils;
import net.momirealms.craftengine.core.util.VersionHelper;
import net.momirealms.craftengine.core.world.WorldPosition;
import net.momirealms.sparrow.nbt.CompoundTag;
import net.momirealms.sparrow.nbt.NBT;
import org.bukkit.Location;
import org.bukkit.attribute.Attribute;
import org.bukkit.entity.*;
import org.bukkit.persistence.PersistentDataType;
import org.jetbrains.annotations.Nullable;
import org.joml.Vector3f;
import java.io.IOException;
import java.lang.ref.WeakReference;
import java.util.Objects;
public class BukkitSeat<O extends SeatOwner> implements Seat<O> {
private final O owner;
private final SeatConfig seatConfig;
private WeakReference<Entity> entity;
public BukkitSeat(O owner, SeatConfig config) {
this.owner = owner;
this.seatConfig = config;
}
@Override
public O owner() {
return this.owner;
}
@Override
public SeatConfig config() {
return this.seatConfig;
}
@Nullable
public Entity getSeatEntity() {
return this.entity == null ? null : this.entity.get();
}
@Override
public boolean isOccupied() {
Entity seatEntity = getSeatEntity();
return seatEntity != null && seatEntity.isValid();
}
@Override
public void destroy() {
if (this.entity != null) {
Entity entity = this.entity.get();
if (entity != null) {
if (entity.isValid()) {
entity.remove();
}
this.entity = null;
}
}
}
private float yRot() {
return this.seatConfig.yRot();
}
private Vector3f position() {
return this.seatConfig.position();
}
private boolean limitPlayerRotation() {
return this.seatConfig.limitPlayerRotation();
}
private Location calculateSeatLocation(Location sourceLocation) {
Vector3f offset = QuaternionUtils.toQuaternionf(0, Math.toRadians(180 - sourceLocation.getYaw()), 0).conjugate().transform(new Vector3f(this.position()));
double yaw = this.yRot() + sourceLocation.getYaw();
if (yaw < -180) yaw += 360;
Location newLocation = sourceLocation.clone();
newLocation.setYaw((float) yaw);
newLocation.add(offset.x, offset.y + 0.6, -offset.z);
return newLocation;
}
@Override
public boolean spawnSeat(net.momirealms.craftengine.core.entity.player.Player player, WorldPosition source) {
return spawnSeatEntityForPlayer((Player) player.platformPlayer(), LocationUtils.toLocation(source));
}
private boolean spawnSeatEntityForPlayer(Player player, Location sourceLocation) {
// 移除就有的座椅
this.destroy();
// 计算座椅的位置
Location location = this.calculateSeatLocation(sourceLocation);
CompoundTag extraData = new CompoundTag();
this.owner.saveCustomData(extraData);
byte[] data;
try {
data = NBT.toBytes(extraData);
} catch (IOException e) {
return false;
}
// 生成座椅实体
Entity seatEntity = this.limitPlayerRotation() ?
EntityUtils.spawnEntity(player.getWorld(), VersionHelper.isOrAbove1_20_2() ? location.subtract(0,0.9875,0) : location.subtract(0,0.990625,0), EntityType.ARMOR_STAND, entity -> {
ArmorStand armorStand = (ArmorStand) entity;
if (VersionHelper.isOrAbove1_21_3()) {
Objects.requireNonNull(armorStand.getAttribute(Attribute.MAX_HEALTH)).setBaseValue(0.01);
} else {
LegacyAttributeUtils.setMaxHealth(armorStand);
}
armorStand.setSmall(true);
armorStand.setInvisible(true);
armorStand.setSilent(true);
armorStand.setInvulnerable(true);
armorStand.setArms(false);
armorStand.setCanTick(false);
armorStand.setAI(false);
armorStand.setGravity(false);
armorStand.setPersistent(false);
armorStand.getPersistentDataContainer().set(BukkitSeatManager.SEAT_KEY, PersistentDataType.BOOLEAN, true);
armorStand.getPersistentDataContainer().set(BukkitSeatManager.SEAT_EXTRA_DATA_KEY, PersistentDataType.BYTE_ARRAY, data);
}) :
EntityUtils.spawnEntity(player.getWorld(), VersionHelper.isOrAbove1_20_2() ? location : location.subtract(0,0.25,0), EntityType.ITEM_DISPLAY, entity -> {
ItemDisplay itemDisplay = (ItemDisplay) entity;
itemDisplay.setPersistent(false);
itemDisplay.getPersistentDataContainer().set(BukkitSeatManager.SEAT_KEY, PersistentDataType.BOOLEAN, true);
itemDisplay.getPersistentDataContainer().set(BukkitSeatManager.SEAT_EXTRA_DATA_KEY, PersistentDataType.BYTE_ARRAY, data);
});
if (!seatEntity.addPassenger(player)) {
seatEntity.remove();
return false;
} else {
this.entity = new WeakReference<>(seatEntity);
return true;
}
}
}

View File

@@ -0,0 +1,120 @@
package net.momirealms.craftengine.bukkit.entity.seat;
import net.momirealms.craftengine.bukkit.entity.furniture.DismountListener1_20;
import net.momirealms.craftengine.bukkit.entity.furniture.DismountListener1_20_3;
import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine;
import net.momirealms.craftengine.bukkit.util.KeyUtils;
import net.momirealms.craftengine.core.entity.seat.SeatManager;
import net.momirealms.craftengine.core.util.VersionHelper;
import net.momirealms.sparrow.nbt.CompoundTag;
import net.momirealms.sparrow.nbt.NBT;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.NamespacedKey;
import org.bukkit.entity.ArmorStand;
import org.bukkit.entity.Entity;
import org.bukkit.entity.ItemDisplay;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.HandlerList;
import org.bukkit.event.Listener;
import org.bukkit.event.entity.PlayerDeathEvent;
import org.bukkit.event.player.PlayerInteractAtEntityEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.persistence.PersistentDataType;
import org.jetbrains.annotations.NotNull;
import java.io.IOException;
public class BukkitSeatManager implements SeatManager {
private static BukkitSeatManager instance;
public static final NamespacedKey SEAT_KEY = KeyUtils.toNamespacedKey(SeatManager.SEAT_KEY);
public static final NamespacedKey SEAT_EXTRA_DATA_KEY = KeyUtils.toNamespacedKey(SeatManager.SEAT_EXTRA_DATA_KEY);
private final BukkitCraftEngine plugin;
private final Listener dismountListener;
public BukkitSeatManager(BukkitCraftEngine plugin) {
this.plugin = plugin;
this.dismountListener = VersionHelper.isOrAbove1_20_3() ? new DismountListener1_20_3(this::handleDismount) : new DismountListener1_20(this::handleDismount);
instance = this;
}
public CompoundTag getSeatExtraData(Entity entity) {
if (!isSeatEntityType(entity)) {
throw new IllegalArgumentException("Entity is not a seat");
}
byte[] bytes = entity.getPersistentDataContainer().get(SEAT_EXTRA_DATA_KEY, PersistentDataType.BYTE_ARRAY);
try {
return NBT.fromBytes(bytes);
} catch (IOException e) {
throw new RuntimeException("Failed to read extra data from seat", e);
}
}
private void handleDismount(Player player, @NotNull Entity dismounted) {
if (!isSeatEntityType(dismounted)) return;
Location location = dismounted.getLocation();
this.plugin.scheduler().sync().runDelayed(() -> tryLeavingSeat(player, dismounted), player.getWorld(), location.getBlockX() >> 4, location.getBlockZ() >> 4);
}
@Override
public void delayedInit() {
Bukkit.getPluginManager().registerEvents(this.dismountListener, this.plugin.javaPlugin());
}
@Override
public void disable() {
HandlerList.unregisterAll(this.dismountListener);
for (Player player : Bukkit.getOnlinePlayers()) {
Entity vehicle = player.getVehicle();
if (vehicle != null) {
tryLeavingSeat(player, vehicle);
}
}
}
@EventHandler(ignoreCancelled = true)
public void onPlayerQuit(PlayerQuitEvent event) {
Player player = event.getPlayer();
Entity entity = player.getVehicle();
if (entity == null) return;
if (this.isSeatEntityType(entity)) {
this.tryLeavingSeat(player, entity);
}
}
@EventHandler(ignoreCancelled = true)
public void onPlayerDeath(PlayerDeathEvent event) {
Player player = event.getPlayer();
Entity entity = player.getVehicle();
if (entity == null) return;
if (this.isSeatEntityType(entity)) {
this.tryLeavingSeat(player, entity);
}
}
// do not allow players to put item on seats
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
public void onInteractArmorStand(PlayerInteractAtEntityEvent event) {
Entity clicked = event.getRightClicked();
if (clicked instanceof ArmorStand armorStand) {
if (!armorStand.getPersistentDataContainer().has(SEAT_KEY)) return;
event.setCancelled(true);
}
}
protected boolean isSeatEntityType(Entity entity) {
return (entity instanceof ArmorStand || entity instanceof ItemDisplay);
}
protected void tryLeavingSeat(@NotNull Player player, @NotNull Entity seat) {
boolean isSeat = seat.getPersistentDataContainer().has(SEAT_KEY);
if (!isSeat) return;
seat.remove();
}
public static BukkitSeatManager instance() {
return instance;
}
}

View File

@@ -4,7 +4,7 @@ import net.momirealms.craftengine.bukkit.nms.FastNMS;
import net.momirealms.craftengine.core.entity.player.Player; import net.momirealms.craftengine.core.entity.player.Player;
import net.momirealms.craftengine.core.item.CustomItem; import net.momirealms.craftengine.core.item.CustomItem;
import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.item.Item;
import net.momirealms.craftengine.core.item.ItemBuildContext; import net.momirealms.craftengine.core.item.NetworkItemBuildContext;
import net.momirealms.craftengine.core.item.NetworkItemHandler; import net.momirealms.craftengine.core.item.NetworkItemHandler;
import net.momirealms.craftengine.core.item.modifier.ArgumentsModifier; import net.momirealms.craftengine.core.item.modifier.ArgumentsModifier;
import net.momirealms.craftengine.core.item.modifier.ItemDataModifier; import net.momirealms.craftengine.core.item.modifier.ItemDataModifier;
@@ -209,15 +209,15 @@ public final class LegacyNetworkItemHandler implements NetworkItemHandler<ItemSt
CompoundTag tag = new CompoundTag(); CompoundTag tag = new CompoundTag();
// 创建context // 创建context
Tag argumentTag = wrapped.getTag(ArgumentsModifier.ARGUMENTS_TAG); Tag argumentTag = wrapped.getTag(ArgumentsModifier.ARGUMENTS_TAG);
ItemBuildContext context; NetworkItemBuildContext context;
if (argumentTag instanceof CompoundTag arguments) { if (argumentTag instanceof CompoundTag arguments) {
ContextHolder.Builder builder = ContextHolder.builder(); ContextHolder.Builder builder = ContextHolder.builder();
for (Map.Entry<String, Tag> entry : arguments.entrySet()) { for (Map.Entry<String, Tag> entry : arguments.entrySet()) {
builder.withParameter(ContextKey.direct(entry.getKey()), entry.getValue().getAsString()); builder.withParameter(ContextKey.direct(entry.getKey()), entry.getValue().getAsString());
} }
context = ItemBuildContext.of(player, builder); context = NetworkItemBuildContext.of(player, builder);
} else { } else {
context = ItemBuildContext.of(player); context = NetworkItemBuildContext.of(player);
} }
// 准备阶段 // 准备阶段
for (ItemDataModifier<ItemStack> modifier : customItem.clientBoundDataModifiers()) { for (ItemDataModifier<ItemStack> modifier : customItem.clientBoundDataModifiers()) {

View File

@@ -185,15 +185,15 @@ public final class ModernNetworkItemHandler implements NetworkItemHandler<ItemSt
.orElseGet(CompoundTag::new); .orElseGet(CompoundTag::new);
CompoundTag arguments = customData.getCompound(ArgumentsModifier.ARGUMENTS_TAG); CompoundTag arguments = customData.getCompound(ArgumentsModifier.ARGUMENTS_TAG);
// 创建context // 创建context
ItemBuildContext context; NetworkItemBuildContext context;
if (arguments == null) { if (arguments == null) {
context = ItemBuildContext.of(player); context = NetworkItemBuildContext.of(player);
} else { } else {
ContextHolder.Builder builder = ContextHolder.builder(); ContextHolder.Builder builder = ContextHolder.builder();
for (Map.Entry<String, Tag> entry : arguments.entrySet()) { for (Map.Entry<String, Tag> entry : arguments.entrySet()) {
builder.withParameter(ContextKey.direct(entry.getKey()), entry.getValue().getAsString()); builder.withParameter(ContextKey.direct(entry.getKey()), entry.getValue().getAsString());
} }
context = ItemBuildContext.of(player, builder); context = NetworkItemBuildContext.of(player, builder);
} }
// 准备阶段 // 准备阶段
CompoundTag tag = new CompoundTag(); CompoundTag tag = new CompoundTag();

View File

@@ -3,7 +3,6 @@ package net.momirealms.craftengine.bukkit.item.behavior;
import net.momirealms.craftengine.bukkit.block.behavior.StrippableBlockBehavior; import net.momirealms.craftengine.bukkit.block.behavior.StrippableBlockBehavior;
import net.momirealms.craftengine.bukkit.item.BukkitItemManager; import net.momirealms.craftengine.bukkit.item.BukkitItemManager;
import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.nms.FastNMS;
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections;
import net.momirealms.craftengine.bukkit.util.*; import net.momirealms.craftengine.bukkit.util.*;
import net.momirealms.craftengine.bukkit.world.BukkitExistingBlock; import net.momirealms.craftengine.bukkit.world.BukkitExistingBlock;
import net.momirealms.craftengine.core.block.BlockStateWrapper; import net.momirealms.craftengine.core.block.BlockStateWrapper;

View File

@@ -12,7 +12,7 @@ import net.momirealms.craftengine.bukkit.util.LocationUtils;
import net.momirealms.craftengine.core.entity.furniture.AnchorType; import net.momirealms.craftengine.core.entity.furniture.AnchorType;
import net.momirealms.craftengine.core.entity.furniture.CustomFurniture; import net.momirealms.craftengine.core.entity.furniture.CustomFurniture;
import net.momirealms.craftengine.core.entity.furniture.FurnitureExtraData; import net.momirealms.craftengine.core.entity.furniture.FurnitureExtraData;
import net.momirealms.craftengine.core.entity.furniture.HitBox; import net.momirealms.craftengine.core.entity.furniture.HitBoxConfig;
import net.momirealms.craftengine.core.entity.player.InteractionResult; import net.momirealms.craftengine.core.entity.player.InteractionResult;
import net.momirealms.craftengine.core.entity.player.Player; import net.momirealms.craftengine.core.entity.player.Player;
import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.item.Item;
@@ -109,8 +109,8 @@ public class FurnitureItemBehavior extends ItemBehavior {
Location furnitureLocation = new Location(world, finalPlacePosition.x(), finalPlacePosition.y(), finalPlacePosition.z(), (float) furnitureYaw, 0); Location furnitureLocation = new Location(world, finalPlacePosition.x(), finalPlacePosition.y(), finalPlacePosition.z(), (float) furnitureYaw, 0);
List<AABB> aabbs = new ArrayList<>(); List<AABB> aabbs = new ArrayList<>();
for (HitBox hitBox : placement.hitBoxes()) { for (HitBoxConfig hitBoxConfig : placement.hitBoxConfigs()) {
hitBox.initShapeForPlacement(finalPlacePosition.x(), finalPlacePosition.y(), finalPlacePosition.z(), (float) furnitureYaw, QuaternionUtils.toQuaternionf(0, Math.toRadians(180 - furnitureYaw), 0).conjugate(), aabbs::add); hitBoxConfig.initShapeForPlacement(finalPlacePosition.x(), finalPlacePosition.y(), finalPlacePosition.z(), (float) furnitureYaw, QuaternionUtils.toQuaternionf(0, Math.toRadians(180 - furnitureYaw), 0).conjugate(), aabbs::add);
} }
if (!aabbs.isEmpty()) { if (!aabbs.isEmpty()) {
if (!FastNMS.INSTANCE.checkEntityCollision(context.getLevel().serverWorld(), aabbs.stream().map(it -> FastNMS.INSTANCE.constructor$AABB(it.minX, it.minY, it.minZ, it.maxX, it.maxY, it.maxZ)).toList(), finalPlacePosition.x(), finalPlacePosition.y(), finalPlacePosition.z())) { if (!FastNMS.INSTANCE.checkEntityCollision(context.getLevel().serverWorld(), aabbs.stream().map(it -> FastNMS.INSTANCE.constructor$AABB(it.minX, it.minY, it.minZ, it.maxX, it.maxY, it.maxZ)).toList(), finalPlacePosition.x(), finalPlacePosition.y(), finalPlacePosition.z())) {

View File

@@ -9,6 +9,7 @@ import net.momirealms.craftengine.bukkit.block.entity.renderer.element.BukkitBlo
import net.momirealms.craftengine.bukkit.entity.furniture.BukkitFurnitureManager; import net.momirealms.craftengine.bukkit.entity.furniture.BukkitFurnitureManager;
import net.momirealms.craftengine.bukkit.entity.furniture.hitbox.BukkitHitBoxTypes; import net.momirealms.craftengine.bukkit.entity.furniture.hitbox.BukkitHitBoxTypes;
import net.momirealms.craftengine.bukkit.entity.projectile.BukkitProjectileManager; import net.momirealms.craftengine.bukkit.entity.projectile.BukkitProjectileManager;
import net.momirealms.craftengine.bukkit.entity.seat.BukkitSeatManager;
import net.momirealms.craftengine.bukkit.font.BukkitFontManager; import net.momirealms.craftengine.bukkit.font.BukkitFontManager;
import net.momirealms.craftengine.bukkit.item.BukkitItemManager; import net.momirealms.craftengine.bukkit.item.BukkitItemManager;
import net.momirealms.craftengine.bukkit.item.behavior.BukkitItemBehaviors; import net.momirealms.craftengine.bukkit.item.behavior.BukkitItemBehaviors;
@@ -209,6 +210,7 @@ public class BukkitCraftEngine extends CraftEngine {
super.advancementManager = new BukkitAdvancementManager(this); super.advancementManager = new BukkitAdvancementManager(this);
super.projectileManager = new BukkitProjectileManager(this); super.projectileManager = new BukkitProjectileManager(this);
super.furnitureManager = new BukkitFurnitureManager(this); super.furnitureManager = new BukkitFurnitureManager(this);
super.seatManager = new BukkitSeatManager(this);
super.onPluginEnable(); super.onPluginEnable();
super.compatibilityManager().onEnable(); super.compatibilityManager().onEnable();

View File

@@ -14,7 +14,10 @@ import net.momirealms.craftengine.core.plugin.config.Config;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.incendo.cloud.Command; import org.incendo.cloud.Command;
import java.util.*; import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class DebugRealStateUsageCommand extends BukkitCommandFeature<CommandSender> { public class DebugRealStateUsageCommand extends BukkitCommandFeature<CommandSender> {

View File

@@ -58,7 +58,10 @@ import net.momirealms.craftengine.bukkit.world.BukkitWorldManager;
import net.momirealms.craftengine.core.advancement.network.AdvancementHolder; import net.momirealms.craftengine.core.advancement.network.AdvancementHolder;
import net.momirealms.craftengine.core.advancement.network.AdvancementProgress; import net.momirealms.craftengine.core.advancement.network.AdvancementProgress;
import net.momirealms.craftengine.core.block.ImmutableBlockState; import net.momirealms.craftengine.core.block.ImmutableBlockState;
import net.momirealms.craftengine.core.entity.furniture.HitBox;
import net.momirealms.craftengine.core.entity.furniture.HitBoxPart;
import net.momirealms.craftengine.core.entity.player.InteractionHand; import net.momirealms.craftengine.core.entity.player.InteractionHand;
import net.momirealms.craftengine.core.entity.seat.Seat;
import net.momirealms.craftengine.core.font.FontManager; import net.momirealms.craftengine.core.font.FontManager;
import net.momirealms.craftengine.core.font.IllegalCharacterProcessResult; import net.momirealms.craftengine.core.font.IllegalCharacterProcessResult;
import net.momirealms.craftengine.core.item.CustomItem; import net.momirealms.craftengine.core.item.CustomItem;
@@ -92,7 +95,6 @@ import net.momirealms.craftengine.core.world.chunk.Palette;
import net.momirealms.craftengine.core.world.chunk.PalettedContainer; import net.momirealms.craftengine.core.world.chunk.PalettedContainer;
import net.momirealms.craftengine.core.world.chunk.packet.BlockEntityData; import net.momirealms.craftengine.core.world.chunk.packet.BlockEntityData;
import net.momirealms.craftengine.core.world.chunk.packet.MCSection; import net.momirealms.craftengine.core.world.chunk.packet.MCSection;
import net.momirealms.craftengine.core.world.collision.AABB;
import net.momirealms.sparrow.nbt.CompoundTag; import net.momirealms.sparrow.nbt.CompoundTag;
import net.momirealms.sparrow.nbt.ListTag; import net.momirealms.sparrow.nbt.ListTag;
import net.momirealms.sparrow.nbt.Tag; import net.momirealms.sparrow.nbt.Tag;
@@ -3635,8 +3637,6 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes
float x = buf.readFloat(); float x = buf.readFloat();
float y = buf.readFloat(); float y = buf.readFloat();
float z = buf.readFloat(); float z = buf.readFloat();
// todo 这个是错误的,这是实体的相对位置而非绝对位置
Location interactionPoint = new Location(platformPlayer.getWorld(), x, y, z);
InteractionHand hand = buf.readVarInt() == 0 ? InteractionHand.MAIN_HAND : InteractionHand.OFF_HAND; InteractionHand hand = buf.readVarInt() == 0 ? InteractionHand.MAIN_HAND : InteractionHand.OFF_HAND;
boolean usingSecondaryAction = buf.readBoolean(); boolean usingSecondaryAction = buf.readBoolean();
if (entityId != furniture.baseEntityId()) { if (entityId != furniture.baseEntityId()) {
@@ -3655,16 +3655,40 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes
return; return;
} }
// todo 重构家具时候注意需要准备加载好的hitbox类以获取hitbox坐标 // 先检查碰撞箱部分是否存在
if (!serverPlayer.canInteractPoint(new Vec3d(location.getX(), location.getY(), location.getZ()), 16d)) { HitBoxPart hitBoxPart = furniture.hitBoxPartByEntityId(entityId);
if (hitBoxPart == null) return;
Vec3d pos = hitBoxPart.pos();
// 检测距离
if (!serverPlayer.canInteractPoint(pos, 16d)) {
return;
}
// 检测
Location eyeLocation = platformPlayer.getEyeLocation();
Vector direction = eyeLocation.getDirection();
Location endLocation = eyeLocation.clone();
endLocation.add(direction.multiply(serverPlayer.getCachedInteractionRange()));
Optional<EntityHitResult> result = hitBoxPart.aabb().clip(LocationUtils.toVec3d(eyeLocation), LocationUtils.toVec3d(endLocation));
if (result.isEmpty()) {
return;
}
EntityHitResult hitResult = result.get();
Vec3d hitLocation = hitResult.hitLocation();
// 获取正确的交互点
Location interactionPoint = new Location(platformPlayer.getWorld(), hitLocation.x, hitLocation.y, hitLocation.z);
HitBox hitbox = furniture.hitBoxByEntityId(entityId);
if (hitbox == null) {
return; return;
} }
FurnitureInteractEvent interactEvent = new FurnitureInteractEvent(serverPlayer.platformPlayer(), furniture, hand, interactionPoint); // 触发事件
FurnitureInteractEvent interactEvent = new FurnitureInteractEvent(serverPlayer.platformPlayer(), furniture, hand, interactionPoint, hitbox);
if (EventUtils.fireAndCheckCancel(interactEvent)) { if (EventUtils.fireAndCheckCancel(interactEvent)) {
return; return;
} }
// 执行事件动作
Item<ItemStack> itemInHand = serverPlayer.getItemInHand(InteractionHand.MAIN_HAND); Item<ItemStack> itemInHand = serverPlayer.getItemInHand(InteractionHand.MAIN_HAND);
Cancellable cancellable = Cancellable.of(interactEvent::isCancelled, interactEvent::setCancelled); Cancellable cancellable = Cancellable.of(interactEvent::isCancelled, interactEvent::setCancelled);
// execute functions // execute functions
@@ -3681,20 +3705,8 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes
} }
// 必须从网络包层面处理,否则无法获取交互的具体实体 // 必须从网络包层面处理,否则无法获取交互的具体实体
if (serverPlayer.isSecondaryUseActive() && !itemInHand.isEmpty()) { if (serverPlayer.isSecondaryUseActive() && !itemInHand.isEmpty() && hitbox.config().canUseItemOn()) {
// try placing another furniture above it
AABB hitBox = furniture.aabbByEntityId(entityId);
if (hitBox == null) return;
Optional<CustomItem<ItemStack>> optionalCustomItem = itemInHand.getCustomItem(); Optional<CustomItem<ItemStack>> optionalCustomItem = itemInHand.getCustomItem();
Location eyeLocation = platformPlayer.getEyeLocation();
Vector direction = eyeLocation.getDirection();
Location endLocation = eyeLocation.clone();
endLocation.add(direction.multiply(serverPlayer.getCachedInteractionRange()));
Optional<EntityHitResult> result = hitBox.clip(LocationUtils.toVec3d(eyeLocation), LocationUtils.toVec3d(endLocation));
if (result.isEmpty()) {
return;
}
EntityHitResult hitResult = result.get();
if (optionalCustomItem.isPresent() && !optionalCustomItem.get().behaviors().isEmpty()) { if (optionalCustomItem.isPresent() && !optionalCustomItem.get().behaviors().isEmpty()) {
for (ItemBehavior behavior : optionalCustomItem.get().behaviors()) { for (ItemBehavior behavior : optionalCustomItem.get().behaviors()) {
if (behavior instanceof FurnitureItemBehavior) { if (behavior instanceof FurnitureItemBehavior) {
@@ -3713,11 +3725,11 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes
); );
} else { } else {
if (!serverPlayer.isSecondaryUseActive()) { if (!serverPlayer.isSecondaryUseActive()) {
furniture.findFirstAvailableSeat(entityId).ifPresent(seatPos -> { for (Seat<HitBox> seat : hitbox.seats()) {
if (furniture.tryOccupySeat(seatPos)) { if (!seat.isOccupied()) {
furniture.spawnSeatEntityForPlayer(serverPlayer, seatPos); seat.spawnSeat(serverPlayer, furniture.position());
} }
}); }
} }
} }
}; };

View File

@@ -8,9 +8,9 @@ import net.momirealms.craftengine.bukkit.plugin.network.payload.protocol.ClientC
import net.momirealms.craftengine.bukkit.plugin.network.payload.protocol.VisualBlockStatePacket; import net.momirealms.craftengine.bukkit.plugin.network.payload.protocol.VisualBlockStatePacket;
import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.CraftEngine;
import net.momirealms.craftengine.core.plugin.logger.Debugger; import net.momirealms.craftengine.core.plugin.logger.Debugger;
import net.momirealms.craftengine.core.plugin.network.PayloadChannelKeys;
import net.momirealms.craftengine.core.plugin.network.ModPacket; import net.momirealms.craftengine.core.plugin.network.ModPacket;
import net.momirealms.craftengine.core.plugin.network.NetWorkUser; import net.momirealms.craftengine.core.plugin.network.NetWorkUser;
import net.momirealms.craftengine.core.plugin.network.PayloadChannelKeys;
import net.momirealms.craftengine.core.plugin.network.codec.NetworkCodec; import net.momirealms.craftengine.core.plugin.network.codec.NetworkCodec;
import net.momirealms.craftengine.core.registry.BuiltInRegistries; import net.momirealms.craftengine.core.registry.BuiltInRegistries;
import net.momirealms.craftengine.core.registry.WritableRegistry; import net.momirealms.craftengine.core.registry.WritableRegistry;

View File

@@ -14,7 +14,7 @@ public final class LocationUtils {
private LocationUtils() {} private LocationUtils() {}
public static Location toLocation(WorldPosition position) { public static Location toLocation(WorldPosition position) {
return new Location((World) position.world().platformWorld(), position.x(), position.y(), position.z(), position.xRot(), position.yRot()); return new Location((World) position.world().platformWorld(), position.x(), position.y(), position.z(), position.yRot(), position.xRot());
} }
public static WorldPosition toWorldPosition(Location location) { public static WorldPosition toWorldPosition(Location location) {

View File

@@ -114,7 +114,7 @@ resource-pack:
method-2: false # This will increase the resource pack size by 64KB method-2: false # This will increase the resource pack size by 64KB
method-3: false # This will increase the resource pack size by 0.67MB method-3: false # This will increase the resource pack size by 0.67MB
method-4: false method-4: false
method-5: true # This can reduce the resource pack size, also it prevents some software from extracting it method-5: true # This will reduce the resource pack size, also it prevents some software from extracting it
method-6: false # This will increase the resource pack size by a certain percentage method-6: false # This will increase the resource pack size by a certain percentage
method-7: false method-7: false
# Create incorrect crc data # Create incorrect crc data

View File

@@ -35,6 +35,9 @@ items:
- type: bouncing_block - type: bouncing_block
bounce-height: 0.66 bounce-height: 0.66
sync-player-position: false sync-player-position: false
- type: seat_block
seats:
- 0,0,0
state: state:
state: white_bed[facing=west,occupied=false,part=foot] state: white_bed[facing=west,occupied=false,part=foot]
entity-renderer: entity-renderer:
@@ -79,6 +82,9 @@ items:
- type: sofa_block - type: sofa_block
- type: bouncing_block - type: bouncing_block
bounce-height: 0.66 bounce-height: 0.66
- type: seat_block
seats:
- 0,0,0 0
states: states:
properties: properties:
facing: facing:

View File

@@ -646,7 +646,7 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem
// 绑定行为 // 绑定行为
for (ImmutableBlockState state : states) { for (ImmutableBlockState state : states) {
if (isEntityBlock) { if (isEntityBlock) {
state.setBlockEntityType(entityBlockBehavior.blockEntityType()); state.setBlockEntityType(entityBlockBehavior.blockEntityType(state));
} }
state.setBehavior(blockBehavior); state.setBehavior(blockBehavior);
int internalId = state.customBlockState().registryId(); int internalId = state.customBlockState().registryId();

View File

@@ -19,7 +19,7 @@ import java.util.concurrent.Callable;
public abstract class BlockBehavior { public abstract class BlockBehavior {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public <T extends BlockBehavior> Optional<T> getAs(Class<T> tClass) { public <T> Optional<T> getAs(Class<T> tClass) {
if (tClass.isInstance(this)) { if (tClass.isInstance(this)) {
return Optional.of((T) this); return Optional.of((T) this);
} }

View File

@@ -7,12 +7,15 @@ import net.momirealms.craftengine.core.block.entity.tick.BlockEntityTicker;
import net.momirealms.craftengine.core.world.BlockPos; import net.momirealms.craftengine.core.world.BlockPos;
import net.momirealms.craftengine.core.world.CEWorld; import net.momirealms.craftengine.core.world.CEWorld;
import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.Nullable;
@ApiStatus.Experimental @ApiStatus.Experimental
public interface EntityBlockBehavior { public interface EntityBlockBehavior {
<T extends BlockEntity> BlockEntityType<T> blockEntityType(); @Nullable
<T extends BlockEntity> BlockEntityType<T> blockEntityType(ImmutableBlockState state);
@Nullable
BlockEntity createBlockEntity(BlockPos pos, ImmutableBlockState state); BlockEntity createBlockEntity(BlockPos pos, ImmutableBlockState state);
default <T extends BlockEntity> BlockEntityTicker<T> createSyncBlockEntityTicker(CEWorld level, ImmutableBlockState state, BlockEntityType<T> blockEntityType) { default <T extends BlockEntity> BlockEntityTicker<T> createSyncBlockEntityTicker(CEWorld level, ImmutableBlockState state, BlockEntityType<T> blockEntityType) {

View File

@@ -2,5 +2,5 @@ package net.momirealms.craftengine.core.block.entity;
import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.Key;
public record BlockEntityType<T extends BlockEntity>(Key id, BlockEntity.Factory<T> factory) { public record BlockEntityType<T extends BlockEntity>(Key id) {
} }

View File

@@ -9,4 +9,5 @@ public final class BlockEntityTypeKeys {
public static final Key SIMPLE_STORAGE = Key.of("craftengine:simple_storage"); public static final Key SIMPLE_STORAGE = Key.of("craftengine:simple_storage");
public static final Key SIMPLE_PARTICLE = Key.of("craftengine:simple_particle"); public static final Key SIMPLE_PARTICLE = Key.of("craftengine:simple_particle");
public static final Key WALL_TORCH_PARTICLE = Key.of("craftengine:wall_torch_particle"); public static final Key WALL_TORCH_PARTICLE = Key.of("craftengine:wall_torch_particle");
public static final Key SEAT = Key.of("craftengine:seat");
} }

View File

@@ -8,8 +8,8 @@ import net.momirealms.craftengine.core.util.ResourceKey;
public abstract class BlockEntityTypes { public abstract class BlockEntityTypes {
public static <T extends BlockEntity> BlockEntityType<T> register(Key id, BlockEntity.Factory<T> factory) { public static <T extends BlockEntity> BlockEntityType<T> register(Key id) {
BlockEntityType<T> type = new BlockEntityType<>(id, factory); BlockEntityType<T> type = new BlockEntityType<>(id);
((WritableRegistry<BlockEntityType<?>>) BuiltInRegistries.BLOCK_ENTITY_TYPE) ((WritableRegistry<BlockEntityType<?>>) BuiltInRegistries.BLOCK_ENTITY_TYPE)
.register(ResourceKey.create(Registries.BLOCK_ENTITY_TYPE.location(), id), type); .register(ResourceKey.create(Registries.BLOCK_ENTITY_TYPE.location(), id), type);
return type; return type;

View File

@@ -1,5 +1,6 @@
package net.momirealms.craftengine.core.block.properties.type; package net.momirealms.craftengine.core.block.properties.type;
public enum DoorHinge { public enum DoorHinge {
LEFT, RIGHT LEFT,
RIGHT
} }

View File

@@ -1,5 +1,6 @@
package net.momirealms.craftengine.core.block.properties.type; package net.momirealms.craftengine.core.block.properties.type;
public enum DoubleBlockHalf { public enum DoubleBlockHalf {
UPPER, LOWER LOWER,
UPPER
} }

View File

@@ -1,5 +1,6 @@
package net.momirealms.craftengine.core.block.properties.type; package net.momirealms.craftengine.core.block.properties.type;
public enum SingleBlockHalf { public enum SingleBlockHalf {
TOP, BOTTOM BOTTOM,
TOP
} }

View File

@@ -70,7 +70,7 @@ public abstract class AbstractFurnitureManager implements FurnitureManager {
this.byId.clear(); this.byId.clear();
} }
protected abstract HitBox defaultHitBox(); protected abstract HitBoxConfig defaultHitBox();
protected abstract FurnitureElement.Builder furnitureElementBuilder(); protected abstract FurnitureElement.Builder furnitureElementBuilder();
@@ -154,7 +154,7 @@ public abstract class AbstractFurnitureManager implements FurnitureManager {
} }
// add hitboxes // add hitboxes
List<HitBox> hitboxes = ResourceConfigUtils.parseConfigAsList(placementArguments.get("hitboxes"), HitBoxTypes::fromMap); List<HitBoxConfig> hitboxes = ResourceConfigUtils.parseConfigAsList(placementArguments.get("hitboxes"), HitBoxTypes::fromMap);
if (hitboxes.isEmpty() && externalModel.isEmpty()) { if (hitboxes.isEmpty() && externalModel.isEmpty()) {
hitboxes = List.of(defaultHitBox()); hitboxes = List.of(defaultHitBox());
} }
@@ -165,7 +165,7 @@ public abstract class AbstractFurnitureManager implements FurnitureManager {
placements.put(anchorType, new CustomFurniture.Placement( placements.put(anchorType, new CustomFurniture.Placement(
anchorType, anchorType,
elements.toArray(new FurnitureElement[0]), elements.toArray(new FurnitureElement[0]),
hitboxes.toArray(new HitBox[0]), hitboxes.toArray(new HitBoxConfig[0]),
ResourceConfigUtils.getOrDefault(ruleSection.get("rotation"), o -> RotationRule.valueOf(o.toString().toUpperCase(Locale.ENGLISH)), RotationRule.ANY), ResourceConfigUtils.getOrDefault(ruleSection.get("rotation"), o -> RotationRule.valueOf(o.toString().toUpperCase(Locale.ENGLISH)), RotationRule.ANY),
ResourceConfigUtils.getOrDefault(ruleSection.get("alignment"), o -> AlignmentRule.valueOf(o.toString().toUpperCase(Locale.ENGLISH)), AlignmentRule.CENTER), ResourceConfigUtils.getOrDefault(ruleSection.get("alignment"), o -> AlignmentRule.valueOf(o.toString().toUpperCase(Locale.ENGLISH)), AlignmentRule.CENTER),
externalModel, externalModel,
@@ -175,7 +175,7 @@ public abstract class AbstractFurnitureManager implements FurnitureManager {
placements.put(anchorType, new CustomFurniture.Placement( placements.put(anchorType, new CustomFurniture.Placement(
anchorType, anchorType,
elements.toArray(new FurnitureElement[0]), elements.toArray(new FurnitureElement[0]),
hitboxes.toArray(new HitBox[0]), hitboxes.toArray(new HitBoxConfig[0]),
RotationRule.ANY, RotationRule.ANY,
AlignmentRule.CENTER, AlignmentRule.CENTER,
externalModel, externalModel,

View File

@@ -1,15 +1,16 @@
package net.momirealms.craftengine.core.entity.furniture; package net.momirealms.craftengine.core.entity.furniture;
import net.momirealms.craftengine.core.entity.seat.SeatConfig;
import org.joml.Vector3f; import org.joml.Vector3f;
public abstract class AbstractHitBox implements HitBox { public abstract class AbstractHitBoxConfig implements HitBoxConfig {
protected final Seat[] seats; protected final SeatConfig[] seats;
protected final Vector3f position; protected final Vector3f position;
protected final boolean canUseItemOn; protected final boolean canUseItemOn;
protected final boolean blocksBuilding; protected final boolean blocksBuilding;
protected final boolean canBeHitByProjectile; protected final boolean canBeHitByProjectile;
public AbstractHitBox(Seat[] seats, Vector3f position, boolean canUseItemOn, boolean blocksBuilding, boolean canBeHitByProjectile) { public AbstractHitBoxConfig(SeatConfig[] seats, Vector3f position, boolean canUseItemOn, boolean blocksBuilding, boolean canBeHitByProjectile) {
this.seats = seats; this.seats = seats;
this.position = position; this.position = position;
this.canUseItemOn = canUseItemOn; this.canUseItemOn = canUseItemOn;
@@ -18,7 +19,7 @@ public abstract class AbstractHitBox implements HitBox {
} }
@Override @Override
public Seat[] seats() { public SeatConfig[] seats() {
return this.seats; return this.seats;
} }

View File

@@ -51,7 +51,7 @@ public interface CustomFurniture {
record Placement(AnchorType anchorType, record Placement(AnchorType anchorType,
FurnitureElement[] elements, FurnitureElement[] elements,
HitBox[] hitBoxes, HitBoxConfig[] hitBoxConfigs,
RotationRule rotationRule, RotationRule rotationRule,
AlignmentRule alignmentRule, AlignmentRule alignmentRule,
Optional<ExternalModel> externalModel, Optional<ExternalModel> externalModel,

View File

@@ -1,12 +1,10 @@
package net.momirealms.craftengine.core.entity.furniture; package net.momirealms.craftengine.core.entity.furniture;
import net.momirealms.craftengine.core.entity.player.Player;
import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.core.world.WorldPosition; import net.momirealms.craftengine.core.world.WorldPosition;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.joml.Vector3f; import org.jetbrains.annotations.Nullable;
import java.util.Optional;
import java.util.UUID; import java.util.UUID;
public interface Furniture { public interface Furniture {
@@ -18,32 +16,30 @@ public interface Furniture {
void destroy(); void destroy();
void destroyColliders();
void destroySeats(); void destroySeats();
Optional<Seat> findFirstAvailableSeat(int targetEntityId);
boolean removeOccupiedSeat(Vector3f seat);
default boolean removeOccupiedSeat(Seat seat) {
return this.removeOccupiedSeat(seat.offset());
}
boolean tryOccupySeat(Seat seat);
UUID uuid(); UUID uuid();
int baseEntityId(); int baseEntityId();
@NotNull AnchorType anchorType(); @Nullable
HitBox hitBoxByEntityId(int id);
@NotNull Key id(); @Nullable HitBoxPart hitBoxPartByEntityId(int id);
@NotNull CustomFurniture config(); @NotNull
AnchorType anchorType();
@NotNull
Key id();
@NotNull
CustomFurniture config();
boolean hasExternalModel(); boolean hasExternalModel();
void spawnSeatEntityForPlayer(Player player, Seat seat);
FurnitureExtraData extraData(); FurnitureExtraData extraData();
void setExtraData(FurnitureExtraData extraData); void setExtraData(FurnitureExtraData extraData);

View File

@@ -15,8 +15,6 @@ import java.util.Optional;
public interface FurnitureManager extends Manageable { public interface FurnitureManager extends Manageable {
Key FURNITURE_KEY = Key.of("craftengine:furniture_id"); Key FURNITURE_KEY = Key.of("craftengine:furniture_id");
Key FURNITURE_EXTRA_DATA_KEY = Key.of("craftengine:furniture_extra_data"); Key FURNITURE_EXTRA_DATA_KEY = Key.of("craftengine:furniture_extra_data");
Key FURNITURE_SEAT_BASE_ENTITY_KEY = Key.of("craftengine:seat_to_base_entity");
Key FURNITURE_SEAT_VECTOR_3F_KEY = Key.of("craftengine:seat_vector");
Key FURNITURE_COLLISION = Key.of("craftengine:collision"); Key FURNITURE_COLLISION = Key.of("craftengine:collision");
String FURNITURE_ADMIN_NODE = "craftengine.furniture.admin"; String FURNITURE_ADMIN_NODE = "craftengine.furniture.admin";

View File

@@ -1,33 +1,19 @@
package net.momirealms.craftengine.core.entity.furniture; package net.momirealms.craftengine.core.entity.furniture;
import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.entity.seat.Seat;
import net.momirealms.craftengine.core.world.WorldPosition; import net.momirealms.craftengine.core.entity.seat.SeatOwner;
import net.momirealms.craftengine.core.world.collision.AABB; import net.momirealms.craftengine.core.world.EntityHitResult;
import org.joml.Quaternionf; import net.momirealms.craftengine.core.world.Vec3d;
import org.joml.Vector3f;
import java.util.function.BiConsumer; import java.util.Optional;
import java.util.function.Consumer;
import java.util.function.Supplier;
public interface HitBox { public interface HitBox extends SeatOwner {
Key type(); Seat<HitBox>[] seats();
void initPacketsAndColliders(int[] entityId, WorldPosition position, Quaternionf conjugated, Optional<EntityHitResult> clip(Vec3d min, Vec3d max);
BiConsumer<Object, Boolean> packets, Consumer<Collider> collider, BiConsumer<Integer, AABB> aabb);
void initShapeForPlacement(double x, double y, double z, float yaw, Quaternionf conjugated, Consumer<AABB> aabbs); HitBoxPart[] parts();
int[] acquireEntityIds(Supplier<Integer> entityIdSupplier); HitBoxConfig config();
Seat[] seats();
Vector3f position();
boolean blocksBuilding();
boolean canBeHitByProjectile();
boolean canUseItemOn();
} }

View File

@@ -0,0 +1,34 @@
package net.momirealms.craftengine.core.entity.furniture;
import net.momirealms.craftengine.core.entity.seat.SeatConfig;
import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.core.world.WorldPosition;
import net.momirealms.craftengine.core.world.collision.AABB;
import org.joml.Quaternionf;
import org.joml.Vector3f;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Supplier;
public interface HitBoxConfig {
Key type();
void initPacketsAndColliders(int[] entityId, WorldPosition position, Quaternionf conjugated,
BiConsumer<Object, Boolean> packets, Consumer<Collider> collider, Consumer<HitBoxPart> aabb);
void initShapeForPlacement(double x, double y, double z, float yaw, Quaternionf conjugated, Consumer<AABB> aabbs);
int[] acquireEntityIds(Supplier<Integer> entityIdSupplier);
SeatConfig[] seats();
Vector3f position();
boolean blocksBuilding();
boolean canBeHitByProjectile();
boolean canUseItemOn();
}

View File

@@ -0,0 +1,8 @@
package net.momirealms.craftengine.core.entity.furniture;
import java.util.Map;
public interface HitBoxConfigFactory {
HitBoxConfig create(Map<String, Object> arguments);
}

View File

@@ -1,23 +0,0 @@
package net.momirealms.craftengine.core.entity.furniture;
import net.momirealms.craftengine.core.util.ResourceConfigUtils;
import java.util.List;
import java.util.Map;
public interface HitBoxFactory {
HitBox create(Map<String, Object> arguments);
@SuppressWarnings("unchecked")
static Seat[] getSeats(Map<String, Object> arguments) {
List<String> seats = (List<String>) arguments.getOrDefault("seats", List.of());
return seats.stream()
.map(arg -> {
String[] split = arg.split(" ");
if (split.length == 1) return new Seat(ResourceConfigUtils.getAsVector3f(split[0], "seats"), 0, false);
return new Seat(ResourceConfigUtils.getAsVector3f(split[0], "seats"), Float.parseFloat(split[1]), true);
})
.toArray(Seat[]::new);
}
}

View File

@@ -0,0 +1,7 @@
package net.momirealms.craftengine.core.entity.furniture;
import net.momirealms.craftengine.core.world.Vec3d;
import net.momirealms.craftengine.core.world.collision.AABB;
public record HitBoxPart(int entityId, AABB aabb, Vec3d pos) {
}

View File

@@ -16,14 +16,14 @@ public class HitBoxTypes {
public static final Key HAPPY_GHAST = Key.of("minecraft:happy_ghast"); public static final Key HAPPY_GHAST = Key.of("minecraft:happy_ghast");
public static final Key CUSTOM = Key.of("minecraft:custom"); public static final Key CUSTOM = Key.of("minecraft:custom");
public static void register(Key key, HitBoxFactory factory) { public static void register(Key key, HitBoxConfigFactory factory) {
((WritableRegistry<HitBoxFactory>) BuiltInRegistries.HITBOX_FACTORY) ((WritableRegistry<HitBoxConfigFactory>) BuiltInRegistries.HITBOX_FACTORY)
.register(ResourceKey.create(Registries.HITBOX_FACTORY.location(), key), factory); .register(ResourceKey.create(Registries.HITBOX_FACTORY.location(), key), factory);
} }
public static HitBox fromMap(Map<String, Object> arguments) { public static HitBoxConfig fromMap(Map<String, Object> arguments) {
Key type = Optional.ofNullable(arguments.get("type")).map(String::valueOf).map(Key::of).orElse(HitBoxTypes.INTERACTION); Key type = Optional.ofNullable(arguments.get("type")).map(String::valueOf).map(Key::of).orElse(HitBoxTypes.INTERACTION);
HitBoxFactory factory = BuiltInRegistries.HITBOX_FACTORY.getValue(type); HitBoxConfigFactory factory = BuiltInRegistries.HITBOX_FACTORY.getValue(type);
if (factory == null) { if (factory == null) {
throw new LocalizedResourceConfigException("warning.config.furniture.hitbox.invalid_type", type.toString()); throw new LocalizedResourceConfigException("warning.config.furniture.hitbox.invalid_type", type.toString());
} }

View File

@@ -1,23 +0,0 @@
package net.momirealms.craftengine.core.entity.furniture;
import org.joml.Vector3f;
import java.util.Objects;
public record Seat(Vector3f offset, float yaw, boolean limitPlayerRotation) {
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Seat seat)) return false;
return Float.compare(yaw, seat.yaw) == 0 && Objects.equals(offset, seat.offset) && limitPlayerRotation == seat.limitPlayerRotation;
}
@Override
public int hashCode() {
int result = Objects.hashCode(offset);
result = 31 * result + Float.hashCode(yaw);
result = 31 * result + Boolean.hashCode(limitPlayerRotation);
return result;
}
}

View File

@@ -0,0 +1,17 @@
package net.momirealms.craftengine.core.entity.seat;
import net.momirealms.craftengine.core.entity.player.Player;
import net.momirealms.craftengine.core.world.WorldPosition;
public interface Seat<O extends SeatOwner> {
O owner();
SeatConfig config();
boolean isOccupied();
void destroy();
boolean spawnSeat(Player player, WorldPosition source);
}

View File

@@ -0,0 +1,30 @@
package net.momirealms.craftengine.core.entity.seat;
import net.momirealms.craftengine.core.util.MiscUtils;
import net.momirealms.craftengine.core.util.ResourceConfigUtils;
import org.joml.Vector3f;
import java.util.List;
public record SeatConfig(Vector3f position, float yRot, boolean limitPlayerRotation) {
public static SeatConfig[] fromObj(Object config) {
if (config instanceof List<?>) {
List<String> seats = MiscUtils.getAsStringList(config);
return seats.stream()
.map(arg -> {
String[] split = arg.split(" ");
if (split.length == 1) return new SeatConfig(ResourceConfigUtils.getAsVector3f(split[0], "seats"), 0, false);
return new SeatConfig(ResourceConfigUtils.getAsVector3f(split[0], "seats"), Float.parseFloat(split[1]), true);
})
.toArray(SeatConfig[]::new);
} else if (config != null) {
String arg = config.toString();
String[] split = arg.split(" ");
if (split.length == 1) return new SeatConfig[] {new SeatConfig(ResourceConfigUtils.getAsVector3f(split[0], "seats"), 0, false)};
return new SeatConfig[] {new SeatConfig(ResourceConfigUtils.getAsVector3f(split[0], "seats"), Float.parseFloat(split[1]), true)};
} else {
return new SeatConfig[0];
}
}
}

View File

@@ -0,0 +1,9 @@
package net.momirealms.craftengine.core.entity.seat;
import net.momirealms.craftengine.core.plugin.Manageable;
import net.momirealms.craftengine.core.util.Key;
public interface SeatManager extends Manageable {
Key SEAT_KEY = Key.of("craftengine:seat");
Key SEAT_EXTRA_DATA_KEY = Key.of("craftengine:seat_extra_data");
}

View File

@@ -0,0 +1,8 @@
package net.momirealms.craftengine.core.entity.seat;
import net.momirealms.sparrow.nbt.CompoundTag;
public interface SeatOwner {
void saveCustomData(CompoundTag data);
}

View File

@@ -0,0 +1,46 @@
package net.momirealms.craftengine.core.item;
import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver;
import net.momirealms.craftengine.core.entity.player.Player;
import net.momirealms.craftengine.core.plugin.context.ContextHolder;
import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters;
import net.momirealms.craftengine.core.plugin.text.minimessage.*;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Map;
public class NetworkItemBuildContext extends ItemBuildContext {
public NetworkItemBuildContext(@Nullable Player player, @NotNull ContextHolder contexts) {
super(player, contexts);
}
@NotNull
public static NetworkItemBuildContext empty() {
return new NetworkItemBuildContext(null, ContextHolder.empty());
}
@NotNull
public static NetworkItemBuildContext of(@Nullable Player player, @NotNull ContextHolder contexts) {
return new NetworkItemBuildContext(player, contexts);
}
@NotNull
public static NetworkItemBuildContext of(@Nullable Player player, @NotNull ContextHolder.Builder builder) {
if (player != null) builder.withParameter(DirectContextParameters.PLAYER, player);
return new NetworkItemBuildContext(player, builder.build());
}
@NotNull
public static NetworkItemBuildContext of(@Nullable Player player) {
if (player == null) return new NetworkItemBuildContext(null, ContextHolder.empty());
return new NetworkItemBuildContext(player, new ContextHolder(Map.of(DirectContextParameters.PLAYER, () -> player)));
}
@NotNull
protected TagResolver[] getInternalTagResolvers() {
return new TagResolver[]{ShiftTag.INSTANCE, ImageTag.INSTANCE, new I18NTag(this), new L10NTag(this), new NamedArgumentTag(this),
new PlaceholderTag(this), new ExpressionTag(this), new GlobalVariableTag(this)};
}
}

View File

@@ -4,6 +4,7 @@ import net.momirealms.craftengine.core.advancement.AdvancementManager;
import net.momirealms.craftengine.core.block.BlockManager; import net.momirealms.craftengine.core.block.BlockManager;
import net.momirealms.craftengine.core.entity.furniture.FurnitureManager; import net.momirealms.craftengine.core.entity.furniture.FurnitureManager;
import net.momirealms.craftengine.core.entity.projectile.ProjectileManager; import net.momirealms.craftengine.core.entity.projectile.ProjectileManager;
import net.momirealms.craftengine.core.entity.seat.SeatManager;
import net.momirealms.craftengine.core.font.FontManager; import net.momirealms.craftengine.core.font.FontManager;
import net.momirealms.craftengine.core.item.ItemManager; import net.momirealms.craftengine.core.item.ItemManager;
import net.momirealms.craftengine.core.item.recipe.RecipeManager; import net.momirealms.craftengine.core.item.recipe.RecipeManager;
@@ -76,6 +77,7 @@ public abstract class CraftEngine implements Plugin {
protected CompatibilityManager compatibilityManager; protected CompatibilityManager compatibilityManager;
protected GlobalVariableManager globalVariableManager; protected GlobalVariableManager globalVariableManager;
protected ProjectileManager projectileManager; protected ProjectileManager projectileManager;
protected SeatManager seatManager;
private final PluginTaskRegistry preLoadTaskRegistry = new PluginTaskRegistry(); private final PluginTaskRegistry preLoadTaskRegistry = new PluginTaskRegistry();
private final PluginTaskRegistry postLoadTaskRegistry = new PluginTaskRegistry(); private final PluginTaskRegistry postLoadTaskRegistry = new PluginTaskRegistry();
@@ -151,6 +153,7 @@ public abstract class CraftEngine implements Plugin {
this.packManager.reload(); this.packManager.reload();
this.advancementManager.reload(); this.advancementManager.reload();
this.projectileManager.reload(); this.projectileManager.reload();
this.seatManager.reload();
if (reloadRecipe) { if (reloadRecipe) {
this.recipeManager.reload(); this.recipeManager.reload();
} }
@@ -229,6 +232,7 @@ public abstract class CraftEngine implements Plugin {
this.fontManager.delayedInit(); this.fontManager.delayedInit();
this.vanillaLootManager.delayedInit(); this.vanillaLootManager.delayedInit();
this.advancementManager.delayedInit(); this.advancementManager.delayedInit();
this.seatManager.delayedInit();
this.compatibilityManager.onDelayedEnable(); this.compatibilityManager.onDelayedEnable();
// reload the plugin // reload the plugin
try { try {
@@ -263,6 +267,7 @@ public abstract class CraftEngine implements Plugin {
if (this.guiManager != null) this.guiManager.disable(); if (this.guiManager != null) this.guiManager.disable();
if (this.soundManager != null) this.soundManager.disable(); if (this.soundManager != null) this.soundManager.disable();
if (this.vanillaLootManager != null) this.vanillaLootManager.disable(); if (this.vanillaLootManager != null) this.vanillaLootManager.disable();
if (this.seatManager != null) this.seatManager.disable();
if (this.translationManager != null) this.translationManager.disable(); if (this.translationManager != null) this.translationManager.disable();
if (this.globalVariableManager != null) this.globalVariableManager.disable(); if (this.globalVariableManager != null) this.globalVariableManager.disable();
if (this.projectileManager != null) this.projectileManager.disable(); if (this.projectileManager != null) this.projectileManager.disable();

View File

@@ -9,10 +9,7 @@ import net.momirealms.craftengine.core.plugin.context.Context;
import net.momirealms.craftengine.core.plugin.context.number.NumberProvider; import net.momirealms.craftengine.core.plugin.context.number.NumberProvider;
import net.momirealms.craftengine.core.plugin.context.number.NumberProviders; import net.momirealms.craftengine.core.plugin.context.number.NumberProviders;
import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters;
import net.momirealms.craftengine.core.plugin.context.selector.PlayerSelector;
import net.momirealms.craftengine.core.plugin.context.selector.PlayerSelectors;
import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.core.util.ResourceConfigUtils;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;

View File

@@ -68,7 +68,7 @@ public sealed interface ComponentProvider extends Function<Context, Component>
if (context instanceof PlayerOptionalContext playerContext) { if (context instanceof PlayerOptionalContext playerContext) {
Player player = playerContext.player(); Player player = playerContext.player();
if (player != null) { if (player != null) {
String content = TranslationManager.instance().miniMessageTranslation(this.key, player.locale()); String content = TranslationManager.instance().miniMessageTranslation(this.key, player.selectedLocale());
if (content == null) { if (content == null) {
return Component.text(this.key); return Component.text(this.key);
} }

View File

@@ -0,0 +1,41 @@
package net.momirealms.craftengine.core.plugin.text.minimessage;
import net.kyori.adventure.text.minimessage.ParsingException;
import net.kyori.adventure.text.minimessage.tag.Tag;
import net.kyori.adventure.text.minimessage.tag.resolver.ArgumentQueue;
import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver;
import net.momirealms.craftengine.core.plugin.context.Context;
import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext;
import net.momirealms.craftengine.core.plugin.locale.TranslationManager;
import net.momirealms.craftengine.core.util.AdventureHelper;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Locale;
public class L10NTag implements TagResolver {
private final Context context;
public L10NTag(Context context) {
this.context = context;
}
@Override
public @Nullable Tag resolve(@NotNull String name, @NotNull ArgumentQueue arguments, @NotNull net.kyori.adventure.text.minimessage.Context ctx) throws ParsingException {
if (!this.has(name)) {
return null;
}
Locale locale = null;
if (this.context instanceof PlayerOptionalContext playerOptionalContext && playerOptionalContext.isPlayerPresent()) {
locale = playerOptionalContext.player().selectedLocale();
}
String i18nKey = arguments.popOr("No argument l10n key provided").toString();
String translation = TranslationManager.instance().miniMessageTranslation(i18nKey, locale);
return Tag.selfClosingInserting(AdventureHelper.miniMessage().deserialize(translation, this.context.tagResolvers()));
}
@Override
public boolean has(@NotNull String name) {
return "l10n".equals(name);
}
}

View File

@@ -5,7 +5,7 @@ import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory;
import net.momirealms.craftengine.core.block.entity.BlockEntityType; import net.momirealms.craftengine.core.block.entity.BlockEntityType;
import net.momirealms.craftengine.core.block.entity.render.element.BlockEntityElementConfigFactory; import net.momirealms.craftengine.core.block.entity.render.element.BlockEntityElementConfigFactory;
import net.momirealms.craftengine.core.block.properties.PropertyFactory; import net.momirealms.craftengine.core.block.properties.PropertyFactory;
import net.momirealms.craftengine.core.entity.furniture.HitBoxFactory; import net.momirealms.craftengine.core.entity.furniture.HitBoxConfigFactory;
import net.momirealms.craftengine.core.item.ItemDataModifierFactory; import net.momirealms.craftengine.core.item.ItemDataModifierFactory;
import net.momirealms.craftengine.core.item.behavior.ItemBehaviorFactory; import net.momirealms.craftengine.core.item.behavior.ItemBehaviorFactory;
import net.momirealms.craftengine.core.item.equipment.EquipmentFactory; import net.momirealms.craftengine.core.item.equipment.EquipmentFactory;
@@ -76,7 +76,7 @@ public class BuiltInRegistries {
public static final Registry<ConditionFactory<PathContext>> PATH_MATCHER_FACTORY = createConstantBoundRegistry(Registries.PATH_MATCHER_FACTORY, 16); public static final Registry<ConditionFactory<PathContext>> PATH_MATCHER_FACTORY = createConstantBoundRegistry(Registries.PATH_MATCHER_FACTORY, 16);
public static final Registry<ResolutionFactory> RESOLUTION_FACTORY = createConstantBoundRegistry(Registries.RESOLUTION_FACTORY, 16); public static final Registry<ResolutionFactory> RESOLUTION_FACTORY = createConstantBoundRegistry(Registries.RESOLUTION_FACTORY, 16);
public static final Registry<CustomSmithingTransformRecipe.ItemDataProcessor.ProcessorFactory> SMITHING_RESULT_PROCESSOR_FACTORY = createConstantBoundRegistry(Registries.SMITHING_RESULT_PROCESSOR_FACTORY, 16); public static final Registry<CustomSmithingTransformRecipe.ItemDataProcessor.ProcessorFactory> SMITHING_RESULT_PROCESSOR_FACTORY = createConstantBoundRegistry(Registries.SMITHING_RESULT_PROCESSOR_FACTORY, 16);
public static final Registry<HitBoxFactory> HITBOX_FACTORY = createConstantBoundRegistry(Registries.HITBOX_FACTORY, 16); public static final Registry<HitBoxConfigFactory> HITBOX_FACTORY = createConstantBoundRegistry(Registries.HITBOX_FACTORY, 16);
public static final Registry<ResourcePackHostFactory> RESOURCE_PACK_HOST_FACTORY = createConstantBoundRegistry(Registries.RESOURCE_PACK_HOST_FACTORY, 16); public static final Registry<ResourcePackHostFactory> RESOURCE_PACK_HOST_FACTORY = createConstantBoundRegistry(Registries.RESOURCE_PACK_HOST_FACTORY, 16);
public static final Registry<FunctionFactory<PlayerOptionalContext>> EVENT_FUNCTION_FACTORY = createConstantBoundRegistry(Registries.EVENT_FUNCTION_FACTORY, 128); public static final Registry<FunctionFactory<PlayerOptionalContext>> EVENT_FUNCTION_FACTORY = createConstantBoundRegistry(Registries.EVENT_FUNCTION_FACTORY, 128);
public static final Registry<ConditionFactory<PlayerOptionalContext>> EVENT_CONDITION_FACTORY = createConstantBoundRegistry(Registries.EVENT_CONDITION_FACTORY, 128); public static final Registry<ConditionFactory<PlayerOptionalContext>> EVENT_CONDITION_FACTORY = createConstantBoundRegistry(Registries.EVENT_CONDITION_FACTORY, 128);

View File

@@ -5,7 +5,7 @@ import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory;
import net.momirealms.craftengine.core.block.entity.BlockEntityType; import net.momirealms.craftengine.core.block.entity.BlockEntityType;
import net.momirealms.craftengine.core.block.entity.render.element.BlockEntityElementConfigFactory; import net.momirealms.craftengine.core.block.entity.render.element.BlockEntityElementConfigFactory;
import net.momirealms.craftengine.core.block.properties.PropertyFactory; import net.momirealms.craftengine.core.block.properties.PropertyFactory;
import net.momirealms.craftengine.core.entity.furniture.HitBoxFactory; import net.momirealms.craftengine.core.entity.furniture.HitBoxConfigFactory;
import net.momirealms.craftengine.core.item.ItemDataModifierFactory; import net.momirealms.craftengine.core.item.ItemDataModifierFactory;
import net.momirealms.craftengine.core.item.behavior.ItemBehaviorFactory; import net.momirealms.craftengine.core.item.behavior.ItemBehaviorFactory;
import net.momirealms.craftengine.core.item.equipment.EquipmentFactory; import net.momirealms.craftengine.core.item.equipment.EquipmentFactory;
@@ -78,7 +78,7 @@ public class Registries {
public static final ResourceKey<Registry<ConditionFactory<PathContext>>> PATH_MATCHER_FACTORY = ResourceKey.create(ROOT_REGISTRY, Key.withDefaultNamespace("path_matcher_factory")); public static final ResourceKey<Registry<ConditionFactory<PathContext>>> PATH_MATCHER_FACTORY = ResourceKey.create(ROOT_REGISTRY, Key.withDefaultNamespace("path_matcher_factory"));
public static final ResourceKey<Registry<ResolutionFactory>> RESOLUTION_FACTORY = ResourceKey.create(ROOT_REGISTRY, Key.withDefaultNamespace("resolution_factory")); public static final ResourceKey<Registry<ResolutionFactory>> RESOLUTION_FACTORY = ResourceKey.create(ROOT_REGISTRY, Key.withDefaultNamespace("resolution_factory"));
public static final ResourceKey<Registry<CustomSmithingTransformRecipe.ItemDataProcessor.ProcessorFactory>> SMITHING_RESULT_PROCESSOR_FACTORY = ResourceKey.create(ROOT_REGISTRY, Key.withDefaultNamespace("smithing_result_processor_factory")); public static final ResourceKey<Registry<CustomSmithingTransformRecipe.ItemDataProcessor.ProcessorFactory>> SMITHING_RESULT_PROCESSOR_FACTORY = ResourceKey.create(ROOT_REGISTRY, Key.withDefaultNamespace("smithing_result_processor_factory"));
public static final ResourceKey<Registry<HitBoxFactory>> HITBOX_FACTORY = ResourceKey.create(ROOT_REGISTRY, Key.withDefaultNamespace("hitbox_factory")); public static final ResourceKey<Registry<HitBoxConfigFactory>> HITBOX_FACTORY = ResourceKey.create(ROOT_REGISTRY, Key.withDefaultNamespace("hitbox_factory"));
public static final ResourceKey<Registry<ResourcePackHostFactory>> RESOURCE_PACK_HOST_FACTORY = ResourceKey.create(ROOT_REGISTRY, Key.withDefaultNamespace("resource_pack_host_factory")); public static final ResourceKey<Registry<ResourcePackHostFactory>> RESOURCE_PACK_HOST_FACTORY = ResourceKey.create(ROOT_REGISTRY, Key.withDefaultNamespace("resource_pack_host_factory"));
public static final ResourceKey<Registry<FunctionFactory<PlayerOptionalContext>>> EVENT_FUNCTION_FACTORY = ResourceKey.create(ROOT_REGISTRY, Key.withDefaultNamespace("event_function_factory")); public static final ResourceKey<Registry<FunctionFactory<PlayerOptionalContext>>> EVENT_FUNCTION_FACTORY = ResourceKey.create(ROOT_REGISTRY, Key.withDefaultNamespace("event_function_factory"));
public static final ResourceKey<Registry<ConditionFactory<PlayerOptionalContext>>> EVENT_CONDITION_FACTORY = ResourceKey.create(ROOT_REGISTRY, Key.withDefaultNamespace("event_condition_factory")); public static final ResourceKey<Registry<ConditionFactory<PlayerOptionalContext>>> EVENT_CONDITION_FACTORY = ResourceKey.create(ROOT_REGISTRY, Key.withDefaultNamespace("event_condition_factory"));

View File

@@ -1,6 +1,7 @@
package net.momirealms.craftengine.core.world.chunk.serialization; package net.momirealms.craftengine.core.world.chunk.serialization;
import net.momirealms.craftengine.core.block.ImmutableBlockState; import net.momirealms.craftengine.core.block.ImmutableBlockState;
import net.momirealms.craftengine.core.block.behavior.EntityBlockBehavior;
import net.momirealms.craftengine.core.block.entity.BlockEntity; import net.momirealms.craftengine.core.block.entity.BlockEntity;
import net.momirealms.craftengine.core.block.entity.BlockEntityType; import net.momirealms.craftengine.core.block.entity.BlockEntityType;
import net.momirealms.craftengine.core.plugin.logger.Debugger; import net.momirealms.craftengine.core.plugin.logger.Debugger;
@@ -14,6 +15,7 @@ import net.momirealms.sparrow.nbt.ListTag;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.Optional;
public final class DefaultBlockEntitySerializer { public final class DefaultBlockEntitySerializer {
@@ -41,9 +43,14 @@ public final class DefaultBlockEntitySerializer {
BlockPos pos = BlockEntity.readPosAndVerify(data, chunk.chunkPos()); BlockPos pos = BlockEntity.readPosAndVerify(data, chunk.chunkPos());
ImmutableBlockState blockState = chunk.getBlockState(pos); ImmutableBlockState blockState = chunk.getBlockState(pos);
if (blockState.blockEntityType() == type) { if (blockState.blockEntityType() == type) {
BlockEntity blockEntity = type.factory().create(pos, blockState); Optional<EntityBlockBehavior> entityBlockBehavior = blockState.behavior().getAs(EntityBlockBehavior.class);
blockEntity.loadCustomData(data); if (entityBlockBehavior.isPresent()) {
blockEntities.add(blockEntity); BlockEntity blockEntity = entityBlockBehavior.get().createBlockEntity(pos, blockState);
if (blockEntity != null) {
blockEntity.loadCustomData(data);
blockEntities.add(blockEntity);
}
}
} }
} }
} }

View File

@@ -39,7 +39,7 @@ zstd_version=1.5.7-4
commons_io_version=2.20.0 commons_io_version=2.20.0
commons_lang3_version=3.19.0 commons_lang3_version=3.19.0
sparrow_nbt_version=0.10.6 sparrow_nbt_version=0.10.6
sparrow_util_version=0.57 sparrow_util_version=0.58
fastutil_version=8.5.18 fastutil_version=8.5.18
netty_version=4.1.127.Final netty_version=4.1.127.Final
joml_version=1.10.8 joml_version=1.10.8