From f7c6208a2a4eeda2750d5d52f74bfb88d3c2b45b Mon Sep 17 00:00:00 2001 From: austin Date: Fri, 25 Apr 2025 19:48:25 -0400 Subject: [PATCH] variable size for block editing --- docs/src/progress/renderertodo.md | 1 + .../client/interact/ItemActions.java | 31 ++- .../client/scene/ClientWorldData.java | 35 ++- .../client/script/ScriptClientVoxelUtils.java | 18 ++ .../client/terrain/editing/BlockEditing.java | 26 ++ .../electrosphere/controls/CameraHandler.java | 81 ++++--- .../controls/ControlCallback.java | 22 +- .../controls/ControlHandler.java | 22 +- .../electrosphere/controls/PlayerCursor.java | 49 ---- .../categories/ControlCategoryMainGame.java | 26 +- .../controls/cursor/CursorState.java | 223 ++++++++++++++++++ .../java/electrosphere/engine/Globals.java | 2 + .../engine/loadingthreads/ClientLoading.java | 24 +- .../state/equip/ClientToolbarState.java | 13 +- .../electrosphere/game/data/item/Item.java | 5 +- .../net/client/protocol/TerrainProtocol.java | 4 +- .../parser/net/message/NetworkMessage.java | 5 + .../parser/net/message/TerrainMessage.java | 102 ++++++++ .../net/parser/net/message/TypeBytes.java | 2 + .../net/server/protocol/TerrainProtocol.java | 12 + .../renderer/RenderingEngine.java | 26 +- .../block/editing/ServerBlockEditing.java | 25 ++ src/net/terrain.json | 19 ++ 23 files changed, 592 insertions(+), 181 deletions(-) create mode 100644 src/main/java/electrosphere/client/terrain/editing/BlockEditing.java delete mode 100644 src/main/java/electrosphere/controls/PlayerCursor.java create mode 100644 src/main/java/electrosphere/controls/cursor/CursorState.java diff --git a/docs/src/progress/renderertodo.md b/docs/src/progress/renderertodo.md index f413d174..bf283203 100644 --- a/docs/src/progress/renderertodo.md +++ b/docs/src/progress/renderertodo.md @@ -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 diff --git a/src/main/java/electrosphere/client/interact/ItemActions.java b/src/main/java/electrosphere/client/interact/ItemActions.java index 76ab425f..b7d784ed 100644 --- a/src/main/java/electrosphere/client/interact/ItemActions.java +++ b/src/main/java/electrosphere/client/interact/ItemActions.java @@ -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 + )); + } } /** diff --git a/src/main/java/electrosphere/client/scene/ClientWorldData.java b/src/main/java/electrosphere/client/scene/ClientWorldData.java index bc1f3ab9..bb39c87e 100644 --- a/src/main/java/electrosphere/client/scene/ClientWorldData.java +++ b/src/main/java/electrosphere/client/scene/ClientWorldData.java @@ -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) ); } diff --git a/src/main/java/electrosphere/client/script/ScriptClientVoxelUtils.java b/src/main/java/electrosphere/client/script/ScriptClientVoxelUtils.java index c9458aa6..22259a9d 100644 --- a/src/main/java/electrosphere/client/script/ScriptClientVoxelUtils.java +++ b/src/main/java/electrosphere/client/script/ScriptClientVoxelUtils.java @@ -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 + )); + } + } diff --git a/src/main/java/electrosphere/client/terrain/editing/BlockEditing.java b/src/main/java/electrosphere/client/terrain/editing/BlockEditing.java new file mode 100644 index 00000000..ccc8bf63 --- /dev/null +++ b/src/main/java/electrosphere/client/terrain/editing/BlockEditing.java @@ -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); + } + +} diff --git a/src/main/java/electrosphere/controls/CameraHandler.java b/src/main/java/electrosphere/controls/CameraHandler.java index ef70caf9..4f3354b1 100644 --- a/src/main/java/electrosphere/controls/CameraHandler.java +++ b/src/main/java/electrosphere/controls/CameraHandler.java @@ -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 diff --git a/src/main/java/electrosphere/controls/ControlCallback.java b/src/main/java/electrosphere/controls/ControlCallback.java index acf7112a..2f498990 100644 --- a/src/main/java/electrosphere/controls/ControlCallback.java +++ b/src/main/java/electrosphere/controls/ControlCallback.java @@ -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){ diff --git a/src/main/java/electrosphere/controls/ControlHandler.java b/src/main/java/electrosphere/controls/ControlHandler.java index 6c449fa7..79a7ebac 100644 --- a/src/main/java/electrosphere/controls/ControlHandler.java +++ b/src/main/java/electrosphere/controls/ControlHandler.java @@ -116,7 +116,7 @@ public class ControlHandler { /** * Constructor */ - ControlHandler(){ + private ControlHandler(){ controls = new HashMap(); } @@ -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 { diff --git a/src/main/java/electrosphere/controls/PlayerCursor.java b/src/main/java/electrosphere/controls/PlayerCursor.java deleted file mode 100644 index 4ea165d0..00000000 --- a/src/main/java/electrosphere/controls/PlayerCursor.java +++ /dev/null @@ -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); - } - -} diff --git a/src/main/java/electrosphere/controls/categories/ControlCategoryMainGame.java b/src/main/java/electrosphere/controls/categories/ControlCategoryMainGame.java index 55c91985..241a2dc1 100644 --- a/src/main/java/electrosphere/controls/categories/ControlCategoryMainGame.java +++ b/src/main/java/electrosphere/controls/categories/ControlCategoryMainGame.java @@ -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); + } } } }}); diff --git a/src/main/java/electrosphere/controls/cursor/CursorState.java b/src/main/java/electrosphere/controls/cursor/CursorState.java new file mode 100644 index 00000000..6d4e2af1 --- /dev/null +++ b/src/main/java/electrosphere/controls/cursor/CursorState.java @@ -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; + } + +} diff --git a/src/main/java/electrosphere/engine/Globals.java b/src/main/java/electrosphere/engine/Globals.java index e5d07669..3f83721b 100644 --- a/src/main/java/electrosphere/engine/Globals.java +++ b/src/main/java/electrosphere/engine/Globals.java @@ -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(); // diff --git a/src/main/java/electrosphere/engine/loadingthreads/ClientLoading.java b/src/main/java/electrosphere/engine/loadingthreads/ClientLoading.java index c9f0ca44..dfd66a40 100644 --- a/src/main/java/electrosphere/engine/loadingthreads/ClientLoading.java +++ b/src/main/java/electrosphere/engine/loadingthreads/ClientLoading.java @@ -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(); diff --git a/src/main/java/electrosphere/entity/state/equip/ClientToolbarState.java b/src/main/java/electrosphere/entity/state/equip/ClientToolbarState.java index d65b39ef..fcc74555 100644 --- a/src/main/java/electrosphere/entity/state/equip/ClientToolbarState.java +++ b/src/main/java/electrosphere/entity/state/equip/ClientToolbarState.java @@ -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(); } } } diff --git a/src/main/java/electrosphere/game/data/item/Item.java b/src/main/java/electrosphere/game/data/item/Item.java index 0aed8a98..501ebb5b 100644 --- a/src/main/java/electrosphere/game/data/item/Item.java +++ b/src/main/java/electrosphere/game/data/item/Item.java @@ -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 tokens = new LinkedList(Arrays.asList(DEFAULT_TOKENS)); - tokens.add(PlayerCursor.CURSOR_BLOCK_TOKEN); + tokens.add(CursorState.CURSOR_BLOCK_TOKEN); rVal.setTokens(tokens); return rVal; diff --git a/src/main/java/electrosphere/net/client/protocol/TerrainProtocol.java b/src/main/java/electrosphere/net/client/protocol/TerrainProtocol.java index 4671c389..14f4d24e 100644 --- a/src/main/java/electrosphere/net/client/protocol/TerrainProtocol.java +++ b/src/main/java/electrosphere/net/client/protocol/TerrainProtocol.java @@ -238,9 +238,9 @@ public class TerrainProtocol implements ClientProtocolTemplate { 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(); } diff --git a/src/main/java/electrosphere/net/parser/net/message/NetworkMessage.java b/src/main/java/electrosphere/net/parser/net/message/NetworkMessage.java index 73d354b7..4a263fed 100644 --- a/src/main/java/electrosphere/net/parser/net/message/NetworkMessage.java +++ b/src/main/java/electrosphere/net/parser/net/message/NetworkMessage.java @@ -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: diff --git a/src/main/java/electrosphere/net/parser/net/message/TerrainMessage.java b/src/main/java/electrosphere/net/parser/net/message/TerrainMessage.java index 8f9cbfdb..71f30297 100644 --- a/src/main/java/electrosphere/net/parser/net/message/TerrainMessage.java +++ b/src/main/java/electrosphere/net/parser/net/message/TerrainMessage.java @@ -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; } diff --git a/src/main/java/electrosphere/net/parser/net/message/TypeBytes.java b/src/main/java/electrosphere/net/parser/net/message/TypeBytes.java index 1b695b12..1c449000 100644 --- a/src/main/java/electrosphere/net/parser/net/message/TypeBytes.java +++ b/src/main/java/electrosphere/net/parser/net/message/TypeBytes.java @@ -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 diff --git a/src/main/java/electrosphere/net/server/protocol/TerrainProtocol.java b/src/main/java/electrosphere/net/server/protocol/TerrainProtocol.java index 7b7e35fc..b82fbae9 100644 --- a/src/main/java/electrosphere/net/server/protocol/TerrainProtocol.java +++ b/src/main/java/electrosphere/net/server/protocol/TerrainProtocol.java @@ -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 { 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: diff --git a/src/main/java/electrosphere/renderer/RenderingEngine.java b/src/main/java/electrosphere/renderer/RenderingEngine.java index 3ac27e13..b6594c20 100644 --- a/src/main/java/electrosphere/renderer/RenderingEngine.java +++ b/src/main/java/electrosphere/renderer/RenderingEngine.java @@ -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); diff --git a/src/main/java/electrosphere/server/physics/block/editing/ServerBlockEditing.java b/src/main/java/electrosphere/server/physics/block/editing/ServerBlockEditing.java index 35639e8e..4edb1fa2 100644 --- a/src/main/java/electrosphere/server/physics/block/editing/ServerBlockEditing.java +++ b/src/main/java/electrosphere/server/physics/block/editing/ServerBlockEditing.java @@ -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); + } + } + } + } + } diff --git a/src/net/terrain.json b/src/net/terrain.json index e7950be1..f90bc96f 100644 --- a/src/net/terrain.json +++ b/src/net/terrain.json @@ -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" + ] } ] }