tunnel-strategy/src/planner.hpp

104 lines
3.1 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;
virtual void _process(double delta_time) 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;
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
};
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