add mechanism to deduplicate outgoing requests
Some checks failed
studiorailgun/Renderer/pipeline/pr-master There was a failure building this commit
Some checks failed
studiorailgun/Renderer/pipeline/pr-master There was a failure building this commit
This commit is contained in:
parent
e6fdac489c
commit
f7cc0b4dcf
@ -5,6 +5,7 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.concurrent.CopyOnWriteArrayList;
|
import java.util.concurrent.CopyOnWriteArrayList;
|
||||||
|
import java.util.concurrent.Semaphore;
|
||||||
|
|
||||||
import org.joml.Vector3i;
|
import org.joml.Vector3i;
|
||||||
|
|
||||||
@ -50,6 +51,11 @@ public class ClientTerrainCache {
|
|||||||
* A map of chunk to its world position
|
* A map of chunk to its world position
|
||||||
*/
|
*/
|
||||||
Map<ChunkData,Vector3i> chunkPositionMap = new ConcurrentHashMap<ChunkData,Vector3i>();
|
Map<ChunkData,Vector3i> chunkPositionMap = new ConcurrentHashMap<ChunkData,Vector3i>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The lock on the terrain cache
|
||||||
|
*/
|
||||||
|
Semaphore lock = new Semaphore(1);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
@ -67,6 +73,7 @@ public class ClientTerrainCache {
|
|||||||
* @param chunkData The chunk data to add at the specified positions
|
* @param chunkData The chunk data to add at the specified positions
|
||||||
*/
|
*/
|
||||||
public void addChunkDataToCache(int worldX, int worldY, int worldZ, ChunkData chunkData){
|
public void addChunkDataToCache(int worldX, int worldY, int worldZ, ChunkData chunkData){
|
||||||
|
lock.acquireUninterruptibly();
|
||||||
Map<Long,ChunkData> cache = this.getCache(chunkData.getStride());
|
Map<Long,ChunkData> cache = this.getCache(chunkData.getStride());
|
||||||
cache.put(getKey(worldX,worldY,worldZ),chunkData);
|
cache.put(getKey(worldX,worldY,worldZ),chunkData);
|
||||||
chunkPositionMap.put(chunkData,new Vector3i(worldX,worldY,worldZ));
|
chunkPositionMap.put(chunkData,new Vector3i(worldX,worldY,worldZ));
|
||||||
@ -74,16 +81,19 @@ public class ClientTerrainCache {
|
|||||||
Long currentChunk = cacheList.remove(0);
|
Long currentChunk = cacheList.remove(0);
|
||||||
cache.remove(currentChunk);
|
cache.remove(currentChunk);
|
||||||
}
|
}
|
||||||
|
lock.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Evicts all chunks from the cache
|
* Evicts all chunks from the cache
|
||||||
*/
|
*/
|
||||||
public void evictAll(){
|
public void evictAll(){
|
||||||
|
lock.acquireUninterruptibly();
|
||||||
this.cacheList.clear();
|
this.cacheList.clear();
|
||||||
this.cacheMapFullRes.clear();
|
this.cacheMapFullRes.clear();
|
||||||
this.cacheMapHalfRes.clear();
|
this.cacheMapHalfRes.clear();
|
||||||
this.chunkPositionMap.clear();
|
this.chunkPositionMap.clear();
|
||||||
|
lock.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -107,7 +117,10 @@ public class ClientTerrainCache {
|
|||||||
* @return True if the cache contains chunk data at the specified point, false otherwise
|
* @return True if the cache contains chunk data at the specified point, false otherwise
|
||||||
*/
|
*/
|
||||||
public boolean containsChunkDataAtWorldPoint(int worldX, int worldY, int worldZ, int stride){
|
public boolean containsChunkDataAtWorldPoint(int worldX, int worldY, int worldZ, int stride){
|
||||||
return this.getCache(stride).containsKey(getKey(worldX,worldY,worldZ));
|
lock.acquireUninterruptibly();
|
||||||
|
boolean rVal = this.getCache(stride).containsKey(getKey(worldX,worldY,worldZ));
|
||||||
|
lock.release();
|
||||||
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -123,7 +136,10 @@ public class ClientTerrainCache {
|
|||||||
* @return The chunk data if it exists, null otherwise
|
* @return The chunk data if it exists, null otherwise
|
||||||
*/
|
*/
|
||||||
public ChunkData getSubChunkDataAtPoint(int worldX, int worldY, int worldZ, int stride){
|
public ChunkData getSubChunkDataAtPoint(int worldX, int worldY, int worldZ, int stride){
|
||||||
return this.getCache(stride).get(getKey(worldX,worldY,worldZ));
|
lock.acquireUninterruptibly();
|
||||||
|
ChunkData rVal = this.getCache(stride).get(getKey(worldX,worldY,worldZ));
|
||||||
|
lock.release();
|
||||||
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -602,8 +602,9 @@ 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
|
||||||
|
* @return true if all cells were successfully requested, false otherwise
|
||||||
*/
|
*/
|
||||||
private void requestChunks(WorldOctTree.FloatingChunkTreeNode<DrawCell> node, List<DrawCellFace> highResFaces){
|
private boolean 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);
|
||||||
@ -622,7 +623,9 @@ public class ClientDrawCellManager {
|
|||||||
){
|
){
|
||||||
//client should request chunk data from server for each chunk necessary to create the model
|
//client should request chunk data from server for each chunk necessary to create the model
|
||||||
LoggerInterface.loggerNetworking.DEBUG("(Client) Send Request for terrain at " + posToCheck);
|
LoggerInterface.loggerNetworking.DEBUG("(Client) Send Request for terrain at " + posToCheck);
|
||||||
Globals.clientTerrainManager.requestChunk(posToCheck.x, posToCheck.y, posToCheck.z, lod);
|
if(!Globals.clientTerrainManager.requestChunk(posToCheck.x, posToCheck.y, posToCheck.z, lod)){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -666,12 +669,15 @@ public class ClientDrawCellManager {
|
|||||||
!Globals.clientTerrainManager.containsChunkDataAtWorldPoint(posToCheck.x, posToCheck.y, posToCheck.z, highResLod)
|
!Globals.clientTerrainManager.containsChunkDataAtWorldPoint(posToCheck.x, posToCheck.y, posToCheck.z, highResLod)
|
||||||
){
|
){
|
||||||
LoggerInterface.loggerNetworking.DEBUG("(Client) Send Request for terrain at " + posToCheck);
|
LoggerInterface.loggerNetworking.DEBUG("(Client) Send Request for terrain at " + posToCheck);
|
||||||
Globals.clientTerrainManager.requestChunk(posToCheck.x, posToCheck.y, posToCheck.z, highResLod);
|
if(!Globals.clientTerrainManager.requestChunk(posToCheck.x, posToCheck.y, posToCheck.z, highResLod)){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -6,7 +6,9 @@ import java.nio.IntBuffer;
|
|||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.concurrent.CopyOnWriteArrayList;
|
import java.util.concurrent.CopyOnWriteArrayList;
|
||||||
import java.util.concurrent.Semaphore;
|
import java.util.concurrent.Semaphore;
|
||||||
|
|
||||||
@ -25,6 +27,7 @@ import electrosphere.renderer.meshgen.TerrainChunkModelGeneration;
|
|||||||
import electrosphere.renderer.model.Model;
|
import electrosphere.renderer.model.Model;
|
||||||
import electrosphere.server.terrain.manager.ServerTerrainChunk;
|
import electrosphere.server.terrain.manager.ServerTerrainChunk;
|
||||||
import electrosphere.server.terrain.manager.ServerTerrainManager;
|
import electrosphere.server.terrain.manager.ServerTerrainManager;
|
||||||
|
import io.github.studiorailgun.HashUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Manages terrain storage and access on the client
|
* Manages terrain storage and access on the client
|
||||||
@ -58,6 +61,11 @@ public class ClientTerrainManager {
|
|||||||
|
|
||||||
//The queue of terrain chunk data to be buffered to gpu
|
//The queue of terrain chunk data to be buffered to gpu
|
||||||
static List<TerrainChunkGenQueueItem> terrainChunkGenerationQueue = new CopyOnWriteArrayList<TerrainChunkGenQueueItem>();
|
static List<TerrainChunkGenQueueItem> terrainChunkGenerationQueue = new CopyOnWriteArrayList<TerrainChunkGenQueueItem>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tracks what outgoing requests are currently active
|
||||||
|
*/
|
||||||
|
Map<Long,Boolean> requestedMap = new ConcurrentHashMap<Long,Boolean>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
@ -134,6 +142,8 @@ public class ClientTerrainManager {
|
|||||||
message.getworldX(), message.getworldY(), message.getworldZ(),
|
message.getworldX(), message.getworldY(), message.getworldZ(),
|
||||||
data
|
data
|
||||||
);
|
);
|
||||||
|
//remove from request map
|
||||||
|
this.requestedMap.remove(this.getRequestKey(message.getworldX(), message.getworldY(), message.getworldZ(), message.getchunkResolution()));
|
||||||
} break;
|
} break;
|
||||||
default:
|
default:
|
||||||
LoggerInterface.loggerEngine.WARNING("ClientTerrainManager: unhandled network message of type" + message.getMessageSubtype());
|
LoggerInterface.loggerEngine.WARNING("ClientTerrainManager: unhandled network message of type" + message.getMessageSubtype());
|
||||||
@ -192,14 +202,23 @@ public class ClientTerrainManager {
|
|||||||
* @param worldY the world y coordinate of the chunk
|
* @param worldY the world y coordinate of the chunk
|
||||||
* @param worldZ the world z coordinate of the chunk
|
* @param worldZ the world z coordinate of the chunk
|
||||||
* @param stride The stride of the data
|
* @param stride The stride of the data
|
||||||
|
* @return true if the request was successfully sent, false otherwise
|
||||||
*/
|
*/
|
||||||
public void requestChunk(int worldX, int worldY, int worldZ, int stride){
|
public boolean requestChunk(int worldX, int worldY, int worldZ, int stride){
|
||||||
Globals.clientConnection.queueOutgoingMessage(TerrainMessage.constructRequestReducedChunkDataMessage(
|
boolean rVal = false;
|
||||||
worldX,
|
lock.acquireUninterruptibly();
|
||||||
worldY,
|
if(!this.requestedMap.containsKey(this.getRequestKey(worldX, worldY, worldZ, stride))){
|
||||||
worldZ,
|
Globals.clientConnection.queueOutgoingMessage(TerrainMessage.constructRequestReducedChunkDataMessage(
|
||||||
stride
|
worldX,
|
||||||
));
|
worldY,
|
||||||
|
worldZ,
|
||||||
|
stride
|
||||||
|
));
|
||||||
|
this.requestedMap.put(this.getRequestKey(worldX, worldY, worldZ, stride), true);
|
||||||
|
rVal = true;
|
||||||
|
}
|
||||||
|
lock.release();
|
||||||
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -273,5 +292,17 @@ public class ClientTerrainManager {
|
|||||||
public Vector3i getPositionOfChunk(ChunkData chunk){
|
public Vector3i getPositionOfChunk(ChunkData chunk){
|
||||||
return terrainCache.getChunkPosition(chunk);
|
return terrainCache.getChunkPosition(chunk);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the key for a given request
|
||||||
|
* @param worldX The world x coordinate
|
||||||
|
* @param worldY The world y coordinate
|
||||||
|
* @param worldZ The world z coordinate
|
||||||
|
* @param stride The stride of the data
|
||||||
|
* @return The key
|
||||||
|
*/
|
||||||
|
private Long getRequestKey(int worldX, int worldY, int worldZ, int stride){
|
||||||
|
return (long)HashUtils.cantorHash(worldY, worldZ, worldZ);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user