summaryrefslogtreecommitdiff
path: root/core
diff options
context:
space:
mode:
Diffstat (limited to 'core')
-rw-r--r--core/SCsub39
-rw-r--r--core/bind/SCsub5
-rw-r--r--core/color_names.inc155
-rw-r--r--core/config/SCsub7
-rw-r--r--core/config/engine.cpp (renamed from core/engine.cpp)27
-rw-r--r--core/config/engine.h (renamed from core/engine.h)16
-rw-r--r--core/config/project_settings.cpp (renamed from core/project_settings.cpp)132
-rw-r--r--core/config/project_settings.h (renamed from core/project_settings.h)39
-rw-r--r--core/core_bind.cpp (renamed from core/bind/core_bind.cpp)226
-rw-r--r--core/core_bind.h (renamed from core/bind/core_bind.h)68
-rw-r--r--core/core_builders.py6
-rw-r--r--core/core_constants.cpp657
-rw-r--r--core/core_constants.h (renamed from core/global_constants.h)11
-rw-r--r--core/core_string_names.cpp2
-rw-r--r--core/core_string_names.h4
-rw-r--r--core/crypto/aes_context.cpp1
-rw-r--r--core/crypto/aes_context.h4
-rw-r--r--core/crypto/crypto.cpp2
-rw-r--r--core/crypto/crypto.h4
-rw-r--r--core/crypto/crypto_core.cpp20
-rw-r--r--core/crypto/crypto_core.h12
-rw-r--r--core/crypto/hashing_context.h4
-rw-r--r--core/debugger/debugger_marshalls.cpp2
-rw-r--r--core/debugger/debugger_marshalls.h4
-rw-r--r--core/debugger/engine_debugger.h12
-rw-r--r--core/debugger/local_debugger.h4
-rw-r--r--core/debugger/remote_debugger.cpp4
-rw-r--r--core/debugger/remote_debugger.h8
-rw-r--r--core/debugger/remote_debugger_peer.cpp2
-rw-r--r--core/debugger/remote_debugger_peer.h4
-rw-r--r--core/debugger/script_debugger.h10
-rw-r--r--core/error/SCsub7
-rw-r--r--core/error/error_list.h (renamed from core/error_list.h)0
-rw-r--r--core/error/error_macros.cpp (renamed from core/error_macros.cpp)4
-rw-r--r--core/error/error_macros.h (renamed from core/error_macros.h)20
-rw-r--r--core/func_ref.cpp93
-rw-r--r--core/func_ref.h54
-rw-r--r--core/global_constants.cpp663
-rw-r--r--core/input/SCsub3
-rw-r--r--core/input/gamecontrollerdb.txt125
-rw-r--r--core/input/input.cpp340
-rw-r--r--core/input/input.h18
-rw-r--r--core/input/input_event.cpp91
-rw-r--r--core/input/input_event.h148
-rw-r--r--core/input/input_map.cpp32
-rw-r--r--core/input/input_map.h9
-rw-r--r--core/int_types.h62
-rw-r--r--core/io/compression.cpp89
-rw-r--r--core/io/compression.h3
-rw-r--r--core/io/config_file.cpp2
-rw-r--r--core/io/config_file.h6
-rw-r--r--core/io/dtls_server.cpp2
-rw-r--r--core/io/file_access_buffered.cpp2
-rw-r--r--core/io/file_access_buffered.h2
-rw-r--r--core/io/file_access_compressed.cpp2
-rw-r--r--core/io/file_access_encrypted.cpp77
-rw-r--r--core/io/file_access_encrypted.h13
-rw-r--r--core/io/file_access_memory.cpp4
-rw-r--r--core/io/file_access_memory.h4
-rw-r--r--core/io/file_access_network.cpp2
-rw-r--r--core/io/file_access_pack.cpp112
-rw-r--r--core/io/file_access_pack.h50
-rw-r--r--core/io/file_access_zip.cpp12
-rw-r--r--core/io/file_access_zip.h14
-rw-r--r--core/io/http_client.cpp65
-rw-r--r--core/io/http_client.h9
-rw-r--r--core/io/image.cpp (renamed from core/image.cpp)110
-rw-r--r--core/io/image.h (renamed from core/image.h)27
-rw-r--r--core/io/image_loader.cpp2
-rw-r--r--core/io/image_loader.h6
-rw-r--r--core/io/ip.cpp2
-rw-r--r--core/io/ip.h2
-rw-r--r--core/io/ip_address.cpp5
-rw-r--r--core/io/ip_address.h2
-rw-r--r--core/io/json.cpp58
-rw-r--r--core/io/json.h34
-rw-r--r--core/io/logger.cpp4
-rw-r--r--core/io/logger.h4
-rw-r--r--core/io/marshalls.cpp8
-rw-r--r--core/io/marshalls.h4
-rw-r--r--core/io/multiplayer_api.h3
-rw-r--r--core/io/net_socket.h2
-rw-r--r--core/io/packed_data_container.cpp (renamed from core/packed_data_container.cpp)5
-rw-r--r--core/io/packed_data_container.h (renamed from core/packed_data_container.h)8
-rw-r--r--core/io/packet_peer.cpp2
-rw-r--r--core/io/packet_peer.h12
-rw-r--r--core/io/packet_peer_dtls.cpp2
-rw-r--r--core/io/packet_peer_udp.cpp66
-rw-r--r--core/io/packet_peer_udp.h15
-rw-r--r--core/io/pck_packer.cpp191
-rw-r--r--core/io/pck_packer.h18
-rw-r--r--core/io/resource.cpp (renamed from core/resource.cpp)16
-rw-r--r--core/io/resource.h (renamed from core/resource.h)17
-rw-r--r--core/io/resource_format_binary.cpp15
-rw-r--r--core/io/resource_importer.cpp5
-rw-r--r--core/io/resource_loader.cpp16
-rw-r--r--core/io/resource_loader.h2
-rw-r--r--core/io/resource_saver.cpp6
-rw-r--r--core/io/resource_saver.h3
-rw-r--r--core/io/stream_peer.h12
-rw-r--r--core/io/stream_peer_ssl.cpp2
-rw-r--r--core/io/stream_peer_tcp.cpp2
-rw-r--r--core/io/stream_peer_tcp.h11
-rw-r--r--core/io/translation_loader_po.cpp130
-rw-r--r--core/io/translation_loader_po.h2
-rw-r--r--core/io/udp_server.cpp100
-rw-r--r--core/io/udp_server.h29
-rw-r--r--core/io/xml_parser.cpp6
-rw-r--r--core/io/xml_parser.h6
-rw-r--r--core/make_binders.py390
-rw-r--r--core/math/a_star.cpp2
-rw-r--r--core/math/a_star.h20
-rw-r--r--core/math/aabb.cpp18
-rw-r--r--core/math/aabb.h16
-rw-r--r--core/math/audio_frame.h2
-rw-r--r--core/math/basis.cpp23
-rw-r--r--core/math/basis.h23
-rw-r--r--core/math/camera_matrix.cpp7
-rw-r--r--core/math/camera_matrix.h2
-rw-r--r--core/math/color.cpp (renamed from core/color.cpp)232
-rw-r--r--core/math/color.h (renamed from core/color.h)80
-rw-r--r--core/math/color_names.inc160
-rw-r--r--core/math/delaunay_3d.h10
-rw-r--r--core/math/disjoint_set.h4
-rw-r--r--core/math/expression.cpp765
-rw-r--r--core/math/expression.h108
-rw-r--r--core/math/geometry_2d.h4
-rw-r--r--core/math/geometry_3d.cpp6
-rw-r--r--core/math/geometry_3d.h52
-rw-r--r--core/math/math_defs.h5
-rw-r--r--core/math/math_fieldwise.cpp10
-rw-r--r--core/math/math_fieldwise.h2
-rw-r--r--core/math/math_funcs.cpp8
-rw-r--r--core/math/math_funcs.h33
-rw-r--r--core/math/octree.h9
-rw-r--r--core/math/plane.cpp30
-rw-r--r--core/math/plane.h8
-rw-r--r--core/math/quat.cpp2
-rw-r--r--core/math/quat.h30
-rw-r--r--core/math/quick_hull.cpp2
-rw-r--r--core/math/quick_hull.h14
-rw-r--r--core/math/random_number_generator.cpp5
-rw-r--r--core/math/random_number_generator.h19
-rw-r--r--core/math/random_pcg.cpp15
-rw-r--r--core/math/random_pcg.h11
-rw-r--r--core/math/rect2.h99
-rw-r--r--core/math/transform.cpp9
-rw-r--r--core/math/transform.h5
-rw-r--r--core/math/transform_2d.cpp2
-rw-r--r--core/math/transform_2d.h6
-rw-r--r--core/math/triangle_mesh.cpp2
-rw-r--r--core/math/triangle_mesh.h2
-rw-r--r--core/math/vector2.cpp13
-rw-r--r--core/math/vector2.h54
-rw-r--r--core/math/vector3.h18
-rw-r--r--core/math/vector3i.h28
-rw-r--r--core/method_bind.h393
-rw-r--r--core/object/SCsub7
-rw-r--r--core/object/callable_method_pointer.cpp (renamed from core/callable_method_pointer.cpp)0
-rw-r--r--core/object/callable_method_pointer.h (renamed from core/callable_method_pointer.h)184
-rw-r--r--core/object/class_db.cpp (renamed from core/class_db.cpp)196
-rw-r--r--core/object/class_db.h (renamed from core/class_db.h)23
-rw-r--r--core/object/message_queue.cpp (renamed from core/message_queue.cpp)4
-rw-r--r--core/object/message_queue.h (renamed from core/message_queue.h)5
-rw-r--r--core/object/method_bind.cpp (renamed from core/method_bind.cpp)2
-rw-r--r--core/object/method_bind.h577
-rw-r--r--core/object/object.cpp (renamed from core/object.cpp)192
-rw-r--r--core/object/object.h (renamed from core/object.h)310
-rw-r--r--core/object/object_id.h (renamed from core/object_id.h)0
-rw-r--r--core/object/reference.cpp (renamed from core/reference.cpp)2
-rw-r--r--core/object/reference.h (renamed from core/reference.h)9
-rw-r--r--core/object/script_language.cpp (renamed from core/script_language.cpp)66
-rw-r--r--core/object/script_language.h (renamed from core/script_language.h)20
-rw-r--r--core/object/undo_redo.cpp (renamed from core/undo_redo.cpp)0
-rw-r--r--core/object/undo_redo.h (renamed from core/undo_redo.h)4
-rw-r--r--core/os/dir_access.cpp2
-rw-r--r--core/os/dir_access.h3
-rw-r--r--core/os/file_access.cpp24
-rw-r--r--core/os/file_access.h3
-rw-r--r--core/os/keyboard.cpp1
-rw-r--r--core/os/keyboard.h5
-rw-r--r--core/os/main_loop.cpp7
-rw-r--r--core/os/main_loop.h4
-rw-r--r--core/os/memory.cpp4
-rw-r--r--core/os/memory.h4
-rw-r--r--core/os/midi_driver.h2
-rw-r--r--core/os/mutex.h2
-rw-r--r--core/os/os.cpp10
-rw-r--r--core/os/os.h19
-rw-r--r--core/os/pool_allocator.cpp (renamed from core/pool_allocator.cpp)4
-rw-r--r--core/os/pool_allocator.h (renamed from core/pool_allocator.h)1
-rw-r--r--core/os/rw_lock.cpp2
-rw-r--r--core/os/rw_lock.h2
-rw-r--r--core/os/semaphore.h2
-rw-r--r--core/os/spin_lock.h (renamed from core/spin_lock.h)0
-rw-r--r--core/os/thread.h3
-rw-r--r--core/os/threaded_array_processor.h2
-rw-r--r--core/register_core_types.cpp35
-rw-r--r--core/string/SCsub7
-rw-r--r--core/string/compressed_translation.cpp (renamed from core/compressed_translation.cpp)13
-rw-r--r--core/string/compressed_translation.h (renamed from core/compressed_translation.h)5
-rw-r--r--core/string/node_path.cpp (renamed from core/node_path.cpp)2
-rw-r--r--core/string/node_path.h (renamed from core/node_path.h)4
-rw-r--r--core/string/print_string.cpp (renamed from core/print_string.cpp)0
-rw-r--r--core/string/print_string.h (renamed from core/print_string.h)2
-rw-r--r--core/string/string_buffer.h (renamed from core/string_buffer.h)28
-rw-r--r--core/string/string_builder.cpp (renamed from core/string_builder.cpp)4
-rw-r--r--core/string/string_builder.h (renamed from core/string_builder.h)4
-rw-r--r--core/string/string_name.cpp (renamed from core/string_name.cpp)18
-rw-r--r--core/string/string_name.h (renamed from core/string_name.h)16
-rw-r--r--core/string/translation.cpp (renamed from core/translation.cpp)219
-rw-r--r--core/string/translation.h (renamed from core/translation.h)34
-rw-r--r--core/string/translation_po.cpp312
-rw-r--r--core/string/translation_po.h92
-rw-r--r--core/string/ucaps.h (renamed from core/ucaps.h)0
-rw-r--r--core/string/ustring.cpp (renamed from core/ustring.cpp)1331
-rw-r--r--core/string/ustring.h (renamed from core/ustring.h)232
-rw-r--r--core/templates/SCsub7
-rw-r--r--core/templates/command_queue_mt.cpp (renamed from core/command_queue_mt.cpp)7
-rw-r--r--core/templates/command_queue_mt.h (renamed from core/command_queue_mt.h)38
-rw-r--r--core/templates/cowdata.h (renamed from core/cowdata.h)6
-rw-r--r--core/templates/hash_map.h (renamed from core/hash_map.h)10
-rw-r--r--core/templates/hashfuncs.h (renamed from core/hashfuncs.h)12
-rw-r--r--core/templates/list.h (renamed from core/list.h)50
-rw-r--r--core/templates/local_vector.h (renamed from core/local_vector.h)8
-rw-r--r--core/templates/map.h (renamed from core/map.h)4
-rw-r--r--core/templates/oa_hash_map.h (renamed from core/oa_hash_map.h)4
-rw-r--r--core/templates/ordered_hash_map.h (renamed from core/ordered_hash_map.h)6
-rw-r--r--core/templates/pair.h (renamed from core/pair.h)0
-rw-r--r--core/templates/rid.h (renamed from core/rid.h)3
-rw-r--r--core/templates/rid_owner.cpp (renamed from core/rid_owner.cpp)0
-rw-r--r--core/templates/rid_owner.h (renamed from core/rid_owner.h)16
-rw-r--r--core/templates/ring_buffer.h (renamed from core/ring_buffer.h)2
-rw-r--r--core/templates/safe_refcount.cpp (renamed from core/safe_refcount.cpp)0
-rw-r--r--core/templates/safe_refcount.h (renamed from core/safe_refcount.h)2
-rw-r--r--core/templates/self_list.h (renamed from core/self_list.h)2
-rw-r--r--core/templates/set.h (renamed from core/set.h)2
-rw-r--r--core/templates/simple_type.h (renamed from core/simple_type.h)5
-rw-r--r--core/templates/sort_array.h (renamed from core/sort_array.h)3
-rw-r--r--core/templates/thread_work_pool.cpp (renamed from core/thread_work_pool.cpp)0
-rw-r--r--core/templates/thread_work_pool.h (renamed from core/thread_work_pool.h)31
-rw-r--r--core/templates/vector.h (renamed from core/vector.h)38
-rw-r--r--core/templates/vmap.h (renamed from core/vmap.h)2
-rw-r--r--core/templates/vset.h (renamed from core/vset.h)2
-rw-r--r--core/typedefs.h22
-rw-r--r--core/variant/SCsub7
-rw-r--r--core/variant/array.cpp (renamed from core/array.cpp)61
-rw-r--r--core/variant/array.h (renamed from core/array.h)13
-rw-r--r--core/variant/binder_common.h666
-rw-r--r--core/variant/callable.cpp (renamed from core/callable.cpp)37
-rw-r--r--core/variant/callable.h (renamed from core/callable.h)18
-rw-r--r--core/variant/callable_bind.cpp193
-rw-r--r--core/variant/callable_bind.h85
-rw-r--r--core/variant/container_type_validate.h (renamed from core/container_type_validate.h)6
-rw-r--r--core/variant/dictionary.cpp (renamed from core/dictionary.cpp)6
-rw-r--r--core/variant/dictionary.h (renamed from core/dictionary.h)6
-rw-r--r--core/variant/method_ptrcall.h (renamed from core/method_ptrcall.h)30
-rw-r--r--core/variant/type_info.h (renamed from core/type_info.h)14
-rw-r--r--core/variant/typed_array.h (renamed from core/typed_array.h)14
-rw-r--r--core/variant/variant.cpp (renamed from core/variant.cpp)124
-rw-r--r--core/variant/variant.h (renamed from core/variant.h)256
-rw-r--r--core/variant/variant_call.cpp1558
-rw-r--r--core/variant/variant_construct.cpp812
-rw-r--r--core/variant/variant_internal.h1384
-rw-r--r--core/variant/variant_op.cpp2015
-rw-r--r--core/variant/variant_parser.cpp (renamed from core/variant_parser.cpp)36
-rw-r--r--core/variant/variant_parser.h (renamed from core/variant_parser.h)13
-rw-r--r--core/variant/variant_setget.cpp2509
-rw-r--r--core/variant/variant_utility.cpp1381
-rw-r--r--core/variant_call.cpp2384
-rw-r--r--core/variant_op.cpp4549
271 files changed, 17699 insertions, 12185 deletions
diff --git a/core/SCsub b/core/SCsub
index 80a5f6b623..78a4395619 100644
--- a/core/SCsub
+++ b/core/SCsub
@@ -3,8 +3,6 @@
Import("env")
import core_builders
-import make_binders
-from platform_methods import run_in_subprocess
env.core_sources = []
@@ -36,7 +34,7 @@ if "SCRIPT_AES256_ENCRYPTION_KEY" in os.environ:
# NOTE: It is safe to generate this file here, since this is still executed serially
with open("script_encryption_key.gen.cpp", "w") as f:
- f.write('#include "core/project_settings.h"\nuint8_t script_encryption_key[32]={' + txt + "};\n")
+ f.write('#include "core/config/project_settings.h"\nuint8_t script_encryption_key[32]={' + txt + "};\n")
# Add required thirdparty code.
@@ -88,11 +86,7 @@ if env["builtin_zlib"]:
# Minizip library, could be unbundled in theory
# However, our version has some custom modifications, so it won't compile with the system one
thirdparty_minizip_dir = "#thirdparty/minizip/"
-thirdparty_minizip_sources = [
- "ioapi.c",
- "unzip.c",
- "zip.c",
-]
+thirdparty_minizip_sources = ["ioapi.c", "unzip.c", "zip.c"]
thirdparty_minizip_sources = [thirdparty_minizip_dir + file for file in thirdparty_minizip_sources]
env_thirdparty.add_source_files(env.core_sources, thirdparty_minizip_sources)
@@ -122,6 +116,7 @@ if env["builtin_zstd"]:
"compress/zstdmt_compress.c",
"compress/zstd_compress_literals.c",
"compress/zstd_compress_sequences.c",
+ "compress/zstd_compress_superblock.c",
"decompress/huf_decompress.c",
"decompress/zstd_ddict.c",
"decompress/zstd_decompress_block.c",
@@ -149,28 +144,27 @@ env.Depends(
env.CommandNoCache(
"#core/io/certs_compressed.gen.h",
"#thirdparty/certs/ca-certificates.crt",
- run_in_subprocess(core_builders.make_certs_header),
-)
-
-# Make binders
-env.CommandNoCache(
- ["method_bind.gen.inc", "method_bind_ext.gen.inc", "method_bind_free_func.gen.inc"],
- "make_binders.py",
- run_in_subprocess(make_binders.run),
+ env.Run(core_builders.make_certs_header, "Building ca-certificates header."),
)
# Authors
env.Depends("#core/authors.gen.h", "../AUTHORS.md")
-env.CommandNoCache("#core/authors.gen.h", "../AUTHORS.md", run_in_subprocess(core_builders.make_authors_header))
+env.CommandNoCache(
+ "#core/authors.gen.h", "../AUTHORS.md", env.Run(core_builders.make_authors_header, "Generating authors header.")
+)
# Donors
env.Depends("#core/donors.gen.h", "../DONORS.md")
-env.CommandNoCache("#core/donors.gen.h", "../DONORS.md", run_in_subprocess(core_builders.make_donors_header))
+env.CommandNoCache(
+ "#core/donors.gen.h", "../DONORS.md", env.Run(core_builders.make_donors_header, "Generating donors header.")
+)
# License
env.Depends("#core/license.gen.h", ["../COPYRIGHT.txt", "../LICENSE.txt"])
env.CommandNoCache(
- "#core/license.gen.h", ["../COPYRIGHT.txt", "../LICENSE.txt"], run_in_subprocess(core_builders.make_license_header)
+ "#core/license.gen.h",
+ ["../COPYRIGHT.txt", "../LICENSE.txt"],
+ env.Run(core_builders.make_license_header, "Generating license header."),
)
# Chain load SCsubs
@@ -180,7 +174,12 @@ SConscript("crypto/SCsub")
SConscript("io/SCsub")
SConscript("debugger/SCsub")
SConscript("input/SCsub")
-SConscript("bind/SCsub")
+SConscript("variant/SCsub")
+SConscript("object/SCsub")
+SConscript("templates/SCsub")
+SConscript("string/SCsub")
+SConscript("config/SCsub")
+SConscript("error/SCsub")
# Build it all as a library
diff --git a/core/bind/SCsub b/core/bind/SCsub
deleted file mode 100644
index 19a6549225..0000000000
--- a/core/bind/SCsub
+++ /dev/null
@@ -1,5 +0,0 @@
-#!/usr/bin/env python
-
-Import("env")
-
-env.add_source_files(env.core_sources, "*.cpp")
diff --git a/core/color_names.inc b/core/color_names.inc
deleted file mode 100644
index 2b50d88b02..0000000000
--- a/core/color_names.inc
+++ /dev/null
@@ -1,155 +0,0 @@
-// Names from https://en.wikipedia.org/wiki/X11_color_names
-#include "core/map.h"
-
-static Map<String, Color> _named_colors;
-static void _populate_named_colors() {
- if (!_named_colors.empty()) {
- return;
- }
- _named_colors.insert("aliceblue", Color(0.94, 0.97, 1.00));
- _named_colors.insert("antiquewhite", Color(0.98, 0.92, 0.84));
- _named_colors.insert("aqua", Color(0.00, 1.00, 1.00));
- _named_colors.insert("aquamarine", Color(0.50, 1.00, 0.83));
- _named_colors.insert("azure", Color(0.94, 1.00, 1.00));
- _named_colors.insert("beige", Color(0.96, 0.96, 0.86));
- _named_colors.insert("bisque", Color(1.00, 0.89, 0.77));
- _named_colors.insert("black", Color(0.00, 0.00, 0.00));
- _named_colors.insert("blanchedalmond", Color(1.00, 0.92, 0.80));
- _named_colors.insert("blue", Color(0.00, 0.00, 1.00));
- _named_colors.insert("blueviolet", Color(0.54, 0.17, 0.89));
- _named_colors.insert("brown", Color(0.65, 0.16, 0.16));
- _named_colors.insert("burlywood", Color(0.87, 0.72, 0.53));
- _named_colors.insert("cadetblue", Color(0.37, 0.62, 0.63));
- _named_colors.insert("chartreuse", Color(0.50, 1.00, 0.00));
- _named_colors.insert("chocolate", Color(0.82, 0.41, 0.12));
- _named_colors.insert("coral", Color(1.00, 0.50, 0.31));
- _named_colors.insert("cornflower", Color(0.39, 0.58, 0.93));
- _named_colors.insert("cornsilk", Color(1.00, 0.97, 0.86));
- _named_colors.insert("crimson", Color(0.86, 0.08, 0.24));
- _named_colors.insert("cyan", Color(0.00, 1.00, 1.00));
- _named_colors.insert("darkblue", Color(0.00, 0.00, 0.55));
- _named_colors.insert("darkcyan", Color(0.00, 0.55, 0.55));
- _named_colors.insert("darkgoldenrod", Color(0.72, 0.53, 0.04));
- _named_colors.insert("darkgray", Color(0.66, 0.66, 0.66));
- _named_colors.insert("darkgreen", Color(0.00, 0.39, 0.00));
- _named_colors.insert("darkkhaki", Color(0.74, 0.72, 0.42));
- _named_colors.insert("darkmagenta", Color(0.55, 0.00, 0.55));
- _named_colors.insert("darkolivegreen", Color(0.33, 0.42, 0.18));
- _named_colors.insert("darkorange", Color(1.00, 0.55, 0.00));
- _named_colors.insert("darkorchid", Color(0.60, 0.20, 0.80));
- _named_colors.insert("darkred", Color(0.55, 0.00, 0.00));
- _named_colors.insert("darksalmon", Color(0.91, 0.59, 0.48));
- _named_colors.insert("darkseagreen", Color(0.56, 0.74, 0.56));
- _named_colors.insert("darkslateblue", Color(0.28, 0.24, 0.55));
- _named_colors.insert("darkslategray", Color(0.18, 0.31, 0.31));
- _named_colors.insert("darkturquoise", Color(0.00, 0.81, 0.82));
- _named_colors.insert("darkviolet", Color(0.58, 0.00, 0.83));
- _named_colors.insert("deeppink", Color(1.00, 0.08, 0.58));
- _named_colors.insert("deepskyblue", Color(0.00, 0.75, 1.00));
- _named_colors.insert("dimgray", Color(0.41, 0.41, 0.41));
- _named_colors.insert("dodgerblue", Color(0.12, 0.56, 1.00));
- _named_colors.insert("firebrick", Color(0.70, 0.13, 0.13));
- _named_colors.insert("floralwhite", Color(1.00, 0.98, 0.94));
- _named_colors.insert("forestgreen", Color(0.13, 0.55, 0.13));
- _named_colors.insert("fuchsia", Color(1.00, 0.00, 1.00));
- _named_colors.insert("gainsboro", Color(0.86, 0.86, 0.86));
- _named_colors.insert("ghostwhite", Color(0.97, 0.97, 1.00));
- _named_colors.insert("gold", Color(1.00, 0.84, 0.00));
- _named_colors.insert("goldenrod", Color(0.85, 0.65, 0.13));
- _named_colors.insert("gray", Color(0.75, 0.75, 0.75));
- _named_colors.insert("webgray", Color(0.50, 0.50, 0.50));
- _named_colors.insert("green", Color(0.00, 1.00, 0.00));
- _named_colors.insert("webgreen", Color(0.00, 0.50, 0.00));
- _named_colors.insert("greenyellow", Color(0.68, 1.00, 0.18));
- _named_colors.insert("honeydew", Color(0.94, 1.00, 0.94));
- _named_colors.insert("hotpink", Color(1.00, 0.41, 0.71));
- _named_colors.insert("indianred", Color(0.80, 0.36, 0.36));
- _named_colors.insert("indigo", Color(0.29, 0.00, 0.51));
- _named_colors.insert("ivory", Color(1.00, 1.00, 0.94));
- _named_colors.insert("khaki", Color(0.94, 0.90, 0.55));
- _named_colors.insert("lavender", Color(0.90, 0.90, 0.98));
- _named_colors.insert("lavenderblush", Color(1.00, 0.94, 0.96));
- _named_colors.insert("lawngreen", Color(0.49, 0.99, 0.00));
- _named_colors.insert("lemonchiffon", Color(1.00, 0.98, 0.80));
- _named_colors.insert("lightblue", Color(0.68, 0.85, 0.90));
- _named_colors.insert("lightcoral", Color(0.94, 0.50, 0.50));
- _named_colors.insert("lightcyan", Color(0.88, 1.00, 1.00));
- _named_colors.insert("lightgoldenrod", Color(0.98, 0.98, 0.82));
- _named_colors.insert("lightgray", Color(0.83, 0.83, 0.83));
- _named_colors.insert("lightgreen", Color(0.56, 0.93, 0.56));
- _named_colors.insert("lightpink", Color(1.00, 0.71, 0.76));
- _named_colors.insert("lightsalmon", Color(1.00, 0.63, 0.48));
- _named_colors.insert("lightseagreen", Color(0.13, 0.70, 0.67));
- _named_colors.insert("lightskyblue", Color(0.53, 0.81, 0.98));
- _named_colors.insert("lightslategray", Color(0.47, 0.53, 0.60));
- _named_colors.insert("lightsteelblue", Color(0.69, 0.77, 0.87));
- _named_colors.insert("lightyellow", Color(1.00, 1.00, 0.88));
- _named_colors.insert("lime", Color(0.00, 1.00, 0.00));
- _named_colors.insert("limegreen", Color(0.20, 0.80, 0.20));
- _named_colors.insert("linen", Color(0.98, 0.94, 0.90));
- _named_colors.insert("magenta", Color(1.00, 0.00, 1.00));
- _named_colors.insert("maroon", Color(0.69, 0.19, 0.38));
- _named_colors.insert("webmaroon", Color(0.50, 0.00, 0.00));
- _named_colors.insert("mediumaquamarine", Color(0.40, 0.80, 0.67));
- _named_colors.insert("mediumblue", Color(0.00, 0.00, 0.80));
- _named_colors.insert("mediumorchid", Color(0.73, 0.33, 0.83));
- _named_colors.insert("mediumpurple", Color(0.58, 0.44, 0.86));
- _named_colors.insert("mediumseagreen", Color(0.24, 0.70, 0.44));
- _named_colors.insert("mediumslateblue", Color(0.48, 0.41, 0.93));
- _named_colors.insert("mediumspringgreen", Color(0.00, 0.98, 0.60));
- _named_colors.insert("mediumturquoise", Color(0.28, 0.82, 0.80));
- _named_colors.insert("mediumvioletred", Color(0.78, 0.08, 0.52));
- _named_colors.insert("midnightblue", Color(0.10, 0.10, 0.44));
- _named_colors.insert("mintcream", Color(0.96, 1.00, 0.98));
- _named_colors.insert("mistyrose", Color(1.00, 0.89, 0.88));
- _named_colors.insert("moccasin", Color(1.00, 0.89, 0.71));
- _named_colors.insert("navajowhite", Color(1.00, 0.87, 0.68));
- _named_colors.insert("navyblue", Color(0.00, 0.00, 0.50));
- _named_colors.insert("oldlace", Color(0.99, 0.96, 0.90));
- _named_colors.insert("olive", Color(0.50, 0.50, 0.00));
- _named_colors.insert("olivedrab", Color(0.42, 0.56, 0.14));
- _named_colors.insert("orange", Color(1.00, 0.65, 0.00));
- _named_colors.insert("orangered", Color(1.00, 0.27, 0.00));
- _named_colors.insert("orchid", Color(0.85, 0.44, 0.84));
- _named_colors.insert("palegoldenrod", Color(0.93, 0.91, 0.67));
- _named_colors.insert("palegreen", Color(0.60, 0.98, 0.60));
- _named_colors.insert("paleturquoise", Color(0.69, 0.93, 0.93));
- _named_colors.insert("palevioletred", Color(0.86, 0.44, 0.58));
- _named_colors.insert("papayawhip", Color(1.00, 0.94, 0.84));
- _named_colors.insert("peachpuff", Color(1.00, 0.85, 0.73));
- _named_colors.insert("peru", Color(0.80, 0.52, 0.25));
- _named_colors.insert("pink", Color(1.00, 0.75, 0.80));
- _named_colors.insert("plum", Color(0.87, 0.63, 0.87));
- _named_colors.insert("powderblue", Color(0.69, 0.88, 0.90));
- _named_colors.insert("purple", Color(0.63, 0.13, 0.94));
- _named_colors.insert("webpurple", Color(0.50, 0.00, 0.50));
- _named_colors.insert("rebeccapurple", Color(0.40, 0.20, 0.60));
- _named_colors.insert("red", Color(1.00, 0.00, 0.00));
- _named_colors.insert("rosybrown", Color(0.74, 0.56, 0.56));
- _named_colors.insert("royalblue", Color(0.25, 0.41, 0.88));
- _named_colors.insert("saddlebrown", Color(0.55, 0.27, 0.07));
- _named_colors.insert("salmon", Color(0.98, 0.50, 0.45));
- _named_colors.insert("sandybrown", Color(0.96, 0.64, 0.38));
- _named_colors.insert("seagreen", Color(0.18, 0.55, 0.34));
- _named_colors.insert("seashell", Color(1.00, 0.96, 0.93));
- _named_colors.insert("sienna", Color(0.63, 0.32, 0.18));
- _named_colors.insert("silver", Color(0.75, 0.75, 0.75));
- _named_colors.insert("skyblue", Color(0.53, 0.81, 0.92));
- _named_colors.insert("slateblue", Color(0.42, 0.35, 0.80));
- _named_colors.insert("slategray", Color(0.44, 0.50, 0.56));
- _named_colors.insert("snow", Color(1.00, 0.98, 0.98));
- _named_colors.insert("springgreen", Color(0.00, 1.00, 0.50));
- _named_colors.insert("steelblue", Color(0.27, 0.51, 0.71));
- _named_colors.insert("tan", Color(0.82, 0.71, 0.55));
- _named_colors.insert("teal", Color(0.00, 0.50, 0.50));
- _named_colors.insert("thistle", Color(0.85, 0.75, 0.85));
- _named_colors.insert("tomato", Color(1.00, 0.39, 0.28));
- _named_colors.insert("turquoise", Color(0.25, 0.88, 0.82));
- _named_colors.insert("transparent", Color(1.00, 1.00, 1.00, 0.00));
- _named_colors.insert("violet", Color(0.93, 0.51, 0.93));
- _named_colors.insert("wheat", Color(0.96, 0.87, 0.70));
- _named_colors.insert("white", Color(1.00, 1.00, 1.00));
- _named_colors.insert("whitesmoke", Color(0.96, 0.96, 0.96));
- _named_colors.insert("yellow", Color(1.00, 1.00, 0.00));
- _named_colors.insert("yellowgreen", Color(0.60, 0.80, 0.20));
-}
diff --git a/core/config/SCsub b/core/config/SCsub
new file mode 100644
index 0000000000..bf70285490
--- /dev/null
+++ b/core/config/SCsub
@@ -0,0 +1,7 @@
+#!/usr/bin/env python
+
+Import("env")
+
+env_config = env.Clone()
+
+env_config.add_source_files(env.core_sources, "*.cpp")
diff --git a/core/engine.cpp b/core/config/engine.cpp
index c8bfffd020..26f8cdf840 100644
--- a/core/engine.cpp
+++ b/core/config/engine.cpp
@@ -158,8 +158,10 @@ Array Engine::get_copyright_info() const {
Dictionary Engine::get_donor_info() const {
Dictionary donors;
- donors["platinum_sponsors"] = array_from_info(DONORS_SPONSOR_PLAT);
+ donors["platinum_sponsors"] = array_from_info(DONORS_SPONSOR_PLATINUM);
donors["gold_sponsors"] = array_from_info(DONORS_SPONSOR_GOLD);
+ donors["silver_sponsors"] = array_from_info(DONORS_SPONSOR_SILVER);
+ donors["bronze_sponsors"] = array_from_info(DONORS_SPONSOR_BRONZE);
donors["mini_sponsors"] = array_from_info(DONORS_SPONSOR_MINI);
donors["gold_donors"] = array_from_info(DONORS_GOLD);
donors["silver_donors"] = array_from_info(DONORS_SILVER);
@@ -179,6 +181,14 @@ String Engine::get_license_text() const {
return String(GODOT_LICENSE_TEXT);
}
+bool Engine::is_abort_on_gpu_errors_enabled() const {
+ return abort_on_gpu_errors;
+}
+
+bool Engine::is_validation_layers_enabled() const {
+ return use_validation_layers;
+}
+
void Engine::add_singleton(const Singleton &p_singleton) {
singletons.push_back(p_singleton);
singleton_ptrs[p_singleton.name] = p_singleton.ptr;
@@ -206,10 +216,17 @@ Engine *Engine::get_singleton() {
return singleton;
}
-bool Engine::is_abort_on_gpu_errors_enabled() const {
- return abort_on_gpu_errors;
-}
-
Engine::Engine() {
singleton = this;
}
+
+Engine::Singleton::Singleton(const StringName &p_name, Object *p_ptr) :
+ name(p_name),
+ ptr(p_ptr) {
+#ifdef DEBUG_ENABLED
+ Reference *ref = Object::cast_to<Reference>(p_ptr);
+ if (ref && !ref->is_referenced()) {
+ WARN_PRINT("You must use Ref<> to ensure the lifetime of a Reference object intended to be used as a singleton.");
+ }
+#endif
+}
diff --git a/core/engine.h b/core/config/engine.h
index fef330c0c1..0d9aa02f28 100644
--- a/core/engine.h
+++ b/core/config/engine.h
@@ -31,20 +31,17 @@
#ifndef ENGINE_H
#define ENGINE_H
-#include "core/list.h"
#include "core/os/main_loop.h"
-#include "core/ustring.h"
-#include "core/vector.h"
+#include "core/string/ustring.h"
+#include "core/templates/list.h"
+#include "core/templates/vector.h"
class Engine {
public:
struct Singleton {
StringName name;
Object *ptr;
- Singleton(const StringName &p_name = StringName(), Object *p_ptr = nullptr) :
- name(p_name),
- ptr(p_ptr) {
- }
+ Singleton(const StringName &p_name = StringName(), Object *p_ptr = nullptr);
};
private:
@@ -60,10 +57,10 @@ private:
float _fps = 1;
int _target_fps = 0;
float _time_scale = 1.0;
- bool _pixel_snap = false;
uint64_t _physics_frames = 0;
float _physics_interpolation_fraction = 0.0f;
bool abort_on_gpu_errors = false;
+ bool use_validation_layers = false;
uint64_t _idle_frames = 0;
bool _in_physics = false;
@@ -109,8 +106,6 @@ public:
bool has_singleton(const String &p_name) const;
Object *get_singleton_object(const String &p_name) const;
- _FORCE_INLINE_ bool get_use_pixel_snap() const { return _pixel_snap; }
-
#ifdef TOOLS_ENABLED
_FORCE_INLINE_ void set_editor_hint(bool p_enabled) { editor_hint = p_enabled; }
_FORCE_INLINE_ bool is_editor_hint() const { return editor_hint; }
@@ -127,6 +122,7 @@ public:
String get_license_text() const;
bool is_abort_on_gpu_errors_enabled() const;
+ bool is_validation_layers_enabled() const;
Engine();
virtual ~Engine() {}
diff --git a/core/project_settings.cpp b/core/config/project_settings.cpp
index 7e96735d67..8b8aff3e9e 100644
--- a/core/project_settings.cpp
+++ b/core/config/project_settings.cpp
@@ -30,7 +30,7 @@
#include "project_settings.h"
-#include "core/bind/core_bind.h"
+#include "core/core_bind.h"
#include "core/core_string_names.h"
#include "core/io/file_access_network.h"
#include "core/io/file_access_pack.h"
@@ -39,7 +39,7 @@
#include "core/os/file_access.h"
#include "core/os/keyboard.h"
#include "core/os/os.h"
-#include "core/variant_parser.h"
+#include "core/variant/variant_parser.h"
#include <zlib.h>
@@ -53,6 +53,8 @@ String ProjectSettings::get_resource_path() const {
return resource_path;
}
+const String ProjectSettings::IMPORTED_FILES_PATH("res://.godot/imported");
+
String ProjectSettings::localize_path(const String &p_path) const {
if (resource_path == "") {
return p_path; //not initialized yet
@@ -122,6 +124,22 @@ void ProjectSettings::set_restart_if_changed(const String &p_name, bool p_restar
props[p_name].restart_if_changed = p_restart;
}
+void ProjectSettings::set_ignore_value_in_docs(const String &p_name, bool p_ignore) {
+ ERR_FAIL_COND_MSG(!props.has(p_name), "Request for nonexistent project setting: " + p_name + ".");
+#ifdef DEBUG_METHODS_ENABLED
+ props[p_name].ignore_value_in_docs = p_ignore;
+#endif
+}
+
+bool ProjectSettings::get_ignore_value_in_docs(const String &p_name) const {
+ ERR_FAIL_COND_V_MSG(!props.has(p_name), false, "Request for nonexistent project setting: " + p_name + ".");
+#ifdef DEBUG_METHODS_ENABLED
+ return props[p_name].ignore_value_in_docs;
+#else
+ return false;
+#endif
+}
+
String ProjectSettings::globalize_path(const String &p_path) const {
if (p_path.begins_with("res://")) {
if (resource_path != "") {
@@ -144,6 +162,12 @@ bool ProjectSettings::_set(const StringName &p_name, const Variant &p_value) {
if (p_value.get_type() == Variant::NIL) {
props.erase(p_name);
+ if (p_name.operator String().begins_with("autoload/")) {
+ String node_name = p_name.operator String().split("/")[1];
+ if (autoloads.has(node_name)) {
+ remove_autoload(node_name);
+ }
+ }
} else {
if (p_name == CoreStringNames::get_singleton()->_custom_features) {
Vector<String> custom_feature_array = String(p_value).split(",");
@@ -181,6 +205,19 @@ bool ProjectSettings::_set(const StringName &p_name, const Variant &p_value) {
} else {
props[p_name] = VariantContainer(p_value, last_order++);
}
+ if (p_name.operator String().begins_with("autoload/")) {
+ String node_name = p_name.operator String().split("/")[1];
+ AutoloadInfo autoload;
+ autoload.name = node_name;
+ String path = p_value;
+ if (path.begins_with("*")) {
+ autoload.is_singleton = true;
+ autoload.path = path.substr(1);
+ } else {
+ autoload.path = path;
+ }
+ add_autoload(autoload);
+ }
}
return true;
@@ -256,12 +293,12 @@ void ProjectSettings::_get_property_list(List<PropertyInfo> *p_list) const {
}
}
-bool ProjectSettings::_load_resource_pack(const String &p_pack, bool p_replace_files) {
+bool ProjectSettings::_load_resource_pack(const String &p_pack, bool p_replace_files, int p_offset) {
if (PackedData::get_singleton()->is_disabled()) {
return false;
}
- bool ok = PackedData::get_singleton()->add_pack(p_pack, p_replace_files) == OK;
+ bool ok = PackedData::get_singleton()->add_pack(p_pack, p_replace_files, p_offset) == OK;
if (!ok) {
return false;
@@ -469,6 +506,14 @@ Error ProjectSettings::setup(const String &p_path, const String &p_main_pack, bo
_load_settings_text(custom_settings);
}
}
+ // Using GLOBAL_GET on every block for compressing can be slow, so assigning here.
+ Compression::zstd_long_distance_matching = GLOBAL_GET("compression/formats/zstd/long_distance_matching");
+ Compression::zstd_level = GLOBAL_GET("compression/formats/zstd/compression_level");
+ Compression::zstd_window_log_size = GLOBAL_GET("compression/formats/zstd/window_log_size");
+
+ Compression::zlib_level = GLOBAL_GET("compression/formats/zlib/compression_level");
+
+ Compression::gzip_level = GLOBAL_GET("compression/formats/gzip/compression_level");
return err;
}
@@ -479,10 +524,6 @@ bool ProjectSettings::has_setting(String p_var) const {
return props.has(p_var);
}
-void ProjectSettings::set_registering_order(bool p_enable) {
- registering_order = p_enable;
-}
-
Error ProjectSettings::_load_settings_binary(const String &p_path) {
Error err;
FileAccess *f = FileAccess::open(p_path, FileAccess::READ, &err);
@@ -584,19 +625,26 @@ Error ProjectSettings::_load_settings_text(const String &p_path) {
}
Error ProjectSettings::_load_settings_text_or_binary(const String &p_text_path, const String &p_bin_path) {
- // Attempt first to load the text-based project.godot file
- Error err_text = _load_settings_text(p_text_path);
- if (err_text == OK) {
+ // Attempt first to load the binary project.godot file.
+ Error err = _load_settings_binary(p_bin_path);
+ if (err == OK) {
+ return OK;
+ } else if (err != ERR_FILE_NOT_FOUND) {
+ // If the file exists but can't be loaded, we want to know it.
+ ERR_PRINT("Couldn't load file '" + p_bin_path + "', error code " + itos(err) + ".");
+ return err;
+ }
+
+ // Fallback to text-based project.godot file if binary was not found.
+ err = _load_settings_text(p_text_path);
+ if (err == OK) {
return OK;
- } else if (err_text != ERR_FILE_NOT_FOUND) {
- // If the text-based file exists but can't be loaded, we want to know it
- ERR_PRINT("Couldn't load file '" + p_text_path + "', error code " + itos(err_text) + ".");
- return err_text;
+ } else if (err != ERR_FILE_NOT_FOUND) {
+ ERR_PRINT("Couldn't load file '" + p_text_path + "', error code " + itos(err) + ".");
+ return err;
}
- // Fallback to binary project.binary file if text-based was not found
- Error err_bin = _load_settings_binary(p_bin_path);
- return err_bin;
+ return err;
}
int ProjectSettings::get_order(const String &p_name) const {
@@ -616,6 +664,12 @@ void ProjectSettings::set_builtin_order(const String &p_name) {
}
}
+bool ProjectSettings::is_builtin_setting(const String &p_name) const {
+ // Return true because a false negative is worse than a false positive.
+ ERR_FAIL_COND_V_MSG(!props.has(p_name), true, "Request for nonexistent project setting: " + p_name + ".");
+ return props[p_name].order < NO_BUILTIN_ORDER_BASE;
+}
+
void ProjectSettings::clear(const String &p_name) {
ERR_FAIL_COND_MSG(!props.has(p_name), "Request for nonexistent project setting: " + p_name + ".");
props.erase(p_name);
@@ -849,7 +903,7 @@ Error ProjectSettings::save_custom(const String &p_path, const CustomMap &p_cust
}
}
-Variant _GLOBAL_DEF(const String &p_var, const Variant &p_default, bool p_restart_if_changed) {
+Variant _GLOBAL_DEF(const String &p_var, const Variant &p_default, bool p_restart_if_changed, bool p_ignore_value_in_docs) {
Variant ret;
if (!ProjectSettings::get_singleton()->has_setting(p_var)) {
ProjectSettings::get_singleton()->set(p_var, p_default);
@@ -859,6 +913,7 @@ Variant _GLOBAL_DEF(const String &p_var, const Variant &p_default, bool p_restar
ProjectSettings::get_singleton()->set_initial_value(p_var, p_default);
ProjectSettings::get_singleton()->set_builtin_order(p_var);
ProjectSettings::get_singleton()->set_restart_if_changed(p_var, p_restart_if_changed);
+ ProjectSettings::get_singleton()->set_ignore_value_in_docs(p_var, p_ignore_value_in_docs);
return ret;
}
@@ -945,6 +1000,29 @@ bool ProjectSettings::has_custom_feature(const String &p_feature) const {
return custom_features.has(p_feature);
}
+Map<StringName, ProjectSettings::AutoloadInfo> ProjectSettings::get_autoload_list() const {
+ return autoloads;
+}
+
+void ProjectSettings::add_autoload(const AutoloadInfo &p_autoload) {
+ ERR_FAIL_COND_MSG(p_autoload.name == StringName(), "Trying to add autoload with no name.");
+ autoloads[p_autoload.name] = p_autoload;
+}
+
+void ProjectSettings::remove_autoload(const StringName &p_autoload) {
+ ERR_FAIL_COND_MSG(!autoloads.has(p_autoload), "Trying to remove non-existent autoload.");
+ autoloads.erase(p_autoload);
+}
+
+bool ProjectSettings::has_autoload(const StringName &p_autoload) const {
+ return autoloads.has(p_autoload);
+}
+
+ProjectSettings::AutoloadInfo ProjectSettings::get_autoload(const StringName &p_name) const {
+ ERR_FAIL_COND_V_MSG(!autoloads.has(p_name), AutoloadInfo(), "Trying to get non-existent autoload.");
+ return autoloads[p_name];
+}
+
void ProjectSettings::_bind_methods() {
ClassDB::bind_method(D_METHOD("has_setting", "name"), &ProjectSettings::has_setting);
ClassDB::bind_method(D_METHOD("set_setting", "name", "value"), &ProjectSettings::set_setting);
@@ -957,7 +1035,7 @@ void ProjectSettings::_bind_methods() {
ClassDB::bind_method(D_METHOD("localize_path", "path"), &ProjectSettings::localize_path);
ClassDB::bind_method(D_METHOD("globalize_path", "path"), &ProjectSettings::globalize_path);
ClassDB::bind_method(D_METHOD("save"), &ProjectSettings::save);
- ClassDB::bind_method(D_METHOD("load_resource_pack", "pack", "replace_files"), &ProjectSettings::_load_resource_pack, DEFVAL(true));
+ ClassDB::bind_method(D_METHOD("load_resource_pack", "pack", "replace_files", "offset"), &ProjectSettings::_load_resource_pack, DEFVAL(true), DEFVAL(0));
ClassDB::bind_method(D_METHOD("property_can_revert", "name"), &ProjectSettings::property_can_revert);
ClassDB::bind_method(D_METHOD("property_get_revert", "name"), &ProjectSettings::property_get_revert);
@@ -965,6 +1043,9 @@ void ProjectSettings::_bind_methods() {
}
ProjectSettings::ProjectSettings() {
+ // Initialization of engine variables should be done in the setup() method,
+ // so that the values can be overridden from project.godot or project.binary.
+
singleton = this;
Array events;
@@ -1164,18 +1245,17 @@ ProjectSettings::ProjectSettings() {
GLOBAL_DEF("debug/settings/profiler/max_functions", 16384);
custom_prop_info["debug/settings/profiler/max_functions"] = PropertyInfo(Variant::INT, "debug/settings/profiler/max_functions", PROPERTY_HINT_RANGE, "128,65535,1");
- //assigning here, because using GLOBAL_GET on every block for compressing can be slow
- Compression::zstd_long_distance_matching = GLOBAL_DEF("compression/formats/zstd/long_distance_matching", false);
+ GLOBAL_DEF("compression/formats/zstd/long_distance_matching", Compression::zstd_long_distance_matching);
custom_prop_info["compression/formats/zstd/long_distance_matching"] = PropertyInfo(Variant::BOOL, "compression/formats/zstd/long_distance_matching");
- Compression::zstd_level = GLOBAL_DEF("compression/formats/zstd/compression_level", 3);
+ GLOBAL_DEF("compression/formats/zstd/compression_level", Compression::zstd_level);
custom_prop_info["compression/formats/zstd/compression_level"] = PropertyInfo(Variant::INT, "compression/formats/zstd/compression_level", PROPERTY_HINT_RANGE, "1,22,1");
- Compression::zstd_window_log_size = GLOBAL_DEF("compression/formats/zstd/window_log_size", 27);
+ GLOBAL_DEF("compression/formats/zstd/window_log_size", Compression::zstd_window_log_size);
custom_prop_info["compression/formats/zstd/window_log_size"] = PropertyInfo(Variant::INT, "compression/formats/zstd/window_log_size", PROPERTY_HINT_RANGE, "10,30,1");
- Compression::zlib_level = GLOBAL_DEF("compression/formats/zlib/compression_level", Z_DEFAULT_COMPRESSION);
+ GLOBAL_DEF("compression/formats/zlib/compression_level", Compression::zlib_level);
custom_prop_info["compression/formats/zlib/compression_level"] = PropertyInfo(Variant::INT, "compression/formats/zlib/compression_level", PROPERTY_HINT_RANGE, "-1,9,1");
- Compression::gzip_level = GLOBAL_DEF("compression/formats/gzip/compression_level", Z_DEFAULT_COMPRESSION);
+ GLOBAL_DEF("compression/formats/gzip/compression_level", Compression::gzip_level);
custom_prop_info["compression/formats/gzip/compression_level"] = PropertyInfo(Variant::INT, "compression/formats/gzip/compression_level", PROPERTY_HINT_RANGE, "-1,9,1");
}
diff --git a/core/project_settings.h b/core/config/project_settings.h
index 3ed80738a1..5a16248c76 100644
--- a/core/project_settings.h
+++ b/core/config/project_settings.h
@@ -31,9 +31,9 @@
#ifndef PROJECT_SETTINGS_H
#define PROJECT_SETTINGS_H
-#include "core/object.h"
+#include "core/object/class_db.h"
#include "core/os/thread_safe.h"
-#include "core/set.h"
+#include "core/templates/set.h"
class ProjectSettings : public Object {
GDCLASS(ProjectSettings, Object);
@@ -41,12 +41,19 @@ class ProjectSettings : public Object {
public:
typedef Map<String, Variant> CustomMap;
+ static const String IMPORTED_FILES_PATH;
enum {
//properties that are not for built in values begin from this value, so builtin ones are displayed first
NO_BUILTIN_ORDER_BASE = 1 << 16
};
+ struct AutoloadInfo {
+ StringName name;
+ String path;
+ bool is_singleton = false;
+ };
+
protected:
struct VariantContainer {
int order = 0;
@@ -56,6 +63,9 @@ protected:
bool hide_from_editor = false;
bool overridden = false;
bool restart_if_changed = false;
+#ifdef DEBUG_METHODS_ENABLED
+ bool ignore_value_in_docs = false;
+#endif
VariantContainer() {}
@@ -66,9 +76,8 @@ protected:
}
};
- bool registering_order = true;
- int last_order = 0;
- int last_builtin_order = NO_BUILTIN_ORDER_BASE;
+ int last_order = NO_BUILTIN_ORDER_BASE;
+ int last_builtin_order = 0;
Map<StringName, VariantContainer> props;
String resource_path;
Map<StringName, PropertyInfo> custom_prop_info;
@@ -79,6 +88,8 @@ protected:
Set<String> custom_features;
Map<StringName, StringName> feature_overrides;
+ Map<StringName, AutoloadInfo> autoloads;
+
bool _set(const StringName &p_name, const Variant &p_value);
bool _get(const StringName &p_name, Variant &r_ret) const;
void _get_property_list(List<PropertyInfo> *p_list) const;
@@ -96,7 +107,7 @@ protected:
void _convert_to_last_version(int p_from_version);
- bool _load_resource_pack(const String &p_pack, bool p_replace_files = true);
+ bool _load_resource_pack(const String &p_pack, bool p_replace_files = true, int p_offset = 0);
void _add_property_info_bind(const Dictionary &p_info);
@@ -117,6 +128,9 @@ public:
void set_initial_value(const String &p_name, const Variant &p_value);
void set_restart_if_changed(const String &p_name, bool p_restart);
+ void set_ignore_value_in_docs(const String &p_name, bool p_ignore);
+ bool get_ignore_value_in_docs(const String &p_name) const;
+
bool property_can_revert(const String &p_name);
Variant property_get_revert(const String &p_name);
@@ -128,6 +142,7 @@ public:
int get_order(const String &p_name) const;
void set_order(const String &p_name, int p_order);
void set_builtin_order(const String &p_name);
+ bool is_builtin_setting(const String &p_name) const;
Error setup(const String &p_path, const String &p_main_pack, bool p_upwards = false);
@@ -144,18 +159,24 @@ public:
bool is_using_datapack() const;
- void set_registering_order(bool p_enable);
-
bool has_custom_feature(const String &p_feature) const;
+ Map<StringName, AutoloadInfo> get_autoload_list() const;
+ void add_autoload(const AutoloadInfo &p_autoload);
+ void remove_autoload(const StringName &p_autoload);
+ bool has_autoload(const StringName &p_autoload) const;
+ AutoloadInfo get_autoload(const StringName &p_name) const;
+
ProjectSettings();
~ProjectSettings();
};
//not a macro any longer
-Variant _GLOBAL_DEF(const String &p_var, const Variant &p_default, bool p_restart_if_changed = false);
+Variant _GLOBAL_DEF(const String &p_var, const Variant &p_default, bool p_restart_if_changed = false, bool p_ignore_value_in_docs = false);
#define GLOBAL_DEF(m_var, m_value) _GLOBAL_DEF(m_var, m_value)
#define GLOBAL_DEF_RST(m_var, m_value) _GLOBAL_DEF(m_var, m_value, true)
+#define GLOBAL_DEF_NOVAL(m_var, m_value) _GLOBAL_DEF(m_var, m_value, false, true)
+#define GLOBAL_DEF_RST_NOVAL(m_var, m_value) _GLOBAL_DEF(m_var, m_value, true, true)
#define GLOBAL_GET(m_var) ProjectSettings::get_singleton()->get(m_var)
#endif // PROJECT_SETTINGS_H
diff --git a/core/bind/core_bind.cpp b/core/core_bind.cpp
index cb82dc7f8f..259d899d39 100644
--- a/core/bind/core_bind.cpp
+++ b/core/core_bind.cpp
@@ -30,7 +30,9 @@
#include "core_bind.h"
+#include "core/config/project_settings.h"
#include "core/crypto/crypto_core.h"
+#include "core/debugger/engine_debugger.h"
#include "core/io/file_access_compressed.h"
#include "core/io/file_access_encrypted.h"
#include "core/io/json.h"
@@ -39,7 +41,6 @@
#include "core/math/geometry_3d.h"
#include "core/os/keyboard.h"
#include "core/os/os.h"
-#include "core/project_settings.h"
/**
* Time constants borrowed from loc_time.h
@@ -518,10 +519,6 @@ uint64_t _OS::get_ticks_usec() const {
return OS::get_singleton()->get_ticks_usec();
}
-uint32_t _OS::get_splash_tick_msec() const {
- return OS::get_singleton()->get_splash_tick_msec();
-}
-
bool _OS::can_use_threads() const {
return OS::get_singleton()->can_use_threads();
}
@@ -545,9 +542,9 @@ void _OS::dump_memory_to_file(const String &p_file) {
struct _OSCoreBindImg {
String path;
Size2 size;
- int fmt;
+ int fmt = 0;
ObjectID id;
- int vram;
+ int vram = 0;
bool operator<(const _OSCoreBindImg &p_img) const { return vram == p_img.vram ? id < p_img.id : vram > p_img.vram; }
};
@@ -729,7 +726,6 @@ void _OS::_bind_methods() {
ClassDB::bind_method(D_METHOD("delay_msec", "msec"), &_OS::delay_msec);
ClassDB::bind_method(D_METHOD("get_ticks_msec"), &_OS::get_ticks_msec);
ClassDB::bind_method(D_METHOD("get_ticks_usec"), &_OS::get_ticks_usec);
- ClassDB::bind_method(D_METHOD("get_splash_tick_msec"), &_OS::get_splash_tick_msec);
ClassDB::bind_method(D_METHOD("get_locale"), &_OS::get_locale);
ClassDB::bind_method(D_METHOD("get_model_name"), &_OS::get_model_name);
@@ -781,6 +777,7 @@ void _OS::_bind_methods() {
// Those default values need to be specified for the docs generator,
// to avoid using values from the documentation writer's own OS instance.
+ ADD_PROPERTY_DEFAULT("tablet_driver", "");
ADD_PROPERTY_DEFAULT("exit_code", 0);
ADD_PROPERTY_DEFAULT("low_processor_usage_mode", false);
ADD_PROPERTY_DEFAULT("low_processor_usage_mode_sleep_usec", 6900);
@@ -1159,10 +1156,6 @@ Vector<Vector3> _Geometry3D::clip_polygon(const Vector<Vector3> &p_points, const
return Geometry3D::clip_polygon(p_points, p_plane);
}
-int _Geometry3D::get_uv84_normal_bit(const Vector3 &p_vector) {
- return Geometry3D::get_uv84_normal_bit(p_vector);
-}
-
void _Geometry3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("build_box_planes", "extents"), &_Geometry3D::build_box_planes);
ClassDB::bind_method(D_METHOD("build_cylinder_planes", "radius", "height", "sides", "axis"), &_Geometry3D::build_cylinder_planes, DEFVAL(Vector3::AXIS_Z));
@@ -1174,8 +1167,6 @@ void _Geometry3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_closest_point_to_segment_uncapped", "point", "s1", "s2"), &_Geometry3D::get_closest_point_to_segment_uncapped);
- ClassDB::bind_method(D_METHOD("get_uv84_normal_bit", "normal"), &_Geometry3D::get_uv84_normal_bit);
-
ClassDB::bind_method(D_METHOD("ray_intersects_triangle", "from", "dir", "a", "b", "c"), &_Geometry3D::ray_intersects_triangle);
ClassDB::bind_method(D_METHOD("segment_intersects_triangle", "from", "to", "a", "b", "c"), &_Geometry3D::segment_intersects_triangle);
ClassDB::bind_method(D_METHOD("segment_intersects_sphere", "from", "to", "sphere_position", "sphere_radius"), &_Geometry3D::segment_intersects_sphere);
@@ -1619,12 +1610,17 @@ Error _Directory::open(const String &p_path) {
memdelete(d);
}
d = alt;
+ dir_open = true;
return OK;
}
+bool _Directory::is_open() const {
+ return d && dir_open;
+}
+
Error _Directory::list_dir_begin(bool p_skip_navigational, bool p_skip_hidden) {
- ERR_FAIL_COND_V_MSG(!d, ERR_UNCONFIGURED, "Directory must be opened before use.");
+ ERR_FAIL_COND_V_MSG(!is_open(), ERR_UNCONFIGURED, "Directory must be opened before use.");
_list_skip_navigational = p_skip_navigational;
_list_skip_hidden = p_skip_hidden;
@@ -1633,7 +1629,7 @@ Error _Directory::list_dir_begin(bool p_skip_navigational, bool p_skip_hidden) {
}
String _Directory::get_next() {
- ERR_FAIL_COND_V_MSG(!d, "", "Directory must be opened before use.");
+ ERR_FAIL_COND_V_MSG(!is_open(), "", "Directory must be opened before use.");
String next = d->get_next();
while (next != "" && ((_list_skip_navigational && (next == "." || next == "..")) || (_list_skip_hidden && d->current_is_hidden()))) {
@@ -1643,42 +1639,49 @@ String _Directory::get_next() {
}
bool _Directory::current_is_dir() const {
- ERR_FAIL_COND_V_MSG(!d, false, "Directory must be opened before use.");
+ ERR_FAIL_COND_V_MSG(!is_open(), false, "Directory must be opened before use.");
return d->current_is_dir();
}
void _Directory::list_dir_end() {
- ERR_FAIL_COND_MSG(!d, "Directory must be opened before use.");
+ ERR_FAIL_COND_MSG(!is_open(), "Directory must be opened before use.");
d->list_dir_end();
}
int _Directory::get_drive_count() {
- ERR_FAIL_COND_V_MSG(!d, 0, "Directory must be opened before use.");
+ ERR_FAIL_COND_V_MSG(!is_open(), 0, "Directory must be opened before use.");
return d->get_drive_count();
}
String _Directory::get_drive(int p_drive) {
- ERR_FAIL_COND_V_MSG(!d, "", "Directory must be opened before use.");
+ ERR_FAIL_COND_V_MSG(!is_open(), "", "Directory must be opened before use.");
return d->get_drive(p_drive);
}
int _Directory::get_current_drive() {
- ERR_FAIL_COND_V_MSG(!d, 0, "Directory must be opened before use.");
+ ERR_FAIL_COND_V_MSG(!is_open(), 0, "Directory must be opened before use.");
return d->get_current_drive();
}
Error _Directory::change_dir(String p_dir) {
- ERR_FAIL_COND_V_MSG(!d, ERR_UNCONFIGURED, "Directory must be opened before use.");
- return d->change_dir(p_dir);
+ ERR_FAIL_COND_V_MSG(!d, ERR_UNCONFIGURED, "Directory is not configured properly.");
+ Error err = d->change_dir(p_dir);
+
+ if (err != OK) {
+ return err;
+ }
+ dir_open = true;
+
+ return OK;
}
String _Directory::get_current_dir() {
- ERR_FAIL_COND_V_MSG(!d, "", "Directory must be opened before use.");
+ ERR_FAIL_COND_V_MSG(!is_open(), "", "Directory must be opened before use.");
return d->get_current_dir();
}
Error _Directory::make_dir(String p_dir) {
- ERR_FAIL_COND_V_MSG(!d, ERR_UNCONFIGURED, "Directory must be opened before use.");
+ ERR_FAIL_COND_V_MSG(!d, ERR_UNCONFIGURED, "Directory is not configured properly.");
if (!p_dir.is_rel_path()) {
DirAccess *d = DirAccess::create_for_path(p_dir);
Error err = d->make_dir(p_dir);
@@ -1689,7 +1692,7 @@ Error _Directory::make_dir(String p_dir) {
}
Error _Directory::make_dir_recursive(String p_dir) {
- ERR_FAIL_COND_V_MSG(!d, ERR_UNCONFIGURED, "Directory must be opened before use.");
+ ERR_FAIL_COND_V_MSG(!d, ERR_UNCONFIGURED, "Directory is not configured properly.");
if (!p_dir.is_rel_path()) {
DirAccess *d = DirAccess::create_for_path(p_dir);
Error err = d->make_dir_recursive(p_dir);
@@ -1700,8 +1703,7 @@ Error _Directory::make_dir_recursive(String p_dir) {
}
bool _Directory::file_exists(String p_file) {
- ERR_FAIL_COND_V_MSG(!d, false, "Directory must be opened before use.");
-
+ ERR_FAIL_COND_V_MSG(!d, false, "Directory is not configured properly.");
if (!p_file.is_rel_path()) {
return FileAccess::exists(p_file);
}
@@ -1710,42 +1712,43 @@ bool _Directory::file_exists(String p_file) {
}
bool _Directory::dir_exists(String p_dir) {
- ERR_FAIL_COND_V_MSG(!d, false, "Directory must be opened before use.");
+ ERR_FAIL_COND_V_MSG(!d, false, "Directory is not configured properly.");
if (!p_dir.is_rel_path()) {
DirAccess *d = DirAccess::create_for_path(p_dir);
bool exists = d->dir_exists(p_dir);
memdelete(d);
return exists;
-
- } else {
- return d->dir_exists(p_dir);
}
+
+ return d->dir_exists(p_dir);
}
int _Directory::get_space_left() {
- ERR_FAIL_COND_V_MSG(!d, 0, "Directory must be opened before use.");
+ ERR_FAIL_COND_V_MSG(!is_open(), 0, "Directory must be opened before use.");
return d->get_space_left() / 1024 * 1024; //return value in megabytes, given binding is int
}
Error _Directory::copy(String p_from, String p_to) {
- ERR_FAIL_COND_V_MSG(!d, ERR_UNCONFIGURED, "Directory must be opened before use.");
+ ERR_FAIL_COND_V_MSG(!is_open(), ERR_UNCONFIGURED, "Directory must be opened before use.");
return d->copy(p_from, p_to);
}
Error _Directory::rename(String p_from, String p_to) {
- ERR_FAIL_COND_V_MSG(!d, ERR_UNCONFIGURED, "Directory must be opened before use.");
+ ERR_FAIL_COND_V_MSG(!is_open(), ERR_UNCONFIGURED, "Directory must be opened before use.");
if (!p_from.is_rel_path()) {
DirAccess *d = DirAccess::create_for_path(p_from);
+ ERR_FAIL_COND_V_MSG(!d->file_exists(p_from), ERR_DOES_NOT_EXIST, "File does not exist.");
Error err = d->rename(p_from, p_to);
memdelete(d);
return err;
}
+ ERR_FAIL_COND_V_MSG(!d->file_exists(p_from), ERR_DOES_NOT_EXIST, "File does not exist.");
return d->rename(p_from, p_to);
}
Error _Directory::remove(String p_name) {
- ERR_FAIL_COND_V_MSG(!d, ERR_UNCONFIGURED, "Directory must be opened before use.");
+ ERR_FAIL_COND_V_MSG(!is_open(), ERR_UNCONFIGURED, "Directory must be opened before use.");
if (!p_name.is_rel_path()) {
DirAccess *d = DirAccess::create_for_path(p_name);
Error err = d->remove(p_name);
@@ -2456,3 +2459,154 @@ Ref<JSONParseResult> _JSON::parse(const String &p_json) {
}
_JSON *_JSON::singleton = nullptr;
+
+////// _EngineDebugger //////
+
+void _EngineDebugger::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("is_active"), &_EngineDebugger::is_active);
+
+ ClassDB::bind_method(D_METHOD("register_profiler", "name", "toggle", "add", "tick"), &_EngineDebugger::register_profiler);
+ ClassDB::bind_method(D_METHOD("unregister_profiler", "name"), &_EngineDebugger::unregister_profiler);
+ ClassDB::bind_method(D_METHOD("is_profiling", "name"), &_EngineDebugger::is_profiling);
+ ClassDB::bind_method(D_METHOD("has_profiler", "name"), &_EngineDebugger::has_profiler);
+
+ ClassDB::bind_method(D_METHOD("profiler_add_frame_data", "name", "data"), &_EngineDebugger::profiler_add_frame_data);
+ ClassDB::bind_method(D_METHOD("profiler_enable", "name", "enable", "arguments"), &_EngineDebugger::profiler_enable, DEFVAL(Array()));
+
+ ClassDB::bind_method(D_METHOD("register_message_capture", "name", "callable"), &_EngineDebugger::register_message_capture);
+ ClassDB::bind_method(D_METHOD("unregister_message_capture", "name"), &_EngineDebugger::unregister_message_capture);
+ ClassDB::bind_method(D_METHOD("has_capture", "name"), &_EngineDebugger::has_capture);
+
+ ClassDB::bind_method(D_METHOD("send_message", "message", "data"), &_EngineDebugger::send_message);
+}
+
+bool _EngineDebugger::is_active() {
+ return EngineDebugger::is_active();
+}
+
+void _EngineDebugger::register_profiler(const StringName &p_name, const Callable &p_toggle, const Callable &p_add, const Callable &p_tick) {
+ ERR_FAIL_COND_MSG(profilers.has(p_name) || has_profiler(p_name), "Profiler already registered: " + p_name);
+ profilers.insert(p_name, ProfilerCallable(p_toggle, p_add, p_tick));
+ ProfilerCallable &p = profilers[p_name];
+ EngineDebugger::Profiler profiler(
+ &p,
+ &_EngineDebugger::call_toggle,
+ &_EngineDebugger::call_add,
+ &_EngineDebugger::call_tick);
+ EngineDebugger::register_profiler(p_name, profiler);
+}
+
+void _EngineDebugger::unregister_profiler(const StringName &p_name) {
+ ERR_FAIL_COND_MSG(!profilers.has(p_name), "Profiler not registered: " + p_name);
+ EngineDebugger::unregister_profiler(p_name);
+ profilers.erase(p_name);
+}
+
+bool _EngineDebugger::_EngineDebugger::is_profiling(const StringName &p_name) {
+ return EngineDebugger::is_profiling(p_name);
+}
+
+bool _EngineDebugger::has_profiler(const StringName &p_name) {
+ return EngineDebugger::has_profiler(p_name);
+}
+
+void _EngineDebugger::profiler_add_frame_data(const StringName &p_name, const Array &p_data) {
+ EngineDebugger::profiler_add_frame_data(p_name, p_data);
+}
+
+void _EngineDebugger::profiler_enable(const StringName &p_name, bool p_enabled, const Array &p_opts) {
+ if (EngineDebugger::get_singleton()) {
+ EngineDebugger::get_singleton()->profiler_enable(p_name, p_enabled, p_opts);
+ }
+}
+
+void _EngineDebugger::register_message_capture(const StringName &p_name, const Callable &p_callable) {
+ ERR_FAIL_COND_MSG(captures.has(p_name) || has_capture(p_name), "Capture already registered: " + p_name);
+ captures.insert(p_name, p_callable);
+ Callable &c = captures[p_name];
+ EngineDebugger::Capture capture(&c, &_EngineDebugger::call_capture);
+ EngineDebugger::register_message_capture(p_name, capture);
+}
+
+void _EngineDebugger::unregister_message_capture(const StringName &p_name) {
+ ERR_FAIL_COND_MSG(!captures.has(p_name), "Capture not registered: " + p_name);
+ EngineDebugger::unregister_message_capture(p_name);
+ captures.erase(p_name);
+}
+
+bool _EngineDebugger::has_capture(const StringName &p_name) {
+ return EngineDebugger::has_capture(p_name);
+}
+
+void _EngineDebugger::send_message(const String &p_msg, const Array &p_data) {
+ ERR_FAIL_COND_MSG(!EngineDebugger::is_active(), "Can't send message. No active debugger");
+ EngineDebugger::get_singleton()->send_message(p_msg, p_data);
+}
+
+void _EngineDebugger::call_toggle(void *p_user, bool p_enable, const Array &p_opts) {
+ Callable &toggle = ((ProfilerCallable *)p_user)->callable_toggle;
+ if (toggle.is_null()) {
+ return;
+ }
+ Variant enable = p_enable, opts = p_opts;
+ const Variant *args[2] = { &enable, &opts };
+ Variant retval;
+ Callable::CallError err;
+ toggle.call(args, 2, retval, err);
+ ERR_FAIL_COND_MSG(err.error != Callable::CallError::CALL_OK, "Error calling 'toggle' to callable: " + Variant::get_callable_error_text(toggle, args, 2, err));
+}
+
+void _EngineDebugger::call_add(void *p_user, const Array &p_data) {
+ Callable &add = ((ProfilerCallable *)p_user)->callable_add;
+ if (add.is_null()) {
+ return;
+ }
+ Variant data = p_data;
+ const Variant *args[1] = { &data };
+ Variant retval;
+ Callable::CallError err;
+ add.call(args, 1, retval, err);
+ ERR_FAIL_COND_MSG(err.error != Callable::CallError::CALL_OK, "Error calling 'add' to callable: " + Variant::get_callable_error_text(add, args, 1, err));
+}
+
+void _EngineDebugger::call_tick(void *p_user, float p_frame_time, float p_idle_time, float p_physics_time, float p_physics_frame_time) {
+ Callable &tick = ((ProfilerCallable *)p_user)->callable_tick;
+ if (tick.is_null()) {
+ return;
+ }
+ Variant frame_time = p_frame_time, idle_time = p_idle_time, physics_time = p_physics_time, physics_frame_time = p_physics_frame_time;
+ const Variant *args[4] = { &frame_time, &idle_time, &physics_time, &physics_frame_time };
+ Variant retval;
+ Callable::CallError err;
+ tick.call(args, 4, retval, err);
+ ERR_FAIL_COND_MSG(err.error != Callable::CallError::CALL_OK, "Error calling 'tick' to callable: " + Variant::get_callable_error_text(tick, args, 4, err));
+}
+
+Error _EngineDebugger::call_capture(void *p_user, const String &p_cmd, const Array &p_data, bool &r_captured) {
+ Callable &capture = *(Callable *)p_user;
+ if (capture.is_null()) {
+ return FAILED;
+ }
+ Variant cmd = p_cmd, data = p_data;
+ const Variant *args[2] = { &cmd, &data };
+ Variant retval;
+ Callable::CallError err;
+ capture.call(args, 2, retval, err);
+ ERR_FAIL_COND_V_MSG(err.error != Callable::CallError::CALL_OK, FAILED, "Error calling 'capture' to callable: " + Variant::get_callable_error_text(capture, args, 2, err));
+ ERR_FAIL_COND_V_MSG(retval.get_type() != Variant::BOOL, FAILED, "Error calling 'capture' to callable: " + String(capture) + ". Return type is not bool.");
+ r_captured = retval;
+ return OK;
+}
+
+_EngineDebugger::~_EngineDebugger() {
+ for (Map<StringName, Callable>::Element *E = captures.front(); E; E = E->next()) {
+ EngineDebugger::unregister_message_capture(E->key());
+ }
+ captures.clear();
+ for (Map<StringName, ProfilerCallable>::Element *E = profilers.front(); E; E = E->next()) {
+ EngineDebugger::unregister_profiler(E->key());
+ }
+ profilers.clear();
+}
+
+_EngineDebugger *_EngineDebugger::singleton = nullptr;
diff --git a/core/bind/core_bind.h b/core/core_bind.h
index f9f5a4e7d7..f3a77a4fa6 100644
--- a/core/bind/core_bind.h
+++ b/core/core_bind.h
@@ -31,8 +31,8 @@
#ifndef CORE_BIND_H
#define CORE_BIND_H
-#include "core/image.h"
#include "core/io/compression.h"
+#include "core/io/image.h"
#include "core/io/resource_loader.h"
#include "core/io/resource_saver.h"
#include "core/os/dir_access.h"
@@ -83,7 +83,6 @@ protected:
public:
enum SaverFlags {
-
FLAG_RELATIVE_PATHS = 1,
FLAG_BUNDLE_RESOURCES = 2,
FLAG_CHANGE_PATH = 4,
@@ -208,7 +207,6 @@ public:
void delay_msec(uint32_t p_msec) const;
uint32_t get_ticks_msec() const;
uint64_t get_ticks_usec() const;
- uint32_t get_splash_tick_msec() const;
bool can_use_threads() const;
@@ -345,7 +343,6 @@ public:
Vector<Vector3> segment_intersects_sphere(const Vector3 &p_from, const Vector3 &p_to, const Vector3 &p_sphere_pos, real_t p_sphere_radius);
Vector<Vector3> segment_intersects_cylinder(const Vector3 &p_from, const Vector3 &p_to, float p_height, float p_radius);
Vector<Vector3> segment_intersects_convex(const Vector3 &p_from, const Vector3 &p_to, const Vector<Plane> &p_planes);
- int get_uv84_normal_bit(const Vector3 &p_vector);
Vector<Vector3> clip_polygon(const Vector<Vector3> &p_points, const Plane &p_plane);
@@ -363,7 +360,6 @@ protected:
public:
enum ModeFlags {
-
READ = 1,
WRITE = 2,
READ_WRITE = 3,
@@ -457,6 +453,7 @@ VARIANT_ENUM_CAST(_File::CompressionMode);
class _Directory : public Reference {
GDCLASS(_Directory, Reference);
DirAccess *d;
+ bool dir_open = false;
protected:
static void _bind_methods();
@@ -464,6 +461,8 @@ protected:
public:
Error open(const String &p_path);
+ bool is_open() const;
+
Error list_dir_begin(bool p_skip_navigational = false, bool p_skip_hidden = false); // This starts dir listing.
String get_next();
bool current_is_dir() const;
@@ -493,8 +492,8 @@ public:
virtual ~_Directory();
private:
- bool _list_skip_navigational;
- bool _list_skip_hidden;
+ bool _list_skip_navigational = false;
+ bool _list_skip_hidden = false;
};
class _Marshalls : public Object {
@@ -560,7 +559,6 @@ protected:
public:
enum Priority {
-
PRIORITY_LOW,
PRIORITY_NORMAL,
PRIORITY_HIGH,
@@ -712,4 +710,58 @@ public:
_JSON() { singleton = this; }
};
+class _EngineDebugger : public Object {
+ GDCLASS(_EngineDebugger, Object);
+
+ class ProfilerCallable {
+ friend class _EngineDebugger;
+
+ Callable callable_toggle;
+ Callable callable_add;
+ Callable callable_tick;
+
+ public:
+ ProfilerCallable() {}
+
+ ProfilerCallable(const Callable &p_toggle, const Callable &p_add, const Callable &p_tick) {
+ callable_toggle = p_toggle;
+ callable_add = p_add;
+ callable_tick = p_tick;
+ }
+ };
+
+ Map<StringName, Callable> captures;
+ Map<StringName, ProfilerCallable> profilers;
+
+protected:
+ static void _bind_methods();
+ static _EngineDebugger *singleton;
+
+public:
+ static _EngineDebugger *get_singleton() { return singleton; }
+
+ bool is_active();
+
+ void register_profiler(const StringName &p_name, const Callable &p_toggle, const Callable &p_add, const Callable &p_tick);
+ void unregister_profiler(const StringName &p_name);
+ bool is_profiling(const StringName &p_name);
+ bool has_profiler(const StringName &p_name);
+ void profiler_add_frame_data(const StringName &p_name, const Array &p_data);
+ void profiler_enable(const StringName &p_name, bool p_enabled, const Array &p_opts = Array());
+
+ void register_message_capture(const StringName &p_name, const Callable &p_callable);
+ void unregister_message_capture(const StringName &p_name);
+ bool has_capture(const StringName &p_name);
+
+ void send_message(const String &p_msg, const Array &p_data);
+
+ static void call_toggle(void *p_user, bool p_enable, const Array &p_opts);
+ static void call_add(void *p_user, const Array &p_data);
+ static void call_tick(void *p_user, float p_frame_time, float p_idle_time, float p_physics_time, float p_physics_frame_time);
+ static Error call_capture(void *p_user, const String &p_cmd, const Array &p_data, bool &r_captured);
+
+ _EngineDebugger() { singleton = this; }
+ ~_EngineDebugger();
+};
+
#endif // CORE_BIND_H
diff --git a/core/core_builders.py b/core/core_builders.py
index d03874608e..004475faa7 100644
--- a/core/core_builders.py
+++ b/core/core_builders.py
@@ -117,14 +117,18 @@ def make_donors_header(target, source, env):
sections = [
"Platinum sponsors",
"Gold sponsors",
+ "Silver sponsors",
+ "Bronze sponsors",
"Mini sponsors",
"Gold donors",
"Silver donors",
"Bronze donors",
]
sections_id = [
- "DONORS_SPONSOR_PLAT",
+ "DONORS_SPONSOR_PLATINUM",
"DONORS_SPONSOR_GOLD",
+ "DONORS_SPONSOR_SILVER",
+ "DONORS_SPONSOR_BRONZE",
"DONORS_SPONSOR_MINI",
"DONORS_GOLD",
"DONORS_SILVER",
diff --git a/core/core_constants.cpp b/core/core_constants.cpp
new file mode 100644
index 0000000000..57ea10c074
--- /dev/null
+++ b/core/core_constants.cpp
@@ -0,0 +1,657 @@
+/*************************************************************************/
+/* core_constants.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* 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. */
+/*************************************************************************/
+
+#include "core_constants.h"
+
+#include "core/input/input_event.h"
+#include "core/object/class_db.h"
+#include "core/os/keyboard.h"
+#include "core/variant/variant.h"
+
+struct _CoreConstant {
+#ifdef DEBUG_METHODS_ENABLED
+ StringName enum_name;
+ bool ignore_value_in_docs = false;
+#endif
+ const char *name;
+ int value = 0;
+
+ _CoreConstant() {}
+
+#ifdef DEBUG_METHODS_ENABLED
+ _CoreConstant(const StringName &p_enum_name, const char *p_name, int p_value, bool p_ignore_value_in_docs = false) :
+ enum_name(p_enum_name),
+ ignore_value_in_docs(p_ignore_value_in_docs),
+ name(p_name),
+ value(p_value) {
+ }
+#else
+ _CoreConstant(const char *p_name, int p_value) :
+ name(p_name),
+ value(p_value) {
+ }
+#endif
+};
+
+static Vector<_CoreConstant> _global_constants;
+
+#ifdef DEBUG_METHODS_ENABLED
+
+#define BIND_CORE_CONSTANT(m_constant) \
+ _global_constants.push_back(_CoreConstant(StringName(), #m_constant, m_constant));
+
+#define BIND_CORE_ENUM_CONSTANT(m_constant) \
+ _global_constants.push_back(_CoreConstant(__constant_get_enum_name(m_constant, #m_constant), #m_constant, m_constant));
+
+#define BIND_CORE_ENUM_CONSTANT_CUSTOM(m_custom_name, m_constant) \
+ _global_constants.push_back(_CoreConstant(__constant_get_enum_name(m_constant, #m_constant), m_custom_name, m_constant));
+
+#define BIND_CORE_CONSTANT_NO_VAL(m_constant) \
+ _global_constants.push_back(_CoreConstant(StringName(), #m_constant, m_constant, true));
+
+#define BIND_CORE_ENUM_CONSTANT_NO_VAL(m_constant) \
+ _global_constants.push_back(_CoreConstant(__constant_get_enum_name(m_constant, #m_constant), #m_constant, m_constant, true));
+
+#define BIND_CORE_ENUM_CONSTANT_CUSTOM_NO_VAL(m_custom_name, m_constant) \
+ _global_constants.push_back(_CoreConstant(__constant_get_enum_name(m_constant, #m_constant), m_custom_name, m_constant, true));
+
+#else
+
+#define BIND_CORE_CONSTANT(m_constant) \
+ _global_constants.push_back(_CoreConstant(#m_constant, m_constant));
+
+#define BIND_CORE_ENUM_CONSTANT(m_constant) \
+ _global_constants.push_back(_CoreConstant(#m_constant, m_constant));
+
+#define BIND_CORE_ENUM_CONSTANT_CUSTOM(m_custom_name, m_constant) \
+ _global_constants.push_back(_CoreConstant(m_custom_name, m_constant));
+
+#define BIND_CORE_CONSTANT_NO_VAL(m_constant) \
+ _global_constants.push_back(_CoreConstant(#m_constant, m_constant));
+
+#define BIND_CORE_ENUM_CONSTANT_NO_VAL(m_constant) \
+ _global_constants.push_back(_CoreConstant(#m_constant, m_constant));
+
+#define BIND_CORE_ENUM_CONSTANT_CUSTOM_NO_VAL(m_custom_name, m_constant) \
+ _global_constants.push_back(_CoreConstant(m_custom_name, m_constant));
+
+#endif
+
+VARIANT_ENUM_CAST(KeyList);
+VARIANT_ENUM_CAST(KeyModifierMask);
+VARIANT_ENUM_CAST(ButtonList);
+VARIANT_ENUM_CAST(JoyButtonList);
+VARIANT_ENUM_CAST(JoyAxisList);
+VARIANT_ENUM_CAST(MidiMessageList);
+
+void register_global_constants() {
+ BIND_CORE_ENUM_CONSTANT(MARGIN_LEFT);
+ BIND_CORE_ENUM_CONSTANT(MARGIN_TOP);
+ BIND_CORE_ENUM_CONSTANT(MARGIN_RIGHT);
+ BIND_CORE_ENUM_CONSTANT(MARGIN_BOTTOM);
+
+ BIND_CORE_ENUM_CONSTANT(CORNER_TOP_LEFT);
+ BIND_CORE_ENUM_CONSTANT(CORNER_TOP_RIGHT);
+ BIND_CORE_ENUM_CONSTANT(CORNER_BOTTOM_RIGHT);
+ BIND_CORE_ENUM_CONSTANT(CORNER_BOTTOM_LEFT);
+
+ BIND_CORE_ENUM_CONSTANT(VERTICAL);
+ BIND_CORE_ENUM_CONSTANT(HORIZONTAL);
+
+ BIND_CORE_ENUM_CONSTANT(HALIGN_LEFT);
+ BIND_CORE_ENUM_CONSTANT(HALIGN_CENTER);
+ BIND_CORE_ENUM_CONSTANT(HALIGN_RIGHT);
+
+ BIND_CORE_ENUM_CONSTANT(VALIGN_TOP);
+ BIND_CORE_ENUM_CONSTANT(VALIGN_CENTER);
+ BIND_CORE_ENUM_CONSTANT(VALIGN_BOTTOM);
+
+ // huge list of keys
+ BIND_CORE_CONSTANT(SPKEY);
+
+ BIND_CORE_ENUM_CONSTANT(KEY_ESCAPE);
+ BIND_CORE_ENUM_CONSTANT(KEY_TAB);
+ BIND_CORE_ENUM_CONSTANT(KEY_BACKTAB);
+ BIND_CORE_ENUM_CONSTANT(KEY_BACKSPACE);
+ BIND_CORE_ENUM_CONSTANT(KEY_ENTER);
+ BIND_CORE_ENUM_CONSTANT(KEY_KP_ENTER);
+ BIND_CORE_ENUM_CONSTANT(KEY_INSERT);
+ BIND_CORE_ENUM_CONSTANT(KEY_DELETE);
+ BIND_CORE_ENUM_CONSTANT(KEY_PAUSE);
+ BIND_CORE_ENUM_CONSTANT(KEY_PRINT);
+ BIND_CORE_ENUM_CONSTANT(KEY_SYSREQ);
+ BIND_CORE_ENUM_CONSTANT(KEY_CLEAR);
+ BIND_CORE_ENUM_CONSTANT(KEY_HOME);
+ BIND_CORE_ENUM_CONSTANT(KEY_END);
+ BIND_CORE_ENUM_CONSTANT(KEY_LEFT);
+ BIND_CORE_ENUM_CONSTANT(KEY_UP);
+ BIND_CORE_ENUM_CONSTANT(KEY_RIGHT);
+ BIND_CORE_ENUM_CONSTANT(KEY_DOWN);
+ BIND_CORE_ENUM_CONSTANT(KEY_PAGEUP);
+ BIND_CORE_ENUM_CONSTANT(KEY_PAGEDOWN);
+ BIND_CORE_ENUM_CONSTANT(KEY_SHIFT);
+ BIND_CORE_ENUM_CONSTANT(KEY_CONTROL);
+ BIND_CORE_ENUM_CONSTANT(KEY_META);
+ BIND_CORE_ENUM_CONSTANT(KEY_ALT);
+ BIND_CORE_ENUM_CONSTANT(KEY_CAPSLOCK);
+ BIND_CORE_ENUM_CONSTANT(KEY_NUMLOCK);
+ BIND_CORE_ENUM_CONSTANT(KEY_SCROLLLOCK);
+ BIND_CORE_ENUM_CONSTANT(KEY_F1);
+ BIND_CORE_ENUM_CONSTANT(KEY_F2);
+ BIND_CORE_ENUM_CONSTANT(KEY_F3);
+ BIND_CORE_ENUM_CONSTANT(KEY_F4);
+ BIND_CORE_ENUM_CONSTANT(KEY_F5);
+ BIND_CORE_ENUM_CONSTANT(KEY_F6);
+ BIND_CORE_ENUM_CONSTANT(KEY_F7);
+ BIND_CORE_ENUM_CONSTANT(KEY_F8);
+ BIND_CORE_ENUM_CONSTANT(KEY_F9);
+ BIND_CORE_ENUM_CONSTANT(KEY_F10);
+ BIND_CORE_ENUM_CONSTANT(KEY_F11);
+ BIND_CORE_ENUM_CONSTANT(KEY_F12);
+ BIND_CORE_ENUM_CONSTANT(KEY_F13);
+ BIND_CORE_ENUM_CONSTANT(KEY_F14);
+ BIND_CORE_ENUM_CONSTANT(KEY_F15);
+ BIND_CORE_ENUM_CONSTANT(KEY_F16);
+ BIND_CORE_ENUM_CONSTANT(KEY_KP_MULTIPLY);
+ BIND_CORE_ENUM_CONSTANT(KEY_KP_DIVIDE);
+ BIND_CORE_ENUM_CONSTANT(KEY_KP_SUBTRACT);
+ BIND_CORE_ENUM_CONSTANT(KEY_KP_PERIOD);
+ BIND_CORE_ENUM_CONSTANT(KEY_KP_ADD);
+ BIND_CORE_ENUM_CONSTANT(KEY_KP_0);
+ BIND_CORE_ENUM_CONSTANT(KEY_KP_1);
+ BIND_CORE_ENUM_CONSTANT(KEY_KP_2);
+ BIND_CORE_ENUM_CONSTANT(KEY_KP_3);
+ BIND_CORE_ENUM_CONSTANT(KEY_KP_4);
+ BIND_CORE_ENUM_CONSTANT(KEY_KP_5);
+ BIND_CORE_ENUM_CONSTANT(KEY_KP_6);
+ BIND_CORE_ENUM_CONSTANT(KEY_KP_7);
+ BIND_CORE_ENUM_CONSTANT(KEY_KP_8);
+ BIND_CORE_ENUM_CONSTANT(KEY_KP_9);
+ BIND_CORE_ENUM_CONSTANT(KEY_SUPER_L);
+ BIND_CORE_ENUM_CONSTANT(KEY_SUPER_R);
+ BIND_CORE_ENUM_CONSTANT(KEY_MENU);
+ BIND_CORE_ENUM_CONSTANT(KEY_HYPER_L);
+ BIND_CORE_ENUM_CONSTANT(KEY_HYPER_R);
+ BIND_CORE_ENUM_CONSTANT(KEY_HELP);
+ BIND_CORE_ENUM_CONSTANT(KEY_DIRECTION_L);
+ BIND_CORE_ENUM_CONSTANT(KEY_DIRECTION_R);
+ BIND_CORE_ENUM_CONSTANT(KEY_BACK);
+ BIND_CORE_ENUM_CONSTANT(KEY_FORWARD);
+ BIND_CORE_ENUM_CONSTANT(KEY_STOP);
+ BIND_CORE_ENUM_CONSTANT(KEY_REFRESH);
+ BIND_CORE_ENUM_CONSTANT(KEY_VOLUMEDOWN);
+ BIND_CORE_ENUM_CONSTANT(KEY_VOLUMEMUTE);
+ BIND_CORE_ENUM_CONSTANT(KEY_VOLUMEUP);
+ BIND_CORE_ENUM_CONSTANT(KEY_BASSBOOST);
+ BIND_CORE_ENUM_CONSTANT(KEY_BASSUP);
+ BIND_CORE_ENUM_CONSTANT(KEY_BASSDOWN);
+ BIND_CORE_ENUM_CONSTANT(KEY_TREBLEUP);
+ BIND_CORE_ENUM_CONSTANT(KEY_TREBLEDOWN);
+ BIND_CORE_ENUM_CONSTANT(KEY_MEDIAPLAY);
+ BIND_CORE_ENUM_CONSTANT(KEY_MEDIASTOP);
+ BIND_CORE_ENUM_CONSTANT(KEY_MEDIAPREVIOUS);
+ BIND_CORE_ENUM_CONSTANT(KEY_MEDIANEXT);
+ BIND_CORE_ENUM_CONSTANT(KEY_MEDIARECORD);
+ BIND_CORE_ENUM_CONSTANT(KEY_HOMEPAGE);
+ BIND_CORE_ENUM_CONSTANT(KEY_FAVORITES);
+ BIND_CORE_ENUM_CONSTANT(KEY_SEARCH);
+ BIND_CORE_ENUM_CONSTANT(KEY_STANDBY);
+ BIND_CORE_ENUM_CONSTANT(KEY_OPENURL);
+ BIND_CORE_ENUM_CONSTANT(KEY_LAUNCHMAIL);
+ BIND_CORE_ENUM_CONSTANT(KEY_LAUNCHMEDIA);
+ BIND_CORE_ENUM_CONSTANT(KEY_LAUNCH0);
+ BIND_CORE_ENUM_CONSTANT(KEY_LAUNCH1);
+ BIND_CORE_ENUM_CONSTANT(KEY_LAUNCH2);
+ BIND_CORE_ENUM_CONSTANT(KEY_LAUNCH3);
+ BIND_CORE_ENUM_CONSTANT(KEY_LAUNCH4);
+ BIND_CORE_ENUM_CONSTANT(KEY_LAUNCH5);
+ BIND_CORE_ENUM_CONSTANT(KEY_LAUNCH6);
+ BIND_CORE_ENUM_CONSTANT(KEY_LAUNCH7);
+ BIND_CORE_ENUM_CONSTANT(KEY_LAUNCH8);
+ BIND_CORE_ENUM_CONSTANT(KEY_LAUNCH9);
+ BIND_CORE_ENUM_CONSTANT(KEY_LAUNCHA);
+ BIND_CORE_ENUM_CONSTANT(KEY_LAUNCHB);
+ BIND_CORE_ENUM_CONSTANT(KEY_LAUNCHC);
+ BIND_CORE_ENUM_CONSTANT(KEY_LAUNCHD);
+ BIND_CORE_ENUM_CONSTANT(KEY_LAUNCHE);
+ BIND_CORE_ENUM_CONSTANT(KEY_LAUNCHF);
+
+ BIND_CORE_ENUM_CONSTANT(KEY_UNKNOWN);
+ BIND_CORE_ENUM_CONSTANT(KEY_SPACE);
+ BIND_CORE_ENUM_CONSTANT(KEY_EXCLAM);
+ BIND_CORE_ENUM_CONSTANT(KEY_QUOTEDBL);
+ BIND_CORE_ENUM_CONSTANT(KEY_NUMBERSIGN);
+ BIND_CORE_ENUM_CONSTANT(KEY_DOLLAR);
+ BIND_CORE_ENUM_CONSTANT(KEY_PERCENT);
+ BIND_CORE_ENUM_CONSTANT(KEY_AMPERSAND);
+ BIND_CORE_ENUM_CONSTANT(KEY_APOSTROPHE);
+ BIND_CORE_ENUM_CONSTANT(KEY_PARENLEFT);
+ BIND_CORE_ENUM_CONSTANT(KEY_PARENRIGHT);
+ BIND_CORE_ENUM_CONSTANT(KEY_ASTERISK);
+ BIND_CORE_ENUM_CONSTANT(KEY_PLUS);
+ BIND_CORE_ENUM_CONSTANT(KEY_COMMA);
+ BIND_CORE_ENUM_CONSTANT(KEY_MINUS);
+ BIND_CORE_ENUM_CONSTANT(KEY_PERIOD);
+ BIND_CORE_ENUM_CONSTANT(KEY_SLASH);
+ BIND_CORE_ENUM_CONSTANT(KEY_0);
+ BIND_CORE_ENUM_CONSTANT(KEY_1);
+ BIND_CORE_ENUM_CONSTANT(KEY_2);
+ BIND_CORE_ENUM_CONSTANT(KEY_3);
+ BIND_CORE_ENUM_CONSTANT(KEY_4);
+ BIND_CORE_ENUM_CONSTANT(KEY_5);
+ BIND_CORE_ENUM_CONSTANT(KEY_6);
+ BIND_CORE_ENUM_CONSTANT(KEY_7);
+ BIND_CORE_ENUM_CONSTANT(KEY_8);
+ BIND_CORE_ENUM_CONSTANT(KEY_9);
+ BIND_CORE_ENUM_CONSTANT(KEY_COLON);
+ BIND_CORE_ENUM_CONSTANT(KEY_SEMICOLON);
+ BIND_CORE_ENUM_CONSTANT(KEY_LESS);
+ BIND_CORE_ENUM_CONSTANT(KEY_EQUAL);
+ BIND_CORE_ENUM_CONSTANT(KEY_GREATER);
+ BIND_CORE_ENUM_CONSTANT(KEY_QUESTION);
+ BIND_CORE_ENUM_CONSTANT(KEY_AT);
+ BIND_CORE_ENUM_CONSTANT(KEY_A);
+ BIND_CORE_ENUM_CONSTANT(KEY_B);
+ BIND_CORE_ENUM_CONSTANT(KEY_C);
+ BIND_CORE_ENUM_CONSTANT(KEY_D);
+ BIND_CORE_ENUM_CONSTANT(KEY_E);
+ BIND_CORE_ENUM_CONSTANT(KEY_F);
+ BIND_CORE_ENUM_CONSTANT(KEY_G);
+ BIND_CORE_ENUM_CONSTANT(KEY_H);
+ BIND_CORE_ENUM_CONSTANT(KEY_I);
+ BIND_CORE_ENUM_CONSTANT(KEY_J);
+ BIND_CORE_ENUM_CONSTANT(KEY_K);
+ BIND_CORE_ENUM_CONSTANT(KEY_L);
+ BIND_CORE_ENUM_CONSTANT(KEY_M);
+ BIND_CORE_ENUM_CONSTANT(KEY_N);
+ BIND_CORE_ENUM_CONSTANT(KEY_O);
+ BIND_CORE_ENUM_CONSTANT(KEY_P);
+ BIND_CORE_ENUM_CONSTANT(KEY_Q);
+ BIND_CORE_ENUM_CONSTANT(KEY_R);
+ BIND_CORE_ENUM_CONSTANT(KEY_S);
+ BIND_CORE_ENUM_CONSTANT(KEY_T);
+ BIND_CORE_ENUM_CONSTANT(KEY_U);
+ BIND_CORE_ENUM_CONSTANT(KEY_V);
+ BIND_CORE_ENUM_CONSTANT(KEY_W);
+ BIND_CORE_ENUM_CONSTANT(KEY_X);
+ BIND_CORE_ENUM_CONSTANT(KEY_Y);
+ BIND_CORE_ENUM_CONSTANT(KEY_Z);
+ BIND_CORE_ENUM_CONSTANT(KEY_BRACKETLEFT);
+ BIND_CORE_ENUM_CONSTANT(KEY_BACKSLASH);
+ BIND_CORE_ENUM_CONSTANT(KEY_BRACKETRIGHT);
+ BIND_CORE_ENUM_CONSTANT(KEY_ASCIICIRCUM);
+ BIND_CORE_ENUM_CONSTANT(KEY_UNDERSCORE);
+ BIND_CORE_ENUM_CONSTANT(KEY_QUOTELEFT);
+ BIND_CORE_ENUM_CONSTANT(KEY_BRACELEFT);
+ BIND_CORE_ENUM_CONSTANT(KEY_BAR);
+ BIND_CORE_ENUM_CONSTANT(KEY_BRACERIGHT);
+ BIND_CORE_ENUM_CONSTANT(KEY_ASCIITILDE);
+ BIND_CORE_ENUM_CONSTANT(KEY_NOBREAKSPACE);
+ BIND_CORE_ENUM_CONSTANT(KEY_EXCLAMDOWN);
+ BIND_CORE_ENUM_CONSTANT(KEY_CENT);
+ BIND_CORE_ENUM_CONSTANT(KEY_STERLING);
+ BIND_CORE_ENUM_CONSTANT(KEY_CURRENCY);
+ BIND_CORE_ENUM_CONSTANT(KEY_YEN);
+ BIND_CORE_ENUM_CONSTANT(KEY_BROKENBAR);
+ BIND_CORE_ENUM_CONSTANT(KEY_SECTION);
+ BIND_CORE_ENUM_CONSTANT(KEY_DIAERESIS);
+ BIND_CORE_ENUM_CONSTANT(KEY_COPYRIGHT);
+ BIND_CORE_ENUM_CONSTANT(KEY_ORDFEMININE);
+ BIND_CORE_ENUM_CONSTANT(KEY_GUILLEMOTLEFT);
+ BIND_CORE_ENUM_CONSTANT(KEY_NOTSIGN);
+ BIND_CORE_ENUM_CONSTANT(KEY_HYPHEN);
+ BIND_CORE_ENUM_CONSTANT(KEY_REGISTERED);
+ BIND_CORE_ENUM_CONSTANT(KEY_MACRON);
+ BIND_CORE_ENUM_CONSTANT(KEY_DEGREE);
+ BIND_CORE_ENUM_CONSTANT(KEY_PLUSMINUS);
+ BIND_CORE_ENUM_CONSTANT(KEY_TWOSUPERIOR);
+ BIND_CORE_ENUM_CONSTANT(KEY_THREESUPERIOR);
+ BIND_CORE_ENUM_CONSTANT(KEY_ACUTE);
+ BIND_CORE_ENUM_CONSTANT(KEY_MU);
+ BIND_CORE_ENUM_CONSTANT(KEY_PARAGRAPH);
+ BIND_CORE_ENUM_CONSTANT(KEY_PERIODCENTERED);
+ BIND_CORE_ENUM_CONSTANT(KEY_CEDILLA);
+ BIND_CORE_ENUM_CONSTANT(KEY_ONESUPERIOR);
+ BIND_CORE_ENUM_CONSTANT(KEY_MASCULINE);
+ BIND_CORE_ENUM_CONSTANT(KEY_GUILLEMOTRIGHT);
+ BIND_CORE_ENUM_CONSTANT(KEY_ONEQUARTER);
+ BIND_CORE_ENUM_CONSTANT(KEY_ONEHALF);
+ BIND_CORE_ENUM_CONSTANT(KEY_THREEQUARTERS);
+ BIND_CORE_ENUM_CONSTANT(KEY_QUESTIONDOWN);
+ BIND_CORE_ENUM_CONSTANT(KEY_AGRAVE);
+ BIND_CORE_ENUM_CONSTANT(KEY_AACUTE);
+ BIND_CORE_ENUM_CONSTANT(KEY_ACIRCUMFLEX);
+ BIND_CORE_ENUM_CONSTANT(KEY_ATILDE);
+ BIND_CORE_ENUM_CONSTANT(KEY_ADIAERESIS);
+ BIND_CORE_ENUM_CONSTANT(KEY_ARING);
+ BIND_CORE_ENUM_CONSTANT(KEY_AE);
+ BIND_CORE_ENUM_CONSTANT(KEY_CCEDILLA);
+ BIND_CORE_ENUM_CONSTANT(KEY_EGRAVE);
+ BIND_CORE_ENUM_CONSTANT(KEY_EACUTE);
+ BIND_CORE_ENUM_CONSTANT(KEY_ECIRCUMFLEX);
+ BIND_CORE_ENUM_CONSTANT(KEY_EDIAERESIS);
+ BIND_CORE_ENUM_CONSTANT(KEY_IGRAVE);
+ BIND_CORE_ENUM_CONSTANT(KEY_IACUTE);
+ BIND_CORE_ENUM_CONSTANT(KEY_ICIRCUMFLEX);
+ BIND_CORE_ENUM_CONSTANT(KEY_IDIAERESIS);
+ BIND_CORE_ENUM_CONSTANT(KEY_ETH);
+ BIND_CORE_ENUM_CONSTANT(KEY_NTILDE);
+ BIND_CORE_ENUM_CONSTANT(KEY_OGRAVE);
+ BIND_CORE_ENUM_CONSTANT(KEY_OACUTE);
+ BIND_CORE_ENUM_CONSTANT(KEY_OCIRCUMFLEX);
+ BIND_CORE_ENUM_CONSTANT(KEY_OTILDE);
+ BIND_CORE_ENUM_CONSTANT(KEY_ODIAERESIS);
+ BIND_CORE_ENUM_CONSTANT(KEY_MULTIPLY);
+ BIND_CORE_ENUM_CONSTANT(KEY_OOBLIQUE);
+ BIND_CORE_ENUM_CONSTANT(KEY_UGRAVE);
+ BIND_CORE_ENUM_CONSTANT(KEY_UACUTE);
+ BIND_CORE_ENUM_CONSTANT(KEY_UCIRCUMFLEX);
+ BIND_CORE_ENUM_CONSTANT(KEY_UDIAERESIS);
+ BIND_CORE_ENUM_CONSTANT(KEY_YACUTE);
+ BIND_CORE_ENUM_CONSTANT(KEY_THORN);
+ BIND_CORE_ENUM_CONSTANT(KEY_SSHARP);
+
+ BIND_CORE_ENUM_CONSTANT(KEY_DIVISION);
+ BIND_CORE_ENUM_CONSTANT(KEY_YDIAERESIS);
+
+ BIND_CORE_ENUM_CONSTANT(KEY_CODE_MASK);
+ BIND_CORE_ENUM_CONSTANT(KEY_MODIFIER_MASK);
+
+ BIND_CORE_ENUM_CONSTANT(KEY_MASK_SHIFT);
+ BIND_CORE_ENUM_CONSTANT(KEY_MASK_ALT);
+ BIND_CORE_ENUM_CONSTANT(KEY_MASK_META);
+ BIND_CORE_ENUM_CONSTANT(KEY_MASK_CTRL);
+ BIND_CORE_ENUM_CONSTANT_NO_VAL(KEY_MASK_CMD);
+ BIND_CORE_ENUM_CONSTANT(KEY_MASK_KPAD);
+ BIND_CORE_ENUM_CONSTANT(KEY_MASK_GROUP_SWITCH);
+
+ // mouse
+ BIND_CORE_ENUM_CONSTANT(BUTTON_LEFT);
+ BIND_CORE_ENUM_CONSTANT(BUTTON_RIGHT);
+ BIND_CORE_ENUM_CONSTANT(BUTTON_MIDDLE);
+ BIND_CORE_ENUM_CONSTANT(BUTTON_XBUTTON1);
+ BIND_CORE_ENUM_CONSTANT(BUTTON_XBUTTON2);
+ BIND_CORE_ENUM_CONSTANT(BUTTON_WHEEL_UP);
+ BIND_CORE_ENUM_CONSTANT(BUTTON_WHEEL_DOWN);
+ BIND_CORE_ENUM_CONSTANT(BUTTON_WHEEL_LEFT);
+ BIND_CORE_ENUM_CONSTANT(BUTTON_WHEEL_RIGHT);
+ BIND_CORE_ENUM_CONSTANT(BUTTON_MASK_LEFT);
+ BIND_CORE_ENUM_CONSTANT(BUTTON_MASK_RIGHT);
+ BIND_CORE_ENUM_CONSTANT(BUTTON_MASK_MIDDLE);
+ BIND_CORE_ENUM_CONSTANT(BUTTON_MASK_XBUTTON1);
+ BIND_CORE_ENUM_CONSTANT(BUTTON_MASK_XBUTTON2);
+
+ // Joypad buttons
+ BIND_CORE_ENUM_CONSTANT(JOY_BUTTON_INVALID);
+ BIND_CORE_ENUM_CONSTANT(JOY_BUTTON_A);
+ BIND_CORE_ENUM_CONSTANT(JOY_BUTTON_B);
+ BIND_CORE_ENUM_CONSTANT(JOY_BUTTON_X);
+ BIND_CORE_ENUM_CONSTANT(JOY_BUTTON_Y);
+ BIND_CORE_ENUM_CONSTANT(JOY_BUTTON_BACK);
+ BIND_CORE_ENUM_CONSTANT(JOY_BUTTON_GUIDE);
+ BIND_CORE_ENUM_CONSTANT(JOY_BUTTON_START);
+ BIND_CORE_ENUM_CONSTANT(JOY_BUTTON_LEFT_STICK);
+ BIND_CORE_ENUM_CONSTANT(JOY_BUTTON_RIGHT_STICK);
+ BIND_CORE_ENUM_CONSTANT(JOY_BUTTON_LEFT_SHOULDER);
+ BIND_CORE_ENUM_CONSTANT(JOY_BUTTON_RIGHT_SHOULDER);
+ BIND_CORE_ENUM_CONSTANT(JOY_BUTTON_DPAD_UP);
+ BIND_CORE_ENUM_CONSTANT(JOY_BUTTON_DPAD_DOWN);
+ BIND_CORE_ENUM_CONSTANT(JOY_BUTTON_DPAD_LEFT);
+ BIND_CORE_ENUM_CONSTANT(JOY_BUTTON_DPAD_RIGHT);
+ BIND_CORE_ENUM_CONSTANT(JOY_BUTTON_SDL_MAX);
+ BIND_CORE_ENUM_CONSTANT(JOY_BUTTON_MAX);
+
+ // Joypad axes
+ BIND_CORE_ENUM_CONSTANT(JOY_AXIS_INVALID);
+ BIND_CORE_ENUM_CONSTANT(JOY_AXIS_LEFT_X);
+ BIND_CORE_ENUM_CONSTANT(JOY_AXIS_LEFT_Y);
+ BIND_CORE_ENUM_CONSTANT(JOY_AXIS_RIGHT_X);
+ BIND_CORE_ENUM_CONSTANT(JOY_AXIS_RIGHT_Y);
+ BIND_CORE_ENUM_CONSTANT(JOY_AXIS_TRIGGER_LEFT);
+ BIND_CORE_ENUM_CONSTANT(JOY_AXIS_TRIGGER_RIGHT);
+ BIND_CORE_ENUM_CONSTANT(JOY_AXIS_SDL_MAX);
+ BIND_CORE_ENUM_CONSTANT(JOY_AXIS_MAX);
+
+ // midi
+ BIND_CORE_ENUM_CONSTANT(MIDI_MESSAGE_NOTE_OFF);
+ BIND_CORE_ENUM_CONSTANT(MIDI_MESSAGE_NOTE_ON);
+ BIND_CORE_ENUM_CONSTANT(MIDI_MESSAGE_AFTERTOUCH);
+ BIND_CORE_ENUM_CONSTANT(MIDI_MESSAGE_CONTROL_CHANGE);
+ BIND_CORE_ENUM_CONSTANT(MIDI_MESSAGE_PROGRAM_CHANGE);
+ BIND_CORE_ENUM_CONSTANT(MIDI_MESSAGE_CHANNEL_PRESSURE);
+ BIND_CORE_ENUM_CONSTANT(MIDI_MESSAGE_PITCH_BEND);
+
+ // error list
+
+ BIND_CORE_ENUM_CONSTANT(OK); // (0)
+ BIND_CORE_ENUM_CONSTANT(FAILED);
+ BIND_CORE_ENUM_CONSTANT(ERR_UNAVAILABLE);
+ BIND_CORE_ENUM_CONSTANT(ERR_UNCONFIGURED);
+ BIND_CORE_ENUM_CONSTANT(ERR_UNAUTHORIZED);
+ BIND_CORE_ENUM_CONSTANT(ERR_PARAMETER_RANGE_ERROR); // (5)
+ BIND_CORE_ENUM_CONSTANT(ERR_OUT_OF_MEMORY);
+ BIND_CORE_ENUM_CONSTANT(ERR_FILE_NOT_FOUND);
+ BIND_CORE_ENUM_CONSTANT(ERR_FILE_BAD_DRIVE);
+ BIND_CORE_ENUM_CONSTANT(ERR_FILE_BAD_PATH);
+ BIND_CORE_ENUM_CONSTANT(ERR_FILE_NO_PERMISSION); // (10)
+ BIND_CORE_ENUM_CONSTANT(ERR_FILE_ALREADY_IN_USE);
+ BIND_CORE_ENUM_CONSTANT(ERR_FILE_CANT_OPEN);
+ BIND_CORE_ENUM_CONSTANT(ERR_FILE_CANT_WRITE);
+ BIND_CORE_ENUM_CONSTANT(ERR_FILE_CANT_READ);
+ BIND_CORE_ENUM_CONSTANT(ERR_FILE_UNRECOGNIZED); // (15)
+ BIND_CORE_ENUM_CONSTANT(ERR_FILE_CORRUPT);
+ BIND_CORE_ENUM_CONSTANT(ERR_FILE_MISSING_DEPENDENCIES);
+ BIND_CORE_ENUM_CONSTANT(ERR_FILE_EOF);
+ BIND_CORE_ENUM_CONSTANT(ERR_CANT_OPEN);
+ BIND_CORE_ENUM_CONSTANT(ERR_CANT_CREATE); // (20)
+ BIND_CORE_ENUM_CONSTANT(ERR_QUERY_FAILED);
+ BIND_CORE_ENUM_CONSTANT(ERR_ALREADY_IN_USE);
+ BIND_CORE_ENUM_CONSTANT(ERR_LOCKED);
+ BIND_CORE_ENUM_CONSTANT(ERR_TIMEOUT);
+ BIND_CORE_ENUM_CONSTANT(ERR_CANT_CONNECT); // (25)
+ BIND_CORE_ENUM_CONSTANT(ERR_CANT_RESOLVE);
+ BIND_CORE_ENUM_CONSTANT(ERR_CONNECTION_ERROR);
+ BIND_CORE_ENUM_CONSTANT(ERR_CANT_ACQUIRE_RESOURCE);
+ BIND_CORE_ENUM_CONSTANT(ERR_CANT_FORK);
+ BIND_CORE_ENUM_CONSTANT(ERR_INVALID_DATA); // (30)
+ BIND_CORE_ENUM_CONSTANT(ERR_INVALID_PARAMETER);
+ BIND_CORE_ENUM_CONSTANT(ERR_ALREADY_EXISTS);
+ BIND_CORE_ENUM_CONSTANT(ERR_DOES_NOT_EXIST);
+ BIND_CORE_ENUM_CONSTANT(ERR_DATABASE_CANT_READ);
+ BIND_CORE_ENUM_CONSTANT(ERR_DATABASE_CANT_WRITE); // (35)
+ BIND_CORE_ENUM_CONSTANT(ERR_COMPILATION_FAILED);
+ BIND_CORE_ENUM_CONSTANT(ERR_METHOD_NOT_FOUND);
+ BIND_CORE_ENUM_CONSTANT(ERR_LINK_FAILED);
+ BIND_CORE_ENUM_CONSTANT(ERR_SCRIPT_FAILED);
+ BIND_CORE_ENUM_CONSTANT(ERR_CYCLIC_LINK); // (40)
+ BIND_CORE_ENUM_CONSTANT(ERR_INVALID_DECLARATION);
+ BIND_CORE_ENUM_CONSTANT(ERR_DUPLICATE_SYMBOL);
+ BIND_CORE_ENUM_CONSTANT(ERR_PARSE_ERROR);
+ BIND_CORE_ENUM_CONSTANT(ERR_BUSY);
+ BIND_CORE_ENUM_CONSTANT(ERR_SKIP); // (45)
+ BIND_CORE_ENUM_CONSTANT(ERR_HELP);
+ BIND_CORE_ENUM_CONSTANT(ERR_BUG);
+ BIND_CORE_ENUM_CONSTANT(ERR_PRINTER_ON_FIRE);
+
+ BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_NONE);
+ BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_RANGE);
+ BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_EXP_RANGE);
+ BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_ENUM);
+ BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_EXP_EASING);
+ BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_LENGTH);
+ BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_KEY_ACCEL);
+ BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_FLAGS);
+
+ BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_LAYERS_2D_RENDER);
+ BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_LAYERS_2D_PHYSICS);
+ BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_LAYERS_3D_RENDER);
+ BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_LAYERS_3D_PHYSICS);
+
+ BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_FILE);
+ BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_DIR);
+ BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_GLOBAL_FILE);
+ BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_GLOBAL_DIR);
+ BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_RESOURCE_TYPE);
+ BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_MULTILINE_TEXT);
+ BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_PLACEHOLDER_TEXT);
+ BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_COLOR_NO_ALPHA);
+ BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_IMAGE_COMPRESS_LOSSY);
+ BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_IMAGE_COMPRESS_LOSSLESS);
+
+ BIND_CORE_ENUM_CONSTANT(PROPERTY_USAGE_STORAGE);
+ BIND_CORE_ENUM_CONSTANT(PROPERTY_USAGE_EDITOR);
+ BIND_CORE_ENUM_CONSTANT(PROPERTY_USAGE_NETWORK);
+
+ BIND_CORE_ENUM_CONSTANT(PROPERTY_USAGE_EDITOR_HELPER);
+ BIND_CORE_ENUM_CONSTANT(PROPERTY_USAGE_CHECKABLE);
+ BIND_CORE_ENUM_CONSTANT(PROPERTY_USAGE_CHECKED);
+ BIND_CORE_ENUM_CONSTANT(PROPERTY_USAGE_INTERNATIONALIZED);
+ BIND_CORE_ENUM_CONSTANT(PROPERTY_USAGE_GROUP);
+ BIND_CORE_ENUM_CONSTANT(PROPERTY_USAGE_CATEGORY);
+ BIND_CORE_ENUM_CONSTANT(PROPERTY_USAGE_SUBGROUP);
+ BIND_CORE_ENUM_CONSTANT(PROPERTY_USAGE_NO_INSTANCE_STATE);
+ BIND_CORE_ENUM_CONSTANT(PROPERTY_USAGE_RESTART_IF_CHANGED);
+ BIND_CORE_ENUM_CONSTANT(PROPERTY_USAGE_SCRIPT_VARIABLE);
+
+ BIND_CORE_ENUM_CONSTANT(PROPERTY_USAGE_DEFAULT);
+ BIND_CORE_ENUM_CONSTANT(PROPERTY_USAGE_DEFAULT_INTL);
+ BIND_CORE_ENUM_CONSTANT(PROPERTY_USAGE_NOEDITOR);
+
+ BIND_CORE_ENUM_CONSTANT(METHOD_FLAG_NORMAL);
+ BIND_CORE_ENUM_CONSTANT(METHOD_FLAG_EDITOR);
+ BIND_CORE_ENUM_CONSTANT(METHOD_FLAG_NOSCRIPT);
+ BIND_CORE_ENUM_CONSTANT(METHOD_FLAG_CONST);
+ BIND_CORE_ENUM_CONSTANT(METHOD_FLAG_REVERSE);
+ BIND_CORE_ENUM_CONSTANT(METHOD_FLAG_VIRTUAL);
+ BIND_CORE_ENUM_CONSTANT(METHOD_FLAG_FROM_SCRIPT);
+ BIND_CORE_ENUM_CONSTANT(METHOD_FLAGS_DEFAULT);
+
+ BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_NIL", Variant::NIL);
+ BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_BOOL", Variant::BOOL);
+ BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_INT", Variant::INT);
+ BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_REAL", Variant::FLOAT);
+ BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_STRING", Variant::STRING);
+ BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_VECTOR2", Variant::VECTOR2);
+ BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_VECTOR2I", Variant::VECTOR2I);
+ BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_RECT2", Variant::RECT2);
+ BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_RECT2I", Variant::RECT2I);
+ BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_VECTOR3", Variant::VECTOR3);
+ BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_VECTOR3I", Variant::VECTOR3I);
+ BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_TRANSFORM2D", Variant::TRANSFORM2D);
+ BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_PLANE", Variant::PLANE);
+ BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_QUAT", Variant::QUAT);
+ BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_AABB", Variant::AABB);
+ BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_BASIS", Variant::BASIS);
+ BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_TRANSFORM", Variant::TRANSFORM);
+ BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_COLOR", Variant::COLOR);
+ BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_STRING_NAME", Variant::STRING_NAME);
+ BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_NODE_PATH", Variant::NODE_PATH);
+ BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_RID", Variant::RID);
+ BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_OBJECT", Variant::OBJECT);
+ BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_CALLABLE", Variant::CALLABLE);
+ BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_SIGNAL", Variant::SIGNAL);
+ BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_DICTIONARY", Variant::DICTIONARY);
+ BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_ARRAY", Variant::ARRAY);
+ BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_RAW_ARRAY", Variant::PACKED_BYTE_ARRAY);
+ BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_INT32_ARRAY", Variant::PACKED_INT32_ARRAY);
+ BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_INT64_ARRAY", Variant::PACKED_INT64_ARRAY);
+ BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_FLOAT32_ARRAY", Variant::PACKED_FLOAT32_ARRAY);
+ BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_FLOAT64_ARRAY", Variant::PACKED_FLOAT64_ARRAY);
+ BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_STRING_ARRAY", Variant::PACKED_STRING_ARRAY);
+ BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_VECTOR2_ARRAY", Variant::PACKED_VECTOR2_ARRAY);
+ BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_VECTOR3_ARRAY", Variant::PACKED_VECTOR3_ARRAY);
+ BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_COLOR_ARRAY", Variant::PACKED_COLOR_ARRAY);
+ BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_MAX", Variant::VARIANT_MAX);
+
+ //comparison
+ BIND_CORE_ENUM_CONSTANT_CUSTOM("OP_EQUAL", Variant::OP_EQUAL);
+ BIND_CORE_ENUM_CONSTANT_CUSTOM("OP_NOT_EQUAL", Variant::OP_NOT_EQUAL);
+ BIND_CORE_ENUM_CONSTANT_CUSTOM("OP_LESS", Variant::OP_LESS);
+ BIND_CORE_ENUM_CONSTANT_CUSTOM("OP_LESS_EQUAL", Variant::OP_LESS_EQUAL);
+ BIND_CORE_ENUM_CONSTANT_CUSTOM("OP_GREATER", Variant::OP_GREATER);
+ BIND_CORE_ENUM_CONSTANT_CUSTOM("OP_GREATER_EQUAL", Variant::OP_GREATER_EQUAL);
+ //mathematic
+ BIND_CORE_ENUM_CONSTANT_CUSTOM("OP_ADD", Variant::OP_ADD);
+ BIND_CORE_ENUM_CONSTANT_CUSTOM("OP_SUBTRACT", Variant::OP_SUBTRACT);
+ BIND_CORE_ENUM_CONSTANT_CUSTOM("OP_MULTIPLY", Variant::OP_MULTIPLY);
+ BIND_CORE_ENUM_CONSTANT_CUSTOM("OP_DIVIDE", Variant::OP_DIVIDE);
+ BIND_CORE_ENUM_CONSTANT_CUSTOM("OP_NEGATE", Variant::OP_NEGATE);
+ BIND_CORE_ENUM_CONSTANT_CUSTOM("OP_POSITIVE", Variant::OP_POSITIVE);
+ BIND_CORE_ENUM_CONSTANT_CUSTOM("OP_MODULE", Variant::OP_MODULE);
+ //bitwise
+ BIND_CORE_ENUM_CONSTANT_CUSTOM("OP_SHIFT_LEFT", Variant::OP_SHIFT_LEFT);
+ BIND_CORE_ENUM_CONSTANT_CUSTOM("OP_SHIFT_RIGHT", Variant::OP_SHIFT_RIGHT);
+ BIND_CORE_ENUM_CONSTANT_CUSTOM("OP_BIT_AND", Variant::OP_BIT_AND);
+ BIND_CORE_ENUM_CONSTANT_CUSTOM("OP_BIT_OR", Variant::OP_BIT_OR);
+ BIND_CORE_ENUM_CONSTANT_CUSTOM("OP_BIT_XOR", Variant::OP_BIT_XOR);
+ BIND_CORE_ENUM_CONSTANT_CUSTOM("OP_BIT_NEGATE", Variant::OP_BIT_NEGATE);
+ //logic
+ BIND_CORE_ENUM_CONSTANT_CUSTOM("OP_AND", Variant::OP_AND);
+ BIND_CORE_ENUM_CONSTANT_CUSTOM("OP_OR", Variant::OP_OR);
+ BIND_CORE_ENUM_CONSTANT_CUSTOM("OP_XOR", Variant::OP_XOR);
+ BIND_CORE_ENUM_CONSTANT_CUSTOM("OP_NOT", Variant::OP_NOT);
+ //containment
+ BIND_CORE_ENUM_CONSTANT_CUSTOM("OP_IN", Variant::OP_IN);
+ BIND_CORE_ENUM_CONSTANT_CUSTOM("OP_MAX", Variant::OP_MAX);
+}
+
+void unregister_global_constants() {
+ _global_constants.clear();
+}
+
+int CoreConstants::get_global_constant_count() {
+ return _global_constants.size();
+}
+
+#ifdef DEBUG_METHODS_ENABLED
+StringName CoreConstants::get_global_constant_enum(int p_idx) {
+ return _global_constants[p_idx].enum_name;
+}
+
+bool CoreConstants::get_ignore_value_in_docs(int p_idx) {
+ return _global_constants[p_idx].ignore_value_in_docs;
+}
+#else
+StringName CoreConstants::get_global_constant_enum(int p_idx) {
+ return StringName();
+}
+
+bool CoreConstants::get_ignore_value_in_docs(int p_idx) {
+ return false;
+}
+#endif
+
+const char *CoreConstants::get_global_constant_name(int p_idx) {
+ return _global_constants[p_idx].name;
+}
+
+int CoreConstants::get_global_constant_value(int p_idx) {
+ return _global_constants[p_idx].value;
+}
diff --git a/core/global_constants.h b/core/core_constants.h
index a20b5ecd9a..6cddd9daec 100644
--- a/core/global_constants.h
+++ b/core/core_constants.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* global_constants.h */
+/* core_constants.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,15 +28,16 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef GLOBAL_CONSTANTS_H
-#define GLOBAL_CONSTANTS_H
+#ifndef CORE_CONSTANTS_H
+#define CORE_CONSTANTS_H
-#include "core/string_name.h"
+#include "core/string/string_name.h"
-class GlobalConstants {
+class CoreConstants {
public:
static int get_global_constant_count();
static StringName get_global_constant_enum(int p_idx);
+ static bool get_ignore_value_in_docs(int p_idx);
static const char *get_global_constant_name(int p_idx);
static int get_global_constant_value(int p_idx);
};
diff --git a/core/core_string_names.cpp b/core/core_string_names.cpp
index 1d3b333efc..6f86f107e6 100644
--- a/core/core_string_names.cpp
+++ b/core/core_string_names.cpp
@@ -73,6 +73,8 @@ CoreStringNames::CoreStringNames() :
a8(StaticCString::create("a8")),
call(StaticCString::create("call")),
call_deferred(StaticCString::create("call_deferred")),
+ bind(StaticCString::create("bind")),
+ unbind(StaticCString::create("unbind")),
emit(StaticCString::create("emit")),
notification(StaticCString::create("notification")) {
}
diff --git a/core/core_string_names.h b/core/core_string_names.h
index 1a18c84572..c0bdc33d28 100644
--- a/core/core_string_names.h
+++ b/core/core_string_names.h
@@ -31,7 +31,7 @@
#ifndef CORE_STRING_NAMES_H
#define CORE_STRING_NAMES_H
-#include "core/string_name.h"
+#include "core/string/string_name.h"
class CoreStringNames {
friend void register_core_types();
@@ -92,6 +92,8 @@ public:
StringName call;
StringName call_deferred;
+ StringName bind;
+ StringName unbind;
StringName emit;
StringName notification;
};
diff --git a/core/crypto/aes_context.cpp b/core/crypto/aes_context.cpp
index 8ef1f4f1d4..608f3c912c 100644
--- a/core/crypto/aes_context.cpp
+++ b/core/crypto/aes_context.cpp
@@ -112,5 +112,4 @@ void AESContext::_bind_methods() {
}
AESContext::AESContext() {
- mode = MODE_MAX;
}
diff --git a/core/crypto/aes_context.h b/core/crypto/aes_context.h
index 006ecee2ad..557bde1f04 100644
--- a/core/crypto/aes_context.h
+++ b/core/crypto/aes_context.h
@@ -32,7 +32,7 @@
#define AES_CONTEXT_H
#include "core/crypto/crypto_core.h"
-#include "core/reference.h"
+#include "core/object/reference.h"
class AESContext : public Reference {
GDCLASS(AESContext, Reference);
@@ -47,7 +47,7 @@ public:
};
private:
- Mode mode;
+ Mode mode = MODE_MAX;
CryptoCore::AESContext ctx;
PackedByteArray iv;
diff --git a/core/crypto/crypto.cpp b/core/crypto/crypto.cpp
index 29d02e11df..d12108bca0 100644
--- a/core/crypto/crypto.cpp
+++ b/core/crypto/crypto.cpp
@@ -30,7 +30,7 @@
#include "crypto.h"
-#include "core/engine.h"
+#include "core/config/engine.h"
#include "core/io/certs_compressed.gen.h"
#include "core/io/compression.h"
diff --git a/core/crypto/crypto.h b/core/crypto/crypto.h
index 916f7798eb..8325f043bf 100644
--- a/core/crypto/crypto.h
+++ b/core/crypto/crypto.h
@@ -32,10 +32,10 @@
#define CRYPTO_H
#include "core/crypto/hashing_context.h"
+#include "core/io/resource.h"
#include "core/io/resource_loader.h"
#include "core/io/resource_saver.h"
-#include "core/reference.h"
-#include "core/resource.h"
+#include "core/object/reference.h"
class CryptoKey : public Resource {
GDCLASS(CryptoKey, Resource);
diff --git a/core/crypto/crypto_core.cpp b/core/crypto/crypto_core.cpp
index b0dc47e655..117e47d538 100644
--- a/core/crypto/crypto_core.cpp
+++ b/core/crypto/crypto_core.cpp
@@ -140,13 +140,19 @@ Error CryptoCore::AESContext::encrypt_ecb(const uint8_t p_src[16], uint8_t r_dst
return ret ? FAILED : OK;
}
-Error CryptoCore::AESContext::decrypt_ecb(const uint8_t p_src[16], uint8_t r_dst[16]) {
- int ret = mbedtls_aes_crypt_ecb((mbedtls_aes_context *)ctx, MBEDTLS_AES_DECRYPT, p_src, r_dst);
+Error CryptoCore::AESContext::encrypt_cbc(size_t p_length, uint8_t r_iv[16], const uint8_t *p_src, uint8_t *r_dst) {
+ int ret = mbedtls_aes_crypt_cbc((mbedtls_aes_context *)ctx, MBEDTLS_AES_ENCRYPT, p_length, r_iv, p_src, r_dst);
return ret ? FAILED : OK;
}
-Error CryptoCore::AESContext::encrypt_cbc(size_t p_length, uint8_t r_iv[16], const uint8_t *p_src, uint8_t *r_dst) {
- int ret = mbedtls_aes_crypt_cbc((mbedtls_aes_context *)ctx, MBEDTLS_AES_ENCRYPT, p_length, r_iv, p_src, r_dst);
+Error CryptoCore::AESContext::encrypt_cfb(size_t p_length, uint8_t p_iv[16], const uint8_t *p_src, uint8_t *r_dst) {
+ size_t iv_off = 0; // Ignore and assume 16-byte alignment.
+ int ret = mbedtls_aes_crypt_cfb128((mbedtls_aes_context *)ctx, MBEDTLS_AES_ENCRYPT, p_length, &iv_off, p_iv, p_src, r_dst);
+ return ret ? FAILED : OK;
+}
+
+Error CryptoCore::AESContext::decrypt_ecb(const uint8_t p_src[16], uint8_t r_dst[16]) {
+ int ret = mbedtls_aes_crypt_ecb((mbedtls_aes_context *)ctx, MBEDTLS_AES_DECRYPT, p_src, r_dst);
return ret ? FAILED : OK;
}
@@ -155,6 +161,12 @@ Error CryptoCore::AESContext::decrypt_cbc(size_t p_length, uint8_t r_iv[16], con
return ret ? FAILED : OK;
}
+Error CryptoCore::AESContext::decrypt_cfb(size_t p_length, uint8_t p_iv[16], const uint8_t *p_src, uint8_t *r_dst) {
+ size_t iv_off = 0; // Ignore and assume 16-byte alignment.
+ int ret = mbedtls_aes_crypt_cfb128((mbedtls_aes_context *)ctx, MBEDTLS_AES_DECRYPT, p_length, &iv_off, p_iv, p_src, r_dst);
+ return ret ? FAILED : OK;
+}
+
// CryptoCore
String CryptoCore::b64_encode_str(const uint8_t *p_src, int p_src_len) {
int b64len = p_src_len / 3 * 4 + 4 + 1;
diff --git a/core/crypto/crypto_core.h b/core/crypto/crypto_core.h
index 82df9c23a8..c2ec6febe3 100644
--- a/core/crypto/crypto_core.h
+++ b/core/crypto/crypto_core.h
@@ -31,13 +31,13 @@
#ifndef CRYPTO_CORE_H
#define CRYPTO_CORE_H
-#include "core/reference.h"
+#include "core/object/reference.h"
class CryptoCore {
public:
class MD5Context {
private:
- void *ctx; // To include, or not to include...
+ void *ctx = nullptr; // To include, or not to include...
public:
MD5Context();
@@ -50,7 +50,7 @@ public:
class SHA1Context {
private:
- void *ctx; // To include, or not to include...
+ void *ctx = nullptr; // To include, or not to include...
public:
SHA1Context();
@@ -63,7 +63,7 @@ public:
class SHA256Context {
private:
- void *ctx; // To include, or not to include...
+ void *ctx = nullptr; // To include, or not to include...
public:
SHA256Context();
@@ -76,7 +76,7 @@ public:
class AESContext {
private:
- void *ctx; // To include, or not to include...
+ void *ctx = nullptr; // To include, or not to include...
public:
AESContext();
@@ -88,6 +88,8 @@ public:
Error decrypt_ecb(const uint8_t p_src[16], uint8_t r_dst[16]);
Error encrypt_cbc(size_t p_length, uint8_t r_iv[16], const uint8_t *p_src, uint8_t *r_dst);
Error decrypt_cbc(size_t p_length, uint8_t r_iv[16], const uint8_t *p_src, uint8_t *r_dst);
+ Error encrypt_cfb(size_t p_length, uint8_t p_iv[16], const uint8_t *p_src, uint8_t *r_dst);
+ Error decrypt_cfb(size_t p_length, uint8_t p_iv[16], const uint8_t *p_src, uint8_t *r_dst);
};
static String b64_encode_str(const uint8_t *p_src, int p_src_len);
diff --git a/core/crypto/hashing_context.h b/core/crypto/hashing_context.h
index f9454fa891..7cd55ba267 100644
--- a/core/crypto/hashing_context.h
+++ b/core/crypto/hashing_context.h
@@ -31,7 +31,7 @@
#ifndef HASHING_CONTEXT_H
#define HASHING_CONTEXT_H
-#include "core/reference.h"
+#include "core/object/reference.h"
class HashingContext : public Reference {
GDCLASS(HashingContext, Reference);
@@ -45,7 +45,7 @@ public:
private:
void *ctx = nullptr;
- HashType type;
+ HashType type = HASH_MD5;
protected:
static void _bind_methods();
diff --git a/core/debugger/debugger_marshalls.cpp b/core/debugger/debugger_marshalls.cpp
index 3f949b0ae1..03de832b5e 100644
--- a/core/debugger/debugger_marshalls.cpp
+++ b/core/debugger/debugger_marshalls.cpp
@@ -171,7 +171,7 @@ bool DebuggerMarshalls::ServersProfilerFrame::deserialize(const Array &p_arr) {
}
servers.push_back(si);
}
- CHECK_SIZE(p_arr, idx + 3, "ServersProfilerFrame");
+ CHECK_SIZE(p_arr, idx + 1, "ServersProfilerFrame");
int func_size = p_arr[idx];
idx += 1;
CHECK_SIZE(p_arr, idx + func_size, "ServersProfilerFrame");
diff --git a/core/debugger/debugger_marshalls.h b/core/debugger/debugger_marshalls.h
index 7b7f4ac4b5..0c13790d60 100644
--- a/core/debugger/debugger_marshalls.h
+++ b/core/debugger/debugger_marshalls.h
@@ -31,7 +31,7 @@
#ifndef DEBUGGER_MARSHARLLS_H
#define DEBUGGER_MARSHARLLS_H
-#include "core/script_language.h"
+#include "core/object/script_language.h"
#include "servers/rendering_server.h"
struct DebuggerMarshalls {
@@ -148,7 +148,7 @@ struct DebuggerMarshalls {
// Visual Profiler
struct VisualProfilerFrame {
- uint64_t frame_number;
+ uint64_t frame_number = 0;
Vector<RS::FrameProfileArea> areas;
Array serialize();
diff --git a/core/debugger/engine_debugger.h b/core/debugger/engine_debugger.h
index 8d5ebb2394..10f04bf97a 100644
--- a/core/debugger/engine_debugger.h
+++ b/core/debugger/engine_debugger.h
@@ -31,12 +31,12 @@
#ifndef ENGINE_DEBUGGER_H
#define ENGINE_DEBUGGER_H
-#include "core/array.h"
-#include "core/map.h"
-#include "core/string_name.h"
-#include "core/ustring.h"
-#include "core/variant.h"
-#include "core/vector.h"
+#include "core/string/string_name.h"
+#include "core/string/ustring.h"
+#include "core/templates/map.h"
+#include "core/templates/vector.h"
+#include "core/variant/array.h"
+#include "core/variant/variant.h"
class RemoteDebuggerPeer;
class ScriptDebugger;
diff --git a/core/debugger/local_debugger.h b/core/debugger/local_debugger.h
index d342da6d44..dbdeec173b 100644
--- a/core/debugger/local_debugger.h
+++ b/core/debugger/local_debugger.h
@@ -32,8 +32,8 @@
#define LOCAL_DEBUGGER_H
#include "core/debugger/engine_debugger.h"
-#include "core/list.h"
-#include "core/script_language.h"
+#include "core/object/script_language.h"
+#include "core/templates/list.h"
class LocalDebugger : public EngineDebugger {
private:
diff --git a/core/debugger/remote_debugger.cpp b/core/debugger/remote_debugger.cpp
index 9d55e1312e..ff89517497 100644
--- a/core/debugger/remote_debugger.cpp
+++ b/core/debugger/remote_debugger.cpp
@@ -30,13 +30,13 @@
#include "remote_debugger.h"
+#include "core/config/project_settings.h"
#include "core/debugger/debugger_marshalls.h"
#include "core/debugger/engine_debugger.h"
#include "core/debugger/script_debugger.h"
#include "core/input/input.h"
+#include "core/object/script_language.h"
#include "core/os/os.h"
-#include "core/project_settings.h"
-#include "core/script_language.h"
#include "scene/main/node.h"
#include "servers/display_server.h"
diff --git a/core/debugger/remote_debugger.h b/core/debugger/remote_debugger.h
index dc7e4436e1..37cc8af2a5 100644
--- a/core/debugger/remote_debugger.h
+++ b/core/debugger/remote_debugger.h
@@ -31,13 +31,13 @@
#ifndef REMOTE_DEBUGGER_H
#define REMOTE_DEBUGGER_H
-#include "core/array.h"
#include "core/debugger/debugger_marshalls.h"
#include "core/debugger/engine_debugger.h"
#include "core/debugger/remote_debugger_peer.h"
-#include "core/object.h"
-#include "core/string_name.h"
-#include "core/ustring.h"
+#include "core/object/class_db.h"
+#include "core/string/string_name.h"
+#include "core/string/ustring.h"
+#include "core/variant/array.h"
class RemoteDebugger : public EngineDebugger {
public:
diff --git a/core/debugger/remote_debugger_peer.cpp b/core/debugger/remote_debugger_peer.cpp
index 0ce0042f50..338c637014 100644
--- a/core/debugger/remote_debugger_peer.cpp
+++ b/core/debugger/remote_debugger_peer.cpp
@@ -30,9 +30,9 @@
#include "remote_debugger_peer.h"
+#include "core/config/project_settings.h"
#include "core/io/marshalls.h"
#include "core/os/os.h"
-#include "core/project_settings.h"
bool RemoteDebuggerPeerTCP::is_peer_connected() {
return connected;
diff --git a/core/debugger/remote_debugger_peer.h b/core/debugger/remote_debugger_peer.h
index 3a75a2a02b..79b88f5549 100644
--- a/core/debugger/remote_debugger_peer.h
+++ b/core/debugger/remote_debugger_peer.h
@@ -32,10 +32,10 @@
#define REMOTE_DEBUGGER_PEER_H
#include "core/io/stream_peer_tcp.h"
+#include "core/object/reference.h"
#include "core/os/mutex.h"
#include "core/os/thread.h"
-#include "core/reference.h"
-#include "core/ustring.h"
+#include "core/string/ustring.h"
class RemoteDebuggerPeer : public Reference {
protected:
diff --git a/core/debugger/script_debugger.h b/core/debugger/script_debugger.h
index 0068691825..7f2f2becc2 100644
--- a/core/debugger/script_debugger.h
+++ b/core/debugger/script_debugger.h
@@ -31,11 +31,11 @@
#ifndef SCRIPT_DEBUGGER_H
#define SCRIPT_DEBUGGER_H
-#include "core/map.h"
-#include "core/script_language.h"
-#include "core/set.h"
-#include "core/string_name.h"
-#include "core/vector.h"
+#include "core/object/script_language.h"
+#include "core/string/string_name.h"
+#include "core/templates/map.h"
+#include "core/templates/set.h"
+#include "core/templates/vector.h"
class ScriptDebugger {
typedef ScriptLanguage::StackInfo StackInfo;
diff --git a/core/error/SCsub b/core/error/SCsub
new file mode 100644
index 0000000000..dfd6248a94
--- /dev/null
+++ b/core/error/SCsub
@@ -0,0 +1,7 @@
+#!/usr/bin/env python
+
+Import("env")
+
+env_error = env.Clone()
+
+env_error.add_source_files(env.core_sources, "*.cpp")
diff --git a/core/error_list.h b/core/error/error_list.h
index a0218cf045..a0218cf045 100644
--- a/core/error_list.h
+++ b/core/error/error_list.h
diff --git a/core/error_macros.cpp b/core/error/error_macros.cpp
index 2fae939965..80879dd25d 100644
--- a/core/error_macros.cpp
+++ b/core/error/error_macros.cpp
@@ -31,8 +31,8 @@
#include "error_macros.h"
#include "core/io/logger.h"
-#include "core/ustring.h"
-#include "os/os.h"
+#include "core/os/os.h"
+#include "core/string/ustring.h"
static ErrorHandlerList *error_handler_list = nullptr;
diff --git a/core/error_macros.h b/core/error/error_macros.h
index d7366be453..6353961b04 100644
--- a/core/error_macros.h
+++ b/core/error/error_macros.h
@@ -476,7 +476,7 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li
* The current function returns.
*/
#define ERR_FAIL() \
- if (1) { \
+ if (true) { \
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Method/function failed."); \
return; \
} else \
@@ -489,7 +489,7 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li
* Prints `m_msg`, and the current function returns.
*/
#define ERR_FAIL_MSG(m_msg) \
- if (1) { \
+ if (true) { \
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Method/function failed.", DEBUG_STR(m_msg)); \
return; \
} else \
@@ -503,7 +503,7 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li
* The current function returns `m_retval`.
*/
#define ERR_FAIL_V(m_retval) \
- if (1) { \
+ if (true) { \
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Method/function failed. Returning: " _STR(m_retval)); \
return m_retval; \
} else \
@@ -516,7 +516,7 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li
* Prints `m_msg`, and the current function returns `m_retval`.
*/
#define ERR_FAIL_V_MSG(m_retval, m_msg) \
- if (1) { \
+ if (true) { \
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Method/function failed. Returning: " _STR(m_retval), DEBUG_STR(m_msg)); \
return m_retval; \
} else \
@@ -536,7 +536,7 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li
* Prints `m_msg` once during the application lifetime.
*/
#define ERR_PRINT_ONCE(m_msg) \
- if (1) { \
+ if (true) { \
static bool first_print = true; \
if (first_print) { \
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, m_msg); \
@@ -561,7 +561,7 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li
* If warning about deprecated usage, use `WARN_DEPRECATED` or `WARN_DEPRECATED_MSG` instead.
*/
#define WARN_PRINT_ONCE(m_msg) \
- if (1) { \
+ if (true) { \
static bool first_print = true; \
if (first_print) { \
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, m_msg, ERR_HANDLER_WARNING); \
@@ -576,7 +576,7 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li
* Warns that the current function is deprecated.
*/
#define WARN_DEPRECATED \
- if (1) { \
+ if (true) { \
static volatile bool warning_shown = false; \
if (!warning_shown) { \
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "This method has been deprecated and will be removed in the future.", ERR_HANDLER_WARNING); \
@@ -589,7 +589,7 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li
* Warns that the current function is deprecated and prints `m_msg`.
*/
#define WARN_DEPRECATED_MSG(m_msg) \
- if (1) { \
+ if (true) { \
static volatile bool warning_shown = false; \
if (!warning_shown) { \
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "This method has been deprecated and will be removed in the future.", DEBUG_STR(m_msg), ERR_HANDLER_WARNING); \
@@ -605,7 +605,7 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li
* The application crashes.
*/
#define CRASH_NOW() \
- if (1) { \
+ if (true) { \
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "FATAL: Method/function failed."); \
GENERATE_TRAP(); \
} else \
@@ -617,7 +617,7 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li
* Prints `m_msg`, and then the application crashes.
*/
#define CRASH_NOW_MSG(m_msg) \
- if (1) { \
+ if (true) { \
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "FATAL: Method/function failed.", DEBUG_STR(m_msg)); \
GENERATE_TRAP(); \
} else \
diff --git a/core/func_ref.cpp b/core/func_ref.cpp
deleted file mode 100644
index 4427d94d2a..0000000000
--- a/core/func_ref.cpp
+++ /dev/null
@@ -1,93 +0,0 @@
-/*************************************************************************/
-/* func_ref.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* 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. */
-/*************************************************************************/
-
-#include "func_ref.h"
-
-Variant FuncRef::call_func(const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
- if (id.is_null()) {
- r_error.error = Callable::CallError::CALL_ERROR_INSTANCE_IS_NULL;
- return Variant();
- }
- Object *obj = ObjectDB::get_instance(id);
-
- if (!obj) {
- r_error.error = Callable::CallError::CALL_ERROR_INSTANCE_IS_NULL;
- return Variant();
- }
-
- return obj->call(function, p_args, p_argcount, r_error);
-}
-
-Variant FuncRef::call_funcv(const Array &p_args) {
- ERR_FAIL_COND_V(id.is_null(), Variant());
-
- Object *obj = ObjectDB::get_instance(id);
-
- ERR_FAIL_COND_V(!obj, Variant());
-
- return obj->callv(function, p_args);
-}
-
-void FuncRef::set_instance(Object *p_obj) {
- ERR_FAIL_NULL(p_obj);
- id = p_obj->get_instance_id();
-}
-
-void FuncRef::set_function(const StringName &p_func) {
- function = p_func;
-}
-
-bool FuncRef::is_valid() const {
- if (id.is_null()) {
- return false;
- }
-
- Object *obj = ObjectDB::get_instance(id);
- if (!obj) {
- return false;
- }
-
- return obj->has_method(function);
-}
-
-void FuncRef::_bind_methods() {
- {
- MethodInfo mi;
- mi.name = "call_func";
- Vector<Variant> defargs;
- ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "call_func", &FuncRef::call_func, mi, defargs);
- }
-
- ClassDB::bind_method(D_METHOD("call_funcv", "arg_array"), &FuncRef::call_funcv);
-
- ClassDB::bind_method(D_METHOD("set_instance", "instance"), &FuncRef::set_instance);
- ClassDB::bind_method(D_METHOD("set_function", "name"), &FuncRef::set_function);
- ClassDB::bind_method(D_METHOD("is_valid"), &FuncRef::is_valid);
-}
diff --git a/core/func_ref.h b/core/func_ref.h
deleted file mode 100644
index 6b0b22bab5..0000000000
--- a/core/func_ref.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/*************************************************************************/
-/* func_ref.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* 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. */
-/*************************************************************************/
-
-#ifndef FUNC_REF_H
-#define FUNC_REF_H
-
-#include "core/reference.h"
-
-class FuncRef : public Reference {
- GDCLASS(FuncRef, Reference);
- ObjectID id;
- StringName function;
-
-protected:
- static void _bind_methods();
-
-public:
- Variant call_func(const Variant **p_args, int p_argcount, Callable::CallError &r_error);
- Variant call_funcv(const Array &p_args);
- void set_instance(Object *p_obj);
- void set_function(const StringName &p_func);
- bool is_valid() const;
-
- FuncRef() {}
-};
-
-#endif // FUNC_REF_H
diff --git a/core/global_constants.cpp b/core/global_constants.cpp
deleted file mode 100644
index 6281e56395..0000000000
--- a/core/global_constants.cpp
+++ /dev/null
@@ -1,663 +0,0 @@
-/*************************************************************************/
-/* global_constants.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* 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. */
-/*************************************************************************/
-
-#include "global_constants.h"
-
-#include "core/input/input_event.h"
-#include "core/object.h"
-#include "core/os/keyboard.h"
-#include "core/variant.h"
-
-struct _GlobalConstant {
-#ifdef DEBUG_METHODS_ENABLED
- StringName enum_name;
-#endif
- const char *name;
- int value;
-
- _GlobalConstant() {}
-
-#ifdef DEBUG_METHODS_ENABLED
- _GlobalConstant(const StringName &p_enum_name, const char *p_name, int p_value) :
- enum_name(p_enum_name),
- name(p_name),
- value(p_value) {
- }
-#else
- _GlobalConstant(const char *p_name, int p_value) :
- name(p_name),
- value(p_value) {
- }
-#endif
-};
-
-static Vector<_GlobalConstant> _global_constants;
-
-#ifdef DEBUG_METHODS_ENABLED
-
-#define BIND_GLOBAL_CONSTANT(m_constant) \
- _global_constants.push_back(_GlobalConstant(StringName(), #m_constant, m_constant));
-
-#define BIND_GLOBAL_ENUM_CONSTANT(m_constant) \
- _global_constants.push_back(_GlobalConstant(__constant_get_enum_name(m_constant, #m_constant), #m_constant, m_constant));
-
-#define BIND_GLOBAL_ENUM_CONSTANT_CUSTOM(m_custom_name, m_constant) \
- _global_constants.push_back(_GlobalConstant(__constant_get_enum_name(m_constant, #m_constant), m_custom_name, m_constant));
-
-#else
-
-#define BIND_GLOBAL_CONSTANT(m_constant) \
- _global_constants.push_back(_GlobalConstant(#m_constant, m_constant));
-
-#define BIND_GLOBAL_ENUM_CONSTANT(m_constant) \
- _global_constants.push_back(_GlobalConstant(#m_constant, m_constant));
-
-#define BIND_GLOBAL_ENUM_CONSTANT_CUSTOM(m_custom_name, m_constant) \
- _global_constants.push_back(_GlobalConstant(m_custom_name, m_constant));
-
-#endif
-
-VARIANT_ENUM_CAST(KeyList);
-VARIANT_ENUM_CAST(KeyModifierMask);
-VARIANT_ENUM_CAST(ButtonList);
-VARIANT_ENUM_CAST(JoyButtonList);
-VARIANT_ENUM_CAST(JoyAxisList);
-VARIANT_ENUM_CAST(MidiMessageList);
-
-void register_global_constants() {
- BIND_GLOBAL_ENUM_CONSTANT(MARGIN_LEFT);
- BIND_GLOBAL_ENUM_CONSTANT(MARGIN_TOP);
- BIND_GLOBAL_ENUM_CONSTANT(MARGIN_RIGHT);
- BIND_GLOBAL_ENUM_CONSTANT(MARGIN_BOTTOM);
-
- BIND_GLOBAL_ENUM_CONSTANT(CORNER_TOP_LEFT);
- BIND_GLOBAL_ENUM_CONSTANT(CORNER_TOP_RIGHT);
- BIND_GLOBAL_ENUM_CONSTANT(CORNER_BOTTOM_RIGHT);
- BIND_GLOBAL_ENUM_CONSTANT(CORNER_BOTTOM_LEFT);
-
- BIND_GLOBAL_ENUM_CONSTANT(VERTICAL);
- BIND_GLOBAL_ENUM_CONSTANT(HORIZONTAL);
-
- BIND_GLOBAL_ENUM_CONSTANT(HALIGN_LEFT);
- BIND_GLOBAL_ENUM_CONSTANT(HALIGN_CENTER);
- BIND_GLOBAL_ENUM_CONSTANT(HALIGN_RIGHT);
-
- BIND_GLOBAL_ENUM_CONSTANT(VALIGN_TOP);
- BIND_GLOBAL_ENUM_CONSTANT(VALIGN_CENTER);
- BIND_GLOBAL_ENUM_CONSTANT(VALIGN_BOTTOM);
-
- // huge list of keys
- BIND_GLOBAL_CONSTANT(SPKEY);
-
- BIND_GLOBAL_ENUM_CONSTANT(KEY_ESCAPE);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_TAB);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_BACKTAB);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_BACKSPACE);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_ENTER);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_KP_ENTER);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_INSERT);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_DELETE);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_PAUSE);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_PRINT);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_SYSREQ);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_CLEAR);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_HOME);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_END);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_LEFT);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_UP);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_RIGHT);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_DOWN);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_PAGEUP);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_PAGEDOWN);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_SHIFT);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_CONTROL);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_META);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_ALT);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_CAPSLOCK);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_NUMLOCK);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_SCROLLLOCK);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_F1);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_F2);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_F3);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_F4);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_F5);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_F6);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_F7);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_F8);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_F9);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_F10);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_F11);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_F12);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_F13);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_F14);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_F15);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_F16);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_KP_MULTIPLY);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_KP_DIVIDE);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_KP_SUBTRACT);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_KP_PERIOD);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_KP_ADD);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_KP_0);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_KP_1);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_KP_2);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_KP_3);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_KP_4);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_KP_5);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_KP_6);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_KP_7);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_KP_8);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_KP_9);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_SUPER_L);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_SUPER_R);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_MENU);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_HYPER_L);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_HYPER_R);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_HELP);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_DIRECTION_L);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_DIRECTION_R);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_BACK);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_FORWARD);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_STOP);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_REFRESH);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_VOLUMEDOWN);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_VOLUMEMUTE);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_VOLUMEUP);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_BASSBOOST);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_BASSUP);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_BASSDOWN);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_TREBLEUP);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_TREBLEDOWN);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_MEDIAPLAY);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_MEDIASTOP);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_MEDIAPREVIOUS);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_MEDIANEXT);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_MEDIARECORD);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_HOMEPAGE);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_FAVORITES);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_SEARCH);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_STANDBY);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_OPENURL);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_LAUNCHMAIL);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_LAUNCHMEDIA);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_LAUNCH0);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_LAUNCH1);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_LAUNCH2);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_LAUNCH3);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_LAUNCH4);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_LAUNCH5);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_LAUNCH6);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_LAUNCH7);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_LAUNCH8);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_LAUNCH9);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_LAUNCHA);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_LAUNCHB);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_LAUNCHC);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_LAUNCHD);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_LAUNCHE);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_LAUNCHF);
-
- BIND_GLOBAL_ENUM_CONSTANT(KEY_UNKNOWN);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_SPACE);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_EXCLAM);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_QUOTEDBL);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_NUMBERSIGN);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_DOLLAR);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_PERCENT);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_AMPERSAND);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_APOSTROPHE);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_PARENLEFT);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_PARENRIGHT);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_ASTERISK);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_PLUS);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_COMMA);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_MINUS);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_PERIOD);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_SLASH);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_0);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_1);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_2);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_3);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_4);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_5);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_6);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_7);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_8);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_9);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_COLON);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_SEMICOLON);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_LESS);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_EQUAL);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_GREATER);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_QUESTION);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_AT);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_A);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_B);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_C);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_D);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_E);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_F);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_G);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_H);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_I);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_J);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_K);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_L);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_M);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_N);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_O);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_P);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_Q);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_R);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_S);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_T);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_U);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_V);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_W);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_X);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_Y);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_Z);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_BRACKETLEFT);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_BACKSLASH);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_BRACKETRIGHT);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_ASCIICIRCUM);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_UNDERSCORE);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_QUOTELEFT);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_BRACELEFT);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_BAR);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_BRACERIGHT);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_ASCIITILDE);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_NOBREAKSPACE);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_EXCLAMDOWN);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_CENT);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_STERLING);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_CURRENCY);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_YEN);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_BROKENBAR);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_SECTION);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_DIAERESIS);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_COPYRIGHT);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_ORDFEMININE);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_GUILLEMOTLEFT);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_NOTSIGN);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_HYPHEN);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_REGISTERED);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_MACRON);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_DEGREE);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_PLUSMINUS);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_TWOSUPERIOR);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_THREESUPERIOR);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_ACUTE);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_MU);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_PARAGRAPH);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_PERIODCENTERED);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_CEDILLA);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_ONESUPERIOR);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_MASCULINE);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_GUILLEMOTRIGHT);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_ONEQUARTER);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_ONEHALF);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_THREEQUARTERS);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_QUESTIONDOWN);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_AGRAVE);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_AACUTE);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_ACIRCUMFLEX);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_ATILDE);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_ADIAERESIS);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_ARING);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_AE);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_CCEDILLA);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_EGRAVE);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_EACUTE);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_ECIRCUMFLEX);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_EDIAERESIS);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_IGRAVE);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_IACUTE);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_ICIRCUMFLEX);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_IDIAERESIS);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_ETH);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_NTILDE);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_OGRAVE);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_OACUTE);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_OCIRCUMFLEX);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_OTILDE);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_ODIAERESIS);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_MULTIPLY);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_OOBLIQUE);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_UGRAVE);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_UACUTE);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_UCIRCUMFLEX);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_UDIAERESIS);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_YACUTE);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_THORN);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_SSHARP);
-
- BIND_GLOBAL_ENUM_CONSTANT(KEY_DIVISION);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_YDIAERESIS);
-
- BIND_GLOBAL_ENUM_CONSTANT(KEY_CODE_MASK);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_MODIFIER_MASK);
-
- BIND_GLOBAL_ENUM_CONSTANT(KEY_MASK_SHIFT);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_MASK_ALT);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_MASK_META);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_MASK_CTRL);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_MASK_CMD);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_MASK_KPAD);
- BIND_GLOBAL_ENUM_CONSTANT(KEY_MASK_GROUP_SWITCH);
-
- // mouse
- BIND_GLOBAL_ENUM_CONSTANT(BUTTON_LEFT);
- BIND_GLOBAL_ENUM_CONSTANT(BUTTON_RIGHT);
- BIND_GLOBAL_ENUM_CONSTANT(BUTTON_MIDDLE);
- BIND_GLOBAL_ENUM_CONSTANT(BUTTON_XBUTTON1);
- BIND_GLOBAL_ENUM_CONSTANT(BUTTON_XBUTTON2);
- BIND_GLOBAL_ENUM_CONSTANT(BUTTON_WHEEL_UP);
- BIND_GLOBAL_ENUM_CONSTANT(BUTTON_WHEEL_DOWN);
- BIND_GLOBAL_ENUM_CONSTANT(BUTTON_WHEEL_LEFT);
- BIND_GLOBAL_ENUM_CONSTANT(BUTTON_WHEEL_RIGHT);
- BIND_GLOBAL_ENUM_CONSTANT(BUTTON_MASK_LEFT);
- BIND_GLOBAL_ENUM_CONSTANT(BUTTON_MASK_RIGHT);
- BIND_GLOBAL_ENUM_CONSTANT(BUTTON_MASK_MIDDLE);
- BIND_GLOBAL_ENUM_CONSTANT(BUTTON_MASK_XBUTTON1);
- BIND_GLOBAL_ENUM_CONSTANT(BUTTON_MASK_XBUTTON2);
-
- // Joypad buttons
- BIND_GLOBAL_ENUM_CONSTANT(JOY_INVALID_BUTTON);
- BIND_GLOBAL_ENUM_CONSTANT(JOY_BUTTON_A);
- BIND_GLOBAL_ENUM_CONSTANT(JOY_BUTTON_B);
- BIND_GLOBAL_ENUM_CONSTANT(JOY_BUTTON_X);
- BIND_GLOBAL_ENUM_CONSTANT(JOY_BUTTON_Y);
- BIND_GLOBAL_ENUM_CONSTANT(JOY_BUTTON_BACK);
- BIND_GLOBAL_ENUM_CONSTANT(JOY_BUTTON_GUIDE);
- BIND_GLOBAL_ENUM_CONSTANT(JOY_BUTTON_START);
- BIND_GLOBAL_ENUM_CONSTANT(JOY_BUTTON_LEFT_STICK);
- BIND_GLOBAL_ENUM_CONSTANT(JOY_BUTTON_RIGHT_STICK);
- BIND_GLOBAL_ENUM_CONSTANT(JOY_BUTTON_LEFT_SHOULDER);
- BIND_GLOBAL_ENUM_CONSTANT(JOY_BUTTON_RIGHT_SHOULDER);
- BIND_GLOBAL_ENUM_CONSTANT(JOY_BUTTON_DPAD_UP);
- BIND_GLOBAL_ENUM_CONSTANT(JOY_BUTTON_DPAD_DOWN);
- BIND_GLOBAL_ENUM_CONSTANT(JOY_BUTTON_DPAD_LEFT);
- BIND_GLOBAL_ENUM_CONSTANT(JOY_BUTTON_DPAD_RIGHT);
- BIND_GLOBAL_ENUM_CONSTANT(JOY_SDL_BUTTONS);
- BIND_GLOBAL_ENUM_CONSTANT(JOY_SONY_X);
- BIND_GLOBAL_ENUM_CONSTANT(JOY_SONY_CROSS);
- BIND_GLOBAL_ENUM_CONSTANT(JOY_SONY_CIRCLE);
- BIND_GLOBAL_ENUM_CONSTANT(JOY_SONY_SQUARE);
- BIND_GLOBAL_ENUM_CONSTANT(JOY_SONY_TRIANGLE);
- BIND_GLOBAL_ENUM_CONSTANT(JOY_SONY_SELECT);
- BIND_GLOBAL_ENUM_CONSTANT(JOY_SONY_START);
- BIND_GLOBAL_ENUM_CONSTANT(JOY_SONY_PS);
- BIND_GLOBAL_ENUM_CONSTANT(JOY_SONY_L1);
- BIND_GLOBAL_ENUM_CONSTANT(JOY_SONY_R1);
- BIND_GLOBAL_ENUM_CONSTANT(JOY_SONY_L3);
- BIND_GLOBAL_ENUM_CONSTANT(JOY_SONY_R3);
- BIND_GLOBAL_ENUM_CONSTANT(JOY_XBOX_A);
- BIND_GLOBAL_ENUM_CONSTANT(JOY_XBOX_B);
- BIND_GLOBAL_ENUM_CONSTANT(JOY_XBOX_X);
- BIND_GLOBAL_ENUM_CONSTANT(JOY_XBOX_Y);
- BIND_GLOBAL_ENUM_CONSTANT(JOY_XBOX_BACK);
- BIND_GLOBAL_ENUM_CONSTANT(JOY_XBOX_START);
- BIND_GLOBAL_ENUM_CONSTANT(JOY_XBOX_HOME);
- BIND_GLOBAL_ENUM_CONSTANT(JOY_XBOX_LS);
- BIND_GLOBAL_ENUM_CONSTANT(JOY_XBOX_RS);
- BIND_GLOBAL_ENUM_CONSTANT(JOY_XBOX_LB);
- BIND_GLOBAL_ENUM_CONSTANT(JOY_XBOX_RB);
- BIND_GLOBAL_ENUM_CONSTANT(JOY_BUTTON_MAX);
-
- // Joypad axes
- BIND_GLOBAL_ENUM_CONSTANT(JOY_INVALID_AXIS);
- BIND_GLOBAL_ENUM_CONSTANT(JOY_AXIS_LEFT_X);
- BIND_GLOBAL_ENUM_CONSTANT(JOY_AXIS_LEFT_Y);
- BIND_GLOBAL_ENUM_CONSTANT(JOY_AXIS_RIGHT_X);
- BIND_GLOBAL_ENUM_CONSTANT(JOY_AXIS_RIGHT_Y);
- BIND_GLOBAL_ENUM_CONSTANT(JOY_AXIS_TRIGGER_LEFT);
- BIND_GLOBAL_ENUM_CONSTANT(JOY_AXIS_TRIGGER_RIGHT);
- BIND_GLOBAL_ENUM_CONSTANT(JOY_SDL_AXES);
- BIND_GLOBAL_ENUM_CONSTANT(JOY_AXIS_0_X);
- BIND_GLOBAL_ENUM_CONSTANT(JOY_AXIS_0_Y);
- BIND_GLOBAL_ENUM_CONSTANT(JOY_AXIS_1_X);
- BIND_GLOBAL_ENUM_CONSTANT(JOY_AXIS_1_Y);
- BIND_GLOBAL_ENUM_CONSTANT(JOY_AXIS_2_X);
- BIND_GLOBAL_ENUM_CONSTANT(JOY_AXIS_2_Y);
- BIND_GLOBAL_ENUM_CONSTANT(JOY_AXIS_3_X);
- BIND_GLOBAL_ENUM_CONSTANT(JOY_AXIS_3_Y);
- BIND_GLOBAL_ENUM_CONSTANT(JOY_AXIS_4_X);
- BIND_GLOBAL_ENUM_CONSTANT(JOY_AXIS_4_Y);
- BIND_GLOBAL_ENUM_CONSTANT(JOY_AXIS_MAX);
-
- // midi
- BIND_GLOBAL_ENUM_CONSTANT(MIDI_MESSAGE_NOTE_OFF);
- BIND_GLOBAL_ENUM_CONSTANT(MIDI_MESSAGE_NOTE_ON);
- BIND_GLOBAL_ENUM_CONSTANT(MIDI_MESSAGE_AFTERTOUCH);
- BIND_GLOBAL_ENUM_CONSTANT(MIDI_MESSAGE_CONTROL_CHANGE);
- BIND_GLOBAL_ENUM_CONSTANT(MIDI_MESSAGE_PROGRAM_CHANGE);
- BIND_GLOBAL_ENUM_CONSTANT(MIDI_MESSAGE_CHANNEL_PRESSURE);
- BIND_GLOBAL_ENUM_CONSTANT(MIDI_MESSAGE_PITCH_BEND);
-
- // error list
-
- BIND_GLOBAL_ENUM_CONSTANT(OK); // (0)
- BIND_GLOBAL_ENUM_CONSTANT(FAILED);
- BIND_GLOBAL_ENUM_CONSTANT(ERR_UNAVAILABLE);
- BIND_GLOBAL_ENUM_CONSTANT(ERR_UNCONFIGURED);
- BIND_GLOBAL_ENUM_CONSTANT(ERR_UNAUTHORIZED);
- BIND_GLOBAL_ENUM_CONSTANT(ERR_PARAMETER_RANGE_ERROR); // (5)
- BIND_GLOBAL_ENUM_CONSTANT(ERR_OUT_OF_MEMORY);
- BIND_GLOBAL_ENUM_CONSTANT(ERR_FILE_NOT_FOUND);
- BIND_GLOBAL_ENUM_CONSTANT(ERR_FILE_BAD_DRIVE);
- BIND_GLOBAL_ENUM_CONSTANT(ERR_FILE_BAD_PATH);
- BIND_GLOBAL_ENUM_CONSTANT(ERR_FILE_NO_PERMISSION); // (10)
- BIND_GLOBAL_ENUM_CONSTANT(ERR_FILE_ALREADY_IN_USE);
- BIND_GLOBAL_ENUM_CONSTANT(ERR_FILE_CANT_OPEN);
- BIND_GLOBAL_ENUM_CONSTANT(ERR_FILE_CANT_WRITE);
- BIND_GLOBAL_ENUM_CONSTANT(ERR_FILE_CANT_READ);
- BIND_GLOBAL_ENUM_CONSTANT(ERR_FILE_UNRECOGNIZED); // (15)
- BIND_GLOBAL_ENUM_CONSTANT(ERR_FILE_CORRUPT);
- BIND_GLOBAL_ENUM_CONSTANT(ERR_FILE_MISSING_DEPENDENCIES);
- BIND_GLOBAL_ENUM_CONSTANT(ERR_FILE_EOF);
- BIND_GLOBAL_ENUM_CONSTANT(ERR_CANT_OPEN);
- BIND_GLOBAL_ENUM_CONSTANT(ERR_CANT_CREATE); // (20)
- BIND_GLOBAL_ENUM_CONSTANT(ERR_QUERY_FAILED);
- BIND_GLOBAL_ENUM_CONSTANT(ERR_ALREADY_IN_USE);
- BIND_GLOBAL_ENUM_CONSTANT(ERR_LOCKED);
- BIND_GLOBAL_ENUM_CONSTANT(ERR_TIMEOUT);
- BIND_GLOBAL_ENUM_CONSTANT(ERR_CANT_CONNECT); // (25)
- BIND_GLOBAL_ENUM_CONSTANT(ERR_CANT_RESOLVE);
- BIND_GLOBAL_ENUM_CONSTANT(ERR_CONNECTION_ERROR);
- BIND_GLOBAL_ENUM_CONSTANT(ERR_CANT_ACQUIRE_RESOURCE);
- BIND_GLOBAL_ENUM_CONSTANT(ERR_CANT_FORK);
- BIND_GLOBAL_ENUM_CONSTANT(ERR_INVALID_DATA); // (30)
- BIND_GLOBAL_ENUM_CONSTANT(ERR_INVALID_PARAMETER);
- BIND_GLOBAL_ENUM_CONSTANT(ERR_ALREADY_EXISTS);
- BIND_GLOBAL_ENUM_CONSTANT(ERR_DOES_NOT_EXIST);
- BIND_GLOBAL_ENUM_CONSTANT(ERR_DATABASE_CANT_READ);
- BIND_GLOBAL_ENUM_CONSTANT(ERR_DATABASE_CANT_WRITE); // (35)
- BIND_GLOBAL_ENUM_CONSTANT(ERR_COMPILATION_FAILED);
- BIND_GLOBAL_ENUM_CONSTANT(ERR_METHOD_NOT_FOUND);
- BIND_GLOBAL_ENUM_CONSTANT(ERR_LINK_FAILED);
- BIND_GLOBAL_ENUM_CONSTANT(ERR_SCRIPT_FAILED);
- BIND_GLOBAL_ENUM_CONSTANT(ERR_CYCLIC_LINK); // (40)
- BIND_GLOBAL_ENUM_CONSTANT(ERR_INVALID_DECLARATION);
- BIND_GLOBAL_ENUM_CONSTANT(ERR_DUPLICATE_SYMBOL);
- BIND_GLOBAL_ENUM_CONSTANT(ERR_PARSE_ERROR);
- BIND_GLOBAL_ENUM_CONSTANT(ERR_BUSY);
- BIND_GLOBAL_ENUM_CONSTANT(ERR_SKIP); // (45)
- BIND_GLOBAL_ENUM_CONSTANT(ERR_HELP);
- BIND_GLOBAL_ENUM_CONSTANT(ERR_BUG);
- BIND_GLOBAL_ENUM_CONSTANT(ERR_PRINTER_ON_FIRE);
-
- BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_HINT_NONE);
- BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_HINT_RANGE);
- BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_HINT_EXP_RANGE);
- BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_HINT_ENUM);
- BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_HINT_EXP_EASING);
- BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_HINT_LENGTH);
- BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_HINT_KEY_ACCEL);
- BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_HINT_FLAGS);
-
- BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_HINT_LAYERS_2D_RENDER);
- BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_HINT_LAYERS_2D_PHYSICS);
- BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_HINT_LAYERS_3D_RENDER);
- BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_HINT_LAYERS_3D_PHYSICS);
-
- BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_HINT_FILE);
- BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_HINT_DIR);
- BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_HINT_GLOBAL_FILE);
- BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_HINT_GLOBAL_DIR);
- BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_HINT_RESOURCE_TYPE);
- BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_HINT_MULTILINE_TEXT);
- BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_HINT_PLACEHOLDER_TEXT);
- BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_HINT_COLOR_NO_ALPHA);
- BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_HINT_IMAGE_COMPRESS_LOSSY);
- BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_HINT_IMAGE_COMPRESS_LOSSLESS);
-
- BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_USAGE_STORAGE);
- BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_USAGE_EDITOR);
- BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_USAGE_NETWORK);
-
- BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_USAGE_EDITOR_HELPER);
- BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_USAGE_CHECKABLE);
- BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_USAGE_CHECKED);
- BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_USAGE_INTERNATIONALIZED);
- BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_USAGE_GROUP);
- BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_USAGE_CATEGORY);
- BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_USAGE_SUBGROUP);
- BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_USAGE_NO_INSTANCE_STATE);
- BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_USAGE_RESTART_IF_CHANGED);
- BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_USAGE_SCRIPT_VARIABLE);
-
- BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_USAGE_DEFAULT);
- BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_USAGE_DEFAULT_INTL);
- BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_USAGE_NOEDITOR);
-
- BIND_GLOBAL_ENUM_CONSTANT(METHOD_FLAG_NORMAL);
- BIND_GLOBAL_ENUM_CONSTANT(METHOD_FLAG_EDITOR);
- BIND_GLOBAL_ENUM_CONSTANT(METHOD_FLAG_NOSCRIPT);
- BIND_GLOBAL_ENUM_CONSTANT(METHOD_FLAG_CONST);
- BIND_GLOBAL_ENUM_CONSTANT(METHOD_FLAG_REVERSE);
- BIND_GLOBAL_ENUM_CONSTANT(METHOD_FLAG_VIRTUAL);
- BIND_GLOBAL_ENUM_CONSTANT(METHOD_FLAG_FROM_SCRIPT);
- BIND_GLOBAL_ENUM_CONSTANT(METHOD_FLAGS_DEFAULT);
-
- BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("TYPE_NIL", Variant::NIL);
- BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("TYPE_BOOL", Variant::BOOL);
- BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("TYPE_INT", Variant::INT);
- BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("TYPE_REAL", Variant::FLOAT);
- BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("TYPE_STRING", Variant::STRING);
- BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("TYPE_VECTOR2", Variant::VECTOR2);
- BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("TYPE_VECTOR2I", Variant::VECTOR2I);
- BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("TYPE_RECT2", Variant::RECT2);
- BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("TYPE_RECT2I", Variant::RECT2I);
- BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("TYPE_VECTOR3", Variant::VECTOR3);
- BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("TYPE_VECTOR3I", Variant::VECTOR3I);
- BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("TYPE_TRANSFORM2D", Variant::TRANSFORM2D);
- BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("TYPE_PLANE", Variant::PLANE);
- BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("TYPE_QUAT", Variant::QUAT);
- BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("TYPE_AABB", Variant::AABB);
- BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("TYPE_BASIS", Variant::BASIS);
- BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("TYPE_TRANSFORM", Variant::TRANSFORM);
- BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("TYPE_COLOR", Variant::COLOR);
- BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("TYPE_STRING_NAME", Variant::STRING_NAME);
- BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("TYPE_NODE_PATH", Variant::NODE_PATH);
- BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("TYPE_RID", Variant::_RID);
- BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("TYPE_OBJECT", Variant::OBJECT);
- BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("TYPE_CALLABLE", Variant::CALLABLE);
- BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("TYPE_SIGNAL", Variant::SIGNAL);
- BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("TYPE_DICTIONARY", Variant::DICTIONARY);
- BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("TYPE_ARRAY", Variant::ARRAY);
- BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("TYPE_RAW_ARRAY", Variant::PACKED_BYTE_ARRAY);
- BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("TYPE_INT32_ARRAY", Variant::PACKED_INT32_ARRAY);
- BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("TYPE_INT64_ARRAY", Variant::PACKED_INT64_ARRAY);
- BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("TYPE_FLOAT32_ARRAY", Variant::PACKED_FLOAT32_ARRAY);
- BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("TYPE_FLOAT64_ARRAY", Variant::PACKED_FLOAT64_ARRAY);
- BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("TYPE_STRING_ARRAY", Variant::PACKED_STRING_ARRAY);
- BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("TYPE_VECTOR2_ARRAY", Variant::PACKED_VECTOR2_ARRAY);
- BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("TYPE_VECTOR3_ARRAY", Variant::PACKED_VECTOR3_ARRAY);
- BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("TYPE_COLOR_ARRAY", Variant::PACKED_COLOR_ARRAY);
- BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("TYPE_MAX", Variant::VARIANT_MAX);
-
- //comparison
- BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("OP_EQUAL", Variant::OP_EQUAL);
- BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("OP_NOT_EQUAL", Variant::OP_NOT_EQUAL);
- BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("OP_LESS", Variant::OP_LESS);
- BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("OP_LESS_EQUAL", Variant::OP_LESS_EQUAL);
- BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("OP_GREATER", Variant::OP_GREATER);
- BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("OP_GREATER_EQUAL", Variant::OP_GREATER_EQUAL);
- //mathematic
- BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("OP_ADD", Variant::OP_ADD);
- BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("OP_SUBTRACT", Variant::OP_SUBTRACT);
- BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("OP_MULTIPLY", Variant::OP_MULTIPLY);
- BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("OP_DIVIDE", Variant::OP_DIVIDE);
- BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("OP_NEGATE", Variant::OP_NEGATE);
- BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("OP_POSITIVE", Variant::OP_POSITIVE);
- BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("OP_MODULE", Variant::OP_MODULE);
- BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("OP_STRING_CONCAT", Variant::OP_STRING_CONCAT);
- //bitwise
- BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("OP_SHIFT_LEFT", Variant::OP_SHIFT_LEFT);
- BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("OP_SHIFT_RIGHT", Variant::OP_SHIFT_RIGHT);
- BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("OP_BIT_AND", Variant::OP_BIT_AND);
- BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("OP_BIT_OR", Variant::OP_BIT_OR);
- BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("OP_BIT_XOR", Variant::OP_BIT_XOR);
- BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("OP_BIT_NEGATE", Variant::OP_BIT_NEGATE);
- //logic
- BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("OP_AND", Variant::OP_AND);
- BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("OP_OR", Variant::OP_OR);
- BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("OP_XOR", Variant::OP_XOR);
- BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("OP_NOT", Variant::OP_NOT);
- //containment
- BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("OP_IN", Variant::OP_IN);
- BIND_GLOBAL_ENUM_CONSTANT_CUSTOM("OP_MAX", Variant::OP_MAX);
-}
-
-void unregister_global_constants() {
- _global_constants.clear();
-}
-
-int GlobalConstants::get_global_constant_count() {
- return _global_constants.size();
-}
-
-#ifdef DEBUG_METHODS_ENABLED
-StringName GlobalConstants::get_global_constant_enum(int p_idx) {
- return _global_constants[p_idx].enum_name;
-}
-#else
-StringName GlobalConstants::get_global_constant_enum(int p_idx) {
- return StringName();
-}
-#endif
-
-const char *GlobalConstants::get_global_constant_name(int p_idx) {
- return _global_constants[p_idx].name;
-}
-
-int GlobalConstants::get_global_constant_value(int p_idx) {
- return _global_constants[p_idx].value;
-}
diff --git a/core/input/SCsub b/core/input/SCsub
index c641819698..740398b266 100644
--- a/core/input/SCsub
+++ b/core/input/SCsub
@@ -2,7 +2,6 @@
Import("env")
-from platform_methods import run_in_subprocess
import input_builders
@@ -16,7 +15,7 @@ env.Depends("#core/input/default_controller_mappings.gen.cpp", controller_databa
env.CommandNoCache(
"#core/input/default_controller_mappings.gen.cpp",
controller_databases,
- run_in_subprocess(input_builders.make_default_controller_mappings),
+ env.Run(input_builders.make_default_controller_mappings, "Generating default controller mappings."),
)
env.add_source_files(env.core_sources, "*.cpp")
diff --git a/core/input/gamecontrollerdb.txt b/core/input/gamecontrollerdb.txt
index 7b5abdd61b..180708cea6 100644
--- a/core/input/gamecontrollerdb.txt
+++ b/core/input/gamecontrollerdb.txt
@@ -8,6 +8,7 @@
03000000c82d00001038000000000000,8BitDo F30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Windows,
03000000c82d00000090000000000000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,
03000000c82d00000650000000000000,8BitDo M30,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:a4,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,start:b11,x:b3,y:b4,platform:Windows,
+03000000c82d00005106000000000000,8BitDo M30 Gamepad,a:b1,b:b0,back:b10,guide:b2,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,start:b11,x:b4,y:b3,platform:Windows,
03000000c82d00000310000000000000,8BitDo N30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Windows,
03000000c82d00002028000000000000,8BitDo N30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Windows,
03000000c82d00008010000000000000,8BitDo N30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Windows,
@@ -35,6 +36,7 @@
03000000c82d00000260000000000000,8BitDo SN30 Pro+,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Windows,
03000000c82d00000261000000000000,8BitDo SN30 Pro+,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Windows,
03000000c82d00000031000000000000,8BitDo Wireless Adapter,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,
+03000000c82d00001890000000000000,8BitDo Zero 2,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows,
03000000c82d00003032000000000000,8BitDo Zero 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Windows,
03000000a00500003232000000000000,8Bitdo Zero GamePad,a:b0,b:b1,back:b10,dpdown:+a2,dpleft:-a0,dpright:+a0,dpup:-a2,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Windows,
030000008f0e00001200000000000000,Acme GA-02,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b2,y:b3,platform:Windows,
@@ -52,6 +54,7 @@
03000000d6200000e557000000000000,Batarang,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
03000000c01100001352000000000000,Battalife Joystick,a:b6,b:b7,back:b2,leftshoulder:b0,leftx:a0,lefty:a1,rightshoulder:b1,start:b3,x:b4,y:b5,platform:Windows,
030000006f0e00003201000000000000,Battlefield 4 PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
+03000000d62000002a79000000000000,BDA PS4 Fightpad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
03000000bc2000006012000000000000,Betop 2126F,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,
03000000bc2000000055000000000000,Betop BFM Gamepad,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
03000000bc2000006312000000000000,Betop Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,
@@ -83,6 +86,8 @@
03000000120c0000f61c000000000000,Elite,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
030000008f0e00000f31000000000000,EXEQ,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Windows,
03000000341a00000108000000000000,EXEQ RF USB Gamepad 8206,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,
+030000006f0e00008001000000000000,Faceoff Wired Pro Controller for Nintendo Switch,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Windows,
+030000006f0e00008401000000000000,Faceoff Deluxe+ Audio Wired Controller for Nintendo Switch,platform:Windows,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,
03000000852100000201000000000000,FF-GP1,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
030000000d0f00008500000000000000,Fighting Commander 2016 PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
030000000d0f00008400000000000000,Fighting Commander 5,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
@@ -98,8 +103,10 @@
03000000ac0500003d03000000000000,GameSir,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
03000000ac0500004d04000000000000,GameSir,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
03000000ffff00000000000000000000,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,
+03000000c01100000140000000000000,GameStop PS4 Fun Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
030000006f0e00000102000000007801,GameStop Xbox 360 Wired Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
030000009b2800003200000000000000,GC/N64 to USB v3.4,a:b0,b:b7,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,lefttrigger:+a5,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:+a2,rightx:a3,righty:a4,start:b3,x:b1,y:b8,platform:Windows,
+030000009b2800006000000000000000,GC/N64 to USB v3.6,a:b0,b:b7,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,lefttrigger:+a5,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:+a2,rightx:a3,righty:a4,start:b3,x:b1,y:b8,platform:Windows,
030000008305000009a0000000000000,Genius,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,
030000008305000031b0000000000000,Genius Maxfire Blaze 3,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,
03000000451300000010000000000000,Genius Maxfire Grandias 12,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,
@@ -157,6 +164,7 @@
030000006d04000016c2000000000000,Logitech Dual Action,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
030000006d04000018c2000000000000,Logitech F510 Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
030000006d04000019c2000000000000,Logitech F710 Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
+030000006d0400001ac2000000000000,Logitech Precision Gamepad,a:b1,b:b2,x:b0,y:b3,back:b8,start:b9,leftshoulder:b4,rightshoulder:b5,dpup:-a1,dpdown:+a1,dpleft:-a0,dpright:+a0,lefttrigger:b6,righttrigger:b7,platform:Windows,
03000000380700006652000000000000,Mad Catz C.T.R.L.R,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Windows,
03000000380700005032000000000000,Mad Catz FightPad PRO (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
03000000380700005082000000000000,Mad Catz FightPad PRO (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
@@ -183,8 +191,11 @@
03000000790000000018000000000000,Mayflash WiiU Pro Game Controller Adapter (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
03000000790000002418000000000000,Mega Drive,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,rightshoulder:b2,start:b9,x:b3,y:b4,platform:Windows,
03000000380700006382000000000000,MLG GamePad PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
+03000000c62400002a89000000000000,MOGA XP5-A Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
+03000000c62400002b89000000000000,MOGA XP5-A Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
03000000efbe0000edfe000000000000,Monect Virtual Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b0,platform:Windows,
03000000250900006688000000000000,MP-8866 Super Dual Box,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows,
+030000006b140000010c000000000000,NACON GC-400ES,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,
030000001008000001e5000000000000,NEXT SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b6,start:b9,x:b3,y:b0,platform:Windows,
03000000152000000182000000000000,NGDS,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b3,y:b0,platform:Windows,
03000000bd12000015d0000000000000,Nintendo Retrolink USB Super SNES Classic Controller,a:b2,b:b1,back:b8,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Windows,
@@ -197,6 +208,7 @@
030000006b14000001a1000000000000,Orange Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b2,y:b3,platform:Windows,
03000000362800000100000000000000,OUYA Game Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:b13,rightx:a3,righty:a4,x:b1,y:b2,platform:Windows,
03000000120c0000f60e000000000000,P4 Wired Gamepad,a:b1,b:b2,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b5,lefttrigger:b7,rightshoulder:b4,righttrigger:b6,start:b9,x:b0,y:b3,platform:Windows,
+030000006f0e00000901000000000000,PDP Versus Fighting Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,
030000008f0e00000300000000000000,Piranha xtreme,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Windows,
030000004c050000da0c000000000000,PlayStation Classic Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Windows,
03000000d62000006dca000000000000,PowerA Pro Ex,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
@@ -232,8 +244,11 @@
03000000321500000003000000000000,Razer Hydra,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
03000000321500000204000000000000,Razer Panthera (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
03000000321500000104000000000000,Razer Panthera (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+03000000321500000810000011010000,Razer Panthera Evo Arcade Stick for PS4,platform:Linux,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b13,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a3,righttrigger:a4,
03000000321500000507000000000000,Razer Raiju Mobile,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
03000000321500000707000000000000,Razer Raiju Mobile,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
+03000000321500000011000000000000,Razer Raion Fightpad for PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+03000000321500000009000000000000,Razer Serval,+lefty:+a2,-lefty:-a1,a:b0,b:b1,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,leftx:a0,rightshoulder:b5,rightstick:b9,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
030000000d0f00001100000000000000,REAL ARCADE PRO.3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,rightstick:b11,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,
030000000d0f00006a00000000000000,Real Arcade Pro.4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
030000000d0f00006b00000000000000,Real Arcade Pro.4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
@@ -248,6 +263,7 @@
0300000000f00000f100000000000000,RetroUSB.com Super RetroPort,a:b1,b:b5,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b0,y:b4,platform:Windows,
030000006b140000010d000000000000,Revolution Pro Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
030000006b140000020d000000000000,Revolution Pro Controller 2(1/2),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+030000006b140000130d000000000000,Revolution Pro Controller 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
030000006f0e00001e01000000000000,Rock Candy PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
030000006f0e00002801000000000000,Rock Candy PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
030000006f0e00002f01000000000000,Rock Candy PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
@@ -275,16 +291,19 @@
03000000d11800000094000000000000,Stadia Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:b12,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:b11,rightx:a3,righty:a4,start:b9,x:b2,y:b3,platform:Windows,
03000000110100001914000000000000,SteelSeries,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftstick:b13,lefttrigger:b6,leftx:a0,lefty:a1,rightstick:b14,righttrigger:b7,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
03000000381000001214000000000000,SteelSeries Free,a:b0,b:b1,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Windows,
+03000000110100003114000000000000,SteelSeries Stratus Duo,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
03000000381000001814000000000000,SteelSeries Stratus XL,a:b0,b:b1,back:b18,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,guide:b19,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b2,y:b3,platform:Windows,
03000000790000001c18000000000000,STK-7024X,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
03000000ff1100003133000000000000,SVEN X-PAD,a:b2,b:b3,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a4,start:b5,x:b0,y:b1,platform:Windows,
03000000d620000011a7000000000000,Switch,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
+03000000457500002211000000000000,SZMY-POWER PC Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
030000004f04000007d0000000000000,T Mini Wireless,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
030000004f0400000ab1000000000000,T.16000M,a:b0,b:b1,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b4,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,start:b10,x:b2,y:b3,platform:Windows,
03000000fa1900000706000000000000,Team 5,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,
03000000b50700001203000000000000,Techmobility X6-38V,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Windows,
030000004f04000015b3000000000000,Thrustmaster Dual Analog 4,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Windows,
030000004f04000023b3000000000000,Thrustmaster Dual Trigger 3-in-1,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+030000004f0400000ed0000000000000,ThrustMaster eSwap PRO Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
030000004f04000000b3000000000000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b11,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b10,x:b1,y:b3,platform:Windows,
030000004f04000004b3000000000000,Thrustmaster Firestorm Dual Power 3,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Windows,
03000000666600000488000000000000,TigerGame PS/PS2 Game Controller Adapter,a:b2,b:b1,back:b9,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows,
@@ -306,6 +325,7 @@
03000000790000001a18000000000000,Venom,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
03000000790000001b18000000000000,Venom Arcade Joystick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,
030000006f0e00000302000000000000,Victrix Pro Fight Stick for PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,
+030000006f0e00000702000000000000,Victrix Pro Fight Stick for PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,
0300000034120000adbe000000000000,vJoy Device,a:b0,b:b1,back:b15,dpdown:b6,dpleft:b7,dpright:b8,dpup:b5,guide:b16,leftshoulder:b9,leftstick:b13,lefttrigger:b11,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b14,righttrigger:b12,rightx:+a3,righty:+a4,start:b4,x:b2,y:b3,platform:Windows,
030000005e0400000a0b000000000000,Xbox Adaptive Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:+a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:-a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
03000000341a00000608000000000000,Xeox,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,
@@ -315,28 +335,39 @@
03000000786901006e70000000000000,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
03000000790000004f18000000000000,ZD-T Android,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
-030000009b2800006000000000000000,GC/N64 to USB v3.6,a:b0,b:b7,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,lefttrigger:+a5,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:+a2,rightx:a3,righty:a4,start:b3,x:b1,y:b8,platform:Windows,
+03000000120c0000101e000000000000,ZEROPLUS P4 Wired Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
# Mac OS X
-030000008f0e00000300000009010000,2In1 USB Joystick,+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Mac OS X,
+030000008f0e00000300000009010000,2In1 USB Joystick,a:b2,b:b1,x:b3,y:b0,back:b8,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Mac OS X,
+03000000c82d00000090000001000000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
+03000000c82d00001038000000010000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
03000000c82d00000650000001000000,8BitDo M30,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,start:b11,x:b3,y:b4,platform:Mac OS X,
+03000000c82d00005106000000010000,8BitDo M30 Gamepad,a:b1,b:b0,back:b10,guide:b2,leftshoulder:b6,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,start:b11,x:b4,y:b3,platform:Mac OS X,
+03000000c82d00001590000001000000,8BitDo N30 Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
+03000000c82d00006528000000010000,8BitDo N30 Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
+030000003512000012ab000001000000,8BitDo NES30 Gamepad,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X,
03000000022000000090000001000000,8Bitdo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
03000000203800000900000000010000,8Bitdo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
03000000c82d00000190000001000000,8Bitdo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
03000000102800000900000000000000,8Bitdo SFC30 GamePad Joystick,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X,
+03000000c82d00001290000001000000,8BitDo SN30 Gamepad,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X,
+03000000c82d00000160000001000000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
03000000c82d00000161000000010000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Mac OS X,
03000000c82d00000260000001000000,8BitDo SN30 Pro+,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
03000000c82d00000261000000010000,8BitDo SN30 Pro+,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
03000000c82d00000031000001000000,8BitDo Wireless Adapter,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
+03000000c82d00001890000001000000,8BitDo Zero 2,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X,
03000000c82d00003032000000010000,8BitDo Zero 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2,righty:a31,start:b11,x:b4,y:b3,platform:Mac OS X,
03000000a00500003232000008010000,8Bitdo Zero GamePad,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Mac OS X,
03000000a00500003232000009010000,8Bitdo Zero GamePad,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Mac OS X,
03000000050b00000045000031000000,ASUS Gamepad,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X,
+03000000d62000002a79000000010000,BDA PS4 Fightpad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
030000008305000031b0000000000000,Cideko AK08b,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
03000000260900008888000088020000,Cyber Gadget GameCube Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:a5,rightx:a2,righty:a3~,start:b7,x:b2,y:b3,platform:Mac OS X,
03000000a306000022f6000001030000,Cyborg V.3 Rumble Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:+a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:-a3,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Mac OS X,
03000000ad1b000001f9000000000000,Gamestop BB-070 X360 Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,
0500000047532047616d657061640000,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X,
+03000000c01100000140000000010000,GameStop PS4 Fun Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
030000006f0e00000102000000000000,GameStop Xbox 360 Wired Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,
030000007d0400000540000001010000,Gravis Eliminator GamePad Pro,a:b1,b:b2,back:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X,
030000000d0f00002d00000000100000,Hori Fighting Commander 3 Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
@@ -378,11 +409,15 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000d8140000cecf000000000000,MC Cthulhu,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X,
030000005e0400002700000001010000,Microsoft SideWinder Plug & Play Game Pad,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,lefttrigger:b4,leftx:a0,lefty:a1,righttrigger:b5,x:b2,y:b3,platform:Mac OS X,
03000000d62000007162000001000000,Moga Pro 2 HID,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Mac OS X,
+03000000c62400002a89000000010000,MOGA XP5-A Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b21,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
+03000000c62400002b89000000010000,MOGA XP5-A Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
03000000632500007505000000020000,NEOGEO mini PAD Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b9,x:b2,y:b3,platform:Mac OS X,
030000001008000001e5000006010000,NEXT SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b6,start:b9,x:b3,y:b0,platform:Mac OS X,
03000000d620000011a7000000020000,Nintendo Switch Core (Plus) Wired Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
030000007e0500000920000000000000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X,
030000007e0500000920000001000000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X,
+03000000550900001472000025050000,NVIDIA Controller v01.04,a:b0,b:b1,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b4,leftstick:b7,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a5,start:b6,x:b2,y:b3,platform:Mac OS X,
+030000006f0e00000901000002010000,PDP Versus Fighting Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X,
030000008f0e00000300000000000000,Piranha xtreme,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Mac OS X,
030000004c050000da0c000000010000,Playstation Classic Controller,a:b2,b:b1,back:b8,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Mac OS X,
03000000d62000006dca000000010000,PowerA Pro Ex,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
@@ -397,12 +432,14 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000321500000104000000010000,Razer Panthera (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
03000000321500000010000000010000,Razer RAIJU,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
03000000321500000507000001010000,Razer Raiju Mobile,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b21,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
+03000000321500000011000000010000,Razer Raion Fightpad for PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
03000000321500000009000000020000,Razer Serval,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Mac OS X,
030000003215000000090000163a0000,Razer Serval,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Mac OS X,
0300000032150000030a000000000000,Razer Wildcat,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,
03000000790000001100000000000000,Retrolink Classic Controller,a:b2,b:b1,back:b8,leftshoulder:b4,leftx:a3,lefty:a4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Mac OS X,
03000000790000001100000006010000,Retrolink SNES Controller,a:b2,b:b1,back:b8,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Mac OS X,
030000006b140000010d000000010000,Revolution Pro Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
+030000006b140000130d000000010000,Revolution Pro Controller 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
03000000c6240000fefa000000000000,Rock Candy Gamepad for PS3,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,
03000000730700000401000000010000,Sanwa PlayOnline Mobile,a:b0,b:b1,back:b2,leftx:a0,lefty:a1,start:b3,platform:Mac OS X,
03000000811700007e05000000000000,Sega Saturn,a:b2,b:b4,dpdown:b16,dpleft:b15,dpright:b14,dpup:b17,leftshoulder:b8,lefttrigger:a5,leftx:a0,lefty:a2,rightshoulder:b9,righttrigger:a4,start:b13,x:b0,y:b6,platform:Mac OS X,
@@ -418,18 +455,22 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000381000002014000001000000,SteelSeries Nimbus,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3~,x:b2,y:b3,platform:Mac OS X,
03000000110100001714000000000000,SteelSeries Stratus XL,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3~,start:b12,x:b2,y:b3,platform:Mac OS X,
03000000110100001714000020010000,SteelSeries Stratus XL,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3~,start:b12,x:b2,y:b3,platform:Mac OS X,
+03000000457500002211000000010000,SZMY-POWER PC Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
030000004f04000015b3000000000000,Thrustmaster Dual Analog 3.2,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Mac OS X,
+030000004f0400000ed0000000020000,ThrustMaster eSwap PRO Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
030000004f04000000b3000000000000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b11,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,rightx:a2,righty:a3,start:b10,x:b1,y:b3,platform:Mac OS X,
03000000bd12000015d0000000000000,Tomee SNES USB Controller,a:b2,b:b1,back:b8,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Mac OS X,
03000000bd12000015d0000000010000,Tomee SNES USB Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Mac OS X,
03000000100800000100000000000000,Twin USB Joystick,a:b4,b:b2,back:b16,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b12,leftstick:b20,lefttrigger:b8,leftx:a0,lefty:a2,rightshoulder:b14,rightstick:b22,righttrigger:b10,rightx:a6,righty:a4,start:b18,x:b6,y:b0,platform:Mac OS X,
030000006f0e00000302000025040000,Victrix Pro Fight Stick for PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X,
+030000006f0e00000702000003060000,Victrix Pro Fight Stick for PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X,
03000000791d00000103000009010000,Wii Classic Controller,a:b2,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b10,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Mac OS X,
050000005769696d6f74652028303000,Wii Remote,a:b4,b:b5,back:b7,dpdown:b3,dpleft:b0,dpright:b1,dpup:b2,guide:b8,leftshoulder:b11,lefttrigger:b12,leftx:a0,lefty:a1,start:b6,x:b10,y:b9,platform:Mac OS X,
050000005769696d6f74652028313800,Wii U Pro Controller,a:b16,b:b15,back:b7,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b8,leftshoulder:b19,leftstick:b23,lefttrigger:b21,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b24,righttrigger:b22,rightx:a2,righty:a3,start:b6,x:b18,y:b17,platform:Mac OS X,
030000005e0400008e02000000000000,X360 Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,
03000000c6240000045d000000000000,Xbox 360 Wired Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,
030000005e0400000a0b000000000000,Xbox Adaptive Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,
+030000005e040000050b000003090000,Xbox Elite Wireless Controller Series 2,a:b0,b:b1,back:b31,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b53,leftshoulder:b6,leftstick:b13,lefttrigger:a6,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
030000005e040000d102000000000000,Xbox One Wired Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,
030000005e040000dd02000000000000,Xbox One Wired Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,
030000005e040000e302000000000000,Xbox One Wired Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,
@@ -439,8 +480,10 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
030000005e040000fd02000003090000,Xbox Wireless Controller,a:b0,b:b1,back:b16,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
03000000172700004431000029010000,XiaoMi Game Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a6,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Mac OS X,
03000000120c0000100e000000010000,ZEROPLUS P4 Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
+03000000120c0000101e000000010000,ZEROPLUS P4 Wired Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
# Linux
+03000000c82d00000090000011010000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
05000000c82d00001038000000010000,8Bitdo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
05000000c82d00005106000000010000,8BitDo M30,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,start:b11,x:b3,y:b4,platform:Linux,
03000000c82d00001590000011010000,8BitDo N30 Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
@@ -465,8 +508,10 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
05000000c82d00006228000000010000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
03000000c82d00000260000011010000,8BitDo SN30 Pro+,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
05000000c82d00000261000000010000,8BitDo SN30 Pro+,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
+05000000202800000900000000010000,8BitDo SNES30 Gamepad,a:b1,b:b0,back:b10,dpdown:b122,dpleft:b119,dpright:b120,dpup:b117,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux,
030000005e0400008e02000020010000,8BitDo Wireless Adapter,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
03000000c82d00000031000011010000,8BitDo Wireless Adapter,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
+03000000c82d00001890000011010000,8BitDo Zero 2,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux,
05000000c82d00003032000000010000,8BitDo Zero 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
05000000a00500003232000001000000,8Bitdo Zero GamePad,a:b0,b:b1,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Linux,
05000000a00500003232000008010000,8Bitdo Zero GamePad,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Linux,
@@ -475,10 +520,12 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
030000006f0e00003901000000430000,Afterglow Prismatic Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000006f0e00003901000013020000,Afterglow Prismatic Wired Controller 048-007-NA,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
03000000100000008200000011010000,Akishop Customs PS360+ v1.66,a:b1,b:b2,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,
+030000007c1800000006000010010000,Alienware Dual Compatible Game Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b3,platform:Linux,
05000000491900000204000021000000,Amazon Fire Game Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
05000000050b00000045000031000000,ASUS Gamepad,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b10,x:b2,y:b3,platform:Linux,
05000000050b00000045000040000000,ASUS Gamepad,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b10,x:b2,y:b3,platform:Linux,
03000000120c00000500000010010000,AxisPad,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,start:b11,x:b0,y:b1,platform:Linux,
+03000000d62000002a79000011010000,BDA PS4 Fightpad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
03000000666600006706000000010000,boom PSX to PC Converter,a:b2,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a2,righty:a3,start:b11,x:b3,y:b0,platform:Linux,
03000000ffff0000ffff000000010000,Chinese-made Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b4,platform:Linux,
03000000e82000006058000001010000,Cideko AK08b,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
@@ -513,22 +560,27 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
030000000d0f00006a00000011010000,HORI CO. LTD. Real Arcade Pro.4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
030000000d0f00006b00000011010000,HORI CO. LTD. Real Arcade Pro.4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
030000000d0f00002200000011010000,HORI CO. LTD. REAL ARCADE Pro.V3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,
+030000000d0f00008500000010010000,HORI Fighting Commander,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
+030000000d0f00008600000002010000,Hori Fighting Commander,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
030000000d0f00005f00000011010000,Hori Fighting Commander 4 (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
030000000d0f00005e00000011010000,Hori Fighting Commander 4 (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
03000000ad1b000001f5000033050000,Hori Pad EX Turbo 2,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000000d0f00009200000011010000,Hori Pokken Tournament DX Pro Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,
+030000000d0f0000aa00000011010000,HORI Real Arcade Pro,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
030000000d0f00001600000000010000,Hori Real Arcade Pro.EX-SE (Xbox 360),a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b2,y:b3,platform:Linux,
030000000d0f00006e00000011010000,HORIPAD 4 (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
030000000d0f00006600000011010000,HORIPAD 4 (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
030000000d0f0000ee00000011010000,HORIPAD mini4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
030000000d0f00006700000001010000,HORIPAD ONE,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000008f0e00001330000010010000,HuiJia SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b9,x:b3,y:b0,platform:Linux,
+03000000242e00008816000001010000,Hyperkin X91,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
03000000830500006020000010010000,iBuffalo SNES Controller,a:b1,b:b0,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b3,y:b2,platform:Linux,
050000006964726f69643a636f6e0000,idroid:con,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
03000000b50700001503000010010000,impact,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Linux,
03000000d80400008200000003000000,IMS PCU#0 Gamepad Interface,a:b1,b:b0,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,start:b5,x:b3,y:b2,platform:Linux,
03000000fd0500000030000000010000,InterAct GoPad I-73000 (Fighting Game Layout),a:b3,b:b4,back:b6,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,start:b7,x:b0,y:b1,platform:Linux,
0500000049190000020400001b010000,Ipega PG-9069 - Bluetooth Gamepad,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b161,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
+03000000632500007505000011010000,Ipega PG-9099 - Bluetooth Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
030000006e0500000320000010010000,JC-U3613M - DirectInput Mode,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b0,y:b1,platform:Linux,
03000000300f00001001000010010000,Jess Tech Dual Analog Rumble Pad,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Linux,
03000000300f00000b01000010010000,Jess Tech GGE909 PC Recoil Pad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Linux,
@@ -567,7 +619,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000380700003888000010010000,MadCatz PC USB Wired Stick 8838,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:a0,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
03000000120c00000500000000010000,Manta Dualshock 2,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b2,y:b3,platform:Linux,
03000000790000004418000010010000,Mayflash GameCube Controller,a:b1,b:b2,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,platform:Linux,
-03000000790000004318000010010000,Mayflash GameCube Controller Adapter,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b2,y:b3,platform:Linux,
+03000000790000004318000010010000,Mayflash GameCube Controller Adapter,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,platform:Linux,
03000000242f00007300000011010000,Mayflash Magic NS,a:b1,b:b4,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b0,y:b3,platform:Linux,
0300000079000000d218000011010000,Mayflash Magic NS,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
03000000d620000010a7000011010000,Mayflash Magic NS,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
@@ -588,14 +640,17 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
05000000d6200000e589000001000000,Moga 2 HID,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Linux,
05000000d6200000ad0d000001000000,Moga Pro,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Linux,
05000000d62000007162000001000000,Moga Pro 2 HID,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Linux,
+03000000c62400002b89000011010000,MOGA XP5-A Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
+05000000c62400002a89000000010000,MOGA XP5-A Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b22,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
03000000250900006688000000010000,MP-8866 Super Dual Box,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Linux,
+030000006b140000010c000010010000,NACON GC-400ES,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
030000000d0f00000900000010010000,Natec Genesis P44,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
030000001008000001e5000010010000,NEXT SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b6,start:b9,x:b3,y:b0,platform:Linux,
060000007e0500000820000000000000,Nintendo Combined Joy-Cons (joycond),a:b0,b:b1,back:b9,dpdown:b15,dpleft:b16,dpright:b17,dpup:b14,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,platform:Linux,
-050000007e0500000920000001800000,Nintendo Switch Pro Controller (joycond),a:b0,b:b1,x:b3,y:b2,back:b9,guide:b11,start:b10,leftstick:b12,rightstick:b13,leftshoulder:b5,rightshoulder:b6,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b7,righttrigger:b8,platform:Linux,
-030000007e0500000920000011810000,Nintendo Switch Pro Controller Wired (joycond),a:b0,b:b1,x:b3,y:b2,back:b9,guide:b11,start:b10,leftstick:b12,rightstick:b13,leftshoulder:b5,rightshoulder:b6,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b7,righttrigger:b8,platform:Linux,
030000007e0500003703000000016800,Nintendo GameCube Controller,a:b0,b:b2,dpdown:b6,dpleft:b4,dpright:b5,dpup:b7,lefttrigger:a4,leftx:a0,lefty:a1~,rightshoulder:b9,righttrigger:a5,rightx:a2,righty:a3~,start:b8,x:b1,y:b3,platform:Linux,
050000007e0500000920000001000000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
+050000007e0500000920000001800000,Nintendo Switch Pro Controller (joycond),a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,platform:Linux,
+030000007e0500000920000011810000,Nintendo Switch Pro Controller Wired (joycond),a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,platform:Linux,
050000007e0500003003000001000000,Nintendo Wii Remote Pro Controller,a:b0,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Linux,
05000000010000000100000003000000,Nintendo Wiimote,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
030000000d0500000308000010010000,Nostromo n45 Dual Analog Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b12,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b10,x:b2,y:b3,platform:Linux,
@@ -603,19 +658,29 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000550900001472000011010000,NVIDIA Controller v01.04,a:b0,b:b1,back:b14,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b16,leftshoulder:b4,leftstick:b7,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a5,start:b6,x:b2,y:b3,platform:Linux,
05000000550900001472000001000000,NVIDIA Controller v01.04,a:b0,b:b1,back:b14,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b16,leftshoulder:b4,leftstick:b7,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a5,start:b6,x:b2,y:b3,platform:Linux,
03000000451300000830000010010000,NYKO CORE,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
+19000000010000000100000001010000,odroidgo2_joypad,a:b1,b:b0,dpdown:b7,dpleft:b8,dpright:b9,dpup:b6,guide:b10,leftshoulder:b4,leftstick:b12,lefttrigger:b11,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b13,righttrigger:b14,start:b15,x:b2,y:b3,platform:Linux,
+19000000010000000200000011000000,odroidgo2_joypad_v11,a:b1,b:b0,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b12,leftshoulder:b4,leftstick:b14,lefttrigger:b13,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b15,righttrigger:b16,start:b17,x:b2,y:b3,platform:Linux,
030000005e0400000202000000010000,Old Xbox pad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b4,platform:Linux,
05000000362800000100000002010000,OUYA Game Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,x:b1,y:b2,platform:Linux,
05000000362800000100000003010000,OUYA Game Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,x:b1,y:b2,platform:Linux,
03000000830500005020000010010000,Padix Co. Ltd. Rockfire PSX/USB Bridge,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b2,y:b3,platform:Linux,
+03000000790000001c18000011010000,PC Game Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
03000000ff1100003133000010010000,PC Game Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
+030000006f0e0000b802000001010000,PDP AFTERGLOW Wired Xbox One Controller,a:b0,b:b1,x:b2,y:b3,back:b6,guide:b8,start:b7,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Linux,
030000006f0e00006401000001010000,PDP Battlefield One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+030000006f0e00008001000011010000,PDP CO. LTD. Faceoff Wired Pro Controller for Nintendo Switch,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Linux,
030000006f0e00003101000000010000,PDP EA Sports Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000006f0e0000c802000012010000,PDP Kingdom Hearts Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+030000006f0e00008701000011010000,PDP Rock Candy Wired Controller for Nintendo Switch,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b13,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
+030000006f0e00000901000011010000,PDP Versus Fighting Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,
030000006f0e0000a802000023020000,PDP Wired Controller for Xbox One,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
+030000006f0e00008501000011010000,PDP Wired Fight Pad Pro for Nintendo Switch,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
+0500000049190000030400001b010000,PG-9099,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
030000004c050000da0c000011010000,Playstation Controller,a:b2,b:b1,back:b8,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Linux,
03000000c62400000053000000010000,PowerA,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
03000000c62400003a54000001010000,PowerA 1428124-01,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
03000000d62000006dca000011010000,PowerA Pro Ex,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
+03000000c62400001a58000001010000,PowerA Xbox One Cabled,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Linux,
030000006d040000d2ca000011010000,Precision Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
03000000ff1100004133000010010000,PS2 Controller,a:b2,b:b1,back:b8,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Linux,
03000000341a00003608000011010000,PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
@@ -640,18 +705,21 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000c01100000140000011010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
050000004c050000c405000000010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
050000004c050000c405000000810000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,
+050000004c050000c405000001800000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,
050000004c050000cc09000000010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
050000004c050000cc09000000810000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,
050000004c050000cc09000001800000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,
03000000300f00001211000011010000,QanBa Arcade JoyStick,a:b2,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b5,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b6,start:b9,x:b1,y:b3,platform:Linux,
030000009b2800003200000001010000,Raphnet Technologies GC/N64 to USB v3.4,a:b0,b:b7,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,rightx:a3,righty:a4,start:b3,x:b1,y:b8,platform:Linux,
+030000009b2800006000000001010000,Raphnet Technologies GC/N64 to USB v3.6,a:b0,b:b7,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,rightx:a3,righty:a4,start:b3,x:b1,y:b8,platform:Linux,
030000009b2800000300000001010000,raphnet.net 4nes4snes v1.5,a:b0,b:b4,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b1,y:b5,platform:Linux,
030000008916000001fd000024010000,Razer Onza Classic Edition,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
-030000008916000000fd000024010000,Razer Onza Tournament Edition,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+030000008916000000fd000024010000,Razer Onza Tournament Edition,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
03000000321500000204000011010000,Razer Panthera (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
03000000321500000104000011010000,Razer Panthera (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
03000000321500000010000011010000,Razer RAIJU,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
03000000321500000507000000010000,Razer Raiju Mobile,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b21,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
+03000000321500000011000011010000,Razer Raion Fightpad for PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
030000008916000000fe000024010000,Razer Sabertooth,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
03000000c6240000045d000024010000,Razer Sabertooth,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
03000000c6240000045d000025010000,Razer Sabertooth,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
@@ -662,11 +730,11 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
0300000081170000990a000001010000,Retronic Adapter,a:b0,leftx:a0,lefty:a1,platform:Linux,
0300000000f000000300000000010000,RetroPad,a:b1,b:b5,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b0,y:b4,platform:Linux,
030000006b140000010d000011010000,Revolution Pro Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
+030000006b140000130d000011010000,Revolution Pro Controller 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
030000006f0e00001f01000000010000,Rock Candy,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000006f0e00001e01000011010000,Rock Candy PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
030000006f0e00004601000001010000,Rock Candy Xbox One Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
03000000a306000023f6000011010000,Saitek Cyborg V.1 Game Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Linux,
-03000000a30600001005000000010000,Saitek Saitek P150,platform:Linux,a:b0,b:b1,y:b4,x:b3,leftshoulder:b7,rightshoulder:b2,dpup:-a1,dpleft:-a0,dpdown:+a1,dpright:+a0,lefttrigger:b6,righttrigger:b5,
03000000a30600000cff000010010000,Saitek P2500 Force Rumble Pad,a:b2,b:b3,back:b11,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,x:b0,y:b1,platform:Linux,
03000000a30600000c04000011010000,Saitek P2900 Wireless Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b12,x:b0,y:b3,platform:Linux,
03000000300f00001201000010010000,Saitek P380,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Linux,
@@ -674,6 +742,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000a30600000b04000000010000,Saitek P990 Dual Analog Pad,a:b1,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b8,x:b0,y:b3,platform:Linux,
03000000a306000018f5000010010000,Saitek PLC Saitek P3200 Rumble Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Linux,
03000000a306000020f6000011010000,Saitek PS2700 Rumble Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Linux,
+03000000a30600001005000000010000,Saitek Saitek P150,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b7,lefttrigger:b6,rightshoulder:b2,righttrigger:b5,x:b3,y:b4,platform:Linux,
03000000d81d00000e00000010010000,Savior,a:b0,b:b1,back:b8,leftshoulder:b6,leftstick:b10,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b11,righttrigger:b3,start:b9,x:b4,y:b5,platform:Linux,
03000000c01600008704000011010000,Serial/Keyboard/Mouse/Joystick,a:b12,b:b10,back:b4,dpdown:b2,dpleft:b3,dpright:b1,dpup:b0,leftshoulder:b9,leftstick:b14,lefttrigger:b6,leftx:a1,lefty:a0,rightshoulder:b8,rightstick:b15,righttrigger:b7,rightx:a2,righty:a3,start:b5,x:b13,y:b11,platform:Linux,
03000000f025000021c1000010010000,ShanWan Gioteck PS3 Wired Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
@@ -687,7 +756,9 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000d11800000094000011010000,Stadia Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Linux,
03000000de2800000112000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux,
03000000de2800000211000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux,
+03000000de2800000211000011010000,Steam Controller,a:b2,b:b3,back:b10,dpdown:b18,dpleft:b19,dpright:b20,dpup:b17,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b5,platform:Linux,
03000000de2800004211000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux,
+03000000de2800004211000011010000,Steam Controller,a:b2,b:b3,back:b10,dpdown:b18,dpleft:b19,dpright:b20,dpup:b17,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b5,platform:Linux,
03000000de280000fc11000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
05000000de2800000212000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux,
05000000de2800000511000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux,
@@ -695,9 +766,10 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000de280000ff11000001000000,Steam Virtual Gamepad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
03000000381000003014000075010000,SteelSeries Stratus Duo,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
03000000381000003114000075010000,SteelSeries Stratus Duo,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+0500000011010000311400001b010000,SteelSeries Stratus Duo,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b32,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
05000000110100001914000009010000,SteelSeries Stratus XL,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
03000000ad1b000038f0000090040000,Street Fighter IV FightStick TE,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
-030000003b07000004a1000000010000,Suncom SFX Plus for USB,a:b0,b:b2,x:b1,y:b3,back:b7,start:b8,leftshoulder:b6,rightshoulder:b9,leftx:a0,lefty:a1,lefttrigger:b4,righttrigger:b5,platform:Linux,
+030000003b07000004a1000000010000,Suncom SFX Plus for USB,a:b0,b:b2,back:b7,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b9,righttrigger:b5,start:b8,x:b1,y:b3,platform:Linux,
03000000666600000488000000010000,Super Joy Box 5 Pro,a:b2,b:b1,back:b9,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Linux,
0300000000f00000f100000000010000,Super RetroPort,a:b1,b:b5,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b0,y:b4,platform:Linux,
03000000457500002211000010010000,SZMY-POWER CO. LTD. GAMEPAD,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
@@ -705,7 +777,8 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
030000004f04000020b3000010010000,Thrustmaster 2 in 1 DT,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Linux,
030000004f04000015b3000010010000,Thrustmaster Dual Analog 4,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Linux,
030000004f04000023b3000000010000,Thrustmaster Dual Trigger 3-in-1,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
-03000000b50700000399000000010000,Thrustmaster Firestorm Digital 2,a:b2,b:b4,x:b3,y:b5,back:b11,start:b1,leftstick:b10,rightstick:b0,leftshoulder:b6,rightshoulder:b8,leftx:a0,lefty:a1,lefttrigger:b7,righttrigger:b9,platform:Linux,
+030000004f0400000ed0000011010000,ThrustMaster eSwap PRO Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
+03000000b50700000399000000010000,Thrustmaster Firestorm Digital 2,a:b2,b:b4,back:b11,leftshoulder:b6,leftstick:b10,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b8,rightstick:b0,righttrigger:b9,start:b1,x:b3,y:b5,platform:Linux,
030000004f04000000b3000010010000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b11,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b10,x:b1,y:b3,platform:Linux,
030000004f04000026b3000002040000,Thrustmaster Gamepad GP XID,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
03000000c6240000025b000002020000,Thrustmaster GPX Gamepad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
@@ -722,8 +795,10 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000790000000600000007010000,USB gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b3,y:b0,platform:Linux,
03000000790000001100000000010000,USB Gamepad1,a:b2,b:b1,back:b8,dpdown:a0,dpleft:a1,dpright:a2,dpup:a4,start:b9,platform:Linux,
030000006f0e00000302000011010000,Victrix Pro Fight Stick for PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,
+030000006f0e00000702000011010000,Victrix Pro Fight Stick for PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,
05000000ac0500003232000001000000,VR-BOX,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b2,y:b3,platform:Linux,
03000000791d00000103000010010000,Wii Classic Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
+050000000d0f0000f600000001000000,Wireless HORIPAD Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
030000005e0400008e02000010010000,X360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000005e0400008e02000014010000,X360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000005e0400001907000000010000,X360 Wireless Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
@@ -735,44 +810,70 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
0000000058626f782047616d65706100,Xbox Gamepad (userspace driver),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Linux,
030000005e040000d102000002010000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
050000005e040000fd02000030110000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+050000005e040000050b000002090000,Xbox One Elite Series 2,a:b0,b:b1,back:b136,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a6,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
030000005e040000ea02000000000000,Xbox One Wireless Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
050000005e040000e002000003090000,Xbox One Wireless Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
050000005e040000fd02000003090000,Xbox One Wireless Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b16,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
030000005e040000ea02000001030000,Xbox One Wireless Controller (Model 1708),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+030000005e0400008e02000000010000,xbox360 Wireless EasySMX,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
03000000450c00002043000010010000,XEOX Gamepad SL-6556-BK,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
03000000ac0500005b05000010010000,Xiaoji Gamesir-G3w,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
05000000172700004431000029010000,XiaoMi Game Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b20,leftshoulder:b6,leftstick:b13,lefttrigger:a7,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a6,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Linux,
03000000c0160000e105000001010000,Xin-Mo Xin-Mo Dual Arcade,a:b4,b:b3,back:b6,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b9,leftshoulder:b2,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b1,y:b0,platform:Linux,
xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
03000000120c0000100e000011010000,ZEROPLUS P4 Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
-030000005e0400008e02000000010000,xbox360 Wireless EasySMX,a:b0,b:b1,x:b2,y:b3,back:b6,guide:b8,start:b7,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Linux,
-030000009b2800006000000001010000,Raphnet Technologies GC/N64 to USB v3.6,a:b0,b:b7,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,rightx:a3,righty:a4,start:b3,x:b1,y:b8,platform:Linux,
+03000000120c0000101e000011010000,ZEROPLUS P4 Wired Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
# Android
+05000000c82d000006500000ffff3f00,8BitDo M30 Gamepad,a:b1,b:b0,back:b4,guide:b17,leftshoulder:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:a4,start:b6,x:b3,y:b2,platform:Android,
+05000000c82d000051060000ffff3f00,8BitDo M30 Gamepad,a:b1,b:b0,back:b4,guide:b17,leftshoulder:b9,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:a5,start:b6,x:b3,y:b2,platform:Android,
+05000000c82d000015900000ffff3f00,8BitDo N30 Pro 2,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
+05000000c82d000065280000ffff3f00,8BitDo N30 Pro 2,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b17,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
+050000000220000000900000ffff3f00,8BitDo NES30 Pro,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
+050000002038000009000000ffff3f00,8BitDo NES30 Pro,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
+05000000c82d000000600000ffff3f00,8BitDo SF30 Pro,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:b15,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b16,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
+05000000c82d000000610000ffff3f00,8BitDo SF30 Pro,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
+05000000c82d000012900000ffff3f00,8BitDo SN30 Gamepad,a:b1,b:b0,back:b4,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,start:b6,x:b3,y:b2,platform:Android,
+05000000c82d000062280000ffff3f00,8BitDo SN30 Gamepad,a:b1,b:b0,back:b4,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,start:b6,x:b3,y:b2,platform:Android,
+05000000c82d000001600000ffff3f00,8BitDo SN30 Pro,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
+05000000c82d000002600000ffff0f00,8BitDo SN30 Pro+,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b17,leftshoulder:b9,leftstick:b7,lefttrigger:b15,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b16,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
+050000002028000009000000ffff3f00,8BitDo SNES30 Gamepad,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
+050000003512000020ab000000780f00,8BitDo SNES30 Gamepad,a:b21,b:b20,back:b30,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b26,rightshoulder:b27,start:b31,x:b24,y:b23,platform:Android,
+05000000c82d000018900000ffff0f00,8BitDo Zero 2,a:b1,b:b0,back:b4,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,start:b6,x:b3,y:b2,platform:Android,
+05000000c82d000030320000ffff0f00,8BitDo Zero 2,a:b1,b:b0,back:b4,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,start:b6,x:b3,y:b2,platform:Android,
05000000bc20000000550000ffff3f00,GameSir G3w,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
05000000d6020000e5890000dfff3f00,GPD XD Plus,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a5,start:b6,x:b2,y:b3,platform:Android,
+0500000031366332860c44aadfff0f00,GS Gamepad,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:b15,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b16,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+0500000083050000602000000ffe0000,iBuffalo SNES Controller,a:b1,b:b0,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b15,rightshoulder:b16,start:b10,x:b3,y:b2,platform:Android,
64633436313965656664373634323364,Microsoft X-Box 360 pad,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,x:b2,y:b3,platform:Android,
+7573622067616d657061642020202020,NEXT SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b6,start:b9,x:b3,y:b0,platform:Android,
050000007e05000009200000ffff0f00,Nintendo Switch Pro Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b3,leftstick:b4,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b16,x:b17,y:b2,platform:Android,
37336435666338653565313731303834,NVIDIA Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
4e564944494120436f72706f72617469,NVIDIA Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
61363931656135336130663561616264,NVIDIA Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
050000005509000003720000cf7f3f00,NVIDIA Controller v01.01,a:b0,b:b1,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
050000005509000010720000ffff3f00,NVIDIA Controller v01.03,a:b0,b:b1,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+050000005509000014720000df7f3f00,NVIDIA Controller v01.04,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a5,start:b6,x:b2,y:b3,platform:Android,
050000004c05000068020000dfff3f00,PS3 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+030000004c050000cc09000000006800,PS4 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
050000004c050000c4050000fffe3f00,PS4 Controller,a:b1,b:b17,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b3,leftstick:b4,lefttrigger:+a3,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:+a4,rightx:a2,righty:a5,start:b16,x:b0,y:b2,platform:Android,
050000004c050000cc090000fffe3f00,PS4 Controller,a:b1,b:b17,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b3,leftstick:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:a4,rightx:a2,righty:a5,start:b16,x:b0,y:b2,platform:Android,
+050000004c050000cc090000ffff3f00,PS4 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
35643031303033326130316330353564,PS4 Controller,a:b1,b:b17,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b3,leftstick:b4,lefttrigger:+a3,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:+a4,rightx:a2,righty:a5,start:b16,x:b0,y:b2,platform:Android,
+62653861643333663663383332396665,Razer Kishi,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
050000003215000005070000ffff3f00,Razer Raiju Mobile,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
050000003215000007070000ffff3f00,Razer Raiju Mobile,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
050000003215000000090000bf7f3f00,Razer Serval,a:b0,b:b1,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,x:b2,y:b3,platform:Android,
05000000de2800000511000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Android,
05000000de2800000611000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Android,
+050000004f0400000ed00000fffe3f00,ThrustMaster eSwap PRO Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
5477696e20555342204a6f7973746963,Twin USB Joystick,a:b22,b:b21,back:b28,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b26,leftstick:b30,lefttrigger:b24,leftx:a0,lefty:a1,rightshoulder:b27,rightstick:b31,righttrigger:b25,rightx:a3,righty:a2,start:b29,x:b23,y:b20,platform:Android,
+30306539356238653637313730656134,Wireless HORIPAD Switch Pro Controller,a:b0,b:b1,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b19,y:b2,platform:Android,
050000005e040000e00200000ffe3f00,Xbox One Wireless Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b15,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b16,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b17,y:b2,platform:Android,
050000005e040000fd020000ffff3f00,Xbox One Wireless Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
050000005e04000091020000ff073f00,Xbox Wireless Controller,a:b0,b:b1,back:b4,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Android,
34356136633366613530316338376136,Xbox Wireless Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b3,leftstick:b15,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b16,righttrigger:a5,rightx:a3,righty:a4,x:b17,y:b2,platform:Android,
-7573622067616d657061642020202020,NEXT SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b6,start:b9,x:b3,y:b0,platform:Android,
+050000001727000044310000ffff3f00,XiaoMi Game Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a7,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a6,rightx:a2,righty:a5,start:b6,x:b2,y:b3,platform:Android,
# iOS
05000000ac0500000100000000006d01,*,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,leftshoulder:b4,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a5,rightx:a3,righty:a4,x:b2,y:b3,platform:iOS,
diff --git a/core/input/input.cpp b/core/input/input.cpp
index 4d152c1ac4..00a7e63a73 100644
--- a/core/input/input.cpp
+++ b/core/input/input.cpp
@@ -30,16 +30,16 @@
#include "input.h"
+#include "core/config/project_settings.h"
#include "core/input/default_controller_mappings.h"
#include "core/input/input_map.h"
#include "core/os/os.h"
-#include "core/project_settings.h"
#ifdef TOOLS_ENABLED
#include "editor/editor_settings.h"
#endif
-static const char *_joy_buttons[JOY_SDL_BUTTONS + 1] = {
+static const char *_joy_buttons[JOY_BUTTON_SDL_MAX] = {
"a",
"b",
"x",
@@ -55,69 +55,15 @@ static const char *_joy_buttons[JOY_SDL_BUTTONS + 1] = {
"dpdown",
"dpleft",
"dpright",
- nullptr
};
-static const char *_joy_button_names[JOY_BUTTON_MAX] = {
- "Face Bottom",
- "Face Right",
- "Face Left",
- "Face Top",
- "Select",
- "Guide",
- "Start",
- "Left Stick",
- "Right Stick",
- "Left Shoulder",
- "Right Shoulder",
- "D-Pad Up",
- "D-Pad Down",
- "D-Pad Left",
- "D-Pad Right",
- "Button 15",
- "Button 16",
- "Button 17",
- "Button 18",
- "Button 19",
- "Button 20",
- "Button 21",
- "Button 22",
- "Button 23",
- "Button 24",
- "Button 25",
- "Button 26",
- "Button 27",
- "Button 28",
- "Button 29",
- "Button 30",
- "Button 31",
- "Button 32",
- "Button 33",
- "Button 34",
- "Button 35"
-};
-
-static const char *_joy_axes[JOY_SDL_AXES + 1] = {
+static const char *_joy_axes[JOY_AXIS_SDL_MAX] = {
"leftx",
"lefty",
"rightx",
"righty",
"lefttrigger",
"righttrigger",
- nullptr
-};
-
-static const char *_joy_axis_names[JOY_AXIS_MAX] = {
- "Left Stick X",
- "Left Stick Y",
- "Right Stick X",
- "Right Stick Y",
- "Left Trigger",
- "Right Trigger",
- "Joystick 3 Stick X",
- "Joystick 3 Stick Y",
- "Joystick 4 Stick X",
- "Joystick 4 Stick Y"
};
Input *Input::singleton = nullptr;
@@ -149,6 +95,9 @@ void Input::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_action_just_pressed", "action"), &Input::is_action_just_pressed);
ClassDB::bind_method(D_METHOD("is_action_just_released", "action"), &Input::is_action_just_released);
ClassDB::bind_method(D_METHOD("get_action_strength", "action"), &Input::get_action_strength);
+ ClassDB::bind_method(D_METHOD("get_action_raw_strength", "action"), &Input::get_action_strength);
+ ClassDB::bind_method(D_METHOD("get_axis", "negative_action", "positive_action"), &Input::get_axis);
+ ClassDB::bind_method(D_METHOD("get_vector", "negative_x", "positive_x", "negative_y", "positive_y", "deadzone"), &Input::get_vector, DEFVAL(-1.0f));
ClassDB::bind_method(D_METHOD("add_joy_mapping", "mapping", "update_existing"), &Input::add_joy_mapping, DEFVAL(false));
ClassDB::bind_method(D_METHOD("remove_joy_mapping", "guid"), &Input::remove_joy_mapping);
ClassDB::bind_method(D_METHOD("joy_connection_changed", "device", "connected", "name", "guid"), &Input::joy_connection_changed);
@@ -159,10 +108,6 @@ void Input::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_connected_joypads"), &Input::get_connected_joypads);
ClassDB::bind_method(D_METHOD("get_joy_vibration_strength", "device"), &Input::get_joy_vibration_strength);
ClassDB::bind_method(D_METHOD("get_joy_vibration_duration", "device"), &Input::get_joy_vibration_duration);
- ClassDB::bind_method(D_METHOD("get_joy_button_string", "button_index"), &Input::get_joy_button_string);
- ClassDB::bind_method(D_METHOD("get_joy_button_index_from_string", "button"), &Input::get_joy_button_index_from_string);
- ClassDB::bind_method(D_METHOD("get_joy_axis_string", "axis_index"), &Input::get_joy_axis_string);
- ClassDB::bind_method(D_METHOD("get_joy_axis_index_from_string", "axis"), &Input::get_joy_axis_index_from_string);
ClassDB::bind_method(D_METHOD("start_joy_vibration", "device", "weak_magnitude", "strong_magnitude", "duration"), &Input::start_joy_vibration, DEFVAL(0));
ClassDB::bind_method(D_METHOD("stop_joy_vibration", "device"), &Input::stop_joy_vibration);
ClassDB::bind_method(D_METHOD("vibrate_handheld", "duration_ms"), &Input::vibrate_handheld, DEFVAL(500));
@@ -215,7 +160,9 @@ void Input::get_argument_options(const StringName &p_function, int p_idx, List<S
const String quote_style = EDITOR_DEF("text_editor/completion/use_single_quotes", 0) ? "'" : "\"";
String pf = p_function;
- if (p_idx == 0 && (pf == "is_action_pressed" || pf == "action_press" || pf == "action_release" || pf == "is_action_just_pressed" || pf == "is_action_just_released" || pf == "get_action_strength")) {
+ if (p_idx == 0 && (pf == "is_action_pressed" || pf == "action_press" || pf == "action_release" ||
+ pf == "is_action_just_pressed" || pf == "is_action_just_released" ||
+ pf == "get_action_strength" || pf == "get_axis" || pf == "get_vector")) {
List<PropertyInfo> pinfo;
ProjectSettings::get_singleton()->get_property_list(&pinfo);
@@ -326,6 +273,46 @@ float Input::get_action_strength(const StringName &p_action) const {
return E->get().strength;
}
+float Input::get_action_raw_strength(const StringName &p_action) const {
+ const Map<StringName, Action>::Element *E = action_state.find(p_action);
+ if (!E) {
+ return 0.0f;
+ }
+
+ return E->get().raw_strength;
+}
+
+float Input::get_axis(const StringName &p_negative_action, const StringName &p_positive_action) const {
+ return get_action_strength(p_positive_action) - get_action_strength(p_negative_action);
+}
+
+Vector2 Input::get_vector(const StringName &p_negative_x, const StringName &p_positive_x, const StringName &p_negative_y, const StringName &p_positive_y, float p_deadzone) const {
+ Vector2 vector = Vector2(
+ get_action_raw_strength(p_positive_x) - get_action_raw_strength(p_negative_x),
+ get_action_raw_strength(p_positive_y) - get_action_raw_strength(p_negative_y));
+
+ if (p_deadzone < 0.0f) {
+ // If the deadzone isn't specified, get it from the average of the actions.
+ p_deadzone = (InputMap::get_singleton()->action_get_deadzone(p_positive_x) +
+ InputMap::get_singleton()->action_get_deadzone(p_negative_x) +
+ InputMap::get_singleton()->action_get_deadzone(p_positive_y) +
+ InputMap::get_singleton()->action_get_deadzone(p_negative_y)) /
+ 4;
+ }
+
+ // Circular length limiting and deadzone.
+ float length = vector.length();
+ if (length <= p_deadzone) {
+ return Vector2();
+ } else if (length > 1.0f) {
+ return vector / length;
+ } else {
+ // Inverse lerp length to map (p_deadzone, 1) to (0, 1).
+ return vector * (Math::inverse_lerp(p_deadzone, 1.0f, length) / length);
+ }
+ return vector;
+}
+
float Input::get_joy_axis(int p_device, int p_axis) const {
_THREAD_SAFE_METHOD_
int c = _combine_device(p_axis, p_device);
@@ -603,10 +590,12 @@ void Input::_parse_input_event_impl(const Ref<InputEvent> &p_event, bool p_is_em
action.physics_frame = Engine::get_singleton()->get_physics_frames();
action.idle_frame = Engine::get_singleton()->get_idle_frames();
action.pressed = p_event->is_action_pressed(E->key());
- action.strength = 0.f;
+ action.strength = 0.0f;
+ action.raw_strength = 0.0f;
action_state[E->key()] = action;
}
action_state[E->key()].strength = p_event->get_action_strength(E->key());
+ action_state[E->key()].raw_strength = p_event->get_action_raw_strength(E->key());
}
}
@@ -874,7 +863,7 @@ void Input::joy_button(int p_device, int p_button, bool p_pressed) {
}
if (map.type == TYPE_AXIS) {
- _axis_event(p_device, map.index, p_pressed ? 1.0 : 0.0);
+ _axis_event(p_device, map.index, p_pressed ? map.value : 0.0);
}
// no event?
}
@@ -890,14 +879,6 @@ void Input::joy_axis(int p_device, int p_axis, const JoyAxis &p_value) {
return;
}
- if (p_value.value > joy.last_axis[p_axis]) {
- if (p_value.value < joy.last_axis[p_axis] + joy.filter) {
- return;
- }
- } else if (p_value.value > joy.last_axis[p_axis] - joy.filter) {
- return;
- }
-
//when changing direction quickly, insert fake event to release pending inputmap actions
float last = joy.last_axis[p_axis];
if (p_value.min == 0 && (last < 0.25 || last > 0.75) && (last - 0.5) * (p_value.value - 0.5) < 0) {
@@ -920,55 +901,42 @@ void Input::joy_axis(int p_device, int p_axis, const JoyAxis &p_value) {
return;
}
- JoyEvent map = _get_mapped_axis_event(map_db[joy.mapping], p_axis, p_value);
+ JoyEvent map = _get_mapped_axis_event(map_db[joy.mapping], p_axis, val);
if (map.type == TYPE_BUTTON) {
- if (map.index == JOY_BUTTON_DPAD_UP || map.index == JOY_BUTTON_DPAD_DOWN) {
- bool pressed = p_value.value != 0.0f;
- int button = p_value.value < 0 ? JOY_BUTTON_DPAD_UP : JOY_BUTTON_DPAD_DOWN;
+ bool pressed = map.value > 0.5;
+ if (pressed == joy_buttons_pressed.has(_combine_device(map.index, p_device))) {
+ // Button already pressed or released; so ignore.
+ return;
+ }
+ _button_event(p_device, map.index, pressed);
- if (!pressed) {
- if (joy_buttons_pressed.has(_combine_device(JOY_BUTTON_DPAD_UP, p_device))) {
- _button_event(p_device, JOY_BUTTON_DPAD_UP, false);
- }
+ // Ensure opposite D-Pad button is also released.
+ switch (map.index) {
+ case JOY_BUTTON_DPAD_UP:
if (joy_buttons_pressed.has(_combine_device(JOY_BUTTON_DPAD_DOWN, p_device))) {
_button_event(p_device, JOY_BUTTON_DPAD_DOWN, false);
}
- }
- if (pressed == joy_buttons_pressed.has(_combine_device(button, p_device))) {
- return;
- }
- _button_event(p_device, button, true);
- return;
- }
-
- if (map.index == JOY_BUTTON_DPAD_LEFT || map.index == JOY_BUTTON_DPAD_RIGHT) {
- bool pressed = p_value.value != 0.0f;
- int button = p_value.value < 0 ? JOY_BUTTON_DPAD_LEFT : JOY_BUTTON_DPAD_RIGHT;
-
- if (!pressed) {
- if (joy_buttons_pressed.has(_combine_device(JOY_BUTTON_DPAD_LEFT, p_device))) {
- _button_event(p_device, JOY_BUTTON_DPAD_LEFT, false);
+ break;
+ case JOY_BUTTON_DPAD_DOWN:
+ if (joy_buttons_pressed.has(_combine_device(JOY_BUTTON_DPAD_UP, p_device))) {
+ _button_event(p_device, JOY_BUTTON_DPAD_UP, false);
}
+ break;
+ case JOY_BUTTON_DPAD_LEFT:
if (joy_buttons_pressed.has(_combine_device(JOY_BUTTON_DPAD_RIGHT, p_device))) {
_button_event(p_device, JOY_BUTTON_DPAD_RIGHT, false);
}
- }
- if (pressed == joy_buttons_pressed.has(_combine_device(button, p_device))) {
- return;
- }
- _button_event(p_device, button, true);
- return;
- }
-
- float deadzone = p_value.min == 0 ? 0.5f : 0.0f;
- bool pressed = p_value.value > deadzone;
- if (pressed == joy_buttons_pressed.has(_combine_device(map.index, p_device))) {
- // button already pressed or released, this is an axis bounce value
- return;
+ break;
+ case JOY_BUTTON_DPAD_RIGHT:
+ if (joy_buttons_pressed.has(_combine_device(JOY_BUTTON_DPAD_LEFT, p_device))) {
+ _button_event(p_device, JOY_BUTTON_DPAD_LEFT, false);
+ }
+ break;
+ default:
+ // Nothing to do.
+ break;
}
-
- _button_event(p_device, map.index, pressed);
return;
}
@@ -1007,18 +975,15 @@ void Input::joy_hat(int p_device, int p_val) {
int cur_val = joy_names[p_device].hat_current;
- if ((p_val & HAT_MASK_UP) != (cur_val & HAT_MASK_UP)) {
- _button_event(p_device, map[HAT_UP].index, p_val & HAT_MASK_UP);
- }
-
- if ((p_val & HAT_MASK_RIGHT) != (cur_val & HAT_MASK_RIGHT)) {
- _button_event(p_device, map[HAT_RIGHT].index, p_val & HAT_MASK_RIGHT);
- }
- if ((p_val & HAT_MASK_DOWN) != (cur_val & HAT_MASK_DOWN)) {
- _button_event(p_device, map[HAT_DOWN].index, p_val & HAT_MASK_DOWN);
- }
- if ((p_val & HAT_MASK_LEFT) != (cur_val & HAT_MASK_LEFT)) {
- _button_event(p_device, map[HAT_LEFT].index, p_val & HAT_MASK_LEFT);
+ for (int hat_direction = 0, hat_mask = 1; hat_direction < HAT_MAX; hat_direction++, hat_mask <<= 1) {
+ if ((p_val & hat_mask) != (cur_val & hat_mask)) {
+ if (map[hat_direction].type == TYPE_BUTTON) {
+ _button_event(p_device, map[hat_direction].index, p_val & hat_mask);
+ }
+ if (map[hat_direction].type == TYPE_AXIS) {
+ _axis_event(p_device, map[hat_direction].index, (p_val & hat_mask) ? map[hat_direction].value : 0.0);
+ }
+ }
}
joy_names[p_device].hat_current = p_val;
@@ -1058,6 +1023,19 @@ Input::JoyEvent Input::_get_mapped_button_event(const JoyDeviceMapping &mapping,
return event;
case TYPE_AXIS:
event.index = binding.output.axis.axis;
+ switch (binding.output.axis.range) {
+ case POSITIVE_HALF_AXIS:
+ event.value = 1;
+ break;
+ case NEGATIVE_HALF_AXIS:
+ event.value = -1;
+ break;
+ case FULL_AXIS:
+ // It doesn't make sense for a button to map to a full axis,
+ // but keeping as a default for a trigger with a positive half-axis.
+ event.value = 1;
+ break;
+ }
return event;
default:
ERR_PRINT_ONCE("Joypad button mapping error.");
@@ -1067,14 +1045,14 @@ Input::JoyEvent Input::_get_mapped_button_event(const JoyDeviceMapping &mapping,
return event;
}
-Input::JoyEvent Input::_get_mapped_axis_event(const JoyDeviceMapping &mapping, int p_axis, const JoyAxis &p_value) {
+Input::JoyEvent Input::_get_mapped_axis_event(const JoyDeviceMapping &mapping, int p_axis, float p_value) {
JoyEvent event;
event.type = TYPE_MAX;
for (int i = 0; i < mapping.bindings.size(); i++) {
const JoyBinding binding = mapping.bindings[i];
if (binding.inputType == TYPE_AXIS && binding.input.axis.axis == p_axis) {
- float value = p_value.value;
+ float value = p_value;
if (binding.input.axis.invert) {
value = -value;
}
@@ -1082,26 +1060,40 @@ Input::JoyEvent Input::_get_mapped_axis_event(const JoyDeviceMapping &mapping, i
(binding.input.axis.range == POSITIVE_HALF_AXIS && value > 0) ||
(binding.input.axis.range == NEGATIVE_HALF_AXIS && value < 0)) {
event.type = binding.outputType;
+ float shifted_positive_value = 0;
+ switch (binding.input.axis.range) {
+ case POSITIVE_HALF_AXIS:
+ shifted_positive_value = value;
+ break;
+ case NEGATIVE_HALF_AXIS:
+ shifted_positive_value = value + 1;
+ break;
+ case FULL_AXIS:
+ shifted_positive_value = (value + 1) / 2;
+ break;
+ }
switch (binding.outputType) {
case TYPE_BUTTON:
event.index = binding.output.button;
+ switch (binding.input.axis.range) {
+ case POSITIVE_HALF_AXIS:
+ event.value = shifted_positive_value;
+ break;
+ case NEGATIVE_HALF_AXIS:
+ event.value = 1 - shifted_positive_value;
+ break;
+ case FULL_AXIS:
+ // It doesn't make sense for a full axis to map to a button,
+ // but keeping as a default for a trigger with a positive half-axis.
+ event.value = (shifted_positive_value * 2) - 1;
+ ;
+ break;
+ }
return event;
case TYPE_AXIS:
event.index = binding.output.axis.axis;
event.value = value;
if (binding.output.axis.range != binding.input.axis.range) {
- float shifted_positive_value = 0;
- switch (binding.input.axis.range) {
- case POSITIVE_HALF_AXIS:
- shifted_positive_value = value;
- break;
- case NEGATIVE_HALF_AXIS:
- shifted_positive_value = value + 1;
- break;
- case FULL_AXIS:
- shifted_positive_value = (value + 1) / 2;
- break;
- }
switch (binding.output.axis.range) {
case POSITIVE_HALF_AXIS:
event.value = shifted_positive_value;
@@ -1128,32 +1120,45 @@ void Input::_get_mapped_hat_events(const JoyDeviceMapping &mapping, int p_hat, J
for (int i = 0; i < mapping.bindings.size(); i++) {
const JoyBinding binding = mapping.bindings[i];
if (binding.inputType == TYPE_HAT && binding.input.hat.hat == p_hat) {
- int index;
+ int hat_direction;
switch (binding.input.hat.hat_mask) {
case HAT_MASK_UP:
- index = 0;
+ hat_direction = HAT_UP;
break;
case HAT_MASK_RIGHT:
- index = 1;
+ hat_direction = HAT_RIGHT;
break;
case HAT_MASK_DOWN:
- index = 2;
+ hat_direction = HAT_DOWN;
break;
case HAT_MASK_LEFT:
- index = 3;
+ hat_direction = HAT_LEFT;
break;
default:
ERR_PRINT_ONCE("Joypad button mapping error.");
continue;
}
- r_events[index].type = binding.outputType;
+ r_events[hat_direction].type = binding.outputType;
switch (binding.outputType) {
case TYPE_BUTTON:
- r_events[index].index = binding.output.button;
+ r_events[hat_direction].index = binding.output.button;
break;
case TYPE_AXIS:
- r_events[index].index = binding.output.axis.axis;
+ r_events[hat_direction].index = binding.output.axis.axis;
+ switch (binding.output.axis.range) {
+ case POSITIVE_HALF_AXIS:
+ r_events[hat_direction].value = 1;
+ break;
+ case NEGATIVE_HALF_AXIS:
+ r_events[hat_direction].value = -1;
+ break;
+ case FULL_AXIS:
+ // It doesn't make sense for a hat direction to map to a full axis,
+ // but keeping as a default for a trigger with a positive half-axis.
+ r_events[hat_direction].value = 1;
+ break;
+ }
break;
default:
ERR_PRINT_ONCE("Joypad button mapping error.");
@@ -1163,21 +1168,21 @@ void Input::_get_mapped_hat_events(const JoyDeviceMapping &mapping, int p_hat, J
}
JoyButtonList Input::_get_output_button(String output) {
- for (int i = 0; _joy_buttons[i]; i++) {
+ for (int i = 0; i < JOY_BUTTON_SDL_MAX; i++) {
if (output == _joy_buttons[i]) {
return JoyButtonList(i);
}
}
- return JoyButtonList::JOY_INVALID_BUTTON;
+ return JoyButtonList::JOY_BUTTON_INVALID;
}
JoyAxisList Input::_get_output_axis(String output) {
- for (int i = 0; _joy_axes[i]; i++) {
+ for (int i = 0; i < JOY_AXIS_SDL_MAX; i++) {
if (output == _joy_axes[i]) {
return JoyAxisList(i);
}
}
- return JoyAxisList::JOY_INVALID_AXIS;
+ return JoyAxisList::JOY_AXIS_INVALID;
}
void Input::parse_mapping(String p_mapping) {
@@ -1213,12 +1218,12 @@ void Input::parse_mapping(String p_mapping) {
JoyAxisRange output_range = FULL_AXIS;
if (output[0] == '+' || output[0] == '-') {
ERR_CONTINUE_MSG(output.length() < 2, String(entry[idx] + "\nInvalid output: " + entry[idx]));
- output = output.right(1);
if (output[0] == '+') {
output_range = POSITIVE_HALF_AXIS;
} else if (output[0] == '-') {
output_range = NEGATIVE_HALF_AXIS;
}
+ output = output.right(1);
}
JoyAxisRange input_range = FULL_AXIS;
@@ -1232,20 +1237,21 @@ void Input::parse_mapping(String p_mapping) {
bool invert_axis = false;
if (input[input.length() - 1] == '~') {
invert_axis = true;
+ input = input.left(input.length() - 1);
}
JoyButtonList output_button = _get_output_button(output);
JoyAxisList output_axis = _get_output_axis(output);
- ERR_CONTINUE_MSG(output_button == JOY_INVALID_BUTTON && output_axis == JOY_INVALID_AXIS,
+ ERR_CONTINUE_MSG(output_button == JOY_BUTTON_INVALID && output_axis == JOY_AXIS_INVALID,
String(entry[idx] + "\nUnrecognised output string: " + output));
- ERR_CONTINUE_MSG(output_button != JOY_INVALID_BUTTON && output_axis != JOY_INVALID_AXIS,
+ ERR_CONTINUE_MSG(output_button != JOY_BUTTON_INVALID && output_axis != JOY_AXIS_INVALID,
String("BUG: Output string matched both button and axis: " + output));
JoyBinding binding;
- if (output_button != JOY_INVALID_BUTTON) {
+ if (output_button != JOY_BUTTON_INVALID) {
binding.outputType = TYPE_BUTTON;
binding.output.button = output_button;
- } else if (output_axis != JOY_INVALID_AXIS) {
+ } else if (output_axis != JOY_AXIS_INVALID) {
binding.outputType = TYPE_AXIS;
binding.output.axis.axis = output_axis;
binding.output.axis.range = output_range;
@@ -1337,20 +1343,6 @@ Array Input::get_connected_joypads() {
return ret;
}
-String Input::get_joy_button_string(int p_button) {
- ERR_FAIL_INDEX_V(p_button, JOY_BUTTON_MAX, "Invalid button");
- return _joy_button_names[p_button];
-}
-
-int Input::get_joy_button_index_from_string(String p_button) {
- for (int i = 0; i < JOY_BUTTON_MAX; i++) {
- if (p_button == _joy_button_names[i]) {
- return i;
- }
- }
- ERR_FAIL_V(JOY_INVALID_BUTTON);
-}
-
int Input::get_unused_joy_id() {
for (int i = 0; i < JOYPADS_MAX; i++) {
if (!joy_names.has(i) || !joy_names[i].connected) {
@@ -1360,20 +1352,6 @@ int Input::get_unused_joy_id() {
return -1;
}
-String Input::get_joy_axis_string(int p_axis) {
- ERR_FAIL_INDEX_V(p_axis, JOY_AXIS_MAX, "Invalid axis");
- return _joy_axis_names[p_axis];
-}
-
-int Input::get_joy_axis_index_from_string(String p_axis) {
- for (int i = 0; i < JOY_AXIS_MAX; i++) {
- if (p_axis == _joy_axis_names[i]) {
- return i;
- }
- }
- ERR_FAIL_V(JOY_INVALID_AXIS);
-}
-
Input::Input() {
singleton = this;
diff --git a/core/input/input.h b/core/input/input.h
index 91e3b83b95..1b2df49ac0 100644
--- a/core/input/input.h
+++ b/core/input/input.h
@@ -32,7 +32,7 @@
#define INPUT_H
#include "core/input/input_event.h"
-#include "core/object.h"
+#include "core/object/object.h"
#include "core/os/thread_safe.h"
class Input : public Object {
@@ -117,6 +117,7 @@ private:
uint64_t idle_frame;
bool pressed;
float strength;
+ float raw_strength;
};
Map<StringName, Action> action_state;
@@ -146,7 +147,6 @@ private:
bool connected = false;
bool last_buttons[JOY_BUTTON_MAX] = { false };
float last_axis[JOY_AXIS_MAX] = { 0.0f };
- float filter = 0.01f;
int last_hat = HAT_MASK_CENTER;
int mapping = -1;
int hat_current = 0;
@@ -217,13 +217,12 @@ private:
Vector<JoyDeviceMapping> map_db;
JoyEvent _get_mapped_button_event(const JoyDeviceMapping &mapping, int p_button);
- JoyEvent _get_mapped_axis_event(const JoyDeviceMapping &mapping, int p_axis, const JoyAxis &p_value);
+ JoyEvent _get_mapped_axis_event(const JoyDeviceMapping &mapping, int p_axis, float p_value);
void _get_mapped_hat_events(const JoyDeviceMapping &mapping, int p_hat, JoyEvent r_events[HAT_MAX]);
JoyButtonList _get_output_button(String output);
JoyAxisList _get_output_axis(String output);
void _button_event(int p_device, int p_index, bool p_pressed);
void _axis_event(int p_device, int p_axis, float p_value);
- float _handle_deadzone(int p_device, int p_axis, float p_value);
void _parse_input_event_impl(const Ref<InputEvent> &p_event, bool p_is_emulated);
@@ -255,7 +254,7 @@ protected:
public:
void set_mouse_mode(MouseMode p_mode);
MouseMode get_mouse_mode() const;
- void get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const;
+ void get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const override;
static Input *get_singleton();
@@ -266,6 +265,10 @@ public:
bool is_action_just_pressed(const StringName &p_action) const;
bool is_action_just_released(const StringName &p_action) const;
float get_action_strength(const StringName &p_action) const;
+ float get_action_raw_strength(const StringName &p_action) const;
+
+ float get_axis(const StringName &p_negative_action, const StringName &p_positive_action) const;
+ Vector2 get_vector(const StringName &p_negative_x, const StringName &p_positive_x, const StringName &p_negative_y, const StringName &p_positive_y, float p_deadzone = -1.0f) const;
float get_joy_axis(int p_device, int p_axis) const;
String get_joy_name(int p_idx);
@@ -327,11 +330,6 @@ public:
void add_joy_mapping(String p_mapping, bool p_update_existing = false);
void remove_joy_mapping(String p_guid);
- String get_joy_button_string(int p_button);
- String get_joy_axis_string(int p_axis);
- int get_joy_axis_index_from_string(String p_axis);
- int get_joy_button_index_from_string(String p_button);
-
int get_unused_joy_id();
bool is_joy_known(int p_device);
diff --git a/core/input/input_event.cpp b/core/input/input_event.cpp
index 6ba082f86f..41bc5e84b0 100644
--- a/core/input/input_event.cpp
+++ b/core/input/input_event.cpp
@@ -61,12 +61,17 @@ bool InputEvent::is_action_released(const StringName &p_action) const {
}
float InputEvent::get_action_strength(const StringName &p_action) const {
- bool pressed;
float strength;
- bool valid = InputMap::get_singleton()->event_get_action_status(Ref<InputEvent>((InputEvent *)this), p_action, &pressed, &strength);
+ bool valid = InputMap::get_singleton()->event_get_action_status(Ref<InputEvent>((InputEvent *)this), p_action, nullptr, &strength);
return valid ? strength : 0.0f;
}
+float InputEvent::get_action_raw_strength(const StringName &p_action) const {
+ float raw_strength;
+ bool valid = InputMap::get_singleton()->event_get_action_status(Ref<InputEvent>((InputEvent *)this), p_action, nullptr, nullptr, &raw_strength);
+ return valid ? raw_strength : 0.0f;
+}
+
bool InputEvent::is_pressed() const {
return false;
}
@@ -83,7 +88,7 @@ String InputEvent::as_text() const {
return String();
}
-bool InputEvent::action_match(const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float p_deadzone) const {
+bool InputEvent::action_match(const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float *p_raw_strength, float p_deadzone) const {
return false;
}
@@ -138,6 +143,14 @@ int64_t InputEventFromWindow::get_window_id() const {
///////////////////////////////////
+void InputEventWithModifiers::set_store_command(bool p_enabled) {
+ store_command = p_enabled;
+}
+
+bool InputEventWithModifiers::is_storing_command() const {
+ return store_command;
+}
+
void InputEventWithModifiers::set_shift(bool p_enabled) {
shift = p_enabled;
}
@@ -186,6 +199,9 @@ void InputEventWithModifiers::set_modifiers_from_event(const InputEventWithModif
}
void InputEventWithModifiers::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_store_command", "enable"), &InputEventWithModifiers::set_store_command);
+ ClassDB::bind_method(D_METHOD("is_storing_command"), &InputEventWithModifiers::is_storing_command);
+
ClassDB::bind_method(D_METHOD("set_alt", "enable"), &InputEventWithModifiers::set_alt);
ClassDB::bind_method(D_METHOD("get_alt"), &InputEventWithModifiers::get_alt);
@@ -201,6 +217,7 @@ void InputEventWithModifiers::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_command", "enable"), &InputEventWithModifiers::set_command);
ClassDB::bind_method(D_METHOD("get_command"), &InputEventWithModifiers::get_command);
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "store_command"), "set_store_command", "is_storing_command");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "alt"), "set_alt", "get_alt");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "shift"), "set_shift", "get_shift");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "control"), "set_control", "get_control");
@@ -208,6 +225,28 @@ void InputEventWithModifiers::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "command"), "set_command", "get_command");
}
+void InputEventWithModifiers::_validate_property(PropertyInfo &property) const {
+ if (store_command) {
+ // If we only want to Store "Command".
+#ifdef APPLE_STYLE_KEYS
+ // Don't store "Meta" on Mac.
+ if (property.name == "meta") {
+ property.usage ^= PROPERTY_USAGE_STORAGE;
+ }
+#else
+ // Don't store "Control".
+ if (property.name == "control") {
+ property.usage ^= PROPERTY_USAGE_STORAGE;
+ }
+#endif
+ } else {
+ // We don't want to store command, only control or meta (on mac).
+ if (property.name == "command") {
+ property.usage ^= PROPERTY_USAGE_STORAGE;
+ }
+ }
+}
+
///////////////////////////////////
void InputEventKey::set_pressed(bool p_pressed) {
@@ -307,7 +346,7 @@ String InputEventKey::as_text() const {
return kc;
}
-bool InputEventKey::action_match(const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float p_deadzone) const {
+bool InputEventKey::action_match(const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float *p_raw_strength, float p_deadzone) const {
Ref<InputEventKey> key = p_event;
if (key.is_null()) {
return false;
@@ -329,8 +368,12 @@ bool InputEventKey::action_match(const Ref<InputEvent> &p_event, bool *p_pressed
if (p_pressed != nullptr) {
*p_pressed = key->is_pressed();
}
+ float strength = (p_pressed != nullptr && *p_pressed) ? 1.0f : 0.0f;
if (p_strength != nullptr) {
- *p_strength = (p_pressed != nullptr && *p_pressed) ? 1.0f : 0.0f;
+ *p_strength = strength;
+ }
+ if (p_raw_strength != nullptr) {
+ *p_raw_strength = strength;
}
}
return match;
@@ -470,7 +513,7 @@ Ref<InputEvent> InputEventMouseButton::xformed_by(const Transform2D &p_xform, co
return mb;
}
-bool InputEventMouseButton::action_match(const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float p_deadzone) const {
+bool InputEventMouseButton::action_match(const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float *p_raw_strength, float p_deadzone) const {
Ref<InputEventMouseButton> mb = p_event;
if (mb.is_null()) {
return false;
@@ -481,8 +524,12 @@ bool InputEventMouseButton::action_match(const Ref<InputEvent> &p_event, bool *p
if (p_pressed != nullptr) {
*p_pressed = mb->is_pressed();
}
+ float strength = (p_pressed != nullptr && *p_pressed) ? 1.0f : 0.0f;
if (p_strength != nullptr) {
- *p_strength = (p_pressed != nullptr && *p_pressed) ? 1.0f : 0.0f;
+ *p_strength = strength;
+ }
+ if (p_raw_strength != nullptr) {
+ *p_raw_strength = strength;
}
}
@@ -713,7 +760,7 @@ bool InputEventJoypadMotion::is_pressed() const {
return Math::abs(axis_value) >= 0.5f;
}
-bool InputEventJoypadMotion::action_match(const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float p_deadzone) const {
+bool InputEventJoypadMotion::action_match(const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float *p_raw_strength, float p_deadzone) const {
Ref<InputEventJoypadMotion> jm = p_event;
if (jm.is_null()) {
return false;
@@ -721,8 +768,9 @@ bool InputEventJoypadMotion::action_match(const Ref<InputEvent> &p_event, bool *
bool match = (axis == jm->axis); // Matches even if not in the same direction, but returns a "not pressed" event.
if (match) {
+ float jm_abs_axis_value = Math::abs(jm->get_axis_value());
bool same_direction = (((axis_value < 0) == (jm->axis_value < 0)) || jm->axis_value == 0);
- bool pressed = same_direction ? Math::abs(jm->get_axis_value()) >= p_deadzone : false;
+ bool pressed = same_direction && jm_abs_axis_value >= p_deadzone;
if (p_pressed != nullptr) {
*p_pressed = pressed;
}
@@ -731,12 +779,19 @@ bool InputEventJoypadMotion::action_match(const Ref<InputEvent> &p_event, bool *
if (p_deadzone == 1.0f) {
*p_strength = 1.0f;
} else {
- *p_strength = CLAMP(Math::inverse_lerp(p_deadzone, 1.0f, Math::abs(jm->get_axis_value())), 0.0f, 1.0f);
+ *p_strength = CLAMP(Math::inverse_lerp(p_deadzone, 1.0f, jm_abs_axis_value), 0.0f, 1.0f);
}
} else {
*p_strength = 0.0f;
}
}
+ if (p_raw_strength != nullptr) {
+ if (same_direction) { // NOT pressed, because we want to ignore the deadzone.
+ *p_raw_strength = jm_abs_axis_value;
+ } else {
+ *p_raw_strength = 0.0f;
+ }
+ }
}
return match;
}
@@ -782,7 +837,7 @@ float InputEventJoypadButton::get_pressure() const {
return pressure;
}
-bool InputEventJoypadButton::action_match(const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float p_deadzone) const {
+bool InputEventJoypadButton::action_match(const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float *p_raw_strength, float p_deadzone) const {
Ref<InputEventJoypadButton> jb = p_event;
if (jb.is_null()) {
return false;
@@ -793,8 +848,12 @@ bool InputEventJoypadButton::action_match(const Ref<InputEvent> &p_event, bool *
if (p_pressed != nullptr) {
*p_pressed = jb->is_pressed();
}
+ float strength = (p_pressed != nullptr && *p_pressed) ? 1.0f : 0.0f;
if (p_strength != nullptr) {
- *p_strength = (p_pressed != nullptr && *p_pressed) ? 1.0f : 0.0f;
+ *p_strength = strength;
+ }
+ if (p_raw_strength != nullptr) {
+ *p_raw_strength = strength;
}
}
@@ -997,7 +1056,7 @@ bool InputEventAction::is_action(const StringName &p_action) const {
return action == p_action;
}
-bool InputEventAction::action_match(const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float p_deadzone) const {
+bool InputEventAction::action_match(const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float *p_raw_strength, float p_deadzone) const {
Ref<InputEventAction> act = p_event;
if (act.is_null()) {
return false;
@@ -1008,8 +1067,12 @@ bool InputEventAction::action_match(const Ref<InputEvent> &p_event, bool *p_pres
if (p_pressed != nullptr) {
*p_pressed = act->pressed;
}
+ float strength = (p_pressed != nullptr && *p_pressed) ? 1.0f : 0.0f;
if (p_strength != nullptr) {
- *p_strength = (p_pressed != nullptr && *p_pressed) ? 1.0f : 0.0f;
+ *p_strength = strength;
+ }
+ if (p_raw_strength != nullptr) {
+ *p_raw_strength = strength;
}
}
return match;
diff --git a/core/input/input_event.h b/core/input/input_event.h
index dd1cc11982..0eae3a2bbe 100644
--- a/core/input/input_event.h
+++ b/core/input/input_event.h
@@ -31,11 +31,11 @@
#ifndef INPUT_EVENT_H
#define INPUT_EVENT_H
+#include "core/io/resource.h"
#include "core/math/transform_2d.h"
#include "core/os/copymem.h"
-#include "core/resource.h"
+#include "core/string/ustring.h"
#include "core/typedefs.h"
-#include "core/ustring.h"
/**
* Input Event classes. These are used in the main loop.
@@ -60,10 +60,7 @@ enum ButtonList {
};
enum JoyButtonList {
-
- JOY_INVALID_BUTTON = -1,
-
- // SDL Buttons
+ JOY_BUTTON_INVALID = -1,
JOY_BUTTON_A = 0,
JOY_BUTTON_B = 1,
JOY_BUTTON_X = 2,
@@ -79,64 +76,20 @@ enum JoyButtonList {
JOY_BUTTON_DPAD_DOWN = 12,
JOY_BUTTON_DPAD_LEFT = 13,
JOY_BUTTON_DPAD_RIGHT = 14,
- JOY_SDL_BUTTONS = 15,
-
- // Sony Buttons
- JOY_SONY_X = JOY_BUTTON_A,
- JOY_SONY_CROSS = JOY_BUTTON_A,
- JOY_SONY_CIRCLE = JOY_BUTTON_B,
- JOY_SONY_SQUARE = JOY_BUTTON_X,
- JOY_SONY_TRIANGLE = JOY_BUTTON_Y,
- JOY_SONY_SELECT = JOY_BUTTON_BACK,
- JOY_SONY_START = JOY_BUTTON_START,
- JOY_SONY_PS = JOY_BUTTON_GUIDE,
- JOY_SONY_L1 = JOY_BUTTON_LEFT_SHOULDER,
- JOY_SONY_R1 = JOY_BUTTON_RIGHT_SHOULDER,
- JOY_SONY_L3 = JOY_BUTTON_LEFT_STICK,
- JOY_SONY_R3 = JOY_BUTTON_RIGHT_STICK,
-
- // Xbox Buttons
- JOY_XBOX_A = JOY_BUTTON_A,
- JOY_XBOX_B = JOY_BUTTON_B,
- JOY_XBOX_X = JOY_BUTTON_X,
- JOY_XBOX_Y = JOY_BUTTON_Y,
- JOY_XBOX_BACK = JOY_BUTTON_BACK,
- JOY_XBOX_START = JOY_BUTTON_START,
- JOY_XBOX_HOME = JOY_BUTTON_GUIDE,
- JOY_XBOX_LS = JOY_BUTTON_LEFT_STICK,
- JOY_XBOX_RS = JOY_BUTTON_RIGHT_STICK,
- JOY_XBOX_LB = JOY_BUTTON_LEFT_SHOULDER,
- JOY_XBOX_RB = JOY_BUTTON_RIGHT_SHOULDER,
-
- JOY_BUTTON_MAX = 36 // Apparently Android supports up to 36 buttons.
+ JOY_BUTTON_SDL_MAX = 15,
+ JOY_BUTTON_MAX = 36, // Android supports up to 36 buttons.
};
enum JoyAxisList {
-
- JOY_INVALID_AXIS = -1,
-
- // SDL Axes
+ JOY_AXIS_INVALID = -1,
JOY_AXIS_LEFT_X = 0,
JOY_AXIS_LEFT_Y = 1,
JOY_AXIS_RIGHT_X = 2,
JOY_AXIS_RIGHT_Y = 3,
JOY_AXIS_TRIGGER_LEFT = 4,
JOY_AXIS_TRIGGER_RIGHT = 5,
- JOY_SDL_AXES = 6,
-
- // Joystick axes.
- JOY_AXIS_0_X = 0,
- JOY_AXIS_0_Y = 1,
- JOY_AXIS_1_X = 2,
- JOY_AXIS_1_Y = 3,
- JOY_AXIS_2_X = 4,
- JOY_AXIS_2_Y = 5,
- JOY_AXIS_3_X = 6,
- JOY_AXIS_3_Y = 7,
- JOY_AXIS_4_X = 8,
- JOY_AXIS_4_Y = 9,
-
- JOY_AXIS_MAX = 10 // OpenVR supports up to 5 Joysticks making a total of 10 axes.
+ JOY_AXIS_SDL_MAX = 6,
+ JOY_AXIS_MAX = 10, // OpenVR supports up to 5 Joysticks making a total of 10 axes.
};
enum MidiMessageList {
@@ -173,6 +126,7 @@ public:
bool is_action_pressed(const StringName &p_action, bool p_allow_echo = false) const;
bool is_action_released(const StringName &p_action) const;
float get_action_strength(const StringName &p_action) const;
+ float get_action_raw_strength(const StringName &p_action) const;
// To be removed someday, since they do not make sense for all events
virtual bool is_pressed() const;
@@ -182,7 +136,7 @@ public:
virtual Ref<InputEvent> xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs = Vector2()) const;
- virtual bool action_match(const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float p_deadzone) const;
+ virtual bool action_match(const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float *p_raw_strength, float p_deadzone) const;
virtual bool shortcut_match(const Ref<InputEvent> &p_event) const;
virtual bool is_action_type() const;
@@ -209,6 +163,8 @@ public:
class InputEventWithModifiers : public InputEventFromWindow {
GDCLASS(InputEventWithModifiers, InputEventFromWindow);
+ bool store_command = true;
+
bool shift = false;
bool alt = false;
#ifdef APPLE_STYLE_KEYS
@@ -228,8 +184,12 @@ class InputEventWithModifiers : public InputEventFromWindow {
protected:
static void _bind_methods();
+ virtual void _validate_property(PropertyInfo &property) const override;
public:
+ void set_store_command(bool p_enabled);
+ bool is_storing_command() const;
+
void set_shift(bool p_enabled);
bool get_shift() const;
@@ -266,7 +226,7 @@ protected:
public:
void set_pressed(bool p_pressed);
- virtual bool is_pressed() const;
+ virtual bool is_pressed() const override;
void set_keycode(uint32_t p_keycode);
uint32_t get_keycode() const;
@@ -278,17 +238,17 @@ public:
uint32_t get_unicode() const;
void set_echo(bool p_enable);
- virtual bool is_echo() const;
+ virtual bool is_echo() const override;
uint32_t get_keycode_with_modifiers() const;
uint32_t get_physical_keycode_with_modifiers() const;
- virtual bool action_match(const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float p_deadzone) const;
- virtual bool shortcut_match(const Ref<InputEvent> &p_event) const;
+ virtual bool action_match(const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float *p_raw_strength, float p_deadzone) const override;
+ virtual bool shortcut_match(const Ref<InputEvent> &p_event) const override;
- virtual bool is_action_type() const { return true; }
+ virtual bool is_action_type() const override { return true; }
- virtual String as_text() const;
+ virtual String as_text() const override;
InputEventKey() {}
};
@@ -336,16 +296,16 @@ public:
int get_button_index() const;
void set_pressed(bool p_pressed);
- virtual bool is_pressed() const;
+ virtual bool is_pressed() const override;
void set_doubleclick(bool p_doubleclick);
bool is_doubleclick() const;
- virtual Ref<InputEvent> xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs = Vector2()) const;
- virtual bool action_match(const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float p_deadzone) const;
+ virtual Ref<InputEvent> xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs = Vector2()) const override;
+ virtual bool action_match(const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float *p_raw_strength, float p_deadzone) const override;
- virtual bool is_action_type() const { return true; }
- virtual String as_text() const;
+ virtual bool is_action_type() const override { return true; }
+ virtual String as_text() const override;
InputEventMouseButton() {}
};
@@ -374,10 +334,10 @@ public:
void set_speed(const Vector2 &p_speed);
Vector2 get_speed() const;
- virtual Ref<InputEvent> xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs = Vector2()) const;
- virtual String as_text() const;
+ virtual Ref<InputEvent> xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs = Vector2()) const override;
+ virtual String as_text() const override;
- virtual bool accumulate(const Ref<InputEvent> &p_event);
+ virtual bool accumulate(const Ref<InputEvent> &p_event) override;
InputEventMouseMotion() {}
};
@@ -397,12 +357,12 @@ public:
void set_axis_value(float p_value);
float get_axis_value() const;
- virtual bool is_pressed() const;
+ virtual bool is_pressed() const override;
- virtual bool action_match(const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float p_deadzone) const;
+ virtual bool action_match(const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float *p_raw_strength, float p_deadzone) const override;
- virtual bool is_action_type() const { return true; }
- virtual String as_text() const;
+ virtual bool is_action_type() const override { return true; }
+ virtual String as_text() const override;
InputEventJoypadMotion() {}
};
@@ -421,16 +381,16 @@ public:
int get_button_index() const;
void set_pressed(bool p_pressed);
- virtual bool is_pressed() const;
+ virtual bool is_pressed() const override;
void set_pressure(float p_pressure);
float get_pressure() const;
- virtual bool action_match(const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float p_deadzone) const;
- virtual bool shortcut_match(const Ref<InputEvent> &p_event) const;
+ virtual bool action_match(const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float *p_raw_strength, float p_deadzone) const override;
+ virtual bool shortcut_match(const Ref<InputEvent> &p_event) const override;
- virtual bool is_action_type() const { return true; }
- virtual String as_text() const;
+ virtual bool is_action_type() const override { return true; }
+ virtual String as_text() const override;
InputEventJoypadButton() {}
};
@@ -452,10 +412,10 @@ public:
Vector2 get_position() const;
void set_pressed(bool p_pressed);
- virtual bool is_pressed() const;
+ virtual bool is_pressed() const override;
- virtual Ref<InputEvent> xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs = Vector2()) const;
- virtual String as_text() const;
+ virtual Ref<InputEvent> xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs = Vector2()) const override;
+ virtual String as_text() const override;
InputEventScreenTouch() {}
};
@@ -483,8 +443,8 @@ public:
void set_speed(const Vector2 &p_speed);
Vector2 get_speed() const;
- virtual Ref<InputEvent> xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs = Vector2()) const;
- virtual String as_text() const;
+ virtual Ref<InputEvent> xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs = Vector2()) const override;
+ virtual String as_text() const override;
InputEventScreenDrag() {}
};
@@ -504,18 +464,18 @@ public:
StringName get_action() const;
void set_pressed(bool p_pressed);
- virtual bool is_pressed() const;
+ virtual bool is_pressed() const override;
void set_strength(float p_strength);
float get_strength() const;
virtual bool is_action(const StringName &p_action) const;
- virtual bool action_match(const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float p_deadzone) const;
+ virtual bool action_match(const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float *p_raw_strength, float p_deadzone) const override;
- virtual bool shortcut_match(const Ref<InputEvent> &p_event) const;
- virtual bool is_action_type() const { return true; }
- virtual String as_text() const;
+ virtual bool shortcut_match(const Ref<InputEvent> &p_event) const override;
+ virtual bool is_action_type() const override { return true; }
+ virtual String as_text() const override;
InputEventAction() {}
};
@@ -544,8 +504,8 @@ public:
void set_factor(real_t p_factor);
real_t get_factor() const;
- virtual Ref<InputEvent> xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs = Vector2()) const;
- virtual String as_text() const;
+ virtual Ref<InputEvent> xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs = Vector2()) const override;
+ virtual String as_text() const override;
InputEventMagnifyGesture() {}
};
@@ -561,8 +521,8 @@ public:
void set_delta(const Vector2 &p_delta);
Vector2 get_delta() const;
- virtual Ref<InputEvent> xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs = Vector2()) const;
- virtual String as_text() const;
+ virtual Ref<InputEvent> xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs = Vector2()) const override;
+ virtual String as_text() const override;
InputEventPanGesture() {}
};
@@ -607,7 +567,7 @@ public:
void set_controller_value(const int p_controller_value);
int get_controller_value() const;
- virtual String as_text() const;
+ virtual String as_text() const override;
InputEventMIDI() {}
};
diff --git a/core/input/input_map.cpp b/core/input/input_map.cpp
index ac032b7d10..979809c7af 100644
--- a/core/input/input_map.cpp
+++ b/core/input/input_map.cpp
@@ -30,8 +30,9 @@
#include "input_map.h"
+#include "core/config/project_settings.h"
+#include "core/input/input.h"
#include "core/os/keyboard.h"
-#include "core/project_settings.h"
InputMap *InputMap::singleton = nullptr;
@@ -50,7 +51,7 @@ void InputMap::_bind_methods() {
ClassDB::bind_method(D_METHOD("action_erase_events", "action"), &InputMap::action_erase_events);
ClassDB::bind_method(D_METHOD("action_get_events", "action"), &InputMap::_action_get_events);
ClassDB::bind_method(D_METHOD("event_is_action", "event", "action"), &InputMap::event_is_action);
- ClassDB::bind_method(D_METHOD("load_from_globals"), &InputMap::load_from_globals);
+ ClassDB::bind_method(D_METHOD("load_from_project_settings"), &InputMap::load_from_project_settings);
}
void InputMap::add_action(const StringName &p_action, float p_deadzone) {
@@ -94,7 +95,9 @@ List<StringName> InputMap::get_actions() const {
return actions;
}
-List<Ref<InputEvent>>::Element *InputMap::_find_event(Action &p_action, const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength) const {
+List<Ref<InputEvent>>::Element *InputMap::_find_event(Action &p_action, const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float *p_raw_strength) const {
+ ERR_FAIL_COND_V(!p_event.is_valid(), nullptr);
+
for (List<Ref<InputEvent>>::Element *E = p_action.inputs.front(); E; E = E->next()) {
const Ref<InputEvent> e = E->get();
@@ -103,7 +106,7 @@ List<Ref<InputEvent>>::Element *InputMap::_find_event(Action &p_action, const Re
int device = e->get_device();
if (device == ALL_DEVICES || device == p_event->get_device()) {
- if (e->action_match(p_event, p_pressed, p_strength, p_action.deadzone)) {
+ if (e->action_match(p_event, p_pressed, p_strength, p_raw_strength, p_action.deadzone)) {
return E;
}
}
@@ -116,6 +119,12 @@ bool InputMap::has_action(const StringName &p_action) const {
return input_map.has(p_action);
}
+float InputMap::action_get_deadzone(const StringName &p_action) {
+ ERR_FAIL_COND_V_MSG(!input_map.has(p_action), 0.0f, "Request for nonexistent InputMap action '" + String(p_action) + "'.");
+
+ return input_map[p_action].deadzone;
+}
+
void InputMap::action_set_deadzone(const StringName &p_action, float p_deadzone) {
ERR_FAIL_COND_MSG(!input_map.has(p_action), "Request for nonexistent InputMap action '" + String(p_action) + "'.");
@@ -126,7 +135,7 @@ void InputMap::action_add_event(const StringName &p_action, const Ref<InputEvent
ERR_FAIL_COND_MSG(p_event.is_null(), "It's not a reference to a valid InputEvent object.");
ERR_FAIL_COND_MSG(!input_map.has(p_action), "Request for nonexistent InputMap action '" + String(p_action) + "'.");
if (_find_event(input_map[p_action], p_event)) {
- return; //already gots
+ return; // Already addded.
}
input_map[p_action].inputs.push_back(p_event);
@@ -143,6 +152,9 @@ void InputMap::action_erase_event(const StringName &p_action, const Ref<InputEve
List<Ref<InputEvent>>::Element *E = _find_event(input_map[p_action], p_event);
if (E) {
input_map[p_action].inputs.erase(E);
+ if (Input::get_singleton()->is_action_pressed(p_action)) {
+ Input::get_singleton()->action_release(p_action);
+ }
}
}
@@ -177,7 +189,7 @@ bool InputMap::event_is_action(const Ref<InputEvent> &p_event, const StringName
return event_get_action_status(p_event, p_action);
}
-bool InputMap::event_get_action_status(const Ref<InputEvent> &p_event, const StringName &p_action, bool *p_pressed, float *p_strength) const {
+bool InputMap::event_get_action_status(const Ref<InputEvent> &p_event, const StringName &p_action, bool *p_pressed, float *p_strength, float *p_raw_strength) const {
Map<StringName, Action>::Element *E = input_map.find(p_action);
ERR_FAIL_COND_V_MSG(!E, false, "Request for nonexistent InputMap action '" + String(p_action) + "'.");
@@ -194,7 +206,8 @@ bool InputMap::event_get_action_status(const Ref<InputEvent> &p_event, const Str
bool pressed;
float strength;
- List<Ref<InputEvent>>::Element *event = _find_event(E->get(), p_event, &pressed, &strength);
+ float raw_strength;
+ List<Ref<InputEvent>>::Element *event = _find_event(E->get(), p_event, &pressed, &strength, &raw_strength);
if (event != nullptr) {
if (p_pressed != nullptr) {
*p_pressed = pressed;
@@ -202,6 +215,9 @@ bool InputMap::event_get_action_status(const Ref<InputEvent> &p_event, const Str
if (p_strength != nullptr) {
*p_strength = strength;
}
+ if (p_raw_strength != nullptr) {
+ *p_raw_strength = raw_strength;
+ }
return true;
} else {
return false;
@@ -212,7 +228,7 @@ const Map<StringName, InputMap::Action> &InputMap::get_action_map() const {
return input_map;
}
-void InputMap::load_from_globals() {
+void InputMap::load_from_project_settings() {
input_map.clear();
List<PropertyInfo> pinfo;
diff --git a/core/input/input_map.h b/core/input/input_map.h
index 548553ed31..948d78ebdd 100644
--- a/core/input/input_map.h
+++ b/core/input/input_map.h
@@ -32,7 +32,7 @@
#define INPUT_MAP_H
#include "core/input/input_event.h"
-#include "core/object.h"
+#include "core/object/class_db.h"
class InputMap : public Object {
GDCLASS(InputMap, Object);
@@ -54,7 +54,7 @@ private:
mutable Map<StringName, Action> input_map;
- List<Ref<InputEvent>>::Element *_find_event(Action &p_action, const Ref<InputEvent> &p_event, bool *p_pressed = nullptr, float *p_strength = nullptr) const;
+ List<Ref<InputEvent>>::Element *_find_event(Action &p_action, const Ref<InputEvent> &p_event, bool *p_pressed = nullptr, float *p_strength = nullptr, float *p_raw_strength = nullptr) const;
Array _action_get_events(const StringName &p_action);
Array _get_actions();
@@ -70,6 +70,7 @@ public:
void add_action(const StringName &p_action, float p_deadzone = 0.5);
void erase_action(const StringName &p_action);
+ float action_get_deadzone(const StringName &p_action);
void action_set_deadzone(const StringName &p_action, float p_deadzone);
void action_add_event(const StringName &p_action, const Ref<InputEvent> &p_event);
bool action_has_event(const StringName &p_action, const Ref<InputEvent> &p_event);
@@ -78,10 +79,10 @@ public:
const List<Ref<InputEvent>> *action_get_events(const StringName &p_action);
bool event_is_action(const Ref<InputEvent> &p_event, const StringName &p_action) const;
- bool event_get_action_status(const Ref<InputEvent> &p_event, const StringName &p_action, bool *p_pressed = nullptr, float *p_strength = nullptr) const;
+ bool event_get_action_status(const Ref<InputEvent> &p_event, const StringName &p_action, bool *p_pressed = nullptr, float *p_strength = nullptr, float *p_raw_strength = nullptr) const;
const Map<StringName, Action> &get_action_map() const;
- void load_from_globals();
+ void load_from_project_settings();
void load_default();
InputMap();
diff --git a/core/int_types.h b/core/int_types.h
deleted file mode 100644
index 71caa2202d..0000000000
--- a/core/int_types.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/*************************************************************************/
-/* int_types.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* 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. */
-/*************************************************************************/
-
-#ifndef INT_TYPES_H
-#define INT_TYPES_H
-
-#ifdef _MSC_VER
-
-typedef signed __int8 int8_t;
-typedef unsigned __int8 uint8_t;
-typedef signed __int16 int16_t;
-typedef unsigned __int16 uint16_t;
-typedef signed __int32 int32_t;
-typedef unsigned __int32 uint32_t;
-typedef signed __int64 int64_t;
-typedef unsigned __int64 uint64_t;
-
-#else
-
-#ifdef NO_STDINT_H
-typedef unsigned char uint8_t;
-typedef signed char int8_t;
-typedef unsigned short uint16_t;
-typedef signed short int16_t;
-typedef unsigned int uint32_t;
-typedef signed int int32_t;
-typedef long long int64_t;
-typedef unsigned long long uint64_t;
-#else
-#include <stdint.h>
-#endif
-
-#endif // _MSC_VER
-
-#endif // INT_TYPES_H
diff --git a/core/io/compression.cpp b/core/io/compression.cpp
index 99ca8107e4..cd8793bb0a 100644
--- a/core/io/compression.cpp
+++ b/core/io/compression.cpp
@@ -30,9 +30,9 @@
#include "compression.h"
+#include "core/config/project_settings.h"
#include "core/io/zip_io.h"
#include "core/os/copymem.h"
-#include "core/project_settings.h"
#include "thirdparty/misc/fastlz.h"
@@ -180,8 +180,95 @@ int Compression::decompress(uint8_t *p_dst, int p_dst_max_size, const uint8_t *p
ERR_FAIL_V(-1);
}
+/**
+ This will handle both Gzip and Deflat streams. It will automatically allocate the output buffer into the provided p_dst_vect Vector.
+ This is required for compressed data who's final uncompressed size is unknown, as is the case for HTTP response bodies.
+ This is much slower however than using Compression::decompress because it may result in multiple full copies of the output buffer.
+*/
+int Compression::decompress_dynamic(Vector<uint8_t> *p_dst_vect, int p_max_dst_size, const uint8_t *p_src, int p_src_size, Mode p_mode) {
+ int ret;
+ uint8_t *dst = nullptr;
+ int out_mark = 0;
+ z_stream strm;
+
+ ERR_FAIL_COND_V(p_src_size <= 0, Z_DATA_ERROR);
+
+ // This function only supports GZip and Deflate
+ int window_bits = p_mode == MODE_DEFLATE ? 15 : 15 + 16;
+ ERR_FAIL_COND_V(p_mode != MODE_DEFLATE && p_mode != MODE_GZIP, Z_ERRNO);
+
+ // Initialize the stream
+ strm.zalloc = Z_NULL;
+ strm.zfree = Z_NULL;
+ strm.opaque = Z_NULL;
+ strm.avail_in = 0;
+ strm.next_in = Z_NULL;
+
+ int err = inflateInit2(&strm, window_bits);
+ ERR_FAIL_COND_V(err != Z_OK, -1);
+
+ // Setup the stream inputs
+ strm.next_in = (Bytef *)p_src;
+ strm.avail_in = p_src_size;
+
+ // Ensure the destination buffer is empty
+ p_dst_vect->resize(0);
+
+ // decompress until deflate stream ends or end of file
+ do {
+ // Add another chunk size to the output buffer
+ // This forces a copy of the whole buffer
+ p_dst_vect->resize(p_dst_vect->size() + gzip_chunk);
+ // Get pointer to the actual output buffer
+ dst = p_dst_vect->ptrw();
+
+ // Set the stream to the new output stream
+ // Since it was copied, we need to reset the stream to the new buffer
+ strm.next_out = &(dst[out_mark]);
+ strm.avail_out = gzip_chunk;
+
+ // run inflate() on input until output buffer is full and needs to be resized
+ // or input runs out
+ do {
+ ret = inflate(&strm, Z_SYNC_FLUSH);
+
+ switch (ret) {
+ case Z_NEED_DICT:
+ ret = Z_DATA_ERROR;
+ [[fallthrough]];
+ case Z_DATA_ERROR:
+ case Z_MEM_ERROR:
+ case Z_STREAM_ERROR:
+ WARN_PRINT(strm.msg);
+ (void)inflateEnd(&strm);
+ p_dst_vect->resize(0);
+ return ret;
+ }
+ } while (strm.avail_out > 0 && strm.avail_in > 0);
+
+ out_mark += gzip_chunk;
+
+ // Encorce max output size
+ if (p_max_dst_size > -1 && strm.total_out > (uint64_t)p_max_dst_size) {
+ (void)inflateEnd(&strm);
+ p_dst_vect->resize(0);
+ return Z_BUF_ERROR;
+ }
+ } while (ret != Z_STREAM_END);
+
+ // If all done successfully, resize the output if it's larger than the actual output
+ if (ret == Z_STREAM_END && (unsigned long)p_dst_vect->size() > strm.total_out) {
+ p_dst_vect->resize(strm.total_out);
+ }
+
+ // clean up and return
+ (void)inflateEnd(&strm);
+ return ret == Z_STREAM_END ? Z_OK : Z_DATA_ERROR;
+}
+
int Compression::zlib_level = Z_DEFAULT_COMPRESSION;
int Compression::gzip_level = Z_DEFAULT_COMPRESSION;
int Compression::zstd_level = 3;
bool Compression::zstd_long_distance_matching = false;
int Compression::zstd_window_log_size = 27; // ZSTD_WINDOWLOG_LIMIT_DEFAULT
+int Compression::gzip_chunk = 16384;
diff --git a/core/io/compression.h b/core/io/compression.h
index f195f96ba5..864869788a 100644
--- a/core/io/compression.h
+++ b/core/io/compression.h
@@ -31,6 +31,7 @@
#ifndef COMPRESSION_H
#define COMPRESSION_H
+#include "core/templates/vector.h"
#include "core/typedefs.h"
class Compression {
@@ -40,6 +41,7 @@ public:
static int zstd_level;
static bool zstd_long_distance_matching;
static int zstd_window_log_size;
+ static int gzip_chunk;
enum Mode {
MODE_FASTLZ,
@@ -51,6 +53,7 @@ public:
static int compress(uint8_t *p_dst, const uint8_t *p_src, int p_src_size, Mode p_mode = MODE_ZSTD);
static int get_max_compressed_buffer_size(int p_src_size, Mode p_mode = MODE_ZSTD);
static int decompress(uint8_t *p_dst, int p_dst_max_size, const uint8_t *p_src, int p_src_size, Mode p_mode = MODE_ZSTD);
+ static int decompress_dynamic(Vector<uint8_t> *p_dst_vect, int p_max_dst_size, const uint8_t *p_src, int p_src_size, Mode p_mode);
Compression() {}
};
diff --git a/core/io/config_file.cpp b/core/io/config_file.cpp
index 1af9142317..8be39178db 100644
--- a/core/io/config_file.cpp
+++ b/core/io/config_file.cpp
@@ -32,7 +32,7 @@
#include "core/io/file_access_encrypted.h"
#include "core/os/keyboard.h"
-#include "core/variant_parser.h"
+#include "core/variant/variant_parser.h"
PackedStringArray ConfigFile::_get_sections() const {
List<String> s;
diff --git a/core/io/config_file.h b/core/io/config_file.h
index ae06960f02..1dc4492ca8 100644
--- a/core/io/config_file.h
+++ b/core/io/config_file.h
@@ -31,10 +31,10 @@
#ifndef CONFIG_FILE_H
#define CONFIG_FILE_H
-#include "core/ordered_hash_map.h"
+#include "core/object/reference.h"
#include "core/os/file_access.h"
-#include "core/reference.h"
-#include "core/variant_parser.h"
+#include "core/templates/ordered_hash_map.h"
+#include "core/variant/variant_parser.h"
class ConfigFile : public Reference {
GDCLASS(ConfigFile, Reference);
diff --git a/core/io/dtls_server.cpp b/core/io/dtls_server.cpp
index e43b1f5385..1930f40c47 100644
--- a/core/io/dtls_server.cpp
+++ b/core/io/dtls_server.cpp
@@ -30,8 +30,8 @@
#include "dtls_server.h"
+#include "core/config/project_settings.h"
#include "core/os/file_access.h"
-#include "core/project_settings.h"
DTLSServer *(*DTLSServer::_create)() = nullptr;
bool DTLSServer::available = false;
diff --git a/core/io/file_access_buffered.cpp b/core/io/file_access_buffered.cpp
index 6208f3a4d1..714f3b6099 100644
--- a/core/io/file_access_buffered.cpp
+++ b/core/io/file_access_buffered.cpp
@@ -30,7 +30,7 @@
#include "file_access_buffered.h"
-#include "core/error_macros.h"
+#include "core/error/error_macros.h"
Error FileAccessBuffered::set_error(Error p_error) const {
return (last_error = p_error);
diff --git a/core/io/file_access_buffered.h b/core/io/file_access_buffered.h
index 99d5ce903d..7fd99b6373 100644
--- a/core/io/file_access_buffered.h
+++ b/core/io/file_access_buffered.h
@@ -33,7 +33,7 @@
#include "core/os/file_access.h"
-#include "core/ustring.h"
+#include "core/string/ustring.h"
class FileAccessBuffered : public FileAccess {
public:
diff --git a/core/io/file_access_compressed.cpp b/core/io/file_access_compressed.cpp
index 7817ccb773..4424192af2 100644
--- a/core/io/file_access_compressed.cpp
+++ b/core/io/file_access_compressed.cpp
@@ -30,7 +30,7 @@
#include "file_access_compressed.h"
-#include "core/print_string.h"
+#include "core/string/print_string.h"
void FileAccessCompressed::configure(const String &p_magic, Compression::Mode p_mode, int p_block_size) {
magic = p_magic.ascii().get_data();
diff --git a/core/io/file_access_encrypted.cpp b/core/io/file_access_encrypted.cpp
index 5938914cb0..2ac24d5169 100644
--- a/core/io/file_access_encrypted.cpp
+++ b/core/io/file_access_encrypted.cpp
@@ -32,57 +32,59 @@
#include "core/crypto/crypto_core.h"
#include "core/os/copymem.h"
-#include "core/print_string.h"
-#include "core/variant.h"
+#include "core/string/print_string.h"
+#include "core/variant/variant.h"
#include <stdio.h>
-#define COMP_MAGIC 0x43454447
-
-Error FileAccessEncrypted::open_and_parse(FileAccess *p_base, const Vector<uint8_t> &p_key, Mode p_mode) {
+Error FileAccessEncrypted::open_and_parse(FileAccess *p_base, const Vector<uint8_t> &p_key, Mode p_mode, bool p_with_magic) {
ERR_FAIL_COND_V_MSG(file != nullptr, ERR_ALREADY_IN_USE, "Can't open file while another file from path '" + file->get_path_absolute() + "' is open.");
ERR_FAIL_COND_V(p_key.size() != 32, ERR_INVALID_PARAMETER);
pos = 0;
eofed = false;
+ use_magic = p_with_magic;
if (p_mode == MODE_WRITE_AES256) {
data.clear();
writing = true;
file = p_base;
- mode = p_mode;
key = p_key;
} else if (p_mode == MODE_READ) {
writing = false;
key = p_key;
- uint32_t magic = p_base->get_32();
- ERR_FAIL_COND_V(magic != COMP_MAGIC, ERR_FILE_UNRECOGNIZED);
- mode = Mode(p_base->get_32());
- ERR_FAIL_INDEX_V(mode, MODE_MAX, ERR_FILE_CORRUPT);
- ERR_FAIL_COND_V(mode == 0, ERR_FILE_CORRUPT);
+ if (use_magic) {
+ uint32_t magic = p_base->get_32();
+ ERR_FAIL_COND_V(magic != ENCRYPTED_HEADER_MAGIC, ERR_FILE_UNRECOGNIZED);
+ }
unsigned char md5d[16];
p_base->get_buffer(md5d, 16);
length = p_base->get_64();
+
+ unsigned char iv[16];
+ for (int i = 0; i < 16; i++) {
+ iv[i] = p_base->get_8();
+ }
+
base = p_base->get_position();
ERR_FAIL_COND_V(p_base->get_len() < base + length, ERR_FILE_CORRUPT);
uint32_t ds = length;
if (ds % 16) {
ds += 16 - (ds % 16);
}
-
data.resize(ds);
uint32_t blen = p_base->get_buffer(data.ptrw(), ds);
ERR_FAIL_COND_V(blen != ds, ERR_FILE_CORRUPT);
- CryptoCore::AESContext ctx;
- ctx.set_decode_key(key.ptrw(), 256);
+ {
+ CryptoCore::AESContext ctx;
- for (size_t i = 0; i < ds; i += 16) {
- ctx.decrypt_ecb(&data.write[i], &data.write[i]);
+ ctx.set_encode_key(key.ptrw(), 256); // Due to the nature of CFB, same key schedule is used for both encryption and decryption!
+ ctx.decrypt_cfb(ds, iv, data.ptrw(), data.ptrw());
}
data.resize(length);
@@ -119,6 +121,25 @@ void FileAccessEncrypted::close() {
return;
}
+ _release();
+
+ file->close();
+ memdelete(file);
+
+ file = nullptr;
+}
+
+void FileAccessEncrypted::release() {
+ if (!file) {
+ return;
+ }
+
+ _release();
+
+ file = nullptr;
+}
+
+void FileAccessEncrypted::_release() {
if (writing) {
Vector<uint8_t> compressed;
size_t len = data.size();
@@ -138,27 +159,23 @@ void FileAccessEncrypted::close() {
CryptoCore::AESContext ctx;
ctx.set_encode_key(key.ptrw(), 256);
- for (size_t i = 0; i < len; i += 16) {
- ctx.encrypt_ecb(&compressed.write[i], &compressed.write[i]);
+ if (use_magic) {
+ file->store_32(ENCRYPTED_HEADER_MAGIC);
}
- file->store_32(COMP_MAGIC);
- file->store_32(mode);
-
file->store_buffer(hash, 16);
file->store_64(data.size());
- file->store_buffer(compressed.ptr(), compressed.size());
- file->close();
- memdelete(file);
- file = nullptr;
- data.clear();
+ unsigned char iv[16];
+ for (int i = 0; i < 16; i++) {
+ iv[i] = Math::rand() % 256;
+ file->store_8(iv[i]);
+ }
- } else {
- file->close();
- memdelete(file);
+ ctx.encrypt_cfb(len, iv, compressed.ptrw(), compressed.ptrw());
+
+ file->store_buffer(compressed.ptr(), compressed.size());
data.clear();
- file = nullptr;
}
}
diff --git a/core/io/file_access_encrypted.h b/core/io/file_access_encrypted.h
index e269c1e30c..c760933038 100644
--- a/core/io/file_access_encrypted.h
+++ b/core/io/file_access_encrypted.h
@@ -33,6 +33,8 @@
#include "core/os/file_access.h"
+#define ENCRYPTED_HEADER_MAGIC 0x43454447
+
class FileAccessEncrypted : public FileAccess {
public:
enum Mode {
@@ -42,22 +44,25 @@ public:
};
private:
- Mode mode = MODE_MAX;
Vector<uint8_t> key;
bool writing = false;
FileAccess *file = nullptr;
- size_t base;
- size_t length;
+ size_t base = 0;
+ size_t length = 0;
Vector<uint8_t> data;
mutable int pos = 0;
mutable bool eofed = false;
+ bool use_magic = true;
+
+ void _release();
public:
- Error open_and_parse(FileAccess *p_base, const Vector<uint8_t> &p_key, Mode p_mode);
+ Error open_and_parse(FileAccess *p_base, const Vector<uint8_t> &p_key, Mode p_mode, bool p_with_magic = true);
Error open_and_parse_password(FileAccess *p_base, const String &p_key, Mode p_mode);
virtual Error _open(const String &p_path, int p_mode_flags); ///< open a file
virtual void close(); ///< close a file
+ virtual void release(); ///< finish and keep base file open
virtual bool is_open() const; ///< true when file is open
virtual String get_path() const; /// returns the path for the current open file
diff --git a/core/io/file_access_memory.cpp b/core/io/file_access_memory.cpp
index a65ff92a89..79cba63765 100644
--- a/core/io/file_access_memory.cpp
+++ b/core/io/file_access_memory.cpp
@@ -30,10 +30,10 @@
#include "file_access_memory.h"
-#include "core/map.h"
+#include "core/config/project_settings.h"
#include "core/os/copymem.h"
#include "core/os/dir_access.h"
-#include "core/project_settings.h"
+#include "core/templates/map.h"
static Map<String, Vector<uint8_t>> *files = nullptr;
diff --git a/core/io/file_access_memory.h b/core/io/file_access_memory.h
index 1a9bd3fbbb..47012b4e83 100644
--- a/core/io/file_access_memory.h
+++ b/core/io/file_access_memory.h
@@ -35,8 +35,8 @@
class FileAccessMemory : public FileAccess {
uint8_t *data = nullptr;
- int length;
- mutable int pos;
+ int length = 0;
+ mutable int pos = 0;
static FileAccess *create();
diff --git a/core/io/file_access_network.cpp b/core/io/file_access_network.cpp
index 6890740d90..1e9266f118 100644
--- a/core/io/file_access_network.cpp
+++ b/core/io/file_access_network.cpp
@@ -30,10 +30,10 @@
#include "file_access_network.h"
+#include "core/config/project_settings.h"
#include "core/io/ip.h"
#include "core/io/marshalls.h"
#include "core/os/os.h"
-#include "core/project_settings.h"
//#define DEBUG_PRINT(m_p) print_line(m_p)
//#define DEBUG_TIME(m_what) printf("MS: %s - %lli\n",m_what,OS::get_singleton()->get_ticks_usec());
diff --git a/core/io/file_access_pack.cpp b/core/io/file_access_pack.cpp
index 37240f234a..a025ca5730 100644
--- a/core/io/file_access_pack.cpp
+++ b/core/io/file_access_pack.cpp
@@ -30,13 +30,15 @@
#include "file_access_pack.h"
+#include "core/io/file_access_encrypted.h"
+#include "core/object/script_language.h"
#include "core/version.h"
#include <stdio.h>
-Error PackedData::add_pack(const String &p_path, bool p_replace_files) {
+Error PackedData::add_pack(const String &p_path, bool p_replace_files, size_t p_offset) {
for (int i = 0; i < sources.size(); i++) {
- if (sources[i]->try_open_pack(p_path, p_replace_files)) {
+ if (sources[i]->try_open_pack(p_path, p_replace_files, p_offset)) {
return OK;
}
}
@@ -44,13 +46,14 @@ Error PackedData::add_pack(const String &p_path, bool p_replace_files) {
return ERR_FILE_UNRECOGNIZED;
}
-void PackedData::add_path(const String &pkg_path, const String &path, uint64_t ofs, uint64_t size, const uint8_t *p_md5, PackSource *p_src, bool p_replace_files) {
+void PackedData::add_path(const String &pkg_path, const String &path, uint64_t ofs, uint64_t size, const uint8_t *p_md5, PackSource *p_src, bool p_replace_files, bool p_encrypted) {
PathMD5 pmd5(path.md5_buffer());
- //printf("adding path %ls, %lli, %lli\n", path.c_str(), pmd5.a, pmd5.b);
+ //printf("adding path %s, %lli, %lli\n", path.utf8().get_data(), pmd5.a, pmd5.b);
bool exists = files.has(pmd5);
PackedFile pf;
+ pf.encrypted = p_encrypted;
pf.pack = pkg_path;
pf.offset = ofs;
pf.size = size;
@@ -123,15 +126,24 @@ PackedData::~PackedData() {
//////////////////////////////////////////////////////////////////
-bool PackedSourcePCK::try_open_pack(const String &p_path, bool p_replace_files) {
+bool PackedSourcePCK::try_open_pack(const String &p_path, bool p_replace_files, size_t p_offset) {
FileAccess *f = FileAccess::open(p_path, FileAccess::READ);
if (!f) {
return false;
}
+ f->seek(p_offset);
+
uint32_t magic = f->get_32();
if (magic != PACK_HEADER_MAGIC) {
+ // loading with offset feature not supported for self contained exe files
+ if (p_offset != 0) {
+ f->close();
+ memdelete(f);
+ ERR_FAIL_V_MSG(false, "Loading self-contained executable with offset not supported.");
+ }
+
//maybe at the end.... self contained exe
f->seek_end();
f->seek(f->get_position() - 4);
@@ -170,6 +182,11 @@ bool PackedSourcePCK::try_open_pack(const String &p_path, bool p_replace_files)
ERR_FAIL_V_MSG(false, "Pack created with a newer version of the engine: " + itos(ver_major) + "." + itos(ver_minor) + ".");
}
+ uint32_t pack_flags = f->get_32();
+ uint64_t file_base = f->get_64();
+
+ bool enc_directory = (pack_flags & PACK_DIR_ENCRYPTED);
+
for (int i = 0; i < 16; i++) {
//reserved
f->get_32();
@@ -177,6 +194,30 @@ bool PackedSourcePCK::try_open_pack(const String &p_path, bool p_replace_files)
int file_count = f->get_32();
+ if (enc_directory) {
+ FileAccessEncrypted *fae = memnew(FileAccessEncrypted);
+ if (!fae) {
+ f->close();
+ memdelete(f);
+ ERR_FAIL_V_MSG(false, "Can't open encrypted pack directory.");
+ }
+
+ Vector<uint8_t> key;
+ key.resize(32);
+ for (int i = 0; i < key.size(); i++) {
+ key.write[i] = script_encryption_key[i];
+ }
+
+ Error err = fae->open_and_parse(f, key, FileAccessEncrypted::MODE_READ, false);
+ if (err) {
+ f->close();
+ memdelete(f);
+ memdelete(fae);
+ ERR_FAIL_V_MSG(false, "Can't open encrypted pack directory.");
+ }
+ f = fae;
+ }
+
for (int i = 0; i < file_count; i++) {
uint32_t sl = f->get_32();
CharString cs;
@@ -187,11 +228,13 @@ bool PackedSourcePCK::try_open_pack(const String &p_path, bool p_replace_files)
String path;
path.parse_utf8(cs.ptr());
- uint64_t ofs = f->get_64();
+ uint64_t ofs = file_base + f->get_64();
uint64_t size = f->get_64();
uint8_t md5[16];
f->get_buffer(md5, 16);
- PackedData::get_singleton()->add_path(p_path, path, ofs, size, md5, this, p_replace_files);
+ uint32_t flags = f->get_32();
+
+ PackedData::get_singleton()->add_path(p_path, path, ofs + p_offset, size, md5, this, p_replace_files, (flags & PACK_FILE_ENCRYPTED));
}
f->close();
@@ -225,7 +268,7 @@ void FileAccessPack::seek(size_t p_position) {
eof = false;
}
- f->seek(pf.offset + p_position);
+ f->seek(off + p_position);
pos = p_position;
}
@@ -310,12 +353,35 @@ FileAccessPack::FileAccessPack(const String &p_path, const PackedData::PackedFil
ERR_FAIL_COND_MSG(!f, "Can't open pack-referenced file '" + String(pf.pack) + "'.");
f->seek(pf.offset);
+ off = pf.offset;
+
+ if (pf.encrypted) {
+ FileAccessEncrypted *fae = memnew(FileAccessEncrypted);
+ if (!fae) {
+ ERR_FAIL_MSG("Can't open encrypted pack-referenced file '" + String(pf.pack) + "'.");
+ }
+
+ Vector<uint8_t> key;
+ key.resize(32);
+ for (int i = 0; i < key.size(); i++) {
+ key.write[i] = script_encryption_key[i];
+ }
+
+ Error err = fae->open_and_parse(f, key, FileAccessEncrypted::MODE_READ, false);
+ if (err) {
+ memdelete(fae);
+ ERR_FAIL_MSG("Can't open encrypted pack-referenced file '" + String(pf.pack) + "'.");
+ }
+ f = fae;
+ off = 0;
+ }
pos = 0;
eof = false;
}
FileAccessPack::~FileAccessPack() {
if (f) {
+ f->close();
memdelete(f);
}
}
@@ -376,8 +442,14 @@ String DirAccessPack::get_drive(int p_drive) {
return "";
}
-Error DirAccessPack::change_dir(String p_dir) {
+PackedData::PackedDir *DirAccessPack::_find_dir(String p_dir) {
String nd = p_dir.replace("\\", "/");
+
+ // Special handling since simplify_path() will forbid it
+ if (p_dir == "..") {
+ return current->parent;
+ }
+
bool absolute = false;
if (nd.begins_with("res://")) {
nd = nd.replace_first("res://", "");
@@ -417,13 +489,21 @@ Error DirAccessPack::change_dir(String p_dir) {
pd = pd->subdirs[p];
} else {
- return ERR_INVALID_PARAMETER;
+ return nullptr;
}
}
- current = pd;
+ return pd;
+}
- return OK;
+Error DirAccessPack::change_dir(String p_dir) {
+ PackedData::PackedDir *pd = _find_dir(p_dir);
+ if (pd) {
+ current = pd;
+ return OK;
+ } else {
+ return ERR_INVALID_PARAMETER;
+ }
}
String DirAccessPack::get_current_dir(bool p_include_drive) {
@@ -441,13 +521,17 @@ String DirAccessPack::get_current_dir(bool p_include_drive) {
bool DirAccessPack::file_exists(String p_file) {
p_file = fix_path(p_file);
- return current->files.has(p_file);
+ PackedData::PackedDir *pd = _find_dir(p_file.get_base_dir());
+ if (!pd) {
+ return false;
+ }
+ return pd->files.has(p_file.get_file());
}
bool DirAccessPack::dir_exists(String p_dir) {
p_dir = fix_path(p_dir);
- return current->subdirs.has(p_dir);
+ return _find_dir(p_dir) != nullptr;
}
Error DirAccessPack::make_dir(String p_dir) {
diff --git a/core/io/file_access_pack.h b/core/io/file_access_pack.h
index 348bc0c450..c13626a5aa 100644
--- a/core/io/file_access_pack.h
+++ b/core/io/file_access_pack.h
@@ -31,16 +31,24 @@
#ifndef FILE_ACCESS_PACK_H
#define FILE_ACCESS_PACK_H
-#include "core/list.h"
-#include "core/map.h"
#include "core/os/dir_access.h"
#include "core/os/file_access.h"
-#include "core/print_string.h"
+#include "core/string/print_string.h"
+#include "core/templates/list.h"
+#include "core/templates/map.h"
// Godot's packed file magic header ("GDPC" in ASCII).
#define PACK_HEADER_MAGIC 0x43504447
// The current packed file format version number.
-#define PACK_FORMAT_VERSION 1
+#define PACK_FORMAT_VERSION 2
+
+enum PackFlags {
+ PACK_DIR_ENCRYPTED = 1 << 0
+};
+
+enum PackFileFlags {
+ PACK_FILE_ENCRYPTED = 1 << 0
+};
class PackSource;
@@ -56,6 +64,7 @@ public:
uint64_t size;
uint8_t md5[16];
PackSource *src;
+ bool encrypted;
};
private:
@@ -102,31 +111,34 @@ private:
public:
void add_pack_source(PackSource *p_source);
- void add_path(const String &pkg_path, const String &path, uint64_t ofs, uint64_t size, const uint8_t *p_md5, PackSource *p_src, bool p_replace_files); // for PackSource
+ void add_path(const String &pkg_path, const String &path, uint64_t ofs, uint64_t size, const uint8_t *p_md5, PackSource *p_src, bool p_replace_files, bool p_encrypted = false); // for PackSource
void set_disabled(bool p_disabled) { disabled = p_disabled; }
_FORCE_INLINE_ bool is_disabled() const { return disabled; }
static PackedData *get_singleton() { return singleton; }
- Error add_pack(const String &p_path, bool p_replace_files);
+ Error add_pack(const String &p_path, bool p_replace_files, size_t p_offset);
_FORCE_INLINE_ FileAccess *try_open_path(const String &p_path);
_FORCE_INLINE_ bool has_path(const String &p_path);
+ _FORCE_INLINE_ DirAccess *try_open_directory(const String &p_path);
+ _FORCE_INLINE_ bool has_directory(const String &p_path);
+
PackedData();
~PackedData();
};
class PackSource {
public:
- virtual bool try_open_pack(const String &p_path, bool p_replace_files) = 0;
+ virtual bool try_open_pack(const String &p_path, bool p_replace_files, size_t p_offset) = 0;
virtual FileAccess *get_file(const String &p_path, PackedData::PackedFile *p_file) = 0;
virtual ~PackSource() {}
};
class PackedSourcePCK : public PackSource {
public:
- virtual bool try_open_pack(const String &p_path, bool p_replace_files);
+ virtual bool try_open_pack(const String &p_path, bool p_replace_files, size_t p_offset);
virtual FileAccess *get_file(const String &p_path, PackedData::PackedFile *p_file);
};
@@ -135,6 +147,7 @@ class FileAccessPack : public FileAccess {
mutable size_t pos;
mutable bool eof;
+ uint64_t off;
FileAccess *f;
virtual Error _open(const String &p_path, int p_mode_flags);
@@ -189,6 +202,16 @@ bool PackedData::has_path(const String &p_path) {
return files.has(PathMD5(p_path.md5_buffer()));
}
+bool PackedData::has_directory(const String &p_path) {
+ DirAccess *da = try_open_directory(p_path);
+ if (da) {
+ memdelete(da);
+ return true;
+ } else {
+ return false;
+ }
+}
+
class DirAccessPack : public DirAccess {
PackedData::PackedDir *current;
@@ -196,6 +219,8 @@ class DirAccessPack : public DirAccess {
List<String> list_files;
bool cdir = false;
+ PackedData::PackedDir *_find_dir(String p_dir);
+
public:
virtual Error list_dir_begin();
virtual String get_next();
@@ -225,4 +250,13 @@ public:
~DirAccessPack() {}
};
+DirAccess *PackedData::try_open_directory(const String &p_path) {
+ DirAccess *da = memnew(DirAccessPack());
+ if (da->change_dir(p_path) != OK) {
+ memdelete(da);
+ da = nullptr;
+ }
+ return da;
+}
+
#endif // FILE_ACCESS_PACK_H
diff --git a/core/io/file_access_zip.cpp b/core/io/file_access_zip.cpp
index c3a62706c7..1163c409bc 100644
--- a/core/io/file_access_zip.cpp
+++ b/core/io/file_access_zip.cpp
@@ -102,7 +102,6 @@ static voidpf godot_alloc(voidpf opaque, uInt items, uInt size) {
static void godot_free(voidpf opaque, voidpf address) {
memfree(address);
}
-
} // extern "C"
void ZipArchive::close_handle(unzFile p_file) const {
@@ -147,8 +146,11 @@ unzFile ZipArchive::get_file_handle(String p_file) const {
return pkg;
}
-bool ZipArchive::try_open_pack(const String &p_path, bool p_replace_files) {
- //printf("opening zip pack %ls, %i, %i\n", p_name.c_str(), p_name.extension().nocasecmp_to("zip"), p_name.extension().nocasecmp_to("pcz"));
+bool ZipArchive::try_open_pack(const String &p_path, bool p_replace_files, size_t p_offset = 0) {
+ //printf("opening zip pack %s, %i, %i\n", p_name.utf8().get_data(), p_name.extension().nocasecmp_to("zip"), p_name.extension().nocasecmp_to("pcz"));
+ // load with offset feature only supported for PCK files
+ ERR_FAIL_COND_V_MSG(p_offset != 0, false, "Invalid PCK data. Note that loading files with a non-zero offset isn't supported with ZIP archives.");
+
if (p_path.get_extension().nocasecmp_to("zip") != 0 && p_path.get_extension().nocasecmp_to("pcz") != 0) {
return false;
}
@@ -197,8 +199,8 @@ bool ZipArchive::try_open_pack(const String &p_path, bool p_replace_files) {
files[fname] = f;
uint8_t md5[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
- PackedData::get_singleton()->add_path(p_path, fname, 1, 0, md5, this, p_replace_files);
- //printf("packed data add path %ls, %ls\n", p_name.c_str(), fname.c_str());
+ PackedData::get_singleton()->add_path(p_path, fname, 1, 0, md5, this, p_replace_files, false);
+ //printf("packed data add path %s, %s\n", p_name.utf8().get_data(), fname.utf8().get_data());
if ((i + 1) < gi.number_entry) {
unzGoToNextFile(zfile);
diff --git a/core/io/file_access_zip.h b/core/io/file_access_zip.h
index 776e830f36..eff07c60e2 100644
--- a/core/io/file_access_zip.h
+++ b/core/io/file_access_zip.h
@@ -28,13 +28,13 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifdef MINIZIP_ENABLED
-
#ifndef FILE_ACCESS_ZIP_H
#define FILE_ACCESS_ZIP_H
+#ifdef MINIZIP_ENABLED
+
#include "core/io/file_access_pack.h"
-#include "core/map.h"
+#include "core/templates/map.h"
#include "thirdparty/minizip/unzip.h"
@@ -69,7 +69,7 @@ public:
bool file_exists(String p_name) const;
- virtual bool try_open_pack(const String &p_path, bool p_replace_files);
+ virtual bool try_open_pack(const String &p_path, bool p_replace_files, size_t p_offset);
FileAccess *get_file(const String &p_path, PackedData::PackedFile *p_file);
static ZipArchive *get_singleton();
@@ -79,7 +79,7 @@ public:
};
class FileAccessZip : public FileAccess {
- unzFile zfile;
+ unzFile zfile = nullptr;
unz_file_info64 file_info;
mutable bool at_eof;
@@ -113,6 +113,6 @@ public:
~FileAccessZip();
};
-#endif // FILE_ACCESS_ZIP_H
-
#endif // MINIZIP_ENABLED
+
+#endif // FILE_ACCESS_ZIP_H
diff --git a/core/io/http_client.cpp b/core/io/http_client.cpp
index 40debae9e5..768fcdbb14 100644
--- a/core/io/http_client.cpp
+++ b/core/io/http_client.cpp
@@ -96,6 +96,10 @@ Error HTTPClient::connect_to_host(const String &p_host, int p_port, bool p_ssl,
void HTTPClient::set_connection(const Ref<StreamPeer> &p_connection) {
ERR_FAIL_COND_MSG(p_connection.is_null(), "Connection is not a reference to a valid StreamPeer object.");
+ if (connection == p_connection) {
+ return;
+ }
+
close();
connection = p_connection;
status = STATUS_CONNECTED;
@@ -105,24 +109,41 @@ Ref<StreamPeer> HTTPClient::get_connection() const {
return connection;
}
+static bool _check_request_url(HTTPClient::Method p_method, const String &p_url) {
+ switch (p_method) {
+ case HTTPClient::METHOD_CONNECT: {
+ // Authority in host:port format, as in RFC7231
+ int pos = p_url.find_char(':');
+ return 0 < pos && pos < p_url.length() - 1;
+ }
+ case HTTPClient::METHOD_OPTIONS: {
+ if (p_url == "*") {
+ return true;
+ }
+ [[fallthrough]];
+ }
+ default:
+ // Absolute path or absolute URL
+ return p_url.begins_with("/") || p_url.begins_with("http://") || p_url.begins_with("https://");
+ }
+}
+
Error HTTPClient::request_raw(Method p_method, const String &p_url, const Vector<String> &p_headers, const Vector<uint8_t> &p_body) {
ERR_FAIL_INDEX_V(p_method, METHOD_MAX, ERR_INVALID_PARAMETER);
- ERR_FAIL_COND_V(!p_url.begins_with("/"), ERR_INVALID_PARAMETER);
+ ERR_FAIL_COND_V(!_check_request_url(p_method, p_url), ERR_INVALID_PARAMETER);
ERR_FAIL_COND_V(status != STATUS_CONNECTED, ERR_INVALID_PARAMETER);
ERR_FAIL_COND_V(connection.is_null(), ERR_INVALID_DATA);
String request = String(_methods[p_method]) + " " + p_url + " HTTP/1.1\r\n";
- if ((ssl && conn_port == PORT_HTTPS) || (!ssl && conn_port == PORT_HTTP)) {
- // Don't append the standard ports
- request += "Host: " + conn_host + "\r\n";
- } else {
- request += "Host: " + conn_host + ":" + itos(conn_port) + "\r\n";
- }
+ bool add_host = true;
bool add_clen = p_body.size() > 0;
bool add_uagent = true;
bool add_accept = true;
for (int i = 0; i < p_headers.size(); i++) {
request += p_headers[i] + "\r\n";
+ if (add_host && p_headers[i].findn("Host:") == 0) {
+ add_host = false;
+ }
if (add_clen && p_headers[i].findn("Content-Length:") == 0) {
add_clen = false;
}
@@ -133,6 +154,14 @@ Error HTTPClient::request_raw(Method p_method, const String &p_url, const Vector
add_accept = false;
}
}
+ if (add_host) {
+ if ((ssl && conn_port == PORT_HTTPS) || (!ssl && conn_port == PORT_HTTP)) {
+ // Don't append the standard ports
+ request += "Host: " + conn_host + "\r\n";
+ } else {
+ request += "Host: " + conn_host + ":" + itos(conn_port) + "\r\n";
+ }
+ }
if (add_clen) {
request += "Content-Length: " + itos(p_body.size()) + "\r\n";
// Should it add utf8 encoding?
@@ -174,22 +203,20 @@ Error HTTPClient::request_raw(Method p_method, const String &p_url, const Vector
Error HTTPClient::request(Method p_method, const String &p_url, const Vector<String> &p_headers, const String &p_body) {
ERR_FAIL_INDEX_V(p_method, METHOD_MAX, ERR_INVALID_PARAMETER);
- ERR_FAIL_COND_V(!p_url.begins_with("/"), ERR_INVALID_PARAMETER);
+ ERR_FAIL_COND_V(!_check_request_url(p_method, p_url), ERR_INVALID_PARAMETER);
ERR_FAIL_COND_V(status != STATUS_CONNECTED, ERR_INVALID_PARAMETER);
ERR_FAIL_COND_V(connection.is_null(), ERR_INVALID_DATA);
String request = String(_methods[p_method]) + " " + p_url + " HTTP/1.1\r\n";
- if ((ssl && conn_port == PORT_HTTPS) || (!ssl && conn_port == PORT_HTTP)) {
- // Don't append the standard ports
- request += "Host: " + conn_host + "\r\n";
- } else {
- request += "Host: " + conn_host + ":" + itos(conn_port) + "\r\n";
- }
+ bool add_host = true;
bool add_uagent = true;
bool add_accept = true;
bool add_clen = p_body.length() > 0;
for (int i = 0; i < p_headers.size(); i++) {
request += p_headers[i] + "\r\n";
+ if (add_host && p_headers[i].findn("Host:") == 0) {
+ add_host = false;
+ }
if (add_clen && p_headers[i].findn("Content-Length:") == 0) {
add_clen = false;
}
@@ -200,6 +227,14 @@ Error HTTPClient::request(Method p_method, const String &p_url, const Vector<Str
add_accept = false;
}
}
+ if (add_host) {
+ if ((ssl && conn_port == PORT_HTTPS) || (!ssl && conn_port == PORT_HTTP)) {
+ // Don't append the standard ports
+ request += "Host: " + conn_host + "\r\n";
+ } else {
+ request += "Host: " + conn_host + ":" + itos(conn_port) + "\r\n";
+ }
+ }
if (add_clen) {
request += "Content-Length: " + itos(p_body.utf8().length()) + "\r\n";
// Should it add utf8 encoding?
@@ -451,7 +486,7 @@ Error HTTPClient::poll() {
}
}
- // This is a HEAD request, we wont receive anything.
+ // This is a HEAD request, we won't receive anything.
if (head_request) {
body_size = 0;
body_left = 0;
diff --git a/core/io/http_client.h b/core/io/http_client.h
index 1dc1f3d76a..3d9fe321ba 100644
--- a/core/io/http_client.h
+++ b/core/io/http_client.h
@@ -34,14 +34,13 @@
#include "core/io/ip.h"
#include "core/io/stream_peer.h"
#include "core/io/stream_peer_tcp.h"
-#include "core/reference.h"
+#include "core/object/reference.h"
class HTTPClient : public Reference {
GDCLASS(HTTPClient, Reference);
public:
enum ResponseCode {
-
// 1xx informational
RESPONSE_CONTINUE = 100,
RESPONSE_SWITCHING_PROTOCOLS = 101,
@@ -116,7 +115,6 @@ public:
};
enum Method {
-
METHOD_GET,
METHOD_HEAD,
METHOD_POST,
@@ -131,7 +129,6 @@ public:
};
enum Status {
-
STATUS_DISCONNECTED,
STATUS_RESOLVING, // Resolving hostname (if passed a hostname)
STATUS_CANT_RESOLVE,
@@ -150,7 +147,6 @@ private:
static const int HOST_MIN_LEN = 4;
enum Port {
-
PORT_HTTP = 80,
PORT_HTTPS = 443,
@@ -182,7 +178,8 @@ private:
int response_num = 0;
Vector<String> response_headers;
- int read_chunk_size = 4096;
+ // 64 KiB by default (favors fast download speeds at the cost of memory usage).
+ int read_chunk_size = 65536;
Error _get_http_data(uint8_t *p_buffer, int p_bytes, int &r_received);
diff --git a/core/image.cpp b/core/io/image.cpp
index e2f353698f..6dde25af32 100644
--- a/core/image.cpp
+++ b/core/io/image.cpp
@@ -30,13 +30,13 @@
#include "image.h"
-#include "core/error_macros.h"
-#include "core/hash_map.h"
+#include "core/error/error_macros.h"
#include "core/io/image_loader.h"
#include "core/io/resource_loader.h"
#include "core/math/math_funcs.h"
#include "core/os/copymem.h"
-#include "core/print_string.h"
+#include "core/string/print_string.h"
+#include "core/templates/hash_map.h"
#include <stdio.h>
@@ -80,7 +80,6 @@ const char *Image::format_names[Image::FORMAT_MAX] = {
"ETC2_RGB8A1",
"ETC2_RA_AS_RG",
"FORMAT_DXT5_RA_AS_RG",
-
};
SavePNGFunc Image::save_png_func = nullptr;
@@ -363,6 +362,82 @@ void Image::get_mipmap_offset_size_and_dimensions(int p_mipmap, int &r_ofs, int
r_size = ofs2 - ofs;
}
+Image::Image3DValidateError Image::validate_3d_image(Image::Format p_format, int p_width, int p_height, int p_depth, bool p_mipmaps, const Vector<Ref<Image>> &p_images) {
+ int w = p_width;
+ int h = p_height;
+ int d = p_depth;
+
+ int arr_ofs = 0;
+
+ while (true) {
+ for (int i = 0; i < d; i++) {
+ int idx = i + arr_ofs;
+ if (idx >= p_images.size()) {
+ return VALIDATE_3D_ERR_MISSING_IMAGES;
+ }
+ if (p_images[idx].is_null() || p_images[idx]->empty()) {
+ return VALIDATE_3D_ERR_IMAGE_EMPTY;
+ }
+ if (p_images[idx]->get_format() != p_format) {
+ return VALIDATE_3D_ERR_IMAGE_FORMAT_MISMATCH;
+ }
+ if (p_images[idx]->get_width() != w || p_images[idx]->get_height() != h) {
+ return VALIDATE_3D_ERR_IMAGE_SIZE_MISMATCH;
+ }
+ if (p_images[idx]->has_mipmaps()) {
+ return VALIDATE_3D_ERR_IMAGE_HAS_MIPMAPS;
+ }
+ }
+
+ arr_ofs += d;
+
+ if (!p_mipmaps) {
+ break;
+ }
+
+ if (w == 1 && h == 1 && d == 1) {
+ break;
+ }
+
+ w = MAX(1, w >> 1);
+ h = MAX(1, h >> 1);
+ d = MAX(1, d >> 1);
+ }
+
+ if (arr_ofs != p_images.size()) {
+ return VALIDATE_3D_ERR_EXTRA_IMAGES;
+ }
+
+ return VALIDATE_3D_OK;
+}
+
+String Image::get_3d_image_validation_error_text(Image3DValidateError p_error) {
+ switch (p_error) {
+ case VALIDATE_3D_OK: {
+ return TTR("Ok");
+ } break;
+ case VALIDATE_3D_ERR_IMAGE_EMPTY: {
+ return TTR("Empty Image found");
+ } break;
+ case VALIDATE_3D_ERR_MISSING_IMAGES: {
+ return TTR("Missing Images");
+ } break;
+ case VALIDATE_3D_ERR_EXTRA_IMAGES: {
+ return TTR("Too many Images");
+ } break;
+ case VALIDATE_3D_ERR_IMAGE_SIZE_MISMATCH: {
+ return TTR("Image size mismatch");
+ } break;
+ case VALIDATE_3D_ERR_IMAGE_FORMAT_MISMATCH: {
+ return TTR("Image format mismatch");
+ } break;
+ case VALIDATE_3D_ERR_IMAGE_HAS_MIPMAPS: {
+ return TTR("Image has included mipmaps");
+ } break;
+ }
+ return String();
+}
+
int Image::get_width() const {
return width;
}
@@ -2635,6 +2710,7 @@ ImageMemLoadFunc Image::_png_mem_loader_func = nullptr;
ImageMemLoadFunc Image::_jpg_mem_loader_func = nullptr;
ImageMemLoadFunc Image::_webp_mem_loader_func = nullptr;
ImageMemLoadFunc Image::_tga_mem_loader_func = nullptr;
+ImageMemLoadFunc Image::_bmp_mem_loader_func = nullptr;
void (*Image::_image_compress_bc_func)(Image *, float, Image::UsedChannels) = nullptr;
void (*Image::_image_compress_bptc_func)(Image *, float, Image::UsedChannels) = nullptr;
@@ -2690,8 +2766,8 @@ Dictionary Image::_get_data() const {
return d;
}
-Color Image::get_pixelv(const Point2 &p_src) const {
- return get_pixel(p_src.x, p_src.y);
+Color Image::get_pixelv(const Point2i &p_point) const {
+ return get_pixel(p_point.x, p_point.y);
}
Color Image::_get_color_at_ofs(const uint8_t *ptr, uint32_t ofs) const {
@@ -2900,8 +2976,8 @@ Color Image::get_pixel(int p_x, int p_y) const {
return _get_color_at_ofs(data.ptr(), ofs);
}
-void Image::set_pixelv(const Point2 &p_dst, const Color &p_color) {
- set_pixel(p_dst.x, p_dst.y, p_color);
+void Image::set_pixelv(const Point2i &p_point, const Color &p_color) {
+ set_pixel(p_point.x, p_point.y, p_color);
}
void Image::set_pixel(int p_x, int p_y, const Color &p_color) {
@@ -3056,15 +3132,16 @@ void Image::_bind_methods() {
ClassDB::bind_method(D_METHOD("_set_data", "data"), &Image::_set_data);
ClassDB::bind_method(D_METHOD("_get_data"), &Image::_get_data);
- ClassDB::bind_method(D_METHOD("get_pixelv", "src"), &Image::get_pixelv);
+ ClassDB::bind_method(D_METHOD("get_pixelv", "point"), &Image::get_pixelv);
ClassDB::bind_method(D_METHOD("get_pixel", "x", "y"), &Image::get_pixel);
- ClassDB::bind_method(D_METHOD("set_pixelv", "dst", "color"), &Image::set_pixelv);
+ ClassDB::bind_method(D_METHOD("set_pixelv", "point", "color"), &Image::set_pixelv);
ClassDB::bind_method(D_METHOD("set_pixel", "x", "y", "color"), &Image::set_pixel);
ClassDB::bind_method(D_METHOD("load_png_from_buffer", "buffer"), &Image::load_png_from_buffer);
ClassDB::bind_method(D_METHOD("load_jpg_from_buffer", "buffer"), &Image::load_jpg_from_buffer);
ClassDB::bind_method(D_METHOD("load_webp_from_buffer", "buffer"), &Image::load_webp_from_buffer);
ClassDB::bind_method(D_METHOD("load_tga_from_buffer", "buffer"), &Image::load_tga_from_buffer);
+ ClassDB::bind_method(D_METHOD("load_bmp_from_buffer", "buffer"), &Image::load_bmp_from_buffer);
ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "_set_data", "_get_data");
@@ -3397,10 +3474,21 @@ Error Image::load_webp_from_buffer(const Vector<uint8_t> &p_array) {
}
Error Image::load_tga_from_buffer(const Vector<uint8_t> &p_array) {
- ERR_FAIL_NULL_V_MSG(_tga_mem_loader_func, ERR_UNAVAILABLE, "TGA module was not installed.");
+ ERR_FAIL_NULL_V_MSG(
+ _tga_mem_loader_func,
+ ERR_UNAVAILABLE,
+ "The TGA module isn't enabled. Recompile the Godot editor or export template binary with the `module_tga_enabled=yes` SCons option.");
return _load_from_buffer(p_array, _tga_mem_loader_func);
}
+Error Image::load_bmp_from_buffer(const Vector<uint8_t> &p_array) {
+ ERR_FAIL_NULL_V_MSG(
+ _bmp_mem_loader_func,
+ ERR_UNAVAILABLE,
+ "The BMP module isn't enabled. Recompile the Godot editor or export template binary with the `module_bmp_enabled=yes` SCons option.");
+ return _load_from_buffer(p_array, _bmp_mem_loader_func);
+}
+
void Image::convert_rg_to_ra_rgba8() {
ERR_FAIL_COND(format != FORMAT_RGBA8);
ERR_FAIL_COND(!data.size());
diff --git a/core/image.h b/core/io/image.h
index 711bf5721c..c4c84589e5 100644
--- a/core/image.h
+++ b/core/io/image.h
@@ -31,9 +31,9 @@
#ifndef IMAGE_H
#define IMAGE_H
-#include "core/color.h"
+#include "core/io/resource.h"
+#include "core/math/color.h"
#include "core/math/rect2.h"
-#include "core/resource.h"
/**
* @author Juan Linietsky <reduzio@gmail.com>
@@ -66,7 +66,6 @@ public:
};
enum Format {
-
FORMAT_L8, //luminance
FORMAT_LA8, //luminance-alpha
FORMAT_R8,
@@ -111,7 +110,6 @@ public:
static const char *format_names[FORMAT_MAX];
enum Interpolation {
-
INTERPOLATE_NEAREST,
INTERPOLATE_BILINEAR,
INTERPOLATE_CUBIC,
@@ -136,6 +134,7 @@ public:
static ImageMemLoadFunc _jpg_mem_loader_func;
static ImageMemLoadFunc _webp_mem_loader_func;
static ImageMemLoadFunc _tga_mem_loader_func;
+ static ImageMemLoadFunc _bmp_mem_loader_func;
static void (*_image_compress_bc_func)(Image *, float, UsedChannels p_channels);
static void (*_image_compress_bptc_func)(Image *, float p_lossy_quality, UsedChannels p_channels);
@@ -230,6 +229,19 @@ public:
void get_mipmap_offset_and_size(int p_mipmap, int &r_ofs, int &r_size) const; //get where the mipmap begins in data
void get_mipmap_offset_size_and_dimensions(int p_mipmap, int &r_ofs, int &r_size, int &w, int &h) const; //get where the mipmap begins in data
+ enum Image3DValidateError {
+ VALIDATE_3D_OK,
+ VALIDATE_3D_ERR_IMAGE_EMPTY,
+ VALIDATE_3D_ERR_MISSING_IMAGES,
+ VALIDATE_3D_ERR_EXTRA_IMAGES,
+ VALIDATE_3D_ERR_IMAGE_SIZE_MISMATCH,
+ VALIDATE_3D_ERR_IMAGE_FORMAT_MISMATCH,
+ VALIDATE_3D_ERR_IMAGE_HAS_MIPMAPS,
+ };
+
+ static Image3DValidateError validate_3d_image(Format p_format, int p_width, int p_height, int p_depth, bool p_mipmaps, const Vector<Ref<Image>> &p_images);
+ static String get_3d_image_validation_error_text(Image3DValidateError p_error);
+
/**
* Resize the image, using the preferred interpolation method.
*/
@@ -362,6 +374,7 @@ public:
Error load_jpg_from_buffer(const Vector<uint8_t> &p_array);
Error load_webp_from_buffer(const Vector<uint8_t> &p_array);
Error load_tga_from_buffer(const Vector<uint8_t> &p_array);
+ Error load_bmp_from_buffer(const Vector<uint8_t> &p_array);
void convert_rg_to_ra_rgba8();
void convert_ra_rgba8_to_rg();
@@ -369,14 +382,14 @@ public:
Image(const uint8_t *p_mem_png_jpg, int p_len = -1);
Image(const char **p_xpm);
- virtual Ref<Resource> duplicate(bool p_subresources = false) const;
+ virtual Ref<Resource> duplicate(bool p_subresources = false) const override;
UsedChannels detect_used_channels(CompressSource p_source = COMPRESS_SOURCE_GENERIC);
void optimize_channels();
- Color get_pixelv(const Point2 &p_src) const;
+ Color get_pixelv(const Point2i &p_point) const;
Color get_pixel(int p_x, int p_y) const;
- void set_pixelv(const Point2 &p_dst, const Color &p_color);
+ void set_pixelv(const Point2i &p_point, const Color &p_color);
void set_pixel(int p_x, int p_y, const Color &p_color);
void set_as_black();
diff --git a/core/io/image_loader.cpp b/core/io/image_loader.cpp
index b1e92eb87f..f6d8668349 100644
--- a/core/io/image_loader.cpp
+++ b/core/io/image_loader.cpp
@@ -30,7 +30,7 @@
#include "image_loader.h"
-#include "core/print_string.h"
+#include "core/string/print_string.h"
bool ImageFormatLoader::recognize(const String &p_extension) const {
List<String> extensions;
diff --git a/core/io/image_loader.h b/core/io/image_loader.h
index 9682f144c7..d5fb4678eb 100644
--- a/core/io/image_loader.h
+++ b/core/io/image_loader.h
@@ -31,11 +31,11 @@
#ifndef IMAGE_LOADER_H
#define IMAGE_LOADER_H
-#include "core/image.h"
+#include "core/io/image.h"
#include "core/io/resource_loader.h"
-#include "core/list.h"
#include "core/os/file_access.h"
-#include "core/ustring.h"
+#include "core/string/ustring.h"
+#include "core/templates/list.h"
class ImageLoader;
diff --git a/core/io/ip.cpp b/core/io/ip.cpp
index 24b8ec7cc1..9f3540efad 100644
--- a/core/io/ip.cpp
+++ b/core/io/ip.cpp
@@ -30,9 +30,9 @@
#include "ip.h"
-#include "core/hash_map.h"
#include "core/os/semaphore.h"
#include "core/os/thread.h"
+#include "core/templates/hash_map.h"
VARIANT_ENUM_CAST(IP::ResolverStatus);
diff --git a/core/io/ip.h b/core/io/ip.h
index d434d02f9b..32572b8eb2 100644
--- a/core/io/ip.h
+++ b/core/io/ip.h
@@ -42,7 +42,6 @@ class IP : public Object {
public:
enum ResolverStatus {
-
RESOLVER_STATUS_NONE,
RESOLVER_STATUS_WAITING,
RESOLVER_STATUS_DONE,
@@ -50,7 +49,6 @@ public:
};
enum Type {
-
TYPE_NONE = 0,
TYPE_IPV4 = 1,
TYPE_IPV6 = 2,
diff --git a/core/io/ip_address.cpp b/core/io/ip_address.cpp
index c7a0ae5605..7d730e5ae8 100644
--- a/core/io/ip_address.cpp
+++ b/core/io/ip_address.cpp
@@ -31,7 +31,6 @@
#include "ip_address.h"
/*
IP_Address::operator Variant() const {
-
return operator String();
}*/
@@ -71,7 +70,7 @@ static void _parse_hex(const String &p_string, int p_start, uint8_t *p_dst) {
}
int n = 0;
- CharType c = p_string[i];
+ char32_t c = p_string[i];
if (c >= '0' && c <= '9') {
n = c - '0';
} else if (c >= 'a' && c <= 'f') {
@@ -101,7 +100,7 @@ void IP_Address::_parse_ipv6(const String &p_string) {
int parts_idx = 0;
for (int i = 0; i < p_string.length(); i++) {
- CharType c = p_string[i];
+ char32_t c = p_string[i];
if (c == ':') {
if (i == 0) {
continue; // next must be a ":"
diff --git a/core/io/ip_address.h b/core/io/ip_address.h
index 2f8f83503e..7a813230f5 100644
--- a/core/io/ip_address.h
+++ b/core/io/ip_address.h
@@ -31,7 +31,7 @@
#ifndef IP_ADDRESS_H
#define IP_ADDRESS_H
-#include "core/ustring.h"
+#include "core/string/ustring.h"
struct IP_Address {
private:
diff --git a/core/io/json.cpp b/core/io/json.cpp
index 1c603865ad..d61c2b8236 100644
--- a/core/io/json.cpp
+++ b/core/io/json.cpp
@@ -30,7 +30,7 @@
#include "json.h"
-#include "core/print_string.h"
+#include "core/string/print_string.h"
const char *JSON::tk_name[TK_MAX] = {
"'{'",
@@ -125,7 +125,7 @@ String JSON::print(const Variant &p_var, const String &p_indent, bool p_sort_key
return _print_var(p_var, p_indent, 0, p_sort_keys);
}
-Error JSON::_get_token(const CharType *p_str, int &index, int p_len, Token &r_token, int &line, String &r_err_str) {
+Error JSON::_get_token(const char32_t *p_str, int &index, int p_len, Token &r_token, int &line, String &r_err_str) {
while (p_len > 0) {
switch (p_str[index]) {
case '\n': {
@@ -180,12 +180,12 @@ Error JSON::_get_token(const CharType *p_str, int &index, int p_len, Token &r_to
} else if (p_str[index] == '\\') {
//escaped characters...
index++;
- CharType next = p_str[index];
+ char32_t next = p_str[index];
if (next == 0) {
r_err_str = "Unterminated String";
return ERR_PARSE_ERROR;
}
- CharType res = 0;
+ char32_t res = 0;
switch (next) {
case 'b':
@@ -206,7 +206,7 @@ Error JSON::_get_token(const CharType *p_str, int &index, int p_len, Token &r_to
case 'u': {
// hex number
for (int j = 0; j < 4; j++) {
- CharType c = p_str[index + j + 1];
+ char32_t c = p_str[index + j + 1];
if (c == 0) {
r_err_str = "Unterminated String";
return ERR_PARSE_ERROR;
@@ -215,7 +215,7 @@ Error JSON::_get_token(const CharType *p_str, int &index, int p_len, Token &r_to
r_err_str = "Malformed hex constant in string";
return ERR_PARSE_ERROR;
}
- CharType v;
+ char32_t v;
if (c >= '0' && c <= '9') {
v = c - '0';
} else if (c >= 'a' && c <= 'f') {
@@ -264,8 +264,8 @@ Error JSON::_get_token(const CharType *p_str, int &index, int p_len, Token &r_to
if (p_str[index] == '-' || (p_str[index] >= '0' && p_str[index] <= '9')) {
//a number
- const CharType *rptr;
- double number = String::to_double(&p_str[index], &rptr);
+ const char32_t *rptr;
+ double number = String::to_float(&p_str[index], &rptr);
index += (rptr - &p_str[index]);
r_token.type = TK_NUMBER;
r_token.value = number;
@@ -293,7 +293,7 @@ Error JSON::_get_token(const CharType *p_str, int &index, int p_len, Token &r_to
return ERR_PARSE_ERROR;
}
-Error JSON::_parse_value(Variant &value, Token &token, const CharType *p_str, int &index, int p_len, int &line, String &r_err_str) {
+Error JSON::_parse_value(Variant &value, Token &token, const char32_t *p_str, int &index, int p_len, int &line, String &r_err_str) {
if (token.type == TK_CURLY_BRACKET_OPEN) {
Dictionary d;
Error err = _parse_object(d, p_str, index, p_len, line, r_err_str);
@@ -337,7 +337,7 @@ Error JSON::_parse_value(Variant &value, Token &token, const CharType *p_str, in
}
}
-Error JSON::_parse_array(Array &array, const CharType *p_str, int &index, int p_len, int &line, String &r_err_str) {
+Error JSON::_parse_array(Array &array, const char32_t *p_str, int &index, int p_len, int &line, String &r_err_str) {
Token token;
bool need_comma = false;
@@ -371,10 +371,11 @@ Error JSON::_parse_array(Array &array, const CharType *p_str, int &index, int p_
need_comma = true;
}
+ r_err_str = "Expected ']'";
return ERR_PARSE_ERROR;
}
-Error JSON::_parse_object(Dictionary &object, const CharType *p_str, int &index, int p_len, int &line, String &r_err_str) {
+Error JSON::_parse_object(Dictionary &object, const char32_t *p_str, int &index, int p_len, int &line, String &r_err_str) {
bool at_key = true;
String key;
Token token;
@@ -433,11 +434,12 @@ Error JSON::_parse_object(Dictionary &object, const CharType *p_str, int &index,
}
}
+ r_err_str = "Expected '}'";
return ERR_PARSE_ERROR;
}
Error JSON::parse(const String &p_json, Variant &r_ret, String &r_err_str, int &r_err_line) {
- const CharType *str = p_json.ptr();
+ const char32_t *str = p_json.ptr();
int idx = 0;
int len = p_json.length();
Token token;
@@ -453,3 +455,35 @@ Error JSON::parse(const String &p_json, Variant &r_ret, String &r_err_str, int &
return err;
}
+
+Error JSONParser::parse_string(const String &p_json_string) {
+ return JSON::parse(p_json_string, data, err_text, err_line);
+}
+String JSONParser::get_error_text() const {
+ return err_text;
+}
+int JSONParser::get_error_line() const {
+ return err_line;
+}
+Variant JSONParser::get_data() const {
+ return data;
+}
+
+Error JSONParser::decode_data(const Variant &p_data, const String &p_indent, bool p_sort_keys) {
+ string = JSON::print(p_data, p_indent, p_sort_keys);
+ data = p_data;
+ return OK;
+}
+
+String JSONParser::get_string() const {
+ return string;
+}
+
+void JSONParser::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("parse_string", "json_string"), &JSONParser::parse_string);
+ ClassDB::bind_method(D_METHOD("get_error_text"), &JSONParser::get_error_text);
+ ClassDB::bind_method(D_METHOD("get_error_line"), &JSONParser::get_error_line);
+ ClassDB::bind_method(D_METHOD("get_data"), &JSONParser::get_data);
+ ClassDB::bind_method(D_METHOD("decode_data", "data", "indent", "sort_keys"), &JSONParser::decode_data, DEFVAL(""), DEFVAL(true));
+ ClassDB::bind_method(D_METHOD("get_string"), &JSONParser::get_string);
+}
diff --git a/core/io/json.h b/core/io/json.h
index 4fc5630a93..431b252e55 100644
--- a/core/io/json.h
+++ b/core/io/json.h
@@ -31,8 +31,8 @@
#ifndef JSON_H
#define JSON_H
-#include "core/variant.h"
-
+#include "core/object/reference.h"
+#include "core/variant/variant.h"
class JSON {
enum TokenType {
TK_CURLY_BRACKET_OPEN,
@@ -49,7 +49,6 @@ class JSON {
};
enum Expecting {
-
EXPECT_OBJECT,
EXPECT_OBJECT_KEY,
EXPECT_COLON,
@@ -65,14 +64,35 @@ class JSON {
static String _print_var(const Variant &p_var, const String &p_indent, int p_cur_indent, bool p_sort_keys);
- static Error _get_token(const CharType *p_str, int &index, int p_len, Token &r_token, int &line, String &r_err_str);
- static Error _parse_value(Variant &value, Token &token, const CharType *p_str, int &index, int p_len, int &line, String &r_err_str);
- static Error _parse_array(Array &array, const CharType *p_str, int &index, int p_len, int &line, String &r_err_str);
- static Error _parse_object(Dictionary &object, const CharType *p_str, int &index, int p_len, int &line, String &r_err_str);
+ static Error _get_token(const char32_t *p_str, int &index, int p_len, Token &r_token, int &line, String &r_err_str);
+ static Error _parse_value(Variant &value, Token &token, const char32_t *p_str, int &index, int p_len, int &line, String &r_err_str);
+ static Error _parse_array(Array &array, const char32_t *p_str, int &index, int p_len, int &line, String &r_err_str);
+ static Error _parse_object(Dictionary &object, const char32_t *p_str, int &index, int p_len, int &line, String &r_err_str);
public:
static String print(const Variant &p_var, const String &p_indent = "", bool p_sort_keys = true);
static Error parse(const String &p_json, Variant &r_ret, String &r_err_str, int &r_err_line);
};
+class JSONParser : public Reference {
+ GDCLASS(JSONParser, Reference);
+
+ Variant data;
+ String string;
+ String err_text;
+ int err_line = 0;
+
+protected:
+ static void _bind_methods();
+
+public:
+ Error parse_string(const String &p_json_string);
+ String get_error_text() const;
+ int get_error_line() const;
+ Variant get_data() const;
+
+ Error decode_data(const Variant &p_data, const String &p_indent = "", bool p_sort_keys = true);
+ String get_string() const;
+};
+
#endif // JSON_H
diff --git a/core/io/logger.cpp b/core/io/logger.cpp
index ef78b1194e..0e6a2e2c9f 100644
--- a/core/io/logger.cpp
+++ b/core/io/logger.cpp
@@ -32,7 +32,7 @@
#include "core/os/dir_access.h"
#include "core/os/os.h"
-#include "core/print_string.h"
+#include "core/string/print_string.h"
#if defined(MINGW_ENABLED) || defined(_MSC_VER)
#define sprintf sprintf_s
@@ -152,7 +152,7 @@ void RotatedFileLogger::rotate_file() {
char timestamp[21];
OS::Date date = OS::get_singleton()->get_date();
OS::Time time = OS::get_singleton()->get_time();
- sprintf(timestamp, "-%04d-%02d-%02d-%02d-%02d-%02d", date.year, date.month, date.day, time.hour, time.min, time.sec);
+ sprintf(timestamp, "_%04d-%02d-%02d_%02d-%02d-%02d", date.year, date.month, date.day, time.hour, time.min, time.sec);
String backup_name = base_path.get_basename() + timestamp;
if (base_path.get_extension() != String()) {
diff --git a/core/io/logger.h b/core/io/logger.h
index 277be9ed35..9eaf506c51 100644
--- a/core/io/logger.h
+++ b/core/io/logger.h
@@ -32,8 +32,8 @@
#define LOGGER_H
#include "core/os/file_access.h"
-#include "core/ustring.h"
-#include "core/vector.h"
+#include "core/string/ustring.h"
+#include "core/templates/vector.h"
#include <stdarg.h>
diff --git a/core/io/marshalls.cpp b/core/io/marshalls.cpp
index eb39b1433f..3cf4acaf39 100644
--- a/core/io/marshalls.cpp
+++ b/core/io/marshalls.cpp
@@ -30,9 +30,9 @@
#include "marshalls.h"
+#include "core/object/reference.h"
#include "core/os/keyboard.h"
-#include "core/print_string.h"
-#include "core/reference.h"
+#include "core/string/print_string.h"
#include <limits.h>
#include <stdio.h>
@@ -420,7 +420,7 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int
}
} break;
- case Variant::_RID: {
+ case Variant::RID: {
r_variant = RID();
} break;
case Variant::OBJECT: {
@@ -1172,7 +1172,7 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo
r_len += 4 * 4;
} break;
- case Variant::_RID: {
+ case Variant::RID: {
} break;
case Variant::CALLABLE: {
} break;
diff --git a/core/io/marshalls.h b/core/io/marshalls.h
index c8ed497528..6969a9b500 100644
--- a/core/io/marshalls.h
+++ b/core/io/marshalls.h
@@ -31,9 +31,9 @@
#ifndef MARSHALLS_H
#define MARSHALLS_H
-#include "core/reference.h"
+#include "core/object/reference.h"
#include "core/typedefs.h"
-#include "core/variant.h"
+#include "core/variant/variant.h"
/**
* Miscellaneous helpers for marshalling data types, and encoding
diff --git a/core/io/multiplayer_api.h b/core/io/multiplayer_api.h
index 4a7ffe8279..ca52a1c689 100644
--- a/core/io/multiplayer_api.h
+++ b/core/io/multiplayer_api.h
@@ -32,7 +32,7 @@
#define MULTIPLAYER_API_H
#include "core/io/networked_multiplayer_peer.h"
-#include "core/reference.h"
+#include "core/object/reference.h"
class MultiplayerAPI : public Reference {
GDCLASS(MultiplayerAPI, Reference);
@@ -102,7 +102,6 @@ public:
};
enum RPCMode {
-
RPC_MODE_DISABLED, // No rpc for this method, calls to this will be blocked (default)
RPC_MODE_REMOTE, // Using rpc() on it will call method / set property in all remote peers
RPC_MODE_MASTER, // Using rpc() on it will call method on wherever the master is, be it local or remote
diff --git a/core/io/net_socket.h b/core/io/net_socket.h
index 746945eced..67d0253985 100644
--- a/core/io/net_socket.h
+++ b/core/io/net_socket.h
@@ -32,7 +32,7 @@
#define NET_SOCKET_H
#include "core/io/ip.h"
-#include "core/reference.h"
+#include "core/object/reference.h"
class NetSocket : public Reference {
protected:
diff --git a/core/packed_data_container.cpp b/core/io/packed_data_container.cpp
index e335ec0daa..fbe8fa8a28 100644
--- a/core/packed_data_container.cpp
+++ b/core/io/packed_data_container.cpp
@@ -39,6 +39,9 @@ Variant PackedDataContainer::getvar(const Variant &p_key, bool *r_valid) const {
if (r_valid) {
*r_valid = !err;
}
+ if (err) {
+ return Object::getvar(p_key, r_valid);
+ }
return ret;
}
@@ -243,7 +246,7 @@ uint32_t PackedDataContainer::_pack(const Variant &p_data, Vector<uint8_t> &tmpd
} break;
// misc types
- case Variant::_RID:
+ case Variant::RID:
case Variant::OBJECT: {
return _pack(Variant(), tmpdata, string_cache);
} break;
diff --git a/core/packed_data_container.h b/core/io/packed_data_container.h
index b41e9aaefc..3899c14bb4 100644
--- a/core/packed_data_container.h
+++ b/core/io/packed_data_container.h
@@ -31,7 +31,7 @@
#ifndef PACKED_DATA_CONTAINER_H
#define PACKED_DATA_CONTAINER_H
-#include "core/resource.h"
+#include "core/io/resource.h"
class PackedDataContainer : public Resource {
GDCLASS(PackedDataContainer, Resource);
@@ -72,7 +72,7 @@ protected:
static void _bind_methods();
public:
- virtual Variant getvar(const Variant &p_key, bool *r_valid = nullptr) const;
+ virtual Variant getvar(const Variant &p_key, bool *r_valid = nullptr) const override;
Error pack(const Variant &p_data);
int size() const;
@@ -84,7 +84,7 @@ class PackedDataContainerRef : public Reference {
GDCLASS(PackedDataContainerRef, Reference);
friend class PackedDataContainer;
- uint32_t offset;
+ uint32_t offset = 0;
Ref<PackedDataContainer> from;
protected:
@@ -97,7 +97,7 @@ public:
bool _is_dictionary() const;
int size() const;
- virtual Variant getvar(const Variant &p_key, bool *r_valid = nullptr) const;
+ virtual Variant getvar(const Variant &p_key, bool *r_valid = nullptr) const override;
PackedDataContainerRef() {}
};
diff --git a/core/io/packet_peer.cpp b/core/io/packet_peer.cpp
index dacd548a3e..b6cc5bf42a 100644
--- a/core/io/packet_peer.cpp
+++ b/core/io/packet_peer.cpp
@@ -30,8 +30,8 @@
#include "packet_peer.h"
+#include "core/config/project_settings.h"
#include "core/io/marshalls.h"
-#include "core/project_settings.h"
/* helpers / binders */
diff --git a/core/io/packet_peer.h b/core/io/packet_peer.h
index f0ba50087f..f7f080aa43 100644
--- a/core/io/packet_peer.h
+++ b/core/io/packet_peer.h
@@ -32,8 +32,8 @@
#define PACKET_PEER_H
#include "core/io/stream_peer.h"
-#include "core/object.h"
-#include "core/ring_buffer.h"
+#include "core/object/class_db.h"
+#include "core/templates/ring_buffer.h"
class PacketPeer : public Reference {
GDCLASS(PacketPeer, Reference);
@@ -90,11 +90,11 @@ protected:
static void _bind_methods();
public:
- virtual int get_available_packet_count() const;
- virtual Error get_packet(const uint8_t **r_buffer, int &r_buffer_size);
- virtual Error put_packet(const uint8_t *p_buffer, int p_buffer_size);
+ virtual int get_available_packet_count() const override;
+ virtual Error get_packet(const uint8_t **r_buffer, int &r_buffer_size) override;
+ virtual Error put_packet(const uint8_t *p_buffer, int p_buffer_size) override;
- virtual int get_max_packet_size() const;
+ virtual int get_max_packet_size() const override;
void set_stream_peer(const Ref<StreamPeer> &p_peer);
Ref<StreamPeer> get_stream_peer() const;
diff --git a/core/io/packet_peer_dtls.cpp b/core/io/packet_peer_dtls.cpp
index 632f86a9f6..9f6fccc993 100644
--- a/core/io/packet_peer_dtls.cpp
+++ b/core/io/packet_peer_dtls.cpp
@@ -29,8 +29,8 @@
/*************************************************************************/
#include "packet_peer_dtls.h"
+#include "core/config/project_settings.h"
#include "core/os/file_access.h"
-#include "core/project_settings.h"
PacketPeerDTLS *(*PacketPeerDTLS::_create)() = nullptr;
bool PacketPeerDTLS::available = false;
diff --git a/core/io/packet_peer_udp.cpp b/core/io/packet_peer_udp.cpp
index 862fca96fc..488cfbeaa8 100644
--- a/core/io/packet_peer_udp.cpp
+++ b/core/io/packet_peer_udp.cpp
@@ -31,12 +31,14 @@
#include "packet_peer_udp.h"
#include "core/io/ip.h"
+#include "core/io/udp_server.h"
void PacketPeerUDP::set_blocking_mode(bool p_enable) {
blocking = p_enable;
}
void PacketPeerUDP::set_broadcast_enabled(bool p_enabled) {
+ ERR_FAIL_COND(udp_server);
broadcast = p_enabled;
if (_sock.is_valid() && _sock->is_open()) {
_sock->set_broadcasting_enabled(p_enabled);
@@ -44,6 +46,7 @@ void PacketPeerUDP::set_broadcast_enabled(bool p_enabled) {
}
Error PacketPeerUDP::join_multicast_group(IP_Address p_multi_address, String p_if_name) {
+ ERR_FAIL_COND_V(udp_server, ERR_LOCKED);
ERR_FAIL_COND_V(!_sock.is_valid(), ERR_UNAVAILABLE);
ERR_FAIL_COND_V(!p_multi_address.is_valid(), ERR_INVALID_PARAMETER);
@@ -58,6 +61,7 @@ Error PacketPeerUDP::join_multicast_group(IP_Address p_multi_address, String p_i
}
Error PacketPeerUDP::leave_multicast_group(IP_Address p_multi_address, String p_if_name) {
+ ERR_FAIL_COND_V(udp_server, ERR_LOCKED);
ERR_FAIL_COND_V(!_sock.is_valid(), ERR_UNAVAILABLE);
ERR_FAIL_COND_V(!_sock->is_open(), ERR_UNCONFIGURED);
return _sock->leave_multicast_group(p_multi_address, p_if_name);
@@ -130,7 +134,7 @@ Error PacketPeerUDP::put_packet(const uint8_t *p_buffer, int p_buffer_size) {
}
do {
- if (connected) {
+ if (connected && !udp_server) {
err = _sock->send(p_buffer, p_buffer_size, sent);
} else {
err = _sock->sendto(p_buffer, p_buffer_size, sent, peer_addr, peer_port);
@@ -174,7 +178,6 @@ Error PacketPeerUDP::listen(int p_port, const IP_Address &p_bind_address, int p_
}
_sock->set_blocking_enabled(false);
- _sock->set_reuse_address_enabled(true);
_sock->set_broadcasting_enabled(broadcast);
err = _sock->bind(p_bind_address, p_port);
@@ -186,26 +189,25 @@ Error PacketPeerUDP::listen(int p_port, const IP_Address &p_bind_address, int p_
return OK;
}
-Error PacketPeerUDP::connect_socket(Ref<NetSocket> p_sock) {
- Error err;
- int read = 0;
- uint16_t r_port;
- IP_Address r_ip;
-
- err = p_sock->recvfrom(recv_buffer, sizeof(recv_buffer), read, r_ip, r_port, true);
- ERR_FAIL_COND_V(err != OK, err);
- err = p_sock->connect_to_host(r_ip, r_port);
- ERR_FAIL_COND_V(err != OK, err);
+Error PacketPeerUDP::connect_shared_socket(Ref<NetSocket> p_sock, IP_Address p_ip, uint16_t p_port, UDPServer *p_server) {
+ udp_server = p_server;
+ connected = true;
_sock = p_sock;
- peer_addr = r_ip;
- peer_port = r_port;
+ peer_addr = p_ip;
+ peer_port = p_port;
packet_ip = peer_addr;
packet_port = peer_port;
- connected = true;
return OK;
}
+void PacketPeerUDP::disconnect_shared_socket() {
+ udp_server = nullptr;
+ _sock = Ref<NetSocket>(NetSocket::create());
+ close();
+}
+
Error PacketPeerUDP::connect_to_host(const IP_Address &p_host, int p_port) {
+ ERR_FAIL_COND_V(udp_server, ERR_LOCKED);
ERR_FAIL_COND_V(!_sock.is_valid(), ERR_UNAVAILABLE);
ERR_FAIL_COND_V(!p_host.is_valid(), ERR_INVALID_PARAMETER);
@@ -243,7 +245,11 @@ bool PacketPeerUDP::is_connected_to_host() const {
}
void PacketPeerUDP::close() {
- if (_sock.is_valid()) {
+ if (udp_server) {
+ udp_server->remove_peer(peer_addr, peer_port);
+ udp_server = nullptr;
+ _sock = Ref<NetSocket>(NetSocket::create());
+ } else if (_sock.is_valid()) {
_sock->close();
}
rb.resize(16);
@@ -262,6 +268,9 @@ Error PacketPeerUDP::_poll() {
if (!_sock->is_open()) {
return FAILED;
}
+ if (udp_server) {
+ return OK; // Handled by UDPServer.
+ }
Error err;
int read;
@@ -284,24 +293,29 @@ Error PacketPeerUDP::_poll() {
return FAILED;
}
- if (rb.space_left() < read + 24) {
+ err = store_packet(ip, port, recv_buffer, read);
#ifdef TOOLS_ENABLED
+ if (err != OK) {
WARN_PRINT("Buffer full, dropping packets!");
-#endif
- continue;
}
-
- uint32_t port32 = port;
- rb.write(ip.get_ipv6(), 16);
- rb.write((uint8_t *)&port32, 4);
- rb.write((uint8_t *)&read, 4);
- rb.write(recv_buffer, read);
- ++queue_count;
+#endif
}
return OK;
}
+Error PacketPeerUDP::store_packet(IP_Address p_ip, uint32_t p_port, uint8_t *p_buf, int p_buf_size) {
+ if (rb.space_left() < p_buf_size + 24) {
+ return ERR_OUT_OF_MEMORY;
+ }
+ rb.write(p_ip.get_ipv6(), 16);
+ rb.write((uint8_t *)&p_port, 4);
+ rb.write((uint8_t *)&p_buf_size, 4);
+ rb.write(p_buf, p_buf_size);
+ ++queue_count;
+ return OK;
+}
+
bool PacketPeerUDP::is_listening() const {
return _sock.is_valid() && _sock->is_open();
}
diff --git a/core/io/packet_peer_udp.h b/core/io/packet_peer_udp.h
index 23fc5460a6..9a44a1ebea 100644
--- a/core/io/packet_peer_udp.h
+++ b/core/io/packet_peer_udp.h
@@ -35,6 +35,8 @@
#include "core/io/net_socket.h"
#include "core/io/packet_peer.h"
+class UDPServer;
+
class PacketPeerUDP : public PacketPeer {
GDCLASS(PacketPeerUDP, PacketPeer);
@@ -55,6 +57,7 @@ protected:
bool connected = false;
bool blocking = true;
bool broadcast = false;
+ UDPServer *udp_server = nullptr;
Ref<NetSocket> _sock;
static void _bind_methods();
@@ -72,7 +75,9 @@ public:
Error wait();
bool is_listening() const;
- Error connect_socket(Ref<NetSocket> p_sock); // Used by UDPServer
+ Error connect_shared_socket(Ref<NetSocket> p_sock, IP_Address p_ip, uint16_t p_port, UDPServer *ref); // Used by UDPServer
+ void disconnect_shared_socket(); // Used by UDPServer
+ Error store_packet(IP_Address p_ip, uint32_t p_port, uint8_t *p_buf, int p_buf_size); // Used internally and by UDPServer
Error connect_to_host(const IP_Address &p_host, int p_port);
bool is_connected_to_host() const;
@@ -80,10 +85,10 @@ public:
int get_packet_port() const;
void set_dest_address(const IP_Address &p_address, int p_port);
- Error put_packet(const uint8_t *p_buffer, int p_buffer_size);
- Error get_packet(const uint8_t **r_buffer, int &r_buffer_size);
- int get_available_packet_count() const;
- int get_max_packet_size() const;
+ Error put_packet(const uint8_t *p_buffer, int p_buffer_size) override;
+ Error get_packet(const uint8_t **r_buffer, int &r_buffer_size) override;
+ int get_available_packet_count() const override;
+ int get_max_packet_size() const override;
void set_broadcast_enabled(bool p_enabled);
Error join_multicast_group(IP_Address p_multi_address, String p_if_name);
Error leave_multicast_group(IP_Address p_multi_address, String p_if_name);
diff --git a/core/io/pck_packer.cpp b/core/io/pck_packer.cpp
index 374b2a5e07..5480d3c535 100644
--- a/core/io/pck_packer.cpp
+++ b/core/io/pck_packer.cpp
@@ -30,36 +30,58 @@
#include "pck_packer.h"
+#include "core/crypto/crypto_core.h"
+#include "core/io/file_access_encrypted.h"
#include "core/io/file_access_pack.h" // PACK_HEADER_MAGIC, PACK_FORMAT_VERSION
#include "core/os/file_access.h"
#include "core/version.h"
-static uint64_t _align(uint64_t p_n, int p_alignment) {
- if (p_alignment == 0) {
- return p_n;
+static int _get_pad(int p_alignment, int p_n) {
+ int rest = p_n % p_alignment;
+ int pad = 0;
+ if (rest > 0) {
+ pad = p_alignment - rest;
}
- uint64_t rest = p_n % p_alignment;
- if (rest == 0) {
- return p_n;
- } else {
- return p_n + (p_alignment - rest);
- }
-}
-
-static void _pad(FileAccess *p_file, int p_bytes) {
- for (int i = 0; i < p_bytes; i++) {
- p_file->store_8(0);
- }
+ return pad;
}
void PCKPacker::_bind_methods() {
- ClassDB::bind_method(D_METHOD("pck_start", "pck_name", "alignment"), &PCKPacker::pck_start, DEFVAL(0));
- ClassDB::bind_method(D_METHOD("add_file", "pck_path", "source_path"), &PCKPacker::add_file);
+ ClassDB::bind_method(D_METHOD("pck_start", "pck_name", "alignment", "key", "encrypt_directory"), &PCKPacker::pck_start, DEFVAL(0), DEFVAL(String()), DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("add_file", "pck_path", "source_path", "encrypt"), &PCKPacker::add_file, DEFVAL(false));
ClassDB::bind_method(D_METHOD("flush", "verbose"), &PCKPacker::flush, DEFVAL(false));
}
-Error PCKPacker::pck_start(const String &p_file, int p_alignment) {
+Error PCKPacker::pck_start(const String &p_file, int p_alignment, const String &p_key, bool p_encrypt_directory) {
+ ERR_FAIL_COND_V_MSG((p_key.empty() || !p_key.is_valid_hex_number(false) || p_key.length() != 64), ERR_CANT_CREATE, "Invalid Encryption Key (must be 64 characters long).");
+
+ String _key = p_key.to_lower();
+ key.resize(32);
+ for (int i = 0; i < 32; i++) {
+ int v = 0;
+ if (i * 2 < _key.length()) {
+ char32_t ct = _key[i * 2];
+ if (ct >= '0' && ct <= '9') {
+ ct = ct - '0';
+ } else if (ct >= 'a' && ct <= 'f') {
+ ct = 10 + ct - 'a';
+ }
+ v |= ct << 4;
+ }
+
+ if (i * 2 + 1 < _key.length()) {
+ char32_t ct = _key[i * 2 + 1];
+ if (ct >= '0' && ct <= '9') {
+ ct = ct - '0';
+ } else if (ct >= 'a' && ct <= 'f') {
+ ct = 10 + ct - 'a';
+ }
+ v |= ct;
+ }
+ key.write[i] = v;
+ }
+ enc_dir = p_encrypt_directory;
+
if (file != nullptr) {
memdelete(file);
}
@@ -76,16 +98,19 @@ Error PCKPacker::pck_start(const String &p_file, int p_alignment) {
file->store_32(VERSION_MINOR);
file->store_32(VERSION_PATCH);
- for (int i = 0; i < 16; i++) {
- file->store_32(0); // reserved
+ uint32_t pack_flags = 0;
+ if (enc_dir) {
+ pack_flags |= PACK_DIR_ENCRYPTED;
}
+ file->store_32(pack_flags); // flags
files.clear();
+ ofs = 0;
return OK;
}
-Error PCKPacker::add_file(const String &p_file, const String &p_src) {
+Error PCKPacker::add_file(const String &p_file, const String &p_src, bool p_encrypt) {
FileAccess *f = FileAccess::open(p_src, FileAccess::READ);
if (!f) {
return ERR_FILE_CANT_OPEN;
@@ -94,8 +119,32 @@ Error PCKPacker::add_file(const String &p_file, const String &p_src) {
File pf;
pf.path = p_file;
pf.src_path = p_src;
+ pf.ofs = ofs;
pf.size = f->get_len();
- pf.offset_offset = 0;
+
+ Vector<uint8_t> data = FileAccess::get_file_as_array(p_src);
+ {
+ unsigned char hash[16];
+ CryptoCore::md5(data.ptr(), data.size(), hash);
+ pf.md5.resize(16);
+ for (int i = 0; i < 16; i++) {
+ pf.md5.write[i] = hash[i];
+ }
+ }
+ pf.encrypted = p_encrypt;
+
+ uint64_t _size = pf.size;
+ if (p_encrypt) { // Add encryption overhead.
+ if (_size % 16) { // Pad to encryption block size.
+ _size += 16 - (_size % 16);
+ }
+ _size += 16; // hash
+ _size += 8; // data size
+ _size += 16; // iv
+ }
+
+ int pad = _get_pad(alignment, ofs + _size);
+ ofs = ofs + _size + pad;
files.push_back(pf);
@@ -108,27 +157,64 @@ Error PCKPacker::add_file(const String &p_file, const String &p_src) {
Error PCKPacker::flush(bool p_verbose) {
ERR_FAIL_COND_V_MSG(!file, ERR_INVALID_PARAMETER, "File must be opened before use.");
- // write the index
+ int64_t file_base_ofs = file->get_position();
+ file->store_64(0); // files base
+ for (int i = 0; i < 16; i++) {
+ file->store_32(0); // reserved
+ }
+
+ // write the index
file->store_32(files.size());
+ FileAccessEncrypted *fae = nullptr;
+ FileAccess *fhead = file;
+
+ if (enc_dir) {
+ fae = memnew(FileAccessEncrypted);
+ ERR_FAIL_COND_V(!fae, ERR_CANT_CREATE);
+
+ Error err = fae->open_and_parse(file, key, FileAccessEncrypted::MODE_WRITE_AES256, false);
+ ERR_FAIL_COND_V(err != OK, ERR_CANT_CREATE);
+
+ fhead = fae;
+ }
+
for (int i = 0; i < files.size(); i++) {
- file->store_pascal_string(files[i].path);
- files.write[i].offset_offset = file->get_position();
- file->store_64(0); // offset
- file->store_64(files[i].size); // size
-
- // # empty md5
- file->store_32(0);
- file->store_32(0);
- file->store_32(0);
- file->store_32(0);
+ int string_len = files[i].path.utf8().length();
+ int pad = _get_pad(4, string_len);
+
+ fhead->store_32(string_len + pad);
+ fhead->store_buffer((const uint8_t *)files[i].path.utf8().get_data(), string_len);
+ for (int j = 0; j < pad; j++) {
+ fhead->store_8(0);
+ }
+
+ fhead->store_64(files[i].ofs);
+ fhead->store_64(files[i].size); // pay attention here, this is where file is
+ fhead->store_buffer(files[i].md5.ptr(), 16); //also save md5 for file
+
+ uint32_t flags = 0;
+ if (files[i].encrypted) {
+ flags |= PACK_FILE_ENCRYPTED;
+ }
+ fhead->store_32(flags);
+ }
+
+ if (fae) {
+ fae->release();
+ memdelete(fae);
}
- uint64_t ofs = file->get_position();
- ofs = _align(ofs, alignment);
+ int header_padding = _get_pad(alignment, file->get_position());
+ for (int i = 0; i < header_padding; i++) {
+ file->store_8(Math::rand() % 256);
+ }
- _pad(file, ofs - file->get_position());
+ int64_t file_base = file->get_position();
+ file->seek(file_base_ofs);
+ file->store_64(file_base); // update files base
+ file->seek(file_base);
const uint32_t buf_max = 65536;
uint8_t *buf = memnew_arr(uint8_t, buf_max);
@@ -137,26 +223,41 @@ Error PCKPacker::flush(bool p_verbose) {
for (int i = 0; i < files.size(); i++) {
FileAccess *src = FileAccess::open(files[i].src_path, FileAccess::READ);
uint64_t to_write = files[i].size;
+
+ fae = nullptr;
+ FileAccess *ftmp = file;
+ if (files[i].encrypted) {
+ fae = memnew(FileAccessEncrypted);
+ ERR_FAIL_COND_V(!fae, ERR_CANT_CREATE);
+
+ Error err = fae->open_and_parse(file, key, FileAccessEncrypted::MODE_WRITE_AES256, false);
+ ERR_FAIL_COND_V(err != OK, ERR_CANT_CREATE);
+ ftmp = fae;
+ }
+
while (to_write > 0) {
int read = src->get_buffer(buf, MIN(to_write, buf_max));
- file->store_buffer(buf, read);
+ ftmp->store_buffer(buf, read);
to_write -= read;
}
- uint64_t pos = file->get_position();
- file->seek(files[i].offset_offset); // go back to store the file's offset
- file->store_64(ofs);
- file->seek(pos);
+ if (fae) {
+ fae->release();
+ memdelete(fae);
+ }
- ofs = _align(ofs + files[i].size, alignment);
- _pad(file, ofs - pos);
+ int pad = _get_pad(alignment, file->get_position());
+ for (int j = 0; j < pad; j++) {
+ file->store_8(Math::rand() % 256);
+ }
src->close();
memdelete(src);
count += 1;
- if (p_verbose && files.size() > 0) {
+ const int file_num = files.size();
+ if (p_verbose && (file_num > 0)) {
if (count % 100 == 0) {
- printf("%i/%i (%.2f)\r", count, files.size(), float(count) / files.size() * 100);
+ printf("%i/%i (%.2f)\r", count, file_num, float(count) / file_num * 100);
fflush(stdout);
}
}
diff --git a/core/io/pck_packer.h b/core/io/pck_packer.h
index 2929967a68..56be1b52df 100644
--- a/core/io/pck_packer.h
+++ b/core/io/pck_packer.h
@@ -31,7 +31,7 @@
#ifndef PCK_PACKER_H
#define PCK_PACKER_H
-#include "core/reference.h"
+#include "core/object/reference.h"
class FileAccess;
@@ -39,21 +39,27 @@ class PCKPacker : public Reference {
GDCLASS(PCKPacker, Reference);
FileAccess *file = nullptr;
- int alignment;
+ int alignment = 0;
+ uint64_t ofs = 0;
+
+ Vector<uint8_t> key;
+ bool enc_dir = false;
static void _bind_methods();
struct File {
String path;
String src_path;
- int size;
- uint64_t offset_offset;
+ uint64_t ofs = 0;
+ uint64_t size = 0;
+ bool encrypted = false;
+ Vector<uint8_t> md5;
};
Vector<File> files;
public:
- Error pck_start(const String &p_file, int p_alignment = 0);
- Error add_file(const String &p_file, const String &p_src);
+ Error pck_start(const String &p_file, int p_alignment = 0, const String &p_key = String(), bool p_encrypt_directory = false);
+ Error add_file(const String &p_file, const String &p_src, bool p_encrypt = false);
Error flush(bool p_verbose = false);
PCKPacker() {}
diff --git a/core/resource.cpp b/core/io/resource.cpp
index 3b589793ef..58ab9a8cde 100644
--- a/core/resource.cpp
+++ b/core/io/resource.cpp
@@ -32,9 +32,9 @@
#include "core/core_string_names.h"
#include "core/io/resource_loader.h"
+#include "core/object/script_language.h"
#include "core/os/file_access.h"
#include "core/os/os.h"
-#include "core/script_language.h"
#include "scene/main/node.h" //only so casting works
#include <stdio.h>
@@ -147,8 +147,8 @@ Ref<Resource> Resource::duplicate_for_local_scene(Node *p_for_scene, Map<Ref<Res
List<PropertyInfo> plist;
get_property_list(&plist);
- Resource *r = Object::cast_to<Resource>(ClassDB::instance(get_class()));
- ERR_FAIL_COND_V(!r, Ref<Resource>());
+ Ref<Resource> r = Object::cast_to<Resource>(ClassDB::instance(get_class()));
+ ERR_FAIL_COND_V(r.is_null(), Ref<Resource>());
r->local_scene = p_for_scene;
@@ -175,9 +175,7 @@ Ref<Resource> Resource::duplicate_for_local_scene(Node *p_for_scene, Map<Ref<Res
r->set(E->get().name, p);
}
- RES res = Ref<Resource>(r);
-
- return res;
+ return r;
}
void Resource::configure_for_local_scene(Node *p_for_scene, Map<Ref<Resource>, Ref<Resource>> &remap_cache) {
@@ -209,8 +207,8 @@ Ref<Resource> Resource::duplicate(bool p_subresources) const {
List<PropertyInfo> plist;
get_property_list(&plist);
- Resource *r = (Resource *)ClassDB::instance(get_class());
- ERR_FAIL_COND_V(!r, Ref<Resource>());
+ Ref<Resource> r = (Resource *)ClassDB::instance(get_class());
+ ERR_FAIL_COND_V(r.is_null(), Ref<Resource>());
for (List<PropertyInfo>::Element *E = plist.front(); E; E = E->next()) {
if (!(E->get().usage & PROPERTY_USAGE_STORAGE)) {
@@ -230,7 +228,7 @@ Ref<Resource> Resource::duplicate(bool p_subresources) const {
}
}
- return Ref<Resource>(r);
+ return r;
}
void Resource::_set_path(const String &p_path) {
diff --git a/core/resource.h b/core/io/resource.h
index ad2f3ce913..6e0bd7d7f4 100644
--- a/core/resource.h
+++ b/core/io/resource.h
@@ -31,24 +31,27 @@
#ifndef RESOURCE_H
#define RESOURCE_H
-#include "core/class_db.h"
-#include "core/object.h"
-#include "core/reference.h"
-#include "core/safe_refcount.h"
-#include "core/self_list.h"
+#include "core/object/class_db.h"
+#include "core/object/reference.h"
+#include "core/templates/safe_refcount.h"
+#include "core/templates/self_list.h"
#define RES_BASE_EXTENSION(m_ext) \
public: \
static void register_custom_data_to_otdb() { ClassDB::add_resource_base_extension(m_ext, get_class_static()); } \
- virtual String get_base_extension() const { return m_ext; } \
+ virtual String get_base_extension() const override { return m_ext; } \
\
private:
class Resource : public Reference {
GDCLASS(Resource, Reference);
OBJ_CATEGORY("Resources");
- RES_BASE_EXTENSION("res");
+public:
+ static void register_custom_data_to_otdb() { ClassDB::add_resource_base_extension("res", get_class_static()); }
+ virtual String get_base_extension() const { return "res"; }
+
+private:
Set<ObjectID> owners;
friend class ResBase;
diff --git a/core/io/resource_format_binary.cpp b/core/io/resource_format_binary.cpp
index 5097f6d98b..aeb859aabd 100644
--- a/core/io/resource_format_binary.cpp
+++ b/core/io/resource_format_binary.cpp
@@ -30,18 +30,17 @@
#include "resource_format_binary.h"
-#include "core/image.h"
+#include "core/config/project_settings.h"
#include "core/io/file_access_compressed.h"
+#include "core/io/image.h"
#include "core/io/marshalls.h"
#include "core/os/dir_access.h"
-#include "core/project_settings.h"
#include "core/version.h"
//#define print_bl(m_what) print_line(m_what)
#define print_bl(m_what) (void)(m_what)
enum {
-
//numbering must be different from variant, in case new variant types are added (variant must be always contiguous for jumptable optimization)
VARIANT_NIL = 1,
VARIANT_BOOL = 2,
@@ -90,7 +89,6 @@ enum {
FORMAT_VERSION = 3,
FORMAT_VERSION_CAN_RENAME_DEPS = 1,
FORMAT_VERSION_NO_NODEPATH_PROPERTY = 3,
-
};
void ResourceLoaderBinary::_advance_padding(uint32_t p_len) {
@@ -863,7 +861,8 @@ void ResourceLoaderBinary::open(FileAccess *p_f) {
if (ver_format > FORMAT_VERSION || ver_major > VERSION_MAJOR) {
f->close();
- ERR_FAIL_MSG("File format '" + itos(FORMAT_VERSION) + "." + itos(ver_major) + "." + itos(ver_minor) + "' is too new! Please upgrade to a new engine version: " + local_path + ".");
+ ERR_FAIL_MSG(vformat("File '%s' can't be loaded, as it uses a format version (%d) or engine version (%d.%d) which are not supported by your engine version (%s).",
+ local_path, ver_format, ver_major, ver_minor, VERSION_BRANCH));
}
type = get_unicode_string();
@@ -1136,7 +1135,9 @@ Error ResourceFormatLoaderBinary::rename_dependencies(const String &p_path, cons
if (ver_format > FORMAT_VERSION || ver_major > VERSION_MAJOR) {
memdelete(f);
memdelete(fw);
- ERR_FAIL_V_MSG(ERR_FILE_UNRECOGNIZED, "File format '" + itos(FORMAT_VERSION) + "." + itos(ver_major) + "." + itos(ver_minor) + "' is too new! Please upgrade to a new engine version: " + local_path + ".");
+ ERR_FAIL_V_MSG(ERR_FILE_UNRECOGNIZED,
+ vformat("File '%s' can't be loaded, as it uses a format version (%d) or engine version (%d.%d) which are not supported by your engine version (%s).",
+ local_path, ver_format, ver_major, ver_minor, VERSION_BRANCH));
}
// Since we're not actually converting the file contents, leave the version
@@ -1464,7 +1465,7 @@ void ResourceFormatSaverBinaryInstance::write_variant(FileAccess *f, const Varia
}
} break;
- case Variant::_RID: {
+ case Variant::RID: {
f->store_32(VARIANT_RID);
WARN_PRINT("Can't save RIDs.");
RID val = p_property;
diff --git a/core/io/resource_importer.cpp b/core/io/resource_importer.cpp
index 9ed159bd20..c88331cf9e 100644
--- a/core/io/resource_importer.cpp
+++ b/core/io/resource_importer.cpp
@@ -30,8 +30,9 @@
#include "resource_importer.h"
+#include "core/config/project_settings.h"
#include "core/os/os.h"
-#include "core/variant_parser.h"
+#include "core/variant/variant_parser.h"
bool ResourceFormatImporter::SortImporterByName::operator()(const Ref<ResourceImporter> &p_a, const Ref<ResourceImporter> &p_b) const {
return p_a->get_importer_name() < p_b->get_importer_name();
@@ -374,7 +375,7 @@ Ref<ResourceImporter> ResourceFormatImporter::get_importer_by_extension(const St
}
String ResourceFormatImporter::get_import_base_path(const String &p_for_file) const {
- return "res://.import/" + p_for_file.get_file() + "-" + p_for_file.md5_text();
+ return ProjectSettings::IMPORTED_FILES_PATH.plus_file(p_for_file.get_file() + "-" + p_for_file.md5_text());
}
bool ResourceFormatImporter::are_import_settings_valid(const String &p_path) const {
diff --git a/core/io/resource_loader.cpp b/core/io/resource_loader.cpp
index 534f3e44de..a8ca6a817e 100644
--- a/core/io/resource_loader.cpp
+++ b/core/io/resource_loader.cpp
@@ -30,13 +30,13 @@
#include "resource_loader.h"
+#include "core/config/project_settings.h"
#include "core/io/resource_importer.h"
#include "core/os/file_access.h"
#include "core/os/os.h"
-#include "core/print_string.h"
-#include "core/project_settings.h"
-#include "core/translation.h"
-#include "core/variant_parser.h"
+#include "core/string/print_string.h"
+#include "core/string/translation.h"
+#include "core/variant/variant_parser.h"
#ifdef DEBUG_LOAD_THREADED
#define print_lt(m_text) print_line(m_text)
@@ -195,7 +195,8 @@ RES ResourceLoader::_load(const String &p_path, const String &p_original_path, c
return res;
}
- ERR_FAIL_COND_V_MSG(found, RES(), "Failed loading resource: " + p_path + ".");
+ ERR_FAIL_COND_V_MSG(found, RES(),
+ vformat("Failed loading resource: %s. Make sure resources have been imported by opening the project in the editor at least once.", p_path));
#ifdef TOOLS_ENABLED
FileAccessRef file_check = FileAccess::create(FileAccess::ACCESS_RESOURCES);
@@ -999,6 +1000,9 @@ void ResourceLoader::load_translation_remaps() {
void ResourceLoader::clear_translation_remaps() {
translation_remaps.clear();
+ while (remapped_list.first() != nullptr) {
+ remapped_list.remove(remapped_list.first());
+ }
}
void ResourceLoader::load_path_remaps() {
@@ -1053,7 +1057,7 @@ bool ResourceLoader::add_custom_resource_format_loader(String script_path) {
ERR_FAIL_COND_V_MSG(obj == nullptr, false, "Cannot instance script as custom resource loader, expected 'ResourceFormatLoader' inheritance, got: " + String(ibt) + ".");
- ResourceFormatLoader *crl = Object::cast_to<ResourceFormatLoader>(obj);
+ Ref<ResourceFormatLoader> crl = Object::cast_to<ResourceFormatLoader>(obj);
crl->set_script(s);
ResourceLoader::add_resource_format_loader(crl);
diff --git a/core/io/resource_loader.h b/core/io/resource_loader.h
index 9322b5273a..02c668f214 100644
--- a/core/io/resource_loader.h
+++ b/core/io/resource_loader.h
@@ -31,9 +31,9 @@
#ifndef RESOURCE_LOADER_H
#define RESOURCE_LOADER_H
+#include "core/io/resource.h"
#include "core/os/semaphore.h"
#include "core/os/thread.h"
-#include "core/resource.h"
class ResourceFormatLoader : public Reference {
GDCLASS(ResourceFormatLoader, Reference);
diff --git a/core/io/resource_saver.cpp b/core/io/resource_saver.cpp
index a8da215b61..6ded27d82f 100644
--- a/core/io/resource_saver.cpp
+++ b/core/io/resource_saver.cpp
@@ -29,10 +29,10 @@
/*************************************************************************/
#include "resource_saver.h"
+#include "core/config/project_settings.h"
#include "core/io/resource_loader.h"
+#include "core/object/script_language.h"
#include "core/os/file_access.h"
-#include "core/project_settings.h"
-#include "core/script_language.h"
Ref<ResourceFormatSaver> ResourceSaver::saver[MAX_SAVERS];
@@ -214,7 +214,7 @@ bool ResourceSaver::add_custom_resource_format_saver(String script_path) {
ERR_FAIL_COND_V_MSG(obj == nullptr, false, "Cannot instance script as custom resource saver, expected 'ResourceFormatSaver' inheritance, got: " + String(ibt) + ".");
- ResourceFormatSaver *crl = Object::cast_to<ResourceFormatSaver>(obj);
+ Ref<ResourceFormatSaver> crl = Object::cast_to<ResourceFormatSaver>(obj);
crl->set_script(s);
ResourceSaver::add_resource_format_saver(crl);
diff --git a/core/io/resource_saver.h b/core/io/resource_saver.h
index 8b4cdd86f8..c724c4a6e5 100644
--- a/core/io/resource_saver.h
+++ b/core/io/resource_saver.h
@@ -31,7 +31,7 @@
#ifndef RESOURCE_SAVER_H
#define RESOURCE_SAVER_H
-#include "core/resource.h"
+#include "core/io/resource.h"
class ResourceFormatSaver : public Reference {
GDCLASS(ResourceFormatSaver, Reference);
@@ -63,7 +63,6 @@ class ResourceSaver {
public:
enum SaverFlags {
-
FLAG_RELATIVE_PATHS = 1,
FLAG_BUNDLE_RESOURCES = 2,
FLAG_CHANGE_PATH = 4,
diff --git a/core/io/stream_peer.h b/core/io/stream_peer.h
index ec0b989ed8..8c1e918dd8 100644
--- a/core/io/stream_peer.h
+++ b/core/io/stream_peer.h
@@ -31,7 +31,7 @@
#ifndef STREAM_PEER_H
#define STREAM_PEER_H
-#include "core/reference.h"
+#include "core/object/reference.h"
class StreamPeer : public Reference {
GDCLASS(StreamPeer, Reference);
@@ -102,13 +102,13 @@ protected:
static void _bind_methods();
public:
- Error put_data(const uint8_t *p_data, int p_bytes);
- Error put_partial_data(const uint8_t *p_data, int p_bytes, int &r_sent);
+ Error put_data(const uint8_t *p_data, int p_bytes) override;
+ Error put_partial_data(const uint8_t *p_data, int p_bytes, int &r_sent) override;
- Error get_data(uint8_t *p_buffer, int p_bytes);
- Error get_partial_data(uint8_t *p_buffer, int p_bytes, int &r_received);
+ Error get_data(uint8_t *p_buffer, int p_bytes) override;
+ Error get_partial_data(uint8_t *p_buffer, int p_bytes, int &r_received) override;
- virtual int get_available_bytes() const;
+ virtual int get_available_bytes() const override;
void seek(int p_pos);
int get_size() const;
diff --git a/core/io/stream_peer_ssl.cpp b/core/io/stream_peer_ssl.cpp
index 3dc31c6769..daf36a5350 100644
--- a/core/io/stream_peer_ssl.cpp
+++ b/core/io/stream_peer_ssl.cpp
@@ -30,7 +30,7 @@
#include "stream_peer_ssl.h"
-#include "core/engine.h"
+#include "core/config/engine.h"
StreamPeerSSL *(*StreamPeerSSL::_create)() = nullptr;
diff --git a/core/io/stream_peer_tcp.cpp b/core/io/stream_peer_tcp.cpp
index cce728c30a..aa9c409528 100644
--- a/core/io/stream_peer_tcp.cpp
+++ b/core/io/stream_peer_tcp.cpp
@@ -30,7 +30,7 @@
#include "stream_peer_tcp.h"
-#include "core/project_settings.h"
+#include "core/config/project_settings.h"
Error StreamPeerTCP::_poll_connection() {
ERR_FAIL_COND_V(status != STATUS_CONNECTING || !_sock.is_valid() || !_sock->is_open(), FAILED);
diff --git a/core/io/stream_peer_tcp.h b/core/io/stream_peer_tcp.h
index ab98d494d6..173f92e2b6 100644
--- a/core/io/stream_peer_tcp.h
+++ b/core/io/stream_peer_tcp.h
@@ -42,7 +42,6 @@ class StreamPeerTCP : public StreamPeer {
public:
enum Status {
-
STATUS_NONE,
STATUS_CONNECTING,
STATUS_CONNECTED,
@@ -72,7 +71,7 @@ public:
uint16_t get_connected_port() const;
void disconnect_from_host();
- int get_available_bytes() const;
+ int get_available_bytes() const override;
Status get_status();
void set_no_delay(bool p_enabled);
@@ -81,10 +80,10 @@ public:
Error poll(NetSocket::PollType p_type, int timeout = 0);
// Read/Write from StreamPeer
- Error put_data(const uint8_t *p_data, int p_bytes);
- Error put_partial_data(const uint8_t *p_data, int p_bytes, int &r_sent);
- Error get_data(uint8_t *p_buffer, int p_bytes);
- Error get_partial_data(uint8_t *p_buffer, int p_bytes, int &r_received);
+ Error put_data(const uint8_t *p_data, int p_bytes) override;
+ Error put_partial_data(const uint8_t *p_data, int p_bytes, int &r_sent) override;
+ Error get_data(uint8_t *p_buffer, int p_bytes) override;
+ Error get_partial_data(uint8_t *p_buffer, int p_bytes, int &r_received) override;
StreamPeerTCP();
~StreamPeerTCP();
diff --git a/core/io/translation_loader_po.cpp b/core/io/translation_loader_po.cpp
index 0e0a948953..34cccca540 100644
--- a/core/io/translation_loader_po.cpp
+++ b/core/io/translation_loader_po.cpp
@@ -31,31 +31,39 @@
#include "translation_loader_po.h"
#include "core/os/file_access.h"
-#include "core/translation.h"
+#include "core/string/translation.h"
+#include "core/string/translation_po.h"
RES TranslationLoaderPO::load_translation(FileAccess *f, Error *r_error) {
enum Status {
-
STATUS_NONE,
STATUS_READING_ID,
STATUS_READING_STRING,
+ STATUS_READING_CONTEXT,
+ STATUS_READING_PLURAL,
};
Status status = STATUS_NONE;
String msg_id;
String msg_str;
+ String msg_context;
+ Vector<String> msgs_plural;
String config;
if (r_error) {
*r_error = ERR_FILE_CORRUPT;
}
- Ref<Translation> translation = Ref<Translation>(memnew(Translation));
+ Ref<TranslationPO> translation = Ref<TranslationPO>(memnew(TranslationPO));
int line = 1;
+ int plural_forms = 0;
+ int plural_index = -1;
+ bool entered_context = false;
bool skip_this = false;
bool skip_next = false;
bool is_eof = false;
+ const String path = f->get_path();
while (!is_eof) {
String l = f->get_line().strip_edges();
@@ -63,40 +71,107 @@ RES TranslationLoaderPO::load_translation(FileAccess *f, Error *r_error) {
// If we reached last line and it's not a content line, break, otherwise let processing that last loop
if (is_eof && l.empty()) {
- if (status == STATUS_READING_ID) {
+ if (status == STATUS_READING_ID || status == STATUS_READING_CONTEXT || (status == STATUS_READING_PLURAL && plural_index != plural_forms - 1)) {
memdelete(f);
- ERR_FAIL_V_MSG(RES(), f->get_path() + ":" + itos(line) + " Unexpected EOF while reading 'msgid' at file: ");
+ ERR_FAIL_V_MSG(RES(), "Unexpected EOF while reading PO file at: " + path + ":" + itos(line));
} else {
break;
}
}
- if (l.begins_with("msgid")) {
+ if (l.begins_with("msgctxt")) {
+ if (status != STATUS_READING_STRING && status != STATUS_READING_PLURAL) {
+ memdelete(f);
+ ERR_FAIL_V_MSG(RES(), "Unexpected 'msgctxt', was expecting 'msgid_plural' or 'msgstr' before 'msgctxt' while parsing: " + path + ":" + itos(line));
+ }
+
+ // In PO file, "msgctxt" appears before "msgid". If we encounter a "msgctxt", we add what we have read
+ // and set "entered_context" to true to prevent adding twice.
+ if (!skip_this && msg_id != "") {
+ if (status == STATUS_READING_STRING) {
+ translation->add_message(msg_id, msg_str, msg_context);
+ } else if (status == STATUS_READING_PLURAL) {
+ if (plural_index != plural_forms - 1) {
+ memdelete(f);
+ ERR_FAIL_V_MSG(RES(), "Number of 'msgstr[]' doesn't match with number of plural forms: " + path + ":" + itos(line));
+ }
+ translation->add_plural_message(msg_id, msgs_plural, msg_context);
+ }
+ }
+ msg_context = "";
+ l = l.substr(7, l.length()).strip_edges();
+ status = STATUS_READING_CONTEXT;
+ entered_context = true;
+ }
+
+ if (l.begins_with("msgid_plural")) {
+ if (plural_forms == 0) {
+ memdelete(f);
+ ERR_FAIL_V_MSG(RES(), "PO file uses 'msgid_plural' but 'Plural-Forms' is invalid or missing in header: " + path + ":" + itos(line));
+ } else if (status != STATUS_READING_ID) {
+ memdelete(f);
+ ERR_FAIL_V_MSG(RES(), "Unexpected 'msgid_plural', was expecting 'msgid' before 'msgid_plural' while parsing: " + path + ":" + itos(line));
+ }
+ // We don't record the message in "msgid_plural" itself as tr_n(), TTRN(), RTRN() interfaces provide the plural string already.
+ // We just have to reset variables related to plurals for "msgstr[]" later on.
+ l = l.substr(12, l.length()).strip_edges();
+ plural_index = -1;
+ msgs_plural.clear();
+ msgs_plural.resize(plural_forms);
+ status = STATUS_READING_PLURAL;
+ } else if (l.begins_with("msgid")) {
if (status == STATUS_READING_ID) {
memdelete(f);
- ERR_FAIL_V_MSG(RES(), f->get_path() + ":" + itos(line) + " Unexpected 'msgid', was expecting 'msgstr' while parsing: ");
+ ERR_FAIL_V_MSG(RES(), "Unexpected 'msgid', was expecting 'msgstr' while parsing: " + path + ":" + itos(line));
}
if (msg_id != "") {
- if (!skip_this) {
- translation->add_message(msg_id, msg_str);
+ if (!skip_this && !entered_context) {
+ if (status == STATUS_READING_STRING) {
+ translation->add_message(msg_id, msg_str, msg_context);
+ } else if (status == STATUS_READING_PLURAL) {
+ if (plural_index != plural_forms - 1) {
+ memdelete(f);
+ ERR_FAIL_V_MSG(RES(), "Number of 'msgstr[]' doesn't match with number of plural forms: " + path + ":" + itos(line));
+ }
+ translation->add_plural_message(msg_id, msgs_plural, msg_context);
+ }
}
} else if (config == "") {
config = msg_str;
+ // Record plural rule.
+ int p_start = config.find("Plural-Forms");
+ if (p_start != -1) {
+ int p_end = config.find("\n", p_start);
+ translation->set_plural_rule(config.substr(p_start, p_end - p_start));
+ plural_forms = translation->get_plural_forms();
+ }
}
l = l.substr(5, l.length()).strip_edges();
status = STATUS_READING_ID;
+ // If we did not encounter msgctxt, we reset context to empty to reset it.
+ if (!entered_context) {
+ msg_context = "";
+ }
msg_id = "";
msg_str = "";
skip_this = skip_next;
skip_next = false;
+ entered_context = false;
}
- if (l.begins_with("msgstr")) {
+ if (l.begins_with("msgstr[")) {
+ if (status != STATUS_READING_PLURAL) {
+ memdelete(f);
+ ERR_FAIL_V_MSG(RES(), "Unexpected 'msgstr[]', was expecting 'msgid_plural' before 'msgstr[]' while parsing: " + path + ":" + itos(line));
+ }
+ plural_index++; // Increment to add to the next slot in vector msgs_plural.
+ l = l.substr(9, l.length()).strip_edges();
+ } else if (l.begins_with("msgstr")) {
if (status != STATUS_READING_ID) {
memdelete(f);
- ERR_FAIL_V_MSG(RES(), f->get_path() + ":" + itos(line) + " Unexpected 'msgstr', was expecting 'msgid' while parsing: ");
+ ERR_FAIL_V_MSG(RES(), "Unexpected 'msgstr', was expecting 'msgid' before 'msgstr' while parsing: " + path + ":" + itos(line));
}
l = l.substr(6, l.length()).strip_edges();
@@ -108,10 +183,13 @@ RES TranslationLoaderPO::load_translation(FileAccess *f, Error *r_error) {
skip_next = true;
}
line++;
- continue; //nothing to read or comment
+ continue; // Nothing to read or comment.
}
- ERR_FAIL_COND_V_MSG(!l.begins_with("\"") || status == STATUS_NONE, RES(), f->get_path() + ":" + itos(line) + " Invalid line '" + l + "' while parsing: ");
+ if (!l.begins_with("\"") || status == STATUS_NONE) {
+ memdelete(f);
+ ERR_FAIL_V_MSG(RES(), "Invalid line '" + l + "' while parsing: " + path + ":" + itos(line));
+ }
l = l.substr(1, l.length());
// Find final quote, ignoring escaped ones (\").
@@ -133,34 +211,49 @@ RES TranslationLoaderPO::load_translation(FileAccess *f, Error *r_error) {
escape_next = false;
}
- ERR_FAIL_COND_V_MSG(end_pos == -1, RES(), f->get_path() + ":" + itos(line) + ": Expected '\"' at end of message while parsing file.");
+ if (end_pos == -1) {
+ memdelete(f);
+ ERR_FAIL_V_MSG(RES(), "Expected '\"' at end of message while parsing: " + path + ":" + itos(line));
+ }
l = l.substr(0, end_pos);
l = l.c_unescape();
if (status == STATUS_READING_ID) {
msg_id += l;
- } else {
+ } else if (status == STATUS_READING_STRING) {
msg_str += l;
+ } else if (status == STATUS_READING_CONTEXT) {
+ msg_context += l;
+ } else if (status == STATUS_READING_PLURAL && plural_index >= 0) {
+ msgs_plural.write[plural_index] = msgs_plural[plural_index] + l;
}
line++;
}
- f->close();
memdelete(f);
+ // Add the last set of data from last iteration.
if (status == STATUS_READING_STRING) {
if (msg_id != "") {
if (!skip_this) {
- translation->add_message(msg_id, msg_str);
+ translation->add_message(msg_id, msg_str, msg_context);
}
} else if (config == "") {
config = msg_str;
}
+ } else if (status == STATUS_READING_PLURAL) {
+ if (!skip_this && msg_id != "") {
+ if (plural_index != plural_forms - 1) {
+ memdelete(f);
+ ERR_FAIL_V_MSG(RES(), "Number of 'msgstr[]' doesn't match with number of plural forms: " + path + ":" + itos(line));
+ }
+ translation->add_plural_message(msg_id, msgs_plural, msg_context);
+ }
}
- ERR_FAIL_COND_V_MSG(config == "", RES(), "No config found in file: " + f->get_path() + ".");
+ ERR_FAIL_COND_V_MSG(config == "", RES(), "No config found in file: " + path + ".");
Vector<String> configs = config.split("\n");
for (int i = 0; i < configs.size(); i++) {
@@ -197,7 +290,6 @@ RES TranslationLoaderPO::load(const String &p_path, const String &p_original_pat
void TranslationLoaderPO::get_recognized_extensions(List<String> *p_extensions) const {
p_extensions->push_back("po");
- //p_extensions->push_back("mo"); //mo in the future...
}
bool TranslationLoaderPO::handles_type(const String &p_type) const {
diff --git a/core/io/translation_loader_po.h b/core/io/translation_loader_po.h
index a196a37dc0..16c9f1e680 100644
--- a/core/io/translation_loader_po.h
+++ b/core/io/translation_loader_po.h
@@ -33,7 +33,7 @@
#include "core/io/resource_loader.h"
#include "core/os/file_access.h"
-#include "core/translation.h"
+#include "core/string/translation.h"
class TranslationLoaderPO : public ResourceFormatLoader {
public:
diff --git a/core/io/udp_server.cpp b/core/io/udp_server.cpp
index 1d329daf8b..acd15aadc6 100644
--- a/core/io/udp_server.cpp
+++ b/core/io/udp_server.cpp
@@ -32,10 +32,58 @@
void UDPServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("listen", "port", "bind_address"), &UDPServer::listen, DEFVAL("*"));
+ ClassDB::bind_method(D_METHOD("poll"), &UDPServer::poll);
ClassDB::bind_method(D_METHOD("is_connection_available"), &UDPServer::is_connection_available);
ClassDB::bind_method(D_METHOD("is_listening"), &UDPServer::is_listening);
ClassDB::bind_method(D_METHOD("take_connection"), &UDPServer::take_connection);
ClassDB::bind_method(D_METHOD("stop"), &UDPServer::stop);
+ ClassDB::bind_method(D_METHOD("set_max_pending_connections", "max_pending_connections"), &UDPServer::set_max_pending_connections);
+ ClassDB::bind_method(D_METHOD("get_max_pending_connections"), &UDPServer::get_max_pending_connections);
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "max_pending_connections", PROPERTY_HINT_RANGE, "0,256,1"), "set_max_pending_connections", "get_max_pending_connections");
+}
+
+Error UDPServer::poll() {
+ ERR_FAIL_COND_V(!_sock.is_valid(), ERR_UNAVAILABLE);
+ if (!_sock->is_open()) {
+ return ERR_UNCONFIGURED;
+ }
+ Error err;
+ int read;
+ IP_Address ip;
+ uint16_t port;
+ while (true) {
+ err = _sock->recvfrom(recv_buffer, sizeof(recv_buffer), read, ip, port);
+ if (err != OK) {
+ if (err == ERR_BUSY) {
+ break;
+ }
+ return FAILED;
+ }
+ Peer p;
+ p.ip = ip;
+ p.port = port;
+ List<Peer>::Element *E = peers.find(p);
+ if (!E) {
+ E = pending.find(p);
+ }
+ if (E) {
+ E->get().peer->store_packet(ip, port, recv_buffer, read);
+ } else {
+ if (pending.size() >= max_pending_connections) {
+ // Drop connection.
+ continue;
+ }
+ // It's a new peer, add it to the pending list.
+ Peer peer;
+ peer.ip = ip;
+ peer.port = port;
+ peer.peer = memnew(PacketPeerUDP);
+ peer.peer->connect_shared_socket(_sock, ip, port, this);
+ peer.peer->store_packet(ip, port, recv_buffer, read);
+ pending.push_back(peer);
+ }
+ }
+ return OK;
}
Error UDPServer::listen(uint16_t p_port, const IP_Address &p_bind_address) {
@@ -82,8 +130,24 @@ bool UDPServer::is_connection_available() const {
return false;
}
- Error err = _sock->poll(NetSocket::POLL_TYPE_IN, 0);
- return (err == OK);
+ return pending.size() > 0;
+}
+
+void UDPServer::set_max_pending_connections(int p_max) {
+ ERR_FAIL_COND_MSG(p_max < 0, "Max pending connections value must be a positive number (0 means refuse new connections).");
+ max_pending_connections = p_max;
+ while (p_max > pending.size()) {
+ List<Peer>::Element *E = pending.back();
+ if (!E) {
+ break;
+ }
+ memdelete(E->get().peer);
+ pending.erase(E);
+ }
+}
+
+int UDPServer::get_max_pending_connections() const {
+ return max_pending_connections;
}
Ref<PacketPeerUDP> UDPServer::take_connection() {
@@ -92,11 +156,20 @@ Ref<PacketPeerUDP> UDPServer::take_connection() {
return conn;
}
- conn = Ref<PacketPeerUDP>(memnew(PacketPeerUDP));
- conn->connect_socket(_sock);
- _sock = Ref<NetSocket>(NetSocket::create());
- listen(bind_port, bind_address);
- return conn;
+ Peer peer = pending[0];
+ pending.pop_front();
+ peers.push_back(peer);
+ return peer.peer;
+}
+
+void UDPServer::remove_peer(IP_Address p_ip, int p_port) {
+ Peer peer;
+ peer.ip = p_ip;
+ peer.port = p_port;
+ List<Peer>::Element *E = peers.find(peer);
+ if (E) {
+ peers.erase(E);
+ }
}
void UDPServer::stop() {
@@ -105,6 +178,19 @@ void UDPServer::stop() {
}
bind_port = 0;
bind_address = IP_Address();
+ List<Peer>::Element *E = peers.front();
+ while (E) {
+ E->get().peer->disconnect_shared_socket();
+ E = E->next();
+ }
+ E = pending.front();
+ while (E) {
+ E->get().peer->disconnect_shared_socket();
+ memdelete(E->get().peer);
+ E = E->next();
+ }
+ peers.clear();
+ pending.clear();
}
UDPServer::UDPServer() :
diff --git a/core/io/udp_server.h b/core/io/udp_server.h
index 90bb82b62b..3175b09b19 100644
--- a/core/io/udp_server.h
+++ b/core/io/udp_server.h
@@ -38,15 +38,40 @@ class UDPServer : public Reference {
GDCLASS(UDPServer, Reference);
protected:
- static void _bind_methods();
- int bind_port;
+ enum {
+ PACKET_BUFFER_SIZE = 65536
+ };
+
+ struct Peer {
+ PacketPeerUDP *peer;
+ IP_Address ip;
+ uint16_t port = 0;
+
+ bool operator==(const Peer &p_other) const {
+ return (ip == p_other.ip && port == p_other.port);
+ }
+ };
+ uint8_t recv_buffer[PACKET_BUFFER_SIZE];
+
+ int bind_port = 0;
IP_Address bind_address;
+
+ List<Peer> peers;
+ List<Peer> pending;
+ int max_pending_connections = 16;
+
Ref<NetSocket> _sock;
+ static void _bind_methods();
+
public:
+ void remove_peer(IP_Address p_ip, int p_port);
Error listen(uint16_t p_port, const IP_Address &p_bind_address = IP_Address("*"));
+ Error poll();
bool is_listening() const;
bool is_connection_available() const;
+ void set_max_pending_connections(int p_max);
+ int get_max_pending_connections() const;
Ref<PacketPeerUDP> take_connection();
void stop();
diff --git a/core/io/xml_parser.cpp b/core/io/xml_parser.cpp
index b11267b60f..85143c0f04 100644
--- a/core/io/xml_parser.cpp
+++ b/core/io/xml_parser.cpp
@@ -30,13 +30,13 @@
#include "xml_parser.h"
-#include "core/print_string.h"
+#include "core/string/print_string.h"
//#define DEBUG_XML
VARIANT_ENUM_CAST(XMLParser::NodeType);
-static bool _equalsn(const CharType *str1, const CharType *str2, int len) {
+static bool _equalsn(const char32_t *str1, const char32_t *str2, int len) {
int i;
for (i = 0; i < len && str1[i] && str2[i]; ++i) {
if (str1[i] != str2[i]) {
@@ -64,7 +64,7 @@ String XMLParser::_replace_special_characters(const String &origstr) {
int specialChar = -1;
for (int i = 0; i < (int)special_characters.size(); ++i) {
- const CharType *p = &origstr[pos] + 1;
+ const char32_t *p = &origstr[pos] + 1;
if (_equalsn(&special_characters[i][1], p, special_characters[i].length() - 1)) {
specialChar = i;
diff --git a/core/io/xml_parser.h b/core/io/xml_parser.h
index ee2174d52c..d8cc26b4c1 100644
--- a/core/io/xml_parser.h
+++ b/core/io/xml_parser.h
@@ -31,10 +31,10 @@
#ifndef XML_PARSER_H
#define XML_PARSER_H
+#include "core/object/reference.h"
#include "core/os/file_access.h"
-#include "core/reference.h"
-#include "core/ustring.h"
-#include "core/vector.h"
+#include "core/string/ustring.h"
+#include "core/templates/vector.h"
/*
Based on irrXML (see their zlib license). Added mainly for compatibility with their Collada loader.
diff --git a/core/make_binders.py b/core/make_binders.py
deleted file mode 100644
index 7d0d08cde6..0000000000
--- a/core/make_binders.py
+++ /dev/null
@@ -1,390 +0,0 @@
-# -*- coding: ibm850 -*-
-
-template_typed = """
-#ifdef TYPED_METHOD_BIND
-template<class T $ifret ,class R$ $ifargs ,$ $arg, class P@$>
-class MethodBind$argc$$ifret R$$ifconst C$ : public MethodBind {
-public:
-
- $ifret R$ $ifnoret void$ (T::*method)($arg, P@$) $ifconst const$;
-#ifdef DEBUG_METHODS_ENABLED
- virtual Variant::Type _gen_argument_type(int p_arg) const { return _get_argument_type(p_arg); }
- virtual GodotTypeInfo::Metadata get_argument_meta(int p_arg) const {
- $ifret if (p_arg==-1) return GetTypeInfo<R>::METADATA;$
- $arg if (p_arg==(@-1)) return GetTypeInfo<P@>::METADATA;
- $
- return GodotTypeInfo::METADATA_NONE;
- }
- Variant::Type _get_argument_type(int p_argument) const {
- $ifret if (p_argument==-1) return (Variant::Type)GetTypeInfo<R>::VARIANT_TYPE;$
- $arg if (p_argument==(@-1)) return (Variant::Type)GetTypeInfo<P@>::VARIANT_TYPE;
- $
- return Variant::NIL;
- }
- virtual PropertyInfo _gen_argument_type_info(int p_argument) const {
- $ifret if (p_argument==-1) return GetTypeInfo<R>::get_class_info();$
- $arg if (p_argument==(@-1)) return GetTypeInfo<P@>::get_class_info();
- $
- return PropertyInfo();
- }
-#endif
- virtual String get_instance_class() const {
- return T::get_class_static();
- }
-
- virtual Variant call(Object* p_object,const Variant** p_args,int p_arg_count, Callable::CallError& r_error) {
-
- T *instance=Object::cast_to<T>(p_object);
- r_error.error=Callable::CallError::CALL_OK;
-#ifdef DEBUG_METHODS_ENABLED
-
- ERR_FAIL_COND_V(!instance,Variant());
- if (p_arg_count>get_argument_count()) {
- r_error.error=Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
- r_error.argument=get_argument_count();
- return Variant();
-
- }
- if (p_arg_count<(get_argument_count()-get_default_argument_count())) {
-
- r_error.error=Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
- r_error.argument=get_argument_count()-get_default_argument_count();
- return Variant();
- }
- $arg CHECK_ARG(@);
- $
-#endif
- $ifret Variant ret = $(instance->*method)($arg, _VC(@)$);
- $ifret return Variant(ret);$
- $ifnoret return Variant();$
- }
-
-#ifdef PTRCALL_ENABLED
- virtual void ptrcall(Object*p_object,const void** p_args,void *r_ret) {
-
- T *instance=Object::cast_to<T>(p_object);
- $ifret PtrToArg<R>::encode( $ (instance->*method)($arg, PtrToArg<P@>::convert(p_args[@-1])$) $ifret ,r_ret)$ ;
- }
-#endif
- MethodBind$argc$$ifret R$$ifconst C$ () {
-#ifdef DEBUG_METHODS_ENABLED
- _set_const($ifconst true$$ifnoconst false$);
- _generate_argument_types($argc$);
-#else
- set_argument_count($argc$);
-#endif
-
- $ifret _set_returns(true); $
- }
-};
-
-template<class T $ifret ,class R$ $ifargs ,$ $arg, class P@$>
-MethodBind* create_method_bind($ifret R$ $ifnoret void$ (T::*p_method)($arg, P@$) $ifconst const$ ) {
-
- MethodBind$argc$$ifret R$$ifconst C$<T $ifret ,R$ $ifargs ,$ $arg, P@$> * a = memnew( (MethodBind$argc$$ifret R$$ifconst C$<T $ifret ,R$ $ifargs ,$ $arg, P@$>) );
- a->method=p_method;
- return a;
-}
-#endif
-"""
-
-template = """
-#ifndef TYPED_METHOD_BIND
-$iftempl template<$ $ifret class R$ $ifretargs ,$ $arg, class P@$ $iftempl >$
-class MethodBind$argc$$ifret R$$ifconst C$ : public MethodBind {
-
-public:
-
- StringName type_name;
- $ifret R$ $ifnoret void$ (__UnexistingClass::*method)($arg, P@$) $ifconst const$;
-
-#ifdef DEBUG_METHODS_ENABLED
- virtual Variant::Type _gen_argument_type(int p_arg) const { return _get_argument_type(p_arg); }
- virtual GodotTypeInfo::Metadata get_argument_meta(int p_arg) const {
- $ifret if (p_arg==-1) return GetTypeInfo<R>::METADATA;$
- $arg if (p_arg==(@-1)) return GetTypeInfo<P@>::METADATA;
- $
- return GodotTypeInfo::METADATA_NONE;
- }
-
- Variant::Type _get_argument_type(int p_argument) const {
- $ifret if (p_argument==-1) return (Variant::Type)GetTypeInfo<R>::VARIANT_TYPE;$
- $arg if (p_argument==(@-1)) return (Variant::Type)GetTypeInfo<P@>::VARIANT_TYPE;
- $
- return Variant::NIL;
- }
-
- virtual PropertyInfo _gen_argument_type_info(int p_argument) const {
- $ifret if (p_argument==-1) return GetTypeInfo<R>::get_class_info();$
- $arg if (p_argument==(@-1)) return GetTypeInfo<P@>::get_class_info();
- $
- return PropertyInfo();
- }
-
-#endif
- virtual String get_instance_class() const {
- return type_name;
- }
-
- virtual Variant call(Object* p_object,const Variant** p_args,int p_arg_count, Callable::CallError& r_error) {
-
- __UnexistingClass *instance = (__UnexistingClass*)p_object;
-
- r_error.error=Callable::CallError::CALL_OK;
-#ifdef DEBUG_METHODS_ENABLED
-
- ERR_FAIL_COND_V(!instance,Variant());
- if (p_arg_count>get_argument_count()) {
- r_error.error=Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
- r_error.argument=get_argument_count();
- return Variant();
- }
-
- if (p_arg_count<(get_argument_count()-get_default_argument_count())) {
-
- r_error.error=Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
- r_error.argument=get_argument_count()-get_default_argument_count();
- return Variant();
- }
-
- $arg CHECK_ARG(@);
- $
-#endif
- $ifret Variant ret = $(instance->*method)($arg, _VC(@)$);
- $ifret return Variant(ret);$
- $ifnoret return Variant();$
- }
-#ifdef PTRCALL_ENABLED
- virtual void ptrcall(Object*p_object,const void** p_args,void *r_ret) {
- __UnexistingClass *instance = (__UnexistingClass*)p_object;
- $ifret PtrToArg<R>::encode( $ (instance->*method)($arg, PtrToArg<P@>::convert(p_args[@-1])$) $ifret ,r_ret) $ ;
- }
-#endif
- MethodBind$argc$$ifret R$$ifconst C$ () {
-#ifdef DEBUG_METHODS_ENABLED
- _set_const($ifconst true$$ifnoconst false$);
- _generate_argument_types($argc$);
-#else
- set_argument_count($argc$);
-#endif
- $ifret _set_returns(true); $
-
-
- }
-};
-
-template<class T $ifret ,class R$ $ifargs ,$ $arg, class P@$>
-MethodBind* create_method_bind($ifret R$ $ifnoret void$ (T::*p_method)($arg, P@$) $ifconst const$ ) {
-
- MethodBind$argc$$ifret R$$ifconst C$ $iftempl <$ $ifret R$ $ifretargs ,$ $arg, P@$ $iftempl >$ * a = memnew( (MethodBind$argc$$ifret R$$ifconst C$ $iftempl <$ $ifret R$ $ifretargs ,$ $arg, P@$ $iftempl >$) );
- union {
-
- $ifret R$ $ifnoret void$ (T::*sm)($arg, P@$) $ifconst const$;
- $ifret R$ $ifnoret void$ (__UnexistingClass::*dm)($arg, P@$) $ifconst const$;
- } u;
- u.sm=p_method;
- a->method=u.dm;
- a->type_name=T::get_class_static();
- return a;
-}
-#endif
-"""
-
-
-template_typed_free_func = """
-#ifdef TYPED_METHOD_BIND
-template<class T $ifret ,class R$ $ifargs ,$ $arg, class P@$>
-class FunctionBind$argc$$ifret R$$ifconst C$ : public MethodBind {
-public:
-
- $ifret R$ $ifnoret void$ (*method) ($ifconst const$ T *$ifargs , $$arg, P@$);
-#ifdef DEBUG_METHODS_ENABLED
- virtual Variant::Type _gen_argument_type(int p_arg) const { return _get_argument_type(p_arg); }
- virtual GodotTypeInfo::Metadata get_argument_meta(int p_arg) const {
- $ifret if (p_arg==-1) return GetTypeInfo<R>::METADATA;$
- $arg if (p_arg==(@-1)) return GetTypeInfo<P@>::METADATA;
- $
- return GodotTypeInfo::METADATA_NONE;
- }
- Variant::Type _get_argument_type(int p_argument) const {
- $ifret if (p_argument==-1) return (Variant::Type)GetTypeInfo<R>::VARIANT_TYPE;$
- $arg if (p_argument==(@-1)) return (Variant::Type)GetTypeInfo<P@>::VARIANT_TYPE;
- $
- return Variant::NIL;
- }
- virtual PropertyInfo _gen_argument_type_info(int p_argument) const {
- $ifret if (p_argument==-1) return GetTypeInfo<R>::get_class_info();$
- $arg if (p_argument==(@-1)) return GetTypeInfo<P@>::get_class_info();
- $
- return PropertyInfo();
- }
-#endif
- virtual String get_instance_class() const {
- return T::get_class_static();
- }
-
- virtual Variant call(Object* p_object,const Variant** p_args,int p_arg_count, Callable::CallError& r_error) {
-
- T *instance=Object::cast_to<T>(p_object);
- r_error.error=Callable::CallError::CALL_OK;
-#ifdef DEBUG_METHODS_ENABLED
-
- ERR_FAIL_COND_V(!instance,Variant());
- if (p_arg_count>get_argument_count()) {
- r_error.error=Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
- r_error.argument=get_argument_count();
- return Variant();
-
- }
- if (p_arg_count<(get_argument_count()-get_default_argument_count())) {
-
- r_error.error=Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
- r_error.argument=get_argument_count()-get_default_argument_count();
- return Variant();
- }
- $arg CHECK_ARG(@);
- $
-#endif
- $ifret Variant ret = $(method)(instance$ifargs , $$arg, _VC(@)$);
- $ifret return Variant(ret);$
- $ifnoret return Variant();$
- }
-
-#ifdef PTRCALL_ENABLED
- virtual void ptrcall(Object*p_object,const void** p_args,void *r_ret) {
-
- T *instance=Object::cast_to<T>(p_object);
- $ifret PtrToArg<R>::encode( $ (method)(instance$ifargs , $$arg, PtrToArg<P@>::convert(p_args[@-1])$) $ifret ,r_ret)$ ;
- }
-#endif
- FunctionBind$argc$$ifret R$$ifconst C$ () {
-#ifdef DEBUG_METHODS_ENABLED
- _set_const($ifconst true$$ifnoconst false$);
- _generate_argument_types($argc$);
-#else
- set_argument_count($argc$);
-#endif
-
- $ifret _set_returns(true); $
- }
-};
-
-template<class T $ifret ,class R$ $ifargs ,$ $arg, class P@$>
-MethodBind* create_method_bind($ifret R$ $ifnoret void$ (*p_method)($ifconst const$ T *$ifargs , $$arg, P@$) ) {
-
- FunctionBind$argc$$ifret R$$ifconst C$<T $ifret ,R$ $ifargs ,$ $arg, P@$> * a = memnew( (FunctionBind$argc$$ifret R$$ifconst C$<T $ifret ,R$ $ifargs ,$ $arg, P@$>) );
- a->method=p_method;
- return a;
-}
-#endif
-"""
-
-
-def make_version(template, nargs, argmax, const, ret):
-
- intext = template
- from_pos = 0
- outtext = ""
-
- while True:
- to_pos = intext.find("$", from_pos)
- if to_pos == -1:
- outtext += intext[from_pos:]
- break
- else:
- outtext += intext[from_pos:to_pos]
- end = intext.find("$", to_pos + 1)
- if end == -1:
- break # ignore
- macro = intext[to_pos + 1 : end]
- cmd = ""
- data = ""
-
- if macro.find(" ") != -1:
- cmd = macro[0 : macro.find(" ")]
- data = macro[macro.find(" ") + 1 :]
- else:
- cmd = macro
-
- if cmd == "argc":
- outtext += str(nargs)
- if cmd == "ifret" and ret:
- outtext += data
- if cmd == "ifargs" and nargs:
- outtext += data
- if cmd == "ifretargs" and nargs and ret:
- outtext += data
- if cmd == "ifconst" and const:
- outtext += data
- elif cmd == "ifnoconst" and not const:
- outtext += data
- elif cmd == "ifnoret" and not ret:
- outtext += data
- elif cmd == "iftempl" and (nargs > 0 or ret):
- outtext += data
- elif cmd == "arg,":
- for i in range(1, nargs + 1):
- if i > 1:
- outtext += ", "
- outtext += data.replace("@", str(i))
- elif cmd == "arg":
- for i in range(1, nargs + 1):
- outtext += data.replace("@", str(i))
- elif cmd == "noarg":
- for i in range(nargs + 1, argmax + 1):
- outtext += data.replace("@", str(i))
-
- from_pos = end + 1
-
- return outtext
-
-
-def run(target, source, env):
-
- versions = 15
- versions_ext = 6
- text = ""
- text_ext = ""
- text_free_func = "#ifndef METHOD_BIND_FREE_FUNC_H\n#define METHOD_BIND_FREE_FUNC_H\n"
- text_free_func += "\n//including this header file allows method binding to use free functions\n"
- text_free_func += (
- "//note that the free function must have a pointer to an instance of the class as its first parameter\n"
- )
-
- for i in range(0, versions + 1):
-
- t = ""
- t += make_version(template, i, versions, False, False)
- t += make_version(template_typed, i, versions, False, False)
- t += make_version(template, i, versions, False, True)
- t += make_version(template_typed, i, versions, False, True)
- t += make_version(template, i, versions, True, False)
- t += make_version(template_typed, i, versions, True, False)
- t += make_version(template, i, versions, True, True)
- t += make_version(template_typed, i, versions, True, True)
- if i >= versions_ext:
- text_ext += t
- else:
- text += t
-
- text_free_func += make_version(template_typed_free_func, i, versions, False, False)
- text_free_func += make_version(template_typed_free_func, i, versions, False, True)
- text_free_func += make_version(template_typed_free_func, i, versions, True, False)
- text_free_func += make_version(template_typed_free_func, i, versions, True, True)
-
- text_free_func += "#endif"
-
- with open(target[0], "w") as f:
- f.write(text)
-
- with open(target[1], "w") as f:
- f.write(text_ext)
-
- with open(target[2], "w") as f:
- f.write(text_free_func)
-
-
-if __name__ == "__main__":
- from platform_methods import subprocess_main
-
- subprocess_main(globals())
diff --git a/core/math/a_star.cpp b/core/math/a_star.cpp
index 30f712b2c3..b4410acf7d 100644
--- a/core/math/a_star.cpp
+++ b/core/math/a_star.cpp
@@ -31,7 +31,7 @@
#include "a_star.h"
#include "core/math/geometry_3d.h"
-#include "core/script_language.h"
+#include "core/object/script_language.h"
#include "scene/scene_string_names.h"
int AStar::get_available_point_id() const {
diff --git a/core/math/a_star.h b/core/math/a_star.h
index ba1c3033b8..7cfa73f2c2 100644
--- a/core/math/a_star.h
+++ b/core/math/a_star.h
@@ -31,8 +31,8 @@
#ifndef A_STAR_H
#define A_STAR_H
-#include "core/oa_hash_map.h"
-#include "core/reference.h"
+#include "core/object/reference.h"
+#include "core/templates/oa_hash_map.h"
/**
A* pathfinding algorithm
@@ -47,20 +47,20 @@ class AStar : public Reference {
struct Point {
Point() {}
- int id;
+ int id = 0;
Vector3 pos;
- real_t weight_scale;
- bool enabled;
+ real_t weight_scale = 0;
+ bool enabled = false;
OAHashMap<int, Point *> neighbours = 4u;
OAHashMap<int, Point *> unlinked_neighbours = 4u;
// Used for pathfinding.
- Point *prev_point;
- real_t g_score;
- real_t f_score;
- uint64_t open_pass;
- uint64_t closed_pass;
+ Point *prev_point = nullptr;
+ real_t g_score = 0;
+ real_t f_score = 0;
+ uint64_t open_pass = 0;
+ uint64_t closed_pass = 0;
};
struct SortPoints {
diff --git a/core/math/aabb.cpp b/core/math/aabb.cpp
index f5c667dab0..08673d0dd1 100644
--- a/core/math/aabb.cpp
+++ b/core/math/aabb.cpp
@@ -30,7 +30,8 @@
#include "aabb.h"
-#include "core/print_string.h"
+#include "core/string/print_string.h"
+#include "core/variant/variant.h"
real_t AABB::get_area() const {
return size.x * size.y * size.z;
@@ -375,6 +376,21 @@ void AABB::get_edge(int p_edge, Vector3 &r_from, Vector3 &r_to) const {
}
}
+Variant AABB::intersects_segment_bind(const Vector3 &p_from, const Vector3 &p_to) const {
+ Vector3 inters;
+ if (intersects_segment(p_from, p_to, &inters)) {
+ return inters;
+ }
+ return Variant();
+}
+Variant AABB::intersects_ray_bind(const Vector3 &p_from, const Vector3 &p_dir) const {
+ Vector3 inters;
+ if (intersects_ray(p_from, p_dir, &inters)) {
+ return inters;
+ }
+ return Variant();
+}
+
AABB::operator String() const {
return String() + position + " - " + size;
}
diff --git a/core/math/aabb.h b/core/math/aabb.h
index 4106fbb93c..45dcbc7f7f 100644
--- a/core/math/aabb.h
+++ b/core/math/aabb.h
@@ -39,6 +39,7 @@
* AABB / AABB (Axis Aligned Bounding Box)
* This is implemented by a point (position) and the box size
*/
+class Variant;
class AABB {
public:
@@ -99,6 +100,21 @@ public:
_FORCE_INLINE_ void project_range_in_plane(const Plane &p_plane, real_t &r_min, real_t &r_max) const;
_FORCE_INLINE_ void expand_to(const Vector3 &p_vector); /** expand to contain a point if necessary */
+ _FORCE_INLINE_ AABB abs() const {
+ return AABB(Vector3(position.x + MIN(size.x, 0), position.y + MIN(size.y, 0), position.z + MIN(size.z, 0)), size.abs());
+ }
+
+ Variant intersects_segment_bind(const Vector3 &p_from, const Vector3 &p_to) const;
+ Variant intersects_ray_bind(const Vector3 &p_from, const Vector3 &p_dir) const;
+
+ _FORCE_INLINE_ void set_end(const Vector3 &p_end) {
+ size = p_end - position;
+ }
+
+ _FORCE_INLINE_ Vector3 get_end() const {
+ return position + size;
+ }
+
operator String() const;
_FORCE_INLINE_ AABB() {}
diff --git a/core/math/audio_frame.h b/core/math/audio_frame.h
index 91f533eafb..43d4a63cd3 100644
--- a/core/math/audio_frame.h
+++ b/core/math/audio_frame.h
@@ -121,7 +121,7 @@ struct AudioFrame {
r = p_frame.r;
}
- _ALWAYS_INLINE_ AudioFrame operator=(const AudioFrame &p_frame) {
+ _ALWAYS_INLINE_ AudioFrame &operator=(const AudioFrame &p_frame) {
l = p_frame.l;
r = p_frame.r;
return *this;
diff --git a/core/math/basis.cpp b/core/math/basis.cpp
index dd38e25bb1..c6030d9757 100644
--- a/core/math/basis.cpp
+++ b/core/math/basis.cpp
@@ -32,7 +32,7 @@
#include "core/math/math_funcs.h"
#include "core/os/copymem.h"
-#include "core/print_string.h"
+#include "core/string/print_string.h"
#define cofac(row1, col1, row2, col2) \
(elements[row1][col1] * elements[row2][col2] - elements[row1][col2] * elements[row2][col1])
@@ -113,19 +113,22 @@ bool Basis::is_rotation() const {
return Math::is_equal_approx(determinant(), 1, UNIT_EPSILON) && is_orthogonal();
}
+#ifdef MATH_CHECKS
+// This method is only used once, in diagonalize. If it's desired elsewhere, feel free to remove the #ifdef.
bool Basis::is_symmetric() const {
- if (!Math::is_equal_approx_ratio(elements[0][1], elements[1][0], UNIT_EPSILON)) {
+ if (!Math::is_equal_approx(elements[0][1], elements[1][0])) {
return false;
}
- if (!Math::is_equal_approx_ratio(elements[0][2], elements[2][0], UNIT_EPSILON)) {
+ if (!Math::is_equal_approx(elements[0][2], elements[2][0])) {
return false;
}
- if (!Math::is_equal_approx_ratio(elements[1][2], elements[2][1], UNIT_EPSILON)) {
+ if (!Math::is_equal_approx(elements[1][2], elements[2][1])) {
return false;
}
return true;
}
+#endif
Basis Basis::diagonalize() {
//NOTE: only implemented for symmetric matrices
@@ -737,18 +740,6 @@ bool Basis::is_equal_approx(const Basis &p_basis) const {
return elements[0].is_equal_approx(p_basis.elements[0]) && elements[1].is_equal_approx(p_basis.elements[1]) && elements[2].is_equal_approx(p_basis.elements[2]);
}
-bool Basis::is_equal_approx_ratio(const Basis &a, const Basis &b, real_t p_epsilon) const {
- for (int i = 0; i < 3; i++) {
- for (int j = 0; j < 3; j++) {
- if (!Math::is_equal_approx_ratio(a.elements[i][j], b.elements[i][j], p_epsilon)) {
- return false;
- }
- }
- }
-
- return true;
-}
-
bool Basis::operator==(const Basis &p_matrix) const {
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
diff --git a/core/math/basis.h b/core/math/basis.h
index 985fb0e44f..2584f1ff48 100644
--- a/core/math/basis.h
+++ b/core/math/basis.h
@@ -36,7 +36,11 @@
class Basis {
public:
- Vector3 elements[3];
+ Vector3 elements[3] = {
+ Vector3(1, 0, 0),
+ Vector3(0, 1, 0),
+ Vector3(0, 0, 1)
+ };
_FORCE_INLINE_ const Vector3 &operator[](int axis) const {
return elements[axis];
@@ -142,9 +146,6 @@ public:
}
bool is_equal_approx(const Basis &p_basis) const;
- // TODO: Break compatibility in 4.0 by getting rid of this so that it's only an instance method. See also TODO in variant_call.cpp
- bool is_equal_approx(const Basis &a, const Basis &b) const { return a.is_equal_approx(b); }
- bool is_equal_approx_ratio(const Basis &a, const Basis &b, real_t p_epsilon = UNIT_EPSILON) const;
bool operator==(const Basis &p_matrix) const;
bool operator!=(const Basis &p_matrix) const;
@@ -234,7 +235,9 @@ public:
void orthonormalize();
Basis orthonormalized() const;
+#ifdef MATH_CHECKS
bool is_symmetric() const;
+#endif
Basis diagonalize();
operator Quat() const { return get_quat(); }
@@ -254,17 +257,7 @@ public:
elements[2] = row2;
}
- _FORCE_INLINE_ Basis() {
- elements[0][0] = 1;
- elements[0][1] = 0;
- elements[0][2] = 0;
- elements[1][0] = 0;
- elements[1][1] = 1;
- elements[1][2] = 0;
- elements[2][0] = 0;
- elements[2][1] = 0;
- elements[2][2] = 1;
- }
+ _FORCE_INLINE_ Basis() {}
};
_FORCE_INLINE_ void Basis::operator*=(const Basis &p_matrix) {
diff --git a/core/math/camera_matrix.cpp b/core/math/camera_matrix.cpp
index 22ab83f358..5e5efb6356 100644
--- a/core/math/camera_matrix.cpp
+++ b/core/math/camera_matrix.cpp
@@ -31,7 +31,7 @@
#include "camera_matrix.h"
#include "core/math/math_funcs.h"
-#include "core/print_string.h"
+#include "core/string/print_string.h"
float CameraMatrix::determinant() const {
return matrix[0][3] * matrix[1][2] * matrix[2][1] * matrix[3][0] - matrix[0][2] * matrix[1][3] * matrix[2][1] * matrix[3][0] -
@@ -278,7 +278,7 @@ Vector2 CameraMatrix::get_viewport_half_extents() const {
return Vector2(res.x, res.y);
}
-void CameraMatrix::get_far_plane_size(real_t &r_width, real_t &r_height) const {
+Vector2 CameraMatrix::get_far_plane_half_extents() const {
const real_t *matrix = (const real_t *)this->matrix;
///////--- Far Plane ---///////
Plane far_plane = Plane(matrix[3] - matrix[2],
@@ -303,8 +303,7 @@ void CameraMatrix::get_far_plane_size(real_t &r_width, real_t &r_height) const {
Vector3 res;
far_plane.intersect_3(right_plane, top_plane, &res);
- r_width = res.x;
- r_height = res.y;
+ return Vector2(res.x, res.y);
}
bool CameraMatrix::get_endpoints(const Transform &p_transform, Vector3 *p_8points) const {
diff --git a/core/math/camera_matrix.h b/core/math/camera_matrix.h
index 49fdecae02..c5cdd98377 100644
--- a/core/math/camera_matrix.h
+++ b/core/math/camera_matrix.h
@@ -74,7 +74,7 @@ struct CameraMatrix {
bool get_endpoints(const Transform &p_transform, Vector3 *p_8points) const;
Vector2 get_viewport_half_extents() const;
- void get_far_plane_size(real_t &r_width, real_t &r_height) const;
+ Vector2 get_far_plane_half_extents() const;
void invert();
CameraMatrix inverse() const;
diff --git a/core/color.cpp b/core/math/color.cpp
index 27a2d0af5c..2afe14bd63 100644
--- a/core/color.cpp
+++ b/core/math/color.cpp
@@ -30,10 +30,10 @@
#include "color.h"
-#include "core/color_names.inc"
-#include "core/map.h"
+#include "color_names.inc"
#include "core/math/math_funcs.h"
-#include "core/print_string.h"
+#include "core/string/print_string.h"
+#include "core/templates/map.h"
uint32_t Color::to_argb32() const {
uint32_t c = (uint8_t)Math::round(a * 255);
@@ -159,7 +159,7 @@ void Color::set_hsv(float p_h, float p_s, float p_v, float p_alpha) {
a = p_alpha;
if (p_s == 0) {
- // acp_hromatic (grey)
+ // Achromatic (grey)
r = g = b = p_v;
return;
}
@@ -217,12 +217,6 @@ void Color::invert() {
b = 1.0 - b;
}
-void Color::contrast() {
- r = Math::fmod(r + 0.5, 1.0);
- g = Math::fmod(g + 0.5, 1.0);
- b = Math::fmod(b + 0.5, 1.0);
-}
-
Color Color::hex(uint32_t p_hex) {
float a = (p_hex & 0xFF) / 255.0;
p_hex >>= 8;
@@ -261,33 +255,21 @@ Color Color::from_rgbe9995(uint32_t p_rgbe) {
return Color(rd, gd, bd, 1.0f);
}
-static float _parse_col(const String &p_str, int p_ofs) {
- int ig = 0;
+static int _parse_col4(const String &p_str, int p_ofs) {
+ char character = p_str[p_ofs];
- for (int i = 0; i < 2; i++) {
- int c = p_str[i + p_ofs];
- int v = 0;
-
- if (c >= '0' && c <= '9') {
- v = c - '0';
- } else if (c >= 'a' && c <= 'f') {
- v = c - 'a';
- v += 10;
- } else if (c >= 'A' && c <= 'F') {
- v = c - 'A';
- v += 10;
- } else {
- return -1;
- }
-
- if (i == 0) {
- ig += v * 16;
- } else {
- ig += v;
- }
+ if (character >= '0' && character <= '9') {
+ return character - '0';
+ } else if (character >= 'a' && character <= 'f') {
+ return character + (10 - 'a');
+ } else if (character >= 'A' && character <= 'F') {
+ return character + (10 - 'A');
}
+ return -1;
+}
- return ig;
+static int _parse_col8(const String &p_str, int p_ofs) {
+ return _parse_col4(p_str, p_ofs) * 16 + _parse_col4(p_str, p_ofs + 1);
}
Color Color::inverted() const {
@@ -296,55 +278,54 @@ Color Color::inverted() const {
return c;
}
-Color Color::contrasted() const {
- Color c = *this;
- c.contrast();
- return c;
-}
-
-Color Color::html(const String &p_color) {
- String color = p_color;
+Color Color::html(const String &p_rgba) {
+ String color = p_rgba;
if (color.length() == 0) {
return Color();
}
if (color[0] == '#') {
- color = color.substr(1, color.length() - 1);
- }
- if (color.length() == 3 || color.length() == 4) {
- String exp_color;
- for (int i = 0; i < color.length(); i++) {
- exp_color += color[i];
- exp_color += color[i];
- }
- color = exp_color;
+ color = color.substr(1);
}
+ // If enabled, use 1 hex digit per channel instead of 2.
+ // Other sizes aren't in the HTML/CSS spec but we could add them if desired.
+ bool is_shorthand = color.length() < 5;
bool alpha = false;
if (color.length() == 8) {
alpha = true;
} else if (color.length() == 6) {
alpha = false;
+ } else if (color.length() == 4) {
+ alpha = true;
+ } else if (color.length() == 3) {
+ alpha = false;
} else {
- ERR_FAIL_V_MSG(Color(), "Invalid color code: " + p_color + ".");
+ ERR_FAIL_V_MSG(Color(), "Invalid color code: " + p_rgba + ".");
}
- int a = 255;
- if (alpha) {
- a = _parse_col(color, 0);
- ERR_FAIL_COND_V_MSG(a < 0, Color(), "Invalid color code: " + p_color + ".");
+ float r, g, b, a = 1.0;
+ if (is_shorthand) {
+ r = _parse_col4(color, 0) / 15.0;
+ g = _parse_col4(color, 1) / 15.0;
+ b = _parse_col4(color, 2) / 15.0;
+ if (alpha) {
+ a = _parse_col4(color, 3) / 15.0;
+ }
+ } else {
+ r = _parse_col8(color, 0) / 255.0;
+ g = _parse_col8(color, 2) / 255.0;
+ b = _parse_col8(color, 4) / 255.0;
+ if (alpha) {
+ a = _parse_col8(color, 6) / 255.0;
+ }
}
+ ERR_FAIL_COND_V_MSG(r < 0, Color(), "Invalid color code: " + p_rgba + ".");
+ ERR_FAIL_COND_V_MSG(g < 0, Color(), "Invalid color code: " + p_rgba + ".");
+ ERR_FAIL_COND_V_MSG(b < 0, Color(), "Invalid color code: " + p_rgba + ".");
+ ERR_FAIL_COND_V_MSG(a < 0, Color(), "Invalid color code: " + p_rgba + ".");
- int from = alpha ? 2 : 0;
-
- int r = _parse_col(color, from + 0);
- ERR_FAIL_COND_V_MSG(r < 0, Color(), "Invalid color code: " + p_color + ".");
- int g = _parse_col(color, from + 2);
- ERR_FAIL_COND_V_MSG(g < 0, Color(), "Invalid color code: " + p_color + ".");
- int b = _parse_col(color, from + 4);
- ERR_FAIL_COND_V_MSG(b < 0, Color(), "Invalid color code: " + p_color + ".");
-
- return Color(r / 255.0, g / 255.0, b / 255.0, a / 255.0);
+ return Color(r, g, b, a);
}
bool Color::html_is_valid(const String &p_color) {
@@ -354,48 +335,26 @@ bool Color::html_is_valid(const String &p_color) {
return false;
}
if (color[0] == '#') {
- color = color.substr(1, color.length() - 1);
+ color = color.substr(1);
}
- bool alpha = false;
-
- if (color.length() == 8) {
- alpha = true;
- } else if (color.length() == 6) {
- alpha = false;
- } else {
+ // Check if the amount of hex digits is valid.
+ int len = color.length();
+ if (!(len == 3 || len == 4 || len == 6 || len == 8)) {
return false;
}
- if (alpha) {
- int a = _parse_col(color, 0);
- if (a < 0) {
+ // Check if each hex digit is valid.
+ for (int i = 0; i < len; i++) {
+ if (_parse_col4(color, i) == -1) {
return false;
}
}
- int from = alpha ? 2 : 0;
-
- int r = _parse_col(color, from + 0);
- if (r < 0) {
- return false;
- }
- int g = _parse_col(color, from + 2);
- if (g < 0) {
- return false;
- }
- int b = _parse_col(color, from + 4);
- if (b < 0) {
- return false;
- }
-
return true;
}
Color Color::named(const String &p_name) {
- if (_named_colors.empty()) {
- _populate_named_colors(); // from color_names.inc
- }
String name = p_name;
// Normalize name
name = name.replace(" ", "");
@@ -405,9 +364,31 @@ Color Color::named(const String &p_name) {
name = name.replace(".", "");
name = name.to_lower();
- const Map<String, Color>::Element *color = _named_colors.find(name);
- ERR_FAIL_NULL_V_MSG(color, Color(), "Invalid color name: " + p_name + ".");
- return color->value();
+ int idx = 0;
+ while (named_colors[idx].name != nullptr) {
+ if (name == named_colors[idx].name) {
+ return named_colors[idx].color;
+ }
+ idx++;
+ }
+
+ ERR_FAIL_V_MSG(Color(), "Invalid color name: " + p_name + ".");
+
+ return Color();
+}
+
+int Color::get_named_color_count() {
+ int idx = 0;
+ while (named_colors[idx].name != nullptr) {
+ idx++;
+ }
+ return idx;
+}
+String Color::get_named_color_name(int p_idx) {
+ return named_colors[p_idx].name;
+}
+Color Color::get_named_color(int p_idx) {
+ return named_colors[p_idx].color;
}
String _to_hex(float p_val) {
@@ -416,7 +397,7 @@ String _to_hex(float p_val) {
String ret;
for (int i = 0; i < 2; i++) {
- CharType c[2] = { 0, 0 };
+ char32_t c[2] = { 0, 0 };
int lv = v & 0xF;
if (lv < 10) {
c[0] = '0' + lv;
@@ -425,7 +406,7 @@ String _to_hex(float p_val) {
}
v >>= 4;
- String cs = (const CharType *)c;
+ String cs = (const char32_t *)c;
ret = cs + ret;
}
@@ -438,7 +419,7 @@ String Color::to_html(bool p_alpha) const {
txt += _to_hex(g);
txt += _to_hex(b);
if (p_alpha) {
- txt = _to_hex(a) + txt;
+ txt += _to_hex(a);
}
return txt;
}
@@ -508,6 +489,13 @@ Color Color::operator+(const Color &p_color) const {
a + p_color.a);
}
+void Color::operator+=(const Color &p_color) {
+ r = r + p_color.r;
+ g = g + p_color.g;
+ b = b + p_color.b;
+ a = a + p_color.a;
+}
+
Color Color::operator-(const Color &p_color) const {
return Color(
r - p_color.r,
@@ -531,12 +519,12 @@ Color Color::operator*(const Color &p_color) const {
a * p_color.a);
}
-Color Color::operator*(const real_t &rvalue) const {
+Color Color::operator*(real_t p_rvalue) const {
return Color(
- r * rvalue,
- g * rvalue,
- b * rvalue,
- a * rvalue);
+ r * p_rvalue,
+ g * p_rvalue,
+ b * p_rvalue,
+ a * p_rvalue);
}
void Color::operator*=(const Color &p_color) {
@@ -546,11 +534,11 @@ void Color::operator*=(const Color &p_color) {
a = a * p_color.a;
}
-void Color::operator*=(const real_t &rvalue) {
- r = r * rvalue;
- g = g * rvalue;
- b = b * rvalue;
- a = a * rvalue;
+void Color::operator*=(real_t p_rvalue) {
+ r = r * p_rvalue;
+ g = g * p_rvalue;
+ b = b * p_rvalue;
+ a = a * p_rvalue;
}
Color Color::operator/(const Color &p_color) const {
@@ -561,12 +549,12 @@ Color Color::operator/(const Color &p_color) const {
a / p_color.a);
}
-Color Color::operator/(const real_t &rvalue) const {
+Color Color::operator/(real_t p_rvalue) const {
return Color(
- r / rvalue,
- g / rvalue,
- b / rvalue,
- a / rvalue);
+ r / p_rvalue,
+ g / p_rvalue,
+ b / p_rvalue,
+ a / p_rvalue);
}
void Color::operator/=(const Color &p_color) {
@@ -576,17 +564,17 @@ void Color::operator/=(const Color &p_color) {
a = a / p_color.a;
}
-void Color::operator/=(const real_t &rvalue) {
- if (rvalue == 0) {
+void Color::operator/=(real_t p_rvalue) {
+ if (p_rvalue == 0) {
r = 1.0;
g = 1.0;
b = 1.0;
a = 1.0;
} else {
- r = r / rvalue;
- g = g / rvalue;
- b = b / rvalue;
- a = a / rvalue;
+ r = r / p_rvalue;
+ g = g / p_rvalue;
+ b = b / p_rvalue;
+ a = a / p_rvalue;
}
}
diff --git a/core/color.h b/core/math/color.h
index 258965fd16..a9be9e9035 100644
--- a/core/color.h
+++ b/core/math/color.h
@@ -32,7 +32,7 @@
#define COLOR_H
#include "core/math/math_funcs.h"
-#include "core/ustring.h"
+#include "core/string/ustring.h"
struct Color {
union {
@@ -45,9 +45,6 @@ struct Color {
float components[4] = { 0, 0, 0, 1.0 };
};
- bool operator==(const Color &p_color) const { return (r == p_color.r && g == p_color.g && b == p_color.b && a == p_color.a); }
- bool operator!=(const Color &p_color) const { return (r != p_color.r || g != p_color.g || b != p_color.b || a != p_color.a); }
-
uint32_t to_rgba32() const;
uint32_t to_argb32() const;
uint32_t to_abgr32() const;
@@ -59,41 +56,41 @@ struct Color {
float get_v() const;
void set_hsv(float p_h, float p_s, float p_v, float p_alpha = 1.0);
- _FORCE_INLINE_ float &operator[](int idx) {
- return components[idx];
+ _FORCE_INLINE_ float &operator[](int p_idx) {
+ return components[p_idx];
}
- _FORCE_INLINE_ const float &operator[](int idx) const {
- return components[idx];
+ _FORCE_INLINE_ const float &operator[](int p_idx) const {
+ return components[p_idx];
}
- Color operator+(const Color &p_color) const;
- _FORCE_INLINE_ void operator+=(const Color &p_color) {
- r = r + p_color.r;
- g = g + p_color.g;
- b = b + p_color.b;
- a = a + p_color.a;
+ bool operator==(const Color &p_color) const {
+ return (r == p_color.r && g == p_color.g && b == p_color.b && a == p_color.a);
+ }
+ bool operator!=(const Color &p_color) const {
+ return (r != p_color.r || g != p_color.g || b != p_color.b || a != p_color.a);
}
+ Color operator+(const Color &p_color) const;
+ void operator+=(const Color &p_color);
+
Color operator-() const;
Color operator-(const Color &p_color) const;
void operator-=(const Color &p_color);
Color operator*(const Color &p_color) const;
- Color operator*(const real_t &rvalue) const;
+ Color operator*(real_t p_rvalue) const;
void operator*=(const Color &p_color);
- void operator*=(const real_t &rvalue);
+ void operator*=(real_t p_rvalue);
Color operator/(const Color &p_color) const;
- Color operator/(const real_t &rvalue) const;
+ Color operator/(real_t p_rvalue) const;
void operator/=(const Color &p_color);
- void operator/=(const real_t &rvalue);
+ void operator/=(real_t p_rvalue);
bool is_equal_approx(const Color &p_color) const;
void invert();
- void contrast();
Color inverted() const;
- Color contrasted() const;
_FORCE_INLINE_ Color lerp(const Color &p_b, float p_t) const {
Color res = *this;
@@ -125,10 +122,9 @@ struct Color {
_FORCE_INLINE_ uint32_t to_rgbe9995() const {
const float pow2to9 = 512.0f;
const float B = 15.0f;
- //const float Emax = 31.0f;
const float N = 9.0f;
- float sharedexp = 65408.000f; //(( pow2to9 - 1.0f)/ pow2to9)*powf( 2.0f, 31.0f - 15.0f);
+ float sharedexp = 65408.000f; // Result of: ((pow2to9 - 1.0f) / pow2to9) * powf(2.0f, 31.0f - 15.0f)
float cRed = MAX(0.0f, MIN(sharedexp, r));
float cGreen = MAX(0.0f, MIN(sharedexp, g));
@@ -136,8 +132,6 @@ struct Color {
float cMax = MAX(cRed, MAX(cGreen, cBlue));
- // expp = MAX(-B - 1, log2(maxc)) + 1 + B
-
float expp = MAX(-B - 1.0f, floor(Math::log(cMax) / Math_LN2)) + 1.0f + B;
float sMax = (float)floor((cMax / Math::pow(2.0f, expp - B - N)) + 0.5f);
@@ -185,9 +179,12 @@ struct Color {
static Color hex(uint32_t p_hex);
static Color hex64(uint64_t p_hex);
- static Color html(const String &p_color);
+ static Color html(const String &p_rgba);
static bool html_is_valid(const String &p_color);
static Color named(const String &p_name);
+ static int get_named_color_count();
+ static String get_named_color_name(int p_idx);
+ static Color get_named_color(int p_idx);
String to_html(bool p_alpha = true) const;
Color from_hsv(float p_h, float p_s, float p_v, float p_a) const;
static Color from_rgbe9995(uint32_t p_rgbe);
@@ -195,12 +192,27 @@ struct Color {
_FORCE_INLINE_ bool operator<(const Color &p_color) const; //used in set keys
operator String() const;
+ // For the binder.
+ _FORCE_INLINE_ void set_r8(int32_t r8) { r = (CLAMP(r8, 0, 255) / 255.0); }
+ _FORCE_INLINE_ int32_t get_r8() const { return int32_t(CLAMP(r * 255.0, 0.0, 255.0)); }
+ _FORCE_INLINE_ void set_g8(int32_t g8) { g = (CLAMP(g8, 0, 255) / 255.0); }
+ _FORCE_INLINE_ int32_t get_g8() const { return int32_t(CLAMP(g * 255.0, 0.0, 255.0)); }
+ _FORCE_INLINE_ void set_b8(int32_t b8) { b = (CLAMP(b8, 0, 255) / 255.0); }
+ _FORCE_INLINE_ int32_t get_b8() const { return int32_t(CLAMP(b * 255.0, 0.0, 255.0)); }
+ _FORCE_INLINE_ void set_a8(int32_t a8) { a = (CLAMP(a8, 0, 255) / 255.0); }
+ _FORCE_INLINE_ int32_t get_a8() const { return int32_t(CLAMP(a * 255.0, 0.0, 255.0)); }
+
+ _FORCE_INLINE_ void set_h(float p_h) { set_hsv(p_h, get_s(), get_v()); }
+ _FORCE_INLINE_ void set_s(float p_s) { set_hsv(get_h(), p_s, get_v()); }
+ _FORCE_INLINE_ void set_v(float p_v) { set_hsv(get_h(), get_s(), p_v); }
+
_FORCE_INLINE_ Color() {}
/**
- * RGB / RGBA construct parameters. Alpha is optional, but defaults to 1.0
+ * RGBA construct parameters.
+ * Alpha is not optional as otherwise we can't bind the RGB version for scripting.
*/
- _FORCE_INLINE_ Color(float p_r, float p_g, float p_b, float p_a = 1.0) {
+ _FORCE_INLINE_ Color(float p_r, float p_g, float p_b, float p_a) {
r = p_r;
g = p_g;
b = p_b;
@@ -208,6 +220,16 @@ struct Color {
}
/**
+ * RGB construct parameters.
+ */
+ _FORCE_INLINE_ Color(float p_r, float p_g, float p_b) {
+ r = p_r;
+ g = p_g;
+ b = p_b;
+ a = 1.0;
+ }
+
+ /**
* Construct a Color from another Color, but with the specified alpha value.
*/
_FORCE_INLINE_ Color(const Color &p_c, float p_a) {
@@ -234,4 +256,8 @@ bool Color::operator<(const Color &p_color) const {
}
}
+_FORCE_INLINE_ Color operator*(real_t p_real, const Color &p_color) {
+ return p_color * p_real;
+}
+
#endif // COLOR_H
diff --git a/core/math/color_names.inc b/core/math/color_names.inc
new file mode 100644
index 0000000000..523c7e3c59
--- /dev/null
+++ b/core/math/color_names.inc
@@ -0,0 +1,160 @@
+// Names from https://en.wikipedia.org/wiki/X11_color_names
+
+// So this in a way that does not require memory allocation
+// the old way leaked memory
+// this is not used as often as for more performance to make sense
+
+struct NamedColor {
+ const char *name;
+ Color color;
+};
+
+static NamedColor named_colors[] = {
+ { "aliceblue", Color(0.94, 0.97, 1.00) },
+ { "antiquewhite", Color(0.98, 0.92, 0.84) },
+ { "aqua", Color(0.00, 1.00, 1.00) },
+ { "aquamarine", Color(0.50, 1.00, 0.83) },
+ { "azure", Color(0.94, 1.00, 1.00) },
+ { "beige", Color(0.96, 0.96, 0.86) },
+ { "bisque", Color(1.00, 0.89, 0.77) },
+ { "black", Color(0.00, 0.00, 0.00) },
+ { "blanchedalmond", Color(1.00, 0.92, 0.80) },
+ { "blue", Color(0.00, 0.00, 1.00) },
+ { "blueviolet", Color(0.54, 0.17, 0.89) },
+ { "brown", Color(0.65, 0.16, 0.16) },
+ { "burlywood", Color(0.87, 0.72, 0.53) },
+ { "cadetblue", Color(0.37, 0.62, 0.63) },
+ { "chartreuse", Color(0.50, 1.00, 0.00) },
+ { "chocolate", Color(0.82, 0.41, 0.12) },
+ { "coral", Color(1.00, 0.50, 0.31) },
+ { "cornflower", Color(0.39, 0.58, 0.93) },
+ { "cornsilk", Color(1.00, 0.97, 0.86) },
+ { "crimson", Color(0.86, 0.08, 0.24) },
+ { "cyan", Color(0.00, 1.00, 1.00) },
+ { "darkblue", Color(0.00, 0.00, 0.55) },
+ { "darkcyan", Color(0.00, 0.55, 0.55) },
+ { "darkgoldenrod", Color(0.72, 0.53, 0.04) },
+ { "darkgray", Color(0.66, 0.66, 0.66) },
+ { "darkgreen", Color(0.00, 0.39, 0.00) },
+ { "darkkhaki", Color(0.74, 0.72, 0.42) },
+ { "darkmagenta", Color(0.55, 0.00, 0.55) },
+ { "darkolivegreen", Color(0.33, 0.42, 0.18) },
+ { "darkorange", Color(1.00, 0.55, 0.00) },
+ { "darkorchid", Color(0.60, 0.20, 0.80) },
+ { "darkred", Color(0.55, 0.00, 0.00) },
+ { "darksalmon", Color(0.91, 0.59, 0.48) },
+ { "darkseagreen", Color(0.56, 0.74, 0.56) },
+ { "darkslateblue", Color(0.28, 0.24, 0.55) },
+ { "darkslategray", Color(0.18, 0.31, 0.31) },
+ { "darkturquoise", Color(0.00, 0.81, 0.82) },
+ { "darkviolet", Color(0.58, 0.00, 0.83) },
+ { "deeppink", Color(1.00, 0.08, 0.58) },
+ { "deepskyblue", Color(0.00, 0.75, 1.00) },
+ { "dimgray", Color(0.41, 0.41, 0.41) },
+ { "dodgerblue", Color(0.12, 0.56, 1.00) },
+ { "firebrick", Color(0.70, 0.13, 0.13) },
+ { "floralwhite", Color(1.00, 0.98, 0.94) },
+ { "forestgreen", Color(0.13, 0.55, 0.13) },
+ { "fuchsia", Color(1.00, 0.00, 1.00) },
+ { "gainsboro", Color(0.86, 0.86, 0.86) },
+ { "ghostwhite", Color(0.97, 0.97, 1.00) },
+ { "gold", Color(1.00, 0.84, 0.00) },
+ { "goldenrod", Color(0.85, 0.65, 0.13) },
+ { "gray", Color(0.75, 0.75, 0.75) },
+ { "green", Color(0.00, 1.00, 0.00) },
+ { "greenyellow", Color(0.68, 1.00, 0.18) },
+ { "honeydew", Color(0.94, 1.00, 0.94) },
+ { "hotpink", Color(1.00, 0.41, 0.71) },
+ { "indianred", Color(0.80, 0.36, 0.36) },
+ { "indigo", Color(0.29, 0.00, 0.51) },
+ { "ivory", Color(1.00, 1.00, 0.94) },
+ { "khaki", Color(0.94, 0.90, 0.55) },
+ { "lavender", Color(0.90, 0.90, 0.98) },
+ { "lavenderblush", Color(1.00, 0.94, 0.96) },
+ { "lawngreen", Color(0.49, 0.99, 0.00) },
+ { "lemonchiffon", Color(1.00, 0.98, 0.80) },
+ { "lightblue", Color(0.68, 0.85, 0.90) },
+ { "lightcoral", Color(0.94, 0.50, 0.50) },
+ { "lightcyan", Color(0.88, 1.00, 1.00) },
+ { "lightgoldenrod", Color(0.98, 0.98, 0.82) },
+ { "lightgray", Color(0.83, 0.83, 0.83) },
+ { "lightgreen", Color(0.56, 0.93, 0.56) },
+ { "lightpink", Color(1.00, 0.71, 0.76) },
+ { "lightsalmon", Color(1.00, 0.63, 0.48) },
+ { "lightseagreen", Color(0.13, 0.70, 0.67) },
+ { "lightskyblue", Color(0.53, 0.81, 0.98) },
+ { "lightslategray", Color(0.47, 0.53, 0.60) },
+ { "lightsteelblue", Color(0.69, 0.77, 0.87) },
+ { "lightyellow", Color(1.00, 1.00, 0.88) },
+ { "lime", Color(0.00, 1.00, 0.00) },
+ { "limegreen", Color(0.20, 0.80, 0.20) },
+ { "linen", Color(0.98, 0.94, 0.90) },
+ { "magenta", Color(1.00, 0.00, 1.00) },
+ { "maroon", Color(0.69, 0.19, 0.38) },
+ { "mediumaquamarine", Color(0.40, 0.80, 0.67) },
+ { "mediumblue", Color(0.00, 0.00, 0.80) },
+ { "mediumorchid", Color(0.73, 0.33, 0.83) },
+ { "mediumpurple", Color(0.58, 0.44, 0.86) },
+ { "mediumseagreen", Color(0.24, 0.70, 0.44) },
+ { "mediumslateblue", Color(0.48, 0.41, 0.93) },
+ { "mediumspringgreen", Color(0.00, 0.98, 0.60) },
+ { "mediumturquoise", Color(0.28, 0.82, 0.80) },
+ { "mediumvioletred", Color(0.78, 0.08, 0.52) },
+ { "midnightblue", Color(0.10, 0.10, 0.44) },
+ { "mintcream", Color(0.96, 1.00, 0.98) },
+ { "mistyrose", Color(1.00, 0.89, 0.88) },
+ { "moccasin", Color(1.00, 0.89, 0.71) },
+ { "navajowhite", Color(1.00, 0.87, 0.68) },
+ { "navyblue", Color(0.00, 0.00, 0.50) },
+ { "oldlace", Color(0.99, 0.96, 0.90) },
+ { "olive", Color(0.50, 0.50, 0.00) },
+ { "olivedrab", Color(0.42, 0.56, 0.14) },
+ { "orange", Color(1.00, 0.65, 0.00) },
+ { "orangered", Color(1.00, 0.27, 0.00) },
+ { "orchid", Color(0.85, 0.44, 0.84) },
+ { "palegoldenrod", Color(0.93, 0.91, 0.67) },
+ { "palegreen", Color(0.60, 0.98, 0.60) },
+ { "paleturquoise", Color(0.69, 0.93, 0.93) },
+ { "palevioletred", Color(0.86, 0.44, 0.58) },
+ { "papayawhip", Color(1.00, 0.94, 0.84) },
+ { "peachpuff", Color(1.00, 0.85, 0.73) },
+ { "peru", Color(0.80, 0.52, 0.25) },
+ { "pink", Color(1.00, 0.75, 0.80) },
+ { "plum", Color(0.87, 0.63, 0.87) },
+ { "powderblue", Color(0.69, 0.88, 0.90) },
+ { "purple", Color(0.63, 0.13, 0.94) },
+ { "rebeccapurple", Color(0.40, 0.20, 0.60) },
+ { "red", Color(1.00, 0.00, 0.00) },
+ { "rosybrown", Color(0.74, 0.56, 0.56) },
+ { "royalblue", Color(0.25, 0.41, 0.88) },
+ { "saddlebrown", Color(0.55, 0.27, 0.07) },
+ { "salmon", Color(0.98, 0.50, 0.45) },
+ { "sandybrown", Color(0.96, 0.64, 0.38) },
+ { "seagreen", Color(0.18, 0.55, 0.34) },
+ { "seashell", Color(1.00, 0.96, 0.93) },
+ { "sienna", Color(0.63, 0.32, 0.18) },
+ { "silver", Color(0.75, 0.75, 0.75) },
+ { "skyblue", Color(0.53, 0.81, 0.92) },
+ { "slateblue", Color(0.42, 0.35, 0.80) },
+ { "slategray", Color(0.44, 0.50, 0.56) },
+ { "snow", Color(1.00, 0.98, 0.98) },
+ { "springgreen", Color(0.00, 1.00, 0.50) },
+ { "steelblue", Color(0.27, 0.51, 0.71) },
+ { "tan", Color(0.82, 0.71, 0.55) },
+ { "teal", Color(0.00, 0.50, 0.50) },
+ { "thistle", Color(0.85, 0.75, 0.85) },
+ { "tomato", Color(1.00, 0.39, 0.28) },
+ { "transparent", Color(1.00, 1.00, 1.00, 0.00) },
+ { "turquoise", Color(0.25, 0.88, 0.82) },
+ { "violet", Color(0.93, 0.51, 0.93) },
+ { "webgray", Color(0.50, 0.50, 0.50) },
+ { "webgreen", Color(0.00, 0.50, 0.00) },
+ { "webmaroon", Color(0.50, 0.00, 0.00) },
+ { "webpurple", Color(0.50, 0.00, 0.50) },
+ { "wheat", Color(0.96, 0.87, 0.70) },
+ { "white", Color(1.00, 1.00, 1.00) },
+ { "whitesmoke", Color(0.96, 0.96, 0.96) },
+ { "yellow", Color(1.00, 1.00, 0.00) },
+ { "yellowgreen", Color(0.60, 0.80, 0.20) },
+ { nullptr, Color(0.60, 0.80, 0.20) },
+};
diff --git a/core/math/delaunay_3d.h b/core/math/delaunay_3d.h
index 014b4c4621..ea8655cfff 100644
--- a/core/math/delaunay_3d.h
+++ b/core/math/delaunay_3d.h
@@ -31,15 +31,15 @@
#ifndef DELAUNAY_3D_H
#define DELAUNAY_3D_H
-#include "core/local_vector.h"
#include "core/math/aabb.h"
#include "core/math/camera_matrix.h"
#include "core/math/vector3.h"
-#include "core/oa_hash_map.h"
#include "core/os/file_access.h"
-#include "core/print_string.h"
-#include "core/variant.h"
-#include "core/vector.h"
+#include "core/string/print_string.h"
+#include "core/templates/local_vector.h"
+#include "core/templates/oa_hash_map.h"
+#include "core/templates/vector.h"
+#include "core/variant/variant.h"
#include "thirdparty/misc/r128.h"
diff --git a/core/math/disjoint_set.h b/core/math/disjoint_set.h
index 198f46e111..51b9ce81af 100644
--- a/core/math/disjoint_set.h
+++ b/core/math/disjoint_set.h
@@ -31,8 +31,8 @@
#ifndef DISJOINT_SET_H
#define DISJOINT_SET_H
-#include "core/map.h"
-#include "core/vector.h"
+#include "core/templates/map.h"
+#include "core/templates/vector.h"
/**
@author Marios Staikopoulos <marios@staik.net>
diff --git a/core/math/expression.cpp b/core/math/expression.cpp
index 13a49feb6b..d1f15caa5e 100644
--- a/core/math/expression.cpp
+++ b/core/math/expression.cpp
@@ -30,716 +30,14 @@
#include "expression.h"
-#include "core/class_db.h"
-#include "core/func_ref.h"
#include "core/io/marshalls.h"
#include "core/math/math_funcs.h"
+#include "core/object/class_db.h"
+#include "core/object/reference.h"
#include "core/os/os.h"
-#include "core/reference.h"
-#include "core/variant_parser.h"
-
-const char *Expression::func_name[Expression::FUNC_MAX] = {
- "sin",
- "cos",
- "tan",
- "sinh",
- "cosh",
- "tanh",
- "asin",
- "acos",
- "atan",
- "atan2",
- "sqrt",
- "fmod",
- "fposmod",
- "posmod",
- "floor",
- "ceil",
- "round",
- "abs",
- "sign",
- "pow",
- "log",
- "exp",
- "is_nan",
- "is_inf",
- "ease",
- "step_decimals",
- "stepify",
- "lerp",
- "lerp_angle",
- "inverse_lerp",
- "range_lerp",
- "smoothstep",
- "move_toward",
- "dectime",
- "randomize",
- "randi",
- "randf",
- "rand_range",
- "seed",
- "rand_seed",
- "deg2rad",
- "rad2deg",
- "linear2db",
- "db2linear",
- "polar2cartesian",
- "cartesian2polar",
- "wrapi",
- "wrapf",
- "max",
- "min",
- "clamp",
- "nearest_po2",
- "weakref",
- "funcref",
- "convert",
- "typeof",
- "type_exists",
- "char",
- "ord",
- "str",
- "print",
- "printerr",
- "printraw",
- "var2str",
- "str2var",
- "var2bytes",
- "bytes2var",
- "color_named",
-};
-
-Expression::BuiltinFunc Expression::find_function(const String &p_string) {
- for (int i = 0; i < FUNC_MAX; i++) {
- if (p_string == func_name[i]) {
- return BuiltinFunc(i);
- }
- }
-
- return FUNC_MAX;
-}
-
-String Expression::get_func_name(BuiltinFunc p_func) {
- ERR_FAIL_INDEX_V(p_func, FUNC_MAX, String());
- return func_name[p_func];
-}
-
-int Expression::get_func_argument_count(BuiltinFunc p_func) {
- switch (p_func) {
- case MATH_RANDOMIZE:
- case MATH_RAND:
- case MATH_RANDF:
- return 0;
- case MATH_SIN:
- case MATH_COS:
- case MATH_TAN:
- case MATH_SINH:
- case MATH_COSH:
- case MATH_TANH:
- case MATH_ASIN:
- case MATH_ACOS:
- case MATH_ATAN:
- case MATH_SQRT:
- case MATH_FLOOR:
- case MATH_CEIL:
- case MATH_ROUND:
- case MATH_ABS:
- case MATH_SIGN:
- case MATH_LOG:
- case MATH_EXP:
- case MATH_ISNAN:
- case MATH_ISINF:
- case MATH_STEP_DECIMALS:
- case MATH_SEED:
- case MATH_RANDSEED:
- case MATH_DEG2RAD:
- case MATH_RAD2DEG:
- case MATH_LINEAR2DB:
- case MATH_DB2LINEAR:
- case LOGIC_NEAREST_PO2:
- case OBJ_WEAKREF:
- case TYPE_OF:
- case TEXT_CHAR:
- case TEXT_ORD:
- case TEXT_STR:
- case TEXT_PRINT:
- case TEXT_PRINTERR:
- case TEXT_PRINTRAW:
- case VAR_TO_STR:
- case STR_TO_VAR:
- case TYPE_EXISTS:
- return 1;
- case VAR_TO_BYTES:
- case BYTES_TO_VAR:
- case MATH_ATAN2:
- case MATH_FMOD:
- case MATH_FPOSMOD:
- case MATH_POSMOD:
- case MATH_POW:
- case MATH_EASE:
- case MATH_STEPIFY:
- case MATH_RANDOM:
- case MATH_POLAR2CARTESIAN:
- case MATH_CARTESIAN2POLAR:
- case LOGIC_MAX:
- case LOGIC_MIN:
- case FUNC_FUNCREF:
- case TYPE_CONVERT:
- case COLORN:
- return 2;
- case MATH_LERP:
- case MATH_LERP_ANGLE:
- case MATH_INVERSE_LERP:
- case MATH_SMOOTHSTEP:
- case MATH_MOVE_TOWARD:
- case MATH_DECTIME:
- case MATH_WRAP:
- case MATH_WRAPF:
- case LOGIC_CLAMP:
- return 3;
- case MATH_RANGE_LERP:
- return 5;
- case FUNC_MAX: {
- }
- }
- return 0;
-}
+#include "core/variant/variant_parser.h"
-#define VALIDATE_ARG_NUM(m_arg) \
- if (!p_inputs[m_arg]->is_num()) { \
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; \
- r_error.argument = m_arg; \
- r_error.expected = Variant::FLOAT; \
- return; \
- }
-
-void Expression::exec_func(BuiltinFunc p_func, const Variant **p_inputs, Variant *r_return, Callable::CallError &r_error, String &r_error_str) {
- r_error.error = Callable::CallError::CALL_OK;
- switch (p_func) {
- case MATH_SIN: {
- VALIDATE_ARG_NUM(0);
- *r_return = Math::sin((double)*p_inputs[0]);
- } break;
- case MATH_COS: {
- VALIDATE_ARG_NUM(0);
- *r_return = Math::cos((double)*p_inputs[0]);
- } break;
- case MATH_TAN: {
- VALIDATE_ARG_NUM(0);
- *r_return = Math::tan((double)*p_inputs[0]);
- } break;
- case MATH_SINH: {
- VALIDATE_ARG_NUM(0);
- *r_return = Math::sinh((double)*p_inputs[0]);
- } break;
- case MATH_COSH: {
- VALIDATE_ARG_NUM(0);
- *r_return = Math::cosh((double)*p_inputs[0]);
- } break;
- case MATH_TANH: {
- VALIDATE_ARG_NUM(0);
- *r_return = Math::tanh((double)*p_inputs[0]);
- } break;
- case MATH_ASIN: {
- VALIDATE_ARG_NUM(0);
- *r_return = Math::asin((double)*p_inputs[0]);
- } break;
- case MATH_ACOS: {
- VALIDATE_ARG_NUM(0);
- *r_return = Math::acos((double)*p_inputs[0]);
- } break;
- case MATH_ATAN: {
- VALIDATE_ARG_NUM(0);
- *r_return = Math::atan((double)*p_inputs[0]);
- } break;
- case MATH_ATAN2: {
- VALIDATE_ARG_NUM(0);
- VALIDATE_ARG_NUM(1);
- *r_return = Math::atan2((double)*p_inputs[0], (double)*p_inputs[1]);
- } break;
- case MATH_SQRT: {
- VALIDATE_ARG_NUM(0);
- *r_return = Math::sqrt((double)*p_inputs[0]);
- } break;
- case MATH_FMOD: {
- VALIDATE_ARG_NUM(0);
- VALIDATE_ARG_NUM(1);
- *r_return = Math::fmod((double)*p_inputs[0], (double)*p_inputs[1]);
- } break;
- case MATH_FPOSMOD: {
- VALIDATE_ARG_NUM(0);
- VALIDATE_ARG_NUM(1);
- *r_return = Math::fposmod((double)*p_inputs[0], (double)*p_inputs[1]);
- } break;
- case MATH_POSMOD: {
- VALIDATE_ARG_NUM(0);
- VALIDATE_ARG_NUM(1);
- *r_return = Math::posmod((int)*p_inputs[0], (int)*p_inputs[1]);
- } break;
- case MATH_FLOOR: {
- VALIDATE_ARG_NUM(0);
- *r_return = Math::floor((double)*p_inputs[0]);
- } break;
- case MATH_CEIL: {
- VALIDATE_ARG_NUM(0);
- *r_return = Math::ceil((double)*p_inputs[0]);
- } break;
- case MATH_ROUND: {
- VALIDATE_ARG_NUM(0);
- *r_return = Math::round((double)*p_inputs[0]);
- } break;
- case MATH_ABS: {
- if (p_inputs[0]->get_type() == Variant::INT) {
- int64_t i = *p_inputs[0];
- *r_return = ABS(i);
- } else if (p_inputs[0]->get_type() == Variant::FLOAT) {
- real_t r = *p_inputs[0];
- *r_return = Math::abs(r);
- } else {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 0;
- r_error.expected = Variant::FLOAT;
- }
- } break;
- case MATH_SIGN: {
- if (p_inputs[0]->get_type() == Variant::INT) {
- int64_t i = *p_inputs[0];
- *r_return = i < 0 ? -1 : (i > 0 ? +1 : 0);
- } else if (p_inputs[0]->get_type() == Variant::FLOAT) {
- real_t r = *p_inputs[0];
- *r_return = r < 0.0 ? -1.0 : (r > 0.0 ? +1.0 : 0.0);
- } else {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 0;
- r_error.expected = Variant::FLOAT;
- }
- } break;
- case MATH_POW: {
- VALIDATE_ARG_NUM(0);
- VALIDATE_ARG_NUM(1);
- *r_return = Math::pow((double)*p_inputs[0], (double)*p_inputs[1]);
- } break;
- case MATH_LOG: {
- VALIDATE_ARG_NUM(0);
- *r_return = Math::log((double)*p_inputs[0]);
- } break;
- case MATH_EXP: {
- VALIDATE_ARG_NUM(0);
- *r_return = Math::exp((double)*p_inputs[0]);
- } break;
- case MATH_ISNAN: {
- VALIDATE_ARG_NUM(0);
- *r_return = Math::is_nan((double)*p_inputs[0]);
- } break;
- case MATH_ISINF: {
- VALIDATE_ARG_NUM(0);
- *r_return = Math::is_inf((double)*p_inputs[0]);
- } break;
- case MATH_EASE: {
- VALIDATE_ARG_NUM(0);
- VALIDATE_ARG_NUM(1);
- *r_return = Math::ease((double)*p_inputs[0], (double)*p_inputs[1]);
- } break;
- case MATH_STEP_DECIMALS: {
- VALIDATE_ARG_NUM(0);
- *r_return = Math::step_decimals((double)*p_inputs[0]);
- } break;
- case MATH_STEPIFY: {
- VALIDATE_ARG_NUM(0);
- VALIDATE_ARG_NUM(1);
- *r_return = Math::stepify((double)*p_inputs[0], (double)*p_inputs[1]);
- } break;
- case MATH_LERP: {
- VALIDATE_ARG_NUM(0);
- VALIDATE_ARG_NUM(1);
- VALIDATE_ARG_NUM(2);
- *r_return = Math::lerp((double)*p_inputs[0], (double)*p_inputs[1], (double)*p_inputs[2]);
- } break;
- case MATH_LERP_ANGLE: {
- VALIDATE_ARG_NUM(0);
- VALIDATE_ARG_NUM(1);
- VALIDATE_ARG_NUM(2);
- *r_return = Math::lerp_angle((double)*p_inputs[0], (double)*p_inputs[1], (double)*p_inputs[2]);
- } break;
- case MATH_INVERSE_LERP: {
- VALIDATE_ARG_NUM(0);
- VALIDATE_ARG_NUM(1);
- VALIDATE_ARG_NUM(2);
- *r_return = Math::inverse_lerp((double)*p_inputs[0], (double)*p_inputs[1], (double)*p_inputs[2]);
- } break;
- case MATH_RANGE_LERP: {
- VALIDATE_ARG_NUM(0);
- VALIDATE_ARG_NUM(1);
- VALIDATE_ARG_NUM(2);
- VALIDATE_ARG_NUM(3);
- VALIDATE_ARG_NUM(4);
- *r_return = Math::range_lerp((double)*p_inputs[0], (double)*p_inputs[1], (double)*p_inputs[2], (double)*p_inputs[3], (double)*p_inputs[4]);
- } break;
- case MATH_SMOOTHSTEP: {
- VALIDATE_ARG_NUM(0);
- VALIDATE_ARG_NUM(1);
- VALIDATE_ARG_NUM(2);
- *r_return = Math::smoothstep((double)*p_inputs[0], (double)*p_inputs[1], (double)*p_inputs[2]);
- } break;
- case MATH_MOVE_TOWARD: {
- VALIDATE_ARG_NUM(0);
- VALIDATE_ARG_NUM(1);
- VALIDATE_ARG_NUM(2);
- *r_return = Math::move_toward((double)*p_inputs[0], (double)*p_inputs[1], (double)*p_inputs[2]);
- } break;
- case MATH_DECTIME: {
- VALIDATE_ARG_NUM(0);
- VALIDATE_ARG_NUM(1);
- VALIDATE_ARG_NUM(2);
- *r_return = Math::dectime((double)*p_inputs[0], (double)*p_inputs[1], (double)*p_inputs[2]);
- } break;
- case MATH_RANDOMIZE: {
- Math::randomize();
-
- } break;
- case MATH_RAND: {
- *r_return = Math::rand();
- } break;
- case MATH_RANDF: {
- *r_return = Math::randf();
- } break;
- case MATH_RANDOM: {
- VALIDATE_ARG_NUM(0);
- VALIDATE_ARG_NUM(1);
- *r_return = Math::random((double)*p_inputs[0], (double)*p_inputs[1]);
- } break;
- case MATH_SEED: {
- VALIDATE_ARG_NUM(0);
- uint64_t seed = *p_inputs[0];
- Math::seed(seed);
-
- } break;
- case MATH_RANDSEED: {
- VALIDATE_ARG_NUM(0);
- uint64_t seed = *p_inputs[0];
- int ret = Math::rand_from_seed(&seed);
- Array reta;
- reta.push_back(ret);
- reta.push_back(seed);
- *r_return = reta;
-
- } break;
- case MATH_DEG2RAD: {
- VALIDATE_ARG_NUM(0);
- *r_return = Math::deg2rad((double)*p_inputs[0]);
- } break;
- case MATH_RAD2DEG: {
- VALIDATE_ARG_NUM(0);
- *r_return = Math::rad2deg((double)*p_inputs[0]);
- } break;
- case MATH_LINEAR2DB: {
- VALIDATE_ARG_NUM(0);
- *r_return = Math::linear2db((double)*p_inputs[0]);
- } break;
- case MATH_DB2LINEAR: {
- VALIDATE_ARG_NUM(0);
- *r_return = Math::db2linear((double)*p_inputs[0]);
- } break;
- case MATH_POLAR2CARTESIAN: {
- VALIDATE_ARG_NUM(0);
- VALIDATE_ARG_NUM(1);
- double r = *p_inputs[0];
- double th = *p_inputs[1];
- *r_return = Vector2(r * Math::cos(th), r * Math::sin(th));
- } break;
- case MATH_CARTESIAN2POLAR: {
- VALIDATE_ARG_NUM(0);
- VALIDATE_ARG_NUM(1);
- double x = *p_inputs[0];
- double y = *p_inputs[1];
- *r_return = Vector2(Math::sqrt(x * x + y * y), Math::atan2(y, x));
- } break;
- case MATH_WRAP: {
- VALIDATE_ARG_NUM(0);
- VALIDATE_ARG_NUM(1);
- VALIDATE_ARG_NUM(2);
- *r_return = Math::wrapi((int64_t)*p_inputs[0], (int64_t)*p_inputs[1], (int64_t)*p_inputs[2]);
- } break;
- case MATH_WRAPF: {
- VALIDATE_ARG_NUM(0);
- VALIDATE_ARG_NUM(1);
- VALIDATE_ARG_NUM(2);
- *r_return = Math::wrapf((double)*p_inputs[0], (double)*p_inputs[1], (double)*p_inputs[2]);
- } break;
- case LOGIC_MAX: {
- if (p_inputs[0]->get_type() == Variant::INT && p_inputs[1]->get_type() == Variant::INT) {
- int64_t a = *p_inputs[0];
- int64_t b = *p_inputs[1];
- *r_return = MAX(a, b);
- } else {
- VALIDATE_ARG_NUM(0);
- VALIDATE_ARG_NUM(1);
-
- real_t a = *p_inputs[0];
- real_t b = *p_inputs[1];
-
- *r_return = MAX(a, b);
- }
-
- } break;
- case LOGIC_MIN: {
- if (p_inputs[0]->get_type() == Variant::INT && p_inputs[1]->get_type() == Variant::INT) {
- int64_t a = *p_inputs[0];
- int64_t b = *p_inputs[1];
- *r_return = MIN(a, b);
- } else {
- VALIDATE_ARG_NUM(0);
- VALIDATE_ARG_NUM(1);
-
- real_t a = *p_inputs[0];
- real_t b = *p_inputs[1];
-
- *r_return = MIN(a, b);
- }
- } break;
- case LOGIC_CLAMP: {
- if (p_inputs[0]->get_type() == Variant::INT && p_inputs[1]->get_type() == Variant::INT && p_inputs[2]->get_type() == Variant::INT) {
- int64_t a = *p_inputs[0];
- int64_t b = *p_inputs[1];
- int64_t c = *p_inputs[2];
- *r_return = CLAMP(a, b, c);
- } else {
- VALIDATE_ARG_NUM(0);
- VALIDATE_ARG_NUM(1);
- VALIDATE_ARG_NUM(2);
-
- real_t a = *p_inputs[0];
- real_t b = *p_inputs[1];
- real_t c = *p_inputs[2];
-
- *r_return = CLAMP(a, b, c);
- }
- } break;
- case LOGIC_NEAREST_PO2: {
- VALIDATE_ARG_NUM(0);
- int64_t num = *p_inputs[0];
- *r_return = next_power_of_2(num);
- } break;
- case OBJ_WEAKREF: {
- if (p_inputs[0]->get_type() != Variant::OBJECT) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 0;
- r_error.expected = Variant::OBJECT;
-
- return;
- }
-
- if (p_inputs[0]->is_ref()) {
- REF r = *p_inputs[0];
- if (!r.is_valid()) {
- return;
- }
-
- Ref<WeakRef> wref = memnew(WeakRef);
- wref->set_ref(r);
- *r_return = wref;
- } else {
- Object *obj = *p_inputs[0];
- if (!obj) {
- return;
- }
- Ref<WeakRef> wref = memnew(WeakRef);
- wref->set_obj(obj);
- *r_return = wref;
- }
-
- } break;
- case FUNC_FUNCREF: {
- if (p_inputs[0]->get_type() != Variant::OBJECT) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 0;
- r_error.expected = Variant::OBJECT;
-
- return;
- }
- if (p_inputs[1]->get_type() != Variant::STRING && p_inputs[1]->get_type() != Variant::NODE_PATH) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 1;
- r_error.expected = Variant::STRING;
-
- return;
- }
-
- Ref<FuncRef> fr = memnew(FuncRef);
-
- fr->set_instance(*p_inputs[0]);
- fr->set_function(*p_inputs[1]);
-
- *r_return = fr;
-
- } break;
- case TYPE_CONVERT: {
- VALIDATE_ARG_NUM(1);
- int type = *p_inputs[1];
- if (type < 0 || type >= Variant::VARIANT_MAX) {
- r_error_str = RTR("Invalid type argument to convert(), use TYPE_* constants.");
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 0;
- r_error.expected = Variant::INT;
- return;
-
- } else {
- *r_return = Variant::construct(Variant::Type(type), p_inputs, 1, r_error);
- }
- } break;
- case TYPE_OF: {
- *r_return = p_inputs[0]->get_type();
-
- } break;
- case TYPE_EXISTS: {
- *r_return = ClassDB::class_exists(*p_inputs[0]);
-
- } break;
- case TEXT_CHAR: {
- CharType result[2] = { *p_inputs[0], 0 };
-
- *r_return = String(result);
-
- } break;
- case TEXT_ORD: {
- if (p_inputs[0]->get_type() != Variant::STRING) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 0;
- r_error.expected = Variant::STRING;
-
- return;
- }
-
- String str = *p_inputs[0];
-
- if (str.length() != 1) {
- r_error_str = RTR("Expected a string of length 1 (a character).");
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 0;
- r_error.expected = Variant::STRING;
-
- return;
- }
-
- *r_return = str.get(0);
-
- } break;
- case TEXT_STR: {
- String str = *p_inputs[0];
-
- *r_return = str;
-
- } break;
- case TEXT_PRINT: {
- String str = *p_inputs[0];
- print_line(str);
-
- } break;
-
- case TEXT_PRINTERR: {
- String str = *p_inputs[0];
- print_error(str);
-
- } break;
- case TEXT_PRINTRAW: {
- String str = *p_inputs[0];
- OS::get_singleton()->print("%s", str.utf8().get_data());
-
- } break;
- case VAR_TO_STR: {
- String vars;
- VariantWriter::write_to_string(*p_inputs[0], vars);
- *r_return = vars;
- } break;
- case STR_TO_VAR: {
- if (p_inputs[0]->get_type() != Variant::STRING) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 0;
- r_error.expected = Variant::STRING;
-
- return;
- }
-
- VariantParser::StreamString ss;
- ss.s = *p_inputs[0];
-
- String errs;
- int line;
- Error err = VariantParser::parse(&ss, *r_return, errs, line);
-
- if (err != OK) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 0;
- r_error.expected = Variant::STRING;
- *r_return = "Parse error at line " + itos(line) + ": " + errs;
- return;
- }
-
- } break;
- case VAR_TO_BYTES: {
- PackedByteArray barr;
- bool full_objects = *p_inputs[1];
- int len;
- Error err = encode_variant(*p_inputs[0], nullptr, len, full_objects);
- if (err) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 0;
- r_error.expected = Variant::NIL;
- r_error_str = "Unexpected error encoding variable to bytes, likely unserializable type found (Object or RID).";
- return;
- }
-
- barr.resize(len);
- {
- uint8_t *w = barr.ptrw();
- encode_variant(*p_inputs[0], w, len, full_objects);
- }
- *r_return = barr;
- } break;
- case BYTES_TO_VAR: {
- if (p_inputs[0]->get_type() != Variant::PACKED_BYTE_ARRAY) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 0;
- r_error.expected = Variant::PACKED_BYTE_ARRAY;
-
- return;
- }
-
- PackedByteArray varr = *p_inputs[0];
- bool allow_objects = *p_inputs[1];
- Variant ret;
- {
- const uint8_t *r = varr.ptr();
- Error err = decode_variant(ret, r, varr.size(), nullptr, allow_objects);
- if (err != OK) {
- r_error_str = RTR("Not enough bytes for decoding bytes, or invalid format.");
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 0;
- r_error.expected = Variant::PACKED_BYTE_ARRAY;
- return;
- }
- }
-
- *r_return = ret;
-
- } break;
- case COLORN: {
- VALIDATE_ARG_NUM(1);
-
- Color color = Color::named(*p_inputs[0]);
- color.a = *p_inputs[1];
-
- *r_return = String(color);
-
- } break;
- default: {
- }
- }
-}
-
-////////
-
-static bool _is_number(CharType c) {
+static bool _is_number(char32_t c) {
return (c >= '0' && c <= '9');
}
@@ -747,7 +45,7 @@ Error Expression::_get_token(Token &r_token) {
while (true) {
#define GET_CHAR() (str_ofs >= expression.length() ? 0 : expression[str_ofs++])
- CharType cchar = GET_CHAR();
+ char32_t cchar = GET_CHAR();
switch (cchar) {
case 0: {
@@ -900,7 +198,7 @@ Error Expression::_get_token(Token &r_token) {
case '"': {
String str;
while (true) {
- CharType ch = GET_CHAR();
+ char32_t ch = GET_CHAR();
if (ch == 0) {
_set_error("Unterminated String");
@@ -912,13 +210,13 @@ Error Expression::_get_token(Token &r_token) {
} else if (ch == '\\') {
//escaped characters...
- CharType next = GET_CHAR();
+ char32_t next = GET_CHAR();
if (next == 0) {
_set_error("Unterminated String");
r_token.type = TK_ERROR;
return ERR_PARSE_ERROR;
}
- CharType res = 0;
+ char32_t res = 0;
switch (next) {
case 'b':
@@ -939,7 +237,7 @@ Error Expression::_get_token(Token &r_token) {
case 'u': {
// hex number
for (int j = 0; j < 4; j++) {
- CharType c = GET_CHAR();
+ char32_t c = GET_CHAR();
if (c == 0) {
_set_error("Unterminated String");
@@ -951,7 +249,7 @@ Error Expression::_get_token(Token &r_token) {
r_token.type = TK_ERROR;
return ERR_PARSE_ERROR;
}
- CharType v;
+ char32_t v;
if (_is_number(c)) {
v = c - '0';
} else if (c >= 'a' && c <= 'f') {
@@ -992,7 +290,7 @@ Error Expression::_get_token(Token &r_token) {
break;
}
- CharType next_char = (str_ofs >= expression.length()) ? 0 : expression[str_ofs];
+ char32_t next_char = (str_ofs >= expression.length()) ? 0 : expression[str_ofs];
if (_is_number(cchar) || (cchar == '.' && _is_number(next_char))) {
//a number
@@ -1004,7 +302,7 @@ Error Expression::_get_token(Token &r_token) {
#define READING_DONE 4
int reading = READING_INT;
- CharType c = cchar;
+ char32_t c = cchar;
bool exp_sign = false;
bool exp_beg = false;
bool is_float = false;
@@ -1062,7 +360,7 @@ Error Expression::_get_token(Token &r_token) {
r_token.type = TK_CONSTANT;
if (is_float) {
- r_token.value = num.to_double();
+ r_token.value = num.to_float();
} else {
r_token.value = num.to_int();
}
@@ -1112,18 +410,9 @@ Error Expression::_get_token(Token &r_token) {
} else if (id == "self") {
r_token.type = TK_SELF;
} else {
- for (int i = 0; i < Variant::VARIANT_MAX; i++) {
- if (id == Variant::get_type_name(Variant::Type(i))) {
- r_token.type = TK_BASIC_TYPE;
- r_token.value = i;
- return OK;
- }
- }
-
- BuiltinFunc bifunc = find_function(id);
- if (bifunc != FUNC_MAX) {
+ if (Variant::has_utility_function(id)) {
r_token.type = TK_BUILTIN_FUNC;
- r_token.value = bifunc;
+ r_token.value = id;
return OK;
}
@@ -1421,6 +710,8 @@ Expression::ENode *Expression::_parse_expression() {
case TK_BUILTIN_FUNC: {
//builtin function
+ StringName func = tk.value;
+
_get_token(tk);
if (tk.type != TK_PARENTHESIS_OPEN) {
_set_error("Expected '('");
@@ -1428,7 +719,7 @@ Expression::ENode *Expression::_parse_expression() {
}
BuiltinFuncNode *bifunc = alloc_node<BuiltinFuncNode>();
- bifunc->func = BuiltinFunc(int(tk.value));
+ bifunc->func = func;
while (true) {
int cofs = str_ofs;
@@ -1456,9 +747,11 @@ Expression::ENode *Expression::_parse_expression() {
}
}
- int expected_args = get_func_argument_count(bifunc->func);
- if (bifunc->arguments.size() != expected_args) {
- _set_error("Builtin func '" + get_func_name(bifunc->func) + "' expects " + itos(expected_args) + " arguments.");
+ if (!Variant::is_utility_function_vararg(bifunc->func)) {
+ int expected_args = Variant::get_utility_function_argument_count(bifunc->func);
+ if (expected_args != bifunc->arguments.size()) {
+ _set_error("Builtin func '" + String(bifunc->func) + "' expects " + itos(expected_args) + " arguments.");
+ }
}
expr = bifunc;
@@ -1973,7 +1266,7 @@ bool Expression::_execute(const Array &p_inputs, Object *p_instance, Expression:
}
bool valid;
- r_ret = base.get_named(index->name, &valid);
+ r_ret = base.get_named(index->name, valid);
if (!valid) {
r_error_str = vformat(RTR("Invalid named index '%s' for base type %s"), String(index->name), Variant::get_type_name(base.get_type()));
return true;
@@ -2041,7 +1334,7 @@ bool Expression::_execute(const Array &p_inputs, Object *p_instance, Expression:
}
Callable::CallError ce;
- r_ret = Variant::construct(constructor->data_type, (const Variant **)argp.ptr(), argp.size(), ce);
+ Variant::construct(constructor->data_type, r_ret, (const Variant **)argp.ptr(), argp.size(), ce);
if (ce.error != Callable::CallError::CALL_OK) {
r_error_str = vformat(RTR("Invalid arguments to construct '%s'"), Variant::get_type_name(constructor->data_type));
@@ -2067,11 +1360,11 @@ bool Expression::_execute(const Array &p_inputs, Object *p_instance, Expression:
argp.write[i] = &arr[i];
}
+ r_ret = Variant(); //may not return anything
Callable::CallError ce;
- exec_func(bifunc->func, (const Variant **)argp.ptr(), &r_ret, ce, r_error_str);
-
+ Variant::call_utility_function(bifunc->func, &r_ret, (const Variant **)argp.ptr(), argp.size(), ce);
if (ce.error != Callable::CallError::CALL_OK) {
- r_error_str = "Builtin Call Failed. " + r_error_str;
+ r_error_str = "Builtin Call Failed. " + Variant::get_call_error_text(bifunc->func, (const Variant **)argp.ptr(), argp.size(), ce);
return true;
}
@@ -2103,7 +1396,7 @@ bool Expression::_execute(const Array &p_inputs, Object *p_instance, Expression:
}
Callable::CallError ce;
- r_ret = base.call(call->method, (const Variant **)argp.ptr(), argp.size(), ce);
+ base.call(call->method, (const Variant **)argp.ptr(), argp.size(), r_ret, ce);
if (ce.error != Callable::CallError::CALL_OK) {
r_error_str = vformat(RTR("On call to '%s':"), String(call->method));
diff --git a/core/math/expression.h b/core/math/expression.h
index 59a9a2f4ed..6b34bc6ae8 100644
--- a/core/math/expression.h
+++ b/core/math/expression.h
@@ -31,92 +31,12 @@
#ifndef EXPRESSION_H
#define EXPRESSION_H
-#include "core/reference.h"
+#include "core/object/reference.h"
class Expression : public Reference {
GDCLASS(Expression, Reference);
-public:
- enum BuiltinFunc {
- MATH_SIN,
- MATH_COS,
- MATH_TAN,
- MATH_SINH,
- MATH_COSH,
- MATH_TANH,
- MATH_ASIN,
- MATH_ACOS,
- MATH_ATAN,
- MATH_ATAN2,
- MATH_SQRT,
- MATH_FMOD,
- MATH_FPOSMOD,
- MATH_POSMOD,
- MATH_FLOOR,
- MATH_CEIL,
- MATH_ROUND,
- MATH_ABS,
- MATH_SIGN,
- MATH_POW,
- MATH_LOG,
- MATH_EXP,
- MATH_ISNAN,
- MATH_ISINF,
- MATH_EASE,
- MATH_STEP_DECIMALS,
- MATH_STEPIFY,
- MATH_LERP,
- MATH_LERP_ANGLE,
- MATH_INVERSE_LERP,
- MATH_RANGE_LERP,
- MATH_SMOOTHSTEP,
- MATH_MOVE_TOWARD,
- MATH_DECTIME,
- MATH_RANDOMIZE,
- MATH_RAND,
- MATH_RANDF,
- MATH_RANDOM,
- MATH_SEED,
- MATH_RANDSEED,
- MATH_DEG2RAD,
- MATH_RAD2DEG,
- MATH_LINEAR2DB,
- MATH_DB2LINEAR,
- MATH_POLAR2CARTESIAN,
- MATH_CARTESIAN2POLAR,
- MATH_WRAP,
- MATH_WRAPF,
- LOGIC_MAX,
- LOGIC_MIN,
- LOGIC_CLAMP,
- LOGIC_NEAREST_PO2,
- OBJ_WEAKREF,
- FUNC_FUNCREF,
- TYPE_CONVERT,
- TYPE_OF,
- TYPE_EXISTS,
- TEXT_CHAR,
- TEXT_ORD,
- TEXT_STR,
- TEXT_PRINT,
- TEXT_PRINTERR,
- TEXT_PRINTRAW,
- VAR_TO_STR,
- STR_TO_VAR,
- VAR_TO_BYTES,
- BYTES_TO_VAR,
- COLORN,
- FUNC_MAX
- };
-
- static int get_func_argument_count(BuiltinFunc p_func);
- static String get_func_name(BuiltinFunc p_func);
- static void exec_func(BuiltinFunc p_func, const Variant **p_inputs, Variant *r_return, Callable::CallError &r_error, String &r_error_str);
- static BuiltinFunc find_function(const String &p_string);
-
private:
- static const char *func_name[FUNC_MAX];
-
struct Input {
Variant::Type type = Variant::NIL;
String name;
@@ -213,7 +133,7 @@ private:
ENode *next = nullptr;
- Type type;
+ Type type = TYPE_INPUT;
ENode() {}
virtual ~ENode() {
@@ -224,7 +144,7 @@ private:
};
struct ExpressionNode {
- bool is_op;
+ bool is_op = false;
union {
Variant::Operator op;
ENode *node;
@@ -234,23 +154,23 @@ private:
ENode *_parse_expression();
struct InputNode : public ENode {
- int index;
+ int index = 0;
InputNode() {
type = TYPE_INPUT;
}
};
struct ConstantNode : public ENode {
- Variant value;
+ Variant value = Variant::NIL;
ConstantNode() {
type = TYPE_CONSTANT;
}
};
struct OperatorNode : public ENode {
- Variant::Operator op;
+ Variant::Operator op = Variant::Operator::OP_ADD;
- ENode *nodes[2];
+ ENode *nodes[2] = { nullptr, nullptr };
OperatorNode() {
type = TYPE_OPERATOR;
@@ -264,8 +184,8 @@ private:
};
struct IndexNode : public ENode {
- ENode *base;
- ENode *index;
+ ENode *base = nullptr;
+ ENode *index = nullptr;
IndexNode() {
type = TYPE_INDEX;
@@ -273,7 +193,7 @@ private:
};
struct NamedIndexNode : public ENode {
- ENode *base;
+ ENode *base = nullptr;
StringName name;
NamedIndexNode() {
@@ -282,7 +202,7 @@ private:
};
struct ConstructorNode : public ENode {
- Variant::Type data_type;
+ Variant::Type data_type = Variant::Type::NIL;
Vector<ENode *> arguments;
ConstructorNode() {
@@ -291,7 +211,7 @@ private:
};
struct CallNode : public ENode {
- ENode *base;
+ ENode *base = nullptr;
StringName method;
Vector<ENode *> arguments;
@@ -315,7 +235,7 @@ private:
};
struct BuiltinFuncNode : public ENode {
- BuiltinFunc func;
+ StringName func;
Vector<ENode *> arguments;
BuiltinFuncNode() {
type = TYPE_BUILTIN_FUNC;
@@ -343,7 +263,7 @@ protected:
public:
Error parse(const String &p_expression, const Vector<String> &p_input_names = Vector<String>());
- Variant execute(Array p_inputs, Object *p_base = nullptr, bool p_show_error = true);
+ Variant execute(Array p_inputs = Array(), Object *p_base = nullptr, bool p_show_error = true);
bool has_execute_failed() const;
String get_error_text() const;
diff --git a/core/math/geometry_2d.h b/core/math/geometry_2d.h
index cfd7abfacb..12bad5768e 100644
--- a/core/math/geometry_2d.h
+++ b/core/math/geometry_2d.h
@@ -34,8 +34,8 @@
#include "core/math/delaunay_2d.h"
#include "core/math/rect2.h"
#include "core/math/triangulate.h"
-#include "core/object.h"
-#include "core/vector.h"
+#include "core/object/object.h"
+#include "core/templates/vector.h"
class Geometry2D {
Geometry2D();
diff --git a/core/math/geometry_3d.cpp b/core/math/geometry_3d.cpp
index 7807ab19a7..ccb6648561 100644
--- a/core/math/geometry_3d.cpp
+++ b/core/math/geometry_3d.cpp
@@ -30,7 +30,7 @@
#include "geometry_3d.h"
-#include "core/print_string.h"
+#include "core/string/print_string.h"
#include "thirdparty/misc/clipper.hpp"
#include "thirdparty/misc/triangulator.h"
@@ -241,7 +241,6 @@ Vector<Vector<Face3>> Geometry3D::separate_objects(Vector<Face3> p_array) {
/*** GEOMETRY WRAPPER ***/
enum _CellFlags {
-
_CELL_SOLID = 1,
_CELL_EXTERIOR = 2,
_CELL_STEP_MASK = 0x1C,
@@ -262,7 +261,6 @@ enum _CellFlags {
_CELL_PREV_Z_POS = 5 << 5,
_CELL_PREV_Z_NEG = 6 << 5,
_CELL_PREV_FIRST = 7 << 5,
-
};
static inline void _plot_face(uint8_t ***p_cell_status, int x, int y, int z, int len_x, int len_y, int len_z, const Vector3 &voxelsize, const Face3 &p_face) {
@@ -648,7 +646,7 @@ Geometry3D::MeshData Geometry3D::build_convex_mesh(const Vector<Plane> &p_planes
Vector<Vector3> vertices;
- Vector3 center = p.get_any_point();
+ Vector3 center = p.center();
// make a quad clockwise
vertices.push_back(center - up * subplane_size + right * subplane_size);
vertices.push_back(center - up * subplane_size - right * subplane_size);
diff --git a/core/math/geometry_3d.h b/core/math/geometry_3d.h
index 6bbf518141..f10fbeaaaf 100644
--- a/core/math/geometry_3d.h
+++ b/core/math/geometry_3d.h
@@ -32,8 +32,8 @@
#define GEOMETRY_3D_H
#include "core/math/face3.h"
-#include "core/object.h"
-#include "core/vector.h"
+#include "core/object/object.h"
+#include "core/templates/vector.h"
class Geometry3D {
Geometry3D();
@@ -636,54 +636,6 @@ public:
void optimize_vertices();
};
- _FORCE_INLINE_ static int get_uv84_normal_bit(const Vector3 &p_vector) {
- int lat = Math::fast_ftoi(Math::floor(Math::acos(p_vector.dot(Vector3(0, 1, 0))) * 4.0 / Math_PI + 0.5));
-
- if (lat == 0) {
- return 24;
- } else if (lat == 4) {
- return 25;
- }
-
- int lon = Math::fast_ftoi(Math::floor((Math_PI + Math::atan2(p_vector.x, p_vector.z)) * 8.0 / (Math_PI * 2.0) + 0.5)) % 8;
-
- return lon + (lat - 1) * 8;
- }
-
- _FORCE_INLINE_ static int get_uv84_normal_bit_neighbors(int p_idx) {
- if (p_idx == 24) {
- return 1 | 2 | 4 | 8;
- } else if (p_idx == 25) {
- return (1 << 23) | (1 << 22) | (1 << 21) | (1 << 20);
- } else {
- int ret = 0;
- if ((p_idx % 8) == 0) {
- ret |= (1 << (p_idx + 7));
- } else {
- ret |= (1 << (p_idx - 1));
- }
- if ((p_idx % 8) == 7) {
- ret |= (1 << (p_idx - 7));
- } else {
- ret |= (1 << (p_idx + 1));
- }
-
- int mask = ret | (1 << p_idx);
- if (p_idx < 8) {
- ret |= 24;
- } else {
- ret |= mask >> 8;
- }
-
- if (p_idx >= 16) {
- ret |= 25;
- } else {
- ret |= mask << 8;
- }
-
- return ret;
- }
- }
static MeshData build_convex_mesh(const Vector<Plane> &p_planes);
static Vector<Plane> build_sphere_planes(real_t p_radius, int p_lats, int p_lons, Vector3::Axis p_axis = Vector3::AXIS_Z);
static Vector<Plane> build_box_planes(const Vector3 &p_extents);
diff --git a/core/math/math_defs.h b/core/math/math_defs.h
index 4928c96abd..5192722839 100644
--- a/core/math/math_defs.h
+++ b/core/math/math_defs.h
@@ -66,27 +66,23 @@ enum ClockDirection {
};
enum Orientation {
-
HORIZONTAL,
VERTICAL
};
enum HAlign {
-
HALIGN_LEFT,
HALIGN_CENTER,
HALIGN_RIGHT
};
enum VAlign {
-
VALIGN_TOP,
VALIGN_CENTER,
VALIGN_BOTTOM
};
enum Margin {
-
MARGIN_LEFT,
MARGIN_TOP,
MARGIN_RIGHT,
@@ -94,7 +90,6 @@ enum Margin {
};
enum Corner {
-
CORNER_TOP_LEFT,
CORNER_TOP_RIGHT,
CORNER_BOTTOM_RIGHT,
diff --git a/core/math/math_fieldwise.cpp b/core/math/math_fieldwise.cpp
index ef2a0c5339..221c6812c1 100644
--- a/core/math/math_fieldwise.cpp
+++ b/core/math/math_fieldwise.cpp
@@ -47,9 +47,7 @@ Variant fieldwise_assign(const Variant &p_target, const Variant &p_source, const
/* clang-format off */
switch (p_source.get_type()) {
-
case Variant::VECTOR2: {
-
SETUP_TYPE(Vector2)
/**/ TRY_TRANSFER_FIELD("x", x)
@@ -59,7 +57,6 @@ Variant fieldwise_assign(const Variant &p_target, const Variant &p_source, const
}
case Variant::RECT2: {
-
SETUP_TYPE(Rect2)
/**/ TRY_TRANSFER_FIELD("x", position.x)
@@ -71,7 +68,6 @@ Variant fieldwise_assign(const Variant &p_target, const Variant &p_source, const
}
case Variant::VECTOR3: {
-
SETUP_TYPE(Vector3)
/**/ TRY_TRANSFER_FIELD("x", x)
@@ -82,7 +78,6 @@ Variant fieldwise_assign(const Variant &p_target, const Variant &p_source, const
}
case Variant::PLANE: {
-
SETUP_TYPE(Plane)
/**/ TRY_TRANSFER_FIELD("x", normal.x)
@@ -94,7 +89,6 @@ Variant fieldwise_assign(const Variant &p_target, const Variant &p_source, const
}
case Variant::QUAT: {
-
SETUP_TYPE(Quat)
/**/ TRY_TRANSFER_FIELD("x", x)
@@ -106,7 +100,6 @@ Variant fieldwise_assign(const Variant &p_target, const Variant &p_source, const
}
case Variant::AABB: {
-
SETUP_TYPE(AABB)
/**/ TRY_TRANSFER_FIELD("px", position.x)
@@ -120,7 +113,6 @@ Variant fieldwise_assign(const Variant &p_target, const Variant &p_source, const
}
case Variant::TRANSFORM2D: {
-
SETUP_TYPE(Transform2D)
/**/ TRY_TRANSFER_FIELD("xx", elements[0][0])
@@ -134,7 +126,6 @@ Variant fieldwise_assign(const Variant &p_target, const Variant &p_source, const
}
case Variant::BASIS: {
-
SETUP_TYPE(Basis)
/**/ TRY_TRANSFER_FIELD("xx", elements[0][0])
@@ -151,7 +142,6 @@ Variant fieldwise_assign(const Variant &p_target, const Variant &p_source, const
}
case Variant::TRANSFORM: {
-
SETUP_TYPE(Transform)
/**/ TRY_TRANSFER_FIELD("xx", basis.elements[0][0])
diff --git a/core/math/math_fieldwise.h b/core/math/math_fieldwise.h
index c1ee9ec8f0..e8aac0dced 100644
--- a/core/math/math_fieldwise.h
+++ b/core/math/math_fieldwise.h
@@ -33,7 +33,7 @@
#ifdef TOOLS_ENABLED
-#include "core/variant.h"
+#include "core/variant/variant.h"
Variant fieldwise_assign(const Variant &p_target, const Variant &p_source, const String &p_field);
diff --git a/core/math/math_funcs.cpp b/core/math/math_funcs.cpp
index 1585c96b38..e57257b442 100644
--- a/core/math/math_funcs.cpp
+++ b/core/math/math_funcs.cpp
@@ -30,12 +30,10 @@
#include "math_funcs.h"
-#include "core/error_macros.h"
+#include "core/error/error_macros.h"
RandomPCG Math::default_rand(RandomPCG::DEFAULT_SEED, RandomPCG::DEFAULT_INC);
-#define PHI 0x9e3779b9
-
uint32_t Math::rand_from_seed(uint64_t *seed) {
RandomPCG rng = RandomPCG(*seed, RandomPCG::DEFAULT_INC);
uint32_t r = rng.rand();
@@ -183,3 +181,7 @@ double Math::random(double from, double to) {
float Math::random(float from, float to) {
return default_rand.random(from, to);
}
+
+int Math::random(int from, int to) {
+ return default_rand.random(from, to);
+}
diff --git a/core/math/math_funcs.h b/core/math/math_funcs.h
index 7a9fd60e23..827637bf2b 100644
--- a/core/math/math_funcs.h
+++ b/core/math/math_funcs.h
@@ -46,7 +46,8 @@ class Math {
public:
Math() {} // useless to instance
- static const uint64_t RANDOM_MAX = 0xFFFFFFFF;
+ // Not using 'RANDOM_MAX' to avoid conflict with system headers on some OSes (at least NetBSD).
+ static const uint64_t RANDOM_32BIT_MAX = 0xFFFFFFFF;
static _ALWAYS_INLINE_ double sin(double p_x) { return ::sin(p_x); }
static _ALWAYS_INLINE_ float sin(float p_x) { return ::sinf(p_x); }
@@ -231,19 +232,19 @@ public:
static _ALWAYS_INLINE_ double range_lerp(double p_value, double p_istart, double p_istop, double p_ostart, double p_ostop) { return Math::lerp(p_ostart, p_ostop, Math::inverse_lerp(p_istart, p_istop, p_value)); }
static _ALWAYS_INLINE_ float range_lerp(float p_value, float p_istart, float p_istop, float p_ostart, float p_ostop) { return Math::lerp(p_ostart, p_ostop, Math::inverse_lerp(p_istart, p_istop, p_value)); }
- static _ALWAYS_INLINE_ double smoothstep(double p_from, double p_to, double p_weight) {
+ static _ALWAYS_INLINE_ double smoothstep(double p_from, double p_to, double p_s) {
if (is_equal_approx(p_from, p_to)) {
return p_from;
}
- double x = CLAMP((p_weight - p_from) / (p_to - p_from), 0.0, 1.0);
- return x * x * (3.0 - 2.0 * x);
+ double s = CLAMP((p_s - p_from) / (p_to - p_from), 0.0, 1.0);
+ return s * s * (3.0 - 2.0 * s);
}
- static _ALWAYS_INLINE_ float smoothstep(float p_from, float p_to, float p_weight) {
+ static _ALWAYS_INLINE_ float smoothstep(float p_from, float p_to, float p_s) {
if (is_equal_approx(p_from, p_to)) {
return p_from;
}
- float x = CLAMP((p_weight - p_from) / (p_to - p_from), 0.0f, 1.0f);
- return x * x * (3.0f - 2.0f * x);
+ float s = CLAMP((p_s - p_from) / (p_to - p_from), 0.0f, 1.0f);
+ return s * s * (3.0f - 2.0f * s);
}
static _ALWAYS_INLINE_ double move_toward(double p_from, double p_to, double p_delta) { return abs(p_to - p_from) <= p_delta ? p_to : p_from + SGN(p_to - p_from) * p_delta; }
static _ALWAYS_INLINE_ float move_toward(float p_from, float p_to, float p_delta) { return abs(p_to - p_from) <= p_delta ? p_to : p_from + SGN(p_to - p_from) * p_delta; }
@@ -283,24 +284,12 @@ public:
static void randomize();
static uint32_t rand_from_seed(uint64_t *seed);
static uint32_t rand();
- static _ALWAYS_INLINE_ double randd() { return (double)rand() / (double)Math::RANDOM_MAX; }
- static _ALWAYS_INLINE_ float randf() { return (float)rand() / (float)Math::RANDOM_MAX; }
+ static _ALWAYS_INLINE_ double randd() { return (double)rand() / (double)Math::RANDOM_32BIT_MAX; }
+ static _ALWAYS_INLINE_ float randf() { return (float)rand() / (float)Math::RANDOM_32BIT_MAX; }
static double random(double from, double to);
static float random(float from, float to);
- static real_t random(int from, int to) { return (real_t)random((real_t)from, (real_t)to); }
-
- static _ALWAYS_INLINE_ bool is_equal_approx_ratio(real_t a, real_t b, real_t epsilon = CMP_EPSILON, real_t min_epsilon = CMP_EPSILON) {
- // this is an approximate way to check that numbers are close, as a ratio of their average size
- // helps compare approximate numbers that may be very big or very small
- real_t diff = abs(a - b);
- if (diff == 0.0 || diff < min_epsilon) {
- return true;
- }
- real_t avg_size = (abs(a) + abs(b)) / 2.0;
- diff /= avg_size;
- return diff < epsilon;
- }
+ static int random(int from, int to);
static _ALWAYS_INLINE_ bool is_equal_approx(real_t a, real_t b) {
// Check for exact equality first, required to handle "infinity" values.
diff --git a/core/math/octree.h b/core/math/octree.h
index 5d9688d442..be1e7d6a61 100644
--- a/core/math/octree.h
+++ b/core/math/octree.h
@@ -31,13 +31,13 @@
#ifndef OCTREE_H
#define OCTREE_H
-#include "core/list.h"
-#include "core/map.h"
#include "core/math/aabb.h"
#include "core/math/geometry_3d.h"
#include "core/math/vector3.h"
-#include "core/print_string.h"
-#include "core/variant.h"
+#include "core/string/print_string.h"
+#include "core/templates/list.h"
+#include "core/templates/map.h"
+#include "core/variant/variant.h"
typedef uint32_t OctreeElementID;
@@ -379,7 +379,6 @@ void Octree<T, use_pairs, AL>::_insert_element(Element *p_element, Octant *p_oct
if (p_octant->aabb.size.x / OCTREE_DIVISOR < element_size) {
//if (p_octant->aabb.size.x*0.5 < element_size) {
-
/* at smallest possible size for the element */
typename Element::OctantOwner owner;
owner.octant = p_octant;
diff --git a/core/math/plane.cpp b/core/math/plane.cpp
index df37ceb0e5..e1ae3288ed 100644
--- a/core/math/plane.cpp
+++ b/core/math/plane.cpp
@@ -31,6 +31,7 @@
#include "plane.h"
#include "core/math/math_funcs.h"
+#include "core/variant/variant.h"
void Plane::set_normal(const Vector3 &p_normal) {
normal = p_normal;
@@ -52,10 +53,6 @@ Plane Plane::normalized() const {
return p;
}
-Vector3 Plane::get_any_point() const {
- return get_normal() * d;
-}
-
Vector3 Plane::get_any_perpendicular_normal() const {
static const Vector3 p1 = Vector3(1, 0, 0);
static const Vector3 p2 = Vector3(0, 1, 0);
@@ -142,6 +139,31 @@ bool Plane::intersects_segment(const Vector3 &p_begin, const Vector3 &p_end, Vec
return true;
}
+Variant Plane::intersect_3_bind(const Plane &p_plane1, const Plane &p_plane2) const {
+ Vector3 inters;
+ if (intersect_3(p_plane1, p_plane2, &inters)) {
+ return inters;
+ } else {
+ return Variant();
+ }
+}
+Variant Plane::intersects_ray_bind(const Vector3 &p_from, const Vector3 &p_dir) const {
+ Vector3 inters;
+ if (intersects_ray(p_from, p_dir, &inters)) {
+ return inters;
+ } else {
+ return Variant();
+ }
+}
+Variant Plane::intersects_segment_bind(const Vector3 &p_begin, const Vector3 &p_end) const {
+ Vector3 inters;
+ if (intersects_segment(p_begin, p_end, &inters)) {
+ return inters;
+ } else {
+ return Variant();
+ }
+}
+
/* misc */
bool Plane::is_equal_approx_any_side(const Plane &p_plane) const {
diff --git a/core/math/plane.h b/core/math/plane.h
index 9a3e5a485f..1386b0a2cb 100644
--- a/core/math/plane.h
+++ b/core/math/plane.h
@@ -33,6 +33,8 @@
#include "core/math/vector3.h"
+class Variant;
+
class Plane {
public:
Vector3 normal;
@@ -47,7 +49,6 @@ public:
/* Plane-Point operations */
_FORCE_INLINE_ Vector3 center() const { return normal * d; }
- Vector3 get_any_point() const;
Vector3 get_any_perpendicular_normal() const;
_FORCE_INLINE_ bool is_point_over(const Vector3 &p_point) const; ///< Point is over plane
@@ -60,6 +61,11 @@ public:
bool intersects_ray(const Vector3 &p_from, const Vector3 &p_dir, Vector3 *p_intersection) const;
bool intersects_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 *p_intersection) const;
+ // For Variant bindings.
+ Variant intersect_3_bind(const Plane &p_plane1, const Plane &p_plane2) const;
+ Variant intersects_ray_bind(const Vector3 &p_from, const Vector3 &p_dir) const;
+ Variant intersects_segment_bind(const Vector3 &p_begin, const Vector3 &p_end) const;
+
_FORCE_INLINE_ Vector3 project(const Vector3 &p_point) const {
return p_point - normal * distance_to(p_point);
}
diff --git a/core/math/quat.cpp b/core/math/quat.cpp
index c10f5da494..b6a017dd41 100644
--- a/core/math/quat.cpp
+++ b/core/math/quat.cpp
@@ -31,7 +31,7 @@
#include "quat.h"
#include "core/math/basis.h"
-#include "core/print_string.h"
+#include "core/string/print_string.h"
// set_euler_xyz expects a vector containing the Euler angles in the format
// (ax,ay,az), where ax is the angle of rotation around x axis,
diff --git a/core/math/quat.h b/core/math/quat.h
index 64d0f00912..f8ab537d7b 100644
--- a/core/math/quat.h
+++ b/core/math/quat.h
@@ -36,12 +36,26 @@
#include "core/math/math_defs.h"
#include "core/math/math_funcs.h"
-#include "core/ustring.h"
+#include "core/string/ustring.h"
class Quat {
public:
- real_t x = 0, y = 0, z = 0, w = 1;
-
+ union {
+ struct {
+ real_t x;
+ real_t y;
+ real_t z;
+ real_t w;
+ };
+ real_t components[4] = { 0, 0, 0, 1.0 };
+ };
+
+ _FORCE_INLINE_ real_t &operator[](int idx) {
+ return components[idx];
+ }
+ _FORCE_INLINE_ const real_t &operator[](int idx) const {
+ return components[idx];
+ }
_FORCE_INLINE_ real_t length_squared() const;
bool is_equal_approx(const Quat &p_quat) const;
real_t length() const;
@@ -91,6 +105,10 @@ public:
return v + ((uv * w) + u.cross(uv)) * ((real_t)2);
}
+ _FORCE_INLINE_ Vector3 xform_inv(const Vector3 &v) const {
+ return inverse().xform(v);
+ }
+
_FORCE_INLINE_ void operator+=(const Quat &q);
_FORCE_INLINE_ void operator-=(const Quat &q);
_FORCE_INLINE_ void operator*=(const real_t &s);
@@ -130,7 +148,7 @@ public:
w(q.w) {
}
- Quat operator=(const Quat &q) {
+ Quat &operator=(const Quat &q) {
x = q.x;
y = q.y;
z = q.z;
@@ -224,4 +242,8 @@ bool Quat::operator!=(const Quat &p_quat) const {
return x != p_quat.x || y != p_quat.y || z != p_quat.z || w != p_quat.w;
}
+_FORCE_INLINE_ Quat operator*(const real_t &p_real, const Quat &p_quat) {
+ return p_quat * p_real;
+}
+
#endif // QUAT_H
diff --git a/core/math/quick_hull.cpp b/core/math/quick_hull.cpp
index 8ba1ba9286..8dff13c050 100644
--- a/core/math/quick_hull.cpp
+++ b/core/math/quick_hull.cpp
@@ -30,7 +30,7 @@
#include "quick_hull.h"
-#include "core/map.h"
+#include "core/templates/map.h"
uint32_t QuickHull::debug_stop_after = 0xFFFFFFFF;
diff --git a/core/math/quick_hull.h b/core/math/quick_hull.h
index cac8e58d23..024325c4fc 100644
--- a/core/math/quick_hull.h
+++ b/core/math/quick_hull.h
@@ -31,17 +31,17 @@
#ifndef QUICK_HULL_H
#define QUICK_HULL_H
-#include "core/list.h"
#include "core/math/aabb.h"
#include "core/math/geometry_3d.h"
-#include "core/set.h"
+#include "core/templates/list.h"
+#include "core/templates/set.h"
class QuickHull {
public:
struct Edge {
union {
uint32_t vertices[2];
- uint64_t id;
+ uint64_t id = 0;
};
bool operator<(const Edge &p_edge) const {
@@ -60,7 +60,7 @@ public:
struct Face {
Plane plane;
- uint32_t vertices[3];
+ uint32_t vertices[3] = { 0 };
Vector<int> points_over;
bool operator<(const Face &p_face) const {
@@ -70,11 +70,13 @@ public:
private:
struct FaceConnect {
- List<Face>::Element *left, *right = nullptr;
+ List<Face>::Element *left = nullptr;
+ List<Face>::Element *right = nullptr;
FaceConnect() {}
};
struct RetFaceConnect {
- List<Geometry3D::MeshData::Face>::Element *left, *right = nullptr;
+ List<Geometry3D::MeshData::Face>::Element *left = nullptr;
+ List<Geometry3D::MeshData::Face>::Element *right = nullptr;
RetFaceConnect() {}
};
diff --git a/core/math/random_number_generator.cpp b/core/math/random_number_generator.cpp
index 67f4c0b14a..a124f63030 100644
--- a/core/math/random_number_generator.cpp
+++ b/core/math/random_number_generator.cpp
@@ -33,7 +33,6 @@
void RandomNumberGenerator::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_seed", "seed"), &RandomNumberGenerator::set_seed);
ClassDB::bind_method(D_METHOD("get_seed"), &RandomNumberGenerator::get_seed);
- ADD_PROPERTY(PropertyInfo(Variant::INT, "seed"), "set_seed", "get_seed");
ClassDB::bind_method(D_METHOD("randi"), &RandomNumberGenerator::randi);
ClassDB::bind_method(D_METHOD("randf"), &RandomNumberGenerator::randf);
@@ -41,4 +40,8 @@ void RandomNumberGenerator::_bind_methods() {
ClassDB::bind_method(D_METHOD("randf_range", "from", "to"), &RandomNumberGenerator::randf_range);
ClassDB::bind_method(D_METHOD("randi_range", "from", "to"), &RandomNumberGenerator::randi_range);
ClassDB::bind_method(D_METHOD("randomize"), &RandomNumberGenerator::randomize);
+
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "seed"), "set_seed", "get_seed");
+ // Default value is non-deterministic, override it for doc generation purposes.
+ ADD_PROPERTY_DEFAULT("seed", 0);
}
diff --git a/core/math/random_number_generator.h b/core/math/random_number_generator.h
index 920308e597..0d0ea17205 100644
--- a/core/math/random_number_generator.h
+++ b/core/math/random_number_generator.h
@@ -32,18 +32,18 @@
#define RANDOM_NUMBER_GENERATOR_H
#include "core/math/random_pcg.h"
-#include "core/reference.h"
+#include "core/object/reference.h"
class RandomNumberGenerator : public Reference {
GDCLASS(RandomNumberGenerator, Reference);
+protected:
RandomPCG randbase;
-protected:
static void _bind_methods();
public:
- _FORCE_INLINE_ void set_seed(uint64_t seed) { randbase.seed(seed); }
+ _FORCE_INLINE_ void set_seed(uint64_t p_seed) { randbase.seed(p_seed); }
_FORCE_INLINE_ uint64_t get_seed() { return randbase.get_seed(); }
@@ -53,18 +53,11 @@ public:
_FORCE_INLINE_ real_t randf() { return randbase.randf(); }
- _FORCE_INLINE_ real_t randf_range(real_t from, real_t to) { return randbase.random(from, to); }
+ _FORCE_INLINE_ real_t randf_range(real_t p_from, real_t p_to) { return randbase.random(p_from, p_to); }
- _FORCE_INLINE_ real_t randfn(real_t mean = 0.0, real_t deviation = 1.0) { return randbase.randfn(mean, deviation); }
+ _FORCE_INLINE_ real_t randfn(real_t p_mean = 0.0, real_t p_deviation = 1.0) { return randbase.randfn(p_mean, p_deviation); }
- _FORCE_INLINE_ int randi_range(int from, int to) {
- unsigned int ret = randbase.rand();
- if (to < from) {
- return ret % (from - to + 1) + to;
- } else {
- return ret % (to - from + 1) + from;
- }
- }
+ _FORCE_INLINE_ int randi_range(int p_from, int p_to) { return randbase.random(p_from, p_to); }
RandomNumberGenerator() {}
};
diff --git a/core/math/random_pcg.cpp b/core/math/random_pcg.cpp
index 02257c38d9..e0768b9403 100644
--- a/core/math/random_pcg.cpp
+++ b/core/math/random_pcg.cpp
@@ -49,3 +49,18 @@ double RandomPCG::random(double p_from, double p_to) {
float RandomPCG::random(float p_from, float p_to) {
return randf() * (p_to - p_from) + p_from;
}
+
+int RandomPCG::random(int p_from, int p_to) {
+ int range;
+ int min;
+ if (p_to > p_from) {
+ range = p_to - p_from + 1;
+ min = p_from;
+ } else if (p_to < p_from) {
+ range = p_from - p_to + 1;
+ min = p_to;
+ } else { // from == to
+ return p_from;
+ }
+ return rand(range) + min;
+}
diff --git a/core/math/random_pcg.h b/core/math/random_pcg.h
index 8fd5a056fa..fe6b1b5639 100644
--- a/core/math/random_pcg.h
+++ b/core/math/random_pcg.h
@@ -31,12 +31,12 @@
#ifndef RANDOM_PCG_H
#define RANDOM_PCG_H
-#include <math.h>
-
#include "core/math/math_defs.h"
#include "thirdparty/misc/pcg.h"
+#include <math.h>
+
#if defined(__GNUC__)
#define CLZ32(x) __builtin_clz(x)
#elif defined(_MSC_VER)
@@ -67,7 +67,6 @@ class RandomPCG {
public:
static const uint64_t DEFAULT_SEED = 12047754176567800795U;
static const uint64_t DEFAULT_INC = PCG_DEFAULT_INC_64;
- static const uint64_t RANDOM_MAX = 0xFFFFFFFF;
RandomPCG(uint64_t p_seed = DEFAULT_SEED, uint64_t p_inc = DEFAULT_INC);
@@ -82,6 +81,10 @@ public:
current_seed = pcg.state;
return pcg32_random_r(&pcg);
}
+ _FORCE_INLINE_ uint32_t rand(uint32_t bounds) {
+ current_seed = pcg.state;
+ return pcg32_boundedrand_r(&pcg, bounds);
+ }
// Obtaining floating point numbers in [0, 1] range with "good enough" uniformity.
// These functions sample the output of rand() as the fraction part of an infinite binary number,
@@ -130,7 +133,7 @@ public:
double random(double p_from, double p_to);
float random(float p_from, float p_to);
- real_t random(int p_from, int p_to) { return (real_t)random((real_t)p_from, (real_t)p_to); }
+ int random(int p_from, int p_to);
};
#endif // RANDOM_PCG_H
diff --git a/core/math/rect2.h b/core/math/rect2.h
index 14393325ec..b1fe865ba5 100644
--- a/core/math/rect2.h
+++ b/core/math/rect2.h
@@ -197,6 +197,10 @@ struct Rect2 {
return g;
}
+ inline Rect2 grow_margin_bind(uint32_t p_margin, real_t p_amount) const {
+ return grow_margin(Margin(p_margin), p_amount);
+ }
+
inline Rect2 grow_individual(real_t p_left, real_t p_top, real_t p_right, real_t p_bottom) const {
Rect2 g = *this;
g.position.x -= p_left;
@@ -240,6 +244,77 @@ struct Rect2 {
return Rect2(Point2(position.x + MIN(size.x, 0), position.y + MIN(size.y, 0)), size.abs());
}
+ Vector2 get_support(const Vector2 &p_normal) const {
+ Vector2 half_extents = size * 0.5;
+ Vector2 ofs = position + half_extents;
+ return Vector2(
+ (p_normal.x > 0) ? -half_extents.x : half_extents.x,
+ (p_normal.y > 0) ? -half_extents.y : half_extents.y) +
+ ofs;
+ }
+
+ _FORCE_INLINE_ bool intersects_filled_polygon(const Vector2 *p_points, int p_point_count) const {
+ Vector2 center = position + size * 0.5;
+ int side_plus = 0;
+ int side_minus = 0;
+ Vector2 end = position + size;
+
+ int i_f = p_point_count - 1;
+ for (int i = 0; i < p_point_count; i++) {
+ const Vector2 &a = p_points[i_f];
+ const Vector2 &b = p_points[i];
+ i_f = i;
+
+ Vector2 r = (b - a);
+ float l = r.length();
+ if (l == 0.0) {
+ continue;
+ }
+
+ //check inside
+ Vector2 tg = r.tangent();
+ float s = tg.dot(center) - tg.dot(a);
+ if (s < 0.0) {
+ side_plus++;
+ } else {
+ side_minus++;
+ }
+
+ //check ray box
+ r /= l;
+ Vector2 ir(1.0 / r.x, 1.0 / r.y);
+
+ // lb is the corner of AABB with minimal coordinates - left bottom, rt is maximal corner
+ // r.org is origin of ray
+ Vector2 t13 = (position - a) * ir;
+ Vector2 t24 = (end - a) * ir;
+
+ float tmin = MAX(MIN(t13.x, t24.x), MIN(t13.y, t24.y));
+ float tmax = MIN(MAX(t13.x, t24.x), MAX(t13.y, t24.y));
+
+ // if tmax < 0, ray (line) is intersecting AABB, but the whole AABB is behind us
+ if (tmax < 0 || tmin > tmax || tmin >= l) {
+ continue;
+ }
+
+ return true;
+ }
+
+ if (side_plus * side_minus == 0) {
+ return true; //all inside
+ } else {
+ return false;
+ }
+ }
+
+ _FORCE_INLINE_ void set_end(const Vector2 &p_end) {
+ size = p_end - position;
+ }
+
+ _FORCE_INLINE_ Vector2 get_end() const {
+ return position + size;
+ }
+
operator String() const { return String(position) + ", " + String(size); }
Rect2() {}
@@ -301,8 +376,8 @@ struct Rect2i {
new_rect.position.x = MAX(p_rect.position.x, position.x);
new_rect.position.y = MAX(p_rect.position.y, position.y);
- Point2 p_rect_end = p_rect.position + p_rect.size;
- Point2 end = position + size;
+ Point2i p_rect_end = p_rect.position + p_rect.size;
+ Point2i end = position + size;
new_rect.size.x = (int)(MIN(p_rect_end.x, end.x) - new_rect.position.x);
new_rect.size.y = (int)(MIN(p_rect_end.y, end.y) - new_rect.position.y);
@@ -324,7 +399,7 @@ struct Rect2i {
return new_rect;
}
- bool has_point(const Point2 &p_point) const {
+ bool has_point(const Point2i &p_point) const {
if (p_point.x < position.x) {
return false;
}
@@ -363,6 +438,10 @@ struct Rect2i {
return g;
}
+ inline Rect2i grow_margin_bind(uint32_t p_margin, int p_amount) const {
+ return grow_margin(Margin(p_margin), p_amount);
+ }
+
inline Rect2i grow_individual(int p_left, int p_top, int p_right, int p_bottom) const {
Rect2i g = *this;
g.position.x -= p_left;
@@ -405,6 +484,14 @@ struct Rect2i {
return Rect2i(Point2i(position.x + MIN(size.x, 0), position.y + MIN(size.y, 0)), size.abs());
}
+ _FORCE_INLINE_ void set_end(const Vector2i &p_end) {
+ size = p_end - position;
+ }
+
+ _FORCE_INLINE_ Vector2i get_end() const {
+ return position + size;
+ }
+
operator String() const { return String(position) + ", " + String(size); }
operator Rect2() const { return Rect2(position, size); }
@@ -415,10 +502,10 @@ struct Rect2i {
size(p_r2.size) {
}
Rect2i(int p_x, int p_y, int p_width, int p_height) :
- position(Point2(p_x, p_y)),
- size(Size2(p_width, p_height)) {
+ position(Point2i(p_x, p_y)),
+ size(Size2i(p_width, p_height)) {
}
- Rect2i(const Point2 &p_pos, const Size2 &p_size) :
+ Rect2i(const Point2i &p_pos, const Size2i &p_size) :
position(p_pos),
size(p_size) {
}
diff --git a/core/math/transform.cpp b/core/math/transform.cpp
index 0274dd18af..733bb4d55e 100644
--- a/core/math/transform.cpp
+++ b/core/math/transform.cpp
@@ -32,7 +32,7 @@
#include "core/math/math_funcs.h"
#include "core/os/copymem.h"
-#include "core/print_string.h"
+#include "core/string/print_string.h"
void Transform::affine_invert() {
basis.invert();
@@ -200,6 +200,13 @@ Transform::Transform(const Basis &p_basis, const Vector3 &p_origin) :
origin(p_origin) {
}
+Transform::Transform(const Vector3 &p_x, const Vector3 &p_y, const Vector3 &p_z, const Vector3 &p_origin) :
+ origin(p_origin) {
+ basis.set_axis(0, p_x);
+ basis.set_axis(1, p_y);
+ basis.set_axis(2, p_z);
+}
+
Transform::Transform(real_t xx, real_t xy, real_t xz, real_t yx, real_t yy, real_t yz, real_t zx, real_t zy, real_t zz, real_t ox, real_t oy, real_t oz) {
basis = Basis(xx, xy, xz, yx, yy, yz, zx, zy, zz);
origin = Vector3(ox, oy, oz);
diff --git a/core/math/transform.h b/core/math/transform.h
index 71847d36ac..c63dbcb989 100644
--- a/core/math/transform.h
+++ b/core/math/transform.h
@@ -106,9 +106,10 @@ public:
operator String() const;
- Transform(real_t xx, real_t xy, real_t xz, real_t yx, real_t yy, real_t yz, real_t zx, real_t zy, real_t zz, real_t ox, real_t oy, real_t oz);
- Transform(const Basis &p_basis, const Vector3 &p_origin = Vector3());
Transform() {}
+ Transform(const Basis &p_basis, const Vector3 &p_origin = Vector3());
+ Transform(const Vector3 &p_x, const Vector3 &p_y, const Vector3 &p_z, const Vector3 &p_origin);
+ Transform(real_t xx, real_t xy, real_t xz, real_t yx, real_t yy, real_t yz, real_t zx, real_t zy, real_t zz, real_t ox, real_t oy, real_t oz);
};
_FORCE_INLINE_ Vector3 Transform::xform(const Vector3 &p_vector) const {
diff --git a/core/math/transform_2d.cpp b/core/math/transform_2d.cpp
index 180aeaa0af..00e561f973 100644
--- a/core/math/transform_2d.cpp
+++ b/core/math/transform_2d.cpp
@@ -251,7 +251,7 @@ Transform2D Transform2D::interpolate_with(const Transform2D &p_transform, real_t
real_t dot = v1.dot(v2);
- dot = (dot < -1.0) ? -1.0 : ((dot > 1.0) ? 1.0 : dot); //clamp dot to [-1,1]
+ dot = CLAMP(dot, -1.0, 1.0);
Vector2 v;
diff --git a/core/math/transform_2d.h b/core/math/transform_2d.h
index 46e97abaa7..342623939e 100644
--- a/core/math/transform_2d.h
+++ b/core/math/transform_2d.h
@@ -128,6 +128,12 @@ struct Transform2D {
elements[2][1] = oy;
}
+ Transform2D(const Vector2 &p_x, const Vector2 &p_y, const Vector2 &p_origin) {
+ elements[0] = p_x;
+ elements[1] = p_y;
+ elements[2] = p_origin;
+ }
+
Transform2D(real_t p_rot, const Vector2 &p_pos);
Transform2D() {
elements[0][0] = 1.0;
diff --git a/core/math/triangle_mesh.cpp b/core/math/triangle_mesh.cpp
index c9a546e385..cfe8422d80 100644
--- a/core/math/triangle_mesh.cpp
+++ b/core/math/triangle_mesh.cpp
@@ -30,7 +30,7 @@
#include "triangle_mesh.h"
-#include "core/sort_array.h"
+#include "core/templates/sort_array.h"
int TriangleMesh::_create_bvh(BVH *p_bvh, BVH **p_bb, int p_from, int p_size, int p_depth, int &max_depth, int &max_alloc) {
if (p_depth > max_depth) {
diff --git a/core/math/triangle_mesh.h b/core/math/triangle_mesh.h
index 86412cf725..d719822ec3 100644
--- a/core/math/triangle_mesh.h
+++ b/core/math/triangle_mesh.h
@@ -32,7 +32,7 @@
#define TRIANGLE_MESH_H
#include "core/math/face3.h"
-#include "core/reference.h"
+#include "core/object/reference.h"
class TriangleMesh : public Reference {
GDCLASS(TriangleMesh, Reference);
diff --git a/core/math/vector2.cpp b/core/math/vector2.cpp
index 233421e070..75e742a5f1 100644
--- a/core/math/vector2.cpp
+++ b/core/math/vector2.cpp
@@ -233,6 +233,19 @@ void Vector2i::operator/=(const int &rvalue) {
y /= rvalue;
}
+Vector2i Vector2i::operator%(const Vector2i &p_v1) const {
+ return Vector2i(x % p_v1.x, y % p_v1.y);
+}
+
+Vector2i Vector2i::operator%(const int &rvalue) const {
+ return Vector2i(x % rvalue, y % rvalue);
+}
+
+void Vector2i::operator%=(const int &rvalue) {
+ x %= rvalue;
+ y %= rvalue;
+}
+
Vector2i Vector2i::operator-() const {
return Vector2i(-x, -y);
}
diff --git a/core/math/vector2.h b/core/math/vector2.h
index 8a08d3bf64..8cb63b2fb5 100644
--- a/core/math/vector2.h
+++ b/core/math/vector2.h
@@ -32,7 +32,7 @@
#define VECTOR2_H
#include "core/math/math_funcs.h"
-#include "core/ustring.h"
+#include "core/string/ustring.h"
struct Vector2i;
@@ -65,6 +65,14 @@ struct Vector2 {
real_t length() const;
real_t length_squared() const;
+ Vector2 min(const Vector2 &p_vector2) const {
+ return Vector2(MIN(x, p_vector2.x), MIN(y, p_vector2.y));
+ }
+
+ Vector2 max(const Vector2 &p_vector2) const {
+ return Vector2(MAX(x, p_vector2.x), MAX(y, p_vector2.y));
+ }
+
real_t distance_to(const Vector2 &p_vector2) const;
real_t distance_squared_to(const Vector2 &p_vector2) const;
real_t angle_to(const Vector2 &p_vector2) const;
@@ -114,10 +122,10 @@ struct Vector2 {
bool operator==(const Vector2 &p_vec2) const;
bool operator!=(const Vector2 &p_vec2) const;
- bool operator<(const Vector2 &p_vec2) const { return Math::is_equal_approx(x, p_vec2.x) ? (y < p_vec2.y) : (x < p_vec2.x); }
- bool operator>(const Vector2 &p_vec2) const { return Math::is_equal_approx(x, p_vec2.x) ? (y > p_vec2.y) : (x > p_vec2.x); }
- bool operator<=(const Vector2 &p_vec2) const { return Math::is_equal_approx(x, p_vec2.x) ? (y <= p_vec2.y) : (x < p_vec2.x); }
- bool operator>=(const Vector2 &p_vec2) const { return Math::is_equal_approx(x, p_vec2.x) ? (y >= p_vec2.y) : (x > p_vec2.x); }
+ bool operator<(const Vector2 &p_vec2) const { return x == p_vec2.x ? (y < p_vec2.y) : (x < p_vec2.x); }
+ bool operator>(const Vector2 &p_vec2) const { return x == p_vec2.x ? (y > p_vec2.y) : (x > p_vec2.x); }
+ bool operator<=(const Vector2 &p_vec2) const { return x == p_vec2.x ? (y <= p_vec2.y) : (x < p_vec2.x); }
+ bool operator>=(const Vector2 &p_vec2) const { return x == p_vec2.x ? (y >= p_vec2.y) : (x > p_vec2.x); }
real_t angle() const;
@@ -150,7 +158,19 @@ _FORCE_INLINE_ Vector2 Vector2::plane_project(real_t p_d, const Vector2 &p_vec)
return p_vec - *this * (dot(p_vec) - p_d);
}
-_FORCE_INLINE_ Vector2 operator*(real_t p_scalar, const Vector2 &p_vec) {
+_FORCE_INLINE_ Vector2 operator*(float p_scalar, const Vector2 &p_vec) {
+ return p_vec * p_scalar;
+}
+
+_FORCE_INLINE_ Vector2 operator*(double p_scalar, const Vector2 &p_vec) {
+ return p_vec * p_scalar;
+}
+
+_FORCE_INLINE_ Vector2 operator*(int32_t p_scalar, const Vector2 &p_vec) {
+ return p_vec * p_scalar;
+}
+
+_FORCE_INLINE_ Vector2 operator*(int64_t p_scalar, const Vector2 &p_vec) {
return p_vec * p_scalar;
}
@@ -270,11 +290,13 @@ struct Vector2i {
void operator*=(const int &rvalue);
Vector2i operator/(const Vector2i &p_v1) const;
-
Vector2i operator/(const int &rvalue) const;
-
void operator/=(const int &rvalue);
+ Vector2i operator%(const Vector2i &p_v1) const;
+ Vector2i operator%(const int &rvalue) const;
+ void operator%=(const int &rvalue);
+
Vector2i operator-() const;
bool operator<(const Vector2i &p_vec2) const { return (x == p_vec2.x) ? (y < p_vec2.y) : (x < p_vec2.x); }
bool operator>(const Vector2i &p_vec2) const { return (x == p_vec2.x) ? (y > p_vec2.y) : (x > p_vec2.x); }
@@ -304,6 +326,22 @@ struct Vector2i {
}
};
+_FORCE_INLINE_ Vector2i operator*(const int32_t &p_scalar, const Vector2i &p_vector) {
+ return p_vector * p_scalar;
+}
+
+_FORCE_INLINE_ Vector2i operator*(const int64_t &p_scalar, const Vector2i &p_vector) {
+ return p_vector * p_scalar;
+}
+
+_FORCE_INLINE_ Vector2i operator*(const float &p_scalar, const Vector2i &p_vector) {
+ return p_vector * p_scalar;
+}
+
+_FORCE_INLINE_ Vector2i operator*(const double &p_scalar, const Vector2i &p_vector) {
+ return p_vector * p_scalar;
+}
+
typedef Vector2i Size2i;
typedef Vector2i Point2i;
diff --git a/core/math/vector3.h b/core/math/vector3.h
index 0bc1a467f2..ae8b9376cf 100644
--- a/core/math/vector3.h
+++ b/core/math/vector3.h
@@ -33,7 +33,7 @@
#include "core/math/math_funcs.h"
#include "core/math/vector3i.h"
-#include "core/ustring.h"
+#include "core/string/ustring.h"
class Basis;
@@ -322,8 +322,8 @@ bool Vector3::operator!=(const Vector3 &p_v) const {
}
bool Vector3::operator<(const Vector3 &p_v) const {
- if (Math::is_equal_approx(x, p_v.x)) {
- if (Math::is_equal_approx(y, p_v.y)) {
+ if (x == p_v.x) {
+ if (y == p_v.y) {
return z < p_v.z;
} else {
return y < p_v.y;
@@ -334,8 +334,8 @@ bool Vector3::operator<(const Vector3 &p_v) const {
}
bool Vector3::operator>(const Vector3 &p_v) const {
- if (Math::is_equal_approx(x, p_v.x)) {
- if (Math::is_equal_approx(y, p_v.y)) {
+ if (x == p_v.x) {
+ if (y == p_v.y) {
return z > p_v.z;
} else {
return y > p_v.y;
@@ -346,8 +346,8 @@ bool Vector3::operator>(const Vector3 &p_v) const {
}
bool Vector3::operator<=(const Vector3 &p_v) const {
- if (Math::is_equal_approx(x, p_v.x)) {
- if (Math::is_equal_approx(y, p_v.y)) {
+ if (x == p_v.x) {
+ if (y == p_v.y) {
return z <= p_v.z;
} else {
return y < p_v.y;
@@ -358,8 +358,8 @@ bool Vector3::operator<=(const Vector3 &p_v) const {
}
bool Vector3::operator>=(const Vector3 &p_v) const {
- if (Math::is_equal_approx(x, p_v.x)) {
- if (Math::is_equal_approx(y, p_v.y)) {
+ if (x == p_v.x) {
+ if (y == p_v.y) {
return z >= p_v.z;
} else {
return y > p_v.y;
diff --git a/core/math/vector3i.h b/core/math/vector3i.h
index 08729ad056..1bfd6d5ab2 100644
--- a/core/math/vector3i.h
+++ b/core/math/vector3i.h
@@ -31,8 +31,8 @@
#ifndef VECTOR3I_H
#define VECTOR3I_H
+#include "core/string/ustring.h"
#include "core/typedefs.h"
-#include "core/ustring.h"
struct Vector3i {
enum Axis {
@@ -80,11 +80,15 @@ struct Vector3i {
_FORCE_INLINE_ Vector3i operator*(const Vector3i &p_v) const;
_FORCE_INLINE_ Vector3i &operator/=(const Vector3i &p_v);
_FORCE_INLINE_ Vector3i operator/(const Vector3i &p_v) const;
+ _FORCE_INLINE_ Vector3i &operator%=(const Vector3i &p_v);
+ _FORCE_INLINE_ Vector3i operator%(const Vector3i &p_v) const;
_FORCE_INLINE_ Vector3i &operator*=(int32_t p_scalar);
_FORCE_INLINE_ Vector3i operator*(int32_t p_scalar) const;
_FORCE_INLINE_ Vector3i &operator/=(int32_t p_scalar);
_FORCE_INLINE_ Vector3i operator/(int32_t p_scalar) const;
+ _FORCE_INLINE_ Vector3i &operator%=(int32_t p_scalar);
+ _FORCE_INLINE_ Vector3i operator%(int32_t p_scalar) const;
_FORCE_INLINE_ Vector3i operator-() const;
@@ -159,6 +163,17 @@ Vector3i Vector3i::operator/(const Vector3i &p_v) const {
return Vector3i(x / p_v.x, y / p_v.y, z / p_v.z);
}
+Vector3i &Vector3i::operator%=(const Vector3i &p_v) {
+ x %= p_v.x;
+ y %= p_v.y;
+ z %= p_v.z;
+ return *this;
+}
+
+Vector3i Vector3i::operator%(const Vector3i &p_v) const {
+ return Vector3i(x % p_v.x, y % p_v.y, z % p_v.z);
+}
+
Vector3i &Vector3i::operator*=(int32_t p_scalar) {
x *= p_scalar;
y *= p_scalar;
@@ -185,6 +200,17 @@ Vector3i Vector3i::operator/(int32_t p_scalar) const {
return Vector3i(x / p_scalar, y / p_scalar, z / p_scalar);
}
+Vector3i &Vector3i::operator%=(int32_t p_scalar) {
+ x %= p_scalar;
+ y %= p_scalar;
+ z %= p_scalar;
+ return *this;
+}
+
+Vector3i Vector3i::operator%(int32_t p_scalar) const {
+ return Vector3i(x % p_scalar, y % p_scalar, z % p_scalar);
+}
+
Vector3i Vector3i::operator-() const {
return Vector3i(-x, -y, -z);
}
diff --git a/core/method_bind.h b/core/method_bind.h
deleted file mode 100644
index ff2c771f81..0000000000
--- a/core/method_bind.h
+++ /dev/null
@@ -1,393 +0,0 @@
-/*************************************************************************/
-/* method_bind.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* 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. */
-/*************************************************************************/
-
-#ifndef METHOD_BIND_H
-#define METHOD_BIND_H
-
-#ifdef DEBUG_ENABLED
-#define DEBUG_METHODS_ENABLED
-#endif
-
-#include "core/list.h"
-#include "core/method_ptrcall.h"
-#include "core/object.h"
-#include "core/type_info.h"
-#include "core/typedefs.h"
-#include "core/variant.h"
-
-#include <stdio.h>
-
-enum MethodFlags {
-
- METHOD_FLAG_NORMAL = 1,
- METHOD_FLAG_EDITOR = 2,
- METHOD_FLAG_NOSCRIPT = 4,
- METHOD_FLAG_CONST = 8,
- METHOD_FLAG_REVERSE = 16, // used for events
- METHOD_FLAG_VIRTUAL = 32,
- METHOD_FLAG_FROM_SCRIPT = 64,
- METHOD_FLAG_VARARG = 128,
- METHOD_FLAGS_DEFAULT = METHOD_FLAG_NORMAL,
-};
-
-template <class T>
-struct VariantCaster {
- static _FORCE_INLINE_ T cast(const Variant &p_variant) {
- return p_variant;
- }
-};
-
-template <class T>
-struct VariantCaster<T &> {
- static _FORCE_INLINE_ T cast(const Variant &p_variant) {
- return p_variant;
- }
-};
-
-template <class T>
-struct VariantCaster<const T &> {
- static _FORCE_INLINE_ T cast(const Variant &p_variant) {
- return p_variant;
- }
-};
-
-#define _VC(m_idx) \
- (VariantCaster<P##m_idx>::cast((m_idx - 1) >= p_arg_count ? get_default_argument(m_idx - 1) : *p_args[m_idx - 1]))
-
-#ifdef PTRCALL_ENABLED
-
-#define VARIANT_ENUM_CAST(m_enum) \
- MAKE_ENUM_TYPE_INFO(m_enum) \
- template <> \
- struct VariantCaster<m_enum> { \
- static _FORCE_INLINE_ m_enum cast(const Variant &p_variant) { \
- return (m_enum)p_variant.operator int(); \
- } \
- }; \
- template <> \
- struct PtrToArg<m_enum> { \
- _FORCE_INLINE_ static m_enum convert(const void *p_ptr) { \
- return m_enum(*reinterpret_cast<const int *>(p_ptr)); \
- } \
- _FORCE_INLINE_ static void encode(m_enum p_val, const void *p_ptr) { \
- *(int *)p_ptr = p_val; \
- } \
- };
-
-#else
-
-#define VARIANT_ENUM_CAST(m_enum) \
- MAKE_ENUM_TYPE_INFO(m_enum) \
- template <> \
- struct VariantCaster<m_enum> { \
- static _FORCE_INLINE_ m_enum cast(const Variant &p_variant) { \
- return (m_enum)p_variant.operator int(); \
- } \
- };
-
-#endif
-
-// Object enum casts must go here
-VARIANT_ENUM_CAST(Object::ConnectFlags);
-
-template <typename T>
-struct VariantObjectClassChecker {
- static _FORCE_INLINE_ bool check(const Variant &p_variant) {
- return true;
- }
-};
-
-template <>
-struct VariantObjectClassChecker<Node *> {
- static _FORCE_INLINE_ bool check(const Variant &p_variant) {
- Object *obj = p_variant;
- Node *node = p_variant;
- return node || !obj;
- }
-};
-
-template <>
-struct VariantObjectClassChecker<Control *> {
- static _FORCE_INLINE_ bool check(const Variant &p_variant) {
- Object *obj = p_variant;
- Control *control = p_variant;
- return control || !obj;
- }
-};
-
-#define CHECK_ARG(m_arg) \
- if ((m_arg - 1) < p_arg_count) { \
- Variant::Type argtype = get_argument_type(m_arg - 1); \
- if (!Variant::can_convert_strict(p_args[m_arg - 1]->get_type(), argtype) || \
- !VariantObjectClassChecker<P##m_arg>::check(*p_args[m_arg - 1])) { \
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; \
- r_error.argument = m_arg - 1; \
- r_error.expected = argtype; \
- return Variant(); \
- } \
- }
-
-#define CHECK_NOARG(m_arg) \
- { \
- if (p_arg##m_arg.get_type() != Variant::NIL) { \
- if (r_argerror) { \
- *r_argerror = (m_arg - 1); \
- } \
- return CALL_ERROR_EXTRA_ARGUMENT; \
- } \
- }
-
-// some helpers
-
-VARIANT_ENUM_CAST(Vector3::Axis);
-
-VARIANT_ENUM_CAST(Error);
-VARIANT_ENUM_CAST(Margin);
-VARIANT_ENUM_CAST(Corner);
-VARIANT_ENUM_CAST(Orientation);
-VARIANT_ENUM_CAST(HAlign);
-VARIANT_ENUM_CAST(VAlign);
-VARIANT_ENUM_CAST(PropertyHint);
-VARIANT_ENUM_CAST(PropertyUsageFlags);
-VARIANT_ENUM_CAST(MethodFlags);
-VARIANT_ENUM_CAST(Variant::Type);
-VARIANT_ENUM_CAST(Variant::Operator);
-
-template <>
-struct VariantCaster<wchar_t> {
- static _FORCE_INLINE_ wchar_t cast(const Variant &p_variant) {
- return (wchar_t)p_variant.operator int();
- }
-};
-#ifdef PTRCALL_ENABLED
-template <>
-struct PtrToArg<wchar_t> {
- _FORCE_INLINE_ static wchar_t convert(const void *p_ptr) {
- return wchar_t(*reinterpret_cast<const int *>(p_ptr));
- }
- _FORCE_INLINE_ static void encode(wchar_t p_val, const void *p_ptr) {
- *(int *)p_ptr = p_val;
- }
-};
-#endif
-
-class MethodBind {
- int method_id;
- uint32_t hint_flags = METHOD_FLAGS_DEFAULT;
- StringName name;
- Vector<Variant> default_arguments;
- int default_argument_count = 0;
- int argument_count = 0;
-
- bool _const = false;
- bool _returns = false;
-
-protected:
-#ifdef DEBUG_METHODS_ENABLED
- Variant::Type *argument_types = nullptr;
- Vector<StringName> arg_names;
-#endif
- void _set_const(bool p_const);
- void _set_returns(bool p_returns);
-#ifdef DEBUG_METHODS_ENABLED
- virtual Variant::Type _gen_argument_type(int p_arg) const = 0;
- virtual PropertyInfo _gen_argument_type_info(int p_arg) const = 0;
- void _generate_argument_types(int p_count);
-
-#endif
- void set_argument_count(int p_count) { argument_count = p_count; }
-
-public:
- Vector<Variant> get_default_arguments() const { return default_arguments; }
- _FORCE_INLINE_ int get_default_argument_count() const { return default_argument_count; }
-
- _FORCE_INLINE_ Variant has_default_argument(int p_arg) const {
- int idx = argument_count - p_arg - 1;
-
- if (idx < 0 || idx >= default_arguments.size()) {
- return false;
- } else {
- return true;
- }
- }
-
- _FORCE_INLINE_ Variant get_default_argument(int p_arg) const {
- int idx = argument_count - p_arg - 1;
-
- if (idx < 0 || idx >= default_arguments.size()) {
- return Variant();
- } else {
- return default_arguments[idx];
- }
- }
-
-#ifdef DEBUG_METHODS_ENABLED
-
- _FORCE_INLINE_ Variant::Type get_argument_type(int p_argument) const {
- ERR_FAIL_COND_V(p_argument < -1 || p_argument > argument_count, Variant::NIL);
- return argument_types[p_argument + 1];
- }
-
- PropertyInfo get_argument_info(int p_argument) const;
- PropertyInfo get_return_info() const;
-
- void set_argument_names(const Vector<StringName> &p_names); //set by class, db, can't be inferred otherwise
- Vector<StringName> get_argument_names() const;
-
- virtual GodotTypeInfo::Metadata get_argument_meta(int p_arg) const = 0;
-
-#endif
- void set_hint_flags(uint32_t p_hint) { hint_flags = p_hint; }
- uint32_t get_hint_flags() const { return hint_flags | (is_const() ? METHOD_FLAG_CONST : 0) | (is_vararg() ? METHOD_FLAG_VARARG : 0); }
- virtual String get_instance_class() const = 0;
-
- _FORCE_INLINE_ int get_argument_count() const { return argument_count; };
-
- virtual Variant call(Object *p_object, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) = 0;
-
-#ifdef PTRCALL_ENABLED
- virtual void ptrcall(Object *p_object, const void **p_args, void *r_ret) = 0;
-#endif
-
- StringName get_name() const;
- void set_name(const StringName &p_name);
- _FORCE_INLINE_ int get_method_id() const { return method_id; }
- _FORCE_INLINE_ bool is_const() const { return _const; }
- _FORCE_INLINE_ bool has_return() const { return _returns; }
- virtual bool is_vararg() const { return false; }
-
- void set_default_arguments(const Vector<Variant> &p_defargs);
-
- MethodBind();
- virtual ~MethodBind();
-};
-
-template <class T>
-class MethodBindVarArg : public MethodBind {
-public:
- typedef Variant (T::*NativeCall)(const Variant **, int, Callable::CallError &);
-
-protected:
- NativeCall call_method = nullptr;
-#ifdef DEBUG_METHODS_ENABLED
- MethodInfo arguments;
-#endif
-
-public:
-#ifdef DEBUG_METHODS_ENABLED
-
- virtual PropertyInfo _gen_argument_type_info(int p_arg) const {
- if (p_arg < 0) {
- return arguments.return_val;
- } else if (p_arg < arguments.arguments.size()) {
- return arguments.arguments[p_arg];
- } else {
- return PropertyInfo(Variant::NIL, "arg_" + itos(p_arg), PROPERTY_HINT_NONE, String(), PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_NIL_IS_VARIANT);
- }
- }
-
- virtual Variant::Type _gen_argument_type(int p_arg) const {
- return _gen_argument_type_info(p_arg).type;
- }
-
- virtual GodotTypeInfo::Metadata get_argument_meta(int) const {
- return GodotTypeInfo::METADATA_NONE;
- }
-
-#else
-
- virtual Variant::Type _gen_argument_type(int p_arg) const {
- return Variant::NIL;
- }
-
-#endif
- virtual Variant call(Object *p_object, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) {
- T *instance = static_cast<T *>(p_object);
- return (instance->*call_method)(p_args, p_arg_count, r_error);
- }
-
- void set_method_info(const MethodInfo &p_info, bool p_return_nil_is_variant) {
- set_argument_count(p_info.arguments.size());
-#ifdef DEBUG_METHODS_ENABLED
- Variant::Type *at = memnew_arr(Variant::Type, p_info.arguments.size() + 1);
- at[0] = p_info.return_val.type;
- if (p_info.arguments.size()) {
- Vector<StringName> names;
- names.resize(p_info.arguments.size());
- for (int i = 0; i < p_info.arguments.size(); i++) {
- at[i + 1] = p_info.arguments[i].type;
- names.write[i] = p_info.arguments[i].name;
- }
-
- set_argument_names(names);
- }
- argument_types = at;
- arguments = p_info;
- if (p_return_nil_is_variant) {
- arguments.return_val.usage |= PROPERTY_USAGE_NIL_IS_VARIANT;
- }
-#endif
- }
-
-#ifdef PTRCALL_ENABLED
- virtual void ptrcall(Object *p_object, const void **p_args, void *r_ret) {
- ERR_FAIL(); //can't call
- } //todo
-#endif
-
- void set_method(NativeCall p_method) { call_method = p_method; }
- virtual bool is_const() const { return false; }
- virtual String get_instance_class() const { return T::get_class_static(); }
-
- virtual bool is_vararg() const { return true; }
-
- MethodBindVarArg() {
- _set_returns(true);
- }
-};
-
-template <class T>
-MethodBind *create_vararg_method_bind(Variant (T::*p_method)(const Variant **, int, Callable::CallError &), const MethodInfo &p_info, bool p_return_nil_is_variant) {
- MethodBindVarArg<T> *a = memnew((MethodBindVarArg<T>));
- a->set_method(p_method);
- a->set_method_info(p_info, p_return_nil_is_variant);
- return a;
-}
-
-/** This amazing hack is based on the FastDelegates theory */
-
-// tale of an amazing hack.. //
-
-// if you declare a nonexistent class..
-class __UnexistingClass;
-
-#include "method_bind.gen.inc"
-
-#endif // METHOD_BIND_H
diff --git a/core/object/SCsub b/core/object/SCsub
new file mode 100644
index 0000000000..5d429960e5
--- /dev/null
+++ b/core/object/SCsub
@@ -0,0 +1,7 @@
+#!/usr/bin/env python
+
+Import("env")
+
+env_object = env.Clone()
+
+env_object.add_source_files(env.core_sources, "*.cpp")
diff --git a/core/callable_method_pointer.cpp b/core/object/callable_method_pointer.cpp
index 21a917cbd7..21a917cbd7 100644
--- a/core/callable_method_pointer.cpp
+++ b/core/object/callable_method_pointer.cpp
diff --git a/core/callable_method_pointer.h b/core/object/callable_method_pointer.h
index 22db7d1c82..68990dcb72 100644
--- a/core/callable_method_pointer.h
+++ b/core/object/callable_method_pointer.h
@@ -31,11 +31,12 @@
#ifndef CALLABLE_METHOD_POINTER_H
#define CALLABLE_METHOD_POINTER_H
-#include "core/callable.h"
-#include "core/hashfuncs.h"
-#include "core/object.h"
+#include "core/object/object.h"
#include "core/os/copymem.h"
-#include "core/simple_type.h"
+#include "core/templates/hashfuncs.h"
+#include "core/templates/simple_type.h"
+#include "core/variant/binder_common.h"
+#include "core/variant/callable.h"
class CallableCustomMethodPointerBase : public CallableCustom {
uint32_t *comp_ptr;
@@ -69,94 +70,6 @@ public:
virtual uint32_t hash() const;
};
-#ifdef DEBUG_METHODS_ENABLED
-
-template <class T>
-struct VariantCasterAndValidate {
- static _FORCE_INLINE_ T cast(const Variant **p_args, uint32_t p_arg_idx, Callable::CallError &r_error) {
- Variant::Type argtype = GetTypeInfo<T>::VARIANT_TYPE;
- if (!Variant::can_convert_strict(p_args[p_arg_idx]->get_type(), argtype)) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = p_arg_idx;
- r_error.expected = argtype;
- }
-
- return VariantCaster<T>::cast(*p_args[p_arg_idx]);
- }
-};
-
-template <class T>
-struct VariantCasterAndValidate<T &> {
- static _FORCE_INLINE_ T cast(const Variant **p_args, uint32_t p_arg_idx, Callable::CallError &r_error) {
- Variant::Type argtype = GetTypeInfo<T>::VARIANT_TYPE;
- if (!Variant::can_convert_strict(p_args[p_arg_idx]->get_type(), argtype)) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = p_arg_idx;
- r_error.expected = argtype;
- }
-
- return VariantCaster<T>::cast(*p_args[p_arg_idx]);
- }
-};
-
-template <class T>
-struct VariantCasterAndValidate<const T &> {
- static _FORCE_INLINE_ T cast(const Variant **p_args, uint32_t p_arg_idx, Callable::CallError &r_error) {
- Variant::Type argtype = GetTypeInfo<T>::VARIANT_TYPE;
- if (!Variant::can_convert_strict(p_args[p_arg_idx]->get_type(), argtype)) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = p_arg_idx;
- r_error.expected = argtype;
- }
-
- return VariantCaster<T>::cast(*p_args[p_arg_idx]);
- }
-};
-
-#endif // DEBUG_METHODS_ENABLED
-
-// GCC 8 raises "parameter 'p_args' set but not used" here, probably using a
-// template version that does not have arguments and thus sees it unused, but
-// obviously the template can be used for functions with and without them, and
-// the optimizer will get rid of it anyway.
-#if defined(DEBUG_METHODS_ENABLED) && defined(__GNUC__) && !defined(__clang__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wunused-but-set-parameter"
-#endif
-
-template <class T, class... P, size_t... Is>
-void call_with_variant_args_helper(T *p_instance, void (T::*p_method)(P...), const Variant **p_args, Callable::CallError &r_error, IndexSequence<Is...>) {
- r_error.error = Callable::CallError::CALL_OK;
-
-#ifdef DEBUG_METHODS_ENABLED
- (p_instance->*p_method)(VariantCasterAndValidate<P>::cast(p_args, Is, r_error)...);
-#else
- (p_instance->*p_method)(VariantCaster<P>::cast(p_args[Is])...);
-#endif
-}
-
-#if defined(DEBUG_METHODS_ENABLED) && defined(__GNUC__) && !defined(__clang__)
-#pragma GCC diagnostic pop
-#endif
-
-template <class T, class... P>
-void call_with_variant_args(T *p_instance, void (T::*p_method)(P...), const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
-#ifdef DEBUG_METHODS_ENABLED
- if ((size_t)p_argcount > sizeof...(P)) {
- r_error.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
- r_error.argument = sizeof...(P);
- return;
- }
-
- if ((size_t)p_argcount < sizeof...(P)) {
- r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
- r_error.argument = sizeof...(P);
- return;
- }
-#endif
- call_with_variant_args_helper<T, P...>(p_instance, p_method, p_args, r_error, BuildIndexSequence<sizeof...(P)>{});
-}
-
template <class T, class... P>
class CallableCustomMethodPointer : public CallableCustomMethodPointerBase {
struct Data {
@@ -201,7 +114,6 @@ Callable create_custom_callable_function_pointer(T *p_instance,
const char *p_func_text,
#endif
void (T::*p_method)(P...)) {
-
typedef CallableCustomMethodPointer<T, P...> CCMP; // Messes with memnew otherwise.
CCMP *ccmp = memnew(CCMP(p_instance, p_method));
#ifdef DEBUG_METHODS_ENABLED
@@ -212,57 +124,70 @@ Callable create_custom_callable_function_pointer(T *p_instance,
// VERSION WITH RETURN
-// GCC 8 raises "parameter 'p_args' set but not used" here, probably using a
-// template version that does not have arguments and thus sees it unused, but
-// obviously the template can be used for functions with and without them, and
-// the optimizer will get rid of it anyway.
-#if defined(DEBUG_METHODS_ENABLED) && defined(__GNUC__) && !defined(__clang__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wunused-but-set-parameter"
+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;
-template <class T, class R, class... P, size_t... Is>
-void call_with_variant_args_ret_helper(T *p_instance, R (T::*p_method)(P...), const Variant **p_args, Variant &r_ret, Callable::CallError &r_error, IndexSequence<Is...>) {
- r_error.error = Callable::CallError::CALL_OK;
+public:
+ 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();
+ }
-#ifdef DEBUG_METHODS_ENABLED
- r_ret = (p_instance->*p_method)(VariantCasterAndValidate<P>::cast(p_args, Is, r_error)...);
-#else
- (p_instance->*p_method)(VariantCaster<P>::cast(p_args[Is])...);
+ 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);
+ }
-#if defined(DEBUG_METHODS_ENABLED) && defined(__GNUC__) && !defined(__clang__)
-#pragma GCC diagnostic pop
+ 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));
+ }
+};
template <class T, class R, class... P>
-void call_with_variant_args_ret(T *p_instance, R (T::*p_method)(P...), const Variant **p_args, int p_argcount, Variant &r_ret, Callable::CallError &r_error) {
+Callable create_custom_callable_function_pointer(T *p_instance,
#ifdef DEBUG_METHODS_ENABLED
- if ((size_t)p_argcount > sizeof...(P)) {
- r_error.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
- r_error.argument = sizeof...(P);
- return;
- }
-
- if ((size_t)p_argcount < sizeof...(P)) {
- r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
- r_error.argument = sizeof...(P);
- return;
- }
+ const char *p_func_text,
#endif
- call_with_variant_args_ret_helper<T, R, P...>(p_instance, p_method, p_args, r_ret, r_error, BuildIndexSequence<sizeof...(P)>{});
+ R (T::*p_method)(P...)) {
+ typedef CallableCustomMethodPointerRet<T, R, P...> CCMP; // Messes with memnew otherwise.
+ CCMP *ccmp = memnew(CCMP(p_instance, p_method));
+#ifdef DEBUG_METHODS_ENABLED
+ ccmp->set_text(p_func_text + 1); // Try to get rid of the ampersand.
+#endif
+ return Callable(ccmp);
}
+// CONST VERSION WITH RETURN
+
template <class T, class R, class... P>
-class CallableCustomMethodPointerRet : public CallableCustomMethodPointerBase {
+class CallableCustomMethodPointerRetC : public CallableCustomMethodPointerBase {
struct Data {
T *instance;
#ifdef DEBUG_ENABLED
uint64_t object_id;
#endif
R(T::*method)
- (P...);
+ (P...) const;
} data;
public:
@@ -279,10 +204,10 @@ public:
#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);
+ call_with_variant_args_retc(data.instance, data.method, p_arguments, p_argcount, r_return_value, r_call_error);
}
- CallableCustomMethodPointerRet(T *p_instance, R (T::*p_method)(P...)) {
+ CallableCustomMethodPointerRetC(T *p_instance, R (T::*p_method)(P...) const) {
zeromem(&data, sizeof(Data)); // Clear beforehand, may have padding bytes.
data.instance = p_instance;
#ifdef DEBUG_ENABLED
@@ -298,9 +223,8 @@ Callable create_custom_callable_function_pointer(T *p_instance,
#ifdef DEBUG_METHODS_ENABLED
const char *p_func_text,
#endif
- R (T::*p_method)(P...)) {
-
- typedef CallableCustomMethodPointerRet<T, R, P...> CCMP; // Messes with memnew otherwise.
+ R (T::*p_method)(P...) const) {
+ typedef CallableCustomMethodPointerRetC<T, R, P...> CCMP; // Messes with memnew otherwise.
CCMP *ccmp = memnew(CCMP(p_instance, p_method));
#ifdef DEBUG_METHODS_ENABLED
ccmp->set_text(p_func_text + 1); // Try to get rid of the ampersand.
diff --git a/core/class_db.cpp b/core/object/class_db.cpp
index 05c9850c39..64ebeb427e 100644
--- a/core/class_db.cpp
+++ b/core/object/class_db.cpp
@@ -30,7 +30,7 @@
#include "class_db.h"
-#include "core/engine.h"
+#include "core/config/engine.h"
#include "core/os/mutex.h"
#include "core/version.h"
@@ -242,21 +242,25 @@ HashMap<StringName, ClassDB::ClassInfo> ClassDB::classes;
HashMap<StringName, StringName> ClassDB::resource_base_extensions;
HashMap<StringName, StringName> ClassDB::compat_classes;
-bool ClassDB::is_parent_class(const StringName &p_class, const StringName &p_inherits) {
- OBJTYPE_RLOCK;
-
+bool ClassDB::_is_parent_class(const StringName &p_class, const StringName &p_inherits) {
StringName inherits = p_class;
while (inherits.operator String().length()) {
if (inherits == p_inherits) {
return true;
}
- inherits = get_parent_class(inherits);
+ inherits = _get_parent_class(inherits);
}
return false;
}
+bool ClassDB::is_parent_class(const StringName &p_class, const StringName &p_inherits) {
+ OBJTYPE_RLOCK;
+
+ return _is_parent_class(p_class, p_inherits);
+}
+
void ClassDB::get_class_list(List<StringName> *p_classes) {
OBJTYPE_RLOCK;
@@ -275,7 +279,7 @@ void ClassDB::get_inheriters_from_class(const StringName &p_class, List<StringNa
const StringName *k = nullptr;
while ((k = classes.next(k))) {
- if (*k != p_class && is_parent_class(*k, p_class)) {
+ if (*k != p_class && _is_parent_class(*k, p_class)) {
p_classes->push_back(*k);
}
}
@@ -287,7 +291,7 @@ void ClassDB::get_direct_inheriters_from_class(const StringName &p_class, List<S
const StringName *k = nullptr;
while ((k = classes.next(k))) {
- if (*k != p_class && get_parent_class(*k) == p_class) {
+ if (*k != p_class && _get_parent_class(*k) == p_class) {
p_classes->push_back(*k);
}
}
@@ -315,14 +319,18 @@ StringName ClassDB::get_compatibility_remapped_class(const StringName &p_class)
return p_class;
}
-StringName ClassDB::get_parent_class(const StringName &p_class) {
- OBJTYPE_RLOCK;
-
+StringName ClassDB::_get_parent_class(const StringName &p_class) {
ClassInfo *ti = classes.getptr(p_class);
ERR_FAIL_COND_V_MSG(!ti, StringName(), "Cannot get class '" + String(p_class) + "'.");
return ti->inherits;
}
+StringName ClassDB::get_parent_class(const StringName &p_class) {
+ OBJTYPE_RLOCK;
+
+ return _get_parent_class(p_class);
+}
+
ClassDB::APIType ClassDB::get_api_type(const StringName &p_class) {
OBJTYPE_RLOCK;
@@ -548,6 +556,29 @@ void ClassDB::_add_class2(const StringName &p_class, const StringName &p_inherit
}
}
+#ifdef DEBUG_METHODS_ENABLED
+static MethodInfo info_from_bind(MethodBind *p_method) {
+ MethodInfo minfo;
+ minfo.name = p_method->get_name();
+ minfo.id = p_method->get_method_id();
+
+ for (int i = 0; i < p_method->get_argument_count(); i++) {
+ minfo.arguments.push_back(p_method->get_argument_info(i));
+ }
+
+ minfo.return_val = p_method->get_return_info();
+ minfo.flags = p_method->get_hint_flags();
+
+ for (int i = 0; i < p_method->get_argument_count(); i++) {
+ if (p_method->has_default_argument(i)) {
+ minfo.default_arguments.push_back(p_method->get_default_argument(i));
+ }
+ }
+
+ return minfo;
+}
+#endif
+
void ClassDB::get_method_list(StringName p_class, List<MethodInfo> *p_methods, bool p_no_inheritance, bool p_exclude_from_properties) {
OBJTYPE_RLOCK;
@@ -570,29 +601,12 @@ void ClassDB::get_method_list(StringName p_class, List<MethodInfo> *p_methods, b
}
for (List<StringName>::Element *E = type->method_order.front(); E; E = E->next()) {
- MethodBind *method = type->method_map.get(E->get());
- MethodInfo minfo;
- minfo.name = E->get();
- minfo.id = method->get_method_id();
-
- if (p_exclude_from_properties && type->methods_in_properties.has(minfo.name)) {
+ if (p_exclude_from_properties && type->methods_in_properties.has(E->get())) {
continue;
}
- for (int i = 0; i < method->get_argument_count(); i++) {
- //Variant::Type t=method->get_argument_type(i);
-
- minfo.arguments.push_back(method->get_argument_info(i));
- }
-
- minfo.return_val = method->get_return_info();
- minfo.flags = method->get_hint_flags();
-
- for (int i = 0; i < method->get_argument_count(); i++) {
- if (method->has_default_argument(i)) {
- minfo.default_arguments.push_back(method->get_default_argument(i));
- }
- }
+ MethodBind *method = type->method_map.get(E->get());
+ MethodInfo minfo = info_from_bind(method);
p_methods->push_back(minfo);
}
@@ -618,6 +632,57 @@ void ClassDB::get_method_list(StringName p_class, List<MethodInfo> *p_methods, b
}
}
+bool ClassDB::get_method_info(StringName p_class, StringName p_method, MethodInfo *r_info, bool p_no_inheritance, bool p_exclude_from_properties) {
+ OBJTYPE_RLOCK;
+
+ ClassInfo *type = classes.getptr(p_class);
+
+ while (type) {
+ if (type->disabled) {
+ if (p_no_inheritance) {
+ break;
+ }
+
+ type = type->inherits_ptr;
+ continue;
+ }
+
+#ifdef DEBUG_METHODS_ENABLED
+ MethodBind **method = type->method_map.getptr(p_method);
+ if (method && *method) {
+ if (r_info != nullptr) {
+ MethodInfo minfo = info_from_bind(*method);
+ *r_info = minfo;
+ }
+ return true;
+ } else if (type->virtual_methods_map.has(p_method)) {
+ if (r_info) {
+ *r_info = type->virtual_methods_map[p_method];
+ }
+ return true;
+ }
+#else
+ if (type->method_map.has(p_method)) {
+ if (r_info) {
+ MethodBind *m = type->method_map[p_method];
+ MethodInfo mi;
+ mi.name = m->get_name();
+ *r_info = mi;
+ }
+ return true;
+ }
+#endif
+
+ if (p_no_inheritance) {
+ break;
+ }
+
+ type = type->inherits_ptr;
+ }
+
+ return false;
+}
+
MethodBind *ClassDB::get_method(StringName p_class, StringName p_name) {
OBJTYPE_RLOCK;
@@ -718,6 +783,25 @@ int ClassDB::get_integer_constant(const StringName &p_class, const StringName &p
return 0;
}
+bool ClassDB::has_integer_constant(const StringName &p_class, const StringName &p_name, bool p_no_inheritance) {
+ OBJTYPE_RLOCK;
+
+ ClassInfo *type = classes.getptr(p_class);
+
+ while (type) {
+ if (type->constant_map.has(p_name)) {
+ return true;
+ }
+ if (p_no_inheritance) {
+ return false;
+ }
+
+ type = type->inherits_ptr;
+ }
+
+ return false;
+}
+
StringName ClassDB::get_integer_constant_enum(const StringName &p_class, const StringName &p_name, bool p_no_inheritance) {
OBJTYPE_RLOCK;
@@ -784,6 +868,25 @@ void ClassDB::get_enum_constants(const StringName &p_class, const StringName &p_
}
}
+bool ClassDB::has_enum(const StringName &p_class, const StringName &p_name, bool p_no_inheritance) {
+ OBJTYPE_RLOCK;
+
+ ClassInfo *type = classes.getptr(p_class);
+
+ while (type) {
+ if (type->enum_map.has(p_name)) {
+ return true;
+ }
+ if (p_no_inheritance) {
+ return false;
+ }
+
+ type = type->inherits_ptr;
+ }
+
+ return false;
+}
+
void ClassDB::add_signal(StringName p_class, const MethodInfo &p_signal) {
OBJTYPE_WLOCK;
@@ -825,7 +928,7 @@ void ClassDB::get_signal_list(StringName p_class, List<MethodInfo> *p_signals, b
}
}
-bool ClassDB::has_signal(StringName p_class, StringName p_signal) {
+bool ClassDB::has_signal(StringName p_class, StringName p_signal, bool p_no_inheritance) {
OBJTYPE_RLOCK;
ClassInfo *type = classes.getptr(p_class);
ClassInfo *check = type;
@@ -833,6 +936,9 @@ bool ClassDB::has_signal(StringName p_class, StringName p_signal) {
if (check->signal_map.has(p_signal)) {
return true;
}
+ if (p_no_inheritance) {
+ return false;
+ }
check = check->inherits_ptr;
}
@@ -910,6 +1016,7 @@ void ClassDB::add_property(StringName p_class, const PropertyInfo &p_pinfo, cons
OBJTYPE_WLOCK
type->property_list.push_back(p_pinfo);
+ type->property_map[p_pinfo.name] = p_pinfo;
#ifdef DEBUG_METHODS_ENABLED
if (mb_get) {
type->methods_in_properties.insert(p_getter);
@@ -959,6 +1066,30 @@ void ClassDB::get_property_list(StringName p_class, List<PropertyInfo> *p_list,
}
}
+bool ClassDB::get_property_info(StringName p_class, StringName p_property, PropertyInfo *r_info, bool p_no_inheritance, const Object *p_validator) {
+ OBJTYPE_RLOCK;
+
+ ClassInfo *check = classes.getptr(p_class);
+ while (check) {
+ if (check->property_map.has(p_property)) {
+ PropertyInfo pinfo = check->property_map[p_property];
+ if (p_validator) {
+ p_validator->_validate_property(pinfo);
+ }
+ if (r_info) {
+ *r_info = pinfo;
+ }
+ return true;
+ }
+ if (p_no_inheritance) {
+ break;
+ }
+ check = check->inherits_ptr;
+ }
+
+ return false;
+}
+
bool ClassDB::set_property(Object *p_object, const StringName &p_property, const Variant &p_value, bool *r_valid) {
ClassInfo *type = classes.getptr(p_object->get_class_name());
ClassInfo *check = type;
@@ -1220,7 +1351,7 @@ MethodBind *ClassDB::bind_methodfi(uint32_t p_flags, MethodBind *p_bind, const c
defvals.resize(p_defcount);
for (int i = 0; i < p_defcount; i++) {
- defvals.write[i] = *p_defs[p_defcount - i - 1];
+ defvals.write[i] = *p_defs[i];
}
p_bind->set_default_arguments(defvals);
@@ -1239,6 +1370,7 @@ void ClassDB::add_virtual_method(const StringName &p_class, const MethodInfo &p_
mi.flags |= METHOD_FLAG_VIRTUAL;
}
classes[p_class].virtual_methods.push_back(mi);
+ classes[p_class].virtual_methods_map[p_method.name] = mi;
#endif
}
diff --git a/core/class_db.h b/core/object/class_db.h
index eae2a9afd4..94f26da60d 100644
--- a/core/class_db.h
+++ b/core/object/class_db.h
@@ -31,17 +31,17 @@
#ifndef CLASS_DB_H
#define CLASS_DB_H
-#include "core/method_bind.h"
-#include "core/object.h"
-#include "core/print_string.h"
+#include "core/object/method_bind.h"
+#include "core/object/object.h"
+#include "core/string/print_string.h"
/** To bind more then 6 parameters include this:
- * #include "core/method_bind_ext.gen.inc"
+ *
*/
// Makes callable_mp readily available in all classes connecting signals.
// Needs to come after method_bind and object have been included.
-#include "core/callable_method_pointer.h"
+#include "core/object/callable_method_pointer.h"
#define DEFVAL(m_defval) (m_defval)
@@ -120,11 +120,13 @@ public:
HashMap<StringName, List<StringName>> enum_map;
HashMap<StringName, MethodInfo> signal_map;
List<PropertyInfo> property_list;
+ HashMap<StringName, PropertyInfo> property_map;
#ifdef DEBUG_METHODS_ENABLED
List<StringName> constant_order;
List<StringName> method_order;
Set<StringName> methods_in_properties;
List<MethodInfo> virtual_methods;
+ Map<StringName, MethodInfo> virtual_methods_map;
StringName category;
#endif
HashMap<StringName, PropertySetGet> property_setget;
@@ -162,6 +164,11 @@ public:
static HashMap<StringName, HashMap<StringName, Variant>> default_values;
static Set<StringName> default_values_cached;
+private:
+ // Non-locking variants of get_parent_class and is_parent_class.
+ static StringName _get_parent_class(const StringName &p_class);
+ static bool _is_parent_class(const StringName &p_class, const StringName &p_inherits);
+
public:
// DO NOT USE THIS!!!!!! NEEDS TO BE PUBLIC BUT DO NOT USE NO MATTER WHAT!!!
template <class T>
@@ -328,7 +335,7 @@ public:
}
static void add_signal(StringName p_class, const MethodInfo &p_signal);
- static bool has_signal(StringName p_class, StringName p_signal);
+ static bool has_signal(StringName p_class, StringName p_signal, bool p_no_inheritance = false);
static bool get_signal(StringName p_class, StringName p_signal, MethodInfo *r_signal);
static void get_signal_list(StringName p_class, List<MethodInfo> *p_signals, bool p_no_inheritance = false);
@@ -337,6 +344,7 @@ public:
static void add_property(StringName p_class, const PropertyInfo &p_pinfo, const StringName &p_setter, const StringName &p_getter, int p_index = -1);
static void set_property_default_value(StringName p_class, const StringName &p_name, const Variant &p_default);
static void get_property_list(StringName p_class, List<PropertyInfo> *p_list, bool p_no_inheritance = false, const Object *p_validator = nullptr);
+ static bool get_property_info(StringName p_class, StringName p_property, PropertyInfo *r_info, bool p_no_inheritance = false, const Object *p_validator = nullptr);
static bool set_property(Object *p_object, const StringName &p_property, const Variant &p_value, bool *r_valid = nullptr);
static bool get_property(Object *p_object, const StringName &p_property, Variant &r_value);
static bool has_property(const StringName &p_class, const StringName &p_property, bool p_no_inheritance = false);
@@ -349,6 +357,7 @@ public:
static void set_method_flags(StringName p_class, StringName p_method, int p_flags);
static void get_method_list(StringName p_class, List<MethodInfo> *p_methods, bool p_no_inheritance = false, bool p_exclude_from_properties = false);
+ static bool get_method_info(StringName p_class, StringName p_method, MethodInfo *r_info, bool p_no_inheritance = false, bool p_exclude_from_properties = false);
static MethodBind *get_method(StringName p_class, StringName p_name);
static void add_virtual_method(const StringName &p_class, const MethodInfo &p_method, bool p_virtual = true);
@@ -357,10 +366,12 @@ public:
static void bind_integer_constant(const StringName &p_class, const StringName &p_enum, const StringName &p_name, int p_constant);
static void get_integer_constant_list(const StringName &p_class, List<String> *p_constants, bool p_no_inheritance = false);
static int get_integer_constant(const StringName &p_class, const StringName &p_name, bool *p_success = nullptr);
+ static bool has_integer_constant(const StringName &p_class, const StringName &p_name, bool p_no_inheritance = false);
static StringName get_integer_constant_enum(const StringName &p_class, const StringName &p_name, bool p_no_inheritance = false);
static void get_enum_list(const StringName &p_class, List<StringName> *p_enums, bool p_no_inheritance = false);
static void get_enum_constants(const StringName &p_class, const StringName &p_enum, List<StringName> *p_constants, bool p_no_inheritance = false);
+ static bool has_enum(const StringName &p_class, const StringName &p_name, bool p_no_inheritance = false);
static Variant class_get_default_property_value(const StringName &p_class, const StringName &p_property, bool *r_valid = nullptr);
diff --git a/core/message_queue.cpp b/core/object/message_queue.cpp
index 6dcf24e7ed..f0d6786853 100644
--- a/core/message_queue.cpp
+++ b/core/object/message_queue.cpp
@@ -30,9 +30,9 @@
#include "message_queue.h"
+#include "core/config/project_settings.h"
#include "core/core_string_names.h"
-#include "core/project_settings.h"
-#include "core/script_language.h"
+#include "core/object/script_language.h"
MessageQueue *MessageQueue::singleton = nullptr;
diff --git a/core/message_queue.h b/core/object/message_queue.h
index 7d13e26208..2901ab196a 100644
--- a/core/message_queue.h
+++ b/core/object/message_queue.h
@@ -31,15 +31,14 @@
#ifndef MESSAGE_QUEUE_H
#define MESSAGE_QUEUE_H
-#include "core/object.h"
+#include "core/object/class_db.h"
#include "core/os/thread_safe.h"
class MessageQueue {
_THREAD_SAFE_CLASS_
enum {
-
- DEFAULT_QUEUE_SIZE_KB = 1024
+ DEFAULT_QUEUE_SIZE_KB = 4096
};
enum {
diff --git a/core/method_bind.cpp b/core/object/method_bind.cpp
index 3244c63292..e6652ac09f 100644
--- a/core/method_bind.cpp
+++ b/core/object/method_bind.cpp
@@ -30,7 +30,7 @@
// object.h needs to be the first include *before* method_bind.h
// FIXME: Find out why and fix potential cyclical dependencies.
-#include "core/object.h"
+#include "core/object/object.h"
#include "method_bind.h"
diff --git a/core/object/method_bind.h b/core/object/method_bind.h
new file mode 100644
index 0000000000..bd308c9630
--- /dev/null
+++ b/core/object/method_bind.h
@@ -0,0 +1,577 @@
+/*************************************************************************/
+/* method_bind.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* 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. */
+/*************************************************************************/
+
+#ifndef METHOD_BIND_H
+#define METHOD_BIND_H
+
+#include "core/variant/binder_common.h"
+
+enum MethodFlags {
+ METHOD_FLAG_NORMAL = 1,
+ METHOD_FLAG_EDITOR = 2,
+ METHOD_FLAG_NOSCRIPT = 4,
+ METHOD_FLAG_CONST = 8,
+ METHOD_FLAG_REVERSE = 16, // used for events
+ METHOD_FLAG_VIRTUAL = 32,
+ METHOD_FLAG_FROM_SCRIPT = 64,
+ METHOD_FLAG_VARARG = 128,
+ METHOD_FLAGS_DEFAULT = METHOD_FLAG_NORMAL,
+};
+
+VARIANT_ENUM_CAST(MethodFlags)
+
+// some helpers
+
+class MethodBind {
+ int method_id;
+ uint32_t hint_flags = METHOD_FLAGS_DEFAULT;
+ StringName name;
+ StringName instance_class;
+ Vector<Variant> default_arguments;
+ int default_argument_count = 0;
+ int argument_count = 0;
+
+ bool _const = false;
+ bool _returns = false;
+
+protected:
+#ifdef DEBUG_METHODS_ENABLED
+ Variant::Type *argument_types = nullptr;
+ Vector<StringName> arg_names;
+#endif
+ void _set_const(bool p_const);
+ void _set_returns(bool p_returns);
+#ifdef DEBUG_METHODS_ENABLED
+ virtual Variant::Type _gen_argument_type(int p_arg) const = 0;
+ virtual PropertyInfo _gen_argument_type_info(int p_arg) const = 0;
+ void _generate_argument_types(int p_count);
+
+#endif
+ void set_argument_count(int p_count) { argument_count = p_count; }
+
+public:
+ _FORCE_INLINE_ const Vector<Variant> &get_default_arguments() const { return default_arguments; }
+ _FORCE_INLINE_ int get_default_argument_count() const { return default_argument_count; }
+
+ _FORCE_INLINE_ Variant has_default_argument(int p_arg) const {
+ int idx = p_arg - (argument_count - default_arguments.size());
+
+ if (idx < 0 || idx >= default_arguments.size()) {
+ return false;
+ } else {
+ return true;
+ }
+ }
+
+ _FORCE_INLINE_ Variant get_default_argument(int p_arg) const {
+ int idx = p_arg - (argument_count - default_arguments.size());
+
+ if (idx < 0 || idx >= default_arguments.size()) {
+ return Variant();
+ } else {
+ return default_arguments[idx];
+ }
+ }
+
+#ifdef DEBUG_METHODS_ENABLED
+ _FORCE_INLINE_ Variant::Type get_argument_type(int p_argument) const {
+ ERR_FAIL_COND_V(p_argument < -1 || p_argument > argument_count, Variant::NIL);
+ return argument_types[p_argument + 1];
+ }
+
+ PropertyInfo get_argument_info(int p_argument) const;
+ PropertyInfo get_return_info() const;
+
+ void set_argument_names(const Vector<StringName> &p_names); // Set by ClassDB, can't be inferred otherwise.
+ Vector<StringName> get_argument_names() const;
+
+ virtual GodotTypeInfo::Metadata get_argument_meta(int p_arg) const = 0;
+#endif
+
+ void set_hint_flags(uint32_t p_hint) { hint_flags = p_hint; }
+ uint32_t get_hint_flags() const { return hint_flags | (is_const() ? METHOD_FLAG_CONST : 0) | (is_vararg() ? METHOD_FLAG_VARARG : 0); }
+ _FORCE_INLINE_ StringName get_instance_class() const { return instance_class; }
+ _FORCE_INLINE_ void set_instance_class(const StringName &p_class) { instance_class = p_class; }
+
+ _FORCE_INLINE_ int get_argument_count() const { return argument_count; };
+
+ virtual Variant call(Object *p_object, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) = 0;
+ virtual void ptrcall(Object *p_object, const void **p_args, void *r_ret) = 0;
+
+ StringName get_name() const;
+ void set_name(const StringName &p_name);
+ _FORCE_INLINE_ int get_method_id() const { return method_id; }
+ _FORCE_INLINE_ bool is_const() const { return _const; }
+ _FORCE_INLINE_ bool has_return() const { return _returns; }
+ virtual bool is_vararg() const { return false; }
+
+ void set_default_arguments(const Vector<Variant> &p_defargs);
+
+ MethodBind();
+ virtual ~MethodBind();
+};
+
+template <class T>
+class MethodBindVarArg : public MethodBind {
+public:
+ typedef Variant (T::*NativeCall)(const Variant **, int, Callable::CallError &);
+
+protected:
+ NativeCall call_method = nullptr;
+#ifdef DEBUG_METHODS_ENABLED
+ MethodInfo arguments;
+#endif
+
+public:
+#ifdef DEBUG_METHODS_ENABLED
+ virtual PropertyInfo _gen_argument_type_info(int p_arg) const {
+ if (p_arg < 0) {
+ return arguments.return_val;
+ } else if (p_arg < arguments.arguments.size()) {
+ return arguments.arguments[p_arg];
+ } else {
+ return PropertyInfo(Variant::NIL, "arg_" + itos(p_arg), PROPERTY_HINT_NONE, String(), PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_NIL_IS_VARIANT);
+ }
+ }
+
+ virtual Variant::Type _gen_argument_type(int p_arg) const {
+ return _gen_argument_type_info(p_arg).type;
+ }
+
+ virtual GodotTypeInfo::Metadata get_argument_meta(int) const {
+ return GodotTypeInfo::METADATA_NONE;
+ }
+#else
+ virtual Variant::Type _gen_argument_type(int p_arg) const {
+ return Variant::NIL;
+ }
+#endif
+
+ virtual Variant call(Object *p_object, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) {
+ T *instance = static_cast<T *>(p_object);
+ return (instance->*call_method)(p_args, p_arg_count, r_error);
+ }
+
+ void set_method_info(const MethodInfo &p_info, bool p_return_nil_is_variant) {
+ set_argument_count(p_info.arguments.size());
+#ifdef DEBUG_METHODS_ENABLED
+ Variant::Type *at = memnew_arr(Variant::Type, p_info.arguments.size() + 1);
+ at[0] = p_info.return_val.type;
+ if (p_info.arguments.size()) {
+ Vector<StringName> names;
+ names.resize(p_info.arguments.size());
+ for (int i = 0; i < p_info.arguments.size(); i++) {
+ at[i + 1] = p_info.arguments[i].type;
+ names.write[i] = p_info.arguments[i].name;
+ }
+
+ set_argument_names(names);
+ }
+ argument_types = at;
+ arguments = p_info;
+ if (p_return_nil_is_variant) {
+ arguments.return_val.usage |= PROPERTY_USAGE_NIL_IS_VARIANT;
+ }
+#endif
+ }
+
+ virtual void ptrcall(Object *p_object, const void **p_args, void *r_ret) {
+ ERR_FAIL(); // Can't call.
+ }
+
+ void set_method(NativeCall p_method) { call_method = p_method; }
+ virtual bool is_const() const { return false; }
+
+ virtual bool is_vararg() const { return true; }
+
+ MethodBindVarArg() {
+ _set_returns(true);
+ }
+};
+
+template <class T>
+MethodBind *create_vararg_method_bind(Variant (T::*p_method)(const Variant **, int, Callable::CallError &), const MethodInfo &p_info, bool p_return_nil_is_variant) {
+ MethodBindVarArg<T> *a = memnew((MethodBindVarArg<T>));
+ a->set_method(p_method);
+ a->set_method_info(p_info, p_return_nil_is_variant);
+ a->set_instance_class(T::get_class_static());
+ return a;
+}
+
+/**** VARIADIC TEMPLATES ****/
+
+#ifndef TYPED_METHOD_BIND
+class __UnexistingClass;
+#define MB_T __UnexistingClass
+#else
+#define MB_T T
+#endif
+
+// no return, not const
+#ifdef TYPED_METHOD_BIND
+template <class T, class... P>
+#else
+template <class... P>
+#endif
+class MethodBindT : public MethodBind {
+ void (MB_T::*method)(P...);
+
+protected:
+#ifdef DEBUG_METHODS_ENABLED
+// GCC raises warnings in the case P = {} as the comparison is always false...
+#if defined(__GNUC__) && !defined(__clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wlogical-op"
+#endif
+ virtual Variant::Type _gen_argument_type(int p_arg) const {
+ if (p_arg >= 0 && p_arg < (int)sizeof...(P)) {
+ return call_get_argument_type<P...>(p_arg);
+ } else {
+ return Variant::NIL;
+ }
+ }
+#if defined(__GNUC__) && !defined(__clang__)
+#pragma GCC diagnostic pop
+#endif
+
+ virtual PropertyInfo _gen_argument_type_info(int p_arg) const {
+ PropertyInfo pi;
+ call_get_argument_type_info<P...>(p_arg, pi);
+ return pi;
+ }
+#endif
+
+public:
+#ifdef DEBUG_METHODS_ENABLED
+ virtual GodotTypeInfo::Metadata get_argument_meta(int p_arg) const {
+ return call_get_argument_metadata<P...>(p_arg);
+ }
+
+#endif
+ virtual Variant call(Object *p_object, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) {
+#ifdef TYPED_METHOD_BIND
+ call_with_variant_args_dv(static_cast<T *>(p_object), method, p_args, p_arg_count, r_error, get_default_arguments());
+#else
+ call_with_variant_args_dv((MB_T *)(p_object), method, p_args, p_arg_count, r_error, get_default_arguments());
+#endif
+ return Variant();
+ }
+
+ virtual void ptrcall(Object *p_object, const void **p_args, void *r_ret) {
+#ifdef TYPED_METHOD_BIND
+ call_with_ptr_args<T, P...>(static_cast<T *>(p_object), method, p_args);
+#else
+ call_with_ptr_args<MB_T, P...>((MB_T *)(p_object), method, p_args);
+#endif
+ }
+
+ MethodBindT(void (MB_T::*p_method)(P...)) {
+ method = p_method;
+#ifdef DEBUG_METHODS_ENABLED
+ _generate_argument_types(sizeof...(P));
+#endif
+ set_argument_count(sizeof...(P));
+ }
+};
+
+template <class T, class... P>
+MethodBind *create_method_bind(void (T::*p_method)(P...)) {
+#ifdef TYPED_METHOD_BIND
+ MethodBind *a = memnew((MethodBindT<T, P...>)(p_method));
+#else
+ MethodBind *a = memnew((MethodBindT<P...>)(reinterpret_cast<void (MB_T::*)(P...)>(p_method)));
+#endif
+ a->set_instance_class(T::get_class_static());
+ return a;
+}
+
+// no return, not const
+
+#ifdef TYPED_METHOD_BIND
+template <class T, class... P>
+#else
+template <class... P>
+#endif
+class MethodBindTC : public MethodBind {
+ void (MB_T::*method)(P...) const;
+
+protected:
+#ifdef DEBUG_METHODS_ENABLED
+// GCC raises warnings in the case P = {} as the comparison is always false...
+#if defined(__GNUC__) && !defined(__clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wlogical-op"
+#endif
+ virtual Variant::Type _gen_argument_type(int p_arg) const {
+ if (p_arg >= 0 && p_arg < (int)sizeof...(P)) {
+ return call_get_argument_type<P...>(p_arg);
+ } else {
+ return Variant::NIL;
+ }
+ }
+#if defined(__GNUC__) && !defined(__clang__)
+#pragma GCC diagnostic pop
+#endif
+
+ virtual PropertyInfo _gen_argument_type_info(int p_arg) const {
+ PropertyInfo pi;
+ call_get_argument_type_info<P...>(p_arg, pi);
+ return pi;
+ }
+#endif
+
+public:
+#ifdef DEBUG_METHODS_ENABLED
+ virtual GodotTypeInfo::Metadata get_argument_meta(int p_arg) const {
+ return call_get_argument_metadata<P...>(p_arg);
+ }
+
+#endif
+ virtual Variant call(Object *p_object, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) {
+#ifdef TYPED_METHOD_BIND
+ call_with_variant_argsc_dv(static_cast<T *>(p_object), method, p_args, p_arg_count, r_error, get_default_arguments());
+#else
+ call_with_variant_argsc_dv((MB_T *)(p_object), method, p_args, p_arg_count, r_error, get_default_arguments());
+#endif
+ return Variant();
+ }
+
+ virtual void ptrcall(Object *p_object, const void **p_args, void *r_ret) {
+#ifdef TYPED_METHOD_BIND
+ call_with_ptr_argsc<T, P...>(static_cast<T *>(p_object), method, p_args);
+#else
+ call_with_ptr_argsc<MB_T, P...>((MB_T *)(p_object), method, p_args);
+#endif
+ }
+
+ MethodBindTC(void (MB_T::*p_method)(P...) const) {
+ method = p_method;
+ _set_const(true);
+#ifdef DEBUG_METHODS_ENABLED
+ _generate_argument_types(sizeof...(P));
+#endif
+ set_argument_count(sizeof...(P));
+ }
+};
+
+template <class T, class... P>
+MethodBind *create_method_bind(void (T::*p_method)(P...) const) {
+#ifdef TYPED_METHOD_BIND
+ MethodBind *a = memnew((MethodBindTC<T, P...>)(p_method));
+#else
+ MethodBind *a = memnew((MethodBindTC<P...>)(reinterpret_cast<void (MB_T::*)(P...) const>(p_method)));
+#endif
+ a->set_instance_class(T::get_class_static());
+ return a;
+}
+
+// return, not const
+
+#ifdef TYPED_METHOD_BIND
+template <class T, class R, class... P>
+#else
+template <class R, class... P>
+#endif
+class MethodBindTR : public MethodBind {
+ R(MB_T::*method)
+ (P...);
+
+protected:
+#ifdef DEBUG_METHODS_ENABLED
+// GCC raises warnings in the case P = {} as the comparison is always false...
+#if defined(__GNUC__) && !defined(__clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wlogical-op"
+#endif
+ virtual Variant::Type _gen_argument_type(int p_arg) const {
+ if (p_arg >= 0 && p_arg < (int)sizeof...(P)) {
+ return call_get_argument_type<P...>(p_arg);
+ } else {
+ return GetTypeInfo<R>::VARIANT_TYPE;
+ }
+ }
+
+ virtual PropertyInfo _gen_argument_type_info(int p_arg) const {
+ if (p_arg >= 0 && p_arg < (int)sizeof...(P)) {
+ PropertyInfo pi;
+ call_get_argument_type_info<P...>(p_arg, pi);
+ return pi;
+ } else {
+ return GetTypeInfo<R>::get_class_info();
+ }
+ }
+#if defined(__GNUC__) && !defined(__clang__)
+#pragma GCC diagnostic pop
+#endif
+#endif
+
+public:
+#ifdef DEBUG_METHODS_ENABLED
+ virtual GodotTypeInfo::Metadata get_argument_meta(int p_arg) const {
+ if (p_arg >= 0) {
+ return call_get_argument_metadata<P...>(p_arg);
+ } else {
+ return GetTypeInfo<R>::METADATA;
+ }
+ }
+#endif
+
+ virtual Variant call(Object *p_object, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) {
+ Variant ret;
+#ifdef TYPED_METHOD_BIND
+ call_with_variant_args_ret_dv(static_cast<T *>(p_object), method, p_args, p_arg_count, ret, r_error, get_default_arguments());
+#else
+ call_with_variant_args_ret_dv((MB_T *)p_object, method, p_args, p_arg_count, ret, r_error, get_default_arguments());
+#endif
+ return ret;
+ }
+
+ virtual void ptrcall(Object *p_object, const void **p_args, void *r_ret) {
+#ifdef TYPED_METHOD_BIND
+ call_with_ptr_args_ret<T, R, P...>(static_cast<T *>(p_object), method, p_args, r_ret);
+#else
+ call_with_ptr_args_ret<MB_T, R, P...>((MB_T *)(p_object), method, p_args, r_ret);
+#endif
+ }
+
+ MethodBindTR(R (MB_T::*p_method)(P...)) {
+ method = p_method;
+ _set_returns(true);
+#ifdef DEBUG_METHODS_ENABLED
+ _generate_argument_types(sizeof...(P));
+#endif
+ set_argument_count(sizeof...(P));
+ }
+};
+
+template <class T, class R, class... P>
+MethodBind *create_method_bind(R (T::*p_method)(P...)) {
+#ifdef TYPED_METHOD_BIND
+ MethodBind *a = memnew((MethodBindTR<T, R, P...>)(p_method));
+#else
+ MethodBind *a = memnew((MethodBindTR<R, P...>)(reinterpret_cast<R (MB_T::*)(P...)>(p_method)));
+#endif
+
+ a->set_instance_class(T::get_class_static());
+ return a;
+}
+
+// return, const
+
+#ifdef TYPED_METHOD_BIND
+template <class T, class R, class... P>
+#else
+template <class R, class... P>
+#endif
+class MethodBindTRC : public MethodBind {
+ R(MB_T::*method)
+ (P...) const;
+
+protected:
+#ifdef DEBUG_METHODS_ENABLED
+// GCC raises warnings in the case P = {} as the comparison is always false...
+#if defined(__GNUC__) && !defined(__clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wlogical-op"
+#endif
+ virtual Variant::Type _gen_argument_type(int p_arg) const {
+ if (p_arg >= 0 && p_arg < (int)sizeof...(P)) {
+ return call_get_argument_type<P...>(p_arg);
+ } else {
+ return GetTypeInfo<R>::VARIANT_TYPE;
+ }
+ }
+
+ virtual PropertyInfo _gen_argument_type_info(int p_arg) const {
+ if (p_arg >= 0 && p_arg < (int)sizeof...(P)) {
+ PropertyInfo pi;
+ call_get_argument_type_info<P...>(p_arg, pi);
+ return pi;
+ } else {
+ return GetTypeInfo<R>::get_class_info();
+ }
+ }
+#if defined(__GNUC__) && !defined(__clang__)
+#pragma GCC diagnostic pop
+#endif
+#endif
+
+public:
+#ifdef DEBUG_METHODS_ENABLED
+ virtual GodotTypeInfo::Metadata get_argument_meta(int p_arg) const {
+ if (p_arg >= 0) {
+ return call_get_argument_metadata<P...>(p_arg);
+ } else {
+ return GetTypeInfo<R>::METADATA;
+ }
+ }
+#endif
+
+ virtual Variant call(Object *p_object, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) {
+ Variant ret;
+#ifdef TYPED_METHOD_BIND
+ call_with_variant_args_retc_dv(static_cast<T *>(p_object), method, p_args, p_arg_count, ret, r_error, get_default_arguments());
+#else
+ call_with_variant_args_retc_dv((MB_T *)(p_object), method, p_args, p_arg_count, ret, r_error, get_default_arguments());
+#endif
+ return ret;
+ }
+
+ virtual void ptrcall(Object *p_object, const void **p_args, void *r_ret) {
+#ifdef TYPED_METHOD_BIND
+ call_with_ptr_args_retc<T, R, P...>(static_cast<T *>(p_object), method, p_args, r_ret);
+#else
+ call_with_ptr_args_retc<MB_T, R, P...>((MB_T *)(p_object), method, p_args, r_ret);
+#endif
+ }
+
+ MethodBindTRC(R (MB_T::*p_method)(P...) const) {
+ method = p_method;
+ _set_returns(true);
+ _set_const(true);
+#ifdef DEBUG_METHODS_ENABLED
+ _generate_argument_types(sizeof...(P));
+#endif
+ set_argument_count(sizeof...(P));
+ }
+};
+
+template <class T, class R, class... P>
+MethodBind *create_method_bind(R (T::*p_method)(P...) const) {
+#ifdef TYPED_METHOD_BIND
+ MethodBind *a = memnew((MethodBindTRC<T, R, P...>)(p_method));
+#else
+ MethodBind *a = memnew((MethodBindTRC<R, P...>)(reinterpret_cast<R (MB_T::*)(P...) const>(p_method)));
+#endif
+ a->set_instance_class(T::get_class_static());
+ return a;
+}
+
+#endif // METHOD_BIND_H
diff --git a/core/object.cpp b/core/object/object.cpp
index 8abea9ca7e..96a41d6852 100644
--- a/core/object.cpp
+++ b/core/object/object.cpp
@@ -30,14 +30,14 @@
#include "object.h"
-#include "core/class_db.h"
#include "core/core_string_names.h"
-#include "core/message_queue.h"
+#include "core/io/resource.h"
+#include "core/object/class_db.h"
+#include "core/object/message_queue.h"
+#include "core/object/script_language.h"
#include "core/os/os.h"
-#include "core/print_string.h"
-#include "core/resource.h"
-#include "core/script_language.h"
-#include "core/translation.h"
+#include "core/string/print_string.h"
+#include "core/string/translation.h"
#ifdef DEBUG_ENABLED
@@ -421,17 +421,6 @@ void Object::set(const StringName &p_name, const Variant &p_value, bool *r_valid
return;
}
- {
- bool valid;
- setvar(p_name, p_value, &valid);
- if (valid) {
- if (r_valid) {
- *r_valid = true;
- }
- return;
- }
- }
-
#ifdef TOOLS_ENABLED
if (script_instance) {
bool valid;
@@ -496,18 +485,6 @@ Variant Object::get(const StringName &p_name, bool *r_valid) const {
return ret;
}
- //if nothing else, use getvar
- {
- bool valid;
- ret = getvar(p_name, &valid);
- if (valid) {
- if (r_valid) {
- *r_valid = true;
- }
- return ret;
- }
- }
-
#ifdef TOOLS_ENABLED
if (script_instance) {
bool valid;
@@ -555,9 +532,12 @@ void Object::set_indexed(const Vector<StringName> &p_names, const Variant &p_val
}
for (int i = 1; i < p_names.size() - 1; i++) {
- value_stack.push_back(value_stack.back()->get().get_named(p_names[i], r_valid));
+ value_stack.push_back(value_stack.back()->get().get_named(p_names[i], valid));
+ if (r_valid) {
+ *r_valid = valid;
+ }
- if (!*r_valid) {
+ if (!valid) {
value_stack.clear();
return;
}
@@ -566,10 +546,13 @@ void Object::set_indexed(const Vector<StringName> &p_names, const Variant &p_val
value_stack.push_back(p_value); // p_names[p_names.size() - 1]
for (int i = p_names.size() - 1; i > 0; i--) {
- value_stack.back()->prev()->get().set_named(p_names[i], value_stack.back()->get(), r_valid);
+ value_stack.back()->prev()->get().set_named(p_names[i], value_stack.back()->get(), valid);
value_stack.pop_back();
- if (!*r_valid) {
+ if (r_valid) {
+ *r_valid = valid;
+ }
+ if (!valid) {
value_stack.clear();
return;
}
@@ -592,7 +575,7 @@ Variant Object::get_indexed(const Vector<StringName> &p_names, bool *r_valid) co
Variant current_value = get(p_names[0], &valid);
for (int i = 1; i < p_names.size(); i++) {
- current_value = current_value.get_named(p_names[i], &valid);
+ current_value = current_value.get_named(p_names[i], valid);
if (!valid) {
break;
@@ -614,9 +597,6 @@ void Object::get_property_list(List<PropertyInfo> *p_list, bool p_reversed) cons
_get_property_listv(p_list, p_reversed);
if (!is_class("Script")) { // can still be set, but this is for userfriendlyness
-#ifdef TOOLS_ENABLED
- p_list->push_back(PropertyInfo(Variant::NIL, "Script", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_GROUP));
-#endif
p_list->push_back(PropertyInfo(Variant::OBJECT, "script", PROPERTY_HINT_RESOURCE_TYPE, "Script", PROPERTY_USAGE_DEFAULT));
}
if (!metadata.empty()) {
@@ -675,89 +655,11 @@ Variant Object::_call_deferred_bind(const Variant **p_args, int p_argcount, Call
StringName method = *p_args[0];
- MessageQueue::get_singleton()->push_call(get_instance_id(), method, &p_args[1], p_argcount - 1);
+ MessageQueue::get_singleton()->push_call(get_instance_id(), method, &p_args[1], p_argcount - 1, true);
return Variant();
}
-#ifdef DEBUG_ENABLED
-static void _test_call_error(const StringName &p_func, const Callable::CallError &error) {
- switch (error.error) {
- case Callable::CallError::CALL_OK:
- case Callable::CallError::CALL_ERROR_INVALID_METHOD:
- break;
- case Callable::CallError::CALL_ERROR_INVALID_ARGUMENT: {
- ERR_FAIL_MSG("Error calling function: " + String(p_func) + " - Invalid type for argument " + itos(error.argument) + ", expected " + Variant::get_type_name(Variant::Type(error.expected)) + ".");
- break;
- }
- case Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS: {
- ERR_FAIL_MSG("Error calling function: " + String(p_func) + " - Too many arguments, expected " + itos(error.argument) + ".");
- break;
- }
- case Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS: {
- ERR_FAIL_MSG("Error calling function: " + String(p_func) + " - Too few arguments, expected " + itos(error.argument) + ".");
- break;
- }
- case Callable::CallError::CALL_ERROR_INSTANCE_IS_NULL:
- break;
- }
-}
-#else
-
-#define _test_call_error(m_str, m_err)
-
-#endif
-
-void Object::call_multilevel(const StringName &p_method, const Variant **p_args, int p_argcount) {
- if (p_method == CoreStringNames::get_singleton()->_free) {
-#ifdef DEBUG_ENABLED
- ERR_FAIL_COND_MSG(Object::cast_to<Reference>(this), "Can't 'free' a reference.");
-
- ERR_FAIL_COND_MSG(_lock_index.get() > 1, "Object is locked and can't be freed.");
-#endif
-
- //must be here, must be before everything,
- memdelete(this);
- return;
- }
-
- //Variant ret;
- OBJ_DEBUG_LOCK
-
- Callable::CallError error;
-
- if (script_instance) {
- script_instance->call_multilevel(p_method, p_args, p_argcount);
- //_test_call_error(p_method,error);
- }
-
- MethodBind *method = ClassDB::get_method(get_class_name(), p_method);
-
- if (method) {
- method->call(this, p_args, p_argcount, error);
- _test_call_error(p_method, error);
- }
-}
-
-void Object::call_multilevel_reversed(const StringName &p_method, const Variant **p_args, int p_argcount) {
- MethodBind *method = ClassDB::get_method(get_class_name(), p_method);
-
- Callable::CallError error;
- OBJ_DEBUG_LOCK
-
- if (method) {
- method->call(this, p_args, p_argcount, error);
- _test_call_error(p_method, error);
- }
-
- //Variant ret;
-
- if (script_instance) {
- script_instance->call_multilevel_reversed(p_method, p_args, p_argcount);
- //_test_call_error(p_method,error);
- }
-}
-
bool Object::has_method(const StringName &p_method) const {
if (p_method == CoreStringNames::get_singleton()->_free) {
return true;
@@ -776,6 +678,10 @@ Variant Object::getvar(const Variant &p_key, bool *r_valid) const {
if (r_valid) {
*r_valid = false;
}
+
+ if (p_key.get_type() == Variant::STRING_NAME || p_key.get_type() == Variant::STRING) {
+ return get(p_key, r_valid);
+ }
return Variant();
}
@@ -783,6 +689,9 @@ void Object::setvar(const Variant &p_key, const Variant &p_value, bool *r_valid)
if (r_valid) {
*r_valid = false;
}
+ if (p_key.get_type() == Variant::STRING_NAME || p_key.get_type() == Variant::STRING) {
+ return set(p_key, p_value, r_valid);
+ }
}
Variant Object::callv(const StringName &p_method, const Array &p_args) {
@@ -820,21 +729,6 @@ Variant Object::call(const StringName &p_name, VARIANT_ARG_DECLARE) {
return ret;
}
-void Object::call_multilevel(const StringName &p_name, 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++;
- }
-
- //Callable::CallError error;
- call_multilevel(p_name, argptr, argc);
-}
-
Variant Object::call(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
r_error.error = Callable::CallError::CALL_OK;
@@ -1408,9 +1302,10 @@ Error Object::connect(const StringName &p_signal, const Callable &p_callable, co
Callable target = p_callable;
- if (s->slot_map.has(target)) {
+ //compare with the base callable, so binds can be ignored
+ if (s->slot_map.has(*target.get_base_comparator())) {
if (p_flags & CONNECT_REFERENCE_COUNTED) {
- s->slot_map[target].reference_count++;
+ s->slot_map[*target.get_base_comparator()].reference_count++;
return OK;
} else {
ERR_FAIL_V_MSG(ERR_INVALID_PARAMETER, "Signal '" + p_signal + "' is already connected to given callable '" + p_callable + "' in that object.");
@@ -1430,7 +1325,8 @@ Error Object::connect(const StringName &p_signal, const Callable &p_callable, co
slot.reference_count = 1;
}
- s->slot_map[target] = slot;
+ //use callable version as key, so binds can be ignored
+ s->slot_map[*target.get_base_comparator()] = slot;
return OK;
}
@@ -1457,7 +1353,7 @@ bool Object::is_connected(const StringName &p_signal, const Callable &p_callable
Callable target = p_callable;
- return s->slot_map.has(target);
+ return s->slot_map.has(*target.get_base_comparator());
//const Map<Signal::Target,Signal::Slot>::Element *E = s->slot_map.find(target);
//return (E!=nullptr );
}
@@ -1479,7 +1375,7 @@ void Object::_disconnect(const StringName &p_signal, const Callable &p_callable,
SignalData *s = signal_map.getptr(p_signal);
ERR_FAIL_COND_MSG(!s, vformat("Nonexistent signal '%s' in %s.", p_signal, to_string()));
- ERR_FAIL_COND_MSG(!s->slot_map.has(p_callable), "Disconnecting nonexistent signal '" + p_signal + "', callable: " + p_callable + ".");
+ ERR_FAIL_COND_MSG(!s->slot_map.has(*p_callable.get_base_comparator()), "Disconnecting nonexistent signal '" + p_signal + "', callable: " + p_callable + ".");
SignalData::Slot *slot = &s->slot_map[p_callable];
@@ -1491,7 +1387,7 @@ void Object::_disconnect(const StringName &p_signal, const Callable &p_callable,
}
target_object->connections.erase(slot->cE);
- s->slot_map.erase(p_callable);
+ s->slot_map.erase(*p_callable.get_base_comparator());
if (s->slot_map.empty() && ClassDB::has_signal(get_class_name(), p_signal)) {
//not user signal, delete
@@ -1525,12 +1421,22 @@ void Object::initialize_class() {
initialized = true;
}
-StringName Object::tr(const StringName &p_message) const {
+String Object::tr(const StringName &p_message, const StringName &p_context) const {
if (!_can_translate || !TranslationServer::get_singleton()) {
return p_message;
}
+ return TranslationServer::get_singleton()->translate(p_message, p_context);
+}
- return TranslationServer::get_singleton()->translate(p_message);
+String Object::tr_n(const StringName &p_message, const StringName &p_message_plural, int p_n, const StringName &p_context) const {
+ if (!_can_translate || !TranslationServer::get_singleton()) {
+ // Return message based on English plural rule if translation is not possible.
+ if (p_n == 1) {
+ return p_message;
+ }
+ return p_message_plural;
+ }
+ return TranslationServer::get_singleton()->translate_plural(p_message, p_message_plural, p_n, p_context);
}
void Object::_clear_internal_resource_paths(const Variant &p_var) {
@@ -1671,7 +1577,8 @@ void Object::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_message_translation", "enable"), &Object::set_message_translation);
ClassDB::bind_method(D_METHOD("can_translate_messages"), &Object::can_translate_messages);
- ClassDB::bind_method(D_METHOD("tr", "message"), &Object::tr);
+ ClassDB::bind_method(D_METHOD("tr", "message", "context"), &Object::tr, DEFVAL(""));
+ ClassDB::bind_method(D_METHOD("tr_n", "message", "plural_message", "n", "context"), &Object::tr_n, DEFVAL(""));
ClassDB::bind_method(D_METHOD("is_queued_for_deletion"), &Object::is_queued_for_deletion);
@@ -1780,7 +1687,8 @@ Variant::Type Object::get_static_property_type_indexed(const Vector<StringName>
}
Callable::CallError ce;
- Variant check = Variant::construct(t, nullptr, 0, ce);
+ Variant check;
+ Variant::construct(t, check, nullptr, 0, ce);
for (int i = 1; i < p_path.size(); i++) {
if (check.get_type() == Variant::OBJECT || check.get_type() == Variant::DICTIONARY || check.get_type() == Variant::ARRAY) {
@@ -1791,7 +1699,7 @@ Variant::Type Object::get_static_property_type_indexed(const Vector<StringName>
return Variant::NIL;
}
- check = check.get_named(p_path[i], &valid);
+ check = check.get_named(p_path[i], valid);
if (!valid) {
if (r_valid) {
diff --git a/core/object.h b/core/object/object.h
index 5b46a0f93a..0bcfa42e3d 100644
--- a/core/object.h
+++ b/core/object/object.h
@@ -31,15 +31,16 @@
#ifndef OBJECT_H
#define OBJECT_H
-#include "core/hash_map.h"
-#include "core/list.h"
-#include "core/map.h"
-#include "core/object_id.h"
+#include "core/object/object_id.h"
#include "core/os/rw_lock.h"
-#include "core/set.h"
-#include "core/spin_lock.h"
-#include "core/variant.h"
-#include "core/vmap.h"
+#include "core/os/spin_lock.h"
+#include "core/templates/hash_map.h"
+#include "core/templates/list.h"
+#include "core/templates/map.h"
+#include "core/templates/set.h"
+#include "core/templates/vmap.h"
+#include "core/variant/callable_bind.h"
+#include "core/variant/variant.h"
#define VARIANT_ARG_LIST const Variant &p_arg1 = Variant(), const Variant &p_arg2 = Variant(), const Variant &p_arg3 = Variant(), const Variant &p_arg4 = Variant(), const Variant &p_arg5 = Variant()
#define VARIANT_ARG_PASS p_arg1, p_arg2, p_arg3, p_arg4, p_arg5
@@ -97,7 +98,6 @@ enum PropertyHint {
};
enum PropertyUsageFlags {
-
PROPERTY_USAGE_STORAGE = 1,
PROPERTY_USAGE_EDITOR = 2,
PROPERTY_USAGE_NETWORK = 4,
@@ -250,142 +250,142 @@ public: \
\
private:
-#define GDCLASS(m_class, m_inherits) \
-private: \
- void operator=(const m_class &p_rval) {} \
- mutable StringName _class_name; \
- friend class ClassDB; \
- \
-public: \
- virtual String get_class() const { \
- return String(#m_class); \
- } \
- virtual const StringName *_get_class_namev() const { \
- if (!_class_name) { \
- _class_name = get_class_static(); \
- } \
- return &_class_name; \
- } \
- static _FORCE_INLINE_ void *get_class_ptr_static() { \
- static int ptr; \
- return &ptr; \
- } \
- static _FORCE_INLINE_ String get_class_static() { \
- return String(#m_class); \
- } \
- static _FORCE_INLINE_ String get_parent_class_static() { \
- return m_inherits::get_class_static(); \
- } \
- static void get_inheritance_list_static(List<String> *p_inheritance_list) { \
- m_inherits::get_inheritance_list_static(p_inheritance_list); \
- p_inheritance_list->push_back(String(#m_class)); \
- } \
- static String get_category_static() { \
- String category = m_inherits::get_category_static(); \
- if (_get_category != m_inherits::_get_category) { \
- if (category != "") { \
- category += "/"; \
- } \
- category += _get_category(); \
- } \
- return category; \
- } \
- static String inherits_static() { \
- return String(#m_inherits); \
- } \
- virtual bool is_class(const String &p_class) const { return (p_class == (#m_class)) ? true : m_inherits::is_class(p_class); } \
- virtual bool is_class_ptr(void *p_ptr) const { return (p_ptr == get_class_ptr_static()) ? true : m_inherits::is_class_ptr(p_ptr); } \
- \
- static void get_valid_parents_static(List<String> *p_parents) { \
- if (m_class::_get_valid_parents_static != m_inherits::_get_valid_parents_static) { \
- m_class::_get_valid_parents_static(p_parents); \
- } \
- \
- m_inherits::get_valid_parents_static(p_parents); \
- } \
- \
-protected: \
- _FORCE_INLINE_ static void (*_get_bind_methods())() { \
- return &m_class::_bind_methods; \
- } \
- \
-public: \
- static void initialize_class() { \
- static bool initialized = false; \
- if (initialized) { \
- return; \
- } \
- m_inherits::initialize_class(); \
- ClassDB::_add_class<m_class>(); \
- if (m_class::_get_bind_methods() != m_inherits::_get_bind_methods()) { \
- _bind_methods(); \
- } \
- initialized = true; \
- } \
- \
-protected: \
- virtual void _initialize_classv() { \
- initialize_class(); \
- } \
- _FORCE_INLINE_ bool (Object::*_get_get() const)(const StringName &p_name, Variant &) const { \
- return (bool (Object::*)(const StringName &, Variant &) const) & m_class::_get; \
- } \
- virtual bool _getv(const StringName &p_name, Variant &r_ret) const { \
- if (m_class::_get_get() != m_inherits::_get_get()) { \
- if (_get(p_name, r_ret)) { \
- return true; \
- } \
- } \
- return m_inherits::_getv(p_name, r_ret); \
- } \
- _FORCE_INLINE_ bool (Object::*_get_set() const)(const StringName &p_name, const Variant &p_property) { \
- return (bool (Object::*)(const StringName &, const Variant &)) & m_class::_set; \
- } \
- virtual bool _setv(const StringName &p_name, const Variant &p_property) { \
- if (m_inherits::_setv(p_name, p_property)) { \
- return true; \
- } \
- if (m_class::_get_set() != m_inherits::_get_set()) { \
- return _set(p_name, p_property); \
- } \
- return false; \
- } \
- _FORCE_INLINE_ void (Object::*_get_get_property_list() const)(List<PropertyInfo> * p_list) const { \
- return (void (Object::*)(List<PropertyInfo> *) const) & m_class::_get_property_list; \
- } \
- virtual void _get_property_listv(List<PropertyInfo> *p_list, bool p_reversed) const { \
- if (!p_reversed) { \
- m_inherits::_get_property_listv(p_list, p_reversed); \
- } \
- p_list->push_back(PropertyInfo(Variant::NIL, get_class_static(), PROPERTY_HINT_NONE, String(), PROPERTY_USAGE_CATEGORY)); \
- if (!_is_gpl_reversed()) { \
- ClassDB::get_property_list(#m_class, p_list, true, this); \
- } \
- if (m_class::_get_get_property_list() != m_inherits::_get_get_property_list()) { \
- _get_property_list(p_list); \
- } \
- if (_is_gpl_reversed()) { \
- ClassDB::get_property_list(#m_class, p_list, true, this); \
- } \
- if (p_reversed) { \
- m_inherits::_get_property_listv(p_list, p_reversed); \
- } \
- } \
- _FORCE_INLINE_ void (Object::*_get_notification() const)(int) { \
- return (void (Object::*)(int)) & m_class::_notification; \
- } \
- virtual void _notificationv(int p_notification, bool p_reversed) { \
- if (!p_reversed) { \
- m_inherits::_notificationv(p_notification, p_reversed); \
- } \
- if (m_class::_get_notification() != m_inherits::_get_notification()) { \
- _notification(p_notification); \
- } \
- if (p_reversed) { \
- m_inherits::_notificationv(p_notification, p_reversed); \
- } \
- } \
- \
+#define GDCLASS(m_class, m_inherits) \
+private: \
+ void operator=(const m_class &p_rval) {} \
+ mutable StringName _class_name; \
+ friend class ClassDB; \
+ \
+public: \
+ virtual String get_class() const override { \
+ return String(#m_class); \
+ } \
+ virtual const StringName *_get_class_namev() const override { \
+ if (!_class_name) { \
+ _class_name = get_class_static(); \
+ } \
+ return &_class_name; \
+ } \
+ static _FORCE_INLINE_ void *get_class_ptr_static() { \
+ static int ptr; \
+ return &ptr; \
+ } \
+ static _FORCE_INLINE_ String get_class_static() { \
+ return String(#m_class); \
+ } \
+ static _FORCE_INLINE_ String get_parent_class_static() { \
+ return m_inherits::get_class_static(); \
+ } \
+ static void get_inheritance_list_static(List<String> *p_inheritance_list) { \
+ m_inherits::get_inheritance_list_static(p_inheritance_list); \
+ p_inheritance_list->push_back(String(#m_class)); \
+ } \
+ static String get_category_static() { \
+ String category = m_inherits::get_category_static(); \
+ if (_get_category != m_inherits::_get_category) { \
+ if (category != "") { \
+ category += "/"; \
+ } \
+ category += _get_category(); \
+ } \
+ return category; \
+ } \
+ static String inherits_static() { \
+ return String(#m_inherits); \
+ } \
+ virtual bool is_class(const String &p_class) const override { return (p_class == (#m_class)) ? true : m_inherits::is_class(p_class); } \
+ virtual bool is_class_ptr(void *p_ptr) const override { return (p_ptr == get_class_ptr_static()) ? true : m_inherits::is_class_ptr(p_ptr); } \
+ \
+ static void get_valid_parents_static(List<String> *p_parents) { \
+ if (m_class::_get_valid_parents_static != m_inherits::_get_valid_parents_static) { \
+ m_class::_get_valid_parents_static(p_parents); \
+ } \
+ \
+ m_inherits::get_valid_parents_static(p_parents); \
+ } \
+ \
+protected: \
+ _FORCE_INLINE_ static void (*_get_bind_methods())() { \
+ return &m_class::_bind_methods; \
+ } \
+ \
+public: \
+ static void initialize_class() { \
+ static bool initialized = false; \
+ if (initialized) { \
+ return; \
+ } \
+ m_inherits::initialize_class(); \
+ ClassDB::_add_class<m_class>(); \
+ if (m_class::_get_bind_methods() != m_inherits::_get_bind_methods()) { \
+ _bind_methods(); \
+ } \
+ initialized = true; \
+ } \
+ \
+protected: \
+ virtual void _initialize_classv() override { \
+ initialize_class(); \
+ } \
+ _FORCE_INLINE_ bool (Object::*_get_get() const)(const StringName &p_name, Variant &) const { \
+ return (bool (Object::*)(const StringName &, Variant &) const) & m_class::_get; \
+ } \
+ virtual bool _getv(const StringName &p_name, Variant &r_ret) const override { \
+ if (m_class::_get_get() != m_inherits::_get_get()) { \
+ if (_get(p_name, r_ret)) { \
+ return true; \
+ } \
+ } \
+ return m_inherits::_getv(p_name, r_ret); \
+ } \
+ _FORCE_INLINE_ bool (Object::*_get_set() const)(const StringName &p_name, const Variant &p_property) { \
+ return (bool (Object::*)(const StringName &, const Variant &)) & m_class::_set; \
+ } \
+ virtual bool _setv(const StringName &p_name, const Variant &p_property) override { \
+ if (m_inherits::_setv(p_name, p_property)) { \
+ return true; \
+ } \
+ if (m_class::_get_set() != m_inherits::_get_set()) { \
+ return _set(p_name, p_property); \
+ } \
+ return false; \
+ } \
+ _FORCE_INLINE_ void (Object::*_get_get_property_list() const)(List<PropertyInfo> * p_list) const { \
+ return (void (Object::*)(List<PropertyInfo> *) const) & m_class::_get_property_list; \
+ } \
+ virtual void _get_property_listv(List<PropertyInfo> *p_list, bool p_reversed) const override { \
+ if (!p_reversed) { \
+ m_inherits::_get_property_listv(p_list, p_reversed); \
+ } \
+ p_list->push_back(PropertyInfo(Variant::NIL, get_class_static(), PROPERTY_HINT_NONE, String(), PROPERTY_USAGE_CATEGORY)); \
+ if (!_is_gpl_reversed()) { \
+ ClassDB::get_property_list(#m_class, p_list, true, this); \
+ } \
+ if (m_class::_get_get_property_list() != m_inherits::_get_get_property_list()) { \
+ _get_property_list(p_list); \
+ } \
+ if (_is_gpl_reversed()) { \
+ ClassDB::get_property_list(#m_class, p_list, true, this); \
+ } \
+ if (p_reversed) { \
+ m_inherits::_get_property_listv(p_list, p_reversed); \
+ } \
+ } \
+ _FORCE_INLINE_ void (Object::*_get_notification() const)(int) { \
+ return (void (Object::*)(int)) & m_class::_notification; \
+ } \
+ virtual void _notificationv(int p_notification, bool p_reversed) override { \
+ if (!p_reversed) { \
+ m_inherits::_notificationv(p_notification, p_reversed); \
+ } \
+ if (m_class::_get_notification() != m_inherits::_get_notification()) { \
+ _notification(p_notification); \
+ } \
+ if (p_reversed) { \
+ m_inherits::_notificationv(p_notification, p_reversed); \
+ } \
+ } \
+ \
private:
#define OBJ_CATEGORY(m_category) \
@@ -394,10 +394,10 @@ protected: \
\
private:
-#define OBJ_SAVE_TYPE(m_class) \
-public: \
- virtual String get_save_class() const { return #m_class; } \
- \
+#define OBJ_SAVE_TYPE(m_class) \
+public: \
+ virtual String get_save_class() const override { return #m_class; } \
+ \
private:
class ScriptInstance;
@@ -405,7 +405,6 @@ class ScriptInstance;
class Object {
public:
enum ConnectFlags {
-
CONNECT_DEFERRED = 1,
CONNECT_PERSIST = 2, // hint for scene to save this connection
CONNECT_ONESHOT = 4,
@@ -655,13 +654,10 @@ public:
void get_method_list(List<MethodInfo> *p_list) const;
Variant callv(const StringName &p_method, const Array &p_args);
virtual Variant call(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error);
- virtual void call_multilevel(const StringName &p_method, const Variant **p_args, int p_argcount);
- virtual void call_multilevel_reversed(const StringName &p_method, const Variant **p_args, int p_argcount);
Variant call(const StringName &p_name, VARIANT_ARG_LIST); // C++ helper
- void call_multilevel(const StringName &p_name, VARIANT_ARG_LIST); // C++ helper
void notification(int p_notification, bool p_reversed = false);
- String to_string();
+ virtual String to_string();
//used mainly by script, get and set all INCLUDING string
virtual Variant getvar(const Variant &p_key, bool *r_valid = nullptr) const;
@@ -722,7 +718,8 @@ public:
virtual void get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const;
- StringName tr(const StringName &p_message) const; // translate message (internationalization)
+ String tr(const StringName &p_message, const StringName &p_context = "") const; // translate message (internationalization)
+ String tr_n(const StringName &p_message, const StringName &p_message_plural, int p_n, const StringName &p_context = "") const;
bool _is_queued_for_deletion = false; // set to true by SceneTree::queue_delete()
bool is_queued_for_deletion() const;
@@ -813,7 +810,4 @@ public:
static int get_object_count();
};
-//needed by macros
-#include "core/class_db.h"
-
#endif // OBJECT_H
diff --git a/core/object_id.h b/core/object/object_id.h
index 63b0c27af8..63b0c27af8 100644
--- a/core/object_id.h
+++ b/core/object/object_id.h
diff --git a/core/reference.cpp b/core/object/reference.cpp
index d1dba0d9bf..ce95d83dfc 100644
--- a/core/reference.cpp
+++ b/core/object/reference.cpp
@@ -30,7 +30,7 @@
#include "reference.h"
-#include "core/script_language.h"
+#include "core/object/script_language.h"
bool Reference::init_ref() {
if (reference()) {
diff --git a/core/reference.h b/core/object/reference.h
index f5794b0b67..0eb127f362 100644
--- a/core/reference.h
+++ b/core/object/reference.h
@@ -31,9 +31,8 @@
#ifndef REFERENCE_H
#define REFERENCE_H
-#include "core/class_db.h"
-#include "core/object.h"
-#include "core/safe_refcount.h"
+#include "core/object/class_db.h"
+#include "core/templates/safe_refcount.h"
class Reference : public Object {
GDCLASS(Reference, Object);
@@ -253,8 +252,6 @@ public:
WeakRef() {}
};
-#ifdef PTRCALL_ENABLED
-
template <class T>
struct PtrToArg<Ref<T>> {
_FORCE_INLINE_ static Ref<T> convert(const void *p_ptr) {
@@ -273,8 +270,6 @@ struct PtrToArg<const Ref<T> &> {
}
};
-#endif // PTRCALL_ENABLED
-
#ifdef DEBUG_METHODS_ENABLED
template <class T>
diff --git a/core/script_language.cpp b/core/object/script_language.cpp
index 38a970f3c6..17ac75e19f 100644
--- a/core/script_language.cpp
+++ b/core/object/script_language.cpp
@@ -30,10 +30,10 @@
#include "script_language.h"
+#include "core/config/project_settings.h"
#include "core/core_string_names.h"
#include "core/debugger/engine_debugger.h"
#include "core/debugger/script_debugger.h"
-#include "core/project_settings.h"
#include <stdint.h>
@@ -275,7 +275,13 @@ void ScriptServer::save_global_classes() {
gcarr.push_back(d);
}
- ProjectSettings::get_singleton()->set("_global_script_classes", gcarr);
+ if (gcarr.empty()) {
+ if (ProjectSettings::get_singleton()->has_setting("_global_script_classes")) {
+ ProjectSettings::get_singleton()->clear("_global_script_classes");
+ }
+ } else {
+ ProjectSettings::get_singleton()->set("_global_script_classes", gcarr);
+ }
ProjectSettings::get_singleton()->save();
}
@@ -308,16 +314,6 @@ Variant ScriptInstance::call(const StringName &p_method, VARIANT_ARG_DECLARE) {
return call(p_method, argptr, argc, error);
}
-void ScriptInstance::call_multilevel(const StringName &p_method, const Variant **p_args, int p_argcount) {
- Callable::CallError ce;
- call(p_method, p_args, p_argcount, ce); // script may not support multilevel calls
-}
-
-void ScriptInstance::call_multilevel_reversed(const StringName &p_method, const Variant **p_args, int p_argcount) {
- Callable::CallError ce;
- call(p_method, p_args, p_argcount, ce); // script may not support multilevel calls
-}
-
void ScriptInstance::property_set_fallback(const StringName &, const Variant &, bool *r_valid) {
if (r_valid) {
*r_valid = false;
@@ -331,19 +327,6 @@ Variant ScriptInstance::property_get_fallback(const StringName &, bool *r_valid)
return Variant();
}
-void ScriptInstance::call_multilevel(const StringName &p_method, 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++;
- }
-
- call_multilevel(p_method, argptr, argc);
-}
-
ScriptInstance::~ScriptInstance() {
}
@@ -352,6 +335,39 @@ ScriptCodeCompletionCache::ScriptCodeCompletionCache() {
singleton = this;
}
+void ScriptLanguage::get_core_type_words(List<String> *p_core_type_words) const {
+ p_core_type_words->push_back("String");
+ p_core_type_words->push_back("Vector2");
+ p_core_type_words->push_back("Vector2i");
+ p_core_type_words->push_back("Rect2");
+ p_core_type_words->push_back("Rect2i");
+ p_core_type_words->push_back("Vector3");
+ p_core_type_words->push_back("Vector3i");
+ p_core_type_words->push_back("Transform2D");
+ p_core_type_words->push_back("Plane");
+ p_core_type_words->push_back("Quat");
+ p_core_type_words->push_back("AABB");
+ p_core_type_words->push_back("Basis");
+ p_core_type_words->push_back("Transform");
+ p_core_type_words->push_back("Color");
+ p_core_type_words->push_back("StringName");
+ p_core_type_words->push_back("NodePath");
+ p_core_type_words->push_back("RID");
+ p_core_type_words->push_back("Callable");
+ p_core_type_words->push_back("Signal");
+ p_core_type_words->push_back("Dictionary");
+ p_core_type_words->push_back("Array");
+ p_core_type_words->push_back("PackedByteArray");
+ p_core_type_words->push_back("PackedInt32Array");
+ p_core_type_words->push_back("PackedInt64Array");
+ p_core_type_words->push_back("PackedFloat32Array");
+ p_core_type_words->push_back("PackedFloat64Array");
+ p_core_type_words->push_back("PackedStringArray");
+ p_core_type_words->push_back("PackedVector2Array");
+ p_core_type_words->push_back("PackedVector3Array");
+ p_core_type_words->push_back("PackedColorArray");
+}
+
void ScriptLanguage::frame() {
}
diff --git a/core/script_language.h b/core/object/script_language.h
index b6c2a47245..3fd56c2f15 100644
--- a/core/script_language.h
+++ b/core/object/script_language.h
@@ -32,9 +32,9 @@
#define SCRIPT_LANGUAGE_H
#include "core/io/multiplayer_api.h"
-#include "core/map.h"
-#include "core/pair.h"
-#include "core/resource.h"
+#include "core/io/resource.h"
+#include "core/templates/map.h"
+#include "core/templates/pair.h"
class ScriptLanguage;
@@ -57,7 +57,6 @@ struct SortNetData {
class ScriptServer {
enum {
-
MAX_LANGUAGES = 16
};
@@ -116,7 +115,7 @@ class Script : public Resource {
OBJ_SAVE_TYPE(Script);
protected:
- virtual bool editor_can_reload_from_file() { return false; } // this is handled by editor better
+ virtual bool editor_can_reload_from_file() override { return false; } // this is handled by editor better
void _notification(int p_what);
static void _bind_methods();
@@ -199,9 +198,6 @@ public:
virtual bool has_method(const StringName &p_method) const = 0;
virtual Variant call(const StringName &p_method, VARIANT_ARG_LIST);
virtual Variant call(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) = 0;
- virtual void call_multilevel(const StringName &p_method, VARIANT_ARG_LIST);
- virtual void call_multilevel(const StringName &p_method, const Variant **p_args, int p_argcount);
- virtual void call_multilevel_reversed(const StringName &p_method, const Variant **p_args, int p_argcount);
virtual void notification(int p_notification) = 0;
virtual String to_string(bool *r_valid) {
if (r_valid) {
@@ -256,7 +252,9 @@ struct ScriptCodeCompletionOption {
Kind kind = KIND_PLAIN_TEXT;
String display;
String insert_text;
+ Color font_color;
RES icon;
+ Variant default_value;
ScriptCodeCompletionOption() {}
@@ -293,12 +291,14 @@ public:
/* EDITOR FUNCTIONS */
struct Warning {
- int line;
+ int start_line = -1, end_line = -1;
+ int leftmost_column = -1, rightmost_column = -1;
int code;
String string_code;
String message;
};
+ void get_core_type_words(List<String> *p_core_type_words) const;
virtual void get_reserved_words(List<String> *p_words) const = 0;
virtual void get_comment_delimiters(List<String> *p_delimiters) const = 0;
virtual void get_string_delimiters(List<String> *p_delimiters) const = 0;
@@ -425,8 +425,6 @@ public:
r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
return Variant();
}
- //virtual void call_multilevel(const StringName& p_method,VARIANT_ARG_LIST) { return Variant(); }
- //virtual void call_multilevel(const StringName& p_method,const Variant** p_args,int p_argcount,Callable::CallError &r_error) { return Variant(); }
virtual void notification(int p_notification) {}
virtual Ref<Script> get_script() const { return script; }
diff --git a/core/undo_redo.cpp b/core/object/undo_redo.cpp
index 1dcbb0cd6b..1dcbb0cd6b 100644
--- a/core/undo_redo.cpp
+++ b/core/object/undo_redo.cpp
diff --git a/core/undo_redo.h b/core/object/undo_redo.h
index b46f7ff867..68d78e0d7d 100644
--- a/core/undo_redo.h
+++ b/core/object/undo_redo.h
@@ -31,8 +31,8 @@
#ifndef UNDO_REDO_H
#define UNDO_REDO_H
-#include "core/object.h"
-#include "core/resource.h"
+#include "core/io/resource.h"
+#include "core/object/class_db.h"
class UndoRedo : public Object {
GDCLASS(UndoRedo, Object);
diff --git a/core/os/dir_access.cpp b/core/os/dir_access.cpp
index 5e1cb8ea29..30b1b51b53 100644
--- a/core/os/dir_access.cpp
+++ b/core/os/dir_access.cpp
@@ -30,10 +30,10 @@
#include "dir_access.h"
+#include "core/config/project_settings.h"
#include "core/os/file_access.h"
#include "core/os/memory.h"
#include "core/os/os.h"
-#include "core/project_settings.h"
String DirAccess::_get_root_path() const {
switch (_access_type) {
diff --git a/core/os/dir_access.h b/core/os/dir_access.h
index 6bce9a4c12..17f84d3c52 100644
--- a/core/os/dir_access.h
+++ b/core/os/dir_access.h
@@ -31,8 +31,8 @@
#ifndef DIR_ACCESS_H
#define DIR_ACCESS_H
+#include "core/string/ustring.h"
#include "core/typedefs.h"
-#include "core/ustring.h"
//@ TODO, excellent candidate for THREAD_SAFE MACRO, should go through all these and add THREAD_SAFE where it applies
class DirAccess {
@@ -57,7 +57,6 @@ protected:
String _get_root_string() const;
String fix_path(String p_path) const;
- bool next_is_dir;
template <class T>
static DirAccess *_create_builtin() {
diff --git a/core/os/file_access.cpp b/core/os/file_access.cpp
index 20b3435911..b962f61e1f 100644
--- a/core/os/file_access.cpp
+++ b/core/os/file_access.cpp
@@ -30,11 +30,11 @@
#include "file_access.h"
+#include "core/config/project_settings.h"
#include "core/crypto/crypto_core.h"
#include "core/io/file_access_pack.h"
#include "core/io/marshalls.h"
#include "core/os/os.h"
-#include "core/project_settings.h"
FileAccess::CreateFunc FileAccess::create_func[ACCESS_MAX] = { nullptr, nullptr };
@@ -51,7 +51,7 @@ FileAccess *FileAccess::create(AccessType p_access) {
}
bool FileAccess::exists(const String &p_name) {
- if (PackedData::get_singleton() && PackedData::get_singleton()->has_path(p_name)) {
+ if (PackedData::get_singleton() && !PackedData::get_singleton()->is_disabled() && PackedData::get_singleton()->has_path(p_name)) {
return true;
}
@@ -234,7 +234,7 @@ double FileAccess::get_double() const {
String FileAccess::get_token() const {
CharString token;
- CharType c = get_8();
+ char32_t c = get_8();
while (!eof_reached()) {
if (c <= ' ') {
@@ -254,8 +254,8 @@ class CharBuffer {
Vector<char> vector;
char stack_buffer[256];
- char *buffer;
- int capacity;
+ char *buffer = nullptr;
+ int capacity = 0;
int written = 0;
bool grow() {
@@ -299,7 +299,7 @@ public:
String FileAccess::get_line() const {
CharBuffer line;
- CharType c = get_8();
+ char32_t c = get_8();
while (!eof_reached()) {
if (c == '\n' || c == '\0') {
@@ -342,8 +342,8 @@ Vector<String> FileAccess::get_csv_line(const String &p_delim) const {
bool in_quote = false;
String current;
for (int i = 0; i < l.length(); i++) {
- CharType c = l[i];
- CharType s[2] = { 0, 0 };
+ char32_t c = l[i];
+ char32_t s[2] = { 0, 0 };
if (!in_quote && c == p_delim[0]) {
strings.push_back(current);
@@ -456,7 +456,7 @@ void FileAccess::store_double(double p_dest) {
}
uint64_t FileAccess::get_modified_time(const String &p_file) {
- if (PackedData::get_singleton() && !PackedData::get_singleton()->is_disabled() && PackedData::get_singleton()->has_path(p_file)) {
+ if (PackedData::get_singleton() && !PackedData::get_singleton()->is_disabled() && (PackedData::get_singleton()->has_path(p_file) || PackedData::get_singleton()->has_directory(p_file))) {
return 0;
}
@@ -469,7 +469,7 @@ uint64_t FileAccess::get_modified_time(const String &p_file) {
}
uint32_t FileAccess::get_unix_permissions(const String &p_file) {
- if (PackedData::get_singleton() && !PackedData::get_singleton()->is_disabled() && PackedData::get_singleton()->has_path(p_file)) {
+ if (PackedData::get_singleton() && !PackedData::get_singleton()->is_disabled() && (PackedData::get_singleton()->has_path(p_file) || PackedData::get_singleton()->has_directory(p_file))) {
return 0;
}
@@ -482,6 +482,10 @@ uint32_t FileAccess::get_unix_permissions(const String &p_file) {
}
Error FileAccess::set_unix_permissions(const String &p_file, uint32_t p_permissions) {
+ if (PackedData::get_singleton() && !PackedData::get_singleton()->is_disabled() && (PackedData::get_singleton()->has_path(p_file) || PackedData::get_singleton()->has_directory(p_file))) {
+ return ERR_UNAVAILABLE;
+ }
+
FileAccess *fa = create_for_path(p_file);
ERR_FAIL_COND_V_MSG(!fa, ERR_CANT_CREATE, "Cannot create FileAccess for path '" + p_file + "'.");
diff --git a/core/os/file_access.h b/core/os/file_access.h
index 48b9ee4269..777c82bbd7 100644
--- a/core/os/file_access.h
+++ b/core/os/file_access.h
@@ -33,8 +33,8 @@
#include "core/math/math_defs.h"
#include "core/os/memory.h"
+#include "core/string/ustring.h"
#include "core/typedefs.h"
-#include "core/ustring.h"
/**
* Multi-Platform abstraction for accessing to files.
@@ -81,7 +81,6 @@ public:
virtual void _set_access_type(AccessType p_access);
enum ModeFlags {
-
READ = 1,
WRITE = 2,
READ_WRITE = 3,
diff --git a/core/os/keyboard.cpp b/core/os/keyboard.cpp
index d088151a6d..ef341987dc 100644
--- a/core/os/keyboard.cpp
+++ b/core/os/keyboard.cpp
@@ -38,7 +38,6 @@ struct _KeyCodeText {
};
static const _KeyCodeText _keycodes[] = {
-
/* clang-format off */
{KEY_ESCAPE ,"Escape"},
{KEY_TAB ,"Tab"},
diff --git a/core/os/keyboard.h b/core/os/keyboard.h
index 5d11e6a378..67c60a2dbe 100644
--- a/core/os/keyboard.h
+++ b/core/os/keyboard.h
@@ -31,7 +31,7 @@
#ifndef KEYBOARD_H
#define KEYBOARD_H
-#include "core/ustring.h"
+#include "core/string/ustring.h"
/*
Special Key:
@@ -294,11 +294,9 @@ enum KeyList {
KEY_DIVISION = 0x00F7,
KEY_YDIAERESIS = 0x00FF,
-
};
enum KeyModifierMask {
-
KEY_CODE_MASK = ((1 << 25) - 1), ///< Apply this mask to any keycode to remove modifiers.
KEY_MODIFIER_MASK = (0xFF << 24), ///< Apply this mask to isolate modifiers.
KEY_MASK_SHIFT = (1 << 25),
@@ -314,7 +312,6 @@ enum KeyModifierMask {
KEY_MASK_KPAD = (1 << 29),
KEY_MASK_GROUP_SWITCH = (1 << 30)
// bit 31 can't be used because variant uses regular 32 bits int as datatype
-
};
String keycode_get_string(uint32_t p_code);
diff --git a/core/os/main_loop.cpp b/core/os/main_loop.cpp
index 434f6fa300..d29bcd011f 100644
--- a/core/os/main_loop.cpp
+++ b/core/os/main_loop.cpp
@@ -30,14 +30,9 @@
#include "main_loop.h"
-#include "core/script_language.h"
+#include "core/object/script_language.h"
void MainLoop::_bind_methods() {
- ClassDB::bind_method(D_METHOD("init"), &MainLoop::init);
- ClassDB::bind_method(D_METHOD("iteration", "delta"), &MainLoop::iteration);
- ClassDB::bind_method(D_METHOD("idle", "delta"), &MainLoop::idle);
- ClassDB::bind_method(D_METHOD("finish"), &MainLoop::finish);
-
BIND_VMETHOD(MethodInfo("_initialize"));
BIND_VMETHOD(MethodInfo(Variant::BOOL, "_iteration", PropertyInfo(Variant::FLOAT, "delta")));
BIND_VMETHOD(MethodInfo(Variant::BOOL, "_idle", PropertyInfo(Variant::FLOAT, "delta")));
diff --git a/core/os/main_loop.h b/core/os/main_loop.h
index 2c34cf193c..8c46ad9b6a 100644
--- a/core/os/main_loop.h
+++ b/core/os/main_loop.h
@@ -32,8 +32,8 @@
#define MAIN_LOOP_H
#include "core/input/input_event.h"
-#include "core/reference.h"
-#include "core/script_language.h"
+#include "core/object/reference.h"
+#include "core/object/script_language.h"
class MainLoop : public Object {
GDCLASS(MainLoop, Object);
diff --git a/core/os/memory.cpp b/core/os/memory.cpp
index 8457c52092..f2723d13f6 100644
--- a/core/os/memory.cpp
+++ b/core/os/memory.cpp
@@ -30,9 +30,9 @@
#include "memory.h"
-#include "core/error_macros.h"
+#include "core/error/error_macros.h"
#include "core/os/copymem.h"
-#include "core/safe_refcount.h"
+#include "core/templates/safe_refcount.h"
#include <stdio.h>
#include <stdlib.h>
diff --git a/core/os/memory.h b/core/os/memory.h
index 46ffb4124b..dee08d4de4 100644
--- a/core/os/memory.h
+++ b/core/os/memory.h
@@ -31,8 +31,8 @@
#ifndef MEMORY_H
#define MEMORY_H
-#include "core/error_macros.h"
-#include "core/safe_refcount.h"
+#include "core/error/error_macros.h"
+#include "core/templates/safe_refcount.h"
#include <stddef.h>
diff --git a/core/os/midi_driver.h b/core/os/midi_driver.h
index bc922e1fcf..f487b31d4c 100644
--- a/core/os/midi_driver.h
+++ b/core/os/midi_driver.h
@@ -32,7 +32,7 @@
#define MIDI_DRIVER_H
#include "core/typedefs.h"
-#include "core/variant.h"
+#include "core/variant/variant.h"
/**
* Multi-Platform abstraction for accessing to MIDI.
diff --git a/core/os/mutex.h b/core/os/mutex.h
index d42cbed821..778bdaba09 100644
--- a/core/os/mutex.h
+++ b/core/os/mutex.h
@@ -31,7 +31,7 @@
#ifndef MUTEX_H
#define MUTEX_H
-#include "core/error_list.h"
+#include "core/error/error_list.h"
#include "core/typedefs.h"
#if !defined(NO_THREADS)
diff --git a/core/os/os.cpp b/core/os/os.cpp
index 231069fcfb..552bf043bf 100644
--- a/core/os/os.cpp
+++ b/core/os/os.cpp
@@ -30,11 +30,11 @@
#include "os.h"
+#include "core/config/project_settings.h"
#include "core/input/input.h"
#include "core/os/dir_access.h"
#include "core/os/file_access.h"
#include "core/os/midi_driver.h"
-#include "core/project_settings.h"
#include "core/version_generated.gen.h"
#include "servers/audio_server.h"
@@ -80,10 +80,6 @@ String OS::get_iso_date_time(bool local) const {
timezone;
}
-uint64_t OS::get_splash_tick_msec() const {
- return _msec_splash;
-}
-
double OS::get_unix_time() const {
return 0;
}
@@ -163,6 +159,10 @@ bool OS::is_stdout_verbose() const {
return _verbose_stdout;
}
+bool OS::is_stdout_debug_enabled() const {
+ return _debug_stdout;
+}
+
void OS::dump_memory_to_file(const char *p_file) {
//Memory::dump_static_mem_to_file(p_file);
}
diff --git a/core/os/os.h b/core/os/os.h
index f21c0d4df7..40104b479b 100644
--- a/core/os/os.h
+++ b/core/os/os.h
@@ -31,13 +31,13 @@
#ifndef OS_H
#define OS_H
-#include "core/engine.h"
-#include "core/image.h"
+#include "core/config/engine.h"
+#include "core/io/image.h"
#include "core/io/logger.h"
-#include "core/list.h"
#include "core/os/main_loop.h"
-#include "core/ustring.h"
-#include "core/vector.h"
+#include "core/string/ustring.h"
+#include "core/templates/list.h"
+#include "core/templates/vector.h"
#include <stdarg.h>
@@ -50,8 +50,8 @@ class OS {
bool low_processor_usage_mode = false;
int low_processor_usage_mode_sleep_usec = 10000;
bool _verbose_stdout = false;
+ bool _debug_stdout = false;
String _local_clipboard;
- uint64_t _msec_splash;
bool _no_window = false;
int _exit_code = 0;
int _orientation;
@@ -77,7 +77,6 @@ public:
typedef bool (*HasServerFeatureCallback)(const String &p_feature);
enum RenderThreadMode {
-
RENDER_THREAD_UNSAFE,
RENDER_THREAD_SAFE,
RENDER_SEPARATE_THREAD
@@ -85,11 +84,13 @@ public:
protected:
friend class Main;
+ // Needed by tests to setup command-line args.
+ friend int test_main(int argc, char *argv[]);
HasServerFeatureCallback has_server_feature_callback = nullptr;
RenderThreadMode _render_thread_mode = RENDER_THREAD_SAFE;
- // functions used by main to initialize/deinitialize the OS
+ // Functions used by Main to initialize/deinitialize the OS.
void add_logger(Logger *p_logger);
virtual void initialize() = 0;
@@ -217,11 +218,11 @@ public:
virtual uint64_t get_ticks_usec() const = 0;
uint32_t get_ticks_msec() const;
- uint64_t get_splash_tick_msec() const;
virtual bool is_userfs_persistent() const { return true; }
bool is_stdout_verbose() const;
+ bool is_stdout_debug_enabled() const;
virtual void disable_crash_handler() {}
virtual bool is_disable_crash_handler() const { return false; }
diff --git a/core/pool_allocator.cpp b/core/os/pool_allocator.cpp
index b222c20a00..52536ff45d 100644
--- a/core/pool_allocator.cpp
+++ b/core/os/pool_allocator.cpp
@@ -30,11 +30,11 @@
#include "pool_allocator.h"
-#include "core/error_macros.h"
+#include "core/error/error_macros.h"
#include "core/os/copymem.h"
#include "core/os/memory.h"
#include "core/os/os.h"
-#include "core/print_string.h"
+#include "core/string/print_string.h"
#include <assert.h>
diff --git a/core/pool_allocator.h b/core/os/pool_allocator.h
index 7d77af6266..c67b4d7fa2 100644
--- a/core/pool_allocator.h
+++ b/core/os/pool_allocator.h
@@ -43,7 +43,6 @@
*/
enum {
-
POOL_ALLOCATOR_INVALID_ID = -1 ///< default invalid value. use INVALID_ID( id ) to test
};
diff --git a/core/os/rw_lock.cpp b/core/os/rw_lock.cpp
index a668fe2b4c..669f05c6b0 100644
--- a/core/os/rw_lock.cpp
+++ b/core/os/rw_lock.cpp
@@ -30,7 +30,7 @@
#include "rw_lock.h"
-#include "core/error_macros.h"
+#include "core/error/error_macros.h"
#include <stddef.h>
diff --git a/core/os/rw_lock.h b/core/os/rw_lock.h
index 1035072cce..1190102a83 100644
--- a/core/os/rw_lock.h
+++ b/core/os/rw_lock.h
@@ -31,7 +31,7 @@
#ifndef RW_LOCK_H
#define RW_LOCK_H
-#include "core/error_list.h"
+#include "core/error/error_list.h"
class RWLock {
protected:
diff --git a/core/os/semaphore.h b/core/os/semaphore.h
index 077e04704b..b170cada3a 100644
--- a/core/os/semaphore.h
+++ b/core/os/semaphore.h
@@ -31,7 +31,7 @@
#ifndef SEMAPHORE_H
#define SEMAPHORE_H
-#include "core/error_list.h"
+#include "core/error/error_list.h"
#include "core/typedefs.h"
#if !defined(NO_THREADS)
diff --git a/core/spin_lock.h b/core/os/spin_lock.h
index 1bb810bb29..1bb810bb29 100644
--- a/core/spin_lock.h
+++ b/core/os/spin_lock.h
diff --git a/core/os/thread.h b/core/os/thread.h
index f761d4ca43..b87ec84313 100644
--- a/core/os/thread.h
+++ b/core/os/thread.h
@@ -31,15 +31,14 @@
#ifndef THREAD_H
#define THREAD_H
+#include "core/string/ustring.h"
#include "core/typedefs.h"
-#include "core/ustring.h"
typedef void (*ThreadCreateCallback)(void *p_userdata);
class Thread {
public:
enum Priority {
-
PRIORITY_LOW,
PRIORITY_NORMAL,
PRIORITY_HIGH
diff --git a/core/os/threaded_array_processor.h b/core/os/threaded_array_processor.h
index d27399e4cc..ed141a5339 100644
--- a/core/os/threaded_array_processor.h
+++ b/core/os/threaded_array_processor.h
@@ -35,7 +35,7 @@
#include "core/os/os.h"
#include "core/os/thread.h"
#include "core/os/thread_safe.h"
-#include "core/safe_refcount.h"
+#include "core/templates/safe_refcount.h"
template <class C, class U>
struct ThreadArrayProcessData {
diff --git a/core/register_core_types.cpp b/core/register_core_types.cpp
index 5dac42cacb..7e32f215e7 100644
--- a/core/register_core_types.cpp
+++ b/core/register_core_types.cpp
@@ -30,24 +30,24 @@
#include "register_core_types.h"
-#include "core/bind/core_bind.h"
-#include "core/class_db.h"
-#include "core/compressed_translation.h"
+#include "core/config/engine.h"
+#include "core/config/project_settings.h"
+#include "core/core_bind.h"
#include "core/core_string_names.h"
#include "core/crypto/aes_context.h"
#include "core/crypto/crypto.h"
#include "core/crypto/hashing_context.h"
-#include "core/engine.h"
-#include "core/func_ref.h"
#include "core/input/input.h"
#include "core/input/input_map.h"
#include "core/io/config_file.h"
#include "core/io/dtls_server.h"
#include "core/io/http_client.h"
#include "core/io/image_loader.h"
+#include "core/io/json.h"
#include "core/io/marshalls.h"
#include "core/io/multiplayer_api.h"
#include "core/io/networked_multiplayer_peer.h"
+#include "core/io/packed_data_container.h"
#include "core/io/packet_peer.h"
#include "core/io/packet_peer_dtls.h"
#include "core/io/packet_peer_udp.h"
@@ -65,11 +65,11 @@
#include "core/math/geometry_3d.h"
#include "core/math/random_number_generator.h"
#include "core/math/triangle_mesh.h"
+#include "core/object/class_db.h"
+#include "core/object/undo_redo.h"
#include "core/os/main_loop.h"
-#include "core/packed_data_container.h"
-#include "core/project_settings.h"
-#include "core/translation.h"
-#include "core/undo_redo.h"
+#include "core/string/compressed_translation.h"
+#include "core/string/translation.h"
static Ref<ResourceFormatSaverBinary> resource_saver_binary;
static Ref<ResourceFormatLoaderBinary> resource_loader_binary;
@@ -86,6 +86,7 @@ static _Engine *_engine = nullptr;
static _ClassDB *_classdb = nullptr;
static _Marshalls *_marshalls = nullptr;
static _JSON *_json = nullptr;
+static _EngineDebugger *_engine_debugger = nullptr;
static IP *ip = nullptr;
@@ -96,8 +97,6 @@ extern Mutex _global_mutex;
extern void register_global_constants();
extern void unregister_global_constants();
-extern void register_variant_methods();
-extern void unregister_variant_methods();
void register_core_types() {
//consistency check
@@ -110,7 +109,8 @@ void register_core_types() {
ResourceLoader::initialize();
register_global_constants();
- register_variant_methods();
+
+ Variant::register_types();
CoreStringNames::create();
@@ -154,7 +154,6 @@ void register_core_types() {
ClassDB::register_class<InputEventPanGesture>();
ClassDB::register_class<InputEventMIDI>();
- ClassDB::register_class<FuncRef>();
ClassDB::register_virtual_class<StreamPeer>();
ClassDB::register_class<StreamPeerBuffer>();
ClassDB::register_class<StreamPeerTCP>();
@@ -199,6 +198,7 @@ void register_core_types() {
ClassDB::register_class<_Semaphore>();
ClassDB::register_class<XMLParser>();
+ ClassDB::register_class<JSONParser>();
ClassDB::register_class<ConfigFile>();
@@ -227,10 +227,11 @@ void register_core_types() {
_classdb = memnew(_ClassDB);
_marshalls = memnew(_Marshalls);
_json = memnew(_JSON);
+ _engine_debugger = memnew(_EngineDebugger);
}
void register_core_settings() {
- //since in register core types, globals may not e present
+ // Since in register core types, globals may not be present.
GLOBAL_DEF("network/limits/tcp/connect_timeout_seconds", (30));
ProjectSettings::get_singleton()->set_custom_property_info("network/limits/tcp/connect_timeout_seconds", PropertyInfo(Variant::INT, "network/limits/tcp/connect_timeout_seconds", PROPERTY_HINT_RANGE, "1,1800,1"));
GLOBAL_DEF_RST("network/limits/packet_peer_stream/max_buffer_po2", (16));
@@ -256,6 +257,7 @@ void register_core_singletons() {
ClassDB::register_class<InputMap>();
ClassDB::register_class<_JSON>();
ClassDB::register_class<Expression>();
+ ClassDB::register_class<_EngineDebugger>();
Engine::get_singleton()->add_singleton(Engine::Singleton("ProjectSettings", ProjectSettings::get_singleton()));
Engine::get_singleton()->add_singleton(Engine::Singleton("IP", IP::get_singleton()));
@@ -271,6 +273,7 @@ void register_core_singletons() {
Engine::get_singleton()->add_singleton(Engine::Singleton("Input", Input::get_singleton()));
Engine::get_singleton()->add_singleton(Engine::Singleton("InputMap", InputMap::get_singleton()));
Engine::get_singleton()->add_singleton(Engine::Singleton("JSON", _JSON::get_singleton()));
+ Engine::get_singleton()->add_singleton(Engine::Singleton("EngineDebugger", _EngineDebugger::get_singleton()));
}
void unregister_core_types() {
@@ -281,6 +284,7 @@ void unregister_core_types() {
memdelete(_classdb);
memdelete(_marshalls);
memdelete(_json);
+ memdelete(_engine_debugger);
memdelete(_geometry_2d);
memdelete(_geometry_3d);
@@ -314,7 +318,8 @@ void unregister_core_types() {
ClassDB::cleanup_defaults();
ObjectDB::cleanup();
- unregister_variant_methods();
+ Variant::unregister_types();
+
unregister_global_constants();
ClassDB::cleanup();
diff --git a/core/string/SCsub b/core/string/SCsub
new file mode 100644
index 0000000000..3217166f18
--- /dev/null
+++ b/core/string/SCsub
@@ -0,0 +1,7 @@
+#!/usr/bin/env python
+
+Import("env")
+
+env_string = env.Clone()
+
+env_string.add_source_files(env.core_sources, "*.cpp")
diff --git a/core/compressed_translation.cpp b/core/string/compressed_translation.cpp
index a66997aa52..bdb296a79b 100644
--- a/core/compressed_translation.cpp
+++ b/core/string/compressed_translation.cpp
@@ -30,7 +30,7 @@
#include "compressed_translation.h"
-#include "core/pair.h"
+#include "core/templates/pair.h"
extern "C" {
#include "thirdparty/misc/smaz.h"
@@ -43,6 +43,8 @@ struct _PHashTranslationCmp {
};
void PHashTranslation::generate(const Ref<Translation> &p_from) {
+ // This method compresses a Translation instance.
+ // Right now it doesn't handle context or plurals, so Translation subclasses using plurals or context (i.e TranslationPO) shouldn't be compressed.
#ifdef TOOLS_ENABLED
List<StringName> keys;
p_from->get_message_list(&keys);
@@ -212,7 +214,9 @@ bool PHashTranslation::_get(const StringName &p_name, Variant &r_ret) const {
return true;
}
-StringName PHashTranslation::get_message(const StringName &p_src_text) const {
+StringName PHashTranslation::get_message(const StringName &p_src_text, const StringName &p_context) const {
+ // p_context passed in is ignore. The use of context is not yet supported in PHashTranslation.
+
int htsize = hash_table.size();
if (htsize == 0) {
@@ -267,6 +271,11 @@ StringName PHashTranslation::get_message(const StringName &p_src_text) const {
}
}
+StringName PHashTranslation::get_plural_message(const StringName &p_src_text, const StringName &p_plural_text, int p_n, const StringName &p_context) const {
+ // The use of plurals translation is not yet supported in PHashTranslation.
+ return get_message(p_src_text, p_context);
+}
+
void PHashTranslation::_get_property_list(List<PropertyInfo> *p_list) const {
p_list->push_back(PropertyInfo(Variant::PACKED_INT32_ARRAY, "hash_table"));
p_list->push_back(PropertyInfo(Variant::PACKED_INT32_ARRAY, "bucket_table"));
diff --git a/core/compressed_translation.h b/core/string/compressed_translation.h
index 3c029bdf58..efb3535362 100644
--- a/core/compressed_translation.h
+++ b/core/string/compressed_translation.h
@@ -31,7 +31,7 @@
#ifndef COMPRESSED_TRANSLATION_H
#define COMPRESSED_TRANSLATION_H
-#include "core/translation.h"
+#include "core/string/translation.h"
class PHashTranslation : public Translation {
GDCLASS(PHashTranslation, Translation);
@@ -79,7 +79,8 @@ protected:
static void _bind_methods();
public:
- virtual StringName get_message(const StringName &p_src_text) const; //overridable for other implementations
+ virtual StringName get_message(const StringName &p_src_text, const StringName &p_context = "") const override; //overridable for other implementations
+ virtual StringName get_plural_message(const StringName &p_src_text, const StringName &p_plural_text, int p_n, const StringName &p_context = "") const override;
void generate(const Ref<Translation> &p_from);
PHashTranslation() {}
diff --git a/core/node_path.cpp b/core/string/node_path.cpp
index 2a51dca74a..4d152d9258 100644
--- a/core/node_path.cpp
+++ b/core/string/node_path.cpp
@@ -30,7 +30,7 @@
#include "node_path.h"
-#include "core/print_string.h"
+#include "core/string/print_string.h"
void NodePath::_update_hash_cache() const {
uint32_t h = data->absolute ? 1 : 0;
diff --git a/core/node_path.h b/core/string/node_path.h
index 7c06bf01ce..b4513ddb3c 100644
--- a/core/node_path.h
+++ b/core/string/node_path.h
@@ -31,8 +31,8 @@
#ifndef NODE_PATH_H
#define NODE_PATH_H
-#include "core/string_name.h"
-#include "core/ustring.h"
+#include "core/string/string_name.h"
+#include "core/string/ustring.h"
class NodePath {
struct Data {
diff --git a/core/print_string.cpp b/core/string/print_string.cpp
index 54de229471..54de229471 100644
--- a/core/print_string.cpp
+++ b/core/string/print_string.cpp
diff --git a/core/print_string.h b/core/string/print_string.h
index 4d03f4a6de..3e8f244cc5 100644
--- a/core/print_string.h
+++ b/core/string/print_string.h
@@ -31,7 +31,7 @@
#ifndef PRINT_STRING_H
#define PRINT_STRING_H
-#include "core/ustring.h"
+#include "core/string/ustring.h"
extern void (*_print_func)(String);
diff --git a/core/string_buffer.h b/core/string/string_buffer.h
index 956a6333d9..1317b538d4 100644
--- a/core/string_buffer.h
+++ b/core/string/string_buffer.h
@@ -31,25 +31,25 @@
#ifndef STRING_BUFFER_H
#define STRING_BUFFER_H
-#include "core/ustring.h"
+#include "core/string/ustring.h"
template <int SHORT_BUFFER_SIZE = 64>
class StringBuffer {
- CharType short_buffer[SHORT_BUFFER_SIZE];
+ char32_t short_buffer[SHORT_BUFFER_SIZE];
String buffer;
int string_length = 0;
- _FORCE_INLINE_ CharType *current_buffer_ptr() {
+ _FORCE_INLINE_ char32_t *current_buffer_ptr() {
return static_cast<String &>(buffer).empty() ? short_buffer : buffer.ptrw();
}
public:
- StringBuffer &append(CharType p_char);
+ StringBuffer &append(char32_t p_char);
StringBuffer &append(const String &p_string);
StringBuffer &append(const char *p_str);
- StringBuffer &append(const CharType *p_str, int p_clip_to_len = -1);
+ StringBuffer &append(const char32_t *p_str, int p_clip_to_len = -1);
- _FORCE_INLINE_ void operator+=(CharType p_char) {
+ _FORCE_INLINE_ void operator+=(char32_t p_char) {
append(p_char);
}
@@ -61,7 +61,7 @@ public:
append(p_str);
}
- _FORCE_INLINE_ void operator+=(const CharType *p_str) {
+ _FORCE_INLINE_ void operator+=(const char32_t *p_str) {
append(p_str);
}
@@ -80,7 +80,7 @@ public:
};
template <int SHORT_BUFFER_SIZE>
-StringBuffer<SHORT_BUFFER_SIZE> &StringBuffer<SHORT_BUFFER_SIZE>::append(CharType p_char) {
+StringBuffer<SHORT_BUFFER_SIZE> &StringBuffer<SHORT_BUFFER_SIZE>::append(char32_t p_char) {
reserve(string_length + 2);
current_buffer_ptr()[string_length++] = p_char;
return *this;
@@ -88,7 +88,7 @@ StringBuffer<SHORT_BUFFER_SIZE> &StringBuffer<SHORT_BUFFER_SIZE>::append(CharTyp
template <int SHORT_BUFFER_SIZE>
StringBuffer<SHORT_BUFFER_SIZE> &StringBuffer<SHORT_BUFFER_SIZE>::append(const String &p_string) {
- return append(p_string.c_str());
+ return append(p_string.get_data());
}
template <int SHORT_BUFFER_SIZE>
@@ -96,7 +96,7 @@ StringBuffer<SHORT_BUFFER_SIZE> &StringBuffer<SHORT_BUFFER_SIZE>::append(const c
int len = strlen(p_str);
reserve(string_length + len + 1);
- CharType *buf = current_buffer_ptr();
+ char32_t *buf = current_buffer_ptr();
for (const char *c_ptr = p_str; *c_ptr; ++c_ptr) {
buf[string_length++] = *c_ptr;
}
@@ -104,13 +104,13 @@ StringBuffer<SHORT_BUFFER_SIZE> &StringBuffer<SHORT_BUFFER_SIZE>::append(const c
}
template <int SHORT_BUFFER_SIZE>
-StringBuffer<SHORT_BUFFER_SIZE> &StringBuffer<SHORT_BUFFER_SIZE>::append(const CharType *p_str, int p_clip_to_len) {
+StringBuffer<SHORT_BUFFER_SIZE> &StringBuffer<SHORT_BUFFER_SIZE>::append(const char32_t *p_str, int p_clip_to_len) {
int len = 0;
while ((p_clip_to_len < 0 || len < p_clip_to_len) && p_str[len]) {
++len;
}
reserve(string_length + len + 1);
- memcpy(&(current_buffer_ptr()[string_length]), p_str, len * sizeof(CharType));
+ memcpy(&(current_buffer_ptr()[string_length]), p_str, len * sizeof(char32_t));
string_length += len;
return *this;
@@ -125,7 +125,7 @@ StringBuffer<SHORT_BUFFER_SIZE> &StringBuffer<SHORT_BUFFER_SIZE>::reserve(int p_
bool need_copy = string_length > 0 && buffer.empty();
buffer.resize(next_power_of_2(p_size));
if (need_copy) {
- memcpy(buffer.ptrw(), short_buffer, string_length * sizeof(CharType));
+ memcpy(buffer.ptrw(), short_buffer, string_length * sizeof(char32_t));
}
return *this;
@@ -150,7 +150,7 @@ String StringBuffer<SHORT_BUFFER_SIZE>::as_string() {
template <int SHORT_BUFFER_SIZE>
double StringBuffer<SHORT_BUFFER_SIZE>::as_double() {
current_buffer_ptr()[string_length] = '\0';
- return String::to_double(current_buffer_ptr());
+ return String::to_float(current_buffer_ptr());
}
template <int SHORT_BUFFER_SIZE>
diff --git a/core/string_builder.cpp b/core/string/string_builder.cpp
index c8d6498f27..dec299ffa3 100644
--- a/core/string_builder.cpp
+++ b/core/string/string_builder.cpp
@@ -61,7 +61,7 @@ String StringBuilder::as_string() const {
return "";
}
- CharType *buffer = memnew_arr(CharType, string_length);
+ char32_t *buffer = memnew_arr(char32_t, string_length);
int current_position = 0;
@@ -73,7 +73,7 @@ String StringBuilder::as_string() const {
// Godot string
const String &s = strings[godot_string_elem];
- memcpy(buffer + current_position, s.ptr(), s.length() * sizeof(CharType));
+ memcpy(buffer + current_position, s.ptr(), s.length() * sizeof(char32_t));
current_position += s.length();
diff --git a/core/string_builder.h b/core/string/string_builder.h
index 2a37d14218..c732f1b9ea 100644
--- a/core/string_builder.h
+++ b/core/string/string_builder.h
@@ -31,8 +31,8 @@
#ifndef STRING_BUILDER_H
#define STRING_BUILDER_H
-#include "core/ustring.h"
-#include "core/vector.h"
+#include "core/string/ustring.h"
+#include "core/templates/vector.h"
class StringBuilder {
uint32_t string_length = 0;
diff --git a/core/string_name.cpp b/core/string/string_name.cpp
index cbf6009681..34afdaee38 100644
--- a/core/string_name.cpp
+++ b/core/string/string_name.cpp
@@ -31,7 +31,7 @@
#include "string_name.h"
#include "core/os/os.h"
-#include "core/print_string.h"
+#include "core/string/print_string.h"
StaticCString StaticCString::create(const char *p_ptr) {
StaticCString scs;
@@ -317,7 +317,7 @@ StringName StringName::search(const char *p_name) {
return StringName(); //does not exist
}
-StringName StringName::search(const CharType *p_name) {
+StringName StringName::search(const char32_t *p_name) {
ERR_FAIL_COND_V(!configured, StringName());
ERR_FAIL_COND_V(!p_name, StringName());
@@ -377,3 +377,17 @@ StringName StringName::search(const String &p_name) {
StringName::~StringName() {
unref();
}
+
+bool operator==(const String &p_name, const StringName &p_string_name) {
+ return p_name == p_string_name.operator String();
+}
+bool operator!=(const String &p_name, const StringName &p_string_name) {
+ return p_name != p_string_name.operator String();
+}
+
+bool operator==(const char *p_name, const StringName &p_string_name) {
+ return p_name == p_string_name.operator String();
+}
+bool operator!=(const char *p_name, const StringName &p_string_name) {
+ return p_name != p_string_name.operator String();
+}
diff --git a/core/string_name.h b/core/string/string_name.h
index df6b458581..320f63bf68 100644
--- a/core/string_name.h
+++ b/core/string/string_name.h
@@ -32,8 +32,10 @@
#define STRING_NAME_H
#include "core/os/mutex.h"
-#include "core/safe_refcount.h"
-#include "core/ustring.h"
+#include "core/string/ustring.h"
+#include "core/templates/safe_refcount.h"
+
+class Main;
struct StaticCString {
const char *ptr;
@@ -42,7 +44,6 @@ struct StaticCString {
class StringName {
enum {
-
STRING_TABLE_BITS = 12,
STRING_TABLE_LEN = 1 << STRING_TABLE_BITS,
STRING_TABLE_MASK = STRING_TABLE_LEN - 1
@@ -73,7 +74,7 @@ class StringName {
void unref();
friend void register_core_types();
friend void unregister_core_types();
-
+ friend class Main;
static Mutex mutex;
static void setup();
static void cleanup();
@@ -120,7 +121,7 @@ public:
}
static StringName search(const char *p_name);
- static StringName search(const CharType *p_name);
+ static StringName search(const char32_t *p_name);
static StringName search(const String &p_name);
struct AlphCompare {
@@ -153,6 +154,11 @@ public:
~StringName();
};
+bool operator==(const String &p_name, const StringName &p_string_name);
+bool operator!=(const String &p_name, const StringName &p_string_name);
+bool operator==(const char *p_name, const StringName &p_string_name);
+bool operator!=(const char *p_name, const StringName &p_string_name);
+
StringName _scs_create(const char *p_chr);
#endif // STRING_NAME_H
diff --git a/core/translation.cpp b/core/string/translation.cpp
index 4f835bd7b4..df8a26e5ce 100644
--- a/core/translation.cpp
+++ b/core/string/translation.cpp
@@ -30,9 +30,9 @@
#include "translation.h"
+#include "core/config/project_settings.h"
#include "core/io/resource_loader.h"
#include "core/os/os.h"
-#include "core/project_settings.h"
// ISO 639-1 language codes, with the addition of glibc locales with their
// regional identifiers. This list must match the language names (in English)
@@ -794,17 +794,12 @@ static const char *locale_renames[][2] = {
///////////////////////////////////////////////
-Vector<String> Translation::_get_messages() const {
- Vector<String> msgs;
- msgs.resize(translation_map.size() * 2);
- int idx = 0;
+Dictionary Translation::_get_messages() const {
+ Dictionary d;
for (const Map<StringName, StringName>::Element *E = translation_map.front(); E; E = E->next()) {
- msgs.set(idx + 0, E->key());
- msgs.set(idx + 1, E->get());
- idx += 2;
+ d[E->key()] = E->value();
}
-
- return msgs;
+ return d;
}
Vector<String> Translation::_get_message_list() const {
@@ -819,14 +814,11 @@ Vector<String> Translation::_get_message_list() const {
return msgs;
}
-void Translation::_set_messages(const Vector<String> &p_messages) {
- int msg_count = p_messages.size();
- ERR_FAIL_COND(msg_count % 2);
-
- const String *r = p_messages.ptr();
-
- for (int i = 0; i < msg_count; i += 2) {
- add_message(r[i + 0], r[i + 1]);
+void Translation::_set_messages(const Dictionary &p_messages) {
+ List<Variant> keys;
+ p_messages.get_key_list(&keys);
+ for (auto E = keys.front(); E; E = E->next()) {
+ translation_map[E->get()] = p_messages[E->get()];
}
}
@@ -848,11 +840,21 @@ void Translation::set_locale(const String &p_locale) {
}
}
-void Translation::add_message(const StringName &p_src_text, const StringName &p_xlated_text) {
+void Translation::add_message(const StringName &p_src_text, const StringName &p_xlated_text, const StringName &p_context) {
translation_map[p_src_text] = p_xlated_text;
}
-StringName Translation::get_message(const StringName &p_src_text) const {
+void Translation::add_plural_message(const StringName &p_src_text, const Vector<String> &p_plural_xlated_texts, const StringName &p_context) {
+ WARN_PRINT("Translation class doesn't handle plural messages. Calling add_plural_message() on a Translation instance is probably a mistake. \nUse a derived Translation class that handles plurals, such as TranslationPO class");
+ ERR_FAIL_COND_MSG(p_plural_xlated_texts.empty(), "Parameter vector p_plural_xlated_texts passed in is empty.");
+ translation_map[p_src_text] = p_plural_xlated_texts[0];
+}
+
+StringName Translation::get_message(const StringName &p_src_text, const StringName &p_context) const {
+ if (p_context != StringName()) {
+ WARN_PRINT("Translation class doesn't handle context. Using context in get_message() on a Translation instance is probably a mistake. \nUse a derived Translation class that handles context, such as TranslationPO class");
+ }
+
const Map<StringName, StringName>::Element *E = translation_map.find(p_src_text);
if (!E) {
return StringName();
@@ -861,7 +863,16 @@ StringName Translation::get_message(const StringName &p_src_text) const {
return E->get();
}
-void Translation::erase_message(const StringName &p_src_text) {
+StringName Translation::get_plural_message(const StringName &p_src_text, const StringName &p_plural_text, int p_n, const StringName &p_context) const {
+ WARN_PRINT("Translation class doesn't handle plural messages. Calling get_plural_message() on a Translation instance is probably a mistake. \nUse a derived Translation class that handles plurals, such as TranslationPO class");
+ return get_message(p_src_text);
+}
+
+void Translation::erase_message(const StringName &p_src_text, const StringName &p_context) {
+ if (p_context != StringName()) {
+ WARN_PRINT("Translation class doesn't handle context. Using context in erase_message() on a Translation instance is probably a mistake. \nUse a derived Translation class that handles context, such as TranslationPO class");
+ }
+
translation_map.erase(p_src_text);
}
@@ -878,15 +889,17 @@ int Translation::get_message_count() const {
void Translation::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_locale", "locale"), &Translation::set_locale);
ClassDB::bind_method(D_METHOD("get_locale"), &Translation::get_locale);
- ClassDB::bind_method(D_METHOD("add_message", "src_message", "xlated_message"), &Translation::add_message);
- ClassDB::bind_method(D_METHOD("get_message", "src_message"), &Translation::get_message);
- ClassDB::bind_method(D_METHOD("erase_message", "src_message"), &Translation::erase_message);
+ ClassDB::bind_method(D_METHOD("add_message", "src_message", "xlated_message", "context"), &Translation::add_message, DEFVAL(""));
+ ClassDB::bind_method(D_METHOD("add_plural_message", "src_message", "xlated_messages", "context"), &Translation::add_plural_message, DEFVAL(""));
+ ClassDB::bind_method(D_METHOD("get_message", "src_message", "context"), &Translation::get_message, DEFVAL(""));
+ ClassDB::bind_method(D_METHOD("get_plural_message", "src_message", "src_plural_message", "n", "context"), &Translation::get_plural_message, DEFVAL(""));
+ ClassDB::bind_method(D_METHOD("erase_message", "src_message", "context"), &Translation::erase_message, DEFVAL(""));
ClassDB::bind_method(D_METHOD("get_message_list"), &Translation::_get_message_list);
ClassDB::bind_method(D_METHOD("get_message_count"), &Translation::get_message_count);
ClassDB::bind_method(D_METHOD("_set_messages"), &Translation::_set_messages);
ClassDB::bind_method(D_METHOD("_get_messages"), &Translation::_get_messages);
- ADD_PROPERTY(PropertyInfo(Variant::PACKED_STRING_ARRAY, "messages", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_messages", "_get_messages");
+ ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "messages", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_messages", "_get_messages");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "locale"), "set_locale", "get_locale");
}
@@ -1020,11 +1033,35 @@ void TranslationServer::remove_translation(const Ref<Translation> &p_translation
translations.erase(p_translation);
}
+Ref<Translation> TranslationServer::get_translation_object(const String &p_locale) {
+ Ref<Translation> res;
+ String lang = get_language_code(p_locale);
+ bool near_match_found = false;
+
+ for (const Set<Ref<Translation>>::Element *E = translations.front(); E; E = E->next()) {
+ const Ref<Translation> &t = E->get();
+ ERR_FAIL_COND_V(t.is_null(), nullptr);
+ String l = t->get_locale();
+
+ // Exact match.
+ if (l == p_locale) {
+ return t;
+ }
+
+ // If near match found, keep that match, but keep looking to try to look for perfect match.
+ if (get_language_code(l) == lang && !near_match_found) {
+ res = t;
+ near_match_found = true;
+ }
+ }
+ return res;
+}
+
void TranslationServer::clear() {
translations.clear();
}
-StringName TranslationServer::translate(const StringName &p_message) const {
+StringName TranslationServer::translate(const StringName &p_message, const StringName &p_context) const {
// Match given message against the translation catalog for the project locale.
if (!enabled) {
@@ -1033,6 +1070,46 @@ StringName TranslationServer::translate(const StringName &p_message) const {
ERR_FAIL_COND_V_MSG(locale.length() < 2, p_message, "Could not translate message as configured locale '" + locale + "' is invalid.");
+ StringName res = _get_message_from_translations(p_message, p_context, locale, false);
+
+ if (!res && fallback.length() >= 2) {
+ res = _get_message_from_translations(p_message, p_context, fallback, false);
+ }
+
+ if (!res) {
+ return p_message;
+ }
+
+ return res;
+}
+
+StringName TranslationServer::translate_plural(const StringName &p_message, const StringName &p_message_plural, int p_n, const StringName &p_context) const {
+ if (!enabled) {
+ if (p_n == 1) {
+ return p_message;
+ }
+ return p_message_plural;
+ }
+
+ ERR_FAIL_COND_V_MSG(locale.length() < 2, p_message, "Could not translate message as configured locale '" + locale + "' is invalid.");
+
+ StringName res = _get_message_from_translations(p_message, p_context, locale, true, p_message_plural, p_n);
+
+ if (!res && fallback.length() >= 2) {
+ res = _get_message_from_translations(p_message, p_context, fallback, true, p_message_plural, p_n);
+ }
+
+ if (!res) {
+ if (p_n == 1) {
+ return p_message;
+ }
+ return p_message_plural;
+ }
+
+ return res;
+}
+
+StringName TranslationServer::_get_message_from_translations(const StringName &p_message, const StringName &p_context, const String &p_locale, bool plural, const String &p_message_plural, int p_n) const {
// Locale can be of the form 'll_CC', i.e. language code and regional code,
// e.g. 'en_US', 'en_GB', etc. It might also be simply 'll', e.g. 'en'.
// To find the relevant translation, we look for those with locale starting
@@ -1044,7 +1121,7 @@ StringName TranslationServer::translate(const StringName &p_message) const {
// logic, so be sure to propagate changes there when changing things here.
StringName res;
- String lang = get_language_code(locale);
+ String lang = get_language_code(p_locale);
bool near_match = false;
for (const Set<Ref<Translation>>::Element *E = translations.front(); E; E = E->next()) {
@@ -1052,7 +1129,7 @@ StringName TranslationServer::translate(const StringName &p_message) const {
ERR_FAIL_COND_V(t.is_null(), p_message);
String l = t->get_locale();
- bool exact_match = (l == locale);
+ bool exact_match = (l == p_locale);
if (!exact_match) {
if (near_match) {
continue; // Only near-match once, but keep looking for exact matches.
@@ -1062,7 +1139,13 @@ StringName TranslationServer::translate(const StringName &p_message) const {
}
}
- StringName r = t->get_message(p_message);
+ StringName r;
+ if (!plural) {
+ r = t->get_message(p_message, p_context);
+ } else {
+ r = t->get_plural_message(p_message, p_message_plural, p_n, p_context);
+ }
+
if (!r) {
continue;
}
@@ -1075,44 +1158,6 @@ StringName TranslationServer::translate(const StringName &p_message) const {
}
}
- if (!res && fallback.length() >= 2) {
- // Try again with the fallback locale.
- String fallback_lang = get_language_code(fallback);
- near_match = false;
-
- for (const Set<Ref<Translation>>::Element *E = translations.front(); E; E = E->next()) {
- const Ref<Translation> &t = E->get();
- ERR_FAIL_COND_V(t.is_null(), p_message);
- String l = t->get_locale();
-
- bool exact_match = (l == fallback);
- if (!exact_match) {
- if (near_match) {
- continue; // Only near-match once, but keep looking for exact matches.
- }
- if (get_language_code(l) != fallback_lang) {
- continue; // Language code does not match.
- }
- }
-
- StringName r = t->get_message(p_message);
- if (!r) {
- continue;
- }
- res = r;
-
- if (exact_match) {
- break;
- } else {
- near_match = true;
- }
- }
- }
-
- if (!res) {
- return p_message;
- }
-
return res;
}
@@ -1169,9 +1214,9 @@ void TranslationServer::set_tool_translation(const Ref<Translation> &p_translati
tool_translation = p_translation;
}
-StringName TranslationServer::tool_translate(const StringName &p_message) const {
+StringName TranslationServer::tool_translate(const StringName &p_message, const StringName &p_context) const {
if (tool_translation.is_valid()) {
- StringName r = tool_translation->get_message(p_message);
+ StringName r = tool_translation->get_message(p_message, p_context);
if (r) {
return r;
}
@@ -1179,13 +1224,27 @@ StringName TranslationServer::tool_translate(const StringName &p_message) const
return p_message;
}
+StringName TranslationServer::tool_translate_plural(const StringName &p_message, const StringName &p_message_plural, int p_n, const StringName &p_context) const {
+ if (tool_translation.is_valid()) {
+ StringName r = tool_translation->get_plural_message(p_message, p_message_plural, p_n, p_context);
+ if (r) {
+ return r;
+ }
+ }
+
+ if (p_n == 1) {
+ return p_message;
+ }
+ return p_message_plural;
+}
+
void TranslationServer::set_doc_translation(const Ref<Translation> &p_translation) {
doc_translation = p_translation;
}
-StringName TranslationServer::doc_translate(const StringName &p_message) const {
+StringName TranslationServer::doc_translate(const StringName &p_message, const StringName &p_context) const {
if (doc_translation.is_valid()) {
- StringName r = doc_translation->get_message(p_message);
+ StringName r = doc_translation->get_message(p_message, p_context);
if (r) {
return r;
}
@@ -1193,16 +1252,32 @@ StringName TranslationServer::doc_translate(const StringName &p_message) const {
return p_message;
}
+StringName TranslationServer::doc_translate_plural(const StringName &p_message, const StringName &p_message_plural, int p_n, const StringName &p_context) const {
+ if (doc_translation.is_valid()) {
+ StringName r = doc_translation->get_plural_message(p_message, p_message_plural, p_n, p_context);
+ if (r) {
+ return r;
+ }
+ }
+
+ if (p_n == 1) {
+ return p_message;
+ }
+ return p_message_plural;
+}
+
void TranslationServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_locale", "locale"), &TranslationServer::set_locale);
ClassDB::bind_method(D_METHOD("get_locale"), &TranslationServer::get_locale);
ClassDB::bind_method(D_METHOD("get_locale_name", "locale"), &TranslationServer::get_locale_name);
- ClassDB::bind_method(D_METHOD("translate", "message"), &TranslationServer::translate);
+ ClassDB::bind_method(D_METHOD("translate", "message", "context"), &TranslationServer::translate, DEFVAL(""));
+ ClassDB::bind_method(D_METHOD("translate_plural", "message", "plural_message", "n", "context"), &TranslationServer::translate_plural, DEFVAL(""));
ClassDB::bind_method(D_METHOD("add_translation", "translation"), &TranslationServer::add_translation);
ClassDB::bind_method(D_METHOD("remove_translation", "translation"), &TranslationServer::remove_translation);
+ ClassDB::bind_method(D_METHOD("get_translation_object", "locale"), &TranslationServer::get_translation_object);
ClassDB::bind_method(D_METHOD("clear"), &TranslationServer::clear);
diff --git a/core/translation.h b/core/string/translation.h
index 4f50a1a4bc..8d34f7997e 100644
--- a/core/translation.h
+++ b/core/string/translation.h
@@ -31,7 +31,7 @@
#ifndef TRANSLATION_H
#define TRANSLATION_H
-#include "core/resource.h"
+#include "core/io/resource.h"
class Translation : public Resource {
GDCLASS(Translation, Resource);
@@ -41,10 +41,9 @@ class Translation : public Resource {
String locale = "en";
Map<StringName, StringName> translation_map;
- Vector<String> _get_message_list() const;
-
- Vector<String> _get_messages() const;
- void _set_messages(const Vector<String> &p_messages);
+ virtual Vector<String> _get_message_list() const;
+ virtual Dictionary _get_messages() const;
+ virtual void _set_messages(const Dictionary &p_messages);
protected:
static void _bind_methods();
@@ -53,12 +52,13 @@ public:
void set_locale(const String &p_locale);
_FORCE_INLINE_ String get_locale() const { return locale; }
- void add_message(const StringName &p_src_text, const StringName &p_xlated_text);
- virtual StringName get_message(const StringName &p_src_text) const; //overridable for other implementations
- void erase_message(const StringName &p_src_text);
-
- void get_message_list(List<StringName> *r_messages) const;
- int get_message_count() const;
+ virtual void add_message(const StringName &p_src_text, const StringName &p_xlated_text, const StringName &p_context = "");
+ virtual void add_plural_message(const StringName &p_src_text, const Vector<String> &p_plural_xlated_texts, const StringName &p_context = "");
+ virtual StringName get_message(const StringName &p_src_text, const StringName &p_context = "") const; //overridable for other implementations
+ virtual StringName get_plural_message(const StringName &p_src_text, const StringName &p_plural_text, int p_n, const StringName &p_context = "") const;
+ virtual void erase_message(const StringName &p_src_text, const StringName &p_context = "");
+ virtual void get_message_list(List<StringName> *r_messages) const;
+ virtual int get_message_count() const;
Translation() {}
};
@@ -80,6 +80,8 @@ class TranslationServer : public Object {
static TranslationServer *singleton;
bool _load_translations(const String &p_from);
+ StringName _get_message_from_translations(const StringName &p_message, const StringName &p_context, const String &p_locale, bool plural, const String &p_message_plural = "", int p_n = 0) const;
+
static void _bind_methods();
public:
@@ -90,6 +92,7 @@ public:
void set_locale(const String &p_locale);
String get_locale() const;
+ Ref<Translation> get_translation_object(const String &p_locale);
String get_locale_name(const String &p_locale) const;
@@ -98,7 +101,8 @@ public:
void add_translation(const Ref<Translation> &p_translation);
void remove_translation(const Ref<Translation> &p_translation);
- StringName translate(const StringName &p_message) const;
+ StringName translate(const StringName &p_message, const StringName &p_context = "") const;
+ StringName translate_plural(const StringName &p_message, const StringName &p_message_plural, int p_n, const StringName &p_context = "") const;
static Vector<String> get_all_locales();
static Vector<String> get_all_locale_names();
@@ -107,9 +111,11 @@ public:
static String get_language_code(const String &p_locale);
void set_tool_translation(const Ref<Translation> &p_translation);
- StringName tool_translate(const StringName &p_message) const;
+ StringName tool_translate(const StringName &p_message, const StringName &p_context = "") const;
+ StringName tool_translate_plural(const StringName &p_message, const StringName &p_message_plural, int p_n, const StringName &p_context = "") const;
void set_doc_translation(const Ref<Translation> &p_translation);
- StringName doc_translate(const StringName &p_message) const;
+ StringName doc_translate(const StringName &p_message, const StringName &p_context = "") const;
+ StringName doc_translate_plural(const StringName &p_message, const StringName &p_message_plural, int p_n, const StringName &p_context = "") const;
void setup();
diff --git a/core/string/translation_po.cpp b/core/string/translation_po.cpp
new file mode 100644
index 0000000000..203f29026b
--- /dev/null
+++ b/core/string/translation_po.cpp
@@ -0,0 +1,312 @@
+/*************************************************************************/
+/* translation_po.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* 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. */
+/*************************************************************************/
+
+#include "translation_po.h"
+
+#include "core/os/file_access.h"
+
+#ifdef DEBUG_TRANSLATION_PO
+void TranslationPO::print_translation_map() {
+ Error err;
+ FileAccess *file = FileAccess::open("translation_map_print_test.txt", FileAccess::WRITE, &err);
+ if (err != OK) {
+ ERR_PRINT("Failed to open translation_map_print_test.txt");
+ return;
+ }
+
+ file->store_line("NPlural : " + String::num_int64(this->get_plural_forms()));
+ file->store_line("Plural rule : " + this->get_plural_rule());
+ file->store_line("");
+
+ List<StringName> context_l;
+ translation_map.get_key_list(&context_l);
+ for (auto E = context_l.front(); E; E = E->next()) {
+ StringName ctx = E->get();
+ file->store_line(" ===== Context: " + String::utf8(String(ctx).utf8()) + " ===== ");
+ const HashMap<StringName, Vector<StringName>> &inner_map = translation_map[ctx];
+
+ List<StringName> id_l;
+ inner_map.get_key_list(&id_l);
+ for (auto E2 = id_l.front(); E2; E2 = E2->next()) {
+ StringName id = E2->get();
+ file->store_line("msgid: " + String::utf8(String(id).utf8()));
+ for (int i = 0; i < inner_map[id].size(); i++) {
+ file->store_line("msgstr[" + String::num_int64(i) + "]: " + String::utf8(String(inner_map[id][i]).utf8()));
+ }
+ file->store_line("");
+ }
+ }
+ file->close();
+}
+#endif
+
+Dictionary TranslationPO::_get_messages() const {
+ // Return translation_map as a Dictionary.
+
+ Dictionary d;
+
+ List<StringName> context_l;
+ translation_map.get_key_list(&context_l);
+ for (auto E = context_l.front(); E; E = E->next()) {
+ StringName ctx = E->get();
+ const HashMap<StringName, Vector<StringName>> &id_str_map = translation_map[ctx];
+
+ Dictionary d2;
+ List<StringName> id_l;
+ id_str_map.get_key_list(&id_l);
+ // Save list of id and strs associated with a context in a temporary dictionary.
+ for (auto E2 = id_l.front(); E2; E2 = E2->next()) {
+ StringName id = E2->get();
+ d2[id] = id_str_map[id];
+ }
+
+ d[ctx] = d2;
+ }
+
+ return d;
+}
+
+void TranslationPO::_set_messages(const Dictionary &p_messages) {
+ // Construct translation_map from a Dictionary.
+
+ List<Variant> context_l;
+ p_messages.get_key_list(&context_l);
+ for (auto E = context_l.front(); E; E = E->next()) {
+ StringName ctx = E->get();
+ const Dictionary &id_str_map = p_messages[ctx];
+
+ HashMap<StringName, Vector<StringName>> temp_map;
+ List<Variant> id_l;
+ id_str_map.get_key_list(&id_l);
+ for (auto E2 = id_l.front(); E2; E2 = E2->next()) {
+ StringName id = E2->get();
+ temp_map[id] = id_str_map[id];
+ }
+
+ translation_map[ctx] = temp_map;
+ }
+}
+
+Vector<String> TranslationPO::_get_message_list() const {
+ // Return all keys in translation_map.
+
+ List<StringName> msgs;
+ get_message_list(&msgs);
+
+ Vector<String> v;
+ for (auto E = msgs.front(); E; E = E->next()) {
+ v.push_back(E->get());
+ }
+
+ return v;
+}
+
+int TranslationPO::_get_plural_index(int p_n) const {
+ // Get a number between [0;number of plural forms).
+
+ input_val.clear();
+ input_val.push_back(p_n);
+
+ Variant result;
+ for (int i = 0; i < equi_tests.size(); i++) {
+ Error err = expr->parse(equi_tests[i], input_name);
+ ERR_FAIL_COND_V_MSG(err != OK, 0, "Cannot parse expression. Error: " + expr->get_error_text());
+
+ result = expr->execute(input_val);
+ ERR_FAIL_COND_V_MSG(expr->has_execute_failed(), 0, "Cannot evaluate expression.");
+
+ // Last expression. Variant result will either map to a bool or an integer, in both cases returning it will give the correct plural index.
+ if (i + 1 == equi_tests.size()) {
+ return result;
+ }
+
+ if (bool(result)) {
+ return i;
+ }
+ }
+
+ ERR_FAIL_V_MSG(0, "Unexpected. Function should have returned. Please report this bug.");
+}
+
+void TranslationPO::_cache_plural_tests(const String &p_plural_rule) {
+ // Some examples of p_plural_rule passed in can have the form:
+ // "n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5" (Arabic)
+ // "n >= 2" (French) // When evaluating the last, esp careful with this one.
+ // "n != 1" (English)
+ int first_ques_mark = p_plural_rule.find("?");
+ if (first_ques_mark == -1) {
+ equi_tests.push_back(p_plural_rule.strip_edges());
+ return;
+ }
+
+ String equi_test = p_plural_rule.substr(0, first_ques_mark).strip_edges();
+ equi_tests.push_back(equi_test);
+
+ String after_colon = p_plural_rule.substr(p_plural_rule.find(":") + 1, p_plural_rule.length());
+ _cache_plural_tests(after_colon);
+}
+
+void TranslationPO::set_plural_rule(const String &p_plural_rule) {
+ // Set plural_forms and plural_rule.
+ // p_plural_rule passed in has the form "Plural-Forms: nplurals=2; plural=(n >= 2);".
+
+ int first_semi_col = p_plural_rule.find(";");
+ plural_forms = p_plural_rule.substr(p_plural_rule.find("=") + 1, first_semi_col - (p_plural_rule.find("=") + 1)).to_int();
+
+ int expression_start = p_plural_rule.find("=", first_semi_col) + 1;
+ int second_semi_col = p_plural_rule.rfind(";");
+ plural_rule = p_plural_rule.substr(expression_start, second_semi_col - expression_start);
+
+ // Setup the cache to make evaluating plural rule faster later on.
+ plural_rule = plural_rule.replacen("(", "");
+ plural_rule = plural_rule.replacen(")", "");
+ _cache_plural_tests(plural_rule);
+ expr.instance();
+ input_name.push_back("n");
+}
+
+void TranslationPO::add_message(const StringName &p_src_text, const StringName &p_xlated_text, const StringName &p_context) {
+ HashMap<StringName, Vector<StringName>> &map_id_str = translation_map[p_context];
+
+ if (map_id_str.has(p_src_text)) {
+ WARN_PRINT("Double translations for \"" + String(p_src_text) + "\" under the same context \"" + String(p_context) + "\" for locale \"" + get_locale() + "\".\nThere should only be one unique translation for a given string under the same context.");
+ map_id_str[p_src_text].set(0, p_xlated_text);
+ } else {
+ map_id_str[p_src_text].push_back(p_xlated_text);
+ }
+}
+
+void TranslationPO::add_plural_message(const StringName &p_src_text, const Vector<String> &p_plural_xlated_texts, const StringName &p_context) {
+ ERR_FAIL_COND_MSG(p_plural_xlated_texts.size() != plural_forms, "Trying to add plural texts that don't match the required number of plural forms for locale \"" + get_locale() + "\"");
+
+ HashMap<StringName, Vector<StringName>> &map_id_str = translation_map[p_context];
+
+ if (map_id_str.has(p_src_text)) {
+ WARN_PRINT("Double translations for \"" + p_src_text + "\" under the same context \"" + p_context + "\" for locale " + get_locale() + ".\nThere should only be one unique translation for a given string under the same context.");
+ map_id_str[p_src_text].clear();
+ }
+
+ for (int i = 0; i < p_plural_xlated_texts.size(); i++) {
+ map_id_str[p_src_text].push_back(p_plural_xlated_texts[i]);
+ }
+}
+
+int TranslationPO::get_plural_forms() const {
+ return plural_forms;
+}
+
+String TranslationPO::get_plural_rule() const {
+ return plural_rule;
+}
+
+StringName TranslationPO::get_message(const StringName &p_src_text, const StringName &p_context) const {
+ if (!translation_map.has(p_context) || !translation_map[p_context].has(p_src_text)) {
+ return StringName();
+ }
+ ERR_FAIL_COND_V_MSG(translation_map[p_context][p_src_text].empty(), StringName(), "Source text \"" + String(p_src_text) + "\" is registered but doesn't have a translation. Please report this bug.");
+
+ return translation_map[p_context][p_src_text][0];
+}
+
+StringName TranslationPO::get_plural_message(const StringName &p_src_text, const StringName &p_plural_text, int p_n, const StringName &p_context) const {
+ ERR_FAIL_COND_V_MSG(p_n < 0, StringName(), "N passed into translation to get a plural message should not be negative. For negative numbers, use singular translation please. Search \"gettext PO Plural Forms\" online for the documentation on translating negative numbers.");
+
+ // If the query is the same as last time, return the cached result.
+ if (p_n == last_plural_n && p_context == last_plural_context && p_src_text == last_plural_key) {
+ return translation_map[p_context][p_src_text][last_plural_mapped_index];
+ }
+
+ if (!translation_map.has(p_context) || !translation_map[p_context].has(p_src_text)) {
+ return StringName();
+ }
+ ERR_FAIL_COND_V_MSG(translation_map[p_context][p_src_text].empty(), StringName(), "Source text \"" + String(p_src_text) + "\" is registered but doesn't have a translation. Please report this bug.");
+
+ if (translation_map[p_context][p_src_text].size() == 1) {
+ WARN_PRINT("Source string \"" + String(p_src_text) + "\" doesn't have plural translations. Use singular translation API for such as tr(), TTR() to translate \"" + String(p_src_text) + "\"");
+ return translation_map[p_context][p_src_text][0];
+ }
+
+ int plural_index = _get_plural_index(p_n);
+ ERR_FAIL_COND_V_MSG(plural_index < 0 || translation_map[p_context][p_src_text].size() < plural_index + 1, StringName(), "Plural index returned or number of plural translations is not valid. Please report this bug.");
+
+ // Cache result so that if the next entry is the same, we can return directly.
+ // _get_plural_index(p_n) can get very costly, especially when evaluating long plural-rule (Arabic)
+ last_plural_key = p_src_text;
+ last_plural_context = p_context;
+ last_plural_n = p_n;
+ last_plural_mapped_index = plural_index;
+
+ return translation_map[p_context][p_src_text][plural_index];
+}
+
+void TranslationPO::erase_message(const StringName &p_src_text, const StringName &p_context) {
+ if (!translation_map.has(p_context)) {
+ return;
+ }
+
+ translation_map[p_context].erase(p_src_text);
+}
+
+void TranslationPO::get_message_list(List<StringName> *r_messages) const {
+ // PHashTranslation uses this function to get the list of msgid.
+ // Return all the keys of translation_map under "" context.
+
+ List<StringName> context_l;
+ translation_map.get_key_list(&context_l);
+
+ for (auto E = context_l.front(); E; E = E->next()) {
+ if (String(E->get()) != "") {
+ continue;
+ }
+
+ List<StringName> msgid_l;
+ translation_map[E->get()].get_key_list(&msgid_l);
+
+ for (auto E2 = msgid_l.front(); E2; E2 = E2->next()) {
+ r_messages->push_back(E2->get());
+ }
+ }
+}
+
+int TranslationPO::get_message_count() const {
+ List<StringName> context_l;
+ translation_map.get_key_list(&context_l);
+
+ int count = 0;
+ for (auto E = context_l.front(); E; E = E->next()) {
+ count += translation_map[E->get()].size();
+ }
+ return count;
+}
+
+void TranslationPO::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("get_plural_forms"), &TranslationPO::get_plural_forms);
+ ClassDB::bind_method(D_METHOD("get_plural_rule"), &TranslationPO::get_plural_rule);
+}
diff --git a/core/string/translation_po.h b/core/string/translation_po.h
new file mode 100644
index 0000000000..c8a47bec5a
--- /dev/null
+++ b/core/string/translation_po.h
@@ -0,0 +1,92 @@
+/*************************************************************************/
+/* translation_po.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* 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. */
+/*************************************************************************/
+
+#ifndef TRANSLATION_PO_H
+#define TRANSLATION_PO_H
+
+//#define DEBUG_TRANSLATION_PO
+
+#include "core/math/expression.h"
+#include "core/string/translation.h"
+
+class TranslationPO : public Translation {
+ GDCLASS(TranslationPO, Translation);
+
+ // TLDR: Maps context to a list of source strings and translated strings. In PO terms, maps msgctxt to a list of msgid and msgstr.
+ // The first key corresponds to context, and the second key (of the contained HashMap) corresponds to source string.
+ // The value Vector<StringName> in the second map stores the translated strings. Index 0, 1, 2 matches msgstr[0], msgstr[1], msgstr[2]... in the case of plurals.
+ // Otherwise index 0 matches to msgstr in a singular translation.
+ // Strings without context have "" as first key.
+ HashMap<StringName, HashMap<StringName, Vector<StringName>>> translation_map;
+
+ int plural_forms = 0; // 0 means no "Plural-Forms" is given in the PO header file. The min for all languages is 1.
+ String plural_rule;
+
+ // Cache temporary variables related to _get_plural_index() to make it faster
+ Vector<String> equi_tests;
+ Vector<String> input_name;
+ mutable Ref<Expression> expr;
+ mutable Array input_val;
+ mutable StringName last_plural_key;
+ mutable StringName last_plural_context;
+ mutable int last_plural_n = -1; // Set it to an impossible value at the beginning.
+ mutable int last_plural_mapped_index = 0;
+
+ void _cache_plural_tests(const String &p_plural_rule);
+ int _get_plural_index(int p_n) const;
+
+ Vector<String> _get_message_list() const override;
+ Dictionary _get_messages() const override;
+ void _set_messages(const Dictionary &p_messages) override;
+
+protected:
+ static void _bind_methods();
+
+public:
+ void get_message_list(List<StringName> *r_messages) const override;
+ int get_message_count() const override;
+ void add_message(const StringName &p_src_text, const StringName &p_xlated_text, const StringName &p_context = "") override;
+ void add_plural_message(const StringName &p_src_text, const Vector<String> &p_plural_xlated_texts, const StringName &p_context = "") override;
+ StringName get_message(const StringName &p_src_text, const StringName &p_context = "") const override;
+ StringName get_plural_message(const StringName &p_src_text, const StringName &p_plural_text, int p_n, const StringName &p_context = "") const override;
+ void erase_message(const StringName &p_src_text, const StringName &p_context = "") override;
+
+ void set_plural_rule(const String &p_plural_rule);
+ int get_plural_forms() const;
+ String get_plural_rule() const;
+
+#ifdef DEBUG_TRANSLATION_PO
+ void print_translation_map();
+#endif
+
+ TranslationPO() {}
+};
+
+#endif // TRANSLATION_PO_H
diff --git a/core/ucaps.h b/core/string/ucaps.h
index 79b346acba..79b346acba 100644
--- a/core/ucaps.h
+++ b/core/string/ucaps.h
diff --git a/core/ustring.cpp b/core/string/ustring.cpp
index 5d3cf5f1a4..213578485e 100644
--- a/core/ustring.cpp
+++ b/core/string/ustring.cpp
@@ -30,16 +30,15 @@
#include "ustring.h"
-#include "core/color.h"
#include "core/crypto/crypto_core.h"
+#include "core/math/color.h"
#include "core/math/math_funcs.h"
#include "core/os/memory.h"
-#include "core/print_string.h"
-#include "core/translation.h"
-#include "core/ucaps.h"
-#include "core/variant.h"
+#include "core/string/print_string.h"
+#include "core/string/translation.h"
+#include "core/string/ucaps.h"
+#include "core/variant/variant.h"
-#include <wchar.h>
#include <cstdint>
#ifndef NO_USE_STDLIB
@@ -62,9 +61,10 @@
#define IS_HEX_DIGIT(m_d) (((m_d) >= '0' && (m_d) <= '9') || ((m_d) >= 'a' && (m_d) <= 'f') || ((m_d) >= 'A' && (m_d) <= 'F'))
const char CharString::_null = 0;
-const CharType String::_null = 0;
+const char16_t Char16String::_null = 0;
+const char32_t String::_null = 0;
-bool is_symbol(CharType c) {
+bool is_symbol(char32_t c) {
return c != '_' && ((c >= '!' && c <= '/') || (c >= ':' && c <= '@') || (c >= '[' && c <= '`') || (c >= '{' && c <= '~') || c == '\t' || c == ' ');
}
@@ -96,9 +96,11 @@ bool select_word(const String &p_s, int p_col, int &r_beg, int &r_end) {
}
}
-/** STRING **/
+/*************************************************************************/
+/* Char16String */
+/*************************************************************************/
-bool CharString::operator<(const CharString &p_right) const {
+bool Char16String::operator<(const Char16String &p_right) const {
if (length() == 0) {
return p_right.length() != 0;
}
@@ -106,7 +108,7 @@ bool CharString::operator<(const CharString &p_right) const {
return is_str_less(get_data(), p_right.get_data());
}
-CharString &CharString::operator+=(char p_char) {
+Char16String &Char16String::operator+=(char16_t p_char) {
resize(size() ? size() + 1 : 2);
set(length(), 0);
set(length() - 1, p_char);
@@ -114,12 +116,60 @@ CharString &CharString::operator+=(char p_char) {
return *this;
}
-const char *CharString::get_data() const {
+Char16String &Char16String::operator=(const char16_t *p_cstr) {
+ copy_from(p_cstr);
+ return *this;
+}
+
+const char16_t *Char16String::get_data() const {
if (size()) {
return &operator[](0);
} else {
- return "";
+ return u"";
+ }
+}
+
+void Char16String::copy_from(const char16_t *p_cstr) {
+ if (!p_cstr) {
+ resize(0);
+ return;
+ }
+
+ const char16_t *s = p_cstr;
+ for (; *s; s++) {
+ }
+ size_t len = s - p_cstr;
+
+ if (len == 0) {
+ resize(0);
+ return;
}
+
+ Error err = resize(++len); // include terminating null char
+
+ ERR_FAIL_COND_MSG(err != OK, "Failed to copy char16_t string.");
+
+ memcpy(ptrw(), p_cstr, len * sizeof(char16_t));
+}
+
+/*************************************************************************/
+/* CharString */
+/*************************************************************************/
+
+bool CharString::operator<(const CharString &p_right) const {
+ if (length() == 0) {
+ return p_right.length() != 0;
+ }
+
+ return is_str_less(get_data(), p_right.get_data());
+}
+
+CharString &CharString::operator+=(char p_char) {
+ resize(size() ? size() + 1 : 2);
+ set(length(), 0);
+ set(length() - 1, p_char);
+
+ return *this;
}
CharString &CharString::operator=(const char *p_cstr) {
@@ -127,6 +177,14 @@ CharString &CharString::operator=(const char *p_cstr) {
return *this;
}
+const char *CharString::get_data() const {
+ if (size()) {
+ return &operator[](0);
+ } else {
+ return "";
+ }
+}
+
void CharString::copy_from(const char *p_cstr) {
if (!p_cstr) {
resize(0);
@@ -147,7 +205,44 @@ void CharString::copy_from(const char *p_cstr) {
memcpy(ptrw(), p_cstr, len);
}
+/*************************************************************************/
+/* String */
+/*************************************************************************/
+
+//TODO: move to TextServer
+//kind of poor should be rewritten properly
+String String::word_wrap(int p_chars_per_line) const {
+ int from = 0;
+ int last_space = 0;
+ String ret;
+ for (int i = 0; i < length(); i++) {
+ if (i - from >= p_chars_per_line) {
+ if (last_space == -1) {
+ ret += substr(from, i - from + 1) + "\n";
+ } else {
+ ret += substr(from, last_space - from) + "\n";
+ i = last_space; //rewind
+ }
+ from = i + 1;
+ last_space = -1;
+ } else if (operator[](i) == ' ' || operator[](i) == '\t') {
+ last_space = i;
+ } else if (operator[](i) == '\n') {
+ ret += substr(from, i - from) + "\n";
+ from = i + 1;
+ last_space = -1;
+ }
+ }
+
+ if (from < length()) {
+ ret += substr(from, length());
+ }
+
+ return ret;
+}
+
void String::copy_from(const char *p_cstr) {
+ // copy Latin-1 encoded c-string directly
if (!p_cstr) {
resize(0);
return;
@@ -166,21 +261,22 @@ void String::copy_from(const char *p_cstr) {
resize(len + 1); // include 0
- CharType *dst = this->ptrw();
+ char32_t *dst = this->ptrw();
for (int i = 0; i < len + 1; i++) {
dst[i] = p_cstr[i];
}
}
-void String::copy_from(const CharType *p_cstr, const int p_clip_to) {
+void String::copy_from(const char *p_cstr, const int p_clip_to) {
+ // copy Latin-1 encoded c-string directly
if (!p_cstr) {
resize(0);
return;
}
int len = 0;
- const CharType *ptr = p_cstr;
+ const char *ptr = p_cstr;
while ((p_clip_to < 0 || len < p_clip_to) && *(ptr++) != 0) {
len++;
}
@@ -190,55 +286,117 @@ void String::copy_from(const CharType *p_cstr, const int p_clip_to) {
return;
}
- copy_from_unchecked(p_cstr, len);
-}
-
-// assumes the following have already been validated:
-// p_char != nullptr
-// p_length > 0
-// p_length <= p_char strlen
-void String::copy_from_unchecked(const CharType *p_char, const int p_length) {
- resize(p_length + 1);
- set(p_length, 0);
+ resize(len + 1); // include 0
- CharType *dst = ptrw();
+ char32_t *dst = this->ptrw();
- for (int i = 0; i < p_length; i++) {
- dst[i] = p_char[i];
+ for (int i = 0; i < len; i++) {
+ dst[i] = p_cstr[i];
}
+ dst[len] = 0;
}
-void String::copy_from(const CharType &p_char) {
+void String::copy_from(const wchar_t *p_cstr) {
+#ifdef WINDOWS_ENABLED
+ // wchar_t is 16-bit, parse as UTF-16
+ parse_utf16((const char16_t *)p_cstr);
+#else
+ // wchar_t is 32-bit, copy directly
+ copy_from((const char32_t *)p_cstr);
+#endif
+}
+
+void String::copy_from(const wchar_t *p_cstr, const int p_clip_to) {
+#ifdef WINDOWS_ENABLED
+ // wchar_t is 16-bit, parse as UTF-16
+ parse_utf16((const char16_t *)p_cstr, p_clip_to);
+#else
+ // wchar_t is 32-bit, copy directly
+ copy_from((const char32_t *)p_cstr, p_clip_to);
+#endif
+}
+
+void String::copy_from(const char32_t &p_char) {
resize(2);
- set(0, p_char);
+ if ((p_char >= 0xd800 && p_char <= 0xdfff) || (p_char > 0x10ffff)) {
+ print_error("Unicode parsing error: Invalid unicode codepoint " + num_int64(p_char, 16) + ".");
+ set(0, 0xfffd);
+ } else {
+ set(0, p_char);
+ }
set(1, 0);
}
-bool String::operator==(const String &p_str) const {
- if (length() != p_str.length()) {
- return false;
+void String::copy_from(const char32_t *p_cstr) {
+ if (!p_cstr) {
+ resize(0);
+ return;
}
- if (empty()) {
- return true;
+
+ int len = 0;
+ const char32_t *ptr = p_cstr;
+ while (*(ptr++) != 0) {
+ len++;
}
- int l = length();
+ if (len == 0) {
+ resize(0);
+ return;
+ }
- const CharType *src = c_str();
- const CharType *dst = p_str.c_str();
+ copy_from_unchecked(p_cstr, len);
+}
- /* Compare char by char */
- for (int i = 0; i < l; i++) {
- if (src[i] != dst[i]) {
- return false;
+void String::copy_from(const char32_t *p_cstr, const int p_clip_to) {
+ if (!p_cstr) {
+ resize(0);
+ return;
+ }
+
+ int len = 0;
+ const char32_t *ptr = p_cstr;
+ while ((p_clip_to < 0 || len < p_clip_to) && *(ptr++) != 0) {
+ len++;
+ }
+
+ if (len == 0) {
+ resize(0);
+ return;
+ }
+
+ copy_from_unchecked(p_cstr, len);
+}
+
+// assumes the following have already been validated:
+// p_char != nullptr
+// p_length > 0
+// p_length <= p_char strlen
+void String::copy_from_unchecked(const char32_t *p_char, const int p_length) {
+ resize(p_length + 1);
+ set(p_length, 0);
+
+ char32_t *dst = ptrw();
+
+ for (int i = 0; i < p_length; i++) {
+ if ((p_char[i] >= 0xd800 && p_char[i] <= 0xdfff) || (p_char[i] > 0x10ffff)) {
+ print_error("Unicode parsing error: Invalid unicode codepoint " + num_int64(p_char[i], 16) + ".");
+ dst[i] = 0xfffd;
+ } else {
+ dst[i] = p_char[i];
}
}
+}
- return true;
+void String::operator=(const char *p_str) {
+ copy_from(p_str);
}
-bool String::operator!=(const String &p_str) const {
- return !(*this == p_str);
+void String::operator=(const char32_t *p_str) {
+ copy_from(p_str);
+}
+
+void String::operator=(const wchar_t *p_str) {
+ copy_from(p_str);
}
String String::operator+(const String &p_str) const {
@@ -247,6 +405,28 @@ String String::operator+(const String &p_str) const {
return res;
}
+String operator+(const char *p_chr, const String &p_str) {
+ String tmp = p_chr;
+ tmp += p_str;
+ return tmp;
+}
+
+String operator+(const wchar_t *p_chr, const String &p_str) {
+#ifdef WINDOWS_ENABLED
+ // wchar_t is 16-bit
+ String tmp = String::utf16((const char16_t *)p_chr);
+#else
+ // wchar_t is 32-bi
+ String tmp = (const char32_t *)p_chr;
+#endif
+ tmp += p_str;
+ return tmp;
+}
+
+String operator+(char32_t p_chr, const String &p_str) {
+ return (String::chr(p_chr) + p_str);
+}
+
String &String::operator+=(const String &p_str) {
if (empty()) {
*this = p_str;
@@ -261,8 +441,8 @@ String &String::operator+=(const String &p_str) {
resize(length() + p_str.size());
- const CharType *src = p_str.c_str();
- CharType *dst = ptrw();
+ const char32_t *src = p_str.get_data();
+ char32_t *dst = ptrw();
set(length(), 0);
@@ -273,19 +453,6 @@ String &String::operator+=(const String &p_str) {
return *this;
}
-String &String::operator+=(const CharType *p_str) {
- *this += String(p_str);
- return *this;
-}
-
-String &String::operator+=(CharType p_char) {
- resize(size() ? size() + 1 : 2);
- set(length(), 0);
- set(length() - 1, p_char);
-
- return *this;
-}
-
String &String::operator+=(const char *p_str) {
if (!p_str || p_str[0] == 0) {
return *this;
@@ -301,7 +468,7 @@ String &String::operator+=(const char *p_str) {
resize(from + src_len + 1);
- CharType *dst = ptrw();
+ char32_t *dst = ptrw();
set(length(), 0);
@@ -312,16 +479,43 @@ String &String::operator+=(const char *p_str) {
return *this;
}
-void String::operator=(const char *p_str) {
- copy_from(p_str);
+String &String::operator+=(const wchar_t *p_str) {
+#ifdef WINDOWS_ENABLED
+ // wchar_t is 16-bit
+ *this += String::utf16((const char16_t *)p_str);
+#else
+ // wchar_t is 32-bit
+ *this += String((const char32_t *)p_str);
+#endif
+ return *this;
}
-void String::operator=(const CharType *p_str) {
- copy_from(p_str);
+String &String::operator+=(const char32_t *p_str) {
+ *this += String(p_str);
+ return *this;
}
-bool String::operator==(const StrRange &p_str_range) const {
- int len = p_str_range.len;
+String &String::operator+=(char32_t p_char) {
+ resize(size() ? size() + 1 : 2);
+ set(length(), 0);
+ if ((p_char >= 0xd800 && p_char <= 0xdfff) || (p_char > 0x10ffff)) {
+ print_error("Unicode parsing error: Invalid unicode codepoint " + num_int64(p_char, 16) + ".");
+ set(length() - 1, 0xfffd);
+ } else {
+ set(length() - 1, p_char);
+ }
+
+ return *this;
+}
+
+bool String::operator==(const char *p_str) const {
+ // compare Latin-1 encoded c-string
+ int len = 0;
+ const char *aux = p_str;
+
+ while (*(aux++) != 0) {
+ len++;
+ }
if (length() != len) {
return false;
@@ -330,12 +524,13 @@ bool String::operator==(const StrRange &p_str_range) const {
return true;
}
- const CharType *c_str = p_str_range.c_str;
- const CharType *dst = &operator[](0);
+ int l = length();
- /* Compare char by char */
- for (int i = 0; i < len; i++) {
- if (c_str[i] != dst[i]) {
+ const char32_t *dst = get_data();
+
+ // Compare char by char
+ for (int i = 0; i < l; i++) {
+ if ((char32_t)p_str[i] != dst[i]) {
return false;
}
}
@@ -343,9 +538,19 @@ bool String::operator==(const StrRange &p_str_range) const {
return true;
}
-bool String::operator==(const char *p_str) const {
+bool String::operator==(const wchar_t *p_str) const {
+#ifdef WINDOWS_ENABLED
+ // wchar_t is 16-bit, parse as UTF-16
+ return *this == String::utf16((const char16_t *)p_str);
+#else
+ // wchar_t is 32-bit, compare char by char
+ return *this == (const char32_t *)p_str;
+#endif
+}
+
+bool String::operator==(const char32_t *p_str) const {
int len = 0;
- const char *aux = p_str;
+ const char32_t *aux = p_str;
while (*(aux++) != 0) {
len++;
@@ -360,7 +565,7 @@ bool String::operator==(const char *p_str) const {
int l = length();
- const CharType *dst = c_str();
+ const char32_t *dst = get_data();
/* Compare char by char */
for (int i = 0; i < l; i++) {
@@ -372,14 +577,32 @@ bool String::operator==(const char *p_str) const {
return true;
}
-bool String::operator==(const CharType *p_str) const {
- int len = 0;
- const CharType *aux = p_str;
+bool String::operator==(const String &p_str) const {
+ if (length() != p_str.length()) {
+ return false;
+ }
+ if (empty()) {
+ return true;
+ }
- while (*(aux++) != 0) {
- len++;
+ int l = length();
+
+ const char32_t *src = get_data();
+ const char32_t *dst = p_str.get_data();
+
+ /* Compare char by char */
+ for (int i = 0; i < l; i++) {
+ if (src[i] != dst[i]) {
+ return false;
+ }
}
+ return true;
+}
+
+bool String::operator==(const StrRange &p_str_range) const {
+ int len = p_str_range.len;
+
if (length() != len) {
return false;
}
@@ -387,13 +610,12 @@ bool String::operator==(const CharType *p_str) const {
return true;
}
- int l = length();
-
- const CharType *dst = c_str();
+ const char32_t *c_str = p_str_range.c_str;
+ const char32_t *dst = &operator[](0);
/* Compare char by char */
- for (int i = 0; i < l; i++) {
- if (p_str[i] != dst[i]) {
+ for (int i = 0; i < len; i++) {
+ if (c_str[i] != dst[i]) {
return false;
}
}
@@ -401,30 +623,89 @@ bool String::operator==(const CharType *p_str) const {
return true;
}
+bool operator==(const char *p_chr, const String &p_str) {
+ return p_str == p_chr;
+}
+
+bool operator==(const wchar_t *p_chr, const String &p_str) {
+#ifdef WINDOWS_ENABLED
+ // wchar_t is 16-bit
+ return p_str == String::utf16((const char16_t *)p_chr);
+#else
+ // wchar_t is 32-bi
+ return p_str == String((const char32_t *)p_chr);
+#endif
+}
+
+bool operator!=(const char *p_chr, const String &p_str) {
+ return !(p_str == p_chr);
+}
+
+bool operator!=(const wchar_t *p_chr, const String &p_str) {
+#ifdef WINDOWS_ENABLED
+ // wchar_t is 16-bit
+ return !(p_str == String::utf16((const char16_t *)p_chr));
+#else
+ // wchar_t is 32-bi
+ return !(p_str == String((const char32_t *)p_chr));
+#endif
+}
+
bool String::operator!=(const char *p_str) const {
return (!(*this == p_str));
}
-bool String::operator!=(const CharType *p_str) const {
+bool String::operator!=(const wchar_t *p_str) const {
return (!(*this == p_str));
}
-bool String::operator<(const CharType *p_str) const {
+bool String::operator!=(const char32_t *p_str) const {
+ return (!(*this == p_str));
+}
+
+bool String::operator!=(const String &p_str) const {
+ return !((*this == p_str));
+}
+
+bool String::operator<=(const String &p_str) const {
+ return !(p_str < *this);
+}
+
+bool String::operator>(const String &p_str) const {
+ return p_str < *this;
+}
+bool String::operator>=(const String &p_str) const {
+ return !(*this < p_str);
+}
+
+bool String::operator<(const char *p_str) const {
if (empty() && p_str[0] == 0) {
return false;
}
if (empty()) {
return true;
}
-
- return is_str_less(c_str(), p_str);
+ return is_str_less(get_data(), p_str);
}
-bool String::operator<=(const String &p_str) const {
- return (*this < p_str) || (*this == p_str);
+bool String::operator<(const wchar_t *p_str) const {
+ if (empty() && p_str[0] == 0) {
+ return false;
+ }
+ if (empty()) {
+ return true;
+ }
+
+#ifdef WINDOWS_ENABLED
+ // wchar_t is 16-bit
+ return is_str_less(get_data(), String::utf16((const char16_t *)p_str).get_data());
+#else
+ // wchar_t is 32-bit
+ return is_str_less(get_data(), (const char32_t *)p_str);
+#endif
}
-bool String::operator<(const char *p_str) const {
+bool String::operator<(const char32_t *p_str) const {
if (empty() && p_str[0] == 0) {
return false;
}
@@ -432,11 +713,11 @@ bool String::operator<(const char *p_str) const {
return true;
}
- return is_str_less(c_str(), p_str);
+ return is_str_less(get_data(), p_str);
}
bool String::operator<(const String &p_str) const {
- return operator<(p_str.c_str());
+ return operator<(p_str.get_data());
}
signed char String::nocasecmp_to(const String &p_str) const {
@@ -450,8 +731,8 @@ signed char String::nocasecmp_to(const String &p_str) const {
return 1;
}
- const CharType *that_str = p_str.c_str();
- const CharType *this_str = c_str();
+ const char32_t *that_str = p_str.get_data();
+ const char32_t *this_str = get_data();
while (true) {
if (*that_str == 0 && *this_str == 0) {
@@ -482,8 +763,8 @@ signed char String::casecmp_to(const String &p_str) const {
return 1;
}
- const CharType *that_str = p_str.c_str();
- const CharType *this_str = c_str();
+ const char32_t *that_str = p_str.get_data();
+ const char32_t *this_str = get_data();
while (true) {
if (*that_str == 0 && *this_str == 0) {
@@ -504,8 +785,8 @@ signed char String::casecmp_to(const String &p_str) const {
}
signed char String::naturalnocasecmp_to(const String &p_str) const {
- const CharType *this_str = c_str();
- const CharType *that_str = p_str.c_str();
+ const char32_t *this_str = get_data();
+ const char32_t *that_str = p_str.get_data();
if (this_str && that_str) {
while (*this_str == '.' || *that_str == '.') {
@@ -527,29 +808,46 @@ signed char String::naturalnocasecmp_to(const String &p_str) const {
if (!*that_str) {
return 1;
} else if (IS_DIGIT(*this_str)) {
- int64_t this_int, that_int;
-
if (!IS_DIGIT(*that_str)) {
return -1;
}
- /* Compare the numbers */
- this_int = to_int(this_str, -1, true);
- that_int = to_int(that_str, -1, true);
-
- if (this_int < that_int) {
- return -1;
- } else if (this_int > that_int) {
- return 1;
- }
+ // Keep ptrs to start of numerical sequences
+ const char32_t *this_substr = this_str;
+ const char32_t *that_substr = that_str;
- /* Skip */
+ // Compare lengths of both numerical sequences, ignoring leading zeros
while (IS_DIGIT(*this_str)) {
this_str++;
}
while (IS_DIGIT(*that_str)) {
that_str++;
}
+ while (*this_substr == '0') {
+ this_substr++;
+ }
+ while (*that_substr == '0') {
+ that_substr++;
+ }
+ int this_len = this_str - this_substr;
+ int that_len = that_str - that_substr;
+
+ if (this_len < that_len) {
+ return -1;
+ } else if (this_len > that_len) {
+ return 1;
+ }
+
+ // If lengths equal, compare lexicographically
+ while (this_substr != this_str && that_substr != that_str) {
+ if (*this_substr < *that_substr) {
+ return -1;
+ } else if (*this_substr > *that_substr) {
+ return 1;
+ }
+ this_substr++;
+ that_substr++;
+ }
} else if (IS_DIGIT(*that_str)) {
return 1;
} else {
@@ -571,6 +869,11 @@ signed char String::naturalnocasecmp_to(const String &p_str) const {
return 0;
}
+const char32_t *String::get_data() const {
+ static const char32_t zero = 0;
+ return size() ? &operator[](0) : &zero;
+}
+
void String::erase(int p_pos, int p_chars) {
*this = left(p_pos) + substr(p_pos + p_chars, length() - ((p_pos + p_chars)));
}
@@ -593,7 +896,7 @@ String String::capitalize() const {
}
String String::camelcase_to_underscore(bool lowercase) const {
- const CharType *cstr = c_str();
+ const char32_t *cstr = get_data();
String new_string;
const char A = 'A', Z = 'Z';
const char a = 'a', z = 'z';
@@ -705,7 +1008,7 @@ String String::get_slice(String p_splitter, int p_slice) const {
return ""; //no find!
}
-String String::get_slicec(CharType p_splitter, int p_slice) const {
+String String::get_slicec(char32_t p_splitter, int p_slice) const {
if (empty()) {
return String();
}
@@ -714,7 +1017,7 @@ String String::get_slicec(CharType p_splitter, int p_slice) const {
return String();
}
- const CharType *c = this->ptr();
+ const char32_t *c = this->ptr();
int i = 0;
int prev = 0;
int count = 0;
@@ -851,7 +1154,7 @@ Vector<float> String::split_floats(const String &p_splitter, bool p_allow_empty)
end = len;
}
if (p_allow_empty || (end > from)) {
- ret.push_back(String::to_double(&c_str()[from]));
+ ret.push_back(String::to_float(&get_data()[from]));
}
if (end == len) {
@@ -880,7 +1183,7 @@ Vector<float> String::split_floats_mk(const Vector<String> &p_splitters, bool p_
}
if (p_allow_empty || (end > from)) {
- ret.push_back(String::to_double(&c_str()[from]));
+ ret.push_back(String::to_float(&get_data()[from]));
}
if (end == len) {
@@ -904,7 +1207,7 @@ Vector<int> String::split_ints(const String &p_splitter, bool p_allow_empty) con
end = len;
}
if (p_allow_empty || (end > from)) {
- ret.push_back(String::to_int(&c_str()[from], end - from));
+ ret.push_back(String::to_int(&get_data()[from], end - from));
}
if (end == len) {
@@ -933,7 +1236,7 @@ Vector<int> String::split_ints_mk(const Vector<String> &p_splitters, bool p_allo
}
if (p_allow_empty || (end > from)) {
- ret.push_back(String::to_int(&c_str()[from], end - from));
+ ret.push_back(String::to_int(&get_data()[from], end - from));
}
if (end == len) {
@@ -946,7 +1249,7 @@ Vector<int> String::split_ints_mk(const Vector<String> &p_splitters, bool p_allo
return ret;
}
-String String::join(Vector<String> parts) {
+String String::join(Vector<String> parts) const {
String ret;
for (int i = 0; i < parts.size(); ++i) {
if (i > 0) {
@@ -957,11 +1260,11 @@ String String::join(Vector<String> parts) {
return ret;
}
-CharType String::char_uppercase(CharType p_char) {
+char32_t String::char_uppercase(char32_t p_char) {
return _find_upper(p_char);
}
-CharType String::char_lowercase(CharType p_char) {
+char32_t String::char_lowercase(char32_t p_char) {
return _find_lower(p_char);
}
@@ -969,8 +1272,8 @@ String String::to_upper() const {
String upper = *this;
for (int i = 0; i < upper.size(); i++) {
- const CharType s = upper[i];
- const CharType t = _find_upper(s);
+ const char32_t s = upper[i];
+ const char32_t t = _find_upper(s);
if (s != t) { // avoid copy on write
upper[i] = t;
}
@@ -983,8 +1286,8 @@ String String::to_lower() const {
String lower = *this;
for (int i = 0; i < lower.size(); i++) {
- const CharType s = lower[i];
- const CharType t = _find_lower(s);
+ const char32_t s = lower[i];
+ const char32_t t = _find_lower(s);
if (s != t) { // avoid copy on write
lower[i] = t;
}
@@ -993,38 +1296,23 @@ String String::to_lower() const {
return lower;
}
-const CharType *String::c_str() const {
- static const CharType zero = 0;
-
- return size() ? &operator[](0) : &zero;
-}
-
-String String::md5(const uint8_t *p_md5) {
- return String::hex_encode_buffer(p_md5, 16);
-}
-
-String String::hex_encode_buffer(const uint8_t *p_buffer, int p_len) {
- static const char hex[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
-
- String ret;
- char v[2] = { 0, 0 };
-
- for (int i = 0; i < p_len; i++) {
- v[0] = hex[p_buffer[i] >> 4];
- ret += v;
- v[0] = hex[p_buffer[i] & 0xF];
- ret += v;
- }
-
- return ret;
-}
-
-String String::chr(CharType p_char) {
- CharType c[2] = { p_char, 0 };
+String String::chr(char32_t p_char) {
+ char32_t c[2] = { p_char, 0 };
return String(c);
}
String String::num(double p_num, int p_decimals) {
+ if (Math::is_nan(p_num)) {
+ return "nan";
+ }
+
+ if (Math::is_inf(p_num)) {
+ if (signbit(p_num)) {
+ return "-inf";
+ } else {
+ return "inf";
+ }
+ }
#ifndef NO_USE_STDLIB
if (p_decimals > 16) {
@@ -1103,7 +1391,7 @@ String String::num(double p_num, int p_decimals) {
/* decimal part */
if (p_decimals > 0 || (p_decimals == -1 && (int)p_num != p_num)) {
- double dec = p_num - (float)((int)p_num);
+ double dec = p_num - (double)((int)p_num);
int digit = 0;
if (p_decimals > MAX_DIGITS)
@@ -1122,7 +1410,7 @@ String String::num(double p_num, int p_decimals) {
if (digit == MAX_DIGITS) //no point in going to infinite
break;
- if ((dec - (float)((int)dec)) < 1e-6)
+ if ((dec - (double)((int)dec)) < 1e-6)
break;
}
@@ -1156,7 +1444,7 @@ String String::num(double p_num, int p_decimals) {
s = "0";
else {
while (intn) {
- CharType num = '0' + (intn % 10);
+ char32_t num = '0' + (intn % 10);
intn /= 10;
s = num + s;
}
@@ -1185,7 +1473,7 @@ String String::num_int64(int64_t p_num, int base, bool capitalize_hex) {
}
String s;
s.resize(chars + 1);
- CharType *c = s.ptrw();
+ char32_t *c = s.ptrw();
c[chars] = 0;
n = p_num;
do {
@@ -1218,7 +1506,7 @@ String String::num_uint64(uint64_t p_num, int base, bool capitalize_hex) {
String s;
s.resize(chars + 1);
- CharType *c = s.ptrw();
+ char32_t *c = s.ptrw();
c[chars] = 0;
n = p_num;
do {
@@ -1237,6 +1525,18 @@ String String::num_uint64(uint64_t p_num, int base, bool capitalize_hex) {
}
String String::num_real(double p_num) {
+ if (Math::is_nan(p_num)) {
+ return "nan";
+ }
+
+ if (Math::is_inf(p_num)) {
+ if (signbit(p_num)) {
+ return "-inf";
+ } else {
+ return "inf";
+ }
+ }
+
String s;
String sd;
/* integer part */
@@ -1248,7 +1548,7 @@ String String::num_real(double p_num) {
/* decimal part */
if ((int)p_num != p_num) {
- double dec = p_num - (float)((int)p_num);
+ double dec = p_num - (double)((int)p_num);
int digit = 0;
int decimals = MAX_DIGITS;
@@ -1262,7 +1562,7 @@ String String::num_real(double p_num) {
dec_max = dec_max * 10 + 9;
digit++;
- if ((dec - (float)((int)dec)) < 1e-6) {
+ if ((dec - (double)((int)dec)) < 1e-6) {
break;
}
@@ -1299,7 +1599,7 @@ String String::num_real(double p_num) {
s = "0";
} else {
while (intn) {
- CharType num = '0' + (intn % 10);
+ char32_t num = '0' + (intn % 10);
intn /= 10;
s = num + s;
}
@@ -1313,6 +1613,17 @@ String String::num_real(double p_num) {
}
String String::num_scientific(double p_num) {
+ if (Math::is_nan(p_num)) {
+ return "nan";
+ }
+
+ if (Math::is_inf(p_num)) {
+ if (signbit(p_num)) {
+ return "-inf";
+ } else {
+ return "inf";
+ }
+ }
#ifndef NO_USE_STDLIB
char buf[256];
@@ -1342,6 +1653,26 @@ String String::num_scientific(double p_num) {
#endif
}
+String String::md5(const uint8_t *p_md5) {
+ return String::hex_encode_buffer(p_md5, 16);
+}
+
+String String::hex_encode_buffer(const uint8_t *p_buffer, int p_len) {
+ static const char hex[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
+
+ String ret;
+ char v[2] = { 0, 0 };
+
+ for (int i = 0; i < p_len; i++) {
+ v[0] = hex[p_buffer[i] >> 4];
+ ret += v;
+ v[0] = hex[p_buffer[i] & 0xF];
+ ret += v;
+ }
+
+ return ret;
+}
+
CharString String::ascii(bool p_allow_extended) const {
if (!length()) {
return CharString();
@@ -1351,7 +1682,13 @@ CharString String::ascii(bool p_allow_extended) const {
cs.resize(size());
for (int i = 0; i < size(); i++) {
- cs[i] = operator[](i);
+ char32_t c = operator[](i);
+ if ((c <= 0x7f) || (c <= 0xff && p_allow_extended)) {
+ cs[i] = c;
+ } else {
+ print_error("Unicode parsing error: Cannot represent " + num_int64(c, 16) + " as ASCII/Latin-1 character.");
+ cs[i] = 0x20;
+ }
}
return cs;
@@ -1365,7 +1702,7 @@ String String::utf8(const char *p_utf8, int p_len) {
}
bool String::parse_utf8(const char *p_utf8, int p_len) {
-#define _UNICERROR(m_err) print_line("Unicode parsing error: " + String(m_err) + ". Is the string valid UTF-8?");
+#define _UNICERROR(m_err) print_error("Unicode parsing error: " + String(m_err) + ". Is the string valid UTF-8?");
if (!p_utf8) {
return true;
@@ -1378,9 +1715,9 @@ bool String::parse_utf8(const char *p_utf8, int p_len) {
/* HANDLE BOM (Byte Order Mark) */
if (p_len < 0 || p_len >= 3) {
- bool has_bom = uint8_t(p_utf8[0]) == 0xEF && uint8_t(p_utf8[1]) == 0xBB && uint8_t(p_utf8[2]) == 0xBF;
+ bool has_bom = uint8_t(p_utf8[0]) == 0xef && uint8_t(p_utf8[1]) == 0xbb && uint8_t(p_utf8[2]) == 0xbf;
if (has_bom) {
- //just skip it
+ //8-bit encoding, byte order has no meaning in UTF-8, just skip it
if (p_len >= 0) {
p_len -= 3;
}
@@ -1399,24 +1736,19 @@ bool String::parse_utf8(const char *p_utf8, int p_len) {
/* Determine the number of characters in sequence */
if ((c & 0x80) == 0) {
skip = 0;
- } else if ((c & 0xE0) == 0xC0) {
+ } else if ((c & 0xe0) == 0xc0) {
skip = 1;
- } else if ((c & 0xF0) == 0xE0) {
+ } else if ((c & 0xf0) == 0xe0) {
skip = 2;
- } else if ((c & 0xF8) == 0xF0) {
+ } else if ((c & 0xf8) == 0xf0) {
skip = 3;
- } else if ((c & 0xFC) == 0xF8) {
- skip = 4;
- } else if ((c & 0xFE) == 0xFC) {
- skip = 5;
} else {
- _UNICERROR("invalid skip");
+ _UNICERROR("invalid skip at " + num_int64(cstr_size));
return true; //invalid utf8
}
- if (skip == 1 && (c & 0x1E) == 0) {
- //printf("overlong rejected\n");
- _UNICERROR("overlong rejected");
+ if (skip == 1 && (c & 0x1e) == 0) {
+ _UNICERROR("overlong rejected at " + num_int64(cstr_size));
return true; //reject overlong
}
@@ -1442,7 +1774,7 @@ bool String::parse_utf8(const char *p_utf8, int p_len) {
}
resize(str_size + 1);
- CharType *dst = ptrw();
+ char32_t *dst = ptrw();
dst[str_size] = 0;
while (cstr_size) {
@@ -1451,19 +1783,14 @@ bool String::parse_utf8(const char *p_utf8, int p_len) {
/* Determine the number of characters in sequence */
if ((*p_utf8 & 0x80) == 0) {
len = 1;
- } else if ((*p_utf8 & 0xE0) == 0xC0) {
+ } else if ((*p_utf8 & 0xe0) == 0xc0) {
len = 2;
- } else if ((*p_utf8 & 0xF0) == 0xE0) {
+ } else if ((*p_utf8 & 0xf0) == 0xe0) {
len = 3;
- } else if ((*p_utf8 & 0xF8) == 0xF0) {
+ } else if ((*p_utf8 & 0xf8) == 0xf0) {
len = 4;
- } else if ((*p_utf8 & 0xFC) == 0xF8) {
- len = 5;
- } else if ((*p_utf8 & 0xFE) == 0xFC) {
- len = 6;
} else {
_UNICERROR("invalid len");
-
return true; //invalid UTF8
}
@@ -1473,7 +1800,6 @@ bool String::parse_utf8(const char *p_utf8, int p_len) {
}
if (len == 2 && (*p_utf8 & 0x1E) == 0) {
- //printf("overlong rejected\n");
_UNICERROR("no space left");
return true; //reject overlong
}
@@ -1485,24 +1811,23 @@ bool String::parse_utf8(const char *p_utf8, int p_len) {
if (len == 1) {
unichar = *p_utf8;
} else {
- unichar = (0xFF >> (len + 1)) & *p_utf8;
+ unichar = (0xff >> (len + 1)) & *p_utf8;
for (int i = 1; i < len; i++) {
- if ((p_utf8[i] & 0xC0) != 0x80) {
+ if ((p_utf8[i] & 0xc0) != 0x80) {
_UNICERROR("invalid utf8");
return true; //invalid utf8
}
- if (unichar == 0 && i == 2 && ((p_utf8[i] & 0x7F) >> (7 - len)) == 0) {
+ if (unichar == 0 && i == 2 && ((p_utf8[i] & 0x7f) >> (7 - len)) == 0) {
_UNICERROR("invalid utf8 overlong");
return true; //no overlong
}
- unichar = (unichar << 6) | (p_utf8[i] & 0x3F);
+ unichar = (unichar << 6) | (p_utf8[i] & 0x3f);
}
}
-
- //printf("char %i, len %i\n",unichar,len);
- if (sizeof(wchar_t) == 2 && unichar > 0xFFFF) {
- unichar = ' '; //too long for windows
+ if (unichar >= 0xd800 && unichar <= 0xdfff) {
+ _UNICERROR("invalid code point");
+ return CharString();
}
*(dst++) = unichar;
@@ -1511,6 +1836,7 @@ bool String::parse_utf8(const char *p_utf8, int p_len) {
}
return false;
+#undef _UNICERROR
}
CharString String::utf8() const {
@@ -1519,7 +1845,7 @@ CharString String::utf8() const {
return CharString();
}
- const CharType *d = &operator[](0);
+ const char32_t *d = &operator[](0);
int fl = 0;
for (int i = 0; i < l; i++) {
uint32_t c = d[i];
@@ -1529,13 +1855,15 @@ CharString String::utf8() const {
fl += 2;
} else if (c <= 0xffff) { // 16 bits
fl += 3;
- } else if (c <= 0x001fffff) { // 21 bits
+ } else if (c <= 0x0010ffff) { // 21 bits
fl += 4;
-
- } else if (c <= 0x03ffffff) { // 26 bits
- fl += 5;
- } else if (c <= 0x7fffffff) { // 31 bits
- fl += 6;
+ } else {
+ print_error("Unicode parsing error: Invalid unicode codepoint " + num_int64(c, 16) + ".");
+ return CharString();
+ }
+ if (c >= 0xd800 && c <= 0xdfff) {
+ print_error("Unicode parsing error: Invalid unicode codepoint " + num_int64(c, 16) + ".");
+ return CharString();
}
}
@@ -1555,35 +1883,17 @@ CharString String::utf8() const {
if (c <= 0x7f) { // 7 bits.
APPEND_CHAR(c);
} else if (c <= 0x7ff) { // 11 bits
-
APPEND_CHAR(uint32_t(0xc0 | ((c >> 6) & 0x1f))); // Top 5 bits.
APPEND_CHAR(uint32_t(0x80 | (c & 0x3f))); // Bottom 6 bits.
} else if (c <= 0xffff) { // 16 bits
-
APPEND_CHAR(uint32_t(0xe0 | ((c >> 12) & 0x0f))); // Top 4 bits.
APPEND_CHAR(uint32_t(0x80 | ((c >> 6) & 0x3f))); // Middle 6 bits.
APPEND_CHAR(uint32_t(0x80 | (c & 0x3f))); // Bottom 6 bits.
- } else if (c <= 0x001fffff) { // 21 bits
-
+ } else { // 21 bits
APPEND_CHAR(uint32_t(0xf0 | ((c >> 18) & 0x07))); // Top 3 bits.
APPEND_CHAR(uint32_t(0x80 | ((c >> 12) & 0x3f))); // Upper middle 6 bits.
APPEND_CHAR(uint32_t(0x80 | ((c >> 6) & 0x3f))); // Lower middle 6 bits.
APPEND_CHAR(uint32_t(0x80 | (c & 0x3f))); // Bottom 6 bits.
- } else if (c <= 0x03ffffff) { // 26 bits
-
- APPEND_CHAR(uint32_t(0xf8 | ((c >> 24) & 0x03))); // Top 2 bits.
- APPEND_CHAR(uint32_t(0x80 | ((c >> 18) & 0x3f))); // Upper middle 6 bits.
- APPEND_CHAR(uint32_t(0x80 | ((c >> 12) & 0x3f))); // middle 6 bits.
- APPEND_CHAR(uint32_t(0x80 | ((c >> 6) & 0x3f))); // Lower middle 6 bits.
- APPEND_CHAR(uint32_t(0x80 | (c & 0x3f))); // Bottom 6 bits.
- } else if (c <= 0x7fffffff) { // 31 bits
-
- APPEND_CHAR(uint32_t(0xfc | ((c >> 30) & 0x01))); // Top 1 bit.
- APPEND_CHAR(uint32_t(0x80 | ((c >> 24) & 0x3f))); // Upper upper middle 6 bits.
- APPEND_CHAR(uint32_t(0x80 | ((c >> 18) & 0x3f))); // Lower upper middle 6 bits.
- APPEND_CHAR(uint32_t(0x80 | ((c >> 12) & 0x3f))); // Upper lower middle 6 bits.
- APPEND_CHAR(uint32_t(0x80 | ((c >> 6) & 0x3f))); // Lower lower middle 6 bits.
- APPEND_CHAR(uint32_t(0x80 | (c & 0x3f))); // Bottom 6 bits.
}
}
#undef APPEND_CHAR
@@ -1592,21 +1902,191 @@ CharString String::utf8() const {
return utf8s;
}
-/*
-String::String(CharType p_char) {
+String String::utf16(const char16_t *p_utf16, int p_len) {
+ String ret;
+ ret.parse_utf16(p_utf16, p_len);
- shared=nullptr;
- copy_from(p_char);
+ return ret;
}
+bool String::parse_utf16(const char16_t *p_utf16, int p_len) {
+#define _UNICERROR(m_err) print_error("Unicode parsing error: " + String(m_err) + ". Is the string valid UTF-16?");
+
+ if (!p_utf16) {
+ return true;
+ }
+
+ String aux;
-*/
+ int cstr_size = 0;
+ int str_size = 0;
+
+ /* HANDLE BOM (Byte Order Mark) */
+ bool byteswap = false; // assume correct endianness if no BOM found
+ if (p_len < 0 || p_len >= 1) {
+ bool has_bom = false;
+ if (uint16_t(p_utf16[0]) == 0xfeff) { // correct BOM, read as is
+ has_bom = true;
+ byteswap = false;
+ } else if (uint16_t(p_utf16[0]) == 0xfffe) { // backwards BOM, swap bytes
+ has_bom = true;
+ byteswap = true;
+ }
+ if (has_bom) {
+ if (p_len >= 0) {
+ p_len -= 1;
+ }
+ p_utf16 += 1;
+ }
+ }
+
+ {
+ const char16_t *ptrtmp = p_utf16;
+ const char16_t *ptrtmp_limit = &p_utf16[p_len];
+ int skip = 0;
+ while (ptrtmp != ptrtmp_limit && *ptrtmp) {
+ uint32_t c = (byteswap) ? BSWAP16(*ptrtmp) : *ptrtmp;
+ if (skip == 0) {
+ if ((c & 0xfffffc00) == 0xd800) {
+ skip = 1; // lead surrogate
+ } else if ((c & 0xfffffc00) == 0xdc00) {
+ _UNICERROR("invalid utf16 surrogate at " + num_int64(cstr_size));
+ return true; // invalid UTF16
+ } else {
+ skip = 0;
+ }
+ str_size++;
+ } else {
+ if ((c & 0xfffffc00) == 0xdc00) { // trail surrogate
+ --skip;
+ } else {
+ _UNICERROR("invalid utf16 surrogate at " + num_int64(cstr_size));
+ return true; // invalid UTF16
+ }
+ }
+
+ cstr_size++;
+ ptrtmp++;
+ }
+
+ if (skip) {
+ _UNICERROR("no space left");
+ return true; // not enough space
+ }
+ }
+
+ if (str_size == 0) {
+ clear();
+ return false;
+ }
+
+ resize(str_size + 1);
+ char32_t *dst = ptrw();
+ dst[str_size] = 0;
+
+ while (cstr_size) {
+ int len = 0;
+ uint32_t c = (byteswap) ? BSWAP16(*p_utf16) : *p_utf16;
+
+ if ((c & 0xfffffc00) == 0xd800) {
+ len = 2;
+ } else {
+ len = 1;
+ }
+
+ if (len > cstr_size) {
+ _UNICERROR("no space left");
+ return true; //not enough space
+ }
+
+ uint32_t unichar = 0;
+ if (len == 1) {
+ unichar = c;
+ } else {
+ uint32_t c2 = (byteswap) ? BSWAP16(p_utf16[1]) : p_utf16[1];
+ unichar = (c << 10UL) + c2 - ((0xd800 << 10UL) + 0xdc00 - 0x10000);
+ }
+
+ *(dst++) = unichar;
+ cstr_size -= len;
+ p_utf16 += len;
+ }
+
+ return false;
+#undef _UNICERROR
+}
+
+Char16String String::utf16() const {
+ int l = length();
+ if (!l) {
+ return Char16String();
+ }
+
+ const char32_t *d = &operator[](0);
+ int fl = 0;
+ for (int i = 0; i < l; i++) {
+ uint32_t c = d[i];
+ if (c <= 0xffff) { // 16 bits.
+ fl += 1;
+ } else if (c <= 0x10ffff) { // 32 bits.
+ fl += 2;
+ } else {
+ print_error("Unicode parsing error: Invalid unicode codepoint " + num_int64(c, 16) + ".");
+ return Char16String();
+ }
+ if (c >= 0xd800 && c <= 0xdfff) {
+ print_error("Unicode parsing error: Invalid unicode codepoint " + num_int64(c, 16) + ".");
+ return Char16String();
+ }
+ }
+
+ Char16String utf16s;
+ if (fl == 0) {
+ return utf16s;
+ }
+
+ utf16s.resize(fl + 1);
+ uint16_t *cdst = (uint16_t *)utf16s.get_data();
+
+#define APPEND_CHAR(m_c) *(cdst++) = m_c
+
+ for (int i = 0; i < l; i++) {
+ uint32_t c = d[i];
+
+ if (c <= 0xffff) { // 16 bits.
+ APPEND_CHAR(c);
+ } else { // 32 bits.
+ APPEND_CHAR(uint32_t((c >> 10) + 0xd7c0)); // lead surrogate.
+ APPEND_CHAR(uint32_t((c & 0x3ff) | 0xdc00)); // trail surrogate.
+ }
+ }
+#undef APPEND_CHAR
+ *cdst = 0; //trailing zero
+
+ return utf16s;
+}
String::String(const char *p_str) {
copy_from(p_str);
}
-String::String(const CharType *p_str, int p_clip_to_len) {
+String::String(const wchar_t *p_str) {
+ copy_from(p_str);
+}
+
+String::String(const char32_t *p_str) {
+ copy_from(p_str);
+}
+
+String::String(const char *p_str, int p_clip_to_len) {
+ copy_from(p_str, p_clip_to_len);
+}
+
+String::String(const wchar_t *p_str, int p_clip_to_len) {
+ copy_from(p_str, p_clip_to_len);
+}
+
+String::String(const char32_t *p_str, int p_clip_to_len) {
copy_from(p_str, p_clip_to_len);
}
@@ -1614,7 +2094,6 @@ String::String(const StrRange &p_range) {
if (!p_range.c_str) {
return;
}
-
copy_from(p_range.c_str, p_range.len);
}
@@ -1623,7 +2102,7 @@ int64_t String::hex_to_int(bool p_with_prefix) const {
return 0;
}
- const CharType *s = ptr();
+ const char32_t *s = ptr();
int64_t sign = s[0] == '-' ? -1 : 1;
@@ -1641,7 +2120,7 @@ int64_t String::hex_to_int(bool p_with_prefix) const {
int64_t hex = 0;
while (*s) {
- CharType c = LOWERCASE(*s);
+ char32_t c = LOWERCASE(*s);
int64_t n;
if (c >= '0' && c <= '9') {
n = c - '0';
@@ -1666,7 +2145,7 @@ int64_t String::bin_to_int(bool p_with_prefix) const {
return 0;
}
- const CharType *s = ptr();
+ const char32_t *s = ptr();
int64_t sign = s[0] == '-' ? -1 : 1;
@@ -1684,7 +2163,7 @@ int64_t String::bin_to_int(bool p_with_prefix) const {
int64_t binary = 0;
while (*s) {
- CharType c = LOWERCASE(*s);
+ char32_t c = LOWERCASE(*s);
int64_t n;
if (c == '0' || c == '1') {
n = c - '0';
@@ -1713,7 +2192,7 @@ int64_t String::to_int() const {
int64_t sign = 1;
for (int i = 0; i < to; i++) {
- CharType c = operator[](i);
+ char32_t c = operator[](i);
if (c >= '0' && c <= '9') {
bool overflow = (integer > INT64_MAX / 10) || (integer == INT64_MAX / 10 && ((sign == 1 && c > '7') || (sign == -1 && c > '8')));
ERR_FAIL_COND_V_MSG(overflow, sign == 1 ? INT64_MAX : INT64_MIN, "Cannot represent " + *this + " as 64-bit integer, provided value is " + (sign == 1 ? "too big." : "too small."));
@@ -1759,6 +2238,37 @@ int64_t String::to_int(const char *p_str, int p_len) {
return integer * sign;
}
+int64_t String::to_int(const wchar_t *p_str, int p_len) {
+ int to = 0;
+ if (p_len >= 0) {
+ to = p_len;
+ } else {
+ while (p_str[to] != 0 && p_str[to] != '.') {
+ to++;
+ }
+ }
+
+ int64_t integer = 0;
+ int64_t sign = 1;
+
+ for (int i = 0; i < to; i++) {
+ wchar_t c = p_str[i];
+ if (c >= '0' && c <= '9') {
+ bool overflow = (integer > INT64_MAX / 10) || (integer == INT64_MAX / 10 && ((sign == 1 && c > '7') || (sign == -1 && c > '8')));
+ ERR_FAIL_COND_V_MSG(overflow, sign == 1 ? INT64_MAX : INT64_MIN, "Cannot represent " + String(p_str).substr(0, to) + " as integer, provided value is " + (sign == 1 ? "too big." : "too small."));
+ integer *= 10;
+ integer += c - '0';
+
+ } else if (c == '-' && integer == 0) {
+ sign = -sign;
+ } else if (c != ' ') {
+ break;
+ }
+ }
+
+ return integer * sign;
+}
+
bool String::is_numeric() const {
if (length() == 0) {
return false;
@@ -1770,14 +2280,13 @@ bool String::is_numeric() const {
}
bool dot = false;
for (int i = s; i < length(); i++) {
- CharType c = operator[](i);
+ char32_t c = operator[](i);
if (c == '.') {
if (dot) {
return false;
}
dot = true;
- }
- if (c < '0' || c > '9') {
+ } else if (c < '0' || c > '9') {
return false;
}
}
@@ -1939,11 +2448,11 @@ static double built_in_strtod(const C *string, /* A decimal ASCII floating-point
}
expSign = false;
}
- if (!IS_DIGIT(CharType(*p))) {
+ if (!IS_DIGIT(char32_t(*p))) {
p = pExp;
goto done;
}
- while (IS_DIGIT(CharType(*p))) {
+ while (IS_DIGIT(char32_t(*p))) {
exp = exp * 10 + (*p - '0');
p += 1;
}
@@ -2000,24 +2509,19 @@ done:
#define READING_EXP 3
#define READING_DONE 4
-double String::to_double(const char *p_str) {
-#ifndef NO_USE_STDLIB
+double String::to_float(const char *p_str) {
return built_in_strtod<char>(p_str);
-//return atof(p_str); DOES NOT WORK ON ANDROID(??)
-#else
- return built_in_strtod<char>(p_str);
-#endif
}
-float String::to_float() const {
- return to_double();
+double String::to_float(const char32_t *p_str, const char32_t **r_end) {
+ return built_in_strtod<char32_t>(p_str, (char32_t **)r_end);
}
-double String::to_double(const CharType *p_str, const CharType **r_end) {
- return built_in_strtod<CharType>(p_str, (CharType **)r_end);
+double String::to_float(const wchar_t *p_str, const wchar_t **r_end) {
+ return built_in_strtod<wchar_t>(p_str, (wchar_t **)r_end);
}
-int64_t String::to_int(const CharType *p_str, int p_len, bool p_clamp) {
+int64_t String::to_int(const char32_t *p_str, int p_len, bool p_clamp) {
if (p_len == 0 || !p_str[0]) {
return 0;
}
@@ -2027,11 +2531,11 @@ int64_t String::to_int(const CharType *p_str, int p_len, bool p_clamp) {
int64_t sign = 1;
int reading = READING_SIGN;
- const CharType *str = p_str;
- const CharType *limit = &p_str[p_len];
+ const char32_t *str = p_str;
+ const char32_t *limit = &p_str[p_len];
while (*str && reading != READING_DONE && str != limit) {
- CharType c = *(str++);
+ char32_t c = *(str++);
switch (reading) {
case READING_SIGN: {
if (c >= '0' && c <= '9') {
@@ -2081,30 +2585,11 @@ int64_t String::to_int(const CharType *p_str, int p_len, bool p_clamp) {
return sign * integer;
}
-double String::to_double() const {
+double String::to_float() const {
if (empty()) {
return 0;
}
-#ifndef NO_USE_STDLIB
- return built_in_strtod<CharType>(c_str());
-//return wcstod(c_str(),nullptr ); DOES NOT WORK ON ANDROID :(
-#else
- return built_in_strtod<CharType>(c_str());
-#endif
-}
-
-bool operator==(const char *p_chr, const String &p_str) {
- return p_str == p_chr;
-}
-
-String operator+(const char *p_chr, const String &p_str) {
- String tmp = p_chr;
- tmp += p_str;
- return tmp;
-}
-
-String operator+(CharType p_chr, const String &p_str) {
- return (String::chr(p_chr) + p_str);
+ return built_in_strtod<char32_t>(get_data());
}
uint32_t String::hash(const char *p_cstr) {
@@ -2127,7 +2612,27 @@ uint32_t String::hash(const char *p_cstr, int p_len) {
return hashv;
}
-uint32_t String::hash(const CharType *p_cstr, int p_len) {
+uint32_t String::hash(const wchar_t *p_cstr, int p_len) {
+ uint32_t hashv = 5381;
+ for (int i = 0; i < p_len; i++) {
+ hashv = ((hashv << 5) + hashv) + p_cstr[i]; /* hash * 33 + c */
+ }
+
+ return hashv;
+}
+
+uint32_t String::hash(const wchar_t *p_cstr) {
+ uint32_t hashv = 5381;
+ uint32_t c;
+
+ while ((c = *p_cstr++)) {
+ hashv = ((hashv << 5) + hashv) + c; /* hash * 33 + c */
+ }
+
+ return hashv;
+}
+
+uint32_t String::hash(const char32_t *p_cstr, int p_len) {
uint32_t hashv = 5381;
for (int i = 0; i < p_len; i++) {
hashv = ((hashv << 5) + hashv) + p_cstr[i]; /* hash * 33 + c */
@@ -2136,7 +2641,7 @@ uint32_t String::hash(const CharType *p_cstr, int p_len) {
return hashv;
}
-uint32_t String::hash(const CharType *p_cstr) {
+uint32_t String::hash(const char32_t *p_cstr) {
uint32_t hashv = 5381;
uint32_t c;
@@ -2150,7 +2655,7 @@ uint32_t String::hash(const CharType *p_cstr) {
uint32_t String::hash() const {
/* simple djb2 hashing */
- const CharType *chr = c_str();
+ const char32_t *chr = get_data();
uint32_t hashv = 5381;
uint32_t c;
@@ -2164,7 +2669,7 @@ uint32_t String::hash() const {
uint64_t String::hash64() const {
/* simple djb2 hashing */
- const CharType *chr = c_str();
+ const char32_t *chr = get_data();
uint64_t hashv = 5381;
uint64_t c;
@@ -2276,7 +2781,7 @@ String String::substr(int p_from, int p_chars) const {
}
String s = String();
- s.copy_from_unchecked(&c_str()[p_from], p_chars);
+ s.copy_from_unchecked(&get_data()[p_from], p_chars);
return s;
}
@@ -2293,8 +2798,8 @@ int String::find(const String &p_str, int p_from) const {
return -1; // won't find anything!
}
- const CharType *src = c_str();
- const CharType *str = p_str.c_str();
+ const char32_t *src = get_data();
+ const char32_t *str = p_str.get_data();
for (int i = p_from; i <= (len - src_len); i++) {
bool found = true;
@@ -2331,7 +2836,7 @@ int String::find(const char *p_str, int p_from) const {
return -1; // won't find anything!
}
- const CharType *src = c_str();
+ const char32_t *src = get_data();
int src_len = 0;
while (p_str[src_len] != '\0') {
@@ -2339,7 +2844,7 @@ int String::find(const char *p_str, int p_from) const {
}
if (src_len == 1) {
- const char needle = p_str[0];
+ const char32_t needle = p_str[0];
for (int i = p_from; i < len; i++) {
if (src[i] == needle) {
@@ -2358,7 +2863,7 @@ int String::find(const char *p_str, int p_from) const {
return -1;
}
- if (src[read_pos] != p_str[j]) {
+ if (src[read_pos] != (char32_t)p_str[j]) {
found = false;
break;
}
@@ -2373,7 +2878,7 @@ int String::find(const char *p_str, int p_from) const {
return -1;
}
-int String::find_char(const CharType &p_char, int p_from) const {
+int String::find_char(const char32_t &p_char, int p_from) const {
return _cowdata.find(p_char, p_from);
}
@@ -2394,7 +2899,7 @@ int String::findmk(const Vector<String> &p_keys, int p_from, int *r_key) const {
return -1; // won't find anything!
}
- const CharType *src = c_str();
+ const char32_t *src = get_data();
for (int i = p_from; i < len; i++) {
bool found = true;
@@ -2403,7 +2908,7 @@ int String::findmk(const Vector<String> &p_keys, int p_from, int *r_key) const {
if (r_key) {
*r_key = k;
}
- const CharType *cmp = keys[k].c_str();
+ const char32_t *cmp = keys[k].get_data();
int l = keys[k].length();
for (int j = 0; j < l; j++) {
@@ -2443,7 +2948,7 @@ int String::findn(const String &p_str, int p_from) const {
return -1; // won't find anything!
}
- const CharType *srcd = c_str();
+ const char32_t *srcd = get_data();
for (int i = p_from; i <= (length() - src_len); i++) {
bool found = true;
@@ -2455,8 +2960,8 @@ int String::findn(const String &p_str, int p_from) const {
return -1;
}
- CharType src = _find_lower(srcd[read_pos]);
- CharType dst = _find_lower(p_str[j]);
+ char32_t src = _find_lower(srcd[read_pos]);
+ char32_t dst = _find_lower(p_str[j]);
if (src != dst) {
found = false;
@@ -2493,7 +2998,7 @@ int String::rfind(const String &p_str, int p_from) const {
return -1; // won't find anything!
}
- const CharType *src = c_str();
+ const char32_t *src = get_data();
for (int i = p_from; i >= 0; i--) {
bool found = true;
@@ -2540,7 +3045,7 @@ int String::rfindn(const String &p_str, int p_from) const {
return -1; // won't find anything!
}
- const CharType *src = c_str();
+ const char32_t *src = get_data();
for (int i = p_from; i >= 0; i--) {
bool found = true;
@@ -2552,8 +3057,8 @@ int String::rfindn(const String &p_str, int p_from) const {
return -1;
}
- CharType srcc = _find_lower(src[read_pos]);
- CharType dstc = _find_lower(p_str[j]);
+ char32_t srcc = _find_lower(src[read_pos]);
+ char32_t dstc = _find_lower(p_str[j]);
if (srcc != dstc) {
found = false;
@@ -2587,8 +3092,8 @@ bool String::begins_with(const String &p_string) const {
return true;
}
- const CharType *src = &p_string[0];
- const CharType *str = &operator[](0);
+ const char32_t *src = &p_string[0];
+ const char32_t *str = &operator[](0);
int i = 0;
for (; i < l; i++) {
@@ -2607,11 +3112,11 @@ bool String::begins_with(const char *p_string) const {
return false;
}
- const CharType *str = &operator[](0);
+ const char32_t *str = &operator[](0);
int i = 0;
while (*p_string && i < l) {
- if (*p_string != str[i]) {
+ if ((char32_t)*p_string != str[i]) {
return false;
}
i++;
@@ -2655,7 +3160,7 @@ int String::_count(const String &p_string, int p_from, int p_to, bool p_case_ins
}
if (p_from == 0 && p_to == len) {
str = String();
- str.copy_from_unchecked(&c_str()[0], len);
+ str.copy_from_unchecked(&get_data()[0], len);
} else {
str = substr(p_from, p_to - p_from);
}
@@ -2693,14 +3198,14 @@ bool String::_base_is_subsequence_of(const String &p_string, bool case_insensiti
return false;
}
- const CharType *src = &operator[](0);
- const CharType *tgt = &p_string[0];
+ const char32_t *src = &operator[](0);
+ const char32_t *tgt = &p_string[0];
for (; *src && *tgt; tgt++) {
bool match = false;
if (case_insensitive) {
- CharType srcc = _find_lower(*src);
- CharType tgtc = _find_lower(*tgt);
+ char32_t srcc = _find_lower(*src);
+ char32_t tgtc = _find_lower(*tgt);
match = srcc == tgtc;
} else {
match = *src == *tgt;
@@ -2746,8 +3251,8 @@ float String::similarity(const String &p_string) const {
int src_size = src_bigrams.size();
int tgt_size = tgt_bigrams.size();
- float sum = src_size + tgt_size;
- float inter = 0;
+ double sum = src_size + tgt_size;
+ double inter = 0;
for (int i = 0; i < src_size; i++) {
for (int j = 0; j < tgt_size; j++) {
if (src_bigrams[i] == tgt_bigrams[j]) {
@@ -2760,7 +3265,7 @@ float String::similarity(const String &p_string) const {
return (2.0f * inter) / sum;
}
-static bool _wildcard_match(const CharType *p_pattern, const CharType *p_string, bool p_case_sensitive) {
+static bool _wildcard_match(const char32_t *p_pattern, const char32_t *p_string, bool p_case_sensitive) {
switch (*p_pattern) {
case '\0':
return !*p_string;
@@ -2779,14 +3284,14 @@ bool String::match(const String &p_wildcard) const {
return false;
}
- return _wildcard_match(p_wildcard.c_str(), c_str(), true);
+ return _wildcard_match(p_wildcard.get_data(), get_data(), true);
}
bool String::matchn(const String &p_wildcard) const {
if (!p_wildcard.length() || !length()) {
return false;
}
- return _wildcard_match(p_wildcard.c_str(), c_str(), false);
+ return _wildcard_match(p_wildcard.get_data(), get_data(), false);
}
String String::format(const Variant &values, String placeholder) const {
@@ -2936,9 +3441,10 @@ String String::repeat(int p_count) const {
ERR_FAIL_COND_V_MSG(p_count < 0, "", "Parameter count should be a positive number.");
String new_string;
- const CharType *src = this->c_str();
+ const char32_t *src = this->get_data();
new_string.resize(length() * p_count + 1);
+ new_string[length() * p_count] = 0;
for (int i = 0; i < p_count; i++) {
for (int j = 0; j < length(); j++) {
@@ -2973,7 +3479,7 @@ String String::right(int p_pos) const {
return substr(p_pos, (length() - p_pos));
}
-CharType String::ord_at(int p_idx) const {
+char32_t String::ord_at(int p_idx) const {
ERR_FAIL_INDEX_V(p_idx, length(), 0);
return operator[](p_idx);
}
@@ -2987,7 +3493,7 @@ String String::dedent() const {
int indent_stop = -1;
for (int i = 0; i < length(); i++) {
- CharType c = operator[](i);
+ char32_t c = operator[](i);
if (c == '\n') {
if (has_text) {
new_string += substr(indent_stop, i - indent_stop);
@@ -3216,7 +3722,7 @@ bool String::is_valid_identifier() const {
return false;
}
- const wchar_t *str = &operator[](0);
+ const char32_t *str = &operator[](0);
for (int i = 0; i < len; i++) {
if (i == 0) {
@@ -3235,36 +3741,14 @@ bool String::is_valid_identifier() const {
return true;
}
-//kind of poor should be rewritten properly
-
-String String::word_wrap(int p_chars_per_line) const {
- int from = 0;
- int last_space = 0;
- String ret;
- for (int i = 0; i < length(); i++) {
- if (i - from >= p_chars_per_line) {
- if (last_space == -1) {
- ret += substr(from, i - from + 1) + "\n";
- } else {
- ret += substr(from, last_space - from) + "\n";
- i = last_space; //rewind
- }
- from = i + 1;
- last_space = -1;
- } else if (operator[](i) == ' ' || operator[](i) == '\t') {
- last_space = i;
- } else if (operator[](i) == '\n') {
- ret += substr(from, i - from) + "\n";
- from = i + 1;
- last_space = -1;
- }
- }
-
- if (from < length()) {
- ret += substr(from, length());
+bool String::is_valid_string() const {
+ int l = length();
+ const char32_t *src = get_data();
+ bool valid = true;
+ for (int i = 0; i < l; i++) {
+ valid = valid && (src[i] < 0xd800 || (src[i] > 0xdfff && src[i] <= 0x10ffff));
}
-
- return ret;
+ return valid;
}
String String::http_escape() const {
@@ -3295,9 +3779,9 @@ String String::http_unescape() const {
String res;
for (int i = 0; i < length(); ++i) {
if (ord_at(i) == '%' && i + 2 < length()) {
- CharType ord1 = ord_at(i + 1);
+ char32_t ord1 = ord_at(i + 1);
if ((ord1 >= '0' && ord1 <= '9') || (ord1 >= 'A' && ord1 <= 'Z')) {
- CharType ord2 = ord_at(i + 2);
+ char32_t ord2 = ord_at(i + 2);
if ((ord2 >= '0' && ord2 <= '9') || (ord2 >= 'A' && ord2 <= 'Z')) {
char bytes[3] = { (char)ord1, (char)ord2, 0 };
res += (char)strtol(bytes, nullptr, 16);
@@ -3380,25 +3864,24 @@ String String::xml_escape(bool p_escape_quotes) const {
}
/*
for (int i=1;i<32;i++) {
-
char chr[2]={i,0};
str=str.replace(chr,"&#"+String::num(i)+";");
}*/
return str;
}
-static _FORCE_INLINE_ int _xml_unescape(const CharType *p_src, int p_src_len, CharType *p_dst) {
+static _FORCE_INLINE_ int _xml_unescape(const char32_t *p_src, int p_src_len, char32_t *p_dst) {
int len = 0;
while (p_src_len) {
if (*p_src == '&') {
int eat = 0;
if (p_src_len >= 4 && p_src[1] == '#') {
- CharType c = 0;
+ char32_t c = 0;
for (int i = 2; i < p_src_len; i++) {
eat = i + 1;
- CharType ct = p_src[i];
+ char32_t ct = p_src[i];
if (ct == ';') {
break;
} else if (ct >= '0' && ct <= '9') {
@@ -3474,12 +3957,12 @@ static _FORCE_INLINE_ int _xml_unescape(const CharType *p_src, int p_src_len, Ch
String String::xml_unescape() const {
String str;
int l = length();
- int len = _xml_unescape(c_str(), l, nullptr);
+ int len = _xml_unescape(get_data(), l, nullptr);
if (len == 0) {
return String();
}
str.resize(len + 1);
- _xml_unescape(c_str(), l, str.ptrw());
+ _xml_unescape(get_data(), l, str.ptrw());
str[len] = 0;
return str;
}
@@ -3600,7 +4083,7 @@ bool String::is_valid_hex_number(bool p_with_prefix) const {
}
for (int i = from; i < len; i++) {
- CharType c = operator[](i);
+ char32_t c = operator[](i);
if ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')) {
continue;
}
@@ -3915,7 +4398,7 @@ String String::percent_decode() const {
String String::property_name_encode() const {
// Escape and quote strings with extended ASCII or further Unicode characters
// as well as '"', '=' or ' ' (32)
- const CharType *cstr = c_str();
+ const char32_t *cstr = get_data();
for (int i = 0; cstr[i]; i++) {
if (cstr[i] == '=' || cstr[i] == '"' || cstr[i] < 33 || cstr[i] > 126) {
return "\"" + c_escape_multiline() + "\"";
@@ -3982,7 +4465,7 @@ String String::lpad(int min_length, const String &character) const {
// In case of an error, the string returned is the error description and "error" is true.
String String::sprintf(const Array &values, bool *error) const {
String formatted;
- CharType *self = (CharType *)c_str();
+ char32_t *self = (char32_t *)get_data();
bool in_format = false;
int value_index = 0;
int min_chars = 0;
@@ -3992,10 +4475,12 @@ String String::sprintf(const Array &values, bool *error) const {
bool left_justified = false;
bool show_sign = false;
- *error = true;
+ if (error) {
+ *error = true;
+ }
for (; *self; self++) {
- const CharType c = *self;
+ const char32_t c = *self;
if (in_format) { // We have % - lets see what else we get.
switch (c) {
@@ -4038,11 +4523,12 @@ String String::sprintf(const Array &values, bool *error) const {
int number_len = str.length();
// Padding.
+ int pad_chars_count = (value < 0 || show_sign) ? min_chars - 1 : min_chars;
String pad_char = pad_with_zeroes ? String("0") : String(" ");
if (left_justified) {
- str = str.rpad(min_chars, pad_char);
+ str = str.rpad(pad_chars_count, pad_char);
} else {
- str = str.lpad(min_chars, pad_char);
+ str = str.lpad(pad_chars_count, pad_char);
}
// Sign.
@@ -4132,9 +4618,11 @@ String String::sprintf(const Array &values, bool *error) const {
if (values[value_index].is_num()) {
int value = values[value_index];
if (value < 0) {
- return "unsigned byte integer is lower than maximum";
- } else if (value > 255) {
- return "unsigned byte integer is greater than maximum";
+ return "unsigned integer is lower than minimum";
+ } else if (value >= 0xd800 && value <= 0xdfff) {
+ return "unsigned integer is invalid Unicode character";
+ } else if (value > 0x10ffff) {
+ return "unsigned integer is greater than maximum";
}
str = chr(values[value_index]);
} else if (values[value_index].get_type() == Variant::STRING) {
@@ -4250,7 +4738,9 @@ String String::sprintf(const Array &values, bool *error) const {
return "not all arguments converted during string formatting";
}
- *error = false;
+ if (error) {
+ *error = false;
+ }
return formatted;
}
@@ -4266,32 +4756,122 @@ String String::unquote() const {
return substr(1, length() - 2);
}
+Vector<uint8_t> String::to_ascii_buffer() const {
+ const String *s = this;
+ if (s->empty()) {
+ return Vector<uint8_t>();
+ }
+ CharString charstr = s->ascii();
+
+ Vector<uint8_t> retval;
+ size_t len = charstr.length();
+ retval.resize(len);
+ uint8_t *w = retval.ptrw();
+ copymem(w, charstr.ptr(), len);
+
+ return retval;
+}
+
+Vector<uint8_t> String::to_utf8_buffer() const {
+ const String *s = this;
+ if (s->empty()) {
+ return Vector<uint8_t>();
+ }
+ CharString charstr = s->utf8();
+
+ Vector<uint8_t> retval;
+ size_t len = charstr.length();
+ retval.resize(len);
+ uint8_t *w = retval.ptrw();
+ copymem(w, charstr.ptr(), len);
+
+ return retval;
+}
+
+Vector<uint8_t> String::to_utf16_buffer() const {
+ const String *s = this;
+ if (s->empty()) {
+ return Vector<uint8_t>();
+ }
+ Char16String charstr = s->utf16();
+
+ Vector<uint8_t> retval;
+ size_t len = charstr.length() * 2;
+ retval.resize(len);
+ uint8_t *w = retval.ptrw();
+ copymem(w, (const void *)charstr.ptr(), len);
+
+ return retval;
+}
+
+Vector<uint8_t> String::to_utf32_buffer() const {
+ const String *s = this;
+ if (s->empty()) {
+ return Vector<uint8_t>();
+ }
+
+ Vector<uint8_t> retval;
+ size_t len = s->length() * 4;
+ retval.resize(len);
+ uint8_t *w = retval.ptrw();
+ copymem(w, (const void *)s->ptr(), len);
+
+ return retval;
+}
+
#ifdef TOOLS_ENABLED
-String TTR(const String &p_text) {
+String TTR(const String &p_text, const String &p_context) {
if (TranslationServer::get_singleton()) {
- return TranslationServer::get_singleton()->tool_translate(p_text);
+ return TranslationServer::get_singleton()->tool_translate(p_text, p_context);
}
return p_text;
}
-String DTR(const String &p_text) {
+String TTRN(const String &p_text, const String &p_text_plural, int p_n, const String &p_context) {
+ if (TranslationServer::get_singleton()) {
+ return TranslationServer::get_singleton()->tool_translate_plural(p_text, p_text_plural, p_n, p_context);
+ }
+
+ // Return message based on English plural rule if translation is not possible.
+ if (p_n == 1) {
+ return p_text;
+ }
+ return p_text_plural;
+}
+
+String DTR(const String &p_text, const String &p_context) {
// Comes straight from the XML, so remove indentation and any trailing whitespace.
const String text = p_text.dedent().strip_edges();
if (TranslationServer::get_singleton()) {
- return TranslationServer::get_singleton()->doc_translate(text);
+ return TranslationServer::get_singleton()->doc_translate(text, p_context);
}
return text;
}
+
+String DTRN(const String &p_text, const String &p_text_plural, int p_n, const String &p_context) {
+ const String text = p_text.dedent().strip_edges();
+ const String text_plural = p_text_plural.dedent().strip_edges();
+
+ if (TranslationServer::get_singleton()) {
+ return TranslationServer::get_singleton()->doc_translate_plural(text, text_plural, p_n, p_context);
+ }
+
+ // Return message based on English plural rule if translation is not possible.
+ if (p_n == 1) {
+ return text;
+ }
+ return text_plural;
+}
#endif
-String RTR(const String &p_text) {
+String RTR(const String &p_text, const String &p_context) {
if (TranslationServer::get_singleton()) {
- String rtr = TranslationServer::get_singleton()->tool_translate(p_text);
+ String rtr = TranslationServer::get_singleton()->tool_translate(p_text, p_context);
if (rtr == String() || rtr == p_text) {
- return TranslationServer::get_singleton()->translate(p_text);
+ return TranslationServer::get_singleton()->translate(p_text, p_context);
} else {
return rtr;
}
@@ -4299,3 +4879,20 @@ String RTR(const String &p_text) {
return p_text;
}
+
+String RTRN(const String &p_text, const String &p_text_plural, int p_n, const String &p_context) {
+ if (TranslationServer::get_singleton()) {
+ String rtr = TranslationServer::get_singleton()->tool_translate_plural(p_text, p_text_plural, p_n, p_context);
+ if (rtr == String() || rtr == p_text || rtr == p_text_plural) {
+ return TranslationServer::get_singleton()->translate_plural(p_text, p_text_plural, p_n, p_context);
+ } else {
+ return rtr;
+ }
+ }
+
+ // Return message based on English plural rule if translation is not possible.
+ if (p_n == 1) {
+ return p_text;
+ }
+ return p_text_plural;
+}
diff --git a/core/ustring.h b/core/string/ustring.h
index e745475f11..bfae16fe64 100644
--- a/core/ustring.h
+++ b/core/string/ustring.h
@@ -31,13 +31,18 @@
#ifndef USTRING_H
#define USTRING_H
-#include "core/array.h"
-#include "core/cowdata.h"
+#include "core/templates/cowdata.h"
+#include "core/templates/vector.h"
#include "core/typedefs.h"
-#include "core/vector.h"
+#include "core/variant/array.h"
+
+/*************************************************************************/
+/* CharProxy */
+/*************************************************************************/
template <class T>
class CharProxy {
+ friend class Char16String;
friend class CharString;
friend class String;
@@ -71,6 +76,54 @@ public:
}
};
+/*************************************************************************/
+/* Char16String */
+/*************************************************************************/
+
+class Char16String {
+ CowData<char16_t> _cowdata;
+ static const char16_t _null;
+
+public:
+ _FORCE_INLINE_ char16_t *ptrw() { return _cowdata.ptrw(); }
+ _FORCE_INLINE_ const char16_t *ptr() const { return _cowdata.ptr(); }
+ _FORCE_INLINE_ int size() const { return _cowdata.size(); }
+ Error resize(int p_size) { return _cowdata.resize(p_size); }
+
+ _FORCE_INLINE_ char16_t get(int p_index) const { return _cowdata.get(p_index); }
+ _FORCE_INLINE_ void set(int p_index, const char16_t &p_elem) { _cowdata.set(p_index, p_elem); }
+ _FORCE_INLINE_ const char16_t &operator[](int p_index) const {
+ if (unlikely(p_index == _cowdata.size())) {
+ return _null;
+ }
+
+ return _cowdata.get(p_index);
+ }
+ _FORCE_INLINE_ CharProxy<char16_t> operator[](int p_index) { return CharProxy<char16_t>(p_index, _cowdata); }
+
+ _FORCE_INLINE_ Char16String() {}
+ _FORCE_INLINE_ Char16String(const Char16String &p_str) { _cowdata._ref(p_str._cowdata); }
+ _FORCE_INLINE_ Char16String &operator=(const Char16String &p_str) {
+ _cowdata._ref(p_str._cowdata);
+ return *this;
+ }
+ _FORCE_INLINE_ Char16String(const char16_t *p_cstr) { copy_from(p_cstr); }
+
+ Char16String &operator=(const char16_t *p_cstr);
+ bool operator<(const Char16String &p_right) const;
+ Char16String &operator+=(char16_t p_char);
+ int length() const { return size() ? size() - 1 : 0; }
+ const char16_t *get_data() const;
+ operator const char16_t *() const { return get_data(); };
+
+protected:
+ void copy_from(const char16_t *p_cstr);
+};
+
+/*************************************************************************/
+/* CharString */
+/*************************************************************************/
+
class CharString {
CowData<char> _cowdata;
static const char _null;
@@ -94,7 +147,7 @@ public:
_FORCE_INLINE_ CharString() {}
_FORCE_INLINE_ CharString(const CharString &p_str) { _cowdata._ref(p_str._cowdata); }
- _FORCE_INLINE_ CharString operator=(const CharString &p_str) {
+ _FORCE_INLINE_ CharString &operator=(const CharString &p_str) {
_cowdata._ref(p_str._cowdata);
return *this;
}
@@ -111,85 +164,103 @@ protected:
void copy_from(const char *p_cstr);
};
-typedef wchar_t CharType;
+/*************************************************************************/
+/* String */
+/*************************************************************************/
struct StrRange {
- const CharType *c_str;
+ const char32_t *c_str;
int len;
- StrRange(const CharType *p_c_str = nullptr, int p_len = 0) {
+ StrRange(const char32_t *p_c_str = nullptr, int p_len = 0) {
c_str = p_c_str;
len = p_len;
}
};
class String {
- CowData<CharType> _cowdata;
- static const CharType _null;
+ CowData<char32_t> _cowdata;
+ static const char32_t _null;
void copy_from(const char *p_cstr);
- void copy_from(const CharType *p_cstr, const int p_clip_to = -1);
- void copy_from(const CharType &p_char);
- void copy_from_unchecked(const CharType *p_char, const int p_length);
+ void copy_from(const char *p_cstr, const int p_clip_to);
+ void copy_from(const wchar_t *p_cstr);
+ void copy_from(const wchar_t *p_cstr, const int p_clip_to);
+ void copy_from(const char32_t *p_cstr);
+ void copy_from(const char32_t *p_cstr, const int p_clip_to);
+
+ void copy_from(const char32_t &p_char);
+
+ void copy_from_unchecked(const char32_t *p_char, const int p_length);
+
bool _base_is_subsequence_of(const String &p_string, bool case_insensitive) const;
int _count(const String &p_string, int p_from, int p_to, bool p_case_insensitive) const;
public:
enum {
-
npos = -1 ///<for "some" compatibility with std::string (npos is a huge value in std::string)
};
- _FORCE_INLINE_ CharType *ptrw() { return _cowdata.ptrw(); }
- _FORCE_INLINE_ const CharType *ptr() const { return _cowdata.ptr(); }
+ _FORCE_INLINE_ char32_t *ptrw() { return _cowdata.ptrw(); }
+ _FORCE_INLINE_ const char32_t *ptr() const { return _cowdata.ptr(); }
void remove(int p_index) { _cowdata.remove(p_index); }
_FORCE_INLINE_ void clear() { resize(0); }
- _FORCE_INLINE_ CharType get(int p_index) const { return _cowdata.get(p_index); }
- _FORCE_INLINE_ void set(int p_index, const CharType &p_elem) { _cowdata.set(p_index, p_elem); }
+ _FORCE_INLINE_ char32_t get(int p_index) const { return _cowdata.get(p_index); }
+ _FORCE_INLINE_ void set(int p_index, const char32_t &p_elem) { _cowdata.set(p_index, p_elem); }
_FORCE_INLINE_ int size() const { return _cowdata.size(); }
Error resize(int p_size) { return _cowdata.resize(p_size); }
- _FORCE_INLINE_ const CharType &operator[](int p_index) const {
+ _FORCE_INLINE_ const char32_t &operator[](int p_index) const {
if (unlikely(p_index == _cowdata.size())) {
return _null;
}
return _cowdata.get(p_index);
}
- _FORCE_INLINE_ CharProxy<CharType> operator[](int p_index) { return CharProxy<CharType>(p_index, _cowdata); }
+ _FORCE_INLINE_ CharProxy<char32_t> operator[](int p_index) { return CharProxy<char32_t>(p_index, _cowdata); }
bool operator==(const String &p_str) const;
bool operator!=(const String &p_str) const;
String operator+(const String &p_str) const;
- //String operator+(CharType p_char) const;
String &operator+=(const String &);
- String &operator+=(CharType p_char);
+ String &operator+=(char32_t p_char);
String &operator+=(const char *p_str);
- String &operator+=(const CharType *p_str);
+ String &operator+=(const wchar_t *p_str);
+ String &operator+=(const char32_t *p_str);
/* Compatibility Operators */
void operator=(const char *p_str);
- void operator=(const CharType *p_str);
+ void operator=(const wchar_t *p_str);
+ void operator=(const char32_t *p_str);
+
bool operator==(const char *p_str) const;
- bool operator==(const CharType *p_str) const;
+ bool operator==(const wchar_t *p_str) const;
+ bool operator==(const char32_t *p_str) const;
bool operator==(const StrRange &p_str_range) const;
+
bool operator!=(const char *p_str) const;
- bool operator!=(const CharType *p_str) const;
- bool operator<(const CharType *p_str) const;
+ bool operator!=(const wchar_t *p_str) const;
+ bool operator!=(const char32_t *p_str) const;
+
+ bool operator<(const char32_t *p_str) const;
bool operator<(const char *p_str) const;
+ bool operator<(const wchar_t *p_str) const;
+
bool operator<(const String &p_str) const;
bool operator<=(const String &p_str) const;
+ bool operator>(const String &p_str) const;
+ bool operator>=(const String &p_str) const;
signed char casecmp_to(const String &p_str) const;
signed char nocasecmp_to(const String &p_str) const;
signed char naturalnocasecmp_to(const String &p_str) const;
- const CharType *c_str() const;
+ const char32_t *get_data() const;
/* standard size stuff */
_FORCE_INLINE_ int length() const {
@@ -197,11 +268,13 @@ public:
return s ? (s - 1) : 0; // length does not include zero
}
+ bool is_valid_string() const;
+
/* complex helpers */
String substr(int p_from, int p_chars = -1) const;
int find(const String &p_str, int p_from = 0) const; ///< return <0 if failed
int find(const char *p_str, int p_from = 0) const; ///< return <0 if failed
- int find_char(const CharType &p_char, int p_from = 0) const; ///< return <0 if failed
+ int find_char(const char32_t &p_char, int p_from = 0) const; ///< return <0 if failed
int findn(const String &p_str, int p_from = 0) const; ///< return <0 if failed, case insensitive
int rfind(const String &p_str, int p_from = -1) const; ///< return <0 if failed
int rfindn(const String &p_str, int p_from = -1) const; ///< return <0 if failed, case insensitive
@@ -238,27 +311,31 @@ public:
static String num_real(double p_num);
static String num_int64(int64_t p_num, int base = 10, bool capitalize_hex = false);
static String num_uint64(uint64_t p_num, int base = 10, bool capitalize_hex = false);
- static String chr(CharType p_char);
+ static String chr(char32_t p_char);
static String md5(const uint8_t *p_md5);
static String hex_encode_buffer(const uint8_t *p_buffer, int p_len);
bool is_numeric() const;
- double to_double() const;
- float to_float() const;
+ double to_float() const;
int64_t hex_to_int(bool p_with_prefix = true) const;
int64_t bin_to_int(bool p_with_prefix = true) const;
int64_t to_int() const;
+
static int64_t to_int(const char *p_str, int p_len = -1);
- static double to_double(const char *p_str);
- static double to_double(const CharType *p_str, const CharType **r_end = nullptr);
- static int64_t to_int(const CharType *p_str, int p_len = -1, bool p_clamp = false);
+ static int64_t to_int(const wchar_t *p_str, int p_len = -1);
+ static int64_t to_int(const char32_t *p_str, int p_len = -1, bool p_clamp = false);
+
+ static double to_float(const char *p_str);
+ static double to_float(const wchar_t *p_str, const wchar_t **r_end = nullptr);
+ static double to_float(const char32_t *p_str, const char32_t **r_end = nullptr);
+
String capitalize() const;
String camelcase_to_underscore(bool lowercase = true) const;
String get_with_code_lines() const;
int get_slice_count(String p_splitter) const;
String get_slice(String p_splitter, int p_slice) const;
- String get_slicec(CharType p_splitter, int p_slice) const;
+ String get_slicec(char32_t p_splitter, int p_slice) const;
Vector<String> split(const String &p_splitter, bool p_allow_empty = true, int p_maxsplit = 0) const;
Vector<String> rsplit(const String &p_splitter, bool p_allow_empty = true, int p_maxsplit = 0) const;
@@ -268,10 +345,10 @@ public:
Vector<int> split_ints(const String &p_splitter, bool p_allow_empty = true) const;
Vector<int> split_ints_mk(const Vector<String> &p_splitters, bool p_allow_empty = true) const;
- String join(Vector<String> parts);
+ String join(Vector<String> parts) const;
- static CharType char_uppercase(CharType p_char);
- static CharType char_lowercase(CharType p_char);
+ static char32_t char_uppercase(char32_t p_char);
+ static char32_t char_lowercase(char32_t p_char);
String to_upper() const;
String to_lower() const;
@@ -288,7 +365,7 @@ public:
String get_extension() const;
String get_basename() const;
String plus_file(const String &p_file) const;
- CharType ord_at(int p_idx) const;
+ char32_t ord_at(int p_idx) const;
void erase(int p_pos, int p_chars);
@@ -297,8 +374,14 @@ public:
bool parse_utf8(const char *p_utf8, int p_len = -1); //return true on error
static String utf8(const char *p_utf8, int p_len = -1);
- static uint32_t hash(const CharType *p_cstr, int p_len); /* hash the string */
- static uint32_t hash(const CharType *p_cstr); /* hash the string */
+ Char16String utf16() const;
+ bool parse_utf16(const char16_t *p_utf16, int p_len = -1); //return true on error
+ static String utf16(const char16_t *p_utf16, int p_len = -1);
+
+ static uint32_t hash(const char32_t *p_cstr, int p_len); /* hash the string */
+ static uint32_t hash(const char32_t *p_cstr); /* hash the string */
+ static uint32_t hash(const wchar_t *p_cstr, int p_len); /* hash the string */
+ static uint32_t hash(const wchar_t *p_cstr); /* hash the string */
static uint32_t hash(const char *p_cstr, int p_len); /* hash the string */
static uint32_t hash(const char *p_cstr); /* hash the string */
uint32_t hash() const; /* hash the string */
@@ -349,24 +432,37 @@ public:
/**
* The constructors must not depend on other overloads
*/
- /* String(CharType p_char);*/
_FORCE_INLINE_ String() {}
_FORCE_INLINE_ String(const String &p_str) { _cowdata._ref(p_str._cowdata); }
- String operator=(const String &p_str) {
+
+ String &operator=(const String &p_str) {
_cowdata._ref(p_str._cowdata);
return *this;
}
+ Vector<uint8_t> to_ascii_buffer() const;
+ Vector<uint8_t> to_utf8_buffer() const;
+ Vector<uint8_t> to_utf16_buffer() const;
+ Vector<uint8_t> to_utf32_buffer() const;
+
String(const char *p_str);
- String(const CharType *p_str, int p_clip_to_len = -1);
+ String(const wchar_t *p_str);
+ String(const char32_t *p_str);
+ String(const char *p_str, int p_clip_to_len);
+ String(const wchar_t *p_str, int p_clip_to_len);
+ String(const char32_t *p_str, int p_clip_to_len);
String(const StrRange &p_range);
};
bool operator==(const char *p_chr, const String &p_str);
+bool operator==(const wchar_t *p_chr, const String &p_str);
+bool operator!=(const char *p_chr, const String &p_str);
+bool operator!=(const wchar_t *p_chr, const String &p_str);
String operator+(const char *p_chr, const String &p_str);
-String operator+(CharType p_chr, const String &p_str);
+String operator+(const wchar_t *p_chr, const String &p_str);
+String operator+(char32_t p_chr, const String &p_str);
String itos(int64_t p_val);
String uitos(uint64_t p_val);
@@ -388,15 +484,18 @@ struct NaturalNoCaseComparator {
template <typename L, typename R>
_FORCE_INLINE_ bool is_str_less(const L *l_ptr, const R *r_ptr) {
while (true) {
- if (*l_ptr == 0 && *r_ptr == 0) {
+ const char32_t l = *l_ptr;
+ const char32_t r = *r_ptr;
+
+ if (l == 0 && r == 0) {
return false;
- } else if (*l_ptr == 0) {
+ } else if (l == 0) {
return true;
- } else if (*r_ptr == 0) {
+ } else if (r == 0) {
return false;
- } else if (*l_ptr < *r_ptr) {
+ } else if (l < r) {
return true;
- } else if (*l_ptr > *r_ptr) {
+ } else if (l > r) {
return false;
}
@@ -411,8 +510,10 @@ _FORCE_INLINE_ bool is_str_less(const L *l_ptr, const R *r_ptr) {
// and doc translate for the class reference (DTR).
#ifdef TOOLS_ENABLED
// Gets parsed.
-String TTR(const String &);
-String DTR(const String &);
+String TTR(const String &p_text, const String &p_context = "");
+String TTRN(const String &p_text, const String &p_text_plural, int p_n, const String &p_context = "");
+String DTR(const String &p_text, const String &p_context = "");
+String DTRN(const String &p_text, const String &p_text_plural, int p_n, const String &p_context = "");
// Use for C strings.
#define TTRC(m_value) (m_value)
// Use to avoid parsing (for use later with C strings).
@@ -420,15 +521,38 @@ String DTR(const String &);
#else
#define TTR(m_value) (String())
+#define TTRN(m_value) (String())
#define DTR(m_value) (String())
+#define DTRN(m_value) (String())
#define TTRC(m_value) (m_value)
#define TTRGET(m_value) (m_value)
#endif
// Runtime translate for the public node API.
-String RTR(const String &);
+String RTR(const String &p_text, const String &p_context = "");
+String RTRN(const String &p_text, const String &p_text_plural, int p_n, const String &p_context = "");
-bool is_symbol(CharType c);
+bool is_symbol(char32_t c);
bool select_word(const String &p_s, int p_col, int &r_beg, int &r_end);
+_FORCE_INLINE_ void sarray_add_str(Vector<String> &arr) {
+}
+
+_FORCE_INLINE_ void sarray_add_str(Vector<String> &arr, const String &p_str) {
+ arr.push_back(p_str);
+}
+
+template <class... P>
+_FORCE_INLINE_ void sarray_add_str(Vector<String> &arr, const String &p_str, P... p_args) {
+ arr.push_back(p_str);
+ sarray_add_str(arr, p_args...);
+}
+
+template <class... P>
+_FORCE_INLINE_ Vector<String> sarray(P... p_args) {
+ Vector<String> arr;
+ sarray_add_str(arr, p_args...);
+ return arr;
+}
+
#endif // USTRING_H
diff --git a/core/templates/SCsub b/core/templates/SCsub
new file mode 100644
index 0000000000..8c4c843a33
--- /dev/null
+++ b/core/templates/SCsub
@@ -0,0 +1,7 @@
+#!/usr/bin/env python
+
+Import("env")
+
+env_templates = env.Clone()
+
+env_templates.add_source_files(env.core_sources, "*.cpp")
diff --git a/core/command_queue_mt.cpp b/core/templates/command_queue_mt.cpp
index ace210ca2c..a94853a21c 100644
--- a/core/command_queue_mt.cpp
+++ b/core/templates/command_queue_mt.cpp
@@ -30,6 +30,7 @@
#include "command_queue_mt.h"
+#include "core/config/project_settings.h"
#include "core/os/os.h"
void CommandQueueMT::lock() {
@@ -71,7 +72,7 @@ CommandQueueMT::SyncSemaphore *CommandQueueMT::_alloc_sync_sem() {
bool CommandQueueMT::dealloc_one() {
tryagain:
- if (dealloc_ptr == write_ptr) {
+ if (dealloc_ptr == (write_ptr_and_epoch >> 1)) {
// The queue is empty
return false;
}
@@ -94,6 +95,10 @@ tryagain:
}
CommandQueueMT::CommandQueueMT(bool p_sync) {
+ command_mem_size = GLOBAL_DEF_RST("memory/limits/command_queue/multithreading_queue_size_kb", DEFAULT_COMMAND_MEM_SIZE_KB);
+ ProjectSettings::get_singleton()->set_custom_property_info("memory/limits/command_queue/multithreading_queue_size_kb", PropertyInfo(Variant::INT, "memory/limits/command_queue/multithreading_queue_size_kb", PROPERTY_HINT_RANGE, "1,4096,1,or_greater"));
+ command_mem_size *= 1024;
+ command_mem = (uint8_t *)memalloc(command_mem_size);
if (p_sync) {
sync = memnew(Semaphore);
}
diff --git a/core/command_queue_mt.h b/core/templates/command_queue_mt.h
index d7a6a5bc43..ac38d330de 100644
--- a/core/command_queue_mt.h
+++ b/core/templates/command_queue_mt.h
@@ -34,7 +34,7 @@
#include "core/os/memory.h"
#include "core/os/mutex.h"
#include "core/os/semaphore.h"
-#include "core/simple_type.h"
+#include "core/templates/simple_type.h"
#include "core/typedefs.h"
#define COMMA(N) _COMMA_##N
@@ -330,15 +330,15 @@ class CommandQueueMT {
/***** BASE *******/
enum {
- COMMAND_MEM_SIZE_KB = 256,
- COMMAND_MEM_SIZE = COMMAND_MEM_SIZE_KB * 1024,
+ DEFAULT_COMMAND_MEM_SIZE_KB = 256,
SYNC_SEMAPHORES = 8
};
- uint8_t *command_mem = (uint8_t *)memalloc(COMMAND_MEM_SIZE);
- uint32_t read_ptr = 0;
- uint32_t write_ptr = 0;
+ uint8_t *command_mem = nullptr;
+ uint32_t read_ptr_and_epoch = 0;
+ uint32_t write_ptr_and_epoch = 0;
uint32_t dealloc_ptr = 0;
+ uint32_t command_mem_size = 0;
SyncSemaphore sync_sems[SYNC_SEMAPHORES];
Mutex mutex;
Semaphore *sync = nullptr;
@@ -348,7 +348,11 @@ class CommandQueueMT {
// alloc size is size+T+safeguard
uint32_t alloc_size = ((sizeof(T) + 8 - 1) & ~(8 - 1)) + 8;
+ // Assert that the buffer is big enough to hold at least two messages.
+ ERR_FAIL_COND_V(alloc_size * 2 + sizeof(uint32_t) > command_mem_size, nullptr);
+
tryagain:
+ uint32_t write_ptr = write_ptr_and_epoch >> 1;
if (write_ptr < dealloc_ptr) {
// behind dealloc_ptr, check that there is room
@@ -362,7 +366,7 @@ class CommandQueueMT {
} else {
// ahead of dealloc_ptr, check that there is room
- if ((COMMAND_MEM_SIZE - write_ptr) < alloc_size + sizeof(uint32_t)) {
+ if ((command_mem_size - write_ptr) < alloc_size + sizeof(uint32_t)) {
// no room at the end, wrap down;
if (dealloc_ptr == 0) { // don't want write_ptr to become dealloc_ptr
@@ -375,12 +379,17 @@ class CommandQueueMT {
}
// if this happens, it's a bug
- ERR_FAIL_COND_V((COMMAND_MEM_SIZE - write_ptr) < 8, nullptr);
+ ERR_FAIL_COND_V((command_mem_size - write_ptr) < 8, nullptr);
// zero means, wrap to beginning
uint32_t *p = (uint32_t *)&command_mem[write_ptr];
- *p = 0;
- write_ptr = 0;
+ *p = 1;
+ write_ptr_and_epoch = 0 | (1 & ~write_ptr_and_epoch); // Invert epoch.
+ // See if we can get the thread to run and clear up some more space while we wait.
+ // This is required if alloc_size * 2 + 4 > COMMAND_MEM_SIZE
+ if (sync) {
+ sync->post();
+ }
goto tryagain;
}
}
@@ -394,6 +403,7 @@ class CommandQueueMT {
// allocate the command
T *cmd = memnew_placement(&command_mem[write_ptr], T);
write_ptr += size;
+ write_ptr_and_epoch = (write_ptr << 1) | (write_ptr_and_epoch & 1);
return cmd;
}
@@ -419,19 +429,21 @@ class CommandQueueMT {
tryagain:
// tried to read an empty queue
- if (read_ptr == write_ptr) {
+ if (read_ptr_and_epoch == write_ptr_and_epoch) {
if (p_lock) {
unlock();
}
return false;
}
+ uint32_t read_ptr = read_ptr_and_epoch >> 1;
uint32_t size_ptr = read_ptr;
uint32_t size = *(uint32_t *)&command_mem[read_ptr] >> 1;
if (size == 0) {
+ *(uint32_t *)&command_mem[read_ptr] = 0; // clear in-use bit.
//end of ringbuffer, wrap
- read_ptr = 0;
+ read_ptr_and_epoch = 0 | (1 & ~read_ptr_and_epoch); // Invert epoch.
goto tryagain;
}
@@ -441,6 +453,8 @@ class CommandQueueMT {
read_ptr += size;
+ read_ptr_and_epoch = (read_ptr << 1) | (read_ptr_and_epoch & 1);
+
if (p_lock) {
unlock();
}
diff --git a/core/cowdata.h b/core/templates/cowdata.h
index 82daefb5bd..d5eb08286d 100644
--- a/core/cowdata.h
+++ b/core/templates/cowdata.h
@@ -31,15 +31,16 @@
#ifndef COWDATA_H
#define COWDATA_H
-#include "core/error_macros.h"
+#include "core/error/error_macros.h"
#include "core/os/memory.h"
-#include "core/safe_refcount.h"
+#include "core/templates/safe_refcount.h"
#include <string.h>
template <class T>
class Vector;
class String;
+class Char16String;
class CharString;
template <class T, class V>
class VMap;
@@ -49,6 +50,7 @@ class CowData {
template <class TV>
friend class Vector;
friend class String;
+ friend class Char16String;
friend class CharString;
template <class TV, class VV>
friend class VMap;
diff --git a/core/hash_map.h b/core/templates/hash_map.h
index 10fc931e7a..e1ba381595 100644
--- a/core/hash_map.h
+++ b/core/templates/hash_map.h
@@ -31,12 +31,12 @@
#ifndef HASH_MAP_H
#define HASH_MAP_H
-#include "core/error_macros.h"
-#include "core/hashfuncs.h"
-#include "core/list.h"
+#include "core/error/error_macros.h"
#include "core/math/math_funcs.h"
#include "core/os/memory.h"
-#include "core/ustring.h"
+#include "core/string/ustring.h"
+#include "core/templates/hashfuncs.h"
+#include "core/templates/list.h"
/**
* @class HashMap
@@ -73,7 +73,7 @@ public:
private:
friend class HashMap;
- uint32_t hash;
+ uint32_t hash = 0;
Element *next = nullptr;
Element() {}
Pair pair;
diff --git a/core/hashfuncs.h b/core/templates/hashfuncs.h
index d984f6c524..86bb1b5228 100644
--- a/core/hashfuncs.h
+++ b/core/templates/hashfuncs.h
@@ -33,12 +33,12 @@
#include "core/math/math_defs.h"
#include "core/math/math_funcs.h"
-#include "core/node_path.h"
-#include "core/object_id.h"
-#include "core/rid.h"
-#include "core/string_name.h"
+#include "core/object/object_id.h"
+#include "core/string/node_path.h"
+#include "core/string/string_name.h"
+#include "core/string/ustring.h"
+#include "core/templates/rid.h"
#include "core/typedefs.h"
-#include "core/ustring.h"
/**
* Hashing functions
*/
@@ -146,6 +146,8 @@ struct HashMapHasherDefault {
static _FORCE_INLINE_ uint32_t hash(const uint8_t p_int) { return p_int; }
static _FORCE_INLINE_ uint32_t hash(const int8_t p_int) { return (uint32_t)p_int; }
static _FORCE_INLINE_ uint32_t hash(const wchar_t p_wchar) { return (uint32_t)p_wchar; }
+ static _FORCE_INLINE_ uint32_t hash(const char16_t p_uchar) { return (uint32_t)p_uchar; }
+ static _FORCE_INLINE_ uint32_t hash(const char32_t p_uchar) { return (uint32_t)p_uchar; }
static _FORCE_INLINE_ uint32_t hash(const RID &p_rid) { return hash_one_uint64(p_rid.get_id()); }
static _FORCE_INLINE_ uint32_t hash(const StringName &p_string_name) { return p_string_name.hash(); }
diff --git a/core/list.h b/core/templates/list.h
index f850db5241..8e14aaa90d 100644
--- a/core/list.h
+++ b/core/templates/list.h
@@ -31,9 +31,9 @@
#ifndef LIST_H
#define LIST_H
-#include "core/error_macros.h"
+#include "core/error/error_macros.h"
#include "core/os/memory.h"
-#include "core/sort_array.h"
+#include "core/templates/sort_array.h"
/**
* Generic Templatized Linked List Implementation.
@@ -137,9 +137,9 @@ public:
private:
struct _Data {
- Element *first;
- Element *last;
- int size_cache;
+ Element *first = nullptr;
+ Element *last = nullptr;
+ int size_cache = 0;
bool erase(const Element *p_I) {
ERR_FAIL_COND_V(!p_I, false);
@@ -395,28 +395,38 @@ public:
ERR_FAIL_COND(p_A->data != _data);
ERR_FAIL_COND(p_B->data != _data);
+ if (p_A == p_B) {
+ return;
+ }
Element *A_prev = p_A->prev_ptr;
Element *A_next = p_A->next_ptr;
+ Element *B_prev = p_B->prev_ptr;
+ Element *B_next = p_B->next_ptr;
- p_A->next_ptr = p_B->next_ptr;
- p_A->prev_ptr = p_B->prev_ptr;
-
- p_B->next_ptr = A_next;
- p_B->prev_ptr = A_prev;
-
- if (p_A->prev_ptr) {
- p_A->prev_ptr->next_ptr = p_A;
+ if (A_prev) {
+ A_prev->next_ptr = p_B;
+ } else {
+ _data->first = p_B;
}
- if (p_A->next_ptr) {
- p_A->next_ptr->prev_ptr = p_A;
+ if (B_prev) {
+ B_prev->next_ptr = p_A;
+ } else {
+ _data->first = p_A;
}
-
- if (p_B->prev_ptr) {
- p_B->prev_ptr->next_ptr = p_B;
+ if (A_next) {
+ A_next->prev_ptr = p_B;
+ } else {
+ _data->last = p_B;
}
- if (p_B->next_ptr) {
- p_B->next_ptr->prev_ptr = p_B;
+ if (B_next) {
+ B_next->prev_ptr = p_A;
+ } else {
+ _data->last = p_A;
}
+ p_A->prev_ptr = A_next == p_B ? p_B : B_prev;
+ p_A->next_ptr = B_next == p_A ? p_B : B_next;
+ p_B->prev_ptr = B_next == p_A ? p_A : A_prev;
+ p_B->next_ptr = A_next == p_B ? p_A : A_next;
}
/**
* copy the list
diff --git a/core/local_vector.h b/core/templates/local_vector.h
index d97f3330dc..4ef040dc77 100644
--- a/core/local_vector.h
+++ b/core/templates/local_vector.h
@@ -31,11 +31,11 @@
#ifndef LOCAL_VECTOR_H
#define LOCAL_VECTOR_H
-#include "core/error_macros.h"
+#include "core/error/error_macros.h"
#include "core/os/copymem.h"
#include "core/os/memory.h"
-#include "core/sort_array.h"
-#include "core/vector.h"
+#include "core/templates/sort_array.h"
+#include "core/templates/vector.h"
template <class T, class U = uint32_t, bool force_trivial = false>
class LocalVector {
@@ -73,10 +73,10 @@ public:
void remove(U p_index) {
ERR_FAIL_UNSIGNED_INDEX(p_index, count);
+ count--;
for (U i = p_index; i < count; i++) {
data[i] = data[i + 1];
}
- count--;
if (!__has_trivial_destructor(T) && !force_trivial) {
data[count].~T();
}
diff --git a/core/map.h b/core/templates/map.h
index fd4f500556..c454d69256 100644
--- a/core/map.h
+++ b/core/templates/map.h
@@ -31,8 +31,8 @@
#ifndef MAP_H
#define MAP_H
-#include "core/error_macros.h"
-#include "core/set.h"
+#include "core/error/error_macros.h"
+#include "core/templates/set.h"
// based on the very nice implementation of rb-trees by:
// https://web.archive.org/web/20120507164830/http://web.mit.edu/~emin/www/source_code/red_black_tree/index.html
diff --git a/core/oa_hash_map.h b/core/templates/oa_hash_map.h
index 775e17fdb5..d9d632b4ce 100644
--- a/core/oa_hash_map.h
+++ b/core/templates/oa_hash_map.h
@@ -31,10 +31,10 @@
#ifndef OA_HASH_MAP_H
#define OA_HASH_MAP_H
-#include "core/hashfuncs.h"
#include "core/math/math_funcs.h"
#include "core/os/copymem.h"
#include "core/os/memory.h"
+#include "core/templates/hashfuncs.h"
/**
* A HashMap implementation that uses open addressing with Robin Hood hashing.
@@ -48,7 +48,7 @@
*
* 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,
diff --git a/core/ordered_hash_map.h b/core/templates/ordered_hash_map.h
index e6a6340a2f..9398868b01 100644
--- a/core/ordered_hash_map.h
+++ b/core/templates/ordered_hash_map.h
@@ -31,9 +31,9 @@
#ifndef ORDERED_HASH_MAP_H
#define ORDERED_HASH_MAP_H
-#include "core/hash_map.h"
-#include "core/list.h"
-#include "core/pair.h"
+#include "core/templates/hash_map.h"
+#include "core/templates/list.h"
+#include "core/templates/pair.h"
/**
* A hash map which allows to iterate elements in insertion order.
diff --git a/core/pair.h b/core/templates/pair.h
index 89ea2b9fd9..89ea2b9fd9 100644
--- a/core/pair.h
+++ b/core/templates/pair.h
diff --git a/core/rid.h b/core/templates/rid.h
index 4b65f3fb6a..a475d166d5 100644
--- a/core/rid.h
+++ b/core/templates/rid.h
@@ -52,6 +52,9 @@ public:
_FORCE_INLINE_ bool operator>(const RID &p_rid) const {
return _id > p_rid._id;
}
+ _FORCE_INLINE_ bool operator>=(const RID &p_rid) const {
+ return _id >= p_rid._id;
+ }
_FORCE_INLINE_ bool operator!=(const RID &p_rid) const {
return _id != p_rid._id;
}
diff --git a/core/rid_owner.cpp b/core/templates/rid_owner.cpp
index a5065f29f8..a5065f29f8 100644
--- a/core/rid_owner.cpp
+++ b/core/templates/rid_owner.cpp
diff --git a/core/rid_owner.h b/core/templates/rid_owner.h
index 2489475c68..d1bcb92010 100644
--- a/core/rid_owner.h
+++ b/core/templates/rid_owner.h
@@ -31,14 +31,14 @@
#ifndef RID_OWNER_H
#define RID_OWNER_H
-#include "core/list.h"
-#include "core/oa_hash_map.h"
#include "core/os/memory.h"
-#include "core/print_string.h"
-#include "core/rid.h"
-#include "core/safe_refcount.h"
-#include "core/set.h"
-#include "core/spin_lock.h"
+#include "core/os/spin_lock.h"
+#include "core/string/print_string.h"
+#include "core/templates/list.h"
+#include "core/templates/oa_hash_map.h"
+#include "core/templates/rid.h"
+#include "core/templates/safe_refcount.h"
+#include "core/templates/set.h"
#include <stdio.h>
#include <typeinfo>
@@ -236,7 +236,7 @@ public:
}
_FORCE_INLINE_ T *get_ptr_by_index(uint32_t p_index) {
- ERR_FAIL_INDEX_V(p_index, alloc_count, nullptr);
+ ERR_FAIL_UNSIGNED_INDEX_V(p_index, alloc_count, nullptr);
if (THREAD_SAFE) {
spin_lock.lock();
}
diff --git a/core/ring_buffer.h b/core/templates/ring_buffer.h
index 6b71d12cf3..12ec047fb6 100644
--- a/core/ring_buffer.h
+++ b/core/templates/ring_buffer.h
@@ -31,7 +31,7 @@
#ifndef RING_BUFFER_H
#define RING_BUFFER_H
-#include "core/vector.h"
+#include "core/templates/vector.h"
template <typename T>
class RingBuffer {
diff --git a/core/safe_refcount.cpp b/core/templates/safe_refcount.cpp
index d5ee778ef7..d5ee778ef7 100644
--- a/core/safe_refcount.cpp
+++ b/core/templates/safe_refcount.cpp
diff --git a/core/safe_refcount.h b/core/templates/safe_refcount.h
index dc4e62354a..6b08b876f8 100644
--- a/core/safe_refcount.h
+++ b/core/templates/safe_refcount.h
@@ -165,7 +165,7 @@ uint64_t atomic_exchange_if_greater(volatile uint64_t *pw, volatile uint64_t val
#endif
struct SafeRefCount {
- uint32_t count;
+ uint32_t count = 0;
public:
// destroy() is called when weak_count_ drops to zero.
diff --git a/core/self_list.h b/core/templates/self_list.h
index 3104bcb714..2a037d109c 100644
--- a/core/self_list.h
+++ b/core/templates/self_list.h
@@ -31,7 +31,7 @@
#ifndef SELF_LIST_H
#define SELF_LIST_H
-#include "core/error_macros.h"
+#include "core/error/error_macros.h"
#include "core/typedefs.h"
template <class T>
diff --git a/core/set.h b/core/templates/set.h
index 1bc0a3f41e..d0ac71a710 100644
--- a/core/set.h
+++ b/core/templates/set.h
@@ -80,7 +80,7 @@ public:
private:
struct _Data {
Element *_root = nullptr;
- Element *_nil;
+ Element *_nil = nullptr;
int size_cache = 0;
_FORCE_INLINE_ _Data() {
diff --git a/core/simple_type.h b/core/templates/simple_type.h
index 10dc36cbd4..841ab9f384 100644
--- a/core/simple_type.h
+++ b/core/templates/simple_type.h
@@ -48,4 +48,9 @@ struct GetSimpleTypeT<T const> {
typedef T type_t;
};
+template <class T>
+struct GetSimpleTypeT<T const &> {
+ typedef T type_t;
+};
+
#endif // SIMPLE_TYPE_H
diff --git a/core/sort_array.h b/core/templates/sort_array.h
index 93cc6f727d..ece5e72e51 100644
--- a/core/sort_array.h
+++ b/core/templates/sort_array.h
@@ -31,7 +31,7 @@
#ifndef SORT_ARRAY_H
#define SORT_ARRAY_H
-#include "core/error_macros.h"
+#include "core/error/error_macros.h"
#include "core/typedefs.h"
#define ERR_BAD_COMPARE(cond) \
@@ -54,7 +54,6 @@ struct _DefaultComparator {
template <class T, class Comparator = _DefaultComparator<T>, bool Validate = SORT_ARRAY_VALIDATE_ENABLED>
class SortArray {
enum {
-
INTROSORT_THRESHOLD = 16
};
diff --git a/core/thread_work_pool.cpp b/core/templates/thread_work_pool.cpp
index 3a95e83ffc..3a95e83ffc 100644
--- a/core/thread_work_pool.cpp
+++ b/core/templates/thread_work_pool.cpp
diff --git a/core/thread_work_pool.h b/core/templates/thread_work_pool.h
index e21d3974ee..e083cdcb24 100644
--- a/core/thread_work_pool.h
+++ b/core/templates/thread_work_pool.h
@@ -41,8 +41,8 @@ class ThreadWorkPool {
std::atomic<uint32_t> index;
struct BaseWork {
- std::atomic<uint32_t> *index;
- uint32_t max_elements;
+ std::atomic<uint32_t> *index = nullptr;
+ uint32_t max_elements = 0;
virtual void work() = 0;
virtual ~BaseWork() = default;
};
@@ -73,13 +73,15 @@ class ThreadWorkPool {
ThreadData *threads = nullptr;
uint32_t thread_count = 0;
+ BaseWork *current_work = nullptr;
static void _thread_function(ThreadData *p_thread);
public:
template <class C, class M, class U>
- void do_work(uint32_t p_elements, C *p_instance, M p_method, U p_userdata) {
+ void begin_work(uint32_t p_elements, C *p_instance, M p_method, U p_userdata) {
ERR_FAIL_COND(!threads); //never initialized
+ ERR_FAIL_COND(current_work != nullptr);
index.store(0);
@@ -90,16 +92,37 @@ public:
w->index = &index;
w->max_elements = p_elements;
+ current_work = w;
+
for (uint32_t i = 0; i < thread_count; i++) {
threads[i].work = w;
threads[i].start.post();
}
+ }
+
+ bool is_working() const {
+ return current_work != nullptr;
+ }
+
+ uint32_t get_work_index() const {
+ return index;
+ }
+
+ void end_work() {
+ ERR_FAIL_COND(current_work == nullptr);
for (uint32_t i = 0; i < thread_count; i++) {
threads[i].completed.wait();
threads[i].work = nullptr;
}
- memdelete(w);
+ memdelete(current_work);
+ current_work = nullptr;
+ }
+
+ template <class C, class M, class U>
+ void do_work(uint32_t p_elements, C *p_instance, M p_method, U p_userdata) {
+ begin_work(p_elements, p_instance, p_method, p_userdata);
+ end_work();
}
void init(int p_thread_count = -1);
diff --git a/core/vector.h b/core/templates/vector.h
index 4c152fb084..9d45f7c30a 100644
--- a/core/vector.h
+++ b/core/templates/vector.h
@@ -37,11 +37,11 @@
* Vector container. Regular Vector Container. Use with care and for smaller arrays when possible. Use Vector for large arrays.
*/
-#include "core/cowdata.h"
-#include "core/error_macros.h"
+#include "core/error/error_macros.h"
#include "core/os/copymem.h"
#include "core/os/memory.h"
-#include "core/sort_array.h"
+#include "core/templates/cowdata.h"
+#include "core/templates/sort_array.h"
template <class T>
class VectorWriteProxy {
@@ -82,7 +82,7 @@ public:
_FORCE_INLINE_ bool empty() const { return _cowdata.empty(); }
_FORCE_INLINE_ T get(int p_index) { return _cowdata.get(p_index); }
- _FORCE_INLINE_ const T get(int p_index) const { return _cowdata.get(p_index); }
+ _FORCE_INLINE_ const T &get(int p_index) const { return _cowdata.get(p_index); }
_FORCE_INLINE_ void set(int p_index, const T &p_elem) { _cowdata.set(p_index, p_elem); }
_FORCE_INLINE_ int size() const { return _cowdata.size(); }
Error resize(int p_size) { return _cowdata.resize(p_size); }
@@ -92,6 +92,10 @@ public:
void append_array(Vector<T> p_other);
+ bool has(const T &p_val) {
+ return find(p_val, 0) != -1;
+ }
+
template <class C>
void sort_custom() {
int len = _cowdata.size();
@@ -153,6 +157,32 @@ public:
return slice;
}
+ bool operator==(const Vector<T> &p_arr) const {
+ int s = size();
+ if (s != p_arr.size()) {
+ return false;
+ }
+ for (int i = 0; i < s; i++) {
+ if (operator[](i) != p_arr[i]) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ bool operator!=(const Vector<T> &p_arr) const {
+ int s = size();
+ if (s != p_arr.size()) {
+ return true;
+ }
+ for (int i = 0; i < s; i++) {
+ if (operator[](i) != p_arr[i]) {
+ return true;
+ }
+ }
+ return false;
+ }
+
_FORCE_INLINE_ Vector() {}
_FORCE_INLINE_ Vector(const Vector &p_from) { _cowdata._ref(p_from._cowdata); }
diff --git a/core/vmap.h b/core/templates/vmap.h
index c91ea9b3c9..8d2a3d2a9c 100644
--- a/core/vmap.h
+++ b/core/templates/vmap.h
@@ -31,7 +31,7 @@
#ifndef VMAP_H
#define VMAP_H
-#include "core/cowdata.h"
+#include "core/templates/cowdata.h"
#include "core/typedefs.h"
template <class T, class V>
diff --git a/core/vset.h b/core/templates/vset.h
index 034b8fe851..4c0b8717b6 100644
--- a/core/vset.h
+++ b/core/templates/vset.h
@@ -31,8 +31,8 @@
#ifndef VSET_H
#define VSET_H
+#include "core/templates/vector.h"
#include "core/typedefs.h"
-#include "core/vector.h"
template <class T>
class VSet {
diff --git a/core/typedefs.h b/core/typedefs.h
index 4bfa5debac..d7ee5ee40e 100644
--- a/core/typedefs.h
+++ b/core/typedefs.h
@@ -41,8 +41,8 @@
#include "platform_config.h"
// Should be available everywhere.
-#include "core/error_list.h"
-#include "core/int_types.h"
+#include "core/error/error_list.h"
+#include <cstdint>
// Turn argument to string constant:
// https://gcc.gnu.org/onlinedocs/cpp/Stringizing.html#Stringizing
@@ -193,6 +193,20 @@ static inline unsigned int nearest_shift(unsigned int p_number) {
return 0;
}
+// constexpr function to find the floored log2 of a number
+template <typename T>
+constexpr T floor_log2(T x) {
+ return x < 2 ? x : 1 + floor_log2(x >> 1);
+}
+
+// Get the number of bits needed to represent the number.
+// IE, if you pass in 8, you will get 4.
+// If you want to know how many bits are needed to store 8 values however, pass in (8 - 1).
+template <typename T>
+constexpr T get_num_bits(T x) {
+ return floor_log2(x);
+}
+
// Swap 16, 32 and 64 bits value for endianness.
#if defined(__GNUC__)
#define BSWAP16(x) __builtin_bswap16(x)
@@ -263,4 +277,8 @@ struct BuildIndexSequence : BuildIndexSequence<N - 1, N - 1, Is...> {};
template <size_t... Is>
struct BuildIndexSequence<0, Is...> : IndexSequence<Is...> {};
+#ifdef DEBUG_ENABLED
+#define DEBUG_METHODS_ENABLED
+#endif
+
#endif // TYPEDEFS_H
diff --git a/core/variant/SCsub b/core/variant/SCsub
new file mode 100644
index 0000000000..7f4c8b7788
--- /dev/null
+++ b/core/variant/SCsub
@@ -0,0 +1,7 @@
+#!/usr/bin/env python
+
+Import("env")
+
+env_variant = env.Clone()
+
+env_variant.add_source_files(env.core_sources, "*.cpp")
diff --git a/core/array.cpp b/core/variant/array.cpp
index d1c0688e63..5043868b1d 100644
--- a/core/array.cpp
+++ b/core/variant/array.cpp
@@ -31,11 +31,11 @@
#include "array.h"
#include "container_type_validate.h"
-#include "core/hashfuncs.h"
-#include "core/object.h"
-#include "core/script_language.h"
-#include "core/variant.h"
-#include "core/vector.h"
+#include "core/object/class_db.h"
+#include "core/object/script_language.h"
+#include "core/templates/hashfuncs.h"
+#include "core/templates/vector.h"
+#include "core/variant/variant.h"
class ArrayPrivate {
public:
@@ -98,6 +98,37 @@ bool Array::operator==(const Array &p_array) const {
return _p == p_array._p;
}
+bool Array::operator!=(const Array &p_array) const {
+ return !operator==(p_array);
+}
+
+bool Array::operator<(const Array &p_array) const {
+ int a_len = size();
+ int b_len = p_array.size();
+
+ int min_cmp = MIN(a_len, b_len);
+
+ for (int i = 0; i < min_cmp; i++) {
+ if (operator[](i) < p_array[i]) {
+ return true;
+ } else if (p_array[i] < operator[](i)) {
+ return false;
+ }
+ }
+
+ return a_len < b_len;
+}
+
+bool Array::operator<=(const Array &p_array) const {
+ return !operator>(p_array);
+}
+bool Array::operator>(const Array &p_array) const {
+ return p_array < *this;
+}
+bool Array::operator>=(const Array &p_array) const {
+ return !operator<(p_array);
+}
+
uint32_t Array::hash() const {
uint32_t h = hash_djb2_one_32(0);
@@ -134,7 +165,7 @@ void Array::_assign(const Array &p_array) {
} else if (Variant::can_convert_strict(src_val.get_type(), _p->typed.type)) {
Variant *ptr = &src_val;
Callable::CallError ce;
- new_array.write[i] = Variant::construct(_p->typed.type, (const Variant **)&ptr, 1, ce, true);
+ Variant::construct(_p->typed.type, new_array.write[i], (const Variant **)&ptr, 1, ce);
if (ce.error != Callable::CallError::CALL_OK) {
ERR_FAIL_MSG("Unable to convert array index " + itos(i) + " from '" + Variant::get_type_name(src_val.get_type()) + "' to '" + Variant::get_type_name(_p->typed.type) + "'.");
}
@@ -161,6 +192,11 @@ void Array::push_back(const Variant &p_value) {
_p->array.push_back(p_value);
}
+void Array::append_array(const Array &p_array) {
+ ERR_FAIL_COND(!_p->typed.validate(p_array, "append_array"));
+ _p->array.append_array(p_array._p->array);
+}
+
Error Array::resize(int p_new_size) {
return _p->array.resize(p_new_size);
}
@@ -330,13 +366,12 @@ struct _ArrayVariantSort {
}
};
-Array &Array::sort() {
+void Array::sort() {
_p->array.sort_custom<_ArrayVariantSort>();
- return *this;
}
struct _ArrayVariantSortCustom {
- Object *obj;
+ Object *obj = nullptr;
StringName func;
_FORCE_INLINE_ bool operator()(const Variant &p_l, const Variant &p_r) const {
@@ -349,14 +384,13 @@ struct _ArrayVariantSortCustom {
return res;
}
};
-Array &Array::sort_custom(Object *p_obj, const StringName &p_function) {
- ERR_FAIL_NULL_V(p_obj, *this);
+void Array::sort_custom(Object *p_obj, const StringName &p_function) {
+ ERR_FAIL_NULL(p_obj);
SortArray<Variant, _ArrayVariantSortCustom, true> avs;
avs.compare.obj = p_obj;
avs.compare.func = p_function;
avs.sort(_p->array.ptrw(), _p->array.size());
- return *this;
}
void Array::shuffle() {
@@ -415,9 +449,8 @@ int Array::bsearch_custom(const Variant &p_value, Object *p_obj, const StringNam
return bisect(_p->array, p_value, p_before, less);
}
-Array &Array::invert() {
+void Array::invert() {
_p->array.invert();
- return *this;
}
void Array::push_front(const Variant &p_value) {
diff --git a/core/array.h b/core/variant/array.h
index d2e0537ad5..e01ac13168 100644
--- a/core/array.h
+++ b/core/variant/array.h
@@ -61,12 +61,14 @@ public:
void clear();
bool operator==(const Array &p_array) const;
+ bool operator!=(const Array &p_array) const;
uint32_t hash() const;
void operator=(const Array &p_array);
void push_back(const Variant &p_value);
_FORCE_INLINE_ void append(const Variant &p_value) { push_back(p_value); } //for python compatibility
+ void append_array(const Array &p_array);
Error resize(int p_new_size);
void insert(int p_pos, const Variant &p_value);
@@ -75,12 +77,12 @@ public:
Variant front() const;
Variant back() const;
- Array &sort();
- Array &sort_custom(Object *p_obj, const StringName &p_function);
+ void sort();
+ void sort_custom(Object *p_obj, const StringName &p_function);
void shuffle();
int bsearch(const Variant &p_value, bool p_before = true);
int bsearch_custom(const Variant &p_value, Object *p_obj, const StringName &p_function, bool p_before = true);
- Array &invert();
+ void invert();
int find(const Variant &p_value, int p_from = 0) const;
int rfind(const Variant &p_value, int p_from = -1) const;
@@ -98,6 +100,11 @@ public:
Array slice(int p_begin, int p_end, int p_step = 1, bool p_deep = false) const;
+ bool operator<(const Array &p_array) const;
+ bool operator<=(const Array &p_array) const;
+ bool operator>(const Array &p_array) const;
+ bool operator>=(const Array &p_array) const;
+
Variant min() const;
Variant max() const;
diff --git a/core/variant/binder_common.h b/core/variant/binder_common.h
new file mode 100644
index 0000000000..e950709526
--- /dev/null
+++ b/core/variant/binder_common.h
@@ -0,0 +1,666 @@
+/*************************************************************************/
+/* binder_common.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* 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. */
+/*************************************************************************/
+
+#ifndef BINDER_COMMON_H
+#define BINDER_COMMON_H
+
+#include "core/object/object.h"
+#include "core/templates/list.h"
+#include "core/templates/simple_type.h"
+#include "core/typedefs.h"
+#include "core/variant/method_ptrcall.h"
+#include "core/variant/type_info.h"
+#include "core/variant/variant.h"
+#include "core/variant/variant_internal.h"
+
+#include <stdio.h>
+
+template <class T>
+struct VariantCaster {
+ static _FORCE_INLINE_ T cast(const Variant &p_variant) {
+ return p_variant;
+ }
+};
+
+template <class T>
+struct VariantCaster<T &> {
+ static _FORCE_INLINE_ T cast(const Variant &p_variant) {
+ return p_variant;
+ }
+};
+
+template <class T>
+struct VariantCaster<const T &> {
+ static _FORCE_INLINE_ T cast(const Variant &p_variant) {
+ return p_variant;
+ }
+};
+
+#define VARIANT_ENUM_CAST(m_enum) \
+ MAKE_ENUM_TYPE_INFO(m_enum) \
+ template <> \
+ struct VariantCaster<m_enum> { \
+ static _FORCE_INLINE_ m_enum cast(const Variant &p_variant) { \
+ return (m_enum)p_variant.operator int(); \
+ } \
+ }; \
+ template <> \
+ struct PtrToArg<m_enum> { \
+ _FORCE_INLINE_ static m_enum convert(const void *p_ptr) { \
+ return m_enum(*reinterpret_cast<const int *>(p_ptr)); \
+ } \
+ _FORCE_INLINE_ static void encode(m_enum p_val, const void *p_ptr) { \
+ *(int *)p_ptr = p_val; \
+ } \
+ };
+
+// Object enum casts must go here
+VARIANT_ENUM_CAST(Object::ConnectFlags);
+
+VARIANT_ENUM_CAST(Vector3::Axis);
+
+VARIANT_ENUM_CAST(Error);
+VARIANT_ENUM_CAST(Margin);
+VARIANT_ENUM_CAST(Corner);
+VARIANT_ENUM_CAST(Orientation);
+VARIANT_ENUM_CAST(HAlign);
+VARIANT_ENUM_CAST(VAlign);
+VARIANT_ENUM_CAST(PropertyHint);
+VARIANT_ENUM_CAST(PropertyUsageFlags);
+VARIANT_ENUM_CAST(Variant::Type);
+VARIANT_ENUM_CAST(Variant::Operator);
+
+template <>
+struct VariantCaster<char32_t> {
+ static _FORCE_INLINE_ char32_t cast(const Variant &p_variant) {
+ return (char32_t)p_variant.operator int();
+ }
+};
+
+template <>
+struct PtrToArg<char32_t> {
+ _FORCE_INLINE_ static char32_t convert(const void *p_ptr) {
+ return char32_t(*reinterpret_cast<const int *>(p_ptr));
+ }
+ _FORCE_INLINE_ static void encode(char32_t p_val, const void *p_ptr) {
+ *(int *)p_ptr = p_val;
+ }
+};
+
+template <typename T>
+struct VariantObjectClassChecker {
+ static _FORCE_INLINE_ bool check(const Variant &p_variant) {
+ return true;
+ }
+};
+
+template <>
+struct VariantObjectClassChecker<Node *> {
+ static _FORCE_INLINE_ bool check(const Variant &p_variant) {
+ Object *obj = p_variant;
+ Node *node = p_variant;
+ return node || !obj;
+ }
+};
+
+template <>
+struct VariantObjectClassChecker<Control *> {
+ static _FORCE_INLINE_ bool check(const Variant &p_variant) {
+ Object *obj = p_variant;
+ Control *control = p_variant;
+ return control || !obj;
+ }
+};
+
+#ifdef DEBUG_METHODS_ENABLED
+
+template <class T>
+struct VariantCasterAndValidate {
+ static _FORCE_INLINE_ T cast(const Variant **p_args, uint32_t p_arg_idx, Callable::CallError &r_error) {
+ Variant::Type argtype = GetTypeInfo<T>::VARIANT_TYPE;
+ if (!Variant::can_convert_strict(p_args[p_arg_idx]->get_type(), argtype) ||
+ !VariantObjectClassChecker<T>::check(p_args[p_arg_idx])) {
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument = p_arg_idx;
+ r_error.expected = argtype;
+ }
+
+ return VariantCaster<T>::cast(*p_args[p_arg_idx]);
+ }
+};
+
+template <class T>
+struct VariantCasterAndValidate<T &> {
+ static _FORCE_INLINE_ T cast(const Variant **p_args, uint32_t p_arg_idx, Callable::CallError &r_error) {
+ Variant::Type argtype = GetTypeInfo<T>::VARIANT_TYPE;
+ if (!Variant::can_convert_strict(p_args[p_arg_idx]->get_type(), argtype) ||
+ !VariantObjectClassChecker<T>::check(p_args[p_arg_idx])) {
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument = p_arg_idx;
+ r_error.expected = argtype;
+ }
+
+ return VariantCaster<T>::cast(*p_args[p_arg_idx]);
+ }
+};
+
+template <class T>
+struct VariantCasterAndValidate<const T &> {
+ static _FORCE_INLINE_ T cast(const Variant **p_args, uint32_t p_arg_idx, Callable::CallError &r_error) {
+ Variant::Type argtype = GetTypeInfo<T>::VARIANT_TYPE;
+ if (!Variant::can_convert_strict(p_args[p_arg_idx]->get_type(), argtype) ||
+ !VariantObjectClassChecker<T>::check(p_args[p_arg_idx])) {
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument = p_arg_idx;
+ r_error.expected = argtype;
+ }
+
+ return VariantCaster<T>::cast(*p_args[p_arg_idx]);
+ }
+};
+
+#endif // DEBUG_METHODS_ENABLED
+
+template <class T, class... P, size_t... Is>
+void call_with_variant_args_helper(T *p_instance, void (T::*p_method)(P...), const Variant **p_args, Callable::CallError &r_error, IndexSequence<Is...>) {
+ r_error.error = Callable::CallError::CALL_OK;
+
+#ifdef DEBUG_METHODS_ENABLED
+ (p_instance->*p_method)(VariantCasterAndValidate<P>::cast(p_args, Is, r_error)...);
+#else
+ (p_instance->*p_method)(VariantCaster<P>::cast(*p_args[Is])...);
+#endif
+ (void)(p_args); //avoid warning
+}
+
+template <class T, class... P, size_t... Is>
+void call_with_variant_argsc_helper(T *p_instance, void (T::*p_method)(P...) const, const Variant **p_args, Callable::CallError &r_error, IndexSequence<Is...>) {
+ r_error.error = Callable::CallError::CALL_OK;
+
+#ifdef DEBUG_METHODS_ENABLED
+ (p_instance->*p_method)(VariantCasterAndValidate<P>::cast(p_args, Is, r_error)...);
+#else
+ (p_instance->*p_method)(VariantCaster<P>::cast(*p_args[Is])...);
+#endif
+ (void)(p_args); //avoid warning
+}
+
+template <class T, class... P, size_t... Is>
+void call_with_ptr_args_helper(T *p_instance, void (T::*p_method)(P...), const void **p_args, IndexSequence<Is...>) {
+ (p_instance->*p_method)(PtrToArg<P>::convert(p_args[Is])...);
+}
+
+template <class T, class... P, size_t... Is>
+void call_with_ptr_argsc_helper(T *p_instance, void (T::*p_method)(P...) const, const void **p_args, IndexSequence<Is...>) {
+ (p_instance->*p_method)(PtrToArg<P>::convert(p_args[Is])...);
+}
+
+template <class T, class R, class... P, size_t... Is>
+void call_with_ptr_args_ret_helper(T *p_instance, R (T::*p_method)(P...), const void **p_args, void *r_ret, IndexSequence<Is...>) {
+ PtrToArg<R>::encode((p_instance->*p_method)(PtrToArg<P>::convert(p_args[Is])...), r_ret);
+}
+
+template <class T, class R, class... P, size_t... Is>
+void call_with_ptr_args_retc_helper(T *p_instance, R (T::*p_method)(P...) const, const void **p_args, void *r_ret, IndexSequence<Is...>) {
+ PtrToArg<R>::encode((p_instance->*p_method)(PtrToArg<P>::convert(p_args[Is])...), r_ret);
+}
+
+template <class T, class R, class... P, size_t... Is>
+void call_with_ptr_args_static_retc_helper(T *p_instance, R (*p_method)(T *, P...), const void **p_args, void *r_ret, IndexSequence<Is...>) {
+ PtrToArg<R>::encode(p_method(p_instance, PtrToArg<P>::convert(p_args[Is])...), r_ret);
+}
+
+template <class T, class... P, size_t... Is>
+void call_with_validated_variant_args_helper(T *p_instance, void (T::*p_method)(P...), const Variant **p_args, IndexSequence<Is...>) {
+ (p_instance->*p_method)((VariantInternalAccessor<typename GetSimpleTypeT<P>::type_t>::get(p_args[Is]))...);
+}
+
+template <class T, class... P, size_t... Is>
+void call_with_validated_variant_argsc_helper(T *p_instance, void (T::*p_method)(P...) const, const Variant **p_args, IndexSequence<Is...>) {
+ (p_instance->*p_method)((VariantInternalAccessor<typename GetSimpleTypeT<P>::type_t>::get(p_args[Is]))...);
+}
+
+template <class T, class R, class... P, size_t... Is>
+void call_with_validated_variant_args_ret_helper(T *p_instance, R (T::*p_method)(P...), const Variant **p_args, Variant *r_ret, IndexSequence<Is...>) {
+ VariantInternalAccessor<typename GetSimpleTypeT<R>::type_t>::set(r_ret, (p_instance->*p_method)((VariantInternalAccessor<typename GetSimpleTypeT<P>::type_t>::get(p_args[Is]))...));
+}
+
+template <class T, class R, class... P, size_t... Is>
+void call_with_validated_variant_args_retc_helper(T *p_instance, R (T::*p_method)(P...) const, const Variant **p_args, Variant *r_ret, IndexSequence<Is...>) {
+ VariantInternalAccessor<typename GetSimpleTypeT<R>::type_t>::set(r_ret, (p_instance->*p_method)((VariantInternalAccessor<typename GetSimpleTypeT<P>::type_t>::get(p_args[Is]))...));
+}
+
+template <class T, class R, class... P, size_t... Is>
+void call_with_validated_variant_args_static_retc_helper(T *p_instance, R (*p_method)(T *, P...), const Variant **p_args, Variant *r_ret, IndexSequence<Is...>) {
+ VariantInternalAccessor<typename GetSimpleTypeT<R>::type_t>::set(r_ret, p_method(p_instance, (VariantInternalAccessor<typename GetSimpleTypeT<P>::type_t>::get(p_args[Is]))...));
+}
+
+template <class T, class... P>
+void call_with_variant_args(T *p_instance, void (T::*p_method)(P...), const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
+#ifdef DEBUG_METHODS_ENABLED
+ if ((size_t)p_argcount > sizeof...(P)) {
+ r_error.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
+ r_error.argument = sizeof...(P);
+ return;
+ }
+
+ if ((size_t)p_argcount < sizeof...(P)) {
+ r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
+ r_error.argument = sizeof...(P);
+ return;
+ }
+#endif
+ call_with_variant_args_helper<T, P...>(p_instance, p_method, p_args, r_error, BuildIndexSequence<sizeof...(P)>{});
+}
+
+template <class T, class... P>
+void call_with_variant_args_dv(T *p_instance, void (T::*p_method)(P...), const Variant **p_args, int p_argcount, Callable::CallError &r_error, const Vector<Variant> &default_values) {
+#ifdef DEBUG_ENABLED
+ if ((size_t)p_argcount > sizeof...(P)) {
+ r_error.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
+ r_error.argument = sizeof...(P);
+ return;
+ }
+#endif
+
+ int32_t missing = (int32_t)sizeof...(P) - (int32_t)p_argcount;
+
+ int32_t dvs = default_values.size();
+#ifdef DEBUG_ENABLED
+ if (missing > dvs) {
+ r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
+ r_error.argument = sizeof...(P);
+ return;
+ }
+#endif
+
+ const Variant *args[sizeof...(P) == 0 ? 1 : sizeof...(P)]; //avoid zero sized array
+ for (int32_t i = 0; i < (int32_t)sizeof...(P); i++) {
+ if (i < p_argcount) {
+ args[i] = p_args[i];
+ } else {
+ args[i] = &default_values[i - p_argcount + (dvs - missing)];
+ }
+ }
+
+ call_with_variant_args_helper(p_instance, p_method, args, r_error, BuildIndexSequence<sizeof...(P)>{});
+}
+
+template <class T, class... P>
+void call_with_variant_argsc(T *p_instance, void (T::*p_method)(P...) const, const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
+#ifdef DEBUG_METHODS_ENABLED
+ if ((size_t)p_argcount > sizeof...(P)) {
+ r_error.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
+ r_error.argument = sizeof...(P);
+ return;
+ }
+
+ if ((size_t)p_argcount < sizeof...(P)) {
+ r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
+ r_error.argument = sizeof...(P);
+ return;
+ }
+#endif
+ call_with_variant_args_helper<T, P...>(p_instance, p_method, p_args, r_error, BuildIndexSequence<sizeof...(P)>{});
+}
+
+template <class T, class... P>
+void call_with_variant_argsc_dv(T *p_instance, void (T::*p_method)(P...) const, const Variant **p_args, int p_argcount, Callable::CallError &r_error, const Vector<Variant> &default_values) {
+#ifdef DEBUG_ENABLED
+ if ((size_t)p_argcount > sizeof...(P)) {
+ r_error.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
+ r_error.argument = sizeof...(P);
+ return;
+ }
+#endif
+
+ int32_t missing = (int32_t)sizeof...(P) - (int32_t)p_argcount;
+
+ int32_t dvs = default_values.size();
+#ifdef DEBUG_ENABLED
+ if (missing > dvs) {
+ r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
+ r_error.argument = sizeof...(P);
+ return;
+ }
+#endif
+
+ const Variant *args[sizeof...(P) == 0 ? 1 : sizeof...(P)]; //avoid zero sized array
+ for (int32_t i = 0; i < (int32_t)sizeof...(P); i++) {
+ if (i < p_argcount) {
+ args[i] = p_args[i];
+ } else {
+ args[i] = &default_values[i - p_argcount + (dvs - missing)];
+ }
+ }
+
+ call_with_variant_argsc_helper(p_instance, p_method, args, r_error, BuildIndexSequence<sizeof...(P)>{});
+}
+
+template <class T, class R, class... P>
+void call_with_variant_args_ret_dv(T *p_instance, R (T::*p_method)(P...), const Variant **p_args, int p_argcount, Variant &r_ret, Callable::CallError &r_error, const Vector<Variant> &default_values) {
+#ifdef DEBUG_ENABLED
+ if ((size_t)p_argcount > sizeof...(P)) {
+ r_error.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
+ r_error.argument = sizeof...(P);
+ return;
+ }
+#endif
+
+ int32_t missing = (int32_t)sizeof...(P) - (int32_t)p_argcount;
+
+ int32_t dvs = default_values.size();
+#ifdef DEBUG_ENABLED
+ if (missing > dvs) {
+ r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
+ r_error.argument = sizeof...(P);
+ return;
+ }
+#endif
+
+ const Variant *args[sizeof...(P) == 0 ? 1 : sizeof...(P)]; //avoid zero sized array
+ for (int32_t i = 0; i < (int32_t)sizeof...(P); i++) {
+ if (i < p_argcount) {
+ args[i] = p_args[i];
+ } else {
+ args[i] = &default_values[i - p_argcount + (dvs - missing)];
+ }
+ }
+
+ call_with_variant_args_ret_helper(p_instance, p_method, args, r_ret, r_error, BuildIndexSequence<sizeof...(P)>{});
+}
+
+template <class T, class R, class... P>
+void call_with_variant_args_retc_dv(T *p_instance, R (T::*p_method)(P...) const, const Variant **p_args, int p_argcount, Variant &r_ret, Callable::CallError &r_error, const Vector<Variant> &default_values) {
+#ifdef DEBUG_ENABLED
+ if ((size_t)p_argcount > sizeof...(P)) {
+ r_error.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
+ r_error.argument = sizeof...(P);
+ return;
+ }
+#endif
+
+ int32_t missing = (int32_t)sizeof...(P) - (int32_t)p_argcount;
+
+ int32_t dvs = default_values.size();
+#ifdef DEBUG_ENABLED
+ if (missing > dvs) {
+ r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
+ r_error.argument = sizeof...(P);
+ return;
+ }
+#endif
+
+ const Variant *args[sizeof...(P) == 0 ? 1 : sizeof...(P)]; //avoid zero sized array
+ for (int32_t i = 0; i < (int32_t)sizeof...(P); i++) {
+ if (i < p_argcount) {
+ args[i] = p_args[i];
+ } else {
+ args[i] = &default_values[i - p_argcount + (dvs - missing)];
+ }
+ }
+
+ call_with_variant_args_retc_helper(p_instance, p_method, args, r_ret, r_error, BuildIndexSequence<sizeof...(P)>{});
+}
+
+template <class T, class... P>
+void call_with_ptr_args(T *p_instance, void (T::*p_method)(P...), const void **p_args) {
+ call_with_ptr_args_helper<T, P...>(p_instance, p_method, p_args, BuildIndexSequence<sizeof...(P)>{});
+}
+
+template <class T, class... P>
+void call_with_ptr_argsc(T *p_instance, void (T::*p_method)(P...) const, const void **p_args) {
+ call_with_ptr_argsc_helper<T, P...>(p_instance, p_method, p_args, BuildIndexSequence<sizeof...(P)>{});
+}
+
+template <class T, class R, class... P>
+void call_with_ptr_args_ret(T *p_instance, R (T::*p_method)(P...), const void **p_args, void *r_ret) {
+ call_with_ptr_args_ret_helper<T, R, P...>(p_instance, p_method, p_args, r_ret, BuildIndexSequence<sizeof...(P)>{});
+}
+
+template <class T, class R, class... P>
+void call_with_ptr_args_retc(T *p_instance, R (T::*p_method)(P...) const, const void **p_args, void *r_ret) {
+ call_with_ptr_args_retc_helper<T, R, P...>(p_instance, p_method, p_args, r_ret, BuildIndexSequence<sizeof...(P)>{});
+}
+
+template <class T, class R, class... P>
+void call_with_ptr_args_static_retc(T *p_instance, R (*p_method)(T *, P...), const void **p_args, void *r_ret) {
+ call_with_ptr_args_static_retc_helper<T, R, P...>(p_instance, p_method, p_args, r_ret, BuildIndexSequence<sizeof...(P)>{});
+}
+
+template <class T, class... P>
+void call_with_validated_variant_args(Variant *base, void (T::*p_method)(P...), const Variant **p_args) {
+ call_with_validated_variant_args_helper<T, P...>(VariantGetInternalPtr<T>::get_ptr(base), p_method, p_args, BuildIndexSequence<sizeof...(P)>{});
+}
+
+template <class T, class R, class... P>
+void call_with_validated_variant_args_ret(Variant *base, R (T::*p_method)(P...), const Variant **p_args, Variant *r_ret) {
+ call_with_validated_variant_args_ret_helper<T, R, P...>(VariantGetInternalPtr<T>::get_ptr(base), p_method, p_args, r_ret, BuildIndexSequence<sizeof...(P)>{});
+}
+
+template <class T, class R, class... P>
+void call_with_validated_variant_args_retc(Variant *base, R (T::*p_method)(P...) const, const Variant **p_args, Variant *r_ret) {
+ call_with_validated_variant_args_retc_helper<T, R, P...>(VariantGetInternalPtr<T>::get_ptr(base), p_method, p_args, r_ret, BuildIndexSequence<sizeof...(P)>{});
+}
+
+template <class T, class R, class... P>
+void call_with_validated_variant_args_static_retc(Variant *base, R (*p_method)(T *, P...), const Variant **p_args, Variant *r_ret) {
+ call_with_validated_variant_args_static_retc_helper<T, R, P...>(VariantGetInternalPtr<T>::get_ptr(base), p_method, p_args, r_ret, BuildIndexSequence<sizeof...(P)>{});
+}
+
+// GCC raises "parameter 'p_args' set but not used" when P = {},
+// it's not clever enough to treat other P values as making this branch valid.
+#if defined(DEBUG_METHODS_ENABLED) && defined(__GNUC__) && !defined(__clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-but-set-parameter"
+#endif
+
+#ifdef DEBUG_METHODS_ENABLED
+
+template <class Q>
+void call_get_argument_type_helper(int p_arg, int &index, Variant::Type &type) {
+ if (p_arg == index) {
+ type = GetTypeInfo<Q>::VARIANT_TYPE;
+ }
+ index++;
+}
+
+template <class... P>
+Variant::Type call_get_argument_type(int p_arg) {
+ Variant::Type type = Variant::NIL;
+ int index = 0;
+ // I think rocket science is simpler than modern C++.
+ using expand_type = int[];
+ expand_type a{ 0, (call_get_argument_type_helper<P>(p_arg, index, type), 0)... };
+ (void)a; // Suppress (valid, but unavoidable) -Wunused-variable warning.
+ (void)index; // Suppress GCC warning.
+ return type;
+}
+
+template <class Q>
+void call_get_argument_type_info_helper(int p_arg, int &index, PropertyInfo &info) {
+ if (p_arg == index) {
+ info = GetTypeInfo<Q>::get_class_info();
+ }
+ index++;
+}
+
+template <class... P>
+void call_get_argument_type_info(int p_arg, PropertyInfo &info) {
+ int index = 0;
+ // I think rocket science is simpler than modern C++.
+ using expand_type = int[];
+ expand_type a{ 0, (call_get_argument_type_info_helper<P>(p_arg, index, info), 0)... };
+ (void)a; // Suppress (valid, but unavoidable) -Wunused-variable warning.
+ (void)index; // Suppress GCC warning.
+}
+
+template <class Q>
+void call_get_argument_metadata_helper(int p_arg, int &index, GodotTypeInfo::Metadata &md) {
+ if (p_arg == index) {
+ md = GetTypeInfo<Q>::METADATA;
+ }
+ index++;
+}
+
+template <class... P>
+GodotTypeInfo::Metadata call_get_argument_metadata(int p_arg) {
+ GodotTypeInfo::Metadata md = GodotTypeInfo::METADATA_NONE;
+
+ int index = 0;
+ // I think rocket science is simpler than modern C++.
+ using expand_type = int[];
+ expand_type a{ 0, (call_get_argument_metadata_helper<P>(p_arg, index, md), 0)... };
+ (void)a; // Suppress (valid, but unavoidable) -Wunused-variable warning.
+ (void)index;
+ return md;
+}
+
+#else
+
+template <class... P>
+Variant::Type call_get_argument_type(int p_arg) {
+ return Variant::NIL;
+}
+
+#endif // DEBUG_METHODS_ENABLED
+
+//////////////////////
+
+template <class T, class R, class... P, size_t... Is>
+void call_with_variant_args_ret_helper(T *p_instance, R (T::*p_method)(P...), const Variant **p_args, Variant &r_ret, Callable::CallError &r_error, IndexSequence<Is...>) {
+ r_error.error = Callable::CallError::CALL_OK;
+
+#ifdef DEBUG_METHODS_ENABLED
+ r_ret = (p_instance->*p_method)(VariantCasterAndValidate<P>::cast(p_args, Is, r_error)...);
+#else
+ r_ret = (p_instance->*p_method)(VariantCaster<P>::cast(*p_args[Is])...);
+#endif
+}
+
+template <class T, class R, class... P>
+void call_with_variant_args_ret(T *p_instance, R (T::*p_method)(P...), const Variant **p_args, int p_argcount, Variant &r_ret, Callable::CallError &r_error) {
+#ifdef DEBUG_METHODS_ENABLED
+ if ((size_t)p_argcount > sizeof...(P)) {
+ r_error.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
+ r_error.argument = sizeof...(P);
+ return;
+ }
+
+ if ((size_t)p_argcount < sizeof...(P)) {
+ r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
+ r_error.argument = sizeof...(P);
+ return;
+ }
+#endif
+ call_with_variant_args_ret_helper<T, R, P...>(p_instance, p_method, p_args, r_ret, r_error, BuildIndexSequence<sizeof...(P)>{});
+}
+
+template <class T, class R, class... P, size_t... Is>
+void call_with_variant_args_retc_helper(T *p_instance, R (T::*p_method)(P...) const, const Variant **p_args, Variant &r_ret, Callable::CallError &r_error, IndexSequence<Is...>) {
+ r_error.error = Callable::CallError::CALL_OK;
+
+#ifdef DEBUG_METHODS_ENABLED
+ r_ret = (p_instance->*p_method)(VariantCasterAndValidate<P>::cast(p_args, Is, r_error)...);
+#else
+ r_ret = (p_instance->*p_method)(VariantCaster<P>::cast(*p_args[Is])...);
+#endif
+ (void)p_args;
+}
+
+template <class T, class R, class... P>
+void call_with_variant_args_retc(T *p_instance, R (T::*p_method)(P...) const, const Variant **p_args, int p_argcount, Variant &r_ret, Callable::CallError &r_error) {
+#ifdef DEBUG_METHODS_ENABLED
+ if ((size_t)p_argcount > sizeof...(P)) {
+ r_error.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
+ r_error.argument = sizeof...(P);
+ return;
+ }
+
+ if ((size_t)p_argcount < sizeof...(P)) {
+ r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
+ r_error.argument = sizeof...(P);
+ return;
+ }
+#endif
+ call_with_variant_args_retc_helper<T, R, P...>(p_instance, p_method, p_args, r_ret, r_error, BuildIndexSequence<sizeof...(P)>{});
+}
+
+template <class T, class R, class... P, size_t... Is>
+void call_with_variant_args_retc_static_helper(T *p_instance, R (*p_method)(T *, P...), const Variant **p_args, Variant &r_ret, Callable::CallError &r_error, IndexSequence<Is...>) {
+ r_error.error = Callable::CallError::CALL_OK;
+
+#ifdef DEBUG_METHODS_ENABLED
+ r_ret = (p_method)(p_instance, VariantCasterAndValidate<P>::cast(p_args, Is, r_error)...);
+#else
+ r_ret = (p_method)(p_instance, VariantCaster<P>::cast(*p_args[Is])...);
+#endif
+
+ (void)p_args;
+}
+
+template <class T, class R, class... P>
+void call_with_variant_args_retc_static_helper_dv(T *p_instance, R (*p_method)(T *, P...), const Variant **p_args, int p_argcount, Variant &r_ret, const Vector<Variant> &default_values, Callable::CallError &r_error) {
+#ifdef DEBUG_ENABLED
+ if ((size_t)p_argcount > sizeof...(P)) {
+ r_error.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
+ r_error.argument = sizeof...(P);
+ return;
+ }
+#endif
+
+ int32_t missing = (int32_t)sizeof...(P) - (int32_t)p_argcount;
+
+ int32_t dvs = default_values.size();
+#ifdef DEBUG_ENABLED
+ if (missing > dvs) {
+ r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
+ r_error.argument = sizeof...(P);
+ return;
+ }
+#endif
+
+ const Variant *args[sizeof...(P) == 0 ? 1 : sizeof...(P)]; //avoid zero sized array
+ for (int32_t i = 0; i < (int32_t)sizeof...(P); i++) {
+ if (i < p_argcount) {
+ args[i] = p_args[i];
+ } else {
+ args[i] = &default_values[i - p_argcount + (dvs - missing)];
+ }
+ }
+
+ call_with_variant_args_retc_static_helper(p_instance, p_method, args, r_ret, r_error, BuildIndexSequence<sizeof...(P)>{});
+}
+
+#if defined(DEBUG_METHODS_ENABLED) && defined(__GNUC__) && !defined(__clang__)
+#pragma GCC diagnostic pop
+#endif
+
+#endif // BINDER_COMMON_H
diff --git a/core/callable.cpp b/core/variant/callable.cpp
index b7bdc715f8..e504fd05e3 100644
--- a/core/callable.cpp
+++ b/core/variant/callable.cpp
@@ -30,10 +30,11 @@
#include "callable.h"
-#include "core/script_language.h"
-#include "message_queue.h"
-#include "object.h"
-#include "reference.h"
+#include "callable_bind.h"
+#include "core/object/message_queue.h"
+#include "core/object/object.h"
+#include "core/object/reference.h"
+#include "core/object/script_language.h"
void Callable::call_deferred(const Variant **p_arguments, int p_argcount) const {
MessageQueue::get_singleton()->push_callable(*this, p_arguments, p_argcount);
@@ -53,6 +54,18 @@ void Callable::call(const Variant **p_arguments, int p_argcount, Variant &r_retu
}
}
+Callable Callable::bind(const Variant **p_arguments, int p_argcount) const {
+ Vector<Variant> args;
+ args.resize(p_argcount);
+ for (int i = 0; i < p_argcount; i++) {
+ args.write[i] = *p_arguments[i];
+ }
+ return Callable(memnew(CallableCustomBind(*this, args)));
+}
+Callable Callable::unbind(int p_argcount) const {
+ return Callable(memnew(CallableCustomUnbind(*this, p_argcount)));
+}
+
Object *Callable::get_object() const {
if (is_null()) {
return nullptr;
@@ -85,6 +98,18 @@ CallableCustom *Callable::get_custom() const {
return custom;
}
+const Callable *Callable::get_base_comparator() const {
+ const Callable *comparator = nullptr;
+ if (is_custom()) {
+ comparator = custom->get_base_comparator();
+ }
+ if (comparator) {
+ return comparator;
+ } else {
+ return this;
+ }
+}
+
uint32_t Callable::hash() const {
if (is_custom()) {
return custom->hash();
@@ -258,6 +283,10 @@ Callable::~Callable() {
}
}
+const Callable *CallableCustom::get_base_comparator() const {
+ return nullptr;
+}
+
CallableCustom::CallableCustom() {
ref_count.init();
}
diff --git a/core/callable.h b/core/variant/callable.h
index 7fd6b54cf7..9334ae3581 100644
--- a/core/callable.h
+++ b/core/variant/callable.h
@@ -31,9 +31,9 @@
#ifndef CALLABLE_H
#define CALLABLE_H
-#include "core/list.h"
-#include "core/object_id.h"
-#include "core/string_name.h"
+#include "core/object/object_id.h"
+#include "core/string/string_name.h"
+#include "core/templates/list.h"
class Object;
class Variant;
@@ -62,9 +62,9 @@ public:
CALL_ERROR_TOO_FEW_ARGUMENTS, // expected is number of arguments
CALL_ERROR_INSTANCE_IS_NULL,
};
- Error error;
- int argument;
- int expected;
+ Error error = Error::CALL_OK;
+ int argument = 0;
+ int expected = 0;
};
void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, CallError &r_call_error) const;
@@ -80,6 +80,9 @@ public:
return method != StringName();
}
+ Callable bind(const Variant **p_arguments, int p_argcount) const;
+ Callable unbind(int p_argcount) const;
+
Object *get_object() const;
ObjectID get_object_id() const;
StringName get_method() const;
@@ -87,6 +90,8 @@ public:
uint32_t hash() const;
+ const Callable *get_base_comparator() const; //used for bind/unbind to do less precise comparisons (ignoring binds) in signal connect/disconnect
+
bool operator==(const Callable &p_callable) const;
bool operator!=(const Callable &p_callable) const;
bool operator<(const Callable &p_callable) const;
@@ -119,6 +124,7 @@ public:
virtual CompareLessFunc get_compare_less_func() const = 0;
virtual ObjectID get_object() const = 0; //must always be able to provide an object
virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const = 0;
+ virtual const Callable *get_base_comparator() const;
CallableCustom();
virtual ~CallableCustom() {}
diff --git a/core/variant/callable_bind.cpp b/core/variant/callable_bind.cpp
new file mode 100644
index 0000000000..da08d3ccbd
--- /dev/null
+++ b/core/variant/callable_bind.cpp
@@ -0,0 +1,193 @@
+/*************************************************************************/
+/* callable_bind.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* 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. */
+/*************************************************************************/
+
+#include "callable_bind.h"
+
+//////////////////////////////////
+
+uint32_t CallableCustomBind::hash() const {
+ return callable.hash();
+}
+String CallableCustomBind::get_as_text() const {
+ return callable.operator String();
+}
+
+bool CallableCustomBind::_equal_func(const CallableCustom *p_a, const CallableCustom *p_b) {
+ const CallableCustomBind *a = (const CallableCustomBind *)p_a;
+ const CallableCustomBind *b = (const CallableCustomBind *)p_b;
+
+ if (!(a->callable != b->callable)) {
+ return false;
+ }
+
+ if (a->binds.size() != b->binds.size()) {
+ return false;
+ }
+
+ return true;
+}
+
+bool CallableCustomBind::_less_func(const CallableCustom *p_a, const CallableCustom *p_b) {
+ const CallableCustomBind *a = (const CallableCustomBind *)p_a;
+ const CallableCustomBind *b = (const CallableCustomBind *)p_b;
+
+ if (a->callable < b->callable) {
+ return true;
+ } else if (b->callable < a->callable) {
+ return false;
+ }
+
+ return a->binds.size() < b->binds.size();
+}
+
+CallableCustom::CompareEqualFunc CallableCustomBind::get_compare_equal_func() const {
+ return _equal_func;
+}
+CallableCustom::CompareLessFunc CallableCustomBind::get_compare_less_func() const {
+ return _less_func;
+}
+ObjectID CallableCustomBind::get_object() const {
+ return callable.get_object_id();
+}
+const Callable *CallableCustomBind::get_base_comparator() const {
+ return &callable;
+}
+
+void CallableCustomBind::call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const {
+ const Variant **args = (const Variant **)alloca(sizeof(const Variant **) * (binds.size() + p_argcount));
+ for (int i = 0; i < p_argcount; i++) {
+ args[i] = (const Variant *)p_arguments[i];
+ }
+ for (int i = 0; i < binds.size(); i++) {
+ args[i + p_argcount] = (const Variant *)&binds[i];
+ }
+
+ callable.call(args, p_argcount + binds.size(), r_return_value, r_call_error);
+}
+
+CallableCustomBind::CallableCustomBind(const Callable &p_callable, const Vector<Variant> &p_binds) {
+ callable = p_callable;
+ binds = p_binds;
+}
+
+CallableCustomBind::~CallableCustomBind() {
+}
+
+//////////////////////////////////
+
+uint32_t CallableCustomUnbind::hash() const {
+ return callable.hash();
+}
+String CallableCustomUnbind::get_as_text() const {
+ return callable.operator String();
+}
+
+bool CallableCustomUnbind::_equal_func(const CallableCustom *p_a, const CallableCustom *p_b) {
+ const CallableCustomUnbind *a = (const CallableCustomUnbind *)p_a;
+ const CallableCustomUnbind *b = (const CallableCustomUnbind *)p_b;
+
+ if (!(a->callable != b->callable)) {
+ return false;
+ }
+
+ if (a->argcount != b->argcount) {
+ return false;
+ }
+
+ return true;
+}
+
+bool CallableCustomUnbind::_less_func(const CallableCustom *p_a, const CallableCustom *p_b) {
+ const CallableCustomUnbind *a = (const CallableCustomUnbind *)p_a;
+ const CallableCustomUnbind *b = (const CallableCustomUnbind *)p_b;
+
+ if (a->callable < b->callable) {
+ return true;
+ } else if (b->callable < a->callable) {
+ return false;
+ }
+
+ return a->argcount < b->argcount;
+}
+
+CallableCustom::CompareEqualFunc CallableCustomUnbind::get_compare_equal_func() const {
+ return _equal_func;
+}
+CallableCustom::CompareLessFunc CallableCustomUnbind::get_compare_less_func() const {
+ return _less_func;
+}
+ObjectID CallableCustomUnbind::get_object() const {
+ return callable.get_object_id();
+}
+const Callable *CallableCustomUnbind::get_base_comparator() const {
+ return &callable;
+}
+
+void CallableCustomUnbind::call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const {
+ if (argcount > p_argcount) {
+ r_call_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
+ r_call_error.argument = 0;
+ r_call_error.expected = argcount;
+ return;
+ }
+ callable.call(p_arguments, p_argcount - argcount, r_return_value, r_call_error);
+}
+
+CallableCustomUnbind::CallableCustomUnbind(const Callable &p_callable, int p_argcount) {
+ callable = p_callable;
+ argcount = p_argcount;
+}
+
+CallableCustomUnbind::~CallableCustomUnbind() {
+}
+
+Callable callable_bind(const Callable &p_callable, const Variant &p_arg1) {
+ return p_callable.bind((const Variant **)&p_arg1, 1);
+}
+
+Callable callable_bind(const Callable &p_callable, const Variant &p_arg1, const Variant &p_arg2) {
+ const Variant *args[2] = { &p_arg1, &p_arg2 };
+ return p_callable.bind(args, 2);
+}
+
+Callable callable_bind(const Callable &p_callable, const Variant &p_arg1, const Variant &p_arg2, const Variant &p_arg3) {
+ const Variant *args[3] = { &p_arg1, &p_arg2, &p_arg3 };
+ return p_callable.bind(args, 3);
+}
+
+Callable callable_bind(const Callable &p_callable, const Variant &p_arg1, const Variant &p_arg2, const Variant &p_arg3, const Variant &p_arg4) {
+ const Variant *args[4] = { &p_arg1, &p_arg2, &p_arg3, &p_arg4 };
+ return p_callable.bind(args, 4);
+}
+
+Callable callable_bind(const Callable &p_callable, const Variant &p_arg1, const Variant &p_arg2, const Variant &p_arg3, const Variant &p_arg4, const Variant &p_arg5) {
+ const Variant *args[5] = { &p_arg1, &p_arg2, &p_arg3, &p_arg4, &p_arg5 };
+ return p_callable.bind(args, 5);
+}
diff --git a/core/variant/callable_bind.h b/core/variant/callable_bind.h
new file mode 100644
index 0000000000..fc5659e412
--- /dev/null
+++ b/core/variant/callable_bind.h
@@ -0,0 +1,85 @@
+/*************************************************************************/
+/* callable_bind.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* 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. */
+/*************************************************************************/
+
+#ifndef CALLABLE_BIND_H
+#define CALLABLE_BIND_H
+
+#include "core/variant/callable.h"
+#include "core/variant/variant.h"
+
+class CallableCustomBind : public CallableCustom {
+ Callable callable;
+ Vector<Variant> binds;
+
+ static bool _equal_func(const CallableCustom *p_a, const CallableCustom *p_b);
+ static bool _less_func(const CallableCustom *p_a, const CallableCustom *p_b);
+
+public:
+ //for every type that inherits, these must always be the same for this type
+ virtual uint32_t hash() const;
+ virtual String get_as_text() const;
+ virtual CompareEqualFunc get_compare_equal_func() const;
+ virtual CompareLessFunc get_compare_less_func() const;
+ virtual ObjectID get_object() const; //must always be able to provide an object
+ virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const;
+ virtual const Callable *get_base_comparator() const;
+
+ CallableCustomBind(const Callable &p_callable, const Vector<Variant> &p_binds);
+ virtual ~CallableCustomBind();
+};
+
+class CallableCustomUnbind : public CallableCustom {
+ Callable callable;
+ int argcount;
+
+ static bool _equal_func(const CallableCustom *p_a, const CallableCustom *p_b);
+ static bool _less_func(const CallableCustom *p_a, const CallableCustom *p_b);
+
+public:
+ //for every type that inherits, these must always be the same for this type
+ virtual uint32_t hash() const;
+ virtual String get_as_text() const;
+ virtual CompareEqualFunc get_compare_equal_func() const;
+ virtual CompareLessFunc get_compare_less_func() const;
+ virtual ObjectID get_object() const; //must always be able to provide an object
+ virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const;
+ virtual const Callable *get_base_comparator() const;
+
+ CallableCustomUnbind(const Callable &p_callable, int p_argcount);
+ virtual ~CallableCustomUnbind();
+};
+
+Callable callable_bind(const Callable &p_callable, const Variant &p_arg1);
+Callable callable_bind(const Callable &p_callable, const Variant &p_arg1, const Variant &p_arg2);
+Callable callable_bind(const Callable &p_callable, const Variant &p_arg1, const Variant &p_arg2, const Variant &p_arg3);
+Callable callable_bind(const Callable &p_callable, const Variant &p_arg1, const Variant &p_arg2, const Variant &p_arg3, const Variant &p_arg4);
+Callable callable_bind(const Callable &p_callable, const Variant &p_arg1, const Variant &p_arg2, const Variant &p_arg3, const Variant &p_arg4, const Variant &p_arg5);
+
+#endif // CALLABLE_BIND_H
diff --git a/core/container_type_validate.h b/core/variant/container_type_validate.h
index f2724e884d..4d3a5f683b 100644
--- a/core/container_type_validate.h
+++ b/core/variant/container_type_validate.h
@@ -31,14 +31,14 @@
#ifndef CONTAINER_TYPE_VALIDATE_H
#define CONTAINER_TYPE_VALIDATE_H
-#include "core/script_language.h"
-#include "core/variant.h"
+#include "core/object/script_language.h"
+#include "core/variant/variant.h"
struct ContainerTypeValidate {
Variant::Type type = Variant::NIL;
StringName class_name;
Ref<Script> script;
- const char *where = "conatiner";
+ const char *where = "container";
_FORCE_INLINE_ bool can_reference(const ContainerTypeValidate &p_type) const {
if (type == p_type.type) {
diff --git a/core/dictionary.cpp b/core/variant/dictionary.cpp
index 052e1bdae1..2bc1f7a86d 100644
--- a/core/dictionary.cpp
+++ b/core/variant/dictionary.cpp
@@ -30,9 +30,9 @@
#include "dictionary.h"
-#include "core/ordered_hash_map.h"
-#include "core/safe_refcount.h"
-#include "core/variant.h"
+#include "core/templates/ordered_hash_map.h"
+#include "core/templates/safe_refcount.h"
+#include "core/variant/variant.h"
struct DictionaryPrivate {
SafeRefCount refcount;
diff --git a/core/dictionary.h b/core/variant/dictionary.h
index a01d96ba01..bbe94122ad 100644
--- a/core/dictionary.h
+++ b/core/variant/dictionary.h
@@ -31,9 +31,9 @@
#ifndef DICTIONARY_H
#define DICTIONARY_H
-#include "core/array.h"
-#include "core/list.h"
-#include "core/ustring.h"
+#include "core/string/ustring.h"
+#include "core/templates/list.h"
+#include "core/variant/array.h"
class Variant;
diff --git a/core/method_ptrcall.h b/core/variant/method_ptrcall.h
index 022ed2a5d6..40fa3543dc 100644
--- a/core/method_ptrcall.h
+++ b/core/variant/method_ptrcall.h
@@ -32,15 +32,12 @@
#define METHOD_PTRCALL_H
#include "core/math/transform_2d.h"
-#include "core/object_id.h"
+#include "core/object/object_id.h"
#include "core/typedefs.h"
-#include "core/variant.h"
-
-#ifdef PTRCALL_ENABLED
+#include "core/variant/variant.h"
template <class T>
-struct PtrToArg {
-};
+struct PtrToArg {};
#define MAKE_PTRARG(m_type) \
template <> \
@@ -146,7 +143,7 @@ MAKE_PTRARG(PackedVector3Array);
MAKE_PTRARG(PackedColorArray);
MAKE_PTRARG_BY_REFERENCE(Variant);
-//this is for Object
+// This is for Object.
template <class T>
struct PtrToArg<T *> {
@@ -170,7 +167,7 @@ struct PtrToArg<const T *> {
}
};
-//this is for ObjectID
+// This is for ObjectID.
template <>
struct PtrToArg<ObjectID> {
@@ -183,7 +180,7 @@ struct PtrToArg<ObjectID> {
}
};
-//this is for the special cases used by Variant
+// This is for the special cases used by Variant.
#define MAKE_VECARG(m_type) \
template <> \
@@ -274,18 +271,11 @@ struct PtrToArg<ObjectID> {
return ret; \
} \
}
-/*
-MAKE_VECARG(String);
-MAKE_VECARG(uint8_t);
-MAKE_VECARG(int);
-MAKE_VECARG(float);
-MAKE_VECARG(Vector2);
-MAKE_VECARG(Vector3);
-MAKE_VECARG(Color);
-*/
+
MAKE_VECARG_ALT(String, StringName);
-//for stuff that gets converted to Array vectors
+// For stuff that gets converted to Array vectors.
+
#define MAKE_VECARR(m_type) \
template <> \
struct PtrToArg<Vector<m_type>> { \
@@ -429,6 +419,7 @@ struct PtrToArg<Vector<Face3>> {
}
}
};
+
template <>
struct PtrToArg<const Vector<Face3> &> {
_FORCE_INLINE_ static Vector<Face3> convert(const void *p_ptr) {
@@ -450,4 +441,3 @@ struct PtrToArg<const Vector<Face3> &> {
};
#endif // METHOD_PTRCALL_H
-#endif
diff --git a/core/type_info.h b/core/variant/type_info.h
index e3d2b5bd53..ce7c2bfe14 100644
--- a/core/type_info.h
+++ b/core/variant/type_info.h
@@ -31,7 +31,7 @@
#ifndef TYPE_INFO_H
#define TYPE_INFO_H
-#ifdef DEBUG_METHODS_ENABLED
+#include "core/typedefs.h"
template <bool C, typename T = void>
struct EnableIf {
@@ -132,7 +132,8 @@ MAKE_TYPE_INFO_WITH_META(uint32_t, Variant::INT, GodotTypeInfo::METADATA_INT_IS_
MAKE_TYPE_INFO_WITH_META(int32_t, Variant::INT, GodotTypeInfo::METADATA_INT_IS_INT32)
MAKE_TYPE_INFO_WITH_META(uint64_t, Variant::INT, GodotTypeInfo::METADATA_INT_IS_UINT64)
MAKE_TYPE_INFO_WITH_META(int64_t, Variant::INT, GodotTypeInfo::METADATA_INT_IS_INT64)
-MAKE_TYPE_INFO(wchar_t, Variant::INT)
+MAKE_TYPE_INFO(char16_t, Variant::INT)
+MAKE_TYPE_INFO(char32_t, Variant::INT)
MAKE_TYPE_INFO_WITH_META(float, Variant::FLOAT, GodotTypeInfo::METADATA_REAL_IS_FLOAT)
MAKE_TYPE_INFO_WITH_META(double, Variant::FLOAT, GodotTypeInfo::METADATA_REAL_IS_DOUBLE)
@@ -152,7 +153,7 @@ MAKE_TYPE_INFO(Transform, Variant::TRANSFORM)
MAKE_TYPE_INFO(Color, Variant::COLOR)
MAKE_TYPE_INFO(StringName, Variant::STRING_NAME)
MAKE_TYPE_INFO(NodePath, Variant::NODE_PATH)
-MAKE_TYPE_INFO(RID, Variant::_RID)
+MAKE_TYPE_INFO(RID, Variant::RID)
MAKE_TYPE_INFO(Callable, Variant::CALLABLE)
MAKE_TYPE_INFO(Signal, Variant::SIGNAL)
MAKE_TYPE_INFO(Dictionary, Variant::DICTIONARY)
@@ -266,11 +267,4 @@ inline StringName __constant_get_enum_name(T param, const String &p_constant) {
#define CLASS_INFO(m_type) (GetTypeInfo<m_type *>::get_class_info())
-#else
-
-#define MAKE_ENUM_TYPE_INFO(m_enum)
-#define CLASS_INFO(m_type)
-
-#endif // DEBUG_METHODS_ENABLED
-
#endif // TYPE_INFO_H
diff --git a/core/typed_array.h b/core/variant/typed_array.h
index 86f26d7550..2f11f22ff8 100644
--- a/core/typed_array.h
+++ b/core/variant/typed_array.h
@@ -31,9 +31,9 @@
#ifndef TYPED_ARRAY_H
#define TYPED_ARRAY_H
-#include "core/array.h"
-#include "core/method_ptrcall.h"
-#include "core/variant.h"
+#include "core/variant/array.h"
+#include "core/variant/method_ptrcall.h"
+#include "core/variant/variant.h"
template <class T>
class TypedArray : public Array {
@@ -105,7 +105,7 @@ MAKE_TYPED_ARRAY(Transform, Variant::TRANSFORM)
MAKE_TYPED_ARRAY(Color, Variant::COLOR)
MAKE_TYPED_ARRAY(StringName, Variant::STRING_NAME)
MAKE_TYPED_ARRAY(NodePath, Variant::NODE_PATH)
-MAKE_TYPED_ARRAY(RID, Variant::_RID)
+MAKE_TYPED_ARRAY(RID, Variant::RID)
MAKE_TYPED_ARRAY(Callable, Variant::CALLABLE)
MAKE_TYPED_ARRAY(Signal, Variant::SIGNAL)
MAKE_TYPED_ARRAY(Dictionary, Variant::DICTIONARY)
@@ -120,8 +120,6 @@ MAKE_TYPED_ARRAY(Vector<Vector2>, Variant::PACKED_VECTOR2_ARRAY)
MAKE_TYPED_ARRAY(Vector<Vector3>, Variant::PACKED_VECTOR3_ARRAY)
MAKE_TYPED_ARRAY(Vector<Color>, Variant::PACKED_COLOR_ARRAY)
-#ifdef PTRCALL_ENABLED
-
template <class T>
struct PtrToArg<TypedArray<T>> {
_FORCE_INLINE_ static TypedArray<T> convert(const void *p_ptr) {
@@ -140,8 +138,6 @@ struct PtrToArg<const TypedArray<T> &> {
}
};
-#endif // PTRCALL_ENABLED
-
#ifdef DEBUG_METHODS_ENABLED
template <class T>
@@ -207,7 +203,7 @@ MAKE_TYPED_ARRAY_INFO(Transform, Variant::TRANSFORM)
MAKE_TYPED_ARRAY_INFO(Color, Variant::COLOR)
MAKE_TYPED_ARRAY_INFO(StringName, Variant::STRING_NAME)
MAKE_TYPED_ARRAY_INFO(NodePath, Variant::NODE_PATH)
-MAKE_TYPED_ARRAY_INFO(RID, Variant::_RID)
+MAKE_TYPED_ARRAY_INFO(RID, Variant::RID)
MAKE_TYPED_ARRAY_INFO(Callable, Variant::CALLABLE)
MAKE_TYPED_ARRAY_INFO(Signal, Variant::SIGNAL)
MAKE_TYPED_ARRAY_INFO(Dictionary, Variant::DICTIONARY)
diff --git a/core/variant.cpp b/core/variant/variant.cpp
index f6b7e2821a..741d05c139 100644
--- a/core/variant.cpp
+++ b/core/variant/variant.cpp
@@ -33,10 +33,10 @@
#include "core/core_string_names.h"
#include "core/debugger/engine_debugger.h"
#include "core/io/marshalls.h"
+#include "core/io/resource.h"
#include "core/math/math_funcs.h"
-#include "core/print_string.h"
-#include "core/resource.h"
-#include "core/variant_parser.h"
+#include "core/string/print_string.h"
+#include "core/variant/variant_parser.h"
#include "scene/gui/control.h"
#include "scene/main/node.h"
@@ -109,7 +109,7 @@ String Variant::get_type_name(Variant::Type p_type) {
return "Color";
} break;
- case _RID: {
+ case RID: {
return "RID";
} break;
case OBJECT: {
@@ -342,7 +342,7 @@ bool Variant::can_convert(Variant::Type p_type_from, Variant::Type p_type_to) {
} break;
- case _RID: {
+ case RID: {
static const Type valid[] = {
OBJECT,
NIL
@@ -649,7 +649,7 @@ bool Variant::can_convert_strict(Variant::Type p_type_from, Variant::Type p_type
} break;
- case _RID: {
+ case RID: {
static const Type valid[] = {
OBJECT,
NIL
@@ -891,8 +891,8 @@ bool Variant::is_zero() const {
return *reinterpret_cast<const Color *>(_data._mem) == Color();
} break;
- case _RID: {
- return *reinterpret_cast<const RID *>(_data._mem) == RID();
+ case RID: {
+ return *reinterpret_cast<const ::RID *>(_data._mem) == ::RID();
} break;
case OBJECT: {
return _get_obj().obj == nullptr;
@@ -1109,8 +1109,8 @@ void Variant::reference(const Variant &p_variant) {
memnew_placement(_data._mem, Color(*reinterpret_cast<const Color *>(p_variant._data._mem)));
} break;
- case _RID: {
- memnew_placement(_data._mem, RID(*reinterpret_cast<const RID *>(p_variant._data._mem)));
+ case RID: {
+ memnew_placement(_data._mem, ::RID(*reinterpret_cast<const ::RID *>(p_variant._data._mem)));
} break;
case OBJECT: {
memnew_placement(_data._mem, ObjData);
@@ -1266,7 +1266,7 @@ void Variant::zero() {
}
}
-void Variant::clear() {
+void Variant::_clear_internal() {
switch (type) {
case STRING: {
reinterpret_cast<String *>(_data._mem)->~String();
@@ -1311,9 +1311,11 @@ void Variant::clear() {
_get_obj().obj = nullptr;
_get_obj().id = ObjectID();
} break;
- case _RID: {
+ case RID: {
// not much need probably
- reinterpret_cast<RID *>(_data._mem)->~RID();
+ // Can't seem to use destructor + scoping operator, so hack.
+ typedef ::RID RID_Class;
+ reinterpret_cast<RID_Class *>(_data._mem)->~RID_Class();
} break;
case CALLABLE: {
reinterpret_cast<Callable *>(_data._mem)->~Callable();
@@ -1358,8 +1360,6 @@ void Variant::clear() {
default: {
} /* not needed */
}
-
- type = NIL;
}
Variant::operator signed int() const {
@@ -1454,7 +1454,7 @@ Variant::operator signed long() const {
case INT:
return _data._int;
case FLOAT:
- return _data._real;
+ return _data._float;
case STRING:
return operator String().to_int();
default: {
@@ -1474,7 +1474,7 @@ Variant::operator unsigned long() const {
case INT:
return _data._int;
case FLOAT:
- return _data._real;
+ return _data._float;
case STRING:
return operator String().to_int();
default: {
@@ -1558,7 +1558,7 @@ Variant::operator unsigned char() const {
}
}
-Variant::operator CharType() const {
+Variant::operator char32_t() const {
return operator unsigned int();
}
@@ -1573,7 +1573,7 @@ Variant::operator float() const {
case FLOAT:
return _data._float;
case STRING:
- return operator String().to_double();
+ return operator String().to_float();
default: {
return 0;
}
@@ -1591,7 +1591,7 @@ Variant::operator double() const {
case FLOAT:
return _data._float;
case STRING:
- return operator String().to_double();
+ return operator String().to_float();
default: {
return 0;
}
@@ -1849,8 +1849,8 @@ String Variant::stringify(List<const void *> &stack) const {
const Signal &s = *reinterpret_cast<const Signal *>(_data._mem);
return s;
} break;
- case _RID: {
- const RID &s = *reinterpret_cast<const RID *>(_data._mem);
+ case RID: {
+ const ::RID &s = *reinterpret_cast<const ::RID *>(_data._mem);
return "RID(" + itos(s.get_id()) + ")";
} break;
default: {
@@ -2041,25 +2041,25 @@ Variant::operator NodePath() const {
}
}
-Variant::operator RID() const {
- if (type == _RID) {
- return *reinterpret_cast<const RID *>(_data._mem);
+Variant::operator ::RID() const {
+ if (type == RID) {
+ return *reinterpret_cast<const ::RID *>(_data._mem);
} else if (type == OBJECT && _get_obj().obj == nullptr) {
- return RID();
+ return ::RID();
} else if (type == OBJECT && _get_obj().obj) {
#ifdef DEBUG_ENABLED
if (EngineDebugger::is_active()) {
- ERR_FAIL_COND_V_MSG(ObjectDB::get_instance(_get_obj().id) == nullptr, RID(), "Invalid pointer (object was freed).");
+ ERR_FAIL_COND_V_MSG(ObjectDB::get_instance(_get_obj().id) == nullptr, ::RID(), "Invalid pointer (object was freed).");
}
#endif
Callable::CallError ce;
Variant ret = _get_obj().obj->call(CoreStringNames::get_singleton()->get_rid, nullptr, 0, ce);
- if (ce.error == Callable::CallError::CALL_OK && ret.get_type() == Variant::_RID) {
+ if (ce.error == Callable::CallError::CALL_OK && ret.get_type() == Variant::RID) {
return ret;
}
- return RID();
+ return ::RID();
} else {
- return RID();
+ return ::RID();
}
}
@@ -2263,9 +2263,9 @@ Variant::operator Vector<Color>() const {
/* helpers */
-Variant::operator Vector<RID>() const {
+Variant::operator Vector<::RID>() const {
Array va = operator Array();
- Vector<RID> rids;
+ Vector<::RID> rids;
rids.resize(va.size());
for (int i = 0; i < rids.size(); i++) {
rids.write[i] = va[i];
@@ -2445,7 +2445,7 @@ Variant::Variant(const char *const p_cstring) {
memnew_placement(_data._mem, String((const char *)p_cstring));
}
-Variant::Variant(const CharType *p_wstring) {
+Variant::Variant(const char32_t *p_wstring) {
type = STRING;
memnew_placement(_data._mem, String(p_wstring));
}
@@ -2520,9 +2520,9 @@ Variant::Variant(const NodePath &p_node_path) {
memnew_placement(_data._mem, NodePath(p_node_path));
}
-Variant::Variant(const RID &p_rid) {
- type = _RID;
- memnew_placement(_data._mem, RID(p_rid));
+Variant::Variant(const ::RID &p_rid) {
+ type = RID;
+ memnew_placement(_data._mem, ::RID(p_rid));
}
Variant::Variant(const Object *p_object) {
@@ -2580,7 +2580,7 @@ Variant::Variant(const Vector<Plane> &p_array) {
}
}
-Variant::Variant(const Vector<RID> &p_array) {
+Variant::Variant(const Vector<::RID> &p_array) {
type = ARRAY;
Array *rid_array = memnew_placement(_data._mem, Array);
@@ -2753,8 +2753,8 @@ void Variant::operator=(const Variant &p_variant) {
case COLOR: {
*reinterpret_cast<Color *>(_data._mem) = *reinterpret_cast<const Color *>(p_variant._data._mem);
} break;
- case _RID: {
- *reinterpret_cast<RID *>(_data._mem) = *reinterpret_cast<const RID *>(p_variant._data._mem);
+ case RID: {
+ *reinterpret_cast<::RID *>(_data._mem) = *reinterpret_cast<const ::RID *>(p_variant._data._mem);
} break;
case OBJECT: {
if (_get_obj().id.is_reference()) {
@@ -2955,8 +2955,8 @@ uint32_t Variant::hash() const {
return hash_djb2_one_float(reinterpret_cast<const Color *>(_data._mem)->a, hash);
} break;
- case _RID: {
- return hash_djb2_one_64(reinterpret_cast<const RID *>(_data._mem)->get_id());
+ case RID: {
+ return hash_djb2_one_64(reinterpret_cast<const ::RID *>(_data._mem)->get_id());
} break;
case OBJECT: {
return hash_djb2_one_64(make_uint64_t(_get_obj().obj));
@@ -3401,7 +3401,8 @@ Variant Variant::call(const StringName &p_method, VARIANT_ARG_DECLARE) {
Callable::CallError error;
- Variant ret = call(p_method, argptr, argc, error);
+ Variant ret;
+ call(p_method, argptr, argc, ret, error);
switch (error.error) {
case Callable::CallError::CALL_ERROR_INVALID_ARGUMENT: {
@@ -3435,6 +3436,30 @@ String Variant::get_construct_string() const {
return vars;
}
+String Variant::get_call_error_text(const StringName &p_method, const Variant **p_argptrs, int p_argcount, const Callable::CallError &ce) {
+ String err_text;
+
+ if (ce.error == Callable::CallError::CALL_ERROR_INVALID_ARGUMENT) {
+ int errorarg = ce.argument;
+ if (p_argptrs) {
+ err_text = "Cannot convert argument " + itos(errorarg + 1) + " from " + Variant::get_type_name(p_argptrs[errorarg]->get_type()) + " to " + Variant::get_type_name(Variant::Type(ce.expected)) + ".";
+ } else {
+ err_text = "Cannot convert argument " + itos(errorarg + 1) + " from [missing argptr, type unknown] to " + Variant::get_type_name(Variant::Type(ce.expected)) + ".";
+ }
+ } else if (ce.error == Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS) {
+ err_text = "Method expected " + itos(ce.argument) + " arguments, but called with " + itos(p_argcount) + ".";
+ } else if (ce.error == Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS) {
+ err_text = "Method expected " + itos(ce.argument) + " arguments, but called with " + itos(p_argcount) + ".";
+ } else if (ce.error == Callable::CallError::CALL_ERROR_INVALID_METHOD) {
+ err_text = "Method not found.";
+ } else if (ce.error == Callable::CallError::CALL_ERROR_INSTANCE_IS_NULL) {
+ err_text = "Instance is null";
+ } else if (ce.error == Callable::CallError::CALL_OK) {
+ return "Call OK";
+ }
+ return "'" + String(p_method) + "': " + err_text;
+}
+
String Variant::get_call_error_text(Object *p_base, const StringName &p_method, const Variant **p_argptrs, int p_argcount, const Callable::CallError &ce) {
String err_text;
@@ -3519,3 +3544,18 @@ String vformat(const String &p_text, const Variant &p1, const Variant &p2, const
return fmt;
}
+
+void Variant::register_types() {
+ _register_variant_operators();
+ _register_variant_methods();
+ _register_variant_setters_getters();
+ _register_variant_constructors();
+ _register_variant_utility_functions();
+}
+void Variant::unregister_types() {
+ _unregister_variant_operators();
+ _unregister_variant_methods();
+ _unregister_variant_setters_getters();
+ _unregister_variant_constructors();
+ _unregister_variant_utility_functions();
+}
diff --git a/core/variant.h b/core/variant/variant.h
index 50b7a21eda..d87078b5da 100644
--- a/core/variant.h
+++ b/core/variant/variant.h
@@ -31,13 +31,10 @@
#ifndef VARIANT_H
#define VARIANT_H
-#include "core/array.h"
-#include "core/callable.h"
-#include "core/color.h"
-#include "core/dictionary.h"
#include "core/io/ip_address.h"
#include "core/math/aabb.h"
#include "core/math/basis.h"
+#include "core/math/color.h"
#include "core/math/face3.h"
#include "core/math/plane.h"
#include "core/math/quat.h"
@@ -45,10 +42,13 @@
#include "core/math/transform_2d.h"
#include "core/math/vector3.h"
#include "core/math/vector3i.h"
-#include "core/node_path.h"
-#include "core/object_id.h"
-#include "core/rid.h"
-#include "core/ustring.h"
+#include "core/object/object_id.h"
+#include "core/string/node_path.h"
+#include "core/string/ustring.h"
+#include "core/templates/rid.h"
+#include "core/variant/array.h"
+#include "core/variant/callable.h"
+#include "core/variant/dictionary.h"
class Object;
class Node; // helper
@@ -97,7 +97,7 @@ public:
COLOR,
STRING_NAME,
NODE_PATH,
- _RID,
+ RID,
OBJECT,
CALLABLE,
SIGNAL,
@@ -120,6 +120,7 @@ public:
private:
friend struct _VariantCall;
+ friend class VariantInternal;
// Variant takes 20 bytes when real_t is float, and 36 if double
// it only allocates extra memory for aabb/matrix.
@@ -127,7 +128,7 @@ private:
struct ObjData {
ObjectID id;
- Object *obj;
+ Object *obj = nullptr;
};
/* array helpers */
@@ -206,7 +207,68 @@ private:
} _data alignas(8);
void reference(const Variant &p_variant);
- void clear();
+
+ void _clear_internal();
+
+ _FORCE_INLINE_ void clear() {
+ static const bool needs_deinit[Variant::VARIANT_MAX] = {
+ false, //NIL,
+ false, //BOOL,
+ false, //INT,
+ false, //FLOAT,
+ true, //STRING,
+ false, //VECTOR2,
+ false, //VECTOR2I,
+ false, //RECT2,
+ false, //RECT2I,
+ false, //VECTOR3,
+ false, //VECTOR3I,
+ true, //TRANSFORM2D,
+ false, //PLANE,
+ false, //QUAT,
+ true, //AABB,
+ true, //BASIS,
+ true, //TRANSFORM,
+
+ // misc types
+ false, //COLOR,
+ true, //STRING_NAME,
+ true, //NODE_PATH,
+ false, //RID,
+ true, //OBJECT,
+ true, //CALLABLE,
+ true, //SIGNAL,
+ true, //DICTIONARY,
+ true, //ARRAY,
+
+ // typed arrays
+ true, //PACKED_BYTE_ARRAY,
+ true, //PACKED_INT32_ARRAY,
+ true, //PACKED_INT64_ARRAY,
+ true, //PACKED_FLOAT32_ARRAY,
+ true, //PACKED_FLOAT64_ARRAY,
+ true, //PACKED_STRING_ARRAY,
+ true, //PACKED_VECTOR2_ARRAY,
+ true, //PACKED_VECTOR3_ARRAY,
+ true, //PACKED_COLOR_ARRAY,
+ };
+
+ if (unlikely(needs_deinit[type])) { //make it fast for types that dont need deinit
+ _clear_internal();
+ }
+ type = NIL;
+ }
+
+ static void _register_variant_operators();
+ static void _unregister_variant_operators();
+ static void _register_variant_methods();
+ static void _unregister_variant_methods();
+ static void _register_variant_setters_getters();
+ static void _unregister_variant_setters_getters();
+ static void _register_variant_constructors();
+ static void _unregister_variant_constructors();
+ static void _register_variant_utility_functions();
+ static void _unregister_variant_utility_functions();
public:
_FORCE_INLINE_ Type get_type() const {
@@ -245,7 +307,7 @@ public:
operator ObjectID() const;
- operator CharType() const;
+ operator char32_t() const;
operator float() const;
operator double() const;
operator String() const;
@@ -265,7 +327,7 @@ public:
operator Color() const;
operator NodePath() const;
- operator RID() const;
+ operator ::RID() const;
operator Object *() const;
operator Node *() const;
@@ -290,7 +352,7 @@ public:
operator Vector<Variant>() const;
operator Vector<StringName>() const;
- operator Vector<RID>() const;
+ operator Vector<::RID>() const;
operator Vector<Vector2>() const;
// some core type enums to convert to
@@ -308,7 +370,6 @@ public:
#ifdef NEED_LONG_INT
Variant(signed long p_long); // real one
Variant(unsigned long p_long);
-//Variant(long unsigned int p_long);
#endif
Variant(signed short p_short); // real one
Variant(unsigned short p_short);
@@ -322,7 +383,7 @@ public:
Variant(const String &p_string);
Variant(const StringName &p_string);
Variant(const char *const p_cstring);
- Variant(const CharType *p_wstring);
+ Variant(const char32_t *p_wstring);
Variant(const Vector2 &p_vector2);
Variant(const Vector2i &p_vector2i);
Variant(const Rect2 &p_rect2);
@@ -337,7 +398,7 @@ public:
Variant(const Transform &p_transform);
Variant(const Color &p_color);
Variant(const NodePath &p_node_path);
- Variant(const RID &p_rid);
+ Variant(const ::RID &p_rid);
Variant(const Object *p_object);
Variant(const Callable &p_callable);
Variant(const Signal &p_signal);
@@ -357,14 +418,13 @@ public:
Variant(const Vector<Variant> &p_array);
Variant(const Vector<StringName> &p_array);
- Variant(const Vector<RID> &p_array); // helper
+ Variant(const Vector<::RID> &p_array); // helper
Variant(const Vector<Vector2> &p_array); // helper
Variant(const IP_Address &p_address);
// If this changes the table in variant_op must be updated
enum Operator {
-
//comparison
OP_EQUAL,
OP_NOT_EQUAL,
@@ -380,7 +440,6 @@ public:
OP_NEGATE,
OP_POSITIVE,
OP_MODULE,
- OP_STRING_CONCAT,
//bitwise
OP_SHIFT_LEFT,
OP_SHIFT_RIGHT,
@@ -408,30 +467,131 @@ public:
return res;
}
+ static Variant::Type get_operator_return_type(Operator p_operator, Type p_type_a, Type p_type_b);
+ typedef void (*ValidatedOperatorEvaluator)(const Variant *left, const Variant *right, Variant *r_ret);
+ static ValidatedOperatorEvaluator get_validated_operator_evaluator(Operator p_operator, Type p_type_a, Type p_type_b);
+ typedef void (*PTROperatorEvaluator)(const void *left, const void *right, void *r_ret);
+ static PTROperatorEvaluator get_ptr_operator_evaluator(Operator p_operator, Type p_type_a, Type p_type_b);
+
void zero();
Variant duplicate(bool deep = false) const;
static void blend(const Variant &a, const Variant &b, float c, Variant &r_dst);
static void interpolate(const Variant &a, const Variant &b, float c, Variant &r_dst);
- void call_ptr(const StringName &p_method, const Variant **p_args, int p_argcount, Variant *r_ret, Callable::CallError &r_error);
- Variant call(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error);
+ /* Built-In Methods */
+
+ typedef void (*ValidatedBuiltInMethod)(Variant *base, const Variant **p_args, int p_argcount, Variant *r_ret);
+ typedef void (*PTRBuiltInMethod)(void *p_base, const void **p_args, void *r_ret, int p_argcount);
+
+ static bool has_builtin_method(Variant::Type p_type, const StringName &p_method);
+
+ static ValidatedBuiltInMethod get_validated_builtin_method(Variant::Type p_type, const StringName &p_method);
+ static PTRBuiltInMethod get_ptr_builtin_method(Variant::Type p_type, const StringName &p_method);
+
+ static int get_builtin_method_argument_count(Variant::Type p_type, const StringName &p_method);
+ static Variant::Type get_builtin_method_argument_type(Variant::Type p_type, const StringName &p_method, int p_argument);
+ static String get_builtin_method_argument_name(Variant::Type p_type, const StringName &p_method, int p_argument);
+ static Vector<Variant> get_builtin_method_default_arguments(Variant::Type p_type, const StringName &p_method);
+ static bool has_builtin_method_return_value(Variant::Type p_type, const StringName &p_method);
+ static Variant::Type get_builtin_method_return_type(Variant::Type p_type, const StringName &p_method);
+ static bool is_builtin_method_const(Variant::Type p_type, const StringName &p_method);
+ static bool is_builtin_method_vararg(Variant::Type p_type, const StringName &p_method);
+ static void get_builtin_method_list(Variant::Type p_type, List<StringName> *p_list);
+
+ void call(const StringName &p_method, const Variant **p_args, int p_argcount, Variant &r_ret, Callable::CallError &r_error);
Variant call(const StringName &p_method, const Variant &p_arg1 = Variant(), const Variant &p_arg2 = Variant(), const Variant &p_arg3 = Variant(), const Variant &p_arg4 = Variant(), const Variant &p_arg5 = Variant());
+ static String get_call_error_text(const StringName &p_method, const Variant **p_argptrs, int p_argcount, const Callable::CallError &ce);
static String get_call_error_text(Object *p_base, const StringName &p_method, const Variant **p_argptrs, int p_argcount, const Callable::CallError &ce);
static String get_callable_error_text(const Callable &p_callable, const Variant **p_argptrs, int p_argcount, const Callable::CallError &ce);
- static Variant construct(const Variant::Type, const Variant **p_args, int p_argcount, Callable::CallError &r_error, bool p_strict = true);
-
+ //dynamic (includes Object)
void get_method_list(List<MethodInfo> *p_list) const;
bool has_method(const StringName &p_method) const;
- static Vector<Variant::Type> get_method_argument_types(Variant::Type p_type, const StringName &p_method);
- static Vector<Variant> get_method_default_arguments(Variant::Type p_type, const StringName &p_method);
- static Variant::Type get_method_return_type(Variant::Type p_type, const StringName &p_method, bool *r_has_return = nullptr);
- static Vector<StringName> get_method_argument_names(Variant::Type p_type, const StringName &p_method);
- static bool is_method_const(Variant::Type p_type, const StringName &p_method);
- void set_named(const StringName &p_index, const Variant &p_value, bool *r_valid = nullptr);
- Variant get_named(const StringName &p_index, bool *r_valid = nullptr) const;
+ /* Constructors */
+
+ typedef void (*ValidatedConstructor)(Variant &r_base, const Variant **p_args);
+ typedef void (*PTRConstructor)(void *base, const void **p_args);
+
+ static int get_constructor_count(Variant::Type p_type);
+ static ValidatedConstructor get_validated_constructor(Variant::Type p_type, int p_constructor);
+ static PTRConstructor get_ptr_constructor(Variant::Type p_type, int p_constructor);
+ static int get_constructor_argument_count(Variant::Type p_type, int p_constructor);
+ static Variant::Type get_constructor_argument_type(Variant::Type p_type, int p_constructor, int p_argument);
+ static String get_constructor_argument_name(Variant::Type p_type, int p_constructor, int p_argument);
+ static void construct(Variant::Type, Variant &base, const Variant **p_args, int p_argcount, Callable::CallError &r_error);
+
+ static void get_constructor_list(Type p_type, List<MethodInfo> *r_list); //convenience
+
+ /* Properties */
+
+ void set_named(const StringName &p_member, const Variant &p_value, bool &r_valid);
+ Variant get_named(const StringName &p_member, bool &r_valid) const;
+
+ typedef void (*ValidatedSetter)(Variant *base, const Variant *value);
+ typedef void (*ValidatedGetter)(const Variant *base, Variant *value);
+
+ static bool has_member(Variant::Type p_type, const StringName &p_member);
+ static Variant::Type get_member_type(Variant::Type p_type, const StringName &p_member);
+ static void get_member_list(Type p_type, List<StringName> *r_members);
+
+ static ValidatedSetter get_member_validated_setter(Variant::Type p_type, const StringName &p_member);
+ static ValidatedGetter get_member_validated_getter(Variant::Type p_type, const StringName &p_member);
+
+ typedef void (*PTRSetter)(void *base, const void *value);
+ typedef void (*PTRGetter)(const void *base, void *value);
+
+ static PTRSetter get_member_ptr_setter(Variant::Type p_type, const StringName &p_member);
+ static PTRGetter get_member_ptr_getter(Variant::Type p_type, const StringName &p_member);
+
+ /* Indexing */
+
+ static bool has_indexing(Variant::Type p_type);
+ static Variant::Type get_indexed_element_type(Variant::Type p_type);
+
+ typedef void (*ValidatedIndexedSetter)(Variant *base, int64_t index, const Variant *value, bool &oob);
+ typedef void (*ValidatedIndexedGetter)(const Variant *base, int64_t index, Variant *value, bool &oob);
+
+ static ValidatedIndexedSetter get_member_validated_indexed_setter(Variant::Type p_type);
+ static ValidatedIndexedGetter get_member_validated_indexed_getter(Variant::Type p_type);
+
+ typedef void (*PTRIndexedSetter)(void *base, int64_t index, const void *value);
+ typedef void (*PTRIndexedGetter)(const void *base, int64_t index, void *value);
+
+ static PTRIndexedSetter get_member_ptr_indexed_setter(Variant::Type p_type);
+ static PTRIndexedGetter get_member_ptr_indexed_getter(Variant::Type p_type);
+
+ void set_indexed(int64_t p_index, const Variant &p_value, bool &r_valid, bool &r_oob);
+ Variant get_indexed(int64_t p_index, bool &r_valid, bool &r_oob) const;
+
+ uint64_t get_indexed_size() const;
+
+ /* Keying */
+
+ static bool is_keyed(Variant::Type p_type);
+
+ typedef void (*ValidatedKeyedSetter)(Variant *base, const Variant *key, const Variant *value, bool &valid);
+ typedef void (*ValidatedKeyedGetter)(const Variant *base, const Variant *key, Variant *value, bool &valid);
+ typedef bool (*ValidatedKeyedChecker)(const Variant *base, const Variant *key, bool &valid);
+
+ static ValidatedKeyedSetter get_member_validated_keyed_setter(Variant::Type p_type);
+ static ValidatedKeyedGetter get_member_validated_keyed_getter(Variant::Type p_type);
+ static ValidatedKeyedChecker get_member_validated_keyed_checker(Variant::Type p_type);
+
+ typedef void (*PTRKeyedSetter)(void *base, const void *key, const void *value);
+ typedef void (*PTRKeyedGetter)(const void *base, const void *key, void *value);
+ typedef bool (*PTRKeyedChecker)(const void *base, const void *key);
+
+ static PTRKeyedSetter get_member_ptr_keyed_setter(Variant::Type p_type);
+ static PTRKeyedGetter get_member_ptr_keyed_getter(Variant::Type p_type);
+ static PTRKeyedChecker get_member_ptr_keyed_checker(Variant::Type p_type);
+
+ void set_keyed(const Variant &p_key, const Variant &p_value, bool &r_valid);
+ Variant get_keyed(const Variant &p_key, bool &r_valid) const;
+ bool has_key(const Variant &p_key, bool &r_valid) const;
+
+ /* Generic */
void set(const Variant &p_index, const Variant &p_value, bool *r_valid = nullptr);
Variant get(const Variant &p_index, bool *r_valid = nullptr) const;
@@ -443,6 +603,32 @@ public:
void get_property_list(List<PropertyInfo> *p_list) const;
+ static void call_utility_function(const StringName &p_name, Variant *r_ret, const Variant **p_args, int p_argcount, Callable::CallError &r_error);
+ static bool has_utility_function(const StringName &p_name);
+
+ typedef void (*ValidatedUtilityFunction)(Variant *r_ret, const Variant **p_args, int p_argcount);
+ typedef void (*PTRUtilityFunction)(void *r_ret, const void **p_args, int p_argcount);
+
+ static ValidatedUtilityFunction get_validated_utility_function(const StringName &p_name);
+ static PTRUtilityFunction get_ptr_utility_function(const StringName &p_name);
+
+ enum UtilityFunctionType {
+ UTILITY_FUNC_TYPE_MATH,
+ UTILITY_FUNC_TYPE_RANDOM,
+ UTILITY_FUNC_TYPE_GENERAL,
+ };
+
+ static UtilityFunctionType get_utility_function_type(const StringName &p_name);
+
+ static int get_utility_function_argument_count(const StringName &p_name);
+ static Variant::Type get_utility_function_argument_type(const StringName &p_name, int p_arg);
+ static String get_utility_function_argument_name(const StringName &p_name, int p_arg);
+ static bool has_utility_function_return_value(const StringName &p_name);
+ static Variant::Type get_utility_function_return_type(const StringName &p_name);
+ static bool is_utility_function_vararg(const StringName &p_name);
+
+ static void get_utility_function_list(List<StringName> *r_functions);
+
//argsVariant call()
bool operator==(const Variant &p_variant) const;
@@ -455,7 +641,6 @@ public:
String stringify(List<const void *> &stack) const;
void static_assign(const Variant &p_variant);
- static void get_constructor_list(Variant::Type p_type, List<MethodInfo> *p_list);
static void get_constants_for_type(Variant::Type p_type, List<StringName> *p_constants);
static bool has_constant(Variant::Type p_type, const StringName &p_value);
static Variant get_constant_value(Variant::Type p_type, const StringName &p_value, bool *r_valid = nullptr);
@@ -468,12 +653,13 @@ public:
void operator=(const Variant &p_variant); // only this is enough for all the other types
+ static void register_types();
+ static void unregister_types();
+
Variant(const Variant &p_variant);
_FORCE_INLINE_ Variant() {}
_FORCE_INLINE_ ~Variant() {
- if (type != Variant::NIL) {
- clear();
- }
+ clear();
}
};
diff --git a/core/variant/variant_call.cpp b/core/variant/variant_call.cpp
new file mode 100644
index 0000000000..13514b7b9f
--- /dev/null
+++ b/core/variant/variant_call.cpp
@@ -0,0 +1,1558 @@
+/*************************************************************************/
+/* variant_call.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* 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. */
+/*************************************************************************/
+
+#include "variant.h"
+
+#include "core/core_string_names.h"
+#include "core/crypto/crypto_core.h"
+#include "core/debugger/engine_debugger.h"
+#include "core/io/compression.h"
+#include "core/object/class_db.h"
+#include "core/os/os.h"
+#include "core/templates/local_vector.h"
+#include "core/templates/oa_hash_map.h"
+
+typedef void (*VariantFunc)(Variant &r_ret, Variant &p_self, const Variant **p_args);
+typedef void (*VariantConstructFunc)(Variant &r_ret, const Variant **p_args);
+
+template <class R, class T, class... P>
+static _FORCE_INLINE_ void vc_method_call(R (T::*method)(P...), Variant *base, const Variant **p_args, int p_argcount, Variant &r_ret, const Vector<Variant> &p_defvals, Callable::CallError &r_error) {
+ call_with_variant_args_ret_dv(VariantGetInternalPtr<T>::get_ptr(base), method, p_args, p_argcount, r_ret, r_error, p_defvals);
+}
+
+template <class R, class T, class... P>
+static _FORCE_INLINE_ void vc_method_call(R (T::*method)(P...) const, Variant *base, const Variant **p_args, int p_argcount, Variant &r_ret, const Vector<Variant> &p_defvals, Callable::CallError &r_error) {
+ call_with_variant_args_retc_dv(VariantGetInternalPtr<T>::get_ptr(base), method, p_args, p_argcount, r_ret, r_error, p_defvals);
+}
+
+template <class T, class... P>
+static _FORCE_INLINE_ void vc_method_call(void (T::*method)(P...), Variant *base, const Variant **p_args, int p_argcount, Variant &r_ret, const Vector<Variant> &p_defvals, Callable::CallError &r_error) {
+ call_with_variant_args_dv(VariantGetInternalPtr<T>::get_ptr(base), method, p_args, p_argcount, r_error, p_defvals);
+}
+
+template <class T, class... P>
+static _FORCE_INLINE_ void vc_method_call(void (T::*method)(P...) const, Variant *base, const Variant **p_args, int p_argcount, Variant &r_ret, const Vector<Variant> &p_defvals, Callable::CallError &r_error) {
+ call_with_variant_argsc_dv(VariantGetInternalPtr<T>::get_ptr(base), method, p_args, p_argcount, r_error, p_defvals);
+}
+
+template <class R, class T, class... P>
+static _FORCE_INLINE_ void vc_validated_call(R (T::*method)(P...), Variant *base, const Variant **p_args, Variant *r_ret) {
+ call_with_validated_variant_args_ret(base, method, p_args, r_ret);
+}
+
+template <class R, class T, class... P>
+static _FORCE_INLINE_ void vc_validated_call(R (T::*method)(P...) const, Variant *base, const Variant **p_args, Variant *r_ret) {
+ call_with_validated_variant_args_retc(base, method, p_args, r_ret);
+}
+template <class T, class... P>
+static _FORCE_INLINE_ void vc_validated_call(void (T::*method)(P...), Variant *base, const Variant **p_args, Variant *r_ret) {
+ call_with_validated_variant_args(base, method, p_args);
+}
+
+template <class T, class... P>
+static _FORCE_INLINE_ void vc_validated_call(void (T::*method)(P...) const, Variant *base, const Variant **p_args, Variant *r_ret) {
+ call_with_validated_variant_argsc(base, method, p_args);
+}
+
+template <class R, class T, class... P>
+static _FORCE_INLINE_ void vc_ptrcall(R (T::*method)(P...), void *p_base, const void **p_args, void *r_ret) {
+ call_with_ptr_args_ret(reinterpret_cast<T *>(p_base), method, p_args, r_ret);
+}
+
+template <class R, class T, class... P>
+static _FORCE_INLINE_ void vc_ptrcall(R (T::*method)(P...) const, void *p_base, const void **p_args, void *r_ret) {
+ call_with_ptr_args_retc(reinterpret_cast<T *>(p_base), method, p_args, r_ret);
+}
+
+template <class T, class... P>
+static _FORCE_INLINE_ void vc_ptrcall(void (T::*method)(P...), void *p_base, const void **p_args, void *r_ret) {
+ call_with_ptr_args(reinterpret_cast<T *>(p_base), method, p_args);
+}
+
+template <class T, class... P>
+static _FORCE_INLINE_ void vc_ptrcall(void (T::*method)(P...) const, void *p_base, const void **p_args, void *r_ret) {
+ call_with_ptr_argsc(reinterpret_cast<T *>(p_base), method, p_args);
+}
+
+template <class R, class T, class... P>
+static _FORCE_INLINE_ void vc_change_return_type(R (T::*method)(P...), Variant *v) {
+ VariantTypeAdjust<R>::adjust(v);
+}
+
+template <class R, class T, class... P>
+static _FORCE_INLINE_ void vc_change_return_type(R (T::*method)(P...) const, Variant *v) {
+ VariantTypeAdjust<R>::adjust(v);
+}
+
+template <class T, class... P>
+static _FORCE_INLINE_ void vc_change_return_type(void (T::*method)(P...), Variant *v) {
+ VariantInternal::clear(v);
+}
+
+template <class T, class... P>
+static _FORCE_INLINE_ void vc_change_return_type(void (T::*method)(P...) const, Variant *v) {
+ VariantInternal::clear(v);
+}
+
+template <class R, class... P>
+static _FORCE_INLINE_ void vc_change_return_type(R (*method)(P...), Variant *v) {
+ VariantTypeAdjust<R>::adjust(v);
+}
+
+template <class R, class T, class... P>
+static _FORCE_INLINE_ int vc_get_argument_count(R (T::*method)(P...)) {
+ return sizeof...(P);
+}
+template <class R, class T, class... P>
+static _FORCE_INLINE_ int vc_get_argument_count(R (T::*method)(P...) const) {
+ return sizeof...(P);
+}
+
+template <class T, class... P>
+static _FORCE_INLINE_ int vc_get_argument_count(void (T::*method)(P...)) {
+ return sizeof...(P);
+}
+
+template <class T, class... P>
+static _FORCE_INLINE_ int vc_get_argument_count(void (T::*method)(P...) const) {
+ return sizeof...(P);
+}
+
+template <class R, class T, class... P>
+static _FORCE_INLINE_ int vc_get_argument_count(R (*method)(T *, P...)) {
+ return sizeof...(P);
+}
+
+template <class R, class T, class... P>
+static _FORCE_INLINE_ Variant::Type vc_get_argument_type(R (T::*method)(P...), int p_arg) {
+ return call_get_argument_type<P...>(p_arg);
+}
+template <class R, class T, class... P>
+static _FORCE_INLINE_ Variant::Type vc_get_argument_type(R (T::*method)(P...) const, int p_arg) {
+ return call_get_argument_type<P...>(p_arg);
+}
+
+template <class T, class... P>
+static _FORCE_INLINE_ Variant::Type vc_get_argument_type(void (T::*method)(P...), int p_arg) {
+ return call_get_argument_type<P...>(p_arg);
+}
+
+template <class T, class... P>
+static _FORCE_INLINE_ Variant::Type vc_get_argument_type(void (T::*method)(P...) const, int p_arg) {
+ return call_get_argument_type<P...>(p_arg);
+}
+
+template <class R, class T, class... P>
+static _FORCE_INLINE_ Variant::Type vc_get_argument_type(R (*method)(T *, P...), int p_arg) {
+ return call_get_argument_type<P...>(p_arg);
+}
+
+template <class R, class T, class... P>
+static _FORCE_INLINE_ Variant::Type vc_get_return_type(R (T::*method)(P...)) {
+ return GetTypeInfo<R>::VARIANT_TYPE;
+}
+
+template <class R, class T, class... P>
+static _FORCE_INLINE_ Variant::Type vc_get_return_type(R (T::*method)(P...) const) {
+ return GetTypeInfo<R>::VARIANT_TYPE;
+}
+
+template <class T, class... P>
+static _FORCE_INLINE_ Variant::Type vc_get_return_type(void (T::*method)(P...)) {
+ return Variant::NIL;
+}
+
+template <class T, class... P>
+static _FORCE_INLINE_ Variant::Type vc_get_return_type(void (T::*method)(P...) const) {
+ return Variant::NIL;
+}
+
+template <class R, class... P>
+static _FORCE_INLINE_ Variant::Type vc_get_return_type(R (*method)(P...)) {
+ return GetTypeInfo<R>::VARIANT_TYPE;
+}
+
+template <class R, class T, class... P>
+static _FORCE_INLINE_ bool vc_has_return_type(R (T::*method)(P...)) {
+ return true;
+}
+template <class R, class T, class... P>
+static _FORCE_INLINE_ bool vc_has_return_type(R (T::*method)(P...) const) {
+ return true;
+}
+
+template <class T, class... P>
+static _FORCE_INLINE_ bool vc_has_return_type(void (T::*method)(P...)) {
+ return false;
+}
+
+template <class T, class... P>
+static _FORCE_INLINE_ bool vc_has_return_type(void (T::*method)(P...) const) {
+ return false;
+}
+
+template <class R, class T, class... P>
+static _FORCE_INLINE_ bool vc_is_const(R (T::*method)(P...)) {
+ return false;
+}
+template <class R, class T, class... P>
+static _FORCE_INLINE_ bool vc_is_const(R (T::*method)(P...) const) {
+ return true;
+}
+
+template <class T, class... P>
+static _FORCE_INLINE_ bool vc_is_const(void (T::*method)(P...)) {
+ return false;
+}
+
+template <class T, class... P>
+static _FORCE_INLINE_ bool vc_is_const(void (T::*method)(P...) const) {
+ return true;
+}
+
+template <class R, class T, class... P>
+static _FORCE_INLINE_ Variant::Type vc_get_base_type(R (T::*method)(P...)) {
+ return GetTypeInfo<T>::VARIANT_TYPE;
+}
+template <class R, class T, class... P>
+static _FORCE_INLINE_ Variant::Type vc_get_base_type(R (T::*method)(P...) const) {
+ return GetTypeInfo<T>::VARIANT_TYPE;
+}
+
+template <class T, class... P>
+static _FORCE_INLINE_ Variant::Type vc_get_base_type(void (T::*method)(P...)) {
+ return GetTypeInfo<T>::VARIANT_TYPE;
+}
+
+template <class T, class... P>
+static _FORCE_INLINE_ Variant::Type vc_get_base_type(void (T::*method)(P...) const) {
+ return GetTypeInfo<T>::VARIANT_TYPE;
+}
+
+#define METHOD_CLASS(m_class, m_method_name, m_method_ptr) \
+ struct Method_##m_class##_##m_method_name { \
+ static void call(Variant *base, const Variant **p_args, int p_argcount, Variant &r_ret, const Vector<Variant> &p_defvals, Callable::CallError &r_error) { \
+ vc_method_call(m_method_ptr, base, p_args, p_argcount, r_ret, p_defvals, r_error); \
+ } \
+ static void validated_call(Variant *base, const Variant **p_args, int p_argcount, Variant *r_ret) { \
+ vc_change_return_type(m_method_ptr, r_ret); \
+ vc_validated_call(m_method_ptr, base, p_args, r_ret); \
+ } \
+ static void ptrcall(void *p_base, const void **p_args, void *r_ret, int p_argcount) { \
+ vc_ptrcall(m_method_ptr, p_base, p_args, r_ret); \
+ } \
+ static int get_argument_count() { \
+ return vc_get_argument_count(m_method_ptr); \
+ } \
+ static Variant::Type get_argument_type(int p_arg) { \
+ return vc_get_argument_type(m_method_ptr, p_arg); \
+ } \
+ static Variant::Type get_return_type() { \
+ return vc_get_return_type(m_method_ptr); \
+ } \
+ static bool has_return_type() { \
+ return vc_has_return_type(m_method_ptr); \
+ } \
+ static bool is_const() { \
+ return vc_is_const(m_method_ptr); \
+ } \
+ static bool is_vararg() { \
+ return false; \
+ } \
+ static Variant::Type get_base_type() { \
+ return vc_get_base_type(m_method_ptr); \
+ } \
+ static StringName get_name() { \
+ return #m_method_name; \
+ } \
+ };
+
+template <class R, class T, class... P>
+static _FORCE_INLINE_ void vc_ptrcall(R (*method)(T *, P...), void *p_base, const void **p_args, void *r_ret) {
+ call_with_ptr_args_static_retc<T, R, P...>(reinterpret_cast<T *>(p_base), method, p_args, r_ret);
+}
+
+#define FUNCTION_CLASS(m_class, m_method_name, m_method_ptr) \
+ struct Method_##m_class##_##m_method_name { \
+ static void call(Variant *base, const Variant **p_args, int p_argcount, Variant &r_ret, const Vector<Variant> &p_defvals, Callable::CallError &r_error) { \
+ call_with_variant_args_retc_static_helper_dv(VariantGetInternalPtr<m_class>::get_ptr(base), m_method_ptr, p_args, p_argcount, r_ret, p_defvals, r_error); \
+ } \
+ static void validated_call(Variant *base, const Variant **p_args, int p_argcount, Variant *r_ret) { \
+ vc_change_return_type(m_method_ptr, r_ret); \
+ call_with_validated_variant_args_static_retc(base, m_method_ptr, p_args, r_ret); \
+ } \
+ static void ptrcall(void *p_base, const void **p_args, void *r_ret, int p_argcount) { \
+ vc_ptrcall(m_method_ptr, p_base, p_args, r_ret); \
+ } \
+ static int get_argument_count() { \
+ return vc_get_argument_count(m_method_ptr); \
+ } \
+ static Variant::Type get_argument_type(int p_arg) { \
+ return vc_get_argument_type(m_method_ptr, p_arg); \
+ } \
+ static Variant::Type get_return_type() { \
+ return vc_get_return_type(m_method_ptr); \
+ } \
+ static bool has_return_type() { \
+ return true; \
+ } \
+ static bool is_const() { \
+ return true; \
+ } \
+ static bool is_vararg() { \
+ return false; \
+ } \
+ static Variant::Type get_base_type() { \
+ return GetTypeInfo<m_class>::VARIANT_TYPE; \
+ } \
+ static StringName get_name() { \
+ return #m_method_name; \
+ } \
+ };
+
+#define VARARG_CLASS(m_class, m_method_name, m_method_ptr, m_has_return, m_return_type) \
+ struct Method_##m_class##_##m_method_name { \
+ static void call(Variant *base, const Variant **p_args, int p_argcount, Variant &r_ret, const Vector<Variant> &p_defvals, Callable::CallError &r_error) { \
+ m_method_ptr(base, p_args, p_argcount, r_ret, r_error); \
+ } \
+ static void validated_call(Variant *base, const Variant **p_args, int p_argcount, Variant *r_ret) { \
+ Callable::CallError ce; \
+ m_method_ptr(base, p_args, p_argcount, *r_ret, ce); \
+ } \
+ static void ptrcall(void *p_base, const void **p_args, void *r_ret, int p_argcount) { \
+ LocalVector<Variant> vars; \
+ vars.resize(p_argcount); \
+ LocalVector<const Variant *> vars_ptrs; \
+ vars_ptrs.resize(p_argcount); \
+ for (int i = 0; i < p_argcount; i++) { \
+ vars[i] = PtrToArg<Variant>::convert(p_args[i]); \
+ vars_ptrs[i] = &vars[i]; \
+ } \
+ Variant base = PtrToArg<m_class>::convert(p_base); \
+ Variant ret; \
+ Callable::CallError ce; \
+ m_method_ptr(&base, (const Variant **)&vars_ptrs[0], p_argcount, ret, ce); \
+ if (m_has_return) { \
+ m_return_type r = ret; \
+ PtrToArg<m_return_type>::encode(ret, r_ret); \
+ } \
+ } \
+ static int get_argument_count() { \
+ return 0; \
+ } \
+ static Variant::Type get_argument_type(int p_arg) { \
+ return Variant::NIL; \
+ } \
+ static Variant::Type get_return_type() { \
+ return GetTypeInfo<m_return_type>::VARIANT_TYPE; \
+ } \
+ static bool has_return_type() { \
+ return m_has_return; \
+ } \
+ static bool is_const() { \
+ return true; \
+ } \
+ static bool is_vararg() { \
+ return true; \
+ } \
+ static Variant::Type get_base_type() { \
+ return GetTypeInfo<m_class>::VARIANT_TYPE; \
+ } \
+ static StringName get_name() { \
+ return #m_method_name; \
+ } \
+ };
+
+struct _VariantCall {
+ static String func_PackedByteArray_get_string_from_ascii(PackedByteArray *p_instance) {
+ String s;
+ if (p_instance->size() > 0) {
+ const uint8_t *r = p_instance->ptr();
+ CharString cs;
+ cs.resize(p_instance->size() + 1);
+ copymem(cs.ptrw(), r, p_instance->size());
+ cs[p_instance->size()] = 0;
+
+ s = cs.get_data();
+ }
+ return s;
+ }
+
+ static String func_PackedByteArray_get_string_from_utf8(PackedByteArray *p_instance) {
+ String s;
+ if (p_instance->size() > 0) {
+ const uint8_t *r = p_instance->ptr();
+ s.parse_utf8((const char *)r, p_instance->size());
+ }
+ return s;
+ }
+
+ static String func_PackedByteArray_get_string_from_utf16(PackedByteArray *p_instance) {
+ String s;
+ if (p_instance->size() > 0) {
+ const uint8_t *r = p_instance->ptr();
+ s.parse_utf16((const char16_t *)r, p_instance->size() / 2);
+ }
+ return s;
+ }
+
+ static String func_PackedByteArray_get_string_from_utf32(PackedByteArray *p_instance) {
+ String s;
+ if (p_instance->size() > 0) {
+ const uint8_t *r = p_instance->ptr();
+ s = String((const char32_t *)r, p_instance->size() / 4);
+ }
+ return s;
+ }
+
+ static PackedByteArray func_PackedByteArray_compress(PackedByteArray *p_instance, int p_mode) {
+ PackedByteArray compressed;
+
+ if (p_instance->size() > 0) {
+ Compression::Mode mode = (Compression::Mode)(p_mode);
+ compressed.resize(Compression::get_max_compressed_buffer_size(p_instance->size(), mode));
+ int result = Compression::compress(compressed.ptrw(), p_instance->ptr(), p_instance->size(), mode);
+
+ result = result >= 0 ? result : 0;
+ compressed.resize(result);
+ }
+
+ return compressed;
+ }
+
+ static PackedByteArray func_PackedByteArray_decompress(PackedByteArray *p_instance, int64_t p_buffer_size, int p_mode) {
+ PackedByteArray decompressed;
+ Compression::Mode mode = (Compression::Mode)(p_mode);
+
+ int64_t buffer_size = p_buffer_size;
+
+ if (buffer_size <= 0) {
+ ERR_FAIL_V_MSG(decompressed, "Decompression buffer size must be greater than zero.");
+ }
+
+ decompressed.resize(buffer_size);
+ int result = Compression::decompress(decompressed.ptrw(), buffer_size, p_instance->ptr(), p_instance->size(), mode);
+
+ result = result >= 0 ? result : 0;
+ decompressed.resize(result);
+
+ return decompressed;
+ }
+
+ static PackedByteArray func_PackedByteArray_decompress_dynamic(PackedByteArray *p_instance, int64_t p_buffer_size, int p_mode) {
+ PackedByteArray decompressed;
+ int64_t max_output_size = p_buffer_size;
+ Compression::Mode mode = (Compression::Mode)(p_mode);
+
+ int result = Compression::decompress_dynamic(&decompressed, max_output_size, p_instance->ptr(), p_instance->size(), mode);
+
+ if (result == OK) {
+ return decompressed;
+ } else {
+ decompressed.clear();
+ ERR_FAIL_V_MSG(decompressed, "Decompression failed.");
+ }
+ }
+
+ static String func_PackedByteArray_hex_encode(PackedByteArray *p_instance) {
+ if (p_instance->size() == 0) {
+ return String();
+ }
+ const uint8_t *r = p_instance->ptr();
+ String s = String::hex_encode_buffer(&r[0], p_instance->size());
+ return s;
+ }
+
+ static void func_Callable_call(Variant *v, const Variant **p_args, int p_argcount, Variant &r_ret, Callable::CallError &r_error) {
+ Callable *callable = VariantGetInternalPtr<Callable>::get_ptr(v);
+ callable->call(p_args, p_argcount, r_ret, r_error);
+ }
+
+ static void func_Callable_call_deferred(Variant *v, const Variant **p_args, int p_argcount, Variant &r_ret, Callable::CallError &r_error) {
+ Callable *callable = VariantGetInternalPtr<Callable>::get_ptr(v);
+ callable->call_deferred(p_args, p_argcount);
+ }
+
+ static void func_Callable_bind(Variant *v, const Variant **p_args, int p_argcount, Variant &r_ret, Callable::CallError &r_error) {
+ Callable *callable = VariantGetInternalPtr<Callable>::get_ptr(v);
+ r_ret = callable->bind(p_args, p_argcount);
+ }
+
+ static void func_Signal_emit(Variant *v, const Variant **p_args, int p_argcount, Variant &r_ret, Callable::CallError &r_error) {
+ Signal *signal = VariantGetInternalPtr<Signal>::get_ptr(v);
+ signal->emit(p_args, p_argcount);
+ }
+
+ struct ConstantData {
+ Map<StringName, int> value;
+#ifdef DEBUG_ENABLED
+ List<StringName> value_ordered;
+#endif
+ Map<StringName, Variant> variant_value;
+#ifdef DEBUG_ENABLED
+ List<StringName> variant_value_ordered;
+#endif
+ };
+
+ static ConstantData *constant_data;
+
+ static void add_constant(int p_type, StringName p_constant_name, int p_constant_value) {
+ constant_data[p_type].value[p_constant_name] = p_constant_value;
+#ifdef DEBUG_ENABLED
+ constant_data[p_type].value_ordered.push_back(p_constant_name);
+#endif
+ }
+
+ static void add_variant_constant(int p_type, StringName p_constant_name, const Variant &p_constant_value) {
+ constant_data[p_type].variant_value[p_constant_name] = p_constant_value;
+#ifdef DEBUG_ENABLED
+ constant_data[p_type].variant_value_ordered.push_back(p_constant_name);
+#endif
+ }
+};
+
+_VariantCall::ConstantData *_VariantCall::constant_data = nullptr;
+
+struct VariantBuiltInMethodInfo {
+ void (*call)(Variant *base, const Variant **p_args, int p_argcount, Variant &r_ret, const Vector<Variant> &p_defvals, Callable::CallError &r_error);
+ Variant::ValidatedBuiltInMethod validated_call;
+ Variant::PTRBuiltInMethod ptrcall;
+
+ Vector<Variant> default_arguments;
+ Vector<String> argument_names;
+
+ bool is_const;
+ bool has_return_type;
+ bool is_vararg;
+ Variant::Type return_type;
+ int argument_count;
+ Variant::Type (*get_argument_type)(int p_arg);
+};
+
+typedef OAHashMap<StringName, VariantBuiltInMethodInfo> BuiltinMethodMap;
+static BuiltinMethodMap *builtin_method_info;
+static List<StringName> *builtin_method_names;
+
+template <class T>
+static void register_builtin_method(const Vector<String> &p_argnames, const Vector<Variant> &p_def_args) {
+ StringName name = T::get_name();
+
+ ERR_FAIL_COND(builtin_method_info[T::get_base_type()].has(name));
+
+ VariantBuiltInMethodInfo imi;
+
+ imi.call = T::call;
+ imi.validated_call = T::validated_call;
+ if (T::is_vararg()) {
+ imi.ptrcall = nullptr;
+ } else {
+ imi.ptrcall = T::ptrcall;
+ }
+
+ imi.default_arguments = p_def_args;
+ imi.argument_names = p_argnames;
+
+ imi.is_const = T::is_const();
+ imi.is_vararg = T::is_vararg();
+ imi.has_return_type = T::has_return_type();
+ imi.return_type = T::get_return_type();
+ imi.argument_count = T::get_argument_count();
+ imi.get_argument_type = T::get_argument_type;
+#ifdef DEBUG_METHODS_ENABLED
+ ERR_FAIL_COND(!imi.is_vararg && imi.argument_count != imi.argument_names.size());
+#endif
+
+ builtin_method_info[T::get_base_type()].insert(name, imi);
+ builtin_method_names[T::get_base_type()].push_back(name);
+}
+
+void Variant::call(const StringName &p_method, const Variant **p_args, int p_argcount, Variant &r_ret, Callable::CallError &r_error) {
+ if (type == Variant::OBJECT) {
+ //call object
+ Object *obj = _get_obj().obj;
+ if (!obj) {
+ r_error.error = Callable::CallError::CALL_ERROR_INSTANCE_IS_NULL;
+ return;
+ }
+#ifdef DEBUG_ENABLED
+ if (EngineDebugger::is_active() && !_get_obj().id.is_reference() && ObjectDB::get_instance(_get_obj().id) == nullptr) {
+ r_error.error = Callable::CallError::CALL_ERROR_INSTANCE_IS_NULL;
+ return;
+ }
+
+#endif
+ r_ret = _get_obj().obj->call(p_method, p_args, p_argcount, r_error);
+
+ //else if (type==Variant::METHOD) {
+ } else {
+ r_error.error = Callable::CallError::CALL_OK;
+
+ const VariantBuiltInMethodInfo *imf = builtin_method_info[type].lookup_ptr(p_method);
+
+ if (!imf) {
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
+ return;
+ }
+
+ imf->call(this, p_args, p_argcount, r_ret, imf->default_arguments, r_error);
+ }
+}
+
+bool Variant::has_method(const StringName &p_method) const {
+ if (type == OBJECT) {
+ Object *obj = get_validated_object();
+ if (!obj) {
+ return false;
+ }
+
+ return obj->has_method(p_method);
+ }
+
+ return builtin_method_info[type].has(p_method);
+}
+
+bool Variant::has_builtin_method(Variant::Type p_type, const StringName &p_method) {
+ ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, false);
+ return builtin_method_info[p_type].has(p_method);
+}
+
+Variant::ValidatedBuiltInMethod Variant::get_validated_builtin_method(Variant::Type p_type, const StringName &p_method) {
+ ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, nullptr);
+ const VariantBuiltInMethodInfo *method = builtin_method_info[p_type].lookup_ptr(p_method);
+ ERR_FAIL_COND_V(!method, nullptr);
+ return method->validated_call;
+}
+
+Variant::PTRBuiltInMethod Variant::get_ptr_builtin_method(Variant::Type p_type, const StringName &p_method) {
+ ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, nullptr);
+ const VariantBuiltInMethodInfo *method = builtin_method_info[p_type].lookup_ptr(p_method);
+ ERR_FAIL_COND_V(!method, nullptr);
+ return method->ptrcall;
+}
+
+int Variant::get_builtin_method_argument_count(Variant::Type p_type, const StringName &p_method) {
+ ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, 0);
+ const VariantBuiltInMethodInfo *method = builtin_method_info[p_type].lookup_ptr(p_method);
+ ERR_FAIL_COND_V(!method, 0);
+ return method->argument_count;
+}
+
+Variant::Type Variant::get_builtin_method_argument_type(Variant::Type p_type, const StringName &p_method, int p_argument) {
+ ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, Variant::NIL);
+ const VariantBuiltInMethodInfo *method = builtin_method_info[p_type].lookup_ptr(p_method);
+ ERR_FAIL_COND_V(!method, Variant::NIL);
+ ERR_FAIL_INDEX_V(p_argument, method->argument_count, Variant::NIL);
+ return method->get_argument_type(p_argument);
+}
+
+String Variant::get_builtin_method_argument_name(Variant::Type p_type, const StringName &p_method, int p_argument) {
+ ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, String());
+ const VariantBuiltInMethodInfo *method = builtin_method_info[p_type].lookup_ptr(p_method);
+ ERR_FAIL_COND_V(!method, String());
+#ifdef DEBUG_METHODS_ENABLED
+ ERR_FAIL_INDEX_V(p_argument, method->argument_count, String());
+ return method->argument_names[p_argument];
+#else
+ return "arg" + itos(p_argument + 1);
+#endif
+}
+
+Vector<Variant> Variant::get_builtin_method_default_arguments(Variant::Type p_type, const StringName &p_method) {
+ ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, Vector<Variant>());
+ const VariantBuiltInMethodInfo *method = builtin_method_info[p_type].lookup_ptr(p_method);
+ ERR_FAIL_COND_V(!method, Vector<Variant>());
+ return method->default_arguments;
+}
+
+bool Variant::has_builtin_method_return_value(Variant::Type p_type, const StringName &p_method) {
+ ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, false);
+ const VariantBuiltInMethodInfo *method = builtin_method_info[p_type].lookup_ptr(p_method);
+ ERR_FAIL_COND_V(!method, false);
+ return method->has_return_type;
+}
+
+void Variant::get_builtin_method_list(Variant::Type p_type, List<StringName> *p_list) {
+ ERR_FAIL_INDEX(p_type, Variant::VARIANT_MAX);
+ for (List<StringName>::Element *E = builtin_method_names[p_type].front(); E; E = E->next()) {
+ p_list->push_back(E->get());
+ }
+}
+
+Variant::Type Variant::get_builtin_method_return_type(Variant::Type p_type, const StringName &p_method) {
+ ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, Variant::NIL);
+ const VariantBuiltInMethodInfo *method = builtin_method_info[p_type].lookup_ptr(p_method);
+ ERR_FAIL_COND_V(!method, Variant::NIL);
+ return method->return_type;
+}
+
+bool Variant::is_builtin_method_const(Variant::Type p_type, const StringName &p_method) {
+ ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, false);
+ const VariantBuiltInMethodInfo *method = builtin_method_info[p_type].lookup_ptr(p_method);
+ ERR_FAIL_COND_V(!method, false);
+ return method->is_const;
+}
+
+bool Variant::is_builtin_method_vararg(Variant::Type p_type, const StringName &p_method) {
+ ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, false);
+ const VariantBuiltInMethodInfo *method = builtin_method_info[p_type].lookup_ptr(p_method);
+ ERR_FAIL_COND_V(!method, false);
+ return method->is_vararg;
+}
+
+void Variant::get_method_list(List<MethodInfo> *p_list) const {
+ if (type == OBJECT) {
+ Object *obj = get_validated_object();
+ if (obj) {
+ obj->get_method_list(p_list);
+ }
+ } else {
+ for (List<StringName>::Element *E = builtin_method_names[type].front(); E; E = E->next()) {
+ const VariantBuiltInMethodInfo *method = builtin_method_info[type].lookup_ptr(E->get());
+ ERR_CONTINUE(!method);
+
+ MethodInfo mi;
+ mi.name = E->get();
+
+ //return type
+ if (method->has_return_type) {
+ mi.return_val.type = method->return_type;
+ if (mi.return_val.type == Variant::NIL) {
+ mi.return_val.usage |= PROPERTY_USAGE_NIL_IS_VARIANT;
+ }
+ }
+
+ if (method->is_const) {
+ mi.flags |= METHOD_FLAG_CONST;
+ }
+ if (method->is_vararg) {
+ mi.flags |= METHOD_FLAG_VARARG;
+ }
+
+ for (int i = 0; i < method->argument_count; i++) {
+ PropertyInfo pi;
+#ifdef DEBUG_METHODS_ENABLED
+ pi.name = method->argument_names[i];
+#else
+ pi.name = "arg" + itos(i + 1);
+#endif
+ pi.type = method->get_argument_type(i);
+ if (pi.type == Variant::NIL) {
+ pi.usage |= PROPERTY_USAGE_NIL_IS_VARIANT;
+ }
+ mi.arguments.push_back(pi);
+ }
+
+ mi.default_arguments = method->default_arguments;
+ p_list->push_back(mi);
+ }
+ }
+}
+
+void Variant::get_constants_for_type(Variant::Type p_type, List<StringName> *p_constants) {
+ ERR_FAIL_INDEX(p_type, Variant::VARIANT_MAX);
+
+ _VariantCall::ConstantData &cd = _VariantCall::constant_data[p_type];
+
+#ifdef DEBUG_ENABLED
+ for (List<StringName>::Element *E = cd.value_ordered.front(); E; E = E->next()) {
+ p_constants->push_back(E->get());
+#else
+ for (Map<StringName, int>::Element *E = cd.value.front(); E; E = E->next()) {
+ p_constants->push_back(E->key());
+#endif
+ }
+
+#ifdef DEBUG_ENABLED
+ for (List<StringName>::Element *E = cd.variant_value_ordered.front(); E; E = E->next()) {
+ p_constants->push_back(E->get());
+#else
+ for (Map<StringName, Variant>::Element *E = cd.variant_value.front(); E; E = E->next()) {
+ p_constants->push_back(E->key());
+#endif
+ }
+}
+
+bool Variant::has_constant(Variant::Type p_type, const StringName &p_value) {
+ ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, false);
+ _VariantCall::ConstantData &cd = _VariantCall::constant_data[p_type];
+ return cd.value.has(p_value) || cd.variant_value.has(p_value);
+}
+
+Variant Variant::get_constant_value(Variant::Type p_type, const StringName &p_value, bool *r_valid) {
+ if (r_valid) {
+ *r_valid = false;
+ }
+
+ ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, 0);
+ _VariantCall::ConstantData &cd = _VariantCall::constant_data[p_type];
+
+ Map<StringName, int>::Element *E = cd.value.find(p_value);
+ if (!E) {
+ Map<StringName, Variant>::Element *F = cd.variant_value.find(p_value);
+ if (F) {
+ if (r_valid) {
+ *r_valid = true;
+ }
+ return F->get();
+ } else {
+ return -1;
+ }
+ }
+ if (r_valid) {
+ *r_valid = true;
+ }
+
+ return E->get();
+}
+
+#ifdef DEBUG_METHODS_ENABLED
+#define bind_method(m_type, m_method, m_arg_names, m_default_args) \
+ METHOD_CLASS(m_type, m_method, &m_type::m_method); \
+ register_builtin_method<Method_##m_type##_##m_method>(m_arg_names, m_default_args);
+#else
+#define bind_method(m_type, m_method, m_arg_names, m_default_args) \
+ METHOD_CLASS(m_type, m_method, &m_type ::m_method); \
+ register_builtin_method<Method_##m_type##_##m_method>(sarray(), m_default_args);
+#endif
+
+#ifdef DEBUG_METHODS_ENABLED
+#define bind_methodv(m_type, m_name, m_method, m_arg_names, m_default_args) \
+ METHOD_CLASS(m_type, m_name, m_method); \
+ register_builtin_method<Method_##m_type##_##m_name>(m_arg_names, m_default_args);
+#else
+#define bind_methodv(m_type, m_name, m_method, m_arg_names, m_default_args) \
+ METHOD_CLASS(m_type, m_name, m_method); \
+ register_builtin_method<Method_##m_type##_##m_name>(sarray(), m_default_args);
+#endif
+
+#ifdef DEBUG_METHODS_ENABLED
+#define bind_function(m_type, m_name, m_method, m_arg_names, m_default_args) \
+ FUNCTION_CLASS(m_type, m_name, m_method); \
+ register_builtin_method<Method_##m_type##_##m_name>(m_arg_names, m_default_args);
+#else
+#define bind_function(m_type, m_name, m_method, m_arg_names, m_default_args) \
+ FUNCTION_CLASS(m_type, m_name, m_method); \
+ register_builtin_method<Method_##m_type##_##m_name>(sarray(), m_default_args);
+#endif
+
+#define bind_custom(m_type, m_name, m_method, m_has_return, m_ret_type) \
+ VARARG_CLASS(m_type, m_name, m_method, m_has_return, m_ret_type) \
+ register_builtin_method<Method_##m_type##_##m_name>(sarray(), Vector<Variant>());
+
+static void _register_variant_builtin_methods() {
+ _VariantCall::constant_data = memnew_arr(_VariantCall::ConstantData, Variant::VARIANT_MAX);
+ builtin_method_info = memnew_arr(BuiltinMethodMap, Variant::VARIANT_MAX);
+ builtin_method_names = memnew_arr(List<StringName>, Variant::VARIANT_MAX);
+
+ /* String */
+
+ bind_method(String, casecmp_to, sarray("to"), varray());
+ bind_method(String, nocasecmp_to, sarray("to"), varray());
+ bind_method(String, naturalnocasecmp_to, sarray("to"), varray());
+ bind_method(String, length, sarray(), varray());
+ bind_method(String, substr, sarray("from", "len"), varray(-1));
+ bind_methodv(String, find, static_cast<int (String::*)(const String &, int) const>(&String::find), sarray("what", "from"), varray(0));
+ bind_method(String, count, sarray("what", "from", "to"), varray(0, 0));
+ bind_method(String, countn, sarray("what", "from", "to"), varray(0, 0));
+ bind_method(String, findn, sarray("what", "from"), varray(0));
+ bind_method(String, rfind, sarray("what", "from"), varray(-1));
+ bind_method(String, rfindn, sarray("what", "from"), varray(-1));
+ bind_method(String, match, sarray("expr"), varray());
+ bind_method(String, matchn, sarray("expr"), varray());
+ bind_methodv(String, begins_with, static_cast<bool (String::*)(const String &) const>(&String::begins_with), sarray("text"), varray());
+ bind_method(String, ends_with, sarray("text"), varray());
+ bind_method(String, is_subsequence_of, sarray("text"), varray());
+ bind_method(String, is_subsequence_ofi, sarray("text"), varray());
+ bind_method(String, bigrams, sarray(), varray());
+ bind_method(String, similarity, sarray("text"), varray());
+
+ bind_method(String, format, sarray("values", "placeholder"), varray("{_}"));
+ bind_methodv(String, replace, static_cast<String (String::*)(const String &, const String &) const>(&String::replace), sarray("what", "forwhat"), varray());
+ bind_method(String, replacen, sarray("what", "forwhat"), varray());
+ bind_method(String, repeat, sarray("count"), varray());
+ bind_method(String, insert, sarray("position", "what"), varray());
+ bind_method(String, capitalize, sarray(), varray());
+ bind_method(String, split, sarray("delimiter", "allow_empty", "maxsplit"), varray(true, 0));
+ bind_method(String, rsplit, sarray("delimiter", "allow_empty", "maxsplit"), varray(true, 0));
+ bind_method(String, split_floats, sarray("delimiter", "allow_empty"), varray(true));
+ bind_method(String, join, sarray("parts"), varray());
+
+ bind_method(String, to_upper, sarray(), varray());
+ bind_method(String, to_lower, sarray(), varray());
+
+ bind_method(String, left, sarray("position"), varray());
+ bind_method(String, right, sarray("position"), varray());
+
+ bind_method(String, strip_edges, sarray("left", "right"), varray(true, true));
+ bind_method(String, strip_escapes, sarray(), varray());
+ bind_method(String, lstrip, sarray("chars"), varray());
+ bind_method(String, rstrip, sarray("chars"), varray());
+ bind_method(String, get_extension, sarray(), varray());
+ bind_method(String, get_basename, sarray(), varray());
+ bind_method(String, plus_file, sarray("file"), varray());
+ bind_method(String, ord_at, sarray("at"), varray());
+ bind_method(String, dedent, sarray(), varray());
+ // FIXME: String needs to be immutable when binding
+ //bind_method(String, erase, sarray("position", "chars"), varray());
+ bind_method(String, hash, sarray(), varray());
+ bind_method(String, md5_text, sarray(), varray());
+ bind_method(String, sha1_text, sarray(), varray());
+ bind_method(String, sha256_text, sarray(), varray());
+ bind_method(String, md5_buffer, sarray(), varray());
+ bind_method(String, sha1_buffer, sarray(), varray());
+ bind_method(String, sha256_buffer, sarray(), varray());
+ bind_method(String, empty, sarray(), varray());
+ // FIXME: Static function, not sure how to bind
+ //bind_method(String, humanize_size, sarray("size"), varray());
+
+ bind_method(String, is_abs_path, sarray(), varray());
+ bind_method(String, is_rel_path, sarray(), varray());
+ bind_method(String, get_base_dir, sarray(), varray());
+ bind_method(String, get_file, sarray(), varray());
+ bind_method(String, xml_escape, sarray("escape_quotes"), varray(false));
+ bind_method(String, xml_unescape, sarray(), varray());
+ bind_method(String, http_escape, sarray(), varray());
+ bind_method(String, http_unescape, sarray(), varray());
+ bind_method(String, c_escape, sarray(), varray());
+ bind_method(String, c_unescape, sarray(), varray());
+ bind_method(String, json_escape, sarray(), varray());
+ bind_method(String, percent_encode, sarray(), varray());
+ bind_method(String, percent_decode, sarray(), varray());
+
+ bind_method(String, is_valid_identifier, sarray(), varray());
+ bind_method(String, is_valid_integer, sarray(), varray());
+ bind_method(String, is_valid_float, sarray(), varray());
+ bind_method(String, is_valid_hex_number, sarray("with_prefix"), varray(false));
+ bind_method(String, is_valid_html_color, sarray(), varray());
+ bind_method(String, is_valid_ip_address, sarray(), varray());
+ bind_method(String, is_valid_filename, sarray(), varray());
+
+ bind_method(String, to_int, sarray(), varray());
+ bind_method(String, to_float, sarray(), varray());
+ bind_method(String, hex_to_int, sarray("with_prefix"), varray(true));
+ bind_method(String, bin_to_int, sarray("with_prefix"), varray(true));
+
+ bind_method(String, lpad, sarray("min_length", "character"), varray(" "));
+ bind_method(String, rpad, sarray("min_length", "character"), varray(" "));
+ bind_method(String, pad_decimals, sarray("digits"), varray());
+ bind_method(String, pad_zeros, sarray("digits"), varray());
+ bind_method(String, trim_prefix, sarray("prefix"), varray());
+ bind_method(String, trim_suffix, sarray("suffix"), varray());
+
+ bind_method(String, to_ascii_buffer, sarray(), varray());
+ bind_method(String, to_utf8_buffer, sarray(), varray());
+ bind_method(String, to_utf16_buffer, sarray(), varray());
+ bind_method(String, to_utf32_buffer, sarray(), varray());
+
+ /* Vector2 */
+
+ bind_method(Vector2, angle, sarray(), varray());
+ bind_method(Vector2, angle_to, sarray("to"), varray());
+ bind_method(Vector2, angle_to_point, sarray("to"), varray());
+ bind_method(Vector2, direction_to, sarray("b"), varray());
+ bind_method(Vector2, distance_to, sarray("to"), varray());
+ bind_method(Vector2, distance_squared_to, sarray("to"), varray());
+ bind_method(Vector2, length, sarray(), varray());
+ bind_method(Vector2, length_squared, sarray(), varray());
+ bind_method(Vector2, normalized, sarray(), varray());
+ bind_method(Vector2, is_normalized, sarray(), varray());
+ bind_method(Vector2, is_equal_approx, sarray("to"), varray());
+ bind_method(Vector2, posmod, sarray("mod"), varray());
+ bind_method(Vector2, posmodv, sarray("modv"), varray());
+ bind_method(Vector2, project, sarray("b"), varray());
+ bind_method(Vector2, lerp, sarray("with", "t"), varray());
+ bind_method(Vector2, slerp, sarray("with", "t"), varray());
+ bind_method(Vector2, cubic_interpolate, sarray("b", "pre_a", "post_b", "t"), varray());
+ bind_method(Vector2, move_toward, sarray("to", "delta"), varray());
+ bind_method(Vector2, rotated, sarray("phi"), varray());
+ bind_method(Vector2, tangent, sarray(), varray());
+ bind_method(Vector2, floor, sarray(), varray());
+ bind_method(Vector2, ceil, sarray(), varray());
+ bind_method(Vector2, round, sarray(), varray());
+ bind_method(Vector2, aspect, sarray(), varray());
+ bind_method(Vector2, dot, sarray("with"), varray());
+ bind_method(Vector2, slide, sarray("n"), varray());
+ bind_method(Vector2, bounce, sarray("n"), varray());
+ bind_method(Vector2, reflect, sarray("n"), varray());
+ bind_method(Vector2, cross, sarray("with"), varray());
+ bind_method(Vector2, abs, sarray(), varray());
+ bind_method(Vector2, sign, sarray(), varray());
+ bind_method(Vector2, snapped, sarray("by"), varray());
+ bind_method(Vector2, clamped, sarray("length"), varray());
+
+ /* Vector2i */
+
+ bind_method(Vector2i, aspect, sarray(), varray());
+ bind_method(Vector2i, sign, sarray(), varray());
+ bind_method(Vector2i, abs, sarray(), varray());
+
+ /* Rect2 */
+
+ bind_method(Rect2, get_area, sarray(), varray());
+ bind_method(Rect2, has_no_area, sarray(), varray());
+ bind_method(Rect2, has_point, sarray("point"), varray());
+ bind_method(Rect2, is_equal_approx, sarray("rect"), varray());
+ bind_method(Rect2, intersects, sarray("b", "include_borders"), varray(false));
+ bind_method(Rect2, encloses, sarray("b"), varray());
+ bind_method(Rect2, clip, sarray("b"), varray());
+ bind_method(Rect2, merge, sarray("b"), varray());
+ bind_method(Rect2, expand, sarray("to"), varray());
+ bind_method(Rect2, grow, sarray("by"), varray());
+ bind_methodv(Rect2, grow_margin, &Rect2::grow_margin_bind, sarray("margin", "by"), varray());
+ bind_method(Rect2, grow_individual, sarray("left", "top", "right", "bottom"), varray());
+ bind_method(Rect2, abs, sarray(), varray());
+
+ /* Rect2i */
+
+ bind_method(Rect2i, get_area, sarray(), varray());
+ bind_method(Rect2i, has_no_area, sarray(), varray());
+ bind_method(Rect2i, has_point, sarray("point"), varray());
+ bind_method(Rect2i, intersects, sarray("b"), varray());
+ bind_method(Rect2i, encloses, sarray("b"), varray());
+ bind_method(Rect2i, clip, sarray("b"), varray());
+ bind_method(Rect2i, merge, sarray("b"), varray());
+ bind_method(Rect2i, expand, sarray("to"), varray());
+ bind_method(Rect2i, grow, sarray("by"), varray());
+ bind_methodv(Rect2i, grow_margin, &Rect2i::grow_margin_bind, sarray("margin", "by"), varray());
+ bind_method(Rect2i, grow_individual, sarray("left", "top", "right", "bottom"), varray());
+ bind_method(Rect2i, abs, sarray(), varray());
+
+ /* Vector3 */
+
+ bind_method(Vector3, min_axis, sarray(), varray());
+ bind_method(Vector3, max_axis, sarray(), varray());
+ bind_method(Vector3, angle_to, sarray("to"), varray());
+ bind_method(Vector3, direction_to, sarray("b"), varray());
+ bind_method(Vector3, distance_to, sarray("b"), varray());
+ bind_method(Vector3, distance_squared_to, sarray("b"), varray());
+ bind_method(Vector3, length, sarray(), varray());
+ bind_method(Vector3, length_squared, sarray(), varray());
+ bind_method(Vector3, normalized, sarray(), varray());
+ bind_method(Vector3, is_normalized, sarray(), varray());
+ bind_method(Vector3, is_equal_approx, sarray("to"), varray());
+ bind_method(Vector3, inverse, sarray(), varray());
+ bind_method(Vector3, snapped, sarray("by"), varray());
+ bind_method(Vector3, rotated, sarray("by_axis", "phi"), varray());
+ bind_method(Vector3, lerp, sarray("b", "t"), varray());
+ bind_method(Vector3, slerp, sarray("b", "t"), varray());
+ bind_method(Vector3, cubic_interpolate, sarray("b", "pre_a", "post_b", "t"), varray());
+ bind_method(Vector3, move_toward, sarray("to", "delta"), varray());
+ bind_method(Vector3, dot, sarray("with"), varray());
+ bind_method(Vector3, cross, sarray("with"), varray());
+ bind_method(Vector3, outer, sarray("with"), varray());
+ bind_method(Vector3, to_diagonal_matrix, sarray(), varray());
+ bind_method(Vector3, abs, sarray(), varray());
+ bind_method(Vector3, floor, sarray(), varray());
+ bind_method(Vector3, ceil, sarray(), varray());
+ bind_method(Vector3, round, sarray(), varray());
+ bind_method(Vector3, posmod, sarray("mod"), varray());
+ bind_method(Vector3, posmodv, sarray("modv"), varray());
+ bind_method(Vector3, project, sarray("b"), varray());
+ bind_method(Vector3, slide, sarray("n"), varray());
+ bind_method(Vector3, bounce, sarray("n"), varray());
+ bind_method(Vector3, reflect, sarray("n"), varray());
+ bind_method(Vector3, sign, sarray(), varray());
+
+ /* Vector3i */
+
+ bind_method(Vector3i, min_axis, sarray(), varray());
+ bind_method(Vector3i, max_axis, sarray(), varray());
+ bind_method(Vector3i, sign, sarray(), varray());
+ bind_method(Vector3i, abs, sarray(), varray());
+
+ /* Plane */
+
+ bind_method(Plane, normalized, sarray(), varray());
+ bind_method(Plane, center, sarray(), varray());
+ bind_method(Plane, is_equal_approx, sarray("to_plane"), varray());
+ bind_method(Plane, is_point_over, sarray("plane"), varray());
+ bind_method(Plane, distance_to, sarray("point"), varray());
+ bind_method(Plane, has_point, sarray("point", "epsilon"), varray(CMP_EPSILON));
+ bind_method(Plane, project, sarray("point"), varray());
+ bind_methodv(Plane, intersect_3, &Plane::intersect_3_bind, sarray("b", "c"), varray());
+ bind_methodv(Plane, intersects_ray, &Plane::intersects_ray_bind, sarray("from", "dir"), varray());
+ bind_methodv(Plane, intersects_segment, &Plane::intersects_segment_bind, sarray("from", "to"), varray());
+
+ /* Quat */
+
+ bind_method(Quat, length, sarray(), varray());
+ bind_method(Quat, length_squared, sarray(), varray());
+ bind_method(Quat, normalized, sarray(), varray());
+ bind_method(Quat, is_normalized, sarray(), varray());
+ bind_method(Quat, is_equal_approx, sarray("to"), varray());
+ bind_method(Quat, inverse, sarray(), varray());
+ bind_method(Quat, dot, sarray("with"), varray());
+ bind_method(Quat, slerp, sarray("b", "t"), varray());
+ bind_method(Quat, slerpni, sarray("b", "t"), varray());
+ bind_method(Quat, cubic_slerp, sarray("b", "pre_a", "post_b", "t"), varray());
+ bind_method(Quat, get_euler, sarray(), varray());
+
+ // FIXME: Quat is atomic, this should be done via construcror
+ //ADDFUNC1(QUAT, NIL, Quat, set_euler, VECTOR3, "euler", varray());
+ //ADDFUNC2(QUAT, NIL, Quat, set_axis_angle, VECTOR3, "axis", FLOAT, "angle", varray());
+
+ /* Color */
+
+ bind_method(Color, to_argb32, sarray(), varray());
+ bind_method(Color, to_abgr32, sarray(), varray());
+ bind_method(Color, to_rgba32, sarray(), varray());
+ bind_method(Color, to_argb64, sarray(), varray());
+ bind_method(Color, to_abgr64, sarray(), varray());
+ bind_method(Color, to_rgba64, sarray(), varray());
+
+ bind_method(Color, inverted, sarray(), varray());
+ bind_method(Color, lerp, sarray("b", "t"), varray());
+ bind_method(Color, lightened, sarray("amount"), varray());
+ bind_method(Color, darkened, sarray("amount"), varray());
+ bind_method(Color, to_html, sarray("with_alpha"), varray(true));
+ bind_method(Color, blend, sarray("over"), varray());
+
+ // FIXME: Color is immutable, need to probably find a way to do this via constructor
+ //ADDFUNC4R(COLOR, COLOR, Color, from_hsv, FLOAT, "h", FLOAT, "s", FLOAT, "v", FLOAT, "a", varray(1.0));
+ bind_method(Color, is_equal_approx, sarray("to"), varray());
+
+ /* RID */
+
+ bind_method(RID, get_id, sarray(), varray());
+
+ /* NodePath */
+
+ bind_method(NodePath, is_absolute, sarray(), varray());
+ bind_method(NodePath, get_name_count, sarray(), varray());
+ bind_method(NodePath, get_name, sarray("idx"), varray());
+ bind_method(NodePath, get_subname_count, sarray(), varray());
+ bind_method(NodePath, get_subname, sarray("idx"), varray());
+ bind_method(NodePath, get_concatenated_subnames, sarray(), varray());
+ bind_method(NodePath, get_as_property_path, sarray(), varray());
+ bind_method(NodePath, is_empty, sarray(), varray());
+
+ /* Callable */
+
+ bind_method(Callable, is_null, sarray(), varray());
+ bind_method(Callable, is_custom, sarray(), varray());
+ bind_method(Callable, is_standard, sarray(), varray());
+ bind_method(Callable, get_object, sarray(), varray());
+ bind_method(Callable, get_object_id, sarray(), varray());
+ bind_method(Callable, get_method, sarray(), varray());
+ bind_method(Callable, hash, sarray(), varray());
+ bind_method(Callable, unbind, sarray("argcount"), varray());
+
+ bind_custom(Callable, call, _VariantCall::func_Callable_call, true, Variant);
+ bind_custom(Callable, call_deferred, _VariantCall::func_Callable_call_deferred, false, Variant);
+ bind_custom(Callable, bind, _VariantCall::func_Callable_bind, true, Callable);
+
+ /* Signal */
+
+ bind_method(Signal, is_null, sarray(), varray());
+ bind_method(Signal, get_object, sarray(), varray());
+ bind_method(Signal, get_object_id, sarray(), varray());
+ bind_method(Signal, get_name, sarray(), varray());
+
+ bind_method(Signal, connect, sarray("callable", "binds", "flags"), varray(Array(), 0));
+ bind_method(Signal, disconnect, sarray("callable"), varray());
+ bind_method(Signal, is_connected, sarray("callable"), varray());
+ bind_method(Signal, get_connections, sarray(), varray());
+
+ bind_custom(Signal, emit, _VariantCall::func_Signal_emit, false, Variant);
+
+ /* Transform2D */
+
+ bind_method(Transform2D, inverse, sarray(), varray());
+ bind_method(Transform2D, affine_inverse, sarray(), varray());
+ bind_method(Transform2D, get_rotation, sarray(), varray());
+ bind_method(Transform2D, get_origin, sarray(), varray());
+ bind_method(Transform2D, get_scale, sarray(), varray());
+ bind_method(Transform2D, orthonormalized, sarray(), varray());
+ bind_method(Transform2D, rotated, sarray("phi"), varray());
+ bind_method(Transform2D, scaled, sarray("scale"), varray());
+ bind_method(Transform2D, translated, sarray("offset"), varray());
+ bind_method(Transform2D, basis_xform, sarray("v"), varray());
+ bind_method(Transform2D, basis_xform_inv, sarray("v"), varray());
+ bind_method(Transform2D, interpolate_with, sarray("xform", "t"), varray());
+ bind_method(Transform2D, is_equal_approx, sarray("xform"), varray());
+
+ /* Basis */
+
+ bind_method(Basis, inverse, sarray(), varray());
+ bind_method(Basis, transposed, sarray(), varray());
+ bind_method(Basis, orthonormalized, sarray(), varray());
+ bind_method(Basis, determinant, sarray(), varray());
+ bind_methodv(Basis, rotated, static_cast<Basis (Basis::*)(const Vector3 &, float) const>(&Basis::rotated), sarray("axis", "phi"), varray());
+ bind_method(Basis, scaled, sarray("scale"), varray());
+ bind_method(Basis, get_scale, sarray(), varray());
+ bind_method(Basis, get_euler, sarray(), varray());
+ bind_method(Basis, tdotx, sarray("with"), varray());
+ bind_method(Basis, tdoty, sarray("with"), varray());
+ bind_method(Basis, tdotz, sarray("with"), varray());
+ bind_method(Basis, get_orthogonal_index, sarray(), varray());
+ bind_method(Basis, slerp, sarray("b", "t"), varray());
+ bind_method(Basis, is_equal_approx, sarray("b"), varray());
+ bind_method(Basis, get_rotation_quat, sarray(), varray());
+
+ /* AABB */
+
+ bind_method(AABB, abs, sarray(), varray());
+ bind_method(AABB, get_area, sarray(), varray());
+ bind_method(AABB, has_no_area, sarray(), varray());
+ bind_method(AABB, has_no_surface, sarray(), varray());
+ bind_method(AABB, has_point, sarray("point"), varray());
+ bind_method(AABB, is_equal_approx, sarray("aabb"), varray());
+ bind_method(AABB, intersects, sarray("with"), varray());
+ bind_method(AABB, encloses, sarray("with"), varray());
+ bind_method(AABB, intersects_plane, sarray("plane"), varray());
+ bind_method(AABB, intersection, sarray("with"), varray());
+ bind_method(AABB, merge, sarray("with"), varray());
+ bind_method(AABB, expand, sarray("to_point"), varray());
+ bind_method(AABB, grow, sarray("by"), varray());
+ bind_method(AABB, get_support, sarray("dir"), varray());
+ bind_method(AABB, get_longest_axis, sarray(), varray());
+ bind_method(AABB, get_longest_axis_index, sarray(), varray());
+ bind_method(AABB, get_longest_axis_size, sarray(), varray());
+ bind_method(AABB, get_shortest_axis, sarray(), varray());
+ bind_method(AABB, get_shortest_axis_index, sarray(), varray());
+ bind_method(AABB, get_shortest_axis_size, sarray(), varray());
+ bind_method(AABB, get_endpoint, sarray("idx"), varray());
+ bind_methodv(AABB, intersects_segment, &AABB::intersects_segment_bind, sarray("from", "to"), varray());
+ bind_methodv(AABB, intersects_ray, &AABB::intersects_ray_bind, sarray("from", "dir"), varray());
+
+ /* Transform */
+
+ bind_method(Transform, inverse, sarray(), varray());
+ bind_method(Transform, affine_inverse, sarray(), varray());
+ bind_method(Transform, orthonormalized, sarray(), varray());
+ bind_method(Transform, rotated, sarray("axis", "phi"), varray());
+ bind_method(Transform, scaled, sarray("scale"), varray());
+ bind_method(Transform, translated, sarray("offset"), varray());
+ bind_method(Transform, looking_at, sarray("target", "up"), varray());
+ bind_method(Transform, interpolate_with, sarray("xform", "weight"), varray());
+ bind_method(Transform, is_equal_approx, sarray("xform"), varray());
+
+ /* Dictionary */
+
+ bind_method(Dictionary, size, sarray(), varray());
+ bind_method(Dictionary, empty, sarray(), varray());
+ bind_method(Dictionary, clear, sarray(), varray());
+ bind_method(Dictionary, has, sarray("key"), varray());
+ bind_method(Dictionary, has_all, sarray("keys"), varray());
+ bind_method(Dictionary, erase, sarray("key"), varray());
+ bind_method(Dictionary, hash, sarray(), varray());
+ bind_method(Dictionary, keys, sarray(), varray());
+ bind_method(Dictionary, values, sarray(), varray());
+ bind_method(Dictionary, duplicate, sarray("deep"), varray(false));
+ bind_method(Dictionary, get, sarray("key", "default"), varray(Variant()));
+
+ /* Array */
+
+ bind_method(Array, size, sarray(), varray());
+ bind_method(Array, empty, sarray(), varray());
+ bind_method(Array, clear, sarray(), varray());
+ bind_method(Array, hash, sarray(), varray());
+ bind_method(Array, push_back, sarray("value"), varray());
+ bind_method(Array, push_front, sarray("value"), varray());
+ bind_method(Array, append, sarray("value"), varray());
+ bind_method(Array, append_array, sarray("array"), varray());
+ bind_method(Array, resize, sarray("size"), varray());
+ bind_method(Array, insert, sarray("position", "value"), varray());
+ bind_method(Array, remove, sarray("position"), varray());
+ bind_method(Array, erase, sarray("value"), varray());
+ bind_method(Array, front, sarray(), varray());
+ bind_method(Array, back, sarray(), varray());
+ bind_method(Array, find, sarray("what", "from"), varray(0));
+ bind_method(Array, rfind, sarray("what", "from"), varray(-1));
+ bind_method(Array, find_last, sarray("value"), varray());
+ bind_method(Array, count, sarray("value"), varray());
+ bind_method(Array, has, sarray("value"), varray());
+ bind_method(Array, pop_back, sarray(), varray());
+ bind_method(Array, pop_front, sarray(), varray());
+ bind_method(Array, sort, sarray(), varray());
+ bind_method(Array, sort_custom, sarray("obj", "func"), varray());
+ bind_method(Array, shuffle, sarray(), varray());
+ bind_method(Array, bsearch, sarray("value", "before"), varray(true));
+ bind_method(Array, bsearch_custom, sarray("value", "obj", "func", "before"), varray(true));
+ bind_method(Array, invert, sarray(), varray());
+ bind_method(Array, duplicate, sarray("deep"), varray(false));
+ bind_method(Array, slice, sarray("begin", "end", "step", "deep"), varray(1, false));
+ bind_method(Array, max, sarray(), varray());
+ bind_method(Array, min, sarray(), varray());
+
+ /* Byte Array */
+ bind_method(PackedByteArray, size, sarray(), varray());
+ bind_method(PackedByteArray, empty, sarray(), varray());
+ bind_method(PackedByteArray, set, sarray("index", "value"), varray());
+ bind_method(PackedByteArray, push_back, sarray("value"), varray());
+ bind_method(PackedByteArray, append, sarray("value"), varray());
+ bind_method(PackedByteArray, append_array, sarray("array"), varray());
+ bind_method(PackedByteArray, remove, sarray("index"), varray());
+ bind_method(PackedByteArray, insert, sarray("at_index", "value"), varray());
+ bind_method(PackedByteArray, resize, sarray("new_size"), varray());
+ bind_method(PackedByteArray, has, sarray("value"), varray());
+ bind_method(PackedByteArray, invert, sarray(), varray());
+ bind_method(PackedByteArray, subarray, sarray("from", "to"), varray());
+ bind_method(PackedByteArray, sort, sarray(), varray());
+
+ bind_function(PackedByteArray, get_string_from_ascii, _VariantCall::func_PackedByteArray_get_string_from_ascii, sarray(), varray());
+ bind_function(PackedByteArray, get_string_from_utf8, _VariantCall::func_PackedByteArray_get_string_from_utf8, sarray(), varray());
+ bind_function(PackedByteArray, get_string_from_utf16, _VariantCall::func_PackedByteArray_get_string_from_utf16, sarray(), varray());
+ bind_function(PackedByteArray, get_string_from_utf32, _VariantCall::func_PackedByteArray_get_string_from_utf32, sarray(), varray());
+ bind_function(PackedByteArray, hex_encode, _VariantCall::func_PackedByteArray_hex_encode, sarray(), varray());
+ bind_function(PackedByteArray, compress, _VariantCall::func_PackedByteArray_compress, sarray("compression_mode"), varray(0));
+ bind_function(PackedByteArray, decompress, _VariantCall::func_PackedByteArray_decompress, sarray("buffer_size", "compression_mode"), varray(0));
+ bind_function(PackedByteArray, decompress_dynamic, _VariantCall::func_PackedByteArray_decompress_dynamic, sarray("max_output_size", "compression_mode"), varray(0));
+
+ /* Int32 Array */
+
+ bind_method(PackedInt32Array, size, sarray(), varray());
+ bind_method(PackedInt32Array, empty, sarray(), varray());
+ bind_method(PackedInt32Array, set, sarray("index", "value"), varray());
+ bind_method(PackedInt32Array, push_back, sarray("value"), varray());
+ bind_method(PackedInt32Array, append, sarray("value"), varray());
+ bind_method(PackedInt32Array, append_array, sarray("array"), varray());
+ bind_method(PackedInt32Array, remove, sarray("index"), varray());
+ bind_method(PackedInt32Array, insert, sarray("at_index", "value"), varray());
+ bind_method(PackedInt32Array, resize, sarray("new_size"), varray());
+ bind_method(PackedInt32Array, has, sarray("value"), varray());
+ bind_method(PackedInt32Array, invert, sarray(), varray());
+ bind_method(PackedInt32Array, subarray, sarray("from", "to"), varray());
+ bind_method(PackedInt32Array, to_byte_array, sarray(), varray());
+ bind_method(PackedInt32Array, sort, sarray(), varray());
+
+ /* Int64 Array */
+
+ bind_method(PackedInt64Array, size, sarray(), varray());
+ bind_method(PackedInt64Array, empty, sarray(), varray());
+ bind_method(PackedInt64Array, set, sarray("index", "value"), varray());
+ bind_method(PackedInt64Array, push_back, sarray("value"), varray());
+ bind_method(PackedInt64Array, append, sarray("value"), varray());
+ bind_method(PackedInt64Array, append_array, sarray("array"), varray());
+ bind_method(PackedInt64Array, remove, sarray("index"), varray());
+ bind_method(PackedInt64Array, insert, sarray("at_index", "value"), varray());
+ bind_method(PackedInt64Array, resize, sarray("new_size"), varray());
+ bind_method(PackedInt64Array, has, sarray("value"), varray());
+ bind_method(PackedInt64Array, invert, sarray(), varray());
+ bind_method(PackedInt64Array, subarray, sarray("from", "to"), varray());
+ bind_method(PackedInt64Array, to_byte_array, sarray(), varray());
+ bind_method(PackedInt64Array, sort, sarray(), varray());
+
+ /* Float32 Array */
+
+ bind_method(PackedFloat32Array, size, sarray(), varray());
+ bind_method(PackedFloat32Array, empty, sarray(), varray());
+ bind_method(PackedFloat32Array, set, sarray("index", "value"), varray());
+ bind_method(PackedFloat32Array, push_back, sarray("value"), varray());
+ bind_method(PackedFloat32Array, append, sarray("value"), varray());
+ bind_method(PackedFloat32Array, append_array, sarray("array"), varray());
+ bind_method(PackedFloat32Array, remove, sarray("index"), varray());
+ bind_method(PackedFloat32Array, insert, sarray("at_index", "value"), varray());
+ bind_method(PackedFloat32Array, resize, sarray("new_size"), varray());
+ bind_method(PackedFloat32Array, has, sarray("value"), varray());
+ bind_method(PackedFloat32Array, invert, sarray(), varray());
+ bind_method(PackedFloat32Array, subarray, sarray("from", "to"), varray());
+ bind_method(PackedFloat32Array, to_byte_array, sarray(), varray());
+ bind_method(PackedFloat32Array, sort, sarray(), varray());
+
+ /* Float64 Array */
+
+ bind_method(PackedFloat64Array, size, sarray(), varray());
+ bind_method(PackedFloat64Array, empty, sarray(), varray());
+ bind_method(PackedFloat64Array, set, sarray("index", "value"), varray());
+ bind_method(PackedFloat64Array, push_back, sarray("value"), varray());
+ bind_method(PackedFloat64Array, append, sarray("value"), varray());
+ bind_method(PackedFloat64Array, append_array, sarray("array"), varray());
+ bind_method(PackedFloat64Array, remove, sarray("index"), varray());
+ bind_method(PackedFloat64Array, insert, sarray("at_index", "value"), varray());
+ bind_method(PackedFloat64Array, resize, sarray("new_size"), varray());
+ bind_method(PackedFloat64Array, has, sarray("value"), varray());
+ bind_method(PackedFloat64Array, invert, sarray(), varray());
+ bind_method(PackedFloat64Array, subarray, sarray("from", "to"), varray());
+ bind_method(PackedFloat64Array, to_byte_array, sarray(), varray());
+ bind_method(PackedFloat64Array, sort, sarray(), varray());
+
+ /* String Array */
+
+ bind_method(PackedStringArray, size, sarray(), varray());
+ bind_method(PackedStringArray, empty, sarray(), varray());
+ bind_method(PackedStringArray, set, sarray("index", "value"), varray());
+ bind_method(PackedStringArray, push_back, sarray("value"), varray());
+ bind_method(PackedStringArray, append, sarray("value"), varray());
+ bind_method(PackedStringArray, append_array, sarray("array"), varray());
+ bind_method(PackedStringArray, remove, sarray("index"), varray());
+ bind_method(PackedStringArray, insert, sarray("at_index", "value"), varray());
+ bind_method(PackedStringArray, resize, sarray("new_size"), varray());
+ bind_method(PackedStringArray, has, sarray("value"), varray());
+ bind_method(PackedStringArray, invert, sarray(), varray());
+ bind_method(PackedStringArray, subarray, sarray("from", "to"), varray());
+ bind_method(PackedStringArray, to_byte_array, sarray(), varray());
+ bind_method(PackedStringArray, sort, sarray(), varray());
+
+ /* Vector2 Array */
+
+ bind_method(PackedVector2Array, size, sarray(), varray());
+ bind_method(PackedVector2Array, empty, sarray(), varray());
+ bind_method(PackedVector2Array, set, sarray("index", "value"), varray());
+ bind_method(PackedVector2Array, push_back, sarray("value"), varray());
+ bind_method(PackedVector2Array, append, sarray("value"), varray());
+ bind_method(PackedVector2Array, append_array, sarray("array"), varray());
+ bind_method(PackedVector2Array, remove, sarray("index"), varray());
+ bind_method(PackedVector2Array, insert, sarray("at_index", "value"), varray());
+ bind_method(PackedVector2Array, resize, sarray("new_size"), varray());
+ bind_method(PackedVector2Array, has, sarray("value"), varray());
+ bind_method(PackedVector2Array, invert, sarray(), varray());
+ bind_method(PackedVector2Array, subarray, sarray("from", "to"), varray());
+ bind_method(PackedVector2Array, to_byte_array, sarray(), varray());
+ bind_method(PackedVector2Array, sort, sarray(), varray());
+
+ /* Vector3 Array */
+
+ bind_method(PackedVector3Array, size, sarray(), varray());
+ bind_method(PackedVector3Array, empty, sarray(), varray());
+ bind_method(PackedVector3Array, set, sarray("index", "value"), varray());
+ bind_method(PackedVector3Array, push_back, sarray("value"), varray());
+ bind_method(PackedVector3Array, append, sarray("value"), varray());
+ bind_method(PackedVector3Array, append_array, sarray("array"), varray());
+ bind_method(PackedVector3Array, remove, sarray("index"), varray());
+ bind_method(PackedVector3Array, insert, sarray("at_index", "value"), varray());
+ bind_method(PackedVector3Array, resize, sarray("new_size"), varray());
+ bind_method(PackedVector3Array, has, sarray("value"), varray());
+ bind_method(PackedVector3Array, invert, sarray(), varray());
+ bind_method(PackedVector3Array, subarray, sarray("from", "to"), varray());
+ bind_method(PackedVector3Array, to_byte_array, sarray(), varray());
+ bind_method(PackedVector3Array, sort, sarray(), varray());
+
+ /* Color Array */
+
+ bind_method(PackedColorArray, size, sarray(), varray());
+ bind_method(PackedColorArray, empty, sarray(), varray());
+ bind_method(PackedColorArray, set, sarray("index", "value"), varray());
+ bind_method(PackedColorArray, push_back, sarray("value"), varray());
+ bind_method(PackedColorArray, append, sarray("value"), varray());
+ bind_method(PackedColorArray, append_array, sarray("array"), varray());
+ bind_method(PackedColorArray, remove, sarray("index"), varray());
+ bind_method(PackedColorArray, insert, sarray("at_index", "value"), varray());
+ bind_method(PackedColorArray, resize, sarray("new_size"), varray());
+ bind_method(PackedColorArray, has, sarray("value"), varray());
+ bind_method(PackedColorArray, invert, sarray(), varray());
+ bind_method(PackedColorArray, subarray, sarray("from", "to"), varray());
+ bind_method(PackedColorArray, to_byte_array, sarray(), varray());
+ bind_method(PackedColorArray, sort, sarray(), varray());
+
+ /* Register constants */
+
+ int ncc = Color::get_named_color_count();
+ for (int i = 0; i < ncc; i++) {
+ _VariantCall::add_variant_constant(Variant::COLOR, Color::get_named_color_name(i), Color::get_named_color(i));
+ }
+
+ _VariantCall::add_constant(Variant::VECTOR3, "AXIS_X", Vector3::AXIS_X);
+ _VariantCall::add_constant(Variant::VECTOR3, "AXIS_Y", Vector3::AXIS_Y);
+ _VariantCall::add_constant(Variant::VECTOR3, "AXIS_Z", Vector3::AXIS_Z);
+
+ _VariantCall::add_variant_constant(Variant::VECTOR3, "ZERO", Vector3(0, 0, 0));
+ _VariantCall::add_variant_constant(Variant::VECTOR3, "ONE", Vector3(1, 1, 1));
+ _VariantCall::add_variant_constant(Variant::VECTOR3, "INF", Vector3(Math_INF, Math_INF, Math_INF));
+ _VariantCall::add_variant_constant(Variant::VECTOR3, "LEFT", Vector3(-1, 0, 0));
+ _VariantCall::add_variant_constant(Variant::VECTOR3, "RIGHT", Vector3(1, 0, 0));
+ _VariantCall::add_variant_constant(Variant::VECTOR3, "UP", Vector3(0, 1, 0));
+ _VariantCall::add_variant_constant(Variant::VECTOR3, "DOWN", Vector3(0, -1, 0));
+ _VariantCall::add_variant_constant(Variant::VECTOR3, "FORWARD", Vector3(0, 0, -1));
+ _VariantCall::add_variant_constant(Variant::VECTOR3, "BACK", Vector3(0, 0, 1));
+
+ _VariantCall::add_constant(Variant::VECTOR3I, "AXIS_X", Vector3i::AXIS_X);
+ _VariantCall::add_constant(Variant::VECTOR3I, "AXIS_Y", Vector3i::AXIS_Y);
+ _VariantCall::add_constant(Variant::VECTOR3I, "AXIS_Z", Vector3i::AXIS_Z);
+
+ _VariantCall::add_variant_constant(Variant::VECTOR3I, "ZERO", Vector3i(0, 0, 0));
+ _VariantCall::add_variant_constant(Variant::VECTOR3I, "ONE", Vector3i(1, 1, 1));
+ _VariantCall::add_variant_constant(Variant::VECTOR3I, "LEFT", Vector3i(-1, 0, 0));
+ _VariantCall::add_variant_constant(Variant::VECTOR3I, "RIGHT", Vector3i(1, 0, 0));
+ _VariantCall::add_variant_constant(Variant::VECTOR3I, "UP", Vector3i(0, 1, 0));
+ _VariantCall::add_variant_constant(Variant::VECTOR3I, "DOWN", Vector3i(0, -1, 0));
+ _VariantCall::add_variant_constant(Variant::VECTOR3I, "FORWARD", Vector3i(0, 0, -1));
+ _VariantCall::add_variant_constant(Variant::VECTOR3I, "BACK", Vector3i(0, 0, 1));
+
+ _VariantCall::add_constant(Variant::VECTOR2, "AXIS_X", Vector2::AXIS_X);
+ _VariantCall::add_constant(Variant::VECTOR2, "AXIS_Y", Vector2::AXIS_Y);
+
+ _VariantCall::add_constant(Variant::VECTOR2I, "AXIS_X", Vector2i::AXIS_X);
+ _VariantCall::add_constant(Variant::VECTOR2I, "AXIS_Y", Vector2i::AXIS_Y);
+
+ _VariantCall::add_variant_constant(Variant::VECTOR2, "ZERO", Vector2(0, 0));
+ _VariantCall::add_variant_constant(Variant::VECTOR2, "ONE", Vector2(1, 1));
+ _VariantCall::add_variant_constant(Variant::VECTOR2, "INF", Vector2(Math_INF, Math_INF));
+ _VariantCall::add_variant_constant(Variant::VECTOR2, "LEFT", Vector2(-1, 0));
+ _VariantCall::add_variant_constant(Variant::VECTOR2, "RIGHT", Vector2(1, 0));
+ _VariantCall::add_variant_constant(Variant::VECTOR2, "UP", Vector2(0, -1));
+ _VariantCall::add_variant_constant(Variant::VECTOR2, "DOWN", Vector2(0, 1));
+
+ _VariantCall::add_variant_constant(Variant::VECTOR2I, "ZERO", Vector2i(0, 0));
+ _VariantCall::add_variant_constant(Variant::VECTOR2I, "ONE", Vector2i(1, 1));
+ _VariantCall::add_variant_constant(Variant::VECTOR2I, "LEFT", Vector2i(-1, 0));
+ _VariantCall::add_variant_constant(Variant::VECTOR2I, "RIGHT", Vector2i(1, 0));
+ _VariantCall::add_variant_constant(Variant::VECTOR2I, "UP", Vector2i(0, -1));
+ _VariantCall::add_variant_constant(Variant::VECTOR2I, "DOWN", Vector2i(0, 1));
+
+ _VariantCall::add_variant_constant(Variant::TRANSFORM2D, "IDENTITY", Transform2D());
+ _VariantCall::add_variant_constant(Variant::TRANSFORM2D, "FLIP_X", Transform2D(-1, 0, 0, 1, 0, 0));
+ _VariantCall::add_variant_constant(Variant::TRANSFORM2D, "FLIP_Y", Transform2D(1, 0, 0, -1, 0, 0));
+
+ Transform identity_transform = Transform();
+ Transform flip_x_transform = Transform(-1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0);
+ Transform flip_y_transform = Transform(1, 0, 0, 0, -1, 0, 0, 0, 1, 0, 0, 0);
+ Transform flip_z_transform = Transform(1, 0, 0, 0, 1, 0, 0, 0, -1, 0, 0, 0);
+ _VariantCall::add_variant_constant(Variant::TRANSFORM, "IDENTITY", identity_transform);
+ _VariantCall::add_variant_constant(Variant::TRANSFORM, "FLIP_X", flip_x_transform);
+ _VariantCall::add_variant_constant(Variant::TRANSFORM, "FLIP_Y", flip_y_transform);
+ _VariantCall::add_variant_constant(Variant::TRANSFORM, "FLIP_Z", flip_z_transform);
+
+ Basis identity_basis = Basis();
+ Basis flip_x_basis = Basis(-1, 0, 0, 0, 1, 0, 0, 0, 1);
+ Basis flip_y_basis = Basis(1, 0, 0, 0, -1, 0, 0, 0, 1);
+ Basis flip_z_basis = Basis(1, 0, 0, 0, 1, 0, 0, 0, -1);
+ _VariantCall::add_variant_constant(Variant::BASIS, "IDENTITY", identity_basis);
+ _VariantCall::add_variant_constant(Variant::BASIS, "FLIP_X", flip_x_basis);
+ _VariantCall::add_variant_constant(Variant::BASIS, "FLIP_Y", flip_y_basis);
+ _VariantCall::add_variant_constant(Variant::BASIS, "FLIP_Z", flip_z_basis);
+
+ _VariantCall::add_variant_constant(Variant::PLANE, "PLANE_YZ", Plane(Vector3(1, 0, 0), 0));
+ _VariantCall::add_variant_constant(Variant::PLANE, "PLANE_XZ", Plane(Vector3(0, 1, 0), 0));
+ _VariantCall::add_variant_constant(Variant::PLANE, "PLANE_XY", Plane(Vector3(0, 0, 1), 0));
+
+ _VariantCall::add_variant_constant(Variant::QUAT, "IDENTITY", Quat(0, 0, 0, 1));
+}
+
+void Variant::_register_variant_methods() {
+ _register_variant_builtin_methods(); //needs to be out due to namespace
+}
+
+void Variant::_unregister_variant_methods() {
+ //clear methods
+ memdelete_arr(builtin_method_names);
+ memdelete_arr(builtin_method_info);
+ memdelete_arr(_VariantCall::constant_data);
+}
diff --git a/core/variant/variant_construct.cpp b/core/variant/variant_construct.cpp
new file mode 100644
index 0000000000..01f5b7df59
--- /dev/null
+++ b/core/variant/variant_construct.cpp
@@ -0,0 +1,812 @@
+/*************************************************************************/
+/* variant_construct.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* 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. */
+/*************************************************************************/
+
+#include "variant.h"
+
+#include "core/core_string_names.h"
+#include "core/crypto/crypto_core.h"
+#include "core/debugger/engine_debugger.h"
+#include "core/io/compression.h"
+#include "core/object/class_db.h"
+#include "core/os/os.h"
+#include "core/templates/local_vector.h"
+#include "core/templates/oa_hash_map.h"
+
+template <class T, class... P>
+class VariantConstructor {
+ template <size_t... Is>
+ static _FORCE_INLINE_ void construct_helper(T &base, const Variant **p_args, Callable::CallError &r_error, IndexSequence<Is...>) {
+ r_error.error = Callable::CallError::CALL_OK;
+
+#ifdef DEBUG_METHODS_ENABLED
+ base = T(VariantCasterAndValidate<P>::cast(p_args, Is, r_error)...);
+#else
+ base = T(VariantCaster<P>::cast(*p_args[Is])...);
+#endif
+ }
+
+ template <size_t... Is>
+ static _FORCE_INLINE_ void validated_construct_helper(T &base, const Variant **p_args, IndexSequence<Is...>) {
+ base = T((*VariantGetInternalPtr<P>::get_ptr(p_args[Is]))...);
+ }
+
+ template <size_t... Is>
+ static _FORCE_INLINE_ void ptr_construct_helper(void *base, const void **p_args, IndexSequence<Is...>) {
+ PtrToArg<T>::encode(T(PtrToArg<P>::convert(p_args[Is])...), base);
+ }
+
+public:
+ static void construct(Variant &r_ret, const Variant **p_args, Callable::CallError &r_error) {
+ r_error.error = Callable::CallError::CALL_OK;
+ VariantTypeChanger<T>::change(&r_ret);
+ construct_helper(*VariantGetInternalPtr<T>::get_ptr(&r_ret), p_args, r_error, BuildIndexSequence<sizeof...(P)>{});
+ }
+
+ static void validated_construct(Variant &r_ret, const Variant **p_args) {
+ VariantTypeChanger<T>::change(&r_ret);
+ validated_construct_helper(*VariantGetInternalPtr<T>::get_ptr(&r_ret), p_args, BuildIndexSequence<sizeof...(P)>{});
+ }
+ static void ptr_construct(void *base, const void **p_args) {
+ ptr_construct_helper(base, p_args, BuildIndexSequence<sizeof...(P)>{});
+ }
+
+ static int get_argument_count() {
+ return sizeof...(P);
+ }
+
+ static Variant::Type get_argument_type(int p_arg) {
+ return call_get_argument_type<P...>(p_arg);
+ }
+
+ static Variant::Type get_base_type() {
+ return GetTypeInfo<T>::VARIANT_TYPE;
+ }
+};
+
+class VariantConstructorObject {
+public:
+ static void construct(Variant &r_ret, const Variant **p_args, Callable::CallError &r_error) {
+ VariantInternal::clear(&r_ret);
+ if (p_args[0]->get_type() == Variant::NIL) {
+ VariantInternal::object_assign_null(&r_ret);
+ r_error.error = Callable::CallError::CALL_OK;
+ } else if (p_args[0]->get_type() == Variant::OBJECT) {
+ VariantInternal::object_assign(&r_ret, p_args[0]);
+ r_error.error = Callable::CallError::CALL_OK;
+ } else {
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument = 0;
+ r_error.expected = Variant::OBJECT;
+ }
+ }
+
+ static void validated_construct(Variant &r_ret, const Variant **p_args) {
+ VariantInternal::clear(&r_ret);
+ VariantInternal::object_assign(&r_ret, p_args[0]);
+ }
+ static void ptr_construct(void *base, const void **p_args) {
+ PtrToArg<Object *>::encode(PtrToArg<Object *>::convert(p_args[0]), base);
+ }
+
+ static int get_argument_count() {
+ return 1;
+ }
+
+ static Variant::Type get_argument_type(int p_arg) {
+ return Variant::OBJECT;
+ }
+
+ static Variant::Type get_base_type() {
+ return Variant::OBJECT;
+ }
+};
+
+class VariantConstructorNilObject {
+public:
+ static void construct(Variant &r_ret, const Variant **p_args, Callable::CallError &r_error) {
+ if (p_args[0]->get_type() != Variant::NIL) {
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument = 0;
+ r_error.expected = Variant::NIL;
+ }
+
+ VariantInternal::clear(&r_ret);
+ VariantInternal::object_assign_null(&r_ret);
+ }
+
+ static void validated_construct(Variant &r_ret, const Variant **p_args) {
+ VariantInternal::clear(&r_ret);
+ VariantInternal::object_assign_null(&r_ret);
+ }
+ static void ptr_construct(void *base, const void **p_args) {
+ PtrToArg<Object *>::encode(nullptr, base);
+ }
+
+ static int get_argument_count() {
+ return 1;
+ }
+
+ static Variant::Type get_argument_type(int p_arg) {
+ return Variant::NIL;
+ }
+
+ static Variant::Type get_base_type() {
+ return Variant::OBJECT;
+ }
+};
+
+class VariantConstructorCallableArgs {
+public:
+ static void construct(Variant &r_ret, const Variant **p_args, Callable::CallError &r_error) {
+ ObjectID object_id;
+ StringName method;
+
+ if (p_args[0]->get_type() == Variant::NIL) {
+ // leave as is
+ } else if (p_args[0]->get_type() == Variant::OBJECT) {
+ object_id = VariantInternal::get_object_id(p_args[0]);
+ } else {
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument = 0;
+ r_error.expected = Variant::OBJECT;
+ return;
+ }
+
+ if (p_args[1]->get_type() == Variant::STRING_NAME) {
+ method = *VariantGetInternalPtr<StringName>::get_ptr(p_args[1]);
+ } else if (p_args[1]->get_type() == Variant::STRING) {
+ method = *VariantGetInternalPtr<String>::get_ptr(p_args[1]);
+ } else {
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument = 1;
+ r_error.expected = Variant::STRING_NAME;
+ return;
+ }
+
+ VariantTypeChanger<Callable>::change(&r_ret);
+ *VariantGetInternalPtr<Callable>::get_ptr(&r_ret) = Callable(object_id, method);
+ }
+
+ static void validated_construct(Variant &r_ret, const Variant **p_args) {
+ VariantTypeChanger<Callable>::change(&r_ret);
+ *VariantGetInternalPtr<Callable>::get_ptr(&r_ret) = Callable(VariantInternal::get_object_id(p_args[0]), *VariantGetInternalPtr<StringName>::get_ptr(p_args[1]));
+ }
+ static void ptr_construct(void *base, const void **p_args) {
+ PtrToArg<Callable>::encode(Callable(PtrToArg<Object *>::convert(p_args[0]), PtrToArg<StringName>::convert(p_args[1])), base);
+ }
+
+ static int get_argument_count() {
+ return 2;
+ }
+
+ static Variant::Type get_argument_type(int p_arg) {
+ if (p_arg == 0) {
+ return Variant::OBJECT;
+ } else {
+ return Variant::STRING_NAME;
+ }
+ }
+
+ static Variant::Type get_base_type() {
+ return Variant::CALLABLE;
+ }
+};
+
+class VariantConstructorSignalArgs {
+public:
+ static void construct(Variant &r_ret, const Variant **p_args, Callable::CallError &r_error) {
+ ObjectID object_id;
+ StringName method;
+
+ if (p_args[0]->get_type() == Variant::NIL) {
+ // leave as is
+ } else if (p_args[0]->get_type() == Variant::OBJECT) {
+ object_id = VariantInternal::get_object_id(p_args[0]);
+ } else {
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument = 0;
+ r_error.expected = Variant::OBJECT;
+ return;
+ }
+
+ if (p_args[1]->get_type() == Variant::STRING_NAME) {
+ method = *VariantGetInternalPtr<StringName>::get_ptr(p_args[1]);
+ } else if (p_args[1]->get_type() == Variant::STRING) {
+ method = *VariantGetInternalPtr<String>::get_ptr(p_args[1]);
+ } else {
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument = 1;
+ r_error.expected = Variant::STRING_NAME;
+ return;
+ }
+
+ VariantTypeChanger<Signal>::change(&r_ret);
+ *VariantGetInternalPtr<Signal>::get_ptr(&r_ret) = Signal(object_id, method);
+ }
+
+ static void validated_construct(Variant &r_ret, const Variant **p_args) {
+ VariantTypeChanger<Signal>::change(&r_ret);
+ *VariantGetInternalPtr<Signal>::get_ptr(&r_ret) = Signal(VariantInternal::get_object_id(p_args[0]), *VariantGetInternalPtr<StringName>::get_ptr(p_args[1]));
+ }
+ static void ptr_construct(void *base, const void **p_args) {
+ PtrToArg<Signal>::encode(Signal(PtrToArg<Object *>::convert(p_args[0]), PtrToArg<StringName>::convert(p_args[1])), base);
+ }
+
+ static int get_argument_count() {
+ return 2;
+ }
+
+ static Variant::Type get_argument_type(int p_arg) {
+ if (p_arg == 0) {
+ return Variant::OBJECT;
+ } else {
+ return Variant::STRING_NAME;
+ }
+ }
+
+ static Variant::Type get_base_type() {
+ return Variant::SIGNAL;
+ }
+};
+
+template <class T>
+class VariantConstructorToArray {
+public:
+ static void construct(Variant &r_ret, const Variant **p_args, Callable::CallError &r_error) {
+ if (p_args[0]->get_type() != GetTypeInfo<T>::VARIANT_TYPE) {
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument = 0;
+ r_error.expected = GetTypeInfo<T>::VARIANT_TYPE;
+ return;
+ }
+
+ VariantTypeChanger<Array>::change(&r_ret);
+ Array &dst_arr = *VariantGetInternalPtr<Array>::get_ptr(&r_ret);
+ const T &src_arr = *VariantGetInternalPtr<T>::get_ptr(p_args[0]);
+
+ int size = src_arr.size();
+ dst_arr.resize(size);
+ for (int i = 0; i < size; i++) {
+ dst_arr[i] = src_arr[i];
+ }
+ }
+
+ static void validated_construct(Variant &r_ret, const Variant **p_args) {
+ VariantTypeChanger<Array>::change(&r_ret);
+ Array &dst_arr = *VariantGetInternalPtr<Array>::get_ptr(&r_ret);
+ const T &src_arr = *VariantGetInternalPtr<T>::get_ptr(p_args[0]);
+
+ int size = src_arr.size();
+ dst_arr.resize(size);
+ for (int i = 0; i < size; i++) {
+ dst_arr[i] = src_arr[i];
+ }
+ }
+ static void ptr_construct(void *base, const void **p_args) {
+ Array dst_arr;
+ T src_arr = PtrToArg<T>::convert(p_args[0]);
+
+ int size = src_arr.size();
+ dst_arr.resize(size);
+ for (int i = 0; i < size; i++) {
+ dst_arr[i] = src_arr[i];
+ }
+
+ PtrToArg<Array>::encode(dst_arr, base);
+ }
+
+ static int get_argument_count() {
+ return 1;
+ }
+
+ static Variant::Type get_argument_type(int p_arg) {
+ return GetTypeInfo<T>::VARIANT_TYPE;
+ }
+
+ static Variant::Type get_base_type() {
+ return Variant::ARRAY;
+ }
+};
+
+template <class T>
+class VariantConstructorFromArray {
+public:
+ static void construct(Variant &r_ret, const Variant **p_args, Callable::CallError &r_error) {
+ if (p_args[0]->get_type() != Variant::ARRAY) {
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument = 0;
+ r_error.expected = Variant::ARRAY;
+ return;
+ }
+
+ VariantTypeChanger<T>::change(&r_ret);
+ const Array &src_arr = *VariantGetInternalPtr<Array>::get_ptr(p_args[0]);
+ T &dst_arr = *VariantGetInternalPtr<T>::get_ptr(&r_ret);
+
+ int size = src_arr.size();
+ dst_arr.resize(size);
+ for (int i = 0; i < size; i++) {
+ dst_arr.write[i] = src_arr[i];
+ }
+ }
+
+ static void validated_construct(Variant &r_ret, const Variant **p_args) {
+ VariantTypeChanger<T>::change(&r_ret);
+ const Array &src_arr = *VariantGetInternalPtr<Array>::get_ptr(p_args[0]);
+ T &dst_arr = *VariantGetInternalPtr<T>::get_ptr(&r_ret);
+
+ int size = src_arr.size();
+ dst_arr.resize(size);
+ for (int i = 0; i < size; i++) {
+ dst_arr.write[i] = src_arr[i];
+ }
+ }
+ static void ptr_construct(void *base, const void **p_args) {
+ Array src_arr = PtrToArg<Array>::convert(p_args[0]);
+ T dst_arr;
+
+ int size = src_arr.size();
+ dst_arr.resize(size);
+ for (int i = 0; i < size; i++) {
+ dst_arr.write[i] = src_arr[i];
+ }
+
+ PtrToArg<T>::encode(dst_arr, base);
+ }
+
+ static int get_argument_count() {
+ return 1;
+ }
+
+ static Variant::Type get_argument_type(int p_arg) {
+ return Variant::ARRAY;
+ }
+
+ static Variant::Type get_base_type() {
+ return GetTypeInfo<T>::VARIANT_TYPE;
+ }
+};
+
+class VariantConstructorNil {
+public:
+ static void construct(Variant &r_ret, const Variant **p_args, Callable::CallError &r_error) {
+ if (p_args[0]->get_type() != Variant::NIL) {
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument = 0;
+ r_error.expected = Variant::NIL;
+ return;
+ }
+
+ r_error.error = Callable::CallError::CALL_OK;
+ VariantInternal::clear(&r_ret);
+ }
+
+ static void validated_construct(Variant &r_ret, const Variant **p_args) {
+ VariantInternal::clear(&r_ret);
+ }
+ static void ptr_construct(void *base, const void **p_args) {
+ PtrToArg<Variant>::encode(Variant(), base);
+ }
+
+ static int get_argument_count() {
+ return 1;
+ }
+
+ static Variant::Type get_argument_type(int p_arg) {
+ return Variant::NIL;
+ }
+
+ static Variant::Type get_base_type() {
+ return Variant::NIL;
+ }
+};
+
+template <class T>
+class VariantConstructNoArgs {
+public:
+ static void construct(Variant &r_ret, const Variant **p_args, Callable::CallError &r_error) {
+ VariantTypeChanger<T>::change_and_reset(&r_ret);
+ r_error.error = Callable::CallError::CALL_OK;
+ }
+
+ static void validated_construct(Variant &r_ret, const Variant **p_args) {
+ VariantTypeChanger<T>::change_and_reset(&r_ret);
+ }
+ static void ptr_construct(void *base, const void **p_args) {
+ PtrToArg<T>::encode(T(), base);
+ }
+
+ static int get_argument_count() {
+ return 0;
+ }
+
+ static Variant::Type get_argument_type(int p_arg) {
+ return Variant::NIL;
+ }
+
+ static Variant::Type get_base_type() {
+ return GetTypeInfo<T>::VARIANT_TYPE;
+ }
+};
+
+class VariantConstructNoArgsNil {
+public:
+ static void construct(Variant &r_ret, const Variant **p_args, Callable::CallError &r_error) {
+ VariantInternal::clear(&r_ret);
+ r_error.error = Callable::CallError::CALL_OK;
+ }
+
+ static void validated_construct(Variant &r_ret, const Variant **p_args) {
+ VariantInternal::clear(&r_ret);
+ }
+ static void ptr_construct(void *base, const void **p_args) {
+ ERR_FAIL_MSG("can't ptrcall nil constructor");
+ }
+
+ static int get_argument_count() {
+ return 0;
+ }
+
+ static Variant::Type get_argument_type(int p_arg) {
+ return Variant::NIL;
+ }
+
+ static Variant::Type get_base_type() {
+ return Variant::NIL;
+ }
+};
+
+class VariantConstructNoArgsObject {
+public:
+ static void construct(Variant &r_ret, const Variant **p_args, Callable::CallError &r_error) {
+ VariantInternal::clear(&r_ret);
+ VariantInternal::object_assign_null(&r_ret);
+ r_error.error = Callable::CallError::CALL_OK;
+ }
+
+ static void validated_construct(Variant &r_ret, const Variant **p_args) {
+ VariantInternal::clear(&r_ret);
+ VariantInternal::object_assign_null(&r_ret);
+ }
+ static void ptr_construct(void *base, const void **p_args) {
+ PtrToArg<Object *>::encode(nullptr, base);
+ }
+
+ static int get_argument_count() {
+ return 0;
+ }
+
+ static Variant::Type get_argument_type(int p_arg) {
+ return Variant::NIL;
+ }
+
+ static Variant::Type get_base_type() {
+ return Variant::OBJECT;
+ }
+};
+
+struct VariantConstructData {
+ void (*construct)(Variant &r_base, const Variant **p_args, Callable::CallError &r_error);
+ Variant::ValidatedConstructor validated_construct;
+ Variant::PTRConstructor ptr_construct;
+ Variant::Type (*get_argument_type)(int);
+ int argument_count;
+ Vector<String> arg_names;
+};
+
+static LocalVector<VariantConstructData> construct_data[Variant::VARIANT_MAX];
+
+template <class T>
+static void add_constructor(const Vector<String> &arg_names) {
+ ERR_FAIL_COND_MSG(arg_names.size() != T::get_argument_count(), "Argument names size mismatch for " + Variant::get_type_name(T::get_base_type()) + ".");
+
+ VariantConstructData cd;
+ cd.construct = T::construct;
+ cd.validated_construct = T::validated_construct;
+ cd.ptr_construct = T::ptr_construct;
+ cd.get_argument_type = T::get_argument_type;
+ cd.argument_count = T::get_argument_count();
+ cd.arg_names = arg_names;
+ construct_data[T::get_base_type()].push_back(cd);
+}
+
+void Variant::_register_variant_constructors() {
+ add_constructor<VariantConstructNoArgsNil>(sarray());
+ add_constructor<VariantConstructorNil>(sarray("from"));
+
+ add_constructor<VariantConstructNoArgs<bool>>(sarray());
+ add_constructor<VariantConstructor<bool, bool>>(sarray("from"));
+ add_constructor<VariantConstructor<bool, int64_t>>(sarray("from"));
+ add_constructor<VariantConstructor<bool, double>>(sarray("from"));
+
+ add_constructor<VariantConstructNoArgs<int64_t>>(sarray());
+ add_constructor<VariantConstructor<int64_t, int64_t>>(sarray("from"));
+ add_constructor<VariantConstructor<int64_t, double>>(sarray("from"));
+ add_constructor<VariantConstructor<int64_t, bool>>(sarray("from"));
+
+ add_constructor<VariantConstructNoArgs<double>>(sarray());
+ add_constructor<VariantConstructor<double, double>>(sarray("from"));
+ add_constructor<VariantConstructor<double, int64_t>>(sarray("from"));
+ add_constructor<VariantConstructor<double, bool>>(sarray("from"));
+
+ add_constructor<VariantConstructNoArgs<String>>(sarray());
+ add_constructor<VariantConstructor<String, String>>(sarray("from"));
+ add_constructor<VariantConstructor<String, StringName>>(sarray("from"));
+ add_constructor<VariantConstructor<String, NodePath>>(sarray("from"));
+
+ add_constructor<VariantConstructNoArgs<Vector2>>(sarray());
+ add_constructor<VariantConstructor<Vector2, Vector2>>(sarray("from"));
+ add_constructor<VariantConstructor<Vector2, Vector2i>>(sarray("from"));
+ add_constructor<VariantConstructor<Vector2, double, double>>(sarray("x", "y"));
+
+ add_constructor<VariantConstructNoArgs<Vector2i>>(sarray());
+ add_constructor<VariantConstructor<Vector2i, Vector2i>>(sarray("from"));
+ add_constructor<VariantConstructor<Vector2i, Vector2>>(sarray("from"));
+ add_constructor<VariantConstructor<Vector2i, int64_t, int64_t>>(sarray("x", "y"));
+
+ add_constructor<VariantConstructNoArgs<Rect2>>(sarray());
+ add_constructor<VariantConstructor<Rect2, Rect2>>(sarray("from"));
+ add_constructor<VariantConstructor<Rect2, Rect2i>>(sarray("from"));
+ add_constructor<VariantConstructor<Rect2, Vector2, Vector2>>(sarray("position", "size"));
+ add_constructor<VariantConstructor<Rect2, double, double, double, double>>(sarray("x", "y", "width", "height"));
+
+ add_constructor<VariantConstructNoArgs<Rect2i>>(sarray());
+ add_constructor<VariantConstructor<Rect2i, Rect2i>>(sarray("from"));
+ add_constructor<VariantConstructor<Rect2i, Rect2>>(sarray("from"));
+ add_constructor<VariantConstructor<Rect2i, Vector2i, Vector2i>>(sarray("position", "size"));
+ add_constructor<VariantConstructor<Rect2i, int64_t, int64_t, int64_t, int64_t>>(sarray("x", "y", "width", "height"));
+
+ add_constructor<VariantConstructNoArgs<Vector3>>(sarray());
+ add_constructor<VariantConstructor<Vector3, Vector3>>(sarray("from"));
+ add_constructor<VariantConstructor<Vector3, Vector3i>>(sarray("from"));
+ add_constructor<VariantConstructor<Vector3, double, double, double>>(sarray("x", "y", "z"));
+
+ add_constructor<VariantConstructNoArgs<Vector3i>>(sarray());
+ add_constructor<VariantConstructor<Vector3i, Vector3i>>(sarray("from"));
+ add_constructor<VariantConstructor<Vector3i, Vector3>>(sarray("from"));
+ add_constructor<VariantConstructor<Vector3i, int64_t, int64_t, int64_t>>(sarray("x", "y", "z"));
+
+ add_constructor<VariantConstructNoArgs<Transform2D>>(sarray());
+ add_constructor<VariantConstructor<Transform2D, Transform2D>>(sarray("from"));
+ add_constructor<VariantConstructor<Transform2D, float, Vector2>>(sarray("rotation", "position"));
+ add_constructor<VariantConstructor<Transform2D, Vector2, Vector2, Vector2>>(sarray("x_axis", "y_axis", "origin"));
+
+ add_constructor<VariantConstructNoArgs<Plane>>(sarray());
+ add_constructor<VariantConstructor<Plane, Plane>>(sarray("from"));
+ add_constructor<VariantConstructor<Plane, Vector3, double>>(sarray("normal", "d"));
+ add_constructor<VariantConstructor<Plane, Vector3, Vector3>>(sarray("point", "normal"));
+ add_constructor<VariantConstructor<Plane, Vector3, Vector3, Vector3>>(sarray("point1", "point2", "point3"));
+ add_constructor<VariantConstructor<Plane, double, double, double, double>>(sarray("a", "b", "c", "d"));
+
+ add_constructor<VariantConstructNoArgs<Quat>>(sarray());
+ add_constructor<VariantConstructor<Quat, Quat>>(sarray("from"));
+ add_constructor<VariantConstructor<Quat, Basis>>(sarray("from"));
+ add_constructor<VariantConstructor<Quat, Vector3>>(sarray("euler"));
+ add_constructor<VariantConstructor<Quat, Vector3, double>>(sarray("axis", "angle"));
+ add_constructor<VariantConstructor<Quat, Vector3, Vector3>>(sarray("arc_from", "arc_to"));
+ add_constructor<VariantConstructor<Quat, double, double, double, double>>(sarray("x", "y", "z", "w"));
+
+ add_constructor<VariantConstructNoArgs<::AABB>>(sarray());
+ add_constructor<VariantConstructor<::AABB, ::AABB>>(sarray("from"));
+ add_constructor<VariantConstructor<::AABB, Vector3, Vector3>>(sarray("position", "size"));
+
+ add_constructor<VariantConstructNoArgs<Basis>>(sarray());
+ add_constructor<VariantConstructor<Basis, Basis>>(sarray("from"));
+ add_constructor<VariantConstructor<Basis, Quat>>(sarray("from"));
+ add_constructor<VariantConstructor<Basis, Vector3>>(sarray("euler"));
+ add_constructor<VariantConstructor<Basis, Vector3, double>>(sarray("axis", "phi"));
+ add_constructor<VariantConstructor<Basis, Vector3, Vector3, Vector3>>(sarray("x_axis", "y_axis", "z_axis"));
+
+ add_constructor<VariantConstructNoArgs<Transform>>(sarray());
+ add_constructor<VariantConstructor<Transform, Transform>>(sarray("from"));
+ add_constructor<VariantConstructor<Transform, Basis, Vector3>>(sarray("basis", "origin"));
+ add_constructor<VariantConstructor<Transform, Vector3, Vector3, Vector3, Vector3>>(sarray("x_axis", "y_axis", "z_axis", "origin"));
+
+ add_constructor<VariantConstructNoArgs<Color>>(sarray());
+ add_constructor<VariantConstructor<Color, Color>>(sarray("from"));
+ add_constructor<VariantConstructor<Color, Color, double>>(sarray("from", "alpha"));
+ add_constructor<VariantConstructor<Color, double, double, double>>(sarray("r", "g", "b"));
+ add_constructor<VariantConstructor<Color, double, double, double, double>>(sarray("r", "g", "b", "a"));
+
+ add_constructor<VariantConstructNoArgs<StringName>>(sarray());
+ add_constructor<VariantConstructor<StringName, StringName>>(sarray("from"));
+ add_constructor<VariantConstructor<StringName, String>>(sarray("from"));
+
+ add_constructor<VariantConstructNoArgs<NodePath>>(sarray());
+ add_constructor<VariantConstructor<NodePath, NodePath>>(sarray("from"));
+ add_constructor<VariantConstructor<NodePath, String>>(sarray("from"));
+
+ add_constructor<VariantConstructNoArgs<::RID>>(sarray());
+ add_constructor<VariantConstructor<::RID, ::RID>>(sarray("from"));
+
+ add_constructor<VariantConstructNoArgsObject>(sarray());
+ add_constructor<VariantConstructorObject>(sarray("from"));
+ add_constructor<VariantConstructorNilObject>(sarray("from"));
+
+ add_constructor<VariantConstructNoArgs<Callable>>(sarray());
+ add_constructor<VariantConstructor<Callable, Callable>>(sarray("from"));
+ add_constructor<VariantConstructorCallableArgs>(sarray("object", "method"));
+
+ add_constructor<VariantConstructNoArgs<Signal>>(sarray());
+ add_constructor<VariantConstructor<Signal, Signal>>(sarray("from"));
+ add_constructor<VariantConstructorSignalArgs>(sarray("object", "signal"));
+
+ add_constructor<VariantConstructNoArgs<Dictionary>>(sarray());
+ add_constructor<VariantConstructor<Dictionary, Dictionary>>(sarray("from"));
+
+ add_constructor<VariantConstructNoArgs<Array>>(sarray());
+ add_constructor<VariantConstructor<Array, Array>>(sarray("from"));
+ add_constructor<VariantConstructorToArray<PackedByteArray>>(sarray("from"));
+ add_constructor<VariantConstructorToArray<PackedInt32Array>>(sarray("from"));
+ add_constructor<VariantConstructorToArray<PackedInt64Array>>(sarray("from"));
+ add_constructor<VariantConstructorToArray<PackedFloat32Array>>(sarray("from"));
+ add_constructor<VariantConstructorToArray<PackedFloat64Array>>(sarray("from"));
+ add_constructor<VariantConstructorToArray<PackedStringArray>>(sarray("from"));
+ add_constructor<VariantConstructorToArray<PackedVector2Array>>(sarray("from"));
+ add_constructor<VariantConstructorToArray<PackedVector3Array>>(sarray("from"));
+ add_constructor<VariantConstructorToArray<PackedColorArray>>(sarray("from"));
+
+ add_constructor<VariantConstructNoArgs<PackedByteArray>>(sarray());
+ add_constructor<VariantConstructor<PackedByteArray, PackedByteArray>>(sarray("from"));
+ add_constructor<VariantConstructorFromArray<PackedByteArray>>(sarray("from"));
+
+ add_constructor<VariantConstructNoArgs<PackedInt32Array>>(sarray());
+ add_constructor<VariantConstructor<PackedInt32Array, PackedInt32Array>>(sarray("from"));
+ add_constructor<VariantConstructorFromArray<PackedInt32Array>>(sarray("from"));
+
+ add_constructor<VariantConstructNoArgs<PackedInt64Array>>(sarray());
+ add_constructor<VariantConstructor<PackedInt64Array, PackedInt64Array>>(sarray("from"));
+ add_constructor<VariantConstructorFromArray<PackedInt64Array>>(sarray("from"));
+
+ add_constructor<VariantConstructNoArgs<PackedFloat32Array>>(sarray());
+ add_constructor<VariantConstructor<PackedFloat32Array, PackedFloat32Array>>(sarray("from"));
+ add_constructor<VariantConstructorFromArray<PackedFloat32Array>>(sarray("from"));
+
+ add_constructor<VariantConstructNoArgs<PackedFloat64Array>>(sarray());
+ add_constructor<VariantConstructor<PackedFloat64Array, PackedFloat64Array>>(sarray("from"));
+ add_constructor<VariantConstructorFromArray<PackedFloat64Array>>(sarray("from"));
+
+ add_constructor<VariantConstructNoArgs<PackedStringArray>>(sarray());
+ add_constructor<VariantConstructor<PackedStringArray, PackedStringArray>>(sarray("from"));
+ add_constructor<VariantConstructorFromArray<PackedStringArray>>(sarray("from"));
+
+ add_constructor<VariantConstructNoArgs<PackedVector2Array>>(sarray());
+ add_constructor<VariantConstructor<PackedVector2Array, PackedVector2Array>>(sarray("from"));
+ add_constructor<VariantConstructorFromArray<PackedVector2Array>>(sarray("from"));
+
+ add_constructor<VariantConstructNoArgs<PackedVector3Array>>(sarray());
+ add_constructor<VariantConstructor<PackedVector3Array, PackedVector3Array>>(sarray("from"));
+ add_constructor<VariantConstructorFromArray<PackedVector3Array>>(sarray("from"));
+
+ add_constructor<VariantConstructNoArgs<PackedColorArray>>(sarray());
+ add_constructor<VariantConstructor<PackedColorArray, PackedColorArray>>(sarray("from"));
+ add_constructor<VariantConstructorFromArray<PackedColorArray>>(sarray("from"));
+}
+
+void Variant::_unregister_variant_constructors() {
+ for (int i = 0; i < Variant::VARIANT_MAX; i++) {
+ construct_data[i].clear();
+ }
+}
+
+void Variant::construct(Variant::Type p_type, Variant &base, const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
+ uint32_t s = construct_data[p_type].size();
+ for (uint32_t i = 0; i < s; i++) {
+ int argc = construct_data[p_type][i].argument_count;
+ if (argc != p_argcount) {
+ continue;
+ }
+ bool args_match = true;
+ for (int j = 0; j < argc; j++) {
+ if (!Variant::can_convert_strict(p_args[j]->get_type(), construct_data[p_type][i].get_argument_type(j))) {
+ args_match = false;
+ break;
+ }
+ }
+
+ if (!args_match) {
+ continue;
+ }
+
+ construct_data[p_type][i].construct(base, p_args, r_error);
+ return;
+ }
+
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
+}
+
+int Variant::get_constructor_count(Variant::Type p_type) {
+ ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, -1);
+ return construct_data[p_type].size();
+}
+
+Variant::ValidatedConstructor Variant::get_validated_constructor(Variant::Type p_type, int p_constructor) {
+ ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, nullptr);
+ ERR_FAIL_INDEX_V(p_constructor, (int)construct_data[p_type].size(), nullptr);
+ return construct_data[p_type][p_constructor].validated_construct;
+}
+
+Variant::PTRConstructor Variant::get_ptr_constructor(Variant::Type p_type, int p_constructor) {
+ ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, nullptr);
+ ERR_FAIL_INDEX_V(p_constructor, (int)construct_data[p_type].size(), nullptr);
+ return construct_data[p_type][p_constructor].ptr_construct;
+}
+
+int Variant::get_constructor_argument_count(Variant::Type p_type, int p_constructor) {
+ ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, -1);
+ ERR_FAIL_INDEX_V(p_constructor, (int)construct_data[p_type].size(), -1);
+ return construct_data[p_type][p_constructor].argument_count;
+}
+
+Variant::Type Variant::get_constructor_argument_type(Variant::Type p_type, int p_constructor, int p_argument) {
+ ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, Variant::VARIANT_MAX);
+ ERR_FAIL_INDEX_V(p_constructor, (int)construct_data[p_type].size(), Variant::VARIANT_MAX);
+ return construct_data[p_type][p_constructor].get_argument_type(p_argument);
+}
+
+String Variant::get_constructor_argument_name(Variant::Type p_type, int p_constructor, int p_argument) {
+ ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, String());
+ ERR_FAIL_INDEX_V(p_constructor, (int)construct_data[p_type].size(), String());
+ return construct_data[p_type][p_constructor].arg_names[p_argument];
+}
+
+void VariantInternal::object_assign(Variant *v, const Variant *o) {
+ if (o->_get_obj().obj && o->_get_obj().id.is_reference()) {
+ Reference *reference = static_cast<Reference *>(o->_get_obj().obj);
+ if (!reference->reference()) {
+ v->_get_obj().obj = nullptr;
+ v->_get_obj().id = ObjectID();
+ return;
+ }
+ }
+
+ v->_get_obj().obj = const_cast<Object *>(o->_get_obj().obj);
+ v->_get_obj().id = o->_get_obj().id;
+}
+
+void Variant::get_constructor_list(Type p_type, List<MethodInfo> *r_list) {
+ ERR_FAIL_INDEX(p_type, Variant::VARIANT_MAX);
+
+ MethodInfo mi;
+ mi.return_val.type = p_type;
+ mi.name = get_type_name(p_type);
+
+ for (int i = 0; i < get_constructor_count(p_type); i++) {
+ int ac = get_constructor_argument_count(p_type, i);
+ mi.arguments.clear();
+ for (int j = 0; j < ac; j++) {
+ PropertyInfo arg;
+ arg.name = get_constructor_argument_name(p_type, i, j);
+ arg.type = get_constructor_argument_type(p_type, i, j);
+ mi.arguments.push_back(arg);
+ }
+ r_list->push_back(mi);
+ }
+}
diff --git a/core/variant/variant_internal.h b/core/variant/variant_internal.h
new file mode 100644
index 0000000000..bf7e46eed7
--- /dev/null
+++ b/core/variant/variant_internal.h
@@ -0,0 +1,1384 @@
+/*************************************************************************/
+/* variant_internal.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* 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. */
+/*************************************************************************/
+
+#ifndef VARIANT_INTERNAL_H
+#define VARIANT_INTERNAL_H
+
+#include "variant.h"
+
+// For use when you want to access the internal pointer of a Variant directly.
+// Use with caution. You need to be sure that the type is correct.
+class VariantInternal {
+public:
+ // Set type.
+ _FORCE_INLINE_ static void initialize(Variant *v, Variant::Type p_type) {
+ v->clear();
+ v->type = p_type;
+
+ switch (p_type) {
+ case Variant::AABB:
+ init_aabb(v);
+ break;
+ case Variant::TRANSFORM2D:
+ init_transform2d(v);
+ break;
+ case Variant::TRANSFORM:
+ init_transform(v);
+ break;
+ case Variant::STRING:
+ init_string(v);
+ break;
+ case Variant::STRING_NAME:
+ init_string_name(v);
+ break;
+ case Variant::NODE_PATH:
+ init_node_path(v);
+ break;
+ case Variant::CALLABLE:
+ init_callable(v);
+ break;
+ case Variant::SIGNAL:
+ init_signal(v);
+ break;
+ case Variant::DICTIONARY:
+ init_dictionary(v);
+ break;
+ case Variant::ARRAY:
+ init_array(v);
+ break;
+ case Variant::PACKED_BYTE_ARRAY:
+ init_byte_array(v);
+ break;
+ case Variant::PACKED_INT32_ARRAY:
+ init_int32_array(v);
+ break;
+ case Variant::PACKED_INT64_ARRAY:
+ init_int64_array(v);
+ break;
+ case Variant::PACKED_FLOAT32_ARRAY:
+ init_float32_array(v);
+ break;
+ case Variant::PACKED_FLOAT64_ARRAY:
+ init_float64_array(v);
+ break;
+ case Variant::PACKED_STRING_ARRAY:
+ init_string_array(v);
+ break;
+ case Variant::PACKED_VECTOR2_ARRAY:
+ init_vector2_array(v);
+ break;
+ case Variant::PACKED_VECTOR3_ARRAY:
+ init_vector3_array(v);
+ break;
+ case Variant::PACKED_COLOR_ARRAY:
+ init_color_array(v);
+ break;
+ default:
+ break;
+ }
+ }
+
+ _FORCE_INLINE_ static void set_object(Variant *v, Object *obj) {
+ if (obj) {
+ v->_get_obj().obj = obj;
+ v->_get_obj().id = obj->get_instance_id();
+ } else {
+ v->_get_obj().obj = nullptr;
+ v->_get_obj().id = ObjectID();
+ }
+ }
+
+ // Atomic types.
+ _FORCE_INLINE_ static bool *get_bool(Variant *v) { return &v->_data._bool; }
+ _FORCE_INLINE_ static const bool *get_bool(const Variant *v) { return &v->_data._bool; }
+ _FORCE_INLINE_ static int64_t *get_int(Variant *v) { return &v->_data._int; }
+ _FORCE_INLINE_ static const int64_t *get_int(const Variant *v) { return &v->_data._int; }
+ _FORCE_INLINE_ static double *get_float(Variant *v) { return &v->_data._float; }
+ _FORCE_INLINE_ static const double *get_float(const Variant *v) { return &v->_data._float; }
+ _FORCE_INLINE_ static String *get_string(Variant *v) { return reinterpret_cast<String *>(v->_data._mem); }
+ _FORCE_INLINE_ static const String *get_string(const Variant *v) { return reinterpret_cast<const String *>(v->_data._mem); }
+
+ // Math types.
+ _FORCE_INLINE_ static Vector2 *get_vector2(Variant *v) { return reinterpret_cast<Vector2 *>(v->_data._mem); }
+ _FORCE_INLINE_ static const Vector2 *get_vector2(const Variant *v) { return reinterpret_cast<const Vector2 *>(v->_data._mem); }
+ _FORCE_INLINE_ static Vector2i *get_vector2i(Variant *v) { return reinterpret_cast<Vector2i *>(v->_data._mem); }
+ _FORCE_INLINE_ static const Vector2i *get_vector2i(const Variant *v) { return reinterpret_cast<const Vector2i *>(v->_data._mem); }
+ _FORCE_INLINE_ static Rect2 *get_rect2(Variant *v) { return reinterpret_cast<Rect2 *>(v->_data._mem); }
+ _FORCE_INLINE_ static const Rect2 *get_rect2(const Variant *v) { return reinterpret_cast<const Rect2 *>(v->_data._mem); }
+ _FORCE_INLINE_ static Rect2i *get_rect2i(Variant *v) { return reinterpret_cast<Rect2i *>(v->_data._mem); }
+ _FORCE_INLINE_ static const Rect2i *get_rect2i(const Variant *v) { return reinterpret_cast<const Rect2i *>(v->_data._mem); }
+ _FORCE_INLINE_ static Vector3 *get_vector3(Variant *v) { return reinterpret_cast<Vector3 *>(v->_data._mem); }
+ _FORCE_INLINE_ static const Vector3 *get_vector3(const Variant *v) { return reinterpret_cast<const Vector3 *>(v->_data._mem); }
+ _FORCE_INLINE_ static Vector3i *get_vector3i(Variant *v) { return reinterpret_cast<Vector3i *>(v->_data._mem); }
+ _FORCE_INLINE_ static const Vector3i *get_vector3i(const Variant *v) { return reinterpret_cast<const Vector3i *>(v->_data._mem); }
+ _FORCE_INLINE_ static Transform2D *get_transform2d(Variant *v) { return v->_data._transform2d; }
+ _FORCE_INLINE_ static const Transform2D *get_transform2d(const Variant *v) { return v->_data._transform2d; }
+ _FORCE_INLINE_ static Plane *get_plane(Variant *v) { return reinterpret_cast<Plane *>(v->_data._mem); }
+ _FORCE_INLINE_ static const Plane *get_plane(const Variant *v) { return reinterpret_cast<const Plane *>(v->_data._mem); }
+ _FORCE_INLINE_ static Quat *get_quat(Variant *v) { return reinterpret_cast<Quat *>(v->_data._mem); }
+ _FORCE_INLINE_ static const Quat *get_quat(const Variant *v) { return reinterpret_cast<const Quat *>(v->_data._mem); }
+ _FORCE_INLINE_ static ::AABB *get_aabb(Variant *v) { return v->_data._aabb; }
+ _FORCE_INLINE_ static const ::AABB *get_aabb(const Variant *v) { return v->_data._aabb; }
+ _FORCE_INLINE_ static Basis *get_basis(Variant *v) { return v->_data._basis; }
+ _FORCE_INLINE_ static const Basis *get_basis(const Variant *v) { return v->_data._basis; }
+ _FORCE_INLINE_ static Transform *get_transform(Variant *v) { return v->_data._transform; }
+ _FORCE_INLINE_ static const Transform *get_transform(const Variant *v) { return v->_data._transform; }
+
+ // Misc types.
+ _FORCE_INLINE_ static Color *get_color(Variant *v) { return reinterpret_cast<Color *>(v->_data._mem); }
+ _FORCE_INLINE_ static const Color *get_color(const Variant *v) { return reinterpret_cast<const Color *>(v->_data._mem); }
+ _FORCE_INLINE_ static StringName *get_string_name(Variant *v) { return reinterpret_cast<StringName *>(v->_data._mem); }
+ _FORCE_INLINE_ static const StringName *get_string_name(const Variant *v) { return reinterpret_cast<const StringName *>(v->_data._mem); }
+ _FORCE_INLINE_ static NodePath *get_node_path(Variant *v) { return reinterpret_cast<NodePath *>(v->_data._mem); }
+ _FORCE_INLINE_ static const NodePath *get_node_path(const Variant *v) { return reinterpret_cast<const NodePath *>(v->_data._mem); }
+ _FORCE_INLINE_ static ::RID *get_rid(Variant *v) { return reinterpret_cast<::RID *>(v->_data._mem); }
+ _FORCE_INLINE_ static const ::RID *get_rid(const Variant *v) { return reinterpret_cast<const ::RID *>(v->_data._mem); }
+ _FORCE_INLINE_ static Callable *get_callable(Variant *v) { return reinterpret_cast<Callable *>(v->_data._mem); }
+ _FORCE_INLINE_ static const Callable *get_callable(const Variant *v) { return reinterpret_cast<const Callable *>(v->_data._mem); }
+ _FORCE_INLINE_ static Signal *get_signal(Variant *v) { return reinterpret_cast<Signal *>(v->_data._mem); }
+ _FORCE_INLINE_ static const Signal *get_signal(const Variant *v) { return reinterpret_cast<const Signal *>(v->_data._mem); }
+ _FORCE_INLINE_ static Dictionary *get_dictionary(Variant *v) { return reinterpret_cast<Dictionary *>(v->_data._mem); }
+ _FORCE_INLINE_ static const Dictionary *get_dictionary(const Variant *v) { return reinterpret_cast<const Dictionary *>(v->_data._mem); }
+ _FORCE_INLINE_ static Array *get_array(Variant *v) { return reinterpret_cast<Array *>(v->_data._mem); }
+ _FORCE_INLINE_ static const Array *get_array(const Variant *v) { return reinterpret_cast<const Array *>(v->_data._mem); }
+
+ // Typed arrays.
+ _FORCE_INLINE_ static PackedByteArray *get_byte_array(Variant *v) { return &static_cast<Variant::PackedArrayRef<uint8_t> *>(v->_data.packed_array)->array; }
+ _FORCE_INLINE_ static const PackedByteArray *get_byte_array(const Variant *v) { return &static_cast<const Variant::PackedArrayRef<uint8_t> *>(v->_data.packed_array)->array; }
+ _FORCE_INLINE_ static PackedInt32Array *get_int32_array(Variant *v) { return &static_cast<Variant::PackedArrayRef<int32_t> *>(v->_data.packed_array)->array; }
+ _FORCE_INLINE_ static const PackedInt32Array *get_int32_array(const Variant *v) { return &static_cast<const Variant::PackedArrayRef<int32_t> *>(v->_data.packed_array)->array; }
+ _FORCE_INLINE_ static PackedInt64Array *get_int64_array(Variant *v) { return &static_cast<Variant::PackedArrayRef<int64_t> *>(v->_data.packed_array)->array; }
+ _FORCE_INLINE_ static const PackedInt64Array *get_int64_array(const Variant *v) { return &static_cast<const Variant::PackedArrayRef<int64_t> *>(v->_data.packed_array)->array; }
+ _FORCE_INLINE_ static PackedFloat32Array *get_float32_array(Variant *v) { return &static_cast<Variant::PackedArrayRef<float> *>(v->_data.packed_array)->array; }
+ _FORCE_INLINE_ static const PackedFloat32Array *get_float32_array(const Variant *v) { return &static_cast<const Variant::PackedArrayRef<float> *>(v->_data.packed_array)->array; }
+ _FORCE_INLINE_ static PackedFloat64Array *get_float64_array(Variant *v) { return &static_cast<Variant::PackedArrayRef<double> *>(v->_data.packed_array)->array; }
+ _FORCE_INLINE_ static const PackedFloat64Array *get_float64_array(const Variant *v) { return &static_cast<const Variant::PackedArrayRef<double> *>(v->_data.packed_array)->array; }
+ _FORCE_INLINE_ static PackedStringArray *get_string_array(Variant *v) { return &static_cast<Variant::PackedArrayRef<String> *>(v->_data.packed_array)->array; }
+ _FORCE_INLINE_ static const PackedStringArray *get_string_array(const Variant *v) { return &static_cast<const Variant::PackedArrayRef<String> *>(v->_data.packed_array)->array; }
+ _FORCE_INLINE_ static PackedVector2Array *get_vector2_array(Variant *v) { return &static_cast<Variant::PackedArrayRef<Vector2> *>(v->_data.packed_array)->array; }
+ _FORCE_INLINE_ static const PackedVector2Array *get_vector2_array(const Variant *v) { return &static_cast<const Variant::PackedArrayRef<Vector2> *>(v->_data.packed_array)->array; }
+ _FORCE_INLINE_ static PackedVector3Array *get_vector3_array(Variant *v) { return &static_cast<Variant::PackedArrayRef<Vector3> *>(v->_data.packed_array)->array; }
+ _FORCE_INLINE_ static const PackedVector3Array *get_vector3_array(const Variant *v) { return &static_cast<const Variant::PackedArrayRef<Vector3> *>(v->_data.packed_array)->array; }
+ _FORCE_INLINE_ static PackedColorArray *get_color_array(Variant *v) { return &static_cast<Variant::PackedArrayRef<Color> *>(v->_data.packed_array)->array; }
+ _FORCE_INLINE_ static const PackedColorArray *get_color_array(const Variant *v) { return &static_cast<const Variant::PackedArrayRef<Color> *>(v->_data.packed_array)->array; }
+
+ _FORCE_INLINE_ static Object **get_object(Variant *v) { return (Object **)&v->_get_obj().obj; }
+ _FORCE_INLINE_ static const Object **get_object(const Variant *v) { return (const Object **)&v->_get_obj().obj; }
+
+ _FORCE_INLINE_ static const ObjectID get_object_id(const Variant *v) { return v->_get_obj().id; }
+
+ template <class T>
+ _FORCE_INLINE_ static void init_generic(Variant *v) {
+ v->type = GetTypeInfo<T>::VARIANT_TYPE;
+ }
+
+ _FORCE_INLINE_ static void init_string(Variant *v) {
+ memnew_placement(v->_data._mem, String);
+ v->type = Variant::STRING;
+ }
+
+ _FORCE_INLINE_ static void init_transform2d(Variant *v) {
+ v->_data._transform2d = memnew(Transform2D);
+ v->type = Variant::TRANSFORM2D;
+ }
+ _FORCE_INLINE_ static void init_aabb(Variant *v) {
+ v->_data._aabb = memnew(AABB);
+ v->type = Variant::AABB;
+ }
+ _FORCE_INLINE_ static void init_basis(Variant *v) {
+ v->_data._basis = memnew(Basis);
+ v->type = Variant::BASIS;
+ }
+ _FORCE_INLINE_ static void init_transform(Variant *v) {
+ v->_data._transform = memnew(Transform);
+ v->type = Variant::TRANSFORM;
+ }
+ _FORCE_INLINE_ static void init_string_name(Variant *v) {
+ memnew_placement(v->_data._mem, StringName);
+ v->type = Variant::STRING_NAME;
+ }
+ _FORCE_INLINE_ static void init_node_path(Variant *v) {
+ memnew_placement(v->_data._mem, NodePath);
+ v->type = Variant::NODE_PATH;
+ }
+ _FORCE_INLINE_ static void init_callable(Variant *v) {
+ memnew_placement(v->_data._mem, Callable);
+ v->type = Variant::CALLABLE;
+ }
+ _FORCE_INLINE_ static void init_signal(Variant *v) {
+ memnew_placement(v->_data._mem, Signal);
+ v->type = Variant::SIGNAL;
+ }
+ _FORCE_INLINE_ static void init_dictionary(Variant *v) {
+ memnew_placement(v->_data._mem, Dictionary);
+ v->type = Variant::DICTIONARY;
+ }
+ _FORCE_INLINE_ static void init_array(Variant *v) {
+ memnew_placement(v->_data._mem, Array);
+ v->type = Variant::ARRAY;
+ }
+ _FORCE_INLINE_ static void init_byte_array(Variant *v) {
+ v->_data.packed_array = Variant::PackedArrayRef<uint8_t>::create(Vector<uint8_t>());
+ v->type = Variant::PACKED_BYTE_ARRAY;
+ }
+ _FORCE_INLINE_ static void init_int32_array(Variant *v) {
+ v->_data.packed_array = Variant::PackedArrayRef<int32_t>::create(Vector<int32_t>());
+ v->type = Variant::PACKED_INT32_ARRAY;
+ }
+ _FORCE_INLINE_ static void init_int64_array(Variant *v) {
+ v->_data.packed_array = Variant::PackedArrayRef<int64_t>::create(Vector<int64_t>());
+ v->type = Variant::PACKED_INT64_ARRAY;
+ }
+ _FORCE_INLINE_ static void init_float32_array(Variant *v) {
+ v->_data.packed_array = Variant::PackedArrayRef<float>::create(Vector<float>());
+ v->type = Variant::PACKED_FLOAT32_ARRAY;
+ }
+ _FORCE_INLINE_ static void init_float64_array(Variant *v) {
+ v->_data.packed_array = Variant::PackedArrayRef<double>::create(Vector<double>());
+ v->type = Variant::PACKED_FLOAT64_ARRAY;
+ }
+ _FORCE_INLINE_ static void init_string_array(Variant *v) {
+ v->_data.packed_array = Variant::PackedArrayRef<String>::create(Vector<String>());
+ v->type = Variant::PACKED_STRING_ARRAY;
+ }
+ _FORCE_INLINE_ static void init_vector2_array(Variant *v) {
+ v->_data.packed_array = Variant::PackedArrayRef<Vector2>::create(Vector<Vector2>());
+ v->type = Variant::PACKED_VECTOR2_ARRAY;
+ }
+ _FORCE_INLINE_ static void init_vector3_array(Variant *v) {
+ v->_data.packed_array = Variant::PackedArrayRef<Vector3>::create(Vector<Vector3>());
+ v->type = Variant::PACKED_VECTOR3_ARRAY;
+ }
+ _FORCE_INLINE_ static void init_color_array(Variant *v) {
+ v->_data.packed_array = Variant::PackedArrayRef<Color>::create(Vector<Color>());
+ v->type = Variant::PACKED_COLOR_ARRAY;
+ }
+
+ _FORCE_INLINE_ static void clear(Variant *v) {
+ v->clear();
+ }
+
+ static void object_assign(Variant *v, const Variant *o); //needs to use reference, do away
+
+ _FORCE_INLINE_ static void object_assign_null(Variant *v) {
+ v->_get_obj().obj = nullptr;
+ v->_get_obj().id = ObjectID();
+ }
+
+ _FORCE_INLINE_ static void *get_opaque_pointer(Variant *v) {
+ switch (v->type) {
+ case Variant::NIL:
+ return nullptr;
+ case Variant::BOOL:
+ return get_bool(v);
+ case Variant::INT:
+ return get_int(v);
+ case Variant::FLOAT:
+ return get_float(v);
+ case Variant::STRING:
+ return get_string(v);
+ case Variant::VECTOR2:
+ return get_vector2(v);
+ case Variant::VECTOR2I:
+ return get_vector2i(v);
+ case Variant::VECTOR3:
+ return get_vector3(v);
+ case Variant::VECTOR3I:
+ return get_vector3i(v);
+ case Variant::RECT2:
+ return get_rect2(v);
+ case Variant::RECT2I:
+ return get_rect2i(v);
+ case Variant::TRANSFORM:
+ return get_transform(v);
+ case Variant::TRANSFORM2D:
+ return get_transform2d(v);
+ case Variant::QUAT:
+ return get_quat(v);
+ case Variant::PLANE:
+ return get_plane(v);
+ case Variant::BASIS:
+ return get_basis(v);
+ case Variant::AABB:
+ return get_aabb(v);
+ case Variant::COLOR:
+ return get_color(v);
+ case Variant::STRING_NAME:
+ return get_string_name(v);
+ case Variant::NODE_PATH:
+ return get_node_path(v);
+ case Variant::RID:
+ return get_rid(v);
+ case Variant::CALLABLE:
+ return get_callable(v);
+ case Variant::SIGNAL:
+ return get_signal(v);
+ case Variant::DICTIONARY:
+ return get_dictionary(v);
+ case Variant::ARRAY:
+ return get_array(v);
+ case Variant::PACKED_BYTE_ARRAY:
+ return get_byte_array(v);
+ case Variant::PACKED_INT32_ARRAY:
+ return get_int32_array(v);
+ case Variant::PACKED_INT64_ARRAY:
+ return get_int64_array(v);
+ case Variant::PACKED_FLOAT32_ARRAY:
+ return get_float32_array(v);
+ case Variant::PACKED_FLOAT64_ARRAY:
+ return get_float64_array(v);
+ case Variant::PACKED_STRING_ARRAY:
+ return get_string_array(v);
+ case Variant::PACKED_VECTOR2_ARRAY:
+ return get_vector2_array(v);
+ case Variant::PACKED_VECTOR3_ARRAY:
+ return get_vector3_array(v);
+ case Variant::PACKED_COLOR_ARRAY:
+ return get_color_array(v);
+ case Variant::OBJECT:
+ return v->_get_obj().obj;
+ case Variant::VARIANT_MAX:
+ ERR_FAIL_V(nullptr);
+ }
+ ERR_FAIL_V(nullptr);
+ }
+
+ _FORCE_INLINE_ static const void *get_opaque_pointer(const Variant *v) {
+ switch (v->type) {
+ case Variant::NIL:
+ return nullptr;
+ case Variant::BOOL:
+ return get_bool(v);
+ case Variant::INT:
+ return get_int(v);
+ case Variant::FLOAT:
+ return get_float(v);
+ case Variant::STRING:
+ return get_string(v);
+ case Variant::VECTOR2:
+ return get_vector2(v);
+ case Variant::VECTOR2I:
+ return get_vector2i(v);
+ case Variant::VECTOR3:
+ return get_vector3(v);
+ case Variant::VECTOR3I:
+ return get_vector3i(v);
+ case Variant::RECT2:
+ return get_rect2(v);
+ case Variant::RECT2I:
+ return get_rect2i(v);
+ case Variant::TRANSFORM:
+ return get_transform(v);
+ case Variant::TRANSFORM2D:
+ return get_transform2d(v);
+ case Variant::QUAT:
+ return get_quat(v);
+ case Variant::PLANE:
+ return get_plane(v);
+ case Variant::BASIS:
+ return get_basis(v);
+ case Variant::AABB:
+ return get_aabb(v);
+ case Variant::COLOR:
+ return get_color(v);
+ case Variant::STRING_NAME:
+ return get_string_name(v);
+ case Variant::NODE_PATH:
+ return get_node_path(v);
+ case Variant::RID:
+ return get_rid(v);
+ case Variant::CALLABLE:
+ return get_callable(v);
+ case Variant::SIGNAL:
+ return get_signal(v);
+ case Variant::DICTIONARY:
+ return get_dictionary(v);
+ case Variant::ARRAY:
+ return get_array(v);
+ case Variant::PACKED_BYTE_ARRAY:
+ return get_byte_array(v);
+ case Variant::PACKED_INT32_ARRAY:
+ return get_int32_array(v);
+ case Variant::PACKED_INT64_ARRAY:
+ return get_int64_array(v);
+ case Variant::PACKED_FLOAT32_ARRAY:
+ return get_float32_array(v);
+ case Variant::PACKED_FLOAT64_ARRAY:
+ return get_float64_array(v);
+ case Variant::PACKED_STRING_ARRAY:
+ return get_string_array(v);
+ case Variant::PACKED_VECTOR2_ARRAY:
+ return get_vector2_array(v);
+ case Variant::PACKED_VECTOR3_ARRAY:
+ return get_vector3_array(v);
+ case Variant::PACKED_COLOR_ARRAY:
+ return get_color_array(v);
+ case Variant::OBJECT:
+ return v->_get_obj().obj;
+ case Variant::VARIANT_MAX:
+ ERR_FAIL_V(nullptr);
+ }
+ ERR_FAIL_V(nullptr);
+ }
+};
+
+template <class T>
+struct VariantGetInternalPtr {
+};
+
+template <>
+struct VariantGetInternalPtr<bool> {
+ static bool *get_ptr(Variant *v) { return VariantInternal::get_bool(v); }
+ static const bool *get_ptr(const Variant *v) { return VariantInternal::get_bool(v); }
+};
+
+template <>
+struct VariantGetInternalPtr<int8_t> {
+ static int64_t *get_ptr(Variant *v) { return VariantInternal::get_int(v); }
+ static const int64_t *get_ptr(const Variant *v) { return VariantInternal::get_int(v); }
+};
+
+template <>
+struct VariantGetInternalPtr<uint8_t> {
+ static int64_t *get_ptr(Variant *v) { return VariantInternal::get_int(v); }
+ static const int64_t *get_ptr(const Variant *v) { return VariantInternal::get_int(v); }
+};
+
+template <>
+struct VariantGetInternalPtr<int16_t> {
+ static int64_t *get_ptr(Variant *v) { return VariantInternal::get_int(v); }
+ static const int64_t *get_ptr(const Variant *v) { return VariantInternal::get_int(v); }
+};
+
+template <>
+struct VariantGetInternalPtr<uint16_t> {
+ static int64_t *get_ptr(Variant *v) { return VariantInternal::get_int(v); }
+ static const int64_t *get_ptr(const Variant *v) { return VariantInternal::get_int(v); }
+};
+
+template <>
+struct VariantGetInternalPtr<int32_t> {
+ static int64_t *get_ptr(Variant *v) { return VariantInternal::get_int(v); }
+ static const int64_t *get_ptr(const Variant *v) { return VariantInternal::get_int(v); }
+};
+
+template <>
+struct VariantGetInternalPtr<uint32_t> {
+ static int64_t *get_ptr(Variant *v) { return VariantInternal::get_int(v); }
+ static const int64_t *get_ptr(const Variant *v) { return VariantInternal::get_int(v); }
+};
+
+template <>
+struct VariantGetInternalPtr<int64_t> {
+ static int64_t *get_ptr(Variant *v) { return VariantInternal::get_int(v); }
+ static const int64_t *get_ptr(const Variant *v) { return VariantInternal::get_int(v); }
+};
+
+template <>
+struct VariantGetInternalPtr<uint64_t> {
+ static int64_t *get_ptr(Variant *v) { return VariantInternal::get_int(v); }
+ static const int64_t *get_ptr(const Variant *v) { return VariantInternal::get_int(v); }
+};
+
+template <>
+struct VariantGetInternalPtr<char32_t> {
+ static int64_t *get_ptr(Variant *v) { return VariantInternal::get_int(v); }
+ static const int64_t *get_ptr(const Variant *v) { return VariantInternal::get_int(v); }
+};
+
+template <>
+struct VariantGetInternalPtr<ObjectID> {
+ static int64_t *get_ptr(Variant *v) { return VariantInternal::get_int(v); }
+ static const int64_t *get_ptr(const Variant *v) { return VariantInternal::get_int(v); }
+};
+
+template <>
+struct VariantGetInternalPtr<Error> {
+ static int64_t *get_ptr(Variant *v) { return VariantInternal::get_int(v); }
+ static const int64_t *get_ptr(const Variant *v) { return VariantInternal::get_int(v); }
+};
+
+template <>
+struct VariantGetInternalPtr<float> {
+ static double *get_ptr(Variant *v) { return VariantInternal::get_float(v); }
+ static const double *get_ptr(const Variant *v) { return VariantInternal::get_float(v); }
+};
+
+template <>
+struct VariantGetInternalPtr<double> {
+ static double *get_ptr(Variant *v) { return VariantInternal::get_float(v); }
+ static const double *get_ptr(const Variant *v) { return VariantInternal::get_float(v); }
+};
+
+template <>
+struct VariantGetInternalPtr<String> {
+ static String *get_ptr(Variant *v) { return VariantInternal::get_string(v); }
+ static const String *get_ptr(const Variant *v) { return VariantInternal::get_string(v); }
+};
+
+template <>
+struct VariantGetInternalPtr<Vector2> {
+ static Vector2 *get_ptr(Variant *v) { return VariantInternal::get_vector2(v); }
+ static const Vector2 *get_ptr(const Variant *v) { return VariantInternal::get_vector2(v); }
+};
+
+template <>
+struct VariantGetInternalPtr<Vector2i> {
+ static Vector2i *get_ptr(Variant *v) { return VariantInternal::get_vector2i(v); }
+ static const Vector2i *get_ptr(const Variant *v) { return VariantInternal::get_vector2i(v); }
+};
+
+template <>
+struct VariantGetInternalPtr<Rect2> {
+ static Rect2 *get_ptr(Variant *v) { return VariantInternal::get_rect2(v); }
+ static const Rect2 *get_ptr(const Variant *v) { return VariantInternal::get_rect2(v); }
+};
+
+template <>
+struct VariantGetInternalPtr<Rect2i> {
+ static Rect2i *get_ptr(Variant *v) { return VariantInternal::get_rect2i(v); }
+ static const Rect2i *get_ptr(const Variant *v) { return VariantInternal::get_rect2i(v); }
+};
+
+template <>
+struct VariantGetInternalPtr<Vector3> {
+ static Vector3 *get_ptr(Variant *v) { return VariantInternal::get_vector3(v); }
+ static const Vector3 *get_ptr(const Variant *v) { return VariantInternal::get_vector3(v); }
+};
+
+template <>
+struct VariantGetInternalPtr<Vector3i> {
+ static Vector3i *get_ptr(Variant *v) { return VariantInternal::get_vector3i(v); }
+ static const Vector3i *get_ptr(const Variant *v) { return VariantInternal::get_vector3i(v); }
+};
+
+template <>
+struct VariantGetInternalPtr<Transform2D> {
+ static Transform2D *get_ptr(Variant *v) { return VariantInternal::get_transform2d(v); }
+ static const Transform2D *get_ptr(const Variant *v) { return VariantInternal::get_transform2d(v); }
+};
+
+template <>
+struct VariantGetInternalPtr<Transform> {
+ static Transform *get_ptr(Variant *v) { return VariantInternal::get_transform(v); }
+ static const Transform *get_ptr(const Variant *v) { return VariantInternal::get_transform(v); }
+};
+
+template <>
+struct VariantGetInternalPtr<Plane> {
+ static Plane *get_ptr(Variant *v) { return VariantInternal::get_plane(v); }
+ static const Plane *get_ptr(const Variant *v) { return VariantInternal::get_plane(v); }
+};
+
+template <>
+struct VariantGetInternalPtr<Quat> {
+ static Quat *get_ptr(Variant *v) { return VariantInternal::get_quat(v); }
+ static const Quat *get_ptr(const Variant *v) { return VariantInternal::get_quat(v); }
+};
+
+template <>
+struct VariantGetInternalPtr<::AABB> {
+ static ::AABB *get_ptr(Variant *v) { return VariantInternal::get_aabb(v); }
+ static const ::AABB *get_ptr(const Variant *v) { return VariantInternal::get_aabb(v); }
+};
+
+template <>
+struct VariantGetInternalPtr<Basis> {
+ static Basis *get_ptr(Variant *v) { return VariantInternal::get_basis(v); }
+ static const Basis *get_ptr(const Variant *v) { return VariantInternal::get_basis(v); }
+};
+
+//
+
+template <>
+struct VariantGetInternalPtr<Color> {
+ static Color *get_ptr(Variant *v) { return VariantInternal::get_color(v); }
+ static const Color *get_ptr(const Variant *v) { return VariantInternal::get_color(v); }
+};
+
+template <>
+struct VariantGetInternalPtr<StringName> {
+ static StringName *get_ptr(Variant *v) { return VariantInternal::get_string_name(v); }
+ static const StringName *get_ptr(const Variant *v) { return VariantInternal::get_string_name(v); }
+};
+
+template <>
+struct VariantGetInternalPtr<NodePath> {
+ static NodePath *get_ptr(Variant *v) { return VariantInternal::get_node_path(v); }
+ static const NodePath *get_ptr(const Variant *v) { return VariantInternal::get_node_path(v); }
+};
+
+template <>
+struct VariantGetInternalPtr<::RID> {
+ static ::RID *get_ptr(Variant *v) { return VariantInternal::get_rid(v); }
+ static const ::RID *get_ptr(const Variant *v) { return VariantInternal::get_rid(v); }
+};
+
+template <>
+struct VariantGetInternalPtr<Callable> {
+ static Callable *get_ptr(Variant *v) { return VariantInternal::get_callable(v); }
+ static const Callable *get_ptr(const Variant *v) { return VariantInternal::get_callable(v); }
+};
+
+template <>
+struct VariantGetInternalPtr<Signal> {
+ static Signal *get_ptr(Variant *v) { return VariantInternal::get_signal(v); }
+ static const Signal *get_ptr(const Variant *v) { return VariantInternal::get_signal(v); }
+};
+
+template <>
+struct VariantGetInternalPtr<Dictionary> {
+ static Dictionary *get_ptr(Variant *v) { return VariantInternal::get_dictionary(v); }
+ static const Dictionary *get_ptr(const Variant *v) { return VariantInternal::get_dictionary(v); }
+};
+
+template <>
+struct VariantGetInternalPtr<Array> {
+ static Array *get_ptr(Variant *v) { return VariantInternal::get_array(v); }
+ static const Array *get_ptr(const Variant *v) { return VariantInternal::get_array(v); }
+};
+
+template <>
+struct VariantGetInternalPtr<PackedByteArray> {
+ static PackedByteArray *get_ptr(Variant *v) { return VariantInternal::get_byte_array(v); }
+ static const PackedByteArray *get_ptr(const Variant *v) { return VariantInternal::get_byte_array(v); }
+};
+
+template <>
+struct VariantGetInternalPtr<PackedInt32Array> {
+ static PackedInt32Array *get_ptr(Variant *v) { return VariantInternal::get_int32_array(v); }
+ static const PackedInt32Array *get_ptr(const Variant *v) { return VariantInternal::get_int32_array(v); }
+};
+
+template <>
+struct VariantGetInternalPtr<PackedInt64Array> {
+ static PackedInt64Array *get_ptr(Variant *v) { return VariantInternal::get_int64_array(v); }
+ static const PackedInt64Array *get_ptr(const Variant *v) { return VariantInternal::get_int64_array(v); }
+};
+
+template <>
+struct VariantGetInternalPtr<PackedFloat32Array> {
+ static PackedFloat32Array *get_ptr(Variant *v) { return VariantInternal::get_float32_array(v); }
+ static const PackedFloat32Array *get_ptr(const Variant *v) { return VariantInternal::get_float32_array(v); }
+};
+
+template <>
+struct VariantGetInternalPtr<PackedFloat64Array> {
+ static PackedFloat64Array *get_ptr(Variant *v) { return VariantInternal::get_float64_array(v); }
+ static const PackedFloat64Array *get_ptr(const Variant *v) { return VariantInternal::get_float64_array(v); }
+};
+
+template <>
+struct VariantGetInternalPtr<PackedStringArray> {
+ static PackedStringArray *get_ptr(Variant *v) { return VariantInternal::get_string_array(v); }
+ static const PackedStringArray *get_ptr(const Variant *v) { return VariantInternal::get_string_array(v); }
+};
+
+template <>
+struct VariantGetInternalPtr<PackedVector2Array> {
+ static PackedVector2Array *get_ptr(Variant *v) { return VariantInternal::get_vector2_array(v); }
+ static const PackedVector2Array *get_ptr(const Variant *v) { return VariantInternal::get_vector2_array(v); }
+};
+
+template <>
+struct VariantGetInternalPtr<PackedVector3Array> {
+ static PackedVector3Array *get_ptr(Variant *v) { return VariantInternal::get_vector3_array(v); }
+ static const PackedVector3Array *get_ptr(const Variant *v) { return VariantInternal::get_vector3_array(v); }
+};
+
+template <>
+struct VariantGetInternalPtr<PackedColorArray> {
+ static PackedColorArray *get_ptr(Variant *v) { return VariantInternal::get_color_array(v); }
+ static const PackedColorArray *get_ptr(const Variant *v) { return VariantInternal::get_color_array(v); }
+};
+
+template <class T>
+struct VariantInternalAccessor {
+};
+
+template <>
+struct VariantInternalAccessor<bool> {
+ static _FORCE_INLINE_ bool get(const Variant *v) { return *VariantInternal::get_bool(v); }
+ static _FORCE_INLINE_ void set(Variant *v, bool p_value) { *VariantInternal::get_bool(v) = p_value; }
+};
+
+#define VARIANT_ACCESSOR_NUMBER(m_type) \
+ template <> \
+ struct VariantInternalAccessor<m_type> { \
+ static _FORCE_INLINE_ m_type get(const Variant *v) { return (m_type)*VariantInternal::get_int(v); } \
+ static _FORCE_INLINE_ void set(Variant *v, m_type p_value) { *VariantInternal::get_int(v) = p_value; } \
+ };
+
+VARIANT_ACCESSOR_NUMBER(int8_t)
+VARIANT_ACCESSOR_NUMBER(uint8_t)
+VARIANT_ACCESSOR_NUMBER(int16_t)
+VARIANT_ACCESSOR_NUMBER(uint16_t)
+VARIANT_ACCESSOR_NUMBER(int32_t)
+VARIANT_ACCESSOR_NUMBER(uint32_t)
+VARIANT_ACCESSOR_NUMBER(int64_t)
+VARIANT_ACCESSOR_NUMBER(uint64_t)
+VARIANT_ACCESSOR_NUMBER(char32_t)
+VARIANT_ACCESSOR_NUMBER(Error)
+VARIANT_ACCESSOR_NUMBER(Margin)
+
+template <>
+struct VariantInternalAccessor<ObjectID> {
+ static _FORCE_INLINE_ ObjectID get(const Variant *v) { return ObjectID(*VariantInternal::get_int(v)); }
+ static _FORCE_INLINE_ void set(Variant *v, ObjectID p_value) { *VariantInternal::get_int(v) = p_value; }
+};
+
+template <>
+struct VariantInternalAccessor<float> {
+ static _FORCE_INLINE_ float get(const Variant *v) { return *VariantInternal::get_float(v); }
+ static _FORCE_INLINE_ void set(Variant *v, float p_value) { *VariantInternal::get_float(v) = p_value; }
+};
+
+template <>
+struct VariantInternalAccessor<double> {
+ static _FORCE_INLINE_ double get(const Variant *v) { return *VariantInternal::get_float(v); }
+ static _FORCE_INLINE_ void set(Variant *v, double p_value) { *VariantInternal::get_float(v) = p_value; }
+};
+
+template <>
+struct VariantInternalAccessor<String> {
+ static _FORCE_INLINE_ const String &get(const Variant *v) { return *VariantInternal::get_string(v); }
+ static _FORCE_INLINE_ void set(Variant *v, const String &p_value) { *VariantInternal::get_string(v) = p_value; }
+};
+
+template <>
+struct VariantInternalAccessor<Vector2> {
+ static _FORCE_INLINE_ const Vector2 &get(const Variant *v) { return *VariantInternal::get_vector2(v); }
+ static _FORCE_INLINE_ void set(Variant *v, const Vector2 &p_value) { *VariantInternal::get_vector2(v) = p_value; }
+};
+
+template <>
+struct VariantInternalAccessor<Vector2i> {
+ static _FORCE_INLINE_ const Vector2i &get(const Variant *v) { return *VariantInternal::get_vector2i(v); }
+ static _FORCE_INLINE_ void set(Variant *v, const Vector2i &p_value) { *VariantInternal::get_vector2i(v) = p_value; }
+};
+
+template <>
+struct VariantInternalAccessor<Rect2> {
+ static _FORCE_INLINE_ const Rect2 &get(const Variant *v) { return *VariantInternal::get_rect2(v); }
+ static _FORCE_INLINE_ void set(Variant *v, const Rect2 &p_value) { *VariantInternal::get_rect2(v) = p_value; }
+};
+
+template <>
+struct VariantInternalAccessor<Rect2i> {
+ static _FORCE_INLINE_ const Rect2i &get(const Variant *v) { return *VariantInternal::get_rect2i(v); }
+ static _FORCE_INLINE_ void set(Variant *v, const Rect2i &p_value) { *VariantInternal::get_rect2i(v) = p_value; }
+};
+
+template <>
+struct VariantInternalAccessor<Vector3> {
+ static _FORCE_INLINE_ const Vector3 &get(const Variant *v) { return *VariantInternal::get_vector3(v); }
+ static _FORCE_INLINE_ void set(Variant *v, const Vector3 &p_value) { *VariantInternal::get_vector3(v) = p_value; }
+};
+
+template <>
+struct VariantInternalAccessor<Vector3i> {
+ static _FORCE_INLINE_ const Vector3i &get(const Variant *v) { return *VariantInternal::get_vector3i(v); }
+ static _FORCE_INLINE_ void set(Variant *v, const Vector3i &p_value) { *VariantInternal::get_vector3i(v) = p_value; }
+};
+
+template <>
+struct VariantInternalAccessor<Transform2D> {
+ static _FORCE_INLINE_ const Transform2D &get(const Variant *v) { return *VariantInternal::get_transform2d(v); }
+ static _FORCE_INLINE_ void set(Variant *v, const Transform2D &p_value) { *VariantInternal::get_transform2d(v) = p_value; }
+};
+
+template <>
+struct VariantInternalAccessor<Transform> {
+ static _FORCE_INLINE_ const Transform &get(const Variant *v) { return *VariantInternal::get_transform(v); }
+ static _FORCE_INLINE_ void set(Variant *v, const Transform &p_value) { *VariantInternal::get_transform(v) = p_value; }
+};
+
+template <>
+struct VariantInternalAccessor<Plane> {
+ static _FORCE_INLINE_ const Plane &get(const Variant *v) { return *VariantInternal::get_plane(v); }
+ static _FORCE_INLINE_ void set(Variant *v, const Plane &p_value) { *VariantInternal::get_plane(v) = p_value; }
+};
+
+template <>
+struct VariantInternalAccessor<Quat> {
+ static _FORCE_INLINE_ const Quat &get(const Variant *v) { return *VariantInternal::get_quat(v); }
+ static _FORCE_INLINE_ void set(Variant *v, const Quat &p_value) { *VariantInternal::get_quat(v) = p_value; }
+};
+
+template <>
+struct VariantInternalAccessor<AABB> {
+ static _FORCE_INLINE_ const AABB &get(const Variant *v) { return *VariantInternal::get_aabb(v); }
+ static _FORCE_INLINE_ void set(Variant *v, const AABB &p_value) { *VariantInternal::get_aabb(v) = p_value; }
+};
+
+template <>
+struct VariantInternalAccessor<Basis> {
+ static _FORCE_INLINE_ const Basis &get(const Variant *v) { return *VariantInternal::get_basis(v); }
+ static _FORCE_INLINE_ void set(Variant *v, const Basis &p_value) { *VariantInternal::get_basis(v) = p_value; }
+};
+
+template <>
+struct VariantInternalAccessor<Color> {
+ static _FORCE_INLINE_ const Color &get(const Variant *v) { return *VariantInternal::get_color(v); }
+ static _FORCE_INLINE_ void set(Variant *v, const Color &p_value) { *VariantInternal::get_color(v) = p_value; }
+};
+
+template <>
+struct VariantInternalAccessor<StringName> {
+ static _FORCE_INLINE_ const StringName &get(const Variant *v) { return *VariantInternal::get_string_name(v); }
+ static _FORCE_INLINE_ void set(Variant *v, const StringName &p_value) { *VariantInternal::get_string_name(v) = p_value; }
+};
+
+template <>
+struct VariantInternalAccessor<NodePath> {
+ static _FORCE_INLINE_ const NodePath &get(const Variant *v) { return *VariantInternal::get_node_path(v); }
+ static _FORCE_INLINE_ void set(Variant *v, const NodePath &p_value) { *VariantInternal::get_node_path(v) = p_value; }
+};
+
+template <>
+struct VariantInternalAccessor<::RID> {
+ static _FORCE_INLINE_ const ::RID &get(const Variant *v) { return *VariantInternal::get_rid(v); }
+ static _FORCE_INLINE_ void set(Variant *v, const ::RID &p_value) { *VariantInternal::get_rid(v) = p_value; }
+};
+
+template <>
+struct VariantInternalAccessor<Callable> {
+ static _FORCE_INLINE_ const Callable &get(const Variant *v) { return *VariantInternal::get_callable(v); }
+ static _FORCE_INLINE_ void set(Variant *v, const Callable &p_value) { *VariantInternal::get_callable(v) = p_value; }
+};
+
+template <>
+struct VariantInternalAccessor<Signal> {
+ static _FORCE_INLINE_ const Signal &get(const Variant *v) { return *VariantInternal::get_signal(v); }
+ static _FORCE_INLINE_ void set(Variant *v, const Signal &p_value) { *VariantInternal::get_signal(v) = p_value; }
+};
+
+template <>
+struct VariantInternalAccessor<Dictionary> {
+ static _FORCE_INLINE_ const Dictionary &get(const Variant *v) { return *VariantInternal::get_dictionary(v); }
+ static _FORCE_INLINE_ void set(Variant *v, const Dictionary &p_value) { *VariantInternal::get_dictionary(v) = p_value; }
+};
+
+template <>
+struct VariantInternalAccessor<Array> {
+ static _FORCE_INLINE_ const Array &get(const Variant *v) { return *VariantInternal::get_array(v); }
+ static _FORCE_INLINE_ void set(Variant *v, const Array &p_value) { *VariantInternal::get_array(v) = p_value; }
+};
+
+template <>
+struct VariantInternalAccessor<PackedByteArray> {
+ static _FORCE_INLINE_ const PackedByteArray &get(const Variant *v) { return *VariantInternal::get_byte_array(v); }
+ static _FORCE_INLINE_ void set(Variant *v, const PackedByteArray &p_value) { *VariantInternal::get_byte_array(v) = p_value; }
+};
+
+template <>
+struct VariantInternalAccessor<PackedInt32Array> {
+ static _FORCE_INLINE_ const PackedInt32Array &get(const Variant *v) { return *VariantInternal::get_int32_array(v); }
+ static _FORCE_INLINE_ void set(Variant *v, const PackedInt32Array &p_value) { *VariantInternal::get_int32_array(v) = p_value; }
+};
+
+template <>
+struct VariantInternalAccessor<PackedInt64Array> {
+ static _FORCE_INLINE_ const PackedInt64Array &get(const Variant *v) { return *VariantInternal::get_int64_array(v); }
+ static _FORCE_INLINE_ void set(Variant *v, const PackedInt64Array &p_value) { *VariantInternal::get_int64_array(v) = p_value; }
+};
+
+template <>
+struct VariantInternalAccessor<PackedFloat32Array> {
+ static _FORCE_INLINE_ const PackedFloat32Array &get(const Variant *v) { return *VariantInternal::get_float32_array(v); }
+ static _FORCE_INLINE_ void set(Variant *v, const PackedFloat32Array &p_value) { *VariantInternal::get_float32_array(v) = p_value; }
+};
+
+template <>
+struct VariantInternalAccessor<PackedFloat64Array> {
+ static _FORCE_INLINE_ const PackedFloat64Array &get(const Variant *v) { return *VariantInternal::get_float64_array(v); }
+ static _FORCE_INLINE_ void set(Variant *v, const PackedFloat64Array &p_value) { *VariantInternal::get_float64_array(v) = p_value; }
+};
+
+template <>
+struct VariantInternalAccessor<PackedStringArray> {
+ static _FORCE_INLINE_ const PackedStringArray &get(const Variant *v) { return *VariantInternal::get_string_array(v); }
+ static _FORCE_INLINE_ void set(Variant *v, const PackedStringArray &p_value) { *VariantInternal::get_string_array(v) = p_value; }
+};
+
+template <>
+struct VariantInternalAccessor<PackedVector2Array> {
+ static _FORCE_INLINE_ const PackedVector2Array &get(const Variant *v) { return *VariantInternal::get_vector2_array(v); }
+ static _FORCE_INLINE_ void set(Variant *v, const PackedVector2Array &p_value) { *VariantInternal::get_vector2_array(v) = p_value; }
+};
+
+template <>
+struct VariantInternalAccessor<PackedVector3Array> {
+ static _FORCE_INLINE_ const PackedVector3Array &get(const Variant *v) { return *VariantInternal::get_vector3_array(v); }
+ static _FORCE_INLINE_ void set(Variant *v, const PackedVector3Array &p_value) { *VariantInternal::get_vector3_array(v) = p_value; }
+};
+
+template <>
+struct VariantInternalAccessor<PackedColorArray> {
+ static _FORCE_INLINE_ const PackedColorArray &get(const Variant *v) { return *VariantInternal::get_color_array(v); }
+ static _FORCE_INLINE_ void set(Variant *v, const PackedColorArray &p_value) { *VariantInternal::get_color_array(v) = p_value; }
+};
+
+template <>
+struct VariantInternalAccessor<Object *> {
+ static _FORCE_INLINE_ Object *get(const Variant *v) { return const_cast<Object *>(*VariantInternal::get_object(v)); }
+ static _FORCE_INLINE_ void set(Variant *v, const Object *p_value) { *VariantInternal::get_object(v) = const_cast<Object *>(p_value); }
+};
+
+template <>
+struct VariantInternalAccessor<Variant> {
+ static _FORCE_INLINE_ Variant &get(Variant *v) { return *v; }
+ static _FORCE_INLINE_ const Variant &get(const Variant *v) { return *v; }
+ static _FORCE_INLINE_ void set(Variant *v, const Variant &p_value) { *v = p_value; }
+};
+
+template <>
+struct VariantInternalAccessor<Vector<Variant>> {
+ static _FORCE_INLINE_ Vector<Variant> get(const Variant *v) {
+ Vector<Variant> ret;
+ int s = VariantInternal::get_array(v)->size();
+ ret.resize(s);
+ for (int i = 0; i < s; i++) {
+ ret.write[i] = VariantInternal::get_array(v)->get(i);
+ }
+
+ return ret;
+ }
+ static _FORCE_INLINE_ void set(Variant *v, const Vector<Variant> &p_value) {
+ int s = p_value.size();
+ VariantInternal::get_array(v)->resize(s);
+ for (int i = 0; i < s; i++) {
+ VariantInternal::get_array(v)->set(i, p_value[i]);
+ }
+ }
+};
+
+template <class T>
+struct VariantInitializer {
+};
+
+template <>
+struct VariantInitializer<bool> {
+ static _FORCE_INLINE_ void init(Variant *v) { VariantInternal::init_generic<bool>(v); }
+};
+
+#define INITIALIZER_INT(m_type) \
+ template <> \
+ struct VariantInitializer<m_type> { \
+ static _FORCE_INLINE_ void init(Variant *v) { VariantInternal::init_generic<int64_t>(v); } \
+ };
+
+INITIALIZER_INT(uint8_t)
+INITIALIZER_INT(int8_t)
+INITIALIZER_INT(uint16_t)
+INITIALIZER_INT(int16_t)
+INITIALIZER_INT(uint32_t)
+INITIALIZER_INT(int32_t)
+INITIALIZER_INT(uint64_t)
+INITIALIZER_INT(int64_t)
+INITIALIZER_INT(char32_t)
+INITIALIZER_INT(Error)
+INITIALIZER_INT(ObjectID)
+
+template <>
+struct VariantInitializer<double> {
+ static _FORCE_INLINE_ void init(Variant *v) { VariantInternal::init_generic<double>(v); }
+};
+
+template <>
+struct VariantInitializer<float> {
+ static _FORCE_INLINE_ void init(Variant *v) { VariantInternal::init_generic<double>(v); }
+};
+
+template <>
+struct VariantInitializer<String> {
+ static _FORCE_INLINE_ void init(Variant *v) { VariantInternal::init_string(v); }
+};
+
+template <>
+struct VariantInitializer<Vector2> {
+ static _FORCE_INLINE_ void init(Variant *v) { VariantInternal::init_generic<Vector2>(v); }
+};
+
+template <>
+struct VariantInitializer<Vector2i> {
+ static _FORCE_INLINE_ void init(Variant *v) { VariantInternal::init_generic<Vector2i>(v); }
+};
+
+template <>
+struct VariantInitializer<Rect2> {
+ static _FORCE_INLINE_ void init(Variant *v) { VariantInternal::init_generic<Rect2>(v); }
+};
+
+template <>
+struct VariantInitializer<Rect2i> {
+ static _FORCE_INLINE_ void init(Variant *v) { VariantInternal::init_generic<Rect2i>(v); }
+};
+
+template <>
+struct VariantInitializer<Vector3> {
+ static _FORCE_INLINE_ void init(Variant *v) { VariantInternal::init_generic<Vector3>(v); }
+};
+
+template <>
+struct VariantInitializer<Vector3i> {
+ static _FORCE_INLINE_ void init(Variant *v) { VariantInternal::init_generic<Vector3i>(v); }
+};
+
+template <>
+struct VariantInitializer<Transform2D> {
+ static _FORCE_INLINE_ void init(Variant *v) { VariantInternal::init_transform2d(v); }
+};
+
+template <>
+struct VariantInitializer<Plane> {
+ static _FORCE_INLINE_ void init(Variant *v) { VariantInternal::init_generic<Plane>(v); }
+};
+
+template <>
+struct VariantInitializer<Quat> {
+ static _FORCE_INLINE_ void init(Variant *v) { VariantInternal::init_generic<Quat>(v); }
+};
+
+template <>
+struct VariantInitializer<AABB> {
+ static _FORCE_INLINE_ void init(Variant *v) { VariantInternal::init_aabb(v); }
+};
+
+template <>
+struct VariantInitializer<Basis> {
+ static _FORCE_INLINE_ void init(Variant *v) { VariantInternal::init_basis(v); }
+};
+
+template <>
+struct VariantInitializer<Transform> {
+ static _FORCE_INLINE_ void init(Variant *v) { VariantInternal::init_transform(v); }
+};
+
+template <>
+struct VariantInitializer<Color> {
+ static _FORCE_INLINE_ void init(Variant *v) { VariantInternal::init_generic<Color>(v); }
+};
+
+template <>
+struct VariantInitializer<StringName> {
+ static _FORCE_INLINE_ void init(Variant *v) { VariantInternal::init_string_name(v); }
+};
+
+template <>
+struct VariantInitializer<NodePath> {
+ static _FORCE_INLINE_ void init(Variant *v) { VariantInternal::init_node_path(v); }
+};
+
+template <>
+struct VariantInitializer<::RID> {
+ static _FORCE_INLINE_ void init(Variant *v) { VariantInternal::init_generic<::RID>(v); }
+};
+
+template <>
+struct VariantInitializer<Callable> {
+ static _FORCE_INLINE_ void init(Variant *v) { VariantInternal::init_callable(v); }
+};
+
+template <>
+struct VariantInitializer<Signal> {
+ static _FORCE_INLINE_ void init(Variant *v) { VariantInternal::init_signal(v); }
+};
+
+template <>
+struct VariantInitializer<Dictionary> {
+ static _FORCE_INLINE_ void init(Variant *v) { VariantInternal::init_dictionary(v); }
+};
+
+template <>
+struct VariantInitializer<Array> {
+ static _FORCE_INLINE_ void init(Variant *v) { VariantInternal::init_array(v); }
+};
+
+template <>
+struct VariantInitializer<PackedByteArray> {
+ static _FORCE_INLINE_ void init(Variant *v) { VariantInternal::init_byte_array(v); }
+};
+
+template <>
+struct VariantInitializer<PackedInt32Array> {
+ static _FORCE_INLINE_ void init(Variant *v) { VariantInternal::init_int32_array(v); }
+};
+
+template <>
+struct VariantInitializer<PackedInt64Array> {
+ static _FORCE_INLINE_ void init(Variant *v) { VariantInternal::init_int64_array(v); }
+};
+
+template <>
+struct VariantInitializer<PackedFloat32Array> {
+ static _FORCE_INLINE_ void init(Variant *v) { VariantInternal::init_float32_array(v); }
+};
+
+template <>
+struct VariantInitializer<PackedFloat64Array> {
+ static _FORCE_INLINE_ void init(Variant *v) { VariantInternal::init_float64_array(v); }
+};
+
+template <>
+struct VariantInitializer<PackedStringArray> {
+ static _FORCE_INLINE_ void init(Variant *v) { VariantInternal::init_string_array(v); }
+};
+
+template <>
+struct VariantInitializer<PackedVector2Array> {
+ static _FORCE_INLINE_ void init(Variant *v) { VariantInternal::init_vector2_array(v); }
+};
+
+template <>
+struct VariantInitializer<PackedVector3Array> {
+ static _FORCE_INLINE_ void init(Variant *v) { VariantInternal::init_vector3_array(v); }
+};
+
+template <>
+struct VariantInitializer<PackedColorArray> {
+ static _FORCE_INLINE_ void init(Variant *v) { VariantInternal::init_color_array(v); }
+};
+
+template <class T>
+struct VariantZeroAssigner {
+};
+
+template <>
+struct VariantZeroAssigner<bool> {
+ static _FORCE_INLINE_ void zero(Variant *v) { *VariantInternal::get_bool(v) = false; }
+};
+
+template <>
+struct VariantZeroAssigner<int64_t> {
+ static _FORCE_INLINE_ void zero(Variant *v) { *VariantInternal::get_int(v) = 0; }
+};
+
+template <>
+struct VariantZeroAssigner<double> {
+ static _FORCE_INLINE_ void zero(Variant *v) { *VariantInternal::get_float(v) = 0.0; }
+};
+
+template <>
+struct VariantZeroAssigner<float> {
+ static _FORCE_INLINE_ void zero(Variant *v) { *VariantInternal::get_float(v) = 0.0; }
+};
+
+template <>
+struct VariantZeroAssigner<String> {
+ static _FORCE_INLINE_ void zero(Variant *v) {}
+};
+
+template <>
+struct VariantZeroAssigner<Vector2> {
+ static _FORCE_INLINE_ void zero(Variant *v) { *VariantInternal::get_vector2(v) = Vector2(); }
+};
+
+template <>
+struct VariantZeroAssigner<Vector2i> {
+ static _FORCE_INLINE_ void zero(Variant *v) { *VariantInternal::get_vector2i(v) = Vector2i(); }
+};
+
+template <>
+struct VariantZeroAssigner<Rect2> {
+ static _FORCE_INLINE_ void zero(Variant *v) { *VariantInternal::get_rect2(v) = Rect2(); }
+};
+
+template <>
+struct VariantZeroAssigner<Rect2i> {
+ static _FORCE_INLINE_ void zero(Variant *v) { *VariantInternal::get_rect2i(v) = Rect2i(); }
+};
+
+template <>
+struct VariantZeroAssigner<Vector3> {
+ static _FORCE_INLINE_ void zero(Variant *v) { *VariantInternal::get_vector3(v) = Vector3(); }
+};
+
+template <>
+struct VariantZeroAssigner<Vector3i> {
+ static _FORCE_INLINE_ void zero(Variant *v) { *VariantInternal::get_vector3i(v) = Vector3i(); }
+};
+
+template <>
+struct VariantZeroAssigner<Transform2D> {
+ static _FORCE_INLINE_ void zero(Variant *v) { *VariantInternal::get_transform2d(v) = Transform2D(); }
+};
+
+template <>
+struct VariantZeroAssigner<Plane> {
+ static _FORCE_INLINE_ void zero(Variant *v) { *VariantInternal::get_plane(v) = Plane(); }
+};
+
+template <>
+struct VariantZeroAssigner<Quat> {
+ static _FORCE_INLINE_ void zero(Variant *v) { *VariantInternal::get_quat(v) = Quat(); }
+};
+
+template <>
+struct VariantZeroAssigner<AABB> {
+ static _FORCE_INLINE_ void zero(Variant *v) { *VariantInternal::get_aabb(v) = AABB(); }
+};
+
+template <>
+struct VariantZeroAssigner<Basis> {
+ static _FORCE_INLINE_ void zero(Variant *v) { *VariantInternal::get_basis(v) = Basis(); }
+};
+
+template <>
+struct VariantZeroAssigner<Transform> {
+ static _FORCE_INLINE_ void zero(Variant *v) { *VariantInternal::get_transform(v) = Transform(); }
+};
+
+template <>
+struct VariantZeroAssigner<Color> {
+ static _FORCE_INLINE_ void zero(Variant *v) { *VariantInternal::get_color(v) = Color(); }
+};
+
+template <>
+struct VariantZeroAssigner<StringName> {
+ static _FORCE_INLINE_ void zero(Variant *v) {}
+};
+
+template <>
+struct VariantZeroAssigner<NodePath> {
+ static _FORCE_INLINE_ void zero(Variant *v) {}
+};
+
+template <>
+struct VariantZeroAssigner<::RID> {
+ static _FORCE_INLINE_ void zero(Variant *v) { *VariantInternal::get_rid(v) = RID(); }
+};
+
+template <>
+struct VariantZeroAssigner<Callable> {
+ static _FORCE_INLINE_ void zero(Variant *v) {}
+};
+
+template <>
+struct VariantZeroAssigner<Signal> {
+ static _FORCE_INLINE_ void zero(Variant *v) {}
+};
+
+template <>
+struct VariantZeroAssigner<Dictionary> {
+ static _FORCE_INLINE_ void zero(Variant *v) {}
+};
+
+template <>
+struct VariantZeroAssigner<Array> {
+ static _FORCE_INLINE_ void zero(Variant *v) {}
+};
+
+template <>
+struct VariantZeroAssigner<PackedByteArray> {
+ static _FORCE_INLINE_ void zero(Variant *v) {}
+};
+
+template <>
+struct VariantZeroAssigner<PackedInt32Array> {
+ static _FORCE_INLINE_ void zero(Variant *v) {}
+};
+
+template <>
+struct VariantZeroAssigner<PackedInt64Array> {
+ static _FORCE_INLINE_ void zero(Variant *v) {}
+};
+
+template <>
+struct VariantZeroAssigner<PackedFloat32Array> {
+ static _FORCE_INLINE_ void zero(Variant *v) {}
+};
+
+template <>
+struct VariantZeroAssigner<PackedFloat64Array> {
+ static _FORCE_INLINE_ void zero(Variant *v) {}
+};
+
+template <>
+struct VariantZeroAssigner<PackedStringArray> {
+ static _FORCE_INLINE_ void zero(Variant *v) {}
+};
+
+template <>
+struct VariantZeroAssigner<PackedVector2Array> {
+ static _FORCE_INLINE_ void zero(Variant *v) {}
+};
+
+template <>
+struct VariantZeroAssigner<PackedVector3Array> {
+ static _FORCE_INLINE_ void zero(Variant *v) {}
+};
+
+template <>
+struct VariantZeroAssigner<PackedColorArray> {
+ static _FORCE_INLINE_ void zero(Variant *v) {}
+};
+
+template <class T>
+struct VariantTypeChanger {
+ static _FORCE_INLINE_ void change(Variant *v) {
+ if (v->get_type() != GetTypeInfo<T>::VARIANT_TYPE || GetTypeInfo<T>::VARIANT_TYPE >= Variant::PACKED_BYTE_ARRAY) { //second condition removed by optimizer
+ VariantInternal::clear(v);
+ VariantInitializer<T>::init(v);
+ }
+ }
+ static _FORCE_INLINE_ void change_and_reset(Variant *v) {
+ if (v->get_type() != GetTypeInfo<T>::VARIANT_TYPE || GetTypeInfo<T>::VARIANT_TYPE >= Variant::PACKED_BYTE_ARRAY) { //second condition removed by optimizer
+ VariantInternal::clear(v);
+ VariantInitializer<T>::init(v);
+ }
+
+ VariantZeroAssigner<T>::zero(v);
+ }
+};
+
+template <class T>
+struct VariantTypeAdjust {
+ _FORCE_INLINE_ static void adjust(Variant *r_ret) {
+ VariantTypeChanger<typename GetSimpleTypeT<T>::type_t>::change(r_ret);
+ }
+};
+
+template <>
+struct VariantTypeAdjust<Variant> {
+ _FORCE_INLINE_ static void adjust(Variant *r_ret) {
+ // Do nothing for variant.
+ }
+};
+
+template <>
+struct VariantTypeAdjust<Object *> {
+ _FORCE_INLINE_ static void adjust(Variant *r_ret) {
+ VariantInternal::clear(r_ret);
+ *r_ret = (Object *)nullptr;
+ }
+};
+
+#endif // VARIANT_INTERNAL_H
diff --git a/core/variant/variant_op.cpp b/core/variant/variant_op.cpp
new file mode 100644
index 0000000000..07b024ecb4
--- /dev/null
+++ b/core/variant/variant_op.cpp
@@ -0,0 +1,2015 @@
+/*************************************************************************/
+/* variant_op.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* 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. */
+/*************************************************************************/
+
+#include "variant.h"
+
+#include "core/core_string_names.h"
+#include "core/debugger/engine_debugger.h"
+#include "core/object/class_db.h"
+
+template <class R, class A, class B>
+class OperatorEvaluatorAdd {
+public:
+ static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
+ const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left);
+ const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right);
+ *r_ret = a + b;
+ r_valid = true;
+ }
+ static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
+ VariantTypeChanger<R>::change(r_ret);
+ *VariantGetInternalPtr<R>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) + *VariantGetInternalPtr<B>::get_ptr(right);
+ }
+ static void ptr_evaluate(const void *left, const void *right, void *r_ret) {
+ PtrToArg<R>::encode(PtrToArg<A>::convert(left) + PtrToArg<B>::convert(right), r_ret);
+ }
+ static Variant::Type get_return_type() { return GetTypeInfo<R>::VARIANT_TYPE; }
+};
+
+template <class R, class A, class B>
+class OperatorEvaluatorSub {
+public:
+ static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
+ const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left);
+ const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right);
+ *r_ret = a - b;
+ r_valid = true;
+ }
+ static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
+ VariantTypeChanger<R>::change(r_ret);
+ *VariantGetInternalPtr<R>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) - *VariantGetInternalPtr<B>::get_ptr(right);
+ }
+ static void ptr_evaluate(const void *left, const void *right, void *r_ret) {
+ PtrToArg<R>::encode(PtrToArg<A>::convert(left) - PtrToArg<B>::convert(right), r_ret);
+ }
+ static Variant::Type get_return_type() { return GetTypeInfo<R>::VARIANT_TYPE; }
+};
+
+template <class R, class A, class B>
+class OperatorEvaluatorMul {
+public:
+ static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
+ const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left);
+ const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right);
+ *r_ret = a * b;
+ r_valid = true;
+ }
+ static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
+ VariantTypeChanger<R>::change(r_ret);
+ *VariantGetInternalPtr<R>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) * *VariantGetInternalPtr<B>::get_ptr(right);
+ }
+ static void ptr_evaluate(const void *left, const void *right, void *r_ret) {
+ PtrToArg<R>::encode(PtrToArg<A>::convert(left) * PtrToArg<B>::convert(right), r_ret);
+ }
+ static Variant::Type get_return_type() { return GetTypeInfo<R>::VARIANT_TYPE; }
+};
+
+template <class R, class A, class B>
+class OperatorEvaluatorXForm {
+public:
+ static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
+ const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left);
+ const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right);
+ *r_ret = a.xform(b);
+ r_valid = true;
+ }
+ static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
+ VariantTypeChanger<R>::change(r_ret);
+ *VariantGetInternalPtr<R>::get_ptr(r_ret) = VariantGetInternalPtr<A>::get_ptr(left)->xform(*VariantGetInternalPtr<B>::get_ptr(right));
+ }
+ static void ptr_evaluate(const void *left, const void *right, void *r_ret) {
+ PtrToArg<R>::encode(PtrToArg<A>::convert(left).xform(PtrToArg<B>::convert(right)), r_ret);
+ }
+ static Variant::Type get_return_type() { return GetTypeInfo<R>::VARIANT_TYPE; }
+};
+
+template <class R, class A, class B>
+class OperatorEvaluatorXFormInv {
+public:
+ static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
+ const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left);
+ const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right);
+ *r_ret = b.xform_inv(a);
+ r_valid = true;
+ }
+ static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
+ VariantTypeChanger<R>::change(r_ret);
+ *VariantGetInternalPtr<R>::get_ptr(r_ret) = VariantGetInternalPtr<B>::get_ptr(right)->xform_inv(*VariantGetInternalPtr<A>::get_ptr(left));
+ }
+ static void ptr_evaluate(const void *left, const void *right, void *r_ret) {
+ PtrToArg<R>::encode(PtrToArg<B>::convert(right).xform_inv(PtrToArg<A>::convert(left)), r_ret);
+ }
+ static Variant::Type get_return_type() { return GetTypeInfo<R>::VARIANT_TYPE; }
+};
+
+template <class R, class A, class B>
+class OperatorEvaluatorDiv {
+public:
+ static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
+ const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left);
+ const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right);
+ *r_ret = a / b;
+ r_valid = true;
+ }
+ static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
+ VariantTypeChanger<R>::change(r_ret);
+ *VariantGetInternalPtr<R>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) / *VariantGetInternalPtr<B>::get_ptr(right);
+ }
+ static void ptr_evaluate(const void *left, const void *right, void *r_ret) {
+ PtrToArg<R>::encode(PtrToArg<A>::convert(left) / PtrToArg<B>::convert(right), r_ret);
+ }
+ static Variant::Type get_return_type() { return GetTypeInfo<R>::VARIANT_TYPE; }
+};
+
+template <class R, class A, class B>
+class OperatorEvaluatorDivNZ {
+public:
+ static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
+ const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left);
+ const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right);
+ if (b == 0) {
+ r_valid = false;
+ *r_ret = "Division by zero error";
+ return;
+ }
+ *r_ret = a / b;
+ r_valid = true;
+ }
+ static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
+ VariantTypeChanger<R>::change(r_ret);
+ *VariantGetInternalPtr<R>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) / *VariantGetInternalPtr<B>::get_ptr(right);
+ }
+ static void ptr_evaluate(const void *left, const void *right, void *r_ret) {
+ PtrToArg<R>::encode(PtrToArg<A>::convert(left) / PtrToArg<B>::convert(right), r_ret);
+ }
+ static Variant::Type get_return_type() { return GetTypeInfo<R>::VARIANT_TYPE; }
+};
+
+template <class R, class A, class B>
+class OperatorEvaluatorMod {
+public:
+ static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
+ const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left);
+ const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right);
+ *r_ret = a % b;
+ r_valid = true;
+ }
+ static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
+ VariantTypeChanger<R>::change(r_ret);
+ *VariantGetInternalPtr<R>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) % *VariantGetInternalPtr<B>::get_ptr(right);
+ }
+ static void ptr_evaluate(const void *left, const void *right, void *r_ret) {
+ PtrToArg<R>::encode(PtrToArg<A>::convert(left) % PtrToArg<B>::convert(right), r_ret);
+ }
+ static Variant::Type get_return_type() { return GetTypeInfo<R>::VARIANT_TYPE; }
+};
+
+template <class R, class A, class B>
+class OperatorEvaluatorModNZ {
+public:
+ static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
+ const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left);
+ const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right);
+ if (b == 0) {
+ r_valid = false;
+ *r_ret = "Module by zero error";
+ return;
+ }
+ *r_ret = a % b;
+ r_valid = true;
+ }
+ static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
+ VariantTypeChanger<R>::change(r_ret);
+ *VariantGetInternalPtr<R>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) % *VariantGetInternalPtr<B>::get_ptr(right);
+ }
+ static void ptr_evaluate(const void *left, const void *right, void *r_ret) {
+ PtrToArg<R>::encode(PtrToArg<A>::convert(left) % PtrToArg<B>::convert(right), r_ret);
+ }
+ static Variant::Type get_return_type() { return GetTypeInfo<R>::VARIANT_TYPE; }
+};
+
+template <class R, class A>
+class OperatorEvaluatorNeg {
+public:
+ static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
+ const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left);
+ *r_ret = -a;
+ r_valid = true;
+ }
+ static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
+ VariantTypeChanger<R>::change(r_ret);
+ *VariantGetInternalPtr<R>::get_ptr(r_ret) = -*VariantGetInternalPtr<A>::get_ptr(left);
+ }
+ static void ptr_evaluate(const void *left, const void *right, void *r_ret) {
+ PtrToArg<R>::encode(-PtrToArg<A>::convert(left), r_ret);
+ }
+ static Variant::Type get_return_type() { return GetTypeInfo<R>::VARIANT_TYPE; }
+};
+
+template <class R, class A>
+class OperatorEvaluatorPos {
+public:
+ static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
+ const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left);
+ *r_ret = a;
+ r_valid = true;
+ }
+ static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
+ VariantTypeChanger<R>::change(r_ret);
+ *VariantGetInternalPtr<R>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left);
+ }
+ static void ptr_evaluate(const void *left, const void *right, void *r_ret) {
+ PtrToArg<R>::encode(PtrToArg<A>::convert(left), r_ret);
+ }
+ static Variant::Type get_return_type() { return GetTypeInfo<R>::VARIANT_TYPE; }
+};
+
+template <class R, class A, class B>
+class OperatorEvaluatorShiftLeft {
+public:
+ static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
+ const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left);
+ const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right);
+ *r_ret = a << b;
+ r_valid = true;
+ }
+ static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
+ VariantTypeChanger<R>::change(r_ret);
+ *VariantGetInternalPtr<R>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) << *VariantGetInternalPtr<B>::get_ptr(right);
+ }
+ static void ptr_evaluate(const void *left, const void *right, void *r_ret) {
+ PtrToArg<R>::encode(PtrToArg<A>::convert(left) << PtrToArg<B>::convert(right), r_ret);
+ }
+ static Variant::Type get_return_type() { return GetTypeInfo<R>::VARIANT_TYPE; }
+};
+
+template <class R, class A, class B>
+class OperatorEvaluatorShiftRight {
+public:
+ static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
+ const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left);
+ const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right);
+ *r_ret = a >> b;
+ r_valid = true;
+ }
+ static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
+ VariantTypeChanger<R>::change(r_ret);
+ *VariantGetInternalPtr<R>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) >> *VariantGetInternalPtr<B>::get_ptr(right);
+ }
+ static void ptr_evaluate(const void *left, const void *right, void *r_ret) {
+ PtrToArg<R>::encode(PtrToArg<A>::convert(left) >> PtrToArg<B>::convert(right), r_ret);
+ }
+ static Variant::Type get_return_type() { return GetTypeInfo<R>::VARIANT_TYPE; }
+};
+
+template <class R, class A, class B>
+class OperatorEvaluatorBitOr {
+public:
+ static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
+ const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left);
+ const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right);
+ *r_ret = a | b;
+ r_valid = true;
+ }
+ static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
+ VariantTypeChanger<R>::change(r_ret);
+ *VariantGetInternalPtr<R>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) | *VariantGetInternalPtr<B>::get_ptr(right);
+ }
+ static void ptr_evaluate(const void *left, const void *right, void *r_ret) {
+ PtrToArg<R>::encode(PtrToArg<A>::convert(left) | PtrToArg<B>::convert(right), r_ret);
+ }
+ static Variant::Type get_return_type() { return GetTypeInfo<R>::VARIANT_TYPE; }
+};
+
+template <class R, class A, class B>
+class OperatorEvaluatorBitAnd {
+public:
+ static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
+ const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left);
+ const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right);
+ *r_ret = a & b;
+ r_valid = true;
+ }
+ static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
+ *VariantGetInternalPtr<R>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) & *VariantGetInternalPtr<B>::get_ptr(right);
+ }
+ static void ptr_evaluate(const void *left, const void *right, void *r_ret) {
+ PtrToArg<R>::encode(PtrToArg<A>::convert(left) & PtrToArg<B>::convert(right), r_ret);
+ }
+ static Variant::Type get_return_type() { return GetTypeInfo<R>::VARIANT_TYPE; }
+};
+
+template <class R, class A, class B>
+class OperatorEvaluatorBitXor {
+public:
+ static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
+ const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left);
+ const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right);
+ *r_ret = a ^ b;
+ r_valid = true;
+ }
+ static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
+ VariantTypeChanger<R>::change(r_ret);
+ *VariantGetInternalPtr<R>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) ^ *VariantGetInternalPtr<B>::get_ptr(right);
+ }
+ static void ptr_evaluate(const void *left, const void *right, void *r_ret) {
+ PtrToArg<R>::encode(PtrToArg<A>::convert(left) ^ PtrToArg<B>::convert(right), r_ret);
+ }
+ static Variant::Type get_return_type() { return GetTypeInfo<R>::VARIANT_TYPE; }
+};
+
+template <class R, class A>
+class OperatorEvaluatorBitNeg {
+public:
+ static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
+ const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left);
+ *r_ret = ~a;
+ r_valid = true;
+ }
+ static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
+ VariantTypeChanger<R>::change(r_ret);
+ *VariantGetInternalPtr<R>::get_ptr(r_ret) = ~*VariantGetInternalPtr<A>::get_ptr(left);
+ }
+ static void ptr_evaluate(const void *left, const void *right, void *r_ret) {
+ PtrToArg<R>::encode(~PtrToArg<A>::convert(left), r_ret);
+ }
+ static Variant::Type get_return_type() { return GetTypeInfo<R>::VARIANT_TYPE; }
+};
+
+template <class A, class B>
+class OperatorEvaluatorEqual {
+public:
+ static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
+ const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left);
+ const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right);
+ *r_ret = a == b;
+ r_valid = true;
+ }
+ static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
+ VariantTypeChanger<bool>::change(r_ret);
+ *VariantGetInternalPtr<bool>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) == *VariantGetInternalPtr<B>::get_ptr(right);
+ }
+ static void ptr_evaluate(const void *left, const void *right, void *r_ret) {
+ PtrToArg<bool>::encode(PtrToArg<A>::convert(left) == PtrToArg<B>::convert(right), r_ret);
+ }
+ static Variant::Type get_return_type() { return Variant::BOOL; }
+};
+
+class OperatorEvaluatorEqualObject {
+public:
+ static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
+ const Object *a = p_left.get_validated_object();
+ const Object *b = p_right.get_validated_object();
+ *r_ret = a == b;
+ r_valid = true;
+ }
+ static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
+ const Object *a = left->get_validated_object();
+ const Object *b = right->get_validated_object();
+ VariantTypeChanger<bool>::change(r_ret);
+ *VariantGetInternalPtr<bool>::get_ptr(r_ret) = a == b;
+ }
+ static void ptr_evaluate(const void *left, const void *right, void *r_ret) {
+ PtrToArg<bool>::encode(PtrToArg<Object *>::convert(left) == PtrToArg<Object *>::convert(right), r_ret);
+ }
+ static Variant::Type get_return_type() { return Variant::BOOL; }
+};
+
+class OperatorEvaluatorEqualObjectNil {
+public:
+ static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
+ const Object *a = p_left.get_validated_object();
+ *r_ret = a == nullptr;
+ r_valid = true;
+ }
+ static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
+ const Object *a = left->get_validated_object();
+ VariantTypeChanger<bool>::change(r_ret);
+ *VariantGetInternalPtr<bool>::get_ptr(r_ret) = a == nullptr;
+ }
+ static void ptr_evaluate(const void *left, const void *right, void *r_ret) {
+ PtrToArg<bool>::encode(PtrToArg<Object *>::convert(left) == nullptr, r_ret);
+ }
+ static Variant::Type get_return_type() { return Variant::BOOL; }
+};
+
+class OperatorEvaluatorEqualNilObject {
+public:
+ static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
+ const Object *b = p_right.get_validated_object();
+ *r_ret = nullptr == b;
+ r_valid = true;
+ }
+ static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
+ const Object *b = right->get_validated_object();
+ VariantTypeChanger<bool>::change(r_ret);
+ *VariantGetInternalPtr<bool>::get_ptr(r_ret) = nullptr == b;
+ }
+ static void ptr_evaluate(const void *left, const void *right, void *r_ret) {
+ PtrToArg<bool>::encode(nullptr == PtrToArg<Object *>::convert(right), r_ret);
+ }
+ static Variant::Type get_return_type() { return Variant::BOOL; }
+};
+
+template <class A, class B>
+class OperatorEvaluatorNotEqual {
+public:
+ static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
+ const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left);
+ const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right);
+ *r_ret = a != b;
+ r_valid = true;
+ }
+ static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
+ VariantTypeChanger<bool>::change(r_ret);
+ *VariantGetInternalPtr<bool>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) != *VariantGetInternalPtr<B>::get_ptr(right);
+ }
+ static void ptr_evaluate(const void *left, const void *right, void *r_ret) {
+ PtrToArg<bool>::encode(PtrToArg<A>::convert(left) != PtrToArg<B>::convert(right), r_ret);
+ }
+ static Variant::Type get_return_type() { return Variant::BOOL; }
+};
+
+class OperatorEvaluatorNotEqualObject {
+public:
+ static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
+ Object *a = p_left.get_validated_object();
+ Object *b = p_right.get_validated_object();
+ *r_ret = a != b;
+ r_valid = true;
+ }
+ static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
+ Object *a = left->get_validated_object();
+ Object *b = right->get_validated_object();
+ VariantTypeChanger<bool>::change(r_ret);
+ *VariantGetInternalPtr<bool>::get_ptr(r_ret) = a != b;
+ }
+ static void ptr_evaluate(const void *left, const void *right, void *r_ret) {
+ PtrToArg<bool>::encode(PtrToArg<Object *>::convert(left) != PtrToArg<Object *>::convert(right), r_ret);
+ }
+ static Variant::Type get_return_type() { return Variant::BOOL; }
+};
+
+class OperatorEvaluatorNotEqualObjectNil {
+public:
+ static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
+ Object *a = p_left.get_validated_object();
+ *r_ret = a != nullptr;
+ r_valid = true;
+ }
+ static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
+ Object *a = left->get_validated_object();
+ VariantTypeChanger<bool>::change(r_ret);
+ *VariantGetInternalPtr<bool>::get_ptr(r_ret) = a != nullptr;
+ }
+ static void ptr_evaluate(const void *left, const void *right, void *r_ret) {
+ PtrToArg<bool>::encode(PtrToArg<Object *>::convert(left) != nullptr, r_ret);
+ }
+ static Variant::Type get_return_type() { return Variant::BOOL; }
+};
+
+class OperatorEvaluatorNotEqualNilObject {
+public:
+ static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
+ Object *b = p_right.get_validated_object();
+ *r_ret = nullptr != b;
+ r_valid = true;
+ }
+ static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
+ Object *b = right->get_validated_object();
+ VariantTypeChanger<bool>::change(r_ret);
+ *VariantGetInternalPtr<bool>::get_ptr(r_ret) = nullptr != b;
+ }
+ static void ptr_evaluate(const void *left, const void *right, void *r_ret) {
+ PtrToArg<bool>::encode(nullptr != PtrToArg<Object *>::convert(right), r_ret);
+ }
+ static Variant::Type get_return_type() { return Variant::BOOL; }
+};
+
+template <class A, class B>
+class OperatorEvaluatorLess {
+public:
+ static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
+ const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left);
+ const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right);
+ *r_ret = a < b;
+ r_valid = true;
+ }
+ static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
+ VariantTypeChanger<bool>::change(r_ret);
+ *VariantGetInternalPtr<bool>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) < *VariantGetInternalPtr<B>::get_ptr(right);
+ }
+ static void ptr_evaluate(const void *left, const void *right, void *r_ret) {
+ PtrToArg<bool>::encode(PtrToArg<A>::convert(left) < PtrToArg<B>::convert(right), r_ret);
+ }
+ static Variant::Type get_return_type() { return Variant::BOOL; }
+};
+
+template <class A, class B>
+class OperatorEvaluatorLessEqual {
+public:
+ static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
+ const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left);
+ const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right);
+ *r_ret = a <= b;
+ r_valid = true;
+ }
+ static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
+ VariantTypeChanger<bool>::change(r_ret);
+ *VariantGetInternalPtr<bool>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) <= *VariantGetInternalPtr<B>::get_ptr(right);
+ }
+ static void ptr_evaluate(const void *left, const void *right, void *r_ret) {
+ PtrToArg<bool>::encode(PtrToArg<A>::convert(left) <= PtrToArg<B>::convert(right), r_ret);
+ }
+ static Variant::Type get_return_type() { return Variant::BOOL; }
+};
+
+template <class A, class B>
+class OperatorEvaluatorGreater {
+public:
+ static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
+ const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left);
+ const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right);
+ *r_ret = a > b;
+ r_valid = true;
+ }
+ static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
+ VariantTypeChanger<bool>::change(r_ret);
+ *VariantGetInternalPtr<bool>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) > *VariantGetInternalPtr<B>::get_ptr(right);
+ }
+ static void ptr_evaluate(const void *left, const void *right, void *r_ret) {
+ PtrToArg<bool>::encode(PtrToArg<A>::convert(left) > PtrToArg<B>::convert(right), r_ret);
+ }
+ static Variant::Type get_return_type() { return Variant::BOOL; }
+};
+
+template <class A, class B>
+class OperatorEvaluatorGreaterEqual {
+public:
+ static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
+ const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left);
+ const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right);
+ *r_ret = a >= b;
+ r_valid = true;
+ }
+ static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
+ VariantTypeChanger<bool>::change(r_ret);
+ *VariantGetInternalPtr<bool>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) >= *VariantGetInternalPtr<B>::get_ptr(right);
+ }
+ static void ptr_evaluate(const void *left, const void *right, void *r_ret) {
+ PtrToArg<bool>::encode(PtrToArg<A>::convert(left) >= PtrToArg<B>::convert(right), r_ret);
+ }
+ static Variant::Type get_return_type() { return Variant::BOOL; }
+};
+
+template <class A, class B>
+class OperatorEvaluatorAnd {
+public:
+ static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
+ const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left);
+ const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right);
+ *r_ret = a && b;
+ r_valid = true;
+ }
+ static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
+ VariantTypeChanger<bool>::change(r_ret);
+ *VariantGetInternalPtr<bool>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) && *VariantGetInternalPtr<B>::get_ptr(right);
+ }
+ static void ptr_evaluate(const void *left, const void *right, void *r_ret) {
+ PtrToArg<bool>::encode(PtrToArg<A>::convert(left) && PtrToArg<B>::convert(right), r_ret);
+ }
+ static Variant::Type get_return_type() { return Variant::BOOL; }
+};
+
+template <class A, class B>
+class OperatorEvaluatorOr {
+public:
+ static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
+ const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left);
+ const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right);
+ *r_ret = a || b;
+ r_valid = true;
+ }
+ static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
+ VariantTypeChanger<bool>::change(r_ret);
+ *VariantGetInternalPtr<bool>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) || *VariantGetInternalPtr<B>::get_ptr(right);
+ }
+ static void ptr_evaluate(const void *left, const void *right, void *r_ret) {
+ PtrToArg<bool>::encode(PtrToArg<A>::convert(left) || PtrToArg<B>::convert(right), r_ret);
+ }
+ static Variant::Type get_return_type() { return Variant::BOOL; }
+};
+
+#define XOR_OP(m_a, m_b) (((m_a) || (m_b)) && !((m_a) && (m_b)))
+template <class A, class B>
+class OperatorEvaluatorXor {
+public:
+ _FORCE_INLINE_ static bool xor_op(const A &a, const B &b) {
+ return ((a) || (b)) && !((a) && (b));
+ }
+ static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
+ const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left);
+ const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right);
+ *r_ret = xor_op(a, b);
+ r_valid = true;
+ }
+ static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
+ VariantTypeChanger<bool>::change(r_ret);
+ *VariantGetInternalPtr<bool>::get_ptr(r_ret) = xor_op(*VariantGetInternalPtr<A>::get_ptr(left), *VariantGetInternalPtr<B>::get_ptr(right));
+ }
+ static void ptr_evaluate(const void *left, const void *right, void *r_ret) {
+ PtrToArg<bool>::encode(xor_op(PtrToArg<A>::convert(left), PtrToArg<B>::convert(right)), r_ret);
+ }
+ static Variant::Type get_return_type() { return Variant::BOOL; }
+};
+
+template <class A>
+class OperatorEvaluatorNot {
+public:
+ static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
+ const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left);
+ *r_ret = !a;
+ r_valid = true;
+ }
+ static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
+ VariantTypeChanger<bool>::change(r_ret);
+ *VariantGetInternalPtr<bool>::get_ptr(r_ret) = !*VariantGetInternalPtr<A>::get_ptr(left);
+ }
+ static void ptr_evaluate(const void *left, const void *right, void *r_ret) {
+ PtrToArg<bool>::encode(!PtrToArg<A>::convert(left));
+ }
+ static Variant::Type get_return_type() { return Variant::BOOL; }
+};
+
+//// CUSTOM ////
+
+class OperatorEvaluatorAddArray {
+public:
+ _FORCE_INLINE_ static void _add_arrays(Array &sum, const Array &array_a, const Array &array_b) {
+ int asize = array_a.size();
+ int bsize = array_b.size();
+ sum.resize(asize + bsize);
+ for (int i = 0; i < asize; i++) {
+ sum[i] = array_a[i];
+ }
+ for (int i = 0; i < bsize; i++) {
+ sum[i + asize] = array_b[i];
+ }
+ }
+ static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
+ const Array &array_a = *VariantGetInternalPtr<Array>::get_ptr(&p_left);
+ const Array &array_b = *VariantGetInternalPtr<Array>::get_ptr(&p_right);
+ Array sum;
+ _add_arrays(sum, array_a, array_b);
+ *r_ret = sum;
+ r_valid = true;
+ }
+ static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
+ VariantTypeChanger<Array>::change(r_ret);
+ _add_arrays(*VariantGetInternalPtr<Array>::get_ptr(r_ret), *VariantGetInternalPtr<Array>::get_ptr(left), *VariantGetInternalPtr<Array>::get_ptr(right));
+ }
+ static void ptr_evaluate(const void *left, const void *right, void *r_ret) {
+ Array ret;
+ _add_arrays(ret, PtrToArg<Array>::convert(left), PtrToArg<Array>::convert(right));
+ PtrToArg<Array>::encode(ret, r_ret);
+ }
+ static Variant::Type get_return_type() { return Variant::ARRAY; }
+};
+
+template <class T>
+class OperatorEvaluatorAppendArray {
+public:
+ static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
+ const Vector<T> &array_a = *VariantGetInternalPtr<Vector<T>>::get_ptr(&p_left);
+ const Vector<T> &array_b = *VariantGetInternalPtr<Vector<T>>::get_ptr(&p_right);
+ Vector<T> sum = array_a;
+ sum.append_array(array_b);
+ *r_ret = sum;
+ r_valid = true;
+ }
+ static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
+ VariantTypeChanger<Vector<T>>::change(r_ret);
+ *VariantGetInternalPtr<Vector<T>>::get_ptr(r_ret) = *VariantGetInternalPtr<Vector<T>>::get_ptr(left);
+ VariantGetInternalPtr<Vector<T>>::get_ptr(r_ret)->append_array(*VariantGetInternalPtr<Vector<T>>::get_ptr(right));
+ }
+ static void ptr_evaluate(const void *left, const void *right, void *r_ret) {
+ Vector<T> sum = PtrToArg<Vector<T>>::convert(left);
+ sum.append_array(PtrToArg<Vector<T>>::convert(right));
+ PtrToArg<Vector<T>>::encode(sum, r_ret);
+ }
+ static Variant::Type get_return_type() { return GetTypeInfo<Vector<T>>::VARIANT_TYPE; }
+};
+
+class OperatorEvaluatorStringModNil {
+public:
+ _FORCE_INLINE_ static String do_mod(const String &s, bool *r_valid) {
+ Array values;
+ values.push_back(Variant());
+
+ String a = s.sprintf(values, r_valid);
+ if (r_valid) {
+ *r_valid = !*r_valid;
+ }
+ return a;
+ }
+ static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
+ const String &a = *VariantGetInternalPtr<String>::get_ptr(&p_left);
+ *r_ret = do_mod(a, &r_valid);
+ r_valid = true;
+ }
+ static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
+ VariantTypeChanger<String>::change(r_ret);
+ *VariantGetInternalPtr<String>::get_ptr(r_ret) = do_mod(*VariantGetInternalPtr<String>::get_ptr(left), nullptr);
+ }
+ static void ptr_evaluate(const void *left, const void *right, void *r_ret) {
+ PtrToArg<String>::encode(do_mod(PtrToArg<String>::convert(left), nullptr), r_ret);
+ }
+ static Variant::Type get_return_type() { return Variant::STRING; }
+};
+
+class OperatorEvaluatorStringModArray {
+public:
+ _FORCE_INLINE_ static String do_mod(const String &s, const Array &p_values, bool *r_valid) {
+ String a = s.sprintf(p_values, r_valid);
+ if (r_valid) {
+ *r_valid = !*r_valid;
+ }
+ return a;
+ }
+ static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
+ const String &a = *VariantGetInternalPtr<String>::get_ptr(&p_left);
+ *r_ret = do_mod(a, *VariantGetInternalPtr<Array>::get_ptr(&p_right), &r_valid);
+ r_valid = true;
+ }
+ static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
+ VariantTypeChanger<String>::change(r_ret);
+ *VariantGetInternalPtr<String>::get_ptr(r_ret) = do_mod(*VariantGetInternalPtr<String>::get_ptr(left), *VariantGetInternalPtr<Array>::get_ptr(right), nullptr);
+ }
+ static void ptr_evaluate(const void *left, const void *right, void *r_ret) {
+ PtrToArg<String>::encode(do_mod(PtrToArg<String>::convert(left), PtrToArg<Array>::convert(right), nullptr), r_ret);
+ }
+ static Variant::Type get_return_type() { return Variant::STRING; }
+};
+
+class OperatorEvaluatorStringModObject {
+public:
+ _FORCE_INLINE_ static String do_mod(const String &s, const Object *p_object, bool *r_valid) {
+ Array values;
+ values.push_back(p_object);
+ String a = s.sprintf(values, r_valid);
+ if (r_valid) {
+ *r_valid = !*r_valid;
+ }
+
+ return a;
+ }
+ static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
+ const String &a = *VariantGetInternalPtr<String>::get_ptr(&p_left);
+ *r_ret = do_mod(a, p_right.get_validated_object(), &r_valid);
+ r_valid = true;
+ }
+ static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
+ VariantTypeChanger<String>::change(r_ret);
+ *VariantGetInternalPtr<String>::get_ptr(r_ret) = do_mod(*VariantGetInternalPtr<String>::get_ptr(left), right->get_validated_object(), nullptr);
+ }
+ static void ptr_evaluate(const void *left, const void *right, void *r_ret) {
+ PtrToArg<String>::encode(do_mod(PtrToArg<String>::convert(left), PtrToArg<Object *>::convert(right), nullptr), r_ret);
+ }
+ static Variant::Type get_return_type() { return Variant::STRING; }
+};
+
+template <class T>
+class OperatorEvaluatorStringModT {
+public:
+ _FORCE_INLINE_ static String do_mod(const String &s, const T &p_value, bool *r_valid) {
+ Array values;
+ values.push_back(p_value);
+ String a = s.sprintf(values, r_valid);
+ if (r_valid) {
+ *r_valid = !*r_valid;
+ }
+ return a;
+ }
+ static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
+ const String &a = *VariantGetInternalPtr<String>::get_ptr(&p_left);
+ *r_ret = do_mod(a, *VariantGetInternalPtr<T>::get_ptr(&p_right), &r_valid);
+ r_valid = true;
+ }
+ static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
+ VariantTypeChanger<String>::change(r_ret);
+ *VariantGetInternalPtr<String>::get_ptr(r_ret) = do_mod(*VariantGetInternalPtr<String>::get_ptr(left), *VariantGetInternalPtr<T>::get_ptr(right), nullptr);
+ }
+ static void ptr_evaluate(const void *left, const void *right, void *r_ret) {
+ PtrToArg<String>::encode(do_mod(PtrToArg<String>::convert(left), PtrToArg<T>::convert(right), nullptr), r_ret);
+ }
+ static Variant::Type get_return_type() { return Variant::STRING; }
+};
+
+template <Variant::Operator op, Variant::Type type_left, Variant::Type type_right>
+class OperatorEvaluatorAlwaysTrue {
+public:
+ static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
+ *r_ret = true;
+ r_valid = true;
+ }
+ static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
+ VariantTypeChanger<bool>::change(r_ret);
+ *VariantGetInternalPtr<bool>::get_ptr(r_ret) = true;
+ }
+ static void ptr_evaluate(const void *left, const void *right, void *r_ret) {
+ PtrToArg<bool>::encode(true, r_ret);
+ }
+ static Variant::Type get_return_type() { return Variant::BOOL; }
+};
+
+template <Variant::Operator op, Variant::Type type_left, Variant::Type type_right>
+class OperatorEvaluatorAlwaysFalse {
+public:
+ static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
+ *r_ret = false;
+ r_valid = true;
+ }
+ static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
+ VariantTypeChanger<bool>::change(r_ret);
+ *VariantGetInternalPtr<bool>::get_ptr(r_ret) = false;
+ }
+ static void ptr_evaluate(const void *left, const void *right, void *r_ret) {
+ PtrToArg<bool>::encode(false, r_ret);
+ }
+ static Variant::Type get_return_type() { return Variant::BOOL; }
+};
+
+///// OR ///////
+
+_FORCE_INLINE_ static bool _operate_or(bool p_left, bool p_right) {
+ return p_left || p_right;
+}
+
+_FORCE_INLINE_ static bool _operate_and(bool p_left, bool p_right) {
+ return p_left && p_right;
+}
+
+_FORCE_INLINE_ static bool _operate_xor(bool p_left, bool p_right) {
+ return (p_left || p_right) && !(p_left && p_right);
+}
+
+_FORCE_INLINE_ static bool _operate_get_nil(const Variant *p_ptr) {
+ return p_ptr->get_validated_object() != nullptr;
+}
+
+_FORCE_INLINE_ static bool _operate_get_bool(const Variant *p_ptr) {
+ return *VariantGetInternalPtr<bool>::get_ptr(p_ptr);
+}
+
+_FORCE_INLINE_ static bool _operate_get_int(const Variant *p_ptr) {
+ return *VariantGetInternalPtr<int64_t>::get_ptr(p_ptr) != 0;
+}
+
+_FORCE_INLINE_ static bool _operate_get_float(const Variant *p_ptr) {
+ return *VariantGetInternalPtr<double>::get_ptr(p_ptr) != 0.0;
+}
+
+_FORCE_INLINE_ static bool _operate_get_object(const Variant *p_ptr) {
+ return p_ptr->get_validated_object() != nullptr;
+}
+
+_FORCE_INLINE_ static bool _operate_get_ptr_nil(const void *p_ptr) {
+ return false;
+}
+
+_FORCE_INLINE_ static bool _operate_get_ptr_bool(const void *p_ptr) {
+ return PtrToArg<bool>::convert(p_ptr);
+}
+
+_FORCE_INLINE_ static bool _operate_get_ptr_int(const void *p_ptr) {
+ return PtrToArg<int64_t>::convert(p_ptr) != 0;
+}
+
+_FORCE_INLINE_ static bool _operate_get_ptr_float(const void *p_ptr) {
+ return PtrToArg<double>::convert(p_ptr) != 0.0;
+}
+
+_FORCE_INLINE_ static bool _operate_get_ptr_object(const void *p_ptr) {
+ return PtrToArg<Object *>::convert(p_ptr) != nullptr;
+}
+
+#define OP_EVALUATOR(m_class_name, m_left, m_right, m_op) \
+ class m_class_name { \
+ public: \
+ static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { \
+ *r_ret = m_op(_operate_get_##m_left(&p_left), _operate_get_##m_right(&p_right)); \
+ r_valid = true; \
+ } \
+ \
+ static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { \
+ VariantTypeChanger<bool>::change(r_ret); \
+ *VariantGetInternalPtr<bool>::get_ptr(r_ret) = m_op(_operate_get_##m_left(left), _operate_get_##m_right(right)); \
+ } \
+ \
+ static void ptr_evaluate(const void *left, const void *right, void *r_ret) { \
+ PtrToArg<bool>::encode(m_op(_operate_get_ptr_##m_left(left), _operate_get_ptr_##m_right(right)), r_ret); \
+ } \
+ \
+ static Variant::Type get_return_type() { \
+ return Variant::BOOL; \
+ } \
+ };
+
+// OR
+
+// nil
+OP_EVALUATOR(OperatorEvaluatorNilXBoolOr, nil, bool, _operate_or)
+OP_EVALUATOR(OperatorEvaluatorBoolXNilOr, bool, nil, _operate_or)
+
+OP_EVALUATOR(OperatorEvaluatorNilXIntOr, nil, int, _operate_or)
+OP_EVALUATOR(OperatorEvaluatorIntXNilOr, int, nil, _operate_or)
+
+OP_EVALUATOR(OperatorEvaluatorNilXFloatOr, nil, float, _operate_or)
+OP_EVALUATOR(OperatorEvaluatorFloatXNilOr, float, nil, _operate_or)
+
+OP_EVALUATOR(OperatorEvaluatorObjectXNilOr, object, nil, _operate_or)
+OP_EVALUATOR(OperatorEvaluatorNilXObjectOr, nil, object, _operate_or)
+
+// bool
+OP_EVALUATOR(OperatorEvaluatorBoolXBoolOr, bool, bool, _operate_or)
+
+OP_EVALUATOR(OperatorEvaluatorBoolXIntOr, bool, int, _operate_or)
+OP_EVALUATOR(OperatorEvaluatorIntXBoolOr, int, bool, _operate_or)
+
+OP_EVALUATOR(OperatorEvaluatorBoolXFloatOr, bool, float, _operate_or)
+OP_EVALUATOR(OperatorEvaluatorFloatXBoolOr, float, bool, _operate_or)
+
+OP_EVALUATOR(OperatorEvaluatorBoolXObjectOr, bool, object, _operate_or)
+OP_EVALUATOR(OperatorEvaluatorObjectXBoolOr, object, bool, _operate_or)
+
+// int
+OP_EVALUATOR(OperatorEvaluatorIntXIntOr, int, int, _operate_or)
+
+OP_EVALUATOR(OperatorEvaluatorIntXFloatOr, int, float, _operate_or)
+OP_EVALUATOR(OperatorEvaluatorFloatXIntOr, float, int, _operate_or)
+
+OP_EVALUATOR(OperatorEvaluatorIntXObjectOr, int, object, _operate_or)
+OP_EVALUATOR(OperatorEvaluatorObjectXIntOr, object, int, _operate_or)
+
+// float
+OP_EVALUATOR(OperatorEvaluatorFloatXFloatOr, float, float, _operate_or)
+
+OP_EVALUATOR(OperatorEvaluatorFloatXObjectOr, float, object, _operate_or)
+OP_EVALUATOR(OperatorEvaluatorObjectXFloatOr, object, float, _operate_or)
+
+// object
+OP_EVALUATOR(OperatorEvaluatorObjectXObjectOr, object, object, _operate_or)
+
+// AND
+
+// nil
+OP_EVALUATOR(OperatorEvaluatorNilXBoolAnd, nil, bool, _operate_and)
+OP_EVALUATOR(OperatorEvaluatorBoolXNilAnd, bool, nil, _operate_and)
+
+OP_EVALUATOR(OperatorEvaluatorNilXIntAnd, nil, int, _operate_and)
+OP_EVALUATOR(OperatorEvaluatorIntXNilAnd, int, nil, _operate_and)
+
+OP_EVALUATOR(OperatorEvaluatorNilXFloatAnd, nil, float, _operate_and)
+OP_EVALUATOR(OperatorEvaluatorFloatXNilAnd, float, nil, _operate_and)
+
+OP_EVALUATOR(OperatorEvaluatorObjectXNilAnd, object, nil, _operate_and)
+OP_EVALUATOR(OperatorEvaluatorNilXObjectAnd, nil, object, _operate_and)
+
+// bool
+OP_EVALUATOR(OperatorEvaluatorBoolXBoolAnd, bool, bool, _operate_and)
+
+OP_EVALUATOR(OperatorEvaluatorBoolXIntAnd, bool, int, _operate_and)
+OP_EVALUATOR(OperatorEvaluatorIntXBoolAnd, int, bool, _operate_and)
+
+OP_EVALUATOR(OperatorEvaluatorBoolXFloatAnd, bool, float, _operate_and)
+OP_EVALUATOR(OperatorEvaluatorFloatXBoolAnd, float, bool, _operate_and)
+
+OP_EVALUATOR(OperatorEvaluatorBoolXObjectAnd, bool, object, _operate_and)
+OP_EVALUATOR(OperatorEvaluatorObjectXBoolAnd, object, bool, _operate_and)
+
+// int
+OP_EVALUATOR(OperatorEvaluatorIntXIntAnd, int, int, _operate_and)
+
+OP_EVALUATOR(OperatorEvaluatorIntXFloatAnd, int, float, _operate_and)
+OP_EVALUATOR(OperatorEvaluatorFloatXIntAnd, float, int, _operate_and)
+
+OP_EVALUATOR(OperatorEvaluatorIntXObjectAnd, int, object, _operate_and)
+OP_EVALUATOR(OperatorEvaluatorObjectXIntAnd, object, int, _operate_and)
+
+// float
+OP_EVALUATOR(OperatorEvaluatorFloatXFloatAnd, float, float, _operate_and)
+
+OP_EVALUATOR(OperatorEvaluatorFloatXObjectAnd, float, object, _operate_and)
+OP_EVALUATOR(OperatorEvaluatorObjectXFloatAnd, object, float, _operate_and)
+
+// object
+OP_EVALUATOR(OperatorEvaluatorObjectXObjectAnd, object, object, _operate_and)
+
+// XOR
+
+// nil
+OP_EVALUATOR(OperatorEvaluatorNilXBoolXor, nil, bool, _operate_xor)
+OP_EVALUATOR(OperatorEvaluatorBoolXNilXor, bool, nil, _operate_xor)
+
+OP_EVALUATOR(OperatorEvaluatorNilXIntXor, nil, int, _operate_xor)
+OP_EVALUATOR(OperatorEvaluatorIntXNilXor, int, nil, _operate_xor)
+
+OP_EVALUATOR(OperatorEvaluatorNilXFloatXor, nil, float, _operate_xor)
+OP_EVALUATOR(OperatorEvaluatorFloatXNilXor, float, nil, _operate_xor)
+
+OP_EVALUATOR(OperatorEvaluatorObjectXNilXor, object, nil, _operate_xor)
+OP_EVALUATOR(OperatorEvaluatorNilXObjectXor, nil, object, _operate_xor)
+
+// bool
+OP_EVALUATOR(OperatorEvaluatorBoolXBoolXor, bool, bool, _operate_xor)
+
+OP_EVALUATOR(OperatorEvaluatorBoolXIntXor, bool, int, _operate_xor)
+OP_EVALUATOR(OperatorEvaluatorIntXBoolXor, int, bool, _operate_xor)
+
+OP_EVALUATOR(OperatorEvaluatorBoolXFloatXor, bool, float, _operate_xor)
+OP_EVALUATOR(OperatorEvaluatorFloatXBoolXor, float, bool, _operate_xor)
+
+OP_EVALUATOR(OperatorEvaluatorBoolXObjectXor, bool, object, _operate_xor)
+OP_EVALUATOR(OperatorEvaluatorObjectXBoolXor, object, bool, _operate_xor)
+
+// int
+OP_EVALUATOR(OperatorEvaluatorIntXIntXor, int, int, _operate_xor)
+
+OP_EVALUATOR(OperatorEvaluatorIntXFloatXor, int, float, _operate_xor)
+OP_EVALUATOR(OperatorEvaluatorFloatXIntXor, float, int, _operate_xor)
+
+OP_EVALUATOR(OperatorEvaluatorIntXObjectXor, int, object, _operate_xor)
+OP_EVALUATOR(OperatorEvaluatorObjectXIntXor, object, int, _operate_xor)
+
+// float
+OP_EVALUATOR(OperatorEvaluatorFloatXFloatXor, float, float, _operate_xor)
+
+OP_EVALUATOR(OperatorEvaluatorFloatXObjectXor, float, object, _operate_xor)
+OP_EVALUATOR(OperatorEvaluatorObjectXFloatXor, object, float, _operate_xor)
+
+// object
+OP_EVALUATOR(OperatorEvaluatorObjectXObjectXor, object, object, _operate_xor)
+
+class OperatorEvaluatorNotBool {
+public:
+ static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
+ *r_ret = !*VariantGetInternalPtr<bool>::get_ptr(&p_left);
+ r_valid = true;
+ }
+ static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
+ VariantTypeChanger<bool>::change(r_ret);
+ *VariantGetInternalPtr<bool>::get_ptr(r_ret) = !*VariantGetInternalPtr<bool>::get_ptr(left);
+ }
+ static void ptr_evaluate(const void *left, const void *right, void *r_ret) {
+ PtrToArg<bool>::encode(!PtrToArg<bool>::convert(left), r_ret);
+ }
+ static Variant::Type get_return_type() { return Variant::BOOL; }
+};
+
+class OperatorEvaluatorNotInt {
+public:
+ static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
+ *r_ret = !*VariantGetInternalPtr<int64_t>::get_ptr(&p_left);
+ r_valid = true;
+ }
+ static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
+ VariantTypeChanger<bool>::change(r_ret);
+ *VariantGetInternalPtr<bool>::get_ptr(r_ret) = !*VariantGetInternalPtr<int64_t>::get_ptr(left);
+ }
+ static void ptr_evaluate(const void *left, const void *right, void *r_ret) {
+ PtrToArg<bool>::encode(!PtrToArg<int64_t>::convert(left), r_ret);
+ }
+ static Variant::Type get_return_type() { return Variant::BOOL; }
+};
+
+class OperatorEvaluatorNotFloat {
+public:
+ static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
+ *r_ret = !*VariantGetInternalPtr<double>::get_ptr(&p_left);
+ r_valid = true;
+ }
+ static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
+ VariantTypeChanger<bool>::change(r_ret);
+ *VariantGetInternalPtr<bool>::get_ptr(r_ret) = !*VariantGetInternalPtr<double>::get_ptr(left);
+ }
+ static void ptr_evaluate(const void *left, const void *right, void *r_ret) {
+ PtrToArg<bool>::encode(!PtrToArg<double>::convert(left), r_ret);
+ }
+ static Variant::Type get_return_type() { return Variant::BOOL; }
+};
+
+class OperatorEvaluatorNotObject {
+public:
+ static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
+ *r_ret = p_left.get_validated_object() == nullptr;
+ r_valid = true;
+ }
+ static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
+ VariantTypeChanger<bool>::change(r_ret);
+ *VariantGetInternalPtr<bool>::get_ptr(r_ret) = left->get_validated_object() == nullptr;
+ }
+ static void ptr_evaluate(const void *left, const void *right, void *r_ret) {
+ PtrToArg<bool>::encode(PtrToArg<Object *>::convert(left) == nullptr, r_ret);
+ }
+ static Variant::Type get_return_type() { return Variant::BOOL; }
+};
+
+////
+
+class OperatorEvaluatorInStringFind {
+public:
+ static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
+ const String &str_a = *VariantGetInternalPtr<String>::get_ptr(&p_left);
+ const String &str_b = *VariantGetInternalPtr<String>::get_ptr(&p_right);
+
+ *r_ret = str_b.find(str_a) != -1;
+ r_valid = true;
+ }
+ static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
+ const String &str_a = *VariantGetInternalPtr<String>::get_ptr(left);
+ const String &str_b = *VariantGetInternalPtr<String>::get_ptr(right);
+ VariantTypeChanger<bool>::change(r_ret);
+ *VariantGetInternalPtr<bool>::get_ptr(r_ret) = str_b.find(str_a) != -1;
+ }
+ static void ptr_evaluate(const void *left, const void *right, void *r_ret) {
+ PtrToArg<bool>::encode(PtrToArg<String>::convert(right).find(PtrToArg<String>::convert(left)) != -1, r_ret);
+ }
+ static Variant::Type get_return_type() { return Variant::BOOL; }
+};
+
+template <class A, class B>
+class OperatorEvaluatorInArrayFind {
+public:
+ static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
+ const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left);
+ const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right);
+
+ *r_ret = b.find(a) != -1;
+ r_valid = true;
+ }
+ static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
+ const A &a = *VariantGetInternalPtr<A>::get_ptr(left);
+ const B &b = *VariantGetInternalPtr<B>::get_ptr(right);
+ VariantTypeChanger<bool>::change(r_ret);
+ *VariantGetInternalPtr<bool>::get_ptr(r_ret) = b.find(a) != -1;
+ }
+ static void ptr_evaluate(const void *left, const void *right, void *r_ret) {
+ PtrToArg<bool>::encode(PtrToArg<B>::convert(right).find(PtrToArg<A>::convert(left)) != -1, r_ret);
+ }
+ static Variant::Type get_return_type() { return Variant::BOOL; }
+};
+
+class OperatorEvaluatorInArrayFindNil {
+public:
+ static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
+ const Array &b = *VariantGetInternalPtr<Array>::get_ptr(&p_right);
+ *r_ret = b.find(Variant()) != -1;
+ r_valid = true;
+ }
+ static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
+ const Array &b = *VariantGetInternalPtr<Array>::get_ptr(right);
+ VariantTypeChanger<bool>::change(r_ret);
+ *VariantGetInternalPtr<bool>::get_ptr(r_ret) = b.find(Variant()) != -1;
+ }
+ static void ptr_evaluate(const void *left, const void *right, void *r_ret) {
+ PtrToArg<bool>::encode(PtrToArg<Array>::convert(right).find(Variant()) != -1, r_ret);
+ }
+ static Variant::Type get_return_type() { return Variant::BOOL; }
+};
+
+class OperatorEvaluatorInArrayFindObject {
+public:
+ static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
+ const Array &b = *VariantGetInternalPtr<Array>::get_ptr(&p_right);
+ *r_ret = b.find(p_left) != -1;
+ r_valid = true;
+ }
+ static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
+ const Array &b = *VariantGetInternalPtr<Array>::get_ptr(right);
+ VariantTypeChanger<bool>::change(r_ret);
+ *VariantGetInternalPtr<bool>::get_ptr(r_ret) = b.find(*left) != -1;
+ }
+ static void ptr_evaluate(const void *left, const void *right, void *r_ret) {
+ PtrToArg<bool>::encode(PtrToArg<Array>::convert(right).find(PtrToArg<Object *>::convert(left)) != -1, r_ret);
+ }
+ static Variant::Type get_return_type() { return Variant::BOOL; }
+};
+
+template <class A>
+class OperatorEvaluatorInDictionaryHas {
+public:
+ static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
+ const Dictionary &b = *VariantGetInternalPtr<Dictionary>::get_ptr(&p_right);
+ const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left);
+
+ *r_ret = b.has(a);
+ r_valid = true;
+ }
+ static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
+ const Dictionary &b = *VariantGetInternalPtr<Dictionary>::get_ptr(right);
+ const A &a = *VariantGetInternalPtr<A>::get_ptr(left);
+ VariantTypeChanger<bool>::change(r_ret);
+ *VariantGetInternalPtr<bool>::get_ptr(r_ret) = b.has(a);
+ }
+ static void ptr_evaluate(const void *left, const void *right, void *r_ret) {
+ PtrToArg<bool>::encode(PtrToArg<Dictionary>::convert(right).has(PtrToArg<A>::convert(left)), r_ret);
+ }
+ static Variant::Type get_return_type() { return Variant::BOOL; }
+};
+
+class OperatorEvaluatorInDictionaryHasNil {
+public:
+ static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
+ const Dictionary &b = *VariantGetInternalPtr<Dictionary>::get_ptr(&p_right);
+
+ *r_ret = b.has(Variant());
+ r_valid = true;
+ }
+ static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
+ const Dictionary &b = *VariantGetInternalPtr<Dictionary>::get_ptr(right);
+ VariantTypeChanger<bool>::change(r_ret);
+ *VariantGetInternalPtr<bool>::get_ptr(r_ret) = b.has(Variant());
+ }
+ static void ptr_evaluate(const void *left, const void *right, void *r_ret) {
+ PtrToArg<bool>::encode(PtrToArg<Dictionary>::convert(right).has(Variant()), r_ret);
+ }
+ static Variant::Type get_return_type() { return Variant::BOOL; }
+};
+
+class OperatorEvaluatorInDictionaryHasObject {
+public:
+ static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
+ const Dictionary &b = *VariantGetInternalPtr<Dictionary>::get_ptr(&p_right);
+
+ *r_ret = b.has(p_left);
+ r_valid = true;
+ }
+ static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
+ const Dictionary &b = *VariantGetInternalPtr<Dictionary>::get_ptr(right);
+ VariantTypeChanger<bool>::change(r_ret);
+ *VariantGetInternalPtr<bool>::get_ptr(r_ret) = b.has(*left);
+ }
+ static void ptr_evaluate(const void *left, const void *right, void *r_ret) {
+ PtrToArg<bool>::encode(PtrToArg<Dictionary>::convert(right).has(PtrToArg<Object *>::convert(left)), r_ret);
+ }
+ static Variant::Type get_return_type() { return Variant::BOOL; }
+};
+
+class OperatorEvaluatorObjectHasPropertyString {
+public:
+ static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
+ Object *b = p_right.get_validated_object();
+ if (!b) {
+ *r_ret = "Invalid base object for 'in'";
+ r_valid = false;
+ return;
+ }
+
+ const String &a = *VariantGetInternalPtr<String>::get_ptr(&p_left);
+
+ b->get(a, &r_valid);
+ *r_ret = r_valid;
+ }
+ static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
+ Object *l = right->get_validated_object();
+ ERR_FAIL_COND(l == nullptr);
+ const String &a = *VariantGetInternalPtr<String>::get_ptr(left);
+
+ bool valid;
+ l->get(a, &valid);
+ VariantTypeChanger<bool>::change(r_ret);
+ *VariantGetInternalPtr<bool>::get_ptr(r_ret) = valid;
+ }
+ static void ptr_evaluate(const void *left, const void *right, void *r_ret) {
+ bool valid;
+ PtrToArg<Object *>::convert(right)->get(PtrToArg<String>::convert(left), &valid);
+ PtrToArg<bool>::encode(valid, r_ret);
+ }
+ static Variant::Type get_return_type() { return Variant::BOOL; }
+};
+
+class OperatorEvaluatorObjectHasPropertyStringName {
+public:
+ static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) {
+ Object *b = p_right.get_validated_object();
+ if (!b) {
+ *r_ret = "Invalid base object for 'in'";
+ r_valid = false;
+ return;
+ }
+
+ const StringName &a = *VariantGetInternalPtr<StringName>::get_ptr(&p_left);
+
+ b->get(a, &r_valid);
+ *r_ret = r_valid;
+ }
+ static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
+ Object *l = right->get_validated_object();
+ ERR_FAIL_COND(l == nullptr);
+ const StringName &a = *VariantGetInternalPtr<StringName>::get_ptr(left);
+
+ bool valid;
+ l->get(a, &valid);
+ VariantTypeChanger<bool>::change(r_ret);
+ *VariantGetInternalPtr<bool>::get_ptr(r_ret) = valid;
+ }
+ static void ptr_evaluate(const void *left, const void *right, void *r_ret) {
+ bool valid;
+ PtrToArg<Object *>::convert(right)->get(PtrToArg<StringName>::convert(left), &valid);
+ PtrToArg<bool>::encode(valid, r_ret);
+ }
+ static Variant::Type get_return_type() { return Variant::BOOL; }
+};
+
+typedef void (*VariantEvaluatorFunction)(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid);
+
+static Variant::Type operator_return_type_table[Variant::OP_MAX][Variant::VARIANT_MAX][Variant::VARIANT_MAX];
+static VariantEvaluatorFunction operator_evaluator_table[Variant::OP_MAX][Variant::VARIANT_MAX][Variant::VARIANT_MAX];
+static Variant::ValidatedOperatorEvaluator validated_operator_evaluator_table[Variant::OP_MAX][Variant::VARIANT_MAX][Variant::VARIANT_MAX];
+static Variant::PTROperatorEvaluator ptr_operator_evaluator_table[Variant::OP_MAX][Variant::VARIANT_MAX][Variant::VARIANT_MAX];
+
+template <class T>
+void register_op(Variant::Operator p_op, Variant::Type p_type_a, Variant::Type p_type_b) {
+ operator_return_type_table[p_op][p_type_a][p_type_b] = T::get_return_type();
+ operator_evaluator_table[p_op][p_type_a][p_type_b] = T::evaluate;
+ validated_operator_evaluator_table[p_op][p_type_a][p_type_b] = T::validated_evaluate;
+ ptr_operator_evaluator_table[p_op][p_type_a][p_type_b] = T::ptr_evaluate;
+}
+
+void Variant::_register_variant_operators() {
+ zeromem(operator_return_type_table, sizeof(operator_return_type_table));
+ zeromem(operator_evaluator_table, sizeof(operator_evaluator_table));
+ zeromem(validated_operator_evaluator_table, sizeof(validated_operator_evaluator_table));
+ zeromem(ptr_operator_evaluator_table, sizeof(ptr_operator_evaluator_table));
+
+ register_op<OperatorEvaluatorAdd<int64_t, int64_t, int64_t>>(Variant::OP_ADD, Variant::INT, Variant::INT);
+ register_op<OperatorEvaluatorAdd<double, int64_t, double>>(Variant::OP_ADD, Variant::INT, Variant::FLOAT);
+ register_op<OperatorEvaluatorAdd<double, double, int64_t>>(Variant::OP_ADD, Variant::FLOAT, Variant::INT);
+ register_op<OperatorEvaluatorAdd<double, double, double>>(Variant::OP_ADD, Variant::FLOAT, Variant::FLOAT);
+ register_op<OperatorEvaluatorAdd<String, String, String>>(Variant::OP_ADD, Variant::STRING, Variant::STRING);
+ register_op<OperatorEvaluatorAdd<Vector2, Vector2, Vector2>>(Variant::OP_ADD, Variant::VECTOR2, Variant::VECTOR2);
+ register_op<OperatorEvaluatorAdd<Vector2i, Vector2i, Vector2i>>(Variant::OP_ADD, Variant::VECTOR2I, Variant::VECTOR2I);
+ register_op<OperatorEvaluatorAdd<Vector3, Vector3, Vector3>>(Variant::OP_ADD, Variant::VECTOR3, Variant::VECTOR3);
+ register_op<OperatorEvaluatorAdd<Vector3i, Vector3i, Vector3i>>(Variant::OP_ADD, Variant::VECTOR3I, Variant::VECTOR3I);
+ register_op<OperatorEvaluatorAdd<Quat, Quat, Quat>>(Variant::OP_ADD, Variant::QUAT, Variant::QUAT);
+ register_op<OperatorEvaluatorAdd<Color, Color, Color>>(Variant::OP_ADD, Variant::COLOR, Variant::COLOR);
+ register_op<OperatorEvaluatorAddArray>(Variant::OP_ADD, Variant::ARRAY, Variant::ARRAY);
+ register_op<OperatorEvaluatorAppendArray<uint8_t>>(Variant::OP_ADD, Variant::PACKED_BYTE_ARRAY, Variant::PACKED_BYTE_ARRAY);
+ register_op<OperatorEvaluatorAppendArray<int32_t>>(Variant::OP_ADD, Variant::PACKED_INT32_ARRAY, Variant::PACKED_INT32_ARRAY);
+ register_op<OperatorEvaluatorAppendArray<int64_t>>(Variant::OP_ADD, Variant::PACKED_INT64_ARRAY, Variant::PACKED_INT64_ARRAY);
+ register_op<OperatorEvaluatorAppendArray<float>>(Variant::OP_ADD, Variant::PACKED_FLOAT32_ARRAY, Variant::PACKED_FLOAT32_ARRAY);
+ register_op<OperatorEvaluatorAppendArray<double>>(Variant::OP_ADD, Variant::PACKED_FLOAT64_ARRAY, Variant::PACKED_FLOAT64_ARRAY);
+ register_op<OperatorEvaluatorAppendArray<String>>(Variant::OP_ADD, Variant::PACKED_STRING_ARRAY, Variant::PACKED_STRING_ARRAY);
+ register_op<OperatorEvaluatorAppendArray<Vector2>>(Variant::OP_ADD, Variant::PACKED_VECTOR2_ARRAY, Variant::PACKED_VECTOR2_ARRAY);
+ register_op<OperatorEvaluatorAppendArray<Vector3>>(Variant::OP_ADD, Variant::PACKED_VECTOR3_ARRAY, Variant::PACKED_VECTOR3_ARRAY);
+ register_op<OperatorEvaluatorAppendArray<Color>>(Variant::OP_ADD, Variant::PACKED_COLOR_ARRAY, Variant::PACKED_COLOR_ARRAY);
+
+ register_op<OperatorEvaluatorSub<int64_t, int64_t, int64_t>>(Variant::OP_SUBTRACT, Variant::INT, Variant::INT);
+ register_op<OperatorEvaluatorSub<double, int64_t, double>>(Variant::OP_SUBTRACT, Variant::INT, Variant::FLOAT);
+ register_op<OperatorEvaluatorSub<double, double, int64_t>>(Variant::OP_SUBTRACT, Variant::FLOAT, Variant::INT);
+ register_op<OperatorEvaluatorSub<double, double, double>>(Variant::OP_SUBTRACT, Variant::FLOAT, Variant::FLOAT);
+ register_op<OperatorEvaluatorSub<Vector2, Vector2, Vector2>>(Variant::OP_SUBTRACT, Variant::VECTOR2, Variant::VECTOR2);
+ register_op<OperatorEvaluatorSub<Vector2i, Vector2i, Vector2i>>(Variant::OP_SUBTRACT, Variant::VECTOR2I, Variant::VECTOR2I);
+ register_op<OperatorEvaluatorSub<Vector3, Vector3, Vector3>>(Variant::OP_SUBTRACT, Variant::VECTOR3, Variant::VECTOR3);
+ register_op<OperatorEvaluatorSub<Vector3i, Vector3i, Vector3i>>(Variant::OP_SUBTRACT, Variant::VECTOR3I, Variant::VECTOR3I);
+
+ register_op<OperatorEvaluatorMul<int64_t, int64_t, int64_t>>(Variant::OP_MULTIPLY, Variant::INT, Variant::INT);
+ register_op<OperatorEvaluatorMul<double, int64_t, double>>(Variant::OP_MULTIPLY, Variant::INT, Variant::FLOAT);
+ register_op<OperatorEvaluatorMul<Vector2, int64_t, Vector2>>(Variant::OP_MULTIPLY, Variant::INT, Variant::VECTOR2);
+ register_op<OperatorEvaluatorMul<Vector2i, int64_t, Vector2i>>(Variant::OP_MULTIPLY, Variant::INT, Variant::VECTOR2I);
+ register_op<OperatorEvaluatorMul<Vector3, int64_t, Vector3>>(Variant::OP_MULTIPLY, Variant::INT, Variant::VECTOR3);
+ register_op<OperatorEvaluatorMul<Vector3i, int64_t, Vector3i>>(Variant::OP_MULTIPLY, Variant::INT, Variant::VECTOR3I);
+
+ register_op<OperatorEvaluatorMul<double, double, double>>(Variant::OP_MULTIPLY, Variant::FLOAT, Variant::FLOAT);
+ register_op<OperatorEvaluatorMul<double, double, int64_t>>(Variant::OP_MULTIPLY, Variant::FLOAT, Variant::INT);
+ register_op<OperatorEvaluatorMul<Vector2, double, Vector2>>(Variant::OP_MULTIPLY, Variant::FLOAT, Variant::VECTOR2);
+ register_op<OperatorEvaluatorMul<Vector2i, double, Vector2i>>(Variant::OP_MULTIPLY, Variant::FLOAT, Variant::VECTOR2I);
+ register_op<OperatorEvaluatorMul<Vector3, double, Vector3>>(Variant::OP_MULTIPLY, Variant::FLOAT, Variant::VECTOR3);
+ register_op<OperatorEvaluatorMul<Vector3i, double, Vector3i>>(Variant::OP_MULTIPLY, Variant::FLOAT, Variant::VECTOR3I);
+
+ register_op<OperatorEvaluatorMul<Vector2, Vector2, Vector2>>(Variant::OP_MULTIPLY, Variant::VECTOR2, Variant::VECTOR2);
+ register_op<OperatorEvaluatorMul<Vector2, Vector2, int64_t>>(Variant::OP_MULTIPLY, Variant::VECTOR2, Variant::INT);
+ register_op<OperatorEvaluatorMul<Vector2, Vector2, double>>(Variant::OP_MULTIPLY, Variant::VECTOR2, Variant::FLOAT);
+
+ register_op<OperatorEvaluatorMul<Vector2i, Vector2i, Vector2i>>(Variant::OP_MULTIPLY, Variant::VECTOR2I, Variant::VECTOR2I);
+ register_op<OperatorEvaluatorMul<Vector2i, Vector2i, int64_t>>(Variant::OP_MULTIPLY, Variant::VECTOR2I, Variant::INT);
+ register_op<OperatorEvaluatorMul<Vector2i, Vector2i, double>>(Variant::OP_MULTIPLY, Variant::VECTOR2I, Variant::FLOAT);
+
+ register_op<OperatorEvaluatorMul<Vector3, Vector3, Vector3>>(Variant::OP_MULTIPLY, Variant::VECTOR3, Variant::VECTOR3);
+ register_op<OperatorEvaluatorMul<Vector3, Vector3, int64_t>>(Variant::OP_MULTIPLY, Variant::VECTOR3, Variant::INT);
+ register_op<OperatorEvaluatorMul<Vector3, Vector3, double>>(Variant::OP_MULTIPLY, Variant::VECTOR3, Variant::FLOAT);
+
+ register_op<OperatorEvaluatorMul<Vector3i, Vector3i, Vector3i>>(Variant::OP_MULTIPLY, Variant::VECTOR3I, Variant::VECTOR3I);
+ register_op<OperatorEvaluatorMul<Vector3i, Vector3i, int64_t>>(Variant::OP_MULTIPLY, Variant::VECTOR3I, Variant::INT);
+ register_op<OperatorEvaluatorMul<Vector3i, Vector3i, double>>(Variant::OP_MULTIPLY, Variant::VECTOR3I, Variant::FLOAT);
+
+ register_op<OperatorEvaluatorMul<Quat, Quat, Quat>>(Variant::OP_MULTIPLY, Variant::QUAT, Variant::QUAT);
+ register_op<OperatorEvaluatorMul<Quat, Quat, int64_t>>(Variant::OP_MULTIPLY, Variant::QUAT, Variant::INT);
+ register_op<OperatorEvaluatorMul<Quat, Quat, double>>(Variant::OP_MULTIPLY, Variant::QUAT, Variant::FLOAT);
+
+ register_op<OperatorEvaluatorMul<Color, Color, Color>>(Variant::OP_MULTIPLY, Variant::COLOR, Variant::COLOR);
+ register_op<OperatorEvaluatorMul<Color, Color, int64_t>>(Variant::OP_MULTIPLY, Variant::COLOR, Variant::INT);
+ register_op<OperatorEvaluatorMul<Color, Color, double>>(Variant::OP_MULTIPLY, Variant::COLOR, Variant::FLOAT);
+
+ register_op<OperatorEvaluatorMul<Transform2D, Transform2D, Transform2D>>(Variant::OP_MULTIPLY, Variant::TRANSFORM2D, Variant::TRANSFORM2D);
+ register_op<OperatorEvaluatorXForm<Vector2, Transform2D, Vector2>>(Variant::OP_MULTIPLY, Variant::TRANSFORM2D, Variant::VECTOR2);
+ register_op<OperatorEvaluatorXFormInv<Vector2, Vector2, Transform2D>>(Variant::OP_MULTIPLY, Variant::VECTOR2, Variant::TRANSFORM2D);
+ register_op<OperatorEvaluatorXForm<Rect2, Transform2D, Rect2>>(Variant::OP_MULTIPLY, Variant::TRANSFORM2D, Variant::RECT2);
+ register_op<OperatorEvaluatorXFormInv<Rect2, Rect2, Transform2D>>(Variant::OP_MULTIPLY, Variant::RECT2, Variant::TRANSFORM2D);
+ register_op<OperatorEvaluatorXForm<Vector<Vector2>, Transform2D, Vector<Vector2>>>(Variant::OP_MULTIPLY, Variant::TRANSFORM2D, Variant::PACKED_VECTOR2_ARRAY);
+ register_op<OperatorEvaluatorXFormInv<Vector<Vector2>, Vector<Vector2>, Transform2D>>(Variant::OP_MULTIPLY, Variant::PACKED_VECTOR2_ARRAY, Variant::TRANSFORM2D);
+
+ register_op<OperatorEvaluatorMul<Transform, Transform, Transform>>(Variant::OP_MULTIPLY, Variant::TRANSFORM, Variant::TRANSFORM);
+ register_op<OperatorEvaluatorXForm<Vector3, Transform, Vector3>>(Variant::OP_MULTIPLY, Variant::TRANSFORM, Variant::VECTOR3);
+ register_op<OperatorEvaluatorXFormInv<Vector3, Vector3, Transform>>(Variant::OP_MULTIPLY, Variant::VECTOR3, Variant::TRANSFORM);
+ register_op<OperatorEvaluatorXForm<::AABB, Transform, ::AABB>>(Variant::OP_MULTIPLY, Variant::TRANSFORM, Variant::AABB);
+ register_op<OperatorEvaluatorXFormInv<::AABB, ::AABB, Transform>>(Variant::OP_MULTIPLY, Variant::AABB, Variant::TRANSFORM);
+ register_op<OperatorEvaluatorXForm<Vector<Vector3>, Transform, Vector<Vector3>>>(Variant::OP_MULTIPLY, Variant::TRANSFORM, Variant::PACKED_VECTOR3_ARRAY);
+ register_op<OperatorEvaluatorXFormInv<Vector<Vector3>, Vector<Vector3>, Transform>>(Variant::OP_MULTIPLY, Variant::PACKED_VECTOR3_ARRAY, Variant::TRANSFORM);
+
+ register_op<OperatorEvaluatorMul<Basis, Basis, Basis>>(Variant::OP_MULTIPLY, Variant::BASIS, Variant::BASIS);
+ register_op<OperatorEvaluatorXForm<Vector3, Basis, Vector3>>(Variant::OP_MULTIPLY, Variant::BASIS, Variant::VECTOR3);
+ register_op<OperatorEvaluatorXFormInv<Vector3, Vector3, Basis>>(Variant::OP_MULTIPLY, Variant::VECTOR3, Variant::BASIS);
+
+ register_op<OperatorEvaluatorMul<Quat, Quat, Quat>>(Variant::OP_MULTIPLY, Variant::QUAT, Variant::QUAT);
+ register_op<OperatorEvaluatorMul<Quat, Quat, int64_t>>(Variant::OP_MULTIPLY, Variant::QUAT, Variant::INT);
+ register_op<OperatorEvaluatorMul<Quat, int64_t, Quat>>(Variant::OP_MULTIPLY, Variant::INT, Variant::QUAT);
+ register_op<OperatorEvaluatorMul<Quat, Quat, double>>(Variant::OP_MULTIPLY, Variant::QUAT, Variant::FLOAT);
+ register_op<OperatorEvaluatorMul<Quat, double, Quat>>(Variant::OP_MULTIPLY, Variant::FLOAT, Variant::QUAT);
+ register_op<OperatorEvaluatorXForm<Vector3, Quat, Vector3>>(Variant::OP_MULTIPLY, Variant::QUAT, Variant::VECTOR3);
+ register_op<OperatorEvaluatorXFormInv<Vector3, Vector3, Quat>>(Variant::OP_MULTIPLY, Variant::VECTOR3, Variant::QUAT);
+
+ register_op<OperatorEvaluatorMul<Color, Color, Color>>(Variant::OP_MULTIPLY, Variant::COLOR, Variant::COLOR);
+ register_op<OperatorEvaluatorMul<Color, Color, int64_t>>(Variant::OP_MULTIPLY, Variant::COLOR, Variant::INT);
+ register_op<OperatorEvaluatorMul<Color, int64_t, Color>>(Variant::OP_MULTIPLY, Variant::INT, Variant::COLOR);
+ register_op<OperatorEvaluatorMul<Color, Color, double>>(Variant::OP_MULTIPLY, Variant::COLOR, Variant::FLOAT);
+ register_op<OperatorEvaluatorMul<Color, double, Color>>(Variant::OP_MULTIPLY, Variant::FLOAT, Variant::COLOR);
+
+ register_op<OperatorEvaluatorDivNZ<int64_t, int64_t, int64_t>>(Variant::OP_DIVIDE, Variant::INT, Variant::INT);
+ register_op<OperatorEvaluatorDiv<double, double, int64_t>>(Variant::OP_DIVIDE, Variant::FLOAT, Variant::INT);
+ register_op<OperatorEvaluatorDiv<double, int64_t, double>>(Variant::OP_DIVIDE, Variant::INT, Variant::FLOAT);
+ register_op<OperatorEvaluatorDiv<double, double, double>>(Variant::OP_DIVIDE, Variant::FLOAT, Variant::FLOAT);
+
+ register_op<OperatorEvaluatorDiv<Vector2, Vector2, Vector2>>(Variant::OP_DIVIDE, Variant::VECTOR2, Variant::VECTOR2);
+ register_op<OperatorEvaluatorDiv<Vector2, Vector2, double>>(Variant::OP_DIVIDE, Variant::VECTOR2, Variant::FLOAT);
+ register_op<OperatorEvaluatorDiv<Vector2, Vector2, int64_t>>(Variant::OP_DIVIDE, Variant::VECTOR2, Variant::INT);
+
+ register_op<OperatorEvaluatorDiv<Vector2i, Vector2i, Vector2i>>(Variant::OP_DIVIDE, Variant::VECTOR2I, Variant::VECTOR2I);
+ register_op<OperatorEvaluatorDivNZ<Vector2i, Vector2i, double>>(Variant::OP_DIVIDE, Variant::VECTOR2I, Variant::FLOAT);
+ register_op<OperatorEvaluatorDivNZ<Vector2i, Vector2i, int64_t>>(Variant::OP_DIVIDE, Variant::VECTOR2I, Variant::INT);
+
+ register_op<OperatorEvaluatorDiv<Vector2, Vector2, Vector2>>(Variant::OP_DIVIDE, Variant::VECTOR2, Variant::VECTOR2);
+ register_op<OperatorEvaluatorDiv<Vector2, Vector2, double>>(Variant::OP_DIVIDE, Variant::VECTOR2, Variant::FLOAT);
+ register_op<OperatorEvaluatorDiv<Vector2, Vector2, int64_t>>(Variant::OP_DIVIDE, Variant::VECTOR2, Variant::INT);
+
+ register_op<OperatorEvaluatorDiv<Vector3, Vector3, Vector3>>(Variant::OP_DIVIDE, Variant::VECTOR3, Variant::VECTOR3);
+ register_op<OperatorEvaluatorDiv<Vector3, Vector3, double>>(Variant::OP_DIVIDE, Variant::VECTOR3, Variant::FLOAT);
+ register_op<OperatorEvaluatorDiv<Vector3, Vector3, int64_t>>(Variant::OP_DIVIDE, Variant::VECTOR3, Variant::INT);
+
+ register_op<OperatorEvaluatorDiv<Vector3i, Vector3i, Vector3i>>(Variant::OP_DIVIDE, Variant::VECTOR3I, Variant::VECTOR3I);
+ register_op<OperatorEvaluatorDivNZ<Vector3i, Vector3i, double>>(Variant::OP_DIVIDE, Variant::VECTOR3I, Variant::FLOAT);
+ register_op<OperatorEvaluatorDivNZ<Vector3i, Vector3i, int64_t>>(Variant::OP_DIVIDE, Variant::VECTOR3I, Variant::INT);
+
+ register_op<OperatorEvaluatorDiv<Quat, Quat, double>>(Variant::OP_DIVIDE, Variant::QUAT, Variant::FLOAT);
+ register_op<OperatorEvaluatorDiv<Quat, Quat, int64_t>>(Variant::OP_DIVIDE, Variant::QUAT, Variant::INT);
+
+ register_op<OperatorEvaluatorDiv<Color, Color, Color>>(Variant::OP_DIVIDE, Variant::COLOR, Variant::COLOR);
+ register_op<OperatorEvaluatorDiv<Color, Color, double>>(Variant::OP_DIVIDE, Variant::COLOR, Variant::FLOAT);
+ register_op<OperatorEvaluatorDiv<Color, Color, int64_t>>(Variant::OP_DIVIDE, Variant::COLOR, Variant::INT);
+
+ register_op<OperatorEvaluatorModNZ<int64_t, int64_t, int64_t>>(Variant::OP_MODULE, Variant::INT, Variant::INT);
+ register_op<OperatorEvaluatorMod<Vector2i, Vector2i, Vector2i>>(Variant::OP_MODULE, Variant::VECTOR2I, Variant::VECTOR2I);
+ register_op<OperatorEvaluatorModNZ<Vector2i, Vector2i, int64_t>>(Variant::OP_MODULE, Variant::VECTOR2I, Variant::INT);
+
+ register_op<OperatorEvaluatorMod<Vector3i, Vector3i, Vector3i>>(Variant::OP_MODULE, Variant::VECTOR3I, Variant::VECTOR3I);
+ register_op<OperatorEvaluatorModNZ<Vector3i, Vector3i, int64_t>>(Variant::OP_MODULE, Variant::VECTOR3I, Variant::INT);
+
+ register_op<OperatorEvaluatorStringModNil>(Variant::OP_MODULE, Variant::STRING, Variant::NIL);
+
+ register_op<OperatorEvaluatorStringModT<bool>>(Variant::OP_MODULE, Variant::STRING, Variant::BOOL);
+ register_op<OperatorEvaluatorStringModT<int64_t>>(Variant::OP_MODULE, Variant::STRING, Variant::INT);
+ register_op<OperatorEvaluatorStringModT<double>>(Variant::OP_MODULE, Variant::STRING, Variant::FLOAT);
+ register_op<OperatorEvaluatorStringModT<String>>(Variant::OP_MODULE, Variant::STRING, Variant::STRING);
+ register_op<OperatorEvaluatorStringModT<Vector2>>(Variant::OP_MODULE, Variant::STRING, Variant::VECTOR2);
+ register_op<OperatorEvaluatorStringModT<Vector2i>>(Variant::OP_MODULE, Variant::STRING, Variant::VECTOR2I);
+ register_op<OperatorEvaluatorStringModT<Rect2>>(Variant::OP_MODULE, Variant::STRING, Variant::RECT2);
+ register_op<OperatorEvaluatorStringModT<Rect2i>>(Variant::OP_MODULE, Variant::STRING, Variant::RECT2I);
+ register_op<OperatorEvaluatorStringModT<Vector3>>(Variant::OP_MODULE, Variant::STRING, Variant::VECTOR3);
+ register_op<OperatorEvaluatorStringModT<Vector3i>>(Variant::OP_MODULE, Variant::STRING, Variant::VECTOR3I);
+ register_op<OperatorEvaluatorStringModT<Transform2D>>(Variant::OP_MODULE, Variant::STRING, Variant::TRANSFORM2D);
+ register_op<OperatorEvaluatorStringModT<Plane>>(Variant::OP_MODULE, Variant::STRING, Variant::PLANE);
+ register_op<OperatorEvaluatorStringModT<Quat>>(Variant::OP_MODULE, Variant::STRING, Variant::QUAT);
+ register_op<OperatorEvaluatorStringModT<::AABB>>(Variant::OP_MODULE, Variant::STRING, Variant::AABB);
+ register_op<OperatorEvaluatorStringModT<Basis>>(Variant::OP_MODULE, Variant::STRING, Variant::BASIS);
+ register_op<OperatorEvaluatorStringModT<Transform>>(Variant::OP_MODULE, Variant::STRING, Variant::TRANSFORM);
+
+ register_op<OperatorEvaluatorStringModT<Color>>(Variant::OP_MODULE, Variant::STRING, Variant::COLOR);
+ register_op<OperatorEvaluatorStringModT<StringName>>(Variant::OP_MODULE, Variant::STRING, Variant::STRING_NAME);
+ register_op<OperatorEvaluatorStringModT<NodePath>>(Variant::OP_MODULE, Variant::STRING, Variant::NODE_PATH);
+ register_op<OperatorEvaluatorStringModObject>(Variant::OP_MODULE, Variant::STRING, Variant::OBJECT);
+ register_op<OperatorEvaluatorStringModT<Callable>>(Variant::OP_MODULE, Variant::STRING, Variant::CALLABLE);
+ register_op<OperatorEvaluatorStringModT<Signal>>(Variant::OP_MODULE, Variant::STRING, Variant::SIGNAL);
+ register_op<OperatorEvaluatorStringModT<Dictionary>>(Variant::OP_MODULE, Variant::STRING, Variant::DICTIONARY);
+ register_op<OperatorEvaluatorStringModArray>(Variant::OP_MODULE, Variant::STRING, Variant::ARRAY);
+
+ register_op<OperatorEvaluatorStringModT<PackedByteArray>>(Variant::OP_MODULE, Variant::STRING, Variant::PACKED_BYTE_ARRAY);
+ register_op<OperatorEvaluatorStringModT<PackedInt32Array>>(Variant::OP_MODULE, Variant::STRING, Variant::PACKED_INT32_ARRAY);
+ register_op<OperatorEvaluatorStringModT<PackedInt64Array>>(Variant::OP_MODULE, Variant::STRING, Variant::PACKED_INT64_ARRAY);
+ register_op<OperatorEvaluatorStringModT<PackedFloat32Array>>(Variant::OP_MODULE, Variant::STRING, Variant::PACKED_FLOAT32_ARRAY);
+ register_op<OperatorEvaluatorStringModT<PackedFloat64Array>>(Variant::OP_MODULE, Variant::STRING, Variant::PACKED_FLOAT64_ARRAY);
+ register_op<OperatorEvaluatorStringModT<PackedStringArray>>(Variant::OP_MODULE, Variant::STRING, Variant::PACKED_STRING_ARRAY);
+ register_op<OperatorEvaluatorStringModT<PackedVector2Array>>(Variant::OP_MODULE, Variant::STRING, Variant::PACKED_VECTOR2_ARRAY);
+ register_op<OperatorEvaluatorStringModT<PackedVector3Array>>(Variant::OP_MODULE, Variant::STRING, Variant::PACKED_VECTOR3_ARRAY);
+ register_op<OperatorEvaluatorStringModT<PackedColorArray>>(Variant::OP_MODULE, Variant::STRING, Variant::PACKED_COLOR_ARRAY);
+
+ register_op<OperatorEvaluatorNeg<int64_t, int64_t>>(Variant::OP_NEGATE, Variant::INT, Variant::NIL);
+ register_op<OperatorEvaluatorNeg<double, double>>(Variant::OP_NEGATE, Variant::FLOAT, Variant::NIL);
+ register_op<OperatorEvaluatorNeg<Vector2, Vector2>>(Variant::OP_NEGATE, Variant::VECTOR2, Variant::NIL);
+ register_op<OperatorEvaluatorNeg<Vector2i, Vector2i>>(Variant::OP_NEGATE, Variant::VECTOR2I, Variant::NIL);
+ register_op<OperatorEvaluatorNeg<Vector3, Vector3>>(Variant::OP_NEGATE, Variant::VECTOR3, Variant::NIL);
+ register_op<OperatorEvaluatorNeg<Vector3i, Vector3i>>(Variant::OP_NEGATE, Variant::VECTOR3I, Variant::NIL);
+ register_op<OperatorEvaluatorNeg<Quat, Quat>>(Variant::OP_NEGATE, Variant::QUAT, Variant::NIL);
+ register_op<OperatorEvaluatorNeg<Plane, Plane>>(Variant::OP_NEGATE, Variant::PLANE, Variant::NIL);
+ register_op<OperatorEvaluatorNeg<Color, Color>>(Variant::OP_NEGATE, Variant::COLOR, Variant::NIL);
+
+ register_op<OperatorEvaluatorPos<int64_t, int64_t>>(Variant::OP_POSITIVE, Variant::INT, Variant::NIL);
+ register_op<OperatorEvaluatorPos<double, double>>(Variant::OP_POSITIVE, Variant::FLOAT, Variant::NIL);
+ register_op<OperatorEvaluatorPos<Vector2, Vector2>>(Variant::OP_POSITIVE, Variant::VECTOR2, Variant::NIL);
+ register_op<OperatorEvaluatorPos<Vector2i, Vector2i>>(Variant::OP_POSITIVE, Variant::VECTOR2I, Variant::NIL);
+ register_op<OperatorEvaluatorPos<Vector3, Vector3>>(Variant::OP_POSITIVE, Variant::VECTOR3, Variant::NIL);
+ register_op<OperatorEvaluatorPos<Vector3i, Vector3i>>(Variant::OP_POSITIVE, Variant::VECTOR3I, Variant::NIL);
+ register_op<OperatorEvaluatorPos<Quat, Quat>>(Variant::OP_POSITIVE, Variant::QUAT, Variant::NIL);
+ register_op<OperatorEvaluatorPos<Plane, Plane>>(Variant::OP_POSITIVE, Variant::PLANE, Variant::NIL);
+ register_op<OperatorEvaluatorPos<Color, Color>>(Variant::OP_POSITIVE, Variant::COLOR, Variant::NIL);
+
+ register_op<OperatorEvaluatorShiftLeft<int64_t, int64_t, int64_t>>(Variant::OP_SHIFT_LEFT, Variant::INT, Variant::INT);
+ register_op<OperatorEvaluatorShiftRight<int64_t, int64_t, int64_t>>(Variant::OP_SHIFT_RIGHT, Variant::INT, Variant::INT);
+ register_op<OperatorEvaluatorBitOr<int64_t, int64_t, int64_t>>(Variant::OP_BIT_OR, Variant::INT, Variant::INT);
+ register_op<OperatorEvaluatorBitAnd<int64_t, int64_t, int64_t>>(Variant::OP_BIT_AND, Variant::INT, Variant::INT);
+ register_op<OperatorEvaluatorBitXor<int64_t, int64_t, int64_t>>(Variant::OP_BIT_XOR, Variant::INT, Variant::INT);
+ register_op<OperatorEvaluatorBitNeg<int64_t, int64_t>>(Variant::OP_BIT_NEGATE, Variant::INT, Variant::NIL);
+
+ register_op<OperatorEvaluatorBitNeg<int64_t, int64_t>>(Variant::OP_BIT_NEGATE, Variant::INT, Variant::NIL);
+
+ register_op<OperatorEvaluatorAlwaysTrue<Variant::OP_EQUAL, Variant::NIL, Variant::NIL>>(Variant::OP_EQUAL, Variant::NIL, Variant::NIL);
+ register_op<OperatorEvaluatorEqual<bool, bool>>(Variant::OP_EQUAL, Variant::BOOL, Variant::BOOL);
+ register_op<OperatorEvaluatorEqual<int64_t, int64_t>>(Variant::OP_EQUAL, Variant::INT, Variant::INT);
+ register_op<OperatorEvaluatorEqual<int64_t, double>>(Variant::OP_EQUAL, Variant::INT, Variant::FLOAT);
+ register_op<OperatorEvaluatorEqual<double, int64_t>>(Variant::OP_EQUAL, Variant::FLOAT, Variant::INT);
+ register_op<OperatorEvaluatorEqual<double, double>>(Variant::OP_EQUAL, Variant::FLOAT, Variant::FLOAT);
+ register_op<OperatorEvaluatorEqual<String, String>>(Variant::OP_EQUAL, Variant::STRING, Variant::STRING);
+ register_op<OperatorEvaluatorEqual<Vector2, Vector2>>(Variant::OP_EQUAL, Variant::VECTOR2, Variant::VECTOR2);
+ register_op<OperatorEvaluatorEqual<Vector2i, Vector2i>>(Variant::OP_EQUAL, Variant::VECTOR2I, Variant::VECTOR2I);
+ register_op<OperatorEvaluatorEqual<Rect2, Rect2>>(Variant::OP_EQUAL, Variant::RECT2, Variant::RECT2);
+ register_op<OperatorEvaluatorEqual<Rect2i, Rect2i>>(Variant::OP_EQUAL, Variant::RECT2I, Variant::RECT2I);
+ register_op<OperatorEvaluatorEqual<Vector3, Vector3>>(Variant::OP_EQUAL, Variant::VECTOR3, Variant::VECTOR3);
+ register_op<OperatorEvaluatorEqual<Vector3i, Vector3i>>(Variant::OP_EQUAL, Variant::VECTOR3I, Variant::VECTOR3I);
+ register_op<OperatorEvaluatorEqual<Transform2D, Transform2D>>(Variant::OP_EQUAL, Variant::TRANSFORM2D, Variant::TRANSFORM2D);
+ register_op<OperatorEvaluatorEqual<Plane, Plane>>(Variant::OP_EQUAL, Variant::PLANE, Variant::PLANE);
+ register_op<OperatorEvaluatorEqual<Quat, Quat>>(Variant::OP_EQUAL, Variant::QUAT, Variant::QUAT);
+ register_op<OperatorEvaluatorEqual<::AABB, ::AABB>>(Variant::OP_EQUAL, Variant::AABB, Variant::AABB);
+ register_op<OperatorEvaluatorEqual<Basis, Basis>>(Variant::OP_EQUAL, Variant::BASIS, Variant::BASIS);
+ register_op<OperatorEvaluatorEqual<Transform, Transform>>(Variant::OP_EQUAL, Variant::TRANSFORM, Variant::TRANSFORM);
+ register_op<OperatorEvaluatorEqual<Color, Color>>(Variant::OP_EQUAL, Variant::COLOR, Variant::COLOR);
+
+ register_op<OperatorEvaluatorEqual<StringName, String>>(Variant::OP_EQUAL, Variant::STRING_NAME, Variant::STRING);
+ register_op<OperatorEvaluatorEqual<String, StringName>>(Variant::OP_EQUAL, Variant::STRING, Variant::STRING_NAME);
+ register_op<OperatorEvaluatorEqual<StringName, StringName>>(Variant::OP_EQUAL, Variant::STRING_NAME, Variant::STRING_NAME);
+
+ register_op<OperatorEvaluatorEqual<NodePath, NodePath>>(Variant::OP_EQUAL, Variant::NODE_PATH, Variant::NODE_PATH);
+ register_op<OperatorEvaluatorEqual<::RID, ::RID>>(Variant::OP_EQUAL, Variant::RID, Variant::RID);
+
+ register_op<OperatorEvaluatorEqualObject>(Variant::OP_EQUAL, Variant::OBJECT, Variant::OBJECT);
+ register_op<OperatorEvaluatorEqualObjectNil>(Variant::OP_EQUAL, Variant::OBJECT, Variant::NIL);
+ register_op<OperatorEvaluatorEqualNilObject>(Variant::OP_EQUAL, Variant::NIL, Variant::OBJECT);
+
+ register_op<OperatorEvaluatorEqual<Callable, Callable>>(Variant::OP_EQUAL, Variant::CALLABLE, Variant::CALLABLE);
+ register_op<OperatorEvaluatorEqual<Signal, Signal>>(Variant::OP_EQUAL, Variant::SIGNAL, Variant::SIGNAL);
+ register_op<OperatorEvaluatorEqual<Dictionary, Dictionary>>(Variant::OP_EQUAL, Variant::DICTIONARY, Variant::DICTIONARY);
+ register_op<OperatorEvaluatorEqual<Array, Array>>(Variant::OP_EQUAL, Variant::ARRAY, Variant::ARRAY);
+ register_op<OperatorEvaluatorEqual<PackedByteArray, PackedByteArray>>(Variant::OP_EQUAL, Variant::PACKED_BYTE_ARRAY, Variant::PACKED_BYTE_ARRAY);
+ register_op<OperatorEvaluatorEqual<PackedInt32Array, PackedInt32Array>>(Variant::OP_EQUAL, Variant::PACKED_INT32_ARRAY, Variant::PACKED_INT32_ARRAY);
+ register_op<OperatorEvaluatorEqual<PackedInt64Array, PackedInt64Array>>(Variant::OP_EQUAL, Variant::PACKED_INT64_ARRAY, Variant::PACKED_INT64_ARRAY);
+ register_op<OperatorEvaluatorEqual<PackedFloat32Array, PackedFloat32Array>>(Variant::OP_EQUAL, Variant::PACKED_FLOAT32_ARRAY, Variant::PACKED_FLOAT32_ARRAY);
+ register_op<OperatorEvaluatorEqual<PackedFloat64Array, PackedFloat64Array>>(Variant::OP_EQUAL, Variant::PACKED_FLOAT64_ARRAY, Variant::PACKED_FLOAT64_ARRAY);
+ register_op<OperatorEvaluatorEqual<PackedStringArray, PackedStringArray>>(Variant::OP_EQUAL, Variant::PACKED_STRING_ARRAY, Variant::PACKED_STRING_ARRAY);
+ register_op<OperatorEvaluatorEqual<PackedVector2Array, PackedVector2Array>>(Variant::OP_EQUAL, Variant::PACKED_VECTOR2_ARRAY, Variant::PACKED_VECTOR2_ARRAY);
+ register_op<OperatorEvaluatorEqual<PackedVector3Array, PackedVector3Array>>(Variant::OP_EQUAL, Variant::PACKED_VECTOR3_ARRAY, Variant::PACKED_VECTOR3_ARRAY);
+ register_op<OperatorEvaluatorEqual<PackedColorArray, PackedColorArray>>(Variant::OP_EQUAL, Variant::PACKED_COLOR_ARRAY, Variant::PACKED_COLOR_ARRAY);
+
+ register_op<OperatorEvaluatorAlwaysFalse<Variant::OP_NOT_EQUAL, Variant::NIL, Variant::NIL>>(Variant::OP_NOT_EQUAL, Variant::NIL, Variant::NIL);
+ register_op<OperatorEvaluatorNotEqual<bool, bool>>(Variant::OP_NOT_EQUAL, Variant::BOOL, Variant::BOOL);
+ register_op<OperatorEvaluatorNotEqual<int64_t, int64_t>>(Variant::OP_NOT_EQUAL, Variant::INT, Variant::INT);
+ register_op<OperatorEvaluatorNotEqual<int64_t, double>>(Variant::OP_NOT_EQUAL, Variant::INT, Variant::FLOAT);
+ register_op<OperatorEvaluatorNotEqual<double, int64_t>>(Variant::OP_NOT_EQUAL, Variant::FLOAT, Variant::INT);
+ register_op<OperatorEvaluatorNotEqual<double, double>>(Variant::OP_NOT_EQUAL, Variant::FLOAT, Variant::FLOAT);
+ register_op<OperatorEvaluatorNotEqual<String, String>>(Variant::OP_NOT_EQUAL, Variant::STRING, Variant::STRING);
+ register_op<OperatorEvaluatorNotEqual<Vector2, Vector2>>(Variant::OP_NOT_EQUAL, Variant::VECTOR2, Variant::VECTOR2);
+ register_op<OperatorEvaluatorNotEqual<Vector2i, Vector2i>>(Variant::OP_NOT_EQUAL, Variant::VECTOR2I, Variant::VECTOR2I);
+ register_op<OperatorEvaluatorNotEqual<Rect2, Rect2>>(Variant::OP_NOT_EQUAL, Variant::RECT2, Variant::RECT2);
+ register_op<OperatorEvaluatorNotEqual<Rect2i, Rect2i>>(Variant::OP_NOT_EQUAL, Variant::RECT2I, Variant::RECT2I);
+ register_op<OperatorEvaluatorNotEqual<Vector3, Vector3>>(Variant::OP_NOT_EQUAL, Variant::VECTOR3, Variant::VECTOR3);
+ register_op<OperatorEvaluatorNotEqual<Vector3i, Vector3i>>(Variant::OP_NOT_EQUAL, Variant::VECTOR3I, Variant::VECTOR3I);
+ register_op<OperatorEvaluatorNotEqual<Transform2D, Transform2D>>(Variant::OP_NOT_EQUAL, Variant::TRANSFORM2D, Variant::TRANSFORM2D);
+ register_op<OperatorEvaluatorNotEqual<Plane, Plane>>(Variant::OP_NOT_EQUAL, Variant::PLANE, Variant::PLANE);
+ register_op<OperatorEvaluatorNotEqual<Quat, Quat>>(Variant::OP_NOT_EQUAL, Variant::QUAT, Variant::QUAT);
+ register_op<OperatorEvaluatorNotEqual<::AABB, ::AABB>>(Variant::OP_NOT_EQUAL, Variant::AABB, Variant::AABB);
+ register_op<OperatorEvaluatorNotEqual<Basis, Basis>>(Variant::OP_NOT_EQUAL, Variant::BASIS, Variant::BASIS);
+ register_op<OperatorEvaluatorNotEqual<Transform, Transform>>(Variant::OP_NOT_EQUAL, Variant::TRANSFORM, Variant::TRANSFORM);
+ register_op<OperatorEvaluatorNotEqual<Color, Color>>(Variant::OP_NOT_EQUAL, Variant::COLOR, Variant::COLOR);
+
+ register_op<OperatorEvaluatorNotEqual<StringName, String>>(Variant::OP_NOT_EQUAL, Variant::STRING_NAME, Variant::STRING);
+ register_op<OperatorEvaluatorNotEqual<String, StringName>>(Variant::OP_NOT_EQUAL, Variant::STRING, Variant::STRING_NAME);
+ register_op<OperatorEvaluatorNotEqual<StringName, StringName>>(Variant::OP_NOT_EQUAL, Variant::STRING_NAME, Variant::STRING_NAME);
+
+ register_op<OperatorEvaluatorNotEqual<NodePath, NodePath>>(Variant::OP_NOT_EQUAL, Variant::NODE_PATH, Variant::NODE_PATH);
+ register_op<OperatorEvaluatorNotEqual<::RID, ::RID>>(Variant::OP_NOT_EQUAL, Variant::RID, Variant::RID);
+
+ register_op<OperatorEvaluatorNotEqualObject>(Variant::OP_NOT_EQUAL, Variant::OBJECT, Variant::OBJECT);
+ register_op<OperatorEvaluatorNotEqualObjectNil>(Variant::OP_NOT_EQUAL, Variant::OBJECT, Variant::NIL);
+ register_op<OperatorEvaluatorNotEqualNilObject>(Variant::OP_NOT_EQUAL, Variant::NIL, Variant::OBJECT);
+
+ register_op<OperatorEvaluatorNotEqual<Callable, Callable>>(Variant::OP_NOT_EQUAL, Variant::CALLABLE, Variant::CALLABLE);
+ register_op<OperatorEvaluatorNotEqual<Signal, Signal>>(Variant::OP_NOT_EQUAL, Variant::SIGNAL, Variant::SIGNAL);
+ register_op<OperatorEvaluatorNotEqual<Dictionary, Dictionary>>(Variant::OP_NOT_EQUAL, Variant::DICTIONARY, Variant::DICTIONARY);
+ register_op<OperatorEvaluatorNotEqual<Array, Array>>(Variant::OP_NOT_EQUAL, Variant::ARRAY, Variant::ARRAY);
+ register_op<OperatorEvaluatorNotEqual<PackedByteArray, PackedByteArray>>(Variant::OP_NOT_EQUAL, Variant::PACKED_BYTE_ARRAY, Variant::PACKED_BYTE_ARRAY);
+ register_op<OperatorEvaluatorNotEqual<PackedInt32Array, PackedInt32Array>>(Variant::OP_NOT_EQUAL, Variant::PACKED_INT32_ARRAY, Variant::PACKED_INT32_ARRAY);
+ register_op<OperatorEvaluatorNotEqual<PackedInt64Array, PackedInt64Array>>(Variant::OP_NOT_EQUAL, Variant::PACKED_INT64_ARRAY, Variant::PACKED_INT64_ARRAY);
+ register_op<OperatorEvaluatorNotEqual<PackedFloat32Array, PackedFloat32Array>>(Variant::OP_NOT_EQUAL, Variant::PACKED_FLOAT32_ARRAY, Variant::PACKED_FLOAT32_ARRAY);
+ register_op<OperatorEvaluatorNotEqual<PackedFloat64Array, PackedFloat64Array>>(Variant::OP_NOT_EQUAL, Variant::PACKED_FLOAT64_ARRAY, Variant::PACKED_FLOAT64_ARRAY);
+ register_op<OperatorEvaluatorNotEqual<PackedStringArray, PackedStringArray>>(Variant::OP_NOT_EQUAL, Variant::PACKED_STRING_ARRAY, Variant::PACKED_STRING_ARRAY);
+ register_op<OperatorEvaluatorNotEqual<PackedVector2Array, PackedVector2Array>>(Variant::OP_NOT_EQUAL, Variant::PACKED_VECTOR2_ARRAY, Variant::PACKED_VECTOR2_ARRAY);
+ register_op<OperatorEvaluatorNotEqual<PackedVector3Array, PackedVector3Array>>(Variant::OP_NOT_EQUAL, Variant::PACKED_VECTOR3_ARRAY, Variant::PACKED_VECTOR3_ARRAY);
+ register_op<OperatorEvaluatorNotEqual<PackedColorArray, PackedColorArray>>(Variant::OP_NOT_EQUAL, Variant::PACKED_COLOR_ARRAY, Variant::PACKED_COLOR_ARRAY);
+
+ register_op<OperatorEvaluatorLess<bool, bool>>(Variant::OP_LESS, Variant::BOOL, Variant::BOOL);
+ register_op<OperatorEvaluatorLess<int64_t, int64_t>>(Variant::OP_LESS, Variant::INT, Variant::INT);
+ register_op<OperatorEvaluatorLess<int64_t, double>>(Variant::OP_LESS, Variant::INT, Variant::FLOAT);
+ register_op<OperatorEvaluatorLess<double, int64_t>>(Variant::OP_LESS, Variant::FLOAT, Variant::INT);
+ register_op<OperatorEvaluatorLess<double, double>>(Variant::OP_LESS, Variant::FLOAT, Variant::FLOAT);
+ register_op<OperatorEvaluatorLess<String, String>>(Variant::OP_LESS, Variant::STRING, Variant::STRING);
+ register_op<OperatorEvaluatorLess<Vector2, Vector2>>(Variant::OP_LESS, Variant::VECTOR2, Variant::VECTOR2);
+ register_op<OperatorEvaluatorLess<Vector2i, Vector2i>>(Variant::OP_LESS, Variant::VECTOR2I, Variant::VECTOR2I);
+ register_op<OperatorEvaluatorLess<Vector3, Vector3>>(Variant::OP_LESS, Variant::VECTOR3, Variant::VECTOR3);
+ register_op<OperatorEvaluatorLess<Vector3i, Vector3i>>(Variant::OP_LESS, Variant::VECTOR3I, Variant::VECTOR3I);
+ register_op<OperatorEvaluatorLess<::RID, ::RID>>(Variant::OP_LESS, Variant::RID, Variant::RID);
+ register_op<OperatorEvaluatorLess<Array, Array>>(Variant::OP_LESS, Variant::ARRAY, Variant::ARRAY);
+
+ register_op<OperatorEvaluatorLessEqual<int64_t, int64_t>>(Variant::OP_LESS_EQUAL, Variant::INT, Variant::INT);
+ register_op<OperatorEvaluatorLessEqual<int64_t, double>>(Variant::OP_LESS_EQUAL, Variant::INT, Variant::FLOAT);
+ register_op<OperatorEvaluatorLessEqual<double, int64_t>>(Variant::OP_LESS_EQUAL, Variant::FLOAT, Variant::INT);
+ register_op<OperatorEvaluatorLessEqual<double, double>>(Variant::OP_LESS_EQUAL, Variant::FLOAT, Variant::FLOAT);
+ register_op<OperatorEvaluatorLessEqual<String, String>>(Variant::OP_LESS_EQUAL, Variant::STRING, Variant::STRING);
+ register_op<OperatorEvaluatorLessEqual<Vector2, Vector2>>(Variant::OP_LESS_EQUAL, Variant::VECTOR2, Variant::VECTOR2);
+ register_op<OperatorEvaluatorLessEqual<Vector2i, Vector2i>>(Variant::OP_LESS_EQUAL, Variant::VECTOR2I, Variant::VECTOR2I);
+ register_op<OperatorEvaluatorLessEqual<Vector3, Vector3>>(Variant::OP_LESS_EQUAL, Variant::VECTOR3, Variant::VECTOR3);
+ register_op<OperatorEvaluatorLessEqual<Vector3i, Vector3i>>(Variant::OP_LESS_EQUAL, Variant::VECTOR3I, Variant::VECTOR3I);
+ register_op<OperatorEvaluatorLessEqual<::RID, ::RID>>(Variant::OP_LESS_EQUAL, Variant::RID, Variant::RID);
+ register_op<OperatorEvaluatorLessEqual<Array, Array>>(Variant::OP_LESS_EQUAL, Variant::ARRAY, Variant::ARRAY);
+
+ register_op<OperatorEvaluatorGreater<bool, bool>>(Variant::OP_GREATER, Variant::BOOL, Variant::BOOL);
+ register_op<OperatorEvaluatorGreater<int64_t, int64_t>>(Variant::OP_GREATER, Variant::INT, Variant::INT);
+ register_op<OperatorEvaluatorGreater<int64_t, double>>(Variant::OP_GREATER, Variant::INT, Variant::FLOAT);
+ register_op<OperatorEvaluatorGreater<double, int64_t>>(Variant::OP_GREATER, Variant::FLOAT, Variant::INT);
+ register_op<OperatorEvaluatorGreater<double, double>>(Variant::OP_GREATER, Variant::FLOAT, Variant::FLOAT);
+ register_op<OperatorEvaluatorGreater<String, String>>(Variant::OP_GREATER, Variant::STRING, Variant::STRING);
+ register_op<OperatorEvaluatorGreater<Vector2, Vector2>>(Variant::OP_GREATER, Variant::VECTOR2, Variant::VECTOR2);
+ register_op<OperatorEvaluatorGreater<Vector2i, Vector2i>>(Variant::OP_GREATER, Variant::VECTOR2I, Variant::VECTOR2I);
+ register_op<OperatorEvaluatorGreater<Vector3, Vector3>>(Variant::OP_GREATER, Variant::VECTOR3, Variant::VECTOR3);
+ register_op<OperatorEvaluatorGreater<Vector3i, Vector3i>>(Variant::OP_GREATER, Variant::VECTOR3I, Variant::VECTOR3I);
+ register_op<OperatorEvaluatorGreater<::RID, ::RID>>(Variant::OP_GREATER, Variant::RID, Variant::RID);
+ register_op<OperatorEvaluatorGreater<Array, Array>>(Variant::OP_GREATER, Variant::ARRAY, Variant::ARRAY);
+
+ register_op<OperatorEvaluatorGreaterEqual<int64_t, int64_t>>(Variant::OP_GREATER_EQUAL, Variant::INT, Variant::INT);
+ register_op<OperatorEvaluatorGreaterEqual<int64_t, double>>(Variant::OP_GREATER_EQUAL, Variant::INT, Variant::FLOAT);
+ register_op<OperatorEvaluatorGreaterEqual<double, int64_t>>(Variant::OP_GREATER_EQUAL, Variant::FLOAT, Variant::INT);
+ register_op<OperatorEvaluatorGreaterEqual<double, double>>(Variant::OP_GREATER_EQUAL, Variant::FLOAT, Variant::FLOAT);
+ register_op<OperatorEvaluatorGreaterEqual<String, String>>(Variant::OP_GREATER_EQUAL, Variant::STRING, Variant::STRING);
+ register_op<OperatorEvaluatorGreaterEqual<Vector2, Vector2>>(Variant::OP_GREATER_EQUAL, Variant::VECTOR2, Variant::VECTOR2);
+ register_op<OperatorEvaluatorGreaterEqual<Vector2i, Vector2i>>(Variant::OP_GREATER_EQUAL, Variant::VECTOR2I, Variant::VECTOR2I);
+ register_op<OperatorEvaluatorGreaterEqual<Vector3, Vector3>>(Variant::OP_GREATER_EQUAL, Variant::VECTOR3, Variant::VECTOR3);
+ register_op<OperatorEvaluatorGreaterEqual<Vector3i, Vector3i>>(Variant::OP_GREATER_EQUAL, Variant::VECTOR3I, Variant::VECTOR3I);
+ register_op<OperatorEvaluatorGreaterEqual<::RID, ::RID>>(Variant::OP_GREATER_EQUAL, Variant::RID, Variant::RID);
+ register_op<OperatorEvaluatorGreaterEqual<Array, Array>>(Variant::OP_GREATER_EQUAL, Variant::ARRAY, Variant::ARRAY);
+
+ register_op<OperatorEvaluatorAlwaysFalse<Variant::OP_OR, Variant::NIL, Variant::NIL>>(Variant::OP_OR, Variant::NIL, Variant::NIL);
+
+ // OR
+ register_op<OperatorEvaluatorNilXBoolOr>(Variant::OP_OR, Variant::NIL, Variant::BOOL);
+ register_op<OperatorEvaluatorBoolXNilOr>(Variant::OP_OR, Variant::BOOL, Variant::NIL);
+ register_op<OperatorEvaluatorNilXIntOr>(Variant::OP_OR, Variant::NIL, Variant::INT);
+ register_op<OperatorEvaluatorIntXNilOr>(Variant::OP_OR, Variant::INT, Variant::NIL);
+ register_op<OperatorEvaluatorNilXFloatOr>(Variant::OP_OR, Variant::NIL, Variant::FLOAT);
+ register_op<OperatorEvaluatorFloatXNilOr>(Variant::OP_OR, Variant::FLOAT, Variant::NIL);
+ register_op<OperatorEvaluatorNilXObjectOr>(Variant::OP_OR, Variant::NIL, Variant::OBJECT);
+ register_op<OperatorEvaluatorObjectXNilOr>(Variant::OP_OR, Variant::OBJECT, Variant::NIL);
+
+ register_op<OperatorEvaluatorBoolXBoolOr>(Variant::OP_OR, Variant::BOOL, Variant::BOOL);
+ register_op<OperatorEvaluatorBoolXIntOr>(Variant::OP_OR, Variant::BOOL, Variant::INT);
+ register_op<OperatorEvaluatorIntXBoolOr>(Variant::OP_OR, Variant::INT, Variant::BOOL);
+ register_op<OperatorEvaluatorBoolXFloatOr>(Variant::OP_OR, Variant::BOOL, Variant::FLOAT);
+ register_op<OperatorEvaluatorFloatXBoolOr>(Variant::OP_OR, Variant::FLOAT, Variant::BOOL);
+ register_op<OperatorEvaluatorBoolXObjectOr>(Variant::OP_OR, Variant::BOOL, Variant::OBJECT);
+ register_op<OperatorEvaluatorObjectXBoolOr>(Variant::OP_OR, Variant::OBJECT, Variant::BOOL);
+
+ register_op<OperatorEvaluatorIntXIntOr>(Variant::OP_OR, Variant::INT, Variant::INT);
+ register_op<OperatorEvaluatorIntXFloatOr>(Variant::OP_OR, Variant::INT, Variant::FLOAT);
+ register_op<OperatorEvaluatorFloatXIntOr>(Variant::OP_OR, Variant::FLOAT, Variant::INT);
+ register_op<OperatorEvaluatorIntXObjectOr>(Variant::OP_OR, Variant::INT, Variant::OBJECT);
+ register_op<OperatorEvaluatorObjectXIntOr>(Variant::OP_OR, Variant::OBJECT, Variant::INT);
+
+ register_op<OperatorEvaluatorFloatXFloatOr>(Variant::OP_OR, Variant::FLOAT, Variant::FLOAT);
+ register_op<OperatorEvaluatorFloatXObjectOr>(Variant::OP_OR, Variant::FLOAT, Variant::OBJECT);
+ register_op<OperatorEvaluatorObjectXFloatOr>(Variant::OP_OR, Variant::OBJECT, Variant::FLOAT);
+ register_op<OperatorEvaluatorObjectXObjectOr>(Variant::OP_OR, Variant::OBJECT, Variant::OBJECT);
+
+ // AND
+ register_op<OperatorEvaluatorNilXBoolAnd>(Variant::OP_AND, Variant::NIL, Variant::BOOL);
+ register_op<OperatorEvaluatorBoolXNilAnd>(Variant::OP_AND, Variant::BOOL, Variant::NIL);
+ register_op<OperatorEvaluatorNilXIntAnd>(Variant::OP_AND, Variant::NIL, Variant::INT);
+ register_op<OperatorEvaluatorIntXNilAnd>(Variant::OP_AND, Variant::INT, Variant::NIL);
+ register_op<OperatorEvaluatorNilXFloatAnd>(Variant::OP_AND, Variant::NIL, Variant::FLOAT);
+ register_op<OperatorEvaluatorFloatXNilAnd>(Variant::OP_AND, Variant::FLOAT, Variant::NIL);
+ register_op<OperatorEvaluatorNilXObjectAnd>(Variant::OP_AND, Variant::NIL, Variant::OBJECT);
+ register_op<OperatorEvaluatorObjectXNilAnd>(Variant::OP_AND, Variant::OBJECT, Variant::NIL);
+
+ register_op<OperatorEvaluatorBoolXBoolAnd>(Variant::OP_AND, Variant::BOOL, Variant::BOOL);
+ register_op<OperatorEvaluatorBoolXIntAnd>(Variant::OP_AND, Variant::BOOL, Variant::INT);
+ register_op<OperatorEvaluatorIntXBoolAnd>(Variant::OP_AND, Variant::INT, Variant::BOOL);
+ register_op<OperatorEvaluatorBoolXFloatAnd>(Variant::OP_AND, Variant::BOOL, Variant::FLOAT);
+ register_op<OperatorEvaluatorFloatXBoolAnd>(Variant::OP_AND, Variant::FLOAT, Variant::BOOL);
+ register_op<OperatorEvaluatorBoolXObjectAnd>(Variant::OP_AND, Variant::BOOL, Variant::OBJECT);
+ register_op<OperatorEvaluatorObjectXBoolAnd>(Variant::OP_AND, Variant::OBJECT, Variant::BOOL);
+
+ register_op<OperatorEvaluatorIntXIntAnd>(Variant::OP_AND, Variant::INT, Variant::INT);
+ register_op<OperatorEvaluatorIntXFloatAnd>(Variant::OP_AND, Variant::INT, Variant::FLOAT);
+ register_op<OperatorEvaluatorFloatXIntAnd>(Variant::OP_AND, Variant::FLOAT, Variant::INT);
+ register_op<OperatorEvaluatorIntXObjectAnd>(Variant::OP_AND, Variant::INT, Variant::OBJECT);
+ register_op<OperatorEvaluatorObjectXIntAnd>(Variant::OP_AND, Variant::OBJECT, Variant::INT);
+
+ register_op<OperatorEvaluatorFloatXFloatAnd>(Variant::OP_AND, Variant::FLOAT, Variant::FLOAT);
+ register_op<OperatorEvaluatorFloatXObjectAnd>(Variant::OP_AND, Variant::FLOAT, Variant::OBJECT);
+ register_op<OperatorEvaluatorObjectXFloatAnd>(Variant::OP_AND, Variant::OBJECT, Variant::FLOAT);
+ register_op<OperatorEvaluatorObjectXObjectAnd>(Variant::OP_AND, Variant::OBJECT, Variant::OBJECT);
+
+ // XOR
+ register_op<OperatorEvaluatorNilXBoolXor>(Variant::OP_XOR, Variant::NIL, Variant::BOOL);
+ register_op<OperatorEvaluatorBoolXNilXor>(Variant::OP_XOR, Variant::BOOL, Variant::NIL);
+ register_op<OperatorEvaluatorNilXIntXor>(Variant::OP_XOR, Variant::NIL, Variant::INT);
+ register_op<OperatorEvaluatorIntXNilXor>(Variant::OP_XOR, Variant::INT, Variant::NIL);
+ register_op<OperatorEvaluatorNilXFloatXor>(Variant::OP_XOR, Variant::NIL, Variant::FLOAT);
+ register_op<OperatorEvaluatorFloatXNilXor>(Variant::OP_XOR, Variant::FLOAT, Variant::NIL);
+ register_op<OperatorEvaluatorNilXObjectXor>(Variant::OP_XOR, Variant::NIL, Variant::OBJECT);
+ register_op<OperatorEvaluatorObjectXNilXor>(Variant::OP_XOR, Variant::OBJECT, Variant::NIL);
+
+ register_op<OperatorEvaluatorBoolXBoolXor>(Variant::OP_XOR, Variant::BOOL, Variant::BOOL);
+ register_op<OperatorEvaluatorBoolXIntXor>(Variant::OP_XOR, Variant::BOOL, Variant::INT);
+ register_op<OperatorEvaluatorIntXBoolXor>(Variant::OP_XOR, Variant::INT, Variant::BOOL);
+ register_op<OperatorEvaluatorBoolXFloatXor>(Variant::OP_XOR, Variant::BOOL, Variant::FLOAT);
+ register_op<OperatorEvaluatorFloatXBoolXor>(Variant::OP_XOR, Variant::FLOAT, Variant::BOOL);
+ register_op<OperatorEvaluatorBoolXObjectXor>(Variant::OP_XOR, Variant::BOOL, Variant::OBJECT);
+ register_op<OperatorEvaluatorObjectXBoolXor>(Variant::OP_XOR, Variant::OBJECT, Variant::BOOL);
+
+ register_op<OperatorEvaluatorIntXIntXor>(Variant::OP_XOR, Variant::INT, Variant::INT);
+ register_op<OperatorEvaluatorIntXFloatXor>(Variant::OP_XOR, Variant::INT, Variant::FLOAT);
+ register_op<OperatorEvaluatorFloatXIntXor>(Variant::OP_XOR, Variant::FLOAT, Variant::INT);
+ register_op<OperatorEvaluatorIntXObjectXor>(Variant::OP_XOR, Variant::INT, Variant::OBJECT);
+ register_op<OperatorEvaluatorObjectXIntXor>(Variant::OP_XOR, Variant::OBJECT, Variant::INT);
+
+ register_op<OperatorEvaluatorFloatXFloatXor>(Variant::OP_XOR, Variant::FLOAT, Variant::FLOAT);
+ register_op<OperatorEvaluatorFloatXObjectXor>(Variant::OP_XOR, Variant::FLOAT, Variant::OBJECT);
+ register_op<OperatorEvaluatorObjectXFloatXor>(Variant::OP_XOR, Variant::OBJECT, Variant::FLOAT);
+ register_op<OperatorEvaluatorObjectXObjectXor>(Variant::OP_XOR, Variant::OBJECT, Variant::OBJECT);
+
+ register_op<OperatorEvaluatorAlwaysTrue<Variant::OP_NOT, Variant::NIL, Variant::NIL>>(Variant::OP_NOT, Variant::NIL, Variant::NIL);
+ register_op<OperatorEvaluatorNotBool>(Variant::OP_NOT, Variant::BOOL, Variant::NIL);
+ register_op<OperatorEvaluatorNotInt>(Variant::OP_NOT, Variant::INT, Variant::NIL);
+ register_op<OperatorEvaluatorNotFloat>(Variant::OP_NOT, Variant::FLOAT, Variant::NIL);
+ register_op<OperatorEvaluatorNotObject>(Variant::OP_NOT, Variant::OBJECT, Variant::NIL);
+
+ register_op<OperatorEvaluatorInStringFind>(Variant::OP_IN, Variant::STRING, Variant::STRING);
+
+ register_op<OperatorEvaluatorInDictionaryHasNil>(Variant::OP_IN, Variant::NIL, Variant::DICTIONARY);
+ register_op<OperatorEvaluatorInDictionaryHas<bool>>(Variant::OP_IN, Variant::BOOL, Variant::DICTIONARY);
+ register_op<OperatorEvaluatorInDictionaryHas<int64_t>>(Variant::OP_IN, Variant::INT, Variant::DICTIONARY);
+ register_op<OperatorEvaluatorInDictionaryHas<double>>(Variant::OP_IN, Variant::FLOAT, Variant::DICTIONARY);
+ register_op<OperatorEvaluatorInDictionaryHas<String>>(Variant::OP_IN, Variant::STRING, Variant::DICTIONARY);
+ register_op<OperatorEvaluatorInDictionaryHas<Vector2>>(Variant::OP_IN, Variant::VECTOR2, Variant::DICTIONARY);
+ register_op<OperatorEvaluatorInDictionaryHas<Vector2i>>(Variant::OP_IN, Variant::VECTOR2I, Variant::DICTIONARY);
+ register_op<OperatorEvaluatorInDictionaryHas<Rect2>>(Variant::OP_IN, Variant::RECT2, Variant::DICTIONARY);
+ register_op<OperatorEvaluatorInDictionaryHas<Rect2i>>(Variant::OP_IN, Variant::RECT2I, Variant::DICTIONARY);
+ register_op<OperatorEvaluatorInDictionaryHas<Vector3>>(Variant::OP_IN, Variant::VECTOR3, Variant::DICTIONARY);
+ register_op<OperatorEvaluatorInDictionaryHas<Vector3i>>(Variant::OP_IN, Variant::VECTOR3I, Variant::DICTIONARY);
+ register_op<OperatorEvaluatorInDictionaryHas<Transform2D>>(Variant::OP_IN, Variant::TRANSFORM2D, Variant::DICTIONARY);
+ register_op<OperatorEvaluatorInDictionaryHas<Plane>>(Variant::OP_IN, Variant::PLANE, Variant::DICTIONARY);
+ register_op<OperatorEvaluatorInDictionaryHas<Quat>>(Variant::OP_IN, Variant::QUAT, Variant::DICTIONARY);
+ register_op<OperatorEvaluatorInDictionaryHas<::AABB>>(Variant::OP_IN, Variant::AABB, Variant::DICTIONARY);
+ register_op<OperatorEvaluatorInDictionaryHas<Basis>>(Variant::OP_IN, Variant::BASIS, Variant::DICTIONARY);
+ register_op<OperatorEvaluatorInDictionaryHas<Transform>>(Variant::OP_IN, Variant::TRANSFORM, Variant::DICTIONARY);
+
+ register_op<OperatorEvaluatorInDictionaryHas<Color>>(Variant::OP_IN, Variant::COLOR, Variant::DICTIONARY);
+ register_op<OperatorEvaluatorInDictionaryHas<StringName>>(Variant::OP_IN, Variant::STRING_NAME, Variant::DICTIONARY);
+ register_op<OperatorEvaluatorInDictionaryHas<NodePath>>(Variant::OP_IN, Variant::NODE_PATH, Variant::DICTIONARY);
+ register_op<OperatorEvaluatorInDictionaryHasObject>(Variant::OP_IN, Variant::OBJECT, Variant::DICTIONARY);
+ register_op<OperatorEvaluatorInDictionaryHas<Callable>>(Variant::OP_IN, Variant::CALLABLE, Variant::DICTIONARY);
+ register_op<OperatorEvaluatorInDictionaryHas<Signal>>(Variant::OP_IN, Variant::SIGNAL, Variant::DICTIONARY);
+ register_op<OperatorEvaluatorInDictionaryHas<Dictionary>>(Variant::OP_IN, Variant::DICTIONARY, Variant::DICTIONARY);
+ register_op<OperatorEvaluatorInDictionaryHas<Array>>(Variant::OP_IN, Variant::ARRAY, Variant::DICTIONARY);
+
+ register_op<OperatorEvaluatorInDictionaryHas<PackedByteArray>>(Variant::OP_IN, Variant::PACKED_BYTE_ARRAY, Variant::DICTIONARY);
+ register_op<OperatorEvaluatorInDictionaryHas<PackedInt32Array>>(Variant::OP_IN, Variant::PACKED_INT32_ARRAY, Variant::DICTIONARY);
+ register_op<OperatorEvaluatorInDictionaryHas<PackedInt64Array>>(Variant::OP_IN, Variant::PACKED_INT64_ARRAY, Variant::DICTIONARY);
+ register_op<OperatorEvaluatorInDictionaryHas<PackedFloat32Array>>(Variant::OP_IN, Variant::PACKED_FLOAT32_ARRAY, Variant::DICTIONARY);
+ register_op<OperatorEvaluatorInDictionaryHas<PackedFloat64Array>>(Variant::OP_IN, Variant::PACKED_FLOAT64_ARRAY, Variant::DICTIONARY);
+ register_op<OperatorEvaluatorInDictionaryHas<PackedStringArray>>(Variant::OP_IN, Variant::PACKED_STRING_ARRAY, Variant::DICTIONARY);
+ register_op<OperatorEvaluatorInDictionaryHas<PackedVector2Array>>(Variant::OP_IN, Variant::PACKED_VECTOR2_ARRAY, Variant::DICTIONARY);
+ register_op<OperatorEvaluatorInDictionaryHas<PackedVector3Array>>(Variant::OP_IN, Variant::PACKED_VECTOR3_ARRAY, Variant::DICTIONARY);
+ register_op<OperatorEvaluatorInDictionaryHas<PackedColorArray>>(Variant::OP_IN, Variant::PACKED_COLOR_ARRAY, Variant::DICTIONARY);
+
+ register_op<OperatorEvaluatorInArrayFindNil>(Variant::OP_IN, Variant::NIL, Variant::ARRAY);
+ register_op<OperatorEvaluatorInArrayFind<bool, Array>>(Variant::OP_IN, Variant::BOOL, Variant::ARRAY);
+ register_op<OperatorEvaluatorInArrayFind<int64_t, Array>>(Variant::OP_IN, Variant::INT, Variant::ARRAY);
+ register_op<OperatorEvaluatorInArrayFind<double, Array>>(Variant::OP_IN, Variant::FLOAT, Variant::ARRAY);
+ register_op<OperatorEvaluatorInArrayFind<String, Array>>(Variant::OP_IN, Variant::STRING, Variant::ARRAY);
+ register_op<OperatorEvaluatorInArrayFind<Vector2, Array>>(Variant::OP_IN, Variant::VECTOR2, Variant::ARRAY);
+ register_op<OperatorEvaluatorInArrayFind<Vector2i, Array>>(Variant::OP_IN, Variant::VECTOR2I, Variant::ARRAY);
+ register_op<OperatorEvaluatorInArrayFind<Rect2, Array>>(Variant::OP_IN, Variant::RECT2, Variant::ARRAY);
+ register_op<OperatorEvaluatorInArrayFind<Rect2i, Array>>(Variant::OP_IN, Variant::RECT2I, Variant::ARRAY);
+ register_op<OperatorEvaluatorInArrayFind<Vector3, Array>>(Variant::OP_IN, Variant::VECTOR3, Variant::ARRAY);
+ register_op<OperatorEvaluatorInArrayFind<Vector3i, Array>>(Variant::OP_IN, Variant::VECTOR3I, Variant::ARRAY);
+ register_op<OperatorEvaluatorInArrayFind<Transform2D, Array>>(Variant::OP_IN, Variant::TRANSFORM2D, Variant::ARRAY);
+ register_op<OperatorEvaluatorInArrayFind<Plane, Array>>(Variant::OP_IN, Variant::PLANE, Variant::ARRAY);
+ register_op<OperatorEvaluatorInArrayFind<Quat, Array>>(Variant::OP_IN, Variant::QUAT, Variant::ARRAY);
+ register_op<OperatorEvaluatorInArrayFind<::AABB, Array>>(Variant::OP_IN, Variant::AABB, Variant::ARRAY);
+ register_op<OperatorEvaluatorInArrayFind<Basis, Array>>(Variant::OP_IN, Variant::BASIS, Variant::ARRAY);
+ register_op<OperatorEvaluatorInArrayFind<Transform, Array>>(Variant::OP_IN, Variant::TRANSFORM, Variant::ARRAY);
+
+ register_op<OperatorEvaluatorInArrayFind<Color, Array>>(Variant::OP_IN, Variant::COLOR, Variant::ARRAY);
+ register_op<OperatorEvaluatorInArrayFind<StringName, Array>>(Variant::OP_IN, Variant::STRING_NAME, Variant::ARRAY);
+ register_op<OperatorEvaluatorInArrayFind<NodePath, Array>>(Variant::OP_IN, Variant::NODE_PATH, Variant::ARRAY);
+ register_op<OperatorEvaluatorInArrayFindObject>(Variant::OP_IN, Variant::OBJECT, Variant::ARRAY);
+ register_op<OperatorEvaluatorInArrayFind<Callable, Array>>(Variant::OP_IN, Variant::CALLABLE, Variant::ARRAY);
+ register_op<OperatorEvaluatorInArrayFind<Signal, Array>>(Variant::OP_IN, Variant::SIGNAL, Variant::ARRAY);
+ register_op<OperatorEvaluatorInArrayFind<Dictionary, Array>>(Variant::OP_IN, Variant::DICTIONARY, Variant::ARRAY);
+ register_op<OperatorEvaluatorInArrayFind<Array, Array>>(Variant::OP_IN, Variant::ARRAY, Variant::ARRAY);
+
+ register_op<OperatorEvaluatorInArrayFind<PackedByteArray, Array>>(Variant::OP_IN, Variant::PACKED_BYTE_ARRAY, Variant::ARRAY);
+ register_op<OperatorEvaluatorInArrayFind<PackedInt32Array, Array>>(Variant::OP_IN, Variant::PACKED_INT32_ARRAY, Variant::ARRAY);
+ register_op<OperatorEvaluatorInArrayFind<PackedInt64Array, Array>>(Variant::OP_IN, Variant::PACKED_INT64_ARRAY, Variant::ARRAY);
+ register_op<OperatorEvaluatorInArrayFind<PackedFloat32Array, Array>>(Variant::OP_IN, Variant::PACKED_FLOAT32_ARRAY, Variant::ARRAY);
+ register_op<OperatorEvaluatorInArrayFind<PackedFloat64Array, Array>>(Variant::OP_IN, Variant::PACKED_FLOAT64_ARRAY, Variant::ARRAY);
+ register_op<OperatorEvaluatorInArrayFind<PackedStringArray, Array>>(Variant::OP_IN, Variant::PACKED_STRING_ARRAY, Variant::ARRAY);
+ register_op<OperatorEvaluatorInArrayFind<PackedVector2Array, Array>>(Variant::OP_IN, Variant::PACKED_VECTOR2_ARRAY, Variant::ARRAY);
+ register_op<OperatorEvaluatorInArrayFind<PackedVector3Array, Array>>(Variant::OP_IN, Variant::PACKED_VECTOR3_ARRAY, Variant::ARRAY);
+ register_op<OperatorEvaluatorInArrayFind<PackedColorArray, Array>>(Variant::OP_IN, Variant::PACKED_COLOR_ARRAY, Variant::ARRAY);
+
+ register_op<OperatorEvaluatorInArrayFind<int, PackedByteArray>>(Variant::OP_IN, Variant::INT, Variant::PACKED_BYTE_ARRAY);
+ register_op<OperatorEvaluatorInArrayFind<float, PackedByteArray>>(Variant::OP_IN, Variant::FLOAT, Variant::PACKED_BYTE_ARRAY);
+
+ register_op<OperatorEvaluatorInArrayFind<int, PackedInt32Array>>(Variant::OP_IN, Variant::INT, Variant::PACKED_INT32_ARRAY);
+ register_op<OperatorEvaluatorInArrayFind<float, PackedInt32Array>>(Variant::OP_IN, Variant::FLOAT, Variant::PACKED_INT32_ARRAY);
+
+ register_op<OperatorEvaluatorInArrayFind<int, PackedInt64Array>>(Variant::OP_IN, Variant::INT, Variant::PACKED_INT64_ARRAY);
+ register_op<OperatorEvaluatorInArrayFind<float, PackedInt64Array>>(Variant::OP_IN, Variant::FLOAT, Variant::PACKED_INT64_ARRAY);
+
+ register_op<OperatorEvaluatorInArrayFind<int, PackedFloat32Array>>(Variant::OP_IN, Variant::INT, Variant::PACKED_FLOAT32_ARRAY);
+ register_op<OperatorEvaluatorInArrayFind<float, PackedFloat32Array>>(Variant::OP_IN, Variant::FLOAT, Variant::PACKED_FLOAT32_ARRAY);
+
+ register_op<OperatorEvaluatorInArrayFind<int, PackedFloat64Array>>(Variant::OP_IN, Variant::INT, Variant::PACKED_FLOAT64_ARRAY);
+ register_op<OperatorEvaluatorInArrayFind<float, PackedFloat64Array>>(Variant::OP_IN, Variant::FLOAT, Variant::PACKED_FLOAT64_ARRAY);
+
+ register_op<OperatorEvaluatorInArrayFind<String, PackedStringArray>>(Variant::OP_IN, Variant::STRING, Variant::PACKED_STRING_ARRAY);
+
+ register_op<OperatorEvaluatorInArrayFind<Vector2, PackedVector2Array>>(Variant::OP_IN, Variant::VECTOR2, Variant::PACKED_VECTOR2_ARRAY);
+ register_op<OperatorEvaluatorInArrayFind<Vector3, PackedVector3Array>>(Variant::OP_IN, Variant::VECTOR3, Variant::PACKED_VECTOR3_ARRAY);
+
+ register_op<OperatorEvaluatorInArrayFind<Color, PackedColorArray>>(Variant::OP_IN, Variant::COLOR, Variant::PACKED_COLOR_ARRAY);
+
+ register_op<OperatorEvaluatorObjectHasPropertyString>(Variant::OP_IN, Variant::STRING, Variant::OBJECT);
+ register_op<OperatorEvaluatorObjectHasPropertyStringName>(Variant::OP_IN, Variant::STRING_NAME, Variant::OBJECT);
+}
+
+void Variant::_unregister_variant_operators() {
+}
+
+void Variant::evaluate(const Operator &p_op, const Variant &p_a,
+ const Variant &p_b, Variant &r_ret, bool &r_valid) {
+ ERR_FAIL_INDEX(p_op, Variant::OP_MAX);
+ Variant::Type type_a = p_a.get_type();
+ Variant::Type type_b = p_b.get_type();
+ ERR_FAIL_INDEX(type_a, Variant::VARIANT_MAX);
+ ERR_FAIL_INDEX(type_b, Variant::VARIANT_MAX);
+
+ VariantEvaluatorFunction ev = operator_evaluator_table[p_op][type_a][type_b];
+ if (unlikely(!ev)) {
+ r_valid = false;
+ r_ret = Variant();
+ return;
+ }
+
+ ev(p_a, p_b, &r_ret, r_valid);
+}
+
+Variant::Type Variant::get_operator_return_type(Operator p_operator, Type p_type_a, Type p_type_b) {
+ ERR_FAIL_INDEX_V(p_operator, Variant::OP_MAX, Variant::NIL);
+ ERR_FAIL_INDEX_V(p_type_a, Variant::VARIANT_MAX, Variant::NIL);
+ ERR_FAIL_INDEX_V(p_type_b, Variant::VARIANT_MAX, Variant::NIL);
+
+ return operator_return_type_table[p_operator][p_type_a][p_type_b];
+}
+
+Variant::ValidatedOperatorEvaluator Variant::get_validated_operator_evaluator(Operator p_operator, Type p_type_a, Type p_type_b) {
+ ERR_FAIL_INDEX_V(p_operator, Variant::OP_MAX, nullptr);
+ ERR_FAIL_INDEX_V(p_type_a, Variant::VARIANT_MAX, nullptr);
+ ERR_FAIL_INDEX_V(p_type_b, Variant::VARIANT_MAX, nullptr);
+ return validated_operator_evaluator_table[p_operator][p_type_a][p_type_b];
+}
+
+Variant::PTROperatorEvaluator Variant::get_ptr_operator_evaluator(Operator p_operator, Type p_type_a, Type p_type_b) {
+ ERR_FAIL_INDEX_V(p_operator, Variant::OP_MAX, nullptr);
+ ERR_FAIL_INDEX_V(p_type_a, Variant::VARIANT_MAX, nullptr);
+ ERR_FAIL_INDEX_V(p_type_b, Variant::VARIANT_MAX, nullptr);
+ return ptr_operator_evaluator_table[p_operator][p_type_a][p_type_b];
+}
+
+static const char *_op_names[Variant::OP_MAX] = {
+ "==",
+ "!=",
+ "<",
+ "<=",
+ ">",
+ ">=",
+ "+",
+ "-",
+ "*",
+ "/",
+ "-",
+ "+",
+ "%",
+ "<<",
+ ">>",
+ "&",
+ "|",
+ "^",
+ "~",
+ "and",
+ "or",
+ "xor",
+ "not",
+ "in"
+};
+
+String Variant::get_operator_name(Operator p_op) {
+ ERR_FAIL_INDEX_V(p_op, OP_MAX, "");
+ return _op_names[p_op];
+}
+
+Variant::operator bool() const {
+ return booleanize();
+}
+
+// We consider all uninitialized or empty types to be false based on the type's
+// zeroiness.
+bool Variant::booleanize() const {
+ return !is_zero();
+}
+
+bool Variant::in(const Variant &p_index, bool *r_valid) const {
+ bool valid;
+ Variant ret;
+ evaluate(OP_IN, p_index, *this, ret, valid);
+ if (r_valid) {
+ *r_valid = valid;
+ return false;
+ }
+ ERR_FAIL_COND_V(ret.type != BOOL, false);
+ return *VariantGetInternalPtr<bool>::get_ptr(&ret);
+}
diff --git a/core/variant_parser.cpp b/core/variant/variant_parser.cpp
index 74f4f32c0e..5a0bbf041b 100644
--- a/core/variant_parser.cpp
+++ b/core/variant/variant_parser.cpp
@@ -33,9 +33,9 @@
#include "core/input/input_event.h"
#include "core/io/resource_loader.h"
#include "core/os/keyboard.h"
-#include "core/string_buffer.h"
+#include "core/string/string_buffer.h"
-CharType VariantParser::StreamFile::get_char() {
+char32_t VariantParser::StreamFile::get_char() {
return f->get_8();
}
@@ -47,7 +47,7 @@ bool VariantParser::StreamFile::is_eof() const {
return f->eof_reached();
}
-CharType VariantParser::StreamString::get_char() {
+char32_t VariantParser::StreamString::get_char() {
if (pos > s.length()) {
return 0;
} else if (pos == s.length()) {
@@ -94,7 +94,7 @@ Error VariantParser::get_token(Stream *p_stream, Token &r_token, int &line, Stri
bool string_name = false;
while (true) {
- CharType cchar;
+ char32_t cchar;
if (p_stream->saved) {
cchar = p_stream->saved;
p_stream->saved = 0;
@@ -145,7 +145,7 @@ Error VariantParser::get_token(Stream *p_stream, Token &r_token, int &line, Stri
}
case ';': {
while (true) {
- CharType ch = p_stream->get_char();
+ char32_t ch = p_stream->get_char();
if (p_stream->is_eof()) {
r_token.type = TK_EOF;
return OK;
@@ -173,7 +173,7 @@ Error VariantParser::get_token(Stream *p_stream, Token &r_token, int &line, Stri
StringBuffer<> color_str;
color_str += '#';
while (true) {
- CharType ch = p_stream->get_char();
+ char32_t ch = p_stream->get_char();
if (p_stream->is_eof()) {
r_token.type = TK_EOF;
return OK;
@@ -204,7 +204,7 @@ Error VariantParser::get_token(Stream *p_stream, Token &r_token, int &line, Stri
case '"': {
String str;
while (true) {
- CharType ch = p_stream->get_char();
+ char32_t ch = p_stream->get_char();
if (ch == 0) {
r_err_str = "Unterminated String";
@@ -214,13 +214,13 @@ Error VariantParser::get_token(Stream *p_stream, Token &r_token, int &line, Stri
break;
} else if (ch == '\\') {
//escaped characters...
- CharType next = p_stream->get_char();
+ char32_t next = p_stream->get_char();
if (next == 0) {
r_err_str = "Unterminated String";
r_token.type = TK_ERROR;
return ERR_PARSE_ERROR;
}
- CharType res = 0;
+ char32_t res = 0;
switch (next) {
case 'b':
@@ -241,7 +241,7 @@ Error VariantParser::get_token(Stream *p_stream, Token &r_token, int &line, Stri
case 'u': {
//hex number
for (int j = 0; j < 4; j++) {
- CharType c = p_stream->get_char();
+ char32_t c = p_stream->get_char();
if (c == 0) {
r_err_str = "Unterminated String";
r_token.type = TK_ERROR;
@@ -252,7 +252,7 @@ Error VariantParser::get_token(Stream *p_stream, Token &r_token, int &line, Stri
r_token.type = TK_ERROR;
return ERR_PARSE_ERROR;
}
- CharType v;
+ char32_t v;
if (c >= '0' && c <= '9') {
v = c - '0';
} else if (c >= 'a' && c <= 'f') {
@@ -321,7 +321,7 @@ Error VariantParser::get_token(Stream *p_stream, Token &r_token, int &line, Stri
cchar = p_stream->get_char();
}
- CharType c = cchar;
+ char32_t c = cchar;
bool exp_sign = false;
bool exp_beg = false;
bool is_float = false;
@@ -421,7 +421,7 @@ Error VariantParser::_parse_enginecfg(Stream *p_stream, Vector<String> &strings,
String accum;
while (true) {
- CharType c = p_stream->get_char();
+ char32_t c = p_stream->get_char();
if (p_stream->is_eof()) {
r_err_str = "Unexpected EOF while parsing old-style project.godot construct";
@@ -1206,7 +1206,7 @@ Error VariantParser::_parse_tag(Token &token, Stream *p_stream, int &line, Strin
r_tag.fields.clear();
while (true) {
- CharType c = p_stream->get_char();
+ char32_t c = p_stream->get_char();
if (p_stream->is_eof()) {
r_err_str = "Unexpected EOF while parsing simple tag";
return ERR_PARSE_ERROR;
@@ -1305,7 +1305,7 @@ Error VariantParser::parse_tag_assign_eof(Stream *p_stream, int &line, String &r
String what;
while (true) {
- CharType c;
+ char32_t c;
if (p_stream->saved) {
c = p_stream->saved;
p_stream->saved = 0;
@@ -1320,7 +1320,7 @@ Error VariantParser::parse_tag_assign_eof(Stream *p_stream, int &line, String &r
if (c == ';') { //comment
while (true) {
- CharType ch = p_stream->get_char();
+ char32_t ch = p_stream->get_char();
if (p_stream->is_eof()) {
return ERR_FILE_EOF;
}
@@ -1608,10 +1608,12 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str
write(dict[E->get()], p_store_string_func, p_store_string_ud, p_encode_res_func, p_encode_res_ud);
if (E->next()) {
p_store_string_func(p_store_string_ud, ",\n");
+ } else {
+ p_store_string_func(p_store_string_ud, "\n");
}
}
- p_store_string_func(p_store_string_ud, "\n}");
+ p_store_string_func(p_store_string_ud, "}");
} break;
case Variant::ARRAY: {
diff --git a/core/variant_parser.h b/core/variant/variant_parser.h
index b55d7b2df0..cf1941a40e 100644
--- a/core/variant_parser.h
+++ b/core/variant/variant_parser.h
@@ -31,18 +31,18 @@
#ifndef VARIANT_PARSER_H
#define VARIANT_PARSER_H
+#include "core/io/resource.h"
#include "core/os/file_access.h"
-#include "core/resource.h"
-#include "core/variant.h"
+#include "core/variant/variant.h"
class VariantParser {
public:
struct Stream {
- virtual CharType get_char() = 0;
+ virtual char32_t get_char() = 0;
virtual bool is_utf8() const = 0;
virtual bool is_eof() const = 0;
- CharType saved = 0;
+ char32_t saved = 0;
Stream() {}
virtual ~Stream() {}
@@ -51,7 +51,7 @@ public:
struct StreamFile : public Stream {
FileAccess *f = nullptr;
- virtual CharType get_char();
+ virtual char32_t get_char();
virtual bool is_utf8() const;
virtual bool is_eof() const;
@@ -62,7 +62,7 @@ public:
String s;
int pos = 0;
- virtual CharType get_char();
+ virtual char32_t get_char();
virtual bool is_utf8() const;
virtual bool is_eof() const;
@@ -100,7 +100,6 @@ public:
};
enum Expecting {
-
EXPECT_OBJECT,
EXPECT_OBJECT_KEY,
EXPECT_COLON,
diff --git a/core/variant/variant_setget.cpp b/core/variant/variant_setget.cpp
new file mode 100644
index 0000000000..f6a2c11830
--- /dev/null
+++ b/core/variant/variant_setget.cpp
@@ -0,0 +1,2509 @@
+/*************************************************************************/
+/* variant_setget.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* 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. */
+/*************************************************************************/
+
+#include "variant.h"
+
+#include "core/core_string_names.h"
+#include "core/debugger/engine_debugger.h"
+#include "core/object/class_db.h"
+#include "core/templates/local_vector.h"
+#include "core/variant/variant_internal.h"
+
+/**** NAMED SETTERS AND GETTERS ****/
+
+#define SETGET_STRUCT(m_base_type, m_member_type, m_member) \
+ struct VariantSetGet_##m_base_type##_##m_member { \
+ static void get(const Variant *base, Variant *member) { \
+ VariantTypeAdjust<m_member_type>::adjust(member); \
+ *VariantGetInternalPtr<m_member_type>::get_ptr(member) = VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_member; \
+ } \
+ static void ptr_get(const void *base, void *member) { \
+ PtrToArg<m_member_type>::encode(PtrToArg<m_base_type>::convert(base).m_member, member); \
+ } \
+ static void set(Variant *base, const Variant *value, bool &valid) { \
+ if (value->get_type() == GetTypeInfo<m_member_type>::VARIANT_TYPE) { \
+ VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_member = *VariantGetInternalPtr<m_member_type>::get_ptr(value); \
+ valid = true; \
+ } else { \
+ valid = false; \
+ } \
+ } \
+ static void validated_set(Variant *base, const Variant *value) { \
+ VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_member = *VariantGetInternalPtr<m_member_type>::get_ptr(value); \
+ } \
+ static void ptr_set(void *base, const void *member) { \
+ m_base_type b = PtrToArg<m_base_type>::convert(base); \
+ b.m_member = PtrToArg<m_member_type>::convert(member); \
+ PtrToArg<m_base_type>::encode(b, base); \
+ } \
+ static Variant::Type get_type() { return GetTypeInfo<m_member_type>::VARIANT_TYPE; } \
+ };
+
+#define SETGET_NUMBER_STRUCT(m_base_type, m_member_type, m_member) \
+ struct VariantSetGet_##m_base_type##_##m_member { \
+ static void get(const Variant *base, Variant *member) { \
+ VariantTypeAdjust<m_member_type>::adjust(member); \
+ *VariantGetInternalPtr<m_member_type>::get_ptr(member) = VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_member; \
+ } \
+ static void ptr_get(const void *base, void *member) { \
+ PtrToArg<m_member_type>::encode(PtrToArg<m_base_type>::convert(base).m_member, member); \
+ } \
+ static void set(Variant *base, const Variant *value, bool &valid) { \
+ if (value->get_type() == Variant::FLOAT) { \
+ VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_member = *VariantGetInternalPtr<double>::get_ptr(value); \
+ valid = true; \
+ } else if (value->get_type() == Variant::INT) { \
+ VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_member = *VariantGetInternalPtr<int64_t>::get_ptr(value); \
+ valid = true; \
+ } else { \
+ valid = false; \
+ } \
+ } \
+ static void validated_set(Variant *base, const Variant *value) { \
+ VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_member = *VariantGetInternalPtr<m_member_type>::get_ptr(value); \
+ } \
+ static void ptr_set(void *base, const void *member) { \
+ m_base_type b = PtrToArg<m_base_type>::convert(base); \
+ b.m_member = PtrToArg<m_member_type>::convert(member); \
+ PtrToArg<m_base_type>::encode(b, base); \
+ } \
+ static Variant::Type get_type() { return GetTypeInfo<m_member_type>::VARIANT_TYPE; } \
+ };
+
+#define SETGET_STRUCT_CUSTOM(m_base_type, m_member_type, m_member, m_custom) \
+ struct VariantSetGet_##m_base_type##_##m_member { \
+ static void get(const Variant *base, Variant *member) { \
+ VariantTypeAdjust<m_member_type>::adjust(member); \
+ *VariantGetInternalPtr<m_member_type>::get_ptr(member) = VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_custom; \
+ } \
+ static void ptr_get(const void *base, void *member) { \
+ PtrToArg<m_member_type>::encode(PtrToArg<m_base_type>::convert(base).m_custom, member); \
+ } \
+ static void set(Variant *base, const Variant *value, bool &valid) { \
+ if (value->get_type() == GetTypeInfo<m_member_type>::VARIANT_TYPE) { \
+ VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_custom = *VariantGetInternalPtr<m_member_type>::get_ptr(value); \
+ valid = true; \
+ } else { \
+ valid = false; \
+ } \
+ } \
+ static void validated_set(Variant *base, const Variant *value) { \
+ VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_custom = *VariantGetInternalPtr<m_member_type>::get_ptr(value); \
+ } \
+ static void ptr_set(void *base, const void *member) { \
+ m_base_type b = PtrToArg<m_base_type>::convert(base); \
+ b.m_custom = PtrToArg<m_member_type>::convert(member); \
+ PtrToArg<m_base_type>::encode(b, base); \
+ } \
+ static Variant::Type get_type() { return GetTypeInfo<m_member_type>::VARIANT_TYPE; } \
+ };
+
+#define SETGET_NUMBER_STRUCT_CUSTOM(m_base_type, m_member_type, m_member, m_custom) \
+ struct VariantSetGet_##m_base_type##_##m_member { \
+ static void get(const Variant *base, Variant *member) { \
+ VariantTypeAdjust<m_member_type>::adjust(member); \
+ *VariantGetInternalPtr<m_member_type>::get_ptr(member) = VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_custom; \
+ } \
+ static void ptr_get(const void *base, void *member) { \
+ PtrToArg<m_member_type>::encode(PtrToArg<m_base_type>::convert(base).m_custom, member); \
+ } \
+ static void set(Variant *base, const Variant *value, bool &valid) { \
+ if (value->get_type() == Variant::FLOAT) { \
+ VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_custom = *VariantGetInternalPtr<double>::get_ptr(value); \
+ valid = true; \
+ } else if (value->get_type() == Variant::INT) { \
+ VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_custom = *VariantGetInternalPtr<int64_t>::get_ptr(value); \
+ valid = true; \
+ } else { \
+ valid = false; \
+ } \
+ } \
+ static void validated_set(Variant *base, const Variant *value) { \
+ VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_custom = *VariantGetInternalPtr<m_member_type>::get_ptr(value); \
+ } \
+ static void ptr_set(void *base, const void *member) { \
+ m_base_type b = PtrToArg<m_base_type>::convert(base); \
+ b.m_custom = PtrToArg<m_member_type>::convert(member); \
+ PtrToArg<m_base_type>::encode(b, base); \
+ } \
+ static Variant::Type get_type() { return GetTypeInfo<m_member_type>::VARIANT_TYPE; } \
+ };
+
+#define SETGET_STRUCT_FUNC(m_base_type, m_member_type, m_member, m_setter, m_getter) \
+ struct VariantSetGet_##m_base_type##_##m_member { \
+ static void get(const Variant *base, Variant *member) { \
+ VariantTypeAdjust<m_member_type>::adjust(member); \
+ *VariantGetInternalPtr<m_member_type>::get_ptr(member) = VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_getter(); \
+ } \
+ static void ptr_get(const void *base, void *member) { \
+ PtrToArg<m_member_type>::encode(PtrToArg<m_base_type>::convert(base).m_getter(), member); \
+ } \
+ static void set(Variant *base, const Variant *value, bool &valid) { \
+ if (value->get_type() == GetTypeInfo<m_member_type>::VARIANT_TYPE) { \
+ VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_setter(*VariantGetInternalPtr<m_member_type>::get_ptr(value)); \
+ valid = true; \
+ } else { \
+ valid = false; \
+ } \
+ } \
+ static void validated_set(Variant *base, const Variant *value) { \
+ VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_setter(*VariantGetInternalPtr<m_member_type>::get_ptr(value)); \
+ } \
+ static void ptr_set(void *base, const void *member) { \
+ m_base_type b = PtrToArg<m_base_type>::convert(base); \
+ b.m_setter(PtrToArg<m_member_type>::convert(member)); \
+ PtrToArg<m_base_type>::encode(b, base); \
+ } \
+ static Variant::Type get_type() { return GetTypeInfo<m_member_type>::VARIANT_TYPE; } \
+ };
+
+#define SETGET_NUMBER_STRUCT_FUNC(m_base_type, m_member_type, m_member, m_setter, m_getter) \
+ struct VariantSetGet_##m_base_type##_##m_member { \
+ static void get(const Variant *base, Variant *member) { \
+ VariantTypeAdjust<m_member_type>::adjust(member); \
+ *VariantGetInternalPtr<m_member_type>::get_ptr(member) = VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_getter(); \
+ } \
+ static void ptr_get(const void *base, void *member) { \
+ PtrToArg<m_member_type>::encode(PtrToArg<m_base_type>::convert(base).m_getter(), member); \
+ } \
+ static void set(Variant *base, const Variant *value, bool &valid) { \
+ if (value->get_type() == Variant::FLOAT) { \
+ VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_setter(*VariantGetInternalPtr<double>::get_ptr(value)); \
+ valid = true; \
+ } else if (value->get_type() == Variant::INT) { \
+ VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_setter(*VariantGetInternalPtr<int64_t>::get_ptr(value)); \
+ valid = true; \
+ } else { \
+ valid = false; \
+ } \
+ } \
+ static void validated_set(Variant *base, const Variant *value) { \
+ VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_setter(*VariantGetInternalPtr<m_member_type>::get_ptr(value)); \
+ } \
+ static void ptr_set(void *base, const void *member) { \
+ m_base_type b = PtrToArg<m_base_type>::convert(base); \
+ b.m_setter(PtrToArg<m_member_type>::convert(member)); \
+ PtrToArg<m_base_type>::encode(b, base); \
+ } \
+ static Variant::Type get_type() { return GetTypeInfo<m_member_type>::VARIANT_TYPE; } \
+ };
+
+#define SETGET_STRUCT_FUNC_INDEX(m_base_type, m_member_type, m_member, m_setter, m_getter, m_index) \
+ struct VariantSetGet_##m_base_type##_##m_member { \
+ static void get(const Variant *base, Variant *member) { \
+ VariantTypeAdjust<m_member_type>::adjust(member); \
+ *VariantGetInternalPtr<m_member_type>::get_ptr(member) = VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_getter(m_index); \
+ } \
+ static void ptr_get(const void *base, void *member) { \
+ PtrToArg<m_member_type>::encode(PtrToArg<m_base_type>::convert(base).m_getter(m_index), member); \
+ } \
+ static void set(Variant *base, const Variant *value, bool &valid) { \
+ if (value->get_type() == GetTypeInfo<m_member_type>::VARIANT_TYPE) { \
+ VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_setter(m_index, *VariantGetInternalPtr<m_member_type>::get_ptr(value)); \
+ valid = true; \
+ } else { \
+ valid = false; \
+ } \
+ } \
+ static void validated_set(Variant *base, const Variant *value) { \
+ VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_setter(m_index, *VariantGetInternalPtr<m_member_type>::get_ptr(value)); \
+ } \
+ static void ptr_set(void *base, const void *member) { \
+ m_base_type b = PtrToArg<m_base_type>::convert(base); \
+ b.m_setter(m_index, PtrToArg<m_member_type>::convert(member)); \
+ PtrToArg<m_base_type>::encode(b, base); \
+ } \
+ static Variant::Type get_type() { return GetTypeInfo<m_member_type>::VARIANT_TYPE; } \
+ };
+
+SETGET_NUMBER_STRUCT(Vector2, double, x)
+SETGET_NUMBER_STRUCT(Vector2, double, y)
+
+SETGET_NUMBER_STRUCT(Vector2i, int64_t, x)
+SETGET_NUMBER_STRUCT(Vector2i, int64_t, y)
+
+SETGET_NUMBER_STRUCT(Vector3, double, x)
+SETGET_NUMBER_STRUCT(Vector3, double, y)
+SETGET_NUMBER_STRUCT(Vector3, double, z)
+
+SETGET_NUMBER_STRUCT(Vector3i, int64_t, x)
+SETGET_NUMBER_STRUCT(Vector3i, int64_t, y)
+SETGET_NUMBER_STRUCT(Vector3i, int64_t, z)
+
+SETGET_STRUCT(Rect2, Vector2, position)
+SETGET_STRUCT(Rect2, Vector2, size)
+SETGET_STRUCT_FUNC(Rect2, Vector2, end, set_end, get_end)
+
+SETGET_STRUCT(Rect2i, Vector2i, position)
+SETGET_STRUCT(Rect2i, Vector2i, size)
+SETGET_STRUCT_FUNC(Rect2i, Vector2i, end, set_end, get_end)
+
+SETGET_STRUCT(AABB, Vector3, position)
+SETGET_STRUCT(AABB, Vector3, size)
+SETGET_STRUCT_FUNC(AABB, Vector3, end, set_end, get_end)
+
+SETGET_STRUCT_CUSTOM(Transform2D, Vector2, x, elements[0])
+SETGET_STRUCT_CUSTOM(Transform2D, Vector2, y, elements[1])
+SETGET_STRUCT_CUSTOM(Transform2D, Vector2, origin, elements[2])
+
+SETGET_NUMBER_STRUCT_CUSTOM(Plane, double, x, normal.x)
+SETGET_NUMBER_STRUCT_CUSTOM(Plane, double, y, normal.y)
+SETGET_NUMBER_STRUCT_CUSTOM(Plane, double, z, normal.z)
+SETGET_STRUCT(Plane, Vector3, normal)
+SETGET_NUMBER_STRUCT(Plane, double, d)
+
+SETGET_NUMBER_STRUCT(Quat, double, x)
+SETGET_NUMBER_STRUCT(Quat, double, y)
+SETGET_NUMBER_STRUCT(Quat, double, z)
+SETGET_NUMBER_STRUCT(Quat, double, w)
+
+SETGET_STRUCT_FUNC_INDEX(Basis, Vector3, x, set_axis, get_axis, 0)
+SETGET_STRUCT_FUNC_INDEX(Basis, Vector3, y, set_axis, get_axis, 1)
+SETGET_STRUCT_FUNC_INDEX(Basis, Vector3, z, set_axis, get_axis, 2)
+
+SETGET_STRUCT(Transform, Basis, basis)
+SETGET_STRUCT(Transform, Vector3, origin)
+
+SETGET_NUMBER_STRUCT(Color, double, r)
+SETGET_NUMBER_STRUCT(Color, double, g)
+SETGET_NUMBER_STRUCT(Color, double, b)
+SETGET_NUMBER_STRUCT(Color, double, a)
+
+SETGET_NUMBER_STRUCT_FUNC(Color, int64_t, r8, set_r8, get_r8)
+SETGET_NUMBER_STRUCT_FUNC(Color, int64_t, g8, set_g8, get_g8)
+SETGET_NUMBER_STRUCT_FUNC(Color, int64_t, b8, set_b8, get_b8)
+SETGET_NUMBER_STRUCT_FUNC(Color, int64_t, a8, set_a8, get_a8)
+
+SETGET_NUMBER_STRUCT_FUNC(Color, double, h, set_h, get_h)
+SETGET_NUMBER_STRUCT_FUNC(Color, double, s, set_s, get_s)
+SETGET_NUMBER_STRUCT_FUNC(Color, double, v, set_v, get_v)
+
+struct VariantSetterGetterInfo {
+ void (*setter)(Variant *base, const Variant *value, bool &valid);
+ void (*getter)(const Variant *base, Variant *value);
+ Variant::ValidatedSetter validated_setter;
+ Variant::ValidatedGetter validated_getter;
+ Variant::PTRSetter ptr_setter;
+ Variant::PTRGetter ptr_getter;
+ Variant::Type member_type;
+};
+
+static LocalVector<VariantSetterGetterInfo> variant_setters_getters[Variant::VARIANT_MAX];
+static LocalVector<StringName> variant_setters_getters_names[Variant::VARIANT_MAX]; //one next to another to make it cache friendly
+
+template <class T>
+static void register_member(Variant::Type p_type, const StringName &p_member) {
+ VariantSetterGetterInfo sgi;
+ sgi.setter = T::set;
+ sgi.validated_setter = T::validated_set;
+ sgi.ptr_setter = T::ptr_set;
+
+ sgi.getter = T::get;
+ sgi.validated_getter = T::get;
+ sgi.ptr_getter = T::ptr_get;
+
+ sgi.member_type = T::get_type();
+
+ variant_setters_getters[p_type].push_back(sgi);
+ variant_setters_getters_names[p_type].push_back(p_member);
+}
+
+void register_named_setters_getters() {
+#define REGISTER_MEMBER(m_base_type, m_member) register_member<VariantSetGet_##m_base_type##_##m_member>(GetTypeInfo<m_base_type>::VARIANT_TYPE, #m_member)
+
+ REGISTER_MEMBER(Vector2, x);
+ REGISTER_MEMBER(Vector2, y);
+
+ REGISTER_MEMBER(Vector2i, x);
+ REGISTER_MEMBER(Vector2i, y);
+
+ REGISTER_MEMBER(Vector3, x);
+ REGISTER_MEMBER(Vector3, y);
+ REGISTER_MEMBER(Vector3, z);
+
+ REGISTER_MEMBER(Vector3i, x);
+ REGISTER_MEMBER(Vector3i, y);
+ REGISTER_MEMBER(Vector3i, z);
+
+ REGISTER_MEMBER(Rect2, position);
+ REGISTER_MEMBER(Rect2, size);
+ REGISTER_MEMBER(Rect2, end);
+
+ REGISTER_MEMBER(Rect2i, position);
+ REGISTER_MEMBER(Rect2i, size);
+ REGISTER_MEMBER(Rect2i, end);
+
+ REGISTER_MEMBER(AABB, position);
+ REGISTER_MEMBER(AABB, size);
+ REGISTER_MEMBER(AABB, end);
+
+ REGISTER_MEMBER(Transform2D, x);
+ REGISTER_MEMBER(Transform2D, y);
+ REGISTER_MEMBER(Transform2D, origin);
+
+ REGISTER_MEMBER(Plane, x);
+ REGISTER_MEMBER(Plane, y);
+ REGISTER_MEMBER(Plane, z);
+ REGISTER_MEMBER(Plane, d);
+ REGISTER_MEMBER(Plane, normal);
+
+ REGISTER_MEMBER(Quat, x);
+ REGISTER_MEMBER(Quat, y);
+ REGISTER_MEMBER(Quat, z);
+ REGISTER_MEMBER(Quat, w);
+
+ REGISTER_MEMBER(Basis, x);
+ REGISTER_MEMBER(Basis, y);
+ REGISTER_MEMBER(Basis, z);
+
+ REGISTER_MEMBER(Transform, basis);
+ REGISTER_MEMBER(Transform, origin);
+
+ REGISTER_MEMBER(Color, r);
+ REGISTER_MEMBER(Color, g);
+ REGISTER_MEMBER(Color, b);
+ REGISTER_MEMBER(Color, a);
+
+ REGISTER_MEMBER(Color, r8);
+ REGISTER_MEMBER(Color, g8);
+ REGISTER_MEMBER(Color, b8);
+ REGISTER_MEMBER(Color, a8);
+
+ REGISTER_MEMBER(Color, h);
+ REGISTER_MEMBER(Color, s);
+ REGISTER_MEMBER(Color, v);
+}
+
+void unregister_named_setters_getters() {
+ for (int i = 0; i < Variant::VARIANT_MAX; i++) {
+ variant_setters_getters[i].clear();
+ variant_setters_getters_names[i].clear();
+ }
+}
+
+bool Variant::has_member(Variant::Type p_type, const StringName &p_member) {
+ ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, false);
+
+ for (uint32_t i = 0; i < variant_setters_getters_names[p_type].size(); i++) {
+ if (variant_setters_getters_names[p_type][i] == p_member) {
+ return true;
+ }
+ }
+ return false;
+}
+
+Variant::Type Variant::get_member_type(Variant::Type p_type, const StringName &p_member) {
+ ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, Variant::VARIANT_MAX);
+
+ for (uint32_t i = 0; i < variant_setters_getters_names[p_type].size(); i++) {
+ if (variant_setters_getters_names[p_type][i] == p_member) {
+ return variant_setters_getters[p_type][i].member_type;
+ }
+ }
+
+ return Variant::NIL;
+}
+
+void Variant::get_member_list(Variant::Type p_type, List<StringName> *r_members) {
+ for (uint32_t i = 0; i < variant_setters_getters_names[p_type].size(); i++) {
+ r_members->push_back(variant_setters_getters_names[p_type][i]);
+ }
+}
+
+Variant::ValidatedSetter Variant::get_member_validated_setter(Variant::Type p_type, const StringName &p_member) {
+ ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, nullptr);
+
+ for (uint32_t i = 0; i < variant_setters_getters_names[p_type].size(); i++) {
+ if (variant_setters_getters_names[p_type][i] == p_member) {
+ return variant_setters_getters[p_type][i].validated_setter;
+ }
+ }
+
+ return nullptr;
+}
+Variant::ValidatedGetter Variant::get_member_validated_getter(Variant::Type p_type, const StringName &p_member) {
+ ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, nullptr);
+
+ for (uint32_t i = 0; i < variant_setters_getters_names[p_type].size(); i++) {
+ if (variant_setters_getters_names[p_type][i] == p_member) {
+ return variant_setters_getters[p_type][i].validated_getter;
+ }
+ }
+
+ return nullptr;
+}
+
+Variant::PTRSetter Variant::get_member_ptr_setter(Variant::Type p_type, const StringName &p_member) {
+ ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, nullptr);
+
+ for (uint32_t i = 0; i < variant_setters_getters_names[p_type].size(); i++) {
+ if (variant_setters_getters_names[p_type][i] == p_member) {
+ return variant_setters_getters[p_type][i].ptr_setter;
+ }
+ }
+
+ return nullptr;
+}
+
+Variant::PTRGetter Variant::get_member_ptr_getter(Variant::Type p_type, const StringName &p_member) {
+ ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, nullptr);
+
+ for (uint32_t i = 0; i < variant_setters_getters_names[p_type].size(); i++) {
+ if (variant_setters_getters_names[p_type][i] == p_member) {
+ return variant_setters_getters[p_type][i].ptr_getter;
+ }
+ }
+
+ return nullptr;
+}
+
+void Variant::set_named(const StringName &p_member, const Variant &p_value, bool &r_valid) {
+ uint32_t s = variant_setters_getters[type].size();
+ if (s) {
+ for (uint32_t i = 0; i < s; i++) {
+ if (variant_setters_getters_names[type][i] == p_member) {
+ variant_setters_getters[type][i].setter(this, &p_value, r_valid);
+ return;
+ }
+ }
+ r_valid = false;
+
+ } else if (type == Variant::OBJECT) {
+ Object *obj = get_validated_object();
+ if (!obj) {
+ r_valid = false;
+ } else {
+ obj->set(p_member, p_value, &r_valid);
+ return;
+ }
+ } else if (type == Variant::DICTIONARY) {
+ Variant *v = VariantGetInternalPtr<Dictionary>::get_ptr(this)->getptr(p_member);
+ if (v) {
+ *v = p_value;
+ r_valid = true;
+ } else {
+ r_valid = false;
+ }
+
+ } else {
+ r_valid = false;
+ }
+}
+
+Variant Variant::get_named(const StringName &p_member, bool &r_valid) const {
+ Variant ret;
+ uint32_t s = variant_setters_getters[type].size();
+ if (s) {
+ for (uint32_t i = 0; i < s; i++) {
+ if (variant_setters_getters_names[type][i] == p_member) {
+ variant_setters_getters[type][i].getter(this, &ret);
+ r_valid = true;
+ return ret;
+ }
+ }
+
+ r_valid = false;
+
+ } else if (type == Variant::OBJECT) {
+ Object *obj = get_validated_object();
+ if (!obj) {
+ r_valid = false;
+ return "Instance base is null.";
+ } else {
+ return obj->get(p_member, &r_valid);
+ }
+ } else if (type == Variant::DICTIONARY) {
+ const Variant *v = VariantGetInternalPtr<Dictionary>::get_ptr(this)->getptr(p_member);
+ if (v) {
+ r_valid = true;
+
+ return *v;
+ } else {
+ r_valid = false;
+ }
+
+ } else {
+ r_valid = false;
+ }
+
+ return ret;
+}
+
+/**** INDEXED SETTERS AND GETTERS ****/
+
+#ifdef DEBUG_ENABLED
+
+#define OOB_TEST(m_idx, m_v) \
+ ERR_FAIL_INDEX(m_idx, m_v)
+
+#else
+
+#define OOB_TEST(m_idx, m_v)
+
+#endif
+
+#ifdef DEBUG_ENABLED
+
+#define NULL_TEST(m_key) \
+ ERR_FAIL_COND(!m_key)
+
+#else
+
+#define NULL_TEST(m_key)
+
+#endif
+
+#define INDEXED_SETGET_STRUCT_TYPED(m_base_type, m_elem_type) \
+ struct VariantIndexedSetGet_##m_base_type { \
+ static void get(const Variant *base, int64_t index, Variant *value, bool &oob) { \
+ int64_t size = VariantGetInternalPtr<m_base_type>::get_ptr(base)->size(); \
+ if (index < 0) { \
+ index += size; \
+ } \
+ if (index < 0 || index >= size) { \
+ oob = true; \
+ return; \
+ } \
+ VariantTypeAdjust<m_elem_type>::adjust(value); \
+ *VariantGetInternalPtr<m_elem_type>::get_ptr(value) = (*VariantGetInternalPtr<m_base_type>::get_ptr(base))[index]; \
+ oob = false; \
+ } \
+ static void ptr_get(const void *base, int64_t index, void *member) { \
+ /* avoid ptrconvert for performance*/ \
+ const m_base_type &v = *reinterpret_cast<const m_base_type *>(base); \
+ if (index < 0) \
+ index += v.size(); \
+ OOB_TEST(index, v.size()); \
+ PtrToArg<m_elem_type>::encode(v[index], member); \
+ } \
+ static void set(Variant *base, int64_t index, const Variant *value, bool &valid, bool &oob) { \
+ if (value->get_type() != GetTypeInfo<m_elem_type>::VARIANT_TYPE) { \
+ oob = false; \
+ valid = false; \
+ return; \
+ } \
+ int64_t size = VariantGetInternalPtr<m_base_type>::get_ptr(base)->size(); \
+ if (index < 0) { \
+ index += size; \
+ } \
+ if (index < 0 || index >= size) { \
+ oob = true; \
+ valid = false; \
+ return; \
+ } \
+ (*VariantGetInternalPtr<m_base_type>::get_ptr(base)).write[index] = *VariantGetInternalPtr<m_elem_type>::get_ptr(value); \
+ oob = false; \
+ valid = true; \
+ } \
+ static void validated_set(Variant *base, int64_t index, const Variant *value, bool &oob) { \
+ int64_t size = VariantGetInternalPtr<m_base_type>::get_ptr(base)->size(); \
+ if (index < 0) { \
+ index += size; \
+ } \
+ if (index < 0 || index >= size) { \
+ oob = true; \
+ return; \
+ } \
+ (*VariantGetInternalPtr<m_base_type>::get_ptr(base)).write[index] = *VariantGetInternalPtr<m_elem_type>::get_ptr(value); \
+ oob = false; \
+ } \
+ static void ptr_set(void *base, int64_t index, const void *member) { \
+ /* avoid ptrconvert for performance*/ \
+ m_base_type &v = *reinterpret_cast<m_base_type *>(base); \
+ if (index < 0) \
+ index += v.size(); \
+ OOB_TEST(index, v.size()); \
+ v.write[index] = PtrToArg<m_elem_type>::convert(member); \
+ } \
+ static Variant::Type get_index_type() { return GetTypeInfo<m_elem_type>::VARIANT_TYPE; } \
+ static uint64_t get_indexed_size(const Variant *base) { return VariantGetInternalPtr<m_base_type>::get_ptr(base)->size(); } \
+ };
+
+#define INDEXED_SETGET_STRUCT_TYPED_NUMERIC(m_base_type, m_elem_type, m_assign_type) \
+ struct VariantIndexedSetGet_##m_base_type { \
+ static void get(const Variant *base, int64_t index, Variant *value, bool &oob) { \
+ int64_t size = VariantGetInternalPtr<m_base_type>::get_ptr(base)->size(); \
+ if (index < 0) { \
+ index += size; \
+ } \
+ if (index < 0 || index >= size) { \
+ oob = true; \
+ return; \
+ } \
+ VariantTypeAdjust<m_elem_type>::adjust(value); \
+ *VariantGetInternalPtr<m_elem_type>::get_ptr(value) = (*VariantGetInternalPtr<m_base_type>::get_ptr(base))[index]; \
+ oob = false; \
+ } \
+ static void ptr_get(const void *base, int64_t index, void *member) { \
+ /* avoid ptrconvert for performance*/ \
+ const m_base_type &v = *reinterpret_cast<const m_base_type *>(base); \
+ if (index < 0) \
+ index += v.size(); \
+ OOB_TEST(index, v.size()); \
+ PtrToArg<m_elem_type>::encode(v[index], member); \
+ } \
+ static void set(Variant *base, int64_t index, const Variant *value, bool &valid, bool &oob) { \
+ int64_t size = VariantGetInternalPtr<m_base_type>::get_ptr(base)->size(); \
+ if (index < 0) { \
+ index += size; \
+ } \
+ if (index < 0 || index >= size) { \
+ oob = true; \
+ valid = false; \
+ return; \
+ } \
+ m_assign_type num; \
+ if (value->get_type() == Variant::INT) { \
+ num = (m_assign_type)*VariantGetInternalPtr<int64_t>::get_ptr(value); \
+ } else if (value->get_type() == Variant::FLOAT) { \
+ num = (m_assign_type)*VariantGetInternalPtr<double>::get_ptr(value); \
+ } else { \
+ oob = false; \
+ valid = false; \
+ return; \
+ } \
+ (*VariantGetInternalPtr<m_base_type>::get_ptr(base)).write[index] = num; \
+ oob = false; \
+ valid = true; \
+ } \
+ static void validated_set(Variant *base, int64_t index, const Variant *value, bool &oob) { \
+ int64_t size = VariantGetInternalPtr<m_base_type>::get_ptr(base)->size(); \
+ if (index < 0) { \
+ index += size; \
+ } \
+ if (index < 0 || index >= size) { \
+ oob = true; \
+ return; \
+ } \
+ (*VariantGetInternalPtr<m_base_type>::get_ptr(base)).write[index] = *VariantGetInternalPtr<m_elem_type>::get_ptr(value); \
+ oob = false; \
+ } \
+ static void ptr_set(void *base, int64_t index, const void *member) { \
+ /* avoid ptrconvert for performance*/ \
+ m_base_type &v = *reinterpret_cast<m_base_type *>(base); \
+ if (index < 0) \
+ index += v.size(); \
+ OOB_TEST(index, v.size()); \
+ v.write[index] = PtrToArg<m_elem_type>::convert(member); \
+ } \
+ static Variant::Type get_index_type() { return GetTypeInfo<m_elem_type>::VARIANT_TYPE; } \
+ static uint64_t get_indexed_size(const Variant *base) { return VariantGetInternalPtr<m_base_type>::get_ptr(base)->size(); } \
+ };
+
+#define INDEXED_SETGET_STRUCT_BULTIN_NUMERIC(m_base_type, m_elem_type, m_assign_type, m_max) \
+ struct VariantIndexedSetGet_##m_base_type { \
+ static void get(const Variant *base, int64_t index, Variant *value, bool &oob) { \
+ if (index < 0 || index >= m_max) { \
+ oob = true; \
+ return; \
+ } \
+ VariantTypeAdjust<m_elem_type>::adjust(value); \
+ *VariantGetInternalPtr<m_elem_type>::get_ptr(value) = (*VariantGetInternalPtr<m_base_type>::get_ptr(base))[index]; \
+ oob = false; \
+ } \
+ static void ptr_get(const void *base, int64_t index, void *member) { \
+ /* avoid ptrconvert for performance*/ \
+ const m_base_type &v = *reinterpret_cast<const m_base_type *>(base); \
+ OOB_TEST(index, m_max); \
+ PtrToArg<m_elem_type>::encode(v[index], member); \
+ } \
+ static void set(Variant *base, int64_t index, const Variant *value, bool &valid, bool &oob) { \
+ if (index < 0 || index >= m_max) { \
+ oob = true; \
+ valid = false; \
+ return; \
+ } \
+ m_assign_type num; \
+ if (value->get_type() == Variant::INT) { \
+ num = (m_assign_type)*VariantGetInternalPtr<int64_t>::get_ptr(value); \
+ } else if (value->get_type() == Variant::FLOAT) { \
+ num = (m_assign_type)*VariantGetInternalPtr<double>::get_ptr(value); \
+ } else { \
+ oob = false; \
+ valid = false; \
+ return; \
+ } \
+ (*VariantGetInternalPtr<m_base_type>::get_ptr(base))[index] = num; \
+ oob = false; \
+ valid = true; \
+ } \
+ static void validated_set(Variant *base, int64_t index, const Variant *value, bool &oob) { \
+ if (index < 0 || index >= m_max) { \
+ oob = true; \
+ return; \
+ } \
+ (*VariantGetInternalPtr<m_base_type>::get_ptr(base))[index] = *VariantGetInternalPtr<m_elem_type>::get_ptr(value); \
+ oob = false; \
+ } \
+ static void ptr_set(void *base, int64_t index, const void *member) { \
+ /* avoid ptrconvert for performance*/ \
+ m_base_type &v = *reinterpret_cast<m_base_type *>(base); \
+ OOB_TEST(index, m_max); \
+ v[index] = PtrToArg<m_elem_type>::convert(member); \
+ } \
+ static Variant::Type get_index_type() { return GetTypeInfo<m_elem_type>::VARIANT_TYPE; } \
+ static uint64_t get_indexed_size(const Variant *base) { return m_max; } \
+ };
+
+#define INDEXED_SETGET_STRUCT_BULTIN_ACCESSOR(m_base_type, m_elem_type, m_accessor, m_max) \
+ struct VariantIndexedSetGet_##m_base_type { \
+ static void get(const Variant *base, int64_t index, Variant *value, bool &oob) { \
+ if (index < 0 || index >= m_max) { \
+ oob = true; \
+ return; \
+ } \
+ VariantTypeAdjust<m_elem_type>::adjust(value); \
+ *VariantGetInternalPtr<m_elem_type>::get_ptr(value) = (*VariantGetInternalPtr<m_base_type>::get_ptr(base))m_accessor[index]; \
+ oob = false; \
+ } \
+ static void ptr_get(const void *base, int64_t index, void *member) { \
+ /* avoid ptrconvert for performance*/ \
+ const m_base_type &v = *reinterpret_cast<const m_base_type *>(base); \
+ OOB_TEST(index, m_max); \
+ PtrToArg<m_elem_type>::encode(v m_accessor[index], member); \
+ } \
+ static void set(Variant *base, int64_t index, const Variant *value, bool &valid, bool &oob) { \
+ if (value->get_type() != GetTypeInfo<m_elem_type>::VARIANT_TYPE) { \
+ oob = false; \
+ valid = false; \
+ } \
+ if (index < 0 || index >= m_max) { \
+ oob = true; \
+ valid = false; \
+ return; \
+ } \
+ (*VariantGetInternalPtr<m_base_type>::get_ptr(base)) m_accessor[index] = *VariantGetInternalPtr<m_elem_type>::get_ptr(value); \
+ oob = false; \
+ valid = true; \
+ } \
+ static void validated_set(Variant *base, int64_t index, const Variant *value, bool &oob) { \
+ if (index < 0 || index >= m_max) { \
+ oob = true; \
+ return; \
+ } \
+ (*VariantGetInternalPtr<m_base_type>::get_ptr(base)) m_accessor[index] = *VariantGetInternalPtr<m_elem_type>::get_ptr(value); \
+ oob = false; \
+ } \
+ static void ptr_set(void *base, int64_t index, const void *member) { \
+ /* avoid ptrconvert for performance*/ \
+ m_base_type &v = *reinterpret_cast<m_base_type *>(base); \
+ OOB_TEST(index, m_max); \
+ v m_accessor[index] = PtrToArg<m_elem_type>::convert(member); \
+ } \
+ static Variant::Type get_index_type() { return GetTypeInfo<m_elem_type>::VARIANT_TYPE; } \
+ static uint64_t get_indexed_size(const Variant *base) { return m_max; } \
+ };
+
+#define INDEXED_SETGET_STRUCT_BULTIN_FUNC(m_base_type, m_elem_type, m_set, m_get, m_max) \
+ struct VariantIndexedSetGet_##m_base_type { \
+ static void get(const Variant *base, int64_t index, Variant *value, bool &oob) { \
+ if (index < 0 || index >= m_max) { \
+ oob = true; \
+ return; \
+ } \
+ VariantTypeAdjust<m_elem_type>::adjust(value); \
+ *VariantGetInternalPtr<m_elem_type>::get_ptr(value) = VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_get(index); \
+ oob = false; \
+ } \
+ static void ptr_get(const void *base, int64_t index, void *member) { \
+ /* avoid ptrconvert for performance*/ \
+ const m_base_type &v = *reinterpret_cast<const m_base_type *>(base); \
+ OOB_TEST(index, m_max); \
+ PtrToArg<m_elem_type>::encode(v.m_get(index), member); \
+ } \
+ static void set(Variant *base, int64_t index, const Variant *value, bool &valid, bool &oob) { \
+ if (value->get_type() != GetTypeInfo<m_elem_type>::VARIANT_TYPE) { \
+ oob = false; \
+ valid = false; \
+ } \
+ if (index < 0 || index >= m_max) { \
+ oob = true; \
+ valid = false; \
+ return; \
+ } \
+ VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_set(index, *VariantGetInternalPtr<m_elem_type>::get_ptr(value)); \
+ oob = false; \
+ valid = true; \
+ } \
+ static void validated_set(Variant *base, int64_t index, const Variant *value, bool &oob) { \
+ if (index < 0 || index >= m_max) { \
+ oob = true; \
+ return; \
+ } \
+ VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_set(index, *VariantGetInternalPtr<m_elem_type>::get_ptr(value)); \
+ oob = false; \
+ } \
+ static void ptr_set(void *base, int64_t index, const void *member) { \
+ /* avoid ptrconvert for performance*/ \
+ m_base_type &v = *reinterpret_cast<m_base_type *>(base); \
+ OOB_TEST(index, m_max); \
+ v.m_set(index, PtrToArg<m_elem_type>::convert(member)); \
+ } \
+ static Variant::Type get_index_type() { return GetTypeInfo<m_elem_type>::VARIANT_TYPE; } \
+ static uint64_t get_indexed_size(const Variant *base) { return m_max; } \
+ };
+
+#define INDEXED_SETGET_STRUCT_VARIANT(m_base_type) \
+ struct VariantIndexedSetGet_##m_base_type { \
+ static void get(const Variant *base, int64_t index, Variant *value, bool &oob) { \
+ int64_t size = VariantGetInternalPtr<m_base_type>::get_ptr(base)->size(); \
+ if (index < 0) { \
+ index += size; \
+ } \
+ if (index < 0 || index >= size) { \
+ oob = true; \
+ return; \
+ } \
+ *value = (*VariantGetInternalPtr<m_base_type>::get_ptr(base))[index]; \
+ oob = false; \
+ } \
+ static void ptr_get(const void *base, int64_t index, void *member) { \
+ /* avoid ptrconvert for performance*/ \
+ const m_base_type &v = *reinterpret_cast<const m_base_type *>(base); \
+ if (index < 0) \
+ index += v.size(); \
+ OOB_TEST(index, v.size()); \
+ PtrToArg<Variant>::encode(v[index], member); \
+ } \
+ static void set(Variant *base, int64_t index, const Variant *value, bool &valid, bool &oob) { \
+ int64_t size = VariantGetInternalPtr<m_base_type>::get_ptr(base)->size(); \
+ if (index < 0) { \
+ index += size; \
+ } \
+ if (index < 0 || index >= size) { \
+ oob = true; \
+ valid = false; \
+ return; \
+ } \
+ (*VariantGetInternalPtr<m_base_type>::get_ptr(base))[index] = *value; \
+ oob = false; \
+ valid = true; \
+ } \
+ static void validated_set(Variant *base, int64_t index, const Variant *value, bool &oob) { \
+ int64_t size = VariantGetInternalPtr<m_base_type>::get_ptr(base)->size(); \
+ if (index < 0) { \
+ index += size; \
+ } \
+ if (index < 0 || index >= size) { \
+ oob = true; \
+ return; \
+ } \
+ (*VariantGetInternalPtr<m_base_type>::get_ptr(base))[index] = *value; \
+ oob = false; \
+ } \
+ static void ptr_set(void *base, int64_t index, const void *member) { \
+ /* avoid ptrconvert for performance*/ \
+ m_base_type &v = *reinterpret_cast<m_base_type *>(base); \
+ if (index < 0) \
+ index += v.size(); \
+ OOB_TEST(index, v.size()); \
+ v[index] = PtrToArg<Variant>::convert(member); \
+ } \
+ static Variant::Type get_index_type() { return Variant::NIL; } \
+ static uint64_t get_indexed_size(const Variant *base) { return 0; } \
+ };
+
+#define INDEXED_SETGET_STRUCT_DICT(m_base_type) \
+ struct VariantIndexedSetGet_##m_base_type { \
+ static void get(const Variant *base, int64_t index, Variant *value, bool &oob) { \
+ const Variant *ptr = VariantGetInternalPtr<m_base_type>::get_ptr(base)->getptr(index); \
+ if (!ptr) { \
+ oob = true; \
+ return; \
+ } \
+ *value = *ptr; \
+ oob = false; \
+ } \
+ static void ptr_get(const void *base, int64_t index, void *member) { \
+ /* avoid ptrconvert for performance*/ \
+ const m_base_type &v = *reinterpret_cast<const m_base_type *>(base); \
+ const Variant *ptr = v.getptr(index); \
+ NULL_TEST(ptr); \
+ PtrToArg<Variant>::encode(*ptr, member); \
+ } \
+ static void set(Variant *base, int64_t index, const Variant *value, bool &valid, bool &oob) { \
+ (*VariantGetInternalPtr<m_base_type>::get_ptr(base))[index] = *value; \
+ oob = false; \
+ valid = true; \
+ } \
+ static void validated_set(Variant *base, int64_t index, const Variant *value, bool &oob) { \
+ (*VariantGetInternalPtr<m_base_type>::get_ptr(base))[index] = *value; \
+ oob = false; \
+ } \
+ static void ptr_set(void *base, int64_t index, const void *member) { \
+ m_base_type &v = *reinterpret_cast<m_base_type *>(base); \
+ v[index] = PtrToArg<Variant>::convert(member); \
+ } \
+ static Variant::Type get_index_type() { return Variant::NIL; } \
+ static uint64_t get_indexed_size(const Variant *base) { return VariantGetInternalPtr<m_base_type>::get_ptr(base)->size(); } \
+ };
+
+INDEXED_SETGET_STRUCT_BULTIN_NUMERIC(Vector2, double, real_t, 2)
+INDEXED_SETGET_STRUCT_BULTIN_NUMERIC(Vector2i, int64_t, int32_t, 2)
+INDEXED_SETGET_STRUCT_BULTIN_NUMERIC(Vector3, double, real_t, 3)
+INDEXED_SETGET_STRUCT_BULTIN_NUMERIC(Vector3i, int64_t, int32_t, 3)
+INDEXED_SETGET_STRUCT_BULTIN_NUMERIC(Quat, double, real_t, 4)
+INDEXED_SETGET_STRUCT_BULTIN_NUMERIC(Color, double, float, 4)
+
+INDEXED_SETGET_STRUCT_BULTIN_ACCESSOR(Transform2D, Vector2, .elements, 3)
+INDEXED_SETGET_STRUCT_BULTIN_FUNC(Basis, Vector3, set_axis, get_axis, 3)
+
+INDEXED_SETGET_STRUCT_TYPED_NUMERIC(PackedByteArray, int64_t, uint8_t)
+INDEXED_SETGET_STRUCT_TYPED_NUMERIC(PackedInt32Array, int64_t, int32_t)
+INDEXED_SETGET_STRUCT_TYPED_NUMERIC(PackedInt64Array, int64_t, int64_t)
+INDEXED_SETGET_STRUCT_TYPED_NUMERIC(PackedFloat32Array, double, float)
+INDEXED_SETGET_STRUCT_TYPED_NUMERIC(PackedFloat64Array, double, double)
+INDEXED_SETGET_STRUCT_TYPED(PackedVector2Array, Vector2)
+INDEXED_SETGET_STRUCT_TYPED(PackedVector3Array, Vector3)
+INDEXED_SETGET_STRUCT_TYPED(PackedStringArray, String)
+INDEXED_SETGET_STRUCT_TYPED(PackedColorArray, Color)
+
+INDEXED_SETGET_STRUCT_VARIANT(Array)
+INDEXED_SETGET_STRUCT_DICT(Dictionary)
+
+struct VariantIndexedSetterGetterInfo {
+ void (*setter)(Variant *base, int64_t index, const Variant *value, bool &valid, bool &oob);
+ void (*getter)(const Variant *base, int64_t index, Variant *value, bool &oob);
+
+ Variant::ValidatedIndexedSetter validated_setter;
+ Variant::ValidatedIndexedGetter validated_getter;
+
+ Variant::PTRIndexedSetter ptr_setter;
+ Variant::PTRIndexedGetter ptr_getter;
+
+ uint64_t (*get_indexed_size)(const Variant *base);
+
+ Variant::Type index_type;
+
+ bool valid = false;
+};
+
+static VariantIndexedSetterGetterInfo variant_indexed_setters_getters[Variant::VARIANT_MAX];
+
+template <class T>
+static void register_indexed_member(Variant::Type p_type) {
+ VariantIndexedSetterGetterInfo &sgi = variant_indexed_setters_getters[p_type];
+
+ sgi.setter = T::set;
+ sgi.validated_setter = T::validated_set;
+ sgi.ptr_setter = T::ptr_set;
+
+ sgi.getter = T::get;
+ sgi.validated_getter = T::get;
+ sgi.ptr_getter = T::ptr_get;
+
+ sgi.index_type = T::get_index_type();
+ sgi.get_indexed_size = T::get_indexed_size;
+
+ sgi.valid = true;
+}
+
+void register_indexed_setters_getters() {
+#define REGISTER_INDEXED_MEMBER(m_base_type) register_indexed_member<VariantIndexedSetGet_##m_base_type>(GetTypeInfo<m_base_type>::VARIANT_TYPE)
+
+ REGISTER_INDEXED_MEMBER(Vector2);
+ REGISTER_INDEXED_MEMBER(Vector2i);
+ REGISTER_INDEXED_MEMBER(Vector3);
+ REGISTER_INDEXED_MEMBER(Vector3i);
+ REGISTER_INDEXED_MEMBER(Quat);
+ REGISTER_INDEXED_MEMBER(Color);
+ REGISTER_INDEXED_MEMBER(Transform2D);
+ REGISTER_INDEXED_MEMBER(Basis);
+
+ REGISTER_INDEXED_MEMBER(PackedByteArray);
+ REGISTER_INDEXED_MEMBER(PackedInt32Array);
+ REGISTER_INDEXED_MEMBER(PackedInt64Array);
+ REGISTER_INDEXED_MEMBER(PackedFloat64Array);
+ REGISTER_INDEXED_MEMBER(PackedVector2Array);
+ REGISTER_INDEXED_MEMBER(PackedVector3Array);
+ REGISTER_INDEXED_MEMBER(PackedStringArray);
+ REGISTER_INDEXED_MEMBER(PackedColorArray);
+
+ REGISTER_INDEXED_MEMBER(Array);
+ REGISTER_INDEXED_MEMBER(Dictionary);
+}
+
+static void unregister_indexed_setters_getters() {
+}
+
+bool Variant::has_indexing(Variant::Type p_type) {
+ ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, false);
+ return variant_indexed_setters_getters[p_type].valid;
+}
+
+Variant::Type Variant::get_indexed_element_type(Variant::Type p_type) {
+ ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, Variant::VARIANT_MAX);
+ return variant_indexed_setters_getters[p_type].index_type;
+}
+
+Variant::ValidatedIndexedSetter Variant::get_member_validated_indexed_setter(Variant::Type p_type) {
+ ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, nullptr);
+ return variant_indexed_setters_getters[p_type].validated_setter;
+}
+Variant::ValidatedIndexedGetter Variant::get_member_validated_indexed_getter(Variant::Type p_type) {
+ ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, nullptr);
+ return variant_indexed_setters_getters[p_type].validated_getter;
+}
+
+Variant::PTRIndexedSetter Variant::get_member_ptr_indexed_setter(Variant::Type p_type) {
+ ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, nullptr);
+ return variant_indexed_setters_getters[p_type].ptr_setter;
+}
+Variant::PTRIndexedGetter Variant::get_member_ptr_indexed_getter(Variant::Type p_type) {
+ ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, nullptr);
+ return variant_indexed_setters_getters[p_type].ptr_getter;
+}
+
+void Variant::set_indexed(int64_t p_index, const Variant &p_value, bool &r_valid, bool &r_oob) {
+ if (likely(variant_indexed_setters_getters[type].valid)) {
+ variant_indexed_setters_getters[type].setter(this, p_index, &p_value, r_valid, r_oob);
+ } else {
+ r_valid = false;
+ r_oob = false;
+ }
+}
+Variant Variant::get_indexed(int64_t p_index, bool &r_valid, bool &r_oob) const {
+ if (likely(variant_indexed_setters_getters[type].valid)) {
+ Variant ret;
+ variant_indexed_setters_getters[type].getter(this, p_index, &ret, r_oob);
+ r_valid = !r_oob;
+ return ret;
+ } else {
+ r_valid = false;
+ r_oob = false;
+ return Variant();
+ }
+}
+
+uint64_t Variant::get_indexed_size() const {
+ if (likely(variant_indexed_setters_getters[type].valid && variant_indexed_setters_getters[type].get_indexed_size)) {
+ return variant_indexed_setters_getters[type].get_indexed_size(this);
+ } else {
+ return 0;
+ }
+}
+
+struct VariantKeyedSetGetDictionary {
+ static void get(const Variant *base, const Variant *key, Variant *value, bool &r_valid) {
+ const Variant *ptr = VariantGetInternalPtr<Dictionary>::get_ptr(base)->getptr(*key);
+ if (!ptr) {
+ r_valid = false;
+ return;
+ }
+ *value = *ptr;
+ r_valid = true;
+ }
+ static void ptr_get(const void *base, const void *key, void *value) {
+ /* avoid ptrconvert for performance*/
+ const Dictionary &v = *reinterpret_cast<const Dictionary *>(base);
+ const Variant *ptr = v.getptr(PtrToArg<Variant>::convert(key));
+ NULL_TEST(ptr);
+ PtrToArg<Variant>::encode(*ptr, value);
+ }
+ static void set(Variant *base, const Variant *key, const Variant *value, bool &r_valid) {
+ (*VariantGetInternalPtr<Dictionary>::get_ptr(base))[*key] = *value;
+ r_valid = true;
+ }
+ static void ptr_set(void *base, const void *key, const void *value) {
+ Dictionary &v = *reinterpret_cast<Dictionary *>(base);
+ v[PtrToArg<Variant>::convert(key)] = PtrToArg<Variant>::convert(value);
+ }
+
+ static bool has(const Variant *base, const Variant *key, bool &r_valid) {
+ r_valid = true;
+ return VariantGetInternalPtr<Dictionary>::get_ptr(base)->has(*key);
+ }
+ static bool ptr_has(const void *base, const void *key) {
+ /* avoid ptrconvert for performance*/
+ const Dictionary &v = *reinterpret_cast<const Dictionary *>(base);
+ return v.has(PtrToArg<Variant>::convert(key));
+ }
+};
+
+struct VariantKeyedSetGetObject {
+ static void get(const Variant *base, const Variant *key, Variant *value, bool &r_valid) {
+ Object *obj = base->get_validated_object();
+
+ if (!obj) {
+ r_valid = false;
+ *value = Variant();
+ return;
+ }
+ *value = obj->getvar(*key, &r_valid);
+ }
+ static void ptr_get(const void *base, const void *key, void *value) {
+ const Object *obj = PtrToArg<Object *>::convert(base);
+ NULL_TEST(obj);
+ Variant v = obj->getvar(PtrToArg<Variant>::convert(key));
+ PtrToArg<Variant>::encode(v, value);
+ }
+ static void set(Variant *base, const Variant *key, const Variant *value, bool &r_valid) {
+ Object *obj = base->get_validated_object();
+
+ if (!obj) {
+ r_valid = false;
+ return;
+ }
+ obj->setvar(*key, *value, &r_valid);
+ }
+ static void ptr_set(void *base, const void *key, const void *value) {
+ Object *obj = PtrToArg<Object *>::convert(base);
+ NULL_TEST(obj);
+ obj->setvar(PtrToArg<Variant>::convert(key), PtrToArg<Variant>::convert(value));
+ }
+
+ static bool has(const Variant *base, const Variant *key, bool &r_valid) {
+ Object *obj = base->get_validated_object();
+ if (obj != nullptr) {
+ r_valid = false;
+ return false;
+ }
+ r_valid = true;
+ bool exists;
+ obj->getvar(*key, &exists);
+ return exists;
+ }
+ static bool ptr_has(const void *base, const void *key) {
+ const Object *obj = PtrToArg<Object *>::convert(base);
+ ERR_FAIL_COND_V(!obj, false);
+ bool valid;
+ obj->getvar(PtrToArg<Variant>::convert(key), &valid);
+ return valid;
+ }
+};
+
+/*typedef void (*ValidatedKeyedSetter)(Variant *base, const Variant *key, const Variant *value);
+typedef void (*ValidatedKeyedGetter)(const Variant *base, const Variant *key, Variant *value, bool &valid);
+typedef bool (*ValidatedKeyedChecker)(const Variant *base, const Variant *key);
+
+typedef void (*PTRKeyedSetter)(void *base, const void *key, const void *value);
+typedef void (*PTRKeyedGetter)(const void *base, const void *key, void *value);
+typedef bool (*PTRKeyedChecker)(const void *base, const void *key);*/
+
+struct VariantKeyedSetterGetterInfo {
+ Variant::ValidatedKeyedSetter validated_setter;
+ Variant::ValidatedKeyedGetter validated_getter;
+ Variant::ValidatedKeyedChecker validated_checker;
+
+ Variant::PTRKeyedSetter ptr_setter;
+ Variant::PTRKeyedGetter ptr_getter;
+ Variant::PTRKeyedChecker ptr_checker;
+
+ bool valid = false;
+};
+
+static VariantKeyedSetterGetterInfo variant_keyed_setters_getters[Variant::VARIANT_MAX];
+
+template <class T>
+static void register_keyed_member(Variant::Type p_type) {
+ VariantKeyedSetterGetterInfo &sgi = variant_keyed_setters_getters[p_type];
+
+ sgi.validated_setter = T::set;
+ sgi.ptr_setter = T::ptr_set;
+
+ sgi.validated_getter = T::get;
+ sgi.ptr_getter = T::ptr_get;
+
+ sgi.validated_checker = T::has;
+ sgi.ptr_checker = T::ptr_has;
+
+ sgi.valid = true;
+}
+
+static void register_keyed_setters_getters() {
+ register_keyed_member<VariantKeyedSetGetDictionary>(Variant::DICTIONARY);
+ register_keyed_member<VariantKeyedSetGetObject>(Variant::OBJECT);
+}
+bool Variant::is_keyed(Variant::Type p_type) {
+ ERR_FAIL_INDEX_V(p_type, VARIANT_MAX, false);
+ return variant_keyed_setters_getters[p_type].valid;
+}
+
+Variant::ValidatedKeyedSetter Variant::get_member_validated_keyed_setter(Variant::Type p_type) {
+ ERR_FAIL_INDEX_V(p_type, VARIANT_MAX, nullptr);
+ return variant_keyed_setters_getters[p_type].validated_setter;
+}
+Variant::ValidatedKeyedGetter Variant::get_member_validated_keyed_getter(Variant::Type p_type) {
+ ERR_FAIL_INDEX_V(p_type, VARIANT_MAX, nullptr);
+ return variant_keyed_setters_getters[p_type].validated_getter;
+}
+Variant::ValidatedKeyedChecker Variant::get_member_validated_keyed_checker(Variant::Type p_type) {
+ ERR_FAIL_INDEX_V(p_type, VARIANT_MAX, nullptr);
+ return variant_keyed_setters_getters[p_type].validated_checker;
+}
+
+Variant::PTRKeyedSetter Variant::get_member_ptr_keyed_setter(Variant::Type p_type) {
+ ERR_FAIL_INDEX_V(p_type, VARIANT_MAX, nullptr);
+ return variant_keyed_setters_getters[p_type].ptr_setter;
+}
+Variant::PTRKeyedGetter Variant::get_member_ptr_keyed_getter(Variant::Type p_type) {
+ ERR_FAIL_INDEX_V(p_type, VARIANT_MAX, nullptr);
+ return variant_keyed_setters_getters[p_type].ptr_getter;
+}
+Variant::PTRKeyedChecker Variant::get_member_ptr_keyed_checker(Variant::Type p_type) {
+ ERR_FAIL_INDEX_V(p_type, VARIANT_MAX, nullptr);
+ return variant_keyed_setters_getters[p_type].ptr_checker;
+}
+
+void Variant::set_keyed(const Variant &p_key, const Variant &p_value, bool &r_valid) {
+ if (likely(variant_keyed_setters_getters[type].valid)) {
+ variant_keyed_setters_getters[type].validated_setter(this, &p_key, &p_value, r_valid);
+ } else {
+ r_valid = false;
+ }
+}
+Variant Variant::get_keyed(const Variant &p_key, bool &r_valid) const {
+ if (likely(variant_keyed_setters_getters[type].valid)) {
+ Variant ret;
+ variant_keyed_setters_getters[type].validated_getter(this, &p_key, &ret, r_valid);
+ return ret;
+ } else {
+ r_valid = false;
+ return Variant();
+ }
+}
+bool Variant::has_key(const Variant &p_key, bool &r_valid) const {
+ if (likely(variant_keyed_setters_getters[type].valid)) {
+ return variant_keyed_setters_getters[type].validated_checker(this, &p_key, r_valid);
+ } else {
+ r_valid = false;
+ return false;
+ }
+}
+
+void Variant::set(const Variant &p_index, const Variant &p_value, bool *r_valid) {
+ if (type == DICTIONARY || type == OBJECT) {
+ bool valid;
+ set_keyed(p_index, p_value, valid);
+ if (r_valid) {
+ *r_valid = valid;
+ }
+ } else {
+ bool valid = false;
+ if (p_index.get_type() == STRING_NAME) {
+ set_named(*VariantGetInternalPtr<StringName>::get_ptr(&p_index), p_value, valid);
+ } else if (p_index.get_type() == INT) {
+ bool obb;
+ set_indexed(*VariantGetInternalPtr<int64_t>::get_ptr(&p_index), p_value, valid, obb);
+ if (obb) {
+ valid = false;
+ }
+ } else if (p_index.get_type() == STRING) { // less efficient version of named
+ set_named(*VariantGetInternalPtr<String>::get_ptr(&p_index), p_value, valid);
+ } else if (p_index.get_type() == FLOAT) { // less efficient version of indexed
+ bool obb;
+ set_indexed(*VariantGetInternalPtr<double>::get_ptr(&p_index), p_value, valid, obb);
+ if (obb) {
+ valid = false;
+ }
+ }
+ if (r_valid) {
+ *r_valid = valid;
+ }
+ }
+}
+
+Variant Variant::get(const Variant &p_index, bool *r_valid) const {
+ Variant ret;
+ if (type == DICTIONARY || type == OBJECT) {
+ bool valid;
+ ret = get_keyed(p_index, valid);
+ if (r_valid) {
+ *r_valid = valid;
+ }
+ } else {
+ bool valid = false;
+ if (p_index.get_type() == STRING_NAME) {
+ ret = get_named(*VariantGetInternalPtr<StringName>::get_ptr(&p_index), valid);
+ } else if (p_index.get_type() == INT) {
+ bool obb;
+ ret = get_indexed(*VariantGetInternalPtr<int64_t>::get_ptr(&p_index), valid, obb);
+ if (obb) {
+ valid = false;
+ }
+ } else if (p_index.get_type() == STRING) { // less efficient version of named
+ ret = get_named(*VariantGetInternalPtr<String>::get_ptr(&p_index), valid);
+ } else if (p_index.get_type() == FLOAT) { // less efficient version of indexed
+ bool obb;
+ ret = get_indexed(*VariantGetInternalPtr<double>::get_ptr(&p_index), valid, obb);
+ if (obb) {
+ valid = false;
+ }
+ }
+ if (r_valid) {
+ *r_valid = valid;
+ }
+ }
+
+ return ret;
+}
+
+void Variant::get_property_list(List<PropertyInfo> *p_list) const {
+ if (type == DICTIONARY) {
+ const Dictionary *dic = reinterpret_cast<const Dictionary *>(_data._mem);
+ List<Variant> keys;
+ dic->get_key_list(&keys);
+ for (List<Variant>::Element *E = keys.front(); E; E = E->next()) {
+ if (E->get().get_type() == Variant::STRING) {
+ p_list->push_back(PropertyInfo(Variant::STRING, E->get()));
+ }
+ }
+ } else if (type == OBJECT) {
+ Object *obj = get_validated_object();
+ ERR_FAIL_COND(!obj);
+ obj->get_property_list(p_list);
+
+ } else {
+ List<StringName> members;
+ get_member_list(type, &members);
+ for (List<StringName>::Element *E = members.front(); E; E = E->next()) {
+ PropertyInfo pi;
+ pi.name = E->get();
+ pi.type = get_member_type(type, E->get());
+ p_list->push_back(pi);
+ }
+ }
+}
+
+bool Variant::iter_init(Variant &r_iter, bool &valid) const {
+ valid = true;
+ switch (type) {
+ case INT: {
+ r_iter = 0;
+ return _data._int > 0;
+ } break;
+ case FLOAT: {
+ r_iter = 0;
+ return _data._float > 0.0;
+ } break;
+ case VECTOR2: {
+ double from = reinterpret_cast<const Vector2 *>(_data._mem)->x;
+ double to = reinterpret_cast<const Vector2 *>(_data._mem)->y;
+
+ r_iter = from;
+
+ return from < to;
+ } break;
+ case VECTOR2I: {
+ int64_t from = reinterpret_cast<const Vector2i *>(_data._mem)->x;
+ int64_t to = reinterpret_cast<const Vector2i *>(_data._mem)->y;
+
+ r_iter = from;
+
+ return from < to;
+ } break;
+ case VECTOR3: {
+ double from = reinterpret_cast<const Vector3 *>(_data._mem)->x;
+ double to = reinterpret_cast<const Vector3 *>(_data._mem)->y;
+ double step = reinterpret_cast<const Vector3 *>(_data._mem)->z;
+
+ r_iter = from;
+
+ if (from == to) {
+ return false;
+ } else if (from < to) {
+ return step > 0;
+ }
+ return step < 0;
+ } break;
+ case VECTOR3I: {
+ int64_t from = reinterpret_cast<const Vector3i *>(_data._mem)->x;
+ int64_t to = reinterpret_cast<const Vector3i *>(_data._mem)->y;
+ int64_t step = reinterpret_cast<const Vector3i *>(_data._mem)->z;
+
+ r_iter = from;
+
+ if (from == to) {
+ return false;
+ } else if (from < to) {
+ return step > 0;
+ }
+ return step < 0;
+ } break;
+ case OBJECT: {
+ if (!_get_obj().obj) {
+ valid = false;
+ return false;
+ }
+
+#ifdef DEBUG_ENABLED
+
+ if (EngineDebugger::is_active() && !_get_obj().id.is_reference() && ObjectDB::get_instance(_get_obj().id) == nullptr) {
+ valid = false;
+ return false;
+ }
+
+#endif
+ Callable::CallError ce;
+ ce.error = Callable::CallError::CALL_OK;
+ Array ref;
+ ref.push_back(r_iter);
+ Variant vref = ref;
+ const Variant *refp[] = { &vref };
+ Variant ret = _get_obj().obj->call(CoreStringNames::get_singleton()->_iter_init, refp, 1, ce);
+
+ if (ref.size() != 1 || ce.error != Callable::CallError::CALL_OK) {
+ valid = false;
+ return false;
+ }
+
+ r_iter = ref[0];
+ return ret;
+ } break;
+
+ case STRING: {
+ const String *str = reinterpret_cast<const String *>(_data._mem);
+ if (str->empty()) {
+ return false;
+ }
+ r_iter = 0;
+ return true;
+ } break;
+ case DICTIONARY: {
+ const Dictionary *dic = reinterpret_cast<const Dictionary *>(_data._mem);
+ if (dic->empty()) {
+ return false;
+ }
+
+ const Variant *next = dic->next(nullptr);
+ r_iter = *next;
+ return true;
+
+ } break;
+ case ARRAY: {
+ const Array *arr = reinterpret_cast<const Array *>(_data._mem);
+ if (arr->empty()) {
+ return false;
+ }
+ r_iter = 0;
+ return true;
+ } break;
+ case PACKED_BYTE_ARRAY: {
+ const Vector<uint8_t> *arr = &PackedArrayRef<uint8_t>::get_array(_data.packed_array);
+ if (arr->size() == 0) {
+ return false;
+ }
+ r_iter = 0;
+ return true;
+
+ } break;
+ case PACKED_INT32_ARRAY: {
+ const Vector<int32_t> *arr = &PackedArrayRef<int32_t>::get_array(_data.packed_array);
+ if (arr->size() == 0) {
+ return false;
+ }
+ r_iter = 0;
+ return true;
+
+ } break;
+ case PACKED_INT64_ARRAY: {
+ const Vector<int64_t> *arr = &PackedArrayRef<int64_t>::get_array(_data.packed_array);
+ if (arr->size() == 0) {
+ return false;
+ }
+ r_iter = 0;
+ return true;
+
+ } break;
+ case PACKED_FLOAT32_ARRAY: {
+ const Vector<float> *arr = &PackedArrayRef<float>::get_array(_data.packed_array);
+ if (arr->size() == 0) {
+ return false;
+ }
+ r_iter = 0;
+ return true;
+
+ } break;
+ case PACKED_FLOAT64_ARRAY: {
+ const Vector<double> *arr = &PackedArrayRef<double>::get_array(_data.packed_array);
+ if (arr->size() == 0) {
+ return false;
+ }
+ r_iter = 0;
+ return true;
+
+ } break;
+ case PACKED_STRING_ARRAY: {
+ const Vector<String> *arr = &PackedArrayRef<String>::get_array(_data.packed_array);
+ if (arr->size() == 0) {
+ return false;
+ }
+ r_iter = 0;
+ return true;
+ } break;
+ case PACKED_VECTOR2_ARRAY: {
+ const Vector<Vector2> *arr = &PackedArrayRef<Vector2>::get_array(_data.packed_array);
+ if (arr->size() == 0) {
+ return false;
+ }
+ r_iter = 0;
+ return true;
+ } break;
+ case PACKED_VECTOR3_ARRAY: {
+ const Vector<Vector3> *arr = &PackedArrayRef<Vector3>::get_array(_data.packed_array);
+ if (arr->size() == 0) {
+ return false;
+ }
+ r_iter = 0;
+ return true;
+ } break;
+ case PACKED_COLOR_ARRAY: {
+ const Vector<Color> *arr = &PackedArrayRef<Color>::get_array(_data.packed_array);
+ if (arr->size() == 0) {
+ return false;
+ }
+ r_iter = 0;
+ return true;
+
+ } break;
+ default: {
+ }
+ }
+
+ valid = false;
+ return false;
+}
+
+bool Variant::iter_next(Variant &r_iter, bool &valid) const {
+ valid = true;
+ switch (type) {
+ case INT: {
+ int64_t idx = r_iter;
+ idx++;
+ if (idx >= _data._int) {
+ return false;
+ }
+ r_iter = idx;
+ return true;
+ } break;
+ case FLOAT: {
+ int64_t idx = r_iter;
+ idx++;
+ if (idx >= _data._float) {
+ return false;
+ }
+ r_iter = idx;
+ return true;
+ } break;
+ case VECTOR2: {
+ double to = reinterpret_cast<const Vector2 *>(_data._mem)->y;
+
+ double idx = r_iter;
+ idx++;
+
+ if (idx >= to) {
+ return false;
+ }
+
+ r_iter = idx;
+ return true;
+ } break;
+ case VECTOR2I: {
+ int64_t to = reinterpret_cast<const Vector2i *>(_data._mem)->y;
+
+ int64_t idx = r_iter;
+ idx++;
+
+ if (idx >= to) {
+ return false;
+ }
+
+ r_iter = idx;
+ return true;
+ } break;
+ case VECTOR3: {
+ double to = reinterpret_cast<const Vector3 *>(_data._mem)->y;
+ double step = reinterpret_cast<const Vector3 *>(_data._mem)->z;
+
+ double idx = r_iter;
+ idx += step;
+
+ if (step < 0 && idx <= to) {
+ return false;
+ }
+
+ if (step > 0 && idx >= to) {
+ return false;
+ }
+
+ r_iter = idx;
+ return true;
+ } break;
+ case VECTOR3I: {
+ int64_t to = reinterpret_cast<const Vector3i *>(_data._mem)->y;
+ int64_t step = reinterpret_cast<const Vector3i *>(_data._mem)->z;
+
+ int64_t idx = r_iter;
+ idx += step;
+
+ if (step < 0 && idx <= to) {
+ return false;
+ }
+
+ if (step > 0 && idx >= to) {
+ return false;
+ }
+
+ r_iter = idx;
+ return true;
+ } break;
+ case OBJECT: {
+ if (!_get_obj().obj) {
+ valid = false;
+ return false;
+ }
+
+#ifdef DEBUG_ENABLED
+
+ if (EngineDebugger::is_active() && !_get_obj().id.is_reference() && ObjectDB::get_instance(_get_obj().id) == nullptr) {
+ valid = false;
+ return false;
+ }
+
+#endif
+ Callable::CallError ce;
+ ce.error = Callable::CallError::CALL_OK;
+ Array ref;
+ ref.push_back(r_iter);
+ Variant vref = ref;
+ const Variant *refp[] = { &vref };
+ Variant ret = _get_obj().obj->call(CoreStringNames::get_singleton()->_iter_next, refp, 1, ce);
+
+ if (ref.size() != 1 || ce.error != Callable::CallError::CALL_OK) {
+ valid = false;
+ return false;
+ }
+
+ r_iter = ref[0];
+
+ return ret;
+ } break;
+
+ case STRING: {
+ const String *str = reinterpret_cast<const String *>(_data._mem);
+ int idx = r_iter;
+ idx++;
+ if (idx >= str->length()) {
+ return false;
+ }
+ r_iter = idx;
+ return true;
+ } break;
+ case DICTIONARY: {
+ const Dictionary *dic = reinterpret_cast<const Dictionary *>(_data._mem);
+ const Variant *next = dic->next(&r_iter);
+ if (!next) {
+ return false;
+ }
+
+ r_iter = *next;
+ return true;
+
+ } break;
+ case ARRAY: {
+ const Array *arr = reinterpret_cast<const Array *>(_data._mem);
+ int idx = r_iter;
+ idx++;
+ if (idx >= arr->size()) {
+ return false;
+ }
+ r_iter = idx;
+ return true;
+ } break;
+ case PACKED_BYTE_ARRAY: {
+ const Vector<uint8_t> *arr = &PackedArrayRef<uint8_t>::get_array(_data.packed_array);
+ int idx = r_iter;
+ idx++;
+ if (idx >= arr->size()) {
+ return false;
+ }
+ r_iter = idx;
+ return true;
+
+ } break;
+ case PACKED_INT32_ARRAY: {
+ const Vector<int32_t> *arr = &PackedArrayRef<int32_t>::get_array(_data.packed_array);
+ int32_t idx = r_iter;
+ idx++;
+ if (idx >= arr->size()) {
+ return false;
+ }
+ r_iter = idx;
+ return true;
+
+ } break;
+ case PACKED_INT64_ARRAY: {
+ const Vector<int64_t> *arr = &PackedArrayRef<int64_t>::get_array(_data.packed_array);
+ int64_t idx = r_iter;
+ idx++;
+ if (idx >= arr->size()) {
+ return false;
+ }
+ r_iter = idx;
+ return true;
+
+ } break;
+ case PACKED_FLOAT32_ARRAY: {
+ const Vector<float> *arr = &PackedArrayRef<float>::get_array(_data.packed_array);
+ int idx = r_iter;
+ idx++;
+ if (idx >= arr->size()) {
+ return false;
+ }
+ r_iter = idx;
+ return true;
+
+ } break;
+ case PACKED_FLOAT64_ARRAY: {
+ const Vector<double> *arr = &PackedArrayRef<double>::get_array(_data.packed_array);
+ int idx = r_iter;
+ idx++;
+ if (idx >= arr->size()) {
+ return false;
+ }
+ r_iter = idx;
+ return true;
+
+ } break;
+ case PACKED_STRING_ARRAY: {
+ const Vector<String> *arr = &PackedArrayRef<String>::get_array(_data.packed_array);
+ int idx = r_iter;
+ idx++;
+ if (idx >= arr->size()) {
+ return false;
+ }
+ r_iter = idx;
+ return true;
+ } break;
+ case PACKED_VECTOR2_ARRAY: {
+ const Vector<Vector2> *arr = &PackedArrayRef<Vector2>::get_array(_data.packed_array);
+ int idx = r_iter;
+ idx++;
+ if (idx >= arr->size()) {
+ return false;
+ }
+ r_iter = idx;
+ return true;
+ } break;
+ case PACKED_VECTOR3_ARRAY: {
+ const Vector<Vector3> *arr = &PackedArrayRef<Vector3>::get_array(_data.packed_array);
+ int idx = r_iter;
+ idx++;
+ if (idx >= arr->size()) {
+ return false;
+ }
+ r_iter = idx;
+ return true;
+ } break;
+ case PACKED_COLOR_ARRAY: {
+ const Vector<Color> *arr = &PackedArrayRef<Color>::get_array(_data.packed_array);
+ int idx = r_iter;
+ idx++;
+ if (idx >= arr->size()) {
+ return false;
+ }
+ r_iter = idx;
+ return true;
+ } break;
+ default: {
+ }
+ }
+
+ valid = false;
+ return false;
+}
+
+Variant Variant::iter_get(const Variant &r_iter, bool &r_valid) const {
+ r_valid = true;
+ switch (type) {
+ case INT: {
+ return r_iter;
+ } break;
+ case FLOAT: {
+ return r_iter;
+ } break;
+ case VECTOR2: {
+ return r_iter;
+ } break;
+ case VECTOR2I: {
+ return r_iter;
+ } break;
+ case VECTOR3: {
+ return r_iter;
+ } break;
+ case VECTOR3I: {
+ return r_iter;
+ } break;
+ case OBJECT: {
+ if (!_get_obj().obj) {
+ r_valid = false;
+ return Variant();
+ }
+#ifdef DEBUG_ENABLED
+ if (EngineDebugger::is_active() && !_get_obj().id.is_reference() && ObjectDB::get_instance(_get_obj().id) == nullptr) {
+ r_valid = false;
+ return Variant();
+ }
+
+#endif
+ Callable::CallError ce;
+ ce.error = Callable::CallError::CALL_OK;
+ const Variant *refp[] = { &r_iter };
+ Variant ret = _get_obj().obj->call(CoreStringNames::get_singleton()->_iter_get, refp, 1, ce);
+
+ if (ce.error != Callable::CallError::CALL_OK) {
+ r_valid = false;
+ return Variant();
+ }
+
+ //r_iter=ref[0];
+
+ return ret;
+ } break;
+
+ case STRING: {
+ const String *str = reinterpret_cast<const String *>(_data._mem);
+ return str->substr(r_iter, 1);
+ } break;
+ case DICTIONARY: {
+ return r_iter; //iterator is the same as the key
+
+ } break;
+ case ARRAY: {
+ const Array *arr = reinterpret_cast<const Array *>(_data._mem);
+ int idx = r_iter;
+#ifdef DEBUG_ENABLED
+ if (idx < 0 || idx >= arr->size()) {
+ r_valid = false;
+ return Variant();
+ }
+#endif
+ return arr->get(idx);
+ } break;
+ case PACKED_BYTE_ARRAY: {
+ const Vector<uint8_t> *arr = &PackedArrayRef<uint8_t>::get_array(_data.packed_array);
+ int idx = r_iter;
+#ifdef DEBUG_ENABLED
+ if (idx < 0 || idx >= arr->size()) {
+ r_valid = false;
+ return Variant();
+ }
+#endif
+ return arr->get(idx);
+ } break;
+ case PACKED_INT32_ARRAY: {
+ const Vector<int32_t> *arr = &PackedArrayRef<int32_t>::get_array(_data.packed_array);
+ int32_t idx = r_iter;
+#ifdef DEBUG_ENABLED
+ if (idx < 0 || idx >= arr->size()) {
+ r_valid = false;
+ return Variant();
+ }
+#endif
+ return arr->get(idx);
+ } break;
+ case PACKED_INT64_ARRAY: {
+ const Vector<int64_t> *arr = &PackedArrayRef<int64_t>::get_array(_data.packed_array);
+ int64_t idx = r_iter;
+#ifdef DEBUG_ENABLED
+ if (idx < 0 || idx >= arr->size()) {
+ r_valid = false;
+ return Variant();
+ }
+#endif
+ return arr->get(idx);
+ } break;
+ case PACKED_FLOAT32_ARRAY: {
+ const Vector<float> *arr = &PackedArrayRef<float>::get_array(_data.packed_array);
+ int idx = r_iter;
+#ifdef DEBUG_ENABLED
+ if (idx < 0 || idx >= arr->size()) {
+ r_valid = false;
+ return Variant();
+ }
+#endif
+ return arr->get(idx);
+ } break;
+ case PACKED_FLOAT64_ARRAY: {
+ const Vector<double> *arr = &PackedArrayRef<double>::get_array(_data.packed_array);
+ int idx = r_iter;
+#ifdef DEBUG_ENABLED
+ if (idx < 0 || idx >= arr->size()) {
+ r_valid = false;
+ return Variant();
+ }
+#endif
+ return arr->get(idx);
+ } break;
+ case PACKED_STRING_ARRAY: {
+ const Vector<String> *arr = &PackedArrayRef<String>::get_array(_data.packed_array);
+ int idx = r_iter;
+#ifdef DEBUG_ENABLED
+ if (idx < 0 || idx >= arr->size()) {
+ r_valid = false;
+ return Variant();
+ }
+#endif
+ return arr->get(idx);
+ } break;
+ case PACKED_VECTOR2_ARRAY: {
+ const Vector<Vector2> *arr = &PackedArrayRef<Vector2>::get_array(_data.packed_array);
+ int idx = r_iter;
+#ifdef DEBUG_ENABLED
+ if (idx < 0 || idx >= arr->size()) {
+ r_valid = false;
+ return Variant();
+ }
+#endif
+ return arr->get(idx);
+ } break;
+ case PACKED_VECTOR3_ARRAY: {
+ const Vector<Vector3> *arr = &PackedArrayRef<Vector3>::get_array(_data.packed_array);
+ int idx = r_iter;
+#ifdef DEBUG_ENABLED
+ if (idx < 0 || idx >= arr->size()) {
+ r_valid = false;
+ return Variant();
+ }
+#endif
+ return arr->get(idx);
+ } break;
+ case PACKED_COLOR_ARRAY: {
+ const Vector<Color> *arr = &PackedArrayRef<Color>::get_array(_data.packed_array);
+ int idx = r_iter;
+#ifdef DEBUG_ENABLED
+ if (idx < 0 || idx >= arr->size()) {
+ r_valid = false;
+ return Variant();
+ }
+#endif
+ return arr->get(idx);
+ } break;
+ default: {
+ }
+ }
+
+ r_valid = false;
+ return Variant();
+}
+
+Variant Variant::duplicate(bool deep) const {
+ switch (type) {
+ case OBJECT: {
+ /* breaks stuff :(
+ if (deep && !_get_obj().ref.is_null()) {
+ Ref<Resource> resource = _get_obj().ref;
+ if (resource.is_valid()) {
+ return resource->duplicate(true);
+ }
+ }
+ */
+ return *this;
+ } break;
+ case DICTIONARY:
+ return operator Dictionary().duplicate(deep);
+ case ARRAY:
+ return operator Array().duplicate(deep);
+ default:
+ return *this;
+ }
+}
+
+void Variant::blend(const Variant &a, const Variant &b, float c, Variant &r_dst) {
+ if (a.type != b.type) {
+ if (a.is_num() && b.is_num()) {
+ real_t va = a;
+ real_t vb = b;
+ r_dst = va + vb * c;
+ } else {
+ r_dst = a;
+ }
+ return;
+ }
+
+ switch (a.type) {
+ case NIL: {
+ r_dst = Variant();
+ }
+ return;
+ case INT: {
+ int64_t va = a._data._int;
+ int64_t vb = b._data._int;
+ r_dst = int(va + vb * c + 0.5);
+ }
+ return;
+ case FLOAT: {
+ double ra = a._data._float;
+ double rb = b._data._float;
+ r_dst = ra + rb * c;
+ }
+ return;
+ case VECTOR2: {
+ r_dst = *reinterpret_cast<const Vector2 *>(a._data._mem) + *reinterpret_cast<const Vector2 *>(b._data._mem) * c;
+ }
+ return;
+ case VECTOR2I: {
+ int32_t vax = reinterpret_cast<const Vector2i *>(a._data._mem)->x;
+ int32_t vbx = reinterpret_cast<const Vector2i *>(b._data._mem)->x;
+ int32_t vay = reinterpret_cast<const Vector2i *>(a._data._mem)->y;
+ int32_t vby = reinterpret_cast<const Vector2i *>(b._data._mem)->y;
+ r_dst = Vector2i(int32_t(vax + vbx * c + 0.5), int32_t(vay + vby * c + 0.5));
+ }
+ return;
+ case RECT2: {
+ const Rect2 *ra = reinterpret_cast<const Rect2 *>(a._data._mem);
+ const Rect2 *rb = reinterpret_cast<const Rect2 *>(b._data._mem);
+ r_dst = Rect2(ra->position + rb->position * c, ra->size + rb->size * c);
+ }
+ return;
+ case RECT2I: {
+ const Rect2i *ra = reinterpret_cast<const Rect2i *>(a._data._mem);
+ const Rect2i *rb = reinterpret_cast<const Rect2i *>(b._data._mem);
+
+ int32_t vax = ra->position.x;
+ int32_t vay = ra->position.y;
+ int32_t vbx = ra->size.x;
+ int32_t vby = ra->size.y;
+ int32_t vcx = rb->position.x;
+ int32_t vcy = rb->position.y;
+ int32_t vdx = rb->size.x;
+ int32_t vdy = rb->size.y;
+
+ r_dst = Rect2i(int32_t(vax + vbx * c + 0.5), int32_t(vay + vby * c + 0.5), int32_t(vcx + vdx * c + 0.5), int32_t(vcy + vdy * c + 0.5));
+ }
+ return;
+ case VECTOR3: {
+ r_dst = *reinterpret_cast<const Vector3 *>(a._data._mem) + *reinterpret_cast<const Vector3 *>(b._data._mem) * c;
+ }
+ return;
+ case VECTOR3I: {
+ int32_t vax = reinterpret_cast<const Vector3i *>(a._data._mem)->x;
+ int32_t vbx = reinterpret_cast<const Vector3i *>(b._data._mem)->x;
+ int32_t vay = reinterpret_cast<const Vector3i *>(a._data._mem)->y;
+ int32_t vby = reinterpret_cast<const Vector3i *>(b._data._mem)->y;
+ int32_t vaz = reinterpret_cast<const Vector3i *>(a._data._mem)->z;
+ int32_t vbz = reinterpret_cast<const Vector3i *>(b._data._mem)->z;
+ r_dst = Vector3i(int32_t(vax + vbx * c + 0.5), int32_t(vay + vby * c + 0.5), int32_t(vaz + vbz * c + 0.5));
+ }
+ return;
+ case AABB: {
+ const ::AABB *ra = reinterpret_cast<const ::AABB *>(a._data._mem);
+ const ::AABB *rb = reinterpret_cast<const ::AABB *>(b._data._mem);
+ r_dst = ::AABB(ra->position + rb->position * c, ra->size + rb->size * c);
+ }
+ return;
+ case QUAT: {
+ Quat empty_rot;
+ const Quat *qa = reinterpret_cast<const Quat *>(a._data._mem);
+ const Quat *qb = reinterpret_cast<const Quat *>(b._data._mem);
+ r_dst = *qa * empty_rot.slerp(*qb, c);
+ }
+ return;
+ case COLOR: {
+ const Color *ca = reinterpret_cast<const Color *>(a._data._mem);
+ const Color *cb = reinterpret_cast<const Color *>(b._data._mem);
+ float new_r = ca->r + cb->r * c;
+ float new_g = ca->g + cb->g * c;
+ float new_b = ca->b + cb->b * c;
+ float new_a = ca->a + cb->a * c;
+ new_r = new_r > 1.0 ? 1.0 : new_r;
+ new_g = new_g > 1.0 ? 1.0 : new_g;
+ new_b = new_b > 1.0 ? 1.0 : new_b;
+ new_a = new_a > 1.0 ? 1.0 : new_a;
+ r_dst = Color(new_r, new_g, new_b, new_a);
+ }
+ return;
+ default: {
+ r_dst = c < 0.5 ? a : b;
+ }
+ return;
+ }
+}
+
+void Variant::interpolate(const Variant &a, const Variant &b, float c, Variant &r_dst) {
+ if (a.type != b.type) {
+ if (a.is_num() && b.is_num()) {
+ //not as efficient but..
+ real_t va = a;
+ real_t vb = b;
+ r_dst = va + (vb - va) * c;
+
+ } else {
+ r_dst = a;
+ }
+ return;
+ }
+
+ switch (a.type) {
+ case NIL: {
+ r_dst = Variant();
+ }
+ return;
+ case BOOL: {
+ r_dst = a;
+ }
+ return;
+ case INT: {
+ int64_t va = a._data._int;
+ int64_t vb = b._data._int;
+ r_dst = int(va + (vb - va) * c);
+ }
+ return;
+ case FLOAT: {
+ real_t va = a._data._float;
+ real_t vb = b._data._float;
+ r_dst = va + (vb - va) * c;
+ }
+ return;
+ case STRING: {
+ //this is pretty funny and bizarre, but artists like to use it for typewritter effects
+ String sa = *reinterpret_cast<const String *>(a._data._mem);
+ String sb = *reinterpret_cast<const String *>(b._data._mem);
+ String dst;
+ int sa_len = sa.length();
+ int sb_len = sb.length();
+ int csize = sa_len + (sb_len - sa_len) * c;
+ if (csize == 0) {
+ r_dst = "";
+ return;
+ }
+ dst.resize(csize + 1);
+ dst[csize] = 0;
+ int split = csize / 2;
+
+ for (int i = 0; i < csize; i++) {
+ char32_t chr = ' ';
+
+ if (i < split) {
+ if (i < sa.length()) {
+ chr = sa[i];
+ } else if (i < sb.length()) {
+ chr = sb[i];
+ }
+
+ } else {
+ if (i < sb.length()) {
+ chr = sb[i];
+ } else if (i < sa.length()) {
+ chr = sa[i];
+ }
+ }
+
+ dst[i] = chr;
+ }
+
+ r_dst = dst;
+ }
+ return;
+ case VECTOR2: {
+ r_dst = reinterpret_cast<const Vector2 *>(a._data._mem)->lerp(*reinterpret_cast<const Vector2 *>(b._data._mem), c);
+ }
+ return;
+ case VECTOR2I: {
+ int32_t vax = reinterpret_cast<const Vector2i *>(a._data._mem)->x;
+ int32_t vbx = reinterpret_cast<const Vector2i *>(b._data._mem)->x;
+ int32_t vay = reinterpret_cast<const Vector2i *>(a._data._mem)->y;
+ int32_t vby = reinterpret_cast<const Vector2i *>(b._data._mem)->y;
+ r_dst = Vector2i(int32_t(vax + vbx * c + 0.5), int32_t(vay + vby * c + 0.5));
+ }
+ return;
+
+ case RECT2: {
+ r_dst = Rect2(reinterpret_cast<const Rect2 *>(a._data._mem)->position.lerp(reinterpret_cast<const Rect2 *>(b._data._mem)->position, c), reinterpret_cast<const Rect2 *>(a._data._mem)->size.lerp(reinterpret_cast<const Rect2 *>(b._data._mem)->size, c));
+ }
+ return;
+ case RECT2I: {
+ const Rect2i *ra = reinterpret_cast<const Rect2i *>(a._data._mem);
+ const Rect2i *rb = reinterpret_cast<const Rect2i *>(b._data._mem);
+
+ int32_t vax = ra->position.x;
+ int32_t vay = ra->position.y;
+ int32_t vbx = ra->size.x;
+ int32_t vby = ra->size.y;
+ int32_t vcx = rb->position.x;
+ int32_t vcy = rb->position.y;
+ int32_t vdx = rb->size.x;
+ int32_t vdy = rb->size.y;
+
+ r_dst = Rect2i(int32_t(vax + vbx * c + 0.5), int32_t(vay + vby * c + 0.5), int32_t(vcx + vdx * c + 0.5), int32_t(vcy + vdy * c + 0.5));
+ }
+ return;
+
+ case VECTOR3: {
+ r_dst = reinterpret_cast<const Vector3 *>(a._data._mem)->lerp(*reinterpret_cast<const Vector3 *>(b._data._mem), c);
+ }
+ return;
+ case VECTOR3I: {
+ int32_t vax = reinterpret_cast<const Vector3i *>(a._data._mem)->x;
+ int32_t vbx = reinterpret_cast<const Vector3i *>(b._data._mem)->x;
+ int32_t vay = reinterpret_cast<const Vector3i *>(a._data._mem)->y;
+ int32_t vby = reinterpret_cast<const Vector3i *>(b._data._mem)->y;
+ int32_t vaz = reinterpret_cast<const Vector3i *>(a._data._mem)->z;
+ int32_t vbz = reinterpret_cast<const Vector3i *>(b._data._mem)->z;
+ r_dst = Vector3i(int32_t(vax + vbx * c + 0.5), int32_t(vay + vby * c + 0.5), int32_t(vaz + vbz * c + 0.5));
+ }
+ return;
+
+ case TRANSFORM2D: {
+ r_dst = a._data._transform2d->interpolate_with(*b._data._transform2d, c);
+ }
+ return;
+ case PLANE: {
+ r_dst = a;
+ }
+ return;
+ case QUAT: {
+ r_dst = reinterpret_cast<const Quat *>(a._data._mem)->slerp(*reinterpret_cast<const Quat *>(b._data._mem), c);
+ }
+ return;
+ case AABB: {
+ r_dst = ::AABB(a._data._aabb->position.lerp(b._data._aabb->position, c), a._data._aabb->size.lerp(b._data._aabb->size, c));
+ }
+ return;
+ case BASIS: {
+ r_dst = Transform(*a._data._basis).interpolate_with(Transform(*b._data._basis), c).basis;
+ }
+ return;
+ case TRANSFORM: {
+ r_dst = a._data._transform->interpolate_with(*b._data._transform, c);
+ }
+ return;
+ case COLOR: {
+ r_dst = reinterpret_cast<const Color *>(a._data._mem)->lerp(*reinterpret_cast<const Color *>(b._data._mem), c);
+ }
+ return;
+ case STRING_NAME: {
+ r_dst = a;
+ }
+ return;
+ case NODE_PATH: {
+ r_dst = a;
+ }
+ return;
+ case RID: {
+ r_dst = a;
+ }
+ return;
+ case OBJECT: {
+ r_dst = a;
+ }
+ return;
+ case DICTIONARY: {
+ }
+ return;
+ case ARRAY: {
+ r_dst = a;
+ }
+ return;
+ case PACKED_BYTE_ARRAY: {
+ r_dst = a;
+ }
+ return;
+ case PACKED_INT32_ARRAY: {
+ const Vector<int32_t> *arr_a = &PackedArrayRef<int32_t>::get_array(a._data.packed_array);
+ const Vector<int32_t> *arr_b = &PackedArrayRef<int32_t>::get_array(b._data.packed_array);
+ int32_t sz = arr_a->size();
+ if (sz == 0 || arr_b->size() != sz) {
+ r_dst = a;
+ } else {
+ Vector<int32_t> v;
+ v.resize(sz);
+ {
+ int32_t *vw = v.ptrw();
+ const int32_t *ar = arr_a->ptr();
+ const int32_t *br = arr_b->ptr();
+
+ Variant va;
+ for (int32_t i = 0; i < sz; i++) {
+ Variant::interpolate(ar[i], br[i], c, va);
+ vw[i] = va;
+ }
+ }
+ r_dst = v;
+ }
+ }
+ return;
+ case PACKED_INT64_ARRAY: {
+ const Vector<int64_t> *arr_a = &PackedArrayRef<int64_t>::get_array(a._data.packed_array);
+ const Vector<int64_t> *arr_b = &PackedArrayRef<int64_t>::get_array(b._data.packed_array);
+ int64_t sz = arr_a->size();
+ if (sz == 0 || arr_b->size() != sz) {
+ r_dst = a;
+ } else {
+ Vector<int64_t> v;
+ v.resize(sz);
+ {
+ int64_t *vw = v.ptrw();
+ const int64_t *ar = arr_a->ptr();
+ const int64_t *br = arr_b->ptr();
+
+ Variant va;
+ for (int64_t i = 0; i < sz; i++) {
+ Variant::interpolate(ar[i], br[i], c, va);
+ vw[i] = va;
+ }
+ }
+ r_dst = v;
+ }
+ }
+ return;
+ case PACKED_FLOAT32_ARRAY: {
+ const Vector<float> *arr_a = &PackedArrayRef<float>::get_array(a._data.packed_array);
+ const Vector<float> *arr_b = &PackedArrayRef<float>::get_array(b._data.packed_array);
+ int sz = arr_a->size();
+ if (sz == 0 || arr_b->size() != sz) {
+ r_dst = a;
+ } else {
+ Vector<float> v;
+ v.resize(sz);
+ {
+ float *vw = v.ptrw();
+ const float *ar = arr_a->ptr();
+ const float *br = arr_b->ptr();
+
+ Variant va;
+ for (int i = 0; i < sz; i++) {
+ Variant::interpolate(ar[i], br[i], c, va);
+ vw[i] = va;
+ }
+ }
+ r_dst = v;
+ }
+ }
+ return;
+ case PACKED_FLOAT64_ARRAY: {
+ const Vector<double> *arr_a = &PackedArrayRef<double>::get_array(a._data.packed_array);
+ const Vector<double> *arr_b = &PackedArrayRef<double>::get_array(b._data.packed_array);
+ int sz = arr_a->size();
+ if (sz == 0 || arr_b->size() != sz) {
+ r_dst = a;
+ } else {
+ Vector<double> v;
+ v.resize(sz);
+ {
+ double *vw = v.ptrw();
+ const double *ar = arr_a->ptr();
+ const double *br = arr_b->ptr();
+
+ Variant va;
+ for (int i = 0; i < sz; i++) {
+ Variant::interpolate(ar[i], br[i], c, va);
+ vw[i] = va;
+ }
+ }
+ r_dst = v;
+ }
+ }
+ return;
+ case PACKED_STRING_ARRAY: {
+ r_dst = a;
+ }
+ return;
+ case PACKED_VECTOR2_ARRAY: {
+ const Vector<Vector2> *arr_a = &PackedArrayRef<Vector2>::get_array(a._data.packed_array);
+ const Vector<Vector2> *arr_b = &PackedArrayRef<Vector2>::get_array(b._data.packed_array);
+ int sz = arr_a->size();
+ if (sz == 0 || arr_b->size() != sz) {
+ r_dst = a;
+ } else {
+ Vector<Vector2> v;
+ v.resize(sz);
+ {
+ Vector2 *vw = v.ptrw();
+ const Vector2 *ar = arr_a->ptr();
+ const Vector2 *br = arr_b->ptr();
+
+ for (int i = 0; i < sz; i++) {
+ vw[i] = ar[i].lerp(br[i], c);
+ }
+ }
+ r_dst = v;
+ }
+ }
+ return;
+ case PACKED_VECTOR3_ARRAY: {
+ const Vector<Vector3> *arr_a = &PackedArrayRef<Vector3>::get_array(a._data.packed_array);
+ const Vector<Vector3> *arr_b = &PackedArrayRef<Vector3>::get_array(b._data.packed_array);
+ int sz = arr_a->size();
+ if (sz == 0 || arr_b->size() != sz) {
+ r_dst = a;
+ } else {
+ Vector<Vector3> v;
+ v.resize(sz);
+ {
+ Vector3 *vw = v.ptrw();
+ const Vector3 *ar = arr_a->ptr();
+ const Vector3 *br = arr_b->ptr();
+
+ for (int i = 0; i < sz; i++) {
+ vw[i] = ar[i].lerp(br[i], c);
+ }
+ }
+ r_dst = v;
+ }
+ }
+ return;
+ case PACKED_COLOR_ARRAY: {
+ const Vector<Color> *arr_a = &PackedArrayRef<Color>::get_array(a._data.packed_array);
+ const Vector<Color> *arr_b = &PackedArrayRef<Color>::get_array(b._data.packed_array);
+ int sz = arr_a->size();
+ if (sz == 0 || arr_b->size() != sz) {
+ r_dst = a;
+ } else {
+ Vector<Color> v;
+ v.resize(sz);
+ {
+ Color *vw = v.ptrw();
+ const Color *ar = arr_a->ptr();
+ const Color *br = arr_b->ptr();
+
+ for (int i = 0; i < sz; i++) {
+ vw[i] = ar[i].lerp(br[i], c);
+ }
+ }
+ r_dst = v;
+ }
+ }
+ return;
+ default: {
+ r_dst = a;
+ }
+ }
+}
+
+void Variant::_register_variant_setters_getters() {
+ register_named_setters_getters();
+ register_indexed_setters_getters();
+ register_keyed_setters_getters();
+}
+void Variant::_unregister_variant_setters_getters() {
+ unregister_named_setters_getters();
+ unregister_indexed_setters_getters();
+}
diff --git a/core/variant/variant_utility.cpp b/core/variant/variant_utility.cpp
new file mode 100644
index 0000000000..d54e223a99
--- /dev/null
+++ b/core/variant/variant_utility.cpp
@@ -0,0 +1,1381 @@
+/*************************************************************************/
+/* variant_utility.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* 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. */
+/*************************************************************************/
+
+#include "variant.h"
+
+#include "core/core_string_names.h"
+#include "core/io/marshalls.h"
+#include "core/object/reference.h"
+#include "core/os/os.h"
+#include "core/templates/oa_hash_map.h"
+#include "core/variant/binder_common.h"
+#include "core/variant/variant_parser.h"
+
+struct VariantUtilityFunctions {
+ // Math
+
+ static inline double sin(double arg) {
+ return Math::sin(arg);
+ }
+
+ static inline double cos(double arg) {
+ return Math::cos(arg);
+ }
+
+ static inline double tan(double arg) {
+ return Math::tan(arg);
+ }
+
+ static inline double sinh(double arg) {
+ return Math::sinh(arg);
+ }
+
+ static inline double cosh(double arg) {
+ return Math::cosh(arg);
+ }
+
+ static inline double tanh(double arg) {
+ return Math::tanh(arg);
+ }
+
+ static inline double asin(double arg) {
+ return Math::asin(arg);
+ }
+
+ static inline double acos(double arg) {
+ return Math::acos(arg);
+ }
+
+ static inline double atan(double arg) {
+ return Math::atan(arg);
+ }
+
+ static inline double atan2(double y, double x) {
+ return Math::atan2(y, x);
+ }
+
+ static inline double sqrt(double x) {
+ return Math::sqrt(x);
+ }
+
+ static inline double fmod(double b, double r) {
+ return Math::fmod(b, r);
+ }
+
+ static inline double fposmod(double b, double r) {
+ return Math::fposmod(b, r);
+ }
+
+ static inline double floor(double x) {
+ return Math::floor(x);
+ }
+
+ static inline double ceil(double x) {
+ return Math::ceil(x);
+ }
+
+ static inline double round(double x) {
+ return Math::round(x);
+ }
+
+ static inline Variant abs(const Variant &x, Callable::CallError &r_error) {
+ r_error.error = Callable::CallError::CALL_OK;
+ switch (x.get_type()) {
+ case Variant::INT: {
+ return ABS(VariantInternalAccessor<int64_t>::get(&x));
+ } break;
+ case Variant::FLOAT: {
+ return Math::absd(VariantInternalAccessor<double>::get(&x));
+ } break;
+ case Variant::VECTOR2: {
+ return VariantInternalAccessor<Vector2>::get(&x).abs();
+ } break;
+ case Variant::VECTOR2I: {
+ return VariantInternalAccessor<Vector2i>::get(&x).abs();
+ } break;
+ case Variant::VECTOR3: {
+ return VariantInternalAccessor<Vector3>::get(&x).abs();
+ } break;
+ case Variant::VECTOR3I: {
+ return VariantInternalAccessor<Vector3i>::get(&x).abs();
+ } break;
+ default: {
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
+ return Variant();
+ }
+ }
+ }
+
+ static inline double absf(double x) {
+ return Math::absd(x);
+ }
+
+ static inline int64_t absi(int64_t x) {
+ return ABS(x);
+ }
+
+ static inline Variant sign(const Variant &x, Callable::CallError &r_error) {
+ r_error.error = Callable::CallError::CALL_OK;
+ switch (x.get_type()) {
+ case Variant::INT: {
+ return SGN(VariantInternalAccessor<int64_t>::get(&x));
+ } break;
+ case Variant::FLOAT: {
+ return SGN(VariantInternalAccessor<double>::get(&x));
+ } break;
+ case Variant::VECTOR2: {
+ return VariantInternalAccessor<Vector2>::get(&x).sign();
+ } break;
+ case Variant::VECTOR2I: {
+ return VariantInternalAccessor<Vector2i>::get(&x).sign();
+ } break;
+ case Variant::VECTOR3: {
+ return VariantInternalAccessor<Vector3>::get(&x).sign();
+ } break;
+ case Variant::VECTOR3I: {
+ return VariantInternalAccessor<Vector3i>::get(&x).sign();
+ } break;
+ default: {
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
+ return Variant();
+ }
+ }
+ }
+
+ static inline double signf(double x) {
+ return SGN(x);
+ }
+
+ static inline int64_t signi(int64_t x) {
+ return SGN(x);
+ }
+
+ static inline double pow(double x, double y) {
+ return Math::pow(x, y);
+ }
+
+ static inline double log(double x) {
+ return Math::log(x);
+ }
+
+ static inline double exp(double x) {
+ return Math::exp(x);
+ }
+
+ static inline bool is_nan(double x) {
+ return Math::is_nan(x);
+ }
+
+ static inline bool is_inf(double x) {
+ return Math::is_inf(x);
+ }
+
+ static inline bool is_equal_approx(double x, double y) {
+ return Math::is_equal_approx(x, y);
+ }
+
+ static inline bool is_zero_approx(double x) {
+ return Math::is_zero_approx(x);
+ }
+
+ static inline double ease(float x, float curve) {
+ return Math::ease(x, curve);
+ }
+
+ static inline int step_decimals(float step) {
+ return Math::step_decimals(step);
+ }
+
+ static inline int range_step_decimals(float step) {
+ return Math::range_step_decimals(step);
+ }
+
+ static inline double stepify(double value, double step) {
+ return Math::stepify(value, step);
+ }
+
+ static inline double lerp(double from, double to, double weight) {
+ return Math::lerp(from, to, weight);
+ }
+
+ static inline double lerp_angle(double from, double to, double weight) {
+ return Math::lerp_angle(from, to, weight);
+ }
+
+ static inline double inverse_lerp(double from, double to, double weight) {
+ return Math::inverse_lerp(from, to, weight);
+ }
+
+ static inline double range_lerp(double value, double istart, double istop, double ostart, double ostop) {
+ return Math::range_lerp(value, istart, istop, ostart, ostop);
+ }
+
+ static inline double smoothstep(double from, double to, double val) {
+ return Math::smoothstep(from, to, val);
+ }
+
+ static inline double move_toward(double from, double to, double delta) {
+ return Math::move_toward(from, to, delta);
+ }
+
+ static inline double dectime(double value, double amount, double step) {
+ return Math::dectime(value, amount, step);
+ }
+
+ static inline double deg2rad(double angle_deg) {
+ return Math::deg2rad(angle_deg);
+ }
+
+ static inline double rad2deg(double angle_rad) {
+ return Math::rad2deg(angle_rad);
+ }
+
+ static inline double linear2db(double linear) {
+ return Math::linear2db(linear);
+ }
+
+ static inline double db2linear(double db) {
+ return Math::db2linear(db);
+ }
+
+ static inline Vector2 polar2cartesian(double r, double th) {
+ return Vector2(r * Math::cos(th), r * Math::sin(th));
+ }
+
+ static inline Vector2 cartesian2polar(double x, double y) {
+ return Vector2(Math::sqrt(x * x + y * y), Math::atan2(y, x));
+ }
+
+ static inline int64_t wrapi(int64_t value, int64_t min, int64_t max) {
+ return Math::wrapi(value, min, max);
+ }
+
+ static inline double wrapf(double value, double min, double max) {
+ return Math::wrapf(value, min, max);
+ }
+
+ static inline Variant max(const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
+ if (p_argcount < 2) {
+ r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
+ r_error.expected = 2;
+ return Variant();
+ }
+ Variant base = *p_args[0];
+ Variant ret;
+ for (int i = 1; i < p_argcount; i++) {
+ bool valid;
+ Variant::evaluate(Variant::OP_GREATER, base, *p_args[i], ret, valid);
+ if (!valid) {
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.expected = base.get_type();
+ r_error.argument = i;
+ return Variant();
+ }
+ if (ret.booleanize()) {
+ base = *p_args[i];
+ }
+ }
+ r_error.error = Callable::CallError::CALL_OK;
+ return base;
+ }
+
+ static inline double maxf(double x, double y) {
+ return MAX(x, y);
+ }
+
+ static inline int64_t maxi(int64_t x, int64_t y) {
+ return MAX(x, y);
+ }
+
+ static inline Variant min(const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
+ if (p_argcount < 2) {
+ r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
+ r_error.expected = 2;
+ return Variant();
+ }
+ Variant base = *p_args[0];
+ Variant ret;
+ for (int i = 1; i < p_argcount; i++) {
+ bool valid;
+ Variant::evaluate(Variant::OP_LESS, base, *p_args[i], ret, valid);
+ if (!valid) {
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.expected = base.get_type();
+ r_error.argument = i;
+ return Variant();
+ }
+ if (ret.booleanize()) {
+ base = *p_args[i];
+ }
+ }
+ r_error.error = Callable::CallError::CALL_OK;
+ return base;
+ }
+
+ static inline double minf(double x, double y) {
+ return MIN(x, y);
+ }
+
+ static inline int64_t mini(int64_t x, int64_t y) {
+ return MIN(x, y);
+ }
+
+ static inline Variant clamp(const Variant &x, const Variant &min, const Variant &max, Callable::CallError &r_error) {
+ Variant value = x;
+
+ Variant ret;
+
+ bool valid;
+ Variant::evaluate(Variant::OP_LESS, value, min, ret, valid);
+ if (!valid) {
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.expected = value.get_type();
+ r_error.argument = 1;
+ return Variant();
+ }
+ if (ret.booleanize()) {
+ value = min;
+ }
+ Variant::evaluate(Variant::OP_GREATER, value, max, ret, valid);
+ if (!valid) {
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.expected = value.get_type();
+ r_error.argument = 2;
+ return Variant();
+ }
+ if (ret.booleanize()) {
+ value = max;
+ }
+
+ r_error.error = Callable::CallError::CALL_OK;
+
+ return value;
+ }
+
+ static inline double clampf(double x, double min, double max) {
+ return CLAMP(x, min, max);
+ }
+
+ static inline int64_t clampi(int64_t x, int64_t min, int64_t max) {
+ return CLAMP(x, min, max);
+ }
+
+ static inline int64_t nearest_po2(int64_t x) {
+ return nearest_power_of_2_templated(uint64_t(x));
+ }
+
+ // Random
+
+ static inline void randomize() {
+ Math::randomize();
+ }
+
+ static inline int64_t randi() {
+ return Math::rand();
+ }
+
+ static inline double randf() {
+ return Math::randf();
+ }
+
+ static inline int64_t randi_range(int64_t from, int64_t to) {
+ return Math::random((int32_t)from, (int32_t)to);
+ }
+
+ static inline double randf_range(double from, double to) {
+ return Math::random(from, to);
+ }
+
+ static inline void seed(int64_t s) {
+ return Math::seed(s);
+ }
+
+ static inline PackedInt64Array rand_from_seed(int64_t seed) {
+ uint64_t s = seed;
+ PackedInt64Array arr;
+ arr.resize(2);
+ arr.write[0] = Math::rand_from_seed(&s);
+ arr.write[1] = s;
+ return arr;
+ }
+
+ // Utility
+
+ static inline Variant weakref(const Variant &obj, Callable::CallError &r_error) {
+ if (obj.get_type() == Variant::OBJECT) {
+ r_error.error = Callable::CallError::CALL_OK;
+ if (obj.is_ref()) {
+ Ref<WeakRef> wref = memnew(WeakRef);
+ REF r = obj;
+ if (r.is_valid()) {
+ wref->set_ref(r);
+ }
+ return wref;
+ } else {
+ Ref<WeakRef> wref = memnew(WeakRef);
+ Object *o = obj.get_validated_object();
+ if (o) {
+ wref->set_obj(o);
+ }
+ return wref;
+ }
+ } else if (obj.get_type() == Variant::NIL) {
+ r_error.error = Callable::CallError::CALL_OK;
+ Ref<WeakRef> wref = memnew(WeakRef);
+ return wref;
+ } else {
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument = 0;
+ r_error.expected = Variant::OBJECT;
+ return Variant();
+ }
+ }
+
+ static inline int64_t _typeof(const Variant &obj) {
+ return obj.get_type();
+ }
+
+ static inline String str(const Variant **p_args, int p_arg_count, Callable::CallError &r_error) {
+ if (p_arg_count < 1) {
+ r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
+ r_error.argument = 1;
+ return String();
+ }
+ String str;
+ for (int i = 0; i < p_arg_count; i++) {
+ String os = p_args[i]->operator String();
+
+ if (i == 0) {
+ str = os;
+ } else {
+ str += os;
+ }
+ }
+
+ r_error.error = Callable::CallError::CALL_OK;
+
+ return str;
+ }
+
+ static inline void print(const Variant **p_args, int p_arg_count, Callable::CallError &r_error) {
+ if (p_arg_count < 1) {
+ r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
+ r_error.argument = 1;
+ }
+ String str;
+ for (int i = 0; i < p_arg_count; i++) {
+ String os = p_args[i]->operator String();
+
+ if (i == 0) {
+ str = os;
+ } else {
+ str += os;
+ }
+ }
+
+ print_line(str);
+ r_error.error = Callable::CallError::CALL_OK;
+ }
+
+ static inline void printerr(const Variant **p_args, int p_arg_count, Callable::CallError &r_error) {
+ if (p_arg_count < 1) {
+ r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
+ r_error.argument = 1;
+ }
+ String str;
+ for (int i = 0; i < p_arg_count; i++) {
+ String os = p_args[i]->operator String();
+
+ if (i == 0) {
+ str = os;
+ } else {
+ str += os;
+ }
+ }
+
+ print_error(str);
+ r_error.error = Callable::CallError::CALL_OK;
+ }
+
+ static inline void printt(const Variant **p_args, int p_arg_count, Callable::CallError &r_error) {
+ if (p_arg_count < 1) {
+ r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
+ r_error.argument = 1;
+ }
+ String str;
+ for (int i = 0; i < p_arg_count; i++) {
+ if (i) {
+ str += "\t";
+ }
+ str += p_args[i]->operator String();
+ }
+
+ print_line(str);
+ r_error.error = Callable::CallError::CALL_OK;
+ }
+
+ static inline void prints(const Variant **p_args, int p_arg_count, Callable::CallError &r_error) {
+ if (p_arg_count < 1) {
+ r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
+ r_error.argument = 1;
+ }
+ String str;
+ for (int i = 0; i < p_arg_count; i++) {
+ if (i) {
+ str += " ";
+ }
+ str += p_args[i]->operator String();
+ }
+
+ print_line(str);
+ r_error.error = Callable::CallError::CALL_OK;
+ }
+
+ static inline void printraw(const Variant **p_args, int p_arg_count, Callable::CallError &r_error) {
+ if (p_arg_count < 1) {
+ r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
+ r_error.argument = 1;
+ }
+ String str;
+ for (int i = 0; i < p_arg_count; i++) {
+ String os = p_args[i]->operator String();
+
+ if (i == 0) {
+ str = os;
+ } else {
+ str += os;
+ }
+ }
+
+ OS::get_singleton()->print("%s", str.utf8().get_data());
+ r_error.error = Callable::CallError::CALL_OK;
+ }
+
+ static inline void push_error(const Variant **p_args, int p_arg_count, Callable::CallError &r_error) {
+ if (p_arg_count < 1) {
+ r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
+ r_error.argument = 1;
+ }
+ String str;
+ for (int i = 0; i < p_arg_count; i++) {
+ String os = p_args[i]->operator String();
+
+ if (i == 0) {
+ str = os;
+ } else {
+ str += os;
+ }
+ }
+
+ ERR_PRINT(str);
+ r_error.error = Callable::CallError::CALL_OK;
+ }
+
+ static inline void push_warning(const Variant **p_args, int p_arg_count, Callable::CallError &r_error) {
+ if (p_arg_count < 1) {
+ r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
+ r_error.argument = 1;
+ }
+ String str;
+ for (int i = 0; i < p_arg_count; i++) {
+ String os = p_args[i]->operator String();
+
+ if (i == 0) {
+ str = os;
+ } else {
+ str += os;
+ }
+ }
+
+ WARN_PRINT(str);
+ r_error.error = Callable::CallError::CALL_OK;
+ }
+
+ static inline String var2str(const Variant &p_var) {
+ String vars;
+ VariantWriter::write_to_string(p_var, vars);
+ return vars;
+ }
+
+ static inline Variant str2var(const String &p_var) {
+ VariantParser::StreamString ss;
+ ss.s = p_var;
+
+ String errs;
+ int line;
+ Variant ret;
+ (void)VariantParser::parse(&ss, ret, errs, line);
+
+ return ret;
+ }
+
+ static inline PackedByteArray var2bytes(const Variant &p_var) {
+ int len;
+ Error err = encode_variant(p_var, nullptr, len, false);
+ if (err != OK) {
+ return PackedByteArray();
+ }
+
+ PackedByteArray barr;
+ barr.resize(len);
+ {
+ uint8_t *w = barr.ptrw();
+ err = encode_variant(p_var, w, len, false);
+ if (err != OK) {
+ return PackedByteArray();
+ }
+ }
+
+ return barr;
+ }
+
+ static inline PackedByteArray var2bytes_with_objects(const Variant &p_var) {
+ int len;
+ Error err = encode_variant(p_var, nullptr, len, true);
+ if (err != OK) {
+ return PackedByteArray();
+ }
+
+ PackedByteArray barr;
+ barr.resize(len);
+ {
+ uint8_t *w = barr.ptrw();
+ err = encode_variant(p_var, w, len, true);
+ if (err != OK) {
+ return PackedByteArray();
+ }
+ }
+
+ return barr;
+ }
+
+ static inline Variant bytes2var(const PackedByteArray &p_arr) {
+ Variant ret;
+ {
+ const uint8_t *r = p_arr.ptr();
+ Error err = decode_variant(ret, r, p_arr.size(), nullptr, false);
+ if (err != OK) {
+ return Variant();
+ }
+ }
+ return ret;
+ }
+
+ static inline Variant bytes2var_with_objects(const PackedByteArray &p_arr) {
+ Variant ret;
+ {
+ const uint8_t *r = p_arr.ptr();
+ Error err = decode_variant(ret, r, p_arr.size(), nullptr, true);
+ if (err != OK) {
+ return Variant();
+ }
+ }
+ return ret;
+ }
+
+ static inline int64_t hash(const Variant &p_arr) {
+ return p_arr.hash();
+ }
+
+ static inline Object *instance_from_id(int64_t p_id) {
+ ObjectID id = ObjectID((uint64_t)p_id);
+ Object *ret = ObjectDB::get_instance(id);
+ return ret;
+ }
+
+ static inline bool is_instance_id_valid(int64_t p_id) {
+ return ObjectDB::get_instance(ObjectID((uint64_t)p_id)) != nullptr;
+ }
+
+ static inline bool is_instance_valid(const Variant &p_instance) {
+ if (p_instance.get_type() != Variant::OBJECT) {
+ return false;
+ }
+ return p_instance.get_validated_object() != nullptr;
+ }
+};
+
+#ifdef DEBUG_METHODS_ENABLED
+#define VCALLR *ret = p_func(VariantCasterAndValidate<P>::cast(p_args, Is, r_error)...)
+#define VCALL p_func(VariantCasterAndValidate<P>::cast(p_args, Is, r_error)...)
+#else
+#define VCALLR *ret = p_func(VariantCaster<P>::cast(*p_args[Is])...)
+#define VCALL p_func(VariantCaster<P>::cast(*p_args[Is])...)
+#endif
+
+template <class R, class... P, size_t... Is>
+static _FORCE_INLINE_ void call_helperpr(R (*p_func)(P...), Variant *ret, const Variant **p_args, Callable::CallError &r_error, IndexSequence<Is...>) {
+ r_error.error = Callable::CallError::CALL_OK;
+ VCALLR;
+ (void)p_args; // avoid gcc warning
+ (void)r_error;
+}
+
+template <class R, class... P, size_t... Is>
+static _FORCE_INLINE_ void validated_call_helperpr(R (*p_func)(P...), Variant *ret, const Variant **p_args, IndexSequence<Is...>) {
+ *ret = p_func(VariantCaster<P>::cast(*p_args[Is])...);
+ (void)p_args;
+}
+
+template <class R, class... P, size_t... Is>
+static _FORCE_INLINE_ void ptr_call_helperpr(R (*p_func)(P...), void *ret, const void **p_args, IndexSequence<Is...>) {
+ PtrToArg<R>::encode(p_func(PtrToArg<P>::convert(p_args[Is])...), ret);
+ (void)p_args;
+}
+
+template <class R, class... P>
+static _FORCE_INLINE_ void call_helperr(R (*p_func)(P...), Variant *ret, const Variant **p_args, Callable::CallError &r_error) {
+ call_helperpr(p_func, ret, p_args, r_error, BuildIndexSequence<sizeof...(P)>{});
+}
+
+template <class R, class... P>
+static _FORCE_INLINE_ void validated_call_helperr(R (*p_func)(P...), Variant *ret, const Variant **p_args) {
+ validated_call_helperpr(p_func, ret, p_args, BuildIndexSequence<sizeof...(P)>{});
+}
+
+template <class R, class... P>
+static _FORCE_INLINE_ void ptr_call_helperr(R (*p_func)(P...), void *ret, const void **p_args) {
+ ptr_call_helperpr(p_func, ret, p_args, BuildIndexSequence<sizeof...(P)>{});
+}
+
+template <class R, class... P>
+static _FORCE_INLINE_ int get_arg_count_helperr(R (*p_func)(P...)) {
+ return sizeof...(P);
+}
+
+template <class R, class... P>
+static _FORCE_INLINE_ Variant::Type get_arg_type_helperr(R (*p_func)(P...), int p_arg) {
+ return call_get_argument_type<P...>(p_arg);
+}
+
+template <class R, class... P>
+static _FORCE_INLINE_ Variant::Type get_ret_type_helperr(R (*p_func)(P...)) {
+ return GetTypeInfo<R>::VARIANT_TYPE;
+}
+
+// WITHOUT RET
+
+template <class... P, size_t... Is>
+static _FORCE_INLINE_ void call_helperp(void (*p_func)(P...), const Variant **p_args, Callable::CallError &r_error, IndexSequence<Is...>) {
+ r_error.error = Callable::CallError::CALL_OK;
+ VCALL;
+ (void)p_args;
+ (void)r_error;
+}
+
+template <class... P, size_t... Is>
+static _FORCE_INLINE_ void validated_call_helperp(void (*p_func)(P...), const Variant **p_args, IndexSequence<Is...>) {
+ p_func(VariantCaster<P>::cast(*p_args[Is])...);
+ (void)p_args;
+}
+
+template <class... P, size_t... Is>
+static _FORCE_INLINE_ void ptr_call_helperp(void (*p_func)(P...), const void **p_args, IndexSequence<Is...>) {
+ p_func(PtrToArg<P>::convert(p_args[Is])...);
+ (void)p_args;
+}
+
+template <class... P>
+static _FORCE_INLINE_ void call_helper(void (*p_func)(P...), const Variant **p_args, Callable::CallError &r_error) {
+ call_helperp(p_func, p_args, r_error, BuildIndexSequence<sizeof...(P)>{});
+}
+
+template <class... P>
+static _FORCE_INLINE_ void validated_call_helper(void (*p_func)(P...), const Variant **p_args) {
+ validated_call_helperp(p_func, p_args, BuildIndexSequence<sizeof...(P)>{});
+}
+
+template <class... P>
+static _FORCE_INLINE_ void ptr_call_helper(void (*p_func)(P...), const void **p_args) {
+ ptr_call_helperp(p_func, p_args, BuildIndexSequence<sizeof...(P)>{});
+}
+
+template <class... P>
+static _FORCE_INLINE_ int get_arg_count_helper(void (*p_func)(P...)) {
+ return sizeof...(P);
+}
+
+template <class... P>
+static _FORCE_INLINE_ Variant::Type get_arg_type_helper(void (*p_func)(P...), int p_arg) {
+ return call_get_argument_type<P...>(p_arg);
+}
+
+template <class... P>
+static _FORCE_INLINE_ Variant::Type get_ret_type_helper(void (*p_func)(P...)) {
+ return Variant::NIL;
+}
+
+#define FUNCBINDR(m_func, m_args, m_category) \
+ class Func_##m_func { \
+ public: \
+ static void call(Variant *r_ret, const Variant **p_args, int p_argcount, Callable::CallError &r_error) { \
+ call_helperr(VariantUtilityFunctions::m_func, r_ret, p_args, r_error); \
+ } \
+ static void validated_call(Variant *r_ret, const Variant **p_args, int p_argcount) { \
+ validated_call_helperr(VariantUtilityFunctions::m_func, r_ret, p_args); \
+ } \
+ static void ptrcall(void *ret, const void **p_args, int p_argcount) { \
+ ptr_call_helperr(VariantUtilityFunctions::m_func, ret, p_args); \
+ } \
+ static int get_argument_count() { \
+ return get_arg_count_helperr(VariantUtilityFunctions::m_func); \
+ } \
+ static Variant::Type get_argument_type(int p_arg) { \
+ return get_arg_type_helperr(VariantUtilityFunctions::m_func, p_arg); \
+ } \
+ static Variant::Type get_return_type() { \
+ return get_ret_type_helperr(VariantUtilityFunctions::m_func); \
+ } \
+ static bool has_return_type() { \
+ return true; \
+ } \
+ static bool is_vararg() { return false; } \
+ static Variant::UtilityFunctionType get_type() { return m_category; } \
+ }; \
+ register_utility_function<Func_##m_func>(#m_func, m_args)
+
+#define FUNCBINDVR(m_func, m_args, m_category) \
+ class Func_##m_func { \
+ public: \
+ static void call(Variant *r_ret, const Variant **p_args, int p_argcount, Callable::CallError &r_error) { \
+ r_error.error = Callable::CallError::CALL_OK; \
+ *r_ret = VariantUtilityFunctions::m_func(*p_args[0], r_error); \
+ } \
+ static void validated_call(Variant *r_ret, const Variant **p_args, int p_argcount) { \
+ Callable::CallError ce; \
+ *r_ret = VariantUtilityFunctions::m_func(*p_args[0], ce); \
+ } \
+ static void ptrcall(void *ret, const void **p_args, int p_argcount) { \
+ Callable::CallError ce; \
+ PtrToArg<Variant>::encode(VariantUtilityFunctions::m_func(PtrToArg<Variant>::convert(p_args[0]), ce), ret); \
+ } \
+ static int get_argument_count() { \
+ return 1; \
+ } \
+ static Variant::Type get_argument_type(int p_arg) { \
+ return Variant::NIL; \
+ } \
+ static Variant::Type get_return_type() { \
+ return Variant::NIL; \
+ } \
+ static bool has_return_type() { \
+ return true; \
+ } \
+ static bool is_vararg() { return false; } \
+ static Variant::UtilityFunctionType get_type() { return m_category; } \
+ }; \
+ register_utility_function<Func_##m_func>(#m_func, m_args)
+
+#define FUNCBINDVR3(m_func, m_args, m_category) \
+ class Func_##m_func { \
+ public: \
+ static void call(Variant *r_ret, const Variant **p_args, int p_argcount, Callable::CallError &r_error) { \
+ r_error.error = Callable::CallError::CALL_OK; \
+ *r_ret = VariantUtilityFunctions::m_func(*p_args[0], *p_args[1], *p_args[2], r_error); \
+ } \
+ static void validated_call(Variant *r_ret, const Variant **p_args, int p_argcount) { \
+ Callable::CallError ce; \
+ *r_ret = VariantUtilityFunctions::m_func(*p_args[0], *p_args[1], *p_args[2], ce); \
+ } \
+ static void ptrcall(void *ret, const void **p_args, int p_argcount) { \
+ Callable::CallError ce; \
+ Variant r; \
+ r = VariantUtilityFunctions::m_func(PtrToArg<Variant>::convert(p_args[0]), PtrToArg<Variant>::convert(p_args[1]), PtrToArg<Variant>::convert(p_args[2]), ce); \
+ PtrToArg<Variant>::encode(r, ret); \
+ } \
+ static int get_argument_count() { \
+ return 3; \
+ } \
+ static Variant::Type get_argument_type(int p_arg) { \
+ return Variant::NIL; \
+ } \
+ static Variant::Type get_return_type() { \
+ return Variant::NIL; \
+ } \
+ static bool has_return_type() { \
+ return true; \
+ } \
+ static bool is_vararg() { return false; } \
+ static Variant::UtilityFunctionType get_type() { return m_category; } \
+ }; \
+ register_utility_function<Func_##m_func>(#m_func, m_args)
+
+#define FUNCBINDVARARG(m_func, m_args, m_category) \
+ class Func_##m_func { \
+ public: \
+ static void call(Variant *r_ret, const Variant **p_args, int p_argcount, Callable::CallError &r_error) { \
+ r_error.error = Callable::CallError::CALL_OK; \
+ *r_ret = VariantUtilityFunctions::m_func(p_args, p_argcount, r_error); \
+ } \
+ static void validated_call(Variant *r_ret, const Variant **p_args, int p_argcount) { \
+ Callable::CallError c; \
+ *r_ret = VariantUtilityFunctions::m_func(p_args, p_argcount, c); \
+ } \
+ static void ptrcall(void *ret, const void **p_args, int p_argcount) { \
+ Vector<Variant> args; \
+ for (int i = 0; i < p_argcount; i++) { \
+ args.push_back(PtrToArg<Variant>::convert(p_args[i])); \
+ } \
+ Vector<const Variant *> argsp; \
+ for (int i = 0; i < p_argcount; i++) { \
+ argsp.push_back(&args[i]); \
+ } \
+ Variant r; \
+ validated_call(&r, (const Variant **)argsp.ptr(), p_argcount); \
+ PtrToArg<Variant>::encode(r, ret); \
+ } \
+ static int get_argument_count() { \
+ return 2; \
+ } \
+ static Variant::Type get_argument_type(int p_arg) { \
+ return Variant::NIL; \
+ } \
+ static Variant::Type get_return_type() { \
+ return Variant::NIL; \
+ } \
+ static bool has_return_type() { \
+ return true; \
+ } \
+ static bool is_vararg() { \
+ return true; \
+ } \
+ static Variant::UtilityFunctionType get_type() { \
+ return m_category; \
+ } \
+ }; \
+ register_utility_function<Func_##m_func>(#m_func, m_args)
+
+#define FUNCBINDVARARGS(m_func, m_args, m_category) \
+ class Func_##m_func { \
+ public: \
+ static void call(Variant *r_ret, const Variant **p_args, int p_argcount, Callable::CallError &r_error) { \
+ r_error.error = Callable::CallError::CALL_OK; \
+ *r_ret = VariantUtilityFunctions::m_func(p_args, p_argcount, r_error); \
+ } \
+ static void validated_call(Variant *r_ret, const Variant **p_args, int p_argcount) { \
+ Callable::CallError c; \
+ *r_ret = VariantUtilityFunctions::m_func(p_args, p_argcount, c); \
+ } \
+ static void ptrcall(void *ret, const void **p_args, int p_argcount) { \
+ Vector<Variant> args; \
+ for (int i = 0; i < p_argcount; i++) { \
+ args.push_back(PtrToArg<Variant>::convert(p_args[i])); \
+ } \
+ Vector<const Variant *> argsp; \
+ for (int i = 0; i < p_argcount; i++) { \
+ argsp.push_back(&args[i]); \
+ } \
+ Variant r; \
+ validated_call(&r, (const Variant **)argsp.ptr(), p_argcount); \
+ PtrToArg<String>::encode(r.operator String(), ret); \
+ } \
+ static int get_argument_count() { \
+ return 1; \
+ } \
+ static Variant::Type get_argument_type(int p_arg) { \
+ return Variant::NIL; \
+ } \
+ static Variant::Type get_return_type() { \
+ return Variant::STRING; \
+ } \
+ static bool has_return_type() { \
+ return true; \
+ } \
+ static bool is_vararg() { \
+ return true; \
+ } \
+ static Variant::UtilityFunctionType get_type() { \
+ return m_category; \
+ } \
+ }; \
+ register_utility_function<Func_##m_func>(#m_func, m_args)
+
+#define FUNCBINDVARARGV(m_func, m_args, m_category) \
+ class Func_##m_func { \
+ public: \
+ static void call(Variant *r_ret, const Variant **p_args, int p_argcount, Callable::CallError &r_error) { \
+ r_error.error = Callable::CallError::CALL_OK; \
+ VariantUtilityFunctions::m_func(p_args, p_argcount, r_error); \
+ } \
+ static void validated_call(Variant *r_ret, const Variant **p_args, int p_argcount) { \
+ Callable::CallError c; \
+ VariantUtilityFunctions::m_func(p_args, p_argcount, c); \
+ } \
+ static void ptrcall(void *ret, const void **p_args, int p_argcount) { \
+ Vector<Variant> args; \
+ for (int i = 0; i < p_argcount; i++) { \
+ args.push_back(PtrToArg<Variant>::convert(p_args[i])); \
+ } \
+ Vector<const Variant *> argsp; \
+ for (int i = 0; i < p_argcount; i++) { \
+ argsp.push_back(&args[i]); \
+ } \
+ Variant r; \
+ validated_call(&r, (const Variant **)argsp.ptr(), p_argcount); \
+ } \
+ static int get_argument_count() { \
+ return 1; \
+ } \
+ static Variant::Type get_argument_type(int p_arg) { \
+ return Variant::NIL; \
+ } \
+ static Variant::Type get_return_type() { \
+ return Variant::NIL; \
+ } \
+ static bool has_return_type() { \
+ return false; \
+ } \
+ static bool is_vararg() { \
+ return true; \
+ } \
+ static Variant::UtilityFunctionType get_type() { \
+ return m_category; \
+ } \
+ }; \
+ register_utility_function<Func_##m_func>(#m_func, m_args)
+
+#define FUNCBIND(m_func, m_args, m_category) \
+ class Func_##m_func { \
+ public: \
+ static void call(Variant *r_ret, const Variant **p_args, int p_argcount, Callable::CallError &r_error) { \
+ call_helper(VariantUtilityFunctions::m_func, p_args, r_error); \
+ } \
+ static void validated_call(Variant *r_ret, const Variant **p_args, int p_argcount) { \
+ validated_call_helper(VariantUtilityFunctions::m_func, p_args); \
+ } \
+ static void ptrcall(void *ret, const void **p_args, int p_argcount) { \
+ ptr_call_helper(VariantUtilityFunctions::m_func, p_args); \
+ } \
+ static int get_argument_count() { \
+ return get_arg_count_helper(VariantUtilityFunctions::m_func); \
+ } \
+ static Variant::Type get_argument_type(int p_arg) { \
+ return get_arg_type_helper(VariantUtilityFunctions::m_func, p_arg); \
+ } \
+ static Variant::Type get_return_type() { \
+ return get_ret_type_helper(VariantUtilityFunctions::m_func); \
+ } \
+ static bool has_return_type() { \
+ return false; \
+ } \
+ static bool is_vararg() { return false; } \
+ static Variant::UtilityFunctionType get_type() { return m_category; } \
+ }; \
+ register_utility_function<Func_##m_func>(#m_func, m_args)
+
+struct VariantUtilityFunctionInfo {
+ void (*call_utility)(Variant *r_ret, const Variant **p_args, int p_argcount, Callable::CallError &r_error);
+ Variant::ValidatedUtilityFunction validated_call_utility;
+ Variant::PTRUtilityFunction ptr_call_utility;
+ Vector<String> argnames;
+ bool is_vararg;
+ bool returns_value;
+ int argcount;
+ Variant::Type (*get_arg_type)(int);
+ Variant::Type return_type;
+ Variant::UtilityFunctionType type;
+};
+
+static OAHashMap<StringName, VariantUtilityFunctionInfo> utility_function_table;
+static List<StringName> utility_function_name_table;
+
+template <class T>
+static void register_utility_function(const String &p_name, const Vector<String> &argnames) {
+ String name = p_name;
+ if (name.begins_with("_")) {
+ name = name.substr(1, name.length() - 1);
+ }
+ StringName sname = name;
+ ERR_FAIL_COND(utility_function_table.has(sname));
+
+ VariantUtilityFunctionInfo bfi;
+ bfi.call_utility = T::call;
+ bfi.validated_call_utility = T::validated_call;
+ bfi.ptr_call_utility = T::ptrcall;
+ bfi.is_vararg = T::is_vararg();
+ bfi.argnames = argnames;
+ bfi.argcount = T::get_argument_count();
+ if (!bfi.is_vararg) {
+ ERR_FAIL_COND_MSG(argnames.size() != bfi.argcount, "wrong number of arguments binding utility function: " + name);
+ }
+ bfi.get_arg_type = T::get_argument_type;
+ bfi.return_type = T::get_return_type();
+ bfi.type = T::get_type();
+ bfi.returns_value = T::has_return_type();
+
+ utility_function_table.insert(sname, bfi);
+ utility_function_name_table.push_back(sname);
+}
+
+void Variant::_register_variant_utility_functions() {
+ // Math
+
+ FUNCBINDR(sin, sarray("angle_rad"), Variant::UTILITY_FUNC_TYPE_MATH);
+ FUNCBINDR(cos, sarray("angle_rad"), Variant::UTILITY_FUNC_TYPE_MATH);
+ FUNCBINDR(tan, sarray("angle_rad"), Variant::UTILITY_FUNC_TYPE_MATH);
+
+ FUNCBINDR(sinh, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH);
+ FUNCBINDR(cosh, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH);
+ FUNCBINDR(tanh, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH);
+
+ FUNCBINDR(asin, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH);
+ FUNCBINDR(acos, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH);
+ FUNCBINDR(atan, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH);
+
+ FUNCBINDR(atan2, sarray("y", "x"), Variant::UTILITY_FUNC_TYPE_MATH);
+
+ FUNCBINDR(sqrt, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH);
+ FUNCBINDR(fmod, sarray("x", "y"), Variant::UTILITY_FUNC_TYPE_MATH);
+ FUNCBINDR(fposmod, sarray("x", "y"), Variant::UTILITY_FUNC_TYPE_MATH);
+ FUNCBINDR(floor, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH);
+ FUNCBINDR(ceil, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH);
+ FUNCBINDR(round, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH);
+
+ FUNCBINDVR(abs, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH);
+
+ FUNCBINDR(absf, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH);
+ FUNCBINDR(absi, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH);
+
+ FUNCBINDVR(sign, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH);
+
+ FUNCBINDR(signf, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH);
+ FUNCBINDR(signi, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH);
+
+ FUNCBINDR(pow, sarray("base", "exp"), Variant::UTILITY_FUNC_TYPE_MATH);
+ FUNCBINDR(log, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH);
+ FUNCBINDR(exp, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH);
+
+ FUNCBINDR(is_nan, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH);
+ FUNCBINDR(is_inf, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH);
+
+ FUNCBINDR(is_equal_approx, sarray("a", "b"), Variant::UTILITY_FUNC_TYPE_MATH);
+ FUNCBINDR(is_zero_approx, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH);
+
+ FUNCBINDR(ease, sarray("x", "curve"), Variant::UTILITY_FUNC_TYPE_MATH);
+ FUNCBINDR(step_decimals, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH);
+ FUNCBINDR(range_step_decimals, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH);
+ FUNCBINDR(stepify, sarray("x", "step"), Variant::UTILITY_FUNC_TYPE_MATH);
+
+ FUNCBINDR(lerp, sarray("from", "to", "weight"), Variant::UTILITY_FUNC_TYPE_MATH);
+ FUNCBINDR(lerp_angle, sarray("from", "to", "weight"), Variant::UTILITY_FUNC_TYPE_MATH);
+ FUNCBINDR(inverse_lerp, sarray("from", "to", "weight"), Variant::UTILITY_FUNC_TYPE_MATH);
+ FUNCBINDR(range_lerp, sarray("value", "istart", "istop", "ostart", "ostop"), Variant::UTILITY_FUNC_TYPE_MATH);
+
+ FUNCBINDR(smoothstep, sarray("from", "to", "x"), Variant::UTILITY_FUNC_TYPE_MATH);
+ FUNCBINDR(move_toward, sarray("from", "to", "delta"), Variant::UTILITY_FUNC_TYPE_MATH);
+ FUNCBINDR(dectime, sarray("value", "amount", "step"), Variant::UTILITY_FUNC_TYPE_MATH);
+
+ FUNCBINDR(deg2rad, sarray("deg"), Variant::UTILITY_FUNC_TYPE_MATH);
+ FUNCBINDR(rad2deg, sarray("rad"), Variant::UTILITY_FUNC_TYPE_MATH);
+ FUNCBINDR(linear2db, sarray("lin"), Variant::UTILITY_FUNC_TYPE_MATH);
+ FUNCBINDR(db2linear, sarray("db"), Variant::UTILITY_FUNC_TYPE_MATH);
+
+ FUNCBINDR(polar2cartesian, sarray("r", "th"), Variant::UTILITY_FUNC_TYPE_MATH);
+ FUNCBINDR(cartesian2polar, sarray("x", "y"), Variant::UTILITY_FUNC_TYPE_MATH);
+
+ FUNCBINDR(wrapi, sarray("value", "min", "max"), Variant::UTILITY_FUNC_TYPE_MATH);
+ FUNCBINDR(wrapf, sarray("value", "min", "max"), Variant::UTILITY_FUNC_TYPE_MATH);
+
+ FUNCBINDVARARG(max, sarray(), Variant::UTILITY_FUNC_TYPE_MATH);
+
+ FUNCBINDR(maxi, sarray("a", "b"), Variant::UTILITY_FUNC_TYPE_MATH);
+ FUNCBINDR(maxf, sarray("a", "b"), Variant::UTILITY_FUNC_TYPE_MATH);
+
+ FUNCBINDVARARG(min, sarray(), Variant::UTILITY_FUNC_TYPE_MATH);
+
+ FUNCBINDR(mini, sarray("a", "b"), Variant::UTILITY_FUNC_TYPE_MATH);
+ FUNCBINDR(minf, sarray("a", "b"), Variant::UTILITY_FUNC_TYPE_MATH);
+
+ FUNCBINDVR3(clamp, sarray("value", "min", "max"), Variant::UTILITY_FUNC_TYPE_MATH);
+ FUNCBINDR(clampi, sarray("value", "min", "max"), Variant::UTILITY_FUNC_TYPE_MATH);
+ FUNCBINDR(clampf, sarray("value", "min", "max"), Variant::UTILITY_FUNC_TYPE_MATH);
+
+ FUNCBINDR(nearest_po2, sarray("value"), Variant::UTILITY_FUNC_TYPE_MATH);
+
+ // Random
+
+ FUNCBIND(randomize, sarray(), Variant::UTILITY_FUNC_TYPE_RANDOM);
+ FUNCBINDR(randi, sarray(), Variant::UTILITY_FUNC_TYPE_RANDOM);
+ FUNCBINDR(randf, sarray(), Variant::UTILITY_FUNC_TYPE_RANDOM);
+ FUNCBINDR(randi_range, sarray("from", "to"), Variant::UTILITY_FUNC_TYPE_RANDOM);
+ FUNCBINDR(randf_range, sarray("from", "to"), Variant::UTILITY_FUNC_TYPE_RANDOM);
+ FUNCBIND(seed, sarray("base"), Variant::UTILITY_FUNC_TYPE_RANDOM);
+ FUNCBINDR(rand_from_seed, sarray("seed"), Variant::UTILITY_FUNC_TYPE_RANDOM);
+
+ // Utility
+
+ FUNCBINDVR(weakref, sarray("obj"), Variant::UTILITY_FUNC_TYPE_GENERAL);
+ FUNCBINDR(_typeof, sarray("variable"), Variant::UTILITY_FUNC_TYPE_GENERAL);
+ FUNCBINDVARARGS(str, sarray(), Variant::UTILITY_FUNC_TYPE_GENERAL);
+ FUNCBINDVARARGV(print, sarray(), Variant::UTILITY_FUNC_TYPE_GENERAL);
+ FUNCBINDVARARGV(printerr, sarray(), Variant::UTILITY_FUNC_TYPE_GENERAL);
+ FUNCBINDVARARGV(printt, sarray(), Variant::UTILITY_FUNC_TYPE_GENERAL);
+ FUNCBINDVARARGV(prints, sarray(), Variant::UTILITY_FUNC_TYPE_GENERAL);
+ FUNCBINDVARARGV(printraw, sarray(), Variant::UTILITY_FUNC_TYPE_GENERAL);
+ FUNCBINDVARARGV(push_error, sarray(), Variant::UTILITY_FUNC_TYPE_GENERAL);
+ FUNCBINDVARARGV(push_warning, sarray(), Variant::UTILITY_FUNC_TYPE_GENERAL);
+
+ FUNCBINDR(var2str, sarray("variable"), Variant::UTILITY_FUNC_TYPE_GENERAL);
+ FUNCBINDR(str2var, sarray("string"), Variant::UTILITY_FUNC_TYPE_GENERAL);
+
+ FUNCBINDR(var2bytes, sarray("variable"), Variant::UTILITY_FUNC_TYPE_GENERAL);
+ FUNCBINDR(bytes2var, sarray("bytes"), Variant::UTILITY_FUNC_TYPE_GENERAL);
+
+ FUNCBINDR(var2bytes_with_objects, sarray("variable"), Variant::UTILITY_FUNC_TYPE_GENERAL);
+ FUNCBINDR(bytes2var_with_objects, sarray("bytes"), Variant::UTILITY_FUNC_TYPE_GENERAL);
+
+ FUNCBINDR(hash, sarray("variable"), Variant::UTILITY_FUNC_TYPE_GENERAL);
+
+ FUNCBINDR(instance_from_id, sarray("instance_id"), Variant::UTILITY_FUNC_TYPE_GENERAL);
+ FUNCBINDR(is_instance_id_valid, sarray("id"), Variant::UTILITY_FUNC_TYPE_GENERAL);
+ FUNCBINDR(is_instance_valid, sarray("instance"), Variant::UTILITY_FUNC_TYPE_GENERAL);
+}
+
+void Variant::_unregister_variant_utility_functions() {
+ utility_function_table.clear();
+ utility_function_name_table.clear();
+}
+
+void Variant::call_utility_function(const StringName &p_name, Variant *r_ret, const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
+ const VariantUtilityFunctionInfo *bfi = utility_function_table.lookup_ptr(p_name);
+ if (!bfi) {
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
+ r_error.argument = 0;
+ r_error.expected = 0;
+ return;
+ }
+
+ if (unlikely(!bfi->is_vararg && p_argcount < bfi->argcount)) {
+ r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
+ r_error.argument = 0;
+ r_error.expected = bfi->argcount;
+ return;
+ }
+
+ if (unlikely(!bfi->is_vararg && p_argcount > bfi->argcount)) {
+ r_error.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
+ r_error.argument = 0;
+ r_error.expected = bfi->argcount;
+ return;
+ }
+
+ bfi->call_utility(r_ret, p_args, p_argcount, r_error);
+}
+
+bool Variant::has_utility_function(const StringName &p_name) {
+ return utility_function_table.has(p_name);
+}
+
+Variant::ValidatedUtilityFunction Variant::get_validated_utility_function(const StringName &p_name) {
+ const VariantUtilityFunctionInfo *bfi = utility_function_table.lookup_ptr(p_name);
+ if (!bfi) {
+ return nullptr;
+ }
+
+ return bfi->validated_call_utility;
+}
+
+Variant::PTRUtilityFunction Variant::get_ptr_utility_function(const StringName &p_name) {
+ const VariantUtilityFunctionInfo *bfi = utility_function_table.lookup_ptr(p_name);
+ if (!bfi) {
+ return nullptr;
+ }
+
+ return bfi->ptr_call_utility;
+}
+
+Variant::UtilityFunctionType Variant::get_utility_function_type(const StringName &p_name) {
+ const VariantUtilityFunctionInfo *bfi = utility_function_table.lookup_ptr(p_name);
+ if (!bfi) {
+ return Variant::UTILITY_FUNC_TYPE_MATH;
+ }
+
+ return bfi->type;
+}
+
+int Variant::get_utility_function_argument_count(const StringName &p_name) {
+ const VariantUtilityFunctionInfo *bfi = utility_function_table.lookup_ptr(p_name);
+ if (!bfi) {
+ return 0;
+ }
+
+ return bfi->argcount;
+}
+
+Variant::Type Variant::get_utility_function_argument_type(const StringName &p_name, int p_arg) {
+ const VariantUtilityFunctionInfo *bfi = utility_function_table.lookup_ptr(p_name);
+ if (!bfi) {
+ return Variant::NIL;
+ }
+
+ return bfi->get_arg_type(p_arg);
+}
+
+String Variant::get_utility_function_argument_name(const StringName &p_name, int p_arg) {
+ const VariantUtilityFunctionInfo *bfi = utility_function_table.lookup_ptr(p_name);
+ if (!bfi) {
+ return String();
+ }
+ ERR_FAIL_COND_V(bfi->is_vararg, String());
+ ERR_FAIL_INDEX_V(p_arg, bfi->argnames.size(), String());
+ return bfi->argnames[p_arg];
+}
+
+bool Variant::has_utility_function_return_value(const StringName &p_name) {
+ const VariantUtilityFunctionInfo *bfi = utility_function_table.lookup_ptr(p_name);
+ if (!bfi) {
+ return false;
+ }
+ return bfi->returns_value;
+}
+
+Variant::Type Variant::get_utility_function_return_type(const StringName &p_name) {
+ const VariantUtilityFunctionInfo *bfi = utility_function_table.lookup_ptr(p_name);
+ if (!bfi) {
+ return Variant::NIL;
+ }
+
+ return bfi->return_type;
+}
+
+bool Variant::is_utility_function_vararg(const StringName &p_name) {
+ const VariantUtilityFunctionInfo *bfi = utility_function_table.lookup_ptr(p_name);
+ if (!bfi) {
+ return false;
+ }
+
+ return bfi->is_vararg;
+}
+
+void Variant::get_utility_function_list(List<StringName> *r_functions) {
+ for (List<StringName>::Element *E = utility_function_name_table.front(); E; E = E->next()) {
+ r_functions->push_back(E->get());
+ }
+}
diff --git a/core/variant_call.cpp b/core/variant_call.cpp
deleted file mode 100644
index 308fa3c407..0000000000
--- a/core/variant_call.cpp
+++ /dev/null
@@ -1,2384 +0,0 @@
-/*************************************************************************/
-/* variant_call.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* 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. */
-/*************************************************************************/
-
-#include "variant.h"
-
-#include "core/color_names.inc"
-#include "core/core_string_names.h"
-#include "core/crypto/crypto_core.h"
-#include "core/debugger/engine_debugger.h"
-#include "core/io/compression.h"
-#include "core/object.h"
-#include "core/os/os.h"
-
-typedef void (*VariantFunc)(Variant &r_ret, Variant &p_self, const Variant **p_args);
-typedef void (*VariantConstructFunc)(Variant &r_ret, const Variant **p_args);
-
-struct _VariantCall {
- static void Vector3_dot(Variant &r_ret, Variant &p_self, const Variant **p_args) {
- r_ret = reinterpret_cast<Vector3 *>(p_self._data._mem)->dot(*reinterpret_cast<const Vector3 *>(p_args[0]->_data._mem));
- }
-
- struct FuncData {
- int arg_count;
- Vector<Variant> default_args;
- Vector<Variant::Type> arg_types;
- Vector<StringName> arg_names;
- Variant::Type return_type;
-
- bool _const;
- bool returns;
-
- VariantFunc func;
-
- _FORCE_INLINE_ bool verify_arguments(const Variant **p_args, Callable::CallError &r_error) {
- if (arg_count == 0) {
- return true;
- }
-
- const Variant::Type *tptr = &arg_types[0];
-
- for (int i = 0; i < arg_count; i++) {
- if (tptr[i] == Variant::NIL || tptr[i] == p_args[i]->type) {
- continue; // all good
- }
- if (!Variant::can_convert(p_args[i]->type, tptr[i])) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = i;
- r_error.expected = tptr[i];
- return false;
- }
- }
- return true;
- }
-
- _FORCE_INLINE_ void call(Variant &r_ret, Variant &p_self, const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
-#ifdef DEBUG_ENABLED
- if (p_argcount > arg_count) {
- r_error.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
- r_error.argument = arg_count;
- return;
- } else
-#endif
- if (p_argcount < arg_count) {
- int def_argcount = default_args.size();
-#ifdef DEBUG_ENABLED
- if (p_argcount < (arg_count - def_argcount)) {
- r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
- r_error.argument = arg_count - def_argcount;
- return;
- }
-
-#endif
- ERR_FAIL_COND(p_argcount > VARIANT_ARG_MAX);
- const Variant *newargs[VARIANT_ARG_MAX];
- for (int i = 0; i < p_argcount; i++) {
- newargs[i] = p_args[i];
- }
- // fill in any remaining parameters with defaults
- int first_default_arg = arg_count - def_argcount;
- for (int i = p_argcount; i < arg_count; i++) {
- newargs[i] = &default_args[i - first_default_arg];
- }
-#ifdef DEBUG_ENABLED
- if (!verify_arguments(newargs, r_error)) {
- return;
- }
-#endif
- func(r_ret, p_self, newargs);
- } else {
-#ifdef DEBUG_ENABLED
- if (!verify_arguments(p_args, r_error)) {
- return;
- }
-#endif
- func(r_ret, p_self, p_args);
- }
- }
- };
-
- struct TypeFunc {
- Map<StringName, FuncData> functions;
- };
-
- static TypeFunc *type_funcs;
-
- struct Arg {
- StringName name;
- Variant::Type type;
- Arg() { type = Variant::NIL; }
- Arg(Variant::Type p_type, const StringName &p_name) :
- name(p_name),
- type(p_type) {
- }
- };
-
- //void addfunc(Variant::Type p_type, const StringName& p_name,VariantFunc p_func);
-
- static void make_func_return_variant(Variant::Type p_type, const StringName &p_name) {
-#ifdef DEBUG_ENABLED
- type_funcs[p_type].functions[p_name].returns = true;
-#endif
- }
-
- static void addfunc(bool p_const, Variant::Type p_type, Variant::Type p_return, bool p_has_return, const StringName &p_name, VariantFunc p_func, const Vector<Variant> &p_defaultarg, const Arg &p_argtype1 = Arg(), const Arg &p_argtype2 = Arg(), const Arg &p_argtype3 = Arg(), const Arg &p_argtype4 = Arg(), const Arg &p_argtype5 = Arg()) {
- FuncData funcdata;
- funcdata.func = p_func;
- funcdata.default_args = p_defaultarg;
- funcdata._const = p_const;
- funcdata.returns = p_has_return;
- funcdata.return_type = p_return;
-
- if (p_argtype1.name) {
- funcdata.arg_types.push_back(p_argtype1.type);
-#ifdef DEBUG_ENABLED
- funcdata.arg_names.push_back(p_argtype1.name);
-#endif
-
- } else {
- goto end;
- }
-
- if (p_argtype2.name) {
- funcdata.arg_types.push_back(p_argtype2.type);
-#ifdef DEBUG_ENABLED
- funcdata.arg_names.push_back(p_argtype2.name);
-#endif
-
- } else {
- goto end;
- }
-
- if (p_argtype3.name) {
- funcdata.arg_types.push_back(p_argtype3.type);
-#ifdef DEBUG_ENABLED
- funcdata.arg_names.push_back(p_argtype3.name);
-#endif
-
- } else {
- goto end;
- }
-
- if (p_argtype4.name) {
- funcdata.arg_types.push_back(p_argtype4.type);
-#ifdef DEBUG_ENABLED
- funcdata.arg_names.push_back(p_argtype4.name);
-#endif
- } else {
- goto end;
- }
-
- if (p_argtype5.name) {
- funcdata.arg_types.push_back(p_argtype5.type);
-#ifdef DEBUG_ENABLED
- funcdata.arg_names.push_back(p_argtype5.name);
-#endif
- } else {
- goto end;
- }
-
- end:
-
- funcdata.arg_count = funcdata.arg_types.size();
- type_funcs[p_type].functions[p_name] = funcdata;
- }
-
-#define VCALL_LOCALMEM0(m_type, m_method) \
- static void _call_##m_type##_##m_method(Variant &r_ret, Variant &p_self, const Variant **p_args) { reinterpret_cast<m_type *>(p_self._data._mem)->m_method(); }
-#define VCALL_LOCALMEM0R(m_type, m_method) \
- static void _call_##m_type##_##m_method(Variant &r_ret, Variant &p_self, const Variant **p_args) { r_ret = reinterpret_cast<m_type *>(p_self._data._mem)->m_method(); }
-#define VCALL_LOCALMEM1(m_type, m_method) \
- static void _call_##m_type##_##m_method(Variant &r_ret, Variant &p_self, const Variant **p_args) { reinterpret_cast<m_type *>(p_self._data._mem)->m_method(*p_args[0]); }
-#define VCALL_LOCALMEM1R(m_type, m_method) \
- static void _call_##m_type##_##m_method(Variant &r_ret, Variant &p_self, const Variant **p_args) { r_ret = reinterpret_cast<m_type *>(p_self._data._mem)->m_method(*p_args[0]); }
-#define VCALL_LOCALMEM2(m_type, m_method) \
- static void _call_##m_type##_##m_method(Variant &r_ret, Variant &p_self, const Variant **p_args) { reinterpret_cast<m_type *>(p_self._data._mem)->m_method(*p_args[0], *p_args[1]); }
-#define VCALL_LOCALMEM2R(m_type, m_method) \
- static void _call_##m_type##_##m_method(Variant &r_ret, Variant &p_self, const Variant **p_args) { r_ret = reinterpret_cast<m_type *>(p_self._data._mem)->m_method(*p_args[0], *p_args[1]); }
-#define VCALL_LOCALMEM3(m_type, m_method) \
- static void _call_##m_type##_##m_method(Variant &r_ret, Variant &p_self, const Variant **p_args) { reinterpret_cast<m_type *>(p_self._data._mem)->m_method(*p_args[0], *p_args[1], *p_args[2]); }
-#define VCALL_LOCALMEM3R(m_type, m_method) \
- static void _call_##m_type##_##m_method(Variant &r_ret, Variant &p_self, const Variant **p_args) { r_ret = reinterpret_cast<m_type *>(p_self._data._mem)->m_method(*p_args[0], *p_args[1], *p_args[2]); }
-#define VCALL_LOCALMEM4(m_type, m_method) \
- static void _call_##m_type##_##m_method(Variant &r_ret, Variant &p_self, const Variant **p_args) { reinterpret_cast<m_type *>(p_self._data._mem)->m_method(*p_args[0], *p_args[1], *p_args[2], *p_args[3]); }
-#define VCALL_LOCALMEM4R(m_type, m_method) \
- static void _call_##m_type##_##m_method(Variant &r_ret, Variant &p_self, const Variant **p_args) { r_ret = reinterpret_cast<m_type *>(p_self._data._mem)->m_method(*p_args[0], *p_args[1], *p_args[2], *p_args[3]); }
-#define VCALL_LOCALMEM5(m_type, m_method) \
- static void _call_##m_type##_##m_method(Variant &r_ret, Variant &p_self, const Variant **p_args) { reinterpret_cast<m_type *>(p_self._data._mem)->m_method(*p_args[0], *p_args[1], *p_args[2], *p_args[3], *p_args[4]); }
-#define VCALL_LOCALMEM5R(m_type, m_method) \
- static void _call_##m_type##_##m_method(Variant &r_ret, Variant &p_self, const Variant **p_args) { r_ret = reinterpret_cast<m_type *>(p_self._data._mem)->m_method(*p_args[0], *p_args[1], *p_args[2], *p_args[3], *p_args[4]); }
-
- // built-in functions of localmem based types
-
- VCALL_LOCALMEM1R(String, casecmp_to);
- VCALL_LOCALMEM1R(String, nocasecmp_to);
- VCALL_LOCALMEM0R(String, length);
- VCALL_LOCALMEM3R(String, count);
- VCALL_LOCALMEM3R(String, countn);
- VCALL_LOCALMEM2R(String, substr);
- VCALL_LOCALMEM2R(String, find);
- VCALL_LOCALMEM2R(String, findn);
- VCALL_LOCALMEM2R(String, rfind);
- VCALL_LOCALMEM2R(String, rfindn);
- VCALL_LOCALMEM1R(String, match);
- VCALL_LOCALMEM1R(String, matchn);
- VCALL_LOCALMEM1R(String, begins_with);
- VCALL_LOCALMEM1R(String, ends_with);
- VCALL_LOCALMEM1R(String, is_subsequence_of);
- VCALL_LOCALMEM1R(String, is_subsequence_ofi);
- VCALL_LOCALMEM0R(String, bigrams);
- VCALL_LOCALMEM1R(String, similarity);
- VCALL_LOCALMEM2R(String, format);
- VCALL_LOCALMEM2R(String, replace);
- VCALL_LOCALMEM2R(String, replacen);
- VCALL_LOCALMEM1R(String, repeat);
- VCALL_LOCALMEM2R(String, insert);
- VCALL_LOCALMEM0R(String, capitalize);
- VCALL_LOCALMEM3R(String, split);
- VCALL_LOCALMEM3R(String, rsplit);
- VCALL_LOCALMEM2R(String, split_floats);
- VCALL_LOCALMEM1R(String, join);
- VCALL_LOCALMEM0R(String, to_upper);
- VCALL_LOCALMEM0R(String, to_lower);
- VCALL_LOCALMEM1R(String, left);
- VCALL_LOCALMEM1R(String, right);
- VCALL_LOCALMEM0R(String, dedent);
- VCALL_LOCALMEM2R(String, strip_edges);
- VCALL_LOCALMEM0R(String, strip_escapes);
- VCALL_LOCALMEM1R(String, lstrip);
- VCALL_LOCALMEM1R(String, rstrip);
- VCALL_LOCALMEM0R(String, get_extension);
- VCALL_LOCALMEM0R(String, get_basename);
- VCALL_LOCALMEM1R(String, plus_file);
- VCALL_LOCALMEM1R(String, ord_at);
- VCALL_LOCALMEM2(String, erase);
- VCALL_LOCALMEM0R(String, hash);
- VCALL_LOCALMEM0R(String, md5_text);
- VCALL_LOCALMEM0R(String, sha1_text);
- VCALL_LOCALMEM0R(String, sha256_text);
- VCALL_LOCALMEM0R(String, md5_buffer);
- VCALL_LOCALMEM0R(String, sha1_buffer);
- VCALL_LOCALMEM0R(String, sha256_buffer);
- VCALL_LOCALMEM0R(String, empty);
- VCALL_LOCALMEM1R(String, humanize_size);
- VCALL_LOCALMEM0R(String, is_abs_path);
- VCALL_LOCALMEM0R(String, is_rel_path);
- VCALL_LOCALMEM0R(String, get_base_dir);
- VCALL_LOCALMEM0R(String, get_file);
- VCALL_LOCALMEM0R(String, xml_escape);
- VCALL_LOCALMEM0R(String, xml_unescape);
- VCALL_LOCALMEM0R(String, http_escape);
- VCALL_LOCALMEM0R(String, http_unescape);
- VCALL_LOCALMEM0R(String, c_escape);
- VCALL_LOCALMEM0R(String, c_unescape);
- VCALL_LOCALMEM0R(String, json_escape);
- VCALL_LOCALMEM0R(String, percent_encode);
- VCALL_LOCALMEM0R(String, percent_decode);
- VCALL_LOCALMEM0R(String, is_valid_identifier);
- VCALL_LOCALMEM0R(String, is_valid_integer);
- VCALL_LOCALMEM0R(String, is_valid_float);
- VCALL_LOCALMEM1R(String, is_valid_hex_number);
- VCALL_LOCALMEM0R(String, is_valid_html_color);
- VCALL_LOCALMEM0R(String, is_valid_ip_address);
- VCALL_LOCALMEM0R(String, is_valid_filename);
- VCALL_LOCALMEM0R(String, to_int);
- VCALL_LOCALMEM0R(String, to_float);
- VCALL_LOCALMEM0R(String, hex_to_int);
- VCALL_LOCALMEM1R(String, pad_decimals);
- VCALL_LOCALMEM1R(String, pad_zeros);
- VCALL_LOCALMEM1R(String, trim_prefix);
- VCALL_LOCALMEM1R(String, trim_suffix);
-
- static void _call_String_to_ascii(Variant &r_ret, Variant &p_self, const Variant **p_args) {
- String *s = reinterpret_cast<String *>(p_self._data._mem);
- if (s->empty()) {
- r_ret = PackedByteArray();
- return;
- }
- CharString charstr = s->ascii();
-
- PackedByteArray retval;
- size_t len = charstr.length();
- retval.resize(len);
- uint8_t *w = retval.ptrw();
- copymem(w, charstr.ptr(), len);
-
- r_ret = retval;
- }
-
- static void _call_String_to_utf8(Variant &r_ret, Variant &p_self, const Variant **p_args) {
- String *s = reinterpret_cast<String *>(p_self._data._mem);
- if (s->empty()) {
- r_ret = PackedByteArray();
- return;
- }
- CharString charstr = s->utf8();
-
- PackedByteArray retval;
- size_t len = charstr.length();
- retval.resize(len);
- uint8_t *w = retval.ptrw();
- copymem(w, charstr.ptr(), len);
-
- r_ret = retval;
- }
-
- VCALL_LOCALMEM1R(Vector2, distance_to);
- VCALL_LOCALMEM1R(Vector2, distance_squared_to);
- VCALL_LOCALMEM0R(Vector2, length);
- VCALL_LOCALMEM0R(Vector2, length_squared);
- VCALL_LOCALMEM0R(Vector2, normalized);
- VCALL_LOCALMEM0R(Vector2, is_normalized);
- VCALL_LOCALMEM1R(Vector2, is_equal_approx);
- VCALL_LOCALMEM1R(Vector2, posmod);
- VCALL_LOCALMEM1R(Vector2, posmodv);
- VCALL_LOCALMEM1R(Vector2, project);
- VCALL_LOCALMEM1R(Vector2, angle_to);
- VCALL_LOCALMEM1R(Vector2, angle_to_point);
- VCALL_LOCALMEM1R(Vector2, direction_to);
- VCALL_LOCALMEM2R(Vector2, lerp);
- VCALL_LOCALMEM2R(Vector2, slerp);
- VCALL_LOCALMEM4R(Vector2, cubic_interpolate);
- VCALL_LOCALMEM2R(Vector2, move_toward);
- VCALL_LOCALMEM1R(Vector2, rotated);
- VCALL_LOCALMEM0R(Vector2, tangent);
- VCALL_LOCALMEM0R(Vector2, floor);
- VCALL_LOCALMEM0R(Vector2, ceil);
- VCALL_LOCALMEM0R(Vector2, round);
- VCALL_LOCALMEM1R(Vector2, snapped);
- VCALL_LOCALMEM0R(Vector2, aspect);
- VCALL_LOCALMEM1R(Vector2, dot);
- VCALL_LOCALMEM1R(Vector2, slide);
- VCALL_LOCALMEM1R(Vector2, bounce);
- VCALL_LOCALMEM1R(Vector2, reflect);
- VCALL_LOCALMEM0R(Vector2, angle);
- VCALL_LOCALMEM1R(Vector2, cross);
- VCALL_LOCALMEM0R(Vector2, abs);
- VCALL_LOCALMEM1R(Vector2, clamped);
- VCALL_LOCALMEM0R(Vector2, sign);
-
- VCALL_LOCALMEM0R(Vector2i, aspect);
- VCALL_LOCALMEM0R(Vector2i, sign);
- VCALL_LOCALMEM0R(Vector2i, abs);
-
- VCALL_LOCALMEM0R(Rect2, get_area);
- VCALL_LOCALMEM0R(Rect2, has_no_area);
- VCALL_LOCALMEM1R(Rect2, has_point);
- VCALL_LOCALMEM1R(Rect2, is_equal_approx);
- VCALL_LOCALMEM2R(Rect2, intersects);
- VCALL_LOCALMEM1R(Rect2, encloses);
- VCALL_LOCALMEM1R(Rect2, clip);
- VCALL_LOCALMEM1R(Rect2, merge);
- VCALL_LOCALMEM1R(Rect2, expand);
- VCALL_LOCALMEM1R(Rect2, grow);
- VCALL_LOCALMEM2R(Rect2, grow_margin);
- VCALL_LOCALMEM4R(Rect2, grow_individual);
- VCALL_LOCALMEM0R(Rect2, abs);
-
- VCALL_LOCALMEM0R(Rect2i, get_area);
- VCALL_LOCALMEM0R(Rect2i, has_no_area);
- VCALL_LOCALMEM1R(Rect2i, has_point);
- VCALL_LOCALMEM1R(Rect2i, intersects);
- VCALL_LOCALMEM1R(Rect2i, encloses);
- VCALL_LOCALMEM1R(Rect2i, clip);
- VCALL_LOCALMEM1R(Rect2i, merge);
- VCALL_LOCALMEM1R(Rect2i, expand);
- VCALL_LOCALMEM1R(Rect2i, grow);
- VCALL_LOCALMEM2R(Rect2i, grow_margin);
- VCALL_LOCALMEM4R(Rect2i, grow_individual);
- VCALL_LOCALMEM0R(Rect2i, abs);
-
- VCALL_LOCALMEM0R(Vector3, min_axis);
- VCALL_LOCALMEM0R(Vector3, max_axis);
- VCALL_LOCALMEM1R(Vector3, distance_to);
- VCALL_LOCALMEM1R(Vector3, distance_squared_to);
- VCALL_LOCALMEM0R(Vector3, length);
- VCALL_LOCALMEM0R(Vector3, length_squared);
- VCALL_LOCALMEM0R(Vector3, normalized);
- VCALL_LOCALMEM0R(Vector3, is_normalized);
- VCALL_LOCALMEM1R(Vector3, is_equal_approx);
- VCALL_LOCALMEM0R(Vector3, inverse);
- VCALL_LOCALMEM1R(Vector3, snapped);
- VCALL_LOCALMEM2R(Vector3, rotated);
- VCALL_LOCALMEM2R(Vector3, lerp);
- VCALL_LOCALMEM2R(Vector3, slerp);
- VCALL_LOCALMEM4R(Vector3, cubic_interpolate);
- VCALL_LOCALMEM2R(Vector3, move_toward);
- VCALL_LOCALMEM1R(Vector3, dot);
- VCALL_LOCALMEM1R(Vector3, cross);
- VCALL_LOCALMEM1R(Vector3, outer);
- VCALL_LOCALMEM0R(Vector3, to_diagonal_matrix);
- VCALL_LOCALMEM0R(Vector3, abs);
- VCALL_LOCALMEM0R(Vector3, floor);
- VCALL_LOCALMEM0R(Vector3, ceil);
- VCALL_LOCALMEM0R(Vector3, round);
- VCALL_LOCALMEM1R(Vector3, posmod);
- VCALL_LOCALMEM1R(Vector3, posmodv);
- VCALL_LOCALMEM1R(Vector3, project);
- VCALL_LOCALMEM1R(Vector3, angle_to);
- VCALL_LOCALMEM1R(Vector3, direction_to);
- VCALL_LOCALMEM1R(Vector3, slide);
- VCALL_LOCALMEM1R(Vector3, bounce);
- VCALL_LOCALMEM1R(Vector3, reflect);
- VCALL_LOCALMEM0R(Vector3, sign);
-
- VCALL_LOCALMEM0R(Vector3i, min_axis);
- VCALL_LOCALMEM0R(Vector3i, max_axis);
- VCALL_LOCALMEM0R(Vector3i, sign);
-
- VCALL_LOCALMEM0R(Plane, normalized);
- VCALL_LOCALMEM0R(Plane, center);
- VCALL_LOCALMEM0R(Plane, get_any_point);
- VCALL_LOCALMEM1R(Plane, is_equal_approx);
- VCALL_LOCALMEM1R(Plane, is_point_over);
- VCALL_LOCALMEM1R(Plane, distance_to);
- VCALL_LOCALMEM2R(Plane, has_point);
- VCALL_LOCALMEM1R(Plane, project);
-
- //return vector3 if intersected, nil if not
- static void _call_Plane_intersect_3(Variant &r_ret, Variant &p_self, const Variant **p_args) {
- Vector3 result;
- if (reinterpret_cast<Plane *>(p_self._data._mem)->intersect_3(*p_args[0], *p_args[1], &result)) {
- r_ret = result;
- } else {
- r_ret = Variant();
- }
- }
-
- static void _call_Plane_intersects_ray(Variant &r_ret, Variant &p_self, const Variant **p_args) {
- Vector3 result;
- if (reinterpret_cast<Plane *>(p_self._data._mem)->intersects_ray(*p_args[0], *p_args[1], &result)) {
- r_ret = result;
- } else {
- r_ret = Variant();
- }
- }
-
- static void _call_Plane_intersects_segment(Variant &r_ret, Variant &p_self, const Variant **p_args) {
- Vector3 result;
- if (reinterpret_cast<Plane *>(p_self._data._mem)->intersects_segment(*p_args[0], *p_args[1], &result)) {
- r_ret = result;
- } else {
- r_ret = Variant();
- }
- }
-
- VCALL_LOCALMEM0R(Quat, length);
- VCALL_LOCALMEM0R(Quat, length_squared);
- VCALL_LOCALMEM0R(Quat, normalized);
- VCALL_LOCALMEM0R(Quat, is_normalized);
- VCALL_LOCALMEM1R(Quat, is_equal_approx);
- VCALL_LOCALMEM0R(Quat, inverse);
- VCALL_LOCALMEM1R(Quat, dot);
- VCALL_LOCALMEM1R(Quat, xform);
- VCALL_LOCALMEM2R(Quat, slerp);
- VCALL_LOCALMEM2R(Quat, slerpni);
- VCALL_LOCALMEM4R(Quat, cubic_slerp);
- VCALL_LOCALMEM0R(Quat, get_euler);
- VCALL_LOCALMEM1(Quat, set_euler);
- VCALL_LOCALMEM2(Quat, set_axis_angle);
-
- VCALL_LOCALMEM0R(Color, to_argb32);
- VCALL_LOCALMEM0R(Color, to_abgr32);
- VCALL_LOCALMEM0R(Color, to_rgba32);
- VCALL_LOCALMEM0R(Color, to_argb64);
- VCALL_LOCALMEM0R(Color, to_abgr64);
- VCALL_LOCALMEM0R(Color, to_rgba64);
- VCALL_LOCALMEM0R(Color, inverted);
- VCALL_LOCALMEM0R(Color, contrasted);
- VCALL_LOCALMEM2R(Color, lerp);
- VCALL_LOCALMEM1R(Color, blend);
- VCALL_LOCALMEM1R(Color, lightened);
- VCALL_LOCALMEM1R(Color, darkened);
- VCALL_LOCALMEM1R(Color, to_html);
- VCALL_LOCALMEM4R(Color, from_hsv);
- VCALL_LOCALMEM1R(Color, is_equal_approx);
-
- VCALL_LOCALMEM0R(RID, get_id);
-
- VCALL_LOCALMEM0R(NodePath, is_absolute);
- VCALL_LOCALMEM0R(NodePath, get_name_count);
- VCALL_LOCALMEM1R(NodePath, get_name);
- VCALL_LOCALMEM0R(NodePath, get_subname_count);
- VCALL_LOCALMEM1R(NodePath, get_subname);
- VCALL_LOCALMEM0R(NodePath, get_concatenated_subnames);
- VCALL_LOCALMEM0R(NodePath, get_as_property_path);
- VCALL_LOCALMEM0R(NodePath, is_empty);
-
- VCALL_LOCALMEM0R(Dictionary, size);
- VCALL_LOCALMEM0R(Dictionary, empty);
- VCALL_LOCALMEM0(Dictionary, clear);
- VCALL_LOCALMEM1R(Dictionary, has);
- VCALL_LOCALMEM1R(Dictionary, has_all);
- VCALL_LOCALMEM1R(Dictionary, erase);
- VCALL_LOCALMEM0R(Dictionary, hash);
- VCALL_LOCALMEM0R(Dictionary, keys);
- VCALL_LOCALMEM0R(Dictionary, values);
- VCALL_LOCALMEM1R(Dictionary, duplicate);
- VCALL_LOCALMEM2R(Dictionary, get);
-
- VCALL_LOCALMEM0R(Callable, is_null);
- VCALL_LOCALMEM0R(Callable, is_custom);
- VCALL_LOCALMEM0(Callable, is_standard);
- VCALL_LOCALMEM0(Callable, get_object);
- VCALL_LOCALMEM0(Callable, get_object_id);
- VCALL_LOCALMEM0(Callable, get_method);
- VCALL_LOCALMEM0(Callable, hash);
-
- VCALL_LOCALMEM0R(Signal, is_null);
- VCALL_LOCALMEM0R(Signal, get_object);
- VCALL_LOCALMEM0R(Signal, get_object_id);
- VCALL_LOCALMEM0R(Signal, get_name);
- VCALL_LOCALMEM3R(Signal, connect);
- VCALL_LOCALMEM1(Signal, disconnect);
- VCALL_LOCALMEM1R(Signal, is_connected);
- VCALL_LOCALMEM0R(Signal, get_connections);
-
- VCALL_LOCALMEM2(Array, set);
- VCALL_LOCALMEM1R(Array, get);
- VCALL_LOCALMEM0R(Array, size);
- VCALL_LOCALMEM0R(Array, empty);
- VCALL_LOCALMEM0(Array, clear);
- VCALL_LOCALMEM0R(Array, hash);
- VCALL_LOCALMEM1(Array, push_back);
- VCALL_LOCALMEM1(Array, push_front);
- VCALL_LOCALMEM0R(Array, pop_back);
- VCALL_LOCALMEM0R(Array, pop_front);
- VCALL_LOCALMEM1(Array, append);
- VCALL_LOCALMEM1(Array, resize);
- VCALL_LOCALMEM2(Array, insert);
- VCALL_LOCALMEM1(Array, remove);
- VCALL_LOCALMEM0R(Array, front);
- VCALL_LOCALMEM0R(Array, back);
- VCALL_LOCALMEM2R(Array, find);
- VCALL_LOCALMEM2R(Array, rfind);
- VCALL_LOCALMEM1R(Array, find_last);
- VCALL_LOCALMEM1R(Array, count);
- VCALL_LOCALMEM1R(Array, has);
- VCALL_LOCALMEM1(Array, erase);
- VCALL_LOCALMEM0(Array, sort);
- VCALL_LOCALMEM2(Array, sort_custom);
- VCALL_LOCALMEM0(Array, shuffle);
- VCALL_LOCALMEM2R(Array, bsearch);
- VCALL_LOCALMEM4R(Array, bsearch_custom);
- VCALL_LOCALMEM1R(Array, duplicate);
- VCALL_LOCALMEM4R(Array, slice);
- VCALL_LOCALMEM0(Array, invert);
- VCALL_LOCALMEM0R(Array, max);
- VCALL_LOCALMEM0R(Array, min);
-
- static void _call_PackedByteArray_get_string_from_ascii(Variant &r_ret, Variant &p_self, const Variant **p_args) {
- PackedByteArray *ba = reinterpret_cast<PackedByteArray *>(p_self._data._mem);
- String s;
- if (ba->size() > 0) {
- const uint8_t *r = ba->ptr();
- CharString cs;
- cs.resize(ba->size() + 1);
- copymem(cs.ptrw(), r, ba->size());
- cs[ba->size()] = 0;
-
- s = cs.get_data();
- }
- r_ret = s;
- }
-
- static void _call_PackedByteArray_get_string_from_utf8(Variant &r_ret, Variant &p_self, const Variant **p_args) {
- PackedByteArray *ba = reinterpret_cast<PackedByteArray *>(p_self._data._mem);
- String s;
- if (ba->size() > 0) {
- const uint8_t *r = ba->ptr();
- s.parse_utf8((const char *)r, ba->size());
- }
- r_ret = s;
- }
-
- static void _call_PackedByteArray_compress(Variant &r_ret, Variant &p_self, const Variant **p_args) {
- PackedByteArray *ba = reinterpret_cast<PackedByteArray *>(p_self._data._mem);
- PackedByteArray compressed;
- if (ba->size() > 0) {
- Compression::Mode mode = (Compression::Mode)(int)(*p_args[0]);
-
- compressed.resize(Compression::get_max_compressed_buffer_size(ba->size(), mode));
- int result = Compression::compress(compressed.ptrw(), ba->ptr(), ba->size(), mode);
-
- result = result >= 0 ? result : 0;
- compressed.resize(result);
- }
- r_ret = compressed;
- }
-
- static void _call_PackedByteArray_decompress(Variant &r_ret, Variant &p_self, const Variant **p_args) {
- PackedByteArray *ba = reinterpret_cast<PackedByteArray *>(p_self._data._mem);
- PackedByteArray decompressed;
- Compression::Mode mode = (Compression::Mode)(int)(*p_args[1]);
-
- int buffer_size = (int)(*p_args[0]);
-
- if (buffer_size <= 0) {
- r_ret = decompressed;
- ERR_FAIL_MSG("Decompression buffer size must be greater than zero.");
- }
-
- decompressed.resize(buffer_size);
- int result = Compression::decompress(decompressed.ptrw(), buffer_size, ba->ptr(), ba->size(), mode);
-
- result = result >= 0 ? result : 0;
- decompressed.resize(result);
-
- r_ret = decompressed;
- }
-
- static void _call_PackedByteArray_hex_encode(Variant &r_ret, Variant &p_self, const Variant **p_args) {
- PackedByteArray *ba = reinterpret_cast<PackedByteArray *>(p_self._data._mem);
- if (ba->size() == 0) {
- r_ret = String();
- return;
- }
- const uint8_t *r = ba->ptr();
- String s = String::hex_encode_buffer(&r[0], ba->size());
- r_ret = s;
- }
-
-#define VCALL_PARRMEM0(m_type, m_elemtype, m_method) \
- static void _call_##m_type##_##m_method(Variant &r_ret, Variant &p_self, const Variant **p_args) { Variant::PackedArrayRef<m_elemtype>::get_array_ptr(p_self._data.packed_array)->m_method(); }
-#define VCALL_PARRMEM0R(m_type, m_elemtype, m_method) \
- static void _call_##m_type##_##m_method(Variant &r_ret, Variant &p_self, const Variant **p_args) { r_ret = Variant::PackedArrayRef<m_elemtype>::get_array_ptr(p_self._data.packed_array)->m_method(); }
-#define VCALL_PARRMEM1(m_type, m_elemtype, m_method) \
- static void _call_##m_type##_##m_method(Variant &r_ret, Variant &p_self, const Variant **p_args) { Variant::PackedArrayRef<m_elemtype>::get_array_ptr(p_self._data.packed_array)->m_method(*p_args[0]); }
-#define VCALL_PARRMEM1R(m_type, m_elemtype, m_method) \
- static void _call_##m_type##_##m_method(Variant &r_ret, Variant &p_self, const Variant **p_args) { r_ret = Variant::PackedArrayRef<m_elemtype>::get_array_ptr(p_self._data.packed_array)->m_method(*p_args[0]); }
-#define VCALL_PARRMEM2(m_type, m_elemtype, m_method) \
- static void _call_##m_type##_##m_method(Variant &r_ret, Variant &p_self, const Variant **p_args) { Variant::PackedArrayRef<m_elemtype>::get_array_ptr(p_self._data.packed_array)->m_method(*p_args[0], *p_args[1]); }
-#define VCALL_PARRMEM2R(m_type, m_elemtype, m_method) \
- static void _call_##m_type##_##m_method(Variant &r_ret, Variant &p_self, const Variant **p_args) { r_ret = Variant::PackedArrayRef<m_elemtype>::get_array_ptr(p_self._data.packed_array)->m_method(*p_args[0], *p_args[1]); }
-#define VCALL_PARRMEM3(m_type, m_elemtype, m_method) \
- static void _call_##m_type##_##m_method(Variant &r_ret, Variant &p_self, const Variant **p_args) { Variant::PackedArrayRef<m_elemtype>::get_array_ptr(p_self._data.packed_array)->m_method(*p_args[0], *p_args[1], *p_args[2]); }
-#define VCALL_PARRMEM3R(m_type, m_elemtype, m_method) \
- static void _call_##m_type##_##m_method(Variant &r_ret, Variant &p_self, const Variant **p_args) { r_ret = Variant::PackedArrayRef<m_elemtype>::get_array_ptr(p_self._data.packed_array)->m_method(*p_args[0], *p_args[1], *p_args[2]); }
-#define VCALL_PARRMEM4(m_type, m_elemtype, m_method) \
- static void _call_##m_type##_##m_method(Variant &r_ret, Variant &p_self, const Variant **p_args) { Variant::PackedArrayRef<m_elemtype>::get_array_ptr(p_self._data.packed_array)->m_method(*p_args[0], *p_args[1], *p_args[2], *p_args[3]); }
-#define VCALL_PARRMEM4R(m_type, m_elemtype, m_method) \
- static void _call_##m_type##_##m_method(Variant &r_ret, Variant &p_self, const Variant **p_args) { r_ret = Variant::PackedArrayRef<m_elemtype>::get_array_ptr(p_self._data.packed_array)->m_method(*p_args[0], *p_args[1], *p_args[2], *p_args[3]); }
-#define VCALL_PARRMEM5(m_type, m_elemtype, m_method) \
- static void _call_##m_type##_##m_method(Variant &r_ret, Variant &p_self, const Variant **p_args) { Variant::PackedArrayRef<m_elemtype>::get_array_ptr(p_self._data.packed_array)->m_method(*p_args[0], *p_args[1], *p_args[2], *p_args[3], *p_args[4]); }
-#define VCALL_PARRMEM5R(m_type, m_elemtype, m_method) \
- static void _call_##m_type##_##m_method(Variant &r_ret, Variant &p_self, const Variant **p_args) { r_ret = Variant::PackedArrayRef<m_elemtype>::get_array_ptr(p_self._data.packed_array)->m_method(*p_args[0], *p_args[1], *p_args[2], *p_args[3], *p_args[4]); }
-
- VCALL_PARRMEM0R(PackedByteArray, uint8_t, size);
- VCALL_PARRMEM0R(PackedByteArray, uint8_t, empty);
- VCALL_PARRMEM2(PackedByteArray, uint8_t, set);
- VCALL_PARRMEM1R(PackedByteArray, uint8_t, get);
- VCALL_PARRMEM1(PackedByteArray, uint8_t, push_back);
- VCALL_PARRMEM1(PackedByteArray, uint8_t, resize);
- VCALL_PARRMEM2R(PackedByteArray, uint8_t, insert);
- VCALL_PARRMEM1(PackedByteArray, uint8_t, remove);
- VCALL_PARRMEM1(PackedByteArray, uint8_t, append);
- VCALL_PARRMEM1(PackedByteArray, uint8_t, append_array);
- VCALL_PARRMEM0(PackedByteArray, uint8_t, invert);
- VCALL_PARRMEM2R(PackedByteArray, uint8_t, subarray);
-
- VCALL_PARRMEM0R(PackedInt32Array, int32_t, size);
- VCALL_PARRMEM0R(PackedInt32Array, int32_t, empty);
- VCALL_PARRMEM2(PackedInt32Array, int32_t, set);
- VCALL_PARRMEM1R(PackedInt32Array, int32_t, get);
- VCALL_PARRMEM1(PackedInt32Array, int32_t, push_back);
- VCALL_PARRMEM1(PackedInt32Array, int32_t, resize);
- VCALL_PARRMEM2R(PackedInt32Array, int32_t, insert);
- VCALL_PARRMEM1(PackedInt32Array, int32_t, remove);
- VCALL_PARRMEM1(PackedInt32Array, int32_t, append);
- VCALL_PARRMEM1(PackedInt32Array, int32_t, append_array);
- VCALL_PARRMEM0(PackedInt32Array, int32_t, invert);
-
- VCALL_PARRMEM0R(PackedInt64Array, int64_t, size);
- VCALL_PARRMEM0R(PackedInt64Array, int64_t, empty);
- VCALL_PARRMEM2(PackedInt64Array, int64_t, set);
- VCALL_PARRMEM1R(PackedInt64Array, int64_t, get);
- VCALL_PARRMEM1(PackedInt64Array, int64_t, push_back);
- VCALL_PARRMEM1(PackedInt64Array, int64_t, resize);
- VCALL_PARRMEM2R(PackedInt64Array, int64_t, insert);
- VCALL_PARRMEM1(PackedInt64Array, int64_t, remove);
- VCALL_PARRMEM1(PackedInt64Array, int64_t, append);
- VCALL_PARRMEM1(PackedInt64Array, int64_t, append_array);
- VCALL_PARRMEM0(PackedInt64Array, int64_t, invert);
-
- VCALL_PARRMEM0R(PackedFloat32Array, float, size);
- VCALL_PARRMEM0R(PackedFloat32Array, float, empty);
- VCALL_PARRMEM2(PackedFloat32Array, float, set);
- VCALL_PARRMEM1R(PackedFloat32Array, float, get);
- VCALL_PARRMEM1(PackedFloat32Array, float, push_back);
- VCALL_PARRMEM1(PackedFloat32Array, float, resize);
- VCALL_PARRMEM2R(PackedFloat32Array, float, insert);
- VCALL_PARRMEM1(PackedFloat32Array, float, remove);
- VCALL_PARRMEM1(PackedFloat32Array, float, append);
- VCALL_PARRMEM1(PackedFloat32Array, float, append_array);
- VCALL_PARRMEM0(PackedFloat32Array, float, invert);
-
- VCALL_PARRMEM0R(PackedFloat64Array, double, size);
- VCALL_PARRMEM0R(PackedFloat64Array, double, empty);
- VCALL_PARRMEM2(PackedFloat64Array, double, set);
- VCALL_PARRMEM1R(PackedFloat64Array, double, get);
- VCALL_PARRMEM1(PackedFloat64Array, double, push_back);
- VCALL_PARRMEM1(PackedFloat64Array, double, resize);
- VCALL_PARRMEM2R(PackedFloat64Array, double, insert);
- VCALL_PARRMEM1(PackedFloat64Array, double, remove);
- VCALL_PARRMEM1(PackedFloat64Array, double, append);
- VCALL_PARRMEM1(PackedFloat64Array, double, append_array);
- VCALL_PARRMEM0(PackedFloat64Array, double, invert);
-
- VCALL_PARRMEM0R(PackedStringArray, String, size);
- VCALL_PARRMEM0R(PackedStringArray, String, empty);
- VCALL_PARRMEM2(PackedStringArray, String, set);
- VCALL_PARRMEM1R(PackedStringArray, String, get);
- VCALL_PARRMEM1(PackedStringArray, String, push_back);
- VCALL_PARRMEM1(PackedStringArray, String, resize);
- VCALL_PARRMEM2R(PackedStringArray, String, insert);
- VCALL_PARRMEM1(PackedStringArray, String, remove);
- VCALL_PARRMEM1(PackedStringArray, String, append);
- VCALL_PARRMEM1(PackedStringArray, String, append_array);
- VCALL_PARRMEM0(PackedStringArray, String, invert);
-
- VCALL_PARRMEM0R(PackedVector2Array, Vector2, size);
- VCALL_PARRMEM0R(PackedVector2Array, Vector2, empty);
- VCALL_PARRMEM2(PackedVector2Array, Vector2, set);
- VCALL_PARRMEM1R(PackedVector2Array, Vector2, get);
- VCALL_PARRMEM1(PackedVector2Array, Vector2, push_back);
- VCALL_PARRMEM1(PackedVector2Array, Vector2, resize);
- VCALL_PARRMEM2R(PackedVector2Array, Vector2, insert);
- VCALL_PARRMEM1(PackedVector2Array, Vector2, remove);
- VCALL_PARRMEM1(PackedVector2Array, Vector2, append);
- VCALL_PARRMEM1(PackedVector2Array, Vector2, append_array);
- VCALL_PARRMEM0(PackedVector2Array, Vector2, invert);
-
- VCALL_PARRMEM0R(PackedVector3Array, Vector3, size);
- VCALL_PARRMEM0R(PackedVector3Array, Vector3, empty);
- VCALL_PARRMEM2(PackedVector3Array, Vector3, set);
- VCALL_PARRMEM1R(PackedVector3Array, Vector3, get);
- VCALL_PARRMEM1(PackedVector3Array, Vector3, push_back);
- VCALL_PARRMEM1(PackedVector3Array, Vector3, resize);
- VCALL_PARRMEM2R(PackedVector3Array, Vector3, insert);
- VCALL_PARRMEM1(PackedVector3Array, Vector3, remove);
- VCALL_PARRMEM1(PackedVector3Array, Vector3, append);
- VCALL_PARRMEM1(PackedVector3Array, Vector3, append_array);
- VCALL_PARRMEM0(PackedVector3Array, Vector3, invert);
-
- VCALL_PARRMEM0R(PackedColorArray, Color, size);
- VCALL_PARRMEM0R(PackedColorArray, Color, empty);
- VCALL_PARRMEM2(PackedColorArray, Color, set);
- VCALL_PARRMEM1R(PackedColorArray, Color, get);
- VCALL_PARRMEM1(PackedColorArray, Color, push_back);
- VCALL_PARRMEM1(PackedColorArray, Color, resize);
- VCALL_PARRMEM2R(PackedColorArray, Color, insert);
- VCALL_PARRMEM1(PackedColorArray, Color, remove);
- VCALL_PARRMEM1(PackedColorArray, Color, append);
- VCALL_PARRMEM1(PackedColorArray, Color, append_array);
- VCALL_PARRMEM0(PackedColorArray, Color, invert);
-
-#define VCALL_PTR0(m_type, m_method) \
- static void _call_##m_type##_##m_method(Variant &r_ret, Variant &p_self, const Variant **p_args) { reinterpret_cast<m_type *>(p_self._data._ptr)->m_method(); }
-#define VCALL_PTR0R(m_type, m_method) \
- static void _call_##m_type##_##m_method(Variant &r_ret, Variant &p_self, const Variant **p_args) { r_ret = reinterpret_cast<m_type *>(p_self._data._ptr)->m_method(); }
-#define VCALL_PTR1(m_type, m_method) \
- static void _call_##m_type##_##m_method(Variant &r_ret, Variant &p_self, const Variant **p_args) { reinterpret_cast<m_type *>(p_self._data._ptr)->m_method(*p_args[0]); }
-#define VCALL_PTR1R(m_type, m_method) \
- static void _call_##m_type##_##m_method(Variant &r_ret, Variant &p_self, const Variant **p_args) { r_ret = reinterpret_cast<m_type *>(p_self._data._ptr)->m_method(*p_args[0]); }
-#define VCALL_PTR2(m_type, m_method) \
- static void _call_##m_type##_##m_method(Variant &r_ret, Variant &p_self, const Variant **p_args) { reinterpret_cast<m_type *>(p_self._data._ptr)->m_method(*p_args[0], *p_args[1]); }
-#define VCALL_PTR2R(m_type, m_method) \
- static void _call_##m_type##_##m_method(Variant &r_ret, Variant &p_self, const Variant **p_args) { r_ret = reinterpret_cast<m_type *>(p_self._data._ptr)->m_method(*p_args[0], *p_args[1]); }
-#define VCALL_PTR3(m_type, m_method) \
- static void _call_##m_type##_##m_method(Variant &r_ret, Variant &p_self, const Variant **p_args) { reinterpret_cast<m_type *>(p_self._data._ptr)->m_method(*p_args[0], *p_args[1], *p_args[2]); }
-#define VCALL_PTR3R(m_type, m_method) \
- static void _call_##m_type##_##m_method(Variant &r_ret, Variant &p_self, const Variant **p_args) { r_ret = reinterpret_cast<m_type *>(p_self._data._ptr)->m_method(*p_args[0], *p_args[1], *p_args[2]); }
-#define VCALL_PTR4(m_type, m_method) \
- static void _call_##m_type##_##m_method(Variant &r_ret, Variant &p_self, const Variant **p_args) { reinterpret_cast<m_type *>(p_self._data._ptr)->m_method(*p_args[0], *p_args[1], *p_args[2], *p_args[3]); }
-#define VCALL_PTR4R(m_type, m_method) \
- static void _call_##m_type##_##m_method(Variant &r_ret, Variant &p_self, const Variant **p_args) { r_ret = reinterpret_cast<m_type *>(p_self._data._ptr)->m_method(*p_args[0], *p_args[1], *p_args[2], *p_args[3]); }
-#define VCALL_PTR5(m_type, m_method) \
- static void _call_##m_type##_##m_method(Variant &r_ret, Variant &p_self, const Variant **p_args) { reinterpret_cast<m_type *>(p_self._data._ptr)->m_method(*p_args[0], *p_args[1], *p_args[2], *p_args[3], *p_args[4]); }
-#define VCALL_PTR5R(m_type, m_method) \
- static void _call_##m_type##_##m_method(Variant &r_ret, Variant &p_self, const Variant **p_args) { r_ret = reinterpret_cast<m_type *>(p_self._data._ptr)->m_method(*p_args[0], *p_args[1], *p_args[2], *p_args[3], *p_args[4]); }
-
- VCALL_PTR0R(AABB, get_area);
- VCALL_PTR0R(AABB, has_no_area);
- VCALL_PTR0R(AABB, has_no_surface);
- VCALL_PTR1R(AABB, has_point);
- VCALL_PTR1R(AABB, is_equal_approx);
- VCALL_PTR1R(AABB, intersects);
- VCALL_PTR1R(AABB, encloses);
- VCALL_PTR1R(AABB, intersects_plane);
- VCALL_PTR2R(AABB, intersects_segment);
- VCALL_PTR1R(AABB, intersection);
- VCALL_PTR1R(AABB, merge);
- VCALL_PTR1R(AABB, expand);
- VCALL_PTR1R(AABB, grow);
- VCALL_PTR1R(AABB, get_support);
- VCALL_PTR0R(AABB, get_longest_axis);
- VCALL_PTR0R(AABB, get_longest_axis_index);
- VCALL_PTR0R(AABB, get_longest_axis_size);
- VCALL_PTR0R(AABB, get_shortest_axis);
- VCALL_PTR0R(AABB, get_shortest_axis_index);
- VCALL_PTR0R(AABB, get_shortest_axis_size);
- VCALL_PTR1R(AABB, get_endpoint);
-
- VCALL_PTR0R(Transform2D, inverse);
- VCALL_PTR0R(Transform2D, affine_inverse);
- VCALL_PTR0R(Transform2D, get_rotation);
- VCALL_PTR0R(Transform2D, get_origin);
- VCALL_PTR0R(Transform2D, get_scale);
- VCALL_PTR0R(Transform2D, orthonormalized);
- VCALL_PTR1R(Transform2D, rotated);
- VCALL_PTR1R(Transform2D, scaled);
- VCALL_PTR1R(Transform2D, translated);
- VCALL_PTR2R(Transform2D, interpolate_with);
- VCALL_PTR1R(Transform2D, is_equal_approx);
-
- static void _call_Transform2D_xform(Variant &r_ret, Variant &p_self, const Variant **p_args) {
- switch (p_args[0]->type) {
- case Variant::VECTOR2:
- r_ret = reinterpret_cast<Transform2D *>(p_self._data._ptr)->xform(p_args[0]->operator Vector2());
- return;
- case Variant::RECT2:
- r_ret = reinterpret_cast<Transform2D *>(p_self._data._ptr)->xform(p_args[0]->operator Rect2());
- return;
- case Variant::PACKED_VECTOR2_ARRAY:
- r_ret = reinterpret_cast<Transform2D *>(p_self._data._ptr)->xform(p_args[0]->operator PackedVector2Array());
- return;
- default:
- r_ret = Variant();
- ERR_PRINT("Invalid type in function 'xform' in base 'Transform2D'. Valid types are Vector2, Rect2, and PackedVector2Array.");
- }
- }
-
- static void _call_Transform2D_xform_inv(Variant &r_ret, Variant &p_self, const Variant **p_args) {
- switch (p_args[0]->type) {
- case Variant::VECTOR2:
- r_ret = reinterpret_cast<Transform2D *>(p_self._data._ptr)->xform_inv(p_args[0]->operator Vector2());
- return;
- case Variant::RECT2:
- r_ret = reinterpret_cast<Transform2D *>(p_self._data._ptr)->xform_inv(p_args[0]->operator Rect2());
- return;
- case Variant::PACKED_VECTOR2_ARRAY:
- r_ret = reinterpret_cast<Transform2D *>(p_self._data._ptr)->xform_inv(p_args[0]->operator PackedVector2Array());
- return;
- default:
- r_ret = Variant();
- ERR_PRINT("Invalid type in function 'xform_inv' in base 'Transform2D'. Valid types are Vector2, Rect2, and PackedVector2Array.");
- }
- }
-
- static void _call_Transform2D_basis_xform(Variant &r_ret, Variant &p_self, const Variant **p_args) {
- switch (p_args[0]->type) {
- case Variant::VECTOR2:
- r_ret = reinterpret_cast<Transform2D *>(p_self._data._ptr)->basis_xform(p_args[0]->operator Vector2());
- return;
- default:
- r_ret = Variant();
- ERR_PRINT("Invalid type in function 'basis_xform' in base 'Transform2D'. Only Vector2 is valid.");
- }
- }
-
- static void _call_Transform2D_basis_xform_inv(Variant &r_ret, Variant &p_self, const Variant **p_args) {
- switch (p_args[0]->type) {
- case Variant::VECTOR2:
- r_ret = reinterpret_cast<Transform2D *>(p_self._data._ptr)->basis_xform_inv(p_args[0]->operator Vector2());
- return;
- default:
- r_ret = Variant();
- ERR_PRINT("Invalid type in function 'basis_xform_inv' in base 'Transform2D'. Only Vector2 is valid.");
- }
- }
-
- VCALL_PTR0R(Basis, inverse);
- VCALL_PTR0R(Basis, transposed);
- VCALL_PTR0R(Basis, determinant);
- VCALL_PTR2R(Basis, rotated);
- VCALL_PTR1R(Basis, scaled);
- VCALL_PTR0R(Basis, get_scale);
- VCALL_PTR0R(Basis, get_euler);
- VCALL_PTR0R(Basis, get_euler_xyz);
- VCALL_PTR1(Basis, set_euler_xyz);
- VCALL_PTR0R(Basis, get_euler_xzy);
- VCALL_PTR1(Basis, set_euler_xzy);
- VCALL_PTR0R(Basis, get_euler_yzx);
- VCALL_PTR1(Basis, set_euler_yzx);
- VCALL_PTR0R(Basis, get_euler_yxz);
- VCALL_PTR1(Basis, set_euler_yxz);
- VCALL_PTR0R(Basis, get_euler_zxy);
- VCALL_PTR1(Basis, set_euler_zxy);
- VCALL_PTR0R(Basis, get_euler_zyx);
- VCALL_PTR1(Basis, set_euler_zyx);
- VCALL_PTR1R(Basis, tdotx);
- VCALL_PTR1R(Basis, tdoty);
- VCALL_PTR1R(Basis, tdotz);
- VCALL_PTR1R(Basis, xform);
- VCALL_PTR1R(Basis, xform_inv);
- VCALL_PTR0R(Basis, get_orthogonal_index);
- VCALL_PTR0R(Basis, orthonormalized);
- VCALL_PTR2R(Basis, slerp);
- VCALL_PTR2R(Basis, is_equal_approx); // TODO: Break compatibility in 4.0 to change this to an instance method (a.is_equal_approx(b) as VCALL_PTR1R) for consistency.
- VCALL_PTR0R(Basis, get_rotation_quat);
-
- VCALL_PTR0R(Transform, inverse);
- VCALL_PTR0R(Transform, affine_inverse);
- VCALL_PTR2R(Transform, rotated);
- VCALL_PTR1R(Transform, scaled);
- VCALL_PTR1R(Transform, translated);
- VCALL_PTR0R(Transform, orthonormalized);
- VCALL_PTR2R(Transform, looking_at);
- VCALL_PTR2R(Transform, interpolate_with);
- VCALL_PTR1R(Transform, is_equal_approx);
-
- static void _call_Transform_xform(Variant &r_ret, Variant &p_self, const Variant **p_args) {
- switch (p_args[0]->type) {
- case Variant::VECTOR3:
- r_ret = reinterpret_cast<Transform *>(p_self._data._ptr)->xform(p_args[0]->operator Vector3());
- return;
- case Variant::PLANE:
- r_ret = reinterpret_cast<Transform *>(p_self._data._ptr)->xform(p_args[0]->operator Plane());
- return;
- case Variant::AABB:
- r_ret = reinterpret_cast<Transform *>(p_self._data._ptr)->xform(p_args[0]->operator ::AABB());
- return;
- case Variant::PACKED_VECTOR3_ARRAY:
- r_ret = reinterpret_cast<Transform *>(p_self._data._ptr)->xform(p_args[0]->operator ::PackedVector3Array());
- return;
- default:
- r_ret = Variant();
- ERR_PRINT("Invalid type in function 'xform' in base 'Transform'. Valid types are Vector3, Plane, AABB, and PackedVector3Array.");
- }
- }
-
- static void _call_Transform_xform_inv(Variant &r_ret, Variant &p_self, const Variant **p_args) {
- switch (p_args[0]->type) {
- case Variant::VECTOR3:
- r_ret = reinterpret_cast<Transform *>(p_self._data._ptr)->xform_inv(p_args[0]->operator Vector3());
- return;
- case Variant::PLANE:
- r_ret = reinterpret_cast<Transform *>(p_self._data._ptr)->xform_inv(p_args[0]->operator Plane());
- return;
- case Variant::AABB:
- r_ret = reinterpret_cast<Transform *>(p_self._data._ptr)->xform_inv(p_args[0]->operator ::AABB());
- return;
- case Variant::PACKED_VECTOR3_ARRAY:
- r_ret = reinterpret_cast<Transform *>(p_self._data._ptr)->xform_inv(p_args[0]->operator ::PackedVector3Array());
- return;
- default:
- r_ret = Variant();
- ERR_PRINT("Invalid type in function 'xform_inv' in base 'Transform'. Valid types are Vector3, Plane, AABB, and PackedVector3Array.");
- }
- }
-
- struct ConstructData {
- int arg_count;
- Vector<Variant::Type> arg_types;
- Vector<String> arg_names;
- VariantConstructFunc func;
- };
-
- struct ConstructFunc {
- List<ConstructData> constructors;
- };
-
- static ConstructFunc *construct_funcs;
-
- static void Vector2_init1(Variant &r_ret, const Variant **p_args) {
- r_ret = Vector2(*p_args[0], *p_args[1]);
- }
-
- static void Vector2i_init1(Variant &r_ret, const Variant **p_args) {
- r_ret = Vector2i(*p_args[0], *p_args[1]);
- }
-
- static void Rect2_init1(Variant &r_ret, const Variant **p_args) {
- r_ret = Rect2(*p_args[0], *p_args[1]);
- }
-
- static void Rect2_init2(Variant &r_ret, const Variant **p_args) {
- r_ret = Rect2(*p_args[0], *p_args[1], *p_args[2], *p_args[3]);
- }
-
- static void Rect2i_init1(Variant &r_ret, const Variant **p_args) {
- r_ret = Rect2i(*p_args[0], *p_args[1]);
- }
-
- static void Rect2i_init2(Variant &r_ret, const Variant **p_args) {
- r_ret = Rect2i(*p_args[0], *p_args[1], *p_args[2], *p_args[3]);
- }
-
- static void Transform2D_init2(Variant &r_ret, const Variant **p_args) {
- Transform2D m(*p_args[0], *p_args[1]);
- r_ret = m;
- }
-
- static void Transform2D_init3(Variant &r_ret, const Variant **p_args) {
- Transform2D m;
- m[0] = *p_args[0];
- m[1] = *p_args[1];
- m[2] = *p_args[2];
- r_ret = m;
- }
-
- static void Vector3_init1(Variant &r_ret, const Variant **p_args) {
- r_ret = Vector3(*p_args[0], *p_args[1], *p_args[2]);
- }
-
- static void Vector3i_init1(Variant &r_ret, const Variant **p_args) {
- r_ret = Vector3i(*p_args[0], *p_args[1], *p_args[2]);
- }
-
- static void Plane_init1(Variant &r_ret, const Variant **p_args) {
- r_ret = Plane(*p_args[0], *p_args[1], *p_args[2], *p_args[3]);
- }
-
- static void Plane_init2(Variant &r_ret, const Variant **p_args) {
- r_ret = Plane(*p_args[0], *p_args[1], *p_args[2]);
- }
-
- static void Plane_init3(Variant &r_ret, const Variant **p_args) {
- r_ret = Plane(p_args[0]->operator Vector3(), p_args[1]->operator real_t());
- }
- static void Plane_init4(Variant &r_ret, const Variant **p_args) {
- r_ret = Plane(p_args[0]->operator Vector3(), p_args[1]->operator Vector3());
- }
-
- static void Quat_init1(Variant &r_ret, const Variant **p_args) {
- r_ret = Quat(*p_args[0], *p_args[1], *p_args[2], *p_args[3]);
- }
-
- static void Quat_init2(Variant &r_ret, const Variant **p_args) {
- r_ret = Quat(((Vector3)(*p_args[0])), ((real_t)(*p_args[1])));
- }
-
- static void Quat_init3(Variant &r_ret, const Variant **p_args) {
- r_ret = Quat(((Vector3)(*p_args[0])));
- }
-
- static void Color_init1(Variant &r_ret, const Variant **p_args) {
- r_ret = Color(*p_args[0], *p_args[1], *p_args[2], *p_args[3]);
- }
-
- static void Color_init2(Variant &r_ret, const Variant **p_args) {
- r_ret = Color(*p_args[0], *p_args[1], *p_args[2]);
- }
-
- static void Color_init3(Variant &r_ret, const Variant **p_args) {
- r_ret = Color::html(*p_args[0]);
- }
-
- static void Color_init4(Variant &r_ret, const Variant **p_args) {
- r_ret = Color::hex(*p_args[0]);
- }
-
- static void Color_init5(Variant &r_ret, const Variant **p_args) {
- r_ret = Color(((Color)(*p_args[0])), *p_args[1]);
- }
-
- static void AABB_init1(Variant &r_ret, const Variant **p_args) {
- r_ret = ::AABB(*p_args[0], *p_args[1]);
- }
-
- static void Basis_init1(Variant &r_ret, const Variant **p_args) {
- Basis m;
- m.set_axis(0, *p_args[0]);
- m.set_axis(1, *p_args[1]);
- m.set_axis(2, *p_args[2]);
- r_ret = m;
- }
-
- static void Basis_init2(Variant &r_ret, const Variant **p_args) {
- r_ret = Basis(p_args[0]->operator Vector3(), p_args[1]->operator real_t());
- }
-
- static void Transform_init1(Variant &r_ret, const Variant **p_args) {
- Transform t;
- t.basis.set_axis(0, *p_args[0]);
- t.basis.set_axis(1, *p_args[1]);
- t.basis.set_axis(2, *p_args[2]);
- t.origin = *p_args[3];
- r_ret = t;
- }
-
- static void Transform_init2(Variant &r_ret, const Variant **p_args) {
- r_ret = Transform(p_args[0]->operator Basis(), p_args[1]->operator Vector3());
- }
-
- static void Callable_init2(Variant &r_ret, const Variant **p_args) {
- r_ret = Callable(p_args[0]->operator ObjectID(), p_args[1]->operator String());
- }
-
- static void Signal_init2(Variant &r_ret, const Variant **p_args) {
- r_ret = Signal(p_args[0]->operator ObjectID(), p_args[1]->operator String());
- }
-
- static void add_constructor(VariantConstructFunc p_func, const Variant::Type p_type,
- const String &p_name1 = "", const Variant::Type p_type1 = Variant::NIL,
- const String &p_name2 = "", const Variant::Type p_type2 = Variant::NIL,
- const String &p_name3 = "", const Variant::Type p_type3 = Variant::NIL,
- const String &p_name4 = "", const Variant::Type p_type4 = Variant::NIL) {
- ConstructData cd;
- cd.func = p_func;
- cd.arg_count = 0;
-
- if (p_name1 == "") {
- goto end;
- }
- cd.arg_count++;
- cd.arg_names.push_back(p_name1);
- cd.arg_types.push_back(p_type1);
-
- if (p_name2 == "") {
- goto end;
- }
- cd.arg_count++;
- cd.arg_names.push_back(p_name2);
- cd.arg_types.push_back(p_type2);
-
- if (p_name3 == "") {
- goto end;
- }
- cd.arg_count++;
- cd.arg_names.push_back(p_name3);
- cd.arg_types.push_back(p_type3);
-
- if (p_name4 == "") {
- goto end;
- }
- cd.arg_count++;
- cd.arg_names.push_back(p_name4);
- cd.arg_types.push_back(p_type4);
-
- end:
-
- construct_funcs[p_type].constructors.push_back(cd);
- }
-
- struct ConstantData {
- Map<StringName, int> value;
-#ifdef DEBUG_ENABLED
- List<StringName> value_ordered;
-#endif
- Map<StringName, Variant> variant_value;
-#ifdef DEBUG_ENABLED
- List<StringName> variant_value_ordered;
-#endif
- };
-
- static ConstantData *constant_data;
-
- static void add_constant(int p_type, StringName p_constant_name, int p_constant_value) {
- constant_data[p_type].value[p_constant_name] = p_constant_value;
-#ifdef DEBUG_ENABLED
- constant_data[p_type].value_ordered.push_back(p_constant_name);
-#endif
- }
-
- static void add_variant_constant(int p_type, StringName p_constant_name, const Variant &p_constant_value) {
- constant_data[p_type].variant_value[p_constant_name] = p_constant_value;
-#ifdef DEBUG_ENABLED
- constant_data[p_type].variant_value_ordered.push_back(p_constant_name);
-#endif
- }
-};
-
-_VariantCall::TypeFunc *_VariantCall::type_funcs = nullptr;
-_VariantCall::ConstructFunc *_VariantCall::construct_funcs = nullptr;
-_VariantCall::ConstantData *_VariantCall::constant_data = nullptr;
-
-Variant Variant::call(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
- Variant ret;
- call_ptr(p_method, p_args, p_argcount, &ret, r_error);
- return ret;
-}
-
-void Variant::call_ptr(const StringName &p_method, const Variant **p_args, int p_argcount, Variant *r_ret, Callable::CallError &r_error) {
- Variant ret;
-
- if (type == Variant::OBJECT) {
- //call object
- Object *obj = _get_obj().obj;
- if (!obj) {
- r_error.error = Callable::CallError::CALL_ERROR_INSTANCE_IS_NULL;
- return;
- }
-#ifdef DEBUG_ENABLED
- if (EngineDebugger::is_active() && !_get_obj().id.is_reference() && ObjectDB::get_instance(_get_obj().id) == nullptr) {
- r_error.error = Callable::CallError::CALL_ERROR_INSTANCE_IS_NULL;
- return;
- }
-
-#endif
- ret = _get_obj().obj->call(p_method, p_args, p_argcount, r_error);
-
- //else if (type==Variant::METHOD) {
-
- } else {
- r_error.error = Callable::CallError::CALL_OK;
-
- Map<StringName, _VariantCall::FuncData>::Element *E = _VariantCall::type_funcs[type].functions.find(p_method);
-
- if (E) {
- _VariantCall::FuncData &funcdata = E->get();
- funcdata.call(ret, *this, p_args, p_argcount, r_error);
-
- } else {
- //handle vararg functions manually
- bool valid = false;
- if (type == CALLABLE) {
- if (p_method == CoreStringNames::get_singleton()->call) {
- reinterpret_cast<const Callable *>(_data._mem)->call(p_args, p_argcount, ret, r_error);
- valid = true;
- }
- if (p_method == CoreStringNames::get_singleton()->call_deferred) {
- reinterpret_cast<const Callable *>(_data._mem)->call_deferred(p_args, p_argcount);
- valid = true;
- }
- } else if (type == SIGNAL) {
- if (p_method == CoreStringNames::get_singleton()->emit) {
- if (r_ret) {
- *r_ret = Variant();
- }
- reinterpret_cast<const Signal *>(_data._mem)->emit(p_args, p_argcount);
- valid = true;
- }
- }
- if (!valid) {
- //ok fail because not found
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
- return;
- }
- }
- }
-
- if (r_error.error == Callable::CallError::CALL_OK && r_ret) {
- *r_ret = ret;
- }
-}
-
-#define VCALL(m_type, m_method) _VariantCall::_call_##m_type##_##m_method
-
-Variant Variant::construct(const Variant::Type p_type, const Variant **p_args, int p_argcount, Callable::CallError &r_error, bool p_strict) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
- ERR_FAIL_INDEX_V(p_type, VARIANT_MAX, Variant());
-
- r_error.error = Callable::CallError::CALL_OK;
- if (p_argcount == 0) { //generic construct
-
- switch (p_type) {
- case NIL:
- return Variant();
-
- // atomic types
- case BOOL:
- return Variant(false);
- case INT:
- return 0;
- case FLOAT:
- return 0.0f;
- case STRING:
- return String();
-
- // math types
- case VECTOR2:
- return Vector2();
- case VECTOR2I:
- return Vector2i();
- case RECT2:
- return Rect2();
- case RECT2I:
- return Rect2i();
- case VECTOR3:
- return Vector3();
- case VECTOR3I:
- return Vector3i();
- case TRANSFORM2D:
- return Transform2D();
- case PLANE:
- return Plane();
- case QUAT:
- return Quat();
- case AABB:
- return ::AABB();
- case BASIS:
- return Basis();
- case TRANSFORM:
- return Transform();
-
- // misc types
- case COLOR:
- return Color();
- case STRING_NAME:
- return StringName();
- case NODE_PATH:
- return NodePath();
- case _RID:
- return RID();
- case OBJECT:
- return (Object *)nullptr;
- case CALLABLE:
- return Callable();
- case SIGNAL:
- return Signal();
- case DICTIONARY:
- return Dictionary();
- case ARRAY:
- return Array();
- case PACKED_BYTE_ARRAY:
- return PackedByteArray();
- case PACKED_INT32_ARRAY:
- return PackedInt32Array();
- case PACKED_INT64_ARRAY:
- return PackedInt64Array();
- case PACKED_FLOAT32_ARRAY:
- return PackedFloat32Array();
- case PACKED_FLOAT64_ARRAY:
- return PackedFloat64Array();
- case PACKED_STRING_ARRAY:
- return PackedStringArray();
- case PACKED_VECTOR2_ARRAY:
- return PackedVector2Array();
- case PACKED_VECTOR3_ARRAY:
- return PackedVector3Array();
- case PACKED_COLOR_ARRAY:
- return PackedColorArray();
- default:
- return Variant();
- }
-
- } else if (p_argcount == 1 && p_args[0]->type == p_type) {
- return *p_args[0]; //copy construct
- } else if (p_argcount == 1 && (!p_strict || Variant::can_convert(p_args[0]->type, p_type))) {
- //near match construct
-
- switch (p_type) {
- case NIL: {
- return Variant();
- } break;
- case BOOL: {
- return Variant(bool(*p_args[0]));
- }
- case INT: {
- return (int64_t(*p_args[0]));
- }
- case FLOAT: {
- return real_t(*p_args[0]);
- }
- case STRING: {
- return String(*p_args[0]);
- }
- case VECTOR2: {
- return Vector2(*p_args[0]);
- }
- case VECTOR2I: {
- return Vector2i(*p_args[0]);
- }
- case RECT2:
- return (Rect2(*p_args[0]));
- case RECT2I:
- return (Rect2i(*p_args[0]));
- case VECTOR3:
- return (Vector3(*p_args[0]));
- case VECTOR3I:
- return (Vector3i(*p_args[0]));
- case TRANSFORM2D:
- return (Transform2D(p_args[0]->operator Transform2D()));
- case PLANE:
- return (Plane(*p_args[0]));
- case QUAT:
- return (p_args[0]->operator Quat());
- case AABB:
- return (::AABB(*p_args[0]));
- case BASIS:
- return (Basis(p_args[0]->operator Basis()));
- case TRANSFORM:
- return (Transform(p_args[0]->operator Transform()));
-
- // misc types
- case COLOR:
- return p_args[0]->type == Variant::STRING ? Color::html(*p_args[0]) : Color::hex(*p_args[0]);
- case STRING_NAME:
- return (StringName(p_args[0]->operator StringName()));
- case NODE_PATH:
- return (NodePath(p_args[0]->operator NodePath()));
- case _RID:
- return (RID(*p_args[0]));
- case OBJECT:
- return ((Object *)(p_args[0]->operator Object *()));
- case CALLABLE:
- return ((Callable)(p_args[0]->operator Callable()));
- case SIGNAL:
- return ((Signal)(p_args[0]->operator Signal()));
- case DICTIONARY:
- return p_args[0]->operator Dictionary();
- case ARRAY:
- return p_args[0]->operator Array();
-
- // arrays
- case PACKED_BYTE_ARRAY:
- return (PackedByteArray(*p_args[0]));
- case PACKED_INT32_ARRAY:
- return (PackedInt32Array(*p_args[0]));
- case PACKED_INT64_ARRAY:
- return (PackedInt64Array(*p_args[0]));
- case PACKED_FLOAT32_ARRAY:
- return (PackedFloat32Array(*p_args[0]));
- case PACKED_FLOAT64_ARRAY:
- return (PackedFloat64Array(*p_args[0]));
- case PACKED_STRING_ARRAY:
- return (PackedStringArray(*p_args[0]));
- case PACKED_VECTOR2_ARRAY:
- return (PackedVector2Array(*p_args[0]));
- case PACKED_VECTOR3_ARRAY:
- return (PackedVector3Array(*p_args[0]));
- case PACKED_COLOR_ARRAY:
- return (PackedColorArray(*p_args[0]));
- default:
- return Variant();
- }
- } else if (p_argcount >= 1) {
- _VariantCall::ConstructFunc &c = _VariantCall::construct_funcs[p_type];
-
- for (List<_VariantCall::ConstructData>::Element *E = c.constructors.front(); E; E = E->next()) {
- const _VariantCall::ConstructData &cd = E->get();
-
- if (cd.arg_count != p_argcount) {
- continue;
- }
-
- //validate parameters
- for (int i = 0; i < cd.arg_count; i++) {
- if (!Variant::can_convert(p_args[i]->type, cd.arg_types[i])) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; //no such constructor
- r_error.argument = i;
- r_error.expected = cd.arg_types[i];
- return Variant();
- }
- }
-
- Variant v;
- cd.func(v, p_args);
- return v;
- }
- }
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; //no such constructor
- return Variant();
-}
-
-bool Variant::has_method(const StringName &p_method) const {
- if (type == OBJECT) {
- Object *obj = get_validated_object();
- if (!obj) {
- return false;
- }
-
- return obj->has_method(p_method);
- }
-
- const _VariantCall::TypeFunc &tf = _VariantCall::type_funcs[type];
- return tf.functions.has(p_method);
-}
-
-Vector<Variant::Type> Variant::get_method_argument_types(Variant::Type p_type, const StringName &p_method) {
- const _VariantCall::TypeFunc &tf = _VariantCall::type_funcs[p_type];
-
- const Map<StringName, _VariantCall::FuncData>::Element *E = tf.functions.find(p_method);
- if (!E) {
- return Vector<Variant::Type>();
- }
-
- return E->get().arg_types;
-}
-
-bool Variant::is_method_const(Variant::Type p_type, const StringName &p_method) {
- const _VariantCall::TypeFunc &tf = _VariantCall::type_funcs[p_type];
-
- const Map<StringName, _VariantCall::FuncData>::Element *E = tf.functions.find(p_method);
- if (!E) {
- return false;
- }
-
- return E->get()._const;
-}
-
-Vector<StringName> Variant::get_method_argument_names(Variant::Type p_type, const StringName &p_method) {
- const _VariantCall::TypeFunc &tf = _VariantCall::type_funcs[p_type];
-
- const Map<StringName, _VariantCall::FuncData>::Element *E = tf.functions.find(p_method);
- if (!E) {
- return Vector<StringName>();
- }
-
- return E->get().arg_names;
-}
-
-Variant::Type Variant::get_method_return_type(Variant::Type p_type, const StringName &p_method, bool *r_has_return) {
- const _VariantCall::TypeFunc &tf = _VariantCall::type_funcs[p_type];
-
- const Map<StringName, _VariantCall::FuncData>::Element *E = tf.functions.find(p_method);
- if (!E) {
- return Variant::NIL;
- }
-
- if (r_has_return) {
- *r_has_return = E->get().returns;
- }
-
- return E->get().return_type;
-}
-
-Vector<Variant> Variant::get_method_default_arguments(Variant::Type p_type, const StringName &p_method) {
- const _VariantCall::TypeFunc &tf = _VariantCall::type_funcs[p_type];
-
- const Map<StringName, _VariantCall::FuncData>::Element *E = tf.functions.find(p_method);
- if (!E) {
- return Vector<Variant>();
- }
-
- return E->get().default_args;
-}
-
-void Variant::get_method_list(List<MethodInfo> *p_list) const {
- const _VariantCall::TypeFunc &tf = _VariantCall::type_funcs[type];
-
- for (const Map<StringName, _VariantCall::FuncData>::Element *E = tf.functions.front(); E; E = E->next()) {
- const _VariantCall::FuncData &fd = E->get();
-
- MethodInfo mi;
- mi.name = E->key();
-
- if (fd._const) {
- mi.flags |= METHOD_FLAG_CONST;
- }
-
- for (int i = 0; i < fd.arg_types.size(); i++) {
- PropertyInfo pi;
- pi.type = fd.arg_types[i];
-#ifdef DEBUG_ENABLED
- pi.name = fd.arg_names[i];
-#endif
- mi.arguments.push_back(pi);
- }
-
- mi.default_arguments = fd.default_args;
- PropertyInfo ret;
-#ifdef DEBUG_ENABLED
- ret.type = fd.return_type;
- if (fd.returns) {
- ret.name = "ret";
- if (fd.return_type == Variant::NIL) {
- ret.usage = PROPERTY_USAGE_NIL_IS_VARIANT;
- }
- }
- mi.return_val = ret;
-#endif
-
- p_list->push_back(mi);
- }
-
- if (type == CALLABLE) {
- MethodInfo mi;
- mi.name = "call";
- mi.return_val.usage = PROPERTY_USAGE_NIL_IS_VARIANT;
- mi.flags |= METHOD_FLAG_VARARG;
-
- p_list->push_back(mi);
-
- mi.name = "call_deferred";
- mi.return_val.usage = 0;
-
- p_list->push_back(mi);
- }
-
- if (type == SIGNAL) {
- MethodInfo mi;
- mi.name = "emit";
- mi.flags |= METHOD_FLAG_VARARG;
-
- p_list->push_back(mi);
- }
-}
-
-void Variant::get_constructor_list(Variant::Type p_type, List<MethodInfo> *p_list) {
- ERR_FAIL_INDEX(p_type, VARIANT_MAX);
-
- //custom constructors
- for (const List<_VariantCall::ConstructData>::Element *E = _VariantCall::construct_funcs[p_type].constructors.front(); E; E = E->next()) {
- const _VariantCall::ConstructData &cd = E->get();
- MethodInfo mi;
- mi.name = Variant::get_type_name(p_type);
- mi.return_val.type = p_type;
- for (int i = 0; i < cd.arg_count; i++) {
- PropertyInfo pi;
- pi.name = cd.arg_names[i];
- pi.type = cd.arg_types[i];
- mi.arguments.push_back(pi);
- }
- p_list->push_back(mi);
- }
- //default constructors
- for (int i = 0; i < VARIANT_MAX; i++) {
- if (i == p_type) {
- continue;
- }
- if (!Variant::can_convert(Variant::Type(i), p_type)) {
- continue;
- }
-
- MethodInfo mi;
- mi.name = Variant::get_type_name(p_type);
- PropertyInfo pi;
- pi.name = "from";
- pi.type = Variant::Type(i);
- mi.arguments.push_back(pi);
- mi.return_val.type = p_type;
- p_list->push_back(mi);
- }
-}
-
-void Variant::get_constants_for_type(Variant::Type p_type, List<StringName> *p_constants) {
- ERR_FAIL_INDEX(p_type, Variant::VARIANT_MAX);
-
- _VariantCall::ConstantData &cd = _VariantCall::constant_data[p_type];
-
-#ifdef DEBUG_ENABLED
- for (List<StringName>::Element *E = cd.value_ordered.front(); E; E = E->next()) {
- p_constants->push_back(E->get());
-#else
- for (Map<StringName, int>::Element *E = cd.value.front(); E; E = E->next()) {
- p_constants->push_back(E->key());
-#endif
- }
-
-#ifdef DEBUG_ENABLED
- for (List<StringName>::Element *E = cd.variant_value_ordered.front(); E; E = E->next()) {
- p_constants->push_back(E->get());
-#else
- for (Map<StringName, Variant>::Element *E = cd.variant_value.front(); E; E = E->next()) {
- p_constants->push_back(E->key());
-#endif
- }
-}
-
-bool Variant::has_constant(Variant::Type p_type, const StringName &p_value) {
- ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, false);
- _VariantCall::ConstantData &cd = _VariantCall::constant_data[p_type];
- return cd.value.has(p_value) || cd.variant_value.has(p_value);
-}
-
-Variant Variant::get_constant_value(Variant::Type p_type, const StringName &p_value, bool *r_valid) {
- if (r_valid) {
- *r_valid = false;
- }
-
- ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, 0);
- _VariantCall::ConstantData &cd = _VariantCall::constant_data[p_type];
-
- Map<StringName, int>::Element *E = cd.value.find(p_value);
- if (!E) {
- Map<StringName, Variant>::Element *F = cd.variant_value.find(p_value);
- if (F) {
- if (r_valid) {
- *r_valid = true;
- }
- return F->get();
- } else {
- return -1;
- }
- }
- if (r_valid) {
- *r_valid = true;
- }
-
- return E->get();
-}
-
-void register_variant_methods() {
- _VariantCall::type_funcs = memnew_arr(_VariantCall::TypeFunc, Variant::VARIANT_MAX);
-
- _VariantCall::construct_funcs = memnew_arr(_VariantCall::ConstructFunc, Variant::VARIANT_MAX);
- _VariantCall::constant_data = memnew_arr(_VariantCall::ConstantData, Variant::VARIANT_MAX);
-
-#define ADDFUNC0R(m_vtype, m_ret, m_class, m_method, m_defarg) \
- _VariantCall::addfunc(true, Variant::m_vtype, Variant::m_ret, true, _scs_create(#m_method), VCALL(m_class, m_method), m_defarg);
-#define ADDFUNC1R(m_vtype, m_ret, m_class, m_method, m_arg1, m_argname1, m_defarg) \
- _VariantCall::addfunc(true, Variant::m_vtype, Variant::m_ret, true, _scs_create(#m_method), VCALL(m_class, m_method), m_defarg, _VariantCall::Arg(Variant::m_arg1, _scs_create(m_argname1)));
-#define ADDFUNC2R(m_vtype, m_ret, m_class, m_method, m_arg1, m_argname1, m_arg2, m_argname2, m_defarg) \
- _VariantCall::addfunc(true, Variant::m_vtype, Variant::m_ret, true, _scs_create(#m_method), VCALL(m_class, m_method), m_defarg, _VariantCall::Arg(Variant::m_arg1, _scs_create(m_argname1)), _VariantCall::Arg(Variant::m_arg2, _scs_create(m_argname2)));
-#define ADDFUNC3R(m_vtype, m_ret, m_class, m_method, m_arg1, m_argname1, m_arg2, m_argname2, m_arg3, m_argname3, m_defarg) \
- _VariantCall::addfunc(true, Variant::m_vtype, Variant::m_ret, true, _scs_create(#m_method), VCALL(m_class, m_method), m_defarg, _VariantCall::Arg(Variant::m_arg1, _scs_create(m_argname1)), _VariantCall::Arg(Variant::m_arg2, _scs_create(m_argname2)), _VariantCall::Arg(Variant::m_arg3, _scs_create(m_argname3)));
-#define ADDFUNC4R(m_vtype, m_ret, m_class, m_method, m_arg1, m_argname1, m_arg2, m_argname2, m_arg3, m_argname3, m_arg4, m_argname4, m_defarg) \
- _VariantCall::addfunc(true, Variant::m_vtype, Variant::m_ret, true, _scs_create(#m_method), VCALL(m_class, m_method), m_defarg, _VariantCall::Arg(Variant::m_arg1, _scs_create(m_argname1)), _VariantCall::Arg(Variant::m_arg2, _scs_create(m_argname2)), _VariantCall::Arg(Variant::m_arg3, _scs_create(m_argname3)), _VariantCall::Arg(Variant::m_arg4, _scs_create(m_argname4)));
-
-#define ADDFUNC0RNC(m_vtype, m_ret, m_class, m_method, m_defarg) \
- _VariantCall::addfunc(false, Variant::m_vtype, Variant::m_ret, true, _scs_create(#m_method), VCALL(m_class, m_method), m_defarg);
-#define ADDFUNC1RNC(m_vtype, m_ret, m_class, m_method, m_arg1, m_argname1, m_defarg) \
- _VariantCall::addfunc(false, Variant::m_vtype, Variant::m_ret, true, _scs_create(#m_method), VCALL(m_class, m_method), m_defarg, _VariantCall::Arg(Variant::m_arg1, _scs_create(m_argname1)));
-#define ADDFUNC2RNC(m_vtype, m_ret, m_class, m_method, m_arg1, m_argname1, m_arg2, m_argname2, m_defarg) \
- _VariantCall::addfunc(false, Variant::m_vtype, Variant::m_ret, true, _scs_create(#m_method), VCALL(m_class, m_method), m_defarg, _VariantCall::Arg(Variant::m_arg1, _scs_create(m_argname1)), _VariantCall::Arg(Variant::m_arg2, _scs_create(m_argname2)));
-#define ADDFUNC3RNC(m_vtype, m_ret, m_class, m_method, m_arg1, m_argname1, m_arg2, m_argname2, m_arg3, m_argname3, m_defarg) \
- _VariantCall::addfunc(false, Variant::m_vtype, Variant::m_ret, true, _scs_create(#m_method), VCALL(m_class, m_method), m_defarg, _VariantCall::Arg(Variant::m_arg1, _scs_create(m_argname1)), _VariantCall::Arg(Variant::m_arg2, _scs_create(m_argname2)), _VariantCall::Arg(Variant::m_arg3, _scs_create(m_argname3)));
-#define ADDFUNC4RNC(m_vtype, m_ret, m_class, m_method, m_arg1, m_argname1, m_arg2, m_argname2, m_arg3, m_argname3, m_arg4, m_argname4, m_defarg) \
- _VariantCall::addfunc(false, Variant::m_vtype, Variant::m_ret, true, _scs_create(#m_method), VCALL(m_class, m_method), m_defarg, _VariantCall::Arg(Variant::m_arg1, _scs_create(m_argname1)), _VariantCall::Arg(Variant::m_arg2, _scs_create(m_argname2)), _VariantCall::Arg(Variant::m_arg3, _scs_create(m_argname3)), _VariantCall::Arg(Variant::m_arg4, _scs_create(m_argname4)));
-
-#define ADDFUNC0(m_vtype, m_ret, m_class, m_method, m_defarg) \
- _VariantCall::addfunc(true, Variant::m_vtype, Variant::m_ret, false, _scs_create(#m_method), VCALL(m_class, m_method), m_defarg);
-#define ADDFUNC1(m_vtype, m_ret, m_class, m_method, m_arg1, m_argname1, m_defarg) \
- _VariantCall::addfunc(true, Variant::m_vtype, Variant::m_ret, false, _scs_create(#m_method), VCALL(m_class, m_method), m_defarg, _VariantCall::Arg(Variant::m_arg1, _scs_create(m_argname1)));
-#define ADDFUNC2(m_vtype, m_ret, m_class, m_method, m_arg1, m_argname1, m_arg2, m_argname2, m_defarg) \
- _VariantCall::addfunc(true, Variant::m_vtype, Variant::m_ret, false, _scs_create(#m_method), VCALL(m_class, m_method), m_defarg, _VariantCall::Arg(Variant::m_arg1, _scs_create(m_argname1)), _VariantCall::Arg(Variant::m_arg2, _scs_create(m_argname2)));
-#define ADDFUNC3(m_vtype, m_ret, m_class, m_method, m_arg1, m_argname1, m_arg2, m_argname2, m_arg3, m_argname3, m_defarg) \
- _VariantCall::addfunc(true, Variant::m_vtype, Variant::m_ret, false, _scs_create(#m_method), VCALL(m_class, m_method), m_defarg, _VariantCall::Arg(Variant::m_arg1, _scs_create(m_argname1)), _VariantCall::Arg(Variant::m_arg2, _scs_create(m_argname2)), _VariantCall::Arg(Variant::m_arg3, _scs_create(m_argname3)));
-#define ADDFUNC4(m_vtype, m_ret, m_class, m_method, m_arg1, m_argname1, m_arg2, m_argname2, m_arg3, m_argname3, m_arg4, m_argname4, m_defarg) \
- _VariantCall::addfunc(true, Variant::m_vtype, Variant::m_ret, false, _scs_create(#m_method), VCALL(m_class, m_method), m_defarg, _VariantCall::Arg(Variant::m_arg1, _scs_create(m_argname1)), _VariantCall::Arg(Variant::m_arg2, _scs_create(m_argname2)), _VariantCall::Arg(Variant::m_arg3, _scs_create(m_argname3)), _VariantCall::Arg(Variant::m_arg4, _scs_create(m_argname4)));
-
-#define ADDFUNC0NC(m_vtype, m_ret, m_class, m_method, m_defarg) \
- _VariantCall::addfunc(false, Variant::m_vtype, Variant::m_ret, false, _scs_create(#m_method), VCALL(m_class, m_method), m_defarg);
-#define ADDFUNC1NC(m_vtype, m_ret, m_class, m_method, m_arg1, m_argname1, m_defarg) \
- _VariantCall::addfunc(false, Variant::m_vtype, Variant::m_ret, false, _scs_create(#m_method), VCALL(m_class, m_method), m_defarg, _VariantCall::Arg(Variant::m_arg1, _scs_create(m_argname1)));
-#define ADDFUNC2NC(m_vtype, m_ret, m_class, m_method, m_arg1, m_argname1, m_arg2, m_argname2, m_defarg) \
- _VariantCall::addfunc(false, Variant::m_vtype, Variant::m_ret, false, _scs_create(#m_method), VCALL(m_class, m_method), m_defarg, _VariantCall::Arg(Variant::m_arg1, _scs_create(m_argname1)), _VariantCall::Arg(Variant::m_arg2, _scs_create(m_argname2)));
-#define ADDFUNC3NC(m_vtype, m_ret, m_class, m_method, m_arg1, m_argname1, m_arg2, m_argname2, m_arg3, m_argname3, m_defarg) \
- _VariantCall::addfunc(false, Variant::m_vtype, Variant::m_ret, false, _scs_create(#m_method), VCALL(m_class, m_method), m_defarg, _VariantCall::Arg(Variant::m_arg1, _scs_create(m_argname1)), _VariantCall::Arg(Variant::m_arg2, _scs_create(m_argname2)), _VariantCall::Arg(Variant::m_arg3, _scs_create(m_argname3)));
-#define ADDFUNC4NC(m_vtype, m_ret, m_class, m_method, m_arg1, m_argname1, m_arg2, m_argname2, m_arg3, m_argname3, m_arg4, m_argname4, m_defarg) \
- _VariantCall::addfunc(false, Variant::m_vtype, Variant::m_ret, false, _scs_create(#m_method), VCALL(m_class, m_method), m_defarg, _VariantCall::Arg(Variant::m_arg1, _scs_create(m_argname1)), _VariantCall::Arg(Variant::m_arg2, _scs_create(m_argname2)), _VariantCall::Arg(Variant::m_arg3, _scs_create(m_argname3)), _VariantCall::Arg(Variant::m_arg4, _scs_create(m_argname4)));
-
- /* STRING */
- ADDFUNC1R(STRING, INT, String, casecmp_to, STRING, "to", varray());
- ADDFUNC1R(STRING, INT, String, nocasecmp_to, STRING, "to", varray());
- ADDFUNC0R(STRING, INT, String, length, varray());
- ADDFUNC2R(STRING, STRING, String, substr, INT, "from", INT, "len", varray(-1));
-
- ADDFUNC2R(STRING, INT, String, find, STRING, "what", INT, "from", varray(0));
-
- ADDFUNC3R(STRING, INT, String, count, STRING, "what", INT, "from", INT, "to", varray(0, 0));
- ADDFUNC3R(STRING, INT, String, countn, STRING, "what", INT, "from", INT, "to", varray(0, 0));
-
- ADDFUNC2R(STRING, INT, String, findn, STRING, "what", INT, "from", varray(0));
- ADDFUNC2R(STRING, INT, String, rfind, STRING, "what", INT, "from", varray(-1));
- ADDFUNC2R(STRING, INT, String, rfindn, STRING, "what", INT, "from", varray(-1));
- ADDFUNC1R(STRING, BOOL, String, match, STRING, "expr", varray());
- ADDFUNC1R(STRING, BOOL, String, matchn, STRING, "expr", varray());
- ADDFUNC1R(STRING, BOOL, String, begins_with, STRING, "text", varray());
- ADDFUNC1R(STRING, BOOL, String, ends_with, STRING, "text", varray());
- ADDFUNC1R(STRING, BOOL, String, is_subsequence_of, STRING, "text", varray());
- ADDFUNC1R(STRING, BOOL, String, is_subsequence_ofi, STRING, "text", varray());
- ADDFUNC0R(STRING, PACKED_STRING_ARRAY, String, bigrams, varray());
- ADDFUNC1R(STRING, FLOAT, String, similarity, STRING, "text", varray());
-
- ADDFUNC2R(STRING, STRING, String, format, NIL, "values", STRING, "placeholder", varray("{_}"));
- ADDFUNC2R(STRING, STRING, String, replace, STRING, "what", STRING, "forwhat", varray());
- ADDFUNC2R(STRING, STRING, String, replacen, STRING, "what", STRING, "forwhat", varray());
- ADDFUNC1R(STRING, STRING, String, repeat, INT, "count", varray());
- ADDFUNC2R(STRING, STRING, String, insert, INT, "position", STRING, "what", varray());
- ADDFUNC0R(STRING, STRING, String, capitalize, varray());
- ADDFUNC3R(STRING, PACKED_STRING_ARRAY, String, split, STRING, "delimiter", BOOL, "allow_empty", INT, "maxsplit", varray(true, 0));
- ADDFUNC3R(STRING, PACKED_STRING_ARRAY, String, rsplit, STRING, "delimiter", BOOL, "allow_empty", INT, "maxsplit", varray(true, 0));
- ADDFUNC2R(STRING, PACKED_FLOAT32_ARRAY, String, split_floats, STRING, "delimiter", BOOL, "allow_empty", varray(true));
- ADDFUNC1R(STRING, STRING, String, join, PACKED_STRING_ARRAY, "parts", varray());
-
- ADDFUNC0R(STRING, STRING, String, to_upper, varray());
- ADDFUNC0R(STRING, STRING, String, to_lower, varray());
-
- ADDFUNC1R(STRING, STRING, String, left, INT, "position", varray());
- ADDFUNC1R(STRING, STRING, String, right, INT, "position", varray());
- ADDFUNC2R(STRING, STRING, String, strip_edges, BOOL, "left", BOOL, "right", varray(true, true));
- ADDFUNC0R(STRING, STRING, String, strip_escapes, varray());
- ADDFUNC1R(STRING, STRING, String, lstrip, STRING, "chars", varray());
- ADDFUNC1R(STRING, STRING, String, rstrip, STRING, "chars", varray());
- ADDFUNC0R(STRING, STRING, String, get_extension, varray());
- ADDFUNC0R(STRING, STRING, String, get_basename, varray());
- ADDFUNC1R(STRING, STRING, String, plus_file, STRING, "file", varray());
- ADDFUNC1R(STRING, INT, String, ord_at, INT, "at", varray());
- ADDFUNC0R(STRING, STRING, String, dedent, varray());
- ADDFUNC2(STRING, NIL, String, erase, INT, "position", INT, "chars", varray());
- ADDFUNC0R(STRING, INT, String, hash, varray());
- ADDFUNC0R(STRING, STRING, String, md5_text, varray());
- ADDFUNC0R(STRING, STRING, String, sha1_text, varray());
- ADDFUNC0R(STRING, STRING, String, sha256_text, varray());
- ADDFUNC0R(STRING, PACKED_BYTE_ARRAY, String, md5_buffer, varray());
- ADDFUNC0R(STRING, PACKED_BYTE_ARRAY, String, sha1_buffer, varray());
- ADDFUNC0R(STRING, PACKED_BYTE_ARRAY, String, sha256_buffer, varray());
- ADDFUNC0R(STRING, BOOL, String, empty, varray());
- ADDFUNC1R(STRING, STRING, String, humanize_size, INT, "size", varray());
- ADDFUNC0R(STRING, BOOL, String, is_abs_path, varray());
- ADDFUNC0R(STRING, BOOL, String, is_rel_path, varray());
- ADDFUNC0R(STRING, STRING, String, get_base_dir, varray());
- ADDFUNC0R(STRING, STRING, String, get_file, varray());
- ADDFUNC0R(STRING, STRING, String, xml_escape, varray());
- ADDFUNC0R(STRING, STRING, String, xml_unescape, varray());
- ADDFUNC0R(STRING, STRING, String, http_escape, varray());
- ADDFUNC0R(STRING, STRING, String, http_unescape, varray());
- ADDFUNC0R(STRING, STRING, String, c_escape, varray());
- ADDFUNC0R(STRING, STRING, String, c_unescape, varray());
- ADDFUNC0R(STRING, STRING, String, json_escape, varray());
- ADDFUNC0R(STRING, STRING, String, percent_encode, varray());
- ADDFUNC0R(STRING, STRING, String, percent_decode, varray());
- ADDFUNC0R(STRING, BOOL, String, is_valid_identifier, varray());
- ADDFUNC0R(STRING, BOOL, String, is_valid_integer, varray());
- ADDFUNC0R(STRING, BOOL, String, is_valid_float, varray());
- ADDFUNC1R(STRING, BOOL, String, is_valid_hex_number, BOOL, "with_prefix", varray(false));
- ADDFUNC0R(STRING, BOOL, String, is_valid_html_color, varray());
- ADDFUNC0R(STRING, BOOL, String, is_valid_ip_address, varray());
- ADDFUNC0R(STRING, BOOL, String, is_valid_filename, varray());
- ADDFUNC0R(STRING, INT, String, to_int, varray());
- ADDFUNC0R(STRING, FLOAT, String, to_float, varray());
- ADDFUNC0R(STRING, INT, String, hex_to_int, varray());
- ADDFUNC1R(STRING, STRING, String, pad_decimals, INT, "digits", varray());
- ADDFUNC1R(STRING, STRING, String, pad_zeros, INT, "digits", varray());
- ADDFUNC1R(STRING, STRING, String, trim_prefix, STRING, "prefix", varray());
- ADDFUNC1R(STRING, STRING, String, trim_suffix, STRING, "suffix", varray());
-
- ADDFUNC0R(STRING, PACKED_BYTE_ARRAY, String, to_ascii, varray());
- ADDFUNC0R(STRING, PACKED_BYTE_ARRAY, String, to_utf8, varray());
-
- ADDFUNC0R(VECTOR2, FLOAT, Vector2, angle, varray());
- ADDFUNC1R(VECTOR2, FLOAT, Vector2, angle_to, VECTOR2, "to", varray());
- ADDFUNC1R(VECTOR2, FLOAT, Vector2, angle_to_point, VECTOR2, "to", varray());
- ADDFUNC1R(VECTOR2, VECTOR2, Vector2, direction_to, VECTOR2, "b", varray());
- ADDFUNC1R(VECTOR2, FLOAT, Vector2, distance_to, VECTOR2, "to", varray());
- ADDFUNC1R(VECTOR2, FLOAT, Vector2, distance_squared_to, VECTOR2, "to", varray());
- ADDFUNC0R(VECTOR2, FLOAT, Vector2, length, varray());
- ADDFUNC0R(VECTOR2, FLOAT, Vector2, length_squared, varray());
- ADDFUNC0R(VECTOR2, VECTOR2, Vector2, normalized, varray());
- ADDFUNC0R(VECTOR2, BOOL, Vector2, is_normalized, varray());
- ADDFUNC1R(VECTOR2, BOOL, Vector2, is_equal_approx, VECTOR2, "v", varray());
- ADDFUNC1R(VECTOR2, VECTOR2, Vector2, posmod, FLOAT, "mod", varray());
- ADDFUNC1R(VECTOR2, VECTOR2, Vector2, posmodv, VECTOR2, "modv", varray());
- ADDFUNC1R(VECTOR2, VECTOR2, Vector2, project, VECTOR2, "b", varray());
- ADDFUNC2R(VECTOR2, VECTOR2, Vector2, lerp, VECTOR2, "b", FLOAT, "t", varray());
- ADDFUNC2R(VECTOR2, VECTOR2, Vector2, slerp, VECTOR2, "b", FLOAT, "t", varray());
- ADDFUNC4R(VECTOR2, VECTOR2, Vector2, cubic_interpolate, VECTOR2, "b", VECTOR2, "pre_a", VECTOR2, "post_b", FLOAT, "t", varray());
- ADDFUNC2R(VECTOR2, VECTOR2, Vector2, move_toward, VECTOR2, "to", FLOAT, "delta", varray());
- ADDFUNC1R(VECTOR2, VECTOR2, Vector2, rotated, FLOAT, "phi", varray());
- ADDFUNC0R(VECTOR2, VECTOR2, Vector2, tangent, varray());
- ADDFUNC0R(VECTOR2, VECTOR2, Vector2, floor, varray());
- ADDFUNC0R(VECTOR2, VECTOR2, Vector2, ceil, varray());
- ADDFUNC0R(VECTOR2, VECTOR2, Vector2, round, varray());
- ADDFUNC1R(VECTOR2, VECTOR2, Vector2, snapped, VECTOR2, "by", varray());
- ADDFUNC0R(VECTOR2, FLOAT, Vector2, aspect, varray());
- ADDFUNC1R(VECTOR2, FLOAT, Vector2, dot, VECTOR2, "with", varray());
- ADDFUNC1R(VECTOR2, VECTOR2, Vector2, slide, VECTOR2, "n", varray());
- ADDFUNC1R(VECTOR2, VECTOR2, Vector2, bounce, VECTOR2, "n", varray());
- ADDFUNC1R(VECTOR2, VECTOR2, Vector2, reflect, VECTOR2, "n", varray());
- ADDFUNC1R(VECTOR2, FLOAT, Vector2, cross, VECTOR2, "with", varray());
- ADDFUNC0R(VECTOR2, VECTOR2, Vector2, abs, varray());
- ADDFUNC1R(VECTOR2, VECTOR2, Vector2, clamped, FLOAT, "length", varray());
- ADDFUNC0R(VECTOR2, VECTOR2, Vector2, sign, varray());
-
- ADDFUNC0R(VECTOR2I, FLOAT, Vector2i, aspect, varray());
- ADDFUNC0R(VECTOR2I, VECTOR2I, Vector2i, sign, varray());
- ADDFUNC0R(VECTOR2I, VECTOR2I, Vector2i, abs, varray());
-
- ADDFUNC0R(RECT2, FLOAT, Rect2, get_area, varray());
- ADDFUNC0R(RECT2, BOOL, Rect2, has_no_area, varray());
- ADDFUNC1R(RECT2, BOOL, Rect2, has_point, VECTOR2, "point", varray());
- ADDFUNC1R(RECT2, BOOL, Rect2, is_equal_approx, RECT2, "rect", varray());
- ADDFUNC2R(RECT2, BOOL, Rect2, intersects, RECT2, "b", BOOL, "include_borders", varray(false));
- ADDFUNC1R(RECT2, BOOL, Rect2, encloses, RECT2, "b", varray());
- ADDFUNC1R(RECT2, RECT2, Rect2, clip, RECT2, "b", varray());
- ADDFUNC1R(RECT2, RECT2, Rect2, merge, RECT2, "b", varray());
- ADDFUNC1R(RECT2, RECT2, Rect2, expand, VECTOR2, "to", varray());
- ADDFUNC1R(RECT2, RECT2, Rect2, grow, FLOAT, "by", varray());
- ADDFUNC2R(RECT2, RECT2, Rect2, grow_margin, INT, "margin", FLOAT, "by", varray());
- ADDFUNC4R(RECT2, RECT2, Rect2, grow_individual, FLOAT, "left", FLOAT, "top", FLOAT, "right", FLOAT, " bottom", varray());
- ADDFUNC0R(RECT2, RECT2, Rect2, abs, varray());
-
- ADDFUNC0R(RECT2I, INT, Rect2i, get_area, varray());
- ADDFUNC0R(RECT2I, BOOL, Rect2i, has_no_area, varray());
- ADDFUNC1R(RECT2I, BOOL, Rect2i, has_point, VECTOR2I, "point", varray());
- ADDFUNC1R(RECT2I, BOOL, Rect2i, intersects, RECT2I, "b", varray());
- ADDFUNC1R(RECT2I, BOOL, Rect2i, encloses, RECT2I, "b", varray());
- ADDFUNC1R(RECT2I, RECT2I, Rect2i, clip, RECT2I, "b", varray());
- ADDFUNC1R(RECT2I, RECT2I, Rect2i, merge, RECT2I, "b", varray());
- ADDFUNC1R(RECT2I, RECT2I, Rect2i, expand, VECTOR2I, "to", varray());
- ADDFUNC1R(RECT2I, RECT2I, Rect2i, grow, INT, "by", varray());
- ADDFUNC2R(RECT2I, RECT2I, Rect2i, grow_margin, INT, "margin", INT, "by", varray());
- ADDFUNC4R(RECT2I, RECT2I, Rect2i, grow_individual, INT, "left", INT, "top", INT, "right", INT, " bottom", varray());
- ADDFUNC0R(RECT2I, RECT2I, Rect2i, abs, varray());
-
- ADDFUNC0R(VECTOR3, INT, Vector3, min_axis, varray());
- ADDFUNC0R(VECTOR3, INT, Vector3, max_axis, varray());
- ADDFUNC1R(VECTOR3, FLOAT, Vector3, angle_to, VECTOR3, "to", varray());
- ADDFUNC1R(VECTOR3, VECTOR3, Vector3, direction_to, VECTOR3, "b", varray());
- ADDFUNC1R(VECTOR3, FLOAT, Vector3, distance_to, VECTOR3, "b", varray());
- ADDFUNC1R(VECTOR3, FLOAT, Vector3, distance_squared_to, VECTOR3, "b", varray());
- ADDFUNC0R(VECTOR3, FLOAT, Vector3, length, varray());
- ADDFUNC0R(VECTOR3, FLOAT, Vector3, length_squared, varray());
- ADDFUNC0R(VECTOR3, VECTOR3, Vector3, normalized, varray());
- ADDFUNC0R(VECTOR3, BOOL, Vector3, is_normalized, varray());
- ADDFUNC1R(VECTOR3, BOOL, Vector3, is_equal_approx, VECTOR3, "v", varray());
- ADDFUNC0R(VECTOR3, VECTOR3, Vector3, inverse, varray());
- ADDFUNC1R(VECTOR3, VECTOR3, Vector3, snapped, VECTOR3, "by", varray());
- ADDFUNC2R(VECTOR3, VECTOR3, Vector3, rotated, VECTOR3, "axis", FLOAT, "phi", varray());
- ADDFUNC2R(VECTOR3, VECTOR3, Vector3, lerp, VECTOR3, "b", FLOAT, "t", varray());
- ADDFUNC2R(VECTOR3, VECTOR3, Vector3, slerp, VECTOR3, "b", FLOAT, "t", varray());
- ADDFUNC4R(VECTOR3, VECTOR3, Vector3, cubic_interpolate, VECTOR3, "b", VECTOR3, "pre_a", VECTOR3, "post_b", FLOAT, "t", varray());
- ADDFUNC2R(VECTOR3, VECTOR3, Vector3, move_toward, VECTOR3, "to", FLOAT, "delta", varray());
- ADDFUNC1R(VECTOR3, FLOAT, Vector3, dot, VECTOR3, "b", varray());
- ADDFUNC1R(VECTOR3, VECTOR3, Vector3, cross, VECTOR3, "b", varray());
- ADDFUNC1R(VECTOR3, BASIS, Vector3, outer, VECTOR3, "b", varray());
- ADDFUNC0R(VECTOR3, BASIS, Vector3, to_diagonal_matrix, varray());
- ADDFUNC0R(VECTOR3, VECTOR3, Vector3, abs, varray());
- ADDFUNC0R(VECTOR3, VECTOR3, Vector3, floor, varray());
- ADDFUNC0R(VECTOR3, VECTOR3, Vector3, ceil, varray());
- ADDFUNC0R(VECTOR3, VECTOR3, Vector3, round, varray());
- ADDFUNC1R(VECTOR3, VECTOR3, Vector3, posmod, FLOAT, "mod", varray());
- ADDFUNC1R(VECTOR3, VECTOR3, Vector3, posmodv, VECTOR3, "modv", varray());
- ADDFUNC1R(VECTOR3, VECTOR3, Vector3, project, VECTOR3, "b", varray());
- ADDFUNC1R(VECTOR3, VECTOR3, Vector3, slide, VECTOR3, "n", varray());
- ADDFUNC1R(VECTOR3, VECTOR3, Vector3, bounce, VECTOR3, "n", varray());
- ADDFUNC1R(VECTOR3, VECTOR3, Vector3, reflect, VECTOR3, "n", varray());
- ADDFUNC0R(VECTOR3, VECTOR3, Vector3, sign, varray());
-
- ADDFUNC0R(VECTOR3I, INT, Vector3i, min_axis, varray());
- ADDFUNC0R(VECTOR3I, INT, Vector3i, max_axis, varray());
- ADDFUNC0R(VECTOR3I, VECTOR3I, Vector3i, sign, varray());
-
- ADDFUNC0R(PLANE, PLANE, Plane, normalized, varray());
- ADDFUNC0R(PLANE, VECTOR3, Plane, center, varray());
- ADDFUNC0R(PLANE, VECTOR3, Plane, get_any_point, varray());
- ADDFUNC1R(PLANE, BOOL, Plane, is_equal_approx, PLANE, "plane", varray());
- ADDFUNC1R(PLANE, BOOL, Plane, is_point_over, VECTOR3, "point", varray());
- ADDFUNC1R(PLANE, FLOAT, Plane, distance_to, VECTOR3, "point", varray());
- ADDFUNC2R(PLANE, BOOL, Plane, has_point, VECTOR3, "point", FLOAT, "epsilon", varray(CMP_EPSILON));
- ADDFUNC1R(PLANE, VECTOR3, Plane, project, VECTOR3, "point", varray());
- ADDFUNC2R(PLANE, VECTOR3, Plane, intersect_3, PLANE, "b", PLANE, "c", varray());
- ADDFUNC2R(PLANE, VECTOR3, Plane, intersects_ray, VECTOR3, "from", VECTOR3, "dir", varray());
- ADDFUNC2R(PLANE, VECTOR3, Plane, intersects_segment, VECTOR3, "begin", VECTOR3, "end", varray());
-
- ADDFUNC0R(QUAT, FLOAT, Quat, length, varray());
- ADDFUNC0R(QUAT, FLOAT, Quat, length_squared, varray());
- ADDFUNC0R(QUAT, QUAT, Quat, normalized, varray());
- ADDFUNC0R(QUAT, BOOL, Quat, is_normalized, varray());
- ADDFUNC1R(QUAT, BOOL, Quat, is_equal_approx, QUAT, "quat", varray());
- ADDFUNC0R(QUAT, QUAT, Quat, inverse, varray());
- ADDFUNC1R(QUAT, FLOAT, Quat, dot, QUAT, "b", varray());
- ADDFUNC1R(QUAT, VECTOR3, Quat, xform, VECTOR3, "v", varray());
- ADDFUNC2R(QUAT, QUAT, Quat, slerp, QUAT, "b", FLOAT, "t", varray());
- ADDFUNC2R(QUAT, QUAT, Quat, slerpni, QUAT, "b", FLOAT, "t", varray());
- ADDFUNC4R(QUAT, QUAT, Quat, cubic_slerp, QUAT, "b", QUAT, "pre_a", QUAT, "post_b", FLOAT, "t", varray());
- ADDFUNC0R(QUAT, VECTOR3, Quat, get_euler, varray());
- ADDFUNC1(QUAT, NIL, Quat, set_euler, VECTOR3, "euler", varray());
- ADDFUNC2(QUAT, NIL, Quat, set_axis_angle, VECTOR3, "axis", FLOAT, "angle", varray());
-
- ADDFUNC0R(COLOR, INT, Color, to_argb32, varray());
- ADDFUNC0R(COLOR, INT, Color, to_abgr32, varray());
- ADDFUNC0R(COLOR, INT, Color, to_rgba32, varray());
- ADDFUNC0R(COLOR, INT, Color, to_argb64, varray());
- ADDFUNC0R(COLOR, INT, Color, to_abgr64, varray());
- ADDFUNC0R(COLOR, INT, Color, to_rgba64, varray());
- ADDFUNC0R(COLOR, COLOR, Color, inverted, varray());
- ADDFUNC0R(COLOR, COLOR, Color, contrasted, varray());
- ADDFUNC2R(COLOR, COLOR, Color, lerp, COLOR, "b", FLOAT, "t", varray());
- ADDFUNC1R(COLOR, COLOR, Color, blend, COLOR, "over", varray());
- ADDFUNC1R(COLOR, COLOR, Color, lightened, FLOAT, "amount", varray());
- ADDFUNC1R(COLOR, COLOR, Color, darkened, FLOAT, "amount", varray());
- ADDFUNC1R(COLOR, STRING, Color, to_html, BOOL, "with_alpha", varray(true));
- ADDFUNC4R(COLOR, COLOR, Color, from_hsv, FLOAT, "h", FLOAT, "s", FLOAT, "v", FLOAT, "a", varray(1.0));
- ADDFUNC1R(COLOR, BOOL, Color, is_equal_approx, COLOR, "color", varray());
-
- ADDFUNC0R(_RID, INT, RID, get_id, varray());
-
- ADDFUNC0R(NODE_PATH, BOOL, NodePath, is_absolute, varray());
- ADDFUNC0R(NODE_PATH, INT, NodePath, get_name_count, varray());
- ADDFUNC1R(NODE_PATH, STRING, NodePath, get_name, INT, "idx", varray());
- ADDFUNC0R(NODE_PATH, INT, NodePath, get_subname_count, varray());
- ADDFUNC1R(NODE_PATH, STRING, NodePath, get_subname, INT, "idx", varray());
- ADDFUNC0R(NODE_PATH, STRING, NodePath, get_concatenated_subnames, varray());
- ADDFUNC0R(NODE_PATH, NODE_PATH, NodePath, get_as_property_path, varray());
- ADDFUNC0R(NODE_PATH, BOOL, NodePath, is_empty, varray());
-
- ADDFUNC0R(DICTIONARY, INT, Dictionary, size, varray());
- ADDFUNC0R(DICTIONARY, BOOL, Dictionary, empty, varray());
- ADDFUNC0NC(DICTIONARY, NIL, Dictionary, clear, varray());
- ADDFUNC1R(DICTIONARY, BOOL, Dictionary, has, NIL, "key", varray());
- ADDFUNC1R(DICTIONARY, BOOL, Dictionary, has_all, ARRAY, "keys", varray());
- ADDFUNC1RNC(DICTIONARY, BOOL, Dictionary, erase, NIL, "key", varray());
- ADDFUNC0R(DICTIONARY, INT, Dictionary, hash, varray());
- ADDFUNC0R(DICTIONARY, ARRAY, Dictionary, keys, varray());
- ADDFUNC0R(DICTIONARY, ARRAY, Dictionary, values, varray());
- ADDFUNC1R(DICTIONARY, DICTIONARY, Dictionary, duplicate, BOOL, "deep", varray(false));
- ADDFUNC2R(DICTIONARY, NIL, Dictionary, get, NIL, "key", NIL, "default", varray(Variant()));
-
- ADDFUNC0R(CALLABLE, BOOL, Callable, is_null, varray());
- ADDFUNC0R(CALLABLE, BOOL, Callable, is_custom, varray());
- ADDFUNC0R(CALLABLE, BOOL, Callable, is_standard, varray());
- ADDFUNC0R(CALLABLE, OBJECT, Callable, get_object, varray());
- ADDFUNC0R(CALLABLE, INT, Callable, get_object_id, varray());
- ADDFUNC0R(CALLABLE, STRING_NAME, Callable, get_method, varray());
- ADDFUNC0R(CALLABLE, INT, Callable, hash, varray());
-
- ADDFUNC0R(SIGNAL, BOOL, Signal, is_null, varray());
- ADDFUNC0R(SIGNAL, OBJECT, Signal, get_object, varray());
- ADDFUNC0R(SIGNAL, INT, Signal, get_object_id, varray());
- ADDFUNC0R(SIGNAL, STRING_NAME, Signal, get_name, varray());
-
- ADDFUNC3R(SIGNAL, INT, Signal, connect, CALLABLE, "callable", ARRAY, "binds", INT, "flags", varray(Array(), 0));
-
- ADDFUNC1R(SIGNAL, NIL, Signal, disconnect, CALLABLE, "callable", varray());
- ADDFUNC1R(SIGNAL, BOOL, Signal, is_connected, CALLABLE, "callable", varray());
- ADDFUNC0R(SIGNAL, ARRAY, Signal, get_connections, varray());
-
- ADDFUNC0R(ARRAY, INT, Array, size, varray());
- ADDFUNC0R(ARRAY, BOOL, Array, empty, varray());
- ADDFUNC0NC(ARRAY, NIL, Array, clear, varray());
- ADDFUNC0R(ARRAY, INT, Array, hash, varray());
- ADDFUNC1NC(ARRAY, NIL, Array, push_back, NIL, "value", varray());
- ADDFUNC1NC(ARRAY, NIL, Array, push_front, NIL, "value", varray());
- ADDFUNC1NC(ARRAY, NIL, Array, append, NIL, "value", varray());
- ADDFUNC1NC(ARRAY, NIL, Array, resize, INT, "size", varray());
- ADDFUNC2NC(ARRAY, NIL, Array, insert, INT, "position", NIL, "value", varray());
- ADDFUNC1NC(ARRAY, NIL, Array, remove, INT, "position", varray());
- ADDFUNC1NC(ARRAY, NIL, Array, erase, NIL, "value", varray());
- ADDFUNC0R(ARRAY, NIL, Array, front, varray());
- ADDFUNC0R(ARRAY, NIL, Array, back, varray());
- ADDFUNC2R(ARRAY, INT, Array, find, NIL, "what", INT, "from", varray(0));
- ADDFUNC2R(ARRAY, INT, Array, rfind, NIL, "what", INT, "from", varray(-1));
- ADDFUNC1R(ARRAY, INT, Array, find_last, NIL, "value", varray());
- ADDFUNC1R(ARRAY, INT, Array, count, NIL, "value", varray());
- ADDFUNC1R(ARRAY, BOOL, Array, has, NIL, "value", varray());
- ADDFUNC0RNC(ARRAY, NIL, Array, pop_back, varray());
- ADDFUNC0RNC(ARRAY, NIL, Array, pop_front, varray());
- ADDFUNC0NC(ARRAY, NIL, Array, sort, varray());
- ADDFUNC2NC(ARRAY, NIL, Array, sort_custom, OBJECT, "obj", STRING, "func", varray());
- ADDFUNC0NC(ARRAY, NIL, Array, shuffle, varray());
- ADDFUNC2R(ARRAY, INT, Array, bsearch, NIL, "value", BOOL, "before", varray(true));
- ADDFUNC4R(ARRAY, INT, Array, bsearch_custom, NIL, "value", OBJECT, "obj", STRING, "func", BOOL, "before", varray(true));
- ADDFUNC0NC(ARRAY, NIL, Array, invert, varray());
- ADDFUNC1R(ARRAY, ARRAY, Array, duplicate, BOOL, "deep", varray(false));
- ADDFUNC4R(ARRAY, ARRAY, Array, slice, INT, "begin", INT, "end", INT, "step", BOOL, "deep", varray(1, false));
- ADDFUNC0R(ARRAY, NIL, Array, max, varray());
- ADDFUNC0R(ARRAY, NIL, Array, min, varray());
-
- ADDFUNC0R(PACKED_BYTE_ARRAY, INT, PackedByteArray, size, varray());
- ADDFUNC0R(PACKED_BYTE_ARRAY, BOOL, PackedByteArray, empty, varray());
- ADDFUNC2(PACKED_BYTE_ARRAY, NIL, PackedByteArray, set, INT, "idx", INT, "byte", varray());
- ADDFUNC1(PACKED_BYTE_ARRAY, NIL, PackedByteArray, push_back, INT, "byte", varray());
- ADDFUNC1(PACKED_BYTE_ARRAY, NIL, PackedByteArray, append, INT, "byte", varray());
- ADDFUNC1(PACKED_BYTE_ARRAY, NIL, PackedByteArray, append_array, PACKED_BYTE_ARRAY, "array", varray());
- ADDFUNC1(PACKED_BYTE_ARRAY, NIL, PackedByteArray, remove, INT, "idx", varray());
- ADDFUNC2R(PACKED_BYTE_ARRAY, INT, PackedByteArray, insert, INT, "idx", INT, "byte", varray());
- ADDFUNC1(PACKED_BYTE_ARRAY, NIL, PackedByteArray, resize, INT, "idx", varray());
- ADDFUNC0(PACKED_BYTE_ARRAY, NIL, PackedByteArray, invert, varray());
- ADDFUNC2R(PACKED_BYTE_ARRAY, PACKED_BYTE_ARRAY, PackedByteArray, subarray, INT, "from", INT, "to", varray());
-
- ADDFUNC0R(PACKED_BYTE_ARRAY, STRING, PackedByteArray, get_string_from_ascii, varray());
- ADDFUNC0R(PACKED_BYTE_ARRAY, STRING, PackedByteArray, get_string_from_utf8, varray());
- ADDFUNC0R(PACKED_BYTE_ARRAY, STRING, PackedByteArray, hex_encode, varray());
- ADDFUNC1R(PACKED_BYTE_ARRAY, PACKED_BYTE_ARRAY, PackedByteArray, compress, INT, "compression_mode", varray(0));
- ADDFUNC2R(PACKED_BYTE_ARRAY, PACKED_BYTE_ARRAY, PackedByteArray, decompress, INT, "buffer_size", INT, "compression_mode", varray(0));
-
- ADDFUNC0R(PACKED_INT32_ARRAY, INT, PackedInt32Array, size, varray());
- ADDFUNC0R(PACKED_INT32_ARRAY, BOOL, PackedInt32Array, empty, varray());
- ADDFUNC2(PACKED_INT32_ARRAY, NIL, PackedInt32Array, set, INT, "idx", INT, "integer", varray());
- ADDFUNC1(PACKED_INT32_ARRAY, NIL, PackedInt32Array, push_back, INT, "integer", varray());
- ADDFUNC1(PACKED_INT32_ARRAY, NIL, PackedInt32Array, append, INT, "integer", varray());
- ADDFUNC1(PACKED_INT32_ARRAY, NIL, PackedInt32Array, append_array, PACKED_INT32_ARRAY, "array", varray());
- ADDFUNC1(PACKED_INT32_ARRAY, NIL, PackedInt32Array, remove, INT, "idx", varray());
- ADDFUNC2R(PACKED_INT32_ARRAY, INT, PackedInt32Array, insert, INT, "idx", INT, "integer", varray());
- ADDFUNC1(PACKED_INT32_ARRAY, NIL, PackedInt32Array, resize, INT, "idx", varray());
- ADDFUNC0(PACKED_INT32_ARRAY, NIL, PackedInt32Array, invert, varray());
-
- ADDFUNC0R(PACKED_INT64_ARRAY, INT, PackedInt64Array, size, varray());
- ADDFUNC0R(PACKED_INT64_ARRAY, BOOL, PackedInt64Array, empty, varray());
- ADDFUNC2(PACKED_INT64_ARRAY, NIL, PackedInt64Array, set, INT, "idx", INT, "integer", varray());
- ADDFUNC1(PACKED_INT64_ARRAY, NIL, PackedInt64Array, push_back, INT, "integer", varray());
- ADDFUNC1(PACKED_INT64_ARRAY, NIL, PackedInt64Array, append, INT, "integer", varray());
- ADDFUNC1(PACKED_INT64_ARRAY, NIL, PackedInt64Array, append_array, PACKED_INT64_ARRAY, "array", varray());
- ADDFUNC1(PACKED_INT64_ARRAY, NIL, PackedInt64Array, remove, INT, "idx", varray());
- ADDFUNC2R(PACKED_INT64_ARRAY, INT, PackedInt64Array, insert, INT, "idx", INT, "integer", varray());
- ADDFUNC1(PACKED_INT64_ARRAY, NIL, PackedInt64Array, resize, INT, "idx", varray());
- ADDFUNC0(PACKED_INT64_ARRAY, NIL, PackedInt64Array, invert, varray());
-
- ADDFUNC0R(PACKED_FLOAT32_ARRAY, INT, PackedFloat32Array, size, varray());
- ADDFUNC0R(PACKED_FLOAT32_ARRAY, BOOL, PackedFloat32Array, empty, varray());
- ADDFUNC2(PACKED_FLOAT32_ARRAY, NIL, PackedFloat32Array, set, INT, "idx", FLOAT, "value", varray());
- ADDFUNC1(PACKED_FLOAT32_ARRAY, NIL, PackedFloat32Array, push_back, FLOAT, "value", varray());
- ADDFUNC1(PACKED_FLOAT32_ARRAY, NIL, PackedFloat32Array, append, FLOAT, "value", varray());
- ADDFUNC1(PACKED_FLOAT32_ARRAY, NIL, PackedFloat32Array, append_array, PACKED_FLOAT32_ARRAY, "array", varray());
- ADDFUNC1(PACKED_FLOAT32_ARRAY, NIL, PackedFloat32Array, remove, INT, "idx", varray());
- ADDFUNC2R(PACKED_FLOAT32_ARRAY, INT, PackedFloat32Array, insert, INT, "idx", FLOAT, "value", varray());
- ADDFUNC1(PACKED_FLOAT32_ARRAY, NIL, PackedFloat32Array, resize, INT, "idx", varray());
- ADDFUNC0(PACKED_FLOAT32_ARRAY, NIL, PackedFloat32Array, invert, varray());
-
- ADDFUNC0R(PACKED_FLOAT64_ARRAY, INT, PackedFloat64Array, size, varray());
- ADDFUNC0R(PACKED_FLOAT64_ARRAY, BOOL, PackedFloat64Array, empty, varray());
- ADDFUNC2(PACKED_FLOAT64_ARRAY, NIL, PackedFloat64Array, set, INT, "idx", FLOAT, "value", varray());
- ADDFUNC1(PACKED_FLOAT64_ARRAY, NIL, PackedFloat64Array, push_back, FLOAT, "value", varray());
- ADDFUNC1(PACKED_FLOAT64_ARRAY, NIL, PackedFloat64Array, append, FLOAT, "value", varray());
- ADDFUNC1(PACKED_FLOAT64_ARRAY, NIL, PackedFloat64Array, append_array, PACKED_FLOAT64_ARRAY, "array", varray());
- ADDFUNC1(PACKED_FLOAT64_ARRAY, NIL, PackedFloat64Array, remove, INT, "idx", varray());
- ADDFUNC2R(PACKED_FLOAT64_ARRAY, INT, PackedFloat64Array, insert, INT, "idx", FLOAT, "value", varray());
- ADDFUNC1(PACKED_FLOAT64_ARRAY, NIL, PackedFloat64Array, resize, INT, "idx", varray());
- ADDFUNC0(PACKED_FLOAT64_ARRAY, NIL, PackedFloat64Array, invert, varray());
-
- ADDFUNC0R(PACKED_STRING_ARRAY, INT, PackedStringArray, size, varray());
- ADDFUNC0R(PACKED_STRING_ARRAY, BOOL, PackedStringArray, empty, varray());
- ADDFUNC2(PACKED_STRING_ARRAY, NIL, PackedStringArray, set, INT, "idx", STRING, "string", varray());
- ADDFUNC1(PACKED_STRING_ARRAY, NIL, PackedStringArray, push_back, STRING, "string", varray());
- ADDFUNC1(PACKED_STRING_ARRAY, NIL, PackedStringArray, append, STRING, "string", varray());
- ADDFUNC1(PACKED_STRING_ARRAY, NIL, PackedStringArray, append_array, PACKED_STRING_ARRAY, "array", varray());
- ADDFUNC1(PACKED_STRING_ARRAY, NIL, PackedStringArray, remove, INT, "idx", varray());
- ADDFUNC2R(PACKED_STRING_ARRAY, INT, PackedStringArray, insert, INT, "idx", STRING, "string", varray());
- ADDFUNC1(PACKED_STRING_ARRAY, NIL, PackedStringArray, resize, INT, "idx", varray());
- ADDFUNC0(PACKED_STRING_ARRAY, NIL, PackedStringArray, invert, varray());
-
- ADDFUNC0R(PACKED_VECTOR2_ARRAY, INT, PackedVector2Array, size, varray());
- ADDFUNC0R(PACKED_VECTOR2_ARRAY, BOOL, PackedVector2Array, empty, varray());
- ADDFUNC2(PACKED_VECTOR2_ARRAY, NIL, PackedVector2Array, set, INT, "idx", VECTOR2, "vector2", varray());
- ADDFUNC1(PACKED_VECTOR2_ARRAY, NIL, PackedVector2Array, push_back, VECTOR2, "vector2", varray());
- ADDFUNC1(PACKED_VECTOR2_ARRAY, NIL, PackedVector2Array, append, VECTOR2, "vector2", varray());
- ADDFUNC1(PACKED_VECTOR2_ARRAY, NIL, PackedVector2Array, append_array, PACKED_VECTOR2_ARRAY, "array", varray());
- ADDFUNC1(PACKED_VECTOR2_ARRAY, NIL, PackedVector2Array, remove, INT, "idx", varray());
- ADDFUNC2R(PACKED_VECTOR2_ARRAY, INT, PackedVector2Array, insert, INT, "idx", VECTOR2, "vector2", varray());
- ADDFUNC1(PACKED_VECTOR2_ARRAY, NIL, PackedVector2Array, resize, INT, "idx", varray());
- ADDFUNC0(PACKED_VECTOR2_ARRAY, NIL, PackedVector2Array, invert, varray());
-
- ADDFUNC0R(PACKED_VECTOR3_ARRAY, INT, PackedVector3Array, size, varray());
- ADDFUNC0R(PACKED_VECTOR3_ARRAY, BOOL, PackedVector3Array, empty, varray());
- ADDFUNC2(PACKED_VECTOR3_ARRAY, NIL, PackedVector3Array, set, INT, "idx", VECTOR3, "vector3", varray());
- ADDFUNC1(PACKED_VECTOR3_ARRAY, NIL, PackedVector3Array, push_back, VECTOR3, "vector3", varray());
- ADDFUNC1(PACKED_VECTOR3_ARRAY, NIL, PackedVector3Array, append, VECTOR3, "vector3", varray());
- ADDFUNC1(PACKED_VECTOR3_ARRAY, NIL, PackedVector3Array, append_array, PACKED_VECTOR3_ARRAY, "array", varray());
- ADDFUNC1(PACKED_VECTOR3_ARRAY, NIL, PackedVector3Array, remove, INT, "idx", varray());
- ADDFUNC2R(PACKED_VECTOR3_ARRAY, INT, PackedVector3Array, insert, INT, "idx", VECTOR3, "vector3", varray());
- ADDFUNC1(PACKED_VECTOR3_ARRAY, NIL, PackedVector3Array, resize, INT, "idx", varray());
- ADDFUNC0(PACKED_VECTOR3_ARRAY, NIL, PackedVector3Array, invert, varray());
-
- ADDFUNC0R(PACKED_COLOR_ARRAY, INT, PackedColorArray, size, varray());
- ADDFUNC0R(PACKED_COLOR_ARRAY, BOOL, PackedColorArray, empty, varray());
- ADDFUNC2(PACKED_COLOR_ARRAY, NIL, PackedColorArray, set, INT, "idx", COLOR, "color", varray());
- ADDFUNC1(PACKED_COLOR_ARRAY, NIL, PackedColorArray, push_back, COLOR, "color", varray());
- ADDFUNC1(PACKED_COLOR_ARRAY, NIL, PackedColorArray, append, COLOR, "color", varray());
- ADDFUNC1(PACKED_COLOR_ARRAY, NIL, PackedColorArray, append_array, PACKED_COLOR_ARRAY, "array", varray());
- ADDFUNC1(PACKED_COLOR_ARRAY, NIL, PackedColorArray, remove, INT, "idx", varray());
- ADDFUNC2R(PACKED_COLOR_ARRAY, INT, PackedColorArray, insert, INT, "idx", COLOR, "color", varray());
- ADDFUNC1(PACKED_COLOR_ARRAY, NIL, PackedColorArray, resize, INT, "idx", varray());
- ADDFUNC0(PACKED_COLOR_ARRAY, NIL, PackedColorArray, invert, varray());
-
- //pointerbased
-
- ADDFUNC0R(AABB, FLOAT, AABB, get_area, varray());
- ADDFUNC0R(AABB, BOOL, AABB, has_no_area, varray());
- ADDFUNC0R(AABB, BOOL, AABB, has_no_surface, varray());
- ADDFUNC1R(AABB, BOOL, AABB, has_point, VECTOR3, "point", varray());
- ADDFUNC1R(AABB, BOOL, AABB, is_equal_approx, AABB, "aabb", varray());
- ADDFUNC1R(AABB, BOOL, AABB, intersects, AABB, "with", varray());
- ADDFUNC1R(AABB, BOOL, AABB, encloses, AABB, "with", varray());
- ADDFUNC1R(AABB, BOOL, AABB, intersects_plane, PLANE, "plane", varray());
- ADDFUNC2R(AABB, BOOL, AABB, intersects_segment, VECTOR3, "from", VECTOR3, "to", varray());
- ADDFUNC1R(AABB, AABB, AABB, intersection, AABB, "with", varray());
- ADDFUNC1R(AABB, AABB, AABB, merge, AABB, "with", varray());
- ADDFUNC1R(AABB, AABB, AABB, expand, VECTOR3, "to_point", varray());
- ADDFUNC1R(AABB, AABB, AABB, grow, FLOAT, "by", varray());
- ADDFUNC1R(AABB, VECTOR3, AABB, get_support, VECTOR3, "dir", varray());
- ADDFUNC0R(AABB, VECTOR3, AABB, get_longest_axis, varray());
- ADDFUNC0R(AABB, INT, AABB, get_longest_axis_index, varray());
- ADDFUNC0R(AABB, FLOAT, AABB, get_longest_axis_size, varray());
- ADDFUNC0R(AABB, VECTOR3, AABB, get_shortest_axis, varray());
- ADDFUNC0R(AABB, INT, AABB, get_shortest_axis_index, varray());
- ADDFUNC0R(AABB, FLOAT, AABB, get_shortest_axis_size, varray());
- ADDFUNC1R(AABB, VECTOR3, AABB, get_endpoint, INT, "idx", varray());
-
- ADDFUNC0R(TRANSFORM2D, TRANSFORM2D, Transform2D, inverse, varray());
- ADDFUNC0R(TRANSFORM2D, TRANSFORM2D, Transform2D, affine_inverse, varray());
- ADDFUNC0R(TRANSFORM2D, FLOAT, Transform2D, get_rotation, varray());
- ADDFUNC0R(TRANSFORM2D, VECTOR2, Transform2D, get_origin, varray());
- ADDFUNC0R(TRANSFORM2D, VECTOR2, Transform2D, get_scale, varray());
- ADDFUNC0R(TRANSFORM2D, TRANSFORM2D, Transform2D, orthonormalized, varray());
- ADDFUNC1R(TRANSFORM2D, TRANSFORM2D, Transform2D, rotated, FLOAT, "phi", varray());
- ADDFUNC1R(TRANSFORM2D, TRANSFORM2D, Transform2D, scaled, VECTOR2, "scale", varray());
- ADDFUNC1R(TRANSFORM2D, TRANSFORM2D, Transform2D, translated, VECTOR2, "offset", varray());
- ADDFUNC1R(TRANSFORM2D, NIL, Transform2D, xform, NIL, "v", varray());
- ADDFUNC1R(TRANSFORM2D, NIL, Transform2D, xform_inv, NIL, "v", varray());
- ADDFUNC1R(TRANSFORM2D, VECTOR2, Transform2D, basis_xform, VECTOR2, "v", varray());
- ADDFUNC1R(TRANSFORM2D, VECTOR2, Transform2D, basis_xform_inv, VECTOR2, "v", varray());
- ADDFUNC2R(TRANSFORM2D, TRANSFORM2D, Transform2D, interpolate_with, TRANSFORM2D, "transform", FLOAT, "weight", varray());
- ADDFUNC1R(TRANSFORM2D, BOOL, Transform2D, is_equal_approx, TRANSFORM2D, "transform", varray());
-
- ADDFUNC0R(BASIS, BASIS, Basis, inverse, varray());
- ADDFUNC0R(BASIS, BASIS, Basis, transposed, varray());
- ADDFUNC0R(BASIS, BASIS, Basis, orthonormalized, varray());
- ADDFUNC0R(BASIS, FLOAT, Basis, determinant, varray());
- ADDFUNC2R(BASIS, BASIS, Basis, rotated, VECTOR3, "axis", FLOAT, "phi", varray());
- ADDFUNC1R(BASIS, BASIS, Basis, scaled, VECTOR3, "scale", varray());
- ADDFUNC0R(BASIS, VECTOR3, Basis, get_scale, varray());
- ADDFUNC0R(BASIS, VECTOR3, Basis, get_euler, varray());
- ADDFUNC1R(BASIS, FLOAT, Basis, tdotx, VECTOR3, "with", varray());
- ADDFUNC1R(BASIS, FLOAT, Basis, tdoty, VECTOR3, "with", varray());
- ADDFUNC1R(BASIS, FLOAT, Basis, tdotz, VECTOR3, "with", varray());
- ADDFUNC1R(BASIS, VECTOR3, Basis, xform, VECTOR3, "v", varray());
- ADDFUNC1R(BASIS, VECTOR3, Basis, xform_inv, VECTOR3, "v", varray());
- ADDFUNC0R(BASIS, INT, Basis, get_orthogonal_index, varray());
- ADDFUNC2R(BASIS, BASIS, Basis, slerp, BASIS, "b", FLOAT, "t", varray());
- ADDFUNC2R(BASIS, BOOL, Basis, is_equal_approx, BASIS, "b", FLOAT, "epsilon", varray(CMP_EPSILON)); // TODO: Replace in 4.0, see other TODO.
- ADDFUNC0R(BASIS, QUAT, Basis, get_rotation_quat, varray());
-
- ADDFUNC0R(TRANSFORM, TRANSFORM, Transform, inverse, varray());
- ADDFUNC0R(TRANSFORM, TRANSFORM, Transform, affine_inverse, varray());
- ADDFUNC0R(TRANSFORM, TRANSFORM, Transform, orthonormalized, varray());
- ADDFUNC2R(TRANSFORM, TRANSFORM, Transform, rotated, VECTOR3, "axis", FLOAT, "phi", varray());
- ADDFUNC1R(TRANSFORM, TRANSFORM, Transform, scaled, VECTOR3, "scale", varray());
- ADDFUNC1R(TRANSFORM, TRANSFORM, Transform, translated, VECTOR3, "offset", varray());
- ADDFUNC2R(TRANSFORM, TRANSFORM, Transform, looking_at, VECTOR3, "target", VECTOR3, "up", varray());
- ADDFUNC2R(TRANSFORM, TRANSFORM, Transform, interpolate_with, TRANSFORM, "transform", FLOAT, "weight", varray());
- ADDFUNC1R(TRANSFORM, BOOL, Transform, is_equal_approx, TRANSFORM, "transform", varray());
- ADDFUNC1R(TRANSFORM, NIL, Transform, xform, NIL, "v", varray());
- ADDFUNC1R(TRANSFORM, NIL, Transform, xform_inv, NIL, "v", varray());
-
- /* REGISTER CONSTRUCTORS */
-
- _VariantCall::add_constructor(_VariantCall::Vector2_init1, Variant::VECTOR2, "x", Variant::FLOAT, "y", Variant::FLOAT);
- _VariantCall::add_constructor(_VariantCall::Vector2i_init1, Variant::VECTOR2I, "x", Variant::INT, "y", Variant::INT);
-
- _VariantCall::add_constructor(_VariantCall::Rect2_init1, Variant::RECT2, "position", Variant::VECTOR2, "size", Variant::VECTOR2);
- _VariantCall::add_constructor(_VariantCall::Rect2_init2, Variant::RECT2, "x", Variant::FLOAT, "y", Variant::FLOAT, "width", Variant::FLOAT, "height", Variant::FLOAT);
-
- _VariantCall::add_constructor(_VariantCall::Rect2i_init1, Variant::RECT2I, "position", Variant::VECTOR2, "size", Variant::VECTOR2);
- _VariantCall::add_constructor(_VariantCall::Rect2i_init2, Variant::RECT2I, "x", Variant::INT, "y", Variant::INT, "width", Variant::INT, "height", Variant::INT);
-
- _VariantCall::add_constructor(_VariantCall::Transform2D_init2, Variant::TRANSFORM2D, "rotation", Variant::FLOAT, "position", Variant::VECTOR2);
- _VariantCall::add_constructor(_VariantCall::Transform2D_init3, Variant::TRANSFORM2D, "x_axis", Variant::VECTOR2, "y_axis", Variant::VECTOR2, "origin", Variant::VECTOR2);
-
- _VariantCall::add_constructor(_VariantCall::Vector3_init1, Variant::VECTOR3, "x", Variant::FLOAT, "y", Variant::FLOAT, "z", Variant::FLOAT);
- _VariantCall::add_constructor(_VariantCall::Vector3i_init1, Variant::VECTOR3I, "x", Variant::INT, "y", Variant::INT, "z", Variant::INT);
-
- _VariantCall::add_constructor(_VariantCall::Plane_init1, Variant::PLANE, "a", Variant::FLOAT, "b", Variant::FLOAT, "c", Variant::FLOAT, "d", Variant::FLOAT);
- _VariantCall::add_constructor(_VariantCall::Plane_init2, Variant::PLANE, "v1", Variant::VECTOR3, "v2", Variant::VECTOR3, "v3", Variant::VECTOR3);
- _VariantCall::add_constructor(_VariantCall::Plane_init3, Variant::PLANE, "normal", Variant::VECTOR3, "d", Variant::FLOAT);
-
- _VariantCall::add_constructor(_VariantCall::Quat_init1, Variant::QUAT, "x", Variant::FLOAT, "y", Variant::FLOAT, "z", Variant::FLOAT, "w", Variant::FLOAT);
- _VariantCall::add_constructor(_VariantCall::Quat_init2, Variant::QUAT, "axis", Variant::VECTOR3, "angle", Variant::FLOAT);
- _VariantCall::add_constructor(_VariantCall::Quat_init3, Variant::QUAT, "euler", Variant::VECTOR3);
-
- _VariantCall::add_constructor(_VariantCall::Color_init1, Variant::COLOR, "r", Variant::FLOAT, "g", Variant::FLOAT, "b", Variant::FLOAT, "a", Variant::FLOAT);
- _VariantCall::add_constructor(_VariantCall::Color_init2, Variant::COLOR, "r", Variant::FLOAT, "g", Variant::FLOAT, "b", Variant::FLOAT);
- // init3 and init4 are the constructors for HTML hex strings and integers respectively which don't need binding here, so we skip to init5.
- _VariantCall::add_constructor(_VariantCall::Color_init5, Variant::COLOR, "c", Variant::COLOR, "a", Variant::FLOAT);
-
- _VariantCall::add_constructor(_VariantCall::AABB_init1, Variant::AABB, "position", Variant::VECTOR3, "size", Variant::VECTOR3);
-
- _VariantCall::add_constructor(_VariantCall::Basis_init1, Variant::BASIS, "x_axis", Variant::VECTOR3, "y_axis", Variant::VECTOR3, "z_axis", Variant::VECTOR3);
- _VariantCall::add_constructor(_VariantCall::Basis_init2, Variant::BASIS, "axis", Variant::VECTOR3, "phi", Variant::FLOAT);
-
- _VariantCall::add_constructor(_VariantCall::Transform_init1, Variant::TRANSFORM, "x_axis", Variant::VECTOR3, "y_axis", Variant::VECTOR3, "z_axis", Variant::VECTOR3, "origin", Variant::VECTOR3);
- _VariantCall::add_constructor(_VariantCall::Transform_init2, Variant::TRANSFORM, "basis", Variant::BASIS, "origin", Variant::VECTOR3);
-
- _VariantCall::add_constructor(_VariantCall::Callable_init2, Variant::CALLABLE, "object", Variant::OBJECT, "method_name", Variant::STRING_NAME);
- _VariantCall::add_constructor(_VariantCall::Signal_init2, Variant::SIGNAL, "object", Variant::OBJECT, "signal_name", Variant::STRING_NAME);
-
- /* REGISTER CONSTANTS */
-
- _populate_named_colors();
- for (Map<String, Color>::Element *color = _named_colors.front(); color; color = color->next()) {
- _VariantCall::add_variant_constant(Variant::COLOR, color->key(), color->value());
- }
-
- _VariantCall::add_constant(Variant::VECTOR3, "AXIS_X", Vector3::AXIS_X);
- _VariantCall::add_constant(Variant::VECTOR3, "AXIS_Y", Vector3::AXIS_Y);
- _VariantCall::add_constant(Variant::VECTOR3, "AXIS_Z", Vector3::AXIS_Z);
-
- _VariantCall::add_variant_constant(Variant::VECTOR3, "ZERO", Vector3(0, 0, 0));
- _VariantCall::add_variant_constant(Variant::VECTOR3, "ONE", Vector3(1, 1, 1));
- _VariantCall::add_variant_constant(Variant::VECTOR3, "INF", Vector3(Math_INF, Math_INF, Math_INF));
- _VariantCall::add_variant_constant(Variant::VECTOR3, "LEFT", Vector3(-1, 0, 0));
- _VariantCall::add_variant_constant(Variant::VECTOR3, "RIGHT", Vector3(1, 0, 0));
- _VariantCall::add_variant_constant(Variant::VECTOR3, "UP", Vector3(0, 1, 0));
- _VariantCall::add_variant_constant(Variant::VECTOR3, "DOWN", Vector3(0, -1, 0));
- _VariantCall::add_variant_constant(Variant::VECTOR3, "FORWARD", Vector3(0, 0, -1));
- _VariantCall::add_variant_constant(Variant::VECTOR3, "BACK", Vector3(0, 0, 1));
-
- _VariantCall::add_constant(Variant::VECTOR3I, "AXIS_X", Vector3::AXIS_X);
- _VariantCall::add_constant(Variant::VECTOR3I, "AXIS_Y", Vector3::AXIS_Y);
- _VariantCall::add_constant(Variant::VECTOR3I, "AXIS_Z", Vector3::AXIS_Z);
-
- _VariantCall::add_variant_constant(Variant::VECTOR3I, "ZERO", Vector3i(0, 0, 0));
- _VariantCall::add_variant_constant(Variant::VECTOR3I, "ONE", Vector3i(1, 1, 1));
- _VariantCall::add_variant_constant(Variant::VECTOR3I, "LEFT", Vector3i(-1, 0, 0));
- _VariantCall::add_variant_constant(Variant::VECTOR3I, "RIGHT", Vector3i(1, 0, 0));
- _VariantCall::add_variant_constant(Variant::VECTOR3I, "UP", Vector3i(0, 1, 0));
- _VariantCall::add_variant_constant(Variant::VECTOR3I, "DOWN", Vector3i(0, -1, 0));
- _VariantCall::add_variant_constant(Variant::VECTOR3I, "FORWARD", Vector3i(0, 0, -1));
- _VariantCall::add_variant_constant(Variant::VECTOR3I, "BACK", Vector3i(0, 0, 1));
-
- _VariantCall::add_constant(Variant::VECTOR2, "AXIS_X", Vector2::AXIS_X);
- _VariantCall::add_constant(Variant::VECTOR2, "AXIS_Y", Vector2::AXIS_Y);
-
- _VariantCall::add_constant(Variant::VECTOR2I, "AXIS_X", Vector2::AXIS_X);
- _VariantCall::add_constant(Variant::VECTOR2I, "AXIS_Y", Vector2::AXIS_Y);
-
- _VariantCall::add_variant_constant(Variant::VECTOR2, "ZERO", Vector2(0, 0));
- _VariantCall::add_variant_constant(Variant::VECTOR2, "ONE", Vector2(1, 1));
- _VariantCall::add_variant_constant(Variant::VECTOR2, "INF", Vector2(Math_INF, Math_INF));
- _VariantCall::add_variant_constant(Variant::VECTOR2, "LEFT", Vector2(-1, 0));
- _VariantCall::add_variant_constant(Variant::VECTOR2, "RIGHT", Vector2(1, 0));
- _VariantCall::add_variant_constant(Variant::VECTOR2, "UP", Vector2(0, -1));
- _VariantCall::add_variant_constant(Variant::VECTOR2, "DOWN", Vector2(0, 1));
-
- _VariantCall::add_variant_constant(Variant::VECTOR2I, "ZERO", Vector2i(0, 0));
- _VariantCall::add_variant_constant(Variant::VECTOR2I, "ONE", Vector2i(1, 1));
- _VariantCall::add_variant_constant(Variant::VECTOR2I, "LEFT", Vector2i(-1, 0));
- _VariantCall::add_variant_constant(Variant::VECTOR2I, "RIGHT", Vector2i(1, 0));
- _VariantCall::add_variant_constant(Variant::VECTOR2I, "UP", Vector2i(0, -1));
- _VariantCall::add_variant_constant(Variant::VECTOR2I, "DOWN", Vector2i(0, 1));
-
- _VariantCall::add_variant_constant(Variant::TRANSFORM2D, "IDENTITY", Transform2D());
- _VariantCall::add_variant_constant(Variant::TRANSFORM2D, "FLIP_X", Transform2D(-1, 0, 0, 1, 0, 0));
- _VariantCall::add_variant_constant(Variant::TRANSFORM2D, "FLIP_Y", Transform2D(1, 0, 0, -1, 0, 0));
-
- Transform identity_transform = Transform();
- Transform flip_x_transform = Transform(-1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0);
- Transform flip_y_transform = Transform(1, 0, 0, 0, -1, 0, 0, 0, 1, 0, 0, 0);
- Transform flip_z_transform = Transform(1, 0, 0, 0, 1, 0, 0, 0, -1, 0, 0, 0);
- _VariantCall::add_variant_constant(Variant::TRANSFORM, "IDENTITY", identity_transform);
- _VariantCall::add_variant_constant(Variant::TRANSFORM, "FLIP_X", flip_x_transform);
- _VariantCall::add_variant_constant(Variant::TRANSFORM, "FLIP_Y", flip_y_transform);
- _VariantCall::add_variant_constant(Variant::TRANSFORM, "FLIP_Z", flip_z_transform);
-
- Basis identity_basis = Basis();
- Basis flip_x_basis = Basis(-1, 0, 0, 0, 1, 0, 0, 0, 1);
- Basis flip_y_basis = Basis(1, 0, 0, 0, -1, 0, 0, 0, 1);
- Basis flip_z_basis = Basis(1, 0, 0, 0, 1, 0, 0, 0, -1);
- _VariantCall::add_variant_constant(Variant::BASIS, "IDENTITY", identity_basis);
- _VariantCall::add_variant_constant(Variant::BASIS, "FLIP_X", flip_x_basis);
- _VariantCall::add_variant_constant(Variant::BASIS, "FLIP_Y", flip_y_basis);
- _VariantCall::add_variant_constant(Variant::BASIS, "FLIP_Z", flip_z_basis);
-
- _VariantCall::add_variant_constant(Variant::PLANE, "PLANE_YZ", Plane(Vector3(1, 0, 0), 0));
- _VariantCall::add_variant_constant(Variant::PLANE, "PLANE_XZ", Plane(Vector3(0, 1, 0), 0));
- _VariantCall::add_variant_constant(Variant::PLANE, "PLANE_XY", Plane(Vector3(0, 0, 1), 0));
-
- _VariantCall::add_variant_constant(Variant::QUAT, "IDENTITY", Quat(0, 0, 0, 1));
-}
-
-void unregister_variant_methods() {
- memdelete_arr(_VariantCall::type_funcs);
- memdelete_arr(_VariantCall::construct_funcs);
- memdelete_arr(_VariantCall::constant_data);
-}
diff --git a/core/variant_op.cpp b/core/variant_op.cpp
deleted file mode 100644
index 0c9a4a992a..0000000000
--- a/core/variant_op.cpp
+++ /dev/null
@@ -1,4549 +0,0 @@
-/*************************************************************************/
-/* variant_op.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* 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. */
-/*************************************************************************/
-
-#include "variant.h"
-
-#include "core/core_string_names.h"
-#include "core/debugger/engine_debugger.h"
-#include "core/object.h"
-
-#define CASE_TYPE_ALL(PREFIX, OP) \
- CASE_TYPE(PREFIX, OP, INT) \
- CASE_TYPE_ALL_BUT_INT(PREFIX, OP)
-
-#define CASE_TYPE_ALL_BUT_INT(PREFIX, OP) \
- CASE_TYPE(PREFIX, OP, NIL) \
- CASE_TYPE(PREFIX, OP, BOOL) \
- CASE_TYPE(PREFIX, OP, FLOAT) \
- CASE_TYPE(PREFIX, OP, STRING) \
- CASE_TYPE(PREFIX, OP, VECTOR2) \
- CASE_TYPE(PREFIX, OP, VECTOR2I) \
- CASE_TYPE(PREFIX, OP, RECT2) \
- CASE_TYPE(PREFIX, OP, RECT2I) \
- CASE_TYPE(PREFIX, OP, VECTOR3) \
- CASE_TYPE(PREFIX, OP, VECTOR3I) \
- CASE_TYPE(PREFIX, OP, TRANSFORM2D) \
- CASE_TYPE(PREFIX, OP, PLANE) \
- CASE_TYPE(PREFIX, OP, QUAT) \
- CASE_TYPE(PREFIX, OP, AABB) \
- CASE_TYPE(PREFIX, OP, BASIS) \
- CASE_TYPE(PREFIX, OP, TRANSFORM) \
- CASE_TYPE(PREFIX, OP, COLOR) \
- CASE_TYPE(PREFIX, OP, STRING_NAME) \
- CASE_TYPE(PREFIX, OP, NODE_PATH) \
- CASE_TYPE(PREFIX, OP, _RID) \
- CASE_TYPE(PREFIX, OP, OBJECT) \
- CASE_TYPE(PREFIX, OP, CALLABLE) \
- CASE_TYPE(PREFIX, OP, SIGNAL) \
- CASE_TYPE(PREFIX, OP, DICTIONARY) \
- CASE_TYPE(PREFIX, OP, ARRAY) \
- CASE_TYPE(PREFIX, OP, PACKED_BYTE_ARRAY) \
- CASE_TYPE(PREFIX, OP, PACKED_INT32_ARRAY) \
- CASE_TYPE(PREFIX, OP, PACKED_INT64_ARRAY) \
- CASE_TYPE(PREFIX, OP, PACKED_FLOAT32_ARRAY) \
- CASE_TYPE(PREFIX, OP, PACKED_FLOAT64_ARRAY) \
- CASE_TYPE(PREFIX, OP, PACKED_STRING_ARRAY) \
- CASE_TYPE(PREFIX, OP, PACKED_VECTOR2_ARRAY) \
- CASE_TYPE(PREFIX, OP, PACKED_VECTOR3_ARRAY) \
- CASE_TYPE(PREFIX, OP, PACKED_COLOR_ARRAY)
-
-#ifdef __GNUC__
-#define TYPE(PREFIX, OP, TYPE) &&PREFIX##_##OP##_##TYPE
-
-/* clang-format off */
-#define TYPES(PREFIX, OP) { \
- TYPE(PREFIX, OP, NIL), \
- TYPE(PREFIX, OP, BOOL), \
- TYPE(PREFIX, OP, INT), \
- TYPE(PREFIX, OP, FLOAT), \
- TYPE(PREFIX, OP, STRING), \
- TYPE(PREFIX, OP, VECTOR2), \
- TYPE(PREFIX, OP, VECTOR2I), \
- TYPE(PREFIX, OP, RECT2), \
- TYPE(PREFIX, OP, RECT2I), \
- TYPE(PREFIX, OP, VECTOR3), \
- TYPE(PREFIX, OP, VECTOR3I), \
- TYPE(PREFIX, OP, TRANSFORM2D), \
- TYPE(PREFIX, OP, PLANE), \
- TYPE(PREFIX, OP, QUAT), \
- TYPE(PREFIX, OP, AABB), \
- TYPE(PREFIX, OP, BASIS), \
- TYPE(PREFIX, OP, TRANSFORM), \
- TYPE(PREFIX, OP, COLOR), \
- TYPE(PREFIX, OP, STRING_NAME), \
- TYPE(PREFIX, OP, NODE_PATH), \
- TYPE(PREFIX, OP, _RID), \
- TYPE(PREFIX, OP, OBJECT), \
- TYPE(PREFIX, OP, CALLABLE), \
- TYPE(PREFIX, OP, SIGNAL), \
- TYPE(PREFIX, OP, DICTIONARY), \
- TYPE(PREFIX, OP, ARRAY), \
- TYPE(PREFIX, OP, PACKED_BYTE_ARRAY), \
- TYPE(PREFIX, OP, PACKED_INT32_ARRAY), \
- TYPE(PREFIX, OP, PACKED_INT64_ARRAY), \
- TYPE(PREFIX, OP, PACKED_FLOAT32_ARRAY), \
- TYPE(PREFIX, OP, PACKED_FLOAT64_ARRAY), \
- TYPE(PREFIX, OP, PACKED_STRING_ARRAY), \
- TYPE(PREFIX, OP, PACKED_VECTOR2_ARRAY), \
- TYPE(PREFIX, OP, PACKED_VECTOR3_ARRAY), \
- TYPE(PREFIX, OP, PACKED_COLOR_ARRAY), \
-}
-
-/* clang-format on */
-
-#define CASES(PREFIX) static const void *switch_table_##PREFIX[25][Variant::VARIANT_MAX] = { \
- TYPES(PREFIX, OP_EQUAL), \
- TYPES(PREFIX, OP_NOT_EQUAL), \
- TYPES(PREFIX, OP_LESS), \
- TYPES(PREFIX, OP_LESS_EQUAL), \
- TYPES(PREFIX, OP_GREATER), \
- TYPES(PREFIX, OP_GREATER_EQUAL), \
- TYPES(PREFIX, OP_ADD), \
- TYPES(PREFIX, OP_SUBTRACT), \
- TYPES(PREFIX, OP_MULTIPLY), \
- TYPES(PREFIX, OP_DIVIDE), \
- TYPES(PREFIX, OP_NEGATE), \
- TYPES(PREFIX, OP_POSITIVE), \
- TYPES(PREFIX, OP_MODULE), \
- TYPES(PREFIX, OP_STRING_CONCAT), \
- TYPES(PREFIX, OP_SHIFT_LEFT), \
- TYPES(PREFIX, OP_SHIFT_RIGHT), \
- TYPES(PREFIX, OP_BIT_AND), \
- TYPES(PREFIX, OP_BIT_OR), \
- TYPES(PREFIX, OP_BIT_XOR), \
- TYPES(PREFIX, OP_BIT_NEGATE), \
- TYPES(PREFIX, OP_AND), \
- TYPES(PREFIX, OP_OR), \
- TYPES(PREFIX, OP_XOR), \
- TYPES(PREFIX, OP_NOT), \
- TYPES(PREFIX, OP_IN), \
-}
-
-#define SWITCH(PREFIX, op, val) goto *switch_table_##PREFIX[op][val];
-#define SWITCH_OP(PREFIX, OP, val)
-#define CASE_TYPE(PREFIX, OP, TYPE) PREFIX##_##OP##_##TYPE:
-
-#else
-#define CASES(PREFIX)
-#define SWITCH(PREFIX, op, val) switch (op)
-#define SWITCH_OP(PREFIX, OP, val) \
- case OP: \
- switch (val)
-#define CASE_TYPE(PREFIX, OP, TYPE) case TYPE:
-#endif
-
-Variant::operator bool() const {
- return booleanize();
-}
-
-// We consider all uninitialized or empty types to be false based on the type's
-// zeroiness.
-bool Variant::booleanize() const {
- return !is_zero();
-}
-
-#define _RETURN(m_what) \
- { \
- r_ret = m_what; \
- return; \
- }
-
-#define _RETURN_FAIL \
- { \
- r_valid = false; \
- return; \
- }
-
-#define DEFAULT_OP_NUM(m_prefix, m_op_name, m_name, m_op, m_type) \
- CASE_TYPE(m_prefix, m_op_name, m_name) { \
- if (p_b.type == INT) \
- _RETURN(p_a._data.m_type m_op p_b._data._int); \
- if (p_b.type == FLOAT) \
- _RETURN(p_a._data.m_type m_op p_b._data._float); \
- \
- _RETURN_FAIL \
- }
-
-#define DEFAULT_OP_NUM_NULL(m_prefix, m_op_name, m_name, m_op, m_type) \
- CASE_TYPE(m_prefix, m_op_name, m_name) { \
- if (p_b.type == INT) \
- _RETURN(p_a._data.m_type m_op p_b._data._int); \
- if (p_b.type == FLOAT) \
- _RETURN(p_a._data.m_type m_op p_b._data._float); \
- if (p_b.type == NIL) \
- _RETURN(!(p_b.type m_op NIL)); \
- \
- _RETURN_FAIL \
- }
-
-#ifdef DEBUG_ENABLED
-#define DEFAULT_OP_NUM_DIV(m_prefix, m_op_name, m_name, m_type) \
- CASE_TYPE(m_prefix, m_op_name, m_name) { \
- if (p_b.type == INT) { \
- if (p_b._data._int == 0) { \
- r_valid = false; \
- _RETURN("Division By Zero"); \
- } \
- _RETURN(p_a._data.m_type / p_b._data._int); \
- } \
- if (p_b.type == FLOAT) { \
- if (p_b._data._float == 0) { \
- r_valid = false; \
- _RETURN("Division By Zero"); \
- } \
- _RETURN(p_a._data.m_type / p_b._data._float); \
- } \
- \
- _RETURN_FAIL \
- }
-#else
-#define DEFAULT_OP_NUM_DIV(m_prefix, m_op_name, m_name, m_type) \
- CASE_TYPE(m_prefix, m_op_name, m_name) { \
- if (p_b.type == INT) \
- _RETURN(p_a._data.m_type / p_b._data._int); \
- if (p_b.type == FLOAT) \
- _RETURN(p_a._data.m_type / p_b._data._float); \
- \
- _RETURN_FAIL \
- }
-#endif
-
-#define DEFAULT_OP_NUM_NEG(m_prefix, m_op_name, m_name, m_type) \
- CASE_TYPE(m_prefix, m_op_name, m_name) { \
- _RETURN(-p_a._data.m_type); \
- }
-
-#define DEFAULT_OP_NUM_POS(m_prefix, m_op_name, m_name, m_type) \
- CASE_TYPE(m_prefix, m_op_name, m_name) { \
- _RETURN(p_a._data.m_type); \
- }
-
-#define DEFAULT_OP_NUM_VEC(m_prefix, m_op_name, m_name, m_op, m_type) \
- CASE_TYPE(m_prefix, m_op_name, m_name) { \
- if (p_b.type == INT) \
- _RETURN(p_a._data.m_type m_op p_b._data._int); \
- if (p_b.type == FLOAT) \
- _RETURN(p_a._data.m_type m_op p_b._data._float); \
- if (p_b.type == VECTOR2) \
- _RETURN(p_a._data.m_type m_op *reinterpret_cast<const Vector2 *>(p_b._data._mem)); \
- if (p_b.type == VECTOR3) \
- _RETURN(p_a._data.m_type m_op *reinterpret_cast<const Vector3 *>(p_b._data._mem)); \
- if (p_b.type == VECTOR2I) \
- _RETURN(p_a._data.m_type m_op *reinterpret_cast<const Vector2 *>(p_b._data._mem)); \
- if (p_b.type == VECTOR3I) \
- _RETURN(p_a._data.m_type m_op *reinterpret_cast<const Vector3 *>(p_b._data._mem)); \
- \
- _RETURN_FAIL \
- }
-
-#define DEFAULT_OP_STR_REV(m_prefix, m_op_name, m_name, m_op, m_type) \
- CASE_TYPE(m_prefix, m_op_name, m_name) { \
- if (p_b.type == STRING) \
- _RETURN(*reinterpret_cast<const m_type *>(p_b._data._mem) m_op *reinterpret_cast<const String *>(p_a._data._mem)); \
- if (p_b.type == STRING_NAME) \
- _RETURN(*reinterpret_cast<const m_type *>(p_b._data._mem) m_op *reinterpret_cast<const StringName *>(p_a._data._mem)); \
- if (p_b.type == NODE_PATH) \
- _RETURN(*reinterpret_cast<const m_type *>(p_b._data._mem) m_op *reinterpret_cast<const NodePath *>(p_a._data._mem)); \
- \
- _RETURN_FAIL \
- }
-
-#define DEFAULT_OP_STR(m_prefix, m_op_name, m_name, m_op, m_type) \
- CASE_TYPE(m_prefix, m_op_name, m_name) { \
- if (p_b.type == STRING) \
- _RETURN(*reinterpret_cast<const m_type *>(p_a._data._mem) m_op *reinterpret_cast<const String *>(p_b._data._mem)); \
- if (p_b.type == STRING_NAME) \
- _RETURN(*reinterpret_cast<const m_type *>(p_a._data._mem) m_op *reinterpret_cast<const StringName *>(p_b._data._mem)); \
- if (p_b.type == NODE_PATH) \
- _RETURN(*reinterpret_cast<const m_type *>(p_a._data._mem) m_op *reinterpret_cast<const NodePath *>(p_b._data._mem)); \
- \
- _RETURN_FAIL \
- }
-
-#define DEFAULT_OP_STR_NULL(m_prefix, m_op_name, m_name, m_op, m_type) \
- CASE_TYPE(m_prefix, m_op_name, m_name) { \
- if (p_b.type == STRING) \
- _RETURN(*reinterpret_cast<const m_type *>(p_a._data._mem) m_op *reinterpret_cast<const String *>(p_b._data._mem)); \
- if (p_b.type == STRING_NAME) \
- _RETURN(*reinterpret_cast<const m_type *>(p_a._data._mem) m_op *reinterpret_cast<const StringName *>(p_b._data._mem)); \
- if (p_b.type == NODE_PATH) \
- _RETURN(*reinterpret_cast<const m_type *>(p_a._data._mem) m_op *reinterpret_cast<const NodePath *>(p_b._data._mem)); \
- if (p_b.type == NIL) \
- _RETURN(!(p_b.type m_op NIL)); \
- \
- _RETURN_FAIL \
- }
-
-#define DEFAULT_OP_STR_NULL_NP(m_prefix, m_op_name, m_name, m_op, m_type) \
- CASE_TYPE(m_prefix, m_op_name, m_name) { \
- if (p_b.type == STRING) \
- _RETURN(*reinterpret_cast<const m_type *>(p_a._data._mem) m_op *reinterpret_cast<const String *>(p_b._data._mem)); \
- if (p_b.type == NODE_PATH) \
- _RETURN(*reinterpret_cast<const m_type *>(p_a._data._mem) m_op *reinterpret_cast<const NodePath *>(p_b._data._mem)); \
- if (p_b.type == NIL) \
- _RETURN(!(p_b.type m_op NIL)); \
- \
- _RETURN_FAIL \
- }
-
-#define DEFAULT_OP_STR_NULL_SN(m_prefix, m_op_name, m_name, m_op, m_type) \
- CASE_TYPE(m_prefix, m_op_name, m_name) { \
- if (p_b.type == STRING) \
- _RETURN(*reinterpret_cast<const m_type *>(p_a._data._mem) m_op *reinterpret_cast<const String *>(p_b._data._mem)); \
- if (p_b.type == STRING_NAME) \
- _RETURN(*reinterpret_cast<const m_type *>(p_a._data._mem) m_op *reinterpret_cast<const StringName *>(p_b._data._mem)); \
- if (p_b.type == NIL) \
- _RETURN(!(p_b.type m_op NIL)); \
- \
- _RETURN_FAIL \
- }
-
-#define DEFAULT_OP_LOCALMEM_REV(m_prefix, m_op_name, m_name, m_op, m_type) \
- CASE_TYPE(m_prefix, m_op_name, m_name) { \
- if (p_b.type == m_name) \
- _RETURN(*reinterpret_cast<const m_type *>(p_b._data._mem) m_op *reinterpret_cast<const m_type *>(p_a._data._mem)); \
- \
- _RETURN_FAIL \
- }
-
-#define DEFAULT_OP_LOCALMEM(m_prefix, m_op_name, m_name, m_op, m_type) \
- CASE_TYPE(m_prefix, m_op_name, m_name) { \
- if (p_b.type == m_name) \
- _RETURN(*reinterpret_cast<const m_type *>(p_a._data._mem) m_op *reinterpret_cast<const m_type *>(p_b._data._mem)); \
- \
- _RETURN_FAIL \
- }
-
-#define DEFAULT_OP_LOCALMEM_NULL(m_prefix, m_op_name, m_name, m_op, m_type) \
- CASE_TYPE(m_prefix, m_op_name, m_name) { \
- if (p_b.type == m_name) \
- _RETURN(*reinterpret_cast<const m_type *>(p_a._data._mem) m_op *reinterpret_cast<const m_type *>(p_b._data._mem)); \
- if (p_b.type == NIL) \
- _RETURN(!(p_b.type m_op NIL)); \
- \
- _RETURN_FAIL \
- }
-
-#define DEFAULT_OP_LOCALMEM_NEG(m_prefix, m_op_name, m_name, m_type) \
- CASE_TYPE(m_prefix, m_op_name, m_name) { \
- _RETURN(-*reinterpret_cast<const m_type *>(p_a._data._mem)); \
- }
-
-#define DEFAULT_OP_LOCALMEM_POS(m_prefix, m_op_name, m_name, m_type) \
- CASE_TYPE(m_prefix, m_op_name, m_name) { \
- _RETURN(*reinterpret_cast<const m_type *>(p_a._data._mem)); \
- }
-
-#define DEFAULT_OP_LOCALMEM_NUM(m_prefix, m_op_name, m_name, m_op, m_type) \
- CASE_TYPE(m_prefix, m_op_name, m_name) { \
- if (p_b.type == m_name) \
- _RETURN(*reinterpret_cast<const m_type *>(p_a._data._mem) m_op *reinterpret_cast<const m_type *>(p_b._data._mem)); \
- if (p_b.type == INT) \
- _RETURN(*reinterpret_cast<const m_type *>(p_a._data._mem) m_op p_b._data._int); \
- if (p_b.type == FLOAT) \
- _RETURN(*reinterpret_cast<const m_type *>(p_a._data._mem) m_op p_b._data._float); \
- \
- _RETURN_FAIL \
- }
-
-#define DEFAULT_OP_PTR(m_op, m_name, m_sub) \
- CASE_TYPE(m_prefix, m_op_name, m_name) { \
- if (p_b.type == m_name) \
- _RETURN(p_a._data.m_sub m_op p_b._data.m_sub); \
- \
- _RETURN_FAIL \
- }
-
-#define DEFAULT_OP_PTRREF(m_prefix, m_op_name, m_name, m_op, m_sub) \
- CASE_TYPE(m_prefix, m_op_name, m_name) { \
- if (p_b.type == m_name) \
- _RETURN(*p_a._data.m_sub m_op *p_b._data.m_sub); \
- \
- _RETURN_FAIL \
- }
-
-#define DEFAULT_OP_PTRREF_NULL(m_prefix, m_op_name, m_name, m_op, m_sub) \
- CASE_TYPE(m_prefix, m_op_name, m_name) { \
- if (p_b.type == m_name) \
- _RETURN(*p_a._data.m_sub m_op *p_b._data.m_sub); \
- if (p_b.type == NIL) \
- _RETURN(!(p_b.type m_op NIL)); \
- \
- _RETURN_FAIL \
- }
-
-#define DEFAULT_OP_ARRAY_EQ(m_prefix, m_op_name, m_name, m_type) \
- CASE_TYPE(m_prefix, m_op_name, m_name) { \
- if (p_b.type == NIL) \
- _RETURN(false) \
- DEFAULT_OP_ARRAY_OP_BODY(m_prefix, m_op_name, m_name, m_type, !=, !=, true, false, false) \
- }
-
-#define DEFAULT_OP_ARRAY_NEQ(m_prefix, m_op_name, m_name, m_type) \
- CASE_TYPE(m_prefix, m_op_name, m_name) { \
- if (p_b.type == NIL) \
- _RETURN(true) \
- DEFAULT_OP_ARRAY_OP_BODY(m_prefix, m_op_name, m_name, m_type, !=, !=, false, true, true) \
- }
-
-#define DEFAULT_OP_ARRAY_LT(m_prefix, m_op_name, m_name, m_type) \
- DEFAULT_OP_ARRAY_OP(m_prefix, m_op_name, m_name, m_type, <, !=, false, a_len < array_b.size(), true)
-
-#define DEFAULT_OP_ARRAY_GT(m_prefix, m_op_name, m_name, m_type) \
- DEFAULT_OP_ARRAY_OP(m_prefix, m_op_name, m_name, m_type, >, !=, false, a_len < array_b.size(), true)
-
-#define DEFAULT_OP_ARRAY_OP(m_prefix, m_op_name, m_name, m_type, m_opa, m_opb, m_ret_def, m_ret_s, m_ret_f) \
- CASE_TYPE(m_prefix, m_op_name, m_name) { \
- DEFAULT_OP_ARRAY_OP_BODY(m_prefix, m_op_name, m_name, m_type, m_opa, m_opb, m_ret_def, m_ret_s, m_ret_f) \
- }
-
-#define DEFAULT_OP_ARRAY_OP_BODY(m_prefix, m_op_name, m_name, m_type, m_opa, m_opb, m_ret_def, m_ret_s, m_ret_f) \
- if (p_a.type != p_b.type) \
- _RETURN_FAIL \
- \
- const Vector<m_type> &array_a = PackedArrayRef<m_type>::get_array(p_a._data.packed_array); \
- const Vector<m_type> &array_b = PackedArrayRef<m_type>::get_array(p_b._data.packed_array); \
- \
- int a_len = array_a.size(); \
- if (a_len m_opa array_b.size()) { \
- _RETURN(m_ret_s); \
- } else { \
- const m_type *ra = array_a.ptr(); \
- const m_type *rb = array_b.ptr(); \
- \
- for (int i = 0; i < a_len; i++) { \
- if (ra[i] m_opb rb[i]) \
- _RETURN(m_ret_f); \
- } \
- \
- _RETURN(m_ret_def); \
- }
-
-#define DEFAULT_OP_ARRAY_ADD(m_prefix, m_op_name, m_name, m_type) \
- CASE_TYPE(m_prefix, m_op_name, m_name) { \
- if (p_a.type != p_b.type) \
- _RETURN_FAIL; \
- \
- const Vector<m_type> &array_a = PackedArrayRef<m_type>::get_array(p_a._data.packed_array); \
- const Vector<m_type> &array_b = PackedArrayRef<m_type>::get_array(p_b._data.packed_array); \
- Vector<m_type> sum = array_a; \
- sum.append_array(array_b); \
- _RETURN(sum); \
- }
-
-void Variant::evaluate(const Operator &p_op, const Variant &p_a,
- const Variant &p_b, Variant &r_ret, bool &r_valid) {
- CASES(math);
- r_valid = true;
-
- SWITCH(math, p_op, p_a.type) {
- SWITCH_OP(math, OP_EQUAL, p_a.type) {
- CASE_TYPE(math, OP_EQUAL, NIL) {
- if (p_b.type == NIL)
- _RETURN(true);
- if (p_b.type == OBJECT)
- _RETURN(p_b._get_obj().obj == nullptr);
-
- _RETURN(false);
- }
-
- CASE_TYPE(math, OP_EQUAL, BOOL) {
- if (p_b.type != BOOL) {
- if (p_b.type == NIL)
- _RETURN(false);
- _RETURN_FAIL;
- }
-
- _RETURN(p_a._data._bool == p_b._data._bool);
- }
-
- CASE_TYPE(math, OP_EQUAL, OBJECT) {
- if (p_b.type == OBJECT)
- _RETURN((p_a._get_obj().obj == p_b._get_obj().obj));
- if (p_b.type == NIL)
- _RETURN(p_a._get_obj().obj == nullptr);
-
- _RETURN_FAIL;
- }
-
- DEFAULT_OP_LOCALMEM_NULL(math, OP_EQUAL, CALLABLE, ==, Callable);
- DEFAULT_OP_LOCALMEM_NULL(math, OP_EQUAL, SIGNAL, ==, Signal);
-
- CASE_TYPE(math, OP_EQUAL, DICTIONARY) {
- if (p_b.type != DICTIONARY) {
- if (p_b.type == NIL)
- _RETURN(false);
- _RETURN_FAIL;
- }
-
- const Dictionary *arr_a = reinterpret_cast<const Dictionary *>(p_a._data._mem);
- const Dictionary *arr_b = reinterpret_cast<const Dictionary *>(p_b._data._mem);
-
- _RETURN(*arr_a == *arr_b);
- }
-
- CASE_TYPE(math, OP_EQUAL, ARRAY) {
- if (p_b.type != ARRAY) {
- if (p_b.type == NIL)
- _RETURN(false);
- _RETURN_FAIL;
- }
- const Array *arr_a = reinterpret_cast<const Array *>(p_a._data._mem);
- const Array *arr_b = reinterpret_cast<const Array *>(p_b._data._mem);
-
- int l = arr_a->size();
- if (arr_b->size() != l)
- _RETURN(false);
- for (int i = 0; i < l; i++) {
- if (!((*arr_a)[i] == (*arr_b)[i])) {
- _RETURN(false);
- }
- }
-
- _RETURN(true);
- }
-
- DEFAULT_OP_NUM_NULL(math, OP_EQUAL, INT, ==, _int);
- DEFAULT_OP_NUM_NULL(math, OP_EQUAL, FLOAT, ==, _float);
- DEFAULT_OP_STR_NULL(math, OP_EQUAL, STRING, ==, String);
- DEFAULT_OP_LOCALMEM_NULL(math, OP_EQUAL, VECTOR2, ==, Vector2);
- DEFAULT_OP_LOCALMEM_NULL(math, OP_EQUAL, VECTOR2I, ==, Vector2i);
- DEFAULT_OP_LOCALMEM_NULL(math, OP_EQUAL, RECT2, ==, Rect2);
- DEFAULT_OP_LOCALMEM_NULL(math, OP_EQUAL, RECT2I, ==, Rect2i);
- DEFAULT_OP_PTRREF_NULL(math, OP_EQUAL, TRANSFORM2D, ==, _transform2d);
- DEFAULT_OP_LOCALMEM_NULL(math, OP_EQUAL, VECTOR3, ==, Vector3);
- DEFAULT_OP_LOCALMEM_NULL(math, OP_EQUAL, VECTOR3I, ==, Vector3i);
- DEFAULT_OP_LOCALMEM_NULL(math, OP_EQUAL, PLANE, ==, Plane);
- DEFAULT_OP_LOCALMEM_NULL(math, OP_EQUAL, QUAT, ==, Quat);
- DEFAULT_OP_PTRREF_NULL(math, OP_EQUAL, AABB, ==, _aabb);
- DEFAULT_OP_PTRREF_NULL(math, OP_EQUAL, BASIS, ==, _basis);
- DEFAULT_OP_PTRREF_NULL(math, OP_EQUAL, TRANSFORM, ==, _transform);
- DEFAULT_OP_LOCALMEM_NULL(math, OP_EQUAL, COLOR, ==, Color);
- DEFAULT_OP_STR_NULL_SN(math, OP_EQUAL, STRING_NAME, ==, StringName);
- DEFAULT_OP_STR_NULL_NP(math, OP_EQUAL, NODE_PATH, ==, NodePath);
- DEFAULT_OP_LOCALMEM_NULL(math, OP_EQUAL, _RID, ==, RID);
-
- DEFAULT_OP_ARRAY_EQ(math, OP_EQUAL, PACKED_BYTE_ARRAY, uint8_t);
- DEFAULT_OP_ARRAY_EQ(math, OP_EQUAL, PACKED_INT32_ARRAY, int32_t);
- DEFAULT_OP_ARRAY_EQ(math, OP_EQUAL, PACKED_INT64_ARRAY, int64_t);
- DEFAULT_OP_ARRAY_EQ(math, OP_EQUAL, PACKED_FLOAT32_ARRAY, float);
- DEFAULT_OP_ARRAY_EQ(math, OP_EQUAL, PACKED_FLOAT64_ARRAY, double);
- DEFAULT_OP_ARRAY_EQ(math, OP_EQUAL, PACKED_STRING_ARRAY, String);
- DEFAULT_OP_ARRAY_EQ(math, OP_EQUAL, PACKED_VECTOR2_ARRAY, Vector2);
- DEFAULT_OP_ARRAY_EQ(math, OP_EQUAL, PACKED_VECTOR3_ARRAY, Vector3);
- DEFAULT_OP_ARRAY_EQ(math, OP_EQUAL, PACKED_COLOR_ARRAY, Color);
- }
-
- SWITCH_OP(math, OP_NOT_EQUAL, p_a.type) {
- CASE_TYPE(math, OP_NOT_EQUAL, NIL) {
- if (p_b.type == NIL)
- _RETURN(false);
- if (p_b.type == OBJECT)
- _RETURN(p_b._get_obj().obj != nullptr);
-
- _RETURN(true);
- }
-
- CASE_TYPE(math, OP_NOT_EQUAL, BOOL) {
- if (p_b.type != BOOL) {
- if (p_b.type == NIL)
- _RETURN(true);
-
- _RETURN_FAIL;
- }
-
- _RETURN(p_a._data._bool != p_b._data._bool);
- }
-
- CASE_TYPE(math, OP_NOT_EQUAL, OBJECT) {
- if (p_b.type == OBJECT)
- _RETURN((p_a._get_obj().obj != p_b._get_obj().obj));
- if (p_b.type == NIL)
- _RETURN(p_a._get_obj().obj != nullptr);
-
- _RETURN_FAIL;
- }
-
- DEFAULT_OP_LOCALMEM_NULL(math, OP_NOT_EQUAL, CALLABLE, !=, Callable);
- DEFAULT_OP_LOCALMEM_NULL(math, OP_NOT_EQUAL, SIGNAL, !=, Signal);
-
- CASE_TYPE(math, OP_NOT_EQUAL, DICTIONARY) {
- if (p_b.type != DICTIONARY) {
- if (p_b.type == NIL)
- _RETURN(true);
- _RETURN_FAIL;
- }
-
- const Dictionary *arr_a = reinterpret_cast<const Dictionary *>(p_a._data._mem);
- const Dictionary *arr_b = reinterpret_cast<const Dictionary *>(p_b._data._mem);
-
- _RETURN(*arr_a != *arr_b);
- }
-
- CASE_TYPE(math, OP_NOT_EQUAL, ARRAY) {
- if (p_b.type != ARRAY) {
- if (p_b.type == NIL)
- _RETURN(true);
-
- _RETURN_FAIL;
- }
-
- const Array *arr_a = reinterpret_cast<const Array *>(p_a._data._mem);
- const Array *arr_b = reinterpret_cast<const Array *>(p_b._data._mem);
-
- int l = arr_a->size();
- if (arr_b->size() != l)
- _RETURN(true);
- for (int i = 0; i < l; i++) {
- if (((*arr_a)[i] != (*arr_b)[i])) {
- _RETURN(true);
- }
- }
-
- _RETURN(false);
- }
-
- DEFAULT_OP_NUM_NULL(math, OP_NOT_EQUAL, INT, !=, _int);
- DEFAULT_OP_NUM_NULL(math, OP_NOT_EQUAL, FLOAT, !=, _float);
- DEFAULT_OP_STR_NULL(math, OP_NOT_EQUAL, STRING, !=, String);
- DEFAULT_OP_LOCALMEM_NULL(math, OP_NOT_EQUAL, VECTOR2, !=, Vector2);
- DEFAULT_OP_LOCALMEM_NULL(math, OP_NOT_EQUAL, VECTOR2I, !=, Vector2i);
- DEFAULT_OP_LOCALMEM_NULL(math, OP_NOT_EQUAL, RECT2, !=, Rect2);
- DEFAULT_OP_LOCALMEM_NULL(math, OP_NOT_EQUAL, RECT2I, !=, Rect2i);
- DEFAULT_OP_PTRREF_NULL(math, OP_NOT_EQUAL, TRANSFORM2D, !=, _transform2d);
- DEFAULT_OP_LOCALMEM_NULL(math, OP_NOT_EQUAL, VECTOR3, !=, Vector3);
- DEFAULT_OP_LOCALMEM_NULL(math, OP_NOT_EQUAL, VECTOR3I, !=, Vector3i);
- DEFAULT_OP_LOCALMEM_NULL(math, OP_NOT_EQUAL, PLANE, !=, Plane);
- DEFAULT_OP_LOCALMEM_NULL(math, OP_NOT_EQUAL, QUAT, !=, Quat);
- DEFAULT_OP_PTRREF_NULL(math, OP_NOT_EQUAL, AABB, !=, _aabb);
- DEFAULT_OP_PTRREF_NULL(math, OP_NOT_EQUAL, BASIS, !=, _basis);
- DEFAULT_OP_PTRREF_NULL(math, OP_NOT_EQUAL, TRANSFORM, !=, _transform);
- DEFAULT_OP_LOCALMEM_NULL(math, OP_NOT_EQUAL, COLOR, !=, Color);
- DEFAULT_OP_STR_NULL_SN(math, OP_NOT_EQUAL, STRING_NAME, !=, StringName);
- DEFAULT_OP_STR_NULL_NP(math, OP_NOT_EQUAL, NODE_PATH, !=, NodePath);
- DEFAULT_OP_LOCALMEM_NULL(math, OP_NOT_EQUAL, _RID, !=, RID);
-
- DEFAULT_OP_ARRAY_NEQ(math, OP_NOT_EQUAL, PACKED_BYTE_ARRAY, uint8_t);
- DEFAULT_OP_ARRAY_NEQ(math, OP_NOT_EQUAL, PACKED_INT32_ARRAY, int32_t);
- DEFAULT_OP_ARRAY_NEQ(math, OP_NOT_EQUAL, PACKED_INT64_ARRAY, int64_t);
- DEFAULT_OP_ARRAY_NEQ(math, OP_NOT_EQUAL, PACKED_FLOAT32_ARRAY, float);
- DEFAULT_OP_ARRAY_NEQ(math, OP_NOT_EQUAL, PACKED_FLOAT64_ARRAY, double);
- DEFAULT_OP_ARRAY_NEQ(math, OP_NOT_EQUAL, PACKED_STRING_ARRAY, String);
- DEFAULT_OP_ARRAY_NEQ(math, OP_NOT_EQUAL, PACKED_VECTOR2_ARRAY, Vector2);
- DEFAULT_OP_ARRAY_NEQ(math, OP_NOT_EQUAL, PACKED_VECTOR3_ARRAY, Vector3);
- DEFAULT_OP_ARRAY_NEQ(math, OP_NOT_EQUAL, PACKED_COLOR_ARRAY, Color);
- }
-
- SWITCH_OP(math, OP_LESS, p_a.type) {
- CASE_TYPE(math, OP_LESS, BOOL) {
- if (p_b.type != BOOL)
- _RETURN_FAIL;
-
- if (p_a._data._bool == p_b._data._bool)
- _RETURN(false);
-
- if (p_a._data._bool && !p_b._data._bool)
- _RETURN(false);
-
- _RETURN(true);
- }
-
- CASE_TYPE(math, OP_LESS, OBJECT) {
- if (p_b.type != OBJECT)
- _RETURN_FAIL;
- _RETURN((p_a._get_obj().obj < p_b._get_obj().obj));
- }
-
- DEFAULT_OP_LOCALMEM_NULL(math, OP_LESS, CALLABLE, <, Callable);
- DEFAULT_OP_LOCALMEM_NULL(math, OP_LESS, SIGNAL, <, Signal);
-
- CASE_TYPE(math, OP_LESS, ARRAY) {
- if (p_b.type != ARRAY)
- _RETURN_FAIL;
-
- const Array *arr_a = reinterpret_cast<const Array *>(p_a._data._mem);
- const Array *arr_b = reinterpret_cast<const Array *>(p_b._data._mem);
-
- int l = arr_a->size();
- if (arr_b->size() < l)
- _RETURN(false);
- for (int i = 0; i < l; i++) {
- if (!((*arr_a)[i] < (*arr_b)[i])) {
- _RETURN(true);
- }
- }
-
- _RETURN(false);
- }
-
- DEFAULT_OP_NUM(math, OP_LESS, INT, <, _int);
- DEFAULT_OP_NUM(math, OP_LESS, FLOAT, <, _float);
- DEFAULT_OP_STR(math, OP_LESS, STRING, <, String);
- DEFAULT_OP_LOCALMEM(math, OP_LESS, VECTOR2, <, Vector2);
- DEFAULT_OP_LOCALMEM(math, OP_LESS, VECTOR2I, <, Vector2i);
- DEFAULT_OP_LOCALMEM(math, OP_LESS, VECTOR3, <, Vector3);
- DEFAULT_OP_LOCALMEM(math, OP_LESS, VECTOR3I, <, Vector3i);
- DEFAULT_OP_LOCALMEM(math, OP_LESS, _RID, <, RID);
- DEFAULT_OP_ARRAY_LT(math, OP_LESS, PACKED_BYTE_ARRAY, uint8_t);
- DEFAULT_OP_ARRAY_LT(math, OP_LESS, PACKED_INT32_ARRAY, int32_t);
- DEFAULT_OP_ARRAY_LT(math, OP_LESS, PACKED_INT64_ARRAY, int64_t);
- DEFAULT_OP_ARRAY_LT(math, OP_LESS, PACKED_FLOAT32_ARRAY, float);
- DEFAULT_OP_ARRAY_LT(math, OP_LESS, PACKED_FLOAT64_ARRAY, double);
- DEFAULT_OP_ARRAY_LT(math, OP_LESS, PACKED_STRING_ARRAY, String);
- DEFAULT_OP_ARRAY_LT(math, OP_LESS, PACKED_VECTOR2_ARRAY, Vector3);
- DEFAULT_OP_ARRAY_LT(math, OP_LESS, PACKED_VECTOR3_ARRAY, Vector3);
- DEFAULT_OP_ARRAY_LT(math, OP_LESS, PACKED_COLOR_ARRAY, Color);
-
- CASE_TYPE(math, OP_LESS, NIL)
- CASE_TYPE(math, OP_LESS, RECT2)
- CASE_TYPE(math, OP_LESS, RECT2I)
- CASE_TYPE(math, OP_LESS, TRANSFORM2D)
- CASE_TYPE(math, OP_LESS, PLANE)
- CASE_TYPE(math, OP_LESS, QUAT)
- CASE_TYPE(math, OP_LESS, AABB)
- CASE_TYPE(math, OP_LESS, BASIS)
- CASE_TYPE(math, OP_LESS, TRANSFORM)
- CASE_TYPE(math, OP_LESS, COLOR)
- CASE_TYPE(math, OP_LESS, STRING_NAME)
- CASE_TYPE(math, OP_LESS, NODE_PATH)
- CASE_TYPE(math, OP_LESS, DICTIONARY)
- _RETURN_FAIL;
- }
-
- SWITCH_OP(math, OP_LESS_EQUAL, p_a.type) {
- CASE_TYPE(math, OP_LESS_EQUAL, OBJECT) {
- if (p_b.type != OBJECT)
- _RETURN_FAIL;
- _RETURN((p_a._get_obj().obj <= p_b._get_obj().obj));
- }
-
- DEFAULT_OP_NUM(math, OP_LESS_EQUAL, INT, <=, _int);
- DEFAULT_OP_NUM(math, OP_LESS_EQUAL, FLOAT, <=, _float);
- DEFAULT_OP_STR(math, OP_LESS_EQUAL, STRING, <=, String);
- DEFAULT_OP_LOCALMEM(math, OP_LESS_EQUAL, VECTOR2, <=, Vector2);
- DEFAULT_OP_LOCALMEM(math, OP_LESS_EQUAL, VECTOR2I, <=, Vector2i);
- DEFAULT_OP_LOCALMEM(math, OP_LESS_EQUAL, VECTOR3, <=, Vector3);
- DEFAULT_OP_LOCALMEM(math, OP_LESS_EQUAL, VECTOR3I, <=, Vector3i);
- DEFAULT_OP_LOCALMEM(math, OP_LESS_EQUAL, _RID, <=, RID);
-
- CASE_TYPE(math, OP_LESS_EQUAL, NIL)
- CASE_TYPE(math, OP_LESS_EQUAL, BOOL)
- CASE_TYPE(math, OP_LESS_EQUAL, RECT2)
- CASE_TYPE(math, OP_LESS_EQUAL, RECT2I)
- CASE_TYPE(math, OP_LESS_EQUAL, TRANSFORM2D)
- CASE_TYPE(math, OP_LESS_EQUAL, PLANE)
- CASE_TYPE(math, OP_LESS_EQUAL, QUAT)
- CASE_TYPE(math, OP_LESS_EQUAL, AABB)
- CASE_TYPE(math, OP_LESS_EQUAL, BASIS)
- CASE_TYPE(math, OP_LESS_EQUAL, TRANSFORM)
- CASE_TYPE(math, OP_LESS_EQUAL, COLOR)
- CASE_TYPE(math, OP_LESS_EQUAL, STRING_NAME)
- CASE_TYPE(math, OP_LESS_EQUAL, NODE_PATH)
- CASE_TYPE(math, OP_LESS_EQUAL, CALLABLE)
- CASE_TYPE(math, OP_LESS_EQUAL, SIGNAL)
-
- CASE_TYPE(math, OP_LESS_EQUAL, DICTIONARY)
- CASE_TYPE(math, OP_LESS_EQUAL, ARRAY)
- CASE_TYPE(math, OP_LESS_EQUAL, PACKED_BYTE_ARRAY);
- CASE_TYPE(math, OP_LESS_EQUAL, PACKED_INT32_ARRAY);
- CASE_TYPE(math, OP_LESS_EQUAL, PACKED_INT64_ARRAY);
- CASE_TYPE(math, OP_LESS_EQUAL, PACKED_FLOAT32_ARRAY);
- CASE_TYPE(math, OP_LESS_EQUAL, PACKED_FLOAT64_ARRAY);
- CASE_TYPE(math, OP_LESS_EQUAL, PACKED_STRING_ARRAY);
- CASE_TYPE(math, OP_LESS_EQUAL, PACKED_VECTOR2_ARRAY);
- CASE_TYPE(math, OP_LESS_EQUAL, PACKED_VECTOR3_ARRAY);
- CASE_TYPE(math, OP_LESS_EQUAL, PACKED_COLOR_ARRAY);
- _RETURN_FAIL;
- }
-
- SWITCH_OP(math, OP_GREATER, p_a.type) {
- CASE_TYPE(math, OP_GREATER, BOOL) {
- if (p_b.type != BOOL)
- _RETURN_FAIL;
-
- if (p_a._data._bool == p_b._data._bool)
- _RETURN(false);
-
- if (!p_a._data._bool && p_b._data._bool)
- _RETURN(false);
-
- _RETURN(true);
- }
-
- CASE_TYPE(math, OP_GREATER, OBJECT) {
- if (p_b.type != OBJECT)
- _RETURN_FAIL;
- _RETURN((p_a._get_obj().obj > p_b._get_obj().obj));
- }
-
- CASE_TYPE(math, OP_GREATER, ARRAY) {
- if (p_b.type != ARRAY)
- _RETURN_FAIL;
-
- const Array *arr_a = reinterpret_cast<const Array *>(p_a._data._mem);
- const Array *arr_b = reinterpret_cast<const Array *>(p_b._data._mem);
-
- int l = arr_a->size();
- if (arr_b->size() > l)
- _RETURN(false);
- for (int i = 0; i < l; i++) {
- if (((*arr_a)[i] < (*arr_b)[i])) {
- _RETURN(false);
- }
- }
-
- _RETURN(true);
- }
-
- DEFAULT_OP_NUM(math, OP_GREATER, INT, >, _int);
- DEFAULT_OP_NUM(math, OP_GREATER, FLOAT, >, _float);
- DEFAULT_OP_STR_REV(math, OP_GREATER, STRING, <, String);
- DEFAULT_OP_LOCALMEM_REV(math, OP_GREATER, VECTOR2, <, Vector2);
- DEFAULT_OP_LOCALMEM_REV(math, OP_GREATER, VECTOR2I, <, Vector2i);
- DEFAULT_OP_LOCALMEM_REV(math, OP_GREATER, VECTOR3, <, Vector3);
- DEFAULT_OP_LOCALMEM_REV(math, OP_GREATER, VECTOR3I, <, Vector3i);
- DEFAULT_OP_LOCALMEM_REV(math, OP_GREATER, _RID, <, RID);
- DEFAULT_OP_ARRAY_GT(math, OP_GREATER, PACKED_BYTE_ARRAY, uint8_t);
- DEFAULT_OP_ARRAY_GT(math, OP_GREATER, PACKED_INT32_ARRAY, int32_t);
- DEFAULT_OP_ARRAY_GT(math, OP_GREATER, PACKED_INT64_ARRAY, int64_t);
- DEFAULT_OP_ARRAY_GT(math, OP_GREATER, PACKED_FLOAT32_ARRAY, float);
- DEFAULT_OP_ARRAY_GT(math, OP_GREATER, PACKED_FLOAT64_ARRAY, double);
- DEFAULT_OP_ARRAY_GT(math, OP_GREATER, PACKED_STRING_ARRAY, String);
- DEFAULT_OP_ARRAY_GT(math, OP_GREATER, PACKED_VECTOR2_ARRAY, Vector3);
- DEFAULT_OP_ARRAY_GT(math, OP_GREATER, PACKED_VECTOR3_ARRAY, Vector3);
- DEFAULT_OP_ARRAY_GT(math, OP_GREATER, PACKED_COLOR_ARRAY, Color);
-
- CASE_TYPE(math, OP_GREATER, NIL)
- CASE_TYPE(math, OP_GREATER, RECT2)
- CASE_TYPE(math, OP_GREATER, RECT2I)
- CASE_TYPE(math, OP_GREATER, TRANSFORM2D)
- CASE_TYPE(math, OP_GREATER, PLANE)
- CASE_TYPE(math, OP_GREATER, QUAT)
- CASE_TYPE(math, OP_GREATER, AABB)
- CASE_TYPE(math, OP_GREATER, BASIS)
- CASE_TYPE(math, OP_GREATER, TRANSFORM)
- CASE_TYPE(math, OP_GREATER, COLOR)
- CASE_TYPE(math, OP_GREATER, STRING_NAME)
- CASE_TYPE(math, OP_GREATER, NODE_PATH)
- CASE_TYPE(math, OP_GREATER, DICTIONARY)
- CASE_TYPE(math, OP_GREATER, CALLABLE)
- CASE_TYPE(math, OP_GREATER, SIGNAL)
-
- _RETURN_FAIL;
- }
-
- SWITCH_OP(math, OP_GREATER_EQUAL, p_a.type) {
- CASE_TYPE(math, OP_GREATER_EQUAL, OBJECT) {
- if (p_b.type != OBJECT)
- _RETURN_FAIL;
- _RETURN((p_a._get_obj().obj >= p_b._get_obj().obj));
- }
-
- DEFAULT_OP_NUM(math, OP_GREATER_EQUAL, INT, >=, _int);
- DEFAULT_OP_NUM(math, OP_GREATER_EQUAL, FLOAT, >=, _float);
- DEFAULT_OP_STR_REV(math, OP_GREATER_EQUAL, STRING, <=, String);
- DEFAULT_OP_LOCALMEM_REV(math, OP_GREATER_EQUAL, VECTOR2, <=, Vector2);
- DEFAULT_OP_LOCALMEM_REV(math, OP_GREATER_EQUAL, VECTOR2I, <=, Vector2i);
- DEFAULT_OP_LOCALMEM_REV(math, OP_GREATER_EQUAL, VECTOR3, <=, Vector3);
- DEFAULT_OP_LOCALMEM_REV(math, OP_GREATER_EQUAL, VECTOR3I, <=, Vector3i);
- DEFAULT_OP_LOCALMEM_REV(math, OP_GREATER_EQUAL, _RID, <=, RID);
-
- CASE_TYPE(math, OP_GREATER_EQUAL, NIL)
- CASE_TYPE(math, OP_GREATER_EQUAL, BOOL)
- CASE_TYPE(math, OP_GREATER_EQUAL, RECT2)
- CASE_TYPE(math, OP_GREATER_EQUAL, RECT2I)
- CASE_TYPE(math, OP_GREATER_EQUAL, TRANSFORM2D)
- CASE_TYPE(math, OP_GREATER_EQUAL, PLANE)
- CASE_TYPE(math, OP_GREATER_EQUAL, QUAT)
- CASE_TYPE(math, OP_GREATER_EQUAL, AABB)
- CASE_TYPE(math, OP_GREATER_EQUAL, BASIS)
- CASE_TYPE(math, OP_GREATER_EQUAL, TRANSFORM)
- CASE_TYPE(math, OP_GREATER_EQUAL, COLOR)
- CASE_TYPE(math, OP_GREATER_EQUAL, STRING_NAME)
- CASE_TYPE(math, OP_GREATER_EQUAL, NODE_PATH)
- CASE_TYPE(math, OP_GREATER_EQUAL, CALLABLE)
- CASE_TYPE(math, OP_GREATER_EQUAL, SIGNAL)
-
- CASE_TYPE(math, OP_GREATER_EQUAL, DICTIONARY)
- CASE_TYPE(math, OP_GREATER_EQUAL, ARRAY)
- CASE_TYPE(math, OP_GREATER_EQUAL, PACKED_BYTE_ARRAY);
- CASE_TYPE(math, OP_GREATER_EQUAL, PACKED_INT32_ARRAY);
- CASE_TYPE(math, OP_GREATER_EQUAL, PACKED_INT64_ARRAY);
- CASE_TYPE(math, OP_GREATER_EQUAL, PACKED_FLOAT32_ARRAY);
- CASE_TYPE(math, OP_GREATER_EQUAL, PACKED_FLOAT64_ARRAY);
- CASE_TYPE(math, OP_GREATER_EQUAL, PACKED_STRING_ARRAY);
- CASE_TYPE(math, OP_GREATER_EQUAL, PACKED_VECTOR2_ARRAY);
- CASE_TYPE(math, OP_GREATER_EQUAL, PACKED_VECTOR3_ARRAY);
- CASE_TYPE(math, OP_GREATER_EQUAL, PACKED_COLOR_ARRAY);
- _RETURN_FAIL;
- }
-
- SWITCH_OP(math, OP_ADD, p_a.type) {
- CASE_TYPE(math, OP_ADD, ARRAY) {
- if (p_a.type != p_b.type)
- _RETURN_FAIL;
-
- const Array &array_a = *reinterpret_cast<const Array *>(p_a._data._mem);
- const Array &array_b = *reinterpret_cast<const Array *>(p_b._data._mem);
- Array sum;
- int asize = array_a.size();
- int bsize = array_b.size();
- sum.resize(asize + bsize);
- for (int i = 0; i < asize; i++) {
- sum[i] = array_a[i];
- }
- for (int i = 0; i < bsize; i++) {
- sum[i + asize] = array_b[i];
- }
- _RETURN(sum);
- }
-
- DEFAULT_OP_NUM(math, OP_ADD, INT, +, _int);
- DEFAULT_OP_NUM(math, OP_ADD, FLOAT, +, _float);
- DEFAULT_OP_STR(math, OP_ADD, STRING, +, String);
- DEFAULT_OP_LOCALMEM(math, OP_ADD, VECTOR2, +, Vector2);
- DEFAULT_OP_LOCALMEM(math, OP_ADD, VECTOR2I, +, Vector2i);
- DEFAULT_OP_LOCALMEM(math, OP_ADD, VECTOR3, +, Vector3);
- DEFAULT_OP_LOCALMEM(math, OP_ADD, VECTOR3I, +, Vector3i);
- DEFAULT_OP_LOCALMEM(math, OP_ADD, QUAT, +, Quat);
- DEFAULT_OP_LOCALMEM(math, OP_ADD, COLOR, +, Color);
-
- DEFAULT_OP_ARRAY_ADD(math, OP_ADD, PACKED_BYTE_ARRAY, uint8_t);
- DEFAULT_OP_ARRAY_ADD(math, OP_ADD, PACKED_INT32_ARRAY, int32_t);
- DEFAULT_OP_ARRAY_ADD(math, OP_ADD, PACKED_INT64_ARRAY, int64_t);
- DEFAULT_OP_ARRAY_ADD(math, OP_ADD, PACKED_FLOAT32_ARRAY, float);
- DEFAULT_OP_ARRAY_ADD(math, OP_ADD, PACKED_FLOAT64_ARRAY, double);
- DEFAULT_OP_ARRAY_ADD(math, OP_ADD, PACKED_STRING_ARRAY, String);
- DEFAULT_OP_ARRAY_ADD(math, OP_ADD, PACKED_VECTOR2_ARRAY, Vector2);
- DEFAULT_OP_ARRAY_ADD(math, OP_ADD, PACKED_VECTOR3_ARRAY, Vector3);
- DEFAULT_OP_ARRAY_ADD(math, OP_ADD, PACKED_COLOR_ARRAY, Color);
-
- CASE_TYPE(math, OP_ADD, NIL)
- CASE_TYPE(math, OP_ADD, BOOL)
- CASE_TYPE(math, OP_ADD, RECT2)
- CASE_TYPE(math, OP_ADD, RECT2I)
- CASE_TYPE(math, OP_ADD, TRANSFORM2D)
- CASE_TYPE(math, OP_ADD, PLANE)
- CASE_TYPE(math, OP_ADD, AABB)
- CASE_TYPE(math, OP_ADD, BASIS)
- CASE_TYPE(math, OP_ADD, TRANSFORM)
- CASE_TYPE(math, OP_ADD, STRING_NAME)
- CASE_TYPE(math, OP_ADD, NODE_PATH)
- CASE_TYPE(math, OP_ADD, _RID)
- CASE_TYPE(math, OP_ADD, OBJECT)
- CASE_TYPE(math, OP_ADD, CALLABLE)
- CASE_TYPE(math, OP_ADD, SIGNAL)
-
- CASE_TYPE(math, OP_ADD, DICTIONARY)
- _RETURN_FAIL;
- }
-
- SWITCH_OP(math, OP_SUBTRACT, p_a.type) {
- DEFAULT_OP_NUM(math, OP_SUBTRACT, INT, -, _int);
- DEFAULT_OP_NUM(math, OP_SUBTRACT, FLOAT, -, _float);
- DEFAULT_OP_LOCALMEM(math, OP_SUBTRACT, VECTOR2, -, Vector2);
- DEFAULT_OP_LOCALMEM(math, OP_SUBTRACT, VECTOR2I, -, Vector2i);
- DEFAULT_OP_LOCALMEM(math, OP_SUBTRACT, VECTOR3, -, Vector3);
- DEFAULT_OP_LOCALMEM(math, OP_SUBTRACT, VECTOR3I, -, Vector3i);
- DEFAULT_OP_LOCALMEM(math, OP_SUBTRACT, QUAT, -, Quat);
- DEFAULT_OP_LOCALMEM(math, OP_SUBTRACT, COLOR, -, Color);
-
- CASE_TYPE(math, OP_SUBTRACT, NIL)
- CASE_TYPE(math, OP_SUBTRACT, BOOL)
- CASE_TYPE(math, OP_SUBTRACT, STRING)
- CASE_TYPE(math, OP_SUBTRACT, RECT2)
- CASE_TYPE(math, OP_SUBTRACT, RECT2I)
- CASE_TYPE(math, OP_SUBTRACT, TRANSFORM2D)
- CASE_TYPE(math, OP_SUBTRACT, PLANE)
- CASE_TYPE(math, OP_SUBTRACT, AABB)
- CASE_TYPE(math, OP_SUBTRACT, BASIS)
- CASE_TYPE(math, OP_SUBTRACT, TRANSFORM)
- CASE_TYPE(math, OP_SUBTRACT, STRING_NAME)
- CASE_TYPE(math, OP_SUBTRACT, NODE_PATH)
- CASE_TYPE(math, OP_SUBTRACT, _RID)
- CASE_TYPE(math, OP_SUBTRACT, OBJECT)
- CASE_TYPE(math, OP_SUBTRACT, CALLABLE)
- CASE_TYPE(math, OP_SUBTRACT, SIGNAL)
-
- CASE_TYPE(math, OP_SUBTRACT, DICTIONARY)
- CASE_TYPE(math, OP_SUBTRACT, ARRAY)
- CASE_TYPE(math, OP_SUBTRACT, PACKED_BYTE_ARRAY);
- CASE_TYPE(math, OP_SUBTRACT, PACKED_INT32_ARRAY);
- CASE_TYPE(math, OP_SUBTRACT, PACKED_INT64_ARRAY);
- CASE_TYPE(math, OP_SUBTRACT, PACKED_FLOAT32_ARRAY);
- CASE_TYPE(math, OP_SUBTRACT, PACKED_FLOAT64_ARRAY);
- CASE_TYPE(math, OP_SUBTRACT, PACKED_STRING_ARRAY);
- CASE_TYPE(math, OP_SUBTRACT, PACKED_VECTOR2_ARRAY);
- CASE_TYPE(math, OP_SUBTRACT, PACKED_VECTOR3_ARRAY);
- CASE_TYPE(math, OP_SUBTRACT, PACKED_COLOR_ARRAY);
- _RETURN_FAIL;
- }
-
- SWITCH_OP(math, OP_MULTIPLY, p_a.type) {
- CASE_TYPE(math, OP_MULTIPLY, TRANSFORM2D) {
- switch (p_b.type) {
- case TRANSFORM2D: {
- _RETURN(*p_a._data._transform2d * *p_b._data._transform2d);
- }
- case VECTOR2: {
- _RETURN(p_a._data._transform2d->xform(*(const Vector2 *)p_b._data._mem));
- }
- default:
- _RETURN_FAIL;
- }
- }
-
- CASE_TYPE(math, OP_MULTIPLY, QUAT) {
- switch (p_b.type) {
- case VECTOR3: {
- _RETURN(reinterpret_cast<const Quat *>(p_a._data._mem)->xform(*(const Vector3 *)p_b._data._mem));
- }
- case QUAT: {
- _RETURN(*reinterpret_cast<const Quat *>(p_a._data._mem) * *reinterpret_cast<const Quat *>(p_b._data._mem));
- }
- case FLOAT: {
- _RETURN(*reinterpret_cast<const Quat *>(p_a._data._mem) * p_b._data._float);
- }
- default:
- _RETURN_FAIL;
- }
- }
-
- CASE_TYPE(math, OP_MULTIPLY, BASIS) {
- switch (p_b.type) {
- case VECTOR3: {
- _RETURN(p_a._data._basis->xform(*(const Vector3 *)p_b._data._mem));
- }
- case BASIS: {
- _RETURN(*p_a._data._basis * *p_b._data._basis);
- }
- default:
- _RETURN_FAIL;
- }
- }
-
- CASE_TYPE(math, OP_MULTIPLY, TRANSFORM) {
- switch (p_b.type) {
- case VECTOR3: {
- _RETURN(p_a._data._transform->xform(*(const Vector3 *)p_b._data._mem));
- }
- case TRANSFORM: {
- _RETURN(*p_a._data._transform * *p_b._data._transform);
- }
- default:
- _RETURN_FAIL;
- }
- }
-
- DEFAULT_OP_NUM_VEC(math, OP_MULTIPLY, INT, *, _int);
- DEFAULT_OP_NUM_VEC(math, OP_MULTIPLY, FLOAT, *, _float);
- DEFAULT_OP_LOCALMEM_NUM(math, OP_MULTIPLY, VECTOR2, *, Vector2);
- DEFAULT_OP_LOCALMEM_NUM(math, OP_MULTIPLY, VECTOR2I, *, Vector2i);
- DEFAULT_OP_LOCALMEM_NUM(math, OP_MULTIPLY, VECTOR3, *, Vector3);
- DEFAULT_OP_LOCALMEM_NUM(math, OP_MULTIPLY, VECTOR3I, *, Vector3i);
- DEFAULT_OP_LOCALMEM_NUM(math, OP_MULTIPLY, COLOR, *, Color);
-
- CASE_TYPE(math, OP_MULTIPLY, NIL)
- CASE_TYPE(math, OP_MULTIPLY, BOOL)
- CASE_TYPE(math, OP_MULTIPLY, STRING)
- CASE_TYPE(math, OP_MULTIPLY, RECT2)
- CASE_TYPE(math, OP_MULTIPLY, RECT2I)
- CASE_TYPE(math, OP_MULTIPLY, PLANE)
- CASE_TYPE(math, OP_MULTIPLY, AABB)
- CASE_TYPE(math, OP_MULTIPLY, STRING_NAME)
- CASE_TYPE(math, OP_MULTIPLY, NODE_PATH)
- CASE_TYPE(math, OP_MULTIPLY, _RID)
- CASE_TYPE(math, OP_MULTIPLY, OBJECT)
- CASE_TYPE(math, OP_MULTIPLY, CALLABLE)
- CASE_TYPE(math, OP_MULTIPLY, SIGNAL)
-
- CASE_TYPE(math, OP_MULTIPLY, DICTIONARY)
- CASE_TYPE(math, OP_MULTIPLY, ARRAY)
- CASE_TYPE(math, OP_MULTIPLY, PACKED_BYTE_ARRAY);
- CASE_TYPE(math, OP_MULTIPLY, PACKED_INT32_ARRAY);
- CASE_TYPE(math, OP_MULTIPLY, PACKED_INT64_ARRAY);
- CASE_TYPE(math, OP_MULTIPLY, PACKED_FLOAT32_ARRAY);
- CASE_TYPE(math, OP_MULTIPLY, PACKED_FLOAT64_ARRAY);
- CASE_TYPE(math, OP_MULTIPLY, PACKED_STRING_ARRAY);
- CASE_TYPE(math, OP_MULTIPLY, PACKED_VECTOR2_ARRAY);
- CASE_TYPE(math, OP_MULTIPLY, PACKED_VECTOR3_ARRAY);
- CASE_TYPE(math, OP_MULTIPLY, PACKED_COLOR_ARRAY);
- _RETURN_FAIL;
- }
-
- SWITCH_OP(math, OP_DIVIDE, p_a.type) {
- CASE_TYPE(math, OP_DIVIDE, QUAT) {
- if (p_b.type != FLOAT)
- _RETURN_FAIL;
-#ifdef DEBUG_ENABLED
- if (p_b._data._float == 0) {
- r_valid = false;
- _RETURN("Division By Zero");
- }
-#endif
- _RETURN(*reinterpret_cast<const Quat *>(p_a._data._mem) / p_b._data._float);
- }
-
- DEFAULT_OP_NUM_DIV(math, OP_DIVIDE, INT, _int);
- DEFAULT_OP_NUM_DIV(math, OP_DIVIDE, FLOAT, _float);
- DEFAULT_OP_LOCALMEM_NUM(math, OP_DIVIDE, VECTOR2, /, Vector2);
- DEFAULT_OP_LOCALMEM_NUM(math, OP_DIVIDE, VECTOR2I, /, Vector2i);
- DEFAULT_OP_LOCALMEM_NUM(math, OP_DIVIDE, VECTOR3, /, Vector3);
- DEFAULT_OP_LOCALMEM_NUM(math, OP_DIVIDE, VECTOR3I, /, Vector3i);
- DEFAULT_OP_LOCALMEM_NUM(math, OP_DIVIDE, COLOR, /, Color);
-
- CASE_TYPE(math, OP_DIVIDE, NIL)
- CASE_TYPE(math, OP_DIVIDE, BOOL)
- CASE_TYPE(math, OP_DIVIDE, STRING)
- CASE_TYPE(math, OP_DIVIDE, RECT2)
- CASE_TYPE(math, OP_DIVIDE, RECT2I)
- CASE_TYPE(math, OP_DIVIDE, TRANSFORM2D)
- CASE_TYPE(math, OP_DIVIDE, PLANE)
- CASE_TYPE(math, OP_DIVIDE, AABB)
- CASE_TYPE(math, OP_DIVIDE, BASIS)
- CASE_TYPE(math, OP_DIVIDE, TRANSFORM)
- CASE_TYPE(math, OP_DIVIDE, STRING_NAME)
- CASE_TYPE(math, OP_DIVIDE, NODE_PATH)
- CASE_TYPE(math, OP_DIVIDE, _RID)
- CASE_TYPE(math, OP_DIVIDE, OBJECT)
- CASE_TYPE(math, OP_DIVIDE, CALLABLE)
- CASE_TYPE(math, OP_DIVIDE, SIGNAL)
-
- CASE_TYPE(math, OP_DIVIDE, DICTIONARY)
- CASE_TYPE(math, OP_DIVIDE, ARRAY)
- CASE_TYPE(math, OP_DIVIDE, PACKED_BYTE_ARRAY);
- CASE_TYPE(math, OP_DIVIDE, PACKED_INT32_ARRAY);
- CASE_TYPE(math, OP_DIVIDE, PACKED_INT64_ARRAY);
- CASE_TYPE(math, OP_DIVIDE, PACKED_FLOAT32_ARRAY);
- CASE_TYPE(math, OP_DIVIDE, PACKED_FLOAT64_ARRAY);
- CASE_TYPE(math, OP_DIVIDE, PACKED_STRING_ARRAY);
- CASE_TYPE(math, OP_DIVIDE, PACKED_VECTOR2_ARRAY);
- CASE_TYPE(math, OP_DIVIDE, PACKED_VECTOR3_ARRAY);
- CASE_TYPE(math, OP_DIVIDE, PACKED_COLOR_ARRAY);
- _RETURN_FAIL;
- }
-
- SWITCH_OP(math, OP_POSITIVE, p_a.type) {
- DEFAULT_OP_NUM_POS(math, OP_POSITIVE, INT, _int);
- DEFAULT_OP_NUM_POS(math, OP_POSITIVE, FLOAT, _float);
- DEFAULT_OP_LOCALMEM_POS(math, OP_POSITIVE, VECTOR3, Vector3);
- DEFAULT_OP_LOCALMEM_POS(math, OP_POSITIVE, VECTOR3I, Vector3i);
- DEFAULT_OP_LOCALMEM_POS(math, OP_POSITIVE, PLANE, Plane);
- DEFAULT_OP_LOCALMEM_POS(math, OP_POSITIVE, QUAT, Quat);
- DEFAULT_OP_LOCALMEM_POS(math, OP_POSITIVE, VECTOR2, Vector2);
- DEFAULT_OP_LOCALMEM_POS(math, OP_POSITIVE, VECTOR2I, Vector2i);
-
- CASE_TYPE(math, OP_POSITIVE, NIL)
- CASE_TYPE(math, OP_POSITIVE, BOOL)
- CASE_TYPE(math, OP_POSITIVE, STRING)
- CASE_TYPE(math, OP_POSITIVE, RECT2)
- CASE_TYPE(math, OP_POSITIVE, RECT2I)
- CASE_TYPE(math, OP_POSITIVE, TRANSFORM2D)
- CASE_TYPE(math, OP_POSITIVE, AABB)
- CASE_TYPE(math, OP_POSITIVE, BASIS)
- CASE_TYPE(math, OP_POSITIVE, TRANSFORM)
- CASE_TYPE(math, OP_POSITIVE, COLOR)
- CASE_TYPE(math, OP_POSITIVE, STRING_NAME)
- CASE_TYPE(math, OP_POSITIVE, NODE_PATH)
- CASE_TYPE(math, OP_POSITIVE, _RID)
- CASE_TYPE(math, OP_POSITIVE, OBJECT)
- CASE_TYPE(math, OP_POSITIVE, CALLABLE)
- CASE_TYPE(math, OP_POSITIVE, SIGNAL)
-
- CASE_TYPE(math, OP_POSITIVE, DICTIONARY)
- CASE_TYPE(math, OP_POSITIVE, ARRAY)
- CASE_TYPE(math, OP_POSITIVE, PACKED_BYTE_ARRAY)
- CASE_TYPE(math, OP_POSITIVE, PACKED_INT32_ARRAY)
- CASE_TYPE(math, OP_POSITIVE, PACKED_INT64_ARRAY)
- CASE_TYPE(math, OP_POSITIVE, PACKED_FLOAT32_ARRAY)
- CASE_TYPE(math, OP_POSITIVE, PACKED_FLOAT64_ARRAY)
- CASE_TYPE(math, OP_POSITIVE, PACKED_STRING_ARRAY)
- CASE_TYPE(math, OP_POSITIVE, PACKED_VECTOR2_ARRAY)
- CASE_TYPE(math, OP_POSITIVE, PACKED_VECTOR3_ARRAY)
- CASE_TYPE(math, OP_POSITIVE, PACKED_COLOR_ARRAY)
- _RETURN_FAIL;
- }
-
- SWITCH_OP(math, OP_NEGATE, p_a.type) {
- DEFAULT_OP_NUM_NEG(math, OP_NEGATE, INT, _int);
- DEFAULT_OP_NUM_NEG(math, OP_NEGATE, FLOAT, _float);
-
- DEFAULT_OP_LOCALMEM_NEG(math, OP_NEGATE, VECTOR2, Vector2);
- DEFAULT_OP_LOCALMEM_NEG(math, OP_NEGATE, VECTOR2I, Vector2i);
- DEFAULT_OP_LOCALMEM_NEG(math, OP_NEGATE, VECTOR3, Vector3);
- DEFAULT_OP_LOCALMEM_NEG(math, OP_NEGATE, VECTOR3I, Vector3i);
- DEFAULT_OP_LOCALMEM_NEG(math, OP_NEGATE, PLANE, Plane);
- DEFAULT_OP_LOCALMEM_NEG(math, OP_NEGATE, QUAT, Quat);
- DEFAULT_OP_LOCALMEM_NEG(math, OP_NEGATE, COLOR, Color);
-
- CASE_TYPE(math, OP_NEGATE, NIL)
- CASE_TYPE(math, OP_NEGATE, BOOL)
- CASE_TYPE(math, OP_NEGATE, STRING)
- CASE_TYPE(math, OP_NEGATE, RECT2)
- CASE_TYPE(math, OP_NEGATE, RECT2I)
- CASE_TYPE(math, OP_NEGATE, TRANSFORM2D)
- CASE_TYPE(math, OP_NEGATE, AABB)
- CASE_TYPE(math, OP_NEGATE, BASIS)
- CASE_TYPE(math, OP_NEGATE, TRANSFORM)
- CASE_TYPE(math, OP_NEGATE, STRING_NAME)
- CASE_TYPE(math, OP_NEGATE, NODE_PATH)
- CASE_TYPE(math, OP_NEGATE, _RID)
- CASE_TYPE(math, OP_NEGATE, OBJECT)
- CASE_TYPE(math, OP_NEGATE, CALLABLE)
- CASE_TYPE(math, OP_NEGATE, SIGNAL)
-
- CASE_TYPE(math, OP_NEGATE, DICTIONARY)
- CASE_TYPE(math, OP_NEGATE, ARRAY)
- CASE_TYPE(math, OP_NEGATE, PACKED_BYTE_ARRAY)
- CASE_TYPE(math, OP_NEGATE, PACKED_INT32_ARRAY)
- CASE_TYPE(math, OP_NEGATE, PACKED_INT64_ARRAY)
- CASE_TYPE(math, OP_NEGATE, PACKED_FLOAT32_ARRAY)
- CASE_TYPE(math, OP_NEGATE, PACKED_FLOAT64_ARRAY)
- CASE_TYPE(math, OP_NEGATE, PACKED_STRING_ARRAY)
- CASE_TYPE(math, OP_NEGATE, PACKED_VECTOR2_ARRAY)
- CASE_TYPE(math, OP_NEGATE, PACKED_VECTOR3_ARRAY)
- CASE_TYPE(math, OP_NEGATE, PACKED_COLOR_ARRAY)
- _RETURN_FAIL;
- }
-
- SWITCH_OP(math, OP_MODULE, p_a.type) {
- CASE_TYPE(math, OP_MODULE, INT) {
- if (p_b.type != INT)
- _RETURN_FAIL;
-#ifdef DEBUG_ENABLED
- if (p_b._data._int == 0) {
- r_valid = false;
- _RETURN("Division By Zero");
- }
-#endif
- _RETURN(p_a._data._int % p_b._data._int);
- }
-
- CASE_TYPE(math, OP_MODULE, STRING) {
- const String *format = reinterpret_cast<const String *>(p_a._data._mem);
-
- String result;
- bool error;
- if (p_b.type == ARRAY) {
- // e.g. "frog %s %d" % ["fish", 12]
- const Array *args = reinterpret_cast<const Array *>(p_b._data._mem);
- result = format->sprintf(*args, &error);
- } else {
- // e.g. "frog %d" % 12
- Array args;
- args.push_back(p_b);
- result = format->sprintf(args, &error);
- }
- r_valid = !error;
- _RETURN(result);
- }
-
- CASE_TYPE(math, OP_MODULE, NIL)
- CASE_TYPE(math, OP_MODULE, BOOL)
- CASE_TYPE(math, OP_MODULE, FLOAT)
- CASE_TYPE(math, OP_MODULE, VECTOR2)
- CASE_TYPE(math, OP_MODULE, VECTOR2I)
- CASE_TYPE(math, OP_MODULE, RECT2)
- CASE_TYPE(math, OP_MODULE, RECT2I)
- CASE_TYPE(math, OP_MODULE, VECTOR3)
- CASE_TYPE(math, OP_MODULE, VECTOR3I)
- CASE_TYPE(math, OP_MODULE, TRANSFORM2D)
- CASE_TYPE(math, OP_MODULE, PLANE)
- CASE_TYPE(math, OP_MODULE, QUAT)
- CASE_TYPE(math, OP_MODULE, AABB)
- CASE_TYPE(math, OP_MODULE, BASIS)
- CASE_TYPE(math, OP_MODULE, TRANSFORM)
- CASE_TYPE(math, OP_MODULE, COLOR)
- CASE_TYPE(math, OP_MODULE, STRING_NAME)
- CASE_TYPE(math, OP_MODULE, NODE_PATH)
- CASE_TYPE(math, OP_MODULE, _RID)
- CASE_TYPE(math, OP_MODULE, OBJECT)
- CASE_TYPE(math, OP_MODULE, CALLABLE)
- CASE_TYPE(math, OP_MODULE, SIGNAL)
-
- CASE_TYPE(math, OP_MODULE, DICTIONARY)
- CASE_TYPE(math, OP_MODULE, ARRAY)
- CASE_TYPE(math, OP_MODULE, PACKED_BYTE_ARRAY)
- CASE_TYPE(math, OP_MODULE, PACKED_INT32_ARRAY)
- CASE_TYPE(math, OP_MODULE, PACKED_INT64_ARRAY)
- CASE_TYPE(math, OP_MODULE, PACKED_FLOAT32_ARRAY)
- CASE_TYPE(math, OP_MODULE, PACKED_FLOAT64_ARRAY)
- CASE_TYPE(math, OP_MODULE, PACKED_STRING_ARRAY)
- CASE_TYPE(math, OP_MODULE, PACKED_VECTOR2_ARRAY)
- CASE_TYPE(math, OP_MODULE, PACKED_VECTOR3_ARRAY)
- CASE_TYPE(math, OP_MODULE, PACKED_COLOR_ARRAY)
- _RETURN_FAIL;
- }
-
- SWITCH_OP(math, OP_STRING_CONCAT, p_a.type) {
- CASE_TYPE_ALL(math, OP_STRING_CONCAT)
-
- _RETURN(p_a.operator String() + p_b.operator String());
- }
-
- SWITCH_OP(math, OP_SHIFT_LEFT, p_a.type) {
- CASE_TYPE(math, OP_SHIFT_LEFT, INT) {
- if (p_b.type != INT)
- _RETURN_FAIL;
- if (p_b._data._int < 0 || p_b._data._int >= 64)
- _RETURN_FAIL;
- _RETURN(p_a._data._int << p_b._data._int);
- }
-
- CASE_TYPE_ALL_BUT_INT(math, OP_SHIFT_LEFT)
- _RETURN_FAIL;
- }
-
- SWITCH_OP(math, OP_SHIFT_RIGHT, p_a.type) {
- CASE_TYPE(math, OP_SHIFT_RIGHT, INT) {
- if (p_b.type != INT)
- _RETURN_FAIL;
- if (p_b._data._int < 0 || p_b._data._int >= 64)
- _RETURN_FAIL;
- _RETURN(p_a._data._int >> p_b._data._int);
- }
-
- CASE_TYPE_ALL_BUT_INT(math, OP_SHIFT_RIGHT)
- _RETURN_FAIL;
- }
-
- SWITCH_OP(math, OP_BIT_AND, p_a.type) {
- CASE_TYPE(math, OP_BIT_AND, INT) {
- if (p_b.type != INT)
- _RETURN_FAIL;
- _RETURN(p_a._data._int & p_b._data._int);
- }
-
- CASE_TYPE_ALL_BUT_INT(math, OP_BIT_AND)
- _RETURN_FAIL;
- }
-
- SWITCH_OP(math, OP_BIT_OR, p_a.type) {
- CASE_TYPE(math, OP_BIT_OR, INT) {
- if (p_b.type != INT)
- _RETURN_FAIL;
- _RETURN(p_a._data._int | p_b._data._int);
- }
-
- CASE_TYPE_ALL_BUT_INT(math, OP_BIT_OR)
- _RETURN_FAIL;
- }
-
- SWITCH_OP(math, OP_BIT_XOR, p_a.type) {
- CASE_TYPE(math, OP_BIT_XOR, INT) {
- if (p_b.type != INT)
- _RETURN_FAIL;
- _RETURN(p_a._data._int ^ p_b._data._int);
- }
-
- CASE_TYPE_ALL_BUT_INT(math, OP_BIT_XOR)
- _RETURN_FAIL;
- }
-
- SWITCH_OP(math, OP_BIT_NEGATE, p_a.type) {
- CASE_TYPE(math, OP_BIT_NEGATE, INT) {
- _RETURN(~p_a._data._int);
- }
-
- CASE_TYPE_ALL_BUT_INT(math, OP_BIT_NEGATE)
- _RETURN_FAIL;
- }
-
- SWITCH_OP(math, OP_AND, p_a.type) {
- CASE_TYPE_ALL(math, OP_AND) {
- bool l = p_a.booleanize();
- bool r = p_b.booleanize();
-
- _RETURN(l && r);
- }
- }
-
- SWITCH_OP(math, OP_OR, p_a.type) {
- CASE_TYPE_ALL(math, OP_OR) {
- bool l = p_a.booleanize();
- bool r = p_b.booleanize();
-
- _RETURN(l || r);
- }
- }
-
- SWITCH_OP(math, OP_XOR, p_a.type) {
- CASE_TYPE_ALL(math, OP_XOR) {
- bool l = p_a.booleanize();
- bool r = p_b.booleanize();
-
- _RETURN((l || r) && !(l && r));
- }
- }
-
- SWITCH_OP(math, OP_NOT, p_a.type) {
- CASE_TYPE_ALL(math, OP_NOT) {
- bool l = p_a.booleanize();
- _RETURN(!l);
- }
- }
-
- SWITCH_OP(math, OP_IN, p_a.type) {
- CASE_TYPE_ALL(math, OP_IN)
- _RETURN(p_b.in(p_a, &r_valid));
- }
- }
-}
-
-void Variant::set_named(const StringName &p_index, const Variant &p_value, bool *r_valid) {
- bool valid = false;
- switch (type) {
- case VECTOR2: {
- if (p_value.type == Variant::INT) {
- Vector2 *v = reinterpret_cast<Vector2 *>(_data._mem);
- if (p_index == CoreStringNames::singleton->x) {
- v->x = p_value._data._int;
- valid = true;
- } else if (p_index == CoreStringNames::singleton->y) {
- v->y = p_value._data._int;
- valid = true;
- }
- } else if (p_value.type == Variant::FLOAT) {
- Vector2 *v = reinterpret_cast<Vector2 *>(_data._mem);
- if (p_index == CoreStringNames::singleton->x) {
- v->x = p_value._data._float;
- valid = true;
- } else if (p_index == CoreStringNames::singleton->y) {
- v->y = p_value._data._float;
- valid = true;
- }
- }
-
- } break;
- case VECTOR2I: {
- if (p_value.type == Variant::INT) {
- Vector2i *v = reinterpret_cast<Vector2i *>(_data._mem);
- if (p_index == CoreStringNames::singleton->x) {
- v->x = p_value._data._int;
- valid = true;
- } else if (p_index == CoreStringNames::singleton->y) {
- v->y = p_value._data._int;
- valid = true;
- }
- } else if (p_value.type == Variant::FLOAT) {
- Vector2i *v = reinterpret_cast<Vector2i *>(_data._mem);
- if (p_index == CoreStringNames::singleton->x) {
- v->x = p_value._data._float;
- valid = true;
- } else if (p_index == CoreStringNames::singleton->y) {
- v->y = p_value._data._float;
- valid = true;
- }
- }
-
- } break;
- case RECT2: {
- if (p_value.type == Variant::VECTOR2) {
- Rect2 *v = reinterpret_cast<Rect2 *>(_data._mem);
- //scalar name
- if (p_index == CoreStringNames::singleton->position) {
- v->position = *reinterpret_cast<const Vector2 *>(p_value._data._mem);
- valid = true;
- } else if (p_index == CoreStringNames::singleton->size) {
- v->size = *reinterpret_cast<const Vector2 *>(p_value._data._mem);
- valid = true;
- } else if (p_index == CoreStringNames::singleton->end) {
- v->size = *reinterpret_cast<const Vector2 *>(p_value._data._mem) - v->position;
- valid = true;
- }
- }
- } break;
- case RECT2I: {
- if (p_value.type == Variant::VECTOR2I) {
- Rect2i *v = reinterpret_cast<Rect2i *>(_data._mem);
- //scalar name
- if (p_index == CoreStringNames::singleton->position) {
- v->position = *reinterpret_cast<const Vector2i *>(p_value._data._mem);
- valid = true;
- } else if (p_index == CoreStringNames::singleton->size) {
- v->size = *reinterpret_cast<const Vector2i *>(p_value._data._mem);
- valid = true;
- } else if (p_index == CoreStringNames::singleton->end) {
- v->size = *reinterpret_cast<const Vector2i *>(p_value._data._mem) - v->position;
- valid = true;
- }
- }
- } break;
- case TRANSFORM2D: {
- if (p_value.type == Variant::VECTOR2) {
- Transform2D *v = _data._transform2d;
- if (p_index == CoreStringNames::singleton->x) {
- v->elements[0] = *reinterpret_cast<const Vector2 *>(p_value._data._mem);
- valid = true;
- } else if (p_index == CoreStringNames::singleton->y) {
- v->elements[1] = *reinterpret_cast<const Vector2 *>(p_value._data._mem);
- valid = true;
- } else if (p_index == CoreStringNames::singleton->origin) {
- v->elements[2] = *reinterpret_cast<const Vector2 *>(p_value._data._mem);
- valid = true;
- }
- }
-
- } break;
- case VECTOR3: {
- if (p_value.type == Variant::INT) {
- Vector3 *v = reinterpret_cast<Vector3 *>(_data._mem);
- if (p_index == CoreStringNames::singleton->x) {
- v->x = p_value._data._int;
- valid = true;
- } else if (p_index == CoreStringNames::singleton->y) {
- v->y = p_value._data._int;
- valid = true;
- } else if (p_index == CoreStringNames::singleton->z) {
- v->z = p_value._data._int;
- valid = true;
- }
- } else if (p_value.type == Variant::FLOAT) {
- Vector3 *v = reinterpret_cast<Vector3 *>(_data._mem);
- if (p_index == CoreStringNames::singleton->x) {
- v->x = p_value._data._float;
- valid = true;
- } else if (p_index == CoreStringNames::singleton->y) {
- v->y = p_value._data._float;
- valid = true;
- } else if (p_index == CoreStringNames::singleton->z) {
- v->z = p_value._data._float;
- valid = true;
- }
- }
-
- } break;
- case VECTOR3I: {
- if (p_value.type == Variant::INT) {
- Vector3i *v = reinterpret_cast<Vector3i *>(_data._mem);
- if (p_index == CoreStringNames::singleton->x) {
- v->x = p_value._data._int;
- valid = true;
- } else if (p_index == CoreStringNames::singleton->y) {
- v->y = p_value._data._int;
- valid = true;
- } else if (p_index == CoreStringNames::singleton->z) {
- v->z = p_value._data._int;
- valid = true;
- }
- } else if (p_value.type == Variant::FLOAT) {
- Vector3i *v = reinterpret_cast<Vector3i *>(_data._mem);
- if (p_index == CoreStringNames::singleton->x) {
- v->x = p_value._data._float;
- valid = true;
- } else if (p_index == CoreStringNames::singleton->y) {
- v->y = p_value._data._float;
- valid = true;
- } else if (p_index == CoreStringNames::singleton->z) {
- v->z = p_value._data._float;
- valid = true;
- }
- }
-
- } break;
- case PLANE: {
- if (p_value.type == Variant::INT) {
- Plane *v = reinterpret_cast<Plane *>(_data._mem);
- if (p_index == CoreStringNames::singleton->x) {
- v->normal.x = p_value._data._int;
- valid = true;
- } else if (p_index == CoreStringNames::singleton->y) {
- v->normal.y = p_value._data._int;
- valid = true;
- } else if (p_index == CoreStringNames::singleton->z) {
- v->normal.z = p_value._data._int;
- valid = true;
- } else if (p_index == CoreStringNames::singleton->d) {
- v->d = p_value._data._int;
- valid = true;
- }
- } else if (p_value.type == Variant::FLOAT) {
- Plane *v = reinterpret_cast<Plane *>(_data._mem);
- if (p_index == CoreStringNames::singleton->x) {
- v->normal.x = p_value._data._float;
- valid = true;
- } else if (p_index == CoreStringNames::singleton->y) {
- v->normal.y = p_value._data._float;
- valid = true;
- } else if (p_index == CoreStringNames::singleton->z) {
- v->normal.z = p_value._data._float;
- valid = true;
- } else if (p_index == CoreStringNames::singleton->d) {
- v->d = p_value._data._float;
- valid = true;
- }
-
- } else if (p_value.type == Variant::VECTOR3) {
- Plane *v = reinterpret_cast<Plane *>(_data._mem);
- if (p_index == CoreStringNames::singleton->normal) {
- v->normal = *reinterpret_cast<const Vector3 *>(p_value._data._mem);
- valid = true;
- }
- }
-
- } break;
- case QUAT: {
- if (p_value.type == Variant::INT) {
- Quat *v = reinterpret_cast<Quat *>(_data._mem);
- if (p_index == CoreStringNames::singleton->x) {
- v->x = p_value._data._int;
- valid = true;
- } else if (p_index == CoreStringNames::singleton->y) {
- v->y = p_value._data._int;
- valid = true;
- } else if (p_index == CoreStringNames::singleton->z) {
- v->z = p_value._data._int;
- valid = true;
- } else if (p_index == CoreStringNames::singleton->w) {
- v->w = p_value._data._int;
- valid = true;
- }
- } else if (p_value.type == Variant::FLOAT) {
- Quat *v = reinterpret_cast<Quat *>(_data._mem);
- if (p_index == CoreStringNames::singleton->x) {
- v->x = p_value._data._float;
- valid = true;
- } else if (p_index == CoreStringNames::singleton->y) {
- v->y = p_value._data._float;
- valid = true;
- } else if (p_index == CoreStringNames::singleton->z) {
- v->z = p_value._data._float;
- valid = true;
- } else if (p_index == CoreStringNames::singleton->w) {
- v->w = p_value._data._float;
- valid = true;
- }
- }
-
- } break;
- case AABB: {
- if (p_value.type == Variant::VECTOR3) {
- ::AABB *v = _data._aabb;
- //scalar name
- if (p_index == CoreStringNames::singleton->position) {
- v->position = *reinterpret_cast<const Vector3 *>(p_value._data._mem);
- valid = true;
- } else if (p_index == CoreStringNames::singleton->size) {
- v->size = *reinterpret_cast<const Vector3 *>(p_value._data._mem);
- valid = true;
- } else if (p_index == CoreStringNames::singleton->end) {
- v->size = *reinterpret_cast<const Vector3 *>(p_value._data._mem) - v->position;
- valid = true;
- }
- }
- } break;
- case BASIS: {
- if (p_value.type == Variant::VECTOR3) {
- Basis *v = _data._basis;
- //scalar name
- if (p_index == CoreStringNames::singleton->x) {
- v->set_axis(0, *reinterpret_cast<const Vector3 *>(p_value._data._mem));
- valid = true;
- } else if (p_index == CoreStringNames::singleton->y) {
- v->set_axis(1, *reinterpret_cast<const Vector3 *>(p_value._data._mem));
- valid = true;
- } else if (p_index == CoreStringNames::singleton->z) {
- v->set_axis(2, *reinterpret_cast<const Vector3 *>(p_value._data._mem));
- valid = true;
- }
- }
- } break;
- case TRANSFORM: {
- if (p_value.type == Variant::BASIS && p_index == CoreStringNames::singleton->basis) {
- _data._transform->basis = *p_value._data._basis;
- valid = true;
- } else if (p_value.type == Variant::VECTOR3 && p_index == CoreStringNames::singleton->origin) {
- _data._transform->origin = *reinterpret_cast<const Vector3 *>(p_value._data._mem);
- valid = true;
- }
-
- } break;
- case COLOR: {
- if (p_value.type == Variant::INT) {
- Color *v = reinterpret_cast<Color *>(_data._mem);
- if (p_index == CoreStringNames::singleton->r) {
- v->r = p_value._data._int;
- valid = true;
- } else if (p_index == CoreStringNames::singleton->g) {
- v->g = p_value._data._int;
- valid = true;
- } else if (p_index == CoreStringNames::singleton->b) {
- v->b = p_value._data._int;
- valid = true;
- } else if (p_index == CoreStringNames::singleton->a) {
- v->a = p_value._data._int;
- valid = true;
- } else if (p_index == CoreStringNames::singleton->r8) {
- v->r = p_value._data._int / 255.0;
- valid = true;
- } else if (p_index == CoreStringNames::singleton->g8) {
- v->g = p_value._data._int / 255.0;
- valid = true;
- } else if (p_index == CoreStringNames::singleton->b8) {
- v->b = p_value._data._int / 255.0;
- valid = true;
- } else if (p_index == CoreStringNames::singleton->a8) {
- v->a = p_value._data._int / 255.0;
- valid = true;
- } else if (p_index == CoreStringNames::singleton->h) {
- v->set_hsv(p_value._data._int, v->get_s(), v->get_v(), v->a);
- valid = true;
- } else if (p_index == CoreStringNames::singleton->s) {
- v->set_hsv(v->get_h(), p_value._data._int, v->get_v(), v->a);
- valid = true;
- } else if (p_index == CoreStringNames::singleton->v) {
- v->set_hsv(v->get_h(), v->get_v(), p_value._data._int, v->a);
- valid = true;
- }
- } else if (p_value.type == Variant::FLOAT) {
- Color *v = reinterpret_cast<Color *>(_data._mem);
- if (p_index == CoreStringNames::singleton->r) {
- v->r = p_value._data._float;
- valid = true;
- } else if (p_index == CoreStringNames::singleton->g) {
- v->g = p_value._data._float;
- valid = true;
- } else if (p_index == CoreStringNames::singleton->b) {
- v->b = p_value._data._float;
- valid = true;
- } else if (p_index == CoreStringNames::singleton->a) {
- v->a = p_value._data._float;
- valid = true;
- } else if (p_index == CoreStringNames::singleton->r8) {
- v->r = p_value._data._float / 255.0;
- valid = true;
- } else if (p_index == CoreStringNames::singleton->g8) {
- v->g = p_value._data._float / 255.0;
- valid = true;
- } else if (p_index == CoreStringNames::singleton->b8) {
- v->b = p_value._data._float / 255.0;
- valid = true;
- } else if (p_index == CoreStringNames::singleton->a8) {
- v->a = p_value._data._float / 255.0;
- valid = true;
- } else if (p_index == CoreStringNames::singleton->h) {
- v->set_hsv(p_value._data._float, v->get_s(), v->get_v(), v->a);
- valid = true;
- } else if (p_index == CoreStringNames::singleton->s) {
- v->set_hsv(v->get_h(), p_value._data._float, v->get_v(), v->a);
- valid = true;
- } else if (p_index == CoreStringNames::singleton->v) {
- v->set_hsv(v->get_h(), v->get_s(), p_value._data._float, v->a);
- valid = true;
- }
- }
- } break;
- case OBJECT: {
-#ifdef DEBUG_ENABLED
- if (!_get_obj().obj) {
- break;
- } else if (EngineDebugger::is_active() && ObjectDB::get_instance(_get_obj().id) == nullptr) {
- break;
- }
-
-#endif
- _get_obj().obj->set(p_index, p_value, &valid);
-
- } break;
- default: {
- set(p_index.operator String(), p_value, &valid);
- } break;
- }
-
- if (r_valid) {
- *r_valid = valid;
- }
-}
-
-Variant Variant::get_named(const StringName &p_index, bool *r_valid) const {
- if (r_valid) {
- *r_valid = true;
- }
-
- switch (type) {
- case VECTOR2: {
- const Vector2 *v = reinterpret_cast<const Vector2 *>(_data._mem);
- if (p_index == CoreStringNames::singleton->x) {
- return v->x;
- } else if (p_index == CoreStringNames::singleton->y) {
- return v->y;
- }
-
- } break;
- case VECTOR2I: {
- const Vector2i *v = reinterpret_cast<const Vector2i *>(_data._mem);
- if (p_index == CoreStringNames::singleton->x) {
- return v->x;
- } else if (p_index == CoreStringNames::singleton->y) {
- return v->y;
- }
-
- } break;
- case RECT2: {
- const Rect2 *v = reinterpret_cast<const Rect2 *>(_data._mem);
- //scalar name
- if (p_index == CoreStringNames::singleton->position) {
- return v->position;
- } else if (p_index == CoreStringNames::singleton->size) {
- return v->size;
- } else if (p_index == CoreStringNames::singleton->end) {
- return v->size + v->position;
- }
- } break;
- case RECT2I: {
- const Rect2i *v = reinterpret_cast<const Rect2i *>(_data._mem);
- //scalar name
- if (p_index == CoreStringNames::singleton->position) {
- return v->position;
- } else if (p_index == CoreStringNames::singleton->size) {
- return v->size;
- } else if (p_index == CoreStringNames::singleton->end) {
- return v->size + v->position;
- }
- } break;
- case TRANSFORM2D: {
- const Transform2D *v = _data._transform2d;
- if (p_index == CoreStringNames::singleton->x) {
- return v->elements[0];
- } else if (p_index == CoreStringNames::singleton->y) {
- return v->elements[1];
- } else if (p_index == CoreStringNames::singleton->origin) {
- return v->elements[2];
- }
-
- } break;
- case VECTOR3: {
- const Vector3 *v = reinterpret_cast<const Vector3 *>(_data._mem);
- if (p_index == CoreStringNames::singleton->x) {
- return v->x;
- } else if (p_index == CoreStringNames::singleton->y) {
- return v->y;
- } else if (p_index == CoreStringNames::singleton->z) {
- return v->z;
- }
-
- } break;
- case VECTOR3I: {
- const Vector3i *v = reinterpret_cast<const Vector3i *>(_data._mem);
- if (p_index == CoreStringNames::singleton->x) {
- return v->x;
- } else if (p_index == CoreStringNames::singleton->y) {
- return v->y;
- } else if (p_index == CoreStringNames::singleton->z) {
- return v->z;
- }
-
- } break;
- case PLANE: {
- const Plane *v = reinterpret_cast<const Plane *>(_data._mem);
- if (p_index == CoreStringNames::singleton->x) {
- return v->normal.x;
- } else if (p_index == CoreStringNames::singleton->y) {
- return v->normal.y;
- } else if (p_index == CoreStringNames::singleton->z) {
- return v->normal.z;
- } else if (p_index == CoreStringNames::singleton->d) {
- return v->d;
- } else if (p_index == CoreStringNames::singleton->normal) {
- return v->normal;
- }
-
- } break;
- case QUAT: {
- const Quat *v = reinterpret_cast<const Quat *>(_data._mem);
- if (p_index == CoreStringNames::singleton->x) {
- return v->x;
- } else if (p_index == CoreStringNames::singleton->y) {
- return v->y;
- } else if (p_index == CoreStringNames::singleton->z) {
- return v->z;
- } else if (p_index == CoreStringNames::singleton->w) {
- return v->w;
- }
-
- } break;
- case AABB: {
- const ::AABB *v = _data._aabb;
- //scalar name
- if (p_index == CoreStringNames::singleton->position) {
- return v->position;
- } else if (p_index == CoreStringNames::singleton->size) {
- return v->size;
- } else if (p_index == CoreStringNames::singleton->end) {
- return v->size + v->position;
- }
- } break;
- case BASIS: {
- const Basis *v = _data._basis;
- //scalar name
- if (p_index == CoreStringNames::singleton->x) {
- return v->get_axis(0);
- } else if (p_index == CoreStringNames::singleton->y) {
- return v->get_axis(1);
- } else if (p_index == CoreStringNames::singleton->z) {
- return v->get_axis(2);
- }
-
- } break;
- case TRANSFORM: {
- if (p_index == CoreStringNames::singleton->basis) {
- return _data._transform->basis;
- } else if (p_index == CoreStringNames::singleton->origin) {
- return _data._transform->origin;
- }
-
- } break;
- case COLOR: {
- const Color *v = reinterpret_cast<const Color *>(_data._mem);
- if (p_index == CoreStringNames::singleton->r) {
- return v->r;
- } else if (p_index == CoreStringNames::singleton->g) {
- return v->g;
- } else if (p_index == CoreStringNames::singleton->b) {
- return v->b;
- } else if (p_index == CoreStringNames::singleton->a) {
- return v->a;
- } else if (p_index == CoreStringNames::singleton->r8) {
- return int(Math::round(v->r * 255.0));
- } else if (p_index == CoreStringNames::singleton->g8) {
- return int(Math::round(v->g * 255.0));
- } else if (p_index == CoreStringNames::singleton->b8) {
- return int(Math::round(v->b * 255.0));
- } else if (p_index == CoreStringNames::singleton->a8) {
- return int(Math::round(v->a * 255.0));
- } else if (p_index == CoreStringNames::singleton->h) {
- return v->get_h();
- } else if (p_index == CoreStringNames::singleton->s) {
- return v->get_s();
- } else if (p_index == CoreStringNames::singleton->v) {
- return v->get_v();
- }
- } break;
- case OBJECT: {
-#ifdef DEBUG_ENABLED
- if (!_get_obj().obj) {
- if (r_valid) {
- *r_valid = false;
- }
- return "Instance base is null.";
- } else {
- if (EngineDebugger::is_active() && !_get_obj().id.is_reference() && ObjectDB::get_instance(_get_obj().id) == nullptr) {
- if (r_valid) {
- *r_valid = false;
- }
- return "Attempted use of stray pointer object.";
- }
- }
-
-#endif
-
- return _get_obj().obj->get(p_index, r_valid);
-
- } break;
- default: {
- return get(p_index.operator String(), r_valid);
- }
- }
-
- if (r_valid) {
- *r_valid = false;
- }
- return Variant();
-}
-
-#define DEFAULT_OP_ARRAY_CMD(m_name, m_type, skip_test, cmd) \
- case m_name: { \
- skip_test; \
- \
- if (p_index.get_type() == Variant::INT || p_index.get_type() == Variant::FLOAT) { \
- int index = p_index; \
- m_type *arr = reinterpret_cast<m_type *>(_data._mem); \
- \
- if (index < 0) \
- index += arr->size(); \
- if (index >= 0 && index < arr->size()) { \
- valid = true; \
- cmd; \
- } \
- } \
- } break;
-
-#define DEFAULT_OP_DVECTOR_SET(m_name, m_type, skip_cond) \
- case m_name: { \
- if (skip_cond) \
- return; \
- \
- if (p_index.get_type() == Variant::INT || p_index.get_type() == Variant::FLOAT) { \
- int index = p_index; \
- Vector<m_type> *arr = PackedArrayRef<m_type>::get_array_ptr(_data.packed_array); \
- \
- if (index < 0) \
- index += arr->size(); \
- if (index >= 0 && index < arr->size()) { \
- valid = true; \
- arr->set(index, p_value); \
- } \
- } \
- } break;
-
-#define DEFAULT_OP_DVECTOR_GET(m_name, m_type) \
- case m_name: { \
- if (p_index.get_type() == Variant::INT || p_index.get_type() == Variant::FLOAT) { \
- int index = p_index; \
- const Vector<m_type> *arr = &PackedArrayRef<m_type>::get_array(_data.packed_array); \
- \
- if (index < 0) \
- index += arr->size(); \
- if (index >= 0 && index < arr->size()) { \
- valid = true; \
- return arr->get(index); \
- } \
- } \
- } break;
-
-void Variant::set(const Variant &p_index, const Variant &p_value, bool *r_valid) {
- static bool _dummy = false;
-
- bool &valid = r_valid ? *r_valid : _dummy;
- valid = false;
-
- switch (type) {
- case NIL: {
- return;
- } break;
- case BOOL: {
- return;
- } break;
- case INT: {
- return;
- } break;
- case FLOAT: {
- return;
- } break;
- case STRING: {
- if (p_index.type != Variant::INT && p_index.type != Variant::FLOAT) {
- return;
- }
-
- int idx = p_index;
- String *str = reinterpret_cast<String *>(_data._mem);
- int len = str->length();
- if (idx < 0) {
- idx += len;
- }
- if (idx < 0 || idx >= len) {
- return;
- }
-
- String chr;
- if (p_value.type == Variant::INT || p_value.type == Variant::FLOAT) {
- chr = String::chr(p_value);
- } else if (p_value.type == Variant::STRING) {
- chr = p_value;
- } else {
- return;
- }
-
- *str = str->substr(0, idx) + chr + str->substr(idx + 1, len);
- valid = true;
- return;
-
- } break;
- case VECTOR2: {
- if (p_value.type != Variant::INT && p_value.type != Variant::FLOAT) {
- return;
- }
-
- if (p_index.get_type() == Variant::INT || p_index.get_type() == Variant::FLOAT) {
- // scalar index
- int idx = p_index;
-
- if (idx < 0) {
- idx += 2;
- }
- if (idx >= 0 && idx < 2) {
- Vector2 *v = reinterpret_cast<Vector2 *>(_data._mem);
- valid = true;
- (*v)[idx] = p_value;
- return;
- }
- } else if (p_index.get_type() == Variant::STRING) {
- //scalar name
-
- const String *str = reinterpret_cast<const String *>(p_index._data._mem);
- Vector2 *v = reinterpret_cast<Vector2 *>(_data._mem);
- if (*str == "x") {
- valid = true;
- v->x = p_value;
- return;
- } else if (*str == "y") {
- valid = true;
- v->y = p_value;
- return;
- }
- }
-
- } break;
- case VECTOR2I: {
- if (p_value.type != Variant::INT && p_value.type != Variant::FLOAT) {
- return;
- }
-
- if (p_index.get_type() == Variant::INT || p_index.get_type() == Variant::FLOAT) {
- // scalar index
- int idx = p_index;
-
- if (idx < 0) {
- idx += 2;
- }
- if (idx >= 0 && idx < 2) {
- Vector2i *v = reinterpret_cast<Vector2i *>(_data._mem);
- valid = true;
- (*v)[idx] = p_value;
- return;
- }
- } else if (p_index.get_type() == Variant::STRING) {
- //scalar name
-
- const String *str = reinterpret_cast<const String *>(p_index._data._mem);
- Vector2i *v = reinterpret_cast<Vector2i *>(_data._mem);
- if (*str == "x") {
- valid = true;
- v->x = p_value;
- return;
- } else if (*str == "y") {
- valid = true;
- v->y = p_value;
- return;
- }
- }
-
- } break;
- case RECT2: {
- if (p_value.type != Variant::VECTOR2) {
- return;
- }
-
- if (p_index.get_type() == Variant::STRING) {
- //scalar name
-
- const String *str = reinterpret_cast<const String *>(p_index._data._mem);
- Rect2 *v = reinterpret_cast<Rect2 *>(_data._mem);
- if (*str == "position") {
- valid = true;
- v->position = p_value;
- return;
- } else if (*str == "size") {
- valid = true;
- v->size = p_value;
- return;
- } else if (*str == "end") {
- valid = true;
- v->size = Vector2(p_value) - v->position;
- return;
- }
- }
- } break;
- case RECT2I: {
- if (p_value.type != Variant::VECTOR2I) {
- return;
- }
-
- if (p_index.get_type() == Variant::STRING) {
- //scalar name
-
- const String *str = reinterpret_cast<const String *>(p_index._data._mem);
- Rect2i *v = reinterpret_cast<Rect2i *>(_data._mem);
- if (*str == "position") {
- valid = true;
- v->position = p_value;
- return;
- } else if (*str == "size") {
- valid = true;
- v->size = p_value;
- return;
- } else if (*str == "end") {
- valid = true;
- v->size = Vector2i(p_value) - v->position;
- return;
- }
- }
- } break;
- case TRANSFORM2D: {
- if (p_value.type != Variant::VECTOR2) {
- return;
- }
-
- if (p_index.get_type() == Variant::INT || p_index.get_type() == Variant::FLOAT) {
- int index = p_index;
-
- if (index < 0) {
- index += 3;
- }
- if (index >= 0 && index < 3) {
- Transform2D *v = _data._transform2d;
-
- valid = true;
- v->elements[index] = p_value;
- return;
- }
- } else if (p_index.get_type() == Variant::STRING && p_value.get_type() == Variant::VECTOR2) {
- //scalar name
- const String *str = reinterpret_cast<const String *>(p_index._data._mem);
- Transform2D *v = _data._transform2d;
- if (*str == "x") {
- valid = true;
- v->elements[0] = p_value;
- return;
- } else if (*str == "y") {
- valid = true;
- v->elements[1] = p_value;
- return;
- } else if (*str == "origin") {
- valid = true;
- v->elements[2] = p_value;
- return;
- }
- }
-
- } break;
- case VECTOR3: {
- if (p_value.type != Variant::INT && p_value.type != Variant::FLOAT) {
- return;
- }
-
- if (p_index.get_type() == Variant::INT || p_index.get_type() == Variant::FLOAT) {
- //scalar index
- int idx = p_index;
- if (idx < 0) {
- idx += 3;
- }
- if (idx >= 0 && idx < 3) {
- Vector3 *v = reinterpret_cast<Vector3 *>(_data._mem);
- valid = true;
- (*v)[idx] = p_value;
- return;
- }
- } else if (p_index.get_type() == Variant::STRING) {
- //scalar name
- const String *str = reinterpret_cast<const String *>(p_index._data._mem);
- Vector3 *v = reinterpret_cast<Vector3 *>(_data._mem);
- if (*str == "x") {
- valid = true;
- v->x = p_value;
- return;
- } else if (*str == "y") {
- valid = true;
- v->y = p_value;
- return;
- } else if (*str == "z") {
- valid = true;
- v->z = p_value;
- return;
- }
- }
-
- } break;
- case VECTOR3I: {
- if (p_value.type != Variant::INT && p_value.type != Variant::FLOAT) {
- return;
- }
-
- if (p_index.get_type() == Variant::INT || p_index.get_type() == Variant::FLOAT) {
- //scalar index
- int idx = p_index;
- if (idx < 0) {
- idx += 3;
- }
- if (idx >= 0 && idx < 3) {
- Vector3i *v = reinterpret_cast<Vector3i *>(_data._mem);
- valid = true;
- (*v)[idx] = p_value;
- return;
- }
- } else if (p_index.get_type() == Variant::STRING) {
- //scalar name
- const String *str = reinterpret_cast<const String *>(p_index._data._mem);
- Vector3i *v = reinterpret_cast<Vector3i *>(_data._mem);
- if (*str == "x") {
- valid = true;
- v->x = p_value;
- return;
- } else if (*str == "y") {
- valid = true;
- v->y = p_value;
- return;
- } else if (*str == "z") {
- valid = true;
- v->z = p_value;
- return;
- }
- }
-
- } break;
- case PLANE: {
- if (p_index.get_type() == Variant::STRING) {
- //scalar name
- const String *str = reinterpret_cast<const String *>(p_index._data._mem);
- Plane *v = reinterpret_cast<Plane *>(_data._mem);
- if (*str == "x") {
- if (p_value.type != Variant::INT && p_value.type != Variant::FLOAT) {
- return;
- }
-
- valid = true;
- v->normal.x = p_value;
- return;
- } else if (*str == "y") {
- if (p_value.type != Variant::INT && p_value.type != Variant::FLOAT) {
- return;
- }
-
- valid = true;
- v->normal.y = p_value;
- return;
- } else if (*str == "z") {
- if (p_value.type != Variant::INT && p_value.type != Variant::FLOAT) {
- return;
- }
-
- valid = true;
- v->normal.z = p_value;
- return;
- } else if (*str == "normal") {
- if (p_value.type != Variant::VECTOR3) {
- return;
- }
-
- valid = true;
- v->normal = p_value;
- return;
- } else if (*str == "d") {
- valid = true;
- v->d = p_value;
- return;
- }
- }
-
- } break;
- case QUAT: {
- if (p_value.type != Variant::INT && p_value.type != Variant::FLOAT) {
- return;
- }
-
- if (p_index.get_type() == Variant::STRING) {
- const String *str = reinterpret_cast<const String *>(p_index._data._mem);
- Quat *v = reinterpret_cast<Quat *>(_data._mem);
- if (*str == "x") {
- valid = true;
- v->x = p_value;
- return;
- } else if (*str == "y") {
- valid = true;
- v->y = p_value;
- return;
- } else if (*str == "z") {
- valid = true;
- v->z = p_value;
- return;
- } else if (*str == "w") {
- valid = true;
- v->w = p_value;
- return;
- }
- }
-
- } break;
- case AABB: {
- if (p_value.type != Variant::VECTOR3) {
- return;
- }
-
- if (p_index.get_type() == Variant::STRING) {
- //scalar name
-
- const String *str = reinterpret_cast<const String *>(p_index._data._mem);
- ::AABB *v = _data._aabb;
- if (*str == "position") {
- valid = true;
- v->position = p_value;
- return;
- } else if (*str == "size") {
- valid = true;
- v->size = p_value;
- return;
- } else if (*str == "end") {
- valid = true;
- v->size = Vector3(p_value) - v->position;
- return;
- }
- }
- } break;
- case BASIS: {
- if (p_value.type != Variant::VECTOR3) {
- return;
- }
-
- if (p_index.get_type() == Variant::INT || p_index.get_type() == Variant::FLOAT) {
- int index = p_index;
-
- if (index < 0) {
- index += 3;
- }
- if (index >= 0 && index < 3) {
- Basis *v = _data._basis;
-
- valid = true;
- v->set_axis(index, p_value);
- return;
- }
- } else if (p_index.get_type() == Variant::STRING) {
- const String *str = reinterpret_cast<const String *>(p_index._data._mem);
- Basis *v = _data._basis;
-
- if (*str == "x") {
- valid = true;
- v->set_axis(0, p_value);
- return;
- } else if (*str == "y") {
- valid = true;
- v->set_axis(1, p_value);
- return;
- } else if (*str == "z") {
- valid = true;
- v->set_axis(2, p_value);
- return;
- }
- }
-
- } break;
- case TRANSFORM: {
- if (p_index.get_type() == Variant::INT || p_index.get_type() == Variant::FLOAT) {
- if (p_value.type != Variant::VECTOR3) {
- return;
- }
-
- int index = p_index;
-
- if (index < 0) {
- index += 4;
- }
- if (index >= 0 && index < 4) {
- Transform *v = _data._transform;
- valid = true;
- if (index == 3) {
- v->origin = p_value;
- } else {
- v->basis.set_axis(index, p_value);
- }
- return;
- }
- } else if (p_index.get_type() == Variant::STRING) {
- Transform *v = _data._transform;
- const String *str = reinterpret_cast<const String *>(p_index._data._mem);
-
- if (*str == "basis") {
- if (p_value.type != Variant::BASIS) {
- return;
- }
- valid = true;
- v->basis = p_value;
- return;
- }
- if (*str == "origin") {
- if (p_value.type != Variant::VECTOR3) {
- return;
- }
- valid = true;
- v->origin = p_value;
- return;
- }
- }
-
- } break;
- case COLOR: {
- if (p_value.type != Variant::INT && p_value.type != Variant::FLOAT) {
- return;
- }
-
- if (p_index.get_type() == Variant::STRING) {
- const String *str = reinterpret_cast<const String *>(p_index._data._mem);
- Color *v = reinterpret_cast<Color *>(_data._mem);
- if (*str == "r") {
- valid = true;
- v->r = p_value;
- return;
- } else if (*str == "g") {
- valid = true;
- v->g = p_value;
- return;
- } else if (*str == "b") {
- valid = true;
- v->b = p_value;
- return;
- } else if (*str == "a") {
- valid = true;
- v->a = p_value;
- return;
- } else if (*str == "h") {
- valid = true;
- v->set_hsv(p_value, v->get_s(), v->get_v(), v->a);
- return;
- } else if (*str == "s") {
- valid = true;
- v->set_hsv(v->get_h(), p_value, v->get_v(), v->a);
- return;
- } else if (*str == "v") {
- valid = true;
- v->set_hsv(v->get_h(), v->get_s(), p_value, v->a);
- return;
- } else if (*str == "r8") {
- valid = true;
- v->r = float(p_value) / 255.0;
- return;
- } else if (*str == "g8") {
- valid = true;
- v->g = float(p_value) / 255.0;
- return;
- } else if (*str == "b8") {
- valid = true;
- v->b = float(p_value) / 255.0;
- return;
- } else if (*str == "a8") {
- valid = true;
- v->a = float(p_value) / 255.0;
- return;
- }
- } else if (p_index.get_type() == Variant::INT) {
- int idx = p_index;
- if (idx < 0) {
- idx += 4;
- }
- if (idx >= 0 && idx < 4) {
- Color *v = reinterpret_cast<Color *>(_data._mem);
- (*v)[idx] = p_value;
- valid = true;
- }
- }
-
- } break;
- case STRING_NAME: {
- } break;
- case NODE_PATH: {
- } break;
- case _RID: {
- } break;
- case OBJECT: {
- Object *obj = _get_obj().obj;
- //only if debugging!
-
- if (obj) {
-#ifdef DEBUG_ENABLED
- if (EngineDebugger::is_active() && !_get_obj().id.is_reference() && ObjectDB::get_instance(_get_obj().id) == nullptr) {
- WARN_PRINT("Attempted use of previously freed pointer object.");
- valid = false;
- return;
- }
-#endif
-
- if (p_index.get_type() != Variant::STRING_NAME && p_index.get_type() != Variant::STRING) {
- obj->setvar(p_index, p_value, r_valid);
- return;
- }
-
- obj->set(p_index, p_value, r_valid);
- return;
- }
- } break;
- case DICTIONARY: {
- Dictionary *dic = reinterpret_cast<Dictionary *>(_data._mem);
- dic->operator[](p_index) = p_value;
- valid = true; //always valid, i guess? should this really be ok?
- return;
- } break;
- DEFAULT_OP_ARRAY_CMD(ARRAY, Array, ;, (*arr)[index] = p_value; return )
- DEFAULT_OP_DVECTOR_SET(PACKED_BYTE_ARRAY, uint8_t, p_value.type != Variant::FLOAT && p_value.type != Variant::INT)
- DEFAULT_OP_DVECTOR_SET(PACKED_INT32_ARRAY, int32_t, p_value.type != Variant::FLOAT && p_value.type != Variant::INT)
- DEFAULT_OP_DVECTOR_SET(PACKED_INT64_ARRAY, int64_t, p_value.type != Variant::FLOAT && p_value.type != Variant::INT)
- DEFAULT_OP_DVECTOR_SET(PACKED_FLOAT32_ARRAY, float, p_value.type != Variant::FLOAT && p_value.type != Variant::INT)
- DEFAULT_OP_DVECTOR_SET(PACKED_FLOAT64_ARRAY, double, p_value.type != Variant::FLOAT && p_value.type != Variant::INT)
- DEFAULT_OP_DVECTOR_SET(PACKED_STRING_ARRAY, String, p_value.type != Variant::STRING)
- DEFAULT_OP_DVECTOR_SET(PACKED_VECTOR2_ARRAY, Vector2, p_value.type != Variant::VECTOR2)
- DEFAULT_OP_DVECTOR_SET(PACKED_VECTOR3_ARRAY, Vector3, p_value.type != Variant::VECTOR3)
- DEFAULT_OP_DVECTOR_SET(PACKED_COLOR_ARRAY, Color, p_value.type != Variant::COLOR)
- default:
- return;
- }
-}
-
-Variant Variant::get(const Variant &p_index, bool *r_valid) const {
- static bool _dummy = false;
-
- bool &valid = r_valid ? *r_valid : _dummy;
-
- valid = false;
-
- switch (type) {
- case NIL: {
- return Variant();
- } break;
- case BOOL: {
- return Variant();
- } break;
- case INT: {
- return Variant();
- } break;
- case FLOAT: {
- return Variant();
- } break;
- case STRING: {
- if (p_index.get_type() == Variant::INT || p_index.get_type() == Variant::FLOAT) {
- //string index
-
- int idx = p_index;
- const String *str = reinterpret_cast<const String *>(_data._mem);
- if (idx < 0) {
- idx += str->length();
- }
- if (idx >= 0 && idx < str->length()) {
- valid = true;
- return str->substr(idx, 1);
- }
- }
-
- } break;
- case VECTOR2: {
- if (p_index.get_type() == Variant::INT || p_index.get_type() == Variant::FLOAT) {
- // scalar index
- int idx = p_index;
- if (idx < 0) {
- idx += 2;
- }
- if (idx >= 0 && idx < 2) {
- const Vector2 *v = reinterpret_cast<const Vector2 *>(_data._mem);
- valid = true;
- return (*v)[idx];
- }
- } else if (p_index.get_type() == Variant::STRING) {
- //scalar name
-
- const String *str = reinterpret_cast<const String *>(p_index._data._mem);
- const Vector2 *v = reinterpret_cast<const Vector2 *>(_data._mem);
- if (*str == "x") {
- valid = true;
- return v->x;
- } else if (*str == "y") {
- valid = true;
- return v->y;
- }
- }
-
- } break;
- case VECTOR2I: {
- if (p_index.get_type() == Variant::INT || p_index.get_type() == Variant::FLOAT) {
- // scalar index
- int idx = p_index;
- if (idx < 0) {
- idx += 2;
- }
- if (idx >= 0 && idx < 2) {
- const Vector2i *v = reinterpret_cast<const Vector2i *>(_data._mem);
- valid = true;
- return (*v)[idx];
- }
- } else if (p_index.get_type() == Variant::STRING) {
- //scalar name
-
- const String *str = reinterpret_cast<const String *>(p_index._data._mem);
- const Vector2i *v = reinterpret_cast<const Vector2i *>(_data._mem);
- if (*str == "x") {
- valid = true;
- return v->x;
- } else if (*str == "y") {
- valid = true;
- return v->y;
- }
- }
-
- } break;
- case RECT2: {
- if (p_index.get_type() == Variant::STRING) {
- //scalar name
-
- const String *str = reinterpret_cast<const String *>(p_index._data._mem);
- const Rect2 *v = reinterpret_cast<const Rect2 *>(_data._mem);
- if (*str == "position") {
- valid = true;
- return v->position;
- } else if (*str == "size") {
- valid = true;
- return v->size;
- } else if (*str == "end") {
- valid = true;
- return v->size + v->position;
- }
- }
- } break;
- case RECT2I: {
- if (p_index.get_type() == Variant::STRING) {
- //scalar name
-
- const String *str = reinterpret_cast<const String *>(p_index._data._mem);
- const Rect2i *v = reinterpret_cast<const Rect2i *>(_data._mem);
- if (*str == "position") {
- valid = true;
- return v->position;
- } else if (*str == "size") {
- valid = true;
- return v->size;
- } else if (*str == "end") {
- valid = true;
- return v->size + v->position;
- }
- }
- } break;
- case VECTOR3: {
- if (p_index.get_type() == Variant::INT || p_index.get_type() == Variant::FLOAT) {
- //scalar index
- int idx = p_index;
- if (idx < 0) {
- idx += 3;
- }
- if (idx >= 0 && idx < 3) {
- const Vector3 *v = reinterpret_cast<const Vector3 *>(_data._mem);
- valid = true;
- return (*v)[idx];
- }
- } else if (p_index.get_type() == Variant::STRING) {
- //scalar name
- const String *str = reinterpret_cast<const String *>(p_index._data._mem);
- const Vector3 *v = reinterpret_cast<const Vector3 *>(_data._mem);
- if (*str == "x") {
- valid = true;
- return v->x;
- } else if (*str == "y") {
- valid = true;
- return v->y;
- } else if (*str == "z") {
- valid = true;
- return v->z;
- }
- }
-
- } break;
- case VECTOR3I: {
- if (p_index.get_type() == Variant::INT || p_index.get_type() == Variant::FLOAT) {
- //scalar index
- int idx = p_index;
- if (idx < 0) {
- idx += 3;
- }
- if (idx >= 0 && idx < 3) {
- const Vector3i *v = reinterpret_cast<const Vector3i *>(_data._mem);
- valid = true;
- return (*v)[idx];
- }
- } else if (p_index.get_type() == Variant::STRING) {
- //scalar name
- const String *str = reinterpret_cast<const String *>(p_index._data._mem);
- const Vector3i *v = reinterpret_cast<const Vector3i *>(_data._mem);
- if (*str == "x") {
- valid = true;
- return v->x;
- } else if (*str == "y") {
- valid = true;
- return v->y;
- } else if (*str == "z") {
- valid = true;
- return v->z;
- }
- }
-
- } break;
- case TRANSFORM2D: {
- if (p_index.get_type() == Variant::INT || p_index.get_type() == Variant::FLOAT) {
- int index = p_index;
-
- if (index < 0) {
- index += 3;
- }
- if (index >= 0 && index < 3) {
- const Transform2D *v = _data._transform2d;
-
- valid = true;
- return v->elements[index];
- }
- } else if (p_index.get_type() == Variant::STRING) {
- //scalar name
- const String *str = reinterpret_cast<const String *>(p_index._data._mem);
- const Transform2D *v = _data._transform2d;
- if (*str == "x") {
- valid = true;
- return v->elements[0];
- } else if (*str == "y") {
- valid = true;
- return v->elements[1];
- } else if (*str == "origin") {
- valid = true;
- return v->elements[2];
- }
- }
-
- } break;
- case PLANE: {
- if (p_index.get_type() == Variant::STRING) {
- //scalar name
- const String *str = reinterpret_cast<const String *>(p_index._data._mem);
- const Plane *v = reinterpret_cast<const Plane *>(_data._mem);
- if (*str == "x") {
- valid = true;
- return v->normal.x;
- } else if (*str == "y") {
- valid = true;
- return v->normal.y;
- } else if (*str == "z") {
- valid = true;
- return v->normal.z;
- } else if (*str == "normal") {
- valid = true;
- return v->normal;
- } else if (*str == "d") {
- valid = true;
- return v->d;
- }
- }
-
- } break;
- case QUAT: {
- if (p_index.get_type() == Variant::STRING) {
- const String *str = reinterpret_cast<const String *>(p_index._data._mem);
- const Quat *v = reinterpret_cast<const Quat *>(_data._mem);
- if (*str == "x") {
- valid = true;
- return v->x;
- } else if (*str == "y") {
- valid = true;
- return v->y;
- } else if (*str == "z") {
- valid = true;
- return v->z;
- } else if (*str == "w") {
- valid = true;
- return v->w;
- }
- }
-
- } break;
- case AABB: {
- if (p_index.get_type() == Variant::STRING) {
- //scalar name
-
- const String *str = reinterpret_cast<const String *>(p_index._data._mem);
- const ::AABB *v = _data._aabb;
- if (*str == "position") {
- valid = true;
- return v->position;
- } else if (*str == "size") {
- valid = true;
- return v->size;
- } else if (*str == "end") {
- valid = true;
- return v->size + v->position;
- }
- }
- } break;
- case BASIS: {
- if (p_index.get_type() == Variant::INT || p_index.get_type() == Variant::FLOAT) {
- int index = p_index;
- if (index < 0) {
- index += 3;
- }
- if (index >= 0 && index < 3) {
- const Basis *v = _data._basis;
-
- valid = true;
- return v->get_axis(index);
- }
- } else if (p_index.get_type() == Variant::STRING) {
- const String *str = reinterpret_cast<const String *>(p_index._data._mem);
- const Basis *v = _data._basis;
-
- if (*str == "x") {
- valid = true;
- return v->get_axis(0);
- } else if (*str == "y") {
- valid = true;
- return v->get_axis(1);
- } else if (*str == "z") {
- valid = true;
- return v->get_axis(2);
- }
- }
-
- } break;
- case TRANSFORM: {
- if (p_index.get_type() == Variant::INT || p_index.get_type() == Variant::FLOAT) {
- int index = p_index;
- if (index < 0) {
- index += 4;
- }
- if (index >= 0 && index < 4) {
- const Transform *v = _data._transform;
- valid = true;
- return index == 3 ? v->origin : v->basis.get_axis(index);
- }
- } else if (p_index.get_type() == Variant::STRING) {
- const Transform *v = _data._transform;
- const String *str = reinterpret_cast<const String *>(p_index._data._mem);
-
- if (*str == "basis") {
- valid = true;
- return v->basis;
- }
- if (*str == "origin") {
- valid = true;
- return v->origin;
- }
- }
-
- } break;
- case COLOR: {
- if (p_index.get_type() == Variant::STRING) {
- const String *str = reinterpret_cast<const String *>(p_index._data._mem);
- const Color *v = reinterpret_cast<const Color *>(_data._mem);
- if (*str == "r") {
- valid = true;
- return v->r;
- } else if (*str == "g") {
- valid = true;
- return v->g;
- } else if (*str == "b") {
- valid = true;
- return v->b;
- } else if (*str == "a") {
- valid = true;
- return v->a;
- } else if (*str == "h") {
- valid = true;
- return v->get_h();
- } else if (*str == "s") {
- valid = true;
- return v->get_s();
- } else if (*str == "v") {
- valid = true;
- return v->get_v();
- } else if (*str == "r8") {
- valid = true;
- return (int)Math::round(v->r * 255.0);
- } else if (*str == "g8") {
- valid = true;
- return (int)Math::round(v->g * 255.0);
- } else if (*str == "b8") {
- valid = true;
- return (int)Math::round(v->b * 255.0);
- } else if (*str == "a8") {
- valid = true;
- return (int)Math::round(v->a * 255.0);
- }
- } else if (p_index.get_type() == Variant::INT) {
- int idx = p_index;
- if (idx < 0) {
- idx += 4;
- }
- if (idx >= 0 && idx < 4) {
- const Color *v = reinterpret_cast<const Color *>(_data._mem);
- valid = true;
- return (*v)[idx];
- }
- }
-
- } break;
- case STRING_NAME: {
- } break;
- case NODE_PATH: {
- } break;
- case _RID: {
- } break;
- case OBJECT: {
- Object *obj = _get_obj().obj;
- if (obj) {
-#ifdef DEBUG_ENABLED
-
- if (EngineDebugger::is_active() && !_get_obj().id.is_reference() && ObjectDB::get_instance(_get_obj().id) == nullptr) {
- valid = false;
- return "Attempted get on previously freed instance.";
- }
-#endif
-
- if (p_index.get_type() != Variant::STRING) {
- return obj->getvar(p_index, r_valid);
- }
-
- return obj->get(p_index, r_valid);
- }
-
- } break;
- case DICTIONARY: {
- const Dictionary *dic = reinterpret_cast<const Dictionary *>(_data._mem);
- const Variant *res = dic->getptr(p_index);
- if (res) {
- valid = true;
- return *res;
- }
- } break;
- DEFAULT_OP_ARRAY_CMD(ARRAY, const Array, ;, return (*arr)[index])
- DEFAULT_OP_DVECTOR_GET(PACKED_BYTE_ARRAY, uint8_t)
- DEFAULT_OP_DVECTOR_GET(PACKED_INT32_ARRAY, int32_t)
- DEFAULT_OP_DVECTOR_GET(PACKED_INT64_ARRAY, int64_t)
- DEFAULT_OP_DVECTOR_GET(PACKED_FLOAT32_ARRAY, float)
- DEFAULT_OP_DVECTOR_GET(PACKED_FLOAT64_ARRAY, double)
- DEFAULT_OP_DVECTOR_GET(PACKED_STRING_ARRAY, String)
- DEFAULT_OP_DVECTOR_GET(PACKED_VECTOR2_ARRAY, Vector2)
- DEFAULT_OP_DVECTOR_GET(PACKED_VECTOR3_ARRAY, Vector3)
- DEFAULT_OP_DVECTOR_GET(PACKED_COLOR_ARRAY, Color)
- default:
- return Variant();
- }
-
- return Variant();
-}
-
-bool Variant::in(const Variant &p_index, bool *r_valid) const {
- if (r_valid) {
- *r_valid = true;
- }
-
- switch (type) {
- case STRING: {
- if (p_index.get_type() == Variant::STRING) {
- //string index
- String idx = p_index;
- const String *str = reinterpret_cast<const String *>(_data._mem);
-
- return str->find(idx) != -1;
- }
-
- } break;
- case OBJECT: {
- Object *obj = _get_obj().obj;
- if (obj) {
- bool valid = false;
-#ifdef DEBUG_ENABLED
-
- if (EngineDebugger::is_active() && !_get_obj().id.is_reference() && ObjectDB::get_instance(_get_obj().id) == nullptr) {
- if (r_valid) {
- *r_valid = false;
- }
- return true; // Attempted get on stray pointer.
- }
-
-#endif
-
- if (p_index.get_type() != Variant::STRING) {
- obj->getvar(p_index, &valid);
- } else {
- obj->get(p_index, &valid);
- }
-
- return valid;
- } else {
- if (r_valid) {
- *r_valid = false;
- }
- }
- return false;
- } break;
- case DICTIONARY: {
- const Dictionary *dic = reinterpret_cast<const Dictionary *>(_data._mem);
- return dic->has(p_index);
-
- } break;
- case ARRAY: {
- const Array *arr = reinterpret_cast<const Array *>(_data._mem);
- int l = arr->size();
- if (l) {
- for (int i = 0; i < l; i++) {
- if (evaluate(OP_EQUAL, (*arr)[i], p_index)) {
- return true;
- }
- }
- }
-
- return false;
-
- } break;
- case PACKED_BYTE_ARRAY: {
- if (p_index.get_type() == Variant::INT || p_index.get_type() == Variant::FLOAT) {
- int index = p_index;
- const Vector<uint8_t> *arr = &PackedArrayRef<uint8_t>::get_array(_data.packed_array);
- int l = arr->size();
- if (l) {
- const uint8_t *r = arr->ptr();
- for (int i = 0; i < l; i++) {
- if (r[i] == index) {
- return true;
- }
- }
- }
-
- return false;
- }
-
- } break;
- case PACKED_INT32_ARRAY: {
- if (p_index.get_type() == Variant::INT || p_index.get_type() == Variant::FLOAT) {
- int32_t index = p_index;
- const Vector<int32_t> *arr = &PackedArrayRef<int32_t>::get_array(_data.packed_array);
- int32_t l = arr->size();
- if (l) {
- const int32_t *r = arr->ptr();
- for (int32_t i = 0; i < l; i++) {
- if (r[i] == index) {
- return true;
- }
- }
- }
-
- return false;
- }
- } break;
- case PACKED_INT64_ARRAY: {
- if (p_index.get_type() == Variant::INT || p_index.get_type() == Variant::FLOAT) {
- int64_t index = p_index;
- const Vector<int64_t> *arr = &PackedArrayRef<int64_t>::get_array(_data.packed_array);
- int64_t l = arr->size();
- if (l) {
- const int64_t *r = arr->ptr();
- for (int64_t i = 0; i < l; i++) {
- if (r[i] == index) {
- return true;
- }
- }
- }
-
- return false;
- }
- } break;
- case PACKED_FLOAT32_ARRAY: {
- if (p_index.get_type() == Variant::INT || p_index.get_type() == Variant::FLOAT) {
- real_t index = p_index;
- const Vector<float> *arr = &PackedArrayRef<float>::get_array(_data.packed_array);
- int l = arr->size();
- if (l) {
- const float *r = arr->ptr();
- for (int i = 0; i < l; i++) {
- if (r[i] == index) {
- return true;
- }
- }
- }
-
- return false;
- }
-
- } break;
- case PACKED_FLOAT64_ARRAY: {
- if (p_index.get_type() == Variant::INT || p_index.get_type() == Variant::FLOAT) {
- real_t index = p_index;
- const Vector<double> *arr = &PackedArrayRef<double>::get_array(_data.packed_array);
- int l = arr->size();
- if (l) {
- const double *r = arr->ptr();
- for (int i = 0; i < l; i++) {
- if (r[i] == index) {
- return true;
- }
- }
- }
-
- return false;
- }
-
- } break;
- case PACKED_STRING_ARRAY: {
- if (p_index.get_type() == Variant::STRING) {
- String index = p_index;
- const Vector<String> *arr = &PackedArrayRef<String>::get_array(_data.packed_array);
-
- int l = arr->size();
- if (l) {
- const String *r = arr->ptr();
- for (int i = 0; i < l; i++) {
- if (r[i] == index) {
- return true;
- }
- }
- }
-
- return false;
- }
-
- } break; //25
- case PACKED_VECTOR2_ARRAY: {
- if (p_index.get_type() == Variant::VECTOR2) {
- Vector2 index = p_index;
- const Vector<Vector2> *arr = &PackedArrayRef<Vector2>::get_array(_data.packed_array);
-
- int l = arr->size();
- if (l) {
- const Vector2 *r = arr->ptr();
- for (int i = 0; i < l; i++) {
- if (r[i] == index) {
- return true;
- }
- }
- }
-
- return false;
- }
-
- } break;
- case PACKED_VECTOR3_ARRAY: {
- if (p_index.get_type() == Variant::VECTOR3) {
- Vector3 index = p_index;
- const Vector<Vector3> *arr = &PackedArrayRef<Vector3>::get_array(_data.packed_array);
-
- int l = arr->size();
- if (l) {
- const Vector3 *r = arr->ptr();
- for (int i = 0; i < l; i++) {
- if (r[i] == index) {
- return true;
- }
- }
- }
-
- return false;
- }
-
- } break;
- case PACKED_COLOR_ARRAY: {
- if (p_index.get_type() == Variant::COLOR) {
- Color index = p_index;
- const Vector<Color> *arr = &PackedArrayRef<Color>::get_array(_data.packed_array);
-
- int l = arr->size();
- if (l) {
- const Color *r = arr->ptr();
- for (int i = 0; i < l; i++) {
- if (r[i] == index) {
- return true;
- }
- }
- }
-
- return false;
- }
- } break;
- default: {
- }
- }
-
- if (r_valid) {
- *r_valid = false;
- }
- return false;
-}
-
-void Variant::get_property_list(List<PropertyInfo> *p_list) const {
- switch (type) {
- case VECTOR2: {
- p_list->push_back(PropertyInfo(Variant::FLOAT, "x"));
- p_list->push_back(PropertyInfo(Variant::FLOAT, "y"));
-
- } break;
- case VECTOR2I: {
- p_list->push_back(PropertyInfo(Variant::INT, "x"));
- p_list->push_back(PropertyInfo(Variant::INT, "y"));
-
- } break;
- case RECT2: {
- p_list->push_back(PropertyInfo(Variant::VECTOR2, "position"));
- p_list->push_back(PropertyInfo(Variant::VECTOR2, "size"));
- p_list->push_back(PropertyInfo(Variant::VECTOR2, "end"));
-
- } break;
- case RECT2I: {
- p_list->push_back(PropertyInfo(Variant::VECTOR2I, "position"));
- p_list->push_back(PropertyInfo(Variant::VECTOR2I, "size"));
- p_list->push_back(PropertyInfo(Variant::VECTOR2I, "end"));
-
- } break;
- case VECTOR3: {
- p_list->push_back(PropertyInfo(Variant::FLOAT, "x"));
- p_list->push_back(PropertyInfo(Variant::FLOAT, "y"));
- p_list->push_back(PropertyInfo(Variant::FLOAT, "z"));
-
- } break;
- case VECTOR3I: {
- p_list->push_back(PropertyInfo(Variant::INT, "x"));
- p_list->push_back(PropertyInfo(Variant::INT, "y"));
- p_list->push_back(PropertyInfo(Variant::INT, "z"));
-
- } break;
- case TRANSFORM2D: {
- p_list->push_back(PropertyInfo(Variant::VECTOR2, "x"));
- p_list->push_back(PropertyInfo(Variant::VECTOR2, "y"));
- p_list->push_back(PropertyInfo(Variant::VECTOR2, "origin"));
-
- } break;
- case PLANE: {
- p_list->push_back(PropertyInfo(Variant::VECTOR3, "normal"));
- p_list->push_back(PropertyInfo(Variant::FLOAT, "x"));
- p_list->push_back(PropertyInfo(Variant::FLOAT, "y"));
- p_list->push_back(PropertyInfo(Variant::FLOAT, "z"));
- p_list->push_back(PropertyInfo(Variant::FLOAT, "d"));
-
- } break;
- case QUAT: {
- p_list->push_back(PropertyInfo(Variant::FLOAT, "x"));
- p_list->push_back(PropertyInfo(Variant::FLOAT, "y"));
- p_list->push_back(PropertyInfo(Variant::FLOAT, "z"));
- p_list->push_back(PropertyInfo(Variant::FLOAT, "w"));
-
- } break;
- case AABB: {
- p_list->push_back(PropertyInfo(Variant::VECTOR3, "position"));
- p_list->push_back(PropertyInfo(Variant::VECTOR3, "size"));
- p_list->push_back(PropertyInfo(Variant::VECTOR3, "end"));
- } break;
- case BASIS: {
- p_list->push_back(PropertyInfo(Variant::VECTOR3, "x"));
- p_list->push_back(PropertyInfo(Variant::VECTOR3, "y"));
- p_list->push_back(PropertyInfo(Variant::VECTOR3, "z"));
-
- } break;
- case TRANSFORM: {
- p_list->push_back(PropertyInfo(Variant::BASIS, "basis"));
- p_list->push_back(PropertyInfo(Variant::VECTOR3, "origin"));
-
- } break;
- case COLOR: {
- p_list->push_back(PropertyInfo(Variant::FLOAT, "r"));
- p_list->push_back(PropertyInfo(Variant::FLOAT, "g"));
- p_list->push_back(PropertyInfo(Variant::FLOAT, "b"));
- p_list->push_back(PropertyInfo(Variant::FLOAT, "a"));
- p_list->push_back(PropertyInfo(Variant::FLOAT, "h"));
- p_list->push_back(PropertyInfo(Variant::FLOAT, "s"));
- p_list->push_back(PropertyInfo(Variant::FLOAT, "v"));
- p_list->push_back(PropertyInfo(Variant::INT, "r8"));
- p_list->push_back(PropertyInfo(Variant::INT, "g8"));
- p_list->push_back(PropertyInfo(Variant::INT, "b8"));
- p_list->push_back(PropertyInfo(Variant::INT, "a8"));
-
- } break;
- case STRING_NAME: {
- } break;
- case NODE_PATH: {
- } break;
- case _RID: {
- } break;
- case OBJECT: {
- Object *obj = _get_obj().obj;
- if (obj) {
-#ifdef DEBUG_ENABLED
-
- if (EngineDebugger::is_active() && !_get_obj().id.is_reference() && ObjectDB::get_instance(_get_obj().id) == nullptr) {
- WARN_PRINT("Attempted get_property list on previously freed instance.");
- return;
- }
-
-#endif
-
- obj->get_property_list(p_list);
- }
-
- } break;
- case DICTIONARY: {
- const Dictionary *dic = reinterpret_cast<const Dictionary *>(_data._mem);
- List<Variant> keys;
- dic->get_key_list(&keys);
- for (List<Variant>::Element *E = keys.front(); E; E = E->next()) {
- if (E->get().get_type() == Variant::STRING) {
- p_list->push_back(PropertyInfo(Variant::STRING, E->get()));
- }
- }
- } break;
- case ARRAY:
- case PACKED_BYTE_ARRAY:
- case PACKED_INT32_ARRAY:
- case PACKED_INT64_ARRAY:
- case PACKED_FLOAT32_ARRAY:
- case PACKED_FLOAT64_ARRAY:
- case PACKED_STRING_ARRAY:
- case PACKED_VECTOR2_ARRAY:
- case PACKED_VECTOR3_ARRAY:
- case PACKED_COLOR_ARRAY: {
- //nothing
- } break;
- default: {
- }
- }
-}
-
-bool Variant::iter_init(Variant &r_iter, bool &valid) const {
- valid = true;
- switch (type) {
- case INT: {
- r_iter = 0;
- return _data._int > 0;
- } break;
- case FLOAT: {
- r_iter = 0;
- return _data._float > 0.0;
- } break;
- case VECTOR2: {
- double from = reinterpret_cast<const Vector2 *>(_data._mem)->x;
- double to = reinterpret_cast<const Vector2 *>(_data._mem)->y;
-
- r_iter = from;
-
- return from < to;
- } break;
- case VECTOR2I: {
- int64_t from = reinterpret_cast<const Vector2i *>(_data._mem)->x;
- int64_t to = reinterpret_cast<const Vector2i *>(_data._mem)->y;
-
- r_iter = from;
-
- return from < to;
- } break;
- case VECTOR3: {
- double from = reinterpret_cast<const Vector3 *>(_data._mem)->x;
- double to = reinterpret_cast<const Vector3 *>(_data._mem)->y;
- double step = reinterpret_cast<const Vector3 *>(_data._mem)->z;
-
- r_iter = from;
-
- if (from == to) {
- return false;
- } else if (from < to) {
- return step > 0;
- }
- return step < 0;
- } break;
- case VECTOR3I: {
- int64_t from = reinterpret_cast<const Vector3i *>(_data._mem)->x;
- int64_t to = reinterpret_cast<const Vector3i *>(_data._mem)->y;
- int64_t step = reinterpret_cast<const Vector3i *>(_data._mem)->z;
-
- r_iter = from;
-
- if (from == to) {
- return false;
- } else if (from < to) {
- return step > 0;
- }
- return step < 0;
- } break;
- case OBJECT: {
- if (!_get_obj().obj) {
- valid = false;
- return false;
- }
-
-#ifdef DEBUG_ENABLED
-
- if (EngineDebugger::is_active() && !_get_obj().id.is_reference() && ObjectDB::get_instance(_get_obj().id) == nullptr) {
- valid = false;
- return false;
- }
-
-#endif
- Callable::CallError ce;
- ce.error = Callable::CallError::CALL_OK;
- Array ref;
- ref.push_back(r_iter);
- Variant vref = ref;
- const Variant *refp[] = { &vref };
- Variant ret = _get_obj().obj->call(CoreStringNames::get_singleton()->_iter_init, refp, 1, ce);
-
- if (ref.size() != 1 || ce.error != Callable::CallError::CALL_OK) {
- valid = false;
- return false;
- }
-
- r_iter = ref[0];
- return ret;
- } break;
-
- case STRING: {
- const String *str = reinterpret_cast<const String *>(_data._mem);
- if (str->empty()) {
- return false;
- }
- r_iter = 0;
- return true;
- } break;
- case DICTIONARY: {
- const Dictionary *dic = reinterpret_cast<const Dictionary *>(_data._mem);
- if (dic->empty()) {
- return false;
- }
-
- const Variant *next = dic->next(nullptr);
- r_iter = *next;
- return true;
-
- } break;
- case ARRAY: {
- const Array *arr = reinterpret_cast<const Array *>(_data._mem);
- if (arr->empty()) {
- return false;
- }
- r_iter = 0;
- return true;
- } break;
- case PACKED_BYTE_ARRAY: {
- const Vector<uint8_t> *arr = &PackedArrayRef<uint8_t>::get_array(_data.packed_array);
- if (arr->size() == 0) {
- return false;
- }
- r_iter = 0;
- return true;
-
- } break;
- case PACKED_INT32_ARRAY: {
- const Vector<int32_t> *arr = &PackedArrayRef<int32_t>::get_array(_data.packed_array);
- if (arr->size() == 0) {
- return false;
- }
- r_iter = 0;
- return true;
-
- } break;
- case PACKED_INT64_ARRAY: {
- const Vector<int64_t> *arr = &PackedArrayRef<int64_t>::get_array(_data.packed_array);
- if (arr->size() == 0) {
- return false;
- }
- r_iter = 0;
- return true;
-
- } break;
- case PACKED_FLOAT32_ARRAY: {
- const Vector<float> *arr = &PackedArrayRef<float>::get_array(_data.packed_array);
- if (arr->size() == 0) {
- return false;
- }
- r_iter = 0;
- return true;
-
- } break;
- case PACKED_FLOAT64_ARRAY: {
- const Vector<double> *arr = &PackedArrayRef<double>::get_array(_data.packed_array);
- if (arr->size() == 0) {
- return false;
- }
- r_iter = 0;
- return true;
-
- } break;
- case PACKED_STRING_ARRAY: {
- const Vector<String> *arr = &PackedArrayRef<String>::get_array(_data.packed_array);
- if (arr->size() == 0) {
- return false;
- }
- r_iter = 0;
- return true;
- } break;
- case PACKED_VECTOR2_ARRAY: {
- const Vector<Vector2> *arr = &PackedArrayRef<Vector2>::get_array(_data.packed_array);
- if (arr->size() == 0) {
- return false;
- }
- r_iter = 0;
- return true;
- } break;
- case PACKED_VECTOR3_ARRAY: {
- const Vector<Vector3> *arr = &PackedArrayRef<Vector3>::get_array(_data.packed_array);
- if (arr->size() == 0) {
- return false;
- }
- r_iter = 0;
- return true;
- } break;
- case PACKED_COLOR_ARRAY: {
- const Vector<Color> *arr = &PackedArrayRef<Color>::get_array(_data.packed_array);
- if (arr->size() == 0) {
- return false;
- }
- r_iter = 0;
- return true;
-
- } break;
- default: {
- }
- }
-
- valid = false;
- return false;
-}
-
-bool Variant::iter_next(Variant &r_iter, bool &valid) const {
- valid = true;
- switch (type) {
- case INT: {
- int64_t idx = r_iter;
- idx++;
- if (idx >= _data._int) {
- return false;
- }
- r_iter = idx;
- return true;
- } break;
- case FLOAT: {
- int64_t idx = r_iter;
- idx++;
- if (idx >= _data._float) {
- return false;
- }
- r_iter = idx;
- return true;
- } break;
- case VECTOR2: {
- double to = reinterpret_cast<const Vector2 *>(_data._mem)->y;
-
- double idx = r_iter;
- idx++;
-
- if (idx >= to) {
- return false;
- }
-
- r_iter = idx;
- return true;
- } break;
- case VECTOR2I: {
- int64_t to = reinterpret_cast<const Vector2i *>(_data._mem)->y;
-
- int64_t idx = r_iter;
- idx++;
-
- if (idx >= to) {
- return false;
- }
-
- r_iter = idx;
- return true;
- } break;
- case VECTOR3: {
- double to = reinterpret_cast<const Vector3 *>(_data._mem)->y;
- double step = reinterpret_cast<const Vector3 *>(_data._mem)->z;
-
- double idx = r_iter;
- idx += step;
-
- if (step < 0 && idx <= to) {
- return false;
- }
-
- if (step > 0 && idx >= to) {
- return false;
- }
-
- r_iter = idx;
- return true;
- } break;
- case VECTOR3I: {
- int64_t to = reinterpret_cast<const Vector3i *>(_data._mem)->y;
- int64_t step = reinterpret_cast<const Vector3i *>(_data._mem)->z;
-
- int64_t idx = r_iter;
- idx += step;
-
- if (step < 0 && idx <= to) {
- return false;
- }
-
- if (step > 0 && idx >= to) {
- return false;
- }
-
- r_iter = idx;
- return true;
- } break;
- case OBJECT: {
- if (!_get_obj().obj) {
- valid = false;
- return false;
- }
-
-#ifdef DEBUG_ENABLED
-
- if (EngineDebugger::is_active() && !_get_obj().id.is_reference() && ObjectDB::get_instance(_get_obj().id) == nullptr) {
- valid = false;
- return false;
- }
-
-#endif
- Callable::CallError ce;
- ce.error = Callable::CallError::CALL_OK;
- Array ref;
- ref.push_back(r_iter);
- Variant vref = ref;
- const Variant *refp[] = { &vref };
- Variant ret = _get_obj().obj->call(CoreStringNames::get_singleton()->_iter_next, refp, 1, ce);
-
- if (ref.size() != 1 || ce.error != Callable::CallError::CALL_OK) {
- valid = false;
- return false;
- }
-
- r_iter = ref[0];
-
- return ret;
- } break;
-
- case STRING: {
- const String *str = reinterpret_cast<const String *>(_data._mem);
- int idx = r_iter;
- idx++;
- if (idx >= str->length()) {
- return false;
- }
- r_iter = idx;
- return true;
- } break;
- case DICTIONARY: {
- const Dictionary *dic = reinterpret_cast<const Dictionary *>(_data._mem);
- const Variant *next = dic->next(&r_iter);
- if (!next) {
- return false;
- }
-
- r_iter = *next;
- return true;
-
- } break;
- case ARRAY: {
- const Array *arr = reinterpret_cast<const Array *>(_data._mem);
- int idx = r_iter;
- idx++;
- if (idx >= arr->size()) {
- return false;
- }
- r_iter = idx;
- return true;
- } break;
- case PACKED_BYTE_ARRAY: {
- const Vector<uint8_t> *arr = &PackedArrayRef<uint8_t>::get_array(_data.packed_array);
- int idx = r_iter;
- idx++;
- if (idx >= arr->size()) {
- return false;
- }
- r_iter = idx;
- return true;
-
- } break;
- case PACKED_INT32_ARRAY: {
- const Vector<int32_t> *arr = &PackedArrayRef<int32_t>::get_array(_data.packed_array);
- int32_t idx = r_iter;
- idx++;
- if (idx >= arr->size()) {
- return false;
- }
- r_iter = idx;
- return true;
-
- } break;
- case PACKED_INT64_ARRAY: {
- const Vector<int64_t> *arr = &PackedArrayRef<int64_t>::get_array(_data.packed_array);
- int64_t idx = r_iter;
- idx++;
- if (idx >= arr->size()) {
- return false;
- }
- r_iter = idx;
- return true;
-
- } break;
- case PACKED_FLOAT32_ARRAY: {
- const Vector<float> *arr = &PackedArrayRef<float>::get_array(_data.packed_array);
- int idx = r_iter;
- idx++;
- if (idx >= arr->size()) {
- return false;
- }
- r_iter = idx;
- return true;
-
- } break;
- case PACKED_FLOAT64_ARRAY: {
- const Vector<double> *arr = &PackedArrayRef<double>::get_array(_data.packed_array);
- int idx = r_iter;
- idx++;
- if (idx >= arr->size()) {
- return false;
- }
- r_iter = idx;
- return true;
-
- } break;
- case PACKED_STRING_ARRAY: {
- const Vector<String> *arr = &PackedArrayRef<String>::get_array(_data.packed_array);
- int idx = r_iter;
- idx++;
- if (idx >= arr->size()) {
- return false;
- }
- r_iter = idx;
- return true;
- } break;
- case PACKED_VECTOR2_ARRAY: {
- const Vector<Vector2> *arr = &PackedArrayRef<Vector2>::get_array(_data.packed_array);
- int idx = r_iter;
- idx++;
- if (idx >= arr->size()) {
- return false;
- }
- r_iter = idx;
- return true;
- } break;
- case PACKED_VECTOR3_ARRAY: {
- const Vector<Vector3> *arr = &PackedArrayRef<Vector3>::get_array(_data.packed_array);
- int idx = r_iter;
- idx++;
- if (idx >= arr->size()) {
- return false;
- }
- r_iter = idx;
- return true;
- } break;
- case PACKED_COLOR_ARRAY: {
- const Vector<Color> *arr = &PackedArrayRef<Color>::get_array(_data.packed_array);
- int idx = r_iter;
- idx++;
- if (idx >= arr->size()) {
- return false;
- }
- r_iter = idx;
- return true;
- } break;
- default: {
- }
- }
-
- valid = false;
- return false;
-}
-
-Variant Variant::iter_get(const Variant &r_iter, bool &r_valid) const {
- r_valid = true;
- switch (type) {
- case INT: {
- return r_iter;
- } break;
- case FLOAT: {
- return r_iter;
- } break;
- case VECTOR2: {
- return r_iter;
- } break;
- case VECTOR2I: {
- return r_iter;
- } break;
- case VECTOR3: {
- return r_iter;
- } break;
- case VECTOR3I: {
- return r_iter;
- } break;
- case OBJECT: {
- if (!_get_obj().obj) {
- r_valid = false;
- return Variant();
- }
-#ifdef DEBUG_ENABLED
- if (EngineDebugger::is_active() && !_get_obj().id.is_reference() && ObjectDB::get_instance(_get_obj().id) == nullptr) {
- r_valid = false;
- return Variant();
- }
-
-#endif
- Callable::CallError ce;
- ce.error = Callable::CallError::CALL_OK;
- const Variant *refp[] = { &r_iter };
- Variant ret = _get_obj().obj->call(CoreStringNames::get_singleton()->_iter_get, refp, 1, ce);
-
- if (ce.error != Callable::CallError::CALL_OK) {
- r_valid = false;
- return Variant();
- }
-
- //r_iter=ref[0];
-
- return ret;
- } break;
-
- case STRING: {
- const String *str = reinterpret_cast<const String *>(_data._mem);
- return str->substr(r_iter, 1);
- } break;
- case DICTIONARY: {
- return r_iter; //iterator is the same as the key
-
- } break;
- case ARRAY: {
- const Array *arr = reinterpret_cast<const Array *>(_data._mem);
- int idx = r_iter;
-#ifdef DEBUG_ENABLED
- if (idx < 0 || idx >= arr->size()) {
- r_valid = false;
- return Variant();
- }
-#endif
- return arr->get(idx);
- } break;
- case PACKED_BYTE_ARRAY: {
- const Vector<uint8_t> *arr = &PackedArrayRef<uint8_t>::get_array(_data.packed_array);
- int idx = r_iter;
-#ifdef DEBUG_ENABLED
- if (idx < 0 || idx >= arr->size()) {
- r_valid = false;
- return Variant();
- }
-#endif
- return arr->get(idx);
- } break;
- case PACKED_INT32_ARRAY: {
- const Vector<int32_t> *arr = &PackedArrayRef<int32_t>::get_array(_data.packed_array);
- int32_t idx = r_iter;
-#ifdef DEBUG_ENABLED
- if (idx < 0 || idx >= arr->size()) {
- r_valid = false;
- return Variant();
- }
-#endif
- return arr->get(idx);
- } break;
- case PACKED_INT64_ARRAY: {
- const Vector<int64_t> *arr = &PackedArrayRef<int64_t>::get_array(_data.packed_array);
- int64_t idx = r_iter;
-#ifdef DEBUG_ENABLED
- if (idx < 0 || idx >= arr->size()) {
- r_valid = false;
- return Variant();
- }
-#endif
- return arr->get(idx);
- } break;
- case PACKED_FLOAT32_ARRAY: {
- const Vector<float> *arr = &PackedArrayRef<float>::get_array(_data.packed_array);
- int idx = r_iter;
-#ifdef DEBUG_ENABLED
- if (idx < 0 || idx >= arr->size()) {
- r_valid = false;
- return Variant();
- }
-#endif
- return arr->get(idx);
- } break;
- case PACKED_FLOAT64_ARRAY: {
- const Vector<double> *arr = &PackedArrayRef<double>::get_array(_data.packed_array);
- int idx = r_iter;
-#ifdef DEBUG_ENABLED
- if (idx < 0 || idx >= arr->size()) {
- r_valid = false;
- return Variant();
- }
-#endif
- return arr->get(idx);
- } break;
- case PACKED_STRING_ARRAY: {
- const Vector<String> *arr = &PackedArrayRef<String>::get_array(_data.packed_array);
- int idx = r_iter;
-#ifdef DEBUG_ENABLED
- if (idx < 0 || idx >= arr->size()) {
- r_valid = false;
- return Variant();
- }
-#endif
- return arr->get(idx);
- } break;
- case PACKED_VECTOR2_ARRAY: {
- const Vector<Vector2> *arr = &PackedArrayRef<Vector2>::get_array(_data.packed_array);
- int idx = r_iter;
-#ifdef DEBUG_ENABLED
- if (idx < 0 || idx >= arr->size()) {
- r_valid = false;
- return Variant();
- }
-#endif
- return arr->get(idx);
- } break;
- case PACKED_VECTOR3_ARRAY: {
- const Vector<Vector3> *arr = &PackedArrayRef<Vector3>::get_array(_data.packed_array);
- int idx = r_iter;
-#ifdef DEBUG_ENABLED
- if (idx < 0 || idx >= arr->size()) {
- r_valid = false;
- return Variant();
- }
-#endif
- return arr->get(idx);
- } break;
- case PACKED_COLOR_ARRAY: {
- const Vector<Color> *arr = &PackedArrayRef<Color>::get_array(_data.packed_array);
- int idx = r_iter;
-#ifdef DEBUG_ENABLED
- if (idx < 0 || idx >= arr->size()) {
- r_valid = false;
- return Variant();
- }
-#endif
- return arr->get(idx);
- } break;
- default: {
- }
- }
-
- r_valid = false;
- return Variant();
-}
-
-Variant Variant::duplicate(bool deep) const {
- switch (type) {
- case OBJECT: {
- /* breaks stuff :(
- if (deep && !_get_obj().ref.is_null()) {
- Ref<Resource> resource = _get_obj().ref;
- if (resource.is_valid()) {
- return resource->duplicate(true);
- }
- }
- */
- return *this;
- } break;
- case DICTIONARY:
- return operator Dictionary().duplicate(deep);
- case ARRAY:
- return operator Array().duplicate(deep);
- default:
- return *this;
- }
-}
-
-void Variant::blend(const Variant &a, const Variant &b, float c, Variant &r_dst) {
- if (a.type != b.type) {
- if (a.is_num() && b.is_num()) {
- real_t va = a;
- real_t vb = b;
- r_dst = va + vb * c;
- } else {
- r_dst = a;
- }
- return;
- }
-
- switch (a.type) {
- case NIL: {
- r_dst = Variant();
- }
- return;
- case INT: {
- int64_t va = a._data._int;
- int64_t vb = b._data._int;
- r_dst = int(va + vb * c + 0.5);
- }
- return;
- case FLOAT: {
- double ra = a._data._float;
- double rb = b._data._float;
- r_dst = ra + rb * c;
- }
- return;
- case VECTOR2: {
- r_dst = *reinterpret_cast<const Vector2 *>(a._data._mem) + *reinterpret_cast<const Vector2 *>(b._data._mem) * c;
- }
- return;
- case VECTOR2I: {
- int32_t vax = reinterpret_cast<const Vector2i *>(a._data._mem)->x;
- int32_t vbx = reinterpret_cast<const Vector2i *>(b._data._mem)->x;
- int32_t vay = reinterpret_cast<const Vector2i *>(a._data._mem)->y;
- int32_t vby = reinterpret_cast<const Vector2i *>(b._data._mem)->y;
- r_dst = Vector2i(int32_t(vax + vbx * c + 0.5), int32_t(vay + vby * c + 0.5));
- }
- return;
- case RECT2: {
- const Rect2 *ra = reinterpret_cast<const Rect2 *>(a._data._mem);
- const Rect2 *rb = reinterpret_cast<const Rect2 *>(b._data._mem);
- r_dst = Rect2(ra->position + rb->position * c, ra->size + rb->size * c);
- }
- return;
- case RECT2I: {
- const Rect2i *ra = reinterpret_cast<const Rect2i *>(a._data._mem);
- const Rect2i *rb = reinterpret_cast<const Rect2i *>(b._data._mem);
-
- int32_t vax = ra->position.x;
- int32_t vay = ra->position.y;
- int32_t vbx = ra->size.x;
- int32_t vby = ra->size.y;
- int32_t vcx = rb->position.x;
- int32_t vcy = rb->position.y;
- int32_t vdx = rb->size.x;
- int32_t vdy = rb->size.y;
-
- r_dst = Rect2i(int32_t(vax + vbx * c + 0.5), int32_t(vay + vby * c + 0.5), int32_t(vcx + vdx * c + 0.5), int32_t(vcy + vdy * c + 0.5));
- }
- return;
- case VECTOR3: {
- r_dst = *reinterpret_cast<const Vector3 *>(a._data._mem) + *reinterpret_cast<const Vector3 *>(b._data._mem) * c;
- }
- return;
- case VECTOR3I: {
- int32_t vax = reinterpret_cast<const Vector3i *>(a._data._mem)->x;
- int32_t vbx = reinterpret_cast<const Vector3i *>(b._data._mem)->x;
- int32_t vay = reinterpret_cast<const Vector3i *>(a._data._mem)->y;
- int32_t vby = reinterpret_cast<const Vector3i *>(b._data._mem)->y;
- int32_t vaz = reinterpret_cast<const Vector3i *>(a._data._mem)->z;
- int32_t vbz = reinterpret_cast<const Vector3i *>(b._data._mem)->z;
- r_dst = Vector3i(int32_t(vax + vbx * c + 0.5), int32_t(vay + vby * c + 0.5), int32_t(vaz + vbz * c + 0.5));
- }
- return;
- case AABB: {
- const ::AABB *ra = reinterpret_cast<const ::AABB *>(a._data._mem);
- const ::AABB *rb = reinterpret_cast<const ::AABB *>(b._data._mem);
- r_dst = ::AABB(ra->position + rb->position * c, ra->size + rb->size * c);
- }
- return;
- case QUAT: {
- Quat empty_rot;
- const Quat *qa = reinterpret_cast<const Quat *>(a._data._mem);
- const Quat *qb = reinterpret_cast<const Quat *>(b._data._mem);
- r_dst = *qa * empty_rot.slerp(*qb, c);
- }
- return;
- case COLOR: {
- const Color *ca = reinterpret_cast<const Color *>(a._data._mem);
- const Color *cb = reinterpret_cast<const Color *>(b._data._mem);
- float new_r = ca->r + cb->r * c;
- float new_g = ca->g + cb->g * c;
- float new_b = ca->b + cb->b * c;
- float new_a = ca->a + cb->a * c;
- new_r = new_r > 1.0 ? 1.0 : new_r;
- new_g = new_g > 1.0 ? 1.0 : new_g;
- new_b = new_b > 1.0 ? 1.0 : new_b;
- new_a = new_a > 1.0 ? 1.0 : new_a;
- r_dst = Color(new_r, new_g, new_b, new_a);
- }
- return;
- default: {
- r_dst = c < 0.5 ? a : b;
- }
- return;
- }
-}
-
-void Variant::interpolate(const Variant &a, const Variant &b, float c, Variant &r_dst) {
- if (a.type != b.type) {
- if (a.is_num() && b.is_num()) {
- //not as efficient but..
- real_t va = a;
- real_t vb = b;
- r_dst = va + (vb - va) * c;
-
- } else {
- r_dst = a;
- }
- return;
- }
-
- switch (a.type) {
- case NIL: {
- r_dst = Variant();
- }
- return;
- case BOOL: {
- r_dst = a;
- }
- return;
- case INT: {
- int64_t va = a._data._int;
- int64_t vb = b._data._int;
- r_dst = int(va + (vb - va) * c);
- }
- return;
- case FLOAT: {
- real_t va = a._data._float;
- real_t vb = b._data._float;
- r_dst = va + (vb - va) * c;
- }
- return;
- case STRING: {
- //this is pretty funny and bizarre, but artists like to use it for typewritter effects
- String sa = *reinterpret_cast<const String *>(a._data._mem);
- String sb = *reinterpret_cast<const String *>(b._data._mem);
- String dst;
- int sa_len = sa.length();
- int sb_len = sb.length();
- int csize = sa_len + (sb_len - sa_len) * c;
- if (csize == 0) {
- r_dst = "";
- return;
- }
- dst.resize(csize + 1);
- dst[csize] = 0;
- int split = csize / 2;
-
- for (int i = 0; i < csize; i++) {
- CharType chr = ' ';
-
- if (i < split) {
- if (i < sa.length()) {
- chr = sa[i];
- } else if (i < sb.length()) {
- chr = sb[i];
- }
-
- } else {
- if (i < sb.length()) {
- chr = sb[i];
- } else if (i < sa.length()) {
- chr = sa[i];
- }
- }
-
- dst[i] = chr;
- }
-
- r_dst = dst;
- }
- return;
- case VECTOR2: {
- r_dst = reinterpret_cast<const Vector2 *>(a._data._mem)->lerp(*reinterpret_cast<const Vector2 *>(b._data._mem), c);
- }
- return;
- case VECTOR2I: {
- int32_t vax = reinterpret_cast<const Vector2i *>(a._data._mem)->x;
- int32_t vbx = reinterpret_cast<const Vector2i *>(b._data._mem)->x;
- int32_t vay = reinterpret_cast<const Vector2i *>(a._data._mem)->y;
- int32_t vby = reinterpret_cast<const Vector2i *>(b._data._mem)->y;
- r_dst = Vector2i(int32_t(vax + vbx * c + 0.5), int32_t(vay + vby * c + 0.5));
- }
- return;
-
- case RECT2: {
- r_dst = Rect2(reinterpret_cast<const Rect2 *>(a._data._mem)->position.lerp(reinterpret_cast<const Rect2 *>(b._data._mem)->position, c), reinterpret_cast<const Rect2 *>(a._data._mem)->size.lerp(reinterpret_cast<const Rect2 *>(b._data._mem)->size, c));
- }
- return;
- case RECT2I: {
- const Rect2i *ra = reinterpret_cast<const Rect2i *>(a._data._mem);
- const Rect2i *rb = reinterpret_cast<const Rect2i *>(b._data._mem);
-
- int32_t vax = ra->position.x;
- int32_t vay = ra->position.y;
- int32_t vbx = ra->size.x;
- int32_t vby = ra->size.y;
- int32_t vcx = rb->position.x;
- int32_t vcy = rb->position.y;
- int32_t vdx = rb->size.x;
- int32_t vdy = rb->size.y;
-
- r_dst = Rect2i(int32_t(vax + vbx * c + 0.5), int32_t(vay + vby * c + 0.5), int32_t(vcx + vdx * c + 0.5), int32_t(vcy + vdy * c + 0.5));
- }
- return;
-
- case VECTOR3: {
- r_dst = reinterpret_cast<const Vector3 *>(a._data._mem)->lerp(*reinterpret_cast<const Vector3 *>(b._data._mem), c);
- }
- return;
- case VECTOR3I: {
- int32_t vax = reinterpret_cast<const Vector3i *>(a._data._mem)->x;
- int32_t vbx = reinterpret_cast<const Vector3i *>(b._data._mem)->x;
- int32_t vay = reinterpret_cast<const Vector3i *>(a._data._mem)->y;
- int32_t vby = reinterpret_cast<const Vector3i *>(b._data._mem)->y;
- int32_t vaz = reinterpret_cast<const Vector3i *>(a._data._mem)->z;
- int32_t vbz = reinterpret_cast<const Vector3i *>(b._data._mem)->z;
- r_dst = Vector3i(int32_t(vax + vbx * c + 0.5), int32_t(vay + vby * c + 0.5), int32_t(vaz + vbz * c + 0.5));
- }
- return;
-
- case TRANSFORM2D: {
- r_dst = a._data._transform2d->interpolate_with(*b._data._transform2d, c);
- }
- return;
- case PLANE: {
- r_dst = a;
- }
- return;
- case QUAT: {
- r_dst = reinterpret_cast<const Quat *>(a._data._mem)->slerp(*reinterpret_cast<const Quat *>(b._data._mem), c);
- }
- return;
- case AABB: {
- r_dst = ::AABB(a._data._aabb->position.lerp(b._data._aabb->position, c), a._data._aabb->size.lerp(b._data._aabb->size, c));
- }
- return;
- case BASIS: {
- r_dst = Transform(*a._data._basis).interpolate_with(Transform(*b._data._basis), c).basis;
- }
- return;
- case TRANSFORM: {
- r_dst = a._data._transform->interpolate_with(*b._data._transform, c);
- }
- return;
- case COLOR: {
- r_dst = reinterpret_cast<const Color *>(a._data._mem)->lerp(*reinterpret_cast<const Color *>(b._data._mem), c);
- }
- return;
- case STRING_NAME: {
- r_dst = a;
- }
- return;
- case NODE_PATH: {
- r_dst = a;
- }
- return;
- case _RID: {
- r_dst = a;
- }
- return;
- case OBJECT: {
- r_dst = a;
- }
- return;
- case DICTIONARY: {
- }
- return;
- case ARRAY: {
- r_dst = a;
- }
- return;
- case PACKED_BYTE_ARRAY: {
- r_dst = a;
- }
- return;
- case PACKED_INT32_ARRAY: {
- const Vector<int32_t> *arr_a = &PackedArrayRef<int32_t>::get_array(a._data.packed_array);
- const Vector<int32_t> *arr_b = &PackedArrayRef<int32_t>::get_array(b._data.packed_array);
- int32_t sz = arr_a->size();
- if (sz == 0 || arr_b->size() != sz) {
- r_dst = a;
- } else {
- Vector<int32_t> v;
- v.resize(sz);
- {
- int32_t *vw = v.ptrw();
- const int32_t *ar = arr_a->ptr();
- const int32_t *br = arr_b->ptr();
-
- Variant va;
- for (int32_t i = 0; i < sz; i++) {
- Variant::interpolate(ar[i], br[i], c, va);
- vw[i] = va;
- }
- }
- r_dst = v;
- }
- }
- return;
- case PACKED_INT64_ARRAY: {
- const Vector<int64_t> *arr_a = &PackedArrayRef<int64_t>::get_array(a._data.packed_array);
- const Vector<int64_t> *arr_b = &PackedArrayRef<int64_t>::get_array(b._data.packed_array);
- int64_t sz = arr_a->size();
- if (sz == 0 || arr_b->size() != sz) {
- r_dst = a;
- } else {
- Vector<int64_t> v;
- v.resize(sz);
- {
- int64_t *vw = v.ptrw();
- const int64_t *ar = arr_a->ptr();
- const int64_t *br = arr_b->ptr();
-
- Variant va;
- for (int64_t i = 0; i < sz; i++) {
- Variant::interpolate(ar[i], br[i], c, va);
- vw[i] = va;
- }
- }
- r_dst = v;
- }
- }
- return;
- case PACKED_FLOAT32_ARRAY: {
- const Vector<float> *arr_a = &PackedArrayRef<float>::get_array(a._data.packed_array);
- const Vector<float> *arr_b = &PackedArrayRef<float>::get_array(b._data.packed_array);
- int sz = arr_a->size();
- if (sz == 0 || arr_b->size() != sz) {
- r_dst = a;
- } else {
- Vector<float> v;
- v.resize(sz);
- {
- float *vw = v.ptrw();
- const float *ar = arr_a->ptr();
- const float *br = arr_b->ptr();
-
- Variant va;
- for (int i = 0; i < sz; i++) {
- Variant::interpolate(ar[i], br[i], c, va);
- vw[i] = va;
- }
- }
- r_dst = v;
- }
- }
- return;
- case PACKED_FLOAT64_ARRAY: {
- const Vector<double> *arr_a = &PackedArrayRef<double>::get_array(a._data.packed_array);
- const Vector<double> *arr_b = &PackedArrayRef<double>::get_array(b._data.packed_array);
- int sz = arr_a->size();
- if (sz == 0 || arr_b->size() != sz) {
- r_dst = a;
- } else {
- Vector<double> v;
- v.resize(sz);
- {
- double *vw = v.ptrw();
- const double *ar = arr_a->ptr();
- const double *br = arr_b->ptr();
-
- Variant va;
- for (int i = 0; i < sz; i++) {
- Variant::interpolate(ar[i], br[i], c, va);
- vw[i] = va;
- }
- }
- r_dst = v;
- }
- }
- return;
- case PACKED_STRING_ARRAY: {
- r_dst = a;
- }
- return;
- case PACKED_VECTOR2_ARRAY: {
- const Vector<Vector2> *arr_a = &PackedArrayRef<Vector2>::get_array(a._data.packed_array);
- const Vector<Vector2> *arr_b = &PackedArrayRef<Vector2>::get_array(b._data.packed_array);
- int sz = arr_a->size();
- if (sz == 0 || arr_b->size() != sz) {
- r_dst = a;
- } else {
- Vector<Vector2> v;
- v.resize(sz);
- {
- Vector2 *vw = v.ptrw();
- const Vector2 *ar = arr_a->ptr();
- const Vector2 *br = arr_b->ptr();
-
- for (int i = 0; i < sz; i++) {
- vw[i] = ar[i].lerp(br[i], c);
- }
- }
- r_dst = v;
- }
- }
- return;
- case PACKED_VECTOR3_ARRAY: {
- const Vector<Vector3> *arr_a = &PackedArrayRef<Vector3>::get_array(a._data.packed_array);
- const Vector<Vector3> *arr_b = &PackedArrayRef<Vector3>::get_array(b._data.packed_array);
- int sz = arr_a->size();
- if (sz == 0 || arr_b->size() != sz) {
- r_dst = a;
- } else {
- Vector<Vector3> v;
- v.resize(sz);
- {
- Vector3 *vw = v.ptrw();
- const Vector3 *ar = arr_a->ptr();
- const Vector3 *br = arr_b->ptr();
-
- for (int i = 0; i < sz; i++) {
- vw[i] = ar[i].lerp(br[i], c);
- }
- }
- r_dst = v;
- }
- }
- return;
- case PACKED_COLOR_ARRAY: {
- const Vector<Color> *arr_a = &PackedArrayRef<Color>::get_array(a._data.packed_array);
- const Vector<Color> *arr_b = &PackedArrayRef<Color>::get_array(b._data.packed_array);
- int sz = arr_a->size();
- if (sz == 0 || arr_b->size() != sz) {
- r_dst = a;
- } else {
- Vector<Color> v;
- v.resize(sz);
- {
- Color *vw = v.ptrw();
- const Color *ar = arr_a->ptr();
- const Color *br = arr_b->ptr();
-
- for (int i = 0; i < sz; i++) {
- vw[i] = ar[i].lerp(br[i], c);
- }
- }
- r_dst = v;
- }
- }
- return;
- default: {
- r_dst = a;
- }
- }
-}
-
-static const char *_op_names[Variant::OP_MAX] = {
- "==",
- "!=",
- "<",
- "<=",
- ">",
- ">=",
- "+",
- "-",
- "*",
- "/",
- "- (negation)",
- "+ (positive)",
- "%",
- "+ (concatenation)",
- "<<",
- ">>",
- "&",
- "|",
- "^",
- "~",
- "and",
- "or",
- "xor",
- "not",
- "in"
-
-};
-
-String Variant::get_operator_name(Operator p_op) {
- ERR_FAIL_INDEX_V(p_op, OP_MAX, "");
- return _op_names[p_op];
-}