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

new hitbox types

This commit is contained in:
XiaoMoMi
2025-03-31 04:56:46 +08:00
parent 01a2193ab3
commit 6dd62fed3f
10 changed files with 191 additions and 55 deletions

View File

@@ -0,0 +1,44 @@
package net.momirealms.craftengine.bukkit.entity.furniture;
import net.momirealms.craftengine.core.entity.furniture.*;
import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.core.util.MiscUtils;
import org.joml.Vector3f;
import java.util.Map;
import java.util.function.Consumer;
import java.util.function.Supplier;
public class BoatHitBox extends AbstractHitBox {
public static final Factory FACTORY = new Factory();
public BoatHitBox(Seat[] seats, Vector3f position) {
super(seats, position);
}
@Override
public Key type() {
return HitBoxTypes.BOAT;
}
@Override
public void addSpawnPackets(int[] entityId, double x, double y, double z, float yaw, Consumer<Object> packets) {
// 生成无重力船
}
@Override
public int[] acquireEntityIds(Supplier<Integer> entityIdSupplier) {
return new int[] {entityIdSupplier.get()};
}
public static class Factory implements HitBoxFactory {
@Override
public HitBox create(Map<String, Object> arguments) {
return new BoatHitBox(
HitBoxFactory.getSeats(arguments),
MiscUtils.getVector3f(arguments.getOrDefault("position", "0"))
);
}
}
}

View File

@@ -237,7 +237,7 @@ public class BukkitFurnitureManager implements FurnitureManager {
LoadedFurniture furniture = this.furnitureByBaseEntityId.remove(id);
if (furniture != null) {
furniture.destroySeats();
for (int sub : furniture.interactionEntityIds()) {
for (int sub : furniture.hitBoxEntityIds()) {
this.furnitureByInteractionEntityId.remove(sub);
}
} else if (entity instanceof Interaction interaction) {
@@ -307,7 +307,7 @@ public class BukkitFurnitureManager implements FurnitureManager {
private synchronized LoadedFurniture addNewFurniture(ItemDisplay display, CustomFurniture furniture, AnchorType anchorType) {
LoadedFurniture loadedFurniture = new LoadedFurniture(display, furniture, anchorType);
this.furnitureByBaseEntityId.put(loadedFurniture.baseEntityId(), loadedFurniture);
for (int entityId : loadedFurniture.interactionEntityIds()) {
for (int entityId : loadedFurniture.hitBoxEntityIds()) {
this.furnitureByInteractionEntityId.put(entityId, loadedFurniture);
}
return loadedFurniture;

View File

@@ -8,5 +8,7 @@ public class BukkitHitBoxTypes extends HitBoxTypes {
static {
register(INTERACTION, InteractionHitBox.FACTORY);
register(SHULKER, ShulkerHitBox.FACTORY);
register(BOAT, BoatHitBox.FACTORY);
}
}

View File

@@ -13,18 +13,18 @@ import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.function.Consumer;
import java.util.function.Supplier;
public class InteractionHitBox extends AbstractHitBox {
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);
private final Vector3f position;
private final Vector3f size;
private final boolean responsive;
private final List<Object> cachedValues = new ArrayList<>();
public InteractionHitBox(Seat[] seats, Vector3f position, Vector3f size, boolean responsive) {
super(seats);
this.position = position;
super(seats, position);
this.size = size;
this.responsive = responsive;
InteractionEntityData.Height.addEntityDataIfNotDefaultValue(size.y, cachedValues);
@@ -36,10 +36,6 @@ public class InteractionHitBox extends AbstractHitBox {
return responsive;
}
public Vector3f position() {
return position;
}
public Vector3f size() {
return size;
}
@@ -50,19 +46,24 @@ public class InteractionHitBox extends AbstractHitBox {
}
@Override
public void addSpawnPackets(int entityId, double x, double y, double z, float yaw, Consumer<Object> packets) {
public void addSpawnPackets(int[] entityId, double x, double y, double z, float yaw, Consumer<Object> packets) {
Vector3f offset = QuaternionUtils.toQuaternionf(0f, Math.toRadians(180f - yaw), 0f).conjugate().transform(new Vector3f(position()));
try {
packets.accept(Reflections.constructor$ClientboundAddEntityPacket.newInstance(
entityId, UUID.randomUUID(), x + offset.x, y + offset.y, z - offset.z, 0, yaw,
entityId[0], UUID.randomUUID(), x + offset.x, y + offset.y, z - offset.z, 0, yaw,
Reflections.instance$EntityType$INTERACTION, 0, Reflections.instance$Vec3$Zero, 0
));
packets.accept(Reflections.constructor$ClientboundSetEntityDataPacket.newInstance(entityId, List.copyOf(this.cachedValues)));
packets.accept(Reflections.constructor$ClientboundSetEntityDataPacket.newInstance(entityId[0], List.copyOf(this.cachedValues)));
} catch (ReflectiveOperationException e) {
throw new RuntimeException("Failed to construct hitbox spawn packet", e);
}
}
@Override
public int[] acquireEntityIds(Supplier<Integer> entityIdSupplier) {
return new int[] {entityIdSupplier.get()};
}
public static class Factory implements HitBoxFactory {
@Override

View File

@@ -26,21 +26,18 @@ public class LoadedFurniture {
private final Key id;
private final CustomFurniture furniture;
private final AnchorType anchorType;
private final Map<Integer, FurnitureElement> elements;
private final Map<Integer, HitBox> hitBoxes;
// location
private Location location;
// base entity
private final WeakReference<Entity> baseEntity;
private final int baseEntityId;
// includes elements + interactions
private final List<Integer> subEntityIds;
// interactions
private final List<Integer> interactionEntityIds;
// cache
private final List<Integer> fakeEntityIds;
private final List<Integer> hitBoxEntityIds;
private final Map<Integer, HitBox> hitBoxes;
// seats
private final Set<Vector3f> occupiedSeats = Collections.synchronizedSet(new HashSet<>());
private final Vector<Entity> seats = new Vector<>();
// cached spawn packet
private Object cachedSpawnPacket;
@@ -54,40 +51,36 @@ public class LoadedFurniture {
this.baseEntity = new WeakReference<>(baseEntity);
this.furniture = furniture;
this.hitBoxes = new HashMap<>();
this.elements = new HashMap<>();
List<Integer> entityIds = new ArrayList<>();
List<Integer> fakeEntityIds = new ArrayList<>();
List<Integer> hitBoxEntityIds = new ArrayList<>();
CustomFurniture.Placement placement = furniture.getPlacement(anchorType);
List<Object> packets = new ArrayList<>();
for (FurnitureElement element : placement.elements()) {
int entityId = Reflections.instance$Entity$ENTITY_COUNTER.incrementAndGet();
entityIds.add(entityId);
this.elements.put(entityId, element);
fakeEntityIds.add(entityId);
element.addSpawnPackets(entityId, this.location.getX(), this.location.getY(), this.location.getZ(), this.location.getYaw(), packets::add);
}
for (HitBox hitBox : placement.hitboxes()) {
int entityId = Reflections.instance$Entity$ENTITY_COUNTER.incrementAndGet();
entityIds.add(entityId);
hitBoxEntityIds.add(entityId);
this.hitBoxes.put(entityId, hitBox);
}
this.subEntityIds = entityIds;
this.interactionEntityIds = hitBoxEntityIds;
}
public synchronized Object spawnPacket() {
if (this.cachedSpawnPacket == null) {
try {
List<Object> packets = new ArrayList<>();
for (Map.Entry<Integer, FurnitureElement> entry : this.elements.entrySet()) {
entry.getValue().addSpawnPackets(entry.getKey(), this.location.getX(), this.location.getY(), this.location.getZ(), this.location.getYaw(), packets::add);
}
for (Map.Entry<Integer, HitBox> entry : this.hitBoxes.entrySet()) {
entry.getValue().addSpawnPackets(entry.getKey(), this.location.getX(), this.location.getY(), this.location.getZ(), this.location.getYaw(), packets::add);
}
this.cachedSpawnPacket = Reflections.constructor$ClientboundBundlePacket.newInstance(packets);
} catch (Exception e) {
CraftEngine.instance().logger().warn("Failed to init spawn packets for furniture " + id, e);
int[] ids = hitBox.acquireEntityIds(Reflections.instance$Entity$ENTITY_COUNTER::incrementAndGet);
for (int entityId : ids) {
fakeEntityIds.add(entityId);
hitBoxEntityIds.add(entityId);
hitBox.addSpawnPackets(ids, this.location.getX(), this.location.getY(), this.location.getZ(), this.location.getYaw(), packets::add);
this.hitBoxes.put(entityId, hitBox);
}
}
try {
this.cachedSpawnPacket = Reflections.constructor$ClientboundBundlePacket.newInstance(packets);
} catch (Exception e) {
CraftEngine.instance().logger().warn("Failed to init spawn packets for furniture " + id, e);
}
this.fakeEntityIds = fakeEntityIds;
this.hitBoxEntityIds = hitBoxEntityIds;
}
@NotNull
public Object spawnPacket() {
return this.cachedSpawnPacket;
}
@@ -178,27 +171,32 @@ public class LoadedFurniture {
}
public int baseEntityId() {
return baseEntityId;
return this.baseEntityId;
}
public List<Integer> interactionEntityIds() {
return interactionEntityIds;
@NotNull
public List<Integer> hitBoxEntityIds() {
return this.hitBoxEntityIds;
}
@NotNull
public List<Integer> subEntityIds() {
return this.subEntityIds;
return this.fakeEntityIds;
}
@NotNull
public AnchorType anchorType() {
return anchorType;
return this.anchorType;
}
@NotNull
public Key furnitureId() {
return id;
return this.id;
}
@NotNull
public CustomFurniture furniture() {
return furniture;
return this.furniture;
}
public void mountSeat(org.bukkit.entity.Player player, Seat seat) {

View File

@@ -0,0 +1,76 @@
package net.momirealms.craftengine.bukkit.entity.furniture;
import net.momirealms.craftengine.core.entity.furniture.*;
import net.momirealms.craftengine.core.util.Direction;
import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.core.util.MiscUtils;
import org.joml.Vector3f;
import java.util.Locale;
import java.util.Map;
import java.util.Optional;
import java.util.function.Consumer;
import java.util.function.Supplier;
public class ShulkerHitBox extends AbstractHitBox {
public static final Factory FACTORY = new Factory();
// 1.20.6+
private final double scale;
private final byte peek;
// todo或许还能做个方向但是会麻烦点和 yaw 有关
private final Direction direction;
public ShulkerHitBox(Seat[] seats, Vector3f position, double scale, byte peek, Direction direction) {
super(seats, position);
this.scale = scale;
this.peek = peek;
this.direction = direction;
}
public Direction direction() {
return direction;
}
public byte peek() {
return peek;
}
public double scale() {
return scale;
}
@Override
public Key type() {
return HitBoxTypes.SHULKER;
}
@Override
public void addSpawnPackets(int[] entityIds, double x, double y, double z, float yaw, Consumer<Object> packets) {
// 1.生成假的展示实体
// 2.生成假的潜影贝
// 3.潜影贝骑展示实体
// 4.潜影贝数据设置隐身尺寸peek方向
}
@Override
public int[] acquireEntityIds(Supplier<Integer> entityIdSupplier) {
// 展示实体 // 潜影贝
return new int[] {entityIdSupplier.get(), entityIdSupplier.get()};
}
public static class Factory implements HitBoxFactory {
@Override
public HitBox create(Map<String, Object> arguments) {
Vector3f position = MiscUtils.getVector3f(arguments.getOrDefault("position", "0"));
double scale = MiscUtils.getAsDouble(arguments.getOrDefault("scale", "1"));
byte peek = (byte) MiscUtils.getAsInt(arguments.getOrDefault("peek", 0));
Direction directionEnum = Optional.ofNullable(arguments.get("direction")).map(it -> Direction.valueOf(it.toString().toUpperCase(Locale.ENGLISH))).orElse(Direction.UP);
return new ShulkerHitBox(
HitBoxFactory.getSeats(arguments),
position,
scale, peek, directionEnum
);
}
}
}

View File

@@ -69,7 +69,7 @@ public class ItemEventListener implements Listener {
block,
event.getBlockFace(),
event.getHand() == EquipmentSlot.HAND ? InteractionHand.MAIN_HAND : InteractionHand.OFF_HAND,
action == Action.RIGHT_CLICK_BLOCK ? CustomBlockInteractEvent.Action.RIGHT_CLICK : CustomBlockInteractEvent.Action.LEFT_CLICK
action.isRightClick() ? CustomBlockInteractEvent.Action.RIGHT_CLICK : CustomBlockInteractEvent.Action.LEFT_CLICK
);
if (EventUtils.fireAndCheckCancel(interactEvent)) {
event.setCancelled(true);