fab placement
Some checks failed
studiorailgun/Renderer/pipeline/head There was a failure building this commit

This commit is contained in:
austin 2025-04-26 21:09:54 -04:00
parent d9b7f9c25c
commit 9fe9670248
14 changed files with 274 additions and 1 deletions

View File

@ -142,6 +142,7 @@
"path" : "Models/basic/geometry/unitvector.glb" "path" : "Models/basic/geometry/unitvector.glb"
} }
}, },
"clientSidePrimary" : "PLACE_FAB",
"clientSideSecondary": "SELECT_FAB", "clientSideSecondary": "SELECT_FAB",
"collidable": { "collidable": {
"type" : "CUBE", "type" : "CUBE",

View File

@ -52,5 +52,11 @@ export const clientHooks: Hook[] = [
callback: (engine: Engine) => { callback: (engine: Engine) => {
engine.classes.menuUtils.static.openFabSelection() engine.classes.menuUtils.static.openFabSelection()
} }
},
{
signal: "PLACE_FAB",
callback: (engine: Engine) => {
engine.classes.voxelUtils.static.placeFab()
}
} }
] ]

View File

@ -18,4 +18,9 @@ export interface ClientVoxelUtils {
*/ */
readonly dig: () => void readonly dig: () => void
/**
* Places the currently selected fab
*/
readonly placeFab: () => void
} }

View File

@ -1558,6 +1558,7 @@ New block type
Fix inventory item tooltip not clearing Fix inventory item tooltip not clearing
More item icons More item icons
Toolbar preview ui element Toolbar preview ui element
Fab tool can place fabs

View File

@ -9,9 +9,11 @@ import electrosphere.audio.movement.MovementAudioService.InteractionType;
import electrosphere.client.entity.camera.CameraEntityUtils; import electrosphere.client.entity.camera.CameraEntityUtils;
import electrosphere.client.terrain.editing.TerrainEditing; import electrosphere.client.terrain.editing.TerrainEditing;
import electrosphere.collision.CollisionEngine; import electrosphere.collision.CollisionEngine;
import electrosphere.controls.cursor.CursorState;
import electrosphere.engine.Globals; import electrosphere.engine.Globals;
import electrosphere.engine.assetmanager.AssetDataStrings; import electrosphere.engine.assetmanager.AssetDataStrings;
import electrosphere.entity.Entity; import electrosphere.entity.Entity;
import electrosphere.entity.EntityUtils;
import electrosphere.net.parser.net.message.TerrainMessage; import electrosphere.net.parser.net.message.TerrainMessage;
import electrosphere.server.physics.terrain.manager.ServerTerrainChunk; import electrosphere.server.physics.terrain.manager.ServerTerrainChunk;
@ -134,4 +136,22 @@ public class ScriptClientVoxelUtils {
)); ));
} }
/**
* Places the currently selected fab
*/
@Export
public static void placeFab(){
if(Globals.cursorState.getSelectedFabPath() != null){
String fabPath = Globals.cursorState.getSelectedFabPath();
Vector3d fabCursorPos = EntityUtils.getPosition(CursorState.getFabCursor());
Vector3i chunkPos = Globals.clientWorldData.convertRealToWorldSpace(fabCursorPos);
Vector3i voxelPos = Globals.clientWorldData.convertRealToBlockSpace(fabCursorPos);
Globals.clientConnection.queueOutgoingMessage(TerrainMessage.constructRequestPlaceFabMessage(
chunkPos.x, chunkPos.y, chunkPos.z,
voxelPos.x, voxelPos.y, voxelPos.z,
fabPath
));
}
}
} }

View File

@ -57,8 +57,8 @@ public class FabMenus {
//attach scrollable after search input for organzation purposes //attach scrollable after search input for organzation purposes
fabSelectionPanelWindow.addChild(FabSelectionPanel.createFabSelectionPanel((File selectedFile) -> { fabSelectionPanelWindow.addChild(FabSelectionPanel.createFabSelectionPanel((File selectedFile) -> {
BlockFab fab = BlockFab.read(selectedFile); BlockFab fab = BlockFab.read(selectedFile);
LoggerInterface.loggerEngine.WARNING("" + fab.getDimensions());
Globals.cursorState.setSelectedFab(fab); Globals.cursorState.setSelectedFab(fab);
Globals.cursorState.setSelectedFabPath("./assets/Data/fab/" + selectedFile.getName());
})); }));
Globals.signalSystem.post(SignalType.YOGA_APPLY,fabSelectionPanelWindow); Globals.signalSystem.post(SignalType.YOGA_APPLY,fabSelectionPanelWindow);

View File

@ -86,6 +86,16 @@ public class CursorState {
*/ */
static Entity playerFabCursor; static Entity playerFabCursor;
/**
* The currently selected fab
*/
private BlockFab selectedFab = null;
/**
* The path for the selected fab
*/
private String selectedFabPath = null;
/** /**
* Creates the cursor entities * Creates the cursor entities
*/ */
@ -318,6 +328,30 @@ public class CursorState {
CursorState.makeFabVisible(); CursorState.makeFabVisible();
} }
/**
* Gets the currently selected fab
* @return The currently selected fab
*/
public BlockFab getSelectedFab(){
return this.selectedFab;
}
/**
* Sets the selected fab path
* @param path The path
*/
public void setSelectedFabPath(String path){
this.selectedFabPath = path;
}
/**
* Gets the selected fab's path
* @return The path
*/
public String getSelectedFabPath(){
return this.selectedFabPath;
}
/** /**
* Gets the size of the block cursor * Gets the size of the block cursor
* @return The size of the block cursor * @return The size of the block cursor
@ -381,5 +415,13 @@ public class CursorState {
} }
} }
} }
/**
* Gets the fab cursor
* @return The fab cursor
*/
public static Entity getFabCursor(){
return playerFabCursor;
}
} }

View File

@ -250,6 +250,11 @@ public abstract class NetworkMessage {
rVal = TerrainMessage.parseRequestEditBlockMessage(byteBuffer,pool); rVal = TerrainMessage.parseRequestEditBlockMessage(byteBuffer,pool);
} }
break; break;
case TypeBytes.TERRAIN_MESSAGE_TYPE_REQUESTPLACEFAB:
if(TerrainMessage.canParseMessage(byteBuffer,secondByte)){
rVal = TerrainMessage.parseRequestPlaceFabMessage(byteBuffer,pool);
}
break;
} }
break; break;
case TypeBytes.MESSAGE_TYPE_SERVER: case TypeBytes.MESSAGE_TYPE_SERVER:

View File

@ -29,6 +29,7 @@ public class TerrainMessage extends NetworkMessage {
SENDFLUIDDATA, SENDFLUIDDATA,
UPDATEFLUIDDATA, UPDATEFLUIDDATA,
REQUESTEDITBLOCK, REQUESTEDITBLOCK,
REQUESTPLACEFAB,
} }
/** /**
@ -62,6 +63,7 @@ public class TerrainMessage extends NetworkMessage {
int blockType; int blockType;
int blockMetadata; int blockMetadata;
int blockEditSize; int blockEditSize;
String fabPath;
/** /**
* Constructor * Constructor
@ -461,6 +463,20 @@ public class TerrainMessage extends NetworkMessage {
this.blockEditSize = blockEditSize; this.blockEditSize = blockEditSize;
} }
/**
* Gets fabPath
*/
public String getfabPath() {
return fabPath;
}
/**
* Sets fabPath
*/
public void setfabPath(String fabPath) {
this.fabPath = fabPath;
}
/** /**
* Removes the packet header from the buffer * Removes the packet header from the buffer
* @param byteBuffer The buffer * @param byteBuffer The buffer
@ -565,6 +581,8 @@ public class TerrainMessage extends NetworkMessage {
} else { } else {
return false; return false;
} }
case TypeBytes.TERRAIN_MESSAGE_TYPE_REQUESTPLACEFAB:
return TerrainMessage.canParseRequestPlaceFabMessage(byteBuffer);
} }
return false; return false;
} }
@ -1262,9 +1280,83 @@ public class TerrainMessage extends NetworkMessage {
return rVal; return rVal;
} }
/**
* Checks if a message of type RequestPlaceFab can be parsed from the byte stream
*/
public static boolean canParseRequestPlaceFabMessage(CircularByteBuffer byteBuffer){
int currentStreamLength = byteBuffer.getRemaining();
List<Byte> temporaryByteQueue = new LinkedList<Byte>();
if(currentStreamLength < 6){
return false;
}
if(currentStreamLength < 10){
return false;
}
if(currentStreamLength < 14){
return false;
}
if(currentStreamLength < 18){
return false;
}
if(currentStreamLength < 22){
return false;
}
if(currentStreamLength < 26){
return false;
}
int fabPathSize = 0;
if(currentStreamLength < 30){
return false;
} else {
temporaryByteQueue.add(byteBuffer.peek(26 + 0));
temporaryByteQueue.add(byteBuffer.peek(26 + 1));
temporaryByteQueue.add(byteBuffer.peek(26 + 2));
temporaryByteQueue.add(byteBuffer.peek(26 + 3));
fabPathSize = ByteStreamUtils.popIntFromByteQueue(temporaryByteQueue);
}
if(currentStreamLength < 30 + fabPathSize){
return false;
}
return true;
}
/**
* Parses a message of type RequestPlaceFab
*/
public static TerrainMessage parseRequestPlaceFabMessage(CircularByteBuffer byteBuffer, MessagePool pool){
TerrainMessage rVal = (TerrainMessage)pool.get(MessageType.TERRAIN_MESSAGE);
rVal.messageType = TerrainMessageType.REQUESTPLACEFAB;
TerrainMessage.stripPacketHeader(byteBuffer);
rVal.setworldX(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
rVal.setworldY(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
rVal.setworldZ(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
rVal.setvoxelX(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
rVal.setvoxelY(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
rVal.setvoxelZ(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
rVal.setfabPath(ByteStreamUtils.popStringFromByteQueue(byteBuffer));
return rVal;
}
/**
* Constructs a message of type RequestPlaceFab
*/
public static TerrainMessage constructRequestPlaceFabMessage(int worldX,int worldY,int worldZ,int voxelX,int voxelY,int voxelZ,String fabPath){
TerrainMessage rVal = new TerrainMessage(TerrainMessageType.REQUESTPLACEFAB);
rVal.setworldX(worldX);
rVal.setworldY(worldY);
rVal.setworldZ(worldZ);
rVal.setvoxelX(voxelX);
rVal.setvoxelY(voxelY);
rVal.setvoxelZ(voxelZ);
rVal.setfabPath(fabPath);
rVal.serialize();
return rVal;
}
@Override @Override
void serialize(){ void serialize(){
byte[] intValues = new byte[8]; byte[] intValues = new byte[8];
byte[] stringBytes;
switch(this.messageType){ switch(this.messageType){
case REQUESTMETADATA: case REQUESTMETADATA:
rawBytes = new byte[2]; rawBytes = new byte[2];
@ -1769,6 +1861,45 @@ public class TerrainMessage extends NetworkMessage {
rawBytes[34+i] = intValues[i]; rawBytes[34+i] = intValues[i];
} }
break; break;
case REQUESTPLACEFAB:
rawBytes = new byte[2+4+4+4+4+4+4+4+fabPath.length()];
//message header
rawBytes[0] = TypeBytes.MESSAGE_TYPE_TERRAIN;
//entity messaage header
rawBytes[1] = TypeBytes.TERRAIN_MESSAGE_TYPE_REQUESTPLACEFAB;
intValues = ByteStreamUtils.serializeIntToBytes(worldX);
for(int i = 0; i < 4; i++){
rawBytes[2+i] = intValues[i];
}
intValues = ByteStreamUtils.serializeIntToBytes(worldY);
for(int i = 0; i < 4; i++){
rawBytes[6+i] = intValues[i];
}
intValues = ByteStreamUtils.serializeIntToBytes(worldZ);
for(int i = 0; i < 4; i++){
rawBytes[10+i] = intValues[i];
}
intValues = ByteStreamUtils.serializeIntToBytes(voxelX);
for(int i = 0; i < 4; i++){
rawBytes[14+i] = intValues[i];
}
intValues = ByteStreamUtils.serializeIntToBytes(voxelY);
for(int i = 0; i < 4; i++){
rawBytes[18+i] = intValues[i];
}
intValues = ByteStreamUtils.serializeIntToBytes(voxelZ);
for(int i = 0; i < 4; i++){
rawBytes[22+i] = intValues[i];
}
intValues = ByteStreamUtils.serializeIntToBytes(fabPath.length());
for(int i = 0; i < 4; i++){
rawBytes[26+i] = intValues[i];
}
stringBytes = fabPath.getBytes();
for(int i = 0; i < fabPath.length(); i++){
rawBytes[30+i] = stringBytes[i];
}
break;
} }
serialized = true; serialized = true;
} }

View File

@ -85,6 +85,7 @@ public class TypeBytes {
public static final byte TERRAIN_MESSAGE_TYPE_SENDFLUIDDATA = 15; public static final byte TERRAIN_MESSAGE_TYPE_SENDFLUIDDATA = 15;
public static final byte TERRAIN_MESSAGE_TYPE_UPDATEFLUIDDATA = 16; public static final byte TERRAIN_MESSAGE_TYPE_UPDATEFLUIDDATA = 16;
public static final byte TERRAIN_MESSAGE_TYPE_REQUESTEDITBLOCK = 17; public static final byte TERRAIN_MESSAGE_TYPE_REQUESTEDITBLOCK = 17;
public static final byte TERRAIN_MESSAGE_TYPE_REQUESTPLACEFAB = 18;
/* /*
Terrain packet sizes Terrain packet sizes
*/ */

View File

@ -92,6 +92,13 @@ public class TerrainProtocol implements ServerProtocolTemplate<TerrainMessage> {
Vector3i blockPos = new Vector3i(message.getvoxelX(),message.getvoxelY(),message.getvoxelZ()); Vector3i blockPos = new Vector3i(message.getvoxelX(),message.getvoxelY(),message.getvoxelZ());
ServerBlockEditing.editBlockArea(playerRealm, worldPos, blockPos, (short)message.getblockType(), (short)message.getblockMetadata(), message.getblockEditSize()); ServerBlockEditing.editBlockArea(playerRealm, worldPos, blockPos, (short)message.getblockType(), (short)message.getblockMetadata(), message.getblockEditSize());
} break; } break;
case REQUESTPLACEFAB: {
Vector3i worldPos = new Vector3i(message.getworldX(),message.getworldY(),message.getworldZ());
Vector3i blockPos = new Vector3i(message.getvoxelX(),message.getvoxelY(),message.getvoxelZ());
Entity targetEntity = EntityLookupUtils.getEntityById(connectionHandler.getPlayerEntityId());
Realm playerRealm = Globals.realmManager.getEntityRealm(targetEntity);
ServerBlockEditing.placeBlockFab(playerRealm, worldPos, blockPos, message.getfabPath());
} break;
//all ignored message types //all ignored message types
case UPDATEFLUIDDATA: case UPDATEFLUIDDATA:
case RESPONSEMETADATA: case RESPONSEMETADATA:

View File

@ -1,6 +1,7 @@
package electrosphere.net.synchronization.client; package electrosphere.net.synchronization.client;
import electrosphere.util.Utilities;
import electrosphere.entity.state.item.ClientChargeState; import electrosphere.entity.state.item.ClientChargeState;
import electrosphere.entity.state.movement.editor.ClientEditorMovementTree; import electrosphere.entity.state.movement.editor.ClientEditorMovementTree;
import electrosphere.entity.state.equip.ClientToolbarState; import electrosphere.entity.state.equip.ClientToolbarState;

View File

@ -1,9 +1,12 @@
package electrosphere.server.physics.block.editing; package electrosphere.server.physics.block.editing;
import java.io.File;
import org.joml.Vector3i; import org.joml.Vector3i;
import electrosphere.client.block.BlockChunkData; import electrosphere.client.block.BlockChunkData;
import electrosphere.controls.cursor.CursorState; import electrosphere.controls.cursor.CursorState;
import electrosphere.game.data.block.BlockFab;
import electrosphere.server.datacell.Realm; import electrosphere.server.datacell.Realm;
import electrosphere.server.datacell.interfaces.VoxelCellManager; import electrosphere.server.datacell.interfaces.VoxelCellManager;
@ -69,4 +72,37 @@ public class ServerBlockEditing {
} }
} }
/**
* Places a block fab
* @param realm The realm
* @param chunkPos The chunk position
* @param voxelPos The voxel position
* @param fabPath The fab
*/
public static void placeBlockFab(Realm realm, Vector3i chunkPos, Vector3i voxelPos, String fabPath){
BlockFab fab = BlockFab.read(new File(fabPath));
Vector3i dims = fab.getDimensions();
Vector3i currChunkPos = new Vector3i();
Vector3i currVoxelPos = new Vector3i();
VoxelCellManager voxelCellManager = (VoxelCellManager) realm.getDataCellManager();
for(int x = 0; x < dims.x; x++){
for(int y = 0; y < dims.y; y++){
for(int z = 0; z < dims.z; z++){
currVoxelPos.set(voxelPos).add(x,y,z);
currChunkPos.set(chunkPos).add(
currVoxelPos.x / BlockChunkData.CHUNK_DATA_WIDTH,
currVoxelPos.y / BlockChunkData.CHUNK_DATA_WIDTH,
currVoxelPos.z / BlockChunkData.CHUNK_DATA_WIDTH
);
currVoxelPos.set(
currVoxelPos.x % BlockChunkData.CHUNK_DATA_WIDTH,
currVoxelPos.y % BlockChunkData.CHUNK_DATA_WIDTH,
currVoxelPos.z % BlockChunkData.CHUNK_DATA_WIDTH
);
voxelCellManager.editBlock(currChunkPos, currVoxelPos, fab.getType(x, y, z), (short)0);
}
}
}
}
} }

View File

@ -128,6 +128,10 @@
{ {
"name" : "blockEditSize", "name" : "blockEditSize",
"type" : "FIXED_INT" "type" : "FIXED_INT"
},
{
"name" : "fabPath",
"type" : "VAR_STRING"
} }
], ],
"messageTypes" : [ "messageTypes" : [
@ -330,6 +334,19 @@
"blockMetadata", "blockMetadata",
"blockEditSize" "blockEditSize"
] ]
},
{
"messageName" : "RequestPlaceFab",
"description" : "Requests that a fab be placed",
"data" : [
"worldX",
"worldY",
"worldZ",
"voxelX",
"voxelY",
"voxelZ",
"fabPath"
]
} }
] ]
} }