area selection utility
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
c96c07334a
commit
cad9a994d0
@ -158,6 +158,37 @@
|
||||
"offsetZ" : 0
|
||||
},
|
||||
"iconPath" : "Textures/icons/hammer.png"
|
||||
},
|
||||
{
|
||||
"id" : "roomTool",
|
||||
"tokens" : [
|
||||
"GRAVITY",
|
||||
"TARGETABLE",
|
||||
"CURSOR_FAB"
|
||||
],
|
||||
"equipData": {
|
||||
"equipClass" : "tool"
|
||||
},
|
||||
"graphicsTemplate": {
|
||||
"model": {
|
||||
"path" : "Models/basic/geometry/unitvector.glb"
|
||||
}
|
||||
},
|
||||
"clientSideSecondary": "SELECT_ROOM",
|
||||
"collidable": {
|
||||
"type" : "CUBE",
|
||||
"dimension1" : 0.1,
|
||||
"dimension2" : 0.1,
|
||||
"dimension3" : 0.35,
|
||||
"rotX": 0,
|
||||
"rotY": 0,
|
||||
"rotZ": 0,
|
||||
"rotW": 1,
|
||||
"offsetX" : 0,
|
||||
"offsetY" : 0.05,
|
||||
"offsetZ" : 0
|
||||
},
|
||||
"iconPath" : "Textures/icons/hammer.png"
|
||||
}
|
||||
],
|
||||
"files" : [
|
||||
|
||||
@ -58,5 +58,11 @@ export const clientHooks: Hook[] = [
|
||||
callback: (engine: Engine) => {
|
||||
engine.classes.voxelUtils.static.placeFab()
|
||||
}
|
||||
},
|
||||
{
|
||||
signal: "SELECT_ROOM",
|
||||
callback: (engine: Engine) => {
|
||||
engine.classes.areaUtils.static.selectAreaRectangular()
|
||||
}
|
||||
}
|
||||
]
|
||||
11
assets/Scripts/types/host/client/client-area-utils.ts
Normal file
11
assets/Scripts/types/host/client/client-area-utils.ts
Normal file
@ -0,0 +1,11 @@
|
||||
/**
|
||||
* Utilities for managing areas on the client
|
||||
*/
|
||||
export interface ClientAreaUtils {
|
||||
|
||||
/**
|
||||
* Selects a rectangular area
|
||||
*/
|
||||
readonly selectAreaRectangular: () => void
|
||||
|
||||
}
|
||||
@ -1,3 +1,4 @@
|
||||
import { ClientAreaUtils } from "/Scripts/types/host/client/client-area-utils";
|
||||
import { ClientLevelEditorUtils } from "/Scripts/types/host/client/client-level-editor-utils";
|
||||
import { ClientVoxelUtils } from "/Scripts/types/host/client/client-voxel-utils";
|
||||
import { Entity } from "/Scripts/types/host/entity/entity";
|
||||
@ -51,6 +52,11 @@ export interface StaticClasses {
|
||||
*/
|
||||
readonly math?: Class<Math>
|
||||
|
||||
/**
|
||||
* Utilities for area management on the client
|
||||
*/
|
||||
readonly areaUtils?: Class<ClientAreaUtils>,
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -1574,6 +1574,10 @@ Block cursor work
|
||||
ChunkDiskMap code org
|
||||
Filter procedural worlds out of level select menu
|
||||
|
||||
(04/28/2025)
|
||||
Area selection utility
|
||||
RoomTool item
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@ -287,6 +287,15 @@ public class BlockChunkData implements BlockMeshgenData {
|
||||
boolean empty = this.getType(x,y,z) == BlockChunkData.BLOCK_TYPE_EMPTY;
|
||||
return empty;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a given location is empty
|
||||
* @param vec The position
|
||||
* @return true if empty, false otherwise
|
||||
*/
|
||||
public boolean isEmpty(Vector3i vec){
|
||||
return this.isEmpty(vec.x,vec.y,vec.z);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this block chunk is homogenous or not
|
||||
|
||||
@ -3,6 +3,9 @@ package electrosphere.client.interact.select;
|
||||
import org.joml.Vector3d;
|
||||
import org.joml.Vector3i;
|
||||
|
||||
import electrosphere.client.block.BlockChunkData;
|
||||
import electrosphere.engine.Globals;
|
||||
|
||||
/**
|
||||
* An area of space that is selected by the client
|
||||
*/
|
||||
@ -18,6 +21,11 @@ public class AreaSelection {
|
||||
RECTANGULAR,
|
||||
}
|
||||
|
||||
/**
|
||||
* Default radius to select
|
||||
*/
|
||||
public static final int DEFAULT_SELECTION_RADIUS = 10;
|
||||
|
||||
/**
|
||||
* The type of selection
|
||||
*/
|
||||
@ -40,6 +48,15 @@ public class AreaSelection {
|
||||
* @return The selection
|
||||
*/
|
||||
public static AreaSelection createRect(Vector3d start, Vector3d end){
|
||||
if(start.x > end.x){
|
||||
throw new Error("Start x is less than end x! " + start.x + " " + end.x);
|
||||
}
|
||||
if(start.y > end.y){
|
||||
throw new Error("Start y is less than end y! " + start.y + " " + end.y);
|
||||
}
|
||||
if(start.z > end.z){
|
||||
throw new Error("Start y is less than end y! " + start.z + " " + end.z);
|
||||
}
|
||||
AreaSelection rVal = new AreaSelection();
|
||||
rVal.type = AreaSelectionType.RECTANGULAR;
|
||||
rVal.rectStart = start;
|
||||
@ -57,6 +74,100 @@ public class AreaSelection {
|
||||
public static AreaSelection selectRectangularBlockCavity(Vector3i chunkPos, Vector3i blockPos, int maxRadius){
|
||||
AreaSelection rVal = null;
|
||||
|
||||
int radStart = 0;
|
||||
int radEnd = 1;
|
||||
int increment = 0;
|
||||
boolean expandPositive = true;
|
||||
boolean expandNegative = true;
|
||||
Vector3i currVoxelPos = new Vector3i();
|
||||
Vector3i currChunkPos = new Vector3i();
|
||||
while(radStart > -maxRadius && radEnd < maxRadius && (expandPositive || expandNegative)){
|
||||
if(increment % 2 == 0){
|
||||
if(!expandPositive){
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
if(!expandNegative){
|
||||
continue;
|
||||
}
|
||||
}
|
||||
for(int x = radStart; x < radEnd; x++){
|
||||
for(int y = radStart; y < radEnd; y++){
|
||||
for(int z = radStart; z < radEnd; z++){
|
||||
currVoxelPos.set(blockPos).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
|
||||
);
|
||||
if(!Globals.clientWorldData.chunkInBounds(currChunkPos)){
|
||||
if(increment % 2 == 0){
|
||||
expandPositive = false;
|
||||
} else {
|
||||
expandNegative = false;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
BlockChunkData chunkData = Globals.clientBlockManager.getChunkDataAtWorldPoint(currChunkPos, BlockChunkData.LOD_FULL_RES);
|
||||
if(chunkData == null){
|
||||
if(increment % 2 == 0){
|
||||
expandPositive = false;
|
||||
} else {
|
||||
expandNegative = false;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
while(currVoxelPos.x < 0){
|
||||
currVoxelPos.x = currVoxelPos.x + BlockChunkData.CHUNK_DATA_WIDTH;
|
||||
}
|
||||
while(currVoxelPos.y < 0){
|
||||
currVoxelPos.y = currVoxelPos.y + BlockChunkData.CHUNK_DATA_WIDTH;
|
||||
}
|
||||
while(currVoxelPos.z < 0){
|
||||
currVoxelPos.z = currVoxelPos.z + BlockChunkData.CHUNK_DATA_WIDTH;
|
||||
}
|
||||
if(!chunkData.isEmpty(currVoxelPos)){
|
||||
if(increment % 2 == 0){
|
||||
expandPositive = false;
|
||||
} else {
|
||||
expandNegative = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if(increment % 2 == 0){
|
||||
if(expandPositive){
|
||||
radEnd++;
|
||||
}
|
||||
} else {
|
||||
if(expandNegative){
|
||||
radStart--;
|
||||
}
|
||||
}
|
||||
increment++;
|
||||
}
|
||||
|
||||
Vector3d startPos = new Vector3d(Globals.clientWorldData.convertBlockToRealSpace(chunkPos, blockPos))
|
||||
.add(
|
||||
radStart * BlockChunkData.BLOCK_SIZE_MULTIPLIER,
|
||||
radStart * BlockChunkData.BLOCK_SIZE_MULTIPLIER,
|
||||
radStart * BlockChunkData.BLOCK_SIZE_MULTIPLIER
|
||||
);
|
||||
Vector3d endPos = new Vector3d(Globals.clientWorldData.convertBlockToRealSpace(chunkPos, blockPos))
|
||||
.add(
|
||||
radEnd * BlockChunkData.BLOCK_SIZE_MULTIPLIER,
|
||||
radEnd * BlockChunkData.BLOCK_SIZE_MULTIPLIER,
|
||||
radEnd * BlockChunkData.BLOCK_SIZE_MULTIPLIER
|
||||
);
|
||||
|
||||
rVal = AreaSelection.createRect(startPos, endPos);
|
||||
|
||||
return rVal;
|
||||
}
|
||||
|
||||
|
||||
@ -239,4 +239,14 @@ public class ClientWorldData {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that a chunk position is in bounds
|
||||
* @param chunkPos The chunk pos
|
||||
* @return true if it is in bounds, false otherwise
|
||||
*/
|
||||
public boolean chunkInBounds(Vector3i chunkPos){
|
||||
return chunkPos.x >= 0 && chunkPos.y >= 0 && chunkPos.z >= 0 &&
|
||||
chunkPos.x < this.worldDiscreteSize && chunkPos.y < this.worldDiscreteSize && chunkPos.z < this.worldDiscreteSize;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -0,0 +1,31 @@
|
||||
package electrosphere.client.script;
|
||||
|
||||
import org.graalvm.polyglot.HostAccess.Export;
|
||||
import org.joml.Vector3d;
|
||||
import org.joml.Vector3i;
|
||||
|
||||
import electrosphere.client.interact.select.AreaSelection;
|
||||
import electrosphere.controls.cursor.CursorState;
|
||||
import electrosphere.engine.Globals;
|
||||
import electrosphere.entity.EntityUtils;
|
||||
|
||||
/**
|
||||
* Script utils for clients dealing with areas
|
||||
*/
|
||||
public class ScriptClientAreaUtils {
|
||||
|
||||
/**
|
||||
* Tries to select a rectangular area
|
||||
*/
|
||||
@Export
|
||||
public static void selectAreaRectangular(){
|
||||
// Vector3d blockCursorPos = Globals.cursorState.getBlockCursorPos();
|
||||
Vector3d cursorPos = new Vector3d(EntityUtils.getPosition(Globals.playerCursor));
|
||||
Vector3i chunkPos = Globals.clientWorldData.convertRealToWorldSpace(cursorPos);
|
||||
Vector3i blockPos = Globals.clientWorldData.convertRealToBlockSpace(cursorPos);
|
||||
AreaSelection selection = AreaSelection.selectRectangularBlockCavity(chunkPos, blockPos, AreaSelection.DEFAULT_SELECTION_RADIUS);
|
||||
Globals.cursorState.selectRectangularArea(selection);
|
||||
CursorState.makeAreaVisible();
|
||||
}
|
||||
|
||||
}
|
||||
@ -169,6 +169,7 @@ public class LoadingUtils {
|
||||
template.getCreatureToolbarData().setSlotItem("2", new ToolbarItem(73, "entityinspector"));
|
||||
template.getCreatureToolbarData().setSlotItem("3", new ToolbarItem(74, "waterSpawner"));
|
||||
template.getCreatureToolbarData().setSlotItem("4", new ToolbarItem(75, "fabTool"));
|
||||
template.getCreatureToolbarData().setSlotItem("5", new ToolbarItem(76, "roomTool"));
|
||||
//set player character template
|
||||
serverPlayerConnection.setCreatureTemplate(template);
|
||||
Globals.clientConnection.queueOutgoingMessage(CharacterMessage.constructRequestSpawnCharacterMessage(CharacterProtocol.SPAWN_EXISTING_TEMPLATE + ""));
|
||||
|
||||
@ -143,6 +143,7 @@ public class CharacterProtocol implements ServerProtocolTemplate<CharacterMessag
|
||||
template.getCreatureToolbarData().setSlotItem("2", new ToolbarItem(73, "entityinspector"));
|
||||
template.getCreatureToolbarData().setSlotItem("3", new ToolbarItem(74, "waterSpawner"));
|
||||
template.getCreatureToolbarData().setSlotItem("4", new ToolbarItem(75, "fabTool"));
|
||||
template.getCreatureToolbarData().setSlotItem("5", new ToolbarItem(76, "roomTool"));
|
||||
//set player character template
|
||||
connectionHandler.setCreatureTemplate(template);
|
||||
} else {
|
||||
@ -165,6 +166,7 @@ public class CharacterProtocol implements ServerProtocolTemplate<CharacterMessag
|
||||
template.getCreatureToolbarData().setSlotItem("2", new ToolbarItem(73, "entityinspector"));
|
||||
template.getCreatureToolbarData().setSlotItem("3", new ToolbarItem(74, "waterSpawner"));
|
||||
template.getCreatureToolbarData().setSlotItem("4", new ToolbarItem(75, "fabTool"));
|
||||
template.getCreatureToolbarData().setSlotItem("5", new ToolbarItem(76, "roomTool"));
|
||||
//set player character template
|
||||
connectionHandler.setCreatureTemplate(template);
|
||||
}
|
||||
|
||||
@ -21,6 +21,7 @@ import java.util.Map;
|
||||
import org.graalvm.polyglot.Source;
|
||||
import org.graalvm.polyglot.Value;
|
||||
|
||||
import electrosphere.client.script.ScriptClientAreaUtils;
|
||||
import electrosphere.client.script.ScriptClientVoxelUtils;
|
||||
import electrosphere.client.ui.menu.script.ScriptLevelEditorUtils;
|
||||
import electrosphere.client.ui.menu.script.ScriptMenuUtils;
|
||||
@ -121,6 +122,7 @@ public class ScriptEngine extends SignalServiceImpl {
|
||||
{"voxelUtils",ScriptClientVoxelUtils.class},
|
||||
{"levelEditorUtils",ScriptLevelEditorUtils.class},
|
||||
{"math",ScriptMathInterface.class},
|
||||
{"areaUtils",ScriptClientAreaUtils.class},
|
||||
};
|
||||
|
||||
//singletons from the host that are provided to the javascript context
|
||||
|
||||
Loading…
Reference in New Issue
Block a user