exporting block prefabs to compressed files
Some checks failed
studiorailgun/Renderer/pipeline/head There was a failure building this commit
Some checks failed
studiorailgun/Renderer/pipeline/head There was a failure building this commit
This commit is contained in:
parent
20c53b151b
commit
69a5e07818
@ -1539,6 +1539,9 @@ Variable block editing size
|
|||||||
Increase block cursor size
|
Increase block cursor size
|
||||||
Block area selection
|
Block area selection
|
||||||
|
|
||||||
|
(04/26/2025)
|
||||||
|
Exporting block prefabs to compressed files
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -19,10 +19,16 @@ public class BlockChunkData {
|
|||||||
*/
|
*/
|
||||||
public static final int TOTAL_DATA_WIDTH = CHUNK_DATA_WIDTH * CHUNK_DATA_WIDTH * CHUNK_DATA_WIDTH;
|
public static final int TOTAL_DATA_WIDTH = CHUNK_DATA_WIDTH * CHUNK_DATA_WIDTH * CHUNK_DATA_WIDTH;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 2 - block type
|
||||||
|
* 2 - metadata
|
||||||
|
*/
|
||||||
|
public static final int BYTES_PER_BLOCK = 2 * 2;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Size of a buffer that stores this chunk's data
|
* Size of a buffer that stores this chunk's data
|
||||||
*/
|
*/
|
||||||
public static final int BUFFER_SIZE = TOTAL_DATA_WIDTH * 2 * 2;
|
public static final int BUFFER_SIZE = TOTAL_DATA_WIDTH * BYTES_PER_BLOCK;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The number of blocks to place within each unit of distance
|
* The number of blocks to place within each unit of distance
|
||||||
|
|||||||
@ -1,10 +1,13 @@
|
|||||||
package electrosphere.client.block;
|
package electrosphere.client.block;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
import org.joml.Vector3d;
|
import org.joml.Vector3d;
|
||||||
import org.joml.Vector3i;
|
import org.joml.Vector3i;
|
||||||
|
|
||||||
import electrosphere.controls.cursor.CursorState;
|
import electrosphere.client.interact.select.AreaSelection;
|
||||||
import electrosphere.engine.Globals;
|
import electrosphere.engine.Globals;
|
||||||
|
import electrosphere.game.data.block.BlockFab;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class for selecting blocks on the client
|
* Class for selecting blocks on the client
|
||||||
@ -68,8 +71,51 @@ public class ClientBlockSelection {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
AreaSelection selection = AreaSelection.createRect(minPos, maxPos);
|
||||||
|
Globals.cursorState.selectRectangularArea(selection);
|
||||||
|
}
|
||||||
|
|
||||||
CursorState.selectRectangularArea(minPos, maxPos);
|
/**
|
||||||
|
* Exports currently selected area of voxels
|
||||||
|
*/
|
||||||
|
public static void exportSelection(){
|
||||||
|
AreaSelection selection = Globals.cursorState.getAreaSelection();
|
||||||
|
Vector3i startChunk = Globals.clientWorldData.convertRealToWorldSpace(selection.getRectStart());
|
||||||
|
Vector3i endChunk = Globals.clientWorldData.convertRealToWorldSpace(selection.getRectEnd());
|
||||||
|
if(!startChunk.equals(endChunk)){
|
||||||
|
throw new Error("Unsupported case! Selected are coverts multiple chunks.. " + startChunk + " " + endChunk);
|
||||||
|
}
|
||||||
|
Vector3i blockStart = Globals.clientWorldData.convertRealToBlockSpace(selection.getRectStart());
|
||||||
|
Vector3i blockEnd = Globals.clientWorldData.convertRealToBlockSpace(selection.getRectEnd());
|
||||||
|
|
||||||
|
BlockChunkData chunk = Globals.clientBlockManager.getChunkDataAtWorldPoint(startChunk, 0);
|
||||||
|
if(chunk == null){
|
||||||
|
throw new Error("Failed to grab chunk at " + startChunk);
|
||||||
|
}
|
||||||
|
|
||||||
|
int blockCount = (blockEnd.x - blockStart.x) * (blockEnd.y - blockStart.y) * (blockEnd.z - blockStart.z);
|
||||||
|
short[] types = new short[blockCount];
|
||||||
|
short[] metadata = new short[blockCount];
|
||||||
|
int i = 0;
|
||||||
|
for(int x = blockStart.x; x < blockEnd.x; x++){
|
||||||
|
for(int y = blockStart.y; y < blockEnd.y; y++){
|
||||||
|
for(int z = blockStart.z; z < blockEnd.z; z++){
|
||||||
|
types[i] = chunk.getType(x, y, z);
|
||||||
|
metadata[i] = chunk.getMetadata(x, y, z);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector3i dimensions = new Vector3i(
|
||||||
|
(blockEnd.x - blockStart.x),
|
||||||
|
(blockEnd.y - blockStart.y),
|
||||||
|
(blockEnd.z - blockStart.z)
|
||||||
|
);
|
||||||
|
|
||||||
|
BlockFab fab = BlockFab.create(dimensions, types, metadata);
|
||||||
|
File exportLoc = new File("./struct.block");
|
||||||
|
fab.save(exportLoc);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,75 @@
|
|||||||
|
package electrosphere.client.interact.select;
|
||||||
|
|
||||||
|
import org.joml.Vector3d;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An area of space that is selected by the client
|
||||||
|
*/
|
||||||
|
public class AreaSelection {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type of selection
|
||||||
|
*/
|
||||||
|
public static enum AreaSelectionType {
|
||||||
|
/**
|
||||||
|
* A rectangle
|
||||||
|
*/
|
||||||
|
RECTANGULAR,
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type of selection
|
||||||
|
*/
|
||||||
|
private AreaSelectionType type;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The start point of the rectangular selection
|
||||||
|
*/
|
||||||
|
private Vector3d rectStart;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The end point of the rectangular selection
|
||||||
|
*/
|
||||||
|
private Vector3d rectEnd;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a rectangular selection
|
||||||
|
* @param start The start point
|
||||||
|
* @param end The end point
|
||||||
|
* @return The selection
|
||||||
|
*/
|
||||||
|
public static AreaSelection createRect(Vector3d start, Vector3d end){
|
||||||
|
AreaSelection rVal = new AreaSelection();
|
||||||
|
rVal.type = AreaSelectionType.RECTANGULAR;
|
||||||
|
rVal.rectStart = start;
|
||||||
|
rVal.rectEnd = end;
|
||||||
|
return rVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the type of area
|
||||||
|
* @return The type of area
|
||||||
|
*/
|
||||||
|
public AreaSelectionType getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the start point of the rectangular selection
|
||||||
|
* @return The start point
|
||||||
|
*/
|
||||||
|
public Vector3d getRectStart() {
|
||||||
|
return rectStart;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the end point of the rectangular selection
|
||||||
|
* @return The end point
|
||||||
|
*/
|
||||||
|
public Vector3d getRectEnd() {
|
||||||
|
return rectEnd;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@ -15,6 +15,9 @@ public class ImGuiAreaTab {
|
|||||||
if(ImGui.button("Select all voxels")){
|
if(ImGui.button("Select all voxels")){
|
||||||
ClientBlockSelection.selectAllBlocks();
|
ClientBlockSelection.selectAllBlocks();
|
||||||
}
|
}
|
||||||
|
if(ImGui.button("Export Selected Blocks")){
|
||||||
|
ClientBlockSelection.exportSelection();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,6 +7,7 @@ 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;
|
||||||
|
import electrosphere.client.interact.select.AreaSelection;
|
||||||
import electrosphere.collision.CollisionEngine;
|
import electrosphere.collision.CollisionEngine;
|
||||||
import electrosphere.engine.Globals;
|
import electrosphere.engine.Globals;
|
||||||
import electrosphere.engine.assetmanager.AssetDataStrings;
|
import electrosphere.engine.assetmanager.AssetDataStrings;
|
||||||
@ -59,6 +60,11 @@ public class CursorState {
|
|||||||
*/
|
*/
|
||||||
private int blockSize = MIN_BLOCK_SIZE;
|
private int blockSize = MIN_BLOCK_SIZE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The current selection of the area selector
|
||||||
|
*/
|
||||||
|
private AreaSelection areaCursorSelection = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates the cursor entities
|
* Creates the cursor entities
|
||||||
*/
|
*/
|
||||||
@ -154,12 +160,12 @@ public class CursorState {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Selects a rectangular area
|
* Selects a rectangular area
|
||||||
* @param startPos The start position of the area
|
* @param selection The area selection to encompass the cursor
|
||||||
* @param endPos The end position of the area
|
|
||||||
*/
|
*/
|
||||||
public static void selectRectangularArea(Vector3d startPos, Vector3d endPos){
|
public void selectRectangularArea(AreaSelection selection){
|
||||||
Vector3d center = new Vector3d(startPos).add(endPos).mul(0.5f);
|
this.areaCursorSelection = selection;
|
||||||
Vector3d scale = new Vector3d(startPos).sub(endPos).absolute();
|
Vector3d center = new Vector3d(areaCursorSelection.getRectStart()).add(areaCursorSelection.getRectEnd()).mul(0.5f);
|
||||||
|
Vector3d scale = new Vector3d(areaCursorSelection.getRectStart()).sub(areaCursorSelection.getRectEnd()).absolute();
|
||||||
EntityCreationUtils.makeEntityDrawable(Globals.playerAreaCursor, AssetDataStrings.UNITCUBE);
|
EntityCreationUtils.makeEntityDrawable(Globals.playerAreaCursor, AssetDataStrings.UNITCUBE);
|
||||||
Actor areaCursorActor = EntityUtils.getActor(Globals.playerAreaCursor);
|
Actor areaCursorActor = EntityUtils.getActor(Globals.playerAreaCursor);
|
||||||
areaCursorActor.addTextureMask(new ActorTextureMask("cube", Arrays.asList(new String[]{"Textures/transparent_red.png"})));
|
areaCursorActor.addTextureMask(new ActorTextureMask("cube", Arrays.asList(new String[]{"Textures/transparent_red.png"})));
|
||||||
@ -261,4 +267,12 @@ public class CursorState {
|
|||||||
return blockSize;
|
return blockSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the currently selected area
|
||||||
|
* @return The currently selected area
|
||||||
|
*/
|
||||||
|
public AreaSelection getAreaSelection(){
|
||||||
|
return this.areaCursorSelection;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
85
src/main/java/electrosphere/game/data/block/BlockFab.java
Normal file
85
src/main/java/electrosphere/game/data/block/BlockFab.java
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
package electrosphere.game.data.block;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.IntBuffer;
|
||||||
|
import java.nio.ShortBuffer;
|
||||||
|
|
||||||
|
import org.joml.Vector3i;
|
||||||
|
|
||||||
|
import electrosphere.client.block.BlockChunkData;
|
||||||
|
import electrosphere.util.FileUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A collection of blocks
|
||||||
|
*/
|
||||||
|
public class BlockFab {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Size of the header for a block fab file
|
||||||
|
* 3 * 4 for the dimensions at the front of the file
|
||||||
|
*/
|
||||||
|
public static final int HEADER_SIZE = 3 * 4;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dimensions of the block fab
|
||||||
|
*/
|
||||||
|
Vector3i dimensions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Block type data
|
||||||
|
*/
|
||||||
|
short[] types;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Block metadata
|
||||||
|
*/
|
||||||
|
short[] metadata;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a block fab
|
||||||
|
* @param dimensions The dimensions of the fab
|
||||||
|
* @param types The block types
|
||||||
|
* @param metadata The block metadata
|
||||||
|
* @return The block fab
|
||||||
|
*/
|
||||||
|
public static BlockFab create(Vector3i dimensions, short[] types, short[] metadata){
|
||||||
|
BlockFab rVal = new BlockFab();
|
||||||
|
rVal.dimensions = dimensions;
|
||||||
|
rVal.types = types;
|
||||||
|
rVal.metadata = metadata;
|
||||||
|
return rVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Saves this fab to a file
|
||||||
|
* @param file The file
|
||||||
|
*/
|
||||||
|
public void save(File file){
|
||||||
|
int blockCount = dimensions.x * dimensions.y * dimensions.z;
|
||||||
|
|
||||||
|
|
||||||
|
ByteBuffer buff = ByteBuffer.allocate(HEADER_SIZE + blockCount * BlockChunkData.BYTES_PER_BLOCK);
|
||||||
|
|
||||||
|
IntBuffer intView = buff.asIntBuffer();
|
||||||
|
intView.put(dimensions.x);
|
||||||
|
intView.put(dimensions.y);
|
||||||
|
intView.put(dimensions.z);
|
||||||
|
buff.position(HEADER_SIZE);
|
||||||
|
|
||||||
|
ShortBuffer shortView = buff.asShortBuffer();
|
||||||
|
|
||||||
|
shortView.put(types);
|
||||||
|
shortView.put(metadata);
|
||||||
|
shortView.flip();
|
||||||
|
|
||||||
|
File exportLoc = new File("./struct.block");
|
||||||
|
try {
|
||||||
|
FileUtils.writeBufferToCompressedFile(exportLoc, buff);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new Error("Failed to export selected blocks to a file!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -33,6 +33,8 @@ import java.security.NoSuchAlgorithmException;
|
|||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.zip.GZIPInputStream;
|
||||||
|
import java.util.zip.GZIPOutputStream;
|
||||||
|
|
||||||
import javax.imageio.ImageIO;
|
import javax.imageio.ImageIO;
|
||||||
|
|
||||||
@ -526,6 +528,32 @@ public class FileUtils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Writes a ByteBuffer to a file and compresses it
|
||||||
|
* @param file The file
|
||||||
|
* @param buff The buffer
|
||||||
|
*/
|
||||||
|
public static void writeBufferToCompressedFile(File file, ByteBuffer buff) throws IOException {
|
||||||
|
try (GZIPOutputStream outStream = new GZIPOutputStream(Files.newOutputStream(file.toPath()))){
|
||||||
|
outStream.write(buff.array());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Writes a ByteBuffer to a file and compresses it
|
||||||
|
* @param file The file
|
||||||
|
* @param buff The buffer
|
||||||
|
*/
|
||||||
|
public static ByteBuffer readBufferFromCompressedFile(File file) throws IOException {
|
||||||
|
ByteBuffer buff = null;
|
||||||
|
try (GZIPInputStream inStream = new GZIPInputStream(Files.newInputStream(file.toPath()))){
|
||||||
|
byte[] bytes = inStream.readAllBytes();
|
||||||
|
buff = ByteBuffer.allocate(bytes.length);
|
||||||
|
buff.put(bytes);
|
||||||
|
buff.flip();
|
||||||
|
}
|
||||||
|
return buff;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user