From 6e55e5293f67c29071f6d0340f919b8cef5facf3 Mon Sep 17 00:00:00 2001
From: Sara <sara@saragerretsen.nl>
Date: Mon, 25 Mar 2024 21:58:30 +0100
Subject: [PATCH] feat: created global world state singleton

---
 src/global_world_state.cpp | 56 ++++++++++++++++++++++++++++++++++++++
 src/global_world_state.hpp | 31 +++++++++++++++++++++
 2 files changed, 87 insertions(+)
 create mode 100644 src/global_world_state.cpp
 create mode 100644 src/global_world_state.hpp

diff --git a/src/global_world_state.cpp b/src/global_world_state.cpp
new file mode 100644
index 0000000..b22257b
--- /dev/null
+++ b/src/global_world_state.cpp
@@ -0,0 +1,56 @@
+#include "global_world_state.hpp"
+#include "character_actor.hpp"
+#include "utils/game_root.hpp"
+
+namespace godot::goap {
+void GlobalWorldState::_bind_methods() {
+#define CLASSNAME GlobalWorldState
+}
+
+bool GlobalWorldState::has_singleton() {
+    return GlobalWorldState::singleton_instance != nullptr;
+}
+
+void GlobalWorldState::_enter_tree() {
+    if(GlobalWorldState::singleton_instance == nullptr)
+        GlobalWorldState::singleton_instance = this;
+}
+
+void GlobalWorldState::_ready() {
+    this->game_mode = GameRoot::get_singleton()->get_game_mode();
+}
+
+void GlobalWorldState::_exit_tree() {
+    if(GlobalWorldState::singleton_instance == this)
+        GlobalWorldState::singleton_instance = nullptr;
+}
+
+void GlobalWorldState::_process(double delta_time) {
+    global_state_cache.clear(); // invalidate cache
+}
+
+Vector3 GlobalWorldState::get_player_position() {
+    return this->game_mode->get_player_instance()->get_character()->get_global_position();
+}
+
+Variant GlobalWorldState::get_world_property(StringName prop_key) {
+    // check if prop key corresponds to a global key
+    if(!prop_key.begins_with("g_"))
+        return nullptr;
+    // check if the key is cached for this frame
+    else if(global_state_cache.has(prop_key))
+        return global_state_cache[prop_key];
+    // fetch by function name
+    StringName const fn = "get_" + prop_key.right(prop_key.length() - 2);
+    if(this->has_method(fn)) {
+        Variant result = this->call(fn);
+        // cache and return
+        this->global_state_cache[prop_key] = result;
+        return result;
+    }
+    return nullptr;
+}
+
+GlobalWorldState *GlobalWorldState::singleton_instance{nullptr};
+}
+
diff --git a/src/global_world_state.hpp b/src/global_world_state.hpp
new file mode 100644
index 0000000..a8f1eed
--- /dev/null
+++ b/src/global_world_state.hpp
@@ -0,0 +1,31 @@
+#ifndef GOAP_GLOBAL_WORLD_STATE_HPP
+#define GOAP_GLOBAL_WORLD_STATE_HPP
+
+#include "action.hpp"
+#include "tunnels_game_mode.hpp"
+#include <godot_cpp/classes/node.hpp>
+
+namespace godot::goap {
+class GlobalWorldState : public Node {
+    GDCLASS(GlobalWorldState, Node);
+    static void _bind_methods();
+public:
+    static bool has_singleton();
+    static GlobalWorldState *get_singleton();
+
+    virtual void _enter_tree() override;
+    virtual void _ready() override;
+    virtual void _exit_tree() override;
+    virtual void _process(double delta_time) override;
+
+    Vector3 get_player_position();
+
+    Variant get_world_property(StringName prop_key);
+private:
+    WorldState global_state_cache{};
+    Ref<TunnelsGameMode> game_mode{};
+    static GlobalWorldState *singleton_instance;
+};
+}
+
+#endif // !GOAP_GLOBAL_WORLD_STATE_HPP