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:
@@ -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());
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user