feat: outlined planner, started implementation

This commit is contained in:
Sara 2024-03-25 21:58:48 +01:00
parent 6e55e5293f
commit dfe6349c76
2 changed files with 188 additions and 0 deletions

95
src/planner.cpp Normal file
View file

@ -0,0 +1,95 @@
#include "planner.hpp"
#include "action.hpp"
#include "global_world_state.hpp"
#include "godot_cpp/templates/pair.hpp"
#include "utils/godot_macros.h"
#include <godot_cpp/templates/hash_set.hpp>
#include <godot_cpp/templates/hashfuncs.hpp>
#include <godot_cpp/variant/vector3.hpp>
namespace godot::goap {
void Planner::_bind_methods() {
#define CLASSNAME Planner
GDPROPERTY_HINTED(actions, Variant::OBJECT, PROPERTY_HINT_ARRAY_TYPE, "Action");
}
void Planner::_ready() {
this->global_world_state = GlobalWorldState::get_singleton();
}
void Planner::_process(double delta_time) {
this->cached_world_state.clear();
}
Vector<State> Planner::make_plan(Goal *goal) {
HashMap<PlannerNode, int, PlannerNodeHasher> open{};
open.insert(PlannerNode{{}, goal->goal_state, nullptr}, 0);
HashMap<PlannerNode, Ref<Action>, PlannerNodeHasher> from{};
HashMap<PlannerNode, float, PlannerNodeHasher> score_to_start{};
HashMap<PlannerNode, float, PlannerNodeHasher> heuristic_score{};
PlannerNode current;
while(!open.is_empty()) {
int current_weight = 0;
for(KeyValue<PlannerNode, int> &kvp : open) {
if(kvp.value > current_weight) {
current = kvp.key;
current_weight = kvp.value;
}
}
}
}
Variant Planner::get_world_property(StringName prop_key) {
if(world_state_override.has(prop_key))
return world_state_override.get(prop_key);
if(prop_key.begins_with("g_"))
return this->global_world_state->get_world_property(prop_key);
if(this->cached_world_state.has(prop_key))
return this->cached_world_state[prop_key];
if(this->has_method("get_" + prop_key)) {
Variant val = this->call(prop_key);
this->cached_world_state[prop_key] = val;
return val;
}
return nullptr;
}
bool Planner::can_do(Ref<Action> action) {
for(WorldProperty &prop : action->context_prerequisites) {
if(this->get_world_property(prop.key) != prop.value)
return false;
}
return true;
}
Vector<Ref<Action>> Planner::find_actions_satisfying(WorldState requirements) {
Vector<Ref<Action>> found_actions{};
for(Ref<Action> &act : this->actions) {
for(WorldProperty &prop : requirements) {
if(act->effects.has(prop.key)
&& act->effects.get(prop.key) == prop.value
&& this->can_do(act))
found_actions.push_back(act);
}
}
return found_actions;
}
void Planner::set_actions(Array value) {
this->actions.clear();
for(size_t i{0}; i < value.size(); ++i) {
Ref<Action> act = value[i];
if(act.is_valid())
this->actions.push_back(value[i]);
}
}
Array Planner::get_actions() const {
Array array{};
for(Ref<Action> const &act : this->actions) {
array.push_back(act);
}
return array;
}
}

93
src/planner.hpp Normal file
View file

@ -0,0 +1,93 @@
#ifndef GOAP_PLANNER_HPP
#define GOAP_PLANNER_HPP
#include "action.hpp"
#include "godot_cpp/classes/object.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;
struct State {
static State new_move_to(Vector3 location);
static State new_animate(StringName animation);
static State new_activate(Node *node);
enum Type {
STATE_MOVE_TO,
STATE_ANIMATE,
STATE_ACTIVATE
};
State::Type type;
union {
Vector3 move_to;
StringName animate;
Node *activate;
};
};
class Goal : public Resource {
GDCLASS(Goal, Resource);
static void _bind_methods();
public:
WorldState goal_state{};
};
class Planner : public Node {
GDCLASS(Planner, Node);
static void _bind_methods();
public:
virtual void _ready() override;
virtual void _process(double delta_time) override;
Vector<State> make_plan(Goal *goal);
Variant get_world_property(StringName prop_key);
bool can_do(Ref<Action> action);
Vector<Ref<Action>> find_actions_satisfying(WorldState requirements);
void set_actions(Array actions);
Array get_actions() const;
private:
CharacterActor *actor{nullptr};
WorldState world_state_override{};
WorldState cached_world_state{};
GlobalWorldState *global_world_state{nullptr};
Vector<Ref<Action>> actions{};
};
struct PlannerNode {
WorldState state;
WorldState open_requirements;
Ref<Action> last_edge;
int heuristic_score(Ref<Action> action) {
int score{0};
return score;
}
};
struct PlannerNodeHasher {
static _FORCE_INLINE_ uint32_t hash(godot::goap::PlannerNode const &node) {
VariantHasher variant_hasher{};
Variant a{1};
variant_hasher.hash(a);
}
};
static _FORCE_INLINE_ bool operator==(PlannerNode const& lhs, PlannerNode const& rhs) {
return true;
}
}
}
#endif // !GOAP_PLANNER_HPP