fixes and cursor work
All checks were successful
studiorailgun/Renderer/pipeline/head This commit looks good

This commit is contained in:
austin 2025-04-27 17:25:39 -04:00
parent 8859b639ca
commit c96c07334a
8 changed files with 74 additions and 61 deletions

View File

@ -1569,6 +1569,10 @@ Fix block meshgen
(04/27/2025) (04/27/2025)
Fab cursor rotation + actually place rotated fab Fab cursor rotation + actually place rotated fab
Fix terrain and blocks not saving/loading to/from disk Fix terrain and blocks not saving/loading to/from disk
Fix swapping to/from editor entity in main game mode
Block cursor work
ChunkDiskMap code org
Filter procedural worlds out of level select menu

View File

@ -4,7 +4,6 @@ import org.joml.Vector3i;
import electrosphere.client.script.ScriptClientVoxelUtils; import electrosphere.client.script.ScriptClientVoxelUtils;
import electrosphere.engine.Globals; import electrosphere.engine.Globals;
import electrosphere.entity.EntityUtils;
/** /**
* Utilities for editing blocks * Utilities for editing blocks
@ -17,9 +16,9 @@ public class BlockEditing {
* @param metadata The metadata of the block * @param metadata The metadata of the block
*/ */
public static void editBlock(short type, short metadata){ public static void editBlock(short type, short metadata){
Vector3i cornerVoxel = Globals.cursorState.getBlockCornerVoxelPos(); Vector3i cornerVoxel = Globals.clientWorldData.convertRealToBlockSpace(Globals.cursorState.getBlockCursorPos());
int blockSize = Globals.cursorState.getBlockSize(); int blockSize = Globals.cursorState.getBlockSize();
Vector3i chunkPos = Globals.clientWorldData.convertRealToWorldSpace(EntityUtils.getPosition(Globals.playerBlockCursor)); Vector3i chunkPos = Globals.clientWorldData.convertRealToWorldSpace(Globals.cursorState.getBlockCursorPos());
ScriptClientVoxelUtils.clientRequestEditBlock(chunkPos, cornerVoxel, type, metadata, blockSize); ScriptClientVoxelUtils.clientRequestEditBlock(chunkPos, cornerVoxel, type, metadata, blockSize);
} }
@ -27,9 +26,9 @@ public class BlockEditing {
* Destroy blocks * Destroy blocks
*/ */
public static void destroyBlock(){ public static void destroyBlock(){
Vector3i cornerVoxel = Globals.cursorState.getBlockCornerVoxelPos(); Vector3i cornerVoxel = Globals.clientWorldData.convertRealToBlockSpace(Globals.cursorState.getBlockCursorPos());
int blockSize = Globals.cursorState.getBlockSize(); int blockSize = Globals.cursorState.getBlockSize();
Vector3i chunkPos = Globals.clientWorldData.convertRealToWorldSpace(EntityUtils.getPosition(Globals.playerBlockCursor)); Vector3i chunkPos = Globals.clientWorldData.convertRealToWorldSpace(Globals.cursorState.getBlockCursorPos());
ScriptClientVoxelUtils.clientRequestEditBlock(chunkPos, cornerVoxel, (short)0, (short)0, blockSize); ScriptClientVoxelUtils.clientRequestEditBlock(chunkPos, cornerVoxel, (short)0, (short)0, blockSize);
} }

View File

@ -16,7 +16,6 @@ import org.joml.Vector3i;
import electrosphere.client.block.BlockChunkCache; import electrosphere.client.block.BlockChunkCache;
import electrosphere.client.block.BlockChunkData; import electrosphere.client.block.BlockChunkData;
import electrosphere.client.scene.ClientWorldData;
import electrosphere.client.terrain.cache.ChunkData; import electrosphere.client.terrain.cache.ChunkData;
import electrosphere.client.terrain.cache.ClientTerrainCache; import electrosphere.client.terrain.cache.ClientTerrainCache;
import electrosphere.client.terrain.cells.ClientDrawCellManager; import electrosphere.client.terrain.cells.ClientDrawCellManager;
@ -39,13 +38,15 @@ import electrosphere.util.math.HashUtils;
*/ */
public class ClientTerrainManager { public class ClientTerrainManager {
//queues messages from server /**
List<TerrainMessage> messageQueue = new LinkedList<TerrainMessage>(); * queues messages from server
*/
private List<TerrainMessage> messageQueue = new LinkedList<TerrainMessage>();
/** /**
* Locks the terrain manager (eg if adding message from network) * Locks the terrain manager (eg if adding message from network)
*/ */
static Semaphore lock = new Semaphore(1); private static Semaphore lock = new Semaphore(1);
/** /**
* Maximum concurrent terrain requests * Maximum concurrent terrain requests
@ -57,10 +58,14 @@ public class ClientTerrainManager {
*/ */
public static final int FAILED_REQUEST_THRESHOLD = 500; public static final int FAILED_REQUEST_THRESHOLD = 500;
//The interpolation ratio of terrain /**
* The interpolation ratio of terrain
*/
public static final int INTERPOLATION_RATIO = ServerTerrainManager.SERVER_TERRAIN_MANAGER_INTERPOLATION_RATIO; public static final int INTERPOLATION_RATIO = ServerTerrainManager.SERVER_TERRAIN_MANAGER_INTERPOLATION_RATIO;
//caches chunks from server /**
* caches chunks from server
*/
static final int CACHE_SIZE = 2500 + (int)(ClientDrawCellManager.FULL_RES_DIST * 10) + (int)(ClientDrawCellManager.HALF_RES_DIST * 10); static final int CACHE_SIZE = 2500 + (int)(ClientDrawCellManager.FULL_RES_DIST * 10) + (int)(ClientDrawCellManager.HALF_RES_DIST * 10);
/** /**
@ -71,37 +76,32 @@ public class ClientTerrainManager {
/** /**
* used for caching the macro values * used for caching the macro values
*/ */
ClientTerrainCache terrainCache; private ClientTerrainCache terrainCache;
/** /**
* Caches block data * Caches block data
*/ */
BlockChunkCache blockCache; private BlockChunkCache blockCache;
/**
* The world data for the client
*/
ClientWorldData clientWorldData;
/** /**
* 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 LinkedList<TerrainChunkGenQueueItem>(); private static List<TerrainChunkGenQueueItem> terrainChunkGenerationQueue = new LinkedList<TerrainChunkGenQueueItem>();
/** /**
* Tracks what outgoing requests are currently active * Tracks what outgoing requests are currently active
*/ */
Map<Long,Integer> requestedMap = new HashMap<Long,Integer>(); private Map<Long,Integer> requestedMap = new HashMap<Long,Integer>();
/** /**
* Tracks what outgoing block requests are currently active * Tracks what outgoing block requests are currently active
*/ */
Map<Long,Integer> requestedBlockMap = new HashMap<Long,Integer>(); private Map<Long,Integer> requestedBlockMap = new HashMap<Long,Integer>();
/** /**
* Used to clear the request map * Used to clear the request map
*/ */
List<Long> toClearFailedRequests = new LinkedList<Long>(); private List<Long> toClearFailedRequests = new LinkedList<Long>();
/** /**
* Constructor * Constructor

View File

@ -1,6 +1,7 @@
package electrosphere.client.ui.menu.mainmenu; package electrosphere.client.ui.menu.mainmenu;
import java.util.List; import java.util.List;
import java.util.stream.Collectors;
import electrosphere.client.ui.components.InputMacros; import electrosphere.client.ui.components.InputMacros;
import electrosphere.client.ui.components.VoxelSelectionPanel; import electrosphere.client.ui.components.VoxelSelectionPanel;
@ -114,7 +115,9 @@ public class MenuGeneratorsLevelEditor {
existingLevelColumn.setAlignContent(YogaAlignment.Start); existingLevelColumn.setAlignContent(YogaAlignment.Start);
rVal.addChild(existingLevelColumn); rVal.addChild(existingLevelColumn);
List<String> saveNames = SaveUtils.getSaves(); List<String> saveNames = SaveUtils.getSaves().stream().filter((String saveName) -> {
return !SaveUtils.isProcedural(saveName);
}).collect(Collectors.toList());
for(String saveName : saveNames){ for(String saveName : saveNames){
//delete level button //delete level button

View File

@ -4,7 +4,6 @@ import java.util.Arrays;
import org.joml.Quaterniond; import org.joml.Quaterniond;
import org.joml.Vector3d; import org.joml.Vector3d;
import org.joml.Vector3i;
import electrosphere.client.block.BlockChunkData; import electrosphere.client.block.BlockChunkData;
import electrosphere.client.entity.camera.CameraEntityUtils; import electrosphere.client.entity.camera.CameraEntityUtils;
@ -249,20 +248,21 @@ public class CursorState {
double y = 0; double y = 0;
double z = 0; double z = 0;
double sizeMult = BlockChunkData.BLOCK_SIZE_MULTIPLIER * blockSize; double sizeMult = BlockChunkData.BLOCK_SIZE_MULTIPLIER * blockSize;
if(input.x % sizeMult > sizeMult / 2.0){ double alignMult = BlockChunkData.BLOCK_SIZE_MULTIPLIER;
x = input.x - input.x % sizeMult + sizeMult + sizeMult / 2.0; if(input.x % alignMult > alignMult / 2.0){
x = input.x - input.x % alignMult + alignMult + sizeMult / 2.0;
} else { } else {
x = input.x - input.x % sizeMult + sizeMult / 2.0; x = input.x - input.x % alignMult + sizeMult / 2.0;
} }
if(input.y % sizeMult > sizeMult / 2.0){ if(input.y % alignMult > alignMult / 2.0){
y = input.y - input.y % sizeMult + sizeMult + sizeMult / 2.0; y = input.y - input.y % alignMult + alignMult + sizeMult / 2.0;
} else { } else {
y = input.y - input.y % sizeMult + sizeMult / 2.0; y = input.y - input.y % alignMult + sizeMult / 2.0;
} }
if(input.z % sizeMult > sizeMult / 2.0){ if(input.z % alignMult > alignMult / 2.0){
z = input.z - input.z % sizeMult + sizeMult + sizeMult / 2.0; z = input.z - input.z % alignMult + alignMult + sizeMult / 2.0;
} else { } else {
z = input.z - input.z % sizeMult + sizeMult / 2.0; z = input.z - input.z % alignMult + sizeMult / 2.0;
} }
return new Vector3d(x,y,z); return new Vector3d(x,y,z);
} }
@ -276,36 +276,33 @@ public class CursorState {
double x = 0; double x = 0;
double y = 0; double y = 0;
double z = 0; double z = 0;
double sizeMult = BlockChunkData.BLOCK_SIZE_MULTIPLIER * blockSize; double alignMult = BlockChunkData.BLOCK_SIZE_MULTIPLIER;
if(input.x % sizeMult > sizeMult / 2.0){ if(input.x % alignMult > alignMult / 2.0){
x = input.x - input.x % sizeMult + sizeMult; x = input.x - input.x % alignMult + alignMult;
} else { } else {
x = input.x - input.x % sizeMult; x = input.x - input.x % alignMult;
} }
if(input.y % sizeMult > sizeMult / 2.0){ if(input.y % alignMult > alignMult / 2.0){
y = input.y - input.y % sizeMult + sizeMult; y = input.y - input.y % alignMult + alignMult;
} else { } else {
y = input.y - input.y % sizeMult; y = input.y - input.y % alignMult;
} }
if(input.z % sizeMult > sizeMult / 2.0){ if(input.z % alignMult > alignMult / 2.0){
z = input.z - input.z % sizeMult + sizeMult; z = input.z - input.z % alignMult + alignMult;
} else { } else {
z = input.z - input.z % sizeMult; z = input.z - input.z % alignMult;
} }
return new Vector3d(x,y,z); return new Vector3d(x,y,z);
} }
/** /**
* Gets the voxel space position of the corner of the block cursor * Gets the block cursor position
* @return The voxel space position * @return The block cursor position
*/ */
public Vector3i getBlockCornerVoxelPos(){ public Vector3d getBlockCursorPos(){
if(Globals.playerBlockCursor == null){ double sizeMult = BlockChunkData.BLOCK_SIZE_MULTIPLIER * blockSize;
throw new Error("Block cursor is null!"); Vector3d posRaw = new Vector3d(EntityUtils.getPosition(Globals.playerBlockCursor)).sub(sizeMult/2.0,sizeMult/2.0,sizeMult/2.0);
} return posRaw;
Vector3d realPos = EntityUtils.getPosition(Globals.playerBlockCursor);
Vector3d clamped = this.clampPositionToBlockCorner(realPos);
return Globals.clientWorldData.convertRealToBlockSpace(clamped);
} }
/** /**

View File

@ -117,7 +117,7 @@ public class CharacterProtocol implements ServerProtocolTemplate<CharacterMessag
*/ */
static Entity swapPlayerCharacter(ServerConnectionHandler connectionHandler){ static Entity swapPlayerCharacter(ServerConnectionHandler connectionHandler){
//change the connection handler's creature template //change the connection handler's creature template
if(connectionHandler.getCurrentCreatureTemplate().getCreatureType().matches(LoadingUtils.EDITOR_RACE_NAME)){ if(connectionHandler.getCurrentCreatureTemplate() != null && connectionHandler.getCurrentCreatureTemplate().getCreatureType().matches(LoadingUtils.EDITOR_RACE_NAME)){
//solve what race to pick //solve what race to pick
String race = LoadingUtils.EDITOR_RACE_NAME; String race = LoadingUtils.EDITOR_RACE_NAME;
List<String> races = Globals.gameConfigCurrent.getCreatureTypeLoader().getPlayableRaces(); List<String> races = Globals.gameConfigCurrent.getCreatureTypeLoader().getPlayableRaces();
@ -173,7 +173,7 @@ public class CharacterProtocol implements ServerProtocolTemplate<CharacterMessag
Player player = connectionHandler.getPlayer(); Player player = connectionHandler.getPlayer();
Entity playerEntity = player.getPlayerEntity(); Entity playerEntity = player.getPlayerEntity();
Vector3d position = EntityUtils.getPosition(playerEntity); Vector3d position = EntityUtils.getPosition(playerEntity);
Globals.realmManager.getEntityRealm(playerEntity).registerSpawnPoint(position);; Globals.realmManager.getEntityRealm(playerEntity).registerSpawnPoint(position);
Globals.realmManager.getEntityRealm(playerEntity).getSpawnPoint().set(position); Globals.realmManager.getEntityRealm(playerEntity).getSpawnPoint().set(position);
ServerEntityUtils.destroyEntity(playerEntity); ServerEntityUtils.destroyEntity(playerEntity);

View File

@ -26,6 +26,16 @@ import electrosphere.util.annotation.Exclude;
*/ */
public class ChunkDiskMap { public class ChunkDiskMap {
/**
* Name of the map file
*/
static final String MAP_FILE_NAME = "voxelchunk.json";
/**
* The directory that stores the voxel data files
*/
static final String VOXEL_DATA_DIR = "/terrain";
/** /**
* The map of world position+chunk type to the file that actually houses that information * The map of world position+chunk type to the file that actually houses that information
*/ */
@ -73,15 +83,15 @@ public class ChunkDiskMap {
public static ChunkDiskMap init(String saveName){ public static ChunkDiskMap init(String saveName){
ChunkDiskMap rVal = null; ChunkDiskMap rVal = null;
LoggerInterface.loggerEngine.DEBUG("INIT CHUNK MAP " + saveName); LoggerInterface.loggerEngine.DEBUG("INIT CHUNK MAP " + saveName);
if(FileUtils.getSaveFile(saveName, "chunk.map").exists()){ if(FileUtils.getSaveFile(saveName, MAP_FILE_NAME).exists()){
rVal = FileUtils.loadObjectFromSavePath(saveName, "chunk.map", ChunkDiskMap.class); rVal = FileUtils.loadObjectFromSavePath(saveName, MAP_FILE_NAME, ChunkDiskMap.class);
LoggerInterface.loggerEngine.DEBUG("POS FILE MAP: " + rVal.worldPosFileMap.keySet()); LoggerInterface.loggerEngine.DEBUG("POS FILE MAP: " + rVal.worldPosFileMap.keySet());
//make sure the subfolder for chunk files exists //make sure the subfolder for chunk files exists
String dirPath = SaveUtils.deriveSaveDirectoryPath(Globals.currentSave.getName()); String dirPath = SaveUtils.deriveSaveDirectoryPath(Globals.currentSave.getName());
if(!Files.exists(new File(dirPath + "/terrain").toPath())){ if(!Files.exists(new File(dirPath + VOXEL_DATA_DIR).toPath())){
try { try {
Files.createDirectories(new File(dirPath + "/terrain").toPath()); Files.createDirectories(new File(dirPath + VOXEL_DATA_DIR).toPath());
} catch (IOException e) { } catch (IOException e) {
LoggerInterface.loggerFileIO.ERROR(e); LoggerInterface.loggerFileIO.ERROR(e);
} }
@ -104,7 +114,7 @@ public class ChunkDiskMap {
* Saves the disk map to disk * Saves the disk map to disk
*/ */
public void save(){ public void save(){
FileUtils.serializeObjectToSavePath(Globals.currentSave.getName(), "chunk.map", this); FileUtils.serializeObjectToSavePath(Globals.currentSave.getName(), MAP_FILE_NAME, this);
} }
/** /**
@ -213,7 +223,7 @@ public class ChunkDiskMap {
if(worldPosFileMap.containsKey(chunkKey)){ if(worldPosFileMap.containsKey(chunkKey)){
fileName = worldPosFileMap.get(chunkKey); fileName = worldPosFileMap.get(chunkKey);
} else { } else {
fileName = "/terrain/" + chunkKey + ".dat"; fileName = VOXEL_DATA_DIR + "/" + chunkKey + ".dat";
} }
//generate binary for the file //generate binary for the file
float[][][] weights = terrainChunk.getWeights(); float[][][] weights = terrainChunk.getWeights();