From d39254968f671a7b7de83d22e9e69731421974fe Mon Sep 17 00:00:00 2001 From: austin Date: Thu, 5 Sep 2024 00:48:43 -0400 Subject: [PATCH] melee ai targeting fix --- assets/Data/units/units.json | 10 +++++ docs/src/progress/currenttarget.md | 1 - docs/src/progress/renderertodo.md | 3 ++ .../electrosphere/entity/EntityUtils.java | 6 ++- .../entity/ServerEntityUtils.java | 4 +- .../actions/combat/MeleeTargetingNode.java | 6 ++- .../entity/ServerEntityUtilsUnitTests.java | 31 +++++++++++++ .../combat/MeleeTargetingNodeTests.java | 45 +++++++++++++++++++ 8 files changed, 100 insertions(+), 6 deletions(-) create mode 100644 src/test/java/electrosphere/entity/ServerEntityUtilsUnitTests.java create mode 100644 src/test/java/electrosphere/server/ai/nodes/actions/combat/MeleeTargetingNodeTests.java diff --git a/assets/Data/units/units.json b/assets/Data/units/units.json index 55b42792..a0f91f58 100644 --- a/assets/Data/units/units.json +++ b/assets/Data/units/units.json @@ -14,6 +14,16 @@ "name" : "Blocker" } ] + }, + { + "id" : "humanSwordsman", + "creatureId" : "human", + "equipment" : [ + { + "pointId" : "handsCombined", + "itemId" : "Katana2H" + } + ] } ] } \ No newline at end of file diff --git a/docs/src/progress/currenttarget.md b/docs/src/progress/currenttarget.md index 76187027..bb2071d4 100644 --- a/docs/src/progress/currenttarget.md +++ b/docs/src/progress/currenttarget.md @@ -20,7 +20,6 @@ + bug fixes Fix falling tree not always deactivating on server - Fix AI tracking deleted entity Fix server ground movement tree playing animation over falling animation Fix empty item slot not showing underneath dragged item Fix grass rendering distance diff --git a/docs/src/progress/renderertodo.md b/docs/src/progress/renderertodo.md index 26f417ce..d1ede71e 100644 --- a/docs/src/progress/renderertodo.md +++ b/docs/src/progress/renderertodo.md @@ -690,6 +690,9 @@ Unit tests for above Fix physics debug rendering pipeline Update human collidable data +(09/05/2024) +Fix AI tracking deleted entity + # TODO diff --git a/src/main/java/electrosphere/entity/EntityUtils.java b/src/main/java/electrosphere/entity/EntityUtils.java index bb9e5daf..1218951c 100644 --- a/src/main/java/electrosphere/entity/EntityUtils.java +++ b/src/main/java/electrosphere/entity/EntityUtils.java @@ -119,8 +119,10 @@ public class EntityUtils { */ public static void cleanUpEntity(Entity e){ //remove from client - Globals.clientSceneWrapper.getScene().deregisterEntity(e); - Globals.clientSceneWrapper.deregisterTranslationMapping(e); + if(Globals.clientSceneWrapper != null){ + Globals.clientSceneWrapper.getScene().deregisterEntity(e); + Globals.clientSceneWrapper.deregisterTranslationMapping(e); + } //remove from all server classes if(Globals.realmManager != null){ Realm realm = Globals.realmManager.getEntityRealm(e); diff --git a/src/main/java/electrosphere/entity/ServerEntityUtils.java b/src/main/java/electrosphere/entity/ServerEntityUtils.java index fbce69c6..cac0c975 100644 --- a/src/main/java/electrosphere/entity/ServerEntityUtils.java +++ b/src/main/java/electrosphere/entity/ServerEntityUtils.java @@ -117,7 +117,9 @@ public class ServerEntityUtils { HitboxCollectionState.destroyHitboxState(entity); Globals.realmManager.removeEntity(entity); EntityLookupUtils.removeEntity(entity); - Globals.aiManager.removeAI(entity); + if(Globals.aiManager != null){ + Globals.aiManager.removeAI(entity); + } // //deregister all behavior trees diff --git a/src/main/java/electrosphere/server/ai/nodes/actions/combat/MeleeTargetingNode.java b/src/main/java/electrosphere/server/ai/nodes/actions/combat/MeleeTargetingNode.java index 4f05c843..29bf9db8 100644 --- a/src/main/java/electrosphere/server/ai/nodes/actions/combat/MeleeTargetingNode.java +++ b/src/main/java/electrosphere/server/ai/nodes/actions/combat/MeleeTargetingNode.java @@ -34,7 +34,7 @@ public class MeleeTargetingNode implements AITreeNode { @Override public AITreeNodeResult evaluate(Entity entity, Blackboard blackboard){ - if(MeleeTargetingNode.hasTarget(blackboard) && this.targetIsValid(entity)){ + if(MeleeTargetingNode.hasTarget(blackboard) && this.targetIsValid(MeleeTargetingNode.getTarget(blackboard))){ return AITreeNodeResult.SUCCESS; } @@ -71,7 +71,9 @@ public class MeleeTargetingNode implements AITreeNode { * @return true if valid, false otherwise */ private boolean targetIsValid(Entity entity){ - return Globals.realmManager.getEntityRealm(entity) != null; + return + Globals.realmManager.getEntityRealm(entity) != null + ; } /** diff --git a/src/test/java/electrosphere/entity/ServerEntityUtilsUnitTests.java b/src/test/java/electrosphere/entity/ServerEntityUtilsUnitTests.java new file mode 100644 index 00000000..af063f14 --- /dev/null +++ b/src/test/java/electrosphere/entity/ServerEntityUtilsUnitTests.java @@ -0,0 +1,31 @@ +package electrosphere.entity; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.joml.Vector3d; + +import annotations.UnitTest; +import electrosphere.engine.Globals; +import electrosphere.server.datacell.Realm; +import electrosphere.server.datacell.RealmManager; + +/** + * Unit tests for the server entity utils + */ +public class ServerEntityUtilsUnitTests { + + @UnitTest + public void destroyEntity_ValidEntity_NoRealm(){ + //setup + Globals.realmManager = new RealmManager(); + Realm realm = Globals.realmManager.createViewportRealm(new Vector3d(0,0,0), new Vector3d(1,1,1)); + Entity entity = EntityCreationUtils.createServerEntity(realm, new Vector3d()); + + //perform action + ServerEntityUtils.destroyEntity(entity); + + //verify + assertEquals(null, Globals.realmManager.getEntityRealm(entity)); + } + +} diff --git a/src/test/java/electrosphere/server/ai/nodes/actions/combat/MeleeTargetingNodeTests.java b/src/test/java/electrosphere/server/ai/nodes/actions/combat/MeleeTargetingNodeTests.java new file mode 100644 index 00000000..d9c02116 --- /dev/null +++ b/src/test/java/electrosphere/server/ai/nodes/actions/combat/MeleeTargetingNodeTests.java @@ -0,0 +1,45 @@ +package electrosphere.server.ai.nodes.actions.combat; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.joml.Vector3d; + +import annotations.IntegrationTest; +import electrosphere.engine.Globals; +import electrosphere.entity.Entity; +import electrosphere.entity.ServerEntityUtils; +import electrosphere.entity.types.creature.CreatureTemplate; +import electrosphere.entity.types.creature.CreatureUtils; +import electrosphere.server.ai.blackboard.Blackboard; +import electrosphere.server.ai.nodes.AITreeNode.AITreeNodeResult; +import electrosphere.server.content.unit.UnitUtils; +import template.EntityTestTemplate; + +/** + * Tests for the melee targeting ai node + */ +public class MeleeTargetingNodeTests extends EntityTestTemplate { + + @IntegrationTest + public void testStopTargetingDeadEntity(){ + float aggroRange = 10; + + //spawn test entities + Entity swordsman = UnitUtils.spawnUnit(Globals.realmManager.first(), new Vector3d(0,0,0), "humanSwordsman"); + Entity target = CreatureUtils.serverSpawnBasicCreature(Globals.realmManager.first(), new Vector3d(1,0,0), "human", CreatureTemplate.createDefault("human")); + + //check if the swordsman can find a target + Blackboard blackboard = new Blackboard(); + MeleeTargetingNode meleeTargetingNode = new MeleeTargetingNode(aggroRange); + AITreeNodeResult eval1 = meleeTargetingNode.evaluate(swordsman, blackboard); + assertEquals(AITreeNodeResult.SUCCESS, eval1); + + //delete the target + ServerEntityUtils.destroyEntity(target); + + //check that the swordsman no longer finds a target + AITreeNodeResult eval2 = meleeTargetingNode.evaluate(swordsman, blackboard); + assertEquals(AITreeNodeResult.FAILURE, eval2); + } + +}