ai work
All checks were successful
studiorailgun/Renderer/pipeline/head This commit looks good

This commit is contained in:
austin 2025-05-01 12:13:39 -04:00
parent 4b25c110ee
commit 4908ea0f44
33 changed files with 616 additions and 36 deletions

View File

@ -1628,6 +1628,7 @@ Item tag adjustments
Pine tree loot pool update
DB characters store toolbar items
Scaffolding for new macro-cognizating ai approach
AI work

View File

@ -84,7 +84,6 @@ import electrosphere.server.datacell.EntityDataCellMapper;
import electrosphere.server.datacell.RealmManager;
import electrosphere.server.db.DatabaseController;
import electrosphere.server.entity.poseactor.PoseModel;
import electrosphere.server.macro.MacroData;
import electrosphere.server.saves.Save;
import electrosphere.server.simulation.MacroSimulation;
import electrosphere.server.simulation.MicroSimulation;
@ -330,7 +329,6 @@ public class Globals {
//macro simulation
public static MacroSimulation macroSimulation;
public static MacroData macroData;
//micro simulation
public static MicroSimulation microSimulation;

View File

@ -10,6 +10,7 @@ import com.google.gson.JsonParseException;
import electrosphere.logger.LoggerInterface;
import electrosphere.server.ai.trees.test.BlockerAITree;
import electrosphere.server.ai.trees.creature.AttackerAITree;
import electrosphere.server.ai.trees.hierarchy.MaslowTree;
/**
* Deserializes ai tree data types
@ -20,13 +21,18 @@ public class AITreeDataSerializer implements JsonDeserializer<AITreeData> {
public AITreeData deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
switch(json.getAsJsonObject().get("name").getAsString()){
case AttackerAITree.TREE_NAME:
case AttackerAITree.TREE_NAME: {
return context.deserialize(json, AttackerTreeData.class);
case BlockerAITree.TREE_NAME:
}
case BlockerAITree.TREE_NAME: {
return context.deserialize(json, BlockerTreeData.class);
}
case MaslowTree.TREE_NAME: {
return context.deserialize(json, MaslowTreeData.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 " + json.getAsJsonObject().get("name").getAsString()));
return null;
}

View File

@ -1,5 +1,7 @@
package electrosphere.game.data.creature.type.ai;
import electrosphere.server.ai.trees.creature.AttackerAITree;
/**
* Configuration data for an attacker tree
*/
@ -33,7 +35,7 @@ public class AttackerTreeData implements AITreeData {
@Override
public String getName() {
return "Attacker";
return AttackerAITree.TREE_NAME;
}
}

View File

@ -1,5 +1,7 @@
package electrosphere.game.data.creature.type.ai;
import electrosphere.server.ai.trees.test.BlockerAITree;
/**
* Data for a blocker ai tree
*/
@ -7,7 +9,7 @@ public class BlockerTreeData implements AITreeData {
@Override
public String getName() {
return "Blocker";
return BlockerAITree.TREE_NAME;
}
}

View File

@ -0,0 +1,20 @@
package electrosphere.game.data.creature.type.ai;
import electrosphere.server.ai.trees.hierarchy.MaslowTree;
/**
* Tree data for controlling a maslow tree
*/
public class MaslowTreeData implements AITreeData {
/**
* The name of the tree
*/
String name;
@Override
public String getName() {
return MaslowTree.TREE_NAME;
}
}

View File

@ -190,6 +190,13 @@ public class AI {
this.applyToPlayer = applyToPlayer;
}
/**
* Gets the blackboard for the ai
* @return The blackboard
*/
public Blackboard getBlackboard(){
return this.blackboard;
}
}

View File

@ -9,6 +9,7 @@ import java.util.Random;
import electrosphere.entity.Entity;
import electrosphere.game.data.creature.type.ai.AITreeData;
import electrosphere.logger.LoggerInterface;
import electrosphere.server.ai.services.NearbyEntityService;
import electrosphere.server.ai.services.TimerService;
/**
@ -41,6 +42,11 @@ public class AIManager {
*/
TimerService timerService = new TimerService();
/**
* The nearby entity service
*/
NearbyEntityService nearbyEntityService = new NearbyEntityService();
/**
* The random of the ai
*/
@ -131,6 +137,7 @@ public class AIManager {
*/
private void execServices(){
timerService.exec();
nearbyEntityService.exec();
}
/**
@ -141,6 +148,14 @@ public class AIManager {
return timerService;
}
/**
* Gets the nearby entity service
* @return The nearby enttiy service
*/
public NearbyEntityService getNearbyEntityService(){
return nearbyEntityService;
}
/**
* Gets the ai manager's random
* @return The random

View File

@ -10,4 +10,19 @@ public class BlackboardKeys {
*/
public static final String MELEE_TARGET = "meleeTarget";
/**
* The collection of nearby entities
*/
public static final String NEARBY_ENTITIES = "nearbyEntities";
/**
* The target of the current action
*/
public static final String ENTITY_TARGET = "target";
/**
* The target to move towards
*/
public static final String MOVE_TO_TARGET = "moveToTarget";
}

View File

@ -0,0 +1,34 @@
package electrosphere.server.ai.nodes.actions.interact;
import org.joml.Vector3d;
import electrosphere.collision.CollisionEngine;
import electrosphere.entity.Entity;
import electrosphere.entity.EntityUtils;
import electrosphere.entity.state.inventory.InventoryUtils;
import electrosphere.server.ai.blackboard.Blackboard;
import electrosphere.server.ai.nodes.AITreeNode;
import electrosphere.server.ai.nodes.plan.FindEntityTargetNode;
/**
* Tries to collect an item
*/
public class CollectItemNode implements AITreeNode {
@Override
public AITreeNodeResult evaluate(Entity entity, Blackboard blackboard){
if(!FindEntityTargetNode.hasTarget(blackboard)){
return AITreeNodeResult.FAILURE;
}
Entity target = FindEntityTargetNode.getTarget(blackboard);
Vector3d parentPos = EntityUtils.getPosition(entity);
Vector3d targetPos = EntityUtils.getPosition(target);
if(parentPos.distance(targetPos) > CollisionEngine.DEFAULT_INTERACT_DISTANCE){
return AITreeNodeResult.FAILURE;
}
InventoryUtils.serverAttemptStoreItemTransform(entity, target);
FindEntityTargetNode.setTarget(blackboard, null);
return AITreeNodeResult.SUCCESS;
}
}

View File

@ -0,0 +1,33 @@
package electrosphere.server.ai.nodes.actions.interact;
import org.joml.Vector3d;
import electrosphere.collision.CollisionEngine;
import electrosphere.entity.Entity;
import electrosphere.entity.EntityUtils;
import electrosphere.server.ai.blackboard.Blackboard;
import electrosphere.server.ai.nodes.AITreeNode;
import electrosphere.server.ai.nodes.plan.FindEntityTargetNode;
import electrosphere.server.player.PlayerActions;
/**
* Tries to harvest an entity
*/
public class HarvestNode implements AITreeNode {
@Override
public AITreeNodeResult evaluate(Entity entity, Blackboard blackboard){
if(!FindEntityTargetNode.hasTarget(blackboard)){
return AITreeNodeResult.FAILURE;
}
Entity target = FindEntityTargetNode.getTarget(blackboard);
Vector3d parentPos = EntityUtils.getPosition(entity);
Vector3d targetPos = EntityUtils.getPosition(target);
if(parentPos.distance(targetPos) > CollisionEngine.DEFAULT_INTERACT_DISTANCE){
return AITreeNodeResult.FAILURE;
}
PlayerActions.harvest(entity, target);
FindEntityTargetNode.setTarget(blackboard, null);
return AITreeNodeResult.SUCCESS;
}
}

View File

@ -9,7 +9,7 @@ import electrosphere.entity.EntityUtils;
import electrosphere.entity.types.creature.CreatureUtils;
import electrosphere.server.ai.blackboard.Blackboard;
import electrosphere.server.ai.nodes.AITreeNode;
import electrosphere.server.ai.nodes.actions.combat.MeleeTargetingNode;
import electrosphere.server.ai.nodes.plan.TargetPositionNode;
import electrosphere.util.math.SpatialMathUtils;
/**
@ -17,18 +17,11 @@ import electrosphere.util.math.SpatialMathUtils;
*/
public class FaceTargetNode implements AITreeNode {
/**
* Constructor
*/
public FaceTargetNode(){
}
@Override
public AITreeNodeResult evaluate(Entity entity, Blackboard blackboard) {
if(MeleeTargetingNode.hasTarget(blackboard)){
Entity target = MeleeTargetingNode.getTarget(blackboard);
if(TargetPositionNode.hasMoveToTarget(blackboard)){
Vector3d parentPos = EntityUtils.getPosition(entity);
Vector3d targetPos = EntityUtils.getPosition(target);
Vector3d targetPos = TargetPositionNode.getMoveToTarget(blackboard);
Quaterniond rotation = SpatialMathUtils.calculateRotationFromPointToPoint(parentPos, targetPos);
EntityUtils.getRotation(entity).set(rotation);
CreatureUtils.setFacingVector(entity, CameraEntityUtils.getFacingVec(rotation));

View File

@ -5,6 +5,8 @@ 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.datacell.Realm;
import electrosphere.server.macro.MacroData;
import electrosphere.server.macro.character.Character;
import electrosphere.server.macro.character.CharacterUtils;
import electrosphere.server.macro.structure.Structure;
@ -16,8 +18,10 @@ public class HasShelter implements AITreeNode {
@Override
public AITreeNodeResult evaluate(Entity entity, Blackboard blackboard) {
Realm entityRealm = Globals.realmManager.getEntityRealm(entity);
MacroData macroData = entityRealm.getServerContentManager().getMacroData();
ServerCharacterData serverCharacterData = ServerCharacterData.getServerCharacterData(entity);
Character character = Globals.macroData.getCharacter(serverCharacterData.getCharacterId());
Character character = macroData.getCharacter(serverCharacterData.getCharacterId());
Structure shelter = CharacterUtils.getShelter(character);
if(shelter == null){
return AITreeNodeResult.FAILURE;

View File

@ -0,0 +1,23 @@
package electrosphere.server.ai.nodes.checks.macro;
import electrosphere.engine.Globals;
import electrosphere.entity.Entity;
import electrosphere.server.ai.blackboard.Blackboard;
import electrosphere.server.ai.nodes.AITreeNode;
import electrosphere.server.datacell.Realm;
/**
* Checks that macro data exists
*/
public class MacroDataExists implements AITreeNode {
@Override
public AITreeNodeResult evaluate(Entity entity, Blackboard blackboard) {
Realm entityRealm = Globals.realmManager.getEntityRealm(entity);
if(entityRealm.getServerContentManager().getMacroData() == null){
return AITreeNodeResult.FAILURE;
}
return AITreeNodeResult.SUCCESS;
}
}

View File

@ -0,0 +1,44 @@
package electrosphere.server.ai.nodes.checks.spatial;
import org.joml.Vector3d;
import electrosphere.entity.Entity;
import electrosphere.entity.EntityUtils;
import electrosphere.server.ai.blackboard.Blackboard;
import electrosphere.server.ai.nodes.AITreeNode;
import electrosphere.server.ai.nodes.plan.FindEntityTargetNode;
/**
* Checks if the target is inside a given range of the entity
*/
public class TargetRangeCheck implements AITreeNode {
/**
* The distance to succeed within
*/
double dist;
/**
* Constructor
* @param dist The distance outside of which the node will fail
*/
public TargetRangeCheck(double dist){
this.dist = dist;
}
@Override
public AITreeNodeResult evaluate(Entity entity, Blackboard blackboard) {
if(!FindEntityTargetNode.hasTarget(blackboard)){
return AITreeNodeResult.FAILURE;
}
Entity target = FindEntityTargetNode.getTarget(blackboard);
Vector3d targetPos = EntityUtils.getPosition(target);
Vector3d entPos = EntityUtils.getPosition(entity);
if(targetPos.distance(entPos) < this.dist){
return AITreeNodeResult.SUCCESS;
} else {
return AITreeNodeResult.FAILURE;
}
}
}

View File

@ -0,0 +1,16 @@
package electrosphere.server.ai.nodes.plan;
import electrosphere.entity.Entity;
import electrosphere.server.ai.blackboard.Blackboard;
import electrosphere.server.ai.nodes.AITreeNode;
/**
* A node that performs functions to try to build a structure
*/
public class BuildStructureNode implements AITreeNode {
@Override
public AITreeNodeResult evaluate(Entity entity, Blackboard blackboard) {
return AITreeNodeResult.SUCCESS;
}
}

View File

@ -0,0 +1,56 @@
package electrosphere.server.ai.nodes.plan;
import electrosphere.entity.Entity;
import electrosphere.entity.state.block.ServerBlockTree;
import electrosphere.server.ai.blackboard.Blackboard;
import electrosphere.server.ai.blackboard.BlackboardKeys;
import electrosphere.server.ai.nodes.AITreeNode;
/**
* Finds a target given some criteria
*/
public class FindEntityTargetNode implements AITreeNode {
@Override
public AITreeNodeResult evaluate(Entity entity, Blackboard blackboard){
if(ServerBlockTree.getServerBlockTree(entity) != null){
ServerBlockTree serverBlockTree = ServerBlockTree.getServerBlockTree(entity);
if(serverBlockTree.isIdle()){
serverBlockTree.start();
return AITreeNodeResult.SUCCESS;
} else {
return AITreeNodeResult.RUNNING;
}
} else {
return AITreeNodeResult.FAILURE;
}
}
/**
* Sets the target in the blackboard
* @param blackboard The blackboard
* @param target The target
*/
public static void setTarget(Blackboard blackboard, Entity target){
blackboard.put(BlackboardKeys.ENTITY_TARGET, target);
}
/**
* Gets the currently targeted entity
* @param blackboard The blackboard
* @return The entity target if it exists, null otherwise
*/
public static Entity getTarget(Blackboard blackboard){
return (Entity)blackboard.get(BlackboardKeys.ENTITY_TARGET);
}
/**
* Checks if the blackboard has a currently targeted entity
* @param blackboard The blackboard
* @return true if it has a currently targeted entity, false otherwise
*/
public static boolean hasTarget(Blackboard blackboard){
return blackboard.has(BlackboardKeys.ENTITY_TARGET);
}
}

View File

@ -0,0 +1,35 @@
package electrosphere.server.ai.nodes.plan;
import electrosphere.entity.Entity;
import electrosphere.server.ai.blackboard.Blackboard;
import electrosphere.server.ai.nodes.AITreeNode;
/**
* Sets the type of structure to build
*/
public class SetBuildGoalNode implements AITreeNode {
/**
* A shelter structure type
*/
public static final String STRUCTURE_TYPE_SHELTER = "shelter";
/**
* The type of structure
*/
String type;
/**
* Constructor
* @param type The type to set the build goal to
*/
public SetBuildGoalNode(String type){
this.type = type;
}
@Override
public AITreeNodeResult evaluate(Entity entity, Blackboard blackboard){
return AITreeNodeResult.SUCCESS;
}
}

View File

@ -0,0 +1,54 @@
package electrosphere.server.ai.nodes.plan;
import org.joml.Vector3d;
import electrosphere.entity.Entity;
import electrosphere.entity.EntityUtils;
import electrosphere.server.ai.blackboard.Blackboard;
import electrosphere.server.ai.blackboard.BlackboardKeys;
import electrosphere.server.ai.nodes.AITreeNode;
/**
* Sets the move-to target position to the position of the targeted entity
*/
public class TargetPositionNode implements AITreeNode {
@Override
public AITreeNodeResult evaluate(Entity entity, Blackboard blackboard){
if(!FindEntityTargetNode.hasTarget(blackboard)){
return AITreeNodeResult.FAILURE;
}
Entity target = FindEntityTargetNode.getTarget(blackboard);
Vector3d targetPos = EntityUtils.getPosition(target);
TargetPositionNode.setMoveToTarget(blackboard, targetPos);
return AITreeNodeResult.SUCCESS;
}
/**
* Sets the move-to target of the blackboard
* @param blackboard The blackboard
* @param position The target position
*/
public static void setMoveToTarget(Blackboard blackboard, Vector3d position){
blackboard.put(BlackboardKeys.MOVE_TO_TARGET, position);
}
/**
* Gets the move-to target of the blackboard
* @param blackboard The blackboard
* @return The move-to target if it exists, null otherwise
*/
public static Vector3d getMoveToTarget(Blackboard blackboard){
return (Vector3d)blackboard.get(BlackboardKeys.MOVE_TO_TARGET);
}
/**
* Checks if the blackboard has a move to target
* @param blackboard the blackboard
* @return true if it has a move-to target, false otherwise
*/
public static boolean hasMoveToTarget(Blackboard blackboard){
return blackboard.has(BlackboardKeys.MOVE_TO_TARGET);
}
}

View File

@ -0,0 +1,64 @@
package electrosphere.server.ai.services;
import java.util.Collection;
import org.joml.Vector3d;
import electrosphere.engine.Globals;
import electrosphere.entity.Entity;
import electrosphere.entity.EntityUtils;
import electrosphere.server.ai.AI;
import electrosphere.server.ai.blackboard.Blackboard;
import electrosphere.server.ai.blackboard.BlackboardKeys;
import electrosphere.server.datacell.Realm;
/**
* Gets the entities that are near this entity
*/
public class NearbyEntityService implements AIService {
/**
* Distance to search for nearby entities
*/
static final double SEARCH_DIST = 32;
@Override
public void exec(){
for(AI ai : Globals.aiManager.getAIList()){
Entity entity = ai.getParent();
Realm realm = Globals.realmManager.getEntityRealm(entity);
Vector3d position = EntityUtils.getPosition(entity);
Collection<Entity> nearbyEntities = realm.getDataCellManager().entityLookup(position, NearbyEntityService.SEARCH_DIST);
NearbyEntityService.setNearbyEntities(ai.getBlackboard(), nearbyEntities);
}
}
/**
* Sets the nearby entities
* @param blackboard The blackboard
* @param entities The nearby entities
*/
public static void setNearbyEntities(Blackboard blackboard, Collection<Entity> entities){
blackboard.put(BlackboardKeys.NEARBY_ENTITIES, entities);
}
/**
* Gets the nearby entities
* @param blackboard The blackboard
* @return The nearby entities
*/
@SuppressWarnings("unchecked")
public static Collection<Entity> getNearbyEntities(Blackboard blackboard){
return (Collection<Entity>)blackboard.get(BlackboardKeys.NEARBY_ENTITIES);
}
/**
* Checks if the blackboard stores nearby entities
* @param blackboard The blackboard
* @return true if it stores nearby entities, false otherwise
*/
public static boolean hasNearbyEntities(Blackboard blackboard){
return blackboard.has(BlackboardKeys.NEARBY_ENTITIES);
}
}

View File

@ -0,0 +1,49 @@
package electrosphere.server.ai.trees.creature;
import electrosphere.entity.state.movement.groundmove.ClientGroundMovementTree.MovementRelativeFacing;
import electrosphere.server.ai.nodes.AITreeNode;
import electrosphere.server.ai.nodes.actions.move.FaceTargetNode;
import electrosphere.server.ai.nodes.actions.move.MoveStartNode;
import electrosphere.server.ai.nodes.actions.move.MoveStopNode;
import electrosphere.server.ai.nodes.checks.spatial.TargetRangeCheck;
import electrosphere.server.ai.nodes.meta.collections.SelectorNode;
import electrosphere.server.ai.nodes.meta.collections.SequenceNode;
import electrosphere.server.ai.nodes.meta.decorators.RunnerNode;
import electrosphere.server.ai.nodes.meta.decorators.SucceederNode;
import electrosphere.server.ai.nodes.plan.TargetPositionNode;
/**
* Moves to a target
*/
public class MoveToTarget {
/**
* Name of the tree
*/
public static final String TREE_NAME = "MoveTo";
/**
* Creates a move-to-target tree
* @param dist The target distance to be within
* @return The root node of the move-to-target tree
*/
public static AITreeNode create(double dist){
return new SelectorNode(
new SequenceNode(
//check if in range of target
new TargetRangeCheck(0),
//if in range, stop moving fowards and return SUCCESS
new SucceederNode(new MoveStopNode())
),
//not in range of target, keep moving towards it
new SequenceNode(
new TargetPositionNode(),
//check that dependencies exist
new FaceTargetNode(),
new RunnerNode(new MoveStartNode(MovementRelativeFacing.FORWARD))
)
);
}
}

View File

@ -1,7 +1,10 @@
package electrosphere.server.ai.trees.hierarchy;
import electrosphere.server.ai.nodes.AITreeNode;
import electrosphere.server.ai.nodes.checks.macro.IsCharacterNode;
import electrosphere.server.ai.nodes.checks.macro.MacroDataExists;
import electrosphere.server.ai.nodes.meta.collections.SequenceNode;
import electrosphere.server.ai.nodes.meta.debug.PublishStatusNode;
import electrosphere.server.ai.trees.hierarchy.safety.MaslowSafetyTree;
/**
@ -20,6 +23,14 @@ public class MaslowTree {
*/
public static AITreeNode create(){
return new SequenceNode(
//check that dependencies exist
new SequenceNode(
new PublishStatusNode("Checking dependencies for maslow tree.."),
new MacroDataExists(),
new IsCharacterNode()
),
//check the first tier of needs
MaslowSafetyTree.create()
);
}

View File

@ -1,6 +1,8 @@
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.nodes.meta.debug.PublishStatusNode;
import electrosphere.server.ai.nodes.meta.decorators.SucceederNode;
/**
@ -18,7 +20,10 @@ public class CombatTree {
* @return The root node of the tree
*/
public static AITreeNode create(){
return new SucceederNode(null);
return new SequenceNode(
new PublishStatusNode("Engaged in mortal combat"),
new SucceederNode(null)
);
}
}

View File

@ -1,6 +1,8 @@
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.nodes.meta.debug.PublishStatusNode;
import electrosphere.server.ai.nodes.meta.decorators.SucceederNode;
/**
@ -18,7 +20,10 @@ public class FleeTree {
* @return The root node of the tree
*/
public static AITreeNode create(){
return new SucceederNode(null);
return new SequenceNode(
new PublishStatusNode("Flee!"),
new SucceederNode(null)
);
}
}

View File

@ -2,6 +2,7 @@ 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.nodes.meta.debug.PublishStatusNode;
import electrosphere.server.ai.trees.hierarchy.safety.shelter.ShelterTree;
/**
@ -20,6 +21,7 @@ public class MaslowSafetyTree {
*/
public static AITreeNode create(){
return new SequenceNode(
new PublishStatusNode("Evaluate safety"),
FleeTree.create(),
CombatTree.create(),
ShelterTree.create()

View File

@ -1,6 +1,8 @@
package electrosphere.server.ai.trees.hierarchy.safety.shelter;
import electrosphere.server.ai.nodes.AITreeNode;
import electrosphere.server.ai.nodes.meta.collections.SequenceNode;
import electrosphere.server.ai.nodes.meta.debug.PublishStatusNode;
import electrosphere.server.ai.nodes.meta.decorators.SucceederNode;
/**
@ -18,6 +20,9 @@ public class ConstructShelterTree {
* @return The root node of the tree
*/
public static AITreeNode create(){
return new SucceederNode(null);
return new SequenceNode(
new PublishStatusNode("Construct a shelter"),
new SucceederNode(null)
);
}
}

View File

@ -5,6 +5,7 @@ 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;
import electrosphere.server.ai.nodes.meta.debug.PublishStatusNode;
/**
* A tree that causes the entity to try to secure shelter
@ -22,6 +23,7 @@ public class ShelterTree {
*/
public static AITreeNode create(){
return new SequenceNode(
new PublishStatusNode("Evaluate shelter"),
//make sure that this entity actually cares about shelter
new SequenceNode(
//if this is a character
@ -32,13 +34,13 @@ public class ShelterTree {
//if has shelter..
new SelectorNode(
new SequenceNode(
new HasShelter(),
//does not have shelter
ConstructShelterTree.create()
),
new SequenceNode(
new HasShelter()
//already has shelter
//TODO: check environment (ie time of day) to see if we should return to shelter
),
new SequenceNode(
//does not have shelter
ConstructShelterTree.create()
)
)
)

View File

@ -0,0 +1,25 @@
package electrosphere.server.ai.trees.jobs;
import electrosphere.server.ai.nodes.AITreeNode;
import electrosphere.server.ai.nodes.meta.collections.SequenceNode;
/**
* A tree that attempts to forage for items
*/
public class ForageTree {
/**
* Name of the tree
*/
public static final String TREE_NAME = "Forage";
/**
* Creates a foraging tree
* @return The root node of the tree
*/
public static AITreeNode create(){
return new SequenceNode(
);
}
}

View File

@ -1,5 +1,6 @@
package electrosphere.server.datacell;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
@ -7,10 +8,15 @@ import org.joml.Vector3d;
import org.joml.Vector3i;
import electrosphere.engine.Globals;
import electrosphere.entity.Entity;
import electrosphere.entity.EntityUtils;
import electrosphere.entity.scene.Scene;
import electrosphere.net.server.player.Player;
import electrosphere.server.datacell.interfaces.DataCellManager;
/**
* A viewport data cell manager
*/
public class ViewportDataCellManager implements DataCellManager {
/**
@ -125,5 +131,19 @@ public class ViewportDataCellManager implements DataCellManager {
public void halt(){
//does nothing
}
@Override
public Collection<Entity> entityLookup(Vector3d pos, double radius) {
List<Entity> rVal = new LinkedList<Entity>();
for(Entity entity : this.serverDataCell.getScene().getEntityList()){
// boundingSphere
Vector3d entPos = EntityUtils.getPosition(entity);
if(pos.distance(entPos) > radius){
continue;
}
rVal.add(entity);
}
return rVal;
}
}

View File

@ -1123,4 +1123,18 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager
LoggerInterface.loggerEngine.WARNING("Cell is ready: " + serverDataCell.isReady());
}
@Override
public Collection<Entity> entityLookup(Vector3d pos, double radius) {
List<Entity> rVal = new LinkedList<Entity>();
this.loadedCellsLock.lock();
for(ServerDataCell cell : this.groundDataCells.values()){
if(ServerWorldData.convertChunkToRealSpace(this.getCellWorldPosition(cell)).distance(pos) > radius){
continue;
}
rVal.addAll(cell.getScene().getEntityList());
}
this.loadedCellsLock.unlock();
return rVal;
}
}

View File

@ -1,8 +1,11 @@
package electrosphere.server.datacell.interfaces;
import java.util.Collection;
import org.joml.Vector3d;
import org.joml.Vector3i;
import electrosphere.entity.Entity;
import electrosphere.net.server.player.Player;
import electrosphere.server.datacell.ServerDataCell;
@ -86,5 +89,13 @@ public interface DataCellManager {
* Halts all asynchronous work being done in this data cell manager
*/
public void halt();
/**
* Looks up entities within a bounding sphere
* @param pos The position of the sphere
* @param radius The radius of the sphere
* @return The list of entities within the bounding sphere
*/
public Collection<Entity> entityLookup(Vector3d pos, double radius);
}

View File

@ -130,11 +130,7 @@ public class PlayerActions {
Entity playerEntity = EntityLookupUtils.getEntityById(connectionHandler.getPlayerEntityId());
switch(signal){
case InteractionData.ON_INTERACT_HARVEST: {
if(ServerLifeTree.hasServerLifeTree(target)){
ServerLifeTree serverLifeTree = ServerLifeTree.getServerLifeTree(target);
serverLifeTree.kill();
}
ServerScriptUtils.fireSignalOnEntity(playerEntity, "entityInteractHarvest", target);
PlayerActions.harvest(playerEntity, target);
} break;
case InteractionData.ON_INTERACT_DOOR: {
if(ServerDoorState.hasServerDoorState(target)){
@ -148,5 +144,18 @@ public class PlayerActions {
}
}
}
/**
* Tries to harvest the target as the creature
* @param creature The creature
* @param target The target to harvest
*/
public static void harvest(Entity creature, Entity target){
if(ServerLifeTree.hasServerLifeTree(target)){
ServerLifeTree serverLifeTree = ServerLifeTree.getServerLifeTree(target);
serverLifeTree.kill();
}
ServerScriptUtils.fireSignalOnEntity(creature, "entityInteractHarvest", target);
}
}

View File

@ -18,11 +18,11 @@ public class MacroSimulation {
* Iterates the macro simulation
*/
public void simulate(){
for(Character character : Globals.macroData.getAliveCharacters()){
//do something
MacroSimulation.checkForShelter(character);
MacroSimulation.checkTownMembership(character);
}
// for(Character character : Globals.macroData.getAliveCharacters()){
// //do something
// MacroSimulation.checkForShelter(character);
// MacroSimulation.checkTownMembership(character);
// }
}
/**