mirror of
https://github.com/godotengine/godot.git
synced 2024-11-21 19:42:43 +00:00
Add ability to export patch packs
Co-authored-by: Poq Xert <poqxert@poqxert.ru>
This commit is contained in:
parent
4254946de9
commit
d3be030ea6
@ -102,6 +102,22 @@ void PackedData::add_pack_source(PackSource *p_source) {
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t *PackedData::get_file_hash(const String &p_path) {
|
||||
PathMD5 pmd5(p_path.md5_buffer());
|
||||
HashMap<PathMD5, PackedFile, PathMD5>::Iterator E = files.find(pmd5);
|
||||
if (!E || E->value.offset == 0) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return E->value.md5;
|
||||
}
|
||||
|
||||
void PackedData::clear() {
|
||||
files.clear();
|
||||
_free_packed_dirs(root);
|
||||
root = memnew(PackedDir);
|
||||
}
|
||||
|
||||
PackedData *PackedData::singleton = nullptr;
|
||||
|
||||
PackedData::PackedData() {
|
||||
|
@ -111,6 +111,7 @@ private:
|
||||
public:
|
||||
void add_pack_source(PackSource *p_source);
|
||||
void add_path(const String &p_pkg_path, const String &p_path, uint64_t p_ofs, uint64_t p_size, const uint8_t *p_md5, PackSource *p_src, bool p_replace_files, bool p_encrypted = false); // for PackSource
|
||||
uint8_t *get_file_hash(const String &p_path);
|
||||
|
||||
void set_disabled(bool p_disabled) { disabled = p_disabled; }
|
||||
_FORCE_INLINE_ bool is_disabled() const { return disabled; }
|
||||
@ -118,6 +119,8 @@ public:
|
||||
static PackedData *get_singleton() { return singleton; }
|
||||
Error add_pack(const String &p_path, bool p_replace_files, uint64_t p_offset);
|
||||
|
||||
void clear();
|
||||
|
||||
_FORCE_INLINE_ Ref<FileAccess> try_open_path(const String &p_path);
|
||||
_FORCE_INLINE_ bool has_path(const String &p_path);
|
||||
|
||||
|
@ -42,6 +42,18 @@
|
||||
Creates a PCK archive at [param path] for the specified [param preset].
|
||||
</description>
|
||||
</method>
|
||||
<method name="export_pack_patch">
|
||||
<return type="int" enum="Error" />
|
||||
<param index="0" name="preset" type="EditorExportPreset" />
|
||||
<param index="1" name="debug" type="bool" />
|
||||
<param index="2" name="path" type="String" />
|
||||
<param index="3" name="patches" type="PackedStringArray" default="PackedStringArray()" />
|
||||
<param index="4" name="flags" type="int" enum="EditorExportPlatform.DebugFlags" is_bitfield="true" default="0" />
|
||||
<description>
|
||||
Creates a patch PCK archive at [param path] for the specified [param preset], containing only the files that have changed since the last patch.
|
||||
[b]Note:[/b] [param patches] is an optional override of the set of patches defined in the export preset. When empty the patches defined in the export preset will be used instead.
|
||||
</description>
|
||||
</method>
|
||||
<method name="export_project">
|
||||
<return type="int" enum="Error" />
|
||||
<param index="0" name="preset" type="EditorExportPreset" />
|
||||
@ -75,6 +87,18 @@
|
||||
Create a ZIP archive at [param path] for the specified [param preset].
|
||||
</description>
|
||||
</method>
|
||||
<method name="export_zip_patch">
|
||||
<return type="int" enum="Error" />
|
||||
<param index="0" name="preset" type="EditorExportPreset" />
|
||||
<param index="1" name="debug" type="bool" />
|
||||
<param index="2" name="path" type="String" />
|
||||
<param index="3" name="patches" type="PackedStringArray" default="PackedStringArray()" />
|
||||
<param index="4" name="flags" type="int" enum="EditorExportPlatform.DebugFlags" is_bitfield="true" default="0" />
|
||||
<description>
|
||||
Create a patch ZIP archive at [param path] for the specified [param preset], containing only the files that have changed since the last patch.
|
||||
[b]Note:[/b] [param patches] is an optional override of the set of patches defined in the export preset. When empty the patches defined in the export preset will be used instead.
|
||||
</description>
|
||||
</method>
|
||||
<method name="find_export_template" qualifiers="const">
|
||||
<return type="Dictionary" />
|
||||
<param index="0" name="template_file_name" type="String" />
|
||||
@ -151,6 +175,15 @@
|
||||
If [param embed] is [code]true[/code], PCK content is appended to the end of [param path] file and return [Dictionary] additionally include following keys: [code]embedded_start: int[/code] (embedded PCK offset) and [code]embedded_size: int[/code] (embedded PCK size).
|
||||
</description>
|
||||
</method>
|
||||
<method name="save_pack_patch">
|
||||
<return type="Dictionary" />
|
||||
<param index="0" name="preset" type="EditorExportPreset" />
|
||||
<param index="1" name="debug" type="bool" />
|
||||
<param index="2" name="path" type="String" />
|
||||
<description>
|
||||
Saves patch PCK archive and returns [Dictionary] with the following keys: [code]result: Error[/code], [code]so_files: Array[/code] (array of the shared/static objects which contains dictionaries with the following keys: [code]path: String[/code], [code]tags: PackedStringArray[/code], and [code]target_folder: String[/code]).
|
||||
</description>
|
||||
</method>
|
||||
<method name="save_zip">
|
||||
<return type="Dictionary" />
|
||||
<param index="0" name="preset" type="EditorExportPreset" />
|
||||
@ -160,6 +193,15 @@
|
||||
Saves ZIP archive and returns [Dictionary] with the following keys: [code]result: Error[/code], [code]so_files: Array[/code] (array of the shared/static objects which contains dictionaries with the following keys: [code]path: String[/code], [code]tags: PackedStringArray[/code], and [code]target_folder: String[/code]).
|
||||
</description>
|
||||
</method>
|
||||
<method name="save_zip_patch">
|
||||
<return type="Dictionary" />
|
||||
<param index="0" name="preset" type="EditorExportPreset" />
|
||||
<param index="1" name="debug" type="bool" />
|
||||
<param index="2" name="path" type="String" />
|
||||
<description>
|
||||
Saves patch ZIP archive and returns [Dictionary] with the following keys: [code]result: Error[/code], [code]so_files: Array[/code] (array of the shared/static objects which contains dictionaries with the following keys: [code]path: String[/code], [code]tags: PackedStringArray[/code], and [code]target_folder: String[/code]).
|
||||
</description>
|
||||
</method>
|
||||
<method name="ssh_push_to_remote" qualifiers="const">
|
||||
<return type="int" enum="Error" />
|
||||
<param index="0" name="host" type="String" />
|
||||
|
@ -36,7 +36,21 @@
|
||||
<description>
|
||||
[b]Optional.[/b]
|
||||
Creates a PCK archive at [param path] for the specified [param preset].
|
||||
This method is called when "Export PCK/ZIP" button is pressed in the export dialog, and PCK is selected as a file type.
|
||||
This method is called when "Export PCK/ZIP" button is pressed in the export dialog, with "Export as Patch" disabled, and PCK is selected as a file type.
|
||||
</description>
|
||||
</method>
|
||||
<method name="_export_pack_patch" qualifiers="virtual">
|
||||
<return type="int" enum="Error" />
|
||||
<param index="0" name="preset" type="EditorExportPreset" />
|
||||
<param index="1" name="debug" type="bool" />
|
||||
<param index="2" name="path" type="String" />
|
||||
<param index="3" name="patches" type="PackedStringArray" />
|
||||
<param index="4" name="flags" type="int" enum="EditorExportPlatform.DebugFlags" is_bitfield="true" />
|
||||
<description>
|
||||
[b]Optional.[/b]
|
||||
Creates a patch PCK archive at [param path] for the specified [param preset], containing only the files that have changed since the last patch.
|
||||
This method is called when "Export PCK/ZIP" button is pressed in the export dialog, with "Export as Patch" enabled, and PCK is selected as a file type.
|
||||
[b]Note:[/b] The patches provided in [param patches] have already been loaded when this method is called and are merely provided as context. When empty the patches defined in the export preset have been loaded instead.
|
||||
</description>
|
||||
</method>
|
||||
<method name="_export_project" qualifiers="virtual">
|
||||
@ -61,7 +75,21 @@
|
||||
<description>
|
||||
[b]Optional.[/b]
|
||||
Create a ZIP archive at [param path] for the specified [param preset].
|
||||
This method is called when "Export PCK/ZIP" button is pressed in the export dialog, and ZIP is selected as a file type.
|
||||
This method is called when "Export PCK/ZIP" button is pressed in the export dialog, with "Export as Patch" disabled, and ZIP is selected as a file type.
|
||||
</description>
|
||||
</method>
|
||||
<method name="_export_zip_patch" qualifiers="virtual">
|
||||
<return type="int" enum="Error" />
|
||||
<param index="0" name="preset" type="EditorExportPreset" />
|
||||
<param index="1" name="debug" type="bool" />
|
||||
<param index="2" name="path" type="String" />
|
||||
<param index="3" name="patches" type="PackedStringArray" />
|
||||
<param index="4" name="flags" type="int" enum="EditorExportPlatform.DebugFlags" is_bitfield="true" />
|
||||
<description>
|
||||
[b]Optional.[/b]
|
||||
Create a ZIP archive at [param path] for the specified [param preset], containing only the files that have changed since the last patch.
|
||||
This method is called when "Export PCK/ZIP" button is pressed in the export dialog, with "Export as Patch" enabled, and ZIP is selected as a file type.
|
||||
[b]Note:[/b] The patches provided in [param patches] have already been loaded when this method is called and are merely provided as context. When empty the patches defined in the export preset have been loaded instead.
|
||||
</description>
|
||||
</method>
|
||||
<method name="_get_binary_extensions" qualifiers="virtual const">
|
||||
|
@ -109,6 +109,12 @@
|
||||
Returns export option value or value of environment variable if it is set.
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_patches" qualifiers="const">
|
||||
<return type="PackedStringArray" />
|
||||
<description>
|
||||
Returns the list of packs on which to base a patch export on.
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_preset_name" qualifiers="const">
|
||||
<return type="String" />
|
||||
<description>
|
||||
|
@ -1007,9 +1007,17 @@ void EditorNode::_fs_changed() {
|
||||
export_preset->update_value_overrides();
|
||||
if (export_defer.pack_only) { // Only export .pck or .zip data pack.
|
||||
if (export_path.ends_with(".zip")) {
|
||||
err = platform->export_zip(export_preset, export_defer.debug, export_path);
|
||||
if (export_defer.patch) {
|
||||
err = platform->export_zip_patch(export_preset, export_defer.debug, export_path, export_defer.patches);
|
||||
} else {
|
||||
err = platform->export_zip(export_preset, export_defer.debug, export_path);
|
||||
}
|
||||
} else if (export_path.ends_with(".pck")) {
|
||||
err = platform->export_pack(export_preset, export_defer.debug, export_path);
|
||||
if (export_defer.patch) {
|
||||
err = platform->export_pack_patch(export_preset, export_defer.debug, export_path, export_defer.patches);
|
||||
} else {
|
||||
err = platform->export_pack(export_preset, export_defer.debug, export_path);
|
||||
}
|
||||
} else {
|
||||
ERR_PRINT(vformat("Export path \"%s\" doesn't end with a supported extension.", export_path));
|
||||
err = FAILED;
|
||||
@ -5147,12 +5155,14 @@ void EditorNode::_begin_first_scan() {
|
||||
requested_first_scan = true;
|
||||
}
|
||||
|
||||
Error EditorNode::export_preset(const String &p_preset, const String &p_path, bool p_debug, bool p_pack_only, bool p_android_build_template) {
|
||||
Error EditorNode::export_preset(const String &p_preset, const String &p_path, bool p_debug, bool p_pack_only, bool p_android_build_template, bool p_patch, const Vector<String> &p_patches) {
|
||||
export_defer.preset = p_preset;
|
||||
export_defer.path = p_path;
|
||||
export_defer.debug = p_debug;
|
||||
export_defer.pack_only = p_pack_only;
|
||||
export_defer.android_build_template = p_android_build_template;
|
||||
export_defer.patch = p_patch;
|
||||
export_defer.patches = p_patches;
|
||||
cmdline_export_mode = true;
|
||||
return OK;
|
||||
}
|
||||
|
@ -246,6 +246,8 @@ private:
|
||||
bool debug = false;
|
||||
bool pack_only = false;
|
||||
bool android_build_template = false;
|
||||
bool patch = false;
|
||||
Vector<String> patches;
|
||||
} export_defer;
|
||||
|
||||
static EditorNode *singleton;
|
||||
@ -879,7 +881,7 @@ public:
|
||||
|
||||
void _copy_warning(const String &p_str);
|
||||
|
||||
Error export_preset(const String &p_preset, const String &p_path, bool p_debug, bool p_pack_only, bool p_android_build_template);
|
||||
Error export_preset(const String &p_preset, const String &p_path, bool p_debug, bool p_pack_only, bool p_android_build_template, bool p_patch, const Vector<String> &p_patches);
|
||||
bool is_project_exporting() const;
|
||||
|
||||
Control *get_gui_base() { return gui_base; }
|
||||
|
@ -83,6 +83,8 @@ void EditorExport::_save() {
|
||||
config->set_value(section, "include_filter", preset->get_include_filter());
|
||||
config->set_value(section, "exclude_filter", preset->get_exclude_filter());
|
||||
config->set_value(section, "export_path", preset->get_export_path());
|
||||
config->set_value(section, "patches", preset->get_patches());
|
||||
|
||||
config->set_value(section, "encryption_include_filters", preset->get_enc_in_filter());
|
||||
config->set_value(section, "encryption_exclude_filters", preset->get_enc_ex_filter());
|
||||
config->set_value(section, "encrypt_pck", preset->get_enc_pck());
|
||||
@ -303,6 +305,7 @@ void EditorExport::load_config() {
|
||||
preset->set_exclude_filter(config->get_value(section, "exclude_filter"));
|
||||
preset->set_export_path(config->get_value(section, "export_path", ""));
|
||||
preset->set_script_export_mode(config->get_value(section, "script_export_mode", EditorExportPreset::MODE_SCRIPT_BINARY_TOKENS_COMPRESSED));
|
||||
preset->set_patches(config->get_value(section, "patches", Vector<String>()));
|
||||
|
||||
if (config->has_section_key(section, "encrypt_pck")) {
|
||||
preset->set_enc_pck(config->get_value(section, "encrypt_pck"));
|
||||
|
@ -167,6 +167,44 @@ bool EditorExportPlatform::fill_log_messages(RichTextLabel *p_log, Error p_err)
|
||||
return has_messages;
|
||||
}
|
||||
|
||||
bool EditorExportPlatform::_check_hash(const uint8_t *p_hash, const Vector<uint8_t> &p_data) {
|
||||
if (p_hash == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned char hash[16];
|
||||
Error err = CryptoCore::md5(p_data.ptr(), p_data.size(), hash);
|
||||
if (err != OK) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 16; i++) {
|
||||
if (p_hash[i] != hash[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Error EditorExportPlatform::_load_patches(const Vector<String> &p_patches) {
|
||||
Error err = OK;
|
||||
if (!p_patches.is_empty()) {
|
||||
for (const String &path : p_patches) {
|
||||
err = PackedData::get_singleton()->add_pack(path, true, 0);
|
||||
if (err != OK) {
|
||||
add_message(EXPORT_MESSAGE_ERROR, TTR("Patch Creation"), vformat(TTR("Could not load patch pack with path \"%s\"."), path));
|
||||
return err;
|
||||
}
|
||||
}
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
void EditorExportPlatform::_unload_patches() {
|
||||
PackedData::get_singleton()->clear();
|
||||
}
|
||||
|
||||
Error EditorExportPlatform::_save_pack_file(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &p_key) {
|
||||
ERR_FAIL_COND_V_MSG(p_total < 1, ERR_PARAMETER_RANGE_ERROR, "Must select at least one file to export.");
|
||||
|
||||
@ -237,6 +275,14 @@ Error EditorExportPlatform::_save_pack_file(void *p_userdata, const String &p_pa
|
||||
return OK;
|
||||
}
|
||||
|
||||
Error EditorExportPlatform::_save_pack_patch_file(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &p_key) {
|
||||
if (_check_hash(PackedData::get_singleton()->get_file_hash(p_path), p_data)) {
|
||||
return OK;
|
||||
}
|
||||
|
||||
return _save_pack_file(p_userdata, p_path, p_data, p_file, p_total, p_enc_in_filters, p_enc_ex_filters, p_key);
|
||||
}
|
||||
|
||||
Error EditorExportPlatform::_save_zip_file(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &p_key) {
|
||||
ERR_FAIL_COND_V_MSG(p_total < 1, ERR_PARAMETER_RANGE_ERROR, "Must select at least one file to export.");
|
||||
|
||||
@ -260,6 +306,8 @@ Error EditorExportPlatform::_save_zip_file(void *p_userdata, const String &p_pat
|
||||
zipWriteInFileInZip(zip, p_data.ptr(), p_data.size());
|
||||
zipCloseFileInZip(zip);
|
||||
|
||||
zd->file_count += 1;
|
||||
|
||||
if (zd->ep->step(TTR("Storing File:") + " " + p_path, 2 + p_file * 100 / p_total, false)) {
|
||||
return ERR_SKIP;
|
||||
}
|
||||
@ -267,6 +315,14 @@ Error EditorExportPlatform::_save_zip_file(void *p_userdata, const String &p_pat
|
||||
return OK;
|
||||
}
|
||||
|
||||
Error EditorExportPlatform::_save_zip_patch_file(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &p_key) {
|
||||
if (_check_hash(PackedData::get_singleton()->get_file_hash(p_path), p_data)) {
|
||||
return OK;
|
||||
}
|
||||
|
||||
return _save_zip_file(p_userdata, p_path, p_data, p_file, p_total, p_enc_in_filters, p_enc_ex_filters, p_key);
|
||||
}
|
||||
|
||||
Ref<ImageTexture> EditorExportPlatform::get_option_icon(int p_index) const {
|
||||
Ref<Theme> theme = EditorNode::get_singleton()->get_editor_theme();
|
||||
ERR_FAIL_COND_V(theme.is_null(), Ref<ImageTexture>());
|
||||
@ -1561,7 +1617,7 @@ Dictionary EditorExportPlatform::_save_pack(const Ref<EditorExportPreset> &p_pre
|
||||
Vector<SharedObject> so_files;
|
||||
int64_t embedded_start = 0;
|
||||
int64_t embedded_size = 0;
|
||||
Error err_code = save_pack(p_preset, p_debug, p_path, &so_files, p_embed, &embedded_start, &embedded_size);
|
||||
Error err_code = save_pack(p_preset, p_debug, p_path, &so_files, nullptr, p_embed, &embedded_start, &embedded_size);
|
||||
|
||||
Dictionary ret;
|
||||
ret["result"] = err_code;
|
||||
@ -1605,9 +1661,55 @@ Dictionary EditorExportPlatform::_save_zip(const Ref<EditorExportPreset> &p_pres
|
||||
return ret;
|
||||
}
|
||||
|
||||
Error EditorExportPlatform::save_pack(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, Vector<SharedObject> *p_so_files, bool p_embed, int64_t *r_embedded_start, int64_t *r_embedded_size) {
|
||||
Dictionary EditorExportPlatform::_save_pack_patch(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path) {
|
||||
Vector<SharedObject> so_files;
|
||||
Error err_code = save_pack_patch(p_preset, p_debug, p_path, &so_files);
|
||||
|
||||
Dictionary ret;
|
||||
ret["result"] = err_code;
|
||||
if (err_code == OK) {
|
||||
Array arr;
|
||||
for (const SharedObject &E : so_files) {
|
||||
Dictionary so;
|
||||
so["path"] = E.path;
|
||||
so["tags"] = E.tags;
|
||||
so["target_folder"] = E.target;
|
||||
arr.push_back(so);
|
||||
}
|
||||
ret["so_files"] = arr;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
Dictionary EditorExportPlatform::_save_zip_patch(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path) {
|
||||
Vector<SharedObject> so_files;
|
||||
Error err_code = save_zip_patch(p_preset, p_debug, p_path, &so_files);
|
||||
|
||||
Dictionary ret;
|
||||
ret["result"] = err_code;
|
||||
if (err_code == OK) {
|
||||
Array arr;
|
||||
for (const SharedObject &E : so_files) {
|
||||
Dictionary so;
|
||||
so["path"] = E.path;
|
||||
so["tags"] = E.tags;
|
||||
so["target_folder"] = E.target;
|
||||
arr.push_back(so);
|
||||
}
|
||||
ret["so_files"] = arr;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
Error EditorExportPlatform::save_pack(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, Vector<SharedObject> *p_so_files, EditorExportSaveFunction p_save_func, bool p_embed, int64_t *r_embedded_start, int64_t *r_embedded_size) {
|
||||
EditorProgress ep("savepack", TTR("Packing"), 102, true);
|
||||
|
||||
if (p_save_func == nullptr) {
|
||||
p_save_func = _save_pack_file;
|
||||
}
|
||||
|
||||
// Create the temporary export directory if it doesn't exist.
|
||||
Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
|
||||
da->make_dir_recursive(EditorPaths::get_singleton()->get_cache_dir());
|
||||
@ -1624,7 +1726,7 @@ Error EditorExportPlatform::save_pack(const Ref<EditorExportPreset> &p_preset, b
|
||||
pd.f = ftmp;
|
||||
pd.so_files = p_so_files;
|
||||
|
||||
Error err = export_project_files(p_preset, p_debug, _save_pack_file, &pd, _pack_add_shared_object);
|
||||
Error err = export_project_files(p_preset, p_debug, p_save_func, &pd, _pack_add_shared_object);
|
||||
|
||||
// Close temp file.
|
||||
pd.f.unref();
|
||||
@ -1636,6 +1738,12 @@ Error EditorExportPlatform::save_pack(const Ref<EditorExportPreset> &p_preset, b
|
||||
return err;
|
||||
}
|
||||
|
||||
if (pd.file_ofs.is_empty()) {
|
||||
DirAccess::remove_file_or_error(tmppath);
|
||||
add_message(EXPORT_MESSAGE_ERROR, TTR("Save PCK"), TTR("No files or changes to export."));
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
pd.file_ofs.sort(); //do sort, so we can do binary search later
|
||||
|
||||
Ref<FileAccess> f;
|
||||
@ -1831,28 +1939,56 @@ Error EditorExportPlatform::save_pack(const Ref<EditorExportPreset> &p_preset, b
|
||||
return OK;
|
||||
}
|
||||
|
||||
Error EditorExportPlatform::save_zip(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, Vector<SharedObject> *p_so_files) {
|
||||
Error EditorExportPlatform::save_pack_patch(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, Vector<SharedObject> *p_so_files, bool p_embed, int64_t *r_embedded_start, int64_t *r_embedded_size) {
|
||||
return save_pack(p_preset, p_debug, p_path, p_so_files, _save_pack_patch_file, p_embed, r_embedded_start, r_embedded_size);
|
||||
}
|
||||
|
||||
Error EditorExportPlatform::save_zip(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, Vector<SharedObject> *p_so_files, EditorExportSaveFunction p_save_func) {
|
||||
EditorProgress ep("savezip", TTR("Packing"), 102, true);
|
||||
|
||||
if (p_save_func == nullptr) {
|
||||
p_save_func = _save_zip_file;
|
||||
}
|
||||
|
||||
String tmppath = EditorPaths::get_singleton()->get_cache_dir().path_join("packtmp");
|
||||
|
||||
Ref<FileAccess> io_fa;
|
||||
zlib_filefunc_def io = zipio_create_io(&io_fa);
|
||||
zipFile zip = zipOpen2(p_path.utf8().get_data(), APPEND_STATUS_CREATE, nullptr, &io);
|
||||
zipFile zip = zipOpen2(tmppath.utf8().get_data(), APPEND_STATUS_CREATE, nullptr, &io);
|
||||
|
||||
ZipData zd;
|
||||
zd.ep = &ep;
|
||||
zd.zip = zip;
|
||||
zd.so_files = p_so_files;
|
||||
|
||||
Error err = export_project_files(p_preset, p_debug, _save_zip_file, &zd, _zip_add_shared_object);
|
||||
Error err = export_project_files(p_preset, p_debug, p_save_func, &zd, _zip_add_shared_object);
|
||||
if (err != OK && err != ERR_SKIP) {
|
||||
add_message(EXPORT_MESSAGE_ERROR, TTR("Save ZIP"), TTR("Failed to export project files."));
|
||||
}
|
||||
|
||||
zipClose(zip, nullptr);
|
||||
|
||||
Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
|
||||
|
||||
if (zd.file_count == 0) {
|
||||
da->remove(tmppath);
|
||||
add_message(EXPORT_MESSAGE_ERROR, TTR("Save PCK"), TTR("No files or changes to export."));
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
err = da->rename(tmppath, p_path);
|
||||
if (err != OK) {
|
||||
da->remove(tmppath);
|
||||
add_message(EXPORT_MESSAGE_ERROR, TTR("Save ZIP"), vformat(TTR("Failed to move temporary file \"%s\" to \"%s\"."), tmppath, p_path));
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
Error EditorExportPlatform::save_zip_patch(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, Vector<SharedObject> *p_so_files) {
|
||||
return save_zip(p_preset, p_debug, p_path, p_so_files, _save_zip_patch_file);
|
||||
}
|
||||
|
||||
Error EditorExportPlatform::export_pack(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, BitField<EditorExportPlatform::DebugFlags> p_flags) {
|
||||
ExportNotifier notifier(*this, p_preset, p_debug, p_path, p_flags);
|
||||
return save_pack(p_preset, p_debug, p_path);
|
||||
@ -1863,6 +1999,28 @@ Error EditorExportPlatform::export_zip(const Ref<EditorExportPreset> &p_preset,
|
||||
return save_zip(p_preset, p_debug, p_path);
|
||||
}
|
||||
|
||||
Error EditorExportPlatform::export_pack_patch(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, const Vector<String> &p_patches, BitField<EditorExportPlatform::DebugFlags> p_flags) {
|
||||
ExportNotifier notifier(*this, p_preset, p_debug, p_path, p_flags);
|
||||
Error err = _load_patches(p_patches.is_empty() ? p_preset->get_patches() : p_patches);
|
||||
if (err != OK) {
|
||||
return err;
|
||||
}
|
||||
err = save_pack_patch(p_preset, p_debug, p_path);
|
||||
_unload_patches();
|
||||
return err;
|
||||
}
|
||||
|
||||
Error EditorExportPlatform::export_zip_patch(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, const Vector<String> &p_patches, BitField<EditorExportPlatform::DebugFlags> p_flags) {
|
||||
ExportNotifier notifier(*this, p_preset, p_debug, p_path, p_flags);
|
||||
Error err = _load_patches(p_patches.is_empty() ? p_preset->get_patches() : p_patches);
|
||||
if (err != OK) {
|
||||
return err;
|
||||
}
|
||||
err = save_zip_patch(p_preset, p_debug, p_path);
|
||||
_unload_patches();
|
||||
return err;
|
||||
}
|
||||
|
||||
Vector<String> EditorExportPlatform::gen_export_flags(BitField<EditorExportPlatform::DebugFlags> p_flags) {
|
||||
Vector<String> ret;
|
||||
String host = EDITOR_GET("network/debug/remote_host");
|
||||
@ -2115,6 +2273,8 @@ void EditorExportPlatform::_bind_methods() {
|
||||
|
||||
ClassDB::bind_method(D_METHOD("save_pack", "preset", "debug", "path", "embed"), &EditorExportPlatform::_save_pack, DEFVAL(false));
|
||||
ClassDB::bind_method(D_METHOD("save_zip", "preset", "debug", "path"), &EditorExportPlatform::_save_zip);
|
||||
ClassDB::bind_method(D_METHOD("save_pack_patch", "preset", "debug", "path"), &EditorExportPlatform::_save_pack_patch);
|
||||
ClassDB::bind_method(D_METHOD("save_zip_patch", "preset", "debug", "path"), &EditorExportPlatform::_save_zip_patch);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("gen_export_flags", "flags"), &EditorExportPlatform::gen_export_flags);
|
||||
|
||||
@ -2123,6 +2283,8 @@ void EditorExportPlatform::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("export_project", "preset", "debug", "path", "flags"), &EditorExportPlatform::export_project, DEFVAL(0));
|
||||
ClassDB::bind_method(D_METHOD("export_pack", "preset", "debug", "path", "flags"), &EditorExportPlatform::export_pack, DEFVAL(0));
|
||||
ClassDB::bind_method(D_METHOD("export_zip", "preset", "debug", "path", "flags"), &EditorExportPlatform::export_zip, DEFVAL(0));
|
||||
ClassDB::bind_method(D_METHOD("export_pack_patch", "preset", "debug", "path", "patches", "flags"), &EditorExportPlatform::export_pack_patch, DEFVAL(PackedStringArray()), DEFVAL(0));
|
||||
ClassDB::bind_method(D_METHOD("export_zip_patch", "preset", "debug", "path", "patches", "flags"), &EditorExportPlatform::export_zip_patch, DEFVAL(PackedStringArray()), DEFVAL(0));
|
||||
|
||||
ClassDB::bind_method(D_METHOD("clear_messages"), &EditorExportPlatform::clear_messages);
|
||||
ClassDB::bind_method(D_METHOD("add_message", "type", "category", "message"), &EditorExportPlatform::add_message);
|
||||
|
@ -101,6 +101,7 @@ private:
|
||||
void *zip = nullptr;
|
||||
EditorProgress *ep = nullptr;
|
||||
Vector<SharedObject> *so_files = nullptr;
|
||||
int file_count = 0;
|
||||
};
|
||||
|
||||
Vector<ExportMessage> messages;
|
||||
@ -109,10 +110,14 @@ private:
|
||||
void _export_find_customized_resources(const Ref<EditorExportPreset> &p_preset, EditorFileSystemDirectory *p_dir, EditorExportPreset::FileExportMode p_mode, HashSet<String> &p_paths);
|
||||
void _export_find_dependencies(const String &p_path, HashSet<String> &p_paths);
|
||||
|
||||
static bool _check_hash(const uint8_t *p_hash, const Vector<uint8_t> &p_data);
|
||||
|
||||
static Error _save_pack_file(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &p_key);
|
||||
static Error _save_pack_patch_file(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &p_key);
|
||||
static Error _pack_add_shared_object(void *p_userdata, const SharedObject &p_so);
|
||||
|
||||
static Error _save_zip_file(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &p_key);
|
||||
static Error _save_zip_patch_file(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &p_key);
|
||||
static Error _zip_add_shared_object(void *p_userdata, const SharedObject &p_so);
|
||||
|
||||
struct ScriptCallbackData {
|
||||
@ -188,6 +193,9 @@ protected:
|
||||
Error ssh_run_on_remote_no_wait(const String &p_host, const String &p_port, const Vector<String> &p_ssh_args, const String &p_cmd_args, OS::ProcessID *r_pid = nullptr, int p_port_fwd = -1) const;
|
||||
Error ssh_push_to_remote(const String &p_host, const String &p_port, const Vector<String> &p_scp_args, const String &p_src_file, const String &p_dst_file) const;
|
||||
|
||||
Error _load_patches(const Vector<String> &p_patches);
|
||||
void _unload_patches();
|
||||
|
||||
public:
|
||||
virtual void get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) const = 0;
|
||||
|
||||
@ -284,8 +292,14 @@ public:
|
||||
Dictionary _save_pack(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, bool p_embed = false);
|
||||
Dictionary _save_zip(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path);
|
||||
|
||||
Error save_pack(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, Vector<SharedObject> *p_so_files = nullptr, bool p_embed = false, int64_t *r_embedded_start = nullptr, int64_t *r_embedded_size = nullptr);
|
||||
Error save_zip(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, Vector<SharedObject> *p_so_files = nullptr);
|
||||
Dictionary _save_pack_patch(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path);
|
||||
Dictionary _save_zip_patch(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path);
|
||||
|
||||
Error save_pack(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, Vector<SharedObject> *p_so_files = nullptr, EditorExportSaveFunction p_save_func = nullptr, bool p_embed = false, int64_t *r_embedded_start = nullptr, int64_t *r_embedded_size = nullptr);
|
||||
Error save_zip(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, Vector<SharedObject> *p_so_files = nullptr, EditorExportSaveFunction p_save_func = nullptr);
|
||||
|
||||
Error save_pack_patch(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, Vector<SharedObject> *p_so_files = nullptr, bool p_embed = false, int64_t *r_embedded_start = nullptr, int64_t *r_embedded_size = nullptr);
|
||||
Error save_zip_patch(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, Vector<SharedObject> *p_so_files = nullptr);
|
||||
|
||||
virtual bool poll_export() { return false; }
|
||||
virtual int get_options_count() const { return 0; }
|
||||
@ -307,6 +321,8 @@ public:
|
||||
virtual Error export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, BitField<EditorExportPlatform::DebugFlags> p_flags = 0) = 0;
|
||||
virtual Error export_pack(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, BitField<EditorExportPlatform::DebugFlags> p_flags = 0);
|
||||
virtual Error export_zip(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, BitField<EditorExportPlatform::DebugFlags> p_flags = 0);
|
||||
virtual Error export_pack_patch(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, const Vector<String> &p_patches = Vector<String>(), BitField<EditorExportPlatform::DebugFlags> p_flags = 0);
|
||||
virtual Error export_zip_patch(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, const Vector<String> &p_patches = Vector<String>(), BitField<EditorExportPlatform::DebugFlags> p_flags = 0);
|
||||
virtual void get_platform_features(List<String> *r_features) const = 0;
|
||||
virtual void resolve_platform_feature_priorities(const Ref<EditorExportPreset> &p_preset, HashSet<String> &p_features) {}
|
||||
virtual String get_debug_protocol() const { return "tcp://"; }
|
||||
|
@ -71,6 +71,8 @@ void EditorExportPlatformExtension::_bind_methods() {
|
||||
GDVIRTUAL_BIND(_export_project, "preset", "debug", "path", "flags");
|
||||
GDVIRTUAL_BIND(_export_pack, "preset", "debug", "path", "flags");
|
||||
GDVIRTUAL_BIND(_export_zip, "preset", "debug", "path", "flags");
|
||||
GDVIRTUAL_BIND(_export_pack_patch, "preset", "debug", "path", "patches", "flags");
|
||||
GDVIRTUAL_BIND(_export_zip_patch, "preset", "debug", "path", "patches", "flags");
|
||||
|
||||
GDVIRTUAL_BIND(_get_platform_features);
|
||||
|
||||
@ -291,6 +293,44 @@ Error EditorExportPlatformExtension::export_zip(const Ref<EditorExportPreset> &p
|
||||
return save_zip(p_preset, p_debug, p_path);
|
||||
}
|
||||
|
||||
Error EditorExportPlatformExtension::export_pack_patch(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, const Vector<String> &p_patches, BitField<EditorExportPlatform::DebugFlags> p_flags) {
|
||||
ExportNotifier notifier(*this, p_preset, p_debug, p_path, p_flags);
|
||||
|
||||
Error err = _load_patches(p_patches.is_empty() ? p_preset->get_patches() : p_patches);
|
||||
if (err != OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
Error ret = FAILED;
|
||||
if (GDVIRTUAL_CALL(_export_pack_patch, p_preset, p_debug, p_path, p_patches, p_flags, ret)) {
|
||||
_unload_patches();
|
||||
return ret;
|
||||
}
|
||||
|
||||
err = save_pack_patch(p_preset, p_debug, p_path);
|
||||
_unload_patches();
|
||||
return err;
|
||||
}
|
||||
|
||||
Error EditorExportPlatformExtension::export_zip_patch(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, const Vector<String> &p_patches, BitField<EditorExportPlatform::DebugFlags> p_flags) {
|
||||
ExportNotifier notifier(*this, p_preset, p_debug, p_path, p_flags);
|
||||
|
||||
Error err = _load_patches(p_patches.is_empty() ? p_preset->get_patches() : p_patches);
|
||||
if (err != OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
Error ret = FAILED;
|
||||
if (GDVIRTUAL_CALL(_export_zip_patch, p_preset, p_debug, p_path, p_patches, p_flags, ret)) {
|
||||
_unload_patches();
|
||||
return ret;
|
||||
}
|
||||
|
||||
err = save_zip_patch(p_preset, p_debug, p_path);
|
||||
_unload_patches();
|
||||
return err;
|
||||
}
|
||||
|
||||
void EditorExportPlatformExtension::get_platform_features(List<String> *r_features) const {
|
||||
Vector<String> ret;
|
||||
if (GDVIRTUAL_REQUIRED_CALL(_get_platform_features, ret) && r_features) {
|
||||
|
@ -136,6 +136,12 @@ public:
|
||||
virtual Error export_zip(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, BitField<EditorExportPlatform::DebugFlags> p_flags = 0) override;
|
||||
GDVIRTUAL4R(Error, _export_zip, Ref<EditorExportPreset>, bool, const String &, BitField<EditorExportPlatform::DebugFlags>);
|
||||
|
||||
virtual Error export_pack_patch(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, const Vector<String> &p_patches = Vector<String>(), BitField<EditorExportPlatform::DebugFlags> p_flags = 0) override;
|
||||
GDVIRTUAL5R(Error, _export_pack_patch, Ref<EditorExportPreset>, bool, const String &, const Vector<String> &, BitField<EditorExportPlatform::DebugFlags>);
|
||||
|
||||
virtual Error export_zip_patch(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, const Vector<String> &p_patches = Vector<String>(), BitField<EditorExportPlatform::DebugFlags> p_flags = 0) override;
|
||||
GDVIRTUAL5R(Error, _export_zip_patch, Ref<EditorExportPreset>, bool, const String &, const Vector<String> &, BitField<EditorExportPlatform::DebugFlags>);
|
||||
|
||||
virtual void get_platform_features(List<String> *r_features) const override;
|
||||
GDVIRTUAL0RC(Vector<String>, _get_platform_features);
|
||||
|
||||
|
@ -194,7 +194,7 @@ Error EditorExportPlatformPC::export_project_data(const Ref<EditorExportPreset>
|
||||
|
||||
int64_t embedded_pos;
|
||||
int64_t embedded_size;
|
||||
Error err = save_pack(p_preset, p_debug, pck_path, &so_files, p_preset->get("binary_format/embed_pck"), &embedded_pos, &embedded_size);
|
||||
Error err = save_pack(p_preset, p_debug, pck_path, &so_files, nullptr, 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 && String(p_preset->get("binary_format/architecture")).contains("32")) {
|
||||
add_message(EXPORT_MESSAGE_ERROR, TTR("PCK Embedding"), TTR("On 32-bit exports the embedded PCK cannot be bigger than 4 GiB."));
|
||||
|
@ -79,6 +79,7 @@ void EditorExportPreset::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("get_include_filter"), &EditorExportPreset::get_include_filter);
|
||||
ClassDB::bind_method(D_METHOD("get_exclude_filter"), &EditorExportPreset::get_exclude_filter);
|
||||
ClassDB::bind_method(D_METHOD("get_custom_features"), &EditorExportPreset::get_custom_features);
|
||||
ClassDB::bind_method(D_METHOD("get_patches"), &EditorExportPreset::get_patches);
|
||||
ClassDB::bind_method(D_METHOD("get_export_path"), &EditorExportPreset::get_export_path);
|
||||
ClassDB::bind_method(D_METHOD("get_encryption_in_filter"), &EditorExportPreset::get_enc_in_filter);
|
||||
ClassDB::bind_method(D_METHOD("get_encryption_ex_filter"), &EditorExportPreset::get_enc_ex_filter);
|
||||
@ -366,6 +367,42 @@ EditorExportPreset::FileExportMode EditorExportPreset::get_file_export_mode(cons
|
||||
return p_default;
|
||||
}
|
||||
|
||||
void EditorExportPreset::add_patch(const String &p_path, int p_at_pos) {
|
||||
ERR_FAIL_COND_EDMSG(patches.has(p_path), vformat("Failed to add patch \"%s\". Patches must be unique.", p_path));
|
||||
|
||||
if (p_at_pos < 0) {
|
||||
patches.push_back(p_path);
|
||||
} else {
|
||||
patches.insert(p_at_pos, p_path);
|
||||
}
|
||||
|
||||
EditorExport::singleton->save_presets();
|
||||
}
|
||||
|
||||
void EditorExportPreset::set_patch(int p_index, const String &p_path) {
|
||||
remove_patch(p_index);
|
||||
add_patch(p_path, p_index);
|
||||
}
|
||||
|
||||
String EditorExportPreset::get_patch(int p_index) {
|
||||
ERR_FAIL_INDEX_V(p_index, patches.size(), String());
|
||||
return patches[p_index];
|
||||
}
|
||||
|
||||
void EditorExportPreset::remove_patch(int p_index) {
|
||||
ERR_FAIL_INDEX(p_index, patches.size());
|
||||
patches.remove_at(p_index);
|
||||
EditorExport::singleton->save_presets();
|
||||
}
|
||||
|
||||
void EditorExportPreset::set_patches(const Vector<String> &p_patches) {
|
||||
patches = p_patches;
|
||||
}
|
||||
|
||||
Vector<String> EditorExportPreset::get_patches() const {
|
||||
return patches;
|
||||
}
|
||||
|
||||
void EditorExportPreset::set_custom_features(const String &p_custom_features) {
|
||||
custom_features = p_custom_features;
|
||||
EditorExport::singleton->save_presets();
|
||||
|
@ -74,6 +74,8 @@ private:
|
||||
bool advanced_options_enabled = false;
|
||||
bool dedicated_server = false;
|
||||
|
||||
Vector<String> patches;
|
||||
|
||||
friend class EditorExport;
|
||||
friend class EditorExportPlatform;
|
||||
|
||||
@ -144,6 +146,13 @@ public:
|
||||
void set_exclude_filter(const String &p_exclude);
|
||||
String get_exclude_filter() const;
|
||||
|
||||
void add_patch(const String &p_path, int p_at_pos = -1);
|
||||
void set_patch(int p_index, const String &p_path);
|
||||
String get_patch(int p_index);
|
||||
void remove_patch(int p_index);
|
||||
void set_patches(const Vector<String> &p_patches);
|
||||
Vector<String> get_patches() const;
|
||||
|
||||
void set_custom_features(const String &p_custom_features);
|
||||
String get_custom_features() const;
|
||||
|
||||
|
@ -102,11 +102,13 @@ void ProjectExportDialog::_notification(int p_what) {
|
||||
case NOTIFICATION_THEME_CHANGED: {
|
||||
duplicate_preset->set_icon(presets->get_editor_theme_icon(SNAME("Duplicate")));
|
||||
delete_preset->set_icon(presets->get_editor_theme_icon(SNAME("Remove")));
|
||||
patch_add_btn->set_icon(get_editor_theme_icon(SNAME("Add")));
|
||||
} break;
|
||||
|
||||
case NOTIFICATION_READY: {
|
||||
duplicate_preset->set_icon(presets->get_editor_theme_icon(SNAME("Duplicate")));
|
||||
delete_preset->set_icon(presets->get_editor_theme_icon(SNAME("Remove")));
|
||||
patch_add_btn->set_icon(get_editor_theme_icon(SNAME("Add")));
|
||||
connect(SceneStringName(confirmed), callable_mp(this, &ProjectExportDialog::_export_pck_zip));
|
||||
_update_export_all();
|
||||
} break;
|
||||
@ -248,6 +250,7 @@ void ProjectExportDialog::_edit_preset(int p_index) {
|
||||
duplicate_preset->set_disabled(true);
|
||||
delete_preset->set_disabled(true);
|
||||
sections->hide();
|
||||
patches->clear();
|
||||
export_error->hide();
|
||||
export_templates_error->hide();
|
||||
return;
|
||||
@ -292,6 +295,21 @@ void ProjectExportDialog::_edit_preset(int p_index) {
|
||||
exclude_filters->set_text(current->get_exclude_filter());
|
||||
server_strip_message->set_visible(current->get_export_filter() == EditorExportPreset::EXPORT_CUSTOMIZED);
|
||||
|
||||
patches->clear();
|
||||
TreeItem *patch_root = patches->create_item();
|
||||
Vector<String> patch_list = current->get_patches();
|
||||
for (int i = 0; i < patch_list.size(); i++) {
|
||||
TreeItem *patch = patches->create_item(patch_root);
|
||||
const String &patch_path = patch_list[i];
|
||||
patch->set_cell_mode(0, TreeItem::CELL_MODE_STRING);
|
||||
patch->set_editable(0, true);
|
||||
patch->set_text(0, patch_path.get_file());
|
||||
patch->set_tooltip_text(0, patch_path);
|
||||
patch->set_metadata(0, i);
|
||||
patch->add_button(0, get_editor_theme_icon(SNAME("Remove")), 0);
|
||||
patch->add_button(0, get_editor_theme_icon(SNAME("FileBrowse")), 1);
|
||||
}
|
||||
|
||||
_fill_resource_tree();
|
||||
|
||||
bool needs_templates;
|
||||
@ -664,6 +682,7 @@ void ProjectExportDialog::_duplicate_preset() {
|
||||
preset->set_export_filter(current->get_export_filter());
|
||||
preset->set_include_filter(current->get_include_filter());
|
||||
preset->set_exclude_filter(current->get_exclude_filter());
|
||||
preset->set_patches(current->get_patches());
|
||||
preset->set_custom_features(current->get_custom_features());
|
||||
|
||||
for (const KeyValue<StringName, Variant> &E : current->get_values()) {
|
||||
@ -720,8 +739,22 @@ Variant ProjectExportDialog::get_drag_data_fw(const Point2 &p_point, Control *p_
|
||||
|
||||
return d;
|
||||
}
|
||||
}
|
||||
} else if (p_from == patches) {
|
||||
TreeItem *item = patches->get_item_at_position(p_point);
|
||||
|
||||
if (item) {
|
||||
int item_metadata = item->get_metadata(0);
|
||||
Dictionary d;
|
||||
d["type"] = "export_patch";
|
||||
d["patch"] = item_metadata;
|
||||
|
||||
Label *label = memnew(Label);
|
||||
label->set_text(item->get_text(0));
|
||||
patches->set_drag_preview(label);
|
||||
|
||||
return d;
|
||||
}
|
||||
}
|
||||
return Variant();
|
||||
}
|
||||
|
||||
@ -735,6 +768,18 @@ bool ProjectExportDialog::can_drop_data_fw(const Point2 &p_point, const Variant
|
||||
if (presets->get_item_at_position(p_point, true) < 0 && !presets->is_pos_at_end_of_items(p_point)) {
|
||||
return false;
|
||||
}
|
||||
} else if (p_from == patches) {
|
||||
Dictionary d = p_data;
|
||||
if (d.get("type", "") != "export_patch") {
|
||||
return false;
|
||||
}
|
||||
|
||||
TreeItem *item = patches->get_item_at_position(p_point);
|
||||
if (!item) {
|
||||
return false;
|
||||
}
|
||||
|
||||
patches->set_drop_mode_flags(Tree::DROP_MODE_INBETWEEN);
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -771,6 +816,31 @@ void ProjectExportDialog::drop_data_fw(const Point2 &p_point, const Variant &p_d
|
||||
} else {
|
||||
_edit_preset(presets->get_item_count() - 1);
|
||||
}
|
||||
} else if (p_from == patches) {
|
||||
Dictionary d = p_data;
|
||||
int from_pos = d["patch"];
|
||||
|
||||
TreeItem *item = patches->get_item_at_position(p_point);
|
||||
if (!item) {
|
||||
return;
|
||||
}
|
||||
|
||||
int to_pos = item->get_metadata(0);
|
||||
|
||||
if (patches->get_drop_section_at_position(p_point) > 0) {
|
||||
to_pos++;
|
||||
}
|
||||
|
||||
if (to_pos > from_pos) {
|
||||
to_pos--;
|
||||
}
|
||||
|
||||
Ref<EditorExportPreset> preset = get_current_preset();
|
||||
String patch = preset->get_patch(from_pos);
|
||||
preset->remove_patch(from_pos);
|
||||
preset->add_patch(patch, to_pos);
|
||||
|
||||
_update_current_preset();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1026,6 +1096,75 @@ void ProjectExportDialog::_set_file_export_mode(int p_id) {
|
||||
_propagate_file_export_mode(include_files->get_root(), EditorExportPreset::MODE_FILE_NOT_CUSTOMIZED);
|
||||
}
|
||||
|
||||
void ProjectExportDialog::_patch_tree_button_clicked(Object *p_item, int p_column, int p_id, int p_mouse_button_index) {
|
||||
TreeItem *ti = Object::cast_to<TreeItem>(p_item);
|
||||
|
||||
patch_index = ti->get_metadata(0);
|
||||
|
||||
Ref<EditorExportPreset> current = get_current_preset();
|
||||
ERR_FAIL_COND(current.is_null());
|
||||
|
||||
if (p_id == 0) {
|
||||
Vector<String> preset_patches = current->get_patches();
|
||||
ERR_FAIL_INDEX(patch_index, preset_patches.size());
|
||||
patch_erase->set_text(vformat(TTR("Delete patch '%s' from list?"), preset_patches[patch_index].get_file()));
|
||||
patch_erase->popup_centered();
|
||||
} else {
|
||||
patch_dialog->popup_file_dialog();
|
||||
}
|
||||
}
|
||||
|
||||
void ProjectExportDialog::_patch_tree_item_edited() {
|
||||
TreeItem *item = patches->get_edited();
|
||||
if (!item) {
|
||||
return;
|
||||
}
|
||||
|
||||
Ref<EditorExportPreset> current = get_current_preset();
|
||||
ERR_FAIL_COND(current.is_null());
|
||||
|
||||
int index = item->get_metadata(0);
|
||||
String patch_path = item->get_text(0);
|
||||
|
||||
current->set_patch(index, patch_path);
|
||||
item->set_tooltip_text(0, patch_path);
|
||||
}
|
||||
|
||||
void ProjectExportDialog::_patch_file_selected(const String &p_path) {
|
||||
Ref<EditorExportPreset> current = get_current_preset();
|
||||
ERR_FAIL_COND(current.is_null());
|
||||
|
||||
String relative_path = ProjectSettings::get_singleton()->get_resource_path().path_to_file(p_path);
|
||||
|
||||
Vector<String> preset_patches = current->get_patches();
|
||||
if (patch_index >= preset_patches.size()) {
|
||||
current->add_patch(relative_path);
|
||||
} else {
|
||||
current->set_patch(patch_index, relative_path);
|
||||
}
|
||||
|
||||
_update_current_preset();
|
||||
}
|
||||
|
||||
void ProjectExportDialog::_patch_delete_confirmed() {
|
||||
Ref<EditorExportPreset> current = get_current_preset();
|
||||
ERR_FAIL_COND(current.is_null());
|
||||
|
||||
Vector<String> preset_patches = current->get_patches();
|
||||
if (patch_index < preset_patches.size()) {
|
||||
current->remove_patch(patch_index);
|
||||
_update_current_preset();
|
||||
}
|
||||
}
|
||||
|
||||
void ProjectExportDialog::_patch_add_pack_pressed() {
|
||||
Ref<EditorExportPreset> current = get_current_preset();
|
||||
ERR_FAIL_COND(current.is_null());
|
||||
|
||||
patch_index = current->get_patches().size();
|
||||
patch_dialog->popup_file_dialog();
|
||||
}
|
||||
|
||||
void ProjectExportDialog::_export_pck_zip() {
|
||||
Ref<EditorExportPreset> current = get_current_preset();
|
||||
ERR_FAIL_COND(current.is_null());
|
||||
@ -1044,11 +1183,20 @@ void ProjectExportDialog::_export_pck_zip_selected(const String &p_path) {
|
||||
|
||||
const Dictionary &fd_option = export_pck_zip->get_selected_options();
|
||||
bool export_debug = fd_option.get(TTR("Export With Debug"), true);
|
||||
bool export_as_patch = fd_option.get(TTR("Export As Patch"), true);
|
||||
|
||||
if (p_path.ends_with(".zip")) {
|
||||
platform->export_zip(current, export_debug, p_path);
|
||||
if (export_as_patch) {
|
||||
platform->export_zip_patch(current, export_debug, p_path);
|
||||
} else {
|
||||
platform->export_zip(current, export_debug, p_path);
|
||||
}
|
||||
} else if (p_path.ends_with(".pck")) {
|
||||
platform->export_pack(current, export_debug, p_path);
|
||||
if (export_as_patch) {
|
||||
platform->export_pack_patch(current, export_debug, p_path);
|
||||
} else {
|
||||
platform->export_pack(current, export_debug, p_path);
|
||||
}
|
||||
} else {
|
||||
ERR_FAIL_MSG("Path must end with .pck or .zip");
|
||||
}
|
||||
@ -1386,6 +1534,40 @@ ProjectExportDialog::ProjectExportDialog() {
|
||||
exclude_filters);
|
||||
exclude_filters->connect(SceneStringName(text_changed), callable_mp(this, &ProjectExportDialog::_filter_changed));
|
||||
|
||||
// Patch packages.
|
||||
|
||||
VBoxContainer *patch_vb = memnew(VBoxContainer);
|
||||
sections->add_child(patch_vb);
|
||||
patch_vb->set_name(TTR("Patches"));
|
||||
|
||||
patches = memnew(Tree);
|
||||
patches->set_v_size_flags(Control::SIZE_EXPAND_FILL);
|
||||
patches->set_hide_root(true);
|
||||
patches->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED);
|
||||
patches->connect("button_clicked", callable_mp(this, &ProjectExportDialog::_patch_tree_button_clicked));
|
||||
patches->connect("item_edited", callable_mp(this, &ProjectExportDialog::_patch_tree_item_edited));
|
||||
SET_DRAG_FORWARDING_GCD(patches, ProjectExportDialog);
|
||||
patches->set_edit_checkbox_cell_only_when_checkbox_is_pressed(true);
|
||||
patch_vb->add_margin_child(TTR("Base Packs:"), patches, true);
|
||||
|
||||
patch_dialog = memnew(EditorFileDialog);
|
||||
patch_dialog->add_filter("*.pck", TTR("Godot Project Pack"));
|
||||
patch_dialog->set_access(EditorFileDialog::ACCESS_FILESYSTEM);
|
||||
patch_dialog->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILE);
|
||||
patch_dialog->connect("file_selected", callable_mp(this, &ProjectExportDialog::_patch_file_selected));
|
||||
add_child(patch_dialog);
|
||||
|
||||
patch_erase = memnew(ConfirmationDialog);
|
||||
patch_erase->set_ok_button_text(TTR("Delete"));
|
||||
patch_erase->connect(SceneStringName(confirmed), callable_mp(this, &ProjectExportDialog::_patch_delete_confirmed));
|
||||
add_child(patch_erase);
|
||||
|
||||
patch_add_btn = memnew(Button);
|
||||
patch_add_btn->set_text(TTR("Add Pack"));
|
||||
patch_add_btn->set_h_size_flags(Control::SIZE_SHRINK_CENTER);
|
||||
patch_add_btn->connect(SceneStringName(pressed), callable_mp(this, &ProjectExportDialog::_patch_add_pack_pressed));
|
||||
patch_vb->add_child(patch_add_btn);
|
||||
|
||||
// Feature tags.
|
||||
|
||||
VBoxContainer *feature_vb = memnew(VBoxContainer);
|
||||
@ -1569,6 +1751,7 @@ ProjectExportDialog::ProjectExportDialog() {
|
||||
|
||||
export_project->add_option(TTR("Export With Debug"), Vector<String>(), true);
|
||||
export_pck_zip->add_option(TTR("Export With Debug"), Vector<String>(), true);
|
||||
export_pck_zip->add_option(TTR("Export As Patch"), Vector<String>(), true);
|
||||
|
||||
set_hide_on_ok(false);
|
||||
|
||||
|
@ -105,6 +105,13 @@ class ProjectExportDialog : public ConfirmationDialog {
|
||||
AcceptDialog *export_all_dialog = nullptr;
|
||||
|
||||
RBSet<String> feature_set;
|
||||
|
||||
Tree *patches = nullptr;
|
||||
int patch_index = -1;
|
||||
EditorFileDialog *patch_dialog = nullptr;
|
||||
ConfirmationDialog *patch_erase = nullptr;
|
||||
Button *patch_add_btn = nullptr;
|
||||
|
||||
LineEdit *custom_features = nullptr;
|
||||
RichTextLabel *custom_feature_display = nullptr;
|
||||
|
||||
@ -148,6 +155,12 @@ class ProjectExportDialog : public ConfirmationDialog {
|
||||
void _tree_popup_edited(bool p_arrow_clicked);
|
||||
void _set_file_export_mode(int p_id);
|
||||
|
||||
void _patch_tree_button_clicked(Object *p_item, int p_column, int p_id, int p_mouse_button_index);
|
||||
void _patch_tree_item_edited();
|
||||
void _patch_file_selected(const String &p_path);
|
||||
void _patch_delete_confirmed();
|
||||
void _patch_add_pack_pressed();
|
||||
|
||||
Variant get_drag_data_fw(const Point2 &p_point, Control *p_from);
|
||||
bool can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const;
|
||||
void drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from);
|
||||
|
@ -650,6 +650,8 @@ void Main::print_help(const char *p_binary) {
|
||||
print_help_option("", "The target directory must exist.\n");
|
||||
print_help_option("--export-debug <preset> <path>", "Export the project in debug mode using the given preset and output path. See --export-release description for other considerations.\n", CLI_OPTION_AVAILABILITY_EDITOR);
|
||||
print_help_option("--export-pack <preset> <path>", "Export the project data only using the given preset and output path. The <path> extension determines whether it will be in PCK or ZIP format.\n", CLI_OPTION_AVAILABILITY_EDITOR);
|
||||
print_help_option("--export-patch <preset> <path>", "Export pack with changed files only. See --export-pack description for other considerations.\n", CLI_OPTION_AVAILABILITY_EDITOR);
|
||||
print_help_option("--patches <paths>", "List of patches to use with --export-patch. The list is comma-separated.\n", CLI_OPTION_AVAILABILITY_EDITOR);
|
||||
print_help_option("--install-android-build-template", "Install the Android build template. Used in conjunction with --export-release or --export-debug.\n", CLI_OPTION_AVAILABILITY_EDITOR);
|
||||
#ifndef DISABLE_DEPRECATED
|
||||
// Commands are long; split the description to a second line.
|
||||
@ -1469,12 +1471,23 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
|
||||
wait_for_import = true;
|
||||
quit_after = 1;
|
||||
} else if (arg == "--export-release" || arg == "--export-debug" ||
|
||||
arg == "--export-pack") { // Export project
|
||||
arg == "--export-pack" || arg == "--export-patch") { // Export project
|
||||
// Actually handling is done in start().
|
||||
editor = true;
|
||||
cmdline_tool = true;
|
||||
wait_for_import = true;
|
||||
main_args.push_back(arg);
|
||||
} else if (arg == "--patches") {
|
||||
if (N) {
|
||||
// Actually handling is done in start().
|
||||
main_args.push_back(arg);
|
||||
main_args.push_back(N->get());
|
||||
|
||||
N = N->next();
|
||||
} else {
|
||||
OS::get_singleton()->print("Missing comma-separated list of patches after --patches, aborting.\n");
|
||||
goto error;
|
||||
}
|
||||
#ifndef DISABLE_DEPRECATED
|
||||
} else if (arg == "--export") { // For users used to 3.x syntax.
|
||||
OS::get_singleton()->print("The Godot 3 --export option was changed to more explicit --export-release / --export-debug / --export-pack options.\nSee the --help output for details.\n");
|
||||
@ -3480,9 +3493,11 @@ int Main::start() {
|
||||
bool doc_tool_implicit_cwd = false;
|
||||
BitField<DocTools::GenerateFlags> gen_flags;
|
||||
String _export_preset;
|
||||
Vector<String> patches;
|
||||
bool export_debug = false;
|
||||
bool export_pack_only = false;
|
||||
bool install_android_build_template = false;
|
||||
bool export_patch = false;
|
||||
#ifdef MODULE_GDSCRIPT_ENABLED
|
||||
String gdscript_docs_path;
|
||||
#endif
|
||||
@ -3572,6 +3587,14 @@ int Main::start() {
|
||||
editor = true;
|
||||
_export_preset = E->next()->get();
|
||||
export_pack_only = true;
|
||||
} else if (E->get() == "--export-patch") {
|
||||
ERR_FAIL_COND_V_MSG(!editor && !found_project, EXIT_FAILURE, "Please provide a valid project path when exporting, aborting.");
|
||||
editor = true;
|
||||
_export_preset = E->next()->get();
|
||||
export_pack_only = true;
|
||||
export_patch = true;
|
||||
} else if (E->get() == "--patches") {
|
||||
patches = E->next()->get().split(",", false);
|
||||
#endif
|
||||
} else {
|
||||
// The parameter does not match anything known, don't skip the next argument
|
||||
@ -3975,7 +3998,7 @@ int Main::start() {
|
||||
sml->get_root()->add_child(editor_node);
|
||||
|
||||
if (!_export_preset.is_empty()) {
|
||||
editor_node->export_preset(_export_preset, positional_arg, export_debug, export_pack_only, install_android_build_template);
|
||||
editor_node->export_preset(_export_preset, positional_arg, export_debug, export_pack_only, install_android_build_template, export_patch, patches);
|
||||
game_path = ""; // Do not load anything.
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user