summaryrefslogtreecommitdiff
path: root/core
diff options
context:
space:
mode:
Diffstat (limited to 'core')
-rw-r--r--core/io/logger.h12
-rw-r--r--core/io/packet_peer.cpp2
-rw-r--r--core/io/resource_format_binary.cpp2
-rw-r--r--core/io/resource_importer.cpp52
-rw-r--r--core/io/resource_importer.h18
-rw-r--r--core/math/basis.cpp68
-rw-r--r--core/math/math_defs.h9
-rw-r--r--core/math/math_funcs.h20
-rw-r--r--core/math/quat.cpp2
-rw-r--r--core/math/vector2.cpp2
-rw-r--r--core/math/vector3.h2
-rw-r--r--core/os/os.cpp11
-rw-r--r--core/os/os.h8
-rw-r--r--core/script_debugger_remote.cpp1
-rw-r--r--core/typedefs.h8
-rw-r--r--core/undo_redo.cpp32
16 files changed, 188 insertions, 61 deletions
diff --git a/core/io/logger.h b/core/io/logger.h
index 0b871a13de..ff5b8ce489 100644
--- a/core/io/logger.h
+++ b/core/io/logger.h
@@ -49,11 +49,11 @@ public:
ERR_SHADER
};
- virtual void logv(const char *p_format, va_list p_list, bool p_err) = 0;
+ virtual void logv(const char *p_format, va_list p_list, bool p_err) _PRINTF_FORMAT_ATTRIBUTE_2_0 = 0;
virtual void log_error(const char *p_function, const char *p_file, int p_line, const char *p_code, const char *p_rationale, ErrorType p_type = ERR_ERROR);
- void logf(const char *p_format, ...);
- void logf_error(const char *p_format, ...);
+ void logf(const char *p_format, ...) _PRINTF_FORMAT_ATTRIBUTE_2_3;
+ void logf_error(const char *p_format, ...) _PRINTF_FORMAT_ATTRIBUTE_2_3;
virtual ~Logger();
};
@@ -64,7 +64,7 @@ public:
class StdLogger : public Logger {
public:
- virtual void logv(const char *p_format, va_list p_list, bool p_err);
+ virtual void logv(const char *p_format, va_list p_list, bool p_err) _PRINTF_FORMAT_ATTRIBUTE_2_0;
virtual ~StdLogger();
};
@@ -88,7 +88,7 @@ class RotatedFileLogger : public Logger {
public:
RotatedFileLogger(const String &p_base_path, int p_max_files = 10);
- virtual void logv(const char *p_format, va_list p_list, bool p_err);
+ virtual void logv(const char *p_format, va_list p_list, bool p_err) _PRINTF_FORMAT_ATTRIBUTE_2_0;
virtual ~RotatedFileLogger();
};
@@ -99,7 +99,7 @@ class CompositeLogger : public Logger {
public:
CompositeLogger(Vector<Logger *> p_loggers);
- virtual void logv(const char *p_format, va_list p_list, bool p_err);
+ virtual void logv(const char *p_format, va_list p_list, bool p_err) _PRINTF_FORMAT_ATTRIBUTE_2_0;
virtual void log_error(const char *p_function, const char *p_file, int p_line, const char *p_code, const char *p_rationale, ErrorType p_type = ERR_ERROR);
void add_logger(Logger *p_logger);
diff --git a/core/io/packet_peer.cpp b/core/io/packet_peer.cpp
index 3aa1fcfd8f..d7bfdbbb37 100644
--- a/core/io/packet_peer.cpp
+++ b/core/io/packet_peer.cpp
@@ -224,7 +224,7 @@ Error PacketPeerStream::get_packet(const uint8_t **r_buffer, int &r_buffer_size)
uint32_t len = decode_uint32(lbuf);
ERR_FAIL_COND_V(remaining < (int)len, ERR_UNAVAILABLE);
- ERR_FAIL_COND_V(input_buffer.size() < len, ERR_UNAVAILABLE);
+ ERR_FAIL_COND_V(input_buffer.size() < (int)len, ERR_UNAVAILABLE);
ring_buffer.read(lbuf, 4); //get rid of first 4 bytes
ring_buffer.read(input_buffer.ptrw(), len); // read packet
diff --git a/core/io/resource_format_binary.cpp b/core/io/resource_format_binary.cpp
index 6c48942d72..42070cd132 100644
--- a/core/io/resource_format_binary.cpp
+++ b/core/io/resource_format_binary.cpp
@@ -106,7 +106,7 @@ StringName ResourceInteractiveLoaderBinary::_get_string() {
uint32_t id = f->get_32();
if (id & 0x80000000) {
uint32_t len = id & 0x7FFFFFFF;
- if (len > str_buf.size()) {
+ if ((int)len > str_buf.size()) {
str_buf.resize(len);
}
if (len == 0)
diff --git a/core/io/resource_importer.cpp b/core/io/resource_importer.cpp
index 9327e000f5..69907a710a 100644
--- a/core/io/resource_importer.cpp
+++ b/core/io/resource_importer.cpp
@@ -33,6 +33,10 @@
#include "core/os/os.h"
#include "core/variant_parser.h"
+bool ResourceFormatImporter::SortImporterByName::operator()(const Ref<ResourceImporter> &p_a, const Ref<ResourceImporter> &p_b) const {
+ return p_a->get_importer_name() < p_b->get_importer_name();
+}
+
Error ResourceFormatImporter::_get_path_and_type(const String &p_path, PathAndType &r_path_and_type, bool *r_valid) const {
Error err;
@@ -90,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 == "metadata") {
+ r_path_and_type.metadata = value;
} else if (assign == "valid") {
if (r_valid) {
*r_valid = value;
@@ -304,6 +310,18 @@ String ResourceFormatImporter::get_resource_type(const String &p_path) const {
return pat.type;
}
+Variant ResourceFormatImporter::get_resource_metadata(const String &p_path) const {
+ PathAndType pat;
+ Error err = _get_path_and_type(p_path, pat);
+
+ if (err != OK) {
+
+ return Variant();
+ }
+
+ return pat.metadata;
+}
+
void ResourceFormatImporter::get_dependencies(const String &p_path, List<String> *p_dependencies, bool p_add_types) {
PathAndType pat;
@@ -366,6 +384,40 @@ String ResourceFormatImporter::get_import_base_path(const String &p_for_file) co
return "res://.import/" + p_for_file.get_file() + "-" + p_for_file.md5_text();
}
+bool ResourceFormatImporter::are_import_settings_valid(const String &p_path) const {
+
+ bool valid = true;
+ PathAndType pat;
+ _get_path_and_type(p_path, pat, &valid);
+
+ if (!valid) {
+ return false;
+ }
+
+ for (int i = 0; i < importers.size(); i++) {
+ if (importers[i]->get_importer_name() == pat.importer) {
+ if (!importers[i]->are_import_settings_valid(p_path)) { //importer thinks this is not valid
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+String ResourceFormatImporter::get_import_settings_hash() const {
+
+ Vector<Ref<ResourceImporter> > sorted_importers = importers;
+
+ sorted_importers.sort_custom<SortImporterByName>();
+
+ String hash;
+ for (int i = 0; i < sorted_importers.size(); i++) {
+ hash += ":" + sorted_importers[i]->get_importer_name() + ":" + sorted_importers[i]->get_import_settings_string();
+ }
+ return hash.md5_text();
+}
+
ResourceFormatImporter *ResourceFormatImporter::singleton = NULL;
ResourceFormatImporter::ResourceFormatImporter() {
diff --git a/core/io/resource_importer.h b/core/io/resource_importer.h
index 32c39a8085..1d27d4dec3 100644
--- a/core/io/resource_importer.h
+++ b/core/io/resource_importer.h
@@ -43,12 +43,18 @@ class ResourceFormatImporter : public ResourceFormatLoader {
String path;
String type;
String importer;
+ Variant metadata;
};
Error _get_path_and_type(const String &p_path, PathAndType &r_path_and_type, bool *r_valid = NULL) const;
static ResourceFormatImporter *singleton;
+ //need them to stay in order to compute the settings hash
+ struct SortImporterByName {
+ bool operator()(const Ref<ResourceImporter> &p_a, const Ref<ResourceImporter> &p_b) const;
+ };
+
Vector<Ref<ResourceImporter> > importers;
public:
@@ -59,6 +65,7 @@ public:
virtual bool recognize_path(const String &p_path, const String &p_for_type = String()) const;
virtual bool handles_type(const String &p_type) const;
virtual String get_resource_type(const String &p_path) const;
+ virtual Variant get_resource_metadata(const String &p_path) const;
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);
@@ -68,12 +75,17 @@ public:
String get_internal_resource_path(const String &p_path) const;
void get_internal_resource_path_list(const String &p_path, List<String> *r_paths);
- void add_importer(const Ref<ResourceImporter> &p_importer) { importers.push_back(p_importer); }
+ void add_importer(const Ref<ResourceImporter> &p_importer) {
+ importers.push_back(p_importer);
+ }
void remove_importer(const Ref<ResourceImporter> &p_importer) { importers.erase(p_importer); }
Ref<ResourceImporter> get_importer_by_name(const String &p_name) const;
Ref<ResourceImporter> get_importer_by_extension(const String &p_extension) const;
void get_importers_for_extension(const String &p_extension, List<Ref<ResourceImporter> > *r_importers);
+ bool are_import_settings_valid(const String &p_path) const;
+ String get_import_settings_hash() const;
+
String get_import_base_path(const String &p_for_file) const;
ResourceFormatImporter();
};
@@ -107,7 +119,9 @@ 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 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) = 0;
+ 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 bool are_import_settings_valid(const String &p_path) const { return true; }
+ virtual String get_import_settings_string() const { return String(); }
};
#endif // RESOURCE_IMPORTER_H
diff --git a/core/math/basis.cpp b/core/math/basis.cpp
index 7f60b7962c..8816e3639a 100644
--- a/core/math/basis.cpp
+++ b/core/math/basis.cpp
@@ -76,9 +76,11 @@ void Basis::invert() {
}
void Basis::orthonormalize() {
+
#ifdef MATH_CHECKS
ERR_FAIL_COND(determinant() == 0);
#endif
+
// Gram-Schmidt Process
Vector3 x = get_axis(0);
@@ -118,16 +120,16 @@ bool Basis::is_diagonal() const {
}
bool Basis::is_rotation() const {
- return Math::is_equal_approx(determinant(), 1) && is_orthogonal();
+ return Math::is_equal_approx(determinant(), 1, UNIT_EPSILON) && is_orthogonal();
}
bool Basis::is_symmetric() const {
- if (!Math::is_equal_approx(elements[0][1], elements[1][0]))
+ if (!Math::is_equal_approx_ratio(elements[0][1], elements[1][0], UNIT_EPSILON))
return false;
- if (!Math::is_equal_approx(elements[0][2], elements[2][0]))
+ if (!Math::is_equal_approx_ratio(elements[0][2], elements[2][0], UNIT_EPSILON))
return false;
- if (!Math::is_equal_approx(elements[1][2], elements[2][1]))
+ if (!Math::is_equal_approx_ratio(elements[1][2], elements[2][1], UNIT_EPSILON))
return false;
return true;
@@ -488,6 +490,11 @@ void Basis::set_euler_xyz(const Vector3 &p_euler) {
// as the x, y, and z components of a Vector3 respectively.
Vector3 Basis::get_euler_yxz() const {
+ /* checking this is a bad idea, because obtaining from scaled transform is a valid use case
+#ifdef MATH_CHECKS
+ ERR_FAIL_COND(!is_rotation());
+#endif
+*/
// Euler angles in YXZ convention.
// See https://en.wikipedia.org/wiki/Euler_angles#Rotation_matrix
//
@@ -496,9 +503,7 @@ Vector3 Basis::get_euler_yxz() const {
// cy*sx*sz-cz*sy cy*cz*sx+sy*sz cy*cx
Vector3 euler;
-#ifdef MATH_CHECKS
- ERR_FAIL_COND_V(!is_rotation(), euler);
-#endif
+
real_t m12 = elements[1][2];
if (m12 < 1) {
@@ -556,7 +561,7 @@ bool Basis::is_equal_approx(const Basis &a, const Basis &b) const {
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
- if (!Math::is_equal_approx(a.elements[i][j], b.elements[i][j]))
+ if (!Math::is_equal_approx_ratio(a.elements[i][j], b.elements[i][j], UNIT_EPSILON))
return false;
}
}
@@ -599,10 +604,14 @@ Basis::operator String() const {
}
Quat Basis::get_quat() const {
-#ifdef MATH_CHECKS
- ERR_FAIL_COND_V(!is_rotation(), Quat());
-#endif
- real_t trace = elements[0][0] + elements[1][1] + elements[2][2];
+
+ /* Allow getting a quaternion from an unnormalized transform */
+ Basis m = *this;
+ m.elements[0].normalize();
+ m.elements[1].normalize();
+ m.elements[2].normalize();
+
+ real_t trace = m.elements[0][0] + m.elements[1][1] + m.elements[2][2];
real_t temp[4];
if (trace > 0.0) {
@@ -610,23 +619,23 @@ Quat Basis::get_quat() const {
temp[3] = (s * 0.5);
s = 0.5 / s;
- temp[0] = ((elements[2][1] - elements[1][2]) * s);
- temp[1] = ((elements[0][2] - elements[2][0]) * s);
- temp[2] = ((elements[1][0] - elements[0][1]) * s);
+ temp[0] = ((m.elements[2][1] - m.elements[1][2]) * s);
+ temp[1] = ((m.elements[0][2] - m.elements[2][0]) * s);
+ temp[2] = ((m.elements[1][0] - m.elements[0][1]) * s);
} else {
- int i = elements[0][0] < elements[1][1] ?
- (elements[1][1] < elements[2][2] ? 2 : 1) :
- (elements[0][0] < elements[2][2] ? 2 : 0);
+ int i = m.elements[0][0] < m.elements[1][1] ?
+ (m.elements[1][1] < m.elements[2][2] ? 2 : 1) :
+ (m.elements[0][0] < m.elements[2][2] ? 2 : 0);
int j = (i + 1) % 3;
int k = (i + 2) % 3;
- real_t s = Math::sqrt(elements[i][i] - elements[j][j] - elements[k][k] + 1.0);
+ real_t s = Math::sqrt(m.elements[i][i] - m.elements[j][j] - m.elements[k][k] + 1.0);
temp[i] = s * 0.5;
s = 0.5 / s;
- temp[3] = (elements[k][j] - elements[j][k]) * s;
- temp[j] = (elements[j][i] + elements[i][j]) * s;
- temp[k] = (elements[k][i] + elements[i][k]) * s;
+ temp[3] = (m.elements[k][j] - m.elements[j][k]) * s;
+ temp[j] = (m.elements[j][i] + m.elements[i][j]) * s;
+ temp[k] = (m.elements[k][i] + m.elements[i][k]) * s;
}
return Quat(temp[0], temp[1], temp[2], temp[3]);
@@ -696,9 +705,11 @@ void Basis::set_orthogonal_index(int p_index) {
}
void Basis::get_axis_angle(Vector3 &r_axis, real_t &r_angle) const {
+ /* checking this is a bad idea, because obtaining from scaled transform is a valid use case
#ifdef MATH_CHECKS
ERR_FAIL_COND(!is_rotation());
#endif
+*/
real_t angle, x, y, z; // variables for result
real_t epsilon = 0.01; // margin to allow for rounding errors
real_t epsilon2 = 0.1; // margin to distinguish between 0 and 180 degrees
@@ -835,14 +846,15 @@ void Basis::set_diagonal(const Vector3 p_diag) {
}
Basis Basis::slerp(const Basis &target, const real_t &t) const {
-// TODO: implement this directly without using quaternions to make it more efficient
-#ifdef MATH_CHECKS
- ERR_FAIL_COND_V(!is_rotation(), Basis());
- ERR_FAIL_COND_V(!target.is_rotation(), Basis());
-#endif
+ //consider scale
Quat from(*this);
Quat to(target);
- return Basis(from.slerp(to, t));
+ Basis b(from.slerp(to, t));
+ b.elements[0] *= Math::lerp(elements[0].length(), target.elements[0].length(), t);
+ b.elements[1] *= Math::lerp(elements[1].length(), target.elements[1].length(), t);
+ b.elements[2] *= Math::lerp(elements[2].length(), target.elements[2].length(), t);
+
+ return b;
}
diff --git a/core/math/math_defs.h b/core/math/math_defs.h
index 48533ba659..c54d3cc96f 100644
--- a/core/math/math_defs.h
+++ b/core/math/math_defs.h
@@ -33,6 +33,7 @@
#define CMP_EPSILON 0.00001
#define CMP_EPSILON2 (CMP_EPSILON * CMP_EPSILON)
+
#define CMP_NORMALIZE_TOLERANCE 0.000001
#define CMP_POINT_IN_PLANE_EPSILON 0.00001
@@ -49,6 +50,14 @@
#define MATH_CHECKS
#endif
+//this epsilon is for values related to a unit size (scalar or vector len)
+#ifdef PRECISE_MATH_CHECKS
+#define UNIT_EPSILON 0.00001
+#else
+//tolerate some more floating point error normally
+#define UNIT_EPSILON 0.001
+#endif
+
#define USEC_TO_SEC(m_usec) ((m_usec) / 1000000.0)
enum ClockDirection {
diff --git a/core/math/math_funcs.h b/core/math/math_funcs.h
index f8f5ddfeaa..17112d8940 100644
--- a/core/math/math_funcs.h
+++ b/core/math/math_funcs.h
@@ -217,8 +217,8 @@ public:
static _ALWAYS_INLINE_ double round(double p_val) { return (p_val >= 0) ? Math::floor(p_val + 0.5) : -Math::floor(-p_val + 0.5); }
static _ALWAYS_INLINE_ float round(float p_val) { return (p_val >= 0) ? Math::floor(p_val + 0.5) : -Math::floor(-p_val + 0.5); }
- static _ALWAYS_INLINE_ int wrapi(int value, int min, int max) {
- int rng = max - min;
+ static _ALWAYS_INLINE_ int64_t wrapi(int64_t value, int64_t min, int64_t max) {
+ int64_t rng = max - min;
return (rng != 0) ? min + ((((value - min) % rng) + rng) % rng) : min;
}
static _ALWAYS_INLINE_ double wrapf(double value, double min, double max) {
@@ -249,13 +249,25 @@ public:
static float random(float from, float to);
static real_t random(int from, int to) { return (real_t)random((real_t)from, (real_t)to); }
- static _ALWAYS_INLINE_ bool is_equal_approx(real_t a, real_t b) {
+ static _ALWAYS_INLINE_ bool is_equal_approx_ratio(real_t a, real_t b, real_t epsilon = CMP_EPSILON) {
+ // this is an approximate way to check that numbers are close, as a ratio of their average size
+ // helps compare approximate numbers that may be very big or very small
+ real_t diff = abs(a - b);
+ if (diff == 0.0) {
+ return true;
+ }
+ real_t avg_size = (abs(a) + abs(b)) / 2.0;
+ diff /= avg_size;
+ 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.
- return abs(a - b) < CMP_EPSILON;
+ return abs(a - b) < epsilon;
}
static _ALWAYS_INLINE_ float absf(float g) {
diff --git a/core/math/quat.cpp b/core/math/quat.cpp
index 6833d5de55..1a67be7384 100644
--- a/core/math/quat.cpp
+++ b/core/math/quat.cpp
@@ -135,7 +135,7 @@ Quat Quat::normalized() const {
}
bool Quat::is_normalized() const {
- return Math::is_equal_approx(length_squared(), 1.0);
+ return Math::is_equal_approx(length_squared(), 1.0, UNIT_EPSILON); //use less epsilon
}
Quat Quat::inverse() const {
diff --git a/core/math/vector2.cpp b/core/math/vector2.cpp
index e580057950..5c1ea5943d 100644
--- a/core/math/vector2.cpp
+++ b/core/math/vector2.cpp
@@ -65,7 +65,7 @@ Vector2 Vector2::normalized() const {
bool Vector2::is_normalized() const {
// use length_squared() instead of length() to avoid sqrt(), makes it more stringent.
- return Math::is_equal_approx(length_squared(), 1.0);
+ return Math::is_equal_approx(length_squared(), 1.0, UNIT_EPSILON);
}
real_t Vector2::distance_to(const Vector2 &p_vector2) const {
diff --git a/core/math/vector3.h b/core/math/vector3.h
index 8d6e093c4c..b11838d16e 100644
--- a/core/math/vector3.h
+++ b/core/math/vector3.h
@@ -414,7 +414,7 @@ Vector3 Vector3::normalized() const {
bool Vector3::is_normalized() const {
// use length_squared() instead of length() to avoid sqrt(), makes it more stringent.
- return Math::is_equal_approx(length_squared(), 1.0);
+ return Math::is_equal_approx(length_squared(), 1.0, UNIT_EPSILON);
}
Vector3 Vector3::inverse() const {
diff --git a/core/os/os.cpp b/core/os/os.cpp
index d2d39d253a..03e63f636e 100644
--- a/core/os/os.cpp
+++ b/core/os/os.cpp
@@ -569,6 +569,11 @@ int OS::get_power_percent_left() {
return -1;
}
+void OS::set_has_server_feature_callback(HasServerFeatureCallback p_callback) {
+
+ has_server_feature_callback = p_callback;
+}
+
bool OS::has_feature(const String &p_feature) {
if (p_feature == get_name())
@@ -625,6 +630,10 @@ bool OS::has_feature(const String &p_feature) {
if (_check_internal_feature_support(p_feature))
return true;
+ if (has_server_feature_callback && has_server_feature_callback(p_feature)) {
+ return true;
+ }
+
if (ProjectSettings::get_singleton()->has_custom_feature(p_feature))
return true;
@@ -729,6 +738,8 @@ OS::OS() {
_logger = NULL;
+ has_server_feature_callback = NULL;
+
Vector<Logger *> loggers;
loggers.push_back(memnew(StdLogger));
_set_logger(memnew(CompositeLogger(loggers)));
diff --git a/core/os/os.h b/core/os/os.h
index 396555970a..d6541034fd 100644
--- a/core/os/os.h
+++ b/core/os/os.h
@@ -77,6 +77,7 @@ protected:
public:
typedef void (*ImeCallback)(void *p_inp, String p_text, Point2 p_selection);
+ typedef bool (*HasServerFeatureCallback)(const String &p_feature);
enum PowerState {
POWERSTATE_UNKNOWN, /**< cannot determine power status */
@@ -121,6 +122,7 @@ public:
protected:
friend class Main;
+ HasServerFeatureCallback has_server_feature_callback;
RenderThreadMode _render_thread_mode;
// functions used by main to initialize/deinitialize the OS
@@ -146,8 +148,8 @@ public:
static OS *get_singleton();
void print_error(const char *p_function, const char *p_file, int p_line, const char *p_code, const char *p_rationale, Logger::ErrorType p_type = Logger::ERR_ERROR);
- void print(const char *p_format, ...);
- void printerr(const char *p_format, ...);
+ void print(const char *p_format, ...) _PRINTF_FORMAT_ATTRIBUTE_2_3;
+ void printerr(const char *p_format, ...) _PRINTF_FORMAT_ATTRIBUTE_2_3;
virtual void alert(const String &p_alert, const String &p_title = "ALERT!") = 0;
virtual String get_stdin_string(bool p_block = true) = 0;
@@ -507,6 +509,8 @@ public:
virtual void force_process_input(){};
bool has_feature(const String &p_feature);
+ void set_has_server_feature_callback(HasServerFeatureCallback p_callback);
+
bool is_layered_allowed() const { return _allow_layered; }
bool is_hidpi_allowed() const { return _allow_hidpi; }
diff --git a/core/script_debugger_remote.cpp b/core/script_debugger_remote.cpp
index 9780cc48ea..3ed25f118d 100644
--- a/core/script_debugger_remote.cpp
+++ b/core/script_debugger_remote.cpp
@@ -1054,7 +1054,6 @@ void ScriptDebuggerRemote::profiling_set_frame_times(float p_frame_time, float p
physics_frame_time = p_physics_frame_time;
}
-
ScriptDebuggerRemote::ResourceUsageFunc ScriptDebuggerRemote::resource_usage_func = NULL;
ScriptDebuggerRemote::ScriptDebuggerRemote() :
diff --git a/core/typedefs.h b/core/typedefs.h
index e01e1c00b9..966360d4f2 100644
--- a/core/typedefs.h
+++ b/core/typedefs.h
@@ -307,4 +307,12 @@ struct _GlobalLock {
#define unlikely(x) x
#endif
+#if defined(__GNUC__)
+#define _PRINTF_FORMAT_ATTRIBUTE_2_0 __attribute__((format(printf, 2, 0)))
+#define _PRINTF_FORMAT_ATTRIBUTE_2_3 __attribute__((format(printf, 2, 3)))
+#else
+#define _PRINTF_FORMAT_ATTRIBUTE_2_0
+#define _PRINTF_FORMAT_ATTRIBUTE_2_3
+#endif
+
#endif // TYPEDEFS_H
diff --git a/core/undo_redo.cpp b/core/undo_redo.cpp
index 40ccd95758..00894b41d8 100644
--- a/core/undo_redo.cpp
+++ b/core/undo_redo.cpp
@@ -63,37 +63,43 @@ void UndoRedo::create_action(const String &p_name, MergeMode p_mode) {
_discard_redo();
// Check if the merge operation is valid
- if (p_mode == MERGE_ENDS && actions.size() && actions[actions.size() - 1].name == p_name && actions[actions.size() - 1].last_tick + 800 > ticks) {
+ if (p_mode != MERGE_DISABLE && actions.size() && actions[actions.size() - 1].name == p_name && actions[actions.size() - 1].last_tick + 800 > ticks) {
current_action = actions.size() - 2;
- // Clear all do ops from last action, and delete all object references
- List<Operation>::Element *E = actions.write[current_action + 1].do_ops.front();
+ if (p_mode == MERGE_ENDS) {
- while (E) {
+ // Clear all do ops from last action, and delete all object references
+ List<Operation>::Element *E = actions.write[current_action + 1].do_ops.front();
- if (E->get().type == Operation::TYPE_REFERENCE) {
+ while (E) {
- Object *obj = ObjectDB::get_instance(E->get().object);
+ if (E->get().type == Operation::TYPE_REFERENCE) {
- if (obj)
- memdelete(obj);
- }
+ Object *obj = ObjectDB::get_instance(E->get().object);
+
+ if (obj)
+ memdelete(obj);
+ }
- E = E->next();
- actions.write[current_action + 1].do_ops.pop_front();
+ E = E->next();
+ actions.write[current_action + 1].do_ops.pop_front();
+ }
}
actions.write[actions.size() - 1].last_tick = ticks;
+
+ merge_mode = p_mode;
+
} else {
Action new_action;
new_action.name = p_name;
new_action.last_tick = ticks;
actions.push_back(new_action);
- }
- merge_mode = p_mode;
+ merge_mode = MERGE_DISABLE;
+ }
}
action_level++;