diff options
Diffstat (limited to 'core')
241 files changed, 3238 insertions, 1383 deletions
diff --git a/core/SCsub b/core/SCsub index 1545bc8aeb..383aaf0e12 100644 --- a/core/SCsub +++ b/core/SCsub @@ -18,9 +18,8 @@ gd_cpp = '#include "project_settings.h"\n' gd_cpp += gd_inc gd_cpp += "void ProjectSettings::register_global_defaults() {\n" + gd_call + "\n}\n" -f = open("global_defaults.gen.cpp", "w") -f.write(gd_cpp) -f.close() +with open("global_defaults.gen.cpp", "w") as f: + f.write(gd_cpp) # Generate AES256 script encryption key @@ -47,9 +46,8 @@ if ("SCRIPT_AES256_ENCRYPTION_KEY" in os.environ): txt = "0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0" print("Invalid AES256 encryption key, not 64 bits hex: " + e) -f = open("script_encryption_key.gen.cpp", "w") -f.write("#include \"project_settings.h\"\nuint8_t script_encryption_key[32]={" + txt + "};\n") -f.close() +with open("script_encryption_key.gen.cpp", "w") as f: + f.write("#include \"project_settings.h\"\nuint8_t script_encryption_key[32]={" + txt + "};\n") # Add required thirdparty code. Header paths are hardcoded, we don't need to append diff --git a/core/allocators.h b/core/allocators.h index 0d5989b4ab..e17ab298d6 100644 --- a/core/allocators.h +++ b/core/allocators.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef ALLOCATORS_H #define ALLOCATORS_H diff --git a/core/array.cpp b/core/array.cpp index a333830d3a..9e3250fd47 100644 --- a/core/array.cpp +++ b/core/array.cpp @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #include "array.h" #include "hashfuncs.h" @@ -34,8 +35,8 @@ #include "variant.h" #include "vector.h" -struct ArrayPrivate { - +class ArrayPrivate { +public: SafeRefCount refcount; Vector<Variant> array; }; @@ -210,13 +211,13 @@ const Variant &Array::get(int p_idx) const { return operator[](p_idx); } -Array Array::duplicate() const { +Array Array::duplicate(bool p_deep) const { Array new_arr; int element_count = size(); new_arr.resize(element_count); for (int i = 0; i < element_count; i++) { - new_arr[i] = get(i); + new_arr[i] = p_deep ? get(i).duplicate(p_deep) : get(i); } return new_arr; @@ -265,6 +266,20 @@ Array &Array::sort_custom(Object *p_obj, const StringName &p_function) { return *this; } +void Array::shuffle() { + + const int n = _p->array.size(); + if (n < 2) + return; + Variant *data = _p->array.ptrw(); + for (int i = n - 1; i >= 1; i--) { + const int j = Math::rand() % (i + 1); + const Variant tmp = data[j]; + data[j] = data[i]; + data[i] = tmp; + } +} + template <typename Less> _FORCE_INLINE_ int bisect(const Vector<Variant> &p_array, const Variant &p_value, bool p_before, const Less &p_less) { diff --git a/core/array.h b/core/array.h index 4aef4f49c5..e549a886e6 100644 --- a/core/array.h +++ b/core/array.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef ARRAY_H #define ARRAY_H @@ -70,6 +71,7 @@ public: Array &sort(); Array &sort_custom(Object *p_obj, const StringName &p_function); + void shuffle(); int bsearch(const Variant &p_value, bool p_before = true); int bsearch_custom(const Variant &p_value, Object *p_obj, const StringName &p_function, bool p_before = true); Array &invert(); @@ -86,7 +88,7 @@ public: Variant pop_back(); Variant pop_front(); - Array duplicate() const; + Array duplicate(bool p_deep = false) const; Array(const Array &p_from); Array(); diff --git a/core/bind/core_bind.cpp b/core/bind/core_bind.cpp index c1e33c1493..9c484f313e 100644 --- a/core/bind/core_bind.cpp +++ b/core/bind/core_bind.cpp @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #include "core_bind.h" #include "core/project_settings.h" @@ -70,7 +71,13 @@ Ref<ResourceInteractiveLoader> _ResourceLoader::load_interactive(const String &p RES _ResourceLoader::load(const String &p_path, const String &p_type_hint, bool p_no_cache) { - RES ret = ResourceLoader::load(p_path, p_type_hint, p_no_cache); + Error err = OK; + RES ret = ResourceLoader::load(p_path, p_type_hint, p_no_cache, &err); + + if (err != OK) { + ERR_EXPLAIN("Error loading resource: '" + p_path + "'"); + ERR_FAIL_COND_V(err != OK, ret); + } return ret; } @@ -198,6 +205,22 @@ String _OS::get_clipboard() const { return OS::get_singleton()->get_clipboard(); } +int _OS::get_video_driver_count() const { + return OS::get_singleton()->get_video_driver_count(); +} + +String _OS::get_video_driver_name(int p_driver) const { + return OS::get_singleton()->get_video_driver_name(p_driver); +} + +int _OS::get_audio_driver_count() const { + return OS::get_singleton()->get_audio_driver_count(); +} + +String _OS::get_audio_driver_name(int p_driver) const { + return OS::get_singleton()->get_audio_driver_name(p_driver); +} + void _OS::set_video_mode(const Size2 &p_size, bool p_fullscreen, bool p_resizeable, int p_screen) { OS::VideoMode vm; @@ -257,10 +280,18 @@ Size2 _OS::get_window_size() const { return OS::get_singleton()->get_window_size(); } +Size2 _OS::get_real_window_size() const { + return OS::get_singleton()->get_real_window_size(); +} + void _OS::set_window_size(const Size2 &p_size) { OS::get_singleton()->set_window_size(p_size); } +Rect2 _OS::get_window_safe_area() const { + return OS::get_singleton()->get_window_safe_area(); +} + void _OS::set_window_fullscreen(bool p_enabled) { OS::get_singleton()->set_window_fullscreen(p_enabled); } @@ -293,6 +324,14 @@ bool _OS::is_window_maximized() const { return OS::get_singleton()->is_window_maximized(); } +void _OS::set_window_always_on_top(bool p_enabled) { + OS::get_singleton()->set_window_always_on_top(p_enabled); +} + +bool _OS::is_window_always_on_top() const { + return OS::get_singleton()->is_window_always_on_top(); +} + void _OS::set_borderless_window(bool p_borderless) { OS::get_singleton()->set_borderless_window(p_borderless); } @@ -600,8 +639,8 @@ uint64_t _OS::get_unix_time_from_datetime(Dictionary datetime) const { unsigned int second = ((datetime.has(SECOND_KEY)) ? static_cast<unsigned int>(datetime[SECOND_KEY]) : 0); unsigned int minute = ((datetime.has(MINUTE_KEY)) ? static_cast<unsigned int>(datetime[MINUTE_KEY]) : 0); unsigned int hour = ((datetime.has(HOUR_KEY)) ? static_cast<unsigned int>(datetime[HOUR_KEY]) : 0); - unsigned int day = ((datetime.has(DAY_KEY)) ? static_cast<unsigned int>(datetime[DAY_KEY]) : 0); - unsigned int month = ((datetime.has(MONTH_KEY)) ? static_cast<unsigned int>(datetime[MONTH_KEY]) - 1 : 0); + unsigned int day = ((datetime.has(DAY_KEY)) ? static_cast<unsigned int>(datetime[DAY_KEY]) : 1); + unsigned int month = ((datetime.has(MONTH_KEY)) ? static_cast<unsigned int>(datetime[MONTH_KEY]) : 1); unsigned int year = ((datetime.has(YEAR_KEY)) ? static_cast<unsigned int>(datetime[YEAR_KEY]) : 0); /// How many days come before each month (0-12) @@ -621,15 +660,15 @@ uint64_t _OS::get_unix_time_from_datetime(Dictionary datetime) const { ERR_EXPLAIN("Invalid hour value of: " + itos(hour)); ERR_FAIL_COND_V(hour > 23, 0); - ERR_EXPLAIN("Invalid month value of: " + itos(month + 1)); - ERR_FAIL_COND_V(month + 1 > 12, 0); + ERR_EXPLAIN("Invalid month value of: " + itos(month)); + ERR_FAIL_COND_V(month > 12 || month == 0, 0); // Do this check after month is tested as valid - ERR_EXPLAIN("Invalid day value of: " + itos(day) + " which is larger than " + itos(MONTH_DAYS_TABLE[LEAPYEAR(year)][month])); - ERR_FAIL_COND_V(day > MONTH_DAYS_TABLE[LEAPYEAR(year)][month], 0); + ERR_EXPLAIN("Invalid day value of: " + itos(day) + " which is larger than " + itos(MONTH_DAYS_TABLE[LEAPYEAR(year)][month - 1]) + " or 0"); + ERR_FAIL_COND_V(day > MONTH_DAYS_TABLE[LEAPYEAR(year)][month - 1] || day == 0, 0); // Calculate all the seconds from months past in this year - uint64_t SECONDS_FROM_MONTHS_PAST_THIS_YEAR = DAYS_PAST_THIS_YEAR_TABLE[LEAPYEAR(year)][month] * SECONDS_PER_DAY; + uint64_t SECONDS_FROM_MONTHS_PAST_THIS_YEAR = DAYS_PAST_THIS_YEAR_TABLE[LEAPYEAR(year)][month - 1] * SECONDS_PER_DAY; uint64_t SECONDS_FROM_YEARS_PAST = 0; for (unsigned int iyear = EPOCH_YR; iyear < year; iyear++) { @@ -922,6 +961,11 @@ void _OS::request_attention() { OS::get_singleton()->request_attention(); } +void _OS::center_window() { + + OS::get_singleton()->center_window(); +} + bool _OS::is_debug_build() const { #ifdef DEBUG_ENABLED @@ -991,6 +1035,11 @@ void _OS::_bind_methods() { //ClassDB::bind_method(D_METHOD("is_video_mode_resizable","screen"),&_OS::is_video_mode_resizable,DEFVAL(0)); //ClassDB::bind_method(D_METHOD("get_fullscreen_mode_list","screen"),&_OS::get_fullscreen_mode_list,DEFVAL(0)); + ClassDB::bind_method(D_METHOD("get_video_driver_count"), &_OS::get_video_driver_count); + ClassDB::bind_method(D_METHOD("get_video_driver_name", "driver"), &_OS::get_video_driver_name); + ClassDB::bind_method(D_METHOD("get_audio_driver_count"), &_OS::get_audio_driver_count); + ClassDB::bind_method(D_METHOD("get_audio_driver_name", "driver"), &_OS::get_audio_driver_name); + ClassDB::bind_method(D_METHOD("get_screen_count"), &_OS::get_screen_count); ClassDB::bind_method(D_METHOD("get_current_screen"), &_OS::get_current_screen); ClassDB::bind_method(D_METHOD("set_current_screen", "screen"), &_OS::set_current_screen); @@ -1001,6 +1050,7 @@ void _OS::_bind_methods() { ClassDB::bind_method(D_METHOD("set_window_position", "position"), &_OS::set_window_position); ClassDB::bind_method(D_METHOD("get_window_size"), &_OS::get_window_size); ClassDB::bind_method(D_METHOD("set_window_size", "size"), &_OS::set_window_size); + ClassDB::bind_method(D_METHOD("get_window_safe_area"), &_OS::get_window_safe_area); ClassDB::bind_method(D_METHOD("set_window_fullscreen", "enabled"), &_OS::set_window_fullscreen); ClassDB::bind_method(D_METHOD("is_window_fullscreen"), &_OS::is_window_fullscreen); ClassDB::bind_method(D_METHOD("set_window_resizable", "enabled"), &_OS::set_window_resizable); @@ -1009,7 +1059,11 @@ void _OS::_bind_methods() { ClassDB::bind_method(D_METHOD("is_window_minimized"), &_OS::is_window_minimized); ClassDB::bind_method(D_METHOD("set_window_maximized", "enabled"), &_OS::set_window_maximized); ClassDB::bind_method(D_METHOD("is_window_maximized"), &_OS::is_window_maximized); + ClassDB::bind_method(D_METHOD("set_window_always_on_top", "enabled"), &_OS::set_window_always_on_top); + ClassDB::bind_method(D_METHOD("is_window_always_on_top"), &_OS::is_window_always_on_top); ClassDB::bind_method(D_METHOD("request_attention"), &_OS::request_attention); + ClassDB::bind_method(D_METHOD("get_real_window_size"), &_OS::get_real_window_size); + ClassDB::bind_method(D_METHOD("center_window"), &_OS::center_window); ClassDB::bind_method(D_METHOD("set_borderless_window", "borderless"), &_OS::set_borderless_window); ClassDB::bind_method(D_METHOD("get_borderless_window"), &_OS::get_borderless_window); @@ -1122,6 +1176,22 @@ void _OS::_bind_methods() { ClassDB::bind_method(D_METHOD("get_power_seconds_left"), &_OS::get_power_seconds_left); ClassDB::bind_method(D_METHOD("get_power_percent_left"), &_OS::get_power_percent_left); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "clipboard"), "set_clipboard", "get_clipboard"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "current_screen"), "set_current_screen", "get_current_screen"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "exit_code"), "set_exit_code", "get_exit_code"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "vsync_enabled"), "set_use_vsync", "is_vsync_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "low_processor_usage_mode"), "set_low_processor_usage_mode", "is_in_low_processor_usage_mode"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "keep_screen_on"), "set_keep_screen_on", "is_keep_screen_on"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "screen_orientation", PROPERTY_HINT_ENUM, "Landscape,Portrait,Reverse Landscape,Reverse Portrait,Sensor Landscape,Sensor Portrait,Sensor"), "set_screen_orientation", "get_screen_orientation"); + ADD_GROUP("Window", "window_"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "window_borderless"), "set_borderless_window", "get_borderless_window"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "window_fullscreen"), "set_window_fullscreen", "is_window_fullscreen"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "window_maximized"), "set_window_maximized", "is_window_maximized"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "window_minimized"), "set_window_minimized", "is_window_minimized"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "window_resizable"), "set_window_resizable", "is_window_resizable"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "window_position"), "set_window_position", "get_window_position"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "window_size"), "set_window_size", "get_window_size"); + BIND_ENUM_CONSTANT(DAY_SUNDAY); BIND_ENUM_CONSTANT(DAY_MONDAY); BIND_ENUM_CONSTANT(DAY_TUESDAY); @@ -1211,6 +1281,16 @@ Variant _Geometry::segment_intersects_segment_2d(const Vector2 &p_from_a, const }; }; +Variant _Geometry::line_intersects_line_2d(const Vector2 &p_from_a, const Vector2 &p_dir_a, const Vector2 &p_from_b, const Vector2 &p_dir_b) { + + Vector2 result; + if (Geometry::line_intersects_line_2d(p_from_a, p_dir_a, p_from_b, p_dir_b, result)) { + return result; + } else { + return Variant(); + } +} + PoolVector<Vector2> _Geometry::get_closest_points_between_segments_2d(const Vector2 &p1, const Vector2 &q1, const Vector2 &p2, const Vector2 &q2) { Vector2 r1, r2; @@ -1366,6 +1446,7 @@ void _Geometry::_bind_methods() { ClassDB::bind_method(D_METHOD("build_capsule_planes", "radius", "height", "sides", "lats", "axis"), &_Geometry::build_capsule_planes, DEFVAL(Vector3::AXIS_Z)); ClassDB::bind_method(D_METHOD("segment_intersects_circle", "segment_from", "segment_to", "circle_position", "circle_radius"), &_Geometry::segment_intersects_circle); ClassDB::bind_method(D_METHOD("segment_intersects_segment_2d", "from_a", "to_a", "from_b", "to_b"), &_Geometry::segment_intersects_segment_2d); + ClassDB::bind_method(D_METHOD("line_intersects_line_2d", "from_a", "dir_a", "from_b", "dir_b"), &_Geometry::line_intersects_line_2d); ClassDB::bind_method(D_METHOD("get_closest_points_between_segments_2d", "p1", "q1", "p2", "q2"), &_Geometry::get_closest_points_between_segments_2d); ClassDB::bind_method(D_METHOD("get_closest_points_between_segments", "p1", "p2", "q1", "q2"), &_Geometry::get_closest_points_between_segments); @@ -1470,6 +1551,17 @@ bool _File::is_open() const { return f != NULL; } +String _File::get_path() const { + + ERR_FAIL_COND_V(!f, ""); + return f->get_path(); +} + +String _File::get_path_absolute() const { + + ERR_FAIL_COND_V(!f, ""); + return f->get_path_absolute(); +} void _File::seek(int64_t p_position) { @@ -1759,6 +1851,8 @@ void _File::_bind_methods() { ClassDB::bind_method(D_METHOD("open", "path", "flags"), &_File::open); ClassDB::bind_method(D_METHOD("close"), &_File::close); + ClassDB::bind_method(D_METHOD("get_path"), &_File::get_path); + ClassDB::bind_method(D_METHOD("get_path_absolute"), &_File::get_path_absolute); ClassDB::bind_method(D_METHOD("is_open"), &_File::is_open); ClassDB::bind_method(D_METHOD("seek", "position"), &_File::seek); ClassDB::bind_method(D_METHOD("seek_end", "position"), &_File::seek_end, DEFVAL(0)); @@ -1801,6 +1895,8 @@ void _File::_bind_methods() { ClassDB::bind_method(D_METHOD("file_exists", "path"), &_File::file_exists); ClassDB::bind_method(D_METHOD("get_modified_time", "file"), &_File::get_modified_time); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "endian_swap"), "set_endian_swap", "get_endian_swap"); + BIND_ENUM_CONSTANT(READ); BIND_ENUM_CONSTANT(WRITE); BIND_ENUM_CONSTANT(READ_WRITE); @@ -2328,7 +2424,7 @@ _Thread::_Thread() { _Thread::~_Thread() { if (active) { - ERR_EXPLAIN("Reference to a Thread object object was lost while the thread is still running.."); + ERR_EXPLAIN("Reference to a Thread object object was lost while the thread is still running..."); } ERR_FAIL_COND(active == true); } @@ -2459,7 +2555,13 @@ Array _ClassDB::get_method_list(StringName p_class, bool p_no_inheritance) const Array ret; for (List<MethodInfo>::Element *E = methods.front(); E; E = E->next()) { +#ifdef DEBUG_METHODS_ENABLED ret.push_back(E->get().operator Dictionary()); +#else + Dictionary dict; + dict["name"] = E->get().name; + ret.push_back(dict); +#endif } return ret; @@ -2550,11 +2652,19 @@ int _Engine::get_iterations_per_second() const { return Engine::get_singleton()->get_iterations_per_second(); } +void _Engine::set_physics_jitter_fix(float p_threshold) { + Engine::get_singleton()->set_physics_jitter_fix(p_threshold); +} + +float _Engine::get_physics_jitter_fix() const { + return Engine::get_singleton()->get_physics_jitter_fix(); +} + void _Engine::set_target_fps(int p_fps) { Engine::get_singleton()->set_target_fps(p_fps); } -float _Engine::get_target_fps() const { +int _Engine::get_target_fps() const { return Engine::get_singleton()->get_target_fps(); } @@ -2616,6 +2726,8 @@ void _Engine::_bind_methods() { ClassDB::bind_method(D_METHOD("set_iterations_per_second", "iterations_per_second"), &_Engine::set_iterations_per_second); ClassDB::bind_method(D_METHOD("get_iterations_per_second"), &_Engine::get_iterations_per_second); + ClassDB::bind_method(D_METHOD("set_physics_jitter_fix", "physics_jitter_fix"), &_Engine::set_physics_jitter_fix); + ClassDB::bind_method(D_METHOD("get_physics_jitter_fix"), &_Engine::get_physics_jitter_fix); ClassDB::bind_method(D_METHOD("set_target_fps", "target_fps"), &_Engine::set_target_fps); ClassDB::bind_method(D_METHOD("get_target_fps"), &_Engine::get_target_fps); @@ -2636,6 +2748,12 @@ void _Engine::_bind_methods() { ClassDB::bind_method(D_METHOD("set_editor_hint", "enabled"), &_Engine::set_editor_hint); ClassDB::bind_method(D_METHOD("is_editor_hint"), &_Engine::is_editor_hint); + + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "editor_hint"), "set_editor_hint", "is_editor_hint"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "iterations_per_second"), "set_iterations_per_second", "get_iterations_per_second"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "target_fps"), "set_target_fps", "get_target_fps"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "time_scale"), "set_time_scale", "get_time_scale"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "physics_jitter_fix"), "set_physics_jitter_fix", "get_physics_jitter_fix"); } _Engine *_Engine::singleton = NULL; diff --git a/core/bind/core_bind.h b/core/bind/core_bind.h index ed4111fea4..625cac25a0 100644 --- a/core/bind/core_bind.h +++ b/core/bind/core_bind.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef CORE_BIND_H #define CORE_BIND_H @@ -145,6 +146,12 @@ public: bool is_video_mode_resizable(int p_screen = 0) const; Array get_fullscreen_mode_list(int p_screen = 0) const; + virtual int get_video_driver_count() const; + virtual String get_video_driver_name(int p_driver) const; + + virtual int get_audio_driver_count() const; + virtual String get_audio_driver_name(int p_driver) const; + virtual int get_screen_count() const; virtual int get_current_screen() const; virtual void set_current_screen(int p_screen); @@ -154,6 +161,8 @@ public: virtual Point2 get_window_position() const; virtual void set_window_position(const Point2 &p_position); virtual Size2 get_window_size() const; + virtual Size2 get_real_window_size() const; + virtual Rect2 get_window_safe_area() const; virtual void set_window_size(const Size2 &p_size); virtual void set_window_fullscreen(bool p_enabled); virtual bool is_window_fullscreen() const; @@ -163,7 +172,10 @@ public: virtual bool is_window_minimized() const; virtual void set_window_maximized(bool p_enabled); virtual bool is_window_maximized() const; + virtual void set_window_always_on_top(bool p_enabled); + virtual bool is_window_always_on_top() const; virtual void request_attention(); + virtual void center_window(); virtual void set_borderless_window(bool p_borderless); virtual bool get_borderless_window() const; @@ -346,6 +358,7 @@ public: PoolVector<Plane> build_cylinder_planes(float p_radius, float p_height, int p_sides, Vector3::Axis p_axis = Vector3::AXIS_Z); PoolVector<Plane> build_capsule_planes(float p_radius, float p_height, int p_sides, int p_lats, Vector3::Axis p_axis = Vector3::AXIS_Z); Variant segment_intersects_segment_2d(const Vector2 &p_from_a, const Vector2 &p_to_a, const Vector2 &p_from_b, const Vector2 &p_to_b); + Variant line_intersects_line_2d(const Vector2 &p_from_a, const Vector2 &p_dir_a, const Vector2 &p_from_b, const Vector2 &p_dir_b); PoolVector<Vector2> get_closest_points_between_segments_2d(const Vector2 &p1, const Vector2 &q1, const Vector2 &p2, const Vector2 &q2); PoolVector<Vector3> get_closest_points_between_segments(const Vector3 &p1, const Vector3 &p2, const Vector3 &q1, const Vector3 &q2); Vector2 get_closest_point_to_segment_2d(const Vector2 &p_point, const Vector2 &p_a, const Vector2 &p_b); @@ -404,6 +417,9 @@ public: void close(); ///< close a file bool is_open() const; ///< true when file is open + String get_path() const; /// returns the path for the current open file + String get_path_absolute() const; /// returns the absolute path for the current open file + void seek(int64_t p_position); ///< seek to a given position void seek_end(int64_t p_position = 0); ///< seek from the end of file int64_t get_position() const; ///< get position in the file @@ -654,8 +670,11 @@ public: void set_iterations_per_second(int p_ips); int get_iterations_per_second() const; + void set_physics_jitter_fix(float p_threshold); + float get_physics_jitter_fix() const; + void set_target_fps(int p_fps); - float get_target_fps() const; + int get_target_fps() const; float get_frames_per_second() const; diff --git a/core/class_db.cpp b/core/class_db.cpp index 141bc1c5e2..59b100e282 100644 --- a/core/class_db.cpp +++ b/core/class_db.cpp @@ -27,23 +27,15 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #include "class_db.h" #include "os/mutex.h" #include "version.h" -#ifdef NO_THREADS - -#define OBJTYPE_RLOCK -#define OBJTYPE_WLOCK - -#else - #define OBJTYPE_RLOCK RWLockRead _rw_lockr_(lock); #define OBJTYPE_WLOCK RWLockWrite _rw_lockw_(lock); -#endif - #ifdef DEBUG_METHODS_ENABLED MethodDefinition D_METHOD(const char *p_name) { @@ -206,6 +198,47 @@ MethodDefinition D_METHOD(const char *p_name, const char *p_arg1, const char *p_ return md; } +MethodDefinition D_METHOD(const char *p_name, const char *p_arg1, const char *p_arg2, const char *p_arg3, const char *p_arg4, const char *p_arg5, const char *p_arg6, const char *p_arg7, const char *p_arg8, const char *p_arg9, const char *p_arg10, const char *p_arg11, const char *p_arg12) { + + MethodDefinition md; + md.name = StaticCString::create(p_name); + md.args.resize(12); + md.args[0] = StaticCString::create(p_arg1); + md.args[1] = StaticCString::create(p_arg2); + md.args[2] = StaticCString::create(p_arg3); + md.args[3] = StaticCString::create(p_arg4); + md.args[4] = StaticCString::create(p_arg5); + md.args[5] = StaticCString::create(p_arg6); + md.args[6] = StaticCString::create(p_arg7); + md.args[7] = StaticCString::create(p_arg8); + md.args[8] = StaticCString::create(p_arg9); + md.args[9] = StaticCString::create(p_arg10); + md.args[10] = StaticCString::create(p_arg11); + md.args[11] = StaticCString::create(p_arg12); + return md; +} + +MethodDefinition D_METHOD(const char *p_name, const char *p_arg1, const char *p_arg2, const char *p_arg3, const char *p_arg4, const char *p_arg5, const char *p_arg6, const char *p_arg7, const char *p_arg8, const char *p_arg9, const char *p_arg10, const char *p_arg11, const char *p_arg12, const char *p_arg13) { + + MethodDefinition md; + md.name = StaticCString::create(p_name); + md.args.resize(13); + md.args[0] = StaticCString::create(p_arg1); + md.args[1] = StaticCString::create(p_arg2); + md.args[2] = StaticCString::create(p_arg3); + md.args[3] = StaticCString::create(p_arg4); + md.args[4] = StaticCString::create(p_arg5); + md.args[5] = StaticCString::create(p_arg6); + md.args[6] = StaticCString::create(p_arg7); + md.args[7] = StaticCString::create(p_arg8); + md.args[8] = StaticCString::create(p_arg9); + md.args[9] = StaticCString::create(p_arg10); + md.args[10] = StaticCString::create(p_arg11); + md.args[11] = StaticCString::create(p_arg12); + md.args[12] = StaticCString::create(p_arg13); + return md; +} + #endif ClassDB::APIType ClassDB::current_api = API_CORE; @@ -221,11 +254,13 @@ HashMap<StringName, StringName, StringNameHasher> ClassDB::compat_classes; ClassDB::ClassInfo::ClassInfo() { + api = API_NONE; creation_func = NULL; inherits_ptr = NULL; disabled = false; exposed = false; } + ClassDB::ClassInfo::~ClassInfo() { } @@ -305,7 +340,7 @@ uint64_t ClassDB::get_api_hash(APIType p_api) { OBJTYPE_RLOCK; #ifdef DEBUG_METHODS_ENABLED - uint64_t hash = hash_djb2_one_64(HashMapHasherDefault::hash(VERSION_FULL_NAME)); + uint64_t hash = hash_djb2_one_64(HashMapHasherDefault::hash(VERSION_FULL_CONFIG)); List<StringName> names; @@ -322,7 +357,7 @@ uint64_t ClassDB::get_api_hash(APIType p_api) { ClassInfo *t = classes.getptr(E->get()); ERR_FAIL_COND_V(!t, 0); - if (t->api != p_api) + if (t->api != p_api || !t->exposed) continue; hash = hash_djb2_one_64(t->name.hash(), hash); hash = hash_djb2_one_64(t->inherits.hash(), hash); @@ -618,7 +653,6 @@ void ClassDB::bind_integer_constant(const StringName &p_class, const StringName } type->constant_map[p_name] = p_constant; -#ifdef DEBUG_METHODS_ENABLED String enum_name = p_enum; if (enum_name != String()) { @@ -637,6 +671,7 @@ void ClassDB::bind_integer_constant(const StringName &p_class, const StringName } } +#ifdef DEBUG_METHODS_ENABLED type->constant_order.push_back(p_name); #endif } @@ -692,7 +727,6 @@ int ClassDB::get_integer_constant(const StringName &p_class, const StringName &p return 0; } -#ifdef DEBUG_METHODS_ENABLED StringName ClassDB::get_integer_constant_enum(const StringName &p_class, const StringName &p_name, bool p_no_inheritance) { OBJTYPE_RLOCK; @@ -761,7 +795,6 @@ void ClassDB::get_enum_constants(const StringName &p_class, const StringName &p_ type = type->inherits_ptr; } } -#endif void ClassDB::add_signal(StringName p_class, const MethodInfo &p_signal) { @@ -853,15 +886,9 @@ void ClassDB::add_property_group(StringName p_class, const String &p_name, const void ClassDB::add_property(StringName p_class, const PropertyInfo &p_pinfo, const StringName &p_setter, const StringName &p_getter, int p_index) { -#ifndef NO_THREADS lock->read_lock(); -#endif - ClassInfo *type = classes.getptr(p_class); - -#ifndef NO_THREADS lock->read_unlock(); -#endif ERR_FAIL_COND(!type); @@ -1338,10 +1365,7 @@ RWLock *ClassDB::lock = NULL; void ClassDB::init() { -#ifndef NO_THREADS - lock = RWLock::create(); -#endif } void ClassDB::cleanup() { @@ -1364,10 +1388,7 @@ void ClassDB::cleanup() { resource_base_extensions.clear(); compat_classes.clear(); -#ifndef NO_THREADS - memdelete(lock); -#endif } // diff --git a/core/class_db.h b/core/class_db.h index c977068be1..2c77ffe65f 100644 --- a/core/class_db.h +++ b/core/class_db.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef CLASS_DB_H #define CLASS_DB_H @@ -67,6 +68,8 @@ MethodDefinition D_METHOD(const char *p_name, const char *p_arg1, const char *p_ MethodDefinition D_METHOD(const char *p_name, const char *p_arg1, const char *p_arg2, const char *p_arg3, const char *p_arg4, const char *p_arg5, const char *p_arg6, const char *p_arg7, const char *p_arg8, const char *p_arg9); MethodDefinition D_METHOD(const char *p_name, const char *p_arg1, const char *p_arg2, const char *p_arg3, const char *p_arg4, const char *p_arg5, const char *p_arg6, const char *p_arg7, const char *p_arg8, const char *p_arg9, const char *p_arg10); MethodDefinition D_METHOD(const char *p_name, const char *p_arg1, const char *p_arg2, const char *p_arg3, const char *p_arg4, const char *p_arg5, const char *p_arg6, const char *p_arg7, const char *p_arg8, const char *p_arg9, const char *p_arg10, const char *p_arg11); +MethodDefinition D_METHOD(const char *p_name, const char *p_arg1, const char *p_arg2, const char *p_arg3, const char *p_arg4, const char *p_arg5, const char *p_arg6, const char *p_arg7, const char *p_arg8, const char *p_arg9, const char *p_arg10, const char *p_arg11, const char *p_arg12); +MethodDefinition D_METHOD(const char *p_name, const char *p_arg1, const char *p_arg2, const char *p_arg3, const char *p_arg4, const char *p_arg5, const char *p_arg6, const char *p_arg7, const char *p_arg8, const char *p_arg9, const char *p_arg10, const char *p_arg11, const char *p_arg12, const char *p_arg13); #else @@ -113,10 +116,10 @@ public: ClassInfo *inherits_ptr; HashMap<StringName, MethodBind *, StringNameHasher> method_map; HashMap<StringName, int, StringNameHasher> constant_map; + HashMap<StringName, List<StringName> > enum_map; HashMap<StringName, MethodInfo, StringNameHasher> signal_map; List<PropertyInfo> property_list; #ifdef DEBUG_METHODS_ENABLED - HashMap<StringName, List<StringName> > enum_map; List<StringName> constant_order; List<StringName> method_order; Set<StringName> methods_in_properties; @@ -341,11 +344,9 @@ public: static void get_integer_constant_list(const StringName &p_class, List<String> *p_constants, bool p_no_inheritance = false); static int get_integer_constant(const StringName &p_class, const StringName &p_name, bool *p_success = NULL); -#ifdef DEBUG_METHODS_ENABLED static StringName get_integer_constant_enum(const StringName &p_class, const StringName &p_name, bool p_no_inheritance = false); static void get_enum_list(const StringName &p_class, List<StringName> *p_enums, bool p_no_inheritance = false); static void get_enum_constants(const StringName &p_class, const StringName &p_enum, List<StringName> *p_constants, bool p_no_inheritance = false); -#endif static StringName get_category(const StringName &p_node); diff --git a/core/color.cpp b/core/color.cpp index 00a31dfdd8..b2f5889166 100644 --- a/core/color.cpp +++ b/core/color.cpp @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #include "color.h" #include "color_names.inc" @@ -399,6 +400,59 @@ String Color::to_html(bool p_alpha) const { return txt; } +Color Color::from_hsv(float p_h, float p_s, float p_v, float p_a) { + + p_h = Math::fmod(p_h * 360.0f, 360.0f); + if (p_h < 0.0) + p_h += 360.0f; + + const float h_ = p_h / 60.0f; + const float c = p_v * p_s; + const float x = c * (1.0f - Math::abs(Math::fmod(h_, 2.0f) - 1.0f)); + float r, g, b; + + switch ((int)h_) { + case 0: { + r = c; + g = x; + b = 0; + } break; + case 1: { + r = x; + g = c; + b = 0; + } break; + case 2: { + r = 0; + g = c; + b = x; + } break; + case 3: { + r = 0; + g = x; + b = c; + } break; + case 4: { + r = x; + g = 0; + b = c; + } break; + case 5: { + r = c; + g = 0; + b = x; + } break; + default: { + r = 0; + g = 0; + b = 0; + } break; + } + + const float m = p_v - c; + return Color(m + r, m + g, m + b, p_a); +} + float Color::gray() const { return (r + g + b) / 3.0; @@ -412,96 +466,95 @@ Color::operator String() const { Color Color::operator+(const Color &p_color) const { return Color( - CLAMP(r + p_color.r, 0.0, 1.0), - CLAMP(g + p_color.g, 0.0, 1.0), - CLAMP(b + p_color.b, 0.0, 1.0), - CLAMP(a + p_color.a, 0.0, 1.0)); + r + p_color.r, + g + p_color.g, + b + p_color.b, + a + p_color.a); } void Color::operator+=(const Color &p_color) { - r = CLAMP(r + p_color.r, 0.0, 1.0); - g = CLAMP(g + p_color.g, 0.0, 1.0); - b = CLAMP(b + p_color.b, 0.0, 1.0); - a = CLAMP(a + p_color.a, 0.0, 1.0); + r = r + p_color.r; + g = g + p_color.g; + b = b + p_color.b; + a = a + p_color.a; } Color Color::operator-(const Color &p_color) const { return Color( - CLAMP(r - p_color.r, 0.0, 1.0), - CLAMP(g - p_color.g, 0.0, 1.0), - CLAMP(b - p_color.b, 0.0, 1.0), - CLAMP(a - p_color.a, 0.0, 1.0)); + r - p_color.r, + g - p_color.g, + b - p_color.b, + a - p_color.a); } void Color::operator-=(const Color &p_color) { - r = CLAMP(r - p_color.r, 0.0, 1.0); - g = CLAMP(g - p_color.g, 0.0, 1.0); - b = CLAMP(b - p_color.b, 0.0, 1.0); - a = CLAMP(a - p_color.a, 0.0, 1.0); + r = r - p_color.r; + g = g - p_color.g; + b = b - p_color.b; + a = a - p_color.a; } Color Color::operator*(const Color &p_color) const { return Color( - CLAMP(r * p_color.r, 0.0, 1.0), - CLAMP(g * p_color.g, 0.0, 1.0), - CLAMP(b * p_color.b, 0.0, 1.0), - CLAMP(a * p_color.a, 0.0, 1.0)); + r * p_color.r, + g * p_color.g, + b * p_color.b, + a * p_color.a); } Color Color::operator*(const real_t &rvalue) const { return Color( - CLAMP(r * rvalue, 0.0, 1.0), - CLAMP(g * rvalue, 0.0, 1.0), - CLAMP(b * rvalue, 0.0, 1.0), - CLAMP(a * rvalue, 0.0, 1.0)); + r * rvalue, + g * rvalue, + b * rvalue, + a * rvalue); } void Color::operator*=(const Color &p_color) { - r = CLAMP(r * p_color.r, 0.0, 1.0); - g = CLAMP(g * p_color.g, 0.0, 1.0); - b = CLAMP(b * p_color.b, 0.0, 1.0); - a = CLAMP(a * p_color.a, 0.0, 1.0); + r = r * p_color.r; + g = g * p_color.g; + b = b * p_color.b; + a = a * p_color.a; } void Color::operator*=(const real_t &rvalue) { - r = CLAMP(r * rvalue, 0.0, 1.0); - g = CLAMP(g * rvalue, 0.0, 1.0); - b = CLAMP(b * rvalue, 0.0, 1.0); - a = CLAMP(a * rvalue, 0.0, 1.0); -}; + r = r * rvalue; + g = g * rvalue; + b = b * rvalue; + a = a * rvalue; +} Color Color::operator/(const Color &p_color) const { return Color( - p_color.r == 0 ? 1 : CLAMP(r / p_color.r, 0.0, 1.0), - p_color.g == 0 ? 1 : CLAMP(g / p_color.g, 0.0, 1.0), - p_color.b == 0 ? 1 : CLAMP(b / p_color.b, 0.0, 1.0), - p_color.a == 0 ? 1 : CLAMP(a / p_color.a, 0.0, 1.0)); + r / p_color.r, + g / p_color.g, + b / p_color.b, + a / p_color.a); } Color Color::operator/(const real_t &rvalue) const { - if (rvalue == 0) return Color(1.0, 1.0, 1.0, 1.0); return Color( - CLAMP(r / rvalue, 0.0, 1.0), - CLAMP(g / rvalue, 0.0, 1.0), - CLAMP(b / rvalue, 0.0, 1.0), - CLAMP(a / rvalue, 0.0, 1.0)); + r / rvalue, + g / rvalue, + b / rvalue, + a / rvalue); } void Color::operator/=(const Color &p_color) { - r = p_color.r == 0 ? 1 : CLAMP(r / p_color.r, 0.0, 1.0); - g = p_color.g == 0 ? 1 : CLAMP(g / p_color.g, 0.0, 1.0); - b = p_color.b == 0 ? 1 : CLAMP(b / p_color.b, 0.0, 1.0); - a = p_color.a == 0 ? 1 : CLAMP(a / p_color.a, 0.0, 1.0); + r = r / p_color.r; + g = g / p_color.g; + b = b / p_color.b; + a = a / p_color.a; } void Color::operator/=(const real_t &rvalue) { @@ -512,18 +565,18 @@ void Color::operator/=(const real_t &rvalue) { b = 1.0; a = 1.0; } else { - r = CLAMP(r / rvalue, 0.0, 1.0); - g = CLAMP(g / rvalue, 0.0, 1.0); - b = CLAMP(b / rvalue, 0.0, 1.0); - a = CLAMP(a / rvalue, 0.0, 1.0); + r = r / rvalue; + g = g / rvalue; + b = b / rvalue; + a = a / rvalue; } }; Color Color::operator-() const { return Color( - CLAMP(1.0 - r, 0.0, 1.0), - CLAMP(1.0 - g, 0.0, 1.0), - CLAMP(1.0 - b, 0.0, 1.0), - CLAMP(1.0 - a, 0.0, 1.0)); + 1.0 - r, + 1.0 - g, + 1.0 - b, + 1.0 - a); } diff --git a/core/color.h b/core/color.h index 70b0e1fea2..a2015a34d6 100644 --- a/core/color.h +++ b/core/color.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef COLOR_H #define COLOR_H @@ -104,18 +105,18 @@ struct Color { _FORCE_INLINE_ Color darkened(float p_amount) const { Color res = *this; - res.r = CLAMP(res.r * (1.0f - p_amount), 0.0, 1.0); - res.g = CLAMP(res.g * (1.0f - p_amount), 0.0, 1.0); - res.b = CLAMP(res.b * (1.0f - p_amount), 0.0, 1.0); + res.r = res.r * (1.0f - p_amount); + res.g = res.g * (1.0f - p_amount); + res.b = res.b * (1.0f - p_amount); return res; } _FORCE_INLINE_ Color lightened(float p_amount) const { Color res = *this; - res.r = CLAMP(res.r + (1.0f - res.r) * p_amount, 0.0, 1.0); - res.g = CLAMP(res.g + (1.0f - res.g) * p_amount, 0.0, 1.0); - res.b = CLAMP(res.b + (1.0f - res.b) * p_amount, 0.0, 1.0); + res.r = res.r + (1.0f - res.r) * p_amount; + res.g = res.g + (1.0f - res.g) * p_amount; + res.b = res.b + (1.0f - res.b) * p_amount; return res; } @@ -189,6 +190,7 @@ struct Color { static bool html_is_valid(const String &p_color); static Color named(const String &p_name); String to_html(bool p_alpha = true) const; + Color from_hsv(float p_h, float p_s, float p_v, float p_a); _FORCE_INLINE_ bool operator<(const Color &p_color) const; //used in set keys operator String() const; diff --git a/core/command_queue_mt.cpp b/core/command_queue_mt.cpp index 8ce0ba7810..a39c920dfa 100644 --- a/core/command_queue_mt.cpp +++ b/core/command_queue_mt.cpp @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #include "command_queue_mt.h" #include "os/os.h" @@ -104,6 +105,7 @@ CommandQueueMT::CommandQueueMT(bool p_sync) { read_ptr = 0; write_ptr = 0; + dealloc_ptr = 0; mutex = Mutex::create(); for (int i = 0; i < SYNC_SEMAPHORES; i++) { diff --git a/core/command_queue_mt.h b/core/command_queue_mt.h index e53ded6755..3942b961d3 100644 --- a/core/command_queue_mt.h +++ b/core/command_queue_mt.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef COMMAND_QUEUE_MT_H #define COMMAND_QUEUE_MT_H @@ -54,7 +55,7 @@ #define _COMMA_11 , #define _COMMA_12 , -// 1-based comma separed list of ITEMs +// 1-based comma separated list of ITEMs #define COMMA_SEP_LIST(ITEM, LENGTH) _COMMA_SEP_LIST_##LENGTH(ITEM) #define _COMMA_SEP_LIST_12(ITEM) \ _COMMA_SEP_LIST_11(ITEM) \ @@ -94,7 +95,7 @@ ITEM(1) #define _COMMA_SEP_LIST_0(ITEM) -// 1-based semicolon separed list of ITEMs +// 1-based semicolon separated list of ITEMs #define SEMIC_SEP_LIST(ITEM, LENGTH) _SEMIC_SEP_LIST_##LENGTH(ITEM) #define _SEMIC_SEP_LIST_12(ITEM) \ _SEMIC_SEP_LIST_11(ITEM); \ @@ -134,7 +135,7 @@ ITEM(1) #define _SEMIC_SEP_LIST_0(ITEM) -// 1-based space separed list of ITEMs +// 1-based space separated list of ITEMs #define SPACE_SEP_LIST(ITEM, LENGTH) _SPACE_SEP_LIST_##LENGTH(ITEM) #define _SPACE_SEP_LIST_12(ITEM) \ _SPACE_SEP_LIST_11(ITEM) \ diff --git a/core/compressed_translation.cpp b/core/compressed_translation.cpp index b393b67d50..266d793af7 100644 --- a/core/compressed_translation.cpp +++ b/core/compressed_translation.cpp @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #include "compressed_translation.h" #include "pair.h" diff --git a/core/compressed_translation.h b/core/compressed_translation.h index bedd38d1bc..ccc47d0bf6 100644 --- a/core/compressed_translation.h +++ b/core/compressed_translation.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef COMPRESSED_TRANSLATION_H #define COMPRESSED_TRANSLATION_H @@ -37,7 +38,7 @@ class PHashTranslation : public Translation { GDCLASS(PHashTranslation, Translation); //this translation uses a sort of modified perfect hash algorithm - //it requieres hashing strings twice and then does a binary search, + //it requires hashing strings twice and then does a binary search, //so it's slower, but at the same time it has an extreemly high chance //of catching untranslated strings diff --git a/core/core_string_names.cpp b/core/core_string_names.cpp index 7a9edcad46..ba596f7f16 100644 --- a/core/core_string_names.cpp +++ b/core/core_string_names.cpp @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #include "core_string_names.h" CoreStringNames *CoreStringNames::singleton = NULL; diff --git a/core/core_string_names.h b/core/core_string_names.h index f48692f470..dcbce14aac 100644 --- a/core/core_string_names.h +++ b/core/core_string_names.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef CORE_STRING_NAMES_H #define CORE_STRING_NAMES_H diff --git a/core/dictionary.cpp b/core/dictionary.cpp index 72893c41f6..ba0de95861 100644 --- a/core/dictionary.cpp +++ b/core/dictionary.cpp @@ -27,21 +27,17 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #include "dictionary.h" #include "ordered_hash_map.h" #include "safe_refcount.h" #include "variant.h" -struct _DictionaryVariantHash { - - static _FORCE_INLINE_ uint32_t hash(const Variant &p_variant) { return p_variant.hash(); } -}; - struct DictionaryPrivate { SafeRefCount refcount; - OrderedHashMap<Variant, Variant, _DictionaryVariantHash> variant_map; + OrderedHashMap<Variant, Variant, VariantHasher, VariantComparator> variant_map; }; void Dictionary::get_key_list(List<Variant> *p_keys) const { @@ -49,7 +45,7 @@ void Dictionary::get_key_list(List<Variant> *p_keys) const { if (_p->variant_map.empty()) return; - for (OrderedHashMap<Variant, Variant, _DictionaryVariantHash>::Element E = _p->variant_map.front(); E; E = E.next()) { + for (OrderedHashMap<Variant, Variant, VariantHasher, VariantComparator>::Element E = _p->variant_map.front(); E; E = E.next()) { p_keys->push_back(E.key()); } } @@ -65,7 +61,7 @@ const Variant &Dictionary::operator[](const Variant &p_key) const { } const Variant *Dictionary::getptr(const Variant &p_key) const { - OrderedHashMap<Variant, Variant, _DictionaryVariantHash>::ConstElement E = ((const OrderedHashMap<Variant, Variant, _DictionaryVariantHash> *)&_p->variant_map)->find(p_key); + OrderedHashMap<Variant, Variant, VariantHasher, VariantComparator>::ConstElement E = ((const OrderedHashMap<Variant, Variant, VariantHasher, VariantComparator> *)&_p->variant_map)->find(p_key); if (!E) return NULL; @@ -74,7 +70,7 @@ const Variant *Dictionary::getptr(const Variant &p_key) const { Variant *Dictionary::getptr(const Variant &p_key) { - OrderedHashMap<Variant, Variant, _DictionaryVariantHash>::Element E = _p->variant_map.find(p_key); + OrderedHashMap<Variant, Variant, VariantHasher, VariantComparator>::Element E = _p->variant_map.find(p_key); if (!E) return NULL; @@ -83,7 +79,7 @@ Variant *Dictionary::getptr(const Variant &p_key) { Variant Dictionary::get_valid(const Variant &p_key) const { - OrderedHashMap<Variant, Variant, _DictionaryVariantHash>::ConstElement E = ((const OrderedHashMap<Variant, Variant, _DictionaryVariantHash> *)&_p->variant_map)->find(p_key); + OrderedHashMap<Variant, Variant, VariantHasher, VariantComparator>::ConstElement E = ((const OrderedHashMap<Variant, Variant, VariantHasher, VariantComparator> *)&_p->variant_map)->find(p_key); if (!E) return Variant(); @@ -176,7 +172,7 @@ Array Dictionary::keys() const { return varr; int i = 0; - for (OrderedHashMap<Variant, Variant, _DictionaryVariantHash>::Element E = _p->variant_map.front(); E; E = E.next()) { + for (OrderedHashMap<Variant, Variant, VariantHasher, VariantComparator>::Element E = _p->variant_map.front(); E; E = E.next()) { varr[i] = E.key(); i++; } @@ -192,7 +188,7 @@ Array Dictionary::values() const { return varr; int i = 0; - for (OrderedHashMap<Variant, Variant, _DictionaryVariantHash>::Element E = _p->variant_map.front(); E; E = E.next()) { + for (OrderedHashMap<Variant, Variant, VariantHasher, VariantComparator>::Element E = _p->variant_map.front(); E; E = E.next()) { varr[i] = E.get(); i++; } @@ -208,14 +204,14 @@ const Variant *Dictionary::next(const Variant *p_key) const { return &_p->variant_map.front().key(); return NULL; } - OrderedHashMap<Variant, Variant, _DictionaryVariantHash>::Element E = _p->variant_map.find(*p_key); + OrderedHashMap<Variant, Variant, VariantHasher, VariantComparator>::Element E = _p->variant_map.find(*p_key); if (E && E.next()) return &E.next().key(); return NULL; } -Dictionary Dictionary::duplicate() const { +Dictionary Dictionary::duplicate(bool p_deep) const { Dictionary n; @@ -223,7 +219,7 @@ Dictionary Dictionary::duplicate() const { get_key_list(&keys); for (List<Variant>::Element *E = keys.front(); E; E = E->next()) { - n[E->get()] = operator[](E->get()); + n[E->get()] = p_deep ? operator[](E->get()).duplicate(p_deep) : operator[](E->get()); } return n; diff --git a/core/dictionary.h b/core/dictionary.h index 86f676fc38..9eef265d5b 100644 --- a/core/dictionary.h +++ b/core/dictionary.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef DICTIONARY_H #define DICTIONARY_H @@ -74,7 +75,7 @@ public: Array keys() const; Array values() const; - Dictionary duplicate() const; + Dictionary duplicate(bool p_deep = false) const; Dictionary(const Dictionary &p_from); Dictionary(); diff --git a/core/dvector.cpp b/core/dvector.cpp index 653c04b498..b679df55ad 100644 --- a/core/dvector.cpp +++ b/core/dvector.cpp @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #include "dvector.h" Mutex *dvector_lock = NULL; diff --git a/core/dvector.h b/core/dvector.h index 492a4e0ed9..c0190fb9e3 100644 --- a/core/dvector.h +++ b/core/dvector.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef DVECTOR_H #define DVECTOR_H diff --git a/core/engine.cpp b/core/engine.cpp index 4cadad1f6e..b2c34a853c 100644 --- a/core/engine.cpp +++ b/core/engine.cpp @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #include "engine.h" #include "version.h" @@ -41,6 +42,16 @@ int Engine::get_iterations_per_second() const { return ips; } +void Engine::set_physics_jitter_fix(float p_threshold) { + if (p_threshold < 0) + p_threshold = 0; + physics_jitter_fix = p_threshold; +} + +float Engine::get_physics_jitter_fix() const { + return physics_jitter_fix; +} + void Engine::set_target_fps(int p_fps) { _target_fps = p_fps > 0 ? p_fps : 0; } @@ -136,6 +147,7 @@ Engine::Engine() { singleton = this; frames_drawn = 0; ips = 60; + physics_jitter_fix = 0.5; _frame_delay = 0; _fps = 1; _target_fps = 0; diff --git a/core/engine.h b/core/engine.h index 2741d09b52..665992699a 100644 --- a/core/engine.h +++ b/core/engine.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef ENGINE_H #define ENGINE_H @@ -56,6 +57,7 @@ private: float _frame_step; int ips; + float physics_jitter_fix; float _fps; int _target_fps; float _time_scale; @@ -78,6 +80,9 @@ public: virtual void set_iterations_per_second(int p_ips); virtual int get_iterations_per_second() const; + void set_physics_jitter_fix(float p_threshold); + float get_physics_jitter_fix() const; + virtual void set_target_fps(int p_fps); virtual float get_target_fps() const; diff --git a/core/error_list.h b/core/error_list.h index 47233e39fe..6b9cd0016b 100644 --- a/core/error_list.h +++ b/core/error_list.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef ERROR_LIST_H #define ERROR_LIST_H diff --git a/core/error_macros.cpp b/core/error_macros.cpp index 76be0756b8..5786802930 100644 --- a/core/error_macros.cpp +++ b/core/error_macros.cpp @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #include "error_macros.h" #include "io/logger.h" diff --git a/core/error_macros.h b/core/error_macros.h index 2bfa94b99e..168b2e06fe 100644 --- a/core/error_macros.h +++ b/core/error_macros.h @@ -27,12 +27,13 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef ERROR_MACROS_H #define ERROR_MACROS_H #include "typedefs.h" /** - * Error macros. Unlike exceptions and asserts, these macros try to mantain consistency and stability + * Error macros. Unlike exceptions and asserts, these macros try to maintain consistency and stability * inside the code. It is recommended to always return processable data, so in case of an error, the * engine can stay working well. * In most cases, bugs and/or invalid data are not fatal and should never allow a perfectly running application @@ -310,4 +311,14 @@ extern bool _err_error_exists; _err_error_exists = false; \ } +#define WARN_DEPRECATED \ + { \ + static bool warning_shown=false;\ + if (!warning_shown) {\ + _err_print_error(FUNCTION_STR, __FILE__, __LINE__,"This method has been deprecated and will be removed in the future", ERR_HANDLER_WARNING); \ + _err_error_exists = false; \ + warning_shown=true;\ + }\ + } + #endif diff --git a/core/func_ref.cpp b/core/func_ref.cpp index 98053808b4..c707f1c4cb 100644 --- a/core/func_ref.cpp +++ b/core/func_ref.cpp @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #include "func_ref.h" Variant FuncRef::call_func(const Variant **p_args, int p_argcount, Variant::CallError &r_error) { diff --git a/core/func_ref.h b/core/func_ref.h index 9f2df8cb5d..681fe747d6 100644 --- a/core/func_ref.h +++ b/core/func_ref.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef FUNC_REF_H #define FUNC_REF_H diff --git a/core/global_constants.cpp b/core/global_constants.cpp index abe829420a..04810afe73 100644 --- a/core/global_constants.cpp +++ b/core/global_constants.cpp @@ -10,7 +10,7 @@ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ -/* "Software") to deal in the Software without restriction, including */ +/* "Software"), to deal in the Software without restriction, including */ /* without limitation the rights to use, copy, modify, merge, publish, */ /* distribute, sublicense, and/or sell copies of the Software, and to */ /* permit persons to whom the Software is furnished to do so, subject to */ @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #include "global_constants.h" #include "object.h" @@ -579,7 +580,7 @@ void register_global_constants() { BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("TYPE_COLOR_ARRAY", Variant::POOL_COLOR_ARRAY); BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("TYPE_MAX", Variant::VARIANT_MAX); - //comparation + //comparison BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("OP_EQUAL", Variant::OP_EQUAL); BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("OP_NOT_EQUAL", Variant::OP_NOT_EQUAL); BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("OP_LESS", Variant::OP_LESS); diff --git a/core/global_constants.h b/core/global_constants.h index 09f93e34a2..76f618989c 100644 --- a/core/global_constants.h +++ b/core/global_constants.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef GLOBAL_CONSTANTS_H #define GLOBAL_CONSTANTS_H diff --git a/core/hash_map.h b/core/hash_map.h index 1a4f879fea..2df743ba7d 100644 --- a/core/hash_map.h +++ b/core/hash_map.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef HASH_MAP_H #define HASH_MAP_H diff --git a/core/hashfuncs.h b/core/hashfuncs.h index 0725a7ebf6..ae99fa39c8 100644 --- a/core/hashfuncs.h +++ b/core/hashfuncs.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef HASHFUNCS_H #define HASHFUNCS_H diff --git a/core/helper/math_fieldwise.h b/core/helper/math_fieldwise.h index c883c44f84..0e7cc3ea4a 100644 --- a/core/helper/math_fieldwise.h +++ b/core/helper/math_fieldwise.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef MATH_FIELDWISE_H #define MATH_FIELDWISE_H diff --git a/core/helper/value_evaluator.h b/core/helper/value_evaluator.h index 954d229517..39177a7820 100644 --- a/core/helper/value_evaluator.h +++ b/core/helper/value_evaluator.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef VALUE_EVALUATOR_H #define VALUE_EVALUATOR_H diff --git a/core/image.cpp b/core/image.cpp index 2f2d7efd7c..51fbe75dec 100644 --- a/core/image.cpp +++ b/core/image.cpp @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #include "image.h" #include "core/io/image_loader.h" @@ -47,7 +48,6 @@ const char *Image::format_names[Image::FORMAT_MAX] = { "RGBA8", "RGBA4444", "RGBA5551", - "RGB10A2", "RFloat", //float "RGFloat", "RGBFloat", @@ -113,7 +113,6 @@ int Image::get_format_pixel_size(Format p_format) { case FORMAT_RGBA8: return 4; case FORMAT_RGBA4444: return 2; case FORMAT_RGBA5551: return 2; - case FORMAT_RGB10A2: return 4; case FORMAT_RF: return 4; //float case FORMAT_RGF: return 8; @@ -367,6 +366,8 @@ int Image::get_mipmap_count() const { template <uint32_t read_bytes, bool read_alpha, uint32_t write_bytes, bool write_alpha, bool read_gray, bool write_gray> static void _convert(int p_width, int p_height, const uint8_t *p_src, uint8_t *p_dst) { + uint32_t max_bytes = MAX(read_bytes, write_bytes); + for (int y = 0; y < p_height; y++) { for (int x = 0; x < p_width; x++) { @@ -380,7 +381,8 @@ static void _convert(int p_width, int p_height, const uint8_t *p_src, uint8_t *p rgba[1] = rofs[0]; rgba[2] = rofs[0]; } else { - for (uint32_t i = 0; i < MAX(read_bytes, write_bytes); i++) { + + for (uint32_t i = 0; i < max_bytes; i++) { rgba[i] = (i < read_bytes) ? rofs[i] : 0; } @@ -448,8 +450,6 @@ void Image::convert(Format p_new_format) { Image new_img(width, height, 0, p_new_format); - //int len=data.size(); - PoolVector<uint8_t>::Read r = data.read(); PoolVector<uint8_t>::Write w = new_img.data.write(); @@ -697,6 +697,11 @@ void Image::resize_to_po2(bool p_square) { void Image::resize(int p_width, int p_height, Interpolation p_interpolation) { + if (data.size() == 0) { + ERR_EXPLAIN("Cannot resize image before creating it, use create() or create_from_data() first."); + ERR_FAIL(); + } + if (!_can_modify(format)) { ERR_EXPLAIN("Cannot resize in indexed, compressed or custom image formats."); ERR_FAIL(); @@ -773,7 +778,7 @@ void Image::crop_from_point(int p_x, int p_y, int p_width, int p_height) { ERR_FAIL_COND(p_y + p_height > MAX_HEIGHT); /* to save memory, cropping should be done in-place, however, since this function - will most likely either not be used much, or in critical areas, for now it wont, because + will most likely either not be used much, or in critical areas, for now it won't, because it's a waste of time. */ if (p_width == width && p_height == height && p_x == 0 && p_y == 0) @@ -935,7 +940,7 @@ bool Image::_can_modify(Format p_format) const { return p_format <= FORMAT_RGBE9995; } -template <int CC> +template <int CC, bool renormalize> static void _generate_po2_mipmap(const uint8_t *p_src, uint8_t *p_dst, uint32_t p_width, uint32_t p_height) { //fast power of 2 mipmap generation @@ -961,6 +966,19 @@ static void _generate_po2_mipmap(const uint8_t *p_src, uint8_t *p_dst, uint32_t dst_ptr[j] = val >> 2; } + if (renormalize) { + Vector3 n(dst_ptr[0] / 255.0, dst_ptr[1] / 255.0, dst_ptr[2] / 255.0); + n *= 2.0; + n -= Vector3(1, 1, 1); + n.normalize(); + n += Vector3(1, 1, 1); + n *= 0.5; + n *= 255; + dst_ptr[0] = CLAMP(int(n.x), 0, 255); + dst_ptr[1] = CLAMP(int(n.y), 0, 255); + dst_ptr[2] = CLAMP(int(n.z), 0, 255); + } + dst_ptr += CC; rup_ptr += CC * 2; rdown_ptr += CC * 2; @@ -1043,11 +1061,11 @@ void Image::shrink_x2() { switch (format) { case FORMAT_L8: - case FORMAT_R8: _generate_po2_mipmap<1>(r.ptr(), w.ptr(), width, height); break; - case FORMAT_LA8: _generate_po2_mipmap<2>(r.ptr(), w.ptr(), width, height); break; - case FORMAT_RG8: _generate_po2_mipmap<2>(r.ptr(), w.ptr(), width, height); break; - case FORMAT_RGB8: _generate_po2_mipmap<3>(r.ptr(), w.ptr(), width, height); break; - case FORMAT_RGBA8: _generate_po2_mipmap<4>(r.ptr(), w.ptr(), width, height); break; + case FORMAT_R8: _generate_po2_mipmap<1, false>(r.ptr(), w.ptr(), width, height); break; + case FORMAT_LA8: _generate_po2_mipmap<2, false>(r.ptr(), w.ptr(), width, height); break; + case FORMAT_RG8: _generate_po2_mipmap<2, false>(r.ptr(), w.ptr(), width, height); break; + case FORMAT_RGB8: _generate_po2_mipmap<3, false>(r.ptr(), w.ptr(), width, height); break; + case FORMAT_RGBA8: _generate_po2_mipmap<4, false>(r.ptr(), w.ptr(), width, height); break; default: {} } } @@ -1058,7 +1076,7 @@ void Image::shrink_x2() { } } -Error Image::generate_mipmaps() { +Error Image::generate_mipmaps(bool p_renormalize) { if (!_can_modify(format)) { ERR_EXPLAIN("Cannot generate mipmaps in indexed, compressed or custom image formats."); @@ -1075,61 +1093,40 @@ Error Image::generate_mipmaps() { PoolVector<uint8_t>::Write wp = data.write(); - if (next_power_of_2(width) == uint32_t(width) && next_power_of_2(height) == uint32_t(height)) { - //use fast code for powers of 2 - int prev_ofs = 0; - int prev_h = height; - int prev_w = width; + int prev_ofs = 0; + int prev_h = height; + int prev_w = width; - for (int i = 1; i < mmcount; i++) { + for (int i = 1; i < mmcount; i++) { - int ofs, w, h; - _get_mipmap_offset_and_size(i, ofs, w, h); + int ofs, w, h; + _get_mipmap_offset_and_size(i, ofs, w, h); - switch (format) { + switch (format) { - case FORMAT_L8: - case FORMAT_R8: _generate_po2_mipmap<1>(&wp[prev_ofs], &wp[ofs], prev_w, prev_h); break; - case FORMAT_LA8: - case FORMAT_RG8: _generate_po2_mipmap<2>(&wp[prev_ofs], &wp[ofs], prev_w, prev_h); break; - case FORMAT_RGB8: _generate_po2_mipmap<3>(&wp[prev_ofs], &wp[ofs], prev_w, prev_h); break; - case FORMAT_RGBA8: _generate_po2_mipmap<4>(&wp[prev_ofs], &wp[ofs], prev_w, prev_h); break; - default: {} - } + case FORMAT_L8: + case FORMAT_R8: _generate_po2_mipmap<1, false>(&wp[prev_ofs], &wp[ofs], prev_w, prev_h); break; + case FORMAT_LA8: + case FORMAT_RG8: _generate_po2_mipmap<2, false>(&wp[prev_ofs], &wp[ofs], prev_w, prev_h); break; + case FORMAT_RGB8: + if (p_renormalize) + _generate_po2_mipmap<3, true>(&wp[prev_ofs], &wp[ofs], prev_w, prev_h); + else + _generate_po2_mipmap<3, false>(&wp[prev_ofs], &wp[ofs], prev_w, prev_h); - prev_ofs = ofs; - prev_w = w; - prev_h = h; + break; + case FORMAT_RGBA8: + if (p_renormalize) + _generate_po2_mipmap<4, true>(&wp[prev_ofs], &wp[ofs], prev_w, prev_h); + else + _generate_po2_mipmap<4, false>(&wp[prev_ofs], &wp[ofs], prev_w, prev_h); + break; + default: {} } - } else { - //use slow code.. - - //use bilinear filtered code for non powers of 2 - int prev_ofs = 0; - int prev_h = height; - int prev_w = width; - - for (int i = 1; i < mmcount; i++) { - - int ofs, w, h; - _get_mipmap_offset_and_size(i, ofs, w, h); - - switch (format) { - - case FORMAT_L8: - case FORMAT_R8: _scale_bilinear<1>(&wp[prev_ofs], &wp[ofs], prev_w, prev_h, w, h); break; - case FORMAT_LA8: - case FORMAT_RG8: _scale_bilinear<2>(&wp[prev_ofs], &wp[ofs], prev_w, prev_h, w, h); break; - case FORMAT_RGB8: _scale_bilinear<3>(&wp[prev_ofs], &wp[ofs], prev_w, prev_h, w, h); break; - case FORMAT_RGBA8: _scale_bilinear<4>(&wp[prev_ofs], &wp[ofs], prev_w, prev_h, w, h); break; - default: {} - } - - prev_ofs = ofs; - prev_w = w; - prev_h = h; - } + prev_ofs = ofs; + prev_w = w; + prev_h = h; } mipmaps = true; @@ -1164,6 +1161,9 @@ PoolVector<uint8_t> Image::get_data() const { void Image::create(int p_width, int p_height, bool p_use_mipmaps, Format p_format) { + ERR_FAIL_INDEX(p_width - 1, MAX_WIDTH); + ERR_FAIL_INDEX(p_height - 1, MAX_HEIGHT); + int mm = 0; int size = _get_dst_image_size(p_width, p_height, p_format, mm, p_use_mipmaps ? -1 : 0); data.resize(size); @@ -1628,6 +1628,12 @@ void Image::blit_rect(const Ref<Image> &p_src, const Rect2 &p_src_rect, const Po ERR_FAIL_COND(format != p_src->format); Rect2i clipped_src_rect = Rect2i(0, 0, p_src->width, p_src->height).clip(p_src_rect); + + if (p_dest.x < 0) + clipped_src_rect.position.x = ABS(p_dest.x); + if (p_dest.y < 0) + clipped_src_rect.position.y = ABS(p_dest.y); + if (clipped_src_rect.size.x <= 0 || clipped_src_rect.size.y <= 0) return; @@ -1676,6 +1682,12 @@ void Image::blit_rect_mask(const Ref<Image> &p_src, const Ref<Image> &p_mask, co ERR_FAIL_COND(format != p_src->format); Rect2i clipped_src_rect = Rect2i(0, 0, p_src->width, p_src->height).clip(p_src_rect); + + if (p_dest.x < 0) + clipped_src_rect.position.x = ABS(p_dest.x); + if (p_dest.y < 0) + clipped_src_rect.position.y = ABS(p_dest.y); + if (clipped_src_rect.size.x <= 0 || clipped_src_rect.size.y <= 0) return; @@ -1727,6 +1739,12 @@ void Image::blend_rect(const Ref<Image> &p_src, const Rect2 &p_src_rect, const P ERR_FAIL_COND(format != p_src->format); Rect2i clipped_src_rect = Rect2i(0, 0, p_src->width, p_src->height).clip(p_src_rect); + + if (p_dest.x < 0) + clipped_src_rect.position.x = ABS(p_dest.x); + if (p_dest.y < 0) + clipped_src_rect.position.y = ABS(p_dest.y); + if (clipped_src_rect.size.x <= 0 || clipped_src_rect.size.y <= 0) return; @@ -1775,6 +1793,12 @@ void Image::blend_rect_mask(const Ref<Image> &p_src, const Ref<Image> &p_mask, c ERR_FAIL_COND(format != p_src->format); Rect2i clipped_src_rect = Rect2i(0, 0, p_src->width, p_src->height).clip(p_src_rect); + + if (p_dest.x < 0) + clipped_src_rect.position.x = ABS(p_dest.x); + if (p_dest.y < 0) + clipped_src_rect.position.y = ABS(p_dest.y); + if (clipped_src_rect.size.x <= 0 || clipped_src_rect.size.y <= 0) return; @@ -1910,6 +1934,10 @@ void Image::unlock() { write_lock = PoolVector<uint8_t>::Write(); } +Color Image::get_pixelv(const Point2 &p_src) const { + return get_pixel(p_src.x, p_src.y); +} + Color Image::get_pixel(int p_x, int p_y) const { uint8_t *ptr = write_lock.ptr(); @@ -1980,15 +2008,6 @@ Color Image::get_pixel(int p_x, int p_y) const { float a = ((u >> 15) & 0x1) / 1.0; return Color(r, g, b, a); } break; - case FORMAT_RGB10A2: { - - uint32_t u = ((uint32_t *)ptr)[ofs]; - float r = (u & 0x3FF) / 1023.0; - float g = ((u >> 10) & 0x3FF) / 1023.0; - float b = ((u >> 20) & 0x3FF) / 1023.0; - float a = ((u >> 30) & 0x3) / 3.0; - return Color(r, g, b, a); - } break; case FORMAT_RF: { float r = ((float *)ptr)[ofs]; @@ -2065,6 +2084,10 @@ Color Image::get_pixel(int p_x, int p_y) const { return Color(); } +void Image::set_pixelv(const Point2 &p_dst, const Color &p_color) { + return set_pixel(p_dst.x, p_dst.y, p_color); +} + void Image::set_pixel(int p_x, int p_y, const Color &p_color) { uint8_t *ptr = write_lock.ptr(); @@ -2134,18 +2157,6 @@ void Image::set_pixel(int p_x, int p_y, const Color &p_color) { ((uint16_t *)ptr)[ofs] = rgba; } break; - case FORMAT_RGB10A2: { - - uint32_t rgba = 0; - - rgba = uint32_t(CLAMP(p_color.r * 1023.0, 0, 1023)); - rgba |= uint32_t(CLAMP(p_color.g * 1023.0, 0, 1023)) << 10; - rgba |= uint32_t(CLAMP(p_color.b * 1023.0, 0, 1023)) << 20; - rgba |= uint32_t(CLAMP(p_color.a * 3.0, 0, 3)) << 30; - - ((uint32_t *)ptr)[ofs] = rgba; - - } break; case FORMAT_RF: { ((float *)ptr)[ofs] = p_color.r; @@ -2268,7 +2279,7 @@ void Image::_bind_methods() { ClassDB::bind_method(D_METHOD("crop", "width", "height"), &Image::crop); ClassDB::bind_method(D_METHOD("flip_x"), &Image::flip_x); ClassDB::bind_method(D_METHOD("flip_y"), &Image::flip_y); - ClassDB::bind_method(D_METHOD("generate_mipmaps"), &Image::generate_mipmaps); + ClassDB::bind_method(D_METHOD("generate_mipmaps", "renormalize"), &Image::generate_mipmaps, DEFVAL(false)); ClassDB::bind_method(D_METHOD("clear_mipmaps"), &Image::clear_mipmaps); ClassDB::bind_method(D_METHOD("create", "width", "height", "use_mipmaps", "format"), &Image::_create_empty); @@ -2290,6 +2301,7 @@ void Image::_bind_methods() { ClassDB::bind_method(D_METHOD("premultiply_alpha"), &Image::premultiply_alpha); ClassDB::bind_method(D_METHOD("srgb_to_linear"), &Image::srgb_to_linear); ClassDB::bind_method(D_METHOD("normalmap_to_xy"), &Image::normalmap_to_xy); + ClassDB::bind_method(D_METHOD("bumpmap_to_normalmap", "bump_scale"), &Image::bumpmap_to_normalmap, DEFVAL(1.0)); ClassDB::bind_method(D_METHOD("blit_rect", "src", "src_rect", "dst"), &Image::blit_rect); ClassDB::bind_method(D_METHOD("blit_rect_mask", "src", "mask", "src_rect", "dst"), &Image::blit_rect_mask); @@ -2307,8 +2319,10 @@ void Image::_bind_methods() { ClassDB::bind_method(D_METHOD("lock"), &Image::lock); ClassDB::bind_method(D_METHOD("unlock"), &Image::unlock); - ClassDB::bind_method(D_METHOD("set_pixel", "x", "y", "color"), &Image::set_pixel); + ClassDB::bind_method(D_METHOD("get_pixelv", "src"), &Image::get_pixelv); ClassDB::bind_method(D_METHOD("get_pixel", "x", "y"), &Image::get_pixel); + ClassDB::bind_method(D_METHOD("set_pixelv", "dst", "color"), &Image::set_pixelv); + ClassDB::bind_method(D_METHOD("set_pixel", "x", "y", "color"), &Image::set_pixel); ClassDB::bind_method(D_METHOD("load_png_from_buffer", "buffer"), &Image::load_png_from_buffer); ClassDB::bind_method(D_METHOD("load_jpg_from_buffer", "buffer"), &Image::load_jpg_from_buffer); @@ -2323,7 +2337,6 @@ void Image::_bind_methods() { BIND_ENUM_CONSTANT(FORMAT_RGBA8); BIND_ENUM_CONSTANT(FORMAT_RGBA4444); BIND_ENUM_CONSTANT(FORMAT_RGBA5551); - BIND_ENUM_CONSTANT(FORMAT_RGB10A2); BIND_ENUM_CONSTANT(FORMAT_RF); //float BIND_ENUM_CONSTANT(FORMAT_RGF); BIND_ENUM_CONSTANT(FORMAT_RGBF); @@ -2399,6 +2412,47 @@ void Image::normalmap_to_xy() { convert(Image::FORMAT_LA8); } +void Image::bumpmap_to_normalmap(float bump_scale) { + ERR_FAIL_COND(!_can_modify(format)); + convert(Image::FORMAT_RF); + + PoolVector<uint8_t> result_image; //rgba output + result_image.resize(width * height * 4); + + { + PoolVector<uint8_t>::Read rp = data.read(); + PoolVector<uint8_t>::Write wp = result_image.write(); + + unsigned char *write_ptr = wp.ptr(); + float *read_ptr = (float *)rp.ptr(); + + for (int ty = 0; ty < height; ty++) { + int py = ty + 1; + if (py >= height) py -= height; + + for (int tx = 0; tx < width; tx++) { + int px = tx + 1; + if (px >= width) px -= width; + float here = read_ptr[ty * width + tx]; + float to_right = read_ptr[ty * width + px]; + float above = read_ptr[py * width + tx]; + Vector3 up = Vector3(0, 1, (here - above) * bump_scale); + Vector3 across = Vector3(1, 0, (to_right - here) * bump_scale); + + Vector3 normal = across.cross(up); + normal.normalize(); + + write_ptr[((ty * width + tx) << 2) + 0] = (127.5 + normal.x * 127.5); + write_ptr[((ty * width + tx) << 2) + 1] = (127.5 + normal.y * 127.5); + write_ptr[((ty * width + tx) << 2) + 2] = (127.5 + normal.z * 127.5); + write_ptr[((ty * width + tx) << 2) + 3] = 255; + } + } + } + format = FORMAT_RGBA8; + data = result_image; +} + void Image::srgb_to_linear() { if (data.size() == 0) diff --git a/core/image.h b/core/image.h index efb62a6a29..80a0c339dd 100644 --- a/core/image.h +++ b/core/image.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef IMAGE_H #define IMAGE_H @@ -68,7 +69,6 @@ public: FORMAT_RGBA8, FORMAT_RGBA4444, FORMAT_RGBA5551, - FORMAT_RGB10A2, FORMAT_RF, //float FORMAT_RGF, FORMAT_RGBF, @@ -217,7 +217,7 @@ public: /** * Generate a mipmap to an image (creates an image 1/4 the size, with averaging of 4->1) */ - Error generate_mipmaps(); + Error generate_mipmaps(bool p_renormalize = false); void clear_mipmaps(); @@ -284,6 +284,7 @@ public: void premultiply_alpha(); void srgb_to_linear(); void normalmap_to_xy(); + void bumpmap_to_normalmap(float bump_scale = 1.0); void blit_rect(const Ref<Image> &p_src, const Rect2 &p_src_rect, const Point2 &p_dest); void blit_rect_mask(const Ref<Image> &p_src, const Ref<Image> &p_mask, const Rect2 &p_src_rect, const Point2 &p_dest); @@ -320,7 +321,9 @@ public: DetectChannels get_detected_channels(); + Color get_pixelv(const Point2 &p_src) const; Color get_pixel(int p_x, int p_y) const; + void set_pixelv(const Point2 &p_dest, const Color &p_color); void set_pixel(int p_x, int p_y, const Color &p_color); void copy_internals_from(const Ref<Image> &p_image) { diff --git a/core/input_map.cpp b/core/input_map.cpp index 7833aab3f3..d33f40cbcf 100644 --- a/core/input_map.cpp +++ b/core/input_map.cpp @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #include "input_map.h" #include "os/keyboard.h" @@ -34,27 +35,32 @@ InputMap *InputMap::singleton = NULL; +int InputMap::ALL_DEVICES = -1; + void InputMap::_bind_methods() { ClassDB::bind_method(D_METHOD("has_action", "action"), &InputMap::has_action); ClassDB::bind_method(D_METHOD("get_actions"), &InputMap::_get_actions); - ClassDB::bind_method(D_METHOD("add_action", "action"), &InputMap::add_action); + ClassDB::bind_method(D_METHOD("add_action", "action", "deadzone"), &InputMap::add_action, DEFVAL(0.5f)); ClassDB::bind_method(D_METHOD("erase_action", "action"), &InputMap::erase_action); + ClassDB::bind_method(D_METHOD("action_set_deadzone", "deadzone"), &InputMap::action_set_deadzone); ClassDB::bind_method(D_METHOD("action_add_event", "action", "event"), &InputMap::action_add_event); ClassDB::bind_method(D_METHOD("action_has_event", "action", "event"), &InputMap::action_has_event); ClassDB::bind_method(D_METHOD("action_erase_event", "action", "event"), &InputMap::action_erase_event); + ClassDB::bind_method(D_METHOD("action_erase_events", "action"), &InputMap::action_erase_events); ClassDB::bind_method(D_METHOD("get_action_list", "action"), &InputMap::_get_action_list); ClassDB::bind_method(D_METHOD("event_is_action", "event", "action"), &InputMap::event_is_action); ClassDB::bind_method(D_METHOD("load_from_globals"), &InputMap::load_from_globals); } -void InputMap::add_action(const StringName &p_action) { +void InputMap::add_action(const StringName &p_action, float p_deadzone) { ERR_FAIL_COND(input_map.has(p_action)); input_map[p_action] = Action(); static int last_id = 1; input_map[p_action].id = last_id; + input_map[p_action].deadzone = p_deadzone; last_id++; } @@ -93,19 +99,21 @@ List<StringName> InputMap::get_actions() const { return actions; } -List<Ref<InputEvent> >::Element *InputMap::_find_event(List<Ref<InputEvent> > &p_list, const Ref<InputEvent> &p_event, bool p_action_test) const { +List<Ref<InputEvent> >::Element *InputMap::_find_event(Action &p_action, const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength) const { - for (List<Ref<InputEvent> >::Element *E = p_list.front(); E; E = E->next()) { + for (List<Ref<InputEvent> >::Element *E = p_action.inputs.front(); E; E = E->next()) { const Ref<InputEvent> e = E->get(); //if (e.type != Ref<InputEvent>::KEY && e.device != p_event.device) -- unsure about the KEY comparison, why is this here? // continue; - if (e->get_device() != p_event->get_device()) - continue; - if (e->action_match(p_event)) - return E; + int device = e->get_device(); + if (device == ALL_DEVICES || device == p_event->get_device()) { + if (e->action_match(p_event, p_pressed, p_strength, p_action.deadzone)) { + return E; + } + } } return NULL; @@ -116,11 +124,18 @@ bool InputMap::has_action(const StringName &p_action) const { return input_map.has(p_action); } +void InputMap::action_set_deadzone(const StringName &p_action, float p_deadzone) { + + ERR_FAIL_COND(!input_map.has(p_action)); + + input_map[p_action].deadzone = p_deadzone; +} + void InputMap::action_add_event(const StringName &p_action, const Ref<InputEvent> &p_event) { ERR_FAIL_COND(p_event.is_null()); ERR_FAIL_COND(!input_map.has(p_action)); - if (_find_event(input_map[p_action].inputs, p_event)) + if (_find_event(input_map[p_action], p_event)) return; //already gots input_map[p_action].inputs.push_back(p_event); @@ -129,18 +144,25 @@ void InputMap::action_add_event(const StringName &p_action, const Ref<InputEvent bool InputMap::action_has_event(const StringName &p_action, const Ref<InputEvent> &p_event) { ERR_FAIL_COND_V(!input_map.has(p_action), false); - return (_find_event(input_map[p_action].inputs, p_event) != NULL); + return (_find_event(input_map[p_action], p_event) != NULL); } void InputMap::action_erase_event(const StringName &p_action, const Ref<InputEvent> &p_event) { ERR_FAIL_COND(!input_map.has(p_action)); - List<Ref<InputEvent> >::Element *E = _find_event(input_map[p_action].inputs, p_event); + List<Ref<InputEvent> >::Element *E = _find_event(input_map[p_action], p_event); if (E) input_map[p_action].inputs.erase(E); } +void InputMap::action_erase_events(const StringName &p_action) { + + ERR_FAIL_COND(!input_map.has(p_action)); + + input_map[p_action].inputs.clear(); +} + Array InputMap::_get_action_list(const StringName &p_action) { Array ret; @@ -165,19 +187,33 @@ const List<Ref<InputEvent> > *InputMap::get_action_list(const StringName &p_acti } bool InputMap::event_is_action(const Ref<InputEvent> &p_event, const StringName &p_action) const { + return event_get_action_status(p_event, p_action); +} +bool InputMap::event_get_action_status(const Ref<InputEvent> &p_event, const StringName &p_action, bool *p_pressed, float *p_strength) const { Map<StringName, Action>::Element *E = input_map.find(p_action); if (!E) { ERR_EXPLAIN("Request for nonexistent InputMap action: " + String(p_action)); ERR_FAIL_COND_V(!E, false); } - Ref<InputEventAction> iea = p_event; - if (iea.is_valid()) { - return iea->get_action() == p_action; + Ref<InputEventAction> input_event_action = p_event; + if (input_event_action.is_valid()) { + return input_event_action->get_action() == p_action; } - return _find_event(E->get().inputs, p_event, true) != NULL; + bool pressed; + float strength; + List<Ref<InputEvent> >::Element *event = _find_event(E->get(), p_event, &pressed, &strength); + if (event != NULL) { + if (p_pressed != NULL) + *p_pressed = pressed; + if (p_strength != NULL) + *p_strength = strength; + return true; + } else { + return false; + } } const Map<StringName, InputMap::Action> &InputMap::get_action_map() const { @@ -199,16 +235,16 @@ void InputMap::load_from_globals() { String name = pi.name.substr(pi.name.find("/") + 1, pi.name.length()); - add_action(name); - - Array va = ProjectSettings::get_singleton()->get(pi.name); + Dictionary action = ProjectSettings::get_singleton()->get(pi.name); + float deadzone = action.has("deadzone") ? (float)action["deadzone"] : 0.5f; + Array events = action["events"]; - for (int i = 0; i < va.size(); i++) { - - Ref<InputEvent> ie = va[i]; - if (ie.is_null()) + add_action(name, deadzone); + for (int i = 0; i < events.size(); i++) { + Ref<InputEvent> event = events[i]; + if (event.is_null()) continue; - action_add_event(name, ie); + action_add_event(name, event); } } } @@ -281,6 +317,16 @@ void InputMap::load_default() { key->set_scancode(KEY_PAGEDOWN); action_add_event("ui_page_down", key); + add_action("ui_home"); + key.instance(); + key->set_scancode(KEY_HOME); + action_add_event("ui_home", key); + + add_action("ui_end"); + key.instance(); + key->set_scancode(KEY_END); + action_add_event("ui_end", key); + //set("display/window/handheld/orientation", "landscape"); } diff --git a/core/input_map.h b/core/input_map.h index 12ac1b339b..bdec75c65b 100644 --- a/core/input_map.h +++ b/core/input_map.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef INPUT_MAP_H #define INPUT_MAP_H @@ -38,8 +39,14 @@ class InputMap : public Object { GDCLASS(InputMap, Object); public: + /** + * A special value used to signify that a given Action can be triggered by any device + */ + static int ALL_DEVICES; + struct Action { int id; + float deadzone; List<Ref<InputEvent> > inputs; }; @@ -48,7 +55,7 @@ private: mutable Map<StringName, Action> input_map; - List<Ref<InputEvent> >::Element *_find_event(List<Ref<InputEvent> > &p_list, const Ref<InputEvent> &p_event, bool p_action_test = false) const; + List<Ref<InputEvent> >::Element *_find_event(Action &p_action, const Ref<InputEvent> &p_event, bool *p_pressed = NULL, float *p_strength = NULL) const; Array _get_action_list(const StringName &p_action); Array _get_actions(); @@ -61,15 +68,18 @@ public: bool has_action(const StringName &p_action) const; List<StringName> get_actions() const; - void add_action(const StringName &p_action); + void add_action(const StringName &p_action, float p_deadzone = 0.5); void erase_action(const StringName &p_action); + void action_set_deadzone(const StringName &p_action, float p_deadzone); void action_add_event(const StringName &p_action, const Ref<InputEvent> &p_event); bool action_has_event(const StringName &p_action, const Ref<InputEvent> &p_event); void action_erase_event(const StringName &p_action, const Ref<InputEvent> &p_event); + void action_erase_events(const StringName &p_action); const List<Ref<InputEvent> > *get_action_list(const StringName &p_action); bool event_is_action(const Ref<InputEvent> &p_event, const StringName &p_action) const; + bool event_get_action_status(const Ref<InputEvent> &p_event, const StringName &p_action, bool *p_pressed = NULL, float *p_strength = NULL) const; const Map<StringName, Action> &get_action_map() const; void load_from_globals(); diff --git a/core/io/compression.cpp b/core/io/compression.cpp index a4dbebe9f7..bc3bfcf356 100644 --- a/core/io/compression.cpp +++ b/core/io/compression.cpp @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #include "compression.h" #include "os/copymem.h" #include "project_settings.h" diff --git a/core/io/compression.h b/core/io/compression.h index 034c5ab708..a0ccd539cb 100644 --- a/core/io/compression.h +++ b/core/io/compression.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef COMPRESSION_H #define COMPRESSION_H diff --git a/core/io/config_file.cpp b/core/io/config_file.cpp index 9a013cb775..aa06ae5cc0 100644 --- a/core/io/config_file.cpp +++ b/core/io/config_file.cpp @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #include "config_file.h" #include "os/file_access.h" #include "os/keyboard.h" diff --git a/core/io/config_file.h b/core/io/config_file.h index 2168e654dd..ac749bed76 100644 --- a/core/io/config_file.h +++ b/core/io/config_file.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef CONFIG_FILE_H #define CONFIG_FILE_H diff --git a/core/io/file_access_buffered.cpp b/core/io/file_access_buffered.cpp index 442ab2c6e4..dcaf99e24a 100644 --- a/core/io/file_access_buffered.cpp +++ b/core/io/file_access_buffered.cpp @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #include "file_access_buffered.h" #include <string.h> diff --git a/core/io/file_access_buffered.h b/core/io/file_access_buffered.h index 2d6df5d48a..f4ed47d6bc 100644 --- a/core/io/file_access_buffered.h +++ b/core/io/file_access_buffered.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef FILE_ACCESS_BUFFERED_H #define FILE_ACCESS_BUFFERED_H diff --git a/core/io/file_access_buffered_fa.h b/core/io/file_access_buffered_fa.h index bb3d3f33f6..493fa1c243 100644 --- a/core/io/file_access_buffered_fa.h +++ b/core/io/file_access_buffered_fa.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef FILE_ACCESS_BUFFERED_FA_H #define FILE_ACCESS_BUFFERED_FA_H diff --git a/core/io/file_access_compressed.cpp b/core/io/file_access_compressed.cpp index aabd70cc7b..d6547ba19f 100644 --- a/core/io/file_access_compressed.cpp +++ b/core/io/file_access_compressed.cpp @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #include "file_access_compressed.h" #include "print_string.h" void FileAccessCompressed::configure(const String &p_magic, Compression::Mode p_mode, int p_block_size) { diff --git a/core/io/file_access_compressed.h b/core/io/file_access_compressed.h index 65eefbcd97..587f58a7c6 100644 --- a/core/io/file_access_compressed.h +++ b/core/io/file_access_compressed.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef FILE_ACCESS_COMPRESSED_H #define FILE_ACCESS_COMPRESSED_H diff --git a/core/io/file_access_encrypted.cpp b/core/io/file_access_encrypted.cpp index 67151f6934..221f457b78 100644 --- a/core/io/file_access_encrypted.cpp +++ b/core/io/file_access_encrypted.cpp @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #include "file_access_encrypted.h" #include "core/variant.h" diff --git a/core/io/file_access_encrypted.h b/core/io/file_access_encrypted.h index 002a124e86..b9365a9fd0 100644 --- a/core/io/file_access_encrypted.h +++ b/core/io/file_access_encrypted.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef FILE_ACCESS_ENCRYPTED_H #define FILE_ACCESS_ENCRYPTED_H diff --git a/core/io/file_access_memory.cpp b/core/io/file_access_memory.cpp index 8812aa847e..1aa1e4a595 100644 --- a/core/io/file_access_memory.cpp +++ b/core/io/file_access_memory.cpp @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #include "file_access_memory.h" #include "map.h" diff --git a/core/io/file_access_memory.h b/core/io/file_access_memory.h index 1d438409cc..2136f4cc0c 100644 --- a/core/io/file_access_memory.h +++ b/core/io/file_access_memory.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef FILE_ACCESS_MEMORY_H #define FILE_ACCESS_MEMORY_H diff --git a/core/io/file_access_network.cpp b/core/io/file_access_network.cpp index 1aa431dcae..21e3a4172b 100644 --- a/core/io/file_access_network.cpp +++ b/core/io/file_access_network.cpp @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #include "file_access_network.h" #include "io/ip.h" #include "marshalls.h" @@ -82,7 +83,7 @@ int64_t FileAccessNetworkClient::get_64() { void FileAccessNetworkClient::_thread_func() { - client->set_nodelay(true); + client->set_no_delay(true); while (!quit) { DEBUG_PRINT("SEM WAIT - " + itos(sem->get())); @@ -417,8 +418,6 @@ int FileAccessNetwork::get_buffer(uint8_t *p_dst, int p_length) const { if (page != last_page) { buffer_mutex->lock(); if (pages[page].buffer.empty()) { - //fuck - waiting_on_page = page; for (int j = 0; j < read_ahead; j++) { diff --git a/core/io/file_access_network.h b/core/io/file_access_network.h index 4d8e8f1a9a..be9bdb1af6 100644 --- a/core/io/file_access_network.h +++ b/core/io/file_access_network.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef FILE_ACCESS_NETWORK_H #define FILE_ACCESS_NETWORK_H diff --git a/core/io/file_access_pack.cpp b/core/io/file_access_pack.cpp index 318e3ad759..efb4c7a073 100644 --- a/core/io/file_access_pack.cpp +++ b/core/io/file_access_pack.cpp @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #include "file_access_pack.h" #include "version.h" @@ -87,7 +88,11 @@ void PackedData::add_path(const String &pkg_path, const String &path, uint64_t o } } } - cd->files.insert(path.get_file()); + String filename = path.get_file(); + // Don't add as a file if the path points to a directoryy + if (!filename.empty()) { + cd->files.insert(filename); + } } } diff --git a/core/io/file_access_pack.h b/core/io/file_access_pack.h index 6c5fec1498..8a40e6d78c 100644 --- a/core/io/file_access_pack.h +++ b/core/io/file_access_pack.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef FILE_ACCESS_PACK_H #define FILE_ACCESS_PACK_H diff --git a/core/io/file_access_zip.cpp b/core/io/file_access_zip.cpp index c439ac7fa5..7b6385c3ff 100644 --- a/core/io/file_access_zip.cpp +++ b/core/io/file_access_zip.cpp @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifdef MINIZIP_ENABLED #include "file_access_zip.h" diff --git a/core/io/file_access_zip.h b/core/io/file_access_zip.h index b8f4a93e2a..df83575f6a 100644 --- a/core/io/file_access_zip.h +++ b/core/io/file_access_zip.h @@ -27,10 +27,11 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifdef MINIZIP_ENABLED -#ifndef FILE_ACCESS_Zip_H -#define FILE_ACCESS_Zip_H +#ifndef FILE_ACCESS_ZIP_H +#define FILE_ACCESS_ZIP_H #include "core/io/file_access_pack.h" #include "map.h" @@ -120,4 +121,4 @@ public: #endif // FILE_ACCESS_ZIP_H -#endif +#endif // MINIZIP_ENABLED diff --git a/core/io/http_client.cpp b/core/io/http_client.cpp index 088c05dfae..9e301ccac5 100644 --- a/core/io/http_client.cpp +++ b/core/io/http_client.cpp @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #include "http_client.h" #include "io/stream_peer_ssl.h" @@ -297,7 +298,7 @@ Error HTTPClient::poll() { case StreamPeerTCP::STATUS_CONNECTED: { if (ssl) { Ref<StreamPeerSSL> ssl = StreamPeerSSL::create(); - Error err = ssl->connect_to_stream(tcp_connection, ssl_verify_host, ssl_verify_host ? conn_host : String()); + Error err = ssl->connect_to_stream(tcp_connection, ssl_verify_host, conn_host); if (err != OK) { close(); status = STATUS_SSL_HANDSHAKE_ERROR; @@ -617,7 +618,27 @@ String HTTPClient::query_string_from_dict(const Dictionary &p_dict) { String query = ""; Array keys = p_dict.keys(); for (int i = 0; i < keys.size(); ++i) { - query += "&" + String(keys[i]).http_escape() + "=" + String(p_dict[keys[i]]).http_escape(); + String encoded_key = String(keys[i]).http_escape(); + Variant value = p_dict[keys[i]]; + switch (value.get_type()) { + case Variant::ARRAY: { + // Repeat the key with every values + Array values = value; + for (int j = 0; j < values.size(); ++j) { + query += "&" + encoded_key + "=" + String(values[j]).http_escape(); + } + break; + } + case Variant::NIL: { + // Add the key with no value + query += "&" + encoded_key; + break; + } + default: { + // Add the key-value pair + query += "&" + encoded_key + "=" + String(value).http_escape(); + } + } } query.erase(0, 1); return query; @@ -681,6 +702,9 @@ void HTTPClient::_bind_methods() { ClassDB::bind_method(D_METHOD("query_string_from_dict", "fields"), &HTTPClient::query_string_from_dict); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "blocking_mode_enabled"), "set_blocking_mode", "is_blocking_mode_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "connection", PROPERTY_HINT_RESOURCE_TYPE, "StreamPeer", 0), "set_connection", "get_connection"); + BIND_ENUM_CONSTANT(METHOD_GET); BIND_ENUM_CONSTANT(METHOD_HEAD); BIND_ENUM_CONSTANT(METHOD_POST); diff --git a/core/io/http_client.h b/core/io/http_client.h index 0fcaf26fdb..839012e701 100644 --- a/core/io/http_client.h +++ b/core/io/http_client.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef HTTP_CLIENT_H #define HTTP_CLIENT_H diff --git a/core/io/image_loader.cpp b/core/io/image_loader.cpp index c4cdb86c85..8ebd9d6cd9 100644 --- a/core/io/image_loader.cpp +++ b/core/io/image_loader.cpp @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #include "image_loader.h" #include "print_string.h" @@ -36,7 +37,7 @@ bool ImageFormatLoader::recognize(const String &p_extension) const { get_recognized_extensions(&extensions); for (List<String>::Element *E = extensions.front(); E; E = E->next()) { - if (E->get().nocasecmp_to(p_extension.get_extension()) == 0) + if (E->get().nocasecmp_to(p_extension) == 0) return true; } diff --git a/core/io/image_loader.h b/core/io/image_loader.h index b147566aed..052a8b8a40 100644 --- a/core/io/image_loader.h +++ b/core/io/image_loader.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef IMAGE_LOADER_H #define IMAGE_LOADER_H diff --git a/core/io/ip.cpp b/core/io/ip.cpp index 9d55c5258f..66bd96df4f 100644 --- a/core/io/ip.cpp +++ b/core/io/ip.cpp @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #include "ip.h" #include "hash_map.h" #include "os/semaphore.h" diff --git a/core/io/ip.h b/core/io/ip.h index 69a9b7fd67..d55b05b6fe 100644 --- a/core/io/ip.h +++ b/core/io/ip.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef IP_H #define IP_H diff --git a/core/io/ip_address.cpp b/core/io/ip_address.cpp index 6495e0503d..6d979d10eb 100644 --- a/core/io/ip_address.cpp +++ b/core/io/ip_address.cpp @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #include "ip_address.h" /* IP_Address::operator Variant() const { @@ -210,7 +211,7 @@ IP_Address::IP_Address(const String &p_string) { clear(); if (p_string == "*") { - // Wildcard (not a vaild IP) + // Wildcard (not a valid IP) wildcard = true; } else if (p_string.find(":") >= 0) { diff --git a/core/io/ip_address.h b/core/io/ip_address.h index 7a1c1a17e6..d7b031b960 100644 --- a/core/io/ip_address.h +++ b/core/io/ip_address.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef IP_ADDRESS_H #define IP_ADDRESS_H diff --git a/core/io/json.cpp b/core/io/json.cpp index 1cc44f8558..7b2c5a62df 100644 --- a/core/io/json.cpp +++ b/core/io/json.cpp @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #include "json.h" #include "print_string.h" diff --git a/core/io/json.h b/core/io/json.h index f47e0c42c4..9c12423798 100644 --- a/core/io/json.h +++ b/core/io/json.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef JSON_H #define JSON_H diff --git a/core/io/marshalls.cpp b/core/io/marshalls.cpp index 3bdd4454e1..0a3a6c1ba1 100644 --- a/core/io/marshalls.cpp +++ b/core/io/marshalls.cpp @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #include "marshalls.h" #include "os/keyboard.h" #include "print_string.h" @@ -332,7 +333,7 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int len -= 12; buf += 12; - if (flags & 2) // Obsolete format with property seperate from subpath + if (flags & 2) // Obsolete format with property separate from subpath subnamecount++; uint32_t total = namecount + subnamecount; @@ -812,7 +813,7 @@ static void _encode_string(const String &p_string, uint8_t *&buf, int &r_len) { while (r_len % 4) { r_len++; //pad if (buf) { - buf++; + *(buf++) = 0; } } } @@ -1210,7 +1211,9 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo r_len += len; if (buf) buf += len; - encode_variant(d[E->get()], buf, len, p_object_as_id); + Variant *v = d.getptr(E->get()); + ERR_FAIL_COND_V(!v, ERR_BUG); + encode_variant(*v, buf, len, p_object_as_id); ERR_FAIL_COND_V(len % 4, ERR_BUG); r_len += len; if (buf) diff --git a/core/io/marshalls.h b/core/io/marshalls.h index b7ce1d39e2..381e4e3d20 100644 --- a/core/io/marshalls.h +++ b/core/io/marshalls.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef MARSHALLS_H #define MARSHALLS_H diff --git a/core/io/multiplayer_api.cpp b/core/io/multiplayer_api.cpp new file mode 100644 index 0000000000..cbe7f87d92 --- /dev/null +++ b/core/io/multiplayer_api.cpp @@ -0,0 +1,722 @@ +#include "core/io/multiplayer_api.h" +#include "core/io/marshalls.h" +#include "scene/main/node.h" + +void MultiplayerAPI::poll() { + + if (!network_peer.is_valid() || network_peer->get_connection_status() == NetworkedMultiplayerPeer::CONNECTION_DISCONNECTED) + return; + + network_peer->poll(); + + if (!network_peer.is_valid()) //it's possible that polling might have resulted in a disconnection, so check here + return; + + while (network_peer->get_available_packet_count()) { + + int sender = network_peer->get_packet_peer(); + const uint8_t *packet; + int len; + + Error err = network_peer->get_packet(&packet, len); + if (err != OK) { + ERR_PRINT("Error getting packet!"); + } + + rpc_sender_id = sender; + _process_packet(sender, packet, len); + rpc_sender_id = 0; + + if (!network_peer.is_valid()) { + break; //it's also possible that a packet or RPC caused a disconnection, so also check here + } + } +} + +void MultiplayerAPI::clear() { + connected_peers.clear(); + path_get_cache.clear(); + path_send_cache.clear(); + last_send_cache_id = 1; +} + +void MultiplayerAPI::set_root_node(Node *p_node) { + root_node = p_node; +} + +void MultiplayerAPI::set_network_peer(const Ref<NetworkedMultiplayerPeer> &p_peer) { + + if (network_peer.is_valid()) { + network_peer->disconnect("peer_connected", this, "add_peer"); + network_peer->disconnect("peer_disconnected", this, "del_peer"); + network_peer->disconnect("connection_succeeded", this, "connected_to_server"); + network_peer->disconnect("connection_failed", this, "connection_failed"); + network_peer->disconnect("server_disconnected", this, "server_disconnected"); + clear(); + } + + network_peer = p_peer; + + ERR_EXPLAIN("Supplied NetworkedNetworkPeer must be connecting or connected."); + ERR_FAIL_COND(p_peer.is_valid() && p_peer->get_connection_status() == NetworkedMultiplayerPeer::CONNECTION_DISCONNECTED); + + if (network_peer.is_valid()) { + network_peer->connect("peer_connected", this, "add_peer"); + network_peer->connect("peer_disconnected", this, "del_peer"); + network_peer->connect("connection_succeeded", this, "connected_to_server"); + network_peer->connect("connection_failed", this, "connection_failed"); + network_peer->connect("server_disconnected", this, "server_disconnected"); + } +} + +Ref<NetworkedMultiplayerPeer> MultiplayerAPI::get_network_peer() const { + return network_peer; +} + +void MultiplayerAPI::_process_packet(int p_from, const uint8_t *p_packet, int p_packet_len) { + + ERR_FAIL_COND(root_node == NULL); + ERR_FAIL_COND(p_packet_len < 5); + + uint8_t packet_type = p_packet[0]; + + switch (packet_type) { + + case NETWORK_COMMAND_SIMPLIFY_PATH: { + + _process_simplify_path(p_from, p_packet, p_packet_len); + } break; + + case NETWORK_COMMAND_CONFIRM_PATH: { + + _process_confirm_path(p_from, p_packet, p_packet_len); + } break; + + case NETWORK_COMMAND_REMOTE_CALL: + case NETWORK_COMMAND_REMOTE_SET: { + + ERR_FAIL_COND(p_packet_len < 6); + + Node *node = _process_get_node(p_from, p_packet, p_packet_len); + + ERR_FAIL_COND(node == NULL); + + //detect cstring end + int len_end = 5; + for (; len_end < p_packet_len; len_end++) { + if (p_packet[len_end] == 0) { + break; + } + } + + ERR_FAIL_COND(len_end >= p_packet_len); + + StringName name = String::utf8((const char *)&p_packet[5]); + + if (packet_type == NETWORK_COMMAND_REMOTE_CALL) { + + _process_rpc(node, name, p_from, p_packet, p_packet_len, len_end + 1); + + } else { + + _process_rset(node, name, p_from, p_packet, p_packet_len, len_end + 1); + } + + } break; + } +} + +Node *MultiplayerAPI::_process_get_node(int p_from, const uint8_t *p_packet, int p_packet_len) { + + uint32_t target = decode_uint32(&p_packet[1]); + Node *node = NULL; + + if (target & 0x80000000) { + //use full path (not cached yet) + + int ofs = target & 0x7FFFFFFF; + ERR_FAIL_COND_V(ofs >= p_packet_len, NULL); + + String paths; + paths.parse_utf8((const char *)&p_packet[ofs], p_packet_len - ofs); + + NodePath np = paths; + + node = root_node->get_node(np); + + if (!node) + ERR_PRINTS("Failed to get path from RPC: " + String(np)); + } else { + //use cached path + int id = target; + + Map<int, PathGetCache>::Element *E = path_get_cache.find(p_from); + ERR_FAIL_COND_V(!E, NULL); + + Map<int, PathGetCache::NodeInfo>::Element *F = E->get().nodes.find(id); + ERR_FAIL_COND_V(!F, NULL); + + PathGetCache::NodeInfo *ni = &F->get(); + //do proper caching later + + node = root_node->get_node(ni->path); + if (!node) + ERR_PRINTS("Failed to get cached path from RPC: " + String(ni->path)); + } + return node; +} + +void MultiplayerAPI::_process_rpc(Node *p_node, const StringName &p_name, int p_from, const uint8_t *p_packet, int p_packet_len, int p_offset) { + if (!p_node->can_call_rpc(p_name, p_from)) + return; + + ERR_FAIL_COND(p_offset >= p_packet_len); + + int argc = p_packet[p_offset]; + Vector<Variant> args; + Vector<const Variant *> argp; + args.resize(argc); + argp.resize(argc); + + p_offset++; + + for (int i = 0; i < argc; i++) { + + ERR_FAIL_COND(p_offset >= p_packet_len); + int vlen; + Error err = decode_variant(args[i], &p_packet[p_offset], p_packet_len - p_offset, &vlen); + ERR_FAIL_COND(err != OK); + //args[i]=p_packet[3+i]; + argp[i] = &args[i]; + p_offset += vlen; + } + + Variant::CallError ce; + + p_node->call(p_name, (const Variant **)argp.ptr(), argc, ce); + if (ce.error != Variant::CallError::CALL_OK) { + String error = Variant::get_call_error_text(p_node, p_name, (const Variant **)argp.ptr(), argc, ce); + error = "RPC - " + error; + ERR_PRINTS(error); + } +} + +void MultiplayerAPI::_process_rset(Node *p_node, const StringName &p_name, int p_from, const uint8_t *p_packet, int p_packet_len, int p_offset) { + + if (!p_node->can_call_rset(p_name, p_from)) + return; + + ERR_FAIL_COND(p_offset >= p_packet_len); + + Variant value; + decode_variant(value, &p_packet[p_offset], p_packet_len - p_offset); + + bool valid; + + p_node->set(p_name, value, &valid); + if (!valid) { + String error = "Error setting remote property '" + String(p_name) + "', not found in object of type " + p_node->get_class(); + ERR_PRINTS(error); + } +} + +void MultiplayerAPI::_process_simplify_path(int p_from, const uint8_t *p_packet, int p_packet_len) { + + ERR_FAIL_COND(p_packet_len < 5); + int id = decode_uint32(&p_packet[1]); + + String paths; + paths.parse_utf8((const char *)&p_packet[5], p_packet_len - 5); + + NodePath path = paths; + + if (!path_get_cache.has(p_from)) { + path_get_cache[p_from] = PathGetCache(); + } + + PathGetCache::NodeInfo ni; + ni.path = path; + ni.instance = 0; + + path_get_cache[p_from].nodes[id] = ni; + + //send ack + + //encode path + CharString pname = String(path).utf8(); + int len = encode_cstring(pname.get_data(), NULL); + + Vector<uint8_t> packet; + + packet.resize(1 + len); + packet[0] = NETWORK_COMMAND_CONFIRM_PATH; + encode_cstring(pname.get_data(), &packet[1]); + + network_peer->set_transfer_mode(NetworkedMultiplayerPeer::TRANSFER_MODE_RELIABLE); + network_peer->set_target_peer(p_from); + network_peer->put_packet(packet.ptr(), packet.size()); +} + +void MultiplayerAPI::_process_confirm_path(int p_from, const uint8_t *p_packet, int p_packet_len) { + + String paths; + paths.parse_utf8((const char *)&p_packet[1], p_packet_len - 1); + + NodePath path = paths; + + PathSentCache *psc = path_send_cache.getptr(path); + ERR_FAIL_COND(!psc); + + Map<int, bool>::Element *E = psc->confirmed_peers.find(p_from); + ERR_FAIL_COND(!E); + E->get() = true; +} + +bool MultiplayerAPI::_send_confirm_path(NodePath p_path, PathSentCache *psc, int p_target) { + bool has_all_peers = true; + List<int> peers_to_add; //if one is missing, take note to add it + + for (Set<int>::Element *E = connected_peers.front(); E; E = E->next()) { + + if (p_target < 0 && E->get() == -p_target) + continue; //continue, excluded + + if (p_target > 0 && E->get() != p_target) + continue; //continue, not for this peer + + Map<int, bool>::Element *F = psc->confirmed_peers.find(E->get()); + + if (!F || F->get() == false) { + //path was not cached, or was cached but is unconfirmed + if (!F) { + //not cached at all, take note + peers_to_add.push_back(E->get()); + } + + has_all_peers = false; + } + } + + //those that need to be added, send a message for this + + for (List<int>::Element *E = peers_to_add.front(); E; E = E->next()) { + + //encode function name + CharString pname = String(p_path).utf8(); + int len = encode_cstring(pname.get_data(), NULL); + + Vector<uint8_t> packet; + + packet.resize(1 + 4 + len); + packet[0] = NETWORK_COMMAND_SIMPLIFY_PATH; + encode_uint32(psc->id, &packet[1]); + encode_cstring(pname.get_data(), &packet[5]); + + network_peer->set_target_peer(E->get()); //to all of you + network_peer->set_transfer_mode(NetworkedMultiplayerPeer::TRANSFER_MODE_RELIABLE); + network_peer->put_packet(packet.ptr(), packet.size()); + + psc->confirmed_peers.insert(E->get(), false); //insert into confirmed, but as false since it was not confirmed + } + + return has_all_peers; +} + +void MultiplayerAPI::_send_rpc(Node *p_from, int p_to, bool p_unreliable, bool p_set, const StringName &p_name, const Variant **p_arg, int p_argcount) { + + if (network_peer.is_null()) { + ERR_EXPLAIN("Attempt to remote call/set when networking is not active in SceneTree."); + ERR_FAIL(); + } + + if (network_peer->get_connection_status() == NetworkedMultiplayerPeer::CONNECTION_CONNECTING) { + ERR_EXPLAIN("Attempt to remote call/set when networking is not connected yet in SceneTree."); + ERR_FAIL(); + } + + if (network_peer->get_connection_status() == NetworkedMultiplayerPeer::CONNECTION_DISCONNECTED) { + ERR_EXPLAIN("Attempt to remote call/set when networking is disconnected."); + ERR_FAIL(); + } + + if (p_argcount > 255) { + ERR_EXPLAIN("Too many arguments >255."); + ERR_FAIL(); + } + + if (p_to != 0 && !connected_peers.has(ABS(p_to))) { + if (p_to == network_peer->get_unique_id()) { + ERR_EXPLAIN("Attempt to remote call/set yourself! unique ID: " + itos(network_peer->get_unique_id())); + } else { + ERR_EXPLAIN("Attempt to remote call unexisting ID: " + itos(p_to)); + } + + ERR_FAIL(); + } + + NodePath from_path = (root_node->get_path()).rel_path_to(p_from->get_path()); + ERR_FAIL_COND(from_path.is_empty()); + + //see if the path is cached + PathSentCache *psc = path_send_cache.getptr(from_path); + if (!psc) { + //path is not cached, create + path_send_cache[from_path] = PathSentCache(); + psc = path_send_cache.getptr(from_path); + psc->id = last_send_cache_id++; + } + + //create base packet, lots of hardcode because it must be tight + + int ofs = 0; + +#define MAKE_ROOM(m_amount) \ + if (packet_cache.size() < m_amount) packet_cache.resize(m_amount); + + //encode type + MAKE_ROOM(1); + packet_cache[0] = p_set ? NETWORK_COMMAND_REMOTE_SET : NETWORK_COMMAND_REMOTE_CALL; + ofs += 1; + + //encode ID + MAKE_ROOM(ofs + 4); + encode_uint32(psc->id, &(packet_cache[ofs])); + ofs += 4; + + //encode function name + CharString name = String(p_name).utf8(); + int len = encode_cstring(name.get_data(), NULL); + MAKE_ROOM(ofs + len); + encode_cstring(name.get_data(), &(packet_cache[ofs])); + ofs += len; + + if (p_set) { + //set argument + Error err = encode_variant(*p_arg[0], NULL, len); + ERR_FAIL_COND(err != OK); + MAKE_ROOM(ofs + len); + encode_variant(*p_arg[0], &(packet_cache[ofs]), len); + ofs += len; + + } else { + //call arguments + MAKE_ROOM(ofs + 1); + packet_cache[ofs] = p_argcount; + ofs += 1; + for (int i = 0; i < p_argcount; i++) { + Error err = encode_variant(*p_arg[i], NULL, len); + ERR_FAIL_COND(err != OK); + MAKE_ROOM(ofs + len); + encode_variant(*p_arg[i], &(packet_cache[ofs]), len); + ofs += len; + } + } + + //see if all peers have cached path (is so, call can be fast) + bool has_all_peers = _send_confirm_path(from_path, psc, p_to); + + //take chance and set transfer mode, since all send methods will use it + network_peer->set_transfer_mode(p_unreliable ? NetworkedMultiplayerPeer::TRANSFER_MODE_UNRELIABLE : NetworkedMultiplayerPeer::TRANSFER_MODE_RELIABLE); + + if (has_all_peers) { + + //they all have verified paths, so send fast + network_peer->set_target_peer(p_to); //to all of you + network_peer->put_packet(packet_cache.ptr(), ofs); //a message with love + } else { + //not all verified path, so send one by one + + //apend path at the end, since we will need it for some packets + CharString pname = String(from_path).utf8(); + int path_len = encode_cstring(pname.get_data(), NULL); + MAKE_ROOM(ofs + path_len); + encode_cstring(pname.get_data(), &(packet_cache[ofs])); + + for (Set<int>::Element *E = connected_peers.front(); E; E = E->next()) { + + if (p_to < 0 && E->get() == -p_to) + continue; //continue, excluded + + if (p_to > 0 && E->get() != p_to) + continue; //continue, not for this peer + + Map<int, bool>::Element *F = psc->confirmed_peers.find(E->get()); + ERR_CONTINUE(!F); //should never happen + + network_peer->set_target_peer(E->get()); //to this one specifically + + if (F->get() == true) { + //this one confirmed path, so use id + encode_uint32(psc->id, &(packet_cache[1])); + network_peer->put_packet(packet_cache.ptr(), ofs); + } else { + //this one did not confirm path yet, so use entire path (sorry!) + encode_uint32(0x80000000 | ofs, &(packet_cache[1])); //offset to path and flag + network_peer->put_packet(packet_cache.ptr(), ofs + path_len); + } + } + } +} + +void MultiplayerAPI::add_peer(int p_id) { + connected_peers.insert(p_id); + path_get_cache.insert(p_id, PathGetCache()); + emit_signal("network_peer_connected", p_id); +} + +void MultiplayerAPI::del_peer(int p_id) { + connected_peers.erase(p_id); + path_get_cache.erase(p_id); //I no longer need your cache, sorry + emit_signal("network_peer_disconnected", p_id); +} + +void MultiplayerAPI::connected_to_server() { + + emit_signal("connected_to_server"); +} + +void MultiplayerAPI::connection_failed() { + + emit_signal("connection_failed"); +} + +void MultiplayerAPI::server_disconnected() { + + emit_signal("server_disconnected"); +} + +bool _should_call_native(Node::RPCMode mode, bool is_master, bool &r_skip_rpc) { + + switch (mode) { + + case Node::RPC_MODE_DISABLED: { + //do nothing + } break; + case Node::RPC_MODE_REMOTE: { + //do nothing also, no need to call local + } break; + case Node::RPC_MODE_SYNC: { + //call it, sync always results in call + return true; + } break; + case Node::RPC_MODE_MASTER: { + if (is_master) + r_skip_rpc = true; //no other master so.. + return is_master; + } break; + case Node::RPC_MODE_SLAVE: { + return !is_master; + } break; + } + return false; +} + +bool _should_call_script(ScriptInstance::RPCMode mode, bool is_master, bool &r_skip_rpc) { + switch (mode) { + + case ScriptInstance::RPC_MODE_DISABLED: { + //do nothing + } break; + case ScriptInstance::RPC_MODE_REMOTE: { + //do nothing also, no need to call local + } break; + case ScriptInstance::RPC_MODE_SYNC: { + //call it, sync always results in call + return true; + } break; + case ScriptInstance::RPC_MODE_MASTER: { + if (is_master) + r_skip_rpc = true; //no other master so.. + return is_master; + } break; + case ScriptInstance::RPC_MODE_SLAVE: { + return !is_master; + } break; + } + return false; +} + +void MultiplayerAPI::rpcp(Node *p_node, int p_peer_id, bool p_unreliable, const StringName &p_method, const Variant **p_arg, int p_argcount) { + + ERR_FAIL_COND(!p_node->is_inside_tree()); + ERR_FAIL_COND(!network_peer.is_valid()); + + int node_id = network_peer->get_unique_id(); + bool skip_rpc = false; + bool call_local_native = false; + bool call_local_script = false; + bool is_master = p_node->is_network_master(); + + if (p_peer_id == 0 || p_peer_id == node_id || (p_peer_id < 0 && p_peer_id != -node_id)) { + //check that send mode can use local call + + const Map<StringName, Node::RPCMode>::Element *E = p_node->get_node_rpc_mode(p_method); + if (E) { + call_local_native = _should_call_native(E->get(), is_master, skip_rpc); + } + + if (call_local_native) { + // done below + } else if (p_node->get_script_instance()) { + //attempt with script + ScriptInstance::RPCMode rpc_mode = p_node->get_script_instance()->get_rpc_mode(p_method); + call_local_script = _should_call_script(rpc_mode, is_master, skip_rpc); + } + } + + if (!skip_rpc) { + _send_rpc(p_node, p_peer_id, p_unreliable, false, p_method, p_arg, p_argcount); + } + + if (call_local_native) { + Variant::CallError ce; + p_node->call(p_method, p_arg, p_argcount, ce); + if (ce.error != Variant::CallError::CALL_OK) { + String error = Variant::get_call_error_text(p_node, p_method, p_arg, p_argcount, ce); + error = "rpc() aborted in local call: - " + error; + ERR_PRINTS(error); + return; + } + } + + if (call_local_script) { + Variant::CallError ce; + ce.error = Variant::CallError::CALL_OK; + p_node->get_script_instance()->call(p_method, p_arg, p_argcount, ce); + if (ce.error != Variant::CallError::CALL_OK) { + String error = Variant::get_call_error_text(p_node, p_method, p_arg, p_argcount, ce); + error = "rpc() aborted in script local call: - " + error; + ERR_PRINTS(error); + return; + } + } +} + +void MultiplayerAPI::rsetp(Node *p_node, int p_peer_id, bool p_unreliable, const StringName &p_property, const Variant &p_value) { + + ERR_FAIL_COND(!p_node->is_inside_tree()); + ERR_FAIL_COND(!network_peer.is_valid()); + + int node_id = network_peer->get_unique_id(); + bool is_master = p_node->is_network_master(); + bool skip_rset = false; + + if (p_peer_id == 0 || p_peer_id == node_id || (p_peer_id < 0 && p_peer_id != -node_id)) { + //check that send mode can use local call + + bool set_local = false; + + const Map<StringName, Node::RPCMode>::Element *E = p_node->get_node_rset_mode(p_property); + if (E) { + + set_local = _should_call_native(E->get(), is_master, skip_rset); + } + + if (set_local) { + bool valid; + p_node->set(p_property, p_value, &valid); + + if (!valid) { + String error = "rset() aborted in local set, property not found: - " + String(p_property); + ERR_PRINTS(error); + return; + } + } else if (p_node->get_script_instance()) { + //attempt with script + ScriptInstance::RPCMode rpc_mode = p_node->get_script_instance()->get_rset_mode(p_property); + + set_local = _should_call_script(rpc_mode, is_master, skip_rset); + + if (set_local) { + + bool valid = p_node->get_script_instance()->set(p_property, p_value); + + if (!valid) { + String error = "rset() aborted in local script set, property not found: - " + String(p_property); + ERR_PRINTS(error); + return; + } + } + } + } + + if (skip_rset) + return; + + const Variant *vptr = &p_value; + + _send_rpc(p_node, p_peer_id, p_unreliable, true, p_property, &vptr, 1); +} + +int MultiplayerAPI::get_network_unique_id() const { + + ERR_FAIL_COND_V(!network_peer.is_valid(), 0); + return network_peer->get_unique_id(); +} + +bool MultiplayerAPI::is_network_server() const { + + ERR_FAIL_COND_V(!network_peer.is_valid(), false); + return network_peer->is_server(); +} + +void MultiplayerAPI::set_refuse_new_network_connections(bool p_refuse) { + + ERR_FAIL_COND(!network_peer.is_valid()); + network_peer->set_refuse_new_connections(p_refuse); +} + +bool MultiplayerAPI::is_refusing_new_network_connections() const { + + ERR_FAIL_COND_V(!network_peer.is_valid(), false); + return network_peer->is_refusing_new_connections(); +} + +Vector<int> MultiplayerAPI::get_network_connected_peers() const { + + ERR_FAIL_COND_V(!network_peer.is_valid(), Vector<int>()); + + Vector<int> ret; + for (Set<int>::Element *E = connected_peers.front(); E; E = E->next()) { + ret.push_back(E->get()); + } + + return ret; +} + +void MultiplayerAPI::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_root_node", "node"), &MultiplayerAPI::set_root_node); + ClassDB::bind_method(D_METHOD("has_network_peer"), &MultiplayerAPI::has_network_peer); + ClassDB::bind_method(D_METHOD("get_network_peer"), &MultiplayerAPI::get_network_peer); + ClassDB::bind_method(D_METHOD("get_network_unique_id"), &MultiplayerAPI::get_network_unique_id); + ClassDB::bind_method(D_METHOD("is_network_server"), &MultiplayerAPI::is_network_server); + ClassDB::bind_method(D_METHOD("get_rpc_sender_id"), &MultiplayerAPI::get_rpc_sender_id); + ClassDB::bind_method(D_METHOD("add_peer", "id"), &MultiplayerAPI::add_peer); + ClassDB::bind_method(D_METHOD("del_peer", "id"), &MultiplayerAPI::del_peer); + ClassDB::bind_method(D_METHOD("set_network_peer", "peer"), &MultiplayerAPI::set_network_peer); + ClassDB::bind_method(D_METHOD("poll"), &MultiplayerAPI::poll); + ClassDB::bind_method(D_METHOD("clear"), &MultiplayerAPI::clear); + + ClassDB::bind_method(D_METHOD("connected_to_server"), &MultiplayerAPI::connected_to_server); + ClassDB::bind_method(D_METHOD("connection_failed"), &MultiplayerAPI::connection_failed); + ClassDB::bind_method(D_METHOD("server_disconnected"), &MultiplayerAPI::server_disconnected); + ClassDB::bind_method(D_METHOD("get_network_connected_peers"), &MultiplayerAPI::get_network_connected_peers); + ClassDB::bind_method(D_METHOD("set_refuse_new_network_connections", "refuse"), &MultiplayerAPI::set_refuse_new_network_connections); + ClassDB::bind_method(D_METHOD("is_refusing_new_network_connections"), &MultiplayerAPI::is_refusing_new_network_connections); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "refuse_new_network_connections"), "set_refuse_new_network_connections", "is_refusing_new_network_connections"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "network_peer", PROPERTY_HINT_RESOURCE_TYPE, "NetworkedMultiplayerPeer", 0), "set_network_peer", "get_network_peer"); + + ADD_SIGNAL(MethodInfo("network_peer_connected", PropertyInfo(Variant::INT, "id"))); + ADD_SIGNAL(MethodInfo("network_peer_disconnected", PropertyInfo(Variant::INT, "id"))); + ADD_SIGNAL(MethodInfo("connected_to_server")); + ADD_SIGNAL(MethodInfo("connection_failed")); + ADD_SIGNAL(MethodInfo("server_disconnected")); +} + +MultiplayerAPI::MultiplayerAPI() { + clear(); +} + +MultiplayerAPI::~MultiplayerAPI() { + clear(); +} diff --git a/core/io/multiplayer_api.h b/core/io/multiplayer_api.h new file mode 100644 index 0000000000..e7c6ffbea6 --- /dev/null +++ b/core/io/multiplayer_api.h @@ -0,0 +1,87 @@ +#ifndef MULTIPLAYER_PROTOCOL_H +#define MULTIPLAYER_PROTOCOL_H + +#include "core/io/networked_multiplayer_peer.h" +#include "core/reference.h" + +class MultiplayerAPI : public Reference { + + GDCLASS(MultiplayerAPI, Reference); + +private: + //path sent caches + struct PathSentCache { + Map<int, bool> confirmed_peers; + int id; + }; + + //path get caches + struct PathGetCache { + struct NodeInfo { + NodePath path; + ObjectID instance; + }; + + Map<int, NodeInfo> nodes; + }; + + Ref<NetworkedMultiplayerPeer> network_peer; + int rpc_sender_id; + Set<int> connected_peers; + HashMap<NodePath, PathSentCache> path_send_cache; + Map<int, PathGetCache> path_get_cache; + int last_send_cache_id; + Vector<uint8_t> packet_cache; + Node *root_node; + +protected: + static void _bind_methods(); + + void _process_packet(int p_from, const uint8_t *p_packet, int p_packet_len); + void _process_simplify_path(int p_from, const uint8_t *p_packet, int p_packet_len); + void _process_confirm_path(int p_from, const uint8_t *p_packet, int p_packet_len); + Node *_process_get_node(int p_from, const uint8_t *p_packet, int p_packet_len); + void _process_rpc(Node *p_node, const StringName &p_name, int p_from, const uint8_t *p_packet, int p_packet_len, int p_offset); + void _process_rset(Node *p_node, const StringName &p_name, int p_from, const uint8_t *p_packet, int p_packet_len, int p_offset); + + void _send_rpc(Node *p_from, int p_to, bool p_unreliable, bool p_set, const StringName &p_name, const Variant **p_arg, int p_argcount); + bool _send_confirm_path(NodePath p_path, PathSentCache *psc, int p_from); + +public: + enum NetworkCommands { + NETWORK_COMMAND_REMOTE_CALL, + NETWORK_COMMAND_REMOTE_SET, + NETWORK_COMMAND_SIMPLIFY_PATH, + NETWORK_COMMAND_CONFIRM_PATH, + }; + + void poll(); + void clear(); + void set_root_node(Node *p_node); + void set_network_peer(const Ref<NetworkedMultiplayerPeer> &p_peer); + Ref<NetworkedMultiplayerPeer> get_network_peer() const; + + // Called by Node.rpc + void rpcp(Node *p_node, int p_peer_id, bool p_unreliable, const StringName &p_method, const Variant **p_arg, int p_argcount); + // Called by Node.rset + void rsetp(Node *p_node, int p_peer_id, bool p_unreliable, const StringName &p_property, const Variant &p_value); + + void add_peer(int p_id); + void del_peer(int p_id); + void connected_to_server(); + void connection_failed(); + void server_disconnected(); + + bool has_network_peer() const { return network_peer.is_valid(); } + Vector<int> get_network_connected_peers() const; + int get_rpc_sender_id() const { return rpc_sender_id; } + int get_network_unique_id() const; + bool is_network_server() const; + void set_refuse_new_network_connections(bool p_refuse); + bool is_refusing_new_network_connections() const; + + MultiplayerAPI(); + ~MultiplayerAPI(); +}; + +#endif // MULTIPLAYER_PROTOCOL_H diff --git a/core/io/networked_multiplayer_peer.cpp b/core/io/networked_multiplayer_peer.cpp index 95a2048b09..6354eef8b5 100644 --- a/core/io/networked_multiplayer_peer.cpp +++ b/core/io/networked_multiplayer_peer.cpp @@ -27,11 +27,13 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #include "networked_multiplayer_peer.h" void NetworkedMultiplayerPeer::_bind_methods() { ClassDB::bind_method(D_METHOD("set_transfer_mode", "mode"), &NetworkedMultiplayerPeer::set_transfer_mode); + ClassDB::bind_method(D_METHOD("get_transfer_mode"), &NetworkedMultiplayerPeer::get_transfer_mode); ClassDB::bind_method(D_METHOD("set_target_peer", "id"), &NetworkedMultiplayerPeer::set_target_peer); ClassDB::bind_method(D_METHOD("get_packet_peer"), &NetworkedMultiplayerPeer::get_packet_peer); @@ -44,6 +46,9 @@ void NetworkedMultiplayerPeer::_bind_methods() { ClassDB::bind_method(D_METHOD("set_refuse_new_connections", "enable"), &NetworkedMultiplayerPeer::set_refuse_new_connections); ClassDB::bind_method(D_METHOD("is_refusing_new_connections"), &NetworkedMultiplayerPeer::is_refusing_new_connections); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "refuse_new_connections"), "set_refuse_new_connections", "is_refusing_new_connections"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "transfer_mode", PROPERTY_HINT_ENUM, "Unreliable,Unreliable Ordered,Reliable"), "set_transfer_mode", "get_transfer_mode"); + BIND_ENUM_CONSTANT(TRANSFER_MODE_UNRELIABLE); BIND_ENUM_CONSTANT(TRANSFER_MODE_UNRELIABLE_ORDERED); BIND_ENUM_CONSTANT(TRANSFER_MODE_RELIABLE); diff --git a/core/io/networked_multiplayer_peer.h b/core/io/networked_multiplayer_peer.h index 3094aa8b99..66089c27b9 100644 --- a/core/io/networked_multiplayer_peer.h +++ b/core/io/networked_multiplayer_peer.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef NETWORKED_MULTIPLAYER_PEER_H #define NETWORKED_MULTIPLAYER_PEER_H @@ -57,6 +58,7 @@ public: }; virtual void set_transfer_mode(TransferMode p_mode) = 0; + virtual TransferMode get_transfer_mode() const = 0; virtual void set_target_peer(int p_peer_id) = 0; virtual int get_packet_peer() const = 0; diff --git a/core/io/packet_peer.cpp b/core/io/packet_peer.cpp index 7e09036171..b777a9f960 100644 --- a/core/io/packet_peer.cpp +++ b/core/io/packet_peer.cpp @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #include "packet_peer.h" #include "io/marshalls.h" @@ -140,6 +141,8 @@ void PacketPeer::_bind_methods() { ClassDB::bind_method(D_METHOD("set_allow_object_decoding", "enable"), &PacketPeer::set_allow_object_decoding); ClassDB::bind_method(D_METHOD("is_object_decoding_allowed"), &PacketPeer::is_object_decoding_allowed); + + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "allow_object_decoding"), "set_allow_object_decoding", "is_object_decoding_allowed"); }; /***************/ @@ -152,11 +155,16 @@ void PacketPeerStream::_set_stream_peer(REF p_peer) { void PacketPeerStream::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_stream_peer", "peer"), &PacketPeerStream::_set_stream_peer); + ClassDB::bind_method(D_METHOD("set_stream_peer", "peer"), &PacketPeerStream::set_stream_peer); + ClassDB::bind_method(D_METHOD("get_stream_peer"), &PacketPeerStream::get_stream_peer); ClassDB::bind_method(D_METHOD("set_input_buffer_max_size", "max_size_bytes"), &PacketPeerStream::set_input_buffer_max_size); ClassDB::bind_method(D_METHOD("set_output_buffer_max_size", "max_size_bytes"), &PacketPeerStream::set_output_buffer_max_size); ClassDB::bind_method(D_METHOD("get_input_buffer_max_size"), &PacketPeerStream::get_input_buffer_max_size); ClassDB::bind_method(D_METHOD("get_output_buffer_max_size"), &PacketPeerStream::get_output_buffer_max_size); + + ADD_PROPERTY(PropertyInfo(Variant::INT, "input_buffer_max_size"), "set_input_buffer_max_size", "get_input_buffer_max_size"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "output_buffer_max_size"), "set_output_buffer_max_size", "get_output_buffer_max_size"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "stream_peer", PROPERTY_HINT_RESOURCE_TYPE, "StreamPeer", 0), "set_stream_peer", "get_stream_peer"); } Error PacketPeerStream::_poll_buffer() const { @@ -263,6 +271,11 @@ void PacketPeerStream::set_stream_peer(const Ref<StreamPeer> &p_peer) { peer = p_peer; } +Ref<StreamPeer> PacketPeerStream::get_stream_peer() const { + + return peer; +} + void PacketPeerStream::set_input_buffer_max_size(int p_max_size) { //warning may lose packets diff --git a/core/io/packet_peer.h b/core/io/packet_peer.h index 3e9373a18d..b10152e96b 100644 --- a/core/io/packet_peer.h +++ b/core/io/packet_peer.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef PACKET_PEER_H #define PACKET_PEER_H @@ -97,6 +98,7 @@ public: virtual int get_max_packet_size() const; void set_stream_peer(const Ref<StreamPeer> &p_peer); + Ref<StreamPeer> get_stream_peer() const; void set_input_buffer_max_size(int p_max_size); int get_input_buffer_max_size() const; void set_output_buffer_max_size(int p_max_size); diff --git a/core/io/packet_peer_udp.cpp b/core/io/packet_peer_udp.cpp index 708c7d456c..bfbea15582 100644 --- a/core/io/packet_peer_udp.cpp +++ b/core/io/packet_peer_udp.cpp @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #include "packet_peer_udp.h" #include "io/ip.h" diff --git a/core/io/packet_peer_udp.h b/core/io/packet_peer_udp.h index d0a1bcf195..035f4ad1c9 100644 --- a/core/io/packet_peer_udp.h +++ b/core/io/packet_peer_udp.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef PACKET_PEER_UDP_H #define PACKET_PEER_UDP_H diff --git a/core/io/pck_packer.cpp b/core/io/pck_packer.cpp index 13a36813ca..b6377662de 100644 --- a/core/io/pck_packer.cpp +++ b/core/io/pck_packer.cpp @@ -27,9 +27,10 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "pck_packer.h" +#include "pck_packer.h" #include "core/os/file_access.h" +#include "version.h" static uint64_t _align(uint64_t p_n, int p_alignment) { @@ -69,9 +70,9 @@ Error PCKPacker::pck_start(const String &p_file, int p_alignment) { alignment = p_alignment; file->store_32(0x43504447); // MAGIC - file->store_32(0); // # version - file->store_32(0); // # major - file->store_32(0); // # minor + file->store_32(1); // # version + file->store_32(VERSION_MAJOR); // # major + file->store_32(VERSION_MINOR); // # minor file->store_32(0); // # revision for (int i = 0; i < 16; i++) { diff --git a/core/io/pck_packer.h b/core/io/pck_packer.h index e725155ed2..4fcf9a8822 100644 --- a/core/io/pck_packer.h +++ b/core/io/pck_packer.h @@ -27,6 +27,10 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + +#ifndef PCK_PACKER_H +#define PCK_PACKER_H + #include "core/reference.h" class FileAccess; @@ -57,3 +61,5 @@ public: PCKPacker(); ~PCKPacker(); }; + +#endif // PCK_PACKER_H diff --git a/core/io/resource_format_binary.cpp b/core/io/resource_format_binary.cpp index d652720ad0..0c626c197b 100644 --- a/core/io/resource_format_binary.cpp +++ b/core/io/resource_format_binary.cpp @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #include "resource_format_binary.h" #include "core/image.h" @@ -1123,7 +1124,7 @@ Error ResourceFormatLoaderBinary::rename_dependencies(const String &p_path, cons DirAccess *da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); da->remove(p_path + ".depren"); memdelete(da); - //fuck it, use the old approach; + //use the old approach WARN_PRINT(("This file is old, so it can't refactor dependencies, opening and resaving: " + p_path).utf8().get_data()); @@ -1161,9 +1162,11 @@ Error ResourceFormatLoaderBinary::rename_dependencies(const String &p_path, cons ERR_FAIL_V(ERR_FILE_UNRECOGNIZED); } - fw->store_32(VERSION_MAJOR); //current version - fw->store_32(VERSION_MINOR); - fw->store_32(FORMAT_VERSION); + // Since we're not actually converting the file contents, leave the version + // numbers in the file untouched. + fw->store_32(ver_major); + fw->store_32(ver_minor); + fw->store_32(ver_format); save_ustring(fw, get_ustring(f)); //type diff --git a/core/io/resource_format_binary.h b/core/io/resource_format_binary.h index 0329d02981..021f7f6a2f 100644 --- a/core/io/resource_format_binary.h +++ b/core/io/resource_format_binary.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef RESOURCE_FORMAT_BINARY_H #define RESOURCE_FORMAT_BINARY_H diff --git a/core/io/resource_import.cpp b/core/io/resource_import.cpp index 8d21f41eab..cfe6655504 100644 --- a/core/io/resource_import.cpp +++ b/core/io/resource_import.cpp @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #include "resource_import.h" #include "os/os.h" @@ -137,9 +138,9 @@ void ResourceFormatImporter::get_recognized_extensions(List<String> *p_extension Set<String> found; - for (Set<Ref<ResourceImporter> >::Element *E = importers.front(); E; E = E->next()) { + for (int i = 0; i < importers.size(); i++) { List<String> local_exts; - E->get()->get_recognized_extensions(&local_exts); + importers[i]->get_recognized_extensions(&local_exts); for (List<String>::Element *F = local_exts.front(); F; F = F->next()) { if (!found.has(F->get())) { p_extensions->push_back(F->get()); @@ -157,8 +158,8 @@ void ResourceFormatImporter::get_recognized_extensions_for_type(const String &p_ Set<String> found; - for (Set<Ref<ResourceImporter> >::Element *E = importers.front(); E; E = E->next()) { - String res_type = E->get()->get_resource_type(); + for (int i = 0; i < importers.size(); i++) { + String res_type = importers[i]->get_resource_type(); if (res_type == String()) continue; @@ -166,7 +167,7 @@ void ResourceFormatImporter::get_recognized_extensions_for_type(const String &p_ continue; List<String> local_exts; - E->get()->get_recognized_extensions(&local_exts); + importers[i]->get_recognized_extensions(&local_exts); for (List<String>::Element *F = local_exts.front(); F; F = F->next()) { if (!found.has(F->get())) { p_extensions->push_back(F->get()); @@ -211,9 +212,9 @@ int ResourceFormatImporter::get_import_order(const String &p_path) const { bool ResourceFormatImporter::handles_type(const String &p_type) const { - for (Set<Ref<ResourceImporter> >::Element *E = importers.front(); E; E = E->next()) { + for (int i = 0; i < importers.size(); i++) { - String res_type = E->get()->get_resource_type(); + String res_type = importers[i]->get_resource_type(); if (res_type == String()) continue; if (ClassDB::is_parent_class(res_type, p_type)) @@ -318,9 +319,9 @@ void ResourceFormatImporter::get_dependencies(const String &p_path, List<String> Ref<ResourceImporter> ResourceFormatImporter::get_importer_by_name(const String &p_name) const { - for (Set<Ref<ResourceImporter> >::Element *E = importers.front(); E; E = E->next()) { - if (E->get()->get_importer_name() == p_name) { - return E->get(); + for (int i = 0; i < importers.size(); i++) { + if (importers[i]->get_importer_name() == p_name) { + return importers[i]; } } @@ -329,12 +330,12 @@ Ref<ResourceImporter> ResourceFormatImporter::get_importer_by_name(const String void ResourceFormatImporter::get_importers_for_extension(const String &p_extension, List<Ref<ResourceImporter> > *r_importers) { - for (Set<Ref<ResourceImporter> >::Element *E = importers.front(); E; E = E->next()) { + for (int i = 0; i < importers.size(); i++) { List<String> local_exts; - E->get()->get_recognized_extensions(&local_exts); + importers[i]->get_recognized_extensions(&local_exts); for (List<String>::Element *F = local_exts.front(); F; F = F->next()) { if (p_extension.to_lower() == F->get()) { - r_importers->push_back(E->get()); + r_importers->push_back(importers[i]); } } } @@ -345,14 +346,14 @@ Ref<ResourceImporter> ResourceFormatImporter::get_importer_by_extension(const St Ref<ResourceImporter> importer; float priority = 0; - for (Set<Ref<ResourceImporter> >::Element *E = importers.front(); E; E = E->next()) { + for (int i = 0; i < importers.size(); i++) { List<String> local_exts; - E->get()->get_recognized_extensions(&local_exts); + importers[i]->get_recognized_extensions(&local_exts); for (List<String>::Element *F = local_exts.front(); F; F = F->next()) { - if (p_extension.to_lower() == F->get() && E->get()->get_priority() > priority) { - importer = E->get(); - priority = E->get()->get_priority(); + if (p_extension.to_lower() == F->get() && importers[i]->get_priority() > priority) { + importer = importers[i]; + priority = importers[i]->get_priority(); } } } diff --git a/core/io/resource_import.h b/core/io/resource_import.h index 3583584092..80e0743eda 100644 --- a/core/io/resource_import.h +++ b/core/io/resource_import.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef RESOURCE_IMPORT_H #define RESOURCE_IMPORT_H @@ -45,7 +46,7 @@ class ResourceFormatImporter : public ResourceFormatLoader { static ResourceFormatImporter *singleton; - Set<Ref<ResourceImporter> > importers; + Vector<Ref<ResourceImporter> > importers; public: static ResourceFormatImporter *get_singleton() { return singleton; } @@ -64,7 +65,7 @@ public: String get_internal_resource_path(const String &p_path) const; void get_internal_resource_path_list(const String &p_path, List<String> *r_paths); - void add_importer(const Ref<ResourceImporter> &p_importer) { importers.insert(p_importer); } + void add_importer(const Ref<ResourceImporter> &p_importer) { importers.push_back(p_importer); } void remove_importer(const Ref<ResourceImporter> &p_importer) { importers.erase(p_importer); } Ref<ResourceImporter> get_importer_by_name(const String &p_name) const; Ref<ResourceImporter> get_importer_by_extension(const String &p_extension) const; diff --git a/core/io/resource_loader.cpp b/core/io/resource_loader.cpp index 527e6997e1..1351030d1e 100644 --- a/core/io/resource_loader.cpp +++ b/core/io/resource_loader.cpp @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #include "resource_loader.h" #include "io/resource_import.h" #include "os/file_access.h" @@ -201,7 +202,8 @@ RES ResourceLoader::load(const String &p_path, const String &p_type_hint, bool p if (OS::get_singleton()->is_stdout_verbose()) print_line("load resource: " + local_path + " (cached)"); - + if (r_error) + *r_error = OK; return RES(ResourceCache::get(local_path)); } diff --git a/core/io/resource_loader.h b/core/io/resource_loader.h index fad768778b..9be82abb42 100644 --- a/core/io/resource_loader.h +++ b/core/io/resource_loader.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef RESOURCE_LOADER_H #define RESOURCE_LOADER_H diff --git a/core/io/resource_saver.cpp b/core/io/resource_saver.cpp index 8a0ccd90ce..3dcd94880a 100644 --- a/core/io/resource_saver.cpp +++ b/core/io/resource_saver.cpp @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #include "resource_saver.h" #include "os/file_access.h" #include "project_settings.h" @@ -55,7 +56,7 @@ Error ResourceSaver::save(const String &p_path, const RES &p_resource, uint32_t for (List<String>::Element *E = extensions.front(); E; E = E->next()) { - if (E->get().nocasecmp_to(extension.get_extension()) == 0) + if (E->get().nocasecmp_to(extension) == 0) recognized = true; } diff --git a/core/io/resource_saver.h b/core/io/resource_saver.h index fd4d563e4a..396f37d414 100644 --- a/core/io/resource_saver.h +++ b/core/io/resource_saver.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef RESOURCE_SAVER_H #define RESOURCE_SAVER_H diff --git a/core/io/stream_peer.cpp b/core/io/stream_peer.cpp index b0fd229ac0..927b9f6366 100644 --- a/core/io/stream_peer.cpp +++ b/core/io/stream_peer.cpp @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #include "stream_peer.h" #include "io/marshalls.h" @@ -309,7 +310,7 @@ float StreamPeer::get_float() { return decode_float(buf); } -float StreamPeer::get_double() { +double StreamPeer::get_double() { uint8_t buf[8]; get_data(buf, 8); @@ -374,18 +375,18 @@ void StreamPeer::_bind_methods() { ClassDB::bind_method(D_METHOD("set_big_endian", "enable"), &StreamPeer::set_big_endian); ClassDB::bind_method(D_METHOD("is_big_endian_enabled"), &StreamPeer::is_big_endian_enabled); - ClassDB::bind_method(D_METHOD("put_8", "val"), &StreamPeer::put_8); - ClassDB::bind_method(D_METHOD("put_u8", "val"), &StreamPeer::put_u8); - ClassDB::bind_method(D_METHOD("put_16", "val"), &StreamPeer::put_16); - ClassDB::bind_method(D_METHOD("put_u16", "val"), &StreamPeer::put_u16); - ClassDB::bind_method(D_METHOD("put_32", "val"), &StreamPeer::put_32); - ClassDB::bind_method(D_METHOD("put_u32", "val"), &StreamPeer::put_u32); - ClassDB::bind_method(D_METHOD("put_64", "val"), &StreamPeer::put_64); - ClassDB::bind_method(D_METHOD("put_u64", "val"), &StreamPeer::put_u64); - ClassDB::bind_method(D_METHOD("put_float", "val"), &StreamPeer::put_float); - ClassDB::bind_method(D_METHOD("put_double", "val"), &StreamPeer::put_double); - ClassDB::bind_method(D_METHOD("put_utf8_string", "val"), &StreamPeer::put_utf8_string); - ClassDB::bind_method(D_METHOD("put_var", "val"), &StreamPeer::put_var); + ClassDB::bind_method(D_METHOD("put_8", "value"), &StreamPeer::put_8); + ClassDB::bind_method(D_METHOD("put_u8", "value"), &StreamPeer::put_u8); + ClassDB::bind_method(D_METHOD("put_16", "value"), &StreamPeer::put_16); + ClassDB::bind_method(D_METHOD("put_u16", "value"), &StreamPeer::put_u16); + ClassDB::bind_method(D_METHOD("put_32", "value"), &StreamPeer::put_32); + ClassDB::bind_method(D_METHOD("put_u32", "value"), &StreamPeer::put_u32); + ClassDB::bind_method(D_METHOD("put_64", "value"), &StreamPeer::put_64); + ClassDB::bind_method(D_METHOD("put_u64", "value"), &StreamPeer::put_u64); + ClassDB::bind_method(D_METHOD("put_float", "value"), &StreamPeer::put_float); + ClassDB::bind_method(D_METHOD("put_double", "value"), &StreamPeer::put_double); + ClassDB::bind_method(D_METHOD("put_utf8_string", "value"), &StreamPeer::put_utf8_string); + ClassDB::bind_method(D_METHOD("put_var", "value"), &StreamPeer::put_var); ClassDB::bind_method(D_METHOD("get_8"), &StreamPeer::get_8); ClassDB::bind_method(D_METHOD("get_u8"), &StreamPeer::get_u8); @@ -400,6 +401,8 @@ void StreamPeer::_bind_methods() { ClassDB::bind_method(D_METHOD("get_string", "bytes"), &StreamPeer::get_string); ClassDB::bind_method(D_METHOD("get_utf8_string", "bytes"), &StreamPeer::get_utf8_string); ClassDB::bind_method(D_METHOD("get_var"), &StreamPeer::get_var); + + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "big_endian"), "set_big_endian", "is_big_endian_enabled"); } //////////////////////////////// @@ -413,6 +416,8 @@ void StreamPeerBuffer::_bind_methods() { ClassDB::bind_method(D_METHOD("get_data_array"), &StreamPeerBuffer::get_data_array); ClassDB::bind_method(D_METHOD("clear"), &StreamPeerBuffer::clear); ClassDB::bind_method(D_METHOD("duplicate"), &StreamPeerBuffer::duplicate); + + ADD_PROPERTY(PropertyInfo(Variant::POOL_BYTE_ARRAY, "data_array"), "set_data_array", "get_data_array"); } Error StreamPeerBuffer::put_data(const uint8_t *p_data, int p_bytes) { diff --git a/core/io/stream_peer.h b/core/io/stream_peer.h index 212bff0e3e..605b0a7980 100644 --- a/core/io/stream_peer.h +++ b/core/io/stream_peer.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef STREAM_PEER_H #define STREAM_PEER_H @@ -82,7 +83,7 @@ public: uint64_t get_u64(); int64_t get_64(); float get_float(); - float get_double(); + double get_double(); String get_string(int p_bytes); String get_utf8_string(int p_bytes); Variant get_var(); diff --git a/core/io/stream_peer_ssl.cpp b/core/io/stream_peer_ssl.cpp index f92b57a044..012ba78c6d 100644 --- a/core/io/stream_peer_ssl.cpp +++ b/core/io/stream_peer_ssl.cpp @@ -27,7 +27,10 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #include "stream_peer_ssl.h" +#include "os/file_access.h" +#include "project_settings.h" StreamPeerSSL *(*StreamPeerSSL::_create)() = NULL; @@ -49,8 +52,38 @@ bool StreamPeerSSL::is_available() { return available; } +PoolByteArray StreamPeerSSL::get_project_cert_array() { + + PoolByteArray out; + String certs_path = GLOBAL_DEF("network/ssl/certificates", ""); + ProjectSettings::get_singleton()->set_custom_property_info("network/ssl/certificates", PropertyInfo(Variant::STRING, "network/ssl/certificates", PROPERTY_HINT_FILE, "*.crt")); + + if (certs_path != "") { + + FileAccess *f = FileAccess::open(certs_path, FileAccess::READ); + if (f) { + int flen = f->get_len(); + out.resize(flen + 1); + { + PoolByteArray::Write w = out.write(); + f->get_buffer(w.ptr(), flen); + w[flen] = 0; //end f string + } + + memdelete(f); + +#ifdef DEBUG_ENABLED + print_line("Loaded certs from '" + certs_path); +#endif + } + } + + return out; +} + void StreamPeerSSL::_bind_methods() { + ClassDB::bind_method(D_METHOD("poll"), &StreamPeerSSL::poll); ClassDB::bind_method(D_METHOD("accept_stream", "stream"), &StreamPeerSSL::accept_stream); ClassDB::bind_method(D_METHOD("connect_to_stream", "stream", "validate_certs", "for_hostname"), &StreamPeerSSL::connect_to_stream, DEFVAL(false), DEFVAL(String())); ClassDB::bind_method(D_METHOD("get_status"), &StreamPeerSSL::get_status); diff --git a/core/io/stream_peer_ssl.h b/core/io/stream_peer_ssl.h index bb4d2edced..77301a7c87 100644 --- a/core/io/stream_peer_ssl.h +++ b/core/io/stream_peer_ssl.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef STREAM_PEER_SSL_H #define STREAM_PEER_SSL_H @@ -56,6 +57,7 @@ public: STATUS_ERROR_HOSTNAME_MISMATCH }; + virtual void poll() = 0; virtual Error accept_stream(Ref<StreamPeer> p_base) = 0; virtual Error connect_to_stream(Ref<StreamPeer> p_base, bool p_validate_certs = false, const String &p_for_hostname = String()) = 0; virtual Status get_status() const = 0; @@ -64,6 +66,7 @@ public: static StreamPeerSSL *create(); + static PoolByteArray get_project_cert_array(); static void load_certs_from_memory(const PoolByteArray &p_memory); static bool is_available(); diff --git a/core/io/stream_peer_tcp.cpp b/core/io/stream_peer_tcp.cpp index 0524a35908..5d008904ff 100644 --- a/core/io/stream_peer_tcp.cpp +++ b/core/io/stream_peer_tcp.cpp @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #include "stream_peer_tcp.h" StreamPeerTCP *(*StreamPeerTCP::_create)() = NULL; @@ -54,6 +55,7 @@ void StreamPeerTCP::_bind_methods() { ClassDB::bind_method(D_METHOD("get_connected_host"), &StreamPeerTCP::get_connected_host); ClassDB::bind_method(D_METHOD("get_connected_port"), &StreamPeerTCP::get_connected_port); ClassDB::bind_method(D_METHOD("disconnect_from_host"), &StreamPeerTCP::disconnect_from_host); + ClassDB::bind_method(D_METHOD("set_no_delay", "enabled"), &StreamPeerTCP::set_no_delay); BIND_ENUM_CONSTANT(STATUS_NONE); BIND_ENUM_CONSTANT(STATUS_CONNECTING); diff --git a/core/io/stream_peer_tcp.h b/core/io/stream_peer_tcp.h index 9a14f57c28..8a16d820f2 100644 --- a/core/io/stream_peer_tcp.h +++ b/core/io/stream_peer_tcp.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef STREAM_PEER_TCP_H #define STREAM_PEER_TCP_H @@ -64,7 +65,7 @@ public: virtual void disconnect_from_host() = 0; virtual IP_Address get_connected_host() const = 0; virtual uint16_t get_connected_port() const = 0; - virtual void set_nodelay(bool p_enabled) = 0; + virtual void set_no_delay(bool p_enabled) = 0; static Ref<StreamPeerTCP> create_ref(); static StreamPeerTCP *create(); diff --git a/core/io/tcp_server.cpp b/core/io/tcp_server.cpp index 5d33cd6f15..5916d58390 100644 --- a/core/io/tcp_server.cpp +++ b/core/io/tcp_server.cpp @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #include "tcp_server.h" TCP_Server *(*TCP_Server::_create)() = NULL; diff --git a/core/io/tcp_server.h b/core/io/tcp_server.h index 28c80f76f7..a250e8b249 100644 --- a/core/io/tcp_server.h +++ b/core/io/tcp_server.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef TCP_SERVER_H #define TCP_SERVER_H diff --git a/core/io/translation_loader_po.cpp b/core/io/translation_loader_po.cpp index 0f62dbeb94..e01e2a84c5 100644 --- a/core/io/translation_loader_po.cpp +++ b/core/io/translation_loader_po.cpp @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #include "translation_loader_po.h" #include "os/file_access.h" #include "translation.h" diff --git a/core/io/translation_loader_po.h b/core/io/translation_loader_po.h index 82a2da103f..33cf9bd8b4 100644 --- a/core/io/translation_loader_po.h +++ b/core/io/translation_loader_po.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef TRANSLATION_LOADER_PO_H #define TRANSLATION_LOADER_PO_H diff --git a/core/io/xml_parser.cpp b/core/io/xml_parser.cpp index a88150fa36..33c9b56d5a 100644 --- a/core/io/xml_parser.cpp +++ b/core/io/xml_parser.cpp @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #include "xml_parser.h" #include "print_string.h" //#define DEBUG_XML diff --git a/core/io/xml_parser.h b/core/io/xml_parser.h index 62d2d2bc94..297b57ffdc 100644 --- a/core/io/xml_parser.h +++ b/core/io/xml_parser.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef XML_PARSER_H #define XML_PARSER_H diff --git a/core/io/zip_io.h b/core/io/zip_io.h index d3c1d1fc57..3a7fdb0302 100644 --- a/core/io/zip_io.h +++ b/core/io/zip_io.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef ZIP_IO_H #define ZIP_IO_H diff --git a/core/list.h b/core/list.h index 0c748aeb85..f977df4634 100644 --- a/core/list.h +++ b/core/list.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef GLOBALS_LIST_H #define GLOBALS_LIST_H @@ -387,7 +388,7 @@ public: }; /** - * return wether the list is empty + * return whether the list is empty */ _FORCE_INLINE_ bool empty() const { diff --git a/core/make_binders.py b/core/make_binders.py index 6f42c6e8eb..6a7602cd5d 100644 --- a/core/make_binders.py +++ b/core/make_binders.py @@ -244,7 +244,7 @@ def make_version(template, nargs, argmax, const, ret): def run(target, source, env): - versions = 11 + versions = 13 versions_ext = 6 text = "" text_ext = "" @@ -265,10 +265,8 @@ def run(target, source, env): else: text += t - f = open(target[0].path, "w") - f.write(text) - f.close() + with open(target[0].path, "w") as f: + f.write(text) - f = open(target[1].path, "w") - f.write(text_ext) - f.close() + with open(target[1].path, "w") as f: + f.write(text_ext) diff --git a/core/map.h b/core/map.h index 1e47b42625..700d4b8693 100644 --- a/core/map.h +++ b/core/map.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef MAP_H #define MAP_H @@ -196,7 +197,7 @@ private: if (node->right != _data._nil) { node = node->right; - while (node->left != _data._nil) { /* returns the minium of the right subtree of node */ + while (node->left != _data._nil) { /* returns the minimum of the right subtree of node */ node = node->left; } return node; @@ -218,7 +219,7 @@ private: if (node->left != _data._nil) { node = node->left; - while (node->right != _data._nil) { /* returns the minium of the left subtree of node */ + while (node->right != _data._nil) { /* returns the minimum of the left subtree of node */ node = node->right; } return node; diff --git a/core/math/a_star.cpp b/core/math/a_star.cpp index cb90116d63..6908d7831d 100644 --- a/core/math/a_star.cpp +++ b/core/math/a_star.cpp @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #include "a_star.h" #include "geometry.h" #include "scene/scene_string_names.h" diff --git a/core/math/a_star.h b/core/math/a_star.h index 563f82826d..f89e17c7bb 100644 --- a/core/math/a_star.h +++ b/core/math/a_star.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef ASTAR_H #define ASTAR_H diff --git a/core/math/aabb.cpp b/core/math/aabb.cpp index a6e5ced296..cff19f990c 100644 --- a/core/math/aabb.cpp +++ b/core/math/aabb.cpp @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #include "aabb.h" #include "print_string.h" diff --git a/core/math/aabb.h b/core/math/aabb.h index ff49337204..39b8f403e7 100644 --- a/core/math/aabb.h +++ b/core/math/aabb.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef AABB_H #define AABB_H diff --git a/core/math/audio_frame.cpp b/core/math/audio_frame.cpp index d22b0f05f4..eff817bbaa 100644 --- a/core/math/audio_frame.cpp +++ b/core/math/audio_frame.cpp @@ -27,4 +27,5 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #include "audio_frame.h" diff --git a/core/math/audio_frame.h b/core/math/audio_frame.h index fd58848c0b..67ba025e1c 100644 --- a/core/math/audio_frame.h +++ b/core/math/audio_frame.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef AUDIOFRAME_H #define AUDIOFRAME_H diff --git a/core/math/bsp_tree.cpp b/core/math/bsp_tree.cpp index 5d8ac000ad..b1424e1d78 100644 --- a/core/math/bsp_tree.cpp +++ b/core/math/bsp_tree.cpp @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #include "bsp_tree.h" #include "error_macros.h" #include "print_string.h" diff --git a/core/math/bsp_tree.h b/core/math/bsp_tree.h index 6a7b577fd0..fb16818ae7 100644 --- a/core/math/bsp_tree.h +++ b/core/math/bsp_tree.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef BSP_TREE_H #define BSP_TREE_H diff --git a/core/math/camera_matrix.cpp b/core/math/camera_matrix.cpp index 8714a07336..1ab9b3532e 100644 --- a/core/math/camera_matrix.cpp +++ b/core/math/camera_matrix.cpp @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #include "camera_matrix.h" #include "math_funcs.h" #include "print_string.h" diff --git a/core/math/camera_matrix.h b/core/math/camera_matrix.h index 9dde244e58..226b4d572b 100644 --- a/core/math/camera_matrix.h +++ b/core/math/camera_matrix.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef CAMERA_MATRIX_H #define CAMERA_MATRIX_H diff --git a/core/math/face3.cpp b/core/math/face3.cpp index e76719f736..801f2a3b4d 100644 --- a/core/math/face3.cpp +++ b/core/math/face3.cpp @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #include "face3.h" #include "geometry.h" diff --git a/core/math/face3.h b/core/math/face3.h index dd4cb25c82..faed0fa8d4 100644 --- a/core/math/face3.h +++ b/core/math/face3.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef FACE3_H #define FACE3_H diff --git a/core/math/geometry.cpp b/core/math/geometry.cpp index a3b48320b1..24f077a4ca 100644 --- a/core/math/geometry.cpp +++ b/core/math/geometry.cpp @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #include "geometry.h" #include "print_string.h" diff --git a/core/math/geometry.h b/core/math/geometry.h index fefdd88794..be998aef0b 100644 --- a/core/math/geometry.h +++ b/core/math/geometry.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef GEOMETRY_H #define GEOMETRY_H @@ -501,16 +502,15 @@ public: } static bool is_point_in_triangle(const Vector2 &s, const Vector2 &a, const Vector2 &b, const Vector2 &c) { - int as_x = s.x - a.x; - int as_y = s.y - a.y; - - bool s_ab = (b.x - a.x) * as_y - (b.y - a.y) * as_x > 0; + Vector2 an = a - s; + Vector2 bn = b - s; + Vector2 cn = c - s; - if (((c.x - a.x) * as_y - (c.y - a.y) * as_x > 0) == s_ab) return false; + bool orientation = an.cross(bn) > 0; - if (((c.x - b.x) * (s.y - b.y) - (c.y - b.y) * (s.x - b.x) > 0) != s_ab) return false; + if ((bn.cross(cn) > 0) != orientation) return false; - return true; + return (cn.cross(an) > 0) == orientation; } static bool is_point_in_polygon(const Vector2 &p_point, const Vector<Vector2> &p_polygon); @@ -529,6 +529,21 @@ public: return p_segment[0] + n * d; // inside } + static bool line_intersects_line_2d(const Vector2 &p_from_a, const Vector2 &p_dir_a, const Vector2 &p_from_b, const Vector2 &p_dir_b, Vector2 &r_result) { + + // see http://paulbourke.net/geometry/pointlineplane/ + + const real_t denom = p_dir_b.y * p_dir_a.x - p_dir_b.x * p_dir_a.y; + if (Math::abs(denom) < CMP_EPSILON) { // parallel? + return false; + } + + const Vector2 v = p_from_a - p_from_b; + const real_t t = (p_dir_b.x * v.y - p_dir_b.y * v.x) / denom; + r_result = p_from_a + t * p_dir_a; + return true; + } + static bool segment_intersects_segment_2d(const Vector2 &p_from_a, const Vector2 &p_to_a, const Vector2 &p_from_b, const Vector2 &p_to_b, Vector2 *r_result) { Vector2 B = p_to_a - p_from_a; diff --git a/core/math/math_2d.cpp b/core/math/math_2d.cpp index 2c83bc1976..a053ffbd93 100644 --- a/core/math/math_2d.cpp +++ b/core/math/math_2d.cpp @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #include "math_2d.h" real_t Vector2::angle() const { @@ -97,14 +98,19 @@ real_t Vector2::cross(const Vector2 &p_other) const { return x * p_other.y - y * p_other.x; } -Vector2 Vector2::cross(real_t p_other) const { +Vector2 Vector2::floor() const { - return Vector2(p_other * y, -p_other * x); + return Vector2(Math::floor(x), Math::floor(y)); } -Vector2 Vector2::floor() const { +Vector2 Vector2::ceil() const { - return Vector2(Math::floor(x), Math::floor(y)); + return Vector2(Math::ceil(x), Math::ceil(y)); +} + +Vector2 Vector2::round() const { + + return Vector2(Math::round(x), Math::round(y)); } Vector2 Vector2::rotated(real_t p_by) const { diff --git a/core/math/math_2d.h b/core/math/math_2d.h index 32e1bb9152..611d47e3ff 100644 --- a/core/math/math_2d.h +++ b/core/math/math_2d.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef MATH_2D_H #define MATH_2D_H @@ -103,7 +104,6 @@ struct Vector2 { real_t dot(const Vector2 &p_other) const; real_t cross(const Vector2 &p_other) const; - Vector2 cross(real_t p_other) const; Vector2 project(const Vector2 &p_vec) const; Vector2 plane_project(real_t p_d, const Vector2 &p_vec) const; @@ -162,6 +162,8 @@ struct Vector2 { } Vector2 floor() const; + Vector2 ceil() const; + Vector2 round() const; Vector2 snapped(const Vector2 &p_by) const; real_t aspect() const { return width / height; } @@ -303,7 +305,7 @@ struct Rect2 { inline real_t distance_to(const Vector2 &p_point) const { - real_t dist; + real_t dist = 0.0; bool inside = true; if (p_point.x < position.x) { diff --git a/core/math/math_defs.h b/core/math/math_defs.h index e260bcd54f..d3484d8d02 100644 --- a/core/math/math_defs.h +++ b/core/math/math_defs.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef MATH_DEFS_H #define MATH_DEFS_H diff --git a/core/math/math_funcs.cpp b/core/math/math_funcs.cpp index 1025e8be75..5c8512d8bd 100644 --- a/core/math/math_funcs.cpp +++ b/core/math/math_funcs.cpp @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #include "math_funcs.h" #include "core/os/os.h" @@ -176,18 +177,3 @@ float Math::random(float from, float to) { float ret = (float)r / (float)RANDOM_MAX; return (ret) * (to - from) + from; } - -int Math::wrapi(int value, int min, int max) { - --max; - int rng = max - min + 1; - value = ((value - min) % rng); - if (value < 0) - return max + 1 + value; - else - return min + value; -} - -float Math::wrapf(float value, float min, float max) { - float rng = max - min; - return min + (value - min) - (rng * floor((value - min) / rng)); -} diff --git a/core/math/math_funcs.h b/core/math/math_funcs.h index d2d49d85d6..20001bb9a6 100644 --- a/core/math/math_funcs.h +++ b/core/math/math_funcs.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef MATH_FUNCS_H #define MATH_FUNCS_H @@ -208,8 +209,18 @@ public: static _ALWAYS_INLINE_ double round(double p_val) { return (p_val >= 0) ? Math::floor(p_val + 0.5) : -Math::floor(-p_val + 0.5); } static _ALWAYS_INLINE_ float round(float p_val) { return (p_val >= 0) ? Math::floor(p_val + 0.5) : -Math::floor(-p_val + 0.5); } - static int wrapi(int value, int min, int max); - static float wrapf(float value, float min, float max); + static _ALWAYS_INLINE_ int wrapi(int value, int min, int max) { + int rng = max - min; + return min + ((((value - min) % rng) + rng) % rng); + } + static _ALWAYS_INLINE_ double wrapf(double value, double min, double max) { + double rng = max - min; + return value - (rng * Math::floor((value - min) / rng)); + } + static _ALWAYS_INLINE_ float wrapf(float value, float min, float max) { + float rng = max - min; + return value - (rng * Math::floor((value - min) / rng)); + } // double only, as these functions are mainly used by the editor and not performance-critical, static double ease(double p_x, double p_c); diff --git a/core/math/matrix3.cpp b/core/math/matrix3.cpp index ceaff04ae8..b0b05d1ec8 100644 --- a/core/math/matrix3.cpp +++ b/core/math/matrix3.cpp @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #include "matrix3.h" #include "math_funcs.h" #include "os/copymem.h" @@ -253,7 +254,7 @@ void Basis::set_scale(const Vector3 &p_scale) { set_axis(2, get_axis(2).normalized() * p_scale.z); } -Vector3 Basis::get_scale() const { +Vector3 Basis::get_scale_abs() const { return Vector3( Vector3(elements[0][0], elements[1][0], elements[2][0]).length(), @@ -261,7 +262,13 @@ Vector3 Basis::get_scale() const { Vector3(elements[0][2], elements[1][2], elements[2][2]).length()); } -Vector3 Basis::get_signed_scale() const { +Vector3 Basis::get_scale_local() const { + real_t det_sign = determinant() > 0 ? 1 : -1; + return det_sign * Vector3(elements[0].length(), elements[1].length(), elements[2].length()); +} + +// get_scale works with get_rotation, use get_scale_abs if you need to enforce positive signature. +Vector3 Basis::get_scale() const { // FIXME: We are assuming M = R.S (R is rotation and S is scaling), and use polar decomposition to extract R and S. // A polar decomposition is M = O.P, where O is an orthogonal matrix (meaning rotation and reflection) and // P is a positive semi-definite matrix (meaning it contains absolute values of scaling along its diagonal). @@ -341,6 +348,14 @@ void Basis::rotate(const Vector3 &p_euler) { *this = rotated(p_euler); } +Basis Basis::rotated(const Quat &p_quat) const { + return Basis(p_quat) * (*this); +} + +void Basis::rotate(const Quat &p_quat) { + *this = rotated(p_quat); +} + // TODO: rename this to get_rotation_euler Vector3 Basis::get_rotation() const { // Assumes that the matrix can be decomposed into a proper rotation and scaling matrix as M = R.S, @@ -370,6 +385,22 @@ void Basis::get_rotation_axis_angle(Vector3 &p_axis, real_t &p_angle) const { m.get_axis_angle(p_axis, p_angle); } +void Basis::get_rotation_axis_angle_local(Vector3 &p_axis, real_t &p_angle) const { + // Assumes that the matrix can be decomposed into a proper rotation and scaling matrix as M = R.S, + // and returns the Euler angles corresponding to the rotation part, complementing get_scale(). + // See the comment in get_scale() for further information. + Basis m = transposed(); + m.orthonormalize(); + real_t det = m.determinant(); + if (det < 0) { + // Ensure that the determinant is 1, such that result is a proper rotation matrix which can be represented by Euler angles. + m.scale(Vector3(-1, -1, -1)); + } + + m.get_axis_angle(p_axis, p_angle); + p_angle = -p_angle; +} + // get_euler_xyz returns a vector containing the Euler angles in the format // (a1,a2,a3), where a3 is the angle of the first rotation, and a1 is the last // (following the convention they are commonly defined in the literature). @@ -766,3 +797,32 @@ void Basis::set_axis_angle(const Vector3 &p_axis, real_t p_phi) { elements[2][1] = p_axis.y * p_axis.z * (1.0 - cosine) + p_axis.x * sine; elements[2][2] = axis_sq.z + cosine * (1.0 - axis_sq.z); } + +void Basis::set_axis_angle_scale(const Vector3 &p_axis, real_t p_phi, const Vector3 &p_scale) { + set_diagonal(p_scale); + rotate(p_axis, p_phi); +} + +void Basis::set_euler_scale(const Vector3 &p_euler, const Vector3 &p_scale) { + set_diagonal(p_scale); + rotate(p_euler); +} + +void Basis::set_quat_scale(const Quat &p_quat, const Vector3 &p_scale) { + set_diagonal(p_scale); + rotate(p_quat); +} + +void Basis::set_diagonal(const Vector3 p_diag) { + elements[0][0] = p_diag.x; + elements[0][1] = 0; + elements[0][2] = 0; + + elements[1][0] = 0; + elements[1][1] = p_diag.y; + elements[1][2] = 0; + + elements[2][0] = 0; + elements[2][1] = 0; + elements[2][2] = p_diag.z; +} diff --git a/core/math/matrix3.h b/core/math/matrix3.h index c426435729..fd383fc673 100644 --- a/core/math/matrix3.h +++ b/core/math/matrix3.h @@ -81,8 +81,12 @@ public: void rotate(const Vector3 &p_euler); Basis rotated(const Vector3 &p_euler) const; + void rotate(const Quat &p_quat); + Basis rotated(const Quat &p_quat) const; + Vector3 get_rotation() const; void get_rotation_axis_angle(Vector3 &p_axis, real_t &p_angle) const; + void get_rotation_axis_angle_local(Vector3 &p_axis, real_t &p_angle) const; Vector3 rotref_posscale_decomposition(Basis &rotref) const; @@ -108,7 +112,12 @@ public: void set_scale(const Vector3 &p_scale); Vector3 get_scale() const; - Vector3 get_signed_scale() const; + Vector3 get_scale_abs() const; + Vector3 get_scale_local() const; + + void set_axis_angle_scale(const Vector3 &p_axis, real_t p_phi, const Vector3 &p_scale); + void set_euler_scale(const Vector3 &p_euler, const Vector3 &p_scale); + void set_quat_scale(const Quat &p_quat, const Vector3 &p_scale); // transposed dot products _FORCE_INLINE_ real_t tdotx(const Vector3 &v) const { @@ -140,6 +149,8 @@ public: int get_orthogonal_index() const; void set_orthogonal_index(int p_index); + void set_diagonal(const Vector3 p_diag); + bool is_orthogonal() const; bool is_diagonal() const; bool is_rotation() const; @@ -219,6 +230,8 @@ public: Basis(const Quat &p_quat) { set_quat(p_quat); }; Basis(const Vector3 &p_euler) { set_euler(p_euler); } Basis(const Vector3 &p_axis, real_t p_phi) { set_axis_angle(p_axis, p_phi); } + Basis(const Vector3 &p_axis, real_t p_phi, const Vector3 &p_scale) { set_axis_angle_scale(p_axis, p_phi, p_scale); } + Basis(const Quat &p_quat, const Vector3 &p_scale) { set_quat_scale(p_quat, p_scale); } _FORCE_INLINE_ Basis(const Vector3 &row0, const Vector3 &row1, const Vector3 &row2) { elements[0] = row0; diff --git a/core/math/octree.h b/core/math/octree.h index c874d60894..4e3d6257f0 100644 --- a/core/math/octree.h +++ b/core/math/octree.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef OCTREE_H #define OCTREE_H @@ -611,7 +612,7 @@ bool Octree<T, use_pairs, AL>::_remove_element_from_octant(Element *p_element, O bool unpaired = false; if (use_pairs && p_octant->last_pass != pass) { - // check wether we should unpair stuff + // check whether we should unpair stuff // always test pairable typename List<Element *, AL>::Element *E = p_octant->pairable_elements.front(); while (E) { diff --git a/core/math/plane.cpp b/core/math/plane.cpp index c4e2f04fa6..78bb1771a4 100644 --- a/core/math/plane.cpp +++ b/core/math/plane.cpp @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #include "plane.h" #include "math_funcs.h" diff --git a/core/math/plane.h b/core/math/plane.h index 5497fde592..e567422dd0 100644 --- a/core/math/plane.h +++ b/core/math/plane.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef PLANE_H #define PLANE_H diff --git a/core/math/quat.cpp b/core/math/quat.cpp index 5706848b35..4f61401ac7 100644 --- a/core/math/quat.cpp +++ b/core/math/quat.cpp @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #include "quat.h" #include "matrix3.h" #include "print_string.h" @@ -88,7 +89,7 @@ void Quat::set_euler_yxz(const Vector3 &p_euler) { set(sin_a1 * cos_a2 * sin_a3 + cos_a1 * sin_a2 * cos_a3, sin_a1 * cos_a2 * cos_a3 - cos_a1 * sin_a2 * sin_a3, - -sin_a1 * sin_a2 * cos_a3 + cos_a1 * sin_a2 * sin_a3, + -sin_a1 * sin_a2 * cos_a3 + cos_a1 * cos_a2 * sin_a3, sin_a1 * sin_a2 * sin_a3 + cos_a1 * cos_a2 * cos_a3); } diff --git a/core/math/quick_hull.cpp b/core/math/quick_hull.cpp index e13f2e9c18..fc90417413 100644 --- a/core/math/quick_hull.cpp +++ b/core/math/quick_hull.cpp @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #include "quick_hull.h" #include "map.h" @@ -73,7 +74,7 @@ Error QuickHull::build(const Vector<Vector3> &p_points, Geometry::MeshData &r_me int longest_axis = aabb.get_longest_axis_index(); //first two vertices are the most distant - int simplex[4]; + int simplex[4] = { 0 }; { real_t max = 0, min = 0; diff --git a/core/math/quick_hull.h b/core/math/quick_hull.h index 40f601536f..eef4a9adff 100644 --- a/core/math/quick_hull.h +++ b/core/math/quick_hull.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef QUICK_HULL_H #define QUICK_HULL_H diff --git a/core/math/transform.cpp b/core/math/transform.cpp index ffad8cfc41..7cd186ca60 100644 --- a/core/math/transform.cpp +++ b/core/math/transform.cpp @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #include "transform.h" #include "math_funcs.h" #include "os/copymem.h" @@ -118,11 +119,11 @@ Transform Transform::interpolate_with(const Transform &p_transform, real_t p_c) /* not sure if very "efficient" but good enough? */ - Vector3 src_scale = basis.get_signed_scale(); + Vector3 src_scale = basis.get_scale(); Quat src_rot = basis.orthonormalized(); Vector3 src_loc = origin; - Vector3 dst_scale = p_transform.basis.get_signed_scale(); + Vector3 dst_scale = p_transform.basis.get_scale(); Quat dst_rot = p_transform.basis; Vector3 dst_loc = p_transform.origin; diff --git a/core/math/transform.h b/core/math/transform.h index e5bc7832a0..c06eaec604 100644 --- a/core/math/transform.h +++ b/core/math/transform.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef TRANSFORM_H #define TRANSFORM_H diff --git a/core/math/triangle_mesh.cpp b/core/math/triangle_mesh.cpp index 6138abc6b9..edd4ad3441 100644 --- a/core/math/triangle_mesh.cpp +++ b/core/math/triangle_mesh.cpp @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #include "triangle_mesh.h" #include "sort.h" diff --git a/core/math/triangle_mesh.h b/core/math/triangle_mesh.h index 4687b0e91b..9f145f2afb 100644 --- a/core/math/triangle_mesh.h +++ b/core/math/triangle_mesh.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef TRIANGLE_MESH_H #define TRIANGLE_MESH_H diff --git a/core/math/triangulate.cpp b/core/math/triangulate.cpp index ff65142341..563ba7268f 100644 --- a/core/math/triangulate.cpp +++ b/core/math/triangulate.cpp @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #include "triangulate.h" real_t Triangulate::get_area(const Vector<Vector2> &contour) { @@ -50,7 +51,8 @@ real_t Triangulate::get_area(const Vector<Vector2> &contour) { bool Triangulate::is_inside_triangle(real_t Ax, real_t Ay, real_t Bx, real_t By, real_t Cx, real_t Cy, - real_t Px, real_t Py) + real_t Px, real_t Py, + bool include_edges) { real_t ax, ay, bx, by, cx, cy, apx, apy, bpx, bpy, cpx, cpy; @@ -73,10 +75,14 @@ bool Triangulate::is_inside_triangle(real_t Ax, real_t Ay, cCROSSap = cx * apy - cy * apx; bCROSScp = bx * cpy - by * cpx; - return ((aCROSSbp >= 0.0) && (bCROSScp >= 0.0) && (cCROSSap >= 0.0)); + if (include_edges) { + return ((aCROSSbp > 0.0) && (bCROSScp > 0.0) && (cCROSSap > 0.0)); + } else { + return ((aCROSSbp >= 0.0) && (bCROSScp >= 0.0) && (cCROSSap >= 0.0)); + } }; -bool Triangulate::snip(const Vector<Vector2> &p_contour, int u, int v, int w, int n, const Vector<int> &V) { +bool Triangulate::snip(const Vector<Vector2> &p_contour, int u, int v, int w, int n, const Vector<int> &V, bool relaxed) { int p; real_t Ax, Ay, Bx, By, Cx, Cy, Px, Py; const Vector2 *contour = &p_contour[0]; @@ -90,13 +96,20 @@ bool Triangulate::snip(const Vector<Vector2> &p_contour, int u, int v, int w, in Cx = contour[V[w]].x; Cy = contour[V[w]].y; - if (CMP_EPSILON > (((Bx - Ax) * (Cy - Ay)) - ((By - Ay) * (Cx - Ax)))) return false; + // It can happen that the triangulation ends up with three aligned vertices to deal with. + // In this scenario, making the check below strict may reject the possibility of + // forming a last triangle with these aligned vertices, preventing the triangulatiom + // from completing. + // To avoid that we allow zero-area triangles if all else failed. + float threshold = relaxed ? -CMP_EPSILON : CMP_EPSILON; + + if (threshold > (((Bx - Ax) * (Cy - Ay)) - ((By - Ay) * (Cx - Ax)))) return false; for (p = 0; p < n; p++) { if ((p == u) || (p == v) || (p == w)) continue; Px = contour[V[p]].x; Py = contour[V[p]].y; - if (is_inside_triangle(Ax, Ay, Bx, By, Cx, Cy, Px, Py)) return false; + if (is_inside_triangle(Ax, Ay, Bx, By, Cx, Cy, Px, Py, relaxed)) return false; } return true; @@ -120,6 +133,8 @@ bool Triangulate::triangulate(const Vector<Vector2> &contour, Vector<int> &resul for (int v = 0; v < n; v++) V[v] = (n - 1) - v; + bool relaxed = false; + int nv = n; /* remove nv-2 Vertices, creating 1 triangle every time */ @@ -128,8 +143,20 @@ bool Triangulate::triangulate(const Vector<Vector2> &contour, Vector<int> &resul for (int v = nv - 1; nv > 2;) { /* if we loop, it is probably a non-simple polygon */ if (0 >= (count--)) { - //** Triangulate: ERROR - probable bad polygon! - return false; + if (relaxed) { + //** Triangulate: ERROR - probable bad polygon! + return false; + } else { + // There may be aligned vertices that the strict + // checks prevent from triangulating. In this situation + // we are better off adding flat triangles than + // failing, so we relax the checks and try one last + // round. + // Only relaxing the constraints as a last resort avoids + // degenerate triangles when they aren't necessary. + count = 2 * nv; + relaxed = true; + } } /* three consecutive vertices in current polygon, <u,v,w> */ @@ -140,7 +167,7 @@ bool Triangulate::triangulate(const Vector<Vector2> &contour, Vector<int> &resul int w = v + 1; if (nv <= w) w = 0; /* next */ - if (snip(contour, u, v, w, nv, V)) { + if (snip(contour, u, v, w, nv, V, relaxed)) { int a, b, c, s, t; /* true names of the vertices */ diff --git a/core/math/triangulate.h b/core/math/triangulate.h index 01b4a50a3e..b1a583d0c5 100644 --- a/core/math/triangulate.h +++ b/core/math/triangulate.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef TRIANGULATE_H #define TRIANGULATE_H @@ -50,10 +51,11 @@ public: static bool is_inside_triangle(real_t Ax, real_t Ay, real_t Bx, real_t By, real_t Cx, real_t Cy, - real_t Px, real_t Py); + real_t Px, real_t Py, + bool include_edges); private: - static bool snip(const Vector<Vector2> &p_contour, int u, int v, int w, int n, const Vector<int> &V); + static bool snip(const Vector<Vector2> &p_contour, int u, int v, int w, int n, const Vector<int> &V, bool relaxed); }; #endif diff --git a/core/math/vector3.cpp b/core/math/vector3.cpp index 02140bc337..78d52d5cd1 100644 --- a/core/math/vector3.cpp +++ b/core/math/vector3.cpp @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #include "vector3.h" #include "matrix3.h" diff --git a/core/math/vector3.h b/core/math/vector3.h index 17dbdafbd4..3bbfd7627c 100644 --- a/core/math/vector3.h +++ b/core/math/vector3.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef VECTOR3_H #define VECTOR3_H @@ -102,6 +103,7 @@ struct Vector3 { _FORCE_INLINE_ Vector3 floor() const; _FORCE_INLINE_ Vector3 sign() const; _FORCE_INLINE_ Vector3 ceil() const; + _FORCE_INLINE_ Vector3 round() const; _FORCE_INLINE_ real_t distance_to(const Vector3 &p_b) const; _FORCE_INLINE_ real_t distance_squared_to(const Vector3 &p_b) const; @@ -203,6 +205,11 @@ Vector3 Vector3::ceil() const { return Vector3(Math::ceil(x), Math::ceil(y), Math::ceil(z)); } +Vector3 Vector3::round() const { + + return Vector3(Math::round(x), Math::round(y), Math::round(z)); +} + Vector3 Vector3::linear_interpolate(const Vector3 &p_b, real_t p_t) const { return Vector3( diff --git a/core/message_queue.cpp b/core/message_queue.cpp index b7b8827f4a..25ee6eafae 100644 --- a/core/message_queue.cpp +++ b/core/message_queue.cpp @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #include "message_queue.h" #include "project_settings.h" @@ -277,7 +278,7 @@ void MessageQueue::flush() { while (read_pos < buffer_end) { - //lock on each interation, so a call can re-add itself to the message queue + //lock on each iteration, so a call can re-add itself to the message queue Message *message = (Message *)&buffer[read_pos]; diff --git a/core/message_queue.h b/core/message_queue.h index 7312f0e1e4..be5ffe4fae 100644 --- a/core/message_queue.h +++ b/core/message_queue.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef MESSAGE_QUEUE_H #define MESSAGE_QUEUE_H diff --git a/core/method_bind.cpp b/core/method_bind.cpp index 4022b22ffe..52ee9e0848 100644 --- a/core/method_bind.cpp +++ b/core/method_bind.cpp @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + // object.h needs to be the first include *before* method_bind.h // FIXME: Find out why and fix potential cyclical dependencies. #include "object.h" diff --git a/core/method_bind.h b/core/method_bind.h index aaf3640ce9..41b500c401 100644 --- a/core/method_bind.h +++ b/core/method_bind.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef METHOD_BIND_H #define METHOD_BIND_H @@ -127,10 +128,36 @@ struct VariantCaster<const T &> { // Object enum casts must go here VARIANT_ENUM_CAST(Object::ConnectFlags); +template <typename T> +struct VariantObjectClassChecker { + static _FORCE_INLINE_ bool check(const Variant &p_variant) { + return true; + } +}; + +template <> +struct VariantObjectClassChecker<Node *> { + static _FORCE_INLINE_ bool check(const Variant &p_variant) { + Object *obj = p_variant; + Node *node = p_variant; + return node || !obj; + } +}; + +template <> +struct VariantObjectClassChecker<Control *> { + static _FORCE_INLINE_ bool check(const Variant &p_variant) { + Object *obj = p_variant; + Control *control = p_variant; + return control || !obj; + } +}; + #define CHECK_ARG(m_arg) \ if ((m_arg - 1) < p_arg_count) { \ Variant::Type argtype = get_argument_type(m_arg - 1); \ - if (!Variant::can_convert_strict(p_args[m_arg - 1]->get_type(), argtype)) { \ + if (!Variant::can_convert_strict(p_args[m_arg - 1]->get_type(), argtype) || \ + !VariantObjectClassChecker<P##m_arg>::check(*p_args[m_arg - 1])) { \ r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; \ r_error.argument = m_arg - 1; \ r_error.expected = argtype; \ @@ -242,7 +269,7 @@ public: PropertyInfo get_argument_info(int p_argument) const; PropertyInfo get_return_info() const; - void set_argument_names(const Vector<StringName> &p_names); //set by class, db, cant be inferred otherwise + void set_argument_names(const Vector<StringName> &p_names); //set by class, db, can't be inferred otherwise Vector<StringName> get_argument_names() const; #endif diff --git a/core/method_ptrcall.h b/core/method_ptrcall.h index 1fe0cf0bc0..2007c3def5 100644 --- a/core/method_ptrcall.h +++ b/core/method_ptrcall.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef METHOD_PTRCALL_H #define METHOD_PTRCALL_H diff --git a/core/node_path.cpp b/core/node_path.cpp index abde887b35..64983fc091 100644 --- a/core/node_path.cpp +++ b/core/node_path.cpp @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #include "node_path.h" #include "print_string.h" @@ -263,8 +264,9 @@ NodePath NodePath::get_as_property_path() const { Vector<StringName> new_path = data->subpath; String initial_subname = data->path[0]; + for (size_t i = 1; i < data->path.size(); i++) { - initial_subname += i == 0 ? data->path[i].operator String() : "/" + data->path[i]; + initial_subname += "/" + data->path[i]; } new_path.insert(0, initial_subname); diff --git a/core/node_path.h b/core/node_path.h index af134e8409..288f39721f 100644 --- a/core/node_path.h +++ b/core/node_path.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef NODE_PATH_H #define NODE_PATH_H diff --git a/core/oa_hash_map.h b/core/oa_hash_map.h index 308624dcc3..0b3b40f30c 100644 --- a/core/oa_hash_map.h +++ b/core/oa_hash_map.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef OA_HASH_MAP_H #define OA_HASH_MAP_H @@ -35,176 +36,181 @@ #include "os/copymem.h" #include "os/memory.h" -// uncomment this to disable intial local storage. -#define OA_HASH_MAP_INITIAL_LOCAL_STORAGE - /** - * This class implements a hash map datastructure that uses open addressing with - * local probing. - * - * It can give huge performance improvements over a chained HashMap because of - * the increased data locality. - * - * Because of that locality property it's important to not use "large" value - * types as the "TData" type. If TData values are too big it can cause more - * cache misses then chaining. If larger values are needed then storing those - * in a separate array and using pointers or indices to reference them is the - * better solution. - * - * This hash map also implements real-time incremental rehashing. + * A HashMap implementation that uses open addressing with robinhood hashing. + * Robinhood hashing swaps out entries that have a smaller probing distance + * than the to-be-inserted entry, that evens out the average probing distance + * and enables faster lookups. * + * The entries are stored inplace, so huge keys or values might fill cache lines + * a lot faster. */ -template <class TKey, class TData, - uint16_t INITIAL_NUM_ELEMENTS = 64, +template <class TKey, class TValue, class Hasher = HashMapHasherDefault, class Comparator = HashMapComparatorDefault<TKey> > class OAHashMap { private: -#ifdef OA_HASH_MAP_INITIAL_LOCAL_STORAGE - TData local_data[INITIAL_NUM_ELEMENTS]; - TKey local_keys[INITIAL_NUM_ELEMENTS]; - uint32_t local_hashes[INITIAL_NUM_ELEMENTS]; - uint8_t local_flags[INITIAL_NUM_ELEMENTS / 4 + (INITIAL_NUM_ELEMENTS % 4 != 0 ? 1 : 0)]; -#endif + TValue *values; + TKey *keys; + uint32_t *hashes; + + uint32_t capacity; - struct { - TData *data; - TKey *keys; - uint32_t *hashes; + uint32_t num_elements; - // This is actually an array of bits, 4 bit pairs per octet. - // | ba ba ba ba | ba ba ba ba | .... - // - // if a is set it means that there is an element present. - // if b is set it means that an element was deleted. This is needed for - // the local probing to work without relocating any succeeding and - // colliding entries. - uint8_t *flags; + static const uint32_t EMPTY_HASH = 0; + static const uint32_t DELETED_HASH_BIT = 1 << 31; - uint32_t capacity; - } table, old_table; + _FORCE_INLINE_ uint32_t _hash(const TKey &p_key) { + uint32_t hash = Hasher::hash(p_key); + + if (hash == EMPTY_HASH) { + hash = EMPTY_HASH + 1; + } else if (hash & DELETED_HASH_BIT) { + hash &= ~DELETED_HASH_BIT; + } - bool is_rehashing; - uint32_t rehash_position; - uint32_t rehash_amount; + return hash; + } - uint32_t elements; + _FORCE_INLINE_ uint32_t _get_probe_length(uint32_t p_pos, uint32_t p_hash) { + p_hash = p_hash & ~DELETED_HASH_BIT; // we don't care if it was deleted or not - /* Methods */ + uint32_t original_pos = p_hash % capacity; - // returns true if the value already existed, false if it's a new entry - bool _raw_set_with_hash(uint32_t p_hash, const TKey &p_key, const TData &p_data) { - for (int i = 0; i < table.capacity; i++) { + return p_pos - original_pos; + } - int pos = (p_hash + i) % table.capacity; + _FORCE_INLINE_ void _construct(uint32_t p_pos, uint32_t p_hash, const TKey &p_key, const TValue &p_value) { + memnew_placement(&keys[p_pos], TKey(p_key)); + memnew_placement(&values[p_pos], TValue(p_value)); + hashes[p_pos] = p_hash; - int flags_pos = pos / 4; - int flags_pos_offset = pos % 4; + num_elements++; + } - bool is_filled_flag = table.flags[flags_pos] & (1 << (2 * flags_pos_offset)); - bool is_deleted_flag = table.flags[flags_pos] & (1 << (2 * flags_pos_offset + 1)); + bool _lookup_pos(const TKey &p_key, uint32_t &r_pos) { + uint32_t hash = _hash(p_key); + uint32_t pos = hash % capacity; + uint32_t distance = 0; - if (is_filled_flag) { - if (table.hashes[pos] == p_hash && Comparator::compare(table.keys[pos], p_key)) { - table.data[pos] = p_data; - return true; - } - continue; + while (42) { + if (hashes[pos] == EMPTY_HASH) { + return false; } - table.keys[pos] = p_key; - table.data[pos] = p_data; - table.hashes[pos] = p_hash; + if (distance > _get_probe_length(pos, hashes[pos])) { + return false; + } - table.flags[flags_pos] |= (1 << (2 * flags_pos_offset)); - table.flags[flags_pos] &= ~(1 << (2 * flags_pos_offset + 1)); + if (hashes[pos] == hash && Comparator::compare(keys[pos], p_key)) { + r_pos = pos; + return true; + } - return false; + pos = (pos + 1) % capacity; + distance++; } - return false; } -public: - _FORCE_INLINE_ uint32_t get_capacity() const { return table.capacity; } - _FORCE_INLINE_ uint32_t get_num_elements() const { return elements; } + void _insert_with_hash(uint32_t p_hash, const TKey &p_key, const TValue &p_value) { - void set(const TKey &p_key, const TData &p_data) { + uint32_t hash = p_hash; + uint32_t distance = 0; + uint32_t pos = hash % capacity; - uint32_t hash = Hasher::hash(p_key); + TKey key = p_key; + TValue value = p_value; - // We don't progress the rehashing if the table just got resized - // to keep the cost of this function low. - if (is_rehashing) { + while (42) { + if (hashes[pos] == EMPTY_HASH) { + _construct(pos, hash, p_key, p_value); - // rehash progress + return; + } - for (int i = 0; i <= rehash_amount && rehash_position < old_table.capacity; rehash_position++) { + // not an empty slot, let's check the probing length of the existing one + uint32_t existing_probe_len = _get_probe_length(pos, hashes[pos]); + if (existing_probe_len < distance) { - int flags_pos = rehash_position / 4; - int flags_pos_offset = rehash_position % 4; + if (hashes[pos] & DELETED_HASH_BIT) { + // we found a place where we can fit in! + _construct(pos, hash, p_key, p_value); - bool is_filled_flag = (old_table.flags[flags_pos] & (1 << (2 * flags_pos_offset))) > 0; - bool is_deleted_flag = (old_table.flags[flags_pos] & (1 << (2 * flags_pos_offset + 1))) > 0; + return; + } - if (is_filled_flag) { - _raw_set_with_hash(old_table.hashes[rehash_position], old_table.keys[rehash_position], old_table.data[rehash_position]); + SWAP(hash, hashes[pos]); + SWAP(key, keys[pos]); + SWAP(value, values[pos]); + distance = existing_probe_len; + } - old_table.keys[rehash_position].~TKey(); - old_table.data[rehash_position].~TData(); + pos = (pos + 1) % capacity; + distance++; + } + } + void _resize_and_rehash() { - memnew_placement(&old_table.keys[rehash_position], TKey); - memnew_placement(&old_table.data[rehash_position], TData); + TKey *old_keys = keys; + TValue *old_values = values; + uint32_t *old_hashes = hashes; - old_table.flags[flags_pos] &= ~(1 << (2 * flags_pos_offset)); - old_table.flags[flags_pos] |= (1 << (2 * flags_pos_offset + 1)); - } - } + uint32_t old_capacity = capacity; - if (rehash_position >= old_table.capacity) { + capacity = old_capacity * 2; + num_elements = 0; - // wohooo, we can get rid of the old table. - is_rehashing = false; + keys = memnew_arr(TKey, capacity); + values = memnew_arr(TValue, capacity); + hashes = memnew_arr(uint32_t, capacity); -#ifdef OA_HASH_MAP_INITIAL_LOCAL_STORAGE - if (old_table.data == local_data) { - // Everything is local, so no cleanup :P - } else -#endif - { - memdelete_arr(old_table.data); - memdelete_arr(old_table.keys); - memdelete_arr(old_table.hashes); - memdelete_arr(old_table.flags); - } - } + for (int i = 0; i < capacity; i++) { + hashes[i] = 0; } - // Table is almost full, resize and start rehashing process. - if (elements >= table.capacity * 0.7) { + for (uint32_t i = 0; i < old_capacity; i++) { + if (old_hashes[i] == EMPTY_HASH) { + continue; + } + if (old_hashes[i] & DELETED_HASH_BIT) { + continue; + } - old_table.capacity = table.capacity; - old_table.data = table.data; - old_table.flags = table.flags; - old_table.hashes = table.hashes; - old_table.keys = table.keys; + _insert_with_hash(old_hashes[i], old_keys[i], old_values[i]); + } - table.capacity = old_table.capacity * 2; + memdelete_arr(old_keys); + memdelete_arr(old_values); + memdelete_arr(old_hashes); + } - table.data = memnew_arr(TData, table.capacity); - table.flags = memnew_arr(uint8_t, table.capacity / 4 + (table.capacity % 4 != 0 ? 1 : 0)); - table.hashes = memnew_arr(uint32_t, table.capacity); - table.keys = memnew_arr(TKey, table.capacity); +public: + _FORCE_INLINE_ uint32_t get_capacity() const { return capacity; } + _FORCE_INLINE_ uint32_t get_num_elements() const { return num_elements; } - zeromem(table.flags, table.capacity / 4 + (table.capacity % 4 != 0 ? 1 : 0)); + void insert(const TKey &p_key, const TValue &p_value) { - is_rehashing = true; - rehash_position = 0; - rehash_amount = (elements * 2) / (table.capacity * 0.7 - old_table.capacity); + if ((float)num_elements / (float)capacity > 0.9) { + _resize_and_rehash(); } - if (!_raw_set_with_hash(hash, p_key, p_data)) - elements++; + uint32_t hash = _hash(p_key); + + _insert_with_hash(hash, p_key, p_value); + } + + void set(const TKey &p_key, const TValue &p_data) { + uint32_t pos = 0; + bool exists = _lookup_pos(p_key, pos); + + if (exists) { + values[pos].~TValue(); + memnew_placement(&values[pos], TValue(p_data)); + } else { + insert(p_key, p_data); + } } /** @@ -213,380 +219,108 @@ public: * if r_data is not NULL then the value will be written to the object * it points to. */ - bool lookup(const TKey &p_key, TData *r_data) { - - uint32_t hash = Hasher::hash(p_key); - - bool check_old_table = is_rehashing; - bool check_new_table = true; - - // search for the key and return the value associated with it - // - // if we're rehashing we need to check both the old and the - // current table. If we find a value in the old table we still - // need to continue searching in the new table as it might have - // been added after - - TData *value = NULL; - - for (int i = 0; i < table.capacity; i++) { - - if (!check_new_table && !check_old_table) { - - break; - } - - // if we're rehashing check the old table - if (check_old_table && i < old_table.capacity) { - - int pos = (hash + i) % old_table.capacity; - - int flags_pos = pos / 4; - int flags_pos_offset = pos % 4; - - bool is_filled_flag = (old_table.flags[flags_pos] & (1 << (2 * flags_pos_offset))) > 0; - bool is_deleted_flag = (old_table.flags[flags_pos] & (1 << (2 * flags_pos_offset + 1))) > 0; - - if (is_filled_flag) { - // found our entry? - if (old_table.hashes[pos] == hash && Comparator::compare(old_table.keys[pos], p_key)) { - value = &old_table.data[pos]; - check_old_table = false; - } - } else if (!is_deleted_flag) { - - // we hit an empty field here, we don't - // need to further check this old table - // because we know it's not in here. + bool lookup(const TKey &p_key, TValue &r_data) { + uint32_t pos = 0; + bool exists = _lookup_pos(p_key, pos); - check_old_table = false; - } - } - - if (check_new_table) { - - int pos = (hash + i) % table.capacity; - - int flags_pos = pos / 4; - int flags_pos_offset = pos % 4; - - bool is_filled_flag = (table.flags[flags_pos] & (1 << (2 * flags_pos_offset))) > 0; - bool is_deleted_flag = (table.flags[flags_pos] & (1 << (2 * flags_pos_offset + 1))) > 0; - - if (is_filled_flag) { - // found our entry? - if (table.hashes[pos] == hash && Comparator::compare(table.keys[pos], p_key)) { - if (r_data != NULL) - *r_data = table.data[pos]; - return true; - } - continue; - } else if (is_deleted_flag) { - continue; - } else if (value != NULL) { - - // We found a value in the old table - if (r_data != NULL) - *r_data = *value; - return true; - } else { - check_new_table = false; - } - } - } - - if (value != NULL) { - if (r_data != NULL) - *r_data = *value; + if (exists) { + r_data.~TValue(); + memnew_placement(&r_data, TValue(values[pos])); return true; } + return false; } _FORCE_INLINE_ bool has(const TKey &p_key) { - return lookup(p_key, NULL); + uint32_t _pos = 0; + return _lookup_pos(p_key, _pos); } void remove(const TKey &p_key) { - uint32_t hash = Hasher::hash(p_key); - - bool check_old_table = is_rehashing; - bool check_new_table = true; - - for (int i = 0; i < table.capacity; i++) { - - if (!check_new_table && !check_old_table) { - return; - } - - // if we're rehashing check the old table - if (check_old_table && i < old_table.capacity) { - - int pos = (hash + i) % old_table.capacity; - - int flags_pos = pos / 4; - int flags_pos_offset = pos % 4; - - bool is_filled_flag = (old_table.flags[flags_pos] & (1 << (2 * flags_pos_offset))) > 0; - bool is_deleted_flag = (old_table.flags[flags_pos] & (1 << (2 * flags_pos_offset + 1))) > 0; - - if (is_filled_flag) { - // found our entry? - if (old_table.hashes[pos] == hash && Comparator::compare(old_table.keys[pos], p_key)) { - old_table.keys[pos].~TKey(); - old_table.data[pos].~TData(); + uint32_t pos = 0; + bool exists = _lookup_pos(p_key, pos); - memnew_placement(&old_table.keys[pos], TKey); - memnew_placement(&old_table.data[pos], TData); - - old_table.flags[flags_pos] &= ~(1 << (2 * flags_pos_offset)); - old_table.flags[flags_pos] |= (1 << (2 * flags_pos_offset + 1)); - - elements--; - return; - } - } else if (!is_deleted_flag) { - - // we hit an empty field here, we don't - // need to further check this old table - // because we know it's not in here. - - check_old_table = false; - } - } - - if (check_new_table) { - - int pos = (hash + i) % table.capacity; - - int flags_pos = pos / 4; - int flags_pos_offset = pos % 4; - - bool is_filled_flag = (table.flags[flags_pos] & (1 << (2 * flags_pos_offset))) > 0; - bool is_deleted_flag = (table.flags[flags_pos] & (1 << (2 * flags_pos_offset + 1))) > 0; - - if (is_filled_flag) { - // found our entry? - if (table.hashes[pos] == hash && Comparator::compare(table.keys[pos], p_key)) { - table.keys[pos].~TKey(); - table.data[pos].~TData(); - - memnew_placement(&table.keys[pos], TKey); - memnew_placement(&table.data[pos], TData); - - table.flags[flags_pos] &= ~(1 << (2 * flags_pos_offset)); - table.flags[flags_pos] |= (1 << (2 * flags_pos_offset + 1)); - - // don't return here, this value might still be in the old table - // if it was already relocated. - - elements--; - return; - } - continue; - } else if (is_deleted_flag) { - continue; - } else { - check_new_table = false; - } - } + if (!exists) { + return; } + + hashes[pos] |= DELETED_HASH_BIT; + values[pos].~TValue(); + keys[pos].~TKey(); + num_elements--; } struct Iterator { bool valid; - uint32_t hash; - const TKey *key; - const TData *data; + const TValue *value; private: + uint32_t pos; friend class OAHashMap; - bool was_from_old_table; }; Iterator iter() const { Iterator it; - it.valid = false; - it.was_from_old_table = false; - - bool check_old_table = is_rehashing; - - for (int i = 0; i < table.capacity; i++) { - - // if we're rehashing check the old table first - if (check_old_table && i < old_table.capacity) { - - int pos = i; - - int flags_pos = pos / 4; - int flags_pos_offset = pos % 4; - - bool is_filled_flag = (old_table.flags[flags_pos] & (1 << (2 * flags_pos_offset))) > 0; - - if (is_filled_flag) { - it.valid = true; - it.hash = old_table.hashes[pos]; - it.data = &old_table.data[pos]; - it.key = &old_table.keys[pos]; - - it.was_from_old_table = true; - - return it; - } - } - - { - - int pos = i; - - int flags_pos = pos / 4; - int flags_pos_offset = pos % 4; - - bool is_filled_flag = (table.flags[flags_pos] & (1 << (2 * flags_pos_offset))) > 0; - - if (is_filled_flag) { - it.valid = true; - it.hash = table.hashes[pos]; - it.data = &table.data[pos]; - it.key = &table.keys[pos]; - - return it; - } - } - } + it.valid = true; + it.pos = 0; - return it; + return next_iter(it); } Iterator next_iter(const Iterator &p_iter) const { + if (!p_iter.valid) { return p_iter; } Iterator it; - it.valid = false; - it.was_from_old_table = false; - - bool check_old_table = is_rehashing; - - // we use this to skip the first check or not - bool was_from_old_table = p_iter.was_from_old_table; - - int prev_index = (p_iter.data - (p_iter.was_from_old_table ? old_table.data : table.data)); - - if (!was_from_old_table) { - prev_index++; - } + it.pos = p_iter.pos; + it.key = NULL; + it.value = NULL; - for (int i = prev_index; i < table.capacity; i++) { + for (uint32_t i = it.pos; i < capacity; i++) { + it.pos = i + 1; - // if we're rehashing check the old table first - if (check_old_table && i < old_table.capacity && !was_from_old_table) { - - int pos = i; - - int flags_pos = pos / 4; - int flags_pos_offset = pos % 4; - - bool is_filled_flag = (old_table.flags[flags_pos] & (1 << (2 * flags_pos_offset))) > 0; - - if (is_filled_flag) { - it.valid = true; - it.hash = old_table.hashes[pos]; - it.data = &old_table.data[pos]; - it.key = &old_table.keys[pos]; - - it.was_from_old_table = true; - - return it; - } + if (hashes[i] == EMPTY_HASH) { + continue; } - - was_from_old_table = false; - - { - int pos = i; - - int flags_pos = pos / 4; - int flags_pos_offset = pos % 4; - - bool is_filled_flag = (table.flags[flags_pos] & (1 << (2 * flags_pos_offset))) > 0; - - if (is_filled_flag) { - it.valid = true; - it.hash = table.hashes[pos]; - it.data = &table.data[pos]; - it.key = &table.keys[pos]; - - return it; - } + if (hashes[i] & DELETED_HASH_BIT) { + continue; } + + it.valid = true; + it.key = &keys[i]; + it.value = &values[i]; + return it; } return it; } - OAHashMap(uint32_t p_initial_capacity = INITIAL_NUM_ELEMENTS) { + OAHashMap(uint32_t p_initial_capacity = 64) { -#ifdef OA_HASH_MAP_INITIAL_LOCAL_STORAGE + capacity = p_initial_capacity; + num_elements = 0; - if (p_initial_capacity <= INITIAL_NUM_ELEMENTS) { - table.data = local_data; - table.keys = local_keys; - table.hashes = local_hashes; - table.flags = local_flags; + keys = memnew_arr(TKey, p_initial_capacity); + values = memnew_arr(TValue, p_initial_capacity); + hashes = memnew_arr(uint32_t, p_initial_capacity); - zeromem(table.flags, INITIAL_NUM_ELEMENTS / 4 + (INITIAL_NUM_ELEMENTS % 4 != 0 ? 1 : 0)); - - table.capacity = INITIAL_NUM_ELEMENTS; - elements = 0; - } else -#endif - { - table.data = memnew_arr(TData, p_initial_capacity); - table.keys = memnew_arr(TKey, p_initial_capacity); - table.hashes = memnew_arr(uint32_t, p_initial_capacity); - table.flags = memnew_arr(uint8_t, p_initial_capacity / 4 + (p_initial_capacity % 4 != 0 ? 1 : 0)); - - zeromem(table.flags, p_initial_capacity / 4 + (p_initial_capacity % 4 != 0 ? 1 : 0)); - - table.capacity = p_initial_capacity; - elements = 0; + for (int i = 0; i < p_initial_capacity; i++) { + hashes[i] = 0; } - - is_rehashing = false; - rehash_position = 0; } ~OAHashMap() { -#ifdef OA_HASH_MAP_INITIAL_LOCAL_STORAGE - if (table.capacity <= INITIAL_NUM_ELEMENTS) { - return; // Everything is local, so no cleanup :P - } -#endif - if (is_rehashing) { - -#ifdef OA_HASH_MAP_INITIAL_LOCAL_STORAGE - if (old_table.data == local_data) { - // Everything is local, so no cleanup :P - } else -#endif - { - memdelete_arr(old_table.data); - memdelete_arr(old_table.keys); - memdelete_arr(old_table.hashes); - memdelete_arr(old_table.flags); - } - } - memdelete_arr(table.data); - memdelete_arr(table.keys); - memdelete_arr(table.hashes); - memdelete_arr(table.flags); + memdelete_arr(keys); + memdelete_arr(values); + memdelete(hashes); } }; diff --git a/core/object.cpp b/core/object.cpp index 2e3196dc47..239700a4ab 100644 --- a/core/object.cpp +++ b/core/object.cpp @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #include "object.h" #include "class_db.h" @@ -604,11 +605,11 @@ void Object::get_property_list(List<PropertyInfo> *p_list, bool p_reversed) cons p_list->push_back(PropertyInfo(Variant::OBJECT, "script", PROPERTY_HINT_RESOURCE_TYPE, "Script", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_STORE_IF_NONZERO)); #ifdef TOOLS_ENABLED if (editor_section_folding.size()) { - p_list->push_back(PropertyInfo(Variant::ARRAY, CoreStringNames::get_singleton()->_sections_unfolded, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR)); + p_list->push_back(PropertyInfo(Variant::ARRAY, CoreStringNames::get_singleton()->_sections_unfolded, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL)); } #endif if (!metadata.empty()) - p_list->push_back(PropertyInfo(Variant::DICTIONARY, "__meta__", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_STORE_IF_NONZERO)); + p_list->push_back(PropertyInfo(Variant::DICTIONARY, "__meta__", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL | PROPERTY_USAGE_STORE_IF_NONZERO)); if (script_instance && !p_reversed) { p_list->push_back(PropertyInfo(Variant::NIL, "Script Variables", PROPERTY_HINT_NONE, String(), PROPERTY_USAGE_CATEGORY)); script_instance->get_property_list(p_list); @@ -1918,9 +1919,7 @@ ObjectID ObjectDB::add_instance(Object *p_object) { rw_lock->write_lock(); instances[++instance_counter] = p_object; -#ifdef DEBUG_ENABLED instance_checks[p_object] = instance_counter; -#endif rw_lock->write_unlock(); return instance_counter; @@ -1931,9 +1930,7 @@ void ObjectDB::remove_instance(Object *p_object) { rw_lock->write_lock(); instances.erase(p_object->get_instance_id()); -#ifdef DEBUG_ENABLED instance_checks.erase(p_object); -#endif rw_lock->write_unlock(); } diff --git a/core/object.h b/core/object.h index 635c599154..c405e22557 100644 --- a/core/object.h +++ b/core/object.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef OBJECT_H #define OBJECT_H @@ -85,6 +86,7 @@ enum PropertyHint { PROPERTY_HINT_PROPERTY_OF_SCRIPT, ///< a property of a script & base PROPERTY_HINT_OBJECT_TOO_BIG, ///< object is too big to send PROPERTY_HINT_MAX, + // When updating PropertyHint, also sync the hardcoded list in VisualScriptEditorVariableEdit }; enum PropertyUsageFlags { @@ -110,10 +112,11 @@ enum PropertyUsageFlags { PROPERTY_USAGE_CLASS_IS_ENUM = 1 << 18, PROPERTY_USAGE_NIL_IS_VARIANT = 1 << 19, PROPERTY_USAGE_INTERNAL = 1 << 20, + PROPERTY_USAGE_DO_NOT_SHARE_ON_DUPLICATE = 1 << 21, // If the object is duplicated also this property will be duplicated PROPERTY_USAGE_DEFAULT = PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_NETWORK, PROPERTY_USAGE_DEFAULT_INTL = PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_NETWORK | PROPERTY_USAGE_INTERNATIONALIZED, - PROPERTY_USAGE_NOEDITOR = PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_NETWORK | PROPERTY_USAGE_INTERNAL, + PROPERTY_USAGE_NOEDITOR = PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_NETWORK, }; #define ADD_SIGNAL(m_signal) ClassDB::add_signal(get_class_static(), m_signal) @@ -759,15 +762,10 @@ public: static void debug_objects(DebugFunc p_func); static int get_object_count(); -#ifdef DEBUG_ENABLED _FORCE_INLINE_ static bool instance_validate(Object *p_ptr) { return instance_checks.has(p_ptr); } -#else - _FORCE_INLINE_ static bool instance_validate(Object *p_ptr) { return true; } - -#endif }; //needed by macros diff --git a/core/ordered_hash_map.h b/core/ordered_hash_map.h index 5954952b6c..93ce9a90a7 100644 --- a/core/ordered_hash_map.h +++ b/core/ordered_hash_map.h @@ -3,7 +3,7 @@ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ -/* http://www.godotengine.org */ +/* https://godotengine.org */ /*************************************************************************/ /* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ /* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef ORDERED_HASH_MAP_H #define ORDERED_HASH_MAP_H diff --git a/core/os/copymem.h b/core/os/copymem.h index 998c0a8b9b..87d77bd426 100644 --- a/core/os/copymem.h +++ b/core/os/copymem.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef COPYMEM_H #define COPYMEM_H diff --git a/core/os/dir_access.cpp b/core/os/dir_access.cpp index c906fa7333..330a9153ef 100644 --- a/core/os/dir_access.cpp +++ b/core/os/dir_access.cpp @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #include "dir_access.h" #include "os/file_access.h" #include "os/memory.h" @@ -293,15 +294,15 @@ String DirAccess::get_full_path(const String &p_path, AccessType p_access) { return full; } -Error DirAccess::copy(String p_from, String p_to, int chmod_flags) { +Error DirAccess::copy(String p_from, String p_to, int p_chmod_flags) { //printf("copy %s -> %s\n",p_from.ascii().get_data(),p_to.ascii().get_data()); Error err; FileAccess *fsrc = FileAccess::open(p_from, FileAccess::READ, &err); if (err) { - - ERR_FAIL_COND_V(err, err); + ERR_PRINTS("Failed to open " + p_from); + return err; } FileAccess *fdst = FileAccess::open(p_to, FileAccess::WRITE, &err); @@ -309,7 +310,8 @@ Error DirAccess::copy(String p_from, String p_to, int chmod_flags) { fsrc->close(); memdelete(fsrc); - ERR_FAIL_COND_V(err, err); + ERR_PRINTS("Failed to open " + p_to); + return err; } fsrc->seek_end(0); @@ -330,9 +332,9 @@ Error DirAccess::copy(String p_from, String p_to, int chmod_flags) { fdst->store_8(fsrc->get_8()); } - if (err == OK && chmod_flags != -1) { + if (err == OK && p_chmod_flags != -1) { fdst->close(); - err = fdst->_chmod(p_to, chmod_flags); + err = fdst->_chmod(p_to, p_chmod_flags); // If running on a platform with no chmod support (i.e., Windows), don't fail if (err == ERR_UNAVAILABLE) err = OK; diff --git a/core/os/dir_access.h b/core/os/dir_access.h index f29f61e838..4df0618021 100644 --- a/core/os/dir_access.h +++ b/core/os/dir_access.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef DIR_ACCESS_H #define DIR_ACCESS_H @@ -92,8 +93,8 @@ public: static bool exists(String p_dir); virtual size_t get_space_left() = 0; - Error copy_dir(String p_from, String p_to, int chmod_flags = -1); - virtual Error copy(String p_from, String p_to, int chmod_flags = -1); + Error copy_dir(String p_from, String p_to, int p_chmod_flags = -1); + virtual Error copy(String p_from, String p_to, int p_chmod_flags = -1); virtual Error rename(String p_from, String p_to) = 0; virtual Error remove(String p_name) = 0; diff --git a/core/os/file_access.cpp b/core/os/file_access.cpp index 989230b162..033b4b12b9 100644 --- a/core/os/file_access.cpp +++ b/core/os/file_access.cpp @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #include "file_access.h" #include "core/io/file_access_pack.h" @@ -478,6 +479,9 @@ void FileAccess::store_double(double p_dest) { uint64_t FileAccess::get_modified_time(const String &p_file) { + if (PackedData::get_singleton() && !PackedData::get_singleton()->is_disabled() && PackedData::get_singleton()->has_path(p_file)) + return 0; + FileAccess *fa = create_for_path(p_file); ERR_FAIL_COND_V(!fa, 0); diff --git a/core/os/file_access.h b/core/os/file_access.h index 61edc9a5db..c4635fdfbb 100644 --- a/core/os/file_access.h +++ b/core/os/file_access.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef FILE_ACCESS_H #define FILE_ACCESS_H @@ -88,6 +89,9 @@ public: virtual void close() = 0; ///< close a file virtual bool is_open() const = 0; ///< true when file is open + virtual String get_path() const { return ""; } /// returns the path for the current open file + virtual String get_path_absolute() const { return ""; } /// returns the absolute path for the current open file + virtual void seek(size_t p_position) = 0; ///< seek to a given position virtual void seek_end(int64_t p_position = 0) = 0; ///< seek from the end of file virtual size_t get_position() const = 0; ///< get position in the file diff --git a/core/os/input.cpp b/core/os/input.cpp index a44adde425..a5b0f91e63 100644 --- a/core/os/input.cpp +++ b/core/os/input.cpp @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #include "input.h" #include "input_map.h" #include "os/os.h" @@ -56,6 +57,7 @@ void Input::_bind_methods() { ClassDB::bind_method(D_METHOD("is_action_pressed", "action"), &Input::is_action_pressed); ClassDB::bind_method(D_METHOD("is_action_just_pressed", "action"), &Input::is_action_just_pressed); ClassDB::bind_method(D_METHOD("is_action_just_released", "action"), &Input::is_action_just_released); + ClassDB::bind_method(D_METHOD("get_action_strength", "action"), &Input::get_action_strength); ClassDB::bind_method(D_METHOD("add_joy_mapping", "mapping", "update_existing"), &Input::add_joy_mapping, DEFVAL(false)); ClassDB::bind_method(D_METHOD("remove_joy_mapping", "guid"), &Input::remove_joy_mapping); ClassDB::bind_method(D_METHOD("joy_connection_changed", "device", "connected", "name", "guid"), &Input::joy_connection_changed); @@ -84,6 +86,7 @@ void Input::_bind_methods() { ClassDB::bind_method(D_METHOD("warp_mouse_position", "to"), &Input::warp_mouse_position); ClassDB::bind_method(D_METHOD("action_press", "action"), &Input::action_press); ClassDB::bind_method(D_METHOD("action_release", "action"), &Input::action_release); + ClassDB::bind_method(D_METHOD("set_default_cursor_shape", "shape"), &Input::set_default_cursor_shape, DEFVAL(CURSOR_ARROW)); ClassDB::bind_method(D_METHOD("set_custom_mouse_cursor", "image", "shape", "hotspot"), &Input::set_custom_mouse_cursor, DEFVAL(CURSOR_ARROW), DEFVAL(Vector2())); ClassDB::bind_method(D_METHOD("parse_input_event", "event"), &Input::parse_input_event); @@ -110,14 +113,14 @@ void Input::_bind_methods() { BIND_ENUM_CONSTANT(CURSOR_HSPLIT); BIND_ENUM_CONSTANT(CURSOR_HELP); - ADD_SIGNAL(MethodInfo("joy_connection_changed", PropertyInfo(Variant::INT, "index"), PropertyInfo(Variant::BOOL, "connected"))); + ADD_SIGNAL(MethodInfo("joy_connection_changed", PropertyInfo(Variant::INT, "device"), PropertyInfo(Variant::BOOL, "connected"))); } void Input::get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const { #ifdef TOOLS_ENABLED String pf = p_function; - if (p_idx == 0 && (pf == "is_action_pressed" || pf == "action_press" || pf == "action_release" || pf == "is_action_just_pressed" || pf == "is_action_just_released")) { + if (p_idx == 0 && (pf == "is_action_pressed" || pf == "action_press" || pf == "action_release" || pf == "is_action_just_pressed" || pf == "is_action_just_released" || pf == "get_action_strength")) { List<PropertyInfo> pinfo; ProjectSettings::get_singleton()->get_property_list(&pinfo); diff --git a/core/os/input.h b/core/os/input.h index 140d11de4d..001871c5dc 100644 --- a/core/os/input.h +++ b/core/os/input.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef INPUT_H #define INPUT_H @@ -84,6 +85,7 @@ public: virtual bool is_action_pressed(const StringName &p_action) const = 0; virtual bool is_action_just_pressed(const StringName &p_action) const = 0; virtual bool is_action_just_released(const StringName &p_action) const = 0; + virtual float get_action_strength(const StringName &p_action) const = 0; virtual float get_joy_axis(int p_device, int p_axis) const = 0; virtual String get_joy_name(int p_idx) = 0; @@ -116,8 +118,11 @@ public: void get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const; - virtual bool is_emulating_touchscreen() const = 0; + virtual bool is_emulating_touch_from_mouse() const = 0; + virtual bool is_emulating_mouse_from_touch() const = 0; + virtual CursorShape get_default_cursor_shape() = 0; + virtual void set_default_cursor_shape(CursorShape p_shape) = 0; virtual void set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape = CURSOR_ARROW, const Vector2 &p_hotspot = Vector2()) = 0; virtual void set_mouse_in_window(bool p_in_window) = 0; diff --git a/core/os/input_event.cpp b/core/os/input_event.cpp index 67590517fb..4ebb821a2f 100644 --- a/core/os/input_event.cpp +++ b/core/os/input_event.cpp @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #include "input_event.h" #include "input_map.h" @@ -40,11 +41,6 @@ int InputEvent::get_device() const { return device; } -bool InputEvent::is_pressed() const { - - return false; -} - bool InputEvent::is_action(const StringName &p_action) const { return InputMap::get_singleton()->event_is_action(Ref<InputEvent>((InputEvent *)this), p_action); @@ -52,11 +48,29 @@ bool InputEvent::is_action(const StringName &p_action) const { bool InputEvent::is_action_pressed(const StringName &p_action) const { - return (is_pressed() && !is_echo() && is_action(p_action)); + bool pressed; + bool valid = InputMap::get_singleton()->event_get_action_status(Ref<InputEvent>((InputEvent *)this), p_action, &pressed); + return valid && pressed && !is_echo(); } + bool InputEvent::is_action_released(const StringName &p_action) const { - return (!is_pressed() && is_action(p_action)); + bool pressed; + bool valid = InputMap::get_singleton()->event_get_action_status(Ref<InputEvent>((InputEvent *)this), p_action, &pressed); + return valid && !pressed; +} + +float InputEvent::get_action_strength(const StringName &p_action) const { + + bool pressed; + float strength; + bool valid = InputMap::get_singleton()->event_get_action_status(Ref<InputEvent>((InputEvent *)this), p_action, &pressed, &strength); + return valid ? strength : 0.0f; +} + +bool InputEvent::is_pressed() const { + + return false; } bool InputEvent::is_echo() const { @@ -74,7 +88,7 @@ String InputEvent::as_text() const { return String(); } -bool InputEvent::action_match(const Ref<InputEvent> &p_event) const { +bool InputEvent::action_match(const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float p_deadzone) const { return false; } @@ -94,15 +108,16 @@ void InputEvent::_bind_methods() { ClassDB::bind_method(D_METHOD("set_device", "device"), &InputEvent::set_device); ClassDB::bind_method(D_METHOD("get_device"), &InputEvent::get_device); - ClassDB::bind_method(D_METHOD("is_pressed"), &InputEvent::is_pressed); ClassDB::bind_method(D_METHOD("is_action", "action"), &InputEvent::is_action); ClassDB::bind_method(D_METHOD("is_action_pressed", "action"), &InputEvent::is_action_pressed); ClassDB::bind_method(D_METHOD("is_action_released", "action"), &InputEvent::is_action_released); + ClassDB::bind_method(D_METHOD("get_action_strength", "action"), &InputEvent::get_action_strength); + + ClassDB::bind_method(D_METHOD("is_pressed"), &InputEvent::is_pressed); ClassDB::bind_method(D_METHOD("is_echo"), &InputEvent::is_echo); ClassDB::bind_method(D_METHOD("as_text"), &InputEvent::as_text); - ClassDB::bind_method(D_METHOD("action_match", "event"), &InputEvent::action_match); ClassDB::bind_method(D_METHOD("shortcut_match", "event"), &InputEvent::shortcut_match); ClassDB::bind_method(D_METHOD("is_action_type"), &InputEvent::is_action_type); @@ -280,7 +295,7 @@ String InputEventKey::as_text() const { return kc; } -bool InputEventKey::action_match(const Ref<InputEvent> &p_event) const { +bool InputEventKey::action_match(const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float p_deadzone) const { Ref<InputEventKey> key = p_event; if (key.is_null()) @@ -289,7 +304,14 @@ bool InputEventKey::action_match(const Ref<InputEvent> &p_event) const { uint32_t code = get_scancode_with_modifiers(); uint32_t event_code = key->get_scancode_with_modifiers(); - return get_scancode() == key->get_scancode() && (!key->is_pressed() || (code & event_code) == code); + bool match = get_scancode() == key->get_scancode() && (!key->is_pressed() || (code & event_code) == code); + if (match) { + if (p_pressed != NULL) + *p_pressed = key->is_pressed(); + if (p_strength != NULL) + *p_strength = (*p_pressed) ? 1.0f : 0.0f; + } + return match; } bool InputEventKey::shortcut_match(const Ref<InputEvent> &p_event) const { @@ -445,13 +467,21 @@ Ref<InputEvent> InputEventMouseButton::xformed_by(const Transform2D &p_xform, co return mb; } -bool InputEventMouseButton::action_match(const Ref<InputEvent> &p_event) const { +bool InputEventMouseButton::action_match(const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float p_deadzone) const { Ref<InputEventMouseButton> mb = p_event; if (mb.is_null()) return false; - return mb->button_index == button_index; + bool match = mb->button_index == button_index; + if (match) { + if (p_pressed != NULL) + *p_pressed = mb->is_pressed(); + if (p_strength != NULL) + *p_strength = (*p_pressed) ? 1.0f : 0.0f; + } + + return match; } String InputEventMouseButton::as_text() const { @@ -609,6 +639,7 @@ void InputEventJoypadMotion::set_axis_value(float p_value) { axis_value = p_value; } + float InputEventJoypadMotion::get_axis_value() const { return axis_value; @@ -616,16 +647,25 @@ float InputEventJoypadMotion::get_axis_value() const { bool InputEventJoypadMotion::is_pressed() const { - return Math::abs(axis_value) > 0.5f; + return Math::abs(axis_value) >= 0.5f; } -bool InputEventJoypadMotion::action_match(const Ref<InputEvent> &p_event) const { +bool InputEventJoypadMotion::action_match(const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float p_deadzone) const { Ref<InputEventJoypadMotion> jm = p_event; if (jm.is_null()) return false; - return (axis == jm->axis && ((axis_value < 0) == (jm->axis_value < 0) || jm->axis_value == 0)); + bool match = (axis == jm->axis); // Matches even if not in the same direction, but returns a "not pressed" event. + if (match) { + bool same_direction = (((axis_value < 0) == (jm->axis_value < 0)) || jm->axis_value == 0); + bool pressed = same_direction ? Math::abs(jm->get_axis_value()) >= p_deadzone : false; + if (p_pressed != NULL) + *p_pressed = pressed; + if (p_strength != NULL) + *p_strength = pressed ? CLAMP(Math::inverse_lerp(p_deadzone, 1.0f, Math::abs(jm->get_axis_value())), 0.0f, 1.0f) : 0.0f; + } + return match; } String InputEventJoypadMotion::as_text() const { @@ -680,13 +720,21 @@ float InputEventJoypadButton::get_pressure() const { return pressure; } -bool InputEventJoypadButton::action_match(const Ref<InputEvent> &p_event) const { +bool InputEventJoypadButton::action_match(const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float p_deadzone) const { Ref<InputEventJoypadButton> jb = p_event; if (jb.is_null()) return false; - return button_index == jb->button_index; + bool match = button_index == jb->button_index; + if (match) { + if (p_pressed != NULL) + *p_pressed = jb->is_pressed(); + if (p_strength != NULL) + *p_strength = (*p_pressed) ? 1.0f : 0.0f; + } + + return match; } String InputEventJoypadButton::as_text() const { @@ -961,6 +1009,11 @@ Ref<InputEvent> InputEventMagnifyGesture::xformed_by(const Transform2D &p_xform, return ev; } +String InputEventMagnifyGesture::as_text() const { + + return "InputEventMagnifyGesture : factor=" + rtos(get_factor()) + ", position=(" + String(get_position()) + ")"; +} + void InputEventMagnifyGesture::_bind_methods() { ClassDB::bind_method(D_METHOD("set_factor", "factor"), &InputEventMagnifyGesture::set_factor); @@ -998,6 +1051,11 @@ Ref<InputEvent> InputEventPanGesture::xformed_by(const Transform2D &p_xform, con return ev; } +String InputEventPanGesture::as_text() const { + + return "InputEventPanGesture : delta=(" + String(get_delta()) + "), position=(" + String(get_position()) + ")"; +} + void InputEventPanGesture::_bind_methods() { ClassDB::bind_method(D_METHOD("set_delta", "delta"), &InputEventPanGesture::set_delta); diff --git a/core/os/input_event.h b/core/os/input_event.h index 53da79f59f..037649ed60 100644 --- a/core/os/input_event.h +++ b/core/os/input_event.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef INPUT_EVENT_H #define INPUT_EVENT_H @@ -109,8 +110,8 @@ enum JoystickList { JOY_WII_C = JOY_BUTTON_5, JOY_WII_Z = JOY_BUTTON_6, - JOY_WII_MINUS = JOY_BUTTON_9, - JOY_WII_PLUS = JOY_BUTTON_10, + JOY_WII_MINUS = JOY_BUTTON_10, + JOY_WII_PLUS = JOY_BUTTON_11, // end of history @@ -153,16 +154,21 @@ public: void set_device(int p_device); int get_device() const; + bool is_action(const StringName &p_action) const; + bool is_action_pressed(const StringName &p_action) const; + bool is_action_released(const StringName &p_action) const; + float get_action_strength(const StringName &p_action) const; + + // To be removed someday, since they do not make sense for all events virtual bool is_pressed() const; - virtual bool is_action(const StringName &p_action) const; - virtual bool is_action_pressed(const StringName &p_action) const; - virtual bool is_action_released(const StringName &p_action) const; virtual bool is_echo() const; + // ...-. + virtual String as_text() const; virtual Ref<InputEvent> xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs = Vector2()) const; - virtual bool action_match(const Ref<InputEvent> &p_event) const; + virtual bool action_match(const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float p_deadzone) const; virtual bool shortcut_match(const Ref<InputEvent> &p_event) const; virtual bool is_action_type() const; @@ -243,7 +249,7 @@ public: uint32_t get_scancode_with_modifiers() const; - virtual bool action_match(const Ref<InputEvent> &p_event) const; + virtual bool action_match(const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float p_deadzone) const; virtual bool shortcut_match(const Ref<InputEvent> &p_event) const; virtual bool is_action_type() const { return true; } @@ -304,7 +310,7 @@ public: bool is_doubleclick() const; virtual Ref<InputEvent> xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs = Vector2()) const; - virtual bool action_match(const Ref<InputEvent> &p_event) const; + virtual bool action_match(const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float p_deadzone) const; virtual bool is_action_type() const { return true; } virtual String as_text() const; @@ -351,7 +357,8 @@ public: float get_axis_value() const; virtual bool is_pressed() const; - virtual bool action_match(const Ref<InputEvent> &p_event) const; + + virtual bool action_match(const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float p_deadzone) const; virtual bool is_action_type() const { return true; } virtual String as_text() const; @@ -378,7 +385,7 @@ public: void set_pressure(float p_pressure); float get_pressure() const; - virtual bool action_match(const Ref<InputEvent> &p_event) const; + virtual bool action_match(const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float p_deadzone) const; virtual bool is_action_type() const { return true; } virtual String as_text() const; @@ -493,6 +500,7 @@ public: real_t get_factor() const; virtual Ref<InputEvent> xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs = Vector2()) const; + virtual String as_text() const; InputEventMagnifyGesture(); }; @@ -510,6 +518,7 @@ public: Vector2 get_delta() const; virtual Ref<InputEvent> xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs = Vector2()) const; + virtual String as_text() const; InputEventPanGesture(); }; diff --git a/core/os/keyboard.cpp b/core/os/keyboard.cpp index 00d78d71f7..9dfc91e308 100644 --- a/core/os/keyboard.cpp +++ b/core/os/keyboard.cpp @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #include "keyboard.h" #include "os/os.h" @@ -460,99 +461,6 @@ const char *find_keycode_name(int p_keycode) { return ""; } -struct _KeyCodeReplace { - int from; - int to; -}; - -static const _KeyCodeReplace _keycode_replace_qwertz[] = { - { KEY_Y, KEY_Z }, - { KEY_Z, KEY_Y }, - { 0, 0 } -}; - -static const _KeyCodeReplace _keycode_replace_azerty[] = { - { KEY_W, KEY_Z }, - { KEY_Z, KEY_W }, - { KEY_A, KEY_Q }, - { KEY_Q, KEY_A }, - { KEY_SEMICOLON, KEY_M }, - { KEY_M, KEY_SEMICOLON }, - { 0, 0 } -}; - -static const _KeyCodeReplace _keycode_replace_qzerty[] = { - { KEY_W, KEY_Z }, - { KEY_Z, KEY_W }, - { KEY_SEMICOLON, KEY_M }, - { KEY_M, KEY_SEMICOLON }, - { 0, 0 } -}; - -static const _KeyCodeReplace _keycode_replace_dvorak[] = { - { KEY_UNDERSCORE, KEY_BRACELEFT }, - { KEY_EQUAL, KEY_BRACERIGHT }, - { KEY_Q, KEY_APOSTROPHE }, - { KEY_W, KEY_COMMA }, - { KEY_E, KEY_PERIOD }, - { KEY_R, KEY_P }, - { KEY_T, KEY_Y }, - { KEY_Y, KEY_F }, - { KEY_U, KEY_G }, - { KEY_I, KEY_C }, - { KEY_O, KEY_R }, - { KEY_P, KEY_L }, - { KEY_BRACELEFT, KEY_SLASH }, - { KEY_BRACERIGHT, KEY_EQUAL }, - { KEY_A, KEY_A }, - { KEY_S, KEY_O }, - { KEY_D, KEY_E }, - { KEY_F, KEY_U }, - { KEY_G, KEY_I }, - { KEY_H, KEY_D }, - { KEY_J, KEY_H }, - { KEY_K, KEY_T }, - { KEY_L, KEY_N }, - { KEY_SEMICOLON, KEY_S }, - { KEY_APOSTROPHE, KEY_UNDERSCORE }, - { KEY_Z, KEY_SEMICOLON }, - { KEY_X, KEY_Q }, - { KEY_C, KEY_J }, - { KEY_V, KEY_K }, - { KEY_B, KEY_X }, - { KEY_N, KEY_B }, - { KEY_M, KEY_M }, - { KEY_COMMA, KEY_W }, - { KEY_PERIOD, KEY_V }, - { KEY_SLASH, KEY_Z }, - { 0, 0 } -}; - -static const _KeyCodeReplace _keycode_replace_neo[] = { - { 0, 0 } -}; - -static const _KeyCodeReplace _keycode_replace_colemak[] = { - { KEY_E, KEY_F }, - { KEY_R, KEY_P }, - { KEY_T, KEY_G }, - { KEY_Y, KEY_J }, - { KEY_U, KEY_L }, - { KEY_I, KEY_U }, - { KEY_O, KEY_Y }, - { KEY_P, KEY_SEMICOLON }, - { KEY_S, KEY_R }, - { KEY_D, KEY_S }, - { KEY_F, KEY_T }, - { KEY_G, KEY_D }, - { KEY_J, KEY_N }, - { KEY_K, KEY_E }, - { KEY_L, KEY_I }, - { KEY_SEMICOLON, KEY_O }, - { KEY_N, KEY_K }, - { 0, 0 } -}; - int keycode_get_count() { const _KeyCodeText *kct = &_keycodes[0]; @@ -573,31 +481,3 @@ int keycode_get_value_by_index(int p_index) { const char *keycode_get_name_by_index(int p_index) { return _keycodes[p_index].text; } - -int latin_keyboard_keycode_convert(int p_keycode) { - - const _KeyCodeReplace *kcr = NULL; - switch (OS::get_singleton()->get_latin_keyboard_variant()) { - - case OS::LATIN_KEYBOARD_QWERTY: return p_keycode; break; - case OS::LATIN_KEYBOARD_QWERTZ: kcr = _keycode_replace_qwertz; break; - case OS::LATIN_KEYBOARD_AZERTY: kcr = _keycode_replace_azerty; break; - case OS::LATIN_KEYBOARD_QZERTY: kcr = _keycode_replace_qzerty; break; - case OS::LATIN_KEYBOARD_DVORAK: kcr = _keycode_replace_dvorak; break; - case OS::LATIN_KEYBOARD_NEO: kcr = _keycode_replace_neo; break; - case OS::LATIN_KEYBOARD_COLEMAK: kcr = _keycode_replace_colemak; break; - default: return p_keycode; - } - - if (!kcr) { - return p_keycode; - } - - while (kcr->from) { - if (kcr->from == p_keycode) - return kcr->to; - kcr++; - } - - return p_keycode; -} diff --git a/core/os/keyboard.h b/core/os/keyboard.h index f910f07f99..a0e6f8b2ef 100644 --- a/core/os/keyboard.h +++ b/core/os/keyboard.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef KEYBOARD_H #define KEYBOARD_H @@ -330,6 +331,5 @@ const char *find_keycode_name(int p_keycode); int keycode_get_count(); int keycode_get_value_by_index(int p_index); const char *keycode_get_name_by_index(int p_index); -int latin_keyboard_keycode_convert(int p_keycode); #endif diff --git a/core/os/main_loop.cpp b/core/os/main_loop.cpp index 186acb0342..916c86613e 100644 --- a/core/os/main_loop.cpp +++ b/core/os/main_loop.cpp @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #include "main_loop.h" #include "script_language.h" diff --git a/core/os/main_loop.h b/core/os/main_loop.h index e5d917ec6b..546e4e280c 100644 --- a/core/os/main_loop.h +++ b/core/os/main_loop.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef MAIN_LOOP_H #define MAIN_LOOP_H diff --git a/core/os/memory.cpp b/core/os/memory.cpp index a8b49a0852..3eab4343a9 100644 --- a/core/os/memory.cpp +++ b/core/os/memory.cpp @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #include "memory.h" #include "copymem.h" #include "core/safe_refcount.h" diff --git a/core/os/memory.h b/core/os/memory.h index 27eb57c873..f5c6c0b38a 100644 --- a/core/os/memory.h +++ b/core/os/memory.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef MEMORY_H #define MEMORY_H diff --git a/core/os/mutex.cpp b/core/os/mutex.cpp index 21480fecee..7c4ea2323c 100644 --- a/core/os/mutex.cpp +++ b/core/os/mutex.cpp @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #include "mutex.h" #include "error_macros.h" #include <stddef.h> diff --git a/core/os/mutex.h b/core/os/mutex.h index ecd1f59151..9debe7f41b 100644 --- a/core/os/mutex.h +++ b/core/os/mutex.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef MUTEX_H #define MUTEX_H diff --git a/core/os/os.cpp b/core/os/os.cpp index bdcdfed060..854d554b10 100644 --- a/core/os/os.cpp +++ b/core/os/os.cpp @@ -27,12 +27,14 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #include "os.h" #include "dir_access.h" #include "input.h" #include "os/file_access.h" #include "project_settings.h" +#include "servers/audio_server.h" #include "version_generated.gen.h" #include <stdarg.h> @@ -409,7 +411,7 @@ Error OS::set_cwd(const String &p_cwd) { bool OS::has_touchscreen_ui_hint() const { //return false; - return Input::get_singleton() && Input::get_singleton()->is_emulating_touchscreen(); + return Input::get_singleton() && Input::get_singleton()->is_emulating_touch_from_mouse(); } int OS::get_free_static_memory() const { @@ -615,6 +617,45 @@ bool OS::has_feature(const String &p_feature) { return false; } +void OS::center_window() { + + if (is_window_fullscreen()) return; + + Size2 scr = get_screen_size(get_current_screen()); + Size2 wnd = get_real_window_size(); + int x = scr.width / 2 - wnd.width / 2; + int y = scr.height / 2 - wnd.height / 2; + set_window_position(Vector2(x, y)); +} + +int OS::get_video_driver_count() const { + + return 2; +} + +const char *OS::get_video_driver_name(int p_driver) const { + + switch (p_driver) { + case VIDEO_DRIVER_GLES2: + return "GLES2"; + case VIDEO_DRIVER_GLES3: + default: + return "GLES3"; + } +} + +int OS::get_audio_driver_count() const { + + return AudioDriverManager::get_driver_count(); +} + +const char *OS::get_audio_driver_name(int p_driver) const { + + AudioDriver *driver = AudioDriverManager::get_driver(p_driver); + ERR_FAIL_COND_V(!driver, ""); + return AudioDriverManager::get_driver(p_driver)->get_name(); +} + OS::OS() { void *volatile stack_bottom; diff --git a/core/os/os.h b/core/os/os.h index c9c228cfaf..f6404468b1 100644 --- a/core/os/os.h +++ b/core/os/os.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef OS_H #define OS_H @@ -43,6 +44,12 @@ @author Juan Linietsky <reduzio@gmail.com> */ +enum VideoDriver { + VIDEO_DRIVER_GLES3, + VIDEO_DRIVER_GLES2, + VIDEO_DRIVER_MAX, +}; + class OS { static OS *singleton; @@ -93,15 +100,17 @@ public: bool resizable; bool borderless_window; bool maximized; + bool always_on_top; bool use_vsync; float get_aspect() const { return (float)width / (float)height; } - VideoMode(int p_width = 1024, int p_height = 600, bool p_fullscreen = false, bool p_resizable = true, bool p_borderless_window = false, bool p_maximized = false, bool p_use_vsync = false) { + VideoMode(int p_width = 1024, int p_height = 600, bool p_fullscreen = false, bool p_resizable = true, bool p_borderless_window = false, bool p_maximized = false, bool p_always_on_top = false, bool p_use_vsync = false) { width = p_width; height = p_height; fullscreen = p_fullscreen; resizable = p_resizable; borderless_window = p_borderless_window; maximized = p_maximized; + always_on_top = p_always_on_top; use_vsync = p_use_vsync; } }; @@ -112,16 +121,10 @@ protected: RenderThreadMode _render_thread_mode; // functions used by main to initialize/deintialize the OS - virtual int get_video_driver_count() const = 0; - virtual const char *get_video_driver_name(int p_driver) const = 0; - - virtual int get_audio_driver_count() const = 0; - virtual const char *get_audio_driver_name(int p_driver) const = 0; - void add_logger(Logger *p_logger); virtual void initialize_core() = 0; - virtual void initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver) = 0; + virtual Error initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver) = 0; virtual void set_main_loop(MainLoop *p_main_loop) = 0; virtual void delete_main_loop() = 0; @@ -172,6 +175,12 @@ public: virtual VideoMode get_video_mode(int p_screen = 0) const = 0; virtual void get_fullscreen_mode_list(List<VideoMode> *p_list, int p_screen = 0) const = 0; + virtual int get_video_driver_count() const; + virtual const char *get_video_driver_name(int p_driver) const; + + virtual int get_audio_driver_count() const; + virtual const char *get_audio_driver_name(int p_driver) const; + virtual int get_screen_count() const { return 1; } virtual int get_current_screen() const { return 0; } virtual void set_current_screen(int p_screen) {} @@ -181,6 +190,7 @@ public: virtual Point2 get_window_position() const { return Vector2(); } virtual void set_window_position(const Point2 &p_position) {} virtual Size2 get_window_size() const = 0; + virtual Size2 get_real_window_size() const { return get_window_size(); } virtual void set_window_size(const Size2 p_size) {} virtual void set_window_fullscreen(bool p_enabled) {} virtual bool is_window_fullscreen() const { return true; } @@ -190,7 +200,22 @@ public: virtual bool is_window_minimized() const { return false; } virtual void set_window_maximized(bool p_enabled) {} virtual bool is_window_maximized() const { return true; } + virtual void set_window_always_on_top(bool p_enabled) {} + virtual bool is_window_always_on_top() const { return false; } virtual void request_attention() {} + virtual void center_window(); + + // Returns window area free of hardware controls and other obstacles. + // The application should use this to determine where to place UI elements. + // + // Keep in mind the area returned is in window coordinates rather than + // viewport coordinates - you should perform the conversion on your own. + // + // The maximum size of the area is Rect2(0, 0, window_size.width, window_size.height). + virtual Rect2 get_window_safe_area() const { + Size2 window_size = get_window_size(); + return Rect2(0, 0, window_size.width, window_size.height); + } virtual void set_borderless_window(bool p_borderless) {} virtual bool get_borderless_window() { return 0; } @@ -295,6 +320,7 @@ public: virtual void disable_crash_handler() {} virtual bool is_disable_crash_handler() const { return false; } + virtual void initialize_debugging() {} enum CursorShape { CURSOR_ARROW, diff --git a/core/os/rw_lock.cpp b/core/os/rw_lock.cpp index 9603ccf0bb..35489490ed 100644 --- a/core/os/rw_lock.cpp +++ b/core/os/rw_lock.cpp @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #include "rw_lock.h" #include "error_macros.h" diff --git a/core/os/rw_lock.h b/core/os/rw_lock.h index d0ce38f453..9053794c83 100644 --- a/core/os/rw_lock.h +++ b/core/os/rw_lock.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef RWLOCK_H #define RWLOCK_H diff --git a/core/os/semaphore.cpp b/core/os/semaphore.cpp index 9455124e48..0377aeeb29 100644 --- a/core/os/semaphore.cpp +++ b/core/os/semaphore.cpp @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #include "semaphore.h" #include "error_macros.h" diff --git a/core/os/semaphore.h b/core/os/semaphore.h index 8bad64ace3..f3021bf74c 100644 --- a/core/os/semaphore.h +++ b/core/os/semaphore.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef SEMAPHORE_H #define SEMAPHORE_H diff --git a/core/os/shell.cpp b/core/os/shell.cpp index 781d922d4b..32649a0667 100644 --- a/core/os/shell.cpp +++ b/core/os/shell.cpp @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #include "shell.h" Shell *Shell::singleton = NULL; diff --git a/core/os/shell.h b/core/os/shell.h index 84ac7eae42..d3d92028ea 100644 --- a/core/os/shell.h +++ b/core/os/shell.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef SHELL_H #define SHELL_H diff --git a/core/os/thread.cpp b/core/os/thread.cpp index 13bf147caf..250cf80a37 100644 --- a/core/os/thread.cpp +++ b/core/os/thread.cpp @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #include "thread.h" Thread *(*Thread::create_func)(ThreadCreateCallback, void *, const Settings &) = NULL; diff --git a/core/os/thread.h b/core/os/thread.h index 92dd00cf0d..c2947bccab 100644 --- a/core/os/thread.h +++ b/core/os/thread.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef THREAD_H #define THREAD_H diff --git a/core/os/thread_dummy.cpp b/core/os/thread_dummy.cpp index 2f8f3d4940..b6371235c4 100644 --- a/core/os/thread_dummy.cpp +++ b/core/os/thread_dummy.cpp @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #include "thread_dummy.h" #include "memory.h" @@ -54,3 +55,11 @@ Semaphore *SemaphoreDummy::create() { void SemaphoreDummy::make_default() { Semaphore::create_func = &SemaphoreDummy::create; }; + +RWLock *RWLockDummy::create() { + return memnew(RWLockDummy); +}; + +void RWLockDummy::make_default() { + RWLock::create_func = &RWLockDummy::create; +}; diff --git a/core/os/thread_dummy.h b/core/os/thread_dummy.h index 5681f45092..74957b95fe 100644 --- a/core/os/thread_dummy.h +++ b/core/os/thread_dummy.h @@ -27,10 +27,12 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef THREAD_DUMMY_H #define THREAD_DUMMY_H #include "mutex.h" +#include "rw_lock.h" #include "semaphore.h" #include "thread.h" @@ -68,4 +70,20 @@ public: static void make_default(); }; +class RWLockDummy : public RWLock { + + static RWLock *create(); + +public: + virtual void read_lock() {} + virtual void read_unlock() {} + virtual Error read_try_lock() { return OK; } + + virtual void write_lock() {} + virtual void write_unlock() {} + virtual Error write_try_lock() { return OK; } + + static void make_default(); +}; + #endif diff --git a/core/os/thread_safe.cpp b/core/os/thread_safe.cpp index 394876ae16..acb37df02b 100644 --- a/core/os/thread_safe.cpp +++ b/core/os/thread_safe.cpp @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #include "thread_safe.h" #include "error_macros.h" #include "os/memory.h" diff --git a/core/os/thread_safe.h b/core/os/thread_safe.h index 05510bcbb9..f0876f38a1 100644 --- a/core/os/thread_safe.h +++ b/core/os/thread_safe.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef THREAD_SAFE_H #define THREAD_SAFE_H diff --git a/core/os/threaded_array_processor.cpp b/core/os/threaded_array_processor.cpp deleted file mode 100644 index 8e92508ea5..0000000000 --- a/core/os/threaded_array_processor.cpp +++ /dev/null @@ -1,2 +0,0 @@ -#include "threaded_array_processor.h" - diff --git a/core/os/threaded_array_processor.h b/core/os/threaded_array_processor.h index e584fbb193..e0fb589767 100644 --- a/core/os/threaded_array_processor.h +++ b/core/os/threaded_array_processor.h @@ -1,3 +1,33 @@ +/*************************************************************************/ +/* threaded_array_processor.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + #ifndef THREADED_ARRAY_PROCESSOR_H #define THREADED_ARRAY_PROCESSOR_H diff --git a/core/packed_data_container.cpp b/core/packed_data_container.cpp index 4d5890685b..eaccdba9bf 100644 --- a/core/packed_data_container.cpp +++ b/core/packed_data_container.cpp @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #include "packed_data_container.h" #include "core_string_names.h" diff --git a/core/packed_data_container.h b/core/packed_data_container.h index b711d795de..fe36417000 100644 --- a/core/packed_data_container.h +++ b/core/packed_data_container.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef PACKED_DATA_CONTAINER_H #define PACKED_DATA_CONTAINER_H diff --git a/core/pair.h b/core/pair.h index 349c034ab7..1d35ae1b6c 100644 --- a/core/pair.h +++ b/core/pair.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef PAIR_H #define PAIR_H diff --git a/core/path_remap.cpp b/core/path_remap.cpp index d92d034f1a..80308d72c0 100644 --- a/core/path_remap.cpp +++ b/core/path_remap.cpp @@ -27,4 +27,5 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #include "path_remap.h" diff --git a/core/path_remap.h b/core/path_remap.h index 1b40c9cace..5e25628aeb 100644 --- a/core/path_remap.h +++ b/core/path_remap.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef PATH_REMAP_H #define PATH_REMAP_H diff --git a/core/pool_allocator.cpp b/core/pool_allocator.cpp index 13d5c5082f..017586b92a 100644 --- a/core/pool_allocator.cpp +++ b/core/pool_allocator.cpp @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #include "pool_allocator.h" #include "core/os/os.h" @@ -89,7 +90,7 @@ bool PoolAllocator::find_hole(EntryArrayPos *p_pos, int p_for_size) { int hole_size = entry.pos - prev_entry_end_pos; - /* detemine if what we want fits in that hole */ + /* determine if what we want fits in that hole */ if (hole_size >= p_for_size) { *p_pos = i; return true; @@ -99,7 +100,7 @@ bool PoolAllocator::find_hole(EntryArrayPos *p_pos, int p_for_size) { prev_entry_end_pos = entry_end(entry); } - /* No holes between entrys, check at the end..*/ + /* No holes between entries, check at the end..*/ if ((pool_size - prev_entry_end_pos) >= p_for_size) { *p_pos = entry_count; diff --git a/core/pool_allocator.h b/core/pool_allocator.h index a1cc65f1fd..d9731aa3eb 100644 --- a/core/pool_allocator.h +++ b/core/pool_allocator.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef POOL_ALLOCATOR_H #define POOL_ALLOCATOR_H diff --git a/core/print_string.cpp b/core/print_string.cpp index 2b366f8145..0355154488 100644 --- a/core/print_string.cpp +++ b/core/print_string.cpp @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #include "print_string.h" #include "os/os.h" diff --git a/core/print_string.h b/core/print_string.h index c3eaf3f336..3465888d4c 100644 --- a/core/print_string.h +++ b/core/print_string.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef PRINT_STRING_H #define PRINT_STRING_H diff --git a/core/project_settings.cpp b/core/project_settings.cpp index bb2408fb1f..ac4a4b7d15 100644 --- a/core/project_settings.cpp +++ b/core/project_settings.cpp @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #include "project_settings.h" #include "bind/core_bind.h" @@ -41,7 +42,7 @@ #include "variant_parser.h" #include <zlib.h> -#define FORMAT_VERSION 3 +#define FORMAT_VERSION 4 ProjectSettings *ProjectSettings::singleton = NULL; @@ -166,7 +167,7 @@ bool ProjectSettings::_set(const StringName &p_name, const Variant &p_value) { } if (props.has(p_name)) { - if (!props[p_name].overrided) + if (!props[p_name].overridden) props[p_name].variant = p_value; } else { @@ -261,18 +262,35 @@ bool ProjectSettings::_load_resource_pack(const String &p_pack) { return true; } +void ProjectSettings::_convert_to_last_version() { + if (!has_setting("config_version") || (int)get_setting("config_version") <= 3) { + + // Converts the actions from array to dictionary (array of events to dictionary with deadzone + events) + for (Map<StringName, ProjectSettings::VariantContainer>::Element *E = props.front(); E; E = E->next()) { + Variant value = E->get().variant; + if (String(E->key()).begins_with("input/") && value.get_type() == Variant::ARRAY) { + Array array = value; + Dictionary action; + action["deadzone"] = Variant(0.5f); + action["events"] = array; + E->get().variant = action; + } + } + } +} + Error ProjectSettings::setup(const String &p_path, const String &p_main_pack, bool p_upwards) { //If looking for files in network, just use network! if (FileAccessNetworkClient::get_singleton()) { - if (_load_settings("res://project.godot") == OK || _load_settings_binary("res://project.binary") == OK) { - - _load_settings("res://override.cfg"); + Error err = _load_settings_text_or_binary("res://project.godot", "res://project.binary"); + if (err == OK) { + // Optional, we don't mind if it fails + _load_settings_text("res://override.cfg"); } - - return OK; + return err; } String exec_path = OS::get_singleton()->get_executable_path(); @@ -284,12 +302,13 @@ Error ProjectSettings::setup(const String &p_path, const String &p_main_pack, bo bool ok = _load_resource_pack(p_main_pack); ERR_FAIL_COND_V(!ok, ERR_CANT_OPEN); - if (_load_settings("res://project.godot") == OK || _load_settings_binary("res://project.binary") == OK) { - //load override from location of the main pack - _load_settings(p_main_pack.get_base_dir().plus_file("override.cfg")); + Error err = _load_settings_text_or_binary("res://project.godot", "res://project.binary"); + if (err == OK) { + // Load override from location of the main pack + // Optional, we don't mind if it fails + _load_settings_text(p_main_pack.get_base_dir().plus_file("override.cfg")); } - - return OK; + return err; } //Attempt with execname.pck @@ -312,12 +331,13 @@ Error ProjectSettings::setup(const String &p_path, const String &p_main_pack, bo // if we opened our package, try and load our project... if (found) { - if (_load_settings("res://project.godot") == OK || _load_settings_binary("res://project.binary") == OK) { - // load override from location of executable - _load_settings(exec_path.get_base_dir().plus_file("override.cfg")); + Error err = _load_settings_text_or_binary("res://project.godot", "res://project.binary"); + if (err == OK) { + // Load override from location of executable + // Optional, we don't mind if it fails + _load_settings_text(exec_path.get_base_dir().plus_file("override.cfg")); } - - return OK; + return err; } } @@ -333,11 +353,13 @@ Error ProjectSettings::setup(const String &p_path, const String &p_main_pack, bo // data.pck and data.zip are deprecated and no longer supported, apologies. // make sure this is loaded from the resource path - if (_load_settings("res://project.godot") == OK || _load_settings_binary("res://project.binary") == OK) { - _load_settings("res://override.cfg"); + Error err = _load_settings_text_or_binary("res://project.godot", "res://project.binary"); + if (err == OK) { + // Optional, we don't mind if it fails + _load_settings_text("res://override.cfg"); } - return OK; + return err; } //Nothing was found, try to find a project.godot somewhere! @@ -349,20 +371,23 @@ Error ProjectSettings::setup(const String &p_path, const String &p_main_pack, bo String candidate = d->get_current_dir(); String current_dir = d->get_current_dir(); + bool found = false; + Error err; while (true) { - //try to load settings in ascending through dirs shape! - if (_load_settings(current_dir + "/project.godot") == OK || _load_settings_binary(current_dir + "/project.binary") == OK) { - - _load_settings(current_dir + "/override.cfg"); + err = _load_settings_text_or_binary(current_dir.plus_file("project.godot"), current_dir.plus_file("project.binary")); + if (err == OK) { + // Optional, we don't mind if it fails + _load_settings_text(current_dir.plus_file("override.cfg")); candidate = current_dir; found = true; break; } if (p_upwards) { + // Try to load settings ascending through dirs shape! d->change_dir(".."); if (d->get_current_dir() == current_dir) break; //not doing anything useful @@ -377,11 +402,13 @@ Error ProjectSettings::setup(const String &p_path, const String &p_main_pack, bo memdelete(d); if (!found) - return ERR_FILE_NOT_FOUND; + return err; if (resource_path.length() && resource_path[resource_path.length() - 1] == '/') resource_path = resource_path.substr(0, resource_path.length() - 1); // chop end + _convert_to_last_version(); + return OK; } @@ -439,13 +466,17 @@ Error ProjectSettings::_load_settings_binary(const String p_path) { return OK; } -Error ProjectSettings::_load_settings(const String p_path) { + +Error ProjectSettings::_load_settings_text(const String p_path) { Error err; FileAccess *f = FileAccess::open(p_path, FileAccess::READ, &err); - if (!f) - return ERR_CANT_OPEN; + if (!f) { + // FIXME: Above 'err' error code is ERR_FILE_CANT_OPEN if the file is missing + // This needs to be streamlined if we want decent error reporting + return ERR_FILE_NOT_FOUND; + } VariantParser::StreamFile stream; stream.f = f; @@ -470,7 +501,7 @@ Error ProjectSettings::_load_settings(const String p_path) { memdelete(f); return OK; } else if (err != OK) { - ERR_PRINTS("ProjectSettings::load - " + p_path + ":" + itos(lines) + " error: " + error_text); + ERR_PRINTS("Error parsing " + p_path + " at line " + itos(lines) + ": " + error_text + " File might be corrupted."); memdelete(f); return err; } @@ -496,6 +527,23 @@ Error ProjectSettings::_load_settings(const String p_path) { return OK; } +Error ProjectSettings::_load_settings_text_or_binary(const String p_text_path, const String p_bin_path) { + + // Attempt first to load the text-based project.godot file + Error err_text = _load_settings_text(p_text_path); + if (err_text == OK) { + return OK; + } else if (err_text != ERR_FILE_NOT_FOUND) { + // If the text-based file exists but can't be loaded, we want to know it + ERR_PRINTS("Couldn't load file '" + p_text_path + "', error code " + itos(err_text) + "."); + return err_text; + } + + // Fallback to binary project.binary file if text-based was not found + Error err_bin = _load_settings_binary(p_bin_path); + return err_bin; +} + int ProjectSettings::get_order(const String &p_name) const { ERR_FAIL_COND_V(!props.has(p_name), -1); @@ -524,7 +572,7 @@ void ProjectSettings::clear(const String &p_name) { Error ProjectSettings::save() { - return save_custom(get_resource_path() + "/project.godot"); + return save_custom(get_resource_path().plus_file("project.godot")); } Error ProjectSettings::_save_settings_binary(const String &p_file, const Map<String, List<String> > &props, const CustomMap &p_custom, const String &p_custom_features) { @@ -663,7 +711,10 @@ Error ProjectSettings::_save_settings_text(const String &p_file, const Map<Strin String vstr; VariantWriter::write_to_string(value, vstr); - file->store_string(F->get() + "=" + vstr + "\n"); + if (F->get().find(" ") != -1) + file->store_string(F->get().quote() + "=" + vstr + "\n"); + else + file->store_string(F->get() + "=" + vstr + "\n"); } } @@ -765,12 +816,11 @@ Error ProjectSettings::save_custom(const String &p_path, const CustomMap &p_cust Variant _GLOBAL_DEF(const String &p_var, const Variant &p_default) { Variant ret; - if (ProjectSettings::get_singleton()->has_setting(p_var)) { - ret = ProjectSettings::get_singleton()->get(p_var); - } else { + if (!ProjectSettings::get_singleton()->has_setting(p_var)) { ProjectSettings::get_singleton()->set(p_var, p_default); - ret = p_default; } + ret = ProjectSettings::get_singleton()->get(p_var); + ProjectSettings::get_singleton()->set_initial_value(p_var, p_default); ProjectSettings::get_singleton()->set_builtin_order(p_var); return ret; @@ -998,6 +1048,20 @@ ProjectSettings::ProjectSettings() { GLOBAL_DEF("input/ui_page_down", va); input_presets.push_back("input/ui_page_down"); + va = Array(); + key.instance(); + key->set_scancode(KEY_HOME); + va.push_back(key); + GLOBAL_DEF("input/ui_home", va); + input_presets.push_back("input/ui_home"); + + va = Array(); + key.instance(); + key->set_scancode(KEY_END); + va.push_back(key); + GLOBAL_DEF("input/ui_end", va); + input_presets.push_back("input/ui_end"); + //GLOBAL_DEF("display/window/handheld/orientation", "landscape"); custom_prop_info["display/window/handheld/orientation"] = PropertyInfo(Variant::STRING, "display/window/handheld/orientation", PROPERTY_HINT_ENUM, "landscape,portrait,reverse_landscape,reverse_portrait,sensor_landscape,sensor_portrait,sensor"); diff --git a/core/project_settings.h b/core/project_settings.h index e60efea222..b01e7855aa 100644 --- a/core/project_settings.h +++ b/core/project_settings.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef GLOBAL_CONFIG_H #define GLOBAL_CONFIG_H @@ -57,19 +58,19 @@ protected: Variant variant; Variant initial; bool hide_from_editor; - bool overrided; + bool overridden; VariantContainer() : order(0), persist(false), hide_from_editor(false), - overrided(false) { + overridden(false) { } VariantContainer(const Variant &p_variant, int p_order, bool p_persist = false) : order(p_order), persist(p_persist), variant(p_variant), hide_from_editor(false), - overrided(false) { + overridden(false) { } }; @@ -92,14 +93,17 @@ protected: static ProjectSettings *singleton; - Error _load_settings(const String p_path); + Error _load_settings_text(const String p_path); Error _load_settings_binary(const String p_path); + Error _load_settings_text_or_binary(const String p_text_path, const String p_bin_path); Error _save_settings_text(const String &p_file, const Map<String, List<String> > &props, const CustomMap &p_custom = CustomMap(), const String &p_custom_features = String()); Error _save_settings_binary(const String &p_file, const Map<String, List<String> > &props, const CustomMap &p_custom = CustomMap(), const String &p_custom_features = String()); Error _save_custom_bnd(const String &p_file); + void _convert_to_last_version(); + bool _load_resource_pack(const String &p_pack); void _add_property_info_bind(const Dictionary &p_info); diff --git a/core/ref_ptr.cpp b/core/ref_ptr.cpp index 0f5abdd455..e3ef817df1 100644 --- a/core/ref_ptr.cpp +++ b/core/ref_ptr.cpp @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #include "ref_ptr.h" #include "reference.h" diff --git a/core/ref_ptr.h b/core/ref_ptr.h index 27acfb7982..a074718d22 100644 --- a/core/ref_ptr.h +++ b/core/ref_ptr.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef REF_PTR_H #define REF_PTR_H /** diff --git a/core/reference.cpp b/core/reference.cpp index 3b5a9bc7cc..c33a7c683c 100644 --- a/core/reference.cpp +++ b/core/reference.cpp @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #include "reference.h" #include "script_language.h" diff --git a/core/reference.h b/core/reference.h index 16b912a402..0d6b1ced6e 100644 --- a/core/reference.h +++ b/core/reference.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef REFERENCE_H #define REFERENCE_H @@ -62,7 +63,7 @@ public: template <class T> class Ref { - T *reference = NULL; + T *reference; void ref(const Ref &p_from) { @@ -212,10 +213,9 @@ public: Ref(T *p_reference) { + reference = NULL; if (p_reference) ref_pointer(p_reference); - else - reference = NULL; } Ref(const Variant &p_variant) { diff --git a/core/register_core_types.cpp b/core/register_core_types.cpp index 29c7cf4606..2a611ccf6a 100644 --- a/core/register_core_types.cpp +++ b/core/register_core_types.cpp @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #include "register_core_types.h" #include "bind/core_bind.h" @@ -41,6 +42,7 @@ #include "io/config_file.h" #include "io/http_client.h" #include "io/marshalls.h" +#include "io/multiplayer_api.h" #include "io/networked_multiplayer_peer.h" #include "io/packet_peer.h" #include "io/packet_peer_udp.h" @@ -144,6 +146,7 @@ void register_core_types() { ClassDB::register_virtual_class<PacketPeer>(); ClassDB::register_class<PacketPeerStream>(); ClassDB::register_virtual_class<NetworkedMultiplayerPeer>(); + ClassDB::register_class<MultiplayerAPI>(); ClassDB::register_class<MainLoop>(); //ClassDB::register_type<OptimizedSaver>(); ClassDB::register_class<Translation>(); diff --git a/core/register_core_types.h b/core/register_core_types.h index 4f5b7e03af..201da5cd07 100644 --- a/core/register_core_types.h +++ b/core/register_core_types.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef REGISTER_CORE_TYPES_H #define REGISTER_CORE_TYPES_H diff --git a/core/resource.cpp b/core/resource.cpp index 3e411a8753..179333aa14 100644 --- a/core/resource.cpp +++ b/core/resource.cpp @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #include "resource.h" #include "core_string_names.h" @@ -73,7 +74,7 @@ void Resource::set_path(const String &p_path, bool p_take_over) { bool exists = ResourceCache::resources.has(p_path); ResourceCache::lock->read_unlock(); - ERR_EXPLAIN("Another resource is loaded from path: " + p_path); + ERR_EXPLAIN("Another resource is loaded from path: " + p_path + " (possible cyclic resource inclusion)"); ERR_FAIL_COND(exists); } } @@ -225,7 +226,7 @@ Ref<Resource> Resource::duplicate(bool p_subresources) const { if (!(E->get().usage & PROPERTY_USAGE_STORAGE)) continue; - Variant p = get(E->get().name); + Variant p = get(E->get().name).duplicate(true); if (p.get_type() == Variant::OBJECT && p_subresources) { RES sr = p; diff --git a/core/resource.h b/core/resource.h index 4c5a44d7fd..60c63bfe7f 100644 --- a/core/resource.h +++ b/core/resource.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef RESOURCE_H #define RESOURCE_H diff --git a/core/rid.cpp b/core/rid.cpp index 3cfb28c044..9661af9271 100644 --- a/core/rid.cpp +++ b/core/rid.cpp @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #include "rid.h" RID_Data::~RID_Data() { diff --git a/core/rid.h b/core/rid.h index 3768083fe3..42306aea36 100644 --- a/core/rid.h +++ b/core/rid.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef RID_H #define RID_H diff --git a/core/ring_buffer.h b/core/ring_buffer.h index 4b4a7fe9cf..de4757612a 100644 --- a/core/ring_buffer.h +++ b/core/ring_buffer.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef RINGBUFFER_H #define RINGBUFFER_H @@ -40,7 +41,7 @@ class RingBuffer { int write_pos; int size_mask; - inline int inc(int &p_var, int p_size) { + inline int inc(int &p_var, int p_size) const { int ret = p_var; p_var += p_size; p_var = p_var & size_mask; @@ -50,7 +51,7 @@ class RingBuffer { public: T read() { ERR_FAIL_COND_V(space_left() < 1, T()); - return data[inc(read_pos, 1)]; + return data.ptr()[inc(read_pos, 1)]; }; int read(T *p_buf, int p_size, bool p_advance = true) { @@ -63,8 +64,9 @@ public: int end = pos + to_read; end = MIN(end, size()); int total = end - pos; + const T *read = data.ptr(); for (int i = 0; i < total; i++) { - p_buf[dst++] = data[pos + i]; + p_buf[dst++] = read[pos + i]; }; to_read -= total; pos = 0; @@ -75,7 +77,7 @@ public: return p_size; }; - int copy(T *p_buf, int p_offset, int p_size) { + int copy(T *p_buf, int p_offset, int p_size) const { int left = data_left(); if ((p_offset + p_size) > left) { @@ -101,7 +103,7 @@ public: return p_size; }; - int find(const T &t, int p_offset, int p_max_size) { + int find(const T &t, int p_offset, int p_max_size) const { int left = data_left(); if ((p_offset + p_max_size) > left) { @@ -164,7 +166,7 @@ public: return p_size; }; - inline int space_left() { + inline int space_left() const { int left = read_pos - write_pos; if (left < 0) { return size() + left - 1; @@ -174,11 +176,11 @@ public: }; return left - 1; }; - inline int data_left() { + inline int data_left() const { return size() - space_left() - 1; }; - inline int size() { + inline int size() const { return data.size(); }; diff --git a/core/safe_refcount.cpp b/core/safe_refcount.cpp index ff2f17103c..3b203f6977 100644 --- a/core/safe_refcount.cpp +++ b/core/safe_refcount.cpp @@ -119,8 +119,8 @@ _ALWAYS_INLINE_ uint64_t _atomic_exchange_if_greater_impl(register uint64_t *pw, // The actual advertised functions; they'll call the right implementation -uint32_t atomic_conditional_increment(register uint32_t *counter) { - return _atomic_conditional_increment_impl(counter); +uint32_t atomic_conditional_increment(register uint32_t *pw) { + return _atomic_conditional_increment_impl(pw); } uint32_t atomic_decrement(register uint32_t *pw) { @@ -143,8 +143,8 @@ uint32_t atomic_exchange_if_greater(register uint32_t *pw, register uint32_t val return _atomic_exchange_if_greater_impl(pw, val); } -uint64_t atomic_conditional_increment(register uint64_t *counter) { - return _atomic_conditional_increment_impl(counter); +uint64_t atomic_conditional_increment(register uint64_t *pw) { + return _atomic_conditional_increment_impl(pw); } uint64_t atomic_decrement(register uint64_t *pw) { diff --git a/core/safe_refcount.h b/core/safe_refcount.h index 217cf69145..eff209c2db 100644 --- a/core/safe_refcount.h +++ b/core/safe_refcount.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef SAFE_REFCOUNT_H #define SAFE_REFCOUNT_H diff --git a/core/script_debugger_local.cpp b/core/script_debugger_local.cpp index 83cdb348bd..55d7270473 100644 --- a/core/script_debugger_local.cpp +++ b/core/script_debugger_local.cpp @@ -27,13 +27,25 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #include "script_debugger_local.h" +#include "scene/main/scene_tree.h" #include "os/os.h" void ScriptDebuggerLocal::debug(ScriptLanguage *p_script, bool p_can_continue) { - print_line("Debugger Break, Reason: '" + p_script->debug_get_error() + "'"); + if (!target_function.empty()) { + String current_function = p_script->debug_get_stack_level_function(0); + if (current_function != target_function) { + set_depth(0); + set_lines_left(1); + return; + } + target_function = ""; + } + + print_line("\nDebugger Break, Reason: '" + p_script->debug_get_error() + "'"); print_line("*Frame " + itos(0) + " - " + p_script->debug_get_stack_level_source(0) + ":" + itos(p_script->debug_get_stack_level_line(0)) + " in function '" + p_script->debug_get_stack_level_function(0) + "'"); print_line("Enter \"help\" for assistance."); int current_frame = 0; @@ -43,8 +55,11 @@ void ScriptDebuggerLocal::debug(ScriptLanguage *p_script, bool p_can_continue) { OS::get_singleton()->print("debug> "); String line = OS::get_singleton()->get_stdin_string().strip_edges(); + // Cache options + String variable_prefix = options["variable_prefix"]; + if (line == "") { - print_line("Debugger Break, Reason: '" + p_script->debug_get_error() + "'"); + print_line("\nDebugger Break, Reason: '" + p_script->debug_get_error() + "'"); print_line("*Frame " + itos(current_frame) + " - " + p_script->debug_get_stack_level_source(current_frame) + ":" + itos(p_script->debug_get_stack_level_line(current_frame)) + " in function '" + p_script->debug_get_stack_level_function(current_frame) + "'"); print_line("Enter \"help\" for assistance."); } else if (line == "c" || line == "continue") @@ -71,38 +86,56 @@ void ScriptDebuggerLocal::debug(ScriptLanguage *p_script, bool p_can_continue) { } } + } else if (line.begins_with("set")) { + + if (line.get_slice_count(" ") == 1) { + + for (Map<String, String>::Element *E = options.front(); E; E = E->next()) { + print_line("\t" + E->key() + "=" + E->value()); + } + + } else { + String key_value = line.get_slicec(' ', 1); + int value_pos = key_value.find("="); + + if (value_pos < 0) { + print_line("Error: Invalid set format. Use: set key=value"); + } else { + + String key = key_value.left(value_pos); + + if (!options.has(key)) { + print_line("Error: Unknown option " + key); + } else { + + // Allow explicit tab character + String value = key_value.right(value_pos + 1).replace("\\t", "\t"); + + options[key] = value; + } + } + } + } else if (line == "lv" || line == "locals") { List<String> locals; List<Variant> values; p_script->debug_get_stack_level_locals(current_frame, &locals, &values); - List<Variant>::Element *V = values.front(); - for (List<String>::Element *E = locals.front(); E; E = E->next()) { - print_line(E->get() + ": " + String(V->get())); - V = V->next(); - } + print_variables(locals, values, variable_prefix); } else if (line == "gv" || line == "globals") { - List<String> locals; + List<String> globals; List<Variant> values; - p_script->debug_get_globals(&locals, &values); - List<Variant>::Element *V = values.front(); - for (List<String>::Element *E = locals.front(); E; E = E->next()) { - print_line(E->get() + ": " + String(V->get())); - V = V->next(); - } + p_script->debug_get_globals(&globals, &values); + print_variables(globals, values, variable_prefix); } else if (line == "mv" || line == "members") { - List<String> locals; + List<String> members; List<Variant> values; - p_script->debug_get_stack_level_members(current_frame, &locals, &values); - List<Variant>::Element *V = values.front(); - for (List<String>::Element *E = locals.front(); E; E = E->next()) { - print_line(E->get() + ": " + String(V->get())); - V = V->next(); - } + p_script->debug_get_stack_level_members(current_frame, &members, &values); + print_variables(members, values, variable_prefix); } else if (line.begins_with("p") || line.begins_with("print")) { @@ -120,65 +153,149 @@ void ScriptDebuggerLocal::debug(ScriptLanguage *p_script, bool p_can_continue) { set_depth(-1); set_lines_left(1); break; - } else if (line.begins_with("n") || line.begins_with("next")) { + } else if (line == "n" || line == "next") { set_depth(0); set_lines_left(1); break; + } else if (line == "fin" || line == "finish") { + + String current_function = p_script->debug_get_stack_level_function(0); + + for (int i = 0; i < total_frames; i++) { + target_function = p_script->debug_get_stack_level_function(i); + if (target_function != current_function) { + set_depth(0); + set_lines_left(1); + return; + } + } + + print_line("Error: Reached last frame."); + target_function = ""; + } else if (line.begins_with("br") || line.begins_with("break")) { if (line.get_slice_count(" ") <= 1) { - //show breakpoints + + const Map<int, Set<StringName> > &breakpoints = get_breakpoints(); + if (breakpoints.size() == 0) { + print_line("No Breakpoints."); + continue; + } + + print_line("Breakpoint(s): " + itos(breakpoints.size())); + for (Map<int, Set<StringName> >::Element *E = breakpoints.front(); E; E = E->next()) { + print_line("\t" + String(E->value().front()->get()) + ":" + itos(E->key())); + } + } else { - String bppos = line.get_slicec(' ', 1); - String source = bppos.get_slicec(':', 0).strip_edges(); - int line = bppos.get_slicec(':', 1).strip_edges().to_int(); + Pair<String, int> breakpoint = to_breakpoint(line); - source = breakpoint_find_source(source); + String source = breakpoint.first; + int linenr = breakpoint.second; - insert_breakpoint(line, source); + if (source.empty()) + continue; - print_line("BreakPoint at " + source + ":" + itos(line)); + insert_breakpoint(linenr, source); + + print_line("Added breakpoint at " + source + ":" + itos(linenr)); } + } else if (line == "q" || line == "quit") { + + // Do not stop again on quit + clear_breakpoints(); + ScriptDebugger::get_singleton()->set_depth(-1); + ScriptDebugger::get_singleton()->set_lines_left(-1); + + SceneTree::get_singleton()->quit(); + break; } else if (line.begins_with("delete")) { if (line.get_slice_count(" ") <= 1) { clear_breakpoints(); } else { - String bppos = line.get_slicec(' ', 1); - String source = bppos.get_slicec(':', 0).strip_edges(); - int line = bppos.get_slicec(':', 1).strip_edges().to_int(); + Pair<String, int> breakpoint = to_breakpoint(line); - source = breakpoint_find_source(source); + String source = breakpoint.first; + int linenr = breakpoint.second; - remove_breakpoint(line, source); + if (source.empty()) + continue; - print_line("Removed BreakPoint at " + source + ":" + itos(line)); + remove_breakpoint(linenr, source); + + print_line("Removed breakpoint at " + source + ":" + itos(linenr)); } } else if (line == "h" || line == "help") { print_line("Built-In Debugger command list:\n"); - print_line("\tc,continue :\t\t Continue execution."); - print_line("\tbt,backtrace :\t\t Show stack trace (frames)."); + print_line("\tc,continue\t\t Continue execution."); + print_line("\tbt,backtrace\t\t Show stack trace (frames)."); print_line("\tfr,frame <frame>:\t Change current frame."); - print_line("\tlv,locals :\t\t Show local variables for current frame."); - print_line("\tmv,members :\t\t Show member variables for \"this\" in frame."); - print_line("\tgv,globals :\t\t Show global variables."); - print_line("\tp,print <expr> :\t Execute and print variable in expression."); - print_line("\ts,step :\t\t Step to next line."); - print_line("\tn,next :\t\t Next line."); - print_line("\tbr,break source:line :\t Place a breakpoint."); - print_line("\tdelete [source:line]:\t\t Delete one/all breakpoints."); + print_line("\tlv,locals\t\t Show local variables for current frame."); + print_line("\tmv,members\t\t Show member variables for \"this\" in frame."); + print_line("\tgv,globals\t\t Show global variables."); + print_line("\tp,print <expr>\t\t Execute and print variable in expression."); + print_line("\ts,step\t\t\t Step to next line."); + print_line("\tn,next\t\t\t Next line."); + print_line("\tfin,finish\t\t Step out of current frame."); + print_line("\tbr,break [source:line]\t List all breakpoints or place a breakpoint."); + print_line("\tdelete [source:line]:\t Delete one/all breakpoints."); + print_line("\tset [key=value]:\t List all options, or set one."); + print_line("\tq,quit\t\t\t Quit application."); } else { print_line("Error: Invalid command, enter \"help\" for assistance."); } } } +void ScriptDebuggerLocal::print_variables(const List<String> &names, const List<Variant> &values, const String &variable_prefix) { + + String value; + Vector<String> value_lines; + const List<Variant>::Element *V = values.front(); + for (const List<String>::Element *E = names.front(); E; E = E->next()) { + + value = String(V->get()); + + if (variable_prefix.empty()) { + print_line(E->get() + ": " + String(V->get())); + } else { + + print_line(E->get() + ":"); + value_lines = value.split("\n"); + for (int i = 0; i < value_lines.size(); ++i) { + print_line(variable_prefix + value_lines[i]); + } + } + + V = V->next(); + } +} + +Pair<String, int> ScriptDebuggerLocal::to_breakpoint(const String &p_line) { + + String breakpoint_part = p_line.get_slicec(' ', 1); + Pair<String, int> breakpoint; + + int last_colon = breakpoint_part.rfind(":"); + if (last_colon < 0) { + print_line("Error: Invalid breakpoint format. Expected [source:line]"); + return breakpoint; + } + + breakpoint.first = breakpoint_find_source(breakpoint_part.left(last_colon).strip_edges()); + breakpoint.second = breakpoint_part.right(last_colon).strip_edges().to_int(); + + return breakpoint; +} + struct _ScriptDebuggerLocalProfileInfoSort { bool operator()(const ScriptLanguage::ProfilingInfo &A, const ScriptLanguage::ProfilingInfo &B) const { @@ -290,11 +407,18 @@ void ScriptDebuggerLocal::profiling_end() { void ScriptDebuggerLocal::send_message(const String &p_message, const Array &p_args) { - print_line("MESSAGE: '" + p_message + "' - " + String(Variant(p_args))); + // This needs to be cleaned up entirely. + // print_line("MESSAGE: '" + p_message + "' - " + String(Variant(p_args))); +} + +void ScriptDebuggerLocal::send_error(const String &p_func, const String &p_file, int p_line, const String &p_err, const String &p_descr, ErrorHandlerType p_type, const Vector<ScriptLanguage::StackInfo> &p_stack_info) { + + print_line("ERROR: '" + (p_descr.empty() ? p_err : p_descr) + "'"); } ScriptDebuggerLocal::ScriptDebuggerLocal() { profiling = false; idle_accum = OS::get_singleton()->get_ticks_usec(); + options["variable_prefix"] = ""; } diff --git a/core/script_debugger_local.h b/core/script_debugger_local.h index f1111612b3..7eea6ef215 100644 --- a/core/script_debugger_local.h +++ b/core/script_debugger_local.h @@ -27,9 +27,11 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef SCRIPT_DEBUGGER_LOCAL_H #define SCRIPT_DEBUGGER_LOCAL_H +#include "list.h" #include "script_language.h" class ScriptDebuggerLocal : public ScriptDebugger { @@ -37,12 +39,18 @@ class ScriptDebuggerLocal : public ScriptDebugger { bool profiling; float frame_time, idle_time, physics_time, physics_frame_time; uint64_t idle_accum; + String target_function; + Map<String, String> options; Vector<ScriptLanguage::ProfilingInfo> pinfo; + Pair<String, int> to_breakpoint(const String &p_line); + void print_variables(const List<String> &names, const List<Variant> &values, const String &variable_prefix); + public: void debug(ScriptLanguage *p_script, bool p_can_continue); virtual void send_message(const String &p_message, const Array &p_args); + virtual void send_error(const String &p_func, const String &p_file, int p_line, const String &p_err, const String &p_descr, ErrorHandlerType p_type, const Vector<ScriptLanguage::StackInfo> &p_stack_info); virtual bool is_profiling() const { return profiling; } virtual void add_profiling_frame_data(const StringName &p_name, const Array &p_data) {} diff --git a/core/script_debugger_remote.cpp b/core/script_debugger_remote.cpp index a0a55ce86e..75bcedbbc8 100644 --- a/core/script_debugger_remote.cpp +++ b/core/script_debugger_remote.cpp @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #include "script_debugger_remote.h" #include "engine.h" @@ -36,6 +37,7 @@ #include "os/os.h" #include "project_settings.h" #include "scene/main/node.h" +#include "scene/resources/packed_scene.h" void ScriptDebuggerRemote::_send_video_memory() { @@ -147,6 +149,16 @@ void ScriptDebuggerRemote::_put_variable(const String &p_name, const Variant &p_ } } +void ScriptDebuggerRemote::_save_node(ObjectID id, const String &p_path) { + + Node *node = Object::cast_to<Node>(ObjectDB::get_instance(id)); + ERR_FAIL_COND(!node); + + Ref<PackedScene> ps = memnew(PackedScene); + ps->pack(node); + ResourceSaver::save(p_path, ps); +} + void ScriptDebuggerRemote::debug(ScriptLanguage *p_script, bool p_can_continue) { //this function is called when there is a debugger break (bug on script) @@ -321,6 +333,8 @@ void ScriptDebuggerRemote::debug(ScriptLanguage *p_script, bool p_can_continue) else remove_breakpoint(cmd[2], cmd[1]); + } else if (command == "save_node") { + _save_node(cmd[1], cmd[2]); } else { _parse_live_edit(cmd); } @@ -354,6 +368,13 @@ void ScriptDebuggerRemote::_get_output() { locking = false; } + if (n_messages_dropped > 0) { + Message msg; + msg.message = "Too many messages! " + String::num_int64(n_messages_dropped) + " messages were dropped."; + messages.push_back(msg); + n_messages_dropped = 0; + } + while (messages.size()) { locking = true; packet_peer_stream->put_var("message:" + messages.front()->get().message); @@ -365,6 +386,20 @@ void ScriptDebuggerRemote::_get_output() { locking = false; } + if (n_errors_dropped > 0) { + OutputError oe; + oe.error = "TOO_MANY_ERRORS"; + oe.error_descr = "Too many errors! " + String::num_int64(n_errors_dropped) + " errors were dropped."; + oe.warning = false; + uint64_t time = OS::get_singleton()->get_ticks_msec(); + oe.hr = time / 3600000; + oe.min = (time / 60000) % 60; + oe.sec = (time / 1000) % 60; + oe.msec = time % 1000; + errors.push_back(oe); + n_errors_dropped = 0; + } + while (errors.size()) { locking = true; packet_peer_stream->put_var("error"); @@ -410,22 +445,6 @@ void ScriptDebuggerRemote::_err_handler(void *ud, const char *p_func, const char if (p_type == ERR_HANDLER_SCRIPT) return; //ignore script errors, those go through debugger - ScriptDebuggerRemote *sdr = (ScriptDebuggerRemote *)ud; - - OutputError oe; - oe.error = p_err; - oe.error_descr = p_descr; - oe.source_file = p_file; - oe.source_line = p_line; - oe.source_func = p_func; - oe.warning = p_type == ERR_HANDLER_WARNING; - uint64_t time = OS::get_singleton()->get_ticks_msec(); - oe.hr = time / 3600000; - oe.min = (time / 60000) % 60; - oe.sec = (time / 1000) % 60; - oe.msec = time % 1000; - Array cstack; - Vector<ScriptLanguage::StackInfo> si; for (int i = 0; i < ScriptServer::get_language_count(); i++) { @@ -434,28 +453,8 @@ void ScriptDebuggerRemote::_err_handler(void *ud, const char *p_func, const char break; } - cstack.resize(si.size() * 2); - for (int i = 0; i < si.size(); i++) { - String path; - int line = 0; - if (si[i].script.is_valid()) { - path = si[i].script->get_path(); - line = si[i].line; - } - cstack[i * 2 + 0] = path; - cstack[i * 2 + 1] = line; - } - - oe.callstack = cstack; - - sdr->mutex->lock(); - - if (!sdr->locking && sdr->tcp_client->is_connected_to_host()) { - - sdr->errors.push_back(oe); - } - - sdr->mutex->unlock(); + ScriptDebuggerRemote *sdr = (ScriptDebuggerRemote *)ud; + sdr->send_error(p_func, p_file, p_line, p_err, p_descr, p_type, si); } bool ScriptDebuggerRemote::_parse_live_edit(const Array &p_command) { @@ -612,7 +611,13 @@ void ScriptDebuggerRemote::_send_object_id(ObjectID p_id) { Array send_props; for (int i = 0; i < properties.size(); i++) { const PropertyInfo &pi = properties[i].first; - const Variant &var = properties[i].second; + Variant &var = properties[i].second; + + WeakRef *ref = Object::cast_to<WeakRef>(var); + if (ref) { + var = ref->get_ref(); + } + RES res = var; Array prop; @@ -890,11 +895,54 @@ void ScriptDebuggerRemote::send_message(const String &p_message, const Array &p_ mutex->lock(); if (!locking && tcp_client->is_connected_to_host()) { - Message msg; - msg.message = p_message; - msg.data = p_args; - messages.push_back(msg); + if (messages.size() >= max_messages_per_frame) { + n_messages_dropped++; + } else { + Message msg; + msg.message = p_message; + msg.data = p_args; + messages.push_back(msg); + } + } + mutex->unlock(); +} + +void ScriptDebuggerRemote::send_error(const String &p_func, const String &p_file, int p_line, const String &p_err, const String &p_descr, ErrorHandlerType p_type, const Vector<ScriptLanguage::StackInfo> &p_stack_info) { + + OutputError oe; + oe.error = p_err; + oe.error_descr = p_descr; + oe.source_file = p_file; + oe.source_line = p_line; + oe.source_func = p_func; + oe.warning = p_type == ERR_HANDLER_WARNING; + uint64_t time = OS::get_singleton()->get_ticks_msec(); + oe.hr = time / 3600000; + oe.min = (time / 60000) % 60; + oe.sec = (time / 1000) % 60; + oe.msec = time % 1000; + Array cstack; + + cstack.resize(p_stack_info.size() * 3); + for (int i = 0; i < p_stack_info.size(); i++) { + cstack[i * 3 + 0] = p_stack_info[i].file; + cstack[i * 3 + 1] = p_stack_info[i].func; + cstack[i * 3 + 2] = p_stack_info[i].line; } + + oe.callstack = cstack; + + mutex->lock(); + + if (!locking && tcp_client->is_connected_to_host()) { + + if (errors.size() >= max_errors_per_frame) { + n_errors_dropped++; + } else { + errors.push_back(oe); + } + } + mutex->unlock(); } @@ -981,11 +1029,11 @@ void ScriptDebuggerRemote::add_profiling_frame_data(const StringName &p_name, co } void ScriptDebuggerRemote::profiling_start() { - //ignores this, uses it via connnection + //ignores this, uses it via connection } void ScriptDebuggerRemote::profiling_end() { - //ignores this, uses it via connnection + //ignores this, uses it via connection } void ScriptDebuggerRemote::profiling_set_frame_times(float p_frame_time, float p_idle_time, float p_physics_time, float p_physics_frame_time) { @@ -1010,7 +1058,11 @@ ScriptDebuggerRemote::ScriptDebuggerRemote() : requested_quit(false), mutex(Mutex::create()), max_cps(GLOBAL_GET("network/limits/debugger_stdout/max_chars_per_second")), + max_messages_per_frame(GLOBAL_GET("network/limits/debugger_stdout/max_messages_per_frame")), + max_errors_per_frame(GLOBAL_GET("network/limits/debugger_stdout/max_errors_per_frame")), char_count(0), + n_messages_dropped(0), + n_errors_dropped(0), last_msec(0), msec_count(0), locking(false), diff --git a/core/script_debugger_remote.h b/core/script_debugger_remote.h index 15afc866e3..cc12d978d6 100644 --- a/core/script_debugger_remote.h +++ b/core/script_debugger_remote.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef SCRIPT_DEBUGGER_REMOTE_H #define SCRIPT_DEBUGGER_REMOTE_H @@ -86,7 +87,11 @@ class ScriptDebuggerRemote : public ScriptDebugger { List<String> output_strings; List<Message> messages; + int max_messages_per_frame; + int n_messages_dropped; List<OutputError> errors; + int max_errors_per_frame; + int n_errors_dropped; int max_cps; int char_count; @@ -128,6 +133,8 @@ class ScriptDebuggerRemote : public ScriptDebugger { void _put_variable(const String &p_name, const Variant &p_variable); + void _save_node(ObjectID id, const String &p_path); + public: struct ResourceUsage { @@ -152,6 +159,7 @@ public: virtual void request_quit(); virtual void send_message(const String &p_message, const Array &p_args); + virtual void send_error(const String &p_func, const String &p_file, int p_line, const String &p_err, const String &p_descr, ErrorHandlerType p_type, const Vector<ScriptLanguage::StackInfo> &p_stack_info); virtual void set_request_scene_tree_message_func(RequestSceneTreeMessageFunc p_func, void *p_udata); virtual void set_live_edit_funcs(LiveEditFuncs *p_funcs); diff --git a/core/script_language.cpp b/core/script_language.cpp index 773eb29036..1dab58e29e 100644 --- a/core/script_language.cpp +++ b/core/script_language.cpp @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #include "script_language.h" ScriptLanguage *ScriptServer::_languages[MAX_LANGUAGES]; @@ -60,6 +61,8 @@ void Script::_bind_methods() { ClassDB::bind_method(D_METHOD("has_script_signal", "signal_name"), &Script::has_script_signal); ClassDB::bind_method(D_METHOD("is_tool"), &Script::is_tool); + + ADD_PROPERTY(PropertyInfo(Variant::STRING, "source_code", PROPERTY_HINT_NONE, "", 0), "set_source_code", "get_source_code"); } void ScriptServer::set_scripting_enabled(bool p_enabled) { diff --git a/core/script_language.h b/core/script_language.h index 1a9d101ddd..55a20c7478 100644 --- a/core/script_language.h +++ b/core/script_language.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef SCRIPT_LANGUAGE_H #define SCRIPT_LANGUAGE_H @@ -178,7 +179,7 @@ class ScriptCodeCompletionCache { public: virtual RES get_cached_resource(const String &p_path) = 0; - static ScriptCodeCompletionCache *get_sigleton() { return singleton; } + static ScriptCodeCompletionCache *get_singleton() { return singleton; } ScriptCodeCompletionCache(); }; @@ -202,6 +203,7 @@ public: virtual void make_template(const String &p_class_name, const String &p_base_class_name, Ref<Script> &p_script) {} virtual bool is_using_templates() { return false; } virtual bool validate(const String &p_script, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path = "", List<String> *r_functions = NULL) const = 0; + virtual String validate_path(const String &p_path) const { return ""; } virtual Script *create_script() const = 0; virtual bool has_named_classes() const = 0; virtual bool supports_builtin_mode() const = 0; @@ -219,7 +221,9 @@ public: RESULT_CLASS, RESULT_CLASS_CONSTANT, RESULT_CLASS_PROPERTY, - RESULT_CLASS_METHOD + RESULT_CLASS_METHOD, + RESULT_CLASS_ENUM, + RESULT_CLASS_TBD_GLOBALSCOPE }; Type type; Ref<Script> script; @@ -253,7 +257,8 @@ public: virtual String debug_parse_stack_level_expression(int p_level, const String &p_expression, int p_max_subitems = -1, int p_max_depth = -1) = 0; struct StackInfo { - Ref<Script> script; + String file; + String func; int line; }; @@ -381,6 +386,7 @@ public: bool is_breakpoint(int p_line, const StringName &p_source) const; bool is_breakpoint_line(int p_line) const; void clear_breakpoints(); + const Map<int, Set<StringName> > &get_breakpoints() const { return breakpoints; } virtual void debug(ScriptLanguage *p_script, bool p_can_continue = true) = 0; virtual void idle_poll(); @@ -390,6 +396,7 @@ public: ScriptLanguage *get_break_language() const; virtual void send_message(const String &p_message, const Array &p_args) = 0; + virtual void send_error(const String &p_func, const String &p_file, int p_line, const String &p_err, const String &p_descr, ErrorHandlerType p_type, const Vector<ScriptLanguage::StackInfo> &p_stack_info) = 0; virtual bool is_remote() const { return false; } virtual void request_quit() {} diff --git a/core/self_list.h b/core/self_list.h index bb7f1a8a5b..6e84e1cd5f 100644 --- a/core/self_list.h +++ b/core/self_list.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef SELF_LIST_H #define SELF_LIST_H @@ -38,6 +39,7 @@ public: class List { SelfList<T> *_first; + SelfList<T> *_last; public: void add(SelfList<T> *p_elem) { @@ -47,47 +49,54 @@ public: p_elem->_root = this; p_elem->_next = _first; p_elem->_prev = NULL; - if (_first) + + if (_first) { _first->_prev = p_elem; + + } else { + _last = p_elem; + } + _first = p_elem; } + void add_last(SelfList<T> *p_elem) { ERR_FAIL_COND(p_elem->_root); - if (!_first) { - add(p_elem); - return; - } + p_elem->_root = this; + p_elem->_next = NULL; + p_elem->_prev = _last; - SelfList<T> *e = _first; + if (_last) { + _last->_next = p_elem; - while (e->next()) { - e = e->next(); + } else { + _first = p_elem; } - e->_next = p_elem; - p_elem->_prev = e->_next; - p_elem->_root = this; + _last = p_elem; } void remove(SelfList<T> *p_elem) { ERR_FAIL_COND(p_elem->_root != this); if (p_elem->_next) { - p_elem->_next->_prev = p_elem->_prev; } - if (p_elem->_prev) { + if (p_elem->_prev) { p_elem->_prev->_next = p_elem->_next; } if (_first == p_elem) { - _first = p_elem->_next; } + if (_last == p_elem) { + _last = p_elem->_prev; + } + p_elem->_next = NULL; p_elem->_prev = NULL; p_elem->_root = NULL; @@ -95,7 +104,10 @@ public: _FORCE_INLINE_ SelfList<T> *first() { return _first; } _FORCE_INLINE_ const SelfList<T> *first() const { return _first; } - _FORCE_INLINE_ List() { _first = NULL; } + _FORCE_INLINE_ List() { + _first = NULL; + _last = NULL; + } _FORCE_INLINE_ ~List() { ERR_FAIL_COND(_first != NULL); } }; diff --git a/core/set.h b/core/set.h index b2a8ee1636..d79dd81644 100644 --- a/core/set.h +++ b/core/set.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef SET_H #define SET_H @@ -184,7 +185,7 @@ private: if (node->right != _data._nil) { node = node->right; - while (node->left != _data._nil) { /* returns the minium of the right subtree of node */ + while (node->left != _data._nil) { /* returns the minimum of the right subtree of node */ node = node->left; } return node; @@ -206,7 +207,7 @@ private: if (node->left != _data._nil) { node = node->left; - while (node->right != _data._nil) { /* returns the minium of the left subtree of node */ + while (node->right != _data._nil) { /* returns the minimum of the left subtree of node */ node = node->right; } return node; diff --git a/core/simple_type.h b/core/simple_type.h index 5429719f02..a645d03181 100644 --- a/core/simple_type.h +++ b/core/simple_type.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef SIMPLE_TYPE_H #define SIMPLE_TYPE_H diff --git a/core/sort.h b/core/sort.h index 94c2c1ecdf..a6780309d8 100644 --- a/core/sort.h +++ b/core/sort.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef SORT_H #define SORT_H diff --git a/core/string_buffer.cpp b/core/string_buffer.cpp deleted file mode 100644 index 970477b90b..0000000000 --- a/core/string_buffer.cpp +++ /dev/null @@ -1,102 +0,0 @@ -/*************************************************************************/ -/* string_buffer.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ -#include "string_buffer.h" - -#include <string.h> - -StringBuffer &StringBuffer::append(CharType p_char) { - reserve(string_length + 2); - current_buffer_ptr()[string_length++] = p_char; - return *this; -} - -StringBuffer &StringBuffer::append(const String &p_string) { - return append(p_string.c_str()); -} - -StringBuffer &StringBuffer::append(const char *p_str) { - int len = strlen(p_str); - reserve(string_length + len + 1); - - CharType *buf = current_buffer_ptr(); - for (const char *c_ptr = p_str; *c_ptr; ++c_ptr) { - buf[string_length++] = *c_ptr; - } - return *this; -} - -StringBuffer &StringBuffer::append(const CharType *p_str, int p_clip_to_len) { - int len = 0; - while ((p_clip_to_len < 0 || len < p_clip_to_len) && p_str[len]) { - ++len; - } - reserve(string_length + len + 1); - memcpy(&(current_buffer_ptr()[string_length]), p_str, len * sizeof(CharType)); - string_length += len; - - return *this; -} - -StringBuffer &StringBuffer::reserve(int p_size) { - if (p_size < SHORT_BUFFER_SIZE || p_size < buffer.size()) - return *this; - - bool need_copy = string_length > 0 && buffer.empty(); - buffer.resize(next_power_of_2(p_size)); - if (need_copy) { - memcpy(buffer.ptrw(), short_buffer, string_length * sizeof(CharType)); - } - - return *this; -} - -int StringBuffer::length() const { - return string_length; -} - -String StringBuffer::as_string() { - current_buffer_ptr()[string_length] = '\0'; - if (buffer.empty()) { - return String(short_buffer); - } else { - buffer.resize(string_length + 1); - return buffer; - } -} - -double StringBuffer::as_double() { - current_buffer_ptr()[string_length] = '\0'; - return String::to_double(current_buffer_ptr()); -} - -int64_t StringBuffer::as_int() { - current_buffer_ptr()[string_length] = '\0'; - return String::to_int(current_buffer_ptr()); -} diff --git a/core/string_buffer.h b/core/string_buffer.h index 4b502f3d92..7e9b151bea 100644 --- a/core/string_buffer.h +++ b/core/string_buffer.h @@ -27,17 +27,19 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef STRING_BUFFER_H #define STRING_BUFFER_H #include "ustring.h" +#include <string.h> +template <int SHORT_BUFFER_SIZE = 64> class StringBuffer { - static const int SHORT_BUFFER_SIZE = 64; CharType short_buffer[SHORT_BUFFER_SIZE]; String buffer; - int string_length = 0; + int string_length; _FORCE_INLINE_ CharType *current_buffer_ptr() { return static_cast<Vector<CharType> &>(buffer).empty() ? short_buffer : buffer.ptrw(); @@ -77,6 +79,89 @@ public: _FORCE_INLINE_ operator String() { return as_string(); } + + StringBuffer() { + string_length = 0; + } }; +template <int SHORT_BUFFER_SIZE> +StringBuffer<SHORT_BUFFER_SIZE> &StringBuffer<SHORT_BUFFER_SIZE>::append(CharType p_char) { + reserve(string_length + 2); + current_buffer_ptr()[string_length++] = p_char; + return *this; +} + +template <int SHORT_BUFFER_SIZE> +StringBuffer<SHORT_BUFFER_SIZE> &StringBuffer<SHORT_BUFFER_SIZE>::append(const String &p_string) { + return append(p_string.c_str()); +} + +template <int SHORT_BUFFER_SIZE> +StringBuffer<SHORT_BUFFER_SIZE> &StringBuffer<SHORT_BUFFER_SIZE>::append(const char *p_str) { + int len = strlen(p_str); + reserve(string_length + len + 1); + + CharType *buf = current_buffer_ptr(); + for (const char *c_ptr = p_str; *c_ptr; ++c_ptr) { + buf[string_length++] = *c_ptr; + } + return *this; +} + +template <int SHORT_BUFFER_SIZE> +StringBuffer<SHORT_BUFFER_SIZE> &StringBuffer<SHORT_BUFFER_SIZE>::append(const CharType *p_str, int p_clip_to_len) { + int len = 0; + while ((p_clip_to_len < 0 || len < p_clip_to_len) && p_str[len]) { + ++len; + } + reserve(string_length + len + 1); + memcpy(&(current_buffer_ptr()[string_length]), p_str, len * sizeof(CharType)); + string_length += len; + + return *this; +} + +template <int SHORT_BUFFER_SIZE> +StringBuffer<SHORT_BUFFER_SIZE> &StringBuffer<SHORT_BUFFER_SIZE>::reserve(int p_size) { + if (p_size < SHORT_BUFFER_SIZE || p_size < buffer.size()) + return *this; + + bool need_copy = string_length > 0 && buffer.empty(); + buffer.resize(next_power_of_2(p_size)); + if (need_copy) { + memcpy(buffer.ptrw(), short_buffer, string_length * sizeof(CharType)); + } + + return *this; +} + +template <int SHORT_BUFFER_SIZE> +int StringBuffer<SHORT_BUFFER_SIZE>::length() const { + return string_length; +} + +template <int SHORT_BUFFER_SIZE> +String StringBuffer<SHORT_BUFFER_SIZE>::as_string() { + current_buffer_ptr()[string_length] = '\0'; + if (buffer.empty()) { + return String(short_buffer); + } else { + buffer.resize(string_length + 1); + return buffer; + } +} + +template <int SHORT_BUFFER_SIZE> +double StringBuffer<SHORT_BUFFER_SIZE>::as_double() { + current_buffer_ptr()[string_length] = '\0'; + return String::to_double(current_buffer_ptr()); +} + +template <int SHORT_BUFFER_SIZE> +int64_t StringBuffer<SHORT_BUFFER_SIZE>::as_int() { + current_buffer_ptr()[string_length] = '\0'; + return String::to_int(current_buffer_ptr()); +} + #endif diff --git a/core/string_builder.cpp b/core/string_builder.cpp index f24e23c986..8ab7e0ea8f 100644 --- a/core/string_builder.cpp +++ b/core/string_builder.cpp @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #include "string_builder.h" #include <string.h> @@ -55,6 +56,9 @@ StringBuilder &StringBuilder::append(const char *p_cstring) { String StringBuilder::as_string() const { + if (string_length == 0) + return ""; + CharType *buffer = memnew_arr(CharType, string_length); int current_position = 0; diff --git a/core/string_builder.h b/core/string_builder.h index 48e3fd663f..596b3bf730 100644 --- a/core/string_builder.h +++ b/core/string_builder.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef STRING_BUILDER_H #define STRING_BUILDER_H @@ -36,7 +37,7 @@ class StringBuilder { - uint32_t string_length = 0; + uint32_t string_length; Vector<String> strings; Vector<const char *> c_strings; @@ -74,6 +75,10 @@ public: _FORCE_INLINE_ operator String() const { return as_string(); } + + StringBuilder() { + string_length = 0; + } }; #endif // STRING_BUILDER_H diff --git a/core/string_db.cpp b/core/string_db.cpp index 3d77aee0a1..2475cbe3e8 100644 --- a/core/string_db.cpp +++ b/core/string_db.cpp @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #include "string_db.h" #include "os/os.h" @@ -163,21 +164,14 @@ void StringName::operator=(const StringName &p_name) { _data = p_name._data; } } -/* was inlined -StringName::operator String() const { - - if (_data) - return _data->get_name(); - return ""; -} -*/ StringName::StringName(const StringName &p_name) { - ERR_FAIL_COND(!configured); _data = NULL; - if (p_name._data && p_name._data->refcount.ref()) { + ERR_FAIL_COND(!configured); + + if (p_name._data && p_name._data->refcount.ref()) { _data = p_name._data; } } diff --git a/core/string_db.h b/core/string_db.h index 5e3086d4ec..01d1ca4033 100644 --- a/core/string_db.h +++ b/core/string_db.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef STRING_DB_H #define STRING_DB_H @@ -66,6 +67,7 @@ class StringName { _Data() { cname = NULL; next = prev = NULL; + idx = 0; hash = 0; } }; diff --git a/core/translation.cpp b/core/translation.cpp index 0c9af4e624..aaa4de5912 100644 --- a/core/translation.cpp +++ b/core/translation.cpp @@ -27,12 +27,21 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #include "translation.h" #include "io/resource_loader.h" #include "os/os.h" #include "project_settings.h" +// ISO 639-1 language codes, with the addition of glibc locales with their +// regional identifiers. This list must match the language names (in English) +// of locale_names. +// +// References: +// - https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes +// - https://lh.2xlibre.net/locales/ + static const char *locale_list[] = { "aa", // Afar "aa_DJ", // Afar (Djibouti) @@ -755,8 +764,17 @@ static const char *locale_names[] = { 0 }; +// Windows has some weird locale identifiers which do not honor the ISO 639-1 +// standardized nomenclature. Whenever those don't conflict with existing ISO +// identifiers, we override them. +// +// Reference: +// - https://msdn.microsoft.com/en-us/library/windows/desktop/ms693062(v=vs.85).aspx + static const char *locale_renames[][2] = { - { "no", "nb" }, + { "in", "id" }, // Indonesian + { "iw", "he" }, // Hebrew + { "no", "nb" }, // Norwegian Bokmål { NULL, NULL } }; @@ -872,7 +890,7 @@ void Translation::_bind_methods() { ClassDB::bind_method(D_METHOD("_set_messages"), &Translation::_set_messages); ClassDB::bind_method(D_METHOD("_get_messages"), &Translation::_get_messages); - ADD_PROPERTY(PropertyInfo(Variant::POOL_STRING_ARRAY, "messages", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "_set_messages", "_get_messages"); + ADD_PROPERTY(PropertyInfo(Variant::POOL_STRING_ARRAY, "messages", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_messages", "_get_messages"); ADD_PROPERTY(PropertyInfo(Variant::STRING, "locale"), "set_locale", "get_locale"); } diff --git a/core/translation.h b/core/translation.h index b8ff1722f5..e7c0dcbc07 100644 --- a/core/translation.h +++ b/core/translation.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef TRANSLATION_H #define TRANSLATION_H diff --git a/core/type_info.h b/core/type_info.h index 24d96c51e8..c1af4fac69 100644 --- a/core/type_info.h +++ b/core/type_info.h @@ -1,3 +1,33 @@ +/*************************************************************************/ +/* type_info.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + #ifndef GET_TYPE_INFO_H #define GET_TYPE_INFO_H diff --git a/core/typedefs.h b/core/typedefs.h index 9508fe28db..4758a5408d 100644 --- a/core/typedefs.h +++ b/core/typedefs.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef TYPEDEFS_H #define TYPEDEFS_H diff --git a/core/ucaps.h b/core/ucaps.h index 764350504a..95bac1aac6 100644 --- a/core/ucaps.h +++ b/core/ucaps.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef UCAPS_H #define UCAPS_H diff --git a/core/undo_redo.cpp b/core/undo_redo.cpp index 46d38b3abc..b3f9dd818d 100644 --- a/core/undo_redo.cpp +++ b/core/undo_redo.cpp @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #include "undo_redo.h" #include "os/os.h" @@ -107,6 +108,7 @@ void UndoRedo::create_action(const String &p_name, MergeMode p_mode) { void UndoRedo::add_do_method(Object *p_object, const String &p_method, VARIANT_ARG_DECLARE) { VARIANT_ARGPTRS + ERR_FAIL_COND(p_object == NULL); ERR_FAIL_COND(action_level <= 0); ERR_FAIL_COND((current_action + 1) >= actions.size()); Operation do_op; @@ -126,6 +128,7 @@ void UndoRedo::add_do_method(Object *p_object, const String &p_method, VARIANT_A void UndoRedo::add_undo_method(Object *p_object, const String &p_method, VARIANT_ARG_DECLARE) { VARIANT_ARGPTRS + ERR_FAIL_COND(p_object == NULL); ERR_FAIL_COND(action_level <= 0); ERR_FAIL_COND((current_action + 1) >= actions.size()); @@ -148,6 +151,7 @@ void UndoRedo::add_undo_method(Object *p_object, const String &p_method, VARIANT } void UndoRedo::add_do_property(Object *p_object, const String &p_property, const Variant &p_value) { + ERR_FAIL_COND(p_object == NULL); ERR_FAIL_COND(action_level <= 0); ERR_FAIL_COND((current_action + 1) >= actions.size()); Operation do_op; @@ -162,6 +166,7 @@ void UndoRedo::add_do_property(Object *p_object, const String &p_property, const } void UndoRedo::add_undo_property(Object *p_object, const String &p_property, const Variant &p_value) { + ERR_FAIL_COND(p_object == NULL); ERR_FAIL_COND(action_level <= 0); ERR_FAIL_COND((current_action + 1) >= actions.size()); @@ -181,6 +186,7 @@ void UndoRedo::add_undo_property(Object *p_object, const String &p_property, con } void UndoRedo::add_do_reference(Object *p_object) { + ERR_FAIL_COND(p_object == NULL); ERR_FAIL_COND(action_level <= 0); ERR_FAIL_COND((current_action + 1) >= actions.size()); Operation do_op; @@ -193,6 +199,7 @@ void UndoRedo::add_do_reference(Object *p_object) { } void UndoRedo::add_undo_reference(Object *p_object) { + ERR_FAIL_COND(p_object == NULL); ERR_FAIL_COND(action_level <= 0); ERR_FAIL_COND((current_action + 1) >= actions.size()); @@ -239,13 +246,6 @@ void UndoRedo::commit_action() { redo(); // perform action - if (max_steps > 0 && actions.size() > max_steps) { - //clear early steps - - while (actions.size() > max_steps) - _pop_history_tail(); - } - if (callback && actions.size() > 0) { callback(callback_ud, actions[actions.size() - 1].name); } @@ -340,16 +340,6 @@ String UndoRedo::get_current_action_name() const { return actions[current_action].name; } -void UndoRedo::set_max_steps(int p_max_steps) { - - max_steps = p_max_steps; -} - -int UndoRedo::get_max_steps() const { - - return max_steps; -} - uint64_t UndoRedo::get_version() const { return version; @@ -378,7 +368,6 @@ UndoRedo::UndoRedo() { version = 1; action_level = 0; current_action = -1; - max_steps = -1; merge_mode = MERGE_DISABLE; callback = NULL; callback_ud = NULL; @@ -503,8 +492,6 @@ void UndoRedo::_bind_methods() { ClassDB::bind_method(D_METHOD("clear_history"), &UndoRedo::clear_history); ClassDB::bind_method(D_METHOD("get_current_action_name"), &UndoRedo::get_current_action_name); ClassDB::bind_method(D_METHOD("get_version"), &UndoRedo::get_version); - ClassDB::bind_method(D_METHOD("set_max_steps", "max_steps"), &UndoRedo::set_max_steps); - ClassDB::bind_method(D_METHOD("get_max_steps"), &UndoRedo::get_max_steps); ClassDB::bind_method(D_METHOD("redo"), &UndoRedo::redo); ClassDB::bind_method(D_METHOD("undo"), &UndoRedo::undo); diff --git a/core/undo_redo.h b/core/undo_redo.h index 27bd7c2fd0..a373296b73 100644 --- a/core/undo_redo.h +++ b/core/undo_redo.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef UNDO_REDO_H #define UNDO_REDO_H @@ -78,7 +79,6 @@ private: Vector<Action> actions; int current_action; int action_level; - int max_steps; MergeMode merge_mode; uint64_t version; @@ -114,9 +114,6 @@ public: String get_current_action_name() const; void clear_history(); - void set_max_steps(int p_max_steps); - int get_max_steps() const; - uint64_t get_version() const; void set_commit_notify_callback(CommitNotifyCallback p_callback, void *p_ud); diff --git a/core/ustring.cpp b/core/ustring.cpp index 11d83a5733..85b7a16e6a 100644 --- a/core/ustring.cpp +++ b/core/ustring.cpp @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #include "ustring.h" #include "color.h" @@ -685,6 +686,9 @@ Vector<String> String::split_spaces() const { int from = 0; int i = 0; int len = length(); + if (len == 0) + return ret; + bool inside = false; while (true) { @@ -941,8 +945,8 @@ String String::num(double p_num, int p_decimals) { #ifndef NO_USE_STDLIB - if (p_decimals > 12) - p_decimals = 12; + if (p_decimals > 16) + p_decimals = 16; char fmt[7]; fmt[0] = '%'; @@ -1097,9 +1101,8 @@ String String::num(double p_num, int p_decimals) { String String::num_int64(int64_t p_num, int base, bool capitalize_hex) { bool sign = p_num < 0; - int64_t num = ABS(p_num); - int64_t n = num; + int64_t n = p_num; int chars = 0; do { @@ -1113,9 +1116,9 @@ String String::num_int64(int64_t p_num, int base, bool capitalize_hex) { s.resize(chars + 1); CharType *c = s.ptrw(); c[chars] = 0; - n = num; + n = p_num; do { - int mod = n % base; + int mod = ABS(n % base); if (mod >= 10) { char a = (capitalize_hex ? 'A' : 'a'); c[--chars] = a + (mod - 10); @@ -1132,6 +1135,36 @@ String String::num_int64(int64_t p_num, int base, bool capitalize_hex) { return s; } +String String::num_uint64(uint64_t p_num, int base, bool capitalize_hex) { + + uint64_t n = p_num; + + int chars = 0; + do { + n /= base; + chars++; + } while (n); + + String s; + s.resize(chars + 1); + CharType *c = s.ptrw(); + c[chars] = 0; + n = p_num; + do { + int mod = n % base; + if (mod >= 10) { + char a = (capitalize_hex ? 'A' : 'a'); + c[--chars] = a + (mod - 10); + } else { + c[--chars] = '0' + mod; + } + + n /= base; + } while (n); + + return s; +} + String String::num_real(double p_num) { String s; @@ -1517,8 +1550,7 @@ String::String(const StrRange &p_range) { int String::hex_to_int(bool p_with_prefix) const { - int l = length(); - if (p_with_prefix && l < 3) + if (p_with_prefix && length() < 3) return 0; const CharType *s = ptr(); @@ -1527,17 +1559,13 @@ int String::hex_to_int(bool p_with_prefix) const { if (sign < 0) { s++; - l--; - if (p_with_prefix && l < 2) - return 0; } if (p_with_prefix) { if (s[0] != '0' || s[1] != 'x') return 0; s += 2; - l -= 2; - }; + } int hex = 0; @@ -1563,8 +1591,7 @@ int String::hex_to_int(bool p_with_prefix) const { int64_t String::hex_to_int64(bool p_with_prefix) const { - int l = length(); - if (p_with_prefix && l < 3) + if (p_with_prefix && length() < 3) return 0; const CharType *s = ptr(); @@ -1573,17 +1600,13 @@ int64_t String::hex_to_int64(bool p_with_prefix) const { if (sign < 0) { s++; - l--; - if (p_with_prefix && l < 2) - return 0; } if (p_with_prefix) { if (s[0] != '0' || s[1] != 'x') return 0; s += 2; - l -= 2; - }; + } int64_t hex = 0; @@ -2214,7 +2237,7 @@ int String::find(const String &p_str, int p_from) const { const int len = length(); if (src_len == 0 || len == 0) - return -1; //wont find anything! + return -1; // won't find anything! const CharType *src = c_str(); const CharType *str = p_str.c_str(); @@ -2253,7 +2276,7 @@ int String::find(const char *p_str, int p_from) const { const int len = length(); if (len == 0) - return -1; //wont find anything! + return -1; // won't find anything! const CharType *src = c_str(); @@ -2314,7 +2337,7 @@ int String::findmk(const Vector<String> &p_keys, int p_from, int *r_key) const { int len = length(); if (len == 0) - return -1; //wont find anything! + return -1; // won't find anything! const CharType *src = c_str(); @@ -2363,7 +2386,7 @@ int String::findn(const String &p_str, int p_from) const { int src_len = p_str.length(); if (src_len == 0 || length() == 0) - return -1; //wont find anything! + return -1; // won't find anything! const CharType *srcd = c_str(); @@ -2459,7 +2482,7 @@ int String::rfindn(const String &p_str, int p_from) const { int len = length(); if (src_len == 0 || len == 0) - return -1; //wont find anything! + return -1; // won't find anything! const CharType *src = c_str(); @@ -2964,6 +2987,40 @@ String String::strip_escapes() const { return substr(beg, end - beg); } +String String::lstrip(const Vector<CharType> &p_chars) const { + + int len = length(); + int beg; + + for (beg = 0; beg < len; beg++) { + + if (p_chars.find(operator[](beg)) == -1) + break; + } + + if (beg == 0) + return *this; + + return substr(beg, len - beg); +} + +String String::rstrip(const Vector<CharType> &p_chars) const { + + int len = length(); + int end; + + for (end = len - 1; end >= 0; end--) { + + if (p_chars.find(operator[](end)) == -1) + break; + } + + if (end == len - 1) + return *this; + + return substr(0, end + 1); +} + String String::simplify_path() const { String s = *this; @@ -3135,8 +3192,8 @@ String String::word_wrap(int p_chars_per_line) const { String String::http_escape() const { const CharString temp = utf8(); String res; - for (int i = 0; i < length(); ++i) { - CharType ord = temp[i]; + for (int i = 0; i < temp.length(); ++i) { + char ord = temp[i]; if (ord == '.' || ord == '-' || ord == '_' || ord == '~' || (ord >= 'a' && ord <= 'z') || (ord >= 'A' && ord <= 'Z') || @@ -3145,9 +3202,9 @@ String String::http_escape() const { } else { char h_Val[3]; #if defined(__GNUC__) || defined(_MSC_VER) - snprintf(h_Val, 3, "%.2X", ord); + snprintf(h_Val, 3, "%hhX", ord); #else - sprintf(h_Val, "%.2X", ord); + sprintf(h_Val, "%hhX", ord); #endif res += "%"; res += h_Val; @@ -3164,7 +3221,7 @@ String String::http_unescape() const { if ((ord1 >= '0' && ord1 <= '9') || (ord1 >= 'A' && ord1 <= 'Z')) { CharType ord2 = ord_at(i + 2); if ((ord2 >= '0' && ord2 <= '9') || (ord2 >= 'A' && ord2 <= 'Z')) { - char bytes[2] = { ord1, ord2 }; + char bytes[2] = { (char)ord1, (char)ord2 }; res += (char)strtol(bytes, NULL, 16); i += 2; } @@ -3415,6 +3472,24 @@ String String::pad_zeros(int p_digits) const { return s; } +String String::trim_prefix(const String &p_prefix) const { + + String s = *this; + if (s.begins_with(p_prefix)) { + return s.substr(p_prefix.length(), s.length() - p_prefix.length()); + } + return s; +} + +String String::trim_suffix(const String &p_suffix) const { + + String s = *this; + if (s.ends_with(p_suffix)) { + return s.substr(0, s.length() - p_suffix.length()); + } + return s; +} + bool String::is_valid_integer() const { int len = length(); @@ -3445,13 +3520,13 @@ bool String::is_valid_hex_number(bool p_with_prefix) const { if (p_with_prefix) { - if (len < 2) + if (len < 3) return false; if (operator[](from) != '0' || operator[](from + 1) != 'x') { return false; - }; + } from += 2; - }; + } for (int i = from; i < len; i++) { @@ -3459,7 +3534,7 @@ bool String::is_valid_hex_number(bool p_with_prefix) const { if ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')) continue; return false; - }; + } return true; }; @@ -3680,8 +3755,8 @@ String String::get_file() const { String String::get_extension() const { int pos = find_last("."); - if (pos < 0) - return *this; + if (pos < 0 || pos < MAX(find_last("/"), find_last("\\"))) + return ""; return substr(pos + 1, length()); } @@ -3759,7 +3834,7 @@ String String::percent_decode() const { String String::get_basename() const { int pos = find_last("."); - if (pos < 0) + if (pos < 0 || pos < MAX(find_last("/"), find_last("\\"))) return *this; return substr(0, pos); diff --git a/core/ustring.h b/core/ustring.h index 8dd8b0fed3..1ed694bb80 100644 --- a/core/ustring.h +++ b/core/ustring.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef RSTRING_H #define RSTRING_H @@ -136,6 +137,8 @@ public: String insert(int p_at_pos, const String &p_string) const; String pad_decimals(int p_digits) const; String pad_zeros(int p_digits) const; + String trim_prefix(const String &p_prefix) const; + String trim_suffix(const String &p_suffix) const; String lpad(int min_length, const String &character = " ") const; String rpad(int min_length, const String &character = " ") const; String sprintf(const Array &values, bool *error) const; @@ -145,6 +148,7 @@ public: static String num_scientific(double p_num); static String num_real(double p_num); static String num_int64(int64_t p_num, int base = 10, bool capitalize_hex = false); + static String num_uint64(uint64_t p_num, int base = 10, bool capitalize_hex = false); static String chr(CharType p_char); static String md5(const uint8_t *p_md5); static String hex_encode_buffer(const uint8_t *p_buffer, int p_len); @@ -186,6 +190,8 @@ public: String dedent() const; String strip_edges(bool left = true, bool right = true) const; String strip_escapes() const; + String lstrip(const Vector<CharType> &p_chars) const; + String rstrip(const Vector<CharType> &p_chars) const; String get_extension() const; String get_basename() const; String plus_file(const String &p_file) const; diff --git a/core/variant.cpp b/core/variant.cpp index 5d4879dba7..a6df95e310 100644 --- a/core/variant.cpp +++ b/core/variant.cpp @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #include "variant.h" #include "core_string_names.h" @@ -1606,6 +1607,8 @@ Variant::operator Vector3() const { if (type == VECTOR3) return *reinterpret_cast<const Vector3 *>(_data._mem); + else if (type == VECTOR2) + return Vector3(reinterpret_cast<const Vector2 *>(_data._mem)->x, reinterpret_cast<const Vector2 *>(_data._mem)->y, 0.0); else return Vector3(); } @@ -3164,7 +3167,11 @@ String Variant::get_call_error_text(Object *p_base, const StringName &p_method, if (ce.error == Variant::CallError::CALL_ERROR_INVALID_ARGUMENT) { int errorarg = ce.argument; - err_text = "Cannot convert argument " + itos(errorarg + 1) + " from " + Variant::get_type_name(p_argptrs[errorarg]->get_type()) + " to " + Variant::get_type_name(ce.expected) + "."; + if (p_argptrs) { + err_text = "Cannot convert argument " + itos(errorarg + 1) + " from " + Variant::get_type_name(p_argptrs[errorarg]->get_type()) + " to " + Variant::get_type_name(ce.expected) + "."; + } else { + err_text = "Cannot convert argument " + itos(errorarg + 1) + " from [missing argptr, type unknown] to " + Variant::get_type_name(ce.expected) + "."; + } } else if (ce.error == Variant::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS) { err_text = "Method expected " + itos(ce.argument) + " arguments, but called with " + itos(p_argcount) + "."; } else if (ce.error == Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS) { diff --git a/core/variant.h b/core/variant.h index 6c9204a18e..f227e4bfdb 100644 --- a/core/variant.h +++ b/core/variant.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef VARIANT_H #define VARIANT_H @@ -139,7 +140,6 @@ private: ::AABB *_aabb; Basis *_basis; Transform *_transform; - RefPtr *_resource; void *_ptr; //generic pointer uint8_t _mem[sizeof(ObjData) > (sizeof(real_t) * 4) ? sizeof(ObjData) : (sizeof(real_t) * 4)]; } _data; @@ -292,7 +292,7 @@ public: // If this changes the table in variant_op must be updated enum Operator { - //comparation + //comparison OP_EQUAL, OP_NOT_EQUAL, OP_LESS, @@ -337,6 +337,7 @@ public: } void zero(); + Variant duplicate(bool deep = false) const; static void blend(const Variant &a, const Variant &b, float c, Variant &r_dst); static void interpolate(const Variant &a, const Variant &b, float c, Variant &r_dst); diff --git a/core/variant_call.cpp b/core/variant_call.cpp index 81e823b5db..bd1cde5a82 100644 --- a/core/variant_call.cpp +++ b/core/variant_call.cpp @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #include "variant.h" #include "core_string_names.h" @@ -152,9 +153,9 @@ struct _VariantCall { funcdata.func = p_func; funcdata.default_args = p_defaultarg; funcdata._const = p_const; + funcdata.returns = p_has_return; #ifdef DEBUG_ENABLED funcdata.return_type = p_return; - funcdata.returns = p_has_return; #endif if (p_argtype1.name) { @@ -263,6 +264,8 @@ struct _VariantCall { VCALL_LOCALMEM1R(String, right); VCALL_LOCALMEM0R(String, dedent); VCALL_LOCALMEM2R(String, strip_edges); + VCALL_LOCALMEM1R(String, lstrip); + VCALL_LOCALMEM1R(String, rstrip); VCALL_LOCALMEM0R(String, get_extension); VCALL_LOCALMEM0R(String, get_basename); VCALL_LOCALMEM1R(String, plus_file); @@ -295,6 +298,8 @@ struct _VariantCall { VCALL_LOCALMEM0R(String, hex_to_int); VCALL_LOCALMEM1R(String, pad_decimals); VCALL_LOCALMEM1R(String, pad_zeros); + VCALL_LOCALMEM1R(String, trim_prefix); + VCALL_LOCALMEM1R(String, trim_suffix); static void _call_String_to_ascii(Variant &r_ret, Variant &p_self, const Variant **p_args) { @@ -339,6 +344,8 @@ struct _VariantCall { VCALL_LOCALMEM1R(Vector2, rotated); VCALL_LOCALMEM0R(Vector2, tangent); VCALL_LOCALMEM0R(Vector2, floor); + VCALL_LOCALMEM0R(Vector2, ceil); + VCALL_LOCALMEM0R(Vector2, round); VCALL_LOCALMEM1R(Vector2, snapped); VCALL_LOCALMEM0R(Vector2, aspect); VCALL_LOCALMEM1R(Vector2, dot); @@ -346,7 +353,7 @@ struct _VariantCall { VCALL_LOCALMEM1R(Vector2, bounce); VCALL_LOCALMEM1R(Vector2, reflect); VCALL_LOCALMEM0R(Vector2, angle); - //VCALL_LOCALMEM1R(Vector2,cross); + VCALL_LOCALMEM1R(Vector2, cross); VCALL_LOCALMEM0R(Vector2, abs); VCALL_LOCALMEM1R(Vector2, clamped); @@ -381,6 +388,7 @@ struct _VariantCall { VCALL_LOCALMEM0R(Vector3, abs); VCALL_LOCALMEM0R(Vector3, floor); VCALL_LOCALMEM0R(Vector3, ceil); + VCALL_LOCALMEM0R(Vector3, round); VCALL_LOCALMEM1R(Vector3, distance_to); VCALL_LOCALMEM1R(Vector3, distance_squared_to); VCALL_LOCALMEM1R(Vector3, angle_to); @@ -442,6 +450,7 @@ struct _VariantCall { VCALL_LOCALMEM1R(Color, lightened); VCALL_LOCALMEM1R(Color, darkened); VCALL_LOCALMEM1R(Color, to_html); + VCALL_LOCALMEM4R(Color, from_hsv); VCALL_LOCALMEM0R(RID, get_id); @@ -463,7 +472,7 @@ struct _VariantCall { VCALL_LOCALMEM0R(Dictionary, hash); VCALL_LOCALMEM0R(Dictionary, keys); VCALL_LOCALMEM0R(Dictionary, values); - VCALL_LOCALMEM0R(Dictionary, duplicate); + VCALL_LOCALMEM1R(Dictionary, duplicate); VCALL_LOCALMEM2(Array, set); VCALL_LOCALMEM1R(Array, get); @@ -489,9 +498,10 @@ struct _VariantCall { VCALL_LOCALMEM1(Array, erase); VCALL_LOCALMEM0(Array, sort); VCALL_LOCALMEM2(Array, sort_custom); + VCALL_LOCALMEM0(Array, shuffle); VCALL_LOCALMEM2R(Array, bsearch); VCALL_LOCALMEM4R(Array, bsearch_custom); - VCALL_LOCALMEM0R(Array, duplicate); + VCALL_LOCALMEM1R(Array, duplicate); VCALL_LOCALMEM0(Array, invert); static void _call_PoolByteArray_get_string_from_ascii(Variant &r_ret, Variant &p_self, const Variant **p_args) { @@ -1457,6 +1467,8 @@ void register_variant_methods() { ADDFUNC1R(STRING, STRING, String, left, INT, "position", varray()); ADDFUNC1R(STRING, STRING, String, right, INT, "position", varray()); ADDFUNC2R(STRING, STRING, String, strip_edges, BOOL, "left", BOOL, "right", varray(true, true)); + ADDFUNC1R(STRING, STRING, String, lstrip, STRING, "chars", varray()); + ADDFUNC1R(STRING, STRING, String, rstrip, STRING, "chars", varray()); ADDFUNC0R(STRING, STRING, String, get_extension, varray()); ADDFUNC0R(STRING, STRING, String, get_basename, varray()); ADDFUNC1R(STRING, STRING, String, plus_file, STRING, "file", varray()); @@ -1490,6 +1502,8 @@ void register_variant_methods() { ADDFUNC0R(STRING, INT, String, hex_to_int, varray()); ADDFUNC1R(STRING, STRING, String, pad_decimals, INT, "digits", varray()); ADDFUNC1R(STRING, STRING, String, pad_zeros, INT, "digits", varray()); + ADDFUNC1R(STRING, STRING, String, trim_prefix, STRING, "prefix", varray()); + ADDFUNC1R(STRING, STRING, String, trim_suffix, STRING, "suffix", varray()); ADDFUNC0R(STRING, POOL_BYTE_ARRAY, String, to_ascii, varray()); ADDFUNC0R(STRING, POOL_BYTE_ARRAY, String, to_utf8, varray()); @@ -1508,13 +1522,15 @@ void register_variant_methods() { ADDFUNC1R(VECTOR2, VECTOR2, Vector2, rotated, REAL, "phi", varray()); ADDFUNC0R(VECTOR2, VECTOR2, Vector2, tangent, varray()); ADDFUNC0R(VECTOR2, VECTOR2, Vector2, floor, varray()); + ADDFUNC0R(VECTOR2, VECTOR2, Vector2, ceil, varray()); + ADDFUNC0R(VECTOR2, VECTOR2, Vector2, round, varray()); ADDFUNC1R(VECTOR2, VECTOR2, Vector2, snapped, VECTOR2, "by", varray()); ADDFUNC0R(VECTOR2, REAL, Vector2, aspect, varray()); ADDFUNC1R(VECTOR2, REAL, Vector2, dot, VECTOR2, "with", varray()); ADDFUNC1R(VECTOR2, VECTOR2, Vector2, slide, VECTOR2, "n", varray()); ADDFUNC1R(VECTOR2, VECTOR2, Vector2, bounce, VECTOR2, "n", varray()); ADDFUNC1R(VECTOR2, VECTOR2, Vector2, reflect, VECTOR2, "n", varray()); - //ADDFUNC1R(VECTOR2,REAL,Vector2,cross,VECTOR2,"with",varray()); + ADDFUNC1R(VECTOR2, REAL, Vector2, cross, VECTOR2, "with", varray()); ADDFUNC0R(VECTOR2, VECTOR2, Vector2, abs, varray()); ADDFUNC1R(VECTOR2, VECTOR2, Vector2, clamped, REAL, "length", varray()); @@ -1538,7 +1554,7 @@ void register_variant_methods() { ADDFUNC0R(VECTOR3, BOOL, Vector3, is_normalized, varray()); ADDFUNC0R(VECTOR3, VECTOR3, Vector3, normalized, varray()); ADDFUNC0R(VECTOR3, VECTOR3, Vector3, inverse, varray()); - ADDFUNC1R(VECTOR3, VECTOR3, Vector3, snapped, REAL, "by", varray()); + ADDFUNC1R(VECTOR3, VECTOR3, Vector3, snapped, VECTOR3, "by", varray()); ADDFUNC2R(VECTOR3, VECTOR3, Vector3, rotated, VECTOR3, "axis", REAL, "phi", varray()); ADDFUNC2R(VECTOR3, VECTOR3, Vector3, linear_interpolate, VECTOR3, "b", REAL, "t", varray()); ADDFUNC4R(VECTOR3, VECTOR3, Vector3, cubic_interpolate, VECTOR3, "b", VECTOR3, "pre_a", VECTOR3, "post_b", REAL, "t", varray()); @@ -1549,6 +1565,7 @@ void register_variant_methods() { ADDFUNC0R(VECTOR3, VECTOR3, Vector3, abs, varray()); ADDFUNC0R(VECTOR3, VECTOR3, Vector3, floor, varray()); ADDFUNC0R(VECTOR3, VECTOR3, Vector3, ceil, varray()); + ADDFUNC0R(VECTOR3, VECTOR3, Vector3, round, varray()); ADDFUNC1R(VECTOR3, REAL, Vector3, distance_to, VECTOR3, "b", varray()); ADDFUNC1R(VECTOR3, REAL, Vector3, distance_squared_to, VECTOR3, "b", varray()); ADDFUNC1R(VECTOR3, REAL, Vector3, angle_to, VECTOR3, "to", varray()); @@ -1588,6 +1605,7 @@ void register_variant_methods() { ADDFUNC1R(COLOR, COLOR, Color, lightened, REAL, "amount", varray()); ADDFUNC1R(COLOR, COLOR, Color, darkened, REAL, "amount", varray()); ADDFUNC1R(COLOR, STRING, Color, to_html, BOOL, "with_alpha", varray(true)); + ADDFUNC4R(COLOR, COLOR, Color, from_hsv, REAL, "h", REAL, "s", REAL, "v", REAL, "a", varray(1.0)); ADDFUNC0R(_RID, INT, RID, get_id, varray()); @@ -1609,7 +1627,7 @@ void register_variant_methods() { ADDFUNC0R(DICTIONARY, INT, Dictionary, hash, varray()); ADDFUNC0R(DICTIONARY, ARRAY, Dictionary, keys, varray()); ADDFUNC0R(DICTIONARY, ARRAY, Dictionary, values, varray()); - ADDFUNC0R(DICTIONARY, DICTIONARY, Dictionary, duplicate, varray()); + ADDFUNC1R(DICTIONARY, DICTIONARY, Dictionary, duplicate, BOOL, "deep", varray(false)); ADDFUNC0R(ARRAY, INT, Array, size, varray()); ADDFUNC0R(ARRAY, BOOL, Array, empty, varray()); @@ -1633,10 +1651,11 @@ void register_variant_methods() { ADDFUNC0RNC(ARRAY, NIL, Array, pop_front, varray()); ADDFUNC0NC(ARRAY, NIL, Array, sort, varray()); ADDFUNC2NC(ARRAY, NIL, Array, sort_custom, OBJECT, "obj", STRING, "func", varray()); + ADDFUNC0NC(ARRAY, NIL, Array, shuffle, varray()); ADDFUNC2R(ARRAY, INT, Array, bsearch, NIL, "value", BOOL, "before", varray(true)); ADDFUNC4R(ARRAY, INT, Array, bsearch_custom, NIL, "value", OBJECT, "obj", STRING, "func", BOOL, "before", varray(true)); ADDFUNC0NC(ARRAY, NIL, Array, invert, varray()); - ADDFUNC0RNC(ARRAY, ARRAY, Array, duplicate, varray()); + ADDFUNC1R(ARRAY, ARRAY, Array, duplicate, BOOL, "deep", varray(false)); ADDFUNC0R(POOL_BYTE_ARRAY, INT, PoolByteArray, size, varray()); ADDFUNC2(POOL_BYTE_ARRAY, NIL, PoolByteArray, set, INT, "idx", INT, "byte", varray()); @@ -1747,10 +1766,10 @@ void register_variant_methods() { ADDFUNC1R(TRANSFORM2D, TRANSFORM2D, Transform2D, rotated, REAL, "phi", varray()); ADDFUNC1R(TRANSFORM2D, TRANSFORM2D, Transform2D, scaled, VECTOR2, "scale", varray()); ADDFUNC1R(TRANSFORM2D, TRANSFORM2D, Transform2D, translated, VECTOR2, "offset", varray()); - ADDFUNC1R(TRANSFORM2D, TRANSFORM2D, Transform2D, xform, NIL, "v", varray()); - ADDFUNC1R(TRANSFORM2D, TRANSFORM2D, Transform2D, xform_inv, NIL, "v", varray()); - ADDFUNC1R(TRANSFORM2D, TRANSFORM2D, Transform2D, basis_xform, NIL, "v", varray()); - ADDFUNC1R(TRANSFORM2D, TRANSFORM2D, Transform2D, basis_xform_inv, NIL, "v", varray()); + ADDFUNC1R(TRANSFORM2D, NIL, Transform2D, xform, NIL, "v", varray()); + ADDFUNC1R(TRANSFORM2D, NIL, Transform2D, xform_inv, NIL, "v", varray()); + ADDFUNC1R(TRANSFORM2D, VECTOR2, Transform2D, basis_xform, VECTOR2, "v", varray()); + ADDFUNC1R(TRANSFORM2D, VECTOR2, Transform2D, basis_xform_inv, VECTOR2, "v", varray()); ADDFUNC2R(TRANSFORM2D, TRANSFORM2D, Transform2D, interpolate_with, TRANSFORM2D, "transform", REAL, "weight", varray()); ADDFUNC0R(BASIS, BASIS, Basis, inverse, varray()); diff --git a/core/variant_construct_string.cpp b/core/variant_construct_string.cpp index 408e54bc99..2250c03f3d 100644 --- a/core/variant_construct_string.cpp +++ b/core/variant_construct_string.cpp @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #include "variant.h" class VariantConstruct { diff --git a/core/variant_op.cpp b/core/variant_op.cpp index 96b09c904d..621af2dfb7 100644 --- a/core/variant_op.cpp +++ b/core/variant_op.cpp @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #include "variant.h" #include "core_string_names.h" @@ -146,7 +147,7 @@ Variant::operator bool() const { return booleanize(); } -// We consider all unitialized or empty types to be false based on the type's +// We consider all uninitialized or empty types to be false based on the type's // zeroiness. bool Variant::booleanize() const { return !is_zero(); @@ -176,7 +177,7 @@ bool Variant::booleanize() const { CASE_TYPE(m_prefix, m_op_name, m_name) { \ if (p_b.type == INT) _RETURN(p_a._data.m_type m_op p_b._data._int); \ if (p_b.type == REAL) _RETURN(p_a._data.m_type m_op p_b._data._real); \ - if (p_b.type == NIL) _RETURN(!p_b.type m_op NIL); \ + if (p_b.type == NIL) _RETURN(!(p_b.type m_op NIL)); \ \ _RETURN_FAIL \ }; @@ -251,7 +252,7 @@ bool Variant::booleanize() const { CASE_TYPE(m_prefix, m_op_name, m_name) { \ if (p_b.type == STRING) _RETURN(*reinterpret_cast<const m_type *>(p_a._data._mem) m_op *reinterpret_cast<const String *>(p_b._data._mem)); \ if (p_b.type == NODE_PATH) _RETURN(*reinterpret_cast<const m_type *>(p_a._data._mem) m_op *reinterpret_cast<const NodePath *>(p_b._data._mem)); \ - if (p_b.type == NIL) _RETURN(!p_b.type m_op NIL); \ + if (p_b.type == NIL) _RETURN(!(p_b.type m_op NIL)); \ \ _RETURN_FAIL \ }; @@ -277,7 +278,7 @@ bool Variant::booleanize() const { if (p_b.type == m_name) \ _RETURN(*reinterpret_cast<const m_type *>(p_a._data._mem) m_op *reinterpret_cast<const m_type *>(p_b._data._mem)); \ if (p_b.type == NIL) \ - _RETURN(!p_b.type m_op NIL); \ + _RETURN(!(p_b.type m_op NIL)); \ \ _RETURN_FAIL \ }; @@ -322,7 +323,7 @@ bool Variant::booleanize() const { if (p_b.type == m_name) \ _RETURN(*p_a._data.m_sub m_op *p_b._data.m_sub); \ if (p_b.type == NIL) \ - _RETURN(!p_b.type m_op NIL); \ + _RETURN(!(p_b.type m_op NIL)); \ \ _RETURN_FAIL \ } @@ -338,7 +339,7 @@ bool Variant::booleanize() const { CASE_TYPE(m_prefix, m_op_name, m_name) { \ if (p_b.type == NIL) \ _RETURN(true) \ - DEFAULT_OP_ARRAY_OP_BODY(m_prefix, m_op_name, m_name, m_type, !=, ==, true, true, false) \ + DEFAULT_OP_ARRAY_OP_BODY(m_prefix, m_op_name, m_name, m_type, !=, !=, false, true, true) \ } #define DEFAULT_OP_ARRAY_LT(m_prefix, m_op_name, m_name, m_type) \ @@ -538,12 +539,12 @@ void Variant::evaluate(const Operator &p_op, const Variant &p_a, if (arr_b->size() != l) _RETURN(true); for (int i = 0; i < l; i++) { - if (((*arr_a)[i] == (*arr_b)[i])) { - _RETURN(false); + if (((*arr_a)[i] != (*arr_b)[i])) { + _RETURN(true); } } - _RETURN(true); + _RETURN(false); } DEFAULT_OP_NUM_NULL(math, OP_NOT_EQUAL, INT, !=, _int); @@ -1458,13 +1459,13 @@ void Variant::set_named(const StringName &p_index, const Variant &p_value, bool v->a = p_value._data._int / 255.0; valid = true; } else if (p_index == CoreStringNames::singleton->h) { - v->set_hsv(p_value._data._int, v->get_s(), v->get_v()); + v->set_hsv(p_value._data._int, v->get_s(), v->get_v(), v->a); valid = true; } else if (p_index == CoreStringNames::singleton->s) { - v->set_hsv(v->get_h(), p_value._data._int, v->get_v()); + v->set_hsv(v->get_h(), p_value._data._int, v->get_v(), v->a); valid = true; } else if (p_index == CoreStringNames::singleton->v) { - v->set_hsv(v->get_h(), v->get_v(), p_value._data._int); + v->set_hsv(v->get_h(), v->get_v(), p_value._data._int, v->a); valid = true; } } else if (p_value.type == Variant::REAL) { @@ -1494,13 +1495,13 @@ void Variant::set_named(const StringName &p_index, const Variant &p_value, bool v->a = p_value._data._real / 255.0; valid = true; } else if (p_index == CoreStringNames::singleton->h) { - v->set_hsv(p_value._data._real, v->get_s(), v->get_v()); + v->set_hsv(p_value._data._real, v->get_s(), v->get_v(), v->a); valid = true; } else if (p_index == CoreStringNames::singleton->s) { - v->set_hsv(v->get_h(), p_value._data._real, v->get_v()); + v->set_hsv(v->get_h(), p_value._data._real, v->get_v(), v->a); valid = true; } else if (p_index == CoreStringNames::singleton->v) { - v->set_hsv(v->get_h(), v->get_v(), p_value._data._real); + v->set_hsv(v->get_h(), v->get_s(), p_value._data._real, v->a); valid = true; } } @@ -2116,15 +2117,15 @@ void Variant::set(const Variant &p_index, const Variant &p_value, bool *r_valid) return; } else if (*str == "h") { valid = true; - v->set_hsv(p_value, v->get_s(), v->get_v()); + v->set_hsv(p_value, v->get_s(), v->get_v(), v->a); return; } else if (*str == "s") { valid = true; - v->set_hsv(v->get_h(), p_value, v->get_v()); + v->set_hsv(v->get_h(), p_value, v->get_v(), v->a); return; } else if (*str == "v") { valid = true; - v->set_hsv(v->get_h(), v->get_s(), p_value); + v->set_hsv(v->get_h(), v->get_s(), p_value, v->a); return; } else if (*str == "r8") { valid = true; @@ -3414,6 +3415,19 @@ Variant Variant::iter_get(const Variant &r_iter, bool &r_valid) const { return Variant(); } +Variant Variant::duplicate(bool deep) const { + switch (type) { + // case OBJECT: + // return operator Object *()->duplicate(); + case DICTIONARY: + return operator Dictionary().duplicate(deep); + case ARRAY: + return operator Array().duplicate(deep); + default: + return *this; + } +} + void Variant::blend(const Variant &a, const Variant &b, float c, Variant &r_dst) { if (a.type != b.type) { if (a.is_num() && b.is_num()) { @@ -3714,8 +3728,9 @@ static const char *_op_names[Variant::OP_MAX] = { "*", "/", "- (negation)", + "+ (positive)", "%", - "..", + "+ (concatenation)", "<<", ">>", "&", diff --git a/core/variant_parser.cpp b/core/variant_parser.cpp index a78e18112d..446aee286d 100644 --- a/core/variant_parser.cpp +++ b/core/variant_parser.cpp @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #include "variant_parser.h" #include "core/string_buffer.h" @@ -177,7 +178,7 @@ Error VariantParser::get_token(Stream *p_stream, Token &r_token, int &line, Stri }; case '#': { - StringBuffer color_str; + StringBuffer<> color_str; color_str += '#'; while (true) { CharType ch = p_stream->get_char(); @@ -298,7 +299,7 @@ Error VariantParser::get_token(Stream *p_stream, Token &r_token, int &line, Stri if (cchar == '-' || (cchar >= '0' && cchar <= '9')) { //a number - StringBuffer num; + StringBuffer<> num; #define READING_SIGN 0 #define READING_INT 1 #define READING_DEC 2 @@ -377,7 +378,7 @@ Error VariantParser::get_token(Stream *p_stream, Token &r_token, int &line, Stri } else if ((cchar >= 'A' && cchar <= 'Z') || (cchar >= 'a' && cchar <= 'z') || cchar == '_') { - StringBuffer id; + StringBuffer<> id; bool first = true; while ((cchar >= 'A' && cchar <= 'Z') || (cchar >= 'a' && cchar <= 'z') || cchar == '_' || (!first && cchar >= '0' && cchar <= '9')) { diff --git a/core/variant_parser.h b/core/variant_parser.h index 18b6998f55..8d95595234 100644 --- a/core/variant_parser.h +++ b/core/variant_parser.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef VARIANT_PARSER_H #define VARIANT_PARSER_H diff --git a/core/vector.h b/core/vector.h index 456d446a4b..f586471e27 100644 --- a/core/vector.h +++ b/core/vector.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef VECTOR_H #define VECTOR_H diff --git a/core/version.h b/core/version.h index bf2f2c9d99..d39172865a 100644 --- a/core/version.h +++ b/core/version.h @@ -27,11 +27,35 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #include "version_generated.gen.h" +// Godot versions are of the form <major>.<minor> for the initial release, +// and then <major>.<minor>.<patch> for subsequent bugfix releases where <patch> != 0 +// That's arbitrary, but we find it pretty and it's the current policy. + +// Defines the main "branch" version. Patch versions in this branch should be +// forward-compatible. +// Example: "3.1" +#define VERSION_BRANCH "" _MKSTR(VERSION_MAJOR) "." _MKSTR(VERSION_MINOR) #ifdef VERSION_PATCH -#define VERSION_MKSTRING "" _MKSTR(VERSION_MAJOR) "." _MKSTR(VERSION_MINOR) "." _MKSTR(VERSION_PATCH) "." VERSION_STATUS "." VERSION_BUILD VERSION_MODULE_CONFIG +// Example: "3.1.4" +#define VERSION_NUMBER "" VERSION_BRANCH "." _MKSTR(VERSION_PATCH) #else -#define VERSION_MKSTRING "" _MKSTR(VERSION_MAJOR) "." _MKSTR(VERSION_MINOR) "." VERSION_STATUS "." VERSION_BUILD VERSION_MODULE_CONFIG +// Example: "3.1" +#define VERSION_NUMBER "" VERSION_BRANCH #endif // VERSION_PATCH -#define VERSION_FULL_NAME "" VERSION_NAME " v" VERSION_MKSTRING + +// Describes the full configuration of that Godot version, including the version number, +// the status (beta, stable, etc.) and potential module-specific features (e.g. mono). +// Example: "3.1.4.stable.mono" +#define VERSION_FULL_CONFIG "" VERSION_NUMBER "." VERSION_STATUS VERSION_MODULE_CONFIG + +// Similar to VERSION_FULL_CONFIG, but also includes the (potentially custom) VERSION_BUILD +// description (e.g. official, custom_build, etc.). +// Example: "3.1.4.stable.mono.official" +#define VERSION_FULL_BUILD "" VERSION_FULL_CONFIG "." VERSION_BUILD + +// Same as above, but prepended with Godot's name and a cosmetic "v" for "version". +// Example: "Godot v3.1.4.stable.official.mono" +#define VERSION_FULL_NAME "" VERSION_NAME " v" VERSION_FULL_BUILD diff --git a/core/vmap.h b/core/vmap.h index 341fc273d4..8636c02997 100644 --- a/core/vmap.h +++ b/core/vmap.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef VMAP_H #define VMAP_H diff --git a/core/vset.h b/core/vset.h index f4036c7c7e..449943b4a1 100644 --- a/core/vset.h +++ b/core/vset.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef VSET_H #define VSET_H |