fab cursor rotation
All checks were successful
studiorailgun/Renderer/pipeline/head This commit looks good
All checks were successful
studiorailgun/Renderer/pipeline/head This commit looks good
This commit is contained in:
parent
0e50845ec6
commit
85c4cd2b6d
@ -1566,6 +1566,9 @@ More block types
|
||||
Transparent blocks
|
||||
Fix block meshgen
|
||||
|
||||
(04/27/2025)
|
||||
Fab cursor rotation + actually place rotated fab
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
package electrosphere.client.interact.select;
|
||||
|
||||
import org.joml.Vector3d;
|
||||
import org.joml.Vector3i;
|
||||
|
||||
/**
|
||||
* An area of space that is selected by the client
|
||||
@ -46,6 +47,19 @@ public class AreaSelection {
|
||||
return rVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the rectangular area of empty voxels in the block chunks starting at a given position
|
||||
* @param chunkPos The chunk position to start from
|
||||
* @param blockPos The block position to start from
|
||||
* @param maxRadius The maximum radius to expand the area to
|
||||
* @return The AreaSelection
|
||||
*/
|
||||
public static AreaSelection selectRectangularBlockCavity(Vector3i chunkPos, Vector3i blockPos, int maxRadius){
|
||||
AreaSelection rVal = null;
|
||||
|
||||
return rVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the type of area
|
||||
* @return The type of area
|
||||
@ -71,5 +85,4 @@ public class AreaSelection {
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -146,9 +146,11 @@ public class ScriptClientVoxelUtils {
|
||||
Vector3d fabCursorPos = EntityUtils.getPosition(CursorState.getFabCursor());
|
||||
Vector3i chunkPos = Globals.clientWorldData.convertRealToWorldSpace(fabCursorPos);
|
||||
Vector3i voxelPos = Globals.clientWorldData.convertRealToBlockSpace(fabCursorPos);
|
||||
int rotation = Globals.cursorState.getFabCursorRotation();
|
||||
Globals.clientConnection.queueOutgoingMessage(TerrainMessage.constructRequestPlaceFabMessage(
|
||||
chunkPos.x, chunkPos.y, chunkPos.z,
|
||||
voxelPos.x, voxelPos.y, voxelPos.z,
|
||||
rotation,
|
||||
fabPath
|
||||
));
|
||||
}
|
||||
|
||||
@ -612,7 +612,10 @@ public class ControlCategoryMainGame {
|
||||
mainGameControlList.add(controlMap.get(TOOLBAR_SCROLL));
|
||||
controlMap.get(TOOLBAR_SCROLL).setOnScroll(new Control.ScrollCallback() {public void execute(MouseState mouseState, ScrollEvent scrollEvent){
|
||||
boolean handled = false;
|
||||
if(Globals.controlCallback.getKey(GLFW.GLFW_KEY_LEFT_CONTROL)){
|
||||
if(
|
||||
Globals.controlCallback.getKey(GLFW.GLFW_KEY_LEFT_CONTROL) &&
|
||||
!Globals.controlCallback.getKey(GLFW.GLFW_KEY_LEFT_SHIFT)
|
||||
){
|
||||
//if the block cursor is visible, capture this input and instead modify block cursor
|
||||
if(Globals.clientScene.getEntitiesWithTag(EntityTags.DRAWABLE).contains(Globals.playerBlockCursor)){
|
||||
Globals.cursorState.updateCursorSize(scrollEvent);
|
||||
@ -620,6 +623,18 @@ public class ControlCategoryMainGame {
|
||||
}
|
||||
}
|
||||
|
||||
if(
|
||||
!Globals.controlCallback.getKey(GLFW.GLFW_KEY_LEFT_CONTROL) &&
|
||||
Globals.controlCallback.getKey(GLFW.GLFW_KEY_LEFT_SHIFT)
|
||||
){
|
||||
//if the fab cursor is visible, capture this input and instead modify fab cursor
|
||||
if(Globals.clientScene.getEntitiesWithTag(EntityTags.DRAWABLE).contains(CursorState.getFabCursor())){
|
||||
Globals.cursorState.rotateBlockCursor(scrollEvent);
|
||||
handled = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if(!handled){
|
||||
if(Globals.playerEntity != null && ClientToolbarState.getClientToolbarState(Globals.playerEntity) != null){
|
||||
ClientToolbarState clientToolbarState = ClientToolbarState.getClientToolbarState(Globals.playerEntity);
|
||||
|
||||
@ -2,6 +2,7 @@ package electrosphere.controls.cursor;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.joml.Quaterniond;
|
||||
import org.joml.Vector3d;
|
||||
import org.joml.Vector3i;
|
||||
|
||||
@ -86,6 +87,18 @@ public class CursorState {
|
||||
*/
|
||||
static Entity playerFabCursor;
|
||||
|
||||
/**
|
||||
* Maximum value to rotate to
|
||||
*/
|
||||
private static final int MAX_ROTATION_VAL = 15;
|
||||
|
||||
/**
|
||||
* The rotation of the fab cursor
|
||||
* The first two bits encode a rotation about the x axis
|
||||
* The next two bits encode a subsequent rotation about the y axis
|
||||
*/
|
||||
private int fabCursorRotation = 0;
|
||||
|
||||
/**
|
||||
* The currently selected fab
|
||||
*/
|
||||
@ -198,6 +211,7 @@ public class CursorState {
|
||||
CursorState.hide();
|
||||
Globals.cursorState.setClampToExistingBlock(false);
|
||||
Globals.clientSceneWrapper.getScene().registerEntityToTag(CursorState.playerFabCursor, EntityTags.DRAWABLE);
|
||||
Globals.cursorState.fabCursorRotation = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -311,6 +325,81 @@ public class CursorState {
|
||||
EntityUtils.getScale(Globals.playerBlockCursor).set(BLOCK_CURSOR_SCALE_MULTIPLIER * this.blockSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* Rotates the block cursor
|
||||
* @param scrollEvent The scroll event
|
||||
*/
|
||||
public void rotateBlockCursor(ScrollEvent scrollEvent){
|
||||
if(scrollEvent.getScrollAmount() > 0){
|
||||
if(this.fabCursorRotation > 0){
|
||||
this.fabCursorRotation--;
|
||||
} else {
|
||||
this.fabCursorRotation = MAX_ROTATION_VAL;
|
||||
}
|
||||
} else {
|
||||
if(this.fabCursorRotation < MAX_ROTATION_VAL){
|
||||
this.fabCursorRotation++;
|
||||
} else {
|
||||
this.fabCursorRotation = 0;
|
||||
}
|
||||
}
|
||||
this.setFabCursorRotation(this.fabCursorRotation);;
|
||||
}
|
||||
|
||||
/**
|
||||
* Rotates the fab cursor
|
||||
* @param rotationVal The value that encodes the rotation
|
||||
*/
|
||||
public void setFabCursorRotation(int rotationVal){
|
||||
Quaterniond rotations = CursorState.getBlockRotation(rotationVal);
|
||||
EntityUtils.getRotation(playerFabCursor).set(rotations);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the rotation of a block based on its int-encoded rotation value
|
||||
* @param rotationVal The int-encoded rotation value
|
||||
* @return The corresponding quaterniond
|
||||
*/
|
||||
public static Quaterniond getBlockRotation(int rotationVal){
|
||||
int tempVal = rotationVal;
|
||||
int xRotation = tempVal & 0x3;
|
||||
int yRotation = tempVal >> 2 & 0x3;
|
||||
Quaterniond rotations = new Quaterniond();
|
||||
double xRot = 0;
|
||||
double yRot = 0;
|
||||
switch(xRotation){
|
||||
case 0: {
|
||||
//no rotation applied
|
||||
} break;
|
||||
case 1: {
|
||||
xRot = Math.PI / 2.0;
|
||||
} break;
|
||||
case 2: {
|
||||
xRot = Math.PI;
|
||||
} break;
|
||||
case 3: {
|
||||
xRot = 3.0 * Math.PI / 2.0;
|
||||
} break;
|
||||
}
|
||||
switch(yRotation){
|
||||
case 0: {
|
||||
//no rotation applied
|
||||
} break;
|
||||
case 1: {
|
||||
yRot = Math.PI / 2.0;
|
||||
} break;
|
||||
case 2: {
|
||||
yRot = Math.PI;
|
||||
} break;
|
||||
case 3: {
|
||||
yRot = 3.0 * Math.PI / 2.0;
|
||||
} break;
|
||||
}
|
||||
rotations.rotateLocalZ(xRot);
|
||||
rotations.rotateLocalY(yRot);
|
||||
return rotations;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the block fab cursor's current fab
|
||||
* @param fab The fab
|
||||
@ -433,4 +522,12 @@ public class CursorState {
|
||||
return playerFabCursor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the rotation of the fab cursor
|
||||
* @return The rotation of the fab cursor
|
||||
*/
|
||||
public int getFabCursorRotation(){
|
||||
return this.fabCursorRotation;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -64,6 +64,7 @@ public class TerrainMessage extends NetworkMessage {
|
||||
int blockMetadata;
|
||||
int blockEditSize;
|
||||
String fabPath;
|
||||
int blockRotation;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
@ -477,6 +478,20 @@ public class TerrainMessage extends NetworkMessage {
|
||||
this.fabPath = fabPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets blockRotation
|
||||
*/
|
||||
public int getblockRotation() {
|
||||
return blockRotation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets blockRotation
|
||||
*/
|
||||
public void setblockRotation(int blockRotation) {
|
||||
this.blockRotation = blockRotation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the packet header from the buffer
|
||||
* @param byteBuffer The buffer
|
||||
@ -1304,17 +1319,20 @@ public class TerrainMessage extends NetworkMessage {
|
||||
if(currentStreamLength < 26){
|
||||
return false;
|
||||
}
|
||||
int fabPathSize = 0;
|
||||
if(currentStreamLength < 30){
|
||||
return false;
|
||||
}
|
||||
int fabPathSize = 0;
|
||||
if(currentStreamLength < 34){
|
||||
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));
|
||||
temporaryByteQueue.add(byteBuffer.peek(30 + 0));
|
||||
temporaryByteQueue.add(byteBuffer.peek(30 + 1));
|
||||
temporaryByteQueue.add(byteBuffer.peek(30 + 2));
|
||||
temporaryByteQueue.add(byteBuffer.peek(30 + 3));
|
||||
fabPathSize = ByteStreamUtils.popIntFromByteQueue(temporaryByteQueue);
|
||||
}
|
||||
if(currentStreamLength < 30 + fabPathSize){
|
||||
if(currentStreamLength < 34 + fabPathSize){
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@ -1333,6 +1351,7 @@ public class TerrainMessage extends NetworkMessage {
|
||||
rVal.setvoxelX(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
|
||||
rVal.setvoxelY(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
|
||||
rVal.setvoxelZ(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
|
||||
rVal.setblockRotation(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
|
||||
rVal.setfabPath(ByteStreamUtils.popStringFromByteQueue(byteBuffer));
|
||||
return rVal;
|
||||
}
|
||||
@ -1340,7 +1359,7 @@ public class TerrainMessage extends NetworkMessage {
|
||||
/**
|
||||
* Constructs a message of type RequestPlaceFab
|
||||
*/
|
||||
public static TerrainMessage constructRequestPlaceFabMessage(int worldX,int worldY,int worldZ,int voxelX,int voxelY,int voxelZ,String fabPath){
|
||||
public static TerrainMessage constructRequestPlaceFabMessage(int worldX,int worldY,int worldZ,int voxelX,int voxelY,int voxelZ,int blockRotation,String fabPath){
|
||||
TerrainMessage rVal = new TerrainMessage(TerrainMessageType.REQUESTPLACEFAB);
|
||||
rVal.setworldX(worldX);
|
||||
rVal.setworldY(worldY);
|
||||
@ -1348,6 +1367,7 @@ public class TerrainMessage extends NetworkMessage {
|
||||
rVal.setvoxelX(voxelX);
|
||||
rVal.setvoxelY(voxelY);
|
||||
rVal.setvoxelZ(voxelZ);
|
||||
rVal.setblockRotation(blockRotation);
|
||||
rVal.setfabPath(fabPath);
|
||||
rVal.serialize();
|
||||
return rVal;
|
||||
@ -1862,7 +1882,7 @@ public class TerrainMessage extends NetworkMessage {
|
||||
}
|
||||
break;
|
||||
case REQUESTPLACEFAB:
|
||||
rawBytes = new byte[2+4+4+4+4+4+4+4+fabPath.length()];
|
||||
rawBytes = new byte[2+4+4+4+4+4+4+4+4+fabPath.length()];
|
||||
//message header
|
||||
rawBytes[0] = TypeBytes.MESSAGE_TYPE_TERRAIN;
|
||||
//entity messaage header
|
||||
@ -1891,13 +1911,17 @@ public class TerrainMessage extends NetworkMessage {
|
||||
for(int i = 0; i < 4; i++){
|
||||
rawBytes[22+i] = intValues[i];
|
||||
}
|
||||
intValues = ByteStreamUtils.serializeIntToBytes(fabPath.length());
|
||||
intValues = ByteStreamUtils.serializeIntToBytes(blockRotation);
|
||||
for(int i = 0; i < 4; i++){
|
||||
rawBytes[26+i] = intValues[i];
|
||||
}
|
||||
intValues = ByteStreamUtils.serializeIntToBytes(fabPath.length());
|
||||
for(int i = 0; i < 4; i++){
|
||||
rawBytes[30+i] = intValues[i];
|
||||
}
|
||||
stringBytes = fabPath.getBytes();
|
||||
for(int i = 0; i < fabPath.length(); i++){
|
||||
rawBytes[30+i] = stringBytes[i];
|
||||
rawBytes[34+i] = stringBytes[i];
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@ -97,7 +97,7 @@ public class TerrainProtocol implements ServerProtocolTemplate<TerrainMessage> {
|
||||
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());
|
||||
ServerBlockEditing.placeBlockFab(playerRealm, worldPos, blockPos, message.getblockRotation(), message.getfabPath());
|
||||
} break;
|
||||
//all ignored message types
|
||||
case UPDATEFLUIDDATA:
|
||||
|
||||
@ -2,7 +2,11 @@ package electrosphere.server.physics.block.editing;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import org.joml.Matrix4f;
|
||||
import org.joml.Quaterniond;
|
||||
import org.joml.Quaternionf;
|
||||
import org.joml.Vector3i;
|
||||
import org.joml.Vector4f;
|
||||
|
||||
import electrosphere.client.block.BlockChunkData;
|
||||
import electrosphere.controls.cursor.CursorState;
|
||||
@ -77,18 +81,28 @@ public class ServerBlockEditing {
|
||||
* @param realm The realm
|
||||
* @param chunkPos The chunk position
|
||||
* @param voxelPos The voxel position
|
||||
* @param rotation The rotation of the fab
|
||||
* @param fabPath The fab
|
||||
*/
|
||||
public static void placeBlockFab(Realm realm, Vector3i chunkPos, Vector3i voxelPos, String fabPath){
|
||||
public static void placeBlockFab(Realm realm, Vector3i chunkPos, Vector3i voxelPos, int rotation, 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();
|
||||
Quaterniond rotationQuatd = CursorState.getBlockRotation(rotation);
|
||||
Quaternionf rotationQuatf = new Quaternionf((float)rotationQuatd.x,(float)rotationQuatd.y,(float)rotationQuatd.z,(float)rotationQuatd.w);
|
||||
Matrix4f rotMat = new Matrix4f().rotate(rotationQuatf);
|
||||
Vector4f rotationHolder = new Vector4f();
|
||||
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);
|
||||
|
||||
rotationHolder.set(x,y,z,1);
|
||||
rotMat.transform(rotationHolder);
|
||||
currVoxelPos.set(voxelPos).add(Math.round(rotationHolder.x),Math.round(rotationHolder.y),Math.round(rotationHolder.z));
|
||||
|
||||
|
||||
currChunkPos.set(chunkPos).add(
|
||||
currVoxelPos.x / BlockChunkData.CHUNK_DATA_WIDTH,
|
||||
currVoxelPos.y / BlockChunkData.CHUNK_DATA_WIDTH,
|
||||
|
||||
@ -132,6 +132,10 @@
|
||||
{
|
||||
"name" : "fabPath",
|
||||
"type" : "VAR_STRING"
|
||||
},
|
||||
{
|
||||
"name" : "blockRotation",
|
||||
"type" : "FIXED_INT"
|
||||
}
|
||||
],
|
||||
"messageTypes" : [
|
||||
@ -345,6 +349,7 @@
|
||||
"voxelX",
|
||||
"voxelY",
|
||||
"voxelZ",
|
||||
"blockRotation",
|
||||
"fabPath"
|
||||
]
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user