architecture work, blocker ai tree
All checks were successful
studiorailgun/Renderer/pipeline/head This commit looks good
All checks were successful
studiorailgun/Renderer/pipeline/head This commit looks good
This commit is contained in:
parent
9349b35596
commit
07a708edfc
4
Jenkinsfile
vendored
4
Jenkinsfile
vendored
@ -23,6 +23,10 @@ pipeline {
|
|||||||
stage('Build (Documentation)') {
|
stage('Build (Documentation)') {
|
||||||
steps {
|
steps {
|
||||||
sh 'cd ./docs && doxygen ./Doxyfile'
|
sh 'cd ./docs && doxygen ./Doxyfile'
|
||||||
|
sh 'rm -rf /docs/*'
|
||||||
|
sh 'cd ./docs-dist/html && rm -f ./docs.tar.gz'
|
||||||
|
sh 'cd ./docs-dist/html && tar -czvf ./docs.tar.gz ./*'
|
||||||
|
sh 'cp ./docs-dist/html/docs.tar.gz /docs/docs.tar.gz && cd /docs/ && tar -xzvf ./docs.tar.gz'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
stage('Test') {
|
stage('Test') {
|
||||||
|
|||||||
@ -514,10 +514,7 @@
|
|||||||
},
|
},
|
||||||
"aiTrees" : [
|
"aiTrees" : [
|
||||||
{
|
{
|
||||||
"name" : "Attacker",
|
"name" : "Blocker"
|
||||||
"aggroRange" : 10,
|
|
||||||
"attackRange" : 2,
|
|
||||||
"stateChangeTimeout" : "240"
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"boneGroups" : [
|
"boneGroups" : [
|
||||||
|
|||||||
@ -6,17 +6,19 @@
|
|||||||
enemy ai
|
enemy ai
|
||||||
review effects
|
review effects
|
||||||
review combat code (lifestate, damage calculation, etc)
|
review combat code (lifestate, damage calculation, etc)
|
||||||
|
- Allow block hotboxxes to block damage
|
||||||
audio fx for everything
|
audio fx for everything
|
||||||
|
- Block SFX
|
||||||
|
|
||||||
|
+ rearchitecture
|
||||||
|
Ability to synchronize state of synchronized variables on client joining scene
|
||||||
|
ie, send currentBlockVariant when client connects
|
||||||
|
this is probably going to involve massive netcode arch to send all synchronized variables for each entity
|
||||||
|
|
||||||
|
+ fix the vibes
|
||||||
|
Attack animation feels slow
|
||||||
|
Hitboxes between server and client feel wayyyy off
|
||||||
|
|
||||||
+ bug fixes
|
+ bug fixes
|
||||||
|
|
||||||
|
|
||||||
Things that feel bad:
|
|
||||||
Attack animation feels slow
|
|
||||||
Short movement bursts feel jittery
|
|
||||||
Part of this may be cylinder collidable instead of capsule
|
|
||||||
Hitboxes between server and client feel wayyyy off
|
|
||||||
|
|
||||||
|
|
||||||
Sound effect on block
|
|
||||||
Allow block hotboxes to block damage
|
|
||||||
|
|||||||
@ -362,7 +362,9 @@ public class HitboxCollectionState {
|
|||||||
//calculate rotation from old position to new position
|
//calculate rotation from old position to new position
|
||||||
//the second quaternion is a rotation along the x axis. This is used to put the hitbox rotation into ode's space
|
//the second quaternion is a rotation along the x axis. This is used to put the hitbox rotation into ode's space
|
||||||
//ode is Z-axis-up
|
//ode is Z-axis-up
|
||||||
rotation = MathUtils.calculateRotationFromPointToPoint(previousWorldPos,worldPosition).mul(new Quaterniond(0,0,0.707,0.707));
|
if(previousWorldPos.distance(worldPosition) > 0.0){
|
||||||
|
rotation = MathUtils.calculateRotationFromPointToPoint(previousWorldPos,worldPosition).mul(new Quaterniond(0,0,0.707,0.707));
|
||||||
|
}
|
||||||
|
|
||||||
//create new capsule
|
//create new capsule
|
||||||
length = previousWorldPos.distance(worldPosition) / 2.0;
|
length = previousWorldPos.distance(worldPosition) / 2.0;
|
||||||
|
|||||||
@ -9,6 +9,7 @@ import com.google.gson.JsonParseException;
|
|||||||
|
|
||||||
import electrosphere.logger.LoggerInterface;
|
import electrosphere.logger.LoggerInterface;
|
||||||
import electrosphere.server.ai.creature.Attacker;
|
import electrosphere.server.ai.creature.Attacker;
|
||||||
|
import electrosphere.server.ai.creature.Blocker;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deserializes ai tree data types
|
* Deserializes ai tree data types
|
||||||
@ -21,6 +22,8 @@ public class AITreeDataSerializer implements JsonDeserializer<AITreeData> {
|
|||||||
switch(json.getAsJsonObject().get("name").getAsString()){
|
switch(json.getAsJsonObject().get("name").getAsString()){
|
||||||
case Attacker.TREE_NAME:
|
case Attacker.TREE_NAME:
|
||||||
return context.deserialize(json, AttackerTreeData.class);
|
return context.deserialize(json, AttackerTreeData.class);
|
||||||
|
case Blocker.TREE_NAME:
|
||||||
|
return context.deserialize(json, BlockerTreeData.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
LoggerInterface.loggerEngine.ERROR(new IllegalArgumentException("JSON Object provided to AITreeDataSerializer that cannot deserialize into a tree data type cleanly"));
|
LoggerInterface.loggerEngine.ERROR(new IllegalArgumentException("JSON Object provided to AITreeDataSerializer that cannot deserialize into a tree data type cleanly"));
|
||||||
|
|||||||
@ -0,0 +1,13 @@
|
|||||||
|
package electrosphere.game.data.creature.type.ai;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data for a blocker ai tree
|
||||||
|
*/
|
||||||
|
public class BlockerTreeData implements AITreeData {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "Blocker";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -5,6 +5,7 @@ import org.joml.Vector3d;
|
|||||||
import electrosphere.client.collision.ClientHitboxCollision;
|
import electrosphere.client.collision.ClientHitboxCollision;
|
||||||
import electrosphere.engine.Globals;
|
import electrosphere.engine.Globals;
|
||||||
import electrosphere.entity.Entity;
|
import electrosphere.entity.Entity;
|
||||||
|
import electrosphere.logger.LoggerInterface;
|
||||||
import electrosphere.net.parser.net.message.CombatMessage;
|
import electrosphere.net.parser.net.message.CombatMessage;
|
||||||
import electrosphere.net.template.ClientProtocolTemplate;
|
import electrosphere.net.template.ClientProtocolTemplate;
|
||||||
|
|
||||||
@ -25,7 +26,11 @@ public class CombatProtocol implements ClientProtocolTemplate<CombatMessage> {
|
|||||||
Vector3d position = new Vector3d(message.getpositionX(),message.getpositionY(),message.getpositionZ());
|
Vector3d position = new Vector3d(message.getpositionX(),message.getpositionY(),message.getpositionZ());
|
||||||
Entity senderEntity = Globals.clientSceneWrapper.getEntityFromServerId(message.getentityID());
|
Entity senderEntity = Globals.clientSceneWrapper.getEntityFromServerId(message.getentityID());
|
||||||
Entity receiverEntity = Globals.clientSceneWrapper.getEntityFromServerId(message.getreceiverEntityID());
|
Entity receiverEntity = Globals.clientSceneWrapper.getEntityFromServerId(message.getreceiverEntityID());
|
||||||
ClientHitboxCollision.handleHitboxCollision(senderEntity, receiverEntity, position, message.gethitboxType(), message.gethurtboxType());
|
if(senderEntity != null && receiverEntity != null){
|
||||||
|
ClientHitboxCollision.handleHitboxCollision(senderEntity, receiverEntity, position, message.gethitboxType(), message.gethurtboxType());
|
||||||
|
} else {
|
||||||
|
LoggerInterface.loggerEngine.WARNING("Received collision event for entities that are undefined! " + senderEntity + " " + receiverEntity);
|
||||||
|
}
|
||||||
} break;
|
} break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -12,8 +12,10 @@ import electrosphere.entity.EntityUtils;
|
|||||||
import electrosphere.entity.types.creature.CreatureUtils;
|
import electrosphere.entity.types.creature.CreatureUtils;
|
||||||
import electrosphere.game.data.creature.type.ai.AITreeData;
|
import electrosphere.game.data.creature.type.ai.AITreeData;
|
||||||
import electrosphere.game.data.creature.type.ai.AttackerTreeData;
|
import electrosphere.game.data.creature.type.ai.AttackerTreeData;
|
||||||
|
import electrosphere.game.data.creature.type.ai.BlockerTreeData;
|
||||||
import electrosphere.logger.LoggerInterface;
|
import electrosphere.logger.LoggerInterface;
|
||||||
import electrosphere.server.ai.creature.Attacker;
|
import electrosphere.server.ai.creature.Attacker;
|
||||||
|
import electrosphere.server.ai.creature.Blocker;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A collection of AITrees that are attached to a single entity.
|
* A collection of AITrees that are attached to a single entity.
|
||||||
@ -55,6 +57,12 @@ public class AI {
|
|||||||
case Attacker.TREE_NAME:
|
case Attacker.TREE_NAME:
|
||||||
rVal.trees.add(Attacker.construct(parent, (AttackerTreeData) aiData));
|
rVal.trees.add(Attacker.construct(parent, (AttackerTreeData) aiData));
|
||||||
break;
|
break;
|
||||||
|
case Blocker.TREE_NAME: {
|
||||||
|
rVal.trees.add(Blocker.construct(parent, (BlockerTreeData) aiData));
|
||||||
|
} break;
|
||||||
|
default: {
|
||||||
|
LoggerInterface.loggerEngine.ERROR(new IllegalArgumentException("Trying to construct ai tree with undefined data type! " + aiData.getName()));
|
||||||
|
} break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
125
src/main/java/electrosphere/server/ai/creature/Blocker.java
Normal file
125
src/main/java/electrosphere/server/ai/creature/Blocker.java
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
package electrosphere.server.ai.creature;
|
||||||
|
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
import org.joml.Vector3d;
|
||||||
|
|
||||||
|
import electrosphere.engine.Globals;
|
||||||
|
import electrosphere.entity.Entity;
|
||||||
|
import electrosphere.entity.EntityTags;
|
||||||
|
import electrosphere.entity.EntityUtils;
|
||||||
|
import electrosphere.entity.state.block.ServerBlockTree;
|
||||||
|
import electrosphere.entity.types.creature.CreatureUtils;
|
||||||
|
import electrosphere.game.data.creature.type.ai.BlockerTreeData;
|
||||||
|
import electrosphere.server.ai.AITree;
|
||||||
|
import electrosphere.server.datacell.Realm;
|
||||||
|
import electrosphere.server.datacell.utils.DataCellSearchUtils;
|
||||||
|
import electrosphere.util.math.MathUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AI that just continuously blocks
|
||||||
|
*/
|
||||||
|
public class Blocker implements AITree {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The name of the tree type
|
||||||
|
*/
|
||||||
|
public static final String TREE_NAME = "Blocker";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The configuring tree data for this tree
|
||||||
|
*/
|
||||||
|
BlockerTreeData treeData;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The parent to this tree
|
||||||
|
*/
|
||||||
|
Entity parent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The current target of this tree
|
||||||
|
*/
|
||||||
|
Entity target = null;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The number of frames the tree has been in its current state
|
||||||
|
*/
|
||||||
|
int currentStateFrameCount = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The random used for rolls on behavior transitions
|
||||||
|
*/
|
||||||
|
Random random = new Random();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Private constructor
|
||||||
|
* @param parent The parent entity
|
||||||
|
*/
|
||||||
|
private Blocker(Entity parent){
|
||||||
|
this.parent = parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs an attacker tree
|
||||||
|
* @param parent The parent entity
|
||||||
|
* @param treeData The tree data
|
||||||
|
* @return The Attacker tree
|
||||||
|
*/
|
||||||
|
public static AITree construct(Entity parent, BlockerTreeData treeData) {
|
||||||
|
Blocker rVal = new Blocker(parent);
|
||||||
|
rVal.treeData = treeData;
|
||||||
|
return rVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void simulate() {
|
||||||
|
if(target == null){
|
||||||
|
searchForTarget();
|
||||||
|
}
|
||||||
|
if(ServerBlockTree.getServerBlockTree(parent) != null){
|
||||||
|
ServerBlockTree serverBlockTree = ServerBlockTree.getServerBlockTree(parent);
|
||||||
|
if(!serverBlockTree.isBlocking()){
|
||||||
|
serverBlockTree.start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(target != null){
|
||||||
|
Vector3d targetPos = EntityUtils.getPosition(target);
|
||||||
|
EntityUtils.getRotation(parent).set(MathUtils.calculateRotationFromPointToPoint(EntityUtils.getPosition(parent), targetPos));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getTreeName() {
|
||||||
|
return TREE_NAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateStateAndPriority() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getCurrentStateName() {
|
||||||
|
return "BLCOKING";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getCurrentStatePriority() {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Searches for a valid target
|
||||||
|
*/
|
||||||
|
private void searchForTarget(){
|
||||||
|
Vector3d position = EntityUtils.getPosition(parent);
|
||||||
|
Realm realm = Globals.realmManager.getEntityRealm(parent);
|
||||||
|
for(Entity current : DataCellSearchUtils.getEntitiesWithTagAroundLocation(realm,position,EntityTags.LIFE_STATE)){
|
||||||
|
if(current != parent && CreatureUtils.isCreature(current)){
|
||||||
|
target = current;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -5,6 +5,8 @@ import org.joml.Vector3d;
|
|||||||
import org.joml.Vector3f;
|
import org.joml.Vector3f;
|
||||||
import org.joml.Vector4d;
|
import org.joml.Vector4d;
|
||||||
|
|
||||||
|
import electrosphere.logger.LoggerInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Utility functions for doing math
|
* Utility functions for doing math
|
||||||
*/
|
*/
|
||||||
@ -91,7 +93,21 @@ public class MathUtils {
|
|||||||
* @return The quaternion
|
* @return The quaternion
|
||||||
*/
|
*/
|
||||||
public static Quaterniond calculateRotationFromPointToPoint(Vector3d originPoint, Vector3d destinationPoint){
|
public static Quaterniond calculateRotationFromPointToPoint(Vector3d originPoint, Vector3d destinationPoint){
|
||||||
return getOriginVector().rotationTo(new Vector3d(destinationPoint).sub(originPoint).normalize(), new Quaterniond());
|
if(originPoint == destinationPoint || originPoint.distance(destinationPoint) == 0.0){
|
||||||
|
String message = "Trying to find rotation between same point!";
|
||||||
|
LoggerInterface.loggerEngine.ERROR(new IllegalStateException(message));
|
||||||
|
return new Quaterniond();
|
||||||
|
}
|
||||||
|
Quaterniond rVal = getOriginVector().rotationTo(new Vector3d(destinationPoint).sub(originPoint).normalize(), new Quaterniond());
|
||||||
|
if(!Double.isFinite(rVal.w) || !Double.isFinite(rVal.x) || !Double.isFinite(rVal.y) || !Double.isFinite(rVal.z)){
|
||||||
|
String message = "Rotation is NaN!\n" +
|
||||||
|
"originPoint: " + originPoint + "\n" +
|
||||||
|
"destinationPoint: " + destinationPoint
|
||||||
|
;
|
||||||
|
LoggerInterface.loggerEngine.ERROR(new IllegalStateException(message));
|
||||||
|
rVal = new Quaterniond();
|
||||||
|
}
|
||||||
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user