summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--SConstruct13
-rw-r--r--core/SCsub129
-rw-r--r--core/templates/command_queue_mt.cpp1
-rw-r--r--core/templates/command_queue_mt.h4
-rw-r--r--doc/classes/Crypto.xml109
-rw-r--r--doc/classes/CryptoKey.xml2
-rw-r--r--doc/classes/SkeletonModifier3D.xml10
-rw-r--r--editor/SCsub83
-rw-r--r--editor/plugins/canvas_item_editor_plugin.cpp7
-rw-r--r--editor/themes/editor_color_map.cpp2
-rw-r--r--editor/themes/editor_theme_manager.cpp14
-rw-r--r--methods.py244
-rw-r--r--modules/SCsub65
-rw-r--r--modules/astcenc/image_compress_astcenc.cpp5
-rw-r--r--modules/modules_builders.py15
-rw-r--r--modules/mono/csharp_script.cpp50
-rw-r--r--modules/mono/csharp_script.h4
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertiesGenerator.cs36
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs18
-rw-r--r--platform/SCsub65
-rw-r--r--platform/windows/detect.py105
-rw-r--r--platform/windows/platform_windows_builders.py26
-rw-r--r--platform_methods.py27
-rw-r--r--scene/3d/skeleton_modifier_3d.cpp3
-rw-r--r--scene/3d/skeleton_modifier_3d.h1
-rw-r--r--scene/gui/box_container.cpp4
-rw-r--r--scene/gui/margin_container.cpp4
-rw-r--r--scene/register_scene_types.cpp2
28 files changed, 606 insertions, 442 deletions
diff --git a/SConstruct b/SConstruct
index 81ce4bca52..cfedcc84ed 100644
--- a/SConstruct
+++ b/SConstruct
@@ -61,7 +61,6 @@ _helper_module("platform_methods", "platform_methods.py")
_helper_module("version", "version.py")
_helper_module("core.core_builders", "core/core_builders.py")
_helper_module("main.main_builders", "main/main_builders.py")
-_helper_module("modules.modules_builders", "modules/modules_builders.py")
# Local
import methods
@@ -69,7 +68,7 @@ import glsl_builders
import gles3_builders
import scu_builders
from methods import print_warning, print_error
-from platform_methods import architectures, architecture_aliases, generate_export_icons
+from platform_methods import architectures, architecture_aliases
if ARGUMENTS.get("target", "editor") == "editor":
_helper_module("editor.editor_builders", "editor/editor_builders.py")
@@ -107,7 +106,6 @@ for x in sorted(glob.glob("platform/*")):
if os.path.exists(x + "/export/export.cpp"):
platform_exporters.append(platform_name)
- generate_export_icons(x, platform_name)
if os.path.exists(x + "/api/api.cpp"):
platform_apis.append(platform_name)
if detect.can_build():
@@ -428,7 +426,7 @@ for name, path in modules_detected.items():
sys.path.remove(path)
sys.modules.pop("config")
-methods.write_modules(modules_detected)
+env.modules_detected = modules_detected
# Update the environment again after all the module options are added.
opts.Update(env)
@@ -544,7 +542,7 @@ env.Append(CFLAGS=env.get("cflags", "").split())
env.Append(LINKFLAGS=env.get("linkflags", "").split())
# Feature build profile
-disabled_classes = []
+env.disabled_classes = []
if env["build_profile"] != "":
print('Using feature build profile: "{}"'.format(env["build_profile"]))
import json
@@ -552,7 +550,7 @@ if env["build_profile"] != "":
try:
ft = json.load(open(env["build_profile"]))
if "disabled_classes" in ft:
- disabled_classes = ft["disabled_classes"]
+ env.disabled_classes = ft["disabled_classes"]
if "disabled_build_options" in ft:
dbo = ft["disabled_build_options"]
for c in dbo:
@@ -560,7 +558,6 @@ if env["build_profile"] != "":
except:
print_error('Failed to open feature build profile: "{}"'.format(env["build_profile"]))
Exit(255)
-methods.write_disabled_classes(disabled_classes)
# Platform specific flags.
# These can sometimes override default options.
@@ -926,7 +923,7 @@ if env.editor_build:
print_error("Not all modules required by editor builds are enabled.")
Exit(255)
-methods.generate_version_header(env.module_version_string)
+env.version_info = methods.get_version_info(env.module_version_string)
env["PROGSUFFIX_WRAP"] = suffix + env.module_version_string + ".console" + env["PROGSUFFIX"]
env["PROGSUFFIX"] = suffix + env.module_version_string + env["PROGSUFFIX"]
diff --git a/core/SCsub b/core/SCsub
index 91620cb075..640c6de6a1 100644
--- a/core/SCsub
+++ b/core/SCsub
@@ -4,44 +4,9 @@ Import("env")
import core_builders
import methods
-
-env.core_sources = []
-
-
-# Generate AES256 script encryption key
import os
-txt = "0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0"
-if "SCRIPT_AES256_ENCRYPTION_KEY" in os.environ:
- key = os.environ["SCRIPT_AES256_ENCRYPTION_KEY"]
- ec_valid = True
- if len(key) != 64:
- ec_valid = False
- else:
- txt = ""
- for i in range(len(key) >> 1):
- if i > 0:
- txt += ","
- txts = "0x" + key[i * 2 : i * 2 + 2]
- try:
- int(txts, 16)
- except Exception:
- ec_valid = False
- txt += txts
- if not ec_valid:
- methods.print_error(
- f'Invalid AES256 encryption key, not 64 hexadecimal characters: "{key}".\n'
- "Unset 'SCRIPT_AES256_ENCRYPTION_KEY' in your environment "
- "or make sure that it contains exactly 64 hexadecimal characters."
- )
- Exit(255)
-
-
-script_encryption_key_contents = (
- '#include "core/config/project_settings.h"\nuint8_t script_encryption_key[32]={' + txt + "};\n"
-)
-
-methods.write_file_if_needed("script_encryption_key.gen.cpp", script_encryption_key_contents)
+env.core_sources = []
# Add required thirdparty code.
@@ -193,8 +158,96 @@ env.core_sources += thirdparty_obj
# Godot source files
env.add_source_files(env.core_sources, "*.cpp")
-env.add_source_files(env.core_sources, "script_encryption_key.gen.cpp")
-env.add_source_files(env.core_sources, "version_hash.gen.cpp")
+
+
+# Generate disabled classes
+def disabled_class_builder(target, source, env):
+ with methods.generated_wrapper(target) as file:
+ for c in source[0].read():
+ cs = c.strip()
+ if cs != "":
+ file.write(f"#define ClassDB_Disable_{cs} 1")
+
+
+env.CommandNoCache("disabled_classes.gen.h", env.Value(env.disabled_classes), env.Run(disabled_class_builder))
+
+
+# Generate version info
+def version_info_builder(target, source, env):
+ with methods.generated_wrapper(target) as file:
+ file.write(
+ """\
+#define VERSION_SHORT_NAME "{short_name}"
+#define VERSION_NAME "{name}"
+#define VERSION_MAJOR {major}
+#define VERSION_MINOR {minor}
+#define VERSION_PATCH {patch}
+#define VERSION_STATUS "{status}"
+#define VERSION_BUILD "{build}"
+#define VERSION_MODULE_CONFIG "{module_config}"
+#define VERSION_WEBSITE "{website}"
+#define VERSION_DOCS_BRANCH "{docs_branch}"
+#define VERSION_DOCS_URL "https://docs.godotengine.org/en/" VERSION_DOCS_BRANCH
+""".format(
+ **env.version_info
+ )
+ )
+
+
+env.CommandNoCache("version_generated.gen.h", "#version.py", env.Run(version_info_builder))
+
+
+# Generate version hash
+def version_hash_builder(target, source, env):
+ with methods.generated_wrapper(target) as file:
+ file.write(
+ """\
+#include "core/version.h"
+
+const char *const VERSION_HASH = "{git_hash}";
+const uint64_t VERSION_TIMESTAMP = {git_timestamp};
+""".format(
+ **env.version_info
+ )
+ )
+
+
+gen_hash = env.CommandNoCache(
+ "version_hash.gen.cpp", env.Value(env.version_info["git_hash"]), env.Run(version_hash_builder)
+)
+env.add_source_files(env.core_sources, gen_hash)
+
+
+# Generate AES256 script encryption key
+def encryption_key_builder(target, source, env):
+ with methods.generated_wrapper(target) as file:
+ file.write(
+ f"""\
+#include "core/config/project_settings.h"
+
+uint8_t script_encryption_key[32] = {{
+ {source[0]}
+}};"""
+ )
+
+
+gdkey = os.environ.get("SCRIPT_AES256_ENCRYPTION_KEY", "0" * 64)
+ec_valid = len(gdkey) == 64
+if ec_valid:
+ try:
+ gdkey = ", ".join([str(int(f"{a}{b}", 16)) for a, b in zip(gdkey[0::2], gdkey[1::2])])
+ except Exception:
+ ec_valid = False
+if not ec_valid:
+ methods.print_error(
+ f'Invalid AES256 encryption key, not 64 hexadecimal characters: "{gdkey}".\n'
+ "Unset `SCRIPT_AES256_ENCRYPTION_KEY` in your environment "
+ "or make sure that it contains exactly 64 hexadecimal characters."
+ )
+ Exit(255)
+gen_encrypt = env.CommandNoCache("script_encryption_key.gen.cpp", env.Value(gdkey), env.Run(encryption_key_builder))
+env.add_source_files(env.core_sources, gen_encrypt)
+
# Certificates
env.Depends(
diff --git a/core/templates/command_queue_mt.cpp b/core/templates/command_queue_mt.cpp
index d9e5e0b217..ef75a70868 100644
--- a/core/templates/command_queue_mt.cpp
+++ b/core/templates/command_queue_mt.cpp
@@ -42,6 +42,7 @@ void CommandQueueMT::unlock() {
}
CommandQueueMT::CommandQueueMT() {
+ command_mem.reserve(DEFAULT_COMMAND_MEM_SIZE_KB * 1024);
}
CommandQueueMT::~CommandQueueMT() {
diff --git a/core/templates/command_queue_mt.h b/core/templates/command_queue_mt.h
index dbf938a117..349404d75b 100644
--- a/core/templates/command_queue_mt.h
+++ b/core/templates/command_queue_mt.h
@@ -325,9 +325,7 @@ class CommandQueueMT {
/***** BASE *******/
- enum {
- DEFAULT_COMMAND_MEM_SIZE_KB = 256,
- };
+ static const uint32_t DEFAULT_COMMAND_MEM_SIZE_KB = 64;
BinaryMutex mutex;
LocalVector<uint8_t> command_mem;
diff --git a/doc/classes/Crypto.xml b/doc/classes/Crypto.xml
index 65abc4c641..0effd54fb9 100644
--- a/doc/classes/Crypto.xml
+++ b/doc/classes/Crypto.xml
@@ -8,66 +8,67 @@
Currently, this includes asymmetric key encryption/decryption, signing/verification, and generating cryptographically secure random bytes, RSA keys, HMAC digests, and self-signed [X509Certificate]s.
[codeblocks]
[gdscript]
- extends Node
-
var crypto = Crypto.new()
- var key = CryptoKey.new()
- var cert = X509Certificate.new()
-
- func _ready():
- # Generate new RSA key.
- key = crypto.generate_rsa(4096)
- # Generate new self-signed certificate with the given key.
- cert = crypto.generate_self_signed_certificate(key, "CN=mydomain.com,O=My Game Company,C=IT")
- # Save key and certificate in the user folder.
- key.save("user://generated.key")
- cert.save("user://generated.crt")
- # Encryption
- var data = "Some data"
- var encrypted = crypto.encrypt(key, data.to_utf8_buffer())
- # Decryption
- var decrypted = crypto.decrypt(key, encrypted)
- # Signing
- var signature = crypto.sign(HashingContext.HASH_SHA256, data.sha256_buffer(), key)
- # Verifying
- var verified = crypto.verify(HashingContext.HASH_SHA256, data.sha256_buffer(), signature, key)
- # Checks
- assert(verified)
- assert(data.to_utf8_buffer() == decrypted)
+
+ # Generate new RSA key.
+ var key = crypto.generate_rsa(4096)
+
+ # Generate new self-signed certificate with the given key.
+ var cert = crypto.generate_self_signed_certificate(key, "CN=mydomain.com,O=My Game Company,C=IT")
+
+ # Save key and certificate in the user folder.
+ key.save("user://generated.key")
+ cert.save("user://generated.crt")
+
+ # Encryption
+ var data = "Some data"
+ var encrypted = crypto.encrypt(key, data.to_utf8_buffer())
+
+ # Decryption
+ var decrypted = crypto.decrypt(key, encrypted)
+
+ # Signing
+ var signature = crypto.sign(HashingContext.HASH_SHA256, data.sha256_buffer(), key)
+
+ # Verifying
+ var verified = crypto.verify(HashingContext.HASH_SHA256, data.sha256_buffer(), signature, key)
+
+ # Checks
+ assert(verified)
+ assert(data.to_utf8_buffer() == decrypted)
[/gdscript]
[csharp]
using Godot;
using System.Diagnostics;
- public partial class MyNode : Node
- {
- private Crypto _crypto = new Crypto();
- private CryptoKey _key = new CryptoKey();
- private X509Certificate _cert = new X509Certificate();
-
- public override void _Ready()
- {
- // Generate new RSA key.
- _key = _crypto.GenerateRsa(4096);
- // Generate new self-signed certificate with the given key.
- _cert = _crypto.GenerateSelfSignedCertificate(_key, "CN=mydomain.com,O=My Game Company,C=IT");
- // Save key and certificate in the user folder.
- _key.Save("user://generated.key");
- _cert.Save("user://generated.crt");
- // Encryption
- string data = "Some data";
- byte[] encrypted = _crypto.Encrypt(_key, data.ToUtf8Buffer());
- // Decryption
- byte[] decrypted = _crypto.Decrypt(_key, encrypted);
- // Signing
- byte[] signature = _crypto.Sign(HashingContext.HashType.Sha256, Data.Sha256Buffer(), _key);
- // Verifying
- bool verified = _crypto.Verify(HashingContext.HashType.Sha256, Data.Sha256Buffer(), signature, _key);
- // Checks
- Debug.Assert(verified);
- Debug.Assert(data.ToUtf8Buffer() == decrypted);
- }
- }
+ Crypto crypto = new Crypto();
+
+ // Generate new RSA key.
+ CryptoKey key = crypto.GenerateRsa(4096);
+
+ // Generate new self-signed certificate with the given key.
+ X509Certificate cert = crypto.GenerateSelfSignedCertificate(key, "CN=mydomain.com,O=My Game Company,C=IT");
+
+ // Save key and certificate in the user folder.
+ key.Save("user://generated.key");
+ cert.Save("user://generated.crt");
+
+ // Encryption
+ string data = "Some data";
+ byte[] encrypted = crypto.Encrypt(key, data.ToUtf8Buffer());
+
+ // Decryption
+ byte[] decrypted = crypto.Decrypt(key, encrypted);
+
+ // Signing
+ byte[] signature = crypto.Sign(HashingContext.HashType.Sha256, Data.Sha256Buffer(), key);
+
+ // Verifying
+ bool verified = crypto.Verify(HashingContext.HashType.Sha256, Data.Sha256Buffer(), signature, key);
+
+ // Checks
+ Debug.Assert(verified);
+ Debug.Assert(data.ToUtf8Buffer() == decrypted);
[/csharp]
[/codeblocks]
</description>
diff --git a/doc/classes/CryptoKey.xml b/doc/classes/CryptoKey.xml
index ff826a3ae5..dd128b6806 100644
--- a/doc/classes/CryptoKey.xml
+++ b/doc/classes/CryptoKey.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="CryptoKey" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
- A cryptographic key (RSA).
+ A cryptographic key (RSA or elliptic-curve).
</brief_description>
<description>
The CryptoKey class represents a cryptographic key. Keys can be loaded and saved like any other [Resource].
diff --git a/doc/classes/SkeletonModifier3D.xml b/doc/classes/SkeletonModifier3D.xml
index fab33750ea..c0b1b6fd53 100644
--- a/doc/classes/SkeletonModifier3D.xml
+++ b/doc/classes/SkeletonModifier3D.xml
@@ -6,9 +6,19 @@
<description>
[SkeletonModifier3D] retrieves a target [Skeleton3D] by having a [Skeleton3D] parent.
If there is [AnimationMixer], modification always performs after playback process of the [AnimationMixer].
+ This node should be used to implement custom IK solvers, constraints, or skeleton physics
</description>
<tutorials>
</tutorials>
+ <methods>
+ <method name="_process_modification" qualifiers="virtual">
+ <return type="void" />
+ <description>
+ Override this virtual method to implement a custom skeleton modifier. You should do things like get the [Skeleton3D]'s current pose and apply the pose here.
+ [method _process_modification] must not apply [member influence] to bone poses because the [Skeleton3D] automatically applies influence to all bone poses set by the modifier.
+ </description>
+ </method>
+ </methods>
<members>
<member name="active" type="bool" setter="set_active" getter="is_active" default="true">
If [code]true[/code], the [SkeletonModifier3D] will be processing.
diff --git a/editor/SCsub b/editor/SCsub
index e3b17b83f8..e613a71238 100644
--- a/editor/SCsub
+++ b/editor/SCsub
@@ -10,40 +10,59 @@ import editor_builders
import methods
-def _make_doc_data_class_path(to_path):
- file_path = os.path.join(to_path, "doc_data_class_path.gen.h")
-
- class_path_data = ""
- class_path_data += "static const int _doc_data_class_path_count = " + str(len(env.doc_class_path)) + ";\n"
- class_path_data += "struct _DocDataClassPath { const char* name; const char* path; };\n"
- class_path_data += (
- "static const _DocDataClassPath _doc_data_class_paths[" + str(len(env.doc_class_path) + 1) + "] = {\n"
- )
- for c in sorted(env.doc_class_path):
- class_path_data += '\t{"' + c + '", "' + env.doc_class_path[c] + '"},\n'
- class_path_data += "\t{nullptr, nullptr}\n"
- class_path_data += "};\n"
-
- methods.write_file_if_needed(file_path, class_path_data)
-
-
if env.editor_build:
+ # Generate doc data paths
+ def doc_data_class_path_builder(target, source, env):
+ paths = dict(sorted(source[0].read().items()))
+ data = "\n".join([f'\t{{"{key}", "{value}"}},' for key, value in paths.items()])
+ with methods.generated_wrapper(target) as file:
+ file.write(
+ f"""\
+static const int _doc_data_class_path_count = {len(paths)};
+
+struct _DocDataClassPath {{
+ const char *name;
+ const char *path;
+}};
+
+static const _DocDataClassPath _doc_data_class_paths[{len(env.doc_class_path) + 1}] = {{
+{data}
+ {{nullptr, nullptr}},
+}};
+"""
+ )
+
+ env.CommandNoCache("doc_data_class_path.gen.h", env.Value(env.doc_class_path), env.Run(doc_data_class_path_builder))
+
# Register exporters
- reg_exporters_inc = '#include "register_exporters.h"\n\n'
- reg_exporters = "void register_exporters() {\n"
+ def register_exporters_builder(target, source, env):
+ platforms = source[0].read()
+ exp_inc = "\n".join([f'#include "platform/{p}/export/export.h"' for p in platforms])
+ exp_reg = "\n".join([f"\tregister_{p}_exporter();" for p in platforms])
+ exp_type = "\n".join([f"\tregister_{p}_exporter_types();" for p in platforms])
+ with methods.generated_wrapper(target) as file:
+ file.write(
+ f"""\
+#include "register_exporters.h"
+
+{exp_inc}
+
+void register_exporters() {{
+{exp_reg}
+}}
+
+void register_exporter_types() {{
+{exp_type}
+}}
+"""
+ )
+
+ gen_exporters = env.CommandNoCache(
+ "register_exporters.gen.cpp", env.Value(env.platform_exporters), env.Run(register_exporters_builder)
+ )
for e in env.platform_exporters:
# Add all .cpp files in export folder
- env.add_source_files(env.editor_sources, "../platform/" + e + "/export/" + "*.cpp")
-
- reg_exporters += "\tregister_" + e + "_exporter();\n"
- reg_exporters_inc += '#include "platform/' + e + '/export/export.h"\n'
- reg_exporters += "}\n\n"
- reg_exporters += "void register_exporter_types() {\n"
- for e in env.platform_exporters:
- reg_exporters += "\tregister_" + e + "_exporter_types();\n"
- reg_exporters += "}\n"
-
- methods.write_file_if_needed("register_exporters.gen.cpp", reg_exporters_inc + reg_exporters)
+ env.add_source_files(env.editor_sources, f"../platform/{e}/export/*.cpp")
# Core API documentation.
docs = []
@@ -61,8 +80,6 @@ if env.editor_build:
else:
docs += Glob(d + "/*.xml") # Custom.
- _make_doc_data_class_path(env.Dir("#editor").abspath)
-
docs = sorted(docs)
env.Depends("#editor/doc_data_compressed.gen.h", docs)
env.CommandNoCache(
@@ -115,7 +132,7 @@ if env.editor_build:
)
env.add_source_files(env.editor_sources, "*.cpp")
- env.add_source_files(env.editor_sources, "register_exporters.gen.cpp")
+ env.add_source_files(env.editor_sources, gen_exporters)
SConscript("debugger/SCsub")
SConscript("export/SCsub")
diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp
index e2ef7c08ac..8f58a6a6f9 100644
--- a/editor/plugins/canvas_item_editor_plugin.cpp
+++ b/editor/plugins/canvas_item_editor_plugin.cpp
@@ -4073,6 +4073,13 @@ void CanvasItemEditor::_notification(int p_what) {
override_camera_button->set_pressed(false);
}
} break;
+
+ case NOTIFICATION_APPLICATION_FOCUS_OUT: {
+ if (drag_type != DRAG_NONE) {
+ _reset_drag();
+ viewport->queue_redraw();
+ }
+ } break;
}
}
diff --git a/editor/themes/editor_color_map.cpp b/editor/themes/editor_color_map.cpp
index 99bcf109d0..9046a8b688 100644
--- a/editor/themes/editor_color_map.cpp
+++ b/editor/themes/editor_color_map.cpp
@@ -169,9 +169,7 @@ void EditorColorMap::create() {
add_conversion_exception("ZoomReset");
add_conversion_exception("LockViewport");
add_conversion_exception("GroupViewport");
- add_conversion_exception("StatusError");
add_conversion_exception("StatusSuccess");
- add_conversion_exception("StatusWarning");
add_conversion_exception("OverbrightIndicator");
add_conversion_exception("MaterialPreviewCube");
add_conversion_exception("MaterialPreviewSphere");
diff --git a/editor/themes/editor_theme_manager.cpp b/editor/themes/editor_theme_manager.cpp
index ee008e5636..2ef62c60a2 100644
--- a/editor/themes/editor_theme_manager.cpp
+++ b/editor/themes/editor_theme_manager.cpp
@@ -436,8 +436,8 @@ void EditorThemeManager::_create_shared_styles(const Ref<EditorTheme> &p_theme,
if (!p_config.dark_theme) {
// Darken some colors to be readable on a light background.
p_config.success_color = p_config.success_color.lerp(p_config.mono_color, 0.35);
- p_config.warning_color = p_config.warning_color.lerp(p_config.mono_color, 0.35);
- p_config.error_color = p_config.error_color.lerp(p_config.mono_color, 0.25);
+ p_config.warning_color = Color(0.82, 0.56, 0.1);
+ p_config.error_color = Color(0.8, 0.22, 0.22);
}
p_theme->set_color("mono_color", EditorStringName(Editor), p_config.mono_color);
@@ -1901,14 +1901,20 @@ void EditorThemeManager::_populate_editor_styles(const Ref<EditorTheme> &p_theme
// When pressed, don't tint the icons with the accent color, just leave them normal.
p_theme->set_color("icon_pressed_color", "EditorLogFilterButton", p_config.icon_normal_color);
// When unpressed, dim the icons.
- p_theme->set_color("icon_normal_color", "EditorLogFilterButton", p_config.icon_disabled_color);
+ Color icon_normal_color = Color(p_config.icon_normal_color, (p_config.dark_theme ? 0.4 : 0.8));
+ p_theme->set_color("icon_normal_color", "EditorLogFilterButton", icon_normal_color);
+ Color icon_hover_color = p_config.icon_normal_color * (p_config.dark_theme ? 1.15 : 1.0);
+ icon_hover_color.a = 1.0;
+ p_theme->set_color("icon_hover_color", "EditorLogFilterButton", icon_hover_color);
// When pressed, add a small bottom border to the buttons to better show their active state,
// similar to active tabs.
Ref<StyleBoxFlat> editor_log_button_pressed = style_flat_button_pressed->duplicate();
editor_log_button_pressed->set_border_width(SIDE_BOTTOM, 2 * EDSCALE);
editor_log_button_pressed->set_border_color(p_config.accent_color);
-
+ if (!p_config.dark_theme) {
+ editor_log_button_pressed->set_bg_color(flat_pressed_color.lightened(0.5));
+ }
p_theme->set_stylebox("normal", "EditorLogFilterButton", style_flat_button);
p_theme->set_stylebox("hover", "EditorLogFilterButton", style_flat_button_hover);
p_theme->set_stylebox("pressed", "EditorLogFilterButton", editor_log_button_pressed);
diff --git a/methods.py b/methods.py
index 0c29632f10..da221cc0ea 100644
--- a/methods.py
+++ b/methods.py
@@ -3,13 +3,16 @@ import sys
import re
import glob
import subprocess
+import contextlib
from collections import OrderedDict
from collections.abc import Mapping
from enum import Enum
-from typing import Iterator
+from typing import Generator, Optional
+from io import TextIOWrapper, StringIO
from pathlib import Path
from os.path import normpath, basename
+
# Get the "Godot" folder name ahead of time
base_folder_path = str(os.path.abspath(Path(__file__).parent)) + "/"
base_folder_only = os.path.basename(os.path.normpath(base_folder_path))
@@ -277,79 +280,6 @@ def get_version_info(module_version_string="", silent=False):
return version_info
-_cleanup_env = None
-_cleanup_bool = False
-
-
-def write_file_if_needed(path, string):
- """Generates a file only if it doesn't already exist or the content has changed.
-
- Utilizes a dedicated SCons environment to ensure the files are properly removed
- during cleanup; will not attempt to create files during cleanup.
-
- - `path` - Path to the file in question; used to create cleanup logic.
- - `string` - Content to compare against an existing file.
- """
- global _cleanup_env
- global _cleanup_bool
-
- if _cleanup_env is None:
- from SCons.Environment import Environment
-
- _cleanup_env = Environment()
- _cleanup_bool = _cleanup_env.GetOption("clean")
-
- _cleanup_env.Clean("#", path)
- if _cleanup_bool:
- return
-
- try:
- with open(path, "r", encoding="utf-8", newline="\n") as f:
- if f.read() == string:
- return
- except FileNotFoundError:
- pass
-
- with open(path, "w", encoding="utf-8", newline="\n") as f:
- f.write(string)
-
-
-def generate_version_header(module_version_string=""):
- version_info = get_version_info(module_version_string)
-
- version_info_header = """\
-/* THIS FILE IS GENERATED DO NOT EDIT */
-#ifndef VERSION_GENERATED_GEN_H
-#define VERSION_GENERATED_GEN_H
-#define VERSION_SHORT_NAME "{short_name}"
-#define VERSION_NAME "{name}"
-#define VERSION_MAJOR {major}
-#define VERSION_MINOR {minor}
-#define VERSION_PATCH {patch}
-#define VERSION_STATUS "{status}"
-#define VERSION_BUILD "{build}"
-#define VERSION_MODULE_CONFIG "{module_config}"
-#define VERSION_WEBSITE "{website}"
-#define VERSION_DOCS_BRANCH "{docs_branch}"
-#define VERSION_DOCS_URL "https://docs.godotengine.org/en/" VERSION_DOCS_BRANCH
-#endif // VERSION_GENERATED_GEN_H
-""".format(
- **version_info
- )
-
- version_hash_data = """\
-/* THIS FILE IS GENERATED DO NOT EDIT */
-#include "core/version.h"
-const char *const VERSION_HASH = "{git_hash}";
-const uint64_t VERSION_TIMESTAMP = {git_timestamp};
-""".format(
- **version_info
- )
-
- write_file_if_needed("core/version_generated.gen.h", version_info_header)
- write_file_if_needed("core/version_hash.gen.cpp", version_hash_data)
-
-
def parse_cg_file(fname, uniforms, sizes, conditionals):
with open(fname, "r", encoding="utf-8") as fs:
line = fs.readline()
@@ -465,63 +395,6 @@ def is_module(path):
return True
-def write_disabled_classes(class_list):
- file_contents = ""
-
- file_contents += "/* THIS FILE IS GENERATED DO NOT EDIT */\n"
- file_contents += "#ifndef DISABLED_CLASSES_GEN_H\n"
- file_contents += "#define DISABLED_CLASSES_GEN_H\n\n"
- for c in class_list:
- cs = c.strip()
- if cs != "":
- file_contents += "#define ClassDB_Disable_" + cs + " 1\n"
- file_contents += "\n#endif\n"
-
- write_file_if_needed("core/disabled_classes.gen.h", file_contents)
-
-
-def write_modules(modules):
- includes_cpp = ""
- initialize_cpp = ""
- uninitialize_cpp = ""
-
- for name, path in modules.items():
- try:
- with open(os.path.join(path, "register_types.h")):
- includes_cpp += '#include "' + path + '/register_types.h"\n'
- initialize_cpp += "#ifdef MODULE_" + name.upper() + "_ENABLED\n"
- initialize_cpp += "\tinitialize_" + name + "_module(p_level);\n"
- initialize_cpp += "#endif\n"
- uninitialize_cpp += "#ifdef MODULE_" + name.upper() + "_ENABLED\n"
- uninitialize_cpp += "\tuninitialize_" + name + "_module(p_level);\n"
- uninitialize_cpp += "#endif\n"
- except OSError:
- pass
-
- modules_cpp = """// register_module_types.gen.cpp
-/* THIS FILE IS GENERATED DO NOT EDIT */
-#include "register_module_types.h"
-
-#include "modules/modules_enabled.gen.h"
-
-%s
-
-void initialize_modules(ModuleInitializationLevel p_level) {
-%s
-}
-
-void uninitialize_modules(ModuleInitializationLevel p_level) {
-%s
-}
-""" % (
- includes_cpp,
- initialize_cpp,
- uninitialize_cpp,
- )
-
- write_file_if_needed("modules/register_module_types.gen.cpp", modules_cpp)
-
-
def convert_custom_modules_path(path):
if not path:
return path
@@ -1649,3 +1522,112 @@ def generate_vs_project(env, original_args, project_name="godot"):
if get_bool(original_args, "vsproj_gen_only", True):
sys.exit()
+
+
+def generate_copyright_header(filename: str) -> str:
+ MARGIN = 70
+ TEMPLATE = """\
+/**************************************************************************/
+/* %s*/
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
+"""
+ filename = filename.split("/")[-1].ljust(MARGIN)
+ if len(filename) > MARGIN:
+ print(f'WARNING: Filename "{filename}" too large for copyright header.')
+ return TEMPLATE % filename
+
+
+@contextlib.contextmanager
+def generated_wrapper(
+ path, # FIXME: type with `Union[str, Node, List[Node]]` when pytest conflicts are resolved
+ guard: Optional[bool] = None,
+ prefix: str = "",
+ suffix: str = "",
+) -> Generator[TextIOWrapper, None, None]:
+ """
+ Wrapper class to automatically handle copyright headers and header guards
+ for generated scripts. Meant to be invoked via `with` statement similar to
+ creating a file.
+
+ - `path`: The path of the file to be created. Can be passed a raw string, an
+ isolated SCons target, or a full SCons target list. If a target list contains
+ multiple entries, produces a warning & only creates the first entry.
+ - `guard`: Optional bool to determine if a header guard should be added. If
+ unassigned, header guards are determined by the file extension.
+ - `prefix`: Custom prefix to prepend to a header guard. Produces a warning if
+ provided a value when `guard` evaluates to `False`.
+ - `suffix`: Custom suffix to append to a header guard. Produces a warning if
+ provided a value when `guard` evaluates to `False`.
+ """
+
+ # Handle unfiltered SCons target[s] passed as path.
+ if not isinstance(path, str):
+ if isinstance(path, list):
+ if len(path) > 1:
+ print_warning(
+ "Attempting to use generated wrapper with multiple targets; "
+ f"will only use first entry: {path[0]}"
+ )
+ path = path[0]
+ if not hasattr(path, "get_abspath"):
+ raise TypeError(f'Expected type "str", "Node" or "List[Node]"; was passed {type(path)}.')
+ path = path.get_abspath()
+
+ path = str(path).replace("\\", "/")
+ if guard is None:
+ guard = path.endswith((".h", ".hh", ".hpp", ".inc"))
+ if not guard and (prefix or suffix):
+ print_warning(f'Trying to assign header guard prefix/suffix while `guard` is disabled: "{path}".')
+
+ header_guard = ""
+ if guard:
+ if prefix:
+ prefix += "_"
+ if suffix:
+ suffix = f"_{suffix}"
+ split = path.split("/")[-1].split(".")
+ header_guard = (f"{prefix}{split[0]}{suffix}.{'.'.join(split[1:])}".upper()
+ .replace(".", "_").replace("-", "_").replace(" ", "_").replace("__", "_")) # fmt: skip
+
+ with open(path, "wt", encoding="utf-8", newline="\n") as file:
+ file.write(generate_copyright_header(path))
+ file.write("\n/* THIS FILE IS GENERATED. EDITS WILL BE LOST. */\n\n")
+
+ if guard:
+ file.write(f"#ifndef {header_guard}\n")
+ file.write(f"#define {header_guard}\n\n")
+
+ with StringIO(newline="\n") as str_io:
+ yield str_io
+ file.write(str_io.getvalue().strip() or "/* NO CONTENT */")
+
+ if guard:
+ file.write(f"\n\n#endif // {header_guard}")
+
+ file.write("\n")
diff --git a/modules/SCsub b/modules/SCsub
index 6fb2aa67f4..739c5de0b5 100644
--- a/modules/SCsub
+++ b/modules/SCsub
@@ -1,6 +1,6 @@
#!/usr/bin/env python
-import modules_builders
+import methods
import os
Import("env")
@@ -12,15 +12,51 @@ env_modules.Append(CPPDEFINES=["GODOT_MODULE"])
Export("env_modules")
-# Header with MODULE_*_ENABLED defines.
-env.Depends("modules_enabled.gen.h", Value(env.module_list))
-env.CommandNoCache(
- "modules_enabled.gen.h",
- Value(env.module_list),
- env.Run(modules_builders.generate_modules_enabled),
+
+def register_module_types_builder(target, source, env):
+ modules = source[0].read()
+ mod_inc = "\n".join([f'#include "{p}/register_types.h"' for p in modules.values()])
+ mod_init = "\n".join(
+ [f"#ifdef MODULE_{n.upper()}_ENABLED\n\tinitialize_{n}_module(p_level);\n#endif" for n in modules.keys()]
+ )
+ mod_uninit = "\n".join(
+ [f"#ifdef MODULE_{n.upper()}_ENABLED\n\tuninitialize_{n}_module(p_level);\n#endif" for n in modules.keys()]
+ )
+ with methods.generated_wrapper(target) as file:
+ file.write(
+ f"""\
+#include "register_module_types.h"
+
+#include "modules/modules_enabled.gen.h"
+
+{mod_inc}
+
+void initialize_modules(ModuleInitializationLevel p_level) {{
+{mod_init}
+}}
+
+void uninitialize_modules(ModuleInitializationLevel p_level) {{
+{mod_uninit}
+}}
+"""
+ )
+
+
+register_module_types = env.CommandNoCache(
+ "register_module_types.gen.cpp", env.Value(env.modules_detected), env.Run(register_module_types_builder)
)
+# Header with MODULE_*_ENABLED defines.
+def modules_enabled_builder(target, source, env):
+ with methods.generated_wrapper(target) as file:
+ for module in source[0].read():
+ file.write(f"#define MODULE_{module.upper()}_ENABLED\n")
+
+
+env.CommandNoCache("modules_enabled.gen.h", env.Value(env.module_list), env.Run(modules_enabled_builder))
+
+
vs_sources = []
test_headers = []
# libmodule_<name>.a for each active module.
@@ -47,18 +83,19 @@ for name, path in env.module_list.items():
# Generate header to be included in `tests/test_main.cpp` to run module-specific tests.
if env["tests"]:
- env.Depends("modules_tests.gen.h", test_headers)
- env.CommandNoCache(
- "modules_tests.gen.h",
- test_headers,
- env.Run(modules_builders.generate_modules_tests),
- )
+
+ def modules_tests_builder(target, source, env):
+ with methods.generated_wrapper(target) as file:
+ for header in source:
+ file.write('#include "{}"\n'.format(os.path.normpath(header.path).replace("\\", "/")))
+
+ env.CommandNoCache("modules_tests.gen.h", test_headers, env.Run(modules_tests_builder))
# libmodules.a with only register_module_types.
# Must be last so that all libmodule_<name>.a libraries are on the right side
# in the linker command.
env.modules_sources = []
-env_modules.add_source_files(env.modules_sources, "register_module_types.gen.cpp")
+env_modules.add_source_files(env.modules_sources, register_module_types)
lib = env_modules.add_library("modules", env.modules_sources)
env.Prepend(LIBS=[lib])
if env["vsproj"]:
diff --git a/modules/astcenc/image_compress_astcenc.cpp b/modules/astcenc/image_compress_astcenc.cpp
index 941c1f44be..499cf739c4 100644
--- a/modules/astcenc/image_compress_astcenc.cpp
+++ b/modules/astcenc/image_compress_astcenc.cpp
@@ -132,7 +132,10 @@ void _compress_astc(Image *r_img, Image::ASTCFormat p_format) {
int dst_mip_w, dst_mip_h;
int dst_ofs = Image::get_image_mipmap_offset_and_dimensions(width, height, target_format, i, dst_mip_w, dst_mip_h);
// Ensure that mip offset is a multiple of 8 (etcpak expects uint64_t pointer).
- ERR_FAIL_COND(dst_ofs % 8 != 0);
+ if (unlikely(dst_ofs % 8 != 0)) {
+ astcenc_context_free(context);
+ ERR_FAIL_MSG("astcenc: Mip offset is not a multiple of 8.");
+ }
uint8_t *dest_mip_write = (uint8_t *)&dest_write[dst_ofs];
// Compress image.
diff --git a/modules/modules_builders.py b/modules/modules_builders.py
deleted file mode 100644
index 5db7c88a90..0000000000
--- a/modules/modules_builders.py
+++ /dev/null
@@ -1,15 +0,0 @@
-"""Functions used to generate source files during build time"""
-
-
-def generate_modules_enabled(target, source, env):
- with open(target[0].path, "w", encoding="utf-8", newline="\n") as f:
- for module in env.module_list:
- f.write("#define %s\n" % ("MODULE_" + module.upper() + "_ENABLED"))
-
-
-def generate_modules_tests(target, source, env):
- import os
-
- with open(target[0].path, "w", encoding="utf-8", newline="\n") as f:
- for header in source:
- f.write('#include "%s"\n' % (os.path.normpath(header.path)))
diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp
index ff2ca9f0ce..36c8a40ed9 100644
--- a/modules/mono/csharp_script.cpp
+++ b/modules/mono/csharp_script.cpp
@@ -1596,14 +1596,7 @@ void CSharpInstance::get_method_list(List<MethodInfo> *p_list) const {
return;
}
- const CSharpScript *top = script.ptr();
- while (top != nullptr) {
- for (const CSharpScript::CSharpMethodInfo &E : top->methods) {
- p_list->push_back(E.method_info);
- }
-
- top = top->base_script.ptr();
- }
+ script->get_script_method_list(p_list);
}
bool CSharpInstance::has_method(const StringName &p_method) const {
@@ -1771,16 +1764,19 @@ void CSharpInstance::mono_object_disposed_baseref(GCHandleIntPtr p_gchandle_to_f
}
void CSharpInstance::connect_event_signals() {
- // The script signals list includes the signals declared in base scripts.
- for (CSharpScript::EventSignalInfo &signal : script->get_script_event_signals()) {
- String signal_name = signal.name;
+ const CSharpScript *top = script.ptr();
+ while (top != nullptr && top->valid) {
+ for (const CSharpScript::EventSignalInfo &signal : top->event_signals) {
+ String signal_name = signal.name;
- // TODO: Use pooling for ManagedCallable instances.
- EventSignalCallable *event_signal_callable = memnew(EventSignalCallable(owner, signal_name));
+ // TODO: Use pooling for ManagedCallable instances.
+ EventSignalCallable *event_signal_callable = memnew(EventSignalCallable(owner, signal_name));
- Callable callable(event_signal_callable);
- connected_event_signals.push_back(callable);
- owner->connect(signal_name, callable);
+ Callable callable(event_signal_callable);
+ connected_event_signals.push_back(callable);
+ owner->connect(signal_name, callable);
+ }
+ top = top->base_script.ptr();
}
}
@@ -2624,25 +2620,33 @@ bool CSharpScript::has_script_signal(const StringName &p_signal) const {
}
}
+ if (base_script.is_valid()) {
+ return base_script->has_script_signal(p_signal);
+ }
+
return false;
}
-void CSharpScript::get_script_signal_list(List<MethodInfo> *r_signals) const {
+void CSharpScript::_get_script_signal_list(List<MethodInfo> *r_signals, bool p_include_base) const {
if (!valid) {
return;
}
- for (const EventSignalInfo &signal : get_script_event_signals()) {
+ for (const EventSignalInfo &signal : event_signals) {
r_signals->push_back(signal.method_info);
}
-}
-Vector<CSharpScript::EventSignalInfo> CSharpScript::get_script_event_signals() const {
- if (!valid) {
- return Vector<EventSignalInfo>();
+ if (!p_include_base) {
+ return;
+ }
+
+ if (base_script.is_valid()) {
+ base_script->get_script_signal_list(r_signals);
}
+}
- return event_signals;
+void CSharpScript::get_script_signal_list(List<MethodInfo> *r_signals) const {
+ _get_script_signal_list(r_signals, true);
}
bool CSharpScript::inherits_script(const Ref<Script> &p_script) const {
diff --git a/modules/mono/csharp_script.h b/modules/mono/csharp_script.h
index 17df3988ee..c48e1a95c9 100644
--- a/modules/mono/csharp_script.h
+++ b/modules/mono/csharp_script.h
@@ -215,6 +215,8 @@ private:
// Do not use unless you know what you are doing
static void update_script_class_info(Ref<CSharpScript> p_script);
+ void _get_script_signal_list(List<MethodInfo> *r_signals, bool p_include_base) const;
+
protected:
static void _bind_methods();
@@ -251,8 +253,6 @@ public:
bool has_script_signal(const StringName &p_signal) const override;
void get_script_signal_list(List<MethodInfo> *r_signals) const override;
- Vector<EventSignalInfo> get_script_event_signals() const;
-
bool get_property_default_value(const StringName &p_property, Variant &r_value) const override;
void get_script_property_list(List<PropertyInfo> *r_list) const override;
void update_exports() override;
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertiesGenerator.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertiesGenerator.cs
index 21223654f3..a25a2c2f68 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertiesGenerator.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertiesGenerator.cs
@@ -590,6 +590,11 @@ namespace Godot.SourceGenerators
if (variantType == VariantType.Object && type is INamedTypeSymbol memberNamedType)
{
+ if (TryGetNodeOrResourceType(exportAttr, out hint, out hintString))
+ {
+ return true;
+ }
+
if (memberNamedType.InheritsFrom("GodotSharp", "Godot.Resource"))
{
hint = PropertyHint.ResourceType;
@@ -607,6 +612,37 @@ namespace Godot.SourceGenerators
}
}
+ static bool TryGetNodeOrResourceType(AttributeData exportAttr, out PropertyHint hint, out string? hintString)
+ {
+ hint = PropertyHint.None;
+ hintString = null;
+
+ if (exportAttr.ConstructorArguments.Length <= 1) return false;
+
+ var hintValue = exportAttr.ConstructorArguments[0].Value;
+
+ var hintEnum = hintValue switch
+ {
+ null => PropertyHint.None,
+ int intValue => (PropertyHint)intValue,
+ _ => (PropertyHint)(long)hintValue
+ };
+
+ if (!hintEnum.HasFlag(PropertyHint.NodeType) && !hintEnum.HasFlag(PropertyHint.ResourceType))
+ return false;
+
+ var hintStringValue = exportAttr.ConstructorArguments[1].Value?.ToString();
+ if (string.IsNullOrWhiteSpace(hintStringValue))
+ {
+ return false;
+ }
+
+ hint = hintEnum;
+ hintString = hintStringValue;
+
+ return true;
+ }
+
static string GetTypeName(INamedTypeSymbol memberSymbol)
{
if (memberSymbol.GetAttributes()
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs
index 1b23276bbd..eef26cdd4e 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs
@@ -798,17 +798,17 @@ namespace Godot.Bridge
GetScriptTypeInfo(scriptType, outTypeInfo);
+ Type native = GodotObject.InternalGetClassNativeBase(scriptType);
+
// Methods
// Performance is not critical here as this will be replaced with source generators.
using var methods = new Collections.Array();
Type? top = scriptType;
- Type native = GodotObject.InternalGetClassNativeBase(top);
-
- while (top != null && top != native)
+ if (scriptType != native)
{
- var methodList = GetMethodListForType(top);
+ var methodList = GetMethodListForType(scriptType);
if (methodList != null)
{
@@ -859,8 +859,6 @@ namespace Godot.Bridge
methods.Add(methodInfo);
}
}
-
- top = top.BaseType;
}
*outMethodsDest = NativeFuncs.godotsharp_array_new_copy(
@@ -912,11 +910,9 @@ namespace Godot.Bridge
// Performance is not critical here as this will be replaced with source generators.
using var signals = new Collections.Dictionary();
- top = scriptType;
-
- while (top != null && top != native)
+ if (scriptType != native)
{
- var signalList = GetSignalListForType(top);
+ var signalList = GetSignalListForType(scriptType);
if (signalList != null)
{
@@ -951,8 +947,6 @@ namespace Godot.Bridge
signals.Add(signalName, signalParams);
}
}
-
- top = top.BaseType;
}
*outEventSignalsDest = NativeFuncs.godotsharp_dictionary_new_copy(
diff --git a/platform/SCsub b/platform/SCsub
index ca282e3e68..b24c189848 100644
--- a/platform/SCsub
+++ b/platform/SCsub
@@ -1,27 +1,64 @@
#!/usr/bin/env python
import methods
+from glob import glob
+from pathlib import Path
Import("env")
env.platform_sources = []
+
+# Generate export icons
+def export_icon_builder(target, source, env):
+ src_path = Path(str(source[0]))
+ src_name = src_path.stem
+ platform = src_path.parent.parent.stem
+ with open(str(source[0]), "rb") as file:
+ svg = "".join([f"\\{hex(x)[1:]}" for x in file.read()])
+ with methods.generated_wrapper(target, prefix=platform) as file:
+ file.write(
+ f"""\
+static const char *_{platform}_{src_name}_svg = "{svg}";
+"""
+ )
+
+
+for platform in env.platform_exporters:
+ for path in glob(f"{platform}/export/*.svg"):
+ env.CommandNoCache(path.replace(".svg", "_svg.gen.h"), path, env.Run(export_icon_builder))
+
+
# Register platform-exclusive APIs
-reg_apis_inc = '#include "register_platform_apis.h"\n'
-reg_apis = "void register_platform_apis() {\n"
-unreg_apis = "void unregister_platform_apis() {\n"
+def register_platform_apis_builder(target, source, env):
+ platforms = source[0].read()
+ api_inc = "\n".join([f'#include "{p}/api/api.h"' for p in platforms])
+ api_reg = "\n".join([f"\tregister_{p}_api();" for p in platforms])
+ api_unreg = "\n".join([f"\tunregister_{p}_api();" for p in platforms])
+ with methods.generated_wrapper(target) as file:
+ file.write(
+ f"""\
+#include "register_platform_apis.h"
+
+{api_inc}
+
+void register_platform_apis() {{
+{api_reg}
+}}
+
+void unregister_platform_apis() {{
+{api_unreg}
+}}
+"""
+ )
+
+
+register_platform_apis = env.CommandNoCache(
+ "register_platform_apis.gen.cpp", env.Value(env.platform_apis), env.Run(register_platform_apis_builder)
+)
+env.add_source_files(env.platform_sources, register_platform_apis)
for platform in env.platform_apis:
- platform_dir = env.Dir(platform)
- env.add_source_files(env.platform_sources, platform + "/api/api.cpp")
- reg_apis += "\tregister_" + platform + "_api();\n"
- unreg_apis += "\tunregister_" + platform + "_api();\n"
- reg_apis_inc += '#include "' + platform + '/api/api.h"\n'
-reg_apis_inc += "\n"
-reg_apis += "}\n\n"
-unreg_apis += "}\n"
-
-methods.write_file_if_needed("register_platform_apis.gen.cpp", reg_apis_inc + reg_apis + unreg_apis)
-env.add_source_files(env.platform_sources, "register_platform_apis.gen.cpp")
+ env.add_source_files(env.platform_sources, f"{platform}/api/api.cpp")
lib = env.add_library("platform", env.platform_sources)
env.Prepend(LIBS=[lib])
diff --git a/platform/windows/detect.py b/platform/windows/detect.py
index ccf889f1a3..93eb34001e 100644
--- a/platform/windows/detect.py
+++ b/platform/windows/detect.py
@@ -18,30 +18,36 @@ def get_name():
return "Windows"
-def get_mingw_tool(tool, prefix="", arch="", test="--version"):
- if not prefix:
- prefix = os.getenv("MINGW_PREFIX", "")
- supported_arches = ["x86_64", "x86_32", "arm64", "arm32"]
- if arch in supported_arches:
- arches = [arch, ""]
- else:
- arches = ["x86_64", "x86_32", "arm64", "arm32", ""]
- for a in arches:
+def try_cmd(test, prefix, arch):
+ if arch:
try:
- path = f"{get_mingw_bin_prefix(prefix, a)}{tool}"
out = subprocess.Popen(
- f"{path} {test}",
+ get_mingw_bin_prefix(prefix, arch) + test,
shell=True,
stderr=subprocess.PIPE,
stdout=subprocess.PIPE,
)
out.communicate()
if out.returncode == 0:
- return path
+ return True
except Exception:
pass
+ else:
+ for a in ["x86_64", "x86_32", "arm64", "arm32"]:
+ try:
+ out = subprocess.Popen(
+ get_mingw_bin_prefix(prefix, a) + test,
+ shell=True,
+ stderr=subprocess.PIPE,
+ stdout=subprocess.PIPE,
+ )
+ out.communicate()
+ if out.returncode == 0:
+ return True
+ except Exception:
+ pass
- return ""
+ return False
def can_build():
@@ -59,7 +65,9 @@ def can_build():
if os.name == "posix":
# Cross-compiling with MinGW-w64 (old MinGW32 is not supported)
- if get_mingw_tool("gcc") or get_mingw_tool("clang"):
+ prefix = os.getenv("MINGW_PREFIX", "")
+
+ if try_cmd("gcc --version", prefix, "") or try_cmd("clang --version", prefix, ""):
return True
return False
@@ -247,26 +255,36 @@ def get_flags():
def build_res_file(target, source, env: "SConsEnvironment"):
- cmdbase = get_mingw_tool("windres", env["mingw_prefix"], env["arch"])
- if not cmdbase:
- return -1
-
arch_aliases = {
"x86_32": "pe-i386",
"x86_64": "pe-x86-64",
"arm32": "armv7-w64-mingw32",
"arm64": "aarch64-w64-mingw32",
}
- cmdbase += " --include-dir . --target=" + arch_aliases[env["arch"]]
+ cmdbase = "windres --include-dir . --target=" + arch_aliases[env["arch"]]
+
+ mingw_bin_prefix = get_mingw_bin_prefix(env["mingw_prefix"], env["arch"])
for x in range(len(source)):
- cmd = f"{cmdbase} -i {source[x]} -o {target[x]}"
+ ok = True
+ # Try prefixed executable (MinGW on Linux).
+ cmd = mingw_bin_prefix + cmdbase + " -i " + str(source[x]) + " -o " + str(target[x])
try:
out = subprocess.Popen(cmd, shell=True, stderr=subprocess.PIPE).communicate()
if len(out[1]):
- return -1
+ ok = False
except Exception:
- return -1
+ ok = False
+
+ # Try generic executable (MSYS2).
+ if not ok:
+ cmd = cmdbase + " -i " + str(source[x]) + " -o " + str(target[x])
+ try:
+ out = subprocess.Popen(cmd, shell=True, stderr=subprocess.PIPE).communicate()
+ if len(out[1]):
+ return -1
+ except Exception:
+ return -1
return 0
@@ -340,8 +358,8 @@ def setup_mingw(env: "SConsEnvironment"):
)
sys.exit(255)
- if not get_mingw_tool("gcc", env["mingw_prefix"], env["arch"]) and not get_mingw_tool(
- "clang", env["mingw_prefix"], env["arch"]
+ if not try_cmd("gcc --version", env["mingw_prefix"], env["arch"]) and not try_cmd(
+ "clang --version", env["mingw_prefix"], env["arch"]
):
print_error("No valid compilers found, use MINGW_PREFIX environment variable to set MinGW path.")
sys.exit(255)
@@ -582,10 +600,10 @@ def configure_mingw(env: "SConsEnvironment"):
## Build type
- if not env["use_llvm"] and not get_mingw_tool("gcc", env["mingw_prefix"], env["arch"]):
+ if not env["use_llvm"] and not try_cmd("gcc --version", env["mingw_prefix"], env["arch"]):
env["use_llvm"] = True
- if env["use_llvm"] and not get_mingw_tool("clang", env["mingw_prefix"], env["arch"]):
+ if env["use_llvm"] and not try_cmd("clang --version", env["mingw_prefix"], env["arch"]):
env["use_llvm"] = False
# TODO: Re-evaluate the need for this / streamline with common config.
@@ -620,26 +638,27 @@ def configure_mingw(env: "SConsEnvironment"):
if env["arch"] in ["x86_32", "x86_64"]:
env["x86_libtheora_opt_gcc"] = True
+ mingw_bin_prefix = get_mingw_bin_prefix(env["mingw_prefix"], env["arch"])
+
if env["use_llvm"]:
- env["CC"] = get_mingw_tool("clang", env["mingw_prefix"], env["arch"])
- env["CXX"] = get_mingw_tool("clang++", env["mingw_prefix"], env["arch"])
- tool_as = get_mingw_tool("as", env["mingw_prefix"], env["arch"])
- tool_ar = get_mingw_tool("ar", env["mingw_prefix"], env["arch"])
- tool_ranlib = get_mingw_tool("ranlib", env["mingw_prefix"], env["arch"])
+ env["CC"] = mingw_bin_prefix + "clang"
+ env["CXX"] = mingw_bin_prefix + "clang++"
+ if try_cmd("as --version", env["mingw_prefix"], env["arch"]):
+ env["AS"] = mingw_bin_prefix + "as"
+ if try_cmd("ar --version", env["mingw_prefix"], env["arch"]):
+ env["AR"] = mingw_bin_prefix + "ar"
+ if try_cmd("ranlib --version", env["mingw_prefix"], env["arch"]):
+ env["RANLIB"] = mingw_bin_prefix + "ranlib"
env.extra_suffix = ".llvm" + env.extra_suffix
else:
- env["CC"] = get_mingw_tool("gcc", env["mingw_prefix"], env["arch"])
- env["CXX"] = get_mingw_tool("g++", env["mingw_prefix"], env["arch"])
- tool_as = get_mingw_tool("as", env["mingw_prefix"], env["arch"])
- tool_ar = get_mingw_tool("gcc-ar", env["mingw_prefix"], env["arch"])
- tool_ranlib = get_mingw_tool("gcc-ranlib", env["mingw_prefix"], env["arch"])
-
- if tool_as:
- env["AS"] = tool_as
- if tool_ar:
- env["AR"] = tool_ar
- if tool_ranlib:
- env["RANLIB"] = tool_ranlib
+ env["CC"] = mingw_bin_prefix + "gcc"
+ env["CXX"] = mingw_bin_prefix + "g++"
+ if try_cmd("as --version", env["mingw_prefix"], env["arch"]):
+ env["AS"] = mingw_bin_prefix + "as"
+ if try_cmd("gcc-ar --version", env["mingw_prefix"], env["arch"]):
+ env["AR"] = mingw_bin_prefix + "gcc-ar"
+ if try_cmd("gcc-ranlib --version", env["mingw_prefix"], env["arch"]):
+ env["RANLIB"] = mingw_bin_prefix + "gcc-ranlib"
## LTO
diff --git a/platform/windows/platform_windows_builders.py b/platform/windows/platform_windows_builders.py
index dd480571ba..729d55cea6 100644
--- a/platform/windows/platform_windows_builders.py
+++ b/platform/windows/platform_windows_builders.py
@@ -1,20 +1,24 @@
"""Functions used to generate source files during build time"""
import os
-from detect import get_mingw_tool
+from detect import get_mingw_bin_prefix
+from detect import try_cmd
def make_debug_mingw(target, source, env):
dst = str(target[0])
# Force separate debug symbols if executable size is larger than 1.9 GB.
if env["separate_debug_symbols"] or os.stat(dst).st_size >= 2040109465:
- objcopy = get_mingw_tool("objcopy", env["mingw_prefix"], env["arch"])
- strip = get_mingw_tool("strip", env["mingw_prefix"], env["arch"])
-
- if not objcopy or not strip:
- print('`separate_debug_symbols` requires both "objcopy" and "strip" to function.')
- return
-
- os.system("{0} --only-keep-debug {1} {1}.debugsymbols".format(objcopy, dst))
- os.system("{0} --strip-debug --strip-unneeded {1}".format(strip, dst))
- os.system("{0} --add-gnu-debuglink={1}.debugsymbols {1}".format(objcopy, dst))
+ mingw_bin_prefix = get_mingw_bin_prefix(env["mingw_prefix"], env["arch"])
+ if try_cmd("objcopy --version", env["mingw_prefix"], env["arch"]):
+ os.system(mingw_bin_prefix + "objcopy --only-keep-debug {0} {0}.debugsymbols".format(dst))
+ else:
+ os.system("objcopy --only-keep-debug {0} {0}.debugsymbols".format(dst))
+ if try_cmd("strip --version", env["mingw_prefix"], env["arch"]):
+ os.system(mingw_bin_prefix + "strip --strip-debug --strip-unneeded {0}".format(dst))
+ else:
+ os.system("strip --strip-debug --strip-unneeded {0}".format(dst))
+ if try_cmd("objcopy --version", env["mingw_prefix"], env["arch"]):
+ os.system(mingw_bin_prefix + "objcopy --add-gnu-debuglink={0}.debugsymbols {0}".format(dst))
+ else:
+ os.system("objcopy --add-gnu-debuglink={0}.debugsymbols {0}".format(dst))
diff --git a/platform_methods.py b/platform_methods.py
index 57b11d1a47..5326e36077 100644
--- a/platform_methods.py
+++ b/platform_methods.py
@@ -43,33 +43,6 @@ def detect_arch():
return "x86_64"
-def generate_export_icons(platform_path, platform_name):
- """
- Generate headers for logo and run icon for the export plugin.
- """
- export_path = platform_path + "/export"
- svg_names = []
- if os.path.isfile(export_path + "/logo.svg"):
- svg_names.append("logo")
- if os.path.isfile(export_path + "/run_icon.svg"):
- svg_names.append("run_icon")
-
- for name in svg_names:
- with open(export_path + "/" + name + ".svg", "rb") as svgf:
- b = svgf.read(1)
- svg_str = " /* AUTOGENERATED FILE, DO NOT EDIT */ \n"
- svg_str += " static const char *_" + platform_name + "_" + name + '_svg = "'
- while len(b) == 1:
- svg_str += "\\" + hex(ord(b))[1:]
- b = svgf.read(1)
-
- svg_str += '";\n'
-
- wf = export_path + "/" + name + "_svg.gen.h"
-
- methods.write_file_if_needed(wf, svg_str)
-
-
def get_build_version(short):
import version
diff --git a/scene/3d/skeleton_modifier_3d.cpp b/scene/3d/skeleton_modifier_3d.cpp
index 96e3e33841..8d806ef5fc 100644
--- a/scene/3d/skeleton_modifier_3d.cpp
+++ b/scene/3d/skeleton_modifier_3d.cpp
@@ -110,7 +110,7 @@ void SkeletonModifier3D::process_modification() {
}
void SkeletonModifier3D::_process_modification() {
- //
+ GDVIRTUAL_CALL(_process_modification);
}
void SkeletonModifier3D::_notification(int p_what) {
@@ -133,6 +133,7 @@ void SkeletonModifier3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "influence", PROPERTY_HINT_RANGE, "0,1,0.001"), "set_influence", "get_influence");
ADD_SIGNAL(MethodInfo("modification_processed"));
+ GDVIRTUAL_BIND(_process_modification);
}
SkeletonModifier3D::SkeletonModifier3D() {
diff --git a/scene/3d/skeleton_modifier_3d.h b/scene/3d/skeleton_modifier_3d.h
index 25c09f3b93..d00a1e94a9 100644
--- a/scene/3d/skeleton_modifier_3d.h
+++ b/scene/3d/skeleton_modifier_3d.h
@@ -60,6 +60,7 @@ protected:
virtual void _set_active(bool p_active);
virtual void _process_modification();
+ GDVIRTUAL0(_process_modification);
public:
virtual PackedStringArray get_configuration_warnings() const override;
diff --git a/scene/gui/box_container.cpp b/scene/gui/box_container.cpp
index 88f65ca1bc..d8fcbbb883 100644
--- a/scene/gui/box_container.cpp
+++ b/scene/gui/box_container.cpp
@@ -243,8 +243,8 @@ Size2 BoxContainer::get_minimum_size() const {
bool first = true;
for (int i = 0; i < get_child_count(); i++) {
- Control *c = as_sortable_control(get_child(i));
- if (!c) {
+ Control *c = Object::cast_to<Control>(get_child(i));
+ if (!c || !c->is_visible() || c->is_set_as_top_level()) {
continue;
}
diff --git a/scene/gui/margin_container.cpp b/scene/gui/margin_container.cpp
index 91e6c1f092..06e4a7cc13 100644
--- a/scene/gui/margin_container.cpp
+++ b/scene/gui/margin_container.cpp
@@ -36,8 +36,8 @@ Size2 MarginContainer::get_minimum_size() const {
Size2 max;
for (int i = 0; i < get_child_count(); i++) {
- Control *c = as_sortable_control(get_child(i));
- if (!c) {
+ Control *c = Object::cast_to<Control>(get_child(i));
+ if (!c || !c->is_visible() || c->is_set_as_top_level()) {
continue;
}
diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp
index 6fac096c93..de94327d79 100644
--- a/scene/register_scene_types.cpp
+++ b/scene/register_scene_types.cpp
@@ -589,7 +589,7 @@ void register_scene_types() {
GDREGISTER_CLASS(CPUParticles3D);
GDREGISTER_CLASS(Marker3D);
GDREGISTER_CLASS(RootMotionView);
- GDREGISTER_ABSTRACT_CLASS(SkeletonModifier3D);
+ GDREGISTER_VIRTUAL_CLASS(SkeletonModifier3D);
OS::get_singleton()->yield(); // may take time to init