Expose registration of physics servers to GDExtension

This exposes PhysicsServer2DManager and PhysicsServer3DManager.
This commit is contained in:
Ricardo Buring 2022-09-06 15:35:33 +02:00
parent 019253512d
commit 532e378cd9
10 changed files with 222 additions and 67 deletions

View file

@ -1302,9 +1302,15 @@
<member name="PhysicsServer2D" type="PhysicsServer2D" setter="" getter="">
The [PhysicsServer2D] singleton.
</member>
<member name="PhysicsServer2DManager" type="PhysicsServer2DManager" setter="" getter="">
The [PhysicsServer2DManager] singleton.
</member>
<member name="PhysicsServer3D" type="PhysicsServer3D" setter="" getter="">
The [PhysicsServer3D] singleton.
</member>
<member name="PhysicsServer3DManager" type="PhysicsServer3DManager" setter="" getter="">
The [PhysicsServer3DManager] singleton.
</member>
<member name="ProjectSettings" type="ProjectSettings" setter="" getter="">
The [ProjectSettings] singleton.
</member>

View file

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="PhysicsServer2DManager" inherits="Object" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Manager for 2D physics server implementations.
</brief_description>
<description>
[PhysicsServer2DManager] is the API for registering [PhysicsServer2D] implementations, and for setting the default implementation.
[b]Note:[/b] It is not possible to switch physics servers at runtime. This class is only used on startup at the server initialization level, by Godot itself and possibly by GDExtensions.
</description>
<tutorials>
</tutorials>
<methods>
<method name="register_server">
<return type="void" />
<param index="0" name="name" type="String" />
<param index="1" name="create_callback" type="Callable" />
<description>
Register a [PhysicsServer2D] implementation by passing a [param name] and a [Callable] that returns a [PhysicsServer2D] object.
</description>
</method>
<method name="set_default_server">
<return type="void" />
<param index="0" name="name" type="String" />
<param index="1" name="priority" type="int" />
<description>
Set the default [PhysicsServer2D] implementation to the one identified by [param name], if [param priority] is greater than the priority of the current default implementation.
</description>
</method>
</methods>
</class>

View file

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="PhysicsServer3DManager" inherits="Object" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Manager for 3D physics server implementations.
</brief_description>
<description>
[PhysicsServer3DManager] is the API for registering [PhysicsServer3D] implementations, and for setting the default implementation.
[b]Note:[/b] It is not possible to switch physics servers at runtime. This class is only used on startup at the server initialization level, by Godot itself and possibly by GDExtensions.
</description>
<tutorials>
</tutorials>
<methods>
<method name="register_server">
<return type="void" />
<param index="0" name="name" type="String" />
<param index="1" name="create_callback" type="Callable" />
<description>
Register a [PhysicsServer3D] implementation by passing a [param name] and a [Callable] that returns a [PhysicsServer2D] object.
</description>
</method>
<method name="set_default_server">
<return type="void" />
<param index="0" name="name" type="String" />
<param index="1" name="priority" type="int" />
<description>
Set the default [PhysicsServer3D] implementation to the one identified by [param name], if [param priority] is greater than the priority of the current default implementation.
</description>
</method>
</methods>
</class>

View file

@ -126,7 +126,9 @@ static RenderingServer *rendering_server = nullptr;
static CameraServer *camera_server = nullptr;
static XRServer *xr_server = nullptr;
static TextServerManager *tsman = nullptr;
static PhysicsServer3DManager *physics_server_3d_manager = nullptr;
static PhysicsServer3D *physics_server_3d = nullptr;
static PhysicsServer2DManager *physics_server_2d_manager = nullptr;
static PhysicsServer2D *physics_server_2d = nullptr;
static NavigationServer3D *navigation_server_3d = nullptr;
static NavigationServer2D *navigation_server_2d = nullptr;
@ -223,25 +225,24 @@ static String get_full_version_string() {
return String(VERSION_FULL_BUILD) + hash;
}
// FIXME: Could maybe be moved to PhysicsServer3DManager and PhysicsServer2DManager directly
// to have less code in main.cpp.
// FIXME: Could maybe be moved to have less code in main.cpp.
void initialize_physics() {
/// 3D Physics Server
physics_server_3d = PhysicsServer3DManager::new_server(
physics_server_3d = PhysicsServer3DManager::get_singleton()->new_server(
ProjectSettings::get_singleton()->get(PhysicsServer3DManager::setting_property_name));
if (!physics_server_3d) {
// Physics server not found, Use the default physics
physics_server_3d = PhysicsServer3DManager::new_default_server();
physics_server_3d = PhysicsServer3DManager::get_singleton()->new_default_server();
}
ERR_FAIL_COND(!physics_server_3d);
physics_server_3d->init();
/// 2D Physics server
physics_server_2d = PhysicsServer2DManager::new_server(
ProjectSettings::get_singleton()->get(PhysicsServer2DManager::setting_property_name));
// 2D Physics server
physics_server_2d = PhysicsServer2DManager::get_singleton()->new_server(
ProjectSettings::get_singleton()->get(PhysicsServer2DManager::get_singleton()->setting_property_name));
if (!physics_server_2d) {
// Physics server not found, Use the default physics
physics_server_2d = PhysicsServer2DManager::new_default_server();
physics_server_2d = PhysicsServer2DManager::get_singleton()->new_default_server();
}
ERR_FAIL_COND(!physics_server_2d);
physics_server_2d->init();
@ -450,6 +451,9 @@ Error Main::test_setup() {
tsman->add_interface(ts);
}
physics_server_3d_manager = memnew(PhysicsServer3DManager);
physics_server_2d_manager = memnew(PhysicsServer2DManager);
// From `Main::setup2()`.
initialize_modules(MODULE_INITIALIZATION_LEVEL_CORE);
register_core_extensions();
@ -555,6 +559,12 @@ void Main::test_cleanup() {
if (tsman) {
memdelete(tsman);
}
if (physics_server_3d_manager) {
memdelete(physics_server_3d_manager);
}
if (physics_server_2d_manager) {
memdelete(physics_server_2d_manager);
}
if (globals) {
memdelete(globals);
}
@ -1783,6 +1793,9 @@ Error Main::setup2(Thread::ID p_main_tid_override) {
tsman->add_interface(ts);
}
physics_server_3d_manager = memnew(PhysicsServer3DManager);
physics_server_2d_manager = memnew(PhysicsServer2DManager);
register_server_types();
initialize_modules(MODULE_INITIALIZATION_LEVEL_SERVERS);
NativeExtensionManager::get_singleton()->initialize_extensions(NativeExtension::INITIALIZATION_LEVEL_SERVERS);
@ -3156,6 +3169,9 @@ void Main::cleanup(bool p_force) {
finalize_theme_db();
// Before deinitializing server extensions, finalize servers which may be loaded as extensions.
finalize_physics();
NativeExtensionManager::get_singleton()->deinitialize_extensions(NativeExtension::INITIALIZATION_LEVEL_SERVERS);
uninitialize_modules(MODULE_INITIALIZATION_LEVEL_SERVERS);
unregister_server_types();
@ -3177,7 +3193,6 @@ void Main::cleanup(bool p_force) {
OS::get_singleton()->finalize();
finalize_physics();
finalize_navigation_server();
finalize_display();
@ -3206,6 +3221,12 @@ void Main::cleanup(bool p_force) {
if (tsman) {
memdelete(tsman);
}
if (physics_server_3d_manager) {
memdelete(physics_server_3d_manager);
}
if (physics_server_2d_manager) {
memdelete(physics_server_2d_manager);
}
if (globals) {
memdelete(globals);
}

View file

@ -876,9 +876,7 @@ PhysicsServer2D::~PhysicsServer2D() {
singleton = nullptr;
}
Vector<PhysicsServer2DManager::ClassInfo> PhysicsServer2DManager::physics_2d_servers;
int PhysicsServer2DManager::default_server_id = -1;
int PhysicsServer2DManager::default_server_priority = -1;
PhysicsServer2DManager *PhysicsServer2DManager::singleton = nullptr;
const String PhysicsServer2DManager::setting_property_name(PNAME("physics/2d/physics_engine"));
void PhysicsServer2DManager::on_servers_changed() {
@ -889,10 +887,19 @@ void PhysicsServer2DManager::on_servers_changed() {
ProjectSettings::get_singleton()->set_custom_property_info(setting_property_name, PropertyInfo(Variant::STRING, setting_property_name, PROPERTY_HINT_ENUM, physics_servers));
}
void PhysicsServer2DManager::register_server(const String &p_name, CreatePhysicsServer2DCallback p_creat_callback) {
ERR_FAIL_COND(!p_creat_callback);
void PhysicsServer2DManager::_bind_methods() {
ClassDB::bind_method(D_METHOD("register_server", "name", "create_callback"), &PhysicsServer2DManager::register_server);
ClassDB::bind_method(D_METHOD("set_default_server", "name", "priority"), &PhysicsServer2DManager::set_default_server);
}
PhysicsServer2DManager *PhysicsServer2DManager::get_singleton() {
return singleton;
}
void PhysicsServer2DManager::register_server(const String &p_name, const Callable &p_create_callback) {
//ERR_FAIL_COND(!p_create_callback.is_valid());
ERR_FAIL_COND(find_server_id(p_name) != -1);
physics_2d_servers.push_back(ClassInfo(p_name, p_creat_callback));
physics_2d_servers.push_back(ClassInfo(p_name, p_create_callback));
on_servers_changed();
}
@ -925,7 +932,11 @@ String PhysicsServer2DManager::get_server_name(int p_id) {
PhysicsServer2D *PhysicsServer2DManager::new_default_server() {
ERR_FAIL_COND_V(default_server_id == -1, nullptr);
return physics_2d_servers[default_server_id].create_callback();
Variant ret;
Callable::CallError ce;
physics_2d_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<PhysicsServer2D>(ret.get_validated_object());
}
PhysicsServer2D *PhysicsServer2DManager::new_server(const String &p_name) {
@ -933,6 +944,18 @@ PhysicsServer2D *PhysicsServer2DManager::new_server(const String &p_name) {
if (id == -1) {
return nullptr;
} else {
return physics_2d_servers[id].create_callback();
Variant ret;
Callable::CallError ce;
physics_2d_servers[id].create_callback.callp(nullptr, 0, ret, ce);
ERR_FAIL_COND_V(ce.error != Callable::CallError::CALL_OK, nullptr);
return Object::cast_to<PhysicsServer2D>(ret.get_validated_object());
}
}
PhysicsServer2DManager::PhysicsServer2DManager() {
singleton = this;
}
PhysicsServer2DManager::~PhysicsServer2DManager() {
singleton = nullptr;
}

View file

@ -766,16 +766,18 @@ public:
real_t get_collision_unsafe_fraction() const;
};
typedef PhysicsServer2D *(*CreatePhysicsServer2DCallback)();
class PhysicsServer2DManager : public Object {
GDCLASS(PhysicsServer2DManager, Object);
static PhysicsServer2DManager *singleton;
class PhysicsServer2DManager {
struct ClassInfo {
String name;
CreatePhysicsServer2DCallback create_callback = nullptr;
Callable create_callback;
ClassInfo() {}
ClassInfo(String p_name, CreatePhysicsServer2DCallback p_create_callback) :
ClassInfo(String p_name, Callable p_create_callback) :
name(p_name),
create_callback(p_create_callback) {}
@ -789,24 +791,30 @@ class PhysicsServer2DManager {
}
};
static Vector<ClassInfo> physics_2d_servers;
static int default_server_id;
static int default_server_priority;
Vector<ClassInfo> physics_2d_servers;
int default_server_id = -1;
int default_server_priority = -1;
void on_servers_changed();
protected:
static void _bind_methods();
public:
static const String setting_property_name;
private:
static void on_servers_changed();
static PhysicsServer2DManager *get_singleton();
public:
static void register_server(const String &p_name, CreatePhysicsServer2DCallback p_creat_callback);
static void set_default_server(const String &p_name, int p_priority = 0);
static int find_server_id(const String &p_name);
static int get_servers_count();
static String get_server_name(int p_id);
static PhysicsServer2D *new_default_server();
static PhysicsServer2D *new_server(const String &p_name);
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);
PhysicsServer2D *new_default_server();
PhysicsServer2D *new_server(const String &p_name);
PhysicsServer2DManager();
~PhysicsServer2DManager();
};
VARIANT_ENUM_CAST(PhysicsServer2D::ShapeType);

View file

@ -1046,9 +1046,7 @@ PhysicsServer3D::~PhysicsServer3D() {
singleton = nullptr;
}
Vector<PhysicsServer3DManager::ClassInfo> PhysicsServer3DManager::physics_servers;
int PhysicsServer3DManager::default_server_id = -1;
int PhysicsServer3DManager::default_server_priority = -1;
PhysicsServer3DManager *PhysicsServer3DManager::singleton = nullptr;
const String PhysicsServer3DManager::setting_property_name(PNAME("physics/3d/physics_engine"));
void PhysicsServer3DManager::on_servers_changed() {
@ -1059,10 +1057,19 @@ void PhysicsServer3DManager::on_servers_changed() {
ProjectSettings::get_singleton()->set_custom_property_info(setting_property_name, PropertyInfo(Variant::STRING, setting_property_name, PROPERTY_HINT_ENUM, physics_servers2));
}
void PhysicsServer3DManager::register_server(const String &p_name, CreatePhysicsServer3DCallback p_creat_callback) {
ERR_FAIL_COND(!p_creat_callback);
void PhysicsServer3DManager::_bind_methods() {
ClassDB::bind_method(D_METHOD("register_server", "name", "create_callback"), &PhysicsServer3DManager::register_server);
ClassDB::bind_method(D_METHOD("set_default_server", "name", "priority"), &PhysicsServer3DManager::set_default_server);
}
PhysicsServer3DManager *PhysicsServer3DManager::get_singleton() {
return singleton;
}
void PhysicsServer3DManager::register_server(const String &p_name, const Callable &p_create_callback) {
//ERR_FAIL_COND(!p_create_callback.is_valid());
ERR_FAIL_COND(find_server_id(p_name) != -1);
physics_servers.push_back(ClassInfo(p_name, p_creat_callback));
physics_servers.push_back(ClassInfo(p_name, p_create_callback));
on_servers_changed();
}
@ -1095,7 +1102,11 @@ String PhysicsServer3DManager::get_server_name(int p_id) {
PhysicsServer3D *PhysicsServer3DManager::new_default_server() {
ERR_FAIL_COND_V(default_server_id == -1, nullptr);
return physics_servers[default_server_id].create_callback();
Variant ret;
Callable::CallError ce;
physics_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<PhysicsServer3D>(ret.get_validated_object());
}
PhysicsServer3D *PhysicsServer3DManager::new_server(const String &p_name) {
@ -1103,6 +1114,18 @@ PhysicsServer3D *PhysicsServer3DManager::new_server(const String &p_name) {
if (id == -1) {
return nullptr;
} else {
return physics_servers[id].create_callback();
Variant ret;
Callable::CallError ce;
physics_servers[id].create_callback.callp(nullptr, 0, ret, ce);
ERR_FAIL_COND_V(ce.error != Callable::CallError::CALL_OK, nullptr);
return Object::cast_to<PhysicsServer3D>(ret.get_validated_object());
}
}
PhysicsServer3DManager::PhysicsServer3DManager() {
singleton = this;
}
PhysicsServer3DManager::~PhysicsServer3DManager() {
singleton = nullptr;
}

View file

@ -983,16 +983,18 @@ public:
real_t get_collision_depth(int p_collision_index = 0) const;
};
typedef PhysicsServer3D *(*CreatePhysicsServer3DCallback)();
class PhysicsServer3DManager : public Object {
GDCLASS(PhysicsServer3DManager, Object);
static PhysicsServer3DManager *singleton;
class PhysicsServer3DManager {
struct ClassInfo {
String name;
CreatePhysicsServer3DCallback create_callback = nullptr;
Callable create_callback;
ClassInfo() {}
ClassInfo(String p_name, CreatePhysicsServer3DCallback p_create_callback) :
ClassInfo(String p_name, Callable p_create_callback) :
name(p_name),
create_callback(p_create_callback) {}
@ -1006,24 +1008,30 @@ class PhysicsServer3DManager {
}
};
static Vector<ClassInfo> physics_servers;
static int default_server_id;
static int default_server_priority;
Vector<ClassInfo> physics_servers;
int default_server_id = -1;
int default_server_priority = -1;
void on_servers_changed();
protected:
static void _bind_methods();
public:
static const String setting_property_name;
private:
static void on_servers_changed();
static PhysicsServer3DManager *get_singleton();
public:
static void register_server(const String &p_name, CreatePhysicsServer3DCallback p_creat_callback);
static void set_default_server(const String &p_name, int p_priority = 0);
static int find_server_id(const String &p_name);
static int get_servers_count();
static String get_server_name(int p_id);
static PhysicsServer3D *new_default_server();
static PhysicsServer3D *new_server(const String &p_name);
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);
PhysicsServer3D *new_default_server();
PhysicsServer3D *new_server(const String &p_name);
PhysicsServer3DManager();
~PhysicsServer3DManager();
};
VARIANT_ENUM_CAST(PhysicsServer3D::ShapeType);

View file

@ -85,7 +85,7 @@
ShaderTypes *shader_types = nullptr;
PhysicsServer3D *_createGodotPhysics3DCallback() {
static PhysicsServer3D *_createGodotPhysics3DCallback() {
bool using_threads = GLOBAL_GET("physics/3d/run_on_separate_thread");
PhysicsServer3D *physics_server_3d = memnew(GodotPhysicsServer3D(using_threads));
@ -93,7 +93,7 @@ PhysicsServer3D *_createGodotPhysics3DCallback() {
return memnew(PhysicsServer3DWrapMT(physics_server_3d, using_threads));
}
PhysicsServer2D *_createGodotPhysics2DCallback() {
static PhysicsServer2D *_createGodotPhysics2DCallback() {
bool using_threads = GLOBAL_GET("physics/2d/run_on_separate_thread");
PhysicsServer2D *physics_server_2d = memnew(GodotPhysicsServer2D(using_threads));
@ -133,6 +133,9 @@ void register_server_types() {
GDREGISTER_ABSTRACT_CLASS(RenderingServer);
GDREGISTER_CLASS(AudioServer);
GDREGISTER_CLASS(PhysicsServer2DManager);
Engine::get_singleton()->add_singleton(Engine::Singleton("PhysicsServer2DManager", PhysicsServer2DManager::get_singleton(), "PhysicsServer2DManager"));
GDREGISTER_ABSTRACT_CLASS(PhysicsServer2D);
GDREGISTER_VIRTUAL_CLASS(PhysicsServer2DExtension);
GDREGISTER_VIRTUAL_CLASS(PhysicsDirectBodyState2DExtension);
@ -144,6 +147,9 @@ void register_server_types() {
GDREGISTER_NATIVE_STRUCT(PhysicsServer2DExtensionMotionResult, "Vector2 travel;Vector2 remainder;Vector2 collision_point;Vector2 collision_normal;Vector2 collider_velocity;real_t collision_depth;real_t collision_safe_fraction;real_t collision_unsafe_fraction;int collision_local_shape;ObjectID collider_id;RID collider;int collider_shape");
GDREGISTER_NATIVE_STRUCT(PhysicsServer2DExtensionStateCallback, "void *instance;void (*callback)(void *p_instance, PhysicsDirectBodyState2D *p_state)");
GDREGISTER_CLASS(PhysicsServer3DManager);
Engine::get_singleton()->add_singleton(Engine::Singleton("PhysicsServer3DManager", PhysicsServer3DManager::get_singleton(), "PhysicsServer3DManager"));
GDREGISTER_ABSTRACT_CLASS(PhysicsServer3D);
GDREGISTER_VIRTUAL_CLASS(PhysicsServer3DExtension);
GDREGISTER_VIRTUAL_CLASS(PhysicsDirectBodyState3DExtension);
@ -264,15 +270,15 @@ void register_server_types() {
GLOBAL_DEF(PhysicsServer2DManager::setting_property_name, "DEFAULT");
ProjectSettings::get_singleton()->set_custom_property_info(PhysicsServer2DManager::setting_property_name, PropertyInfo(Variant::STRING, PhysicsServer2DManager::setting_property_name, PROPERTY_HINT_ENUM, "DEFAULT"));
PhysicsServer2DManager::register_server("GodotPhysics2D", &_createGodotPhysics2DCallback);
PhysicsServer2DManager::set_default_server("GodotPhysics2D");
PhysicsServer2DManager::get_singleton()->register_server("GodotPhysics2D", callable_mp_static(_createGodotPhysics2DCallback));
PhysicsServer2DManager::get_singleton()->set_default_server("GodotPhysics2D");
// Physics 3D
GLOBAL_DEF(PhysicsServer3DManager::setting_property_name, "DEFAULT");
ProjectSettings::get_singleton()->set_custom_property_info(PhysicsServer3DManager::setting_property_name, PropertyInfo(Variant::STRING, PhysicsServer3DManager::setting_property_name, PROPERTY_HINT_ENUM, "DEFAULT"));
PhysicsServer3DManager::register_server("GodotPhysics3D", &_createGodotPhysics3DCallback);
PhysicsServer3DManager::set_default_server("GodotPhysics3D");
PhysicsServer3DManager::get_singleton()->register_server("GodotPhysics3D", callable_mp_static(_createGodotPhysics3DCallback));
PhysicsServer3DManager::get_singleton()->set_default_server("GodotPhysics3D");
writer_mjpeg = memnew(MovieWriterMJPEG);
MovieWriter::add_writer(writer_mjpeg);

View file

@ -207,10 +207,10 @@ struct GodotTestCaseListener : public doctest::IReporter {
RenderingServerDefault::get_singleton()->init();
RenderingServerDefault::get_singleton()->set_render_loop_enabled(false);
physics_server_3d = PhysicsServer3DManager::new_default_server();
physics_server_3d = PhysicsServer3DManager::get_singleton()->new_default_server();
physics_server_3d->init();
physics_server_2d = PhysicsServer2DManager::new_default_server();
physics_server_2d = PhysicsServer2DManager::get_singleton()->new_default_server();
physics_server_2d->init();
navigation_server_3d = NavigationServer3DManager::new_default_server();