diff options
166 files changed, 1430 insertions, 1301 deletions
diff --git a/AUTHORS.md b/AUTHORS.md index ba563eb507..43b4917382 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -52,6 +52,7 @@ name is available. Clay John (clayjohn) Dana Olson (adolson) Daniel J. Ramirez (djrm) + Daniel Rakos (aqnuep) Dharkael (lupoDharkael) Dmitry Koteroff (Krakean) DualMatrix @@ -41,6 +41,7 @@ generous deed immortalized in the next stable release of Godot Engine. Matthieu Huvé Maxim Karsten Mike King + Nathan Warden Neal Gompa (Conan Kudo) Patrick Aarstad Slobodan Milnovic @@ -49,13 +50,11 @@ generous deed immortalized in the next stable release of Godot Engine. Steve VilliHaukka Xananax - Y8.com Zashi ## Gold donors Andrei - Brandon Waite cheese65536 David Gehrig Ed Morley @@ -66,12 +65,12 @@ generous deed immortalized in the next stable release of Godot Engine. Manuele Finocchiaro Officine Pixel S.n.c. Retro Village + Ronan Zeegers Sofox Zaven Muradyan Alexander Trey Saunders Allen Schade - Andreas Schüle Asher Glick Austen McRae Brian van der Stel @@ -85,8 +84,6 @@ generous deed immortalized in the next stable release of Godot Engine. Jay Horton Jon Smith Jon Woodward - Jorge Bernal - Joshua Lesperance Justo Delgado Baudí Karl Werf Kommentgames @@ -96,11 +93,13 @@ generous deed immortalized in the next stable release of Godot Engine. Mored1984 paul gruenbacher Paul LaMotte + Péter Magyar Rob Messick Ross Esmond Ryan Badour Scott Wadden Sergey + Shawn Yu Svenne Krap Tom Langwaldt William Wold @@ -129,6 +128,7 @@ generous deed immortalized in the next stable release of Godot Engine. Robin Arys Ronnie Ashlock ScottMakesGames + Tad C Johnson Thomas Bjarnelöf Vincent Henderson Wojciech Chojnacki @@ -149,24 +149,25 @@ generous deed immortalized in the next stable release of Godot Engine. D Daniel Daniel Eichler + David White Deadly Lampshade Eric Eric Monson - Ethan Bennis Eugenio Hugo Salgüero Jáñez flesk Francisco Javier Moreno Carracedo gavlig GGGames.org Giles Montgomery - Giovanni Solimeno Guilherme Felipe de C. G. da Silva Heath Hayes Hysteria Idzard Kwadijk Jared White + Jesse Nave Jose Malheiro Joshua Flores + Joshua Lesperance Juan T Chen Juraj Móza Kasper Jeppesen @@ -174,13 +175,13 @@ generous deed immortalized in the next stable release of Godot Engine. Klavdij Voncina Leandro Voltolino Maarten Elings - Malcolm Peralty Markus Fehr Markus Wiesner Martin Eigel Marvin Matt Eunson Matthew Hillier + Max Bulai Max R.R. Collada M H Nick Nikitin @@ -219,14 +220,18 @@ generous deed immortalized in the next stable release of Godot Engine. Alice Robinson Andreas Evers Andreas Krampitz + Andreas Schüle Andrew Peart Anthony Bongiovanni Anthony Staunton Antony K. Jones Arda Erol + Artem Bashev Arthur S. Muszynski + Artistofdeath Aubrey Falconer Avencherus + B A Balázs Batári Bastian Böhm Beliar @@ -242,6 +247,7 @@ generous deed immortalized in the next stable release of Godot Engine. Boyquotes Branwyn Tylwyth Bryan Stevenson + Caleb Dumitry Carwyn Edwards Chris Brown Chris Chapin @@ -250,7 +256,6 @@ generous deed immortalized in the next stable release of Godot Engine. Christian Winter Christoffer Sundbom Christopher Schmitt - Chris Wilson Clay Heaton Cobaltum Collin Shooltz @@ -263,7 +268,9 @@ generous deed immortalized in the next stable release of Godot Engine. David Cravens David May Dimitri Stanojevic + Dominic Cooney Dominik Wetzel + DrevanTonder Duobix Edward Herbert Egon Elbre @@ -272,12 +279,12 @@ generous deed immortalized in the next stable release of Godot Engine. Emanuel Kotzayan Eric Ellingson Eric Martini - Eric McCarthy Eric Williams Evan Rose Felix Kollmann fengjiongmax Flaredown + FuDiggity G3Dev sàrl Gary Hulst Gerrit Großkopf @@ -286,9 +293,9 @@ generous deed immortalized in the next stable release of Godot Engine. Greg Olson Greg P Guldoman + Hal A Heribert Hirth Hiroshi Naruo - HMan Hunter Jones Hylpher ialex32x @@ -310,6 +317,7 @@ generous deed immortalized in the next stable release of Godot Engine. Joel Setterberg Johannes Eichler Johannes Wuensch + Jomei Jackson Jonas Rudlang Jonas Yamazaki Jonathan G @@ -318,21 +326,24 @@ generous deed immortalized in the next stable release of Godot Engine. Jon Bonazza Jon Sully Jose Aleman + Joseph Catrambone Josh 'Cheeseness' Bush Juanfran Juan Negrier Judd + Jueast Julian Murgia Kasier Bald0 KC Chan kickmaniac Kiyohiro Kawamura (kyorohiro) Klagsam + Klassix KR McGinley KsyTek Games Kuan Cheang kycho - Lavik1988 + Leviathan Hunter Levi Lindsey Linus Lind Lundgren Lionel Gaillard @@ -344,6 +355,7 @@ generous deed immortalized in the next stable release of Godot Engine. Malcolm Malik Ahmed Malik Nejer + Marc Urlus Marcus Richter Markus Michael Egger Martin Holas @@ -357,6 +369,7 @@ generous deed immortalized in the next stable release of Godot Engine. Mikael Olsson Mikayla Hutchinson Mike Cunningham + Mitchell J. Wagner mlevin cantu MoM Moritz Laass @@ -365,6 +378,7 @@ generous deed immortalized in the next stable release of Godot Engine. nee Neil Blakey-Milner Nerdforge + Nicholas Niclas Eriksen Nicolás Montaña Nicolas SAN AGUSTIN @@ -372,6 +386,7 @@ generous deed immortalized in the next stable release of Godot Engine. NZ Omar Delarosa Oscar Norlander + Pafka Pan Ip Patrick Forringer Patrick Nafarrete @@ -382,6 +397,7 @@ generous deed immortalized in the next stable release of Godot Engine. Pierre-Igor Berthet Pietro Vertechi Pitsanu Tongprasin + Point08 Poryg Rafa Laguna Rafal Wyszomirski @@ -408,7 +424,7 @@ generous deed immortalized in the next stable release of Godot Engine. Simon Wenner SK Sootstone - Theo Cranmore + Stonepyre Thibault Barbaroux thomas Thomas Bell @@ -434,7 +450,6 @@ generous deed immortalized in the next stable release of Godot Engine. Veodok Victor Vigilant Watch - Viktor Ferenczi waka nya Wayne Haak werner mendizabal @@ -442,6 +457,7 @@ generous deed immortalized in the next stable release of Godot Engine. Will William Hogben Wout Standaert + Yeung Si Xiang ## Bronze donors diff --git a/core/array.cpp b/core/array.cpp index 65934d6ec9..a334af2c04 100644 --- a/core/array.cpp +++ b/core/array.cpp @@ -133,12 +133,18 @@ void Array::erase(const Variant &p_value) { } Variant Array::front() const { - ERR_FAIL_COND_V(_p->array.size() == 0, Variant()); + if (_p->array.size() == 0) { + ERR_EXPLAIN("Can't take value from empty array"); + ERR_FAIL_V(Variant()); + } return operator[](0); } Variant Array::back() const { - ERR_FAIL_COND_V(_p->array.size() == 0, Variant()); + if (_p->array.size() == 0) { + ERR_EXPLAIN("Can't take value from empty array"); + ERR_FAIL_V(Variant()); + } return operator[](_p->array.size() - 1); } @@ -165,8 +171,8 @@ int Array::rfind(const Variant &p_value, int p_from) const { if (_p->array[i] == p_value) { return i; - }; - }; + } + } return -1; } @@ -186,8 +192,8 @@ int Array::count(const Variant &p_value) const { if (_p->array[i] == p_value) { amount++; - }; - }; + } + } return amount; } diff --git a/core/bind/core_bind.cpp b/core/bind/core_bind.cpp index da7b15da94..ba9bd10bfd 100644 --- a/core/bind/core_bind.cpp +++ b/core/bind/core_bind.cpp @@ -149,8 +149,10 @@ _ResourceLoader::_ResourceLoader() { } Error _ResourceSaver::save(const String &p_path, const RES &p_resource, SaverFlags p_flags) { - - ERR_FAIL_COND_V(p_resource.is_null(), ERR_INVALID_PARAMETER); + if (p_resource.is_null()) { + ERR_EXPLAIN("Can't save empty resource to path: " + String(p_path)) + ERR_FAIL_V(ERR_INVALID_PARAMETER); + } return ResourceSaver::save(p_path, p_resource, p_flags); } @@ -246,11 +248,11 @@ PoolStringArray _OS::get_connected_midi_inputs() { } void _OS::open_midi_inputs() { - return OS::get_singleton()->open_midi_inputs(); + OS::get_singleton()->open_midi_inputs(); } void _OS::close_midi_inputs() { - return OS::get_singleton()->close_midi_inputs(); + OS::get_singleton()->close_midi_inputs(); } void _OS::set_video_mode(const Size2 &p_size, bool p_fullscreen, bool p_resizeable, int p_screen) { @@ -2266,7 +2268,7 @@ bool _Directory::current_is_dir() const { void _Directory::list_dir_end() { ERR_FAIL_COND(!d); - return d->list_dir_end(); + d->list_dir_end(); } int _Directory::get_drive_count() { @@ -2700,6 +2702,8 @@ Variant _Thread::wait_to_finish() { target_method = StringName(); target_instance = NULL; userdata = Variant(); + if (thread) + memdelete(thread); thread = NULL; return r; diff --git a/core/class_db.cpp b/core/class_db.cpp index 9fe9b23c68..2cbf53ba0b 100644 --- a/core/class_db.cpp +++ b/core/class_db.cpp @@ -925,7 +925,7 @@ void ClassDB::add_property(StringName p_class, const PropertyInfo &p_pinfo, cons #ifdef DEBUG_METHODS_ENABLED if (!mb_set) { ERR_EXPLAIN("Invalid Setter: " + p_class + "::" + p_setter + " for property: " + p_pinfo.name); - ERR_FAIL_COND(!mb_set); + ERR_FAIL(); } else { int exp_args = 1 + (p_index >= 0 ? 1 : 0); if (mb_set->get_argument_count() != exp_args) { @@ -944,7 +944,7 @@ void ClassDB::add_property(StringName p_class, const PropertyInfo &p_pinfo, cons if (!mb_get) { ERR_EXPLAIN("Invalid Getter: " + p_class + "::" + p_getter + " for property: " + p_pinfo.name); - ERR_FAIL_COND(!mb_get); + ERR_FAIL(); } else { int exp_args = 0 + (p_index >= 0 ? 1 : 0); diff --git a/core/color.cpp b/core/color.cpp index 8959fce4e3..1843532124 100644 --- a/core/color.cpp +++ b/core/color.cpp @@ -388,9 +388,8 @@ bool Color::html_is_valid(const String &p_color) { return false; } - int a = 255; if (alpha) { - a = _parse_col(color, 0); + int a = _parse_col(color, 0); if (a < 0) { return false; } diff --git a/core/command_queue_mt.h b/core/command_queue_mt.h index 798fa4394d..3789eda5db 100644 --- a/core/command_queue_mt.h +++ b/core/command_queue_mt.h @@ -346,7 +346,7 @@ class CommandQueueMT { } return NULL; } - } else if (write_ptr >= dealloc_ptr) { + } else { // ahead of dealloc_ptr, check that there is room if ((COMMAND_MEM_SIZE - write_ptr) < alloc_size + sizeof(uint32_t)) { diff --git a/core/engine.cpp b/core/engine.cpp index 50822244cf..2d8473fbd9 100644 --- a/core/engine.cpp +++ b/core/engine.cpp @@ -197,8 +197,10 @@ void Engine::add_singleton(const Singleton &p_singleton) { Object *Engine::get_singleton_object(const String &p_name) const { const Map<StringName, Object *>::Element *E = singleton_ptrs.find(p_name); - ERR_EXPLAIN("Failed to retrieve non-existent singleton '" + p_name + "'"); - ERR_FAIL_COND_V(!E, NULL); + if (!E) { + ERR_EXPLAIN("Failed to retrieve non-existent singleton '" + p_name + "'"); + ERR_FAIL_V(NULL); + } return E->get(); }; diff --git a/core/hash_map.h b/core/hash_map.h index 31332991de..1513d7a65b 100644 --- a/core/hash_map.h +++ b/core/hash_map.h @@ -208,7 +208,10 @@ private: /* if element doesn't exist, create it */ Element *e = memnew(Element); - ERR_FAIL_COND_V(!e, NULL); /* out of memory */ + if (!e) { + ERR_EXPLAIN("Out of memory"); + ERR_FAIL_V(NULL); + } uint32_t hash = Hasher::hash(p_key); uint32_t index = hash & ((1 << hash_table_power) - 1); e->next = hash_table[index]; @@ -495,8 +498,10 @@ public: } else { /* get the next key */ const Element *e = get_element(*p_key); - ERR_FAIL_COND_V(!e, NULL); /* invalid key supplied */ - + if (!e) { + ERR_EXPLAIN("Invalid key supplied") + ERR_FAIL_V(NULL); + } if (e->next) { /* if there is a "next" in the list, return that */ return &e->next->pair.key; diff --git a/core/image.cpp b/core/image.cpp index dd8f2b9bac..18a3aae88f 100644 --- a/core/image.cpp +++ b/core/image.cpp @@ -1372,6 +1372,7 @@ void Image::shrink_x2() { int new_size = data.size() - ofs; new_img.resize(new_size); + ERR_FAIL_COND(new_img.size() == 0); { PoolVector<uint8_t>::Write w = new_img.write(); @@ -1391,6 +1392,7 @@ void Image::shrink_x2() { ERR_FAIL_COND(!_can_modify(format)); int ps = get_format_pixel_size(format); new_img.resize((width / 2) * (height / 2) * ps); + ERR_FAIL_COND(new_img.size() == 0); { PoolVector<uint8_t>::Write w = new_img.write(); @@ -1464,7 +1466,10 @@ Error Image::generate_mipmaps(bool p_renormalize) { ERR_FAIL_V(ERR_UNAVAILABLE); } - ERR_FAIL_COND_V(width == 0 || height == 0, ERR_UNCONFIGURED); + if (width == 0 || height == 0) { + ERR_EXPLAIN("Cannot generate mipmaps with width or height equal to 0."); + ERR_FAIL_V(ERR_UNCONFIGURED); + } int mmcount; @@ -2532,7 +2537,7 @@ Color Image::get_pixel(int p_x, int p_y) const { } void Image::set_pixelv(const Point2 &p_dst, const Color &p_color) { - return set_pixel(p_dst.x, p_dst.y, p_color); + set_pixel(p_dst.x, p_dst.y, p_color); } void Image::set_pixel(int p_x, int p_y, const Color &p_color) { diff --git a/core/io/file_access_buffered.cpp b/core/io/file_access_buffered.cpp index 93eaeb08c5..15523a49a9 100644 --- a/core/io/file_access_buffered.cpp +++ b/core/io/file_access_buffered.cpp @@ -35,79 +35,79 @@ Error FileAccessBuffered::set_error(Error p_error) const { return (last_error = p_error); -}; +} void FileAccessBuffered::set_cache_size(int p_size) { cache_size = p_size; -}; +} int FileAccessBuffered::get_cache_size() { return cache_size; -}; +} int FileAccessBuffered::cache_data_left() const { if (file.offset >= file.size) { return 0; - }; + } if (cache.offset == -1 || file.offset < cache.offset || file.offset >= cache.offset + cache.buffer.size()) { return read_data_block(file.offset, cache_size); + } - } else { - - return cache.buffer.size() - (file.offset - cache.offset); - }; - - return 0; -}; + return cache.buffer.size() - (file.offset - cache.offset); +} void FileAccessBuffered::seek(size_t p_position) { file.offset = p_position; -}; +} void FileAccessBuffered::seek_end(int64_t p_position) { file.offset = file.size + p_position; -}; +} size_t FileAccessBuffered::get_position() const { return file.offset; -}; +} size_t FileAccessBuffered::get_len() const { return file.size; -}; +} bool FileAccessBuffered::eof_reached() const { return file.offset > file.size; -}; +} uint8_t FileAccessBuffered::get_8() const { - - ERR_FAIL_COND_V(!file.open, 0); + if (!file.open) { + ERR_EXPLAIN("Can't get data, when file is not opened."); + ERR_FAIL_V(0); + } uint8_t byte = 0; if (cache_data_left() >= 1) { byte = cache.buffer[file.offset - cache.offset]; - }; + } ++file.offset; return byte; -}; +} int FileAccessBuffered::get_buffer(uint8_t *p_dest, int p_length) const { - - ERR_FAIL_COND_V(!file.open, -1); + if (!file.open) { + ERR_EXPLAIN("Can't get buffer, when file is not opened."); + ERR_FAIL_V(-1); + } if (p_length > cache_size) { @@ -124,16 +124,16 @@ int FileAccessBuffered::get_buffer(uint8_t *p_dest, int p_length) const { p_length -= size; file.offset += size; total_read += size; - }; + } int err = read_data_block(file.offset, p_length, p_dest); if (err >= 0) { total_read += err; file.offset += err; - }; + } return total_read; - }; + } int to_read = p_length; int total_read = 0; @@ -143,10 +143,10 @@ int FileAccessBuffered::get_buffer(uint8_t *p_dest, int p_length) const { if (left == 0) { file.offset += to_read; return total_read; - }; + } if (left < 0) { return left; - }; + } int r = MIN(left, to_read); //PoolVector<uint8_t>::Read read = cache.buffer.read(); @@ -156,25 +156,25 @@ int FileAccessBuffered::get_buffer(uint8_t *p_dest, int p_length) const { file.offset += r; total_read += r; to_read -= r; - }; + } return p_length; -}; +} bool FileAccessBuffered::is_open() const { return file.open; -}; +} Error FileAccessBuffered::get_error() const { return last_error; -}; +} FileAccessBuffered::FileAccessBuffered() { cache_size = DEFAULT_CACHE_SIZE; -}; +} FileAccessBuffered::~FileAccessBuffered() { } diff --git a/core/io/file_access_buffered_fa.h b/core/io/file_access_buffered_fa.h index 24b40cbce8..6e806e7b3f 100644 --- a/core/io/file_access_buffered_fa.h +++ b/core/io/file_access_buffered_fa.h @@ -40,7 +40,10 @@ class FileAccessBufferedFA : public FileAccessBuffered { int read_data_block(int p_offset, int p_size, uint8_t *p_dest = 0) const { - ERR_FAIL_COND_V(!f.is_open(), -1); + if (!f.is_open()) { + ERR_EXPLAIN("Can't read data block, when file is not opened."); + ERR_FAIL_V(-1); + } ((T *)&f)->seek(p_offset); diff --git a/core/io/http_client.cpp b/core/io/http_client.cpp index c3626bfe31..170bef4430 100644 --- a/core/io/http_client.cpp +++ b/core/io/http_client.cpp @@ -482,8 +482,6 @@ Error HTTPClient::poll() { return OK; } } - // Wait for response - return OK; } break; case STATUS_DISCONNECTED: { return ERR_UNCONFIGURED; diff --git a/core/io/json.cpp b/core/io/json.cpp index c211ca2ed4..4e729cb355 100644 --- a/core/io/json.cpp +++ b/core/io/json.cpp @@ -347,8 +347,6 @@ Error JSON::_parse_value(Variant &value, Token &token, const CharType *p_str, in r_err_str = "Expected value, got " + String(tk_name[token.type]) + "."; return ERR_PARSE_ERROR; } - - return ERR_PARSE_ERROR; } Error JSON::_parse_array(Array &array, const CharType *p_str, int &index, int p_len, int &line, String &r_err_str) { diff --git a/core/io/pck_packer.cpp b/core/io/pck_packer.cpp index 55685a2d9a..c16d89d695 100644 --- a/core/io/pck_packer.cpp +++ b/core/io/pck_packer.cpp @@ -63,10 +63,11 @@ void PCKPacker::_bind_methods() { Error PCKPacker::pck_start(const String &p_file, int p_alignment) { file = FileAccess::open(p_file, FileAccess::WRITE); - if (file == NULL) { - return ERR_CANT_CREATE; - }; + if (!file) { + ERR_EXPLAIN("Can't open file to write: " + String(p_file)); + ERR_FAIL_V(ERR_CANT_CREATE); + } alignment = p_alignment; diff --git a/core/io/resource_importer.cpp b/core/io/resource_importer.cpp index 4a58d37ca5..63d7ba547c 100644 --- a/core/io/resource_importer.cpp +++ b/core/io/resource_importer.cpp @@ -161,7 +161,8 @@ void ResourceFormatImporter::get_recognized_extensions(List<String> *p_extension void ResourceFormatImporter::get_recognized_extensions_for_type(const String &p_type, List<String> *p_extensions) const { if (p_type == "") { - return get_recognized_extensions(p_extensions); + get_recognized_extensions(p_extensions); + return; } Set<String> found; @@ -347,7 +348,7 @@ void ResourceFormatImporter::get_dependencies(const String &p_path, List<String> return; } - return ResourceLoader::get_dependencies(pat.path, p_dependencies, p_add_types); + ResourceLoader::get_dependencies(pat.path, p_dependencies, p_add_types); } Ref<ResourceImporter> ResourceFormatImporter::get_importer_by_name(const String &p_name) const { diff --git a/core/io/resource_loader.cpp b/core/io/resource_loader.cpp index 56d3b8b133..a29b9d1ddb 100644 --- a/core/io/resource_loader.cpp +++ b/core/io/resource_loader.cpp @@ -207,8 +207,6 @@ RES ResourceFormatLoader::load(const String &p_path, const String &p_original_pa ERR_FAIL_COND_V(err != OK, RES()); } - - return RES(); } void ResourceFormatLoader::get_dependencies(const String &p_path, List<String> *p_dependencies, bool p_add_types) { @@ -283,7 +281,6 @@ RES ResourceLoader::_load(const String &p_path, const String &p_original_path, c ERR_EXPLAIN("No loader found for resource: " + p_path); } ERR_FAIL_V(RES()); - return RES(); } bool ResourceLoader::_add_to_loading_map(const String &p_path) { @@ -543,7 +540,6 @@ Ref<ResourceInteractiveLoader> ResourceLoader::load_interactive(const String &p_ ERR_EXPLAIN("No loader found for resource: " + path); } ERR_FAIL_V(Ref<ResourceInteractiveLoader>()); - return Ref<ResourceInteractiveLoader>(); } void ResourceLoader::add_resource_format_loader(Ref<ResourceFormatLoader> p_format_loader, bool p_at_front) { diff --git a/core/math/bsp_tree.cpp b/core/math/bsp_tree.cpp index d7e6e82cd9..a12f9fee2e 100644 --- a/core/math/bsp_tree.cpp +++ b/core/math/bsp_tree.cpp @@ -142,7 +142,7 @@ int BSP_Tree::_get_points_inside(int p_node, const Vector3 *p_points, int *p_ind } return _get_points_inside(node->over, p_points, p_indices, p_center, p_half_extents, p_indices_count); - } else if (dist_min <= 0) { //all points behind plane + } else { //all points behind plane if (node->under == UNDER_LEAF) { @@ -150,8 +150,6 @@ int BSP_Tree::_get_points_inside(int p_node, const Vector3 *p_points, int *p_ind } return _get_points_inside(node->under, p_points, p_indices, p_center, p_half_extents, p_indices_count); } - - return 0; } int BSP_Tree::get_points_inside(const Vector3 *p_points, int p_point_count) const { @@ -271,8 +269,6 @@ bool BSP_Tree::point_is_inside(const Vector3 &p_point) const { ERR_FAIL_COND_V(idx < MAX_NODES && idx >= node_count, false); #endif } - - return false; } static int _bsp_find_best_half_plane(const Face3 *p_faces, const Vector<int> &p_indices, real_t p_tolerance) { diff --git a/core/math/camera_matrix.cpp b/core/math/camera_matrix.cpp index f615cc8c65..8b3b6c82f3 100644 --- a/core/math/camera_matrix.cpp +++ b/core/math/camera_matrix.cpp @@ -507,21 +507,21 @@ void CameraMatrix::set_light_bias() { real_t *m = &matrix[0][0]; - m[0] = 0.5, - m[1] = 0.0, - m[2] = 0.0, - m[3] = 0.0, - m[4] = 0.0, - m[5] = 0.5, - m[6] = 0.0, - m[7] = 0.0, - m[8] = 0.0, - m[9] = 0.0, - m[10] = 0.5, - m[11] = 0.0, - m[12] = 0.5, - m[13] = 0.5, - m[14] = 0.5, + m[0] = 0.5; + m[1] = 0.0; + m[2] = 0.0; + m[3] = 0.0; + m[4] = 0.0; + m[5] = 0.5; + m[6] = 0.0; + m[7] = 0.0; + m[8] = 0.0; + m[9] = 0.0; + m[10] = 0.5; + m[11] = 0.0; + m[12] = 0.5; + m[13] = 0.5; + m[14] = 0.5; m[15] = 1.0; } @@ -529,21 +529,21 @@ void CameraMatrix::set_light_atlas_rect(const Rect2 &p_rect) { real_t *m = &matrix[0][0]; - m[0] = p_rect.size.width, - m[1] = 0.0, - m[2] = 0.0, - m[3] = 0.0, - m[4] = 0.0, - m[5] = p_rect.size.height, - m[6] = 0.0, - m[7] = 0.0, - m[8] = 0.0, - m[9] = 0.0, - m[10] = 1.0, - m[11] = 0.0, - m[12] = p_rect.position.x, - m[13] = p_rect.position.y, - m[14] = 0.0, + m[0] = p_rect.size.width; + m[1] = 0.0; + m[2] = 0.0; + m[3] = 0.0; + m[4] = 0.0; + m[5] = p_rect.size.height; + m[6] = 0.0; + m[7] = 0.0; + m[8] = 0.0; + m[9] = 0.0; + m[10] = 1.0; + m[11] = 0.0; + m[12] = p_rect.position.x; + m[13] = p_rect.position.y; + m[14] = 0.0; m[15] = 1.0; } diff --git a/core/math/math_funcs.cpp b/core/math/math_funcs.cpp index 5b5fd8e283..7a2e74a413 100644 --- a/core/math/math_funcs.cpp +++ b/core/math/math_funcs.cpp @@ -161,8 +161,6 @@ uint32_t Math::larger_prime(uint32_t p_val) { return primes[idx]; idx++; } - - return 0; } double Math::random(double from, double to) { diff --git a/core/math/random_number_generator.h b/core/math/random_number_generator.h index a6182a4b33..9b54ea9b2e 100644 --- a/core/math/random_number_generator.h +++ b/core/math/random_number_generator.h @@ -47,7 +47,7 @@ public: _FORCE_INLINE_ uint64_t get_seed() { return randbase.get_seed(); } - _FORCE_INLINE_ void randomize() { return randbase.randomize(); } + _FORCE_INLINE_ void randomize() { randbase.randomize(); } _FORCE_INLINE_ uint32_t randi() { return randbase.rand(); } diff --git a/core/object.cpp b/core/object.cpp index ee512ff23c..3367d6b6c3 100644 --- a/core/object.cpp +++ b/core/object.cpp @@ -742,13 +742,11 @@ void Object::call_multilevel(const StringName &p_method, const Variant **p_args, if (Object::cast_to<Reference>(this)) { ERR_EXPLAIN("Can't 'free' a reference."); ERR_FAIL(); - return; } if (_lock_index.get() > 1) { ERR_EXPLAIN("Object is locked and can't be freed."); ERR_FAIL(); - return; } #endif @@ -1467,7 +1465,7 @@ Error Object::connect(const StringName &p_signal, Object *p_to_object, const Str if (!signal_is_valid) { ERR_EXPLAIN("In Object of type '" + String(get_class()) + "': Attempt to connect nonexistent signal '" + p_signal + "' to method '" + p_to_object->get_class() + "." + p_to_method + "'"); - ERR_FAIL_COND_V(!signal_is_valid, ERR_INVALID_PARAMETER); + ERR_FAIL_V(ERR_INVALID_PARAMETER); } signal_map[p_signal] = Signal(); s = &signal_map[p_signal]; @@ -1517,7 +1515,7 @@ bool Object::is_connected(const StringName &p_signal, Object *p_to_object, const return false; ERR_EXPLAIN("Nonexistent signal: " + p_signal); - ERR_FAIL_COND_V(!s, false); + ERR_FAIL_V(false); } Signal::Target target(p_to_object->get_instance_id(), p_to_method); diff --git a/core/os/dir_access.cpp b/core/os/dir_access.cpp index 1c57bfdf3d..0cdb5b41b7 100644 --- a/core/os/dir_access.cpp +++ b/core/os/dir_access.cpp @@ -43,8 +43,6 @@ String DirAccess::_get_root_path() const { case ACCESS_USERDATA: return OS::get_singleton()->get_user_data_dir(); default: return ""; } - - return ""; } String DirAccess::_get_root_string() const { @@ -54,8 +52,6 @@ String DirAccess::_get_root_string() const { case ACCESS_USERDATA: return "user://"; default: return ""; } - - return ""; } int DirAccess::get_current_drive() { @@ -378,7 +374,7 @@ Error DirAccess::_copy_dir(DirAccess *p_target_da, String p_to, int p_chmod_flag list_dir_end(); return ERR_BUG; } - Error err = copy(get_current_dir() + "/" + n, p_to + rel_path, p_chmod_flags); + Error err = copy(get_current_dir().plus_file(n), p_to + rel_path, p_chmod_flags); if (err) { list_dir_end(); return err; diff --git a/core/os/memory.h b/core/os/memory.h index f3ca9fc614..e073b11e76 100644 --- a/core/os/memory.h +++ b/core/os/memory.h @@ -66,7 +66,7 @@ public: class DefaultAllocator { public: _FORCE_INLINE_ static void *alloc(size_t p_memory) { return Memory::alloc_static(p_memory, false); } - _FORCE_INLINE_ static void free(void *p_ptr) { return Memory::free_static(p_ptr, false); } + _FORCE_INLINE_ static void free(void *p_ptr) { Memory::free_static(p_ptr, false); } }; void *operator new(size_t p_size, const char *p_description); ///< operator new that takes a description and uses MemoryStaticPool diff --git a/core/project_settings.cpp b/core/project_settings.cpp index 983b2a2576..fc1a74801d 100644 --- a/core/project_settings.cpp +++ b/core/project_settings.cpp @@ -863,8 +863,6 @@ Error ProjectSettings::save_custom(const String &p_path, const CustomMap &p_cust ERR_EXPLAIN("Unknown config file format: " + p_path); ERR_FAIL_V(ERR_FILE_UNRECOGNIZED); } - - return OK; } Variant _GLOBAL_DEF(const String &p_var, const Variant &p_default, bool p_restart_if_changed) { diff --git a/core/ustring.cpp b/core/ustring.cpp index ff28fa420d..18c48b4dad 100644 --- a/core/ustring.cpp +++ b/core/ustring.cpp @@ -481,8 +481,6 @@ signed char String::nocasecmp_to(const String &p_str) const { this_str++; that_str++; } - - return 0; //should never reach anyway } signed char String::casecmp_to(const String &p_str) const { @@ -513,8 +511,6 @@ signed char String::casecmp_to(const String &p_str) const { this_str++; that_str++; } - - return 0; //should never reach anyway } signed char String::naturalnocasecmp_to(const String &p_str) const { @@ -731,8 +727,6 @@ String String::get_slicec(CharType p_splitter, int p_slice) const { i++; } - - return String(); //no find! } Vector<String> String::split_spaces() const { diff --git a/core/variant.cpp b/core/variant.cpp index 9306867ac7..5b51a4e513 100644 --- a/core/variant.cpp +++ b/core/variant.cpp @@ -1171,8 +1171,6 @@ Variant::operator signed int() const { return 0; } } - - return 0; } Variant::operator unsigned int() const { @@ -1188,8 +1186,6 @@ Variant::operator unsigned int() const { return 0; } } - - return 0; } Variant::operator int64_t() const { @@ -1206,8 +1202,6 @@ Variant::operator int64_t() const { return 0; } } - - return 0; } /* @@ -1244,8 +1238,6 @@ Variant::operator uint64_t() const { return 0; } } - - return 0; } #ifdef NEED_LONG_INT @@ -1300,8 +1292,6 @@ Variant::operator signed short() const { return 0; } } - - return 0; } Variant::operator unsigned short() const { @@ -1317,8 +1307,6 @@ Variant::operator unsigned short() const { return 0; } } - - return 0; } Variant::operator signed char() const { @@ -1334,8 +1322,6 @@ Variant::operator signed char() const { return 0; } } - - return 0; } Variant::operator unsigned char() const { @@ -1351,8 +1337,6 @@ Variant::operator unsigned char() const { return 0; } } - - return 0; } Variant::operator CharType() const { @@ -1374,8 +1358,6 @@ Variant::operator float() const { return 0; } } - - return 0; } Variant::operator double() const { @@ -1391,8 +1373,6 @@ Variant::operator double() const { return 0; } } - - return true; } Variant::operator StringName() const { diff --git a/core/variant_op.cpp b/core/variant_op.cpp index f3c9bcaa7e..d677c7776a 100644 --- a/core/variant_op.cpp +++ b/core/variant_op.cpp @@ -2183,7 +2183,8 @@ void Variant::set(const Variant &p_index, const Variant &p_value, bool *r_valid) return; } - return obj->set(p_index, p_value, r_valid); + obj->set(p_index, p_value, r_valid); + return; } } break; case DICTIONARY: { diff --git a/core/variant_parser.cpp b/core/variant_parser.cpp index d7371b0434..d5513bc2d7 100644 --- a/core/variant_parser.cpp +++ b/core/variant_parser.cpp @@ -436,8 +436,6 @@ Error VariantParser::_parse_enginecfg(Stream *p_stream, Vector<String> &strings, line++; } } - - return OK; } template <class T> @@ -799,8 +797,6 @@ Error VariantParser::parse_value(Token &token, Variant &value, Stream *p_stream, } } - return OK; - } else if (id == "Resource" || id == "SubResource" || id == "ExtResource") { get_token(p_stream, token, line, r_err_str); @@ -864,8 +860,6 @@ Error VariantParser::parse_value(Token &token, Variant &value, Stream *p_stream, return ERR_PARSE_ERROR; } } - - return OK; #ifndef DISABLE_DEPRECATED } else if (id == "InputEvent") { @@ -1256,8 +1250,6 @@ Error VariantParser::parse_value(Token &token, Variant &value, Stream *p_stream, r_err_str = "Expected value, got " + String(tk_name[token.type]) + "."; return ERR_PARSE_ERROR; } - - return ERR_PARSE_ERROR; } Error VariantParser::_parse_array(Array &array, Stream *p_stream, int &line, String &r_err_str, ResourceParser *p_res_parser) { @@ -1301,8 +1293,6 @@ Error VariantParser::_parse_array(Array &array, Stream *p_stream, int &line, Str array.push_back(v); need_comma = true; } - - return OK; } Error VariantParser::_parse_dictionary(Dictionary &object, Stream *p_stream, int &line, String &r_err_str, ResourceParser *p_res_parser) { @@ -1372,8 +1362,6 @@ Error VariantParser::_parse_dictionary(Dictionary &object, Stream *p_stream, int at_key = true; } } - - return OK; } Error VariantParser::_parse_tag(Token &token, Stream *p_stream, int &line, String &r_err_str, Tag &r_tag, ResourceParser *p_res_parser, bool p_simple_tag) { @@ -1557,8 +1545,6 @@ Error VariantParser::parse_tag_assign_eof(Stream *p_stream, int &line, String &r line++; } } - - return OK; } Error VariantParser::parse(Stream *p_stream, Variant &r_ret, String &r_err_str, int &r_err_line, ResourceParser *p_res_parser) { diff --git a/doc/classes/@GlobalScope.xml b/doc/classes/@GlobalScope.xml index 4f5e1a27db..0428140908 100644 --- a/doc/classes/@GlobalScope.xml +++ b/doc/classes/@GlobalScope.xml @@ -648,7 +648,7 @@ _ key. </constant> <constant name="KEY_QUOTELEFT" value="96" enum="KeyList"> - Left Quote key. + ` key. </constant> <constant name="KEY_BRACELEFT" value="123" enum="KeyList"> { key. @@ -675,9 +675,10 @@ £ key. </constant> <constant name="KEY_CURRENCY" value="164" enum="KeyList"> + ¤ key. </constant> <constant name="KEY_YEN" value="165" enum="KeyList"> - Yen key. + ¥ key. </constant> <constant name="KEY_BROKENBAR" value="166" enum="KeyList"> ¦ key. @@ -692,21 +693,22 @@ © key. </constant> <constant name="KEY_ORDFEMININE" value="170" enum="KeyList"> + ª key. </constant> <constant name="KEY_GUILLEMOTLEFT" value="171" enum="KeyList"> « key. </constant> <constant name="KEY_NOTSIGN" value="172" enum="KeyList"> - » key. + ¬ key. </constant> <constant name="KEY_HYPHEN" value="173" enum="KeyList"> - ‐ key. + Soft hyphen key. </constant> <constant name="KEY_REGISTERED" value="174" enum="KeyList"> ® key. </constant> <constant name="KEY_MACRON" value="175" enum="KeyList"> - Macron key. + ¯ key. </constant> <constant name="KEY_DEGREE" value="176" enum="KeyList"> ° key. @@ -727,19 +729,19 @@ µ key. </constant> <constant name="KEY_PARAGRAPH" value="182" enum="KeyList"> - § key. + ¶ key. </constant> <constant name="KEY_PERIODCENTERED" value="183" enum="KeyList"> · key. </constant> <constant name="KEY_CEDILLA" value="184" enum="KeyList"> - ¬ key. + ¸ key. </constant> <constant name="KEY_ONESUPERIOR" value="185" enum="KeyList"> ¹ key. </constant> <constant name="KEY_MASCULINE" value="186" enum="KeyList"> - ♂ key. + º key. </constant> <constant name="KEY_GUILLEMOTRIGHT" value="187" enum="KeyList"> » key. @@ -757,97 +759,97 @@ ¿ key. </constant> <constant name="KEY_AGRAVE" value="192" enum="KeyList"> - à key. + À key. </constant> <constant name="KEY_AACUTE" value="193" enum="KeyList"> - á key. + Á key. </constant> <constant name="KEY_ACIRCUMFLEX" value="194" enum="KeyList"> - â key. + Â key. </constant> <constant name="KEY_ATILDE" value="195" enum="KeyList"> - ã key. + Ã key. </constant> <constant name="KEY_ADIAERESIS" value="196" enum="KeyList"> - ä key. + Ä key. </constant> <constant name="KEY_ARING" value="197" enum="KeyList"> - å key. + Å key. </constant> <constant name="KEY_AE" value="198" enum="KeyList"> - æ key. + Æ key. </constant> <constant name="KEY_CCEDILLA" value="199" enum="KeyList"> - ç key. + Ç key. </constant> <constant name="KEY_EGRAVE" value="200" enum="KeyList"> - è key. + È key. </constant> <constant name="KEY_EACUTE" value="201" enum="KeyList"> - é key. + É key. </constant> <constant name="KEY_ECIRCUMFLEX" value="202" enum="KeyList"> - ê key. + Ê key. </constant> <constant name="KEY_EDIAERESIS" value="203" enum="KeyList"> - ë key. + Ë key. </constant> <constant name="KEY_IGRAVE" value="204" enum="KeyList"> - ì key. + Ì key. </constant> <constant name="KEY_IACUTE" value="205" enum="KeyList"> - í key. + Í key. </constant> <constant name="KEY_ICIRCUMFLEX" value="206" enum="KeyList"> - î key. + Î key. </constant> <constant name="KEY_IDIAERESIS" value="207" enum="KeyList"> - ë key. + Ï key. </constant> <constant name="KEY_ETH" value="208" enum="KeyList"> - ð key. + Ð key. </constant> <constant name="KEY_NTILDE" value="209" enum="KeyList"> - ñ key. + Ñ key. </constant> <constant name="KEY_OGRAVE" value="210" enum="KeyList"> - ò key. + Ò key. </constant> <constant name="KEY_OACUTE" value="211" enum="KeyList"> - ó key. + Ó key. </constant> <constant name="KEY_OCIRCUMFLEX" value="212" enum="KeyList"> - ô key. + Ô key. </constant> <constant name="KEY_OTILDE" value="213" enum="KeyList"> - õ key. + Õ key. </constant> <constant name="KEY_ODIAERESIS" value="214" enum="KeyList"> - ö key. + Ö key. </constant> <constant name="KEY_MULTIPLY" value="215" enum="KeyList"> × key. </constant> <constant name="KEY_OOBLIQUE" value="216" enum="KeyList"> - ø key. + Ø key. </constant> <constant name="KEY_UGRAVE" value="217" enum="KeyList"> - ù key. + Ù key. </constant> <constant name="KEY_UACUTE" value="218" enum="KeyList"> - ú key. + Ú key. </constant> <constant name="KEY_UCIRCUMFLEX" value="219" enum="KeyList"> - û key. + Û key. </constant> <constant name="KEY_UDIAERESIS" value="220" enum="KeyList"> - ü key. + Ü key. </constant> <constant name="KEY_YACUTE" value="221" enum="KeyList"> - ý key. + Ý key. </constant> <constant name="KEY_THORN" value="222" enum="KeyList"> - þ key. + Þ key. </constant> <constant name="KEY_SSHARP" value="223" enum="KeyList"> ß key. @@ -1003,16 +1005,16 @@ Xbox controller Y button. </constant> <constant name="JOY_DS_A" value="1" enum="JoystickList"> - DualShock controller A button. + Nintendo controller A button. </constant> <constant name="JOY_DS_B" value="0" enum="JoystickList"> - DualShock controller B button. + Nintendo controller B button. </constant> <constant name="JOY_DS_X" value="3" enum="JoystickList"> - DualShock controller X button. + Nintendo controller X button. </constant> <constant name="JOY_DS_Y" value="2" enum="JoystickList"> - DualShock controller Y button. + Nintendo controller Y button. </constant> <constant name="JOY_VR_GRIP" value="2" enum="JoystickList"> Grip (side) buttons on a VR controller. @@ -1084,8 +1086,10 @@ Gamepad right stick vertical axis. </constant> <constant name="JOY_AXIS_4" value="4" enum="JoystickList"> + Generic gamepad axis 4. </constant> <constant name="JOY_AXIS_5" value="5" enum="JoystickList"> + Generic gamepad axis 5. </constant> <constant name="JOY_AXIS_6" value="6" enum="JoystickList"> Gamepad left trigger analog axis. @@ -1094,8 +1098,10 @@ Gamepad right trigger analog axis. </constant> <constant name="JOY_AXIS_8" value="8" enum="JoystickList"> + Generic gamepad axis 8. </constant> <constant name="JOY_AXIS_9" value="9" enum="JoystickList"> + Generic gamepad axis 9. </constant> <constant name="JOY_AXIS_MAX" value="10" enum="JoystickList"> Represents the maximum number of joystick axes supported. @@ -1131,18 +1137,25 @@ OpenVR touchpad Y axis (Joystick axis on Oculus Touch and Windows MR controllers). </constant> <constant name="MIDI_MESSAGE_NOTE_OFF" value="8" enum="MidiMessageList"> + MIDI note OFF message. </constant> <constant name="MIDI_MESSAGE_NOTE_ON" value="9" enum="MidiMessageList"> + MIDI note ON message. </constant> <constant name="MIDI_MESSAGE_AFTERTOUCH" value="10" enum="MidiMessageList"> + MIDI aftertouch message. </constant> <constant name="MIDI_MESSAGE_CONTROL_CHANGE" value="11" enum="MidiMessageList"> + MIDI control change message. </constant> <constant name="MIDI_MESSAGE_PROGRAM_CHANGE" value="12" enum="MidiMessageList"> + MIDI program change message. </constant> <constant name="MIDI_MESSAGE_CHANNEL_PRESSURE" value="13" enum="MidiMessageList"> + MIDI channel pressure message. </constant> <constant name="MIDI_MESSAGE_PITCH_BEND" value="14" enum="MidiMessageList"> + MIDI pitch bend message. </constant> <constant name="OK" value="0" enum="Error"> Methods that return [enum Error] return [constant OK] when no error occurred. Note that many functions don't return an error code but will print error messages to standard output. @@ -1304,88 +1317,112 @@ No hint for the edited property. </constant> <constant name="PROPERTY_HINT_RANGE" value="1" enum="PropertyHint"> - Hints that the string is a range, defined as [code]"min,max"[/code] or [code]"min,max,step"[/code]. This is valid for integers and floats. + Hints that an integer or float property should be within a range specified via the hint string [code]"min,max"[/code] or [code]"min,max,step"[/code]. The hint string can optionally include [code]"allow_greater"[/code] and/or [code]"allow_lesser"[/code] to allow manual input going respectively above the max or below the min values. Example: [code]"-360,360,1,allow_greater,allow_lesser"[/code]. </constant> <constant name="PROPERTY_HINT_EXP_RANGE" value="2" enum="PropertyHint"> - Hints that the string is an exponential range, defined as [code]"min,max"[/code] or [code]"min,max,step"[/code]. This is valid for integers and floats. + Hints that an integer or float property should be within an exponential range specified via the hint string [code]"min,max"[/code] or [code]"min,max,step"[/code]. The hint string can optionally include [code]"allow_greater"[/code] and/or [code]"allow_lesser"[/code] to allow manual input going respectively above the max or below the min values. Example: [code]"0.01,100,0.01,allow_greater"[/code]. </constant> <constant name="PROPERTY_HINT_ENUM" value="3" enum="PropertyHint"> - Property hint for an enumerated value, like [code]"Hello,Something,Else"[/code]. This is valid for integer, float and string properties. + Hints that an integer, float or string property is an enumerated value to pick in a list specified via a hint string such as [code]"Hello,Something,Else"[/code]. </constant> <constant name="PROPERTY_HINT_EXP_EASING" value="4" enum="PropertyHint"> + Hints that a float property should be edited via an exponential easing function. The hint string can include [code]"attenuation"[/code] to flip the curve horizontally and/or [code]"inout"[/code] to also include in/out easing. </constant> <constant name="PROPERTY_HINT_LENGTH" value="5" enum="PropertyHint"> + Deprecated hint, unused. </constant> <constant name="PROPERTY_HINT_KEY_ACCEL" value="7" enum="PropertyHint"> + Deprecated hint, unused. </constant> <constant name="PROPERTY_HINT_FLAGS" value="8" enum="PropertyHint"> - Property hint for a bitmask description. For example, for bits 0, 1, 2, 3 and 5, the hint could be something like [code]"Bit0,Bit1,Bit2,Bit3,,Bit5"[/code]. This is only valid for integer properties. + Hints that an integer property is a bitmask with named bit flags. For example, to allow toggling bits 0, 1, 2 and 4, the hint could be something like [code]"Bit0,Bit1,Bit2,,Bit4"[/code]. </constant> <constant name="PROPERTY_HINT_LAYERS_2D_RENDER" value="9" enum="PropertyHint"> + Hints that an integer property is a bitmask using the optionally named 2D render layers. </constant> <constant name="PROPERTY_HINT_LAYERS_2D_PHYSICS" value="10" enum="PropertyHint"> + Hints that an integer property is a bitmask using the optionally named 2D physics layers. </constant> <constant name="PROPERTY_HINT_LAYERS_3D_RENDER" value="11" enum="PropertyHint"> + Hints that an integer property is a bitmask using the optionally named 3D render layers. </constant> <constant name="PROPERTY_HINT_LAYERS_3D_PHYSICS" value="12" enum="PropertyHint"> + Hints that an integer property is a bitmask using the optionally named 3D physics layers. </constant> <constant name="PROPERTY_HINT_FILE" value="13" enum="PropertyHint"> - String property is a file, will pop up a file dialog when edited. Hint string can be a set of wildcards like [code]"*.doc"[/code]. + Hints that a string property is a path to a file. Editing it will show a file dialog for picking the path. The hint string can be a set of filters with wildcards like [code]"*.png,*.jpg"[/code]. </constant> <constant name="PROPERTY_HINT_DIR" value="14" enum="PropertyHint"> - String property is a directory, will pop up a file dialog when edited. + Hints that a string property is a path to a directory. Editing it will show a file dialog for picking the path. </constant> <constant name="PROPERTY_HINT_GLOBAL_FILE" value="15" enum="PropertyHint"> + Hints that a string property is an absolute path to a file outside the project folder. Editing it will show a file dialog for picking the path. The hint string can be a set of filters with wildcards like [code]"*.png,*.jpg"[/code]. </constant> <constant name="PROPERTY_HINT_GLOBAL_DIR" value="16" enum="PropertyHint"> + Hints that a string property is an absolute path to a directory outside the project folder. Editing it will show a file dialog for picking the path. </constant> <constant name="PROPERTY_HINT_RESOURCE_TYPE" value="17" enum="PropertyHint"> - String property is a resource, will open the resource popup menu when edited. + Hints that a property is an instance of a [Resource]-derived type, optionally specified via the hint string (e.g. [code]"Texture"[/code]). Editing it will show a popup menu of valid resource types to instantiate. </constant> <constant name="PROPERTY_HINT_MULTILINE_TEXT" value="18" enum="PropertyHint"> + Hints that a string property is text with line breaks. Editing it will show a text input field where line breaks can be typed. </constant> <constant name="PROPERTY_HINT_PLACEHOLDER_TEXT" value="19" enum="PropertyHint"> + Hints that a string property should have a placeholder text visible on its input field, whenever the property is empty. The hint string is the placeholder text to use. </constant> <constant name="PROPERTY_HINT_COLOR_NO_ALPHA" value="20" enum="PropertyHint"> + Hints that a color property should be edited without changing its alpha component, i.e. only R, G and B channels are edited. </constant> <constant name="PROPERTY_HINT_IMAGE_COMPRESS_LOSSY" value="21" enum="PropertyHint"> - Hints that the image is compressed using lossy compression. + Hints that an image is compressed using lossy compression. </constant> <constant name="PROPERTY_HINT_IMAGE_COMPRESS_LOSSLESS" value="22" enum="PropertyHint"> - Hints that the image is compressed using lossless compression. + Hints that an image is compressed using lossless compression. </constant> <constant name="PROPERTY_USAGE_STORAGE" value="1" enum="PropertyUsageFlags"> - Property will be used as storage (default). + The property is serialized and saved in the scene file (default). </constant> <constant name="PROPERTY_USAGE_EDITOR" value="2" enum="PropertyUsageFlags"> - Property will be visible in editor (default). + The property is shown in the editor inspector (default). </constant> <constant name="PROPERTY_USAGE_NETWORK" value="4" enum="PropertyUsageFlags"> + Deprecated usage flag, unused. </constant> <constant name="PROPERTY_USAGE_EDITOR_HELPER" value="8" enum="PropertyUsageFlags"> + Deprecated usage flag, unused. </constant> <constant name="PROPERTY_USAGE_CHECKABLE" value="16" enum="PropertyUsageFlags"> + The property can be checked in the editor inspector. </constant> <constant name="PROPERTY_USAGE_CHECKED" value="32" enum="PropertyUsageFlags"> + The property is checked in the editor inspector. </constant> <constant name="PROPERTY_USAGE_INTERNATIONALIZED" value="64" enum="PropertyUsageFlags"> + The property is a translatable string. </constant> <constant name="PROPERTY_USAGE_GROUP" value="128" enum="PropertyUsageFlags"> + Used to group properties together in the editor. </constant> <constant name="PROPERTY_USAGE_CATEGORY" value="256" enum="PropertyUsageFlags"> + Used to categorize properties together in the editor. </constant> <constant name="PROPERTY_USAGE_NO_INSTANCE_STATE" value="2048" enum="PropertyUsageFlags"> + The property does not save its state in [PackedScene]. </constant> <constant name="PROPERTY_USAGE_RESTART_IF_CHANGED" value="4096" enum="PropertyUsageFlags"> + Editing the property prompts the user for restarting the editor. </constant> <constant name="PROPERTY_USAGE_SCRIPT_VARIABLE" value="8192" enum="PropertyUsageFlags"> + The property is a script variable which should be serialized and saved in the scene file. </constant> <constant name="PROPERTY_USAGE_DEFAULT" value="7" enum="PropertyUsageFlags"> - Default usage (storage and editor). + Default usage (storage, editor and network). </constant> <constant name="PROPERTY_USAGE_DEFAULT_INTL" value="71" enum="PropertyUsageFlags"> + Default usage for translatable strings (storage, editor, network and internationalized). </constant> <constant name="PROPERTY_USAGE_NOEDITOR" value="5" enum="PropertyUsageFlags"> + Default usage but without showing the property in the editor (storage, network). </constant> <constant name="METHOD_FLAG_NORMAL" value="1" enum="MethodFlags"> Flag for a normal method. @@ -1394,23 +1431,25 @@ Flag for an editor method. </constant> <constant name="METHOD_FLAG_NOSCRIPT" value="4" enum="MethodFlags"> + Deprecated method flag, unused. </constant> <constant name="METHOD_FLAG_CONST" value="8" enum="MethodFlags"> Flag for a constant method. </constant> <constant name="METHOD_FLAG_REVERSE" value="16" enum="MethodFlags"> + Deprecated method flag, unused. </constant> <constant name="METHOD_FLAG_VIRTUAL" value="32" enum="MethodFlags"> Flag for a virtual method. </constant> <constant name="METHOD_FLAG_FROM_SCRIPT" value="64" enum="MethodFlags"> - Flag for a method from a script. + Deprecated method flag, unused. </constant> <constant name="METHOD_FLAGS_DEFAULT" value="1" enum="MethodFlags"> Default method flags. </constant> <constant name="TYPE_NIL" value="0" enum="Variant.Type"> - Variable is of type nil (only applied for [code]null[/code]). + Variable is of type [Nil] (only applied for [code]null[/code]). </constant> <constant name="TYPE_BOOL" value="1" enum="Variant.Type"> Variable is of type [bool]. @@ -1419,7 +1458,7 @@ Variable is of type [int]. </constant> <constant name="TYPE_REAL" value="3" enum="Variant.Type"> - Variable is of type [float]/real. + Variable is of type [float] (real). </constant> <constant name="TYPE_STRING" value="4" enum="Variant.Type"> Variable is of type [String]. @@ -1494,54 +1533,79 @@ Represents the size of the [enum Variant.Type] enum. </constant> <constant name="OP_EQUAL" value="0" enum="Variant.Operator"> + Equality operator ([code]==[/code]). </constant> <constant name="OP_NOT_EQUAL" value="1" enum="Variant.Operator"> + Inequality operator ([code]!=[/code]). </constant> <constant name="OP_LESS" value="2" enum="Variant.Operator"> + Less than operator ([code]<[/code]). </constant> <constant name="OP_LESS_EQUAL" value="3" enum="Variant.Operator"> + Less than or equal operator ([code]<=[/code]). </constant> <constant name="OP_GREATER" value="4" enum="Variant.Operator"> + Greater than operator ([code]>[/code]). </constant> <constant name="OP_GREATER_EQUAL" value="5" enum="Variant.Operator"> + Greater than or equal operator ([code]>=[/code]). </constant> <constant name="OP_ADD" value="6" enum="Variant.Operator"> + Addition operator ([code]+[/code]). </constant> <constant name="OP_SUBTRACT" value="7" enum="Variant.Operator"> + Subtraction operator ([code]-[/code]). </constant> <constant name="OP_MULTIPLY" value="8" enum="Variant.Operator"> + Multiplication operator ([code]*[/code]). </constant> <constant name="OP_DIVIDE" value="9" enum="Variant.Operator"> + Division operator ([code]/[/code]). </constant> <constant name="OP_NEGATE" value="10" enum="Variant.Operator"> + Unary negation operator ([code]-[/code]). </constant> <constant name="OP_POSITIVE" value="11" enum="Variant.Operator"> + Unary plus operator ([code]+[/code]). </constant> <constant name="OP_MODULE" value="12" enum="Variant.Operator"> + Remainder/modulo operator ([code]%[/code]). </constant> <constant name="OP_STRING_CONCAT" value="13" enum="Variant.Operator"> + String concatenation operator ([code]+[/code]). </constant> <constant name="OP_SHIFT_LEFT" value="14" enum="Variant.Operator"> + Left shift operator ([code]<<[/code]). </constant> <constant name="OP_SHIFT_RIGHT" value="15" enum="Variant.Operator"> + Right shift operator ([code]>>[/code]). </constant> <constant name="OP_BIT_AND" value="16" enum="Variant.Operator"> + Bitwise AND operator ([code]&[/code]). </constant> <constant name="OP_BIT_OR" value="17" enum="Variant.Operator"> + Bitwise OR operator ([code]|[/code]). </constant> <constant name="OP_BIT_XOR" value="18" enum="Variant.Operator"> + Bitwise XOR operator ([code]^[/code]). </constant> <constant name="OP_BIT_NEGATE" value="19" enum="Variant.Operator"> + Bitwise NOT operator ([code]~[/code]). </constant> <constant name="OP_AND" value="20" enum="Variant.Operator"> + Logical AND operator ([code]and[/code] or [code]&&[/code]). </constant> <constant name="OP_OR" value="21" enum="Variant.Operator"> + Logical OR operator ([code]or[/code] or [code]||[/code]). </constant> <constant name="OP_XOR" value="22" enum="Variant.Operator"> + Logical XOR operator (not implemented in GDScript). </constant> <constant name="OP_NOT" value="23" enum="Variant.Operator"> + Logical NOT operator ([code]not[/code] or [code]![/code]). </constant> <constant name="OP_IN" value="24" enum="Variant.Operator"> + Logical IN operator ([code]in[/code]). </constant> <constant name="OP_MAX" value="25" enum="Variant.Operator"> Represents the size of the [enum Variant.Operator] enum. diff --git a/doc/classes/AudioServer.xml b/doc/classes/AudioServer.xml index dec1de42bc..f063cfe5ce 100644 --- a/doc/classes/AudioServer.xml +++ b/doc/classes/AudioServer.xml @@ -177,6 +177,13 @@ <description> </description> </method> + <method name="get_global_rate_scale"> + <return type="float"> + </return> + <description> + Returns the global rate scale at which audio is being played. + </description> + </method> <method name="get_mix_rate" qualifiers="const"> <return type="float"> </return> @@ -390,6 +397,15 @@ <description> </description> </method> + <method name="set_global_rate_scale"> + <return type="void"> + </return> + <argument index="0" name="scale" type="float"> + </argument> + <description> + Scales the rate at which audio is played (i.e. setting it to [code]0.5[/code] will make the audio be played twice as fast). + </description> + </method> <method name="swap_bus_effects"> <return type="void"> </return> @@ -411,6 +427,16 @@ </description> </method> </methods> + <members> + <member name="bus_count" type="int" setter="set_bus_count" getter="get_bus_count"> + Adds and removes buses to make the number of buses match [code]amount[/code]. + </member> + <member name="device" type="string" setter="set_device" getter="get_device"> + </member> + <member name="global_rate_scale" type="float" setter="set_global_rate_scale" getter="get_global_rate_scale"> + Scales the rate at which audio is played (i.e. setting it to [code]0.5[/code] will make the audio be played twice as fast). + </member> + </members> <signals> <signal name="bus_layout_changed"> <description> diff --git a/doc/classes/Line2D.xml b/doc/classes/Line2D.xml index 27d3f4bade..b627ae7344 100644 --- a/doc/classes/Line2D.xml +++ b/doc/classes/Line2D.xml @@ -99,6 +99,9 @@ <member name="width" type="float" setter="set_width" getter="get_width" default="10.0"> The line's width. </member> + <member name="width_curve" type="Curve" setter="set_curve" getter="get_curve"> + The line's width varies with the curve. The original width is simply multiply by the value of the Curve. + </member> </members> <constants> <constant name="LINE_JOINT_SHARP" value="0" enum="LineJointMode"> diff --git a/doc/classes/RandomNumberGenerator.xml b/doc/classes/RandomNumberGenerator.xml index 31abe9b000..9054e2fa88 100644 --- a/doc/classes/RandomNumberGenerator.xml +++ b/doc/classes/RandomNumberGenerator.xml @@ -6,6 +6,13 @@ <description> RandomNumberGenerator is a class for generating pseudo-random numbers. It currently uses [url=http://www.pcg-random.org/]PCG32[/url]. [b]Note:[/b] The underlying algorithm is an implementation detail. As a result, it should not be depended upon for reproducible random streams across Godot versions. + To generate a random float number (within a given range) based on a time-dependant seed: + [codeblock] + var rng = RandomNumberGenerator.new() + func _ready(): + rng.randomize() + var my_random_number = rng.randf_range(-10.0, 10.0) + [/codeblock] </description> <tutorials> </tutorials> diff --git a/drivers/gles2/shaders/scene.glsl b/drivers/gles2/shaders/scene.glsl index 2aef913ae8..ca222362e7 100644 --- a/drivers/gles2/shaders/scene.glsl +++ b/drivers/gles2/shaders/scene.glsl @@ -262,7 +262,7 @@ void light_compute( #endif SRGB_APPROX(specular_brdf_NL) - specular_interp += specular_brdf_NL * light_color * attenuation; + specular_interp += specular_brdf_NL * light_color * attenuation * (1.0 / M_PI); } } @@ -1641,18 +1641,30 @@ FRAGMENT_SHADER_CODE #endif // defined(USE_REFLECTION_PROBE1) || defined(USE_REFLECTION_PROBE2) - // scales the specular reflections, needs to be be computed before lighting happens, - // but after environment and reflection probes are added - //TODO: this curve is not really designed for gammaspace, should be adjusted - const vec4 c0 = vec4(-1.0, -0.0275, -0.572, 0.022); - const vec4 c1 = vec4(1.0, 0.0425, 1.04, -0.04); - vec4 r = roughness * c0 + c1; - float ndotv = clamp(dot(normal, eye_position), 0.0, 1.0); - float a004 = min(r.x * r.x, exp2(-9.28 * ndotv)) * r.x + r.y; - vec2 env = vec2(-1.04, 1.04) * a004 + r.zw; + // environment BRDF approximation - vec3 f0 = F0(metallic, specular, albedo); - specular_light *= env.x * f0 + env.y; + { + +#if defined(DIFFUSE_TOON) + //simplify for toon, as + specular_light *= specular * metallic * albedo * 2.0; +#else + + // scales the specular reflections, needs to be be computed before lighting happens, + // but after environment and reflection probes are added + //TODO: this curve is not really designed for gammaspace, should be adjusted + const vec4 c0 = vec4(-1.0, -0.0275, -0.572, 0.022); + const vec4 c1 = vec4(1.0, 0.0425, 1.04, -0.04); + vec4 r = roughness * c0 + c1; + float ndotv = clamp(dot(normal, eye_position), 0.0, 1.0); + float a004 = min(r.x * r.x, exp2(-9.28 * ndotv)) * r.x + r.y; + vec2 env = vec2(-1.04, 1.04) * a004 + r.zw; + + vec3 f0 = F0(metallic, specular, albedo); + specular_light *= env.x * f0 + env.y; + +#endif + } #ifdef USE_LIGHTMAP //ambient light will come entirely from lightmap is lightmap is used @@ -2048,6 +2060,17 @@ FRAGMENT_SHADER_CODE specular_light += specular_interp * specular_blob_intensity * light_att; diffuse_light += diffuse_interp * albedo * light_att; + // Same as above, needed for VERTEX_LIGHTING or else lights are too bright + const vec4 c0 = vec4(-1.0, -0.0275, -0.572, 0.022); + const vec4 c1 = vec4(1.0, 0.0425, 1.04, -0.04); + vec4 r = roughness * c0 + c1; + float ndotv = clamp(dot(normal, eye_position), 0.0, 1.0); + float a004 = min(r.x * r.x, exp2(-9.28 * ndotv)) * r.x + r.y; + vec2 env = vec2(-1.04, 1.04) * a004 + r.zw; + + vec3 f0 = F0(metallic, specular, albedo); + specular_light *= env.x * f0 + env.y; + #else //fragment lighting light_compute( @@ -2115,16 +2138,6 @@ FRAGMENT_SHADER_CODE diffuse_light *= 1.0 - metallic; ambient_light *= 1.0 - metallic; - // environment BRDF approximation - - { - -#if defined(DIFFUSE_TOON) - //simplify for toon, as - specular_light *= specular * metallic * albedo * 2.0; -#endif - } - gl_FragColor = vec4(ambient_light + diffuse_light + specular_light, alpha); //add emission if in base pass diff --git a/drivers/gles3/rasterizer_storage_gles3.cpp b/drivers/gles3/rasterizer_storage_gles3.cpp index 0f6db2dfb8..b280898188 100644 --- a/drivers/gles3/rasterizer_storage_gles3.cpp +++ b/drivers/gles3/rasterizer_storage_gles3.cpp @@ -4644,7 +4644,6 @@ Transform2D RasterizerStorageGLES3::multimesh_instance_get_transform_2d(RID p_mu } Color RasterizerStorageGLES3::multimesh_instance_get_color(RID p_multimesh, int p_index) const { - MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh); ERR_FAIL_COND_V(!multimesh, Color()); ERR_FAIL_INDEX_V(p_index, multimesh->size, Color()); diff --git a/drivers/unix/dir_access_unix.cpp b/drivers/unix/dir_access_unix.cpp index 950979a78e..251bab5783 100644 --- a/drivers/unix/dir_access_unix.cpp +++ b/drivers/unix/dir_access_unix.cpp @@ -313,7 +313,7 @@ Error DirAccessUnix::change_dir(String p_dir) { // try_dir is the directory we are trying to change into String try_dir = ""; if (p_dir.is_rel_path()) { - String next_dir = current_dir + "/" + p_dir; + String next_dir = current_dir.plus_file(p_dir); next_dir = next_dir.simplify_path(); try_dir = next_dir; } else { diff --git a/drivers/unix/net_socket_posix.cpp b/drivers/unix/net_socket_posix.cpp index 16562e2c8f..f8e771aea0 100644 --- a/drivers/unix/net_socket_posix.cpp +++ b/drivers/unix/net_socket_posix.cpp @@ -684,10 +684,10 @@ Ref<NetSocket> NetSocketPosix::accept(IP_Address &r_ip, uint16_t &r_port) { return Ref<NetSocket>(ns); } -Error NetSocketPosix::join_multicast_group(const IP_Address &p_ip, String p_if_name) { - return _change_multicast_group(p_ip, p_if_name, true); +Error NetSocketPosix::join_multicast_group(const IP_Address &p_multi_address, String p_if_name) { + return _change_multicast_group(p_multi_address, p_if_name, true); } -Error NetSocketPosix::leave_multicast_group(const IP_Address &p_ip, String p_if_name) { - return _change_multicast_group(p_ip, p_if_name, false); +Error NetSocketPosix::leave_multicast_group(const IP_Address &p_multi_address, String p_if_name) { + return _change_multicast_group(p_multi_address, p_if_name, false); } diff --git a/editor/animation_bezier_editor.cpp b/editor/animation_bezier_editor.cpp index e524dffd43..14ea18f885 100644 --- a/editor/animation_bezier_editor.cpp +++ b/editor/animation_bezier_editor.cpp @@ -275,8 +275,6 @@ void AnimationBezierTrackEdit::_notification(int p_what) { int margin = 0; { - int ofs = 0; - NodePath path = animation->track_get_path(track); Node *node = NULL; @@ -290,6 +288,8 @@ void AnimationBezierTrackEdit::_notification(int p_what) { int h = font->get_height(); if (node) { + int ofs = 0; + Ref<Texture> icon = EditorNode::get_singleton()->get_object_icon(node, "Node"); h = MAX(h, icon->get_height()); diff --git a/editor/animation_track_editor_plugins.cpp b/editor/animation_track_editor_plugins.cpp index 07dbc1fd81..226eef9c1e 100644 --- a/editor/animation_track_editor_plugins.cpp +++ b/editor/animation_track_editor_plugins.cpp @@ -1009,7 +1009,7 @@ void AnimationTrackEditTypeAudio::drop_data(const Point2 &p_point, const Variant } } - return AnimationTrackEdit::drop_data(p_point, p_data); + AnimationTrackEdit::drop_data(p_point, p_data); } void AnimationTrackEditTypeAudio::_gui_input(const Ref<InputEvent> &p_event) { diff --git a/editor/collada/collada.cpp b/editor/collada/collada.cpp index 4bc9dff26c..57c00e1bef 100644 --- a/editor/collada/collada.cpp +++ b/editor/collada/collada.cpp @@ -308,7 +308,7 @@ void Collada::_parse_image(XMLParser &parser) { String path = parser.get_attribute_value("source").strip_edges(); if (path.find("://") == -1 && path.is_rel_path()) { // path is relative to file being loaded, so convert to a resource path - image.path = ProjectSettings::get_singleton()->localize_path(state.local_path.get_base_dir() + "/" + path.percent_decode()); + image.path = ProjectSettings::get_singleton()->localize_path(state.local_path.get_base_dir().plus_file(path.percent_decode())); } } else { @@ -325,7 +325,7 @@ void Collada::_parse_image(XMLParser &parser) { if (path.find("://") == -1 && path.is_rel_path()) { // path is relative to file being loaded, so convert to a resource path - path = ProjectSettings::get_singleton()->localize_path(state.local_path.get_base_dir() + "/" + path); + path = ProjectSettings::get_singleton()->localize_path(state.local_path.get_base_dir().plus_file(path)); } else if (path.find("file:///") == 0) { path = path.replace_first("file:///", ""); diff --git a/editor/create_dialog.cpp b/editor/create_dialog.cpp index e84602b29f..547d627925 100644 --- a/editor/create_dialog.cpp +++ b/editor/create_dialog.cpp @@ -191,24 +191,36 @@ void CreateDialog::add_type(const String &p_type, HashMap<String, TreeItem *> &p item->set_custom_color(0, get_color("disabled_font_color", "Editor")); item->set_selectable(0, false); } else if (!(*to_select && (*to_select)->get_text(0) == search_box->get_text())) { - bool is_search_subsequence = search_box->get_text().is_subsequence_ofi(p_type); - String to_select_type = *to_select ? (*to_select)->get_text(0) : ""; - to_select_type = to_select_type.split(" ")[0]; - bool current_item_is_preferred; - if (cpp_type) { - String cpp_to_select_type = to_select_type; - if (ScriptServer::is_global_class(to_select_type)) - cpp_to_select_type = ScriptServer::get_global_class_native_base(to_select_type); - current_item_is_preferred = ClassDB::is_parent_class(p_type, preferred_search_result_type) && !ClassDB::is_parent_class(cpp_to_select_type, preferred_search_result_type); - } else { - current_item_is_preferred = ed.script_class_is_parent(p_type, preferred_search_result_type) && !ed.script_class_is_parent(to_select_type, preferred_search_result_type) && search_box->get_text() != to_select_type; - } - if (search_box->get_text() == p_type || (*to_select && p_type.length() < (*to_select)->get_text(0).length())) { - current_item_is_preferred = true; + bool current_type_prefered = _is_type_prefered(p_type); + bool selected_type_prefered = *to_select ? _is_type_prefered((*to_select)->get_text(0).split(" ")[0]) : false; + + String search_term = search_box->get_text().to_lower(); + bool is_subsequence_of_type = search_box->get_text().is_subsequence_ofi(p_type); + bool is_substring_of_type = p_type.to_lower().find(search_term) >= 0; + bool is_substring_of_selected = false; + bool is_subsequence_of_selected = false; + bool is_selected_equal = false; + + if (*to_select) { + String name = (*to_select)->get_text(0).split(" ")[0].to_lower(); + is_substring_of_selected = name.find(search_term) >= 0; + is_subsequence_of_selected = search_term.is_subsequence_of(name); + is_selected_equal = name == search_term; } - if (((!*to_select || current_item_is_preferred) && is_search_subsequence)) { - *to_select = item; + if (is_subsequence_of_type && !is_selected_equal) { + if (is_substring_of_type) { + if (!is_substring_of_selected || (is_substring_of_selected && (current_type_prefered && !selected_type_prefered))) { + *to_select = item; + } + } else { + // substring results weigh more than subsequences, so let's make sure we don't override them + if (!is_substring_of_selected) { + if (!is_subsequence_of_selected || (is_subsequence_of_selected && (current_type_prefered && !selected_type_prefered))) { + *to_select = item; + } + } + } } } @@ -232,6 +244,16 @@ void CreateDialog::add_type(const String &p_type, HashMap<String, TreeItem *> &p p_types[p_type] = item; } +bool CreateDialog::_is_type_prefered(const String &type) { + bool cpp_type = ClassDB::class_exists(type); + EditorData &ed = EditorNode::get_editor_data(); + + if (cpp_type) { + return ClassDB::is_parent_class(type, preferred_search_result_type); + } + return ed.script_class_is_parent(type, preferred_search_result_type); +} + bool CreateDialog::_is_class_disabled_by_feature_profile(const StringName &p_class) { Ref<EditorFeatureProfile> profile = EditorFeatureProfileManager::get_singleton()->get_current_profile(); @@ -275,7 +297,6 @@ void CreateDialog::select_type(const String &p_type) { } void CreateDialog::_update_search() { - search_options->clear(); favorite->set_disabled(true); @@ -308,8 +329,9 @@ void CreateDialog::_update_search() { if (cpp_type && !ClassDB::can_instance(type)) continue; // can't create what can't be instanced - bool skip = false; if (cpp_type) { + bool skip = false; + for (Set<StringName>::Element *E = type_blacklist.front(); E && !skip; E = E->next()) { if (ClassDB::is_parent_class(type, E->get())) skip = true; diff --git a/editor/create_dialog.h b/editor/create_dialog.h index 0eddbc3ceb..f6c3b57589 100644 --- a/editor/create_dialog.h +++ b/editor/create_dialog.h @@ -90,6 +90,7 @@ class CreateDialog : public ConfirmationDialog { void drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from); bool _is_class_disabled_by_feature_profile(const StringName &p_class); + bool _is_type_prefered(const String &type); protected: void _notification(int p_what); diff --git a/editor/editor_file_dialog.cpp b/editor/editor_file_dialog.cpp index 8025fc9795..24c5a788b6 100644 --- a/editor/editor_file_dialog.cpp +++ b/editor/editor_file_dialog.cpp @@ -672,6 +672,18 @@ bool EditorFileDialog::_is_open_should_be_disabled() { return false; } +void EditorFileDialog::update_file_name() { + int idx = filter->get_selected() - 1; + if ((idx == -1 && filter->get_item_count() == 2) || (filter->get_item_count() > 2 && idx >= 0 && idx < filter->get_item_count() - 2)) { + if (idx == -1) idx += 1; + String filter_str = filters[idx]; + String file_str = file->get_text(); + String base_name = file_str.get_basename(); + file_str = base_name + "." + filter_str.split(";")[1].strip_edges().to_lower(); + file->set_text(file_str); + } +} + // DO NOT USE THIS FUNCTION UNLESS NEEDED, CALL INVALIDATE() INSTEAD. void EditorFileDialog::update_file_list() { @@ -865,7 +877,7 @@ void EditorFileDialog::update_file_list() { } void EditorFileDialog::_filter_selected(int) { - + update_file_name(); update_file_list(); } @@ -1364,6 +1376,7 @@ void EditorFileDialog::_bind_methods() { ClassDB::bind_method(D_METHOD("_select_drive"), &EditorFileDialog::_select_drive); ClassDB::bind_method(D_METHOD("_make_dir"), &EditorFileDialog::_make_dir); ClassDB::bind_method(D_METHOD("_make_dir_confirm"), &EditorFileDialog::_make_dir_confirm); + ClassDB::bind_method(D_METHOD("_update_file_name"), &EditorFileDialog::update_file_name); ClassDB::bind_method(D_METHOD("_update_file_list"), &EditorFileDialog::update_file_list); ClassDB::bind_method(D_METHOD("_update_dir"), &EditorFileDialog::update_dir); ClassDB::bind_method(D_METHOD("_thumbnail_done"), &EditorFileDialog::_thumbnail_done); diff --git a/editor/editor_file_dialog.h b/editor/editor_file_dialog.h index 6578be8563..86bf0f0eb3 100644 --- a/editor/editor_file_dialog.h +++ b/editor/editor_file_dialog.h @@ -148,6 +148,7 @@ private: bool invalidated; void update_dir(); + void update_file_name(); void update_file_list(); void update_filters(); diff --git a/editor/editor_file_system.cpp b/editor/editor_file_system.cpp index 3c7c6ec9ed..87a37acac6 100644 --- a/editor/editor_file_system.cpp +++ b/editor/editor_file_system.cpp @@ -96,7 +96,7 @@ String EditorFileSystemDirectory::get_path() const { String p; const EditorFileSystemDirectory *d = this; while (d->parent) { - p = d->name + "/" + p; + p = d->name.plus_file(p); d = d->parent; } @@ -108,7 +108,7 @@ String EditorFileSystemDirectory::get_file_path(int p_idx) const { String file = get_file(p_idx); const EditorFileSystemDirectory *d = this; while (d->parent) { - file = d->name + "/" + file; + file = d->name.plus_file(file); d = d->parent; } diff --git a/editor/editor_help.cpp b/editor/editor_help.cpp index ff50940842..d1f765a312 100644 --- a/editor/editor_help.cpp +++ b/editor/editor_help.cpp @@ -1334,7 +1334,7 @@ static void _add_text_to_rt(const String &p_bbcode, RichTextLabel *p_rt) { end = bbcode.length(); String image = bbcode.substr(brk_end + 1, end - brk_end - 1); - Ref<Texture> texture = ResourceLoader::load(base_path + "/" + image, "Texture"); + Ref<Texture> texture = ResourceLoader::load(base_path.plus_file(image), "Texture"); if (texture.is_valid()) p_rt->add_image(texture); @@ -1390,7 +1390,7 @@ static void _add_text_to_rt(const String &p_bbcode, RichTextLabel *p_rt) { String fnt = tag.substr(5, tag.length()); - Ref<Font> font = ResourceLoader::load(base_path + "/" + fnt, "Font"); + Ref<Font> font = ResourceLoader::load(base_path.plus_file(fnt), "Font"); if (font.is_valid()) p_rt->push_font(font); else { diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index ed311d8a37..213327d8fd 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -2851,7 +2851,7 @@ void EditorNode::set_addon_plugin_enabled(const String &p_addon, bool p_enabled, Ref<ConfigFile> cf; cf.instance(); - String addon_path = "res://addons/" + p_addon + "/plugin.cfg"; + String addon_path = String("res://addons").plus_file(p_addon).plus_file("plugin.cfg"); if (!DirAccess::exists(addon_path.get_base_dir())) { ProjectSettings *ps = ProjectSettings::get_singleton(); PoolStringArray enabled_plugins = ps->get("editor_plugins/enabled"); @@ -2878,7 +2878,7 @@ void EditorNode::set_addon_plugin_enabled(const String &p_addon, bool p_enabled, } String path = cf->get_value("plugin", "script"); - path = "res://addons/" + p_addon + "/" + path; + path = String("res://addons").plus_file(p_addon).plus_file(path); Ref<Script> script = ResourceLoader::load(path); diff --git a/editor/editor_plugin.cpp b/editor/editor_plugin.cpp index 78c38af555..90d6c3a983 100644 --- a/editor/editor_plugin.cpp +++ b/editor/editor_plugin.cpp @@ -200,7 +200,7 @@ ScriptEditor *EditorInterface::get_script_editor() { } void EditorInterface::select_file(const String &p_file) { - return EditorNode::get_singleton()->get_filesystem_dock()->select_file(p_file); + EditorNode::get_singleton()->get_filesystem_dock()->select_file(p_file); } String EditorInterface::get_selected_path() const { diff --git a/editor/editor_properties.cpp b/editor/editor_properties.cpp index 659893a1b6..a8ef563368 100644 --- a/editor/editor_properties.cpp +++ b/editor/editor_properties.cpp @@ -208,7 +208,13 @@ EditorPropertyTextEnum::EditorPropertyTextEnum() { void EditorPropertyPath::_path_selected(const String &p_path) { - emit_changed(get_edited_property(), p_path); + String final_path = p_path; + if (final_path.is_abs_path()) { + String res_path = OS::get_singleton()->get_resource_dir() + "/"; + final_path = res_path.path_to_file(final_path); + } + + emit_changed(get_edited_property(), final_path); update_property(); } void EditorPropertyPath::_path_pressed() { @@ -221,6 +227,13 @@ void EditorPropertyPath::_path_pressed() { } String full_path = get_edited_object()->get(get_edited_property()); + if (full_path.is_rel_path()) { + + if (!DirAccess::exists(full_path.get_base_dir())) { + DirAccessRef da(DirAccess::create(DirAccess::ACCESS_FILESYSTEM)); + da->make_dir_recursive(full_path.get_base_dir()); + } + } dialog->clear_filters(); diff --git a/editor/editor_properties_array_dict.cpp b/editor/editor_properties_array_dict.cpp index a49f9489e1..347699c632 100644 --- a/editor/editor_properties_array_dict.cpp +++ b/editor/editor_properties_array_dict.cpp @@ -183,16 +183,20 @@ void EditorPropertyArray::_property_changed(const String &p_prop, Variant p_valu void EditorPropertyArray::_change_type(Object *p_button, int p_index) { Button *button = Object::cast_to<Button>(p_button); - + changing_type_idx = p_index; Rect2 rect = button->get_global_rect(); change_type->set_as_minsize(); change_type->set_global_position(rect.position + rect.size - Vector2(change_type->get_combined_minimum_size().x, 0)); change_type->popup(); - changing_type_idx = p_index; } void EditorPropertyArray::_change_type_menu(int p_index) { + if (p_index == Variant::VARIANT_MAX) { + _remove_pressed(changing_type_idx); + return; + } + Variant value; Variant::CallError ce; value = Variant::construct(Variant::Type(p_index), NULL, 0, ce); @@ -204,6 +208,7 @@ void EditorPropertyArray::_change_type_menu(int p_index) { if (array.get_type() == Variant::ARRAY) { array = array.call("duplicate"); //dupe, so undo/redo works better } + object->set_array(array); update_property(); } @@ -356,21 +361,27 @@ void EditorPropertyArray::update_property() { prop->set_selectable(false); prop->connect("property_changed", this, "_property_changed"); prop->connect("object_id_selected", this, "_object_id_selected"); - if (array.get_type() == Variant::ARRAY) { - HBoxContainer *hb = memnew(HBoxContainer); - vbox->add_child(hb); - hb->add_child(prop); - prop->set_h_size_flags(SIZE_EXPAND_FILL); - - if (subtype == Variant::NIL) { - Button *edit = memnew(Button); - edit->set_icon(get_icon("Edit", "EditorIcons")); - hb->add_child(edit); - edit->connect("pressed", this, "_change_type", varray(edit, i + offset)); - } + prop->set_h_size_flags(SIZE_EXPAND_FILL); + + HBoxContainer *hb = memnew(HBoxContainer); + + vbox->add_child(hb); + hb->add_child(prop); + bool is_untyped_array = array.get_type() == Variant::ARRAY && subtype == Variant::NIL; + + if (is_untyped_array) { + + Button *edit = memnew(Button); + edit->set_icon(get_icon("Edit", "EditorIcons")); + hb->add_child(edit); + edit->connect("pressed", this, "_change_type", varray(edit, i + offset)); } else { - vbox->add_child(prop); + + Button *remove = memnew(Button); + remove->set_icon(get_icon("Remove", "EditorIcons")); + remove->connect("pressed", this, "_remove_pressed", varray(i + offset)); + hb->add_child(remove); } prop->update_property(); @@ -388,8 +399,21 @@ void EditorPropertyArray::update_property() { #endif } -void EditorPropertyArray::_notification(int p_what) { +void EditorPropertyArray::_remove_pressed(int p_index) { + Variant array = object->get_array(); + array.call("remove", p_index); + + if (array.get_type() == Variant::ARRAY) { + array = array.call("duplicate"); + } + + emit_changed(get_edited_property(), array, "", false); + object->set_array(array); + update_property(); +} + +void EditorPropertyArray::_notification(int p_what) { if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED) { } } @@ -476,6 +500,7 @@ void EditorPropertyArray::_bind_methods() { ClassDB::bind_method("_change_type", &EditorPropertyArray::_change_type); ClassDB::bind_method("_change_type_menu", &EditorPropertyArray::_change_type_menu); ClassDB::bind_method("_object_id_selected", &EditorPropertyArray::_object_id_selected); + ClassDB::bind_method("_remove_pressed", &EditorPropertyArray::_remove_pressed); } EditorPropertyArray::EditorPropertyArray() { @@ -498,11 +523,13 @@ EditorPropertyArray::EditorPropertyArray() { change_type = memnew(PopupMenu); add_child(change_type); change_type->connect("id_pressed", this, "_change_type_menu"); - changing_type_idx = -1; + for (int i = 0; i < Variant::VARIANT_MAX; i++) { String type = Variant::get_type_name(Variant::Type(i)); change_type->add_item(type, i); } + change_type->add_separator(); + change_type->add_item(TTR("Remove Item"), Variant::VARIANT_MAX); changing_type_idx = -1; subtype = Variant::NIL; @@ -995,7 +1022,7 @@ EditorPropertyDictionary::EditorPropertyDictionary() { change_type = memnew(PopupMenu); add_child(change_type); change_type->connect("id_pressed", this, "_change_type_menu"); - changing_type_idx = -1; + for (int i = 0; i < Variant::VARIANT_MAX; i++) { String type = Variant::get_type_name(Variant::Type(i)); change_type->add_item(type, i); diff --git a/editor/editor_properties_array_dict.h b/editor/editor_properties_array_dict.h index 18519c754a..2fe7c07d56 100644 --- a/editor/editor_properties_array_dict.h +++ b/editor/editor_properties_array_dict.h @@ -105,6 +105,7 @@ class EditorPropertyArray : public EditorProperty { void _change_type_menu(int p_index); void _object_id_selected(const String &p_property, ObjectID p_id); + void _remove_pressed(int p_index); protected: static void _bind_methods(); diff --git a/editor/editor_resource_preview.cpp b/editor/editor_resource_preview.cpp index 6cca0a0ffa..f2e4d1086b 100644 --- a/editor/editor_resource_preview.cpp +++ b/editor/editor_resource_preview.cpp @@ -218,6 +218,7 @@ void EditorResourcePreview::_generate_preview(Ref<ImageTexture> &r_texture, Ref< void EditorResourcePreview::_thread() { #ifndef SERVER_ENABLED + exited = false; while (!exit) { preview_sem->wait(); @@ -452,8 +453,8 @@ void EditorResourcePreview::check_for_invalidation(const String &p_path) { void EditorResourcePreview::start() { ERR_FAIL_COND(thread); thread = Thread::create(_thread_func, this); - exited = false; } + void EditorResourcePreview::stop() { if (thread) { exit = true; diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp index a36163f661..ecc63b1a8d 100644 --- a/editor/editor_settings.cpp +++ b/editor/editor_settings.cpp @@ -938,7 +938,7 @@ fail: Vector<String> list = extra_config->get_value("init_projects", "list"); for (int i = 0; i < list.size(); i++) { - list.write[i] = exe_path + "/" + list[i]; + list.write[i] = exe_path.plus_file(list[i]); }; extra_config->set_value("init_projects", "list", list); }; diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp index 83e529ac35..9301d8c1a4 100644 --- a/editor/filesystem_dock.cpp +++ b/editor/filesystem_dock.cpp @@ -1329,7 +1329,7 @@ void FileSystemDock::_duplicate_operation_confirm() { if (to_duplicate.is_file) { new_path = base_dir.plus_file(new_name); } else { - new_path = base_dir.substr(0, base_dir.find_last("/")) + "/" + new_name; + new_path = base_dir.substr(0, base_dir.find_last("/")).plus_file(new_name); } //Present a more user friendly warning for name conflict diff --git a/editor/groups_editor.cpp b/editor/groups_editor.cpp index 3cf3bbf0f2..5a8dc205c2 100644 --- a/editor/groups_editor.cpp +++ b/editor/groups_editor.cpp @@ -59,7 +59,7 @@ void GroupDialog::_group_selected() { void GroupDialog::_load_nodes(Node *p_current) { String item_name = p_current->get_name(); if (p_current != scene_tree->get_edited_scene_root()) { - item_name = String(p_current->get_parent()->get_name()) + "/" + String(item_name); + item_name = String(p_current->get_parent()->get_name()) + "/" + item_name; } bool keep = true; @@ -69,7 +69,7 @@ void GroupDialog::_load_nodes(Node *p_current) { keep = false; } - TreeItem *node; + TreeItem *node = NULL; NodePath path = scene_tree->get_edited_scene_root()->get_path_to(p_current); if (keep && p_current->is_in_group(selected_group)) { if (remove_filter->get_text().is_subsequence_ofi(String(p_current->get_name()))) { diff --git a/editor/plugins/collision_shape_2d_editor_plugin.h b/editor/plugins/collision_shape_2d_editor_plugin.h index 965e6c8827..10a1a6bd98 100644 --- a/editor/plugins/collision_shape_2d_editor_plugin.h +++ b/editor/plugins/collision_shape_2d_editor_plugin.h @@ -89,7 +89,7 @@ class CollisionShape2DEditorPlugin : public EditorPlugin { public: virtual bool forward_canvas_gui_input(const Ref<InputEvent> &p_event) { return collision_shape_2d_editor->forward_canvas_gui_input(p_event); } - virtual void forward_canvas_draw_over_viewport(Control *p_overlay) { return collision_shape_2d_editor->forward_canvas_draw_over_viewport(p_overlay); } + virtual void forward_canvas_draw_over_viewport(Control *p_overlay) { collision_shape_2d_editor->forward_canvas_draw_over_viewport(p_overlay); } virtual String get_name() const { return "CollisionShape2D"; } bool has_main_screen() const { return false; } diff --git a/editor/plugins/curve_editor_plugin.cpp b/editor/plugins/curve_editor_plugin.cpp index 3b1d728b8b..d2d2b8f130 100644 --- a/editor/plugins/curve_editor_plugin.cpp +++ b/editor/plugins/curve_editor_plugin.cpp @@ -156,9 +156,9 @@ void CurveEditor::on_gui_input(const Ref<InputEvent> &p_event) { Vector2 mpos = mm.get_position(); if (_dragging && _curve_ref.is_valid()) { - Curve &curve = **_curve_ref; if (_selected_point != -1) { + Curve &curve = **_curve_ref; if (!_has_undo_data) { // Save full curve state before dragging points, diff --git a/editor/plugins/path_2d_editor_plugin.h b/editor/plugins/path_2d_editor_plugin.h index 4edd17d146..44472f7a81 100644 --- a/editor/plugins/path_2d_editor_plugin.h +++ b/editor/plugins/path_2d_editor_plugin.h @@ -123,7 +123,7 @@ class Path2DEditorPlugin : public EditorPlugin { public: virtual bool forward_canvas_gui_input(const Ref<InputEvent> &p_event) { return path2d_editor->forward_gui_input(p_event); } - virtual void forward_canvas_draw_over_viewport(Control *p_overlay) { return path2d_editor->forward_canvas_draw_over_viewport(p_overlay); } + virtual void forward_canvas_draw_over_viewport(Control *p_overlay) { path2d_editor->forward_canvas_draw_over_viewport(p_overlay); } virtual String get_name() const { return "Path2D"; } bool has_main_screen() const { return false; } diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp index 1b00889e9a..d999f3189e 100644 --- a/editor/plugins/script_editor_plugin.cpp +++ b/editor/plugins/script_editor_plugin.cpp @@ -3463,7 +3463,7 @@ void ScriptEditorPlugin::get_window_layout(Ref<ConfigFile> p_layout) { void ScriptEditorPlugin::get_breakpoints(List<String> *p_breakpoints) { - return script_editor->get_breakpoints(p_breakpoints); + script_editor->get_breakpoints(p_breakpoints); } void ScriptEditorPlugin::edited_scene_changed() { diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp index 9bf3a9f0eb..f705970d79 100644 --- a/editor/plugins/script_text_editor.cpp +++ b/editor/plugins/script_text_editor.cpp @@ -574,8 +574,8 @@ void ScriptTextEditor::_validate_script() { Connection connection = E->get(); String base_path = base->get_name(); - String source_path = base == connection.source ? base_path : base_path + "/" + String(base->get_path_to(Object::cast_to<Node>(connection.source))); - String target_path = base == connection.target ? base_path : base_path + "/" + String(base->get_path_to(Object::cast_to<Node>(connection.target))); + String source_path = base == connection.source ? base_path : base_path + "/" + base->get_path_to(Object::cast_to<Node>(connection.source)); + String target_path = base == connection.target ? base_path : base_path + "/" + base->get_path_to(Object::cast_to<Node>(connection.target)); warnings_panel->push_cell(); warnings_panel->push_color(warnings_panel->get_color("warning_color", "Editor")); @@ -644,6 +644,43 @@ void ScriptTextEditor::_validate_script() { emit_signal("edited_script_changed"); } +void ScriptTextEditor::_update_bookmark_list() { + + bookmarks_menu->get_popup()->clear(); + + bookmarks_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/toggle_bookmark"), BOOKMARK_TOGGLE); + bookmarks_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/remove_all_bookmarks"), BOOKMARK_REMOVE_ALL); + bookmarks_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/goto_next_bookmark"), BOOKMARK_GOTO_NEXT); + bookmarks_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/goto_previous_bookmark"), BOOKMARK_GOTO_PREV); + + Array bookmark_list = code_editor->get_text_edit()->get_bookmarks_array(); + if (bookmark_list.size() == 0) { + return; + } + + bookmarks_menu->get_popup()->add_separator(); + + for (int i = 0; i < bookmark_list.size(); i++) { + String line = code_editor->get_text_edit()->get_line(bookmark_list[i]).strip_edges(); + // Limit the size of the line if too big. + if (line.length() > 50) { + line = line.substr(0, 50); + } + + bookmarks_menu->get_popup()->add_item(String::num((int)bookmark_list[i] + 1) + " - \"" + line + "\""); + bookmarks_menu->get_popup()->set_item_metadata(bookmarks_menu->get_popup()->get_item_count() - 1, bookmark_list[i]); + } +} + +void ScriptTextEditor::_bookmark_item_pressed(int p_idx) { + + if (p_idx < 4) { // Any item before the separator. + _edit_option(bookmarks_menu->get_popup()->get_item_id(p_idx)); + } else { + code_editor->goto_line(bookmarks_menu->get_popup()->get_item_metadata(p_idx)); + } +} + static Vector<Node *> _find_all_node_for_script(Node *p_base, Node *p_current, const Ref<Script> &p_script) { Vector<Node *> nodes; @@ -1092,7 +1129,7 @@ void ScriptTextEditor::_edit_option(int p_op) { String selected_text = code_editor->get_text_edit()->get_selection_text(); // Yep, because it doesn't make sense to instance this dialog for every single script open... - // So this will be delegated to the ScriptEditor + // So this will be delegated to the ScriptEditor. emit_signal("search_in_files_requested", selected_text); } break; @@ -1258,6 +1295,8 @@ void ScriptTextEditor::_change_syntax_highlighter(int p_idx) { void ScriptTextEditor::_bind_methods() { ClassDB::bind_method("_validate_script", &ScriptTextEditor::_validate_script); + ClassDB::bind_method("_update_bookmark_list", &ScriptTextEditor::_update_bookmark_list); + ClassDB::bind_method("_bookmark_item_pressed", &ScriptTextEditor::_bookmark_item_pressed); ClassDB::bind_method("_load_theme_settings", &ScriptTextEditor::_load_theme_settings); ClassDB::bind_method("_breakpoint_toggled", &ScriptTextEditor::_breakpoint_toggled); ClassDB::bind_method("_lookup_connections", &ScriptTextEditor::_lookup_connections); @@ -1708,18 +1747,16 @@ ScriptTextEditor::ScriptTextEditor() { search_menu->get_popup()->connect("id_pressed", this, "_edit_option"); - PopupMenu *bookmarks = memnew(PopupMenu); - bookmarks->set_name("bookmarks"); - edit_menu->get_popup()->add_child(bookmarks); - edit_menu->get_popup()->add_submenu_item(TTR("Bookmarks"), "bookmarks"); - bookmarks->add_shortcut(ED_GET_SHORTCUT("script_text_editor/toggle_bookmark"), BOOKMARK_TOGGLE); - bookmarks->add_shortcut(ED_GET_SHORTCUT("script_text_editor/remove_all_bookmarks"), BOOKMARK_REMOVE_ALL); - bookmarks->add_shortcut(ED_GET_SHORTCUT("script_text_editor/goto_next_bookmark"), BOOKMARK_GOTO_NEXT); - bookmarks->add_shortcut(ED_GET_SHORTCUT("script_text_editor/goto_previous_bookmark"), BOOKMARK_GOTO_PREV); - bookmarks->connect("id_pressed", this, "_edit_option"); - edit_hb->add_child(edit_menu); + bookmarks_menu = memnew(MenuButton); + edit_hb->add_child(bookmarks_menu); + bookmarks_menu->set_text(TTR("Bookmarks")); + bookmarks_menu->set_switch_on_hover(true); + _update_bookmark_list(); + bookmarks_menu->connect("about_to_show", this, "_update_bookmark_list"); + bookmarks_menu->get_popup()->connect("index_pressed", this, "_bookmark_item_pressed"); + quick_open = memnew(ScriptEditorQuickOpen); add_child(quick_open); quick_open->connect("goto_line", this, "_goto_line"); diff --git a/editor/plugins/script_text_editor.h b/editor/plugins/script_text_editor.h index 89975e061e..f83f1ea759 100644 --- a/editor/plugins/script_text_editor.h +++ b/editor/plugins/script_text_editor.h @@ -70,6 +70,7 @@ class ScriptTextEditor : public ScriptEditorBase { MenuButton *edit_menu; MenuButton *search_menu; + MenuButton *bookmarks_menu; PopupMenu *highlighter_menu; PopupMenu *context_menu; @@ -144,8 +145,9 @@ protected: static void _code_complete_scripts(void *p_ud, const String &p_code, List<String> *r_options, bool &r_force); void _breakpoint_toggled(int p_row); - //no longer virtual - void _validate_script(); + void _validate_script(); // No longer virtual. + void _update_bookmark_list(); + void _bookmark_item_pressed(int p_idx); void _code_complete_script(const String &p_code, List<String> *r_options, bool &r_force); void _load_theme_settings(); void _set_theme_for_script(); diff --git a/editor/plugins/shader_editor_plugin.cpp b/editor/plugins/shader_editor_plugin.cpp index d02817f6e8..04d13f0027 100644 --- a/editor/plugins/shader_editor_plugin.cpp +++ b/editor/plugins/shader_editor_plugin.cpp @@ -386,6 +386,9 @@ void ShaderEditor::_bind_methods() { ClassDB::bind_method("_editor_settings_changed", &ShaderEditor::_editor_settings_changed); ClassDB::bind_method("_text_edit_gui_input", &ShaderEditor::_text_edit_gui_input); + ClassDB::bind_method("_update_bookmark_list", &ShaderEditor::_update_bookmark_list); + ClassDB::bind_method("_bookmark_item_pressed", &ShaderEditor::_bookmark_item_pressed); + ClassDB::bind_method("_menu_option", &ShaderEditor::_menu_option); ClassDB::bind_method("_params_changed", &ShaderEditor::_params_changed); ClassDB::bind_method("apply_shaders", &ShaderEditor::apply_shaders); @@ -521,6 +524,43 @@ void ShaderEditor::_text_edit_gui_input(const Ref<InputEvent> &ev) { } } +void ShaderEditor::_update_bookmark_list() { + + bookmarks_menu->get_popup()->clear(); + + bookmarks_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/toggle_bookmark"), BOOKMARK_TOGGLE); + bookmarks_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/remove_all_bookmarks"), BOOKMARK_REMOVE_ALL); + bookmarks_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/goto_next_bookmark"), BOOKMARK_GOTO_NEXT); + bookmarks_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/goto_previous_bookmark"), BOOKMARK_GOTO_PREV); + + Array bookmark_list = shader_editor->get_text_edit()->get_bookmarks_array(); + if (bookmark_list.size() == 0) { + return; + } + + bookmarks_menu->get_popup()->add_separator(); + + for (int i = 0; i < bookmark_list.size(); i++) { + String line = shader_editor->get_text_edit()->get_line(bookmark_list[i]).strip_edges(); + // Limit the size of the line if too big. + if (line.length() > 50) { + line = line.substr(0, 50); + } + + bookmarks_menu->get_popup()->add_item(String::num((int)bookmark_list[i] + 1) + " - \"" + line + "\""); + bookmarks_menu->get_popup()->set_item_metadata(bookmarks_menu->get_popup()->get_item_count() - 1, bookmark_list[i]); + } +} + +void ShaderEditor::_bookmark_item_pressed(int p_idx) { + + if (p_idx < 4) { // Any item before the separator. + _menu_option(bookmarks_menu->get_popup()->get_item_id(p_idx)); + } else { + shader_editor->goto_line(bookmarks_menu->get_popup()->get_item_metadata(p_idx)); + } +} + void ShaderEditor::_make_context_menu(bool p_selection) { context_menu->clear(); @@ -539,6 +579,7 @@ void ShaderEditor::_make_context_menu(bool p_selection) { context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/indent_left"), EDIT_INDENT_LEFT); context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/indent_right"), EDIT_INDENT_RIGHT); context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/toggle_comment"), EDIT_TOGGLE_COMMENT); + context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/toggle_bookmark"), BOOKMARK_TOGGLE); context_menu->set_position(get_global_transform().xform(get_local_mouse_position())); context_menu->set_size(Vector2(1, 1)); @@ -609,20 +650,18 @@ ShaderEditor::ShaderEditor(EditorNode *p_node) { search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/goto_line"), SEARCH_GOTO_LINE); search_menu->get_popup()->connect("id_pressed", this, "_menu_option"); - PopupMenu *bookmarks = memnew(PopupMenu); - bookmarks->set_name("bookmarks"); - edit_menu->get_popup()->add_child(bookmarks); - edit_menu->get_popup()->add_submenu_item(TTR("Bookmarks"), "bookmarks"); - bookmarks->add_shortcut(ED_GET_SHORTCUT("script_text_editor/toggle_bookmark"), BOOKMARK_TOGGLE); - bookmarks->add_shortcut(ED_GET_SHORTCUT("script_text_editor/remove_all_bookmarks"), BOOKMARK_REMOVE_ALL); - bookmarks->add_shortcut(ED_GET_SHORTCUT("script_text_editor/goto_next_bookmark"), BOOKMARK_GOTO_NEXT); - bookmarks->add_shortcut(ED_GET_SHORTCUT("script_text_editor/goto_previous_bookmark"), BOOKMARK_GOTO_PREV); - bookmarks->connect("id_pressed", this, "_edit_option"); + bookmarks_menu = memnew(MenuButton); + bookmarks_menu->set_text(TTR("Bookmarks")); + bookmarks_menu->set_switch_on_hover(true); + _update_bookmark_list(); + bookmarks_menu->connect("about_to_show", this, "_update_bookmark_list"); + bookmarks_menu->get_popup()->connect("index_pressed", this, "_bookmark_item_pressed"); add_child(main_container); main_container->add_child(hbc); hbc->add_child(search_menu); hbc->add_child(edit_menu); + hbc->add_child(bookmarks_menu); hbc->add_style_override("panel", p_node->get_gui_base()->get_stylebox("ScriptEditorPanel", "EditorStyles")); main_container->add_child(shader_editor); diff --git a/editor/plugins/shader_editor_plugin.h b/editor/plugins/shader_editor_plugin.h index b56c1451ad..f01e39189f 100644 --- a/editor/plugins/shader_editor_plugin.h +++ b/editor/plugins/shader_editor_plugin.h @@ -99,6 +99,7 @@ class ShaderEditor : public PanelContainer { MenuButton *edit_menu; MenuButton *search_menu; + MenuButton *bookmarks_menu; MenuButton *settings_menu; PopupMenu *context_menu; uint64_t idle; @@ -124,6 +125,9 @@ protected: void _make_context_menu(bool p_selection); void _text_edit_gui_input(const Ref<InputEvent> &ev); + void _update_bookmark_list(); + void _bookmark_item_pressed(int p_idx); + public: void apply_shaders(); diff --git a/editor/plugins/text_editor.cpp b/editor/plugins/text_editor.cpp index 787813336d..fae88f4eb7 100644 --- a/editor/plugins/text_editor.cpp +++ b/editor/plugins/text_editor.cpp @@ -219,6 +219,43 @@ void TextEditor::_validate_script() { emit_signal("edited_script_changed"); } +void TextEditor::_update_bookmark_list() { + + bookmarks_menu->get_popup()->clear(); + + bookmarks_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/toggle_bookmark"), BOOKMARK_TOGGLE); + bookmarks_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/remove_all_bookmarks"), BOOKMARK_REMOVE_ALL); + bookmarks_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/goto_next_bookmark"), BOOKMARK_GOTO_NEXT); + bookmarks_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/goto_previous_bookmark"), BOOKMARK_GOTO_PREV); + + Array bookmark_list = code_editor->get_text_edit()->get_bookmarks_array(); + if (bookmark_list.size() == 0) { + return; + } + + bookmarks_menu->get_popup()->add_separator(); + + for (int i = 0; i < bookmark_list.size(); i++) { + String line = code_editor->get_text_edit()->get_line(bookmark_list[i]).strip_edges(); + // Limit the size of the line if too big. + if (line.length() > 50) { + line = line.substr(0, 50); + } + + bookmarks_menu->get_popup()->add_item(String::num((int)bookmark_list[i] + 1) + " - \"" + line + "\""); + bookmarks_menu->get_popup()->set_item_metadata(bookmarks_menu->get_popup()->get_item_count() - 1, bookmark_list[i]); + } +} + +void TextEditor::_bookmark_item_pressed(int p_idx) { + + if (p_idx < 4) { // Any item before the separator. + _edit_option(bookmarks_menu->get_popup()->get_item_id(p_idx)); + } else { + code_editor->goto_line(bookmarks_menu->get_popup()->get_item_metadata(p_idx)); + } +} + void TextEditor::apply_code() { text_file->set_text(code_editor->get_text_edit()->get_text()); } @@ -471,6 +508,8 @@ void TextEditor::_convert_case(CodeTextEditor::CaseStyle p_case) { void TextEditor::_bind_methods() { ClassDB::bind_method("_validate_script", &TextEditor::_validate_script); + ClassDB::bind_method("_update_bookmark_list", &TextEditor::_update_bookmark_list); + ClassDB::bind_method("_bookmark_item_pressed", &TextEditor::_bookmark_item_pressed); ClassDB::bind_method("_load_theme_settings", &TextEditor::_load_theme_settings); ClassDB::bind_method("_edit_option", &TextEditor::_edit_option); ClassDB::bind_method("_change_syntax_highlighter", &TextEditor::_change_syntax_highlighter); @@ -547,6 +586,7 @@ void TextEditor::_make_context_menu(bool p_selection, bool p_can_fold, bool p_is context_menu->add_separator(); context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/indent_left"), EDIT_INDENT_LEFT); context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/indent_right"), EDIT_INDENT_RIGHT); + context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/toggle_bookmark"), BOOKMARK_TOGGLE); if (p_selection) { context_menu->add_separator(); @@ -584,6 +624,7 @@ TextEditor::TextEditor() { search_menu = memnew(MenuButton); edit_hb->add_child(search_menu); search_menu->set_text(TTR("Search")); + search_menu->set_switch_on_hover(true); search_menu->get_popup()->connect("id_pressed", this, "_edit_option"); search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/find"), SEARCH_FIND); @@ -598,6 +639,7 @@ TextEditor::TextEditor() { edit_menu = memnew(MenuButton); edit_menu->set_text(TTR("Edit")); + edit_menu->set_switch_on_hover(true); edit_menu->get_popup()->connect("id_pressed", this, "_edit_option"); edit_hb->add_child(edit_menu); @@ -642,15 +684,13 @@ TextEditor::TextEditor() { highlighter_menu->add_radio_check_item(TTR("Standard")); highlighter_menu->connect("id_pressed", this, "_change_syntax_highlighter"); - PopupMenu *bookmarks = memnew(PopupMenu); - bookmarks->set_name("bookmarks"); - edit_menu->get_popup()->add_child(bookmarks); - edit_menu->get_popup()->add_submenu_item(TTR("Bookmarks"), "bookmarks"); - bookmarks->add_shortcut(ED_GET_SHORTCUT("script_text_editor/toggle_bookmark"), BOOKMARK_TOGGLE); - bookmarks->add_shortcut(ED_GET_SHORTCUT("script_text_editor/remove_all_bookmarks"), BOOKMARK_REMOVE_ALL); - bookmarks->add_shortcut(ED_GET_SHORTCUT("script_text_editor/goto_next_bookmark"), BOOKMARK_GOTO_NEXT); - bookmarks->add_shortcut(ED_GET_SHORTCUT("script_text_editor/goto_previous_bookmark"), BOOKMARK_GOTO_PREV); - bookmarks->connect("id_pressed", this, "_edit_option"); + bookmarks_menu = memnew(MenuButton); + edit_hb->add_child(bookmarks_menu); + bookmarks_menu->set_text(TTR("Bookmarks")); + bookmarks_menu->set_switch_on_hover(true); + _update_bookmark_list(); + bookmarks_menu->connect("about_to_show", this, "_update_bookmark_list"); + bookmarks_menu->get_popup()->connect("index_pressed", this, "_bookmark_item_pressed"); code_editor->get_text_edit()->set_drag_forwarding(this); } diff --git a/editor/plugins/text_editor.h b/editor/plugins/text_editor.h index 277e93fd39..ae0c0bcf93 100644 --- a/editor/plugins/text_editor.h +++ b/editor/plugins/text_editor.h @@ -46,6 +46,7 @@ private: MenuButton *edit_menu; PopupMenu *highlighter_menu; MenuButton *search_menu; + MenuButton *bookmarks_menu; PopupMenu *context_menu; GotoLineDialog *goto_line_dialog; @@ -110,6 +111,9 @@ protected: void _validate_script(); + void _update_bookmark_list(); + void _bookmark_item_pressed(int p_idx); + public: virtual void add_syntax_highlighter(SyntaxHighlighter *p_highlighter); virtual void set_syntax_highlighter(SyntaxHighlighter *p_highlighter); diff --git a/editor/plugins/texture_region_editor_plugin.cpp b/editor/plugins/texture_region_editor_plugin.cpp index 4e15bd5116..8f58fbd6ab 100644 --- a/editor/plugins/texture_region_editor_plugin.cpp +++ b/editor/plugins/texture_region_editor_plugin.cpp @@ -192,8 +192,8 @@ void TextureRegionEditor::_region_draw() { } updating_scroll = false; - float margins[4]; if (node_ninepatch || obj_styleBox.is_valid()) { + float margins[4]; if (node_ninepatch) { margins[0] = node_ninepatch->get_patch_margin(MARGIN_TOP); margins[1] = node_ninepatch->get_patch_margin(MARGIN_BOTTOM); @@ -204,6 +204,11 @@ void TextureRegionEditor::_region_draw() { margins[1] = obj_styleBox->get_margin_size(MARGIN_BOTTOM); margins[2] = obj_styleBox->get_margin_size(MARGIN_LEFT); margins[3] = obj_styleBox->get_margin_size(MARGIN_RIGHT); + } else { + margins[0] = 0; + margins[1] = 0; + margins[2] = 0; + margins[3] = 0; } Vector2 pos[4] = { mtx.basis_xform(Vector2(0, margins[0])) + Vector2(0, endpoints[0].y - draw_ofs.y * draw_zoom), diff --git a/editor/project_export.cpp b/editor/project_export.cpp index 956da92c35..c78a81dbe0 100644 --- a/editor/project_export.cpp +++ b/editor/project_export.cpp @@ -931,8 +931,17 @@ void ProjectExportDialog::_export_project() { export_project->add_filter("*." + extension_list[i] + " ; " + platform->get_name() + " Export"); } - if (current->get_export_path() != "") { - export_project->set_current_path(current->get_export_path()); + String current_preset_export_path = current->get_export_path(); + + if (current_preset_export_path != "") { + + if (!DirAccess::exists(current_preset_export_path.get_base_dir())) { + + DirAccessRef da(DirAccess::create(DirAccess::ACCESS_FILESYSTEM)); + da->make_dir_recursive(current_preset_export_path.get_base_dir()); + } + + export_project->set_current_path(current_preset_export_path); } else { if (extension_list.size() >= 1) { export_project->set_current_file(default_filename + "." + extension_list[0]); diff --git a/editor/project_settings_editor.cpp b/editor/project_settings_editor.cpp index df0dd8781e..001846604c 100644 --- a/editor/project_settings_editor.cpp +++ b/editor/project_settings_editor.cpp @@ -42,10 +42,10 @@ ProjectSettingsEditor *ProjectSettingsEditor::singleton = NULL; static const char *_button_names[JOY_BUTTON_MAX] = { - "PS Cross, XBox A, Nintendo B", - "PS Circle, XBox B, Nintendo A", - "PS Square, XBox X, Nintendo Y", - "PS Triangle, XBox Y, Nintendo X", + "DualShock Cross, Xbox A, Nintendo B", + "DualShock Circle, Xbox B, Nintendo A", + "DualShock Square, Xbox X, Nintendo Y", + "DualShock Triangle, Xbox Y, Nintendo X", "L, L1", "R, R1", "L2", @@ -257,7 +257,7 @@ void ProjectSettingsEditor::_device_input_add() { Ref<InputEventJoypadMotion> jm; jm.instance(); jm->set_axis(device_index->get_selected() >> 1); - jm->set_axis_value(device_index->get_selected() & 1 ? 1 : -1); + jm->set_axis_value((device_index->get_selected() & 1) ? 1 : -1); jm->set_device(_get_current_device()); for (int i = 0; i < events.size(); i++) { @@ -483,7 +483,7 @@ void ProjectSettingsEditor::_add_item(int p_item, Ref<InputEvent> p_exiting_even for (int i = 0; i < JOY_AXIS_MAX * 2; i++) { String desc = _axis_names[i]; - device_index->add_item(TTR("Axis") + " " + itos(i / 2) + " " + (i & 1 ? "+" : "-") + desc); + device_index->add_item(TTR("Axis") + " " + itos(i / 2) + " " + ((i & 1) ? "+" : "-") + desc); } device_input->popup_centered_minsize(Size2(350, 95) * EDSCALE); diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp index a15ae2efda..442de08ffa 100644 --- a/editor/scene_tree_dock.cpp +++ b/editor/scene_tree_dock.cpp @@ -89,6 +89,8 @@ void SceneTreeDock::_unhandled_key_input(Ref<InputEvent> p_event) { _tool_selected(TOOL_NEW); } else if (ED_IS_SHORTCUT("scene_tree/instance_scene", p_event)) { _tool_selected(TOOL_INSTANCE); + } else if (ED_IS_SHORTCUT("scene_tree/expand_collapse_all", p_event)) { + _tool_selected(TOOL_EXPAND_COLLAPSE); } else if (ED_IS_SHORTCUT("scene_tree/change_node_type", p_event)) { _tool_selected(TOOL_REPLACE); } else if (ED_IS_SHORTCUT("scene_tree/duplicate", p_event)) { @@ -370,6 +372,23 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { quick_open->set_title(TTR("Instance Child Scene")); } break; + case TOOL_EXPAND_COLLAPSE: { + + if (!scene_tree->get_selected()) + break; + + Tree *tree = scene_tree->get_scene_tree(); + TreeItem *selected_item = tree->get_selected(); + + if (!selected_item) + selected_item = tree->get_root(); + + bool collapsed = _is_collapsed_recursive(selected_item); + _set_collapsed_recursive(selected_item, !collapsed); + + tree->ensure_cursor_is_visible(); + + } break; case TOOL_REPLACE: { if (!profile_allow_editing) { @@ -418,6 +437,8 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { } } } + script_create_dialog->connect("script_created", this, "_script_created"); + script_create_dialog->connect("popup_hide", this, "_script_creation_closed"); script_create_dialog->config(inherits, path); script_create_dialog->popup_centered(); @@ -998,6 +1019,17 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { } } +void SceneTreeDock::_node_collapsed(Object *p_obj) { + + TreeItem *ti = Object::cast_to<TreeItem>(p_obj); + if (!ti) + return; + + if (Input::get_singleton()->is_key_pressed(KEY_SHIFT)) { + _set_collapsed_recursive(ti, ti->is_collapsed()); + } +} + void SceneTreeDock::_notification(int p_what) { switch (p_what) { @@ -1030,6 +1062,7 @@ void SceneTreeDock::_notification(int p_what) { filter->set_clear_button_enabled(true); EditorNode::get_singleton()->get_editor_selection()->connect("selection_changed", this, "_selection_changed"); + scene_tree->get_scene_tree()->connect("item_collapsed", this, "_node_collapsed"); // create_root_dialog HBoxContainer *top_row = memnew(HBoxContainer); @@ -1493,7 +1526,6 @@ void SceneTreeDock::_do_reparent(Node *p_new_parent, int p_position_in_parent, V if (p_nodes.find(validate) != -1) { ERR_EXPLAIN("Selection changed at some point.. can't reparent"); ERR_FAIL(); - return; } validate = validate->get_parent(); } @@ -1624,6 +1656,52 @@ void SceneTreeDock::_do_reparent(Node *p_new_parent, int p_position_in_parent, V editor_data->get_undo_redo().commit_action(); } +bool SceneTreeDock::_is_collapsed_recursive(TreeItem *p_item) const { + + bool is_branch_collapsed = false; + + List<TreeItem *> needs_check; + needs_check.push_back(p_item); + + while (!needs_check.empty()) { + + TreeItem *item = needs_check.back()->get(); + needs_check.pop_back(); + + TreeItem *child = item->get_children(); + is_branch_collapsed = item->is_collapsed() && child; + + if (is_branch_collapsed) { + break; + } + while (child) { + needs_check.push_back(child); + child = child->get_next(); + } + } + return is_branch_collapsed; +} + +void SceneTreeDock::_set_collapsed_recursive(TreeItem *p_item, bool p_collapsed) { + + List<TreeItem *> to_collapse; + to_collapse.push_back(p_item); + + while (!to_collapse.empty()) { + + TreeItem *item = to_collapse.back()->get(); + to_collapse.pop_back(); + + item->set_collapsed(p_collapsed); + + TreeItem *child = item->get_children(); + while (child) { + to_collapse.push_back(child); + child = child->get_next(); + } + } +} + void SceneTreeDock::_script_created(Ref<Script> p_script) { List<Node *> selected = editor_selection->get_selected_node_list(); @@ -1647,6 +1725,11 @@ void SceneTreeDock::_script_created(Ref<Script> p_script) { _update_script_button(); } +void SceneTreeDock::_script_creation_closed() { + script_create_dialog->disconnect("script_created", this, "_script_created"); + script_create_dialog->disconnect("popup_hide", this, "_script_creation_closed"); +} + void SceneTreeDock::_toggle_editable_children_from_selection() { List<Node *> selection = editor_selection->get_selected_node_list(); @@ -2238,8 +2321,10 @@ void SceneTreeDock::_tree_rmb(const Vector2 &p_menu_pos) { menu->add_icon_shortcut(get_icon("Add", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/add_child_node"), TOOL_NEW); menu->add_icon_shortcut(get_icon("Instance", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/instance_scene"), TOOL_INSTANCE); - menu->add_separator(); } + menu->add_icon_shortcut(get_icon("Collapse", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/expand_collapse_all"), TOOL_EXPAND_COLLAPSE); + menu->add_separator(); + existing_script = selected->get_script(); } @@ -2506,6 +2591,7 @@ void SceneTreeDock::_bind_methods() { ClassDB::bind_method(D_METHOD("_node_selected"), &SceneTreeDock::_node_selected); ClassDB::bind_method(D_METHOD("_node_renamed"), &SceneTreeDock::_node_renamed); ClassDB::bind_method(D_METHOD("_script_created"), &SceneTreeDock::_script_created); + ClassDB::bind_method(D_METHOD("_script_creation_closed"), &SceneTreeDock::_script_creation_closed); ClassDB::bind_method(D_METHOD("_load_request"), &SceneTreeDock::_load_request); ClassDB::bind_method(D_METHOD("_script_open_request"), &SceneTreeDock::_script_open_request); ClassDB::bind_method(D_METHOD("_unhandled_key_input"), &SceneTreeDock::_unhandled_key_input); @@ -2516,6 +2602,7 @@ void SceneTreeDock::_bind_methods() { ClassDB::bind_method(D_METHOD("_node_prerenamed"), &SceneTreeDock::_node_prerenamed); ClassDB::bind_method(D_METHOD("_import_subscene"), &SceneTreeDock::_import_subscene); ClassDB::bind_method(D_METHOD("_selection_changed"), &SceneTreeDock::_selection_changed); + ClassDB::bind_method(D_METHOD("_node_collapsed"), &SceneTreeDock::_node_collapsed); ClassDB::bind_method(D_METHOD("_new_scene_from"), &SceneTreeDock::_new_scene_from); ClassDB::bind_method(D_METHOD("_nodes_dragged"), &SceneTreeDock::_nodes_dragged); ClassDB::bind_method(D_METHOD("_files_dropped"), &SceneTreeDock::_files_dropped); @@ -2555,6 +2642,7 @@ SceneTreeDock::SceneTreeDock(EditorNode *p_editor, Node *p_scene_root, EditorSel ED_SHORTCUT("scene_tree/batch_rename", TTR("Batch Rename"), KEY_MASK_CMD | KEY_F2); ED_SHORTCUT("scene_tree/add_child_node", TTR("Add Child Node"), KEY_MASK_CMD | KEY_A); ED_SHORTCUT("scene_tree/instance_scene", TTR("Instance Child Scene")); + ED_SHORTCUT("scene_tree/expand_collapse_all", TTR("Expand/Collapse All")); ED_SHORTCUT("scene_tree/change_node_type", TTR("Change Type")); ED_SHORTCUT("scene_tree/attach_script", TTR("Attach Script")); ED_SHORTCUT("scene_tree/extend_script", TTR("Extend Script")); @@ -2572,7 +2660,7 @@ SceneTreeDock::SceneTreeDock(EditorNode *p_editor, Node *p_scene_root, EditorSel button_add = memnew(ToolButton); button_add->connect("pressed", this, "_tool_selected", make_binds(TOOL_NEW, false)); - button_add->set_tooltip(TTR("Add/Create a New Node")); + button_add->set_tooltip(TTR("Add/Create a New Node.")); button_add->set_shortcut(ED_GET_SHORTCUT("scene_tree/add_child_node")); filter_hbc->add_child(button_add); @@ -2661,7 +2749,6 @@ SceneTreeDock::SceneTreeDock(EditorNode *p_editor, Node *p_scene_root, EditorSel script_create_dialog = memnew(ScriptCreateDialog); script_create_dialog->set_inheritance_base_type("Node"); add_child(script_create_dialog); - script_create_dialog->connect("script_created", this, "_script_created"); reparent_dialog = memnew(ReparentDialog); add_child(reparent_dialog); diff --git a/editor/scene_tree_dock.h b/editor/scene_tree_dock.h index b645c22295..3729e27ce6 100644 --- a/editor/scene_tree_dock.h +++ b/editor/scene_tree_dock.h @@ -60,6 +60,7 @@ class SceneTreeDock : public VBoxContainer { TOOL_NEW, TOOL_INSTANCE, + TOOL_EXPAND_COLLAPSE, TOOL_RENAME, TOOL_BATCH_RENAME, TOOL_REPLACE, @@ -116,6 +117,7 @@ class SceneTreeDock : public VBoxContainer { HBoxContainer *tool_hbc; void _tool_selected(int p_tool, bool p_confirm_override = false); + void _node_collapsed(Object *p_obj); EditorData *editor_data; EditorSelection *editor_selection; @@ -152,6 +154,9 @@ class SceneTreeDock : public VBoxContainer { void _node_reparent(NodePath p_path, bool p_keep_global_xform); void _do_reparent(Node *p_new_parent, int p_position_in_parent, Vector<Node *> p_nodes, bool p_keep_global_xform); + bool _is_collapsed_recursive(TreeItem *p_item) const; + void _set_collapsed_recursive(TreeItem *p_item, bool p_collapsed); + void _set_owners(Node *p_owner, const Array &p_nodes); enum ReplaceOwnerMode { @@ -170,6 +175,7 @@ class SceneTreeDock : public VBoxContainer { void _node_selected(); void _node_renamed(); void _script_created(Ref<Script> p_script); + void _script_creation_closed(); void _delete_confirm(); diff --git a/editor/script_create_dialog.cpp b/editor/script_create_dialog.cpp index ffa221edaf..8916f4d8c4 100644 --- a/editor/script_create_dialog.cpp +++ b/editor/script_create_dialog.cpp @@ -286,8 +286,8 @@ void ScriptCreateDialog::_create_new() { } } - hide(); emit_signal("script_created", scr); + hide(); } void ScriptCreateDialog::_load_exist() { @@ -300,8 +300,8 @@ void ScriptCreateDialog::_load_exist() { return; } - hide(); emit_signal("script_created", p_script.get_ref_ptr()); + hide(); } void ScriptCreateDialog::_lang_changed(int l) { diff --git a/editor/script_editor_debugger.cpp b/editor/script_editor_debugger.cpp index 00c8ed6ad3..8fd1064427 100644 --- a/editor/script_editor_debugger.cpp +++ b/editor/script_editor_debugger.cpp @@ -626,8 +626,7 @@ void ScriptEditorDebugger::_parse_message(const String &p_msg, const Array &p_da d["frame"] = i; s->set_metadata(0, d); - //String line = itos(i)+" - "+String(d["file"])+":"+itos(d["line"])+" - at func: "+d["function"]; - String line = itos(i) + " - " + String(d["file"]) + ":" + itos(d["line"]); + String line = itos(i) + " - " + String(d["file"]) + ":" + itos(d["line"]) + " - at function: " + d["function"]; s->set_text(0, line); if (i == 0) diff --git a/editor/spatial_editor_gizmos.cpp b/editor/spatial_editor_gizmos.cpp index fc4ff2ecfc..fe6d9dd8c7 100644 --- a/editor/spatial_editor_gizmos.cpp +++ b/editor/spatial_editor_gizmos.cpp @@ -147,7 +147,7 @@ void EditorSpatialGizmo::set_handle(int p_idx, Camera *p_camera, const Point2 &p } ERR_FAIL_COND(!gizmo_plugin); - return gizmo_plugin->set_handle(this, p_idx, p_camera, p_point); + gizmo_plugin->set_handle(this, p_idx, p_camera, p_point); } void EditorSpatialGizmo::commit_handle(int p_idx, const Variant &p_restore, bool p_cancel) { @@ -158,7 +158,7 @@ void EditorSpatialGizmo::commit_handle(int p_idx, const Variant &p_restore, bool } ERR_FAIL_COND(!gizmo_plugin); - return gizmo_plugin->commit_handle(this, p_idx, p_restore, p_cancel); + gizmo_plugin->commit_handle(this, p_idx, p_restore, p_cancel); } void EditorSpatialGizmo::set_spatial_node(Spatial *p_node) { diff --git a/main/main.cpp b/main/main.cpp index 815e940a0a..3f84eca1d2 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -1709,13 +1709,13 @@ bool Main::start() { if (sep == -1) { DirAccess *da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); - local_game_path = da->get_current_dir() + "/" + local_game_path; + local_game_path = da->get_current_dir().plus_file(local_game_path); memdelete(da); } else { DirAccess *da = DirAccess::open(local_game_path.substr(0, sep)); if (da) { - local_game_path = da->get_current_dir() + "/" + local_game_path.substr(sep + 1, local_game_path.length()); + local_game_path = da->get_current_dir().plus_file(local_game_path.substr(sep + 1, local_game_path.length())); memdelete(da); } } diff --git a/modules/assimp/editor_scene_importer_assimp.cpp b/modules/assimp/editor_scene_importer_assimp.cpp index 8c3c04674b..093e2f3006 100644 --- a/modules/assimp/editor_scene_importer_assimp.cpp +++ b/modules/assimp/editor_scene_importer_assimp.cpp @@ -848,7 +848,7 @@ Ref<Material> EditorSceneImporterAssimp::_generate_material_from_index(ImportSta if (AI_SUCCESS == ai_material->GetTexture(tex_normal, 0, &ai_filename, NULL, NULL, NULL, NULL, map_mode)) { filename = _assimp_raw_string_to_string(ai_filename); - String path = state.path.get_base_dir() + "/" + filename.replace("\\", "/"); + String path = state.path.get_base_dir().plus_file(filename.replace("\\", "/")); bool found = false; _find_texture_path(state.path, path, found); if (found) { @@ -869,7 +869,7 @@ Ref<Material> EditorSceneImporterAssimp::_generate_material_from_index(ImportSta if (AI_SUCCESS == ai_material->Get(AI_MATKEY_FBX_NORMAL_TEXTURE, ai_filename)) { filename = _assimp_raw_string_to_string(ai_filename); - String path = state.path.get_base_dir() + "/" + filename.replace("\\", "/"); + String path = state.path.get_base_dir().plus_file(filename.replace("\\", "/")); bool found = false; _find_texture_path(state.path, path, found); if (found) { @@ -892,7 +892,7 @@ Ref<Material> EditorSceneImporterAssimp::_generate_material_from_index(ImportSta if (AI_SUCCESS == ai_material->GetTexture(tex_emissive, 0, &ai_filename, NULL, NULL, NULL, NULL, map_mode)) { filename = _assimp_raw_string_to_string(ai_filename); - String path = state.path.get_base_dir() + "/" + filename.replace("\\", "/"); + String path = state.path.get_base_dir().plus_file(filename.replace("\\", "/")); bool found = false; _find_texture_path(state.path, path, found); if (found) { @@ -914,7 +914,7 @@ Ref<Material> EditorSceneImporterAssimp::_generate_material_from_index(ImportSta aiTextureMapMode map_mode[2]; if (AI_SUCCESS == ai_material->GetTexture(tex_albedo, 0, &ai_filename, NULL, NULL, NULL, NULL, map_mode)) { filename = _assimp_raw_string_to_string(ai_filename); - String path = state.path.get_base_dir() + "/" + filename.replace("\\", "/"); + String path = state.path.get_base_dir().plus_file(filename.replace("\\", "/")); bool found = false; _find_texture_path(state.path, path, found); if (found) { @@ -944,7 +944,7 @@ Ref<Material> EditorSceneImporterAssimp::_generate_material_from_index(ImportSta aiTextureMapMode map_mode[2]; if (AI_SUCCESS == ai_material->GetTexture(AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_BASE_COLOR_TEXTURE, &tex_gltf_base_color_path, NULL, NULL, NULL, NULL, map_mode)) { String filename = _assimp_raw_string_to_string(tex_gltf_base_color_path); - String path = state.path.get_base_dir() + "/" + filename.replace("\\", "/"); + String path = state.path.get_base_dir().plus_file(filename.replace("\\", "/")); bool found = false; _find_texture_path(state.path, path, found); if (found) { @@ -973,7 +973,7 @@ Ref<Material> EditorSceneImporterAssimp::_generate_material_from_index(ImportSta aiString tex_fbx_pbs_base_color_path = aiString(); if (AI_SUCCESS == ai_material->Get(AI_MATKEY_FBX_MAYA_BASE_COLOR_TEXTURE, tex_fbx_pbs_base_color_path)) { String filename = _assimp_raw_string_to_string(tex_fbx_pbs_base_color_path); - String path = state.path.get_base_dir() + "/" + filename.replace("\\", "/"); + String path = state.path.get_base_dir().plus_file(filename.replace("\\", "/")); bool found = false; _find_texture_path(state.path, path, found); if (found) { @@ -1005,7 +1005,7 @@ Ref<Material> EditorSceneImporterAssimp::_generate_material_from_index(ImportSta aiString tex_fbx_pbs_normal_path = aiString(); if (AI_SUCCESS == ai_material->Get(AI_MATKEY_FBX_MAYA_NORMAL_TEXTURE, tex_fbx_pbs_normal_path)) { String filename = _assimp_raw_string_to_string(tex_fbx_pbs_normal_path); - String path = state.path.get_base_dir() + "/" + filename.replace("\\", "/"); + String path = state.path.get_base_dir().plus_file(filename.replace("\\", "/")); bool found = false; _find_texture_path(state.path, path, found); if (found) { @@ -1027,7 +1027,7 @@ Ref<Material> EditorSceneImporterAssimp::_generate_material_from_index(ImportSta aiString tex_fbx_stingray_normal_path = aiString(); if (AI_SUCCESS == ai_material->Get(AI_MATKEY_FBX_MAYA_STINGRAY_NORMAL_TEXTURE, tex_fbx_stingray_normal_path)) { String filename = _assimp_raw_string_to_string(tex_fbx_stingray_normal_path); - String path = state.path.get_base_dir() + "/" + filename.replace("\\", "/"); + String path = state.path.get_base_dir().plus_file(filename.replace("\\", "/")); bool found = false; _find_texture_path(state.path, path, found); if (found) { @@ -1045,7 +1045,7 @@ Ref<Material> EditorSceneImporterAssimp::_generate_material_from_index(ImportSta aiString tex_fbx_pbs_base_color_path = aiString(); if (AI_SUCCESS == ai_material->Get(AI_MATKEY_FBX_MAYA_STINGRAY_COLOR_TEXTURE, tex_fbx_pbs_base_color_path)) { String filename = _assimp_raw_string_to_string(tex_fbx_pbs_base_color_path); - String path = state.path.get_base_dir() + "/" + filename.replace("\\", "/"); + String path = state.path.get_base_dir().plus_file(filename.replace("\\", "/")); bool found = false; _find_texture_path(state.path, path, found); if (found) { @@ -1077,7 +1077,7 @@ Ref<Material> EditorSceneImporterAssimp::_generate_material_from_index(ImportSta aiString tex_fbx_pbs_emissive_path = aiString(); if (AI_SUCCESS == ai_material->Get(AI_MATKEY_FBX_MAYA_STINGRAY_EMISSIVE_TEXTURE, tex_fbx_pbs_emissive_path)) { String filename = _assimp_raw_string_to_string(tex_fbx_pbs_emissive_path); - String path = state.path.get_base_dir() + "/" + filename.replace("\\", "/"); + String path = state.path.get_base_dir().plus_file(filename.replace("\\", "/")); bool found = false; _find_texture_path(state.path, path, found); if (found) { @@ -1107,7 +1107,7 @@ Ref<Material> EditorSceneImporterAssimp::_generate_material_from_index(ImportSta aiString tex_gltf_pbr_metallicroughness_path; if (AI_SUCCESS == ai_material->GetTexture(AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_METALLICROUGHNESS_TEXTURE, &tex_gltf_pbr_metallicroughness_path)) { String filename = _assimp_raw_string_to_string(tex_gltf_pbr_metallicroughness_path); - String path = state.path.get_base_dir() + "/" + filename.replace("\\", "/"); + String path = state.path.get_base_dir().plus_file(filename.replace("\\", "/")); bool found = false; _find_texture_path(state.path, path, found); if (found) { @@ -1134,7 +1134,7 @@ Ref<Material> EditorSceneImporterAssimp::_generate_material_from_index(ImportSta aiString tex_fbx_pbs_metallic_path; if (AI_SUCCESS == ai_material->Get(AI_MATKEY_FBX_MAYA_STINGRAY_METALLIC_TEXTURE, tex_fbx_pbs_metallic_path)) { String filename = _assimp_raw_string_to_string(tex_fbx_pbs_metallic_path); - String path = state.path.get_base_dir() + "/" + filename.replace("\\", "/"); + String path = state.path.get_base_dir().plus_file(filename.replace("\\", "/")); bool found = false; _find_texture_path(state.path, path, found); if (found) { @@ -1154,7 +1154,7 @@ Ref<Material> EditorSceneImporterAssimp::_generate_material_from_index(ImportSta aiString tex_fbx_pbs_rough_path; if (AI_SUCCESS == ai_material->Get(AI_MATKEY_FBX_MAYA_STINGRAY_ROUGHNESS_TEXTURE, tex_fbx_pbs_rough_path)) { String filename = _assimp_raw_string_to_string(tex_fbx_pbs_rough_path); - String path = state.path.get_base_dir() + "/" + filename.replace("\\", "/"); + String path = state.path.get_base_dir().plus_file(filename.replace("\\", "/")); bool found = false; _find_texture_path(state.path, path, found); if (found) { @@ -1177,7 +1177,7 @@ Ref<Material> EditorSceneImporterAssimp::_generate_material_from_index(ImportSta aiString tex_fbx_pbs_metallic_path; if (AI_SUCCESS == ai_material->Get(AI_MATKEY_FBX_MAYA_METALNESS_TEXTURE, tex_fbx_pbs_metallic_path)) { String filename = _assimp_raw_string_to_string(tex_fbx_pbs_metallic_path); - String path = state.path.get_base_dir() + "/" + filename.replace("\\", "/"); + String path = state.path.get_base_dir().plus_file(filename.replace("\\", "/")); bool found = false; _find_texture_path(state.path, path, found); if (found) { @@ -1197,7 +1197,7 @@ Ref<Material> EditorSceneImporterAssimp::_generate_material_from_index(ImportSta aiString tex_fbx_pbs_rough_path; if (AI_SUCCESS == ai_material->Get(AI_MATKEY_FBX_MAYA_DIFFUSE_ROUGHNESS_TEXTURE, tex_fbx_pbs_rough_path)) { String filename = _assimp_raw_string_to_string(tex_fbx_pbs_rough_path); - String path = state.path.get_base_dir() + "/" + filename.replace("\\", "/"); + String path = state.path.get_base_dir().plus_file(filename.replace("\\", "/")); bool found = false; _find_texture_path(state.path, path, found); if (found) { @@ -1684,7 +1684,7 @@ void EditorSceneImporterAssimp::_find_texture_path(const String &p_path, _Direct path = name; return; } - String name_ignore_sub_directory = p_path.get_base_dir() + "/" + path.get_file().get_basename() + extension; + String name_ignore_sub_directory = p_path.get_base_dir().plus_file(path.get_file().get_basename()) + extension; if (dir.file_exists(name_ignore_sub_directory)) { found = true; path = name_ignore_sub_directory; diff --git a/modules/bullet/rigid_body_bullet.cpp b/modules/bullet/rigid_body_bullet.cpp index 733a900396..085cce9733 100644 --- a/modules/bullet/rigid_body_bullet.cpp +++ b/modules/bullet/rigid_body_bullet.cpp @@ -866,7 +866,7 @@ void RigidBodyBullet::on_enter_area(AreaBullet *p_area) { if (p_area->is_spOv_gravityPoint()) { ++countGravityPointSpaces; - assert(0 < countGravityPointSpaces); + ERR_FAIL_COND(countGravityPointSpaces <= 0); } } @@ -888,7 +888,7 @@ void RigidBodyBullet::on_exit_area(AreaBullet *p_area) { if (wasTheAreaFound) { if (p_area->is_spOv_gravityPoint()) { --countGravityPointSpaces; - assert(0 <= countGravityPointSpaces); + ERR_FAIL_COND(countGravityPointSpaces < 0); } --areaWhereIamCount; diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp index 95f3c12806..bc28f7009e 100644 --- a/modules/gdscript/gdscript.cpp +++ b/modules/gdscript/gdscript.cpp @@ -332,7 +332,7 @@ ScriptInstance *GDScript::instance_create(Object *p_this) { } Variant::CallError unchecked_error; - return _create_instance(NULL, 0, p_this, Object::cast_to<Reference>(p_this), unchecked_error); + return _create_instance(NULL, 0, p_this, Object::cast_to<Reference>(p_this) != NULL, unchecked_error); } PlaceHolderScriptInstance *GDScript::placeholder_instance_create(Object *p_this) { diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp index caffe04700..4c976bd2e0 100644 --- a/modules/gdscript/gdscript_compiler.cpp +++ b/modules/gdscript/gdscript_compiler.cpp @@ -1259,8 +1259,6 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser:: ERR_FAIL_V(-1); //unreachable code } break; } - - ERR_FAIL_V(-1); //unreachable code } Error GDScriptCompiler::_parse_block(CodeGen &codegen, const GDScriptParser::BlockNode *p_block, int p_stack_level, int p_break_addr, int p_continue_addr) { diff --git a/modules/gdscript/gdscript_function.cpp b/modules/gdscript/gdscript_function.cpp index bae5eca218..d5e74c07c9 100644 --- a/modules/gdscript/gdscript_function.cpp +++ b/modules/gdscript/gdscript_function.cpp @@ -1556,14 +1556,14 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a //error // function, file, line, error, explanation String err_file; - if (p_instance) + if (p_instance && p_instance->script->is_valid() && p_instance->script->path != "") err_file = p_instance->script->path; else if (script) err_file = script->path; if (err_file == "") err_file = "<built-in>"; String err_func = name; - if (p_instance && p_instance->script->name != "") + if (p_instance && p_instance->script->is_valid() && p_instance->script->name != "") err_func = p_instance->script->name + "." + err_func; int err_line = line; if (err_text == "") { @@ -1591,15 +1591,26 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a GDScriptLanguage::get_singleton()->script_frame_time += time_taken - function_call_time; } - if (ScriptDebugger::get_singleton()) - GDScriptLanguage::get_singleton()->exit_function(); + bool yielded = retvalue.is_ref() && Object::cast_to<GDScriptFunctionState>(retvalue); + + // Check if this is the last time the function is resuming from yield + // Will be true if never yielded as well + // When it's the last resume it will postpone the exit from stack, + // so the debugger knows which function triggered the resume of the next function (if any) + if (!p_state || yielded) { + if (ScriptDebugger::get_singleton()) + GDScriptLanguage::get_singleton()->exit_function(); #endif - if (_stack_size) { - //free stack - for (int i = 0; i < _stack_size; i++) - stack[i].~Variant(); + if (_stack_size) { + //free stack + for (int i = 0; i < _stack_size; i++) + stack[i].~Variant(); + } + +#ifdef DEBUG_ENABLED } +#endif return retvalue; } @@ -1775,7 +1786,7 @@ Variant GDScriptFunctionState::_signal_callback(const Variant **p_args, int p_ar if (state.instance_id && !ObjectDB::get_instance(state.instance_id)) { #ifdef DEBUG_ENABLED - ERR_EXPLAIN("Resumed after yield, but class instance is gone"); + ERR_EXPLAIN("Resumed function '" + String(function->get_name()) + "()' after yield, but class instance is gone. At script: " + state.script->get_path() + ":" + itos(state.line)); ERR_FAIL_V(Variant()); #else return Variant(); @@ -1838,6 +1849,17 @@ Variant GDScriptFunctionState::_signal_callback(const Variant **p_args, int p_ar } } +#ifdef DEBUG_ENABLED + if (ScriptDebugger::get_singleton()) + GDScriptLanguage::get_singleton()->exit_function(); + if (state.stack_size) { + //free stack + Variant *stack = (Variant *)state.stack.ptr(); + for (int i = 0; i < state.stack_size; i++) + stack[i].~Variant(); + } +#endif + return ret; } @@ -1860,7 +1882,7 @@ Variant GDScriptFunctionState::resume(const Variant &p_arg) { ERR_FAIL_COND_V(!function, Variant()); if (state.instance_id && !ObjectDB::get_instance(state.instance_id)) { #ifdef DEBUG_ENABLED - ERR_EXPLAIN("Resumed after yield, but class instance is gone"); + ERR_EXPLAIN("Resumed function '" + String(function->get_name()) + "()' after yield, but class instance is gone. At script: " + state.script->get_path() + ":" + itos(state.line)); ERR_FAIL_V(Variant()); #else return Variant(); @@ -1892,6 +1914,17 @@ Variant GDScriptFunctionState::resume(const Variant &p_arg) { } else { emit_signal("completed", ret); } + +#ifdef DEBUG_ENABLED + if (ScriptDebugger::get_singleton()) + GDScriptLanguage::get_singleton()->exit_function(); + if (state.stack_size) { + //free stack + Variant *stack = (Variant *)state.stack.ptr(); + for (int i = 0; i < state.stack_size; i++) + stack[i].~Variant(); + } +#endif } return ret; diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp index a4a27c39d7..9ab86a5459 100644 --- a/modules/gdscript/gdscript_parser.cpp +++ b/modules/gdscript/gdscript_parser.cpp @@ -463,7 +463,7 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s } if (!path.is_abs_path() && base_path != "") - path = base_path + "/" + path; + path = base_path.plus_file(path); path = path.replace("///", "//").simplify_path(); if (path == self_path) { diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp index 20b227bda1..9522eaee77 100644 --- a/modules/mono/csharp_script.cpp +++ b/modules/mono/csharp_script.cpp @@ -2701,7 +2701,7 @@ ScriptInstance *CSharpScript::instance_create(Object *p_this) { } Variant::CallError unchecked_error; - return _create_instance(NULL, 0, p_this, Object::cast_to<Reference>(p_this), unchecked_error); + return _create_instance(NULL, 0, p_this, Object::cast_to<Reference>(p_this) != NULL, unchecked_error); } PlaceHolderScriptInstance *CSharpScript::placeholder_instance_create(Object *p_this) { diff --git a/modules/upnp/SCsub b/modules/upnp/SCsub index 6d669ab73b..ec1d7f44d5 100644 --- a/modules/upnp/SCsub +++ b/modules/upnp/SCsub @@ -23,10 +23,11 @@ if env['builtin_miniupnpc']: "portlistingparse.c", "upnpreplyparse.c", ] - thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources] + thirdparty_sources = [thirdparty_dir + "miniupnpc/" + file for file in thirdparty_sources] env_upnp.Prepend(CPPPATH=[thirdparty_dir]) env_upnp.Append(CPPFLAGS=["-DMINIUPNP_STATICLIB"]) + env_upnp.Append(CPPFLAGS=["-DMINIUPNPC_SET_SOCKET_TIMEOUT"]) env_thirdparty = env_upnp.Clone() env_thirdparty.disable_warnings() diff --git a/modules/visual_script/visual_script_editor.cpp b/modules/visual_script/visual_script_editor.cpp index 3ac170a935..4579644d49 100644 --- a/modules/visual_script/visual_script_editor.cpp +++ b/modules/visual_script/visual_script_editor.cpp @@ -1099,6 +1099,9 @@ void VisualScriptEditor::_expression_text_changed(const String &p_text, int p_id void VisualScriptEditor::_available_node_doubleclicked() { + if (edited_func == String()) + return; + TreeItem *item = nodes->get_selected(); if (!item) @@ -1107,7 +1110,6 @@ void VisualScriptEditor::_available_node_doubleclicked() { String which = item->get_metadata(0); if (which == String()) return; - Vector2 ofs = graph->get_scroll_ofs() + graph->get_size() * 0.5; if (graph->is_using_snap()) { diff --git a/platform/android/export/export.cpp b/platform/android/export/export.cpp index 0bd82b769f..08cbb176fe 100644 --- a/platform/android/export/export.cpp +++ b/platform/android/export/export.cpp @@ -594,7 +594,7 @@ class EditorExportPlatformAndroid : public EditorExportPlatform { if (abi_index != -1) { exported = true; String abi = abis[abi_index]; - String dst_path = "lib/" + abi + "/" + p_so.path.get_file(); + String dst_path = String("lib").plus_file(abi).plus_file(p_so.path.get_file()); Vector<uint8_t> array = FileAccess::get_file_as_array(p_so.path); Error store_err = store_in_apk(ed, dst_path, array); ERR_FAIL_COND_V(store_err, store_err); @@ -665,6 +665,8 @@ class EditorExportPlatformAndroid : public EditorExportPlatform { bool screen_support_large = p_preset->get("screen/support_large"); bool screen_support_xlarge = p_preset->get("screen/support_xlarge"); + int xr_mode_index = p_preset->get("graphics/xr_mode"); + Vector<String> perms; const char **aperms = android_perms; @@ -822,6 +824,14 @@ class EditorExportPlatformAndroid : public EditorExportPlatform { encode_uint32(min_gles3 ? 0x00030000 : 0x00020000, &p_manifest.write[iofs + 16]); } + if (tname == "meta-data" && attrname == "value") { + if (xr_mode_index == 1 /* XRMode.OVR */) { + string_table.write[attr_value] = "vr_only"; + } else { + string_table.write[attr_value] = ""; + } + } + iofs += 20; } @@ -1139,6 +1149,7 @@ public: virtual void get_export_options(List<ExportOption> *r_options) { + r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "graphics/xr_mode", PROPERTY_HINT_ENUM, "Regular,Oculus Mobile VR"), 0)); r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "graphics/32_bits_framebuffer"), true)); r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "one_click_deploy/clear_previous_install"), true)); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_package/debug", PROPERTY_HINT_GLOBAL_FILE, "*.apk"), "")); @@ -2071,6 +2082,14 @@ public: } } + int xr_mode_index = p_preset->get("graphics/xr_mode"); + if (xr_mode_index == 1 /* XRMode.OVR */) { + cl.push_back("--xr_mode_ovr"); + } else { + // XRMode.REGULAR is the default. + cl.push_back("--xr_mode_regular"); + } + if (use_32_fb) cl.push_back("--use_depth_32"); diff --git a/platform/android/java/AndroidManifest.xml b/platform/android/java/AndroidManifest.xml index 9997950137..a7e6db4059 100644 --- a/platform/android/java/AndroidManifest.xml +++ b/platform/android/java/AndroidManifest.xml @@ -13,7 +13,7 @@ <!--glEsVersion is modified by the exporter, changing this value here has no effect--> <uses-feature android:glEsVersion="0x00020000" android:required="true" /> -<!--Adding custom text to manifest is fine, but do it outside the custom user and application BEGIN/ENDregions, as that gets rewritten--> +<!--Adding custom text to manifest is fine, but do it outside the custom user and application BEGIN/END regions, as that gets rewritten--> <!--Custom permissions XML added by add-ons. It's recommended to add them from the export preset, though--> <!--CHUNK_USER_PERMISSIONS_BEGIN--> @@ -25,12 +25,15 @@ <!--The following values are replaced when Godot exports, modifying them here has no effect. Do these changes in the--> <!--export preset. Adding new ones is fine.--> +<!-- Metadata for VR app detection on Oculus devices. This is modified by the exporter based on the selected xr mode. Changing this value here has no effect. --> + <meta-data android:name="com.samsung.android.vr.application.mode" android:value=""/> + <activity android:name="org.godotengine.godot.Godot" android:label="@string/godot_project_name_string" - android:theme="@android:style/Theme.NoTitleBar.Fullscreen" + android:theme="@android:style/Theme.Black.NoTitleBar.Fullscreen" android:launchMode="singleTask" android:screenOrientation="landscape" - android:configChanges="orientation|keyboardHidden|screenSize|smallestScreenSize" + android:configChanges="orientation|keyboardHidden|screenSize|smallestScreenSize|density|keyboard|navigation|screenLayout|uiMode" android:resizeableActivity="false" tools:ignore="UnusedAttribute"> diff --git a/platform/android/java/src/org/godotengine/godot/Godot.java b/platform/android/java/src/org/godotengine/godot/Godot.java index 751e885118..6e1841fa8b 100644 --- a/platform/android/java/src/org/godotengine/godot/Godot.java +++ b/platform/android/java/src/org/godotengine/godot/Godot.java @@ -58,7 +58,6 @@ import android.os.Environment; import android.os.Messenger; import android.provider.Settings.Secure; import android.support.v4.content.ContextCompat; -import android.util.Log; import android.view.Display; import android.view.KeyEvent; import android.view.MotionEvent; @@ -115,6 +114,7 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC private Button mPauseButton; private Button mWiFiSettingsButton; + private XRMode xrMode = XRMode.REGULAR; private boolean use_32_bits = false; private boolean use_immersive = false; private boolean use_debug_opengl = false; @@ -282,7 +282,7 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC // ...add to FrameLayout layout.addView(edittext); - mView = new GodotView(this, XRMode.PANCAKE, use_gl3, use_32_bits, use_debug_opengl); + mView = new GodotView(this, xrMode, use_gl3, use_32_bits, use_debug_opengl); layout.addView(mView, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)); edittext.setView(mView); io.setEdit(edittext); @@ -488,7 +488,11 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC for (int i = 0; i < command_line.length; i++) { boolean has_extra = i < command_line.length - 1; - if (command_line[i].equals("--use_depth_32")) { + if (command_line[i].equals(XRMode.REGULAR.cmdLineArg)) { + xrMode = XRMode.REGULAR; + } else if (command_line[i].equals(XRMode.OVR.cmdLineArg)) { + xrMode = XRMode.OVR; + } else if (command_line[i].equals("--use_depth_32")) { use_32_bits = true; } else if (command_line[i].equals("--debug_opengl")) { use_debug_opengl = true; diff --git a/platform/android/java/src/org/godotengine/godot/GodotView.java b/platform/android/java/src/org/godotengine/godot/GodotView.java index 1c189a1579..fc3e47e69d 100644 --- a/platform/android/java/src/org/godotengine/godot/GodotView.java +++ b/platform/android/java/src/org/godotengine/godot/GodotView.java @@ -40,9 +40,9 @@ import org.godotengine.godot.xr.XRMode; import org.godotengine.godot.xr.ovr.OvrConfigChooser; import org.godotengine.godot.xr.ovr.OvrContextFactory; import org.godotengine.godot.xr.ovr.OvrWindowSurfaceFactory; -import org.godotengine.godot.xr.pancake.PancakeConfigChooser; -import org.godotengine.godot.xr.pancake.PancakeContextFactory; -import org.godotengine.godot.xr.pancake.PancakeFallbackConfigChooser; +import org.godotengine.godot.xr.regular.RegularConfigChooser; +import org.godotengine.godot.xr.regular.RegularContextFactory; +import org.godotengine.godot.xr.regular.RegularFallbackConfigChooser; /** * A simple GLSurfaceView sub-class that demonstrate how to perform @@ -123,7 +123,7 @@ public class GodotView extends GLSurfaceView { setEGLWindowSurfaceFactory(new OvrWindowSurfaceFactory()); break; - case PANCAKE: + case REGULAR: default: /* By default, GLSurfaceView() creates a RGB_565 opaque surface. * If we want a translucent one, we should change the surface's @@ -137,7 +137,7 @@ public class GodotView extends GLSurfaceView { /* Setup the context factory for 2.0 rendering. * See ContextFactory class definition below */ - setEGLContextFactory(new PancakeContextFactory()); + setEGLContextFactory(new RegularContextFactory()); /* We need to choose an EGLConfig that matches the format of * our surface exactly. This is going to be done in our @@ -147,15 +147,15 @@ public class GodotView extends GLSurfaceView { if (GLUtils.use_32) { setEGLConfigChooser(translucent ? - new PancakeFallbackConfigChooser(8, 8, 8, 8, 24, stencil, - new PancakeConfigChooser(8, 8, 8, 8, 16, stencil)) : - new PancakeFallbackConfigChooser(8, 8, 8, 8, 24, stencil, - new PancakeConfigChooser(5, 6, 5, 0, 16, stencil))); + new RegularFallbackConfigChooser(8, 8, 8, 8, 24, stencil, + new RegularConfigChooser(8, 8, 8, 8, 16, stencil)) : + new RegularFallbackConfigChooser(8, 8, 8, 8, 24, stencil, + new RegularConfigChooser(5, 6, 5, 0, 16, stencil))); } else { setEGLConfigChooser(translucent ? - new PancakeConfigChooser(8, 8, 8, 8, 16, stencil) : - new PancakeConfigChooser(5, 6, 5, 0, 16, stencil)); + new RegularConfigChooser(8, 8, 8, 8, 16, stencil) : + new RegularConfigChooser(5, 6, 5, 0, 16, stencil)); } break; } diff --git a/platform/android/java/src/org/godotengine/godot/xr/XRMode.java b/platform/android/java/src/org/godotengine/godot/xr/XRMode.java index cbc8a1e902..dd5701af7d 100644 --- a/platform/android/java/src/org/godotengine/godot/xr/XRMode.java +++ b/platform/android/java/src/org/godotengine/godot/xr/XRMode.java @@ -34,6 +34,16 @@ package org.godotengine.godot.xr; * Godot available XR modes. */ public enum XRMode { - PANCAKE, // Regular/flatscreen - OVR, // Oculus mobile VR SDK + REGULAR(0, "Regular", "--xr_mode_regular"), // Regular/flatscreen + OVR(1, "Oculus Mobile VR", "--xr_mode_ovr"); + + final int index; + final String label; + public final String cmdLineArg; + + XRMode(int index, String label, String cmdLineArg) { + this.index = index; + this.label = label; + this.cmdLineArg = cmdLineArg; + } } diff --git a/platform/android/java/src/org/godotengine/godot/xr/pancake/PancakeConfigChooser.java b/platform/android/java/src/org/godotengine/godot/xr/regular/RegularConfigChooser.java index ac19a09e76..3836967f86 100644 --- a/platform/android/java/src/org/godotengine/godot/xr/pancake/PancakeConfigChooser.java +++ b/platform/android/java/src/org/godotengine/godot/xr/regular/RegularConfigChooser.java @@ -1,5 +1,5 @@ /*************************************************************************/ -/* PancakeConfigChooser.java */ +/* RegularConfigChooser.java */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,7 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -package org.godotengine.godot.xr.pancake; +package org.godotengine.godot.xr.regular; import android.opengl.GLSurfaceView; import javax.microedition.khronos.egl.EGL10; @@ -39,9 +39,9 @@ import org.godotengine.godot.utils.GLUtils; /** * Used to select the egl config for pancake games. */ -public class PancakeConfigChooser implements GLSurfaceView.EGLConfigChooser { +public class RegularConfigChooser implements GLSurfaceView.EGLConfigChooser { - private static final String TAG = PancakeConfigChooser.class.getSimpleName(); + private static final String TAG = RegularConfigChooser.class.getSimpleName(); private int[] mValue = new int[1]; @@ -69,7 +69,7 @@ public class PancakeConfigChooser implements GLSurfaceView.EGLConfigChooser { EGL10.EGL_NONE }; - public PancakeConfigChooser(int r, int g, int b, int a, int depth, int stencil) { + public RegularConfigChooser(int r, int g, int b, int a, int depth, int stencil) { mRedSize = r; mGreenSize = g; mBlueSize = b; diff --git a/platform/android/java/src/org/godotengine/godot/xr/pancake/PancakeContextFactory.java b/platform/android/java/src/org/godotengine/godot/xr/regular/RegularContextFactory.java index aca6ffdba6..4f1e9a696b 100644 --- a/platform/android/java/src/org/godotengine/godot/xr/pancake/PancakeContextFactory.java +++ b/platform/android/java/src/org/godotengine/godot/xr/regular/RegularContextFactory.java @@ -1,5 +1,5 @@ /*************************************************************************/ -/* PancakeContextFactory.java */ +/* RegularContextFactory.java */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,7 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -package org.godotengine.godot.xr.pancake; +package org.godotengine.godot.xr.regular; import android.opengl.GLSurfaceView; import android.util.Log; @@ -42,8 +42,8 @@ import org.godotengine.godot.utils.GLUtils; /** * Factory used to setup the opengl context for pancake games. */ -public class PancakeContextFactory implements GLSurfaceView.EGLContextFactory { - private static final String TAG = PancakeContextFactory.class.getSimpleName(); +public class RegularContextFactory implements GLSurfaceView.EGLContextFactory { + private static final String TAG = RegularContextFactory.class.getSimpleName(); private static final int _EGL_CONTEXT_FLAGS_KHR = 0x30FC; private static final int _EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR = 0x00000001; diff --git a/platform/android/java/src/org/godotengine/godot/xr/pancake/PancakeFallbackConfigChooser.java b/platform/android/java/src/org/godotengine/godot/xr/regular/RegularFallbackConfigChooser.java index e19f218916..f5718ef2b3 100644 --- a/platform/android/java/src/org/godotengine/godot/xr/pancake/PancakeFallbackConfigChooser.java +++ b/platform/android/java/src/org/godotengine/godot/xr/regular/RegularFallbackConfigChooser.java @@ -1,5 +1,5 @@ /*************************************************************************/ -/* PancakeFallbackConfigChooser.java */ +/* RegularFallbackConfigChooser.java */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,7 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -package org.godotengine.godot.xr.pancake; +package org.godotengine.godot.xr.regular; import android.util.Log; import javax.microedition.khronos.egl.EGL10; @@ -37,13 +37,13 @@ import javax.microedition.khronos.egl.EGLDisplay; import org.godotengine.godot.utils.GLUtils; /* Fallback if 32bit View is not supported*/ -public class PancakeFallbackConfigChooser extends PancakeConfigChooser { +public class RegularFallbackConfigChooser extends RegularConfigChooser { - private static final String TAG = PancakeFallbackConfigChooser.class.getSimpleName(); + private static final String TAG = RegularFallbackConfigChooser.class.getSimpleName(); - private PancakeConfigChooser fallback; + private RegularConfigChooser fallback; - public PancakeFallbackConfigChooser(int r, int g, int b, int a, int depth, int stencil, PancakeConfigChooser fallback) { + public RegularFallbackConfigChooser(int r, int g, int b, int a, int depth, int stencil, RegularConfigChooser fallback) { super(r, g, b, a, depth, stencil); this.fallback = fallback; } diff --git a/platform/iphone/export/export.cpp b/platform/iphone/export/export.cpp index a9daa6ea5f..99ce2e8f87 100644 --- a/platform/iphone/export/export.cpp +++ b/platform/iphone/export/export.cpp @@ -564,7 +564,7 @@ Error EditorExportPlatformIOS::_walk_dir_recursive(DirAccess *p_da, FileHandler dirs.push_back(path); } } else { - Error err = p_handler(current_dir + "/" + path, p_userdata); + Error err = p_handler(current_dir.plus_file(path), p_userdata); if (err) { p_da->list_dir_end(); return err; @@ -784,7 +784,7 @@ Error EditorExportPlatformIOS::_export_additional_assets(const String &p_out_dir } } - String destination = destination_dir + "/" + asset.get_file(); + String destination = destination_dir.plus_file(asset.get_file()); Error err = dir_exists ? da->copy_dir(asset, destination) : da->copy(asset, destination); memdelete(da); if (err) { diff --git a/platform/javascript/detect.py b/platform/javascript/detect.py index 145ac42863..c6afa02c6d 100644 --- a/platform/javascript/detect.py +++ b/platform/javascript/detect.py @@ -69,9 +69,9 @@ def configure(env): exec(f.read(), em_config) except StandardError as e: raise RuntimeError("Emscripten configuration file '%s' is invalid:\n%s" % (em_config_file, e)) - if 'EMSCRIPTEN_ROOT' not in em_config: - raise RuntimeError("'EMSCRIPTEN_ROOT' missing in Emscripten configuration file '%s'" % em_config_file) - env.PrependENVPath('PATH', em_config['EMSCRIPTEN_ROOT']) + if 'BINARYEN_ROOT' not in em_config and 'EMSCRIPTEN_ROOT' not in em_config: + raise RuntimeError("'BINARYEN_ROOT' or 'EMSCRIPTEN_ROOT' missing in Emscripten configuration file '%s'" % em_config_file) + env.PrependENVPath('PATH', em_config.get('BINARYEN_ROOT', em_config.get('EMSCRIPTEN_ROOT'))) env['CC'] = 'emcc' env['CXX'] = 'em++' diff --git a/platform/osx/export/export.cpp b/platform/osx/export/export.cpp index 9dabbb12fc..8cabc45250 100644 --- a/platform/osx/export/export.cpp +++ b/platform/osx/export/export.cpp @@ -570,7 +570,7 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p if (export_format == "dmg") { // write it into our application bundle - file = tmp_app_path_name + "/" + file; + file = tmp_app_path_name.plus_file(file); // write the file, need to add chmod FileAccess *f = FileAccess::open(file, FileAccess::WRITE); diff --git a/platform/x11/os_x11.cpp b/platform/x11/os_x11.cpp index bf6bc0b464..624efe8815 100644 --- a/platform/x11/os_x11.cpp +++ b/platform/x11/os_x11.cpp @@ -2997,7 +2997,7 @@ void OS_X11::alert(const String &p_alert, const String &p_title) { for (int i = 0; i < path_elems.size(); i++) { for (unsigned int k = 0; k < sizeof(message_programs) / sizeof(char *); k++) { - String tested_path = path_elems[i] + "/" + message_programs[k]; + String tested_path = path_elems[i].plus_file(message_programs[k]); if (FileAccess::exists(tested_path)) { program = tested_path; diff --git a/scene/2d/canvas_item.cpp b/scene/2d/canvas_item.cpp index 78e98deb93..23f6404e3e 100644 --- a/scene/2d/canvas_item.cpp +++ b/scene/2d/canvas_item.cpp @@ -1074,6 +1074,7 @@ Vector2 CanvasItem::make_canvas_position_local(const Vector2 &screen_point) cons Ref<InputEvent> CanvasItem::make_input_local(const Ref<InputEvent> &p_event) const { + ERR_FAIL_COND_V(p_event.is_null(), p_event); ERR_FAIL_COND_V(!is_inside_tree(), p_event); return p_event->xformed_by((get_canvas_transform() * get_global_transform()).affine_inverse()); diff --git a/scene/2d/line_2d.cpp b/scene/2d/line_2d.cpp index 1c8245d159..ad405fabbb 100644 --- a/scene/2d/line_2d.cpp +++ b/scene/2d/line_2d.cpp @@ -84,10 +84,10 @@ void Line2D::set_points(const PoolVector<Vector2> &p_points) { update(); } -void Line2D::set_width(float width) { - if (width < 0.0) - width = 0.0; - _width = width; +void Line2D::set_width(float p_width) { + if (p_width < 0.0) + p_width = 0.0; + _width = p_width; update(); } @@ -95,12 +95,32 @@ float Line2D::get_width() const { return _width; } +void Line2D::set_curve(const Ref<Curve> &p_curve) { + // Cleanup previous connection if any + if (_curve.is_valid()) { + _curve->disconnect(CoreStringNames::get_singleton()->changed, this, "_curve_changed"); + } + + _curve = p_curve; + + // Connect to the curve so the line will update when it is changed + if (_curve.is_valid()) { + _curve->connect(CoreStringNames::get_singleton()->changed, this, "_curve_changed"); + } + + update(); +} + +Ref<Curve> Line2D::get_curve() const { + return _curve; +} + PoolVector<Vector2> Line2D::get_points() const { return _points; } -void Line2D::set_point_position(int i, Vector2 pos) { - _points.set(i, pos); +void Line2D::set_point_position(int i, Vector2 p_pos) { + _points.set(i, p_pos); update(); } @@ -121,11 +141,11 @@ void Line2D::clear_points() { } } -void Line2D::add_point(Vector2 pos, int atpos) { - if (atpos < 0 || _points.size() < atpos) { - _points.append(pos); +void Line2D::add_point(Vector2 p_pos, int p_atpos) { + if (p_atpos < 0 || _points.size() < p_atpos) { + _points.append(p_pos); } else { - _points.insert(atpos, pos); + _points.insert(p_atpos, p_pos); } update(); } @@ -135,8 +155,8 @@ void Line2D::remove_point(int i) { update(); } -void Line2D::set_default_color(Color color) { - _default_color = color; +void Line2D::set_default_color(Color p_color) { + _default_color = p_color; update(); } @@ -144,18 +164,18 @@ Color Line2D::get_default_color() const { return _default_color; } -void Line2D::set_gradient(const Ref<Gradient> &gradient) { +void Line2D::set_gradient(const Ref<Gradient> &p_gradient) { // Cleanup previous connection if any if (_gradient.is_valid()) { - (**_gradient).disconnect(CoreStringNames::get_singleton()->changed, this, "_gradient_changed"); + _gradient->disconnect(CoreStringNames::get_singleton()->changed, this, "_gradient_changed"); } - _gradient = gradient; + _gradient = p_gradient; // Connect to the gradient so the line will update when the ColorRamp is changed if (_gradient.is_valid()) { - (**_gradient).connect(CoreStringNames::get_singleton()->changed, this, "_gradient_changed"); + _gradient->connect(CoreStringNames::get_singleton()->changed, this, "_gradient_changed"); } update(); @@ -165,8 +185,8 @@ Ref<Gradient> Line2D::get_gradient() const { return _gradient; } -void Line2D::set_texture(const Ref<Texture> &texture) { - _texture = texture; +void Line2D::set_texture(const Ref<Texture> &p_texture) { + _texture = p_texture; update(); } @@ -174,8 +194,8 @@ Ref<Texture> Line2D::get_texture() const { return _texture; } -void Line2D::set_texture_mode(const LineTextureMode mode) { - _texture_mode = mode; +void Line2D::set_texture_mode(const LineTextureMode p_mode) { + _texture_mode = p_mode; update(); } @@ -183,8 +203,8 @@ Line2D::LineTextureMode Line2D::get_texture_mode() const { return _texture_mode; } -void Line2D::set_joint_mode(LineJointMode mode) { - _joint_mode = mode; +void Line2D::set_joint_mode(LineJointMode p_mode) { + _joint_mode = p_mode; update(); } @@ -192,8 +212,8 @@ Line2D::LineJointMode Line2D::get_joint_mode() const { return _joint_mode; } -void Line2D::set_begin_cap_mode(LineCapMode mode) { - _begin_cap_mode = mode; +void Line2D::set_begin_cap_mode(LineCapMode p_mode) { + _begin_cap_mode = p_mode; update(); } @@ -201,8 +221,8 @@ Line2D::LineCapMode Line2D::get_begin_cap_mode() const { return _begin_cap_mode; } -void Line2D::set_end_cap_mode(LineCapMode mode) { - _end_cap_mode = mode; +void Line2D::set_end_cap_mode(LineCapMode p_mode) { + _end_cap_mode = p_mode; update(); } @@ -218,10 +238,10 @@ void Line2D::_notification(int p_what) { } } -void Line2D::set_sharp_limit(float limit) { - if (limit < 0.f) - limit = 0.f; - _sharp_limit = limit; +void Line2D::set_sharp_limit(float p_limit) { + if (p_limit < 0.f) + p_limit = 0.f; + _sharp_limit = p_limit; update(); } @@ -229,10 +249,10 @@ float Line2D::get_sharp_limit() const { return _sharp_limit; } -void Line2D::set_round_precision(int precision) { - if (precision < 1) - precision = 1; - _round_precision = precision; +void Line2D::set_round_precision(int p_precision) { + if (p_precision < 1) + p_precision = 1; + _round_precision = p_precision; update(); } @@ -268,10 +288,11 @@ void Line2D::_draw() { lb.round_precision = _round_precision; lb.sharp_limit = _sharp_limit; lb.width = _width; + lb.curve = *_curve; RID texture_rid; if (_texture.is_valid()) { - texture_rid = (**_texture).get_rid(); + texture_rid = _texture->get_rid(); lb.tile_aspect = _texture->get_size().aspect(); } @@ -312,6 +333,10 @@ void Line2D::_gradient_changed() { update(); } +void Line2D::_curve_changed() { + update(); +} + // static void Line2D::_bind_methods() { @@ -331,6 +356,9 @@ void Line2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_width", "width"), &Line2D::set_width); ClassDB::bind_method(D_METHOD("get_width"), &Line2D::get_width); + ClassDB::bind_method(D_METHOD("set_curve", "curve"), &Line2D::set_curve); + ClassDB::bind_method(D_METHOD("get_curve"), &Line2D::get_curve); + ClassDB::bind_method(D_METHOD("set_default_color", "color"), &Line2D::set_default_color); ClassDB::bind_method(D_METHOD("get_default_color"), &Line2D::get_default_color); @@ -360,6 +388,7 @@ void Line2D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::POOL_VECTOR2_ARRAY, "points"), "set_points", "get_points"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "width"), "set_width", "get_width"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "width_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_curve", "get_curve"); ADD_PROPERTY(PropertyInfo(Variant::COLOR, "default_color"), "set_default_color", "get_default_color"); ADD_GROUP("Fill", ""); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "gradient", PROPERTY_HINT_RESOURCE_TYPE, "Gradient"), "set_gradient", "get_gradient"); @@ -386,4 +415,5 @@ void Line2D::_bind_methods() { BIND_ENUM_CONSTANT(LINE_TEXTURE_STRETCH); ClassDB::bind_method(D_METHOD("_gradient_changed"), &Line2D::_gradient_changed); + ClassDB::bind_method(D_METHOD("_curve_changed"), &Line2D::_curve_changed); } diff --git a/scene/2d/line_2d.h b/scene/2d/line_2d.h index 11be5055d4..14afa463ba 100644 --- a/scene/2d/line_2d.h +++ b/scene/2d/line_2d.h @@ -78,6 +78,9 @@ public: void set_width(float width); float get_width() const; + void set_curve(const Ref<Curve> &curve); + Ref<Curve> get_curve() const; + void set_default_color(Color color); Color get_default_color() const; @@ -113,6 +116,7 @@ protected: private: void _gradient_changed(); + void _curve_changed(); private: PoolVector<Vector2> _points; @@ -120,6 +124,7 @@ private: LineCapMode _begin_cap_mode; LineCapMode _end_cap_mode; float _width; + Ref<Curve> _curve; Color _default_color; Ref<Gradient> _gradient; Ref<Texture> _texture; diff --git a/scene/2d/line_builder.cpp b/scene/2d/line_builder.cpp index eb09d3c9d3..9fe5fb98b6 100644 --- a/scene/2d/line_builder.cpp +++ b/scene/2d/line_builder.cpp @@ -95,6 +95,7 @@ static inline Vector2 interpolate(const Rect2 &r, const Vector2 &v) { LineBuilder::LineBuilder() { joint_mode = Line2D::LINE_JOINT_SHARP; width = 10; + curve = NULL; default_color = Color(0.4, 0.5, 1); gradient = NULL; sharp_limit = 2.f; @@ -136,8 +137,8 @@ void LineBuilder::build() { Vector2 pos1 = points[1]; Vector2 f0 = (pos1 - pos0).normalized(); Vector2 u0 = rotate90(f0); - Vector2 pos_up0 = pos0 + u0 * hw; - Vector2 pos_down0 = pos0 - u0 * hw; + Vector2 pos_up0 = pos0; + Vector2 pos_down0 = pos0; Color color0; Color color1; @@ -145,12 +146,30 @@ void LineBuilder::build() { float current_distance0 = 0.f; float current_distance1 = 0.f; float total_distance = 0.f; + float width_factor = 1.f; _interpolate_color = gradient != NULL; + bool retrieve_curve = curve != NULL; bool distance_required = _interpolate_color || + retrieve_curve || texture_mode == Line2D::LINE_TEXTURE_TILE || texture_mode == Line2D::LINE_TEXTURE_STRETCH; - if (distance_required) + if (distance_required) { total_distance = calculate_total_distance(points); + //Ajust totalDistance. + // The line's outer length will be a little higher due to begin and end caps + if (begin_cap_mode == Line2D::LINE_CAP_BOX || begin_cap_mode == Line2D::LINE_CAP_ROUND) { + if (retrieve_curve) + total_distance += width * curve->interpolate_baked(0.f) * 0.5f; + else + total_distance += width * 0.5f; + } + if (end_cap_mode == Line2D::LINE_CAP_BOX || end_cap_mode == Line2D::LINE_CAP_ROUND) { + if (retrieve_curve) + total_distance += width * curve->interpolate_baked(1.f) * 0.5f; + else + total_distance += width * 0.5f; + } + } if (_interpolate_color) color0 = gradient->get_color(0); else @@ -159,22 +178,28 @@ void LineBuilder::build() { float uvx0 = 0.f; float uvx1 = 0.f; + if (retrieve_curve) + width_factor = curve->interpolate_baked(0.f); + + pos_up0 += u0 * hw * width_factor; + pos_down0 -= u0 * hw * width_factor; + // Begin cap if (begin_cap_mode == Line2D::LINE_CAP_BOX) { // Push back first vertices a little bit - pos_up0 -= f0 * hw; - pos_down0 -= f0 * hw; - // The line's outer length will be a little higher due to begin and end caps - total_distance += width; - current_distance0 += hw; + pos_up0 -= f0 * hw * width_factor; + pos_down0 -= f0 * hw * width_factor; + + current_distance0 += hw * width_factor; current_distance1 = current_distance0; } else if (begin_cap_mode == Line2D::LINE_CAP_ROUND) { if (texture_mode == Line2D::LINE_TEXTURE_TILE) { - uvx0 = 0.5f / tile_aspect; + uvx0 = width_factor * 0.5f / tile_aspect; + } else if (texture_mode == Line2D::LINE_TEXTURE_STRETCH) { + uvx0 = width * width_factor / total_distance; } - new_arc(pos0, pos_up0 - pos0, -Math_PI, color0, Rect2(0.f, 0.f, fmin(uvx0 * 2, 1.f), 1.f)); - total_distance += width; - current_distance0 += hw; + new_arc(pos0, pos_up0 - pos0, -Math_PI, color0, Rect2(0.f, 0.f, uvx0 * 2, 1.f)); + current_distance0 += hw * width_factor; current_distance1 = current_distance0; } @@ -206,13 +231,23 @@ void LineBuilder::build() { const float dp = u0.dot(f1); const Orientation orientation = (dp > 0.f ? UP : DOWN); + if (distance_required) { + current_distance1 += pos0.distance_to(pos1); + } + if (_interpolate_color) { + color1 = gradient->get_color_at_offset(current_distance1 / total_distance); + } + if (retrieve_curve) { + width_factor = curve->interpolate_baked(current_distance1 / total_distance); + } + Vector2 inner_normal0, inner_normal1; if (orientation == UP) { - inner_normal0 = u0 * hw; - inner_normal1 = u1 * hw; + inner_normal0 = u0 * hw * width_factor; + inner_normal1 = u1 * hw * width_factor; } else { - inner_normal0 = -u0 * hw; - inner_normal1 = -u1 * hw; + inner_normal0 = -u0 * hw * width_factor; + inner_normal1 = -u1 * hw * width_factor; } /* @@ -259,7 +294,8 @@ void LineBuilder::build() { Vector2 pos_up1, pos_down1; if (intersection_result == SEGMENT_INTERSECT) { // Fallback on bevel if sharp angle is too high (because it would produce very long miters) - if (current_joint_mode == Line2D::LINE_JOINT_SHARP && corner_pos_out.distance_squared_to(pos1) / hw_sq > sharp_limit_sq) { + float width_factor_sq = width_factor * width_factor; + if (current_joint_mode == Line2D::LINE_JOINT_SHARP && corner_pos_out.distance_squared_to(pos1) / (hw_sq * width_factor_sq) > sharp_limit_sq) { current_joint_mode = Line2D::LINE_JOINT_BEVEL; } if (current_joint_mode == Line2D::LINE_JOINT_SHARP) { @@ -271,9 +307,9 @@ void LineBuilder::build() { // Bevel or round if (orientation == UP) { pos_up1 = corner_pos_up; - pos_down1 = pos1 - u0 * hw; + pos_down1 = pos1 - u0 * hw * width_factor; } else { - pos_up1 = pos1 + u0 * hw; + pos_up1 = pos1 + u0 * hw * width_factor; pos_down1 = corner_pos_down; } } @@ -289,12 +325,6 @@ void LineBuilder::build() { // Add current line body quad // Triangles are clockwise - if (distance_required) { - current_distance1 += pos0.distance_to(pos1); - } - if (_interpolate_color) { - color1 = gradient->get_color_at_offset(current_distance1 / total_distance); - } if (texture_mode == Line2D::LINE_TEXTURE_TILE) { uvx1 = current_distance1 / (width * tile_aspect); } else if (texture_mode == Line2D::LINE_TEXTURE_STRETCH) { @@ -315,15 +345,15 @@ void LineBuilder::build() { } else { if (orientation == UP) { pos_up0 = corner_pos_up; - pos_down0 = pos1 - u1 * hw; + pos_down0 = pos1 - u1 * hw * width_factor; } else { - pos_up0 = pos1 + u1 * hw; + pos_up0 = pos1 + u1 * hw * width_factor; pos_down0 = corner_pos_down; } } } else { - pos_up0 = pos1 + u1 * hw; - pos_down0 = pos1 - u1 * hw; + pos_up0 = pos1 + u1 * hw * width_factor; + pos_down0 = pos1 - u1 * hw * width_factor; } // From this point, bu0 and bd0 concern the next segment @@ -362,26 +392,28 @@ void LineBuilder::build() { strip_begin(pos_up0, pos_down0, color1, uvx1); } } - // Last (or only) segment - pos1 = points[points.size() - 1]; - Vector2 pos_up1 = pos1 + u0 * hw; - Vector2 pos_down1 = pos1 - u0 * hw; - - // End cap (box) - if (end_cap_mode == Line2D::LINE_CAP_BOX) { - pos_up1 += f0 * hw; - pos_down1 += f0 * hw; - } - if (distance_required) { current_distance1 += pos0.distance_to(pos1); } if (_interpolate_color) { color1 = gradient->get_color(gradient->get_points_count() - 1); } + if (retrieve_curve) { + width_factor = curve->interpolate_baked(1.f); + } + + Vector2 pos_up1 = pos1 + u0 * hw * width_factor; + Vector2 pos_down1 = pos1 - u0 * hw * width_factor; + + // End cap (box) + if (end_cap_mode == Line2D::LINE_CAP_BOX) { + pos_up1 += f0 * hw * width_factor; + pos_down1 += f0 * hw * width_factor; + } + if (texture_mode == Line2D::LINE_TEXTURE_TILE) { uvx1 = current_distance1 / (width * tile_aspect); } else if (texture_mode == Line2D::LINE_TEXTURE_STRETCH) { @@ -394,7 +426,13 @@ void LineBuilder::build() { if (end_cap_mode == Line2D::LINE_CAP_ROUND) { // Note: color is not used in case we don't interpolate... Color color = _interpolate_color ? gradient->get_color(gradient->get_points_count() - 1) : Color(0, 0, 0); - new_arc(pos1, pos_up1 - pos1, Math_PI, color, Rect2(uvx1 - 0.5f / tile_aspect, 0.f, 1.0f / tile_aspect, 1.f)); + float dist = 0; + if (texture_mode == Line2D::LINE_TEXTURE_TILE) { + dist = width_factor / tile_aspect; + } else if (texture_mode == Line2D::LINE_TEXTURE_STRETCH) { + dist = width * width_factor / total_distance; + } + new_arc(pos1, pos_up1 - pos1, Math_PI, color, Rect2(uvx1 - 0.5f * dist, 0.f, dist, 1.f)); } } diff --git a/scene/2d/line_builder.h b/scene/2d/line_builder.h index b961385e33..91b4518f9b 100644 --- a/scene/2d/line_builder.h +++ b/scene/2d/line_builder.h @@ -45,6 +45,7 @@ public: Line2D::LineCapMode begin_cap_mode; Line2D::LineCapMode end_cap_mode; float width; + Curve *curve; Color default_color; Gradient *gradient; Line2D::LineTextureMode texture_mode; diff --git a/scene/2d/navigation_2d.cpp b/scene/2d/navigation_2d.cpp index 72b5f2fb12..f644db462b 100644 --- a/scene/2d/navigation_2d.cpp +++ b/scene/2d/navigation_2d.cpp @@ -92,7 +92,6 @@ void Navigation2D::_navpoly_link(int p_id) { if (!valid) { nm.polygons.pop_back(); ERR_CONTINUE(!valid); - continue; } p.center = center / plen; diff --git a/scene/3d/audio_stream_player_3d.h b/scene/3d/audio_stream_player_3d.h index 7a652ed65f..93954e758a 100644 --- a/scene/3d/audio_stream_player_3d.h +++ b/scene/3d/audio_stream_player_3d.h @@ -71,7 +71,7 @@ private: struct Output { AudioFilterSW filter; - AudioFilterSW::Processor filter_process[6]; + AudioFilterSW::Processor filter_process[8]; AudioFrame vol[4]; float filter_gain; float pitch_scale; diff --git a/scene/3d/navigation.cpp b/scene/3d/navigation.cpp index 612d91c6e1..12d562c0c6 100644 --- a/scene/3d/navigation.cpp +++ b/scene/3d/navigation.cpp @@ -90,7 +90,6 @@ void Navigation::_navmesh_link(int p_id) { if (!valid) { nm.polygons.pop_back(); ERR_CONTINUE(!valid); - continue; } p.center = center; diff --git a/scene/3d/spatial.cpp b/scene/3d/spatial.cpp index efd418e3c7..1a41a31253 100644 --- a/scene/3d/spatial.cpp +++ b/scene/3d/spatial.cpp @@ -506,6 +506,8 @@ bool Spatial::is_set_as_toplevel() const { Ref<World> Spatial::get_world() const { ERR_FAIL_COND_V(!is_inside_world(), Ref<World>()); + ERR_FAIL_COND_V(!data.viewport, Ref<World>()); + return data.viewport->find_world(); } diff --git a/scene/3d/visual_instance.cpp b/scene/3d/visual_instance.cpp index 4bb4d18071..5141c84803 100644 --- a/scene/3d/visual_instance.cpp +++ b/scene/3d/visual_instance.cpp @@ -60,7 +60,7 @@ void VisualInstance::_notification(int p_what) { if (skeleton) VisualServer::get_singleton()->instance_attach_skeleton( instance, skeleton->get_skeleton() ); */ - + ERR_FAIL_COND(get_world().is_null()); VisualServer::get_singleton()->instance_set_scenario(instance, get_world()->get_scenario()); _update_visibility(); diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp index 6e0e26312f..eccd42cb9f 100644 --- a/scene/gui/control.cpp +++ b/scene/gui/control.cpp @@ -2249,6 +2249,7 @@ Ref<Theme> Control::get_theme() const { void Control::set_tooltip(const String &p_tooltip) { data.tooltip = p_tooltip; + update_configuration_warning(); } String Control::get_tooltip(const Point2 &p_pos) const { @@ -2540,6 +2541,7 @@ void Control::set_mouse_filter(MouseFilter p_filter) { ERR_FAIL_INDEX(p_filter, 3); data.mouse_filter = p_filter; + update_configuration_warning(); } Control::MouseFilter Control::get_mouse_filter() const { @@ -2703,6 +2705,20 @@ void Control::get_argument_options(const StringName &p_function, int p_idx, List } } } + +String Control::get_configuration_warning() const { + String warning = CanvasItem::get_configuration_warning(); + + if (data.mouse_filter == MOUSE_FILTER_IGNORE && data.tooltip != "") { + if (warning != String()) { + warning += "\n"; + } + warning += TTR("The Hint Tooltip won't be displayed as the control's Mouse Filter is set to \"Ignore\". To solve this, set the Mouse Filter to \"Stop\" or \"Pass\"."); + } + + return warning; +} + void Control::set_clip_contents(bool p_clip) { data.clip_contents = p_clip; diff --git a/scene/gui/control.h b/scene/gui/control.h index 2489a5eda4..1a59a6d2e4 100644 --- a/scene/gui/control.h +++ b/scene/gui/control.h @@ -487,6 +487,7 @@ public: bool is_visibility_clip_disabled() const; virtual void get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const; + virtual String get_configuration_warning() const; Control(); ~Control(); diff --git a/scene/gui/file_dialog.cpp b/scene/gui/file_dialog.cpp index ba4d390fc5..04fb991f78 100644 --- a/scene/gui/file_dialog.cpp +++ b/scene/gui/file_dialog.cpp @@ -381,6 +381,18 @@ void FileDialog::_tree_item_activated() { } } +void FileDialog::update_file_name() { + int idx = filter->get_selected() - 1; + if ((idx == -1 && filter->get_item_count() == 2) || (filter->get_item_count() > 2 && idx >= 0 && idx < filter->get_item_count() - 2)) { + if (idx == -1) idx += 1; + String filter_str = filters[idx]; + String file_str = file->get_text(); + String base_name = file_str.get_basename(); + file_str = base_name + "." + filter_str.strip_edges().to_lower(); + file->set_text(file_str); + } +} + void FileDialog::update_file_list() { tree->clear(); @@ -506,6 +518,7 @@ void FileDialog::update_file_list() { void FileDialog::_filter_selected(int) { + update_file_name(); update_file_list(); } @@ -797,6 +810,7 @@ void FileDialog::_bind_methods() { ClassDB::bind_method(D_METHOD("_select_drive"), &FileDialog::_select_drive); ClassDB::bind_method(D_METHOD("_make_dir"), &FileDialog::_make_dir); ClassDB::bind_method(D_METHOD("_make_dir_confirm"), &FileDialog::_make_dir_confirm); + ClassDB::bind_method(D_METHOD("_update_file_name"), &FileDialog::update_file_name); ClassDB::bind_method(D_METHOD("_update_file_list"), &FileDialog::update_file_list); ClassDB::bind_method(D_METHOD("_update_dir"), &FileDialog::update_dir); ClassDB::bind_method(D_METHOD("_go_up"), &FileDialog::_go_up); diff --git a/scene/gui/file_dialog.h b/scene/gui/file_dialog.h index 9f7ea1a2f2..191af5fef3 100644 --- a/scene/gui/file_dialog.h +++ b/scene/gui/file_dialog.h @@ -102,6 +102,7 @@ private: bool invalidated; void update_dir(); + void update_file_name(); void update_file_list(); void update_filters(); diff --git a/scene/gui/option_button.cpp b/scene/gui/option_button.cpp index 872402e9e1..58671655dc 100644 --- a/scene/gui/option_button.cpp +++ b/scene/gui/option_button.cpp @@ -282,7 +282,7 @@ void OptionButton::_set_items(const Array &p_items) { void OptionButton::get_translatable_strings(List<String> *p_strings) const { - return popup->get_translatable_strings(p_strings); + popup->get_translatable_strings(p_strings); } void OptionButton::_bind_methods() { diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index fdd21f525b..a6e3d644f6 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -681,6 +681,13 @@ void TextEdit::_notification(int p_what) { } } + if (line_length_guideline) { + int x = xmargin_beg + cache.font->get_char_size('0').width * line_length_guideline_col - cursor.x_ofs; + if (x > xmargin_beg && x < xmargin_end) { + VisualServer::get_singleton()->canvas_item_add_line(ci, Point2(x, 0), Point2(x, size.height), cache.line_length_guideline_color); + } + } + int brace_open_match_line = -1; int brace_open_match_column = -1; bool brace_open_matching = false; @@ -1339,13 +1346,6 @@ void TextEdit::_notification(int p_what) { } } - if (line_length_guideline) { - int x = xmargin_beg + cache.font->get_char_size('0').width * line_length_guideline_col - cursor.x_ofs; - if (x > xmargin_beg && x < xmargin_end) { - VisualServer::get_singleton()->canvas_item_add_line(ci, Point2(x, 0), Point2(x, size.height), cache.line_length_guideline_color); - } - } - bool completion_below = false; if (completion_active) { // code completion box @@ -4817,14 +4817,18 @@ void TextEdit::deselect() { void TextEdit::select(int p_from_line, int p_from_column, int p_to_line, int p_to_column) { - if (p_from_line >= text.size()) + if (p_from_line < 0) + p_from_line = 0; + else if (p_from_line >= text.size()) p_from_line = text.size() - 1; if (p_from_column >= text[p_from_line].length()) p_from_column = text[p_from_line].length(); if (p_from_column < 0) p_from_column = 0; - if (p_to_line >= text.size()) + if (p_to_line < 0) + p_to_line = 0; + else if (p_to_line >= text.size()) p_to_line = text.size() - 1; if (p_to_column >= text[p_to_line].length()) p_to_column = text[p_to_line].length(); diff --git a/scene/main/http_request.cpp b/scene/main/http_request.cpp index e65314644e..88b942ee45 100644 --- a/scene/main/http_request.cpp +++ b/scene/main/http_request.cpp @@ -425,7 +425,7 @@ void HTTPRequest::_notification(int p_what) { void HTTPRequest::set_use_threads(bool p_use) { - ERR_FAIL_COND(status != HTTPClient::STATUS_DISCONNECTED); + ERR_FAIL_COND(get_http_client_status() != HTTPClient::STATUS_DISCONNECTED); use_threads = p_use; } @@ -436,7 +436,7 @@ bool HTTPRequest::is_using_threads() const { void HTTPRequest::set_body_size_limit(int p_bytes) { - ERR_FAIL_COND(status != HTTPClient::STATUS_DISCONNECTED); + ERR_FAIL_COND(get_http_client_status() != HTTPClient::STATUS_DISCONNECTED); body_size_limit = p_bytes; } @@ -448,7 +448,7 @@ int HTTPRequest::get_body_size_limit() const { void HTTPRequest::set_download_file(const String &p_file) { - ERR_FAIL_COND(status != HTTPClient::STATUS_DISCONNECTED); + ERR_FAIL_COND(get_http_client_status() != HTTPClient::STATUS_DISCONNECTED); download_to_file = p_file; } @@ -546,7 +546,6 @@ HTTPRequest::HTTPRequest() { downloaded = 0; body_size_limit = -1; file = NULL; - status = HTTPClient::STATUS_DISCONNECTED; } HTTPRequest::~HTTPRequest() { diff --git a/scene/main/http_request.h b/scene/main/http_request.h index baabda4010..2e58d579ba 100644 --- a/scene/main/http_request.h +++ b/scene/main/http_request.h @@ -88,8 +88,6 @@ private: int redirections; - HTTPClient::Status status; - bool _update_connection(); int max_redirects; diff --git a/scene/main/node.cpp b/scene/main/node.cpp index a580a7f8ac..5888760973 100644 --- a/scene/main/node.cpp +++ b/scene/main/node.cpp @@ -71,6 +71,8 @@ void Node::_notification(int p_notification) { } break; case NOTIFICATION_ENTER_TREE: { + ERR_FAIL_COND(!get_viewport()); + ERR_FAIL_COND(!get_tree()); if (data.pause_mode == PAUSE_MODE_INHERIT) { @@ -94,6 +96,8 @@ void Node::_notification(int p_notification) { } break; case NOTIFICATION_EXIT_TREE: { + ERR_FAIL_COND(!get_viewport()); + ERR_FAIL_COND(!get_tree()); get_tree()->node_count--; orphan_node_count++; @@ -840,6 +844,8 @@ bool Node::is_processing_internal() const { void Node::set_process_priority(int p_priority) { data.process_priority = p_priority; + ERR_FAIL_COND(!data.tree); + if (is_processing()) data.tree->make_group_changed("idle_process"); diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index dcd70a1844..8561d9aedb 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -1701,6 +1701,8 @@ bool Viewport::_gui_drop(Control *p_at_control, Point2 p_at_pos, bool p_just_che void Viewport::_gui_input_event(Ref<InputEvent> p_event) { + ERR_FAIL_COND(p_event.is_null()) + //? /* if (!is_visible()) { diff --git a/scene/resources/texture.cpp b/scene/resources/texture.cpp index 3a0144849a..a5e9351753 100644 --- a/scene/resources/texture.cpp +++ b/scene/resources/texture.cpp @@ -1487,8 +1487,10 @@ uint32_t CubeMap::get_flags() const { void CubeMap::set_side(Side p_side, const Ref<Image> &p_image) { + ERR_FAIL_COND(p_image.is_null()); ERR_FAIL_COND(p_image->empty()); ERR_FAIL_INDEX(p_side, 6); + if (!_is_valid()) { format = p_image->get_format(); w = p_image->get_width(); diff --git a/servers/audio/audio_stream.cpp b/servers/audio/audio_stream.cpp index 388346b67c..17f5e158a7 100644 --- a/servers/audio/audio_stream.cpp +++ b/servers/audio/audio_stream.cpp @@ -49,8 +49,9 @@ void AudioStreamPlaybackResampled::_begin_resample() { void AudioStreamPlaybackResampled::mix(AudioFrame *p_buffer, float p_rate_scale, int p_frames) { float target_rate = AudioServer::get_singleton()->get_mix_rate(); + float global_rate_scale = AudioServer::get_singleton()->get_global_rate_scale(); - uint64_t mix_increment = uint64_t(((get_stream_sampling_rate() * p_rate_scale) / double(target_rate)) * double(FP_LEN)); + uint64_t mix_increment = uint64_t(((get_stream_sampling_rate() * p_rate_scale) / double(target_rate * global_rate_scale)) * double(FP_LEN)); for (int i = 0; i < p_frames; i++) { diff --git a/servers/audio/effects/audio_effect_record.cpp b/servers/audio/effects/audio_effect_record.cpp index abf9d5593c..acf27d2bbf 100644 --- a/servers/audio/effects/audio_effect_record.cpp +++ b/servers/audio/effects/audio_effect_record.cpp @@ -216,6 +216,9 @@ Ref<AudioStreamSample> AudioEffectRecord::get_recording() const { PoolVector<uint8_t> dst_data; + ERR_FAIL_COND_V(current_instance.is_null(), NULL); + ERR_FAIL_COND_V(current_instance->recording_data.size(), NULL); + if (dst_format == AudioStreamSample::FORMAT_8_BITS) { int data_size = current_instance->recording_data.size(); dst_data.resize(data_size); diff --git a/servers/audio_server.cpp b/servers/audio_server.cpp index fc3ecedd03..a6473d69c0 100644 --- a/servers/audio_server.cpp +++ b/servers/audio_server.cpp @@ -944,6 +944,15 @@ bool AudioServer::is_bus_channel_active(int p_bus, int p_channel) const { return buses[p_bus]->channels[p_channel].active; } +void AudioServer::set_global_rate_scale(float p_scale) { + + global_rate_scale = p_scale; +} +float AudioServer::get_global_rate_scale() const { + + return global_rate_scale; +} + void AudioServer::init_channels_and_buffers() { channel_count = get_channel_count(); temp_buffer.resize(channel_count); @@ -1352,6 +1361,9 @@ void AudioServer::_bind_methods() { ClassDB::bind_method(D_METHOD("get_bus_peak_volume_left_db", "bus_idx", "channel"), &AudioServer::get_bus_peak_volume_left_db); ClassDB::bind_method(D_METHOD("get_bus_peak_volume_right_db", "bus_idx", "channel"), &AudioServer::get_bus_peak_volume_right_db); + ClassDB::bind_method(D_METHOD("set_global_rate_scale", "scale"), &AudioServer::set_global_rate_scale); + ClassDB::bind_method(D_METHOD("get_global_rate_scale"), &AudioServer::get_global_rate_scale); + ClassDB::bind_method(D_METHOD("lock"), &AudioServer::lock); ClassDB::bind_method(D_METHOD("unlock"), &AudioServer::unlock); @@ -1372,6 +1384,10 @@ void AudioServer::_bind_methods() { ClassDB::bind_method(D_METHOD("set_bus_layout", "bus_layout"), &AudioServer::set_bus_layout); ClassDB::bind_method(D_METHOD("generate_bus_layout"), &AudioServer::generate_bus_layout); + ADD_PROPERTY(PropertyInfo(Variant::INT, "bus_count"), "set_bus_count", "get_bus_count"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "device"), "set_device", "get_device"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "global_rate_scale"), "set_global_rate_scale", "get_global_rate_scale"); + ADD_SIGNAL(MethodInfo("bus_layout_changed")); BIND_ENUM_CONSTANT(SPEAKER_MODE_STEREO); @@ -1396,6 +1412,7 @@ AudioServer::AudioServer() { #endif mix_time = 0; mix_size = 0; + global_rate_scale = 1; } AudioServer::~AudioServer() { diff --git a/servers/audio_server.h b/servers/audio_server.h index 942fe7bc87..b0fff9d4b7 100644 --- a/servers/audio_server.h +++ b/servers/audio_server.h @@ -181,6 +181,8 @@ private: int channel_count; int to_mix; + float global_rate_scale; + struct Bus { StringName name; @@ -339,6 +341,9 @@ public: bool is_bus_channel_active(int p_bus, int p_channel) const; + void set_global_rate_scale(float p_scale); + float get_global_rate_scale() const; + virtual void init(); virtual void finish(); virtual void update(); diff --git a/servers/physics/collision_object_sw.cpp b/servers/physics/collision_object_sw.cpp index b1c21290ab..39de440da2 100644 --- a/servers/physics/collision_object_sw.cpp +++ b/servers/physics/collision_object_sw.cpp @@ -76,6 +76,13 @@ void CollisionObjectSW::set_shape_transform(int p_index, const Transform &p_tran //_shapes_changed(); } +void CollisionObjectSW::set_shape_as_disabled(int p_idx, bool p_enable) { + shapes.write[p_idx].disabled = p_enable; + if (!pending_shape_update_list.in_list()) { + PhysicsServerSW::singleton->pending_shape_update_list.add(&pending_shape_update_list); + } +} + void CollisionObjectSW::remove_shape(ShapeSW *p_shape) { //remove a shape, all the times it appears diff --git a/servers/physics/collision_object_sw.h b/servers/physics/collision_object_sw.h index c2c3fe0e5a..895eda8528 100644 --- a/servers/physics/collision_object_sw.h +++ b/servers/physics/collision_object_sw.h @@ -139,8 +139,11 @@ public: _FORCE_INLINE_ void set_ray_pickable(bool p_enable) { ray_pickable = p_enable; } _FORCE_INLINE_ bool is_ray_pickable() const { return ray_pickable; } - _FORCE_INLINE_ void set_shape_as_disabled(int p_idx, bool p_enable) { shapes.write[p_idx].disabled = p_enable; } - _FORCE_INLINE_ bool is_shape_set_as_disabled(int p_idx) const { return shapes[p_idx].disabled; } + void set_shape_as_disabled(int p_idx, bool p_enable); + _FORCE_INLINE_ bool is_shape_set_as_disabled(int p_idx) const { + CRASH_BAD_INDEX(p_idx, shapes.size()); + return shapes[p_idx].disabled; + } _FORCE_INLINE_ void set_collision_layer(uint32_t p_layer) { collision_layer = p_layer; } _FORCE_INLINE_ uint32_t get_collision_layer() const { return collision_layer; } diff --git a/servers/physics_2d/collision_object_2d_sw.cpp b/servers/physics_2d/collision_object_2d_sw.cpp index 445a2e0613..f556638db1 100644 --- a/servers/physics_2d/collision_object_2d_sw.cpp +++ b/servers/physics_2d/collision_object_2d_sw.cpp @@ -29,6 +29,7 @@ /*************************************************************************/ #include "collision_object_2d_sw.h" +#include "servers/physics_2d/physics_2d_server_sw.h" #include "space_2d_sw.h" void CollisionObject2DSW::add_shape(Shape2DSW *p_shape, const Transform2D &p_transform, bool p_disabled) { @@ -43,8 +44,12 @@ void CollisionObject2DSW::add_shape(Shape2DSW *p_shape, const Transform2D &p_tra s.one_way_collision_margin = 0; shapes.push_back(s); p_shape->add_owner(this); - _update_shapes(); - _shapes_changed(); + + if (!pending_shape_update_list.in_list()) { + Physics2DServerSW::singletonsw->pending_shape_update_list.add(&pending_shape_update_list); + } + // _update_shapes(); + // _shapes_changed(); } void CollisionObject2DSW::set_shape(int p_index, Shape2DSW *p_shape) { @@ -54,8 +59,12 @@ void CollisionObject2DSW::set_shape(int p_index, Shape2DSW *p_shape) { shapes.write[p_index].shape = p_shape; p_shape->add_owner(this); - _update_shapes(); - _shapes_changed(); + + if (!pending_shape_update_list.in_list()) { + Physics2DServerSW::singletonsw->pending_shape_update_list.add(&pending_shape_update_list); + } + // _update_shapes(); + // _shapes_changed(); } void CollisionObject2DSW::set_shape_metadata(int p_index, const Variant &p_metadata) { @@ -70,8 +79,12 @@ void CollisionObject2DSW::set_shape_transform(int p_index, const Transform2D &p_ shapes.write[p_index].xform = p_transform; shapes.write[p_index].xform_inv = p_transform.affine_inverse(); - _update_shapes(); - _shapes_changed(); + + if (!pending_shape_update_list.in_list()) { + Physics2DServerSW::singletonsw->pending_shape_update_list.add(&pending_shape_update_list); + } + // _update_shapes(); + // _shapes_changed(); } void CollisionObject2DSW::set_shape_as_disabled(int p_idx, bool p_disabled) { @@ -89,9 +102,15 @@ void CollisionObject2DSW::set_shape_as_disabled(int p_idx, bool p_disabled) { if (p_disabled && shape.bpid != 0) { space->get_broadphase()->remove(shape.bpid); shape.bpid = 0; - _update_shapes(); + if (!pending_shape_update_list.in_list()) { + Physics2DServerSW::singletonsw->pending_shape_update_list.add(&pending_shape_update_list); + } + //_update_shapes(); } else if (!p_disabled && shape.bpid == 0) { - _update_shapes(); // automatically adds shape with bpid == 0 + if (!pending_shape_update_list.in_list()) { + Physics2DServerSW::singletonsw->pending_shape_update_list.add(&pending_shape_update_list); + } + //_update_shapes(); // automatically adds shape with bpid == 0 } } @@ -122,8 +141,11 @@ void CollisionObject2DSW::remove_shape(int p_index) { shapes[p_index].shape->remove_owner(this); shapes.remove(p_index); - _update_shapes(); - _shapes_changed(); + if (!pending_shape_update_list.in_list()) { + Physics2DServerSW::singletonsw->pending_shape_update_list.add(&pending_shape_update_list); + } + // _update_shapes(); + // _shapes_changed(); } void CollisionObject2DSW::_set_static(bool p_static) { @@ -239,7 +261,8 @@ void CollisionObject2DSW::_shape_changed() { _shapes_changed(); } -CollisionObject2DSW::CollisionObject2DSW(Type p_type) { +CollisionObject2DSW::CollisionObject2DSW(Type p_type) : + pending_shape_update_list(this) { _static = true; type = p_type; diff --git a/servers/physics_2d/collision_object_2d_sw.h b/servers/physics_2d/collision_object_2d_sw.h index fa18e61262..ed59469878 100644 --- a/servers/physics_2d/collision_object_2d_sw.h +++ b/servers/physics_2d/collision_object_2d_sw.h @@ -78,6 +78,8 @@ private: uint32_t collision_layer; bool _static; + SelfList<CollisionObject2DSW> pending_shape_update_list; + void _update_shapes(); protected: diff --git a/servers/physics_2d/physics_2d_server_sw.cpp b/servers/physics_2d/physics_2d_server_sw.cpp index 0efa15d43e..cc656d3b73 100644 --- a/servers/physics_2d/physics_2d_server_sw.cpp +++ b/servers/physics_2d/physics_2d_server_sw.cpp @@ -902,6 +902,8 @@ void Physics2DServerSW::body_apply_torque_impulse(RID p_body, real_t p_torque) { Body2DSW *body = body_owner.get(p_body); ERR_FAIL_COND(!body); + _update_shapes(); + body->apply_torque_impulse(p_torque); } @@ -910,6 +912,8 @@ void Physics2DServerSW::body_apply_impulse(RID p_body, const Vector2 &p_pos, con Body2DSW *body = body_owner.get(p_body); ERR_FAIL_COND(!body); + _update_shapes(); + body->apply_impulse(p_pos, p_impulse); body->wakeup(); }; @@ -944,6 +948,8 @@ void Physics2DServerSW::body_set_axis_velocity(RID p_body, const Vector2 &p_axis Body2DSW *body = body_owner.get(p_body); ERR_FAIL_COND(!body); + _update_shapes(); + Vector2 v = body->get_linear_velocity(); Vector2 axis = p_axis_velocity.normalized(); v -= axis * axis.dot(v); @@ -1052,6 +1058,8 @@ bool Physics2DServerSW::body_test_motion(RID p_body, const Transform2D &p_from, ERR_FAIL_COND_V(!body->get_space(), false); ERR_FAIL_COND_V(body->get_space()->is_locked(), false); + _update_shapes(); + return body->get_space()->test_body_motion(body, p_from, p_motion, p_infinite_inertia, p_margin, r_result, p_exclude_raycast_shapes); } @@ -1238,6 +1246,8 @@ Physics2DServer::JointType Physics2DServerSW::joint_get_type(RID p_joint) const void Physics2DServerSW::free(RID p_rid) { + _update_shapes(); // just in case + if (shape_owner.owns(p_rid)) { Shape2DSW *shape = shape_owner.get(p_rid); @@ -1335,6 +1345,8 @@ void Physics2DServerSW::step(real_t p_step) { if (!active) return; + _update_shapes(); + doing_sync = false; last_step = p_step; @@ -1418,6 +1430,14 @@ void Physics2DServerSW::finish() { memdelete(direct_state); }; +void Physics2DServerSW::_update_shapes() { + + while (pending_shape_update_list.first()) { + pending_shape_update_list.first()->self()->_shape_changed(); + pending_shape_update_list.remove(pending_shape_update_list.first()); + } +} + int Physics2DServerSW::get_process_info(ProcessInfo p_info) { switch (p_info) { diff --git a/servers/physics_2d/physics_2d_server_sw.h b/servers/physics_2d/physics_2d_server_sw.h index adc011af40..72625c397c 100644 --- a/servers/physics_2d/physics_2d_server_sw.h +++ b/servers/physics_2d/physics_2d_server_sw.h @@ -70,6 +70,9 @@ class Physics2DServerSW : public Physics2DServer { static Physics2DServerSW *singletonsw; //void _clear_query(Query2DSW *p_query); + friend class CollisionObject2DSW; + SelfList<CollisionObject2DSW>::List pending_shape_update_list; + void _update_shapes(); RID _shape_create(ShapeType p_shape); diff --git a/thirdparty/README.md b/thirdparty/README.md index 3e1e8f9734..b003ae6e8a 100644 --- a/thirdparty/README.md +++ b/thirdparty/README.md @@ -308,9 +308,13 @@ File extracted from upstream release tarball `mbedtls-2.16.0-apache.tgz`: ## miniupnpc - Upstream: https://github.com/miniupnp/miniupnp/tree/master/miniupnpc -- Version: git (25615e0, 2018) +- Version: git (3cf6efa, 2019) - License: BSD-3-Clause +Extract only the `miniupnpc` folder inside `thirdparty/miniupnpc`. +Exclude all non `.c` and `.h` files, plus all files beginning with `test` +`minihttptestserver.c` and `wingenminiupnpcstrings.c`. + The only modified file is miniupnpcstrings.h, which was created for Godot (it is usually autogenerated by cmake). diff --git a/thirdparty/miniupnpc/LICENSE b/thirdparty/miniupnpc/LICENSE index 0816733704..39e0345f8a 100644 --- a/thirdparty/miniupnpc/LICENSE +++ b/thirdparty/miniupnpc/LICENSE @@ -1,5 +1,5 @@ -MiniUPnPc -Copyright (c) 2005-2016, Thomas BERNARD +MiniUPnP Project +Copyright (c) 2005-2019, Thomas BERNARD All rights reserved. Redistribution and use in source and binary forms, with or without diff --git a/thirdparty/miniupnpc/miniupnpc.def b/thirdparty/miniupnpc/miniupnpc.def deleted file mode 100644 index 60e0bbe423..0000000000 --- a/thirdparty/miniupnpc/miniupnpc.def +++ /dev/null @@ -1,45 +0,0 @@ -LIBRARY -; miniupnpc library - miniupnpc - -EXPORTS -; miniupnpc - upnpDiscover - freeUPNPDevlist - parserootdesc - UPNP_GetValidIGD - UPNP_GetIGDFromUrl - GetUPNPUrls - FreeUPNPUrls -; miniwget - miniwget - miniwget_getaddr -; upnpcommands - UPNP_GetTotalBytesSent - UPNP_GetTotalBytesReceived - UPNP_GetTotalPacketsSent - UPNP_GetTotalPacketsReceived - UPNP_GetStatusInfo - UPNP_GetConnectionTypeInfo - UPNP_GetExternalIPAddress - UPNP_GetLinkLayerMaxBitRates - UPNP_AddPortMapping - UPNP_AddAnyPortMapping - UPNP_DeletePortMapping - UPNP_DeletePortMappingRange - UPNP_GetPortMappingNumberOfEntries - UPNP_GetSpecificPortMappingEntry - UPNP_GetGenericPortMappingEntry - UPNP_GetListOfPortMappings - UPNP_AddPinhole - UPNP_CheckPinholeWorking - UPNP_UpdatePinhole - UPNP_GetPinholePackets - UPNP_DeletePinhole - UPNP_GetFirewallStatus - UPNP_GetOutboundPinholeTimeout -; upnperrors - strupnperror -; portlistingparse - ParsePortListing - FreePortListing diff --git a/thirdparty/miniupnpc/miniupnpc.h b/thirdparty/miniupnpc/miniupnpc.h deleted file mode 100644 index 8ddc282bd1..0000000000 --- a/thirdparty/miniupnpc/miniupnpc.h +++ /dev/null @@ -1,153 +0,0 @@ -/* $Id: miniupnpc.h,v 1.53 2018/05/07 11:05:16 nanard Exp $ */ -/* vim: tabstop=4 shiftwidth=4 noexpandtab - * Project: miniupnp - * http://miniupnp.free.fr/ - * Author: Thomas Bernard - * Copyright (c) 2005-2018 Thomas Bernard - * This software is subjects to the conditions detailed - * in the LICENCE file provided within this distribution */ -#ifndef MINIUPNPC_H_INCLUDED -#define MINIUPNPC_H_INCLUDED - -#include "miniupnpc_declspec.h" -#include "igd_desc_parse.h" -#include "upnpdev.h" - -/* error codes : */ -#define UPNPDISCOVER_SUCCESS (0) -#define UPNPDISCOVER_UNKNOWN_ERROR (-1) -#define UPNPDISCOVER_SOCKET_ERROR (-101) -#define UPNPDISCOVER_MEMORY_ERROR (-102) - -/* versions : */ -#define MINIUPNPC_VERSION "2.1" -#define MINIUPNPC_API_VERSION 17 - -/* Source port: - Using "1" as an alias for 1900 for backwards compatibility - (presuming one would have used that for the "sameport" parameter) */ -#define UPNP_LOCAL_PORT_ANY 0 -#define UPNP_LOCAL_PORT_SAME 1 - -#ifdef __cplusplus -extern "C" { -#endif - -/* Structures definitions : */ -struct UPNParg { const char * elt; const char * val; }; - -char * -simpleUPnPcommand(int, const char *, const char *, - const char *, struct UPNParg *, - int *); - -/* upnpDiscover() - * discover UPnP devices on the network. - * The discovered devices are returned as a chained list. - * It is up to the caller to free the list with freeUPNPDevlist(). - * delay (in millisecond) is the maximum time for waiting any device - * response. - * If available, device list will be obtained from MiniSSDPd. - * Default path for minissdpd socket will be used if minissdpdsock argument - * is NULL. - * If multicastif is not NULL, it will be used instead of the default - * multicast interface for sending SSDP discover packets. - * If localport is set to UPNP_LOCAL_PORT_SAME(1) SSDP packets will be sent - * from the source port 1900 (same as destination port), if set to - * UPNP_LOCAL_PORT_ANY(0) system assign a source port, any other value will - * be attempted as the source port. - * "searchalltypes" parameter is useful when searching several types, - * if 0, the discovery will stop with the first type returning results. - * TTL should default to 2. */ -MINIUPNP_LIBSPEC struct UPNPDev * -upnpDiscover(int delay, const char * multicastif, - const char * minissdpdsock, int localport, - int ipv6, unsigned char ttl, - int * error); - -MINIUPNP_LIBSPEC struct UPNPDev * -upnpDiscoverAll(int delay, const char * multicastif, - const char * minissdpdsock, int localport, - int ipv6, unsigned char ttl, - int * error); - -MINIUPNP_LIBSPEC struct UPNPDev * -upnpDiscoverDevice(const char * device, int delay, const char * multicastif, - const char * minissdpdsock, int localport, - int ipv6, unsigned char ttl, - int * error); - -MINIUPNP_LIBSPEC struct UPNPDev * -upnpDiscoverDevices(const char * const deviceTypes[], - int delay, const char * multicastif, - const char * minissdpdsock, int localport, - int ipv6, unsigned char ttl, - int * error, - int searchalltypes); - -/* parserootdesc() : - * parse root XML description of a UPnP device and fill the IGDdatas - * structure. */ -MINIUPNP_LIBSPEC void parserootdesc(const char *, int, struct IGDdatas *); - -/* structure used to get fast access to urls - * controlURL: controlURL of the WANIPConnection - * ipcondescURL: url of the description of the WANIPConnection - * controlURL_CIF: controlURL of the WANCommonInterfaceConfig - * controlURL_6FC: controlURL of the WANIPv6FirewallControl - */ -struct UPNPUrls { - char * controlURL; - char * ipcondescURL; - char * controlURL_CIF; - char * controlURL_6FC; - char * rootdescURL; -}; - -/* UPNP_GetValidIGD() : - * return values : - * 0 = NO IGD found - * 1 = A valid connected IGD has been found - * 2 = A valid IGD has been found but it reported as - * not connected - * 3 = an UPnP device has been found but was not recognized as an IGD - * - * In any non zero return case, the urls and data structures - * passed as parameters are set. Donc forget to call FreeUPNPUrls(urls) to - * free allocated memory. - */ -MINIUPNP_LIBSPEC int -UPNP_GetValidIGD(struct UPNPDev * devlist, - struct UPNPUrls * urls, - struct IGDdatas * data, - char * lanaddr, int lanaddrlen); - -/* UPNP_GetIGDFromUrl() - * Used when skipping the discovery process. - * When succeding, urls, data, and lanaddr arguments are set. - * return value : - * 0 - Not ok - * 1 - OK */ -MINIUPNP_LIBSPEC int -UPNP_GetIGDFromUrl(const char * rootdescurl, - struct UPNPUrls * urls, - struct IGDdatas * data, - char * lanaddr, int lanaddrlen); - -MINIUPNP_LIBSPEC void -GetUPNPUrls(struct UPNPUrls *, struct IGDdatas *, - const char *, unsigned int); - -MINIUPNP_LIBSPEC void -FreeUPNPUrls(struct UPNPUrls *); - -/* return 0 or 1 */ -MINIUPNP_LIBSPEC int UPNPIGD_IsConnected(struct UPNPUrls *, struct IGDdatas *); - - -#ifdef __cplusplus -} -#endif - -#endif - diff --git a/thirdparty/miniupnpc/codelength.h b/thirdparty/miniupnpc/miniupnpc/codelength.h index ea0b005ffe..ea0b005ffe 100644 --- a/thirdparty/miniupnpc/codelength.h +++ b/thirdparty/miniupnpc/miniupnpc/codelength.h diff --git a/thirdparty/miniupnpc/connecthostport.c b/thirdparty/miniupnpc/miniupnpc/connecthostport.c index ea6e4e5943..a59dc82437 100644 --- a/thirdparty/miniupnpc/connecthostport.c +++ b/thirdparty/miniupnpc/miniupnpc/connecthostport.c @@ -1,8 +1,8 @@ -/* $Id: connecthostport.c,v 1.15 2015/10/09 16:26:19 nanard Exp $ */ +/* $Id: connecthostport.c,v 1.21 2019/04/23 12:11:08 nanard Exp $ */ /* vim: tabstop=4 shiftwidth=4 noexpandtab * Project : miniupnp * Author : Thomas Bernard - * Copyright (c) 2010-2018 Thomas Bernard + * Copyright (c) 2010-2019 Thomas Bernard * This software is subject to the conditions detailed in the * LICENCE file provided in this distribution. */ @@ -41,13 +41,6 @@ #include <sys/select.h> #endif /* #else _WIN32 */ -/* definition of PRINT_SOCKET_ERROR */ -#ifdef _WIN32 -#define PRINT_SOCKET_ERROR(x) fprintf(stderr, "Socket error: %s, %d\n", x, WSAGetLastError()); -#else -#define PRINT_SOCKET_ERROR(x) perror(x) -#endif - #if defined(__amigaos__) || defined(__amigaos4__) #define herror(A) printf("%s\n", A) #endif @@ -123,8 +116,22 @@ SOCKET connecthostport(const char * host, unsigned short port, int err; FD_ZERO(&wset); FD_SET(s, &wset); - if((n = select(s + 1, NULL, &wset, NULL, NULL)) == -1 && errno == EINTR) +#ifdef MINIUPNPC_SET_SOCKET_TIMEOUT + timeout.tv_sec = 3; + timeout.tv_usec = 0; + n = select(s + 1, NULL, &wset, NULL, &timeout); +#else + n = select(s + 1, NULL, &wset, NULL, NULL); +#endif + if(n == -1 && errno == EINTR) continue; +#ifdef MINIUPNPC_SET_SOCKET_TIMEOUT + if(n == 0) { + errno = ETIMEDOUT; + n = -1; + break; + } +#endif /*len = 0;*/ /*n = getpeername(s, NULL, &len);*/ len = sizeof(err); @@ -163,7 +170,7 @@ SOCKET connecthostport(const char * host, unsigned short port, for(i = 0, j = 1; host[j] && (host[j] != ']') && i < MAXHOSTNAMELEN; i++, j++) { tmp_host[i] = host[j]; - if(0 == memcmp(host+j, "%25", 3)) /* %25 is just url encoding for '%' */ + if(0 == strncmp(host+j, "%25", 3)) /* %25 is just url encoding for '%' */ j+=2; /* skip "25" */ } tmp_host[i] = '\0'; @@ -183,9 +190,11 @@ SOCKET connecthostport(const char * host, unsigned short port, #endif return INVALID_SOCKET; } - s = -1; + s = INVALID_SOCKET; for(p = ai; p; p = p->ai_next) { + if(!ISINVALID(s)) + closesocket(s); s = socket(p->ai_family, p->ai_socktype, p->ai_protocol); if(ISINVALID(s)) continue; @@ -208,7 +217,7 @@ SOCKET connecthostport(const char * host, unsigned short port, PRINT_SOCKET_ERROR("setsockopt"); } #endif /* #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT */ - n = connect(s, p->ai_addr, p->ai_addrlen); + n = connect(s, p->ai_addr, MSC_CAST_INT p->ai_addrlen); #ifdef MINIUPNPC_IGNORE_EINTR /* EINTR The system call was interrupted by a signal that was caught * EINPROGRESS The socket is nonblocking and the connection cannot @@ -220,8 +229,22 @@ SOCKET connecthostport(const char * host, unsigned short port, int err; FD_ZERO(&wset); FD_SET(s, &wset); - if((n = select(s + 1, NULL, &wset, NULL, NULL)) == -1 && errno == EINTR) +#ifdef MINIUPNPC_SET_SOCKET_TIMEOUT + timeout.tv_sec = 3; + timeout.tv_usec = 0; + n = select(s + 1, NULL, &wset, NULL, &timeout); +#else + n = select(s + 1, NULL, &wset, NULL, NULL); +#endif + if(n == -1 && errno == EINTR) continue; +#ifdef MINIUPNPC_SET_SOCKET_TIMEOUT + if(n == 0) { + errno = ETIMEDOUT; + n = -1; + break; + } +#endif /*len = 0;*/ /*n = getpeername(s, NULL, &len);*/ len = sizeof(err); @@ -237,15 +260,8 @@ SOCKET connecthostport(const char * host, unsigned short port, } } #endif /* #ifdef MINIUPNPC_IGNORE_EINTR */ - if(n < 0) - { - closesocket(s); - continue; - } - else - { + if(n >= 0) /* connect() was successful */ break; - } } freeaddrinfo(ai); if(ISINVALID(s)) @@ -256,9 +272,9 @@ SOCKET connecthostport(const char * host, unsigned short port, if(n < 0) { PRINT_SOCKET_ERROR("connect"); + closesocket(s); return INVALID_SOCKET; } #endif /* #ifdef USE_GETHOSTBYNAME */ return s; } - diff --git a/thirdparty/miniupnpc/connecthostport.h b/thirdparty/miniupnpc/miniupnpc/connecthostport.h index 701816b5b6..701816b5b6 100644 --- a/thirdparty/miniupnpc/connecthostport.h +++ b/thirdparty/miniupnpc/miniupnpc/connecthostport.h diff --git a/thirdparty/miniupnpc/igd_desc_parse.c b/thirdparty/miniupnpc/miniupnpc/igd_desc_parse.c index d2999ad011..d2999ad011 100644 --- a/thirdparty/miniupnpc/igd_desc_parse.c +++ b/thirdparty/miniupnpc/miniupnpc/igd_desc_parse.c diff --git a/thirdparty/miniupnpc/igd_desc_parse.h b/thirdparty/miniupnpc/miniupnpc/igd_desc_parse.h index 0de546b697..0de546b697 100644 --- a/thirdparty/miniupnpc/igd_desc_parse.h +++ b/thirdparty/miniupnpc/miniupnpc/igd_desc_parse.h diff --git a/thirdparty/miniupnpc/listdevices.c b/thirdparty/miniupnpc/miniupnpc/listdevices.c index bd9ba57efc..bd9ba57efc 100644 --- a/thirdparty/miniupnpc/listdevices.c +++ b/thirdparty/miniupnpc/miniupnpc/listdevices.c diff --git a/thirdparty/miniupnpc/minisoap.c b/thirdparty/miniupnpc/miniupnpc/minisoap.c index 520c9302e8..f92b36ce89 100644 --- a/thirdparty/miniupnpc/minisoap.c +++ b/thirdparty/miniupnpc/miniupnpc/minisoap.c @@ -25,12 +25,6 @@ /* only for malloc */ #include <stdlib.h> -#ifdef _WIN32 -#define PRINT_SOCKET_ERROR(x) fprintf(stderr, "Socket error: %s, %d\n", x, WSAGetLastError()); -#else -#define PRINT_SOCKET_ERROR(x) perror(x) -#endif - /* httpWrite sends the headers and the body to the socket * and returns the number of bytes sent */ static int @@ -79,11 +73,10 @@ int soapPostSubmit(SOCKET fd, const char * body, const char * httpversion) { - int bodysize; char headerbuf[512]; int headerssize; char portstr[8]; - bodysize = (int)strlen(body); + int bodysize = (int)strlen(body); /* We are not using keep-alive HTTP connections. * HTTP/1.1 needs the header Connection: close to do that. * This is the default with HTTP/1.0 diff --git a/thirdparty/miniupnpc/minisoap.h b/thirdparty/miniupnpc/miniupnpc/minisoap.h index d6a45d03ba..d6a45d03ba 100644 --- a/thirdparty/miniupnpc/minisoap.h +++ b/thirdparty/miniupnpc/miniupnpc/minisoap.h diff --git a/thirdparty/miniupnpc/minissdpc.c b/thirdparty/miniupnpc/miniupnpc/minissdpc.c index 1d29b4ba5b..29f8110155 100644 --- a/thirdparty/miniupnpc/minissdpc.c +++ b/thirdparty/miniupnpc/miniupnpc/minissdpc.c @@ -1,9 +1,9 @@ -/* $Id: minissdpc.c,v 1.32 2016/10/07 09:04:36 nanard Exp $ */ +/* $Id: minissdpc.c,v 1.40 2019/04/23 12:12:55 nanard Exp $ */ /* vim: tabstop=4 shiftwidth=4 noexpandtab * Project : miniupnp * Web : http://miniupnp.free.fr/ * Author : Thomas BERNARD - * copyright (c) 2005-2018 Thomas Bernard + * copyright (c) 2005-2019 Thomas Bernard * This software is subjet to the conditions detailed in the * provided LICENCE file. */ /*#include <syslog.h>*/ @@ -381,6 +381,7 @@ free_tmp_and_return: * the last 4 arguments are filled during the parsing : * - location/locationsize : "location:" field of the SSDP reply packet * - st/stsize : "st:" field of the SSDP reply packet. + * - usn/usnsize : "usn:" filed of the SSDP reply packet * The strings are NOT null terminated */ static void parseMSEARCHReply(const char * reply, int size, @@ -418,17 +419,17 @@ parseMSEARCHReply(const char * reply, int size, putchar('\n');*/ /* skip the colon and white spaces */ do { b++; } while(reply[b]==' '); - if(0==strncasecmp(reply+a, "location", 8)) + if(0==strncasecmp(reply+a, "location:", 9)) { *location = reply+b; *locationsize = i-b; } - else if(0==strncasecmp(reply+a, "st", 2)) + else if(0==strncasecmp(reply+a, "st:", 3)) { *st = reply+b; *stsize = i-b; } - else if(0==strncasecmp(reply+a, "usn", 3)) + else if(0==strncasecmp(reply+a, "usn:", 4)) { *usn = reply+b; *usnsize = i-b; @@ -471,7 +472,7 @@ ssdpDiscoverDevices(const char * const deviceTypes[], int searchalltypes) { struct UPNPDev * tmp; - struct UPNPDev * devlist = 0; + struct UPNPDev * devlist = NULL; unsigned int scope_id = 0; int opt = 1; static const char MSearchMsgFmt[] = @@ -491,7 +492,7 @@ ssdpDiscoverDevices(const char * const deviceTypes[], struct sockaddr_storage sockudp_w; #else int rv; - struct addrinfo hints, *servinfo, *p; + struct addrinfo hints, *servinfo; #endif #ifdef _WIN32 unsigned long _ttl = (unsigned long)ttl; @@ -545,51 +546,42 @@ ssdpDiscoverDevices(const char * const deviceTypes[], destAddr.sin_addr.s_addr = inet_addr("223.255.255.255"); destAddr.sin_port = 0; if (GetBestInterfaceEx((struct sockaddr *)&destAddr, &ifbestidx) == NO_ERROR) { - DWORD dwSize = 0; - DWORD dwRetVal = 0; - unsigned int i = 0; - ULONG flags = GAA_FLAG_INCLUDE_PREFIX; - ULONG family = AF_INET; - LPVOID lpMsgBuf = NULL; + DWORD dwRetVal = NO_ERROR; PIP_ADAPTER_ADDRESSES pAddresses = NULL; - ULONG outBufLen = 0; - ULONG Iterations = 0; + ULONG outBufLen = 15360; + int Iterations; PIP_ADAPTER_ADDRESSES pCurrAddresses = NULL; PIP_ADAPTER_UNICAST_ADDRESS pUnicast = NULL; - PIP_ADAPTER_ANYCAST_ADDRESS pAnycast = NULL; - PIP_ADAPTER_MULTICAST_ADDRESS pMulticast = NULL; - IP_ADAPTER_DNS_SERVER_ADDRESS *pDnServer = NULL; - IP_ADAPTER_PREFIX *pPrefix = NULL; - outBufLen = 15360; - do { + for (Iterations = 0; Iterations < 3; Iterations++) { pAddresses = (IP_ADAPTER_ADDRESSES *) HeapAlloc(GetProcessHeap(), 0, outBufLen); if (pAddresses == NULL) { break; } - dwRetVal = GetAdaptersAddresses(family, flags, NULL, pAddresses, &outBufLen); + dwRetVal = GetAdaptersAddresses(AF_INET, GAA_FLAG_INCLUDE_PREFIX, NULL, pAddresses, &outBufLen); - if (dwRetVal == ERROR_BUFFER_OVERFLOW) { - HeapFree(GetProcessHeap(), 0, pAddresses); - pAddresses = NULL; - } else { + if (dwRetVal != ERROR_BUFFER_OVERFLOW) { break; } - Iterations++; - } while ((dwRetVal == ERROR_BUFFER_OVERFLOW) && (Iterations < 3)); + HeapFree(GetProcessHeap(), 0, pAddresses); + pAddresses = NULL; + } if (dwRetVal == NO_ERROR) { pCurrAddresses = pAddresses; while (pCurrAddresses) { #ifdef DEBUG + int i; + PIP_ADAPTER_MULTICAST_ADDRESS pMulticast = NULL; + PIP_ADAPTER_ANYCAST_ADDRESS pAnycast = NULL; + printf("\tIfIndex (IPv4 interface): %u\n", pCurrAddresses->IfIndex); printf("\tAdapter name: %s\n", pCurrAddresses->AdapterName); pUnicast = pCurrAddresses->FirstUnicastAddress; if (pUnicast != NULL) { for (i = 0; pUnicast != NULL; i++) { - IPAddr.S_un.S_addr = (u_long) pUnicast->Address; - printf("\tIP Address[%d]: \t%s\n", i, inet_ntoa(IPAddr) ); + printf("\tIP Address[%d]: \t%s\n", i, inet_ntoa(((PSOCKADDR_IN)pUnicast->Address.lpSockaddr)->sin_addr) ); pUnicast = pUnicast->Next; } printf("\tNumber of Unicast Addresses: %d\n", i); @@ -597,8 +589,7 @@ ssdpDiscoverDevices(const char * const deviceTypes[], pAnycast = pCurrAddresses->FirstAnycastAddress; if (pAnycast) { for (i = 0; pAnycast != NULL; i++) { - IPAddr.S_un.S_addr = (u_long) pAnyCast->Address; - printf("\tAnycast Address[%d]: \t%s\n", i, inet_ntoa(IPAddr) ); + printf("\tAnycast Address[%d]: \t%s\n", i, inet_ntoa(((PSOCKADDR_IN)pAnycast->Address.lpSockaddr)->sin_addr) ); pAnycast = pAnycast->Next; } printf("\tNumber of Anycast Addresses: %d\n", i); @@ -606,8 +597,8 @@ ssdpDiscoverDevices(const char * const deviceTypes[], pMulticast = pCurrAddresses->FirstMulticastAddress; if (pMulticast) { for (i = 0; pMulticast != NULL; i++) { - IPAddr.S_un.S_addr = (u_long) pMultiCast->Address; - printf("\tMulticast Address[%d]: \t%s\n", i, inet_ntoa(IPAddr) ); + printf("\tMulticast Address[%d]: \t%s\n", i, inet_ntoa(((PSOCKADDR_IN)pMulticast->Address.lpSockaddr)->sin_addr) ); + pMulticast = pMulticast->Next; } } printf("\n"); @@ -647,7 +638,7 @@ ssdpDiscoverDevices(const char * const deviceTypes[], if(error) *error = MINISSDPC_SOCKET_ERROR; PRINT_SOCKET_ERROR("setsockopt(SO_REUSEADDR,...)"); - return NULL; + goto error; } if(ipv6) { @@ -692,7 +683,11 @@ ssdpDiscoverDevices(const char * const deviceTypes[], #endif } else { struct in_addr mc_if; +#if defined(_WIN32) && (_WIN32_WINNT >= _WIN32_WINNT_VISTA) + InetPtonA(AF_INET, multicastif, &mc_if); +#else mc_if.s_addr = inet_addr(multicastif); /* ex: 192.168.x.x */ +#endif if(mc_if.s_addr != INADDR_NONE) { ((struct sockaddr_in *)&sockudp_r)->sin_addr.s_addr = mc_if.s_addr; @@ -819,24 +814,26 @@ ssdpDiscoverDevices(const char * const deviceTypes[], fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv)); #endif break; - } - for(p = servinfo; p; p = p->ai_next) { - n = sendto(sudp, bufr, n, 0, p->ai_addr, p->ai_addrlen); - if (n < 0) { + } else { + struct addrinfo *p; + for(p = servinfo; p; p = p->ai_next) { + n = sendto(sudp, bufr, n, 0, p->ai_addr, MSC_CAST_INT p->ai_addrlen); + if (n < 0) { #ifdef DEBUG - char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV]; - if (getnameinfo(p->ai_addr, p->ai_addrlen, hbuf, sizeof(hbuf), sbuf, - sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV) == 0) { - fprintf(stderr, "host:%s port:%s\n", hbuf, sbuf); - } + char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV]; + if (getnameinfo(p->ai_addr, (socklen_t)p->ai_addrlen, hbuf, sizeof(hbuf), sbuf, + sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV) == 0) { + fprintf(stderr, "host:%s port:%s\n", hbuf, sbuf); + } #endif - PRINT_SOCKET_ERROR("sendto"); - continue; - } else { - sentok = 1; + PRINT_SOCKET_ERROR("sendto"); + continue; + } else { + sentok = 1; + } } + freeaddrinfo(servinfo); } - freeaddrinfo(servinfo); if(!sentok) { if(error) *error = MINISSDPC_SOCKET_ERROR; @@ -877,11 +874,11 @@ ssdpDiscoverDevices(const char * const deviceTypes[], stsize, st, usnsize, (usn?usn:""), urlsize, descURL); #endif /* DEBUG */ for(tmp=devlist; tmp; tmp = tmp->pNext) { - if(memcmp(tmp->descURL, descURL, urlsize) == 0 && + if(strncmp(tmp->descURL, descURL, urlsize) == 0 && tmp->descURL[urlsize] == '\0' && - memcmp(tmp->st, st, stsize) == 0 && + strncmp(tmp->st, st, stsize) == 0 && tmp->st[stsize] == '\0' && - (usnsize == 0 || memcmp(tmp->usn, usn, usnsize) == 0) && + (usnsize == 0 || strncmp(tmp->usn, usn, usnsize) == 0) && tmp->usn[usnsize] == '\0') break; } diff --git a/thirdparty/miniupnpc/minissdpc.h b/thirdparty/miniupnpc/miniupnpc/minissdpc.h index 167d897cb6..c99f929b9e 100644 --- a/thirdparty/miniupnpc/minissdpc.h +++ b/thirdparty/miniupnpc/miniupnpc/minissdpc.h @@ -32,13 +32,13 @@ MINIUPNP_LIBSPEC int connectToMiniSSDPD(const char * socketpath); MINIUPNP_LIBSPEC int -disconnectFromMiniSSDPD(int fd); +disconnectFromMiniSSDPD(int s); MINIUPNP_LIBSPEC int -requestDevicesFromMiniSSDPD(int fd, const char * devtype); +requestDevicesFromMiniSSDPD(int s, const char * devtype); MINIUPNP_LIBSPEC struct UPNPDev * -receiveDevicesFromMiniSSDPD(int fd, int * error); +receiveDevicesFromMiniSSDPD(int s, int * error); #endif /* !(defined(_WIN32) || defined(__amigaos__) || defined(__amigaos4__)) */ diff --git a/thirdparty/miniupnpc/miniupnpc.c b/thirdparty/miniupnpc/miniupnpc/miniupnpc.c index 5d93ef9933..3181d10eb6 100644 --- a/thirdparty/miniupnpc/miniupnpc.c +++ b/thirdparty/miniupnpc/miniupnpc/miniupnpc.c @@ -1,9 +1,9 @@ -/* $Id: miniupnpc.c,v 1.149 2016/02/09 09:50:46 nanard Exp $ */ +/* $Id: miniupnpc.c,v 1.154 2019/04/23 12:12:13 nanard Exp $ */ /* vim: tabstop=4 shiftwidth=4 noexpandtab * Project : miniupnp * Web : http://miniupnp.free.fr/ * Author : Thomas BERNARD - * copyright (c) 2005-2018 Thomas Bernard + * copyright (c) 2005-2019 Thomas Bernard * This software is subjet to the conditions detailed in the * provided LICENSE file. */ #include <stdlib.h> @@ -63,7 +63,7 @@ #include "connecthostport.h" /* compare the beginning of a string with a constant string */ -#define COMPARE(str, cstr) (0==memcmp(str, cstr, sizeof(cstr) - 1)) +#define COMPARE(str, cstr) (0==strncmp(str, cstr, sizeof(cstr) - 1)) #ifndef MAXHOSTNAMELEN #define MAXHOSTNAMELEN 64 @@ -85,8 +85,7 @@ static int is_rfc1918addr(const char * addr) return 1; /* 172.16.0.0 - 172.31.255.255 (172.16/12 prefix) */ if(COMPARE(addr, "172.")) { - int i = atoi(addr + 4); - if((16 <= i) && (i <= 31)) + if((atoi(addr + 4) | 0x0f) == 0x1f) return 1; } return 0; @@ -416,7 +415,7 @@ static char * build_absolute_url(const char * baseurl, const char * descURL, const char * url, unsigned int scope_id) { - int l, n; + size_t l, n; char * s; const char * base; char * p; @@ -459,7 +458,7 @@ build_absolute_url(const char * baseurl, const char * descURL, memcpy(s, base, n); if(scope_id != 0) { s[n] = '\0'; - if(0 == memcmp(s, "http://[fe80:", 13)) { + if(n > 13 && 0 == memcmp(s, "http://[fe80:", 13)) { /* this is a linklocal IPv6 address */ p = strchr(s, ']'); if(p) { @@ -573,7 +572,6 @@ UPNP_GetValidIGD(struct UPNPDev * devlist, int ndev = 0; int i; int state = -1; /* state 1 : IGD connected. State 2 : IGD. State 3 : anything */ - int n_igd = 0; char extIpAddr[16]; char myLanAddr[40]; int status_code = -1; @@ -588,12 +586,10 @@ UPNP_GetValidIGD(struct UPNPDev * devlist, /* counting total number of devices in the list */ for(dev = devlist; dev; dev = dev->pNext) ndev++; - if(ndev > 0) - { - desc = calloc(ndev, sizeof(struct xml_desc)); - if(!desc) - return -1; /* memory allocation error */ - } + /* ndev is always > 0 */ + desc = calloc(ndev, sizeof(struct xml_desc)); + if(!desc) + return -1; /* memory allocation error */ /* Step 1 : downloading descriptions and testing type */ for(dev = devlist, i = 0; dev; dev = dev->pNext, i++) { @@ -617,7 +613,6 @@ UPNP_GetValidIGD(struct UPNPDev * devlist, "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:")) { desc[i].is_igd = 1; - n_igd++; if(lanaddr) strncpy(lanaddr, myLanAddr, lanaddrlen); } @@ -685,14 +680,9 @@ UPNP_GetValidIGD(struct UPNPDev * devlist, } state = 0; free_and_return: - if(desc) { - for(i = 0; i < ndev; i++) { - if(desc[i].xml) { - free(desc[i].xml); - } - } - free(desc); - } + for(i = 0; i < ndev; i++) + free(desc[i].xml); + free(desc); return state; } @@ -717,7 +707,6 @@ UPNP_GetIGDFromUrl(const char * rootdescurl, memset(urls, 0, sizeof(struct UPNPUrls)); parserootdesc(descXML, descXMLsize, data); free(descXML); - descXML = NULL; GetUPNPUrls(urls, data, rootdescurl, 0); return 1; } else { diff --git a/thirdparty/miniupnpc/miniupnpc_declspec.h b/thirdparty/miniupnpc/miniupnpc/miniupnpc_declspec.h index 40adb922ec..40adb922ec 100644 --- a/thirdparty/miniupnpc/miniupnpc_declspec.h +++ b/thirdparty/miniupnpc/miniupnpc/miniupnpc_declspec.h diff --git a/thirdparty/miniupnpc/miniupnpc_socketdef.h b/thirdparty/miniupnpc/miniupnpc/miniupnpc_socketdef.h index 965d9151b9..d4f79a7bd6 100644 --- a/thirdparty/miniupnpc/miniupnpc_socketdef.h +++ b/thirdparty/miniupnpc/miniupnpc/miniupnpc_socketdef.h @@ -28,6 +28,13 @@ #endif +#ifdef _MSC_VER +#define MSC_CAST_INT (int) +#else +#define MSC_CAST_INT +#endif + +/* definition of PRINT_SOCKET_ERROR */ #ifdef _WIN32 #define PRINT_SOCKET_ERROR(x) fprintf(stderr, "Socket error: %s, %d\n", x, WSAGetLastError()); #else diff --git a/thirdparty/miniupnpc/miniupnpcmodule.c b/thirdparty/miniupnpc/miniupnpc/miniupnpcmodule.c index 8657a0e002..d9341ab5bf 100644 --- a/thirdparty/miniupnpc/miniupnpcmodule.c +++ b/thirdparty/miniupnpc/miniupnpc/miniupnpcmodule.c @@ -1,8 +1,9 @@ -/* $Id: miniupnpcmodule.c,v 1.24 2014/06/10 09:48:11 nanard Exp $*/ -/* Project : miniupnp +/* $Id: miniupnpcmodule.c,v 1.34 2019/05/20 19:07:16 nanard Exp $*/ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * Project : miniupnp * Author : Thomas BERNARD * website : https://miniupnp.tuxfamily.org/ - * copyright (c) 2007-2018 Thomas Bernard + * copyright (c) 2007-2019 Thomas Bernard * This software is subjet to the conditions detailed in the * provided LICENCE file. */ #include <Python.h> @@ -292,7 +293,7 @@ Py_END_ALLOW_THREADS } /* AddPortMapping(externalPort, protocol, internalHost, internalPort, desc, - * remoteHost) + * remoteHost, leaseDuration) * protocol is 'UDP' or 'TCP' */ static PyObject * UPnP_addportmapping(UPnPObject *self, PyObject *args) @@ -305,17 +306,24 @@ UPnP_addportmapping(UPnPObject *self, PyObject *args) const char * host; const char * desc; const char * remoteHost; - const char * leaseDuration = "0"; + unsigned int intLeaseDuration = 0; + char strLeaseDuration[12]; int r; - if (!PyArg_ParseTuple(args, "HssHzz", &ePort, &proto, - &host, &iPort, &desc, &remoteHost)) +#if (PY_MAJOR_VERSION >= 3) || (PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION > 3) + if (!PyArg_ParseTuple(args, "HssHzz|I", &ePort, &proto, + &host, &iPort, &desc, &remoteHost, &intLeaseDuration)) +#else + if (!PyArg_ParseTuple(args, "HssHzz|i", &ePort, &proto, + &host, &iPort, &desc, &remoteHost, (int *)&intLeaseDuration)) +#endif return NULL; Py_BEGIN_ALLOW_THREADS sprintf(extPort, "%hu", ePort); sprintf(inPort, "%hu", iPort); + sprintf(strLeaseDuration, "%u", intLeaseDuration); r = UPNP_AddPortMapping(self->urls.controlURL, self->data.first.servicetype, extPort, inPort, host, desc, proto, - remoteHost, leaseDuration); + remoteHost, strLeaseDuration); Py_END_ALLOW_THREADS if(r==UPNPCOMMAND_SUCCESS) { @@ -676,6 +684,16 @@ initminiupnpc(void) /* initialize Winsock. */ WSADATA wsaData; int nResult = WSAStartup(MAKEWORD(2,2), &wsaData); + if (nResult != 0) + { + /* error code could be WSASYSNOTREADY WSASYSNOTREADY + * WSASYSNOTREADY WSASYSNOTREADY WSASYSNOTREADY */ +#if PY_MAJOR_VERSION >= 3 + return 0; +#else + return; +#endif + } UPnPType.tp_new = PyType_GenericNew; #endif diff --git a/thirdparty/miniupnpc/miniupnpcstrings.h b/thirdparty/miniupnpc/miniupnpc/miniupnpcstrings.h index a718cc7bbf..a718cc7bbf 100644 --- a/thirdparty/miniupnpc/miniupnpcstrings.h +++ b/thirdparty/miniupnpc/miniupnpc/miniupnpcstrings.h diff --git a/thirdparty/miniupnpc/miniupnpctypes.h b/thirdparty/miniupnpc/miniupnpc/miniupnpctypes.h index 307ce39699..307ce39699 100644 --- a/thirdparty/miniupnpc/miniupnpctypes.h +++ b/thirdparty/miniupnpc/miniupnpc/miniupnpctypes.h diff --git a/thirdparty/miniupnpc/miniwget.c b/thirdparty/miniupnpc/miniupnpc/miniwget.c index a46ba76022..5c135f4efd 100644 --- a/thirdparty/miniupnpc/miniwget.c +++ b/thirdparty/miniupnpc/miniupnpc/miniwget.c @@ -243,7 +243,7 @@ getHTTPResponse(SOCKET s, int * size, int * status_code) /* reading chunk size */ if(chunksize_buf_index == 0) { /* skipping any leading CR LF */ - if(i<n && buf[i] == '\r') i++; + if(buf[i] == '\r') i++; if(i<n && buf[i] == '\n') i++; } while(i<n && isxdigit(buf[i]) @@ -350,7 +350,7 @@ getHTTPResponse(SOCKET s, int * size, int * status_code) } } end_of_stream: - free(header_buf); header_buf = NULL; + free(header_buf); *size = content_buf_used; if(content_buf_used == 0) { @@ -371,7 +371,7 @@ miniwget3(const char * host, int * status_code) { char buf[2048]; - SOCKET s; + SOCKET s; int n; int len; int sent; @@ -559,7 +559,7 @@ parseURL(const char * url, #else /* under windows, scope is numerical */ char tmp[8]; - int l; + size_t l; scope++; /* "%25" is just '%' in URL encoding */ if(scope[0] == '2' && scope[1] == '5') @@ -659,4 +659,3 @@ miniwget_getaddr(const char * url, int * size, #endif return miniwget2(hostname, port, path, size, addr, addrlen, scope_id, status_code); } - diff --git a/thirdparty/miniupnpc/miniwget_private.h b/thirdparty/miniupnpc/miniupnpc/miniwget_private.h index e4eaac8085..e4eaac8085 100644 --- a/thirdparty/miniupnpc/miniwget_private.h +++ b/thirdparty/miniupnpc/miniupnpc/miniwget_private.h diff --git a/thirdparty/miniupnpc/minixml.c b/thirdparty/miniupnpc/miniupnpc/minixml.c index ed2d3c759c..ed2d3c759c 100644 --- a/thirdparty/miniupnpc/minixml.c +++ b/thirdparty/miniupnpc/miniupnpc/minixml.c diff --git a/thirdparty/miniupnpc/minixml.h b/thirdparty/miniupnpc/miniupnpc/minixml.h index 19e6f513bf..2e60397388 100644 --- a/thirdparty/miniupnpc/minixml.h +++ b/thirdparty/miniupnpc/miniupnpc/minixml.h @@ -10,7 +10,7 @@ * */ #ifndef MINIXML_H_INCLUDED #define MINIXML_H_INCLUDED -#define IS_WHITE_SPACE(c) ((c==' ') || (c=='\t') || (c=='\r') || (c=='\n')) +#define IS_WHITE_SPACE(c) ((c)==' ' || (c)=='\t' || (c)=='\r' || (c)=='\n') /* if a callback function pointer is set to NULL, * the function is not called */ diff --git a/thirdparty/miniupnpc/minixmlvalid.c b/thirdparty/miniupnpc/miniupnpc/minixmlvalid.c index dad1488122..dad1488122 100644 --- a/thirdparty/miniupnpc/minixmlvalid.c +++ b/thirdparty/miniupnpc/miniupnpc/minixmlvalid.c diff --git a/thirdparty/miniupnpc/portlistingparse.c b/thirdparty/miniupnpc/miniupnpc/portlistingparse.c index 55859f2714..55859f2714 100644 --- a/thirdparty/miniupnpc/portlistingparse.c +++ b/thirdparty/miniupnpc/miniupnpc/portlistingparse.c diff --git a/thirdparty/miniupnpc/portlistingparse.h b/thirdparty/miniupnpc/miniupnpc/portlistingparse.h index e3957a3f4c..e3957a3f4c 100644 --- a/thirdparty/miniupnpc/portlistingparse.h +++ b/thirdparty/miniupnpc/miniupnpc/portlistingparse.h diff --git a/thirdparty/miniupnpc/receivedata.c b/thirdparty/miniupnpc/miniupnpc/receivedata.c index 7b9cc5b778..7b9cc5b778 100644 --- a/thirdparty/miniupnpc/receivedata.c +++ b/thirdparty/miniupnpc/miniupnpc/receivedata.c diff --git a/thirdparty/miniupnpc/receivedata.h b/thirdparty/miniupnpc/miniupnpc/receivedata.h index c9fdc561f8..c9fdc561f8 100644 --- a/thirdparty/miniupnpc/receivedata.h +++ b/thirdparty/miniupnpc/miniupnpc/receivedata.h diff --git a/thirdparty/miniupnpc/upnpc.c b/thirdparty/miniupnpc/miniupnpc/upnpc.c index 0c65cbe8c0..674c89beb0 100644 --- a/thirdparty/miniupnpc/upnpc.c +++ b/thirdparty/miniupnpc/miniupnpc/upnpc.c @@ -1,7 +1,7 @@ /* $Id: upnpc.c,v 1.119 2018/03/13 23:34:46 nanard Exp $ */ /* Project : miniupnp * Author : Thomas Bernard - * Copyright (c) 2005-2018 Thomas Bernard + * Copyright (c) 2005-2019 Thomas Bernard * This software is subject to the conditions detailed in the * LICENCE file provided in this distribution. */ @@ -579,7 +579,7 @@ int main(int argc, char ** argv) } #endif printf("upnpc : miniupnpc library test client, version %s.\n", MINIUPNPC_VERSION_STRING); - printf(" (c) 2005-2018 Thomas Bernard.\n"); + printf(" (c) 2005-2019 Thomas Bernard.\n"); printf("Go to http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/\n" "for more information.\n"); /* command line processing */ diff --git a/thirdparty/miniupnpc/upnpcommands.c b/thirdparty/miniupnpc/miniupnpc/upnpcommands.c index b6a693a93a..1e1ee6786f 100644 --- a/thirdparty/miniupnpc/upnpcommands.c +++ b/thirdparty/miniupnpc/miniupnpc/upnpcommands.c @@ -1,4 +1,4 @@ -/* $Id: upnpcommands.c,v 1.49 2018/03/13 23:34:47 nanard Exp $ */ +/* $Id: upnpcommands.c,v 1.51 2019/04/23 11:45:15 nanard Exp $ */ /* vim: tabstop=4 shiftwidth=4 noexpandtab * Project : miniupnp * Author : Thomas Bernard @@ -33,11 +33,11 @@ UPNP_GetTotalBytesSent(const char * controlURL, char * p; if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, "GetTotalBytesSent", 0, &bufsize))) { - return UPNPCOMMAND_HTTP_ERROR; + return (UNSIGNED_INTEGER)UPNPCOMMAND_HTTP_ERROR; } ParseNameValue(buffer, bufsize, &pdata); /*DisplayNameValueList(buffer, bufsize);*/ - free(buffer); buffer = NULL; + free(buffer); p = GetValueFromNameValueList(&pdata, "NewTotalBytesSent"); r = my_atoui(p); ClearNameValueList(&pdata); @@ -57,11 +57,11 @@ UPNP_GetTotalBytesReceived(const char * controlURL, char * p; if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, "GetTotalBytesReceived", 0, &bufsize))) { - return UPNPCOMMAND_HTTP_ERROR; + return (UNSIGNED_INTEGER)UPNPCOMMAND_HTTP_ERROR; } ParseNameValue(buffer, bufsize, &pdata); /*DisplayNameValueList(buffer, bufsize);*/ - free(buffer); buffer = NULL; + free(buffer); p = GetValueFromNameValueList(&pdata, "NewTotalBytesReceived"); r = my_atoui(p); ClearNameValueList(&pdata); @@ -81,11 +81,11 @@ UPNP_GetTotalPacketsSent(const char * controlURL, char * p; if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, "GetTotalPacketsSent", 0, &bufsize))) { - return UPNPCOMMAND_HTTP_ERROR; + return (UNSIGNED_INTEGER)UPNPCOMMAND_HTTP_ERROR; } ParseNameValue(buffer, bufsize, &pdata); /*DisplayNameValueList(buffer, bufsize);*/ - free(buffer); buffer = NULL; + free(buffer); p = GetValueFromNameValueList(&pdata, "NewTotalPacketsSent"); r = my_atoui(p); ClearNameValueList(&pdata); @@ -105,11 +105,11 @@ UPNP_GetTotalPacketsReceived(const char * controlURL, char * p; if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, "GetTotalPacketsReceived", 0, &bufsize))) { - return UPNPCOMMAND_HTTP_ERROR; + return (UNSIGNED_INTEGER)UPNPCOMMAND_HTTP_ERROR; } ParseNameValue(buffer, bufsize, &pdata); /*DisplayNameValueList(buffer, bufsize);*/ - free(buffer); buffer = NULL; + free(buffer); p = GetValueFromNameValueList(&pdata, "NewTotalPacketsReceived"); r = my_atoui(p); ClearNameValueList(&pdata); @@ -142,7 +142,7 @@ UPNP_GetStatusInfo(const char * controlURL, } ParseNameValue(buffer, bufsize, &pdata); /*DisplayNameValueList(buffer, bufsize);*/ - free(buffer); buffer = NULL; + free(buffer); up = GetValueFromNameValueList(&pdata, "NewUptime"); p = GetValueFromNameValueList(&pdata, "NewConnectionStatus"); err = GetValueFromNameValueList(&pdata, "NewLastConnectionError"); @@ -202,7 +202,7 @@ UPNP_GetConnectionTypeInfo(const char * controlURL, return UPNPCOMMAND_HTTP_ERROR; } ParseNameValue(buffer, bufsize, &pdata); - free(buffer); buffer = NULL; + free(buffer); p = GetValueFromNameValueList(&pdata, "NewConnectionType"); /*p = GetValueFromNameValueList(&pdata, "NewPossibleConnectionTypes");*/ /* PossibleConnectionTypes will have several values.... */ @@ -251,7 +251,7 @@ UPNP_GetLinkLayerMaxBitRates(const char * controlURL, } /*DisplayNameValueList(buffer, bufsize);*/ ParseNameValue(buffer, bufsize, &pdata); - free(buffer); buffer = NULL; + free(buffer); /*down = GetValueFromNameValueList(&pdata, "NewDownstreamMaxBitRate");*/ /*up = GetValueFromNameValueList(&pdata, "NewUpstreamMaxBitRate");*/ down = GetValueFromNameValueList(&pdata, "NewLayer1DownstreamMaxBitRate"); @@ -315,7 +315,7 @@ UPNP_GetExternalIPAddress(const char * controlURL, } /*DisplayNameValueList(buffer, bufsize);*/ ParseNameValue(buffer, bufsize, &pdata); - free(buffer); buffer = NULL; + free(buffer); /*printf("external ip = %s\n", GetValueFromNameValueList(&pdata, "NewExternalIPAddress") );*/ p = GetValueFromNameValueList(&pdata, "NewExternalIPAddress"); if(p) { @@ -385,7 +385,7 @@ UPNP_AddPortMapping(const char * controlURL, const char * servicetype, /*buffer[bufsize] = '\0';*/ /*puts(buffer);*/ ParseNameValue(buffer, bufsize, &pdata); - free(buffer); buffer = NULL; + free(buffer); resVal = GetValueFromNameValueList(&pdata, "errorCode"); if(resVal) { /*printf("AddPortMapping errorCode = '%s'\n", resVal); */ @@ -446,7 +446,7 @@ UPNP_AddAnyPortMapping(const char * controlURL, const char * servicetype, return UPNPCOMMAND_HTTP_ERROR; } ParseNameValue(buffer, bufsize, &pdata); - free(buffer); buffer = NULL; + free(buffer); resVal = GetValueFromNameValueList(&pdata, "errorCode"); if(resVal) { ret = UPNPCOMMAND_UNKNOWN_ERROR; @@ -501,7 +501,7 @@ UPNP_DeletePortMapping(const char * controlURL, const char * servicetype, } /*DisplayNameValueList(buffer, bufsize);*/ ParseNameValue(buffer, bufsize, &pdata); - free(buffer); buffer = NULL; + free(buffer); resVal = GetValueFromNameValueList(&pdata, "errorCode"); if(resVal) { ret = UPNPCOMMAND_UNKNOWN_ERROR; @@ -549,7 +549,7 @@ UPNP_DeletePortMappingRange(const char * controlURL, const char * servicetype, return UPNPCOMMAND_HTTP_ERROR; } ParseNameValue(buffer, bufsize, &pdata); - free(buffer); buffer = NULL; + free(buffer); resVal = GetValueFromNameValueList(&pdata, "errorCode"); if(resVal) { ret = UPNPCOMMAND_UNKNOWN_ERROR; @@ -597,7 +597,7 @@ UPNP_GetGenericPortMappingEntry(const char * controlURL, return UPNPCOMMAND_HTTP_ERROR; } ParseNameValue(buffer, bufsize, &pdata); - free(buffer); buffer = NULL; + free(buffer); p = GetValueFromNameValueList(&pdata, "NewRemoteHost"); if(p && rHost) @@ -677,7 +677,7 @@ UPNP_GetPortMappingNumberOfEntries(const char * controlURL, DisplayNameValueList(buffer, bufsize); #endif ParseNameValue(buffer, bufsize, &pdata); - free(buffer); buffer = NULL; + free(buffer); p = GetValueFromNameValueList(&pdata, "NewPortMappingNumberOfEntries"); if(numEntries && p) { @@ -739,7 +739,7 @@ UPNP_GetSpecificPortMappingEntry(const char * controlURL, } /*DisplayNameValueList(buffer, bufsize);*/ ParseNameValue(buffer, bufsize, &pdata); - free(buffer); buffer = NULL; + free(buffer); p = GetValueFromNameValueList(&pdata, "NewInternalClient"); if(p) { @@ -836,7 +836,7 @@ UPNP_GetListOfPortMappings(const char * controlURL, /*DisplayNameValueList(buffer, bufsize);*/ ParseNameValue(buffer, bufsize, &pdata); - free(buffer); buffer = NULL; + free(buffer); /*p = GetValueFromNameValueList(&pdata, "NewPortListing");*/ /*if(p) { @@ -898,7 +898,7 @@ UPNP_GetFirewallStatus(const char * controlURL, return UPNPCOMMAND_HTTP_ERROR; } ParseNameValue(buffer, bufsize, &pdata); - free(buffer); buffer = NULL; + free(buffer); fe = GetValueFromNameValueList(&pdata, "FirewallEnabled"); ipa = GetValueFromNameValueList(&pdata, "InboundPinholeAllowed"); if(ipa && fe) @@ -935,7 +935,6 @@ UPNP_GetOutboundPinholeTimeout(const char * controlURL, const char * servicetype int bufsize; struct NameValueParserData pdata; const char * resVal; - char * p; int ret; if(!intPort || !intClient || !proto || !remotePort || !remoteHost) @@ -960,7 +959,7 @@ UPNP_GetOutboundPinholeTimeout(const char * controlURL, const char * servicetype if(!buffer) return UPNPCOMMAND_HTTP_ERROR; ParseNameValue(buffer, bufsize, &pdata); - free(buffer); buffer = NULL; + free(buffer); resVal = GetValueFromNameValueList(&pdata, "errorCode"); if(resVal) { @@ -969,10 +968,10 @@ UPNP_GetOutboundPinholeTimeout(const char * controlURL, const char * servicetype } else { - ret = UPNPCOMMAND_SUCCESS; - p = GetValueFromNameValueList(&pdata, "OutboundPinholeTimeout"); + const char * p = GetValueFromNameValueList(&pdata, "OutboundPinholeTimeout"); if(p) *opTimeout = my_atoui(p); + ret = UPNPCOMMAND_SUCCESS; } ClearNameValueList(&pdata); return ret; @@ -1037,7 +1036,7 @@ UPNP_AddPinhole(const char * controlURL, const char * servicetype, if(!buffer) return UPNPCOMMAND_HTTP_ERROR; ParseNameValue(buffer, bufsize, &pdata); - free(buffer); buffer = NULL; + free(buffer); p = GetValueFromNameValueList(&pdata, "UniqueID"); if(p) { @@ -1087,7 +1086,7 @@ UPNP_UpdatePinhole(const char * controlURL, const char * servicetype, if(!buffer) return UPNPCOMMAND_HTTP_ERROR; ParseNameValue(buffer, bufsize, &pdata); - free(buffer); buffer = NULL; + free(buffer); resVal = GetValueFromNameValueList(&pdata, "errorCode"); if(resVal) { @@ -1129,7 +1128,7 @@ UPNP_DeletePinhole(const char * controlURL, const char * servicetype, const char return UPNPCOMMAND_HTTP_ERROR; /*DisplayNameValueList(buffer, bufsize);*/ ParseNameValue(buffer, bufsize, &pdata); - free(buffer); buffer = NULL; + free(buffer); resVal = GetValueFromNameValueList(&pdata, "errorCode"); if(resVal) { @@ -1171,7 +1170,7 @@ UPNP_CheckPinholeWorking(const char * controlURL, const char * servicetype, return UPNPCOMMAND_HTTP_ERROR; } ParseNameValue(buffer, bufsize, &pdata); - free(buffer); buffer = NULL; + free(buffer); p = GetValueFromNameValueList(&pdata, "IsWorking"); if(p) @@ -1218,7 +1217,7 @@ UPNP_GetPinholePackets(const char * controlURL, const char * servicetype, if(!buffer) return UPNPCOMMAND_HTTP_ERROR; ParseNameValue(buffer, bufsize, &pdata); - free(buffer); buffer = NULL; + free(buffer); p = GetValueFromNameValueList(&pdata, "PinholePackets"); if(p) @@ -1237,5 +1236,3 @@ UPNP_GetPinholePackets(const char * controlURL, const char * servicetype, ClearNameValueList(&pdata); return ret; } - - diff --git a/thirdparty/miniupnpc/miniupnpc/upnpcommands.h b/thirdparty/miniupnpc/miniupnpc/upnpcommands.h index 0c6d501666..1b6d447732 100644 --- a/thirdparty/miniupnpc/miniupnpc/upnpcommands.h +++ b/thirdparty/miniupnpc/miniupnpc/upnpcommands.h @@ -206,9 +206,9 @@ UPNP_DeletePortMappingRange(const char * controlURL, const char * servicetype, /* UPNP_GetPortMappingNumberOfEntries() * not supported by all routers */ MINIUPNP_LIBSPEC int -UPNP_GetPortMappingNumberOfEntries(const char* controlURL, - const char* servicetype, - unsigned int * num); +UPNP_GetPortMappingNumberOfEntries(const char * controlURL, + const char * servicetype, + unsigned int * numEntries); /* UPNP_GetSpecificPortMappingEntry() * retrieves an existing port mapping diff --git a/thirdparty/miniupnpc/upnpdev.c b/thirdparty/miniupnpc/miniupnpc/upnpdev.c index d89a9934c3..d89a9934c3 100644 --- a/thirdparty/miniupnpc/upnpdev.c +++ b/thirdparty/miniupnpc/miniupnpc/upnpdev.c diff --git a/thirdparty/miniupnpc/upnpdev.h b/thirdparty/miniupnpc/miniupnpc/upnpdev.h index f4ae174426..f4ae174426 100644 --- a/thirdparty/miniupnpc/upnpdev.h +++ b/thirdparty/miniupnpc/miniupnpc/upnpdev.h diff --git a/thirdparty/miniupnpc/upnperrors.c b/thirdparty/miniupnpc/miniupnpc/upnperrors.c index 40a2e7857f..650af42557 100644 --- a/thirdparty/miniupnpc/upnperrors.c +++ b/thirdparty/miniupnpc/miniupnpc/upnperrors.c @@ -1,7 +1,7 @@ -/* $Id: upnperrors.c,v 1.5 2011/04/10 11:19:36 nanard Exp $ */ +/* $Id: upnperrors.c,v 1.9 2019/06/25 21:15:46 nanard Exp $ */ /* Project : miniupnp * Author : Thomas BERNARD - * copyright (c) 2007 Thomas Bernard + * copyright (c) 2007-2019 Thomas Bernard * All Right reserved. * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ * This software is subjet to the conditions detailed in the @@ -27,10 +27,14 @@ const char * strupnperror(int err) case UPNPCOMMAND_INVALID_RESPONSE: s = "Miniupnpc Invalid response"; break; + case UPNPCOMMAND_HTTP_ERROR: + s = "Miniupnpc HTTP error"; + break; case UPNPDISCOVER_SOCKET_ERROR: s = "Miniupnpc Socket error"; break; case UPNPDISCOVER_MEMORY_ERROR: + case UPNPCOMMAND_MEM_ALLOC_ERROR: s = "Miniupnpc Memory allocation error"; break; case 401: diff --git a/thirdparty/miniupnpc/upnperrors.h b/thirdparty/miniupnpc/miniupnpc/upnperrors.h index 8499d9a1c9..8499d9a1c9 100644 --- a/thirdparty/miniupnpc/upnperrors.h +++ b/thirdparty/miniupnpc/miniupnpc/upnperrors.h diff --git a/thirdparty/miniupnpc/upnpreplyparse.c b/thirdparty/miniupnpc/miniupnpc/upnpreplyparse.c index 68a47c0278..4d06f0585d 100644 --- a/thirdparty/miniupnpc/upnpreplyparse.c +++ b/thirdparty/miniupnpc/miniupnpc/upnpreplyparse.c @@ -1,8 +1,8 @@ -/* $Id: upnpreplyparse.c,v 1.19 2015/07/15 10:29:11 nanard Exp $ */ +/* $Id: upnpreplyparse.c,v 1.20 2017/12/12 11:26:25 nanard Exp $ */ /* vim: tabstop=4 shiftwidth=4 noexpandtab * MiniUPnP project * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ - * (c) 2006-2017 Thomas Bernard + * (c) 2006-2019 Thomas Bernard * This software is subject to the conditions detailed * in the LICENCE file provided within the distribution */ @@ -78,6 +78,7 @@ NameValueParserGetData(void * d, const char * datas, int l) if(strcmp(data->curelt, "NewPortListing") == 0) { /* specific case for NewPortListing which is a XML Document */ + free(data->portListing); data->portListing = malloc(l + 1); if(!data->portListing) { diff --git a/thirdparty/miniupnpc/upnpreplyparse.h b/thirdparty/miniupnpc/miniupnpc/upnpreplyparse.h index 6badd15b26..6badd15b26 100644 --- a/thirdparty/miniupnpc/upnpreplyparse.h +++ b/thirdparty/miniupnpc/miniupnpc/upnpreplyparse.h diff --git a/thirdparty/miniupnpc/miniwget.h b/thirdparty/miniupnpc/miniwget.h deleted file mode 100644 index f5572c2544..0000000000 --- a/thirdparty/miniupnpc/miniwget.h +++ /dev/null @@ -1,27 +0,0 @@ -/* $Id: miniwget.h,v 1.12 2016/01/24 17:24:36 nanard Exp $ */ -/* Project : miniupnp - * Author : Thomas Bernard - * Copyright (c) 2005-2016 Thomas Bernard - * This software is subject to the conditions detailed in the - * LICENCE file provided in this distribution. - * */ -#ifndef MINIWGET_H_INCLUDED -#define MINIWGET_H_INCLUDED - -#include "miniupnpc_declspec.h" - -#ifdef __cplusplus -extern "C" { -#endif - -MINIUPNP_LIBSPEC void * miniwget(const char *, int *, unsigned int, int *); - -MINIUPNP_LIBSPEC void * miniwget_getaddr(const char *, int *, char *, int, unsigned int, int *); - -int parseURL(const char *, char *, unsigned short *, char * *, unsigned int *); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/thirdparty/miniupnpc/upnpcommands.h b/thirdparty/miniupnpc/upnpcommands.h deleted file mode 100644 index 0c6d501666..0000000000 --- a/thirdparty/miniupnpc/upnpcommands.h +++ /dev/null @@ -1,348 +0,0 @@ -/* $Id: upnpcommands.h,v 1.32 2018/03/13 23:34:47 nanard Exp $ */ -/* Miniupnp project : http://miniupnp.free.fr/ - * Author : Thomas Bernard - * Copyright (c) 2005-2018 Thomas Bernard - * This software is subject to the conditions detailed in the - * LICENCE file provided within this distribution */ -#ifndef UPNPCOMMANDS_H_INCLUDED -#define UPNPCOMMANDS_H_INCLUDED - -#include "miniupnpc_declspec.h" -#include "miniupnpctypes.h" - -/* MiniUPnPc return codes : */ -#define UPNPCOMMAND_SUCCESS (0) -#define UPNPCOMMAND_UNKNOWN_ERROR (-1) -#define UPNPCOMMAND_INVALID_ARGS (-2) -#define UPNPCOMMAND_HTTP_ERROR (-3) -#define UPNPCOMMAND_INVALID_RESPONSE (-4) -#define UPNPCOMMAND_MEM_ALLOC_ERROR (-5) - -#ifdef __cplusplus -extern "C" { -#endif - -struct PortMappingParserData; - -MINIUPNP_LIBSPEC UNSIGNED_INTEGER -UPNP_GetTotalBytesSent(const char * controlURL, - const char * servicetype); - -MINIUPNP_LIBSPEC UNSIGNED_INTEGER -UPNP_GetTotalBytesReceived(const char * controlURL, - const char * servicetype); - -MINIUPNP_LIBSPEC UNSIGNED_INTEGER -UPNP_GetTotalPacketsSent(const char * controlURL, - const char * servicetype); - -MINIUPNP_LIBSPEC UNSIGNED_INTEGER -UPNP_GetTotalPacketsReceived(const char * controlURL, - const char * servicetype); - -/* UPNP_GetStatusInfo() - * status and lastconnerror are 64 byte buffers - * Return values : - * UPNPCOMMAND_SUCCESS, UPNPCOMMAND_INVALID_ARGS, UPNPCOMMAND_UNKNOWN_ERROR - * or a UPnP Error code */ -MINIUPNP_LIBSPEC int -UPNP_GetStatusInfo(const char * controlURL, - const char * servicetype, - char * status, - unsigned int * uptime, - char * lastconnerror); - -/* UPNP_GetConnectionTypeInfo() - * argument connectionType is a 64 character buffer - * Return Values : - * UPNPCOMMAND_SUCCESS, UPNPCOMMAND_INVALID_ARGS, UPNPCOMMAND_UNKNOWN_ERROR - * or a UPnP Error code */ -MINIUPNP_LIBSPEC int -UPNP_GetConnectionTypeInfo(const char * controlURL, - const char * servicetype, - char * connectionType); - -/* UPNP_GetExternalIPAddress() call the corresponding UPNP method. - * if the third arg is not null the value is copied to it. - * at least 16 bytes must be available - * - * Return values : - * 0 : SUCCESS - * NON ZERO : ERROR Either an UPnP error code or an unknown error. - * - * possible UPnP Errors : - * 402 Invalid Args - See UPnP Device Architecture section on Control. - * 501 Action Failed - See UPnP Device Architecture section on Control. */ -MINIUPNP_LIBSPEC int -UPNP_GetExternalIPAddress(const char * controlURL, - const char * servicetype, - char * extIpAdd); - -/* UPNP_GetLinkLayerMaxBitRates() - * call WANCommonInterfaceConfig:1#GetCommonLinkProperties - * - * return values : - * UPNPCOMMAND_SUCCESS, UPNPCOMMAND_INVALID_ARGS, UPNPCOMMAND_UNKNOWN_ERROR - * or a UPnP Error Code. */ -MINIUPNP_LIBSPEC int -UPNP_GetLinkLayerMaxBitRates(const char* controlURL, - const char* servicetype, - unsigned int * bitrateDown, - unsigned int * bitrateUp); - -/* UPNP_AddPortMapping() - * if desc is NULL, it will be defaulted to "libminiupnpc" - * remoteHost is usually NULL because IGD don't support it. - * - * Return values : - * 0 : SUCCESS - * NON ZERO : ERROR. Either an UPnP error code or an unknown error. - * - * List of possible UPnP errors for AddPortMapping : - * errorCode errorDescription (short) - Description (long) - * 402 Invalid Args - See UPnP Device Architecture section on Control. - * 501 Action Failed - See UPnP Device Architecture section on Control. - * 606 Action not authorized - The action requested REQUIRES authorization and - * the sender was not authorized. - * 715 WildCardNotPermittedInSrcIP - The source IP address cannot be - * wild-carded - * 716 WildCardNotPermittedInExtPort - The external port cannot be wild-carded - * 718 ConflictInMappingEntry - The port mapping entry specified conflicts - * with a mapping assigned previously to another client - * 724 SamePortValuesRequired - Internal and External port values - * must be the same - * 725 OnlyPermanentLeasesSupported - The NAT implementation only supports - * permanent lease times on port mappings - * 726 RemoteHostOnlySupportsWildcard - RemoteHost must be a wildcard - * and cannot be a specific IP address or DNS name - * 727 ExternalPortOnlySupportsWildcard - ExternalPort must be a wildcard and - * cannot be a specific port value - * 728 NoPortMapsAvailable - There are not enough free ports available to - * complete port mapping. - * 729 ConflictWithOtherMechanisms - Attempted port mapping is not allowed - * due to conflict with other mechanisms. - * 732 WildCardNotPermittedInIntPort - The internal port cannot be wild-carded - */ -MINIUPNP_LIBSPEC int -UPNP_AddPortMapping(const char * controlURL, const char * servicetype, - const char * extPort, - const char * inPort, - const char * inClient, - const char * desc, - const char * proto, - const char * remoteHost, - const char * leaseDuration); - -/* UPNP_AddAnyPortMapping() - * if desc is NULL, it will be defaulted to "libminiupnpc" - * remoteHost is usually NULL because IGD don't support it. - * - * Return values : - * 0 : SUCCESS - * NON ZERO : ERROR. Either an UPnP error code or an unknown error. - * - * List of possible UPnP errors for AddPortMapping : - * errorCode errorDescription (short) - Description (long) - * 402 Invalid Args - See UPnP Device Architecture section on Control. - * 501 Action Failed - See UPnP Device Architecture section on Control. - * 606 Action not authorized - The action requested REQUIRES authorization and - * the sender was not authorized. - * 715 WildCardNotPermittedInSrcIP - The source IP address cannot be - * wild-carded - * 716 WildCardNotPermittedInExtPort - The external port cannot be wild-carded - * 728 NoPortMapsAvailable - There are not enough free ports available to - * complete port mapping. - * 729 ConflictWithOtherMechanisms - Attempted port mapping is not allowed - * due to conflict with other mechanisms. - * 732 WildCardNotPermittedInIntPort - The internal port cannot be wild-carded - */ -MINIUPNP_LIBSPEC int -UPNP_AddAnyPortMapping(const char * controlURL, const char * servicetype, - const char * extPort, - const char * inPort, - const char * inClient, - const char * desc, - const char * proto, - const char * remoteHost, - const char * leaseDuration, - char * reservedPort); - -/* UPNP_DeletePortMapping() - * Use same argument values as what was used for AddPortMapping(). - * remoteHost is usually NULL because IGD don't support it. - * Return Values : - * 0 : SUCCESS - * NON ZERO : error. Either an UPnP error code or an undefined error. - * - * List of possible UPnP errors for DeletePortMapping : - * 402 Invalid Args - See UPnP Device Architecture section on Control. - * 606 Action not authorized - The action requested REQUIRES authorization - * and the sender was not authorized. - * 714 NoSuchEntryInArray - The specified value does not exist in the array */ -MINIUPNP_LIBSPEC int -UPNP_DeletePortMapping(const char * controlURL, const char * servicetype, - const char * extPort, const char * proto, - const char * remoteHost); - -/* UPNP_DeletePortRangeMapping() - * Use same argument values as what was used for AddPortMapping(). - * remoteHost is usually NULL because IGD don't support it. - * Return Values : - * 0 : SUCCESS - * NON ZERO : error. Either an UPnP error code or an undefined error. - * - * List of possible UPnP errors for DeletePortMapping : - * 606 Action not authorized - The action requested REQUIRES authorization - * and the sender was not authorized. - * 730 PortMappingNotFound - This error message is returned if no port - * mapping is found in the specified range. - * 733 InconsistentParameters - NewStartPort and NewEndPort values are not consistent. */ -MINIUPNP_LIBSPEC int -UPNP_DeletePortMappingRange(const char * controlURL, const char * servicetype, - const char * extPortStart, const char * extPortEnd, - const char * proto, - const char * manage); - -/* UPNP_GetPortMappingNumberOfEntries() - * not supported by all routers */ -MINIUPNP_LIBSPEC int -UPNP_GetPortMappingNumberOfEntries(const char* controlURL, - const char* servicetype, - unsigned int * num); - -/* UPNP_GetSpecificPortMappingEntry() - * retrieves an existing port mapping - * params : - * in extPort - * in proto - * in remoteHost - * out intClient (16 bytes) - * out intPort (6 bytes) - * out desc (80 bytes) - * out enabled (4 bytes) - * out leaseDuration (16 bytes) - * - * return value : - * UPNPCOMMAND_SUCCESS, UPNPCOMMAND_INVALID_ARGS, UPNPCOMMAND_UNKNOWN_ERROR - * or a UPnP Error Code. - * - * List of possible UPnP errors for _GetSpecificPortMappingEntry : - * 402 Invalid Args - See UPnP Device Architecture section on Control. - * 501 Action Failed - See UPnP Device Architecture section on Control. - * 606 Action not authorized - The action requested REQUIRES authorization - * and the sender was not authorized. - * 714 NoSuchEntryInArray - The specified value does not exist in the array. - */ -MINIUPNP_LIBSPEC int -UPNP_GetSpecificPortMappingEntry(const char * controlURL, - const char * servicetype, - const char * extPort, - const char * proto, - const char * remoteHost, - char * intClient, - char * intPort, - char * desc, - char * enabled, - char * leaseDuration); - -/* UPNP_GetGenericPortMappingEntry() - * params : - * in index - * out extPort (6 bytes) - * out intClient (16 bytes) - * out intPort (6 bytes) - * out protocol (4 bytes) - * out desc (80 bytes) - * out enabled (4 bytes) - * out rHost (64 bytes) - * out duration (16 bytes) - * - * return value : - * UPNPCOMMAND_SUCCESS, UPNPCOMMAND_INVALID_ARGS, UPNPCOMMAND_UNKNOWN_ERROR - * or a UPnP Error Code. - * - * Possible UPNP Error codes : - * 402 Invalid Args - See UPnP Device Architecture section on Control. - * 606 Action not authorized - The action requested REQUIRES authorization - * and the sender was not authorized. - * 713 SpecifiedArrayIndexInvalid - The specified array index is out of bounds - */ -MINIUPNP_LIBSPEC int -UPNP_GetGenericPortMappingEntry(const char * controlURL, - const char * servicetype, - const char * index, - char * extPort, - char * intClient, - char * intPort, - char * protocol, - char * desc, - char * enabled, - char * rHost, - char * duration); - -/* UPNP_GetListOfPortMappings() Available in IGD v2 - * - * - * Possible UPNP Error codes : - * 606 Action not Authorized - * 730 PortMappingNotFound - no port mapping is found in the specified range. - * 733 InconsistantParameters - NewStartPort and NewEndPort values are not - * consistent. - */ -MINIUPNP_LIBSPEC int -UPNP_GetListOfPortMappings(const char * controlURL, - const char * servicetype, - const char * startPort, - const char * endPort, - const char * protocol, - const char * numberOfPorts, - struct PortMappingParserData * data); - -/* IGD:2, functions for service WANIPv6FirewallControl:1 */ -MINIUPNP_LIBSPEC int -UPNP_GetFirewallStatus(const char * controlURL, - const char * servicetype, - int * firewallEnabled, - int * inboundPinholeAllowed); - -MINIUPNP_LIBSPEC int -UPNP_GetOutboundPinholeTimeout(const char * controlURL, const char * servicetype, - const char * remoteHost, - const char * remotePort, - const char * intClient, - const char * intPort, - const char * proto, - int * opTimeout); - -MINIUPNP_LIBSPEC int -UPNP_AddPinhole(const char * controlURL, const char * servicetype, - const char * remoteHost, - const char * remotePort, - const char * intClient, - const char * intPort, - const char * proto, - const char * leaseTime, - char * uniqueID); - -MINIUPNP_LIBSPEC int -UPNP_UpdatePinhole(const char * controlURL, const char * servicetype, - const char * uniqueID, - const char * leaseTime); - -MINIUPNP_LIBSPEC int -UPNP_DeletePinhole(const char * controlURL, const char * servicetype, const char * uniqueID); - -MINIUPNP_LIBSPEC int -UPNP_CheckPinholeWorking(const char * controlURL, const char * servicetype, - const char * uniqueID, int * isWorking); - -MINIUPNP_LIBSPEC int -UPNP_GetPinholePackets(const char * controlURL, const char * servicetype, - const char * uniqueID, int * packets); - -#ifdef __cplusplus -} -#endif - -#endif - |