terrain editing/saving work
Some checks failed
studiorailgun/Renderer/pipeline/head There was a failure building this commit

This commit is contained in:
austin 2025-04-15 21:55:54 -04:00
parent 01595f3228
commit ef067a0d34
8 changed files with 52 additions and 18 deletions

View File

@ -16,6 +16,6 @@
- Spawn player in a town with a quest to complete a nearby dungeon - Spawn player in a town with a quest to complete a nearby dungeon
+ bug fixes + bug fixes
Can't drop item out of inventory - Terrain edits do not save
+ unreproducible bugs + unreproducible bugs

View File

@ -1503,6 +1503,7 @@ Associate each server connection with a character ID
Code cleanup Code cleanup
Fix dig script function Fix dig script function
Fix shovel functionality Fix shovel functionality
Terrain editing/saving work

View File

@ -157,8 +157,7 @@ public class SaveUtils {
//write server structures //write server structures
Globals.realmManager.save(saveName); Globals.realmManager.save(saveName);
//close the server LoggerInterface.loggerEngine.WARNING("Finished saving " + saveName);
Globals.server.close();
} }
/** /**

View File

@ -146,9 +146,9 @@ public class ChunkDiskMap {
lock.lock(); lock.lock();
LoggerInterface.loggerEngine.INFO("Load chunk " + worldX + " " + worldY + " " + worldZ); LoggerInterface.loggerEngine.INFO("Load chunk " + worldX + " " + worldY + " " + worldZ);
ServerTerrainChunk rVal = null; ServerTerrainChunk rVal = null;
if(containsTerrainAtPosition(worldX, worldY, worldZ)){ if(this.containsTerrainAtPosition(worldX, worldY, worldZ)){
//read file //read file
String fileName = worldPosFileMap.get(getTerrainChunkKey(worldX, worldY, worldZ)); String fileName = worldPosFileMap.get(ChunkDiskMap.getTerrainChunkKey(worldX, worldY, worldZ));
byte[] rawDataCompressed = FileUtils.loadBinaryFromSavePath(Globals.currentSave.getName(), "/terrain/" + fileName); byte[] rawDataCompressed = FileUtils.loadBinaryFromSavePath(Globals.currentSave.getName(), "/terrain/" + fileName);
//decompress //decompress
byte[] rawData = null; byte[] rawData = null;
@ -209,7 +209,7 @@ public class ChunkDiskMap {
LoggerInterface.loggerEngine.DEBUG("Save to disk: " + terrainChunk.getWorldX() + " " + terrainChunk.getWorldY() + " " + terrainChunk.getWorldZ()); LoggerInterface.loggerEngine.DEBUG("Save to disk: " + terrainChunk.getWorldX() + " " + terrainChunk.getWorldY() + " " + terrainChunk.getWorldZ());
//get the file name for this chunk //get the file name for this chunk
String fileName = null; String fileName = null;
String chunkKey = getTerrainChunkKey(terrainChunk.getWorldX(),terrainChunk.getWorldY(),terrainChunk.getWorldZ()); String chunkKey = ChunkDiskMap.getTerrainChunkKey(terrainChunk.getWorldX(),terrainChunk.getWorldY(),terrainChunk.getWorldZ());
if(worldPosFileMap.containsKey(chunkKey)){ if(worldPosFileMap.containsKey(chunkKey)){
fileName = worldPosFileMap.get(chunkKey); fileName = worldPosFileMap.get(chunkKey);
} else { } else {

View File

@ -12,7 +12,9 @@ import electrosphere.server.terrain.manager.ServerTerrainChunk;
*/ */
public class TerrainEditing { public class TerrainEditing {
//the minimum value before hard setting to 0 /**
* the minimum value before hard setting to 0
*/
static final float MINIMUM_FULL_VALUE = 0.01f; static final float MINIMUM_FULL_VALUE = 0.01f;
/** /**
@ -120,13 +122,14 @@ public class TerrainEditing {
currentPositionMagnitude > 0 && currentPositionMagnitude > 0 &&
(data = voxelCellManager.getChunkAtPosition(chunkPos)) != null (data = voxelCellManager.getChunkAtPosition(chunkPos)) != null
){ ){
int typeAtPos = voxelCellManager.getVoxelTypeAtLocalPosition(chunkPos, voxelPos);
float current = data.getWeights()[voxelPos.x][voxelPos.y][voxelPos.z]; float current = data.getWeights()[voxelPos.x][voxelPos.y][voxelPos.z];
//hard clamp so it doesn't go over 1 //hard clamp so it doesn't go over 1
float finalValue = Math.max(Math.min(current + weight / distance,1),-1); float finalValue = Math.max(Math.min(current + weight / distance,1),-1);
if(finalValue < MINIMUM_FULL_VALUE && current > MINIMUM_FULL_VALUE){ if(finalValue < MINIMUM_FULL_VALUE && current >= MINIMUM_FULL_VALUE){
finalValue = -1; finalValue = -1;
typeAtPos = ServerTerrainChunk.VOXEL_TYPE_AIR;
} }
int typeAtPos = voxelCellManager.getVoxelTypeAtLocalPosition(chunkPos, voxelPos);
voxelCellManager.editChunk(chunkPos, voxelPos, finalValue, typeAtPos); voxelCellManager.editChunk(chunkPos, voxelPos, finalValue, typeAtPos);
} }
} }

View File

@ -9,6 +9,8 @@ import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.concurrent.Semaphore; import java.util.concurrent.Semaphore;
import electrosphere.server.terrain.diskmap.ChunkDiskMap;
/** /**
* Caches chunk data on the server * Caches chunk data on the server
*/ */
@ -64,11 +66,24 @@ public class ServerChunkCache {
*/ */
Semaphore lock = new Semaphore(1); Semaphore lock = new Semaphore(1);
/**
* The disk map to use for file io
*/
ChunkDiskMap chunkDiskMap;
/**
* Constructor
* @param diskMap The disk map to use for file io
*/
public ServerChunkCache(ChunkDiskMap chunkDiskMap){
this.chunkDiskMap = chunkDiskMap;
}
/** /**
* Gets the collection of server terrain chunks that are cached * Gets the collection of server terrain chunks that are cached
* @return The collection of chunks * @return The collection of chunks
*/ */
public Collection<ServerTerrainChunk> getContents(){ public Collection<ServerTerrainChunk> getFullRes(){
lock.acquireUninterruptibly(); lock.acquireUninterruptibly();
Collection<ServerTerrainChunk> rVal = Collections.unmodifiableCollection(cacheMapFullRes.values()); Collection<ServerTerrainChunk> rVal = Collections.unmodifiableCollection(cacheMapFullRes.values());
lock.release(); lock.release();
@ -100,10 +115,11 @@ public class ServerChunkCache {
ServerTerrainChunk rVal = null; ServerTerrainChunk rVal = null;
Long key = this.getKey(worldX, worldY, worldZ); Long key = this.getKey(worldX, worldY, worldZ);
lock.acquireUninterruptibly(); lock.acquireUninterruptibly();
queryRecencyQueue.remove(key); if(queryRecencyQueue.remove(key)){
queryRecencyQueue.add(0, key); queryRecencyQueue.add(0, key);
Map<Long,ServerTerrainChunk> cache = this.getCache(stride); Map<Long,ServerTerrainChunk> cache = this.getCache(stride);
rVal = cache.get(key); rVal = cache.get(key);
}
lock.release(); lock.release();
return rVal; return rVal;
} }
@ -124,7 +140,10 @@ public class ServerChunkCache {
cache.put(key, chunk); cache.put(key, chunk);
while(queryRecencyQueue.size() > cacheSize){ while(queryRecencyQueue.size() > cacheSize){
Long oldKey = queryRecencyQueue.remove(queryRecencyQueue.size() - 1); Long oldKey = queryRecencyQueue.remove(queryRecencyQueue.size() - 1);
cacheMapFullRes.remove(oldKey); ServerTerrainChunk fullRes = cacheMapFullRes.remove(oldKey);
if(fullRes != null){
this.chunkDiskMap.saveToDisk(fullRes);
}
cacheMapHalfRes.remove(oldKey); cacheMapHalfRes.remove(oldKey);
cacheMapQuarterRes.remove(oldKey); cacheMapQuarterRes.remove(oldKey);
cacheMapEighthRes.remove(oldKey); cacheMapEighthRes.remove(oldKey);

View File

@ -27,6 +27,11 @@ public class ServerTerrainChunk {
*/ */
public static final int CHUNK_PLACEMENT_OFFSET = CHUNK_DATA_GENERATOR_SIZE - 1; public static final int CHUNK_PLACEMENT_OFFSET = CHUNK_DATA_GENERATOR_SIZE - 1;
/**
* An empty terrain voxel
*/
public static final int VOXEL_TYPE_AIR = 0;
/** /**
* Gets the x coordinate of the world position of the chunk * Gets the x coordinate of the world position of the chunk
*/ */

View File

@ -44,7 +44,9 @@ public class ServerTerrainManager {
*/ */
public static final int VERTICAL_INTERPOLATION_RATIO = 50; public static final int VERTICAL_INTERPOLATION_RATIO = 50;
//the interpolation width of a server terrain manager is hard coded at the moment to make sure it's divisible by the sub chunk calculations /**
* the interpolation width of a server terrain manager is hard coded at the moment to make sure it's divisible by the sub chunk calculations
*/
public static final int SERVER_TERRAIN_MANAGER_INTERPOLATION_RATIO = 128; public static final int SERVER_TERRAIN_MANAGER_INTERPOLATION_RATIO = 128;
/** /**
@ -67,7 +69,7 @@ public class ServerTerrainManager {
* The cache of chunks * The cache of chunks
*/ */
@Exclude @Exclude
ServerChunkCache chunkCache = new ServerChunkCache(); ServerChunkCache chunkCache;
//The map of chunk position <-> file on disk containing chunk data //The map of chunk position <-> file on disk containing chunk data
ChunkDiskMap chunkDiskMap = null; ChunkDiskMap chunkDiskMap = null;
@ -108,6 +110,7 @@ public class ServerTerrainManager {
generator.generate(this.model); generator.generate(this.model);
this.chunkGenerator.setModel(this.model); this.chunkGenerator.setModel(this.model);
this.chunkDiskMap = ChunkDiskMap.init(); this.chunkDiskMap = ChunkDiskMap.init();
this.chunkCache = new ServerChunkCache(this.chunkDiskMap);
} }
/** /**
@ -123,6 +126,7 @@ public class ServerTerrainManager {
generator.generate(this.model); generator.generate(this.model);
this.chunkGenerator.setModel(this.model); this.chunkGenerator.setModel(this.model);
this.chunkDiskMap = ChunkDiskMap.init(); this.chunkDiskMap = ChunkDiskMap.init();
this.chunkCache = new ServerChunkCache(this.chunkDiskMap);
} }
/** /**
@ -165,7 +169,7 @@ public class ServerTerrainManager {
FileUtils.saveBinaryToSavePath(saveName, "./biome.dat", shortBuff.array()); FileUtils.saveBinaryToSavePath(saveName, "./biome.dat", shortBuff.array());
} }
//for each chunk, save via disk map //for each chunk, save via disk map
for(ServerTerrainChunk chunk : this.chunkCache.getContents()){ for(ServerTerrainChunk chunk : this.chunkCache.getFullRes()){
chunkDiskMap.saveToDisk(chunk); chunkDiskMap.saveToDisk(chunk);
} }
//save disk map itself //save disk map itself
@ -219,6 +223,9 @@ public class ServerTerrainManager {
} }
//load chunk disk map //load chunk disk map
chunkDiskMap = ChunkDiskMap.init(saveName); chunkDiskMap = ChunkDiskMap.init(saveName);
//init cache
this.chunkCache = new ServerChunkCache(this.chunkDiskMap);
} }
/** /**