ai work
Some checks failed
studiorailgun/Renderer/pipeline/head There was a failure building this commit
Some checks failed
studiorailgun/Renderer/pipeline/head There was a failure building this commit
This commit is contained in:
parent
4b8aa104b5
commit
4b25c110ee
@ -596,9 +596,7 @@
|
||||
},
|
||||
"aiTrees" : [
|
||||
{
|
||||
"name" : "Attacker",
|
||||
"aggroRange" : 10,
|
||||
"attackRange" : 0.8
|
||||
"name" : "Maslow"
|
||||
}
|
||||
],
|
||||
"cameraData" : {
|
||||
|
||||
@ -1627,6 +1627,7 @@ Blocks stack
|
||||
Item tag adjustments
|
||||
Pine tree loot pool update
|
||||
DB characters store toolbar items
|
||||
Scaffolding for new macro-cognizating ai approach
|
||||
|
||||
|
||||
|
||||
|
||||
@ -1,9 +1,11 @@
|
||||
package electrosphere.client.ui.menu.debug;
|
||||
|
||||
import electrosphere.engine.Globals;
|
||||
import electrosphere.entity.Entity;
|
||||
import electrosphere.renderer.ui.imgui.ImGuiWindow;
|
||||
import electrosphere.renderer.ui.imgui.ImGuiWindow.ImGuiWindowCallback;
|
||||
import electrosphere.server.ai.AI;
|
||||
import electrosphere.server.datacell.utils.EntityLookupUtils;
|
||||
import imgui.ImGui;
|
||||
|
||||
/**
|
||||
@ -38,6 +40,15 @@ public class ImGuiAI {
|
||||
Globals.aiManager.setActive(!Globals.aiManager.isActive());
|
||||
}
|
||||
|
||||
|
||||
int serverIdForClientEntity = Globals.clientSceneWrapper.mapClientToServerId(Globals.playerEntity.getId());
|
||||
Entity serverPlayerEntity = EntityLookupUtils.getEntityById(serverIdForClientEntity);
|
||||
AI playerAi = AI.getAI(serverPlayerEntity);
|
||||
ImGui.text("AI applied to player entity: " + playerAi.isApplyToPlayer());
|
||||
if(ImGui.button("Toggle AI on player entity")){
|
||||
playerAi.setApplyToPlayer(!playerAi.isApplyToPlayer());
|
||||
}
|
||||
|
||||
if(ImGui.collapsingHeader("Statuses")){
|
||||
for(AI ai : Globals.aiManager.getAIList()){
|
||||
ImGui.text(ai.getParent().getId() + " - " + ai.getStatus());
|
||||
|
||||
@ -14,6 +14,7 @@ import electrosphere.logger.LoggerInterface;
|
||||
import electrosphere.server.ai.blackboard.Blackboard;
|
||||
import electrosphere.server.ai.nodes.AITreeNode;
|
||||
import electrosphere.server.ai.trees.creature.AttackerAITree;
|
||||
import electrosphere.server.ai.trees.hierarchy.MaslowTree;
|
||||
import electrosphere.server.ai.trees.test.BlockerAITree;
|
||||
|
||||
/**
|
||||
@ -47,6 +48,11 @@ public class AI {
|
||||
*/
|
||||
List<AITreeNode> evaluatedNodes = new LinkedList<AITreeNode>();
|
||||
|
||||
/**
|
||||
* Tracks whether this should apply even if there is a controlling player
|
||||
*/
|
||||
boolean applyToPlayer = false;
|
||||
|
||||
/**
|
||||
* The status of the ai
|
||||
*/
|
||||
@ -69,6 +75,9 @@ public class AI {
|
||||
case AttackerAITree.TREE_NAME: {
|
||||
rVal.rootNode = AttackerAITree.create((AttackerTreeData) aiData);
|
||||
} break;
|
||||
case MaslowTree.TREE_NAME: {
|
||||
rVal.rootNode = MaslowTree.create();
|
||||
} break;
|
||||
default: {
|
||||
LoggerInterface.loggerEngine.ERROR(new IllegalArgumentException("Trying to construct ai tree with undefined data type! " + aiData.getName()));
|
||||
} break;
|
||||
@ -137,7 +146,7 @@ public class AI {
|
||||
* @return true if should simulate, false otherwise
|
||||
*/
|
||||
private boolean shouldExecute(){
|
||||
return !CreatureUtils.hasControllerPlayerId(this.parent);
|
||||
return this.applyToPlayer || !CreatureUtils.hasControllerPlayerId(this.parent);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -164,5 +173,23 @@ public class AI {
|
||||
ServerGroundMovementTree.getServerGroundMovementTree(this.parent).slowdown();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this should apply ai behavior even if the entity is controlled by a player
|
||||
* @return true if it should always apply ai behavior, false if it should defer to player
|
||||
*/
|
||||
public boolean isApplyToPlayer() {
|
||||
return applyToPlayer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether this should apply ai behavior even if the entity is controlled by a player
|
||||
* @param applyToPlayer true if it sohuld always apply ai behavior, false if it should defer to player
|
||||
*/
|
||||
public void setApplyToPlayer(boolean applyToPlayer) {
|
||||
this.applyToPlayer = applyToPlayer;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -0,0 +1,28 @@
|
||||
package electrosphere.server.ai.nodes.checks.macro;
|
||||
|
||||
import electrosphere.engine.Globals;
|
||||
import electrosphere.entity.Entity;
|
||||
import electrosphere.entity.state.server.ServerCharacterData;
|
||||
import electrosphere.server.ai.blackboard.Blackboard;
|
||||
import electrosphere.server.ai.nodes.AITreeNode;
|
||||
import electrosphere.server.macro.character.Character;
|
||||
import electrosphere.server.macro.character.CharacterUtils;
|
||||
import electrosphere.server.macro.structure.Structure;
|
||||
|
||||
/**
|
||||
* Checks if the character has shelter
|
||||
*/
|
||||
public class HasShelter implements AITreeNode {
|
||||
|
||||
@Override
|
||||
public AITreeNodeResult evaluate(Entity entity, Blackboard blackboard) {
|
||||
ServerCharacterData serverCharacterData = ServerCharacterData.getServerCharacterData(entity);
|
||||
Character character = Globals.macroData.getCharacter(serverCharacterData.getCharacterId());
|
||||
Structure shelter = CharacterUtils.getShelter(character);
|
||||
if(shelter == null){
|
||||
return AITreeNodeResult.FAILURE;
|
||||
}
|
||||
return AITreeNodeResult.SUCCESS;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,21 @@
|
||||
package electrosphere.server.ai.nodes.checks.macro;
|
||||
|
||||
import electrosphere.entity.Entity;
|
||||
import electrosphere.entity.state.server.ServerCharacterData;
|
||||
import electrosphere.server.ai.blackboard.Blackboard;
|
||||
import electrosphere.server.ai.nodes.AITreeNode;
|
||||
|
||||
/**
|
||||
* Checks if this entity is a character
|
||||
*/
|
||||
public class IsCharacterNode implements AITreeNode {
|
||||
|
||||
@Override
|
||||
public AITreeNodeResult evaluate(Entity entity, Blackboard blackboard) {
|
||||
if(ServerCharacterData.hasServerCharacterDataTree(entity)){
|
||||
return AITreeNodeResult.SUCCESS;
|
||||
}
|
||||
return AITreeNodeResult.FAILURE;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,27 @@
|
||||
package electrosphere.server.ai.trees.hierarchy;
|
||||
|
||||
import electrosphere.server.ai.nodes.AITreeNode;
|
||||
import electrosphere.server.ai.nodes.meta.collections.SequenceNode;
|
||||
import electrosphere.server.ai.trees.hierarchy.safety.MaslowSafetyTree;
|
||||
|
||||
/**
|
||||
* Arranges goals based on an approximation of Maslow's hierarchy of needs
|
||||
*/
|
||||
public class MaslowTree {
|
||||
|
||||
/**
|
||||
* Name of the tree
|
||||
*/
|
||||
public static final String TREE_NAME = "Maslow";
|
||||
|
||||
/**
|
||||
* Creates an attacker ai tree
|
||||
* @return The root node of the tree
|
||||
*/
|
||||
public static AITreeNode create(){
|
||||
return new SequenceNode(
|
||||
MaslowSafetyTree.create()
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,24 @@
|
||||
package electrosphere.server.ai.trees.hierarchy.safety;
|
||||
|
||||
import electrosphere.server.ai.nodes.AITreeNode;
|
||||
import electrosphere.server.ai.nodes.meta.decorators.SucceederNode;
|
||||
|
||||
/**
|
||||
* A tree that causes the entity to engage in combat when it determines it needs to in order to maintain its safety
|
||||
*/
|
||||
public class CombatTree {
|
||||
|
||||
/**
|
||||
* Name of the tree
|
||||
*/
|
||||
public static final String TREE_NAME = "CombatTree";
|
||||
|
||||
/**
|
||||
* Creates a combat tree
|
||||
* @return The root node of the tree
|
||||
*/
|
||||
public static AITreeNode create(){
|
||||
return new SucceederNode(null);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,24 @@
|
||||
package electrosphere.server.ai.trees.hierarchy.safety;
|
||||
|
||||
import electrosphere.server.ai.nodes.AITreeNode;
|
||||
import electrosphere.server.ai.nodes.meta.decorators.SucceederNode;
|
||||
|
||||
/**
|
||||
* A tree that causes the entity to flee in terror if it deems it needs to
|
||||
*/
|
||||
public class FleeTree {
|
||||
|
||||
/**
|
||||
* Name of the tree
|
||||
*/
|
||||
public static final String TREE_NAME = "FleeTree";
|
||||
|
||||
/**
|
||||
* Creates an flee tree
|
||||
* @return The root node of the tree
|
||||
*/
|
||||
public static AITreeNode create(){
|
||||
return new SucceederNode(null);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,29 @@
|
||||
package electrosphere.server.ai.trees.hierarchy.safety;
|
||||
|
||||
import electrosphere.server.ai.nodes.AITreeNode;
|
||||
import electrosphere.server.ai.nodes.meta.collections.SequenceNode;
|
||||
import electrosphere.server.ai.trees.hierarchy.safety.shelter.ShelterTree;
|
||||
|
||||
/**
|
||||
* A tree that runs all of the tier 1 maslow need trees
|
||||
*/
|
||||
public class MaslowSafetyTree {
|
||||
|
||||
/**
|
||||
* Name of the tree
|
||||
*/
|
||||
public static final String TREE_NAME = "MaslowSafetyTree";
|
||||
|
||||
/**
|
||||
* Creates a tier 1 maslow tree
|
||||
* @return The root node of the tree
|
||||
*/
|
||||
public static AITreeNode create(){
|
||||
return new SequenceNode(
|
||||
FleeTree.create(),
|
||||
CombatTree.create(),
|
||||
ShelterTree.create()
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,23 @@
|
||||
package electrosphere.server.ai.trees.hierarchy.safety.shelter;
|
||||
|
||||
import electrosphere.server.ai.nodes.AITreeNode;
|
||||
import electrosphere.server.ai.nodes.meta.decorators.SucceederNode;
|
||||
|
||||
/**
|
||||
* Tree for constructing shelter
|
||||
*/
|
||||
public class ConstructShelterTree {
|
||||
|
||||
/**
|
||||
* Name of the tree
|
||||
*/
|
||||
public static final String TREE_NAME = "ConstructShelterTree";
|
||||
|
||||
/**
|
||||
* Creates a construct shelter tree
|
||||
* @return The root node of the tree
|
||||
*/
|
||||
public static AITreeNode create(){
|
||||
return new SucceederNode(null);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,48 @@
|
||||
package electrosphere.server.ai.trees.hierarchy.safety.shelter;
|
||||
|
||||
import electrosphere.server.ai.nodes.AITreeNode;
|
||||
import electrosphere.server.ai.nodes.checks.macro.HasShelter;
|
||||
import electrosphere.server.ai.nodes.checks.macro.IsCharacterNode;
|
||||
import electrosphere.server.ai.nodes.meta.collections.SelectorNode;
|
||||
import electrosphere.server.ai.nodes.meta.collections.SequenceNode;
|
||||
|
||||
/**
|
||||
* A tree that causes the entity to try to secure shelter
|
||||
*/
|
||||
public class ShelterTree {
|
||||
|
||||
/**
|
||||
* Name of the tree
|
||||
*/
|
||||
public static final String TREE_NAME = "ShelterTree";
|
||||
|
||||
/**
|
||||
* Creates a shelter tree
|
||||
* @return The root node of the tree
|
||||
*/
|
||||
public static AITreeNode create(){
|
||||
return new SequenceNode(
|
||||
//make sure that this entity actually cares about shelter
|
||||
new SequenceNode(
|
||||
//if this is a character
|
||||
new IsCharacterNode()
|
||||
),
|
||||
//now that we know the entity cares about shelter, check if they have shelter
|
||||
new SequenceNode(
|
||||
//if has shelter..
|
||||
new SelectorNode(
|
||||
new SequenceNode(
|
||||
new HasShelter(),
|
||||
//does not have shelter
|
||||
ConstructShelterTree.create()
|
||||
),
|
||||
new SequenceNode(
|
||||
//already has shelter
|
||||
//TODO: check environment (ie time of day) to see if we should return to shelter
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
@ -301,5 +301,19 @@ public class MacroData {
|
||||
blockers.addAll(this.structures);
|
||||
return blockers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a character by its id
|
||||
* @param id The id
|
||||
* @return The character if it exists, null otherwise
|
||||
*/
|
||||
public Character getCharacter(int id){
|
||||
for(Character character : this.characters){
|
||||
if(character.getId() == id){
|
||||
return character;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user