mirror of
https://github.com/Xiao-MoMi/craft-engine.git
synced 2025-12-27 19:09:08 +00:00
完成第三人称光线追踪,修复眼睛位置
This commit is contained in:
@@ -715,13 +715,14 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem
|
||||
return null;
|
||||
}
|
||||
if (!(arguments instanceof Map)) {
|
||||
return new CullingData(DEFAULT_BLOCK_ENTITY_AABB, Config.entityCullingViewDistance(), 0.5);
|
||||
return new CullingData(DEFAULT_BLOCK_ENTITY_AABB, Config.entityCullingViewDistance(), 0.5, true);
|
||||
}
|
||||
Map<String, Object> argumentsMap = ResourceConfigUtils.getAsMap(arguments, "entity-culling");
|
||||
return new CullingData(
|
||||
ResourceConfigUtils.getAsAABB(argumentsMap.getOrDefault("aabb", 1), "aabb"),
|
||||
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.5), "aabb-expansion"),
|
||||
ResourceConfigUtils.getAsBoolean(argumentsMap.getOrDefault("ray-tracing", true), "ray-tracing")
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -218,4 +218,6 @@ public abstract class Player extends AbstractEntity implements NetWorkUser {
|
||||
@Override
|
||||
public void remove() {
|
||||
}
|
||||
|
||||
public abstract WorldPosition eyePosition();
|
||||
}
|
||||
|
||||
@@ -208,6 +208,7 @@ public class Config {
|
||||
protected boolean client_optimization$entity_culling$enable;
|
||||
protected int client_optimization$entity_culling$view_distance;
|
||||
protected int client_optimization$entity_culling$threads;
|
||||
protected boolean client_optimization$entity_culling$ray_tracing;
|
||||
protected boolean client_optimization$entity_culling$rate_limiting$enable;
|
||||
protected int client_optimization$entity_culling$rate_limiting$bucket_size;
|
||||
protected int client_optimization$entity_culling$rate_limiting$restore_per_tick;
|
||||
@@ -579,6 +580,7 @@ public class Config {
|
||||
}
|
||||
client_optimization$entity_culling$view_distance = config.getInt("client-optimization.entity-culling.view-distance", 64);
|
||||
client_optimization$entity_culling$threads = config.getInt("client-optimization.entity-culling.threads", 1);
|
||||
client_optimization$entity_culling$ray_tracing = client_optimization$entity_culling$enable && config.getBoolean("client-optimization.entity-culling.ray-tracing", true);
|
||||
client_optimization$entity_culling$rate_limiting$enable = config.getBoolean("client-optimization.entity-culling.rate-limiting.enable", true);
|
||||
client_optimization$entity_culling$rate_limiting$bucket_size = config.getInt("client-optimization.entity-culling.rate-limiting.bucket-size", 300);
|
||||
client_optimization$entity_culling$rate_limiting$restore_per_tick = config.getInt("client-optimization.entity-culling.rate-limiting.restore-per-tick", 5);
|
||||
@@ -1197,6 +1199,10 @@ public class Config {
|
||||
return instance.client_optimization$entity_culling$rate_limiting$restore_per_tick;
|
||||
}
|
||||
|
||||
public static boolean entityCullingRayTracing() {
|
||||
return instance.client_optimization$entity_culling$ray_tracing;
|
||||
}
|
||||
|
||||
public YamlDocument loadOrCreateYamlData(String fileName) {
|
||||
Path path = this.plugin.dataFolderPath().resolve(fileName);
|
||||
if (!Files.exists(path)) {
|
||||
|
||||
@@ -6,22 +6,28 @@ public final class CullingData {
|
||||
public final AABB aabb;
|
||||
public final int maxDistance;
|
||||
public final double aabbExpansion;
|
||||
public final boolean rayTracing;
|
||||
|
||||
public CullingData(AABB aabb, int maxDistance, double aabbExpansion) {
|
||||
public CullingData(AABB aabb, int maxDistance, double aabbExpansion, boolean rayTracing) {
|
||||
this.aabb = aabb;
|
||||
this.maxDistance = maxDistance;
|
||||
this.aabbExpansion = aabbExpansion;
|
||||
this.rayTracing = rayTracing;
|
||||
}
|
||||
|
||||
public AABB aabb() {
|
||||
return aabb;
|
||||
return this.aabb;
|
||||
}
|
||||
|
||||
public int maxDistance() {
|
||||
return maxDistance;
|
||||
return this.maxDistance;
|
||||
}
|
||||
|
||||
public double aabbExpansion() {
|
||||
return aabbExpansion;
|
||||
return this.aabbExpansion;
|
||||
}
|
||||
|
||||
public boolean rayTracing() {
|
||||
return this.rayTracing;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,8 +16,8 @@ public final class EntityCulling {
|
||||
private final Player player;
|
||||
private final boolean[] dotSelectors = new boolean[MAX_SAMPLES];
|
||||
private final MutableVec3d[] targetPoints = new MutableVec3d[MAX_SAMPLES];
|
||||
private final int[] lastHitBlock = new int[MAX_SAMPLES * 3];
|
||||
private final boolean[] canCheckLastHitBlock = new boolean[MAX_SAMPLES];
|
||||
private final int[] lastHitBlock = new int[3];
|
||||
private boolean canCheckLastHitBlock = false;
|
||||
private int hitBlockCount = 0;
|
||||
private int lastVisitChunkX = Integer.MAX_VALUE;
|
||||
private int lastVisitChunkZ = Integer.MAX_VALUE;
|
||||
@@ -52,9 +52,9 @@ public final class EntityCulling {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isVisible(CullingData cullable, Vec3d cameraPos) {
|
||||
public boolean isVisible(CullingData cullable, Vec3d cameraPos, boolean rayTracing) {
|
||||
// 情空标志位
|
||||
Arrays.fill(this.canCheckLastHitBlock, false);
|
||||
this.canCheckLastHitBlock = false;
|
||||
this.hitBlockCount = 0;
|
||||
AABB aabb = cullable.aabb;
|
||||
double aabbExpansion = cullable.aabbExpansion;
|
||||
@@ -97,6 +97,10 @@ public final class EntityCulling {
|
||||
}
|
||||
}
|
||||
|
||||
if (!rayTracing || !cullable.rayTracing) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 清空之前的缓存
|
||||
Arrays.fill(this.dotSelectors, false);
|
||||
if (relX == Relative.POSITIVE) {
|
||||
@@ -190,7 +194,7 @@ public final class EntityCulling {
|
||||
int startBlockZ = MiscUtils.floor(start.z);
|
||||
|
||||
// 遍历所有目标点进行视线检测
|
||||
outer: for (int targetIndex = 0; targetIndex < targetCount; targetIndex++) {
|
||||
for (int targetIndex = 0; targetIndex < targetCount; targetIndex++) {
|
||||
MutableVec3d currentTarget = targets[targetIndex];
|
||||
|
||||
// 计算起点到目标的相对向量(世界坐标差)
|
||||
@@ -199,14 +203,9 @@ public final class EntityCulling {
|
||||
double deltaZ = start.z - currentTarget.z;
|
||||
|
||||
// 检查之前命中的方块,大概率还是命中
|
||||
for (int i = 0; i < MAX_SAMPLES; i++) {
|
||||
if (this.canCheckLastHitBlock[i]) {
|
||||
int offset = i * 3;
|
||||
if (rayIntersection(this.lastHitBlock[offset], this.lastHitBlock[offset + 1], this.lastHitBlock[offset + 2], start, new MutableVec3d(deltaX, deltaY, deltaZ).normalize())) {
|
||||
continue outer;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
if (this.canCheckLastHitBlock) {
|
||||
if (rayIntersection(this.lastHitBlock[0], this.lastHitBlock[1], this.lastHitBlock[2], start, new MutableVec3d(deltaX, deltaY, deltaZ).normalize())) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -292,7 +291,7 @@ public final class EntityCulling {
|
||||
if (isLineOfSightClear) {
|
||||
return true;
|
||||
} else {
|
||||
this.canCheckLastHitBlock[this.hitBlockCount++] = true;
|
||||
this.canCheckLastHitBlock = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ package net.momirealms.craftengine.core.plugin.entityculling;
|
||||
|
||||
import net.momirealms.craftengine.core.entity.player.Player;
|
||||
import net.momirealms.craftengine.core.plugin.CraftEngine;
|
||||
import net.momirealms.craftengine.core.plugin.config.Config;
|
||||
import net.momirealms.craftengine.core.plugin.logger.Debugger;
|
||||
|
||||
import java.util.concurrent.Executors;
|
||||
@@ -14,6 +15,7 @@ public class EntityCullingThread {
|
||||
private final AtomicBoolean isRunning = new AtomicBoolean(false);
|
||||
private final int id;
|
||||
private final int threads;
|
||||
private int timer;
|
||||
|
||||
public EntityCullingThread(int id, int threads) {
|
||||
this.id = id;
|
||||
@@ -35,7 +37,7 @@ public class EntityCullingThread {
|
||||
this.scheduler.execute(() -> {
|
||||
try {
|
||||
int processed = 0;
|
||||
long startTime = System.currentTimeMillis();
|
||||
long startTime = System.nanoTime();
|
||||
|
||||
for (Player player : CraftEngine.instance().networkManager().onlineUsers()) {
|
||||
// 使用绝对值确保非负,使用 threads 而不是 threads-1 确保均匀分布
|
||||
@@ -45,10 +47,10 @@ public class EntityCullingThread {
|
||||
}
|
||||
}
|
||||
|
||||
long duration = System.currentTimeMillis() - startTime;
|
||||
if (duration > 45) {
|
||||
String value = String.format("EntityCullingThread-%d processed %d players in %dms (over 45ms)",
|
||||
this.id, processed, duration);
|
||||
long duration = System.nanoTime() - startTime;
|
||||
if (Config.debugEntityCulling() && this.timer++ % 20 == 0) {
|
||||
String value = String.format("EntityCullingThread-%d processed %d players in %sms",
|
||||
this.id, processed, String.format("%.2f", duration / 1_000_000.0));
|
||||
Debugger.ENTITY_CULLING.debug(() -> value);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
|
||||
@@ -143,7 +143,7 @@ public class CEChunk {
|
||||
ConstantBlockEntityRenderer renderer = new ConstantBlockEntityRenderer(
|
||||
elements,
|
||||
Optional.ofNullable(state.cullingData())
|
||||
.map(data -> new CullingData(data.aabb.move(pos), data.maxDistance, data.aabbExpansion))
|
||||
.map(data -> new CullingData(data.aabb.move(pos), data.maxDistance, data.aabbExpansion, data.rayTracing))
|
||||
.orElse(null)
|
||||
);
|
||||
World wrappedWorld = this.world.world();
|
||||
|
||||
Reference in New Issue
Block a user