summaryrefslogtreecommitdiff
path: root/core
diff options
context:
space:
mode:
Diffstat (limited to 'core')
-rw-r--r--core/SCsub10
-rw-r--r--core/allocators.h1
-rw-r--r--core/array.cpp23
-rw-r--r--core/array.h4
-rw-r--r--core/bind/core_bind.cpp138
-rw-r--r--core/bind/core_bind.h21
-rw-r--r--core/class_db.cpp73
-rw-r--r--core/class_db.h7
-rw-r--r--core/color.cpp161
-rw-r--r--core/color.h14
-rw-r--r--core/command_queue_mt.cpp2
-rw-r--r--core/command_queue_mt.h7
-rw-r--r--core/compressed_translation.cpp1
-rw-r--r--core/compressed_translation.h3
-rw-r--r--core/core_string_names.cpp1
-rw-r--r--core/core_string_names.h1
-rw-r--r--core/dictionary.cpp26
-rw-r--r--core/dictionary.h3
-rw-r--r--core/dvector.cpp1
-rw-r--r--core/dvector.h1
-rw-r--r--core/engine.cpp12
-rw-r--r--core/engine.h5
-rw-r--r--core/error_list.h1
-rw-r--r--core/error_macros.cpp1
-rw-r--r--core/error_macros.h13
-rw-r--r--core/func_ref.cpp1
-rw-r--r--core/func_ref.h1
-rw-r--r--core/global_constants.cpp5
-rw-r--r--core/global_constants.h1
-rw-r--r--core/hash_map.h1
-rw-r--r--core/hashfuncs.h1
-rw-r--r--core/helper/math_fieldwise.h1
-rw-r--r--core/helper/value_evaluator.h1
-rw-r--r--core/image.cpp224
-rw-r--r--core/image.h7
-rw-r--r--core/input_map.cpp92
-rw-r--r--core/input_map.h14
-rw-r--r--core/io/compression.cpp1
-rw-r--r--core/io/compression.h1
-rw-r--r--core/io/config_file.cpp1
-rw-r--r--core/io/config_file.h1
-rw-r--r--core/io/file_access_buffered.cpp1
-rw-r--r--core/io/file_access_buffered.h1
-rw-r--r--core/io/file_access_buffered_fa.h1
-rw-r--r--core/io/file_access_compressed.cpp1
-rw-r--r--core/io/file_access_compressed.h1
-rw-r--r--core/io/file_access_encrypted.cpp1
-rw-r--r--core/io/file_access_encrypted.h1
-rw-r--r--core/io/file_access_memory.cpp1
-rw-r--r--core/io/file_access_memory.h1
-rw-r--r--core/io/file_access_network.cpp5
-rw-r--r--core/io/file_access_network.h1
-rw-r--r--core/io/file_access_pack.cpp7
-rw-r--r--core/io/file_access_pack.h1
-rw-r--r--core/io/file_access_zip.cpp1
-rw-r--r--core/io/file_access_zip.h7
-rw-r--r--core/io/http_client.cpp28
-rw-r--r--core/io/http_client.h1
-rw-r--r--core/io/image_loader.cpp3
-rw-r--r--core/io/image_loader.h1
-rw-r--r--core/io/ip.cpp1
-rw-r--r--core/io/ip.h1
-rw-r--r--core/io/ip_address.cpp3
-rw-r--r--core/io/ip_address.h1
-rw-r--r--core/io/json.cpp1
-rw-r--r--core/io/json.h1
-rw-r--r--core/io/marshalls.cpp9
-rw-r--r--core/io/marshalls.h1
-rw-r--r--core/io/multiplayer_api.cpp722
-rw-r--r--core/io/multiplayer_api.h87
-rw-r--r--core/io/networked_multiplayer_peer.cpp5
-rw-r--r--core/io/networked_multiplayer_peer.h2
-rw-r--r--core/io/packet_peer.cpp15
-rw-r--r--core/io/packet_peer.h2
-rw-r--r--core/io/packet_peer_udp.cpp1
-rw-r--r--core/io/packet_peer_udp.h1
-rw-r--r--core/io/pck_packer.cpp9
-rw-r--r--core/io/pck_packer.h6
-rw-r--r--core/io/resource_format_binary.cpp11
-rw-r--r--core/io/resource_format_binary.h1
-rw-r--r--core/io/resource_import.cpp37
-rw-r--r--core/io/resource_import.h5
-rw-r--r--core/io/resource_loader.cpp4
-rw-r--r--core/io/resource_loader.h1
-rw-r--r--core/io/resource_saver.cpp3
-rw-r--r--core/io/resource_saver.h1
-rw-r--r--core/io/stream_peer.cpp31
-rw-r--r--core/io/stream_peer.h3
-rw-r--r--core/io/stream_peer_ssl.cpp33
-rw-r--r--core/io/stream_peer_ssl.h3
-rw-r--r--core/io/stream_peer_tcp.cpp2
-rw-r--r--core/io/stream_peer_tcp.h3
-rw-r--r--core/io/tcp_server.cpp1
-rw-r--r--core/io/tcp_server.h1
-rw-r--r--core/io/translation_loader_po.cpp1
-rw-r--r--core/io/translation_loader_po.h1
-rw-r--r--core/io/xml_parser.cpp1
-rw-r--r--core/io/xml_parser.h1
-rw-r--r--core/io/zip_io.h1
-rw-r--r--core/list.h3
-rw-r--r--core/make_binders.py12
-rw-r--r--core/map.h5
-rw-r--r--core/math/a_star.cpp1
-rw-r--r--core/math/a_star.h1
-rw-r--r--core/math/aabb.cpp1
-rw-r--r--core/math/aabb.h1
-rw-r--r--core/math/audio_frame.cpp1
-rw-r--r--core/math/audio_frame.h1
-rw-r--r--core/math/bsp_tree.cpp1
-rw-r--r--core/math/bsp_tree.h1
-rw-r--r--core/math/camera_matrix.cpp1
-rw-r--r--core/math/camera_matrix.h1
-rw-r--r--core/math/face3.cpp1
-rw-r--r--core/math/face3.h1
-rw-r--r--core/math/geometry.cpp1
-rw-r--r--core/math/geometry.h29
-rw-r--r--core/math/math_2d.cpp14
-rw-r--r--core/math/math_2d.h6
-rw-r--r--core/math/math_defs.h1
-rw-r--r--core/math/math_funcs.cpp16
-rw-r--r--core/math/math_funcs.h15
-rw-r--r--core/math/matrix3.cpp64
-rw-r--r--core/math/matrix3.h15
-rw-r--r--core/math/octree.h3
-rw-r--r--core/math/plane.cpp1
-rw-r--r--core/math/plane.h1
-rw-r--r--core/math/quat.cpp3
-rw-r--r--core/math/quick_hull.cpp3
-rw-r--r--core/math/quick_hull.h1
-rw-r--r--core/math/transform.cpp5
-rw-r--r--core/math/transform.h1
-rw-r--r--core/math/triangle_mesh.cpp1
-rw-r--r--core/math/triangle_mesh.h1
-rw-r--r--core/math/triangulate.cpp43
-rw-r--r--core/math/triangulate.h6
-rw-r--r--core/math/vector3.cpp1
-rw-r--r--core/math/vector3.h7
-rw-r--r--core/message_queue.cpp3
-rw-r--r--core/message_queue.h1
-rw-r--r--core/method_bind.cpp1
-rw-r--r--core/method_bind.h31
-rw-r--r--core/method_ptrcall.h1
-rw-r--r--core/node_path.cpp4
-rw-r--r--core/node_path.h1
-rw-r--r--core/oa_hash_map.h618
-rw-r--r--core/object.cpp9
-rw-r--r--core/object.h10
-rw-r--r--core/ordered_hash_map.h3
-rw-r--r--core/os/copymem.h1
-rw-r--r--core/os/dir_access.cpp14
-rw-r--r--core/os/dir_access.h5
-rw-r--r--core/os/file_access.cpp4
-rw-r--r--core/os/file_access.h4
-rw-r--r--core/os/input.cpp7
-rw-r--r--core/os/input.h7
-rw-r--r--core/os/input_event.cpp96
-rw-r--r--core/os/input_event.h29
-rw-r--r--core/os/keyboard.cpp122
-rw-r--r--core/os/keyboard.h2
-rw-r--r--core/os/main_loop.cpp1
-rw-r--r--core/os/main_loop.h1
-rw-r--r--core/os/memory.cpp1
-rw-r--r--core/os/memory.h1
-rw-r--r--core/os/mutex.cpp1
-rw-r--r--core/os/mutex.h1
-rw-r--r--core/os/os.cpp43
-rw-r--r--core/os/os.h42
-rw-r--r--core/os/rw_lock.cpp1
-rw-r--r--core/os/rw_lock.h1
-rw-r--r--core/os/semaphore.cpp1
-rw-r--r--core/os/semaphore.h1
-rw-r--r--core/os/shell.cpp1
-rw-r--r--core/os/shell.h1
-rw-r--r--core/os/thread.cpp1
-rw-r--r--core/os/thread.h1
-rw-r--r--core/os/thread_dummy.cpp9
-rw-r--r--core/os/thread_dummy.h18
-rw-r--r--core/os/thread_safe.cpp1
-rw-r--r--core/os/thread_safe.h1
-rw-r--r--core/os/threaded_array_processor.cpp2
-rw-r--r--core/os/threaded_array_processor.h30
-rw-r--r--core/packed_data_container.cpp1
-rw-r--r--core/packed_data_container.h1
-rw-r--r--core/pair.h1
-rw-r--r--core/path_remap.cpp1
-rw-r--r--core/path_remap.h1
-rw-r--r--core/pool_allocator.cpp5
-rw-r--r--core/pool_allocator.h1
-rw-r--r--core/print_string.cpp1
-rw-r--r--core/print_string.h1
-rw-r--r--core/project_settings.cpp134
-rw-r--r--core/project_settings.h12
-rw-r--r--core/ref_ptr.cpp1
-rw-r--r--core/ref_ptr.h1
-rw-r--r--core/reference.cpp1
-rw-r--r--core/reference.h6
-rw-r--r--core/register_core_types.cpp3
-rw-r--r--core/register_core_types.h1
-rw-r--r--core/resource.cpp5
-rw-r--r--core/resource.h1
-rw-r--r--core/rid.cpp1
-rw-r--r--core/rid.h1
-rw-r--r--core/ring_buffer.h18
-rw-r--r--core/safe_refcount.cpp8
-rw-r--r--core/safe_refcount.h1
-rw-r--r--core/script_debugger_local.cpp216
-rw-r--r--core/script_debugger_local.h8
-rw-r--r--core/script_debugger_remote.cpp142
-rw-r--r--core/script_debugger_remote.h8
-rw-r--r--core/script_language.cpp3
-rw-r--r--core/script_language.h13
-rw-r--r--core/self_list.h42
-rw-r--r--core/set.h5
-rw-r--r--core/simple_type.h1
-rw-r--r--core/sort.h1
-rw-r--r--core/string_buffer.cpp102
-rw-r--r--core/string_buffer.h89
-rw-r--r--core/string_builder.cpp4
-rw-r--r--core/string_builder.h7
-rw-r--r--core/string_db.cpp14
-rw-r--r--core/string_db.h2
-rw-r--r--core/translation.cpp22
-rw-r--r--core/translation.h1
-rw-r--r--core/type_info.h30
-rw-r--r--core/typedefs.h1
-rw-r--r--core/ucaps.h1
-rw-r--r--core/undo_redo.cpp27
-rw-r--r--core/undo_redo.h5
-rw-r--r--core/ustring.cpp149
-rw-r--r--core/ustring.h6
-rw-r--r--core/variant.cpp9
-rw-r--r--core/variant.h5
-rw-r--r--core/variant_call.cpp43
-rw-r--r--core/variant_construct_string.cpp1
-rw-r--r--core/variant_op.cpp53
-rw-r--r--core/variant_parser.cpp7
-rw-r--r--core/variant_parser.h1
-rw-r--r--core/vector.h1
-rw-r--r--core/version.h30
-rw-r--r--core/vmap.h1
-rw-r--r--core/vset.h1
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