From 7858cc83ee4205ad94d41f15943ecbdbb0cfbfa0 Mon Sep 17 00:00:00 2001 From: austin Date: Sat, 5 Apr 2025 18:03:22 -0400 Subject: [PATCH] block cursor --- docs/src/progress/renderertodo.md | 1 + .../electrosphere/controls/CameraHandler.java | 11 +++-- .../electrosphere/controls/PlayerCursor.java | 49 +++++++++++++++++++ .../java/electrosphere/engine/Globals.java | 1 + .../engine/loadingthreads/ClientLoading.java | 10 ++++ .../state/equip/ClientToolbarState.java | 21 ++++---- .../electrosphere/game/data/item/Item.java | 7 ++- 7 files changed, 85 insertions(+), 15 deletions(-) create mode 100644 src/main/java/electrosphere/controls/PlayerCursor.java diff --git a/docs/src/progress/renderertodo.md b/docs/src/progress/renderertodo.md index d479753d..a851f74a 100644 --- a/docs/src/progress/renderertodo.md +++ b/docs/src/progress/renderertodo.md @@ -1453,6 +1453,7 @@ Fix human data for RH sword slash attack moves Cursor only for specific items Added shovel (works inversely of how you would expect currently) Script cache busting on file modification +Block cursor diff --git a/src/main/java/electrosphere/controls/CameraHandler.java b/src/main/java/electrosphere/controls/CameraHandler.java index e614542c..ef70caf9 100644 --- a/src/main/java/electrosphere/controls/CameraHandler.java +++ b/src/main/java/electrosphere/controls/CameraHandler.java @@ -158,11 +158,14 @@ public class CameraHandler { 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){ - EntityUtils.getPosition(Globals.playerCursor).set(cursorPos); - } else { - EntityUtils.getPosition(Globals.playerCursor).set(new Vector3d(centerPos).add(new Vector3d(eyePos).normalize().mul(-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); } } diff --git a/src/main/java/electrosphere/controls/PlayerCursor.java b/src/main/java/electrosphere/controls/PlayerCursor.java new file mode 100644 index 00000000..4ea165d0 --- /dev/null +++ b/src/main/java/electrosphere/controls/PlayerCursor.java @@ -0,0 +1,49 @@ +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/engine/Globals.java b/src/main/java/electrosphere/engine/Globals.java index 82cf3145..d8004c13 100644 --- a/src/main/java/electrosphere/engine/Globals.java +++ b/src/main/java/electrosphere/engine/Globals.java @@ -409,6 +409,7 @@ public class Globals { //the player in world cursor public static Entity playerCursor; + public static Entity playerBlockCursor; //the creature the player camera will orbit and will receive controlHandler movementTree updates public static Entity playerEntity; diff --git a/src/main/java/electrosphere/engine/loadingthreads/ClientLoading.java b/src/main/java/electrosphere/engine/loadingthreads/ClientLoading.java index dea0a608..980c90d8 100644 --- a/src/main/java/electrosphere/engine/loadingthreads/ClientLoading.java +++ b/src/main/java/electrosphere/engine/loadingthreads/ClientLoading.java @@ -25,6 +25,7 @@ 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; @@ -303,6 +304,15 @@ public class ClientLoading { DrawableUtils.makeEntityTransparent(Globals.playerCursor); EntityUtils.getScale(Globals.playerCursor).set(0.2f); + //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); + //cloud object // Entity cloudEnt = EntityCreationUtils.createClientSpatialEntity(); // EntityCreationUtils.makeEntityDrawablePreexistingModel(cloudEnt, Globals.assetManager.queuedAsset(new QueuedModel(() -> { diff --git a/src/main/java/electrosphere/entity/state/equip/ClientToolbarState.java b/src/main/java/electrosphere/entity/state/equip/ClientToolbarState.java index 7ce08337..066a4cf8 100644 --- a/src/main/java/electrosphere/entity/state/equip/ClientToolbarState.java +++ b/src/main/java/electrosphere/entity/state/equip/ClientToolbarState.java @@ -18,6 +18,7 @@ import electrosphere.game.data.item.Item; import java.util.List; import electrosphere.collision.PhysicsEntityUtils; +import electrosphere.controls.PlayerCursor; import electrosphere.engine.Globals; import electrosphere.entity.ClientEntityUtils; import electrosphere.entity.Entity; @@ -43,11 +44,6 @@ public class ClientToolbarState implements BehaviorTree { * The maximum number of toolbar slots */ public static final int MAX_TOOLBAR_SIZE = 10; - - /** - * Token for displaying cursor - */ - public static final String CURSOR_TOKEN = "CURSOR"; /** * The selected toolbar slot @@ -178,13 +174,15 @@ public class ClientToolbarState implements BehaviorTree { } //cursor logic - if(targetPoint != null){ + if(targetPoint != null && parent == Globals.playerEntity){ Item itemData = Globals.gameConfigCurrent.getItemMap().getItem(toEquip); - if(Globals.playerCursor != null){ - if(itemData.getTokens().contains(ClientToolbarState.CURSOR_TOKEN)){ + 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 { - Globals.clientSceneWrapper.getScene().removeEntityFromTag(Globals.playerCursor, EntityTags.DRAWABLE); + } else if(itemData.getTokens().contains(PlayerCursor.CURSOR_BLOCK_TOKEN)) { + Globals.clientSceneWrapper.getScene().registerEntityToTag(Globals.playerBlockCursor, EntityTags.DRAWABLE); } } } @@ -253,6 +251,9 @@ public class ClientToolbarState implements BehaviorTree { if(Globals.playerCursor != null){ Globals.clientSceneWrapper.getScene().removeEntityFromTag(Globals.playerCursor, EntityTags.DRAWABLE); } + if(Globals.playerBlockCursor != null){ + Globals.clientSceneWrapper.getScene().removeEntityFromTag(Globals.playerBlockCursor, EntityTags.DRAWABLE); + } //null out the attached entity this.equippedEntity = null; diff --git a/src/main/java/electrosphere/game/data/item/Item.java b/src/main/java/electrosphere/game/data/item/Item.java index 667c6f69..0c549b22 100644 --- a/src/main/java/electrosphere/game/data/item/Item.java +++ b/src/main/java/electrosphere/game/data/item/Item.java @@ -2,8 +2,11 @@ package electrosphere.game.data.item; import java.util.Arrays; import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; import java.util.Map; +import electrosphere.controls.PlayerCursor; import electrosphere.engine.Globals; import electrosphere.engine.assetmanager.AssetDataStrings; import electrosphere.game.data.block.BlockType; @@ -150,7 +153,9 @@ public class Item extends CommonEntityType { //attach common tokens - rVal.setTokens(Arrays.asList(DEFAULT_TOKENS)); + List tokens = new LinkedList(Arrays.asList(DEFAULT_TOKENS)); + tokens.add(PlayerCursor.CURSOR_BLOCK_TOKEN); + rVal.setTokens(tokens); return rVal; }