diff --git a/.gitignore b/.gitignore index 402c519..df2b0ab 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ temp/ scp.sh start-edge.sh console-edge.sh +old/ diff --git a/build.sh b/build-godot.sh similarity index 96% rename from build.sh rename to build-godot.sh index 4b43f1d..aa2d86b 100755 --- a/build.sh +++ b/build-godot.sh @@ -16,9 +16,7 @@ ln -f -s ../custom.py . scons platform=linuxbsd target=editor arch=x86_64 ${LTO} # Create JSON for IDE support. -#if [[ ! -f compile_commands.json ]]; then - scons compiledb=yes -#fi +scons compiledb=yes # Build Templates. scons platform=linuxbsd target=template_release arch=x86_64 ${TEMPLATE} ${LTO} diff --git a/build-n2n.sh b/build-n2n.sh new file mode 100755 index 0000000..56d9077 --- /dev/null +++ b/build-n2n.sh @@ -0,0 +1,28 @@ +#!/bin/bash + +# Build n2n for current platform. + +mkdir -p bin + +mkdir -p n2n/thirdparty/libnatpmp/build +pushd n2n/thirdparty/libnatpmp/build +cmake .. +make +popd + +mkdir -p n2n/thirdparty/miniupnp/miniupnpc/build +pushd n2n/thirdparty/miniupnp/miniupnpc/build +cmake .. +make +popd + +pushd n2n +./autogen.sh +CFLAGS="-I thirdparty/libnatpmp -I thirdparty/miniupnp/miniupnpc/include" \ + LDFLAGS="-L thirdparty/libnatpmp/build -L thirdparty/miniupnp/miniupnpc/build" \ + ./configure --enable-pthread --enable-natpmp --enable-miniupnp +make edge +make supernode +mv edge ../bin/. +mv supernode ../bin/. +popd diff --git a/custom.py b/custom.py index 5d3554c..62ff08a 100644 --- a/custom.py +++ b/custom.py @@ -40,5 +40,4 @@ module_visual_script_enabled = "no" module_vorbis_enabled = "no" module_websocket_enabled = "no" module_webxr_enabled = "no" -custom_modules = "../modules" - +#custom_modules = "../modules" diff --git a/edit.sh b/edit.sh index d42b036..d192659 100755 --- a/edit.sh +++ b/edit.sh @@ -1,4 +1,4 @@ #!/bin/bash -#sudo godot/bin/godot.linuxbsd.editor.x86_64 --editor --path hamncheese | tee output.log -godot/bin/godot.linuxbsd.editor.x86_64 --editor --path test | tee output.log +#~/.steam/steam/steamapps/common/Godot\ Engine/godot.x11.opt.tools.64 --editor --path hamncheese | tee output.log +godot/bin/godot.linuxbsd.editor.x86_64 --editor --path hamncheese | tee output.log diff --git a/godot/.gitignore b/godot/.gitignore index 060f569..61ea171 100644 --- a/godot/.gitignore +++ b/godot/.gitignore @@ -132,23 +132,9 @@ cppcheck-cppcheck-build-dir/ *.pydevproject *.launch -# Gcov and Lcov code coverage -*.gcno +# GCOV code coverage *.gcda -*.gcov.html -*.func.html -*.func-sort-c.html -*index-sort-f.html -*index-sort-l.html -*index.html -godot.info -amber.png -emerald.png -glass.png -ruby.png -snow.png -updown.png -gcov.css +*.gcno # Geany *.geany diff --git a/godot/COPYRIGHT.txt b/godot/COPYRIGHT.txt index f884c69..1c22a72 100644 --- a/godot/COPYRIGHT.txt +++ b/godot/COPYRIGHT.txt @@ -204,7 +204,7 @@ License: OFL-1.1 Files: ./thirdparty/freetype/ Comment: The FreeType Project -Copyright: 1996-2022, David Turner, Robert Wilhelm, and Werner Lemberg. +Copyright: 1996-2023, David Turner, Robert Wilhelm, and Werner Lemberg. License: FTL Files: ./thirdparty/glad/ @@ -256,6 +256,12 @@ Comment: jpeg-compressor Copyright: 2012, Rich Geldreich License: public-domain or Apache-2.0 +Files: ./thirdparty/libktx/ +Comment: KTX +Copyright: 2013-2020, Mark Callow + 2010-2020 The Khronos Group, Inc. +License: Apache-2.0 + Files: ./thirdparty/libogg/ Comment: OggVorbis Copyright: 2002, Xiph.org Foundation @@ -487,7 +493,7 @@ License: Expat Files: ./thirdparty/zlib/ Comment: zlib -Copyright: 1995-2022, Jean-loup Gailly and Mark Adler +Copyright: 1995-2023, Jean-loup Gailly and Mark Adler License: Zlib Files: ./thirdparty/zstd/ diff --git a/godot/SConstruct b/godot/SConstruct index 6968967..df750be 100644 --- a/godot/SConstruct +++ b/godot/SConstruct @@ -193,6 +193,7 @@ opts.Add(BoolVariable("vulkan", "Enable the vulkan rendering driver", True)) opts.Add(BoolVariable("opengl3", "Enable the OpenGL/GLES3 rendering driver", True)) opts.Add(BoolVariable("openxr", "Enable the OpenXR driver", True)) opts.Add(BoolVariable("use_volk", "Use the volk library to load the Vulkan loader dynamically", True)) +opts.Add(BoolVariable("disable_exceptions", "Force disabling exception handling code", True)) opts.Add("custom_modules", "A list of comma-separated directory paths containing custom modules to build.", "") opts.Add(BoolVariable("custom_modules_recursive", "Detect custom modules recursively for each specified path.", True)) @@ -710,6 +711,16 @@ if selected_platform in platform_list: ) Exit(255) + # Disable exception handling. Godot doesn't use exceptions anywhere, and this + # saves around 20% of binary size and very significant build time (GH-80513). + if env["disable_exceptions"]: + if env.msvc: + env.Append(CPPDEFINES=[("_HAS_EXCEPTIONS", 0)]) + else: + env.Append(CCFLAGS=["-fno-exceptions"]) + elif env.msvc: + env.Append(CCFLAGS=["/EHsc"]) + # Configure compiler warnings if env.msvc: # MSVC if env["warnings"] == "no": @@ -739,11 +750,9 @@ if selected_platform in platform_list: ] ) - # Set exception handling model to avoid warnings caused by Windows system headers. - env.Append(CCFLAGS=["/EHsc"]) - if env["werror"]: env.Append(CCFLAGS=["/WX"]) + env.Append(LINKFLAGS=["/WX"]) else: # GCC, Clang common_warnings = [] @@ -969,7 +978,7 @@ if selected_platform in platform_list: print("Error: The `vsproj` option is only usable on Windows with Visual Studio.") Exit(255) env["CPPPATH"] = [Dir(path) for path in env["CPPPATH"]] - methods.generate_vs_project(env, GetOption("num_jobs"), env["vsproj_name"]) + methods.generate_vs_project(env, ARGUMENTS, env["vsproj_name"]) methods.generate_cpp_hint_file("cpp.hint") # Check for the existence of headers diff --git a/godot/core/config/engine.cpp b/godot/core/config/engine.cpp index 7fdea7d..17d3bdb 100644 --- a/godot/core/config/engine.cpp +++ b/godot/core/config/engine.cpp @@ -74,6 +74,14 @@ int Engine::get_max_fps() const { return _max_fps; } +void Engine::set_audio_output_latency(int p_msec) { + _audio_output_latency = p_msec > 1 ? p_msec : 1; +} + +int Engine::get_audio_output_latency() const { + return _audio_output_latency; +} + uint64_t Engine::get_frames_drawn() { return frames_drawn; } @@ -239,6 +247,10 @@ bool Engine::is_validation_layers_enabled() const { return use_validation_layers; } +bool Engine::is_generate_spirv_debug_info_enabled() const { + return generate_spirv_debug_info; +} + void Engine::set_print_error_messages(bool p_enabled) { CoreGlobals::print_error_enabled = p_enabled; } diff --git a/godot/core/config/engine.h b/godot/core/config/engine.h index 5ea653b..ff88fbc 100644 --- a/godot/core/config/engine.h +++ b/godot/core/config/engine.h @@ -61,12 +61,14 @@ private: double physics_jitter_fix = 0.5; double _fps = 1; int _max_fps = 0; + int _audio_output_latency = 0; double _time_scale = 1.0; uint64_t _physics_frames = 0; int max_physics_steps_per_frame = 8; double _physics_interpolation_fraction = 0.0f; bool abort_on_gpu_errors = false; bool use_validation_layers = false; + bool generate_spirv_debug_info = false; int32_t gpu_idx = -1; uint64_t _process_frames = 0; @@ -98,6 +100,9 @@ public: virtual void set_max_fps(int p_fps); virtual int get_max_fps() const; + virtual void set_audio_output_latency(int p_msec); + virtual int get_audio_output_latency() const; + virtual double get_frames_per_second() const { return _fps; } uint64_t get_frames_drawn(); @@ -156,6 +161,7 @@ public: bool is_abort_on_gpu_errors_enabled() const; bool is_validation_layers_enabled() const; + bool is_generate_spirv_debug_info_enabled() const; int32_t get_gpu_index() const; Engine(); diff --git a/godot/core/config/project_settings.cpp b/godot/core/config/project_settings.cpp index 1bfb745..9ffbac3 100644 --- a/godot/core/config/project_settings.cpp +++ b/godot/core/config/project_settings.cpp @@ -249,6 +249,11 @@ bool ProjectSettings::get_ignore_value_in_docs(const String &p_name) const { #endif } +void ProjectSettings::add_hidden_prefix(const String &p_prefix) { + ERR_FAIL_COND_MSG(hidden_prefixes.find(p_prefix) > -1, vformat("Hidden prefix '%s' already exists.", p_prefix)); + hidden_prefixes.push_back(p_prefix); +} + String ProjectSettings::globalize_path(const String &p_path) const { if (p_path.begins_with("res://")) { if (!resource_path.is_empty()) { @@ -388,7 +393,18 @@ void ProjectSettings::_get_property_list(List *p_list) const { vc.name = E.key; vc.order = v->order; vc.type = v->variant.get_type(); - if (v->internal || vc.name.begins_with("input/") || vc.name.begins_with("importer_defaults/") || vc.name.begins_with("import/") || vc.name.begins_with("autoload/") || vc.name.begins_with("editor_plugins/") || vc.name.begins_with("shader_globals/")) { + + bool internal = v->internal; + if (!internal) { + for (const String &F : hidden_prefixes) { + if (vc.name.begins_with(F)) { + internal = true; + break; + } + } + } + + if (internal) { vc.flags = PROPERTY_USAGE_STORAGE; } else { vc.flags = PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_STORAGE; @@ -1382,11 +1398,13 @@ ProjectSettings::ProjectSettings() { GLOBAL_DEF_BASIC(PropertyInfo(Variant::INT, "rendering/textures/canvas_textures/default_texture_filter", PROPERTY_HINT_ENUM, "Nearest,Linear,Linear Mipmap,Nearest Mipmap"), 1); GLOBAL_DEF_BASIC(PropertyInfo(Variant::INT, "rendering/textures/canvas_textures/default_texture_repeat", PROPERTY_HINT_ENUM, "Disable,Enable,Mirror"), 0); - // These properties will not show up in the dialog nor in the documentation. If you want to exclude whole groups, see _get_property_list() method. + // These properties will not show up in the dialog. If you want to exclude whole groups, use add_hidden_prefix(). GLOBAL_DEF_INTERNAL("application/config/features", PackedStringArray()); GLOBAL_DEF_INTERNAL("internationalization/locale/translation_remaps", PackedStringArray()); GLOBAL_DEF_INTERNAL("internationalization/locale/translations", PackedStringArray()); GLOBAL_DEF_INTERNAL("internationalization/locale/translations_pot_files", PackedStringArray()); + + ProjectSettings::get_singleton()->add_hidden_prefix("input/"); } ProjectSettings::~ProjectSettings() { diff --git a/godot/core/config/project_settings.h b/godot/core/config/project_settings.h index dba4aa6..302df7e 100644 --- a/godot/core/config/project_settings.h +++ b/godot/core/config/project_settings.h @@ -104,6 +104,7 @@ protected: HashSet custom_features; HashMap>> feature_overrides; + LocalVector hidden_prefixes; HashMap autoloads; Array global_class_list; @@ -168,6 +169,7 @@ public: void set_restart_if_changed(const String &p_name, bool p_restart); void set_ignore_value_in_docs(const String &p_name, bool p_ignore); bool get_ignore_value_in_docs(const String &p_name) const; + void add_hidden_prefix(const String &p_prefix); String get_project_data_dir_name() const; String get_project_data_path() const; diff --git a/godot/core/core_bind.cpp b/godot/core/core_bind.cpp index 4e220d0..05fe393 100644 --- a/godot/core/core_bind.cpp +++ b/godot/core/core_bind.cpp @@ -929,6 +929,17 @@ Geometry3D *Geometry3D::get_singleton() { return singleton; } +Vector Geometry3D::compute_convex_mesh_points(const TypedArray &p_planes) { + Vector planes_vec; + int size = p_planes.size(); + planes_vec.resize(size); + for (int i = 0; i < size; ++i) { + planes_vec.set(i, p_planes[i]); + } + Variant ret = ::Geometry3D::compute_convex_mesh_points(planes_vec.ptr(), size); + return ret; +} + TypedArray Geometry3D::build_box_planes(const Vector3 &p_extents) { Variant ret = ::Geometry3D::build_box_planes(p_extents); return ret; @@ -1029,6 +1040,7 @@ Vector Geometry3D::clip_polygon(const Vector &p_points, const } void Geometry3D::_bind_methods() { + ClassDB::bind_method(D_METHOD("compute_convex_mesh_points", "planes"), &Geometry3D::compute_convex_mesh_points); ClassDB::bind_method(D_METHOD("build_box_planes", "extents"), &Geometry3D::build_box_planes); ClassDB::bind_method(D_METHOD("build_cylinder_planes", "radius", "height", "sides", "axis"), &Geometry3D::build_cylinder_planes, DEFVAL(Vector3::AXIS_Z)); ClassDB::bind_method(D_METHOD("build_capsule_planes", "radius", "height", "sides", "lats", "axis"), &Geometry3D::build_capsule_planes, DEFVAL(Vector3::AXIS_Z)); diff --git a/godot/core/core_bind.h b/godot/core/core_bind.h index 1cbbcdd..5f51b64 100644 --- a/godot/core/core_bind.h +++ b/godot/core/core_bind.h @@ -320,6 +320,7 @@ protected: public: static Geometry3D *get_singleton(); + Vector compute_convex_mesh_points(const TypedArray &p_planes); TypedArray build_box_planes(const Vector3 &p_extents); TypedArray build_cylinder_planes(float p_radius, float p_height, int p_sides, Vector3::Axis p_axis = Vector3::AXIS_Z); TypedArray build_capsule_planes(float p_radius, float p_height, int p_sides, int p_lats, Vector3::Axis p_axis = Vector3::AXIS_Z); diff --git a/godot/core/core_constants.cpp b/godot/core/core_constants.cpp index 2332bc2..33b3271 100644 --- a/godot/core/core_constants.cpp +++ b/godot/core/core_constants.cpp @@ -420,6 +420,10 @@ void register_global_constants() { BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, LAUNCHD); BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, LAUNCHE); BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, LAUNCHF); + BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, GLOBE); + BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, KEYBOARD); + BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, JIS_EISU); + BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, JIS_KANA); BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, UNKNOWN); BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, SPACE); BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, EXCLAM); @@ -492,10 +496,6 @@ void register_global_constants() { BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, ASCIITILDE); BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, YEN); BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, SECTION); - BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, GLOBE); - BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, KEYBOARD); - BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, JIS_EISU); - BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, JIS_KANA); BIND_CORE_BITFIELD_CLASS_FLAG_CUSTOM(KeyModifierMask, KEY_CODE_MASK, CODE_MASK); BIND_CORE_BITFIELD_CLASS_FLAG_CUSTOM(KeyModifierMask, KEY_MODIFIER_MASK, MODIFIER_MASK); diff --git a/godot/core/crypto/crypto_core.cpp b/godot/core/crypto/crypto_core.cpp index 3ca2ec2..17b34c0 100644 --- a/godot/core/crypto/crypto_core.cpp +++ b/godot/core/crypto/crypto_core.cpp @@ -73,7 +73,7 @@ Error CryptoCore::RandomGenerator::init() { } Error CryptoCore::RandomGenerator::get_random_bytes(uint8_t *r_buffer, size_t p_bytes) { - ERR_FAIL_COND_V(!ctx, ERR_UNCONFIGURED); + ERR_FAIL_NULL_V(ctx, ERR_UNCONFIGURED); int ret = mbedtls_ctr_drbg_random((mbedtls_ctr_drbg_context *)ctx, r_buffer, p_bytes); ERR_FAIL_COND_V_MSG(ret, FAILED, " failed\n ! mbedtls_ctr_drbg_seed returned an error" + itos(ret)); return OK; diff --git a/godot/core/crypto/hashing_context.cpp b/godot/core/crypto/hashing_context.cpp index 35f491c..157a0c0 100644 --- a/godot/core/crypto/hashing_context.cpp +++ b/godot/core/crypto/hashing_context.cpp @@ -35,7 +35,7 @@ Error HashingContext::start(HashType p_type) { ERR_FAIL_COND_V(ctx != nullptr, ERR_ALREADY_IN_USE); _create_ctx(p_type); - ERR_FAIL_COND_V(ctx == nullptr, ERR_UNAVAILABLE); + ERR_FAIL_NULL_V(ctx, ERR_UNAVAILABLE); switch (type) { case HASH_MD5: return ((CryptoCore::MD5Context *)ctx)->start(); @@ -48,7 +48,7 @@ Error HashingContext::start(HashType p_type) { } Error HashingContext::update(PackedByteArray p_chunk) { - ERR_FAIL_COND_V(ctx == nullptr, ERR_UNCONFIGURED); + ERR_FAIL_NULL_V(ctx, ERR_UNCONFIGURED); size_t len = p_chunk.size(); ERR_FAIL_COND_V(len == 0, FAILED); const uint8_t *r = p_chunk.ptr(); @@ -64,7 +64,7 @@ Error HashingContext::update(PackedByteArray p_chunk) { } PackedByteArray HashingContext::finish() { - ERR_FAIL_COND_V(ctx == nullptr, PackedByteArray()); + ERR_FAIL_NULL_V(ctx, PackedByteArray()); PackedByteArray out; Error err = FAILED; switch (type) { diff --git a/godot/core/debugger/engine_profiler.h b/godot/core/debugger/engine_profiler.h index f74481c..d3d0021 100644 --- a/godot/core/debugger/engine_profiler.h +++ b/godot/core/debugger/engine_profiler.h @@ -31,10 +31,8 @@ #ifndef ENGINE_PROFILER_H #define ENGINE_PROFILER_H -#include "core/object/ref_counted.h" - #include "core/object/gdvirtual.gen.inc" -#include "core/object/script_language.h" +#include "core/object/ref_counted.h" class EngineProfiler : public RefCounted { GDCLASS(EngineProfiler, RefCounted); diff --git a/godot/core/debugger/remote_debugger.cpp b/godot/core/debugger/remote_debugger.cpp index b4d6fa4..a817ea8 100644 --- a/godot/core/debugger/remote_debugger.cpp +++ b/godot/core/debugger/remote_debugger.cpp @@ -415,7 +415,7 @@ void RemoteDebugger::debug(bool p_can_continue, bool p_is_error_breakpoint) { Array msg; msg.push_back(p_can_continue); msg.push_back(error_str); - ERR_FAIL_COND(!script_lang); + ERR_FAIL_NULL(script_lang); msg.push_back(script_lang->debug_get_stack_level_count() > 0); msg.push_back(Thread::get_caller_id() == Thread::get_main_id() ? String(RTR("Main Thread")) : itos(Thread::get_caller_id())); if (allow_focus_steal_fn) { @@ -485,7 +485,7 @@ void RemoteDebugger::debug(bool p_can_continue, bool p_is_error_breakpoint) { } else if (command == "get_stack_frame_vars") { ERR_FAIL_COND(data.size() != 1); - ERR_FAIL_COND(!script_lang); + ERR_FAIL_NULL(script_lang); int lv = data[0]; List members; diff --git a/godot/core/extension/extension_api_dump.cpp b/godot/core/extension/extension_api_dump.cpp index c67867f..97ead0b 100644 --- a/godot/core/extension/extension_api_dump.cpp +++ b/godot/core/extension/extension_api_dump.cpp @@ -750,6 +750,9 @@ Dictionary GDExtensionAPIDump::generate_extension_api() { class_list.sort_custom(); for (const StringName &class_name : class_list) { + if (!ClassDB::is_class_exposed(class_name)) { + continue; + } Dictionary d; d["name"] = String(class_name); d["is_refcounted"] = ClassDB::is_parent_class(class_name, "RefCounted"); diff --git a/godot/core/extension/gdextension.cpp b/godot/core/extension/gdextension.cpp index 67b55db..3bc7dde 100644 --- a/godot/core/extension/gdextension.cpp +++ b/godot/core/extension/gdextension.cpp @@ -281,7 +281,42 @@ public: } }; +#ifndef DISABLE_DEPRECATED void GDExtension::_register_extension_class(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, GDExtensionConstStringNamePtr p_parent_class_name, const GDExtensionClassCreationInfo *p_extension_funcs) { + const GDExtensionClassCreationInfo2 class_info2 = { + p_extension_funcs->is_virtual, // GDExtensionBool is_virtual; + p_extension_funcs->is_abstract, // GDExtensionBool is_abstract; + true, // GDExtensionBool is_exposed; + p_extension_funcs->set_func, // GDExtensionClassSet set_func; + p_extension_funcs->get_func, // GDExtensionClassGet get_func; + p_extension_funcs->get_property_list_func, // GDExtensionClassGetPropertyList get_property_list_func; + p_extension_funcs->free_property_list_func, // GDExtensionClassFreePropertyList free_property_list_func; + p_extension_funcs->property_can_revert_func, // GDExtensionClassPropertyCanRevert property_can_revert_func; + p_extension_funcs->property_get_revert_func, // GDExtensionClassPropertyGetRevert property_get_revert_func; + nullptr, // GDExtensionClassValidateProperty validate_property_func; + nullptr, // GDExtensionClassNotification2 notification_func; + p_extension_funcs->to_string_func, // GDExtensionClassToString to_string_func; + p_extension_funcs->reference_func, // GDExtensionClassReference reference_func; + p_extension_funcs->unreference_func, // GDExtensionClassUnreference unreference_func; + p_extension_funcs->create_instance_func, // GDExtensionClassCreateInstance create_instance_func; /* this one is mandatory */ + p_extension_funcs->free_instance_func, // GDExtensionClassFreeInstance free_instance_func; /* this one is mandatory */ + p_extension_funcs->get_virtual_func, // GDExtensionClassGetVirtual get_virtual_func; + p_extension_funcs->get_rid_func, // GDExtensionClassGetRID get_rid; + p_extension_funcs->class_userdata, // void *class_userdata; + }; + + const ClassCreationDeprecatedInfo legacy = { + p_extension_funcs->notification_func, + }; + _register_extension_class_internal(p_library, p_class_name, p_parent_class_name, &class_info2, &legacy); +} +#endif // DISABLE_DEPRECATED + +void GDExtension::_register_extension_class2(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, GDExtensionConstStringNamePtr p_parent_class_name, const GDExtensionClassCreationInfo2 *p_extension_funcs) { + _register_extension_class_internal(p_library, p_class_name, p_parent_class_name, p_extension_funcs); +} + +void GDExtension::_register_extension_class_internal(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, GDExtensionConstStringNamePtr p_parent_class_name, const GDExtensionClassCreationInfo2 *p_extension_funcs, const ClassCreationDeprecatedInfo *p_deprecated_funcs) { GDExtension *self = reinterpret_cast(p_library); StringName class_name = *reinterpret_cast(p_class_name); @@ -319,13 +354,20 @@ void GDExtension::_register_extension_class(GDExtensionClassLibraryPtr p_library extension->gdextension.editor_class = self->level_initialized == INITIALIZATION_LEVEL_EDITOR; extension->gdextension.is_virtual = p_extension_funcs->is_virtual; extension->gdextension.is_abstract = p_extension_funcs->is_abstract; + extension->gdextension.is_exposed = p_extension_funcs->is_exposed; extension->gdextension.set = p_extension_funcs->set_func; extension->gdextension.get = p_extension_funcs->get_func; extension->gdextension.get_property_list = p_extension_funcs->get_property_list_func; extension->gdextension.free_property_list = p_extension_funcs->free_property_list_func; extension->gdextension.property_can_revert = p_extension_funcs->property_can_revert_func; extension->gdextension.property_get_revert = p_extension_funcs->property_get_revert_func; - extension->gdextension.notification = p_extension_funcs->notification_func; + extension->gdextension.validate_property = p_extension_funcs->validate_property_func; +#ifndef DISABLE_DEPRECATED + if (p_deprecated_funcs) { + extension->gdextension.notification = p_deprecated_funcs->notification_func; + } +#endif // DISABLE_DEPRECATED + extension->gdextension.notification2 = p_extension_funcs->notification_func; extension->gdextension.to_string = p_extension_funcs->to_string_func; extension->gdextension.reference = p_extension_funcs->reference_func; extension->gdextension.unreference = p_extension_funcs->unreference_func; @@ -337,6 +379,7 @@ void GDExtension::_register_extension_class(GDExtensionClassLibraryPtr p_library ClassDB::register_extension_class(&extension->gdextension); } + void GDExtension::_register_extension_class_method(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, const GDExtensionClassMethodInfo *p_method_info) { GDExtension *self = reinterpret_cast(p_library); @@ -448,7 +491,7 @@ void GDExtension::register_interface_function(StringName p_function_name, GDExte GDExtensionInterfaceFunctionPtr GDExtension::get_interface_function(StringName p_function_name) { GDExtensionInterfaceFunctionPtr *function = gdextension_interface_functions.getptr(p_function_name); - ERR_FAIL_COND_V_MSG(function == nullptr, nullptr, "Attempt to get non-existent interface function: " + p_function_name); + ERR_FAIL_NULL_V_MSG(function, nullptr, "Attempt to get non-existent interface function: " + String(p_function_name) + "."); return *function; } @@ -482,9 +525,16 @@ Error GDExtension::open_library(const String &p_path, const String &p_entry_symb } void GDExtension::close_library() { - ERR_FAIL_COND(library == nullptr); + ERR_FAIL_NULL(library); OS::get_singleton()->close_dynamic_library(library); +#if defined(TOOLS_ENABLED) && defined(WINDOWS_ENABLED) + // Delete temporary copy of library if it exists. + if (!temp_lib_path.is_empty() && Engine::get_singleton()->is_editor_hint()) { + DirAccess::remove_absolute(temp_lib_path); + } +#endif + library = nullptr; } @@ -493,12 +543,12 @@ bool GDExtension::is_library_open() const { } GDExtension::InitializationLevel GDExtension::get_minimum_library_initialization_level() const { - ERR_FAIL_COND_V(library == nullptr, INITIALIZATION_LEVEL_CORE); + ERR_FAIL_NULL_V(library, INITIALIZATION_LEVEL_CORE); return InitializationLevel(initialization.minimum_initialization_level); } void GDExtension::initialize_library(InitializationLevel p_level) { - ERR_FAIL_COND(library == nullptr); + ERR_FAIL_NULL(library); ERR_FAIL_COND_MSG(p_level <= int32_t(level_initialized), vformat("Level '%d' must be higher than the current level '%d'", p_level, level_initialized)); level_initialized = int32_t(p_level); @@ -508,7 +558,7 @@ void GDExtension::initialize_library(InitializationLevel p_level) { initialization.initialize(initialization.userdata, GDExtensionInitializationLevel(p_level)); } void GDExtension::deinitialize_library(InitializationLevel p_level) { - ERR_FAIL_COND(library == nullptr); + ERR_FAIL_NULL(library); ERR_FAIL_COND(p_level > int32_t(level_initialized)); level_initialized = int32_t(p_level) - 1; @@ -541,7 +591,10 @@ GDExtension::~GDExtension() { void GDExtension::initialize_gdextensions() { gdextension_setup_interface(); +#ifndef DISABLE_DEPRECATED register_interface_function("classdb_register_extension_class", (GDExtensionInterfaceFunctionPtr)&GDExtension::_register_extension_class); +#endif // DISABLE_DEPRECATED + register_interface_function("classdb_register_extension_class2", (GDExtensionInterfaceFunctionPtr)&GDExtension::_register_extension_class2); register_interface_function("classdb_register_extension_class_method", (GDExtensionInterfaceFunctionPtr)&GDExtension::_register_extension_class_method); register_interface_function("classdb_register_extension_class_integer_constant", (GDExtensionInterfaceFunctionPtr)&GDExtension::_register_extension_class_integer_constant); register_interface_function("classdb_register_extension_class_property", (GDExtensionInterfaceFunctionPtr)&GDExtension::_register_extension_class_property); @@ -607,12 +660,13 @@ Ref GDExtensionResourceLoader::load(const String &p_path, const String } bool compatible = true; - if (VERSION_MAJOR < compatibility_minimum[0]) { - compatible = false; - } else if (VERSION_MINOR < compatibility_minimum[1]) { - compatible = false; - } else if (VERSION_PATCH < compatibility_minimum[2]) { - compatible = false; + // Check version lexicographically. + if (VERSION_MAJOR != compatibility_minimum[0]) { + compatible = VERSION_MAJOR > compatibility_minimum[0]; + } else if (VERSION_MINOR != compatibility_minimum[1]) { + compatible = VERSION_MINOR > compatibility_minimum[1]; + } else { + compatible = VERSION_PATCH >= compatibility_minimum[2]; } if (!compatible) { if (r_error) { @@ -640,6 +694,45 @@ Ref GDExtensionResourceLoader::load(const String &p_path, const String Ref lib; lib.instantiate(); String abs_path = ProjectSettings::get_singleton()->globalize_path(library_path); + +#if defined(WINDOWS_ENABLED) && defined(TOOLS_ENABLED) + // If running on the editor on Windows, we copy the library and open the copy. + // This is so the original file isn't locked and can be updated by a compiler. + if (Engine::get_singleton()->is_editor_hint()) { + if (!FileAccess::exists(abs_path)) { + if (r_error) { + *r_error = ERR_FILE_NOT_FOUND; + } + ERR_PRINT("GDExtension library not found: " + library_path); + return Ref(); + } + + // Copy the file to the same directory as the original with a prefix in the name. + // This is so relative path to dependencies are satisfied. + String copy_path = abs_path.get_base_dir().path_join("~" + abs_path.get_file()); + + // If there's a left-over copy (possibly from a crash) then delete it first. + if (FileAccess::exists(copy_path)) { + DirAccess::remove_absolute(copy_path); + } + + Error copy_err = DirAccess::copy_absolute(abs_path, copy_path); + if (copy_err) { + if (r_error) { + *r_error = ERR_CANT_CREATE; + } + ERR_PRINT("Error copying GDExtension library: " + library_path); + return Ref(); + } + FileAccess::set_hidden_attribute(copy_path, true); + + // Save the copied path so it can be deleted later. + lib->set_temp_library_path(copy_path); + + // Use the copy to open the library. + abs_path = copy_path; + } +#endif err = lib->open_library(abs_path, entry_symbol); if (r_error) { @@ -647,6 +740,12 @@ Ref GDExtensionResourceLoader::load(const String &p_path, const String } if (err != OK) { +#if defined(WINDOWS_ENABLED) && defined(TOOLS_ENABLED) + // If the DLL fails to load, make sure that temporary DLL copies are cleaned up. + if (Engine::get_singleton()->is_editor_hint()) { + DirAccess::remove_absolute(lib->get_temp_library_path()); + } +#endif // Errors already logged in open_library() return Ref(); } diff --git a/godot/core/extension/gdextension.h b/godot/core/extension/gdextension.h index b935f87..628cfae 100644 --- a/godot/core/extension/gdextension.h +++ b/godot/core/extension/gdextension.h @@ -43,6 +43,9 @@ class GDExtension : public Resource { void *library = nullptr; // pointer if valid, String library_path; +#if defined(WINDOWS_ENABLED) && defined(TOOLS_ENABLED) + String temp_lib_path; +#endif struct Extension { ObjectGDExtension gdextension; @@ -50,7 +53,17 @@ class GDExtension : public Resource { HashMap extension_classes; + struct ClassCreationDeprecatedInfo { +#ifndef DISABLE_DEPRECATED + GDExtensionClassNotification notification_func = nullptr; +#endif // DISABLE_DEPRECATED + }; + +#ifndef DISABLE_DEPRECATED static void _register_extension_class(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, GDExtensionConstStringNamePtr p_parent_class_name, const GDExtensionClassCreationInfo *p_extension_funcs); +#endif // DISABLE_DEPRECATED + static void _register_extension_class2(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, GDExtensionConstStringNamePtr p_parent_class_name, const GDExtensionClassCreationInfo2 *p_extension_funcs); + static void _register_extension_class_internal(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, GDExtensionConstStringNamePtr p_parent_class_name, const GDExtensionClassCreationInfo2 *p_extension_funcs, const ClassCreationDeprecatedInfo *p_deprecated_funcs = nullptr); static void _register_extension_class_method(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, const GDExtensionClassMethodInfo *p_method_info); static void _register_extension_class_integer_constant(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, GDExtensionConstStringNamePtr p_enum_name, GDExtensionConstStringNamePtr p_constant_name, GDExtensionInt p_constant_value, GDExtensionBool p_is_bitfield); static void _register_extension_class_property(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, const GDExtensionPropertyInfo *p_info, GDExtensionConstStringNamePtr p_setter, GDExtensionConstStringNamePtr p_getter); @@ -76,6 +89,11 @@ public: Error open_library(const String &p_path, const String &p_entry_symbol); void close_library(); +#if defined(WINDOWS_ENABLED) && defined(TOOLS_ENABLED) + void set_temp_library_path(const String &p_path) { temp_lib_path = p_path; } + String get_temp_library_path() const { return temp_lib_path; } +#endif + enum InitializationLevel { INITIALIZATION_LEVEL_CORE = GDEXTENSION_INITIALIZATION_CORE, INITIALIZATION_LEVEL_SERVERS = GDEXTENSION_INITIALIZATION_SERVERS, diff --git a/godot/core/extension/gdextension_interface.cpp b/godot/core/extension/gdextension_interface.cpp index b4541de..f59ee29 100644 --- a/godot/core/extension/gdextension_interface.cpp +++ b/godot/core/extension/gdextension_interface.cpp @@ -1041,13 +1041,85 @@ static void gdextension_ref_set_object(GDExtensionRefPtr p_ref, GDExtensionObjec ref->reference_ptr(o); } +#ifndef DISABLE_DEPRECATED static GDExtensionScriptInstancePtr gdextension_script_instance_create(const GDExtensionScriptInstanceInfo *p_info, GDExtensionScriptInstanceDataPtr p_instance_data) { + GDExtensionScriptInstanceInfo2 *info_2 = memnew(GDExtensionScriptInstanceInfo2); + info_2->set_func = p_info->set_func; + info_2->get_func = p_info->get_func; + info_2->get_property_list_func = p_info->get_property_list_func; + info_2->free_property_list_func = p_info->free_property_list_func; + info_2->property_can_revert_func = p_info->property_can_revert_func; + info_2->property_get_revert_func = p_info->property_get_revert_func; + info_2->get_owner_func = p_info->get_owner_func; + info_2->get_property_state_func = p_info->get_property_state_func; + info_2->get_method_list_func = p_info->get_method_list_func; + info_2->free_method_list_func = p_info->free_method_list_func; + info_2->get_property_type_func = p_info->get_property_type_func; + info_2->validate_property_func = nullptr; + info_2->has_method_func = p_info->has_method_func; + info_2->call_func = p_info->call_func; + info_2->notification_func = nullptr; + info_2->to_string_func = p_info->to_string_func; + info_2->refcount_incremented_func = p_info->refcount_incremented_func; + info_2->refcount_decremented_func = p_info->refcount_decremented_func; + info_2->get_script_func = p_info->get_script_func; + info_2->is_placeholder_func = p_info->is_placeholder_func; + info_2->set_fallback_func = p_info->set_fallback_func; + info_2->get_fallback_func = p_info->get_fallback_func; + info_2->get_language_func = p_info->get_language_func; + info_2->free_func = p_info->free_func; + + ScriptInstanceExtension *script_instance_extension = memnew(ScriptInstanceExtension); + script_instance_extension->instance = p_instance_data; + script_instance_extension->native_info = info_2; + script_instance_extension->free_native_info = true; + script_instance_extension->deprecated_native_info.notification_func = p_info->notification_func; + return reinterpret_cast(script_instance_extension); +} +#endif // DISABLE_DEPRECATED + +static GDExtensionScriptInstancePtr gdextension_script_instance_create2(const GDExtensionScriptInstanceInfo2 *p_info, GDExtensionScriptInstanceDataPtr p_instance_data) { ScriptInstanceExtension *script_instance_extension = memnew(ScriptInstanceExtension); script_instance_extension->instance = p_instance_data; script_instance_extension->native_info = p_info; return reinterpret_cast(script_instance_extension); } +static GDExtensionScriptInstancePtr gdextension_placeholder_script_instance_create(GDExtensionObjectPtr p_language, GDExtensionObjectPtr p_script, GDExtensionObjectPtr p_owner) { + ScriptLanguage *language = (ScriptLanguage *)p_language; + Ref