Make NavigationServer backend engine selectable
Adds engine backend selection for NavigationServers, aka allows to swap navigation module for other backend implementations.
This commit is contained in:
@ -256,8 +256,8 @@ NavigationServer2D::NavigationServer2D() {
|
||||
debug_navigation_avoidance_enable_obstacles_static = GLOBAL_DEF("debug/shapes/avoidance/2d/enable_obstacles_static", true);
|
||||
|
||||
if (Engine::get_singleton()->is_editor_hint()) {
|
||||
// enable NavigationServer3D when in Editor or else navigation mesh edge connections are invisible
|
||||
// on runtime tests SceneTree has "Visible Navigation" set and main iteration takes care of this.
|
||||
// Enable NavigationServer2D when in Editor or navigation mesh edge connections are invisible.
|
||||
// On runtime tests SceneTree has "Visible Navigation" set and main iteration takes care of this.
|
||||
set_debug_enabled(true);
|
||||
set_debug_navigation_enabled(true);
|
||||
set_debug_avoidance_enabled(true);
|
||||
@ -550,30 +550,24 @@ bool NavigationServer2D::get_debug_navigation_avoidance_enable_obstacles_static(
|
||||
|
||||
static NavigationServer2D *navigation_server_2d = nullptr;
|
||||
|
||||
NavigationServer2DCallback NavigationServer2DManager::create_callback = nullptr;
|
||||
|
||||
void NavigationServer2DManager::set_default_server(NavigationServer2DCallback p_callback) {
|
||||
create_callback = p_callback;
|
||||
}
|
||||
|
||||
NavigationServer2D *NavigationServer2DManager::new_default_server() {
|
||||
if (create_callback == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return create_callback();
|
||||
}
|
||||
|
||||
void NavigationServer2DManager::initialize_server() {
|
||||
ERR_FAIL_COND(navigation_server_2d != nullptr);
|
||||
|
||||
// Init 2D Navigation Server
|
||||
navigation_server_2d = NavigationServer2DManager::new_default_server();
|
||||
// Init 2D Navigation Server.
|
||||
navigation_server_2d = NavigationServer2DManager::get_singleton()->new_server(
|
||||
GLOBAL_GET(NavigationServer2DManager::setting_property_name));
|
||||
if (!navigation_server_2d) {
|
||||
// Navigation server not found, use the default.
|
||||
navigation_server_2d = NavigationServer2DManager::get_singleton()->new_default_server();
|
||||
}
|
||||
|
||||
// Fall back to dummy if no default server has been registered.
|
||||
if (!navigation_server_2d) {
|
||||
WARN_VERBOSE("Failed to initialize NavigationServer2D. Fall back to dummy server.");
|
||||
navigation_server_2d = memnew(NavigationServer2DDummy);
|
||||
}
|
||||
|
||||
// Should be impossible, but make sure it's not null.
|
||||
ERR_FAIL_NULL_MSG(navigation_server_2d, "Failed to initialize NavigationServer2D.");
|
||||
navigation_server_2d->init();
|
||||
}
|
||||
@ -584,3 +578,101 @@ void NavigationServer2DManager::finalize_server() {
|
||||
memdelete(navigation_server_2d);
|
||||
navigation_server_2d = nullptr;
|
||||
}
|
||||
|
||||
const String NavigationServer2DManager::setting_property_name(PNAME("navigation/2d/navigation_engine"));
|
||||
|
||||
void NavigationServer2DManager::on_servers_changed() {
|
||||
String navigation_servers_enum_str("DEFAULT");
|
||||
for (int i = get_servers_count() - 1; 0 <= i; --i) {
|
||||
navigation_servers_enum_str += "," + get_server_name(i);
|
||||
}
|
||||
ProjectSettings::get_singleton()->set_custom_property_info(PropertyInfo(Variant::STRING, setting_property_name, PROPERTY_HINT_ENUM, navigation_servers_enum_str));
|
||||
ProjectSettings::get_singleton()->set_restart_if_changed(setting_property_name, true);
|
||||
ProjectSettings::get_singleton()->set_as_basic(setting_property_name, true);
|
||||
}
|
||||
|
||||
void NavigationServer2DManager::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("register_server", "name", "create_callback"), &NavigationServer2DManager::register_server);
|
||||
ClassDB::bind_method(D_METHOD("set_default_server", "name", "priority"), &NavigationServer2DManager::set_default_server);
|
||||
}
|
||||
|
||||
NavigationServer2DManager *NavigationServer2DManager::get_singleton() {
|
||||
return singleton;
|
||||
}
|
||||
|
||||
void NavigationServer2DManager::register_server(const String &p_name, const Callable &p_create_callback) {
|
||||
ERR_FAIL_COND(find_server_id(p_name) != -1);
|
||||
navigation_servers.push_back(ClassInfo(p_name, p_create_callback));
|
||||
on_servers_changed();
|
||||
}
|
||||
|
||||
void NavigationServer2DManager::set_default_server(const String &p_name, int p_priority) {
|
||||
const int id = find_server_id(p_name);
|
||||
ERR_FAIL_COND(id == -1); // Not found
|
||||
if (default_server_priority < p_priority) {
|
||||
default_server_id = id;
|
||||
default_server_priority = p_priority;
|
||||
}
|
||||
}
|
||||
|
||||
int NavigationServer2DManager::find_server_id(const String &p_name) {
|
||||
for (int i = navigation_servers.size() - 1; 0 <= i; --i) {
|
||||
if (p_name == navigation_servers[i].name) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int NavigationServer2DManager::get_servers_count() {
|
||||
return navigation_servers.size();
|
||||
}
|
||||
|
||||
String NavigationServer2DManager::get_server_name(int p_id) {
|
||||
ERR_FAIL_INDEX_V(p_id, get_servers_count(), "");
|
||||
return navigation_servers[p_id].name;
|
||||
}
|
||||
|
||||
NavigationServer2D *NavigationServer2DManager::new_default_server() {
|
||||
if (default_server_id == -1) {
|
||||
return nullptr;
|
||||
}
|
||||
Variant ret;
|
||||
Callable::CallError ce;
|
||||
navigation_servers[default_server_id].create_callback.callp(nullptr, 0, ret, ce);
|
||||
ERR_FAIL_COND_V(ce.error != Callable::CallError::CALL_OK, nullptr);
|
||||
return Object::cast_to<NavigationServer2D>(ret.get_validated_object());
|
||||
}
|
||||
|
||||
NavigationServer2D *NavigationServer2DManager::new_server(const String &p_name) {
|
||||
int id = find_server_id(p_name);
|
||||
if (id == -1) {
|
||||
return nullptr;
|
||||
} else {
|
||||
Variant ret;
|
||||
Callable::CallError ce;
|
||||
navigation_servers[id].create_callback.callp(nullptr, 0, ret, ce);
|
||||
ERR_FAIL_COND_V(ce.error != Callable::CallError::CALL_OK, nullptr);
|
||||
return Object::cast_to<NavigationServer2D>(ret.get_validated_object());
|
||||
}
|
||||
}
|
||||
|
||||
NavigationServer2D *NavigationServer2DManager::create_dummy_server_callback() {
|
||||
return memnew(NavigationServer2DDummy);
|
||||
}
|
||||
|
||||
NavigationServer2DManager::NavigationServer2DManager() {
|
||||
}
|
||||
|
||||
NavigationServer2DManager::~NavigationServer2DManager() {
|
||||
}
|
||||
|
||||
void NavigationServer2DManager::initialize_server_manager() {
|
||||
ERR_FAIL_COND(singleton != nullptr);
|
||||
singleton = memnew(NavigationServer2DManager);
|
||||
}
|
||||
|
||||
void NavigationServer2DManager::finalize_server_manager() {
|
||||
ERR_FAIL_NULL(singleton);
|
||||
memdelete(singleton);
|
||||
}
|
||||
|
||||
@ -431,18 +431,63 @@ public:
|
||||
#endif // DEBUG_ENABLED
|
||||
};
|
||||
|
||||
typedef NavigationServer2D *(*NavigationServer2DCallback)();
|
||||
|
||||
/// Manager used for the server singleton registration
|
||||
class NavigationServer2DManager {
|
||||
static NavigationServer2DCallback create_callback;
|
||||
class NavigationServer2DManager : public Object {
|
||||
GDCLASS(NavigationServer2DManager, Object);
|
||||
|
||||
static inline NavigationServer2DManager *singleton = nullptr;
|
||||
|
||||
struct ClassInfo {
|
||||
String name;
|
||||
Callable create_callback;
|
||||
|
||||
ClassInfo() {}
|
||||
|
||||
ClassInfo(const String &p_name, const Callable &p_create_callback) :
|
||||
name(p_name),
|
||||
create_callback(p_create_callback) {}
|
||||
|
||||
ClassInfo(const ClassInfo &p_ci) :
|
||||
name(p_ci.name),
|
||||
create_callback(p_ci.create_callback) {}
|
||||
|
||||
void operator=(const ClassInfo &p_ci) {
|
||||
name = p_ci.name;
|
||||
create_callback = p_ci.create_callback;
|
||||
}
|
||||
};
|
||||
|
||||
Vector<ClassInfo> navigation_servers;
|
||||
int default_server_id = -1;
|
||||
int default_server_priority = -1;
|
||||
|
||||
void on_servers_changed();
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
|
||||
public:
|
||||
static void set_default_server(NavigationServer2DCallback p_callback);
|
||||
static NavigationServer2D *new_default_server();
|
||||
static const String setting_property_name;
|
||||
|
||||
static NavigationServer2DManager *get_singleton();
|
||||
|
||||
void register_server(const String &p_name, const Callable &p_create_callback);
|
||||
void set_default_server(const String &p_name, int p_priority = 0);
|
||||
int find_server_id(const String &p_name);
|
||||
int get_servers_count();
|
||||
String get_server_name(int p_id);
|
||||
NavigationServer2D *new_default_server();
|
||||
NavigationServer2D *new_server(const String &p_name);
|
||||
|
||||
NavigationServer2DManager();
|
||||
~NavigationServer2DManager();
|
||||
|
||||
static void initialize_server();
|
||||
static void finalize_server();
|
||||
|
||||
static void initialize_server_manager();
|
||||
static void finalize_server_manager();
|
||||
static NavigationServer2D *create_dummy_server_callback();
|
||||
};
|
||||
|
||||
VARIANT_ENUM_CAST(NavigationServer2D::ProcessInfo);
|
||||
|
||||
@ -1033,25 +1033,16 @@ bool NavigationServer3D::get_debug_avoidance_enabled() const {
|
||||
|
||||
static NavigationServer3D *navigation_server_3d = nullptr;
|
||||
|
||||
NavigationServer3DCallback NavigationServer3DManager::create_callback = nullptr;
|
||||
|
||||
void NavigationServer3DManager::set_default_server(NavigationServer3DCallback p_callback) {
|
||||
create_callback = p_callback;
|
||||
}
|
||||
|
||||
NavigationServer3D *NavigationServer3DManager::new_default_server() {
|
||||
if (create_callback == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return create_callback();
|
||||
}
|
||||
|
||||
void NavigationServer3DManager::initialize_server() {
|
||||
ERR_FAIL_COND(navigation_server_3d != nullptr);
|
||||
|
||||
// Init 3D Navigation Server
|
||||
navigation_server_3d = NavigationServer3DManager::new_default_server();
|
||||
// Init 3D Navigation Server.
|
||||
navigation_server_3d = NavigationServer3DManager::get_singleton()->new_server(
|
||||
GLOBAL_GET(NavigationServer3DManager::setting_property_name));
|
||||
if (!navigation_server_3d) {
|
||||
// Navigation server not found, use the default.
|
||||
navigation_server_3d = NavigationServer3DManager::get_singleton()->new_default_server();
|
||||
}
|
||||
|
||||
// Fall back to dummy if no default server has been registered.
|
||||
if (!navigation_server_3d) {
|
||||
@ -1070,3 +1061,101 @@ void NavigationServer3DManager::finalize_server() {
|
||||
memdelete(navigation_server_3d);
|
||||
navigation_server_3d = nullptr;
|
||||
}
|
||||
|
||||
const String NavigationServer3DManager::setting_property_name(PNAME("navigation/3d/navigation_engine"));
|
||||
|
||||
void NavigationServer3DManager::on_servers_changed() {
|
||||
String navigation_servers_enum_str("DEFAULT");
|
||||
for (int i = get_servers_count() - 1; 0 <= i; --i) {
|
||||
navigation_servers_enum_str += "," + get_server_name(i);
|
||||
}
|
||||
ProjectSettings::get_singleton()->set_custom_property_info(PropertyInfo(Variant::STRING, setting_property_name, PROPERTY_HINT_ENUM, navigation_servers_enum_str));
|
||||
ProjectSettings::get_singleton()->set_restart_if_changed(setting_property_name, true);
|
||||
ProjectSettings::get_singleton()->set_as_basic(setting_property_name, true);
|
||||
}
|
||||
|
||||
void NavigationServer3DManager::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("register_server", "name", "create_callback"), &NavigationServer3DManager::register_server);
|
||||
ClassDB::bind_method(D_METHOD("set_default_server", "name", "priority"), &NavigationServer3DManager::set_default_server);
|
||||
}
|
||||
|
||||
NavigationServer3DManager *NavigationServer3DManager::get_singleton() {
|
||||
return singleton;
|
||||
}
|
||||
|
||||
void NavigationServer3DManager::register_server(const String &p_name, const Callable &p_create_callback) {
|
||||
ERR_FAIL_COND(find_server_id(p_name) != -1);
|
||||
navigation_servers.push_back(ClassInfo(p_name, p_create_callback));
|
||||
on_servers_changed();
|
||||
}
|
||||
|
||||
void NavigationServer3DManager::set_default_server(const String &p_name, int p_priority) {
|
||||
const int id = find_server_id(p_name);
|
||||
ERR_FAIL_COND(id == -1); // Not found
|
||||
if (default_server_priority < p_priority) {
|
||||
default_server_id = id;
|
||||
default_server_priority = p_priority;
|
||||
}
|
||||
}
|
||||
|
||||
int NavigationServer3DManager::find_server_id(const String &p_name) {
|
||||
for (int i = navigation_servers.size() - 1; 0 <= i; --i) {
|
||||
if (p_name == navigation_servers[i].name) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int NavigationServer3DManager::get_servers_count() {
|
||||
return navigation_servers.size();
|
||||
}
|
||||
|
||||
String NavigationServer3DManager::get_server_name(int p_id) {
|
||||
ERR_FAIL_INDEX_V(p_id, get_servers_count(), "");
|
||||
return navigation_servers[p_id].name;
|
||||
}
|
||||
|
||||
NavigationServer3D *NavigationServer3DManager::new_default_server() {
|
||||
if (default_server_id == -1) {
|
||||
return nullptr;
|
||||
}
|
||||
Variant ret;
|
||||
Callable::CallError ce;
|
||||
navigation_servers[default_server_id].create_callback.callp(nullptr, 0, ret, ce);
|
||||
ERR_FAIL_COND_V(ce.error != Callable::CallError::CALL_OK, nullptr);
|
||||
return Object::cast_to<NavigationServer3D>(ret.get_validated_object());
|
||||
}
|
||||
|
||||
NavigationServer3D *NavigationServer3DManager::new_server(const String &p_name) {
|
||||
int id = find_server_id(p_name);
|
||||
if (id == -1) {
|
||||
return nullptr;
|
||||
} else {
|
||||
Variant ret;
|
||||
Callable::CallError ce;
|
||||
navigation_servers[id].create_callback.callp(nullptr, 0, ret, ce);
|
||||
ERR_FAIL_COND_V(ce.error != Callable::CallError::CALL_OK, nullptr);
|
||||
return Object::cast_to<NavigationServer3D>(ret.get_validated_object());
|
||||
}
|
||||
}
|
||||
|
||||
NavigationServer3D *NavigationServer3DManager::create_dummy_server_callback() {
|
||||
return memnew(NavigationServer3DDummy);
|
||||
}
|
||||
|
||||
NavigationServer3DManager::NavigationServer3DManager() {
|
||||
}
|
||||
|
||||
NavigationServer3DManager::~NavigationServer3DManager() {
|
||||
}
|
||||
|
||||
void NavigationServer3DManager::initialize_server_manager() {
|
||||
ERR_FAIL_COND(singleton != nullptr);
|
||||
singleton = memnew(NavigationServer3DManager);
|
||||
}
|
||||
|
||||
void NavigationServer3DManager::finalize_server_manager() {
|
||||
ERR_FAIL_NULL(singleton);
|
||||
memdelete(singleton);
|
||||
}
|
||||
|
||||
@ -519,18 +519,63 @@ public:
|
||||
#endif // DEBUG_ENABLED
|
||||
};
|
||||
|
||||
typedef NavigationServer3D *(*NavigationServer3DCallback)();
|
||||
|
||||
/// Manager used for the server singleton registration
|
||||
class NavigationServer3DManager {
|
||||
static NavigationServer3DCallback create_callback;
|
||||
class NavigationServer3DManager : public Object {
|
||||
GDCLASS(NavigationServer3DManager, Object);
|
||||
|
||||
static inline NavigationServer3DManager *singleton = nullptr;
|
||||
|
||||
struct ClassInfo {
|
||||
String name;
|
||||
Callable create_callback;
|
||||
|
||||
ClassInfo() {}
|
||||
|
||||
ClassInfo(const String &p_name, const Callable &p_create_callback) :
|
||||
name(p_name),
|
||||
create_callback(p_create_callback) {}
|
||||
|
||||
ClassInfo(const ClassInfo &p_ci) :
|
||||
name(p_ci.name),
|
||||
create_callback(p_ci.create_callback) {}
|
||||
|
||||
void operator=(const ClassInfo &p_ci) {
|
||||
name = p_ci.name;
|
||||
create_callback = p_ci.create_callback;
|
||||
}
|
||||
};
|
||||
|
||||
Vector<ClassInfo> navigation_servers;
|
||||
int default_server_id = -1;
|
||||
int default_server_priority = -1;
|
||||
|
||||
void on_servers_changed();
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
|
||||
public:
|
||||
static void set_default_server(NavigationServer3DCallback p_callback);
|
||||
static NavigationServer3D *new_default_server();
|
||||
static const String setting_property_name;
|
||||
|
||||
static NavigationServer3DManager *get_singleton();
|
||||
|
||||
void register_server(const String &p_name, const Callable &p_create_callback);
|
||||
void set_default_server(const String &p_name, int p_priority = 0);
|
||||
int find_server_id(const String &p_name);
|
||||
int get_servers_count();
|
||||
String get_server_name(int p_id);
|
||||
NavigationServer3D *new_default_server();
|
||||
NavigationServer3D *new_server(const String &p_name);
|
||||
|
||||
NavigationServer3DManager();
|
||||
~NavigationServer3DManager();
|
||||
|
||||
static void initialize_server();
|
||||
static void finalize_server();
|
||||
|
||||
static void initialize_server_manager();
|
||||
static void finalize_server_manager();
|
||||
static NavigationServer3D *create_dummy_server_callback();
|
||||
};
|
||||
|
||||
VARIANT_ENUM_CAST(NavigationServer3D::ProcessInfo);
|
||||
|
||||
@ -261,9 +261,16 @@ void register_server_types() {
|
||||
ServersDebugger::initialize();
|
||||
|
||||
#ifndef NAVIGATION_2D_DISABLED
|
||||
GDREGISTER_CLASS(NavigationServer2DManager);
|
||||
Engine::get_singleton()->add_singleton(Engine::Singleton("NavigationServer2DManager", NavigationServer2DManager::get_singleton(), "NavigationServer2DManager"));
|
||||
|
||||
GDREGISTER_ABSTRACT_CLASS(NavigationServer2D);
|
||||
GDREGISTER_CLASS(NavigationPathQueryParameters2D);
|
||||
GDREGISTER_CLASS(NavigationPathQueryResult2D);
|
||||
|
||||
GLOBAL_DEF(PropertyInfo(Variant::STRING, NavigationServer2DManager::setting_property_name, PROPERTY_HINT_ENUM, "DEFAULT"), "DEFAULT");
|
||||
|
||||
NavigationServer2DManager::get_singleton()->register_server("Dummy", callable_mp_static(NavigationServer2DManager::create_dummy_server_callback));
|
||||
#endif // NAVIGATION_2D_DISABLED
|
||||
|
||||
#ifndef PHYSICS_2D_DISABLED
|
||||
@ -295,9 +302,16 @@ void register_server_types() {
|
||||
#endif // PHYSICS_2D_DISABLED
|
||||
|
||||
#ifndef NAVIGATION_3D_DISABLED
|
||||
GDREGISTER_CLASS(NavigationServer3DManager);
|
||||
Engine::get_singleton()->add_singleton(Engine::Singleton("NavigationServer3DManager", NavigationServer3DManager::get_singleton(), "NavigationServer3DManager"));
|
||||
|
||||
GDREGISTER_ABSTRACT_CLASS(NavigationServer3D);
|
||||
GDREGISTER_CLASS(NavigationPathQueryParameters3D);
|
||||
GDREGISTER_CLASS(NavigationPathQueryResult3D);
|
||||
|
||||
GLOBAL_DEF(PropertyInfo(Variant::STRING, NavigationServer3DManager::setting_property_name, PROPERTY_HINT_ENUM, "DEFAULT"), "DEFAULT");
|
||||
|
||||
NavigationServer3DManager::get_singleton()->register_server("Dummy", callable_mp_static(NavigationServer3DManager::create_dummy_server_callback));
|
||||
#endif // NAVIGATION_3D_DISABLED
|
||||
|
||||
#ifndef PHYSICS_3D_DISABLED
|
||||
|
||||
Reference in New Issue
Block a user