diff --git a/core/bind/core_bind.cpp b/core/bind/core_bind.cpp index 3443496ba9f..514a22fa6bc 100644 --- a/core/bind/core_bind.cpp +++ b/core/bind/core_bind.cpp @@ -798,6 +798,8 @@ Dictionary _OS::get_time(bool utc) const { * @return epoch calculated */ int64_t _OS::get_unix_time_from_datetime(Dictionary datetime) const { + // if datetime is an empty Dictionary throws an error + ERR_FAIL_COND_V_MSG(datetime.empty(), 0, "Invalid datetime Dictionary: Dictionary is empty"); // Bunch of conversion constants static const unsigned int SECONDS_PER_MINUTE = 60; diff --git a/core/os/thread.cpp b/core/os/thread.cpp index ca1752ffb03..1f260c08e34 100644 --- a/core/os/thread.cpp +++ b/core/os/thread.cpp @@ -47,7 +47,7 @@ uint64_t Thread::_thread_id_hash(const std::thread::id &p_t) { } Thread::ID Thread::main_thread_id = _thread_id_hash(std::this_thread::get_id()); -thread_local Thread::ID Thread::caller_id = _thread_id_hash(std::this_thread::get_id()); +thread_local Thread::ID Thread::caller_id = 0; void Thread::_set_platform_funcs( Error (*p_set_name_func)(const String &), @@ -112,6 +112,10 @@ Error Thread::set_name(const String &p_name) { return ERR_UNAVAILABLE; } +Thread::Thread() { + caller_id = _thread_id_hash(std::this_thread::get_id()); +} + Thread::~Thread() { if (id != _thread_id_hash(std::thread::id())) { #ifdef DEBUG_ENABLED diff --git a/core/os/thread.h b/core/os/thread.h index 3c617648259..527c86c0221 100644 --- a/core/os/thread.h +++ b/core/os/thread.h @@ -98,6 +98,7 @@ public: ///< waits until thread is finished, and deallocates it. void wait_to_finish(); + Thread(); ~Thread(); #else _FORCE_INLINE_ ID get_id() const { return 0; } diff --git a/doc/classes/OS.xml b/doc/classes/OS.xml index 2278835f381..053a49acd40 100644 --- a/doc/classes/OS.xml +++ b/doc/classes/OS.xml @@ -549,6 +549,7 @@ Gets an epoch time value from a dictionary of time values. [code]datetime[/code] must be populated with the following keys: [code]year[/code], [code]month[/code], [code]day[/code], [code]hour[/code], [code]minute[/code], [code]second[/code]. + If the dictionary is empty [code]0[/code] is returned. You can pass the output from [method get_datetime_from_unix_time] directly into this function. Daylight Savings Time ([code]dst[/code]), if present, is ignored. diff --git a/doc/classes/Physics2DServer.xml b/doc/classes/Physics2DServer.xml index ed9729105f3..bac71c46dae 100644 --- a/doc/classes/Physics2DServer.xml +++ b/doc/classes/Physics2DServer.xml @@ -58,7 +58,7 @@ - Creates an [Area2D]. + Creates an [Area2D]. After creating an [Area2D] with this method, assign it to a space using [method area_set_space] to use the created [Area2D] in the physics world. diff --git a/editor/editor_export.cpp b/editor/editor_export.cpp index 200b1055d1d..be633849291 100644 --- a/editor/editor_export.cpp +++ b/editor/editor_export.cpp @@ -299,6 +299,7 @@ void EditorExportPlatform::gen_debug_flags(Vector &r_flags, int p_flags) } Error EditorExportPlatform::_save_pack_file(void *p_userdata, const String &p_path, const Vector &p_data, int p_file, int p_total) { + ERR_FAIL_COND_V_MSG(p_total < 1, ERR_PARAMETER_RANGE_ERROR, "Must select at least one file to export."); PackData *pd = (PackData *)p_userdata; @@ -332,6 +333,7 @@ Error EditorExportPlatform::_save_pack_file(void *p_userdata, const String &p_pa } Error EditorExportPlatform::_save_zip_file(void *p_userdata, const String &p_path, const Vector &p_data, int p_file, int p_total) { + ERR_FAIL_COND_V_MSG(p_total < 1, ERR_PARAMETER_RANGE_ERROR, "Must select at least one file to export."); String path = p_path.replace_first("res://", ""); @@ -740,18 +742,26 @@ Error EditorExportPlatform::export_project_files(const Ref & // Ignore import files, since these are automatically added to the jar later with the resources _edit_filter_list(paths, String("*.import"), true); + Error err = OK; Vector > export_plugins = EditorExport::get_singleton()->get_export_plugins(); + for (int i = 0; i < export_plugins.size(); i++) { export_plugins.write[i]->set_export_preset(p_preset); if (p_so_func) { for (int j = 0; j < export_plugins[i]->shared_objects.size(); j++) { - p_so_func(p_udata, export_plugins[i]->shared_objects[j]); + err = p_so_func(p_udata, export_plugins[i]->shared_objects[j]); + if (err != OK) { + return err; + } } } for (int j = 0; j < export_plugins[i]->extra_files.size(); j++) { - p_func(p_udata, export_plugins[i]->extra_files[j].path, export_plugins[i]->extra_files[j].data, 0, paths.size()); + err = p_func(p_udata, export_plugins[i]->extra_files[j].path, export_plugins[i]->extra_files[j].data, 0, paths.size()); + if (err != OK) { + return err; + } } export_plugins.write[i]->_clear(); @@ -774,7 +784,7 @@ Error EditorExportPlatform::export_project_files(const Ref & //file is imported, replace by what it imports Ref config; config.instance(); - Error err = config->load(path + ".import"); + err = config->load(path + ".import"); if (err != OK) { ERR_PRINTS("Could not parse: '" + path + "', not exported."); continue; @@ -841,12 +851,18 @@ Error EditorExportPlatform::export_project_files(const Ref & } if (p_so_func) { for (int j = 0; j < export_plugins[i]->shared_objects.size(); j++) { - p_so_func(p_udata, export_plugins[i]->shared_objects[j]); + err = p_so_func(p_udata, export_plugins[i]->shared_objects[j]); + if (err != OK) { + return err; + } } } for (int j = 0; j < export_plugins[i]->extra_files.size(); j++) { - p_func(p_udata, export_plugins[i]->extra_files[j].path, export_plugins[i]->extra_files[j].data, idx, total); + err = p_func(p_udata, export_plugins[i]->extra_files[j].path, export_plugins[i]->extra_files[j].data, idx, total); + if (err != OK) { + return err; + } if (export_plugins[i]->extra_files[j].remap) { do_export = false; //if remap, do not path_remaps.push_back(path); @@ -865,7 +881,10 @@ Error EditorExportPlatform::export_project_files(const Ref & //just store it as it comes if (do_export) { Vector array = FileAccess::get_file_as_array(path); - p_func(p_udata, path, array, idx, total); + err = p_func(p_udata, path, array, idx, total); + if (err != OK) { + return err; + } } } @@ -902,7 +921,10 @@ Error EditorExportPlatform::export_project_files(const Ref & new_file.write[j] = utf8[j]; } - p_func(p_udata, from + ".remap", new_file, idx, total); + err = p_func(p_udata, from + ".remap", new_file, idx, total); + if (err != OK) { + return err; + } } } else { //old remap mode, will still work, but it's unused because it's not multiple pck export friendly @@ -915,11 +937,17 @@ Error EditorExportPlatform::export_project_files(const Ref & String splash = ProjectSettings::get_singleton()->get("application/boot_splash/image"); if (icon != String() && FileAccess::exists(icon)) { Vector array = FileAccess::get_file_as_array(icon); - p_func(p_udata, icon, array, idx, total); + err = p_func(p_udata, icon, array, idx, total); + if (err != OK) { + return err; + } } if (splash != String() && FileAccess::exists(splash) && icon != splash) { Vector array = FileAccess::get_file_as_array(splash); - p_func(p_udata, splash, array, idx, total); + err = p_func(p_udata, splash, array, idx, total); + if (err != OK) { + return err; + } } String config_file = "project.binary"; @@ -928,9 +956,7 @@ Error EditorExportPlatform::export_project_files(const Ref & Vector data = FileAccess::get_file_as_array(engine_cfb); DirAccess::remove_file_or_error(engine_cfb); - p_func(p_udata, "res://" + config_file, data, idx, total); - - return OK; + return p_func(p_udata, "res://" + config_file, data, idx, total); } Error EditorExportPlatform::_add_shared_object(void *p_userdata, const SharedObject &p_so) { @@ -965,6 +991,7 @@ Error EditorExportPlatform::save_pack(const Ref &p_preset, c if (err != OK) { DirAccess::remove_file_or_error(tmppath); + ERR_PRINT("Failed to export project files"); return err; } diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp index f55e3fc2fcd..c06fbe7ad3f 100644 --- a/editor/plugins/canvas_item_editor_plugin.cpp +++ b/editor/plugins/canvas_item_editor_plugin.cpp @@ -924,9 +924,11 @@ void CanvasItemEditor::_restore_canvas_item_state(List p_canvas_it for (List::Element *E = drag_selection.front(); E; E = E->next()) { CanvasItem *canvas_item = E->get(); CanvasItemEditorSelectedItem *se = editor_selection->get_node_editor_data(canvas_item); - canvas_item->_edit_set_state(se->undo_state); - if (restore_bones) { - _restore_canvas_item_ik_chain(canvas_item, &(se->pre_drag_bones_undo_state)); + if (se) { + canvas_item->_edit_set_state(se->undo_state); + if (restore_bones) { + _restore_canvas_item_ik_chain(canvas_item, &(se->pre_drag_bones_undo_state)); + } } } } @@ -951,13 +953,15 @@ void CanvasItemEditor::_commit_canvas_item_state(List p_canvas_ite for (List::Element *E = modified_canvas_items.front(); E; E = E->next()) { CanvasItem *canvas_item = E->get(); CanvasItemEditorSelectedItem *se = editor_selection->get_node_editor_data(canvas_item); - undo_redo->add_do_method(canvas_item, "_edit_set_state", canvas_item->_edit_get_state()); - undo_redo->add_undo_method(canvas_item, "_edit_set_state", se->undo_state); - if (commit_bones) { - for (List::Element *F = se->pre_drag_bones_undo_state.front(); F; F = F->next()) { - canvas_item = Object::cast_to(canvas_item->get_parent()); - undo_redo->add_do_method(canvas_item, "_edit_set_state", canvas_item->_edit_get_state()); - undo_redo->add_undo_method(canvas_item, "_edit_set_state", F->get()); + if (se) { + undo_redo->add_do_method(canvas_item, "_edit_set_state", canvas_item->_edit_get_state()); + undo_redo->add_undo_method(canvas_item, "_edit_set_state", se->undo_state); + if (commit_bones) { + for (List::Element *F = se->pre_drag_bones_undo_state.front(); F; F = F->next()) { + canvas_item = Object::cast_to(canvas_item->get_parent()); + undo_redo->add_do_method(canvas_item, "_edit_set_state", canvas_item->_edit_get_state()); + undo_redo->add_undo_method(canvas_item, "_edit_set_state", F->get()); + } } } } @@ -2126,17 +2130,19 @@ bool CanvasItemEditor::_gui_input_move(const Ref &p_event) { for (List::Element *E = drag_selection.front(); E; E = E->next()) { CanvasItem *canvas_item = E->get(); CanvasItemEditorSelectedItem *se = editor_selection->get_node_editor_data(canvas_item); - Transform2D xform = canvas_item->get_global_transform_with_canvas().affine_inverse() * canvas_item->get_transform(); + if (se) { + Transform2D xform = canvas_item->get_global_transform_with_canvas().affine_inverse() * canvas_item->get_transform(); - Node2D *node2d = Object::cast_to(canvas_item); - if (node2d && se->pre_drag_bones_undo_state.size() > 0 && !force_no_IK) { - real_t initial_leaf_node_rotation = node2d->get_global_transform_with_canvas().get_rotation(); - _restore_canvas_item_ik_chain(node2d, &(all_bones_ik_states[index])); - real_t final_leaf_node_rotation = node2d->get_global_transform_with_canvas().get_rotation(); - node2d->rotate(initial_leaf_node_rotation - final_leaf_node_rotation); - _solve_IK(node2d, new_pos); - } else { - canvas_item->_edit_set_position(canvas_item->_edit_get_position() + xform.xform(new_pos) - xform.xform(previous_pos)); + Node2D *node2d = Object::cast_to(canvas_item); + if (node2d && se->pre_drag_bones_undo_state.size() > 0 && !force_no_IK) { + real_t initial_leaf_node_rotation = node2d->get_global_transform_with_canvas().get_rotation(); + _restore_canvas_item_ik_chain(node2d, &(all_bones_ik_states[index])); + real_t final_leaf_node_rotation = node2d->get_global_transform_with_canvas().get_rotation(); + node2d->rotate(initial_leaf_node_rotation - final_leaf_node_rotation); + _solve_IK(node2d, new_pos); + } else { + canvas_item->_edit_set_position(canvas_item->_edit_get_position() + xform.xform(new_pos) - xform.xform(previous_pos)); + } } index++; } @@ -2258,17 +2264,19 @@ bool CanvasItemEditor::_gui_input_move(const Ref &p_event) { for (List::Element *E = drag_selection.front(); E; E = E->next()) { CanvasItem *canvas_item = E->get(); CanvasItemEditorSelectedItem *se = editor_selection->get_node_editor_data(canvas_item); - Transform2D xform = canvas_item->get_global_transform_with_canvas().affine_inverse() * canvas_item->get_transform(); + if (se) { + Transform2D xform = canvas_item->get_global_transform_with_canvas().affine_inverse() * canvas_item->get_transform(); - Node2D *node2d = Object::cast_to(canvas_item); - if (node2d && se->pre_drag_bones_undo_state.size() > 0) { - real_t initial_leaf_node_rotation = node2d->get_global_transform_with_canvas().get_rotation(); - _restore_canvas_item_ik_chain(node2d, &(all_bones_ik_states[index])); - real_t final_leaf_node_rotation = node2d->get_global_transform_with_canvas().get_rotation(); - node2d->rotate(initial_leaf_node_rotation - final_leaf_node_rotation); - _solve_IK(node2d, new_pos); - } else { - canvas_item->_edit_set_position(canvas_item->_edit_get_position() + xform.xform(new_pos) - xform.xform(previous_pos)); + Node2D *node2d = Object::cast_to(canvas_item); + if (node2d && se->pre_drag_bones_undo_state.size() > 0) { + real_t initial_leaf_node_rotation = node2d->get_global_transform_with_canvas().get_rotation(); + _restore_canvas_item_ik_chain(node2d, &(all_bones_ik_states[index])); + real_t final_leaf_node_rotation = node2d->get_global_transform_with_canvas().get_rotation(); + node2d->rotate(initial_leaf_node_rotation - final_leaf_node_rotation); + _solve_IK(node2d, new_pos); + } else { + canvas_item->_edit_set_position(canvas_item->_edit_get_position() + xform.xform(new_pos) - xform.xform(previous_pos)); + } } index++; } diff --git a/misc/dist/html/editor.html b/misc/dist/html/editor.html index 3bf87f35065..99ac2379cef 100644 --- a/misc/dist/html/editor.html +++ b/misc/dist/html/editor.html @@ -502,7 +502,7 @@ showTab('loader'); setLoaderEnabled(true); }; - editor.start({'args': args}); + editor.start({'args': args, 'persistentDrops': is_project_manager}); }); }, 0); OnEditorExit = null; @@ -563,7 +563,7 @@ //selectVideoMode(); showTab('editor'); setLoaderEnabled(false); - editor.start({'args': ['--video-driver', video_driver]}).then(function() { + editor.start({'args': ['--project-manager', '--video-driver', video_driver], 'persistentDrops': true}).then(function() { setStatusMode('hidden'); initializing = false; }); diff --git a/modules/gdnative/include/gdnative/gdnative.h b/modules/gdnative/include/gdnative/gdnative.h index 63e2d446e77..b5316244fb5 100644 --- a/modules/gdnative/include/gdnative/gdnative.h +++ b/modules/gdnative/include/gdnative/gdnative.h @@ -53,7 +53,9 @@ extern "C" { #endif // This is for libraries *using* the header, NOT GODOT EXPOSING STUFF!! -#ifdef _WIN32 +#ifdef __GNUC__ +#define GDN_EXPORT __attribute__((visibility("default"))) +#elif defined(_WIN32) #define GDN_EXPORT __declspec(dllexport) #else #define GDN_EXPORT diff --git a/platform/javascript/js/engine/config.js b/platform/javascript/js/engine/config.js index 25d71d0905c..60727828757 100644 --- a/platform/javascript/js/engine/config.js +++ b/platform/javascript/js/engine/config.js @@ -103,6 +103,11 @@ const InternalConfig = function (initConfig) { // eslint-disable-line no-unused- * @type {Array.} */ persistentPaths: ['/userfs'], + /** + * @ignore + * @type {boolean} + */ + persistentDrops: false, /** * @ignore * @type {Array.} @@ -231,6 +236,7 @@ const InternalConfig = function (initConfig) { // eslint-disable-line no-unused- this.locale = parse('locale', this.locale); this.canvasResizePolicy = parse('canvasResizePolicy', this.canvasResizePolicy); this.persistentPaths = parse('persistentPaths', this.persistentPaths); + this.persistentDrops = parse('persistentDrops', this.persistentDrops); this.experimentalVK = parse('experimentalVK', this.experimentalVK); this.gdnativeLibs = parse('gdnativeLibs', this.gdnativeLibs); this.fileSizes = parse('fileSizes', this.fileSizes); @@ -316,6 +322,7 @@ const InternalConfig = function (initConfig) { // eslint-disable-line no-unused- 'canvas': this.canvas, 'canvasResizePolicy': this.canvasResizePolicy, 'locale': locale, + 'persistentDrops': this.persistentDrops, 'virtualKeyboard': this.experimentalVK, 'onExecute': this.onExecute, 'onExit': function (p_code) { diff --git a/platform/javascript/js/libs/library_godot_display.js b/platform/javascript/js/libs/library_godot_display.js index 781a202f89f..99aa4793d92 100644 --- a/platform/javascript/js/libs/library_godot_display.js +++ b/platform/javascript/js/libs/library_godot_display.js @@ -192,33 +192,45 @@ const GodotDisplayDragDrop = { GodotDisplayDragDrop.promises = []; GodotDisplayDragDrop.pending_files = []; callback(drops); - const dirs = [DROP.substr(0, DROP.length - 1)]; - // Remove temporary files - files.forEach(function (file) { - FS.unlink(file); - let dir = file.replace(DROP, ''); - let idx = dir.lastIndexOf('/'); - while (idx > 0) { - dir = dir.substr(0, idx); - if (dirs.indexOf(DROP + dir) === -1) { - dirs.push(DROP + dir); - } - idx = dir.lastIndexOf('/'); + if (GodotConfig.persistent_drops) { + // Delay removal at exit. + GodotOS.atexit(function (resolve, reject) { + GodotDisplayDragDrop.remove_drop(files, DROP); + resolve(); + }); + } else { + GodotDisplayDragDrop.remove_drop(files, DROP); + } + }); + }, + + remove_drop: function (files, drop_path) { + const dirs = [drop_path.substr(0, drop_path.length - 1)]; + // Remove temporary files + files.forEach(function (file) { + FS.unlink(file); + let dir = file.replace(drop_path, ''); + let idx = dir.lastIndexOf('/'); + while (idx > 0) { + dir = dir.substr(0, idx); + if (dirs.indexOf(drop_path + dir) === -1) { + dirs.push(drop_path + dir); } - }); - // Remove dirs. - dirs.sort(function (a, b) { - const al = (a.match(/\//g) || []).length; - const bl = (b.match(/\//g) || []).length; - if (al > bl) { - return -1; - } else if (al < bl) { - return 1; - } - return 0; - }).forEach(function (dir) { - FS.rmdir(dir); - }); + idx = dir.lastIndexOf('/'); + } + }); + // Remove dirs. + dirs.sort(function (a, b) { + const al = (a.match(/\//g) || []).length; + const bl = (b.match(/\//g) || []).length; + if (al > bl) { + return -1; + } else if (al < bl) { + return 1; + } + return 0; + }).forEach(function (dir) { + FS.rmdir(dir); }); }, @@ -908,6 +920,7 @@ const GodotDisplay = { canvas.style.left = 0; break; } + GodotDisplayScreen.updateSize(); if (p_fullscreen) { GodotDisplayScreen.requestFullscreen(); } diff --git a/platform/javascript/js/libs/library_godot_os.js b/platform/javascript/js/libs/library_godot_os.js index 775a822d881..1d9f889bce4 100644 --- a/platform/javascript/js/libs/library_godot_os.js +++ b/platform/javascript/js/libs/library_godot_os.js @@ -60,6 +60,7 @@ const GodotConfig = { locale: 'en', canvas_resize_policy: 2, // Adaptive virtual_keyboard: false, + persistent_drops: false, on_execute: null, on_exit: null, @@ -68,6 +69,7 @@ const GodotConfig = { GodotConfig.canvas = p_opts['canvas']; GodotConfig.locale = p_opts['locale'] || GodotConfig.locale; GodotConfig.virtual_keyboard = p_opts['virtualKeyboard']; + GodotConfig.persistent_drops = !!p_opts['persistentDrops']; GodotConfig.on_execute = p_opts['onExecute']; GodotConfig.on_exit = p_opts['onExit']; }, @@ -80,6 +82,7 @@ const GodotConfig = { GodotConfig.locale = 'en'; GodotConfig.canvas_resize_policy = 2; GodotConfig.virtual_keyboard = false; + GodotConfig.persistent_drops = false; GodotConfig.on_execute = null; GodotConfig.on_exit = null; }, diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp index 829daedd25c..5d482ad6885 100644 --- a/scene/gui/control.cpp +++ b/scene/gui/control.cpp @@ -70,7 +70,9 @@ Dictionary Control::_edit_get_state() const { } void Control::_edit_set_state(const Dictionary &p_state) { - + ERR_FAIL_COND((p_state.size() <= 0) || + !p_state.has("rotation") || !p_state.has("scale") || + !p_state.has("pivot") || !p_state.has("anchors") || !p_state.has("offsets")); Dictionary state = p_state; set_rotation(state["rotation"]);