diff --git a/assets/Data/creatures/human.json b/assets/Data/creatures/human.json index 9cfb526f..4028b721 100644 --- a/assets/Data/creatures/human.json +++ b/assets/Data/creatures/human.json @@ -134,16 +134,25 @@ "length" : 1, "loops" : false }, + "animationFirstPersonStartup" : { + "name" : "Jog" + }, "animationLoop" : { "name" : "Jog", "length" : 1, "loops" : false }, + "animationFirstPersonLoop" : { + "name" : "Jog" + }, "animationWindDown" : { "name" : "Jog", "length" : 1, "loops" : false }, + "animationFirstPersonWindDown" : { + "name" : "Jog" + }, "sprintSystem" : { "maxVelocity" : 0.058, "staminaMax" : 500, @@ -167,6 +176,9 @@ "name" : "Jump", "length" : 1, "loops" : false + }, + "animationFirstPersonJump" : { + "name" : "Jump" } }, { @@ -176,10 +188,16 @@ "length" : 1, "loops" : true }, + "animationFirstPersonFall" : { + "name" : "Fall" + }, "animationLand" : { "name" : "Land", "length" : 1, "loops" : true + }, + "animationFirstPersonLand" : { + "name" : "Land" } } ], @@ -224,6 +242,7 @@ { "equipPointId" : "handLeft", "bone" : "MiddleLower.L", + "firstPersonBone" : "hand.L", "offsetVector" : [], "offsetRotation" : [], "equipClassWhitelist" : [ @@ -235,6 +254,7 @@ { "equipPointId" : "handRight", "bone" : "MiddleLower.R", + "firstPersonBone" : "hand.R", "offsetVector" : [], "offsetRotation" : [0.3057,0.2926,0.09933,0.9006], "equipClassWhitelist" : [ @@ -294,7 +314,16 @@ "driftGoal" : 0.02, "driftFrameStart" : 7, "driftFrameEnd" : 15, - "initialMove" : true + "initialMove" : true, + "animationFirstPersonWindup" : { + "name" : "Jump" + }, + "animationFirstPersonHold" : { + "name" : "Jump" + }, + "animationFirstPersonAttack" : { + "name" : "Jump" + } }, { "attackMoveId" : "Sword1HSlash2", @@ -310,7 +339,16 @@ "driftGoal" : 0.03, "driftFrameStart" : 1, "driftFrameEnd" : 10, - "initialMove" : false + "initialMove" : false, + "animationFirstPersonWindup" : { + "name" : "Jump" + }, + "animationFirstPersonHold" : { + "name" : "Jump" + }, + "animationFirstPersonAttack" : { + "name" : "Jump" + } }, { "attackMoveId" : "Bow2HFire", @@ -327,14 +365,33 @@ "movementStart" : 0, "movementEnd" : 0, "movementGoal" : 0, - "initialMove" : true + "initialMove" : true, + "animationFirstPersonWindup" : { + "name" : "Jump" + }, + "animationFirstPersonHold" : { + "name" : "Jump" + }, + "animationFirstPersonAttack" : { + "name" : "Jump" + } } ], "healthSystem" : { "maxHealth" : 100, "onDamageIFrames" : 30 }, - "modelPath" : "Models/creatures/person2/person2_1.glb" + "idleData": { + "idleAnimation" : "Idle1", + "firstPersonIdleAnimation" : "Idle" + }, + "modelPath" : "Models/creatures/person2/person2_1.glb", + "viewModelData" : { + "heightFromOrigin" : 0.8, + "cameraViewDirOffsetY" : -0.3, + "cameraViewDirOffsetZ" : 0.0, + "firstPersonModelPath" : "Models/creatures/viewmodel.glb" + } } ], "files" : [] diff --git a/assets/Models/creatures/viewmodel.glb b/assets/Models/creatures/viewmodel.glb new file mode 100644 index 00000000..f257e2d2 Binary files /dev/null and b/assets/Models/creatures/viewmodel.glb differ diff --git a/buildNumber.properties b/buildNumber.properties index 48df1751..08feaf59 100644 --- a/buildNumber.properties +++ b/buildNumber.properties @@ -1,3 +1,3 @@ #maven.buildNumber.plugin properties file -#Thu May 02 18:40:02 EDT 2024 -buildNumber=119 +#Sun May 19 19:34:37 EDT 2024 +buildNumber=132 diff --git a/docs/src/progress/renderertodo.md b/docs/src/progress/renderertodo.md index e8e27c07..7e129130 100644 --- a/docs/src/progress/renderertodo.md +++ b/docs/src/progress/renderertodo.md @@ -273,23 +273,46 @@ Ground Texture Atlas system First Person Camera -# TODO +(05/15/2024) +More consistent terrain editing +(05/16/2024) +Reintroduce strafing + +(05/??/2024) First person render pipeline - - Dedicated client scene - Properly compositing onto main texture - Potentially look at storing the framebuffer for the pipeline in the pipeline class itself -Overhaul of 'attach' semantics - - Having different types of attach tree propagation - - Ability to turn on/off combinations of models at will (already exists, but needs review) - +(05/19/2024) Character movement in particular feels off - Bring back strafing - Fix interaction with networking - Potentially facing vector on server misaligned with client facing vector? - Nope! They're perfectly aligned - May be in the ground move tree itself the hard setting velocity instead of applying a force is causing weirdness +(05/23/2024) +Viewmodel + - Fix hands placement + - Animations defined in data file + +(05/24/2024) +Viewmodel + - Add animations queues in btrees + - idle + - jump + - ground movement + - land + - fall + - attack + +Attaching items to hands in first person + +Fix grass placement + + +# TODO + Fix being able to walk off far side of the world (ie in level editor) Grass System properly LOD @@ -308,6 +331,13 @@ Data Cleanup Clean up Material class - fix storing textures in the mat class ( pain :c ) +Clean up framebuffer class + - Comment everything + +Overhaul of 'attach' semantics + - Having different types of attach tree propagation + - Ability to turn on/off combinations of models at will (already exists, but needs review) + More Debug menus - Screen that shows the overall status of draw cell manager - Screen that shows the overall status of fluid cell manager diff --git a/src/main/java/electrosphere/client/foliagemanager/ClientFoliageManager.java b/src/main/java/electrosphere/client/foliagemanager/ClientFoliageManager.java index 8660a725..82dc3d95 100644 --- a/src/main/java/electrosphere/client/foliagemanager/ClientFoliageManager.java +++ b/src/main/java/electrosphere/client/foliagemanager/ClientFoliageManager.java @@ -1,7 +1,6 @@ package electrosphere.client.foliagemanager; import java.nio.ByteBuffer; -import java.nio.DoubleBuffer; import java.nio.FloatBuffer; import java.util.ArrayList; import java.util.HashMap; @@ -18,7 +17,6 @@ import org.joml.Vector3d; import org.joml.Vector3f; import org.joml.Vector3i; import org.lwjgl.BufferUtils; -import org.lwjgl.system.MemoryUtil; import electrosphere.client.terrain.cache.ChunkData; import electrosphere.engine.Globals; @@ -395,17 +393,20 @@ public class ClientFoliageManager { //get position to place double rand1 = placementRandomizer.nextDouble(); double rand2 = placementRandomizer.nextDouble(); - double relativePositionOnGridX = x / (1.0 * TARGET_FOLIAGE_SPACING) - 0.5 + rand1 / TARGET_FOLIAGE_SPACING; - double relativePositionOnGridZ = z / (1.0 * TARGET_FOLIAGE_SPACING) - 0.5 + rand2 / TARGET_FOLIAGE_SPACING; - double offsetX = relativePositionOnGridX; - double offsetZ = relativePositionOnGridZ; + double relativePositionOnGridX = x / (1.0 * TARGET_FOLIAGE_SPACING) + rand1 / TARGET_FOLIAGE_SPACING; + double relativePositionOnGridZ = z / (1.0 * TARGET_FOLIAGE_SPACING) + rand2 / TARGET_FOLIAGE_SPACING; + double offsetX = relativePositionOnGridX - 0.5; + double offsetZ = relativePositionOnGridZ - 0.5; //determine quadrant we're placing in double offsetY = 0; boolean addBlade = false; - if(relativePositionOnGridX >=0){ - if(relativePositionOnGridZ >= 0){ - relativePositionOnGridX += 0.5; - relativePositionOnGridZ += 0.5; + if(relativePositionOnGridX >=0.5){ + if(relativePositionOnGridZ >= 0.5){ + relativePositionOnGridX = relativePositionOnGridX - 0.5; + relativePositionOnGridZ = relativePositionOnGridZ - 0.5; + relativePositionOnGridX /= 0.5; + relativePositionOnGridZ /= 0.5; + // System.out.println(relativePositionOnGridX + " " + relativePositionOnGridZ); //if we have heights for all four surrounding spots, interpolate for y value if(sample_11 != null && sample_12 != null && sample_21 != null && sample_22 != null){ offsetY = @@ -416,8 +417,9 @@ public class ClientFoliageManager { addBlade = true; } } else { - relativePositionOnGridX += 0.5; - relativePositionOnGridZ += 0.5; + relativePositionOnGridX = relativePositionOnGridX - 0.5; + relativePositionOnGridX /= 0.5; + relativePositionOnGridZ /= 0.5; //if we have heights for all four surrounding spots, interpolate for y value if(sample_10 != null && sample_11 != null && sample_20 != null && sample_21 != null){ offsetY = @@ -429,9 +431,10 @@ public class ClientFoliageManager { } } } else { - if(relativePositionOnGridZ >= 0){ - relativePositionOnGridX += 0.5; - relativePositionOnGridZ += 0.5; + if(relativePositionOnGridZ >= 0.5){ + relativePositionOnGridZ = relativePositionOnGridZ - 0.5; + relativePositionOnGridX /= 0.5; + relativePositionOnGridZ /= 0.5; //if we have heights for all four surrounding spots, interpolate for y value if(sample_01 != null && sample_02 != null && sample_11 != null && sample_12 != null){ offsetY = @@ -442,8 +445,8 @@ public class ClientFoliageManager { addBlade = true; } } else { - relativePositionOnGridX += 0.5; - relativePositionOnGridZ += 0.5; + relativePositionOnGridX /= 0.5; + relativePositionOnGridZ /= 0.5; //if we have heights for all four surrounding spots, interpolate for y value if(sample_00 != null && sample_01 != null && sample_10 != null && sample_11 != null){ offsetY = diff --git a/src/main/java/electrosphere/controls/ControlHandler.java b/src/main/java/electrosphere/controls/ControlHandler.java index 1bea9d0b..e6087bdc 100644 --- a/src/main/java/electrosphere/controls/ControlHandler.java +++ b/src/main/java/electrosphere/controls/ControlHandler.java @@ -475,14 +475,14 @@ public class ControlHandler { if(movementTree instanceof ClientGroundMovementTree){ ClientGroundMovementTree groundTree = (ClientGroundMovementTree) movementTree; Vector3f cameraEyeVector = CameraEntityUtils.getCameraEye(Globals.playerCamera); - if(controls.get(DATA_STRING_INPUT_CODE_MOVEMENT_LEFT).isState()){ + if(controls.get(DATA_STRING_INPUT_CODE_STRAFE_LEFT).isState()){ Vector3d newFacingVector = new Vector3d(-cameraEyeVector.x,0,-cameraEyeVector.z).rotateY(Math.PI/4.0).normalize(); CreatureUtils.setFacingVector(Globals.playerEntity, newFacingVector); - groundTree.start(MovementRelativeFacing.FORWARD); - } else if(controls.get(DATA_STRING_INPUT_CODE_MOVEMENT_RIGHT).isState()){ + groundTree.start(MovementRelativeFacing.FORWARD_LEFT); + } else if(controls.get(DATA_STRING_INPUT_CODE_STRAFE_RIGHT).isState()){ Vector3d newFacingVector = new Vector3d(-cameraEyeVector.x,0,-cameraEyeVector.z).rotateY(-Math.PI/4.0).normalize(); CreatureUtils.setFacingVector(Globals.playerEntity, newFacingVector); - groundTree.start(MovementRelativeFacing.FORWARD); + groundTree.start(MovementRelativeFacing.FORWARD_RIGHT); } else { Vector3d newFacingVector = new Vector3d(-cameraEyeVector.x,0,-cameraEyeVector.z).normalize(); CreatureUtils.setFacingVector(Globals.playerEntity, newFacingVector); @@ -497,14 +497,14 @@ public class ControlHandler { if(movementTree instanceof ClientGroundMovementTree){ ClientGroundMovementTree groundTree = (ClientGroundMovementTree) movementTree; Vector3f cameraEyeVector = CameraEntityUtils.getCameraEye(Globals.playerCamera); - if(controls.get(DATA_STRING_INPUT_CODE_MOVEMENT_LEFT).isState()){ + if(controls.get(DATA_STRING_INPUT_CODE_STRAFE_LEFT).isState()){ Vector3d newFacingVector = new Vector3d(-cameraEyeVector.x,0,-cameraEyeVector.z).rotateY(Math.PI/4.0).normalize(); CreatureUtils.setFacingVector(Globals.playerEntity, newFacingVector); - groundTree.start(MovementRelativeFacing.FORWARD); - } else if(controls.get(DATA_STRING_INPUT_CODE_MOVEMENT_RIGHT).isState()){ + groundTree.start(MovementRelativeFacing.FORWARD_LEFT); + } else if(controls.get(DATA_STRING_INPUT_CODE_STRAFE_RIGHT).isState()){ Vector3d newFacingVector = new Vector3d(-cameraEyeVector.x,0,-cameraEyeVector.z).rotateY(-Math.PI/4.0).normalize(); CreatureUtils.setFacingVector(Globals.playerEntity, newFacingVector); - groundTree.start(MovementRelativeFacing.FORWARD); + groundTree.start(MovementRelativeFacing.FORWARD_RIGHT); } else { Vector3d newFacingVector = new Vector3d(-cameraEyeVector.x,0,-cameraEyeVector.z).normalize(); CreatureUtils.setFacingVector(Globals.playerEntity, newFacingVector); @@ -532,15 +532,15 @@ public class ControlHandler { if(movementTree instanceof ClientGroundMovementTree){ ClientGroundMovementTree groundTree = (ClientGroundMovementTree) movementTree; Vector3f cameraEyeVector = CameraEntityUtils.getCameraEye(Globals.playerCamera); - if(controls.get(DATA_STRING_INPUT_CODE_MOVEMENT_LEFT).isState()){ + if(controls.get(DATA_STRING_INPUT_CODE_STRAFE_LEFT).isState()){ CreatureUtils.setFacingVector(Globals.playerEntity, new Vector3d(-cameraEyeVector.x,0,-cameraEyeVector.z).rotateY(3.0/4.0*Math.PI).normalize()); - groundTree.start(MovementRelativeFacing.FORWARD); - } else if(controls.get(DATA_STRING_INPUT_CODE_MOVEMENT_RIGHT).isState()){ + groundTree.start(MovementRelativeFacing.BACKWARD_LEFT); + } else if(controls.get(DATA_STRING_INPUT_CODE_STRAFE_RIGHT).isState()){ CreatureUtils.setFacingVector(Globals.playerEntity, new Vector3d(-cameraEyeVector.x,0,-cameraEyeVector.z).rotateY(5.0/4.0*Math.PI).normalize()); - groundTree.start(MovementRelativeFacing.FORWARD); + groundTree.start(MovementRelativeFacing.BACKWARD_RIGHT); } else { - CreatureUtils.setFacingVector(Globals.playerEntity, new Vector3d(-cameraEyeVector.x,0,-cameraEyeVector.z).rotateY(Math.PI).normalize()); - groundTree.start(MovementRelativeFacing.FORWARD); + CreatureUtils.setFacingVector(Globals.playerEntity, new Vector3d(-cameraEyeVector.x,0,-cameraEyeVector.z).normalize()); + groundTree.start(MovementRelativeFacing.BACKWARD); } } } @@ -551,15 +551,15 @@ public class ControlHandler { if(movementTree instanceof ClientGroundMovementTree){ ClientGroundMovementTree groundTree = (ClientGroundMovementTree) movementTree; Vector3f cameraEyeVector = CameraEntityUtils.getCameraEye(Globals.playerCamera); - if(controls.get(DATA_STRING_INPUT_CODE_MOVEMENT_LEFT).isState()){ + if(controls.get(DATA_STRING_INPUT_CODE_STRAFE_LEFT).isState()){ CreatureUtils.setFacingVector(Globals.playerEntity, new Vector3d(-cameraEyeVector.x,0,-cameraEyeVector.z).rotateY(3.0/4.0*Math.PI).normalize()); - groundTree.start(MovementRelativeFacing.FORWARD); - } else if(controls.get(DATA_STRING_INPUT_CODE_MOVEMENT_RIGHT).isState()){ + groundTree.start(MovementRelativeFacing.BACKWARD_LEFT); + } else if(controls.get(DATA_STRING_INPUT_CODE_STRAFE_RIGHT).isState()){ CreatureUtils.setFacingVector(Globals.playerEntity, new Vector3d(-cameraEyeVector.x,0,-cameraEyeVector.z).rotateY(5.0/4.0*Math.PI).normalize()); - groundTree.start(MovementRelativeFacing.FORWARD); + groundTree.start(MovementRelativeFacing.BACKWARD_RIGHT); } else { - CreatureUtils.setFacingVector(Globals.playerEntity, new Vector3d(-cameraEyeVector.x,0,-cameraEyeVector.z).rotateY(Math.PI).normalize()); - groundTree.start(MovementRelativeFacing.FORWARD); + CreatureUtils.setFacingVector(Globals.playerEntity, new Vector3d(-cameraEyeVector.x,0,-cameraEyeVector.z).normalize()); + groundTree.start(MovementRelativeFacing.BACKWARD); } } } diff --git a/src/main/java/electrosphere/engine/Globals.java b/src/main/java/electrosphere/engine/Globals.java index e8d43980..29a0eaec 100644 --- a/src/main/java/electrosphere/engine/Globals.java +++ b/src/main/java/electrosphere/engine/Globals.java @@ -369,6 +369,8 @@ public class Globals { //the creature the player camera will orbit and will receive controlHandler movementTree updates public static Entity playerEntity; + //the entity for the first person modal (view model) + public static Entity firstPersonEntity; //client current selected voxel type public static VoxelType clientSelectedVoxelType = null; diff --git a/src/main/java/electrosphere/engine/loadingthreads/ClientLoading.java b/src/main/java/electrosphere/engine/loadingthreads/ClientLoading.java index 31d07b81..7b518b4a 100644 --- a/src/main/java/electrosphere/engine/loadingthreads/ClientLoading.java +++ b/src/main/java/electrosphere/engine/loadingthreads/ClientLoading.java @@ -182,7 +182,7 @@ public class ClientLoading { Globals.playerCamera = CameraEntityUtils.spawnPlayerEntityTrackingCameraFirstPersonEntity(new Vector3f(1,0,1), new Vector3f(0,0,1)); } - + /* Targeting crosshair diff --git a/src/main/java/electrosphere/entity/EntityDataStrings.java b/src/main/java/electrosphere/entity/EntityDataStrings.java index 024ad915..6bb350a0 100644 --- a/src/main/java/electrosphere/entity/EntityDataStrings.java +++ b/src/main/java/electrosphere/entity/EntityDataStrings.java @@ -70,6 +70,7 @@ public class EntityDataStrings { public static final String SERVER_JUMP_TREE = "serverJumpTree"; public static final String FALL_TREE = "fallTree"; public static final String CREATURE_TEMPLATE = "creatureTemplate"; + public static final String FIRST_PERSON_TREE = "firstPersonTree"; /* diff --git a/src/main/java/electrosphere/entity/state/attack/ClientAttackTree.java b/src/main/java/electrosphere/entity/state/attack/ClientAttackTree.java index 8d24bd45..96caecf2 100644 --- a/src/main/java/electrosphere/entity/state/attack/ClientAttackTree.java +++ b/src/main/java/electrosphere/entity/state/attack/ClientAttackTree.java @@ -11,6 +11,7 @@ import electrosphere.entity.EntityDataStrings; import electrosphere.entity.EntityUtils; import electrosphere.entity.ServerEntityUtils; import electrosphere.entity.btree.BehaviorTree; +import electrosphere.entity.state.client.firstPerson.FirstPersonTree; import electrosphere.entity.state.collidable.Impulse; import electrosphere.entity.state.equip.ClientEquipState; import electrosphere.entity.state.movement.groundmove.ClientGroundMovementTree; @@ -48,6 +49,9 @@ import org.joml.Vector3f; public class ClientAttackTree implements BehaviorTree { @SynchronizableEnum + /** + * States available to the attack tree + */ public static enum AttackTreeState { WINDUP, HOLD, @@ -56,29 +60,39 @@ public class ClientAttackTree implements BehaviorTree { IDLE, } - //the state of drifting forward during the attack @SynchronizableEnum + /** + * The state of drifting forward during the attack + */ public static enum AttackTreeDriftState { DRIFT, NO_DRIFT, } + //the current state of the tree @SyncedField AttackTreeState state; + //the current state of drifting caused by the tree @SyncedField AttackTreeDriftState driftState; + //the parent entity of this attack tree Entity parent; + //the queue of network messages to process CopyOnWriteArrayList networkMessageQueue = new CopyOnWriteArrayList(); + //the last time this tree was updated by server long lastUpdateTime = 0; + //the current frame of the current animation/move float frameCurrent; + //the name of the current animation String animationName = "SwingWeapon"; + //the max frame int maxFrame = 60; List currentMoveset = null; @@ -239,13 +253,14 @@ public class ClientAttackTree implements BehaviorTree { if(parent.containsKey(EntityDataStrings.CLIENT_ROTATOR_TREE)){ RotatorTree.getClientRotatorTree(parent).setActive(true); } - if(entityActor != null){ - if(!entityActor.isPlayingAnimation() || !entityActor.isPlayingAnimation(animationName)){ - entityActor.playAnimation(animationName,1); - entityActor.incrementAnimationTime(0.0001); - } - } if(currentMove != null && frameCurrent > currentMove.getWindupFrames()){ + if(entityActor != null){ + if(!entityActor.isPlayingAnimation() || !entityActor.isPlayingAnimation(currentMove.getWindupAnimationName())){ + entityActor.playAnimation(currentMove.getWindupAnimationName(),1); + entityActor.incrementAnimationTime(0.0001); + } + FirstPersonTree.conditionallyPlayAnimation(Globals.firstPersonEntity, currentMove.getAnimationFirstPersonWindup().getName()); + } if(currentMoveCanHold && stillHold){ state = AttackTreeState.HOLD; } else { @@ -259,6 +274,7 @@ public class ClientAttackTree implements BehaviorTree { entityActor.playAnimation(animationName,1); entityActor.incrementAnimationTime(0.0001); } + FirstPersonTree.conditionallyPlayAnimation(Globals.firstPersonEntity, currentMove.getAnimationFirstPersonHold().getName()); } if(!stillHold){ state = AttackTreeState.ATTACK; diff --git a/src/main/java/electrosphere/entity/state/ambientaudio/ClientAmbientAudioTree.java b/src/main/java/electrosphere/entity/state/client/ambientaudio/ClientAmbientAudioTree.java similarity index 98% rename from src/main/java/electrosphere/entity/state/ambientaudio/ClientAmbientAudioTree.java rename to src/main/java/electrosphere/entity/state/client/ambientaudio/ClientAmbientAudioTree.java index b44a36f2..72d9e3c8 100644 --- a/src/main/java/electrosphere/entity/state/ambientaudio/ClientAmbientAudioTree.java +++ b/src/main/java/electrosphere/entity/state/client/ambientaudio/ClientAmbientAudioTree.java @@ -1,4 +1,4 @@ -package electrosphere.entity.state.ambientaudio; +package electrosphere.entity.state.client.ambientaudio; import org.joml.Vector3d; diff --git a/src/main/java/electrosphere/entity/state/client/firstPerson/FirstPersonTree.java b/src/main/java/electrosphere/entity/state/client/firstPerson/FirstPersonTree.java new file mode 100644 index 00000000..613e308e --- /dev/null +++ b/src/main/java/electrosphere/entity/state/client/firstPerson/FirstPersonTree.java @@ -0,0 +1,123 @@ +package electrosphere.entity.state.client.firstPerson; + +import electrosphere.engine.Globals; +import electrosphere.entity.Entity; +import electrosphere.entity.EntityDataStrings; +import electrosphere.entity.EntityUtils; +import electrosphere.entity.btree.BehaviorTree; +import electrosphere.renderer.actor.Actor; + +/** + * Manages the animations for the first person view model + */ +public class FirstPersonTree implements BehaviorTree { + + + //the offset from the origin to place the viewmodel + double heightFromOrigin; + + //the amount to pull below the camera + double cameraViewDirOffsetY; + + //the amount to pull behind the camera + double cameraViewDirOffsetZ; + + //the animation to play currently + String currentAnimation = "Idle"; + + @Override + public void simulate(float deltaTime) { + if(Globals.firstPersonEntity != null){ + Actor actor = EntityUtils.getActor(Globals.firstPersonEntity); + if( + (!actor.isPlayingAnimation() || !actor.isPlayingAnimation(currentAnimation)) && + (Globals.assetManager.fetchModel(actor.getModelPath()) != null && Globals.assetManager.fetchModel(actor.getModelPath()).getAnimation(currentAnimation) != null) + + ){ + actor.playAnimation(currentAnimation,3); + actor.incrementAnimationTime(0.0001); + } + } + } + + /** + * Attaches this tree to the entity. + * @param entity The entity to attach to + * @param heightFromOrigin How far from the origin of the creature to place the viewmodel + * @param cameraViewDirOffset How far to pull the view model behind the camera + */ + public static FirstPersonTree attachTree(Entity parent, double heightFromOrigin, double cameraViewDirOffsetY, double cameraViewDirOffsetZ){ + FirstPersonTree rVal = new FirstPersonTree(); + + rVal.heightFromOrigin = heightFromOrigin; + rVal.cameraViewDirOffsetY = cameraViewDirOffsetY; + rVal.cameraViewDirOffsetZ = cameraViewDirOffsetZ; + + //!!WARNING!! THIS WAS MANUALLY MODIFIED OH GOD + parent.putData(EntityDataStrings.FIRST_PERSON_TREE, rVal); + Globals.clientScene.registerBehaviorTree(rVal); + return rVal; + } + + /** + * Gets the tree on the entity + * @param target the entity + * @return The tree + */ + public static FirstPersonTree getTree(Entity target){ + return (FirstPersonTree)target.getData(EntityDataStrings.FIRST_PERSON_TREE); + } + + /** + * Checks if the provided entity has the tree + * @param target the provided entity + * @return true if the entity has a FirstPersonTree, false otherwise + */ + public static boolean hasTree(Entity target){ + return target.containsKey(EntityDataStrings.FIRST_PERSON_TREE); + } + + /** + * the offset from the origin to place the viewmodel + * @return + */ + public double getHeightFromOrigin(){ + return heightFromOrigin; + } + + /** + * the amount to pull below the camera + * @return + */ + public double getCameraViewDirOffsetY(){ + return cameraViewDirOffsetY; + } + + /** + * the amount to pull behind the camera + * @return + */ + public double getCameraViewDirOffsetZ(){ + return cameraViewDirOffsetZ; + } + + /** + * Plays an animation if it exists + * @param animationName the name of the animation + */ + public void playAnimation(String animationName){ + this.currentAnimation = animationName; + } + + /** + * If the entity has a first person tree, plays the provided animation + * @param entity The entity + * @param animationName the name of the animation + */ + public static void conditionallyPlayAnimation(Entity entity, String animationName){ + if(hasTree(entity)){ + getTree(entity).playAnimation(animationName); + } + } + +} diff --git a/src/main/java/electrosphere/entity/state/equip/ClientEquipState.java b/src/main/java/electrosphere/entity/state/equip/ClientEquipState.java index f16ce735..a50ac58d 100644 --- a/src/main/java/electrosphere/entity/state/equip/ClientEquipState.java +++ b/src/main/java/electrosphere/entity/state/equip/ClientEquipState.java @@ -34,11 +34,20 @@ import electrosphere.renderer.actor.ActorMeshMask; */ public class ClientEquipState implements BehaviorTree { + //the parent entity of the btree Entity parent; + //the list of available equip points List equipPoints = new LinkedList(); + + //the map of point to the equipped entity Map equipMap = new HashMap(); + /** + * Creates the tree + * @param parent the entity this is attached to + * @param equipPoints the list of available points + */ public ClientEquipState(Entity parent, List equipPoints){ this.parent = parent; for(EquipPoint point : equipPoints){ @@ -46,10 +55,19 @@ public class ClientEquipState implements BehaviorTree { } } + /** + * Gets the list of equipped points + * @return the list + */ public List equippedPoints(){ return new LinkedList(equipMap.keySet()); } + /** + * Attempts to equip the item + * @param toEquip the item to equip + * @param point the point to equip to + */ public void commandAttemptEquip(Entity toEquip, EquipPoint point){ boolean hasEquipped = hasEquippedAtPoint(point.getEquipPointId()); boolean targetIsItem = ItemUtils.isItem(toEquip); @@ -117,7 +135,11 @@ public class ClientEquipState implements BehaviorTree { } else { //since we're not replacing meshes we must be attaching to a bone equipMap.put(point.getEquipPointId(),toEquip); - AttachUtils.clientAttachEntityToEntityAtBone(parent, toEquip, point.getBone(), AttachUtils.getEquipPointRotationOffset(point.getOffsetRotation())); + if(Globals.controlHandler.cameraIsThirdPerson()){ + AttachUtils.clientAttachEntityToEntityAtBone(parent, toEquip, point.getBone(), AttachUtils.getEquipPointRotationOffset(point.getOffsetRotation())); + } else { + AttachUtils.clientAttachEntityToEntityAtBone(Globals.firstPersonEntity, toEquip, point.getFirstPersonBone(), AttachUtils.getEquipPointRotationOffset(point.getOffsetRotation())); + } if(toEquip.containsKey(EntityDataStrings.PHYSICS_COLLISION_BODY) && toEquip.containsKey(EntityDataStrings.PHYSICS_COLLIDABLE)){ DBody rigidBody = (DBody)toEquip.getData(EntityDataStrings.PHYSICS_COLLISION_BODY); Globals.clientSceneWrapper.getCollisionEngine().deregisterPhysicsObject(rigidBody); @@ -171,6 +193,11 @@ public class ClientEquipState implements BehaviorTree { // } } + /** + * Gets the equip point by its name + * @param name the name of the equip point + * @return the equip point object if it exists, otherwise null + */ public EquipPoint getEquipPoint(String name){ for(EquipPoint point : equipPoints){ if(point.getEquipPointId().equals(name)){ @@ -180,6 +207,11 @@ public class ClientEquipState implements BehaviorTree { return null; } + /** + * Gets the item equipped at a point + * @param point the point's name + * @return the item entity + */ public Entity getEquippedItemAtPoint(String point){ return equipMap.get(point); } @@ -223,6 +255,10 @@ public class ClientEquipState implements BehaviorTree { // } // } + /** + * Attempts to unequip the item at a given point + * @param pointId the id of the point + */ public void commandAttemptUnequip(String pointId){ boolean hasEquipped = hasEquippedAtPoint(pointId); if(hasEquipped){ @@ -266,6 +302,11 @@ public class ClientEquipState implements BehaviorTree { } } + /** + * Checks if a point has an item equipped + * @param point the equip point + * @return true if there is an item equipped, false otherwise + */ public boolean hasEquippedAtPoint(String point){ return equipMap.containsKey(point); } diff --git a/src/main/java/electrosphere/entity/state/idle/IdleTree.java b/src/main/java/electrosphere/entity/state/idle/IdleTree.java index b7c2cf13..f5e5cc5f 100644 --- a/src/main/java/electrosphere/entity/state/idle/IdleTree.java +++ b/src/main/java/electrosphere/entity/state/idle/IdleTree.java @@ -3,6 +3,7 @@ package electrosphere.entity.state.idle; import electrosphere.net.synchronization.BehaviorTreeIdEnums; import electrosphere.entity.state.attack.ClientAttackTree; +import electrosphere.entity.state.client.firstPerson.FirstPersonTree; import electrosphere.entity.state.movement.AirplaneMovementTree; import electrosphere.entity.state.movement.groundmove.ClientGroundMovementTree; import electrosphere.entity.state.movement.groundmove.ClientGroundMovementTree.MovementTreeState; @@ -13,6 +14,8 @@ import electrosphere.entity.EntityDataStrings; import electrosphere.entity.EntityUtils; import electrosphere.entity.btree.BehaviorTree; import electrosphere.entity.types.creature.CreatureUtils; +import electrosphere.game.data.creature.type.CreatureType; +import electrosphere.game.data.creature.type.IdleData; import electrosphere.net.synchronization.annotation.SyncedField; import electrosphere.net.synchronization.annotation.SynchronizableEnum; import electrosphere.net.synchronization.annotation.SynchronizedBehaviorTree; @@ -37,10 +40,13 @@ public class IdleTree implements BehaviorTree { private IdleTreeState state; Entity parent; + IdleData idleData; public IdleTree(Entity e){ state = IdleTreeState.IDLE; parent = e; + CreatureType creatureType = Globals.gameConfigCurrent.getCreatureTypeLoader().getCreature(CreatureUtils.getType(parent)); + idleData = creatureType.getIdleData(); } /** @@ -80,12 +86,14 @@ public class IdleTree implements BehaviorTree { case IDLE: if(entityActor != null){ if( - (!entityActor.isPlayingAnimation() || !entityActor.isPlayingAnimation(Animation.ANIMATION_IDLE_1)) && - (Globals.assetManager.fetchModel(entityActor.getModelPath()) != null && Globals.assetManager.fetchModel(entityActor.getModelPath()).getAnimation(Animation.ANIMATION_IDLE_1) != null) + idleData != null && + (!entityActor.isPlayingAnimation() || !entityActor.isPlayingAnimation(idleData.getIdleAnimation())) && + (Globals.assetManager.fetchModel(entityActor.getModelPath()) != null && Globals.assetManager.fetchModel(entityActor.getModelPath()).getAnimation(idleData.getIdleAnimation()) != null) ){ - entityActor.playAnimation(Animation.ANIMATION_IDLE_1,3); + entityActor.playAnimation(idleData.getIdleAnimation(),3); entityActor.incrementAnimationTime(0.0001); + FirstPersonTree.conditionallyPlayAnimation(Globals.firstPersonEntity, idleData.getFirstPersonIdleAnimation()); } } break; diff --git a/src/main/java/electrosphere/entity/state/movement/FallTree.java b/src/main/java/electrosphere/entity/state/movement/FallTree.java index ef80367d..eac1af94 100644 --- a/src/main/java/electrosphere/entity/state/movement/FallTree.java +++ b/src/main/java/electrosphere/entity/state/movement/FallTree.java @@ -1,29 +1,42 @@ package electrosphere.entity.state.movement; +import electrosphere.engine.Globals; import electrosphere.entity.Entity; import electrosphere.entity.EntityDataStrings; import electrosphere.entity.EntityUtils; import electrosphere.entity.btree.BehaviorTree; +import electrosphere.entity.state.client.firstPerson.FirstPersonTree; +import electrosphere.game.data.creature.type.movement.FallMovementSystem; import electrosphere.renderer.actor.Actor; +/** + * Behavior tree for playing animations when an entity is falling/landing + */ public class FallTree implements BehaviorTree { + /** + * The state of the fall tree + */ static enum FallState { ACTIVE, INACTIVE, } + //the raw data from disk + FallMovementSystem fallMovementSystem; + + //current state FallState state = FallState.INACTIVE; - String animationFall = "Armature|Fall"; - String animationLand = "Armature|Land"; - + //the entity this is attached to Entity parent; + //the related jump tree JumpTree jumpTree; - public FallTree(Entity parent){ + public FallTree(Entity parent, FallMovementSystem fallMovementSystem){ this.parent = parent; + this.fallMovementSystem = fallMovementSystem; } @Override @@ -32,13 +45,13 @@ public class FallTree implements BehaviorTree { switch(state){ case ACTIVE: if(entityActor != null){ - String animationToPlay = determineCorrectAnimation(); if( - !entityActor.isPlayingAnimation() || !entityActor.isPlayingAnimation(animationToPlay) && + !entityActor.isPlayingAnimation() || !entityActor.isPlayingAnimation(fallMovementSystem.getAnimationFall().getName()) && (jumpTree == null || !jumpTree.isJumping()) ){ - entityActor.playAnimation(animationToPlay,1); + entityActor.playAnimation(fallMovementSystem.getAnimationFall().getName(),1); entityActor.incrementAnimationTime(0.0001); + FirstPersonTree.conditionallyPlayAnimation(Globals.firstPersonEntity, fallMovementSystem.getAnimationFirstPersonFall().getName()); } } break; @@ -47,55 +60,55 @@ public class FallTree implements BehaviorTree { } } + /** + * Starts the falling tree + */ public void start(){ state = FallState.ACTIVE; } + /** + * Returns the status of the fall tree + * @return true if falling, false otherwise + */ public boolean isFalling(){ return state == FallState.ACTIVE; } + /** + * Triggers the falling tree to land + */ public void land(){ if(state != FallState.INACTIVE){ state = FallState.INACTIVE; Actor entityActor = EntityUtils.getActor(parent); if(entityActor != null){ - String animationToPlay = determineCorrectAnimation(); if( - !entityActor.isPlayingAnimation() || !entityActor.isPlayingAnimation(animationToPlay) + !entityActor.isPlayingAnimation() || !entityActor.isPlayingAnimation(fallMovementSystem.getAnimationLand().getName()) ){ - entityActor.playAnimation(animationToPlay,1); + entityActor.playAnimation(fallMovementSystem.getAnimationLand().getName(),1); entityActor.incrementAnimationTime(0.0001); + FirstPersonTree.conditionallyPlayAnimation(Globals.firstPersonEntity, fallMovementSystem.getAnimationFirstPersonLand().getName()); } } } } + /** + * Gets the falling tree state of an entity + * @param parent the entity + * @return the state + */ public static FallTree getFallTree(Entity parent){ return (FallTree)parent.getData(EntityDataStrings.FALL_TREE); } - String determineCorrectAnimation(){ - switch(state){ - case ACTIVE: - return animationFall; - case INACTIVE: - return animationLand; - default: - return animationLand; - } - } - + /** + * Sets the related jump tree + * @param jumpTree the jump tree that is related to this fall tree (on the same entity) + */ public void setJumpTree(JumpTree jumpTree){ this.jumpTree = jumpTree; } - - public void setAnimationFall(String animationName){ - animationFall = animationName; - } - - public void setAnimationLand(String animationName){ - animationLand = animationName; - } } diff --git a/src/main/java/electrosphere/entity/state/movement/JumpTree.java b/src/main/java/electrosphere/entity/state/movement/JumpTree.java index 4dd1e2ef..9a82c1a1 100644 --- a/src/main/java/electrosphere/entity/state/movement/JumpTree.java +++ b/src/main/java/electrosphere/entity/state/movement/JumpTree.java @@ -7,13 +7,16 @@ import org.ode4j.ode.DBody; import electrosphere.collision.PhysicsEntityUtils; import electrosphere.collision.PhysicsUtils; import electrosphere.collision.collidable.Collidable; +import electrosphere.engine.Globals; import electrosphere.entity.Entity; import electrosphere.entity.EntityDataStrings; import electrosphere.entity.EntityUtils; import electrosphere.entity.btree.BehaviorTree; +import electrosphere.entity.state.client.firstPerson.FirstPersonTree; import electrosphere.entity.state.collidable.Impulse; import electrosphere.entity.state.gravity.GravityUtils; import electrosphere.entity.types.collision.CollisionObjUtils; +import electrosphere.game.data.creature.type.movement.JumpMovementSystem; import electrosphere.renderer.actor.Actor; public class JumpTree implements BehaviorTree { @@ -28,6 +31,8 @@ public class JumpTree implements BehaviorTree { String animationJump = "Armature|Jump"; + JumpMovementSystem jumpData; + Entity parent; int jumpFrames = 0; @@ -37,10 +42,11 @@ public class JumpTree implements BehaviorTree { static final float jumpFalloff = 0.99f; - public JumpTree(Entity parent, int jumpFrames, float jumpForce){ + public JumpTree(Entity parent, int jumpFrames, float jumpForce, JumpMovementSystem jumpData){ this.parent = parent; this.jumpFrames = jumpFrames; this.jumpForce = jumpForce; + this.jumpData = jumpData; } public void start(){ @@ -58,10 +64,10 @@ public class JumpTree implements BehaviorTree { switch(state){ case ACTIVE: if(entityActor != null){ - String animationToPlay = determineCorrectAnimation(); - if(!entityActor.isPlayingAnimation() || !entityActor.isPlayingAnimation(animationToPlay)){ - entityActor.playAnimation(animationToPlay,1); + if(!entityActor.isPlayingAnimation() || !entityActor.isPlayingAnimation(jumpData.getAnimationJump().getName())){ + entityActor.playAnimation(jumpData.getAnimationJump().getName(),1); entityActor.incrementAnimationTime(0.0001); + FirstPersonTree.conditionallyPlayAnimation(Globals.firstPersonEntity, jumpData.getAnimationFirstPersonJump().getName()); } } currentFrame++; diff --git a/src/main/java/electrosphere/entity/state/movement/groundmove/ClientGroundMovementTree.java b/src/main/java/electrosphere/entity/state/movement/groundmove/ClientGroundMovementTree.java index c6b1ee73..eaee0f01 100644 --- a/src/main/java/electrosphere/entity/state/movement/groundmove/ClientGroundMovementTree.java +++ b/src/main/java/electrosphere/entity/state/movement/groundmove/ClientGroundMovementTree.java @@ -15,6 +15,7 @@ import electrosphere.engine.Main; import electrosphere.entity.types.camera.CameraEntityUtils; import electrosphere.entity.types.collision.CollisionObjUtils; import electrosphere.entity.types.creature.CreatureUtils; +import electrosphere.game.data.creature.type.movement.GroundMovementSystem; import electrosphere.entity.ClientEntityUtils; import electrosphere.entity.Entity; import electrosphere.entity.EntityDataStrings; @@ -22,6 +23,7 @@ import electrosphere.entity.EntityUtils; import electrosphere.entity.btree.BehaviorTree; import electrosphere.entity.state.attack.ClientAttackTree; import electrosphere.entity.state.attack.ClientAttackTree.AttackTreeState; +import electrosphere.entity.state.client.firstPerson.FirstPersonTree; import electrosphere.entity.state.movement.FallTree; import electrosphere.entity.state.movement.JumpTree; import electrosphere.entity.state.movement.SprintTree; @@ -96,6 +98,8 @@ public class ClientGroundMovementTree implements BehaviorTree { SprintTree sprintTree; JumpTree jumpTree; FallTree fallTree; + + GroundMovementSystem groundMovementData; Entity parent; @@ -288,6 +292,7 @@ public class ClientGroundMovementTree implements BehaviorTree { ){ entityActor.playAnimation(animationToPlay,1); entityActor.incrementAnimationTime(0.0001); + FirstPersonTree.conditionallyPlayAnimation(Globals.firstPersonEntity, groundMovementData.getAnimationFirstPersonStartup().getName()); } } //run startup code @@ -322,6 +327,7 @@ public class ClientGroundMovementTree implements BehaviorTree { ){ entityActor.playAnimation(animationToPlay,1); entityActor.incrementAnimationTime(0.0001); + FirstPersonTree.conditionallyPlayAnimation(Globals.firstPersonEntity, groundMovementData.getAnimationFirstPersonLoop().getName()); } } if(velocity != maxNaturalVelocity){ @@ -350,6 +356,7 @@ public class ClientGroundMovementTree implements BehaviorTree { ){ entityActor.playAnimation(animationToPlay,1); entityActor.incrementAnimationTime(0.0001); + FirstPersonTree.conditionallyPlayAnimation(Globals.firstPersonEntity, groundMovementData.getAnimationFirstPersonWindDown().getName()); } } //velocity stuff @@ -665,11 +672,12 @@ public class ClientGroundMovementTree implements BehaviorTree { * @param entity The entity to attach to * @param tree The behavior tree to attach */ - public static ClientGroundMovementTree attachTree(Entity parent, Collidable collidable){ + public static ClientGroundMovementTree attachTree(Entity parent, Collidable collidable, GroundMovementSystem groundMovementData){ ClientGroundMovementTree rVal = new ClientGroundMovementTree(parent); //put manual code here (setting params, etc) rVal.collidable = collidable; + rVal.groundMovementData = groundMovementData; //!!WARNING!! from here below should not be touched //This was generated automatically to properly alert various systems that the btree exists and should be tracked diff --git a/src/main/java/electrosphere/entity/state/movement/groundmove/ServerGroundMovementTree.java b/src/main/java/electrosphere/entity/state/movement/groundmove/ServerGroundMovementTree.java index 58bd57a4..ee79f7f7 100644 --- a/src/main/java/electrosphere/entity/state/movement/groundmove/ServerGroundMovementTree.java +++ b/src/main/java/electrosphere/entity/state/movement/groundmove/ServerGroundMovementTree.java @@ -148,9 +148,14 @@ public class ServerGroundMovementTree implements BehaviorTree { } public void simulate(float deltaTime){ - float velocity = CreatureUtils.getVelocity(parent); - float acceleration = CreatureUtils.getAcceleration(parent); - float maxNaturalVelocity = sprintTree != null && sprintTree.getState() == SprintTreeState.SPRINTING ? sprintTree.getMaxVelocity() : CreatureUtils.getMaxNaturalVelocity(parent); + float velocity = 0; + float acceleration = 0; + float maxNaturalVelocity = 0; + if(CreatureUtils.hasVelocity(parent)){ + velocity = CreatureUtils.getVelocity(parent); + acceleration = CreatureUtils.getAcceleration(parent); + maxNaturalVelocity = sprintTree != null && sprintTree.getState() == SprintTreeState.SPRINTING ? sprintTree.getMaxVelocity() : CreatureUtils.getMaxNaturalVelocity(parent); + } PoseActor entityPoseActor = EntityUtils.getPoseActor(parent); // Model entityModel = Globals.assetManager.fetchModel(EntityUtils.getEntityModelPath(parent)); Vector3d position = EntityUtils.getPosition(parent); @@ -208,27 +213,6 @@ public class ServerGroundMovementTree implements BehaviorTree { case MOVEUPDATE: { if(updateTime >= lastUpdateTime){ lastUpdateTime = updateTime; - switch(message.gettreeState()){ - case 0: - state = MovementTreeState.STARTUP; - // System.out.println("Set state STARTUP"); - GravityUtils.serverAttemptActivateGravity(parent); - break; - case 1: - state = MovementTreeState.MOVE; - // System.out.println("Set state MOVE"); - GravityUtils.serverAttemptActivateGravity(parent); - break; - case 2: - state = MovementTreeState.SLOWDOWN; - // System.out.println("Set state SLOWDOWN"); - GravityUtils.serverAttemptActivateGravity(parent); - break; - case 3: - state = MovementTreeState.IDLE; - // System.out.println("Set state IDLE"); - break; - } //we want to always update the server facing vector with where the client says they're facing EntityUtils.getRotation(parent).set(message.getrotationX(),message.getrotationY(),message.getrotationZ(),message.getrotationW()); CreatureUtils.setFacingVector(parent, new Vector3d(0,0,1).rotate(EntityUtils.getRotation(parent))); diff --git a/src/main/java/electrosphere/entity/types/attach/AttachUtils.java b/src/main/java/electrosphere/entity/types/attach/AttachUtils.java index e35ff6d0..8c2fe0fa 100644 --- a/src/main/java/electrosphere/entity/types/attach/AttachUtils.java +++ b/src/main/java/electrosphere/entity/types/attach/AttachUtils.java @@ -24,8 +24,7 @@ import org.joml.Vector3f; import org.joml.Vector4d; /** - * - * @author amaterasu + * Utilities for attaching entities to entities */ public class AttachUtils { @@ -110,6 +109,9 @@ public class AttachUtils { // Quaternionf rotation = parentActor.getBoneRotation(targetBone); // EntityUtils.getRotation(currentEntity).set(rotation).normalize(); Vector3d facingAngle = CreatureUtils.getFacingVector(parent); + if(facingAngle == null){ + facingAngle = new Vector3d(0,0,1); + } //calculate rotation of model EntityUtils.getRotation(currentEntity) .rotationTo(new Vector3d(0,0,1), new Vector3d(facingAngle.x,facingAngle.y,facingAngle.z)) diff --git a/src/main/java/electrosphere/entity/types/camera/CameraEntityUtils.java b/src/main/java/electrosphere/entity/types/camera/CameraEntityUtils.java index 8d273f94..9a54b85d 100644 --- a/src/main/java/electrosphere/entity/types/camera/CameraEntityUtils.java +++ b/src/main/java/electrosphere/entity/types/camera/CameraEntityUtils.java @@ -158,6 +158,26 @@ public class CameraEntityUtils { public static float getCameraYaw(Entity camera){ return (float)camera.getData(EntityDataStrings.CAMERA_YAW); } + + /** + * Gets the quaternion containing the camera pitch + * @param camera + * @return + */ + public static Quaternionf getPitchQuat(Entity camera){ + Quaternionf pitchQuat = new Quaternionf().fromAxisAngleDeg(new Vector3f(1,0,0), -getCameraPitch(camera)); + return pitchQuat; + } + + /** + * Gets the quaternion containing the camera yaw + * @param camera + * @return + */ + public static Quaternionf getYawQuat(Entity camera){ + Quaternionf yawQuat = new Quaternionf().fromAxisAngleDeg(new Vector3f(0,1,0), -getCameraYaw(camera)); + return yawQuat; + } public static void destroyCameraEntity(Entity e){ if(e != null){ diff --git a/src/main/java/electrosphere/entity/types/creature/CreatureUtils.java b/src/main/java/electrosphere/entity/types/creature/CreatureUtils.java index 8e56b3a5..4292fe6e 100644 --- a/src/main/java/electrosphere/entity/types/creature/CreatureUtils.java +++ b/src/main/java/electrosphere/entity/types/creature/CreatureUtils.java @@ -101,6 +101,8 @@ public class CreatureUtils { Entity rVal = EntityCreationUtils.createClientSpatialEntity(); EntityCreationUtils.makeEntityDrawable(rVal, rawType.getModelPath()); Actor creatureActor = EntityUtils.getActor(rVal); + EntityUtils.setEntityType(rVal, ENTITY_TYPE_CREATURE); + EntityUtils.setEntitySubtype(rVal, type); for(HitboxData hitboxdata : rawType.getHitboxes()){ List hitboxList = new LinkedList(); List hurtboxList = new LinkedList(); @@ -132,7 +134,7 @@ public class CreatureUtils { // Generic ground case GroundMovementSystem.GROUND_MOVEMENT_SYSTEM: GroundMovementSystem groundMovementSystem = (GroundMovementSystem)movementSystem; - ClientGroundMovementTree moveTree = ClientGroundMovementTree.attachTree(rVal, CollisionObjUtils.getCollidable(rVal)); + ClientGroundMovementTree moveTree = ClientGroundMovementTree.attachTree(rVal, CollisionObjUtils.getCollidable(rVal), groundMovementSystem); if(groundMovementSystem.getAnimationStartup() != null){ moveTree.setAnimationStartUp(groundMovementSystem.getAnimationStartup().getName()); } @@ -174,7 +176,7 @@ public class CreatureUtils { // Jump case JumpMovementSystem.JUMP_MOVEMENT_SYSTEM: JumpMovementSystem jumpMovementSystem = (JumpMovementSystem)movementSystem; - JumpTree jumpTree = new JumpTree(rVal, jumpMovementSystem.getJumpFrames(), jumpMovementSystem.getJumpForce()); + JumpTree jumpTree = new JumpTree(rVal, jumpMovementSystem.getJumpFrames(), jumpMovementSystem.getJumpForce(), jumpMovementSystem); if(jumpMovementSystem.getAnimationJump() != null){ jumpTree.setAnimationJump(jumpMovementSystem.getAnimationJump().getName()); } @@ -191,13 +193,7 @@ public class CreatureUtils { // Falling case FallMovementSystem.FALL_MOVEMENT_SYSTEM: FallMovementSystem fallMovementSystem = (FallMovementSystem)movementSystem; - FallTree fallTree = new FallTree(rVal); - if(fallMovementSystem.getAnimationFall()!=null){ - fallTree.setAnimationFall(fallMovementSystem.getAnimationFall().getName()); - } - if(fallMovementSystem.getAnimationLand()!=null){ - fallTree.setAnimationLand(fallMovementSystem.getAnimationLand().getName()); - } + FallTree fallTree = new FallTree(rVal, fallMovementSystem); if(CreatureUtils.clientGetEntityMovementTree(rVal) != null && CreatureUtils.clientGetEntityMovementTree(rVal) instanceof ClientGroundMovementTree){ ((ClientGroundMovementTree)CreatureUtils.clientGetEntityMovementTree(rVal)).setClientFallTree(fallTree); } @@ -374,8 +370,6 @@ public class CreatureUtils { rVal.putData(EntityDataStrings.TREE_IDLE, idleTree); Globals.clientScene.registerBehaviorTree(idleTree); Globals.clientScene.registerEntityToTag(rVal, EntityTags.CREATURE); - EntityUtils.setEntityType(rVal, ENTITY_TYPE_CREATURE); - EntityUtils.setEntitySubtype(rVal, type); CreatureUtils.setFacingVector(rVal, new Vector3d(0,0,1)); rVal.putData(EntityDataStrings.DRAW_CAST_SHADOW, true); return rVal; @@ -717,6 +711,10 @@ public class CreatureUtils { public static void setAcceleration(Entity e, float scalar){ e.putData(EntityDataStrings.DATA_STRING_ACCELERATION, scalar); } + + public static boolean hasVelocity(Entity e){ + return e.containsKey(EntityDataStrings.DATA_STRING_VELOCITY); + } public static float getVelocity(Entity e){ return (float)e.getData(EntityDataStrings.DATA_STRING_VELOCITY); diff --git a/src/main/java/electrosphere/entity/types/foliage/FoliageUtils.java b/src/main/java/electrosphere/entity/types/foliage/FoliageUtils.java index 1d70e93c..0fe0cea1 100644 --- a/src/main/java/electrosphere/entity/types/foliage/FoliageUtils.java +++ b/src/main/java/electrosphere/entity/types/foliage/FoliageUtils.java @@ -11,7 +11,7 @@ import electrosphere.entity.EntityDataStrings; import electrosphere.entity.EntityTags; import electrosphere.entity.EntityUtils; import electrosphere.entity.ServerEntityUtils; -import electrosphere.entity.state.ambientaudio.ClientAmbientAudioTree; +import electrosphere.entity.state.client.ambientaudio.ClientAmbientAudioTree; import electrosphere.entity.state.idle.IdleTree; import electrosphere.entity.types.collision.CollisionObjUtils; import electrosphere.entity.types.tree.ProceduralTree; diff --git a/src/main/java/electrosphere/game/data/creature/type/CreatureType.java b/src/main/java/electrosphere/game/data/creature/type/CreatureType.java index d14d2bb6..06820377 100644 --- a/src/main/java/electrosphere/game/data/creature/type/CreatureType.java +++ b/src/main/java/electrosphere/game/data/creature/type/CreatureType.java @@ -11,6 +11,9 @@ import electrosphere.game.data.creature.type.visualattribute.VisualAttribute; import java.util.List; +/** + * A given type of creature + */ public class CreatureType { String creatureId; List hitboxes; @@ -24,6 +27,8 @@ public class CreatureType { HealthSystem healthSystem; LookAtSystem lookAtSystem; String modelPath; + ViewModelData viewModelData; + IdleData idleData; AttackMoveResolver attackMoveResolver; @@ -82,6 +87,14 @@ public class CreatureType { public AttackMoveResolver getAttackMoveResolver(){ return attackMoveResolver; } + + public ViewModelData getViewModelData(){ + return viewModelData; + } + + public IdleData getIdleData(){ + return idleData; + } } diff --git a/src/main/java/electrosphere/game/data/creature/type/IdleData.java b/src/main/java/electrosphere/game/data/creature/type/IdleData.java new file mode 100644 index 00000000..caec317a --- /dev/null +++ b/src/main/java/electrosphere/game/data/creature/type/IdleData.java @@ -0,0 +1,30 @@ +package electrosphere.game.data.creature.type; + +/** + * Data about how the creature will behave when in idle state + */ +public class IdleData { + + //the animation that plays when the creature is idle + String idleAnimation; + + //the animation that plays when the creature idles in first person + String firstPersonIdleAnimation; + + /** + * the animation that plays when the creature is idle + * @return + */ + public String getIdleAnimation(){ + return idleAnimation; + } + + /** + * the animation that plays when the creature idles in first person + * @return + */ + public String getFirstPersonIdleAnimation(){ + return firstPersonIdleAnimation; + } + +} diff --git a/src/main/java/electrosphere/game/data/creature/type/ViewModelData.java b/src/main/java/electrosphere/game/data/creature/type/ViewModelData.java new file mode 100644 index 00000000..164979dd --- /dev/null +++ b/src/main/java/electrosphere/game/data/creature/type/ViewModelData.java @@ -0,0 +1,54 @@ +package electrosphere.game.data.creature.type; + +/** + * Data about the first person view model for this creature type + */ +public class ViewModelData { + + //How far from the origin of the creature to place the viewmodel + double heightFromOrigin; + + //How far to pull the view model below the camera + double cameraViewDirOffsetY; + + //How far to pull the view model behind the camera + double cameraViewDirOffsetZ; + + //the actual model + String firstPersonModelPath; + + + /** + * How far from the origin of the creature to place the viewmodel + * @return + */ + public double getHeightFromOrigin(){ + return heightFromOrigin; + } + + /** + * How far to pull the view model below the camera + * @return + */ + public double getCameraViewDirOffsetY(){ + return cameraViewDirOffsetY; + } + + /** + * How far to pull the view model behind the camera + * @return + */ + public double getCameraViewDirOffsetZ(){ + return cameraViewDirOffsetZ; + } + + /** + * the actual model + * @return + */ + public String getFirstPersonModelPath(){ + return firstPersonModelPath; + } + + +} diff --git a/src/main/java/electrosphere/game/data/creature/type/attack/AttackMove.java b/src/main/java/electrosphere/game/data/creature/type/attack/AttackMove.java index 57a95377..db02674f 100644 --- a/src/main/java/electrosphere/game/data/creature/type/attack/AttackMove.java +++ b/src/main/java/electrosphere/game/data/creature/type/attack/AttackMove.java @@ -1,15 +1,14 @@ package electrosphere.game.data.creature.type.attack; -import java.util.List; +import electrosphere.game.data.creature.type.Animation; /** - * - * @author amaterasu + * Data about a single attack move this creature is capable of */ public class AttackMove { /* - + Base data */ String attackMoveId; String type; @@ -21,6 +20,10 @@ public class AttackMove { String holdAnimationName; String attackAnimationName; + Animation animationFirstPersonWindup; + Animation animationFirstPersonHold; + Animation animationFirstPersonAttack; + /* Damage stuff */ @@ -45,66 +48,154 @@ public class AttackMove { int driftFrameStart; //when do we start drifting int driftFrameEnd; //when do we stop drifting + /** + * Gets the id of the attack move + * @return the id of the attack move + */ public String getAttackMoveId(){ return attackMoveId; } + /** + * Gets the type of attack move + * @return the attack move type + */ public String getType() { return type; } + /** + * Gets the name of the animation to play in 3rd person for the windup + * @return the animation name + */ public String getWindupAnimationName() { return windupAnimationName; } + /** + * Gets the name of the animation to play in 3rd person for the hold + * @return the animation name + */ public String getHoldAnimationName() { return holdAnimationName; } + /** + * Gets the name of the animation to play in 3rd person for the attack + * @return the animation name + */ public String getAttackAnimationName() { return attackAnimationName; } + /** + * Gets the animation data for the 1st person windup + * @return the animation data + */ + public Animation getAnimationFirstPersonWindup(){ + return animationFirstPersonWindup; + } + + /** + * Gets the animation data for the 1st person hold + * @return the animation data + */ + public Animation getAnimationFirstPersonHold(){ + return animationFirstPersonHold; + } + + /** + * Gets the animation data for the 1st person attack + * @return the animation data + */ + public Animation getAnimationFirstPersonAttack(){ + return animationFirstPersonAttack; + } + + /** + * Gets the number of frames to windup for + * @return the number of frames + */ public int getWindupFrames() { return windupFrames; } + /** + * Gets the number of frames to attack for + * @return the number of frames + */ public int getAttackFrames() { return attackFrames; } + /** + * Gets the number of frames to cooldown for + * @return the number of frames + */ public int getCooldownFrames(){ return cooldownFrames; } + /** + * Gets the id of the next attack move + * @return the id of the next attack move + */ public String getNextMoveId() { return nextMoveId; } + /** + * Gets the frame number where the window to chain the next attack starts + * @return the frame number + */ public int getMoveChainWindowStart(){ return moveChainWindowStart; } + /** + * Gets the frame number where the window to chain the next attack ends + * @return the frame number + */ public int getMoveChainWindowEnd(){ return moveChainWindowEnd; } + /** + * Gets the amount we want the animation to push the creature forward + * @return the amount to push forward + */ public float getDriftGoal(){ return driftGoal; } + /** + * Gets the frame number where the drift starts + * @return the frame number + */ public int getDriftFrameStart(){ return driftFrameStart; } + /** + * Gets the frame number where the drift starts + * @return the frame number + */ public int getDriftFrameEnd(){ return driftFrameEnd; } + /** + * Returns if the move is the initial move in the attack chain + * @return true if the initial move, false otherwise + */ public boolean isInitialMove(){ return initialMove; } + /** + * Returns if it fires a projectile + * @return true if it fires a projectile, false otherwise + */ public boolean getFiresProjectile(){ return firesProjectile; } diff --git a/src/main/java/electrosphere/game/data/creature/type/equip/EquipPoint.java b/src/main/java/electrosphere/game/data/creature/type/equip/EquipPoint.java index 34ab1d7a..928daf7e 100644 --- a/src/main/java/electrosphere/game/data/creature/type/equip/EquipPoint.java +++ b/src/main/java/electrosphere/game/data/creature/type/equip/EquipPoint.java @@ -2,30 +2,68 @@ package electrosphere.game.data.creature.type.equip; import java.util.List; +/** + * A portion of the creature that can have an item attached to it + */ public class EquipPoint { + //the id of the equip point String equipPointId; + //the bone that can have the item attached to it (may not be defined depending on the type of equip point (think legs)) String bone; + //the bone to attach items to for the first person viewmodel (may not be defined based on the viewmodel) + String firstPersonBone; + //the offset to apply to items that are attached to the bone List offsetVector; + //the rotation to apply to the items that are attached to the bone List offsetRotation; + //the equip classes that are whitelisted for this equip point List equipClassWhitelist; + /** + * Gets the equip point id + * @return the id of the equip point + */ public String getEquipPointId(){ return equipPointId; } + /** + * Gets the bone that can have the item attached to it (may not be defined depending on the type of equip point (think legs)) + * @return the bone + */ public String getBone(){ return bone; } + /** + * Gets the bone to attach items to for the first person viewmodel (may not be defined based on the viewmodel) + * @return the bone + */ + public String getFirstPersonBone(){ + return firstPersonBone; + } + + /** + * Gets the offset to apply to items that are attached to the bone + * @return the offset + */ public List getOffsetVector(){ return offsetVector; } + /** + * Gets the rotation to apply to the items that are attached to the bone + * @return the rotation + */ public List getOffsetRotation(){ return offsetRotation; } + /** + * Gets the equip classes that are whitelisted for this equip point + * @return the classes + */ public List getEquipClassWhitelist(){ return equipClassWhitelist; } diff --git a/src/main/java/electrosphere/game/data/creature/type/movement/FallMovementSystem.java b/src/main/java/electrosphere/game/data/creature/type/movement/FallMovementSystem.java index 875bc561..2e6b86fc 100644 --- a/src/main/java/electrosphere/game/data/creature/type/movement/FallMovementSystem.java +++ b/src/main/java/electrosphere/game/data/creature/type/movement/FallMovementSystem.java @@ -2,23 +2,55 @@ package electrosphere.game.data.creature.type.movement; import electrosphere.game.data.creature.type.Animation; +/** + * Data about a falling movement system + */ public class FallMovementSystem implements MovementSystem { public static final String FALL_MOVEMENT_SYSTEM = "FALL"; String type; + //Fall data Animation animationFall; - Animation animationLand; + Animation animationFirstPersonFall; + //landing data + Animation animationLand; + Animation animationFirstPersonLand; + + /** + * Gets the animation to play in 3rd person when the creature is falling + * @return the animation data + */ public Animation getAnimationFall(){ return animationFall; } + /** + * Gets the animation to play in 1st person when the creature is falling + * @return the animation data + */ + public Animation getAnimationFirstPersonFall(){ + return animationFirstPersonFall; + } + + /** + * Gets the animation to play in 3rd person when the creature is landing + * @return the animation data + */ public Animation getAnimationLand(){ return animationLand; } + /** + * Gets the animation to play in 1st person when the creature is landing + * @return the animation data + */ + public Animation getAnimationFirstPersonLand(){ + return animationFirstPersonLand; + } + @Override public String getType() { return type; diff --git a/src/main/java/electrosphere/game/data/creature/type/movement/GroundMovementSystem.java b/src/main/java/electrosphere/game/data/creature/type/movement/GroundMovementSystem.java index 52df3a88..a6e7cbdb 100644 --- a/src/main/java/electrosphere/game/data/creature/type/movement/GroundMovementSystem.java +++ b/src/main/java/electrosphere/game/data/creature/type/movement/GroundMovementSystem.java @@ -3,40 +3,105 @@ package electrosphere.game.data.creature.type.movement; import electrosphere.game.data.creature.type.Animation; import electrosphere.game.data.creature.type.SprintSystem; +/** + * A ground movement system's data + */ public class GroundMovementSystem implements MovementSystem { + //move system type string public static final String GROUND_MOVEMENT_SYSTEM = "GROUND"; + //type of move system String type; + //core physics numbers float acceleration; float maxVelocity; + + //startup data Animation animationStartup; + Animation animationFirstPersonStartup; + + //loop data Animation animationLoop; + Animation animationFirstPersonLoop; + + //wind down data Animation animationWindDown; + Animation animationFirstPersonWindDown; + + //sprint data SprintSystem sprintSystem; + /** + * Gets the acceleration factor for this creature + * @return the acceleration factor + */ public float getAcceleration() { return acceleration; } + /** + * Gets the maximum velocity the creature can move at with this system + * @return the max velocity + */ public float getMaxVelocity() { return maxVelocity; } + /** + * Gets the animation to play in 3rd person for startup + * @return The animation data + */ public Animation getAnimationStartup() { return animationStartup; } + /** + * Gets the animation to play in 1st person for startup + * @return The animation data + */ + public Animation getAnimationFirstPersonStartup(){ + return animationFirstPersonStartup; + } + + /** + * Gets the animation to loop in 3rd person + * @return The animation data + */ public Animation getAnimationLoop() { return animationLoop; } + /** + * Gets the animation to loop in 1st person + * @return The animation data + */ + public Animation getAnimationFirstPersonLoop(){ + return animationFirstPersonLoop; + } + + /** + * Gets the animation to play in 3rd person to wind down + * @return The animation data + */ public Animation getAnimationWindDown() { return animationWindDown; } + /** + * Gets the animation to play in 1st person to wind down + * @return The animation data + */ + public Animation getAnimationFirstPersonWindDown(){ + return animationFirstPersonWindDown; + } + + /** + * Gets the sprint system data + * @return The sprint system data + */ public SprintSystem getSprintSystem() { return sprintSystem; } diff --git a/src/main/java/electrosphere/game/data/creature/type/movement/JumpMovementSystem.java b/src/main/java/electrosphere/game/data/creature/type/movement/JumpMovementSystem.java index 6bdd93a8..601f9c82 100644 --- a/src/main/java/electrosphere/game/data/creature/type/movement/JumpMovementSystem.java +++ b/src/main/java/electrosphere/game/data/creature/type/movement/JumpMovementSystem.java @@ -9,7 +9,8 @@ public class JumpMovementSystem implements MovementSystem { String type; Animation animationJump; - + Animation animationFirstPersonJump; + int jumpFrames; float jumpForce; @@ -25,6 +26,10 @@ public class JumpMovementSystem implements MovementSystem { return animationJump; } + public Animation getAnimationFirstPersonJump(){ + return animationFirstPersonJump; + } + @Override public String getType() { return type; diff --git a/src/main/java/electrosphere/game/data/foliage/type/TreeModel.java b/src/main/java/electrosphere/game/data/foliage/type/TreeModel.java index e3216f0c..38faf8d2 100644 --- a/src/main/java/electrosphere/game/data/foliage/type/TreeModel.java +++ b/src/main/java/electrosphere/game/data/foliage/type/TreeModel.java @@ -99,6 +99,12 @@ public class TreeModel { //The maximum scalar of a branch to generate a sway behavior tree float maximumScalarToGenerateSwayTree; + //The model for the trunk of the tree + String trunkModelPath; + + //the model for a leaf blob + String leafModelPath; + /** * how quickly do the limbs shrink * @return @@ -332,4 +338,20 @@ public class TreeModel { return this.physicsBody; } + /** + * The model for the trunk of the tree + * @return + */ + public String getTrunkModelPath(){ + return trunkModelPath; + } + + /** + * the model for a leaf blob + * @return + */ + public String getLeafModelPath(){ + return leafModelPath; + } + } diff --git a/src/main/java/electrosphere/logger/LoggerInterface.java b/src/main/java/electrosphere/logger/LoggerInterface.java index 2ebb3cf4..a57827cc 100644 --- a/src/main/java/electrosphere/logger/LoggerInterface.java +++ b/src/main/java/electrosphere/logger/LoggerInterface.java @@ -26,7 +26,7 @@ public class LoggerInterface { */ public static void initLoggers(){ loggerStartup = new Logger(LogLevel.WARNING); - loggerNetworking = new Logger(LogLevel.DEBUG); + loggerNetworking = new Logger(LogLevel.WARNING); loggerFileIO = new Logger(LogLevel.WARNING); loggerGameLogic = new Logger(LogLevel.WARNING); loggerRenderer = new Logger(LogLevel.WARNING); diff --git a/src/main/java/electrosphere/net/client/protocol/EntityProtocol.java b/src/main/java/electrosphere/net/client/protocol/EntityProtocol.java index e4efb82e..a75fa5d9 100644 --- a/src/main/java/electrosphere/net/client/protocol/EntityProtocol.java +++ b/src/main/java/electrosphere/net/client/protocol/EntityProtocol.java @@ -6,15 +6,20 @@ import org.joml.Vector3d; import electrosphere.engine.Globals; import electrosphere.entity.ClientEntityUtils; import electrosphere.entity.Entity; +import electrosphere.entity.EntityCreationUtils; import electrosphere.entity.EntityDataStrings; +import electrosphere.entity.EntityTags; import electrosphere.entity.EntityUtils; import electrosphere.entity.state.attack.ClientAttackTree; import electrosphere.entity.state.attack.ServerAttackTree; +import electrosphere.entity.state.client.firstPerson.FirstPersonTree; import electrosphere.entity.types.attach.AttachUtils; import electrosphere.entity.types.creature.CreatureTemplate; import electrosphere.entity.types.creature.CreatureUtils; import electrosphere.entity.types.foliage.FoliageUtils; import electrosphere.entity.types.item.ItemUtils; +import electrosphere.game.data.creature.type.CreatureType; +import electrosphere.game.data.creature.type.ViewModelData; import electrosphere.logger.LoggerInterface; import electrosphere.net.parser.net.message.EntityMessage; import electrosphere.util.Utilities; @@ -101,19 +106,7 @@ public class EntityProtocol { case SETPROPERTY: { if(Globals.clientSceneWrapper.serverToClientMapContainsId(message.getentityID())){ if(message.getpropertyType() == 0){ - Entity target = Globals.clientSceneWrapper.getEntityFromServerId(message.getentityID()); - if(target != null){ - CreatureUtils.setControllerPlayerId(target, message.getpropertyValue()); - if(Globals.clientPlayer != null && message.getpropertyValue() == Globals.clientPlayer.getId()){ - Globals.clientCharacterID = message.getentityID(); - Globals.playerEntity = target; - if(Globals.controlHandler.cameraIsThirdPerson()){ - Globals.playerEntity.putData(EntityDataStrings.DATA_STRING_DRAW, true); - } else { - Globals.playerEntity.putData(EntityDataStrings.DATA_STRING_DRAW, false); - } - } - } + setPlayerEntity(message); } } else { //TODO: bounce message @@ -168,4 +161,33 @@ public class EntityProtocol { Globals.profiler.endCpuSample(); } + /** + * Sets the player's entity + * @param message the network message to parse + */ + static void setPlayerEntity(EntityMessage message){ + Entity target = Globals.clientSceneWrapper.getEntityFromServerId(message.getentityID()); + if(target != null){ + CreatureUtils.setControllerPlayerId(target, message.getpropertyValue()); + String creatureTypeRaw = CreatureUtils.getType(target); + CreatureType creatureType = Globals.gameConfigCurrent.getCreatureTypeLoader().getCreature(creatureTypeRaw); + ViewModelData viewModelData = creatureType.getViewModelData(); + if(Globals.clientPlayer != null && message.getpropertyValue() == Globals.clientPlayer.getId()){ + Globals.clientCharacterID = message.getentityID(); + Globals.playerEntity = target; + if(Globals.controlHandler.cameraIsThirdPerson()){ + Globals.playerEntity.putData(EntityDataStrings.DATA_STRING_DRAW, true); + } else { + Globals.playerEntity.putData(EntityDataStrings.DATA_STRING_DRAW, false); + if(viewModelData != null && viewModelData.getFirstPersonModelPath() != null){ + Globals.firstPersonEntity = EntityCreationUtils.createClientSpatialEntity(); + EntityCreationUtils.makeEntityDrawable(Globals.firstPersonEntity, viewModelData.getFirstPersonModelPath()); + FirstPersonTree.attachTree(Globals.firstPersonEntity, viewModelData.getHeightFromOrigin(), viewModelData.getCameraViewDirOffsetY(), viewModelData.getCameraViewDirOffsetZ()); + Globals.clientSceneWrapper.getScene().removeEntityFromTag(Globals.firstPersonEntity,EntityTags.DRAWABLE); + } + } + } + } + } + } diff --git a/src/main/java/electrosphere/renderer/RenderingEngine.java b/src/main/java/electrosphere/renderer/RenderingEngine.java index ddf14ce0..5848422c 100644 --- a/src/main/java/electrosphere/renderer/RenderingEngine.java +++ b/src/main/java/electrosphere/renderer/RenderingEngine.java @@ -103,6 +103,7 @@ import electrosphere.renderer.light.LightManager; import electrosphere.renderer.model.Model; import electrosphere.renderer.pipelines.CompositePipeline; import electrosphere.renderer.pipelines.DebugContentPipeline; +import electrosphere.renderer.pipelines.FirstPersonItemsPipeline; import electrosphere.renderer.pipelines.MainContentNoOITPipeline; import electrosphere.renderer.pipelines.MainContentPipeline; import electrosphere.renderer.pipelines.NormalsForOutlinePipeline; @@ -244,6 +245,7 @@ public class RenderingEngine { MainContentPipeline mainContentPipeline = new MainContentPipeline(); MainContentNoOITPipeline mainContentNoOITPipeline = new MainContentNoOITPipeline(); DebugContentPipeline debugContentPipeline = new DebugContentPipeline(); + FirstPersonItemsPipeline firstPersonItemsPipeline = new FirstPersonItemsPipeline(); ShadowMapPipeline shadowMapPipeline = new ShadowMapPipeline(); VolumeBufferPipeline volumeBufferPipeline = new VolumeBufferPipeline(); NormalsForOutlinePipeline normalsForOutlinePipeline = new NormalsForOutlinePipeline(); @@ -448,6 +450,12 @@ public class RenderingEngine { // fogColor.put(1.0f); // fogColor.flip(); // GL11.glFogfv(GL_FOG_COLOR, fogColor); + + // + //Init pipelines + // + firstPersonItemsPipeline.init(); + compositePipeline.setFirstPersonPipeline(firstPersonItemsPipeline); // // Projection and View matrix creation @@ -496,6 +504,7 @@ public class RenderingEngine { } debugContentPipeline.render(openGLState, renderPipelineState); normalsForOutlinePipeline.render(openGLState, renderPipelineState); + firstPersonItemsPipeline.render(openGLState, renderPipelineState); postProcessingPipeline.render(openGLState, renderPipelineState); compositePipeline.render(openGLState, renderPipelineState); } diff --git a/src/main/java/electrosphere/renderer/actor/Actor.java b/src/main/java/electrosphere/renderer/actor/Actor.java index 2abc7ab1..7594bd82 100644 --- a/src/main/java/electrosphere/renderer/actor/Actor.java +++ b/src/main/java/electrosphere/renderer/actor/Actor.java @@ -336,14 +336,31 @@ public class Actor { return meshMask; } + /** + * Masks a shader with another shader + * @param mesh The mesh to apply the mask on + * @param vertexShader the vertex shader to apply + * @param fragmentShader the fragment shader to apply + */ public void maskShader(String mesh, String vertexShader, String fragmentShader){ shaderMasks.add(new ActorShaderMask(this.modelPath, mesh, vertexShader, null, fragmentShader)); } + /** + * Masks a shader with another shader + * @param mesh the mesh to apply the mask on + * @param vertexShader the vertex shader to apply + * @param geometryShader the geometry shader to apply + * @param fragmentShader the fragment shader to apply + */ public void maskShader(String mesh, String vertexShader, String geometryShader, String fragmentShader){ shaderMasks.add(new ActorShaderMask(this.modelPath, mesh, vertexShader, geometryShader, fragmentShader)); } + /** + * Unmasks a shader + * @param mesh the mesh to unmask + */ public void unmaskShader(String mesh){ throw new UnsupportedOperationException("Not implemented yet"); } diff --git a/src/main/java/electrosphere/renderer/actor/ActorShaderMask.java b/src/main/java/electrosphere/renderer/actor/ActorShaderMask.java index 26eec461..41bb9d8b 100644 --- a/src/main/java/electrosphere/renderer/actor/ActorShaderMask.java +++ b/src/main/java/electrosphere/renderer/actor/ActorShaderMask.java @@ -1,13 +1,29 @@ package electrosphere.renderer.actor; +/** + * Masks a shader on a mesh with another shader + */ public class ActorShaderMask { + //the model name String modelName; + //the mesh name String meshName; + //the vertex shader String vertexShaderPath; + //the geometry shader String geometryShaderPath; + //the fragment shader String fragmentShaderPath; + /** + * Constructor + * @param modelName + * @param meshName + * @param vertexShaderPath + * @param geometryShaderPath + * @param fragmentShaderPath + */ public ActorShaderMask(String modelName, String meshName, String vertexShaderPath, String geometryShaderPath, String fragmentShaderPath){ this.modelName = modelName; this.meshName = meshName; @@ -16,22 +32,42 @@ public class ActorShaderMask { this.fragmentShaderPath = fragmentShaderPath; } + /** + * Gets the model name + * @return the model name + */ public String getModelName(){ return modelName; } + /** + * Gets the mesh name + * @return the mesh name + */ public String getMeshName(){ return meshName; } + /** + * Gets the vertex shader path + * @return the vertex shader path + */ public String getVertexShaderPath(){ return vertexShaderPath; } + /** + * Gets the geometry shader path + * @return the geometry shader path + */ public String getGeometryShaderPath(){ return geometryShaderPath; } + /** + * Gets the fragment shader path + * @return the fragment shader path + */ public String getFragmentShaderPath(){ return fragmentShaderPath; } diff --git a/src/main/java/electrosphere/renderer/framebuffer/FramebufferUtils.java b/src/main/java/electrosphere/renderer/framebuffer/FramebufferUtils.java index 3cd3f55c..ebb3363d 100644 --- a/src/main/java/electrosphere/renderer/framebuffer/FramebufferUtils.java +++ b/src/main/java/electrosphere/renderer/framebuffer/FramebufferUtils.java @@ -58,8 +58,7 @@ import static org.lwjgl.opengl.GL30.glRenderbufferStorage; import static org.lwjgl.system.MemoryUtil.NULL; /** - * - * @author amaterasu + * Utilities for framebuffer creation */ public class FramebufferUtils { diff --git a/src/main/java/electrosphere/renderer/model/Model.java b/src/main/java/electrosphere/renderer/model/Model.java index deaa882c..8a7e50a1 100644 --- a/src/main/java/electrosphere/renderer/model/Model.java +++ b/src/main/java/electrosphere/renderer/model/Model.java @@ -436,17 +436,17 @@ public class Model { * Describes the model at a high level */ public void describeHighLevel(){ - LoggerInterface.loggerRenderer.DEBUG("Meshes: "); + LoggerInterface.loggerRenderer.WARNING("Meshes: "); for(Mesh mesh : meshes){ - LoggerInterface.loggerRenderer.DEBUG(mesh.getMeshName()); + LoggerInterface.loggerRenderer.WARNING(mesh.getMeshName()); } - LoggerInterface.loggerRenderer.DEBUG("Animations: "); + LoggerInterface.loggerRenderer.WARNING("Animations: "); for(Animation anim : animations){ - LoggerInterface.loggerRenderer.DEBUG(anim.name); + LoggerInterface.loggerRenderer.WARNING(anim.name); } - LoggerInterface.loggerRenderer.DEBUG("Bones:"); + LoggerInterface.loggerRenderer.WARNING("Bones:"); for(Bone bone : bones){ - LoggerInterface.loggerRenderer.DEBUG(bone.boneID); + LoggerInterface.loggerRenderer.WARNING(bone.boneID); } } diff --git a/src/main/java/electrosphere/renderer/pipelines/CompositePipeline.java b/src/main/java/electrosphere/renderer/pipelines/CompositePipeline.java index 49b70814..f67fec38 100644 --- a/src/main/java/electrosphere/renderer/pipelines/CompositePipeline.java +++ b/src/main/java/electrosphere/renderer/pipelines/CompositePipeline.java @@ -9,6 +9,9 @@ import electrosphere.renderer.RenderingEngine; public class CompositePipeline implements RenderPipeline { + //the pipeline for the first person render items + FirstPersonItemsPipeline firstPersonItemsPipeline; + @Override public void render(OpenGLState openGLState, RenderPipelineState renderPipelineState) { Globals.profiler.beginCpuSample("CompositePipeline.render"); @@ -60,12 +63,55 @@ public class CompositePipeline implements RenderPipeline { openGLState.glBindTexture(GL40.GL_TEXTURE_2D, RenderingEngine.transparencyAccumulatorTexture.getTexturePointer()); openGLState.glActiveTexture(GL40.GL_TEXTURE1); openGLState.glBindTexture(GL40.GL_TEXTURE_2D, RenderingEngine.transparencyRevealageTexture.getTexturePointer()); + openGLState.glActiveTexture(GL40.GL_TEXTURE2); + openGLState.glBindTexture(GL40.GL_TEXTURE_2D, firstPersonItemsPipeline.getFramebuffer().getTexturePointer()); GL40.glDrawArrays(GL40.GL_TRIANGLES, 0, 6); + + + + + + // + //Draw the first person texture on top of the other textures + // + openGLState.setActiveShader(renderPipelineState, RenderingEngine.screenTextureShaders); + + openGLState.glActiveTexture(GL40.GL_TEXTURE0); + openGLState.glBindTexture(GL40.GL_TEXTURE_2D, 0); + openGLState.glActiveTexture(GL40.GL_TEXTURE1); + openGLState.glBindTexture(GL40.GL_TEXTURE_2D, 0); + openGLState.glActiveTexture(GL40.GL_TEXTURE2); + openGLState.glBindTexture(GL40.GL_TEXTURE_2D, 0); + openGLState.glActiveTexture(GL40.GL_TEXTURE3); + openGLState.glBindTexture(GL40.GL_TEXTURE_2D, 0); + openGLState.glActiveTexture(GL40.GL_TEXTURE0); + openGLState.glBindTexture(GL40.GL_TEXTURE_2D, firstPersonItemsPipeline.getFramebuffer().getTexturePointer()); + openGLState.glActiveTexture(GL40.GL_TEXTURE1); + + GL40.glDrawArrays(GL40.GL_TRIANGLES, 0, 6); + + + + + + + + // + //Close down pipeline + // GL40.glBindVertexArray(0); Globals.profiler.endCpuSample(); } + + /** + * Get the first person pipeline + * @param firstPersonItemsPipeline the first person pipeline + */ + public void setFirstPersonPipeline(FirstPersonItemsPipeline firstPersonItemsPipeline){ + this.firstPersonItemsPipeline = firstPersonItemsPipeline; + } } diff --git a/src/main/java/electrosphere/renderer/pipelines/FirstPersonItemsPipeline.java b/src/main/java/electrosphere/renderer/pipelines/FirstPersonItemsPipeline.java index 081089c2..c2ae9f18 100644 --- a/src/main/java/electrosphere/renderer/pipelines/FirstPersonItemsPipeline.java +++ b/src/main/java/electrosphere/renderer/pipelines/FirstPersonItemsPipeline.java @@ -1,13 +1,119 @@ package electrosphere.renderer.pipelines; +import static org.lwjgl.opengl.GL30.GL_FRAMEBUFFER; + +import org.joml.Matrix4d; +import org.joml.Quaterniond; +import org.joml.Quaternionf; +import org.joml.Vector3d; +import org.joml.Vector3f; +import org.joml.Vector4d; +import org.lwjgl.opengl.GL40; + +import electrosphere.engine.Globals; +import electrosphere.entity.Entity; +import electrosphere.entity.EntityUtils; +import electrosphere.entity.state.client.firstPerson.FirstPersonTree; +import electrosphere.entity.types.camera.CameraEntityUtils; import electrosphere.renderer.OpenGLState; import electrosphere.renderer.RenderPipelineState; +import electrosphere.renderer.actor.Actor; +import electrosphere.renderer.framebuffer.Framebuffer; +import electrosphere.renderer.framebuffer.FramebufferUtils; +/** + * Renders content that should only be rendered in first person (ie the view model/hands/whatever) + */ public class FirstPersonItemsPipeline implements RenderPipeline { + //framebuffer to store what is rendered in this pass + Framebuffer firstPersonFramebuffer; + + //internal model matrix + Matrix4d modelTransformMatrix = new Matrix4d(); + + /** + * Initializes the pipeline + */ + public void init(){ + this.firstPersonFramebuffer = FramebufferUtils.generateTextureFramebuffer(Globals.WINDOW_WIDTH, Globals.WINDOW_HEIGHT); + } + @Override public void render(OpenGLState openGLState, RenderPipelineState renderPipelineState) { - //todo, render hands to a screenbuffer + + //update logic + updateFirstPersonModelPosition(Globals.firstPersonEntity); + + //setup opengl state + this.firstPersonFramebuffer.bind(); + renderPipelineState.setUseBones(true); + renderPipelineState.setUseLight(false); + renderPipelineState.setUseMaterial(true); + renderPipelineState.setUseMeshShader(true); + renderPipelineState.setUseShadowMap(false); + renderPipelineState.setBufferStandardUniforms(true); + renderPipelineState.setFrustumCheck(false); + + openGLState.glDepthTest(true); + openGLState.glDepthFunc(GL40.GL_LESS); + GL40.glDepthMask(true); + + //clear + GL40.glClearColor(0.0f, 0.0f, 0.0f, 0.0f); + GL40.glClear(GL40.GL_COLOR_BUFFER_BIT); + GL40.glClear(GL40.GL_DEPTH_BUFFER_BIT); + + + //render + if( + !Globals.controlHandler.cameraIsThirdPerson() && + Globals.firstPersonEntity != null + ){ + Vector3d position = EntityUtils.getPosition(Globals.firstPersonEntity); + Actor actor = EntityUtils.getActor(Globals.firstPersonEntity); + //calculate camera-modified vector3f + Vector3f cameraModifiedPosition = new Vector3f((float)position.x,(float)position.y,(float)position.z).sub(CameraEntityUtils.getCameraCenter(Globals.playerCamera)); + //calculate and apply model transform + modelTransformMatrix.identity(); + modelTransformMatrix.translate(cameraModifiedPosition); + modelTransformMatrix.rotate(EntityUtils.getRotation(Globals.firstPersonEntity)); + modelTransformMatrix.scale(new Vector3d(EntityUtils.getScale(Globals.firstPersonEntity))); + actor.applySpatialData(modelTransformMatrix,position); + + //draw + actor.draw(renderPipelineState, openGLState); + } + + //finish up + openGLState.glBindFramebuffer(GL_FRAMEBUFFER,0); + } + + /** + * Gets the framebuffer of the pipeline + * @return the framebuffer + */ + public Framebuffer getFramebuffer(){ + return this.firstPersonFramebuffer; + } + + /** + * Updates the position and rotation of the first person model + */ + private void updateFirstPersonModelPosition(Entity target){ + + FirstPersonTree tree = FirstPersonTree.getTree(target); + + Quaternionf quatRaw = CameraEntityUtils.getYawQuat(Globals.playerCamera).mul(CameraEntityUtils.getPitchQuat(Globals.playerCamera)); + Quaterniond quatd = new Quaterniond(quatRaw).normalize(); + EntityUtils.getRotation(Globals.firstPersonEntity).set(quatd); + + Matrix4d rotationMat = new Matrix4d().rotate(quatd); + + Vector3d playerPos = EntityUtils.getPosition(Globals.playerEntity); + Vector4d behindCameraOffsetRaw = rotationMat.transform(new Vector4d(0,tree.getCameraViewDirOffsetY(),tree.getCameraViewDirOffsetZ(),1)); //pushes the model behind the camera + Vector3d behindCameraOffset = new Vector3d(behindCameraOffsetRaw.x,behindCameraOffsetRaw.y,behindCameraOffsetRaw.z); + EntityUtils.getPosition(Globals.firstPersonEntity).set(playerPos).add(0.0f,tree.getHeightFromOrigin(),0.0f).add(behindCameraOffset); } } diff --git a/src/main/java/electrosphere/server/simulation/MicroSimulation.java b/src/main/java/electrosphere/server/simulation/MicroSimulation.java index 3294db40..2157b1e8 100644 --- a/src/main/java/electrosphere/server/simulation/MicroSimulation.java +++ b/src/main/java/electrosphere/server/simulation/MicroSimulation.java @@ -58,6 +58,15 @@ public class MicroSimulation { currentActor.incrementAnimationTime(Globals.timekeeper.getSimFrameTime() / Main.targetFrameRate); } } + //update first person model animations + if(Globals.firstPersonEntity != null){ + //fetch actor + Actor currentActor = EntityUtils.getActor(Globals.firstPersonEntity); + //increment animations + if(currentActor.isPlayingAnimation()){ + currentActor.incrementAnimationTime(Globals.timekeeper.getSimFrameTime() / Main.targetFrameRate); + } + } //make items play idle animation for(Entity item : dataCell.getScene().getEntitiesWithTag(EntityTags.ITEM)){ ItemUtils.updateItemActorAnimation(item); diff --git a/src/main/java/electrosphere/server/terrain/editing/TerrainEditing.java b/src/main/java/electrosphere/server/terrain/editing/TerrainEditing.java index 52a311a5..1632bbf8 100644 --- a/src/main/java/electrosphere/server/terrain/editing/TerrainEditing.java +++ b/src/main/java/electrosphere/server/terrain/editing/TerrainEditing.java @@ -12,6 +12,9 @@ import electrosphere.server.terrain.manager.ServerTerrainChunk; * Provides utilities for editing terrain (particularly brushes, etc) */ public class TerrainEditing { + + //the minimum value before hard setting to 0 + static final float MINIMUM_FULL_VALUE = 0.01f; /** * Performs a terrain chunk edit. Basically has a sphere around the provided position that it attempts to add value to. @@ -62,7 +65,10 @@ public class TerrainEditing { ){ float current = data.getWeights()[voxelPos.x][voxelPos.y][voxelPos.z]; //hard clamp so it doesn't go over 1 - float finalValue = Math.max(Math.min(current + weight * distance,1),-1); + float finalValue = Math.max(Math.min(current + weight / distance,1),-1); + if(finalValue < MINIMUM_FULL_VALUE && current > MINIMUM_FULL_VALUE){ + finalValue = -1; + } voxelCellManager.editChunk(chunkPos, voxelPos, finalValue, type); } }