diff options
52 files changed, 479 insertions, 329 deletions
diff --git a/bin/tests/test_string.cpp b/bin/tests/test_string.cpp index 4990c58896..d99ad4476f 100644 --- a/bin/tests/test_string.cpp +++ b/bin/tests/test_string.cpp @@ -842,7 +842,7 @@ bool test_29() { IP_Address ip0("2001:0db8:85a3:0000:0000:8a2e:0370:7334"); OS::get_singleton()->print("ip0 is %ls\n", String(ip0).c_str()); - IP_Address ip(0x0123, 0x4567, 0x89ab, 0xcdef, IP_Address::TYPE_IPV6); + IP_Address ip(0x0123, 0x4567, 0x89ab, 0xcdef, true); OS::get_singleton()->print("ip6 is %ls\n", String(ip).c_str()); IP_Address ip2("fe80::52e5:49ff:fe93:1baf"); diff --git a/core/io/http_client.cpp b/core/io/http_client.cpp index 7b2b710a72..4f14a1fc4d 100644 --- a/core/io/http_client.cpp +++ b/core/io/http_client.cpp @@ -29,11 +29,14 @@ #include "http_client.h" #include "io/stream_peer_ssl.h" -VARIANT_ENUM_CAST(IP_Address::AddrType); +void HTTPClient::set_ip_type(IP::Type p_type) { + ip_type = p_type; +} -Error HTTPClient::connect(const String &p_host, int p_port, bool p_ssl,bool p_verify_host, IP_Address::AddrType p_addr_type){ +Error HTTPClient::connect(const String &p_host, int p_port, bool p_ssl,bool p_verify_host){ close(); + tcp_connection->set_ip_type(ip_type); conn_port=p_port; conn_host=p_host; @@ -63,7 +66,7 @@ Error HTTPClient::connect(const String &p_host, int p_port, bool p_ssl,bool p_ve status=STATUS_CONNECTING; } else { //is hostname - resolving=IP::get_singleton()->resolve_hostname_queue_item(conn_host, p_addr_type); + resolving=IP::get_singleton()->resolve_hostname_queue_item(conn_host, ip_type); status=STATUS_RESOLVING; } @@ -636,7 +639,8 @@ Error HTTPClient::_get_http_data(uint8_t* p_buffer, int p_bytes,int &r_received) void HTTPClient::_bind_methods() { - ObjectTypeDB::bind_method(_MD("connect:Error","host","port","use_ssl","verify_host"),&HTTPClient::connect,DEFVAL(false),DEFVAL(true),DEFVAL(IP_Address::TYPE_ANY)); + ObjectTypeDB::bind_method(_MD("set_ip_type","ip_type"),&HTTPClient::set_ip_type); + ObjectTypeDB::bind_method(_MD("connect:Error","host","port","use_ssl","verify_host"),&HTTPClient::connect,DEFVAL(false),DEFVAL(true)); ObjectTypeDB::bind_method(_MD("set_connection","connection:StreamPeer"),&HTTPClient::set_connection); ObjectTypeDB::bind_method(_MD("get_connection:StreamPeer"),&HTTPClient::get_connection); ObjectTypeDB::bind_method(_MD("request_raw","method","url","headers","body"),&HTTPClient::request_raw); @@ -762,6 +766,7 @@ String HTTPClient::query_string_from_dict(const Dictionary& p_dict) { HTTPClient::HTTPClient(){ + ip_type = IP::TYPE_ANY; tcp_connection = StreamPeerTCP::create_ref(); resolving = IP::RESOLVER_INVALID_ID; status=STATUS_DISCONNECTED; diff --git a/core/io/http_client.h b/core/io/http_client.h index fff78febd8..ef0a687cdd 100644 --- a/core/io/http_client.h +++ b/core/io/http_client.h @@ -132,6 +132,7 @@ public: private: + IP::Type ip_type; Status status; IP::ResolverID resolving; int conn_port; @@ -164,8 +165,9 @@ private: public: + void set_ip_type(IP::Type p_type); //Error connect_and_get(const String& p_url,bool p_verify_host=true); //connects to a full url and perform request - Error connect(const String &p_host,int p_port,bool p_ssl=false,bool p_verify_host=true, IP_Address::AddrType p_addr_type = IP_Address::TYPE_ANY); + Error connect(const String &p_host,int p_port,bool p_ssl=false,bool p_verify_host=true); void set_connection(const Ref<StreamPeer>& p_connection); Ref<StreamPeer> get_connection() const; diff --git a/core/io/ip.cpp b/core/io/ip.cpp index c2036435c8..b057d72e49 100644 --- a/core/io/ip.cpp +++ b/core/io/ip.cpp @@ -32,7 +32,6 @@ #include "hash_map.h" VARIANT_ENUM_CAST(IP::ResolverStatus); -VARIANT_ENUM_CAST(IP_Address::AddrType); /************* RESOLVER ******************/ @@ -44,12 +43,12 @@ struct _IP_ResolverPrivate { volatile IP::ResolverStatus status; IP_Address response; String hostname; - IP_Address::AddrType type; + IP::Type type; void clear() { status = IP::RESOLVER_STATUS_NONE; response = IP_Address(); - type = IP_Address::TYPE_NONE; + type = IP::TYPE_NONE; hostname=""; }; @@ -83,7 +82,7 @@ struct _IP_ResolverPrivate { continue; queue[i].response=IP::get_singleton()->resolve_hostname(queue[i].hostname, queue[i].type); - if (queue[i].response.type==IP_Address::TYPE_NONE) + if (queue[i].response==IP_Address()) queue[i].status=IP::RESOLVER_STATUS_ERROR; else queue[i].status=IP::RESOLVER_STATUS_DONE; @@ -108,25 +107,28 @@ struct _IP_ResolverPrivate { HashMap<String, IP_Address> cache; + static String get_cache_key(String p_hostname, IP::Type p_type) { + return itos(p_type) + p_hostname; + } + }; -IP_Address IP::resolve_hostname(const String& p_hostname, IP_Address::AddrType p_type) { +IP_Address IP::resolve_hostname(const String& p_hostname, IP::Type p_type) { GLOBAL_LOCK_FUNCTION; - if (resolver->cache.has(p_hostname)) - if (resolver->cache[p_hostname].type & p_type != 0) - return resolver->cache[p_hostname]; - // requested type is different from type in cache. continue resolution, if successful it'll overwrite cache + String key = _IP_ResolverPrivate::get_cache_key(p_hostname, p_type); + if (resolver->cache.has(key)) + return resolver->cache[key]; IP_Address res = _resolve_hostname(p_hostname, p_type); - resolver->cache[p_hostname]=res; + resolver->cache[key]=res; return res; } -IP::ResolverID IP::resolve_hostname_queue_item(const String& p_hostname, IP_Address::AddrType p_type) { +IP::ResolverID IP::resolve_hostname_queue_item(const String& p_hostname, IP::Type p_type) { GLOBAL_LOCK_FUNCTION; @@ -137,10 +139,11 @@ IP::ResolverID IP::resolve_hostname_queue_item(const String& p_hostname, IP_Addr return id; } + String key = _IP_ResolverPrivate::get_cache_key(p_hostname, p_type); resolver->queue[id].hostname=p_hostname; resolver->queue[id].type = p_type; - if (resolver->cache.has(p_hostname) && (resolver->cache[p_hostname].type & p_type) != 0) { - resolver->queue[id].response=resolver->cache[p_hostname]; + if (resolver->cache.has(key)) { + resolver->queue[id].response=resolver->cache[key]; resolver->queue[id].status=IP::RESOLVER_STATUS_DONE; } else { resolver->queue[id].response=IP_Address(); @@ -194,7 +197,10 @@ void IP::clear_cache(const String &p_hostname) { if (p_hostname.empty()) { resolver->cache.clear(); } else { - resolver->cache.erase(p_hostname); + resolver->cache.erase(_IP_ResolverPrivate::get_cache_key(p_hostname, IP::TYPE_NONE)); + resolver->cache.erase(_IP_ResolverPrivate::get_cache_key(p_hostname, IP::TYPE_IPV4)); + resolver->cache.erase(_IP_ResolverPrivate::get_cache_key(p_hostname, IP::TYPE_IPV6)); + resolver->cache.erase(_IP_ResolverPrivate::get_cache_key(p_hostname, IP::TYPE_ANY)); } }; @@ -212,8 +218,8 @@ Array IP::_get_local_addresses() const { void IP::_bind_methods() { - ObjectTypeDB::bind_method(_MD("resolve_hostname","host","ip_type"),&IP::resolve_hostname,DEFVAL(IP_Address::TYPE_ANY)); - ObjectTypeDB::bind_method(_MD("resolve_hostname_queue_item","host","ip_type"),&IP::resolve_hostname_queue_item,DEFVAL(IP_Address::TYPE_ANY)); + ObjectTypeDB::bind_method(_MD("resolve_hostname","host","ip_type"),&IP::resolve_hostname,DEFVAL(IP::TYPE_ANY)); + ObjectTypeDB::bind_method(_MD("resolve_hostname_queue_item","host","ip_type"),&IP::resolve_hostname_queue_item,DEFVAL(IP::TYPE_ANY)); ObjectTypeDB::bind_method(_MD("get_resolve_item_status","id"),&IP::get_resolve_item_status); ObjectTypeDB::bind_method(_MD("get_resolve_item_address","id"),&IP::get_resolve_item_address); ObjectTypeDB::bind_method(_MD("erase_resolve_item","id"),&IP::erase_resolve_item); @@ -228,6 +234,10 @@ void IP::_bind_methods() { BIND_CONSTANT( RESOLVER_MAX_QUERIES ); BIND_CONSTANT( RESOLVER_INVALID_ID ); + BIND_CONSTANT( TYPE_NONE ); + BIND_CONSTANT( TYPE_IPV4 ); + BIND_CONSTANT( TYPE_IPV6 ); + BIND_CONSTANT( TYPE_ANY ); } diff --git a/core/io/ip.h b/core/io/ip.h index c155d7690f..0a0e75fe7b 100644 --- a/core/io/ip.h +++ b/core/io/ip.h @@ -48,12 +48,12 @@ public: RESOLVER_STATUS_ERROR, }; - enum AddressType { + enum Type { - ADDRESS_IPV4 = 1, - ADDRESS_IPV6 = 2, - - ADDRESS_ANY = 3, + TYPE_NONE = 0, + TYPE_IPV4 = 1, + TYPE_IPV6 = 2, + TYPE_ANY = 3, }; enum { @@ -73,7 +73,7 @@ protected: static IP*singleton; static void _bind_methods(); - virtual IP_Address _resolve_hostname(const String& p_hostname, IP_Address::AddrType p_type = IP_Address::TYPE_ANY)=0; + virtual IP_Address _resolve_hostname(const String& p_hostname, Type p_type = TYPE_ANY)=0; Array _get_local_addresses() const; static IP* (*_create)(); @@ -81,9 +81,9 @@ public: - IP_Address resolve_hostname(const String& p_hostname, IP_Address::AddrType p_type = IP_Address::TYPE_ANY); + IP_Address resolve_hostname(const String& p_hostname, Type p_type = TYPE_ANY); // async resolver hostname - ResolverID resolve_hostname_queue_item(const String& p_hostname, IP_Address::AddrType p_type = IP_Address::TYPE_ANY); + ResolverID resolve_hostname_queue_item(const String& p_hostname, Type p_type = TYPE_ANY); ResolverStatus get_resolve_item_status(ResolverID p_id) const; IP_Address get_resolve_item_address(ResolverID p_id) const; virtual void get_local_addresses(List<IP_Address> *r_addresses) const=0; @@ -101,4 +101,6 @@ public: }; +VARIANT_ENUM_CAST(IP::Type); + #endif // IP_H diff --git a/core/io/ip_address.cpp b/core/io/ip_address.cpp index 2d46ae4143..1fda7fed7b 100644 --- a/core/io/ip_address.cpp +++ b/core/io/ip_address.cpp @@ -38,21 +38,18 @@ IP_Address::operator Variant() const { IP_Address::operator String() const { - if (type == TYPE_NONE) - return "0.0.0.0"; - if (type == TYPE_IPV4) - return itos(field8[0])+"."+itos(field8[1])+"."+itos(field8[2])+"."+itos(field8[3]); - else { - String ret; - for (int i=0; i<8; i++) { - if (i > 0) - ret = ret + ":"; - uint16_t num = (field8[i*2] << 8) + field8[i*2+1]; - ret = ret + String::num_int64(num, 16); - }; - - return ret; + if(is_ipv4()) + // IPv4 address mapped to IPv6 + return itos(field8[12])+"."+itos(field8[13])+"."+itos(field8[14])+"."+itos(field8[15]); + String ret; + for (int i=0; i<8; i++) { + if (i > 0) + ret = ret + ":"; + uint16_t num = (field8[i*2] << 8) + field8[i*2+1]; + ret = ret + String::num_int64(num, 16); }; + + return ret; } static void _parse_hex(const String& p_string, int p_start, uint8_t* p_dst) { @@ -176,17 +173,41 @@ void IP_Address::clear() { memset(&field8[0], 0, sizeof(field8)); }; +bool IP_Address::is_ipv4() const{ + return (field32[0]==0 && field32[1]==0 && field16[4]==0 && field16[5]==0xffff); +} + +const uint8_t *IP_Address::get_ipv4() const{ + ERR_FAIL_COND_V(!is_ipv4(),0); + return &(field8[12]); +} + +void IP_Address::set_ipv4(const uint8_t *p_ip) { + clear(); + field16[5]=0xffff; + field32[3]=*((const uint32_t *)p_ip); +} + +const uint8_t *IP_Address::get_ipv6() const{ + return field8; +} + +void IP_Address::set_ipv6(const uint8_t *p_buf) { + clear(); + for (int i=0; i<16; i++) + field8[i] = p_buf[i]; +} + IP_Address::IP_Address(const String& p_string) { clear(); if (p_string.find(":") >= 0) { _parse_ipv6(p_string); - type = TYPE_IPV6; } else { - - _parse_ipv4(p_string, 0, &field8[0]); - type = TYPE_IPV4; + // Mapped to IPv6 + field16[5] = 0xffff; + _parse_ipv4(p_string, 0, &field8[12]); }; } @@ -198,25 +219,22 @@ _FORCE_INLINE_ static void _32_to_buf(uint8_t* p_dst, uint32_t p_n) { p_dst[3] = (p_n >> 0) & 0xff; }; -IP_Address::IP_Address(uint32_t p_a,uint32_t p_b,uint32_t p_c,uint32_t p_d, IP_Address::AddrType p_type) { +IP_Address::IP_Address(uint32_t p_a,uint32_t p_b,uint32_t p_c,uint32_t p_d, bool is_v6) { - type = p_type; - memset(&field8[0], 0, sizeof(field8)); - if (p_type == TYPE_IPV4) { - field8[0]=p_a; - field8[1]=p_b; - field8[2]=p_c; - field8[3]=p_d; - } else if (type == TYPE_IPV6) { + clear(); + if (!is_v6) { + // Mapped to IPv6 + field16[5]=0xffff; + field8[12]=p_a; + field8[13]=p_b; + field8[14]=p_c; + field8[15]=p_d; + } else { _32_to_buf(&field8[0], p_a); _32_to_buf(&field8[4], p_b); _32_to_buf(&field8[8], p_c); _32_to_buf(&field8[12], p_d); - } else { - type = TYPE_NONE; - ERR_EXPLAIN("Invalid type specified for IP_Address (use TYPE_IPV4 or TYPE_IPV6"); - ERR_FAIL(); - }; + } } diff --git a/core/io/ip_address.h b/core/io/ip_address.h index e42e54def8..87f32b0ac2 100644 --- a/core/io/ip_address.h +++ b/core/io/ip_address.h @@ -33,16 +33,7 @@ struct IP_Address { -public: - enum AddrType { - TYPE_NONE = 0, - TYPE_IPV4 = 1, - TYPE_IPV6 = 2, - - TYPE_ANY = 3, - }; - - AddrType type; +private: union { uint8_t field8[16]; @@ -70,11 +61,17 @@ public: } void clear(); + bool is_ipv4() const; + const uint8_t *get_ipv4() const; + void set_ipv4(const uint8_t *p_ip); + + const uint8_t *get_ipv6() const; + void set_ipv6(const uint8_t *buf); operator String() const; IP_Address(const String& p_string); - IP_Address(uint32_t p_a,uint32_t p_b,uint32_t p_c,uint32_t p_d, AddrType p_type=TYPE_IPV4); - IP_Address() { clear(); type=TYPE_NONE; } + IP_Address(uint32_t p_a,uint32_t p_b,uint32_t p_c,uint32_t p_d, bool is_v6=false); + IP_Address() { clear(); } }; diff --git a/core/io/packet_peer_udp.cpp b/core/io/packet_peer_udp.cpp index 8cecfa69ed..6216176e77 100644 --- a/core/io/packet_peer_udp.cpp +++ b/core/io/packet_peer_udp.cpp @@ -31,20 +31,18 @@ PacketPeerUDP* (*PacketPeerUDP::_create)()=NULL; -VARIANT_ENUM_CAST(IP_Address::AddrType); - String PacketPeerUDP::_get_packet_ip() const { return get_packet_address(); } -Error PacketPeerUDP::_set_send_address(const String& p_address,int p_port,IP_Address::AddrType p_type) { +Error PacketPeerUDP::_set_send_address(const String& p_address, int p_port) { IP_Address ip; if (p_address.is_valid_ip_address()) { ip=p_address; } else { - ip=IP::get_singleton()->resolve_hostname(p_address, p_type); + ip=IP::get_singleton()->resolve_hostname(p_address, ip_type); if (ip==IP_Address()) return ERR_CANT_RESOLVE; } @@ -53,16 +51,22 @@ Error PacketPeerUDP::_set_send_address(const String& p_address,int p_port,IP_Add return OK; } +void PacketPeerUDP::set_ip_type(IP::Type p_type) { + close(); + ip_type = p_type; +} + void PacketPeerUDP::_bind_methods() { - ObjectTypeDB::bind_method(_MD("listen:Error","port","ip_type", "recv_buf_size"),&PacketPeerUDP::listen,DEFVAL(IP_Address::TYPE_ANY),DEFVAL(65536)); + ObjectTypeDB::bind_method(_MD("set_ip_type","ip_type"),&PacketPeerUDP::set_ip_type); + ObjectTypeDB::bind_method(_MD("listen:Error","port", "recv_buf_size"),&PacketPeerUDP::listen,DEFVAL(65536)); ObjectTypeDB::bind_method(_MD("close"),&PacketPeerUDP::close); ObjectTypeDB::bind_method(_MD("wait:Error"),&PacketPeerUDP::wait); ObjectTypeDB::bind_method(_MD("is_listening"),&PacketPeerUDP::is_listening); ObjectTypeDB::bind_method(_MD("get_packet_ip"),&PacketPeerUDP::_get_packet_ip); //ObjectTypeDB::bind_method(_MD("get_packet_address"),&PacketPeerUDP::_get_packet_address); ObjectTypeDB::bind_method(_MD("get_packet_port"),&PacketPeerUDP::get_packet_port); - ObjectTypeDB::bind_method(_MD("set_send_address","host","port","ip_type"),&PacketPeerUDP::_set_send_address,DEFVAL(IP_Address::TYPE_ANY)); + ObjectTypeDB::bind_method(_MD("set_send_address","host","port"),&PacketPeerUDP::_set_send_address); } @@ -83,4 +87,5 @@ PacketPeerUDP* PacketPeerUDP::create() { PacketPeerUDP::PacketPeerUDP() { + ip_type = IP::TYPE_ANY; } diff --git a/core/io/packet_peer_udp.h b/core/io/packet_peer_udp.h index 82205672ec..5f80ea08fc 100644 --- a/core/io/packet_peer_udp.h +++ b/core/io/packet_peer_udp.h @@ -30,6 +30,7 @@ #define PACKET_PEER_UDP_H +#include "io/ip.h" #include "io/packet_peer.h" class PacketPeerUDP : public PacketPeer { @@ -37,16 +38,19 @@ class PacketPeerUDP : public PacketPeer { protected: + IP::Type ip_type; + static PacketPeerUDP* (*_create)(); static void _bind_methods(); String _get_packet_ip() const; - virtual Error _set_send_address(const String& p_address,int p_port, IP_Address::AddrType p_address_type = IP_Address::TYPE_ANY); + virtual Error _set_send_address(const String& p_address,int p_port); public: - virtual Error listen(int p_port, IP_Address::AddrType p_address_type = IP_Address::TYPE_ANY, int p_recv_buffer_size=65536)=0; + virtual void set_ip_type(IP::Type p_type); + virtual Error listen(int p_port, int p_recv_buffer_size=65536)=0; virtual void close()=0; virtual Error wait()=0; virtual bool is_listening() const=0; diff --git a/core/io/stream_peer_tcp.cpp b/core/io/stream_peer_tcp.cpp index e2ddc11933..52cc11a4a4 100644 --- a/core/io/stream_peer_tcp.cpp +++ b/core/io/stream_peer_tcp.cpp @@ -30,15 +30,13 @@ StreamPeerTCP* (*StreamPeerTCP::_create)()=NULL; -VARIANT_ENUM_CAST(IP_Address::AddrType); - -Error StreamPeerTCP::_connect(const String& p_address,int p_port,IP_Address::AddrType p_type) { +Error StreamPeerTCP::_connect(const String& p_address,int p_port) { IP_Address ip; if (p_address.is_valid_ip_address()) { ip=p_address; } else { - ip=IP::get_singleton()->resolve_hostname(p_address, p_type); + ip=IP::get_singleton()->resolve_hostname(p_address, ip_type); if (ip==IP_Address()) return ERR_CANT_RESOLVE; } @@ -47,9 +45,15 @@ Error StreamPeerTCP::_connect(const String& p_address,int p_port,IP_Address::Add return OK; } +void StreamPeerTCP::set_ip_type(IP::Type p_type) { + disconnect(); + ip_type = p_type; +} + void StreamPeerTCP::_bind_methods() { - ObjectTypeDB::bind_method(_MD("connect","host","port","ip_type"),&StreamPeerTCP::_connect,DEFVAL(IP_Address::TYPE_ANY)); + ObjectTypeDB::bind_method(_MD("set_ip_type","ip_type"),&StreamPeerTCP::set_ip_type); + ObjectTypeDB::bind_method(_MD("connect","host","port"),&StreamPeerTCP::_connect); ObjectTypeDB::bind_method(_MD("is_connected"),&StreamPeerTCP::is_connected); ObjectTypeDB::bind_method(_MD("get_status"),&StreamPeerTCP::get_status); ObjectTypeDB::bind_method(_MD("get_connected_host"),&StreamPeerTCP::get_connected_host); @@ -79,6 +83,7 @@ StreamPeerTCP* StreamPeerTCP::create() { StreamPeerTCP::StreamPeerTCP() { + ip_type = IP::TYPE_ANY; } StreamPeerTCP::~StreamPeerTCP() { diff --git a/core/io/stream_peer_tcp.h b/core/io/stream_peer_tcp.h index ecc1beaccb..abc5947fff 100644 --- a/core/io/stream_peer_tcp.h +++ b/core/io/stream_peer_tcp.h @@ -51,12 +51,15 @@ public: protected: - virtual Error _connect(const String& p_address, int p_port, IP_Address::AddrType p_type = IP_Address::TYPE_ANY); + IP::Type ip_type; + + virtual Error _connect(const String& p_address, int p_port); static StreamPeerTCP* (*_create)(); static void _bind_methods(); public: + virtual void set_ip_type(IP::Type p_type); virtual Error connect(const IP_Address& p_host, uint16_t p_port)=0; //read/write from streampeer diff --git a/core/io/tcp_server.cpp b/core/io/tcp_server.cpp index 77a3d8331d..431b17321b 100644 --- a/core/io/tcp_server.cpp +++ b/core/io/tcp_server.cpp @@ -30,8 +30,6 @@ TCP_Server* (*TCP_Server::_create)()=NULL; -VARIANT_ENUM_CAST(IP_Address::AddrType); - Ref<TCP_Server> TCP_Server::create_ref() { if (!_create) @@ -46,19 +44,25 @@ TCP_Server* TCP_Server::create() { return _create(); } -Error TCP_Server::_listen(uint16_t p_port, IP_Address::AddrType p_type, DVector<String> p_accepted_hosts) { +Error TCP_Server::_listen(uint16_t p_port, DVector<String> p_accepted_hosts) { List<String> hosts; for(int i=0;i<p_accepted_hosts.size();i++) hosts.push_back(p_accepted_hosts.get(i)); - return listen(p_port,p_type, hosts.size()?&hosts:NULL); + return listen(p_port, hosts.size()?&hosts:NULL); + +} +void TCP_Server::set_ip_type(IP::Type p_type) { + stop(); + ip_type = p_type; } void TCP_Server::_bind_methods() { - ObjectTypeDB::bind_method(_MD("listen","port","ip_type", "accepted_hosts"),&TCP_Server::_listen,DEFVAL(IP_Address::TYPE_ANY),DEFVAL(DVector<String>())); + ObjectTypeDB::bind_method(_MD("set_ip_type","ip_type"),&TCP_Server::set_ip_type); + ObjectTypeDB::bind_method(_MD("listen","port","accepted_hosts"),&TCP_Server::_listen,DEFVAL(DVector<String>())); ObjectTypeDB::bind_method(_MD("is_connection_available"),&TCP_Server::is_connection_available); ObjectTypeDB::bind_method(_MD("take_connection"),&TCP_Server::take_connection); ObjectTypeDB::bind_method(_MD("stop"),&TCP_Server::stop); @@ -68,4 +72,5 @@ void TCP_Server::_bind_methods() { TCP_Server::TCP_Server() { + ip_type = IP::TYPE_ANY; } diff --git a/core/io/tcp_server.h b/core/io/tcp_server.h index 7288fbb492..14153a3324 100644 --- a/core/io/tcp_server.h +++ b/core/io/tcp_server.h @@ -38,14 +38,17 @@ class TCP_Server : public Reference { OBJ_TYPE( TCP_Server, Reference ); protected: + IP::Type ip_type; + static TCP_Server* (*_create)(); //bind helper - Error _listen(uint16_t p_port, IP_Address::AddrType p_type = IP_Address::TYPE_ANY ,DVector<String> p_accepted_hosts=DVector<String>()); + Error _listen(uint16_t p_port, DVector<String> p_accepted_hosts=DVector<String>()); static void _bind_methods(); public: - virtual Error listen(uint16_t p_port, IP_Address::AddrType p_type = IP_Address::TYPE_ANY, const List<String> *p_accepted_hosts=NULL)=0; + virtual void set_ip_type(IP::Type p_type); + virtual Error listen(uint16_t p_port, const List<String> *p_accepted_hosts=NULL)=0; virtual bool is_connection_available() const=0; virtual Ref<StreamPeerTCP> take_connection()=0; diff --git a/core/variant_call.cpp b/core/variant_call.cpp index 9c27f80e67..0707332be9 100644 --- a/core/variant_call.cpp +++ b/core/variant_call.cpp @@ -1825,10 +1825,6 @@ _VariantCall::addfunc(Variant::m_vtype,Variant::m_ret,_SCS(#m_method),VCALL(m_cl _VariantCall::add_constant(Variant::IMAGE,"INTERPOLATE_BILINEAR",Image::INTERPOLATE_BILINEAR); _VariantCall::add_constant(Variant::IMAGE,"INTERPOLATE_CUBIC",Image::INTERPOLATE_CUBIC); - _VariantCall::add_constant(Variant::INT, "IP_TYPE_NONE", IP_Address::TYPE_NONE); - _VariantCall::add_constant(Variant::INT, "IP_TYPE_IPV4", IP_Address::TYPE_IPV4); - _VariantCall::add_constant(Variant::INT, "IP_TYPE_IPV6", IP_Address::TYPE_IPV6); - _VariantCall::add_constant(Variant::INT, "IP_TYPE_ANY", IP_Address::TYPE_ANY); } void unregister_variant_methods() { diff --git a/doc/base/classes.xml b/doc/base/classes.xml index 82f54d16b8..d637127823 100644 --- a/doc/base/classes.xml +++ b/doc/base/classes.xml @@ -11864,6 +11864,13 @@ Get the main editor control. Use this as a parent for main screens. </description> </method> + <method name="edit_resource"> + <argument index="0" name="p_resource" type="Resource"> + </argument> + <description> + Tells the editor to handle the edit of the given resource. Ex: If you pass a Script as a argument, the editor will open the scriptEditor. + </description> + </method> <method name="get_name" qualifiers="virtual"> <return type="String"> </return> @@ -16087,7 +16094,7 @@ </return> <argument index="0" name="host" type="String"> </argument> - <argument index="1" name="ip_type" type="int" default="int.IP_TYPE_ANY"> + <argument index="1" name="ip_type" type="int" default="IP.TYPE_ANY"> </argument> <description> Resolve a given hostname, blocking. Resolved hostname is returned as an IPv4 or IPv6 depending on "ip_type". @@ -16098,7 +16105,7 @@ </return> <argument index="0" name="host" type="String"> </argument> - <argument index="1" name="ip_type" type="int" default="int.IP_TYPE_ANY"> + <argument index="1" name="ip_type" type="int" default="IP.TYPE_ANY"> </argument> <description> Create a queue item for resolving a given hostname to an IPv4 or IPv6 depending on "ip_type". The queue ID is returned, or RESOLVER_INVALID_ID on error. @@ -25380,15 +25387,10 @@ </return> <argument index="0" name="port" type="int"> </argument> - <argument index="1" name="ip_type" type="int" default="int.IP_TYPE_ANY"> - </argument> - <argument index="2" name="recv_buf_size" type="int" default="65536"> + <argument index="1" name="recv_buf_size" type="int" default="65536"> </argument> <description> - Make this [PacketPeerUDP] listen on the "port" using protocol "ip_type" and a buffer size "recv_buf_size". Listens on all available adresses. - IP_TYPE_IPV4 = IPv4 only - IP_TYPE_IPV6 = IPv6 only - IP_TYPE_ANY = Dual stack (supports both IPv6 and IPv4 connections). + Make this [PacketPeerUDP] listen on the "port" with a buffer size "recv_buf_size". Listens on all available addresses. </description> </method> <method name="set_send_address"> @@ -25398,10 +25400,8 @@ </argument> <argument index="1" name="port" type="int"> </argument> - <argument index="2" name="ip_type" type="int" default="int.IP_TYPE_ANY"> - </argument> <description> - Set the destination address and port for sending packets and variables, a hostname will be resolved using "ip_type" (v4/v6/any) if valid. + Set the destination address and port for sending packets and variables, a hostname will be resolved using if valid. </description> </method> <method name="wait"> @@ -39225,10 +39225,8 @@ </argument> <argument index="1" name="port" type="int"> </argument> - <argument index="2" name="ip_type" type="int" default="int.IP_TYPE_ANY"> - </argument> <description> - Connect to the specified host:port pair. A hostname will be resolved using "ip_type" (v4/v6/any) if valid. Returns [OK] on success or [FAILED] on failure. + Connect to the specified host:port pair. A hostname will be resolved if valid. Returns [OK] on success or [FAILED] on failure. </description> </method> <method name="disconnect"> @@ -40551,15 +40549,10 @@ </return> <argument index="0" name="port" type="int"> </argument> - <argument index="1" name="ip_type" type="int" default="int.IP_TYPE_ANY"> - </argument> - <argument index="2" name="accepted_hosts" type="StringArray" default="StringArray([])"> + <argument index="1" name="accepted_hosts" type="StringArray" default="StringArray([])"> </argument> <description> - Listen on a port using protocol "ip_type", alternatively give a white-list of accepted hosts. - IP_TYPE_IPV4 = IPv4 only - IP_TYPE_IPV6 = IPv6 only - IP_TYPE_ANY = Dual stack (supports both IPv6 and IPv4 connections). + Listen on a port using protocol, alternatively give a white-list of accepted hosts. </description> </method> <method name="stop"> diff --git a/drivers/unix/ip_unix.cpp b/drivers/unix/ip_unix.cpp index f1f130e30f..0ebd593953 100644 --- a/drivers/unix/ip_unix.cpp +++ b/drivers/unix/ip_unix.cpp @@ -37,9 +37,6 @@ #ifndef AI_ADDRCONFIG #define AI_ADDRCONFIG 0x00000400 #endif - #ifndef AI_V4MAPPED - #define AI_V4MAPPED 0x00000800 - #endif #ifdef UWP_ENABLED #include <ws2tcpip.h> #include <winsock2.h> @@ -75,32 +72,29 @@ static IP_Address _sockaddr2ip(struct sockaddr* p_addr) { IP_Address ip; if (p_addr->sa_family == AF_INET) { struct sockaddr_in* addr = (struct sockaddr_in*)p_addr; - ip.field32[0] = *((unsigned long*)&addr->sin_addr); - ip.type = IP_Address::TYPE_IPV4; + ip.set_ipv4((uint8_t *)&(addr->sin_addr)); } else { struct sockaddr_in6* addr6 = (struct sockaddr_in6*)p_addr; - for (int i=0; i<16; i++) - ip.field8[i] = addr6->sin6_addr.s6_addr[i]; - ip.type = IP_Address::TYPE_IPV6; + ip.set_ipv6(addr6->sin6_addr.s6_addr); }; return ip; }; -IP_Address IP_Unix::_resolve_hostname(const String& p_hostname, IP_Address::AddrType p_type) { +IP_Address IP_Unix::_resolve_hostname(const String& p_hostname, Type p_type) { struct addrinfo hints; struct addrinfo* result; memset(&hints, 0, sizeof(struct addrinfo)); - if (p_type == IP_Address::TYPE_IPV4) { + if (p_type == TYPE_IPV4) { hints.ai_family = AF_INET; - } else if (p_type == IP_Address::TYPE_IPV6) { + } else if (p_type == TYPE_IPV6) { hints.ai_family = AF_INET6; hints.ai_flags = 0; } else { hints.ai_family = AF_UNSPEC; - hints.ai_flags = (AI_V4MAPPED | AI_ADDRCONFIG); + hints.ai_flags = AI_ADDRCONFIG; }; int s = getaddrinfo(p_hostname.utf8().get_data(), NULL, &hints, &result); @@ -184,15 +178,12 @@ void IP_Unix::get_local_addresses(List<IP_Address> *r_addresses) const { SOCKADDR_IN* ipv4 = reinterpret_cast<SOCKADDR_IN*>(address->Address.lpSockaddr); - ip.field32[0] = *((unsigned long*)&ipv4->sin_addr); - ip.type = IP_Address::TYPE_IPV4; + ip.set_ipv4((uint8_t *)&(ipv4->sin_addr)); } else { // ipv6 SOCKADDR_IN6* ipv6 = reinterpret_cast<SOCKADDR_IN6*>(address->Address.lpSockaddr); - for (int i=0; i<16; i++) { - ip.field8[i] = ipv6->sin6_addr.s6_addr[i]; - }; - ip.type = IP_Address::TYPE_IPV6; + + ip.set_ipv6(ipv6->sin6_addr.s6_addr); }; diff --git a/drivers/unix/ip_unix.h b/drivers/unix/ip_unix.h index c901265a2b..00870d5492 100644 --- a/drivers/unix/ip_unix.h +++ b/drivers/unix/ip_unix.h @@ -36,7 +36,7 @@ class IP_Unix : public IP { OBJ_TYPE(IP_Unix, IP); - virtual IP_Address _resolve_hostname(const String& p_hostname, IP_Address::AddrType p_type); + virtual IP_Address _resolve_hostname(const String& p_hostname, IP::Type p_type); static IP* _create_unix(); public: diff --git a/drivers/unix/packet_peer_udp_posix.cpp b/drivers/unix/packet_peer_udp_posix.cpp index 2a2d8ba426..4d9ef6cdae 100644 --- a/drivers/unix/packet_peer_udp_posix.cpp +++ b/drivers/unix/packet_peer_udp_posix.cpp @@ -76,12 +76,14 @@ Error PacketPeerUDPPosix::get_packet(const uint8_t **r_buffer,int &r_buffer_size uint32_t size; uint8_t type; rb.read(&type, 1, true); - if (type == IP_Address::TYPE_IPV4) { - rb.read((uint8_t*)&packet_ip.field8,4,true); - packet_ip.type = IP_Address::TYPE_IPV4; + if (type == IP::TYPE_IPV4) { + uint8_t ip[4]; + rb.read(ip,4,true); + packet_ip.set_ipv4(ip); } else { - rb.read((uint8_t*)&packet_ip.field8,16,true); - packet_ip.type = IP_Address::TYPE_IPV6; + uint8_t ipv6[16]; + rb.read(ipv6,16,true); + packet_ip.set_ipv6(ipv6); }; rb.read((uint8_t*)&packet_port,4,true); rb.read((uint8_t*)&size,4,true); @@ -94,12 +96,12 @@ Error PacketPeerUDPPosix::get_packet(const uint8_t **r_buffer,int &r_buffer_size } Error PacketPeerUDPPosix::put_packet(const uint8_t *p_buffer,int p_buffer_size){ - ERR_FAIL_COND_V(peer_addr.type == IP_Address::TYPE_NONE, ERR_UNCONFIGURED); + ERR_FAIL_COND_V(peer_addr == IP_Address(), ERR_UNCONFIGURED); - int sock = _get_socket(peer_addr.type); + int sock = _get_socket(); ERR_FAIL_COND_V( sock == -1, FAILED ); struct sockaddr_storage addr; - size_t addr_size = _set_sockaddr(&addr, peer_addr, peer_port); + size_t addr_size = _set_sockaddr(&addr, peer_addr, peer_port, ip_type); errno = 0; int err; @@ -119,24 +121,16 @@ int PacketPeerUDPPosix::get_max_packet_size() const{ return 512; // uhm maybe not } -Error PacketPeerUDPPosix::listen(int p_port, IP_Address::AddrType p_type, int p_recv_buffer_size) { +Error PacketPeerUDPPosix::listen(int p_port, int p_recv_buffer_size) { close(); - int sock = _get_socket(p_type); + int sock = _get_socket(); if (sock == -1 ) return ERR_CANT_CREATE; - if(p_type == IP_Address::TYPE_IPV6) { - // Use IPv6 only socket - int yes = 1; - if(setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY, (const char*)&yes, sizeof(yes)) != 0) { - WARN_PRINT("Unable to unset IPv4 address mapping over IPv6"); - } - } - sockaddr_storage addr = {0}; - size_t addr_size = _set_listen_sockaddr(&addr, p_port, p_type, NULL); + size_t addr_size = _set_listen_sockaddr(&addr, p_port, ip_type, NULL); if (bind(sock, (struct sockaddr*)&addr, addr_size) == -1 ) { close(); @@ -171,7 +165,7 @@ Error PacketPeerUDPPosix::_poll(bool p_wait) { uint32_t port = 0; if (from.ss_family == AF_INET) { - uint8_t type = (uint8_t)IP_Address::TYPE_IPV4; + uint8_t type = (uint8_t)IP::TYPE_IPV4; rb.write(&type, 1); struct sockaddr_in* sin_from = (struct sockaddr_in*)&from; rb.write((uint8_t*)&sin_from->sin_addr, 4); @@ -179,7 +173,7 @@ Error PacketPeerUDPPosix::_poll(bool p_wait) { } else if (from.ss_family == AF_INET6) { - uint8_t type = (uint8_t)IP_Address::TYPE_IPV6; + uint8_t type = (uint8_t)IP::TYPE_IPV6; rb.write(&type, 1); struct sockaddr_in6* s6_from = (struct sockaddr_in6*)&from; @@ -189,7 +183,7 @@ Error PacketPeerUDPPosix::_poll(bool p_wait) { } else { // WARN_PRINT("Ignoring packet with unknown address family"); - uint8_t type = (uint8_t)IP_Address::TYPE_NONE; + uint8_t type = (uint8_t)IP::TYPE_NONE; rb.write(&type, 1); }; @@ -225,12 +219,12 @@ int PacketPeerUDPPosix::get_packet_port() const{ return packet_port; } -int PacketPeerUDPPosix::_get_socket(IP_Address::AddrType p_type) { +int PacketPeerUDPPosix::_get_socket() { if (sockfd != -1) return sockfd; - sockfd = _socket_create(p_type, SOCK_DGRAM, IPPROTO_UDP); + sockfd = _socket_create(ip_type, SOCK_DGRAM, IPPROTO_UDP); return sockfd; } @@ -259,6 +253,7 @@ PacketPeerUDPPosix::PacketPeerUDPPosix() { packet_port=0; queue_count=0; peer_port=0; + ip_type = IP::TYPE_ANY; } PacketPeerUDPPosix::~PacketPeerUDPPosix() { diff --git a/drivers/unix/packet_peer_udp_posix.h b/drivers/unix/packet_peer_udp_posix.h index 8449dd2331..89b8886cf5 100644 --- a/drivers/unix/packet_peer_udp_posix.h +++ b/drivers/unix/packet_peer_udp_posix.h @@ -52,7 +52,7 @@ class PacketPeerUDPPosix : public PacketPeerUDP { IP_Address peer_addr; int peer_port; - _FORCE_INLINE_ int _get_socket(IP_Address::AddrType p_type); + _FORCE_INLINE_ int _get_socket(); static PacketPeerUDP* _create(); virtual Error _poll(bool p_block); @@ -65,7 +65,7 @@ public: virtual int get_max_packet_size() const; - virtual Error listen(int p_port, IP_Address::AddrType p_address_type, int p_recv_buffer_size=65536); + virtual Error listen(int p_port, int p_recv_buffer_size=65536); virtual void close(); virtual Error wait(); virtual bool is_listening() const; diff --git a/drivers/unix/socket_helpers.h b/drivers/unix/socket_helpers.h index 5e8e8dfd7a..962f228c3c 100644 --- a/drivers/unix/socket_helpers.h +++ b/drivers/unix/socket_helpers.h @@ -16,31 +16,42 @@ // helpers for sockaddr -> IP_Address and back, should work for posix and winsock. All implementations should use this -static size_t _set_sockaddr(struct sockaddr_storage* p_addr, const IP_Address& p_ip, int p_port) { +static size_t _set_sockaddr(struct sockaddr_storage* p_addr, const IP_Address& p_ip, int p_port, IP::Type p_sock_type = IP::TYPE_ANY) { memset(p_addr, 0, sizeof(struct sockaddr_storage)); - if (p_ip.type == IP_Address::TYPE_IPV6) { + + ERR_FAIL_COND_V(p_ip==IP_Address(),0); + + // IPv6 socket + if (p_sock_type == IP::TYPE_IPV6 || p_sock_type == IP::TYPE_ANY) { + + // IPv6 only socket with IPv4 address + ERR_FAIL_COND_V(p_sock_type == IP::TYPE_IPV6 && p_ip.is_ipv4(),0); struct sockaddr_in6* addr6 = (struct sockaddr_in6*)p_addr; addr6->sin6_family = AF_INET6; addr6->sin6_port = htons(p_port); - copymem(&addr6->sin6_addr.s6_addr, p_ip.field8, 16); + copymem(&addr6->sin6_addr.s6_addr, p_ip.get_ipv6(), 16); return sizeof(sockaddr_in6); - } else { + } else { // IPv4 socket + // IPv4 socket with IPv6 address + ERR_FAIL_COND_V(!p_ip.is_ipv4(),0); + + uint32_t ipv4 = *((uint32_t *)p_ip.get_ipv4()); struct sockaddr_in* addr4 = (struct sockaddr_in*)p_addr; - addr4->sin_family = AF_INET; // host byte order + addr4->sin_family = AF_INET; addr4->sin_port = htons(p_port); // short, network byte order - addr4->sin_addr = *((struct in_addr*)&p_ip.field32[0]); + copymem(&addr4->sin_addr.s_addr, p_ip.get_ipv4(), 16); return sizeof(sockaddr_in); }; }; -static size_t _set_listen_sockaddr(struct sockaddr_storage* p_addr, int p_port, IP_Address::AddrType p_address_type, const List<String> *p_accepted_hosts) { +static size_t _set_listen_sockaddr(struct sockaddr_storage* p_addr, int p_port, IP::Type p_sock_type, const List<String> *p_accepted_hosts) { memset(p_addr, 0, sizeof(struct sockaddr_storage)); - if (p_address_type == IP_Address::TYPE_IPV4) { + if (p_sock_type == IP::TYPE_IPV4) { struct sockaddr_in* addr4 = (struct sockaddr_in*)p_addr; addr4->sin_family = AF_INET; addr4->sin_port = htons(p_port); @@ -56,20 +67,20 @@ static size_t _set_listen_sockaddr(struct sockaddr_storage* p_addr, int p_port, }; }; -static int _socket_create(IP_Address::AddrType p_type, int type, int protocol) { +static int _socket_create(IP::Type p_type, int type, int protocol) { - ERR_FAIL_COND_V(p_type > IP_Address::TYPE_ANY || p_type < IP_Address::TYPE_NONE, ERR_INVALID_PARAMETER); + ERR_FAIL_COND_V(p_type > IP::TYPE_ANY || p_type < IP::TYPE_NONE, ERR_INVALID_PARAMETER); - int family = p_type == IP_Address::TYPE_IPV4 ? AF_INET : AF_INET6; + int family = p_type == IP::TYPE_IPV4 ? AF_INET : AF_INET6; int sockfd = socket(family, type, protocol); ERR_FAIL_COND_V( sockfd == -1, -1 ); if(family == AF_INET6) { - // Ensure IPv4 over IPv6 is enabled - int no = 0; - if(setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY, (const char*)&no, sizeof(no)) != 0) { - WARN_PRINT("Unable to set IPv4 address mapping over IPv6"); + // Select IPv4 over IPv6 mapping + int opt = p_type != IP::TYPE_ANY; + if(setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY, (const char*)&opt, sizeof(opt)) != 0) { + WARN_PRINT("Unable to set/unset IPv4 address mapping over IPv6"); } } @@ -80,19 +91,16 @@ static int _socket_create(IP_Address::AddrType p_type, int type, int protocol) { static void _set_ip_addr_port(IP_Address& r_ip, int& r_port, struct sockaddr_storage* p_addr) { if (p_addr->ss_family == AF_INET) { - r_ip.type = IP_Address::TYPE_IPV4; struct sockaddr_in* addr4 = (struct sockaddr_in*)p_addr; - r_ip.field32[0] = (uint32_t)addr4->sin_addr.s_addr; + r_ip.set_ipv4((uint8_t *)&(addr4->sin_addr.s_addr)); r_port = ntohs(addr4->sin_port); } else if (p_addr->ss_family == AF_INET6) { - r_ip.type = IP_Address::TYPE_IPV6; - struct sockaddr_in6* addr6 = (struct sockaddr_in6*)p_addr; - copymem(&addr6->sin6_addr.s6_addr, r_ip.field8, 16); + r_ip.set_ipv6(addr6->sin6_addr.s6_addr); r_port = ntohs(addr6->sin6_port); }; diff --git a/drivers/unix/stream_peer_tcp_posix.cpp b/drivers/unix/stream_peer_tcp_posix.cpp index 76f654a277..f2a1417920 100644 --- a/drivers/unix/stream_peer_tcp_posix.cpp +++ b/drivers/unix/stream_peer_tcp_posix.cpp @@ -98,7 +98,7 @@ Error StreamPeerTCPPosix::_poll_connection(bool p_block) const { }; struct sockaddr_storage their_addr; - size_t addr_size = _set_sockaddr(&their_addr, peer_host, peer_port); + size_t addr_size = _set_sockaddr(&their_addr, peer_host, peer_port, ip_type); if (::connect(sockfd, (struct sockaddr *)&their_addr,addr_size) == -1) { @@ -107,7 +107,12 @@ Error StreamPeerTCPPosix::_poll_connection(bool p_block) const { return OK; }; - return OK; + if (errno == EINPROGRESS || errno == EALREADY) { + return OK; + } + + status = STATUS_ERROR; + return ERR_CONNECTION_ERROR; } else { status = STATUS_CONNECTED; @@ -117,8 +122,9 @@ Error StreamPeerTCPPosix::_poll_connection(bool p_block) const { return OK; }; -void StreamPeerTCPPosix::set_socket(int p_sockfd, IP_Address p_host, int p_port) { +void StreamPeerTCPPosix::set_socket(int p_sockfd, IP_Address p_host, int p_port, IP::Type p_ip_type) { + ip_type = p_ip_type; sockfd = p_sockfd; #ifndef NO_FCNTL fcntl(sockfd, F_SETFL, O_NONBLOCK); @@ -135,9 +141,9 @@ void StreamPeerTCPPosix::set_socket(int p_sockfd, IP_Address p_host, int p_port) Error StreamPeerTCPPosix::connect(const IP_Address& p_host, uint16_t p_port) { - ERR_FAIL_COND_V( p_host.type == IP_Address::TYPE_NONE, ERR_INVALID_PARAMETER); + ERR_FAIL_COND_V( p_host == IP_Address(), ERR_INVALID_PARAMETER); - sockfd = _socket_create(p_host.type, SOCK_STREAM, IPPROTO_TCP); + sockfd = _socket_create(ip_type, SOCK_STREAM, IPPROTO_TCP); if (sockfd == -1) { ERR_PRINT("Socket creation failed!"); disconnect(); @@ -153,7 +159,7 @@ Error StreamPeerTCPPosix::connect(const IP_Address& p_host, uint16_t p_port) { #endif struct sockaddr_storage their_addr; - size_t addr_size = _set_sockaddr(&their_addr, p_host, p_port); + size_t addr_size = _set_sockaddr(&their_addr, p_host, p_port, ip_type); errno = 0; if (::connect(sockfd, (struct sockaddr *)&their_addr,addr_size) == -1 && errno != EINPROGRESS) { @@ -387,6 +393,7 @@ StreamPeerTCPPosix::StreamPeerTCPPosix() { sockfd = -1; status = STATUS_NONE; peer_port = 0; + ip_type = IP::TYPE_ANY; }; StreamPeerTCPPosix::~StreamPeerTCPPosix() { diff --git a/drivers/unix/stream_peer_tcp_posix.h b/drivers/unix/stream_peer_tcp_posix.h index df0a49da61..1df509cac4 100644 --- a/drivers/unix/stream_peer_tcp_posix.h +++ b/drivers/unix/stream_peer_tcp_posix.h @@ -69,7 +69,7 @@ public: virtual int get_available_bytes() const; - void set_socket(int p_sockfd, IP_Address p_host, int p_port); + void set_socket(int p_sockfd, IP_Address p_host, int p_port, IP::Type p_ip_type); virtual IP_Address get_connected_host() const; virtual uint16_t get_connected_port() const; diff --git a/drivers/unix/tcp_server_posix.cpp b/drivers/unix/tcp_server_posix.cpp index ef971c0c70..0178f08b8c 100644 --- a/drivers/unix/tcp_server_posix.cpp +++ b/drivers/unix/tcp_server_posix.cpp @@ -68,20 +68,13 @@ void TCPServerPosix::make_default() { TCP_Server::_create = TCPServerPosix::_create; }; -Error TCPServerPosix::listen(uint16_t p_port, IP_Address::AddrType p_type, const List<String> *p_accepted_hosts) { +Error TCPServerPosix::listen(uint16_t p_port,const List<String> *p_accepted_hosts) { int sockfd; - sockfd = _socket_create(p_type, SOCK_STREAM, IPPROTO_TCP); + sockfd = _socket_create(ip_type, SOCK_STREAM, IPPROTO_TCP); ERR_FAIL_COND_V(sockfd == -1, FAILED); - if(p_type == IP_Address::TYPE_IPV6) { - // Use IPv6 only socket - int yes = 1; - if(setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY, (const char*)&yes, sizeof(yes)) != 0) { - WARN_PRINT("Unable to unset IPv4 address mapping over IPv6"); - } - } #ifndef NO_FCNTL fcntl(sockfd, F_SETFL, O_NONBLOCK); #else @@ -95,7 +88,7 @@ Error TCPServerPosix::listen(uint16_t p_port, IP_Address::AddrType p_type, const } struct sockaddr_storage addr; - size_t addr_size = _set_listen_sockaddr(&addr, p_port, p_type, p_accepted_hosts); + size_t addr_size = _set_listen_sockaddr(&addr, p_port, ip_type, p_accepted_hosts); // automatically fill with my IP TODO: use p_accepted_hosts @@ -164,7 +157,7 @@ Ref<StreamPeerTCP> TCPServerPosix::take_connection() { int port; _set_ip_addr_port(ip, port, &their_addr); - conn->set_socket(fd, ip, port); + conn->set_socket(fd, ip, port, ip_type); return conn; }; @@ -183,6 +176,7 @@ void TCPServerPosix::stop() { TCPServerPosix::TCPServerPosix() { listen_sockfd = -1; + ip_type = IP::TYPE_ANY; }; TCPServerPosix::~TCPServerPosix() { diff --git a/drivers/unix/tcp_server_posix.h b/drivers/unix/tcp_server_posix.h index 03020f3822..6f9fa8cb5b 100644 --- a/drivers/unix/tcp_server_posix.h +++ b/drivers/unix/tcp_server_posix.h @@ -40,7 +40,7 @@ class TCPServerPosix : public TCP_Server { public: - virtual Error listen(uint16_t p_port, IP_Address::AddrType p_type, const List<String> *p_accepted_hosts=NULL); + virtual Error listen(uint16_t p_port,const List<String> *p_accepted_hosts=NULL); virtual bool is_connection_available() const; virtual Ref<StreamPeerTCP> take_connection(); diff --git a/modules/enet/networked_multiplayer_enet.cpp b/modules/enet/networked_multiplayer_enet.cpp index 695d69ded8..2ee0d8fb61 100644 --- a/modules/enet/networked_multiplayer_enet.cpp +++ b/modules/enet/networked_multiplayer_enet.cpp @@ -77,7 +77,7 @@ Error NetworkedMultiplayerENet::create_server(int p_port, int p_max_clients, int Error NetworkedMultiplayerENet::create_client(const IP_Address& p_ip, int p_port, int p_in_bandwidth, int p_out_bandwidth){ ERR_FAIL_COND_V(active,ERR_ALREADY_IN_USE); - ERR_FAIL_COND_V(p_ip.type != IP_Address::TYPE_IPV4, ERR_INVALID_PARAMETER); + ERR_FAIL_COND_V(!p_ip.is_ipv4(), ERR_INVALID_PARAMETER); host = enet_host_create (NULL /* create a client host */, 1 /* only allow 1 outgoing connection */, @@ -91,7 +91,7 @@ Error NetworkedMultiplayerENet::create_client(const IP_Address& p_ip, int p_port _setup_compressor(); ENetAddress address; - address.host=p_ip.field32[0]; + address.host=*((uint32_t *)p_ip.get_ipv4()); address.port=p_port; //enet_address_set_host (& address, "localhost"); @@ -150,8 +150,7 @@ void NetworkedMultiplayerENet::poll(){ } IP_Address ip; - ip.type = IP_Address::TYPE_IPV4; - ip.field32[0]=event.peer -> address.host; + ip.set_ipv4((uint8_t *)&(event.peer -> address.host)); int *new_id = memnew( int ); *new_id = event.data; @@ -685,6 +684,6 @@ NetworkedMultiplayerENet::~NetworkedMultiplayerENet(){ // sets IP for ENet to bind when using create_server // if no IP is set, then ENet bind to ENET_HOST_ANY void NetworkedMultiplayerENet::set_bind_ip(const IP_Address& p_ip){ - ERR_FAIL_COND(p_ip.type != IP_Address::TYPE_IPV4); - bind_ip=p_ip.field32[0]; + ERR_FAIL_COND(!p_ip.is_ipv4()); + bind_ip=*(uint32_t *)p_ip.get_ipv4(); } diff --git a/modules/gdscript/gd_parser.cpp b/modules/gdscript/gd_parser.cpp index 364ec488e2..8127324d2e 100644 --- a/modules/gdscript/gd_parser.cpp +++ b/modules/gdscript/gd_parser.cpp @@ -1478,6 +1478,15 @@ GDParser::Node* GDParser::_reduce_expression(Node *p_node,bool p_to_const) { return op; } + if (op->arguments[0]->type==Node::TYPE_OPERATOR) { + OperatorNode *on = static_cast<OperatorNode*>(op->arguments[0]); + if (on->op != OperatorNode::OP_INDEX && on->op != OperatorNode::OP_INDEX_NAMED) { + _set_error("Can't assign to an expression",tokenizer->get_token_line()-1); + error_line=op->line; + return op; + } + } + } break; default: { break; } } @@ -2014,7 +2023,7 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) { } break; default: { - Node *expression = _parse_and_reduce_expression(p_block,p_static,false,true); + Node *expression = _parse_and_reduce_expression(p_block,p_static,true,true); if (!expression) { if (_recover_from_completion()) { break; diff --git a/platform/windows/packet_peer_udp_winsock.cpp b/platform/windows/packet_peer_udp_winsock.cpp index 18c3814cfc..ef497c428d 100644 --- a/platform/windows/packet_peer_udp_winsock.cpp +++ b/platform/windows/packet_peer_udp_winsock.cpp @@ -53,12 +53,14 @@ Error PacketPeerUDPWinsock::get_packet(const uint8_t **r_buffer,int &r_buffer_si uint32_t size; uint8_t type; rb.read(&type, 1, true); - if (type == IP_Address::TYPE_IPV4) { - rb.read((uint8_t*)&packet_ip.field8,4,true); - packet_ip.type = IP_Address::TYPE_IPV4; + if (type == IP::TYPE_IPV4) { + uint8_t ip[4]; + rb.read(ip,4,true); + packet_ip.set_ipv4(ip); } else { - rb.read((uint8_t*)&packet_ip.field8,16,true); - packet_ip.type = IP_Address::TYPE_IPV6; + uint8_t ip[16]; + rb.read(ip,16,true); + packet_ip.set_ipv6(ip); }; rb.read((uint8_t*)&packet_port,4,true); rb.read((uint8_t*)&size,4,true); @@ -71,10 +73,10 @@ Error PacketPeerUDPWinsock::get_packet(const uint8_t **r_buffer,int &r_buffer_si } Error PacketPeerUDPWinsock::put_packet(const uint8_t *p_buffer,int p_buffer_size){ - int sock = _get_socket(peer_addr.type); + int sock = _get_socket(); ERR_FAIL_COND_V( sock == -1, FAILED ); struct sockaddr_storage addr; - size_t addr_size = _set_sockaddr(&addr, peer_addr, peer_port); + size_t addr_size = _set_sockaddr(&addr, peer_addr, peer_port, ip_type); _set_blocking(true); @@ -112,23 +114,15 @@ void PacketPeerUDPWinsock::_set_blocking(bool p_blocking) { }; } -Error PacketPeerUDPWinsock::listen(int p_port, IP_Address::AddrType p_type, int p_recv_buffer_size) { +Error PacketPeerUDPWinsock::listen(int p_port, int p_recv_buffer_size) { close(); - int sock = _get_socket(p_type); + int sock = _get_socket(); if (sock == -1 ) return ERR_CANT_CREATE; - if(p_type == IP_Address::TYPE_IPV6) { - // Use IPv6 only socket - int yes = 1; - if(setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY, (const char*)&yes, sizeof(yes)) != 0) { - WARN_PRINT("Unable to unset IPv4 address mapping over IPv6"); - } - } - struct sockaddr_storage addr = {0}; - size_t addr_size = _set_listen_sockaddr(&addr, p_port, p_type, NULL); + size_t addr_size = _set_listen_sockaddr(&addr, p_port, ip_type, NULL); if (bind(sock, (struct sockaddr*)&addr, addr_size) == -1 ) { close(); @@ -170,7 +164,7 @@ Error PacketPeerUDPWinsock::_poll(bool p_wait) { uint32_t port = 0; if (from.ss_family == AF_INET) { - uint8_t type = (uint8_t)IP_Address::TYPE_IPV4; + uint8_t type = (uint8_t)IP::TYPE_IPV4; rb.write(&type, 1); struct sockaddr_in* sin_from = (struct sockaddr_in*)&from; rb.write((uint8_t*)&sin_from->sin_addr, 4); @@ -178,7 +172,7 @@ Error PacketPeerUDPWinsock::_poll(bool p_wait) { } else if (from.ss_family == AF_INET6) { - uint8_t type = (uint8_t)IP_Address::TYPE_IPV6; + uint8_t type = (uint8_t)IP::TYPE_IPV6; rb.write(&type, 1); struct sockaddr_in6* s6_from = (struct sockaddr_in6*)&from; @@ -188,7 +182,7 @@ Error PacketPeerUDPWinsock::_poll(bool p_wait) { } else { // WARN_PRINT("Ignoring packet with unknown address family"); - uint8_t type = (uint8_t)IP_Address::TYPE_NONE; + uint8_t type = (uint8_t)IP::TYPE_NONE; rb.write(&type, 1); }; @@ -242,12 +236,12 @@ int PacketPeerUDPWinsock::get_packet_port() const{ return packet_port; } -int PacketPeerUDPWinsock::_get_socket(IP_Address::AddrType p_type) { +int PacketPeerUDPWinsock::_get_socket() { if (sockfd != -1) return sockfd; - sockfd = _socket_create(p_type, SOCK_DGRAM, IPPROTO_UDP); + sockfd = _socket_create(ip_type, SOCK_DGRAM, IPPROTO_UDP); return sockfd; } @@ -277,6 +271,7 @@ PacketPeerUDPWinsock::PacketPeerUDPWinsock() { packet_port=0; queue_count=0; peer_port=0; + ip_type = IP::TYPE_ANY; } PacketPeerUDPWinsock::~PacketPeerUDPWinsock() { diff --git a/platform/windows/packet_peer_udp_winsock.h b/platform/windows/packet_peer_udp_winsock.h index f31e73ecd1..2199115889 100644 --- a/platform/windows/packet_peer_udp_winsock.h +++ b/platform/windows/packet_peer_udp_winsock.h @@ -50,7 +50,7 @@ class PacketPeerUDPWinsock : public PacketPeerUDP { IP_Address peer_addr; int peer_port; - _FORCE_INLINE_ int _get_socket(IP_Address::AddrType p_type); + _FORCE_INLINE_ int _get_socket(); static PacketPeerUDP* _create(); @@ -67,7 +67,7 @@ public: virtual int get_max_packet_size() const; - virtual Error listen(int p_port, IP_Address::AddrType p_address_type, int p_recv_buffer_size=65536); + virtual Error listen(int p_port, int p_recv_buffer_size=65536); virtual void close(); virtual Error wait(); virtual bool is_listening() const; diff --git a/platform/windows/stream_peer_winsock.cpp b/platform/windows/stream_peer_winsock.cpp index 7e790c2b6c..a48a02c7a7 100644 --- a/platform/windows/stream_peer_winsock.cpp +++ b/platform/windows/stream_peer_winsock.cpp @@ -88,7 +88,7 @@ Error StreamPeerWinsock::_poll_connection(bool p_block) const { }; struct sockaddr_storage their_addr; - size_t addr_size = _set_sockaddr(&their_addr, peer_host, peer_port); + size_t addr_size = _set_sockaddr(&their_addr, peer_host, peer_port, ip_type); if (::connect(sockfd, (struct sockaddr *)&their_addr,addr_size) == SOCKET_ERROR) { @@ -98,7 +98,12 @@ Error StreamPeerWinsock::_poll_connection(bool p_block) const { return OK; }; - return OK; + if (errno == WSAEINPROGRESS || errno == WSAEALREADY) { + return OK; + } + + status = STATUS_ERROR; + return ERR_CONNECTION_ERROR; } else { status = STATUS_CONNECTED; @@ -284,8 +289,9 @@ void StreamPeerWinsock::disconnect() { peer_port = 0; }; -void StreamPeerWinsock::set_socket(int p_sockfd, IP_Address p_host, int p_port) { +void StreamPeerWinsock::set_socket(int p_sockfd, IP_Address p_host, int p_port, IP::Type p_ip_type) { + ip_type = p_ip_type; sockfd = p_sockfd; status = STATUS_CONNECTING; peer_host = p_host; @@ -294,9 +300,9 @@ void StreamPeerWinsock::set_socket(int p_sockfd, IP_Address p_host, int p_port) Error StreamPeerWinsock::connect(const IP_Address& p_host, uint16_t p_port) { - ERR_FAIL_COND_V( p_host.type == IP_Address::TYPE_NONE, ERR_INVALID_PARAMETER); + ERR_FAIL_COND_V( p_host == IP_Address(), ERR_INVALID_PARAMETER); - sockfd = _socket_create(p_host.type, SOCK_STREAM, IPPROTO_TCP); + sockfd = _socket_create(ip_type, SOCK_STREAM, IPPROTO_TCP); if (sockfd == INVALID_SOCKET) { ERR_PRINT("Socket creation failed!"); disconnect(); @@ -312,7 +318,7 @@ Error StreamPeerWinsock::connect(const IP_Address& p_host, uint16_t p_port) { }; struct sockaddr_storage their_addr; - size_t addr_size = _set_sockaddr(&their_addr, p_host, p_port); + size_t addr_size = _set_sockaddr(&their_addr, p_host, p_port, ip_type); if (::connect(sockfd, (struct sockaddr *)&their_addr,addr_size) == SOCKET_ERROR) { @@ -362,6 +368,7 @@ StreamPeerWinsock::StreamPeerWinsock() { sockfd = INVALID_SOCKET; status = STATUS_NONE; peer_port = 0; + ip_type = IP::TYPE_ANY; }; StreamPeerWinsock::~StreamPeerWinsock() { diff --git a/platform/windows/stream_peer_winsock.h b/platform/windows/stream_peer_winsock.h index 24afbbefd4..e17a7167e1 100644 --- a/platform/windows/stream_peer_winsock.h +++ b/platform/windows/stream_peer_winsock.h @@ -68,7 +68,7 @@ public: virtual int get_available_bytes() const; - void set_socket(int p_sockfd, IP_Address p_host, int p_port); + void set_socket(int p_sockfd, IP_Address p_host, int p_port, IP::Type p_ip_type); virtual IP_Address get_connected_host() const; virtual uint16_t get_connected_port() const; diff --git a/platform/windows/tcp_server_winsock.cpp b/platform/windows/tcp_server_winsock.cpp index e93e29525b..1c3682adfa 100644 --- a/platform/windows/tcp_server_winsock.cpp +++ b/platform/windows/tcp_server_winsock.cpp @@ -63,20 +63,12 @@ void TCPServerWinsock::cleanup() { }; -Error TCPServerWinsock::listen(uint16_t p_port, IP_Address::AddrType p_type,const List<String> *p_accepted_hosts) { +Error TCPServerWinsock::listen(uint16_t p_port,const List<String> *p_accepted_hosts) { int sockfd; - sockfd = _socket_create(p_type, SOCK_STREAM, IPPROTO_TCP); + sockfd = _socket_create(ip_type, SOCK_STREAM, IPPROTO_TCP); ERR_FAIL_COND_V(sockfd == INVALID_SOCKET, FAILED); - if(p_type == IP_Address::TYPE_IPV6) { - // Use IPv6 only socket - int yes = 1; - if(setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY, (const char*)&yes, sizeof(yes)) != 0) { - WARN_PRINT("Unable to unset IPv4 address mapping over IPv6"); - } - } - unsigned long par = 1; if (ioctlsocket(sockfd, FIONBIO, &par)) { perror("setting non-block mode"); @@ -85,7 +77,7 @@ Error TCPServerWinsock::listen(uint16_t p_port, IP_Address::AddrType p_type,cons }; struct sockaddr_storage my_addr; - size_t addr_size = _set_listen_sockaddr(&my_addr, p_port, p_type, p_accepted_hosts); + size_t addr_size = _set_listen_sockaddr(&my_addr, p_port, ip_type, p_accepted_hosts); int reuse=1; if(setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse)) < 0) { @@ -158,7 +150,7 @@ Ref<StreamPeerTCP> TCPServerWinsock::take_connection() { int port; _set_ip_addr_port(ip, port, &their_addr); - conn->set_socket(fd, ip, port); + conn->set_socket(fd, ip, port, ip_type); return conn; }; @@ -176,6 +168,7 @@ void TCPServerWinsock::stop() { TCPServerWinsock::TCPServerWinsock() { listen_sockfd = INVALID_SOCKET; + ip_type = IP::TYPE_ANY; }; TCPServerWinsock::~TCPServerWinsock() { diff --git a/platform/windows/tcp_server_winsock.h b/platform/windows/tcp_server_winsock.h index 04d196dce3..5c544436a7 100644 --- a/platform/windows/tcp_server_winsock.h +++ b/platform/windows/tcp_server_winsock.h @@ -39,7 +39,7 @@ class TCPServerWinsock : public TCP_Server { public: - virtual Error listen(uint16_t p_port, IP_Address::AddrType p_type,const List<String> *p_accepted_hosts=NULL); + virtual Error listen(uint16_t p_port,const List<String> *p_accepted_hosts=NULL); virtual bool is_connection_available() const; virtual Ref<StreamPeerTCP> take_connection(); diff --git a/scene/2d/canvas_item.cpp b/scene/2d/canvas_item.cpp index 6ee3a8de3e..5d0d611917 100644 --- a/scene/2d/canvas_item.cpp +++ b/scene/2d/canvas_item.cpp @@ -261,16 +261,13 @@ void CanvasItem::show() { if (!hidden) return; - hidden=false; VisualServer::get_singleton()->canvas_item_set_visible(canvas_item,true); if (!is_inside_tree()) return; - if (is_visible()) { - _propagate_visibility_changed(true); - } + _propagate_visibility_changed(true); _change_notify("visibility/visible"); } @@ -280,15 +277,13 @@ void CanvasItem::hide() { if (hidden) return; - bool propagate=is_inside_tree() && is_visible(); hidden=true; VisualServer::get_singleton()->canvas_item_set_visible(canvas_item,false); if (!is_inside_tree()) return; - if (propagate) - _propagate_visibility_changed(false); + _propagate_visibility_changed(false); _change_notify("visibility/visible"); } diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp index fd3d409f29..ed16212f3e 100644 --- a/scene/2d/tile_map.cpp +++ b/scene/2d/tile_map.cpp @@ -268,10 +268,10 @@ void TileMap::_update_dirty_quadrants() { if (!pending_update) return; - if (!is_inside_tree()) - return; - if (!tile_set.is_valid()) + if (!is_inside_tree() || !tile_set.is_valid()) { + pending_update = false; return; + } VisualServer *vs = VisualServer::get_singleton(); Physics2DServer *ps = Physics2DServer::get_singleton(); diff --git a/scene/3d/bone_attachment.cpp b/scene/3d/bone_attachment.cpp index 9840b78c56..fb961c1fec 100644 --- a/scene/3d/bone_attachment.cpp +++ b/scene/3d/bone_attachment.cpp @@ -137,3 +137,8 @@ BoneAttachment::BoneAttachment() bound=false; } + +void BoneAttachment::_bind_methods(){ + ObjectTypeDB::bind_method(_MD("set_bone_name","bone_name"),&BoneAttachment::set_bone_name); + ObjectTypeDB::bind_method(_MD("get_bone_name"),&BoneAttachment::get_bone_name); +} diff --git a/scene/3d/bone_attachment.h b/scene/3d/bone_attachment.h index 8f6894ccc0..26514acdf9 100644 --- a/scene/3d/bone_attachment.h +++ b/scene/3d/bone_attachment.h @@ -47,6 +47,8 @@ protected: void _get_property_list( List<PropertyInfo>* p_list ) const; void _notification(int p_what); + static void _bind_methods(); + public: void set_bone_name(const String& p_name); diff --git a/scene/3d/navigation_mesh.cpp b/scene/3d/navigation_mesh.cpp index bb901d701e..25f675ac0c 100644 --- a/scene/3d/navigation_mesh.cpp +++ b/scene/3d/navigation_mesh.cpp @@ -356,6 +356,11 @@ void NavigationMeshInstance::set_navigation_mesh(const Ref<NavigationMesh>& p_na if (navigation && navmesh.is_valid() && enabled) { nav_id = navigation->navmesh_create(navmesh,get_relative_transform(navigation),this); } + + if (debug_view && navmesh.is_valid()) { + debug_view->cast_to<MeshInstance>()->set_mesh( navmesh->get_debug_mesh() ); + } + update_gizmo(); update_configuration_warning(); diff --git a/scene/gui/color_picker.cpp b/scene/gui/color_picker.cpp index 4f195c7488..a65c85d24c 100644 --- a/scene/gui/color_picker.cpp +++ b/scene/gui/color_picker.cpp @@ -162,7 +162,7 @@ void ColorPicker::_html_entered(const String& p_html) { if (!is_inside_tree()) return; - _update_color(); + set_color(color); emit_signal("color_changed",color); } diff --git a/scene/gui/scroll_container.cpp b/scene/gui/scroll_container.cpp index 388dc3e4e4..bad478a745 100644 --- a/scene/gui/scroll_container.cpp +++ b/scene/gui/scroll_container.cpp @@ -88,14 +88,22 @@ void ScrollContainer::_input_event(const InputEvent& p_input_event) { const InputEventMouseButton &mb=p_input_event.mouse_button; - if (mb.button_index==BUTTON_WHEEL_UP && mb.pressed && v_scroll->is_visible()) { - - v_scroll->set_val( v_scroll->get_val()-v_scroll->get_page()/8 ); + if (mb.button_index==BUTTON_WHEEL_UP && mb.pressed) { + if (h_scroll->is_visible() && !v_scroll->is_visible()){ + // only horizontal is enabled, scroll horizontally + h_scroll->set_val( h_scroll->get_val()-h_scroll->get_page()/8 ); + } else if (v_scroll->is_visible()) { + v_scroll->set_val( v_scroll->get_val()-v_scroll->get_page()/8 ); + } } - if (mb.button_index==BUTTON_WHEEL_DOWN && mb.pressed && v_scroll->is_visible()) { - - v_scroll->set_val( v_scroll->get_val()+v_scroll->get_page()/8 ); + if (mb.button_index==BUTTON_WHEEL_DOWN && mb.pressed) { + if (h_scroll->is_visible() && !v_scroll->is_visible()){ + // only horizontal is enabled, scroll horizontally + h_scroll->set_val( h_scroll->get_val()+h_scroll->get_page()/8 ); + } else if (v_scroll->is_visible()) { + v_scroll->set_val( v_scroll->get_val()+v_scroll->get_page()/8 ); + } } if(!OS::get_singleton()->has_touchscreen_ui_hint()) diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp index 5eb65d816c..c6727d132e 100644 --- a/scene/gui/tree.cpp +++ b/scene/gui/tree.cpp @@ -569,6 +569,15 @@ void TreeItem::set_button(int p_column,int p_idx,const Ref<Texture>& p_button){ } +void TreeItem::set_button_color(int p_column,int p_idx,const Color& p_color) { + + ERR_FAIL_INDEX( p_column, cells.size() ); + ERR_FAIL_INDEX( p_idx, cells[p_column].buttons.size() ); + cells[p_column].buttons[p_idx].color=p_color; + _changed_notify(p_column); + +} + void TreeItem::set_editable(int p_column,bool p_editable) { ERR_FAIL_INDEX( p_column, cells.size() ); @@ -1061,7 +1070,7 @@ int Tree::draw_item(const Point2i& p_pos,const Point2& p_draw_ofs, const Size2& o.y+=(label_h-s.height)/2; o+=cache.button_pressed->get_offset(); - b->draw(ci,o,p_item->cells[i].buttons[j].disabled?Color(1,1,1,0.5):Color(1,1,1,1)); + b->draw(ci,o,p_item->cells[i].buttons[j].disabled?Color(1,1,1,0.5):p_item->cells[i].buttons[j].color); w-=s.width+cache.button_margin; bw+=s.width+cache.button_margin; } @@ -1396,11 +1405,7 @@ void Tree::select_single_item(TreeItem *p_selected, TreeItem *p_current, int p_c if (select_mode==SELECT_ROW) { - - if (p_selected==p_current) { - - if (!c.selected) { - + if (p_selected==p_current && !c.selected) { c.selected=true; selected_item=p_selected; selected_col=0; @@ -1410,24 +1415,17 @@ void Tree::select_single_item(TreeItem *p_selected, TreeItem *p_current, int p_c emitted_row=true; } //if (p_col==i) - // p_current->selected_signal.call(p_col); - } + // p_current->selected_signal.call(p_col); - } else { - - if (c.selected) { + } else if (c.selected) { c.selected=false; //p_current->deselected_signal.call(p_col); - } - } - } else if (select_mode==SELECT_SINGLE || select_mode==SELECT_MULTI) { if (!r_in_range && &selected_cell==&c) { - if (!selected_cell.selected) { selected_cell.selected=true; @@ -1438,6 +1436,8 @@ void Tree::select_single_item(TreeItem *p_selected, TreeItem *p_current, int p_c emit_signal("cell_selected"); if (select_mode==SELECT_MULTI) emit_signal("multi_selected",p_current,i,true); + else if(select_mode == SELECT_SINGLE) + emit_signal("item_selected"); } else if (select_mode==SELECT_MULTI && (selected_item!=p_selected || selected_col!=i)) { @@ -2405,6 +2405,9 @@ void Tree::_input_event(InputEvent p_event) { } + if (range_drag_enabled) + break; + switch(b.button_index) { case BUTTON_RIGHT: case BUTTON_LEFT: { @@ -2923,8 +2926,7 @@ void Tree::item_selected(int p_column,TreeItem *p_item) { void Tree::item_deselected(int p_column,TreeItem *p_item) { - if (select_mode==SELECT_MULTI) { - + if (select_mode==SELECT_MULTI || select_mode == SELECT_SINGLE) { p_item->cells[p_column].selected=false; } update(); diff --git a/scene/gui/tree.h b/scene/gui/tree.h index 84c610db36..19b48f2000 100644 --- a/scene/gui/tree.h +++ b/scene/gui/tree.h @@ -93,7 +93,8 @@ friend class Tree; int id; bool disabled; Ref<Texture> texture; - Button() { id=0; disabled=false; } + Color color; + Button() { id=0; disabled=false; color=Color(1,1,1,1); } }; Vector< Button > buttons; @@ -189,6 +190,7 @@ public: int get_button_by_id(int p_column,int p_id) const; bool is_button_disabled(int p_column,int p_idx) const; void set_button(int p_column,int p_idx,const Ref<Texture>& p_button); + void set_button_color(int p_column,int p_idx,const Color& p_color); /* range works for mode number or mode combo */ diff --git a/scene/main/http_request.cpp b/scene/main/http_request.cpp index 956f6e0422..4203edda77 100644 --- a/scene/main/http_request.cpp +++ b/scene/main/http_request.cpp @@ -28,6 +28,10 @@ /*************************************************************************/ #include "http_request.h" +void HTTPRequest::set_ip_type(IP::Type p_type) { + client->set_ip_type(p_type); +} + void HTTPRequest::_redirect_request(const String& p_new_url) { @@ -535,6 +539,7 @@ int HTTPRequest::get_body_size() const{ void HTTPRequest::_bind_methods() { + ObjectTypeDB::bind_method(_MD("set_ip_type","ip_type"),&HTTPRequest::set_ip_type); ObjectTypeDB::bind_method(_MD("request","url","custom_headers","ssl_validate_domain","method","request_data"),&HTTPRequest::request,DEFVAL(StringArray()),DEFVAL(true),DEFVAL(HTTPClient::METHOD_GET),DEFVAL(String())); ObjectTypeDB::bind_method(_MD("cancel_request"),&HTTPRequest::cancel_request); diff --git a/scene/main/http_request.h b/scene/main/http_request.h index 89d790d53b..5bf47111e8 100644 --- a/scene/main/http_request.h +++ b/scene/main/http_request.h @@ -116,6 +116,7 @@ protected: static void _bind_methods(); public: + void set_ip_type(IP::Type p_type); Error request(const String& p_url, const Vector<String>& p_custom_headers=Vector<String>(), bool p_ssl_validate_domain=true, HTTPClient::Method p_method=HTTPClient::METHOD_GET, const String& p_request_data=""); //connects to a full url and perform request void cancel_request(); HTTPClient::Status get_http_client_status() const; diff --git a/tools/editor/editor_node.cpp b/tools/editor/editor_node.cpp index 5d04e4f5da..98aa5acd43 100644 --- a/tools/editor/editor_node.cpp +++ b/tools/editor/editor_node.cpp @@ -1922,6 +1922,9 @@ void EditorNode::_run(bool p_current,const String& p_custom) { log->clear(); } + if (bool(EDITOR_DEF("run/always_open_output_on_play", true))) { + make_bottom_panel_item_visible(log); + } List<String> breakpoints; editor_data.get_editor_breakpoints(&breakpoints); diff --git a/tools/editor/editor_plugin.cpp b/tools/editor/editor_plugin.cpp index 3e0eb8be31..106e91348e 100644 --- a/tools/editor/editor_plugin.cpp +++ b/tools/editor/editor_plugin.cpp @@ -76,6 +76,11 @@ Control * EditorPlugin::get_editor_viewport() { return EditorNode::get_singleton()->get_viewport(); } +void EditorPlugin::edit_resource(const Ref<Resource>& p_resource){ + + EditorNode::get_singleton()->edit_resource(p_resource); +} + void EditorPlugin::add_control_to_container(CustomControlContainer p_location,Control *p_control) { switch(p_location) { @@ -370,6 +375,7 @@ void EditorPlugin::_bind_methods() { ObjectTypeDB::bind_method(_MD("get_selection:EditorSelection"),&EditorPlugin::get_selection); ObjectTypeDB::bind_method(_MD("get_editor_settings:EditorSettings"),&EditorPlugin::get_editor_settings); ObjectTypeDB::bind_method(_MD("queue_save_layout"),&EditorPlugin::queue_save_layout); + ObjectTypeDB::bind_method(_MD("edit_resource"),&EditorPlugin::edit_resource); ObjectTypeDB::add_virtual_method(get_type_static(),MethodInfo(Variant::BOOL,"forward_canvas_input_event",PropertyInfo(Variant::MATRIX32,"canvas_xform"),PropertyInfo(Variant::INPUT_EVENT,"event"))); ObjectTypeDB::add_virtual_method(get_type_static(),MethodInfo("forward_draw_over_canvas",PropertyInfo(Variant::MATRIX32,"canvas_xform"),PropertyInfo(Variant::OBJECT,"canvas:Control"))); diff --git a/tools/editor/editor_plugin.h b/tools/editor/editor_plugin.h index 2026b83cc0..9e7449f7fa 100644 --- a/tools/editor/editor_plugin.h +++ b/tools/editor/editor_plugin.h @@ -101,6 +101,7 @@ public: void remove_control_from_docks(Control *p_control); void remove_control_from_bottom_panel(Control *p_control); Control* get_editor_viewport(); + void edit_resource(const Ref<Resource>& p_resource); virtual Ref<SpatialEditorGizmo> create_spatial_gizmo(Spatial* p_spatial); virtual bool forward_canvas_input_event(const Matrix32& p_canvas_xform, const InputEvent& p_event); diff --git a/tools/editor/plugins/tile_map_editor_plugin.cpp b/tools/editor/plugins/tile_map_editor_plugin.cpp index 7c610770b0..5d4e3fd874 100644 --- a/tools/editor/plugins/tile_map_editor_plugin.cpp +++ b/tools/editor/plugins/tile_map_editor_plugin.cpp @@ -289,7 +289,7 @@ void TileMapEditor::_pick_tile(const Point2& p_pos) { canvas_item_editor->update(); } -DVector<Vector2> TileMapEditor::_bucket_fill(const Point2i& p_start, bool erase) { +DVector<Vector2> TileMapEditor::_bucket_fill(const Point2i& p_start, bool erase, bool preview) { int prev_id = node->get_cell(p_start.x, p_start.y); int id = TileMap::INVALID_CELL; @@ -300,10 +300,39 @@ DVector<Vector2> TileMapEditor::_bucket_fill(const Point2i& p_start, bool erase) return DVector<Vector2>(); } - Rect2 r = node->get_item_rect(); + Rect2i r = node->get_item_rect(); r.pos = r.pos/node->get_cell_size(); r.size = r.size/node->get_cell_size(); + int area = r.get_area(); + if(preview) { + // Test if we can re-use the result from preview bucket fill + bool invalidate_cache = false; + // Area changed + if(r != bucket_cache_rect) + _clear_bucket_cache(); + // Cache grid is not initialized + if(bucket_cache_visited == 0) { + bucket_cache_visited = new bool[area]; + invalidate_cache = true; + } + // Tile ID changed or position wasn't visited by the previous fill + int loc = (p_start.x - r.get_pos().x) + (p_start.y - r.get_pos().y) * r.get_size().x; + if(prev_id != bucket_cache_tile || !bucket_cache_visited[loc]) { + invalidate_cache = true; + } + if(invalidate_cache) { + for(int i = 0; i < area; ++i) + bucket_cache_visited[i] = false; + bucket_cache = DVector<Vector2>(); + bucket_cache_tile = prev_id; + bucket_cache_rect = r; + } + else { + return bucket_cache; + } + } + DVector<Vector2> points; List<Point2i> queue; @@ -319,9 +348,17 @@ DVector<Vector2> TileMapEditor::_bucket_fill(const Point2i& p_start, bool erase) if (node->get_cell(n.x, n.y) == prev_id) { - node->set_cellv(n, id, flip_h, flip_v, transpose); - - points.push_back(n); + if(preview) { + int loc = (n.x - r.get_pos().x) + (n.y - r.get_pos().y) * r.get_size().x; + if(bucket_cache_visited[loc]) + continue; + bucket_cache_visited[loc] = true; + bucket_cache.push_back(n); + } + else { + node->set_cellv(n, id, flip_h, flip_v, transpose); + points.push_back(n); + } queue.push_back(n + Point2i(0, 1)); queue.push_back(n + Point2i(0, -1)); @@ -330,7 +367,7 @@ DVector<Vector2> TileMapEditor::_bucket_fill(const Point2i& p_start, bool erase) } } - return points; + return preview ? bucket_cache : points; } void TileMapEditor::_fill_points(const DVector<Vector2> p_points, const Dictionary& p_op) { @@ -468,6 +505,25 @@ void TileMapEditor::_draw_cell(int p_cell, const Point2i& p_point, bool p_flip_h canvas_item_editor->draw_texture_rect_region(t, rect, r, Color(1,1,1,0.5), p_transpose); } +void TileMapEditor::_draw_fill_preview(int p_cell, const Point2i& p_point, bool p_flip_h, bool p_flip_v, bool p_transpose, const Matrix32& p_xform) { + + DVector<Vector2> points = _bucket_fill(p_point, false, true); + DVector<Vector2>::Read pr = points.read(); + int len = points.size(); + int time_after = OS::get_singleton()->get_ticks_msec(); + + for(int i = 0; i < len; ++i) { + _draw_cell(p_cell, pr[i], p_flip_h, p_flip_v, p_transpose, p_xform); + } +} + +void TileMapEditor::_clear_bucket_cache() { + if(bucket_cache_visited) { + delete[] bucket_cache_visited; + bucket_cache_visited = 0; + } +} + void TileMapEditor::_update_copydata() { copydata.clear(); @@ -1148,8 +1204,8 @@ void TileMapEditor::_canvas_draw() { canvas_item_editor->draw_line(endpoints[i],endpoints[(i+1)%4],col,2); - if (tool==TOOL_SELECTING || tool==TOOL_PICKING || tool==TOOL_BUCKET) { - + bool bucket_preview = EditorSettings::get_singleton()->get("tile_map/bucket_fill_preview"); + if (tool==TOOL_SELECTING || tool==TOOL_PICKING || !bucket_preview) { return; } @@ -1214,6 +1270,11 @@ void TileMapEditor::_canvas_draw() { canvas_item_editor->draw_colored_polygon(points, Color(0.2,1.0,0.8,0.2)); + } else if(tool == TOOL_BUCKET) { + + int tile = get_selected_tile(); + _draw_fill_preview(tile, over_tile, flip_h, flip_v, transpose, xform); + } else { int st = get_selected_tile(); @@ -1264,6 +1325,8 @@ void TileMapEditor::edit(Node *p_tile_map) { if (node) node->connect("settings_changed",this,"_tileset_settings_changed"); + _clear_bucket_cache(); + } void TileMapEditor::_tileset_settings_changed() { @@ -1365,6 +1428,9 @@ TileMapEditor::TileMapEditor(EditorNode *p_editor) { flip_v=false; transpose=false; + bucket_cache_tile = -1; + bucket_cache_visited = 0; + ED_SHORTCUT("tile_map_editor/erase_selection", TTR("Erase selection"), KEY_DELETE); ED_SHORTCUT("tile_map_editor/find_tile", TTR("Find tile"), KEY_MASK_CMD+KEY_F); ED_SHORTCUT("tile_map_editor/transpose", TTR("Transpose")); @@ -1479,6 +1545,10 @@ TileMapEditor::TileMapEditor(EditorNode *p_editor) { rotate_0->set_pressed(true); } +TileMapEditor::~TileMapEditor() { + _clear_bucket_cache(); +} + /////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////// @@ -1512,6 +1582,7 @@ TileMapEditorPlugin::TileMapEditorPlugin(EditorNode *p_node) { EDITOR_DEF("tile_map/preview_size",64); EDITOR_DEF("tile_map/palette_item_hseparation",8); EDITOR_DEF("tile_map/show_tile_names", true); + EDITOR_DEF("tile_map/bucket_fill_preview", true); tile_map_editor = memnew( TileMapEditor(p_node) ); add_control_to_container(CONTAINER_CANVAS_EDITOR_SIDE, tile_map_editor); diff --git a/tools/editor/plugins/tile_map_editor_plugin.h b/tools/editor/plugins/tile_map_editor_plugin.h index a5815e8f2e..44b83fe745 100644 --- a/tools/editor/plugins/tile_map_editor_plugin.h +++ b/tools/editor/plugins/tile_map_editor_plugin.h @@ -106,6 +106,11 @@ class TileMapEditor : public VBoxContainer { Point2i over_tile; + bool * bucket_cache_visited; + Rect2i bucket_cache_rect; + int bucket_cache_tile; + DVector<Vector2> bucket_cache; + struct CellOp { int idx; bool xf; @@ -129,7 +134,7 @@ class TileMapEditor : public VBoxContainer { void _pick_tile(const Point2& p_pos); - DVector<Vector2> _bucket_fill(const Point2i& p_start, bool erase=false); + DVector<Vector2> _bucket_fill(const Point2i& p_start, bool erase=false, bool preview=false); void _fill_points(const DVector<Vector2> p_points, const Dictionary& p_op); void _erase_points(const DVector<Vector2> p_points); @@ -137,6 +142,9 @@ class TileMapEditor : public VBoxContainer { void _select(const Point2i& p_from, const Point2i& p_to); void _draw_cell(int p_cell, const Point2i& p_point, bool p_flip_h, bool p_flip_v, bool p_transpose, const Matrix32& p_xform); + void _draw_fill_preview(int p_cell, const Point2i& p_point, bool p_flip_h, bool p_flip_v, bool p_transpose, const Matrix32& p_xform); + void _clear_bucket_cache(); + void _update_copydata(); int get_selected_tile() const; @@ -171,6 +179,7 @@ public: void edit(Node *p_tile_map); TileMapEditor(EditorNode *p_editor); + ~TileMapEditor(); }; class TileMapEditorPlugin : public EditorPlugin { diff --git a/tools/editor/scene_tree_editor.cpp b/tools/editor/scene_tree_editor.cpp index dd0d5ac342..aa74f47e8d 100644 --- a/tools/editor/scene_tree_editor.cpp +++ b/tools/editor/scene_tree_editor.cpp @@ -208,13 +208,6 @@ void SceneTreeEditor::_cell_button_pressed(Object *p_item,int p_column,int p_id) if (n->is_type("Spatial")) { - Spatial *ci = n->cast_to<Spatial>(); - if (!ci->is_visible() && ci->get_parent_spatial() && !ci->get_parent_spatial()->is_visible()) { - error->set_text(TTR("This item cannot be made visible because the parent is hidden. Unhide the parent first.")); - error->popup_centered_minsize(); - return; - } - bool v = !bool(n->call("is_hidden")); undo_redo->create_action(TTR("Toggle Spatial Visible")); undo_redo->add_do_method(n,"_set_visible_",!v); @@ -222,12 +215,6 @@ void SceneTreeEditor::_cell_button_pressed(Object *p_item,int p_column,int p_id) undo_redo->commit_action(); } else if (n->is_type("CanvasItem")) { - CanvasItem *ci = n->cast_to<CanvasItem>(); - if (!ci->is_visible() && ci->get_parent_item() && !ci->get_parent_item()->is_visible()) { - error->set_text(TTR("This item cannot be made visible because the parent is hidden. Unhide the parent first.")); - error->popup_centered_minsize(); - return; - } bool v = !bool(n->call("is_hidden")); undo_redo->create_action(TTR("Toggle CanvasItem Visible")); undo_redo->add_do_method(n,v?"hide":"show"); @@ -415,6 +402,7 @@ bool SceneTreeEditor::_add_nodes(Node *p_node,TreeItem *p_parent) { if (!p_node->is_connected("visibility_changed",this,"_node_visibility_changed")) p_node->connect("visibility_changed",this,"_node_visibility_changed",varray(p_node)); + _update_visibility_color(p_node, item); } else if (p_node->is_type("Spatial")) { bool h = p_node->call("is_hidden"); @@ -426,6 +414,7 @@ bool SceneTreeEditor::_add_nodes(Node *p_node,TreeItem *p_parent) { if (!p_node->is_connected("visibility_changed",this,"_node_visibility_changed")) p_node->connect("visibility_changed",this,"_node_visibility_changed",varray(p_node)); + _update_visibility_color(p_node, item); } } @@ -491,9 +480,20 @@ void SceneTreeEditor::_node_visibility_changed(Node *p_node) { else item->set_button(0,idx,get_icon("Visible","EditorIcons")); - + _update_visibility_color(p_node, item); } +void SceneTreeEditor::_update_visibility_color(Node *p_node, TreeItem *p_item) { + if (p_node->is_type("CanvasItem") || p_node->is_type("Spatial")) { + Color color(1,1,1,1); + bool visible_on_screen = p_node->call("is_visible"); + if (!visible_on_screen) { + color = Color(0.6,0.6,0.6,1); + } + int idx=p_item->get_button_by_id(0,BUTTON_VISIBILITY); + p_item->set_button_color(0,idx,color); + } +} void SceneTreeEditor::_node_script_changed(Node *p_node) { diff --git a/tools/editor/scene_tree_editor.h b/tools/editor/scene_tree_editor.h index bdc3f8b17b..3e0e2f1677 100644 --- a/tools/editor/scene_tree_editor.h +++ b/tools/editor/scene_tree_editor.h @@ -117,6 +117,7 @@ class SceneTreeEditor : public Control { void _update_selection(TreeItem *item); void _node_script_changed(Node *p_node); void _node_visibility_changed(Node *p_node); + void _update_visibility_color(Node *p_node, TreeItem *p_item); void _subscene_option(int p_idx); void _node_replace_owner(Node* p_base,Node* p_node,Node* p_root); diff --git a/tools/editor/script_editor_debugger.cpp b/tools/editor/script_editor_debugger.cpp index 5f8ed10b54..88cb357148 100644 --- a/tools/editor/script_editor_debugger.cpp +++ b/tools/editor/script_editor_debugger.cpp @@ -581,7 +581,6 @@ void ScriptEditorDebugger::_parse_message(const String& p_msg,const Array& p_dat //LOG if (EditorNode::get_log()->is_hidden()) { - log_forced_visible=true; if (EditorNode::get_singleton()->are_bottom_panels_hidden()) { EditorNode::get_singleton()->make_bottom_panel_item_visible(EditorNode::get_log()); } @@ -957,7 +956,6 @@ void ScriptEditorDebugger::_notification(int p_what) { break; EditorNode::get_log()->add_message("** Debug Process Started **"); - log_forced_visible=false; ppeer->set_stream_peer(connection); @@ -1089,8 +1087,8 @@ void ScriptEditorDebugger::start() { stop(); - if (!EditorNode::get_log()->is_visible()) { - EditorNode::get_singleton()->make_bottom_panel_item_visible(EditorNode::get_log()); + if (is_visible()) { + EditorNode::get_singleton()->make_bottom_panel_item_visible(this); } uint16_t port = GLOBAL_DEF("debug/remote_port",6007); @@ -1132,13 +1130,6 @@ void ScriptEditorDebugger::stop(){ pending_in_queue=0; message.clear(); - if (log_forced_visible) { - //EditorNode::get_singleton()->make_bottom_panel_item_visible(this); - if (EditorNode::get_log()->is_visible()) - EditorNode::get_singleton()->hide_bottom_panel(); - log_forced_visible=false; - } - node_path_cache.clear(); res_path_cache.clear(); profiler_signature.clear(); @@ -1980,8 +1971,6 @@ ScriptEditorDebugger::ScriptEditorDebugger(EditorNode *p_editor){ msgdialog = memnew( AcceptDialog ); add_child(msgdialog); - log_forced_visible=false; - p_editor->get_undo_redo()->set_method_notify_callback(_method_changeds,this); p_editor->get_undo_redo()->set_property_notify_callback(_property_changeds,this); live_debug=false; diff --git a/tools/editor/script_editor_debugger.h b/tools/editor/script_editor_debugger.h index c64c2f6688..985edd8df3 100644 --- a/tools/editor/script_editor_debugger.h +++ b/tools/editor/script_editor_debugger.h @@ -96,7 +96,6 @@ class ScriptEditorDebugger : public Control { TabContainer *tabs; LineEdit *reason; - bool log_forced_visible; ScriptEditorDebuggerVariables *variables; Button *step; |