summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/web_builds.yml2
-rw-r--r--core/templates/command_queue_mt.h2
-rw-r--r--core/templates/simple_type.h21
-rw-r--r--core/variant/binder_common.h16
-rw-r--r--core/variant/variant_internal.h2
-rw-r--r--doc/classes/@GlobalScope.xml1
-rw-r--r--editor/editor_properties.cpp1
-rw-r--r--editor/editor_translation.cpp170
-rw-r--r--editor/editor_translation.h2
-rw-r--r--editor/pot_generator.cpp7
-rw-r--r--scene/main/node.cpp6
-rw-r--r--tests/core/math/test_math_funcs.h3
12 files changed, 178 insertions, 55 deletions
diff --git a/.github/workflows/web_builds.yml b/.github/workflows/web_builds.yml
index 47f7e4d458..cfa1571d1f 100644
--- a/.github/workflows/web_builds.yml
+++ b/.github/workflows/web_builds.yml
@@ -7,7 +7,7 @@ env:
# Used for the cache key. Add version suffix to force clean build.
GODOT_BASE_BRANCH: master
SCONSFLAGS: verbose=yes warnings=extra werror=yes debug_symbols=no
- EM_VERSION: 3.1.39
+ EM_VERSION: 3.1.59
EM_CACHE_FOLDER: "emsdk-cache"
concurrency:
diff --git a/core/templates/command_queue_mt.h b/core/templates/command_queue_mt.h
index c149861467..bb36f38d54 100644
--- a/core/templates/command_queue_mt.h
+++ b/core/templates/command_queue_mt.h
@@ -208,7 +208,7 @@
#define ARG(N) p##N
#define PARAM(N) P##N p##N
#define TYPE_PARAM(N) typename P##N
-#define PARAM_DECL(N) typename GetSimpleTypeT<P##N>::type_t p##N
+#define PARAM_DECL(N) GetSimpleTypeT<P##N> p##N
#define DECL_CMD(N) \
template <typename T, typename M COMMA(N) COMMA_SEP_LIST(TYPE_PARAM, N)> \
diff --git a/core/templates/simple_type.h b/core/templates/simple_type.h
index b2ae0110e2..197115ddb9 100644
--- a/core/templates/simple_type.h
+++ b/core/templates/simple_type.h
@@ -31,26 +31,9 @@
#ifndef SIMPLE_TYPE_H
#define SIMPLE_TYPE_H
-/* Batch of specializations to obtain the actual simple type */
+#include <type_traits>
template <typename T>
-struct GetSimpleTypeT {
- typedef T type_t;
-};
-
-template <typename T>
-struct GetSimpleTypeT<T &> {
- typedef T type_t;
-};
-
-template <typename T>
-struct GetSimpleTypeT<T const> {
- typedef T type_t;
-};
-
-template <typename T>
-struct GetSimpleTypeT<T const &> {
- typedef T type_t;
-};
+using GetSimpleTypeT = typename std::remove_cv_t<std::remove_reference_t<T>>;
#endif // SIMPLE_TYPE_H
diff --git a/core/variant/binder_common.h b/core/variant/binder_common.h
index 0fe4518b0f..61b90e2a26 100644
--- a/core/variant/binder_common.h
+++ b/core/variant/binder_common.h
@@ -362,42 +362,42 @@ void call_with_ptr_args_static_method_helper(void (*p_method)(P...), const void
template <typename T, typename... P, size_t... Is>
void call_with_validated_variant_args_helper(T *p_instance, void (T::*p_method)(P...), const Variant **p_args, IndexSequence<Is...>) {
- (p_instance->*p_method)((VariantInternalAccessor<typename GetSimpleTypeT<P>::type_t>::get(p_args[Is]))...);
+ (p_instance->*p_method)((VariantInternalAccessor<GetSimpleTypeT<P>>::get(p_args[Is]))...);
}
template <typename T, typename... P, size_t... Is>
void call_with_validated_variant_argsc_helper(T *p_instance, void (T::*p_method)(P...) const, const Variant **p_args, IndexSequence<Is...>) {
- (p_instance->*p_method)((VariantInternalAccessor<typename GetSimpleTypeT<P>::type_t>::get(p_args[Is]))...);
+ (p_instance->*p_method)((VariantInternalAccessor<GetSimpleTypeT<P>>::get(p_args[Is]))...);
}
template <typename T, typename R, typename... P, size_t... Is>
void call_with_validated_variant_args_ret_helper(T *p_instance, R (T::*p_method)(P...), const Variant **p_args, Variant *r_ret, IndexSequence<Is...>) {
- VariantInternalAccessor<typename GetSimpleTypeT<R>::type_t>::set(r_ret, (p_instance->*p_method)((VariantInternalAccessor<typename GetSimpleTypeT<P>::type_t>::get(p_args[Is]))...));
+ VariantInternalAccessor<GetSimpleTypeT<R>>::set(r_ret, (p_instance->*p_method)((VariantInternalAccessor<GetSimpleTypeT<P>>::get(p_args[Is]))...));
}
template <typename T, typename R, typename... P, size_t... Is>
void call_with_validated_variant_args_retc_helper(T *p_instance, R (T::*p_method)(P...) const, const Variant **p_args, Variant *r_ret, IndexSequence<Is...>) {
- VariantInternalAccessor<typename GetSimpleTypeT<R>::type_t>::set(r_ret, (p_instance->*p_method)((VariantInternalAccessor<typename GetSimpleTypeT<P>::type_t>::get(p_args[Is]))...));
+ VariantInternalAccessor<GetSimpleTypeT<R>>::set(r_ret, (p_instance->*p_method)((VariantInternalAccessor<GetSimpleTypeT<P>>::get(p_args[Is]))...));
}
template <typename T, typename R, typename... P, size_t... Is>
void call_with_validated_variant_args_static_retc_helper(T *p_instance, R (*p_method)(T *, P...), const Variant **p_args, Variant *r_ret, IndexSequence<Is...>) {
- VariantInternalAccessor<typename GetSimpleTypeT<R>::type_t>::set(r_ret, p_method(p_instance, (VariantInternalAccessor<typename GetSimpleTypeT<P>::type_t>::get(p_args[Is]))...));
+ VariantInternalAccessor<GetSimpleTypeT<R>>::set(r_ret, p_method(p_instance, (VariantInternalAccessor<GetSimpleTypeT<P>>::get(p_args[Is]))...));
}
template <typename T, typename... P, size_t... Is>
void call_with_validated_variant_args_static_helper(T *p_instance, void (*p_method)(T *, P...), const Variant **p_args, IndexSequence<Is...>) {
- p_method(p_instance, (VariantInternalAccessor<typename GetSimpleTypeT<P>::type_t>::get(p_args[Is]))...);
+ p_method(p_instance, (VariantInternalAccessor<GetSimpleTypeT<P>>::get(p_args[Is]))...);
}
template <typename R, typename... P, size_t... Is>
void call_with_validated_variant_args_static_method_ret_helper(R (*p_method)(P...), const Variant **p_args, Variant *r_ret, IndexSequence<Is...>) {
- VariantInternalAccessor<typename GetSimpleTypeT<R>::type_t>::set(r_ret, p_method((VariantInternalAccessor<typename GetSimpleTypeT<P>::type_t>::get(p_args[Is]))...));
+ VariantInternalAccessor<GetSimpleTypeT<R>>::set(r_ret, p_method((VariantInternalAccessor<GetSimpleTypeT<P>>::get(p_args[Is]))...));
}
template <typename... P, size_t... Is>
void call_with_validated_variant_args_static_method_helper(void (*p_method)(P...), const Variant **p_args, IndexSequence<Is...>) {
- p_method((VariantInternalAccessor<typename GetSimpleTypeT<P>::type_t>::get(p_args[Is]))...);
+ p_method((VariantInternalAccessor<GetSimpleTypeT<P>>::get(p_args[Is]))...);
}
template <typename T, typename... P>
diff --git a/core/variant/variant_internal.h b/core/variant/variant_internal.h
index ec87081f15..c52ab6917b 100644
--- a/core/variant/variant_internal.h
+++ b/core/variant/variant_internal.h
@@ -1546,7 +1546,7 @@ struct VariantTypeChanger {
template <typename T>
struct VariantTypeAdjust {
_FORCE_INLINE_ static void adjust(Variant *r_ret) {
- VariantTypeChanger<typename GetSimpleTypeT<T>::type_t>::change(r_ret);
+ VariantTypeChanger<GetSimpleTypeT<T>>::change(r_ret);
}
};
diff --git a/doc/classes/@GlobalScope.xml b/doc/classes/@GlobalScope.xml
index 26bf515135..4b32acaaa0 100644
--- a/doc/classes/@GlobalScope.xml
+++ b/doc/classes/@GlobalScope.xml
@@ -1097,6 +1097,7 @@
remap(75, 0, 100, -1, 1) # Returns 0.5
[/codeblock]
For complex use cases where multiple ranges are needed, consider using [Curve] or [Gradient] instead.
+ [b]Note:[/b] If [code]istart == istop[/code], the return value is undefined (most likely NaN, INF, or -INF).
</description>
</method>
<method name="rid_allocate_id">
diff --git a/editor/editor_properties.cpp b/editor/editor_properties.cpp
index 9cb5fcc18c..816d3d7778 100644
--- a/editor/editor_properties.cpp
+++ b/editor/editor_properties.cpp
@@ -2025,6 +2025,7 @@ void EditorPropertyQuaternion::_custom_value_changed(double val) {
spin[1]->set_value_no_signal(temp_q.y);
spin[2]->set_value_no_signal(temp_q.z);
spin[3]->set_value_no_signal(temp_q.w);
+ _value_changed(-1, "");
}
void EditorPropertyQuaternion::_value_changed(double val, const String &p_name) {
diff --git a/editor/editor_translation.cpp b/editor/editor_translation.cpp
index 194d78326d..77154ec344 100644
--- a/editor/editor_translation.cpp
+++ b/editor/editor_translation.cpp
@@ -156,30 +156,166 @@ void load_extractable_translations(const String &p_locale) {
}
}
-List<StringName> get_extractable_message_list() {
+Vector<Vector<String>> get_extractable_message_list() {
ExtractableTranslationList *etl = _extractable_translations;
- List<StringName> msgids;
- while (etl->data) {
- if (!strcmp(etl->lang, "source")) {
- Vector<uint8_t> data;
- data.resize(etl->uncomp_size);
- int ret = Compression::decompress(data.ptrw(), etl->uncomp_size, etl->data, etl->comp_size, Compression::MODE_DEFLATE);
- ERR_FAIL_COND_V_MSG(ret == -1, msgids, "Compressed file is corrupt.");
+ Vector<Vector<String>> list;
- Ref<FileAccessMemory> fa;
- fa.instantiate();
- fa->open_custom(data.ptr(), data.size());
-
- Ref<Translation> tr = TranslationLoaderPO::load_translation(fa);
+ while (etl->data) {
+ if (strcmp(etl->lang, "source")) {
+ etl++;
+ continue;
+ }
- if (tr.is_valid()) {
- tr->get_message_list(&msgids);
- break;
+ Vector<uint8_t> data;
+ data.resize(etl->uncomp_size);
+ int ret = Compression::decompress(data.ptrw(), etl->uncomp_size, etl->data, etl->comp_size, Compression::MODE_DEFLATE);
+ ERR_FAIL_COND_V_MSG(ret == -1, list, "Compressed file is corrupt.");
+
+ Ref<FileAccessMemory> fa;
+ fa.instantiate();
+ fa->open_custom(data.ptr(), data.size());
+
+ // Taken from TranslationLoaderPO, modified to work specifically with POTs.
+ {
+ const String path = fa->get_path();
+
+ fa->seek(0);
+
+ enum Status {
+ STATUS_NONE,
+ STATUS_READING_ID,
+ STATUS_READING_STRING,
+ STATUS_READING_CONTEXT,
+ STATUS_READING_PLURAL,
+ };
+
+ Status status = STATUS_NONE;
+
+ String msg_id;
+ String msg_id_plural;
+ String msg_context;
+
+ int line = 1;
+ bool entered_context = false;
+ bool is_eof = false;
+
+ while (!is_eof) {
+ String l = fa->get_line().strip_edges();
+ is_eof = fa->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.is_empty()) {
+ if (status == STATUS_READING_ID || status == STATUS_READING_CONTEXT || status == STATUS_READING_PLURAL) {
+ ERR_FAIL_V_MSG(Vector<Vector<String>>(), "Unexpected EOF while reading POT file at: " + path + ":" + itos(line));
+ } else {
+ break;
+ }
+ }
+
+ if (l.begins_with("msgctxt")) {
+ ERR_FAIL_COND_V_MSG(status != STATUS_READING_STRING && status != STATUS_READING_PLURAL, Vector<Vector<String>>(),
+ "Unexpected 'msgctxt', was expecting 'msgid_plural' or 'msgstr' before 'msgctxt' while parsing: " + path + ":" + itos(line));
+
+ // In POT files, "msgctxt" appears before "msgid". If we encounter a "msgctxt", we add what we have read
+ // and set "entered_context" to true to prevent adding twice.
+ if (!msg_id.is_empty()) {
+ Vector<String> msgs;
+ msgs.push_back(msg_id);
+ msgs.push_back(msg_context);
+ msgs.push_back(msg_id_plural);
+ list.push_back(msgs);
+ }
+ msg_context = "";
+ l = l.substr(7, l.length()).strip_edges();
+ status = STATUS_READING_CONTEXT;
+ entered_context = true;
+ }
+
+ if (l.begins_with("msgid_plural")) {
+ if (status != STATUS_READING_ID) {
+ ERR_FAIL_V_MSG(Vector<Vector<String>>(), "Unexpected 'msgid_plural', was expecting 'msgid' before 'msgid_plural' while parsing: " + path + ":" + itos(line));
+ }
+ l = l.substr(12, l.length()).strip_edges();
+ status = STATUS_READING_PLURAL;
+ } else if (l.begins_with("msgid")) {
+ ERR_FAIL_COND_V_MSG(status == STATUS_READING_ID, Vector<Vector<String>>(), "Unexpected 'msgid', was expecting 'msgstr' while parsing: " + path + ":" + itos(line));
+
+ if (!msg_id.is_empty() && !entered_context) {
+ Vector<String> msgs;
+ msgs.push_back(msg_id);
+ msgs.push_back(msg_context);
+ msgs.push_back(msg_id_plural);
+ list.push_back(msgs);
+ }
+
+ l = l.substr(5, l.length()).strip_edges();
+ status = STATUS_READING_ID;
+ // If we did not encounter msgctxt, we reset context to empty to reset it.
+ if (!entered_context) {
+ msg_context = "";
+ }
+ msg_id = "";
+ msg_id_plural = "";
+ entered_context = false;
+ }
+
+ if (l.begins_with("msgstr[")) {
+ ERR_FAIL_COND_V_MSG(status != STATUS_READING_PLURAL, Vector<Vector<String>>(),
+ "Unexpected 'msgstr[]', was expecting 'msgid_plural' before 'msgstr[]' while parsing: " + path + ":" + itos(line));
+ l = l.substr(9, l.length()).strip_edges();
+ } else if (l.begins_with("msgstr")) {
+ ERR_FAIL_COND_V_MSG(status != STATUS_READING_ID, Vector<Vector<String>>(),
+ "Unexpected 'msgstr', was expecting 'msgid' before 'msgstr' while parsing: " + path + ":" + itos(line));
+ l = l.substr(6, l.length()).strip_edges();
+ status = STATUS_READING_STRING;
+ }
+
+ if (l.is_empty() || l.begins_with("#")) {
+ line++;
+ continue; // Nothing to read or comment.
+ }
+
+ ERR_FAIL_COND_V_MSG(!l.begins_with("\"") || status == STATUS_NONE, Vector<Vector<String>>(), "Invalid line '" + l + "' while parsing: " + path + ":" + itos(line));
+
+ l = l.substr(1, l.length());
+ // Find final quote, ignoring escaped ones (\").
+ // The escape_next logic is necessary to properly parse things like \\"
+ // where the backslash is the one being escaped, not the quote.
+ int end_pos = -1;
+ bool escape_next = false;
+ for (int i = 0; i < l.length(); i++) {
+ if (l[i] == '\\' && !escape_next) {
+ escape_next = true;
+ continue;
+ }
+
+ if (l[i] == '"' && !escape_next) {
+ end_pos = i;
+ break;
+ }
+
+ escape_next = false;
+ }
+
+ ERR_FAIL_COND_V_MSG(end_pos == -1, Vector<Vector<String>>(), "Expected '\"' at end of message while parsing: " + path + ":" + itos(line));
+
+ l = l.substr(0, end_pos);
+ l = l.c_unescape();
+
+ if (status == STATUS_READING_ID) {
+ msg_id += l;
+ } else if (status == STATUS_READING_CONTEXT) {
+ msg_context += l;
+ } else if (status == STATUS_READING_PLURAL) {
+ msg_id_plural += l;
+ }
+
+ line++;
}
}
etl++;
}
- return msgids;
+ return list;
}
diff --git a/editor/editor_translation.h b/editor/editor_translation.h
index 4785495629..eee9e533c4 100644
--- a/editor/editor_translation.h
+++ b/editor/editor_translation.h
@@ -40,6 +40,6 @@ void load_editor_translations(const String &p_locale);
void load_property_translations(const String &p_locale);
void load_doc_translations(const String &p_locale);
void load_extractable_translations(const String &p_locale);
-List<StringName> get_extractable_message_list();
+Vector<Vector<String>> get_extractable_message_list();
#endif // EDITOR_TRANSLATION_H
diff --git a/editor/pot_generator.cpp b/editor/pot_generator.cpp
index 8323ae944b..76b6593f1d 100644
--- a/editor/pot_generator.cpp
+++ b/editor/pot_generator.cpp
@@ -34,7 +34,6 @@
#include "core/error/error_macros.h"
#include "editor/editor_translation.h"
#include "editor/editor_translation_parser.h"
-#include "plugins/packed_scene_translation_parser_plugin.h"
POTGenerator *POTGenerator::singleton = nullptr;
@@ -66,8 +65,6 @@ void POTGenerator::generate_pot(const String &p_file) {
// Clear all_translation_strings of the previous round.
all_translation_strings.clear();
- List<StringName> extractable_msgids = get_extractable_message_list();
-
// Collect all translatable strings according to files order in "POT Generation" setting.
for (int i = 0; i < files.size(); i++) {
Vector<String> msgids;
@@ -92,8 +89,8 @@ void POTGenerator::generate_pot(const String &p_file) {
}
if (GLOBAL_GET("internationalization/locale/translation_add_builtin_strings_to_pot")) {
- for (const StringName &extractable_msgid : extractable_msgids) {
- _add_new_msgid(extractable_msgid, "", "", "");
+ for (const Vector<String> &extractable_msgids : get_extractable_message_list()) {
+ _add_new_msgid(extractable_msgids[0], extractable_msgids[1], extractable_msgids[2], "");
}
}
diff --git a/scene/main/node.cpp b/scene/main/node.cpp
index 827273132c..e54209c1dd 100644
--- a/scene/main/node.cpp
+++ b/scene/main/node.cpp
@@ -2930,8 +2930,10 @@ void Node::_duplicate_properties_node(const Node *p_root, const Node *p_original
}
}
- for (int i = 0; i < p_copy->get_child_count(); i++) {
- _duplicate_properties_node(p_root, p_original->get_child(i), p_copy->get_child(i));
+ for (int i = 0; i < p_original->get_child_count(); i++) {
+ Node *copy_child = p_copy->get_child(i);
+ ERR_FAIL_NULL_MSG(copy_child, "Child node disappeared while duplicating.");
+ _duplicate_properties_node(p_root, p_original->get_child(i), copy_child);
}
}
diff --git a/tests/core/math/test_math_funcs.h b/tests/core/math/test_math_funcs.h
index 0a9d9c97d9..f2eae3a20d 100644
--- a/tests/core/math/test_math_funcs.h
+++ b/tests/core/math/test_math_funcs.h
@@ -381,6 +381,9 @@ TEST_CASE_TEMPLATE("[Math] remap", T, float, double) {
CHECK(Math::remap((T)-100.0, (T)-100.0, (T)-200.0, (T)0.0, (T)-1000.0) == doctest::Approx((T)0.0));
CHECK(Math::remap((T)-200.0, (T)-100.0, (T)-200.0, (T)0.0, (T)-1000.0) == doctest::Approx((T)-1000.0));
CHECK(Math::remap((T)-250.0, (T)-100.0, (T)-200.0, (T)0.0, (T)-1000.0) == doctest::Approx((T)-1500.0));
+
+ // Note: undefined behaviour can happen when `p_istart == p_istop`. We don't bother testing this as it will
+ // vary between hardware and compilers properly implementing IEEE 754.
}
TEST_CASE_TEMPLATE("[Math] angle_difference", T, float, double) {