Port LimboAI plugin and editor

This commit is contained in:
Serhii Snitsaruk 2024-01-09 13:34:24 +01:00
parent bb346ef5f2
commit 9645baeb30
30 changed files with 1086 additions and 663 deletions

View File

@ -16,9 +16,11 @@
#include "core/object/class_db.h"
#include "core/templates/list.h"
#include "core/variant/variant.h"
#endif // LIMBOAI_MODULE
#endif // ! LIMBOAI_MODULE
#ifdef LIMBOAI_GDEXTENSION
#endif // LIMBOAI_GDEXTENSION
#include "godot_cpp/core/error_macros.hpp"
#endif // ! LIMBOAI_GDEXTENSION
Ref<BehaviorTree> BehaviorTree::clone() const {
Ref<BehaviorTree> copy = duplicate(false);
@ -29,6 +31,12 @@ Ref<BehaviorTree> BehaviorTree::clone() const {
return copy;
}
void BehaviorTree::copy_from(const Ref<BehaviorTree> &p_other) {
ERR_FAIL_COND(p_other.is_null());
description = p_other->get_description();
root_task = p_other->get_root_task();
}
Ref<BTTask> BehaviorTree::instantiate(Node *p_agent, const Ref<Blackboard> &p_blackboard) const {
ERR_FAIL_COND_V_MSG(root_task == nullptr, memnew(BTTask), "Trying to instance a behavior tree with no valid root task.");
Ref<BTTask> inst = root_task->clone();
@ -42,6 +50,7 @@ void BehaviorTree::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_root_task", "p_value"), &BehaviorTree::set_root_task);
ClassDB::bind_method(D_METHOD("get_root_task"), &BehaviorTree::get_root_task);
ClassDB::bind_method(D_METHOD("clone"), &BehaviorTree::clone);
ClassDB::bind_method(D_METHOD("copy_from", "p_other"), &BehaviorTree::copy_from);
ClassDB::bind_method(D_METHOD("instantiate", "p_agent", "p_blackboard"), &BehaviorTree::instantiate);
ADD_PROPERTY(PropertyInfo(Variant::STRING, "description", PROPERTY_HINT_MULTILINE_TEXT), "set_description", "get_description");

View File

@ -52,6 +52,7 @@ public:
Ref<BTTask> get_root_task() const { return root_task; }
Ref<BehaviorTree> clone() const;
void copy_from(const Ref<BehaviorTree> &p_other);
Ref<BTTask> instantiate(Node *p_agent, const Ref<Blackboard> &p_blackboard) const;
};

View File

@ -12,7 +12,7 @@
#include "bt_state.h"
#include "../editor/debugger/limbo_debugger.h"
#include "../util/limbo_def.h"
#include "../util/limbo_compat.h"
#include "../util/limbo_string_names.h"
#ifdef LIMBOAI_MODULE

View File

@ -382,12 +382,7 @@ void BTTask::print_tree(int p_initial_tabs) {
tabs += "--";
}
#ifdef LIMBOAI_MODULE
print_line(vformat("%s Name: %s Instance: %s", tabs, get_task_name(), Ref<BTTask>(this)));
#endif
#ifdef LIMBOAI_GDEXTENSION
UtilityFunctions::print(vformat("%s Name: %s Instance: %s", tabs, get_task_name(), Ref<BTTask>(this)));
#endif
PRINT_LINE(vformat("%s Name: %s Instance: %s", tabs, get_task_name(), Ref<BTTask>(this)));
for (int i = 0; i < get_child_count(); i++) {
get_child(i)->print_tree(p_initial_tabs + 1);
@ -445,6 +440,7 @@ void BTTask::_bind_methods() {
GDVIRTUAL_BIND(_get_configuration_warning);
#endif // LIMBOAI_MODULE
#ifdef LIMBOAI_GDEXTENSION
// TODO: Until virtual functions are implemented in godot-cpp, we do this. Replace this code when possible.
ClassDB::bind_method(D_METHOD("_setup"), &BTTask::_setup);
ClassDB::bind_method(D_METHOD("_enter"), &BTTask::_enter);
ClassDB::bind_method(D_METHOD("_exit"), &BTTask::_exit);

View File

@ -35,7 +35,7 @@
#ifdef LIMBOAI_GDEXTENSION
#include "blackboard/blackboard.h"
#include "util/limbo_def.h"
#include "util/limbo_compat.h"
#include "util/limbo_string_names.h"
#include "util/limbo_task_db.h"

View File

@ -85,7 +85,7 @@ void BTCooldown::_chill() {
SceneTree *st = (SceneTree *)Engine::get_singleton()->get_main_loop();
timer = st->create_timer(duration, process_pause);
#endif
timer->connect("timeout", callable_mp(this, &BTCooldown::_on_timeout), CONNECT_ONE_SHOT);
timer->connect(LSNAME(timeout), callable_mp(this, &BTCooldown::_on_timeout), CONNECT_ONE_SHOT);
}
}

View File

@ -16,12 +16,12 @@
#endif // LIMBOAI_MODULE
#ifdef LIMBOAI_GDEXTENSION
#include "../util/limbo_def.h"
#include "../util/limbo_compat.h"
#include "../util/limbo_string_names.h"
#include <godot_cpp/classes/button.hpp>
#endif // LIMBOAI_GDEXTENSION
#endif // ! LIMBOAI_GDEXTENSION
void ActionBanner::set_text(const String &p_text) {
message->set_text(p_text);
@ -67,6 +67,7 @@ void ActionBanner::_notification(int p_what) {
}
void ActionBanner::_bind_methods() {
ClassDB::bind_method(D_METHOD("_execute_action", "p_action", "p_auto_close"), &ActionBanner::_execute_action);
}
ActionBanner::ActionBanner() {

View File

@ -18,7 +18,7 @@
#include "scene/gui/label.h"
#include "scene/gui/margin_container.h"
#include "scene/gui/texture_rect.h"
#endif // LIMBOAI_MODULE
#endif // ! LIMBOAI_MODULE
#ifdef LIMBOAI_GDEXTENSION
#include <godot_cpp/classes/h_box_container.hpp>
@ -27,7 +27,7 @@
#include <godot_cpp/classes/texture_rect.hpp>
using namespace godot;
#endif // LIMBOAI_GDEXTENSION
#endif // ! LIMBOAI_GDEXTENSION
class ActionBanner : public MarginContainer {
GDCLASS(ActionBanner, MarginContainer);
@ -55,4 +55,4 @@ public:
ActionBanner();
};
#endif // ACTION_BANNER
#endif // ! ACTION_BANNER

View File

@ -14,6 +14,7 @@
#include "behavior_tree_view.h"
#include "../../bt/tasks/bt_task.h"
#include "../../util/limbo_compat.h"
#include "../../util/limbo_utility.h"
#include "behavior_tree_data.h"
@ -27,6 +28,11 @@
#include "scene/resources/style_box.h"
#endif // LIMBOAI_MODULE
#ifdef LIMBOAI_GDEXTENSION
#include <godot_cpp/classes/editor_interface.hpp>
#endif // LIMBOAI_GDEXTENSION
void BehaviorTreeView::_draw_running_status(Object *p_obj, Rect2 p_rect) {
p_rect = p_rect.grow_side(SIDE_LEFT, p_rect.get_position().x);
theme_cache.sbf_running->draw(tree->get_canvas_item(), p_rect);
@ -167,6 +173,9 @@ void BehaviorTreeView::_do_update_theme_item_cache() {
void BehaviorTreeView::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_READY: {
tree->connect(LSNAME(item_collapsed), callable_mp(this, &BehaviorTreeView::_item_collapsed));
} break;
case NOTIFICATION_POSTINITIALIZE:
case NOTIFICATION_LAYOUT_DIRECTION_CHANGED:
case NOTIFICATION_TRANSLATION_CHANGED:
@ -192,7 +201,6 @@ BehaviorTreeView::BehaviorTreeView() {
tree->set_column_expand(2, false);
tree->set_anchor(SIDE_RIGHT, ANCHOR_END);
tree->set_anchor(SIDE_BOTTOM, ANCHOR_END);
tree->connect(LSNAME(item_collapsed), callable_mp(this, &BehaviorTreeView::_item_collapsed));
}
#endif // TOOLS_ENABLED

View File

@ -129,7 +129,7 @@ void LimboDebugger::_track_tree(NodePath p_path) {
_untrack_tree();
}
Node *node = GET_SCENE_TREE()->get_root()->get_node_or_null(p_path);
Node *node = SCENE_TREE()->get_root()->get_node_or_null(p_path);
ERR_FAIL_COND(node == nullptr);
tracked_player = p_path;
@ -164,7 +164,7 @@ void LimboDebugger::_untrack_tree() {
NodePath was_tracking = tracked_player;
tracked_player = NodePath();
Node *node = GET_SCENE_TREE()->get_root()->get_node_or_null(was_tracking);
Node *node = SCENE_TREE()->get_root()->get_node_or_null(was_tracking);
ERR_FAIL_COND(node == nullptr);
if (node->is_class("BTPlayer")) {

File diff suppressed because it is too large Load Diff

View File

@ -10,14 +10,16 @@
*/
#ifdef TOOLS_ENABLED
#ifndef LIMBO_AI_EDITOR_PLUGIN_H
#define LIMBO_AI_EDITOR_PLUGIN_H
#include "modules/limboai/bt/behavior_tree.h"
#include "modules/limboai/bt/tasks/bt_task.h"
#include "../bt/behavior_tree.h"
#include "../bt/tasks/bt_task.h"
#include "task_palette.h"
#include "task_tree.h"
#ifdef LIMBOAI_MODULE
#include "core/object/class_db.h"
#include "core/object/object.h"
#include "core/templates/hash_set.h"
@ -37,6 +39,31 @@
#include "scene/gui/tree.h"
#include "scene/resources/texture.h"
#define GET_UNDO_REDO() EditorUndoRedoManager::get_singleton()
#endif // ! LIMBOAI_MODULE
#ifdef LIMBOAI_GDEXTENSION
#include <godot_cpp/classes/control.hpp>
#include <godot_cpp/classes/editor_plugin.hpp>
#include <godot_cpp/classes/editor_spin_slider.hpp>
#include <godot_cpp/classes/file_dialog.hpp>
#include <godot_cpp/classes/h_box_container.hpp>
#include <godot_cpp/classes/h_split_container.hpp>
#include <godot_cpp/classes/input_event.hpp>
#include <godot_cpp/classes/menu_button.hpp>
#include <godot_cpp/classes/panel.hpp>
#include <godot_cpp/classes/popup_menu.hpp>
#include <godot_cpp/classes/texture2d.hpp>
#include <godot_cpp/variant/packed_string_array.hpp>
#include <godot_cpp/variant/variant.hpp>
using namespace godot;
#define GET_UNDO_REDO() plugin->get_undo_redo()
#endif // ! LIMBOAI_GDEXTENSION
class LimboAIEditor : public Control {
GDCLASS(LimboAIEditor, Control);
@ -75,8 +102,10 @@ private:
Ref<Texture2D> rename_task_icon;
Ref<Texture2D> change_type_icon;
Ref<Texture2D> extract_subtree_icon;
Ref<Texture2D> behavior_tree_icon;
} theme_cache;
EditorPlugin *plugin;
Vector<Ref<BehaviorTree>> history;
int idx_history;
HashSet<Ref<BehaviorTree>> dirty;
@ -133,15 +162,15 @@ private:
void _load_bt(String p_path);
void _mark_as_dirty(bool p_dirty);
void _create_user_task_dir();
void _edit_project_settings();
void _remove_task_from_favorite(const String &p_task);
void _extract_subtree(const String &p_path);
void _replace_task(const Ref<BTTask> &p_task, const Ref<BTTask> &p_by_task);
void _reload_modified();
void _resave_modified(String _str = "");
void _popup_file_dialog(FileDialog *p_dialog) { p_dialog->popup_centered_clamped(Size2i(700, 500), 0.8f); }
void _rename_task_confirmed();
void _on_tree_rmb(const Vector2 &p_menu_pos);
void _action_selected(int p_id);
void _misc_option_selected(int p_id);
@ -155,24 +184,32 @@ private:
void _on_history_back();
void _on_history_forward();
void _on_task_dragged(Ref<BTTask> p_task, Ref<BTTask> p_to_task, int p_type);
void _on_resources_reload(const Vector<String> &p_resources);
void _on_resources_reload(const PackedStringArray &p_resources);
void _task_type_selected(const String &p_class_or_path);
void _replace_task(const Ref<BTTask> &p_task, const Ref<BTTask> &p_by_task);
virtual void shortcut_input(const Ref<InputEvent> &p_event) override;
void _edit_project_settings();
void _process_shortcut_input(const Ref<InputEvent> &p_event);
#ifdef LIMBOAI_MODULE
virtual void shortcut_input(const Ref<InputEvent> &p_event) override { _process_shortcut_input(p_event); }
#endif // LIMBOAI_MODULE
protected:
virtual void _update_theme_item_cache() override;
virtual void _do_update_theme_item_cache();
void _notification(int p_what);
static void _bind_methods();
public:
void set_plugin(EditorPlugin *p_plugin) { plugin = p_plugin; };
void edit_bt(Ref<BehaviorTree> p_behavior_tree, bool p_force_refresh = false);
void apply_changes();
#ifdef LIMBOAI_GDEXTENSION
virtual void _shortcut_input(const Ref<InputEvent> &p_event) override { _process_shortcut_input(p_event); }
#endif // LIMBOAI_GDEXTENSION
LimboAIEditor();
~LimboAIEditor();
};
@ -184,15 +221,29 @@ private:
LimboAIEditor *limbo_ai_editor;
protected:
static void _bind_methods() {}
void _notification(int p_notification);
public:
virtual String get_name() const override { return "LimboAI"; }
#ifdef LIMBOAI_MODULE
bool has_main_screen() const override { return true; }
virtual String get_name() const override { return "LimboAI"; }
virtual void make_visible(bool p_visible) override;
virtual void apply_changes() override;
virtual void edit(Object *p_object) override;
virtual bool handles(Object *p_object) const override;
#endif // LIMBOAI_MODULE
#ifdef LIMBOAI_GDEXTENSION
bool _has_main_screen() const override { return true; }
virtual String _get_plugin_name() const override { return "LimboAI"; }
virtual void _make_visible(bool p_visible) override;
virtual void _apply_changes() override;
virtual void _edit(Object *p_object) override;
virtual bool _handles(Object *p_object) const override;
#endif // LIMBOAI_GDEXTENSION
LimboAIEditorPlugin();
~LimboAIEditorPlugin();
@ -200,4 +251,4 @@ public:
#endif // LIMBO_AI_EDITOR_PLUGIN_H
#endif // TOOLS_ENABLED
#endif // ! TOOLS_ENABLED

View File

@ -63,6 +63,14 @@ void ModeSwitchButton::clear() {
modes.clear();
}
void ModeSwitchButton::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_READY: {
connect(LSNAME(pressed), callable_mp(this, &ModeSwitchButton::next_mode));
} break;
}
}
void ModeSwitchButton::_bind_methods() {
ClassDB::bind_method(D_METHOD("add_mode", "p_id", "p_icon", "p_tooltip"), &ModeSwitchButton::add_mode);
ClassDB::bind_method(D_METHOD("get_mode"), &ModeSwitchButton::get_mode);
@ -73,5 +81,4 @@ void ModeSwitchButton::_bind_methods() {
}
ModeSwitchButton::ModeSwitchButton() {
call_deferred(LSNAME(connect), LSNAME(pressed), callable_mp(this, &ModeSwitchButton::next_mode));
}

View File

@ -56,6 +56,8 @@ private:
protected:
static void _bind_methods();
void _notification(int p_what);
public:
void add_mode(int p_id, const Ref<Texture2D> &p_icon, const String &p_tooltip = "");
int get_mode() const { return modes.size() > 0 ? modes[current_mode_index].id : -1; }

View File

@ -11,7 +11,7 @@
#include "task_palette.h"
#include "../util/limbo_def.h"
#include "../util/limbo_compat.h"
#include "../util/limbo_string_names.h"
#include "../util/limbo_task_db.h"
#include "../util/limbo_utility.h"
@ -29,6 +29,7 @@
#endif // LIMBO_MODULE
#ifdef LIMBOAI_GDEXTENSION
#include "godot_cpp/core/error_macros.hpp"
#include <godot_cpp/classes/button_group.hpp>
#include <godot_cpp/classes/check_box.hpp>
#include <godot_cpp/classes/config_file.hpp>
@ -98,7 +99,7 @@ void TaskPaletteSection::_on_task_button_gui_input(const Ref<InputEvent> &p_even
}
Ref<InputEventMouseButton> mb = p_event;
if (mb.is_valid() && mb->get_button_index() == MBTN_RIGHT) {
if (mb.is_valid() && mb->get_button_index() == LW_MBTN(RIGHT)) {
emit_signal(LSNAME(task_button_rmb), p_task);
}
}
@ -150,10 +151,15 @@ void TaskPaletteSection::_do_update_theme_item_cache() {
}
void TaskPaletteSection::_notification(int p_what) {
if (p_what == NOTIFICATION_THEME_CHANGED) {
switch (p_what) {
case NOTIFICATION_READY: {
section_header->connect(LSNAME(pressed), callable_mp(this, &TaskPaletteSection::_on_header_pressed));
} break;
case NOTIFICATION_THEME_CHANGED: {
_do_update_theme_item_cache();
BUTTON_SET_ICON(section_header, (is_collapsed() ? theme_cache.arrow_right_icon : theme_cache.arrow_down_icon));
section_header->add_theme_font_override(LSNAME(font), get_theme_font(LSNAME(bold), LSNAME(EditorFonts)));
} break;
}
}
@ -162,12 +168,10 @@ void TaskPaletteSection::_bind_methods() {
ADD_SIGNAL(MethodInfo("task_button_rmb"));
}
TaskPaletteSection::TaskPaletteSection(String p_category_name) {
TaskPaletteSection::TaskPaletteSection() {
section_header = memnew(Button);
add_child(section_header);
section_header->set_text(p_category_name);
section_header->set_focus_mode(FOCUS_NONE);
section_header->connect(LSNAME(pressed), callable_mp(this, &TaskPaletteSection::_on_header_pressed));
tasks_container = memnew(HFlowContainer);
add_child(tasks_container);
@ -248,7 +252,7 @@ void TaskPalette::_on_task_button_rmb(const String &p_task) {
void TaskPalette::_apply_filter(const String &p_text) {
for (int i = 0; i < sections->get_child_count(); i++) {
TaskPaletteSection *sec = Object::cast_to<TaskPaletteSection>(sections->get_child(i));
ERR_FAIL_COND(sec == nullptr);
ERR_FAIL_NULL(sec);
sec->set_filter(p_text);
}
}
@ -401,6 +405,7 @@ void TaskPalette::refresh() {
} else {
for (int i = 0; i < sections->get_child_count(); i++) {
TaskPaletteSection *sec = Object::cast_to<TaskPaletteSection>(sections->get_child(i));
ERR_FAIL_NULL(sec);
if (sec->is_collapsed()) {
collapsed_sections.insert(sec->get_category_name());
}
@ -422,7 +427,8 @@ void TaskPalette::refresh() {
continue;
}
TaskPaletteSection *sec = memnew(TaskPaletteSection(cat));
TaskPaletteSection *sec = memnew(TaskPaletteSection());
sec->set_category_name(cat);
for (String task_meta : tasks) {
Ref<Texture2D> icon = LimboUtility::get_singleton()->get_task_icon(task_meta);
@ -499,6 +505,23 @@ void TaskPalette::_do_update_theme_item_cache() {
void TaskPalette::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_READY: {
// **** Signals
tool_filters->connect(LSNAME(pressed), callable_mp(this, &TaskPalette::_show_filter_popup));
filter_edit->connect(LSNAME(text_changed), callable_mp(this, &TaskPalette::_apply_filter));
tool_refresh->connect(LSNAME(pressed), callable_mp(this, &TaskPalette::refresh));
menu->connect(LSNAME(id_pressed), callable_mp(this, &TaskPalette::_menu_action_selected));
type_all->connect(LSNAME(pressed), callable_mp(this, &TaskPalette::_type_filter_changed));
type_core->connect(LSNAME(pressed), callable_mp(this, &TaskPalette::_type_filter_changed));
type_user->connect(LSNAME(pressed), callable_mp(this, &TaskPalette::_type_filter_changed));
category_all->connect(LSNAME(pressed), callable_mp(this, &TaskPalette::_category_filter_changed));
category_include->connect(LSNAME(pressed), callable_mp(this, &TaskPalette::_category_filter_changed));
category_exclude->connect(LSNAME(pressed), callable_mp(this, &TaskPalette::_category_filter_changed));
category_choice->connect(LSNAME(draw), callable_mp(this, &TaskPalette::_draw_filter_popup_background));
select_all->connect(LSNAME(pressed), callable_mp(this, &TaskPalette::_set_all_filter_categories).bind(true));
deselect_all->connect(LSNAME(pressed), callable_mp(this, &TaskPalette::_set_all_filter_categories).bind(false));
filter_popup->connect(LSNAME(popup_hide), callable_mp(this, &TaskPalette::_update_filter_button));
} break;
case NOTIFICATION_ENTER_TREE: {
Ref<ConfigFile> cf;
cf.instantiate();
@ -590,13 +613,11 @@ TaskPalette::TaskPalette() {
tool_filters->set_flat(true);
tool_filters->set_toggle_mode(true);
tool_filters->set_focus_mode(FocusMode::FOCUS_NONE);
tool_filters->connect("pressed", callable_mp(this, &TaskPalette::_show_filter_popup));
hb->add_child(tool_filters);
filter_edit = memnew(LineEdit);
filter_edit->set_clear_button_enabled(true);
filter_edit->set_placeholder(TTR("Filter tasks"));
filter_edit->connect("text_changed", callable_mp(this, &TaskPalette::_apply_filter));
filter_edit->set_h_size_flags(SIZE_EXPAND_FILL);
hb->add_child(filter_edit);
@ -604,7 +625,6 @@ TaskPalette::TaskPalette() {
tool_refresh->set_tooltip_text(TTR("Refresh tasks"));
tool_refresh->set_flat(true);
tool_refresh->set_focus_mode(FocusMode::FOCUS_NONE);
tool_refresh->connect("pressed", callable_mp(this, &TaskPalette::refresh));
hb->add_child(tool_refresh);
ScrollContainer *sc = memnew(ScrollContainer);
@ -619,7 +639,6 @@ TaskPalette::TaskPalette() {
menu = memnew(PopupMenu);
add_child(menu);
menu->connect("id_pressed", callable_mp(this, &TaskPalette::_menu_action_selected));
filter_popup = memnew(PopupPanel);
{
@ -644,7 +663,6 @@ TaskPalette::TaskPalette() {
type_all->set_focus_mode(FocusMode::FOCUS_NONE);
type_all->set_button_group(type_filter_group);
type_all->set_pressed(true);
type_all->connect("pressed", callable_mp(this, &TaskPalette::_type_filter_changed));
type_filter->add_child(type_all);
type_core = memnew(Button);
@ -653,7 +671,6 @@ TaskPalette::TaskPalette() {
type_core->set_toggle_mode(true);
type_core->set_focus_mode(FocusMode::FOCUS_NONE);
type_core->set_button_group(type_filter_group);
type_core->connect("pressed", callable_mp(this, &TaskPalette::_type_filter_changed));
type_filter->add_child(type_core);
type_user = memnew(Button);
@ -662,7 +679,6 @@ TaskPalette::TaskPalette() {
type_user->set_toggle_mode(true);
type_user->set_focus_mode(FocusMode::FOCUS_NONE);
type_user->set_button_group(type_filter_group);
type_user->connect("pressed", callable_mp(this, &TaskPalette::_type_filter_changed));
type_filter->add_child(type_user);
Control *space1 = memnew(Control);
@ -687,7 +703,6 @@ TaskPalette::TaskPalette() {
category_all->set_focus_mode(FocusMode::FOCUS_NONE);
category_all->set_pressed(true);
category_all->set_button_group(category_filter_group);
category_all->connect("pressed", callable_mp(this, &TaskPalette::_category_filter_changed));
category_filter->add_child(category_all);
category_include = memnew(Button);
@ -696,7 +711,6 @@ TaskPalette::TaskPalette() {
category_include->set_toggle_mode(true);
category_include->set_focus_mode(FocusMode::FOCUS_NONE);
category_include->set_button_group(category_filter_group);
category_include->connect("pressed", callable_mp(this, &TaskPalette::_category_filter_changed));
category_filter->add_child(category_include);
category_exclude = memnew(Button);
@ -705,11 +719,9 @@ TaskPalette::TaskPalette() {
category_exclude->set_toggle_mode(true);
category_exclude->set_focus_mode(FocusMode::FOCUS_NONE);
category_exclude->set_button_group(category_filter_group);
category_exclude->connect("pressed", callable_mp(this, &TaskPalette::_category_filter_changed));
category_filter->add_child(category_exclude);
category_choice = memnew(VBoxContainer);
category_choice->connect("draw", callable_mp(this, &TaskPalette::_draw_filter_popup_background));
vbox->add_child(category_choice);
HBoxContainer *selection_controls = memnew(HBoxContainer);
@ -719,13 +731,11 @@ TaskPalette::TaskPalette() {
select_all = memnew(Button);
select_all->set_tooltip_text(TTR("Select all categories"));
select_all->set_focus_mode(FocusMode::FOCUS_NONE);
select_all->connect("pressed", callable_mp(this, &TaskPalette::_set_all_filter_categories).bind(true));
selection_controls->add_child(select_all);
deselect_all = memnew(Button);
deselect_all->set_tooltip_text(TTR("Deselect all categories"));
deselect_all->set_focus_mode(FocusMode::FOCUS_NONE);
deselect_all->connect("pressed", callable_mp(this, &TaskPalette::_set_all_filter_categories).bind(false));
selection_controls->add_child(deselect_all);
category_scroll = memnew(ScrollContainer);
@ -735,7 +745,6 @@ TaskPalette::TaskPalette() {
category_scroll->add_child(category_list);
}
add_child(filter_popup);
filter_popup->connect("popup_hide", callable_mp(this, &TaskPalette::_update_filter_button));
}
TaskPalette::~TaskPalette() {

View File

@ -20,7 +20,7 @@
#include "scene/gui/flow_container.h"
#include "scene/gui/line_edit.h"
#include "scene/gui/popup.h"
#endif // LIMBOAI_MODULE
#endif // ! LIMBOAI_MODULE
#ifdef LIMBOAI_GDEXTENSION
#include <godot_cpp/classes/button.hpp>
@ -35,7 +35,7 @@
#include <godot_cpp/templates/hash_set.hpp>
using namespace godot;
#endif // LIMBOAI_GDEXTENSION
#endif // ! LIMBOAI_GDEXTENSION
class TaskButton : public Button {
GDCLASS(TaskButton, Button);
@ -74,10 +74,11 @@ private:
void _on_header_pressed();
protected:
virtual void _do_update_theme_item_cache();
static void _bind_methods();
void _notification(int p_what);
static void _bind_methods();
virtual void _do_update_theme_item_cache();
public:
void set_filter(String p_filter);
@ -87,10 +88,9 @@ public:
bool is_collapsed() const;
String get_category_name() const { return section_header->get_text(); }
void set_category_name(const String &p_cat) { section_header->set_text(p_cat); }
TaskPaletteSection() :
TaskPaletteSection("") {}
TaskPaletteSection(String p_category_name);
TaskPaletteSection();
~TaskPaletteSection();
};

View File

@ -13,6 +13,7 @@
#include "../bt/tasks/bt_comment.h"
#include "../bt/tasks/composites/bt_probability_selector.h"
#include "../util/limbo_compat.h"
#include "../util/limbo_utility.h"
#ifdef LIMBOAI_MODULE
@ -21,6 +22,8 @@
#endif // LIMBOAI_MODULE
#ifdef LIMBOAI_GDEXTENSION
#include <godot_cpp/classes/editor_interface.hpp>
using namespace godot;
#endif // LIMBOAI_GDEXTENSION
@ -30,7 +33,6 @@ TreeItem *TaskTree::_create_tree(const Ref<BTTask> &p_task, TreeItem *p_parent,
ERR_FAIL_COND_V(p_task.is_null(), nullptr);
TreeItem *item = tree->create_item(p_parent, p_idx);
item->set_metadata(0, p_task);
// p_task->connect("changed"...)
for (int i = 0; i < p_task->get_child_count(); i++) {
_create_tree(p_task->get_child(i), item);
}
@ -133,12 +135,12 @@ TreeItem *TaskTree::_find_item(const Ref<BTTask> &p_task) const {
}
void TaskTree::_on_item_mouse_selected(const Vector2 &p_pos, MouseButton p_button_index) {
if (p_button_index == MBTN_LEFT) {
if (p_button_index == LW_MBTN(LEFT)) {
Rect2 rect = get_selected_probability_rect();
if (rect != Rect2() && rect.has_point(p_pos)) {
emit_signal(LSNAME(probability_clicked));
}
} else if (p_button_index == MBTN_RIGHT) {
} else if (p_button_index == LW_MBTN(RIGHT)) {
emit_signal(LSNAME(rmb_pressed), get_screen_position() + p_pos);
}
}
@ -355,6 +357,11 @@ void TaskTree::_do_update_theme_item_cache() {
void TaskTree::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_READY: {
tree->connect("item_mouse_selected", callable_mp(this, &TaskTree::_on_item_mouse_selected));
tree->connect("item_selected", callable_mp(this, &TaskTree::_on_item_selected));
tree->connect("item_activated", callable_mp(this, &TaskTree::_on_item_activated));
} break;
case NOTIFICATION_THEME_CHANGED: {
_do_update_theme_item_cache();
_update_tree();
@ -397,16 +404,13 @@ TaskTree::TaskTree() {
tree->set_anchor(SIDE_RIGHT, ANCHOR_END);
tree->set_anchor(SIDE_BOTTOM, ANCHOR_END);
tree->set_allow_rmb_select(true);
tree->connect("item_mouse_selected", callable_mp(this, &TaskTree::_on_item_mouse_selected));
tree->connect("item_selected", callable_mp(this, &TaskTree::_on_item_selected));
tree->connect("item_activated", callable_mp(this, &TaskTree::_on_item_activated));
tree->set_drag_forwarding(callable_mp(this, &TaskTree::_get_drag_data_fw), callable_mp(this, &TaskTree::_can_drop_data_fw), callable_mp(this, &TaskTree::_drop_data_fw));
}
TaskTree::~TaskTree() {
Callable on_task_changed = callable_mp(this, &TaskTree::_on_task_changed);
if (last_selected.is_valid() && last_selected->is_connected("changed", on_task_changed)) {
last_selected->disconnect("changed", on_task_changed);
if (last_selected.is_valid() && last_selected->is_connected(LSNAME(changed), on_task_changed)) {
last_selected->disconnect(LSNAME(changed), on_task_changed);
}
}

49
gdextension/SConstruct Normal file
View File

@ -0,0 +1,49 @@
#!/usr/bin/env python
import os
import sys
env = SConscript("godot-cpp/SConstruct")
# For reference:
# - CCFLAGS are compilation flags shared between C and C++
# - CFLAGS are for C-specific compilation flags
# - CXXFLAGS are for C++-specific compilation flags
# - CPPFLAGS are for pre-processor flags
# - CPPDEFINES are for pre-processor defines
# - LINKFLAGS are for linking flags
# tweak this if you want to use different folders, or more folders, to store your source code in.
env.Append(CPPPATH=["limboai/"])
env.Append(CPPDEFINES = ['LIMBOAI_GDEXTENSION'])
sources = Glob("limboai/*.cpp")
sources += (Glob("limboai/blackboard/*.cpp"))
sources += (Glob("limboai/blackboard/bb_param/*.cpp"))
sources += (Glob("limboai/bt/*.cpp"))
sources += (Glob("limboai/bt/tasks/*.cpp"))
sources += (Glob("limboai/bt/tasks/blackboard/*.cpp"))
sources += (Glob("limboai/bt/tasks/composites/*.cpp"))
sources += (Glob("limboai/bt/tasks/decorators/*.cpp"))
sources += (Glob("limboai/bt/tasks/scene/*.cpp"))
sources += (Glob("limboai/bt/tasks/utility/*.cpp"))
sources += (Glob("limboai/editor/*.cpp"))
sources += (Glob("limboai/editor/debugger/behavior_tree_data.cpp"))
sources += (Glob("limboai/editor/debugger/behavior_tree_view.cpp"))
sources += (Glob("limboai/editor/debugger/limbo_debugger.cpp"))
sources += (Glob("limboai/hsm/*.cpp"))
sources += (Glob("limboai/util/*.cpp"))
if env["platform"] == "macos":
library = env.SharedLibrary(
"demo/bin/liblimboai.{}.{}.framework/liblimboai.{}.{}".format(
env["platform"], env["target"], env["platform"], env["target"]
),
source=sources,
)
else:
library = env.SharedLibrary(
"demo/bin/liblimboai{}{}".format(env["suffix"], env["SHLIBSUFFIX"]),
source=sources,
)
Default(library)

View File

@ -0,0 +1,27 @@
[configuration]
entry_symbol = "limboai_init"
compatibility_minimum = "4.2"
[libraries]
macos.debug = "res://bin/liblimboai.macos.editor.framework"
macos.release = "res://bin/liblimboai.macos.template_release.framework"
windows.debug.x86_32 = "res://bin/liblimboai.windows.editor.x86_32.dll"
windows.release.x86_32 = "res://bin/liblimboai.windows.template_release.x86_32.dll"
windows.debug.x86_64 = "res://bin/liblimboai.windows.editor.x86_64.dll"
windows.release.x86_64 = "res://bin/liblimboai.windows.template_release.x86_64.dll"
linux.debug.x86_64 = "liblimboai.linux.editor.dev.x86_64.so"
linux.release.x86_64 = "res://bin/liblimboai.linux.template_release.x86_64.so"
linux.debug.arm64 = "res://bin/liblimboai.linux.editor.arm64.so"
linux.release.arm64 = "res://bin/liblimboai.linux.template_release.arm64.so"
linux.debug.rv64 = "res://bin/liblimboai.linux.editor.rv64.so"
linux.release.rv64 = "res://bin/liblimboai.linux.template_release.rv64.so"
android.debug.x86_64 = "res://bin/liblimboai.android.template_debug.x86_64.so"
android.release.x86_64 = "res://bin/liblimboai.android.template_release.x86_64.so"
android.debug.arm64 = "res://bin/liblimboai.android.template_debug.arm64.so"
android.release.arm64 = "res://bin/liblimboai.android.template_release.arm64.so"
[icons]
GDExample = "res://icons/gd_example.svg"

View File

@ -11,7 +11,7 @@
#include "limbo_state.h"
#include "../util/limbo_def.h"
#include "../util/limbo_compat.h"
#ifdef LIMBOAI_MODULE
#include "core/error/error_macros.h"

View File

@ -90,7 +90,10 @@
#include "bt/tasks/utility/bt_random_wait.h"
#include "bt/tasks/utility/bt_wait.h"
#include "bt/tasks/utility/bt_wait_ticks.h"
#include "editor/action_banner.h"
#include "editor/debugger/behavior_tree_data.h"
#include "editor/debugger/limbo_debugger.h"
#include "editor/mode_switch_button.h"
#include "hsm/limbo_hsm.h"
#include "hsm/limbo_state.h"
#include "util/limbo_string_names.h"
@ -100,16 +103,33 @@
#ifdef TOOLS_ENABLED
#include "editor/debugger/behavior_tree_view.h"
#include "editor/limbo_ai_editor_plugin.h"
#endif
#endif // ! TOOLS_ENABLED
#ifdef LIMBOAI_MODULE
#include "core/object/class_db.h"
#include "core/os/memory.h"
#include "core/string/print_string.h"
#endif // ! LIMBOAI_MODULE
#ifdef LIMBOAI_GDEXTENSION
#include <godot_cpp/classes/engine.hpp>
#include <godot_cpp/core/class_db.hpp>
#include <godot_cpp/core/memory.hpp>
using namespace godot;
#endif // ! LIMBOAI_GDEXTENSION
static LimboUtility *_limbo_utility = nullptr;
void initialize_limboai_module(ModuleInitializationLevel p_level) {
if (p_level == MODULE_INITIALIZATION_LEVEL_SCENE) {
#ifdef LIMBOAI_GDEXTENSION
GDREGISTER_CLASS(LimboDebugger);
#endif
LimboDebugger::initialize();
GDREGISTER_CLASS(LimboUtility);
@ -149,76 +169,85 @@ void initialize_limboai_module(ModuleInitializationLevel p_level) {
LIMBO_REGISTER_TASK(BTCooldown);
LIMBO_REGISTER_TASK(BTProbability);
LIMBO_REGISTER_TASK(BTForEach);
LIMBO_REGISTER_TASK(BTNewScope);
LIMBO_REGISTER_TASK(BTSubtree);
GDREGISTER_CLASS(BTAction);
GDREGISTER_CLASS(BTCondition);
LIMBO_REGISTER_TASK(BTAwaitAnimation);
LIMBO_REGISTER_TASK(BTCallMethod);
LIMBO_REGISTER_TASK(BTConsolePrint);
LIMBO_REGISTER_TASK(BTFail);
LIMBO_REGISTER_TASK(BTNewScope);
LIMBO_REGISTER_TASK(BTPauseAnimation);
LIMBO_REGISTER_TASK(BTPlayAnimation);
LIMBO_REGISTER_TASK(BTRandomWait);
LIMBO_REGISTER_TASK(BTSetAgentProperty);
LIMBO_REGISTER_TASK(BTSetVar);
LIMBO_REGISTER_TASK(BTStopAnimation);
LIMBO_REGISTER_TASK(BTSubtree);
LIMBO_REGISTER_TASK(BTWait);
LIMBO_REGISTER_TASK(BTWaitTicks);
GDREGISTER_CLASS(BTCondition);
LIMBO_REGISTER_TASK(BTCheckAgentProperty);
LIMBO_REGISTER_TASK(BTCheckTrigger);
LIMBO_REGISTER_TASK(BTCheckVar);
GDREGISTER_ABSTRACT_CLASS(BBParam);
GDREGISTER_CLASS(BBInt);
GDREGISTER_CLASS(BBAabb);
GDREGISTER_CLASS(BBArray);
GDREGISTER_CLASS(BBBasis);
GDREGISTER_CLASS(BBBool);
GDREGISTER_CLASS(BBByteArray);
GDREGISTER_CLASS(BBColor);
GDREGISTER_CLASS(BBColorArray);
GDREGISTER_CLASS(BBDictionary);
GDREGISTER_CLASS(BBFloat);
GDREGISTER_CLASS(BBString);
GDREGISTER_CLASS(BBVector2);
GDREGISTER_CLASS(BBVector2i);
GDREGISTER_CLASS(BBRect2);
GDREGISTER_CLASS(BBRect2i);
GDREGISTER_CLASS(BBVector3);
GDREGISTER_CLASS(BBVector3i);
GDREGISTER_CLASS(BBTransform2D);
GDREGISTER_CLASS(BBVector4);
GDREGISTER_CLASS(BBVector4i);
GDREGISTER_CLASS(BBFloatArray);
GDREGISTER_CLASS(BBInt);
GDREGISTER_CLASS(BBIntArray);
GDREGISTER_CLASS(BBNode);
GDREGISTER_CLASS(BBPlane);
GDREGISTER_CLASS(BBQuaternion);
GDREGISTER_CLASS(BBAabb);
GDREGISTER_CLASS(BBBasis);
GDREGISTER_CLASS(BBTransform3D);
GDREGISTER_CLASS(BBColor);
GDREGISTER_CLASS(BBStringName);
GDREGISTER_CLASS(BBColor);
GDREGISTER_CLASS(BBNode);
GDREGISTER_CLASS(BBDictionary);
GDREGISTER_CLASS(BBArray);
GDREGISTER_CLASS(BBByteArray);
GDREGISTER_CLASS(BBIntArray);
GDREGISTER_CLASS(BBFloatArray);
GDREGISTER_CLASS(BBColorArray);
GDREGISTER_CLASS(BBRect2);
GDREGISTER_CLASS(BBRect2i);
GDREGISTER_CLASS(BBString);
GDREGISTER_CLASS(BBStringArray);
GDREGISTER_CLASS(BBVector2Array);
GDREGISTER_CLASS(BBVector3Array);
GDREGISTER_CLASS(BBStringName);
GDREGISTER_CLASS(BBTransform2D);
GDREGISTER_CLASS(BBTransform3D);
GDREGISTER_CLASS(BBVariant);
GDREGISTER_CLASS(BBVector2);
GDREGISTER_CLASS(BBVector2Array);
GDREGISTER_CLASS(BBVector2i);
GDREGISTER_CLASS(BBVector3);
GDREGISTER_CLASS(BBVector3Array);
GDREGISTER_CLASS(BBVector3i);
GDREGISTER_CLASS(BBVector4);
GDREGISTER_CLASS(BBVector4i);
_limbo_utility = memnew(LimboUtility);
#ifdef LIMBOAI_MODULE
Engine::get_singleton()->add_singleton(Engine::Singleton("LimboUtility", LimboUtility::get_singleton()));
#endif
LimboStringNames::create();
}
#ifdef TOOLS_ENABLED
if (p_level == MODULE_INITIALIZATION_LEVEL_EDITOR) {
EditorPlugins::add_by_type<LimboAIEditorPlugin>();
} // else if (p_level == MODULE_INITIALIZATION_LEVEL_SCENE) {
#ifdef LIMBOAI_GDEXTENSION
// GDREGISTER_CLASS(BehaviorTreeView);
// }
GDREGISTER_CLASS(TaskTree);
GDREGISTER_CLASS(TaskButton);
GDREGISTER_CLASS(TaskPaletteSection);
GDREGISTER_CLASS(TaskPalette);
GDREGISTER_CLASS(ActionBanner);
GDREGISTER_CLASS(ModeSwitchButton);
GDREGISTER_CLASS(LimboAIEditor);
GDREGISTER_CLASS(LimboAIEditorPlugin);
#endif // ! LIMBOAI_GDEXTENSION
EditorPlugins::add_by_type<LimboAIEditorPlugin>();
}
#endif
#endif // ! TOOLS_ENABLED
}
void uninitialize_limboai_module(ModuleInitializationLevel p_level) {
@ -228,3 +257,18 @@ void uninitialize_limboai_module(ModuleInitializationLevel p_level) {
memdelete(_limbo_utility);
}
}
#ifdef LIMBOAI_GDEXTENSION
extern "C" {
// Initialization.
GDExtensionBool GDE_EXPORT limboai_init(GDExtensionInterfaceGetProcAddress p_get_proc_address, const GDExtensionClassLibraryPtr p_library, GDExtensionInitialization *r_initialization) {
godot::GDExtensionBinding::InitObject init_obj(p_get_proc_address, p_library, r_initialization);
init_obj.register_initializer(initialize_limboai_module);
init_obj.register_terminator(uninitialize_limboai_module);
init_obj.set_minimum_library_initialization_level(MODULE_INITIALIZATION_LEVEL_SCENE);
return init_obj.init();
}
#endif // ! LIMBOAI_GDEXTENSION
}

View File

@ -12,8 +12,20 @@
#ifndef LIMBOAI_REGISTER_TYPES_H
#define LIMBOAI_REGISTER_TYPES_H
#ifdef LIMBOAI_MODULE
#include "modules/register_module_types.h"
#endif // LIMBOAI_MODULE
#ifdef LIMBOAI_GDEXTENSION
#include <godot_cpp/core/class_db.hpp>
using namespace godot;
#endif // LIMBOAI_GDEXTENSION
void initialize_limboai_module(ModuleInitializationLevel p_level);
void uninitialize_limboai_module(ModuleInitializationLevel p_level);

View File

@ -9,7 +9,7 @@
* =============================================================================
*/
#include "limbo_def.h"
#include "limbo_compat.h"
#ifdef LIMBOAI_MODULE
@ -25,6 +25,7 @@ void EDIT_SCRIPT(const String &p_path) {
#include "godot_cpp/classes/editor_interface.hpp"
#include <godot_cpp/classes/editor_settings.hpp>
#include <godot_cpp/classes/project_settings.hpp>
#include <godot_cpp/classes/resource_loader.hpp>
#include <godot_cpp/classes/script.hpp>
#include <godot_cpp/classes/translation_server.hpp>
@ -51,4 +52,35 @@ void EDIT_SCRIPT(const String &p_path) {
EditorInterface::get_singleton()->edit_script(res);
}
Variant _GLOBAL_DEF(const String &p_var, const Variant &p_default, bool p_restart_if_changed, bool p_ignore_value_in_docs, bool p_basic, bool p_internal) {
Variant ret;
if (!ProjectSettings::get_singleton()->has_setting(p_var)) {
ProjectSettings::get_singleton()->set(p_var, p_default);
}
ret = GLOBAL_GET(p_var);
ProjectSettings::get_singleton()->set_initial_value(p_var, p_default);
// ProjectSettings::get_singleton()->set_builtin_order(p_var);
ProjectSettings::get_singleton()->set_as_basic(p_var, p_basic);
ProjectSettings::get_singleton()->set_restart_if_changed(p_var, p_restart_if_changed);
// ProjectSettings::get_singleton()->set_ignore_value_in_docs(p_var, p_ignore_value_in_docs);
ProjectSettings::get_singleton()->set_as_internal(p_var, p_internal);
return ret;
}
Variant _GLOBAL_DEF(const PropertyInfo &p_info, const Variant &p_default, bool p_restart_if_changed, bool p_ignore_value_in_docs, bool p_basic, bool p_internal) {
Variant ret = _GLOBAL_DEF(p_info.name, p_default, p_restart_if_changed, p_ignore_value_in_docs, p_basic, p_internal);
Dictionary dic_info;
dic_info["type"] = p_info.type;
dic_info["name"] = p_info.name;
dic_info["class_name"] = p_info.class_name;
dic_info["hint"] = p_info.hint;
dic_info["hint_string"] = p_info.hint_string;
dic_info["usage"] = p_info.usage;
ProjectSettings::get_singleton()->add_property_info(dic_info);
return ret;
}
#endif // LIMBOAI_GDEXTENSION

152
util/limbo_compat.h Normal file
View File

@ -0,0 +1,152 @@
#/**
* limbo_compat.h
* =============================================================================
* Copyright 2021-2024 Serhii Snitsaruk
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE file or at
* https://opensource.org/licenses/MIT.
* =============================================================================
*/
/*
* Defines and funcs that help to bridge some differences between GDExtension and Godot APIs.
* This helps us writing compatible code with both module and GDExtension.
*/
#ifndef LIMBO_COMPAT_H
#define LIMBO_COMPAT_H
#ifdef LIMBOAI_MODULE
#include "core/string/print_string.h"
// * API abstractions: Module edition
#define SCRIPT_EDITOR() (ScriptEditor::get_singleton())
#define EDITOR_FILE_SYSTEM() (EditorFileSystem::get_singleton())
#define EDITOR_SETTINGS() (EditorSettings::get_singleton())
#define BASE_CONTROL() (EditorNode::get_singleton()->get_gui_base())
#define MAIN_SCREEN_CONTROL(EditorNode::get_singleton()->get_main_screen_control())
#define SCENE_TREE() (SceneTree::get_singleton())
#define IS_DEBUGGER_ACTIVE() (EngineDebugger::is_active())
#define PRINT_LINE(...) (print_line(__VA_ARGS__))
#define IS_CLASS(m_obj, m_class) (m_obj->is_class_ptr(m_class::get_class_ptr_static()))
#define RAND_RANGE(m_from, m_to) (Math::random(m_from, m_to))
#define RANDF() (Math::randf())
#define VCALL(m_method) (GDVIRTUAL_CALL(method))
#define VCALL_ARGS(method, ...) (call(LSNAME(method), __VA_ARGS__))
#define BUTTON_SET_ICON(m_btn, m_icon) m_btn->set_icon(m_icon)
#define RESOURCE_LOAD(m_path, m_hint) ResourceLoader::load(m_path, m_hint)
#define RESOURCE_LOAD_NO_CACHE(m_path, m_hint) ResourceLoader::load(m_path, m_hint, ResourceLoader::CACHE_MODE_IGNORE)
#define RESOURCE_SAVE(m_res, m_path, m_flags) ResourceSaver::save(m_res, m_path, m_flags)
#define RESOURCE_IS_CACHED(m_path) (ResourceCache::has(m_path))
#define RESOURCE_GET_TYPE(m_path) (ResourceLoader::get_resource_type(m_path))
#define RESOURCE_EXISTS(m_path, m_type_hint) (ResourceLoader::exists(m_path, m_type_hint))
#define GET_PROJECT_SETTINGS_DIR() EditorPaths::get_singleton()->get_project_settings_dir()
#define EDIT_RESOURCE(m_res) EditorNode::get_singleton()->edit_resource(m_res)
#define INSPECTOR_GET_EDITED_OBJECT() (InspectorDock::get_inspector_singleton()->get_edited_object())
#define SET_MAIN_SCREEN_EDITOR(m_name) (EditorNode::get_singleton()->select_editor_by_name(m_name))
#define FILE_EXISTS(m_path) FileAccess::exists(m_path)
#define DIR_ACCESS_CREATE() DirAccess::create(DirAccess::ACCESS_RESOURCES)
#define SHOW_DOC(m_doc) ( \
ScriptEditor::get_singleton()->goto_help(m_doc); \
EditorNode::get_singleton()->set_visible_editor(EditorNode::EDITOR_SCRIPT);)
#define VARIANT_EVALUATE(m_op, m_lvalue, m_rvalue, r_ret) r_ret = Variant::evaluate(m_op, m_lvalue, m_rvalue)
// * Enum
#define LW_KEY(key) (Key::key)
#define LW_KEY_MASK(mask) (KeyModifierMask::##mask)
#define LW_MBTN(key) (MouseButton::key)
#endif // ! LIMBOAI_MODULE
#ifdef LIMBOAI_GDEXTENSION
#include <godot_cpp/classes/ref_counted.hpp>
#include <godot_cpp/variant/utility_functions.hpp>
#include <godot_cpp/variant/variant.hpp>
using namespace godot;
// * API abstractions: GDExtension edition
#define SCRIPT_EDITOR() (EditorInterface::get_singleton()->get_script_editor())
#define EDITOR_FILE_SYSTEM() (EditorInterface::get_singleton()->get_resource_filesystem())
#define EDITOR_SETTINGS() (EditorInterface::get_singleton()->get_editor_settings())
#define BASE_CONTROL() (EditorInterface::get_singleton()->get_base_control())
#define MAIN_SCREEN_CONTROL() (EditorInterface::get_singleton()->get_editor_main_screen())
#define SCENE_TREE() ((SceneTree *)(Engine::get_singleton()->get_main_loop()))
#define IS_DEBUGGER_ACTIVE() (EngineDebugger::get_singleton()->is_active())
#define PRINT_LINE(...) (UtilityFunctions::print(__VA_ARGS__))
#define IS_CLASS(m_obj, m_class) (m_obj->get_class_static() == m_class::get_class_static())
#define RAND_RANGE(m_from, m_to) (UtilityFunctions::randf_range(m_from, m_to))
#define RANDF() (UtilityFunctions::randf())
#define VCALL(m_name) (call(LSNAME(m_name)))
#define VCALL_ARGS(m_name, ...) (call(LSNAME(m_name), __VA_ARGS__))
#define BUTTON_SET_ICON(m_btn, m_icon) m_btn->set_button_icon(m_icon)
#define RESOURCE_LOAD(m_path, m_hint) ResourceLoader::get_singleton()->load(m_path, m_hint)
#define RESOURCE_LOAD_NO_CACHE(m_path, m_hint) ResourceLoader::get_singleton()->load(m_path, m_hint, ResourceLoader::CACHE_MODE_IGNORE)
#define RESOURCE_SAVE(m_res, m_path, m_flags) ResourceSaver::get_singleton()->save(m_res, m_path, m_flags)
#define RESOURCE_IS_CACHED(m_path) (ResourceLoader::get_singleton()->has_cached(res_path))
#define RESOURCE_GET_TYPE(m_path) (ResourceLoader::get_resource_type(m_path))
#define RESOURCE_EXISTS(m_path, m_type_hint) (ResourceLoader::get_singleton()->exists(m_path, m_type_hint))
#define GET_PROJECT_SETTINGS_DIR() EditorInterface::get_singleton()->get_editor_paths()->get_project_settings_dir()
#define EDIT_RESOURCE(m_res) EditorInterface::get_singleton()->edit_resource(m_res)
void EDIT_SCRIPT(const String &p_path); // TODO: need a module version!
#define INSPECTOR_GET_EDITED_OBJECT() (EditorInterface::get_singleton()->get_inspector()->get_edited_object())
#define SET_MAIN_SCREEN_EDITOR(m_name) (EditorInterface::get_singleton()->set_main_screen_editor(m_name))
#define FILE_EXISTS(m_path) FileAccess::file_exists(m_path)
#define DIR_ACCESS_CREATE() DirAccess::open("res://")
#define SHOW_DOC(m_doc) EditorInterface::get_singleton()->get_script_editor()->get_current_editor()->emit_signal("go_to_help", m_doc)
#define VARIANT_EVALUATE(m_op, m_lvalue, m_rvalue, r_ret) \
{ \
bool r_valid; \
Variant::evaluate(m_op, m_lvalue, m_rvalue, r_ret, r_valid); \
}
// * Enums
#define LW_KEY(key) (Key::KEY_##key)
#define LW_KEY_MASK(mask) (KeyModifierMask::KEY_MASK_##mask)
#define LW_MBTN(key) (MouseButton::MOUSE_BUTTON_##key)
// * Missing defines
#define EDITOR_GET(m_var) _EDITOR_GET(m_var)
Variant _EDITOR_GET(const String &p_setting);
#define GLOBAL_GET(m_var) ProjectSettings::get_singleton()->get_setting_with_override(m_var)
#define GLOBAL_DEF(m_var, m_value) _GLOBAL_DEF(m_var, m_value)
Variant _GLOBAL_DEF(const String &p_var, const Variant &p_default, bool p_restart_if_changed = false, bool p_ignore_value_in_docs = false, bool p_basic = false, bool p_internal = false);
Variant _GLOBAL_DEF(const PropertyInfo &p_info, const Variant &p_default, bool p_restart_if_changed = false, bool p_ignore_value_in_docs = false, bool p_basic = false, bool p_internal = false);
#define EDSCALE (EditorInterface::get_singleton()->get_editor_scale())
String TTR(const String &p_text, const String &p_context = "");
#endif // ! LIMBOAI_GDEXTENSION
// * Shared defines
#define VARIANT_IS_ARRAY(m_variant) (m_variant.get_type() >= Variant::ARRAY)
#define VARIANT_IS_NUM(m_variant) (m_variant.get_type() == Variant::INT || m_variant.get_type() == Variant::FLOAT)
inline void VARIANT_DELETE_IF_OBJECT(Variant m_variant) {
if (m_variant.get_type() == Variant::OBJECT) {
Ref<RefCounted> r = m_variant;
if (r.is_null()) {
memdelete((Object *)m_variant);
}
}
}
#endif // LIMBO_COMPAT_H

View File

@ -1,85 +0,0 @@
#/**
* limbo_def.h
* =============================================================================
* Copyright 2021-2024 Serhii Snitsaruk
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE file or at
* https://opensource.org/licenses/MIT.
* =============================================================================
*/
#ifndef LIMBO_DEF_H
#define LIMBO_DEF_H
#ifdef LIMBOAI_MODULE
#include "core/string/print_string.h"
#define IS_CLASS(m_obj, m_class) (m_obj->is_class_ptr(m_class::get_class_ptr_static()))
#define RAND_RANGE(m_from, m_to) (Math::random(m_from, m_to))
#define RANDF() (Math::randf())
#define PRINT_LINE(...) (print_line(__VA_ARGS__))
#define IS_DEBUGGER_ACTIVE() (EngineDebugger::is_active())
#define GET_SCENE_TREE() (SceneTree::get_singleton())
#define VCALL(m_method) (GDVIRTUAL_CALL(method))
#define VCALL_ARGS(method, ...) (call(LSNAME(method), __VA_ARGS__))
#define BUTTON_SET_ICON(m_btn, m_icon) m_btn->set_icon(m_icon)
#define RESOURCE_LOAD(m_path, m_hint) ResourceLoader::load(m_path, m_hint)
#define GET_PROJECT_SETTINGS_DIR() EditorPaths::get_singleton()->get_project_settings_dir()
#define SHOW_DOC(m_doc) ( \
ScriptEditor::get_singleton()->goto_help(m_doc); \
EditorNode::get_singleton()->set_visible_editor(EditorNode::EDITOR_SCRIPT);)
#define MBTN_RIGHT MouseButton::RIGHT
#define MBTN_LEFT MouseButton::LEFT
#endif // LIMBOAI_MODULE
#ifdef LIMBOAI_GDEXTENSION
#include <godot_cpp/variant/string.hpp>
#include <godot_cpp/variant/utility_functions.hpp>
#include <godot_cpp/variant/variant.hpp>
using namespace godot;
#define IS_CLASS(m_obj, m_class) (m_obj->get_class_static() == m_class::get_class_static())
#define RAND_RANGE(m_from, m_to) (UtilityFunctions::randf_range(m_from, m_to))
#define RANDF() (UtilityFunctions::randf())
#define PRINT_LINE(...) (UtilityFunctions::print(__VA_ARGS__))
#define IS_DEBUGGER_ACTIVE() (EngineDebugger::get_singleton()->is_active())
#define GET_SCENE_TREE() ((SceneTree *)(Engine::get_singleton()->get_main_loop()))
#define VCALL(m_name) (call(LSNAME(m_name)))
#define VCALL_ARGS(m_name, ...) (call(LSNAME(m_name), __VA_ARGS__))
#define BUTTON_SET_ICON(m_btn, m_icon) m_btn->set_button_icon(m_icon)
#define RESOURCE_LOAD(m_path, m_hint) ResourceLoader::get_singleton()->load(m_path, m_hint)
#define GET_PROJECT_SETTINGS_DIR() EditorInterface::get_singleton()->get_editor_paths()->get_project_settings_dir()
#define SHOW_DOC(m_doc) EditorInterface::get_singleton()->get_script_editor()->get_current_editor()->emit_signal("go_to_help", m_doc)
#define MBTN_RIGHT MouseButton::MOUSE_BUTTON_RIGHT
#define MBTN_LEFT MouseButton::MOUSE_BUTTON_LEFT
// Missing definitions
#define EDITOR_GET(m_var) _EDITOR_GET(m_var)
Variant _EDITOR_GET(const String &p_setting);
#define GLOBAL_GET(m_var) ProjectSettings::get_singleton()->get_setting_with_override(m_var)
#define EDSCALE ((int)EDITOR_GET("interface/editor/display_scale"))
String TTR(const String &p_text, const String &p_context = "");
#endif // LIMBOAI_GDEXTENSION
// ! Shared definitions.
void EDIT_SCRIPT(const String &p_path);
#define VARIANT_IS_ARRAY(m_variant) (m_variant.get_type() >= Variant::ARRAY)
#define VARIANT_IS_NUM(m_variant) (m_variant.get_type() == Variant::INT || m_variant.get_type() == Variant::FLOAT)
#endif // LIMBO_DEF_H

View File

@ -10,85 +10,121 @@
*/
#include "limbo_string_names.h"
#include "godot_cpp/variant/string_name.hpp"
#ifdef LIMBOAI_MODULE
#define SN(m_arg) (StaticCString::create(m_arg))
#endif // LIMBOAI_MODULE
#endif // ! LIMBOAI_MODULE
#ifdef LIMBOAI_GDEXTENSION
#include "godot_cpp/variant/string_name.hpp"
#define SN(m_arg) (StringName(m_arg))
#endif // LIMBOAI_GDEXTENSION
#endif // ! LIMBOAI_GDEXTENSION
LimboStringNames *LimboStringNames::singleton = nullptr;
LimboStringNames::LimboStringNames() {
_generate_name = SN("_generate_name");
_setup = SN("_setup");
_draw_failure_status = SN("_draw_failure_status");
_draw_probability = SN("_draw_probability");
_draw_running_status = SN("_draw_running_status");
_draw_success_status = SN("_draw_success_status");
_enter = SN("_enter");
_exit = SN("_exit");
_tick = SN("_tick");
behavior_tree_finished = SN("behavior_tree_finished");
setup = SN("setup");
entered = SN("entered");
exited = SN("exited");
updated = SN("updated");
_update = SN("_update");
state_changed = SN("state_changed");
_generate_name = SN("_generate_name");
_get_configuration_warning = SN("_get_configuration_warning");
changed = SN("changed");
changed = SN("emit_changed");
_replace_task = SN("_replace_task");
_setup = SN("_setup");
_tick = SN("_tick");
_update = SN("_update");
_update_banners = SN("_update_banners");
_weight_ = SN("_weight_");
error_value = SN("error_value");
accent_color = SN("accent_color");
add_child = SN("add_child");
add_child_at_index = SN("add_child_at_index");
AnimationFilter = SN("AnimationFilter");
Back = SN("Back");
behavior_tree = SN("behavior_tree");
_draw_success_status = SN("_draw_success_status");
_draw_failure_status = SN("_draw_failure_status");
_draw_running_status = SN("_draw_running_status");
LimboExtraClock = SN("LimboExtraClock");
EditorIcons = SN("EditorIcons");
BTAlwaysSucceed = SN("BTAlwaysSucceed");
BTAlwaysFail = SN("BTAlwaysFail");
behavior_tree_finished = SN("behavior_tree_finished");
BehaviorTree = SN("BehaviorTree");
bold = SN("bold");
EditorFonts = SN("EditorFonts");
item_collapsed = SN("item_collapsed");
pressed = SN("pressed");
StatusWarning = SN("StatusWarning");
mode_changed = SN("mode_changed");
BTAlwaysFail = SN("BTAlwaysFail");
BTAlwaysSucceed = SN("BTAlwaysSucceed");
changed = SN("changed");
connect = SN("connect");
task_button_pressed = SN("task_button_pressed");
Debug = SN("Debug");
disabled_font_color = SN("disabled_font_color");
doc_italic = SN("doc_italic");
draw = SN("draw");
Duplicate = SN("Duplicate");
Editor = SN("Editor");
EditorFonts = SN("EditorFonts");
EditorIcons = SN("EditorIcons");
emit_changed = SN("emit_changed");
entered = SN("entered");
error_value = SN("error_value");
exited = SN("exited");
favorite_tasks_changed = SN("favorite_tasks_changed");
Favorites = SN("Favorites");
font = SN("font");
font_color = SN("font_color");
font_size = SN("font_size");
Forward = SN("Tools");
gui_input = SN("gui_input");
icon_max_width = SN("icon_max_width");
GuiTreeArrowDown = SN("GuiTreeArrowDown");
GuiTreeArrowRight = SN("GuiTreeArrowRight");
font = SN("font");
task_button_rmb = SN("task_button_rmb");
favorite_tasks_changed = SN("favorite_tasks_changed");
task_selected = SN("task_selected");
toggled = SN("toggled");
Favorites = SN("Favorites");
Script = SN("Script");
Help = SN("Help");
icon_max_width = SN("icon_max_width");
id_pressed = SN("id_pressed");
item_collapsed = SN("item_collapsed");
LimboDeselectAll = SN("LimboDeselectAll");
LimboExtraClock = SN("LimboExtraClock");
LimboPercent = SN("LimboPercent");
LimboSelectAll = SN("LimboSelectAll");
LineEdit = SN("LineEdit");
Load = SN("Load");
managed = SN("managed");
mode_changed = SN("mode_changed");
MoveDown = SN("MoveDown");
MoveUp = SN("MoveUp");
New = SN("New");
NewRoot = SN("NewRoot");
NodeWarning = SN("NodeWarning");
NonFavorite = SN("NonFavorite");
normal = SN("normal");
LineEdit = SN("LineEdit");
AnimationFilter = SN("AnimationFilter");
Reload = SN("Reload");
LimboSelectAll = SN("LimboSelectAll");
LimboDeselectAll = SN("LimboDeselectAll");
Search = SN("Search");
refresh = SN("refresh");
_draw_probability = SN("_draw_probability");
popup_hide = SN("popup_hide");
pressed = SN("pressed");
probability_clicked = SN("probability_clicked");
refresh = SN("refresh");
Reload = SN("Reload");
Remove = SN("Remove");
remove_child = SN("remove_child");
Rename = SN("Rename");
rmb_pressed = SN("rmb_pressed");
Save = SN("Save");
Script = SN("Script");
ScriptCreate = SN("ScriptCreate");
Search = SN("Search");
set_custom_name = SN("set_custom_name");
set_root_task = SN("set_root_task");
setup = SN("setup");
state_changed = SN("state_changed");
StatusWarning = SN("StatusWarning");
task_activated = SN("task_activated");
task_button_pressed = SN("task_button_pressed");
task_button_rmb = SN("task_button_rmb");
task_dragged = SN("task_dragged");
doc_italic = SN("doc_italic");
NodeWarning = SN("NodeWarning");
Editor = SN("Editor");
disabled_font_color = SN("disabled_font_color");
font_color = SN("font_color");
accent_color = SN("accent_color");
font_size = SN("font_size");
task_meta = SN("task_meta");
task_selected = SN("task_selected");
text_changed = SN("text_changed");
timeout = SN("timeout");
toggled = SN("toggled");
update_task = SN("update_task");
update_tree = SN("update_tree");
updated = SN("updated");
visibility_changed = SN("visibility_changed");
EVENT_FINISHED = "finished";
repeat_forever.parse_utf8("Repeat ∞");

View File

@ -16,14 +16,14 @@
#include "core/string/string_name.h"
#include "core/typedefs.h"
#include "modules/register_module_types.h"
#endif // LIMBOAI_MODULE
#endif // ! LIMBOAI_MODULE
#ifdef LIMBOAI_GDEXTENSION
#include "godot_cpp/variant/string.hpp"
#include <godot_cpp/variant/string_name.hpp>
using namespace godot;
#endif // LIMBOAI_GDEXTENSION
#endif // ! LIMBOAI_GDEXTENSION
class LimboStringNames {
friend void initialize_limboai_module(ModuleInitializationLevel p_level);
@ -42,72 +42,106 @@ class LimboStringNames {
public:
_FORCE_INLINE_ static LimboStringNames *get_singleton() { return singleton; }
StringName _generate_name;
StringName _setup;
StringName _draw_failure_status;
StringName _draw_probability;
StringName _draw_running_status;
StringName _draw_success_status;
StringName _enter;
StringName _exit;
StringName _tick;
StringName behavior_tree_finished;
StringName setup;
StringName entered;
StringName exited;
StringName updated;
StringName _update;
StringName state_changed;
StringName _generate_name;
StringName _get_configuration_warning;
StringName changed;
StringName emit_changed;
StringName _replace_task;
StringName _setup;
StringName _tick;
StringName _update_banners;
StringName _update;
StringName _weight_;
StringName error_value;
StringName accent_color;
StringName add_child_at_index;
StringName add_child;
StringName AnimationFilter;
StringName Back;
StringName behavior_tree_finished;
StringName behavior_tree;
StringName _draw_success_status;
StringName _draw_failure_status;
StringName _draw_running_status;
StringName LimboExtraClock;
StringName EditorIcons;
StringName BTAlwaysSucceed;
StringName BTAlwaysFail;
StringName BehaviorTree;
StringName bold;
StringName EditorFonts;
StringName item_collapsed;
StringName pressed;
StringName StatusWarning;
StringName mode_changed;
StringName BTAlwaysFail;
StringName BTAlwaysSucceed;
StringName changed;
StringName connect;
StringName task_button_pressed;
StringName Debug;
StringName disabled_font_color;
StringName doc_italic;
StringName draw;
StringName Duplicate;
StringName Editor;
StringName EditorFonts;
StringName EditorIcons;
StringName emit_changed;
StringName entered;
StringName error_value;
StringName exited;
StringName favorite_tasks_changed;
StringName Favorites;
StringName font_color;
StringName font_size;
StringName font;
StringName Forward;
StringName gui_input;
StringName icon_max_width;
StringName GuiTreeArrowDown;
StringName GuiTreeArrowRight;
StringName font;
StringName task_button_rmb;
StringName favorite_tasks_changed;
StringName task_selected;
StringName toggled;
StringName Favorites;
StringName Script;
StringName Help;
StringName icon_max_width;
StringName id_pressed;
StringName item_collapsed;
StringName LimboDeselectAll;
StringName LimboExtraClock;
StringName LimboExtractSubtree;
StringName LimboPercent;
StringName LimboSelectAll;
StringName LineEdit;
StringName Load;
StringName managed;
StringName mode_changed;
StringName MoveDown;
StringName MoveUp;
StringName New;
StringName NewRoot;
StringName NodeWarning;
StringName NonFavorite;
StringName normal;
StringName LineEdit;
StringName AnimationFilter;
StringName Reload;
StringName LimboSelectAll;
StringName LimboDeselectAll;
StringName Search;
StringName refresh;
StringName _draw_probability;
StringName popup_hide;
StringName pressed;
StringName probability_clicked;
StringName refresh;
StringName Reload;
StringName remove_child;
StringName Remove;
StringName Rename;
StringName rmb_pressed;
StringName Save;
StringName Script;
StringName ScriptCreate;
StringName Search;
StringName set_custom_name;
StringName set_root_task;
StringName setup;
StringName state_changed;
StringName StatusWarning;
StringName task_activated;
StringName task_button_pressed;
StringName task_button_rmb;
StringName task_dragged;
StringName doc_italic;
StringName NodeWarning;
StringName Editor;
StringName disabled_font_color;
StringName font_color;
StringName accent_color;
StringName font_size;
StringName task_meta;
StringName task_selected;
StringName text_changed;
StringName timeout;
StringName toggled;
StringName Tools;
StringName update_task;
StringName update_tree;
StringName updated;
StringName visibility_changed;
String EVENT_FINISHED;
String repeat_forever;

View File

@ -11,6 +11,8 @@
#include "limbo_task_db.h"
#include "limbo_compat.h"
#ifdef LIMBOAI_MODULE
#include "core/config/project_settings.h"
#include "core/io/dir_access.h"
@ -19,6 +21,7 @@
#ifdef LIMBOAI_GDEXTENSION
#include <godot_cpp/classes/dir_access.hpp>
#include <godot_cpp/classes/project_settings.hpp>
using namespace godot;
#endif // LIMBOAI_GDEXTENSION
@ -30,12 +33,7 @@ _FORCE_INLINE_ void _populate_scripted_tasks_from_dir(String p_path, List<String
return;
}
#ifdef LIMBOAI_MODULE
Ref<DirAccess> dir = DirAccess::create(DirAccess::ACCESS_RESOURCES);
#endif
#ifdef LIMBOAI_GDEXTENSION
Ref<DirAccess> dir = memnew(DirAccess);
#endif
Ref<DirAccess> dir = DIR_ACCESS_CREATE();
if (dir->change_dir(p_path) == OK) {
dir->list_dir_begin();
@ -58,12 +56,7 @@ _FORCE_INLINE_ void _populate_from_user_dir(String p_path, HashMap<String, List<
return;
}
#ifdef LIMBOAI_MODULE
Ref<DirAccess> dir = DirAccess::create(DirAccess::ACCESS_RESOURCES);
#endif
#ifdef LIMBOAI_GDEXTENSION
Ref<DirAccess> dir = memnew(DirAccess);
#endif
Ref<DirAccess> dir = DIR_ACCESS_CREATE();
if (dir->change_dir(p_path) == OK) {
dir->list_dir_begin();

View File

@ -29,10 +29,13 @@
#ifdef LIMBOAI_GDEXTENSION
#include "bt/tasks/bt_task.h"
#include "godot_cpp/classes/input_event_key.hpp"
#include "godot_cpp/variant/utility_functions.hpp"
#include <godot_cpp/classes/resource_loader.hpp>
#include <godot_cpp/classes/theme.hpp>
#include <godot_cpp/core/error_macros.hpp>
#endif
#endif // LIMBOAI_GDEXTENSION
LimboUtility *LimboUtility::singleton = nullptr;
@ -139,57 +142,29 @@ String LimboUtility::get_check_operator_string(CheckType p_check_type) const {
bool LimboUtility::perform_check(CheckType p_check_type, const Variant &left_value, const Variant &right_value) {
Variant ret;
#ifdef LIMBOAI_MODULE
switch (p_check_type) {
case LimboUtility::CheckType::CHECK_EQUAL: {
ret = Variant::evaluate(Variant::OP_EQUAL, left_value, right_value);
VARIANT_EVALUATE(Variant::OP_LESS, left_value, right_value, ret);
} break;
case LimboUtility::CheckType::CHECK_LESS_THAN: {
ret = Variant::evaluate(Variant::OP_LESS, left_value, right_value);
VARIANT_EVALUATE(Variant::OP_LESS, left_value, right_value, ret);
} break;
case LimboUtility::CheckType::CHECK_LESS_THAN_OR_EQUAL: {
ret = Variant::evaluate(Variant::OP_LESS_EQUAL, left_value, right_value);
VARIANT_EVALUATE(Variant::OP_LESS_EQUAL, left_value, right_value, ret);
} break;
case LimboUtility::CheckType::CHECK_GREATER_THAN: {
ret = Variant::evaluate(Variant::OP_GREATER, left_value, right_value);
VARIANT_EVALUATE(Variant::OP_GREATER, left_value, right_value, ret);
} break;
case LimboUtility::CheckType::CHECK_GREATER_THAN_OR_EQUAL: {
ret = Variant::evaluate(Variant::OP_GREATER_EQUAL, left_value, right_value);
VARIANT_EVALUATE(Variant::OP_GREATER_EQUAL, left_value, right_value, ret);
} break;
case LimboUtility::CheckType::CHECK_NOT_EQUAL: {
ret = Variant::evaluate(Variant::OP_NOT_EQUAL, left_value, right_value);
} break;
default: {
ret = false;
} break;
}
#endif
#ifdef LIMBOAI_GDEXTENSION
bool valid;
switch (p_check_type) {
case LimboUtility::CheckType::CHECK_EQUAL: {
Variant::evaluate(Variant::OP_LESS, left_value, right_value, ret, valid);
} break;
case LimboUtility::CheckType::CHECK_LESS_THAN: {
Variant::evaluate(Variant::OP_LESS, left_value, right_value, ret, valid);
} break;
case LimboUtility::CheckType::CHECK_LESS_THAN_OR_EQUAL: {
Variant::evaluate(Variant::OP_LESS_EQUAL, left_value, right_value, ret, valid);
} break;
case LimboUtility::CheckType::CHECK_GREATER_THAN: {
Variant::evaluate(Variant::OP_GREATER, left_value, right_value, ret, valid);
} break;
case LimboUtility::CheckType::CHECK_GREATER_THAN_OR_EQUAL: {
Variant::evaluate(Variant::OP_GREATER_EQUAL, left_value, right_value, ret, valid);
} break;
case LimboUtility::CheckType::CHECK_NOT_EQUAL: {
Variant::evaluate(Variant::OP_NOT_EQUAL, left_value, right_value, ret, valid);
VARIANT_EVALUATE(Variant::OP_NOT_EQUAL, left_value, right_value, ret);
} break;
default: {
return false;
} break;
}
#endif
return ret;
}
@ -238,93 +213,78 @@ String LimboUtility::get_operation_string(Operation p_operation) const {
Variant LimboUtility::perform_operation(Operation p_operation, const Variant &left_value, const Variant &right_value) {
Variant ret;
#ifdef LIMBOAI_MODULE
switch (p_operation) {
case OPERATION_NONE: {
ret = right_value;
} break;
case OPERATION_ADDITION: {
ret = Variant::evaluate(Variant::OP_ADD, left_value, right_value);
VARIANT_EVALUATE(Variant::OP_ADD, left_value, right_value, ret);
} break;
case OPERATION_SUBTRACTION: {
ret = Variant::evaluate(Variant::OP_SUBTRACT, left_value, right_value);
VARIANT_EVALUATE(Variant::OP_SUBTRACT, left_value, right_value, ret);
} break;
case OPERATION_MULTIPLICATION: {
ret = Variant::evaluate(Variant::OP_MULTIPLY, left_value, right_value);
VARIANT_EVALUATE(Variant::OP_MULTIPLY, left_value, right_value, ret);
} break;
case OPERATION_DIVISION: {
ret = Variant::evaluate(Variant::OP_DIVIDE, left_value, right_value);
VARIANT_EVALUATE(Variant::OP_DIVIDE, left_value, right_value, ret);
} break;
case OPERATION_MODULO: {
ret = Variant::evaluate(Variant::OP_MODULE, left_value, right_value);
VARIANT_EVALUATE(Variant::OP_MODULE, left_value, right_value, ret);
} break;
case OPERATION_POWER: {
ret = Variant::evaluate(Variant::OP_POWER, left_value, right_value);
} break;
case OPERATION_BIT_SHIFT_LEFT: {
ret = Variant::evaluate(Variant::OP_SHIFT_LEFT, left_value, right_value);
} break;
case OPERATION_BIT_SHIFT_RIGHT: {
ret = Variant::evaluate(Variant::OP_SHIFT_RIGHT, left_value, right_value);
} break;
case OPERATION_BIT_AND: {
ret = Variant::evaluate(Variant::OP_BIT_AND, left_value, right_value);
} break;
case OPERATION_BIT_OR: {
ret = Variant::evaluate(Variant::OP_BIT_OR, left_value, right_value);
} break;
case OPERATION_BIT_XOR: {
ret = Variant::evaluate(Variant::OP_BIT_XOR, left_value, right_value);
} break;
}
#endif // LIMBOAI_MODULE
#ifdef LIMBOAI_GDEXTENSION
bool valid;
switch (p_operation) {
case OPERATION_NONE: {
ret = right_value;
} break;
case OPERATION_ADDITION: {
Variant::evaluate(Variant::OP_ADD, left_value, right_value, ret, valid);
} break;
case OPERATION_SUBTRACTION: {
Variant::evaluate(Variant::OP_SUBTRACT, left_value, right_value, ret, valid);
} break;
case OPERATION_MULTIPLICATION: {
Variant::evaluate(Variant::OP_MULTIPLY, left_value, right_value, ret, valid);
} break;
case OPERATION_DIVISION: {
Variant::evaluate(Variant::OP_DIVIDE, left_value, right_value, ret, valid);
} break;
case OPERATION_MODULO: {
Variant::evaluate(Variant::OP_MODULE, left_value, right_value, ret, valid);
} break;
// TODO: Uncomment when https://github.com/godotengine/godot-cpp/issues/1348 is fixed.
// case OPERATION_POWER: {
// TODO: Fix when godot-cpp https://github.com/godotengine/godot-cpp/issues/1348 is resolved.
// Variant::evaluate(Variant::OP_POWER, left_value, right_value, ret, valid);
// } break;
ERR_PRINT("LimboUtility: Operation POWER is not available due to https://github.com/godotengine/godot-cpp/issues/1348");
} break;
case OPERATION_BIT_SHIFT_LEFT: {
Variant::evaluate(Variant::OP_SHIFT_LEFT, left_value, right_value, ret, valid);
VARIANT_EVALUATE(Variant::OP_SHIFT_LEFT, left_value, right_value, ret);
} break;
case OPERATION_BIT_SHIFT_RIGHT: {
Variant::evaluate(Variant::OP_SHIFT_RIGHT, left_value, right_value, ret, valid);
VARIANT_EVALUATE(Variant::OP_SHIFT_RIGHT, left_value, right_value, ret);
} break;
case OPERATION_BIT_AND: {
Variant::evaluate(Variant::OP_BIT_AND, left_value, right_value, ret, valid);
VARIANT_EVALUATE(Variant::OP_BIT_AND, left_value, right_value, ret);
} break;
case OPERATION_BIT_OR: {
Variant::evaluate(Variant::OP_BIT_OR, left_value, right_value, ret, valid);
VARIANT_EVALUATE(Variant::OP_BIT_OR, left_value, right_value, ret);
} break;
case OPERATION_BIT_XOR: {
Variant::evaluate(Variant::OP_BIT_XOR, left_value, right_value, ret, valid);
VARIANT_EVALUATE(Variant::OP_BIT_XOR, left_value, right_value, ret);
} break;
}
#endif // LIMBOAI_GDEXTENSION
return Variant();
}
Ref<Shortcut> LimboUtility::add_shortcut(const String &p_path, const String &p_name, Key p_keycode) {
Ref<Shortcut> sc = memnew(Shortcut);
sc->set_name(p_name);
Array events;
Ref<InputEventKey> ev = memnew(InputEventKey);
ev->set_keycode(p_keycode);
events.append(ev);
sc->set_events(events);
shortcuts[p_path] = sc;
return sc;
}
bool LimboUtility::is_shortcut(const String &p_path, const Ref<InputEvent> &p_event) const {
HashMap<String, Ref<Shortcut>>::ConstIterator E = shortcuts.find(p_path);
ERR_FAIL_COND_V_MSG(!E, false, vformat("LimboUtility: Shortcut not found: %s.", p_path));
return E->value->matches_event(p_event);
}
Ref<Shortcut> LimboUtility::get_shortcut(const String &p_path) const {
HashMap<String, Ref<Shortcut>>::ConstIterator SC = shortcuts.find(p_path);
if (SC) {
return SC->value;
}
return nullptr;
}
void LimboUtility::_bind_methods() {
ClassDB::bind_method(D_METHOD("decorate_var", "p_variable"), &LimboUtility::decorate_var);
ClassDB::bind_method(D_METHOD("get_status_name", "p_status"), &LimboUtility::get_status_name);

View File

@ -12,9 +12,12 @@
#ifndef LIMBO_UTILITY_H
#define LIMBO_UTILITY_H
#include "limbo_compat.h"
#ifdef LIMBOAI_MODULE
#include "core/object/object.h"
#include "core/input/shortcut.h"
#include "core/object/class_db.h"
#include "core/variant/binder_common.h"
#include "core/variant/variant.h"
@ -24,9 +27,12 @@
#ifdef LIMBOAI_GDEXTENSION
#include <godot_cpp/classes/object.hpp>
#include <godot_cpp/classes/shortcut.hpp>
#include <godot_cpp/classes/texture2d.hpp>
#include <godot_cpp/core/binder_common.hpp>
#include <godot_cpp/core/class_db.hpp>
#include <godot_cpp/templates/hash_map.hpp>
using namespace godot;
#endif // LIMBOAI_GDEXTENSION
@ -35,6 +41,9 @@ using namespace godot;
class LimboUtility : public Object {
GDCLASS(LimboUtility, Object);
private:
HashMap<String, Ref<Shortcut>> shortcuts;
public:
enum CheckType : unsigned int {
CHECK_EQUAL,
@ -77,6 +86,10 @@ public:
String get_operation_string(Operation p_operation) const;
Variant perform_operation(Operation p_operation, const Variant &left_value, const Variant &right_value);
Ref<Shortcut> add_shortcut(const String &p_path, const String &p_name, Key p_keycode = LW_KEY(NONE));
bool is_shortcut(const String &p_path, const Ref<InputEvent> &p_event) const;
Ref<Shortcut> get_shortcut(const String &p_path) const;
LimboUtility();
~LimboUtility();
};
@ -84,4 +97,8 @@ public:
VARIANT_ENUM_CAST(LimboUtility::CheckType);
VARIANT_ENUM_CAST(LimboUtility::Operation);
#define LW_SHORTCUT(m_path, m_name, m_keycode) (LimboUtility::get_singleton()->add_shortcut(m_path, m_name, m_keycode))
#define LW_IS_SHORTCUT(m_path, m_event) (LimboUtility::get_singleton()->is_shortcut(m_path, m_event))
#define LW_GET_SHORTCUT(m_path) (LimboUtility::get_singleton()->get_shortcut(m_path))
#endif // LIMBO_UTILITY_H