107 lines
3.2 KiB
C++
107 lines
3.2 KiB
C++
#ifndef GOAP_PLANNER_HPP
|
|
#define GOAP_PLANNER_HPP
|
|
|
|
#include "action.hpp"
|
|
#include "godot_cpp/variant/variant.hpp"
|
|
#include <godot_cpp/classes/node.hpp>
|
|
#include <godot_cpp/classes/resource.hpp>
|
|
#include <godot_cpp/templates/vector.hpp>
|
|
#include <godot_cpp/variant/string_name.hpp>
|
|
|
|
namespace godot {
|
|
class CharacterActor;
|
|
|
|
namespace goap {
|
|
class GlobalWorldState;
|
|
|
|
class Goal : public Resource {
|
|
GDCLASS(Goal, Resource);
|
|
static void _bind_methods();
|
|
|
|
void set_goal_state(Dictionary dict);
|
|
Dictionary get_goal_state() const;
|
|
void set_prerequisites(Dictionary dict);
|
|
Dictionary get_prerequisites() const;
|
|
public:
|
|
WorldState goal_state{};
|
|
WorldState prerequisites{};
|
|
};
|
|
|
|
struct PlannerNode {
|
|
WorldState open_requirements{};
|
|
WorldState state{};
|
|
Ref<Action> last_edge{};
|
|
|
|
PlannerNode() = default;
|
|
PlannerNode(PlannerNode const &src) = default;
|
|
|
|
static PlannerNode goal_node(WorldState const &goal);
|
|
|
|
PlannerNode new_node_along(Ref<Action> action) const;
|
|
};
|
|
|
|
class Planner : public Node {
|
|
GDCLASS(Planner, Node);
|
|
static void _bind_methods();
|
|
public:
|
|
virtual void _ready() override;
|
|
|
|
Array gdscript_make_plan(Ref<Goal> goal);
|
|
Vector<Ref<Action>> make_plan(Ref<Goal> goal);
|
|
|
|
Variant get_world_property(StringName prop_key);
|
|
|
|
bool can_do(Ref<Action> action);
|
|
Vector<PlannerNode> find_neighbours_of(PlannerNode &node);
|
|
Vector<Ref<Action>> find_actions_satisfying(WorldState requirements);
|
|
|
|
void set_actions(Array actions);
|
|
Array get_actions() const;
|
|
|
|
void set_goals(Array goals);
|
|
Array get_goals() const;
|
|
private:
|
|
CharacterActor *actor{nullptr}; // the parent actor of this planner
|
|
WorldState cached_world_state{}; // the cached worldstate, cleared for every make_plan call
|
|
GlobalWorldState *global_world_state{nullptr}; // cached singleton instance
|
|
// configured settings
|
|
Vector<Ref<Action>> actions{}; // available actions
|
|
Vector<Ref<Goal>> goals{}; // available goals
|
|
};
|
|
|
|
struct PlannerNodeHasher {
|
|
static _FORCE_INLINE_
|
|
uint32_t hash(godot::goap::PlannerNode const &node) {
|
|
uint32_t hash{1};
|
|
for(KeyValue<StringName, Variant> const &kvp : node.state) {
|
|
hash = hash_murmur3_one_32(kvp.key.hash(), hash);
|
|
hash = hash_murmur3_one_32(kvp.value.hash(), hash);
|
|
}
|
|
return hash_fmix32(hash);
|
|
}
|
|
};
|
|
|
|
static _FORCE_INLINE_ bool operator==(PlannerNode const &lhs, PlannerNode const &rhs) {
|
|
return PlannerNodeHasher::hash(lhs) == PlannerNodeHasher::hash(rhs);
|
|
}
|
|
static _FORCE_INLINE_ bool operator!=(PlannerNode const &lhs, PlannerNode const &rhs) {
|
|
return !(lhs == rhs);
|
|
}
|
|
static _FORCE_INLINE_ bool operator<(PlannerNode const &lhs, PlannerNode const &rhs) {
|
|
return lhs.open_requirements.size() < rhs.open_requirements.size();
|
|
}
|
|
static _FORCE_INLINE_ bool operator>=(PlannerNode const &lhs, PlannerNode const &rhs) {
|
|
return !(lhs < rhs);
|
|
}
|
|
static _FORCE_INLINE_ bool operator>(PlannerNode const &lhs, PlannerNode const &rhs) {
|
|
return lhs.open_requirements.size() > rhs.open_requirements.size();
|
|
}
|
|
static _FORCE_INLINE_ bool operator<=(PlannerNode const &lhs, PlannerNode const &rhs) {
|
|
return !(lhs > rhs);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
#endif // !GOAP_PLANNER_HPP
|