structure editing tab
All checks were successful
studiorailgun/Renderer/pipeline/head This commit looks good

This commit is contained in:
austin 2025-04-29 12:54:07 -04:00
parent 4c6c30db0f
commit 1ded83c968
11 changed files with 282 additions and 9 deletions

View File

@ -1581,6 +1581,8 @@ Grid alignment actually aligns entity to grid
(04/29/2025)
Fix door tree physics
BlockFab metadata
Structure editing tab in editor view

View File

@ -79,6 +79,16 @@ public class ClientBlockSelection {
* Exports currently selected area of voxels
*/
public static void exportSelection(){
BlockFab fab = ClientBlockSelection.convertSelectionToFab();
File exportLoc = new File("./assets/Data/fab/struct.block");
fab.write(exportLoc);
}
/**
* Converts the current selection by the player into a fab
* @return The fab
*/
public static BlockFab convertSelectionToFab(){
AreaSelection selection = Globals.cursorState.getAreaSelection();
Vector3i startChunk = Globals.clientWorldData.convertRealToWorldSpace(selection.getRectStart());
Vector3i endChunk = Globals.clientWorldData.convertRealToWorldSpace(selection.getRectEnd());
@ -114,8 +124,7 @@ public class ClientBlockSelection {
);
BlockFab fab = BlockFab.create(dimensions, types, metadata);
File exportLoc = new File("./assets/Data/fab/struct.block");
fab.write(exportLoc);
return fab;
}
}

View File

@ -0,0 +1,56 @@
package electrosphere.client.leveledit;
import org.joml.Vector3d;
import electrosphere.game.data.block.BlockFab;
/**
* Stores the data for the client's level edits
*/
public class ClientLevelEditorData {
/**
* The currently edited fab
*/
private BlockFab currentFab;
/**
* The origin point of the current fab
*/
private Vector3d currentFabOrigin;
/**
* Gets the currently edited fab
* @return The fab if it exists, null otherwise
*/
public BlockFab getCurrentFab() {
return currentFab;
}
/**
* Sets the fab currently being edited
* @param currentFab The fab
*/
public void setCurrentFab(BlockFab currentFab) {
this.currentFab = currentFab;
}
/**
* Gets the origin point of the current fab
* @return The origin point
*/
public Vector3d getCurrentFabOrigin() {
return currentFabOrigin;
}
/**
* Sets the origin point of the current fab
* @param currentFabOrigin The origin point
*/
public void setCurrentFabOrigin(Vector3d currentFabOrigin) {
this.currentFabOrigin = currentFabOrigin;
}
}

View File

@ -18,6 +18,9 @@ public class ImGuiAreaTab {
if(ImGui.button("Export Selected Blocks")){
ClientBlockSelection.exportSelection();
}
if(ImGui.button("Add Area Selection As Room")){
ClientBlockSelection.exportSelection();
}
}
}

View File

@ -32,10 +32,27 @@ public class ImGuiEditorDetailsWindow {
detailsWindow.setCallback(new ImGuiWindowCallback() {
@Override
public void exec() {
ImGui.text("Some details or smthn");
//close button
if(ImGui.button("Close")){
detailsWindow.setOpen(false);
switch(ImGuiEditorWindows.getCurrentTab()){
case 0: {
//general tab
ImGui.text("General tab");
} break;
case 1: {
//assets tab
ImGui.text("Asset tab");
} break;
case 2: {
//hierarchy tab
ImGui.text("Hierarchy tab");
} break;
case 3: {
//area tab
ImGui.text("Area tab");
} break;
case 4: {
//structure tab
ImGuiStructureTab.drawDetails();
} break;
}
}
});

View File

@ -19,6 +19,11 @@ public class ImGuiEditorWindows {
//tracks if the editor menu is open
private static boolean editorIsOpen = false;
/**
* The current tab
*/
private static int currentTab = 0;
/**
* Initializes imgui windows
*/
@ -46,10 +51,12 @@ public class ImGuiEditorWindows {
public void exec() {
if(ImGui.beginTabBar("Tabs")){
if(ImGui.beginTabItem("General")){
currentTab = 0;
ImGui.text("hello :)");
ImGui.endTabItem();
}
if(ImGui.beginTabItem("Assets")){
currentTab = 1;
ImGui.text("asset selector here");
if(ImGui.button("testasset")){
@ -61,13 +68,20 @@ public class ImGuiEditorWindows {
ImGui.endTabItem();
}
if(ImGui.beginTabItem("Hierarchy")){
currentTab = 2;
ImGui.text("hierarchy controls here");
ImGui.endTabItem();
}
if(ImGui.beginTabItem("Areas")){
currentTab = 3;
ImGuiAreaTab.draw();
ImGui.endTabItem();
}
if(ImGui.beginTabItem("Structure")){
currentTab = 4;
ImGuiStructureTab.draw();
ImGui.endTabItem();
}
ImGui.endTabBar();
}
@ -105,4 +119,12 @@ public class ImGuiEditorWindows {
}
}
/**
* Gets the current tab
* @return The current tab
*/
protected static int getCurrentTab(){
return currentTab;
}
}

View File

@ -0,0 +1,75 @@
package electrosphere.client.ui.menu.editor;
import java.io.File;
import org.joml.Vector3d;
import electrosphere.client.block.ClientBlockSelection;
import electrosphere.client.interact.select.AreaSelection;
import electrosphere.engine.Globals;
import electrosphere.game.data.block.BlockFab;
import electrosphere.game.data.block.BlockFabMetadata;
import imgui.ImGui;
/**
* Tab for editing structures
*/
public class ImGuiStructureTab {
/**
* Draws the contents of the structure tab
*/
protected static void draw(){
if(Globals.clientLevelEditorData.getCurrentFab() == null){
ImGui.text("No structure currently being edited");
if(ImGui.button("Discover structure")){
ClientBlockSelection.selectAllBlocks();
AreaSelection area = Globals.cursorState.getAreaSelection();
if(area != null){
BlockFab blockFab = ClientBlockSelection.convertSelectionToFab();
Globals.clientLevelEditorData.setCurrentFab(blockFab);
Globals.clientLevelEditorData.setCurrentFabOrigin(area.getRectStart());
}
}
} else {
BlockFab currentFab = Globals.clientLevelEditorData.getCurrentFab();
if(ImGui.button("Convert current selection to room")){
AreaSelection currentSelection = Globals.cursorState.getAreaSelection();
if(currentSelection != null){
currentFab.getFabMetadata().getAreas().add(currentSelection);
}
}
if(ImGui.button("Save")){
File exportLoc = new File("./assets/Data/fab/struct.block");
currentFab.write(exportLoc);
}
}
}
/**
* Draws the details tab
*/
protected static void drawDetails(){
if(Globals.clientLevelEditorData.getCurrentFab() == null){
ImGui.text("Select a fab to show details here");
} else {
BlockFab currentFab = Globals.clientLevelEditorData.getCurrentFab();
ImGui.text("Origin: " + Globals.clientLevelEditorData.getCurrentFabOrigin());
ImGui.text("Dimensions: " + currentFab.getDimensions());
BlockFabMetadata fabMetadata = currentFab.getFabMetadata();
if(fabMetadata.getAreas() != null){
if(ImGui.collapsingHeader("Areas in fab: " + fabMetadata.getAreas().size())){
int i = 0;
for(AreaSelection area : fabMetadata.getAreas()){
Vector3d dims = new Vector3d(area.getRectEnd()).sub(area.getRectStart());
ImGui.text("Area " + i + " dimensions " + dims);
i++;
}
}
} else {
ImGui.text("Areas undefined in metadata");
}
}
}
}

View File

@ -506,7 +506,11 @@ public class CursorState {
* Hints to show the block cursor
*/
public void hintShowBlockCursor(){
if(!Globals.clientSceneWrapper.getScene().getEntitiesWithTag(EntityTags.DRAWABLE).contains(CursorState.playerFabCursor)){
if(
!Globals.clientSceneWrapper.getScene().getEntitiesWithTag(EntityTags.DRAWABLE).contains(CursorState.playerFabCursor) &&
!Globals.clientSceneWrapper.getScene().getEntitiesWithTag(EntityTags.DRAWABLE).contains(Globals.playerAreaCursor) &&
!Globals.clientSceneWrapper.getScene().getEntitiesWithTag(EntityTags.DRAWABLE).contains(Globals.playerCursor)
){
CursorState.makeBlockVisible(AssetDataStrings.TEXTURE_RED_TRANSPARENT);
}
}

View File

@ -20,6 +20,7 @@ import electrosphere.client.entity.character.ClientCharacterManager;
import electrosphere.client.entity.particle.ParticleService;
import electrosphere.client.fluid.cells.FluidCellManager;
import electrosphere.client.fluid.manager.ClientFluidManager;
import electrosphere.client.leveledit.ClientLevelEditorData;
import electrosphere.client.player.ClientPlayerData;
import electrosphere.client.scene.ClientSceneWrapper;
import electrosphere.client.scene.ClientWorldData;
@ -400,6 +401,9 @@ public class Globals {
//structure manager
public static StructureManager structureManager;
//client level editor data management
public static ClientLevelEditorData clientLevelEditorData = new ClientLevelEditorData();
//the player camera entity
public static Entity playerCamera;

View File

@ -8,6 +8,8 @@ import java.nio.ShortBuffer;
import org.joml.Vector3i;
import com.google.gson.Gson;
import electrosphere.client.block.BlockChunkData;
import electrosphere.logger.LoggerInterface;
import electrosphere.renderer.meshgen.BlockMeshgenData;
@ -21,7 +23,7 @@ public class BlockFab implements BlockMeshgenData {
/**
* File version format
*/
public static final int FILE_VER = 1;
public static final int FILE_VER = 2;
/**
* Size of the header for a block fab file
@ -48,6 +50,11 @@ public class BlockFab implements BlockMeshgenData {
*/
short[] metadata;
/**
* The metadata of the fab
*/
BlockFabMetadata fabMetadata;
/**
* Creates a block fab
* @param dimensions The dimensions of the fab
@ -60,6 +67,7 @@ public class BlockFab implements BlockMeshgenData {
rVal.dimensions = dimensions;
rVal.types = types;
rVal.metadata = metadata;
rVal.fabMetadata = new BlockFabMetadata();
return rVal;
}
@ -70,8 +78,11 @@ public class BlockFab implements BlockMeshgenData {
public void write(File file){
int blockCount = dimensions.x * dimensions.y * dimensions.z;
Gson gson = new Gson();
String serializedMetadata = gson.toJson(this.fabMetadata);
byte[] serializedMetadataBytes = serializedMetadata.getBytes();
ByteBuffer buff = ByteBuffer.allocate(HEADER_SIZE + blockCount * BlockChunkData.BYTES_PER_BLOCK);
ByteBuffer buff = ByteBuffer.allocate(HEADER_SIZE + blockCount * BlockChunkData.BYTES_PER_BLOCK + serializedMetadataBytes.length);
IntBuffer intView = buff.asIntBuffer();
intView.put(FILE_VER);
@ -84,6 +95,8 @@ public class BlockFab implements BlockMeshgenData {
shortView.put(types);
shortView.put(metadata);
buff.position(HEADER_SIZE + types.length * 2 + metadata.length * 2);
buff.put(serializedMetadataBytes);
shortView.flip();
try {
@ -106,6 +119,9 @@ public class BlockFab implements BlockMeshgenData {
IntBuffer intView = buff.asIntBuffer();
int fileVer = intView.get();
LoggerInterface.loggerFileIO.DEBUG("Read fab file with ver " + fileVer);
if(fileVer != FILE_VER){
LoggerInterface.loggerFileIO.WARNING("Reading unsupported fab file with version: " + fileVer);
}
int dimX = intView.get();
int dimY = intView.get();
@ -137,10 +153,25 @@ public class BlockFab implements BlockMeshgenData {
}
}
//read the fab metadata
buff.position(HEADER_SIZE + blockCount * 2 + blockCount * 2);
BlockFabMetadata fabMetadata = new BlockFabMetadata();
if(buff.remaining() > 0){
byte[] fabMetadataBytes = new byte[buff.remaining()];
buff.get(fabMetadataBytes);
String fabMetadataString = new String(fabMetadataBytes);
Gson gson = new Gson();
fabMetadata = gson.fromJson(fabMetadataString, BlockFabMetadata.class);
} else {
LoggerInterface.loggerFileIO.WARNING("Fab file does not have metadata defined! " + file.getAbsolutePath());
}
//construct returned object
rVal = new BlockFab();
rVal.dimensions = dims;
rVal.types = types;
rVal.metadata = metadata;
rVal.fabMetadata = fabMetadata;
} catch (IOException e) {
LoggerInterface.loggerFileIO.ERROR(e);
throw new Error("Failed to read BlockFab " + file);
@ -183,4 +214,12 @@ public class BlockFab implements BlockMeshgenData {
return this.types[x * dimensions.y * dimensions.z + y * dimensions.z + z];
}
/**
* Gets the fab metadata for the fab
* @return The metadata
*/
public BlockFabMetadata getFabMetadata(){
return fabMetadata;
}
}

View File

@ -0,0 +1,42 @@
package electrosphere.game.data.block;
import java.util.LinkedList;
import java.util.List;
import electrosphere.client.interact.select.AreaSelection;
/**
* Metdata associated with the fab
*/
public class BlockFabMetadata {
/**
* Area data for the fab
*/
private List<AreaSelection> areas;
/**
* Constructor
*/
protected BlockFabMetadata(){
this.areas = new LinkedList<AreaSelection>();
}
/**
* Gets the areas defined in the metadata
* @return The areas
*/
public List<AreaSelection> getAreas() {
return areas;
}
/**
* Sets the areas defined in the metadata
* @param areas The areas
*/
public void setAreas(List<AreaSelection> areas) {
this.areas = areas;
}
}