variable size for block editing
Some checks failed
studiorailgun/Renderer/pipeline/head There was a failure building this commit

This commit is contained in:
austin 2025-04-25 19:48:25 -04:00
parent 7b1610d847
commit f7c6208a2a
23 changed files with 592 additions and 181 deletions

View File

@ -1535,6 +1535,7 @@ Fix macro character entities not being assigned ServerCharacterData
Audio on placing blocks
Audio on placing/removing voxels
Debounce item usage activations
Variable block editing size

View File

@ -5,6 +5,7 @@ import org.joml.Vector3d;
import electrosphere.audio.VirtualAudioSourceManager.VirtualAudioSourceType;
import electrosphere.client.entity.camera.CameraEntityUtils;
import electrosphere.client.script.ClientScriptUtils;
import electrosphere.client.terrain.editing.BlockEditing;
import electrosphere.collision.CollisionEngine;
import electrosphere.engine.Globals;
import electrosphere.engine.assetmanager.AssetDataStrings;
@ -148,16 +149,12 @@ public class ItemActions {
if(cursorPos == null){
cursorPos = new Vector3d(centerPos).add(new Vector3d(eyePos).normalize().mul(-CollisionEngine.DEFAULT_INTERACT_DISTANCE));
}
//tell the server we want the secondary hand item to START doing something
Globals.clientConnection.queueOutgoingMessage(InventoryMessage.constructclientRequestPerformItemActionMessage(
"handRight",
ITEM_ACTION_CODE_SECONDARY,
ITEM_ACTION_CODE_STATE_ON,
cursorPos.x,
cursorPos.y,
cursorPos.z
));
//TODO: do any immediate client side calculations here (ie start playing an animation until we get response from server)
//send server message if we're not doing a block edit
//client sends custom packets for block editing
boolean sendServerMessage = true;
//do any immediate client side calculations here (ie start playing an animation until we get response from server)
if(Globals.playerEntity != null){
ClientToolbarState clientToolbarState = ClientToolbarState.getClientToolbarState(Globals.playerEntity);
Entity primaryEntity = clientToolbarState.getCurrentPrimaryItem();
@ -168,11 +165,25 @@ public class ItemActions {
}
if(data.getSecondaryUsage() != null){
if(data.getSecondaryUsage().getBlockId() != null){
sendServerMessage = false;
BlockEditing.editBlock((short)(int)data.getSecondaryUsage().getBlockId(),(short)0);
Globals.virtualAudioSourceManager.createVirtualAudioSource(AssetDataStrings.INTERACT_SFX_BLOCK_PLACE, VirtualAudioSourceType.CREATURE, false);
}
}
}
}
//send server message
if(sendServerMessage){
//tell the server we want the secondary hand item to START doing something
Globals.clientConnection.queueOutgoingMessage(InventoryMessage.constructclientRequestPerformItemActionMessage(
"handRight",
ITEM_ACTION_CODE_SECONDARY,
ITEM_ACTION_CODE_STATE_ON,
cursorPos.x,
cursorPos.y,
cursorPos.z
));
}
}
/**

View File

@ -4,6 +4,7 @@ import org.joml.Vector3d;
import org.joml.Vector3f;
import org.joml.Vector3i;
import electrosphere.client.block.BlockChunkData;
import electrosphere.server.physics.terrain.manager.ServerTerrainChunk;
/**
@ -178,17 +179,39 @@ public class ClientWorldData {
*/
public Vector3d convertWorldToRealSpace(Vector3i position){
return new Vector3d(
convertWorldToReal(position.x),
convertWorldToReal(position.y),
convertWorldToReal(position.z)
this.convertWorldToReal(position.x),
this.convertWorldToReal(position.y),
this.convertWorldToReal(position.z)
);
}
public Vector3i convertRealToVoxelSpace(Vector3d position){
return new Vector3i(
(int)Math.floor(position.x - convertChunkToRealSpace(convertRealToChunkSpace(position.x))),
(int)Math.floor(position.y - convertChunkToRealSpace(convertRealToChunkSpace(position.y))),
(int)Math.floor(position.z - convertChunkToRealSpace(convertRealToChunkSpace(position.z)))
(int)Math.floor(position.x - this.convertChunkToRealSpace(this.convertRealToChunkSpace(position.x))),
(int)Math.floor(position.y - this.convertChunkToRealSpace(this.convertRealToChunkSpace(position.y))),
(int)Math.floor(position.z - this.convertChunkToRealSpace(this.convertRealToChunkSpace(position.z)))
);
}
/**
* Converts a real position to a block position
* @param real The real position
* @return The closest block position
*/
public int convertRealToLocalBlockSpace(double real){
return (int)Math.floor(real * BlockChunkData.BLOCKS_PER_UNIT_DISTANCE % BlockChunkData.CHUNK_DATA_WIDTH);
}
/**
* Converts the position to a block-space position
* @param position The real-space position
* @return The nearest block-space position
*/
public Vector3i convertRealToBlockSpace(Vector3d position){
return new Vector3i(
this.convertRealToLocalBlockSpace(position.x),
this.convertRealToLocalBlockSpace(position.y),
this.convertRealToLocalBlockSpace(position.z)
);
}

View File

@ -12,6 +12,7 @@ import electrosphere.collision.CollisionEngine;
import electrosphere.engine.Globals;
import electrosphere.engine.assetmanager.AssetDataStrings;
import electrosphere.entity.Entity;
import electrosphere.net.parser.net.message.TerrainMessage;
import electrosphere.server.physics.terrain.manager.ServerTerrainChunk;
/**
@ -116,4 +117,21 @@ public class ScriptClientVoxelUtils {
}
}
/**
* Requests a block edit from the client
* @param chunkPos The position of the chunk to edit
* @param blockPos The position of the block to edit
* @param blockType The type of block
* @param blockMetadata The metadata of the block
* @param size The size of the blocks to edit
*/
@Export
public static void clientRequestEditBlock(Vector3i chunkPos, Vector3i blockPos, short blockType, short blockMetadata, int size){
Globals.clientConnection.queueOutgoingMessage(TerrainMessage.constructRequestEditBlockMessage(
chunkPos.x, chunkPos.y, chunkPos.z,
blockPos.x, blockPos.y, blockPos.z,
blockType, blockMetadata, size
));
}
}

View File

@ -0,0 +1,26 @@
package electrosphere.client.terrain.editing;
import org.joml.Vector3i;
import electrosphere.client.script.ScriptClientVoxelUtils;
import electrosphere.engine.Globals;
import electrosphere.entity.EntityUtils;
/**
* Utilities for editing blocks
*/
public class BlockEditing {
/**
* Edit blocks
* @param type The type of block
* @param metadata The metadata of the block
*/
public static void editBlock(short type, short metadata){
Vector3i cornerVoxel = Globals.cursorState.getBlockCornerVoxelPos();
int blockSize = Globals.cursorState.getBlockSize();
Vector3i chunkPos = Globals.clientWorldData.convertRealToWorldSpace(EntityUtils.getPosition(Globals.playerBlockCursor));
ScriptClientVoxelUtils.clientRequestEditBlock(chunkPos, cornerVoxel, type, metadata, blockSize);
}
}

View File

@ -5,9 +5,7 @@ import org.joml.Vector3d;
import electrosphere.client.entity.camera.CameraEntityUtils;
import electrosphere.client.entity.crosshair.Crosshair;
import electrosphere.collision.CollisionEngine;
import electrosphere.engine.Globals;
import electrosphere.entity.Entity;
import electrosphere.entity.EntityUtils;
import electrosphere.net.parser.net.message.EntityMessage;
import electrosphere.renderer.ui.events.MouseEvent;
@ -18,29 +16,59 @@ import electrosphere.util.math.SpatialMathUtils;
*/
public class CameraHandler {
//The first person camera perspective
/**
* The first person camera perspective
*/
public static final int CAMERA_PERSPECTIVE_FIRST = 1;
//The third person camera perspective
/**
* The third person camera perspective
*/
public static final int CAMERA_PERSPECTIVE_THIRD = 3;
//the horizontal mouse sensitivity
/**
* the horizontal mouse sensitivity
*/
float mouseSensitivityHorizontal = .1f;
//the vertical mouse sensitivity
/**
* the vertical mouse sensitivity
*/
float mouseSensitivityVertical = .08f;
//the speed of the freecam
/**
* the speed of the freecam
*/
float cameraSpeed;
//the current yaw
/**
* the current yaw
*/
float yaw = 150;
//the current pitch
/**
* the current pitch
*/
float pitch = 50;
//the camera's rotation vector
/**
* the camera's rotation vector
*/
Vector3d cameraRotationVector = new Vector3d();
//the radial offset of the camera
/**
* the radial offset of the camera
*/
Vector3d radialOffset = new Vector3d(0,1,0);
//if set to true, the camera will track the player's entity
/**
* if set to true, the camera will track the player's entity
*/
boolean trackPlayerEntity = true;
//sets whether the camera handler should update the player's camera or not
/**
* sets whether the camera handler should update the player's camera or not
*/
boolean update = true;
/**
@ -138,37 +166,12 @@ public class CameraHandler {
Globals.viewMatrix = CameraEntityUtils.getCameraViewMatrix(Globals.playerCamera);
//update the cursor on client side
this.updatePlayerCursor();
Globals.cursorState.updatePlayerCursor();
}
}
Globals.profiler.endCpuSample();
}
/**
* Updates the position of the player's in world cursor
*/
private void updatePlayerCursor(){
CollisionEngine collisionEngine = Globals.clientSceneWrapper.getCollisionEngine();
Entity camera = Globals.playerCamera;
if(
collisionEngine != null &&
camera != null &&
Globals.playerCursor != null
){
Vector3d eyePos = new Vector3d(CameraEntityUtils.getCameraEye(camera));
Vector3d centerPos = new Vector3d(CameraEntityUtils.getCameraCenter(camera));
Vector3d cursorPos = collisionEngine.rayCastPosition(centerPos, new Vector3d(eyePos).mul(-1.0), CollisionEngine.DEFAULT_INTERACT_DISTANCE);
if(cursorPos == null){
cursorPos = new Vector3d(centerPos).add(new Vector3d(eyePos).normalize().mul(-CollisionEngine.DEFAULT_INTERACT_DISTANCE));
}
EntityUtils.getPosition(Globals.playerCursor).set(cursorPos);
//clamp block cursor to nearest voxel
cursorPos.set(PlayerCursor.clampPositionToNearestBlock(cursorPos));
EntityUtils.getPosition(Globals.playerBlockCursor).set(cursorPos);
}
}
/**
* Gets the yaw of the camera handler
* @return the yaw

View File

@ -5,15 +5,23 @@ import org.lwjgl.glfw.GLFWKeyCallbackI;
import electrosphere.logger.LoggerInterface;
/**
* Callback that is invoked on key input received by GLFW
*/
public class ControlCallback implements GLFWKeyCallbackI {
/**
* The size of the key state tracking array
*/
static final short KEY_VALUE_ARRAY_SIZE = 512;
/**
* Array that tracks the state of keys
*/
boolean[] keyValues = new boolean[KEY_VALUE_ARRAY_SIZE];
@Override
public void invoke(long window, int key, int scancode, int action, int mods) {
public void invoke(long window, int key, int scancode, int action, int mods){
if(key >= 0 && key < KEY_VALUE_ARRAY_SIZE){
if(action == GLFW.GLFW_PRESS || action == GLFW.GLFW_REPEAT){
keyValues[key] = true;
@ -21,18 +29,12 @@ public class ControlCallback implements GLFWKeyCallbackI {
keyValues[key] = false;
}
}
// if(key == GLFW.GLFW_KEY_D){
// System.out.println("[D]Action: " + action + " keyValues: " + keyValues[key]);
// }
// if(key == GLFW.GLFW_KEY_W){
// System.out.println("[W]Action: " + action + " keyValues: " + keyValues[key]);
// }
}
/**
* !!!WARNING!!!, will silently fail if opengl elementsn ot defined or keycode is outside of key value array size or is not in main rendering thread
* @param keycode
* @return
* @param keycode The keycode to check
* @return true if it is pressed, false otherwise
*/
public boolean getKey(int keycode){
if(keycode >= 0 && keycode < KEY_VALUE_ARRAY_SIZE){

View File

@ -116,7 +116,7 @@ public class ControlHandler {
/**
* Constructor
*/
ControlHandler(){
private ControlHandler(){
controls = new HashMap<String, Control>();
}
@ -375,25 +375,25 @@ public class ControlHandler {
}
//set to menu state if a menu is open, otherwise use the hinted control scheme
if(onlyInventoryMenusOpen()){
setHandlerState(ControlsState.INVENTORY);
} else if(hasControlBlockingMenuOpen()){
setHandlerState(ControlsState.IN_GAME_MAIN_MENU);
if(this.onlyInventoryMenusOpen()){
this.setHandlerState(ControlsState.INVENTORY);
} else if(this.hasControlBlockingMenuOpen()){
this.setHandlerState(ControlsState.IN_GAME_MAIN_MENU);
} else {
setHandlerState(properState);
this.setHandlerState(properState);
}
//checks if the current handler state should have mouse enabled or not
if(Arrays.binarySearch(mouseEnabledStates,getHandlerState()) >= 0){
showMouse();
this.showMouse();
} else {
hideMouse();
this.hideMouse();
}
}
/**
* Transfers the mouse position from the glfw buffer to variables stored inside the control handler
*/
void getMousePositionInBuffer(){
private void getMousePositionInBuffer(){
//only if not headless, gather position
if(!Globals.HEADLESS){
glfwGetCursorPos(Globals.window, this.mouseState.getMouseBufferX(), this.mouseState.getMouseBufferY());
@ -404,7 +404,7 @@ public class ControlHandler {
* Checks if the mouse button 1 is currently pressed
* @return true if pressed, false otherwise
*/
boolean getButton1Raw(){
private boolean getButton1Raw(){
if(Globals.HEADLESS){
return false;
} else {
@ -416,7 +416,7 @@ public class ControlHandler {
* Checks if the mouse button 2 is currently pressed
* @return true if pressed, false otherwise
*/
boolean getButton2Raw(){
private boolean getButton2Raw(){
if(Globals.HEADLESS){
return false;
} else {

View File

@ -1,49 +0,0 @@
package electrosphere.controls;
import org.joml.Vector3d;
import electrosphere.client.block.BlockChunkData;
/**
* Utilities for dealing with cursors
*/
public class PlayerCursor {
/**
* Token for displaying cursor
*/
public static final String CURSOR_TOKEN = "CURSOR";
/**
* Token for displaying block cursor
*/
public static final String CURSOR_BLOCK_TOKEN = "CURSOR_BLOCK";
/**
* Clamps a real position to the nearest block
* @param input The input real position
* @return The real position clamped to the nearest block
*/
public static Vector3d clampPositionToNearestBlock(Vector3d input){
double x = 0;
double y = 0;
double z = 0;
if(input.x % BlockChunkData.BLOCK_SIZE_MULTIPLIER > BlockChunkData.BLOCK_SIZE_MULTIPLIER / 2.0){
x = input.x - input.x % 0.25 + BlockChunkData.BLOCK_SIZE_MULTIPLIER + BlockChunkData.BLOCK_SIZE_MULTIPLIER / 2.0;
} else {
x = input.x - input.x % 0.25 + BlockChunkData.BLOCK_SIZE_MULTIPLIER / 2.0;
}
if(input.y % BlockChunkData.BLOCK_SIZE_MULTIPLIER > BlockChunkData.BLOCK_SIZE_MULTIPLIER / 2.0){
y = input.y - input.y % 0.25 + BlockChunkData.BLOCK_SIZE_MULTIPLIER + BlockChunkData.BLOCK_SIZE_MULTIPLIER / 2.0;
} else {
y = input.y - input.y % 0.25 + BlockChunkData.BLOCK_SIZE_MULTIPLIER / 2.0;
}
if(input.z % BlockChunkData.BLOCK_SIZE_MULTIPLIER > BlockChunkData.BLOCK_SIZE_MULTIPLIER / 2.0){
z = input.z - input.z % 0.25 + BlockChunkData.BLOCK_SIZE_MULTIPLIER + BlockChunkData.BLOCK_SIZE_MULTIPLIER / 2.0;
} else {
z = input.z - input.z % 0.25 + BlockChunkData.BLOCK_SIZE_MULTIPLIER / 2.0;
}
return new Vector3d(x,y,z);
}
}

View File

@ -1,5 +1,7 @@
package electrosphere.controls.categories;
import static org.lwjgl.glfw.GLFW.GLFW_KEY_LEFT_CONTROL;
import java.util.HashMap;
import java.util.List;
@ -26,6 +28,7 @@ import electrosphere.engine.Globals;
import electrosphere.engine.Main;
import electrosphere.engine.assetmanager.AssetDataStrings;
import electrosphere.entity.Entity;
import electrosphere.entity.EntityTags;
import electrosphere.entity.btree.BehaviorTree;
import electrosphere.entity.state.equip.ClientEquipState;
import electrosphere.entity.state.equip.ClientToolbarState;
@ -597,12 +600,23 @@ public class ControlCategoryMainGame {
*/
mainGameControlList.add(controlMap.get(TOOLBAR_SCROLL));
controlMap.get(TOOLBAR_SCROLL).setOnScroll(new Control.ScrollCallback() {public void execute(MouseState mouseState, ScrollEvent scrollEvent){
if(Globals.playerEntity != null && ClientToolbarState.getClientToolbarState(Globals.playerEntity) != null){
ClientToolbarState clientToolbarState = ClientToolbarState.getClientToolbarState(Globals.playerEntity);
if(scrollEvent.getScrollAmount() > 0){
clientToolbarState.attemptChangeSelection(clientToolbarState.getSelectedSlot() - 1);
} else {
clientToolbarState.attemptChangeSelection(clientToolbarState.getSelectedSlot() + 1);
boolean handled = false;
if(Globals.controlCallback.getKey(GLFW_KEY_LEFT_CONTROL)){
//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);
handled = true;
}
}
if(!handled){
if(Globals.playerEntity != null && ClientToolbarState.getClientToolbarState(Globals.playerEntity) != null){
ClientToolbarState clientToolbarState = ClientToolbarState.getClientToolbarState(Globals.playerEntity);
if(scrollEvent.getScrollAmount() > 0){
clientToolbarState.attemptChangeSelection(clientToolbarState.getSelectedSlot() - 1);
} else {
clientToolbarState.attemptChangeSelection(clientToolbarState.getSelectedSlot() + 1);
}
}
}
}});

View File

@ -0,0 +1,223 @@
package electrosphere.controls.cursor;
import java.util.Arrays;
import org.joml.Vector3d;
import org.joml.Vector3i;
import electrosphere.client.block.BlockChunkData;
import electrosphere.client.entity.camera.CameraEntityUtils;
import electrosphere.collision.CollisionEngine;
import electrosphere.engine.Globals;
import electrosphere.engine.assetmanager.AssetDataStrings;
import electrosphere.entity.DrawableUtils;
import electrosphere.entity.Entity;
import electrosphere.entity.EntityCreationUtils;
import electrosphere.entity.EntityTags;
import electrosphere.entity.EntityUtils;
import electrosphere.renderer.actor.Actor;
import electrosphere.renderer.actor.ActorTextureMask;
import electrosphere.renderer.ui.events.ScrollEvent;
/**
* Tracking for the cursor state
*/
public class CursorState {
/**
* Token for displaying cursor
*/
public static final String CURSOR_TOKEN = "CURSOR";
/**
* Token for displaying block cursor
*/
public static final String CURSOR_BLOCK_TOKEN = "CURSOR_BLOCK";
/**
* Minimum size of the block cursor
*/
public static final int MIN_BLOCK_SIZE = 1;
/**
* Maximum size of the block cursor
*/
public static final int MAX_BLOCK_SIZE = 4;
/**
* The scale multiplier for scaling the block cursor
*/
private static final float BLOCK_CURSOR_SCALE_MULTIPLIER = 0.2f;
/**
* Size of blocks to edit
*/
private int blockSize = MIN_BLOCK_SIZE;
/**
* Creates the cursor entities
*/
public static void createCursorEntities(){
//player's cursor
Globals.playerCursor = EntityCreationUtils.createClientSpatialEntity();
EntityCreationUtils.makeEntityDrawable(Globals.playerCursor, AssetDataStrings.UNITSPHERE);
Actor cursorActor = EntityUtils.getActor(Globals.playerCursor);
cursorActor.addTextureMask(new ActorTextureMask("sphere", Arrays.asList(new String[]{"Textures/transparent_red.png"})));
DrawableUtils.makeEntityTransparent(Globals.playerCursor);
EntityUtils.getScale(Globals.playerCursor).set(0.2f);
Globals.clientSceneWrapper.getScene().removeEntityFromTag(Globals.playerCursor, EntityTags.DRAWABLE);
//player's block cursor
Globals.playerBlockCursor = EntityCreationUtils.createClientSpatialEntity();
EntityCreationUtils.makeEntityDrawable(Globals.playerBlockCursor, AssetDataStrings.UNITCUBE);
Actor blockCursorActor = EntityUtils.getActor(Globals.playerBlockCursor);
blockCursorActor.addTextureMask(new ActorTextureMask("cube", Arrays.asList(new String[]{"Textures/transparent_red.png"})));
DrawableUtils.makeEntityTransparent(Globals.playerBlockCursor);
EntityUtils.getScale(Globals.playerBlockCursor).set(BLOCK_CURSOR_SCALE_MULTIPLIER);
Globals.clientSceneWrapper.getScene().removeEntityFromTag(Globals.playerBlockCursor, EntityTags.DRAWABLE);
}
/**
* Updates the position of the player's in world cursor
*/
public void updatePlayerCursor(){
CollisionEngine collisionEngine = Globals.clientSceneWrapper.getCollisionEngine();
Entity camera = Globals.playerCamera;
if(
collisionEngine != null &&
camera != null &&
Globals.playerCursor != null
){
Vector3d eyePos = new Vector3d(CameraEntityUtils.getCameraEye(camera));
Vector3d centerPos = new Vector3d(CameraEntityUtils.getCameraCenter(camera));
Vector3d cursorPos = collisionEngine.rayCastPosition(centerPos, new Vector3d(eyePos).mul(-1.0), CollisionEngine.DEFAULT_INTERACT_DISTANCE);
if(cursorPos == null){
cursorPos = new Vector3d(centerPos).add(new Vector3d(eyePos).normalize().mul(-CollisionEngine.DEFAULT_INTERACT_DISTANCE));
}
EntityUtils.getPosition(Globals.playerCursor).set(cursorPos);
//clamp block cursor to nearest voxel
cursorPos.set(this.clampPositionToNearestBlock(cursorPos));
EntityUtils.getPosition(Globals.playerBlockCursor).set(cursorPos);
}
}
/**
* Makes the real position cursor visible
*/
public static void makeRealVisible(){
Globals.clientSceneWrapper.getScene().removeEntityFromTag(Globals.playerBlockCursor, EntityTags.DRAWABLE);
Globals.clientSceneWrapper.getScene().registerEntityToTag(Globals.playerCursor, EntityTags.DRAWABLE);
}
/**
* Makes the block position cursor visible
*/
public static void makeBlockVisible(){
Globals.clientSceneWrapper.getScene().removeEntityFromTag(Globals.playerCursor, EntityTags.DRAWABLE);
Globals.clientSceneWrapper.getScene().registerEntityToTag(Globals.playerBlockCursor, EntityTags.DRAWABLE);
}
/**
* Hides the cursor
*/
public static void hide(){
Globals.clientSceneWrapper.getScene().removeEntityFromTag(Globals.playerCursor, EntityTags.DRAWABLE);
Globals.clientSceneWrapper.getScene().removeEntityFromTag(Globals.playerBlockCursor, EntityTags.DRAWABLE);
}
/**
* Clamps a real position to the nearest block
* @param input The input real position
* @return The real position clamped to the nearest block
*/
public Vector3d clampPositionToNearestBlock(Vector3d input){
double x = 0;
double y = 0;
double z = 0;
double sizeMult = BlockChunkData.BLOCK_SIZE_MULTIPLIER * blockSize;
if(input.x % sizeMult > sizeMult / 2.0){
x = input.x - input.x % sizeMult + sizeMult + sizeMult / 2.0;
} else {
x = input.x - input.x % sizeMult + sizeMult / 2.0;
}
if(input.y % sizeMult > sizeMult / 2.0){
y = input.y - input.y % sizeMult + sizeMult + sizeMult / 2.0;
} else {
y = input.y - input.y % sizeMult + sizeMult / 2.0;
}
if(input.z % sizeMult > sizeMult / 2.0){
z = input.z - input.z % sizeMult + sizeMult + sizeMult / 2.0;
} else {
z = input.z - input.z % sizeMult + sizeMult / 2.0;
}
return new Vector3d(x,y,z);
}
/**
* Clamps a real position to the corner of the block cursor
* @param input The input real position
* @return The corner position
*/
public Vector3d clampPositionToBlockCorner(Vector3d input){
double x = 0;
double y = 0;
double z = 0;
double sizeMult = BlockChunkData.BLOCK_SIZE_MULTIPLIER * blockSize;
if(input.x % sizeMult > sizeMult / 2.0){
x = input.x - input.x % sizeMult + sizeMult;
} else {
x = input.x - input.x % sizeMult;
}
if(input.y % sizeMult > sizeMult / 2.0){
y = input.y - input.y % sizeMult + sizeMult;
} else {
y = input.y - input.y % sizeMult;
}
if(input.z % sizeMult > sizeMult / 2.0){
z = input.z - input.z % sizeMult + sizeMult;
} else {
z = input.z - input.z % sizeMult;
}
return new Vector3d(x,y,z);
}
/**
* Gets the voxel space position of the corner of the block cursor
* @return The voxel space position
*/
public Vector3i getBlockCornerVoxelPos(){
if(Globals.playerBlockCursor == null){
throw new Error("Block cursor is null!");
}
Vector3d realPos = EntityUtils.getPosition(Globals.playerBlockCursor);
Vector3d clamped = this.clampPositionToBlockCorner(realPos);
return Globals.clientWorldData.convertRealToBlockSpace(clamped);
}
/**
* Updates the cursor size
* @param scrollEvent The scroll event
*/
public void updateCursorSize(ScrollEvent scrollEvent){
if(scrollEvent.getScrollAmount() > 0){
if(this.blockSize < MAX_BLOCK_SIZE){
this.blockSize = this.blockSize * 2;
}
} else {
if(this.blockSize > MIN_BLOCK_SIZE){
this.blockSize = this.blockSize / 2;
}
}
EntityUtils.getScale(Globals.playerBlockCursor).set(BLOCK_CURSOR_SCALE_MULTIPLIER * this.blockSize);
}
/**
* Gets the size of the block cursor
* @return The size of the block cursor
*/
public int getBlockSize(){
return blockSize;
}
}

View File

@ -36,6 +36,7 @@ import electrosphere.controls.ControlCallback;
import electrosphere.controls.ControlHandler;
import electrosphere.controls.MouseCallback;
import electrosphere.controls.ScrollCallback;
import electrosphere.controls.cursor.CursorState;
import electrosphere.engine.assetmanager.AssetDataStrings;
import electrosphere.engine.assetmanager.AssetManager;
import electrosphere.engine.loadingthreads.InitialAssetLoading;
@ -203,6 +204,7 @@ public class Globals {
public static ControlCallback controlCallback = new ControlCallback();
public static MouseCallback mouseCallback = new MouseCallback();
public static ScrollCallback scrollCallback = new ScrollCallback();
public static CursorState cursorState = new CursorState();
//

View File

@ -1,6 +1,5 @@
package electrosphere.engine.loadingthreads;
import java.util.Arrays;
import java.util.concurrent.TimeUnit;
import org.joml.Vector3d;
@ -18,22 +17,19 @@ import electrosphere.client.ui.menu.WindowStrings;
import electrosphere.client.ui.menu.WindowUtils;
import electrosphere.client.ui.menu.mainmenu.MenuCharacterCreation;
import electrosphere.controls.ControlHandler;
import electrosphere.controls.cursor.CursorState;
import electrosphere.engine.Globals;
import electrosphere.engine.assetmanager.AssetDataStrings;
import electrosphere.engine.signal.Signal.SignalType;
import electrosphere.engine.threads.LabeledThread.ThreadLabel;
import electrosphere.entity.DrawableUtils;
import electrosphere.entity.Entity;
import electrosphere.entity.EntityCreationUtils;
import electrosphere.entity.EntityTags;
import electrosphere.entity.EntityUtils;
import electrosphere.logger.LoggerInterface;
import electrosphere.net.NetUtils;
import electrosphere.net.client.ClientNetworking;
import electrosphere.net.parser.net.message.CharacterMessage;
import electrosphere.net.parser.net.message.LoreMessage;
import electrosphere.renderer.actor.Actor;
import electrosphere.renderer.actor.ActorTextureMask;
public class ClientLoading {
@ -296,23 +292,7 @@ public class ClientLoading {
// Globals.clientScene.registerBehaviorTree(new ApplyRotationTree(cloudRing,new Quaterniond().rotationZ(0.0001)));
// Globals.assetManager.queueOverrideMeshShader("Models/environment/cloudRing.fbx", "Sphere", "Shaders/skysphere/skysphere.vs", "Shaders/skysphere/skysphere.fs");
//player's cursor
Globals.playerCursor = EntityCreationUtils.createClientSpatialEntity();
EntityCreationUtils.makeEntityDrawable(Globals.playerCursor, AssetDataStrings.UNITSPHERE);
Actor cursorActor = EntityUtils.getActor(Globals.playerCursor);
cursorActor.addTextureMask(new ActorTextureMask("sphere", Arrays.asList(new String[]{"Textures/transparent_red.png"})));
DrawableUtils.makeEntityTransparent(Globals.playerCursor);
EntityUtils.getScale(Globals.playerCursor).set(0.2f);
Globals.clientSceneWrapper.getScene().removeEntityFromTag(Globals.playerCursor, EntityTags.DRAWABLE);
//player's block cursor
Globals.playerBlockCursor = EntityCreationUtils.createClientSpatialEntity();
EntityCreationUtils.makeEntityDrawable(Globals.playerBlockCursor, AssetDataStrings.UNITCUBE);
Actor blockCursorActor = EntityUtils.getActor(Globals.playerBlockCursor);
blockCursorActor.addTextureMask(new ActorTextureMask("cube", Arrays.asList(new String[]{"Textures/transparent_red.png"})));
DrawableUtils.makeEntityTransparent(Globals.playerBlockCursor);
EntityUtils.getScale(Globals.playerBlockCursor).set(0.2f);
Globals.clientSceneWrapper.getScene().removeEntityFromTag(Globals.playerBlockCursor, EntityTags.DRAWABLE);
CursorState.createCursorEntities();
//cloud object
// Entity cloudEnt = EntityCreationUtils.createClientSpatialEntity();

View File

@ -18,7 +18,7 @@ import electrosphere.game.data.item.Item;
import java.util.List;
import electrosphere.collision.PhysicsEntityUtils;
import electrosphere.controls.PlayerCursor;
import electrosphere.controls.cursor.CursorState;
import electrosphere.engine.Globals;
import electrosphere.entity.ClientEntityUtils;
import electrosphere.entity.Entity;
@ -177,12 +177,11 @@ public class ClientToolbarState implements BehaviorTree {
if(targetPoint != null && parent == Globals.playerEntity){
Item itemData = Globals.gameConfigCurrent.getItemMap().getItem(toEquip);
if(Globals.playerCursor != null && Globals.playerBlockCursor != null){
Globals.clientSceneWrapper.getScene().removeEntityFromTag(Globals.playerCursor, EntityTags.DRAWABLE);
Globals.clientSceneWrapper.getScene().removeEntityFromTag(Globals.playerBlockCursor, EntityTags.DRAWABLE);
if(itemData.getTokens().contains(PlayerCursor.CURSOR_TOKEN)){
Globals.clientSceneWrapper.getScene().registerEntityToTag(Globals.playerCursor, EntityTags.DRAWABLE);
} else if(itemData.getTokens().contains(PlayerCursor.CURSOR_BLOCK_TOKEN)) {
Globals.clientSceneWrapper.getScene().registerEntityToTag(Globals.playerBlockCursor, EntityTags.DRAWABLE);
CursorState.hide();
if(itemData.getTokens().contains(CursorState.CURSOR_TOKEN)){
CursorState.makeRealVisible();
} else if(itemData.getTokens().contains(CursorState.CURSOR_BLOCK_TOKEN)) {
CursorState.makeBlockVisible();
}
}
}

View File

@ -6,7 +6,7 @@ import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import electrosphere.controls.PlayerCursor;
import electrosphere.controls.cursor.CursorState;
import electrosphere.engine.Globals;
import electrosphere.engine.assetmanager.AssetDataStrings;
import electrosphere.game.data.block.BlockType;
@ -149,12 +149,13 @@ public class Item extends CommonEntityType {
//set usage
ItemUsage usage = new ItemUsage();
usage.setBlockId(blockType.getId());
usage.setOnlyOnMouseDown(true);
rVal.setSecondaryUsage(usage);
//attach common tokens
List<String> tokens = new LinkedList<String>(Arrays.asList(DEFAULT_TOKENS));
tokens.add(PlayerCursor.CURSOR_BLOCK_TOKEN);
tokens.add(CursorState.CURSOR_BLOCK_TOKEN);
rVal.setTokens(tokens);
return rVal;

View File

@ -238,9 +238,9 @@ public class TerrainProtocol implements ClientProtocolTemplate<TerrainMessage> {
case UPDATEFLUIDDATA: {
Globals.clientFluidManager.attachFluidMessage(message);
} break;
default:
default: {
LoggerInterface.loggerNetworking.WARNING("Client networking: Unhandled message of type: " + message.getMessageSubtype());
break;
} break;
}
Globals.profiler.endCpuSample();
}

View File

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

View File

@ -28,6 +28,7 @@ public class TerrainMessage extends NetworkMessage {
REQUESTFLUIDDATA,
SENDFLUIDDATA,
UPDATEFLUIDDATA,
REQUESTEDITBLOCK,
}
/**
@ -60,6 +61,7 @@ public class TerrainMessage extends NetworkMessage {
int terrainValue;
int blockType;
int blockMetadata;
int blockEditSize;
/**
* Constructor
@ -445,6 +447,20 @@ public class TerrainMessage extends NetworkMessage {
this.blockMetadata = blockMetadata;
}
/**
* Gets blockEditSize
*/
public int getblockEditSize() {
return blockEditSize;
}
/**
* Sets blockEditSize
*/
public void setblockEditSize(int blockEditSize) {
this.blockEditSize = blockEditSize;
}
/**
* Removes the packet header from the buffer
* @param byteBuffer The buffer
@ -543,6 +559,12 @@ public class TerrainMessage extends NetworkMessage {
return TerrainMessage.canParsesendFluidDataMessage(byteBuffer);
case TypeBytes.TERRAIN_MESSAGE_TYPE_UPDATEFLUIDDATA:
return TerrainMessage.canParseupdateFluidDataMessage(byteBuffer);
case TypeBytes.TERRAIN_MESSAGE_TYPE_REQUESTEDITBLOCK:
if(byteBuffer.getRemaining() >= TypeBytes.TERRAIN_MESSAGE_TYPE_REQUESTEDITBLOCK_SIZE){
return true;
} else {
return false;
}
}
return false;
}
@ -1203,6 +1225,43 @@ public class TerrainMessage extends NetworkMessage {
return rVal;
}
/**
* Parses a message of type RequestEditBlock
*/
public static TerrainMessage parseRequestEditBlockMessage(CircularByteBuffer byteBuffer, MessagePool pool){
TerrainMessage rVal = (TerrainMessage)pool.get(MessageType.TERRAIN_MESSAGE);
rVal.messageType = TerrainMessageType.REQUESTEDITBLOCK;
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.setblockType(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
rVal.setblockMetadata(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
rVal.setblockEditSize(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
return rVal;
}
/**
* Constructs a message of type RequestEditBlock
*/
public static TerrainMessage constructRequestEditBlockMessage(int worldX,int worldY,int worldZ,int voxelX,int voxelY,int voxelZ,int blockType,int blockMetadata,int blockEditSize){
TerrainMessage rVal = new TerrainMessage(TerrainMessageType.REQUESTEDITBLOCK);
rVal.setworldX(worldX);
rVal.setworldY(worldY);
rVal.setworldZ(worldZ);
rVal.setvoxelX(voxelX);
rVal.setvoxelY(voxelY);
rVal.setvoxelZ(voxelZ);
rVal.setblockType(blockType);
rVal.setblockMetadata(blockMetadata);
rVal.setblockEditSize(blockEditSize);
rVal.serialize();
return rVal;
}
@Override
void serialize(){
byte[] intValues = new byte[8];
@ -1667,6 +1726,49 @@ public class TerrainMessage extends NetworkMessage {
rawBytes[18+i] = chunkData[i];
}
break;
case REQUESTEDITBLOCK:
rawBytes = new byte[2+4+4+4+4+4+4+4+4+4];
//message header
rawBytes[0] = TypeBytes.MESSAGE_TYPE_TERRAIN;
//entity messaage header
rawBytes[1] = TypeBytes.TERRAIN_MESSAGE_TYPE_REQUESTEDITBLOCK;
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(blockType);
for(int i = 0; i < 4; i++){
rawBytes[26+i] = intValues[i];
}
intValues = ByteStreamUtils.serializeIntToBytes(blockMetadata);
for(int i = 0; i < 4; i++){
rawBytes[30+i] = intValues[i];
}
intValues = ByteStreamUtils.serializeIntToBytes(blockEditSize);
for(int i = 0; i < 4; i++){
rawBytes[34+i] = intValues[i];
}
break;
}
serialized = true;
}

View File

@ -84,6 +84,7 @@ public class TypeBytes {
public static final byte TERRAIN_MESSAGE_TYPE_REQUESTFLUIDDATA = 14;
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_REQUESTEDITBLOCK = 17;
/*
Terrain packet sizes
*/
@ -99,6 +100,7 @@ public class TypeBytes {
public static final byte TERRAIN_MESSAGE_TYPE_REQUESTREDUCEDBLOCKDATA_SIZE = 18;
public static final byte TERRAIN_MESSAGE_TYPE_UPDATEBLOCK_SIZE = 34;
public static final byte TERRAIN_MESSAGE_TYPE_REQUESTFLUIDDATA_SIZE = 14;
public static final byte TERRAIN_MESSAGE_TYPE_REQUESTEDITBLOCK_SIZE = 38;
/*
Server subcategories

View File

@ -7,10 +7,12 @@ import java.nio.ShortBuffer;
import java.util.function.Consumer;
import org.joml.Vector3d;
import org.joml.Vector3i;
import electrosphere.client.block.BlockChunkData;
import electrosphere.client.terrain.cache.ChunkData;
import electrosphere.engine.Globals;
import electrosphere.entity.Entity;
import electrosphere.logger.LoggerInterface;
import electrosphere.net.parser.net.message.TerrainMessage;
import electrosphere.net.server.ServerConnectionHandler;
@ -18,6 +20,8 @@ import electrosphere.net.server.player.Player;
import electrosphere.net.template.ServerProtocolTemplate;
import electrosphere.server.datacell.Realm;
import electrosphere.server.datacell.ServerWorldData;
import electrosphere.server.datacell.utils.EntityLookupUtils;
import electrosphere.server.physics.block.editing.ServerBlockEditing;
import electrosphere.server.physics.fluid.manager.ServerFluidChunk;
import electrosphere.server.physics.terrain.editing.TerrainEditing;
import electrosphere.server.physics.terrain.manager.ServerTerrainChunk;
@ -80,6 +84,14 @@ public class TerrainProtocol implements ServerProtocolTemplate<TerrainMessage> {
message.getworldX(), message.getworldY(), message.getworldZ()
);
} break;
case REQUESTEDITBLOCK: {
LoggerInterface.loggerNetworking.DEBUG("(Server) Received request to edit block at " + message.getworldX() + " " + message.getworldY() + " " + message.getworldZ());
Entity targetEntity = EntityLookupUtils.getEntityById(connectionHandler.getPlayerEntityId());
Realm playerRealm = Globals.realmManager.getEntityRealm(targetEntity);
Vector3i worldPos = new Vector3i(message.getworldX(),message.getworldY(),message.getworldZ());
Vector3i blockPos = new Vector3i(message.getvoxelX(),message.getvoxelY(),message.getvoxelZ());
ServerBlockEditing.editBlockArea(playerRealm, worldPos, blockPos, (short)message.getblockType(), (short)message.getblockMetadata(), message.getblockEditSize());
} break;
//all ignored message types
case UPDATEFLUIDDATA:
case RESPONSEMETADATA:

View File

@ -52,6 +52,9 @@ import electrosphere.renderer.pipelines.debug.DebugContentPipeline;
import electrosphere.renderer.shader.VisualShader;
import electrosphere.renderer.texture.Texture;
/**
* The main object for the rendering engine
*/
public class RenderingEngine {
@ -139,10 +142,9 @@ public class RenderingEngine {
*/
public static VisualShader compositeAnimeOutline;
// public static boolean renderHitboxes = false;
// public static boolean renderPhysics = false;
/**
* The light manager for the rendering engine
*/
LightManager lightManager;
public static int outputFramebuffer = 0;
@ -178,7 +180,9 @@ public class RenderingEngine {
RenderScreenPipeline renderScreenPipeline = new RenderScreenPipeline();
ImGuiPipeline imGuiPipeline;
/**
* Initializes the opengl context
*/
public void createOpenglContext(){
LoggerInterface.loggerRenderer.INFO("Create OpenGL Context");
@ -306,16 +310,11 @@ public class RenderingEngine {
GL45.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
GL45.glClear(GL45.GL_COLOR_BUFFER_BIT | GL45.GL_DEPTH_BUFFER_BIT);
// //Hide the cursor and capture it
// glfwSetInputMode(Globals.window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
//init screen rendering quadrant
screenTextureVAO = createScreenTextureVAO();
// initScreenTextureShaderProgram();
screenTextureShaders = VisualShader.loadSpecificShader("/Shaders/core/screentexture/simple1/simple1.vs", "/Shaders/core/screentexture/simple1/simple1.fs");
// screenTextureShaders = ShaderProgram.loadSpecificShader("/Shaders/screentexture/drawDepthBuffer/drawDepthBuffer.vs", "/Shaders/screentexture/drawDepthBuffer/drawDepthBuffer.fs");
//default framebuffer
defaultFramebuffer = new Framebuffer(GL_DEFAULT_FRAMEBUFFER);
@ -354,7 +353,6 @@ public class RenderingEngine {
}
Texture lightBufferDepthTexture = lightDepthBuffer.getDepthTexture();
RenderingEngine.lightBufferDepthTexture = lightBufferDepthTexture;
// glEnable(GL_CULL_FACE); // enabled for shadow mapping
//
//create volume depth framebuffer/shader for volumetric rendering
@ -372,11 +370,6 @@ public class RenderingEngine {
//
//Game normals
//
/*
gameImageNormalsTexture;
static Framebuffer gameImageNormalsFramebuffer;
static ShaderProgram renderNormalsShader;
*/
try {
gameImageNormalsTexture = FramebufferUtils.generateScreenTextureColorAlpha(openGLState, Globals.userSettings.getRenderResolutionX(), Globals.userSettings.getRenderResolutionY());
Texture gameImageNormalsDepthTexture = FramebufferUtils.generateScreenTextureDepth(openGLState, Globals.userSettings.getRenderResolutionX(), Globals.userSettings.getRenderResolutionY());
@ -409,7 +402,6 @@ public class RenderingEngine {
try {
normalsOutlineTexture = FramebufferUtils.generateScreenTextureColorAlpha(openGLState, Globals.userSettings.getRenderResolutionX(), Globals.userSettings.getRenderResolutionY());
normalsOutlineFrambuffer = FramebufferUtils.generateScreenTextureFramebuffer(openGLState, Globals.userSettings.getRenderResolutionX(), Globals.userSettings.getRenderResolutionY(), normalsOutlineTexture);
// normalsOutlineShader = ShaderProgram.loadSpecificShader("Shaders/anime/outlineNormals.vs", "Shaders/anime/outlineNormals.fs");
Globals.assetManager.addShaderToQueue("Shaders/core/anime/outlineNormals.vs", "Shaders/core/anime/outlineNormals.fs");
} catch(Exception e){
LoggerInterface.loggerRenderer.ERROR(e);

View File

@ -3,6 +3,7 @@ package electrosphere.server.physics.block.editing;
import org.joml.Vector3i;
import electrosphere.client.block.BlockChunkData;
import electrosphere.controls.cursor.CursorState;
import electrosphere.server.datacell.Realm;
import electrosphere.server.datacell.interfaces.VoxelCellManager;
@ -44,4 +45,28 @@ public class ServerBlockEditing {
}
}
/**
* Performs a series of block edits on an area of blocks. Basically has a sphere around the provided position that it attempts to add value to
* @param realm The realm to modify in
* @param worldPos The world position
* @param voxelPos The block position within the chunk at the world position
* @param type The new type of block
* @param metadata The new metadata for the block
* @param size The size of the area to edit
*/
public static void editBlockArea(Realm realm, Vector3i worldPos, Vector3i voxelPos, short type, short metadata, int size){
if(size < CursorState.MIN_BLOCK_SIZE || size > CursorState.MAX_BLOCK_SIZE){
throw new Error("Size out of bounds: " + size);
}
Vector3i pos = new Vector3i();
for(int x = 0; x < size; x++){
for(int y = 0; y < size; y++){
for(int z = 0; z < size; z++){
pos = new Vector3i(voxelPos).add(x,y,z);
ServerBlockEditing.editBlockChunk(realm, worldPos, pos, type, metadata);
}
}
}
}
}

View File

@ -124,6 +124,10 @@
{
"name" : "blockMetadata",
"type" : "FIXED_INT"
},
{
"name" : "blockEditSize",
"type" : "FIXED_INT"
}
],
"messageTypes" : [
@ -311,6 +315,21 @@
"worldZ",
"chunkData"
]
},
{
"messageName" : "RequestEditBlock",
"description" : "Requests that a block be edited on the server",
"data" : [
"worldX",
"worldY",
"worldZ",
"voxelX",
"voxelY",
"voxelZ",
"blockType",
"blockMetadata",
"blockEditSize"
]
}
]
}