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)') {
|
||||
steps {
|
||||
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') {
|
||||
|
||||
@ -514,10 +514,7 @@
|
||||
},
|
||||
"aiTrees" : [
|
||||
{
|
||||
"name" : "Attacker",
|
||||
"aggroRange" : 10,
|
||||
"attackRange" : 2,
|
||||
"stateChangeTimeout" : "240"
|
||||
"name" : "Blocker"
|
||||
}
|
||||
],
|
||||
"boneGroups" : [
|
||||
|
||||
@ -6,17 +6,19 @@
|
||||
enemy ai
|
||||
review effects
|
||||
review combat code (lifestate, damage calculation, etc)
|
||||
- Allow block hotboxxes to block damage
|
||||
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
|
||||
|
||||
|
||||
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
|
||||
//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
|
||||
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
|
||||
length = previousWorldPos.distance(worldPosition) / 2.0;
|
||||
|
||||
@ -9,6 +9,7 @@ import com.google.gson.JsonParseException;
|
||||
|
||||
import electrosphere.logger.LoggerInterface;
|
||||
import electrosphere.server.ai.creature.Attacker;
|
||||
import electrosphere.server.ai.creature.Blocker;
|
||||
|
||||
/**
|
||||
* Deserializes ai tree data types
|
||||
@ -21,6 +22,8 @@ public class AITreeDataSerializer implements JsonDeserializer<AITreeData> {
|
||||
switch(json.getAsJsonObject().get("name").getAsString()){
|
||||
case Attacker.TREE_NAME:
|
||||
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"));
|
||||
|
||||
@ -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.engine.Globals;
|
||||
import electrosphere.entity.Entity;
|
||||
import electrosphere.logger.LoggerInterface;
|
||||
import electrosphere.net.parser.net.message.CombatMessage;
|
||||
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());
|
||||
Entity senderEntity = Globals.clientSceneWrapper.getEntityFromServerId(message.getentityID());
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -12,8 +12,10 @@ import electrosphere.entity.EntityUtils;
|
||||
import electrosphere.entity.types.creature.CreatureUtils;
|
||||
import electrosphere.game.data.creature.type.ai.AITreeData;
|
||||
import electrosphere.game.data.creature.type.ai.AttackerTreeData;
|
||||
import electrosphere.game.data.creature.type.ai.BlockerTreeData;
|
||||
import electrosphere.logger.LoggerInterface;
|
||||
import electrosphere.server.ai.creature.Attacker;
|
||||
import electrosphere.server.ai.creature.Blocker;
|
||||
|
||||
/**
|
||||
* A collection of AITrees that are attached to a single entity.
|
||||
@ -55,6 +57,12 @@ public class AI {
|
||||
case Attacker.TREE_NAME:
|
||||
rVal.trees.add(Attacker.construct(parent, (AttackerTreeData) aiData));
|
||||
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.Vector4d;
|
||||
|
||||
import electrosphere.logger.LoggerInterface;
|
||||
|
||||
/**
|
||||
* Utility functions for doing math
|
||||
*/
|
||||
@ -91,7 +93,21 @@ public class MathUtils {
|
||||
* @return The quaternion
|
||||
*/
|
||||
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