Re-add support for installing templates from TPZ
This commit is contained in:
@@ -45,6 +45,7 @@
|
||||
#include "editor/file_system/editor_file_system.h"
|
||||
#include "editor/file_system/editor_paths.h"
|
||||
#include "editor/gui/editor_bottom_panel.h"
|
||||
#include "editor/gui/editor_file_dialog.h"
|
||||
#include "editor/gui/progress_dialog.h"
|
||||
#include "editor/settings/editor_settings.h"
|
||||
#include "editor/themes/editor_scale.h"
|
||||
@@ -221,6 +222,171 @@ void ExportTemplateManager::_delete_file(const TreeItem *p_item) {
|
||||
}
|
||||
}
|
||||
|
||||
void ExportTemplateManager::_tpz_file_selected(const String &p_file) {
|
||||
Ref<FileAccess> io_fa;
|
||||
zlib_filefunc_def io = zipio_create_io(&io_fa);
|
||||
|
||||
unzFile pkg = unzOpen2(p_file.utf8().get_data(), &io);
|
||||
if (!pkg) {
|
||||
EditorNode::get_singleton()->show_warning(TTR("Can't open the export templates file."));
|
||||
return;
|
||||
}
|
||||
int ret = unzGoToFirstFile(pkg);
|
||||
|
||||
// Count them and find version.
|
||||
int fc = 0;
|
||||
String version;
|
||||
String contents_dir;
|
||||
|
||||
while (ret == UNZ_OK) {
|
||||
unz_file_info info;
|
||||
char fname[16384];
|
||||
ret = unzGetCurrentFileInfo(pkg, &info, fname, 16384, nullptr, 0, nullptr, 0);
|
||||
if (ret != UNZ_OK) {
|
||||
break;
|
||||
}
|
||||
|
||||
String file = String::utf8(fname);
|
||||
|
||||
// Skip the __MACOSX directory created by macOS's built-in file zipper.
|
||||
if (file.begins_with("__MACOSX")) {
|
||||
ret = unzGoToNextFile(pkg);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (file.ends_with("version.txt")) {
|
||||
Vector<uint8_t> uncomp_data;
|
||||
uncomp_data.resize(info.uncompressed_size);
|
||||
|
||||
// Read.
|
||||
unzOpenCurrentFile(pkg);
|
||||
ret = unzReadCurrentFile(pkg, uncomp_data.ptrw(), uncomp_data.size());
|
||||
ERR_BREAK_MSG(ret < 0, vformat("An error occurred while attempting to read from file: %s. This file will not be used.", file));
|
||||
unzCloseCurrentFile(pkg);
|
||||
|
||||
String data_str = String::utf8((const char *)uncomp_data.ptr(), uncomp_data.size());
|
||||
data_str = data_str.strip_edges();
|
||||
|
||||
// Version number should be of the form major.minor[.patch].status[.module_config]
|
||||
// so it can in theory have 3 or more slices.
|
||||
if (data_str.get_slice_count(".") < 3) {
|
||||
EditorNode::get_singleton()->show_warning(vformat(TTR("Invalid version.txt format inside the export templates file: %s."), data_str));
|
||||
unzClose(pkg);
|
||||
return;
|
||||
}
|
||||
|
||||
version = data_str;
|
||||
contents_dir = file.get_base_dir().trim_suffix("/").trim_suffix("\\");
|
||||
}
|
||||
|
||||
if (file.get_file().size() != 0) {
|
||||
fc++;
|
||||
}
|
||||
|
||||
ret = unzGoToNextFile(pkg);
|
||||
}
|
||||
|
||||
if (version.is_empty()) {
|
||||
EditorNode::get_singleton()->show_warning(TTR("No version.txt found inside the export templates file."));
|
||||
unzClose(pkg);
|
||||
return;
|
||||
}
|
||||
|
||||
Ref<DirAccess> d = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
|
||||
String template_path = EditorPaths::get_singleton()->get_export_templates_dir().path_join(version);
|
||||
Error err = d->make_dir_recursive(template_path);
|
||||
if (err != OK) {
|
||||
EditorNode::get_singleton()->show_warning(TTR("Error creating path for extracting templates:") + "\n" + template_path);
|
||||
unzClose(pkg);
|
||||
return;
|
||||
}
|
||||
|
||||
EditorProgress ep("export_tpz", TTR("Extracting Export Templates"), fc);
|
||||
|
||||
fc = 0;
|
||||
ret = unzGoToFirstFile(pkg);
|
||||
while (ret == UNZ_OK) {
|
||||
// Get filename.
|
||||
unz_file_info info;
|
||||
char fname[16384];
|
||||
ret = unzGetCurrentFileInfo(pkg, &info, fname, 16384, nullptr, 0, nullptr, 0);
|
||||
if (ret != UNZ_OK) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (String::utf8(fname).ends_with("/")) {
|
||||
// File is a directory, ignore it.
|
||||
// Directories will be created when extracting each file.
|
||||
ret = unzGoToNextFile(pkg);
|
||||
continue;
|
||||
}
|
||||
|
||||
String file_path(String::utf8(fname).simplify_path());
|
||||
|
||||
String file = file_path.get_file();
|
||||
|
||||
// Skip the __MACOSX directory created by macOS's built-in file zipper.
|
||||
if (file.is_empty() || file.begins_with("__MACOSX")) {
|
||||
ret = unzGoToNextFile(pkg);
|
||||
continue;
|
||||
}
|
||||
|
||||
Vector<uint8_t> uncomp_data;
|
||||
uncomp_data.resize(info.uncompressed_size);
|
||||
|
||||
// Read
|
||||
unzOpenCurrentFile(pkg);
|
||||
ret = unzReadCurrentFile(pkg, uncomp_data.ptrw(), uncomp_data.size());
|
||||
ERR_BREAK_MSG(ret < 0, vformat("An error occurred while attempting to read from file: %s. This file will not be used.", file));
|
||||
unzCloseCurrentFile(pkg);
|
||||
|
||||
String base_dir = file_path.get_base_dir().trim_suffix("/");
|
||||
|
||||
if (base_dir != contents_dir && base_dir.begins_with(contents_dir)) {
|
||||
base_dir = base_dir.substr(contents_dir.length(), file_path.length()).trim_prefix("/");
|
||||
file = base_dir.path_join(file);
|
||||
|
||||
Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
|
||||
ERR_CONTINUE(da.is_null());
|
||||
|
||||
String output_dir = template_path.path_join(base_dir);
|
||||
|
||||
if (!DirAccess::exists(output_dir)) {
|
||||
Error mkdir_err = da->make_dir_recursive(output_dir);
|
||||
ERR_CONTINUE(mkdir_err != OK);
|
||||
}
|
||||
}
|
||||
ep.step(TTR("Importing:") + " " + file, fc);
|
||||
|
||||
String to_write = template_path.path_join(file);
|
||||
Ref<FileAccess> f = FileAccess::open(to_write, FileAccess::WRITE);
|
||||
|
||||
if (f.is_null()) {
|
||||
ret = unzGoToNextFile(pkg);
|
||||
fc++;
|
||||
ERR_CONTINUE_MSG(true, "Can't open file from path '" + String(to_write) + "'.");
|
||||
}
|
||||
|
||||
f->store_buffer(uncomp_data.ptr(), uncomp_data.size());
|
||||
f.unref(); // close file.
|
||||
#ifndef WINDOWS_ENABLED
|
||||
FileAccess::set_unix_permissions(to_write, (info.external_fa >> 16) & 0x01FF);
|
||||
#endif
|
||||
|
||||
ret = unzGoToNextFile(pkg);
|
||||
fc++;
|
||||
}
|
||||
|
||||
unzClose(pkg);
|
||||
|
||||
EditorSettings::get_singleton()->set("_export_template_download_directory", p_file.get_base_dir());
|
||||
|
||||
const String selected_version = version_list->get_item_text(version_list->get_current());
|
||||
if (selected_version == version) {
|
||||
_update_template_tree();
|
||||
}
|
||||
}
|
||||
|
||||
void ExportTemplateManager::_initialize_template_data() {
|
||||
// Base templates.
|
||||
{
|
||||
@@ -1163,6 +1329,7 @@ void ExportTemplateManager::_notification(int p_what) {
|
||||
install_button->set_button_icon(get_editor_theme_icon("AssetStore"));
|
||||
open_mirror->set_button_icon(get_editor_theme_icon("ExternalLink"));
|
||||
delete_all_button->set_button_icon(get_editor_theme_icon("Remove"));
|
||||
tpz_button->set_button_icon(get_editor_theme_icon("FileBrowse"));
|
||||
|
||||
theme_cache.install_icon = get_editor_theme_icon("AssetStore");
|
||||
theme_cache.remove_icon = get_editor_theme_icon("Remove");
|
||||
@@ -1399,6 +1566,21 @@ ExportTemplateManager::ExportTemplateManager() {
|
||||
download_header->add_child(install_button);
|
||||
install_button->connect(SceneStringName(pressed), callable_mp(this, &ExportTemplateManager::_install_templates).bind((TreeItem *)nullptr));
|
||||
|
||||
tpz_button = memnew(Button);
|
||||
tpz_button->set_tooltip_text(TTRC("Install from a TPZ file."));
|
||||
download_header->add_child(tpz_button);
|
||||
|
||||
tpz_selection_dialog = memnew(EditorFileDialog);
|
||||
tpz_selection_dialog->set_title(TTRC("Select Template File"));
|
||||
tpz_selection_dialog->set_access(FileDialog::ACCESS_FILESYSTEM);
|
||||
tpz_selection_dialog->set_file_mode(FileDialog::FILE_MODE_OPEN_FILE);
|
||||
tpz_selection_dialog->set_current_dir(EDITOR_DEF("_export_template_download_directory", ""));
|
||||
tpz_selection_dialog->add_filter("*.tpz", TTRC("Godot Export Templates"));
|
||||
tpz_selection_dialog->connect("file_selected", callable_mp(this, &ExportTemplateManager::_tpz_file_selected));
|
||||
add_child(tpz_selection_dialog);
|
||||
|
||||
tpz_button->connect(SceneStringName(pressed), callable_mp((FileDialog *)tpz_selection_dialog, &FileDialog::popup_file_dialog));
|
||||
|
||||
HSplitContainer *main_split = memnew(HSplitContainer);
|
||||
main_split->set_v_size_flags(Control::SIZE_EXPAND_FILL);
|
||||
main_vb->add_child(main_split);
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
|
||||
class Button;
|
||||
class EditorExportPreset;
|
||||
class EditorFileDialog;
|
||||
class ItemList;
|
||||
class HBoxContainer;
|
||||
class OptionButton;
|
||||
@@ -196,8 +197,10 @@ class ExportTemplateManager : public AcceptDialog {
|
||||
Button *open_folder_button = nullptr;
|
||||
Button *install_button = nullptr;
|
||||
Button *delete_all_button = nullptr;
|
||||
Button *tpz_button = nullptr;
|
||||
HBoxContainer *offline_container = nullptr;
|
||||
ConfirmationDialog *confirm_delete = nullptr;
|
||||
EditorFileDialog *tpz_selection_dialog = nullptr;
|
||||
|
||||
void _request_mirrors();
|
||||
void _mirrors_request_completed(int p_result, int p_response_code, const PackedStringArray &p_headers, const PackedByteArray &p_body);
|
||||
@@ -210,6 +213,7 @@ class ExportTemplateManager : public AcceptDialog {
|
||||
void _delete_all();
|
||||
void _delete_confirmed();
|
||||
void _delete_file(const TreeItem *p_item);
|
||||
void _tpz_file_selected(const String &p_file);
|
||||
|
||||
void _initialize_template_data();
|
||||
void _update_version_list();
|
||||
|
||||
Reference in New Issue
Block a user