Add quarter res chunks + good requeue mechanism
This commit is contained in:
parent
c045c0a0d4
commit
d077f43188
@ -31,6 +31,11 @@ public class ClientTerrainCache {
|
|||||||
*/
|
*/
|
||||||
Map<Long,ChunkData> cacheMapHalfRes = new ConcurrentHashMap<Long,ChunkData>();
|
Map<Long,ChunkData> cacheMapHalfRes = new ConcurrentHashMap<Long,ChunkData>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The map of half res chunk key -> chunk data
|
||||||
|
*/
|
||||||
|
Map<Long,ChunkData> cacheMapQuarterRes = new ConcurrentHashMap<Long,ChunkData>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The list of keys in the cache
|
* The list of keys in the cache
|
||||||
*/
|
*/
|
||||||
@ -146,6 +151,9 @@ public class ClientTerrainCache {
|
|||||||
case 1: {
|
case 1: {
|
||||||
return cacheMapHalfRes;
|
return cacheMapHalfRes;
|
||||||
}
|
}
|
||||||
|
case 2: {
|
||||||
|
return cacheMapQuarterRes;
|
||||||
|
}
|
||||||
default: {
|
default: {
|
||||||
throw new Error("Invalid stride probided! " + stride);
|
throw new Error("Invalid stride probided! " + stride);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -25,6 +25,11 @@ public class ClientDrawCellManager {
|
|||||||
*/
|
*/
|
||||||
static final int UPDATE_ATTEMPTS_PER_FRAME = 3;
|
static final int UPDATE_ATTEMPTS_PER_FRAME = 3;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The number of generation attempts before a cell is marked as having not requested its data
|
||||||
|
*/
|
||||||
|
static final int FAILED_GENERATION_ATTEMPT_THRESHOLD = 250;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The distance to draw at full resolution
|
* The distance to draw at full resolution
|
||||||
*/
|
*/
|
||||||
@ -35,6 +40,11 @@ public class ClientDrawCellManager {
|
|||||||
*/
|
*/
|
||||||
public static final double HALF_RES_DIST = 16 * ServerTerrainChunk.CHUNK_DIMENSION;
|
public static final double HALF_RES_DIST = 16 * ServerTerrainChunk.CHUNK_DIMENSION;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The distance for quarter resolution
|
||||||
|
*/
|
||||||
|
public static final double QUARTER_RES_DIST = 20 * ServerTerrainChunk.CHUNK_DIMENSION;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The octree holding all the chunks to evaluate
|
* The octree holding all the chunks to evaluate
|
||||||
*/
|
*/
|
||||||
@ -164,7 +174,8 @@ public class ClientDrawCellManager {
|
|||||||
} else if(shouldRequest(playerPos, node)){
|
} else if(shouldRequest(playerPos, node)){
|
||||||
Globals.profiler.beginCpuSample("ClientDrawCellManager.request");
|
Globals.profiler.beginCpuSample("ClientDrawCellManager.request");
|
||||||
DrawCell cell = node.getData();
|
DrawCell cell = node.getData();
|
||||||
this.requestChunks(node);
|
List<DrawCellFace> highResFaces = this.solveHighResFace(node);
|
||||||
|
this.requestChunks(node, highResFaces);
|
||||||
cell.setHasRequested(true);
|
cell.setHasRequested(true);
|
||||||
Globals.profiler.endCpuSample();
|
Globals.profiler.endCpuSample();
|
||||||
updated = true;
|
updated = true;
|
||||||
@ -174,6 +185,11 @@ public class ClientDrawCellManager {
|
|||||||
List<DrawCellFace> highResFaces = this.solveHighResFace(node);
|
List<DrawCellFace> highResFaces = this.solveHighResFace(node);
|
||||||
if(containsDataToGenerate(node,highResFaces)){
|
if(containsDataToGenerate(node,highResFaces)){
|
||||||
node.getData().generateDrawableEntity(textureAtlas, lodLevel, highResFaces);
|
node.getData().generateDrawableEntity(textureAtlas, lodLevel, highResFaces);
|
||||||
|
} else if(node.getData() != null){
|
||||||
|
node.getData().setFailedGenerationAttempts(node.getData().getFailedGenerationAttempts() + 1);
|
||||||
|
if(node.getData().getFailedGenerationAttempts() > FAILED_GENERATION_ATTEMPT_THRESHOLD){
|
||||||
|
node.getData().setHasRequested(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Globals.profiler.endCpuSample();
|
Globals.profiler.endCpuSample();
|
||||||
updated = true;
|
updated = true;
|
||||||
@ -215,6 +231,11 @@ public class ClientDrawCellManager {
|
|||||||
node.isLeaf() &&
|
node.isLeaf() &&
|
||||||
node.canSplit() &&
|
node.canSplit() &&
|
||||||
(
|
(
|
||||||
|
(
|
||||||
|
node.getLevel() < this.chunkTree.getMaxLevel() - 2 &&
|
||||||
|
this.getMinDistance(pos, node) <= QUARTER_RES_DIST
|
||||||
|
)
|
||||||
|
||
|
||||||
(
|
(
|
||||||
node.getLevel() < this.chunkTree.getMaxLevel() - 1 &&
|
node.getLevel() < this.chunkTree.getMaxLevel() - 1 &&
|
||||||
this.getMinDistance(pos, node) <= HALF_RES_DIST
|
this.getMinDistance(pos, node) <= HALF_RES_DIST
|
||||||
@ -358,10 +379,15 @@ public class ClientDrawCellManager {
|
|||||||
node.getLevel() == this.chunkTree.getMaxLevel() - 1 &&
|
node.getLevel() == this.chunkTree.getMaxLevel() - 1 &&
|
||||||
this.getMinDistance(pos, node) > FULL_RES_DIST
|
this.getMinDistance(pos, node) > FULL_RES_DIST
|
||||||
)
|
)
|
||||||
||
|
||
|
||||||
(
|
(
|
||||||
|
node.getLevel() == this.chunkTree.getMaxLevel() - 2 &&
|
||||||
this.getMinDistance(pos, node) > HALF_RES_DIST
|
this.getMinDistance(pos, node) > HALF_RES_DIST
|
||||||
)
|
)
|
||||||
|
||
|
||||||
|
(
|
||||||
|
this.getMinDistance(pos, node) > QUARTER_RES_DIST
|
||||||
|
)
|
||||||
)
|
)
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
@ -389,6 +415,12 @@ public class ClientDrawCellManager {
|
|||||||
&&
|
&&
|
||||||
this.getMinDistance(pos, node) <= HALF_RES_DIST
|
this.getMinDistance(pos, node) <= HALF_RES_DIST
|
||||||
)
|
)
|
||||||
|
||
|
||||||
|
(
|
||||||
|
node.getLevel() == this.chunkTree.getMaxLevel() - 2
|
||||||
|
&&
|
||||||
|
this.getMinDistance(pos, node) <= QUARTER_RES_DIST
|
||||||
|
)
|
||||||
)
|
)
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
@ -410,12 +442,18 @@ public class ClientDrawCellManager {
|
|||||||
// &&
|
// &&
|
||||||
// this.getMinDistance(pos, node) <= FULL_RES_DIST
|
// this.getMinDistance(pos, node) <= FULL_RES_DIST
|
||||||
)
|
)
|
||||||
||
|
||
|
||||||
(
|
(
|
||||||
node.getLevel() == this.chunkTree.getMaxLevel() - 1
|
node.getLevel() == this.chunkTree.getMaxLevel() - 1
|
||||||
&&
|
&&
|
||||||
this.getMinDistance(pos, node) <= HALF_RES_DIST
|
this.getMinDistance(pos, node) <= HALF_RES_DIST
|
||||||
)
|
)
|
||||||
|
||
|
||||||
|
(
|
||||||
|
node.getLevel() == this.chunkTree.getMaxLevel() - 2
|
||||||
|
&&
|
||||||
|
this.getMinDistance(pos, node) <= QUARTER_RES_DIST
|
||||||
|
)
|
||||||
)
|
)
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
@ -494,7 +532,7 @@ public class ClientDrawCellManager {
|
|||||||
* Requests all chunks for a given draw cell
|
* Requests all chunks for a given draw cell
|
||||||
* @param cell The cell
|
* @param cell The cell
|
||||||
*/
|
*/
|
||||||
private void requestChunks(WorldOctTree.FloatingChunkTreeNode<DrawCell> node){
|
private void requestChunks(WorldOctTree.FloatingChunkTreeNode<DrawCell> node, List<DrawCellFace> highResFaces){
|
||||||
DrawCell cell = node.getData();
|
DrawCell cell = node.getData();
|
||||||
int lod = this.chunkTree.getMaxLevel() - node.getLevel();
|
int lod = this.chunkTree.getMaxLevel() - node.getLevel();
|
||||||
int spacingFactor = (int)Math.pow(2,lod);
|
int spacingFactor = (int)Math.pow(2,lod);
|
||||||
@ -518,6 +556,51 @@ public class ClientDrawCellManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
int highResLod = this.chunkTree.getMaxLevel() - (node.getLevel() + 1);
|
||||||
|
int highResSpacingFactor = (int)Math.pow(2,highResLod);
|
||||||
|
if(highResFaces != null){
|
||||||
|
for(DrawCellFace highResFace : highResFaces){
|
||||||
|
//x & y are in face-space
|
||||||
|
for(int x = 0; x < 3; x++){
|
||||||
|
for(int y = 0; y < 3; y++){
|
||||||
|
Vector3i posToCheck = null;
|
||||||
|
//implicitly performing transforms to adapt from face-space to world space
|
||||||
|
switch(highResFace){
|
||||||
|
case X_POSITIVE: {
|
||||||
|
posToCheck = new Vector3i(cell.getWorldPos()).add(spacingFactor,x*highResSpacingFactor,y*highResSpacingFactor);
|
||||||
|
} break;
|
||||||
|
case X_NEGATIVE: {
|
||||||
|
posToCheck = new Vector3i(cell.getWorldPos()).add(0,x*highResSpacingFactor,y*highResSpacingFactor);
|
||||||
|
} break;
|
||||||
|
case Y_POSITIVE: {
|
||||||
|
posToCheck = new Vector3i(cell.getWorldPos()).add(x*highResSpacingFactor,spacingFactor,y*highResSpacingFactor);
|
||||||
|
} break;
|
||||||
|
case Y_NEGATIVE: {
|
||||||
|
posToCheck = new Vector3i(cell.getWorldPos()).add(x*highResSpacingFactor,0,y*highResSpacingFactor);
|
||||||
|
} break;
|
||||||
|
case Z_POSITIVE: {
|
||||||
|
posToCheck = new Vector3i(cell.getWorldPos()).add(x*highResSpacingFactor,y*highResSpacingFactor,spacingFactor);
|
||||||
|
} break;
|
||||||
|
case Z_NEGATIVE: {
|
||||||
|
posToCheck = new Vector3i(cell.getWorldPos()).add(x*highResSpacingFactor,y*highResSpacingFactor,0);
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
if(
|
||||||
|
posToCheck.x >= 0 &&
|
||||||
|
posToCheck.x < Globals.clientWorldData.getWorldDiscreteSize() &&
|
||||||
|
posToCheck.y >= 0 &&
|
||||||
|
posToCheck.y < Globals.clientWorldData.getWorldDiscreteSize() &&
|
||||||
|
posToCheck.z >= 0 &&
|
||||||
|
posToCheck.z < Globals.clientWorldData.getWorldDiscreteSize() &&
|
||||||
|
!Globals.clientTerrainManager.containsChunkDataAtWorldPoint(posToCheck.x, posToCheck.y, posToCheck.z, highResLod)
|
||||||
|
){
|
||||||
|
LoggerInterface.loggerNetworking.DEBUG("(Client) Send Request for terrain at " + posToCheck);
|
||||||
|
Globals.clientTerrainManager.requestChunk(posToCheck.x, posToCheck.y, posToCheck.z, highResLod);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -14,7 +14,6 @@ import electrosphere.entity.Entity;
|
|||||||
import electrosphere.entity.types.terrain.TerrainChunk;
|
import electrosphere.entity.types.terrain.TerrainChunk;
|
||||||
import electrosphere.renderer.meshgen.TransvoxelModelGeneration;
|
import electrosphere.renderer.meshgen.TransvoxelModelGeneration;
|
||||||
import electrosphere.renderer.meshgen.TransvoxelModelGeneration.TransvoxelChunkData;
|
import electrosphere.renderer.meshgen.TransvoxelModelGeneration.TransvoxelChunkData;
|
||||||
import electrosphere.server.terrain.manager.ServerTerrainChunk;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A single drawcell - contains an entity that has a physics mesh and potentially graphics
|
* A single drawcell - contains an entity that has a physics mesh and potentially graphics
|
||||||
@ -88,6 +87,11 @@ public class DrawCell {
|
|||||||
* True if there are multiple types of voxels in this chunk
|
* True if there are multiple types of voxels in this chunk
|
||||||
*/
|
*/
|
||||||
boolean multiVoxelType = false;
|
boolean multiVoxelType = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Number of failed generation attempts
|
||||||
|
*/
|
||||||
|
int failedGenerationAttempts = 0;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -118,6 +122,7 @@ public class DrawCell {
|
|||||||
Globals.profiler.endCpuSample();
|
Globals.profiler.endCpuSample();
|
||||||
if(!success){
|
if(!success){
|
||||||
this.setHasRequested(false);
|
this.setHasRequested(false);
|
||||||
|
this.failedGenerationAttempts++;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(modelEntity != null){
|
if(modelEntity != null){
|
||||||
@ -131,6 +136,7 @@ public class DrawCell {
|
|||||||
Globals.profiler.endCpuSample();
|
Globals.profiler.endCpuSample();
|
||||||
if(!success){
|
if(!success){
|
||||||
this.setHasRequested(false);
|
this.setHasRequested(false);
|
||||||
|
this.failedGenerationAttempts++;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -464,6 +470,9 @@ public class DrawCell {
|
|||||||
*/
|
*/
|
||||||
public void setHasRequested(boolean hasRequested) {
|
public void setHasRequested(boolean hasRequested) {
|
||||||
this.hasRequested = hasRequested;
|
this.hasRequested = hasRequested;
|
||||||
|
if(!this.hasRequested){
|
||||||
|
this.failedGenerationAttempts = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -490,6 +499,22 @@ public class DrawCell {
|
|||||||
return this.multiVoxelType;
|
return this.multiVoxelType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the number of failed generation attempts
|
||||||
|
* @return The number of failed generation attempts
|
||||||
|
*/
|
||||||
|
public int getFailedGenerationAttempts(){
|
||||||
|
return failedGenerationAttempts;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the number of failed generation attempts
|
||||||
|
* @param attempts The number of failed generation attempts
|
||||||
|
*/
|
||||||
|
public void setFailedGenerationAttempts(int attempts){
|
||||||
|
failedGenerationAttempts = failedGenerationAttempts + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -36,6 +36,11 @@ public class ServerChunkCache {
|
|||||||
*/
|
*/
|
||||||
Map<Long,ServerTerrainChunk> cacheMapHalfRes = new ConcurrentHashMap<Long,ServerTerrainChunk>();
|
Map<Long,ServerTerrainChunk> cacheMapHalfRes = new ConcurrentHashMap<Long,ServerTerrainChunk>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The map of quarter res chunk key -> chunk data
|
||||||
|
*/
|
||||||
|
Map<Long,ServerTerrainChunk> cacheMapQuarterRes = new ConcurrentHashMap<Long,ServerTerrainChunk>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tracks how recently a chunk has been queries for (used for evicting old chunks from cache)
|
* Tracks how recently a chunk has been queries for (used for evicting old chunks from cache)
|
||||||
*/
|
*/
|
||||||
@ -192,6 +197,9 @@ public class ServerChunkCache {
|
|||||||
case 1: {
|
case 1: {
|
||||||
return cacheMapHalfRes;
|
return cacheMapHalfRes;
|
||||||
}
|
}
|
||||||
|
case 2: {
|
||||||
|
return cacheMapQuarterRes;
|
||||||
|
}
|
||||||
default: {
|
default: {
|
||||||
throw new Error("Invalid stride probided! " + stride);
|
throw new Error("Invalid stride probided! " + stride);
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user