164 lines
4.6 KiB
Java
164 lines
4.6 KiB
Java
package electrosphere.client.terrain.cache;
|
|
|
|
import java.util.Collection;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
import java.util.concurrent.ConcurrentHashMap;
|
|
import java.util.concurrent.CopyOnWriteArrayList;
|
|
|
|
import org.joml.Vector3i;
|
|
|
|
import io.github.studiorailgun.HashUtils;
|
|
|
|
|
|
/**
|
|
* Acts as a cache in front of terrain model to streamline receiving chunks
|
|
*/
|
|
public class ClientTerrainCache {
|
|
|
|
/**
|
|
* Cache capacity
|
|
*/
|
|
int cacheSize;
|
|
|
|
/**
|
|
* The map of full res chunk key -> chunk data
|
|
*/
|
|
Map<Long,ChunkData> cacheMapFullRes = new ConcurrentHashMap<Long,ChunkData>();
|
|
|
|
/**
|
|
* The map of half res chunk key -> chunk data
|
|
*/
|
|
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
|
|
*/
|
|
List<Long> cacheList = new CopyOnWriteArrayList<Long>();
|
|
|
|
/**
|
|
* A map of chunk to its world position
|
|
*/
|
|
Map<ChunkData,Vector3i> chunkPositionMap = new ConcurrentHashMap<ChunkData,Vector3i>();
|
|
|
|
/**
|
|
* Constructor
|
|
* @param cacheSize The capacity of the cache
|
|
*/
|
|
public ClientTerrainCache(int cacheSize){
|
|
this.cacheSize = cacheSize;
|
|
}
|
|
|
|
/**
|
|
* Adds a chunk data to the terrain cache
|
|
* @param worldX The x world position
|
|
* @param worldY The y world position
|
|
* @param worldZ The z world position
|
|
* @param chunkData The chunk data to add at the specified positions
|
|
*/
|
|
public void addChunkDataToCache(int worldX, int worldY, int worldZ, ChunkData chunkData){
|
|
Map<Long,ChunkData> cache = this.getCache(chunkData.getStride());
|
|
cache.put(getKey(worldX,worldY,worldZ),chunkData);
|
|
chunkPositionMap.put(chunkData,new Vector3i(worldX,worldY,worldZ));
|
|
while(cacheList.size() > cacheSize){
|
|
Long currentChunk = cacheList.remove(0);
|
|
cache.remove(currentChunk);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Evicts all chunks from the cache
|
|
*/
|
|
public void evictAll(){
|
|
this.cacheList.clear();
|
|
this.cacheMapFullRes.clear();
|
|
this.cacheMapHalfRes.clear();
|
|
this.chunkPositionMap.clear();
|
|
}
|
|
|
|
|
|
/**
|
|
* Generates a key for the cache based on the position provided
|
|
* @param worldX The x world position
|
|
* @param worldY The y world position
|
|
* @param worldZ The z world position
|
|
* @return The cache key
|
|
*/
|
|
public long getKey(int worldX, int worldY, int worldZ){
|
|
return HashUtils.cantorHash(worldX, worldY, worldZ);
|
|
}
|
|
|
|
/**
|
|
* Checks whether the cache contains chunk data at a given world point
|
|
* @param worldX The x world position
|
|
* @param worldY The y world position
|
|
* @param worldZ The z world position
|
|
* @param stride The stride of the data
|
|
* @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){
|
|
return this.getCache(stride).containsKey(getKey(worldX,worldY,worldZ));
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
* Gets chunk data at the given world point
|
|
* @param worldX The x world position
|
|
* @param worldY The y world position
|
|
* @param worldZ The z world position
|
|
* @param stride The stride of the data
|
|
* @return The chunk data if it exists, null otherwise
|
|
*/
|
|
public ChunkData getSubChunkDataAtPoint(int worldX, int worldY, int worldZ, int stride){
|
|
return this.getCache(stride).get(getKey(worldX,worldY,worldZ));
|
|
}
|
|
|
|
/**
|
|
* Gets the list of all chunks in the cache
|
|
* @return The list of all chunks in the cache
|
|
*/
|
|
public Collection<ChunkData> getAllChunks(){
|
|
return this.cacheMapFullRes.values();
|
|
}
|
|
|
|
/**
|
|
* Gets the world position of a chunk
|
|
* @param chunk The chunk
|
|
* @return The world position of the chunk
|
|
*/
|
|
public Vector3i getChunkPosition(ChunkData chunk){
|
|
return chunkPositionMap.get(chunk);
|
|
}
|
|
|
|
/**
|
|
* Gets the cache
|
|
* @param stride The stride of the data
|
|
* @return The cache to use
|
|
*/
|
|
public Map<Long,ChunkData> getCache(int stride){
|
|
switch(stride){
|
|
case 0: {
|
|
return cacheMapFullRes;
|
|
}
|
|
case 1: {
|
|
return cacheMapHalfRes;
|
|
}
|
|
case 2: {
|
|
return cacheMapQuarterRes;
|
|
}
|
|
default: {
|
|
throw new Error("Invalid stride probided! " + stride);
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|