-Made editor support SSL certs by default (embedded them)

-Made asset sharing support https
-Many fixes to HTTPRequest
-Added an asset installer dialog
-Visual cleanups to asset sharing tab
-Fixed some issues in ScrollContainer, hope it does not break things
-Asset sharing tab is not visible (hidden on purpose) for now.
This commit is contained in:
Juan Linietsky 2016-03-12 10:44:12 -03:00
parent d85f06c42d
commit 8b1dcbfe4d
32 changed files with 6011 additions and 142 deletions

1
.gitignore vendored
View file

@ -18,6 +18,7 @@ core/global_defaults.cpp
drivers/unix/os_unix_global_settings_path.cpp
tools/editor/register_exporters.cpp
tools/editor/doc_data_compressed.h
tools/editor/certs_compressed.h
tools/editor/editor_icons.cpp
-fpic
.fscache

View file

@ -2214,6 +2214,8 @@ void Image::blit_rect(const Image& p_src, const Rect2& p_src_rect,const Point2&
Image (*Image::_png_mem_loader_func)(const uint8_t*,int)=NULL;
Image (*Image::_jpg_mem_loader_func)(const uint8_t*,int)=NULL;
void (*Image::_image_compress_bc_func)(Image *)=NULL;
void (*Image::_image_compress_pvrtc2_func)(Image *)=NULL;
void (*Image::_image_compress_pvrtc4_func)(Image *)=NULL;
@ -2388,7 +2390,7 @@ String Image::get_format_name(Format p_format) {
return format_names[p_format];
}
Image::Image(const uint8_t* p_png,int p_len) {
Image::Image(const uint8_t* p_mem_png_jpg, int p_len) {
width=0;
height=0;
@ -2396,8 +2398,13 @@ Image::Image(const uint8_t* p_png,int p_len) {
format=FORMAT_GRAYSCALE;
if (_png_mem_loader_func) {
*this = _png_mem_loader_func(p_png,p_len);
*this = _png_mem_loader_func(p_mem_png_jpg,p_len);
}
if (empty() && _jpg_mem_loader_func) {
*this = _jpg_mem_loader_func(p_mem_png_jpg,p_len);
}
}
Image::Image() {

View file

@ -97,6 +97,7 @@ public:
};
static Image (*_png_mem_loader_func)(const uint8_t* p_png,int p_size);
static Image (*_jpg_mem_loader_func)(const uint8_t* p_png,int p_size);
static void (*_image_compress_bc_func)(Image *);
static void (*_image_compress_pvrtc2_func)(Image *);
static void (*_image_compress_pvrtc4_func)(Image *);
@ -355,7 +356,7 @@ public:
static void set_compress_bc_func(void (*p_compress_func)(Image *));
static String get_format_name(Format p_format);
Image(const uint8_t* p_mem_png, int p_len=-1);
Image(const uint8_t* p_mem_png_jpg, int p_len=-1);
Image(const char **p_xpm);
~Image();

View file

@ -4,12 +4,28 @@
StreamPeerSSL* (*StreamPeerSSL::_create)()=NULL;
StreamPeerSSL *StreamPeerSSL::create() {
return _create();
}
StreamPeerSSL::LoadCertsFromMemory StreamPeerSSL::load_certs_func=NULL;
bool StreamPeerSSL::available=false;
bool StreamPeerSSL::initialize_certs=true;
void StreamPeerSSL::load_certs_from_memory(const ByteArray& p_memory) {
if (load_certs_func)
load_certs_func(p_memory);
}
bool StreamPeerSSL::is_available() {
return available;
}
void StreamPeerSSL::_bind_methods() {

View file

@ -5,11 +5,23 @@
class StreamPeerSSL : public StreamPeer {
OBJ_TYPE(StreamPeerSSL,StreamPeer);
public:
typedef void (*LoadCertsFromMemory)(const ByteArray& p_certs);
protected:
static StreamPeerSSL* (*_create)();
static void _bind_methods();
static LoadCertsFromMemory load_certs_func;
static bool available;
friend class Main;
static bool initialize_certs;
public:
enum Status {
STATUS_DISCONNECTED,
STATUS_CONNECTED,
@ -25,6 +37,8 @@ public:
static StreamPeerSSL* create();
static void load_certs_from_memory(const ByteArray& p_memory);
static bool is_available();
StreamPeerSSL();
};

View file

@ -17,23 +17,9 @@
#include <string.h>
Error ImageLoaderJPG::load_image(Image *p_image,FileAccess *f) {
Error jpeg_load_image_from_buffer(Image *p_image,const uint8_t* p_buffer, int p_buffer_len) {
DVector<uint8_t> src_image;
int src_image_len = f->get_len();
ERR_FAIL_COND_V(src_image_len == 0, ERR_FILE_CORRUPT);
src_image.resize(src_image_len);
DVector<uint8_t>::Write w = src_image.write();
f->get_buffer(&w[0],src_image_len);
f->close();
jpgd::jpeg_decoder_mem_stream mem_stream(w.ptr(),src_image_len);
jpgd::jpeg_decoder_mem_stream mem_stream(p_buffer,p_buffer_len);
jpgd::jpeg_decoder decoder(&mem_stream);
@ -85,14 +71,36 @@ Error ImageLoaderJPG::load_image(Image *p_image,FileAccess *f) {
fmt=Image::FORMAT_RGBA;
dw = DVector<uint8_t>::Write();
w = DVector<uint8_t>::Write();
p_image->create(image_width,image_height,0,fmt,data);
return OK;
}
Error ImageLoaderJPG::load_image(Image *p_image,FileAccess *f) {
DVector<uint8_t> src_image;
int src_image_len = f->get_len();
ERR_FAIL_COND_V(src_image_len == 0, ERR_FILE_CORRUPT);
src_image.resize(src_image_len);
DVector<uint8_t>::Write w = src_image.write();
f->get_buffer(&w[0],src_image_len);
f->close();
Error err = jpeg_load_image_from_buffer(p_image,w.ptr(),src_image_len);
w = DVector<uint8_t>::Write();
return err;
}
void ImageLoaderJPG::get_recognized_extensions(List<String> *p_extensions) const {
p_extensions->push_back("jpg");
@ -100,9 +108,17 @@ void ImageLoaderJPG::get_recognized_extensions(List<String> *p_extensions) const
}
static Image _jpegd_mem_loader_func(const uint8_t* p_png,int p_size) {
Image img;
Error err = jpeg_load_image_from_buffer(&img,p_png,p_size);
return img;
}
ImageLoaderJPG::ImageLoaderJPG() {
Image::_jpg_mem_loader_func=_jpegd_mem_loader_func;
}

View file

@ -532,8 +532,26 @@ StreamPeerSSL* StreamPeerOpenSSL::_create_func() {
Vector<X509*> StreamPeerOpenSSL::certs;
void StreamPeerOpenSSL::_load_certs(const ByteArray& p_array) {
ByteArray::Read r = p_array.read();
BIO* mem = BIO_new(BIO_s_mem());
BIO_puts(mem,(const char*)r.ptr());
while(true) {
X509*cert = PEM_read_bio_X509(mem, NULL, 0, NULL);
if (!cert)
break;
certs.push_back(cert);
}
BIO_free(mem);
}
void StreamPeerOpenSSL::initialize_ssl() {
available=true;
load_certs_func=_load_certs;
_create=_create_func;
CRYPTO_malloc_init(); // Initialize malloc, free, etc for OpenSSL's use
SSL_library_init(); // Initialize OpenSSL's SSL libraries
@ -544,20 +562,24 @@ void StreamPeerOpenSSL::initialize_ssl() {
Globals::get_singleton()->set_custom_property_info("ssl/certificates",PropertyInfo(Variant::STRING,"ssl/certificates",PROPERTY_HINT_FILE,"*.crt"));
if (certs_path!="") {
Vector<uint8_t> data = FileAccess::get_file_as_array(certs_path);;
if (data.size()) {
data.push_back(0);
BIO* mem = BIO_new(BIO_s_mem());
BIO_puts(mem,(const char*) data.ptr());
while(true) {
X509*cert = PEM_read_bio_X509(mem, NULL, 0, NULL);
if (!cert)
break;
certs.push_back(cert);
FileAccess *f=FileAccess::open(certs_path,FileAccess::READ);
if (f) {
ByteArray arr;
int flen = f->get_len();
arr.resize(flen+1);
{
ByteArray::Write w = arr.write();
f->get_buffer(w.ptr(),flen);
w[flen]=0; //end f string
}
BIO_free(mem);
memdelete(f);
_load_certs(arr);
print_line("Loaded certs from '"+certs_path+"': "+itos(certs.size()));
}
print_line("Loaded certs from '"+certs_path+"': "+itos(certs.size()));
}
String config_path =GLOBAL_DEF("ssl/config","");
Globals::get_singleton()->set_custom_property_info("ssl/config",PropertyInfo(Variant::STRING,"ssl/config",PROPERTY_HINT_FILE,"*.cnf"));

View file

@ -54,6 +54,7 @@ private:
static Vector<X509*> certs;
static void _load_certs(const ByteArray& p_array);
protected:
static void _bind_methods();
public:

View file

@ -73,6 +73,7 @@
#include "core/os/thread.h"
#include "core/io/file_access_pack.h"
#include "core/io/file_access_zip.h"
#include "core/io/stream_peer_ssl.h"
#include "translation.h"
#include "version.h"
#include "main/input_default.h"
@ -635,6 +636,7 @@ Error Main::setup(const char *execpath,int argc, char *argv[],bool p_second_phas
if (editor) {
packed_data->set_disabled(true);
globals->set_disable_platform_override(true);
StreamPeerSSL::initialize_certs=false; //will be initialized by editor
}
#endif

View file

@ -31,7 +31,12 @@
Size2 PanelContainer::get_minimum_size() const {
Ref<StyleBox> style=get_stylebox("panel");
Ref<StyleBox> style;
if (has_stylebox("panel"))
style=get_stylebox("panel");
else
style=get_stylebox("panel","PanelContainer");
Size2 ms;

View file

@ -35,7 +35,37 @@ bool ScrollContainer::clips_input() const {
Size2 ScrollContainer::get_minimum_size() const {
return Size2(1, 1);
Size2 min_size;
for(int i=0;i<get_child_count();i++) {
Control *c = get_child(i)->cast_to<Control>();
if (!c)
continue;
if (c->is_set_as_toplevel())
continue;
if (c == h_scroll || c == v_scroll)
continue;
Size2 minsize = c->get_combined_minimum_size();
if (!scroll_h) {
min_size.x = MAX(min_size.x, minsize.x);
}
if (!scroll_v) {
min_size.y = MAX(min_size.y, minsize.y);
}
}
if (h_scroll->is_visible()) {
min_size.y+=h_scroll->get_minimum_size().y;
}
if (v_scroll->is_visible()) {
min_size.x+=v_scroll->get_minimum_size().x;
}
return min_size;
};
@ -179,6 +209,12 @@ void ScrollContainer::_notification(int p_what) {
child_max_size = Size2(0, 0);
Size2 size = get_size();
if (h_scroll->is_visible())
size.y-=h_scroll->get_minimum_size().y;
if (v_scroll->is_visible())
size.x-=h_scroll->get_minimum_size().x;
for(int i=0;i<get_child_count();i++) {
Control *c = get_child(i)->cast_to<Control>();

View file

@ -574,7 +574,14 @@ void TreeItem::set_custom_color(int p_column,const Color& p_color) {
cells[p_column].color=p_color;
_changed_notify(p_column);
}
Color TreeItem::get_custom_color(int p_column) const {
ERR_FAIL_INDEX_V( p_column, cells.size(), Color() );
if (!cells[p_column].custom_color)
return Color();
return cells[p_column].color;
}
void TreeItem::clear_custom_color(int p_column) {
ERR_FAIL_INDEX( p_column, cells.size() );

View file

@ -221,6 +221,7 @@ public:
bool is_editable(int p_column);
void set_custom_color(int p_column,const Color& p_color);
Color get_custom_color(int p_column) const;
void clear_custom_color(int p_column);
void set_custom_bg_color(int p_column,const Color& p_color);

View file

@ -7,28 +7,22 @@ void HTTPRequest::_redirect_request(const String& p_new_url) {
Error HTTPRequest::_request() {
print_line("Requesting:\n\tURL: "+url+"\n\tString: "+request_string+"\n\tPort: "+itos(port)+"\n\tSSL: "+itos(use_ssl)+"\n\tValidate SSL: "+itos(validate_ssl));
return client->connect(url,port,use_ssl,validate_ssl);
}
Error HTTPRequest::request(const String& p_url, const Vector<String>& p_custom_headers, bool p_ssl_validate_domain) {
ERR_FAIL_COND_V(!is_inside_tree(),ERR_UNCONFIGURED);
if ( requesting ) {
ERR_EXPLAIN("HTTPRequest is processing a request. Wait for completion or cancel it before attempting a new one.");
ERR_FAIL_V(ERR_BUSY);
}
Error HTTPRequest::_parse_url(const String& p_url) {
url=p_url;
use_ssl=false;
request_string="";
port=80;
headers=p_custom_headers;
request_sent=false;
got_response=false;
validate_ssl=p_ssl_validate_domain;
body_len=-1;
body.resize(0);
downloaded=0;
redirections=0;
print_line("1 url: "+url);
@ -71,8 +65,23 @@ Error HTTPRequest::request(const String& p_url, const Vector<String>& p_custom_h
print_line("4 url: "+url);
return OK;
}
Error HTTPRequest::request(const String& p_url, const Vector<String>& p_custom_headers, bool p_ssl_validate_domain) {
ERR_FAIL_COND_V(!is_inside_tree(),ERR_UNCONFIGURED);
if ( requesting ) {
ERR_EXPLAIN("HTTPRequest is processing a request. Wait for completion or cancel it before attempting a new one.");
ERR_FAIL_V(ERR_BUSY);
}
Error err = _parse_url(p_url);
validate_ssl=p_ssl_validate_domain;
bool has_user_agent=false;
bool has_accept=false;
headers=p_custom_headers;
for(int i=0;i<headers.size();i++) {
@ -91,7 +100,7 @@ Error HTTPRequest::request(const String& p_url, const Vector<String>& p_custom_h
}
Error err = _request();
err = _request();
if (err==OK) {
set_process(true);
@ -112,16 +121,92 @@ void HTTPRequest::cancel_request() {
set_process(false);
}
if (file) {
memdelete(file);
file=NULL;
}
client->close();
body.resize(0);
//downloaded=0;
got_response=false;
response_code=-1;
body_len=-1;
//body_len=-1;
request_sent=false;
requesting=false;
}
bool HTTPRequest::_handle_response(bool *ret_value) {
if (!client->has_response()) {
call_deferred("emit_signal","request_completed",RESULT_NO_RESPONSE,0,StringArray(),ByteArray());
*ret_value=true;
return true;
}
got_response=true;
response_code=client->get_response_code();
List<String> rheaders;
client->get_response_headers(&rheaders);
response_headers.resize(0);
downloaded=0;
for (List<String>::Element *E=rheaders.front();E;E=E->next()) {
print_line("HEADER: "+E->get());
response_headers.push_back(E->get());
}
if (response_code==301 || response_code==302) {
//redirect
if (max_redirects>=0 && redirections>=max_redirects) {
call_deferred("emit_signal","request_completed",RESULT_REDIRECT_LIMIT_REACHED,response_code,response_headers,ByteArray());
*ret_value=true;
return true;
}
String new_request;
for (List<String>::Element *E=rheaders.front();E;E=E->next()) {
if (E->get().findn("Location: ")!=-1) {
new_request=E->get().substr(9,E->get().length()).strip_edges();
}
}
print_line("NEW LOCATION: "+new_request);
if (new_request!="") {
//process redirect
client->close();
int new_redirs=redirections+1; //because _request() will clear it
Error err;
if (new_request.begins_with("http")) {
//new url, request all again
err=_parse_url(new_request);
} else {
request_string=new_request;
}
err = _request();
print_line("new connection: "+itos(err));
if (err==OK) {
request_sent=false;
got_response=false;
body_len=-1;
body.resize(0);
downloaded=0;
redirections=new_redirs;
*ret_value=false;
return true;
}
}
}
return false;
}
bool HTTPRequest::_update_connection() {
switch( client->get_status() ) {
@ -157,52 +242,10 @@ bool HTTPRequest::_update_connection() {
//no body
got_response=true;
response_code=client->get_response_code();
List<String> rheaders;
client->get_response_headers(&rheaders);
response_headers.resize(0);
for (List<String>::Element *E=rheaders.front();E;E=E->next()) {
print_line("HEADER: "+E->get());
response_headers.push_back(E->get());
}
bool ret_value;
if (response_code==301) {
//redirect
if (max_redirects>=0 && redirections>=max_redirects) {
call_deferred("emit_signal","request_completed",RESULT_REDIRECT_LIMIT_REACHED,response_code,response_headers,ByteArray());
return true;
}
String new_request;
for (List<String>::Element *E=rheaders.front();E;E=E->next()) {
if (E->get().findn("Location: ")!=-1) {
new_request=E->get().substr(9,E->get().length()).strip_edges();
}
}
print_line("NEW LOCATION: "+new_request);
if (new_request!="") {
//process redirect
client->close();
request_string=new_request;
int new_redirs=redirections+1; //because _request() will clear it
Error err = _request();
print_line("new connection: "+itos(err));
if (err==OK) {
request_sent=false;
got_response=false;
body_len=-1;
body.resize(0);
redirections=new_redirs;
return false;
}
}
}
if (_handle_response(&ret_value))
return ret_value;
call_deferred("emit_signal","request_completed",RESULT_SUCCESS,response_code,response_headers,ByteArray());
@ -240,20 +283,12 @@ bool HTTPRequest::_update_connection() {
case HTTPClient::STATUS_BODY: {
if (!got_response) {
if (!client->has_response()) {
call_deferred("emit_signal","request_completed",RESULT_NO_RESPONSE,0,StringArray(),ByteArray());
return true;
}
got_response=true;
response_code=client->get_response_code();
List<String> rheaders;
client->get_response_headers(&rheaders);
response_headers.resize(0);
for (List<String>::Element *E=rheaders.front();E;E=E->next()) {
print_line("HEADER: "+E->get());
response_headers.push_back(E->get());
}
bool ret_value;
if (_handle_response(&ret_value))
return ret_value;
if (!client->is_response_chunked() && client->get_response_body_length()==0) {
@ -263,7 +298,7 @@ bool HTTPRequest::_update_connection() {
if (client->is_response_chunked()) {
body_len=-1;
body_len=-1; //no body len because chunked, change your webserver configuration if you want body len
} else {
body_len=client->get_response_body_length();
@ -273,22 +308,41 @@ bool HTTPRequest::_update_connection() {
}
}
if (download_to_file!=String()) {
file=FileAccess::open(download_to_file,FileAccess::WRITE);
if (!file) {
call_deferred("emit_signal","request_completed",RESULT_DOWNLOAD_FILE_CANT_OPEN,response_code,response_headers,ByteArray());
}
}
}
//print_line("BODY: "+itos(body.size()));
client->poll();
body.append_array(client->read_response_body_chunk());
ByteArray chunk = client->read_response_body_chunk();
downloaded+=chunk.size();
if (body_size_limit>=0 && body.size()>body_size_limit) {
if (file) {
ByteArray::Read r=chunk.read();
file->store_buffer(r.ptr(),chunk.size());
if (file->get_error()!=OK) {
call_deferred("emit_signal","request_completed",RESULT_DOWNLOAD_FILE_WRITE_ERROR,response_code,response_headers,ByteArray());
return true;
}
} else {
body.append_array(chunk);
}
if (body_size_limit>=0 && downloaded>body_size_limit) {
call_deferred("emit_signal","request_completed",RESULT_BODY_SIZE_LIMIT_EXCEEDED,response_code,response_headers,ByteArray());
return true;
}
if (body_len>=0) {
if (body.size()==body_len) {
if (downloaded==body_len) {
call_deferred("emit_signal","request_completed",RESULT_SUCCESS,response_code,response_headers,body);
return true;
}
@ -351,6 +405,18 @@ int HTTPRequest::get_body_size_limit() const {
return body_size_limit;
}
void HTTPRequest::set_download_file(const String& p_file) {
ERR_FAIL_COND( status!=HTTPClient::STATUS_DISCONNECTED );
download_to_file=p_file;
}
String HTTPRequest::get_download_file() const {
return download_to_file;
}
HTTPClient::Status HTTPRequest::get_http_client_status() const {
return client->get_status();
}
@ -365,6 +431,14 @@ int HTTPRequest::get_max_redirects() const{
return max_redirects;
}
int HTTPRequest::get_downloaded_bytes() const {
return downloaded;
}
int HTTPRequest::get_body_size() const{
return body_len;
}
void HTTPRequest::_bind_methods() {
@ -382,6 +456,12 @@ void HTTPRequest::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_max_redirects","amount"),&HTTPRequest::set_max_redirects);
ObjectTypeDB::bind_method(_MD("get_max_redirects"),&HTTPRequest::get_max_redirects);
ObjectTypeDB::bind_method(_MD("set_download_file","path"),&HTTPRequest::set_download_file);
ObjectTypeDB::bind_method(_MD("get_download_file"),&HTTPRequest::get_download_file);
ObjectTypeDB::bind_method(_MD("get_downloaded_bytes"),&HTTPRequest::get_downloaded_bytes);
ObjectTypeDB::bind_method(_MD("get_body_size"),&HTTPRequest::get_body_size);
ObjectTypeDB::bind_method(_MD("_redirect_request"),&HTTPRequest::_redirect_request);
ADD_PROPERTY(PropertyInfo(Variant::BOOL,"use_threads"),_SCS("set_use_threads"),_SCS("is_using_threads"));
@ -401,6 +481,7 @@ void HTTPRequest::_bind_methods() {
BIND_CONSTANT( RESULT_BODY_SIZE_LIMIT_EXCEEDED );
BIND_CONSTANT( RESULT_REQUEST_FAILED );
BIND_CONSTANT( RESULT_REDIRECT_LIMIT_REACHED );
BIND_CONSTANT( RESULT_DOWNLOAD_FILE_WRITE_ERROR );
}
@ -413,14 +494,19 @@ HTTPRequest::HTTPRequest()
max_redirects=8;
body_len=-1;
got_response=false;
validate_ssl=false;
validate_ssl=false;
use_ssl=false;
response_code=0;
request_sent=false;
client.instance();
use_threads=false;
body_size_limit=-1;
file=NULL;
status=HTTPClient::STATUS_DISCONNECTED;
}
HTTPRequest::~HTTPRequest() {
if (file)
memdelete(file);
}

View file

@ -3,6 +3,7 @@
#include "node.h"
#include "io/http_client.h"
#include "os/file_access.h"
class HTTPRequest : public Node {
@ -20,6 +21,8 @@ public:
RESULT_NO_RESPONSE,
RESULT_BODY_SIZE_LIMIT_EXCEEDED,
RESULT_REQUEST_FAILED,
RESULT_DOWNLOAD_FILE_CANT_OPEN,
RESULT_DOWNLOAD_FILE_WRITE_ERROR,
RESULT_REDIRECT_LIMIT_REACHED
};
@ -44,8 +47,12 @@ private:
int response_code;
DVector<String> response_headers;
int body_len;
String download_to_file;
FileAccess *file;
int body_len;
int downloaded;
int body_size_limit;
int redirections;
@ -58,8 +65,12 @@ private:
void _redirect_request(const String& p_new_url);
bool _handle_response(bool *ret_value);
Error _parse_url(const String& p_url);
Error _request();
protected:
void _notification(int p_what);
@ -73,13 +84,20 @@ public:
void set_use_threads(bool p_use);
bool is_using_threads() const;
void set_download_file(const String& p_file);
String get_download_file() const;
void set_body_size_limit(int p_bytes);
int get_body_size_limit() const;
void set_max_redirects(int p_max);
int get_max_redirects() const;
int get_downloaded_bytes() const;
int get_body_size() const;
HTTPRequest();
~HTTPRequest();
};
#endif // HTTPREQUEST_H

View file

@ -890,7 +890,11 @@ void make_default_theme() {
t->set_stylebox("border","ReferenceFrame", make_stylebox( reference_border_png,4,4,4,4) );
t->set_stylebox("panelnc","Panel", ttnc );
t->set_stylebox("panelf","Panel", tc_sb );
t->set_stylebox("panel","PanelContainer", tc_sb );
Ref<StyleBoxTexture> sb_pc = make_stylebox( tab_container_bg_png,4,4,4,4,7,7,7,7);
t->set_stylebox("panel","PanelContainer", sb_pc );
t->set_icon("minus","GraphEdit", make_icon(icon_zoom_less_png) );
t->set_icon("reset","GraphEdit", make_icon(icon_zoom_reset_png) );

File diff suppressed because it is too large Load diff

View file

@ -26,6 +26,31 @@ def make_doc_header(target,source,env):
def make_certs_header(target,source,env):
src = source[0].srcnode().abspath
dst = target[0].srcnode().abspath
f = open(src,"rb")
g = open(dst,"wb")
buf = f.read()
decomp_size = len(buf)
import zlib
buf = zlib.compress(buf)
g.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n")
g.write("#ifndef _CERTS_RAW_H\n")
g.write("#define _CERTS_RAW_H\n")
g.write("static const int _certs_compressed_size="+str(len(buf))+";\n")
g.write("static const int _certs_uncompressed_size="+str(decomp_size)+";\n")
g.write("static const unsigned char _certs_compressed[]={\n")
for i in range(len(buf)):
g.write(str(ord(buf[i]))+",\n")
g.write("};\n")
g.write("#endif")
@ -47,6 +72,9 @@ if (env["tools"]=="yes"):
env.Depends("#tools/editor/doc_data_compressed.h","#doc/base/classes.xml")
env.Command("#tools/editor/doc_data_compressed.h","#doc/base/classes.xml",make_doc_header)
env.Depends("#tools/editor/certs_compressed.h","#tools/certs/ca-certificates.crt")
env.Command("#tools/editor/certs_compressed.h","#tools/certs/ca-certificates.crt",make_certs_header)
#make_doc_header(env.File("#tools/editor/doc_data_raw.h").srcnode().abspath,env.File("#doc/base/classes.xml").srcnode().abspath,env)
env.add_source_files(env.tool_sources,"*.cpp")

View file

@ -1,6 +1,6 @@
#include "addon_editor_plugin.h"
#include "editor_node.h"
#include "editor_settings.h"
@ -142,6 +142,7 @@ void EditorAddonLibraryItemDescription::set_image(int p_type,int p_index,const R
case EditorAddonLibrary::IMAGE_QUEUE_ICON: {
item->call("set_image",p_type,p_index,p_image);
icon=p_image;
} break;
case EditorAddonLibrary::IMAGE_QUEUE_THUMBNAIL: {
@ -166,12 +167,30 @@ void EditorAddonLibraryItemDescription::set_image(int p_type,int p_index,const R
void EditorAddonLibraryItemDescription::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_image"),&EditorAddonLibraryItemDescription::set_image);
ObjectTypeDB::bind_method(_MD("_link_click"),&EditorAddonLibraryItemDescription::_link_click);
}
void EditorAddonLibraryItemDescription::configure(const String& p_title,int p_asset_id,const String& p_category,int p_category_id,const String& p_author,int p_author_id,int p_rating,const String& p_cost,const String& p_description) {
void EditorAddonLibraryItemDescription::_link_click(const String& p_url) {
ERR_FAIL_COND(!p_url.begins_with("http"));
OS::get_singleton()->shell_open(p_url);
}
void EditorAddonLibraryItemDescription::configure(const String& p_title,int p_asset_id,const String& p_category,int p_category_id,const String& p_author,int p_author_id,int p_rating,const String& p_cost,const String& p_version,const String& p_description,const String& p_download_url,const String& p_browse_url) {
asset_id=p_asset_id;
title=p_title;
download_url=p_download_url;
item->configure(p_title,p_asset_id,p_category,p_category_id,p_author,p_author_id,p_rating,p_cost);
description->parse_bbcode(p_description);
description->clear();
description->add_text("Version: "+p_version+"\n");
description->add_text("Contents: ");
description->push_meta(p_browse_url);
description->add_text("View Files");
description->pop();
description->add_text("\nDescription:\n\n");
description->append_bbcode(p_description);
set_title(p_title);
}
@ -215,6 +234,7 @@ EditorAddonLibraryItemDescription::EditorAddonLibraryItemDescription() {
desc_bg->set_v_size_flags(SIZE_EXPAND_FILL);
description = memnew( RichTextLabel );
description->connect("meta_clicked",this,"_link_click");
//desc_vbox->add_child(description);
desc_bg->add_child(description);
desc_bg->add_style_override("panel",get_stylebox("normal","TextEdit"));
@ -242,6 +262,205 @@ EditorAddonLibraryItemDescription::EditorAddonLibraryItemDescription() {
}
///////////////////////////////////////////////////////////////////////////////////
void EditorAddonLibraryItemDownload::_http_download_completed(int p_status, int p_code, const StringArray& headers, const ByteArray& p_data) {
String error_text;
switch(p_status) {
case HTTPRequest::RESULT_CANT_RESOLVE: {
error_text=("Can't resolve hostname: "+host);
status->set_text("Can't resolve.");
} break;
case HTTPRequest::RESULT_BODY_SIZE_LIMIT_EXCEEDED:
case HTTPRequest::RESULT_CONNECTION_ERROR:
case HTTPRequest::RESULT_CHUNKED_BODY_SIZE_MISMATCH: {
error_text=("Connection error, please try again.");
status->set_text("Can't connect.");
} break;
case HTTPRequest::RESULT_SSL_HANDSHAKE_ERROR:
case HTTPRequest::RESULT_CANT_CONNECT: {
error_text=("Can't connect to host: "+host);
status->set_text("Can't connect.");
} break;
case HTTPRequest::RESULT_NO_RESPONSE: {
error_text=("No response from host: "+host);
status->set_text("No response.");
} break;
case HTTPRequest::RESULT_REQUEST_FAILED: {
error_text=("Request failed, return code: "+itos(p_code));
status->set_text("Req. Failed.");
} break;
case HTTPRequest::RESULT_REDIRECT_LIMIT_REACHED: {
error_text=("Request failed, too many redirects");
status->set_text("Redirect Loop.");
} break;
default: {
if (p_code!=200) {
error_text=("Request failed, return code: "+itos(p_code));
status->set_text("Failed: "+itos(p_code));
} else {
//all good
}
} break;
}
if (error_text!=String()) {
download_error->set_text("Asset Download Error:\n"+error_text);
download_error->popup_centered_minsize();
return;
}
progress->set_max( download->get_body_size() );
progress->set_val(download->get_downloaded_bytes());
print_line("max: "+itos(download->get_body_size())+" bytes: "+itos(download->get_downloaded_bytes()));
install->set_disabled(false);
status->set_text("Success!");
set_process(false);
}
void EditorAddonLibraryItemDownload::configure(const String& p_title,int p_asset_id,const Ref<Texture>& p_preview, const String& p_download_url) {
title->set_text(p_title);
icon->set_texture(p_preview);
asset_id=p_asset_id;
if (!p_preview.is_valid())
icon->set_texture(get_icon("GodotAssetDefault","EditorIcons"));
host=p_download_url;
set_process(true);
download->set_download_file(EditorSettings::get_singleton()->get_settings_path().plus_file("tmp").plus_file("tmp_asset_"+itos(p_asset_id))+".zip");
Error err = download->request(p_download_url);
ERR_FAIL_COND(err!=OK);
asset_installer->connect("confirmed",this,"_close");
dismiss->set_normal_texture(get_icon("Close","EditorIcons"));
}
void EditorAddonLibraryItemDownload::_notification(int p_what) {
if (p_what==NOTIFICATION_PROCESS) {
progress->set_max( download->get_body_size() );
progress->set_val(download->get_downloaded_bytes());
int cstatus = download->get_http_client_status();
if (cstatus!=prev_status) {
switch(cstatus) {
case HTTPClient::STATUS_RESOLVING: {
status->set_text("Resolving..");
} break;
case HTTPClient::STATUS_CONNECTING: {
status->set_text("Connecting..");
} break;
case HTTPClient::STATUS_REQUESTING: {
status->set_text("Requesting..");
} break;
case HTTPClient::STATUS_BODY: {
status->set_text("Downloading..");
} break;
default: {}
}
prev_status=cstatus;
}
}
}
void EditorAddonLibraryItemDownload::_close() {
DirAccess *da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
da->remove(download->get_download_file()); //clean up removed file
memdelete(da);
queue_delete();
}
void EditorAddonLibraryItemDownload::_install() {
String file = download->get_download_file();
asset_installer->open(file,1);
}
void EditorAddonLibraryItemDownload::_bind_methods() {
ObjectTypeDB::bind_method("_http_download_completed",&EditorAddonLibraryItemDownload::_http_download_completed);
ObjectTypeDB::bind_method("_install",&EditorAddonLibraryItemDownload::_install);
ObjectTypeDB::bind_method("_close",&EditorAddonLibraryItemDownload::_close);
}
EditorAddonLibraryItemDownload::EditorAddonLibraryItemDownload() {
HBoxContainer *hb = memnew( HBoxContainer);
add_child(hb);
icon = memnew( TextureFrame );
hb->add_child(icon);
VBoxContainer *vb = memnew( VBoxContainer );
hb->add_child(vb);
vb->set_h_size_flags(SIZE_EXPAND_FILL);
HBoxContainer *title_hb = memnew( HBoxContainer);
vb->add_child(title_hb);
title = memnew( Label );
title_hb->add_child(title);
title->set_h_size_flags(SIZE_EXPAND_FILL);
dismiss = memnew( TextureButton );
dismiss->connect("pressed",this,"_close");
title_hb->add_child(dismiss);
title->set_clip_text(true);
vb->add_spacer();
status = memnew (Label("Idle"));
vb->add_child(status);
status->add_color_override("font_color", Color(0.5,0.5,0.5) );
progress = memnew( ProgressBar );
vb->add_child(progress);
HBoxContainer *hb2 = memnew( HBoxContainer );
vb->add_child(hb2);
hb2->add_spacer();
install = memnew( Button );
install->set_text("Install");
install->set_disabled(true);
install->connect("pressed",this,"_install");
hb2->add_child(install);
set_custom_minimum_size(Size2(250,0));
download = memnew( HTTPRequest );
add_child(download);
download->connect("request_completed",this,"_http_download_completed");
download_error = memnew( AcceptDialog );
add_child(download_error);
download_error->set_title("Download Error");
asset_installer = memnew( EditorAssetInstaller );
add_child(asset_installer);
prev_status=-1;
}
////////////////////////////////////////////////////////////////////////////////
@ -261,7 +480,7 @@ void EditorAddonLibrary::_notification(int p_what) {
HTTPClient::Status s = request->get_http_client_status();
bool visible = s!=HTTPClient::STATUS_DISCONNECTED;
if (visible !=load_status->is_visible()) {
if (visible != !load_status->is_hidden()) {
load_status->set_hidden(!visible);
}
@ -280,14 +499,41 @@ void EditorAddonLibrary::_notification(int p_what) {
case HTTPClient::STATUS_BODY: {
load_status->set_val(0.4);
} break;
default: {}
}
}
bool no_downloads = downloads_hb->get_child_count()==0;
if (no_downloads != downloads_scroll->is_hidden()) {
downloads_scroll->set_hidden(no_downloads);
}
}
}
void EditorAddonLibrary::_install_asset() {
ERR_FAIL_COND(!description);
for(int i=0;i<downloads_hb->get_child_count();i++) {
EditorAddonLibraryItemDownload *d = downloads_hb->get_child(i)->cast_to<EditorAddonLibraryItemDownload>();
if (d && d->get_asset_id() == description->get_asset_id()) {
EditorNode::get_singleton()->show_warning("Download for this asset is already in progress!");
return;
}
}
EditorAddonLibraryItemDownload * download = memnew( EditorAddonLibraryItemDownload );
downloads_hb->add_child(download);
download->configure(description->get_title(),description->get_asset_id(),description->get_preview_icon(),description->get_download_url());
}
const char* EditorAddonLibrary::sort_key[SORT_MAX]={
"rating",
"downloads",
@ -708,15 +954,23 @@ void EditorAddonLibrary::_http_request_completed(int p_status, int p_code, const
Dictionary r = d["info"];
r["download_url"]="https://github.com/reduz/godot-test-addon/archive/master.zip";
r["browse_url"]="https://github.com/reduz/godot-test-addon";
r["version"]="1.1";
ERR_FAIL_COND(!r.has("title"));
ERR_FAIL_COND(!r.has("asset_id"));
ERR_FAIL_COND(!r.has("author"));
ERR_FAIL_COND(!r.has("author_id"));
ERR_FAIL_COND(!r.has("version"));
ERR_FAIL_COND(!r.has("category"));
ERR_FAIL_COND(!r.has("category_id"));
ERR_FAIL_COND(!r.has("rating"));
ERR_FAIL_COND(!r.has("cost"));
ERR_FAIL_COND(!r.has("description"));
ERR_FAIL_COND(!r.has("download_url"));
ERR_FAIL_COND(!r.has("browse_url"));
if (description) {
memdelete(description);
@ -725,8 +979,9 @@ void EditorAddonLibrary::_http_request_completed(int p_status, int p_code, const
description = memnew( EditorAddonLibraryItemDescription );
add_child(description);
description->popup_centered_minsize();
description->connect("confirmed",this,"_install_asset");
description->configure(r["title"],r["asset_id"],r["category"],r["category_id"],r["author"],r["author_id"],r["rating"],r["cost"],r["description"]);
description->configure(r["title"],r["asset_id"],r["category"],r["category_id"],r["author"],r["author_id"],r["rating"],r["cost"],r["version"],r["description"],r["download_url"],r["browse_url"]);
/*item->connect("asset_selected",this,"_select_asset");
item->connect("author_selected",this,"_select_author");
item->connect("category_selected",this,"_category_selected");*/
@ -764,6 +1019,34 @@ void EditorAddonLibrary::_http_request_completed(int p_status, int p_code, const
}
void EditorAddonLibrary::_asset_file_selected(const String& p_file) {
if (asset_installer) {
memdelete( asset_installer );
asset_installer=NULL;
}
asset_installer = memnew( EditorAssetInstaller );
add_child(asset_installer);
asset_installer->open(p_file);
}
void EditorAddonLibrary::_asset_open() {
asset_open->popup_centered_ratio();
}
void EditorAddonLibrary::_manage_plugins() {
ProjectSettings::get_singleton()->popup_project_settings();
ProjectSettings::get_singleton()->set_plugins_page();
}
void EditorAddonLibrary::_bind_methods() {
ObjectTypeDB::bind_method("_http_request_completed",&EditorAddonLibrary::_http_request_completed);
@ -772,40 +1055,35 @@ void EditorAddonLibrary::_bind_methods() {
ObjectTypeDB::bind_method("_select_category",&EditorAddonLibrary::_select_category);
ObjectTypeDB::bind_method("_image_request_completed",&EditorAddonLibrary::_image_request_completed);
ObjectTypeDB::bind_method("_search",&EditorAddonLibrary::_search,DEFVAL(0));
ObjectTypeDB::bind_method("_install_asset",&EditorAddonLibrary::_install_asset);
ObjectTypeDB::bind_method("_manage_plugins",&EditorAddonLibrary::_manage_plugins);
ObjectTypeDB::bind_method("_asset_open",&EditorAddonLibrary::_asset_open);
ObjectTypeDB::bind_method("_asset_file_selected",&EditorAddonLibrary::_asset_file_selected);
}
EditorAddonLibrary::EditorAddonLibrary() {
tabs = memnew( TabContainer );
tabs->set_v_size_flags(SIZE_EXPAND_FILL);
add_child(tabs);
installed = memnew( EditorPluginSettings );
installed->set_name("Installed");
tabs->add_child(installed);
Ref<StyleBoxEmpty> border;
border.instance();
border->set_default_margin(MARGIN_LEFT,15);
border->set_default_margin(MARGIN_RIGHT,15);
border->set_default_margin(MARGIN_BOTTOM,15);
border->set_default_margin(MARGIN_BOTTOM,5);
border->set_default_margin(MARGIN_TOP,5);
PanelContainer *margin_panel = memnew( PanelContainer );
margin_panel->set_name("Online");
margin_panel->add_style_override("panel",border);
tabs->add_child(margin_panel);
add_style_override("panel",border);
VBoxContainer *library_main = memnew( VBoxContainer );
margin_panel->add_child(library_main);
add_child(library_main);
HBoxContainer *search_hb = memnew( HBoxContainer );
library_main->add_child(search_hb);
library_main->add_constant_override("separation",20);
library_main->add_constant_override("separation",10);
search_hb->add_child( memnew( Label("Search: ")));
filter =memnew( LineEdit );
@ -815,6 +1093,20 @@ EditorAddonLibrary::EditorAddonLibrary() {
search = memnew( Button("Search"));
search->connect("pressed",this,"_search");
search_hb->add_child(search);
search_hb->add_child(memnew( VSeparator ));
Button * open_asset = memnew( Button );
open_asset->set_text("Import");
search_hb->add_child(open_asset);
open_asset->connect("pressed",this,"_asset_open");
Button * plugins = memnew( Button );
plugins->set_text("Plugins");
search_hb->add_child(plugins);
plugins->connect("pressed",this,"_manage_plugins");
library_vb->add_child(search_hb);
HBoxContainer *search_hb2 = memnew( HBoxContainer );
@ -907,6 +1199,7 @@ EditorAddonLibrary::EditorAddonLibrary() {
add_child(request);
request->connect("request_completed",this,"_http_request_completed");
last_queue_id=0;
library_vb->add_constant_override("separation",20);
@ -928,6 +1221,24 @@ EditorAddonLibrary::EditorAddonLibrary() {
//host="http://localhost:8000";
host="http://godotengine.org/addonlib";
set_process(true);
downloads_scroll = memnew( ScrollContainer );
downloads_scroll->set_enable_h_scroll(true);
downloads_scroll->set_enable_v_scroll(false);
library_main->add_child(downloads_scroll);
downloads_hb = memnew( HBoxContainer );
downloads_scroll->add_child(downloads_hb);
asset_open = memnew( EditorFileDialog );
asset_open->set_access(EditorFileDialog::ACCESS_FILESYSTEM);
asset_open->add_filter("*.zip ; Assets ZIP File");
asset_open->set_mode(EditorFileDialog::MODE_OPEN_FILE);
add_child(asset_open);
asset_open->connect("file_selected",this,"_asset_file_selected");
asset_installer=NULL;
}

View file

@ -20,6 +20,7 @@
#include "editor_plugin_settings.h"
#include "scene/main/http_request.h"
#include "editor_asset_installer.h"
class EditorAssetLibraryItem : public PanelContainer {
@ -77,25 +78,79 @@ class EditorAddonLibraryItemDescription : public ConfirmationDialog {
void set_image(int p_type,int p_index,const Ref<Texture>& p_image);
int asset_id;
String download_url;
String title;
Ref<Texture> icon;
void _link_click(const String& p_url);
protected:
static void _bind_methods();
public:
void configure(const String& p_title,int p_asset_id,const String& p_category,int p_category_id,const String& p_author,int p_author_id,int p_rating,const String& p_cost,const String& p_description);
void configure(const String& p_title,int p_asset_id,const String& p_category,int p_category_id,const String& p_author,int p_author_id,int p_rating,const String& p_cost,const String& p_version,const String& p_description,const String& p_download_url,const String& p_browse_url);
void add_preview(int p_id, bool p_video,const String& p_url);
String get_title() { return title; }
Ref<Texture> get_preview_icon() { return icon; }
String get_download_url() { return download_url; }
int get_asset_id() { return asset_id; }
EditorAddonLibraryItemDescription();
};
class EditorAddonLibrary : public VBoxContainer {
OBJ_TYPE(EditorAddonLibrary,VBoxContainer);
class EditorAddonLibraryItemDownload : public PanelContainer {
OBJ_TYPE(EditorAddonLibraryItemDownload, PanelContainer);
TextureFrame *icon;
Label* title;
ProgressBar *progress;
Button *install;
TextureButton *dismiss;
AcceptDialog *download_error;
HTTPRequest *download;
String host;
Label *status;
int prev_status;
int asset_id;
EditorAssetInstaller *asset_installer;
void _close();
void _install();
void _http_download_completed(int p_status, int p_code, const StringArray& headers, const ByteArray& p_data);
protected:
void _notification(int p_what);
static void _bind_methods();
public:
int get_asset_id() { return asset_id; }
void configure(const String& p_title,int p_asset_id,const Ref<Texture>& p_preview, const String& p_download_url);
EditorAddonLibraryItemDownload();
};
class EditorAddonLibrary : public PanelContainer {
OBJ_TYPE(EditorAddonLibrary,PanelContainer);
String host;
TabContainer *tabs;
EditorPluginSettings *installed;
EditorFileDialog *asset_open;
EditorAssetInstaller *asset_installer;
void _asset_open();
void _asset_file_selected(const String& p_file);
ScrollContainer *library_scroll;
VBoxContainer *library_vb;
LineEdit *filter;
@ -116,6 +171,7 @@ class EditorAddonLibrary : public VBoxContainer {
HTTPRequest *request;
enum SortOrder {
SORT_RATING,
SORT_DOWNLOADS,
@ -155,6 +211,7 @@ class EditorAddonLibrary : public VBoxContainer {
void _image_request_completed(int p_status, int p_code, const StringArray& headers, const ByteArray& p_data, int p_queue_id);
void _request_image(ObjectID p_for,int p_asset_id,ImageType p_type,int p_image_index);
void _update_image_queue();
@ -174,13 +231,24 @@ class EditorAddonLibrary : public VBoxContainer {
RequestType requesting;
ScrollContainer *downloads_scroll;
HBoxContainer *downloads_hb;
void _install_asset();
void _select_author(int p_id);
void _select_category(int p_id);
void _select_asset(int p_id);
void _manage_plugins();
void _search(int p_page=0);
void _api_request(const String& p_request, const String &p_arguments="");
void _http_request_completed(int p_status, int p_code, const StringArray& headers, const ByteArray& p_data);
void _http_download_completed(int p_status, int p_code, const StringArray& headers, const ByteArray& p_data);
friend class EditorAddonLibraryItemDescription;
friend class EditorAssetLibraryItem;

View file

@ -0,0 +1,327 @@
#include "editor_asset_installer.h"
#include "io/zip_io.h"
#include "os/dir_access.h"
#include "os/file_access.h"
#include "editor_node.h"
void EditorAssetInstaller::_update_subitems(TreeItem* p_item,bool p_check,bool p_first) {
if (p_check) {
if (p_item->get_custom_color(0)==Color()) {
p_item->set_checked(0,true);
}
} else {
p_item->set_checked(0,false);
}
if (p_item->get_children()) {
_update_subitems(p_item->get_children(),p_check);
}
if (!p_first && p_item->get_next()) {
_update_subitems(p_item->get_next(),p_check);
}
}
void EditorAssetInstaller::_item_edited() {
if (updating)
return;
TreeItem *item = tree->get_edited();
if (!item)
return;
String path=item->get_metadata(0);
updating=true;
if (path==String()) { //a dir
_update_subitems(item,item->is_checked(0),true);
}
if (item->is_checked(0)) {
while(item) {
item->set_checked(0,true);
item=item->get_parent();
}
}
updating=false;
}
void EditorAssetInstaller::open(const String& p_path,int p_depth) {
package_path=p_path;
Set<String> files_sorted;
FileAccess *src_f=NULL;
zlib_filefunc_def io = zipio_create_io_from_file(&src_f);
unzFile pkg = unzOpen2(p_path.utf8().get_data(), &io);
if (!pkg) {
error->set_text("Error opening package file, not in zip format.");
return;
}
int ret = unzGoToFirstFile(pkg);
while(ret==UNZ_OK) {
//get filename
unz_file_info info;
char fname[16384];
ret = unzGetCurrentFileInfo(pkg,&info,fname,16384,NULL,0,NULL,0);
String name=fname;
files_sorted.insert(name);
ret = unzGoToNextFile(pkg);
}
Map<String,Ref<Texture> > extension_guess;
{
extension_guess["png"]=get_icon("Texture","EditorIcons");
extension_guess["jpg"]=get_icon("Texture","EditorIcons");
extension_guess["tex"]=get_icon("Texture","EditorIcons");
extension_guess["atex"]=get_icon("Texture","EditorIcons");
extension_guess["dds"]=get_icon("Texture","EditorIcons");
extension_guess["scn"]=get_icon("PackedScene","EditorIcons");
extension_guess["tscn"]=get_icon("PackedScene","EditorIcons");
extension_guess["xml"]=get_icon("PackedScene","EditorIcons");
extension_guess["xscn"]=get_icon("PackedScene","EditorIcons");
extension_guess["mtl"]=get_icon("Material","EditorIcons");
extension_guess["shd"]=get_icon("Shader","EditorIcons");
extension_guess["gd"]=get_icon("GDScript","EditorIcons");
}
Ref<Texture> generic_extension = get_icon("Object","EditorIcons");
unzClose(pkg);
updating=true;
tree->clear();
TreeItem *root=tree->create_item();
root->set_cell_mode(0,TreeItem::CELL_MODE_CHECK);
root->set_checked(0,true);
root->set_icon(0,get_icon("folder","FileDialog"));
root->set_text(0,"res://");
root->set_editable(0,true);
Map<String,TreeItem*> dir_map;
for(Set<String>::Element *E=files_sorted.front();E;E=E->next()) {
String path = E->get();
int depth=p_depth;
bool skip=false;
while(depth>0) {
int pp = path.find("/");
if (pp==-1) {
skip=true;
break;
}
path=path.substr(pp+1,path.length());
depth--;
}
if (skip || path==String())
continue;
bool isdir=false;
if (path.ends_with("/")) {
//a directory
path=path.substr(0,path.length()-1);
isdir=true;
}
int pp = path.find_last("/");
TreeItem *parent;
if (pp==-1) {
parent=root;
} else {
String ppath=path.substr(0,pp);
print_line("PPATH IS: "+ppath);
ERR_CONTINUE(!dir_map.has(ppath));
parent=dir_map[ppath];
}
TreeItem *ti = tree->create_item(parent);
ti->set_cell_mode(0,TreeItem::CELL_MODE_CHECK);
ti->set_checked(0,true);
ti->set_editable(0,true);
if (isdir) {
dir_map[path]=ti;
ti->set_text(0,path.get_file()+"/");
ti->set_icon(0,get_icon("folder","FileDialog"));
} else {
String file = path.get_file();
String extension = file.extension().to_lower();
if (extension_guess.has(extension)) {
ti->set_icon(0,extension_guess[extension]);
} else {
ti->set_icon(0,generic_extension);
}
ti->set_text(0,file);
String res_path = "res://"+path;
if (FileAccess::exists(res_path)) {
ti->set_custom_color(0,Color(1,0.3,0.2));
ti->set_tooltip(0,res_path+" (Already Exists)");
ti->set_checked(0,false);
} else {
ti->set_tooltip(0,res_path);
}
ti->set_metadata(0,res_path);
}
status_map[E->get()]=ti;
}
popup_centered_ratio();
updating=false;
}
void EditorAssetInstaller::ok_pressed() {
FileAccess *src_f=NULL;
zlib_filefunc_def io = zipio_create_io_from_file(&src_f);
unzFile pkg = unzOpen2(package_path.utf8().get_data(), &io);
if (!pkg) {
error->set_text("Error opening package file, not in zip format.");
return;
}
int ret = unzGoToFirstFile(pkg);
Vector<String> failed_files;
ProgressDialog::get_singleton()->add_task("uncompress","Uncompressing Assets",status_map.size());
int idx=0;
while(ret==UNZ_OK) {
//get filename
unz_file_info info;
char fname[16384];
ret = unzGetCurrentFileInfo(pkg,&info,fname,16384,NULL,0,NULL,0);
String name=fname;
if (status_map.has(name) && status_map[name]->is_checked(0)) {
String path = status_map[name]->get_metadata(0);
if (path==String()) { // a dir
String dirpath;
TreeItem *t = status_map[name];
while(t) {
dirpath=t->get_text(0)+dirpath;
t=t->get_parent();
}
if (dirpath.ends_with("/")) {
dirpath=dirpath.substr(0,dirpath.length()-1);
}
DirAccess *da = DirAccess::create(DirAccess::ACCESS_RESOURCES);
da->make_dir(dirpath);
memdelete(da);
} else {
Vector<uint8_t> data;
data.resize(info.uncompressed_size);
//read
unzOpenCurrentFile(pkg);
unzReadCurrentFile(pkg,data.ptr(),data.size());
unzCloseCurrentFile(pkg);
FileAccess *f=FileAccess::open(path,FileAccess::WRITE);
if (f) {
f->store_buffer(data.ptr(),data.size());
memdelete(f);
} else {
failed_files.push_back(path);
}
ProgressDialog::get_singleton()->task_step("uncompress",path,idx);
}
}
idx++;
ret = unzGoToNextFile(pkg);
}
ProgressDialog::get_singleton()->end_task("uncompress");
unzClose(pkg);
if (failed_files.size()) {
String msg="The following files failed extraction from package:\n\n";
for(int i=0;i<failed_files.size();i++) {
if (i>15) {
msg+="\nAnd "+itos(failed_files.size()-i)+" more files.";
break;
}
msg+=failed_files[i];
}
EditorNode::get_singleton()->show_warning(msg);
} else {
EditorNode::get_singleton()->show_warning("Package Installed Successfully!","Success!");
}
}
void EditorAssetInstaller::_bind_methods() {
ObjectTypeDB::bind_method("_item_edited",&EditorAssetInstaller::_item_edited);
}
EditorAssetInstaller::EditorAssetInstaller() {
VBoxContainer *vb = memnew( VBoxContainer );
add_child(vb);
set_child_rect(vb);
tree = memnew( Tree );
vb->add_margin_child("Package Contents:",tree,true);
tree->connect("item_edited",this,"_item_edited");
error = memnew( AcceptDialog) ;
add_child(error);
get_ok()->set_text("Install");
set_title("Package Installer");
updating=false;
set_hide_on_ok(true);
}

View file

@ -0,0 +1,28 @@
#ifndef EDITORASSETINSTALLER_H
#define EDITORASSETINSTALLER_H
#include "scene/gui/dialogs.h"
#include "scene/gui/tree.h"
class EditorAssetInstaller : public ConfirmationDialog {
OBJ_TYPE( EditorAssetInstaller, ConfirmationDialog );
Tree *tree;
String package_path;
AcceptDialog *error;
Map<String,TreeItem*> status_map;
bool updating;
void _update_subitems(TreeItem* p_item,bool p_check,bool p_first=false);
void _item_edited();
virtual void ok_pressed();
protected:
static void _bind_methods();
public:
void open(const String& p_path,int p_depth=0);
EditorAssetInstaller();
};
#endif // EDITORASSETINSTALLER_H

View file

@ -0,0 +1,21 @@
#include "editor_initialize_ssl.h"
#include "certs_compressed.h"
#include "io/stream_peer_ssl.h"
#include "io/compression.h"
void editor_initialize_certificates() {
ByteArray data;
data.resize(_certs_uncompressed_size);
{
ByteArray::Write w = data.write();
Compression::decompress(w.ptr(),_certs_uncompressed_size,_certs_compressed,_certs_compressed_size,Compression::MODE_DEFLATE);
}
StreamPeerSSL::load_certs_from_memory(data);
}

View file

@ -0,0 +1,6 @@
#ifndef EDITOR_INITIALIZE_SSL_H
#define EDITOR_INITIALIZE_SSL_H
void editor_initialize_certificates();
#endif // EDITOR_INITIALIZE_SSL_H

View file

@ -107,7 +107,7 @@
#include "tools/editor/io_plugins/editor_export_scene.h"
#include "plugins/editor_preview_plugins.h"
#include "editor_initialize_ssl.h"
#include "script_editor_debugger.h"
EditorNode *EditorNode::singleton=NULL;
@ -4145,9 +4145,10 @@ Error EditorNode::export_platform(const String& p_platform, const String& p_path
return OK;
}
void EditorNode::show_warning(const String& p_text) {
void EditorNode::show_warning(const String& p_text, const String &p_title) {
warning->set_text(p_text);
warning->set_title(p_title);
warning->popup_centered_minsize();
}
@ -4950,6 +4951,7 @@ EditorNode::EditorNode() {
EditorHelp::generate_doc(); //before any editor classes are crated
SceneState::set_disable_placeholders(true);
editor_initialize_certificates(); //for asset sharing
InputDefault *id = Input::get_singleton()->cast_to<InputDefault>();

View file

@ -655,7 +655,7 @@ public:
Ref<Theme> get_editor_theme() const { return theme; }
void show_warning(const String& p_text);
void show_warning(const String& p_text,const String& p_title="Warning!");
Error export_platform(const String& p_platform, const String& p_path, bool p_debug,const String& p_password,bool p_quit_after=false);

Binary file not shown.

Before

Width:  |  Height:  |  Size: 476 B

After

Width:  |  Height:  |  Size: 288 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 896 B

After

Width:  |  Height:  |  Size: 289 B

View file

@ -140,6 +140,9 @@ void BackgroundProgress::end_task(const String& p_task){
////////////////////////////////////////////////
ProgressDialog *ProgressDialog::singleton=NULL;
void ProgressDialog::_notification(int p_what) {
switch(p_what) {
@ -237,4 +240,5 @@ ProgressDialog::ProgressDialog() {
main->set_area_as_parent_rect();
set_exclusive(true);
last_progress_tick=0;
singleton=this;
}

View file

@ -86,12 +86,14 @@ class ProgressDialog : public Popup {
VBoxContainer *main;
uint64_t last_progress_tick;
static ProgressDialog *singleton;
void _popup();
protected:
void _notification(int p_what);
public:
static ProgressDialog *get_singleton() { return singleton; }
void add_task(const String& p_task,const String& p_label, int p_steps);
void task_step(const String& p_task, const String& p_state, int p_step=-1, bool p_force_redraw=true);
void end_task(const String& p_task);

View file

@ -1396,6 +1396,11 @@ void ProjectSettings::_clear_search_box() {
globals_editor->get_property_editor()->update_tree();
}
void ProjectSettings::set_plugins_page() {
tab_container->set_current_tab( plugin_settings->get_index() );
}
void ProjectSettings::_bind_methods() {
ObjectTypeDB::bind_method(_MD("_item_selected"),&ProjectSettings::_item_selected);
@ -1452,7 +1457,7 @@ ProjectSettings::ProjectSettings(EditorData *p_data) {
data=p_data;
TabContainer *tab_container = memnew( TabContainer );
tab_container = memnew( TabContainer );
add_child(tab_container);
set_child_rect(tab_container);

View file

@ -34,7 +34,7 @@
#include "optimized_save_dialog.h"
#include "undo_redo.h"
#include "editor_data.h"
#include "scene/gui/tab_container.h"
#include "editor_plugin_settings.h"
//#include "project_export_settings.h"
@ -42,6 +42,9 @@
class ProjectSettings : public AcceptDialog {
OBJ_TYPE( ProjectSettings, AcceptDialog );
TabContainer *tab_container;
Timer *timer;
InputEvent::Type add_type;
String add_at;
@ -164,6 +167,7 @@ public:
void add_translation(const String& p_translation);
static ProjectSettings *get_singleton() { return singleton; }
void popup_project_settings();
void set_plugins_page();
void queue_save();