This commit is contained in:
parent
4908ea0f44
commit
48622bb08f
@ -3,7 +3,8 @@
|
|||||||
{
|
{
|
||||||
"id" : "bush4",
|
"id" : "bush4",
|
||||||
"tokens" : [
|
"tokens" : [
|
||||||
"FLAMMABLE"
|
"FLAMMABLE",
|
||||||
|
"HARVESTABLE"
|
||||||
],
|
],
|
||||||
"hitboxes" : [
|
"hitboxes" : [
|
||||||
{
|
{
|
||||||
|
|||||||
@ -3,6 +3,7 @@
|
|||||||
{
|
{
|
||||||
"id" : "rock_static",
|
"id" : "rock_static",
|
||||||
"tokens" : [
|
"tokens" : [
|
||||||
|
"HARVESTABLE"
|
||||||
],
|
],
|
||||||
"buttonInteraction" : {
|
"buttonInteraction" : {
|
||||||
"onInteract" : "harvest",
|
"onInteract" : "harvest",
|
||||||
|
|||||||
@ -5,7 +5,8 @@
|
|||||||
"maxStack" : 100,
|
"maxStack" : 100,
|
||||||
"tokens" : [
|
"tokens" : [
|
||||||
"GRAVITY",
|
"GRAVITY",
|
||||||
"TARGETABLE"
|
"TARGETABLE",
|
||||||
|
"HARVESTABLE"
|
||||||
],
|
],
|
||||||
"itemAudio": {
|
"itemAudio": {
|
||||||
"uiGrabAudio" : "Audio/ui/items/specific/Pick Up Stone A.wav",
|
"uiGrabAudio" : "Audio/ui/items/specific/Pick Up Stone A.wav",
|
||||||
|
|||||||
@ -5,7 +5,8 @@
|
|||||||
"maxStack" : 100,
|
"maxStack" : 100,
|
||||||
"tokens" : [
|
"tokens" : [
|
||||||
"GRAVITY",
|
"GRAVITY",
|
||||||
"TARGETABLE"
|
"TARGETABLE",
|
||||||
|
"HARVESTABLE"
|
||||||
],
|
],
|
||||||
"itemAudio": {
|
"itemAudio": {
|
||||||
"uiGrabAudio" : "Audio/ui/items/specific/Pick Up Wood A.wav",
|
"uiGrabAudio" : "Audio/ui/items/specific/Pick Up Wood A.wav",
|
||||||
|
|||||||
@ -20,6 +20,7 @@
|
|||||||
"files": [
|
"files": [
|
||||||
"Data/game/recipes/weapons.json",
|
"Data/game/recipes/weapons.json",
|
||||||
"Data/game/recipes/tools.json",
|
"Data/game/recipes/tools.json",
|
||||||
"Data/game/recipes/fabs.json"
|
"Data/game/recipes/fabs.json",
|
||||||
|
"Data/game/recipes/voxelrecipes.json"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
23
assets/Data/game/recipes/voxelrecipes.json
Normal file
23
assets/Data/game/recipes/voxelrecipes.json
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
"recipes": [
|
||||||
|
{
|
||||||
|
"displayName": "Refiend Wood",
|
||||||
|
"craftingTag" : "HAND",
|
||||||
|
"ingredients": [
|
||||||
|
{
|
||||||
|
"itemType": "mat:Log",
|
||||||
|
"count": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"products": [
|
||||||
|
{
|
||||||
|
"itemType": "block:refined_wood",
|
||||||
|
"count": 1
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"files": [
|
||||||
|
|
||||||
|
]
|
||||||
|
}
|
||||||
@ -1607,7 +1607,7 @@ Items keep charge state
|
|||||||
UI renders charge state
|
UI renders charge state
|
||||||
Item stacking
|
Item stacking
|
||||||
|
|
||||||
(04/20/2025)
|
(04/30/2025)
|
||||||
Voxel placement improvements
|
Voxel placement improvements
|
||||||
Smaller wall section
|
Smaller wall section
|
||||||
First proper house~!
|
First proper house~!
|
||||||
@ -1630,6 +1630,10 @@ DB characters store toolbar items
|
|||||||
Scaffolding for new macro-cognizating ai approach
|
Scaffolding for new macro-cognizating ai approach
|
||||||
AI work
|
AI work
|
||||||
|
|
||||||
|
(05/01/2025)
|
||||||
|
Many new AI trees
|
||||||
|
- AI can seek out items
|
||||||
|
- AI can harvest entities
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -349,7 +349,8 @@ public class CameraEntityUtils {
|
|||||||
*/
|
*/
|
||||||
public static Vector3d getFacingVec(Quaterniond rotation){
|
public static Vector3d getFacingVec(Quaterniond rotation){
|
||||||
//quaternion is multiplied by pi because we want to point away from the eye of the camera, NOT towards it
|
//quaternion is multiplied by pi because we want to point away from the eye of the camera, NOT towards it
|
||||||
Matrix4d rotationMat = new Matrix4d().rotate(rotation);
|
Quaterniond quatd = new Quaterniond(rotation).normalize();
|
||||||
|
Matrix4d rotationMat = new Matrix4d().rotate(quatd);
|
||||||
Vector4d rotationVecRaw = SpatialMathUtils.getOriginVector4();
|
Vector4d rotationVecRaw = SpatialMathUtils.getOriginVector4();
|
||||||
rotationVecRaw = rotationMat.transform(rotationVecRaw);
|
rotationVecRaw = rotationMat.transform(rotationVecRaw);
|
||||||
if(rotationVecRaw.length() < 0.001){
|
if(rotationVecRaw.length() < 0.001){
|
||||||
|
|||||||
@ -747,4 +747,21 @@ public class InventoryUtils {
|
|||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the enity has a given type of tool
|
||||||
|
* @param entity The entity
|
||||||
|
* @param toolType The type of tool
|
||||||
|
* @return true if it has the type of tool, false otherwise
|
||||||
|
*/
|
||||||
|
public static boolean serverHasTool(Entity entity, String toolType){
|
||||||
|
List<Entity> items = InventoryUtils.getAllInventoryItems(entity);
|
||||||
|
for(Entity itemEnt : items){
|
||||||
|
Item itemData = Globals.gameConfigCurrent.getItemMap().getItem(itemEnt);
|
||||||
|
if(itemData.getTokens().contains(toolType)){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -124,9 +124,11 @@ public class ServerLifeTree implements BehaviorTree {
|
|||||||
* Kills the entity
|
* Kills the entity
|
||||||
*/
|
*/
|
||||||
public void kill(){
|
public void kill(){
|
||||||
|
if(this.getState() == LifeStateEnum.ALIVE){
|
||||||
lifeCurrent = 0;
|
lifeCurrent = 0;
|
||||||
this.setState(LifeStateEnum.DYING);
|
this.setState(LifeStateEnum.DYING);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Roll the loot pool
|
* Roll the loot pool
|
||||||
|
|||||||
@ -31,6 +31,7 @@ import electrosphere.net.synchronization.enums.BehaviorTreeIdEnums;
|
|||||||
import electrosphere.net.synchronization.enums.FieldIdEnums;
|
import electrosphere.net.synchronization.enums.FieldIdEnums;
|
||||||
import electrosphere.renderer.anim.Animation;
|
import electrosphere.renderer.anim.Animation;
|
||||||
import electrosphere.script.utils.AccessTransforms;
|
import electrosphere.script.utils.AccessTransforms;
|
||||||
|
import electrosphere.server.ai.AI;
|
||||||
import electrosphere.server.datacell.utils.DataCellSearchUtils;
|
import electrosphere.server.datacell.utils.DataCellSearchUtils;
|
||||||
import electrosphere.server.utils.ServerScriptUtils;
|
import electrosphere.server.utils.ServerScriptUtils;
|
||||||
import electrosphere.util.math.SpatialMathUtils;
|
import electrosphere.util.math.SpatialMathUtils;
|
||||||
@ -175,9 +176,11 @@ public class ServerGroundMovementTree implements BehaviorTree {
|
|||||||
Vector3d position = EntityUtils.getPosition(parent);
|
Vector3d position = EntityUtils.getPosition(parent);
|
||||||
Vector3d facingVector = CreatureUtils.getFacingVector(parent);
|
Vector3d facingVector = CreatureUtils.getFacingVector(parent);
|
||||||
if(ServerPlayerViewDirTree.hasTree(parent)){
|
if(ServerPlayerViewDirTree.hasTree(parent)){
|
||||||
|
if(AI.getAI(parent) == null || !AI.getAI(parent).isApplyToPlayer()){
|
||||||
ServerPlayerViewDirTree serverViewTree =ServerPlayerViewDirTree.getTree(parent);
|
ServerPlayerViewDirTree serverViewTree =ServerPlayerViewDirTree.getTree(parent);
|
||||||
facingVector = CameraEntityUtils.getFacingVec(serverViewTree.getYaw(), serverViewTree.getPitch());
|
facingVector = CameraEntityUtils.getFacingVec(serverViewTree.getYaw(), serverViewTree.getPitch());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
DBody body = PhysicsEntityUtils.getDBody(parent);
|
DBody body = PhysicsEntityUtils.getDBody(parent);
|
||||||
DVector3C linearVelocity = body.getLinearVel();
|
DVector3C linearVelocity = body.getLinearVel();
|
||||||
|
|
||||||
|
|||||||
@ -19,7 +19,9 @@ import electrosphere.entity.Entity;
|
|||||||
import electrosphere.entity.EntityCreationUtils;
|
import electrosphere.entity.EntityCreationUtils;
|
||||||
import electrosphere.entity.EntityDataStrings;
|
import electrosphere.entity.EntityDataStrings;
|
||||||
import electrosphere.entity.EntityUtils;
|
import electrosphere.entity.EntityUtils;
|
||||||
|
import electrosphere.entity.types.EntityTypes.EntityType;
|
||||||
import electrosphere.entity.types.collision.CollisionObjUtils;
|
import electrosphere.entity.types.collision.CollisionObjUtils;
|
||||||
|
import electrosphere.entity.types.common.CommonEntityUtils;
|
||||||
import electrosphere.logger.LoggerInterface;
|
import electrosphere.logger.LoggerInterface;
|
||||||
import electrosphere.renderer.meshgen.BlockMeshgen;
|
import electrosphere.renderer.meshgen.BlockMeshgen;
|
||||||
import electrosphere.renderer.meshgen.BlockMeshgen.BlockMeshData;
|
import electrosphere.renderer.meshgen.BlockMeshgen.BlockMeshData;
|
||||||
@ -119,6 +121,7 @@ public class BlockChunkEntity {
|
|||||||
Quaterniond entityRot = EntityUtils.getRotation(entity);
|
Quaterniond entityRot = EntityUtils.getRotation(entity);
|
||||||
PhysicsUtils.setRigidBodyTransform(realm.getCollisionEngine(), entityPos, entityRot, terrainBody);
|
PhysicsUtils.setRigidBodyTransform(realm.getCollisionEngine(), entityPos, entityRot, terrainBody);
|
||||||
entity.putData(EntityDataStrings.TERRAIN_IS_TERRAIN, true);
|
entity.putData(EntityDataStrings.TERRAIN_IS_TERRAIN, true);
|
||||||
|
CommonEntityUtils.setEntityType(entity, EntityType.ENGINE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -136,6 +136,7 @@ public class TerrainChunk {
|
|||||||
Quaterniond entityRot = EntityUtils.getRotation(entity);
|
Quaterniond entityRot = EntityUtils.getRotation(entity);
|
||||||
PhysicsUtils.setRigidBodyTransform(realm.getCollisionEngine(), entityPos, entityRot, terrainBody);
|
PhysicsUtils.setRigidBodyTransform(realm.getCollisionEngine(), entityPos, entityRot, terrainBody);
|
||||||
entity.putData(EntityDataStrings.TERRAIN_IS_TERRAIN, true);
|
entity.putData(EntityDataStrings.TERRAIN_IS_TERRAIN, true);
|
||||||
|
CommonEntityUtils.setEntityType(entity, EntityType.ENGINE);
|
||||||
}
|
}
|
||||||
// ServerEntityUtils.initiallyPositionEntity(realm, rVal, position);
|
// ServerEntityUtils.initiallyPositionEntity(realm, rVal, position);
|
||||||
// physicsObject = PhysicsUtils.attachTerrainRigidBody(physicsEntity,heightmap,true);
|
// physicsObject = PhysicsUtils.attachTerrainRigidBody(physicsEntity,heightmap,true);
|
||||||
|
|||||||
@ -18,6 +18,7 @@ import electrosphere.game.data.foliage.type.FoliageType;
|
|||||||
import electrosphere.game.data.foliage.type.FoliageTypeLoader;
|
import electrosphere.game.data.foliage.type.FoliageTypeLoader;
|
||||||
import electrosphere.game.data.foliage.type.model.FoliageTypeMap;
|
import electrosphere.game.data.foliage.type.model.FoliageTypeMap;
|
||||||
import electrosphere.game.data.item.ItemDataMap;
|
import electrosphere.game.data.item.ItemDataMap;
|
||||||
|
import electrosphere.game.data.item.source.ItemSourcingMap;
|
||||||
import electrosphere.game.data.projectile.ProjectileTypeHolder;
|
import electrosphere.game.data.projectile.ProjectileTypeHolder;
|
||||||
import electrosphere.game.data.struct.StructureDataLoader;
|
import electrosphere.game.data.struct.StructureDataLoader;
|
||||||
import electrosphere.game.data.tutorial.HintDefinition;
|
import electrosphere.game.data.tutorial.HintDefinition;
|
||||||
@ -96,6 +97,11 @@ public class Config {
|
|||||||
*/
|
*/
|
||||||
StructureDataLoader structureData;
|
StructureDataLoader structureData;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The item sourcing map for items
|
||||||
|
*/
|
||||||
|
ItemSourcingMap itemSourcingMap;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads the default data
|
* Loads the default data
|
||||||
* @return The config
|
* @return The config
|
||||||
@ -124,6 +130,9 @@ public class Config {
|
|||||||
ItemDataMap.loadSpawnItems(config.itemMap, config.objectTypeLoader);
|
ItemDataMap.loadSpawnItems(config.itemMap, config.objectTypeLoader);
|
||||||
ItemDataMap.generateBlockItems(config.itemMap, config.blockData);
|
ItemDataMap.generateBlockItems(config.itemMap, config.blockData);
|
||||||
|
|
||||||
|
//construct the sourcing map
|
||||||
|
config.itemSourcingMap = ItemSourcingMap.parse(config);
|
||||||
|
|
||||||
//validate
|
//validate
|
||||||
ConfigValidator.valdiate(config);
|
ConfigValidator.valdiate(config);
|
||||||
|
|
||||||
@ -376,4 +385,12 @@ public class Config {
|
|||||||
return this.structureData;
|
return this.structureData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the item sourcing map of the config
|
||||||
|
* @return The item sourcing map
|
||||||
|
*/
|
||||||
|
public ItemSourcingMap getItemSourcingMap(){
|
||||||
|
return this.itemSourcingMap;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,23 @@
|
|||||||
|
package electrosphere.game.data.common;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* All common entity tokens
|
||||||
|
*/
|
||||||
|
public class CommonEntityTokens {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This entity is a tree foliage type
|
||||||
|
*/
|
||||||
|
public static final String TOKEN_TREE = "TREE";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An axe
|
||||||
|
*/
|
||||||
|
public static final String TOKEN_AXE = "AXE";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flags this object as harvestable
|
||||||
|
*/
|
||||||
|
public static final String TOKEN_HARVESTABLE = "HARVESTABLE";
|
||||||
|
|
||||||
|
}
|
||||||
@ -124,6 +124,15 @@ public class Item extends CommonEntityType {
|
|||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the id of the item type for a given block type
|
||||||
|
* @param blockType The block type
|
||||||
|
* @return The id of the corresponding item data
|
||||||
|
*/
|
||||||
|
public static String getBlockTypeId(BlockType blockType){
|
||||||
|
return "block:" + blockType.getName();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates item data from a block type
|
* Creates item data from a block type
|
||||||
* @param description The block type
|
* @param description The block type
|
||||||
@ -131,7 +140,7 @@ public class Item extends CommonEntityType {
|
|||||||
*/
|
*/
|
||||||
public static Item createBlockItem(BlockType blockType){
|
public static Item createBlockItem(BlockType blockType){
|
||||||
Item rVal = new Item();
|
Item rVal = new Item();
|
||||||
rVal.setId("block:" + blockType.getName());
|
rVal.setId(Item.getBlockTypeId(blockType));
|
||||||
|
|
||||||
|
|
||||||
if(blockType.getTexture() != null){
|
if(blockType.getTexture() != null){
|
||||||
|
|||||||
@ -0,0 +1,13 @@
|
|||||||
|
package electrosphere.game.data.item;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hardcoded item ids for items
|
||||||
|
*/
|
||||||
|
public class ItemIdStrings {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The basic stone axe
|
||||||
|
*/
|
||||||
|
public static final String ITEM_STONE_AXE = "Stone Axe";
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,85 @@
|
|||||||
|
package electrosphere.game.data.item.source;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import electrosphere.game.data.common.CommonEntityType;
|
||||||
|
import electrosphere.game.data.crafting.RecipeData;
|
||||||
|
import electrosphere.game.data.foliage.type.FoliageType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data that stores how an item can be sources
|
||||||
|
*/
|
||||||
|
public class ItemSourcingData {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Types of sources for items
|
||||||
|
*/
|
||||||
|
public static enum SourcingType {
|
||||||
|
/**
|
||||||
|
* Craft a recipe
|
||||||
|
*/
|
||||||
|
RECIPE,
|
||||||
|
/**
|
||||||
|
* Harvest from an item
|
||||||
|
*/
|
||||||
|
HARVEST,
|
||||||
|
/**
|
||||||
|
* Fell a tree
|
||||||
|
*/
|
||||||
|
TREE,
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The list of recipes that create this item
|
||||||
|
*/
|
||||||
|
List<RecipeData> recipes;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The list of harvesting targets that can drop this item
|
||||||
|
*/
|
||||||
|
List<CommonEntityType> harvestTargets;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The list of trees that can drop this item
|
||||||
|
*/
|
||||||
|
List<FoliageType> trees;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
* @param recipes The recipes to source from
|
||||||
|
* @param harvestTargets The objects to harvest from
|
||||||
|
* @param trees The trees to drop from
|
||||||
|
*/
|
||||||
|
public ItemSourcingData(List<RecipeData> recipes, List<CommonEntityType> harvestTargets, List<FoliageType> trees){
|
||||||
|
this.recipes = recipes;
|
||||||
|
this.harvestTargets = harvestTargets;
|
||||||
|
this.trees = trees;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the list of recipes that can produce this item
|
||||||
|
* @return The list of recipes
|
||||||
|
*/
|
||||||
|
public List<RecipeData> getRecipes() {
|
||||||
|
return recipes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the list of harvest targets that can drop this item
|
||||||
|
* @return The list of harvest targets
|
||||||
|
*/
|
||||||
|
public List<CommonEntityType> getHarvestTargets() {
|
||||||
|
return harvestTargets;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the list of trees that can drop this item
|
||||||
|
* @return The list of trees
|
||||||
|
*/
|
||||||
|
public List<FoliageType> getTrees() {
|
||||||
|
return trees;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,129 @@
|
|||||||
|
package electrosphere.game.data.item.source;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import electrosphere.game.data.Config;
|
||||||
|
import electrosphere.game.data.common.CommonEntityTokens;
|
||||||
|
import electrosphere.game.data.common.CommonEntityType;
|
||||||
|
import electrosphere.game.data.common.life.loot.LootPool;
|
||||||
|
import electrosphere.game.data.common.life.loot.LootTicket;
|
||||||
|
import electrosphere.game.data.crafting.RecipeData;
|
||||||
|
import electrosphere.game.data.crafting.RecipeDataMap;
|
||||||
|
import electrosphere.game.data.crafting.RecipeIngredientData;
|
||||||
|
import electrosphere.game.data.foliage.type.FoliageType;
|
||||||
|
import electrosphere.game.data.foliage.type.FoliageTypeLoader;
|
||||||
|
import electrosphere.game.data.item.Item;
|
||||||
|
import electrosphere.game.data.item.ItemDataMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Map of items to the methods to source them
|
||||||
|
*/
|
||||||
|
public class ItemSourcingMap {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Map of item id -> sourcing data
|
||||||
|
*/
|
||||||
|
private Map<String,ItemSourcingData> itemSourcingDataMap = new HashMap<String,ItemSourcingData>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a sourcing map from a given config
|
||||||
|
* @param config The config
|
||||||
|
* @return The sourcing map
|
||||||
|
*/
|
||||||
|
public static ItemSourcingMap parse(Config config){
|
||||||
|
ItemSourcingMap sourcingMap = new ItemSourcingMap();
|
||||||
|
|
||||||
|
RecipeDataMap recipeMap = config.getRecipeMap();
|
||||||
|
ItemDataMap itemMap = config.getItemMap();
|
||||||
|
FoliageTypeLoader foliageMap = config.getFoliageMap();
|
||||||
|
|
||||||
|
//structures that store sources
|
||||||
|
List<RecipeData> recipes;
|
||||||
|
List<CommonEntityType> harvestTargets;
|
||||||
|
List<FoliageType> trees;
|
||||||
|
|
||||||
|
//iterate through each item and find where they can be sources
|
||||||
|
for(Item item : itemMap.getTypes()){
|
||||||
|
//construct new lists for each item type
|
||||||
|
recipes = new LinkedList<RecipeData>();
|
||||||
|
harvestTargets = new LinkedList<CommonEntityType>();
|
||||||
|
trees = new LinkedList<FoliageType>();
|
||||||
|
//check if any recipes can create this item
|
||||||
|
for(RecipeData recipe : recipeMap.getTypes()){
|
||||||
|
for(RecipeIngredientData product : recipe.getProducts()){
|
||||||
|
if(product.getItemType().equals(item.getId())){
|
||||||
|
recipes.add(recipe);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//check if any common objects can from this item as loot
|
||||||
|
for(CommonEntityType foliageEnt : foliageMap.getTypes()){
|
||||||
|
if(foliageEnt.getTokens() == null){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(!foliageEnt.getTokens().contains(CommonEntityTokens.TOKEN_HARVESTABLE)){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(foliageEnt.getHealthSystem() != null){
|
||||||
|
if(foliageEnt.getHealthSystem().getLootPool() != null){
|
||||||
|
LootPool lootPool = foliageEnt.getHealthSystem().getLootPool();
|
||||||
|
for(LootTicket ticket : lootPool.getTickets()){
|
||||||
|
if(ticket.getItemId().equals(item.getId())){
|
||||||
|
harvestTargets.add(foliageEnt);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//check if any trees can drop the item
|
||||||
|
for(FoliageType foliage : foliageMap.getTypes()){
|
||||||
|
if(foliage.getTokens() != null && foliage.getTokens().contains(CommonEntityTokens.TOKEN_TREE)){
|
||||||
|
if(foliage.getHealthSystem() != null){
|
||||||
|
if(foliage.getHealthSystem().getLootPool() != null){
|
||||||
|
LootPool lootPool = foliage.getHealthSystem().getLootPool();
|
||||||
|
for(LootTicket ticket : lootPool.getTickets()){
|
||||||
|
if(ticket.getItemId().equals(item.getId())){
|
||||||
|
trees.add(foliage);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//store the sourcing data
|
||||||
|
ItemSourcingData sourcingData = new ItemSourcingData(recipes, harvestTargets, trees);
|
||||||
|
sourcingMap.itemSourcingDataMap.put(item.getId(),sourcingData);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return sourcingMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the sourcing data for a given item type
|
||||||
|
* @param itemId The item type
|
||||||
|
* @return The sourcing data for that type of item
|
||||||
|
*/
|
||||||
|
public ItemSourcingData getSourcingData(String itemId){
|
||||||
|
return itemSourcingDataMap.get(itemId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the sourcing data for a given item type
|
||||||
|
* @param item The item data
|
||||||
|
* @return The sourcing data for that type of item
|
||||||
|
*/
|
||||||
|
public ItemSourcingData getSourcingData(Item item){
|
||||||
|
return itemSourcingDataMap.get(item.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,138 @@
|
|||||||
|
package electrosphere.game.data.item.source;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import electrosphere.engine.Globals;
|
||||||
|
import electrosphere.entity.Entity;
|
||||||
|
import electrosphere.entity.state.inventory.InventoryUtils;
|
||||||
|
import electrosphere.entity.types.item.ItemUtils;
|
||||||
|
import electrosphere.game.data.common.CommonEntityTokens;
|
||||||
|
import electrosphere.game.data.crafting.RecipeData;
|
||||||
|
import electrosphere.game.data.crafting.RecipeIngredientData;
|
||||||
|
import electrosphere.game.data.item.ItemIdStrings;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A tree of dependencies to acquire a final item
|
||||||
|
*/
|
||||||
|
public class ItemSourcingTree {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The root item to search for
|
||||||
|
*/
|
||||||
|
String rootItemId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The map of item id -> specific
|
||||||
|
*/
|
||||||
|
Map<String,ItemSourcingData> itemSourceMap = new HashMap<String,ItemSourcingData>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an item sourcing tree
|
||||||
|
* @param itemType The type of item to source
|
||||||
|
* @return The tree of dependencies to get the item
|
||||||
|
*/
|
||||||
|
public static ItemSourcingTree create(String itemType){
|
||||||
|
ItemSourcingTree rVal = new ItemSourcingTree();
|
||||||
|
rVal.rootItemId = itemType;
|
||||||
|
rVal.evaluate();
|
||||||
|
return rVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Evaluates what items are still depended upon
|
||||||
|
*/
|
||||||
|
public void evaluate(){
|
||||||
|
//all items that haven't had sources solved for yet
|
||||||
|
List<String> unsolvedItems = new LinkedList<String>();
|
||||||
|
unsolvedItems.add(this.rootItemId);
|
||||||
|
|
||||||
|
while(unsolvedItems.size() > 0){
|
||||||
|
String currentId = unsolvedItems.remove(0);
|
||||||
|
ItemSourcingData sourcingData = Globals.gameConfigCurrent.getItemSourcingMap().getSourcingData(currentId);
|
||||||
|
if(sourcingData.recipes.size() > 0){
|
||||||
|
for(RecipeData recipeData : sourcingData.recipes){
|
||||||
|
for(RecipeIngredientData reagent : recipeData.getIngredients()){
|
||||||
|
if(!unsolvedItems.contains(reagent.getItemType()) && !itemSourceMap.containsKey(reagent.getItemType())){
|
||||||
|
unsolvedItems.add(reagent.getItemType());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(sourcingData.trees.size() > 0){
|
||||||
|
unsolvedItems.add(ItemIdStrings.ITEM_STONE_AXE);
|
||||||
|
}
|
||||||
|
this.itemSourceMap.put(currentId,sourcingData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the sourcing data for the current dependency
|
||||||
|
* @param entity The entity to check
|
||||||
|
* @return The sourcing data for the current dependency
|
||||||
|
*/
|
||||||
|
public ItemSourcingData getCurrentDependency(Entity entity){
|
||||||
|
List<Entity> items = InventoryUtils.getAllInventoryItems(entity);
|
||||||
|
List<String> itemIds = items.stream().map((Entity item) -> {return ItemUtils.getType(item);}).collect(Collectors.toList());
|
||||||
|
if(itemIds.contains(this.rootItemId)){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
String currentRootId = this.rootItemId;
|
||||||
|
while(currentRootId != null){
|
||||||
|
ItemSourcingData sourcingData = this.itemSourceMap.get(currentRootId);
|
||||||
|
if(sourcingData == null){
|
||||||
|
throw new Error("Failed to find sourcing data for " + currentRootId);
|
||||||
|
}
|
||||||
|
if(sourcingData.harvestTargets.size() > 0){
|
||||||
|
return sourcingData;
|
||||||
|
}
|
||||||
|
if(sourcingData.trees.size() > 0){
|
||||||
|
//if we don't have an axe in inventory, consider it a dependency
|
||||||
|
if(!InventoryUtils.serverHasTool(entity, CommonEntityTokens.TOKEN_AXE)){
|
||||||
|
currentRootId = ItemIdStrings.ITEM_STONE_AXE;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
//we have an axe, return this sourcing data
|
||||||
|
return sourcingData;
|
||||||
|
}
|
||||||
|
|
||||||
|
currentRootId = null;
|
||||||
|
if(sourcingData.recipes.size() > 0){
|
||||||
|
boolean foundAllIngredients = true;
|
||||||
|
RecipeData craftableRecipe = null;
|
||||||
|
for(RecipeData recipeData : sourcingData.recipes){
|
||||||
|
//check if we have all the ingredients to craft this item
|
||||||
|
foundAllIngredients = true;
|
||||||
|
for(RecipeIngredientData ingredient : recipeData.getIngredients()){
|
||||||
|
if(!itemIds.contains(ingredient.getItemType())){
|
||||||
|
//ingredient is not in inventory
|
||||||
|
foundAllIngredients = false;
|
||||||
|
currentRootId = ingredient.getItemType();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(foundAllIngredients){
|
||||||
|
craftableRecipe = recipeData;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(craftableRecipe != null){
|
||||||
|
return sourcingData;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the item id of the root item
|
||||||
|
* @return The id
|
||||||
|
*/
|
||||||
|
public String getRootItem(){
|
||||||
|
return this.rootItemId;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -25,4 +25,34 @@ public class BlackboardKeys {
|
|||||||
*/
|
*/
|
||||||
public static final String MOVE_TO_TARGET = "moveToTarget";
|
public static final String MOVE_TO_TARGET = "moveToTarget";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The structure that is being targeted
|
||||||
|
*/
|
||||||
|
public static final String STRUCTURE_TARGET = "structureTarget";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The material currently needed for building the targeted structure
|
||||||
|
*/
|
||||||
|
public static final String BUILDING_MATERIAL_CURRENT = "buildingMaterialCurrent";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type of item to scan the inventory for
|
||||||
|
*/
|
||||||
|
public static final String INVENTORY_CHECK_TYPE = "inventoryCheckType";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tree that stores the item sourcing
|
||||||
|
*/
|
||||||
|
public static final String ITEM_SOURCING_TREE = "itemSourcingTree";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sourcing data for the item that is currently being sought after
|
||||||
|
*/
|
||||||
|
public static final String ITEM_SOURCING_DATA = "itemSourcingData";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type of entity to try to harvest
|
||||||
|
*/
|
||||||
|
public static final String HARVEST_TARGET_TYPE = "harvestTargetType";
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,7 +8,7 @@ import electrosphere.entity.EntityUtils;
|
|||||||
import electrosphere.entity.state.inventory.InventoryUtils;
|
import electrosphere.entity.state.inventory.InventoryUtils;
|
||||||
import electrosphere.server.ai.blackboard.Blackboard;
|
import electrosphere.server.ai.blackboard.Blackboard;
|
||||||
import electrosphere.server.ai.nodes.AITreeNode;
|
import electrosphere.server.ai.nodes.AITreeNode;
|
||||||
import electrosphere.server.ai.nodes.plan.FindEntityTargetNode;
|
import electrosphere.server.ai.nodes.plan.TargetEntityCategoryNode;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tries to collect an item
|
* Tries to collect an item
|
||||||
@ -17,17 +17,17 @@ public class CollectItemNode implements AITreeNode {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AITreeNodeResult evaluate(Entity entity, Blackboard blackboard){
|
public AITreeNodeResult evaluate(Entity entity, Blackboard blackboard){
|
||||||
if(!FindEntityTargetNode.hasTarget(blackboard)){
|
if(!TargetEntityCategoryNode.hasTarget(blackboard)){
|
||||||
return AITreeNodeResult.FAILURE;
|
return AITreeNodeResult.FAILURE;
|
||||||
}
|
}
|
||||||
Entity target = FindEntityTargetNode.getTarget(blackboard);
|
Entity target = TargetEntityCategoryNode.getTarget(blackboard);
|
||||||
Vector3d parentPos = EntityUtils.getPosition(entity);
|
Vector3d parentPos = EntityUtils.getPosition(entity);
|
||||||
Vector3d targetPos = EntityUtils.getPosition(target);
|
Vector3d targetPos = EntityUtils.getPosition(target);
|
||||||
if(parentPos.distance(targetPos) > CollisionEngine.DEFAULT_INTERACT_DISTANCE){
|
if(parentPos.distance(targetPos) > CollisionEngine.DEFAULT_INTERACT_DISTANCE){
|
||||||
return AITreeNodeResult.FAILURE;
|
return AITreeNodeResult.FAILURE;
|
||||||
}
|
}
|
||||||
InventoryUtils.serverAttemptStoreItemTransform(entity, target);
|
InventoryUtils.serverAttemptStoreItemTransform(entity, target);
|
||||||
FindEntityTargetNode.setTarget(blackboard, null);
|
TargetEntityCategoryNode.setTarget(blackboard, null);
|
||||||
return AITreeNodeResult.SUCCESS;
|
return AITreeNodeResult.SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -6,8 +6,9 @@ import electrosphere.collision.CollisionEngine;
|
|||||||
import electrosphere.entity.Entity;
|
import electrosphere.entity.Entity;
|
||||||
import electrosphere.entity.EntityUtils;
|
import electrosphere.entity.EntityUtils;
|
||||||
import electrosphere.server.ai.blackboard.Blackboard;
|
import electrosphere.server.ai.blackboard.Blackboard;
|
||||||
|
import electrosphere.server.ai.blackboard.BlackboardKeys;
|
||||||
import electrosphere.server.ai.nodes.AITreeNode;
|
import electrosphere.server.ai.nodes.AITreeNode;
|
||||||
import electrosphere.server.ai.nodes.plan.FindEntityTargetNode;
|
import electrosphere.server.ai.nodes.plan.TargetEntityCategoryNode;
|
||||||
import electrosphere.server.player.PlayerActions;
|
import electrosphere.server.player.PlayerActions;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -17,17 +18,45 @@ public class HarvestNode implements AITreeNode {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AITreeNodeResult evaluate(Entity entity, Blackboard blackboard){
|
public AITreeNodeResult evaluate(Entity entity, Blackboard blackboard){
|
||||||
if(!FindEntityTargetNode.hasTarget(blackboard)){
|
if(!TargetEntityCategoryNode.hasTarget(blackboard)){
|
||||||
return AITreeNodeResult.FAILURE;
|
return AITreeNodeResult.FAILURE;
|
||||||
}
|
}
|
||||||
Entity target = FindEntityTargetNode.getTarget(blackboard);
|
Entity target = TargetEntityCategoryNode.getTarget(blackboard);
|
||||||
Vector3d parentPos = EntityUtils.getPosition(entity);
|
Vector3d parentPos = EntityUtils.getPosition(entity);
|
||||||
Vector3d targetPos = EntityUtils.getPosition(target);
|
Vector3d targetPos = EntityUtils.getPosition(target);
|
||||||
if(parentPos.distance(targetPos) > CollisionEngine.DEFAULT_INTERACT_DISTANCE){
|
if(parentPos.distance(targetPos) > CollisionEngine.DEFAULT_INTERACT_DISTANCE){
|
||||||
return AITreeNodeResult.FAILURE;
|
return AITreeNodeResult.FAILURE;
|
||||||
}
|
}
|
||||||
PlayerActions.harvest(entity, target);
|
PlayerActions.harvest(entity, target);
|
||||||
FindEntityTargetNode.setTarget(blackboard, null);
|
TargetEntityCategoryNode.setTarget(blackboard, null);
|
||||||
return AITreeNodeResult.SUCCESS;
|
return AITreeNodeResult.SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sets the type of entity to try to harvest
|
||||||
|
* @param blackboard The blackboard
|
||||||
|
* @param type The type of entity to try to harvest
|
||||||
|
*/
|
||||||
|
public static void setHarvestTargetType(Blackboard blackboard, String type){
|
||||||
|
blackboard.put(BlackboardKeys.HARVEST_TARGET_TYPE, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* checks if this blackboard has a type of entity it wants to try to harvest
|
||||||
|
* @param blackboard The blackboard
|
||||||
|
* @return true if the type is defined, false otherwise
|
||||||
|
*/
|
||||||
|
public static boolean hasHarvestTargetType(Blackboard blackboard){
|
||||||
|
return blackboard.has(BlackboardKeys.HARVEST_TARGET_TYPE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the type of entity to try to harvest
|
||||||
|
* @param blackboard The blackboard
|
||||||
|
* @return The type of entity to try to harvest
|
||||||
|
*/
|
||||||
|
public static String getHarvestTargetType(Blackboard blackboard){
|
||||||
|
return (String)blackboard.get(BlackboardKeys.HARVEST_TARGET_TYPE);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,18 @@
|
|||||||
|
package electrosphere.server.ai.nodes.actions.interact;
|
||||||
|
|
||||||
|
import electrosphere.entity.Entity;
|
||||||
|
import electrosphere.server.ai.blackboard.Blackboard;
|
||||||
|
import electrosphere.server.ai.nodes.AITreeNode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Places a block
|
||||||
|
*/
|
||||||
|
public class PlaceBlockNode implements AITreeNode {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AITreeNodeResult evaluate(Entity entity, Blackboard blackboard) {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
throw new UnsupportedOperationException("Unimplemented method 'evaluate'");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -9,7 +9,6 @@ import electrosphere.entity.EntityUtils;
|
|||||||
import electrosphere.entity.types.creature.CreatureUtils;
|
import electrosphere.entity.types.creature.CreatureUtils;
|
||||||
import electrosphere.server.ai.blackboard.Blackboard;
|
import electrosphere.server.ai.blackboard.Blackboard;
|
||||||
import electrosphere.server.ai.nodes.AITreeNode;
|
import electrosphere.server.ai.nodes.AITreeNode;
|
||||||
import electrosphere.server.ai.nodes.plan.TargetPositionNode;
|
|
||||||
import electrosphere.util.math.SpatialMathUtils;
|
import electrosphere.util.math.SpatialMathUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -17,17 +16,37 @@ import electrosphere.util.math.SpatialMathUtils;
|
|||||||
*/
|
*/
|
||||||
public class FaceTargetNode implements AITreeNode {
|
public class FaceTargetNode implements AITreeNode {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The key to lookup the target under
|
||||||
|
*/
|
||||||
|
String targetKey;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
* @param targetKey The key to lookup the target under
|
||||||
|
*/
|
||||||
|
public FaceTargetNode(String targetKey){
|
||||||
|
this.targetKey = targetKey;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AITreeNodeResult evaluate(Entity entity, Blackboard blackboard) {
|
public AITreeNodeResult evaluate(Entity entity, Blackboard blackboard) {
|
||||||
if(TargetPositionNode.hasMoveToTarget(blackboard)){
|
Object targetRaw = blackboard.get(this.targetKey);
|
||||||
|
Vector3d targetPos = null;
|
||||||
|
if(targetRaw == null){
|
||||||
|
throw new Error("Target undefined!");
|
||||||
|
}
|
||||||
|
if(targetRaw instanceof Vector3d){
|
||||||
|
targetPos = (Vector3d)targetRaw;
|
||||||
|
}
|
||||||
|
if(targetRaw instanceof Entity){
|
||||||
|
targetPos = EntityUtils.getPosition((Entity)targetRaw);
|
||||||
|
}
|
||||||
Vector3d parentPos = EntityUtils.getPosition(entity);
|
Vector3d parentPos = EntityUtils.getPosition(entity);
|
||||||
Vector3d targetPos = TargetPositionNode.getMoveToTarget(blackboard);
|
|
||||||
Quaterniond rotation = SpatialMathUtils.calculateRotationFromPointToPoint(parentPos, targetPos);
|
Quaterniond rotation = SpatialMathUtils.calculateRotationFromPointToPoint(parentPos, targetPos);
|
||||||
EntityUtils.getRotation(entity).set(rotation);
|
EntityUtils.getRotation(entity).set(rotation);
|
||||||
CreatureUtils.setFacingVector(entity, CameraEntityUtils.getFacingVec(rotation));
|
CreatureUtils.setFacingVector(entity, CameraEntityUtils.getFacingVec(rotation));
|
||||||
return AITreeNodeResult.SUCCESS;
|
return AITreeNodeResult.SUCCESS;
|
||||||
}
|
}
|
||||||
return AITreeNodeResult.FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,33 @@
|
|||||||
|
package electrosphere.server.ai.nodes.checks;
|
||||||
|
|
||||||
|
import electrosphere.entity.Entity;
|
||||||
|
import electrosphere.server.ai.blackboard.Blackboard;
|
||||||
|
import electrosphere.server.ai.nodes.AITreeNode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a blackboard key exists
|
||||||
|
*/
|
||||||
|
public class BlackboardKeyCheckNode implements AITreeNode {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The key to check for
|
||||||
|
*/
|
||||||
|
String key;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
* @param key The key to check for
|
||||||
|
*/
|
||||||
|
public BlackboardKeyCheckNode(String key){
|
||||||
|
this.key = key;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AITreeNodeResult evaluate(Entity entity, Blackboard blackboard) {
|
||||||
|
if(blackboard.has(this.key)){
|
||||||
|
return AITreeNodeResult.SUCCESS;
|
||||||
|
}
|
||||||
|
return AITreeNodeResult.FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,104 @@
|
|||||||
|
package electrosphere.server.ai.nodes.checks.inventory;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import electrosphere.entity.Entity;
|
||||||
|
import electrosphere.entity.state.inventory.InventoryUtils;
|
||||||
|
import electrosphere.entity.state.inventory.RelationalInventoryState;
|
||||||
|
import electrosphere.entity.state.inventory.UnrelationalInventoryState;
|
||||||
|
import electrosphere.entity.types.common.CommonEntityUtils;
|
||||||
|
import electrosphere.server.ai.blackboard.Blackboard;
|
||||||
|
import electrosphere.server.ai.blackboard.BlackboardKeys;
|
||||||
|
import electrosphere.server.ai.nodes.AITreeNode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if any of the inventories on a given entity contain the target item type
|
||||||
|
*/
|
||||||
|
public class InventoryContainsNode implements AITreeNode {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The key to look for the item type in
|
||||||
|
*/
|
||||||
|
String key = BlackboardKeys.INVENTORY_CHECK_TYPE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
* @param key The key to lookup the entity type under
|
||||||
|
*/
|
||||||
|
public InventoryContainsNode(String key){
|
||||||
|
this.key = key;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AITreeNodeResult evaluate(Entity entity, Blackboard blackboard) {
|
||||||
|
|
||||||
|
//error checking
|
||||||
|
if(!InventoryContainsNode.hasInventoryCheckType(blackboard)){
|
||||||
|
return AITreeNodeResult.FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
//key isn't defined
|
||||||
|
if(!blackboard.has(key)){
|
||||||
|
return AITreeNodeResult.FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
//type to look for
|
||||||
|
String type = (String)blackboard.get(this.key);
|
||||||
|
|
||||||
|
//check equip inventory if it exists
|
||||||
|
if(InventoryUtils.hasEquipInventory(entity)){
|
||||||
|
RelationalInventoryState equipInventory = InventoryUtils.getEquipInventory(entity);
|
||||||
|
if(equipInventory.getSlots().contains(type)){
|
||||||
|
return AITreeNodeResult.SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//check natural inventory if it exists
|
||||||
|
if(InventoryUtils.hasNaturalInventory(entity)){
|
||||||
|
UnrelationalInventoryState naturalInventory = InventoryUtils.getNaturalInventory(entity);
|
||||||
|
List<String> itemIds = naturalInventory.getItems().stream().map((Entity itemEnt) -> {return CommonEntityUtils.getEntitySubtype(entity);}).collect(Collectors.toList());
|
||||||
|
if(itemIds.contains(type)){
|
||||||
|
return AITreeNodeResult.SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//check toolbar inventory if it exists
|
||||||
|
if(InventoryUtils.hasToolbarInventory(entity)){
|
||||||
|
RelationalInventoryState toolbarInventory = InventoryUtils.getToolbarInventory(entity);
|
||||||
|
if(toolbarInventory.getSlots().contains(type)){
|
||||||
|
return AITreeNodeResult.SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return AITreeNodeResult.FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the type of item to check for
|
||||||
|
* @param blackboard The blackboard
|
||||||
|
* @param type The type of item to check for
|
||||||
|
*/
|
||||||
|
public static void setInventoryCheckType(Blackboard blackboard, String type){
|
||||||
|
blackboard.put(BlackboardKeys.INVENTORY_CHECK_TYPE, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if this has an item type to search for
|
||||||
|
* @param blackboard The blackboard
|
||||||
|
* @return true if there is an item type to check for, false otherwise
|
||||||
|
*/
|
||||||
|
public static boolean hasInventoryCheckType(Blackboard blackboard){
|
||||||
|
return blackboard.has(BlackboardKeys.INVENTORY_CHECK_TYPE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the item type to check for
|
||||||
|
* @param blackboard The blackboard
|
||||||
|
* @return The item type to check for if it exists, null otherwise
|
||||||
|
*/
|
||||||
|
public static String getInventoryCheckType(Blackboard blackboard){
|
||||||
|
return (String)blackboard.get(BlackboardKeys.INVENTORY_CHECK_TYPE);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,62 @@
|
|||||||
|
package electrosphere.server.ai.nodes.checks.inventory;
|
||||||
|
|
||||||
|
import electrosphere.entity.Entity;
|
||||||
|
import electrosphere.game.data.item.source.ItemSourcingData;
|
||||||
|
import electrosphere.game.data.item.source.ItemSourcingData.SourcingType;
|
||||||
|
import electrosphere.server.ai.blackboard.Blackboard;
|
||||||
|
import electrosphere.server.ai.nodes.AITreeNode;
|
||||||
|
import electrosphere.server.ai.nodes.plan.SolveSourcingTreeNode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the supplied type of sourcing is the path for the current target item to acquire
|
||||||
|
*/
|
||||||
|
public class SourcingTypeNode implements AITreeNode {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type of sourcing
|
||||||
|
*/
|
||||||
|
SourcingType sourcingType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
* @param sourcingType The type of sourcing to check
|
||||||
|
*/
|
||||||
|
public SourcingTypeNode(SourcingType sourcingType){
|
||||||
|
this.sourcingType = sourcingType;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AITreeNodeResult evaluate(Entity entity, Blackboard blackboard) {
|
||||||
|
if(!SolveSourcingTreeNode.hasItemSourcingData(blackboard)){
|
||||||
|
return AITreeNodeResult.FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
ItemSourcingData sourcingData = SolveSourcingTreeNode.getItemSourcingData(blackboard);
|
||||||
|
if(sourcingData == null){
|
||||||
|
throw new Error("Sourcing data is null!");
|
||||||
|
}
|
||||||
|
|
||||||
|
//succeed based on the type of sourcing that this node is set for
|
||||||
|
switch(this.sourcingType){
|
||||||
|
case RECIPE: {
|
||||||
|
if(sourcingData.getRecipes().size() > 0){
|
||||||
|
return AITreeNodeResult.SUCCESS;
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
case HARVEST: {
|
||||||
|
if(sourcingData.getHarvestTargets().size() > 0){
|
||||||
|
return AITreeNodeResult.SUCCESS;
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
case TREE: {
|
||||||
|
if(sourcingData.getTrees().size() > 0){
|
||||||
|
return AITreeNodeResult.SUCCESS;
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return AITreeNodeResult.FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -22,6 +22,9 @@ public class HasShelter implements AITreeNode {
|
|||||||
MacroData macroData = entityRealm.getServerContentManager().getMacroData();
|
MacroData macroData = entityRealm.getServerContentManager().getMacroData();
|
||||||
ServerCharacterData serverCharacterData = ServerCharacterData.getServerCharacterData(entity);
|
ServerCharacterData serverCharacterData = ServerCharacterData.getServerCharacterData(entity);
|
||||||
Character character = macroData.getCharacter(serverCharacterData.getCharacterId());
|
Character character = macroData.getCharacter(serverCharacterData.getCharacterId());
|
||||||
|
if(character == null){
|
||||||
|
throw new Error("Character is null");
|
||||||
|
}
|
||||||
Structure shelter = CharacterUtils.getShelter(character);
|
Structure shelter = CharacterUtils.getShelter(character);
|
||||||
if(shelter == null){
|
if(shelter == null){
|
||||||
return AITreeNodeResult.FAILURE;
|
return AITreeNodeResult.FAILURE;
|
||||||
|
|||||||
@ -0,0 +1,85 @@
|
|||||||
|
package electrosphere.server.ai.nodes.checks.spatial;
|
||||||
|
|
||||||
|
import org.joml.Vector3d;
|
||||||
|
|
||||||
|
import electrosphere.engine.Globals;
|
||||||
|
import electrosphere.entity.Entity;
|
||||||
|
import electrosphere.entity.EntityUtils;
|
||||||
|
import electrosphere.game.data.block.BlockFab;
|
||||||
|
import electrosphere.game.data.struct.StructureData;
|
||||||
|
import electrosphere.server.ai.blackboard.Blackboard;
|
||||||
|
import electrosphere.server.ai.blackboard.BlackboardKeys;
|
||||||
|
import electrosphere.server.ai.nodes.AITreeNode;
|
||||||
|
import electrosphere.server.datacell.Realm;
|
||||||
|
import electrosphere.server.macro.MacroData;
|
||||||
|
import electrosphere.server.macro.structure.Structure;
|
||||||
|
import electrosphere.server.macro.utils.StructurePlacementUtils;
|
||||||
|
import electrosphere.util.FileUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tries to begin building a structure
|
||||||
|
*/
|
||||||
|
public class BeginStructureNode implements AITreeNode {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The data for the structure to place
|
||||||
|
*/
|
||||||
|
StructureData structureData;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
* @param structureData The type of structure to place
|
||||||
|
*/
|
||||||
|
public BeginStructureNode(StructureData structureData){
|
||||||
|
this.structureData = structureData;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AITreeNodeResult evaluate(Entity entity, Blackboard blackboard) {
|
||||||
|
if(!BeginStructureNode.hasStructureTarget(blackboard)){
|
||||||
|
//requisite data
|
||||||
|
Realm realm = Globals.realmManager.getEntityRealm(entity);
|
||||||
|
MacroData macroData = realm.getServerContentManager().getMacroData();
|
||||||
|
Vector3d position = EntityUtils.getPosition(entity);
|
||||||
|
|
||||||
|
//solve where to place
|
||||||
|
Vector3d placementPos = StructurePlacementUtils.getPlacementPosition(macroData, structureData, position);
|
||||||
|
|
||||||
|
//add to macro data
|
||||||
|
Structure struct = Structure.createStructure(structureData, placementPos);
|
||||||
|
struct.setRepairable(true);
|
||||||
|
struct.setFab(BlockFab.read(FileUtils.getAssetFile(struct.getFabPath())));
|
||||||
|
// macroData.getStructures().add(struct);
|
||||||
|
|
||||||
|
BeginStructureNode.setStructureTarget(blackboard, struct);
|
||||||
|
}
|
||||||
|
return AITreeNodeResult.SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the structure target for the entity
|
||||||
|
* @param blackboard The blackboard
|
||||||
|
* @param structure The structure to target
|
||||||
|
*/
|
||||||
|
public static void setStructureTarget(Blackboard blackboard, Structure structure){
|
||||||
|
blackboard.put(BlackboardKeys.STRUCTURE_TARGET, structure);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the blackboard has a structure target
|
||||||
|
* @param blackboard The blackboard
|
||||||
|
*/
|
||||||
|
public static boolean hasStructureTarget(Blackboard blackboard){
|
||||||
|
return blackboard.has(BlackboardKeys.STRUCTURE_TARGET);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the structure target in the blackboard
|
||||||
|
* @param blackboard The blackboard
|
||||||
|
* @return The structure if it exists, null otherwise
|
||||||
|
*/
|
||||||
|
public static Structure getStructureTarget(Blackboard blackboard){
|
||||||
|
return (Structure)blackboard.get(BlackboardKeys.STRUCTURE_TARGET);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -6,33 +6,45 @@ import electrosphere.entity.Entity;
|
|||||||
import electrosphere.entity.EntityUtils;
|
import electrosphere.entity.EntityUtils;
|
||||||
import electrosphere.server.ai.blackboard.Blackboard;
|
import electrosphere.server.ai.blackboard.Blackboard;
|
||||||
import electrosphere.server.ai.nodes.AITreeNode;
|
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
|
* Checks if the target is inside a given range of the entity
|
||||||
*/
|
*/
|
||||||
public class TargetRangeCheck implements AITreeNode {
|
public class TargetRangeCheckNode implements AITreeNode {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The distance to succeed within
|
* The distance to succeed within
|
||||||
*/
|
*/
|
||||||
double dist;
|
double dist;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The key to lookup the target under
|
||||||
|
*/
|
||||||
|
String targetKey;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
* @param dist The distance outside of which the node will fail
|
* @param dist The distance outside of which the node will fail
|
||||||
|
* @param targetKey The key to lookup the target under
|
||||||
*/
|
*/
|
||||||
public TargetRangeCheck(double dist){
|
public TargetRangeCheckNode(double dist, String targetKey){
|
||||||
this.dist = dist;
|
this.dist = dist;
|
||||||
|
this.targetKey = targetKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AITreeNodeResult evaluate(Entity entity, Blackboard blackboard) {
|
public AITreeNodeResult evaluate(Entity entity, Blackboard blackboard) {
|
||||||
if(!FindEntityTargetNode.hasTarget(blackboard)){
|
Object targetRaw = blackboard.get(this.targetKey);
|
||||||
return AITreeNodeResult.FAILURE;
|
Vector3d targetPos = null;
|
||||||
|
if(targetRaw == null){
|
||||||
|
throw new Error("Target undefined!");
|
||||||
|
}
|
||||||
|
if(targetRaw instanceof Vector3d){
|
||||||
|
targetPos = (Vector3d)targetRaw;
|
||||||
|
}
|
||||||
|
if(targetRaw instanceof Entity){
|
||||||
|
targetPos = EntityUtils.getPosition((Entity)targetRaw);
|
||||||
}
|
}
|
||||||
Entity target = FindEntityTargetNode.getTarget(blackboard);
|
|
||||||
Vector3d targetPos = EntityUtils.getPosition(target);
|
|
||||||
Vector3d entPos = EntityUtils.getPosition(entity);
|
Vector3d entPos = EntityUtils.getPosition(entity);
|
||||||
|
|
||||||
if(targetPos.distance(entPos) < this.dist){
|
if(targetPos.distance(entPos) < this.dist){
|
||||||
@ -0,0 +1,39 @@
|
|||||||
|
package electrosphere.server.ai.nodes.meta;
|
||||||
|
|
||||||
|
import electrosphere.entity.Entity;
|
||||||
|
import electrosphere.server.ai.blackboard.Blackboard;
|
||||||
|
import electrosphere.server.ai.nodes.AITreeNode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transfers data from one blackboard key to another
|
||||||
|
*/
|
||||||
|
public class DataTransferNode implements AITreeNode {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The key to pull data from
|
||||||
|
*/
|
||||||
|
String sourceKey;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The key to push data into
|
||||||
|
*/
|
||||||
|
String destinationKey;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
* @param sourceKey The key to pull data from
|
||||||
|
* @param destinationKey The key to push data into
|
||||||
|
*/
|
||||||
|
public DataTransferNode(String sourceKey, String destinationKey){
|
||||||
|
this.sourceKey = sourceKey;
|
||||||
|
this.destinationKey = destinationKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AITreeNodeResult evaluate(Entity entity, Blackboard blackboard) {
|
||||||
|
Object data = blackboard.get(this.sourceKey);
|
||||||
|
blackboard.put(this.destinationKey, data);
|
||||||
|
return AITreeNodeResult.SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -1,16 +0,0 @@
|
|||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,56 +0,0 @@
|
|||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,35 +0,0 @@
|
|||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -0,0 +1,106 @@
|
|||||||
|
package electrosphere.server.ai.nodes.plan;
|
||||||
|
|
||||||
|
import electrosphere.entity.Entity;
|
||||||
|
import electrosphere.game.data.item.source.ItemSourcingData;
|
||||||
|
import electrosphere.game.data.item.source.ItemSourcingTree;
|
||||||
|
import electrosphere.server.ai.blackboard.Blackboard;
|
||||||
|
import electrosphere.server.ai.blackboard.BlackboardKeys;
|
||||||
|
import electrosphere.server.ai.nodes.AITreeNode;
|
||||||
|
import electrosphere.server.ai.nodes.actions.interact.HarvestNode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Solves a dependency tree for how to acquire a given item
|
||||||
|
*/
|
||||||
|
public class SolveSourcingTreeNode implements AITreeNode {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Blackboard key that stores the id of the item to source
|
||||||
|
*/
|
||||||
|
String itemIdKey;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
* @param itemIdKey The blackboard key that stores the id of the item to calculate sourcing for
|
||||||
|
*/
|
||||||
|
public SolveSourcingTreeNode(String itemIdKey){
|
||||||
|
this.itemIdKey = itemIdKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AITreeNodeResult evaluate(Entity entity, Blackboard blackboard) {
|
||||||
|
if(!blackboard.has(itemIdKey)){
|
||||||
|
return AITreeNodeResult.FAILURE;
|
||||||
|
}
|
||||||
|
if(!SolveSourcingTreeNode.hasItemSourcingTree(blackboard) || !SolveSourcingTreeNode.getItemSourcingTree(blackboard).getRootItem().equals(this.itemIdKey)){
|
||||||
|
String itemId = (String)blackboard.get(itemIdKey);
|
||||||
|
ItemSourcingTree sourcingTree = ItemSourcingTree.create(itemId);
|
||||||
|
SolveSourcingTreeNode.setItemSourcingTree(blackboard, sourcingTree);
|
||||||
|
}
|
||||||
|
ItemSourcingTree sourcingTree = SolveSourcingTreeNode.getItemSourcingTree(blackboard);
|
||||||
|
ItemSourcingData sourcingData = sourcingTree.getCurrentDependency(entity);
|
||||||
|
if(sourcingData == null){
|
||||||
|
throw new Error("Source data is null!");
|
||||||
|
}
|
||||||
|
//set the type to harvest if this is a harvest type
|
||||||
|
if(sourcingData.getHarvestTargets().size() > 0){
|
||||||
|
HarvestNode.setHarvestTargetType(blackboard, sourcingData.getHarvestTargets().get(0).getId());
|
||||||
|
}
|
||||||
|
SolveSourcingTreeNode.setItemSourcingData(blackboard, sourcingData);
|
||||||
|
return AITreeNodeResult.SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the item sourcing tree of the blackboard
|
||||||
|
* @param blackboard The blackboard
|
||||||
|
* @param tree The tree
|
||||||
|
*/
|
||||||
|
public static void setItemSourcingTree(Blackboard blackboard, ItemSourcingTree tree){
|
||||||
|
blackboard.put(BlackboardKeys.ITEM_SOURCING_TREE, tree);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the blackboard has an item sourcing tree
|
||||||
|
* @param blackboard The blackboard
|
||||||
|
* @return The item sourcing tree
|
||||||
|
*/
|
||||||
|
public static boolean hasItemSourcingTree(Blackboard blackboard){
|
||||||
|
return blackboard.has(BlackboardKeys.ITEM_SOURCING_TREE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the item sourcing tree of the blackboard
|
||||||
|
* @param blackboard The blackboard
|
||||||
|
* @return The item sourcing tree
|
||||||
|
*/
|
||||||
|
public static ItemSourcingTree getItemSourcingTree(Blackboard blackboard){
|
||||||
|
return (ItemSourcingTree)blackboard.get(BlackboardKeys.ITEM_SOURCING_TREE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the item sourcing data of the blackboard
|
||||||
|
* @param blackboard The blackboard
|
||||||
|
* @param tree The data
|
||||||
|
*/
|
||||||
|
public static void setItemSourcingData(Blackboard blackboard, ItemSourcingData data){
|
||||||
|
blackboard.put(BlackboardKeys.ITEM_SOURCING_DATA, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the blackboard has an item sourcing data
|
||||||
|
* @param blackboard The blackboard
|
||||||
|
* @return The item sourcing data
|
||||||
|
*/
|
||||||
|
public static boolean hasItemSourcingData(Blackboard blackboard){
|
||||||
|
return blackboard.has(BlackboardKeys.ITEM_SOURCING_DATA);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the item sourcing data of the blackboard
|
||||||
|
* @param blackboard The blackboard
|
||||||
|
* @return The item sourcing data
|
||||||
|
*/
|
||||||
|
public static ItemSourcingData getItemSourcingData(Blackboard blackboard){
|
||||||
|
return (ItemSourcingData)blackboard.get(BlackboardKeys.ITEM_SOURCING_DATA);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,106 @@
|
|||||||
|
package electrosphere.server.ai.nodes.plan;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
import electrosphere.entity.Entity;
|
||||||
|
import electrosphere.entity.types.common.CommonEntityUtils;
|
||||||
|
import electrosphere.server.ai.blackboard.Blackboard;
|
||||||
|
import electrosphere.server.ai.blackboard.BlackboardKeys;
|
||||||
|
import electrosphere.server.ai.nodes.AITreeNode;
|
||||||
|
import electrosphere.server.ai.services.NearbyEntityService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Targets a nearby entity of a specific type
|
||||||
|
*/
|
||||||
|
public class TargetEntityCategoryNode implements AITreeNode {
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The blackboard key to pull the entity type from
|
||||||
|
*/
|
||||||
|
String sourceKey;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
* @param sourceKey The blackboard key to pull the entity type from
|
||||||
|
*/
|
||||||
|
public TargetEntityCategoryNode(String sourceKey){
|
||||||
|
this.sourceKey = sourceKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AITreeNodeResult evaluate(Entity entity, Blackboard blackboard) {
|
||||||
|
String goalEntityId = (String)blackboard.get(sourceKey);
|
||||||
|
|
||||||
|
if(goalEntityId == null){
|
||||||
|
throw new Error("Entity id to search for is null!");
|
||||||
|
}
|
||||||
|
|
||||||
|
if(TargetEntityCategoryNode.hasTarget(blackboard)){
|
||||||
|
Entity currentTarget = TargetEntityCategoryNode.getTarget(blackboard);
|
||||||
|
if(currentTarget == null){
|
||||||
|
TargetEntityCategoryNode.clearTarget(blackboard);
|
||||||
|
} else {
|
||||||
|
String typeId = CommonEntityUtils.getEntitySubtype(currentTarget);
|
||||||
|
if(!typeId.equals(goalEntityId)){
|
||||||
|
TargetEntityCategoryNode.clearTarget(blackboard);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!TargetEntityCategoryNode.hasTarget(blackboard)){
|
||||||
|
Collection<Entity> nearbyEntities = NearbyEntityService.getNearbyEntities(blackboard);
|
||||||
|
for(Entity potential : nearbyEntities){
|
||||||
|
//get id -- skip empty ids
|
||||||
|
String potentialId = CommonEntityUtils.getEntitySubtype(potential);
|
||||||
|
if(potentialId == null){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
//set to target if id match
|
||||||
|
if(potentialId.equals(goalEntityId)){
|
||||||
|
TargetEntityCategoryNode.setTarget(blackboard, potential);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!TargetEntityCategoryNode.hasTarget(blackboard)){
|
||||||
|
return AITreeNodeResult.FAILURE;
|
||||||
|
}
|
||||||
|
return AITreeNodeResult.SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears the target
|
||||||
|
* @param blackboard The target
|
||||||
|
*/
|
||||||
|
public static void clearTarget(Blackboard blackboard){
|
||||||
|
blackboard.delete(BlackboardKeys.ENTITY_TARGET);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -13,13 +13,32 @@ import electrosphere.server.ai.nodes.AITreeNode;
|
|||||||
*/
|
*/
|
||||||
public class TargetPositionNode implements AITreeNode {
|
public class TargetPositionNode implements AITreeNode {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The key to lookup the target under
|
||||||
|
*/
|
||||||
|
String targetKey;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* constructor
|
||||||
|
* @param targetKey The key to lookup the target under
|
||||||
|
*/
|
||||||
|
public TargetPositionNode(String targetKey){
|
||||||
|
this.targetKey = targetKey;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AITreeNodeResult evaluate(Entity entity, Blackboard blackboard){
|
public AITreeNodeResult evaluate(Entity entity, Blackboard blackboard){
|
||||||
if(!FindEntityTargetNode.hasTarget(blackboard)){
|
Object targetRaw = blackboard.get(this.targetKey);
|
||||||
return AITreeNodeResult.FAILURE;
|
Vector3d targetPos = null;
|
||||||
|
if(targetRaw == null){
|
||||||
|
throw new Error("Target undefined!");
|
||||||
|
}
|
||||||
|
if(targetRaw instanceof Vector3d){
|
||||||
|
targetPos = (Vector3d)targetRaw;
|
||||||
|
}
|
||||||
|
if(targetRaw instanceof Entity){
|
||||||
|
targetPos = EntityUtils.getPosition((Entity)targetRaw);
|
||||||
}
|
}
|
||||||
Entity target = FindEntityTargetNode.getTarget(blackboard);
|
|
||||||
Vector3d targetPos = EntityUtils.getPosition(target);
|
|
||||||
TargetPositionNode.setMoveToTarget(blackboard, targetPos);
|
TargetPositionNode.setMoveToTarget(blackboard, targetPos);
|
||||||
return AITreeNodeResult.SUCCESS;
|
return AITreeNodeResult.SUCCESS;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,28 @@
|
|||||||
|
package electrosphere.server.ai.nodes.solvers;
|
||||||
|
|
||||||
|
import electrosphere.entity.Entity;
|
||||||
|
import electrosphere.entity.state.block.ServerBlockTree;
|
||||||
|
import electrosphere.server.ai.blackboard.Blackboard;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,47 @@
|
|||||||
|
package electrosphere.server.ai.nodes.solvers;
|
||||||
|
|
||||||
|
import org.joml.Vector3i;
|
||||||
|
|
||||||
|
import electrosphere.engine.Globals;
|
||||||
|
import electrosphere.entity.Entity;
|
||||||
|
import electrosphere.game.data.block.BlockFab;
|
||||||
|
import electrosphere.game.data.block.BlockType;
|
||||||
|
import electrosphere.game.data.item.Item;
|
||||||
|
import electrosphere.server.ai.blackboard.Blackboard;
|
||||||
|
import electrosphere.server.ai.nodes.AITreeNode;
|
||||||
|
import electrosphere.server.ai.nodes.checks.spatial.BeginStructureNode;
|
||||||
|
import electrosphere.server.ai.trees.struct.BuildStructureTree;
|
||||||
|
import electrosphere.server.datacell.Realm;
|
||||||
|
import electrosphere.server.macro.structure.Structure;
|
||||||
|
import electrosphere.server.macro.utils.StructureRepairUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Solves for the current build material
|
||||||
|
*/
|
||||||
|
public class SolveBuildMaterialNode implements AITreeNode {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AITreeNodeResult evaluate(Entity entity, Blackboard blackboard) {
|
||||||
|
if(!BuildStructureTree.hasCurrentMaterial(blackboard)){
|
||||||
|
Structure struct = BeginStructureNode.getStructureTarget(blackboard);
|
||||||
|
if(!struct.isRepairable()){
|
||||||
|
return AITreeNodeResult.FAILURE;
|
||||||
|
}
|
||||||
|
//solve for repairable block
|
||||||
|
Realm realm = Globals.realmManager.getEntityRealm(entity);
|
||||||
|
Vector3i repairPos = StructureRepairUtils.getRepairablePosition(realm, struct);
|
||||||
|
|
||||||
|
//get the id of item entity type for the block we need
|
||||||
|
BlockFab fab = struct.getFab();
|
||||||
|
short blockTypeId = fab.getType(repairPos.x, repairPos.y, repairPos.z);
|
||||||
|
BlockType blockType = Globals.gameConfigCurrent.getBlockData().getTypeFromId(blockTypeId);
|
||||||
|
String itemId = Item.getBlockTypeId(blockType);
|
||||||
|
|
||||||
|
//store
|
||||||
|
BuildStructureTree.setCurrentMaterial(blackboard, itemId);
|
||||||
|
}
|
||||||
|
|
||||||
|
return AITreeNodeResult.SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,66 @@
|
|||||||
|
package electrosphere.server.ai.trees.creature;
|
||||||
|
|
||||||
|
import electrosphere.collision.CollisionEngine;
|
||||||
|
import electrosphere.game.data.item.source.ItemSourcingData.SourcingType;
|
||||||
|
import electrosphere.server.ai.blackboard.BlackboardKeys;
|
||||||
|
import electrosphere.server.ai.nodes.AITreeNode;
|
||||||
|
import electrosphere.server.ai.nodes.actions.interact.HarvestNode;
|
||||||
|
import electrosphere.server.ai.nodes.checks.inventory.SourcingTypeNode;
|
||||||
|
import electrosphere.server.ai.nodes.meta.collections.SelectorNode;
|
||||||
|
import electrosphere.server.ai.nodes.meta.collections.SequenceNode;
|
||||||
|
import electrosphere.server.ai.nodes.meta.debug.PublishStatusNode;
|
||||||
|
import electrosphere.server.ai.nodes.meta.decorators.RunnerNode;
|
||||||
|
import electrosphere.server.ai.nodes.meta.decorators.SucceederNode;
|
||||||
|
import electrosphere.server.ai.nodes.plan.SolveSourcingTreeNode;
|
||||||
|
import electrosphere.server.ai.nodes.plan.TargetEntityCategoryNode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A tree to acquire an item
|
||||||
|
*/
|
||||||
|
public class AcquireItemTree {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Name of the tree
|
||||||
|
*/
|
||||||
|
public static final String TREE_NAME = "AcquireItem";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a acquire-item tree
|
||||||
|
* @param key The blackboard key to search for the item name under
|
||||||
|
* @return The root node of the acquire-item tree
|
||||||
|
*/
|
||||||
|
public static AITreeNode create(String blackboardKey){
|
||||||
|
return new SequenceNode(
|
||||||
|
new PublishStatusNode("Acquire an item"),
|
||||||
|
//solve how we're going to get this top level item
|
||||||
|
new SolveSourcingTreeNode(blackboardKey),
|
||||||
|
new SelectorNode(
|
||||||
|
new SequenceNode(
|
||||||
|
new PublishStatusNode("Craft an item"),
|
||||||
|
//check if we should be sourcing this from a recipe
|
||||||
|
new SourcingTypeNode(SourcingType.RECIPE),
|
||||||
|
//TODO: logic to craft a recipe
|
||||||
|
new RunnerNode(null)
|
||||||
|
),
|
||||||
|
new SequenceNode(
|
||||||
|
new PublishStatusNode("Harvest an item"),
|
||||||
|
//check if we should be sourcing this from harvesting foliage
|
||||||
|
new SourcingTypeNode(SourcingType.HARVEST),
|
||||||
|
new TargetEntityCategoryNode(BlackboardKeys.HARVEST_TARGET_TYPE),
|
||||||
|
MoveToTarget.create(CollisionEngine.DEFAULT_INTERACT_DISTANCE, BlackboardKeys.ENTITY_TARGET),
|
||||||
|
new HarvestNode(),
|
||||||
|
new RunnerNode(null)
|
||||||
|
),
|
||||||
|
new SequenceNode(
|
||||||
|
new PublishStatusNode("Fell a tree"),
|
||||||
|
//check if we should be sourcing this from felling a tree
|
||||||
|
new SourcingTypeNode(SourcingType.TREE),
|
||||||
|
//TODO: logic to fell a tree
|
||||||
|
new RunnerNode(null)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
new SucceederNode(null)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -5,12 +5,11 @@ import electrosphere.server.ai.nodes.AITreeNode;
|
|||||||
import electrosphere.server.ai.nodes.actions.move.FaceTargetNode;
|
import electrosphere.server.ai.nodes.actions.move.FaceTargetNode;
|
||||||
import electrosphere.server.ai.nodes.actions.move.MoveStartNode;
|
import electrosphere.server.ai.nodes.actions.move.MoveStartNode;
|
||||||
import electrosphere.server.ai.nodes.actions.move.MoveStopNode;
|
import electrosphere.server.ai.nodes.actions.move.MoveStopNode;
|
||||||
import electrosphere.server.ai.nodes.checks.spatial.TargetRangeCheck;
|
import electrosphere.server.ai.nodes.checks.spatial.TargetRangeCheckNode;
|
||||||
import electrosphere.server.ai.nodes.meta.collections.SelectorNode;
|
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.TargetPositionNode;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Moves to a target
|
* Moves to a target
|
||||||
@ -25,22 +24,22 @@ public class MoveToTarget {
|
|||||||
/**
|
/**
|
||||||
* Creates a move-to-target tree
|
* Creates a move-to-target tree
|
||||||
* @param dist The target distance to be within
|
* @param dist The target distance to be within
|
||||||
|
* @param targetKey The key to lookup the target under
|
||||||
* @return The root node of the move-to-target tree
|
* @return The root node of the move-to-target tree
|
||||||
*/
|
*/
|
||||||
public static AITreeNode create(double dist){
|
public static AITreeNode create(double dist, String targetKey){
|
||||||
return new SelectorNode(
|
return new SelectorNode(
|
||||||
new SequenceNode(
|
new SequenceNode(
|
||||||
//check if in range of target
|
//check if in range of target
|
||||||
new TargetRangeCheck(0),
|
new TargetRangeCheckNode(dist, targetKey),
|
||||||
//if in range, stop moving fowards and return SUCCESS
|
//if in range, stop moving fowards and return SUCCESS
|
||||||
new SucceederNode(new MoveStopNode())
|
new SucceederNode(new MoveStopNode())
|
||||||
),
|
),
|
||||||
|
|
||||||
//not in range of target, keep moving towards it
|
//not in range of target, keep moving towards it
|
||||||
new SequenceNode(
|
new SequenceNode(
|
||||||
new TargetPositionNode(),
|
|
||||||
//check that dependencies exist
|
//check that dependencies exist
|
||||||
new FaceTargetNode(),
|
new FaceTargetNode(targetKey),
|
||||||
new RunnerNode(new MoveStartNode(MovementRelativeFacing.FORWARD))
|
new RunnerNode(new MoveStartNode(MovementRelativeFacing.FORWARD))
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|||||||
@ -2,6 +2,7 @@ package electrosphere.server.ai.trees.creature.melee;
|
|||||||
|
|
||||||
import electrosphere.entity.state.movement.groundmove.ClientGroundMovementTree.MovementRelativeFacing;
|
import electrosphere.entity.state.movement.groundmove.ClientGroundMovementTree.MovementRelativeFacing;
|
||||||
import electrosphere.game.data.creature.type.ai.AttackerTreeData;
|
import electrosphere.game.data.creature.type.ai.AttackerTreeData;
|
||||||
|
import electrosphere.server.ai.blackboard.BlackboardKeys;
|
||||||
import electrosphere.server.ai.nodes.AITreeNode;
|
import electrosphere.server.ai.nodes.AITreeNode;
|
||||||
import electrosphere.server.ai.nodes.AITreeNode.AITreeNodeResult;
|
import electrosphere.server.ai.nodes.AITreeNode.AITreeNodeResult;
|
||||||
import electrosphere.server.ai.nodes.actions.combat.AttackStartNode;
|
import electrosphere.server.ai.nodes.actions.combat.AttackStartNode;
|
||||||
@ -66,19 +67,19 @@ public class MeleeAITree {
|
|||||||
//wait
|
//wait
|
||||||
new SequenceNode(
|
new SequenceNode(
|
||||||
new PublishStatusNode("Waiting"),
|
new PublishStatusNode("Waiting"),
|
||||||
new FaceTargetNode(),
|
new FaceTargetNode(BlackboardKeys.ENTITY_TARGET),
|
||||||
new TimerNode(new SucceederNode(null), 600)
|
new TimerNode(new SucceederNode(null), 600)
|
||||||
),
|
),
|
||||||
//wait
|
//wait
|
||||||
new SequenceNode(
|
new SequenceNode(
|
||||||
new PublishStatusNode("Waiting"),
|
new PublishStatusNode("Waiting"),
|
||||||
new FaceTargetNode(),
|
new FaceTargetNode(BlackboardKeys.ENTITY_TARGET),
|
||||||
new TimerNode(new SucceederNode(null), 300)
|
new TimerNode(new SucceederNode(null), 300)
|
||||||
),
|
),
|
||||||
//attack
|
//attack
|
||||||
new SequenceNode(
|
new SequenceNode(
|
||||||
new PublishStatusNode("Attacking"),
|
new PublishStatusNode("Attacking"),
|
||||||
new FaceTargetNode(),
|
new FaceTargetNode(BlackboardKeys.ENTITY_TARGET),
|
||||||
new AttackStartNode(),
|
new AttackStartNode(),
|
||||||
new TimerNode(new SucceederNode(null), 300)
|
new TimerNode(new SucceederNode(null), 300)
|
||||||
)
|
)
|
||||||
@ -96,7 +97,7 @@ public class MeleeAITree {
|
|||||||
//wait
|
//wait
|
||||||
new SequenceNode(
|
new SequenceNode(
|
||||||
new PublishStatusNode("Waiting"),
|
new PublishStatusNode("Waiting"),
|
||||||
new FaceTargetNode(),
|
new FaceTargetNode(BlackboardKeys.ENTITY_TARGET),
|
||||||
new TimerNode(new SucceederNode(null), 1200)
|
new TimerNode(new SucceederNode(null), 1200)
|
||||||
),
|
),
|
||||||
|
|
||||||
@ -108,7 +109,7 @@ public class MeleeAITree {
|
|||||||
new MoveStartNode(MovementRelativeFacing.RIGHT),
|
new MoveStartNode(MovementRelativeFacing.RIGHT),
|
||||||
new FailerNode(null)
|
new FailerNode(null)
|
||||||
)),
|
)),
|
||||||
new FaceTargetNode(),
|
new FaceTargetNode(BlackboardKeys.ENTITY_TARGET),
|
||||||
new TimerNode(new SucceederNode(null), 600),
|
new TimerNode(new SucceederNode(null), 600),
|
||||||
new SucceederNode(new WalkStopNode()),
|
new SucceederNode(new WalkStopNode()),
|
||||||
new SucceederNode(new MoveStopNode())
|
new SucceederNode(new MoveStopNode())
|
||||||
@ -122,7 +123,7 @@ public class MeleeAITree {
|
|||||||
new MoveStartNode(MovementRelativeFacing.LEFT),
|
new MoveStartNode(MovementRelativeFacing.LEFT),
|
||||||
new FailerNode(null)
|
new FailerNode(null)
|
||||||
)),
|
)),
|
||||||
new FaceTargetNode(),
|
new FaceTargetNode(BlackboardKeys.ENTITY_TARGET),
|
||||||
new TimerNode(new SucceederNode(null), 600),
|
new TimerNode(new SucceederNode(null), 600),
|
||||||
new SucceederNode(new WalkStopNode()),
|
new SucceederNode(new WalkStopNode()),
|
||||||
new SucceederNode(new MoveStopNode())
|
new SucceederNode(new MoveStopNode())
|
||||||
@ -132,7 +133,7 @@ public class MeleeAITree {
|
|||||||
//move towards target and attack
|
//move towards target and attack
|
||||||
new SequenceNode(
|
new SequenceNode(
|
||||||
new PublishStatusNode("Move into attack range"),
|
new PublishStatusNode("Move into attack range"),
|
||||||
new FaceTargetNode(),
|
new FaceTargetNode(BlackboardKeys.ENTITY_TARGET),
|
||||||
new SucceederNode(new MoveStartNode(MovementRelativeFacing.FORWARD)),
|
new SucceederNode(new MoveStartNode(MovementRelativeFacing.FORWARD)),
|
||||||
new TimerNode(new SucceederNode(null), 600)
|
new TimerNode(new SucceederNode(null), 600)
|
||||||
)
|
)
|
||||||
|
|||||||
@ -1,9 +1,12 @@
|
|||||||
package electrosphere.server.ai.trees.hierarchy.safety.shelter;
|
package electrosphere.server.ai.trees.hierarchy.safety.shelter;
|
||||||
|
|
||||||
|
import electrosphere.engine.Globals;
|
||||||
import electrosphere.server.ai.nodes.AITreeNode;
|
import electrosphere.server.ai.nodes.AITreeNode;
|
||||||
|
import electrosphere.server.ai.nodes.checks.spatial.BeginStructureNode;
|
||||||
import electrosphere.server.ai.nodes.meta.collections.SequenceNode;
|
import electrosphere.server.ai.nodes.meta.collections.SequenceNode;
|
||||||
import electrosphere.server.ai.nodes.meta.debug.PublishStatusNode;
|
import electrosphere.server.ai.nodes.meta.debug.PublishStatusNode;
|
||||||
import electrosphere.server.ai.nodes.meta.decorators.SucceederNode;
|
import electrosphere.server.ai.nodes.meta.decorators.SucceederNode;
|
||||||
|
import electrosphere.server.ai.trees.struct.BuildStructureTree;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tree for constructing shelter
|
* Tree for constructing shelter
|
||||||
@ -22,6 +25,8 @@ public class ConstructShelterTree {
|
|||||||
public static AITreeNode create(){
|
public static AITreeNode create(){
|
||||||
return new SequenceNode(
|
return new SequenceNode(
|
||||||
new PublishStatusNode("Construct a shelter"),
|
new PublishStatusNode("Construct a shelter"),
|
||||||
|
new BeginStructureNode(Globals.gameConfigCurrent.getStructureData().getTypes().iterator().next()),
|
||||||
|
BuildStructureTree.create(),
|
||||||
new SucceederNode(null)
|
new SucceederNode(null)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,93 @@
|
|||||||
|
package electrosphere.server.ai.trees.struct;
|
||||||
|
|
||||||
|
import electrosphere.collision.CollisionEngine;
|
||||||
|
import electrosphere.server.ai.blackboard.Blackboard;
|
||||||
|
import electrosphere.server.ai.blackboard.BlackboardKeys;
|
||||||
|
import electrosphere.server.ai.nodes.AITreeNode;
|
||||||
|
import electrosphere.server.ai.nodes.actions.interact.PlaceBlockNode;
|
||||||
|
import electrosphere.server.ai.nodes.checks.inventory.InventoryContainsNode;
|
||||||
|
import electrosphere.server.ai.nodes.meta.collections.SelectorNode;
|
||||||
|
import electrosphere.server.ai.nodes.meta.collections.SequenceNode;
|
||||||
|
import electrosphere.server.ai.nodes.meta.debug.PublishStatusNode;
|
||||||
|
import electrosphere.server.ai.nodes.meta.decorators.RunnerNode;
|
||||||
|
import electrosphere.server.ai.nodes.solvers.SolveBuildMaterialNode;
|
||||||
|
import electrosphere.server.ai.trees.creature.AcquireItemTree;
|
||||||
|
import electrosphere.server.ai.trees.creature.MoveToTarget;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A tree to build whatever the current structure target is
|
||||||
|
*/
|
||||||
|
public class BuildStructureTree {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 SequenceNode(
|
||||||
|
new PublishStatusNode("Construct a structure"),
|
||||||
|
//figure out current task
|
||||||
|
new SelectorNode(
|
||||||
|
//make sure we know what material we need to build with currently
|
||||||
|
new SequenceNode(
|
||||||
|
new SolveBuildMaterialNode(),
|
||||||
|
new PublishStatusNode("Trying to place block in structure"),
|
||||||
|
//if has building materials
|
||||||
|
new SequenceNode(
|
||||||
|
new InventoryContainsNode(BlackboardKeys.BUILDING_MATERIAL_CURRENT),
|
||||||
|
//if we're within range to place the material
|
||||||
|
new SelectorNode(
|
||||||
|
//in range, place block
|
||||||
|
new PlaceBlockNode(),
|
||||||
|
//not in range, move to within range
|
||||||
|
new SequenceNode(
|
||||||
|
//TODO: Solve for where to move towards
|
||||||
|
MoveToTarget.create(CollisionEngine.DEFAULT_INTERACT_DISTANCE, BlackboardKeys.ENTITY_TARGET)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
//does not have building materials
|
||||||
|
new SequenceNode(
|
||||||
|
new PublishStatusNode("Acquire building material"),
|
||||||
|
//try to find building materials
|
||||||
|
AcquireItemTree.create(BlackboardKeys.BUILDING_MATERIAL_CURRENT),
|
||||||
|
new RunnerNode(null)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the current needed building material
|
||||||
|
* @param blackboard The blackboard
|
||||||
|
* @param entityTypeId The id of the material
|
||||||
|
*/
|
||||||
|
public static void setCurrentMaterial(Blackboard blackboard, String entityTypeId){
|
||||||
|
blackboard.put(BlackboardKeys.BUILDING_MATERIAL_CURRENT, entityTypeId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the blackboard stores the currently sought after material
|
||||||
|
* @param blackboard The blackboard
|
||||||
|
* @return true if there is a currently desired material, false otherwise
|
||||||
|
*/
|
||||||
|
public static boolean hasCurrentMaterial(Blackboard blackboard){
|
||||||
|
return blackboard.has(BlackboardKeys.BUILDING_MATERIAL_CURRENT);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the currently sought after material
|
||||||
|
* @param blackboard The blackboard
|
||||||
|
* @return The id of the entity type of the sought after material if it exists, null otherwise
|
||||||
|
*/
|
||||||
|
public static String getCurrentMaterial(Blackboard blackboard){
|
||||||
|
return (String)blackboard.get(BlackboardKeys.BUILDING_MATERIAL_CURRENT);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -1,6 +1,7 @@
|
|||||||
package electrosphere.server.ai.trees.test;
|
package electrosphere.server.ai.trees.test;
|
||||||
|
|
||||||
import electrosphere.game.data.creature.type.ai.BlockerTreeData;
|
import electrosphere.game.data.creature.type.ai.BlockerTreeData;
|
||||||
|
import electrosphere.server.ai.blackboard.BlackboardKeys;
|
||||||
import electrosphere.server.ai.nodes.AITreeNode;
|
import electrosphere.server.ai.nodes.AITreeNode;
|
||||||
import electrosphere.server.ai.nodes.actions.BlockStartNode;
|
import electrosphere.server.ai.nodes.actions.BlockStartNode;
|
||||||
import electrosphere.server.ai.nodes.actions.combat.MeleeTargetingNode;
|
import electrosphere.server.ai.nodes.actions.combat.MeleeTargetingNode;
|
||||||
@ -25,7 +26,7 @@ public class BlockerAITree {
|
|||||||
return new SequenceNode(
|
return new SequenceNode(
|
||||||
new BlockStartNode(),
|
new BlockStartNode(),
|
||||||
new MeleeTargetingNode(5.0f),
|
new MeleeTargetingNode(5.0f),
|
||||||
new FaceTargetNode()
|
new FaceTargetNode(BlackboardKeys.ENTITY_TARGET)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -248,7 +248,7 @@ public class ServerWorldData {
|
|||||||
* @param real The real position
|
* @param real The real position
|
||||||
* @return The local block grid position
|
* @return The local block grid position
|
||||||
*/
|
*/
|
||||||
public int convertRealToLocalBlockSpace(double real){
|
public static int convertRealToLocalBlockSpace(double real){
|
||||||
return (int)Math.floor(real * BlockChunkData.BLOCKS_PER_UNIT_DISTANCE % BlockChunkData.CHUNK_DATA_WIDTH);
|
return (int)Math.floor(real * BlockChunkData.BLOCKS_PER_UNIT_DISTANCE % BlockChunkData.CHUNK_DATA_WIDTH);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -350,7 +350,7 @@ public class ServerWorldData {
|
|||||||
* @param position The real coordinate
|
* @param position The real coordinate
|
||||||
* @return The local block grid space coordinate
|
* @return The local block grid space coordinate
|
||||||
*/
|
*/
|
||||||
public Vector3i convertRealToLocalBlockSpace(Vector3d position){
|
public static Vector3i convertRealToLocalBlockSpace(Vector3d position){
|
||||||
return new Vector3i(
|
return new Vector3i(
|
||||||
convertRealToLocalBlockSpace(position.x),
|
convertRealToLocalBlockSpace(position.x),
|
||||||
convertRealToLocalBlockSpace(position.y),
|
convertRealToLocalBlockSpace(position.y),
|
||||||
|
|||||||
@ -43,6 +43,10 @@ public class ContentSerialization {
|
|||||||
for(Entity entity : entities){
|
for(Entity entity : entities){
|
||||||
if(!CreatureUtils.hasControllerPlayerId(entity) && !ServerCharacterData.hasServerCharacterDataTree(entity)){
|
if(!CreatureUtils.hasControllerPlayerId(entity) && !ServerCharacterData.hasServerCharacterDataTree(entity)){
|
||||||
EntityType type = CommonEntityUtils.getEntityType(entity);
|
EntityType type = CommonEntityUtils.getEntityType(entity);
|
||||||
|
if(type == EntityType.ENGINE){
|
||||||
|
//do not serialize engine entities
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if(type != null){
|
if(type != null){
|
||||||
EntitySerialization serializedEntity = constructEntitySerialization(entity);
|
EntitySerialization serializedEntity = constructEntitySerialization(entity);
|
||||||
rVal.serializedEntities.add(serializedEntity);
|
rVal.serializedEntities.add(serializedEntity);
|
||||||
@ -114,6 +118,9 @@ public class ContentSerialization {
|
|||||||
*/
|
*/
|
||||||
public static Entity serverHydrateEntitySerialization(Realm realm, EntitySerialization serializedEntity){
|
public static Entity serverHydrateEntitySerialization(Realm realm, EntitySerialization serializedEntity){
|
||||||
Entity rVal = null;
|
Entity rVal = null;
|
||||||
|
if(serializedEntity.getSubtype() == null){
|
||||||
|
throw new Error("Subtype undefined!");
|
||||||
|
}
|
||||||
switch(EntityTypes.fromInt(serializedEntity.getType())){
|
switch(EntityTypes.fromInt(serializedEntity.getType())){
|
||||||
case CREATURE: {
|
case CREATURE: {
|
||||||
CreatureTemplate template = null;
|
CreatureTemplate template = null;
|
||||||
|
|||||||
@ -104,17 +104,17 @@ public class MacroData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//add a test character
|
//add a test character
|
||||||
Character testChar = new Character();
|
// Character testChar = new Character();
|
||||||
testChar.setPos(new Vector3d(ServerWorldData.convertChunkToRealSpace(new Vector3i(32774, 3, 32769))));
|
// testChar.setPos(new Vector3d(ServerWorldData.convertChunkToRealSpace(new Vector3i(32774, 3, 32769))));
|
||||||
Race.setRace(testChar, Race.create("human", "human"));
|
// Race.setRace(testChar, Race.create("human", "human"));
|
||||||
rVal.characters.add(testChar);
|
// rVal.characters.add(testChar);
|
||||||
|
|
||||||
//add a test character
|
//add a test character
|
||||||
Vector3d structPos = ServerWorldData.convertChunkToRealSpace(new Vector3i(32774, 0, 32770));
|
// Vector3d structPos = ServerWorldData.convertChunkToRealSpace(new Vector3i(32774, 0, 32770));
|
||||||
double elevationAtStruct = serverWorldData.getServerTerrainManager().getElevation(32774, 32770, 0, 0);
|
// double elevationAtStruct = serverWorldData.getServerTerrainManager().getElevation(32774, 32770, 0, 0);
|
||||||
structPos.y = elevationAtStruct;
|
// structPos.y = elevationAtStruct;
|
||||||
Structure struct = Structure.createStructure(Globals.gameConfigCurrent.getStructureData().getType("test1"),structPos);
|
// Structure struct = Structure.createStructure(Globals.gameConfigCurrent.getStructureData().getType("test1"),structPos);
|
||||||
rVal.structures.add(struct);
|
// rVal.structures.add(struct);
|
||||||
|
|
||||||
//spawn initial characters in each race
|
//spawn initial characters in each race
|
||||||
//find initial positions to place characters at per race
|
//find initial positions to place characters at per race
|
||||||
|
|||||||
@ -41,6 +41,11 @@ public class Structure extends CharacterData implements MacroAreaObject {
|
|||||||
*/
|
*/
|
||||||
String type;
|
String type;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tracks whether this structure needs repairs or not
|
||||||
|
*/
|
||||||
|
boolean repairable = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
* @param dataType The data type of the structure
|
* @param dataType The data type of the structure
|
||||||
@ -126,5 +131,21 @@ public class Structure extends CharacterData implements MacroAreaObject {
|
|||||||
this.fab = fab;
|
this.fab = fab;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the structure is repairable
|
||||||
|
* @return true if it is repairable, false otherwise
|
||||||
|
*/
|
||||||
|
public boolean isRepairable() {
|
||||||
|
return repairable;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets whether this structure is repairable or not
|
||||||
|
* @param repairable true if it is repairable, false otherwise
|
||||||
|
*/
|
||||||
|
public void setRepairable(boolean repairable) {
|
||||||
|
this.repairable = repairable;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,24 @@
|
|||||||
|
package electrosphere.server.macro.utils;
|
||||||
|
|
||||||
|
import org.joml.Vector3d;
|
||||||
|
|
||||||
|
import electrosphere.game.data.struct.StructureData;
|
||||||
|
import electrosphere.server.macro.MacroData;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utilities for placing structures
|
||||||
|
*/
|
||||||
|
public class StructurePlacementUtils {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets an optimal position to place a structure
|
||||||
|
* @param macroData The macro data
|
||||||
|
* @param structureData The data for the structure
|
||||||
|
* @param approxLocation The location to start searching from
|
||||||
|
* @return The position
|
||||||
|
*/
|
||||||
|
public static Vector3d getPlacementPosition(MacroData macroData, StructureData structureData, Vector3d approxLocation){
|
||||||
|
return approxLocation;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,49 @@
|
|||||||
|
package electrosphere.server.macro.utils;
|
||||||
|
|
||||||
|
import org.joml.Vector3d;
|
||||||
|
import org.joml.Vector3i;
|
||||||
|
|
||||||
|
import electrosphere.client.block.BlockChunkData;
|
||||||
|
import electrosphere.game.data.block.BlockFab;
|
||||||
|
import electrosphere.server.datacell.Realm;
|
||||||
|
import electrosphere.server.datacell.ServerWorldData;
|
||||||
|
import electrosphere.server.datacell.gridded.GriddedDataCellManager;
|
||||||
|
import electrosphere.server.macro.structure.Structure;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utilities for repairing a structure
|
||||||
|
*/
|
||||||
|
public class StructureRepairUtils {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Solves for the next position in the structure's fab that can be repaired
|
||||||
|
* @param realm The realm the structure is within
|
||||||
|
* @param struct The structure
|
||||||
|
* @return The next position that can be repaired if it exists, null otherwise
|
||||||
|
*/
|
||||||
|
public static Vector3i getRepairablePosition(Realm realm, Structure struct){
|
||||||
|
//error checking
|
||||||
|
if(!(realm.getDataCellManager() instanceof GriddedDataCellManager)){
|
||||||
|
throw new Error("Realm is not a gridded realm!");
|
||||||
|
}
|
||||||
|
|
||||||
|
BlockFab fab = struct.getFab();
|
||||||
|
Vector3d structStartPos = struct.getStartPos();
|
||||||
|
GriddedDataCellManager griddedDataCellManager = (GriddedDataCellManager)realm.getDataCellManager();
|
||||||
|
for(int x = 0; x < fab.getDimensions().x; x++){
|
||||||
|
for(int y = 0; y < fab.getDimensions().y; y++){
|
||||||
|
for(int z = 0; z < fab.getDimensions().z; z++){
|
||||||
|
Vector3d offsetPos = new Vector3d(structStartPos).add(x,y,z);
|
||||||
|
Vector3i chunkPos = ServerWorldData.convertRealToChunkSpace(offsetPos);
|
||||||
|
Vector3i blockPos = ServerWorldData.convertRealToLocalBlockSpace(offsetPos);
|
||||||
|
BlockChunkData blockChunkData = griddedDataCellManager.getBlocksAtPosition(chunkPos);
|
||||||
|
if(blockChunkData.getType(blockPos.x, blockPos.y, blockPos.z) != fab.getType(x, y, z)){
|
||||||
|
return new Vector3i(x,y,z);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user