summaryrefslogtreecommitdiff
path: root/core
diff options
context:
space:
mode:
Diffstat (limited to 'core')
-rw-r--r--core/SCsub12
-rw-r--r--core/array.cpp4
-rw-r--r--core/array.h2
-rw-r--r--core/dictionary.cpp4
-rw-r--r--core/dictionary.h2
-rw-r--r--core/error_macros.h8
-rw-r--r--core/func_ref.cpp13
-rw-r--r--core/func_ref.h1
-rw-r--r--core/image.cpp163
-rw-r--r--core/image.h1
-rw-r--r--core/io/compression.cpp6
-rw-r--r--core/io/file_access_buffered_fa.h8
-rw-r--r--core/io/file_access_compressed.cpp13
-rw-r--r--core/io/file_access_compressed.h2
-rw-r--r--core/io/file_access_encrypted.cpp10
-rw-r--r--core/io/file_access_encrypted.h2
-rw-r--r--core/io/file_access_memory.h2
-rw-r--r--core/io/file_access_network.cpp10
-rw-r--r--core/io/file_access_network.h2
-rw-r--r--core/io/file_access_pack.h2
-rw-r--r--core/io/file_access_zip.h2
-rw-r--r--core/io/http_client.cpp2
-rw-r--r--core/io/multiplayer_api.cpp39
-rw-r--r--core/io/resource_importer.cpp10
-rw-r--r--core/io/resource_importer.h5
-rw-r--r--core/io/resource_loader.cpp24
-rw-r--r--core/io/resource_loader.h2
-rw-r--r--core/io/zip_io.h2
-rw-r--r--core/list.h10
-rw-r--r--core/make_binders.py12
-rw-r--r--core/math/a_star.cpp91
-rw-r--r--core/math/a_star.h22
-rw-r--r--core/math/audio_frame.h9
-rw-r--r--core/math/camera_matrix.cpp8
-rw-r--r--core/math/camera_matrix.h1
-rw-r--r--core/math/delaunay.h4
-rw-r--r--core/math/expression.cpp7
-rw-r--r--core/math/expression.h1
-rw-r--r--core/math/geometry.cpp2
-rw-r--r--core/math/geometry.h12
-rw-r--r--core/math/math_funcs.h25
-rw-r--r--core/math/plane.cpp4
-rw-r--r--core/math/plane.h4
-rw-r--r--core/math/rect2.h41
-rw-r--r--core/math/transform_2d.cpp2
-rw-r--r--core/math/transform_2d.h2
-rw-r--r--core/math/vector2.h9
-rw-r--r--core/math/vector3.h23
-rw-r--r--core/message_queue.cpp10
-rw-r--r--core/message_queue.h2
-rw-r--r--core/method_bind.h6
-rw-r--r--core/object.cpp32
-rw-r--r--core/object.h8
-rw-r--r--core/ordered_hash_map.h4
-rw-r--r--core/os/dir_access.cpp2
-rw-r--r--core/os/file_access.cpp23
-rw-r--r--core/os/file_access.h7
-rw-r--r--core/os/input.cpp9
-rw-r--r--core/os/input.h4
-rw-r--r--core/os/input_event.cpp13
-rw-r--r--core/os/os.cpp10
-rw-r--r--core/os/os.h9
-rw-r--r--core/project_settings.cpp6
-rw-r--r--core/reference.h19
-rw-r--r--core/resource.cpp20
-rw-r--r--core/resource.h10
-rw-r--r--core/string_builder.h4
-rw-r--r--core/translation.cpp33
-rw-r--r--core/translation.h2
-rw-r--r--core/type_info.h122
-rw-r--r--core/undo_redo.cpp16
-rw-r--r--core/undo_redo.h4
-rw-r--r--core/ustring.cpp25
-rw-r--r--core/ustring.h5
-rw-r--r--core/variant.cpp27
-rw-r--r--core/variant.h1
-rw-r--r--core/variant_call.cpp15
-rw-r--r--core/variant_parser.cpp3
78 files changed, 853 insertions, 240 deletions
diff --git a/core/SCsub b/core/SCsub
index 00d0bcac24..06efc8408d 100644
--- a/core/SCsub
+++ b/core/SCsub
@@ -80,9 +80,9 @@ if env['builtin_zlib']:
]
thirdparty_zlib_sources = [thirdparty_zlib_dir + file for file in thirdparty_zlib_sources]
- env_thirdparty.Append(CPPPATH=[thirdparty_zlib_dir])
+ env_thirdparty.Prepend(CPPPATH=[thirdparty_zlib_dir])
# Needs to be available in main env too
- env.Append(CPPPATH=[thirdparty_zlib_dir])
+ env.Prepend(CPPPATH=[thirdparty_zlib_dir])
env_thirdparty.add_source_files(env.core_sources, thirdparty_zlib_sources)
@@ -128,11 +128,11 @@ if env['builtin_zstd']:
]
thirdparty_zstd_sources = [thirdparty_zstd_dir + file for file in thirdparty_zstd_sources]
- env_thirdparty.Append(CPPPATH=[thirdparty_zstd_dir, thirdparty_zstd_dir + "common"])
- env_thirdparty.Append(CCFLAGS="-DZSTD_STATIC_LINKING_ONLY")
- env.Append(CPPPATH=thirdparty_zstd_dir)
+ env_thirdparty.Prepend(CPPPATH=[thirdparty_zstd_dir, thirdparty_zstd_dir + "common"])
+ env_thirdparty.Append(CPPFLAGS="-DZSTD_STATIC_LINKING_ONLY")
+ env.Prepend(CPPPATH=thirdparty_zstd_dir)
# Also needed in main env includes will trigger warnings
- env.Append(CCFLAGS="-DZSTD_STATIC_LINKING_ONLY")
+ env.Append(CPPFLAGS="-DZSTD_STATIC_LINKING_ONLY")
env_thirdparty.add_source_files(env.core_sources, thirdparty_zstd_sources)
diff --git a/core/array.cpp b/core/array.cpp
index 649e610a69..65934d6ec9 100644
--- a/core/array.cpp
+++ b/core/array.cpp
@@ -401,6 +401,10 @@ Variant Array::max() const {
return maxval;
}
+const void *Array::id() const {
+ return _p->array.ptr();
+}
+
Array::Array(const Array &p_from) {
_p = NULL;
diff --git a/core/array.h b/core/array.h
index 6158db4065..d4e937a486 100644
--- a/core/array.h
+++ b/core/array.h
@@ -94,6 +94,8 @@ public:
Variant min() const;
Variant max() const;
+ const void *id() const;
+
Array(const Array &p_from);
Array();
~Array();
diff --git a/core/dictionary.cpp b/core/dictionary.cpp
index bea0997cc9..5e4dfb9a5a 100644
--- a/core/dictionary.cpp
+++ b/core/dictionary.cpp
@@ -270,6 +270,10 @@ void Dictionary::operator=(const Dictionary &p_dictionary) {
_ref(p_dictionary);
}
+const void *Dictionary::id() const {
+ return _p->variant_map.id();
+}
+
Dictionary::Dictionary(const Dictionary &p_from) {
_p = NULL;
_ref(p_from);
diff --git a/core/dictionary.h b/core/dictionary.h
index eab7354cef..b68d3f5737 100644
--- a/core/dictionary.h
+++ b/core/dictionary.h
@@ -82,6 +82,8 @@ public:
Dictionary duplicate(bool p_deep = false) const;
+ const void *id() const;
+
Dictionary(const Dictionary &p_from);
Dictionary();
~Dictionary();
diff --git a/core/error_macros.h b/core/error_macros.h
index ca5ccd24cf..f72e987e23 100644
--- a/core/error_macros.h
+++ b/core/error_macros.h
@@ -41,7 +41,7 @@
*/
/**
- * Pointer to the error macro priting function. Reassign to any function to have errors printed
+ * Pointer to the error macro printing function. Reassign to any function to have errors printed
*/
/** Function used by the error macros */
@@ -86,7 +86,7 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li
#define _FNL __FILE__ ":"
-/** An index has failed if m_index<0 or m_index >=m_size, the function exists */
+/** An index has failed if m_index<0 or m_index >=m_size, the function exits */
extern bool _err_error_exists;
@@ -140,7 +140,7 @@ extern bool _err_error_exists;
_err_error_exists = false; \
} while (0); // (*)
-/** An index has failed if m_index<0 or m_index >=m_size, the function exists.
+/** An index has failed if m_index<0 or m_index >=m_size, the function exits.
* This function returns an error value, if returning Error, please select the most
* appropriate error condition from error_macros.h
*/
@@ -154,7 +154,7 @@ extern bool _err_error_exists;
_err_error_exists = false; \
} while (0); // (*)
-/** An index has failed if m_index >=m_size, the function exists.
+/** An index has failed if m_index >=m_size, the function exits.
* This function returns an error value, if returning Error, please select the most
* appropriate error condition from error_macros.h
*/
diff --git a/core/func_ref.cpp b/core/func_ref.cpp
index 4a965473d9..3d03137d09 100644
--- a/core/func_ref.cpp
+++ b/core/func_ref.cpp
@@ -51,11 +51,23 @@ void FuncRef::set_instance(Object *p_obj) {
ERR_FAIL_NULL(p_obj);
id = p_obj->get_instance_id();
}
+
void FuncRef::set_function(const StringName &p_func) {
function = p_func;
}
+bool FuncRef::is_valid() const {
+ if (id == 0)
+ return false;
+
+ Object *obj = ObjectDB::get_instance(id);
+ if (!obj)
+ return false;
+
+ return obj->has_method(function);
+}
+
void FuncRef::_bind_methods() {
{
@@ -67,6 +79,7 @@ void FuncRef::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_instance", "instance"), &FuncRef::set_instance);
ClassDB::bind_method(D_METHOD("set_function", "name"), &FuncRef::set_function);
+ ClassDB::bind_method(D_METHOD("is_valid"), &FuncRef::is_valid);
}
FuncRef::FuncRef() :
diff --git a/core/func_ref.h b/core/func_ref.h
index 339279fdba..a143b58bf0 100644
--- a/core/func_ref.h
+++ b/core/func_ref.h
@@ -46,6 +46,7 @@ public:
Variant call_func(const Variant **p_args, int p_argcount, Variant::CallError &r_error);
void set_instance(Object *p_obj);
void set_function(const StringName &p_func);
+ bool is_valid() const;
FuncRef();
};
diff --git a/core/image.cpp b/core/image.cpp
index 90afd9f35a..30af724de9 100644
--- a/core/image.cpp
+++ b/core/image.cpp
@@ -725,6 +725,131 @@ static void _scale_nearest(const uint8_t *__restrict p_src, uint8_t *__restrict
}
}
+#define LANCZOS_TYPE 3
+
+static float _lanczos(float p_x) {
+ return Math::abs(p_x) >= LANCZOS_TYPE ? 0 : Math::sincn(p_x) * Math::sincn(p_x / LANCZOS_TYPE);
+}
+
+template <int CC, class T>
+static void _scale_lanczos(const uint8_t *__restrict p_src, uint8_t *__restrict p_dst, uint32_t p_src_width, uint32_t p_src_height, uint32_t p_dst_width, uint32_t p_dst_height) {
+
+ int32_t src_width = p_src_width;
+ int32_t src_height = p_src_height;
+ int32_t dst_height = p_dst_height;
+ int32_t dst_width = p_dst_width;
+
+ uint32_t buffer_size = src_height * dst_width * CC;
+ float *buffer = memnew_arr(float, buffer_size); // Store the first pass in a buffer
+
+ { // FIRST PASS (horizontal)
+
+ float x_scale = float(src_width) / float(dst_width);
+
+ float scale_factor = MAX(x_scale, 1); // A larger kernel is required only when downscaling
+ int32_t half_kernel = LANCZOS_TYPE * scale_factor;
+
+ float *kernel = memnew_arr(float, half_kernel * 2 - 1);
+
+ for (int32_t buffer_x = 0; buffer_x < dst_width; buffer_x++) {
+
+ float src_real_x = buffer_x * x_scale;
+ int32_t src_x = src_real_x;
+
+ int32_t start_x = MAX(0, src_x - half_kernel + 1);
+ int32_t end_x = MIN(src_width - 1, src_x + half_kernel);
+
+ // Create the kernel used by all the pixels of the column
+ for (int32_t target_x = start_x; target_x <= end_x; target_x++)
+ kernel[target_x - start_x] = _lanczos((src_real_x - target_x) / scale_factor);
+
+ for (int32_t buffer_y = 0; buffer_y < src_height; buffer_y++) {
+
+ float pixel[CC] = { 0 };
+ float weight = 0;
+
+ for (int32_t target_x = start_x; target_x <= end_x; target_x++) {
+
+ float lanczos_val = kernel[target_x - start_x];
+ weight += lanczos_val;
+
+ const T *__restrict src_data = ((const T *)p_src) + (buffer_y * src_width + target_x) * CC;
+
+ for (uint32_t i = 0; i < CC; i++) {
+ if (sizeof(T) == 2) //half float
+ pixel[i] += Math::half_to_float(src_data[i]) * lanczos_val;
+ else
+ pixel[i] += src_data[i] * lanczos_val;
+ }
+ }
+
+ float *dst_data = ((float *)buffer) + (buffer_y * dst_width + buffer_x) * CC;
+
+ for (uint32_t i = 0; i < CC; i++)
+ dst_data[i] = pixel[i] / weight; // Normalize the sum of all the samples
+ }
+ }
+
+ memdelete_arr(kernel);
+ } // End of first pass
+
+ { // SECOND PASS (vertical + result)
+
+ float y_scale = float(src_height) / float(dst_height);
+
+ float scale_factor = MAX(y_scale, 1);
+ int32_t half_kernel = LANCZOS_TYPE * scale_factor;
+
+ float *kernel = memnew_arr(float, half_kernel * 2 - 1);
+
+ for (int32_t dst_y = 0; dst_y < dst_height; dst_y++) {
+
+ float buffer_real_y = dst_y * y_scale;
+ int32_t buffer_y = buffer_real_y;
+
+ int32_t start_y = MAX(0, buffer_y - half_kernel + 1);
+ int32_t end_y = MIN(src_height - 1, buffer_y + half_kernel);
+
+ for (int32_t target_y = start_y; target_y <= end_y; target_y++)
+ kernel[target_y - start_y] = _lanczos((buffer_real_y - target_y) / scale_factor);
+
+ for (int32_t dst_x = 0; dst_x < dst_width; dst_x++) {
+
+ float pixel[CC] = { 0 };
+ float weight = 0;
+
+ for (int32_t target_y = start_y; target_y <= end_y; target_y++) {
+
+ float lanczos_val = kernel[target_y - start_y];
+ weight += lanczos_val;
+
+ float *buffer_data = ((float *)buffer) + (target_y * dst_width + dst_x) * CC;
+
+ for (uint32_t i = 0; i < CC; i++)
+ pixel[i] += buffer_data[i] * lanczos_val;
+ }
+
+ T *dst_data = ((T *)p_dst) + (dst_y * dst_width + dst_x) * CC;
+
+ for (uint32_t i = 0; i < CC; i++) {
+ pixel[i] /= weight;
+
+ if (sizeof(T) == 1) //byte
+ dst_data[i] = CLAMP(Math::fast_ftoi(pixel[i]), 0, 255);
+ else if (sizeof(T) == 2) //half float
+ dst_data[i] = Math::make_half_float(pixel[i]);
+ else // float
+ dst_data[i] = pixel[i];
+ }
+ }
+ }
+
+ memdelete_arr(kernel);
+ } // End of second pass
+
+ memdelete_arr(buffer);
+}
+
static void _overlay(const uint8_t *__restrict p_src, uint8_t *__restrict p_dst, float p_alpha, uint32_t p_width, uint32_t p_height, uint32_t p_pixel_size) {
uint16_t alpha = CLAMP((uint16_t)(p_alpha * 256.0f), 0, 256);
@@ -939,6 +1064,31 @@ void Image::resize(int p_width, int p_height, Interpolation p_interpolation) {
}
}
} break;
+ case INTERPOLATE_LANCZOS: {
+
+ if (format >= FORMAT_L8 && format <= FORMAT_RGBA8) {
+ switch (get_format_pixel_size(format)) {
+ case 1: _scale_lanczos<1, uint8_t>(r_ptr, w_ptr, width, height, p_width, p_height); break;
+ case 2: _scale_lanczos<2, uint8_t>(r_ptr, w_ptr, width, height, p_width, p_height); break;
+ case 3: _scale_lanczos<3, uint8_t>(r_ptr, w_ptr, width, height, p_width, p_height); break;
+ case 4: _scale_lanczos<4, uint8_t>(r_ptr, w_ptr, width, height, p_width, p_height); break;
+ }
+ } else if (format >= FORMAT_RF && format <= FORMAT_RGBAF) {
+ switch (get_format_pixel_size(format)) {
+ case 4: _scale_lanczos<1, float>(r_ptr, w_ptr, width, height, p_width, p_height); break;
+ case 8: _scale_lanczos<2, float>(r_ptr, w_ptr, width, height, p_width, p_height); break;
+ case 12: _scale_lanczos<3, float>(r_ptr, w_ptr, width, height, p_width, p_height); break;
+ case 16: _scale_lanczos<4, float>(r_ptr, w_ptr, width, height, p_width, p_height); break;
+ }
+ } else if (format >= FORMAT_RH && format <= FORMAT_RGBAH) {
+ switch (get_format_pixel_size(format)) {
+ case 2: _scale_lanczos<1, uint16_t>(r_ptr, w_ptr, width, height, p_width, p_height); break;
+ case 4: _scale_lanczos<2, uint16_t>(r_ptr, w_ptr, width, height, p_width, p_height); break;
+ case 6: _scale_lanczos<3, uint16_t>(r_ptr, w_ptr, width, height, p_width, p_height); break;
+ case 8: _scale_lanczos<4, uint16_t>(r_ptr, w_ptr, width, height, p_width, p_height); break;
+ }
+ }
+ } break;
}
r = PoolVector<uint8_t>::Read();
@@ -1876,7 +2026,7 @@ Image::Image(int p_width, int p_height, bool p_mipmaps, Format p_format, const P
Rect2 Image::get_used_rect() const {
- if (format != FORMAT_LA8 && format != FORMAT_RGBA8)
+ if (format != FORMAT_LA8 && format != FORMAT_RGBA8 && format != FORMAT_RGBAF && format != FORMAT_RGBAH && format != FORMAT_RGBA4444 && format != FORMAT_RGBA5551)
return Rect2(Point2(), Size2(width, height));
int len = data.size();
@@ -1884,17 +2034,13 @@ Rect2 Image::get_used_rect() const {
if (len == 0)
return Rect2();
- //int data_size = len;
- PoolVector<uint8_t>::Read r = data.read();
- const unsigned char *rptr = r.ptr();
-
- int ps = format == FORMAT_LA8 ? 2 : 4;
+ const_cast<Image *>(this)->lock();
int minx = 0xFFFFFF, miny = 0xFFFFFFF;
int maxx = -1, maxy = -1;
for (int j = 0; j < height; j++) {
for (int i = 0; i < width; i++) {
- bool opaque = rptr[(j * width + i) * ps + (ps - 1)] > 2;
+ bool opaque = get_pixel(i, j).a > 0.99;
if (!opaque)
continue;
if (i > maxx)
@@ -1908,6 +2054,8 @@ Rect2 Image::get_used_rect() const {
}
}
+ const_cast<Image *>(this)->unlock();
+
if (maxx == -1)
return Rect2();
else
@@ -2687,6 +2835,7 @@ void Image::_bind_methods() {
BIND_ENUM_CONSTANT(INTERPOLATE_BILINEAR);
BIND_ENUM_CONSTANT(INTERPOLATE_CUBIC);
BIND_ENUM_CONSTANT(INTERPOLATE_TRILINEAR);
+ BIND_ENUM_CONSTANT(INTERPOLATE_LANCZOS);
BIND_ENUM_CONSTANT(ALPHA_NONE);
BIND_ENUM_CONSTANT(ALPHA_BIT);
diff --git a/core/image.h b/core/image.h
index 69a42f169a..752ef20208 100644
--- a/core/image.h
+++ b/core/image.h
@@ -109,6 +109,7 @@ public:
INTERPOLATE_BILINEAR,
INTERPOLATE_CUBIC,
INTERPOLATE_TRILINEAR,
+ INTERPOLATE_LANCZOS,
/* INTERPOLATE_TRICUBIC, */
/* INTERPOLATE GAUSS */
};
diff --git a/core/io/compression.cpp b/core/io/compression.cpp
index a113f3b61b..b51e50150e 100644
--- a/core/io/compression.cpp
+++ b/core/io/compression.cpp
@@ -175,7 +175,9 @@ int Compression::decompress(uint8_t *p_dst, int p_dst_max_size, const uint8_t *p
} break;
case MODE_ZSTD: {
ZSTD_DCtx *dctx = ZSTD_createDCtx();
- if (zstd_long_distance_matching) ZSTD_DCtx_setMaxWindowSize(dctx, (size_t)1 << zstd_window_log_size);
+ if (zstd_long_distance_matching) {
+ ZSTD_DCtx_setParameter(dctx, ZSTD_d_windowLogMax, zstd_window_log_size);
+ }
int ret = ZSTD_decompressDCtx(dctx, p_dst, p_dst_max_size, p_src, p_src_size);
ZSTD_freeDCtx(dctx);
return ret;
@@ -189,4 +191,4 @@ int Compression::zlib_level = Z_DEFAULT_COMPRESSION;
int Compression::gzip_level = Z_DEFAULT_COMPRESSION;
int Compression::zstd_level = 3;
bool Compression::zstd_long_distance_matching = false;
-int Compression::zstd_window_log_size = 27;
+int Compression::zstd_window_log_size = 27; // ZSTD_WINDOWLOG_LIMIT_DEFAULT
diff --git a/core/io/file_access_buffered_fa.h b/core/io/file_access_buffered_fa.h
index be960fbc25..24b40cbce8 100644
--- a/core/io/file_access_buffered_fa.h
+++ b/core/io/file_access_buffered_fa.h
@@ -143,6 +143,14 @@ public:
return f._get_modified_time(p_file);
}
+ virtual uint32_t _get_unix_permissions(const String &p_file) {
+ return f._get_unix_permissions(p_file);
+ }
+
+ virtual Error _set_unix_permissions(const String &p_file, uint32_t p_permissions) {
+ return f._set_unix_permissions(p_file, p_permissions);
+ }
+
FileAccessBufferedFA(){
};
diff --git a/core/io/file_access_compressed.cpp b/core/io/file_access_compressed.cpp
index b268d5c710..6c4310a572 100644
--- a/core/io/file_access_compressed.cpp
+++ b/core/io/file_access_compressed.cpp
@@ -373,6 +373,19 @@ uint64_t FileAccessCompressed::_get_modified_time(const String &p_file) {
return 0;
}
+uint32_t FileAccessCompressed::_get_unix_permissions(const String &p_file) {
+ if (f)
+ return f->_get_unix_permissions(p_file);
+ return 0;
+}
+
+Error FileAccessCompressed::_set_unix_permissions(const String &p_file, uint32_t p_permissions) {
+ if (f) {
+ return f->_set_unix_permissions(p_file, p_permissions);
+ }
+ return FAILED;
+}
+
FileAccessCompressed::FileAccessCompressed() :
cmode(Compression::MODE_ZSTD),
writing(false),
diff --git a/core/io/file_access_compressed.h b/core/io/file_access_compressed.h
index f408b1bc29..773fed6a3a 100644
--- a/core/io/file_access_compressed.h
+++ b/core/io/file_access_compressed.h
@@ -91,6 +91,8 @@ public:
virtual bool file_exists(const String &p_name); ///< return true if a file exists
virtual uint64_t _get_modified_time(const String &p_file);
+ virtual uint32_t _get_unix_permissions(const String &p_file);
+ virtual Error _set_unix_permissions(const String &p_file, uint32_t p_permissions);
FileAccessCompressed();
virtual ~FileAccessCompressed();
diff --git a/core/io/file_access_encrypted.cpp b/core/io/file_access_encrypted.cpp
index 6ad68dd74d..3cf6908961 100644
--- a/core/io/file_access_encrypted.cpp
+++ b/core/io/file_access_encrypted.cpp
@@ -301,6 +301,16 @@ uint64_t FileAccessEncrypted::_get_modified_time(const String &p_file) {
return 0;
}
+uint32_t FileAccessEncrypted::_get_unix_permissions(const String &p_file) {
+
+ return 0;
+}
+
+Error FileAccessEncrypted::_set_unix_permissions(const String &p_file, uint32_t p_permissions) {
+
+ return FAILED;
+}
+
FileAccessEncrypted::FileAccessEncrypted() {
file = NULL;
diff --git a/core/io/file_access_encrypted.h b/core/io/file_access_encrypted.h
index e77d62a9f4..d779a150ac 100644
--- a/core/io/file_access_encrypted.h
+++ b/core/io/file_access_encrypted.h
@@ -79,6 +79,8 @@ public:
virtual bool file_exists(const String &p_name); ///< return true if a file exists
virtual uint64_t _get_modified_time(const String &p_file);
+ virtual uint32_t _get_unix_permissions(const String &p_file);
+ virtual Error _set_unix_permissions(const String &p_file, uint32_t p_permissions);
FileAccessEncrypted();
~FileAccessEncrypted();
diff --git a/core/io/file_access_memory.h b/core/io/file_access_memory.h
index 73952133c1..4db7811aaa 100644
--- a/core/io/file_access_memory.h
+++ b/core/io/file_access_memory.h
@@ -70,6 +70,8 @@ public:
virtual bool file_exists(const String &p_name); ///< return true if a file exists
virtual uint64_t _get_modified_time(const String &p_file) { return 0; }
+ virtual uint32_t _get_unix_permissions(const String &p_file) { return 0; }
+ virtual Error _set_unix_permissions(const String &p_file, uint32_t p_permissions) { return FAILED; }
FileAccessMemory();
};
diff --git a/core/io/file_access_network.cpp b/core/io/file_access_network.cpp
index 501a21a50d..722e62c54e 100644
--- a/core/io/file_access_network.cpp
+++ b/core/io/file_access_network.cpp
@@ -497,6 +497,16 @@ uint64_t FileAccessNetwork::_get_modified_time(const String &p_file) {
return exists_modtime;
}
+uint32_t FileAccessNetwork::_get_unix_permissions(const String &p_file) {
+ //could be implemented, not sure if worth it
+ return 0;
+}
+
+Error FileAccessNetwork::_set_unix_permissions(const String &p_file, uint32_t p_permissions) {
+
+ return FAILED;
+}
+
void FileAccessNetwork::configure() {
GLOBAL_DEF("network/remote_fs/page_size", 65536);
diff --git a/core/io/file_access_network.h b/core/io/file_access_network.h
index 5bbf7588c7..073b75a37b 100644
--- a/core/io/file_access_network.h
+++ b/core/io/file_access_network.h
@@ -159,6 +159,8 @@ public:
virtual bool file_exists(const String &p_path); ///< return true if a file exists
virtual uint64_t _get_modified_time(const String &p_file);
+ virtual uint32_t _get_unix_permissions(const String &p_file);
+ virtual Error _set_unix_permissions(const String &p_file, uint32_t p_permissions);
static void configure();
diff --git a/core/io/file_access_pack.h b/core/io/file_access_pack.h
index a90672ce26..a21dd7d22d 100644
--- a/core/io/file_access_pack.h
+++ b/core/io/file_access_pack.h
@@ -142,6 +142,8 @@ class FileAccessPack : public FileAccess {
FileAccess *f;
virtual Error _open(const String &p_path, int p_mode_flags);
virtual uint64_t _get_modified_time(const String &p_file) { return 0; }
+ virtual uint32_t _get_unix_permissions(const String &p_file) { return 0; }
+ virtual Error _set_unix_permissions(const String &p_file, uint32_t p_permissions) { return FAILED; }
public:
virtual void close();
diff --git a/core/io/file_access_zip.h b/core/io/file_access_zip.h
index fc8f85c07b..217176c0af 100644
--- a/core/io/file_access_zip.h
+++ b/core/io/file_access_zip.h
@@ -112,6 +112,8 @@ public:
virtual bool file_exists(const String &p_name); ///< return true if a file exists
virtual uint64_t _get_modified_time(const String &p_file) { return 0; } // todo
+ virtual uint32_t _get_unix_permissions(const String &p_file) { return 0; }
+ virtual Error _set_unix_permissions(const String &p_file, uint32_t p_permissions) { return FAILED; }
FileAccessZip(const String &p_path, const PackedData::PackedFile &p_file);
~FileAccessZip();
diff --git a/core/io/http_client.cpp b/core/io/http_client.cpp
index e5c6d2a4f2..ce2054db36 100644
--- a/core/io/http_client.cpp
+++ b/core/io/http_client.cpp
@@ -429,7 +429,7 @@ Error HTTPClient::poll() {
response_num = RESPONSE_OK;
// Per the HTTP 1.1 spec, keep-alive is the default.
- // Not following that specification breaks standard implemetations.
+ // Not following that specification breaks standard implementations.
// Broken web servers should be fixed.
bool keep_alive = true;
diff --git a/core/io/multiplayer_api.cpp b/core/io/multiplayer_api.cpp
index 86382939f1..2779837190 100644
--- a/core/io/multiplayer_api.cpp
+++ b/core/io/multiplayer_api.cpp
@@ -283,8 +283,9 @@ void MultiplayerAPI::_process_rpc(Node *p_node, const StringName &p_name, int p_
rpc_mode = p_node->get_script_instance()->get_rpc_mode(p_name);
}
- ERR_EXPLAIN("RPC '" + String(p_name) + "' is not allowed from: " + itos(p_from) + ". Mode is " + itos((int)rpc_mode) + ", master is " + itos(p_node->get_network_master()) + ".");
- ERR_FAIL_COND(!_can_call_mode(p_node, rpc_mode, p_from));
+ bool can_call = _can_call_mode(p_node, rpc_mode, p_from);
+ ERR_EXPLAIN("RPC '" + String(p_name) + "' is not allowed on node " + p_node->get_path() + " from: " + itos(p_from) + ". Mode is " + itos((int)rpc_mode) + ", master is " + itos(p_node->get_network_master()) + ".");
+ ERR_FAIL_COND(!can_call);
int argc = p_packet[p_offset];
Vector<Variant> args;
@@ -332,8 +333,9 @@ void MultiplayerAPI::_process_rset(Node *p_node, const StringName &p_name, int p
rset_mode = p_node->get_script_instance()->get_rset_mode(p_name);
}
- ERR_EXPLAIN("RSET '" + String(p_name) + "' is not allowed from: " + itos(p_from) + ". Mode is " + itos((int)rset_mode) + ", master is " + itos(p_node->get_network_master()) + ".");
- ERR_FAIL_COND(!_can_call_mode(p_node, rset_mode, p_from));
+ bool can_call = _can_call_mode(p_node, rset_mode, p_from);
+ ERR_EXPLAIN("RSET '" + String(p_name) + "' is not allowed on node " + p_node->get_path() + " from: " + itos(p_from) + ". Mode is " + itos((int)rset_mode) + ", master is " + itos(p_node->get_network_master()) + ".");
+ ERR_FAIL_COND(!can_call);
Variant value;
Error err = decode_variant(value, &p_packet[p_offset], p_packet_len - p_offset, NULL, allow_object_decoding || network_peer->is_object_decoding_allowed());
@@ -632,7 +634,7 @@ void MultiplayerAPI::rpcp(Node *p_node, int p_peer_id, bool p_unreliable, const
ERR_FAIL_COND(network_peer->get_connection_status() != NetworkedMultiplayerPeer::CONNECTION_CONNECTED);
int node_id = network_peer->get_unique_id();
- bool skip_rpc = false;
+ bool skip_rpc = node_id == p_peer_id;
bool call_local_native = false;
bool call_local_script = false;
bool is_master = p_node->is_network_master();
@@ -659,8 +661,11 @@ void MultiplayerAPI::rpcp(Node *p_node, int p_peer_id, bool p_unreliable, const
}
if (call_local_native) {
+ int temp_id = rpc_sender_id;
+ rpc_sender_id = get_network_unique_id();
Variant::CallError ce;
p_node->call(p_method, p_arg, p_argcount, ce);
+ rpc_sender_id = temp_id;
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;
@@ -670,9 +675,12 @@ void MultiplayerAPI::rpcp(Node *p_node, int p_peer_id, bool p_unreliable, const
}
if (call_local_script) {
+ int temp_id = rpc_sender_id;
+ rpc_sender_id = get_network_unique_id();
Variant::CallError ce;
ce.error = Variant::CallError::CALL_OK;
p_node->get_script_instance()->call(p_method, p_arg, p_argcount, ce);
+ rpc_sender_id = temp_id;
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;
@@ -680,6 +688,9 @@ void MultiplayerAPI::rpcp(Node *p_node, int p_peer_id, bool p_unreliable, const
return;
}
}
+
+ ERR_EXPLAIN("RPC '" + p_method + "' on yourself is not allowed by selected mode");
+ ERR_FAIL_COND(skip_rpc && !(call_local_native || call_local_script));
}
void MultiplayerAPI::rsetp(Node *p_node, int p_peer_id, bool p_unreliable, const StringName &p_property, const Variant &p_value) {
@@ -693,13 +704,11 @@ void MultiplayerAPI::rsetp(Node *p_node, int p_peer_id, bool p_unreliable, const
int node_id = network_peer->get_unique_id();
bool is_master = p_node->is_network_master();
- bool skip_rset = false;
+ bool skip_rset = node_id == p_peer_id;
+ bool set_local = 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, RPCMode>::Element *E = p_node->get_node_rset_mode(p_property);
if (E) {
@@ -708,7 +717,11 @@ void MultiplayerAPI::rsetp(Node *p_node, int p_peer_id, bool p_unreliable, const
if (set_local) {
bool valid;
+ int temp_id = rpc_sender_id;
+
+ rpc_sender_id = get_network_unique_id();
p_node->set(p_property, p_value, &valid);
+ rpc_sender_id = temp_id;
if (!valid) {
String error = "rset() aborted in local set, property not found: - " + String(p_property);
@@ -722,8 +735,11 @@ void MultiplayerAPI::rsetp(Node *p_node, int p_peer_id, bool p_unreliable, const
set_local = _should_call_local(rpc_mode, is_master, skip_rset);
if (set_local) {
+ int temp_id = rpc_sender_id;
+ rpc_sender_id = get_network_unique_id();
bool valid = p_node->get_script_instance()->set(p_property, p_value);
+ rpc_sender_id = temp_id;
if (!valid) {
String error = "rset() aborted in local script set, property not found: - " + String(p_property);
@@ -734,8 +750,11 @@ void MultiplayerAPI::rsetp(Node *p_node, int p_peer_id, bool p_unreliable, const
}
}
- if (skip_rset)
+ if (skip_rset) {
+ ERR_EXPLAIN("RSET for '" + p_property + "' on yourself is not allowed by selected mode");
+ ERR_FAIL_COND(!set_local);
return;
+ }
const Variant *vptr = &p_value;
diff --git a/core/io/resource_importer.cpp b/core/io/resource_importer.cpp
index b5fa412576..4a58d37ca5 100644
--- a/core/io/resource_importer.cpp
+++ b/core/io/resource_importer.cpp
@@ -94,6 +94,8 @@ Error ResourceFormatImporter::_get_path_and_type(const String &p_path, PathAndTy
r_path_and_type.type = value;
} else if (assign == "importer") {
r_path_and_type.importer = value;
+ } else if (assign == "group_file") {
+ r_path_and_type.group_file = value;
} else if (assign == "metadata") {
r_path_and_type.metadata = value;
} else if (assign == "valid") {
@@ -294,6 +296,14 @@ void ResourceFormatImporter::get_internal_resource_path_list(const String &p_pat
memdelete(f);
}
+String ResourceFormatImporter::get_import_group_file(const String &p_path) const {
+
+ bool valid = true;
+ PathAndType pat;
+ _get_path_and_type(p_path, pat, &valid);
+ return valid ? pat.group_file : String();
+}
+
bool ResourceFormatImporter::is_import_valid(const String &p_path) const {
bool valid = true;
diff --git a/core/io/resource_importer.h b/core/io/resource_importer.h
index 1c146c33d7..2e01989564 100644
--- a/core/io/resource_importer.h
+++ b/core/io/resource_importer.h
@@ -43,6 +43,7 @@ class ResourceFormatImporter : public ResourceFormatLoader {
String path;
String type;
String importer;
+ String group_file;
Variant metadata;
};
@@ -69,6 +70,7 @@ public:
virtual bool is_import_valid(const String &p_path) const;
virtual void get_dependencies(const String &p_path, List<String> *p_dependencies, bool p_add_types = false);
virtual bool is_imported(const String &p_path) const { return recognize_path(p_path); }
+ virtual String get_import_group_file(const String &p_path) const;
virtual bool exists(const String &p_path) const;
virtual bool can_be_imported(const String &p_path) const;
@@ -120,8 +122,11 @@ public:
virtual void get_import_options(List<ImportOption> *r_options, int p_preset = 0) const = 0;
virtual bool get_option_visibility(const String &p_option, const Map<StringName, Variant> &p_options) const = 0;
+ virtual String get_option_group_file() const { return String(); }
virtual Error import(const String &p_source_file, const String &p_save_path, const Map<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files = NULL, Variant *r_metadata = NULL) = 0;
+
+ virtual Error import_group_file(const String &p_group_file, const Map<String, Map<StringName, Variant> > &p_source_file_options, const Map<String, String> &p_base_paths) { return ERR_UNAVAILABLE; }
virtual bool are_import_settings_valid(const String &p_path) const { return true; }
virtual String get_import_settings_string() const { return String(); }
};
diff --git a/core/io/resource_loader.cpp b/core/io/resource_loader.cpp
index e4b694b64f..56d3b8b133 100644
--- a/core/io/resource_loader.cpp
+++ b/core/io/resource_loader.cpp
@@ -608,6 +608,30 @@ int ResourceLoader::get_import_order(const String &p_path) {
return 0;
}
+String ResourceLoader::get_import_group_file(const String &p_path) {
+ String path = _path_remap(p_path);
+
+ String local_path;
+ if (path.is_rel_path())
+ local_path = "res://" + path;
+ else
+ local_path = ProjectSettings::get_singleton()->localize_path(path);
+
+ for (int i = 0; i < loader_count; i++) {
+
+ if (!loader[i]->recognize_path(local_path))
+ continue;
+ /*
+ if (p_type_hint!="" && !loader[i]->handles_type(p_type_hint))
+ continue;
+ */
+
+ return loader[i]->get_import_group_file(p_path);
+ }
+
+ return String(); //not found
+}
+
bool ResourceLoader::is_import_valid(const String &p_path) {
String path = _path_remap(p_path);
diff --git a/core/io/resource_loader.h b/core/io/resource_loader.h
index ca7610a0d2..9e7020be7c 100644
--- a/core/io/resource_loader.h
+++ b/core/io/resource_loader.h
@@ -81,6 +81,7 @@ public:
virtual bool is_import_valid(const String &p_path) const { return true; }
virtual bool is_imported(const String &p_path) const { return false; }
virtual int get_import_order(const String &p_path) const { return 0; }
+ virtual String get_import_group_file(const String &p_path) const { return ""; } //no group
virtual ~ResourceFormatLoader() {}
};
@@ -155,6 +156,7 @@ public:
static void get_dependencies(const String &p_path, List<String> *p_dependencies, bool p_add_types = false);
static Error rename_dependencies(const String &p_path, const Map<String, String> &p_map);
static bool is_import_valid(const String &p_path);
+ static String get_import_group_file(const String &p_path);
static bool is_imported(const String &p_path);
static int get_import_order(const String &p_path);
diff --git a/core/io/zip_io.h b/core/io/zip_io.h
index fb63878a4c..4eb1c8b46c 100644
--- a/core/io/zip_io.h
+++ b/core/io/zip_io.h
@@ -33,7 +33,7 @@
#include "core/os/file_access.h"
-// Not direclty used in this header, but assumed available in downstream users
+// Not directly used in this header, but assumed available in downstream users
// like platform/*/export/export.cpp. Could be fixed, but probably better to have
// thirdparty includes in as little headers as possible.
#include "thirdparty/minizip/unzip.h"
diff --git a/core/list.h b/core/list.h
index c26aad6463..103a82a31d 100644
--- a/core/list.h
+++ b/core/list.h
@@ -503,8 +503,7 @@ public:
if (p_I->prev_ptr)
p_I->prev_ptr->next_ptr = p_I->next_ptr;
- if (p_I->next_ptr)
- p_I->next_ptr->prev_ptr = p_I->prev_ptr;
+ p_I->next_ptr->prev_ptr = p_I->prev_ptr;
_data->last->next_ptr = p_I;
p_I->prev_ptr = _data->last;
@@ -538,8 +537,7 @@ public:
if (_data->last == p_I)
_data->last = p_I->prev_ptr;
- if (p_I->prev_ptr)
- p_I->prev_ptr->next_ptr = p_I->next_ptr;
+ p_I->prev_ptr->next_ptr = p_I->next_ptr;
if (p_I->next_ptr)
p_I->next_ptr->prev_ptr = p_I->prev_ptr;
@@ -691,6 +689,10 @@ public:
memdelete_arr(aux_buffer);
}
+ const void *id() const {
+ return (void *)_data;
+ }
+
/**
* copy constructor for the list
*/
diff --git a/core/make_binders.py b/core/make_binders.py
index 4c61b90d99..5c1c66cab6 100644
--- a/core/make_binders.py
+++ b/core/make_binders.py
@@ -9,6 +9,12 @@ public:
$ifret R$ $ifnoret void$ (T::*method)($arg, P@$) $ifconst const$;
#ifdef DEBUG_METHODS_ENABLED
virtual Variant::Type _gen_argument_type(int p_arg) const { return _get_argument_type(p_arg); }
+ virtual GodotTypeInfo::Metadata get_argument_meta(int p_arg) const {
+ $ifret if (p_arg==-1) return GetTypeInfo<R>::METADATA;$
+ $arg if (p_arg==(@-1)) return GetTypeInfo<P@>::METADATA;
+ $
+ return GodotTypeInfo::METADATA_NONE;
+ }
Variant::Type _get_argument_type(int p_argument) const {
$ifret if (p_argument==-1) return (Variant::Type)GetTypeInfo<R>::VARIANT_TYPE;$
$arg if (p_argument==(@-1)) return (Variant::Type)GetTypeInfo<P@>::VARIANT_TYPE;
@@ -94,6 +100,12 @@ public:
#ifdef DEBUG_METHODS_ENABLED
virtual Variant::Type _gen_argument_type(int p_arg) const { return _get_argument_type(p_arg); }
+ virtual GodotTypeInfo::Metadata get_argument_meta(int p_arg) const {
+ $ifret if (p_arg==-1) return GetTypeInfo<R>::METADATA;$
+ $arg if (p_arg==(@-1)) return GetTypeInfo<P@>::METADATA;
+ $
+ return GodotTypeInfo::METADATA_NONE;
+ }
Variant::Type _get_argument_type(int p_argument) const {
$ifret if (p_argument==-1) return (Variant::Type)GetTypeInfo<R>::VARIANT_TYPE;$
diff --git a/core/math/a_star.cpp b/core/math/a_star.cpp
index e1388ad2ac..3d71e66f80 100644
--- a/core/math/a_star.cpp
+++ b/core/math/a_star.cpp
@@ -54,7 +54,8 @@ void AStar::add_point(int p_id, const Vector3 &p_pos, real_t p_weight_scale) {
pt->pos = p_pos;
pt->weight_scale = p_weight_scale;
pt->prev_point = NULL;
- pt->last_pass = 0;
+ pt->open_pass = 0;
+ pt->closed_pass = 0;
pt->enabled = true;
points[p_id] = pt;
} else {
@@ -246,86 +247,62 @@ bool AStar::_solve(Point *begin_point, Point *end_point) {
if (!end_point->enabled)
return false;
- SelfList<Point>::List open_list;
-
bool found_route = false;
- for (Set<Point *>::Element *E = begin_point->neighbours.front(); E; E = E->next()) {
-
- Point *n = E->get();
+ Vector<Point *> open_list;
+ SortArray<Point *, SortPoints> sorter;
- if (!n->enabled)
- continue;
+ begin_point->g_score = 0;
+ begin_point->f_score = _estimate_cost(begin_point->id, end_point->id);
- n->prev_point = begin_point;
- n->distance = _compute_cost(begin_point->id, n->id) * n->weight_scale;
- n->last_pass = pass;
- open_list.add(&n->list);
- }
+ open_list.push_back(begin_point);
while (true) {
- if (open_list.first() == NULL) {
- // No path found
+ if (open_list.size() == 0) // No path found
break;
- }
- // Check open list
-
- SelfList<Point> *least_cost_point = open_list.first();
- real_t least_cost = Math_INF;
- // TODO: Cache previous results
- for (SelfList<Point> *E = open_list.first(); E; E = E->next()) {
-
- Point *p = E->self();
-
- real_t cost = p->distance;
- cost += _estimate_cost(p->id, end_point->id);
-
- if (cost < least_cost) {
- least_cost_point = E;
- least_cost = cost;
- }
- }
+ Point *p = open_list[0]; // The currently processed point
- Point *p = least_cost_point->self();
if (p == end_point) {
found_route = true;
break;
}
+ sorter.pop_heap(0, open_list.size(), open_list.ptrw()); // Remove the current point from the open list
+ open_list.remove(open_list.size() - 1);
+ p->closed_pass = pass; // Mark the point as closed
+
for (Set<Point *>::Element *E = p->neighbours.front(); E; E = E->next()) {
- Point *e = E->get();
+ Point *e = E->get(); // The neighbour point
- if (!e->enabled)
+ if (!e->enabled || e->closed_pass == pass)
continue;
- real_t distance = _compute_cost(p->id, e->id) * e->weight_scale + p->distance;
+ real_t tentative_g_score = p->g_score + _compute_cost(p->id, e->id) * e->weight_scale;
+
+ bool new_point = false;
- if (e->last_pass == pass) {
- // Already visited, is this cheaper?
+ if (e->open_pass != pass) { // The point wasn't inside the open list
- if (e->distance > distance) {
- e->prev_point = p;
- e->distance = distance;
- }
- } else {
- // Add to open neighbours
+ e->open_pass = pass;
+ open_list.push_back(e);
+ new_point = true;
+ } else if (tentative_g_score >= e->g_score) { // The new path is worse than the previous
- e->prev_point = p;
- e->distance = distance;
- e->last_pass = pass; // Mark as used
- open_list.add(&e->list);
+ continue;
}
- }
- open_list.remove(least_cost_point);
- }
+ e->prev_point = p;
+ e->g_score = tentative_g_score;
+ e->f_score = e->g_score + _estimate_cost(e->id, end_point->id);
- // Clear the openf list
- while (open_list.first()) {
- open_list.remove(open_list.first());
+ if (new_point) // The position of the new points is already known
+ sorter.push_heap(0, open_list.size() - 1, 0, e, open_list.ptrw());
+ else
+ sorter.push_heap(0, open_list.find(e), 0, e, open_list.ptrw());
+ }
}
return found_route;
@@ -352,8 +329,6 @@ PoolVector<Vector3> AStar::get_point_path(int p_from_id, int p_to_id) {
ERR_FAIL_COND_V(!points.has(p_from_id), PoolVector<Vector3>());
ERR_FAIL_COND_V(!points.has(p_to_id), PoolVector<Vector3>());
- pass++;
-
Point *a = points[p_from_id];
Point *b = points[p_to_id];
@@ -403,8 +378,6 @@ PoolVector<int> AStar::get_id_path(int p_from_id, int p_to_id) {
ERR_FAIL_COND_V(!points.has(p_from_id), PoolVector<int>());
ERR_FAIL_COND_V(!points.has(p_to_id), PoolVector<int>());
- pass++;
-
Point *a = points[p_from_id];
Point *b = points[p_to_id];
diff --git a/core/math/a_star.h b/core/math/a_star.h
index c63e1aa4dc..fac8a9d312 100644
--- a/core/math/a_star.h
+++ b/core/math/a_star.h
@@ -48,26 +48,34 @@ class AStar : public Reference {
struct Point {
- SelfList<Point> list;
-
int id;
Vector3 pos;
real_t weight_scale;
- uint64_t last_pass;
bool enabled;
Set<Point *> neighbours;
// Used for pathfinding
Point *prev_point;
- real_t distance;
-
- Point() :
- list(this) {}
+ real_t g_score;
+ real_t f_score;
+ uint64_t open_pass;
+ uint64_t closed_pass;
};
Map<int, Point *> points;
+ struct SortPoints {
+ _FORCE_INLINE_ bool operator()(const Point *A, const Point *B) const { // Returns true when the Point A is worse than Point B
+ if (A->f_score > B->f_score)
+ return true;
+ else if (A->f_score < B->f_score)
+ return false;
+ else
+ return A->g_score < B->g_score; // If the f_costs are the same then prioritize the points that are further away from the start
+ }
+ };
+
struct Segment {
union {
struct {
diff --git a/core/math/audio_frame.h b/core/math/audio_frame.h
index ebe0356c93..98e4e33021 100644
--- a/core/math/audio_frame.h
+++ b/core/math/audio_frame.h
@@ -31,6 +31,7 @@
#ifndef AUDIOFRAME_H
#define AUDIOFRAME_H
+#include "core/math/vector2.h"
#include "core/typedefs.h"
static inline float undenormalise(volatile float f) {
@@ -128,6 +129,14 @@ struct AudioFrame {
return *this;
}
+ _ALWAYS_INLINE_ operator Vector2() const {
+ return Vector2(l, r);
+ }
+
+ _ALWAYS_INLINE_ AudioFrame(const Vector2 &p_v2) {
+ l = p_v2.x;
+ r = p_v2.y;
+ }
_ALWAYS_INLINE_ AudioFrame() {}
};
diff --git a/core/math/camera_matrix.cpp b/core/math/camera_matrix.cpp
index caf08c7379..f615cc8c65 100644
--- a/core/math/camera_matrix.cpp
+++ b/core/math/camera_matrix.cpp
@@ -210,6 +210,14 @@ void CameraMatrix::set_frustum(real_t p_left, real_t p_right, real_t p_bottom, r
te[15] = 0;
}
+void CameraMatrix::set_frustum(real_t p_size, real_t p_aspect, Vector2 p_offset, real_t p_near, real_t p_far, bool p_flip_fov) {
+ if (!p_flip_fov) {
+ p_size *= p_aspect;
+ }
+
+ set_frustum(-p_size / 2 + p_offset.x, +p_size / 2 + p_offset.x, -p_size / p_aspect / 2 + p_offset.y, +p_size / p_aspect / 2 + p_offset.y, p_near, p_far);
+}
+
real_t CameraMatrix::get_z_far() const {
const real_t *matrix = (const real_t *)this->matrix;
diff --git a/core/math/camera_matrix.h b/core/math/camera_matrix.h
index 015588a8cb..3bcf48f5da 100644
--- a/core/math/camera_matrix.h
+++ b/core/math/camera_matrix.h
@@ -61,6 +61,7 @@ struct CameraMatrix {
void set_orthogonal(real_t p_left, real_t p_right, real_t p_bottom, real_t p_top, real_t p_znear, real_t p_zfar);
void set_orthogonal(real_t p_size, real_t p_aspect, real_t p_znear, real_t p_zfar, bool p_flip_fov = false);
void set_frustum(real_t p_left, real_t p_right, real_t p_bottom, real_t p_top, real_t p_near, real_t p_far);
+ void set_frustum(real_t p_size, real_t p_aspect, Vector2 p_offset, real_t p_near, real_t p_far, bool p_flip_fov = false);
static real_t get_fovy(real_t p_fovx, real_t p_aspect) {
diff --git a/core/math/delaunay.h b/core/math/delaunay.h
index bd0cf97937..ed52c506db 100644
--- a/core/math/delaunay.h
+++ b/core/math/delaunay.h
@@ -80,11 +80,11 @@ public:
}
static bool edge_compare(const Vector<Vector2> &p_vertices, const Edge &p_a, const Edge &p_b) {
- if (p_vertices[p_a.edge[0]].distance_to(p_vertices[p_b.edge[0]]) < CMP_EPSILON && p_vertices[p_a.edge[1]].distance_to(p_vertices[p_b.edge[1]]) < CMP_EPSILON) {
+ if (Math::is_zero_approx(p_vertices[p_a.edge[0]].distance_to(p_vertices[p_b.edge[0]])) && Math::is_zero_approx(p_vertices[p_a.edge[1]].distance_to(p_vertices[p_b.edge[1]]))) {
return true;
}
- if (p_vertices[p_a.edge[0]].distance_to(p_vertices[p_b.edge[1]]) < CMP_EPSILON && p_vertices[p_a.edge[1]].distance_to(p_vertices[p_b.edge[0]]) < CMP_EPSILON) {
+ if (Math::is_zero_approx(p_vertices[p_a.edge[0]].distance_to(p_vertices[p_b.edge[1]])) && Math::is_zero_approx(p_vertices[p_a.edge[1]].distance_to(p_vertices[p_b.edge[0]]))) {
return true;
}
diff --git a/core/math/expression.cpp b/core/math/expression.cpp
index 133dcc7ab9..079c9b524f 100644
--- a/core/math/expression.cpp
+++ b/core/math/expression.cpp
@@ -64,6 +64,7 @@ const char *Expression::func_name[Expression::FUNC_MAX] = {
"is_inf",
"ease",
"decimals",
+ "step_decimals",
"stepify",
"lerp",
"inverse_lerp",
@@ -149,6 +150,7 @@ int Expression::get_func_argument_count(BuiltinFunc p_func) {
case MATH_ISNAN:
case MATH_ISINF:
case MATH_DECIMALS:
+ case MATH_STEP_DECIMALS:
case MATH_SEED:
case MATH_RANDSEED:
case MATH_DEG2RAD:
@@ -365,6 +367,11 @@ void Expression::exec_func(BuiltinFunc p_func, const Variant **p_inputs, Variant
VALIDATE_ARG_NUM(0);
*r_return = Math::step_decimals((double)*p_inputs[0]);
} break;
+ case MATH_STEP_DECIMALS: {
+
+ VALIDATE_ARG_NUM(0);
+ *r_return = Math::step_decimals((double)*p_inputs[0]);
+ } break;
case MATH_STEPIFY: {
VALIDATE_ARG_NUM(0);
diff --git a/core/math/expression.h b/core/math/expression.h
index f9075cb689..f20619f0b6 100644
--- a/core/math/expression.h
+++ b/core/math/expression.h
@@ -62,6 +62,7 @@ public:
MATH_ISINF,
MATH_EASE,
MATH_DECIMALS,
+ MATH_STEP_DECIMALS,
MATH_STEPIFY,
MATH_LERP,
MATH_INVERSE_LERP,
diff --git a/core/math/geometry.cpp b/core/math/geometry.cpp
index a84b5a16c7..0ab8707d3a 100644
--- a/core/math/geometry.cpp
+++ b/core/math/geometry.cpp
@@ -836,7 +836,7 @@ Geometry::MeshData Geometry::build_convex_mesh(const PoolVector<Plane> &p_planes
Vector3 rel = edge1_A - edge0_A;
real_t den = clip.normal.dot(rel);
- if (Math::abs(den) < CMP_EPSILON)
+ if (Math::is_zero_approx(den))
continue; // point too short
real_t dist = -(clip.normal.dot(edge0_A) - clip.d) / den;
diff --git a/core/math/geometry.h b/core/math/geometry.h
index 7347cb742a..0b2adf9513 100644
--- a/core/math/geometry.h
+++ b/core/math/geometry.h
@@ -181,8 +181,8 @@ public:
}
}
// finally do the division to get sc and tc
- sc = (Math::abs(sN) < CMP_EPSILON ? 0.0 : sN / sD);
- tc = (Math::abs(tN) < CMP_EPSILON ? 0.0 : tN / tD);
+ sc = (Math::is_zero_approx(sN) ? 0.0 : sN / sD);
+ tc = (Math::is_zero_approx(tN) ? 0.0 : tN / tD);
// get the difference of the two closest points
Vector3 dP = w + (sc * u) - (tc * v); // = S1(sc) - S2(tc)
@@ -195,7 +195,7 @@ public:
Vector3 e2 = p_v2 - p_v0;
Vector3 h = p_dir.cross(e2);
real_t a = e1.dot(h);
- if (a > -CMP_EPSILON && a < CMP_EPSILON) // parallel test
+ if (Math::is_zero_approx(a)) // parallel test
return false;
real_t f = 1.0 / a;
@@ -233,7 +233,7 @@ public:
Vector3 e2 = p_v2 - p_v0;
Vector3 h = rel.cross(e2);
real_t a = e1.dot(h);
- if (a > -CMP_EPSILON && a < CMP_EPSILON) // parallel test
+ if (Math::is_zero_approx(a)) // parallel test
return false;
real_t f = 1.0 / a;
@@ -535,7 +535,7 @@ public:
// 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?
+ if (Math::is_zero_approx(denom)) { // parallel?
return false;
}
@@ -833,7 +833,7 @@ public:
further_away_opposite.y = MIN(p[i].y, further_away_opposite.y);
}
- further_away += (further_away - further_away_opposite) * Vector2(1.221313, 1.512312); // make point outside that wont intersect with points in segment from p_point
+ further_away += (further_away - further_away_opposite) * Vector2(1.221313, 1.512312); // make point outside that won't intersect with points in segment from p_point
int intersections = 0;
for (int i = 0; i < c; i++) {
diff --git a/core/math/math_funcs.h b/core/math/math_funcs.h
index 0d209402dd..82b5b56c01 100644
--- a/core/math/math_funcs.h
+++ b/core/math/math_funcs.h
@@ -61,6 +61,12 @@ public:
static _ALWAYS_INLINE_ double sinh(double p_x) { return ::sinh(p_x); }
static _ALWAYS_INLINE_ float sinh(float p_x) { return ::sinhf(p_x); }
+ static _ALWAYS_INLINE_ float sinc(float p_x) { return p_x == 0 ? 1 : ::sin(p_x) / p_x; }
+ static _ALWAYS_INLINE_ double sinc(double p_x) { return p_x == 0 ? 1 : ::sin(p_x) / p_x; }
+
+ static _ALWAYS_INLINE_ float sincn(float p_x) { return sinc(Math_PI * p_x); }
+ static _ALWAYS_INLINE_ double sincn(double p_x) { return sinc(Math_PI * p_x); }
+
static _ALWAYS_INLINE_ double cosh(double p_x) { return ::cosh(p_x); }
static _ALWAYS_INLINE_ float cosh(float p_x) { return ::coshf(p_x); }
@@ -272,13 +278,20 @@ public:
return diff < epsilon;
}
- static _ALWAYS_INLINE_ bool is_equal_approx(real_t a, real_t b, real_t epsilon = CMP_EPSILON) {
- // TODO: Comparing floats for approximate-equality is non-trivial.
- // Using epsilon should cover the typical cases in Godot (where a == b is used to compare two reals), such as matrix and vector comparison operators.
- // A proper implementation in terms of ULPs should eventually replace the contents of this function.
- // See https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/ for details.
+ static _ALWAYS_INLINE_ bool is_equal_approx(real_t a, real_t b) {
+ real_t tolerance = CMP_EPSILON * abs(a);
+ if (tolerance < CMP_EPSILON) {
+ tolerance = CMP_EPSILON;
+ }
+ return abs(a - b) < tolerance;
+ }
+
+ static _ALWAYS_INLINE_ bool is_equal_approx(real_t a, real_t b, real_t tolerance) {
+ return abs(a - b) < tolerance;
+ }
- return abs(a - b) < epsilon;
+ static _ALWAYS_INLINE_ bool is_zero_approx(real_t s) {
+ return abs(s) < CMP_EPSILON;
}
static _ALWAYS_INLINE_ float absf(float g) {
diff --git a/core/math/plane.cpp b/core/math/plane.cpp
index cd3cbce300..b01853c4ac 100644
--- a/core/math/plane.cpp
+++ b/core/math/plane.cpp
@@ -110,7 +110,7 @@ bool Plane::intersects_ray(const Vector3 &p_from, const Vector3 &p_dir, Vector3
real_t den = normal.dot(segment);
//printf("den is %i\n",den);
- if (Math::abs(den) <= CMP_EPSILON) {
+ if (Math::is_zero_approx(den)) {
return false;
}
@@ -135,7 +135,7 @@ bool Plane::intersects_segment(const Vector3 &p_begin, const Vector3 &p_end, Vec
real_t den = normal.dot(segment);
//printf("den is %i\n",den);
- if (Math::abs(den) <= CMP_EPSILON) {
+ if (Math::is_zero_approx(den)) {
return false;
}
diff --git a/core/math/plane.h b/core/math/plane.h
index 1c6e4b816b..ec817edd2c 100644
--- a/core/math/plane.h
+++ b/core/math/plane.h
@@ -125,12 +125,12 @@ Plane::Plane(const Vector3 &p_point1, const Vector3 &p_point2, const Vector3 &p_
bool Plane::operator==(const Plane &p_plane) const {
- return normal == p_plane.normal && d == p_plane.d;
+ return normal == p_plane.normal && Math::is_equal_approx(d, p_plane.d);
}
bool Plane::operator!=(const Plane &p_plane) const {
- return normal != p_plane.normal || d != p_plane.d;
+ return normal != p_plane.normal || !Math::is_equal_approx(d, p_plane.d);
}
#endif // PLANE_H
diff --git a/core/math/rect2.h b/core/math/rect2.h
index 901d372132..d636aa223f 100644
--- a/core/math/rect2.h
+++ b/core/math/rect2.h
@@ -67,7 +67,7 @@ struct Rect2 {
if (p_point.x < position.x) {
real_t d = position.x - p_point.x;
- dist = inside ? d : MIN(dist, d);
+ dist = d;
inside = false;
}
if (p_point.y < position.y) {
@@ -103,7 +103,7 @@ struct Rect2 {
((p_rect.position.y + p_rect.size.y) < (position.y + size.y));
}
- inline bool has_no_area() const {
+ _FORCE_INLINE_ bool has_no_area() const {
return (size.x <= 0 || size.y <= 0);
}
@@ -154,8 +154,6 @@ struct Rect2 {
return true;
}
- inline bool no_area() const { return (size.width <= 0 || size.height <= 0); }
-
bool operator==(const Rect2 &p_rect) const { return position == p_rect.position && size == p_rect.size; }
bool operator!=(const Rect2 &p_rect) const { return position != p_rect.position || size != p_rect.size; }
@@ -189,7 +187,7 @@ struct Rect2 {
return g;
}
- inline Rect2 expand(const Vector2 &p_vector) const {
+ _FORCE_INLINE_ Rect2 expand(const Vector2 &p_vector) const {
Rect2 r = *this;
r.expand_to(p_vector);
@@ -215,7 +213,7 @@ struct Rect2 {
size = end - begin;
}
- inline Rect2 abs() const {
+ _FORCE_INLINE_ Rect2 abs() const {
return Rect2(Point2(position.x + MIN(size.x, 0), position.y + MIN(size.y, 0)), size.abs());
}
@@ -265,7 +263,7 @@ struct Rect2i {
((p_rect.position.y + p_rect.size.y) < (position.y + size.y));
}
- inline bool has_no_area() const {
+ _FORCE_INLINE_ bool has_no_area() const {
return (size.x <= 0 || size.y <= 0);
}
@@ -316,8 +314,6 @@ struct Rect2i {
return true;
}
- bool no_area() { return (size.width <= 0 || size.height <= 0); }
-
bool operator==(const Rect2i &p_rect) const { return position == p_rect.position && size == p_rect.size; }
bool operator!=(const Rect2i &p_rect) const { return position != p_rect.position || size != p_rect.size; }
@@ -331,6 +327,33 @@ struct Rect2i {
return g;
}
+ inline Rect2i grow_margin(Margin p_margin, int p_amount) const {
+ Rect2i g = *this;
+ g = g.grow_individual((MARGIN_LEFT == p_margin) ? p_amount : 0,
+ (MARGIN_TOP == p_margin) ? p_amount : 0,
+ (MARGIN_RIGHT == p_margin) ? p_amount : 0,
+ (MARGIN_BOTTOM == p_margin) ? p_amount : 0);
+ return g;
+ }
+
+ inline Rect2i grow_individual(int p_left, int p_top, int p_right, int p_bottom) const {
+
+ Rect2i g = *this;
+ g.position.x -= p_left;
+ g.position.y -= p_top;
+ g.size.width += p_left + p_right;
+ g.size.height += p_top + p_bottom;
+
+ return g;
+ }
+
+ _FORCE_INLINE_ Rect2i expand(const Vector2i &p_vector) const {
+
+ Rect2i r = *this;
+ r.expand_to(p_vector);
+ return r;
+ }
+
inline void expand_to(const Point2i &p_vector) {
Point2i begin = position;
diff --git a/core/math/transform_2d.cpp b/core/math/transform_2d.cpp
index 7d00158f3d..1d0387bd45 100644
--- a/core/math/transform_2d.cpp
+++ b/core/math/transform_2d.cpp
@@ -106,7 +106,7 @@ Size2 Transform2D::get_scale() const {
return Size2(elements[0].length(), det_sign * elements[1].length());
}
-void Transform2D::set_scale(Size2 &p_scale) {
+void Transform2D::set_scale(const Size2 &p_scale) {
elements[0].normalize();
elements[1].normalize();
elements[0] *= p_scale.x;
diff --git a/core/math/transform_2d.h b/core/math/transform_2d.h
index b9e7a36fb3..c44678674a 100644
--- a/core/math/transform_2d.h
+++ b/core/math/transform_2d.h
@@ -81,7 +81,7 @@ struct Transform2D {
real_t basis_determinant() const;
Size2 get_scale() const;
- void set_scale(Size2 &p_scale);
+ void set_scale(const Size2 &p_scale);
_FORCE_INLINE_ const Vector2 &get_origin() const { return elements[2]; }
_FORCE_INLINE_ void set_origin(const Vector2 &p_origin) { elements[2] = p_origin; }
diff --git a/core/math/vector2.h b/core/math/vector2.h
index ae2d1ec660..a0c6024c9f 100644
--- a/core/math/vector2.h
+++ b/core/math/vector2.h
@@ -99,14 +99,15 @@ struct Vector2 {
Vector2 operator/(const real_t &rvalue) const;
void operator/=(const real_t &rvalue);
+ void operator/=(const Vector2 &rvalue) { *this = *this / rvalue; }
Vector2 operator-() const;
bool operator==(const Vector2 &p_vec2) const;
bool operator!=(const Vector2 &p_vec2) const;
- bool operator<(const Vector2 &p_vec2) const { return (x == p_vec2.x) ? (y < p_vec2.y) : (x < p_vec2.x); }
- bool operator<=(const Vector2 &p_vec2) const { return (x == p_vec2.x) ? (y <= p_vec2.y) : (x <= p_vec2.x); }
+ bool operator<(const Vector2 &p_vec2) const { return (Math::is_equal_approx(x, p_vec2.x)) ? (y < p_vec2.y) : (x < p_vec2.x); }
+ bool operator<=(const Vector2 &p_vec2) const { return (Math::is_equal_approx(x, p_vec2.x)) ? (y <= p_vec2.y) : (x < p_vec2.x); }
real_t angle() const;
@@ -212,11 +213,11 @@ _FORCE_INLINE_ Vector2 Vector2::operator-() const {
_FORCE_INLINE_ bool Vector2::operator==(const Vector2 &p_vec2) const {
- return x == p_vec2.x && y == p_vec2.y;
+ return Math::is_equal_approx(x, p_vec2.x) && Math::is_equal_approx(y, p_vec2.y);
}
_FORCE_INLINE_ bool Vector2::operator!=(const Vector2 &p_vec2) const {
- return x != p_vec2.x || y != p_vec2.y;
+ return !Math::is_equal_approx(x, p_vec2.x) || !Math::is_equal_approx(y, p_vec2.y);
}
Vector2 Vector2::linear_interpolate(const Vector2 &p_b, real_t p_t) const {
diff --git a/core/math/vector3.h b/core/math/vector3.h
index e9074c5bd4..21fc09653f 100644
--- a/core/math/vector3.h
+++ b/core/math/vector3.h
@@ -341,17 +341,17 @@ Vector3 Vector3::operator-() const {
bool Vector3::operator==(const Vector3 &p_v) const {
- return (x == p_v.x && y == p_v.y && z == p_v.z);
+ return (Math::is_equal_approx(x, p_v.x) && Math::is_equal_approx(y, p_v.y) && Math::is_equal_approx(z, p_v.z));
}
bool Vector3::operator!=(const Vector3 &p_v) const {
- return (x != p_v.x || y != p_v.y || z != p_v.z);
+ return (!Math::is_equal_approx(x, p_v.x) || !Math::is_equal_approx(y, p_v.y) || !Math::is_equal_approx(z, p_v.z));
}
bool Vector3::operator<(const Vector3 &p_v) const {
- if (x == p_v.x) {
- if (y == p_v.y)
+ if (Math::is_equal_approx(x, p_v.x)) {
+ if (Math::is_equal_approx(y, p_v.y))
return z < p_v.z;
else
return y < p_v.y;
@@ -362,8 +362,8 @@ bool Vector3::operator<(const Vector3 &p_v) const {
bool Vector3::operator<=(const Vector3 &p_v) const {
- if (x == p_v.x) {
- if (y == p_v.y)
+ if (Math::is_equal_approx(x, p_v.x)) {
+ if (Math::is_equal_approx(y, p_v.y))
return z <= p_v.z;
else
return y < p_v.y;
@@ -402,13 +402,14 @@ real_t Vector3::length_squared() const {
void Vector3::normalize() {
- real_t l = length();
- if (l == 0) {
+ real_t lengthsq = length_squared();
+ if (lengthsq == 0) {
x = y = z = 0;
} else {
- x /= l;
- y /= l;
- z /= l;
+ real_t length = Math::sqrt(lengthsq);
+ x /= length;
+ y /= length;
+ z /= length;
}
}
diff --git a/core/message_queue.cpp b/core/message_queue.cpp
index c57bd4081c..1d661f25f9 100644
--- a/core/message_queue.cpp
+++ b/core/message_queue.cpp
@@ -58,7 +58,7 @@ Error MessageQueue::push_call(ObjectID p_id, const StringName &p_method, const V
Message *msg = memnew_placement(&buffer[buffer_end], Message);
msg->args = p_argcount;
- msg->instance_ID = p_id;
+ msg->instance_id = p_id;
msg->target = p_method;
msg->type = TYPE_CALL;
if (p_show_error)
@@ -109,7 +109,7 @@ Error MessageQueue::push_set(ObjectID p_id, const StringName &p_prop, const Vari
Message *msg = memnew_placement(&buffer[buffer_end], Message);
msg->args = 1;
- msg->instance_ID = p_id;
+ msg->instance_id = p_id;
msg->target = p_prop;
msg->type = TYPE_SET;
@@ -143,7 +143,7 @@ Error MessageQueue::push_notification(ObjectID p_id, int p_notification) {
Message *msg = memnew_placement(&buffer[buffer_end], Message);
msg->type = TYPE_NOTIFICATION;
- msg->instance_ID = p_id;
+ msg->instance_id = p_id;
//msg->target;
msg->notification = p_notification;
@@ -177,7 +177,7 @@ void MessageQueue::statistics() {
while (read_pos < buffer_end) {
Message *message = (Message *)&buffer[read_pos];
- Object *target = ObjectDB::get_instance(message->instance_ID);
+ Object *target = ObjectDB::get_instance(message->instance_id);
if (target != NULL) {
@@ -289,7 +289,7 @@ void MessageQueue::flush() {
_THREAD_SAFE_UNLOCK_
- Object *target = ObjectDB::get_instance(message->instance_ID);
+ Object *target = ObjectDB::get_instance(message->instance_id);
if (target != NULL) {
diff --git a/core/message_queue.h b/core/message_queue.h
index 2515eb4a98..026d17ad3f 100644
--- a/core/message_queue.h
+++ b/core/message_queue.h
@@ -54,7 +54,7 @@ class MessageQueue {
struct Message {
- ObjectID instance_ID;
+ ObjectID instance_id;
StringName target;
int16_t type;
union {
diff --git a/core/method_bind.h b/core/method_bind.h
index 5ea8adb7e0..1b0c3b27c0 100644
--- a/core/method_bind.h
+++ b/core/method_bind.h
@@ -273,6 +273,8 @@ public:
void set_argument_names(const Vector<StringName> &p_names); //set by class, db, can't be inferred otherwise
Vector<StringName> get_argument_names() const;
+ virtual GodotTypeInfo::Metadata get_argument_meta(int p_arg) const = 0;
+
#endif
void set_hint_flags(uint32_t p_hint) { hint_flags = p_hint; }
uint32_t get_hint_flags() const { return hint_flags | (is_const() ? METHOD_FLAG_CONST : 0) | (is_vararg() ? METHOD_FLAG_VARARG : 0); }
@@ -329,6 +331,10 @@ public:
return _gen_argument_type_info(p_arg).type;
}
+ virtual GodotTypeInfo::Metadata get_argument_meta(int) const {
+ return GodotTypeInfo::METADATA_NONE;
+ }
+
#else
virtual Variant::Type _gen_argument_type(int p_arg) const {
diff --git a/core/object.cpp b/core/object.cpp
index 8d4edeb852..64f55f08a9 100644
--- a/core/object.cpp
+++ b/core/object.cpp
@@ -608,18 +608,16 @@ Variant Object::get_indexed(const Vector<StringName> &p_names, bool *r_valid) co
}
bool valid = false;
- Variant current_value = get(p_names[0]);
+ Variant current_value = get(p_names[0], &valid);
for (int i = 1; i < p_names.size(); i++) {
current_value = current_value.get_named(p_names[i], &valid);
- if (!valid) {
- if (r_valid)
- *r_valid = false;
- return Variant();
- }
+ if (!valid)
+ break;
}
if (r_valid)
- *r_valid = true;
+ *r_valid = valid;
+
return current_value;
}
@@ -1069,6 +1067,10 @@ Variant Object::get_meta(const String &p_name) const {
return metadata[p_name];
}
+void Object::remove_meta(const String &p_name) {
+ metadata.erase(p_name);
+}
+
Array Object::_get_property_list_bind() const {
List<PropertyInfo> lpi;
@@ -1376,7 +1378,10 @@ Array Object::_get_incoming_connections() const {
void Object::get_signal_list(List<MethodInfo> *p_signals) const {
if (!script.is_null()) {
- Ref<Script>(script)->get_script_signal_list(p_signals);
+ Ref<Script> scr = script;
+ if (scr.is_valid()) {
+ scr->get_script_signal_list(p_signals);
+ }
}
ClassDB::get_signal_list(get_class_name(), p_signals);
@@ -1699,6 +1704,7 @@ void Object::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_script"), &Object::get_script);
ClassDB::bind_method(D_METHOD("set_meta", "name", "value"), &Object::set_meta);
+ ClassDB::bind_method(D_METHOD("remove_meta", "name"), &Object::remove_meta);
ClassDB::bind_method(D_METHOD("get_meta", "name"), &Object::get_meta);
ClassDB::bind_method(D_METHOD("has_meta", "name"), &Object::has_meta);
ClassDB::bind_method(D_METHOD("get_meta_list"), &Object::_get_meta_list_bind);
@@ -1951,8 +1957,8 @@ Object::Object() {
_class_ptr = NULL;
_block_signals = false;
_predelete_ok = 0;
- _instance_ID = 0;
- _instance_ID = ObjectDB::add_instance(this);
+ _instance_id = 0;
+ _instance_id = ObjectDB::add_instance(this);
_can_translate = true;
_is_queued_for_deletion = false;
instance_binding_count = 0;
@@ -2006,7 +2012,7 @@ Object::~Object() {
}
ObjectDB::remove_instance(this);
- _instance_ID = 0;
+ _instance_id = 0;
_predelete_ok = 2;
if (!ScriptServer::are_languages_finished()) {
@@ -2054,10 +2060,10 @@ void ObjectDB::remove_instance(Object *p_object) {
rw_lock->write_unlock();
}
-Object *ObjectDB::get_instance(ObjectID p_instance_ID) {
+Object *ObjectDB::get_instance(ObjectID p_instance_id) {
rw_lock->read_lock();
- Object **obj = instances.getptr(p_instance_ID);
+ Object **obj = instances.getptr(p_instance_id);
rw_lock->read_unlock();
if (!obj)
diff --git a/core/object.h b/core/object.h
index 09ecfb74a7..4394c1c3da 100644
--- a/core/object.h
+++ b/core/object.h
@@ -88,6 +88,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_NODE_PATH_VALID_TYPES,
+ PROPERTY_HINT_SAVE_FILE, ///< a file path must be passed, hint_text (optionally) is a filter "*.png,*.wav,*.doc,". This opens a save dialog
PROPERTY_HINT_MAX,
// When updating PropertyHint, also sync the hardcoded list in VisualScriptEditorVariableEdit
};
@@ -464,7 +465,7 @@ private:
bool _block_signals;
int _predelete_ok;
Set<Object *> change_receptors;
- ObjectID _instance_ID;
+ ObjectID _instance_id;
bool _predelete();
void _postinitialize();
bool _can_translate;
@@ -576,7 +577,7 @@ public:
bool _is_gpl_reversed() const { return false; }
- _FORCE_INLINE_ ObjectID get_instance_id() const { return _instance_ID; }
+ _FORCE_INLINE_ ObjectID get_instance_id() const { return _instance_id; }
// this is used for editors
void add_change_receptor(Object *p_receptor);
@@ -673,6 +674,7 @@ public:
bool has_meta(const String &p_name) const;
void set_meta(const String &p_name, const Variant &p_value);
+ void remove_meta(const String &p_name);
Variant get_meta(const String &p_name) const;
void get_meta_list(List<String> *p_list) const;
@@ -775,7 +777,7 @@ class ObjectDB {
public:
typedef void (*DebugFunc)(Object *p_obj);
- static Object *get_instance(ObjectID p_instance_ID);
+ static Object *get_instance(ObjectID p_instance_id);
static void debug_objects(DebugFunc p_func);
static int get_object_count();
diff --git a/core/ordered_hash_map.h b/core/ordered_hash_map.h
index 09d43d6797..2c18de92be 100644
--- a/core/ordered_hash_map.h
+++ b/core/ordered_hash_map.h
@@ -274,6 +274,10 @@ public:
inline bool empty() const { return list.empty(); }
inline int size() const { return list.size(); }
+ const void *id() const {
+ return list.id();
+ }
+
void clear() {
map.clear();
list.clear();
diff --git a/core/os/dir_access.cpp b/core/os/dir_access.cpp
index 2c1c655175..d81c30f33a 100644
--- a/core/os/dir_access.cpp
+++ b/core/os/dir_access.cpp
@@ -330,7 +330,7 @@ Error DirAccess::copy(String p_from, String p_to, int p_chmod_flags) {
if (err == OK && p_chmod_flags != -1) {
fdst->close();
- err = fdst->_chmod(p_to, p_chmod_flags);
+ err = FileAccess::set_unix_permissions(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/file_access.cpp b/core/os/file_access.cpp
index 4be1364278..079f51bada 100644
--- a/core/os/file_access.cpp
+++ b/core/os/file_access.cpp
@@ -507,6 +507,29 @@ uint64_t FileAccess::get_modified_time(const String &p_file) {
return mt;
}
+uint32_t FileAccess::get_unix_permissions(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);
+
+ uint32_t mt = fa->_get_unix_permissions(p_file);
+ memdelete(fa);
+ return mt;
+}
+
+Error FileAccess::set_unix_permissions(const String &p_file, uint32_t p_permissions) {
+
+ FileAccess *fa = create_for_path(p_file);
+ ERR_FAIL_COND_V(!fa, ERR_CANT_CREATE);
+
+ Error err = fa->_set_unix_permissions(p_file, p_permissions);
+ memdelete(fa);
+ return err;
+}
+
void FileAccess::store_string(const String &p_string) {
if (p_string.length() == 0)
diff --git a/core/os/file_access.h b/core/os/file_access.h
index 9df2a5cade..4930eae35a 100644
--- a/core/os/file_access.h
+++ b/core/os/file_access.h
@@ -56,6 +56,9 @@ public:
bool endian_swap;
bool real_is_double;
+ virtual uint32_t _get_unix_permissions(const String &p_file) = 0;
+ virtual Error _set_unix_permissions(const String &p_file, uint32_t p_permissions) = 0;
+
protected:
String fix_path(const String &p_path) const;
virtual Error _open(const String &p_path, int p_mode_flags) = 0; ///< open a file
@@ -148,14 +151,14 @@ public:
virtual Error reopen(const String &p_path, int p_mode_flags); ///< does not change the AccessType
- virtual Error _chmod(const String &p_path, int p_mod) { return ERR_UNAVAILABLE; }
-
static FileAccess *create(AccessType p_access); /// Create a file access (for the current platform) this is the only portable way of accessing files.
static FileAccess *create_for_path(const String &p_path);
static FileAccess *open(const String &p_path, int p_mode_flags, Error *r_error = NULL); /// Create a file access (for the current platform) this is the only portable way of accessing files.
static CreateFunc get_create_func(AccessType p_access);
static bool exists(const String &p_name); ///< return true if a file exists
static uint64_t get_modified_time(const String &p_file);
+ static uint32_t get_unix_permissions(const String &p_file);
+ static Error set_unix_permissions(const String &p_file, uint32_t p_permissions);
static void set_backup_save(bool p_enable) { backup_save = p_enable; };
static bool is_backup_save_enabled() { return backup_save; };
diff --git a/core/os/input.cpp b/core/os/input.cpp
index caa9fb1493..f04d4a1b3e 100644
--- a/core/os/input.cpp
+++ b/core/os/input.cpp
@@ -34,6 +34,10 @@
#include "core/os/os.h"
#include "core/project_settings.h"
+#ifdef TOOLS_ENABLED
+#include "editor/editor_settings.h"
+#endif
+
Input *Input::singleton = NULL;
Input *Input::get_singleton() {
@@ -89,6 +93,7 @@ void Input::_bind_methods() {
ClassDB::bind_method(D_METHOD("action_press", "action", "strength"), &Input::action_press, DEFVAL(1.f));
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("get_current_cursor_shape"), &Input::get_current_cursor_shape);
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);
ClassDB::bind_method(D_METHOD("set_use_accumulated_input", "enable"), &Input::set_use_accumulated_input);
@@ -122,6 +127,8 @@ void Input::_bind_methods() {
void Input::get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const {
#ifdef TOOLS_ENABLED
+ const String quote_style = EDITOR_DEF("text_editor/completion/use_single_quotes", 0) ? "'" : "\"";
+
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" || pf == "get_action_strength")) {
@@ -135,7 +142,7 @@ void Input::get_argument_options(const StringName &p_function, int p_idx, List<S
continue;
String name = pi.name.substr(pi.name.find("/") + 1, pi.name.length());
- r_options->push_back("\"" + name + "\"");
+ r_options->push_back(quote_style + name + quote_style);
}
}
#endif
diff --git a/core/os/input.h b/core/os/input.h
index c8b80b28d0..de04f239e6 100644
--- a/core/os/input.h
+++ b/core/os/input.h
@@ -121,10 +121,10 @@ public:
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 CursorShape get_default_cursor_shape() const = 0;
virtual void set_default_cursor_shape(CursorShape p_shape) = 0;
+ virtual CursorShape get_current_cursor_shape() const = 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;
virtual String get_joy_button_string(int p_button) = 0;
virtual String get_joy_axis_string(int p_axis) = 0;
diff --git a/core/os/input_event.cpp b/core/os/input_event.cpp
index 25a5c2afeb..a072017353 100644
--- a/core/os/input_event.cpp
+++ b/core/os/input_event.cpp
@@ -717,8 +717,17 @@ bool InputEventJoypadMotion::action_match(const Ref<InputEvent> &p_event, bool *
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;
+ if (p_strength != NULL) {
+ if (pressed) {
+ if (p_deadzone == 1.0f) {
+ *p_strength = 1.0f;
+ } else {
+ *p_strength = CLAMP(Math::inverse_lerp(p_deadzone, 1.0f, Math::abs(jm->get_axis_value())), 0.0f, 1.0f);
+ }
+ } else {
+ *p_strength = 0.0f;
+ }
+ }
}
return match;
}
diff --git a/core/os/os.cpp b/core/os/os.cpp
index 03e63f636e..ea378c9e83 100644
--- a/core/os/os.cpp
+++ b/core/os/os.cpp
@@ -220,6 +220,16 @@ int OS::get_virtual_keyboard_height() const {
return 0;
}
+void OS::set_cursor_shape(CursorShape p_shape) {
+}
+
+OS::CursorShape OS::get_cursor_shape() const {
+ return CURSOR_ARROW;
+}
+
+void OS::set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) {
+}
+
void OS::print_all_resources(String p_to_file) {
ERR_FAIL_COND(p_to_file != "" && _OSPRF);
diff --git a/core/os/os.h b/core/os/os.h
index d02d5a2c84..4ae8a354e5 100644
--- a/core/os/os.h
+++ b/core/os/os.h
@@ -45,6 +45,8 @@
@author Juan Linietsky <reduzio@gmail.com>
*/
+class Mutex;
+
class OS {
static OS *singleton;
@@ -260,7 +262,7 @@ public:
virtual int get_low_processor_usage_mode_sleep_usec() const;
virtual String get_executable_path() const;
- virtual Error execute(const String &p_path, const List<String> &p_arguments, bool p_blocking, ProcessID *r_child_id = NULL, String *r_pipe = NULL, int *r_exitcode = NULL, bool read_stderr = false) = 0;
+ virtual Error execute(const String &p_path, const List<String> &p_arguments, bool p_blocking, ProcessID *r_child_id = NULL, String *r_pipe = NULL, int *r_exitcode = NULL, bool read_stderr = false, Mutex *p_pipe_mutex = NULL) = 0;
virtual Error kill(const ProcessID &p_pid) = 0;
virtual int get_process_id() const;
@@ -377,8 +379,9 @@ public:
// returns height of the currently shown virtual keyboard (0 if keyboard is hidden)
virtual int get_virtual_keyboard_height() const;
- virtual void set_cursor_shape(CursorShape p_shape) = 0;
- virtual void set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) = 0;
+ virtual void set_cursor_shape(CursorShape p_shape);
+ virtual CursorShape get_cursor_shape() const;
+ virtual void set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot);
virtual bool get_swap_ok_cancel() { return false; }
virtual void dump_memory_to_file(const char *p_file);
diff --git a/core/project_settings.cpp b/core/project_settings.cpp
index 5752cdca2b..c86d1567dd 100644
--- a/core/project_settings.cpp
+++ b/core/project_settings.cpp
@@ -501,7 +501,7 @@ Error ProjectSettings::_load_settings_binary(const String p_path) {
d.resize(vlen);
f->get_buffer(d.ptrw(), vlen);
Variant value;
- err = decode_variant(value, d.ptr(), d.size(), NULL, false);
+ err = decode_variant(value, d.ptr(), d.size(), NULL, true);
ERR_EXPLAIN("Error decoding property: " + key);
ERR_CONTINUE(err != OK);
set(key, value);
@@ -694,7 +694,7 @@ Error ProjectSettings::_save_settings_binary(const String &p_file, const Map<Str
file->store_string(key);
int len;
- err = encode_variant(value, NULL, len, false);
+ err = encode_variant(value, NULL, len, true);
if (err != OK)
memdelete(file);
ERR_FAIL_COND_V(err != OK, ERR_INVALID_DATA);
@@ -702,7 +702,7 @@ Error ProjectSettings::_save_settings_binary(const String &p_file, const Map<Str
Vector<uint8_t> buff;
buff.resize(len);
- err = encode_variant(value, buff.ptrw(), len, false);
+ err = encode_variant(value, buff.ptrw(), len, true);
if (err != OK)
memdelete(file);
ERR_FAIL_COND_V(err != OK, ERR_INVALID_DATA);
diff --git a/core/reference.h b/core/reference.h
index f3fcc922c7..8a19f846c7 100644
--- a/core/reference.h
+++ b/core/reference.h
@@ -197,6 +197,19 @@ public:
r.reference = NULL;
}
+ template <class T_Other>
+ void reference_ptr(T_Other *p_ptr) {
+ if (reference == p_ptr) {
+ return;
+ }
+ unref();
+
+ T *r = Object::cast_to<T>(p_ptr);
+ if (r) {
+ ref_pointer(r);
+ }
+ }
+
Ref(const Ref &p_from) {
reference = NULL;
@@ -362,7 +375,8 @@ struct PtrToArg<const RefPtr &> {
template <class T>
struct GetTypeInfo<Ref<T> > {
- enum { VARIANT_TYPE = Variant::OBJECT };
+ static const Variant::Type VARIANT_TYPE = Variant::OBJECT;
+ static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE;
static inline PropertyInfo get_class_info() {
return PropertyInfo(Variant::OBJECT, String(), PROPERTY_HINT_RESOURCE_TYPE, T::get_class_static());
@@ -371,7 +385,8 @@ struct GetTypeInfo<Ref<T> > {
template <class T>
struct GetTypeInfo<const Ref<T> &> {
- enum { VARIANT_TYPE = Variant::OBJECT };
+ static const Variant::Type VARIANT_TYPE = Variant::OBJECT;
+ static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE;
static inline PropertyInfo get_class_info() {
return PropertyInfo(Variant::OBJECT, String(), PROPERTY_HINT_RESOURCE_TYPE, T::get_class_static());
diff --git a/core/resource.cpp b/core/resource.cpp
index 74c93cd790..74e2c1ed6b 100644
--- a/core/resource.cpp
+++ b/core/resource.cpp
@@ -363,6 +363,26 @@ bool Resource::is_translation_remapped() const {
return remapped_list.in_list();
}
+#ifdef TOOLS_ENABLED
+//helps keep IDs same number when loading/saving scenes. -1 clears ID and it Returns -1 when no id stored
+void Resource::set_id_for_path(const String &p_path, int p_id) {
+ if (p_id == -1) {
+ id_for_path.erase(p_path);
+ } else {
+ id_for_path[p_path] = p_id;
+ }
+}
+
+int Resource::get_id_for_path(const String &p_path) const {
+
+ if (id_for_path.has(p_path)) {
+ return id_for_path[p_path];
+ } else {
+ return -1;
+ }
+}
+#endif
+
void Resource::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_path", "path"), &Resource::_set_path);
diff --git a/core/resource.h b/core/resource.h
index a4d9e998ac..853b2859c7 100644
--- a/core/resource.h
+++ b/core/resource.h
@@ -88,7 +88,9 @@ protected:
void _set_path(const String &p_path);
void _take_over_path(const String &p_path);
-
+#ifdef TOOLS_ENABLED
+ Map<String, int> id_for_path;
+#endif
public:
static Node *(*_get_local_scene_func)(); //used by editor
@@ -137,6 +139,12 @@ public:
virtual RID get_rid() const; // some resources may offer conversion to RID
+#ifdef TOOLS_ENABLED
+ //helps keep IDs same number when loading/saving scenes. -1 clears ID and it Returns -1 when no id stored
+ void set_id_for_path(const String &p_path, int p_id);
+ int get_id_for_path(const String &p_path) const;
+#endif
+
Resource();
~Resource();
};
diff --git a/core/string_builder.h b/core/string_builder.h
index 40d70e8f45..0c4985d230 100644
--- a/core/string_builder.h
+++ b/core/string_builder.h
@@ -70,6 +70,10 @@ public:
return appended_strings.size();
}
+ _FORCE_INLINE_ uint32_t get_string_length() const {
+ return string_length;
+ }
+
String as_string() const;
_FORCE_INLINE_ operator String() const {
diff --git a/core/translation.cpp b/core/translation.cpp
index 6921f1d9f1..0b55badc61 100644
--- a/core/translation.cpp
+++ b/core/translation.cpp
@@ -179,6 +179,7 @@ static const char *locale_list[] = {
"ff_SN", // Fulah (Senegal)
"fi", // Finnish
"fi_FI", // Finnish (Finland)
+ "fil", // Filipino
"fil_PH", // Filipino (Philippines)
"fo_FO", // Faroese (Faroe Islands)
"fr", // French
@@ -227,6 +228,7 @@ static const char *locale_list[] = {
"ja", // Japanese
"ja_JP", // Japanese (Japan)
"kab_DZ", // Kabyle (Algeria)
+ "ka", // Georgian
"ka_GE", // Georgian (Georgia)
"kk_KZ", // Kazakh (Kazakhstan)
"kl_GL", // Kalaallisut (Greenland)
@@ -257,10 +259,12 @@ static const char *locale_list[] = {
"mg_MG", // Malagasy (Madagascar)
"mh_MH", // Marshallese (Marshall Islands)
"mhr_RU", // Eastern Mari (Russia)
- "mi_NZ", // Maori (New Zealand)
+ "mi", // Māori
+ "mi_NZ", // Māori (New Zealand)
"miq_NI", // Mískito (Nicaragua)
"mk", // Macedonian
"mk_MK", // Macedonian (Macedonia)
+ "ml", // Malayalam
"ml_IN", // Malayalam (India)
"mni_IN", // Manipuri (India)
"mn_MN", // Mongolian (Mongolia)
@@ -326,6 +330,7 @@ static const char *locale_list[] = {
"sgs_LT", // Samogitian (Lithuania)
"shs_CA", // Shuswap (Canada)
"sid_ET", // Sidamo (Ethiopia)
+ "si", // Sinhala
"si_LK", // Sinhala (Sri Lanka)
"sk", // Slovak
"sk_SK", // Slovak (Slovakia)
@@ -343,6 +348,7 @@ static const char *locale_list[] = {
"sq_MK", // Albanian (Macedonia)
"sr", // Serbian
"sr_Cyrl", // Serbian (Cyrillic)
+ "sr_Latn", // Serbian (Latin)
"sr_ME", // Serbian (Montenegro)
"sr_RS", // Serbian (Serbia)
"ss_ZA", // Swati (South Africa)
@@ -357,6 +363,7 @@ static const char *locale_list[] = {
"ta_IN", // Tamil (India)
"ta_LK", // Tamil (Sri Lanka)
"tcy_IN", // Tulu (India)
+ "te", // Telugu
"te_IN", // Telugu (India)
"tg_TJ", // Tajik (Tajikistan)
"the_NP", // Chitwania Tharu (Nepal)
@@ -540,6 +547,7 @@ static const char *locale_names[] = {
"Fulah (Senegal)",
"Finnish",
"Finnish (Finland)",
+ "Filipino",
"Filipino (Philippines)",
"Faroese (Faroe Islands)",
"French",
@@ -588,6 +596,7 @@ static const char *locale_names[] = {
"Japanese",
"Japanese (Japan)",
"Kabyle (Algeria)",
+ "Georgian",
"Georgian (Georgia)",
"Kazakh (Kazakhstan)",
"Kalaallisut (Greenland)",
@@ -618,10 +627,12 @@ static const char *locale_names[] = {
"Malagasy (Madagascar)",
"Marshallese (Marshall Islands)",
"Eastern Mari (Russia)",
- "Maori (New Zealand)",
+ "Māori",
+ "Māori (New Zealand)",
"Mískito (Nicaragua)",
"Macedonian",
"Macedonian (Macedonia)",
+ "Malayalam",
"Malayalam (India)",
"Manipuri (India)",
"Mongolian (Mongolia)",
@@ -687,6 +698,7 @@ static const char *locale_names[] = {
"Samogitian (Lithuania)",
"Shuswap (Canada)",
"Sidamo (Ethiopia)",
+ "Sinhala",
"Sinhala (Sri Lanka)",
"Slovak",
"Slovak (Slovakia)",
@@ -704,6 +716,7 @@ static const char *locale_names[] = {
"Albanian (Macedonia)",
"Serbian",
"Serbian (Cyrillic)",
+ "Serbian (Latin)",
"Serbian (Montenegro)",
"Serbian (Serbia)",
"Swati (South Africa)",
@@ -718,6 +731,7 @@ static const char *locale_names[] = {
"Tamil (India)",
"Tamil (Sri Lanka)",
"Tulu (India)",
+ "Telugu",
"Telugu (India)",
"Tajik (Tajikistan)",
"Chitwania Tharu (Nepal)",
@@ -968,6 +982,19 @@ String TranslationServer::get_locale_name(const String &p_locale) const {
return locale_name_map[p_locale];
}
+Array TranslationServer::get_loaded_locales() const {
+ Array locales;
+ for (const Set<Ref<Translation> >::Element *E = translations.front(); E; E = E->next()) {
+
+ const Ref<Translation> &t = E->get();
+ String l = t->get_locale();
+
+ locales.push_back(l);
+ }
+
+ return locales;
+}
+
Vector<String> TranslationServer::get_all_locales() {
Vector<String> locales;
@@ -1168,6 +1195,8 @@ void TranslationServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("remove_translation", "translation"), &TranslationServer::remove_translation);
ClassDB::bind_method(D_METHOD("clear"), &TranslationServer::clear);
+
+ ClassDB::bind_method(D_METHOD("get_loaded_locales"), &TranslationServer::get_loaded_locales);
}
void TranslationServer::load_translations() {
diff --git a/core/translation.h b/core/translation.h
index b12bad0d72..d172b9ecf2 100644
--- a/core/translation.h
+++ b/core/translation.h
@@ -94,6 +94,8 @@ public:
String get_locale_name(const String &p_locale) const;
+ Array get_loaded_locales() const;
+
void add_translation(const Ref<Translation> &p_translation);
void remove_translation(const Ref<Translation> &p_translation);
diff --git a/core/type_info.h b/core/type_info.h
index c38688fea1..d85a63ee42 100644
--- a/core/type_info.h
+++ b/core/type_info.h
@@ -67,43 +67,80 @@ struct TypeInherits {
!TypesAreSame<B volatile const, void volatile const>::value;
};
+namespace GodotTypeInfo {
+enum Metadata {
+ METADATA_NONE,
+ METADATA_INT_IS_INT8,
+ METADATA_INT_IS_INT16,
+ METADATA_INT_IS_INT32,
+ METADATA_INT_IS_INT64,
+ METADATA_INT_IS_UINT8,
+ METADATA_INT_IS_UINT16,
+ METADATA_INT_IS_UINT32,
+ METADATA_INT_IS_UINT64,
+ METADATA_REAL_IS_FLOAT,
+ METADATA_REAL_IS_DOUBLE
+};
+}
+
template <class T, typename = void>
struct GetTypeInfo {
static const Variant::Type VARIANT_TYPE = Variant::NIL;
+ static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE;
static inline PropertyInfo get_class_info() {
ERR_PRINT("GetTypeInfo fallback. Bug!");
return PropertyInfo(); // Not "Nil", this is an error
}
};
-#define MAKE_TYPE_INFO(m_type, m_var_type) \
- template <> \
- struct GetTypeInfo<m_type> { \
- static const Variant::Type VARIANT_TYPE = m_var_type; \
- static inline PropertyInfo get_class_info() { \
- return PropertyInfo(VARIANT_TYPE, String()); \
- } \
- }; \
- template <> \
- struct GetTypeInfo<const m_type &> { \
- static const Variant::Type VARIANT_TYPE = m_var_type; \
- static inline PropertyInfo get_class_info() { \
- return PropertyInfo(VARIANT_TYPE, String()); \
- } \
+#define MAKE_TYPE_INFO(m_type, m_var_type) \
+ template <> \
+ struct GetTypeInfo<m_type> { \
+ static const Variant::Type VARIANT_TYPE = m_var_type; \
+ static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE; \
+ static inline PropertyInfo get_class_info() { \
+ return PropertyInfo(VARIANT_TYPE, String()); \
+ } \
+ }; \
+ template <> \
+ struct GetTypeInfo<const m_type &> { \
+ static const Variant::Type VARIANT_TYPE = m_var_type; \
+ static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE; \
+ static inline PropertyInfo get_class_info() { \
+ return PropertyInfo(VARIANT_TYPE, String()); \
+ } \
+ };
+
+#define MAKE_TYPE_INFO_WITH_META(m_type, m_var_type, m_metadata) \
+ template <> \
+ struct GetTypeInfo<m_type> { \
+ static const Variant::Type VARIANT_TYPE = m_var_type; \
+ static const GodotTypeInfo::Metadata METADATA = m_metadata; \
+ static inline PropertyInfo get_class_info() { \
+ return PropertyInfo(VARIANT_TYPE, String()); \
+ } \
+ }; \
+ template <> \
+ struct GetTypeInfo<const m_type &> { \
+ static const Variant::Type VARIANT_TYPE = m_var_type; \
+ static const GodotTypeInfo::Metadata METADATA = m_metadata; \
+ static inline PropertyInfo get_class_info() { \
+ return PropertyInfo(VARIANT_TYPE, String()); \
+ } \
};
MAKE_TYPE_INFO(bool, Variant::BOOL)
-MAKE_TYPE_INFO(uint8_t, Variant::INT)
-MAKE_TYPE_INFO(int8_t, Variant::INT)
-MAKE_TYPE_INFO(uint16_t, Variant::INT)
-MAKE_TYPE_INFO(int16_t, Variant::INT)
-MAKE_TYPE_INFO(uint32_t, Variant::INT)
-MAKE_TYPE_INFO(int32_t, Variant::INT)
-MAKE_TYPE_INFO(int64_t, Variant::INT)
-MAKE_TYPE_INFO(uint64_t, Variant::INT)
+MAKE_TYPE_INFO_WITH_META(uint8_t, Variant::INT, GodotTypeInfo::METADATA_INT_IS_UINT8)
+MAKE_TYPE_INFO_WITH_META(int8_t, Variant::INT, GodotTypeInfo::METADATA_INT_IS_INT8)
+MAKE_TYPE_INFO_WITH_META(uint16_t, Variant::INT, GodotTypeInfo::METADATA_INT_IS_UINT16)
+MAKE_TYPE_INFO_WITH_META(int16_t, Variant::INT, GodotTypeInfo::METADATA_INT_IS_INT16)
+MAKE_TYPE_INFO_WITH_META(uint32_t, Variant::INT, GodotTypeInfo::METADATA_INT_IS_UINT32)
+MAKE_TYPE_INFO_WITH_META(int32_t, Variant::INT, GodotTypeInfo::METADATA_INT_IS_INT32)
+MAKE_TYPE_INFO_WITH_META(uint64_t, Variant::INT, GodotTypeInfo::METADATA_INT_IS_UINT64)
+MAKE_TYPE_INFO_WITH_META(int64_t, Variant::INT, GodotTypeInfo::METADATA_INT_IS_INT64)
MAKE_TYPE_INFO(wchar_t, Variant::INT)
-MAKE_TYPE_INFO(float, Variant::REAL)
-MAKE_TYPE_INFO(double, Variant::REAL)
+MAKE_TYPE_INFO_WITH_META(float, Variant::REAL, GodotTypeInfo::METADATA_REAL_IS_FLOAT)
+MAKE_TYPE_INFO_WITH_META(double, Variant::REAL, GodotTypeInfo::METADATA_REAL_IS_DOUBLE)
MAKE_TYPE_INFO(String, Variant::STRING)
MAKE_TYPE_INFO(Vector2, Variant::VECTOR2)
@@ -138,6 +175,7 @@ MAKE_TYPE_INFO(BSP_Tree, Variant::DICTIONARY)
template <>
struct GetTypeInfo<RefPtr> {
static const Variant::Type VARIANT_TYPE = Variant::OBJECT;
+ static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE;
static inline PropertyInfo get_class_info() {
return PropertyInfo(Variant::OBJECT, String(), PROPERTY_HINT_RESOURCE_TYPE, "Reference");
}
@@ -145,6 +183,7 @@ struct GetTypeInfo<RefPtr> {
template <>
struct GetTypeInfo<const RefPtr &> {
static const Variant::Type VARIANT_TYPE = Variant::OBJECT;
+ static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE;
static inline PropertyInfo get_class_info() {
return PropertyInfo(Variant::OBJECT, String(), PROPERTY_HINT_RESOURCE_TYPE, "Reference");
}
@@ -154,6 +193,7 @@ struct GetTypeInfo<const RefPtr &> {
template <>
struct GetTypeInfo<Variant> {
static const Variant::Type VARIANT_TYPE = Variant::NIL;
+ static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE;
static inline PropertyInfo get_class_info() {
return PropertyInfo(Variant::NIL, String(), PROPERTY_HINT_NONE, String(), PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_NIL_IS_VARIANT);
}
@@ -162,25 +202,28 @@ struct GetTypeInfo<Variant> {
template <>
struct GetTypeInfo<const Variant &> {
static const Variant::Type VARIANT_TYPE = Variant::NIL;
+ static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE;
static inline PropertyInfo get_class_info() {
return PropertyInfo(Variant::NIL, String(), PROPERTY_HINT_NONE, String(), PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_NIL_IS_VARIANT);
}
};
-#define MAKE_TEMPLATE_TYPE_INFO(m_template, m_type, m_var_type) \
- template <> \
- struct GetTypeInfo<m_template<m_type> > { \
- static const Variant::Type VARIANT_TYPE = m_var_type; \
- static inline PropertyInfo get_class_info() { \
- return PropertyInfo(VARIANT_TYPE, String()); \
- } \
- }; \
- template <> \
- struct GetTypeInfo<const m_template<m_type> &> { \
- static const Variant::Type VARIANT_TYPE = m_var_type; \
- static inline PropertyInfo get_class_info() { \
- return PropertyInfo(VARIANT_TYPE, String()); \
- } \
+#define MAKE_TEMPLATE_TYPE_INFO(m_template, m_type, m_var_type) \
+ template <> \
+ struct GetTypeInfo<m_template<m_type> > { \
+ static const Variant::Type VARIANT_TYPE = m_var_type; \
+ static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE; \
+ static inline PropertyInfo get_class_info() { \
+ return PropertyInfo(VARIANT_TYPE, String()); \
+ } \
+ }; \
+ template <> \
+ struct GetTypeInfo<const m_template<m_type> &> { \
+ static const Variant::Type VARIANT_TYPE = m_var_type; \
+ static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE; \
+ static inline PropertyInfo get_class_info() { \
+ return PropertyInfo(VARIANT_TYPE, String()); \
+ } \
};
MAKE_TEMPLATE_TYPE_INFO(Vector, uint8_t, Variant::POOL_BYTE_ARRAY)
@@ -202,6 +245,7 @@ MAKE_TEMPLATE_TYPE_INFO(PoolVector, Face3, Variant::POOL_VECTOR3_ARRAY)
template <typename T>
struct GetTypeInfo<T *, typename EnableIf<TypeInherits<Object, T>::value>::type> {
static const Variant::Type VARIANT_TYPE = Variant::OBJECT;
+ static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE;
static inline PropertyInfo get_class_info() {
return PropertyInfo(StringName(T::get_class_static()));
}
@@ -210,6 +254,7 @@ struct GetTypeInfo<T *, typename EnableIf<TypeInherits<Object, T>::value>::type>
template <typename T>
struct GetTypeInfo<const T *, typename EnableIf<TypeInherits<Object, T>::value>::type> {
static const Variant::Type VARIANT_TYPE = Variant::OBJECT;
+ static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE;
static inline PropertyInfo get_class_info() {
return PropertyInfo(StringName(T::get_class_static()));
}
@@ -219,6 +264,7 @@ struct GetTypeInfo<const T *, typename EnableIf<TypeInherits<Object, T>::value>:
template <> \
struct GetTypeInfo<m_impl> { \
static const Variant::Type VARIANT_TYPE = Variant::INT; \
+ static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE; \
static inline PropertyInfo get_class_info() { \
return PropertyInfo(Variant::INT, String(), PROPERTY_HINT_NONE, String(), PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_CLASS_IS_ENUM, String(#m_enum).replace("::", ".")); \
} \
diff --git a/core/undo_redo.cpp b/core/undo_redo.cpp
index 69581e4115..f7ca6d3bde 100644
--- a/core/undo_redo.cpp
+++ b/core/undo_redo.cpp
@@ -239,8 +239,8 @@ void UndoRedo::_pop_history_tail() {
}
}
-bool UndoRedo::is_commiting_action() const {
- return commiting > 0;
+bool UndoRedo::is_committing_action() const {
+ return committing > 0;
}
void UndoRedo::commit_action() {
@@ -255,9 +255,9 @@ void UndoRedo::commit_action() {
merging = false;
}
- commiting++;
+ committing++;
redo(); // perform action
- commiting--;
+ committing--;
if (callback && actions.size() > 0) {
callback(callback_ud, actions[actions.size() - 1].name);
}
@@ -396,7 +396,7 @@ void UndoRedo::set_property_notify_callback(PropertyNotifyCallback p_property_ca
UndoRedo::UndoRedo() {
- commiting = 0;
+ committing = 0;
version = 1;
action_level = 0;
current_action = -1;
@@ -496,10 +496,8 @@ void UndoRedo::_bind_methods() {
ClassDB::bind_method(D_METHOD("create_action", "name", "merge_mode"), &UndoRedo::create_action, DEFVAL(MERGE_DISABLE));
ClassDB::bind_method(D_METHOD("commit_action"), &UndoRedo::commit_action);
- ClassDB::bind_method(D_METHOD("is_commiting_action"), &UndoRedo::is_commiting_action);
-
- //ClassDB::bind_method(D_METHOD("add_do_method","p_object", "p_method", "VARIANT_ARG_LIST"),&UndoRedo::add_do_method);
- //ClassDB::bind_method(D_METHOD("add_undo_method","p_object", "p_method", "VARIANT_ARG_LIST"),&UndoRedo::add_undo_method);
+ // FIXME: Typo in "commiting", fix in 4.0 when breaking compat.
+ ClassDB::bind_method(D_METHOD("is_commiting_action"), &UndoRedo::is_committing_action);
{
MethodInfo mi;
diff --git a/core/undo_redo.h b/core/undo_redo.h
index 6293e77acc..e2cc6c659b 100644
--- a/core/undo_redo.h
+++ b/core/undo_redo.h
@@ -95,7 +95,7 @@ private:
MethodNotifyCallback method_callback;
PropertyNotifyCallback property_callback;
- int commiting;
+ int committing;
protected:
static void _bind_methods();
@@ -110,7 +110,7 @@ public:
void add_do_reference(Object *p_object);
void add_undo_reference(Object *p_object);
- bool is_commiting_action() const;
+ bool is_committing_action() const;
void commit_action();
bool redo();
diff --git a/core/ustring.cpp b/core/ustring.cpp
index d60bd16921..78feddb229 100644
--- a/core/ustring.cpp
+++ b/core/ustring.cpp
@@ -123,6 +123,31 @@ const char *CharString::get_data() const {
return "";
}
+CharString &CharString::operator=(const char *p_cstr) {
+
+ copy_from(p_cstr);
+ return *this;
+}
+
+void CharString::copy_from(const char *p_cstr) {
+
+ if (!p_cstr) {
+ resize(0);
+ return;
+ }
+
+ size_t len = strlen(p_cstr);
+
+ if (len == 0) {
+ resize(0);
+ return;
+ }
+
+ resize(len + 1); // include terminating null char
+
+ strcpy(ptrw(), p_cstr);
+}
+
void String::copy_from(const char *p_cstr) {
if (!p_cstr) {
diff --git a/core/ustring.h b/core/ustring.h
index 85103057df..e2e62874d6 100644
--- a/core/ustring.h
+++ b/core/ustring.h
@@ -101,12 +101,17 @@ public:
_cowdata._ref(p_str._cowdata);
return *this;
}
+ _FORCE_INLINE_ CharString(const char *p_cstr) { copy_from(p_cstr); }
+ CharString &operator=(const char *p_cstr);
bool operator<(const CharString &p_right) const;
CharString &operator+=(char p_char);
int length() const { return size() ? size() - 1 : 0; }
const char *get_data() const;
operator const char *() const { return get_data(); };
+
+protected:
+ void copy_from(const char *p_cstr);
};
typedef wchar_t CharType;
diff --git a/core/variant.cpp b/core/variant.cpp
index 8ae0ef0695..6eadf59fce 100644
--- a/core/variant.cpp
+++ b/core/variant.cpp
@@ -1415,7 +1415,12 @@ struct _VariantStrPair {
};
Variant::operator String() const {
+ List<const void *> stack;
+ return stringify(stack);
+}
+
+String Variant::stringify(List<const void *> &stack) const {
switch (type) {
case NIL: return "Null";
@@ -1467,6 +1472,12 @@ Variant::operator String() const {
case DICTIONARY: {
const Dictionary &d = *reinterpret_cast<const Dictionary *>(_data._mem);
+ if (stack.find(d.id())) {
+ return "{...}";
+ }
+
+ stack.push_back(d.id());
+
//const String *K=NULL;
String str("{");
List<Variant> keys;
@@ -1477,8 +1488,9 @@ Variant::operator String() const {
for (List<Variant>::Element *E = keys.front(); E; E = E->next()) {
_VariantStrPair sp;
- sp.key = String(E->get());
- sp.value = d[E->get()];
+ sp.key = E->get().stringify(stack);
+ sp.value = d[E->get()].stringify(stack);
+
pairs.push_back(sp);
}
@@ -1561,12 +1573,19 @@ Variant::operator String() const {
case ARRAY: {
Array arr = operator Array();
+ if (stack.find(arr.id())) {
+ return "[...]";
+ }
+ stack.push_back(arr.id());
+
String str("[");
for (int i = 0; i < arr.size(); i++) {
if (i)
str += ", ";
- str += String(arr[i]);
- };
+
+ str += arr[i].stringify(stack);
+ }
+
str += "]";
return str;
diff --git a/core/variant.h b/core/variant.h
index 9215d15bf0..5151262f27 100644
--- a/core/variant.h
+++ b/core/variant.h
@@ -401,6 +401,7 @@ public:
bool hash_compare(const Variant &p_variant) const;
bool booleanize() const;
+ String stringify(List<const void *> &stack) const;
void static_assign(const Variant &p_variant);
static void get_constructor_list(Variant::Type p_type, List<MethodInfo> *p_list);
diff --git a/core/variant_call.cpp b/core/variant_call.cpp
index 143b07418e..f9f73b4e51 100644
--- a/core/variant_call.cpp
+++ b/core/variant_call.cpp
@@ -36,6 +36,7 @@
#include "core/object.h"
#include "core/os/os.h"
#include "core/script_language.h"
+#include "thirdparty/misc/sha256.h"
typedef void (*VariantFunc)(Variant &r_ret, Variant &p_self, const Variant **p_args);
typedef void (*VariantConstructFunc)(Variant &r_ret, const Variant **p_args);
@@ -587,6 +588,19 @@ struct _VariantCall {
r_ret = decompressed;
}
+ static void _call_PoolByteArray_sha256_string(Variant &r_ret, Variant &p_self, const Variant **p_args) {
+ PoolByteArray *ba = reinterpret_cast<PoolByteArray *>(p_self._data._mem);
+ PoolByteArray::Read r = ba->read();
+ String s;
+ unsigned char hash[32];
+ sha256_context sha256;
+ sha256_init(&sha256);
+ sha256_hash(&sha256, (unsigned char *)r.ptr(), ba->size());
+ sha256_done(&sha256, hash);
+ s = String::hex_encode_buffer(hash, 32);
+ r_ret = s;
+ }
+
VCALL_LOCALMEM0R(PoolByteArray, size);
VCALL_LOCALMEM2(PoolByteArray, set);
VCALL_LOCALMEM1R(PoolByteArray, get);
@@ -1733,6 +1747,7 @@ void register_variant_methods() {
ADDFUNC0R(POOL_BYTE_ARRAY, STRING, PoolByteArray, get_string_from_ascii, varray());
ADDFUNC0R(POOL_BYTE_ARRAY, STRING, PoolByteArray, get_string_from_utf8, varray());
+ ADDFUNC0R(POOL_BYTE_ARRAY, STRING, PoolByteArray, sha256_string, varray());
ADDFUNC1R(POOL_BYTE_ARRAY, POOL_BYTE_ARRAY, PoolByteArray, compress, INT, "compression_mode", varray(0));
ADDFUNC2R(POOL_BYTE_ARRAY, POOL_BYTE_ARRAY, PoolByteArray, decompress, INT, "buffer_size", INT, "compression_mode", varray(0));
diff --git a/core/variant_parser.cpp b/core/variant_parser.cpp
index 6377197282..d7371b0434 100644
--- a/core/variant_parser.cpp
+++ b/core/variant_parser.cpp
@@ -1542,6 +1542,9 @@ Error VariantParser::parse_tag_assign_eof(Stream *p_stream, int &line, String &r
} else if (c != '=') {
what += String::chr(c);
} else {
+ if (p_stream->is_utf8()) {
+ what.parse_utf8(what.ascii(true).get_data());
+ }
r_assign = what;
Token token;
get_token(p_stream, token, line, r_err_str);