#ifndef GOAP_PLANNER_HPP #define GOAP_PLANNER_HPP #include "action.hpp" #include "godot_cpp/variant/variant.hpp" #include #include #include #include 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 last_edge{}; PlannerNode() = default; PlannerNode(PlannerNode const &src) = default; static PlannerNode goal_node(WorldState const &goal); PlannerNode new_node_along(Ref action) const; }; class Planner : public Node { GDCLASS(Planner, Node); static void _bind_methods(); public: virtual void _ready() override; virtual void _process(double delta_time) override; Array gdscript_make_plan(Ref goal); Vector> make_plan(Ref goal); Variant get_world_property(StringName prop_key); bool can_do(Ref action); Vector find_neighbours_of(PlannerNode &node); Vector> find_actions_satisfying(WorldState requirements); void set_actions(Array actions); Array get_actions() 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> actions{}; // available actions }; struct PlannerNodeHasher { static _FORCE_INLINE_ uint32_t hash(godot::goap::PlannerNode const &node) { uint32_t hash{1}; for(KeyValue 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