diff options
Diffstat (limited to 'core')
-rw-r--r-- | core/SCsub | 39 | ||||
-rw-r--r-- | core/bind/SCsub | 5 | ||||
-rw-r--r-- | core/color_names.inc | 155 | ||||
-rw-r--r-- | core/config/SCsub | 7 | ||||
-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.py | 6 | ||||
-rw-r--r-- | core/core_constants.cpp | 657 | ||||
-rw-r--r-- | core/core_constants.h (renamed from core/global_constants.h) | 11 | ||||
-rw-r--r-- | core/core_string_names.cpp | 2 | ||||
-rw-r--r-- | core/core_string_names.h | 4 | ||||
-rw-r--r-- | core/crypto/aes_context.cpp | 1 | ||||
-rw-r--r-- | core/crypto/aes_context.h | 4 | ||||
-rw-r--r-- | core/crypto/crypto.cpp | 2 | ||||
-rw-r--r-- | core/crypto/crypto.h | 4 | ||||
-rw-r--r-- | core/crypto/crypto_core.cpp | 20 | ||||
-rw-r--r-- | core/crypto/crypto_core.h | 12 | ||||
-rw-r--r-- | core/crypto/hashing_context.h | 4 | ||||
-rw-r--r-- | core/debugger/debugger_marshalls.cpp | 2 | ||||
-rw-r--r-- | core/debugger/debugger_marshalls.h | 4 | ||||
-rw-r--r-- | core/debugger/engine_debugger.h | 12 | ||||
-rw-r--r-- | core/debugger/local_debugger.h | 4 | ||||
-rw-r--r-- | core/debugger/remote_debugger.cpp | 4 | ||||
-rw-r--r-- | core/debugger/remote_debugger.h | 8 | ||||
-rw-r--r-- | core/debugger/remote_debugger_peer.cpp | 2 | ||||
-rw-r--r-- | core/debugger/remote_debugger_peer.h | 4 | ||||
-rw-r--r-- | core/debugger/script_debugger.h | 10 | ||||
-rw-r--r-- | core/error/SCsub | 7 | ||||
-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.cpp | 93 | ||||
-rw-r--r-- | core/func_ref.h | 54 | ||||
-rw-r--r-- | core/global_constants.cpp | 663 | ||||
-rw-r--r-- | core/input/SCsub | 3 | ||||
-rw-r--r-- | core/input/gamecontrollerdb.txt | 125 | ||||
-rw-r--r-- | core/input/input.cpp | 340 | ||||
-rw-r--r-- | core/input/input.h | 18 | ||||
-rw-r--r-- | core/input/input_event.cpp | 91 | ||||
-rw-r--r-- | core/input/input_event.h | 148 | ||||
-rw-r--r-- | core/input/input_map.cpp | 32 | ||||
-rw-r--r-- | core/input/input_map.h | 9 | ||||
-rw-r--r-- | core/int_types.h | 62 | ||||
-rw-r--r-- | core/io/compression.cpp | 89 | ||||
-rw-r--r-- | core/io/compression.h | 3 | ||||
-rw-r--r-- | core/io/config_file.cpp | 2 | ||||
-rw-r--r-- | core/io/config_file.h | 6 | ||||
-rw-r--r-- | core/io/dtls_server.cpp | 2 | ||||
-rw-r--r-- | core/io/file_access_buffered.cpp | 2 | ||||
-rw-r--r-- | core/io/file_access_buffered.h | 2 | ||||
-rw-r--r-- | core/io/file_access_compressed.cpp | 2 | ||||
-rw-r--r-- | core/io/file_access_encrypted.cpp | 77 | ||||
-rw-r--r-- | core/io/file_access_encrypted.h | 13 | ||||
-rw-r--r-- | core/io/file_access_memory.cpp | 4 | ||||
-rw-r--r-- | core/io/file_access_memory.h | 4 | ||||
-rw-r--r-- | core/io/file_access_network.cpp | 2 | ||||
-rw-r--r-- | core/io/file_access_pack.cpp | 112 | ||||
-rw-r--r-- | core/io/file_access_pack.h | 50 | ||||
-rw-r--r-- | core/io/file_access_zip.cpp | 12 | ||||
-rw-r--r-- | core/io/file_access_zip.h | 14 | ||||
-rw-r--r-- | core/io/http_client.cpp | 65 | ||||
-rw-r--r-- | core/io/http_client.h | 9 | ||||
-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.cpp | 2 | ||||
-rw-r--r-- | core/io/image_loader.h | 6 | ||||
-rw-r--r-- | core/io/ip.cpp | 2 | ||||
-rw-r--r-- | core/io/ip.h | 2 | ||||
-rw-r--r-- | core/io/ip_address.cpp | 5 | ||||
-rw-r--r-- | core/io/ip_address.h | 2 | ||||
-rw-r--r-- | core/io/json.cpp | 58 | ||||
-rw-r--r-- | core/io/json.h | 34 | ||||
-rw-r--r-- | core/io/logger.cpp | 4 | ||||
-rw-r--r-- | core/io/logger.h | 4 | ||||
-rw-r--r-- | core/io/marshalls.cpp | 8 | ||||
-rw-r--r-- | core/io/marshalls.h | 4 | ||||
-rw-r--r-- | core/io/multiplayer_api.h | 3 | ||||
-rw-r--r-- | core/io/net_socket.h | 2 | ||||
-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.cpp | 2 | ||||
-rw-r--r-- | core/io/packet_peer.h | 12 | ||||
-rw-r--r-- | core/io/packet_peer_dtls.cpp | 2 | ||||
-rw-r--r-- | core/io/packet_peer_udp.cpp | 66 | ||||
-rw-r--r-- | core/io/packet_peer_udp.h | 15 | ||||
-rw-r--r-- | core/io/pck_packer.cpp | 191 | ||||
-rw-r--r-- | core/io/pck_packer.h | 18 | ||||
-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.cpp | 15 | ||||
-rw-r--r-- | core/io/resource_importer.cpp | 5 | ||||
-rw-r--r-- | core/io/resource_loader.cpp | 16 | ||||
-rw-r--r-- | core/io/resource_loader.h | 2 | ||||
-rw-r--r-- | core/io/resource_saver.cpp | 6 | ||||
-rw-r--r-- | core/io/resource_saver.h | 3 | ||||
-rw-r--r-- | core/io/stream_peer.h | 12 | ||||
-rw-r--r-- | core/io/stream_peer_ssl.cpp | 2 | ||||
-rw-r--r-- | core/io/stream_peer_tcp.cpp | 2 | ||||
-rw-r--r-- | core/io/stream_peer_tcp.h | 11 | ||||
-rw-r--r-- | core/io/translation_loader_po.cpp | 130 | ||||
-rw-r--r-- | core/io/translation_loader_po.h | 2 | ||||
-rw-r--r-- | core/io/udp_server.cpp | 100 | ||||
-rw-r--r-- | core/io/udp_server.h | 29 | ||||
-rw-r--r-- | core/io/xml_parser.cpp | 6 | ||||
-rw-r--r-- | core/io/xml_parser.h | 6 | ||||
-rw-r--r-- | core/make_binders.py | 390 | ||||
-rw-r--r-- | core/math/a_star.cpp | 2 | ||||
-rw-r--r-- | core/math/a_star.h | 20 | ||||
-rw-r--r-- | core/math/aabb.cpp | 18 | ||||
-rw-r--r-- | core/math/aabb.h | 16 | ||||
-rw-r--r-- | core/math/audio_frame.h | 2 | ||||
-rw-r--r-- | core/math/basis.cpp | 23 | ||||
-rw-r--r-- | core/math/basis.h | 23 | ||||
-rw-r--r-- | core/math/camera_matrix.cpp | 7 | ||||
-rw-r--r-- | core/math/camera_matrix.h | 2 | ||||
-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.inc | 160 | ||||
-rw-r--r-- | core/math/delaunay_3d.h | 10 | ||||
-rw-r--r-- | core/math/disjoint_set.h | 4 | ||||
-rw-r--r-- | core/math/expression.cpp | 765 | ||||
-rw-r--r-- | core/math/expression.h | 108 | ||||
-rw-r--r-- | core/math/geometry_2d.h | 4 | ||||
-rw-r--r-- | core/math/geometry_3d.cpp | 6 | ||||
-rw-r--r-- | core/math/geometry_3d.h | 52 | ||||
-rw-r--r-- | core/math/math_defs.h | 5 | ||||
-rw-r--r-- | core/math/math_fieldwise.cpp | 10 | ||||
-rw-r--r-- | core/math/math_fieldwise.h | 2 | ||||
-rw-r--r-- | core/math/math_funcs.cpp | 8 | ||||
-rw-r--r-- | core/math/math_funcs.h | 33 | ||||
-rw-r--r-- | core/math/octree.h | 9 | ||||
-rw-r--r-- | core/math/plane.cpp | 30 | ||||
-rw-r--r-- | core/math/plane.h | 8 | ||||
-rw-r--r-- | core/math/quat.cpp | 2 | ||||
-rw-r--r-- | core/math/quat.h | 30 | ||||
-rw-r--r-- | core/math/quick_hull.cpp | 2 | ||||
-rw-r--r-- | core/math/quick_hull.h | 14 | ||||
-rw-r--r-- | core/math/random_number_generator.cpp | 5 | ||||
-rw-r--r-- | core/math/random_number_generator.h | 19 | ||||
-rw-r--r-- | core/math/random_pcg.cpp | 15 | ||||
-rw-r--r-- | core/math/random_pcg.h | 11 | ||||
-rw-r--r-- | core/math/rect2.h | 99 | ||||
-rw-r--r-- | core/math/transform.cpp | 9 | ||||
-rw-r--r-- | core/math/transform.h | 5 | ||||
-rw-r--r-- | core/math/transform_2d.cpp | 2 | ||||
-rw-r--r-- | core/math/transform_2d.h | 6 | ||||
-rw-r--r-- | core/math/triangle_mesh.cpp | 2 | ||||
-rw-r--r-- | core/math/triangle_mesh.h | 2 | ||||
-rw-r--r-- | core/math/vector2.cpp | 13 | ||||
-rw-r--r-- | core/math/vector2.h | 54 | ||||
-rw-r--r-- | core/math/vector3.h | 18 | ||||
-rw-r--r-- | core/math/vector3i.h | 28 | ||||
-rw-r--r-- | core/method_bind.h | 393 | ||||
-rw-r--r-- | core/object/SCsub | 7 | ||||
-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.h | 577 | ||||
-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.cpp | 2 | ||||
-rw-r--r-- | core/os/dir_access.h | 3 | ||||
-rw-r--r-- | core/os/file_access.cpp | 24 | ||||
-rw-r--r-- | core/os/file_access.h | 3 | ||||
-rw-r--r-- | core/os/keyboard.cpp | 1 | ||||
-rw-r--r-- | core/os/keyboard.h | 5 | ||||
-rw-r--r-- | core/os/main_loop.cpp | 7 | ||||
-rw-r--r-- | core/os/main_loop.h | 4 | ||||
-rw-r--r-- | core/os/memory.cpp | 4 | ||||
-rw-r--r-- | core/os/memory.h | 4 | ||||
-rw-r--r-- | core/os/midi_driver.h | 2 | ||||
-rw-r--r-- | core/os/mutex.h | 2 | ||||
-rw-r--r-- | core/os/os.cpp | 10 | ||||
-rw-r--r-- | core/os/os.h | 19 | ||||
-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.cpp | 2 | ||||
-rw-r--r-- | core/os/rw_lock.h | 2 | ||||
-rw-r--r-- | core/os/semaphore.h | 2 | ||||
-rw-r--r-- | core/os/spin_lock.h (renamed from core/spin_lock.h) | 0 | ||||
-rw-r--r-- | core/os/thread.h | 3 | ||||
-rw-r--r-- | core/os/threaded_array_processor.h | 2 | ||||
-rw-r--r-- | core/register_core_types.cpp | 35 | ||||
-rw-r--r-- | core/string/SCsub | 7 | ||||
-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.cpp | 312 | ||||
-rw-r--r-- | core/string/translation_po.h | 92 | ||||
-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/SCsub | 7 | ||||
-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.h | 22 | ||||
-rw-r--r-- | core/variant/SCsub | 7 | ||||
-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.h | 666 | ||||
-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.cpp | 193 | ||||
-rw-r--r-- | core/variant/callable_bind.h | 85 | ||||
-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.cpp | 1558 | ||||
-rw-r--r-- | core/variant/variant_construct.cpp | 812 | ||||
-rw-r--r-- | core/variant/variant_internal.h | 1384 | ||||
-rw-r--r-- | core/variant/variant_op.cpp | 2015 | ||||
-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.cpp | 2509 | ||||
-rw-r--r-- | core/variant/variant_utility.cpp | 1381 | ||||
-rw-r--r-- | core/variant_call.cpp | 2384 | ||||
-rw-r--r-- | core/variant_op.cpp | 4549 |
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]; -} |