summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/ISSUE_TEMPLATE/bug_report.md11
-rw-r--r--.github/config.yml14
-rw-r--r--SConstruct68
-rw-r--r--core/callable_method_pointer.h36
-rw-r--r--core/message_queue.cpp15
-rw-r--r--core/message_queue.h1
-rw-r--r--core/oa_hash_map.h42
-rw-r--r--core/project_settings.cpp67
-rw-r--r--editor/SCsub26
-rw-r--r--editor/animation_track_editor.cpp4
-rw-r--r--editor/editor_feature_profile.cpp36
-rw-r--r--editor/editor_feature_profile.h3
-rw-r--r--editor/icons/SCsub9
-rw-r--r--main/main.cpp6
-rw-r--r--main/tests/test_oa_hash_map.cpp83
-rw-r--r--methods.py69
-rw-r--r--modules/SCsub13
-rw-r--r--modules/gdscript/gdscript_editor.cpp6
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs2
-rw-r--r--platform/android/display_server_android.cpp19
-rw-r--r--platform/android/display_server_android.h2
-rw-r--r--platform/android/export/export.cpp29
-rw-r--r--platform/android/java/app/build.gradle5
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/GodotLib.java11
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/GodotRenderer.java2
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/vulkan/VkRenderer.kt11
-rw-r--r--platform/android/java/plugins/godotpayment/src/main/java/org/godotengine/godot/plugin/payment/GodotPayment.java6
-rw-r--r--platform/android/java_godot_lib_jni.cpp25
-rw-r--r--platform/android/java_godot_lib_jni.h6
-rw-r--r--platform/android/plugin/godot_plugin_config.h16
-rw-r--r--platform/android/plugin/godot_plugin_jni.cpp5
-rw-r--r--platform/javascript/audio_driver_javascript.cpp4
-rw-r--r--scene/debugger/scene_debugger.cpp9
-rw-r--r--scene/gui/color_picker.cpp2
-rw-r--r--scene/gui/container.cpp4
35 files changed, 506 insertions, 161 deletions
diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
index 91528465c0..7e8c5fd740 100644
--- a/.github/ISSUE_TEMPLATE/bug_report.md
+++ b/.github/ISSUE_TEMPLATE/bug_report.md
@@ -6,13 +6,24 @@ labels: ''
assignees: ''
---
+<!-- Please search existing issues for potential duplicates before filing yours:
+https://github.com/godotengine/godot/issues?q=is%3Aissue
+-->
**Godot version:**
+<!-- Specify commit hash if using non-official build. -->
+
**OS/device including version:**
+<!-- Specify GPU model, drivers, and the backend (GLES2, GLES3, Vulkan) if graphics-related. -->
+
**Issue description:**
+<!-- What happened, and what was expected. -->
+
**Steps to reproduce:**
+
**Minimal reproduction project:**
+<!-- A small Godot project which reproduces the issue. Drag and drop a zip archive to upload it. -->
diff --git a/.github/config.yml b/.github/config.yml
new file mode 100644
index 0000000000..f787bec00e
--- /dev/null
+++ b/.github/config.yml
@@ -0,0 +1,14 @@
+blank_issues_enabled: false
+
+contact_links:
+ - name: Godot proposals
+ url: https://github.com/godotengine/godot-proposals
+ about: Please submit feature proposals on the Godot proposals repository, not here.
+
+ - name: Godot documentation repository
+ url: https://github.com/godotengine/godot-docs
+ about: Please report issues with documentation on the Godot documentation repository, not here.
+
+ - name: Godot community channels
+ url: https://godotengine.org/community
+ about: Please ask for technical support on one of the other community channels, not here.
diff --git a/SConstruct b/SConstruct
index f74940b059..515cad57d0 100644
--- a/SConstruct
+++ b/SConstruct
@@ -50,8 +50,6 @@ for x in sorted(glob.glob("platform/*")):
sys.path.remove(tmppath)
sys.modules.pop("detect")
-module_list = methods.detect_modules()
-
methods.save_active_platforms(active_platforms, active_platform_ids)
custom_tools = ["default"]
@@ -123,6 +121,7 @@ opts.Add(BoolVariable("use_precise_math_checks", "Math checks use very precise e
opts.Add(BoolVariable("deprecated", "Enable deprecated features", True))
opts.Add(BoolVariable("minizip", "Enable ZIP archive support using minizip", True))
opts.Add(BoolVariable("xaudio2", "Enable the XAudio2 audio driver", False))
+opts.Add("custom_modules", "A list of comma-separated directory paths containing custom modules to build.", "")
# Advanced options
opts.Add(BoolVariable("verbose", "Enable verbose output for the compilation", False))
@@ -181,18 +180,41 @@ for k in platform_opts.keys():
for o in opt_list:
opts.Add(o)
-for x in module_list:
- module_enabled = True
- tmppath = "./modules/" + x
- sys.path.insert(0, tmppath)
+# Detect modules.
+modules_detected = {}
+module_search_paths = ["modules"] # Built-in path.
+
+if ARGUMENTS.get("custom_modules"):
+ paths = ARGUMENTS.get("custom_modules").split(",")
+ for p in paths:
+ try:
+ module_search_paths.append(methods.convert_custom_modules_path(p))
+ except ValueError as e:
+ print(e)
+ sys.exit(255)
+
+for path in module_search_paths:
+ # Note: custom modules can override built-in ones.
+ modules_detected.update(methods.detect_modules(path))
+ include_path = os.path.dirname(path)
+ if include_path:
+ env_base.Prepend(CPPPATH=[include_path])
+
+# Add module options.
+for name, path in modules_detected.items():
+ enabled = True
+ sys.path.insert(0, path)
import config
- enabled_attr = getattr(config, "is_enabled", None)
- if callable(enabled_attr) and not config.is_enabled():
- module_enabled = False
- sys.path.remove(tmppath)
+ try:
+ enabled = config.is_enabled()
+ except AttributeError:
+ pass
+ sys.path.remove(path)
sys.modules.pop("config")
- opts.Add(BoolVariable("module_" + x + "_enabled", "Enable module '%s'" % (x,), module_enabled))
+ opts.Add(BoolVariable("module_" + name + "_enabled", "Enable module '%s'" % (name,), enabled))
+
+methods.write_modules(modules_detected)
opts.Update(env_base) # update environment
Help(opts.GenerateHelpText(env_base)) # generate help
@@ -501,41 +523,41 @@ if selected_platform in platform_list:
sys.path.remove(tmppath)
sys.modules.pop("detect")
- env.module_list = []
+ modules_enabled = {}
env.module_icons_paths = []
env.doc_class_path = {}
- for x in sorted(module_list):
- if not env["module_" + x + "_enabled"]:
+ for name, path in sorted(modules_detected.items()):
+ if not env["module_" + name + "_enabled"]:
continue
- tmppath = "./modules/" + x
- sys.path.insert(0, tmppath)
- env.current_module = x
+ sys.path.insert(0, path)
+ env.current_module = name
import config
if config.can_build(env, selected_platform):
config.configure(env)
- env.module_list.append(x)
-
# Get doc classes paths (if present)
try:
doc_classes = config.get_doc_classes()
doc_path = config.get_doc_path()
for c in doc_classes:
- env.doc_class_path[c] = "modules/" + x + "/" + doc_path
+ env.doc_class_path[c] = path + "/" + doc_path
except:
pass
# Get icon paths (if present)
try:
icons_path = config.get_icons_path()
- env.module_icons_paths.append("modules/" + x + "/" + icons_path)
+ env.module_icons_paths.append(path + "/" + icons_path)
except:
# Default path for module icons
- env.module_icons_paths.append("modules/" + x + "/" + "icons")
+ env.module_icons_paths.append(path + "/" + "icons")
+ modules_enabled[name] = path
- sys.path.remove(tmppath)
+ sys.path.remove(path)
sys.modules.pop("config")
+ env.module_list = modules_enabled
+
methods.update_version(env.module_version_string)
env["PROGSUFFIX"] = suffix + env.module_version_string + env["PROGSUFFIX"]
diff --git a/core/callable_method_pointer.h b/core/callable_method_pointer.h
index 3b0503e259..22db7d1c82 100644
--- a/core/callable_method_pointer.h
+++ b/core/callable_method_pointer.h
@@ -161,19 +161,35 @@ template <class T, class... P>
class CallableCustomMethodPointer : public CallableCustomMethodPointerBase {
struct Data {
T *instance;
+#ifdef DEBUG_ENABLED
+ uint64_t object_id;
+#endif
void (T::*method)(P...);
} data;
public:
- virtual ObjectID get_object() const { return data.instance->get_instance_id(); }
+ virtual ObjectID get_object() const {
+#ifdef DEBUG_ENABLED
+ if (ObjectDB::get_instance(ObjectID(data.object_id)) == nullptr) {
+ return ObjectID();
+ }
+#endif
+ return data.instance->get_instance_id();
+ }
virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const {
+#ifdef DEBUG_ENABLED
+ ERR_FAIL_COND_MSG(ObjectDB::get_instance(ObjectID(data.object_id)) == nullptr, "Invalid Object id '" + uitos(data.object_id) + "', can't call method.");
+#endif
call_with_variant_args(data.instance, data.method, p_arguments, p_argcount, r_call_error);
}
CallableCustomMethodPointer(T *p_instance, void (T::*p_method)(P...)) {
zeromem(&data, sizeof(Data)); // Clear beforehand, may have padding bytes.
data.instance = p_instance;
+#ifdef DEBUG_ENABLED
+ data.object_id = p_instance->get_instance_id();
+#endif
data.method = p_method;
_setup((uint32_t *)&data, sizeof(Data));
}
@@ -242,20 +258,36 @@ template <class T, class R, class... P>
class CallableCustomMethodPointerRet : public CallableCustomMethodPointerBase {
struct Data {
T *instance;
+#ifdef DEBUG_ENABLED
+ uint64_t object_id;
+#endif
R(T::*method)
(P...);
} data;
public:
- virtual ObjectID get_object() const { return data.instance->get_instance_id(); }
+ virtual ObjectID get_object() const {
+#ifdef DEBUG_ENABLED
+ if (ObjectDB::get_instance(ObjectID(data.object_id)) == nullptr) {
+ return ObjectID();
+ }
+#endif
+ return data.instance->get_instance_id();
+ }
virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const {
+#ifdef DEBUG_ENABLED
+ ERR_FAIL_COND_MSG(ObjectDB::get_instance(ObjectID(data.object_id)) == nullptr, "Invalid Object id '" + uitos(data.object_id) + "', can't call method.");
+#endif
call_with_variant_args_ret(data.instance, data.method, p_arguments, p_argcount, r_return_value, r_call_error);
}
CallableCustomMethodPointerRet(T *p_instance, R (T::*p_method)(P...)) {
zeromem(&data, sizeof(Data)); // Clear beforehand, may have padding bytes.
data.instance = p_instance;
+#ifdef DEBUG_ENABLED
+ data.object_id = p_instance->get_instance_id();
+#endif
data.method = p_method;
_setup((uint32_t *)&data, sizeof(Data));
}
diff --git a/core/message_queue.cpp b/core/message_queue.cpp
index 8c71f760b2..6dcf24e7ed 100644
--- a/core/message_queue.cpp
+++ b/core/message_queue.cpp
@@ -155,6 +155,21 @@ Error MessageQueue::push_callable(const Callable &p_callable, const Variant **p_
return OK;
}
+Error MessageQueue::push_callable(const Callable &p_callable, VARIANT_ARG_DECLARE) {
+ VARIANT_ARGPTRS;
+
+ int argc = 0;
+
+ for (int i = 0; i < VARIANT_ARG_MAX; i++) {
+ if (argptr[i]->get_type() == Variant::NIL) {
+ break;
+ }
+ argc++;
+ }
+
+ return push_callable(p_callable, argptr, argc);
+}
+
void MessageQueue::statistics() {
Map<StringName, int> set_count;
Map<int, int> notify_count;
diff --git a/core/message_queue.h b/core/message_queue.h
index 8e50f1b2b7..7d13e26208 100644
--- a/core/message_queue.h
+++ b/core/message_queue.h
@@ -79,6 +79,7 @@ public:
Error push_notification(ObjectID p_id, int p_notification);
Error push_set(ObjectID p_id, const StringName &p_prop, const Variant &p_value);
Error push_callable(const Callable &p_callable, const Variant **p_args, int p_argcount, bool p_show_error = false);
+ Error push_callable(const Callable &p_callable, VARIANT_ARG_LIST);
Error push_call(Object *p_object, const StringName &p_method, VARIANT_ARG_LIST);
Error push_notification(Object *p_object, int p_notification);
diff --git a/core/oa_hash_map.h b/core/oa_hash_map.h
index c595e445d5..775e17fdb5 100644
--- a/core/oa_hash_map.h
+++ b/core/oa_hash_map.h
@@ -48,17 +48,19 @@
*
* Only used keys and values are constructed. For free positions there's space
* in the arrays for each, but that memory is kept uninitialized.
+ *
+ * The assignment operator copy the pairs from one map to the other.
*/
template <class TKey, class TValue,
class Hasher = HashMapHasherDefault,
class Comparator = HashMapComparatorDefault<TKey>>
class OAHashMap {
private:
- TValue *values;
- TKey *keys;
- uint32_t *hashes;
+ TValue *values = nullptr;
+ TKey *keys = nullptr;
+ uint32_t *hashes = nullptr;
- uint32_t capacity;
+ uint32_t capacity = 0;
uint32_t num_elements = 0;
@@ -142,7 +144,9 @@ private:
void _resize_and_rehash(uint32_t p_new_capacity) {
uint32_t old_capacity = capacity;
- capacity = p_new_capacity;
+
+ // Capacity can't be 0.
+ capacity = MAX(1, p_new_capacity);
TKey *old_keys = keys;
TValue *old_values = values;
@@ -157,6 +161,11 @@ private:
hashes[i] = 0;
}
+ if (old_capacity == 0) {
+ // Nothing to do.
+ return;
+ }
+
for (uint32_t i = 0; i < old_capacity; i++) {
if (old_hashes[i] == EMPTY_HASH) {
continue;
@@ -341,17 +350,32 @@ public:
return it;
}
- OAHashMap(const OAHashMap &) = delete; // Delete the copy constructor so we don't get unexpected copies and dangling pointers.
- OAHashMap &operator=(const OAHashMap &) = delete; // Same for assignment operator.
+ OAHashMap(const OAHashMap &p_other) {
+ (*this) = p_other;
+ }
+
+ OAHashMap &operator=(const OAHashMap &p_other) {
+ if (capacity != 0) {
+ clear();
+ }
+
+ _resize_and_rehash(p_other.capacity);
+
+ for (Iterator it = p_other.iter(); it.valid; it = p_other.next_iter(it)) {
+ set(*it.key, *it.value);
+ }
+ return *this;
+ }
OAHashMap(uint32_t p_initial_capacity = 64) {
- capacity = p_initial_capacity;
+ // Capacity can't be 0.
+ capacity = MAX(1, p_initial_capacity);
keys = static_cast<TKey *>(Memory::alloc_static(sizeof(TKey) * capacity));
values = static_cast<TValue *>(Memory::alloc_static(sizeof(TValue) * capacity));
hashes = static_cast<uint32_t *>(Memory::alloc_static(sizeof(uint32_t) * capacity));
- for (uint32_t i = 0; i < p_initial_capacity; i++) {
+ for (uint32_t i = 0; i < capacity; i++) {
hashes[i] = EMPTY_HASH;
}
}
diff --git a/core/project_settings.cpp b/core/project_settings.cpp
index 83d94ad607..5247f6da40 100644
--- a/core/project_settings.cpp
+++ b/core/project_settings.cpp
@@ -295,10 +295,16 @@ void ProjectSettings::_convert_to_last_version(int p_from_version) {
* using the following merit order:
* - If using NetworkClient, try to lookup project file or fail.
* - If --main-pack was passed by the user (`p_main_pack`), load it or fail.
- * - Search for .pck file matching binary name. There are two possibilities:
- * o exec_path.get_basename() + '.pck' (e.g. 'win_game.exe' -> 'win_game.pck')
- * o exec_path + '.pck' (e.g. 'linux_game' -> 'linux_game.pck')
- * For each tentative, if the file exists, load it or fail.
+ * - Search for project PCKs automatically. For each step we try loading a potential
+ * PCK, and if it doesn't work, we proceed to the next step. If any step succeeds,
+ * we try loading the project settings, and abort if it fails. Steps:
+ * o Bundled PCK in the executable.
+ * o [macOS only] PCK with same basename as the binary in the .app resource dir.
+ * o PCK with same basename as the binary in the binary's directory. We handle both
+ * changing the extension to '.pck' (e.g. 'win_game.exe' -> 'win_game.pck') and
+ * appending '.pck' to the binary name (e.g. 'linux_game' -> 'linux_game.pck').
+ * o PCK with the same basename as the binary in the current working directory.
+ * Same as above for the two possible PCK file names.
* - On relevant platforms (Android/iOS), lookup project file in OS resource path.
* If found, load it or fail.
* - Lookup project file in passed `p_path` (--path passed by the user), i.e. we
@@ -339,65 +345,68 @@ Error ProjectSettings::_setup(const String &p_path, const String &p_main_pack, b
String exec_path = OS::get_singleton()->get_executable_path();
if (exec_path != "") {
- // Attempt with exec_name.pck
- // (This is the usual case when distributing a Godot game.)
+ // We do several tests sequentially until one succeeds to find a PCK,
+ // and if so we attempt loading it at the end.
- // Based on the OS, it can be the exec path + '.pck' (Linux w/o extension, macOS in .app bundle)
- // or the exec path's basename + '.pck' (Windows).
- // We need to test both possibilities as extensions for Linux binaries are optional
- // (so both 'mygame.bin' and 'mygame' should be able to find 'mygame.pck').
+ // Attempt with PCK bundled into executable.
+ bool found = _load_resource_pack(exec_path);
+ // Attempt with exec_name.pck.
+ // (This is the usual case when distributing a Godot game.)
String exec_dir = exec_path.get_base_dir();
String exec_filename = exec_path.get_file();
String exec_basename = exec_filename.get_basename();
- // Attempt with PCK bundled into executable
- bool found = _load_resource_pack(exec_path);
+ // Based on the OS, it can be the exec path + '.pck' (Linux w/o extension, macOS in .app bundle)
+ // or the exec path's basename + '.pck' (Windows).
+ // We need to test both possibilities as extensions for Linux binaries are optional
+ // (so both 'mygame.bin' and 'mygame' should be able to find 'mygame.pck').
#ifdef OSX_ENABLED
if (!found) {
- // Attempt to load PCK from macOS .app bundle resources
+ // Attempt to load PCK from macOS .app bundle resources.
found = _load_resource_pack(OS::get_singleton()->get_bundle_resource_dir().plus_file(exec_basename + ".pck"));
}
#endif
if (!found) {
- // Try to load data pack at the location of the executable
- // As mentioned above, we have two potential names to attempt
+ // Try to load data pack at the location of the executable.
+ // As mentioned above, we have two potential names to attempt.
found = _load_resource_pack(exec_dir.plus_file(exec_basename + ".pck")) || _load_resource_pack(exec_dir.plus_file(exec_filename + ".pck"));
+ }
- if (!found) {
- // If we couldn't find them next to the executable, we attempt
- // the current working directory. Same story, two tests.
- found = _load_resource_pack(exec_basename + ".pck") || _load_resource_pack(exec_filename + ".pck");
- }
+ if (!found) {
+ // If we couldn't find them next to the executable, we attempt
+ // the current working directory. Same story, two tests.
+ found = _load_resource_pack(exec_basename + ".pck") || _load_resource_pack(exec_filename + ".pck");
}
- // If we opened our package, try and load our project
+ // If we opened our package, try and load our project.
if (found) {
Error err = _load_settings_text_or_binary("res://project.godot", "res://project.binary");
if (err == OK) {
- // Load override from location of executable
- // Optional, we don't mind if it fails
+ // Load override from location of the executable.
+ // Optional, we don't mind if it fails.
_load_settings_text(exec_path.get_base_dir().plus_file("override.cfg"));
}
return err;
}
}
- // Try to use the filesystem for files, according to OS. (only Android -when reading from pck- and iOS use this)
+ // Try to use the filesystem for files, according to OS.
+ // (Only Android -when reading from pck- and iOS use this.)
if (OS::get_singleton()->get_resource_dir() != "") {
// OS will call ProjectSettings->get_resource_path which will be empty if not overridden!
// If the OS would rather use a specific location, then it will not be empty.
resource_path = OS::get_singleton()->get_resource_dir().replace("\\", "/");
if (resource_path != "" && resource_path[resource_path.length() - 1] == '/') {
- resource_path = resource_path.substr(0, resource_path.length() - 1); // chop end
+ resource_path = resource_path.substr(0, resource_path.length() - 1); // Chop end.
}
Error err = _load_settings_text_or_binary("res://project.godot", "res://project.binary");
if (err == OK) {
- // Optional, we don't mind if it fails
+ // Optional, we don't mind if it fails.
_load_settings_text("res://override.cfg");
}
return err;
@@ -418,7 +427,7 @@ Error ProjectSettings::_setup(const String &p_path, const String &p_main_pack, b
while (true) {
err = _load_settings_text_or_binary(current_dir.plus_file("project.godot"), current_dir.plus_file("project.binary"));
if (err == OK) {
- // Optional, we don't mind if it fails
+ // Optional, we don't mind if it fails.
_load_settings_text(current_dir.plus_file("override.cfg"));
candidate = current_dir;
found = true;
@@ -438,7 +447,7 @@ Error ProjectSettings::_setup(const String &p_path, const String &p_main_pack, b
}
resource_path = candidate;
- resource_path = resource_path.replace("\\", "/"); // windows path to unix path just in case
+ resource_path = resource_path.replace("\\", "/"); // Windows path to Unix path just in case.
memdelete(d);
if (!found) {
@@ -446,7 +455,7 @@ Error ProjectSettings::_setup(const String &p_path, const String &p_main_pack, b
}
if (resource_path.length() && resource_path[resource_path.length() - 1] == '/') {
- resource_path = resource_path.substr(0, resource_path.length() - 1); // chop end
+ resource_path = resource_path.substr(0, resource_path.length() - 1); // Chop end.
}
return OK;
diff --git a/editor/SCsub b/editor/SCsub
index 13ae85bbf0..651dd5fffd 100644
--- a/editor/SCsub
+++ b/editor/SCsub
@@ -6,6 +6,7 @@ env.editor_sources = []
import os
import os.path
+import glob
from platform_methods import run_in_subprocess
import editor_builders
@@ -40,20 +41,21 @@ if env["tools"]:
f.write(reg_exporters_inc)
f.write(reg_exporters)
- # API documentation
+ # Core API documentation.
docs = []
- doc_dirs = ["doc/classes"]
+ docs += Glob("#doc/classes/*.xml")
- for p in env.doc_class_path.values():
- if p not in doc_dirs:
- doc_dirs.append(p)
+ # Module API documentation.
+ module_dirs = []
+ for d in env.doc_class_path.values():
+ if d not in module_dirs:
+ module_dirs.append(d)
- for d in doc_dirs:
- try:
- for f in os.listdir(os.path.join(env.Dir("#").abspath, d)):
- docs.append("#" + os.path.join(d, f))
- except OSError:
- pass
+ for d in module_dirs:
+ if not os.path.isabs(d):
+ docs += Glob("#" + d + "/*.xml") # Built-in.
+ else:
+ docs += Glob(d + "/*.xml") # Custom.
_make_doc_data_class_path(os.path.join(env.Dir("#").abspath, "editor"))
@@ -61,8 +63,6 @@ if env["tools"]:
env.Depends("#editor/doc_data_compressed.gen.h", docs)
env.CommandNoCache("#editor/doc_data_compressed.gen.h", docs, run_in_subprocess(editor_builders.make_doc_header))
- import glob
-
path = env.Dir(".").abspath
# Editor translations
diff --git a/editor/animation_track_editor.cpp b/editor/animation_track_editor.cpp
index 2a8e0d856e..75e7542abb 100644
--- a/editor/animation_track_editor.cpp
+++ b/editor/animation_track_editor.cpp
@@ -4882,12 +4882,12 @@ void AnimationTrackEditor::_box_selection_draw() {
void AnimationTrackEditor::_scroll_input(const Ref<InputEvent> &p_event) {
Ref<InputEventMouseButton> mb = p_event;
- if (mb.is_valid() && mb->is_pressed() && mb->get_command() && mb->get_button_index() == BUTTON_WHEEL_DOWN) {
+ if (mb.is_valid() && mb->is_pressed() && mb->get_command() && mb->get_button_index() == BUTTON_WHEEL_UP) {
timeline->get_zoom()->set_value(timeline->get_zoom()->get_value() * 1.05);
scroll->accept_event();
}
- if (mb.is_valid() && mb->is_pressed() && mb->get_command() && mb->get_button_index() == BUTTON_WHEEL_UP) {
+ if (mb.is_valid() && mb->is_pressed() && mb->get_command() && mb->get_button_index() == BUTTON_WHEEL_DOWN) {
timeline->get_zoom()->set_value(timeline->get_zoom()->get_value() / 1.05);
scroll->accept_event();
}
diff --git a/editor/editor_feature_profile.cpp b/editor/editor_feature_profile.cpp
index d3749477cc..2a410c03e7 100644
--- a/editor/editor_feature_profile.cpp
+++ b/editor/editor_feature_profile.cpp
@@ -29,6 +29,7 @@
/*************************************************************************/
#include "editor_feature_profile.h"
+
#include "core/io/json.h"
#include "core/os/dir_access.h"
#include "editor/editor_settings.h"
@@ -353,7 +354,7 @@ void EditorFeatureProfileManager::_update_profile_list(const String &p_select_pr
}
if (name == current_profile) {
- name += " (current)";
+ name += " " + TTR("(current)");
}
profile_list->add_item(name);
int index = profile_list->get_item_count() - 1;
@@ -363,12 +364,15 @@ void EditorFeatureProfileManager::_update_profile_list(const String &p_select_pr
}
}
+ class_list_vbc->set_visible(selected_profile != String());
+ property_list_vbc->set_visible(selected_profile != String());
+ no_profile_selected_help->set_visible(selected_profile == String());
profile_actions[PROFILE_CLEAR]->set_disabled(current_profile == String());
profile_actions[PROFILE_ERASE]->set_disabled(selected_profile == String());
profile_actions[PROFILE_EXPORT]->set_disabled(selected_profile == String());
profile_actions[PROFILE_SET]->set_disabled(selected_profile == String());
- current_profile_name->set_text(current_profile);
+ current_profile_name->set_text(current_profile != String() ? current_profile : TTR("(none)"));
_update_selected_profile();
}
@@ -451,6 +455,10 @@ void EditorFeatureProfileManager::_create_new_profile() {
new_profile->save_to_file(file);
_update_profile_list(name);
+ // The newly created profile is the first one, make it the current profile automatically.
+ if (profile_list->get_item_count() == 1) {
+ _profile_action(PROFILE_SET);
+ }
}
void EditorFeatureProfileManager::_profile_selected(int p_what) {
@@ -730,6 +738,10 @@ void EditorFeatureProfileManager::_import_profiles(const Vector<String> &p_paths
}
_update_profile_list();
+ // The newly imported profile is the first one, make it the current profile automatically.
+ if (profile_list->get_item_count() == 1) {
+ _profile_action(PROFILE_SET);
+ }
}
void EditorFeatureProfileManager::_export_profile(const String &p_path) {
@@ -779,6 +791,7 @@ EditorFeatureProfileManager::EditorFeatureProfileManager() {
HBoxContainer *name_hbc = memnew(HBoxContainer);
current_profile_name = memnew(LineEdit);
name_hbc->add_child(current_profile_name);
+ current_profile_name->set_text(TTR("(none)"));
current_profile_name->set_editable(false);
current_profile_name->set_h_size_flags(Control::SIZE_EXPAND_FILL);
profile_actions[PROFILE_CLEAR] = memnew(Button(TTR("Unset")));
@@ -827,7 +840,7 @@ EditorFeatureProfileManager::EditorFeatureProfileManager() {
h_split->set_v_size_flags(Control::SIZE_EXPAND_FILL);
main_vbc->add_child(h_split);
- VBoxContainer *class_list_vbc = memnew(VBoxContainer);
+ class_list_vbc = memnew(VBoxContainer);
h_split->add_child(class_list_vbc);
class_list_vbc->set_h_size_flags(Control::SIZE_EXPAND_FILL);
@@ -837,17 +850,30 @@ EditorFeatureProfileManager::EditorFeatureProfileManager() {
class_list->set_edit_checkbox_cell_only_when_checkbox_is_pressed(true);
class_list->connect("cell_selected", callable_mp(this, &EditorFeatureProfileManager::_class_list_item_selected));
class_list->connect("item_edited", callable_mp(this, &EditorFeatureProfileManager::_class_list_item_edited), varray(), CONNECT_DEFERRED);
+ // It will be displayed once the user creates or chooses a profile.
+ class_list_vbc->hide();
- VBoxContainer *property_list_vbc = memnew(VBoxContainer);
+ property_list_vbc = memnew(VBoxContainer);
h_split->add_child(property_list_vbc);
property_list_vbc->set_h_size_flags(Control::SIZE_EXPAND_FILL);
property_list = memnew(Tree);
- property_list_vbc->add_margin_child(TTR("Class Options"), property_list, true);
+ property_list_vbc->add_margin_child(TTR("Class Options:"), property_list, true);
property_list->set_hide_root(true);
property_list->set_hide_folding(true);
property_list->set_edit_checkbox_cell_only_when_checkbox_is_pressed(true);
property_list->connect("item_edited", callable_mp(this, &EditorFeatureProfileManager::_property_item_edited), varray(), CONNECT_DEFERRED);
+ // It will be displayed once the user creates or chooses a profile.
+ property_list_vbc->hide();
+
+ no_profile_selected_help = memnew(Label(TTR("Create or import a profile to edit available classes and properties.")));
+ // Add some spacing above the help label.
+ Ref<StyleBoxEmpty> sb = memnew(StyleBoxEmpty);
+ sb->set_default_margin(MARGIN_TOP, 20 * EDSCALE);
+ no_profile_selected_help->add_theme_style_override("normal", sb);
+ no_profile_selected_help->set_align(Label::ALIGN_CENTER);
+ no_profile_selected_help->set_v_size_flags(Control::SIZE_EXPAND_FILL);
+ h_split->add_child(no_profile_selected_help);
new_profile_dialog = memnew(ConfirmationDialog);
new_profile_dialog->set_title(TTR("New profile name:"));
diff --git a/editor/editor_feature_profile.h b/editor/editor_feature_profile.h
index 4036ec7ec6..38413e35a2 100644
--- a/editor/editor_feature_profile.h
+++ b/editor/editor_feature_profile.h
@@ -120,8 +120,11 @@ class EditorFeatureProfileManager : public AcceptDialog {
HSplitContainer *h_split;
+ VBoxContainer *class_list_vbc;
Tree *class_list;
+ VBoxContainer *property_list_vbc;
Tree *property_list;
+ Label *no_profile_selected_help;
EditorFileDialog *import_profiles;
EditorFileDialog *export_profile;
diff --git a/editor/icons/SCsub b/editor/icons/SCsub
index f0d51999f0..e143276259 100644
--- a/editor/icons/SCsub
+++ b/editor/icons/SCsub
@@ -2,6 +2,8 @@
Import("env")
+import os
+
from platform_methods import run_in_subprocess
import editor_icons_builders
@@ -15,7 +17,10 @@ env["BUILDERS"]["MakeEditorIconsBuilder"] = make_editor_icons_builder
icon_sources = Glob("*.svg")
# Module icons
-for module_icons in env.module_icons_paths:
- icon_sources += Glob("#" + module_icons + "/*.svg")
+for path in env.module_icons_paths:
+ if not os.path.isabs(path):
+ icon_sources += Glob("#" + path + "/*.svg") # Built-in.
+ else:
+ icon_sources += Glob(path + "/*.svg") # Custom.
env.Alias("editor_icons", [env.MakeEditorIconsBuilder("#editor/editor_icons.gen.h", icon_sources)])
diff --git a/main/main.cpp b/main/main.cpp
index f05032e68c..94dd895a26 100644
--- a/main/main.cpp
+++ b/main/main.cpp
@@ -1645,7 +1645,11 @@ bool Main::start() {
print_line("Loading docs...");
for (int i = 0; i < _doc_data_class_path_count; i++) {
- String path = doc_tool.plus_file(_doc_data_class_paths[i].path);
+ // Custom modules are always located by absolute path.
+ String path = _doc_data_class_paths[i].path;
+ if (path.is_rel_path()) {
+ path = doc_tool.plus_file(path);
+ }
String name = _doc_data_class_paths[i].name;
doc_data_classes[name] = path;
if (!checked_paths.has(path)) {
diff --git a/main/tests/test_oa_hash_map.cpp b/main/tests/test_oa_hash_map.cpp
index 719817baf4..9182f66b61 100644
--- a/main/tests/test_oa_hash_map.cpp
+++ b/main/tests/test_oa_hash_map.cpp
@@ -210,6 +210,89 @@ MainLoop *test() {
}
}
+ // Test map with 0 capacity.
+ {
+ OAHashMap<int, String> original_map(0);
+ original_map.set(1, "1");
+ OS::get_singleton()->print("OAHashMap 0 capacity initialization passed.\n");
+ }
+
+ // Test copy constructor.
+ {
+ OAHashMap<int, String> original_map;
+ original_map.set(1, "1");
+ original_map.set(2, "2");
+ original_map.set(3, "3");
+ original_map.set(4, "4");
+ original_map.set(5, "5");
+
+ OAHashMap<int, String> map_copy(original_map);
+
+ bool pass = true;
+ for (
+ OAHashMap<int, String>::Iterator it = original_map.iter();
+ it.valid;
+ it = original_map.next_iter(it)) {
+ if (map_copy.lookup_ptr(*it.key) == nullptr) {
+ pass = false;
+ }
+ if (*it.value != *map_copy.lookup_ptr(*it.key)) {
+ pass = false;
+ }
+ }
+ if (pass) {
+ OS::get_singleton()->print("OAHashMap copy constructor test passed.\n");
+ } else {
+ OS::get_singleton()->print("OAHashMap copy constructor test FAILED.\n");
+ }
+
+ map_copy.set(1, "Random String");
+ if (*map_copy.lookup_ptr(1) == *original_map.lookup_ptr(1)) {
+ OS::get_singleton()->print("OAHashMap copy constructor, atomic copy test FAILED.\n");
+ } else {
+ OS::get_singleton()->print("OAHashMap copy constructor, atomic copy test passed.\n");
+ }
+ }
+
+ // Test assign operator.
+ {
+ OAHashMap<int, String> original_map;
+ original_map.set(1, "1");
+ original_map.set(2, "2");
+ original_map.set(3, "3");
+ original_map.set(4, "4");
+ original_map.set(5, "5");
+
+ OAHashMap<int, String> map_copy(100000);
+ map_copy.set(1, "Just a string.");
+ map_copy = original_map;
+
+ bool pass = true;
+ for (
+ OAHashMap<int, String>::Iterator it = map_copy.iter();
+ it.valid;
+ it = map_copy.next_iter(it)) {
+ if (original_map.lookup_ptr(*it.key) == nullptr) {
+ pass = false;
+ }
+ if (*it.value != *original_map.lookup_ptr(*it.key)) {
+ pass = false;
+ }
+ }
+ if (pass) {
+ OS::get_singleton()->print("OAHashMap assign operation test passed.\n");
+ } else {
+ OS::get_singleton()->print("OAHashMap assign operation test FAILED.\n");
+ }
+
+ map_copy.set(1, "Random String");
+ if (*map_copy.lookup_ptr(1) == *original_map.lookup_ptr(1)) {
+ OS::get_singleton()->print("OAHashMap assign operation atomic copy test FAILED.\n");
+ } else {
+ OS::get_singleton()->print("OAHashMap assign operation atomic copy test passed.\n");
+ }
+ }
+
return nullptr;
}
diff --git a/methods.py b/methods.py
index 805ae256c3..46b58a13cd 100644
--- a/methods.py
+++ b/methods.py
@@ -137,37 +137,47 @@ def parse_cg_file(fname, uniforms, sizes, conditionals):
fs.close()
-def detect_modules():
+def detect_modules(at_path):
+ module_list = {} # name : path
- module_list = []
+ modules_glob = os.path.join(at_path, "*")
+ files = glob.glob(modules_glob)
+ files.sort() # so register_module_types does not change that often, and also plugins are registered in alphabetic order
+
+ for x in files:
+ if not is_module(x):
+ continue
+ name = os.path.basename(x)
+ path = x.replace("\\", "/") # win32
+ module_list[name] = path
+
+ return module_list
+
+
+def is_module(path):
+ return os.path.isdir(path) and os.path.exists(path + "/config.py")
+
+
+def write_modules(module_list):
includes_cpp = ""
+ preregister_cpp = ""
register_cpp = ""
unregister_cpp = ""
- preregister_cpp = ""
- files = glob.glob("modules/*")
- files.sort() # so register_module_types does not change that often, and also plugins are registered in alphabetic order
- for x in files:
- if not os.path.isdir(x):
- continue
- if not os.path.exists(x + "/config.py"):
- continue
- x = x.replace("modules/", "") # rest of world
- x = x.replace("modules\\", "") # win32
- module_list.append(x)
+ for name, path in module_list.items():
try:
- with open("modules/" + x + "/register_types.h"):
- includes_cpp += '#include "modules/' + x + '/register_types.h"\n'
- register_cpp += "#ifdef MODULE_" + x.upper() + "_ENABLED\n"
- register_cpp += "\tregister_" + x + "_types();\n"
- register_cpp += "#endif\n"
- preregister_cpp += "#ifdef MODULE_" + x.upper() + "_ENABLED\n"
- preregister_cpp += "#ifdef MODULE_" + x.upper() + "_HAS_PREREGISTER\n"
- preregister_cpp += "\tpreregister_" + x + "_types();\n"
+ with open(os.path.join(path, "register_types.h")):
+ includes_cpp += '#include "' + path + '/register_types.h"\n'
+ preregister_cpp += "#ifdef MODULE_" + name.upper() + "_ENABLED\n"
+ preregister_cpp += "#ifdef MODULE_" + name.upper() + "_HAS_PREREGISTER\n"
+ preregister_cpp += "\tpreregister_" + name + "_types();\n"
preregister_cpp += "#endif\n"
preregister_cpp += "#endif\n"
- unregister_cpp += "#ifdef MODULE_" + x.upper() + "_ENABLED\n"
- unregister_cpp += "\tunregister_" + x + "_types();\n"
+ register_cpp += "#ifdef MODULE_" + name.upper() + "_ENABLED\n"
+ register_cpp += "\tregister_" + name + "_types();\n"
+ register_cpp += "#endif\n"
+ unregister_cpp += "#ifdef MODULE_" + name.upper() + "_ENABLED\n"
+ unregister_cpp += "\tunregister_" + name + "_types();\n"
unregister_cpp += "#endif\n"
except IOError:
pass
@@ -202,7 +212,18 @@ void unregister_module_types() {
with open("modules/register_module_types.gen.cpp", "w") as f:
f.write(modules_cpp)
- return module_list
+
+def convert_custom_modules_path(path):
+ if not path:
+ return path
+ err_msg = "Build option 'custom_modules' must %s"
+ if not os.path.isdir(path):
+ raise ValueError(err_msg % "point to an existing directory.")
+ if os.path.realpath(path) == os.path.realpath("modules"):
+ raise ValueError(err_msg % "be a directory other than built-in `modules` directory.")
+ if is_module(path):
+ raise ValueError(err_msg % "point to a directory with modules, not a single module.")
+ return os.path.realpath(os.path.expanduser(path))
def disable_module(self):
diff --git a/modules/SCsub b/modules/SCsub
index fb46c5f877..9155a53eaf 100644
--- a/modules/SCsub
+++ b/modules/SCsub
@@ -3,6 +3,7 @@
Import("env")
import modules_builders
+import os
env_modules = env.Clone()
@@ -13,16 +14,20 @@ env.CommandNoCache("modules_enabled.gen.h", Value(env.module_list), modules_buil
vs_sources = []
# libmodule_<name>.a for each active module.
-for module in env.module_list:
+for name, path in env.module_list.items():
env.modules_sources = []
- SConscript(module + "/SCsub")
+
+ if not os.path.isabs(path):
+ SConscript(name + "/SCsub") # Built-in.
+ else:
+ SConscript(path + "/SCsub") # Custom.
# Some modules are not linked automatically but can be enabled optionally
# on iOS, so we handle those specially.
- if env["platform"] == "iphone" and module in ["arkit", "camera"]:
+ if env["platform"] == "iphone" and name in ["arkit", "camera"]:
continue
- lib = env_modules.add_library("module_%s" % module, env.modules_sources)
+ lib = env_modules.add_library("module_%s" % name, env.modules_sources)
env.Prepend(LIBS=[lib])
if env["vsproj"]:
vs_sources += env.modules_sources
diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp
index 7433c4a5bc..50d8289fd1 100644
--- a/modules/gdscript/gdscript_editor.cpp
+++ b/modules/gdscript/gdscript_editor.cpp
@@ -2082,7 +2082,11 @@ static void _find_identifiers_in_base(const GDScriptCompletionContext &p_context
if (!p_only_functions) {
List<PropertyInfo> members;
- tmp.get_property_list(&members);
+ if (p_base.value.get_type() != Variant::NIL) {
+ p_base.value.get_property_list(&members);
+ } else {
+ tmp.get_property_list(&members);
+ }
for (List<PropertyInfo>::Element *E = members.front(); E; E = E->next()) {
if (String(E->get().name).find("/") == -1) {
diff --git a/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs b/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs
index eb7696685f..c874025be0 100644
--- a/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs
@@ -421,7 +421,7 @@ namespace GodotTools
aboutLabel.Text =
"C# support in Godot Engine is in late alpha stage and, while already usable, " +
"it is not meant for use in production.\n\n" +
- "Projects can be exported to Linux, macOS, Windows and Android, but not yet to iOS, HTML5 or UWP. " +
+ "Projects can be exported to Linux, macOS, Windows, Android, iOS and HTML5, but not yet to UWP. " +
"Bugs and usability issues will be addressed gradually over future releases, " +
"potentially including compatibility breaking changes as new features are implemented for a better overall C# experience.\n\n" +
"If you experience issues with this Mono build, please report them on Godot's issue tracker with details about your system, MSBuild version, IDE, etc.:\n\n" +
diff --git a/platform/android/display_server_android.cpp b/platform/android/display_server_android.cpp
index c5b06827b2..1436d832de 100644
--- a/platform/android/display_server_android.cpp
+++ b/platform/android/display_server_android.cpp
@@ -367,6 +367,25 @@ void DisplayServerAndroid::register_android_driver() {
register_create_function("android", create_func, get_rendering_drivers_func);
}
+void DisplayServerAndroid::reset_window() {
+#if defined(VULKAN_ENABLED)
+ if (rendering_driver == "vulkan") {
+ ANativeWindow *native_window = OS_Android::get_singleton()->get_native_window();
+ ERR_FAIL_COND(!native_window);
+
+ ERR_FAIL_COND(!context_vulkan);
+ context_vulkan->window_destroy(MAIN_WINDOW_ID);
+
+ Size2i display_size = OS_Android::get_singleton()->get_display_size();
+ if (context_vulkan->window_create(native_window, display_size.width, display_size.height) == -1) {
+ memdelete(context_vulkan);
+ context_vulkan = nullptr;
+ ERR_FAIL_MSG("Failed to reset Vulkan window.");
+ }
+ }
+#endif
+}
+
DisplayServerAndroid::DisplayServerAndroid(const String &p_rendering_driver, DisplayServer::WindowMode p_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) {
rendering_driver = p_rendering_driver;
diff --git a/platform/android/display_server_android.h b/platform/android/display_server_android.h
index 199371d08d..d64542df58 100644
--- a/platform/android/display_server_android.h
+++ b/platform/android/display_server_android.h
@@ -166,6 +166,8 @@ public:
static Vector<String> get_rendering_drivers_func();
static void register_android_driver();
+ void reset_window();
+
DisplayServerAndroid(const String &p_rendering_driver, WindowMode p_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error);
~DisplayServerAndroid();
};
diff --git a/platform/android/export/export.cpp b/platform/android/export/export.cpp
index dfaaf68b69..1bd198ccc0 100644
--- a/platform/android/export/export.cpp
+++ b/platform/android/export/export.cpp
@@ -254,6 +254,8 @@ class EditorExportPlatformAndroid : public EditorExportPlatform {
};
Vector<PluginConfig> plugins;
+ String last_plugin_names;
+ uint64_t last_custom_build_time = 0;
volatile bool plugins_changed;
Mutex plugins_lock;
Vector<Device> devices;
@@ -1831,6 +1833,29 @@ public:
return list;
}
+ inline bool is_clean_build_required(Vector<PluginConfig> enabled_plugins) {
+ String plugin_names = get_plugins_names(enabled_plugins);
+ bool first_build = last_custom_build_time == 0;
+ bool have_plugins_changed = false;
+
+ if (!first_build) {
+ have_plugins_changed = plugin_names != last_plugin_names;
+ if (!have_plugins_changed) {
+ for (int i = 0; i < enabled_plugins.size(); i++) {
+ if (enabled_plugins.get(i).last_updated > last_custom_build_time) {
+ have_plugins_changed = true;
+ break;
+ }
+ }
+ }
+ }
+
+ last_custom_build_time = OS::get_singleton()->get_unix_time();
+ last_plugin_names = plugin_names;
+
+ return have_plugins_changed || first_build;
+ }
+
virtual Error export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags = 0) {
ExportNotifier notifier(*this, p_preset, p_debug, p_path, p_flags);
@@ -1877,8 +1902,12 @@ public:
String local_plugins_binaries = get_plugins_binaries(BINARY_TYPE_LOCAL, enabled_plugins);
String remote_plugins_binaries = get_plugins_binaries(BINARY_TYPE_REMOTE, enabled_plugins);
String custom_maven_repos = get_plugins_custom_maven_repos(enabled_plugins);
+ bool clean_build_required = is_clean_build_required(enabled_plugins);
List<String> cmdline;
+ if (clean_build_required) {
+ cmdline.push_back("clean");
+ }
cmdline.push_back("build");
cmdline.push_back("-Pexport_package_name=" + package_name); // argument to specify the package name.
cmdline.push_back("-Pplugins_local_binaries=" + local_plugins_binaries); // argument to specify the list of plugins local dependencies.
diff --git a/platform/android/java/app/build.gradle b/platform/android/java/app/build.gradle
index ea341b37b1..19202d2310 100644
--- a/platform/android/java/app/build.gradle
+++ b/platform/android/java/app/build.gradle
@@ -75,6 +75,11 @@ android {
}
defaultConfig {
+ // The default ignore pattern for the 'assets' directory includes hidden files and directories which are used by Godot projects.
+ aaptOptions {
+ ignoreAssetsPattern "!.svn:!.git:!.ds_store:!*.scc:<dir>_*:!CVS:!thumbs.db:!picasa.ini:!*~"
+ }
+
// Feel free to modify the application id to your own.
applicationId getExportPackageName()
minSdkVersion versions.minSdk
diff --git a/platform/android/java/lib/src/org/godotengine/godot/GodotLib.java b/platform/android/java/lib/src/org/godotengine/godot/GodotLib.java
index 72198ba123..3693f36557 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/GodotLib.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/GodotLib.java
@@ -66,11 +66,12 @@ public class GodotLib {
/**
* Invoked on the GL thread when the underlying Android surface has changed size.
- * @param width
- * @param height
+ * @param p_surface
+ * @param p_width
+ * @param p_height
* @see android.opengl.GLSurfaceView.Renderer#onSurfaceChanged(GL10, int, int)
*/
- public static native void resize(int width, int height);
+ public static native void resize(Surface p_surface, int p_width, int p_height);
/**
* Invoked on the render thread when the underlying Android surface is created or recreated.
@@ -189,7 +190,7 @@ public class GodotLib {
* @param p_method Name of the method to invoke
* @param p_params Parameters to use for method invocation
*/
- public static native void callobject(int p_id, String p_method, Object[] p_params);
+ public static native void callobject(long p_id, String p_method, Object[] p_params);
/**
* Invoke method |p_method| on the Godot object specified by |p_id| during idle time.
@@ -197,7 +198,7 @@ public class GodotLib {
* @param p_method Name of the method to invoke
* @param p_params Parameters to use for method invocation
*/
- public static native void calldeferred(int p_id, String p_method, Object[] p_params);
+ public static native void calldeferred(long p_id, String p_method, Object[] p_params);
/**
* Forward the results from a permission request.
diff --git a/platform/android/java/lib/src/org/godotengine/godot/GodotRenderer.java b/platform/android/java/lib/src/org/godotengine/godot/GodotRenderer.java
index 99d3662317..64395f7d1e 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/GodotRenderer.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/GodotRenderer.java
@@ -64,7 +64,7 @@ class GodotRenderer implements GLSurfaceView.Renderer {
}
public void onSurfaceChanged(GL10 gl, int width, int height) {
- GodotLib.resize(width, height);
+ GodotLib.resize(null, width, height);
for (GodotPlugin plugin : pluginRegistry.getAllPlugins()) {
plugin.onGLSurfaceChanged(gl, width, height);
}
diff --git a/platform/android/java/lib/src/org/godotengine/godot/vulkan/VkRenderer.kt b/platform/android/java/lib/src/org/godotengine/godot/vulkan/VkRenderer.kt
index 608ad48df9..aeb4628d5d 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/vulkan/VkRenderer.kt
+++ b/platform/android/java/lib/src/org/godotengine/godot/vulkan/VkRenderer.kt
@@ -59,9 +59,7 @@ internal class VkRenderer {
* Called when the surface is created and signals the beginning of rendering.
*/
fun onVkSurfaceCreated(surface: Surface) {
- // TODO: properly implement surface re-creation:
- // GodotLib.newcontext should be called here once it's done.
- //GodotLib.newcontext(surface, false)
+ GodotLib.newcontext(surface, false)
for (plugin in pluginRegistry.getAllPlugins()) {
plugin.onVkSurfaceCreated(surface)
@@ -72,12 +70,7 @@ internal class VkRenderer {
* Called after the surface is created and whenever its size changes.
*/
fun onVkSurfaceChanged(surface: Surface, width: Int, height: Int) {
- GodotLib.resize(width, height)
-
- // TODO: properly implement surface re-creation:
- // Update the native renderer instead of restarting the app.
- // GodotLib.newcontext should not be called here once it's done.
- GodotLib.newcontext(surface, false)
+ GodotLib.resize(surface, width, height)
for (plugin in pluginRegistry.getAllPlugins()) {
plugin.onVkSurfaceChanged(surface, width, height)
diff --git a/platform/android/java/plugins/godotpayment/src/main/java/org/godotengine/godot/plugin/payment/GodotPayment.java b/platform/android/java/plugins/godotpayment/src/main/java/org/godotengine/godot/plugin/payment/GodotPayment.java
index ded7f0a9aa..e2b12c94a4 100644
--- a/platform/android/java/plugins/godotpayment/src/main/java/org/godotengine/godot/plugin/payment/GodotPayment.java
+++ b/platform/android/java/plugins/godotpayment/src/main/java/org/godotengine/godot/plugin/payment/GodotPayment.java
@@ -48,7 +48,7 @@ import org.json.JSONException;
import org.json.JSONObject;
public class GodotPayment extends GodotPlugin {
- private Integer purchaseCallbackId = 0;
+ private Long purchaseCallbackId = 0L;
private String accessToken;
private String purchaseValidationUrlPrefix;
private String transactionId;
@@ -129,11 +129,11 @@ public class GodotPayment extends GodotPlugin {
GodotLib.calldeferred(purchaseCallbackId, "purchase_owned", new Object[] { sku });
}
- public int getPurchaseCallbackId() {
+ public long getPurchaseCallbackId() {
return purchaseCallbackId;
}
- public void setPurchaseCallbackId(int purchaseCallbackId) {
+ public void setPurchaseCallbackId(long purchaseCallbackId) {
this.purchaseCallbackId = purchaseCallbackId;
}
diff --git a/platform/android/java_godot_lib_jni.cpp b/platform/android/java_godot_lib_jni.cpp
index 23e0d24b57..1f61c4a805 100644
--- a/platform/android/java_godot_lib_jni.cpp
+++ b/platform/android/java_godot_lib_jni.cpp
@@ -164,9 +164,20 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_setup(JNIEnv *env, jc
ClassDB::register_class<JNISingleton>();
}
-JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_resize(JNIEnv *env, jclass clazz, jint width, jint height) {
- if (os_android)
- os_android->set_display_size(Size2i(width, height));
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_resize(JNIEnv *env, jclass clazz, jobject p_surface, jint p_width, jint p_height) {
+ if (os_android) {
+ os_android->set_display_size(Size2i(p_width, p_height));
+
+ // No need to reset the surface during startup
+ if (step > 0) {
+ if (p_surface) {
+ ANativeWindow *native_window = ANativeWindow_fromSurface(env, p_surface);
+ os_android->set_native_window(native_window);
+
+ DisplayServerAndroid::get_singleton()->reset_window();
+ }
+ }
+ }
}
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_newcontext(JNIEnv *env, jclass clazz, jobject p_surface, jboolean p_32_bits) {
@@ -375,8 +386,8 @@ JNIEXPORT jstring JNICALL Java_org_godotengine_godot_GodotLib_getGlobal(JNIEnv *
return env->NewStringUTF(ProjectSettings::get_singleton()->get(js).operator String().utf8().get_data());
}
-JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_callobject(JNIEnv *env, jclass clazz, jint ID, jstring method, jobjectArray params) {
- Object *obj = ObjectDB::get_instance(ObjectID((uint64_t)ID));
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_callobject(JNIEnv *env, jclass clazz, jlong ID, jstring method, jobjectArray params) {
+ Object *obj = ObjectDB::get_instance(ObjectID(ID));
ERR_FAIL_COND(!obj);
int res = env->PushLocalFrame(16);
@@ -405,8 +416,8 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_callobject(JNIEnv *en
env->PopLocalFrame(nullptr);
}
-JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_calldeferred(JNIEnv *env, jclass clazz, jint ID, jstring method, jobjectArray params) {
- Object *obj = ObjectDB::get_instance(ObjectID((uint64_t)ID));
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_calldeferred(JNIEnv *env, jclass clazz, jlong ID, jstring method, jobjectArray params) {
+ Object *obj = ObjectDB::get_instance(ObjectID(ID));
ERR_FAIL_COND(!obj);
int res = env->PushLocalFrame(16);
diff --git a/platform/android/java_godot_lib_jni.h b/platform/android/java_godot_lib_jni.h
index 221d701e2b..e8be7be0d0 100644
--- a/platform/android/java_godot_lib_jni.h
+++ b/platform/android/java_godot_lib_jni.h
@@ -40,7 +40,7 @@ extern "C" {
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_initialize(JNIEnv *env, jclass clazz, jobject activity, jobject p_asset_manager, jboolean p_use_apk_expansion);
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_ondestroy(JNIEnv *env, jclass clazz, jobject activity);
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_setup(JNIEnv *env, jclass clazz, jobjectArray p_cmdline);
-JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_resize(JNIEnv *env, jclass clazz, jint width, jint height);
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_resize(JNIEnv *env, jclass clazz, jobject p_surface, jint p_width, jint p_height);
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_newcontext(JNIEnv *env, jclass clazz, jobject p_surface, jboolean p_32_bits);
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_step(JNIEnv *env, jclass clazz);
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_back(JNIEnv *env, jclass clazz);
@@ -61,8 +61,8 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_gyroscope(JNIEnv *env
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_focusin(JNIEnv *env, jclass clazz);
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_focusout(JNIEnv *env, jclass clazz);
JNIEXPORT jstring JNICALL Java_org_godotengine_godot_GodotLib_getGlobal(JNIEnv *env, jclass clazz, jstring path);
-JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_callobject(JNIEnv *env, jclass clazz, jint ID, jstring method, jobjectArray params);
-JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_calldeferred(JNIEnv *env, jclass clazz, jint ID, jstring method, jobjectArray params);
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_callobject(JNIEnv *env, jclass clazz, jlong ID, jstring method, jobjectArray params);
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_calldeferred(JNIEnv *env, jclass clazz, jlong ID, jstring method, jobjectArray params);
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_setVirtualKeyboardHeight(JNIEnv *env, jclass clazz, jint p_height);
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_requestPermissionResult(JNIEnv *env, jclass clazz, jstring p_permission, jboolean p_result);
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_onRendererResumed(JNIEnv *env, jclass clazz);
diff --git a/platform/android/plugin/godot_plugin_config.h b/platform/android/plugin/godot_plugin_config.h
index 9ad7de1202..c59a56717e 100644
--- a/platform/android/plugin/godot_plugin_config.h
+++ b/platform/android/plugin/godot_plugin_config.h
@@ -70,6 +70,8 @@ The `dependencies` section and fields are optional and defined as follow:
struct PluginConfig {
// Set to true when the config file is properly loaded.
bool valid_config = false;
+ // Unix timestamp of last change to this plugin.
+ uint64_t last_updated = 0;
// Required config section
String name;
@@ -87,6 +89,7 @@ struct PluginConfig {
*/
static const PluginConfig GODOT_PAYMENT = {
/*.valid_config =*/true,
+ /*.last_updated =*/0,
/*.name =*/"GodotPayment",
/*.binary_type =*/"local",
/*.binary =*/"res://android/build/libs/plugins/GodotPayment.release.aar",
@@ -150,6 +153,18 @@ static inline bool is_plugin_config_valid(PluginConfig plugin_config) {
return valid_name && valid_binary && valid_binary_type && valid_local_dependencies;
}
+static inline uint64_t get_plugin_modification_time(const PluginConfig &plugin_config, const String &config_path) {
+ uint64_t last_updated = FileAccess::get_modified_time(config_path);
+ last_updated = MAX(last_updated, FileAccess::get_modified_time(plugin_config.binary));
+
+ for (int i = 0; i < plugin_config.local_dependencies.size(); i++) {
+ String binary = plugin_config.local_dependencies.get(i);
+ last_updated = MAX(last_updated, FileAccess::get_modified_time(binary));
+ }
+
+ return last_updated;
+}
+
static inline PluginConfig load_plugin_config(Ref<ConfigFile> config_file, const String &path) {
PluginConfig plugin_config = {};
@@ -177,6 +192,7 @@ static inline PluginConfig load_plugin_config(Ref<ConfigFile> config_file, const
}
plugin_config.valid_config = is_plugin_config_valid(plugin_config);
+ plugin_config.last_updated = get_plugin_modification_time(plugin_config, path);
}
}
diff --git a/platform/android/plugin/godot_plugin_jni.cpp b/platform/android/plugin/godot_plugin_jni.cpp
index 557743fa73..053a4c078e 100644
--- a/platform/android/plugin/godot_plugin_jni.cpp
+++ b/platform/android/plugin/godot_plugin_jni.cpp
@@ -114,12 +114,13 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_plugin_GodotPlugin_nativeEmitS
String signal_name = jstring_to_string(j_signal_name, env);
int count = env->GetArrayLength(j_signal_params);
+ Variant variant_params[count];
const Variant *args[count];
for (int i = 0; i < count; i++) {
jobject j_param = env->GetObjectArrayElement(j_signal_params, i);
- Variant variant = _jobject_to_variant(env, j_param);
- args[i] = &variant;
+ variant_params[i] = _jobject_to_variant(env, j_param);
+ args[i] = &variant_params[i];
env->DeleteLocalRef(j_param);
};
diff --git a/platform/javascript/audio_driver_javascript.cpp b/platform/javascript/audio_driver_javascript.cpp
index b52bd4ce60..b8914414e6 100644
--- a/platform/javascript/audio_driver_javascript.cpp
+++ b/platform/javascript/audio_driver_javascript.cpp
@@ -70,14 +70,14 @@ Error AudioDriverJavaScript::init() {
/* clang-format off */
_driver_id = EM_ASM_INT({
const MIX_RATE = $0;
- const LATENCY = $1;
+ const LATENCY = $1 / 1000;
return Module.IDHandler.add({
'context': new (window.AudioContext || window.webkitAudioContext)({ sampleRate: MIX_RATE, latencyHint: LATENCY}),
'input': null,
'stream': null,
'script': null
});
- });
+ }, mix_rate, latency);
/* clang-format on */
int channel_count = get_total_channels_by_speaker_mode(get_speaker_mode());
diff --git a/scene/debugger/scene_debugger.cpp b/scene/debugger/scene_debugger.cpp
index 0222585948..f57c8e58db 100644
--- a/scene/debugger/scene_debugger.cpp
+++ b/scene/debugger/scene_debugger.cpp
@@ -361,15 +361,6 @@ void SceneDebuggerObject::serialize(Array &r_arr, int p_max_size) {
RES res = var;
- if (var.get_type() == Variant::OBJECT && var.is_ref()) {
- REF r = var;
- if (r.is_valid()) {
- res = *r;
- } else {
- res = RES();
- }
- }
-
Array prop;
prop.push_back(pi.name);
prop.push_back(pi.type);
diff --git a/scene/gui/color_picker.cpp b/scene/gui/color_picker.cpp
index 88710289c7..84170a65d1 100644
--- a/scene/gui/color_picker.cpp
+++ b/scene/gui/color_picker.cpp
@@ -66,7 +66,7 @@ void ColorPicker::_notification(int p_what) {
} break;
case NOTIFICATION_PARENTED: {
for (int i = 0; i < 4; i++) {
- set_margin((Margin)i, get_theme_constant("margin"));
+ set_margin((Margin)i, get_margin((Margin)i) + get_theme_constant("margin"));
}
} break;
case NOTIFICATION_VISIBILITY_CHANGED: {
diff --git a/scene/gui/container.cpp b/scene/gui/container.cpp
index 18a84ce348..a89eef6209 100644
--- a/scene/gui/container.cpp
+++ b/scene/gui/container.cpp
@@ -140,7 +140,7 @@ void Container::queue_sort() {
return;
}
- MessageQueue::get_singleton()->push_call(this, "_sort_children");
+ MessageQueue::get_singleton()->push_callable(callable_mp(this, &Container::_sort_children));
pending_sort = true;
}
@@ -177,8 +177,6 @@ String Container::get_configuration_warning() const {
}
void Container::_bind_methods() {
- ClassDB::bind_method(D_METHOD("_sort_children"), &Container::_sort_children);
-
ClassDB::bind_method(D_METHOD("queue_sort"), &Container::queue_sort);
ClassDB::bind_method(D_METHOD("fit_child_in_rect", "child", "rect"), &Container::fit_child_in_rect);