153 lines
4.8 KiB
Java
153 lines
4.8 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 chunk key -> chunk data
|
|
Map<Long,ChunkData> cacheMap = 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>();
|
|
|
|
/**
|
|
* The map tracking chunks that have been requested
|
|
*/
|
|
Map<Long,Boolean> requestedChunks = new ConcurrentHashMap<Long,Boolean>();
|
|
|
|
/**
|
|
* 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){
|
|
cacheMap.put(getKey(worldX,worldY,worldZ),chunkData);
|
|
chunkPositionMap.put(chunkData,new Vector3i(worldX,worldY,worldZ));
|
|
while(cacheList.size() > cacheSize){
|
|
Long currentChunk = cacheList.remove(0);
|
|
ChunkData data = cacheMap.remove(currentChunk);
|
|
Vector3i worldPos = data.getWorldPos();
|
|
requestedChunks.remove(getKey(worldPos.x,worldPos.y,worldPos.z));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Evicts all chunks from the cache
|
|
*/
|
|
public void evictAll(){
|
|
this.cacheList.clear();
|
|
this.cacheMap.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
|
|
* @return True if the cache contains chunk data at the specified point, false otherwise
|
|
*/
|
|
public boolean containsChunkDataAtWorldPoint(int worldX, int worldY, int worldZ){
|
|
return cacheMap.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
|
|
* @return The chunk data if it exists, null otherwise
|
|
*/
|
|
public ChunkData getSubChunkDataAtPoint(int worldX, int worldY, int worldZ){
|
|
return cacheMap.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.cacheMap.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 number of cells that have been requested
|
|
* @return The number of cells that have been requested
|
|
*/
|
|
public int getRequestedCellCount(){
|
|
return this.requestedChunks.size();
|
|
}
|
|
|
|
/**
|
|
* Checks if a chunk has been requested or not
|
|
* @param worldX The x coordinate in the world
|
|
* @param worldY The y coordinate in the world
|
|
* @param worldZ The z coordinate in the world
|
|
* @return true if it has been requested, false otherwise
|
|
*/
|
|
public boolean hasRequested(int worldX, int worldY, int worldZ){
|
|
return this.requestedChunks.containsKey(getKey(worldX, worldY, worldZ));
|
|
}
|
|
|
|
/**
|
|
* Marks a chunk as requested
|
|
* @param worldX The x coordinate in the world
|
|
* @param worldY The y coordinate in the world
|
|
* @param worldZ The z coordinate in the world
|
|
*/
|
|
public void markAsRequested(int worldX, int worldY, int worldZ){
|
|
this.requestedChunks.put(getKey(worldX, worldY, worldZ),true);
|
|
}
|
|
|
|
}
|