diff --git a/src/main/java/me/cortex/voxy/server/DirtyUpdateService.java b/src/main/java/me/cortex/voxy/server/DirtyUpdateService.java index d35e3545..5385927a 100644 --- a/src/main/java/me/cortex/voxy/server/DirtyUpdateService.java +++ b/src/main/java/me/cortex/voxy/server/DirtyUpdateService.java @@ -99,6 +99,7 @@ public class DirtyUpdateService { int standardViewDist = server.getPlayerList().getViewDistance() * 16; int m = (1 << (lvl + 1)) - 1; int perPlayerBudget = 25; + java.util.ArrayList cols = new java.util.ArrayList<>(); for (int dx = 0; dx <= m; dx++) { for (int dz = 0; dz <= m; dz++) { double centerX = (((sx << (lvl + 1)) | dx) * sectionSize) + (sectionSize / 2.0); @@ -109,19 +110,26 @@ public class DirtyUpdateService { if (distSq > standardViewDist * standardViewDist && distSq < voxyDistance * voxyDistance) { int absX = (sx << (lvl + 1)) | dx; int absZ = (sz << (lvl + 1)) | dz; - int minAbsY = (sy << (lvl + 1)); - int maxAbsY = minAbsY + m; - int[] yList = VisibleBandUtil.computeVisibleBands(matchLevel, dirty.world, absX, absZ); - for (int i = 0; i < yList.length && perPlayerBudget > 0; i++) { - int absY = yList[i]; - if (absY < minAbsY || absY > maxAbsY) continue; - var voxelized = WorldSectionToVoxelizedConverter.convert(dirty.section, lvl, absX, absY, absZ); - if (voxelized.lvl0NonAirCount > 0) { - var payload = VoxyNetwork.LodUpdatePayload.create(voxelized, dirty.world.getMapper()); - ServerPlayNetworking.send(player, payload); - perPlayerBudget--; - } - } + cols.add(new long[]{absX, absZ, Double.doubleToRawLongBits(distSq)}); + } + } + } + cols.sort((a,b)->Long.compare(a[2], b[2])); + for (var it : cols) { + if (perPlayerBudget <= 0) break; + int absX = (int) it[0]; + int absZ = (int) it[1]; + int minAbsY = (sy << (lvl + 1)); + int maxAbsY = minAbsY + m; + int[] yList = VisibleBandUtil.computeVisibleBands(matchLevel, dirty.world, absX, absZ); + for (int i = 0; i < yList.length && perPlayerBudget > 0; i++) { + int absY = yList[i]; + if (absY < minAbsY || absY > maxAbsY) continue; + var voxelized = WorldSectionToVoxelizedConverter.convert(dirty.section, lvl, absX, absY, absZ); + if (voxelized.lvl0NonAirCount > 0) { + var payload = VoxyNetwork.LodUpdatePayload.create(voxelized, dirty.world.getMapper()); + ServerPlayNetworking.send(player, payload); + perPlayerBudget--; } } } diff --git a/src/main/java/me/cortex/voxy/server/PlayerLodTracker.java b/src/main/java/me/cortex/voxy/server/PlayerLodTracker.java index dd48a079..d8f1e526 100644 --- a/src/main/java/me/cortex/voxy/server/PlayerLodTracker.java +++ b/src/main/java/me/cortex/voxy/server/PlayerLodTracker.java @@ -112,7 +112,7 @@ public class PlayerLodTracker { prog.yList = VisibleBandUtil.computeVisibleBands(level, engine, x, z); prog.nextIdx = 0; } - budget.addAndGet(-processVerticalList(player, engine, x, z, prog, budget.get())); + // defer processing to global prioritized loop } }, (x, z) -> { // On Remove (Unload) @@ -120,17 +120,29 @@ public class PlayerLodTracker { state.sentColumns.remove(key); }); if (budget.get() > 0) { + java.util.ArrayList cols = new java.util.ArrayList<>(state.sentColumns.size()); for (var entry : state.sentColumns.entrySet()) { - if (budget.get() <= 0) break; long key = entry.getKey(); - int x = (int)(key >> 32); - int z = (int)key; - var prog = entry.getValue(); + int cx = (int)(key >> 32); + int cz = (int)key; + double dx = cx - state.lastX; + double dz = cz - state.lastZ; + double d2 = dx*dx + dz*dz; + cols.add(new long[]{key, Double.doubleToRawLongBits(d2)}); + } + cols.sort((a,b)->Long.compare(a[1], b[1])); + for (var it : cols) { + if (budget.get() <= 0) break; + long key = it[0]; + int cx = (int)(key >> 32); + int cz = (int)key; + var prog = state.sentColumns.get(key); + if (prog == null) continue; if (prog.yList == null) { - prog.yList = VisibleBandUtil.computeVisibleBands(level, engine, x, z); + prog.yList = VisibleBandUtil.computeVisibleBands(level, engine, cx, cz); prog.nextIdx = 0; } - budget.addAndGet(-processVerticalList(player, engine, x, z, prog, budget.get())); + budget.addAndGet(-processVerticalList(player, engine, cx, cz, prog, budget.get())); } } }