summaryrefslogtreecommitdiff
path: root/core
diff options
context:
space:
mode:
Diffstat (limited to 'core')
-rw-r--r--core/class_db.cpp6
-rw-r--r--core/class_db.h14
-rw-r--r--core/command_queue_mt.h24
-rw-r--r--core/dictionary.cpp5
-rw-r--r--core/dictionary.h1
-rw-r--r--core/dvector.h2
-rw-r--r--core/global_constants.cpp4
-rw-r--r--core/hashfuncs.h7
-rw-r--r--core/image.cpp174
-rw-r--r--core/image.h12
-rw-r--r--core/io/http_client.cpp69
-rw-r--r--core/io/http_client.h1
-rw-r--r--core/io/multiplayer_api.cpp7
-rw-r--r--core/io/multiplayer_api.h2
-rw-r--r--core/io/stream_peer_ssl.cpp17
-rw-r--r--core/io/stream_peer_ssl.h8
-rw-r--r--core/io/translation_loader_po.cpp40
-rw-r--r--core/math/a_star.cpp24
-rw-r--r--core/math/a_star.h2
-rw-r--r--core/math/aabb.cpp4
-rw-r--r--core/math/bsp_tree.cpp10
-rw-r--r--core/math/math_funcs.h18
-rw-r--r--core/math/matrix3.cpp24
-rw-r--r--core/math/matrix3.h4
-rw-r--r--core/math/quat.cpp16
-rw-r--r--core/math/quat.h4
-rw-r--r--core/math/transform.cpp4
-rw-r--r--core/message_queue.cpp2
-rw-r--r--core/method_ptrcall.h45
-rw-r--r--core/node_path.cpp37
-rw-r--r--core/node_path.h15
-rw-r--r--core/object.cpp6
-rw-r--r--core/object.h4
-rw-r--r--core/os/input_event.cpp12
-rw-r--r--core/os/input_event.h5
-rw-r--r--core/os/main_loop.cpp1
-rw-r--r--core/os/main_loop.h1
-rw-r--r--core/os/os.cpp17
-rw-r--r--core/os/os.h10
-rw-r--r--core/project_settings.cpp28
-rw-r--r--core/project_settings.h14
-rw-r--r--core/register_core_types.cpp2
-rw-r--r--core/resource.cpp17
-rw-r--r--core/safe_refcount.cpp48
-rw-r--r--core/safe_refcount.h50
-rw-r--r--core/script_debugger_remote.cpp9
-rw-r--r--core/script_debugger_remote.h5
-rw-r--r--core/script_language.cpp91
-rw-r--r--core/script_language.h29
-rw-r--r--core/string_db.h6
-rw-r--r--core/translation.cpp8
-rw-r--r--core/type_info.h1
-rw-r--r--core/typedefs.h7
-rw-r--r--core/undo_redo.cpp16
-rw-r--r--core/undo_redo.h4
-rw-r--r--core/ustring.cpp48
-rw-r--r--core/variant.cpp24
-rw-r--r--core/variant.h2
-rw-r--r--core/variant_op.cpp13
-rw-r--r--core/vector.h13
60 files changed, 834 insertions, 259 deletions
diff --git a/core/class_db.cpp b/core/class_db.cpp
index 59b100e282..f97eaf6099 100644
--- a/core/class_db.cpp
+++ b/core/class_db.cpp
@@ -248,9 +248,9 @@ void ClassDB::set_current_api(APIType p_api) {
current_api = p_api;
}
-HashMap<StringName, ClassDB::ClassInfo, StringNameHasher> ClassDB::classes;
-HashMap<StringName, StringName, StringNameHasher> ClassDB::resource_base_extensions;
-HashMap<StringName, StringName, StringNameHasher> ClassDB::compat_classes;
+HashMap<StringName, ClassDB::ClassInfo> ClassDB::classes;
+HashMap<StringName, StringName> ClassDB::resource_base_extensions;
+HashMap<StringName, StringName> ClassDB::compat_classes;
ClassDB::ClassInfo::ClassInfo() {
diff --git a/core/class_db.h b/core/class_db.h
index 2c77ffe65f..f1d1879236 100644
--- a/core/class_db.h
+++ b/core/class_db.h
@@ -114,10 +114,10 @@ public:
APIType api;
ClassInfo *inherits_ptr;
- HashMap<StringName, MethodBind *, StringNameHasher> method_map;
- HashMap<StringName, int, StringNameHasher> constant_map;
+ HashMap<StringName, MethodBind *> method_map;
+ HashMap<StringName, int> constant_map;
HashMap<StringName, List<StringName> > enum_map;
- HashMap<StringName, MethodInfo, StringNameHasher> signal_map;
+ HashMap<StringName, MethodInfo> signal_map;
List<PropertyInfo> property_list;
#ifdef DEBUG_METHODS_ENABLED
List<StringName> constant_order;
@@ -126,7 +126,7 @@ public:
List<MethodInfo> virtual_methods;
StringName category;
#endif
- HashMap<StringName, PropertySetGet, StringNameHasher> property_setget;
+ HashMap<StringName, PropertySetGet> property_setget;
StringName inherits;
StringName name;
@@ -143,9 +143,9 @@ public:
}
static RWLock *lock;
- static HashMap<StringName, ClassInfo, StringNameHasher> classes;
- static HashMap<StringName, StringName, StringNameHasher> resource_base_extensions;
- static HashMap<StringName, StringName, StringNameHasher> compat_classes;
+ static HashMap<StringName, ClassInfo> classes;
+ static HashMap<StringName, StringName> resource_base_extensions;
+ static HashMap<StringName, StringName> compat_classes;
#ifdef DEBUG_METHODS_ENABLED
static MethodBind *bind_methodfi(uint32_t p_flags, MethodBind *p_bind, const MethodDefinition &method_name, const Variant **p_defs, int p_defcount);
diff --git a/core/command_queue_mt.h b/core/command_queue_mt.h
index 3942b961d3..7978eaa7bf 100644
--- a/core/command_queue_mt.h
+++ b/core/command_queue_mt.h
@@ -54,9 +54,13 @@
#define _COMMA_10 ,
#define _COMMA_11 ,
#define _COMMA_12 ,
+#define _COMMA_13 ,
// 1-based comma separated list of ITEMs
#define COMMA_SEP_LIST(ITEM, LENGTH) _COMMA_SEP_LIST_##LENGTH(ITEM)
+#define _COMMA_SEP_LIST_13(ITEM) \
+ _COMMA_SEP_LIST_12(ITEM) \
+ , ITEM(13)
#define _COMMA_SEP_LIST_12(ITEM) \
_COMMA_SEP_LIST_11(ITEM) \
, ITEM(12)
@@ -97,6 +101,9 @@
// 1-based semicolon separated list of ITEMs
#define SEMIC_SEP_LIST(ITEM, LENGTH) _SEMIC_SEP_LIST_##LENGTH(ITEM)
+#define _SEMIC_SEP_LIST_13(ITEM) \
+ _SEMIC_SEP_LIST_12(ITEM); \
+ ITEM(13)
#define _SEMIC_SEP_LIST_12(ITEM) \
_SEMIC_SEP_LIST_11(ITEM); \
ITEM(12)
@@ -137,6 +144,9 @@
// 1-based space separated list of ITEMs
#define SPACE_SEP_LIST(ITEM, LENGTH) _SPACE_SEP_LIST_##LENGTH(ITEM)
+#define _SPACE_SEP_LIST_13(ITEM) \
+ _SPACE_SEP_LIST_12(ITEM) \
+ ITEM(13)
#define _SPACE_SEP_LIST_12(ITEM) \
_SPACE_SEP_LIST_11(ITEM) \
ITEM(12)
@@ -262,7 +272,7 @@
ss->sem->wait(); \
}
-#define MAX_CMD_PARAMS 12
+#define MAX_CMD_PARAMS 13
class CommandQueueMT {
@@ -290,15 +300,15 @@ class CommandQueueMT {
};
DECL_CMD(0)
- SPACE_SEP_LIST(DECL_CMD, 12)
+ SPACE_SEP_LIST(DECL_CMD, 13)
/* comands that return */
DECL_CMD_RET(0)
- SPACE_SEP_LIST(DECL_CMD_RET, 12)
+ SPACE_SEP_LIST(DECL_CMD_RET, 13)
/* commands that don't return but sync */
DECL_CMD_SYNC(0)
- SPACE_SEP_LIST(DECL_CMD_SYNC, 12)
+ SPACE_SEP_LIST(DECL_CMD_SYNC, 13)
/***** BASE *******/
@@ -432,15 +442,15 @@ class CommandQueueMT {
public:
/* NORMAL PUSH COMMANDS */
DECL_PUSH(0)
- SPACE_SEP_LIST(DECL_PUSH, 12)
+ SPACE_SEP_LIST(DECL_PUSH, 13)
/* PUSH AND RET COMMANDS */
DECL_PUSH_AND_RET(0)
- SPACE_SEP_LIST(DECL_PUSH_AND_RET, 12)
+ SPACE_SEP_LIST(DECL_PUSH_AND_RET, 13)
/* PUSH AND RET SYNC COMMANDS*/
DECL_PUSH_AND_SYNC(0)
- SPACE_SEP_LIST(DECL_PUSH_AND_SYNC, 12)
+ SPACE_SEP_LIST(DECL_PUSH_AND_SYNC, 13)
void wait_and_flush_one() {
ERR_FAIL_COND(!sync);
diff --git a/core/dictionary.cpp b/core/dictionary.cpp
index d68411a572..42d9eab310 100644
--- a/core/dictionary.cpp
+++ b/core/dictionary.cpp
@@ -140,6 +140,11 @@ void Dictionary::erase(const Variant &p_key) {
_p->variant_map.erase(p_key);
}
+bool Dictionary::erase_checked(const Variant &p_key) {
+
+ return _p->variant_map.erase(p_key);
+}
+
bool Dictionary::operator==(const Dictionary &p_dictionary) const {
return _p == p_dictionary._p;
diff --git a/core/dictionary.h b/core/dictionary.h
index 84a5cafe1d..00ec67fb99 100644
--- a/core/dictionary.h
+++ b/core/dictionary.h
@@ -66,6 +66,7 @@ public:
bool has_all(const Array &p_keys) const;
void erase(const Variant &p_key);
+ bool erase_checked(const Variant &p_key);
bool operator==(const Dictionary &p_dictionary) const;
diff --git a/core/dvector.h b/core/dvector.h
index c0190fb9e3..e03a755e6c 100644
--- a/core/dvector.h
+++ b/core/dvector.h
@@ -150,7 +150,7 @@ class PoolVector {
}
if (old_alloc->refcount.unref() == true) {
- //this should never happen but..
+ //this should never happen but..
#ifdef DEBUG_ENABLED
MemoryPool::alloc_mutex->lock();
diff --git a/core/global_constants.cpp b/core/global_constants.cpp
index 04810afe73..5b4dd05dbf 100644
--- a/core/global_constants.cpp
+++ b/core/global_constants.cpp
@@ -378,6 +378,8 @@ void register_global_constants() {
BIND_GLOBAL_ENUM_CONSTANT(BUTTON_LEFT);
BIND_GLOBAL_ENUM_CONSTANT(BUTTON_RIGHT);
BIND_GLOBAL_ENUM_CONSTANT(BUTTON_MIDDLE);
+ BIND_GLOBAL_ENUM_CONSTANT(BUTTON_XBUTTON1);
+ BIND_GLOBAL_ENUM_CONSTANT(BUTTON_XBUTTON2);
BIND_GLOBAL_ENUM_CONSTANT(BUTTON_WHEEL_UP);
BIND_GLOBAL_ENUM_CONSTANT(BUTTON_WHEEL_DOWN);
BIND_GLOBAL_ENUM_CONSTANT(BUTTON_WHEEL_LEFT);
@@ -385,6 +387,8 @@ void register_global_constants() {
BIND_GLOBAL_ENUM_CONSTANT(BUTTON_MASK_LEFT);
BIND_GLOBAL_ENUM_CONSTANT(BUTTON_MASK_RIGHT);
BIND_GLOBAL_ENUM_CONSTANT(BUTTON_MASK_MIDDLE);
+ BIND_GLOBAL_ENUM_CONSTANT(BUTTON_MASK_XBUTTON1);
+ BIND_GLOBAL_ENUM_CONSTANT(BUTTON_MASK_XBUTTON2);
//joypads
BIND_GLOBAL_ENUM_CONSTANT(JOY_BUTTON_0);
diff --git a/core/hashfuncs.h b/core/hashfuncs.h
index ae99fa39c8..735e679d1e 100644
--- a/core/hashfuncs.h
+++ b/core/hashfuncs.h
@@ -33,6 +33,8 @@
#include "math_defs.h"
#include "math_funcs.h"
+#include "node_path.h"
+#include "string_db.h"
#include "typedefs.h"
#include "ustring.h"
@@ -131,6 +133,7 @@ static inline uint64_t make_uint64_t(T p_in) {
}
struct HashMapHasherDefault {
+
static _FORCE_INLINE_ uint32_t hash(const String &p_string) { return p_string.hash(); }
static _FORCE_INLINE_ uint32_t hash(const char *p_cstr) { return hash_djb2(p_cstr); }
static _FORCE_INLINE_ uint32_t hash(const uint64_t p_int) { return hash_one_uint64(p_int); }
@@ -145,6 +148,10 @@ struct HashMapHasherDefault {
static _FORCE_INLINE_ uint32_t hash(const uint8_t p_int) { return p_int; }
static _FORCE_INLINE_ uint32_t hash(const int8_t p_int) { return (uint32_t)p_int; }
static _FORCE_INLINE_ uint32_t hash(const wchar_t p_wchar) { return (uint32_t)p_wchar; }
+
+ static _FORCE_INLINE_ uint32_t hash(const StringName &p_string_name) { return p_string_name.hash(); }
+ static _FORCE_INLINE_ uint32_t hash(const NodePath &p_path) { return p_path.hash(); }
+
//static _FORCE_INLINE_ uint32_t hash(const void* p_ptr) { return uint32_t(uint64_t(p_ptr))*(0x9e3779b1L); }
};
diff --git a/core/image.cpp b/core/image.cpp
index c08b1ac39b..19440d1718 100644
--- a/core/image.cpp
+++ b/core/image.cpp
@@ -33,6 +33,7 @@
#include "core/io/image_loader.h"
#include "core/os/copymem.h"
#include "hash_map.h"
+#include "math_funcs.h"
#include "print_string.h"
#include "thirdparty/misc/hq2x.h"
@@ -525,7 +526,7 @@ static double _bicubic_interp_kernel(double x) {
}
template <int CC>
-static void _scale_cubic(const uint8_t *p_src, uint8_t *p_dst, uint32_t p_src_width, uint32_t p_src_height, uint32_t p_dst_width, uint32_t p_dst_height) {
+static void _scale_cubic(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) {
// get source image size
int width = p_src_width;
@@ -555,7 +556,7 @@ static void _scale_cubic(const uint8_t *p_src, uint8_t *p_dst, uint32_t p_src_wi
// initial pixel value
- uint8_t *dst = p_dst + (y * p_dst_width + x) * CC;
+ uint8_t *__restrict dst = p_dst + (y * p_dst_width + x) * CC;
double color[CC];
for (int i = 0; i < CC; i++) {
@@ -583,7 +584,7 @@ static void _scale_cubic(const uint8_t *p_src, uint8_t *p_dst, uint32_t p_src_wi
ox2 = xmax;
// get pixel of original image
- const uint8_t *p = p_src + (oy2 * p_src_width + ox2) * CC;
+ const uint8_t *__restrict p = p_src + (oy2 * p_src_width + ox2) * CC;
for (int i = 0; i < CC; i++) {
@@ -600,7 +601,7 @@ static void _scale_cubic(const uint8_t *p_src, uint8_t *p_dst, uint32_t p_src_wi
}
template <int CC>
-static void _scale_bilinear(const uint8_t *p_src, uint8_t *p_dst, uint32_t p_src_width, uint32_t p_src_height, uint32_t p_dst_width, uint32_t p_dst_height) {
+static void _scale_bilinear(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) {
enum {
FRAC_BITS = 8,
@@ -655,7 +656,7 @@ static void _scale_bilinear(const uint8_t *p_src, uint8_t *p_dst, uint32_t p_src
}
template <int CC>
-static void _scale_nearest(const uint8_t *p_src, uint8_t *p_dst, uint32_t p_src_width, uint32_t p_src_height, uint32_t p_dst_width, uint32_t p_dst_height) {
+static void _scale_nearest(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) {
for (uint32_t i = 0; i < p_dst_height; i++) {
@@ -676,6 +677,16 @@ static void _scale_nearest(const uint8_t *p_src, uint8_t *p_dst, uint32_t p_src_
}
}
+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);
+
+ for (uint32_t i = 0; i < p_width * p_height * p_pixel_size; i++) {
+
+ p_dst[i] = (p_dst[i] * (256 - alpha) + p_src[i] * alpha) >> 8;
+ }
+}
+
void Image::resize_to_po2(bool p_square) {
if (!_can_modify(format)) {
@@ -707,6 +718,8 @@ void Image::resize(int p_width, int p_height, Interpolation p_interpolation) {
ERR_FAIL();
}
+ bool mipmap_aware = p_interpolation == INTERPOLATE_TRILINEAR /* || p_interpolation == INTERPOLATE_TRICUBIC */;
+
ERR_FAIL_COND(p_width <= 0);
ERR_FAIL_COND(p_height <= 0);
ERR_FAIL_COND(p_width > MAX_WIDTH);
@@ -717,6 +730,32 @@ void Image::resize(int p_width, int p_height, Interpolation p_interpolation) {
Image dst(p_width, p_height, 0, format);
+ // Setup mipmap-aware scaling
+ Image dst2;
+ int mip1;
+ int mip2;
+ float mip1_weight;
+ if (mipmap_aware) {
+ float avg_scale = ((float)p_width / width + (float)p_height / height) * 0.5f;
+ if (avg_scale >= 1.0f) {
+ mipmap_aware = false;
+ } else {
+ float level = Math::log(1.0f / avg_scale) / Math::log(2.0f);
+ mip1 = CLAMP((int)Math::floor(level), 0, get_mipmap_count());
+ mip2 = CLAMP((int)Math::ceil(level), 0, get_mipmap_count());
+ mip1_weight = 1.0f - (level - mip1);
+ }
+ }
+ bool interpolate_mipmaps = mipmap_aware && mip1 != mip2;
+ if (interpolate_mipmaps) {
+ dst2.create(p_width, p_height, 0, format);
+ }
+ bool had_mipmaps = mipmaps;
+ if (interpolate_mipmaps && !had_mipmaps) {
+ generate_mipmaps();
+ }
+ // --
+
PoolVector<uint8_t>::Read r = data.read();
const unsigned char *r_ptr = r.ptr();
@@ -734,13 +773,57 @@ void Image::resize(int p_width, int p_height, Interpolation p_interpolation) {
case 4: _scale_nearest<4>(r_ptr, w_ptr, width, height, p_width, p_height); break;
}
} break;
- case INTERPOLATE_BILINEAR: {
+ case INTERPOLATE_BILINEAR:
+ case INTERPOLATE_TRILINEAR: {
+
+ for (int i = 0; i < 2; ++i) {
+ int src_width;
+ int src_height;
+ const unsigned char *src_ptr;
+
+ if (!mipmap_aware) {
+ if (i == 0) {
+ // Standard behavior
+ src_width = width;
+ src_height = height;
+ src_ptr = r_ptr;
+ } else {
+ // No need for a second iteration
+ break;
+ }
+ } else {
+ if (i == 0) {
+ // Read from the first mipmap that will be interpolated
+ // (if both levels are the same, we will not interpolate, but at least we'll sample from the right level)
+ int offs;
+ _get_mipmap_offset_and_size(mip1, offs, src_width, src_height);
+ src_ptr = r_ptr + offs;
+ } else if (!interpolate_mipmaps) {
+ // No need generate a second image
+ break;
+ } else {
+ // Switch to read from the second mipmap that will be interpolated
+ int offs;
+ _get_mipmap_offset_and_size(mip2, offs, src_width, src_height);
+ src_ptr = r_ptr + offs;
+ // Switch to write to the second destination image
+ w = dst2.data.write();
+ w_ptr = w.ptr();
+ }
+ }
- switch (get_format_pixel_size(format)) {
- case 1: _scale_bilinear<1>(r_ptr, w_ptr, width, height, p_width, p_height); break;
- case 2: _scale_bilinear<2>(r_ptr, w_ptr, width, height, p_width, p_height); break;
- case 3: _scale_bilinear<3>(r_ptr, w_ptr, width, height, p_width, p_height); break;
- case 4: _scale_bilinear<4>(r_ptr, w_ptr, width, height, p_width, p_height); break;
+ switch (get_format_pixel_size(format)) {
+ case 1: _scale_bilinear<1>(src_ptr, w_ptr, src_width, src_height, p_width, p_height); break;
+ case 2: _scale_bilinear<2>(src_ptr, w_ptr, src_width, src_height, p_width, p_height); break;
+ case 3: _scale_bilinear<3>(src_ptr, w_ptr, src_width, src_height, p_width, p_height); break;
+ case 4: _scale_bilinear<4>(src_ptr, w_ptr, src_width, src_height, p_width, p_height); break;
+ }
+ }
+
+ if (interpolate_mipmaps) {
+ // Switch to read again from the first scaled mipmap to overlay it over the second
+ r = dst.data.read();
+ _overlay(r.ptr(), w.ptr(), mip1_weight, p_width, p_height, get_format_pixel_size(format));
}
} break;
@@ -759,7 +842,11 @@ void Image::resize(int p_width, int p_height, Interpolation p_interpolation) {
r = PoolVector<uint8_t>::Read();
w = PoolVector<uint8_t>::Write();
- if (mipmaps > 0)
+ if (interpolate_mipmaps) {
+ dst._copy_internals_from(dst2);
+ }
+
+ if (had_mipmaps)
dst.generate_mipmaps();
_copy_internals_from(dst);
@@ -1076,6 +1163,36 @@ void Image::shrink_x2() {
}
}
+void Image::normalize() {
+
+ bool used_mipmaps = has_mipmaps();
+ if (used_mipmaps) {
+ clear_mipmaps();
+ }
+
+ lock();
+
+ for (int y = 0; y < height; y++) {
+
+ for (int x = 0; x < width; x++) {
+
+ Color c = get_pixel(x, y);
+ Vector3 v(c.r * 2.0 - 1.0, c.g * 2.0 - 1.0, c.b * 2.0 - 1.0);
+ v.normalize();
+ c.r = v.x * 0.5 + 0.5;
+ c.g = v.y * 0.5 + 0.5;
+ c.b = v.z * 0.5 + 0.5;
+ set_pixel(x, y, c);
+ }
+ }
+
+ unlock();
+
+ if (used_mipmaps) {
+ generate_mipmaps(true);
+ }
+}
+
Error Image::generate_mipmaps(bool p_renormalize) {
if (!_can_modify(format)) {
@@ -1868,8 +1985,9 @@ void Image::fill(const Color &c) {
unlock();
}
-Ref<Image> (*Image::_png_mem_loader_func)(const uint8_t *, int) = NULL;
-Ref<Image> (*Image::_jpg_mem_loader_func)(const uint8_t *, int) = NULL;
+ImageMemLoadFunc Image::_png_mem_loader_func = NULL;
+ImageMemLoadFunc Image::_jpg_mem_loader_func = NULL;
+ImageMemLoadFunc Image::_webp_mem_loader_func = NULL;
void (*Image::_image_compress_bc_func)(Image *, Image::CompressSource) = NULL;
void (*Image::_image_compress_pvrtc2_func)(Image *) = NULL;
@@ -2327,6 +2445,7 @@ void Image::_bind_methods() {
ClassDB::bind_method(D_METHOD("load_png_from_buffer", "buffer"), &Image::load_png_from_buffer);
ClassDB::bind_method(D_METHOD("load_jpg_from_buffer", "buffer"), &Image::load_jpg_from_buffer);
+ ClassDB::bind_method(D_METHOD("load_webp_from_buffer", "buffer"), &Image::load_webp_from_buffer);
ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "_set_data", "_get_data");
@@ -2372,6 +2491,7 @@ void Image::_bind_methods() {
BIND_ENUM_CONSTANT(INTERPOLATE_NEAREST);
BIND_ENUM_CONSTANT(INTERPOLATE_BILINEAR);
BIND_ENUM_CONSTANT(INTERPOLATE_CUBIC);
+ BIND_ENUM_CONSTANT(INTERPOLATE_TRILINEAR);
BIND_ENUM_CONSTANT(ALPHA_NONE);
BIND_ENUM_CONSTANT(ALPHA_BIT);
@@ -2619,32 +2739,26 @@ String Image::get_format_name(Format p_format) {
}
Error Image::load_png_from_buffer(const PoolVector<uint8_t> &p_array) {
-
- int buffer_size = p_array.size();
-
- ERR_FAIL_COND_V(buffer_size == 0, ERR_INVALID_PARAMETER);
- ERR_FAIL_COND_V(!_png_mem_loader_func, ERR_INVALID_PARAMETER);
-
- PoolVector<uint8_t>::Read r = p_array.read();
-
- Ref<Image> image = _png_mem_loader_func(r.ptr(), buffer_size);
- ERR_FAIL_COND_V(!image.is_valid(), ERR_PARSE_ERROR);
-
- copy_internals_from(image);
-
- return OK;
+ return _load_from_buffer(p_array, _png_mem_loader_func);
}
Error Image::load_jpg_from_buffer(const PoolVector<uint8_t> &p_array) {
+ return _load_from_buffer(p_array, _jpg_mem_loader_func);
+}
+
+Error Image::load_webp_from_buffer(const PoolVector<uint8_t> &p_array) {
+ return _load_from_buffer(p_array, _webp_mem_loader_func);
+}
+Error Image::_load_from_buffer(const PoolVector<uint8_t> &p_array, ImageMemLoadFunc p_loader) {
int buffer_size = p_array.size();
ERR_FAIL_COND_V(buffer_size == 0, ERR_INVALID_PARAMETER);
- ERR_FAIL_COND_V(!_jpg_mem_loader_func, ERR_INVALID_PARAMETER);
+ ERR_FAIL_COND_V(!p_loader, ERR_INVALID_PARAMETER);
PoolVector<uint8_t>::Read r = p_array.read();
- Ref<Image> image = _jpg_mem_loader_func(r.ptr(), buffer_size);
+ Ref<Image> image = p_loader(r.ptr(), buffer_size);
ERR_FAIL_COND_V(!image.is_valid(), ERR_PARSE_ERROR);
copy_internals_from(image);
diff --git a/core/image.h b/core/image.h
index e38fa19ded..8c4854e053 100644
--- a/core/image.h
+++ b/core/image.h
@@ -47,6 +47,7 @@
class Image;
typedef Error (*SavePNGFunc)(const String &p_path, const Ref<Image> &p_img);
+typedef Ref<Image> (*ImageMemLoadFunc)(const uint8_t *p_png, int p_size);
class Image : public Resource {
GDCLASS(Image, Resource);
@@ -107,6 +108,8 @@ public:
INTERPOLATE_NEAREST,
INTERPOLATE_BILINEAR,
INTERPOLATE_CUBIC,
+ INTERPOLATE_TRILINEAR,
+ /* INTERPOLATE_TRICUBIC, */
/* INTERPOLATE GAUSS */
};
@@ -118,8 +121,9 @@ public:
//some functions provided by something else
- static Ref<Image> (*_png_mem_loader_func)(const uint8_t *p_png, int p_size);
- static Ref<Image> (*_jpg_mem_loader_func)(const uint8_t *p_png, int p_size);
+ static ImageMemLoadFunc _png_mem_loader_func;
+ static ImageMemLoadFunc _jpg_mem_loader_func;
+ static ImageMemLoadFunc _webp_mem_loader_func;
static void (*_image_compress_bc_func)(Image *, CompressSource p_source);
static void (*_image_compress_pvrtc2_func)(Image *);
@@ -175,6 +179,8 @@ private:
void _set_data(const Dictionary &p_data);
Dictionary _get_data() const;
+ Error _load_from_buffer(const PoolVector<uint8_t> &p_array, ImageMemLoadFunc p_loader);
+
public:
int get_width() const; ///< Get image width
int get_height() const; ///< Get image height
@@ -220,6 +226,7 @@ public:
Error generate_mipmaps(bool p_renormalize = false);
void clear_mipmaps();
+ void normalize(); //for normal maps
/**
* Create a new image of a given size and format. Current image will be lost
@@ -301,6 +308,7 @@ public:
Error load_png_from_buffer(const PoolVector<uint8_t> &p_array);
Error load_jpg_from_buffer(const PoolVector<uint8_t> &p_array);
+ Error load_webp_from_buffer(const PoolVector<uint8_t> &p_array);
Image(const uint8_t *p_mem_png_jpg, int p_len = -1);
Image(const char **p_xpm);
diff --git a/core/io/http_client.cpp b/core/io/http_client.cpp
index 8d85e78226..f1620f1493 100644
--- a/core/io/http_client.cpp
+++ b/core/io/http_client.cpp
@@ -30,6 +30,7 @@
#include "http_client.h"
#include "io/stream_peer_ssl.h"
+#include "version.h"
const char *HTTPClient::_methods[METHOD_MAX] = {
"GET",
@@ -121,16 +122,30 @@ Error HTTPClient::request_raw(Method p_method, const String &p_url, const Vector
request += "Host: " + conn_host + ":" + itos(conn_port) + "\r\n";
}
bool add_clen = p_body.size() > 0;
+ bool add_uagent = true;
+ bool add_accept = true;
for (int i = 0; i < p_headers.size(); i++) {
request += p_headers[i] + "\r\n";
- if (add_clen && p_headers[i].find("Content-Length:") == 0) {
+ if (add_clen && p_headers[i].findn("Content-Length:") == 0) {
add_clen = false;
}
+ if (add_uagent && p_headers[i].findn("User-Agent:") == 0) {
+ add_uagent = false;
+ }
+ if (add_accept && p_headers[i].findn("Accept:") == 0) {
+ add_accept = false;
+ }
}
if (add_clen) {
request += "Content-Length: " + itos(p_body.size()) + "\r\n";
// Should it add utf8 encoding?
}
+ if (add_uagent) {
+ request += "User-Agent: GodotEngine/" + String(VERSION_FULL_BUILD) + " (" + OS::get_singleton()->get_name() + ")\r\n";
+ }
+ if (add_accept) {
+ request += "Accept: */*\r\n";
+ }
request += "\r\n";
CharString cs = request.utf8();
@@ -173,17 +188,31 @@ Error HTTPClient::request(Method p_method, const String &p_url, const Vector<Str
} else {
request += "Host: " + conn_host + ":" + itos(conn_port) + "\r\n";
}
+ bool add_uagent = true;
+ bool add_accept = true;
bool add_clen = p_body.length() > 0;
for (int i = 0; i < p_headers.size(); i++) {
request += p_headers[i] + "\r\n";
- if (add_clen && p_headers[i].find("Content-Length:") == 0) {
+ if (add_clen && p_headers[i].findn("Content-Length:") == 0) {
add_clen = false;
}
+ if (add_uagent && p_headers[i].findn("User-Agent:") == 0) {
+ add_uagent = false;
+ }
+ if (add_accept && p_headers[i].findn("Accept:") == 0) {
+ add_accept = false;
+ }
}
if (add_clen) {
request += "Content-Length: " + itos(p_body.utf8().length()) + "\r\n";
// Should it add utf8 encoding?
}
+ if (add_uagent) {
+ request += "User-Agent: GodotEngine/" + String(VERSION_FULL_BUILD) + " (" + OS::get_singleton()->get_name() + ")\r\n";
+ }
+ if (add_accept) {
+ request += "Accept: */*\r\n";
+ }
request += "\r\n";
request += p_body;
@@ -250,6 +279,7 @@ void HTTPClient::close() {
chunk_left = 0;
read_until_eof = false;
response_num = 0;
+ handshaking = false;
}
Error HTTPClient::poll() {
@@ -298,16 +328,40 @@ Error HTTPClient::poll() {
} break;
case StreamPeerTCP::STATUS_CONNECTED: {
if (ssl) {
- Ref<StreamPeerSSL> ssl = StreamPeerSSL::create();
- Error err = ssl->connect_to_stream(tcp_connection, ssl_verify_host, conn_host);
- if (err != OK) {
+ Ref<StreamPeerSSL> ssl;
+ if (!handshaking) {
+ // Connect the StreamPeerSSL and start handshaking
+ ssl = Ref<StreamPeerSSL>(StreamPeerSSL::create());
+ ssl->set_blocking_handshake_enabled(false);
+ Error err = ssl->connect_to_stream(tcp_connection, ssl_verify_host, conn_host);
+ if (err != OK) {
+ close();
+ status = STATUS_SSL_HANDSHAKE_ERROR;
+ return ERR_CANT_CONNECT;
+ }
+ connection = ssl;
+ handshaking = true;
+ } else {
+ // We are already handshaking, which means we can use your already active SSL connection
+ ssl = static_cast<Ref<StreamPeerSSL> >(connection);
+ ssl->poll(); // Try to finish the handshake
+ }
+
+ if (ssl->get_status() == StreamPeerSSL::STATUS_CONNECTED) {
+ // Handshake has been successfull
+ handshaking = false;
+ status = STATUS_CONNECTED;
+ return OK;
+ } else if (ssl->get_status() != StreamPeerSSL::STATUS_HANDSHAKING) {
+ // Handshake has failed
close();
status = STATUS_SSL_HANDSHAKE_ERROR;
return ERR_CANT_CONNECT;
}
- connection = ssl;
+ // ... we will need to poll more for handshake to finish
+ } else {
+ status = STATUS_CONNECTED;
}
- status = STATUS_CONNECTED;
return OK;
} break;
case StreamPeerTCP::STATUS_ERROR:
@@ -640,6 +694,7 @@ HTTPClient::HTTPClient() {
response_num = 0;
ssl = false;
blocking = false;
+ handshaking = false;
read_chunk_size = 4096;
}
diff --git a/core/io/http_client.h b/core/io/http_client.h
index 38ec82ce8c..82b56b01db 100644
--- a/core/io/http_client.h
+++ b/core/io/http_client.h
@@ -165,6 +165,7 @@ private:
bool ssl;
bool ssl_verify_host;
bool blocking;
+ bool handshaking;
Vector<uint8_t> response_str;
diff --git a/core/io/multiplayer_api.cpp b/core/io/multiplayer_api.cpp
index 846c89510e..ffd3ecaed0 100644
--- a/core/io/multiplayer_api.cpp
+++ b/core/io/multiplayer_api.cpp
@@ -704,7 +704,7 @@ void MultiplayerAPI::rsetp(Node *p_node, int p_peer_id, bool p_unreliable, const
_send_rpc(p_node, p_peer_id, p_unreliable, true, p_property, &vptr, 1);
}
-Error MultiplayerAPI::send_bytes(PoolVector<uint8_t> p_data, int p_to) {
+Error MultiplayerAPI::send_bytes(PoolVector<uint8_t> p_data, int p_to, NetworkedMultiplayerPeer::TransferMode p_mode) {
ERR_FAIL_COND_V(p_data.size() < 1, ERR_INVALID_DATA);
ERR_FAIL_COND_V(!network_peer.is_valid(), ERR_UNCONFIGURED);
@@ -714,7 +714,10 @@ Error MultiplayerAPI::send_bytes(PoolVector<uint8_t> p_data, int p_to) {
PoolVector<uint8_t>::Read r = p_data.read();
packet_cache[0] = NETWORK_COMMAND_RAW;
memcpy(&packet_cache[1], &r[0], p_data.size());
+
network_peer->set_target_peer(p_to);
+ network_peer->set_transfer_mode(p_mode);
+
return network_peer->put_packet(packet_cache.ptr(), p_data.size() + 1);
}
@@ -770,7 +773,7 @@ Vector<int> MultiplayerAPI::get_network_connected_peers() const {
void MultiplayerAPI::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_root_node", "node"), &MultiplayerAPI::set_root_node);
- ClassDB::bind_method(D_METHOD("send_bytes", "bytes", "id"), &MultiplayerAPI::send_bytes, DEFVAL(NetworkedMultiplayerPeer::TARGET_PEER_BROADCAST));
+ ClassDB::bind_method(D_METHOD("send_bytes", "bytes", "id"), &MultiplayerAPI::send_bytes, DEFVAL(NetworkedMultiplayerPeer::TARGET_PEER_BROADCAST), DEFVAL(NetworkedMultiplayerPeer::TRANSFER_MODE_RELIABLE));
ClassDB::bind_method(D_METHOD("has_network_peer"), &MultiplayerAPI::has_network_peer);
ClassDB::bind_method(D_METHOD("get_network_peer"), &MultiplayerAPI::get_network_peer);
ClassDB::bind_method(D_METHOD("get_network_unique_id"), &MultiplayerAPI::get_network_unique_id);
diff --git a/core/io/multiplayer_api.h b/core/io/multiplayer_api.h
index ef56c4c7f2..e47b1830e8 100644
--- a/core/io/multiplayer_api.h
+++ b/core/io/multiplayer_api.h
@@ -104,7 +104,7 @@ public:
void set_root_node(Node *p_node);
void set_network_peer(const Ref<NetworkedMultiplayerPeer> &p_peer);
Ref<NetworkedMultiplayerPeer> get_network_peer() const;
- Error send_bytes(PoolVector<uint8_t> p_data, int p_to = NetworkedMultiplayerPeer::TARGET_PEER_BROADCAST);
+ Error send_bytes(PoolVector<uint8_t> p_data, int p_to = NetworkedMultiplayerPeer::TARGET_PEER_BROADCAST, NetworkedMultiplayerPeer::TransferMode p_mode = NetworkedMultiplayerPeer::TRANSFER_MODE_RELIABLE);
// Called by Node.rpc
void rpcp(Node *p_node, int p_peer_id, bool p_unreliable, const StringName &p_method, const Variant **p_arg, int p_argcount);
diff --git a/core/io/stream_peer_ssl.cpp b/core/io/stream_peer_ssl.cpp
index 012ba78c6d..c71af6b641 100644
--- a/core/io/stream_peer_ssl.cpp
+++ b/core/io/stream_peer_ssl.cpp
@@ -52,6 +52,14 @@ bool StreamPeerSSL::is_available() {
return available;
}
+void StreamPeerSSL::set_blocking_handshake_enabled(bool p_enabled) {
+ blocking_handshake = p_enabled;
+}
+
+bool StreamPeerSSL::is_blocking_handshake_enabled() const {
+ return blocking_handshake;
+}
+
PoolByteArray StreamPeerSSL::get_project_cert_array() {
PoolByteArray out;
@@ -84,16 +92,21 @@ PoolByteArray StreamPeerSSL::get_project_cert_array() {
void StreamPeerSSL::_bind_methods() {
ClassDB::bind_method(D_METHOD("poll"), &StreamPeerSSL::poll);
- ClassDB::bind_method(D_METHOD("accept_stream", "stream"), &StreamPeerSSL::accept_stream);
+ ClassDB::bind_method(D_METHOD("accept_stream"), &StreamPeerSSL::accept_stream);
ClassDB::bind_method(D_METHOD("connect_to_stream", "stream", "validate_certs", "for_hostname"), &StreamPeerSSL::connect_to_stream, DEFVAL(false), DEFVAL(String()));
ClassDB::bind_method(D_METHOD("get_status"), &StreamPeerSSL::get_status);
ClassDB::bind_method(D_METHOD("disconnect_from_stream"), &StreamPeerSSL::disconnect_from_stream);
+ ClassDB::bind_method(D_METHOD("set_blocking_handshake_enabled", "enabled"), &StreamPeerSSL::set_blocking_handshake_enabled);
+ ClassDB::bind_method(D_METHOD("is_blocking_handshake_enabled"), &StreamPeerSSL::is_blocking_handshake_enabled);
+
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "blocking_handshake"), "set_blocking_handshake_enabled", "is_blocking_handshake_enabled");
BIND_ENUM_CONSTANT(STATUS_DISCONNECTED);
BIND_ENUM_CONSTANT(STATUS_CONNECTED);
- BIND_ENUM_CONSTANT(STATUS_ERROR_NO_CERTIFICATE);
+ BIND_ENUM_CONSTANT(STATUS_ERROR);
BIND_ENUM_CONSTANT(STATUS_ERROR_HOSTNAME_MISMATCH);
}
StreamPeerSSL::StreamPeerSSL() {
+ blocking_handshake = true;
}
diff --git a/core/io/stream_peer_ssl.h b/core/io/stream_peer_ssl.h
index 77301a7c87..870704e875 100644
--- a/core/io/stream_peer_ssl.h
+++ b/core/io/stream_peer_ssl.h
@@ -49,14 +49,20 @@ protected:
friend class Main;
static bool initialize_certs;
+ bool blocking_handshake;
+
public:
enum Status {
STATUS_DISCONNECTED,
+ STATUS_HANDSHAKING,
STATUS_CONNECTED,
- STATUS_ERROR_NO_CERTIFICATE,
+ STATUS_ERROR,
STATUS_ERROR_HOSTNAME_MISMATCH
};
+ void set_blocking_handshake_enabled(bool p_enabled);
+ bool is_blocking_handshake_enabled() const;
+
virtual void poll() = 0;
virtual Error accept_stream(Ref<StreamPeer> p_base) = 0;
virtual Error connect_to_stream(Ref<StreamPeer> p_base, bool p_validate_certs = false, const String &p_for_hostname = String()) = 0;
diff --git a/core/io/translation_loader_po.cpp b/core/io/translation_loader_po.cpp
index 16d5e3c282..85c1fc5ddf 100644
--- a/core/io/translation_loader_po.cpp
+++ b/core/io/translation_loader_po.cpp
@@ -54,32 +54,25 @@ RES TranslationLoaderPO::load_translation(FileAccess *f, Error *r_error, const S
int line = 1;
bool skip_this = false;
bool skip_next = false;
+ bool is_eof = false;
- while (true) {
+ while (!is_eof) {
- String l = f->get_line();
+ String l = f->get_line().strip_edges();
+ is_eof = f->eof_reached();
- if (f->eof_reached()) {
+ // If we reached last line and it's not a content line, break, otherwise let processing that last loop
+ if (is_eof && l.empty()) {
- if (status == STATUS_READING_STRING) {
-
- if (msg_id != "") {
- if (!skip_this)
- translation->add_message(msg_id, msg_str);
- } else if (config == "")
- config = msg_str;
- break;
-
- } else if (status == STATUS_NONE)
+ if (status == STATUS_READING_ID) {
+ memdelete(f);
+ ERR_EXPLAIN(p_path + ":" + itos(line) + " Unexpected EOF while reading 'msgid' at file: ");
+ ERR_FAIL_V(RES());
+ } else {
break;
-
- memdelete(f);
- ERR_EXPLAIN(p_path + ":" + itos(line) + " Unexpected EOF while reading 'msgid' at file: ");
- ERR_FAIL_V(RES());
+ }
}
- l = l.strip_edges();
-
if (l.begins_with("msgid")) {
if (status == STATUS_READING_ID) {
@@ -160,6 +153,15 @@ RES TranslationLoaderPO::load_translation(FileAccess *f, Error *r_error, const S
f->close();
memdelete(f);
+ if (status == STATUS_READING_STRING) {
+
+ if (msg_id != "") {
+ if (!skip_this)
+ translation->add_message(msg_id, msg_str);
+ } else if (config == "")
+ config = msg_str;
+ }
+
if (config == "") {
ERR_EXPLAIN("No config found in file: " + p_path);
ERR_FAIL_V(RES());
diff --git a/core/math/a_star.cpp b/core/math/a_star.cpp
index 6908d7831d..021391da83 100644
--- a/core/math/a_star.cpp
+++ b/core/math/a_star.cpp
@@ -96,11 +96,11 @@ void AStar::remove_point(int p_id) {
Point *p = points[p_id];
- for (int i = 0; i < p->neighbours.size(); i++) {
+ for (Set<Point *>::Element *E = p->neighbours.front(); E; E = E->next()) {
- Segment s(p_id, p->neighbours[i]->id);
+ Segment s(p_id, E->get()->id);
segments.erase(s);
- p->neighbours[i]->neighbours.erase(p);
+ E->get()->neighbours.erase(p);
}
memdelete(p);
@@ -115,10 +115,10 @@ void AStar::connect_points(int p_id, int p_with_id, bool bidirectional) {
Point *a = points[p_id];
Point *b = points[p_with_id];
- a->neighbours.push_back(b);
+ a->neighbours.insert(b);
if (bidirectional)
- b->neighbours.push_back(a);
+ b->neighbours.insert(a);
Segment s(p_id, p_with_id);
if (s.from == p_id) {
@@ -168,8 +168,8 @@ PoolVector<int> AStar::get_point_connections(int p_id) {
Point *p = points[p_id];
- for (int i = 0; i < p->neighbours.size(); i++) {
- point_list.push_back(p->neighbours[i]->id);
+ for (Set<Point *>::Element *E = p->neighbours.front(); E; E = E->next()) {
+ point_list.push_back(E->get()->id);
}
return point_list;
@@ -242,9 +242,9 @@ bool AStar::_solve(Point *begin_point, Point *end_point) {
bool found_route = false;
- for (int i = 0; i < begin_point->neighbours.size(); i++) {
+ for (Set<Point *>::Element *E = begin_point->neighbours.front(); E; E = E->next()) {
- Point *n = begin_point->neighbours[i];
+ Point *n = E->get();
n->prev_point = begin_point;
n->distance = _compute_cost(begin_point->id, n->id) * n->weight_scale;
n->last_pass = pass;
@@ -283,12 +283,10 @@ bool AStar::_solve(Point *begin_point, Point *end_point) {
}
Point *p = least_cost_point->self();
- // Open the neighbours for search
- int es = p->neighbours.size();
- for (int i = 0; i < es; i++) {
+ for (Set<Point *>::Element *E = p->neighbours.front(); E; E = E->next()) {
- Point *e = p->neighbours[i];
+ Point *e = E->get();
real_t distance = _compute_cost(p->id, e->id) * e->weight_scale + p->distance;
diff --git a/core/math/a_star.h b/core/math/a_star.h
index f89e17c7bb..8c1b5f64cb 100644
--- a/core/math/a_star.h
+++ b/core/math/a_star.h
@@ -54,7 +54,7 @@ class AStar : public Reference {
real_t weight_scale;
uint64_t last_pass;
- Vector<Point *> neighbours;
+ Set<Point *> neighbours;
// Used for pathfinding
Point *prev_point;
diff --git a/core/math/aabb.cpp b/core/math/aabb.cpp
index cff19f990c..e2e71dda92 100644
--- a/core/math/aabb.cpp
+++ b/core/math/aabb.cpp
@@ -245,7 +245,6 @@ Vector3 AABB::get_longest_axis() const {
if (size.z > max_size) {
axis = Vector3(0, 0, 1);
- max_size = size.z;
}
return axis;
@@ -262,7 +261,6 @@ int AABB::get_longest_axis_index() const {
if (size.z > max_size) {
axis = 2;
- max_size = size.z;
}
return axis;
@@ -280,7 +278,6 @@ Vector3 AABB::get_shortest_axis() const {
if (size.z < max_size) {
axis = Vector3(0, 0, 1);
- max_size = size.z;
}
return axis;
@@ -297,7 +294,6 @@ int AABB::get_shortest_axis_index() const {
if (size.z < max_size) {
axis = 2;
- max_size = size.z;
}
return axis;
diff --git a/core/math/bsp_tree.cpp b/core/math/bsp_tree.cpp
index b1424e1d78..2e184f7a88 100644
--- a/core/math/bsp_tree.cpp
+++ b/core/math/bsp_tree.cpp
@@ -244,10 +244,8 @@ bool BSP_Tree::point_is_inside(const Vector3 &p_point) const {
const Node *nodesptr = &nodes[0];
const Plane *planesptr = &planes[0];
- int plane_count = planes.size();
int idx = node_count - 1;
- int steps = 0;
while (true) {
@@ -259,21 +257,19 @@ bool BSP_Tree::point_is_inside(const Vector3 &p_point) const {
return true;
}
- uint16_t plane = nodesptr[idx].plane;
#ifdef DEBUG_ENABLED
-
+ int plane_count = planes.size();
+ uint16_t plane = nodesptr[idx].plane;
ERR_FAIL_INDEX_V(plane, plane_count, false);
#endif
+
bool over = planesptr[nodesptr[idx].plane].is_point_over(p_point);
idx = over ? nodes[idx].over : nodes[idx].under;
#ifdef DEBUG_ENABLED
-
ERR_FAIL_COND_V(idx < MAX_NODES && idx >= node_count, false);
#endif
-
- steps++;
}
return false;
diff --git a/core/math/math_funcs.h b/core/math/math_funcs.h
index 20001bb9a6..f0c0268f31 100644
--- a/core/math/math_funcs.h
+++ b/core/math/math_funcs.h
@@ -182,8 +182,22 @@ public:
static _ALWAYS_INLINE_ float abs(float g) { return absf(g); }
static _ALWAYS_INLINE_ int abs(int g) { return g > 0 ? g : -g; }
- static _ALWAYS_INLINE_ double fposmod(double p_x, double p_y) { return (p_x >= 0) ? Math::fmod(p_x, p_y) : p_y - Math::fmod(-p_x, p_y); }
- static _ALWAYS_INLINE_ float fposmod(float p_x, float p_y) { return (p_x >= 0) ? Math::fmod(p_x, p_y) : p_y - Math::fmod(-p_x, p_y); }
+ static _ALWAYS_INLINE_ double fposmod(double p_x, double p_y) {
+ double value = Math::fmod(p_x, p_y);
+ if ((value < 0 && p_y > 0) || (value > 0 && p_y < 0)) {
+ value += p_y;
+ }
+ value += 0.0;
+ return value;
+ }
+ static _ALWAYS_INLINE_ float fposmod(float p_x, float p_y) {
+ float value = Math::fmod(p_x, p_y);
+ if ((value < 0 && p_y > 0) || (value > 0 && p_y < 0)) {
+ value += p_y;
+ }
+ value += 0.0;
+ return value;
+ }
static _ALWAYS_INLINE_ double deg2rad(double p_y) { return p_y * Math_PI / 180.0; }
static _ALWAYS_INLINE_ float deg2rad(float p_y) { return p_y * Math_PI / 180.0; }
diff --git a/core/math/matrix3.cpp b/core/math/matrix3.cpp
index 202115e2ca..2371f49561 100644
--- a/core/math/matrix3.cpp
+++ b/core/math/matrix3.cpp
@@ -356,8 +356,7 @@ void Basis::rotate(const Quat &p_quat) {
*this = rotated(p_quat);
}
-// TODO: rename this to get_rotation_euler
-Vector3 Basis::get_rotation() const {
+Vector3 Basis::get_rotation_euler() const {
// Assumes that the matrix can be decomposed into a proper rotation and scaling matrix as M = R.S,
// and returns the Euler angles corresponding to the rotation part, complementing get_scale().
// See the comment in get_scale() for further information.
@@ -371,6 +370,20 @@ Vector3 Basis::get_rotation() const {
return m.get_euler();
}
+Quat Basis::get_rotation_quat() const {
+ // Assumes that the matrix can be decomposed into a proper rotation and scaling matrix as M = R.S,
+ // and returns the Euler angles corresponding to the rotation part, complementing get_scale().
+ // See the comment in get_scale() for further information.
+ Basis m = orthonormalized();
+ real_t det = m.determinant();
+ if (det < 0) {
+ // Ensure that the determinant is 1, such that result is a proper rotation matrix which can be represented by Euler angles.
+ m.scale(Vector3(-1, -1, -1));
+ }
+
+ return m.get_quat();
+}
+
void Basis::get_rotation_axis_angle(Vector3 &p_axis, real_t &p_angle) const {
// Assumes that the matrix can be decomposed into a proper rotation and scaling matrix as M = R.S,
// and returns the Euler angles corresponding to the rotation part, complementing get_scale().
@@ -591,10 +604,9 @@ Basis::operator String() const {
}
Quat Basis::get_quat() const {
- //commenting this check because precision issues cause it to fail when it shouldn't
- //#ifdef MATH_CHECKS
- //ERR_FAIL_COND_V(is_rotation() == false, Quat());
- //#endif
+#ifdef MATH_CHECKS
+ ERR_FAIL_COND_V(is_rotation() == false, Quat());
+#endif
real_t trace = elements[0][0] + elements[1][1] + elements[2][2];
real_t temp[4];
diff --git a/core/math/matrix3.h b/core/math/matrix3.h
index 63d4f5d79d..cd1b51baa6 100644
--- a/core/math/matrix3.h
+++ b/core/math/matrix3.h
@@ -84,9 +84,11 @@ public:
void rotate(const Quat &p_quat);
Basis rotated(const Quat &p_quat) const;
- Vector3 get_rotation() const;
+ Vector3 get_rotation_euler() const;
void get_rotation_axis_angle(Vector3 &p_axis, real_t &p_angle) const;
void get_rotation_axis_angle_local(Vector3 &p_axis, real_t &p_angle) const;
+ Quat get_rotation_quat() const;
+ Vector3 get_rotation() const { return get_rotation_euler(); };
Vector3 rotref_posscale_decomposition(Basis &rotref) const;
diff --git a/core/math/quat.cpp b/core/math/quat.cpp
index b938fc3cfd..67c9048a41 100644
--- a/core/math/quat.cpp
+++ b/core/math/quat.cpp
@@ -139,15 +139,15 @@ bool Quat::is_normalized() const {
Quat Quat::inverse() const {
#ifdef MATH_CHECKS
- ERR_FAIL_COND_V(is_normalized() == false, Quat(0, 0, 0, 0));
+ ERR_FAIL_COND_V(is_normalized() == false, Quat());
#endif
return Quat(-x, -y, -z, w);
}
Quat Quat::slerp(const Quat &q, const real_t &t) const {
#ifdef MATH_CHECKS
- ERR_FAIL_COND_V(is_normalized() == false, Quat(0, 0, 0, 0));
- ERR_FAIL_COND_V(q.is_normalized() == false, Quat(0, 0, 0, 0));
+ ERR_FAIL_COND_V(is_normalized() == false, Quat());
+ ERR_FAIL_COND_V(q.is_normalized() == false, Quat());
#endif
Quat to1;
real_t omega, cosom, sinom, scale0, scale1;
@@ -192,7 +192,10 @@ Quat Quat::slerp(const Quat &q, const real_t &t) const {
}
Quat Quat::slerpni(const Quat &q, const real_t &t) const {
-
+#ifdef MATH_CHECKS
+ ERR_FAIL_COND_V(is_normalized() == false, Quat());
+ ERR_FAIL_COND_V(q.is_normalized() == false, Quat());
+#endif
const Quat &from = *this;
real_t dot = from.dot(q);
@@ -211,7 +214,10 @@ Quat Quat::slerpni(const Quat &q, const real_t &t) const {
}
Quat Quat::cubic_slerp(const Quat &q, const Quat &prep, const Quat &postq, const real_t &t) const {
-
+#ifdef MATH_CHECKS
+ ERR_FAIL_COND_V(is_normalized() == false, Quat());
+ ERR_FAIL_COND_V(q.is_normalized() == false, Quat());
+#endif
//the only way to do slerp :|
real_t t2 = (1.0 - t) * t * 2;
Quat sp = this->slerp(q, t);
diff --git a/core/math/quat.h b/core/math/quat.h
index 3e1344a913..6dc8d66f60 100644
--- a/core/math/quat.h
+++ b/core/math/quat.h
@@ -84,7 +84,9 @@ public:
}
_FORCE_INLINE_ Vector3 xform(const Vector3 &v) const {
-
+#ifdef MATH_CHECKS
+ ERR_FAIL_COND_V(is_normalized() == false, v);
+#endif
Vector3 u(x, y, z);
Vector3 uv = u.cross(v);
return v + ((uv * w) + u.cross(uv)) * ((real_t)2);
diff --git a/core/math/transform.cpp b/core/math/transform.cpp
index 7cd186ca60..d1e190f4b9 100644
--- a/core/math/transform.cpp
+++ b/core/math/transform.cpp
@@ -120,11 +120,11 @@ Transform Transform::interpolate_with(const Transform &p_transform, real_t p_c)
/* not sure if very "efficient" but good enough? */
Vector3 src_scale = basis.get_scale();
- Quat src_rot = basis.orthonormalized();
+ Quat src_rot = basis.get_rotation_quat();
Vector3 src_loc = origin;
Vector3 dst_scale = p_transform.basis.get_scale();
- Quat dst_rot = p_transform.basis;
+ Quat dst_rot = p_transform.basis.get_rotation_quat();
Vector3 dst_loc = p_transform.origin;
Transform dst; //this could be made faster by using a single function in Basis..
diff --git a/core/message_queue.cpp b/core/message_queue.cpp
index 25ee6eafae..3adaad868a 100644
--- a/core/message_queue.cpp
+++ b/core/message_queue.cpp
@@ -342,7 +342,7 @@ MessageQueue::MessageQueue() {
buffer_end = 0;
buffer_max_used = 0;
- buffer_size = GLOBAL_DEF("memory/limits/message_queue/max_size_kb", DEFAULT_QUEUE_SIZE_KB);
+ buffer_size = GLOBAL_DEF_RST("memory/limits/message_queue/max_size_kb", DEFAULT_QUEUE_SIZE_KB);
buffer_size *= 1024;
buffer = memnew_arr(uint8_t, buffer_size);
}
diff --git a/core/method_ptrcall.h b/core/method_ptrcall.h
index 2007c3def5..677e8e1fb2 100644
--- a/core/method_ptrcall.h
+++ b/core/method_ptrcall.h
@@ -214,6 +214,50 @@ struct PtrToArg<const T *> {
} \
}
+#define MAKE_VECARG_ALT(m_type, m_type_alt) \
+ template <> \
+ struct PtrToArg<Vector<m_type_alt> > { \
+ _FORCE_INLINE_ static Vector<m_type_alt> convert(const void *p_ptr) { \
+ const PoolVector<m_type> *dvs = reinterpret_cast<const PoolVector<m_type> *>(p_ptr); \
+ Vector<m_type_alt> ret; \
+ int len = dvs->size(); \
+ ret.resize(len); \
+ { \
+ PoolVector<m_type>::Read r = dvs->read(); \
+ for (int i = 0; i < len; i++) { \
+ ret[i] = r[i]; \
+ } \
+ } \
+ return ret; \
+ } \
+ _FORCE_INLINE_ static void encode(Vector<m_type_alt> p_vec, void *p_ptr) { \
+ PoolVector<m_type> *dv = reinterpret_cast<PoolVector<m_type> *>(p_ptr); \
+ int len = p_vec.size(); \
+ dv->resize(len); \
+ { \
+ PoolVector<m_type>::Write w = dv->write(); \
+ for (int i = 0; i < len; i++) { \
+ w[i] = p_vec[i]; \
+ } \
+ } \
+ } \
+ }; \
+ template <> \
+ struct PtrToArg<const Vector<m_type_alt> &> { \
+ _FORCE_INLINE_ static Vector<m_type_alt> convert(const void *p_ptr) { \
+ const PoolVector<m_type> *dvs = reinterpret_cast<const PoolVector<m_type> *>(p_ptr); \
+ Vector<m_type_alt> ret; \
+ int len = dvs->size(); \
+ ret.resize(len); \
+ { \
+ PoolVector<m_type>::Read r = dvs->read(); \
+ for (int i = 0; i < len; i++) { \
+ ret[i] = r[i]; \
+ } \
+ } \
+ return ret; \
+ } \
+ }
MAKE_VECARG(String);
MAKE_VECARG(uint8_t);
MAKE_VECARG(int);
@@ -221,6 +265,7 @@ MAKE_VECARG(float);
MAKE_VECARG(Vector2);
MAKE_VECARG(Vector3);
MAKE_VECARG(Color);
+MAKE_VECARG_ALT(String, StringName);
//for stuff that gets converted to Array vectors
#define MAKE_VECARR(m_type) \
diff --git a/core/node_path.cpp b/core/node_path.cpp
index 64983fc091..487d5ee8c6 100644
--- a/core/node_path.cpp
+++ b/core/node_path.cpp
@@ -32,10 +32,7 @@
#include "print_string.h"
-uint32_t NodePath::hash() const {
-
- if (!data)
- return 0;
+void NodePath::_update_hash_cache() const {
uint32_t h = data->absolute ? 1 : 0;
int pc = data->path.size();
@@ -49,13 +46,15 @@ uint32_t NodePath::hash() const {
h = h ^ ssn[i].hash();
}
- return h;
+ data->hash_cache_valid = true;
+ data->hash_cache = h;
}
void NodePath::prepend_period() {
if (data->path.size() && data->path[0].operator String() != ".") {
data->path.insert(0, ".");
+ data->hash_cache_valid = false;
}
}
@@ -114,21 +113,33 @@ bool NodePath::operator==(const NodePath &p_path) const {
if (data->absolute != p_path.data->absolute)
return false;
- if (data->path.size() != p_path.data->path.size())
+ int path_size = data->path.size();
+
+ if (path_size != p_path.data->path.size()) {
return false;
+ }
+
+ int subpath_size = data->subpath.size();
- if (data->subpath.size() != p_path.data->subpath.size())
+ if (subpath_size != p_path.data->subpath.size()) {
return false;
+ }
- for (int i = 0; i < data->path.size(); i++) {
+ const StringName *l_path_ptr = data->path.ptr();
+ const StringName *r_path_ptr = p_path.data->path.ptr();
+
+ for (int i = 0; i < path_size; i++) {
- if (data->path[i] != p_path.data->path[i])
+ if (l_path_ptr[i] != r_path_ptr[i])
return false;
}
- for (int i = 0; i < data->subpath.size(); i++) {
+ const StringName *l_subpath_ptr = data->subpath.ptr();
+ const StringName *r_subpath_ptr = p_path.data->subpath.ptr();
+
+ for (int i = 0; i < subpath_size; i++) {
- if (data->subpath[i] != p_path.data->subpath[i])
+ if (l_subpath_ptr[i] != r_subpath_ptr[i])
return false;
}
@@ -286,6 +297,7 @@ NodePath::NodePath(const Vector<StringName> &p_path, bool p_absolute) {
data->absolute = p_absolute;
data->path = p_path;
data->has_slashes = true;
+ data->hash_cache_valid = false;
}
NodePath::NodePath(const Vector<StringName> &p_path, const Vector<StringName> &p_subpath, bool p_absolute) {
@@ -301,6 +313,7 @@ NodePath::NodePath(const Vector<StringName> &p_path, const Vector<StringName> &p
data->path = p_path;
data->subpath = p_subpath;
data->has_slashes = true;
+ data->hash_cache_valid = false;
}
void NodePath::simplify() {
@@ -324,6 +337,7 @@ void NodePath::simplify() {
}
}
}
+ data->hash_cache_valid = false;
}
NodePath NodePath::simplified() const {
@@ -396,6 +410,7 @@ NodePath::NodePath(const String &p_path) {
data->absolute = absolute ? true : false;
data->has_slashes = has_slashes;
data->subpath = subpath;
+ data->hash_cache_valid = false;
if (slices == 0)
return;
diff --git a/core/node_path.h b/core/node_path.h
index 288f39721f..71235029af 100644
--- a/core/node_path.h
+++ b/core/node_path.h
@@ -47,11 +47,15 @@ class NodePath {
StringName concatenated_subpath;
bool absolute;
bool has_slashes;
+ mutable bool hash_cache_valid;
+ mutable uint32_t hash_cache;
};
- Data *data;
+ mutable Data *data;
void unref();
+ void _update_hash_cache() const;
+
public:
_FORCE_INLINE_ StringName get_sname() const {
@@ -78,7 +82,14 @@ public:
NodePath get_parent() const;
- uint32_t hash() const;
+ _FORCE_INLINE_ uint32_t hash() const {
+ if (!data)
+ return 0;
+ if (!data->hash_cache_valid) {
+ _update_hash_cache();
+ }
+ return data->hash_cache;
+ }
operator String() const;
bool is_empty() const;
diff --git a/core/object.cpp b/core/object.cpp
index 1d2aeb7ba5..d86c60a3b8 100644
--- a/core/object.cpp
+++ b/core/object.cpp
@@ -601,8 +601,12 @@ void Object::get_property_list(List<PropertyInfo> *p_list, bool p_reversed) cons
_get_property_listv(p_list, p_reversed);
- if (!is_class("Script")) // can still be set, but this is for userfriendlyness
+ if (!is_class("Script")) { // can still be set, but this is for userfriendlyness
+#ifdef TOOLS_ENABLED
+ p_list->push_back(PropertyInfo(Variant::NIL, "Script", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_GROUP));
+#endif
p_list->push_back(PropertyInfo(Variant::OBJECT, "script", PROPERTY_HINT_RESOURCE_TYPE, "Script", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_STORE_IF_NONZERO));
+ }
#ifdef TOOLS_ENABLED
if (editor_section_folding.size()) {
p_list->push_back(PropertyInfo(Variant::ARRAY, CoreStringNames::get_singleton()->_sections_unfolded, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL));
diff --git a/core/object.h b/core/object.h
index 7963a43fd6..8dc3426d1d 100644
--- a/core/object.h
+++ b/core/object.h
@@ -31,6 +31,7 @@
#ifndef OBJECT_H
#define OBJECT_H
+#include "hash_map.h"
#include "list.h"
#include "map.h"
#include "os/rw_lock.h"
@@ -85,6 +86,7 @@ enum PropertyHint {
PROPERTY_HINT_PROPERTY_OF_INSTANCE, ///< a property of an instance
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_MAX,
// When updating PropertyHint, also sync the hardcoded list in VisualScriptEditorVariableEdit
};
@@ -450,7 +452,7 @@ private:
Signal() { lock = 0; }
};
- HashMap<StringName, Signal, StringNameHasher> signal_map;
+ HashMap<StringName, Signal> signal_map;
List<Connection> connections;
#ifdef DEBUG_ENABLED
SafeRefCount _lock_index;
diff --git a/core/os/input_event.cpp b/core/os/input_event.cpp
index 4ebb821a2f..ca6446d015 100644
--- a/core/os/input_event.cpp
+++ b/core/os/input_event.cpp
@@ -509,6 +509,12 @@ String InputEventMouseButton::as_text() const {
case BUTTON_WHEEL_RIGHT:
button_index_string = "BUTTON_WHEEL_RIGHT";
break;
+ case BUTTON_XBUTTON1:
+ button_index_string = "BUTTON_XBUTTON1";
+ break;
+ case BUTTON_XBUTTON2:
+ button_index_string = "BUTTON_XBUTTON2";
+ break;
default:
button_index_string = itos(get_button_index());
break;
@@ -601,6 +607,12 @@ String InputEventMouseMotion::as_text() const {
case BUTTON_MASK_RIGHT:
button_mask_string = "BUTTON_MASK_RIGHT";
break;
+ case BUTTON_MASK_XBUTTON1:
+ button_mask_string = "BUTTON_MASK_XBUTTON1";
+ break;
+ case BUTTON_MASK_XBUTTON2:
+ button_mask_string = "BUTTON_MASK_XBUTTON2";
+ break;
default:
button_mask_string = itos(get_button_mask());
break;
diff --git a/core/os/input_event.h b/core/os/input_event.h
index 037649ed60..bd1a85ce29 100644
--- a/core/os/input_event.h
+++ b/core/os/input_event.h
@@ -53,10 +53,13 @@ enum ButtonList {
BUTTON_WHEEL_DOWN = 5,
BUTTON_WHEEL_LEFT = 6,
BUTTON_WHEEL_RIGHT = 7,
+ BUTTON_XBUTTON1 = 8,
+ BUTTON_XBUTTON2 = 9,
BUTTON_MASK_LEFT = (1 << (BUTTON_LEFT - 1)),
BUTTON_MASK_RIGHT = (1 << (BUTTON_RIGHT - 1)),
BUTTON_MASK_MIDDLE = (1 << (BUTTON_MIDDLE - 1)),
-
+ BUTTON_MASK_XBUTTON1 = (1 << (BUTTON_XBUTTON1 - 1)),
+ BUTTON_MASK_XBUTTON2 = (1 << (BUTTON_XBUTTON2 - 1))
};
enum JoystickList {
diff --git a/core/os/main_loop.cpp b/core/os/main_loop.cpp
index 916c86613e..c51801e3e2 100644
--- a/core/os/main_loop.cpp
+++ b/core/os/main_loop.cpp
@@ -58,6 +58,7 @@ void MainLoop::_bind_methods() {
BIND_CONSTANT(NOTIFICATION_OS_MEMORY_WARNING);
BIND_CONSTANT(NOTIFICATION_TRANSLATION_CHANGED);
BIND_CONSTANT(NOTIFICATION_WM_ABOUT);
+ BIND_CONSTANT(NOTIFICATION_CRASH);
};
void MainLoop::set_init_script(const Ref<Script> &p_init_script) {
diff --git a/core/os/main_loop.h b/core/os/main_loop.h
index 546e4e280c..f96e46141e 100644
--- a/core/os/main_loop.h
+++ b/core/os/main_loop.h
@@ -62,6 +62,7 @@ public:
// fixes this issue.
NOTIFICATION_TRANSLATION_CHANGED = 90,
NOTIFICATION_WM_ABOUT = 91,
+ NOTIFICATION_CRASH = 92,
};
virtual void input_event(const Ref<InputEvent> &p_event);
diff --git a/core/os/os.cpp b/core/os/os.cpp
index 5eed10e30c..89866e4044 100644
--- a/core/os/os.cpp
+++ b/core/os/os.cpp
@@ -614,6 +614,9 @@ bool OS::has_feature(const String &p_feature) {
if (_check_internal_feature_support(p_feature))
return true;
+ if (ProjectSettings::get_singleton()->has_custom_feature(p_feature))
+ return true;
+
return false;
}
@@ -656,9 +659,23 @@ const char *OS::get_audio_driver_name(int p_driver) const {
return AudioDriverManager::get_driver(p_driver)->get_name();
}
+void OS::set_restart_on_exit(bool p_restart, const List<String> &p_restart_arguments) {
+ restart_on_exit = p_restart;
+ restart_commandline = p_restart_arguments;
+}
+
+bool OS::is_restart_on_exit_set() const {
+ return restart_on_exit;
+}
+
+List<String> OS::get_restart_on_exit_arguments() const {
+ return restart_commandline;
+}
+
OS::OS() {
void *volatile stack_bottom;
+ restart_on_exit = false;
last_error = NULL;
singleton = this;
_keep_screen_on = true; // set default value to true, because this had been true before godot 2.0.
diff --git a/core/os/os.h b/core/os/os.h
index adf01a90e7..4e0cb003fb 100644
--- a/core/os/os.h
+++ b/core/os/os.h
@@ -74,6 +74,9 @@ class OS {
CompositeLogger *_logger;
+ bool restart_on_exit;
+ List<String> restart_commandline;
+
protected:
void _set_logger(CompositeLogger *p_logger);
@@ -182,7 +185,7 @@ public:
virtual int get_video_driver_count() const;
virtual const char *get_video_driver_name(int p_driver) const;
-
+ virtual int get_current_video_driver() const = 0;
virtual int get_audio_driver_count() const;
virtual const char *get_audio_driver_name(int p_driver) const;
@@ -496,6 +499,11 @@ public:
bool is_layered_allowed() const { return _allow_layered; }
bool is_hidpi_allowed() const { return _allow_hidpi; }
+
+ void set_restart_on_exit(bool p_restart, const List<String> &p_restart_arguments);
+ bool is_restart_on_exit_set() const;
+ List<String> get_restart_on_exit_arguments() const;
+
OS();
virtual ~OS();
};
diff --git a/core/project_settings.cpp b/core/project_settings.cpp
index ac4a4b7d15..60e8933751 100644
--- a/core/project_settings.cpp
+++ b/core/project_settings.cpp
@@ -105,6 +105,11 @@ void ProjectSettings::set_initial_value(const String &p_name, const Variant &p_v
ERR_FAIL_COND(!props.has(p_name));
props[p_name].initial = p_value;
}
+void ProjectSettings::set_restart_if_changed(const String &p_name, bool p_restart) {
+
+ ERR_FAIL_COND(!props.has(p_name));
+ props[p_name].restart_if_changed = p_restart;
+}
String ProjectSettings::globalize_path(const String &p_path) const {
@@ -137,7 +142,7 @@ bool ProjectSettings::_set(const StringName &p_name, const Variant &p_value) {
else {
if (p_name == CoreStringNames::get_singleton()->_custom_features) {
- Vector<String> custom_feature_array = p_value;
+ Vector<String> custom_feature_array = String(p_value).split(",");
for (int i = 0; i < custom_feature_array.size(); i++) {
custom_features.insert(custom_feature_array[i]);
@@ -225,6 +230,9 @@ void ProjectSettings::_get_property_list(List<PropertyInfo> *p_list) const {
else
vc.flags = PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_STORAGE;
+ if (v->restart_if_changed) {
+ vc.flags |= PROPERTY_USAGE_RESTART_IF_CHANGED;
+ }
vclist.insert(vc);
}
@@ -515,7 +523,11 @@ Error ProjectSettings::_load_settings_text(const String p_path) {
}
} else {
// config_version is checked and dropped
- set(section + "/" + assign, value);
+ if (section == String()) {
+ set(assign, value);
+ } else {
+ set(section + "/" + assign, value);
+ }
}
} else if (next_tag.name != String()) {
section = next_tag.name;
@@ -813,7 +825,7 @@ Error ProjectSettings::save_custom(const String &p_path, const CustomMap &p_cust
return OK;
}
-Variant _GLOBAL_DEF(const String &p_var, const Variant &p_default) {
+Variant _GLOBAL_DEF(const String &p_var, const Variant &p_default, bool p_restart_if_changed) {
Variant ret;
if (!ProjectSettings::get_singleton()->has_setting(p_var)) {
@@ -823,6 +835,7 @@ Variant _GLOBAL_DEF(const String &p_var, const Variant &p_default) {
ProjectSettings::get_singleton()->set_initial_value(p_var, p_default);
ProjectSettings::get_singleton()->set_builtin_order(p_var);
+ ProjectSettings::get_singleton()->set_restart_if_changed(p_var, p_restart_if_changed);
return ret;
}
@@ -870,6 +883,10 @@ void ProjectSettings::set_custom_property_info(const String &p_prop, const Prope
custom_prop_info[p_prop].name = p_prop;
}
+const Map<StringName, PropertyInfo> &ProjectSettings::get_custom_property_info() const {
+ return custom_prop_info;
+}
+
void ProjectSettings::set_disable_feature_overrides(bool p_disable) {
disable_feature_overrides = p_disable;
@@ -904,6 +921,10 @@ Variant ProjectSettings::get_setting(const String &p_setting) const {
return get(p_setting);
}
+bool ProjectSettings::has_custom_feature(const String &p_feature) const {
+ return custom_features.has(p_feature);
+}
+
void ProjectSettings::_bind_methods() {
ClassDB::bind_method(D_METHOD("has_setting", "name"), &ProjectSettings::has_setting);
@@ -1068,7 +1089,6 @@ ProjectSettings::ProjectSettings() {
custom_prop_info["rendering/threads/thread_model"] = PropertyInfo(Variant::INT, "rendering/threads/thread_model", PROPERTY_HINT_ENUM, "Single-Unsafe,Single-Safe,Multi-Threaded");
custom_prop_info["physics/2d/thread_model"] = PropertyInfo(Variant::INT, "physics/2d/thread_model", PROPERTY_HINT_ENUM, "Single-Unsafe,Single-Safe,Multi-Threaded");
custom_prop_info["rendering/quality/intended_usage/framebuffer_allocation"] = PropertyInfo(Variant::INT, "rendering/quality/intended_usage/framebuffer_allocation", PROPERTY_HINT_ENUM, "2D,2D Without Sampling,3D,3D Without Effects");
- GLOBAL_DEF("rendering/quality/intended_usage/framebuffer_mode", 2);
GLOBAL_DEF("debug/settings/profiler/max_functions", 16384);
diff --git a/core/project_settings.h b/core/project_settings.h
index b01e7855aa..75ebc5acc8 100644
--- a/core/project_settings.h
+++ b/core/project_settings.h
@@ -59,18 +59,21 @@ protected:
Variant initial;
bool hide_from_editor;
bool overridden;
+ bool restart_if_changed;
VariantContainer() :
order(0),
persist(false),
hide_from_editor(false),
- overridden(false) {
+ overridden(false),
+ restart_if_changed(false) {
}
VariantContainer(const Variant &p_variant, int p_order, bool p_persist = false) :
order(p_order),
persist(p_persist),
variant(p_variant),
hide_from_editor(false),
- overridden(false) {
+ overridden(false),
+ restart_if_changed(false) {
}
};
@@ -120,6 +123,7 @@ public:
String globalize_path(const String &p_path) const;
void set_initial_value(const String &p_name, const Variant &p_value);
+ void set_restart_if_changed(const String &p_name, bool p_restart);
bool property_can_revert(const String &p_name);
Variant property_get_revert(const String &p_name);
@@ -137,6 +141,7 @@ public:
Error save_custom(const String &p_path = "", const CustomMap &p_custom = CustomMap(), const Vector<String> &p_custom_features = Vector<String>(), bool p_merge_with_current = true);
Error save();
void set_custom_property_info(const String &p_prop, const PropertyInfo &p_info);
+ const Map<StringName, PropertyInfo> &get_custom_property_info() const;
Vector<String> get_optimizer_presets() const;
@@ -150,13 +155,16 @@ public:
void set_registering_order(bool p_enable);
+ bool has_custom_feature(const String &p_feature) const;
+
ProjectSettings();
~ProjectSettings();
};
//not a macro any longer
-Variant _GLOBAL_DEF(const String &p_var, const Variant &p_default);
+Variant _GLOBAL_DEF(const String &p_var, const Variant &p_default, bool p_restart_if_changed = false);
#define GLOBAL_DEF(m_var, m_value) _GLOBAL_DEF(m_var, m_value)
+#define GLOBAL_DEF_RST(m_var, m_value) _GLOBAL_DEF(m_var, m_value, true)
#define GLOBAL_GET(m_var) ProjectSettings::get_singleton()->get(m_var)
#endif
diff --git a/core/register_core_types.cpp b/core/register_core_types.cpp
index 2a611ccf6a..9bcc2d4530 100644
--- a/core/register_core_types.cpp
+++ b/core/register_core_types.cpp
@@ -191,7 +191,7 @@ void register_core_types() {
void register_core_settings() {
//since in register core types, globals may not e present
- GLOBAL_DEF("network/limits/packet_peer_stream/max_buffer_po2", (16));
+ GLOBAL_DEF_RST("network/limits/packet_peer_stream/max_buffer_po2", (16));
}
void register_core_singletons() {
diff --git a/core/resource.cpp b/core/resource.cpp
index 4cca73be5d..87ff4d3c2a 100644
--- a/core/resource.cpp
+++ b/core/resource.cpp
@@ -225,15 +225,20 @@ Ref<Resource> Resource::duplicate(bool p_subresources) const {
if (!(E->get().usage & PROPERTY_USAGE_STORAGE))
continue;
- Variant p = get(E->get().name).duplicate(true);
- if (p.get_type() == Variant::OBJECT && p_subresources) {
+ Variant p = get(E->get().name);
+
+ if ((p.get_type() == Variant::DICTIONARY || p.get_type() == Variant::ARRAY)) {
+ p = p.duplicate(p_subresources); //does not make a long of sense but should work?
+ } else if (p.get_type() == Variant::OBJECT && (p_subresources || (E->get().usage & PROPERTY_USAGE_DO_NOT_SHARE_ON_DUPLICATE))) {
RES sr = p;
- if (sr.is_valid())
- p = sr->duplicate(true);
- }
+ if (sr.is_valid()) {
+ r->set(E->get().name, sr->duplicate(p_subresources));
+ }
+ } else {
- r->set(E->get().name, p);
+ r->set(E->get().name, p);
+ }
}
return Ref<Resource>(r);
diff --git a/core/safe_refcount.cpp b/core/safe_refcount.cpp
index 3b203f6977..692ff722f3 100644
--- a/core/safe_refcount.cpp
+++ b/core/safe_refcount.cpp
@@ -57,113 +57,113 @@
return m_val; \
}
-_ALWAYS_INLINE_ uint32_t _atomic_conditional_increment_impl(register uint32_t *pw){
+_ALWAYS_INLINE_ uint32_t _atomic_conditional_increment_impl(volatile uint32_t *pw){
ATOMIC_CONDITIONAL_INCREMENT_BODY(pw, LONG, InterlockedCompareExchange, uint32_t)
}
-_ALWAYS_INLINE_ uint32_t _atomic_decrement_impl(register uint32_t *pw) {
+_ALWAYS_INLINE_ uint32_t _atomic_decrement_impl(volatile uint32_t *pw) {
return InterlockedDecrement((LONG volatile *)pw);
}
-_ALWAYS_INLINE_ uint32_t _atomic_increment_impl(register uint32_t *pw) {
+_ALWAYS_INLINE_ uint32_t _atomic_increment_impl(volatile uint32_t *pw) {
return InterlockedIncrement((LONG volatile *)pw);
}
-_ALWAYS_INLINE_ uint32_t _atomic_sub_impl(register uint32_t *pw, register uint32_t val) {
+_ALWAYS_INLINE_ uint32_t _atomic_sub_impl(volatile uint32_t *pw, volatile uint32_t val) {
return InterlockedExchangeAdd((LONG volatile *)pw, -(int32_t)val) - val;
}
-_ALWAYS_INLINE_ uint32_t _atomic_add_impl(register uint32_t *pw, register uint32_t val) {
+_ALWAYS_INLINE_ uint32_t _atomic_add_impl(volatile uint32_t *pw, volatile uint32_t val) {
return InterlockedAdd((LONG volatile *)pw, val);
}
-_ALWAYS_INLINE_ uint32_t _atomic_exchange_if_greater_impl(register uint32_t *pw, register uint32_t val){
+_ALWAYS_INLINE_ uint32_t _atomic_exchange_if_greater_impl(volatile uint32_t *pw, volatile uint32_t val){
ATOMIC_EXCHANGE_IF_GREATER_BODY(pw, val, LONG, InterlockedCompareExchange, uint32_t)
}
-_ALWAYS_INLINE_ uint64_t _atomic_conditional_increment_impl(register uint64_t *pw){
+_ALWAYS_INLINE_ uint64_t _atomic_conditional_increment_impl(volatile uint64_t *pw){
ATOMIC_CONDITIONAL_INCREMENT_BODY(pw, LONGLONG, InterlockedCompareExchange64, uint64_t)
}
-_ALWAYS_INLINE_ uint64_t _atomic_decrement_impl(register uint64_t *pw) {
+_ALWAYS_INLINE_ uint64_t _atomic_decrement_impl(volatile uint64_t *pw) {
return InterlockedDecrement64((LONGLONG volatile *)pw);
}
-_ALWAYS_INLINE_ uint64_t _atomic_increment_impl(register uint64_t *pw) {
+_ALWAYS_INLINE_ uint64_t _atomic_increment_impl(volatile uint64_t *pw) {
return InterlockedIncrement64((LONGLONG volatile *)pw);
}
-_ALWAYS_INLINE_ uint64_t _atomic_sub_impl(register uint64_t *pw, register uint64_t val) {
+_ALWAYS_INLINE_ uint64_t _atomic_sub_impl(volatile uint64_t *pw, volatile uint64_t val) {
return InterlockedExchangeAdd64((LONGLONG volatile *)pw, -(int64_t)val) - val;
}
-_ALWAYS_INLINE_ uint64_t _atomic_add_impl(register uint64_t *pw, register uint64_t val) {
+_ALWAYS_INLINE_ uint64_t _atomic_add_impl(volatile uint64_t *pw, volatile uint64_t val) {
return InterlockedAdd64((LONGLONG volatile *)pw, val);
}
-_ALWAYS_INLINE_ uint64_t _atomic_exchange_if_greater_impl(register uint64_t *pw, register uint64_t val){
+_ALWAYS_INLINE_ uint64_t _atomic_exchange_if_greater_impl(volatile uint64_t *pw, volatile uint64_t val){
ATOMIC_EXCHANGE_IF_GREATER_BODY(pw, val, LONGLONG, InterlockedCompareExchange64, uint64_t)
}
// The actual advertised functions; they'll call the right implementation
-uint32_t atomic_conditional_increment(register uint32_t *pw) {
+uint32_t atomic_conditional_increment(volatile uint32_t *pw) {
return _atomic_conditional_increment_impl(pw);
}
-uint32_t atomic_decrement(register uint32_t *pw) {
+uint32_t atomic_decrement(volatile uint32_t *pw) {
return _atomic_decrement_impl(pw);
}
-uint32_t atomic_increment(register uint32_t *pw) {
+uint32_t atomic_increment(volatile uint32_t *pw) {
return _atomic_increment_impl(pw);
}
-uint32_t atomic_sub(register uint32_t *pw, register uint32_t val) {
+uint32_t atomic_sub(volatile uint32_t *pw, volatile uint32_t val) {
return _atomic_sub_impl(pw, val);
}
-uint32_t atomic_add(register uint32_t *pw, register uint32_t val) {
+uint32_t atomic_add(volatile uint32_t *pw, volatile uint32_t val) {
return _atomic_add_impl(pw, val);
}
-uint32_t atomic_exchange_if_greater(register uint32_t *pw, register uint32_t val) {
+uint32_t atomic_exchange_if_greater(volatile uint32_t *pw, volatile uint32_t val) {
return _atomic_exchange_if_greater_impl(pw, val);
}
-uint64_t atomic_conditional_increment(register uint64_t *pw) {
+uint64_t atomic_conditional_increment(volatile uint64_t *pw) {
return _atomic_conditional_increment_impl(pw);
}
-uint64_t atomic_decrement(register uint64_t *pw) {
+uint64_t atomic_decrement(volatile uint64_t *pw) {
return _atomic_decrement_impl(pw);
}
-uint64_t atomic_increment(register uint64_t *pw) {
+uint64_t atomic_increment(volatile uint64_t *pw) {
return _atomic_increment_impl(pw);
}
-uint64_t atomic_sub(register uint64_t *pw, register uint64_t val) {
+uint64_t atomic_sub(volatile uint64_t *pw, volatile uint64_t val) {
return _atomic_sub_impl(pw, val);
}
-uint64_t atomic_add(register uint64_t *pw, register uint64_t val) {
+uint64_t atomic_add(volatile uint64_t *pw, volatile uint64_t val) {
return _atomic_add_impl(pw, val);
}
-uint64_t atomic_exchange_if_greater(register uint64_t *pw, register uint64_t val) {
+uint64_t atomic_exchange_if_greater(volatile uint64_t *pw, volatile uint64_t val) {
return _atomic_exchange_if_greater_impl(pw, val);
}
#endif
diff --git a/core/safe_refcount.h b/core/safe_refcount.h
index eff209c2db..36bcf5e576 100644
--- a/core/safe_refcount.h
+++ b/core/safe_refcount.h
@@ -44,7 +44,7 @@
/* Bogus implementation unaware of multiprocessing */
template <class T>
-static _ALWAYS_INLINE_ T atomic_conditional_increment(register T *pw) {
+static _ALWAYS_INLINE_ T atomic_conditional_increment(volatile T *pw) {
if (*pw == 0)
return 0;
@@ -55,7 +55,7 @@ static _ALWAYS_INLINE_ T atomic_conditional_increment(register T *pw) {
}
template <class T>
-static _ALWAYS_INLINE_ T atomic_decrement(register T *pw) {
+static _ALWAYS_INLINE_ T atomic_decrement(volatile T *pw) {
(*pw)--;
@@ -63,7 +63,7 @@ static _ALWAYS_INLINE_ T atomic_decrement(register T *pw) {
}
template <class T>
-static _ALWAYS_INLINE_ T atomic_increment(register T *pw) {
+static _ALWAYS_INLINE_ T atomic_increment(volatile T *pw) {
(*pw)++;
@@ -71,7 +71,7 @@ static _ALWAYS_INLINE_ T atomic_increment(register T *pw) {
}
template <class T, class V>
-static _ALWAYS_INLINE_ T atomic_sub(register T *pw, register V val) {
+static _ALWAYS_INLINE_ T atomic_sub(volatile T *pw, volatile V val) {
(*pw) -= val;
@@ -79,7 +79,7 @@ static _ALWAYS_INLINE_ T atomic_sub(register T *pw, register V val) {
}
template <class T, class V>
-static _ALWAYS_INLINE_ T atomic_add(register T *pw, register V val) {
+static _ALWAYS_INLINE_ T atomic_add(volatile T *pw, volatile V val) {
(*pw) += val;
@@ -87,7 +87,7 @@ static _ALWAYS_INLINE_ T atomic_add(register T *pw, register V val) {
}
template <class T, class V>
-static _ALWAYS_INLINE_ T atomic_exchange_if_greater(register T *pw, register V val) {
+static _ALWAYS_INLINE_ T atomic_exchange_if_greater(volatile T *pw, volatile V val) {
if (val > *pw)
*pw = val;
@@ -103,7 +103,7 @@ static _ALWAYS_INLINE_ T atomic_exchange_if_greater(register T *pw, register V v
// Clang states it supports GCC atomic builtins.
template <class T>
-static _ALWAYS_INLINE_ T atomic_conditional_increment(register T *pw) {
+static _ALWAYS_INLINE_ T atomic_conditional_increment(volatile T *pw) {
while (true) {
T tmp = static_cast<T const volatile &>(*pw);
@@ -115,31 +115,31 @@ static _ALWAYS_INLINE_ T atomic_conditional_increment(register T *pw) {
}
template <class T>
-static _ALWAYS_INLINE_ T atomic_decrement(register T *pw) {
+static _ALWAYS_INLINE_ T atomic_decrement(volatile T *pw) {
return __sync_sub_and_fetch(pw, 1);
}
template <class T>
-static _ALWAYS_INLINE_ T atomic_increment(register T *pw) {
+static _ALWAYS_INLINE_ T atomic_increment(volatile T *pw) {
return __sync_add_and_fetch(pw, 1);
}
template <class T, class V>
-static _ALWAYS_INLINE_ T atomic_sub(register T *pw, register V val) {
+static _ALWAYS_INLINE_ T atomic_sub(volatile T *pw, volatile V val) {
return __sync_sub_and_fetch(pw, val);
}
template <class T, class V>
-static _ALWAYS_INLINE_ T atomic_add(register T *pw, register V val) {
+static _ALWAYS_INLINE_ T atomic_add(volatile T *pw, volatile V val) {
return __sync_add_and_fetch(pw, val);
}
template <class T, class V>
-static _ALWAYS_INLINE_ T atomic_exchange_if_greater(register T *pw, register V val) {
+static _ALWAYS_INLINE_ T atomic_exchange_if_greater(volatile T *pw, volatile V val) {
while (true) {
T tmp = static_cast<T const volatile &>(*pw);
@@ -153,19 +153,19 @@ static _ALWAYS_INLINE_ T atomic_exchange_if_greater(register T *pw, register V v
#elif defined(_MSC_VER)
// For MSVC use a separate compilation unit to prevent windows.h from polluting
// the global namespace.
-uint32_t atomic_conditional_increment(register uint32_t *pw);
-uint32_t atomic_decrement(register uint32_t *pw);
-uint32_t atomic_increment(register uint32_t *pw);
-uint32_t atomic_sub(register uint32_t *pw, register uint32_t val);
-uint32_t atomic_add(register uint32_t *pw, register uint32_t val);
-uint32_t atomic_exchange_if_greater(register uint32_t *pw, register uint32_t val);
-
-uint64_t atomic_conditional_increment(register uint64_t *pw);
-uint64_t atomic_decrement(register uint64_t *pw);
-uint64_t atomic_increment(register uint64_t *pw);
-uint64_t atomic_sub(register uint64_t *pw, register uint64_t val);
-uint64_t atomic_add(register uint64_t *pw, register uint64_t val);
-uint64_t atomic_exchange_if_greater(register uint64_t *pw, register uint64_t val);
+uint32_t atomic_conditional_increment(volatile uint32_t *pw);
+uint32_t atomic_decrement(volatile uint32_t *pw);
+uint32_t atomic_increment(volatile uint32_t *pw);
+uint32_t atomic_sub(volatile uint32_t *pw, volatile uint32_t val);
+uint32_t atomic_add(volatile uint32_t *pw, volatile uint32_t val);
+uint32_t atomic_exchange_if_greater(volatile uint32_t *pw, volatile uint32_t val);
+
+uint64_t atomic_conditional_increment(volatile uint64_t *pw);
+uint64_t atomic_decrement(volatile uint64_t *pw);
+uint64_t atomic_increment(volatile uint64_t *pw);
+uint64_t atomic_sub(volatile uint64_t *pw, volatile uint64_t val);
+uint64_t atomic_add(volatile uint64_t *pw, volatile uint64_t val);
+uint64_t atomic_exchange_if_greater(volatile uint64_t *pw, volatile uint64_t val);
#else
//no threads supported?
diff --git a/core/script_debugger_remote.cpp b/core/script_debugger_remote.cpp
index 0473e2cc71..3955f222f9 100644
--- a/core/script_debugger_remote.cpp
+++ b/core/script_debugger_remote.cpp
@@ -169,6 +169,10 @@ void ScriptDebuggerRemote::debug(ScriptLanguage *p_script, bool p_can_continue)
ERR_FAIL();
}
+ if (allow_focus_steal_pid) {
+ OS::get_singleton()->enable_for_stealing_focus(allow_focus_steal_pid);
+ }
+
packet_peer_stream->put_var("debug_enter");
packet_peer_stream->put_var(2);
packet_peer_stream->put_var(p_can_continue);
@@ -1070,6 +1074,10 @@ void ScriptDebuggerRemote::profiling_set_frame_times(float p_frame_time, float p
physics_frame_time = p_physics_frame_time;
}
+void ScriptDebuggerRemote::set_allow_focus_steal_pid(OS::ProcessID p_pid) {
+ allow_focus_steal_pid = p_pid;
+}
+
ScriptDebuggerRemote::ResourceUsageFunc ScriptDebuggerRemote::resource_usage_func = NULL;
ScriptDebuggerRemote::ScriptDebuggerRemote() :
@@ -1091,6 +1099,7 @@ ScriptDebuggerRemote::ScriptDebuggerRemote() :
n_errors_dropped(0),
last_msec(0),
msec_count(0),
+ allow_focus_steal_pid(0),
locking(false),
poll_every(0),
request_scene_tree(NULL),
diff --git a/core/script_debugger_remote.h b/core/script_debugger_remote.h
index cc12d978d6..b68fc4f9c9 100644
--- a/core/script_debugger_remote.h
+++ b/core/script_debugger_remote.h
@@ -34,6 +34,7 @@
#include "io/packet_peer.h"
#include "io/stream_peer_tcp.h"
#include "list.h"
+#include "os/os.h"
#include "script_language.h"
class ScriptDebuggerRemote : public ScriptDebugger {
@@ -98,6 +99,8 @@ class ScriptDebuggerRemote : public ScriptDebugger {
uint64_t last_msec;
uint64_t msec_count;
+ OS::ProcessID allow_focus_steal_pid;
+
bool locking; //hack to avoid a deadloop
static void _print_handler(void *p_this, const String &p_string, bool p_error);
@@ -171,6 +174,8 @@ public:
virtual void profiling_end();
virtual void profiling_set_frame_times(float p_frame_time, float p_idle_time, float p_physics_time, float p_physics_frame_time);
+ void set_allow_focus_steal_pid(OS::ProcessID p_pid);
+
ScriptDebuggerRemote();
~ScriptDebuggerRemote();
};
diff --git a/core/script_language.cpp b/core/script_language.cpp
index 1dab58e29e..37ba3cfc62 100644
--- a/core/script_language.cpp
+++ b/core/script_language.cpp
@@ -29,6 +29,7 @@
/*************************************************************************/
#include "script_language.h"
+#include "project_settings.h"
ScriptLanguage *ScriptServer::_languages[MAX_LANGUAGES];
int ScriptServer::_language_count = 0;
@@ -103,6 +104,20 @@ void ScriptServer::unregister_language(ScriptLanguage *p_language) {
void ScriptServer::init_languages() {
+ { //load global classes
+ global_classes_clear();
+ if (ProjectSettings::get_singleton()->has_setting("_global_script_classes")) {
+ Array script_classes = ProjectSettings::get_singleton()->get("_global_script_classes");
+
+ for (int i = 0; i < script_classes.size(); i++) {
+ Dictionary c = script_classes[i];
+ if (!c.has("class") || !c.has("language") || !c.has("path") || !c.has("base"))
+ continue;
+ add_global_class(c["class"], c["base"], c["language"], c["path"]);
+ }
+ }
+ }
+
for (int i = 0; i < _language_count; i++) {
_languages[i]->init();
}
@@ -113,6 +128,7 @@ void ScriptServer::finish_languages() {
for (int i = 0; i < _language_count; i++) {
_languages[i]->finish();
}
+ global_classes_clear();
}
void ScriptServer::set_reload_scripts_on_save(bool p_enable) {
@@ -139,6 +155,67 @@ void ScriptServer::thread_exit() {
}
}
+HashMap<StringName, ScriptServer::GlobalScriptClass> ScriptServer::global_classes;
+
+void ScriptServer::global_classes_clear() {
+ global_classes.clear();
+}
+
+void ScriptServer::add_global_class(const StringName &p_class, const StringName &p_base, const StringName &p_language, const String &p_path) {
+ GlobalScriptClass g;
+ g.language = p_language;
+ g.path = p_path;
+ g.base = p_base;
+ global_classes[p_class] = g;
+}
+void ScriptServer::remove_global_class(const StringName &p_class) {
+ global_classes.erase(p_class);
+}
+bool ScriptServer::is_global_class(const StringName &p_class) {
+ return global_classes.has(p_class);
+}
+StringName ScriptServer::get_global_class_language(const StringName &p_class) {
+ ERR_FAIL_COND_V(!global_classes.has(p_class), StringName());
+ return global_classes[p_class].language;
+}
+String ScriptServer::get_global_class_path(const String &p_class) {
+ ERR_FAIL_COND_V(!global_classes.has(p_class), String());
+ return global_classes[p_class].path;
+}
+
+StringName ScriptServer::get_global_class_base(const String &p_class) {
+ ERR_FAIL_COND_V(!global_classes.has(p_class), String());
+ return global_classes[p_class].base;
+}
+void ScriptServer::get_global_class_list(List<StringName> *r_global_classes) {
+ const StringName *K = NULL;
+ List<StringName> classes;
+ while ((K = global_classes.next(K))) {
+ classes.push_back(*K);
+ }
+ classes.sort_custom<StringName::AlphCompare>();
+ for (List<StringName>::Element *E = classes.front(); E; E = E->next()) {
+ r_global_classes->push_back(E->get());
+ }
+}
+void ScriptServer::save_global_classes() {
+ List<StringName> gc;
+ get_global_class_list(&gc);
+ Array gcarr;
+ for (List<StringName>::Element *E = gc.front(); E; E = E->next()) {
+ Dictionary d;
+ d["class"] = E->get();
+ d["language"] = global_classes[E->get()].language;
+ d["path"] = global_classes[E->get()].path;
+ d["base"] = global_classes[E->get()].base;
+ gcarr.push_back(d);
+ }
+
+ ProjectSettings::get_singleton()->set("_global_script_classes", gcarr);
+ ProjectSettings::get_singleton()->save();
+}
+
+////////////////////
void ScriptInstance::get_property_state(List<Pair<StringName, Variant> > &state) {
List<PropertyInfo> pinfo;
@@ -347,6 +424,20 @@ Variant::Type PlaceHolderScriptInstance::get_property_type(const StringName &p_n
return Variant::NIL;
}
+void PlaceHolderScriptInstance::get_method_list(List<MethodInfo> *p_list) const {
+
+ if (script.is_valid()) {
+ script->get_script_method_list(p_list);
+ }
+}
+bool PlaceHolderScriptInstance::has_method(const StringName &p_method) const {
+
+ if (script.is_valid()) {
+ return script->has_method(p_method);
+ }
+ return false;
+}
+
void PlaceHolderScriptInstance::update(const List<PropertyInfo> &p_properties, const Map<StringName, Variant> &p_values) {
Set<StringName> new_values;
diff --git a/core/script_language.h b/core/script_language.h
index ad66fc5528..4e81b9b626 100644
--- a/core/script_language.h
+++ b/core/script_language.h
@@ -54,6 +54,14 @@ class ScriptServer {
static bool scripting_enabled;
static bool reload_scripts_on_save;
+ struct GlobalScriptClass {
+ StringName language;
+ String path;
+ String base;
+ };
+
+ static HashMap<StringName, GlobalScriptClass> global_classes;
+
public:
static ScriptEditRequestFunction edit_request_func;
@@ -70,6 +78,16 @@ public:
static void thread_enter();
static void thread_exit();
+ static void global_classes_clear();
+ static void add_global_class(const StringName &p_class, const StringName &p_base, const StringName &p_language, const String &p_path);
+ static void remove_global_class(const StringName &p_class);
+ static bool is_global_class(const StringName &p_class);
+ static StringName get_global_class_language(const StringName &p_class);
+ static String get_global_class_path(const String &p_class);
+ static StringName get_global_class_base(const String &p_class);
+ static void get_global_class_list(List<StringName> *r_global_classes);
+ static void save_global_classes();
+
static void init_languages();
static void finish_languages();
};
@@ -195,7 +213,7 @@ public:
virtual Ref<Script> get_template(const String &p_class_name, const String &p_base_class_name) const = 0;
virtual void make_template(const String &p_class_name, const String &p_base_class_name, Ref<Script> &p_script) {}
virtual bool is_using_templates() { return false; }
- virtual bool validate(const String &p_script, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path = "", List<String> *r_functions = NULL) const = 0;
+ virtual bool validate(const String &p_script, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path = "", List<String> *r_functions = NULL, Set<int> *r_safe_lines = NULL) const = 0;
virtual String validate_path(const String &p_path) const { return ""; }
virtual Script *create_script() const = 0;
virtual bool has_named_classes() const = 0;
@@ -285,7 +303,10 @@ public:
virtual void frame();
- virtual ~ScriptLanguage(){};
+ virtual bool handles_global_class_type(const String &p_type) const { return false; }
+ virtual String get_global_class_name(const String &p_path, String *r_base_type = NULL) const { return String(); }
+
+ virtual ~ScriptLanguage() {}
};
extern uint8_t script_encryption_key[32];
@@ -304,8 +325,8 @@ public:
virtual void get_property_list(List<PropertyInfo> *p_properties) const;
virtual Variant::Type get_property_type(const StringName &p_name, bool *r_is_valid = NULL) const;
- virtual void get_method_list(List<MethodInfo> *p_list) const {}
- virtual bool has_method(const StringName &p_method) const { return false; }
+ virtual void get_method_list(List<MethodInfo> *p_list) const;
+ virtual bool has_method(const StringName &p_method) const;
virtual Variant call(const StringName &p_method, VARIANT_ARG_LIST) { return Variant(); }
virtual Variant call(const StringName &p_method, const Variant **p_args, int p_argcount, Variant::CallError &r_error) {
r_error.error = Variant::CallError::CALL_ERROR_INVALID_METHOD;
diff --git a/core/string_db.h b/core/string_db.h
index 01d1ca4033..965385b136 100644
--- a/core/string_db.h
+++ b/core/string_db.h
@@ -31,7 +31,6 @@
#ifndef STRING_DB_H
#define STRING_DB_H
-#include "hash_map.h"
#include "os/mutex.h"
#include "safe_refcount.h"
#include "ustring.h"
@@ -168,11 +167,6 @@ public:
~StringName();
};
-struct StringNameHasher {
-
- static _FORCE_INLINE_ uint32_t hash(const StringName &p_string) { return p_string.hash(); }
-};
-
StringName _scs_create(const char *p_chr);
#endif
diff --git a/core/translation.cpp b/core/translation.cpp
index aaa4de5912..78115c3749 100644
--- a/core/translation.cpp
+++ b/core/translation.cpp
@@ -1171,13 +1171,11 @@ void TranslationServer::_bind_methods() {
void TranslationServer::load_translations() {
String locale = get_locale();
- bool found = _load_translations("locale/translations"); //all
+ _load_translations("locale/translations"); //all
+ _load_translations("locale/translations_" + locale.substr(0, 2));
- if (_load_translations("locale/translations_" + locale.substr(0, 2)))
- found = true;
if (locale.substr(0, 2) != locale) {
- if (_load_translations("locale/translations_" + locale))
- found = true;
+ _load_translations("locale/translations_" + locale);
}
}
diff --git a/core/type_info.h b/core/type_info.h
index c1af4fac69..bf497f1e5f 100644
--- a/core/type_info.h
+++ b/core/type_info.h
@@ -194,6 +194,7 @@ MAKE_TEMPLATE_TYPE_INFO(Vector, Color, Variant::POOL_COLOR_ARRAY)
MAKE_TEMPLATE_TYPE_INFO(Vector, Variant, Variant::ARRAY)
MAKE_TEMPLATE_TYPE_INFO(Vector, RID, Variant::ARRAY)
MAKE_TEMPLATE_TYPE_INFO(Vector, Plane, Variant::ARRAY)
+MAKE_TEMPLATE_TYPE_INFO(Vector, StringName, Variant::POOL_STRING_ARRAY)
MAKE_TEMPLATE_TYPE_INFO(PoolVector, Plane, Variant::ARRAY)
MAKE_TEMPLATE_TYPE_INFO(PoolVector, Face3, Variant::POOL_VECTOR3_ARRAY)
diff --git a/core/typedefs.h b/core/typedefs.h
index 4758a5408d..71771ea4e6 100644
--- a/core/typedefs.h
+++ b/core/typedefs.h
@@ -74,7 +74,7 @@ T *_nullptr() {
#define OFFSET_OF(st, m) \
((size_t)((char *)&(_nullptr<st>()->m) - (char *)0))
- /**
+/**
* Some platforms (devices) not define NULL
*/
@@ -82,7 +82,7 @@ T *_nullptr() {
#define NULL 0
#endif
- /**
+/**
* Windows defines a lot of badly stuff we'll never ever use. undefine it.
*/
@@ -97,6 +97,7 @@ T *_nullptr() {
#undef CLAMP // override standard definition
#undef Error
#undef OK
+#undef CONNECT_DEFERRED // override from Windows SDK, clashes with Object enum
#endif
#include "int_types.h"
@@ -104,7 +105,7 @@ T *_nullptr() {
#include "error_list.h"
#include "error_macros.h"
- /** Generic ABS function, for math uses please use Math::abs */
+/** Generic ABS function, for math uses please use Math::abs */
#ifndef ABS
#define ABS(m_v) ((m_v < 0) ? (-(m_v)) : (m_v))
diff --git a/core/undo_redo.cpp b/core/undo_redo.cpp
index b3f9dd818d..b9a2fdd0ac 100644
--- a/core/undo_redo.cpp
+++ b/core/undo_redo.cpp
@@ -299,26 +299,30 @@ void UndoRedo::_process_operation_list(List<Operation>::Element *E) {
}
}
-void UndoRedo::redo() {
+bool UndoRedo::redo() {
- ERR_FAIL_COND(action_level > 0);
+ ERR_FAIL_COND_V(action_level > 0, false);
if ((current_action + 1) >= actions.size())
- return; //nothing to redo
+ return false; //nothing to redo
current_action++;
_process_operation_list(actions[current_action].do_ops.front());
version++;
+
+ return true;
}
-void UndoRedo::undo() {
+bool UndoRedo::undo() {
- ERR_FAIL_COND(action_level > 0);
+ ERR_FAIL_COND_V(action_level > 0, false);
if (current_action < 0)
- return; //nothing to redo
+ return false; //nothing to redo
_process_operation_list(actions[current_action].undo_ops.front());
current_action--;
version--;
+
+ return true;
}
void UndoRedo::clear_history() {
diff --git a/core/undo_redo.h b/core/undo_redo.h
index a373296b73..3a17c78851 100644
--- a/core/undo_redo.h
+++ b/core/undo_redo.h
@@ -109,8 +109,8 @@ public:
void commit_action();
- void redo();
- void undo();
+ bool redo();
+ bool undo();
String get_current_action_name() const;
void clear_history();
diff --git a/core/ustring.cpp b/core/ustring.cpp
index 51f05468e2..bb08dd13c4 100644
--- a/core/ustring.cpp
+++ b/core/ustring.cpp
@@ -757,36 +757,32 @@ Vector<String> String::rsplit(const String &p_splitter, bool p_allow_empty, int
Vector<String> ret;
const int len = length();
- int from = len;
+ int remaining_len = len;
while (true) {
- int end = rfind(p_splitter, from);
- if (end < 0)
- end = 0;
-
- if (p_allow_empty || (end < from)) {
- const String str = substr(end > 0 ? end + p_splitter.length() : end, end > 0 ? from - end : from + 2);
-
- if (p_maxsplit <= 0) {
- ret.push_back(str);
- } else if (p_maxsplit > 0) {
-
- // Put rest of the string and leave cycle.
- if (p_maxsplit == ret.size()) {
- ret.push_back(substr(0, from + 2));
- break;
- }
-
- // Otherwise, push items until positive limit is reached.
- ret.push_back(str);
+ if (remaining_len < p_splitter.length() || (p_maxsplit > 0 && p_maxsplit == ret.size())) {
+ // no room for another splitter or hit max splits, push what's left and we're done
+ if (p_allow_empty || remaining_len > 0) {
+ ret.push_back(substr(0, remaining_len));
}
+ break;
}
- if (end == 0)
+ int left_edge = rfind(p_splitter, remaining_len - p_splitter.length());
+
+ if (left_edge < 0) {
+ // no more splitters, we're done
+ ret.push_back(substr(0, remaining_len));
break;
+ }
+
+ int substr_start = left_edge + p_splitter.length();
+ if (p_allow_empty || substr_start < remaining_len) {
+ ret.push_back(substr(substr_start, remaining_len - substr_start));
+ }
- from = end - p_splitter.length();
+ remaining_len = left_edge;
}
ret.invert();
@@ -925,8 +921,8 @@ String String::to_upper() const {
for (int i = 0; i < upper.size(); i++) {
- const char s = upper[i];
- const char t = _find_upper(s);
+ const CharType s = upper[i];
+ const CharType t = _find_upper(s);
if (s != t) // avoid copy on write
upper[i] = t;
}
@@ -940,8 +936,8 @@ String String::to_lower() const {
for (int i = 0; i < lower.size(); i++) {
- const char s = lower[i];
- const char t = _find_lower(s);
+ const CharType s = lower[i];
+ const CharType t = _find_lower(s);
if (s != t) // avoid copy on write
lower[i] = t;
}
diff --git a/core/variant.cpp b/core/variant.cpp
index a6df95e310..c48aa57652 100644
--- a/core/variant.cpp
+++ b/core/variant.cpp
@@ -2012,6 +2012,19 @@ Variant::operator Vector<String>() const {
}
return to;
}
+Variant::operator Vector<StringName>() const {
+
+ PoolVector<String> from = operator PoolVector<String>();
+ Vector<StringName> to;
+ int len = from.size();
+ to.resize(len);
+ for (int i = 0; i < len; i++) {
+
+ to[i] = from[i];
+ }
+ return to;
+}
+
Variant::operator Vector<Vector3>() const {
PoolVector<Vector3> from = operator PoolVector<Vector3>();
@@ -2444,6 +2457,17 @@ Variant::Variant(const Vector<String> &p_array) {
*this = v;
}
+Variant::Variant(const Vector<StringName> &p_array) {
+
+ type = NIL;
+ PoolVector<String> v;
+ int len = p_array.size();
+ v.resize(len);
+ for (int i = 0; i < len; i++)
+ v.set(i, p_array[i]);
+ *this = v;
+}
+
Variant::Variant(const Vector<Vector3> &p_array) {
type = NIL;
diff --git a/core/variant.h b/core/variant.h
index f227e4bfdb..4b245d25e6 100644
--- a/core/variant.h
+++ b/core/variant.h
@@ -216,6 +216,7 @@ public:
operator Vector<int>() const;
operator Vector<real_t>() const;
operator Vector<String>() const;
+ operator Vector<StringName>() const;
operator Vector<Vector3>() const;
operator Vector<Color>() const;
operator Vector<RID>() const;
@@ -280,6 +281,7 @@ public:
Variant(const Vector<int> &p_int_array);
Variant(const Vector<real_t> &p_real_array);
Variant(const Vector<String> &p_string_array);
+ Variant(const Vector<StringName> &p_string_array);
Variant(const Vector<Vector3> &p_vector3_array);
Variant(const Vector<Color> &p_color_array);
Variant(const Vector<Plane> &p_array); // helper
diff --git a/core/variant_op.cpp b/core/variant_op.cpp
index 621af2dfb7..bfa69b1fde 100644
--- a/core/variant_op.cpp
+++ b/core/variant_op.cpp
@@ -3417,8 +3417,17 @@ Variant Variant::iter_get(const Variant &r_iter, bool &r_valid) const {
Variant Variant::duplicate(bool deep) const {
switch (type) {
- // case OBJECT:
- // return operator Object *()->duplicate();
+ case OBJECT: {
+ /* breaks stuff :(
+ if (deep && !_get_obj().ref.is_null()) {
+ Ref<Resource> resource = _get_obj().ref;
+ if (resource.is_valid()) {
+ return resource->duplicate(true);
+ }
+ }
+ */
+ return *this;
+ } break;
case DICTIONARY:
return operator Dictionary().duplicate(deep);
case ARRAY:
diff --git a/core/vector.h b/core/vector.h
index f586471e27..c026448ddd 100644
--- a/core/vector.h
+++ b/core/vector.h
@@ -152,6 +152,8 @@ public:
Error insert(int p_pos, const T &p_val);
+ void append_array(const Vector<T> &p_other);
+
template <class C>
void sort_custom() {
@@ -408,6 +410,17 @@ Error Vector<T>::insert(int p_pos, const T &p_val) {
}
template <class T>
+void Vector<T>::append_array(const Vector<T> &p_other) {
+ const int ds = p_other.size();
+ if (ds == 0)
+ return;
+ const int bs = size();
+ resize(bs + ds);
+ for (int i = 0; i < ds; ++i)
+ operator[](bs + i) = p_other[i];
+}
+
+template <class T>
Vector<T>::Vector(const Vector &p_from) {
_ptr = NULL;