2014-02-10 02:10:30 +01:00
/*************************************************************************/
2017-09-01 16:07:55 +02:00
/* editor_export.cpp */
2014-02-10 02:10:30 +01:00
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
2017-08-27 14:16:55 +02:00
/* https://godotengine.org */
2014-02-10 02:10:30 +01:00
/*************************************************************************/
2019-01-01 12:53:14 +01:00
/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
2014-02-10 02:10:30 +01:00
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
2018-01-05 00:50:27 +01:00
2017-02-20 03:19:30 +01:00
# include "editor_export.h"
2017-04-28 18:29:15 +02:00
2019-07-11 15:21:47 +02:00
# include "core/crypto/crypto_core.h"
2018-09-11 18:13:45 +02:00
# include "core/io/config_file.h"
# include "core/io/resource_loader.h"
# include "core/io/resource_saver.h"
# include "core/io/zip_io.h"
2019-08-09 13:45:30 +02:00
# include "core/os/dir_access.h"
2018-09-11 18:13:45 +02:00
# include "core/os/file_access.h"
# include "core/project_settings.h"
# include "core/script_language.h"
# include "core/version.h"
2017-03-05 14:21:25 +01:00
# include "editor/editor_file_system.h"
2017-03-05 16:44:50 +01:00
# include "editor/plugins/script_editor_plugin.h"
2017-02-13 02:51:16 +01:00
# include "editor_node.h"
# include "editor_settings.h"
2019-02-12 17:18:13 +01:00
# include "scene/resources/resource_format_text.h"
2017-04-28 18:29:15 +02:00
2017-02-21 04:05:15 +01:00
static int _get_pad ( int p_alignment , int p_n ) {
2017-02-13 02:51:16 +01:00
2017-02-21 04:05:15 +01:00
int rest = p_n % p_alignment ;
int pad = 0 ;
if ( rest > 0 ) {
pad = p_alignment - rest ;
} ;
2017-02-13 02:51:16 +01:00
2017-02-21 04:05:15 +01:00
return pad ;
2017-03-21 03:31:41 +01:00
}
2017-02-21 04:05:15 +01:00
# define PCK_PADDING 16
2017-02-13 02:51:16 +01:00
2017-03-05 16:44:50 +01:00
bool EditorExportPreset : : _set ( const StringName & p_name , const Variant & p_value ) {
2017-02-13 02:51:16 +01:00
2017-03-05 16:44:50 +01:00
if ( values . has ( p_name ) ) {
values [ p_name ] = p_value ;
2017-02-20 03:19:30 +01:00
EditorExport : : singleton - > save_presets ( ) ;
2017-02-13 02:51:16 +01:00
return true ;
}
return false ;
}
2017-03-05 16:44:50 +01:00
bool EditorExportPreset : : _get ( const StringName & p_name , Variant & r_ret ) const {
2017-02-13 02:51:16 +01:00
if ( values . has ( p_name ) ) {
2017-03-05 16:44:50 +01:00
r_ret = values [ p_name ] ;
2017-02-13 02:51:16 +01:00
return true ;
}
return false ;
}
2017-03-28 03:21:21 +02:00
2017-03-05 16:44:50 +01:00
void EditorExportPreset : : _get_property_list ( List < PropertyInfo > * p_list ) const {
2017-02-13 02:51:16 +01:00
2017-03-05 16:44:50 +01:00
for ( const List < PropertyInfo > : : Element * E = properties . front ( ) ; E ; E = E - > next ( ) ) {
2017-02-13 02:51:16 +01:00
2017-03-28 03:21:21 +02:00
if ( platform - > get_option_visibility ( E - > get ( ) . name , values ) ) {
p_list - > push_back ( E - > get ( ) ) ;
}
2017-02-13 02:51:16 +01:00
}
}
2017-02-21 04:05:15 +01:00
Ref < EditorExportPlatform > EditorExportPreset : : get_platform ( ) const {
2017-02-13 02:51:16 +01:00
2017-02-20 03:19:30 +01:00
return platform ;
2017-02-13 02:51:16 +01:00
}
2017-02-20 03:19:30 +01:00
Vector < String > EditorExportPreset : : get_files_to_export ( ) const {
2017-02-13 02:51:16 +01:00
2017-02-20 03:19:30 +01:00
Vector < String > files ;
2017-03-05 16:44:50 +01:00
for ( Set < String > : : Element * E = selected_files . front ( ) ; E ; E = E - > next ( ) ) {
2017-02-20 03:19:30 +01:00
files . push_back ( E - > get ( ) ) ;
}
return files ;
}
2017-03-05 16:44:50 +01:00
void EditorExportPreset : : set_name ( const String & p_name ) {
name = p_name ;
2017-02-20 03:19:30 +01:00
EditorExport : : singleton - > save_presets ( ) ;
}
String EditorExportPreset : : get_name ( ) const {
return name ;
}
void EditorExportPreset : : set_runnable ( bool p_enable ) {
2017-03-05 16:44:50 +01:00
runnable = p_enable ;
2017-02-20 03:19:30 +01:00
EditorExport : : singleton - > save_presets ( ) ;
}
bool EditorExportPreset : : is_runnable ( ) const {
return runnable ;
}
void EditorExportPreset : : set_export_filter ( ExportFilter p_filter ) {
2017-03-05 16:44:50 +01:00
export_filter = p_filter ;
2017-02-20 03:19:30 +01:00
EditorExport : : singleton - > save_presets ( ) ;
}
EditorExportPreset : : ExportFilter EditorExportPreset : : get_export_filter ( ) const {
return export_filter ;
}
2017-02-13 02:51:16 +01:00
2017-03-05 16:44:50 +01:00
void EditorExportPreset : : set_include_filter ( const String & p_include ) {
2017-02-13 02:51:16 +01:00
2017-03-05 16:44:50 +01:00
include_filter = p_include ;
2017-02-20 03:19:30 +01:00
EditorExport : : singleton - > save_presets ( ) ;
}
String EditorExportPreset : : get_include_filter ( ) const {
return include_filter ;
}
2018-10-27 15:53:05 +02:00
void EditorExportPreset : : set_export_path ( const String & p_path ) {
export_path = p_path ;
2019-08-22 22:14:45 +02:00
/* NOTE(SonerSound): if there is a need to implement a PropertyHint that specifically indicates a relative path,
* this should be removed . */
if ( export_path . is_abs_path ( ) ) {
String res_path = OS : : get_singleton ( ) - > get_resource_dir ( ) ;
export_path = res_path . path_to_file ( export_path ) ;
}
2018-10-27 15:53:05 +02:00
EditorExport : : singleton - > save_presets ( ) ;
}
String EditorExportPreset : : get_export_path ( ) const {
return export_path ;
}
2017-03-05 16:44:50 +01:00
void EditorExportPreset : : set_exclude_filter ( const String & p_exclude ) {
2017-02-20 03:19:30 +01:00
2017-03-05 16:44:50 +01:00
exclude_filter = p_exclude ;
2017-02-20 03:19:30 +01:00
EditorExport : : singleton - > save_presets ( ) ;
}
String EditorExportPreset : : get_exclude_filter ( ) const {
return exclude_filter ;
}
2017-03-05 16:44:50 +01:00
void EditorExportPreset : : add_export_file ( const String & p_path ) {
2017-02-20 03:19:30 +01:00
selected_files . insert ( p_path ) ;
EditorExport : : singleton - > save_presets ( ) ;
}
2017-03-05 16:44:50 +01:00
void EditorExportPreset : : remove_export_file ( const String & p_path ) {
2017-02-20 03:19:30 +01:00
selected_files . erase ( p_path ) ;
EditorExport : : singleton - > save_presets ( ) ;
}
2017-03-05 16:44:50 +01:00
bool EditorExportPreset : : has_export_file ( const String & p_path ) {
2017-02-20 03:19:30 +01:00
return selected_files . has ( p_path ) ;
}
2017-03-05 16:44:50 +01:00
void EditorExportPreset : : add_patch ( const String & p_path , int p_at_pos ) {
2017-02-20 03:19:30 +01:00
2017-03-05 16:44:50 +01:00
if ( p_at_pos < 0 )
2017-02-20 03:19:30 +01:00
patches . push_back ( p_path ) ;
else
2017-03-05 16:44:50 +01:00
patches . insert ( p_at_pos , p_path ) ;
2017-02-20 03:19:30 +01:00
EditorExport : : singleton - > save_presets ( ) ;
}
void EditorExportPreset : : remove_patch ( int p_idx ) {
patches . remove ( p_idx ) ;
EditorExport : : singleton - > save_presets ( ) ;
}
2017-03-05 16:44:50 +01:00
void EditorExportPreset : : set_patch ( int p_index , const String & p_path ) {
ERR_FAIL_INDEX ( p_index , patches . size ( ) ) ;
2018-07-25 03:11:03 +02:00
patches . write [ p_index ] = p_path ;
2017-02-20 03:19:30 +01:00
EditorExport : : singleton - > save_presets ( ) ;
}
String EditorExportPreset : : get_patch ( int p_index ) {
2017-03-05 16:44:50 +01:00
ERR_FAIL_INDEX_V ( p_index , patches . size ( ) , String ( ) ) ;
2017-02-20 03:19:30 +01:00
return patches [ p_index ] ;
}
Vector < String > EditorExportPreset : : get_patches ( ) const {
return patches ;
}
2017-07-19 22:00:46 +02:00
void EditorExportPreset : : set_custom_features ( const String & p_custom_features ) {
custom_features = p_custom_features ;
EditorExport : : singleton - > save_presets ( ) ;
}
String EditorExportPreset : : get_custom_features ( ) const {
return custom_features ;
}
2018-12-23 19:28:29 +01:00
void EditorExportPreset : : set_script_export_mode ( int p_mode ) {
script_mode = p_mode ;
EditorExport : : singleton - > save_presets ( ) ;
}
int EditorExportPreset : : get_script_export_mode ( ) const {
return script_mode ;
}
void EditorExportPreset : : set_script_encryption_key ( const String & p_key ) {
script_key = p_key ;
EditorExport : : singleton - > save_presets ( ) ;
}
String EditorExportPreset : : get_script_encryption_key ( ) const {
return script_key ;
}
2018-12-08 21:07:33 +01:00
EditorExportPreset : : EditorExportPreset ( ) :
export_filter ( EXPORT_ALL_RESOURCES ) ,
export_path ( " " ) ,
2018-12-23 19:28:29 +01:00
runnable ( false ) ,
script_mode ( MODE_SCRIPT_COMPILED ) {
2017-02-13 02:51:16 +01:00
}
///////////////////////////////////
void EditorExportPlatform : : gen_debug_flags ( Vector < String > & r_flags , int p_flags ) {
2017-05-09 13:57:07 +02:00
String host = EditorSettings : : get_singleton ( ) - > get ( " network/debug/remote_host " ) ;
2017-06-10 16:28:18 +02:00
int remote_port = ( int ) EditorSettings : : get_singleton ( ) - > get ( " network/debug/remote_port " ) ;
2017-02-13 02:51:16 +01:00
2017-03-05 16:44:50 +01:00
if ( p_flags & DEBUG_FLAG_REMOTE_DEBUG_LOCALHOST )
host = " localhost " ;
2017-02-13 02:51:16 +01:00
2017-03-05 16:44:50 +01:00
if ( p_flags & DEBUG_FLAG_DUMB_CLIENT ) {
2017-02-13 02:51:16 +01:00
int port = EditorSettings : : get_singleton ( ) - > get ( " filesystem/file_server/port " ) ;
String passwd = EditorSettings : : get_singleton ( ) - > get ( " filesystem/file_server/password " ) ;
2017-08-19 16:45:03 +02:00
r_flags . push_back ( " --remote-fs " ) ;
2017-03-05 16:44:50 +01:00
r_flags . push_back ( host + " : " + itos ( port ) ) ;
if ( passwd ! = " " ) {
2017-08-19 16:45:03 +02:00
r_flags . push_back ( " --remote-fs-password " ) ;
2017-02-13 02:51:16 +01:00
r_flags . push_back ( passwd ) ;
}
}
2017-03-05 16:44:50 +01:00
if ( p_flags & DEBUG_FLAG_REMOTE_DEBUG ) {
2017-02-13 02:51:16 +01:00
2017-08-19 16:45:03 +02:00
r_flags . push_back ( " --remote-debug " ) ;
2017-02-13 02:51:16 +01:00
2017-06-10 16:28:18 +02:00
r_flags . push_back ( host + " : " + String : : num ( remote_port ) ) ;
2017-02-13 02:51:16 +01:00
List < String > breakpoints ;
ScriptEditor : : get_singleton ( ) - > get_breakpoints ( & breakpoints ) ;
if ( breakpoints . size ( ) ) {
2017-08-19 16:45:03 +02:00
r_flags . push_back ( " --breakpoints " ) ;
2017-02-13 02:51:16 +01:00
String bpoints ;
2017-03-05 16:44:50 +01:00
for ( const List < String > : : Element * E = breakpoints . front ( ) ; E ; E = E - > next ( ) ) {
2017-02-13 02:51:16 +01:00
2017-03-05 16:44:50 +01:00
bpoints + = E - > get ( ) . replace ( " " , " %20 " ) ;
2017-02-13 02:51:16 +01:00
if ( E - > next ( ) )
2017-03-05 16:44:50 +01:00
bpoints + = " , " ;
2017-02-13 02:51:16 +01:00
}
r_flags . push_back ( bpoints ) ;
}
}
2017-03-05 16:44:50 +01:00
if ( p_flags & DEBUG_FLAG_VIEW_COLLISONS ) {
2017-02-13 02:51:16 +01:00
2017-08-19 16:45:03 +02:00
r_flags . push_back ( " --debug-collisions " ) ;
2017-02-13 02:51:16 +01:00
}
2017-03-05 16:44:50 +01:00
if ( p_flags & DEBUG_FLAG_VIEW_NAVIGATION ) {
2017-02-13 02:51:16 +01:00
2017-08-19 16:45:03 +02:00
r_flags . push_back ( " --debug-navigation " ) ;
2017-02-13 02:51:16 +01:00
}
}
2017-03-05 16:44:50 +01:00
Error EditorExportPlatform : : _save_pack_file ( void * p_userdata , const String & p_path , const Vector < uint8_t > & p_data , int p_file , int p_total ) {
2017-02-13 02:51:16 +01:00
2017-03-05 16:44:50 +01:00
PackData * pd = ( PackData * ) p_userdata ;
2017-02-21 04:05:15 +01:00
SavedData sd ;
2017-03-05 16:44:50 +01:00
sd . path_utf8 = p_path . utf8 ( ) ;
2017-09-10 15:37:49 +02:00
sd . ofs = pd - > f - > get_position ( ) ;
2017-02-21 04:05:15 +01:00
sd . size = p_data . size ( ) ;
2017-03-05 16:44:50 +01:00
pd - > f - > store_buffer ( p_data . ptr ( ) , p_data . size ( ) ) ;
int pad = _get_pad ( PCK_PADDING , sd . size ) ;
for ( int i = 0 ; i < pad ; i + + ) {
2017-02-21 04:05:15 +01:00
pd - > f - > store_8 ( 0 ) ;
}
{
2019-07-02 03:06:52 +02:00
unsigned char hash [ 16 ] ;
CryptoCore : : md5 ( p_data . ptr ( ) , p_data . size ( ) , hash ) ;
2017-02-21 04:05:15 +01:00
sd . md5 . resize ( 16 ) ;
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < 16 ; i + + ) {
2019-07-02 03:06:52 +02:00
sd . md5 . write [ i ] = hash [ i ] ;
2017-02-21 04:05:15 +01:00
}
}
pd - > file_ofs . push_back ( sd ) ;
2018-12-19 19:50:40 +01:00
if ( pd - > ep - > step ( TTR ( " Storing File: " ) + " " + p_path , 2 + p_file * 100 / p_total , false ) ) {
return ERR_SKIP ;
}
2017-02-21 04:05:15 +01:00
2017-02-20 03:19:30 +01:00
return OK ;
2017-02-13 02:51:16 +01:00
}
2017-03-05 16:44:50 +01:00
Error EditorExportPlatform : : _save_zip_file ( void * p_userdata , const String & p_path , const Vector < uint8_t > & p_data , int p_file , int p_total ) {
2017-02-13 02:51:16 +01:00
2017-03-05 16:44:50 +01:00
String path = p_path . replace_first ( " res:// " , " " ) ;
2017-02-13 02:51:16 +01:00
2017-03-05 16:44:50 +01:00
ZipData * zd = ( ZipData * ) p_userdata ;
2017-02-13 02:51:16 +01:00
2017-03-05 16:44:50 +01:00
zipFile zip = ( zipFile ) zd - > zip ;
2017-02-13 02:51:16 +01:00
zipOpenNewFileInZip ( zip ,
2017-03-05 16:44:50 +01:00
path . utf8 ( ) . get_data ( ) ,
NULL ,
NULL ,
0 ,
NULL ,
0 ,
NULL ,
Z_DEFLATED ,
Z_DEFAULT_COMPRESSION ) ;
zipWriteInFileInZip ( zip , p_data . ptr ( ) , p_data . size ( ) ) ;
2017-02-13 02:51:16 +01:00
zipCloseFileInZip ( zip ) ;
2018-12-19 19:50:40 +01:00
if ( zd - > ep - > step ( TTR ( " Storing File: " ) + " " + p_path , 2 + p_file * 100 / p_total , false ) ) {
return ERR_SKIP ;
}
2017-02-21 04:05:15 +01:00
2017-02-13 02:51:16 +01:00
return OK ;
}
2017-04-22 01:15:42 +02:00
String EditorExportPlatform : : find_export_template ( String template_file_name , String * err ) const {
2017-02-13 02:51:16 +01:00
Refactor version macros and fix related bugs
The previous logic with VERSION_MKSTRING was a bit unwieldy, so there were
several places hardcoding their own variant of the version string, potentially
with bugs (e.g. forgetting the patch number when defined).
The new logic defines:
- VERSION_BRANCH, the main 'major.minor' version (e.g. 3.1)
- VERSION_NUMBER, which can be 'major.minor' or 'major.minor.patch',
depending on whether the latter is defined (e.g. 3.1.4)
- VERSION_FULL_CONFIG, which contains the version status (e.g. stable)
and the module-specific suffix (e.g. mono)
- VERSION_FULL_BUILD, same as above but with build/reference name
(e.g. official, custom_build, mageia, etc.)
Note: Slight change here, as the previous format had the build name
*before* the module-specific suffix; now it's after
- VERSION_FULL_NAME, same as before, so VERSION_FULL_BUILD prefixed
with "Godot v" for readability
Bugs fixed thanks to that:
- Export templates version matching now properly takes VERSION_PATCH
into account by relying on VERSION_FULL_CONFIG.
- ClassDB hash no longer takes the build name into account, but limits
itself to VERSION_FULL_CONFIG (build name is cosmetic, not relevant
for the API hash).
- Docs XML no longer hardcode the VERSION_STATUS, this was annoying.
- Small cleanup in Windows .rc file thanks to new macros.
2018-02-23 19:48:49 +01:00
String current_version = VERSION_FULL_CONFIG ;
Add initial support for the XDG Base Directory spec
Spec version 0.7 from https://standards.freedesktop.org/basedir-spec/basedir-spec-0.7.html
(latest as of this commit).
Three virtual methods are added to OS for the various XDG paths we will use:
- OS::get_data_path gives XDG_DATA_HOME, or if missing:
~/.local/share on X11, ~/Library/Application Support/ on macOS and %APPDATA% on Windows
- OS::get_config_path gives XDG_CONFIG_HOME, or if missing:
~/.config on X11, ~/Library/Application Support/ on macOS and %APPDATA% on Windows
- OS::get_cache_path gives XDG_CACHE_HOME, or if missing:
~/.cache on X11, ~/Library/Caches on macOS and %APPDATA% on Windows
So for Windows there are no changes, for Linux we follow the full split spec
and for macOS stuff will move from ~/.godot to ~/Library/Application Support/Godot.
Support for system-wide installation of templates on Unix was removed for now,
as it's a bit hackish and I don't think anyone uses it.
user:// will still be OS::get_data_path() + "/godot/app_userdata/$name" by
default, but when using the application/config/use_shared_user_dir option
it will now use XDG_DATA_HOME/$name, e.g. ~/.local/share/MyGame.
For now everything still goes in EditorSettings::get_settings_dir(), but
this will be changed in a later commit to make use of the new splitting
where relevant.
Part of #3513.
2017-11-17 17:11:41 +01:00
String template_path = EditorSettings : : get_singleton ( ) - > get_templates_dir ( ) . plus_file ( current_version ) . plus_file ( template_file_name ) ;
2017-02-13 02:51:16 +01:00
Add initial support for the XDG Base Directory spec
Spec version 0.7 from https://standards.freedesktop.org/basedir-spec/basedir-spec-0.7.html
(latest as of this commit).
Three virtual methods are added to OS for the various XDG paths we will use:
- OS::get_data_path gives XDG_DATA_HOME, or if missing:
~/.local/share on X11, ~/Library/Application Support/ on macOS and %APPDATA% on Windows
- OS::get_config_path gives XDG_CONFIG_HOME, or if missing:
~/.config on X11, ~/Library/Application Support/ on macOS and %APPDATA% on Windows
- OS::get_cache_path gives XDG_CACHE_HOME, or if missing:
~/.cache on X11, ~/Library/Caches on macOS and %APPDATA% on Windows
So for Windows there are no changes, for Linux we follow the full split spec
and for macOS stuff will move from ~/.godot to ~/Library/Application Support/Godot.
Support for system-wide installation of templates on Unix was removed for now,
as it's a bit hackish and I don't think anyone uses it.
user:// will still be OS::get_data_path() + "/godot/app_userdata/$name" by
default, but when using the application/config/use_shared_user_dir option
it will now use XDG_DATA_HOME/$name, e.g. ~/.local/share/MyGame.
For now everything still goes in EditorSettings::get_settings_dir(), but
this will be changed in a later commit to make use of the new splitting
where relevant.
Part of #3513.
2017-11-17 17:11:41 +01:00
if ( FileAccess : : exists ( template_path ) ) {
return template_path ;
2017-02-13 02:51:16 +01:00
}
2017-04-22 01:15:42 +02:00
// Not found
if ( err ) {
2019-01-21 18:34:53 +01:00
* err + = TTR ( " No export template found at the expected path: " ) + " \n " + template_path + " \n " ;
2017-04-22 01:15:42 +02:00
}
Add initial support for the XDG Base Directory spec
Spec version 0.7 from https://standards.freedesktop.org/basedir-spec/basedir-spec-0.7.html
(latest as of this commit).
Three virtual methods are added to OS for the various XDG paths we will use:
- OS::get_data_path gives XDG_DATA_HOME, or if missing:
~/.local/share on X11, ~/Library/Application Support/ on macOS and %APPDATA% on Windows
- OS::get_config_path gives XDG_CONFIG_HOME, or if missing:
~/.config on X11, ~/Library/Application Support/ on macOS and %APPDATA% on Windows
- OS::get_cache_path gives XDG_CACHE_HOME, or if missing:
~/.cache on X11, ~/Library/Caches on macOS and %APPDATA% on Windows
So for Windows there are no changes, for Linux we follow the full split spec
and for macOS stuff will move from ~/.godot to ~/Library/Application Support/Godot.
Support for system-wide installation of templates on Unix was removed for now,
as it's a bit hackish and I don't think anyone uses it.
user:// will still be OS::get_data_path() + "/godot/app_userdata/$name" by
default, but when using the application/config/use_shared_user_dir option
it will now use XDG_DATA_HOME/$name, e.g. ~/.local/share/MyGame.
For now everything still goes in EditorSettings::get_settings_dir(), but
this will be changed in a later commit to make use of the new splitting
where relevant.
Part of #3513.
2017-11-17 17:11:41 +01:00
return String ( ) ;
2017-04-22 01:15:42 +02:00
}
bool EditorExportPlatform : : exists_export_template ( String template_file_name , String * err ) const {
return find_export_template ( template_file_name , err ) ! = " " ;
2017-02-13 02:51:16 +01:00
}
2017-02-20 03:19:30 +01:00
Ref < EditorExportPreset > EditorExportPlatform : : create_preset ( ) {
Ref < EditorExportPreset > preset ;
preset . instance ( ) ;
2017-03-05 16:44:50 +01:00
preset - > platform = Ref < EditorExportPlatform > ( this ) ;
2017-02-20 03:19:30 +01:00
List < ExportOption > options ;
get_export_options ( & options ) ;
2017-03-05 16:44:50 +01:00
for ( List < ExportOption > : : Element * E = options . front ( ) ; E ; E = E - > next ( ) ) {
2017-02-20 03:19:30 +01:00
preset - > properties . push_back ( E - > get ( ) . option ) ;
2017-03-05 16:44:50 +01:00
preset - > values [ E - > get ( ) . option . name ] = E - > get ( ) . default_value ;
2017-02-20 03:19:30 +01:00
}
return preset ;
}
2017-02-13 02:51:16 +01:00
2017-03-05 16:44:50 +01:00
void EditorExportPlatform : : _export_find_resources ( EditorFileSystemDirectory * p_dir , Set < String > & p_paths ) {
2017-02-21 04:05:15 +01:00
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < p_dir - > get_subdir_count ( ) ; i + + ) {
_export_find_resources ( p_dir - > get_subdir ( i ) , p_paths ) ;
2017-02-21 04:05:15 +01:00
}
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < p_dir - > get_file_count ( ) ; i + + ) {
2017-02-21 04:05:15 +01:00
p_paths . insert ( p_dir - > get_file_path ( i ) ) ;
}
}
2017-03-05 16:44:50 +01:00
void EditorExportPlatform : : _export_find_dependencies ( const String & p_path , Set < String > & p_paths ) {
2017-02-21 04:05:15 +01:00
if ( p_paths . has ( p_path ) )
return ;
p_paths . insert ( p_path ) ;
EditorFileSystemDirectory * dir ;
int file_idx ;
2017-03-05 16:44:50 +01:00
dir = EditorFileSystem : : get_singleton ( ) - > find_file ( p_path , & file_idx ) ;
2017-02-21 04:05:15 +01:00
if ( ! dir )
return ;
Vector < String > deps = dir - > get_file_deps ( file_idx ) ;
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < deps . size ( ) ; i + + ) {
2017-02-21 04:05:15 +01:00
2017-03-05 16:44:50 +01:00
_export_find_dependencies ( deps [ i ] , p_paths ) ;
2017-02-21 04:05:15 +01:00
}
}
2017-08-14 15:13:09 +02:00
void EditorExportPlatform : : _edit_files_with_filter ( DirAccess * da , const Vector < String > & p_filters , Set < String > & r_list , bool exclude ) {
da - > list_dir_begin ( ) ;
String cur_dir = da - > get_current_dir ( ) . replace ( " \\ " , " / " ) ;
if ( ! cur_dir . ends_with ( " / " ) )
cur_dir + = " / " ;
2018-07-18 12:20:37 +02:00
String cur_dir_no_prefix = cur_dir . replace ( " res:// " , " " ) ;
2017-08-14 15:13:09 +02:00
Vector < String > dirs ;
String f ;
while ( ( f = da - > get_next ( ) ) ! = " " ) {
if ( da - > current_is_dir ( ) )
dirs . push_back ( f ) ;
else {
String fullpath = cur_dir + f ;
2018-07-18 12:20:37 +02:00
// Test also against path without res:// so that filters like `file.txt` can work.
String fullpath_no_prefix = cur_dir_no_prefix + f ;
2017-08-14 15:13:09 +02:00
for ( int i = 0 ; i < p_filters . size ( ) ; + + i ) {
2018-07-18 12:20:37 +02:00
if ( fullpath . matchn ( p_filters [ i ] ) | | fullpath_no_prefix . matchn ( p_filters [ i ] ) ) {
2017-08-14 15:13:09 +02:00
if ( ! exclude ) {
r_list . insert ( fullpath ) ;
} else {
r_list . erase ( fullpath ) ;
}
}
}
}
}
da - > list_dir_end ( ) ;
for ( int i = 0 ; i < dirs . size ( ) ; + + i ) {
String dir = dirs [ i ] ;
if ( dir . begins_with ( " . " ) )
continue ;
da - > change_dir ( dir ) ;
_edit_files_with_filter ( da , p_filters , r_list , exclude ) ;
da - > change_dir ( " .. " ) ;
}
}
void EditorExportPlatform : : _edit_filter_list ( Set < String > & r_list , const String & p_filter , bool exclude ) {
if ( p_filter = = " " )
return ;
Vector < String > split = p_filter . split ( " , " ) ;
Vector < String > filters ;
for ( int i = 0 ; i < split . size ( ) ; i + + ) {
String f = split [ i ] . strip_edges ( ) ;
if ( f . empty ( ) )
continue ;
filters . push_back ( f ) ;
}
DirAccess * da = DirAccess : : open ( " res:// " ) ;
ERR_FAIL_NULL ( da ) ;
_edit_files_with_filter ( da , filters , r_list , exclude ) ;
memdelete ( da ) ;
}
2018-12-23 19:28:29 +01:00
void EditorExportPlugin : : set_export_preset ( const Ref < EditorExportPreset > & p_preset ) {
if ( p_preset . is_valid ( ) ) {
export_preset = p_preset ;
}
}
Ref < EditorExportPreset > EditorExportPlugin : : get_export_preset ( ) const {
return export_preset ;
}
2017-09-15 00:38:38 +02:00
void EditorExportPlugin : : add_file ( const String & p_path , const Vector < uint8_t > & p_file , bool p_remap ) {
ExtraFile ef ;
ef . data = p_file ;
ef . path = p_path ;
ef . remap = p_remap ;
extra_files . push_back ( ef ) ;
}
2017-10-02 17:01:43 +02:00
void EditorExportPlugin : : add_shared_object ( const String & p_path , const Vector < String > & tags ) {
2017-09-15 00:38:38 +02:00
2017-10-02 17:01:43 +02:00
shared_objects . push_back ( SharedObject ( p_path , tags ) ) ;
}
void EditorExportPlugin : : add_ios_framework ( const String & p_path ) {
ios_frameworks . push_back ( p_path ) ;
}
Vector < String > EditorExportPlugin : : get_ios_frameworks ( ) const {
return ios_frameworks ;
}
void EditorExportPlugin : : add_ios_plist_content ( const String & p_plist_content ) {
ios_plist_content + = p_plist_content + " \n " ;
}
String EditorExportPlugin : : get_ios_plist_content ( ) const {
return ios_plist_content ;
}
void EditorExportPlugin : : add_ios_linker_flags ( const String & p_flags ) {
if ( ios_linker_flags . length ( ) > 0 ) {
ios_linker_flags + = ' ' ;
}
ios_linker_flags + = p_flags ;
}
String EditorExportPlugin : : get_ios_linker_flags ( ) const {
return ios_linker_flags ;
}
void EditorExportPlugin : : add_ios_bundle_file ( const String & p_path ) {
ios_bundle_files . push_back ( p_path ) ;
}
Vector < String > EditorExportPlugin : : get_ios_bundle_files ( ) const {
return ios_bundle_files ;
}
void EditorExportPlugin : : add_ios_cpp_code ( const String & p_code ) {
ios_cpp_code + = p_code ;
}
String EditorExportPlugin : : get_ios_cpp_code ( ) const {
return ios_cpp_code ;
2017-09-15 00:38:38 +02:00
}
2017-09-15 18:45:03 +02:00
void EditorExportPlugin : : _export_file_script ( const String & p_path , const String & p_type , const PoolVector < String > & p_features ) {
2017-09-15 00:38:38 +02:00
if ( get_script_instance ( ) ) {
2017-09-15 18:45:03 +02:00
get_script_instance ( ) - > call ( " _export_file " , p_path , p_type , p_features ) ;
2017-09-15 00:38:38 +02:00
}
}
2017-10-02 17:01:43 +02:00
void EditorExportPlugin : : _export_begin_script ( const PoolVector < String > & p_features , bool p_debug , const String & p_path , int p_flags ) {
2017-09-15 18:45:03 +02:00
if ( get_script_instance ( ) ) {
2017-10-02 17:01:43 +02:00
get_script_instance ( ) - > call ( " _export_begin " , p_features , p_debug , p_path , p_flags ) ;
2017-09-15 18:45:03 +02:00
}
}
2018-12-07 19:05:10 +01:00
void EditorExportPlugin : : _export_end_script ( ) {
if ( get_script_instance ( ) ) {
get_script_instance ( ) - > call ( " _export_end " ) ;
}
}
2017-09-15 18:45:03 +02:00
void EditorExportPlugin : : _export_file ( const String & p_path , const String & p_type , const Set < String > & p_features ) {
}
2017-10-02 17:01:43 +02:00
void EditorExportPlugin : : _export_begin ( const Set < String > & p_features , bool p_debug , const String & p_path , int p_flags ) {
2017-09-15 00:38:38 +02:00
}
void EditorExportPlugin : : skip ( ) {
skipped = true ;
}
void EditorExportPlugin : : _bind_methods ( ) {
2017-10-02 17:01:43 +02:00
ClassDB : : bind_method ( D_METHOD ( " add_shared_object " , " path " , " tags " ) , & EditorExportPlugin : : add_shared_object ) ;
2017-09-15 00:38:38 +02:00
ClassDB : : bind_method ( D_METHOD ( " add_file " , " path " , " file " , " remap " ) , & EditorExportPlugin : : add_file ) ;
2017-10-02 17:01:43 +02:00
ClassDB : : bind_method ( D_METHOD ( " add_ios_framework " , " path " ) , & EditorExportPlugin : : add_ios_framework ) ;
ClassDB : : bind_method ( D_METHOD ( " add_ios_plist_content " , " plist_content " ) , & EditorExportPlugin : : add_ios_plist_content ) ;
ClassDB : : bind_method ( D_METHOD ( " add_ios_linker_flags " , " flags " ) , & EditorExportPlugin : : add_ios_linker_flags ) ;
ClassDB : : bind_method ( D_METHOD ( " add_ios_bundle_file " , " path " ) , & EditorExportPlugin : : add_ios_bundle_file ) ;
ClassDB : : bind_method ( D_METHOD ( " add_ios_cpp_code " , " code " ) , & EditorExportPlugin : : add_ios_cpp_code ) ;
2017-09-15 00:38:38 +02:00
ClassDB : : bind_method ( D_METHOD ( " skip " ) , & EditorExportPlugin : : skip ) ;
2017-09-15 18:45:03 +02:00
BIND_VMETHOD ( MethodInfo ( " _export_file " , PropertyInfo ( Variant : : STRING , " path " ) , PropertyInfo ( Variant : : STRING , " type " ) , PropertyInfo ( Variant : : POOL_STRING_ARRAY , " features " ) ) ) ;
2017-10-02 17:01:43 +02:00
BIND_VMETHOD ( MethodInfo ( " _export_begin " , PropertyInfo ( Variant : : POOL_STRING_ARRAY , " features " ) , PropertyInfo ( Variant : : BOOL , " is_debug " ) , PropertyInfo ( Variant : : STRING , " path " ) , PropertyInfo ( Variant : : INT , " flags " ) ) ) ;
2019-05-23 23:31:02 +02:00
BIND_VMETHOD ( MethodInfo ( " _export_end " ) ) ;
2017-09-15 00:38:38 +02:00
}
EditorExportPlugin : : EditorExportPlugin ( ) {
skipped = false ;
}
2017-10-02 17:01:43 +02:00
EditorExportPlatform : : FeatureContainers EditorExportPlatform : : get_feature_containers ( const Ref < EditorExportPreset > & p_preset ) {
2017-02-21 04:05:15 +01:00
Ref < EditorExportPlatform > platform = p_preset - > get_platform ( ) ;
List < String > feature_list ;
2017-10-02 17:01:43 +02:00
platform - > get_platform_features ( & feature_list ) ;
2017-03-05 16:44:50 +01:00
platform - > get_preset_features ( p_preset , & feature_list ) ;
2017-10-02 17:01:43 +02:00
FeatureContainers result ;
2017-03-05 16:44:50 +01:00
for ( List < String > : : Element * E = feature_list . front ( ) ; E ; E = E - > next ( ) ) {
2017-10-02 17:01:43 +02:00
result . features . insert ( E - > get ( ) ) ;
result . features_pv . push_back ( E - > get ( ) ) ;
2017-02-21 04:05:15 +01:00
}
2018-12-07 20:29:47 +01:00
if ( p_preset - > get_custom_features ( ) ! = String ( ) ) {
Vector < String > tmp_custom_list = p_preset - > get_custom_features ( ) . split ( " , " ) ;
for ( int i = 0 ; i < tmp_custom_list . size ( ) ; i + + ) {
String f = tmp_custom_list [ i ] . strip_edges ( ) ;
if ( f ! = String ( ) ) {
result . features . insert ( f ) ;
result . features_pv . push_back ( f ) ;
}
}
}
2017-10-02 17:01:43 +02:00
return result ;
}
2017-02-21 04:05:15 +01:00
2017-10-02 17:01:43 +02:00
EditorExportPlatform : : ExportNotifier : : ExportNotifier ( EditorExportPlatform & p_platform , const Ref < EditorExportPreset > & p_preset , bool p_debug , const String & p_path , int p_flags ) {
FeatureContainers features = p_platform . get_feature_containers ( p_preset ) ;
2017-09-15 00:38:38 +02:00
Vector < Ref < EditorExportPlugin > > export_plugins = EditorExport : : get_singleton ( ) - > get_export_plugins ( ) ;
2017-10-02 17:01:43 +02:00
//initial export plugin callback
for ( int i = 0 ; i < export_plugins . size ( ) ; i + + ) {
if ( export_plugins [ i ] - > get_script_instance ( ) ) { //script based
2018-07-25 03:11:03 +02:00
export_plugins . write [ i ] - > _export_begin_script ( features . features_pv , p_debug , p_path , p_flags ) ;
2017-10-02 17:01:43 +02:00
} else {
2018-07-25 03:11:03 +02:00
export_plugins . write [ i ] - > _export_begin ( features . features , p_debug , p_path , p_flags ) ;
2017-10-02 17:01:43 +02:00
}
}
}
EditorExportPlatform : : ExportNotifier : : ~ ExportNotifier ( ) {
Vector < Ref < EditorExportPlugin > > export_plugins = EditorExport : : get_singleton ( ) - > get_export_plugins ( ) ;
for ( int i = 0 ; i < export_plugins . size ( ) ; i + + ) {
2018-12-07 19:05:10 +01:00
if ( export_plugins [ i ] - > get_script_instance ( ) ) {
export_plugins . write [ i ] - > _export_end_script ( ) ;
}
2018-07-25 03:11:03 +02:00
export_plugins . write [ i ] - > _export_end ( ) ;
2017-10-02 17:01:43 +02:00
}
}
2017-09-15 00:38:38 +02:00
2017-10-02 17:01:43 +02:00
Error EditorExportPlatform : : export_project_files ( const Ref < EditorExportPreset > & p_preset , EditorExportSaveFunction p_func , void * p_udata , EditorExportSaveSharedObject p_so_func ) {
2017-02-21 04:05:15 +01:00
//figure out paths of files that will be exported
Set < String > paths ;
2017-09-15 00:38:38 +02:00
Vector < String > path_remaps ;
2017-02-21 04:05:15 +01:00
2017-03-05 16:44:50 +01:00
if ( p_preset - > get_export_filter ( ) = = EditorExportPreset : : EXPORT_ALL_RESOURCES ) {
2017-02-21 04:05:15 +01:00
//find stuff
2017-03-05 16:44:50 +01:00
_export_find_resources ( EditorFileSystem : : get_singleton ( ) - > get_filesystem ( ) , paths ) ;
2017-02-21 04:05:15 +01:00
} else {
2017-03-05 16:44:50 +01:00
bool scenes_only = p_preset - > get_export_filter ( ) = = EditorExportPreset : : EXPORT_SELECTED_SCENES ;
2017-02-21 04:05:15 +01:00
Vector < String > files = p_preset - > get_files_to_export ( ) ;
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < files . size ( ) ; i + + ) {
if ( scenes_only & & ResourceLoader : : get_resource_type ( files [ i ] ) ! = " PackedScene " )
2017-02-21 04:05:15 +01:00
continue ;
2017-03-05 16:44:50 +01:00
_export_find_dependencies ( files [ i ] , paths ) ;
2017-02-21 04:05:15 +01:00
}
}
2019-05-17 15:43:56 +02:00
//add native icons to non-resource include list
_edit_filter_list ( paths , String ( " *.icns " ) , false ) ;
_edit_filter_list ( paths , String ( " *.ico " ) , false ) ;
2017-08-14 15:13:09 +02:00
_edit_filter_list ( paths , p_preset - > get_include_filter ( ) , false ) ;
_edit_filter_list ( paths , p_preset - > get_exclude_filter ( ) , true ) ;
2017-10-02 17:01:43 +02:00
Vector < Ref < EditorExportPlugin > > export_plugins = EditorExport : : get_singleton ( ) - > get_export_plugins ( ) ;
2017-09-15 18:45:03 +02:00
for ( int i = 0 ; i < export_plugins . size ( ) ; i + + ) {
2018-12-23 19:28:29 +01:00
export_plugins . write [ i ] - > set_export_preset ( p_preset ) ;
2017-09-15 18:45:03 +02:00
if ( p_so_func ) {
for ( int j = 0 ; j < export_plugins [ i ] - > shared_objects . size ( ) ; j + + ) {
p_so_func ( p_udata , export_plugins [ i ] - > shared_objects [ j ] ) ;
}
}
for ( int j = 0 ; j < export_plugins [ i ] - > extra_files . size ( ) ; j + + ) {
p_func ( p_udata , export_plugins [ i ] - > extra_files [ j ] . path , export_plugins [ i ] - > extra_files [ j ] . data , 0 , paths . size ( ) ) ;
}
2018-07-25 03:11:03 +02:00
export_plugins . write [ i ] - > _clear ( ) ;
2017-09-15 18:45:03 +02:00
}
2017-10-02 17:01:43 +02:00
FeatureContainers feature_containers = get_feature_containers ( p_preset ) ;
Set < String > & features = feature_containers . features ;
PoolVector < String > & features_pv = feature_containers . features_pv ;
2017-02-21 04:05:15 +01:00
//store everything in the export medium
int idx = 0 ;
2017-03-05 16:44:50 +01:00
int total = paths . size ( ) ;
2017-02-21 04:05:15 +01:00
2017-03-05 16:44:50 +01:00
for ( Set < String > : : Element * E = paths . front ( ) ; E ; E = E - > next ( ) ) {
2017-02-21 04:05:15 +01:00
String path = E - > get ( ) ;
2017-09-15 18:45:03 +02:00
String type = ResourceLoader : : get_resource_type ( path ) ;
2017-02-21 04:05:15 +01:00
2017-03-05 16:44:50 +01:00
if ( FileAccess : : exists ( path + " .import " ) ) {
2017-02-21 04:05:15 +01:00
//file is imported, replace by what it imports
Ref < ConfigFile > config ;
config . instance ( ) ;
2017-03-05 16:44:50 +01:00
Error err = config - > load ( path + " .import " ) ;
if ( err ! = OK ) {
ERR_PRINTS ( " Could not parse: ' " + path + " ', not exported. " ) ;
2017-02-21 04:05:15 +01:00
continue ;
}
List < String > remaps ;
2017-03-05 16:44:50 +01:00
config - > get_section_keys ( " remap " , & remaps ) ;
2017-02-21 04:05:15 +01:00
2018-08-22 04:56:04 +02:00
Set < String > remap_features ;
for ( List < String > : : Element * F = remaps . front ( ) ; F ; F = F - > next ( ) ) {
String remap = F - > get ( ) ;
String feature = remap . get_slice ( " . " , 1 ) ;
2018-08-27 18:47:13 +02:00
if ( features . has ( feature ) ) {
2018-08-22 04:56:04 +02:00
remap_features . insert ( feature ) ;
}
}
if ( remap_features . size ( ) > 1 ) {
this - > resolve_platform_feature_priorities ( p_preset , remap_features ) ;
}
2018-12-19 19:50:40 +01:00
err = OK ;
2017-03-05 16:44:50 +01:00
for ( List < String > : : Element * F = remaps . front ( ) ; F ; F = F - > next ( ) ) {
2017-02-21 04:05:15 +01:00
2017-03-05 16:44:50 +01:00
String remap = F - > get ( ) ;
if ( remap = = " path " ) {
String remapped_path = config - > get_value ( " remap " , remap ) ;
2017-02-21 04:05:15 +01:00
Vector < uint8_t > array = FileAccess : : get_file_as_array ( remapped_path ) ;
2018-12-19 19:50:40 +01:00
err = p_func ( p_udata , remapped_path , array , idx , total ) ;
2017-02-21 04:05:15 +01:00
} else if ( remap . begins_with ( " path. " ) ) {
2017-03-05 16:44:50 +01:00
String feature = remap . get_slice ( " . " , 1 ) ;
2018-08-22 04:56:04 +02:00
if ( remap_features . has ( feature ) ) {
2017-03-05 16:44:50 +01:00
String remapped_path = config - > get_value ( " remap " , remap ) ;
2017-02-21 04:05:15 +01:00
Vector < uint8_t > array = FileAccess : : get_file_as_array ( remapped_path ) ;
2018-12-19 19:50:40 +01:00
err = p_func ( p_udata , remapped_path , array , idx , total ) ;
2017-02-21 04:05:15 +01:00
}
}
}
2018-12-19 19:50:40 +01:00
if ( err ! = OK ) {
return err ;
}
2017-02-21 04:05:15 +01:00
//also save the .import file
2017-03-05 16:44:50 +01:00
Vector < uint8_t > array = FileAccess : : get_file_as_array ( path + " .import " ) ;
2018-12-19 19:50:40 +01:00
err = p_func ( p_udata , path + " .import " , array , idx , total ) ;
if ( err ! = OK ) {
return err ;
}
2017-02-21 04:05:15 +01:00
} else {
2017-09-15 00:38:38 +02:00
bool do_export = true ;
for ( int i = 0 ; i < export_plugins . size ( ) ; i + + ) {
if ( export_plugins [ i ] - > get_script_instance ( ) ) { //script based
2018-07-25 03:11:03 +02:00
export_plugins . write [ i ] - > _export_file_script ( path , type , features_pv ) ;
2017-09-15 00:38:38 +02:00
} else {
2018-07-25 03:11:03 +02:00
export_plugins . write [ i ] - > _export_file ( path , type , features ) ;
2017-09-15 00:38:38 +02:00
}
if ( p_so_func ) {
for ( int j = 0 ; j < export_plugins [ i ] - > shared_objects . size ( ) ; j + + ) {
p_so_func ( p_udata , export_plugins [ i ] - > shared_objects [ j ] ) ;
}
}
for ( int j = 0 ; j < export_plugins [ i ] - > extra_files . size ( ) ; j + + ) {
p_func ( p_udata , export_plugins [ i ] - > extra_files [ j ] . path , export_plugins [ i ] - > extra_files [ j ] . data , idx , total ) ;
if ( export_plugins [ i ] - > extra_files [ j ] . remap ) {
do_export = false ; //if remap, do not
path_remaps . push_back ( path ) ;
path_remaps . push_back ( export_plugins [ i ] - > extra_files [ j ] . path ) ;
}
}
if ( export_plugins [ i ] - > skipped ) {
do_export = false ;
}
2018-07-25 03:11:03 +02:00
export_plugins . write [ i ] - > _clear ( ) ;
2017-09-15 00:38:38 +02:00
if ( ! do_export )
break ; //apologies, not exporting
}
2017-02-21 04:05:15 +01:00
//just store it as it comes
2017-09-15 00:38:38 +02:00
if ( do_export ) {
Vector < uint8_t > array = FileAccess : : get_file_as_array ( path ) ;
p_func ( p_udata , path , array , idx , total ) ;
}
2017-02-21 04:05:15 +01:00
}
idx + + ;
}
//save config!
2017-07-19 22:00:46 +02:00
Vector < String > custom_list ;
if ( p_preset - > get_custom_features ( ) ! = String ( ) ) {
Vector < String > tmp_custom_list = p_preset - > get_custom_features ( ) . split ( " , " ) ;
for ( int i = 0 ; i < tmp_custom_list . size ( ) ; i + + ) {
String f = tmp_custom_list [ i ] . strip_edges ( ) ;
if ( f ! = String ( ) ) {
custom_list . push_back ( f ) ;
}
}
}
2017-09-15 00:38:38 +02:00
ProjectSettings : : CustomMap custom_map ;
if ( path_remaps . size ( ) ) {
2017-12-18 15:21:13 +01:00
if ( 1 ) { //new remap mode, use always as it's friendlier with multiple .pck exports
for ( int i = 0 ; i < path_remaps . size ( ) ; i + = 2 ) {
String from = path_remaps [ i ] ;
String to = path_remaps [ i + 1 ] ;
String remap_file = " [remap] \n \n path= \" " + to . c_escape ( ) + " \" \n " ;
CharString utf8 = remap_file . utf8 ( ) ;
Vector < uint8_t > new_file ;
new_file . resize ( utf8 . length ( ) ) ;
for ( int j = 0 ; j < utf8 . length ( ) ; j + + ) {
2018-07-25 03:11:03 +02:00
new_file . write [ j ] = utf8 [ j ] ;
2017-12-18 15:21:13 +01:00
}
p_func ( p_udata , from + " .remap " , new_file , idx , total ) ;
}
} else {
//old remap mode, will still work, but it's unused because it's not multiple pck export friendly
custom_map [ " path_remap/remapped_paths " ] = path_remaps ;
}
2017-09-15 00:38:38 +02:00
}
2017-12-06 00:13:58 +01:00
// Store icon and splash images directly, they need to bypass the import system and be loaded as images
String icon = ProjectSettings : : get_singleton ( ) - > get ( " application/config/icon " ) ;
String splash = ProjectSettings : : get_singleton ( ) - > get ( " application/boot_splash/image " ) ;
if ( icon ! = String ( ) & & FileAccess : : exists ( icon ) ) {
Vector < uint8_t > array = FileAccess : : get_file_as_array ( icon ) ;
p_func ( p_udata , icon , array , idx , total ) ;
}
2019-02-16 21:58:46 +01:00
if ( splash ! = String ( ) & & FileAccess : : exists ( splash ) & & icon ! = splash ) {
2017-12-06 00:13:58 +01:00
Vector < uint8_t > array = FileAccess : : get_file_as_array ( splash ) ;
p_func ( p_udata , splash , array , idx , total ) ;
}
2017-07-19 22:00:46 +02:00
String config_file = " project.binary " ;
2017-11-17 21:48:24 +01:00
String engine_cfb = EditorSettings : : get_singleton ( ) - > get_cache_dir ( ) . plus_file ( " tmp " + config_file ) ;
2017-09-15 00:38:38 +02:00
ProjectSettings : : get_singleton ( ) - > save_custom ( engine_cfb , custom_map , custom_list ) ;
2017-02-21 04:05:15 +01:00
Vector < uint8_t > data = FileAccess : : get_file_as_array ( engine_cfb ) ;
2019-08-09 13:45:30 +02:00
DirAccess : : remove_file_or_error ( engine_cfb ) ;
2017-02-21 04:05:15 +01:00
2017-03-05 16:44:50 +01:00
p_func ( p_udata , " res:// " + config_file , data , idx , total ) ;
2017-02-21 04:05:15 +01:00
2017-02-13 02:51:16 +01:00
return OK ;
}
2017-10-02 17:01:43 +02:00
Error EditorExportPlatform : : _add_shared_object ( void * p_userdata , const SharedObject & p_so ) {
PackData * pack_data = ( PackData * ) p_userdata ;
if ( pack_data - > so_files ) {
pack_data - > so_files - > push_back ( p_so ) ;
}
return OK ;
}
2019-03-25 20:56:33 +01:00
Error EditorExportPlatform : : save_pack ( const Ref < EditorExportPreset > & p_preset , const String & p_path , Vector < SharedObject > * p_so_files , bool p_embed , int64_t * r_embedded_start , int64_t * r_embedded_size ) {
2017-02-21 04:05:15 +01:00
2018-12-19 19:50:40 +01:00
EditorProgress ep ( " savepack " , TTR ( " Packing " ) , 102 , true ) ;
2017-02-21 04:05:15 +01:00
2017-11-17 21:48:24 +01:00
String tmppath = EditorSettings : : get_singleton ( ) - > get_cache_dir ( ) . plus_file ( " packtmp " ) ;
2017-03-05 16:44:50 +01:00
FileAccess * ftmp = FileAccess : : open ( tmppath , FileAccess : : WRITE ) ;
2019-09-25 10:28:50 +02:00
ERR_FAIL_COND_V_MSG ( ! ftmp , ERR_CANT_CREATE , " Cannot create file ' " + tmppath + " '. " ) ;
2017-02-21 04:05:15 +01:00
PackData pd ;
2017-03-05 16:44:50 +01:00
pd . ep = & ep ;
pd . f = ftmp ;
2017-10-02 17:01:43 +02:00
pd . so_files = p_so_files ;
2017-02-21 04:05:15 +01:00
2017-10-02 17:01:43 +02:00
Error err = export_project_files ( p_preset , _save_pack_file , & pd , _add_shared_object ) ;
2017-02-21 04:05:15 +01:00
memdelete ( ftmp ) ; //close tmp file
2019-08-09 13:45:30 +02:00
if ( err ! = OK ) {
DirAccess : : remove_file_or_error ( tmppath ) ;
2017-02-21 04:05:15 +01:00
return err ;
2019-08-09 13:45:30 +02:00
}
2017-02-21 04:05:15 +01:00
pd . file_ofs . sort ( ) ; //do sort, so we can do binary search later
2019-03-25 20:56:33 +01:00
FileAccess * f ;
int64_t embed_pos = 0 ;
if ( ! p_embed ) {
// Regular output to separate PCK file
f = FileAccess : : open ( p_path , FileAccess : : WRITE ) ;
2019-08-09 13:45:30 +02:00
if ( ! f ) {
DirAccess : : remove_file_or_error ( tmppath ) ;
ERR_FAIL_V ( ERR_CANT_CREATE ) ;
}
2019-03-25 20:56:33 +01:00
} else {
// Append to executable
f = FileAccess : : open ( p_path , FileAccess : : READ_WRITE ) ;
2019-08-09 13:45:30 +02:00
if ( ! f ) {
DirAccess : : remove_file_or_error ( tmppath ) ;
ERR_FAIL_V ( ERR_FILE_CANT_OPEN ) ;
}
2019-03-25 20:56:33 +01:00
f - > seek_end ( ) ;
embed_pos = f - > get_position ( ) ;
if ( r_embedded_start ) {
* r_embedded_start = embed_pos ;
}
// Ensure embedded PCK starts at a 64-bit multiple
int pad = f - > get_position ( ) % 8 ;
for ( int i = 0 ; i < pad ; i + + ) {
f - > store_8 ( 0 ) ;
}
}
int64_t pck_start_pos = f - > get_position ( ) ;
f - > store_32 ( 0x43504447 ) ; //GDPC
2017-02-21 04:05:15 +01:00
f - > store_32 ( 1 ) ; //pack version
f - > store_32 ( VERSION_MAJOR ) ;
f - > store_32 ( VERSION_MINOR ) ;
f - > store_32 ( 0 ) ; //hmph
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < 16 ; i + + ) {
2017-02-21 04:05:15 +01:00
//reserved
f - > store_32 ( 0 ) ;
}
f - > store_32 ( pd . file_ofs . size ( ) ) ; //amount of files
2019-03-25 20:56:33 +01:00
int64_t header_size = f - > get_position ( ) ;
2017-02-21 04:05:15 +01:00
//precalculate header size
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < pd . file_ofs . size ( ) ; i + + ) {
2017-02-21 04:05:15 +01:00
header_size + = 4 ; // size of path string (32 bits is enough)
2019-03-25 20:56:33 +01:00
int string_len = pd . file_ofs [ i ] . path_utf8 . length ( ) ;
2017-03-05 16:44:50 +01:00
header_size + = string_len + _get_pad ( 4 , string_len ) ; ///size of path string
2017-02-21 04:05:15 +01:00
header_size + = 8 ; // offset to file _with_ header size included
header_size + = 8 ; // size of file
2017-03-05 16:44:50 +01:00
header_size + = 16 ; // md5
2017-02-21 04:05:15 +01:00
}
2019-03-25 20:56:33 +01:00
int header_padding = _get_pad ( PCK_PADDING , header_size ) ;
2017-02-21 04:05:15 +01:00
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < pd . file_ofs . size ( ) ; i + + ) {
2017-02-21 04:05:15 +01:00
2019-03-25 20:56:33 +01:00
int string_len = pd . file_ofs [ i ] . path_utf8 . length ( ) ;
int pad = _get_pad ( 4 , string_len ) ;
2017-03-05 16:44:50 +01:00
f - > store_32 ( string_len + pad ) ;
f - > store_buffer ( ( const uint8_t * ) pd . file_ofs [ i ] . path_utf8 . get_data ( ) , string_len ) ;
2019-03-25 20:56:33 +01:00
for ( int j = 0 ; j < pad ; j + + ) {
2017-02-21 04:05:15 +01:00
f - > store_8 ( 0 ) ;
}
f - > store_64 ( pd . file_ofs [ i ] . ofs + header_padding + header_size ) ;
f - > store_64 ( pd . file_ofs [ i ] . size ) ; // pay attention here, this is where file is
2017-03-05 16:44:50 +01:00
f - > store_buffer ( pd . file_ofs [ i ] . md5 . ptr ( ) , 16 ) ; //also save md5 for file
2017-02-21 04:05:15 +01:00
}
2019-03-25 20:56:33 +01:00
for ( int i = 0 ; i < header_padding ; i + + ) {
2017-02-21 04:05:15 +01:00
f - > store_8 ( 0 ) ;
}
2019-08-09 13:45:30 +02:00
// Save the rest of the data.
2017-02-21 04:05:15 +01:00
2017-03-05 16:44:50 +01:00
ftmp = FileAccess : : open ( tmppath , FileAccess : : READ ) ;
2017-02-21 04:05:15 +01:00
if ( ! ftmp ) {
memdelete ( f ) ;
2019-08-09 13:45:30 +02:00
DirAccess : : remove_file_or_error ( tmppath ) ;
2019-09-25 10:28:50 +02:00
ERR_FAIL_V_MSG ( ERR_CANT_CREATE , " Can't open file to read from path ' " + String ( tmppath ) + " '. " ) ;
2017-02-21 04:05:15 +01:00
}
2017-03-05 16:44:50 +01:00
const int bufsize = 16384 ;
2017-02-21 04:05:15 +01:00
uint8_t buf [ bufsize ] ;
2017-03-05 16:44:50 +01:00
while ( true ) {
2017-02-21 04:05:15 +01:00
2017-03-05 16:44:50 +01:00
int got = ftmp - > get_buffer ( buf , bufsize ) ;
if ( got < = 0 )
2017-02-21 04:05:15 +01:00
break ;
2017-03-05 16:44:50 +01:00
f - > store_buffer ( buf , got ) ;
2017-02-21 04:05:15 +01:00
}
memdelete ( ftmp ) ;
2019-03-25 20:56:33 +01:00
if ( p_embed ) {
// Ensure embedded data ends at a 64-bit multiple
int64_t embed_end = f - > get_position ( ) - embed_pos + 12 ;
int pad = embed_end % 8 ;
for ( int i = 0 ; i < pad ; i + + ) {
f - > store_8 ( 0 ) ;
}
int64_t pck_size = f - > get_position ( ) - pck_start_pos ;
f - > store_64 ( pck_size ) ;
f - > store_32 ( 0x43504447 ) ; //GDPC
if ( r_embedded_size ) {
* r_embedded_size = f - > get_position ( ) - embed_pos ;
}
}
2017-02-21 04:05:15 +01:00
memdelete ( f ) ;
2019-08-09 13:45:30 +02:00
DirAccess : : remove_file_or_error ( tmppath ) ;
2017-02-13 02:51:16 +01:00
return OK ;
}
2017-03-05 16:44:50 +01:00
Error EditorExportPlatform : : save_zip ( const Ref < EditorExportPreset > & p_preset , const String & p_path ) {
2017-02-13 02:51:16 +01:00
2018-12-19 19:50:40 +01:00
EditorProgress ep ( " savezip " , TTR ( " Packing " ) , 102 , true ) ;
2017-02-21 04:05:15 +01:00
FileAccess * src_f ;
zlib_filefunc_def io = zipio_create_io_from_file ( & src_f ) ;
2017-03-05 16:44:50 +01:00
zipFile zip = zipOpen2 ( p_path . utf8 ( ) . get_data ( ) , APPEND_STATUS_CREATE , NULL , & io ) ;
2017-02-21 04:05:15 +01:00
ZipData zd ;
2017-03-05 16:44:50 +01:00
zd . ep = & ep ;
zd . zip = zip ;
2017-02-21 04:05:15 +01:00
2017-03-05 16:44:50 +01:00
Error err = export_project_files ( p_preset , _save_zip_file , & zd ) ;
2018-12-19 19:50:40 +01:00
if ( err ! = OK & & err ! = ERR_SKIP )
2017-09-02 22:32:31 +02:00
ERR_PRINT ( " Failed to export project files " ) ;
2017-02-21 04:05:15 +01:00
2017-03-05 16:44:50 +01:00
zipClose ( zip , NULL ) ;
2017-02-21 04:05:15 +01:00
2017-02-13 02:51:16 +01:00
return OK ;
}
2018-04-26 23:08:19 +02:00
Error EditorExportPlatform : : export_pack ( const Ref < EditorExportPreset > & p_preset , bool p_debug , const String & p_path , int p_flags ) {
ExportNotifier notifier ( * this , p_preset , p_debug , p_path , p_flags ) ;
return save_pack ( p_preset , p_path ) ;
}
Error EditorExportPlatform : : export_zip ( const Ref < EditorExportPreset > & p_preset , bool p_debug , const String & p_path , int p_flags ) {
ExportNotifier notifier ( * this , p_preset , p_debug , p_path , p_flags ) ;
return save_zip ( p_preset , p_path ) ;
}
2017-03-24 00:14:12 +01:00
void EditorExportPlatform : : gen_export_flags ( Vector < String > & r_flags , int p_flags ) {
2017-05-09 13:57:07 +02:00
String host = EditorSettings : : get_singleton ( ) - > get ( " network/debug/remote_host " ) ;
2017-06-10 16:28:18 +02:00
int remote_port = ( int ) EditorSettings : : get_singleton ( ) - > get ( " network/debug/remote_port " ) ;
2017-03-24 00:14:12 +01:00
if ( p_flags & DEBUG_FLAG_REMOTE_DEBUG_LOCALHOST )
host = " localhost " ;
if ( p_flags & DEBUG_FLAG_DUMB_CLIENT ) {
int port = EditorSettings : : get_singleton ( ) - > get ( " filesystem/file_server/port " ) ;
String passwd = EditorSettings : : get_singleton ( ) - > get ( " filesystem/file_server/password " ) ;
2017-08-19 16:45:03 +02:00
r_flags . push_back ( " --remote-fs " ) ;
2017-03-24 00:14:12 +01:00
r_flags . push_back ( host + " : " + itos ( port ) ) ;
if ( passwd ! = " " ) {
2017-08-19 16:45:03 +02:00
r_flags . push_back ( " --remote-fs-password " ) ;
2017-03-24 00:14:12 +01:00
r_flags . push_back ( passwd ) ;
}
}
if ( p_flags & DEBUG_FLAG_REMOTE_DEBUG ) {
2017-08-19 16:45:03 +02:00
r_flags . push_back ( " --remote-debug " ) ;
2017-03-24 00:14:12 +01:00
2017-06-10 16:28:18 +02:00
r_flags . push_back ( host + " : " + String : : num ( remote_port ) ) ;
2017-03-24 00:14:12 +01:00
List < String > breakpoints ;
ScriptEditor : : get_singleton ( ) - > get_breakpoints ( & breakpoints ) ;
if ( breakpoints . size ( ) ) {
2017-08-19 16:45:03 +02:00
r_flags . push_back ( " --breakpoints " ) ;
2017-03-24 00:14:12 +01:00
String bpoints ;
for ( const List < String > : : Element * E = breakpoints . front ( ) ; E ; E = E - > next ( ) ) {
bpoints + = E - > get ( ) . replace ( " " , " %20 " ) ;
if ( E - > next ( ) )
bpoints + = " , " ;
}
r_flags . push_back ( bpoints ) ;
}
}
if ( p_flags & DEBUG_FLAG_VIEW_COLLISONS ) {
2017-08-19 16:45:03 +02:00
r_flags . push_back ( " --debug-collisions " ) ;
2017-03-24 00:14:12 +01:00
}
if ( p_flags & DEBUG_FLAG_VIEW_NAVIGATION ) {
2017-08-19 16:45:03 +02:00
r_flags . push_back ( " --debug-navigation " ) ;
2017-03-24 00:14:12 +01:00
}
}
2017-02-13 02:51:16 +01:00
EditorExportPlatform : : EditorExportPlatform ( ) {
}
////
2017-03-05 16:44:50 +01:00
EditorExport * EditorExport : : singleton = NULL ;
2017-02-20 03:19:30 +01:00
void EditorExport : : _save ( ) {
Ref < ConfigFile > config ;
config . instance ( ) ;
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < export_presets . size ( ) ; i + + ) {
2017-02-20 03:19:30 +01:00
Ref < EditorExportPreset > preset = export_presets [ i ] ;
2017-03-05 16:44:50 +01:00
String section = " preset. " + itos ( i ) ;
2017-02-20 03:19:30 +01:00
2017-03-05 16:44:50 +01:00
config - > set_value ( section , " name " , preset - > get_name ( ) ) ;
config - > set_value ( section , " platform " , preset - > get_platform ( ) - > get_name ( ) ) ;
config - > set_value ( section , " runnable " , preset - > is_runnable ( ) ) ;
2017-07-20 11:48:00 +02:00
config - > set_value ( section , " custom_features " , preset - > get_custom_features ( ) ) ;
2018-12-23 19:28:29 +01:00
2017-03-05 16:44:50 +01:00
bool save_files = false ;
switch ( preset - > get_export_filter ( ) ) {
2017-02-20 03:19:30 +01:00
case EditorExportPreset : : EXPORT_ALL_RESOURCES : {
2017-03-05 16:44:50 +01:00
config - > set_value ( section , " export_filter " , " all_resources " ) ;
2017-02-20 03:19:30 +01:00
} break ;
case EditorExportPreset : : EXPORT_SELECTED_SCENES : {
2017-03-05 16:44:50 +01:00
config - > set_value ( section , " export_filter " , " scenes " ) ;
save_files = true ;
2017-02-20 03:19:30 +01:00
} break ;
case EditorExportPreset : : EXPORT_SELECTED_RESOURCES : {
2017-03-05 16:44:50 +01:00
config - > set_value ( section , " export_filter " , " resources " ) ;
save_files = true ;
2017-02-20 03:19:30 +01:00
} break ;
}
if ( save_files ) {
Vector < String > export_files = preset - > get_files_to_export ( ) ;
2017-03-05 16:44:50 +01:00
config - > set_value ( section , " export_files " , export_files ) ;
2017-02-20 03:19:30 +01:00
}
2017-03-05 16:44:50 +01:00
config - > set_value ( section , " include_filter " , preset - > get_include_filter ( ) ) ;
config - > set_value ( section , " exclude_filter " , preset - > get_exclude_filter ( ) ) ;
2018-10-27 15:53:05 +02:00
config - > set_value ( section , " export_path " , preset - > get_export_path ( ) ) ;
2017-03-05 16:44:50 +01:00
config - > set_value ( section , " patch_list " , preset - > get_patches ( ) ) ;
2018-12-23 19:28:29 +01:00
config - > set_value ( section , " script_export_mode " , preset - > get_script_export_mode ( ) ) ;
config - > set_value ( section , " script_encryption_key " , preset - > get_script_encryption_key ( ) ) ;
2017-02-20 03:19:30 +01:00
2017-03-05 16:44:50 +01:00
String option_section = " preset. " + itos ( i ) + " .options " ;
2017-02-20 03:19:30 +01:00
2017-03-05 16:44:50 +01:00
for ( const List < PropertyInfo > : : Element * E = preset - > get_properties ( ) . front ( ) ; E ; E = E - > next ( ) ) {
config - > set_value ( option_section , E - > get ( ) . name , preset - > get ( E - > get ( ) . name ) ) ;
2017-02-20 03:19:30 +01:00
}
}
config - > save ( " res://export_presets.cfg " ) ;
}
void EditorExport : : save_presets ( ) {
if ( block_save )
return ;
save_timer - > start ( ) ;
}
void EditorExport : : _bind_methods ( ) {
2017-03-05 16:44:50 +01:00
ClassDB : : bind_method ( " _save " , & EditorExport : : _save ) ;
2017-02-20 03:19:30 +01:00
}
2017-03-05 16:44:50 +01:00
void EditorExport : : add_export_platform ( const Ref < EditorExportPlatform > & p_platform ) {
2017-02-13 02:51:16 +01:00
export_platforms . push_back ( p_platform ) ;
}
int EditorExport : : get_export_platform_count ( ) {
return export_platforms . size ( ) ;
}
Ref < EditorExportPlatform > EditorExport : : get_export_platform ( int p_idx ) {
2017-03-05 16:44:50 +01:00
ERR_FAIL_INDEX_V ( p_idx , export_platforms . size ( ) , Ref < EditorExportPlatform > ( ) ) ;
2017-02-13 02:51:16 +01:00
return export_platforms [ p_idx ] ;
}
2017-03-05 16:44:50 +01:00
void EditorExport : : add_export_preset ( const Ref < EditorExportPreset > & p_preset , int p_at_pos ) {
2017-02-13 02:51:16 +01:00
2017-03-05 16:44:50 +01:00
if ( p_at_pos < 0 )
2017-02-13 02:51:16 +01:00
export_presets . push_back ( p_preset ) ;
else
2017-03-05 16:44:50 +01:00
export_presets . insert ( p_at_pos , p_preset ) ;
2017-02-13 02:51:16 +01:00
}
2019-02-26 22:43:37 +01:00
String EditorExportPlatform : : test_etc2 ( ) const {
String driver = ProjectSettings : : get_singleton ( ) - > get ( " rendering/quality/driver/driver_name " ) ;
2019-03-05 13:46:51 +01:00
bool driver_fallback = ProjectSettings : : get_singleton ( ) - > get ( " rendering/quality/driver/fallback_to_gles2 " ) ;
2019-03-03 11:52:53 +01:00
bool etc_supported = ProjectSettings : : get_singleton ( ) - > get ( " rendering/vram_compression/import_etc " ) ;
bool etc2_supported = ProjectSettings : : get_singleton ( ) - > get ( " rendering/vram_compression/import_etc2 " ) ;
2019-02-26 22:43:37 +01:00
2019-03-03 11:52:53 +01:00
if ( driver = = " GLES2 " & & ! etc_supported ) {
2019-03-05 13:46:51 +01:00
return TTR ( " Target platform requires 'ETC' texture compression for GLES2. Enable 'Import Etc' in Project Settings. " ) ;
} else if ( driver = = " GLES3 " ) {
String err ;
if ( ! etc2_supported ) {
err + = TTR ( " Target platform requires 'ETC2' texture compression for GLES3. Enable 'Import Etc 2' in Project Settings. " ) ;
}
if ( driver_fallback & & ! etc_supported ) {
if ( err ! = String ( ) )
err + = " \n " ;
err + = TTR ( " Target platform requires 'ETC' texture compression for the driver fallback to GLES2. \n Enable 'Import Etc' in Project Settings, or disable 'Driver Fallback Enabled'. " ) ;
}
return err ;
2019-02-26 22:43:37 +01:00
}
return String ( ) ;
}
2017-02-13 02:51:16 +01:00
int EditorExport : : get_export_preset_count ( ) const {
return export_presets . size ( ) ;
}
Ref < EditorExportPreset > EditorExport : : get_export_preset ( int p_idx ) {
2017-03-05 16:44:50 +01:00
ERR_FAIL_INDEX_V ( p_idx , export_presets . size ( ) , Ref < EditorExportPreset > ( ) ) ;
2017-02-13 02:51:16 +01:00
return export_presets [ p_idx ] ;
}
void EditorExport : : remove_export_preset ( int p_idx ) {
export_presets . remove ( p_idx ) ;
2018-10-03 18:03:03 +02:00
save_presets ( ) ;
2017-02-13 02:51:16 +01:00
}
2017-09-15 00:38:38 +02:00
void EditorExport : : add_export_plugin ( const Ref < EditorExportPlugin > & p_plugin ) {
2017-11-15 17:24:32 +01:00
if ( export_plugins . find ( p_plugin ) = = - 1 ) {
2017-09-15 00:38:38 +02:00
export_plugins . push_back ( p_plugin ) ;
}
}
void EditorExport : : remove_export_plugin ( const Ref < EditorExportPlugin > & p_plugin ) {
export_plugins . erase ( p_plugin ) ;
}
Vector < Ref < EditorExportPlugin > > EditorExport : : get_export_plugins ( ) {
return export_plugins ;
}
2017-02-20 03:19:30 +01:00
void EditorExport : : _notification ( int p_what ) {
2017-03-05 16:44:50 +01:00
if ( p_what = = NOTIFICATION_ENTER_TREE ) {
2017-02-20 03:19:30 +01:00
load_config ( ) ;
}
}
2017-02-13 02:51:16 +01:00
void EditorExport : : load_config ( ) {
2017-02-20 03:19:30 +01:00
Ref < ConfigFile > config ;
config . instance ( ) ;
Error err = config - > load ( " res://export_presets.cfg " ) ;
2017-03-05 16:44:50 +01:00
if ( err ! = OK )
2017-02-20 03:19:30 +01:00
return ;
2017-02-13 02:51:16 +01:00
2017-03-05 16:44:50 +01:00
block_save = true ;
2017-02-20 03:19:30 +01:00
2017-03-05 16:44:50 +01:00
int index = 0 ;
while ( true ) {
2017-02-20 03:19:30 +01:00
2017-03-05 16:44:50 +01:00
String section = " preset. " + itos ( index ) ;
2017-02-20 03:19:30 +01:00
if ( ! config - > has_section ( section ) )
break ;
2017-03-05 16:44:50 +01:00
String platform = config - > get_value ( section , " platform " ) ;
2017-02-20 03:19:30 +01:00
Ref < EditorExportPreset > preset ;
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < export_platforms . size ( ) ; i + + ) {
if ( export_platforms [ i ] - > get_name ( ) = = platform ) {
2018-07-25 03:11:03 +02:00
preset = export_platforms . write [ i ] - > create_preset ( ) ;
2017-02-20 03:19:30 +01:00
break ;
}
}
if ( ! preset . is_valid ( ) ) {
index + + ;
ERR_CONTINUE ( ! preset . is_valid ( ) ) ;
}
2017-03-05 16:44:50 +01:00
preset - > set_name ( config - > get_value ( section , " name " ) ) ;
preset - > set_runnable ( config - > get_value ( section , " runnable " ) ) ;
2017-02-20 03:19:30 +01:00
2017-07-19 22:00:46 +02:00
if ( config - > has_section_key ( section , " custom_features " ) ) {
preset - > set_custom_features ( config - > get_value ( section , " custom_features " ) ) ;
}
2017-03-05 16:44:50 +01:00
String export_filter = config - > get_value ( section , " export_filter " ) ;
2017-02-20 03:19:30 +01:00
2017-03-05 16:44:50 +01:00
bool get_files = false ;
2017-02-20 03:19:30 +01:00
2017-03-05 16:44:50 +01:00
if ( export_filter = = " all_resources " ) {
2017-02-20 03:19:30 +01:00
preset - > set_export_filter ( EditorExportPreset : : EXPORT_ALL_RESOURCES ) ;
2017-03-05 16:44:50 +01:00
} else if ( export_filter = = " scenes " ) {
2017-02-20 03:19:30 +01:00
preset - > set_export_filter ( EditorExportPreset : : EXPORT_SELECTED_SCENES ) ;
2017-03-05 16:44:50 +01:00
get_files = true ;
} else if ( export_filter = = " resources " ) {
2017-02-20 03:19:30 +01:00
preset - > set_export_filter ( EditorExportPreset : : EXPORT_SELECTED_RESOURCES ) ;
2017-03-05 16:44:50 +01:00
get_files = true ;
2017-02-20 03:19:30 +01:00
}
if ( get_files ) {
2017-03-05 16:44:50 +01:00
Vector < String > files = config - > get_value ( section , " export_files " ) ;
2017-02-20 03:19:30 +01:00
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < files . size ( ) ; i + + ) {
2017-02-20 03:19:30 +01:00
preset - > add_export_file ( files [ i ] ) ;
}
}
2017-03-05 16:44:50 +01:00
preset - > set_include_filter ( config - > get_value ( section , " include_filter " ) ) ;
preset - > set_exclude_filter ( config - > get_value ( section , " exclude_filter " ) ) ;
2018-10-27 15:53:05 +02:00
preset - > set_export_path ( config - > get_value ( section , " export_path " , " " ) ) ;
2017-02-20 03:19:30 +01:00
2017-03-05 16:44:50 +01:00
Vector < String > patch_list = config - > get_value ( section , " patch_list " ) ;
2017-02-20 03:19:30 +01:00
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < patch_list . size ( ) ; i + + ) {
2017-02-20 03:19:30 +01:00
preset - > add_patch ( patch_list [ i ] ) ;
}
2018-12-23 19:28:29 +01:00
if ( config - > has_section_key ( section , " script_export_mode " ) ) {
preset - > set_script_export_mode ( config - > get_value ( section , " script_export_mode " ) ) ;
}
if ( config - > has_section_key ( section , " script_encryption_key " ) ) {
preset - > set_script_encryption_key ( config - > get_value ( section , " script_encryption_key " ) ) ;
}
2017-03-05 16:44:50 +01:00
String option_section = " preset. " + itos ( index ) + " .options " ;
2017-02-20 03:19:30 +01:00
List < String > options ;
2017-03-05 16:44:50 +01:00
config - > get_section_keys ( option_section , & options ) ;
2017-02-13 02:51:16 +01:00
2017-03-05 16:44:50 +01:00
for ( List < String > : : Element * E = options . front ( ) ; E ; E = E - > next ( ) ) {
2017-02-20 03:19:30 +01:00
2017-03-05 16:44:50 +01:00
Variant value = config - > get_value ( option_section , E - > get ( ) ) ;
2017-02-20 03:19:30 +01:00
2017-03-05 16:44:50 +01:00
preset - > set ( E - > get ( ) , value ) ;
2017-02-20 03:19:30 +01:00
}
add_export_preset ( preset ) ;
index + + ;
}
2017-03-05 16:44:50 +01:00
block_save = false ;
2017-02-13 02:51:16 +01:00
}
2017-03-24 00:14:12 +01:00
bool EditorExport : : poll_export_platforms ( ) {
bool changed = false ;
for ( int i = 0 ; i < export_platforms . size ( ) ; i + + ) {
2018-07-25 03:11:03 +02:00
if ( export_platforms . write [ i ] - > poll_devices ( ) ) {
2017-03-24 00:14:12 +01:00
changed = true ;
}
}
return changed ;
}
2017-02-13 02:51:16 +01:00
EditorExport : : EditorExport ( ) {
2017-03-05 16:44:50 +01:00
save_timer = memnew ( Timer ) ;
2017-02-20 03:19:30 +01:00
add_child ( save_timer ) ;
save_timer - > set_wait_time ( 0.8 ) ;
save_timer - > set_one_shot ( true ) ;
2017-03-05 16:44:50 +01:00
save_timer - > connect ( " timeout " , this , " _save " ) ;
block_save = false ;
2017-02-13 02:51:16 +01:00
2017-03-05 16:44:50 +01:00
singleton = this ;
2017-02-13 02:51:16 +01:00
}
EditorExport : : ~ EditorExport ( ) {
2017-02-20 03:19:30 +01:00
}
//////////
2017-03-05 16:44:50 +01:00
void EditorExportPlatformPC : : get_preset_features ( const Ref < EditorExportPreset > & p_preset , List < String > * r_features ) {
2017-02-20 03:19:30 +01:00
if ( p_preset - > get ( " texture_format/s3tc " ) ) {
r_features - > push_back ( " s3tc " ) ;
}
if ( p_preset - > get ( " texture_format/etc " ) ) {
r_features - > push_back ( " etc " ) ;
}
if ( p_preset - > get ( " texture_format/etc2 " ) ) {
r_features - > push_back ( " etc2 " ) ;
}
2017-10-02 21:38:39 +02:00
if ( p_preset - > get ( " binary_format/64_bits " ) ) {
r_features - > push_back ( " 64 " ) ;
} else {
r_features - > push_back ( " 32 " ) ;
}
2017-02-20 03:19:30 +01:00
}
void EditorExportPlatformPC : : get_export_options ( List < ExportOption > * r_options ) {
2018-08-22 04:56:04 +02:00
r_options - > push_back ( ExportOption ( PropertyInfo ( Variant : : BOOL , " texture_format/bptc " ) , false ) ) ;
2017-03-05 16:44:50 +01:00
r_options - > push_back ( ExportOption ( PropertyInfo ( Variant : : BOOL , " texture_format/s3tc " ) , true ) ) ;
r_options - > push_back ( ExportOption ( PropertyInfo ( Variant : : BOOL , " texture_format/etc " ) , false ) ) ;
r_options - > push_back ( ExportOption ( PropertyInfo ( Variant : : BOOL , " texture_format/etc2 " ) , false ) ) ;
2018-08-22 04:56:04 +02:00
r_options - > push_back ( ExportOption ( PropertyInfo ( Variant : : BOOL , " texture_format/no_bptc_fallbacks " ) , true ) ) ;
2017-03-05 16:44:50 +01:00
r_options - > push_back ( ExportOption ( PropertyInfo ( Variant : : BOOL , " binary_format/64_bits " ) , true ) ) ;
2019-03-25 20:56:33 +01:00
r_options - > push_back ( ExportOption ( PropertyInfo ( Variant : : BOOL , " binary_format/embed_pck " ) , false ) ) ;
2017-03-05 16:44:50 +01:00
r_options - > push_back ( ExportOption ( PropertyInfo ( Variant : : STRING , " custom_template/release " , PROPERTY_HINT_GLOBAL_FILE ) , " " ) ) ;
r_options - > push_back ( ExportOption ( PropertyInfo ( Variant : : STRING , " custom_template/debug " , PROPERTY_HINT_GLOBAL_FILE ) , " " ) ) ;
2017-02-20 03:19:30 +01:00
}
String EditorExportPlatformPC : : get_name ( ) const {
return name ;
}
2017-07-19 22:00:46 +02:00
String EditorExportPlatformPC : : get_os_name ( ) const {
return os_name ;
}
2017-03-05 16:44:50 +01:00
Ref < Texture > EditorExportPlatformPC : : get_logo ( ) const {
2017-02-20 03:19:30 +01:00
return logo ;
}
2017-03-05 16:44:50 +01:00
bool EditorExportPlatformPC : : can_export ( const Ref < EditorExportPreset > & p_preset , String & r_error , bool & r_missing_templates ) const {
2017-02-22 01:30:20 +01:00
2017-04-22 01:15:42 +02:00
String err ;
bool valid = true ;
2018-04-27 15:43:48 +02:00
bool use64 = p_preset - > get ( " binary_format/64_bits " ) ;
2017-04-22 01:15:42 +02:00
if ( use64 & & ( ! exists_export_template ( debug_file_64 , & err ) | | ! exists_export_template ( release_file_64 , & err ) ) ) {
valid = false ;
}
if ( ! use64 & & ( ! exists_export_template ( debug_file_32 , & err ) | | ! exists_export_template ( release_file_32 , & err ) ) ) {
valid = false ;
}
String custom_debug_binary = p_preset - > get ( " custom_template/debug " ) ;
String custom_release_binary = p_preset - > get ( " custom_template/release " ) ;
if ( custom_debug_binary = = " " & & custom_release_binary = = " " ) {
if ( ! err . empty ( ) )
r_error = err ;
2017-12-08 00:38:47 +01:00
r_missing_templates = ! valid ;
2017-04-22 01:15:42 +02:00
return valid ;
}
bool dvalid = true ;
bool rvalid = true ;
if ( ! FileAccess : : exists ( custom_debug_binary ) ) {
dvalid = false ;
2019-01-21 18:34:53 +01:00
err + = TTR ( " Custom debug template not found. " ) + " \n " ;
2017-04-22 01:15:42 +02:00
}
2017-02-22 01:30:20 +01:00
2017-04-22 01:15:42 +02:00
if ( ! FileAccess : : exists ( custom_release_binary ) ) {
rvalid = false ;
2019-01-21 18:34:53 +01:00
err + = TTR ( " Custom release template not found. " ) + " \n " ;
2017-02-22 01:30:20 +01:00
}
2017-03-21 03:31:41 +01:00
2019-06-26 15:08:25 +02:00
valid = dvalid | | rvalid ;
2017-04-22 01:15:42 +02:00
if ( ! err . empty ( ) )
r_error = err ;
return valid ;
2017-02-20 03:19:30 +01:00
}
2018-10-29 22:18:49 +01:00
List < String > EditorExportPlatformPC : : get_binary_extensions ( const Ref < EditorExportPreset > & p_preset ) const {
List < String > list ;
2017-12-12 22:09:48 +01:00
for ( Map < String , String > : : Element * E = extensions . front ( ) ; E ; E = E - > next ( ) ) {
if ( p_preset - > get ( E - > key ( ) ) ) {
2018-10-29 22:18:49 +01:00
list . push_back ( extensions [ E - > key ( ) ] ) ;
return list ;
2017-12-12 22:09:48 +01:00
}
}
if ( extensions . has ( " default " ) ) {
2018-10-29 22:18:49 +01:00
list . push_back ( extensions [ " default " ] ) ;
return list ;
2017-12-12 22:09:48 +01:00
}
2018-10-29 22:18:49 +01:00
return list ;
2017-02-20 03:19:30 +01:00
}
2017-03-05 16:44:50 +01:00
Error EditorExportPlatformPC : : export_project ( const Ref < EditorExportPreset > & p_preset , bool p_debug , const String & p_path , int p_flags ) {
2017-10-02 17:01:43 +02:00
ExportNotifier notifier ( * this , p_preset , p_debug , p_path , p_flags ) ;
2017-02-20 03:19:30 +01:00
2019-03-06 13:20:18 +01:00
if ( ! DirAccess : : exists ( p_path . get_base_dir ( ) ) ) {
2019-03-05 08:52:45 +01:00
return ERR_FILE_BAD_PATH ;
}
2017-03-21 23:34:26 +01:00
String custom_debug = p_preset - > get ( " custom_template/debug " ) ;
String custom_release = p_preset - > get ( " custom_template/release " ) ;
String template_path = p_debug ? custom_debug : custom_release ;
template_path = template_path . strip_edges ( ) ;
if ( template_path = = String ( ) ) {
if ( p_preset - > get ( " binary_format/64_bits " ) ) {
if ( p_debug ) {
template_path = find_export_template ( debug_file_64 ) ;
} else {
template_path = find_export_template ( release_file_64 ) ;
}
} else {
if ( p_debug ) {
template_path = find_export_template ( debug_file_32 ) ;
} else {
template_path = find_export_template ( release_file_32 ) ;
}
}
}
if ( template_path ! = String ( ) & & ! FileAccess : : exists ( template_path ) ) {
2018-01-04 20:00:39 +01:00
EditorNode : : get_singleton ( ) - > show_warning ( TTR ( " Template file not found: " ) + " \n " + template_path ) ;
2017-03-21 23:34:26 +01:00
return ERR_FILE_NOT_FOUND ;
}
DirAccess * da = DirAccess : : create ( DirAccess : : ACCESS_FILESYSTEM ) ;
2017-09-17 19:40:58 +02:00
Error err = da - > copy ( template_path , p_path , get_chmod_flags ( ) ) ;
2019-03-25 20:56:33 +01:00
memdelete ( da ) ;
2018-03-06 16:13:18 +01:00
if ( err = = OK ) {
2019-03-25 20:56:33 +01:00
String pck_path ;
if ( p_preset - > get ( " binary_format/embed_pck " ) ) {
pck_path = p_path ;
} else {
pck_path = p_path . get_basename ( ) + " .pck " ;
}
2017-03-21 23:34:26 +01:00
2018-03-06 16:13:18 +01:00
Vector < SharedObject > so_files ;
2018-01-04 19:42:29 +01:00
2019-03-25 20:56:33 +01:00
int64_t embedded_pos ;
int64_t embedded_size ;
err = save_pack ( p_preset , pck_path , & so_files , p_preset - > get ( " binary_format/embed_pck " ) , & embedded_pos , & embedded_size ) ;
if ( err = = OK & & p_preset - > get ( " binary_format/embed_pck " ) ) {
if ( embedded_size > = 0x100000000 & & ! p_preset - > get ( " binary_format/64_bits " ) ) {
EditorNode : : get_singleton ( ) - > show_warning ( TTR ( " On 32-bit exports the embedded PCK cannot be bigger than 4 GiB. " ) ) ;
return ERR_UNAVAILABLE ;
}
FixUpEmbeddedPckFunc fixup_func = get_fixup_embedded_pck_func ( ) ;
if ( fixup_func ) {
err = fixup_func ( p_path , embedded_pos , embedded_size ) ;
}
}
2018-01-04 19:42:29 +01:00
2018-03-06 16:13:18 +01:00
if ( err = = OK & & ! so_files . empty ( ) ) {
//if shared object files, copy them
da = DirAccess : : create ( DirAccess : : ACCESS_FILESYSTEM ) ;
for ( int i = 0 ; i < so_files . size ( ) & & err = = OK ; i + + ) {
err = da - > copy ( so_files [ i ] . path , p_path . get_base_dir ( ) . plus_file ( so_files [ i ] . path . get_file ( ) ) ) ;
}
2019-03-25 20:56:33 +01:00
memdelete ( da ) ;
2018-03-06 16:13:18 +01:00
}
2018-01-04 19:42:29 +01:00
}
2018-03-06 16:13:18 +01:00
return err ;
2017-02-20 03:19:30 +01:00
}
2017-12-12 22:09:48 +01:00
void EditorExportPlatformPC : : set_extension ( const String & p_extension , const String & p_feature_key ) {
extensions [ p_feature_key ] = p_extension ;
2017-02-20 03:19:30 +01:00
}
2017-03-05 16:44:50 +01:00
void EditorExportPlatformPC : : set_name ( const String & p_name ) {
name = p_name ;
2017-02-20 03:19:30 +01:00
}
2017-07-19 22:00:46 +02:00
void EditorExportPlatformPC : : set_os_name ( const String & p_name ) {
os_name = p_name ;
}
2017-03-05 16:44:50 +01:00
void EditorExportPlatformPC : : set_logo ( const Ref < Texture > & p_logo ) {
logo = p_logo ;
2017-02-20 03:19:30 +01:00
}
2017-03-05 16:44:50 +01:00
void EditorExportPlatformPC : : set_release_64 ( const String & p_file ) {
2017-02-22 01:30:20 +01:00
2017-03-05 16:44:50 +01:00
release_file_64 = p_file ;
2017-02-22 01:30:20 +01:00
}
2017-03-05 16:44:50 +01:00
void EditorExportPlatformPC : : set_release_32 ( const String & p_file ) {
2017-02-22 01:30:20 +01:00
2017-03-05 16:44:50 +01:00
release_file_32 = p_file ;
2017-02-22 01:30:20 +01:00
}
2017-03-05 16:44:50 +01:00
void EditorExportPlatformPC : : set_debug_64 ( const String & p_file ) {
2017-02-22 01:30:20 +01:00
2017-03-05 16:44:50 +01:00
debug_file_64 = p_file ;
2017-02-22 01:30:20 +01:00
}
2017-03-05 16:44:50 +01:00
void EditorExportPlatformPC : : set_debug_32 ( const String & p_file ) {
2017-02-22 01:30:20 +01:00
2017-03-05 16:44:50 +01:00
debug_file_32 = p_file ;
2017-02-22 01:30:20 +01:00
}
2017-07-19 22:00:46 +02:00
void EditorExportPlatformPC : : add_platform_feature ( const String & p_feature ) {
extra_features . insert ( p_feature ) ;
}
void EditorExportPlatformPC : : get_platform_features ( List < String > * r_features ) {
r_features - > push_back ( " pc " ) ; //all pcs support "pc"
r_features - > push_back ( " s3tc " ) ; //all pcs support "s3tc" compression
r_features - > push_back ( get_os_name ( ) ) ; //OS name is a feature
for ( Set < String > : : Element * E = extra_features . front ( ) ; E ; E = E - > next ( ) ) {
r_features - > push_back ( E - > get ( ) ) ;
}
}
2018-08-22 04:56:04 +02:00
void EditorExportPlatformPC : : resolve_platform_feature_priorities ( const Ref < EditorExportPreset > & p_preset , Set < String > & p_features ) {
if ( p_features . has ( " bptc " ) ) {
if ( p_preset - > has ( " texture_format/no_bptc_fallbacks " ) ) {
p_features . erase ( " s3tc " ) ;
}
}
}
2017-09-17 19:40:58 +02:00
int EditorExportPlatformPC : : get_chmod_flags ( ) const {
return chmod_flags ;
}
void EditorExportPlatformPC : : set_chmod_flags ( int p_flags ) {
chmod_flags = p_flags ;
}
2019-03-25 20:56:33 +01:00
EditorExportPlatformPC : : FixUpEmbeddedPckFunc EditorExportPlatformPC : : get_fixup_embedded_pck_func ( ) const {
return fixup_embedded_pck_func ;
}
void EditorExportPlatformPC : : set_fixup_embedded_pck_func ( FixUpEmbeddedPckFunc p_fixup_embedded_pck_func ) {
fixup_embedded_pck_func = p_fixup_embedded_pck_func ;
}
2017-02-20 03:19:30 +01:00
EditorExportPlatformPC : : EditorExportPlatformPC ( ) {
2017-09-17 19:40:58 +02:00
chmod_flags = - 1 ;
2019-03-25 20:56:33 +01:00
fixup_embedded_pck_func = NULL ;
2017-02-13 02:51:16 +01:00
}
2017-12-15 12:38:24 +01:00
///////////////////////
void EditorExportTextSceneToBinaryPlugin : : _export_file ( const String & p_path , const String & p_type , const Set < String > & p_features ) {
String extension = p_path . get_extension ( ) . to_lower ( ) ;
if ( extension ! = " tres " & & extension ! = " tscn " ) {
return ;
}
bool convert = GLOBAL_GET ( " editor/convert_text_resources_to_binary_on_export " ) ;
if ( ! convert )
return ;
2019-08-09 13:45:30 +02:00
String tmp_path = EditorSettings : : get_singleton ( ) - > get_cache_dir ( ) . plus_file ( " tmpfile.res " ) ;
2017-12-15 12:38:24 +01:00
Error err = ResourceFormatLoaderText : : convert_file_to_binary ( p_path , tmp_path ) ;
2019-08-09 13:45:30 +02:00
if ( err ! = OK ) {
DirAccess : : remove_file_or_error ( tmp_path ) ;
ERR_FAIL ( ) ;
}
2017-12-15 12:38:24 +01:00
Vector < uint8_t > data = FileAccess : : get_file_as_array ( tmp_path ) ;
2019-08-09 13:45:30 +02:00
if ( data . size ( ) = = 0 ) {
DirAccess : : remove_file_or_error ( tmp_path ) ;
ERR_FAIL ( ) ;
}
DirAccess : : remove_file_or_error ( tmp_path ) ;
2017-12-15 12:38:24 +01:00
add_file ( p_path + " .converted.res " , data , true ) ;
}
EditorExportTextSceneToBinaryPlugin : : EditorExportTextSceneToBinaryPlugin ( ) {
GLOBAL_DEF ( " editor/convert_text_resources_to_binary_on_export " , false ) ;
}