macro pathfinding implementation
This commit is contained in:
parent
57de3d5d81
commit
414707f6d5
@ -2086,6 +2086,7 @@ Skybox reflects time of day
|
|||||||
Standardize data sourcing in MacroTemporalData
|
Standardize data sourcing in MacroTemporalData
|
||||||
Macro pathfinding scaffolding
|
Macro pathfinding scaffolding
|
||||||
Macro pathfinding work
|
Macro pathfinding work
|
||||||
|
Actual macro pathfinding implementation
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -15,13 +15,18 @@ public class SequenceNode implements CollectionNode {
|
|||||||
/**
|
/**
|
||||||
* The child nodes of the sequence
|
* The child nodes of the sequence
|
||||||
*/
|
*/
|
||||||
List<AITreeNode> children;
|
private List<AITreeNode> children;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The name associated with this node
|
||||||
|
*/
|
||||||
|
private String name;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
* @param children All the children of the sequence
|
* @param children All the children of the sequence
|
||||||
*/
|
*/
|
||||||
public SequenceNode(List<AITreeNode> children){
|
public SequenceNode(String name, List<AITreeNode> children){
|
||||||
if(children == null){
|
if(children == null){
|
||||||
throw new IllegalArgumentException("Trying to create sequence node with no children!");
|
throw new IllegalArgumentException("Trying to create sequence node with no children!");
|
||||||
}
|
}
|
||||||
@ -29,13 +34,14 @@ public class SequenceNode implements CollectionNode {
|
|||||||
throw new IllegalArgumentException("Trying to create sequence node with no children!");
|
throw new IllegalArgumentException("Trying to create sequence node with no children!");
|
||||||
}
|
}
|
||||||
this.children = children;
|
this.children = children;
|
||||||
|
this.name = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
* @param children All the children of the sequence
|
* @param children All the children of the sequence
|
||||||
*/
|
*/
|
||||||
public SequenceNode(AITreeNode ... children){
|
public SequenceNode(String name, AITreeNode ... children){
|
||||||
if(children == null){
|
if(children == null){
|
||||||
throw new IllegalArgumentException("Trying to create sequence node with no children!");
|
throw new IllegalArgumentException("Trying to create sequence node with no children!");
|
||||||
}
|
}
|
||||||
@ -43,14 +49,19 @@ public class SequenceNode implements CollectionNode {
|
|||||||
throw new IllegalArgumentException("Trying to create sequence node with no children!");
|
throw new IllegalArgumentException("Trying to create sequence node with no children!");
|
||||||
}
|
}
|
||||||
this.children = Arrays.asList(children);
|
this.children = Arrays.asList(children);
|
||||||
|
this.name = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AITreeNodeResult evaluate(Entity entity, Blackboard blackboard) {
|
public AITreeNodeResult evaluate(Entity entity, Blackboard blackboard) {
|
||||||
for(AITreeNode child : children){
|
for(AITreeNode child : children){
|
||||||
AITreeNodeResult result = child.evaluate(entity, blackboard);
|
try {
|
||||||
if(result != AITreeNodeResult.SUCCESS){
|
AITreeNodeResult result = child.evaluate(entity, blackboard);
|
||||||
return result;
|
if(result != AITreeNodeResult.SUCCESS){
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
} catch(Throwable e){
|
||||||
|
throw new Error(this.name, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return AITreeNodeResult.SUCCESS;
|
return AITreeNodeResult.SUCCESS;
|
||||||
|
|||||||
@ -10,6 +10,7 @@ import electrosphere.server.ai.blackboard.Blackboard;
|
|||||||
import electrosphere.server.ai.nodes.AITreeNode;
|
import electrosphere.server.ai.nodes.AITreeNode;
|
||||||
import electrosphere.server.datacell.Realm;
|
import electrosphere.server.datacell.Realm;
|
||||||
import electrosphere.server.macro.MacroData;
|
import electrosphere.server.macro.MacroData;
|
||||||
|
import electrosphere.server.macro.region.MacroRegion;
|
||||||
import electrosphere.server.macro.spatial.MacroAreaObject;
|
import electrosphere.server.macro.spatial.MacroAreaObject;
|
||||||
import electrosphere.server.macro.spatial.path.MacroPathNode;
|
import electrosphere.server.macro.spatial.path.MacroPathNode;
|
||||||
import electrosphere.server.macro.structure.VirtualStructure;
|
import electrosphere.server.macro.structure.VirtualStructure;
|
||||||
@ -40,8 +41,8 @@ public class MacroPathfindingNode implements AITreeNode {
|
|||||||
*
|
*
|
||||||
* @param targetEntityKey
|
* @param targetEntityKey
|
||||||
*/
|
*/
|
||||||
public static PathfindingNode createPathEntity(String targetEntityKey){
|
public static MacroPathfindingNode createPathEntity(String targetEntityKey){
|
||||||
PathfindingNode rVal = new PathfindingNode();
|
MacroPathfindingNode rVal = new MacroPathfindingNode();
|
||||||
rVal.targetEntityKey = targetEntityKey;
|
rVal.targetEntityKey = targetEntityKey;
|
||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
@ -58,8 +59,8 @@ public class MacroPathfindingNode implements AITreeNode {
|
|||||||
if(targetRaw == null){
|
if(targetRaw == null){
|
||||||
throw new Error("Target undefined!");
|
throw new Error("Target undefined!");
|
||||||
}
|
}
|
||||||
if(targetRaw instanceof MacroPathNode macroNode){
|
if(targetRaw instanceof MacroRegion macroRegion){
|
||||||
targetPos = macroNode.getPosition();
|
targetPos = macroRegion.getPos();
|
||||||
} else {
|
} else {
|
||||||
throw new Error("Unsupported target type " + targetRaw);
|
throw new Error("Unsupported target type " + targetRaw);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -25,6 +25,7 @@ public class StandardCharacterTree {
|
|||||||
*/
|
*/
|
||||||
public static AITreeNode create(StandardCharacterTreeData data){
|
public static AITreeNode create(StandardCharacterTreeData data){
|
||||||
return new SequenceNode(
|
return new SequenceNode(
|
||||||
|
"StandardCharacter",
|
||||||
new PublishStatusNode("StandardCharacter"),
|
new PublishStatusNode("StandardCharacter"),
|
||||||
//check that dependencies exist
|
//check that dependencies exist
|
||||||
new SelectorNode(
|
new SelectorNode(
|
||||||
|
|||||||
@ -27,6 +27,7 @@ public class CharacterGoalTree {
|
|||||||
*/
|
*/
|
||||||
public static AITreeNode create(){
|
public static AITreeNode create(){
|
||||||
return new SequenceNode(
|
return new SequenceNode(
|
||||||
|
"CharacterGoalTree",
|
||||||
//check if we have goals
|
//check if we have goals
|
||||||
MacroCharacterGoalNode.createAny(),
|
MacroCharacterGoalNode.createAny(),
|
||||||
//select based on the type of goals the character has
|
//select based on the type of goals the character has
|
||||||
@ -34,6 +35,7 @@ public class CharacterGoalTree {
|
|||||||
|
|
||||||
//character's goal is to leave sim range
|
//character's goal is to leave sim range
|
||||||
new SequenceNode(
|
new SequenceNode(
|
||||||
|
"CharacterGoalTree",
|
||||||
MacroCharacterGoalNode.create(CharacterGoalType.LEAVE_SIM_RANGE),
|
MacroCharacterGoalNode.create(CharacterGoalType.LEAVE_SIM_RANGE),
|
||||||
new PublishStatusNode("Leaving simulation range"),
|
new PublishStatusNode("Leaving simulation range"),
|
||||||
new FaceTargetNode(BlackboardKeys.POINT_TARGET),
|
new FaceTargetNode(BlackboardKeys.POINT_TARGET),
|
||||||
@ -42,6 +44,7 @@ public class CharacterGoalTree {
|
|||||||
|
|
||||||
//character's goal is to build a structure
|
//character's goal is to build a structure
|
||||||
new SequenceNode(
|
new SequenceNode(
|
||||||
|
"CharacterGoalTree",
|
||||||
MacroCharacterGoalNode.create(CharacterGoalType.BUILD_STRUCTURE),
|
MacroCharacterGoalNode.create(CharacterGoalType.BUILD_STRUCTURE),
|
||||||
new PublishStatusNode("Construct a shelter"),
|
new PublishStatusNode("Construct a shelter"),
|
||||||
new BeginStructureNode(),
|
new BeginStructureNode(),
|
||||||
@ -50,6 +53,7 @@ public class CharacterGoalTree {
|
|||||||
|
|
||||||
//character's goal is to acquire an item
|
//character's goal is to acquire an item
|
||||||
new SequenceNode(
|
new SequenceNode(
|
||||||
|
"CharacterGoalTree",
|
||||||
MacroCharacterGoalNode.create(CharacterGoalType.ACQUIRE_ITEM),
|
MacroCharacterGoalNode.create(CharacterGoalType.ACQUIRE_ITEM),
|
||||||
new PublishStatusNode("Acquire building material"),
|
new PublishStatusNode("Acquire building material"),
|
||||||
//try to find building materials
|
//try to find building materials
|
||||||
@ -58,6 +62,7 @@ public class CharacterGoalTree {
|
|||||||
|
|
||||||
//character's goal is to move to a macro virtual structure
|
//character's goal is to move to a macro virtual structure
|
||||||
new SequenceNode(
|
new SequenceNode(
|
||||||
|
"CharacterGoalTree",
|
||||||
MacroCharacterGoalNode.create(CharacterGoalType.MOVE_TO_MACRO_STRUCT),
|
MacroCharacterGoalNode.create(CharacterGoalType.MOVE_TO_MACRO_STRUCT),
|
||||||
new PublishStatusNode("Move to macro structure"),
|
new PublishStatusNode("Move to macro structure"),
|
||||||
MacroMoveToTree.create(BlackboardKeys.MACRO_TARGET)
|
MacroMoveToTree.create(BlackboardKeys.MACRO_TARGET)
|
||||||
|
|||||||
@ -21,6 +21,7 @@ public class AttackerAITree {
|
|||||||
*/
|
*/
|
||||||
public static AITreeNode create(AttackerTreeData attackerTreeData){
|
public static AITreeNode create(AttackerTreeData attackerTreeData){
|
||||||
return new SequenceNode(
|
return new SequenceNode(
|
||||||
|
"AttackerAITree",
|
||||||
MeleeAITree.create(attackerTreeData)
|
MeleeAITree.create(attackerTreeData)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -12,6 +12,7 @@ import electrosphere.server.ai.nodes.meta.collections.SelectorNode;
|
|||||||
import electrosphere.server.ai.nodes.meta.collections.SequenceNode;
|
import electrosphere.server.ai.nodes.meta.collections.SequenceNode;
|
||||||
import electrosphere.server.ai.nodes.meta.decorators.RunnerNode;
|
import electrosphere.server.ai.nodes.meta.decorators.RunnerNode;
|
||||||
import electrosphere.server.ai.nodes.meta.decorators.SucceederNode;
|
import electrosphere.server.ai.nodes.meta.decorators.SucceederNode;
|
||||||
|
import electrosphere.server.ai.nodes.plan.MacroPathfindingNode;
|
||||||
import electrosphere.server.ai.nodes.plan.PathfindingNode;
|
import electrosphere.server.ai.nodes.plan.PathfindingNode;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -50,8 +51,9 @@ public class MacroMoveToTree {
|
|||||||
}
|
}
|
||||||
return new SelectorNode(
|
return new SelectorNode(
|
||||||
new SequenceNode(
|
new SequenceNode(
|
||||||
|
"MacroMoveToTree",
|
||||||
//check if in range of target
|
//check if in range of target
|
||||||
new TargetRangeCheckNode(dist, targetKey),
|
new TargetRangeCheckNode(dist, targetKey),
|
||||||
new DataDeleteNode(BlackboardKeys.PATHFINDING_POINT),
|
new DataDeleteNode(BlackboardKeys.PATHFINDING_POINT),
|
||||||
new DataDeleteNode(BlackboardKeys.PATHFINDING_DATA),
|
new DataDeleteNode(BlackboardKeys.PATHFINDING_DATA),
|
||||||
//if in range, stop moving fowards and return SUCCESS
|
//if in range, stop moving fowards and return SUCCESS
|
||||||
@ -60,7 +62,8 @@ public class MacroMoveToTree {
|
|||||||
|
|
||||||
//not in range of target, keep moving towards it
|
//not in range of target, keep moving towards it
|
||||||
new SequenceNode(
|
new SequenceNode(
|
||||||
PathfindingNode.createPathEntity(targetKey),
|
"MacroMoveToTree",
|
||||||
|
MacroPathfindingNode.createPathEntity(targetKey),
|
||||||
new FaceTargetNode(BlackboardKeys.PATHFINDING_POINT),
|
new FaceTargetNode(BlackboardKeys.PATHFINDING_POINT),
|
||||||
new RunnerNode(new MoveStartNode(MovementRelativeFacing.FORWARD))
|
new RunnerNode(new MoveStartNode(MovementRelativeFacing.FORWARD))
|
||||||
)
|
)
|
||||||
|
|||||||
@ -50,6 +50,7 @@ public class MoveToTree {
|
|||||||
}
|
}
|
||||||
return new SelectorNode(
|
return new SelectorNode(
|
||||||
new SequenceNode(
|
new SequenceNode(
|
||||||
|
"MoveToTree",
|
||||||
//check if in range of target
|
//check if in range of target
|
||||||
new TargetRangeCheckNode(dist, targetKey),
|
new TargetRangeCheckNode(dist, targetKey),
|
||||||
new DataDeleteNode(BlackboardKeys.PATHFINDING_POINT),
|
new DataDeleteNode(BlackboardKeys.PATHFINDING_POINT),
|
||||||
@ -60,6 +61,7 @@ public class MoveToTree {
|
|||||||
|
|
||||||
//not in range of target, keep moving towards it
|
//not in range of target, keep moving towards it
|
||||||
new SequenceNode(
|
new SequenceNode(
|
||||||
|
"MoveToTree",
|
||||||
PathfindingNode.createPathEntity(targetKey),
|
PathfindingNode.createPathEntity(targetKey),
|
||||||
new FaceTargetNode(BlackboardKeys.PATHFINDING_POINT),
|
new FaceTargetNode(BlackboardKeys.PATHFINDING_POINT),
|
||||||
new RunnerNode(new MoveStartNode(MovementRelativeFacing.FORWARD))
|
new RunnerNode(new MoveStartNode(MovementRelativeFacing.FORWARD))
|
||||||
|
|||||||
@ -24,6 +24,7 @@ public class ExploreTree {
|
|||||||
*/
|
*/
|
||||||
public static AITreeNode create(){
|
public static AITreeNode create(){
|
||||||
return new SequenceNode(
|
return new SequenceNode(
|
||||||
|
"Explore",
|
||||||
new PublishStatusNode("Explore"),
|
new PublishStatusNode("Explore"),
|
||||||
//resolve point to explore towards
|
//resolve point to explore towards
|
||||||
new TargetExploreNode(BlackboardKeys.MOVE_TO_TARGET),
|
new TargetExploreNode(BlackboardKeys.MOVE_TO_TARGET),
|
||||||
|
|||||||
@ -25,6 +25,7 @@ public class EquipToolbarTree {
|
|||||||
*/
|
*/
|
||||||
public static AITreeNode create(String targetKey){
|
public static AITreeNode create(String targetKey){
|
||||||
return new SequenceNode(
|
return new SequenceNode(
|
||||||
|
"EquipToolbar",
|
||||||
new PublishStatusNode("Equip an item"),
|
new PublishStatusNode("Equip an item"),
|
||||||
//check that we have this type of item
|
//check that we have this type of item
|
||||||
new DataTransferNode(targetKey, BlackboardKeys.INVENTORY_CHECK_TYPE),
|
new DataTransferNode(targetKey, BlackboardKeys.INVENTORY_CHECK_TYPE),
|
||||||
|
|||||||
@ -44,6 +44,7 @@ public class MeleeAITree {
|
|||||||
public static AITreeNode create(AttackerTreeData attackerTreeData){
|
public static AITreeNode create(AttackerTreeData attackerTreeData){
|
||||||
|
|
||||||
return new SequenceNode(
|
return new SequenceNode(
|
||||||
|
"MeleeAITree",
|
||||||
//preconditions here
|
//preconditions here
|
||||||
new HasWeaponNode(),
|
new HasWeaponNode(),
|
||||||
new MeleeTargetingNode(attackerTreeData.getAggroRange()),
|
new MeleeTargetingNode(attackerTreeData.getAggroRange()),
|
||||||
@ -53,6 +54,7 @@ public class MeleeAITree {
|
|||||||
|
|
||||||
//in attack range
|
//in attack range
|
||||||
new SequenceNode(
|
new SequenceNode(
|
||||||
|
"MeleeAITree",
|
||||||
//check prior to performing action
|
//check prior to performing action
|
||||||
new MeleeRangeCheckNode(attackerTreeData,MeleeRangeCheckType.ATTACK),
|
new MeleeRangeCheckNode(attackerTreeData,MeleeRangeCheckType.ATTACK),
|
||||||
|
|
||||||
@ -66,18 +68,21 @@ public class MeleeAITree {
|
|||||||
new RandomizerNode(
|
new RandomizerNode(
|
||||||
//wait
|
//wait
|
||||||
new SequenceNode(
|
new SequenceNode(
|
||||||
|
"MeleeAITree",
|
||||||
new PublishStatusNode("Waiting"),
|
new PublishStatusNode("Waiting"),
|
||||||
new FaceTargetNode(BlackboardKeys.ENTITY_TARGET),
|
new FaceTargetNode(BlackboardKeys.ENTITY_TARGET),
|
||||||
new TimerNode(new SucceederNode(null), 600)
|
new TimerNode(new SucceederNode(null), 600)
|
||||||
),
|
),
|
||||||
//wait
|
//wait
|
||||||
new SequenceNode(
|
new SequenceNode(
|
||||||
|
"MeleeAITree",
|
||||||
new PublishStatusNode("Waiting"),
|
new PublishStatusNode("Waiting"),
|
||||||
new FaceTargetNode(BlackboardKeys.ENTITY_TARGET),
|
new FaceTargetNode(BlackboardKeys.ENTITY_TARGET),
|
||||||
new TimerNode(new SucceederNode(null), 300)
|
new TimerNode(new SucceederNode(null), 300)
|
||||||
),
|
),
|
||||||
//attack
|
//attack
|
||||||
new SequenceNode(
|
new SequenceNode(
|
||||||
|
"MeleeAITree",
|
||||||
new PublishStatusNode("Attacking"),
|
new PublishStatusNode("Attacking"),
|
||||||
new FaceTargetNode(BlackboardKeys.ENTITY_TARGET),
|
new FaceTargetNode(BlackboardKeys.ENTITY_TARGET),
|
||||||
new AttackStartNode(),
|
new AttackStartNode(),
|
||||||
@ -88,6 +93,7 @@ public class MeleeAITree {
|
|||||||
|
|
||||||
//in aggro range
|
//in aggro range
|
||||||
new SequenceNode(
|
new SequenceNode(
|
||||||
|
"MeleeAITree",
|
||||||
//check prior to performing action
|
//check prior to performing action
|
||||||
new MeleeRangeCheckNode(attackerTreeData,MeleeRangeCheckType.AGGRO),
|
new MeleeRangeCheckNode(attackerTreeData,MeleeRangeCheckType.AGGRO),
|
||||||
|
|
||||||
@ -96,6 +102,7 @@ public class MeleeAITree {
|
|||||||
|
|
||||||
//wait
|
//wait
|
||||||
new SequenceNode(
|
new SequenceNode(
|
||||||
|
"MeleeAITree",
|
||||||
new PublishStatusNode("Waiting"),
|
new PublishStatusNode("Waiting"),
|
||||||
new FaceTargetNode(BlackboardKeys.ENTITY_TARGET),
|
new FaceTargetNode(BlackboardKeys.ENTITY_TARGET),
|
||||||
new TimerNode(new SucceederNode(null), 1200)
|
new TimerNode(new SucceederNode(null), 1200)
|
||||||
@ -103,6 +110,7 @@ public class MeleeAITree {
|
|||||||
|
|
||||||
//strafe to the right
|
//strafe to the right
|
||||||
new SequenceNode(
|
new SequenceNode(
|
||||||
|
"MeleeAITree",
|
||||||
new PublishStatusNode("Strafing right"),
|
new PublishStatusNode("Strafing right"),
|
||||||
new WalkStartNode(),
|
new WalkStartNode(),
|
||||||
new InverterNode(new OnFailureNode(
|
new InverterNode(new OnFailureNode(
|
||||||
@ -117,6 +125,7 @@ public class MeleeAITree {
|
|||||||
|
|
||||||
//strafe to the left
|
//strafe to the left
|
||||||
new SequenceNode(
|
new SequenceNode(
|
||||||
|
"MeleeAITree",
|
||||||
new PublishStatusNode("Strafing left"),
|
new PublishStatusNode("Strafing left"),
|
||||||
new WalkStartNode(),
|
new WalkStartNode(),
|
||||||
new InverterNode(new OnFailureNode(
|
new InverterNode(new OnFailureNode(
|
||||||
@ -132,6 +141,7 @@ public class MeleeAITree {
|
|||||||
//approach target
|
//approach target
|
||||||
//move towards target and attack
|
//move towards target and attack
|
||||||
new SequenceNode(
|
new SequenceNode(
|
||||||
|
"MeleeAITree",
|
||||||
new PublishStatusNode("Move into attack range"),
|
new PublishStatusNode("Move into attack range"),
|
||||||
new FaceTargetNode(BlackboardKeys.ENTITY_TARGET),
|
new FaceTargetNode(BlackboardKeys.ENTITY_TARGET),
|
||||||
new SucceederNode(new MoveStartNode(MovementRelativeFacing.FORWARD)),
|
new SucceederNode(new MoveStartNode(MovementRelativeFacing.FORWARD)),
|
||||||
|
|||||||
@ -35,11 +35,13 @@ public class AcquireItemTree {
|
|||||||
*/
|
*/
|
||||||
public static AITreeNode create(String blackboardKey){
|
public static AITreeNode create(String blackboardKey){
|
||||||
return new SequenceNode(
|
return new SequenceNode(
|
||||||
|
"AcquireItemTree",
|
||||||
new PublishStatusNode("Acquire an item"),
|
new PublishStatusNode("Acquire an item"),
|
||||||
//solve how we're going to get this top level item
|
//solve how we're going to get this top level item
|
||||||
new SolveSourcingTreeNode(blackboardKey),
|
new SolveSourcingTreeNode(blackboardKey),
|
||||||
new SelectorNode(
|
new SelectorNode(
|
||||||
new SequenceNode(
|
new SequenceNode(
|
||||||
|
"AcquireItemTree",
|
||||||
new PublishStatusNode("Pick up an item"),
|
new PublishStatusNode("Pick up an item"),
|
||||||
//check if we should be sourcing this item by picking it up
|
//check if we should be sourcing this item by picking it up
|
||||||
new SourcingTypeNode(SourcingType.PICKUP, BlackboardKeys.ITEM_TARGET_CATEGORY),
|
new SourcingTypeNode(SourcingType.PICKUP, BlackboardKeys.ITEM_TARGET_CATEGORY),
|
||||||
@ -50,6 +52,7 @@ public class AcquireItemTree {
|
|||||||
new RunnerNode(null)
|
new RunnerNode(null)
|
||||||
),
|
),
|
||||||
new SequenceNode(
|
new SequenceNode(
|
||||||
|
"AcquireItemTree",
|
||||||
new PublishStatusNode("Craft an item"),
|
new PublishStatusNode("Craft an item"),
|
||||||
//check if we should be sourcing this from a recipe
|
//check if we should be sourcing this from a recipe
|
||||||
new SourcingTypeNode(SourcingType.RECIPE, blackboardKey),
|
new SourcingTypeNode(SourcingType.RECIPE, blackboardKey),
|
||||||
@ -57,6 +60,7 @@ public class AcquireItemTree {
|
|||||||
new RunnerNode(null)
|
new RunnerNode(null)
|
||||||
),
|
),
|
||||||
new SequenceNode(
|
new SequenceNode(
|
||||||
|
"AcquireItemTree",
|
||||||
new PublishStatusNode("Harvest an item"),
|
new PublishStatusNode("Harvest an item"),
|
||||||
//check if we should be sourcing this from harvesting foliage
|
//check if we should be sourcing this from harvesting foliage
|
||||||
new SourcingTypeNode(SourcingType.HARVEST, blackboardKey),
|
new SourcingTypeNode(SourcingType.HARVEST, blackboardKey),
|
||||||
@ -66,6 +70,7 @@ public class AcquireItemTree {
|
|||||||
new RunnerNode(null)
|
new RunnerNode(null)
|
||||||
),
|
),
|
||||||
new SequenceNode(
|
new SequenceNode(
|
||||||
|
"AcquireItemTree",
|
||||||
new PublishStatusNode("Fell a tree"),
|
new PublishStatusNode("Fell a tree"),
|
||||||
//check if we should be sourcing this from felling a tree
|
//check if we should be sourcing this from felling a tree
|
||||||
new SourcingTypeNode(SourcingType.TREE, blackboardKey),
|
new SourcingTypeNode(SourcingType.TREE, blackboardKey),
|
||||||
@ -74,6 +79,7 @@ public class AcquireItemTree {
|
|||||||
new RunnerNode(null)
|
new RunnerNode(null)
|
||||||
),
|
),
|
||||||
new SequenceNode(
|
new SequenceNode(
|
||||||
|
"AcquireItemTree",
|
||||||
new PublishStatusNode("Explore new chunks for resources"),
|
new PublishStatusNode("Explore new chunks for resources"),
|
||||||
//Failed to find sources of material in existing chunks, must move for new chunks
|
//Failed to find sources of material in existing chunks, must move for new chunks
|
||||||
ExploreTree.create()
|
ExploreTree.create()
|
||||||
|
|||||||
@ -42,6 +42,7 @@ public class FellTree {
|
|||||||
public static AITreeNode create(String targetKey){
|
public static AITreeNode create(String targetKey){
|
||||||
|
|
||||||
return new SequenceNode(
|
return new SequenceNode(
|
||||||
|
"FellTree",
|
||||||
//preconditions here
|
//preconditions here
|
||||||
new DataStorageNode(BlackboardKeys.INVENTORY_CHECK_TYPE, ItemIdStrings.ITEM_STONE_AXE),
|
new DataStorageNode(BlackboardKeys.INVENTORY_CHECK_TYPE, ItemIdStrings.ITEM_STONE_AXE),
|
||||||
EquipToolbarTree.create(BlackboardKeys.INVENTORY_CHECK_TYPE),
|
EquipToolbarTree.create(BlackboardKeys.INVENTORY_CHECK_TYPE),
|
||||||
@ -51,6 +52,7 @@ public class FellTree {
|
|||||||
|
|
||||||
//in attack range
|
//in attack range
|
||||||
new SequenceNode(
|
new SequenceNode(
|
||||||
|
"FellTree",
|
||||||
//check if in range of target
|
//check if in range of target
|
||||||
new TargetRangeCheckNode(FellTree.FELL_RANGE, targetKey),
|
new TargetRangeCheckNode(FellTree.FELL_RANGE, targetKey),
|
||||||
//stop walking now that we're in range
|
//stop walking now that we're in range
|
||||||
@ -60,6 +62,7 @@ public class FellTree {
|
|||||||
|
|
||||||
//attack
|
//attack
|
||||||
new SequenceNode(
|
new SequenceNode(
|
||||||
|
"FellTree",
|
||||||
new PublishStatusNode("Attacking"),
|
new PublishStatusNode("Attacking"),
|
||||||
new FaceTargetNode(BlackboardKeys.ENTITY_TARGET),
|
new FaceTargetNode(BlackboardKeys.ENTITY_TARGET),
|
||||||
new AttackStartNode(),
|
new AttackStartNode(),
|
||||||
|
|||||||
@ -23,8 +23,10 @@ public class MaslowTree {
|
|||||||
*/
|
*/
|
||||||
public static AITreeNode create(){
|
public static AITreeNode create(){
|
||||||
return new SequenceNode(
|
return new SequenceNode(
|
||||||
|
"MaslowTree",
|
||||||
//check that dependencies exist
|
//check that dependencies exist
|
||||||
new SequenceNode(
|
new SequenceNode(
|
||||||
|
"MaslowTree",
|
||||||
new PublishStatusNode("Checking dependencies for maslow tree.."),
|
new PublishStatusNode("Checking dependencies for maslow tree.."),
|
||||||
new MacroDataExists(),
|
new MacroDataExists(),
|
||||||
new IsCharacterNode()
|
new IsCharacterNode()
|
||||||
|
|||||||
@ -21,6 +21,7 @@ public class CombatTree {
|
|||||||
*/
|
*/
|
||||||
public static AITreeNode create(){
|
public static AITreeNode create(){
|
||||||
return new SequenceNode(
|
return new SequenceNode(
|
||||||
|
"CombatTree",
|
||||||
new PublishStatusNode("Engaged in mortal combat"),
|
new PublishStatusNode("Engaged in mortal combat"),
|
||||||
new SucceederNode(null)
|
new SucceederNode(null)
|
||||||
);
|
);
|
||||||
|
|||||||
@ -21,6 +21,7 @@ public class FleeTree {
|
|||||||
*/
|
*/
|
||||||
public static AITreeNode create(){
|
public static AITreeNode create(){
|
||||||
return new SequenceNode(
|
return new SequenceNode(
|
||||||
|
"FleeTree",
|
||||||
new PublishStatusNode("Flee!"),
|
new PublishStatusNode("Flee!"),
|
||||||
new SucceederNode(null)
|
new SucceederNode(null)
|
||||||
);
|
);
|
||||||
|
|||||||
@ -21,6 +21,7 @@ public class MaslowSafetyTree {
|
|||||||
*/
|
*/
|
||||||
public static AITreeNode create(){
|
public static AITreeNode create(){
|
||||||
return new SequenceNode(
|
return new SequenceNode(
|
||||||
|
"MaslowSafetyTree",
|
||||||
new PublishStatusNode("Evaluate safety"),
|
new PublishStatusNode("Evaluate safety"),
|
||||||
new SelectorNode(
|
new SelectorNode(
|
||||||
FleeTree.create(),
|
FleeTree.create(),
|
||||||
|
|||||||
@ -23,6 +23,7 @@ public class ConstructShelterTree {
|
|||||||
*/
|
*/
|
||||||
public static AITreeNode create(){
|
public static AITreeNode create(){
|
||||||
return new SequenceNode(
|
return new SequenceNode(
|
||||||
|
"ConstructShelter",
|
||||||
new PublishStatusNode("Construct a shelter"),
|
new PublishStatusNode("Construct a shelter"),
|
||||||
new BeginStructureNode(),
|
new BeginStructureNode(),
|
||||||
BuildStructureTree.create(),
|
BuildStructureTree.create(),
|
||||||
|
|||||||
@ -23,22 +23,27 @@ public class ShelterTree {
|
|||||||
*/
|
*/
|
||||||
public static AITreeNode create(){
|
public static AITreeNode create(){
|
||||||
return new SequenceNode(
|
return new SequenceNode(
|
||||||
|
"ShelterTree",
|
||||||
new PublishStatusNode("Evaluate shelter"),
|
new PublishStatusNode("Evaluate shelter"),
|
||||||
//make sure that this entity actually cares about shelter
|
//make sure that this entity actually cares about shelter
|
||||||
new SequenceNode(
|
new SequenceNode(
|
||||||
|
"ShelterTree",
|
||||||
//if this is a character
|
//if this is a character
|
||||||
new IsCharacterNode()
|
new IsCharacterNode()
|
||||||
),
|
),
|
||||||
//now that we know the entity cares about shelter, check if they have shelter
|
//now that we know the entity cares about shelter, check if they have shelter
|
||||||
new SequenceNode(
|
new SequenceNode(
|
||||||
|
"ShelterTree",
|
||||||
//if has shelter..
|
//if has shelter..
|
||||||
new SelectorNode(
|
new SelectorNode(
|
||||||
new SequenceNode(
|
new SequenceNode(
|
||||||
|
"ShelterTree",
|
||||||
new HasShelter()
|
new HasShelter()
|
||||||
//already has shelter
|
//already has shelter
|
||||||
//TODO: check environment (ie time of day) to see if we should return to shelter
|
//TODO: check environment (ie time of day) to see if we should return to shelter
|
||||||
),
|
),
|
||||||
new SequenceNode(
|
new SequenceNode(
|
||||||
|
"ShelterTree",
|
||||||
//does not have shelter
|
//does not have shelter
|
||||||
ConstructShelterTree.create()
|
ConstructShelterTree.create()
|
||||||
)
|
)
|
||||||
|
|||||||
@ -19,6 +19,7 @@ public class ForageTree {
|
|||||||
*/
|
*/
|
||||||
public static AITreeNode create(){
|
public static AITreeNode create(){
|
||||||
return new SequenceNode(
|
return new SequenceNode(
|
||||||
|
"ForageTree"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -32,18 +32,22 @@ public class BuildStructureTree {
|
|||||||
*/
|
*/
|
||||||
public static AITreeNode create(){
|
public static AITreeNode create(){
|
||||||
return new SequenceNode(
|
return new SequenceNode(
|
||||||
|
"BuildStructureTree",
|
||||||
new PublishStatusNode("Construct a structure"),
|
new PublishStatusNode("Construct a structure"),
|
||||||
//figure out current task
|
//figure out current task
|
||||||
new SelectorNode(
|
new SelectorNode(
|
||||||
//make sure we know what material we need to build with currently
|
//make sure we know what material we need to build with currently
|
||||||
new SequenceNode(
|
new SequenceNode(
|
||||||
|
"BuildStructureTree",
|
||||||
new SolveBuildMaterialNode(),
|
new SolveBuildMaterialNode(),
|
||||||
new PublishStatusNode("Trying to place block in structure"),
|
new PublishStatusNode("Trying to place block in structure"),
|
||||||
//if has building materials
|
//if has building materials
|
||||||
new SequenceNode(
|
new SequenceNode(
|
||||||
|
"BuildStructureTree",
|
||||||
new InventoryContainsNode(BlackboardKeys.BUILDING_MATERIAL_CURRENT),
|
new InventoryContainsNode(BlackboardKeys.BUILDING_MATERIAL_CURRENT),
|
||||||
//if we're within range to place the material
|
//if we're within range to place the material
|
||||||
new SequenceNode(
|
new SequenceNode(
|
||||||
|
"BuildStructureTree",
|
||||||
//not in range, move to within range
|
//not in range, move to within range
|
||||||
MoveToTree.create(CollisionEngine.DEFAULT_INTERACT_DISTANCE, BlackboardKeys.STRUCTURE_TARGET),
|
MoveToTree.create(CollisionEngine.DEFAULT_INTERACT_DISTANCE, BlackboardKeys.STRUCTURE_TARGET),
|
||||||
//equip the type of block to place
|
//equip the type of block to place
|
||||||
@ -55,6 +59,7 @@ public class BuildStructureTree {
|
|||||||
),
|
),
|
||||||
//does not have building materials
|
//does not have building materials
|
||||||
new SequenceNode(
|
new SequenceNode(
|
||||||
|
"BuildStructureTree",
|
||||||
new InverterNode(new InventoryContainsNode(BlackboardKeys.BUILDING_MATERIAL_CURRENT)),
|
new InverterNode(new InventoryContainsNode(BlackboardKeys.BUILDING_MATERIAL_CURRENT)),
|
||||||
new RunnerNode(new PublishStatusNode("Waiting on macro character to set goal to find materials to build with"))
|
new RunnerNode(new PublishStatusNode("Waiting on macro character to set goal to find materials to build with"))
|
||||||
),
|
),
|
||||||
|
|||||||
@ -24,6 +24,7 @@ public class BlockerAITree {
|
|||||||
*/
|
*/
|
||||||
public static AITreeNode create(BlockerTreeData data){
|
public static AITreeNode create(BlockerTreeData data){
|
||||||
return new SequenceNode(
|
return new SequenceNode(
|
||||||
|
"BlockerAITree",
|
||||||
new BlockStartNode(),
|
new BlockStartNode(),
|
||||||
new MeleeTargetingNode(5.0f),
|
new MeleeTargetingNode(5.0f),
|
||||||
new FaceTargetNode(BlackboardKeys.ENTITY_TARGET)
|
new FaceTargetNode(BlackboardKeys.ENTITY_TARGET)
|
||||||
|
|||||||
@ -200,6 +200,14 @@ public class MacroPathNode {
|
|||||||
return this.neighborNodes.stream().map((Long neighborId) -> cache.getNodeById(neighborId)).collect(Collectors.toList());
|
return this.neighborNodes.stream().map((Long neighborId) -> cache.getNodeById(neighborId)).collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the list of neighbor ids
|
||||||
|
* @return The list of neighbor ids
|
||||||
|
*/
|
||||||
|
public List<Long> getNeighborIds(){
|
||||||
|
return this.neighborNodes;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds a neighbor to this node
|
* Adds a neighbor to this node
|
||||||
* @param neighbor The neighbor
|
* @param neighbor The neighbor
|
||||||
|
|||||||
@ -1,6 +1,10 @@
|
|||||||
package electrosphere.server.service;
|
package electrosphere.server.service;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.PriorityQueue;
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
|
|
||||||
import org.joml.Vector3d;
|
import org.joml.Vector3d;
|
||||||
@ -11,6 +15,7 @@ import electrosphere.engine.signal.SignalServiceImpl;
|
|||||||
import electrosphere.engine.threads.ThreadCounts;
|
import electrosphere.engine.threads.ThreadCounts;
|
||||||
import electrosphere.server.datacell.Realm;
|
import electrosphere.server.datacell.Realm;
|
||||||
import electrosphere.server.macro.MacroData;
|
import electrosphere.server.macro.MacroData;
|
||||||
|
import electrosphere.server.macro.spatial.path.MacroPathCache;
|
||||||
import electrosphere.server.macro.spatial.path.MacroPathNode;
|
import electrosphere.server.macro.spatial.path.MacroPathNode;
|
||||||
import electrosphere.server.pathfinding.recast.PathingProgressiveData;
|
import electrosphere.server.pathfinding.recast.PathingProgressiveData;
|
||||||
|
|
||||||
@ -75,7 +80,120 @@ public class MacroPathingService extends SignalServiceImpl {
|
|||||||
* @return The path
|
* @return The path
|
||||||
*/
|
*/
|
||||||
private List<Vector3d> findPath(MacroData macroData, MacroPathNode start, MacroPathNode end){
|
private List<Vector3d> findPath(MacroData macroData, MacroPathNode start, MacroPathNode end){
|
||||||
throw new Error("Not implemented yet!");
|
List<Vector3d> rVal = null;
|
||||||
|
//tracks whether we've found the goal or not
|
||||||
|
boolean foundGoal = false;
|
||||||
|
int countConsidered = 0;
|
||||||
|
MacroPathCache pathCache = macroData.getPathCache();
|
||||||
|
|
||||||
|
//create sets
|
||||||
|
PriorityQueue<PathfinderNode> openSet = new PriorityQueue<PathfinderNode>();
|
||||||
|
Map<Long,PathfinderNode> openSetLookup = new HashMap<Long,PathfinderNode>();
|
||||||
|
Map<Long,PathfinderNode> closetSet = new HashMap<Long,PathfinderNode>();
|
||||||
|
|
||||||
|
//add start node
|
||||||
|
PathfinderNode node = new PathfinderNode(start, 0, start.getId());
|
||||||
|
openSet.add(node);
|
||||||
|
openSetLookup.put(node.graphNode.getId(),node);
|
||||||
|
|
||||||
|
//search
|
||||||
|
while(openSet.size() > 0 && !foundGoal){
|
||||||
|
|
||||||
|
//pull from open set
|
||||||
|
PathfinderNode currentNode = openSet.poll();
|
||||||
|
long currentCost = currentNode.cost;
|
||||||
|
openSetLookup.remove(currentNode.graphNode.getId());
|
||||||
|
closetSet.put(currentNode.graphNode.getId(), currentNode);
|
||||||
|
countConsidered++;
|
||||||
|
|
||||||
|
|
||||||
|
//iterate along neighbors
|
||||||
|
for(Long neighborId : currentNode.graphNode.getNeighborIds()){
|
||||||
|
//goal check
|
||||||
|
if(end.getId() == neighborId){
|
||||||
|
foundGoal = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
//add-to-set check
|
||||||
|
if(!closetSet.containsKey(neighborId) && !openSetLookup.containsKey(neighborId)){
|
||||||
|
MacroPathNode neighborGraphNode = pathCache.getNodeById(neighborId);
|
||||||
|
long newCost = currentCost + neighborGraphNode.getCost();
|
||||||
|
PathfinderNode newNode = new PathfinderNode(
|
||||||
|
neighborGraphNode,
|
||||||
|
newCost, currentNode.graphNode.getId()
|
||||||
|
);
|
||||||
|
openSet.add(newNode);
|
||||||
|
openSetLookup.put(neighborGraphNode.getId(), newNode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//if found goal
|
||||||
|
if(foundGoal){
|
||||||
|
//reverse up the chain from here
|
||||||
|
rVal = new LinkedList<Vector3d>();
|
||||||
|
rVal.add(end.getPosition());
|
||||||
|
while(currentNode.prevNode != currentNode.graphNode.getId()){
|
||||||
|
rVal.add(0,currentNode.getPosition());
|
||||||
|
currentNode = closetSet.get(currentNode.prevNode);
|
||||||
|
}
|
||||||
|
rVal.add(0,start.getPosition());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
//error check
|
||||||
|
if(openSet.size() < 1){
|
||||||
|
throw new Error("Open set ran out of nodes! " + countConsidered);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!foundGoal){
|
||||||
|
throw new Error("Failed to find goal " + countConsidered);
|
||||||
|
}
|
||||||
|
return rVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A node to use during searching
|
||||||
|
*/
|
||||||
|
protected static class PathfinderNode implements Comparable<PathfinderNode> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The corresponding graph node
|
||||||
|
*/
|
||||||
|
MacroPathNode graphNode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cost to get to this node
|
||||||
|
*/
|
||||||
|
long cost = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The previous node
|
||||||
|
*/
|
||||||
|
long prevNode = 0;
|
||||||
|
|
||||||
|
public PathfinderNode(
|
||||||
|
MacroPathNode graphNode,
|
||||||
|
long cost, long prevNode
|
||||||
|
){
|
||||||
|
this.graphNode = graphNode;
|
||||||
|
this.cost = cost;
|
||||||
|
this.prevNode = prevNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compareTo(PathfinderNode o) {
|
||||||
|
return (int)(this.cost - o.cost);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the position of the node
|
||||||
|
* @return The position of the node
|
||||||
|
*/
|
||||||
|
public Vector3d getPosition(){
|
||||||
|
return graphNode.getPosition();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -42,13 +42,13 @@ public class CharaSimulation {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
//send a character on a walk
|
//send a character on a walk
|
||||||
// if(chara.getId() == 3){
|
if(chara.getId() == 3){
|
||||||
// Town hometown = CharacterUtils.getHometown(realm.getMacroData(), chara);
|
Town hometown = CharacterUtils.getHometown(realm.getMacroData(), chara);
|
||||||
// if(hometown != null){
|
if(hometown != null){
|
||||||
// MacroRegion target = hometown.getFarmPlots(realm.getMacroData()).get(0);
|
MacroRegion target = hometown.getFarmPlots(realm.getMacroData()).get(0);
|
||||||
// CharacterGoal.setCharacterGoal(chara, new CharacterGoal(CharacterGoalType.MOVE_TO_MACRO_STRUCT, target));
|
CharacterGoal.setCharacterGoal(chara, new CharacterGoal(CharacterGoalType.MOVE_TO_MACRO_STRUCT, target));
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user