diff options
Diffstat (limited to 'core')
-rw-r--r-- | core/class_db.cpp | 18 | ||||
-rw-r--r-- | core/math/a_star.cpp | 14 | ||||
-rw-r--r-- | core/math/expression.cpp | 4 | ||||
-rw-r--r-- | core/object.cpp | 15 | ||||
-rw-r--r-- | core/object.h | 1 | ||||
-rw-r--r-- | core/ustring.cpp | 31 |
6 files changed, 63 insertions, 20 deletions
diff --git a/core/class_db.cpp b/core/class_db.cpp index eed9ec17cb..05c9850c39 100644 --- a/core/class_db.cpp +++ b/core/class_db.cpp @@ -1386,7 +1386,23 @@ Variant ClassDB::class_get_default_property_value(const StringName &p_class, con if (r_valid != nullptr) { *r_valid = true; } - return default_values[p_class][p_property]; + + Variant var = default_values[p_class][p_property]; + +#ifdef DEBUG_ENABLED + // Some properties may have an instantiated Object as default value, + // (like Path2D's `curve` used to have), but that's not a good practice. + // Instead, those properties should use PROPERTY_USAGE_EDITOR_INSTANTIATE_OBJECT + // to be auto-instantiated when created in the editor. + if (var.get_type() == Variant::OBJECT) { + Object *obj = var.get_validated_object(); + if (obj) { + WARN_PRINT(vformat("Instantiated %s used as default value for %s's \"%s\" property.", obj->get_class(), p_class, p_property)); + } + } +#endif + + return var; } RWLock *ClassDB::lock = nullptr; diff --git a/core/math/a_star.cpp b/core/math/a_star.cpp index 580a7cf7bb..30f712b2c3 100644 --- a/core/math/a_star.cpp +++ b/core/math/a_star.cpp @@ -280,10 +280,16 @@ int AStar::get_closest_point(const Vector3 &p_point, bool p_include_disabled) co continue; // Disabled points should not be considered. } + // Keep the closest point's ID, and in case of multiple closest IDs, + // the smallest one (makes it deterministic). real_t d = p_point.distance_squared_to((*it.value)->pos); - if (closest_id < 0 || d < closest_dist) { + int id = *(it.key); + if (d <= closest_dist) { + if (d == closest_dist && id > closest_id) { // Keep lowest ID. + continue; + } closest_dist = d; - closest_id = *(it.key); + closest_id = id; } } @@ -291,7 +297,6 @@ int AStar::get_closest_point(const Vector3 &p_point, bool p_include_disabled) co } Vector3 AStar::get_closest_position_in_segment(const Vector3 &p_point) const { - bool found = false; real_t closest_dist = 1e20; Vector3 closest_point; @@ -311,10 +316,9 @@ Vector3 AStar::get_closest_position_in_segment(const Vector3 &p_point) const { Vector3 p = Geometry3D::get_closest_point_to_segment(p_point, segment); real_t d = p_point.distance_squared_to(p); - if (!found || d < closest_dist) { + if (d < closest_dist) { closest_point = p; closest_dist = d; - found = true; } } diff --git a/core/math/expression.cpp b/core/math/expression.cpp index db3bf2f830..6421606ca2 100644 --- a/core/math/expression.cpp +++ b/core/math/expression.cpp @@ -896,6 +896,7 @@ Error Expression::_get_token(Token &r_token) { return OK; } + case '\'': case '"': { String str; while (true) { @@ -905,7 +906,8 @@ Error Expression::_get_token(Token &r_token) { _set_error("Unterminated String"); r_token.type = TK_ERROR; return ERR_PARSE_ERROR; - } else if (ch == '"') { + } else if (ch == cchar) { + // cchar contain a corresponding quote symbol break; } else if (ch == '\\') { //escaped characters... diff --git a/core/object.cpp b/core/object.cpp index 3ea3e27d41..8abea9ca7e 100644 --- a/core/object.cpp +++ b/core/object.cpp @@ -2040,20 +2040,27 @@ void ObjectDB::cleanup() { WARN_PRINT("ObjectDB instances leaked at exit (run with --verbose for details)."); if (OS::get_singleton()->is_stdout_verbose()) { + // Ensure calling the native classes because if a leaked instance has a script + // that overrides any of those methods, it'd not be OK to call them at this point, + // now the scripting languages have already been terminated. + MethodBind *node_get_name = ClassDB::get_method("Node", "get_name"); + MethodBind *resource_get_path = ClassDB::get_method("Resource", "get_path"); + Callable::CallError call_error; + for (uint32_t i = 0; i < slot_count; i++) { uint32_t slot = object_slots[i].next_free; Object *obj = object_slots[slot].object; - String node_name; + String extra_info; if (obj->is_class("Node")) { - node_name = " - Node name: " + String(obj->call("get_name")); + extra_info = " - Node name: " + String(node_get_name->call(obj, nullptr, 0, call_error)); } if (obj->is_class("Resource")) { - node_name = " - Resource path: " + String(obj->call("get_path")); + extra_info = " - Resource path: " + String(resource_get_path->call(obj, nullptr, 0, call_error)); } uint64_t id = uint64_t(slot) | (uint64_t(object_slots[slot].validator) << OBJECTDB_VALIDATOR_BITS) | (object_slots[slot].is_reference ? OBJECTDB_REFERENCE_BIT : 0); - print_line("Leaked instance: " + String(obj->get_class()) + ":" + itos(id) + node_name); + print_line("Leaked instance: " + String(obj->get_class()) + ":" + itos(id) + extra_info); } print_line("Hint: Leaked instances typically happen when nodes are removed from the scene tree (with `remove_child()`) but not freed (with `free()` or `queue_free()`)."); } diff --git a/core/object.h b/core/object.h index 95662f6208..5b46a0f93a 100644 --- a/core/object.h +++ b/core/object.h @@ -124,6 +124,7 @@ enum PropertyUsageFlags { PROPERTY_USAGE_RESOURCE_NOT_PERSISTENT = 1 << 24, PROPERTY_USAGE_KEYING_INCREMENTS = 1 << 25, // Used in inspector to increment property when keyed in animation player PROPERTY_USAGE_DEFERRED_SET_RESOURCE = 1 << 26, // when loading, the resource for this property can be set at the end of loading + PROPERTY_USAGE_EDITOR_INSTANTIATE_OBJECT = 1 << 27, // For Object properties, instantiate them when creating in editor. PROPERTY_USAGE_DEFAULT = PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_NETWORK, PROPERTY_USAGE_DEFAULT_INTL = PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_NETWORK | PROPERTY_USAGE_INTERNATIONALIZED, diff --git a/core/ustring.cpp b/core/ustring.cpp index cfb547742a..444338d5ae 100644 --- a/core/ustring.cpp +++ b/core/ustring.cpp @@ -4143,27 +4143,40 @@ String String::sprintf(const Array &values, bool *error) const { } double value = values[value_index]; - String str = String::num(value, min_decimals); + bool is_negative = (value < 0); + String str = String::num(ABS(value), min_decimals); // Pad decimals out. str = str.pad_decimals(min_decimals); - // Show sign - if (show_sign && str.left(1) != "-") { - str = str.insert(0, "+"); - } + int initial_len = str.length(); - // Padding + // Padding. Leave room for sign later if required. + int pad_chars_count = (is_negative || show_sign) ? min_chars - 1 : min_chars; + String pad_char = pad_with_zeroes ? String("0") : String(" "); if (left_justified) { - str = str.rpad(min_chars); + if (pad_with_zeroes) { + return "left justification cannot be used with zeros as the padding"; + } else { + str = str.rpad(pad_chars_count, pad_char); + } } else { - str = str.lpad(min_chars); + str = str.lpad(pad_chars_count, pad_char); + } + + // Add sign if needed. + if (show_sign || is_negative) { + String sign_char = is_negative ? "-" : "+"; + if (left_justified) { + str = str.insert(0, sign_char); + } else { + str = str.insert(pad_with_zeroes ? 0 : str.length() - initial_len, sign_char); + } } formatted += str; ++value_index; in_format = false; - break; } case 's': { // String |