From 512998eb244e4f92a3958fcd9d666becce7d24cc Mon Sep 17 00:00:00 2001 From: austin Date: Wed, 20 Mar 2024 21:09:00 -0400 Subject: [PATCH] Free camera support for debugging --- docs/src/progress/renderertodo.md | 12 ++- .../client/fluid/cells/FluidCell.java | 3 + .../client/sim/ClientFunctions.java | 1 + .../electrosphere/controls/CameraHandler.java | 18 +++++ .../controls/ControlHandler.java | 76 ++++++++++++++++++ .../engine/loadingthreads/ClientLoading.java | 1 - .../types/camera/CameraEntityUtils.java | 11 +-- .../electrosphere/menu/ImGuiWindowMacros.java | 77 ++++++++----------- .../menu/MenuGeneratorsInGame.java | 12 ++- .../electrosphere/server/datacell/Realm.java | 5 -- .../fluid/manager/ServerFluidManager.java | 25 +++++- 11 files changed, 173 insertions(+), 68 deletions(-) diff --git a/docs/src/progress/renderertodo.md b/docs/src/progress/renderertodo.md index e7023465..e20a54f8 100644 --- a/docs/src/progress/renderertodo.md +++ b/docs/src/progress/renderertodo.md @@ -182,8 +182,9 @@ Fix character movement Fix Frustum Culling for skybox -Fix Character creation preview not working +Free camera system that can detatch from player entity +Fix Character creation preview not working Clean up main method/class @@ -354,3 +355,12 @@ dynamic camp/house system - npcs will gradually join your camp the longer you st dynamic warfare system - Guard towers that need to be captured by factions before enabling assault on real settlements - Raids against villages + + + + + +# Known bugs + - Draw cell manager iso values dont make sense and should scale empty cells based on neighbor cells + - Draw cell manager logic doesn't fill in border cells properly (the logic to check if a border cell exists always succeeds as long as the potential location is within world bounds, not if it actually exists in cache) + - Control handler re-polls for mouse coordiantes for each control handler group it processes, so only the first group gets the mouse movement event properly \ No newline at end of file diff --git a/src/main/java/electrosphere/client/fluid/cells/FluidCell.java b/src/main/java/electrosphere/client/fluid/cells/FluidCell.java index 26cba915..3021cfc9 100644 --- a/src/main/java/electrosphere/client/fluid/cells/FluidCell.java +++ b/src/main/java/electrosphere/client/fluid/cells/FluidCell.java @@ -292,6 +292,9 @@ public class FluidCell { (1 + weights[x][y][z]) < weights[currX][currY][currZ] ){ weights[x][y][z] = -(1 - weights[currX][currY][currZ]); + if(weights[x][y][z] >= 0){ + weights[x][y][z] = -0.01f; + } } } } diff --git a/src/main/java/electrosphere/client/sim/ClientFunctions.java b/src/main/java/electrosphere/client/sim/ClientFunctions.java index d6470bfd..3726d5b9 100644 --- a/src/main/java/electrosphere/client/sim/ClientFunctions.java +++ b/src/main/java/electrosphere/client/sim/ClientFunctions.java @@ -32,6 +32,7 @@ public class ClientFunctions { updateSkyboxPos(); Globals.clientSceneWrapper.destroyEntitiesOutsideSimRange(); InstanceUpdater.updateInstancedActorPriority(); + Globals.cameraHandler.updateGlobalCamera(); // updateCellManager(); } diff --git a/src/main/java/electrosphere/controls/CameraHandler.java b/src/main/java/electrosphere/controls/CameraHandler.java index 683a8828..ef7817ef 100644 --- a/src/main/java/electrosphere/controls/CameraHandler.java +++ b/src/main/java/electrosphere/controls/CameraHandler.java @@ -20,6 +20,7 @@ public class CameraHandler { float pitch = 50; Vector3f cameraRotationVector = new Vector3f(); Vector3f radialOffset = new Vector3f(0,1,0); + boolean trackPlayerEntity = true; public void handleMouseEvent(MouseEvent event){ @@ -89,6 +90,10 @@ public class CameraHandler { // cameraRotationVector.normalize(); // System.out.println(yaw + " " + pitch); } + if(trackPlayerEntity && Globals.playerEntity != null){ + Vector3d entityPos = EntityUtils.getPosition(Globals.playerEntity); + CameraEntityUtils.setCameraCenter(Globals.playerCamera, new Vector3f((float)entityPos.x,(float)entityPos.y,(float)entityPos.z).add(CameraEntityUtils.getOrbitalCameraRadialOffset(Globals.playerCamera))); + } //update view matrix offset float xFactor = (float)Math.cos(yaw / 180.0f * Math.PI); float yFactor = (float)Math.sin(yaw / 180.0f * Math.PI); @@ -110,4 +115,17 @@ public class CameraHandler { return pitch; } + //set player tracking + public void setTrackPlayerEntity(boolean track){ + trackPlayerEntity = track; + } + + //get trackPlayerEntity + public boolean getTrackPlayerEntity(){ + return trackPlayerEntity; + } + + + + } diff --git a/src/main/java/electrosphere/controls/ControlHandler.java b/src/main/java/electrosphere/controls/ControlHandler.java index fedf8433..b238b8b0 100644 --- a/src/main/java/electrosphere/controls/ControlHandler.java +++ b/src/main/java/electrosphere/controls/ControlHandler.java @@ -193,6 +193,15 @@ public class ControlHandler { public static final String DEBUG_FRAMESTEP = "framestep"; public static final String DEBUG_OPEN_DEBUG_MENU = "openDebugMenu"; + + + public static final String FREECAM_UP = "freecamUp"; + public static final String FREECAM_DOWN = "freecamDown"; + public static final String FREECAM_FORWARD = "freecamForward"; + public static final String FREECAM_BACKWARD = "freecamBackward"; + public static final String FREECAM_LEFT = "freecamLeft"; + public static final String FREECAM_RIGHT = "freecamRight"; + public static final String FREECAM_MOUSE = "freecamMouse"; public static enum ControlsState { @@ -200,6 +209,7 @@ public class ControlHandler { TITLE_MENU, MAIN_GAME, IN_GAME_MAIN_MENU, + IN_GAME_FREE_CAMERA, INVENTORY, NO_INPUT, } @@ -232,6 +242,7 @@ public class ControlHandler { List typingControlList = new LinkedList(); List inventoryControlList = new LinkedList(); List alwaysOnDebugControlList = new LinkedList(); + List freeCameraControlList = new LinkedList(); ControlHandler(){ controls = new HashMap(); @@ -341,6 +352,18 @@ public class ControlHandler { set state */ handler.setHandlerState(ControlsState.TITLE_MENU); + + /* + * Free camera + */ + handler.addControl(FREECAM_UP, new Control(ControlType.KEY,GLFW_KEY_SPACE)); + handler.addControl(FREECAM_DOWN, new Control(ControlType.KEY,GLFW_KEY_LEFT_CONTROL)); + handler.addControl(FREECAM_FORWARD, new Control(ControlType.KEY,GLFW_KEY_W)); + handler.addControl(FREECAM_BACKWARD, new Control(ControlType.KEY,GLFW_KEY_S)); + handler.addControl(FREECAM_LEFT, new Control(ControlType.KEY,GLFW_KEY_A)); + handler.addControl(FREECAM_RIGHT, new Control(ControlType.KEY,GLFW_KEY_D)); + handler.addControl(FREECAM_MOUSE, new Control(ControlType.MOUSE_MOVEMENT,0)); + /* Save to file @@ -395,6 +418,12 @@ public class ControlHandler { // pollMenuNavigationControls(); break; + case IN_GAME_FREE_CAMERA: + runHandlers(freeCameraControlList); + runHandlers(mainGameDebugControlList); + runHandlers(alwaysOnDebugControlList); + break; + case INVENTORY: runHandlers(inventoryControlList); runHandlers(menuNavigationControlList); @@ -416,6 +445,7 @@ public class ControlHandler { setTypingControls(); setInventoryControls(); setAlwaysOnDebugControls(); + setFreecamControls(); } void setMainGameControls(){ @@ -1121,6 +1151,48 @@ public class ControlHandler { controls.get(DATA_STRING_INPUT_CODE_MENU_BACKOUT).setRepeatTimeout(0.5f * Main.targetFrameRate); } + + void setFreecamControls(){ + freeCameraControlList.add(controls.get(FREECAM_UP)); + controls.get(FREECAM_UP).setOnRepeat(new ControlMethod(){public void execute(){ + Vector3f playerCameraCenterPos = CameraEntityUtils.getCameraCenter(Globals.playerCamera); + playerCameraCenterPos.add(0,0.1f,0); + CameraEntityUtils.setCameraCenter(Globals.playerCamera,playerCameraCenterPos); + }}); + + + freeCameraControlList.add(controls.get(FREECAM_DOWN)); + controls.get(FREECAM_DOWN).setOnRepeat(new ControlMethod(){public void execute(){ + Vector3f playerCameraCenterPos = CameraEntityUtils.getCameraCenter(Globals.playerCamera); + playerCameraCenterPos.add(0,-0.1f,0); + CameraEntityUtils.setCameraCenter(Globals.playerCamera,playerCameraCenterPos); + }}); + + + freeCameraControlList.add(controls.get(FREECAM_FORWARD)); + controls.get(FREECAM_FORWARD).setOnRepeat(new ControlMethod(){public void execute(){ + Vector3f playerCameraCenterPos = CameraEntityUtils.getCameraCenter(Globals.playerCamera); + Vector3f playerCameraEyePos = CameraEntityUtils.getCameraEye(Globals.playerCamera); + playerCameraCenterPos.add(new Vector3f(playerCameraEyePos).mul(-0.1f)); + CameraEntityUtils.setCameraCenter(Globals.playerCamera,playerCameraCenterPos); + }}); + + freeCameraControlList.add(controls.get(FREECAM_BACKWARD)); + controls.get(FREECAM_BACKWARD).setOnRepeat(new ControlMethod(){public void execute(){ + Vector3f playerCameraCenterPos = CameraEntityUtils.getCameraCenter(Globals.playerCamera); + Vector3f playerCameraEyePos = CameraEntityUtils.getCameraEye(Globals.playerCamera); + playerCameraCenterPos.add(new Vector3f(playerCameraEyePos).mul(0.1f)); + CameraEntityUtils.setCameraCenter(Globals.playerCamera,playerCameraCenterPos); + }}); + + freeCameraControlList.add(controls.get(FREECAM_MOUSE)); + controls.get(FREECAM_MOUSE).setOnMove(new Control.MouseCallback(){public void execute(MouseEvent event){ + Globals.cameraHandler.handleMouseEvent(event); + }}); + + freeCameraControlList.add(controls.get(DATA_STRING_INPUT_CODE_IN_GAME_MAIN_MENU)); + + } void setTypingControls(){ @@ -1352,6 +1424,10 @@ public class ControlHandler { public void setHandlerState(ControlsState state){ this.state = state; } + + public ControlsState getHandlerState(){ + return state; + } public ControlsState getState(){ return state; diff --git a/src/main/java/electrosphere/engine/loadingthreads/ClientLoading.java b/src/main/java/electrosphere/engine/loadingthreads/ClientLoading.java index a83dbdc1..33fe9048 100644 --- a/src/main/java/electrosphere/engine/loadingthreads/ClientLoading.java +++ b/src/main/java/electrosphere/engine/loadingthreads/ClientLoading.java @@ -177,7 +177,6 @@ public class ClientLoading { */ Globals.playerCamera = CameraEntityUtils.spawnPlayerEntityTrackingCameraEntity(new Vector3f(1,0,1), new Vector3f(0,0,1)); - // Globals.playerCamera = CameraEntityUtils.spawnPlayerEntityAirplaneTrackingCameraEntity(new Vector3f(1,0,1), new Vector3f(0,0,1)); diff --git a/src/main/java/electrosphere/entity/types/camera/CameraEntityUtils.java b/src/main/java/electrosphere/entity/types/camera/CameraEntityUtils.java index 419102b6..93027fb6 100644 --- a/src/main/java/electrosphere/entity/types/camera/CameraEntityUtils.java +++ b/src/main/java/electrosphere/entity/types/camera/CameraEntityUtils.java @@ -62,16 +62,7 @@ public class CameraEntityUtils { rVal.putData(EntityDataStrings.CAMERA_ORBIT_RADIAL_OFFSET, new Vector3f(0,1,0)); rVal.putData(EntityDataStrings.CAMERA_PITCH, 0.0f); rVal.putData(EntityDataStrings.CAMERA_YAW, 0.0f); - BehaviorTree entityTrackingTree = new BehaviorTree() { - @Override - public void simulate(float deltaTime) { - if(Globals.playerEntity != null){ - Vector3d entityPos = EntityUtils.getPosition(Globals.playerEntity); - CameraEntityUtils.setCameraCenter(rVal, new Vector3f((float)entityPos.x,(float)entityPos.y,(float)entityPos.z).add(getOrbitalCameraRadialOffset(rVal))); - } - } - }; - Globals.clientScene.registerBehaviorTree(entityTrackingTree); + Globals.cameraHandler.setTrackPlayerEntity(true); return rVal; } diff --git a/src/main/java/electrosphere/menu/ImGuiWindowMacros.java b/src/main/java/electrosphere/menu/ImGuiWindowMacros.java index 99528fd0..ab2316f3 100644 --- a/src/main/java/electrosphere/menu/ImGuiWindowMacros.java +++ b/src/main/java/electrosphere/menu/ImGuiWindowMacros.java @@ -4,6 +4,7 @@ import java.util.HashMap; import java.util.Map; import electrosphere.audio.VirtualAudioSource; +import electrosphere.controls.ControlHandler.ControlsState; import electrosphere.engine.Globals; import electrosphere.entity.EntityUtils; import electrosphere.renderer.RenderingEngine; @@ -29,11 +30,6 @@ public class ImGuiWindowMacros { private static ImGuiLinePlot globalFrametimePlot; private static Map globalFrametimeDatasets; - //server sim time graph - private static ImGuiWindow serverFrametimeWindow; - private static ImGuiBarPlot serverFrametimePlot; - private static double serverFrametimeTrackerStorage = 0; - //audio debug menu private static ImGuiWindow audioDebugMenu; private static boolean showAllVirtualAudioChildren = false; @@ -42,15 +38,18 @@ public class ImGuiWindowMacros { //player entity details private static ImGuiWindow playerEntityWindow; + //fluid details + private static ImGuiWindow fluidWindow; + /** * Initializes imgui windows */ public static void initImGuiWindows(){ createMainDebugMenu(); createFramerateGraph(); - createServerFrametimeGraph(); createAudioDebugMenu(); createPlayerEntityDebugWindow(); + createFluidDebugWindow(); } /** @@ -95,40 +94,6 @@ public class ImGuiWindowMacros { } } - /** - * Creates a server frametime breakdown graph - */ - private static void createServerFrametimeGraph(){ - serverFrametimeWindow = new ImGuiWindow("Server Frametime Graph"); - serverFrametimePlot = new ImGuiBarPlot("Server Frametime plot"); - serverFrametimeWindow.addElement(serverFrametimePlot); - serverFrametimeWindow.setOpen(false); - RenderingEngine.addImGuiWindow(serverFrametimeWindow); - } - - /** - * Starts a tracker for server frametime for a given method - */ - public static void startServerFrametimeTrackerFlame(double startValue){ - serverFrametimeTrackerStorage = startValue; - } - - /** - * Finishes tracking a single run of a specific method - * @param valueName The name of the method - * @param endValue the end time that the method finished on - */ - public static void clockServerFrametimeTrackerFlame(String valueName, double endValue){ - serverFrametimePlot.addToDatapoint(valueName, endValue - serverFrametimeTrackerStorage); - } - - /** - * Clears the server frametime values so they can be re-filled - */ - public static void clearServerFrametime(){ - serverFrametimePlot.clearDatapoints(); - } - /** * Create audio debug menu */ @@ -197,17 +162,39 @@ public class ImGuiWindowMacros { playerEntityWindow.setCallback(new ImGuiWindowCallback() { @Override public void exec() { - //audio engine details + //player entity details ImGui.text("Player Entity Details"); if(Globals.playerEntity != null){ ImGui.text("Position: " + EntityUtils.getPosition(Globals.playerEntity)); } + if(ImGui.button("Toggle Player Camera Lock")){ + Globals.cameraHandler.setTrackPlayerEntity(!Globals.cameraHandler.getTrackPlayerEntity()); + } } }); playerEntityWindow.setOpen(false); RenderingEngine.addImGuiWindow(playerEntityWindow); } + /** + * Create fluid debug menu + */ + private static void createFluidDebugWindow(){ + fluidWindow = new ImGuiWindow("Fluids"); + fluidWindow.setCallback(new ImGuiWindowCallback() { + @Override + public void exec() { + //audio engine details + ImGui.text("Fluids Debug"); + if(ImGui.button("Toggle Simulation")){ + Globals.serverFluidManager.setSimulate(!Globals.serverFluidManager.getSimulate());; + } + } + }); + fluidWindow.setOpen(false); + RenderingEngine.addImGuiWindow(fluidWindow); + } + /** * Inits the main debug menu @@ -221,10 +208,6 @@ public class ImGuiWindowMacros { if(ImGui.button("Show Overall Frametime")){ globalFrametimeWindow.setOpen(true); } - //show server frametime bar graph - if(ImGui.button("Show Server Frametime Breakdown")){ - serverFrametimeWindow.setOpen(true); - } //show audio debug if(ImGui.button("Show Audio Debug Menu")){ audioDebugMenu.setOpen(true); @@ -233,6 +216,10 @@ public class ImGuiWindowMacros { if(ImGui.button("Show Player Entity Debug Menu")){ playerEntityWindow.setOpen(true); } + //show fluids debug + if(ImGui.button("Show Fluids Debug Menu")){ + fluidWindow.setOpen(true); + } //close button if(ImGui.button("Close")){ mainDebugWindow.setOpen(false); diff --git a/src/main/java/electrosphere/menu/MenuGeneratorsInGame.java b/src/main/java/electrosphere/menu/MenuGeneratorsInGame.java index 768d21ea..48cd48e8 100644 --- a/src/main/java/electrosphere/menu/MenuGeneratorsInGame.java +++ b/src/main/java/electrosphere/menu/MenuGeneratorsInGame.java @@ -47,7 +47,11 @@ public class MenuGeneratorsInGame { div.setOnNavigationCallback(new NavigationEventCallback() {public boolean execute(NavigationEvent event){ WindowUtils.recursiveSetVisible(Globals.elementManager.getWindow(WindowStrings.WINDOW_MENU_INGAME_MAIN), false); Globals.elementManager.unregisterWindow(WindowStrings.WINDOW_MENU_INGAME_MAIN); - Globals.controlHandler.setHandlerState(ControlsState.MAIN_GAME); + if(Globals.cameraHandler.getTrackPlayerEntity()){ + Globals.controlHandler.setHandlerState(ControlsState.MAIN_GAME); + } else { + Globals.controlHandler.setHandlerState(ControlsState.IN_GAME_FREE_CAMERA); + } Globals.controlHandler.hideMouse(); return false; }}); @@ -68,7 +72,11 @@ public class MenuGeneratorsInGame { backButton.setOnClick(new ClickableElement.ClickEventCallback(){public boolean execute(ClickEvent event){ WindowUtils.recursiveSetVisible(Globals.elementManager.getWindow(WindowStrings.WINDOW_MENU_INGAME_MAIN), false); Globals.elementManager.unregisterWindow(WindowStrings.WINDOW_MENU_INGAME_MAIN); - Globals.controlHandler.setHandlerState(ControlsState.MAIN_GAME); + if(Globals.cameraHandler.getTrackPlayerEntity()){ + Globals.controlHandler.setHandlerState(ControlsState.MAIN_GAME); + } else { + Globals.controlHandler.setHandlerState(ControlsState.IN_GAME_FREE_CAMERA); + } Globals.controlHandler.hideMouse(); return false; }}); diff --git a/src/main/java/electrosphere/server/datacell/Realm.java b/src/main/java/electrosphere/server/datacell/Realm.java index 297f39ea..4dbeb4dd 100644 --- a/src/main/java/electrosphere/server/datacell/Realm.java +++ b/src/main/java/electrosphere/server/datacell/Realm.java @@ -156,15 +156,10 @@ public class Realm { * Tells the data cell manager to simulate all loaded cells */ protected void simulate(){ - ImGuiWindowMacros.clearServerFrametime(); //simulate bullet physics engine step - ImGuiWindowMacros.startServerFrametimeTrackerFlame(System.currentTimeMillis()); collisionEngine.simulatePhysics((float)Globals.timekeeper.getSimFrameTime()); - ImGuiWindowMacros.clockServerFrametimeTrackerFlame("physics", System.currentTimeMillis()); //main simulation - ImGuiWindowMacros.startServerFrametimeTrackerFlame(System.currentTimeMillis()); dataCellManager.simulate(); - ImGuiWindowMacros.clockServerFrametimeTrackerFlame("simulate", System.currentTimeMillis()); //data cell manager update misc variables (player positions, unload not-in-use cells) if(dataCellManager != null){ dataCellManager.unloadPlayerlessChunks(); diff --git a/src/main/java/electrosphere/server/fluid/manager/ServerFluidManager.java b/src/main/java/electrosphere/server/fluid/manager/ServerFluidManager.java index 0e3a3a74..91d66181 100644 --- a/src/main/java/electrosphere/server/fluid/manager/ServerFluidManager.java +++ b/src/main/java/electrosphere/server/fluid/manager/ServerFluidManager.java @@ -58,6 +58,9 @@ public class ServerFluidManager { //the terrain manager associated ServerTerrainManager serverTerrainManager; + + //controls whether fluid simulation should actually happen or not + boolean simulate = true; /** @@ -292,12 +295,26 @@ public class ServerFluidManager { * Simulates a chunk */ public boolean simulate(int worldX, int worldY, int worldZ){ - ServerFluidChunk fluidChunk = this.getChunk(worldX, worldY, worldZ); - ServerTerrainChunk terrainChunk = this.serverTerrainManager.getChunk(worldX, worldY, worldZ); - if(fluidChunk != null && terrainChunk != null && this.serverFluidSimulator != null){ - return this.serverFluidSimulator.simulate(fluidChunk,terrainChunk,worldX,worldY,worldZ); + if(simulate){ + ServerFluidChunk fluidChunk = this.getChunk(worldX, worldY, worldZ); + ServerTerrainChunk terrainChunk = this.serverTerrainManager.getChunk(worldX, worldY, worldZ); + if(fluidChunk != null && terrainChunk != null && this.serverFluidSimulator != null){ + return this.serverFluidSimulator.simulate(fluidChunk,terrainChunk,worldX,worldY,worldZ); + } } return false; } + + //getter for simulate + public boolean getSimulate(){ + return simulate; + } + + //setter for simulate + public void setSimulate(boolean simulate){ + this.simulate = simulate; + } + + }