diff options
Diffstat (limited to 'core')
54 files changed, 973 insertions, 124 deletions
diff --git a/core/SCsub b/core/SCsub index c4f1cdbe97..c508ecc37e 100644 --- a/core/SCsub +++ b/core/SCsub @@ -93,19 +93,19 @@ env.add_source_files(env.core_sources, "*.cpp") # Make binders import make_binders -env.Command(['method_bind.gen.inc', 'method_bind_ext.gen.inc'], 'make_binders.py', make_binders.run) +env.CommandNoCache(['method_bind.gen.inc', 'method_bind_ext.gen.inc'], 'make_binders.py', make_binders.run) # Authors env.Depends('#core/authors.gen.h', "../AUTHORS.md") -env.Command('#core/authors.gen.h', "../AUTHORS.md", methods.make_authors_header) +env.CommandNoCache('#core/authors.gen.h', "../AUTHORS.md", methods.make_authors_header) # Donors env.Depends('#core/donors.gen.h', "../DONORS.md") -env.Command('#core/donors.gen.h', "../DONORS.md", methods.make_donors_header) +env.CommandNoCache('#core/donors.gen.h', "../DONORS.md", methods.make_donors_header) # License env.Depends('#core/license.gen.h', ["../COPYRIGHT.txt", "../LICENSE.txt"]) -env.Command('#core/license.gen.h', ["../COPYRIGHT.txt", "../LICENSE.txt"], methods.make_license_header) +env.CommandNoCache('#core/license.gen.h', ["../COPYRIGHT.txt", "../LICENSE.txt"], methods.make_license_header) # Chain load SCsubs SConscript('os/SCsub') diff --git a/core/bind/core_bind.cpp b/core/bind/core_bind.cpp index b7f20588f2..7a14e85f20 100644 --- a/core/bind/core_bind.cpp +++ b/core/bind/core_bind.cpp @@ -348,6 +348,11 @@ bool _OS::get_borderless_window() const { return OS::get_singleton()->get_borderless_window(); } +void _OS::set_ime_active(const bool p_active) { + + return OS::get_singleton()->set_ime_active(p_active); +} + void _OS::set_ime_position(const Point2 &p_pos) { return OS::get_singleton()->set_ime_position(p_pos); @@ -794,6 +799,11 @@ uint32_t _OS::get_ticks_msec() const { return OS::get_singleton()->get_ticks_msec(); } +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(); @@ -1126,6 +1136,7 @@ void _OS::_bind_methods() { ClassDB::bind_method(D_METHOD("delay_usec", "usec"), &_OS::delay_usec); 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_latin_keyboard_variant"), &_OS::get_latin_keyboard_variant); diff --git a/core/bind/core_bind.h b/core/bind/core_bind.h index 1de5e43b27..48b7b74005 100644 --- a/core/bind/core_bind.h +++ b/core/bind/core_bind.h @@ -183,6 +183,7 @@ public: virtual bool get_window_per_pixel_transparency_enabled() const; virtual void set_window_per_pixel_transparency_enabled(bool p_enabled); + virtual void set_ime_active(const bool p_active); virtual void set_ime_position(const Point2 &p_pos); Error native_video_play(String p_path, float p_volume, String p_audio_track, String p_subtitle_track); @@ -276,6 +277,7 @@ public: void delay_usec(uint32_t p_usec) const; 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; diff --git a/core/class_db.cpp b/core/class_db.cpp index 59b100e282..f97eaf6099 100644 --- a/core/class_db.cpp +++ b/core/class_db.cpp @@ -248,9 +248,9 @@ void ClassDB::set_current_api(APIType p_api) { current_api = p_api; } -HashMap<StringName, ClassDB::ClassInfo, StringNameHasher> ClassDB::classes; -HashMap<StringName, StringName, StringNameHasher> ClassDB::resource_base_extensions; -HashMap<StringName, StringName, StringNameHasher> ClassDB::compat_classes; +HashMap<StringName, ClassDB::ClassInfo> ClassDB::classes; +HashMap<StringName, StringName> ClassDB::resource_base_extensions; +HashMap<StringName, StringName> ClassDB::compat_classes; ClassDB::ClassInfo::ClassInfo() { diff --git a/core/class_db.h b/core/class_db.h index 2c77ffe65f..f1d1879236 100644 --- a/core/class_db.h +++ b/core/class_db.h @@ -114,10 +114,10 @@ public: APIType api; ClassInfo *inherits_ptr; - HashMap<StringName, MethodBind *, StringNameHasher> method_map; - HashMap<StringName, int, StringNameHasher> constant_map; + HashMap<StringName, MethodBind *> method_map; + HashMap<StringName, int> constant_map; HashMap<StringName, List<StringName> > enum_map; - HashMap<StringName, MethodInfo, StringNameHasher> signal_map; + HashMap<StringName, MethodInfo> signal_map; List<PropertyInfo> property_list; #ifdef DEBUG_METHODS_ENABLED List<StringName> constant_order; @@ -126,7 +126,7 @@ public: List<MethodInfo> virtual_methods; StringName category; #endif - HashMap<StringName, PropertySetGet, StringNameHasher> property_setget; + HashMap<StringName, PropertySetGet> property_setget; StringName inherits; StringName name; @@ -143,9 +143,9 @@ public: } static RWLock *lock; - static HashMap<StringName, ClassInfo, StringNameHasher> classes; - static HashMap<StringName, StringName, StringNameHasher> resource_base_extensions; - static HashMap<StringName, StringName, StringNameHasher> compat_classes; + static HashMap<StringName, ClassInfo> classes; + static HashMap<StringName, StringName> resource_base_extensions; + static HashMap<StringName, StringName> compat_classes; #ifdef DEBUG_METHODS_ENABLED static MethodBind *bind_methodfi(uint32_t p_flags, MethodBind *p_bind, const MethodDefinition &method_name, const Variant **p_defs, int p_defcount); diff --git a/core/color.cpp b/core/color.cpp index b2f5889166..88e57ec6e2 100644 --- a/core/color.cpp +++ b/core/color.cpp @@ -37,38 +37,38 @@ uint32_t Color::to_argb32() const { - uint32_t c = (uint8_t)(a * 255); + uint32_t c = (uint8_t)Math::round(a * 255); c <<= 8; - c |= (uint8_t)(r * 255); + c |= (uint8_t)Math::round(r * 255); c <<= 8; - c |= (uint8_t)(g * 255); + c |= (uint8_t)Math::round(g * 255); c <<= 8; - c |= (uint8_t)(b * 255); + c |= (uint8_t)Math::round(b * 255); return c; } uint32_t Color::to_abgr32() const { - uint32_t c = (uint8_t)(a * 255); + uint32_t c = (uint8_t)Math::round(a * 255); c <<= 8; - c |= (uint8_t)(b * 255); + c |= (uint8_t)Math::round(b * 255); c <<= 8; - c |= (uint8_t)(g * 255); + c |= (uint8_t)Math::round(g * 255); c <<= 8; - c |= (uint8_t)(r * 255); + c |= (uint8_t)Math::round(r * 255); return c; } uint32_t Color::to_rgba32() const { - uint32_t c = (uint8_t)(r * 255); + uint32_t c = (uint8_t)Math::round(r * 255); c <<= 8; - c |= (uint8_t)(g * 255); + c |= (uint8_t)Math::round(g * 255); c <<= 8; - c |= (uint8_t)(b * 255); + c |= (uint8_t)Math::round(b * 255); c <<= 8; - c |= (uint8_t)(a * 255); + c |= (uint8_t)Math::round(a * 255); return c; } @@ -368,7 +368,7 @@ Color Color::named(const String &p_name) { String _to_hex(float p_val) { - int v = p_val * 255; + int v = Math::round(p_val * 255); v = CLAMP(v, 0, 255); String ret; diff --git a/core/command_queue_mt.h b/core/command_queue_mt.h index 3942b961d3..7978eaa7bf 100644 --- a/core/command_queue_mt.h +++ b/core/command_queue_mt.h @@ -54,9 +54,13 @@ #define _COMMA_10 , #define _COMMA_11 , #define _COMMA_12 , +#define _COMMA_13 , // 1-based comma separated list of ITEMs #define COMMA_SEP_LIST(ITEM, LENGTH) _COMMA_SEP_LIST_##LENGTH(ITEM) +#define _COMMA_SEP_LIST_13(ITEM) \ + _COMMA_SEP_LIST_12(ITEM) \ + , ITEM(13) #define _COMMA_SEP_LIST_12(ITEM) \ _COMMA_SEP_LIST_11(ITEM) \ , ITEM(12) @@ -97,6 +101,9 @@ // 1-based semicolon separated list of ITEMs #define SEMIC_SEP_LIST(ITEM, LENGTH) _SEMIC_SEP_LIST_##LENGTH(ITEM) +#define _SEMIC_SEP_LIST_13(ITEM) \ + _SEMIC_SEP_LIST_12(ITEM); \ + ITEM(13) #define _SEMIC_SEP_LIST_12(ITEM) \ _SEMIC_SEP_LIST_11(ITEM); \ ITEM(12) @@ -137,6 +144,9 @@ // 1-based space separated list of ITEMs #define SPACE_SEP_LIST(ITEM, LENGTH) _SPACE_SEP_LIST_##LENGTH(ITEM) +#define _SPACE_SEP_LIST_13(ITEM) \ + _SPACE_SEP_LIST_12(ITEM) \ + ITEM(13) #define _SPACE_SEP_LIST_12(ITEM) \ _SPACE_SEP_LIST_11(ITEM) \ ITEM(12) @@ -262,7 +272,7 @@ ss->sem->wait(); \ } -#define MAX_CMD_PARAMS 12 +#define MAX_CMD_PARAMS 13 class CommandQueueMT { @@ -290,15 +300,15 @@ class CommandQueueMT { }; DECL_CMD(0) - SPACE_SEP_LIST(DECL_CMD, 12) + SPACE_SEP_LIST(DECL_CMD, 13) /* comands that return */ DECL_CMD_RET(0) - SPACE_SEP_LIST(DECL_CMD_RET, 12) + SPACE_SEP_LIST(DECL_CMD_RET, 13) /* commands that don't return but sync */ DECL_CMD_SYNC(0) - SPACE_SEP_LIST(DECL_CMD_SYNC, 12) + SPACE_SEP_LIST(DECL_CMD_SYNC, 13) /***** BASE *******/ @@ -432,15 +442,15 @@ class CommandQueueMT { public: /* NORMAL PUSH COMMANDS */ DECL_PUSH(0) - SPACE_SEP_LIST(DECL_PUSH, 12) + SPACE_SEP_LIST(DECL_PUSH, 13) /* PUSH AND RET COMMANDS */ DECL_PUSH_AND_RET(0) - SPACE_SEP_LIST(DECL_PUSH_AND_RET, 12) + SPACE_SEP_LIST(DECL_PUSH_AND_RET, 13) /* PUSH AND RET SYNC COMMANDS*/ DECL_PUSH_AND_SYNC(0) - SPACE_SEP_LIST(DECL_PUSH_AND_SYNC, 12) + SPACE_SEP_LIST(DECL_PUSH_AND_SYNC, 13) void wait_and_flush_one() { ERR_FAIL_COND(!sync); diff --git a/core/global_constants.cpp b/core/global_constants.cpp index 04810afe73..5b4dd05dbf 100644 --- a/core/global_constants.cpp +++ b/core/global_constants.cpp @@ -378,6 +378,8 @@ void register_global_constants() { 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); @@ -385,6 +387,8 @@ void register_global_constants() { 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); //joypads BIND_GLOBAL_ENUM_CONSTANT(JOY_BUTTON_0); diff --git a/core/hashfuncs.h b/core/hashfuncs.h index ae99fa39c8..735e679d1e 100644 --- a/core/hashfuncs.h +++ b/core/hashfuncs.h @@ -33,6 +33,8 @@ #include "math_defs.h" #include "math_funcs.h" +#include "node_path.h" +#include "string_db.h" #include "typedefs.h" #include "ustring.h" @@ -131,6 +133,7 @@ static inline uint64_t make_uint64_t(T p_in) { } struct HashMapHasherDefault { + static _FORCE_INLINE_ uint32_t hash(const String &p_string) { return p_string.hash(); } static _FORCE_INLINE_ uint32_t hash(const char *p_cstr) { return hash_djb2(p_cstr); } static _FORCE_INLINE_ uint32_t hash(const uint64_t p_int) { return hash_one_uint64(p_int); } @@ -145,6 +148,10 @@ 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 StringName &p_string_name) { return p_string_name.hash(); } + static _FORCE_INLINE_ uint32_t hash(const NodePath &p_path) { return p_path.hash(); } + //static _FORCE_INLINE_ uint32_t hash(const void* p_ptr) { return uint32_t(uint64_t(p_ptr))*(0x9e3779b1L); } }; diff --git a/core/image.cpp b/core/image.cpp index c08b1ac39b..b0bed80a6f 100644 --- a/core/image.cpp +++ b/core/image.cpp @@ -1076,6 +1076,36 @@ void Image::shrink_x2() { } } +void Image::normalize() { + + bool used_mipmaps = has_mipmaps(); + if (used_mipmaps) { + clear_mipmaps(); + } + + lock(); + + for (int y = 0; y < height; y++) { + + for (int x = 0; x < width; x++) { + + Color c = get_pixel(x, y); + Vector3 v(c.r * 2.0 - 1.0, c.g * 2.0 - 1.0, c.b * 2.0 - 1.0); + v.normalize(); + c.r = v.x * 0.5 + 0.5; + c.g = v.y * 0.5 + 0.5; + c.b = v.z * 0.5 + 0.5; + set_pixel(x, y, c); + } + } + + unlock(); + + if (used_mipmaps) { + generate_mipmaps(true); + } +} + Error Image::generate_mipmaps(bool p_renormalize) { if (!_can_modify(format)) { diff --git a/core/image.h b/core/image.h index e38fa19ded..43516e2c0b 100644 --- a/core/image.h +++ b/core/image.h @@ -220,6 +220,7 @@ public: Error generate_mipmaps(bool p_renormalize = false); void clear_mipmaps(); + void normalize(); //for normal maps /** * Create a new image of a given size and format. Current image will be lost diff --git a/core/io/http_client.cpp b/core/io/http_client.cpp index 8d85e78226..f1620f1493 100644 --- a/core/io/http_client.cpp +++ b/core/io/http_client.cpp @@ -30,6 +30,7 @@ #include "http_client.h" #include "io/stream_peer_ssl.h" +#include "version.h" const char *HTTPClient::_methods[METHOD_MAX] = { "GET", @@ -121,16 +122,30 @@ Error HTTPClient::request_raw(Method p_method, const String &p_url, const Vector request += "Host: " + conn_host + ":" + itos(conn_port) + "\r\n"; } 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_clen && p_headers[i].find("Content-Length:") == 0) { + if (add_clen && p_headers[i].findn("Content-Length:") == 0) { add_clen = false; } + if (add_uagent && p_headers[i].findn("User-Agent:") == 0) { + add_uagent = false; + } + if (add_accept && p_headers[i].findn("Accept:") == 0) { + add_accept = false; + } } if (add_clen) { request += "Content-Length: " + itos(p_body.size()) + "\r\n"; // Should it add utf8 encoding? } + if (add_uagent) { + request += "User-Agent: GodotEngine/" + String(VERSION_FULL_BUILD) + " (" + OS::get_singleton()->get_name() + ")\r\n"; + } + if (add_accept) { + request += "Accept: */*\r\n"; + } request += "\r\n"; CharString cs = request.utf8(); @@ -173,17 +188,31 @@ Error HTTPClient::request(Method p_method, const String &p_url, const Vector<Str } else { request += "Host: " + conn_host + ":" + itos(conn_port) + "\r\n"; } + 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_clen && p_headers[i].find("Content-Length:") == 0) { + if (add_clen && p_headers[i].findn("Content-Length:") == 0) { add_clen = false; } + if (add_uagent && p_headers[i].findn("User-Agent:") == 0) { + add_uagent = false; + } + if (add_accept && p_headers[i].findn("Accept:") == 0) { + add_accept = false; + } } if (add_clen) { request += "Content-Length: " + itos(p_body.utf8().length()) + "\r\n"; // Should it add utf8 encoding? } + if (add_uagent) { + request += "User-Agent: GodotEngine/" + String(VERSION_FULL_BUILD) + " (" + OS::get_singleton()->get_name() + ")\r\n"; + } + if (add_accept) { + request += "Accept: */*\r\n"; + } request += "\r\n"; request += p_body; @@ -250,6 +279,7 @@ void HTTPClient::close() { chunk_left = 0; read_until_eof = false; response_num = 0; + handshaking = false; } Error HTTPClient::poll() { @@ -298,16 +328,40 @@ Error HTTPClient::poll() { } break; case StreamPeerTCP::STATUS_CONNECTED: { if (ssl) { - Ref<StreamPeerSSL> ssl = StreamPeerSSL::create(); - Error err = ssl->connect_to_stream(tcp_connection, ssl_verify_host, conn_host); - if (err != OK) { + Ref<StreamPeerSSL> ssl; + if (!handshaking) { + // Connect the StreamPeerSSL and start handshaking + ssl = Ref<StreamPeerSSL>(StreamPeerSSL::create()); + ssl->set_blocking_handshake_enabled(false); + Error err = ssl->connect_to_stream(tcp_connection, ssl_verify_host, conn_host); + if (err != OK) { + close(); + status = STATUS_SSL_HANDSHAKE_ERROR; + return ERR_CANT_CONNECT; + } + connection = ssl; + handshaking = true; + } else { + // We are already handshaking, which means we can use your already active SSL connection + ssl = static_cast<Ref<StreamPeerSSL> >(connection); + ssl->poll(); // Try to finish the handshake + } + + if (ssl->get_status() == StreamPeerSSL::STATUS_CONNECTED) { + // Handshake has been successfull + handshaking = false; + status = STATUS_CONNECTED; + return OK; + } else if (ssl->get_status() != StreamPeerSSL::STATUS_HANDSHAKING) { + // Handshake has failed close(); status = STATUS_SSL_HANDSHAKE_ERROR; return ERR_CANT_CONNECT; } - connection = ssl; + // ... we will need to poll more for handshake to finish + } else { + status = STATUS_CONNECTED; } - status = STATUS_CONNECTED; return OK; } break; case StreamPeerTCP::STATUS_ERROR: @@ -640,6 +694,7 @@ HTTPClient::HTTPClient() { response_num = 0; ssl = false; blocking = false; + handshaking = false; read_chunk_size = 4096; } diff --git a/core/io/http_client.h b/core/io/http_client.h index 38ec82ce8c..82b56b01db 100644 --- a/core/io/http_client.h +++ b/core/io/http_client.h @@ -165,6 +165,7 @@ private: bool ssl; bool ssl_verify_host; bool blocking; + bool handshaking; Vector<uint8_t> response_str; diff --git a/core/io/logger.cpp b/core/io/logger.cpp index 8a5d683b56..786bec461b 100644 --- a/core/io/logger.cpp +++ b/core/io/logger.cpp @@ -112,7 +112,7 @@ void RotatedFileLogger::clear_old_backups() { int max_backups = max_files - 1; // -1 for the current file String basename = base_path.get_file().get_basename(); - String extension = "." + base_path.get_extension(); + String extension = base_path.get_extension(); DirAccess *da = DirAccess::open(base_path.get_base_dir()); if (!da) { @@ -123,7 +123,7 @@ void RotatedFileLogger::clear_old_backups() { String f = da->get_next(); Set<String> backups; while (f != String()) { - if (!da->current_is_dir() && f.begins_with(basename) && f.ends_with(extension) && f != base_path.get_file()) { + if (!da->current_is_dir() && f.begins_with(basename) && f.get_extension() == extension && f != base_path.get_file()) { backups.insert(f); } f = da->get_next(); diff --git a/core/io/multiplayer_api.cpp b/core/io/multiplayer_api.cpp index 846c89510e..ffd3ecaed0 100644 --- a/core/io/multiplayer_api.cpp +++ b/core/io/multiplayer_api.cpp @@ -704,7 +704,7 @@ void MultiplayerAPI::rsetp(Node *p_node, int p_peer_id, bool p_unreliable, const _send_rpc(p_node, p_peer_id, p_unreliable, true, p_property, &vptr, 1); } -Error MultiplayerAPI::send_bytes(PoolVector<uint8_t> p_data, int p_to) { +Error MultiplayerAPI::send_bytes(PoolVector<uint8_t> p_data, int p_to, NetworkedMultiplayerPeer::TransferMode p_mode) { ERR_FAIL_COND_V(p_data.size() < 1, ERR_INVALID_DATA); ERR_FAIL_COND_V(!network_peer.is_valid(), ERR_UNCONFIGURED); @@ -714,7 +714,10 @@ Error MultiplayerAPI::send_bytes(PoolVector<uint8_t> p_data, int p_to) { PoolVector<uint8_t>::Read r = p_data.read(); packet_cache[0] = NETWORK_COMMAND_RAW; memcpy(&packet_cache[1], &r[0], p_data.size()); + network_peer->set_target_peer(p_to); + network_peer->set_transfer_mode(p_mode); + return network_peer->put_packet(packet_cache.ptr(), p_data.size() + 1); } @@ -770,7 +773,7 @@ Vector<int> MultiplayerAPI::get_network_connected_peers() const { void MultiplayerAPI::_bind_methods() { ClassDB::bind_method(D_METHOD("set_root_node", "node"), &MultiplayerAPI::set_root_node); - ClassDB::bind_method(D_METHOD("send_bytes", "bytes", "id"), &MultiplayerAPI::send_bytes, DEFVAL(NetworkedMultiplayerPeer::TARGET_PEER_BROADCAST)); + ClassDB::bind_method(D_METHOD("send_bytes", "bytes", "id"), &MultiplayerAPI::send_bytes, DEFVAL(NetworkedMultiplayerPeer::TARGET_PEER_BROADCAST), DEFVAL(NetworkedMultiplayerPeer::TRANSFER_MODE_RELIABLE)); ClassDB::bind_method(D_METHOD("has_network_peer"), &MultiplayerAPI::has_network_peer); ClassDB::bind_method(D_METHOD("get_network_peer"), &MultiplayerAPI::get_network_peer); ClassDB::bind_method(D_METHOD("get_network_unique_id"), &MultiplayerAPI::get_network_unique_id); diff --git a/core/io/multiplayer_api.h b/core/io/multiplayer_api.h index ef56c4c7f2..e47b1830e8 100644 --- a/core/io/multiplayer_api.h +++ b/core/io/multiplayer_api.h @@ -104,7 +104,7 @@ public: void set_root_node(Node *p_node); void set_network_peer(const Ref<NetworkedMultiplayerPeer> &p_peer); Ref<NetworkedMultiplayerPeer> get_network_peer() const; - Error send_bytes(PoolVector<uint8_t> p_data, int p_to = NetworkedMultiplayerPeer::TARGET_PEER_BROADCAST); + Error send_bytes(PoolVector<uint8_t> p_data, int p_to = NetworkedMultiplayerPeer::TARGET_PEER_BROADCAST, NetworkedMultiplayerPeer::TransferMode p_mode = NetworkedMultiplayerPeer::TRANSFER_MODE_RELIABLE); // Called by Node.rpc void rpcp(Node *p_node, int p_peer_id, bool p_unreliable, const StringName &p_method, const Variant **p_arg, int p_argcount); diff --git a/core/io/stream_peer_ssl.cpp b/core/io/stream_peer_ssl.cpp index 012ba78c6d..c71af6b641 100644 --- a/core/io/stream_peer_ssl.cpp +++ b/core/io/stream_peer_ssl.cpp @@ -52,6 +52,14 @@ bool StreamPeerSSL::is_available() { return available; } +void StreamPeerSSL::set_blocking_handshake_enabled(bool p_enabled) { + blocking_handshake = p_enabled; +} + +bool StreamPeerSSL::is_blocking_handshake_enabled() const { + return blocking_handshake; +} + PoolByteArray StreamPeerSSL::get_project_cert_array() { PoolByteArray out; @@ -84,16 +92,21 @@ PoolByteArray StreamPeerSSL::get_project_cert_array() { void StreamPeerSSL::_bind_methods() { ClassDB::bind_method(D_METHOD("poll"), &StreamPeerSSL::poll); - ClassDB::bind_method(D_METHOD("accept_stream", "stream"), &StreamPeerSSL::accept_stream); + ClassDB::bind_method(D_METHOD("accept_stream"), &StreamPeerSSL::accept_stream); ClassDB::bind_method(D_METHOD("connect_to_stream", "stream", "validate_certs", "for_hostname"), &StreamPeerSSL::connect_to_stream, DEFVAL(false), DEFVAL(String())); ClassDB::bind_method(D_METHOD("get_status"), &StreamPeerSSL::get_status); ClassDB::bind_method(D_METHOD("disconnect_from_stream"), &StreamPeerSSL::disconnect_from_stream); + ClassDB::bind_method(D_METHOD("set_blocking_handshake_enabled", "enabled"), &StreamPeerSSL::set_blocking_handshake_enabled); + ClassDB::bind_method(D_METHOD("is_blocking_handshake_enabled"), &StreamPeerSSL::is_blocking_handshake_enabled); + + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "blocking_handshake"), "set_blocking_handshake_enabled", "is_blocking_handshake_enabled"); BIND_ENUM_CONSTANT(STATUS_DISCONNECTED); BIND_ENUM_CONSTANT(STATUS_CONNECTED); - BIND_ENUM_CONSTANT(STATUS_ERROR_NO_CERTIFICATE); + BIND_ENUM_CONSTANT(STATUS_ERROR); BIND_ENUM_CONSTANT(STATUS_ERROR_HOSTNAME_MISMATCH); } StreamPeerSSL::StreamPeerSSL() { + blocking_handshake = true; } diff --git a/core/io/stream_peer_ssl.h b/core/io/stream_peer_ssl.h index 77301a7c87..870704e875 100644 --- a/core/io/stream_peer_ssl.h +++ b/core/io/stream_peer_ssl.h @@ -49,14 +49,20 @@ protected: friend class Main; static bool initialize_certs; + bool blocking_handshake; + public: enum Status { STATUS_DISCONNECTED, + STATUS_HANDSHAKING, STATUS_CONNECTED, - STATUS_ERROR_NO_CERTIFICATE, + STATUS_ERROR, STATUS_ERROR_HOSTNAME_MISMATCH }; + void set_blocking_handshake_enabled(bool p_enabled); + bool is_blocking_handshake_enabled() const; + virtual void poll() = 0; virtual Error accept_stream(Ref<StreamPeer> p_base) = 0; virtual Error connect_to_stream(Ref<StreamPeer> p_base, bool p_validate_certs = false, const String &p_for_hostname = String()) = 0; diff --git a/core/math/a_star.cpp b/core/math/a_star.cpp index 6908d7831d..021391da83 100644 --- a/core/math/a_star.cpp +++ b/core/math/a_star.cpp @@ -96,11 +96,11 @@ void AStar::remove_point(int p_id) { Point *p = points[p_id]; - for (int i = 0; i < p->neighbours.size(); i++) { + for (Set<Point *>::Element *E = p->neighbours.front(); E; E = E->next()) { - Segment s(p_id, p->neighbours[i]->id); + Segment s(p_id, E->get()->id); segments.erase(s); - p->neighbours[i]->neighbours.erase(p); + E->get()->neighbours.erase(p); } memdelete(p); @@ -115,10 +115,10 @@ void AStar::connect_points(int p_id, int p_with_id, bool bidirectional) { Point *a = points[p_id]; Point *b = points[p_with_id]; - a->neighbours.push_back(b); + a->neighbours.insert(b); if (bidirectional) - b->neighbours.push_back(a); + b->neighbours.insert(a); Segment s(p_id, p_with_id); if (s.from == p_id) { @@ -168,8 +168,8 @@ PoolVector<int> AStar::get_point_connections(int p_id) { Point *p = points[p_id]; - for (int i = 0; i < p->neighbours.size(); i++) { - point_list.push_back(p->neighbours[i]->id); + for (Set<Point *>::Element *E = p->neighbours.front(); E; E = E->next()) { + point_list.push_back(E->get()->id); } return point_list; @@ -242,9 +242,9 @@ bool AStar::_solve(Point *begin_point, Point *end_point) { bool found_route = false; - for (int i = 0; i < begin_point->neighbours.size(); i++) { + for (Set<Point *>::Element *E = begin_point->neighbours.front(); E; E = E->next()) { - Point *n = begin_point->neighbours[i]; + Point *n = E->get(); n->prev_point = begin_point; n->distance = _compute_cost(begin_point->id, n->id) * n->weight_scale; n->last_pass = pass; @@ -283,12 +283,10 @@ bool AStar::_solve(Point *begin_point, Point *end_point) { } Point *p = least_cost_point->self(); - // Open the neighbours for search - int es = p->neighbours.size(); - for (int i = 0; i < es; i++) { + for (Set<Point *>::Element *E = p->neighbours.front(); E; E = E->next()) { - Point *e = p->neighbours[i]; + Point *e = E->get(); real_t distance = _compute_cost(p->id, e->id) * e->weight_scale + p->distance; diff --git a/core/math/a_star.h b/core/math/a_star.h index f89e17c7bb..8c1b5f64cb 100644 --- a/core/math/a_star.h +++ b/core/math/a_star.h @@ -54,7 +54,7 @@ class AStar : public Reference { real_t weight_scale; uint64_t last_pass; - Vector<Point *> neighbours; + Set<Point *> neighbours; // Used for pathfinding Point *prev_point; diff --git a/core/math/aabb.h b/core/math/aabb.h index 39b8f403e7..cdb8eb48a3 100644 --- a/core/math/aabb.h +++ b/core/math/aabb.h @@ -76,6 +76,7 @@ public: _FORCE_INLINE_ bool smits_intersect_ray(const Vector3 &p_from, const Vector3 &p_dir, real_t t0, real_t t1) const; _FORCE_INLINE_ bool intersects_convex_shape(const Plane *p_planes, int p_plane_count) const; + _FORCE_INLINE_ bool inside_convex_shape(const Plane *p_planes, int p_plane_count) const; bool intersects_plane(const Plane &p_plane) const; _FORCE_INLINE_ bool has_point(const Vector3 &p_point) const; @@ -207,6 +208,25 @@ bool AABB::intersects_convex_shape(const Plane *p_planes, int p_plane_count) con return true; } +bool AABB::inside_convex_shape(const Plane *p_planes, int p_plane_count) const { + + Vector3 half_extents = size * 0.5; + Vector3 ofs = position + half_extents; + + for (int i = 0; i < p_plane_count; i++) { + const Plane &p = p_planes[i]; + Vector3 point( + (p.normal.x < 0) ? -half_extents.x : half_extents.x, + (p.normal.y < 0) ? -half_extents.y : half_extents.y, + (p.normal.z < 0) ? -half_extents.z : half_extents.z); + point += ofs; + if (p.is_point_over(point)) + return false; + } + + return true; +} + bool AABB::has_point(const Vector3 &p_point) const { if (p_point.x < position.x) diff --git a/core/math/delaunay.cpp b/core/math/delaunay.cpp new file mode 100644 index 0000000000..8cae92b7c0 --- /dev/null +++ b/core/math/delaunay.cpp @@ -0,0 +1 @@ +#include "delaunay.h" diff --git a/core/math/delaunay.h b/core/math/delaunay.h new file mode 100644 index 0000000000..09aebc773f --- /dev/null +++ b/core/math/delaunay.h @@ -0,0 +1,145 @@ +#ifndef DELAUNAY_H +#define DELAUNAY_H + +#include "math_2d.h" + +class Delaunay2D { +public: + struct Triangle { + + int points[3]; + bool bad; + Triangle() { bad = false; } + Triangle(int p_a, int p_b, int p_c) { + points[0] = p_a; + points[1] = p_b; + points[2] = p_c; + bad = false; + } + }; + + struct Edge { + int edge[2]; + bool bad; + Edge() { bad = false; } + Edge(int p_a, int p_b) { + bad = false; + edge[0] = p_a; + edge[1] = p_b; + } + }; + + static bool circum_circle_contains(const Vector<Vector2> &p_vertices, const Triangle &p_triangle, int p_vertex) { + + Vector2 p1 = p_vertices[p_triangle.points[0]]; + Vector2 p2 = p_vertices[p_triangle.points[1]]; + Vector2 p3 = p_vertices[p_triangle.points[2]]; + + real_t ab = p1.x * p1.x + p1.y * p1.y; + real_t cd = p2.x * p2.x + p2.y * p2.y; + real_t ef = p3.x * p3.x + p3.y * p3.y; + + Vector2 circum( + (ab * (p3.y - p2.y) + cd * (p1.y - p3.y) + ef * (p2.y - p1.y)) / (p1.x * (p3.y - p2.y) + p2.x * (p1.y - p3.y) + p3.x * (p2.y - p1.y)), + (ab * (p3.x - p2.x) + cd * (p1.x - p3.x) + ef * (p2.x - p1.x)) / (p1.y * (p3.x - p2.x) + p2.y * (p1.x - p3.x) + p3.y * (p2.x - p1.x))); + + circum *= 0.5; + float r = p1.distance_squared_to(circum); + float d = p_vertices[p_vertex].distance_squared_to(circum); + return d <= r; + } + + static bool edge_compare(const Vector<Vector2> &p_vertices, const Edge &p_a, const Edge &p_b) { + if (p_vertices[p_a.edge[0]].distance_to(p_vertices[p_b.edge[0]]) < CMP_EPSILON && p_vertices[p_a.edge[1]].distance_to(p_vertices[p_b.edge[1]]) < CMP_EPSILON) { + return true; + } + + if (p_vertices[p_a.edge[0]].distance_to(p_vertices[p_b.edge[1]]) < CMP_EPSILON && p_vertices[p_a.edge[1]].distance_to(p_vertices[p_b.edge[0]]) < CMP_EPSILON) { + return true; + } + + return false; + } + + static Vector<Triangle> triangulate(const Vector<Vector2> &p_points) { + + Vector<Vector2> points = p_points; + Vector<Triangle> triangles; + + Rect2 rect; + for (int i = 0; i < p_points.size(); i++) { + if (i == 0) { + rect.position = p_points[i]; + } else { + rect.expand_to(p_points[i]); + } + } + + float delta_max = MAX(rect.size.width, rect.size.height); + Vector2 center = rect.position + rect.size * 0.5; + + points.push_back(Vector2(center.x - 20 * delta_max, center.y - delta_max)); + points.push_back(Vector2(center.x, center.y + 20 * delta_max)); + points.push_back(Vector2(center.x + 20 * delta_max, center.y - delta_max)); + + triangles.push_back(Triangle(p_points.size() + 0, p_points.size() + 1, p_points.size() + 2)); + + for (int i = 0; i < p_points.size(); i++) { + //std::cout << "Traitement du point " << *p << std::endl; + //std::cout << "_triangles contains " << _triangles.size() << " elements" << std::endl; + + Vector<Edge> polygon; + + for (int j = 0; j < triangles.size(); j++) { + if (circum_circle_contains(points, triangles[j], i)) { + triangles[j].bad = true; + polygon.push_back(Edge(triangles[j].points[0], triangles[j].points[1])); + polygon.push_back(Edge(triangles[j].points[1], triangles[j].points[2])); + polygon.push_back(Edge(triangles[j].points[2], triangles[j].points[0])); + } + } + + for (int j = 0; j < triangles.size(); j++) { + if (triangles[j].bad) { + triangles.remove(j); + j--; + } + } + + for (int j = 0; j < polygon.size(); j++) { + for (int k = j + 1; k < polygon.size(); k++) { + if (edge_compare(points, polygon[j], polygon[k])) { + polygon[j].bad = true; + polygon[k].bad = true; + } + } + } + + for (int j = 0; j < polygon.size(); j++) { + + if (polygon[j].bad) { + continue; + } + triangles.push_back(Triangle(polygon[j].edge[0], polygon[j].edge[1], i)); + } + } + + for (int i = 0; i < triangles.size(); i++) { + bool invalid = false; + for (int j = 0; j < 3; j++) { + if (triangles[i].points[j] >= p_points.size()) { + invalid = true; + break; + } + } + if (invalid) { + triangles.remove(i); + i--; + } + } + + return triangles; + } +}; + +#endif // DELAUNAY_H diff --git a/core/math/math_funcs.h b/core/math/math_funcs.h index 20001bb9a6..f0c0268f31 100644 --- a/core/math/math_funcs.h +++ b/core/math/math_funcs.h @@ -182,8 +182,22 @@ public: static _ALWAYS_INLINE_ float abs(float g) { return absf(g); } static _ALWAYS_INLINE_ int abs(int g) { return g > 0 ? g : -g; } - static _ALWAYS_INLINE_ double fposmod(double p_x, double p_y) { return (p_x >= 0) ? Math::fmod(p_x, p_y) : p_y - Math::fmod(-p_x, p_y); } - static _ALWAYS_INLINE_ float fposmod(float p_x, float p_y) { return (p_x >= 0) ? Math::fmod(p_x, p_y) : p_y - Math::fmod(-p_x, p_y); } + static _ALWAYS_INLINE_ double fposmod(double p_x, double p_y) { + double value = Math::fmod(p_x, p_y); + if ((value < 0 && p_y > 0) || (value > 0 && p_y < 0)) { + value += p_y; + } + value += 0.0; + return value; + } + static _ALWAYS_INLINE_ float fposmod(float p_x, float p_y) { + float value = Math::fmod(p_x, p_y); + if ((value < 0 && p_y > 0) || (value > 0 && p_y < 0)) { + value += p_y; + } + value += 0.0; + return value; + } static _ALWAYS_INLINE_ double deg2rad(double p_y) { return p_y * Math_PI / 180.0; } static _ALWAYS_INLINE_ float deg2rad(float p_y) { return p_y * Math_PI / 180.0; } diff --git a/core/math/matrix3.cpp b/core/math/matrix3.cpp index 202115e2ca..2371f49561 100644 --- a/core/math/matrix3.cpp +++ b/core/math/matrix3.cpp @@ -356,8 +356,7 @@ void Basis::rotate(const Quat &p_quat) { *this = rotated(p_quat); } -// TODO: rename this to get_rotation_euler -Vector3 Basis::get_rotation() const { +Vector3 Basis::get_rotation_euler() const { // Assumes that the matrix can be decomposed into a proper rotation and scaling matrix as M = R.S, // and returns the Euler angles corresponding to the rotation part, complementing get_scale(). // See the comment in get_scale() for further information. @@ -371,6 +370,20 @@ Vector3 Basis::get_rotation() const { return m.get_euler(); } +Quat Basis::get_rotation_quat() const { + // Assumes that the matrix can be decomposed into a proper rotation and scaling matrix as M = R.S, + // and returns the Euler angles corresponding to the rotation part, complementing get_scale(). + // See the comment in get_scale() for further information. + Basis m = orthonormalized(); + real_t det = m.determinant(); + if (det < 0) { + // Ensure that the determinant is 1, such that result is a proper rotation matrix which can be represented by Euler angles. + m.scale(Vector3(-1, -1, -1)); + } + + return m.get_quat(); +} + void Basis::get_rotation_axis_angle(Vector3 &p_axis, real_t &p_angle) const { // Assumes that the matrix can be decomposed into a proper rotation and scaling matrix as M = R.S, // and returns the Euler angles corresponding to the rotation part, complementing get_scale(). @@ -591,10 +604,9 @@ Basis::operator String() const { } Quat Basis::get_quat() const { - //commenting this check because precision issues cause it to fail when it shouldn't - //#ifdef MATH_CHECKS - //ERR_FAIL_COND_V(is_rotation() == false, Quat()); - //#endif +#ifdef MATH_CHECKS + ERR_FAIL_COND_V(is_rotation() == false, Quat()); +#endif real_t trace = elements[0][0] + elements[1][1] + elements[2][2]; real_t temp[4]; diff --git a/core/math/matrix3.h b/core/math/matrix3.h index 63d4f5d79d..cd1b51baa6 100644 --- a/core/math/matrix3.h +++ b/core/math/matrix3.h @@ -84,9 +84,11 @@ public: void rotate(const Quat &p_quat); Basis rotated(const Quat &p_quat) const; - Vector3 get_rotation() const; + Vector3 get_rotation_euler() const; void get_rotation_axis_angle(Vector3 &p_axis, real_t &p_angle) const; void get_rotation_axis_angle_local(Vector3 &p_axis, real_t &p_angle) const; + Quat get_rotation_quat() const; + Vector3 get_rotation() const { return get_rotation_euler(); }; Vector3 rotref_posscale_decomposition(Basis &rotref) const; diff --git a/core/math/quat.cpp b/core/math/quat.cpp index b938fc3cfd..67c9048a41 100644 --- a/core/math/quat.cpp +++ b/core/math/quat.cpp @@ -139,15 +139,15 @@ bool Quat::is_normalized() const { Quat Quat::inverse() const { #ifdef MATH_CHECKS - ERR_FAIL_COND_V(is_normalized() == false, Quat(0, 0, 0, 0)); + ERR_FAIL_COND_V(is_normalized() == false, Quat()); #endif return Quat(-x, -y, -z, w); } Quat Quat::slerp(const Quat &q, const real_t &t) const { #ifdef MATH_CHECKS - ERR_FAIL_COND_V(is_normalized() == false, Quat(0, 0, 0, 0)); - ERR_FAIL_COND_V(q.is_normalized() == false, Quat(0, 0, 0, 0)); + ERR_FAIL_COND_V(is_normalized() == false, Quat()); + ERR_FAIL_COND_V(q.is_normalized() == false, Quat()); #endif Quat to1; real_t omega, cosom, sinom, scale0, scale1; @@ -192,7 +192,10 @@ Quat Quat::slerp(const Quat &q, const real_t &t) const { } Quat Quat::slerpni(const Quat &q, const real_t &t) const { - +#ifdef MATH_CHECKS + ERR_FAIL_COND_V(is_normalized() == false, Quat()); + ERR_FAIL_COND_V(q.is_normalized() == false, Quat()); +#endif const Quat &from = *this; real_t dot = from.dot(q); @@ -211,7 +214,10 @@ Quat Quat::slerpni(const Quat &q, const real_t &t) const { } Quat Quat::cubic_slerp(const Quat &q, const Quat &prep, const Quat &postq, const real_t &t) const { - +#ifdef MATH_CHECKS + ERR_FAIL_COND_V(is_normalized() == false, Quat()); + ERR_FAIL_COND_V(q.is_normalized() == false, Quat()); +#endif //the only way to do slerp :| real_t t2 = (1.0 - t) * t * 2; Quat sp = this->slerp(q, t); diff --git a/core/math/quat.h b/core/math/quat.h index 3e1344a913..6dc8d66f60 100644 --- a/core/math/quat.h +++ b/core/math/quat.h @@ -84,7 +84,9 @@ public: } _FORCE_INLINE_ Vector3 xform(const Vector3 &v) const { - +#ifdef MATH_CHECKS + ERR_FAIL_COND_V(is_normalized() == false, v); +#endif Vector3 u(x, y, z); Vector3 uv = u.cross(v); return v + ((uv * w) + u.cross(uv)) * ((real_t)2); diff --git a/core/math/transform.cpp b/core/math/transform.cpp index 7cd186ca60..d1e190f4b9 100644 --- a/core/math/transform.cpp +++ b/core/math/transform.cpp @@ -120,11 +120,11 @@ Transform Transform::interpolate_with(const Transform &p_transform, real_t p_c) /* not sure if very "efficient" but good enough? */ Vector3 src_scale = basis.get_scale(); - Quat src_rot = basis.orthonormalized(); + Quat src_rot = basis.get_rotation_quat(); Vector3 src_loc = origin; Vector3 dst_scale = p_transform.basis.get_scale(); - Quat dst_rot = p_transform.basis; + Quat dst_rot = p_transform.basis.get_rotation_quat(); Vector3 dst_loc = p_transform.origin; Transform dst; //this could be made faster by using a single function in Basis.. diff --git a/core/math/triangle_mesh.cpp b/core/math/triangle_mesh.cpp index edd4ad3441..5475f733c3 100644 --- a/core/math/triangle_mesh.cpp +++ b/core/math/triangle_mesh.cpp @@ -88,6 +88,26 @@ int TriangleMesh::_create_bvh(BVH *p_bvh, BVH **p_bb, int p_from, int p_size, in return index; } +void TriangleMesh::get_indices(PoolVector<int> *r_triangles_indices) const { + + if (!valid) + return; + + const int triangles_num = triangles.size(); + + // Parse vertices indices + PoolVector<Triangle>::Read triangles_read = triangles.read(); + + r_triangles_indices->resize(triangles_num * 3); + PoolVector<int>::Write r_indices_write = r_triangles_indices->write(); + + for (int i = 0; i < triangles_num; ++i) { + r_indices_write[3 * i + 0] = triangles_read[i].indices[0]; + r_indices_write[3 * i + 1] = triangles_read[i].indices[1]; + r_indices_write[3 * i + 2] = triangles_read[i].indices[2]; + } +} + void TriangleMesh::create(const PoolVector<Vector3> &p_faces) { valid = false; @@ -490,6 +510,222 @@ bool TriangleMesh::intersect_ray(const Vector3 &p_begin, const Vector3 &p_dir, V return inters; } +bool TriangleMesh::intersect_convex_shape(const Plane *p_planes, int p_plane_count) const { + uint32_t *stack = (uint32_t *)alloca(sizeof(int) * max_depth); + + //p_fully_inside = true; + + enum { + TEST_AABB_BIT = 0, + VISIT_LEFT_BIT = 1, + VISIT_RIGHT_BIT = 2, + VISIT_DONE_BIT = 3, + VISITED_BIT_SHIFT = 29, + NODE_IDX_MASK = (1 << VISITED_BIT_SHIFT) - 1, + VISITED_BIT_MASK = ~NODE_IDX_MASK, + + }; + + int level = 0; + + PoolVector<Triangle>::Read trianglesr = triangles.read(); + PoolVector<Vector3>::Read verticesr = vertices.read(); + PoolVector<BVH>::Read bvhr = bvh.read(); + + const Triangle *triangleptr = trianglesr.ptr(); + const Vector3 *vertexptr = verticesr.ptr(); + int pos = bvh.size() - 1; + const BVH *bvhptr = bvhr.ptr(); + + stack[0] = pos; + while (true) { + + uint32_t node = stack[level] & NODE_IDX_MASK; + const BVH &b = bvhptr[node]; + bool done = false; + + switch (stack[level] >> VISITED_BIT_SHIFT) { + case TEST_AABB_BIT: { + + bool valid = b.aabb.intersects_convex_shape(p_planes, p_plane_count); + if (!valid) { + + stack[level] = (VISIT_DONE_BIT << VISITED_BIT_SHIFT) | node; + + } else { + + if (b.face_index >= 0) { + + const Triangle &s = triangleptr[b.face_index]; + + for (int j = 0; j < 3; ++j) { + const Vector3 &point = vertexptr[s.indices[j]]; + const Vector3 &next_point = vertexptr[s.indices[(j + 1) % 3]]; + Vector3 res; + bool over = true; + for (int i = 0; i < p_plane_count; i++) { + const Plane &p = p_planes[i]; + + if (p.intersects_segment(point, next_point, &res)) { + bool inisde = true; + for (int k = 0; k < p_plane_count; k++) { + if (k == i) continue; + const Plane &pp = p_planes[k]; + if (pp.is_point_over(res)) { + inisde = false; + break; + } + } + if (inisde) return true; + } + + if (p.is_point_over(point)) { + over = false; + break; + } + } + if (over) return true; + } + + stack[level] = (VISIT_DONE_BIT << VISITED_BIT_SHIFT) | node; + + } else { + + stack[level] = (VISIT_LEFT_BIT << VISITED_BIT_SHIFT) | node; + } + } + continue; + } + case VISIT_LEFT_BIT: { + + stack[level] = (VISIT_RIGHT_BIT << VISITED_BIT_SHIFT) | node; + stack[level + 1] = b.left | TEST_AABB_BIT; + level++; + continue; + } + case VISIT_RIGHT_BIT: { + + stack[level] = (VISIT_DONE_BIT << VISITED_BIT_SHIFT) | node; + stack[level + 1] = b.right | TEST_AABB_BIT; + level++; + continue; + } + case VISIT_DONE_BIT: { + + if (level == 0) { + done = true; + break; + } else + level--; + continue; + } + } + + if (done) + break; + } + + return false; +} + +bool TriangleMesh::inside_convex_shape(const Plane *p_planes, int p_plane_count, Vector3 p_scale) const { + uint32_t *stack = (uint32_t *)alloca(sizeof(int) * max_depth); + + enum { + TEST_AABB_BIT = 0, + VISIT_LEFT_BIT = 1, + VISIT_RIGHT_BIT = 2, + VISIT_DONE_BIT = 3, + VISITED_BIT_SHIFT = 29, + NODE_IDX_MASK = (1 << VISITED_BIT_SHIFT) - 1, + VISITED_BIT_MASK = ~NODE_IDX_MASK, + + }; + + int level = 0; + + PoolVector<Triangle>::Read trianglesr = triangles.read(); + PoolVector<Vector3>::Read verticesr = vertices.read(); + PoolVector<BVH>::Read bvhr = bvh.read(); + + Transform scale(Basis().scaled(p_scale)); + + const Triangle *triangleptr = trianglesr.ptr(); + const Vector3 *vertexptr = verticesr.ptr(); + int pos = bvh.size() - 1; + const BVH *bvhptr = bvhr.ptr(); + + stack[0] = pos; + while (true) { + + uint32_t node = stack[level] & NODE_IDX_MASK; + const BVH &b = bvhptr[node]; + bool done = false; + + switch (stack[level] >> VISITED_BIT_SHIFT) { + case TEST_AABB_BIT: { + + bool intersects = scale.xform(b.aabb).intersects_convex_shape(p_planes, p_plane_count); + if (!intersects) return false; + + bool inside = scale.xform(b.aabb).inside_convex_shape(p_planes, p_plane_count); + if (inside) { + + stack[level] = (VISIT_DONE_BIT << VISITED_BIT_SHIFT) | node; + + } else { + + if (b.face_index >= 0) { + const Triangle &s = triangleptr[b.face_index]; + for (int j = 0; j < 3; ++j) { + Vector3 point = scale.xform(vertexptr[s.indices[j]]); + for (int i = 0; i < p_plane_count; i++) { + const Plane &p = p_planes[i]; + if (p.is_point_over(point)) return false; + } + } + + stack[level] = (VISIT_DONE_BIT << VISITED_BIT_SHIFT) | node; + + } else { + + stack[level] = (VISIT_LEFT_BIT << VISITED_BIT_SHIFT) | node; + } + } + continue; + } + case VISIT_LEFT_BIT: { + + stack[level] = (VISIT_RIGHT_BIT << VISITED_BIT_SHIFT) | node; + stack[level + 1] = b.left | TEST_AABB_BIT; + level++; + continue; + } + case VISIT_RIGHT_BIT: { + + stack[level] = (VISIT_DONE_BIT << VISITED_BIT_SHIFT) | node; + stack[level + 1] = b.right | TEST_AABB_BIT; + level++; + continue; + } + case VISIT_DONE_BIT: { + + if (level == 0) { + done = true; + break; + } else + level--; + continue; + } + } + + if (done) + break; + } + + return true; +} + bool TriangleMesh::is_valid() const { return valid; diff --git a/core/math/triangle_mesh.h b/core/math/triangle_mesh.h index 9f145f2afb..bf793fc50f 100644 --- a/core/math/triangle_mesh.h +++ b/core/math/triangle_mesh.h @@ -89,9 +89,15 @@ public: bool is_valid() const; bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_point, Vector3 &r_normal) const; bool intersect_ray(const Vector3 &p_begin, const Vector3 &p_dir, Vector3 &r_point, Vector3 &r_normal) const; + bool intersect_convex_shape(const Plane *p_planes, int p_plane_count) const; + bool inside_convex_shape(const Plane *p_planes, int p_plane_count, Vector3 p_scale = Vector3(1, 1, 1)) const; Vector3 get_area_normal(const AABB &p_aabb) const; PoolVector<Face3> get_faces() const; + PoolVector<Triangle> get_triangles() const { return triangles; } + PoolVector<Vector3> get_vertices() const { return vertices; } + void get_indices(PoolVector<int> *p_triangles_indices) const; + void create(const PoolVector<Vector3> &p_faces); TriangleMesh(); }; diff --git a/core/method_ptrcall.h b/core/method_ptrcall.h index 2007c3def5..677e8e1fb2 100644 --- a/core/method_ptrcall.h +++ b/core/method_ptrcall.h @@ -214,6 +214,50 @@ struct PtrToArg<const T *> { } \ } +#define MAKE_VECARG_ALT(m_type, m_type_alt) \ + template <> \ + struct PtrToArg<Vector<m_type_alt> > { \ + _FORCE_INLINE_ static Vector<m_type_alt> convert(const void *p_ptr) { \ + const PoolVector<m_type> *dvs = reinterpret_cast<const PoolVector<m_type> *>(p_ptr); \ + Vector<m_type_alt> ret; \ + int len = dvs->size(); \ + ret.resize(len); \ + { \ + PoolVector<m_type>::Read r = dvs->read(); \ + for (int i = 0; i < len; i++) { \ + ret[i] = r[i]; \ + } \ + } \ + return ret; \ + } \ + _FORCE_INLINE_ static void encode(Vector<m_type_alt> p_vec, void *p_ptr) { \ + PoolVector<m_type> *dv = reinterpret_cast<PoolVector<m_type> *>(p_ptr); \ + int len = p_vec.size(); \ + dv->resize(len); \ + { \ + PoolVector<m_type>::Write w = dv->write(); \ + for (int i = 0; i < len; i++) { \ + w[i] = p_vec[i]; \ + } \ + } \ + } \ + }; \ + template <> \ + struct PtrToArg<const Vector<m_type_alt> &> { \ + _FORCE_INLINE_ static Vector<m_type_alt> convert(const void *p_ptr) { \ + const PoolVector<m_type> *dvs = reinterpret_cast<const PoolVector<m_type> *>(p_ptr); \ + Vector<m_type_alt> ret; \ + int len = dvs->size(); \ + ret.resize(len); \ + { \ + PoolVector<m_type>::Read r = dvs->read(); \ + for (int i = 0; i < len; i++) { \ + ret[i] = r[i]; \ + } \ + } \ + return ret; \ + } \ + } MAKE_VECARG(String); MAKE_VECARG(uint8_t); MAKE_VECARG(int); @@ -221,6 +265,7 @@ 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 #define MAKE_VECARR(m_type) \ diff --git a/core/node_path.cpp b/core/node_path.cpp index 64983fc091..487d5ee8c6 100644 --- a/core/node_path.cpp +++ b/core/node_path.cpp @@ -32,10 +32,7 @@ #include "print_string.h" -uint32_t NodePath::hash() const { - - if (!data) - return 0; +void NodePath::_update_hash_cache() const { uint32_t h = data->absolute ? 1 : 0; int pc = data->path.size(); @@ -49,13 +46,15 @@ uint32_t NodePath::hash() const { h = h ^ ssn[i].hash(); } - return h; + data->hash_cache_valid = true; + data->hash_cache = h; } void NodePath::prepend_period() { if (data->path.size() && data->path[0].operator String() != ".") { data->path.insert(0, "."); + data->hash_cache_valid = false; } } @@ -114,21 +113,33 @@ bool NodePath::operator==(const NodePath &p_path) const { if (data->absolute != p_path.data->absolute) return false; - if (data->path.size() != p_path.data->path.size()) + int path_size = data->path.size(); + + if (path_size != p_path.data->path.size()) { return false; + } + + int subpath_size = data->subpath.size(); - if (data->subpath.size() != p_path.data->subpath.size()) + if (subpath_size != p_path.data->subpath.size()) { return false; + } - for (int i = 0; i < data->path.size(); i++) { + const StringName *l_path_ptr = data->path.ptr(); + const StringName *r_path_ptr = p_path.data->path.ptr(); + + for (int i = 0; i < path_size; i++) { - if (data->path[i] != p_path.data->path[i]) + if (l_path_ptr[i] != r_path_ptr[i]) return false; } - for (int i = 0; i < data->subpath.size(); i++) { + const StringName *l_subpath_ptr = data->subpath.ptr(); + const StringName *r_subpath_ptr = p_path.data->subpath.ptr(); + + for (int i = 0; i < subpath_size; i++) { - if (data->subpath[i] != p_path.data->subpath[i]) + if (l_subpath_ptr[i] != r_subpath_ptr[i]) return false; } @@ -286,6 +297,7 @@ NodePath::NodePath(const Vector<StringName> &p_path, bool p_absolute) { data->absolute = p_absolute; data->path = p_path; data->has_slashes = true; + data->hash_cache_valid = false; } NodePath::NodePath(const Vector<StringName> &p_path, const Vector<StringName> &p_subpath, bool p_absolute) { @@ -301,6 +313,7 @@ NodePath::NodePath(const Vector<StringName> &p_path, const Vector<StringName> &p data->path = p_path; data->subpath = p_subpath; data->has_slashes = true; + data->hash_cache_valid = false; } void NodePath::simplify() { @@ -324,6 +337,7 @@ void NodePath::simplify() { } } } + data->hash_cache_valid = false; } NodePath NodePath::simplified() const { @@ -396,6 +410,7 @@ NodePath::NodePath(const String &p_path) { data->absolute = absolute ? true : false; data->has_slashes = has_slashes; data->subpath = subpath; + data->hash_cache_valid = false; if (slices == 0) return; diff --git a/core/node_path.h b/core/node_path.h index 288f39721f..71235029af 100644 --- a/core/node_path.h +++ b/core/node_path.h @@ -47,11 +47,15 @@ class NodePath { StringName concatenated_subpath; bool absolute; bool has_slashes; + mutable bool hash_cache_valid; + mutable uint32_t hash_cache; }; - Data *data; + mutable Data *data; void unref(); + void _update_hash_cache() const; + public: _FORCE_INLINE_ StringName get_sname() const { @@ -78,7 +82,14 @@ public: NodePath get_parent() const; - uint32_t hash() const; + _FORCE_INLINE_ uint32_t hash() const { + if (!data) + return 0; + if (!data->hash_cache_valid) { + _update_hash_cache(); + } + return data->hash_cache; + } operator String() const; bool is_empty() const; diff --git a/core/object.h b/core/object.h index 7963a43fd6..8dc3426d1d 100644 --- a/core/object.h +++ b/core/object.h @@ -31,6 +31,7 @@ #ifndef OBJECT_H #define OBJECT_H +#include "hash_map.h" #include "list.h" #include "map.h" #include "os/rw_lock.h" @@ -85,6 +86,7 @@ enum PropertyHint { PROPERTY_HINT_PROPERTY_OF_INSTANCE, ///< a property of an instance PROPERTY_HINT_PROPERTY_OF_SCRIPT, ///< a property of a script & base PROPERTY_HINT_OBJECT_TOO_BIG, ///< object is too big to send + PROPERTY_HINT_NODE_PATH_VALID_TYPES, PROPERTY_HINT_MAX, // When updating PropertyHint, also sync the hardcoded list in VisualScriptEditorVariableEdit }; @@ -450,7 +452,7 @@ private: Signal() { lock = 0; } }; - HashMap<StringName, Signal, StringNameHasher> signal_map; + HashMap<StringName, Signal> signal_map; List<Connection> connections; #ifdef DEBUG_ENABLED SafeRefCount _lock_index; diff --git a/core/os/input_event.cpp b/core/os/input_event.cpp index 4ebb821a2f..ca6446d015 100644 --- a/core/os/input_event.cpp +++ b/core/os/input_event.cpp @@ -509,6 +509,12 @@ String InputEventMouseButton::as_text() const { case BUTTON_WHEEL_RIGHT: button_index_string = "BUTTON_WHEEL_RIGHT"; break; + case BUTTON_XBUTTON1: + button_index_string = "BUTTON_XBUTTON1"; + break; + case BUTTON_XBUTTON2: + button_index_string = "BUTTON_XBUTTON2"; + break; default: button_index_string = itos(get_button_index()); break; @@ -601,6 +607,12 @@ String InputEventMouseMotion::as_text() const { case BUTTON_MASK_RIGHT: button_mask_string = "BUTTON_MASK_RIGHT"; break; + case BUTTON_MASK_XBUTTON1: + button_mask_string = "BUTTON_MASK_XBUTTON1"; + break; + case BUTTON_MASK_XBUTTON2: + button_mask_string = "BUTTON_MASK_XBUTTON2"; + break; default: button_mask_string = itos(get_button_mask()); break; diff --git a/core/os/input_event.h b/core/os/input_event.h index 037649ed60..bd1a85ce29 100644 --- a/core/os/input_event.h +++ b/core/os/input_event.h @@ -53,10 +53,13 @@ enum ButtonList { BUTTON_WHEEL_DOWN = 5, BUTTON_WHEEL_LEFT = 6, BUTTON_WHEEL_RIGHT = 7, + BUTTON_XBUTTON1 = 8, + BUTTON_XBUTTON2 = 9, BUTTON_MASK_LEFT = (1 << (BUTTON_LEFT - 1)), BUTTON_MASK_RIGHT = (1 << (BUTTON_RIGHT - 1)), BUTTON_MASK_MIDDLE = (1 << (BUTTON_MIDDLE - 1)), - + BUTTON_MASK_XBUTTON1 = (1 << (BUTTON_XBUTTON1 - 1)), + BUTTON_MASK_XBUTTON2 = (1 << (BUTTON_XBUTTON2 - 1)) }; enum JoystickList { diff --git a/core/os/main_loop.cpp b/core/os/main_loop.cpp index 916c86613e..c51801e3e2 100644 --- a/core/os/main_loop.cpp +++ b/core/os/main_loop.cpp @@ -58,6 +58,7 @@ void MainLoop::_bind_methods() { BIND_CONSTANT(NOTIFICATION_OS_MEMORY_WARNING); BIND_CONSTANT(NOTIFICATION_TRANSLATION_CHANGED); BIND_CONSTANT(NOTIFICATION_WM_ABOUT); + BIND_CONSTANT(NOTIFICATION_CRASH); }; void MainLoop::set_init_script(const Ref<Script> &p_init_script) { diff --git a/core/os/main_loop.h b/core/os/main_loop.h index 546e4e280c..f96e46141e 100644 --- a/core/os/main_loop.h +++ b/core/os/main_loop.h @@ -62,6 +62,7 @@ public: // fixes this issue. NOTIFICATION_TRANSLATION_CHANGED = 90, NOTIFICATION_WM_ABOUT = 91, + NOTIFICATION_CRASH = 92, }; virtual void input_event(const Ref<InputEvent> &p_event); diff --git a/core/os/os.h b/core/os/os.h index b36f94060c..adf01a90e7 100644 --- a/core/os/os.h +++ b/core/os/os.h @@ -232,6 +232,7 @@ public: virtual Size2 get_layered_buffer_size() { return Size2(0, 0); } virtual void swap_layered_buffer() {} + virtual void set_ime_active(const bool p_active) {} virtual void set_ime_position(const Point2 &p_pos) {} virtual void set_ime_intermediate_text_callback(ImeCallback p_callback, void *p_inp) {} diff --git a/core/project_settings.cpp b/core/project_settings.cpp index ac4a4b7d15..b1fd66e566 100644 --- a/core/project_settings.cpp +++ b/core/project_settings.cpp @@ -137,7 +137,7 @@ bool ProjectSettings::_set(const StringName &p_name, const Variant &p_value) { else { if (p_name == CoreStringNames::get_singleton()->_custom_features) { - Vector<String> custom_feature_array = p_value; + Vector<String> custom_feature_array = String(p_value).split(","); for (int i = 0; i < custom_feature_array.size(); i++) { custom_features.insert(custom_feature_array[i]); @@ -515,7 +515,11 @@ Error ProjectSettings::_load_settings_text(const String p_path) { } } else { // config_version is checked and dropped - set(section + "/" + assign, value); + if (section == String()) { + set(assign, value); + } else { + set(section + "/" + assign, value); + } } } else if (next_tag.name != String()) { section = next_tag.name; @@ -870,6 +874,10 @@ void ProjectSettings::set_custom_property_info(const String &p_prop, const Prope custom_prop_info[p_prop].name = p_prop; } +const Map<StringName, PropertyInfo> &ProjectSettings::get_custom_property_info() const { + return custom_prop_info; +} + void ProjectSettings::set_disable_feature_overrides(bool p_disable) { disable_feature_overrides = p_disable; diff --git a/core/project_settings.h b/core/project_settings.h index b01e7855aa..66f3ed954e 100644 --- a/core/project_settings.h +++ b/core/project_settings.h @@ -137,6 +137,7 @@ public: Error save_custom(const String &p_path = "", const CustomMap &p_custom = CustomMap(), const Vector<String> &p_custom_features = Vector<String>(), bool p_merge_with_current = true); Error save(); void set_custom_property_info(const String &p_prop, const PropertyInfo &p_info); + const Map<StringName, PropertyInfo> &get_custom_property_info() const; Vector<String> get_optimizer_presets() const; diff --git a/core/resource.cpp b/core/resource.cpp index 179333aa14..87ff4d3c2a 100644 --- a/core/resource.cpp +++ b/core/resource.cpp @@ -187,7 +187,6 @@ Ref<Resource> Resource::duplicate_for_local_scene(Node *p_for_scene, Map<Ref<Res void Resource::configure_for_local_scene(Node *p_for_scene, Map<Ref<Resource>, Ref<Resource> > &remap_cache) { - print_line("configure for local: " + get_class()); List<PropertyInfo> plist; get_property_list(&plist); @@ -226,15 +225,20 @@ Ref<Resource> Resource::duplicate(bool p_subresources) const { if (!(E->get().usage & PROPERTY_USAGE_STORAGE)) continue; - Variant p = get(E->get().name).duplicate(true); - if (p.get_type() == Variant::OBJECT && p_subresources) { + Variant p = get(E->get().name); + + if ((p.get_type() == Variant::DICTIONARY || p.get_type() == Variant::ARRAY)) { + p = p.duplicate(p_subresources); //does not make a long of sense but should work? + } else if (p.get_type() == Variant::OBJECT && (p_subresources || (E->get().usage & PROPERTY_USAGE_DO_NOT_SHARE_ON_DUPLICATE))) { RES sr = p; - if (sr.is_valid()) - p = sr->duplicate(true); - } + if (sr.is_valid()) { + r->set(E->get().name, sr->duplicate(p_subresources)); + } + } else { - r->set(E->get().name, p); + r->set(E->get().name, p); + } } return Ref<Resource>(r); @@ -288,7 +292,7 @@ uint32_t Resource::hash_edited_version() const { for (List<PropertyInfo>::Element *E = plist.front(); E; E = E->next()) { - if (E->get().type == Variant::OBJECT && E->get().hint == PROPERTY_HINT_RESOURCE_TYPE) { + if (E->get().usage & PROPERTY_USAGE_STORAGE && E->get().type == Variant::OBJECT && E->get().hint == PROPERTY_HINT_RESOURCE_TYPE) { RES res = get(E->get().name); if (res.is_valid()) { hash = hash_djb2_one_32(res->hash_edited_version(), hash); diff --git a/core/script_debugger_remote.cpp b/core/script_debugger_remote.cpp index 0473e2cc71..3955f222f9 100644 --- a/core/script_debugger_remote.cpp +++ b/core/script_debugger_remote.cpp @@ -169,6 +169,10 @@ void ScriptDebuggerRemote::debug(ScriptLanguage *p_script, bool p_can_continue) ERR_FAIL(); } + if (allow_focus_steal_pid) { + OS::get_singleton()->enable_for_stealing_focus(allow_focus_steal_pid); + } + packet_peer_stream->put_var("debug_enter"); packet_peer_stream->put_var(2); packet_peer_stream->put_var(p_can_continue); @@ -1070,6 +1074,10 @@ void ScriptDebuggerRemote::profiling_set_frame_times(float p_frame_time, float p physics_frame_time = p_physics_frame_time; } +void ScriptDebuggerRemote::set_allow_focus_steal_pid(OS::ProcessID p_pid) { + allow_focus_steal_pid = p_pid; +} + ScriptDebuggerRemote::ResourceUsageFunc ScriptDebuggerRemote::resource_usage_func = NULL; ScriptDebuggerRemote::ScriptDebuggerRemote() : @@ -1091,6 +1099,7 @@ ScriptDebuggerRemote::ScriptDebuggerRemote() : n_errors_dropped(0), last_msec(0), msec_count(0), + allow_focus_steal_pid(0), locking(false), poll_every(0), request_scene_tree(NULL), diff --git a/core/script_debugger_remote.h b/core/script_debugger_remote.h index cc12d978d6..b68fc4f9c9 100644 --- a/core/script_debugger_remote.h +++ b/core/script_debugger_remote.h @@ -34,6 +34,7 @@ #include "io/packet_peer.h" #include "io/stream_peer_tcp.h" #include "list.h" +#include "os/os.h" #include "script_language.h" class ScriptDebuggerRemote : public ScriptDebugger { @@ -98,6 +99,8 @@ class ScriptDebuggerRemote : public ScriptDebugger { uint64_t last_msec; uint64_t msec_count; + OS::ProcessID allow_focus_steal_pid; + bool locking; //hack to avoid a deadloop static void _print_handler(void *p_this, const String &p_string, bool p_error); @@ -171,6 +174,8 @@ public: virtual void profiling_end(); virtual void profiling_set_frame_times(float p_frame_time, float p_idle_time, float p_physics_time, float p_physics_frame_time); + void set_allow_focus_steal_pid(OS::ProcessID p_pid); + ScriptDebuggerRemote(); ~ScriptDebuggerRemote(); }; diff --git a/core/script_language.cpp b/core/script_language.cpp index 1dab58e29e..37ba3cfc62 100644 --- a/core/script_language.cpp +++ b/core/script_language.cpp @@ -29,6 +29,7 @@ /*************************************************************************/ #include "script_language.h" +#include "project_settings.h" ScriptLanguage *ScriptServer::_languages[MAX_LANGUAGES]; int ScriptServer::_language_count = 0; @@ -103,6 +104,20 @@ void ScriptServer::unregister_language(ScriptLanguage *p_language) { void ScriptServer::init_languages() { + { //load global classes + global_classes_clear(); + if (ProjectSettings::get_singleton()->has_setting("_global_script_classes")) { + Array script_classes = ProjectSettings::get_singleton()->get("_global_script_classes"); + + for (int i = 0; i < script_classes.size(); i++) { + Dictionary c = script_classes[i]; + if (!c.has("class") || !c.has("language") || !c.has("path") || !c.has("base")) + continue; + add_global_class(c["class"], c["base"], c["language"], c["path"]); + } + } + } + for (int i = 0; i < _language_count; i++) { _languages[i]->init(); } @@ -113,6 +128,7 @@ void ScriptServer::finish_languages() { for (int i = 0; i < _language_count; i++) { _languages[i]->finish(); } + global_classes_clear(); } void ScriptServer::set_reload_scripts_on_save(bool p_enable) { @@ -139,6 +155,67 @@ void ScriptServer::thread_exit() { } } +HashMap<StringName, ScriptServer::GlobalScriptClass> ScriptServer::global_classes; + +void ScriptServer::global_classes_clear() { + global_classes.clear(); +} + +void ScriptServer::add_global_class(const StringName &p_class, const StringName &p_base, const StringName &p_language, const String &p_path) { + GlobalScriptClass g; + g.language = p_language; + g.path = p_path; + g.base = p_base; + global_classes[p_class] = g; +} +void ScriptServer::remove_global_class(const StringName &p_class) { + global_classes.erase(p_class); +} +bool ScriptServer::is_global_class(const StringName &p_class) { + return global_classes.has(p_class); +} +StringName ScriptServer::get_global_class_language(const StringName &p_class) { + ERR_FAIL_COND_V(!global_classes.has(p_class), StringName()); + return global_classes[p_class].language; +} +String ScriptServer::get_global_class_path(const String &p_class) { + ERR_FAIL_COND_V(!global_classes.has(p_class), String()); + return global_classes[p_class].path; +} + +StringName ScriptServer::get_global_class_base(const String &p_class) { + ERR_FAIL_COND_V(!global_classes.has(p_class), String()); + return global_classes[p_class].base; +} +void ScriptServer::get_global_class_list(List<StringName> *r_global_classes) { + const StringName *K = NULL; + List<StringName> classes; + while ((K = global_classes.next(K))) { + classes.push_back(*K); + } + classes.sort_custom<StringName::AlphCompare>(); + for (List<StringName>::Element *E = classes.front(); E; E = E->next()) { + r_global_classes->push_back(E->get()); + } +} +void ScriptServer::save_global_classes() { + List<StringName> gc; + get_global_class_list(&gc); + Array gcarr; + for (List<StringName>::Element *E = gc.front(); E; E = E->next()) { + Dictionary d; + d["class"] = E->get(); + d["language"] = global_classes[E->get()].language; + d["path"] = global_classes[E->get()].path; + d["base"] = global_classes[E->get()].base; + gcarr.push_back(d); + } + + ProjectSettings::get_singleton()->set("_global_script_classes", gcarr); + ProjectSettings::get_singleton()->save(); +} + +//////////////////// void ScriptInstance::get_property_state(List<Pair<StringName, Variant> > &state) { List<PropertyInfo> pinfo; @@ -347,6 +424,20 @@ Variant::Type PlaceHolderScriptInstance::get_property_type(const StringName &p_n return Variant::NIL; } +void PlaceHolderScriptInstance::get_method_list(List<MethodInfo> *p_list) const { + + if (script.is_valid()) { + script->get_script_method_list(p_list); + } +} +bool PlaceHolderScriptInstance::has_method(const StringName &p_method) const { + + if (script.is_valid()) { + return script->has_method(p_method); + } + return false; +} + void PlaceHolderScriptInstance::update(const List<PropertyInfo> &p_properties, const Map<StringName, Variant> &p_values) { Set<StringName> new_values; diff --git a/core/script_language.h b/core/script_language.h index ad66fc5528..2950b35109 100644 --- a/core/script_language.h +++ b/core/script_language.h @@ -54,6 +54,14 @@ class ScriptServer { static bool scripting_enabled; static bool reload_scripts_on_save; + struct GlobalScriptClass { + StringName language; + String path; + String base; + }; + + static HashMap<StringName, GlobalScriptClass> global_classes; + public: static ScriptEditRequestFunction edit_request_func; @@ -70,6 +78,16 @@ public: static void thread_enter(); static void thread_exit(); + static void global_classes_clear(); + static void add_global_class(const StringName &p_class, const StringName &p_base, const StringName &p_language, const String &p_path); + static void remove_global_class(const StringName &p_class); + static bool is_global_class(const StringName &p_class); + static StringName get_global_class_language(const StringName &p_class); + static String get_global_class_path(const String &p_class); + static StringName get_global_class_base(const String &p_class); + static void get_global_class_list(List<StringName> *r_global_classes); + static void save_global_classes(); + static void init_languages(); static void finish_languages(); }; @@ -285,7 +303,10 @@ public: virtual void frame(); - virtual ~ScriptLanguage(){}; + virtual bool handles_global_class_type(const String &p_type) const { return false; } + virtual String get_global_class_name(const String &p_path, String *r_base_type = NULL) const { return String(); } + + virtual ~ScriptLanguage() {} }; extern uint8_t script_encryption_key[32]; @@ -304,8 +325,8 @@ public: virtual void get_property_list(List<PropertyInfo> *p_properties) const; virtual Variant::Type get_property_type(const StringName &p_name, bool *r_is_valid = NULL) const; - virtual void get_method_list(List<MethodInfo> *p_list) const {} - virtual bool has_method(const StringName &p_method) const { return false; } + virtual void get_method_list(List<MethodInfo> *p_list) const; + virtual bool has_method(const StringName &p_method) const; virtual Variant call(const StringName &p_method, VARIANT_ARG_LIST) { return Variant(); } virtual Variant call(const StringName &p_method, const Variant **p_args, int p_argcount, Variant::CallError &r_error) { r_error.error = Variant::CallError::CALL_ERROR_INVALID_METHOD; diff --git a/core/string_db.h b/core/string_db.h index 01d1ca4033..965385b136 100644 --- a/core/string_db.h +++ b/core/string_db.h @@ -31,7 +31,6 @@ #ifndef STRING_DB_H #define STRING_DB_H -#include "hash_map.h" #include "os/mutex.h" #include "safe_refcount.h" #include "ustring.h" @@ -168,11 +167,6 @@ public: ~StringName(); }; -struct StringNameHasher { - - static _FORCE_INLINE_ uint32_t hash(const StringName &p_string) { return p_string.hash(); } -}; - StringName _scs_create(const char *p_chr); #endif diff --git a/core/type_info.h b/core/type_info.h index c1af4fac69..bf497f1e5f 100644 --- a/core/type_info.h +++ b/core/type_info.h @@ -194,6 +194,7 @@ MAKE_TEMPLATE_TYPE_INFO(Vector, Color, Variant::POOL_COLOR_ARRAY) MAKE_TEMPLATE_TYPE_INFO(Vector, Variant, Variant::ARRAY) MAKE_TEMPLATE_TYPE_INFO(Vector, RID, Variant::ARRAY) MAKE_TEMPLATE_TYPE_INFO(Vector, Plane, Variant::ARRAY) +MAKE_TEMPLATE_TYPE_INFO(Vector, StringName, Variant::POOL_STRING_ARRAY) MAKE_TEMPLATE_TYPE_INFO(PoolVector, Plane, Variant::ARRAY) MAKE_TEMPLATE_TYPE_INFO(PoolVector, Face3, Variant::POOL_VECTOR3_ARRAY) diff --git a/core/undo_redo.cpp b/core/undo_redo.cpp index b3f9dd818d..b9a2fdd0ac 100644 --- a/core/undo_redo.cpp +++ b/core/undo_redo.cpp @@ -299,26 +299,30 @@ void UndoRedo::_process_operation_list(List<Operation>::Element *E) { } } -void UndoRedo::redo() { +bool UndoRedo::redo() { - ERR_FAIL_COND(action_level > 0); + ERR_FAIL_COND_V(action_level > 0, false); if ((current_action + 1) >= actions.size()) - return; //nothing to redo + return false; //nothing to redo current_action++; _process_operation_list(actions[current_action].do_ops.front()); version++; + + return true; } -void UndoRedo::undo() { +bool UndoRedo::undo() { - ERR_FAIL_COND(action_level > 0); + ERR_FAIL_COND_V(action_level > 0, false); if (current_action < 0) - return; //nothing to redo + return false; //nothing to redo _process_operation_list(actions[current_action].undo_ops.front()); current_action--; version--; + + return true; } void UndoRedo::clear_history() { diff --git a/core/undo_redo.h b/core/undo_redo.h index a373296b73..3a17c78851 100644 --- a/core/undo_redo.h +++ b/core/undo_redo.h @@ -109,8 +109,8 @@ public: void commit_action(); - void redo(); - void undo(); + bool redo(); + bool undo(); String get_current_action_name() const; void clear_history(); diff --git a/core/variant.cpp b/core/variant.cpp index a6df95e310..c48aa57652 100644 --- a/core/variant.cpp +++ b/core/variant.cpp @@ -2012,6 +2012,19 @@ Variant::operator Vector<String>() const { } return to; } +Variant::operator Vector<StringName>() const { + + PoolVector<String> from = operator PoolVector<String>(); + Vector<StringName> to; + int len = from.size(); + to.resize(len); + for (int i = 0; i < len; i++) { + + to[i] = from[i]; + } + return to; +} + Variant::operator Vector<Vector3>() const { PoolVector<Vector3> from = operator PoolVector<Vector3>(); @@ -2444,6 +2457,17 @@ Variant::Variant(const Vector<String> &p_array) { *this = v; } +Variant::Variant(const Vector<StringName> &p_array) { + + type = NIL; + PoolVector<String> v; + int len = p_array.size(); + v.resize(len); + for (int i = 0; i < len; i++) + v.set(i, p_array[i]); + *this = v; +} + Variant::Variant(const Vector<Vector3> &p_array) { type = NIL; diff --git a/core/variant.h b/core/variant.h index f227e4bfdb..4b245d25e6 100644 --- a/core/variant.h +++ b/core/variant.h @@ -216,6 +216,7 @@ public: operator Vector<int>() const; operator Vector<real_t>() const; operator Vector<String>() const; + operator Vector<StringName>() const; operator Vector<Vector3>() const; operator Vector<Color>() const; operator Vector<RID>() const; @@ -280,6 +281,7 @@ public: Variant(const Vector<int> &p_int_array); Variant(const Vector<real_t> &p_real_array); Variant(const Vector<String> &p_string_array); + Variant(const Vector<StringName> &p_string_array); Variant(const Vector<Vector3> &p_vector3_array); Variant(const Vector<Color> &p_color_array); Variant(const Vector<Plane> &p_array); // helper diff --git a/core/variant_op.cpp b/core/variant_op.cpp index 621af2dfb7..bfa69b1fde 100644 --- a/core/variant_op.cpp +++ b/core/variant_op.cpp @@ -3417,8 +3417,17 @@ Variant Variant::iter_get(const Variant &r_iter, bool &r_valid) const { Variant Variant::duplicate(bool deep) const { switch (type) { - // case OBJECT: - // return operator Object *()->duplicate(); + 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: |