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-12-04 22:16:12 +08:00
parent be84b0292a
commit af592e4287
10 changed files with 191 additions and 53 deletions

View File

@@ -31,6 +31,7 @@ import net.momirealms.craftengine.core.world.WorldPosition;
import net.momirealms.craftengine.core.world.collision.AABB; import net.momirealms.craftengine.core.world.collision.AABB;
import net.momirealms.sparrow.nbt.CompoundTag; import net.momirealms.sparrow.nbt.CompoundTag;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.Particle;
import org.bukkit.World; import org.bukkit.World;
import java.nio.file.Path; import java.nio.file.Path;
@@ -119,6 +120,9 @@ public class FurnitureItemBehavior extends ItemBehavior {
// 检查方块、实体阻挡 // 检查方块、实体阻挡
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())) { 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())) {
if (player != null && player.enableFurnitureDebug() && VersionHelper.isPaper()) {
// bukkitPlayer.getWorld().spawnParticle(Particle.FLAME, , List.of(bukkitPlayer), );
}
return InteractionResult.FAIL; return InteractionResult.FAIL;
} }
} }

View File

@@ -30,11 +30,11 @@ public class SetEntityViewDistanceScaleCommand extends BukkitCommandFeature<Comm
.required("scale", DoubleParser.doubleParser(0.125, 8)) .required("scale", DoubleParser.doubleParser(0.125, 8))
.handler(context -> { .handler(context -> {
if (!Config.enableEntityCulling()) { if (!Config.enableEntityCulling()) {
context.sender().sendMessage(Component.text("Entity culling is not enabled on this server").color(NamedTextColor.RED)); plugin().senderFactory().wrap(context.sender()).sendMessage(Component.text("Entity culling is not enabled on this server").color(NamedTextColor.RED));
return; return;
} }
if (Config.entityCullingViewDistance() <= 0) { if (Config.entityCullingViewDistance() <= 0) {
context.sender().sendMessage(Component.text("View distance is not enabled on this server").color(NamedTextColor.RED)); plugin().senderFactory().wrap(context.sender()).sendMessage(Component.text("View distance is not enabled on this server").color(NamedTextColor.RED));
return; return;
} }
Player player = context.get("player"); Player player = context.get("player");

View File

@@ -32,7 +32,7 @@ public class ToggleEntityCullingCommand extends BukkitCommandFeature<CommandSend
.optional("state", BooleanParser.booleanParser()) .optional("state", BooleanParser.booleanParser())
.handler(context -> { .handler(context -> {
if (!Config.enableEntityCulling()) { if (!Config.enableEntityCulling()) {
context.sender().sendMessage(Component.text("Entity culling is not enabled on this server").color(NamedTextColor.RED)); plugin().senderFactory().wrap(context.sender()).sendMessage(Component.text("Entity culling is not enabled on this server").color(NamedTextColor.RED));
return; return;
} }
Player player = context.get("player"); Player player = context.get("player");

View File

@@ -1,5 +1,6 @@
package net.momirealms.craftengine.bukkit.plugin.network; package net.momirealms.craftengine.bukkit.plugin.network;
import com.destroystokyo.paper.ParticleBuilder;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import com.google.common.collect.Sets; import com.google.common.collect.Sets;
import com.google.gson.JsonElement; import com.google.gson.JsonElement;

View File

@@ -1480,6 +1480,14 @@ public class BukkitServerPlayer extends Player {
return LocationUtils.toWorldPosition(this.getEyeLocation()); return LocationUtils.toWorldPosition(this.getEyeLocation());
} }
@Override
public void playParticle(Key particleId, double x, double y, double z) {
Particle particle = Registry.PARTICLE_TYPE.get(KeyUtils.toNamespacedKey(particleId));
if (particle != null) {
platformPlayer().getWorld().spawnParticle(particle, List.of(platformPlayer()), null, x, y, z, 1, 0, 0,0, 0, null, false);
}
}
public Location getEyeLocation() { public Location getEyeLocation() {
org.bukkit.entity.Player player = platformPlayer(); org.bukkit.entity.Player player = platformPlayer();
Location eyeLocation = player.getEyeLocation(); Location eyeLocation = player.getEyeLocation();

View File

@@ -146,28 +146,9 @@ public abstract class AbstractFurnitureManager implements FurnitureManager {
hitboxes = List.of(defaultHitBox()); hitboxes = List.of(defaultHitBox());
} }
List<AABB> aabbs = new ArrayList<>();
for (FurnitureHitBoxConfig<?> hitBox : hitboxes) {
hitBox.collectBoundingBox(aabbs::add);
}
double minX = 0;
double minY = 0;
double minZ = 0;
double maxX = 0;
double maxY = 0;
double maxZ = 0;
for (AABB aabb : aabbs) {
minX = Math.min(minX, aabb.minX);
minY = Math.min(minY, aabb.minY);
minZ = Math.min(minZ, aabb.minZ);
maxX = Math.max(maxX, aabb.maxX);
maxY = Math.max(maxY, aabb.maxY);
maxZ = Math.max(maxZ, aabb.maxZ);
}
AABB maxAABB = new AABB(minX, minY, minZ, maxX, maxY, maxZ);
variants.put(variantName, new FurnitureVariant( variants.put(variantName, new FurnitureVariant(
variantName, variantName,
parseCullingData(section.get("entity-culling"), maxAABB), parseCullingData(section.get("entity-culling")),
elements.toArray(new FurnitureElementConfig[0]), elements.toArray(new FurnitureElementConfig[0]),
hitboxes.toArray(new FurnitureHitBoxConfig[0]), hitboxes.toArray(new FurnitureHitBoxConfig[0]),
externalModel, externalModel,
@@ -185,16 +166,18 @@ public abstract class AbstractFurnitureManager implements FurnitureManager {
AbstractFurnitureManager.this.byId.put(id, furniture); AbstractFurnitureManager.this.byId.put(id, furniture);
} }
private CullingData parseCullingData(Object arguments, AABB maxHitbox) {
private CullingData parseCullingData(Object arguments) {
if (arguments instanceof Boolean b && !b) if (arguments instanceof Boolean b && !b)
return null; return null;
if (!(arguments instanceof Map)) if (!(arguments instanceof Map))
return new CullingData(maxHitbox, Config.entityCullingViewDistance(), 0.5, true); return new CullingData(null, Config.entityCullingViewDistance(), 0.25, true);
Map<String, Object> argumentsMap = ResourceConfigUtils.getAsMap(arguments, "entity-culling"); Map<String, Object> argumentsMap = ResourceConfigUtils.getAsMap(arguments, "entity-culling");
return new CullingData( return new CullingData(
ResourceConfigUtils.getAsAABB(argumentsMap.getOrDefault("aabb", maxHitbox), "aabb"), ResourceConfigUtils.getOrDefault(argumentsMap.get("aabb"), it -> ResourceConfigUtils.getAsAABB(it, "aabb"), null),
ResourceConfigUtils.getAsInt(argumentsMap.getOrDefault("view-distance", Config.entityCullingViewDistance()), "view-distance"), ResourceConfigUtils.getAsInt(argumentsMap.getOrDefault("view-distance", Config.entityCullingViewDistance()), "view-distance"),
ResourceConfigUtils.getAsDouble(argumentsMap.getOrDefault("aabb-expansion", 0.5), "aabb-expansion"), ResourceConfigUtils.getAsDouble(argumentsMap.getOrDefault("aabb-expansion", 0.25), "aabb-expansion"),
ResourceConfigUtils.getAsBoolean(argumentsMap.getOrDefault("ray-tracing", true), "ray-tracing") ResourceConfigUtils.getAsBoolean(argumentsMap.getOrDefault("ray-tracing", true), "ray-tracing")
); );
} }

View File

@@ -23,10 +23,13 @@ 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;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.joml.Quaternionf; import org.joml.Quaternionf;
import org.joml.Vector3f; import org.joml.Vector3f;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.UUID; import java.util.UUID;
@@ -109,9 +112,62 @@ public abstract class Furniture implements Cullable {
if (parent == null) return null; if (parent == null) return null;
AABB aabb = parent.aabb; AABB aabb = parent.aabb;
WorldPosition position = position(); WorldPosition position = position();
Vec3d pos1 = getRelativePosition(position, new Vector3f((float) aabb.minX, (float) aabb.minY, (float) aabb.minZ)); if (aabb == null) {
Vec3d pos2 = getRelativePosition(position, new Vector3f((float) aabb.maxX, (float) aabb.maxY, (float) aabb.maxZ)); List<AABB> aabbs = new ArrayList<>();
return new CullingData(new AABB(pos1.x, pos1.y, pos1.z, pos2.x, pos2.y, pos2.z), parent.maxDistance, parent.aabbExpansion, parent.rayTracing); for (FurnitureHitBoxConfig<?> hitBoxConfig : this.currentVariant.hitBoxConfigs()) {
hitBoxConfig.prepareForPlacement(position, aabbs::add);
}
return new CullingData(getMaxAABB(aabbs), parent.maxDistance, parent.aabbExpansion, parent.rayTracing);
} else {
Vector3f[] vertices = new Vector3f[] {
// 底面两个对角点
new Vector3f((float) aabb.minX, (float) aabb.minY, (float) aabb.minZ),
new Vector3f((float) aabb.maxX, (float) aabb.minY, (float) aabb.maxZ),
// 顶面两个对角点
new Vector3f((float) aabb.minX, (float) aabb.maxY, (float) aabb.minZ),
new Vector3f((float) aabb.maxX, (float) aabb.maxY, (float) aabb.maxZ)
};
double minX = Double.MAX_VALUE, minY = aabb.minY; // Y方向不变
double maxX = -Double.MAX_VALUE, maxY = aabb.maxY; // Y方向不变
double minZ = Double.MAX_VALUE, maxZ = -Double.MAX_VALUE;
for (Vector3f vertex : vertices) {
Vec3d rotatedPos = getRelativePosition(position, vertex);
minX = Math.min(minX, rotatedPos.x);
minZ = Math.min(minZ, rotatedPos.z);
maxX = Math.max(maxX, rotatedPos.x);
maxZ = Math.max(maxZ, rotatedPos.z);
}
return new CullingData(new AABB(minX, minY, minZ, maxX, maxY, maxZ),
parent.maxDistance, parent.aabbExpansion, parent.rayTracing);
}
}
private static @NotNull AABB getMaxAABB(List<AABB> aabbs) {
double minX = 0;
double minY = 0;
double minZ = 0;
double maxX = 0;
double maxY = 0;
double maxZ = 0;
for (int i = 0; i < aabbs.size(); i++) {
AABB aabb = aabbs.get(i);
if (i == 0) {
minX = aabb.minX;
minY = aabb.minY;
minZ = aabb.minZ;
maxX = aabb.maxX;
maxY = aabb.maxY;
maxZ = aabb.maxZ;
} else {
minX = Math.min(minX, aabb.minX);
minY = Math.min(minY, aabb.minY);
minZ = Math.min(minZ, aabb.minZ);
maxX = Math.max(maxX, aabb.maxX);
maxY = Math.max(maxY, aabb.maxY);
maxZ = Math.max(maxZ, aabb.maxZ);
}
}
return new AABB(minX, minY, minZ, maxX, maxY, maxZ);
} }
@Nullable @Nullable

View File

@@ -230,6 +230,8 @@ public abstract class Player extends AbstractEntity implements NetWorkUser {
public void remove() { public void remove() {
} }
public abstract void playParticle(Key particleId, double x, double y, double z);
public abstract void removeTrackedFurniture(int entityId); public abstract void removeTrackedFurniture(int entityId);
public abstract void clearTrackedFurniture(); public abstract void clearTrackedFurniture();

View File

@@ -2,6 +2,7 @@ package net.momirealms.craftengine.core.plugin.entityculling;
import net.momirealms.craftengine.core.entity.player.Player; import net.momirealms.craftengine.core.entity.player.Player;
import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.plugin.config.Config;
import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.core.util.MiscUtils; import net.momirealms.craftengine.core.util.MiscUtils;
import net.momirealms.craftengine.core.world.ChunkPos; import net.momirealms.craftengine.core.world.ChunkPos;
import net.momirealms.craftengine.core.world.MutableVec3d; import net.momirealms.craftengine.core.world.MutableVec3d;
@@ -59,13 +60,12 @@ public final class EntityCulling {
AABB aabb = cullable.aabb; AABB aabb = cullable.aabb;
double aabbExpansion = cullable.aabbExpansion; double aabbExpansion = cullable.aabbExpansion;
// 根据AABB获取能包裹此AABB的最小长方体 double minX = aabb.minX - aabbExpansion;
int minX = MiscUtils.floor(aabb.minX - aabbExpansion); double minY = aabb.minY - aabbExpansion;
int minY = MiscUtils.floor(aabb.minY - aabbExpansion); double minZ = aabb.minZ - aabbExpansion;
int minZ = MiscUtils.floor(aabb.minZ - aabbExpansion); double maxX = aabb.maxX + aabbExpansion;
int maxX = MiscUtils.ceil(aabb.maxX + aabbExpansion); double maxY = aabb.maxY + aabbExpansion;
int maxY = MiscUtils.ceil(aabb.maxY + aabbExpansion); double maxZ = aabb.maxZ + aabbExpansion;
int maxZ = MiscUtils.ceil(aabb.maxZ + aabbExpansion);
double cameraX = cameraPos.x; double cameraX = cameraPos.x;
double cameraY = cameraPos.y; double cameraY = cameraPos.y;
@@ -95,6 +95,10 @@ public final class EntityCulling {
if (distanceSq > maxDistanceSq) { if (distanceSq > maxDistanceSq) {
return false; return false;
} }
// 太近了,不剔除
else if (distanceSq < 1) {
return true;
}
} }
if (!rayTracing || !cullable.rayTracing) { if (!rayTracing || !cullable.rayTracing) {
@@ -120,25 +124,31 @@ public final class EntityCulling {
} }
int size = 0; int size = 0;
if (this.dotSelectors[0]) targetPoints[size++].set(minX + 0.05, minY + 0.05, minZ + 0.05); if (this.dotSelectors[0]) targetPoints[size++].set(minX, minY, minZ);
if (this.dotSelectors[1]) targetPoints[size++].set(maxX - 0.05, minY + 0.05, minZ + 0.05); if (this.dotSelectors[1]) targetPoints[size++].set(maxX, minY, minZ);
if (this.dotSelectors[2]) targetPoints[size++].set(minX + 0.05, minY + 0.05, maxZ - 0.05); if (this.dotSelectors[2]) targetPoints[size++].set(minX, minY, maxZ);
if (this.dotSelectors[3]) targetPoints[size++].set(maxX - 0.05, minY + 0.05, maxZ - 0.05); if (this.dotSelectors[3]) targetPoints[size++].set(maxX, minY, maxZ);
if (this.dotSelectors[4]) targetPoints[size++].set(minX + 0.05, maxY - 0.05, minZ + 0.05); if (this.dotSelectors[4]) targetPoints[size++].set(minX, maxY, minZ);
if (this.dotSelectors[5]) targetPoints[size++].set(maxX - 0.05, maxY - 0.05, minZ + 0.05); if (this.dotSelectors[5]) targetPoints[size++].set(maxX, maxY, minZ);
if (this.dotSelectors[6]) targetPoints[size++].set(minX + 0.05, maxY - 0.05, maxZ - 0.05); if (this.dotSelectors[6]) targetPoints[size++].set(minX, maxY, maxZ);
if (this.dotSelectors[7]) targetPoints[size++].set(maxX - 0.05, maxY - 0.05, maxZ - 0.05); if (this.dotSelectors[7]) targetPoints[size++].set(maxX, maxY, maxZ);
// 面中心点 // 面中心点
double averageX = (minX + maxX) / 2.0; double averageX = (minX + maxX) / 2.0;
double averageY = (minY + maxY) / 2.0; double averageY = (minY + maxY) / 2.0;
double averageZ = (minZ + maxZ) / 2.0; double averageZ = (minZ + maxZ) / 2.0;
if (this.dotSelectors[8]) targetPoints[size++].set(averageX, averageY, minZ + 0.05); if (this.dotSelectors[8]) targetPoints[size++].set(averageX, averageY, minZ);
if (this.dotSelectors[9]) targetPoints[size++].set(averageX, averageY, maxZ - 0.05); if (this.dotSelectors[9]) targetPoints[size++].set(averageX, averageY, maxZ);
if (this.dotSelectors[10]) targetPoints[size++].set(minX + 0.05, averageY, averageZ); if (this.dotSelectors[10]) targetPoints[size++].set(minX, averageY, averageZ);
if (this.dotSelectors[11]) targetPoints[size++].set(maxX - 0.05, averageY, averageZ); if (this.dotSelectors[11]) targetPoints[size++].set(maxX, averageY, averageZ);
if (this.dotSelectors[12]) targetPoints[size++].set(averageX, minY + 0.05, averageZ); if (this.dotSelectors[12]) targetPoints[size++].set(averageX, minY, averageZ);
if (this.dotSelectors[13]) targetPoints[size].set(averageX, maxY - 0.05, averageZ); if (this.dotSelectors[13]) targetPoints[size++].set(averageX, maxY, averageZ);
// if (Config.debugEntityCulling()) {
// for (int i = 0; i < size; i++) {
// MutableVec3d targetPoint = this.targetPoints[i];
// this.player.playParticle(Key.of("flame"), targetPoint.x, targetPoint.y, targetPoint.z);
// }
// }
return isVisible(cameraPos, this.targetPoints, size); return isVisible(cameraPos, this.targetPoints, size);
} }
@@ -356,7 +366,7 @@ public final class EntityCulling {
return deltaX + 32 * deltaY + 32 * 32 * deltaZ; return deltaX + 32 * deltaY + 32 * 32 * deltaZ;
} }
private double distanceSq(int min, int max, double camera, Relative rel) { private double distanceSq(double min, double max, double camera, Relative rel) {
if (rel == Relative.NEGATIVE) { if (rel == Relative.NEGATIVE) {
double dx = camera - max; double dx = camera - max;
return dx * dx; return dx * dx;
@@ -394,7 +404,7 @@ public final class EntityCulling {
private enum Relative { private enum Relative {
INSIDE, POSITIVE, NEGATIVE; INSIDE, POSITIVE, NEGATIVE;
public static Relative from(int min, int max, double pos) { public static Relative from(double min, double max, double pos) {
if (min > pos) return POSITIVE; if (min > pos) return POSITIVE;
else if (max < pos) return NEGATIVE; else if (max < pos) return NEGATIVE;
return INSIDE; return INSIDE;

View File

@@ -7,6 +7,8 @@ import net.momirealms.craftengine.core.world.Vec3d;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.joml.Vector3f; import org.joml.Vector3f;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional; import java.util.Optional;
public class AABB { public class AABB {
@@ -159,6 +161,78 @@ public class AABB {
return (value >= min - EPSILON) && (value <= max + EPSILON); return (value >= min - EPSILON) && (value <= max + EPSILON);
} }
public List<Vec3d> getEdgePoints(double interval) {
List<Vec3d> points = new ArrayList<>();
// AABB的8个顶点
Vec3d[] vertices = {
new Vec3d(minX, minY, minZ), // 0
new Vec3d(maxX, minY, minZ), // 1
new Vec3d(minX, maxY, minZ), // 2
new Vec3d(maxX, maxY, minZ), // 3
new Vec3d(minX, minY, maxZ), // 4
new Vec3d(maxX, minY, maxZ), // 5
new Vec3d(minX, maxY, maxZ), // 6
new Vec3d(maxX, maxY, maxZ) // 7
};
// 12条边的定义连接哪两个顶点
int[][] edges = {
{0, 1}, // 底部X边
{1, 3}, // 底部Y边
{3, 2}, // 底部X边
{2, 0}, // 底部Y边
{4, 5}, // 顶部X边
{5, 7}, // 顶部Y边
{7, 6}, // 顶部X边
{6, 4}, // 顶部Y边
{0, 4}, // Z边左下前
{1, 5}, // Z边右下前
{2, 6}, // Z边左后上
{3, 7} // Z边右后上
};
for (int[] edge : edges) {
Vec3d start = vertices[edge[0]];
Vec3d end = vertices[edge[1]];
points.addAll(sampleLine(start, end, interval));
}
return points;
}
private List<Vec3d> sampleLine(Vec3d start, Vec3d end, double interval) {
List<Vec3d> points = new ArrayList<>();
// 计算线段长度
double dx = end.x - start.x;
double dy = end.y - start.y;
double dz = end.z - start.z;
double length = Math.sqrt(dx * dx + dy * dy + dz * dz);
// 计算采样点数(去掉终点避免重复)
int numPoints = (int) Math.floor(length / interval);
// 如果线段太短,至少返回起点
if (numPoints <= 0) {
points.add(start);
return points;
}
// 按间隔采样
for (int i = 0; i <= numPoints; i++) {
double t = (double) i / numPoints;
double x = start.x + dx * t;
double y = start.y + dy * t;
double z = start.z + dz * t;
points.add(new Vec3d(x, y, z));
}
return points;
}
@Override @Override
public String toString() { public String toString() {
return "AABB{" + return "AABB{" +