diff options
Diffstat (limited to 'modules')
57 files changed, 827 insertions, 307 deletions
diff --git a/modules/basis_universal/register_types.cpp b/modules/basis_universal/register_types.cpp index 9a13406900..d2105d7c5d 100644 --- a/modules/basis_universal/register_types.cpp +++ b/modules/basis_universal/register_types.cpp @@ -203,7 +203,7 @@ static Ref<Image> basis_universal_unpacker(const Vector<uint8_t> &p_buffer) { format = basist::transcoder_texture_format::cTFETC2; // get this from renderer imgfmt = Image::FORMAT_ETC2_RGBA8; } else { - //gles2 most likely + //opengl most likely format = basist::transcoder_texture_format::cTFRGBA4444; // get this from renderer imgfmt = Image::FORMAT_RGBA4444; } @@ -216,7 +216,7 @@ static Ref<Image> basis_universal_unpacker(const Vector<uint8_t> &p_buffer) { format = basist::transcoder_texture_format::cTFETC2; // get this from renderer imgfmt = Image::FORMAT_ETC2_RGBA8; } else { - //gles2 most likely, bad for normal maps, nothing to do about this. + //opengl most likely, bad for normal maps, nothing to do about this. format = basist::transcoder_texture_format::cTFRGBA32; imgfmt = Image::FORMAT_RGBA8; } diff --git a/modules/bullet/area_bullet.cpp b/modules/bullet/area_bullet.cpp index c3bd84c329..b5a7da0c38 100644 --- a/modules/bullet/area_bullet.cpp +++ b/modules/bullet/area_bullet.cpp @@ -94,10 +94,9 @@ void AreaBullet::dispatch_callbacks() { void AreaBullet::call_event(CollisionObjectBullet *p_otherObject, PhysicsServer3D::AreaBodyStatus p_status) { InOutEventCallback &event = eventsCallbacks[static_cast<int>(p_otherObject->getType())]; - Object *areaGodoObject = ObjectDB::get_instance(event.event_callback_id); - if (!areaGodoObject) { - event.event_callback_id = ObjectID(); + if (!event.event_callback.is_valid()) { + event.event_callback = Callable(); return; } @@ -108,7 +107,8 @@ void AreaBullet::call_event(CollisionObjectBullet *p_otherObject, PhysicsServer3 call_event_res[4] = 0; // self_shape ID Callable::CallError outResp; - areaGodoObject->call(event.event_callback_method, (const Variant **)call_event_res_ptr, 5, outResp); + Variant ret; + event.event_callback.call((const Variant **)call_event_res, 5, ret, outResp); } void AreaBullet::scratch() { @@ -267,13 +267,12 @@ Variant AreaBullet::get_param(PhysicsServer3D::AreaParameter p_param) const { } } -void AreaBullet::set_event_callback(Type p_callbackObjectType, ObjectID p_id, const StringName &p_method) { +void AreaBullet::set_event_callback(Type p_callbackObjectType, const Callable &p_callback) { InOutEventCallback &ev = eventsCallbacks[static_cast<int>(p_callbackObjectType)]; - ev.event_callback_id = p_id; - ev.event_callback_method = p_method; + ev.event_callback = p_callback; /// Set if monitoring - if (eventsCallbacks[0].event_callback_id.is_valid() || eventsCallbacks[1].event_callback_id.is_valid()) { + if (!eventsCallbacks[0].event_callback.is_null() || !eventsCallbacks[1].event_callback.is_null()) { set_godot_object_flags(get_godot_object_flags() | GOF_IS_MONITORING_AREA); } else { set_godot_object_flags(get_godot_object_flags() & (~GOF_IS_MONITORING_AREA)); @@ -281,7 +280,7 @@ void AreaBullet::set_event_callback(Type p_callbackObjectType, ObjectID p_id, co } bool AreaBullet::has_event_callback(Type p_callbackObjectType) { - return eventsCallbacks[static_cast<int>(p_callbackObjectType)].event_callback_id.is_valid(); + return !eventsCallbacks[static_cast<int>(p_callbackObjectType)].event_callback.is_null(); } void AreaBullet::on_enter_area(AreaBullet *p_area) { diff --git a/modules/bullet/area_bullet.h b/modules/bullet/area_bullet.h index c8b516c951..d96c550082 100644 --- a/modules/bullet/area_bullet.h +++ b/modules/bullet/area_bullet.h @@ -47,8 +47,7 @@ class AreaBullet : public RigidCollisionObjectBullet { public: struct InOutEventCallback { - ObjectID event_callback_id; - StringName event_callback_method; + Callable event_callback; InOutEventCallback() {} }; @@ -162,7 +161,7 @@ public: void set_param(PhysicsServer3D::AreaParameter p_param, const Variant &p_value); Variant get_param(PhysicsServer3D::AreaParameter p_param) const; - void set_event_callback(Type p_callbackObjectType, ObjectID p_id, const StringName &p_method); + void set_event_callback(Type p_callbackObjectType, const Callable &p_callback); bool has_event_callback(Type p_callbackObjectType); virtual void on_enter_area(AreaBullet *p_area); diff --git a/modules/bullet/bullet_physics_server.cpp b/modules/bullet/bullet_physics_server.cpp index bb2db49c87..610d2145cd 100644 --- a/modules/bullet/bullet_physics_server.cpp +++ b/modules/bullet/bullet_physics_server.cpp @@ -413,18 +413,18 @@ void BulletPhysicsServer3D::area_set_monitorable(RID p_area, bool p_monitorable) area->set_monitorable(p_monitorable); } -void BulletPhysicsServer3D::area_set_monitor_callback(RID p_area, Object *p_receiver, const StringName &p_method) { +void BulletPhysicsServer3D::area_set_monitor_callback(RID p_area, const Callable &p_callback) { AreaBullet *area = area_owner.get_or_null(p_area); ERR_FAIL_COND(!area); - area->set_event_callback(CollisionObjectBullet::TYPE_RIGID_BODY, p_receiver ? p_receiver->get_instance_id() : ObjectID(), p_method); + area->set_event_callback(CollisionObjectBullet::TYPE_RIGID_BODY, p_callback.is_valid() ? p_callback : Callable()); } -void BulletPhysicsServer3D::area_set_area_monitor_callback(RID p_area, Object *p_receiver, const StringName &p_method) { +void BulletPhysicsServer3D::area_set_area_monitor_callback(RID p_area, const Callable &p_callback) { AreaBullet *area = area_owner.get_or_null(p_area); ERR_FAIL_COND(!area); - area->set_event_callback(CollisionObjectBullet::TYPE_AREA, p_receiver ? p_receiver->get_instance_id() : ObjectID(), p_method); + area->set_event_callback(CollisionObjectBullet::TYPE_AREA, p_callback.is_valid() ? p_callback : Callable()); } void BulletPhysicsServer3D::area_set_ray_pickable(RID p_area, bool p_enable) { diff --git a/modules/bullet/bullet_physics_server.h b/modules/bullet/bullet_physics_server.h index 7c146de0c3..94635b5bfc 100644 --- a/modules/bullet/bullet_physics_server.h +++ b/modules/bullet/bullet_physics_server.h @@ -160,8 +160,8 @@ public: virtual void area_set_collision_layer(RID p_area, uint32_t p_layer) override; virtual void area_set_monitorable(RID p_area, bool p_monitorable) override; - virtual void area_set_monitor_callback(RID p_area, Object *p_receiver, const StringName &p_method) override; - virtual void area_set_area_monitor_callback(RID p_area, Object *p_receiver, const StringName &p_method) override; + virtual void area_set_monitor_callback(RID p_area, const Callable &p_callback) override; + virtual void area_set_area_monitor_callback(RID p_area, const Callable &p_callback) override; virtual void area_set_ray_pickable(RID p_area, bool p_enable) override; /* RIGID BODY API */ diff --git a/modules/camera/camera_osx.mm b/modules/camera/camera_osx.mm index 02f7287d1b..6def813e5c 100644 --- a/modules/camera/camera_osx.mm +++ b/modules/camera/camera_osx.mm @@ -181,7 +181,7 @@ uint8_t *w = img_data[1].ptrw(); memcpy(w, dataCbCr, 2 * new_width * new_height); - ///TODO GLES2 doesn't support FORMAT_RG8, need to do some form of conversion + ///TODO OpenGL doesn't support FORMAT_RG8, need to do some form of conversion img[1].instantiate(); img[1]->create(new_width, new_height, 0, Image::FORMAT_RG8, img_data[1]); } diff --git a/modules/csg/csg_shape.cpp b/modules/csg/csg_shape.cpp index 863936ab8c..b9be7535dc 100644 --- a/modules/csg/csg_shape.cpp +++ b/modules/csg/csg_shape.cpp @@ -572,9 +572,9 @@ void CSGShape3D::_validate_property(PropertyInfo &property) const { bool is_collision_prefixed = property.name.begins_with("collision_"); if ((is_collision_prefixed || property.name.begins_with("use_collision")) && is_inside_tree() && !is_root_shape()) { //hide collision if not root - property.usage = PROPERTY_USAGE_NOEDITOR; + property.usage = PROPERTY_USAGE_NO_EDITOR; } else if (is_collision_prefixed && !bool(get("use_collision"))) { - property.usage = PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL; + property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL; } GeometryInstance3D::_validate_property(property); } diff --git a/modules/denoise/config.py b/modules/denoise/config.py index 6f650354cb..3aa840acb0 100644 --- a/modules/denoise/config.py +++ b/modules/denoise/config.py @@ -5,7 +5,13 @@ def can_build(env, platform): # as doing lightmap generation and denoising on Android or HTML5 # would be a bit far-fetched. desktop_platforms = ["linuxbsd", "osx", "windows"] - supported_arch = env["bits"] == "64" and env["arch"] != "arm64" and not env["arch"].startswith("rv") + supported_arch = env["bits"] == "64" + if env["arch"] == "arm64": + supported_arch = False + if env["arch"].startswith("ppc"): + supported_arch = False + if env["arch"].startswith("rv"): + supported_arch = False return env["tools"] and platform in desktop_platforms and supported_arch diff --git a/modules/fbx/editor_scene_importer_fbx.cpp b/modules/fbx/editor_scene_importer_fbx.cpp index 9bdeafbf91..b11c145599 100644 --- a/modules/fbx/editor_scene_importer_fbx.cpp +++ b/modules/fbx/editor_scene_importer_fbx.cpp @@ -843,7 +843,7 @@ Node3D *EditorSceneFormatImporterFBX::_generate_scene( if (state.animation_player == nullptr) { print_verbose("Creating animation player"); state.animation_player = memnew(AnimationPlayer); - state.root->add_child(state.animation_player); + state.root->add_child(state.animation_player, true); state.animation_player->set_owner(state.root_owner); } diff --git a/modules/gdnative/include/nativescript/godot_nativescript.h b/modules/gdnative/include/nativescript/godot_nativescript.h index 5390d30c9f..bc53a4001d 100644 --- a/modules/gdnative/include/nativescript/godot_nativescript.h +++ b/modules/gdnative/include/nativescript/godot_nativescript.h @@ -102,7 +102,7 @@ typedef enum { GODOT_PROPERTY_USAGE_DEFAULT = GODOT_PROPERTY_USAGE_STORAGE | GODOT_PROPERTY_USAGE_EDITOR | GODOT_PROPERTY_USAGE_NETWORK, GODOT_PROPERTY_USAGE_DEFAULT_INTL = GODOT_PROPERTY_USAGE_STORAGE | GODOT_PROPERTY_USAGE_EDITOR | GODOT_PROPERTY_USAGE_NETWORK | GODOT_PROPERTY_USAGE_INTERNATIONALIZED, - GODOT_PROPERTY_USAGE_NOEDITOR = GODOT_PROPERTY_USAGE_STORAGE | GODOT_PROPERTY_USAGE_NETWORK, + GODOT_PROPERTY_USAGE_NO_EDITOR = GODOT_PROPERTY_USAGE_STORAGE | GODOT_PROPERTY_USAGE_NETWORK, } godot_nativescript_property_usage_flags; typedef struct { diff --git a/modules/gdnative/videodecoder/video_stream_gdnative.cpp b/modules/gdnative/videodecoder/video_stream_gdnative.cpp index 4c9bfb395d..e249363016 100644 --- a/modules/gdnative/videodecoder/video_stream_gdnative.cpp +++ b/modules/gdnative/videodecoder/video_stream_gdnative.cpp @@ -341,7 +341,7 @@ void VideoStreamGDNative::_bind_methods() { ClassDB::bind_method(D_METHOD("set_file", "file"), &VideoStreamGDNative::set_file); ClassDB::bind_method(D_METHOD("get_file"), &VideoStreamGDNative::get_file); - ADD_PROPERTY(PropertyInfo(Variant::STRING, "file", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "set_file", "get_file"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "file", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "set_file", "get_file"); } void VideoStreamGDNative::set_audio_track(int p_track) { diff --git a/modules/gdscript/doc_classes/@GDScript.xml b/modules/gdscript/doc_classes/@GDScript.xml index 631ee4d895..5b476cda01 100644 --- a/modules/gdscript/doc_classes/@GDScript.xml +++ b/modules/gdscript/doc_classes/@GDScript.xml @@ -98,6 +98,7 @@ [codeblock] [{function:bar, line:12, source:res://script.gd}, {function:foo, line:9, source:res://script.gd}, {function:_ready, line:6, source:res://script.gd}] [/codeblock] + [b]Note:[/b] Not supported for calling from threads. Instead, this will return an empty array. </description> </method> <method name="inst2dict"> @@ -160,17 +161,24 @@ <method name="print_debug" qualifiers="vararg"> <return type="void" /> <description> - Like [method @GlobalScope.print], but prints only when used in debug mode. + Like [method @GlobalScope.print], but includes the current stack frame when running with the debugger turned on. + Output in the console would look something like this: + [codeblock] + Test print + At: res://test.gd:15:_process() + [/codeblock] + [b]Note:[/b] Not supported for calling from threads. Instead of the stack frame, this will print the thread ID. </description> </method> <method name="print_stack"> <return type="void" /> <description> - Prints a stack track at code location, only works when running with debugger turned on. + Prints a stack trace at the current code location. Only works when running with debugger turned on. Output in the console would look something like this: [codeblock] Frame 0 - res://test.gd:16 in function '_process' [/codeblock] + [b]Note:[/b] Not supported for calling from threads. Instead of the stack trace, this will print the thread ID. </description> </method> <method name="range" qualifiers="vararg"> diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp index 2e55506fd4..e4d3ed118c 100644 --- a/modules/gdscript/gdscript.cpp +++ b/modules/gdscript/gdscript.cpp @@ -979,7 +979,7 @@ bool GDScript::_set(const StringName &p_name, const Variant &p_value) { } void GDScript::_get_property_list(List<PropertyInfo> *p_properties) const { - p_properties->push_back(PropertyInfo(Variant::STRING, "script/source", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL)); + p_properties->push_back(PropertyInfo(Variant::STRING, "script/source", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL)); } void GDScript::_bind_methods() { @@ -1257,6 +1257,8 @@ bool GDScriptInstance::set(const StringName &p_name, const Variant &p_value) { call(member->setter, &val, 1, err); if (err.error == Callable::CallError::CALL_OK) { return true; //function exists, call was successful + } else { + return false; } } else { if (member->data_type.has_type) { diff --git a/modules/gdscript/gdscript_tokenizer.cpp b/modules/gdscript/gdscript_tokenizer.cpp index d4a098811a..cd247d1d26 100644 --- a/modules/gdscript/gdscript_tokenizer.cpp +++ b/modules/gdscript/gdscript_tokenizer.cpp @@ -1064,7 +1064,8 @@ void GDScriptTokenizer::check_indent() { // First time indenting, choose character now. indent_char = current_indent_char; } else if (current_indent_char != indent_char) { - Token error = make_error(vformat("Used \"%s\" for indentation instead \"%s\" as used before in the file.", String(¤t_indent_char, 1).c_escape(), String(&indent_char, 1).c_escape())); + Token error = make_error(vformat("Used %s character for indentation instead of %s as used before in the file.", + _get_indent_char_name(current_indent_char), _get_indent_char_name(indent_char))); error.start_line = line; error.start_column = 1; error.leftmost_column = 1; @@ -1114,6 +1115,12 @@ void GDScriptTokenizer::check_indent() { } } +String GDScriptTokenizer::_get_indent_char_name(char32_t ch) { + ERR_FAIL_COND_V(ch != ' ' && ch != '\t', String(&ch, 1).c_escape()); + + return ch == ' ' ? "space" : "tab"; +} + void GDScriptTokenizer::_skip_whitespace() { if (pending_indents != 0) { // Still have some indent/dedent tokens to give. diff --git a/modules/gdscript/gdscript_tokenizer.h b/modules/gdscript/gdscript_tokenizer.h index 84b82c07f0..b4ee11fd9a 100644 --- a/modules/gdscript/gdscript_tokenizer.h +++ b/modules/gdscript/gdscript_tokenizer.h @@ -233,6 +233,7 @@ private: bool has_error() const { return !error_stack.is_empty(); } Token pop_error(); char32_t _advance(); + String _get_indent_char_name(char32_t ch); void _skip_whitespace(); void check_indent(); diff --git a/modules/gdscript/gdscript_utility_functions.cpp b/modules/gdscript/gdscript_utility_functions.cpp index f1b0079536..e997d3a51e 100644 --- a/modules/gdscript/gdscript_utility_functions.cpp +++ b/modules/gdscript/gdscript_utility_functions.cpp @@ -437,9 +437,13 @@ struct GDScriptUtilityFunctionsDefinitions { str += p_args[i]->operator String(); } - ScriptLanguage *script = GDScriptLanguage::get_singleton(); - if (script->debug_get_stack_level_count() > 0) { - str += "\n At: " + script->debug_get_stack_level_source(0) + ":" + itos(script->debug_get_stack_level_line(0)) + ":" + script->debug_get_stack_level_function(0) + "()"; + if (Thread::get_caller_id() == Thread::get_main_id()) { + ScriptLanguage *script = GDScriptLanguage::get_singleton(); + if (script->debug_get_stack_level_count() > 0) { + str += "\n At: " + script->debug_get_stack_level_source(0) + ":" + itos(script->debug_get_stack_level_line(0)) + ":" + script->debug_get_stack_level_function(0) + "()"; + } + } else { + str += "\n At: Cannot retrieve debug info outside the main thread. Thread ID: " + itos(Thread::get_caller_id()); } print_line(str); @@ -448,15 +452,24 @@ struct GDScriptUtilityFunctionsDefinitions { static inline void print_stack(Variant *r_ret, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) { VALIDATE_ARG_COUNT(0); + if (Thread::get_caller_id() != Thread::get_main_id()) { + print_line("Cannot retrieve debug info outside the main thread. Thread ID: " + itos(Thread::get_caller_id())); + return; + } ScriptLanguage *script = GDScriptLanguage::get_singleton(); for (int i = 0; i < script->debug_get_stack_level_count(); i++) { print_line("Frame " + itos(i) + " - " + script->debug_get_stack_level_source(i) + ":" + itos(script->debug_get_stack_level_line(i)) + " in function '" + script->debug_get_stack_level_function(i) + "'"); }; + *r_ret = Variant(); } static inline void get_stack(Variant *r_ret, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) { VALIDATE_ARG_COUNT(0); + if (Thread::get_caller_id() != Thread::get_main_id()) { + *r_ret = Array(); + return; + } ScriptLanguage *script = GDScriptLanguage::get_singleton(); Array ret; diff --git a/modules/gdscript/gdscript_vm.cpp b/modules/gdscript/gdscript_vm.cpp index a1cc2246d6..6dd8c3e0dd 100644 --- a/modules/gdscript/gdscript_vm.cpp +++ b/modules/gdscript/gdscript_vm.cpp @@ -3309,7 +3309,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a } int err_line = line; if (err_text == "") { - err_text = "Internal Script Error! - opcode #" + itos(last_opcode) + " (report please)."; + err_text = "Internal script error! Opcode: " + itos(last_opcode) + " (please report)."; } if (!GDScriptLanguage::get_singleton()->debug_break(err_text, false)) { diff --git a/modules/gdscript/language_server/gdscript_extend_parser.cpp b/modules/gdscript/language_server/gdscript_extend_parser.cpp index f4c0c4d9bb..80f4721e2d 100644 --- a/modules/gdscript/language_server/gdscript_extend_parser.cpp +++ b/modules/gdscript/language_server/gdscript_extend_parser.cpp @@ -269,7 +269,7 @@ void ExtendGDScriptParser::parse_class_symbol(const GDScriptParser::ClassNode *p if (j > 0) { symbol.detail += ", "; } - symbol.detail += m.signal->parameters[i]->identifier->name; + symbol.detail += m.signal->parameters[j]->identifier->name; } symbol.detail += ")"; diff --git a/modules/gdscript/language_server/gdscript_workspace.cpp b/modules/gdscript/language_server/gdscript_workspace.cpp index 371e3de419..932bfb2caa 100644 --- a/modules/gdscript/language_server/gdscript_workspace.cpp +++ b/modules/gdscript/language_server/gdscript_workspace.cpp @@ -338,7 +338,9 @@ Error GDScriptWorkspace::initialize() { } Vector<DocData::MethodDoc> methods_signals; + methods_signals.append_array(class_data.constructors); methods_signals.append_array(class_data.methods); + methods_signals.append_array(class_data.operators); const int signal_start_idx = methods_signals.size(); methods_signals.append_array(class_data.signals); diff --git a/modules/gdscript/tests/scripts/parser/errors/mixing_tabs_spaces.out b/modules/gdscript/tests/scripts/parser/errors/mixing_tabs_spaces.out index 6390de9788..31bed2dbc7 100644 --- a/modules/gdscript/tests/scripts/parser/errors/mixing_tabs_spaces.out +++ b/modules/gdscript/tests/scripts/parser/errors/mixing_tabs_spaces.out @@ -1,2 +1,2 @@ GDTEST_PARSER_ERROR -Used "\t" for indentation instead " " as used before in the file. +Used tab character for indentation instead of space as used before in the file. diff --git a/modules/gltf/doc_classes/GLTFMesh.xml b/modules/gltf/doc_classes/GLTFMesh.xml index 1e7199d229..58853217e2 100644 --- a/modules/gltf/doc_classes/GLTFMesh.xml +++ b/modules/gltf/doc_classes/GLTFMesh.xml @@ -9,6 +9,8 @@ <members> <member name="blend_weights" type="PackedFloat32Array" setter="set_blend_weights" getter="get_blend_weights" default="PackedFloat32Array()"> </member> + <member name="instance_materials" type="Array" setter="set_instance_materials" getter="get_instance_materials" default="[]"> + </member> <member name="mesh" type="ImporterMesh" setter="set_mesh" getter="get_mesh"> </member> </members> diff --git a/modules/gltf/gltf_document.cpp b/modules/gltf/gltf_document.cpp index 333fc4637d..0b2854e731 100644 --- a/modules/gltf/gltf_document.cpp +++ b/modules/gltf/gltf_document.cpp @@ -795,6 +795,9 @@ Error GLTFDocument::_encode_buffer_views(Ref<GLTFState> state) { buffers.push_back(d); } print_verbose("glTF: Total buffer views: " + itos(state->buffer_views.size())); + if (!buffers.size()) { + return OK; + } state->json["bufferViews"] = buffers; return OK; } @@ -884,6 +887,9 @@ Error GLTFDocument::_encode_accessors(Ref<GLTFState> state) { accessors.push_back(d); } + if (!accessors.size()) { + return OK; + } state->json["accessors"] = accessors; ERR_FAIL_COND_V(!state->json.has("accessors"), ERR_FILE_CORRUPT); print_verbose("glTF: Total accessors: " + itos(state->accessors.size())); @@ -2112,6 +2118,7 @@ Error GLTFDocument::_serialize_meshes(Ref<GLTFState> state) { if (import_mesh.is_null()) { continue; } + Array instance_materials = state->meshes.write[gltf_mesh_i]->get_instance_materials(); Array primitives; Dictionary gltf_mesh; Array target_names; @@ -2431,7 +2438,14 @@ Error GLTFDocument::_serialize_meshes(Ref<GLTFState> state) { } } - Ref<BaseMaterial3D> mat = import_mesh->get_surface_material(surface_i); + Variant v; + if (surface_i < instance_materials.size()) { + v = instance_materials.get(surface_i); + } + Ref<BaseMaterial3D> mat = v; + if (!mat.is_valid()) { + mat = import_mesh->get_surface_material(surface_i); + } if (mat.is_valid()) { Map<Ref<BaseMaterial3D>, GLTFMaterialIndex>::Element *material_cache_i = state->material_cache.find(mat); if (material_cache_i && material_cache_i->get() != -1) { @@ -2475,6 +2489,9 @@ Error GLTFDocument::_serialize_meshes(Ref<GLTFState> state) { meshes.push_back(gltf_mesh); } + if (!meshes.size()) { + return OK; + } state->json["meshes"] = meshes; print_verbose("glTF: Total meshes: " + itos(meshes.size())); @@ -3454,6 +3471,9 @@ Error GLTFDocument::_serialize_materials(Ref<GLTFState> state) { } materials.push_back(d); } + if (!materials.size()) { + return OK; + } state->json["materials"] = materials; print_verbose("Total materials: " + itos(state->materials.size())); @@ -4837,6 +4857,9 @@ Error GLTFDocument::_serialize_animations(Ref<GLTFState> state) { } } + if (!animations.size()) { + return OK; + } state->json["animations"] = animations; print_verbose("glTF: Total animations '" + itos(state->animations.size()) + "'."); @@ -5057,6 +5080,18 @@ GLTFMeshIndex GLTFDocument::_convert_mesh_to_gltf(Ref<GLTFState> state, MeshInst } Ref<GLTFMesh> gltf_mesh; gltf_mesh.instantiate(); + Array instance_materials; + for (int32_t surface_i = 0; surface_i < current_mesh->get_surface_count(); surface_i++) { + Ref<Material> mat = current_mesh->get_surface_material(surface_i); + if (p_mesh_instance->get_surface_override_material(surface_i).is_valid()) { + mat = p_mesh_instance->get_surface_override_material(surface_i); + } + if (p_mesh_instance->get_material_override().is_valid()) { + mat = p_mesh_instance->get_material_override(); + } + instance_materials.append(mat); + } + gltf_mesh->set_instance_materials(instance_materials); gltf_mesh->set_mesh(current_mesh); gltf_mesh->set_blend_weights(blend_weights); GLTFMeshIndex mesh_i = state->meshes.size(); @@ -5570,7 +5605,7 @@ void GLTFDocument::_generate_scene_node(Ref<GLTFState> state, Node *scene_parent // Bone Attachment - Parent Case BoneAttachment3D *bone_attachment = _generate_bone_attachment(state, active_skeleton, node_index, gltf_node->parent); - scene_parent->add_child(bone_attachment); + scene_parent->add_child(bone_attachment, true); bone_attachment->set_owner(scene_root); // There is no gltf_node that represent this, so just directly create a unique name @@ -5593,7 +5628,7 @@ void GLTFDocument::_generate_scene_node(Ref<GLTFState> state, Node *scene_parent current_node = _generate_spatial(state, scene_parent, node_index); } - scene_parent->add_child(current_node); + scene_parent->add_child(current_node, true); if (current_node != scene_root) { current_node->set_owner(scene_root); } @@ -5623,7 +5658,7 @@ void GLTFDocument::_generate_skeleton_bone_node(Ref<GLTFState> state, Node *scen // Bone Attachment - Direct Parented Skeleton Case BoneAttachment3D *bone_attachment = _generate_bone_attachment(state, active_skeleton, node_index, gltf_node->parent); - scene_parent->add_child(bone_attachment); + scene_parent->add_child(bone_attachment, true); bone_attachment->set_owner(scene_root); // There is no gltf_node that represent this, so just directly create a unique name @@ -5637,7 +5672,7 @@ void GLTFDocument::_generate_skeleton_bone_node(Ref<GLTFState> state, Node *scen // Add it to the scene if it has not already been added if (skeleton->get_parent() == nullptr) { - scene_parent->add_child(skeleton); + scene_parent->add_child(skeleton, true); skeleton->set_owner(scene_root); } } @@ -5651,7 +5686,7 @@ void GLTFDocument::_generate_skeleton_bone_node(Ref<GLTFState> state, Node *scen // Bone Attachment - Same Node Case BoneAttachment3D *bone_attachment = _generate_bone_attachment(state, active_skeleton, node_index, node_index); - scene_parent->add_child(bone_attachment); + scene_parent->add_child(bone_attachment, true); bone_attachment->set_owner(scene_root); // There is no gltf_node that represent this, so just directly create a unique name @@ -5671,7 +5706,7 @@ void GLTFDocument::_generate_skeleton_bone_node(Ref<GLTFState> state, Node *scen current_node = _generate_light(state, scene_parent, node_index); } - scene_parent->add_child(current_node); + scene_parent->add_child(current_node, true); if (current_node != scene_root) { current_node->set_owner(scene_root); } @@ -5821,7 +5856,7 @@ void GLTFDocument::_import_animation(Ref<GLTFState> state, AnimationPlayer *ap, animation->set_name(name); if (anim->get_loop()) { - animation->set_loop(true); + animation->set_loop_mode(Animation::LOOP_LINEAR); } float length = 0.0; @@ -6185,7 +6220,7 @@ void GLTFDocument::_process_mesh_instances(Ref<GLTFState> state, Node *scene_roo ERR_CONTINUE_MSG(skeleton == nullptr, vformat("Unable to find Skeleton for node %d skin %d", node_i, skin_i)); mi->get_parent()->remove_child(mi); - skeleton->add_child(mi); + skeleton->add_child(mi, true); mi->set_owner(skeleton->get_owner()); mi->set_skin(state->skins.write[skin_i]->godot_skin); @@ -6865,7 +6900,7 @@ Node *GLTFDocument::import_scene_gltf(const String &p_path, uint32_t p_flags, in gltf_document->_process_mesh_instances(r_state, root); if (r_state->animations.size()) { AnimationPlayer *ap = memnew(AnimationPlayer); - root->add_child(ap); + root->add_child(ap, true); ap->set_owner(root); for (int i = 0; i < r_state->animations.size(); i++) { gltf_document->_import_animation(r_state, ap, i, p_bake_fps); diff --git a/modules/gltf/gltf_mesh.cpp b/modules/gltf/gltf_mesh.cpp index 747820521a..7134345b30 100644 --- a/modules/gltf/gltf_mesh.cpp +++ b/modules/gltf/gltf_mesh.cpp @@ -36,9 +36,12 @@ void GLTFMesh::_bind_methods() { ClassDB::bind_method(D_METHOD("set_mesh", "mesh"), &GLTFMesh::set_mesh); ClassDB::bind_method(D_METHOD("get_blend_weights"), &GLTFMesh::get_blend_weights); ClassDB::bind_method(D_METHOD("set_blend_weights", "blend_weights"), &GLTFMesh::set_blend_weights); + ClassDB::bind_method(D_METHOD("get_instance_materials"), &GLTFMesh::get_instance_materials); + ClassDB::bind_method(D_METHOD("set_instance_materials", "instance_materials"), &GLTFMesh::set_instance_materials); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "mesh"), "set_mesh", "get_mesh"); ADD_PROPERTY(PropertyInfo(Variant::PACKED_FLOAT32_ARRAY, "blend_weights"), "set_blend_weights", "get_blend_weights"); // Vector<float> + ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "instance_materials"), "set_instance_materials", "get_instance_materials"); } Ref<ImporterMesh> GLTFMesh::get_mesh() { @@ -49,6 +52,14 @@ void GLTFMesh::set_mesh(Ref<ImporterMesh> p_mesh) { mesh = p_mesh; } +Array GLTFMesh::get_instance_materials() { + return instance_materials; +} + +void GLTFMesh::set_instance_materials(Array p_instance_materials) { + instance_materials = p_instance_materials; +} + Vector<float> GLTFMesh::get_blend_weights() { return blend_weights; } diff --git a/modules/gltf/gltf_mesh.h b/modules/gltf/gltf_mesh.h index 3aba0ede32..cc2be93c09 100644 --- a/modules/gltf/gltf_mesh.h +++ b/modules/gltf/gltf_mesh.h @@ -43,6 +43,7 @@ class GLTFMesh : public Resource { private: Ref<ImporterMesh> mesh; Vector<float> blend_weights; + Array instance_materials; protected: static void _bind_methods(); @@ -52,5 +53,7 @@ public: void set_mesh(Ref<ImporterMesh> p_mesh); Vector<float> get_blend_weights(); void set_blend_weights(Vector<float> p_blend_weights); + Array get_instance_materials(); + void set_instance_materials(Array p_instance_materials); }; #endif // GLTF_MESH_H diff --git a/modules/minimp3/audio_stream_mp3.cpp b/modules/minimp3/audio_stream_mp3.cpp index 17ce051b67..49e9f5f97e 100644 --- a/modules/minimp3/audio_stream_mp3.cpp +++ b/modules/minimp3/audio_stream_mp3.cpp @@ -228,9 +228,9 @@ void AudioStreamMP3::_bind_methods() { ClassDB::bind_method(D_METHOD("set_loop_offset", "seconds"), &AudioStreamMP3::set_loop_offset); ClassDB::bind_method(D_METHOD("get_loop_offset"), &AudioStreamMP3::get_loop_offset); - ADD_PROPERTY(PropertyInfo(Variant::PACKED_BYTE_ARRAY, "data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_data", "get_data"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "loop", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_loop", "has_loop"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "loop_offset", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_loop_offset", "get_loop_offset"); + ADD_PROPERTY(PropertyInfo(Variant::PACKED_BYTE_ARRAY, "data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_data", "get_data"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "loop", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_loop", "has_loop"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "loop_offset", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_loop_offset", "get_loop_offset"); } AudioStreamMP3::AudioStreamMP3() { diff --git a/modules/mono/build_scripts/make_android_mono_config.py b/modules/mono/build_scripts/make_android_mono_config.py index 28494bff6e..1920ef1c1a 100644 --- a/modules/mono/build_scripts/make_android_mono_config.py +++ b/modules/mono/build_scripts/make_android_mono_config.py @@ -8,7 +8,9 @@ def generate_compressed_config(config_src, output_dir): decompr_size = len(buf) import zlib - buf = zlib.compress(buf) + # Use maximum zlib compression level to further reduce file size + # (at the cost of initial build times). + buf = zlib.compress(buf, zlib.Z_BEST_COMPRESSION) compr_size = len(buf) bytes_seq_str = "" diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp index b85b65e6d9..d9b291489b 100644 --- a/modules/mono/csharp_script.cpp +++ b/modules/mono/csharp_script.cpp @@ -1813,8 +1813,9 @@ void CSharpInstance::get_event_signals_state_for_reloading(List<Pair<StringName, } void CSharpInstance::get_property_list(List<PropertyInfo> *p_properties) const { + List<PropertyInfo> props; for (OrderedHashMap<StringName, PropertyInfo>::ConstElement E = script->member_info.front(); E; E = E.next()) { - p_properties->push_front(E.value()); + props.push_front(E.value()); } // Call _get_property_list @@ -1837,15 +1838,19 @@ void CSharpInstance::get_property_list(List<PropertyInfo> *p_properties) const { if (ret) { Array array = Array(GDMonoMarshal::mono_object_to_variant(ret)); for (int i = 0, size = array.size(); i < size; i++) { - p_properties->push_back(PropertyInfo::from_dict(array.get(i))); + props.push_back(PropertyInfo::from_dict(array.get(i))); } } - return; + break; } top = top->get_parent_class(); } + + for (const PropertyInfo &prop : props) { + p_properties->push_back(prop); + } } Variant::Type CSharpInstance::get_property_type(const StringName &p_name, bool *r_is_valid) const { @@ -2976,7 +2981,7 @@ bool CSharpScript::_set(const StringName &p_name, const Variant &p_value) { } void CSharpScript::_get_property_list(List<PropertyInfo> *p_properties) const { - p_properties->push_back(PropertyInfo(Variant::STRING, CSharpLanguage::singleton->string_names._script_source, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL)); + p_properties->push_back(PropertyInfo(Variant::STRING, CSharpLanguage::singleton->string_names._script_source, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL)); } void CSharpScript::_bind_methods() { @@ -3499,8 +3504,14 @@ Ref<Script> CSharpScript::get_base_script() const { } void CSharpScript::get_script_property_list(List<PropertyInfo> *r_list) const { + List<PropertyInfo> props; + for (OrderedHashMap<StringName, PropertyInfo>::ConstElement E = member_info.front(); E; E = E.next()) { - r_list->push_front(E.value()); + props.push_front(E.value()); + } + + for (const PropertyInfo &prop : props) { + r_list->push_back(prop); } } diff --git a/modules/mono/doc_classes/CSharpScript.xml b/modules/mono/doc_classes/CSharpScript.xml index abd860a55f..2bca8bc24e 100644 --- a/modules/mono/doc_classes/CSharpScript.xml +++ b/modules/mono/doc_classes/CSharpScript.xml @@ -12,13 +12,10 @@ </tutorials> <methods> <method name="new" qualifiers="vararg"> - <return type="Variant"> - </return> + <return type="Variant" /> <description> Returns a new instance of the script. </description> </method> </methods> - <constants> - </constants> </class> diff --git a/modules/mono/doc_classes/GodotSharp.xml b/modules/mono/doc_classes/GodotSharp.xml index 417f8ac704..a148072245 100644 --- a/modules/mono/doc_classes/GodotSharp.xml +++ b/modules/mono/doc_classes/GodotSharp.xml @@ -11,66 +11,55 @@ </tutorials> <methods> <method name="attach_thread"> - <return type="void"> - </return> + <return type="void" /> <description> Attaches the current thread to the Mono runtime. </description> </method> <method name="detach_thread"> - <return type="void"> - </return> + <return type="void" /> <description> Detaches the current thread from the Mono runtime. </description> </method> <method name="get_domain_id"> - <return type="int"> - </return> + <return type="int" /> <description> Returns the current MonoDomain ID. [b]Note:[/b] The Mono runtime must be initialized for this method to work (use [method is_runtime_initialized] to check). If the Mono runtime isn't initialized at the time this method is called, the engine will crash. </description> </method> <method name="get_scripts_domain_id"> - <return type="int"> - </return> + <return type="int" /> <description> Returns the scripts MonoDomain's ID. This will be the same MonoDomain ID as [method get_domain_id], unless the scripts domain isn't loaded. [b]Note:[/b] The Mono runtime must be initialized for this method to work (use [method is_runtime_initialized] to check). If the Mono runtime isn't initialized at the time this method is called, the engine will crash. </description> </method> <method name="is_domain_finalizing_for_unload"> - <return type="bool"> - </return> - <argument index="0" name="domain_id" type="int"> - </argument> + <return type="bool" /> + <argument index="0" name="domain_id" type="int" /> <description> Returns [code]true[/code] if the domain is being finalized, [code]false[/code] otherwise. </description> </method> <method name="is_runtime_initialized"> - <return type="bool"> - </return> + <return type="bool" /> <description> Returns [code]true[/code] if the Mono runtime is initialized, [code]false[/code] otherwise. </description> </method> <method name="is_runtime_shutting_down"> - <return type="bool"> - </return> + <return type="bool" /> <description> Returns [code]true[/code] if the Mono runtime is shutting down, [code]false[/code] otherwise. </description> </method> <method name="is_scripts_domain_loaded"> - <return type="bool"> - </return> + <return type="bool" /> <description> Returns [code]true[/code] if the scripts domain is loaded, [code]false[/code] otherwise. </description> </method> </methods> - <constants> - </constants> </class> diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Callable.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Callable.cs index a28a46896b..2722b64e6d 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Callable.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Callable.cs @@ -1,4 +1,5 @@ using System; +using System.Runtime.CompilerServices; namespace Godot { @@ -71,5 +72,32 @@ namespace Godot _method = null; _delegate = @delegate; } + + /// <summary> + /// Calls the method represented by this <see cref="Callable"/>. + /// Arguments can be passed and should match the method's signature. + /// </summary> + /// <param name="args">Arguments that will be passed to the method call.</param> + /// <returns>The value returned by the method.</returns> + public object Call(params object[] args) + { + return godot_icall_Callable_Call(ref this, args); + } + + /// <summary> + /// Calls the method represented by this <see cref="Callable"/> in deferred mode, i.e. during the idle frame. + /// Arguments can be passed and should match the method's signature. + /// </summary> + /// <param name="args">Arguments that will be passed to the method call.</param> + public void CallDeferred(params object[] args) + { + godot_icall_Callable_CallDeferred(ref this, args); + } + + [MethodImpl(MethodImplOptions.InternalCall)] + internal static extern object godot_icall_Callable_Call(ref Callable callable, object[] args); + + [MethodImpl(MethodImplOptions.InternalCall)] + internal static extern void godot_icall_Callable_CallDeferred(ref Callable callable, object[] args); } } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Mathf.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Mathf.cs index 6f7fac7429..fbc8ff64a6 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Mathf.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Mathf.cs @@ -693,5 +693,23 @@ namespace Godot } return min + ((((value - min) % range) + range) % range); } + + private static real_t Fract(real_t value) + { + return value - (real_t)Math.Floor(value); + } + + /// <summary> + /// Returns the [code]value[/code] wrapped between [code]0[/code] and the [code]length[/code]. + /// If the limit is reached, the next value the function returned is decreased to the [code]0[/code] side or increased to the [code]length[/code] side (like a triangle wave). + /// If [code]length[/code] is less than zero, it becomes positive. + /// </summary> + /// <param name="value">The value to pingpong.</param> + /// <param name="length">The maximum value of the function.</param> + /// <returns>The ping-ponged value.</returns> + public static real_t PingPong(real_t value, real_t length) + { + return (length != (real_t)0.0) ? Abs(Fract((value - length) / (length * (real_t)2.0)) * length * (real_t)2.0 - length) : (real_t)0.0; + } } } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Quaternion.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Quaternion.cs index 1694ac0320..c18f818ed2 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Quaternion.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Quaternion.cs @@ -472,26 +472,22 @@ namespace Godot return new Quaternion(-left.x, -left.y, -left.z, -left.w); } - public static Quaternion operator *(Quaternion left, Vector3 right) + public static Vector3 operator *(Quaternion quat, Vector3 vec) { - return new Quaternion - ( - (left.w * right.x) + (left.y * right.z) - (left.z * right.y), - (left.w * right.y) + (left.z * right.x) - (left.x * right.z), - (left.w * right.z) + (left.x * right.y) - (left.y * right.x), - -(left.x * right.x) - (left.y * right.y) - (left.z * right.z) - ); +#if DEBUG + if (!quat.IsNormalized()) + { + throw new InvalidOperationException("Quaternion is not normalized."); + } +#endif + var u = new Vector3(quat.x, quat.y, quat.z); + Vector3 uv = u.Cross(vec); + return vec + (((uv * quat.w) + u.Cross(uv)) * 2); } - public static Quaternion operator *(Vector3 left, Quaternion right) + public static Vector3 operator *(Vector3 vec, Quaternion quat) { - return new Quaternion - ( - (right.w * left.x) + (right.y * left.z) - (right.z * left.y), - (right.w * left.y) + (right.z * left.x) - (right.x * left.z), - (right.w * left.z) + (right.x * left.y) - (right.y * left.x), - -(right.x * left.x) - (right.y * left.y) - (right.z * left.z) - ); + return quat.Inverse() * vec; } public static Quaternion operator *(Quaternion left, real_t right) diff --git a/modules/mono/glue/callable_glue.cpp b/modules/mono/glue/callable_glue.cpp new file mode 100644 index 0000000000..54b65fdb94 --- /dev/null +++ b/modules/mono/glue/callable_glue.cpp @@ -0,0 +1,79 @@ +/*************************************************************************/ +/* callable_glue.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifdef MONO_GLUE_ENABLED + +#include "../mono_gd/gd_mono_marshal.h" +#include "arguments_vector.h" + +MonoObject *godot_icall_Callable_Call(GDMonoMarshal::M_Callable *p_callable, MonoArray *p_args) { + Callable callable = GDMonoMarshal::managed_to_callable(*p_callable); + + int argc = mono_array_length(p_args); + + ArgumentsVector<Variant> arg_store(argc); + ArgumentsVector<const Variant *> args(argc); + + for (int i = 0; i < argc; i++) { + MonoObject *elem = mono_array_get(p_args, MonoObject *, i); + arg_store.set(i, GDMonoMarshal::mono_object_to_variant(elem)); + args.set(i, &arg_store.get(i)); + } + + Variant result; + Callable::CallError error; + callable.call(args.ptr(), argc, result, error); + + return GDMonoMarshal::variant_to_mono_object(result); +} + +void godot_icall_Callable_CallDeferred(GDMonoMarshal::M_Callable *p_callable, MonoArray *p_args) { + Callable callable = GDMonoMarshal::managed_to_callable(*p_callable); + + int argc = mono_array_length(p_args); + + ArgumentsVector<Variant> arg_store(argc); + ArgumentsVector<const Variant *> args(argc); + + for (int i = 0; i < argc; i++) { + MonoObject *elem = mono_array_get(p_args, MonoObject *, i); + arg_store.set(i, GDMonoMarshal::mono_object_to_variant(elem)); + args.set(i, &arg_store.get(i)); + } + + callable.call_deferred(args.ptr(), argc); +} + +void godot_register_callable_icalls() { + GDMonoUtils::add_internal_call("Godot.Callable::godot_icall_Callable_Call", godot_icall_Callable_Call); + GDMonoUtils::add_internal_call("Godot.Callable::godot_icall_Callable_CallDeferred", godot_icall_Callable_CallDeferred); +} + +#endif // MONO_GLUE_ENABLED diff --git a/modules/mono/glue/glue_header.h b/modules/mono/glue/glue_header.h index eed3bd2167..074220bb9b 100644 --- a/modules/mono/glue/glue_header.h +++ b/modules/mono/glue/glue_header.h @@ -36,6 +36,7 @@ void godot_register_collections_icalls(); void godot_register_gd_icalls(); void godot_register_string_name_icalls(); void godot_register_nodepath_icalls(); +void godot_register_callable_icalls(); void godot_register_object_icalls(); void godot_register_rid_icalls(); void godot_register_string_icalls(); @@ -50,6 +51,7 @@ void godot_register_glue_header_icalls() { godot_register_gd_icalls(); godot_register_string_name_icalls(); godot_register_nodepath_icalls(); + godot_register_callable_icalls(); godot_register_object_icalls(); godot_register_rid_icalls(); godot_register_string_icalls(); diff --git a/modules/mono/utils/string_utils.cpp b/modules/mono/utils/string_utils.cpp index 6fdb5079ce..74f5e6d18a 100644 --- a/modules/mono/utils/string_utils.cpp +++ b/modules/mono/utils/string_utils.cpp @@ -201,11 +201,11 @@ String str_format(const char *p_format, ...) { } #if defined(MINGW_ENABLED) -#define gd_vsnprintf(m_buffer, m_count, m_format, m_args_copy) vsnprintf_s(m_buffer, m_count, _TRUNCATE, m_format, m_args_copy) -#define gd_vscprintf(m_format, m_args_copy) _vscprintf(m_format, m_args_copy) +#define RSnprintf(m_buffer, m_count, m_format, m_args_copy) vsnprintf_s(m_buffer, m_count, _TRUNCATE, m_format, m_args_copy) +#define RScprintf(m_format, m_args_copy) _vscprintf(m_format, m_args_copy) #else -#define gd_vsnprintf(m_buffer, m_count, m_format, m_args_copy) vsnprintf(m_buffer, m_count, m_format, m_args_copy) -#define gd_vscprintf(m_format, m_args_copy) vsnprintf(nullptr, 0, p_format, m_args_copy) +#define RSnprintf(m_buffer, m_count, m_format, m_args_copy) vsnprintf(m_buffer, m_count, m_format, m_args_copy) +#define RScprintf(m_format, m_args_copy) vsnprintf(nullptr, 0, p_format, m_args_copy) #endif String str_format(const char *p_format, va_list p_list) { @@ -231,7 +231,7 @@ char *str_format_new(const char *p_format, va_list p_list) { va_list list; va_copy(list, p_list); - int len = gd_vscprintf(p_format, list); + int len = RScprintf(p_format, list); va_end(list); len += 1; // for the trailing '/0' @@ -239,7 +239,7 @@ char *str_format_new(const char *p_format, va_list p_list) { char *buffer(memnew_arr(char, len)); va_copy(list, p_list); - gd_vsnprintf(buffer, len, p_format, list); + RSnprintf(buffer, len, p_format, list); va_end(list); return buffer; diff --git a/modules/ogg/ogg_packet_sequence.cpp b/modules/ogg/ogg_packet_sequence.cpp index b7a3ad2876..abb2b67ab0 100644 --- a/modules/ogg/ogg_packet_sequence.cpp +++ b/modules/ogg/ogg_packet_sequence.cpp @@ -127,9 +127,9 @@ void OGGPacketSequence::_bind_methods() { ClassDB::bind_method(D_METHOD("get_length"), &OGGPacketSequence::get_length); - ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "packet_data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_packet_data", "get_packet_data"); - ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "granule_positions", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_packet_granule_positions", "get_packet_granule_positions"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sampling_rate", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_sampling_rate", "get_sampling_rate"); + ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "packet_data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_packet_data", "get_packet_data"); + ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "granule_positions", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_packet_granule_positions", "get_packet_granule_positions"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sampling_rate", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_sampling_rate", "get_sampling_rate"); } bool OGGPacketSequencePlayback::next_ogg_packet(ogg_packet **p_packet) const { diff --git a/modules/opensimplex/doc_classes/NoiseTexture.xml b/modules/opensimplex/doc_classes/NoiseTexture.xml index 8a10411cf6..16fea228b1 100644 --- a/modules/opensimplex/doc_classes/NoiseTexture.xml +++ b/modules/opensimplex/doc_classes/NoiseTexture.xml @@ -8,8 +8,9 @@ NoiseTexture can also generate normal map textures. The class uses [Thread]s to generate the texture data internally, so [method Texture2D.get_image] may return [code]null[/code] if the generation process has not completed yet. In that case, you need to wait for the texture to be generated before accessing the image and the generated byte data: [codeblock] - var texture = preload("res://noise.tres") - yield(texture, "changed") + var texture = NoiseTexture.new() + texture.noise = OpenSimplexNoise.new() + await texture.changed var image = texture.get_image() var data = image.get_data() [/codeblock] diff --git a/modules/opensimplex/noise_texture.cpp b/modules/opensimplex/noise_texture.cpp index 9db3f3d5fd..e36dcfcea5 100644 --- a/modules/opensimplex/noise_texture.cpp +++ b/modules/opensimplex/noise_texture.cpp @@ -80,7 +80,7 @@ void NoiseTexture::_bind_methods() { void NoiseTexture::_validate_property(PropertyInfo &property) const { if (property.name == "bump_strength") { if (!as_normal_map) { - property.usage = PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL; + property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL; } } } diff --git a/modules/raycast/config.py b/modules/raycast/config.py index 2f8bacd4ae..7e8b3e9840 100644 --- a/modules/raycast/config.py +++ b/modules/raycast/config.py @@ -1,6 +1,6 @@ def can_build(env, platform): # Depends on Embree library, which only supports x86_64 and aarch64. - if env["arch"].startswith("rv"): + if env["arch"].startswith("rv") or env["arch"].startswith("ppc"): return False if platform == "android": diff --git a/modules/text_server_adv/text_server_adv.cpp b/modules/text_server_adv/text_server_adv.cpp index 776134b598..1a0b0e357d 100644 --- a/modules/text_server_adv/text_server_adv.cpp +++ b/modules/text_server_adv/text_server_adv.cpp @@ -1279,6 +1279,23 @@ _FORCE_INLINE_ bool TextServerAdvanced::_ensure_cache_for_size(FontDataAdvanced fd->underline_thickness = (FT_MulFix(fd->face->underline_thickness, fd->face->size->metrics.y_scale) / 64.0) / fd->oversampling * fd->scale; if (!p_font_data->face_init) { + // Get style flags and name. + if (fd->face->family_name != nullptr) { + p_font_data->font_name = String::utf8((const char *)fd->face->family_name); + } + if (fd->face->style_name != nullptr) { + p_font_data->style_name = String::utf8((const char *)fd->face->style_name); + } + p_font_data->style_flags = 0; + if (fd->face->style_flags & FT_STYLE_FLAG_BOLD) { + p_font_data->style_flags |= FONT_BOLD; + } + if (fd->face->style_flags & FT_STYLE_FLAG_ITALIC) { + p_font_data->style_flags |= FONT_ITALIC; + } + if (fd->face->face_flags & FT_FACE_FLAG_FIXED_WIDTH) { + p_font_data->style_flags |= FONT_FIXED_WIDTH; + } // Get supported scripts from OpenType font data. p_font_data->supported_scripts.clear(); unsigned int count = hb_ot_layout_table_get_script_tags(hb_font_get_face(fd->hb_handle), HB_OT_TAG_GSUB, 0, nullptr, nullptr); @@ -1648,6 +1665,66 @@ void TextServerAdvanced::font_set_data_ptr(RID p_font_rid, const uint8_t *p_data fd->data_size = p_data_size; } +void TextServerAdvanced::font_set_style(RID p_font_rid, uint32_t /*FontStyle*/ p_style) { + FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); + ERR_FAIL_COND(!fd); + + MutexLock lock(fd->mutex); + Vector2i size = _get_size(fd, 16); + ERR_FAIL_COND(!_ensure_cache_for_size(fd, size)); + fd->style_flags = p_style; +} + +uint32_t /*FontStyle*/ TextServerAdvanced::font_get_style(RID p_font_rid) const { + FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); + ERR_FAIL_COND_V(!fd, 0); + + MutexLock lock(fd->mutex); + Vector2i size = _get_size(fd, 16); + ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 0); + return fd->style_flags; +} + +void TextServerAdvanced::font_set_style_name(RID p_font_rid, const String &p_name) { + FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); + ERR_FAIL_COND(!fd); + + MutexLock lock(fd->mutex); + Vector2i size = _get_size(fd, 16); + ERR_FAIL_COND(!_ensure_cache_for_size(fd, size)); + fd->style_name = p_name; +} + +String TextServerAdvanced::font_get_style_name(RID p_font_rid) const { + FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); + ERR_FAIL_COND_V(!fd, String()); + + MutexLock lock(fd->mutex); + Vector2i size = _get_size(fd, 16); + ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), String()); + return fd->style_name; +} + +void TextServerAdvanced::font_set_name(RID p_font_rid, const String &p_name) { + FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); + ERR_FAIL_COND(!fd); + + MutexLock lock(fd->mutex); + Vector2i size = _get_size(fd, 16); + ERR_FAIL_COND(!_ensure_cache_for_size(fd, size)); + fd->font_name = p_name; +} + +String TextServerAdvanced::font_get_name(RID p_font_rid) const { + FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); + ERR_FAIL_COND_V(!fd, String()); + + MutexLock lock(fd->mutex); + Vector2i size = _get_size(fd, 16); + ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), String()); + return fd->font_name; +} + void TextServerAdvanced::font_set_antialiased(RID p_font_rid, bool p_antialiased) { FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -2931,6 +3008,27 @@ TextServer::Direction TextServerAdvanced::shaped_text_get_direction(RID p_shaped return sd->direction; } +void TextServerAdvanced::shaped_text_set_custom_punctuation(RID p_shaped, const String &p_punct) { + _THREAD_SAFE_METHOD_ + ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); + ERR_FAIL_COND(!sd); + + if (sd->custom_punct != p_punct) { + if (sd->parent != RID()) { + full_copy(sd); + } + sd->custom_punct = p_punct; + invalidate(sd); + } +} + +String TextServerAdvanced::shaped_text_get_custom_punctuation(RID p_shaped) const { + _THREAD_SAFE_METHOD_ + const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); + ERR_FAIL_COND_V(!sd, String()); + return sd->custom_punct; +} + void TextServerAdvanced::shaped_text_set_bidi_override(RID p_shaped, const Array &p_override) { ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND(!sd); @@ -3230,6 +3328,7 @@ RID TextServerAdvanced::shaped_text_substr(RID p_shaped, int p_start, int p_leng new_sd->orientation = sd->orientation; new_sd->direction = sd->direction; + new_sd->custom_punct = sd->custom_punct; new_sd->para_direction = sd->para_direction; new_sd->line_breaks_valid = sd->line_breaks_valid; new_sd->justification_ops_valid = sd->justification_ops_valid; @@ -3654,10 +3753,10 @@ void TextServerAdvanced::shaped_text_overrun_trim_to_width(RID p_shaped_line, fl width -= sd_glyphs[i].advance * sd_glyphs[i].repeat; } if (sd_glyphs[i].count > 0) { - bool above_min_char_treshold = ((is_rtl) ? sd_size - 1 - i : i) >= ell_min_characters; + bool above_min_char_threshold = ((is_rtl) ? sd_size - 1 - i : i) >= ell_min_characters; - if (width + (((above_min_char_treshold && add_ellipsis) || enforce_ellipsis) ? ellipsis_width : 0) <= p_width) { - if (cut_per_word && above_min_char_treshold) { + if (width + (((above_min_char_threshold && add_ellipsis) || enforce_ellipsis) ? ellipsis_width : 0) <= p_width) { + if (cut_per_word && above_min_char_threshold) { if ((sd_glyphs[i].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT) { last_valid_cut = i; found = true; @@ -3669,7 +3768,7 @@ void TextServerAdvanced::shaped_text_overrun_trim_to_width(RID p_shaped_line, fl if (found) { trim_pos = last_valid_cut; - if (add_ellipsis && (above_min_char_treshold || enforce_ellipsis) && width - ellipsis_width <= p_width) { + if (add_ellipsis && (above_min_char_threshold || enforce_ellipsis) && width - ellipsis_width <= p_width) { ellipsis_pos = trim_pos; } break; @@ -3810,6 +3909,9 @@ bool TextServerAdvanced::shaped_text_update_breaks(RID p_shaped) { const char32_t *ch = sd->text.ptr(); Glyph *sd_glyphs = sd->glyphs.ptrw(); + int c_punct_size = sd->custom_punct.length(); + const char32_t *c_punct = sd->custom_punct.ptr(); + for (i = 0; i < sd_size; i++) { if (sd_glyphs[i].count > 0) { char32_t c = ch[sd_glyphs[i].start - sd->start]; @@ -3822,12 +3924,21 @@ bool TextServerAdvanced::shaped_text_update_breaks(RID p_shaped) { if (is_whitespace(c)) { sd_glyphs[i].flags |= GRAPHEME_IS_SPACE; } + if (c_punct_size == 0) { + if (u_ispunct(c) && c != 0x005F) { + sd_glyphs[i].flags |= GRAPHEME_IS_PUNCTUATION; + } + } else { + for (int j = 0; j < c_punct_size; j++) { + if (c_punct[j] == c) { + sd_glyphs[i].flags |= GRAPHEME_IS_PUNCTUATION; + break; + } + } + } if (is_underscore(c)) { sd_glyphs[i].flags |= GRAPHEME_IS_UNDERSCORE; } - if (u_ispunct(c) && c != 0x005F) { - sd_glyphs[i].flags |= GRAPHEME_IS_PUNCTUATION; - } if (breaks.has(sd->glyphs[i].start)) { if (breaks[sd->glyphs[i].start]) { sd_glyphs[i].flags |= GRAPHEME_IS_BREAK_HARD; diff --git a/modules/text_server_adv/text_server_adv.h b/modules/text_server_adv/text_server_adv.h index 15f3a7f1a9..eb8316b200 100644 --- a/modules/text_server_adv/text_server_adv.h +++ b/modules/text_server_adv/text_server_adv.h @@ -177,6 +177,10 @@ class TextServerAdvanced : public TextServer { Dictionary variation_coordinates; float oversampling = 0.f; + uint32_t style_flags = 0; + String font_name; + String style_name; + Map<Vector2i, FontDataForSizeAdvanced *> cache; bool face_init = false; @@ -321,6 +325,15 @@ public: virtual void font_set_data(RID p_font_rid, const PackedByteArray &p_data) override; virtual void font_set_data_ptr(RID p_font_rid, const uint8_t *p_data_ptr, size_t p_data_size) override; + virtual void font_set_style(RID p_font_rid, uint32_t /*FontStyle*/ p_style) override; + virtual uint32_t /*FontStyle*/ font_get_style(RID p_font_rid) const override; + + virtual void font_set_style_name(RID p_font_rid, const String &p_name) override; + virtual String font_get_style_name(RID p_font_rid) const override; + + virtual void font_set_name(RID p_font_rid, const String &p_name) override; + virtual String font_get_name(RID p_font_rid) const override; + virtual void font_set_antialiased(RID p_font_rid, bool p_antialiased) override; virtual bool font_is_antialiased(RID p_font_rid) const override; @@ -450,6 +463,9 @@ public: virtual void shaped_text_set_bidi_override(RID p_shaped, const Array &p_override) override; + virtual void shaped_text_set_custom_punctuation(RID p_shaped, const String &p_punct) override; + virtual String shaped_text_get_custom_punctuation(RID p_shaped) const override; + virtual void shaped_text_set_orientation(RID p_shaped, Orientation p_orientation = ORIENTATION_HORIZONTAL) override; virtual Orientation shaped_text_get_orientation(RID p_shaped) const override; diff --git a/modules/text_server_fb/text_server_fb.cpp b/modules/text_server_fb/text_server_fb.cpp index f598eb80ea..43a636e484 100644 --- a/modules/text_server_fb/text_server_fb.cpp +++ b/modules/text_server_fb/text_server_fb.cpp @@ -736,6 +736,23 @@ _FORCE_INLINE_ bool TextServerFallback::_ensure_cache_for_size(FontDataFallback fd->underline_thickness = (FT_MulFix(fd->face->underline_thickness, fd->face->size->metrics.y_scale) / 64.0) / fd->oversampling * fd->scale; if (!p_font_data->face_init) { + // Get style flags and name. + if (fd->face->family_name != nullptr) { + p_font_data->font_name = String::utf8((const char *)fd->face->family_name); + } + if (fd->face->style_name != nullptr) { + p_font_data->style_name = String::utf8((const char *)fd->face->style_name); + } + p_font_data->style_flags = 0; + if (fd->face->style_flags & FT_STYLE_FLAG_BOLD) { + p_font_data->style_flags |= FONT_BOLD; + } + if (fd->face->style_flags & FT_STYLE_FLAG_ITALIC) { + p_font_data->style_flags |= FONT_ITALIC; + } + if (fd->face->face_flags & FT_FACE_FLAG_FIXED_WIDTH) { + p_font_data->style_flags |= FONT_FIXED_WIDTH; + } // Read OpenType variations. p_font_data->supported_varaitions.clear(); if (fd->face->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS) { @@ -826,6 +843,66 @@ void TextServerFallback::font_set_data_ptr(RID p_font_rid, const uint8_t *p_data fd->data_size = p_data_size; } +void TextServerFallback::font_set_style(RID p_font_rid, uint32_t /*FontStyle*/ p_style) { + FontDataFallback *fd = font_owner.get_or_null(p_font_rid); + ERR_FAIL_COND(!fd); + + MutexLock lock(fd->mutex); + Vector2i size = _get_size(fd, 16); + ERR_FAIL_COND(!_ensure_cache_for_size(fd, size)); + fd->style_flags = p_style; +} + +uint32_t /*FontStyle*/ TextServerFallback::font_get_style(RID p_font_rid) const { + FontDataFallback *fd = font_owner.get_or_null(p_font_rid); + ERR_FAIL_COND_V(!fd, 0); + + MutexLock lock(fd->mutex); + Vector2i size = _get_size(fd, 16); + ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 0); + return fd->style_flags; +} + +void TextServerFallback::font_set_style_name(RID p_font_rid, const String &p_name) { + FontDataFallback *fd = font_owner.get_or_null(p_font_rid); + ERR_FAIL_COND(!fd); + + MutexLock lock(fd->mutex); + Vector2i size = _get_size(fd, 16); + ERR_FAIL_COND(!_ensure_cache_for_size(fd, size)); + fd->style_name = p_name; +} + +String TextServerFallback::font_get_style_name(RID p_font_rid) const { + FontDataFallback *fd = font_owner.get_or_null(p_font_rid); + ERR_FAIL_COND_V(!fd, String()); + + MutexLock lock(fd->mutex); + Vector2i size = _get_size(fd, 16); + ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), String()); + return fd->style_name; +} + +void TextServerFallback::font_set_name(RID p_font_rid, const String &p_name) { + FontDataFallback *fd = font_owner.get_or_null(p_font_rid); + ERR_FAIL_COND(!fd); + + MutexLock lock(fd->mutex); + Vector2i size = _get_size(fd, 16); + ERR_FAIL_COND(!_ensure_cache_for_size(fd, size)); + fd->font_name = p_name; +} + +String TextServerFallback::font_get_name(RID p_font_rid) const { + FontDataFallback *fd = font_owner.get_or_null(p_font_rid); + ERR_FAIL_COND_V(!fd, String()); + + MutexLock lock(fd->mutex); + Vector2i size = _get_size(fd, 16); + ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), String()); + return fd->font_name; +} + void TextServerFallback::font_set_antialiased(RID p_font_rid, bool p_antialiased) { FontDataFallback *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -2030,6 +2107,27 @@ TextServer::Direction TextServerFallback::shaped_text_get_direction(RID p_shaped return TextServer::DIRECTION_LTR; } +void TextServerFallback::shaped_text_set_custom_punctuation(RID p_shaped, const String &p_punct) { + _THREAD_SAFE_METHOD_ + ShapedTextData *sd = shaped_owner.get_or_null(p_shaped); + ERR_FAIL_COND(!sd); + + if (sd->custom_punct != p_punct) { + if (sd->parent != RID()) { + full_copy(sd); + } + sd->custom_punct = p_punct; + invalidate(sd); + } +} + +String TextServerFallback::shaped_text_get_custom_punctuation(RID p_shaped) const { + _THREAD_SAFE_METHOD_ + const ShapedTextData *sd = shaped_owner.get_or_null(p_shaped); + ERR_FAIL_COND_V(!sd, String()); + return sd->custom_punct; +} + void TextServerFallback::shaped_text_set_orientation(RID p_shaped, TextServer::Orientation p_orientation) { ShapedTextData *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND(!sd); @@ -2332,6 +2430,7 @@ RID TextServerFallback::shaped_text_substr(RID p_shaped, int p_start, int p_leng new_sd->orientation = sd->orientation; new_sd->direction = sd->direction; + new_sd->custom_punct = sd->custom_punct; new_sd->para_direction = sd->para_direction; new_sd->line_breaks_valid = sd->line_breaks_valid; new_sd->justification_ops_valid = sd->justification_ops_valid; @@ -2615,27 +2714,41 @@ bool TextServerFallback::shaped_text_update_breaks(RID p_shaped) { } int sd_size = sd->glyphs.size(); + Glyph *sd_glyphs = sd->glyphs.ptrw(); + + int c_punct_size = sd->custom_punct.length(); + const char32_t *c_punct = sd->custom_punct.ptr(); + for (int i = 0; i < sd_size; i++) { - if (sd->glyphs[i].count > 0) { - char32_t c = sd->text[sd->glyphs[i].start]; - if (is_punct(c)) { - sd->glyphs.write[i].flags |= GRAPHEME_IS_PUNCTUATION; + if (sd_glyphs[i].count > 0) { + char32_t c = sd->text[sd_glyphs[i].start]; + if (c_punct_size == 0) { + if (is_punct(c)) { + sd_glyphs[i].flags |= GRAPHEME_IS_PUNCTUATION; + } + } else { + for (int j = 0; j < c_punct_size; j++) { + if (c_punct[j] == c) { + sd_glyphs[i].flags |= GRAPHEME_IS_PUNCTUATION; + break; + } + } } if (is_underscore(c)) { sd->glyphs.write[i].flags |= GRAPHEME_IS_UNDERSCORE; } if (is_whitespace(c) && !is_linebreak(c)) { - sd->glyphs.write[i].flags |= GRAPHEME_IS_SPACE; - sd->glyphs.write[i].flags |= GRAPHEME_IS_BREAK_SOFT; + sd_glyphs[i].flags |= GRAPHEME_IS_SPACE; + sd_glyphs[i].flags |= GRAPHEME_IS_BREAK_SOFT; } if (is_linebreak(c)) { - sd->glyphs.write[i].flags |= GRAPHEME_IS_BREAK_HARD; + sd_glyphs[i].flags |= GRAPHEME_IS_BREAK_HARD; } if (c == 0x0009 || c == 0x000b) { - sd->glyphs.write[i].flags |= GRAPHEME_IS_TAB; + sd_glyphs[i].flags |= GRAPHEME_IS_TAB; } - i += (sd->glyphs[i].count - 1); + i += (sd_glyphs[i].count - 1); } } sd->line_breaks_valid = true; @@ -2713,10 +2826,10 @@ void TextServerFallback::shaped_text_overrun_trim_to_width(RID p_shaped_line, fl width -= sd_glyphs[i].advance * sd_glyphs[i].repeat; if (sd_glyphs[i].count > 0) { - bool above_min_char_treshold = (i >= ell_min_characters); + bool above_min_char_threshold = (i >= ell_min_characters); - if (width + (((above_min_char_treshold && add_ellipsis) || enforce_ellipsis) ? ellipsis_width : 0) <= p_width) { - if (cut_per_word && above_min_char_treshold) { + if (width + (((above_min_char_threshold && add_ellipsis) || enforce_ellipsis) ? ellipsis_width : 0) <= p_width) { + if (cut_per_word && above_min_char_threshold) { if ((sd_glyphs[i].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT) { last_valid_cut = i; found = true; @@ -2728,7 +2841,7 @@ void TextServerFallback::shaped_text_overrun_trim_to_width(RID p_shaped_line, fl if (found) { trim_pos = last_valid_cut; - if (add_ellipsis && (above_min_char_treshold || enforce_ellipsis) && width - ellipsis_width <= p_width) { + if (add_ellipsis && (above_min_char_threshold || enforce_ellipsis) && width - ellipsis_width <= p_width) { ellipsis_pos = trim_pos; } break; diff --git a/modules/text_server_fb/text_server_fb.h b/modules/text_server_fb/text_server_fb.h index fb7de8f443..2f495115e0 100644 --- a/modules/text_server_fb/text_server_fb.h +++ b/modules/text_server_fb/text_server_fb.h @@ -142,6 +142,10 @@ class TextServerFallback : public TextServer { Dictionary variation_coordinates; float oversampling = 0.f; + uint32_t style_flags = 0; + String font_name; + String style_name; + Map<Vector2i, FontDataForSizeFallback *> cache; bool face_init = false; @@ -234,6 +238,15 @@ public: virtual void font_set_data(RID p_font_rid, const PackedByteArray &p_data) override; virtual void font_set_data_ptr(RID p_font_rid, const uint8_t *p_data_ptr, size_t p_data_size) override; + virtual void font_set_style(RID p_font_rid, uint32_t /*FontStyle*/ p_style) override; + virtual uint32_t /*FontStyle*/ font_get_style(RID p_font_rid) const override; + + virtual void font_set_style_name(RID p_font_rid, const String &p_name) override; + virtual String font_get_style_name(RID p_font_rid) const override; + + virtual void font_set_name(RID p_font_rid, const String &p_name) override; + virtual String font_get_name(RID p_font_rid) const override; + virtual void font_set_antialiased(RID p_font_rid, bool p_antialiased) override; virtual bool font_is_antialiased(RID p_font_rid) const override; @@ -361,6 +374,9 @@ public: virtual void shaped_text_set_bidi_override(RID p_shaped, const Array &p_override) override; + virtual void shaped_text_set_custom_punctuation(RID p_shaped, const String &p_punct) override; + virtual String shaped_text_get_custom_punctuation(RID p_shaped) const override; + virtual void shaped_text_set_orientation(RID p_shaped, Orientation p_orientation = ORIENTATION_HORIZONTAL) override; virtual Orientation shaped_text_get_orientation(RID p_shaped) const override; diff --git a/modules/theora/video_stream_theora.cpp b/modules/theora/video_stream_theora.cpp index ef434f107e..4f5ae4afb0 100644 --- a/modules/theora/video_stream_theora.cpp +++ b/modules/theora/video_stream_theora.cpp @@ -673,7 +673,7 @@ void VideoStreamTheora::_bind_methods() { ClassDB::bind_method(D_METHOD("set_file", "file"), &VideoStreamTheora::set_file); ClassDB::bind_method(D_METHOD("get_file"), &VideoStreamTheora::get_file); - ADD_PROPERTY(PropertyInfo(Variant::STRING, "file", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "set_file", "get_file"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "file", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "set_file", "get_file"); } //////////// diff --git a/modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml b/modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml index 942d92311b..f4abb3c122 100644 --- a/modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml +++ b/modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml @@ -140,73 +140,76 @@ </constant> <constant name="MATH_WRAPF" value="42" enum="BuiltinFunc"> </constant> - <constant name="LOGIC_MAX" value="43" enum="BuiltinFunc"> + <constant name="MATH_PINGPONG" value="43" enum="BuiltinFunc"> + Return the [code]value[/code] wrapped between [code]0[/code] and the [code]length[/code]. If the limit is reached, the next value the function returned is decreased to the [code]0[/code] side or increased to the [code]length[/code] side (like a triangle wave). If [code]length[/code] is less than zero, it becomes positive. + </constant> + <constant name="LOGIC_MAX" value="44" enum="BuiltinFunc"> Return the greater of the two numbers, also known as their maximum. </constant> - <constant name="LOGIC_MIN" value="44" enum="BuiltinFunc"> + <constant name="LOGIC_MIN" value="45" enum="BuiltinFunc"> Return the lesser of the two numbers, also known as their minimum. </constant> - <constant name="LOGIC_CLAMP" value="45" enum="BuiltinFunc"> + <constant name="LOGIC_CLAMP" value="46" enum="BuiltinFunc"> Return the input clamped inside the given range, ensuring the result is never outside it. Equivalent to [code]min(max(input, range_low), range_high)[/code]. </constant> - <constant name="LOGIC_NEAREST_PO2" value="46" enum="BuiltinFunc"> + <constant name="LOGIC_NEAREST_PO2" value="47" enum="BuiltinFunc"> Return the nearest power of 2 to the input. </constant> - <constant name="OBJ_WEAKREF" value="47" enum="BuiltinFunc"> + <constant name="OBJ_WEAKREF" value="48" enum="BuiltinFunc"> Create a [WeakRef] from the input. </constant> - <constant name="TYPE_CONVERT" value="48" enum="BuiltinFunc"> + <constant name="TYPE_CONVERT" value="49" enum="BuiltinFunc"> Convert between types. </constant> - <constant name="TYPE_OF" value="49" enum="BuiltinFunc"> + <constant name="TYPE_OF" value="50" enum="BuiltinFunc"> Return the type of the input as an integer. Check [enum Variant.Type] for the integers that might be returned. </constant> - <constant name="TYPE_EXISTS" value="50" enum="BuiltinFunc"> + <constant name="TYPE_EXISTS" value="51" enum="BuiltinFunc"> Checks if a type is registered in the [ClassDB]. </constant> - <constant name="TEXT_CHAR" value="51" enum="BuiltinFunc"> + <constant name="TEXT_CHAR" value="52" enum="BuiltinFunc"> Return a character with the given ascii value. </constant> - <constant name="TEXT_STR" value="52" enum="BuiltinFunc"> + <constant name="TEXT_STR" value="53" enum="BuiltinFunc"> Convert the input to a string. </constant> - <constant name="TEXT_PRINT" value="53" enum="BuiltinFunc"> + <constant name="TEXT_PRINT" value="54" enum="BuiltinFunc"> Print the given string to the output window. </constant> - <constant name="TEXT_PRINTERR" value="54" enum="BuiltinFunc"> + <constant name="TEXT_PRINTERR" value="55" enum="BuiltinFunc"> Print the given string to the standard error output. </constant> - <constant name="TEXT_PRINTRAW" value="55" enum="BuiltinFunc"> + <constant name="TEXT_PRINTRAW" value="56" enum="BuiltinFunc"> Print the given string to the standard output, without adding a newline. </constant> - <constant name="TEXT_PRINT_VERBOSE" value="56" enum="BuiltinFunc"> + <constant name="TEXT_PRINT_VERBOSE" value="57" enum="BuiltinFunc"> </constant> - <constant name="VAR_TO_STR" value="57" enum="BuiltinFunc"> + <constant name="VAR_TO_STR" value="58" enum="BuiltinFunc"> Serialize a [Variant] to a string. </constant> - <constant name="STR_TO_VAR" value="58" enum="BuiltinFunc"> + <constant name="STR_TO_VAR" value="59" enum="BuiltinFunc"> Deserialize a [Variant] from a string serialized using [constant VAR_TO_STR]. </constant> - <constant name="VAR_TO_BYTES" value="59" enum="BuiltinFunc"> + <constant name="VAR_TO_BYTES" value="60" enum="BuiltinFunc"> Serialize a [Variant] to a [PackedByteArray]. </constant> - <constant name="BYTES_TO_VAR" value="60" enum="BuiltinFunc"> + <constant name="BYTES_TO_VAR" value="61" enum="BuiltinFunc"> Deserialize a [Variant] from a [PackedByteArray] serialized using [constant VAR_TO_BYTES]. </constant> - <constant name="MATH_SMOOTHSTEP" value="61" enum="BuiltinFunc"> + <constant name="MATH_SMOOTHSTEP" value="62" enum="BuiltinFunc"> Return a number smoothly interpolated between the first two inputs, based on the third input. Similar to [constant MATH_LERP], but interpolates faster at the beginning and slower at the end. Using Hermite interpolation formula: [codeblock] var t = clamp((weight - from) / (to - from), 0.0, 1.0) return t * t * (3.0 - 2.0 * t) [/codeblock] </constant> - <constant name="MATH_POSMOD" value="62" enum="BuiltinFunc"> + <constant name="MATH_POSMOD" value="63" enum="BuiltinFunc"> </constant> - <constant name="MATH_LERP_ANGLE" value="63" enum="BuiltinFunc"> + <constant name="MATH_LERP_ANGLE" value="64" enum="BuiltinFunc"> </constant> - <constant name="TEXT_ORD" value="64" enum="BuiltinFunc"> + <constant name="TEXT_ORD" value="65" enum="BuiltinFunc"> </constant> - <constant name="FUNC_MAX" value="65" enum="BuiltinFunc"> + <constant name="FUNC_MAX" value="66" enum="BuiltinFunc"> Represents the size of the [enum BuiltinFunc] enum. </constant> </constants> diff --git a/modules/visual_script/visual_script.cpp b/modules/visual_script/visual_script.cpp index 01fc7cfca0..700cc85672 100644 --- a/modules/visual_script/visual_script.cpp +++ b/modules/visual_script/visual_script.cpp @@ -113,7 +113,7 @@ void VisualScriptNode::_bind_methods() { ClassDB::bind_method(D_METHOD("_set_default_input_values", "values"), &VisualScriptNode::_set_default_input_values); ClassDB::bind_method(D_METHOD("_get_default_input_values"), &VisualScriptNode::_get_default_input_values); - ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "_default_input_values", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_default_input_values", "_get_default_input_values"); + ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "_default_input_values", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_default_input_values", "_get_default_input_values"); ADD_SIGNAL(MethodInfo("ports_changed")); } @@ -1172,7 +1172,7 @@ void VisualScript::_bind_methods() { ClassDB::bind_method(D_METHOD("_set_data", "data"), &VisualScript::_set_data); ClassDB::bind_method(D_METHOD("_get_data"), &VisualScript::_get_data); - ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_data", "_get_data"); + ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_data", "_get_data"); ADD_SIGNAL(MethodInfo("node_ports_changed", PropertyInfo(Variant::INT, "id"))); } diff --git a/modules/visual_script/visual_script_builtin_funcs.cpp b/modules/visual_script/visual_script_builtin_funcs.cpp index 7e01031128..54a5e1449f 100644 --- a/modules/visual_script/visual_script_builtin_funcs.cpp +++ b/modules/visual_script/visual_script_builtin_funcs.cpp @@ -81,6 +81,7 @@ const char *VisualScriptBuiltinFunc::func_name[VisualScriptBuiltinFunc::FUNC_MAX "db2linear", "wrapi", "wrapf", + "pingpong", "max", "min", "clamp", @@ -190,6 +191,7 @@ int VisualScriptBuiltinFunc::get_func_argument_count(BuiltinFunc p_func) { case MATH_FMOD: case MATH_FPOSMOD: case MATH_POSMOD: + case MATH_PINGPONG: case MATH_POW: case MATH_EASE: case MATH_SNAPPED: @@ -381,6 +383,13 @@ PropertyInfo VisualScriptBuiltinFunc::get_input_value_port_info(int p_idx) const case MATH_DB2LINEAR: { return PropertyInfo(Variant::FLOAT, "db"); } break; + case MATH_PINGPONG: { + if (p_idx == 0) { + return PropertyInfo(Variant::FLOAT, "value"); + } else { + return PropertyInfo(Variant::FLOAT, "length"); + } + } break; case MATH_WRAP: { if (p_idx == 0) { return PropertyInfo(Variant::INT, "value"); @@ -537,6 +546,7 @@ PropertyInfo VisualScriptBuiltinFunc::get_output_value_port_info(int p_idx) cons case MATH_RAD2DEG: case MATH_LINEAR2DB: case MATH_WRAPF: + case MATH_PINGPONG: case MATH_DB2LINEAR: { t = Variant::FLOAT; } break; @@ -859,6 +869,11 @@ void VisualScriptBuiltinFunc::exec_func(BuiltinFunc p_func, const Variant **p_in VALIDATE_ARG_NUM(0); *r_return = Math::db2linear((double)*p_inputs[0]); } break; + case VisualScriptBuiltinFunc::MATH_PINGPONG: { + VALIDATE_ARG_NUM(0); + VALIDATE_ARG_NUM(1); + *r_return = Math::pingpong((double)*p_inputs[0], (double)*p_inputs[1]); + } break; case VisualScriptBuiltinFunc::MATH_WRAP: { VALIDATE_ARG_NUM(0); VALIDATE_ARG_NUM(1); @@ -1206,6 +1221,7 @@ void VisualScriptBuiltinFunc::_bind_methods() { BIND_ENUM_CONSTANT(MATH_DB2LINEAR); BIND_ENUM_CONSTANT(MATH_WRAP); BIND_ENUM_CONSTANT(MATH_WRAPF); + BIND_ENUM_CONSTANT(MATH_PINGPONG); BIND_ENUM_CONSTANT(LOGIC_MAX); BIND_ENUM_CONSTANT(LOGIC_MIN); BIND_ENUM_CONSTANT(LOGIC_CLAMP); @@ -1296,6 +1312,7 @@ void register_visual_script_builtin_func_node() { VisualScriptLanguage::singleton->add_register_func("functions/built_in/db2linear", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_DB2LINEAR>); VisualScriptLanguage::singleton->add_register_func("functions/built_in/wrapi", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_WRAP>); VisualScriptLanguage::singleton->add_register_func("functions/built_in/wrapf", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_WRAPF>); + VisualScriptLanguage::singleton->add_register_func("functions/built_in/pingpong", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_PINGPONG>); VisualScriptLanguage::singleton->add_register_func("functions/built_in/max", create_builtin_func_node<VisualScriptBuiltinFunc::LOGIC_MAX>); VisualScriptLanguage::singleton->add_register_func("functions/built_in/min", create_builtin_func_node<VisualScriptBuiltinFunc::LOGIC_MIN>); diff --git a/modules/visual_script/visual_script_builtin_funcs.h b/modules/visual_script/visual_script_builtin_funcs.h index f9eb7e983f..30f1f0d417 100644 --- a/modules/visual_script/visual_script_builtin_funcs.h +++ b/modules/visual_script/visual_script_builtin_funcs.h @@ -81,6 +81,7 @@ public: MATH_DB2LINEAR, MATH_WRAP, MATH_WRAPF, + MATH_PINGPONG, LOGIC_MAX, LOGIC_MIN, LOGIC_CLAMP, diff --git a/modules/visual_script/visual_script_editor.cpp b/modules/visual_script/visual_script_editor.cpp index b23374bfb1..c74d6f9a4a 100644 --- a/modules/visual_script/visual_script_editor.cpp +++ b/modules/visual_script/visual_script_editor.cpp @@ -1676,6 +1676,128 @@ String VisualScriptEditor::_validate_name(const String &p_name) const { return valid; } +void VisualScriptEditor::_on_nodes_copy() { + clipboard->nodes.clear(); + clipboard->data_connections.clear(); + clipboard->sequence_connections.clear(); + + for (int i = 0; i < graph->get_child_count(); i++) { + GraphNode *gn = Object::cast_to<GraphNode>(graph->get_child(i)); + if (gn) { + if (gn->is_selected()) { + int id = gn->get_name().operator String().to_int(); + Ref<VisualScriptNode> node = script->get_node(id); + if (Object::cast_to<VisualScriptFunction>(*node)) { + EditorNode::get_singleton()->show_warning(TTR("Can't copy the function node.")); + return; + } + if (node.is_valid()) { + clipboard->nodes[id] = node->duplicate(true); + clipboard->nodes_positions[id] = script->get_node_position(id); + } + } + } + } + + if (clipboard->nodes.is_empty()) { + return; + } + + List<VisualScript::SequenceConnection> sequence_connections; + script->get_sequence_connection_list(&sequence_connections); + + for (const VisualScript::SequenceConnection &E : sequence_connections) { + if (clipboard->nodes.has(E.from_node) && clipboard->nodes.has(E.to_node)) { + clipboard->sequence_connections.insert(E); + } + } + + List<VisualScript::DataConnection> data_connections; + script->get_data_connection_list(&data_connections); + + for (const VisualScript::DataConnection &E : data_connections) { + if (clipboard->nodes.has(E.from_node) && clipboard->nodes.has(E.to_node)) { + clipboard->data_connections.insert(E); + } + } +} + +void VisualScriptEditor::_on_nodes_paste() { + if (clipboard->nodes.is_empty()) { + EditorNode::get_singleton()->show_warning(TTR("Clipboard is empty!")); + return; + } + + Map<int, int> remap; + + undo_redo->create_action(TTR("Paste VisualScript Nodes")); + int idc = script->get_available_id() + 1; + + Set<int> to_select; + + Set<Vector2> existing_positions; + + { + List<int> nodes; + script->get_node_list(&nodes); + for (int &E : nodes) { + Vector2 pos = script->get_node_position(E).snapped(Vector2(2, 2)); + existing_positions.insert(pos); + } + } + + bool first_paste = true; + Vector2 position_offset = Vector2(0, 0); + + for (KeyValue<int, Ref<VisualScriptNode>> &E : clipboard->nodes) { + Ref<VisualScriptNode> node = E.value->duplicate(); + + int new_id = idc++; + to_select.insert(new_id); + + remap[E.key] = new_id; + + Vector2 paste_pos = clipboard->nodes_positions[E.key]; + + if (first_paste) { + position_offset = _get_pos_in_graph(mouse_up_position - graph->get_global_position()) - paste_pos; + first_paste = false; + } + + paste_pos += position_offset; + + while (existing_positions.has(paste_pos.snapped(Vector2(2, 2)))) { + paste_pos += Vector2(20, 20) * EDSCALE; + } + + undo_redo->add_do_method(script.ptr(), "add_node", new_id, node, paste_pos); + undo_redo->add_undo_method(script.ptr(), "remove_node", new_id); + } + + for (Set<VisualScript::SequenceConnection>::Element *E = clipboard->sequence_connections.front(); E; E = E->next()) { + undo_redo->add_do_method(script.ptr(), "sequence_connect", remap[E->get().from_node], E->get().from_output, remap[E->get().to_node]); + undo_redo->add_undo_method(script.ptr(), "sequence_disconnect", remap[E->get().from_node], E->get().from_output, remap[E->get().to_node]); + } + + for (Set<VisualScript::DataConnection>::Element *E = clipboard->data_connections.front(); E; E = E->next()) { + undo_redo->add_do_method(script.ptr(), "data_connect", remap[E->get().from_node], E->get().from_port, remap[E->get().to_node], E->get().to_port); + undo_redo->add_undo_method(script.ptr(), "data_disconnect", remap[E->get().from_node], E->get().from_port, remap[E->get().to_node], E->get().to_port); + } + + undo_redo->add_do_method(this, "_update_graph"); + undo_redo->add_undo_method(this, "_update_graph"); + + undo_redo->commit_action(); + + for (int i = 0; i < graph->get_child_count(); i++) { + GraphNode *gn = Object::cast_to<GraphNode>(graph->get_child(i)); + if (gn) { + int id = gn->get_name().operator String().to_int(); + gn->set_selected(to_select.has(id)); + } + } +} + void VisualScriptEditor::_on_nodes_delete() { // Delete all the selected nodes. @@ -2073,20 +2195,20 @@ void VisualScriptEditor::drop_data_fw(const Point2 &p_point, const Variant &p_da Ref<VisualScriptNode> vnode; if (use_set) { - Ref<VisualScriptVariableSet> vnodes; - vnodes.instantiate(); - vnodes->set_variable(d["variable"]); - vnode = vnodes; + Ref<VisualScriptPropertySet> pset; + pset.instantiate(); + vnode = pset; } else { - Ref<VisualScriptVariableGet> vnodeg; - vnodeg.instantiate(); - vnodeg->set_variable(d["variable"]); - vnode = vnodeg; + Ref<VisualScriptPropertyGet> pget; + pget.instantiate(); + vnode = pget; } int new_id = script->get_available_id(); - undo_redo->create_action(TTR("Add Node")); + undo_redo->add_do_method(vnode.ptr(), "set_property", d["variable"]); + undo_redo->add_do_method(vnode.ptr(), "set_base_script", script->get_path()); + undo_redo->add_do_method(script.ptr(), "add_node", new_id, vnode, pos); undo_redo->add_undo_method(script.ptr(), "remove_node", new_id); undo_redo->add_do_method(this, "_update_graph"); @@ -2329,12 +2451,14 @@ void VisualScriptEditor::drop_data_fw(const Point2 &p_point, const Variant &p_da pget.instantiate(); pget->set_call_mode(VisualScriptPropertyGet::CALL_MODE_INSTANCE); pget->set_base_type(obj->get_class()); - vnode = pget; } undo_redo->add_do_method(script.ptr(), "add_node", base_id, vnode, pos); undo_redo->add_do_method(vnode.ptr(), "set_property", d["property"]); + if (!obj->get_script().is_null()) { + undo_redo->add_do_method(vnode.ptr(), "set_base_script", Ref<Script>(obj->get_script())->get_path()); + } if (!use_get) { undo_redo->add_do_method(vnode.ptr(), "set_default_input_value", 0, d["value"]); } @@ -2365,7 +2489,6 @@ void VisualScriptEditor::drop_data_fw(const Point2 &p_point, const Variant &p_da pset->set_call_mode(VisualScriptPropertySet::CALL_MODE_NODE_PATH); pset->set_base_path(sn->get_path_to(node)); } - vnode = pset; } else { Ref<VisualScriptPropertyGet> pget; @@ -2380,9 +2503,13 @@ void VisualScriptEditor::drop_data_fw(const Point2 &p_point, const Variant &p_da } undo_redo->add_do_method(script.ptr(), "add_node", base_id, vnode, pos); undo_redo->add_do_method(vnode.ptr(), "set_property", d["property"]); + if (!obj->get_script().is_null()) { + undo_redo->add_do_method(vnode.ptr(), "set_base_script", Ref<Script>(obj->get_script())->get_path()); + } if (!use_get) { undo_redo->add_do_method(vnode.ptr(), "set_default_input_value", 0, d["value"]); } + undo_redo->add_undo_method(script.ptr(), "remove_node", base_id); undo_redo->add_do_method(this, "_update_graph"); @@ -2460,18 +2587,21 @@ void VisualScriptEditor::reload_text() { String VisualScriptEditor::get_name() { String name; - if (script->get_path().find("local://") == -1 && script->get_path().find("::") == -1) { - name = script->get_path().get_file(); - if (is_unsaved()) { - if (script->get_path().is_empty()) { - name = TTR("[unsaved]"); - } - name += "(*)"; + name = script->get_path().get_file(); + if (name.is_empty()) { + // This appears for newly created built-in scripts before saving the scene. + name = TTR("[unsaved]"); + } else if (script->is_built_in()) { + const String &script_name = script->get_name(); + if (script_name != "") { + // If the built-in script has a custom resource name defined, + // display the built-in script name as follows: `ResourceName (scene_file.tscn)` + name = vformat("%s (%s)", script_name, name.get_slice("::", 0)); } - } else if (script->get_name() != "") { - name = script->get_name(); - } else { - name = script->get_class() + "(" + itos(script->get_instance_id()) + ")"; + } + + if (is_unsaved()) { + name += "(*)"; } return name; @@ -3739,120 +3869,15 @@ void VisualScriptEditor::_menu_option(int p_what) { case EDIT_FIND_NODE_TYPE: { _generic_search(script->get_instance_base_type()); } break; - case EDIT_COPY_NODES: + case EDIT_COPY_NODES: { + _on_nodes_copy(); + } break; case EDIT_CUT_NODES: { - clipboard->nodes.clear(); - clipboard->data_connections.clear(); - clipboard->sequence_connections.clear(); - - for (int i = 0; i < graph->get_child_count(); i++) { - GraphNode *gn = Object::cast_to<GraphNode>(graph->get_child(i)); - if (gn) { - if (gn->is_selected()) { - int id = gn->get_name().operator String().to_int(); - Ref<VisualScriptNode> node = script->get_node(id); - if (Object::cast_to<VisualScriptFunction>(*node)) { - EditorNode::get_singleton()->show_warning(TTR("Can't copy the function node.")); - return; - } - if (node.is_valid()) { - clipboard->nodes[id] = node->duplicate(true); - clipboard->nodes_positions[id] = script->get_node_position(id); - } - } - } - } - - if (clipboard->nodes.is_empty()) { - break; - } - - List<VisualScript::SequenceConnection> sequence_connections; - script->get_sequence_connection_list(&sequence_connections); - - for (const VisualScript::SequenceConnection &E : sequence_connections) { - if (clipboard->nodes.has(E.from_node) && clipboard->nodes.has(E.to_node)) { - clipboard->sequence_connections.insert(E); - } - } - - List<VisualScript::DataConnection> data_connections; - script->get_data_connection_list(&data_connections); - - for (const VisualScript::DataConnection &E : data_connections) { - if (clipboard->nodes.has(E.from_node) && clipboard->nodes.has(E.to_node)) { - clipboard->data_connections.insert(E); - } - } - if (p_what == EDIT_CUT_NODES) { - _on_nodes_delete(); // oh yeah, also delete on cut - } - + _on_nodes_copy(); + _on_nodes_delete(); } break; case EDIT_PASTE_NODES: { - if (clipboard->nodes.is_empty()) { - EditorNode::get_singleton()->show_warning(TTR("Clipboard is empty!")); - break; - } - - Map<int, int> remap; - - undo_redo->create_action(TTR("Paste VisualScript Nodes")); - int idc = script->get_available_id() + 1; - - Set<int> to_select; - - Set<Vector2> existing_positions; - - { - List<int> nodes; - script->get_node_list(&nodes); - for (int &E : nodes) { - Vector2 pos = script->get_node_position(E).snapped(Vector2(2, 2)); - existing_positions.insert(pos); - } - } - - for (KeyValue<int, Ref<VisualScriptNode>> &E : clipboard->nodes) { - Ref<VisualScriptNode> node = E.value->duplicate(); - - int new_id = idc++; - to_select.insert(new_id); - - remap[E.key] = new_id; - - Vector2 paste_pos = clipboard->nodes_positions[E.key]; - - while (existing_positions.has(paste_pos.snapped(Vector2(2, 2)))) { - paste_pos += Vector2(20, 20) * EDSCALE; - } - - undo_redo->add_do_method(script.ptr(), "add_node", new_id, node, paste_pos); - undo_redo->add_undo_method(script.ptr(), "remove_node", new_id); - } - - for (Set<VisualScript::SequenceConnection>::Element *E = clipboard->sequence_connections.front(); E; E = E->next()) { - undo_redo->add_do_method(script.ptr(), "sequence_connect", remap[E->get().from_node], E->get().from_output, remap[E->get().to_node]); - undo_redo->add_undo_method(script.ptr(), "sequence_disconnect", remap[E->get().from_node], E->get().from_output, remap[E->get().to_node]); - } - - for (Set<VisualScript::DataConnection>::Element *E = clipboard->data_connections.front(); E; E = E->next()) { - undo_redo->add_do_method(script.ptr(), "data_connect", remap[E->get().from_node], E->get().from_port, remap[E->get().to_node], E->get().to_port); - undo_redo->add_undo_method(script.ptr(), "data_disconnect", remap[E->get().from_node], E->get().from_port, remap[E->get().to_node], E->get().to_port); - } - - undo_redo->add_do_method(this, "_update_graph"); - undo_redo->add_undo_method(this, "_update_graph"); - - undo_redo->commit_action(); - - for (int i = 0; i < graph->get_child_count(); i++) { - GraphNode *gn = Object::cast_to<GraphNode>(graph->get_child(i)); - if (gn) { - int id = gn->get_name().operator String().to_int(); - gn->set_selected(to_select.has(id)); - } - } + _on_nodes_paste(); } break; case EDIT_CREATE_FUNCTION: { // Create Function. @@ -4334,6 +4359,8 @@ VisualScriptEditor::VisualScriptEditor() { graph->connect("node_selected", callable_mp(this, &VisualScriptEditor::_node_selected)); graph->connect("begin_node_move", callable_mp(this, &VisualScriptEditor::_begin_node_move)); graph->connect("end_node_move", callable_mp(this, &VisualScriptEditor::_end_node_move)); + graph->connect("copy_nodes_request", callable_mp(this, &VisualScriptEditor::_on_nodes_copy)); + graph->connect("paste_nodes_request", callable_mp(this, &VisualScriptEditor::_on_nodes_paste)); graph->connect("delete_nodes_request", callable_mp(this, &VisualScriptEditor::_on_nodes_delete)); graph->connect("duplicate_nodes_request", callable_mp(this, &VisualScriptEditor::_on_nodes_duplicate)); graph->connect("gui_input", callable_mp(this, &VisualScriptEditor::_graph_gui_input)); diff --git a/modules/visual_script/visual_script_editor.h b/modules/visual_script/visual_script_editor.h index 19f5aabac9..9467c2dea4 100644 --- a/modules/visual_script/visual_script_editor.h +++ b/modules/visual_script/visual_script_editor.h @@ -253,6 +253,8 @@ class VisualScriptEditor : public ScriptEditorBase { void _node_item_selected(); void _node_item_unselected(); + void _on_nodes_copy(); + void _on_nodes_paste(); void _on_nodes_delete(); void _on_nodes_duplicate(); diff --git a/modules/visual_script/visual_script_expression.cpp b/modules/visual_script/visual_script_expression.cpp index 99b7275008..55c707890f 100644 --- a/modules/visual_script/visual_script_expression.cpp +++ b/modules/visual_script/visual_script_expression.cpp @@ -136,7 +136,7 @@ void VisualScriptExpression::_get_property_list(List<PropertyInfo> *p_list) cons argt += "," + Variant::get_type_name(Variant::Type(i)); } - p_list->push_back(PropertyInfo(Variant::STRING, "expression", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR)); + p_list->push_back(PropertyInfo(Variant::STRING, "expression", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR)); p_list->push_back(PropertyInfo(Variant::INT, "out_type", PROPERTY_HINT_ENUM, argt)); p_list->push_back(PropertyInfo(Variant::INT, "input_count", PROPERTY_HINT_RANGE, "0,64,1")); p_list->push_back(PropertyInfo(Variant::BOOL, "sequenced")); diff --git a/modules/visual_script/visual_script_func_nodes.cpp b/modules/visual_script/visual_script_func_nodes.cpp index 205918a5f0..a2ad38bf01 100644 --- a/modules/visual_script/visual_script_func_nodes.cpp +++ b/modules/visual_script/visual_script_func_nodes.cpp @@ -514,7 +514,7 @@ Dictionary VisualScriptFunctionCall::_get_argument_cache() const { void VisualScriptFunctionCall::_validate_property(PropertyInfo &property) const { if (property.name == "base_type") { if (call_mode != CALL_MODE_INSTANCE) { - property.usage = PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL; + property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL; } } @@ -696,7 +696,7 @@ void VisualScriptFunctionCall::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::STRING, "singleton"), "set_singleton", "get_singleton"); ADD_PROPERTY(PropertyInfo(Variant::INT, "basic_type", PROPERTY_HINT_ENUM, bt), "set_basic_type", "get_basic_type"); ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "node_path", PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE), "set_base_path", "get_base_path"); - ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "argument_cache", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_argument_cache", "_get_argument_cache"); + ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "argument_cache", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_argument_cache", "_get_argument_cache"); ADD_PROPERTY(PropertyInfo(Variant::STRING, "function"), "set_function", "get_function"); //when set, if loaded properly, will override argument count. ADD_PROPERTY(PropertyInfo(Variant::INT, "use_default_args"), "set_use_default_args", "get_use_default_args"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "validate"), "set_validate", "get_validate"); @@ -1282,7 +1282,7 @@ VisualScriptPropertySet::AssignOp VisualScriptPropertySet::get_assign_op() const void VisualScriptPropertySet::_validate_property(PropertyInfo &property) const { if (property.name == "base_type") { if (call_mode != CALL_MODE_INSTANCE) { - property.usage = PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL; + property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL; } } @@ -1420,7 +1420,7 @@ void VisualScriptPropertySet::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "set_mode", PROPERTY_HINT_ENUM, "Self,Node Path,Instance,Basic Type"), "set_call_mode", "get_call_mode"); ADD_PROPERTY(PropertyInfo(Variant::STRING, "base_type", PROPERTY_HINT_TYPE_STRING, "Object"), "set_base_type", "get_base_type"); ADD_PROPERTY(PropertyInfo(Variant::STRING, "base_script", PROPERTY_HINT_FILE, script_ext_hint), "set_base_script", "get_base_script"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "type_cache", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_type_cache", "_get_type_cache"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "type_cache", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_type_cache", "_get_type_cache"); ADD_PROPERTY(PropertyInfo(Variant::INT, "basic_type", PROPERTY_HINT_ENUM, bt), "set_basic_type", "get_basic_type"); ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "node_path", PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE), "set_base_path", "get_base_path"); ADD_PROPERTY(PropertyInfo(Variant::STRING, "property"), "set_property", "get_property"); @@ -1988,7 +1988,7 @@ StringName VisualScriptPropertyGet::get_index() const { void VisualScriptPropertyGet::_validate_property(PropertyInfo &property) const { if (property.name == "base_type") { if (call_mode != CALL_MODE_INSTANCE) { - property.usage = PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL; + property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL; } } @@ -2122,7 +2122,7 @@ void VisualScriptPropertyGet::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "set_mode", PROPERTY_HINT_ENUM, "Self,Node Path,Instance,Basic Type"), "set_call_mode", "get_call_mode"); ADD_PROPERTY(PropertyInfo(Variant::STRING, "base_type", PROPERTY_HINT_TYPE_STRING, "Object"), "set_base_type", "get_base_type"); ADD_PROPERTY(PropertyInfo(Variant::STRING, "base_script", PROPERTY_HINT_FILE, script_ext_hint), "set_base_script", "get_base_script"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "type_cache", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_type_cache", "_get_type_cache"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "type_cache", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_type_cache", "_get_type_cache"); ADD_PROPERTY(PropertyInfo(Variant::INT, "basic_type", PROPERTY_HINT_ENUM, bt), "set_basic_type", "get_basic_type"); ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "node_path", PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE), "set_base_path", "get_base_path"); ADD_PROPERTY(PropertyInfo(Variant::STRING, "property"), "set_property", "get_property"); diff --git a/modules/visual_script/visual_script_nodes.cpp b/modules/visual_script/visual_script_nodes.cpp index ef77c0cef3..471d8ef0ae 100644 --- a/modules/visual_script/visual_script_nodes.cpp +++ b/modules/visual_script/visual_script_nodes.cpp @@ -3415,8 +3415,8 @@ void VisualScriptConstructor::_bind_methods() { ClassDB::bind_method(D_METHOD("set_constructor", "constructor"), &VisualScriptConstructor::set_constructor); ClassDB::bind_method(D_METHOD("get_constructor"), &VisualScriptConstructor::get_constructor); - ADD_PROPERTY(PropertyInfo(Variant::INT, "type", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "set_constructor_type", "get_constructor_type"); - ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "constructor", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "set_constructor", "get_constructor"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "type", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "set_constructor_type", "get_constructor_type"); + ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "constructor", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "set_constructor", "get_constructor"); } VisualScriptConstructor::VisualScriptConstructor() { @@ -3958,7 +3958,7 @@ void VisualScriptDeconstruct::_bind_methods() { } ADD_PROPERTY(PropertyInfo(Variant::INT, "type", PROPERTY_HINT_ENUM, argt), "set_deconstruct_type", "get_deconstruct_type"); - ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "elem_cache", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_elem_cache", "_get_elem_cache"); + ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "elem_cache", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_elem_cache", "_get_elem_cache"); } VisualScriptDeconstruct::VisualScriptDeconstruct() { diff --git a/modules/visual_script/visual_script_yield_nodes.cpp b/modules/visual_script/visual_script_yield_nodes.cpp index c62de64a85..4b89c9ccd0 100644 --- a/modules/visual_script/visual_script_yield_nodes.cpp +++ b/modules/visual_script/visual_script_yield_nodes.cpp @@ -186,7 +186,7 @@ void VisualScriptYield::_bind_methods() { ClassDB::bind_method(D_METHOD("set_wait_time", "sec"), &VisualScriptYield::set_wait_time); ClassDB::bind_method(D_METHOD("get_wait_time"), &VisualScriptYield::get_wait_time); - ADD_PROPERTY(PropertyInfo(Variant::INT, "mode", PROPERTY_HINT_ENUM, "Frame,Physics Frame,Time", PROPERTY_USAGE_NOEDITOR), "set_yield_mode", "get_yield_mode"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "mode", PROPERTY_HINT_ENUM, "Frame,Physics Frame,Time", PROPERTY_USAGE_NO_EDITOR), "set_yield_mode", "get_yield_mode"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "wait_time"), "set_wait_time", "get_wait_time"); BIND_ENUM_CONSTANT(YIELD_FRAME); @@ -415,7 +415,7 @@ VisualScriptYieldSignal::CallMode VisualScriptYieldSignal::get_call_mode() const void VisualScriptYieldSignal::_validate_property(PropertyInfo &property) const { if (property.name == "base_type") { if (call_mode != CALL_MODE_INSTANCE) { - property.usage = PROPERTY_USAGE_NOEDITOR; + property.usage = PROPERTY_USAGE_NO_EDITOR; } } diff --git a/modules/vorbis/audio_stream_ogg_vorbis.cpp b/modules/vorbis/audio_stream_ogg_vorbis.cpp index e4a80c339f..d913c115d9 100644 --- a/modules/vorbis/audio_stream_ogg_vorbis.cpp +++ b/modules/vorbis/audio_stream_ogg_vorbis.cpp @@ -425,7 +425,7 @@ void AudioStreamOGGVorbis::_bind_methods() { ClassDB::bind_method(D_METHOD("set_loop_offset", "seconds"), &AudioStreamOGGVorbis::set_loop_offset); ClassDB::bind_method(D_METHOD("get_loop_offset"), &AudioStreamOGGVorbis::get_loop_offset); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "packet_sequence", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_packet_sequence", "get_packet_sequence"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "packet_sequence", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_packet_sequence", "get_packet_sequence"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "loop"), "set_loop", "has_loop"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "loop_offset"), "set_loop_offset", "get_loop_offset"); } diff --git a/modules/websocket/emws_peer.cpp b/modules/websocket/emws_peer.cpp index d7263dcf43..035d036b90 100644 --- a/modules/websocket/emws_peer.cpp +++ b/modules/websocket/emws_peer.cpp @@ -54,11 +54,14 @@ Error EMWSPeer::read_msg(const uint8_t *p_data, uint32_t p_size, bool p_is_strin } Error EMWSPeer::put_packet(const uint8_t *p_buffer, int p_buffer_size) { - ERR_FAIL_COND_V(_out_buf_size && ((uint64_t)godot_js_websocket_buffered_amount(peer_sock) >= (1ULL << _out_buf_size)), ERR_OUT_OF_MEMORY); + ERR_FAIL_COND_V(_out_buf_size && ((uint64_t)godot_js_websocket_buffered_amount(peer_sock) + p_buffer_size >= (1ULL << _out_buf_size)), ERR_OUT_OF_MEMORY); int is_bin = write_mode == WebSocketPeer::WRITE_MODE_BINARY ? 1 : 0; - godot_js_websocket_send(peer_sock, p_buffer, p_buffer_size, is_bin); + if (godot_js_websocket_send(peer_sock, p_buffer, p_buffer_size, is_bin) != 0) { + return FAILED; + } + return OK; } diff --git a/modules/websocket/wsl_peer.cpp b/modules/websocket/wsl_peer.cpp index 7f027e1c0d..fc520ec57c 100644 --- a/modules/websocket/wsl_peer.cpp +++ b/modules/websocket/wsl_peer.cpp @@ -242,15 +242,15 @@ void WSLPeer::poll() { Error WSLPeer::put_packet(const uint8_t *p_buffer, int p_buffer_size) { ERR_FAIL_COND_V(!is_connected_to_host(), FAILED); ERR_FAIL_COND_V(_out_pkt_size && (wslay_event_get_queued_msg_count(_data->ctx) >= (1ULL << _out_pkt_size)), ERR_OUT_OF_MEMORY); - ERR_FAIL_COND_V(_out_buf_size && (wslay_event_get_queued_msg_length(_data->ctx) >= (1ULL << _out_buf_size)), ERR_OUT_OF_MEMORY); + ERR_FAIL_COND_V(_out_buf_size && (wslay_event_get_queued_msg_length(_data->ctx) + p_buffer_size >= (1ULL << _out_buf_size)), ERR_OUT_OF_MEMORY); - struct wslay_event_msg msg; // Should I use fragmented? + struct wslay_event_msg msg; msg.opcode = write_mode == WRITE_MODE_TEXT ? WSLAY_TEXT_FRAME : WSLAY_BINARY_FRAME; msg.msg = p_buffer; msg.msg_length = p_buffer_size; - wslay_event_queue_msg(_data->ctx, &msg); - if (wslay_event_send(_data->ctx) < 0) { + // Queue & send message. + if (wslay_event_queue_msg(_data->ctx, &msg) != 0 || wslay_event_send(_data->ctx) != 0) { close_now(); return FAILED; } |