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>();
|
||||
|
||||
/**
|
||||
* The map of half res chunk key -> chunk data
|
||||
*/
|
||||
Map<Long,ChunkData> cacheMapQuarterRes = new ConcurrentHashMap<Long,ChunkData>();
|
||||
|
||||
/**
|
||||
* The list of keys in the cache
|
||||
*/
|
||||
@ -146,6 +151,9 @@ public class ClientTerrainCache {
|
||||
case 1: {
|
||||
return cacheMapHalfRes;
|
||||
}
|
||||
case 2: {
|
||||
return cacheMapQuarterRes;
|
||||
}
|
||||
default: {
|
||||
throw new Error("Invalid stride probided! " + stride);
|
||||
}
|
||||
|
||||
@ -25,6 +25,11 @@ public class ClientDrawCellManager {
|
||||
*/
|
||||
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
|
||||
*/
|
||||
@ -35,6 +40,11 @@ public class ClientDrawCellManager {
|
||||
*/
|
||||
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
|
||||
*/
|
||||
@ -164,7 +174,8 @@ public class ClientDrawCellManager {
|
||||
} else if(shouldRequest(playerPos, node)){
|
||||
Globals.profiler.beginCpuSample("ClientDrawCellManager.request");
|
||||
DrawCell cell = node.getData();
|
||||
this.requestChunks(node);
|
||||
List<DrawCellFace> highResFaces = this.solveHighResFace(node);
|
||||
this.requestChunks(node, highResFaces);
|
||||
cell.setHasRequested(true);
|
||||
Globals.profiler.endCpuSample();
|
||||
updated = true;
|
||||
@ -174,6 +185,11 @@ public class ClientDrawCellManager {
|
||||
List<DrawCellFace> highResFaces = this.solveHighResFace(node);
|
||||
if(containsDataToGenerate(node,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();
|
||||
updated = true;
|
||||
@ -215,6 +231,11 @@ public class ClientDrawCellManager {
|
||||
node.isLeaf() &&
|
||||
node.canSplit() &&
|
||||
(
|
||||
(
|
||||
node.getLevel() < this.chunkTree.getMaxLevel() - 2 &&
|
||||
this.getMinDistance(pos, node) <= QUARTER_RES_DIST
|
||||
)
|
||||
||
|
||||
(
|
||||
node.getLevel() < this.chunkTree.getMaxLevel() - 1 &&
|
||||
this.getMinDistance(pos, node) <= HALF_RES_DIST
|
||||
@ -358,10 +379,15 @@ public class ClientDrawCellManager {
|
||||
node.getLevel() == this.chunkTree.getMaxLevel() - 1 &&
|
||||
this.getMinDistance(pos, node) > FULL_RES_DIST
|
||||
)
|
||||
||
|
||||
||
|
||||
(
|
||||
node.getLevel() == this.chunkTree.getMaxLevel() - 2 &&
|
||||
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
|
||||
)
|
||||
||
|
||||
(
|
||||
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
|
||||
)
|
||||
||
|
||||
||
|
||||
(
|
||||
node.getLevel() == this.chunkTree.getMaxLevel() - 1
|
||||
&&
|
||||
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
|
||||
* @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();
|
||||
int lod = this.chunkTree.getMaxLevel() - node.getLevel();
|
||||
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.renderer.meshgen.TransvoxelModelGeneration;
|
||||
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
|
||||
@ -88,6 +87,11 @@ public class DrawCell {
|
||||
* True if there are multiple types of voxels in this chunk
|
||||
*/
|
||||
boolean multiVoxelType = false;
|
||||
|
||||
/**
|
||||
* Number of failed generation attempts
|
||||
*/
|
||||
int failedGenerationAttempts = 0;
|
||||
|
||||
|
||||
/**
|
||||
@ -118,6 +122,7 @@ public class DrawCell {
|
||||
Globals.profiler.endCpuSample();
|
||||
if(!success){
|
||||
this.setHasRequested(false);
|
||||
this.failedGenerationAttempts++;
|
||||
return;
|
||||
}
|
||||
if(modelEntity != null){
|
||||
@ -131,6 +136,7 @@ public class DrawCell {
|
||||
Globals.profiler.endCpuSample();
|
||||
if(!success){
|
||||
this.setHasRequested(false);
|
||||
this.failedGenerationAttempts++;
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -464,6 +470,9 @@ public class DrawCell {
|
||||
*/
|
||||
public void setHasRequested(boolean hasRequested) {
|
||||
this.hasRequested = hasRequested;
|
||||
if(!this.hasRequested){
|
||||
this.failedGenerationAttempts = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -490,6 +499,22 @@ public class DrawCell {
|
||||
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>();
|
||||
|
||||
/**
|
||||
* 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)
|
||||
*/
|
||||
@ -192,6 +197,9 @@ public class ServerChunkCache {
|
||||
case 1: {
|
||||
return cacheMapHalfRes;
|
||||
}
|
||||
case 2: {
|
||||
return cacheMapQuarterRes;
|
||||
}
|
||||
default: {
|
||||
throw new Error("Invalid stride probided! " + stride);
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user