This commit is contained in:
@@ -33,6 +33,17 @@ public class DirtyUpdateService {
|
|||||||
section.acquire();
|
section.acquire();
|
||||||
this.dirtyQueue.add(new DirtySection(world, section, updateFlags, neighborMsk));
|
this.dirtyQueue.add(new DirtySection(world, section, updateFlags, neighborMsk));
|
||||||
// Logger.info("Section dirty: " + section.lvl + " " + section.x + " " + section.y + " " + section.z);
|
// Logger.info("Section dirty: " + section.lvl + " " + section.x + " " + section.y + " " + section.z);
|
||||||
|
int lvl = section.lvl;
|
||||||
|
int sx = section.x;
|
||||||
|
int sz = section.z;
|
||||||
|
int m = (1 << (lvl + 1)) - 1;
|
||||||
|
for (int dx = 0; dx <= m; dx++) {
|
||||||
|
for (int dz = 0; dz <= m; dz++) {
|
||||||
|
int absX = (sx << (lvl + 1)) | dx;
|
||||||
|
int absZ = (sz << (lvl + 1)) | dz;
|
||||||
|
this.instance.getVisibleBandCache().invalidate(absX, absZ);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -121,7 +132,8 @@ public class DirtyUpdateService {
|
|||||||
int absZ = (int) it[1];
|
int absZ = (int) it[1];
|
||||||
int minAbsY = (sy << (lvl + 1));
|
int minAbsY = (sy << (lvl + 1));
|
||||||
int maxAbsY = minAbsY + m;
|
int maxAbsY = minAbsY + m;
|
||||||
int[] yList = VisibleBandUtil.computeVisibleBands(matchLevel, dirty.world, absX, absZ);
|
int[] yList = this.instance.getVisibleBandCache().getOrSchedule(matchLevel, dirty.world, absX, absZ);
|
||||||
|
if (yList == null) continue;
|
||||||
for (int i = 0; i < yList.length && perPlayerBudget > 0; i++) {
|
for (int i = 0; i < yList.length && perPlayerBudget > 0; i++) {
|
||||||
int absY = yList[i];
|
int absY = yList[i];
|
||||||
if (absY < minAbsY || absY > maxAbsY) continue;
|
if (absY < minAbsY || absY > maxAbsY) continue;
|
||||||
|
|||||||
@@ -109,9 +109,12 @@ public class PlayerLodTracker {
|
|||||||
long key = (((long)x) << 32) ^ (z & 0xffffffffL);
|
long key = (((long)x) << 32) ^ (z & 0xffffffffL);
|
||||||
var prog = state.sentColumns.computeIfAbsent(key, k -> new ColumnProgress());
|
var prog = state.sentColumns.computeIfAbsent(key, k -> new ColumnProgress());
|
||||||
if (prog.yList == null) {
|
if (prog.yList == null) {
|
||||||
prog.yList = VisibleBandUtil.computeVisibleBands(level, engine, x, z);
|
int[] ys = this.instance.getVisibleBandCache().getOrSchedule(level, engine, x, z);
|
||||||
|
if (ys != null) {
|
||||||
|
prog.yList = ys;
|
||||||
prog.nextIdx = 0;
|
prog.nextIdx = 0;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// defer processing to global prioritized loop
|
// defer processing to global prioritized loop
|
||||||
}
|
}
|
||||||
}, (x, z) -> {
|
}, (x, z) -> {
|
||||||
@@ -139,8 +142,13 @@ public class PlayerLodTracker {
|
|||||||
var prog = state.sentColumns.get(key);
|
var prog = state.sentColumns.get(key);
|
||||||
if (prog == null) continue;
|
if (prog == null) continue;
|
||||||
if (prog.yList == null) {
|
if (prog.yList == null) {
|
||||||
prog.yList = VisibleBandUtil.computeVisibleBands(level, engine, cx, cz);
|
int[] ys = this.instance.getVisibleBandCache().getOrSchedule(level, engine, cx, cz);
|
||||||
|
if (ys != null) {
|
||||||
|
prog.yList = ys;
|
||||||
prog.nextIdx = 0;
|
prog.nextIdx = 0;
|
||||||
|
} else {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
budget.addAndGet(-processVerticalList(player, engine, cx, cz, prog, budget.get()));
|
budget.addAndGet(-processVerticalList(player, engine, cx, cz, prog, budget.get()));
|
||||||
}
|
}
|
||||||
|
|||||||
39
src/main/java/me/cortex/voxy/server/VisibleBandCache.java
Normal file
39
src/main/java/me/cortex/voxy/server/VisibleBandCache.java
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
package me.cortex.voxy.server;
|
||||||
|
|
||||||
|
import me.cortex.voxy.common.world.WorldEngine;
|
||||||
|
import net.minecraft.server.level.ServerLevel;
|
||||||
|
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
final class VisibleBandCache {
|
||||||
|
private final VoxyServerInstance instance;
|
||||||
|
private final ConcurrentHashMap<Long, int[]> cache = new ConcurrentHashMap<>();
|
||||||
|
private final ConcurrentHashMap<Long, Boolean> pending = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
VisibleBandCache(VoxyServerInstance instance) {
|
||||||
|
this.instance = instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
int[] getOrSchedule(ServerLevel level, WorldEngine engine, int chunkX, int chunkZ) {
|
||||||
|
long key = (((long) chunkX) << 32) ^ (chunkZ & 0xffffffffL);
|
||||||
|
int[] ys = cache.get(key);
|
||||||
|
if (ys != null) return ys;
|
||||||
|
if (pending.putIfAbsent(key, Boolean.TRUE) == null) {
|
||||||
|
this.instance.getThreadPool().execute(() -> {
|
||||||
|
try {
|
||||||
|
int[] result = VisibleBandUtil.computeVisibleBands(level, engine, chunkX, chunkZ);
|
||||||
|
cache.put(key, result);
|
||||||
|
} finally {
|
||||||
|
pending.remove(key);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
void invalidate(int chunkX, int chunkZ) {
|
||||||
|
long key = (((long) chunkX) << 32) ^ (chunkZ & 0xffffffffL);
|
||||||
|
cache.remove(key);
|
||||||
|
pending.remove(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -21,6 +21,7 @@ public class VoxyServerInstance extends VoxyInstance {
|
|||||||
|
|
||||||
private final DirtyUpdateService dirtyUpdateService;
|
private final DirtyUpdateService dirtyUpdateService;
|
||||||
private final PlayerLodTracker playerLodTracker;
|
private final PlayerLodTracker playerLodTracker;
|
||||||
|
private final VisibleBandCache visibleBandCache;
|
||||||
|
|
||||||
public VoxyServerInstance(MinecraftServer server) {
|
public VoxyServerInstance(MinecraftServer server) {
|
||||||
super();
|
super();
|
||||||
@@ -35,6 +36,7 @@ public class VoxyServerInstance extends VoxyInstance {
|
|||||||
|
|
||||||
this.dirtyUpdateService = new DirtyUpdateService(this);
|
this.dirtyUpdateService = new DirtyUpdateService(this);
|
||||||
this.playerLodTracker = new PlayerLodTracker(this);
|
this.playerLodTracker = new PlayerLodTracker(this);
|
||||||
|
this.visibleBandCache = new VisibleBandCache(this);
|
||||||
|
|
||||||
// Start a service to tick the dirty service
|
// Start a service to tick the dirty service
|
||||||
this.threadPool.serviceManager.createServiceNoCleanup(() -> this.dirtyUpdateService::tick, VoxyServerConfig.CONFIG.dirtyUpdateDelay * 50, "DirtyUpdateService");
|
this.threadPool.serviceManager.createServiceNoCleanup(() -> this.dirtyUpdateService::tick, VoxyServerConfig.CONFIG.dirtyUpdateDelay * 50, "DirtyUpdateService");
|
||||||
@@ -110,4 +112,8 @@ public class VoxyServerInstance extends VoxyInstance {
|
|||||||
public UnifiedServiceThreadPool getThreadPool() {
|
public UnifiedServiceThreadPool getThreadPool() {
|
||||||
return this.threadPool;
|
return this.threadPool;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VisibleBandCache getVisibleBandCache() {
|
||||||
|
return this.visibleBandCache;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user