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

完善collider

This commit is contained in:
XiaoMoMi
2025-04-01 01:49:31 +08:00
parent f9ab8ea66a
commit a8bbf2d556
6 changed files with 121 additions and 45 deletions

View File

@@ -130,16 +130,6 @@ public class BukkitFurnitureManager implements FurnitureManager {
elements.add(furnitureElement);
}
// add hitboxes
List<Map<String, Object>> hitboxConfigs = (List<Map<String, Object>>) placementArguments.getOrDefault("hitboxes", List.of());
List<HitBox> hitboxes = new ArrayList<>();
for (Map<String, Object> config : hitboxConfigs) {
hitboxes.add(HitBoxTypes.fromMap(config));
}
if (hitboxes.isEmpty()) {
hitboxes.add(InteractionHitBox.DEFAULT);
}
// add colliders
List<Map<String, Object>> colliderConfigs = (List<Map<String, Object>>) placementArguments.getOrDefault("colliders", List.of());
List<Collider> colliders = new ArrayList<>();
@@ -147,8 +137,8 @@ public class BukkitFurnitureManager implements FurnitureManager {
if (!config.containsKey("position")) {
colliders.add(new Collider(
(boolean) config.getOrDefault("can-be-hit-by-projectile", false),
MiscUtils.getVector3f(config.getOrDefault("point-1", "0")),
MiscUtils.getVector3f(config.getOrDefault("point-2", "0"))
MiscUtils.getVector3d(config.getOrDefault("point-1", "0")),
MiscUtils.getVector3d(config.getOrDefault("point-2", "0"))
));
} else {
colliders.add(new Collider(
@@ -160,6 +150,18 @@ public class BukkitFurnitureManager implements FurnitureManager {
}
}
// add hitboxes
List<Map<String, Object>> hitboxConfigs = (List<Map<String, Object>>) placementArguments.getOrDefault("hitboxes", List.of());
List<HitBox> hitboxes = new ArrayList<>();
for (Map<String, Object> config : hitboxConfigs) {
HitBox hitBox = HitBoxTypes.fromMap(config);
hitboxes.add(hitBox);
hitBox.optionCollider().ifPresent(colliders::add);
}
if (hitboxes.isEmpty()) {
hitboxes.add(InteractionHitBox.DEFAULT);
}
// rules
Map<String, Object> ruleSection = MiscUtils.castToMap(placementArguments.get("rules"), true);
if (ruleSection != null) {
@@ -276,6 +278,10 @@ public class BukkitFurnitureManager implements FurnitureManager {
CustomFurniture customFurniture = optionalFurniture.get();
LoadedFurniture previous = this.furnitureByBaseEntityId.get(display.getEntityId());
if (previous != null) return;
Location location = entity.getLocation();
if (FastNMS.INSTANCE.isPreventingStatusUpdates(location.getWorld(), location.getBlockX() >> 4, location.getBlockZ() >> 4)) {
return;
}
LoadedFurniture furniture = addNewFurniture(display, customFurniture, getAnchorType(entity, customFurniture));
for (Player player : display.getTrackedPlayers()) {
this.plugin.adapt(player).furnitureView().computeIfAbsent(furniture.baseEntityId(), k -> new ArrayList<>()).addAll(furniture.subEntityIds());

View File

@@ -20,6 +20,7 @@ import org.bukkit.entity.ItemDisplay;
import org.bukkit.persistence.PersistentDataType;
import org.jetbrains.annotations.NotNull;
import org.joml.Quaternionf;
import org.joml.Vector3d;
import org.joml.Vector3f;
import java.lang.ref.WeakReference;
@@ -34,6 +35,8 @@ public class LoadedFurniture {
// base entity
private final WeakReference<Entity> baseEntity;
private final int baseEntityId;
// colliders
private final CollisionEntity[] collisionEntities;
// cache
private final List<Integer> fakeEntityIds;
private final List<Integer> hitBoxEntityIds;
@@ -88,12 +91,14 @@ public class LoadedFurniture {
}
this.fakeEntityIds = fakeEntityIds;
this.hitBoxEntityIds = hitBoxEntityIds;
if (placement.colliders().length != 0) {
int colliderSize = placement.colliders().length;
this.collisionEntities = new CollisionEntity[colliderSize];
if (colliderSize != 0) {
Object world = FastNMS.INSTANCE.field$CraftWorld$ServerLevel(this.location.getWorld());
for (Collider collider : placement.colliders()) {
Vector3f offset1 = conjugated.transform(new Vector3f(collider.point1()));
Vector3f offset2 = conjugated.transform(new Vector3f(collider.point2()));
for (int i = 0; i < colliderSize; i++) {
Collider collider = placement.colliders()[i];
Vector3d offset1 = conjugated.transform(new Vector3d(collider.point1()));
Vector3d offset2 = conjugated.transform(new Vector3d(collider.point2()));
double x1 = x + offset1.x();
double x2 = x + offset2.x();
double y1 = y + offset1.y();
@@ -103,6 +108,7 @@ public class LoadedFurniture {
Object aabb = FastNMS.INSTANCE.constructor$AABB(x1, y1, z1, x2, y2, z2);
CollisionEntity entity = FastNMS.INSTANCE.createCollisionEntity(world, aabb, x, y, z, true, collider.canBeHitByProjectile());
FastNMS.INSTANCE.method$LevelWriter$addFreshEntity(world, entity);
this.collisionEntities[i] = entity;
}
}
}
@@ -135,6 +141,10 @@ public class LoadedFurniture {
return;
}
this.baseEntity().remove();
for (CollisionEntity entity : this.collisionEntities) {
if (entity != null)
entity.destroy();
}
for (Entity entity : this.seats) {
for (Entity passenger : entity.getPassengers()) {
entity.removePassenger(passenger);

View File

@@ -1,5 +1,6 @@
package net.momirealms.craftengine.bukkit.entity.furniture.hitbox;
import net.momirealms.craftengine.bukkit.entity.data.InteractionEntityData;
import net.momirealms.craftengine.bukkit.entity.data.ShulkerData;
import net.momirealms.craftengine.bukkit.nms.FastNMS;
import net.momirealms.craftengine.bukkit.util.DirectionUtils;
@@ -21,15 +22,54 @@ public class ShulkerHitBox extends AbstractHitBox {
// 1.20.6+
private final double scale;
private final byte peek;
private final boolean interactive;
private final boolean interactionEntity;
// todo或许还能做个方向但是会麻烦点和 yaw 有关
private final Direction direction;
private List<Object> cachedValues;
private final Direction direction = Direction.UP;
private final List<Object> cachedShulkerValues = new ArrayList<>();
private final List<Object> cachedInteractionValues = new ArrayList<>();
public ShulkerHitBox(Seat[] seats, Vector3f position, double scale, byte peek, Direction direction) {
public ShulkerHitBox(Seat[] seats, Vector3f position, double scale, byte peek, boolean interactionEntity, boolean interactive) {
super(seats, position);
this.scale = scale;
this.peek = peek;
this.direction = direction;
this.interactive = interactive;
this.interactionEntity = interactionEntity;
ShulkerData.Peek.addEntityDataIfNotDefaultValue(peek, this.cachedShulkerValues);
// ShulkerData.AttachFace.addEntityDataIfNotDefaultValue(DirectionUtils.toNMSDirection(direction), this.cachedShulkerValues);
ShulkerData.NoGravity.addEntityDataIfNotDefaultValue(true, this.cachedShulkerValues);
ShulkerData.Silent.addEntityDataIfNotDefaultValue(true, this.cachedShulkerValues);
ShulkerData.MobFlags.addEntityDataIfNotDefaultValue((byte) 0x01, this.cachedShulkerValues); // 无ai
ShulkerData.SharedFlags.addEntityDataIfNotDefaultValue((byte) 0x20, this.cachedShulkerValues); // 不可见
if (this.interactionEntity) {
InteractionEntityData.Height.addEntityDataIfNotDefaultValue((float) ((1 + getPeekHeight(peek)) * scale) + 0.001f, cachedInteractionValues);
InteractionEntityData.Width.addEntityDataIfNotDefaultValue((float) scale + 0.001f, cachedInteractionValues);
InteractionEntityData.Responsive.addEntityDataIfNotDefaultValue(interactive, cachedInteractionValues);
}
}
@Override
public Optional<Collider> optionCollider() {
return Optional.of(new Collider(
true,
position(),
(float) scale(),
1 + getPeekHeight(peek())
));
}
private static float getPeekHeight(byte peek) {
return (float) (0.5F - Math.sin((0.5F + peek * 0.01F) * 3.1415927F) * 0.5F);
}
public boolean interactionEntity() {
return interactionEntity;
}
public boolean interactive() {
return interactive;
}
public Direction direction() {
@@ -61,35 +101,34 @@ public class ShulkerHitBox extends AbstractHitBox {
entityIds[1], UUID.randomUUID(), x + offset.x, y + offset.y, z - offset.z, 0, yaw,
Reflections.instance$EntityType$SHULKER, 0, Reflections.instance$Vec3$Zero, 0
));
packets.accept(Reflections.constructor$ClientboundSetEntityDataPacket.newInstance(entityIds[1], getCachedValues()));
packets.accept(Reflections.constructor$ClientboundSetEntityDataPacket.newInstance(entityIds[1], List.copyOf(this.cachedShulkerValues)));
packets.accept(FastNMS.INSTANCE.constructor$ClientboundSetPassengersPacket(entityIds[0], entityIds[1]));
if (VersionHelper.isVersionNewerThan1_20_5()) {
Object attributeInstance = Reflections.constructor$AttributeInstance.newInstance(Reflections.instance$Holder$Attribute$scale, (Consumer<?>) (o) -> {});
Reflections.method$AttributeInstance$setBaseValue.invoke(attributeInstance, scale);
packets.accept(Reflections.constructor$ClientboundUpdateAttributesPacket0.newInstance(entityIds[1], Collections.singletonList(attributeInstance)));
}
if (this.interactionEntity) {
packets.accept(Reflections.constructor$ClientboundAddEntityPacket.newInstance(
entityIds[2], UUID.randomUUID(), x + offset.x, y + offset.y - 0.0005f, z - offset.z, 0, yaw,
Reflections.instance$EntityType$INTERACTION, 0, Reflections.instance$Vec3$Zero, 0
));
packets.accept(Reflections.constructor$ClientboundSetEntityDataPacket.newInstance(entityIds[2], List.copyOf(this.cachedInteractionValues)));
}
} catch (ReflectiveOperationException e) {
throw new RuntimeException("Failed to construct shulker hitbox spawn packet", e);
}
}
private synchronized List<Object> getCachedValues() {
if (this.cachedValues == null) {
this.cachedValues = new ArrayList<>();
ShulkerData.Peek.addEntityDataIfNotDefaultValue(peek, this.cachedValues);
ShulkerData.AttachFace.addEntityDataIfNotDefaultValue(DirectionUtils.toNMSDirection(direction), this.cachedValues);
ShulkerData.NoGravity.addEntityDataIfNotDefaultValue(true, this.cachedValues);
ShulkerData.Silent.addEntityDataIfNotDefaultValue(true, this.cachedValues);
ShulkerData.MobFlags.addEntityDataIfNotDefaultValue((byte) 0x01, this.cachedValues); // 无ai
ShulkerData.SharedFlags.addEntityDataIfNotDefaultValue((byte) 0x20, this.cachedValues); // 不可见
}
return this.cachedValues;
}
@Override
public int[] acquireEntityIds(Supplier<Integer> entityIdSupplier) {
// 展示实体 // 潜影贝
return new int[] {entityIdSupplier.get(), entityIdSupplier.get()};
if (this.interactionEntity) {
// 展示实体 // 潜影贝 // 交互实体
return new int[] {entityIdSupplier.get(), entityIdSupplier.get(), entityIdSupplier.get()};
} else {
// 展示实体 // 潜影贝
return new int[] {entityIdSupplier.get(), entityIdSupplier.get()};
}
}
public static class Factory implements HitBoxFactory {
@@ -100,10 +139,12 @@ public class ShulkerHitBox extends AbstractHitBox {
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);
boolean interactive = (boolean) arguments.getOrDefault("interactive", true);
boolean interactionEntity = (boolean) arguments.getOrDefault("interaction-entity", true);
return new ShulkerHitBox(
HitBoxFactory.getSeats(arguments),
position,
scale, peek, directionEnum
scale, peek, interactionEntity, interactive
);
}
}