Add support for scene/resource customization in export plugins
EditorExportPlugin adds a set of callbacks to allow customizing scenes, resources or subresources in all files exported: * Can take scene files, resource files and subresources in all of them. * Uses a cache for the converted files if nothing changes, so this work only happens if a file is modified. * Uses hashing to differentiate export configuration caches. * Removed the previous conversion code to binary, as this one uses existing stuff. This API is useful in several scenarios: * Needed by the "server" export platform to get rid of textures, meshes, audio, etc. * Needed by text to binary converters. * Needed by eventual optimizations such as shader precompiling on export, mesh merging and optimization, etc. This is a draft, feedback is very welcome.
This commit is contained in:
parent
c40855f818
commit
ef17c4668a
@ -32,6 +32,7 @@
|
|||||||
|
|
||||||
#include "core/io/file_access_encrypted.h"
|
#include "core/io/file_access_encrypted.h"
|
||||||
#include "core/os/keyboard.h"
|
#include "core/os/keyboard.h"
|
||||||
|
#include "core/string/string_builder.h"
|
||||||
#include "core/variant/variant_parser.h"
|
#include "core/variant/variant_parser.h"
|
||||||
|
|
||||||
PackedStringArray ConfigFile::_get_sections() const {
|
PackedStringArray ConfigFile::_get_sections() const {
|
||||||
@ -130,6 +131,28 @@ void ConfigFile::erase_section_key(const String &p_section, const String &p_key)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String ConfigFile::encode_to_text() const {
|
||||||
|
StringBuilder sb;
|
||||||
|
bool first = true;
|
||||||
|
for (const KeyValue<String, HashMap<String, Variant>> &E : values) {
|
||||||
|
if (first) {
|
||||||
|
first = false;
|
||||||
|
} else {
|
||||||
|
sb.append("\n");
|
||||||
|
}
|
||||||
|
if (!E.key.is_empty()) {
|
||||||
|
sb.append("[" + E.key + "]\n\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const KeyValue<String, Variant> &F : E.value) {
|
||||||
|
String vstr;
|
||||||
|
VariantWriter::write_to_string(F.value, vstr);
|
||||||
|
sb.append(F.key.property_name_encode() + "=" + vstr + "\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sb.as_string();
|
||||||
|
}
|
||||||
|
|
||||||
Error ConfigFile::save(const String &p_path) {
|
Error ConfigFile::save(const String &p_path) {
|
||||||
Error err;
|
Error err;
|
||||||
Ref<FileAccess> file = FileAccess::open(p_path, FileAccess::WRITE, &err);
|
Ref<FileAccess> file = FileAccess::open(p_path, FileAccess::WRITE, &err);
|
||||||
@ -295,6 +318,7 @@ Error ConfigFile::_parse(const String &p_path, VariantParser::Stream *p_stream)
|
|||||||
void ConfigFile::clear() {
|
void ConfigFile::clear() {
|
||||||
values.clear();
|
values.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConfigFile::_bind_methods() {
|
void ConfigFile::_bind_methods() {
|
||||||
ClassDB::bind_method(D_METHOD("set_value", "section", "key", "value"), &ConfigFile::set_value);
|
ClassDB::bind_method(D_METHOD("set_value", "section", "key", "value"), &ConfigFile::set_value);
|
||||||
ClassDB::bind_method(D_METHOD("get_value", "section", "key", "default"), &ConfigFile::get_value, DEFVAL(Variant()));
|
ClassDB::bind_method(D_METHOD("get_value", "section", "key", "default"), &ConfigFile::get_value, DEFVAL(Variant()));
|
||||||
@ -312,6 +336,8 @@ void ConfigFile::_bind_methods() {
|
|||||||
ClassDB::bind_method(D_METHOD("parse", "data"), &ConfigFile::parse);
|
ClassDB::bind_method(D_METHOD("parse", "data"), &ConfigFile::parse);
|
||||||
ClassDB::bind_method(D_METHOD("save", "path"), &ConfigFile::save);
|
ClassDB::bind_method(D_METHOD("save", "path"), &ConfigFile::save);
|
||||||
|
|
||||||
|
ClassDB::bind_method(D_METHOD("encode_to_text"), &ConfigFile::encode_to_text);
|
||||||
|
|
||||||
BIND_METHOD_ERR_RETURN_DOC("load", ERR_FILE_CANT_OPEN);
|
BIND_METHOD_ERR_RETURN_DOC("load", ERR_FILE_CANT_OPEN);
|
||||||
|
|
||||||
ClassDB::bind_method(D_METHOD("load_encrypted", "path", "key"), &ConfigFile::load_encrypted);
|
ClassDB::bind_method(D_METHOD("load_encrypted", "path", "key"), &ConfigFile::load_encrypted);
|
||||||
|
@ -68,6 +68,8 @@ public:
|
|||||||
Error load(const String &p_path);
|
Error load(const String &p_path);
|
||||||
Error parse(const String &p_data);
|
Error parse(const String &p_data);
|
||||||
|
|
||||||
|
String encode_to_text() const; // used by exporter
|
||||||
|
|
||||||
void clear();
|
void clear();
|
||||||
|
|
||||||
Error load_encrypted(const String &p_path, const Vector<uint8_t> &p_key);
|
Error load_encrypted(const String &p_path, const Vector<uint8_t> &p_key);
|
||||||
|
@ -98,6 +98,12 @@
|
|||||||
Removes the entire contents of the config.
|
Removes the entire contents of the config.
|
||||||
</description>
|
</description>
|
||||||
</method>
|
</method>
|
||||||
|
<method name="encode_to_text" qualifiers="const">
|
||||||
|
<return type="String" />
|
||||||
|
<description>
|
||||||
|
Obtain the text version of this config file (the same text that would be written to a file).
|
||||||
|
</description>
|
||||||
|
</method>
|
||||||
<method name="erase_section">
|
<method name="erase_section">
|
||||||
<return type="void" />
|
<return type="void" />
|
||||||
<param index="0" name="section" type="String" />
|
<param index="0" name="section" type="String" />
|
||||||
|
9
doc/classes/EditorExportPlatform.xml
Normal file
9
doc/classes/EditorExportPlatform.xml
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
|
<class name="EditorExportPlatform" inherits="RefCounted" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
|
||||||
|
<brief_description>
|
||||||
|
</brief_description>
|
||||||
|
<description>
|
||||||
|
</description>
|
||||||
|
<tutorials>
|
||||||
|
</tutorials>
|
||||||
|
</class>
|
@ -10,6 +10,51 @@
|
|||||||
<tutorials>
|
<tutorials>
|
||||||
</tutorials>
|
</tutorials>
|
||||||
<methods>
|
<methods>
|
||||||
|
<method name="_begin_customize_resources" qualifiers="virtual const">
|
||||||
|
<return type="bool" />
|
||||||
|
<param index="0" name="platform" type="EditorExportPlatform" />
|
||||||
|
<param index="1" name="features" type="PackedStringArray" />
|
||||||
|
<description>
|
||||||
|
Return true if this plugin will customize resources based on the platform and features used.
|
||||||
|
</description>
|
||||||
|
</method>
|
||||||
|
<method name="_begin_customize_scenes" qualifiers="virtual const">
|
||||||
|
<return type="bool" />
|
||||||
|
<param index="0" name="platform" type="EditorExportPlatform" />
|
||||||
|
<param index="1" name="features" type="PackedStringArray" />
|
||||||
|
<description>
|
||||||
|
Return true if this plugin will customize scenes based on the platform and features used.
|
||||||
|
</description>
|
||||||
|
</method>
|
||||||
|
<method name="_customize_resource" qualifiers="virtual">
|
||||||
|
<return type="Resource" />
|
||||||
|
<param index="0" name="resource" type="Resource" />
|
||||||
|
<param index="1" name="path" type="String" />
|
||||||
|
<description>
|
||||||
|
Customize a resource. If changes are made to it, return the same or a new resource. Otherwise, return [code]null[/code].
|
||||||
|
The [i]path[/i] argument is only used when customizing an actual file, otherwise this means that this resource is part of another one and it will be empty.
|
||||||
|
</description>
|
||||||
|
</method>
|
||||||
|
<method name="_customize_scene" qualifiers="virtual">
|
||||||
|
<return type="Node" />
|
||||||
|
<param index="0" name="scene" type="Node" />
|
||||||
|
<param index="1" name="path" type="String" />
|
||||||
|
<description>
|
||||||
|
Customize a scene. If changes are made to it, return the same or a new scene. Otherwise, return [code]null[/code]. If a new scene is returned, it is up to you to dispose of the old one.
|
||||||
|
</description>
|
||||||
|
</method>
|
||||||
|
<method name="_end_customize_resources" qualifiers="virtual">
|
||||||
|
<return type="void" />
|
||||||
|
<description>
|
||||||
|
This is called when the customization process for resources ends.
|
||||||
|
</description>
|
||||||
|
</method>
|
||||||
|
<method name="_end_customize_scenes" qualifiers="virtual">
|
||||||
|
<return type="void" />
|
||||||
|
<description>
|
||||||
|
This is called when the customization process for scenes ends.
|
||||||
|
</description>
|
||||||
|
</method>
|
||||||
<method name="_export_begin" qualifiers="virtual">
|
<method name="_export_begin" qualifiers="virtual">
|
||||||
<return type="void" />
|
<return type="void" />
|
||||||
<param index="0" name="features" type="PackedStringArray" />
|
<param index="0" name="features" type="PackedStringArray" />
|
||||||
@ -36,6 +81,18 @@
|
|||||||
Calling [method skip] inside this callback will make the file not included in the export.
|
Calling [method skip] inside this callback will make the file not included in the export.
|
||||||
</description>
|
</description>
|
||||||
</method>
|
</method>
|
||||||
|
<method name="_get_customization_configuration_hash" qualifiers="virtual const">
|
||||||
|
<return type="int" />
|
||||||
|
<description>
|
||||||
|
Return a hash based on the configuration passed (for both scenes and resources). This helps keep separate caches for separate export configurations.
|
||||||
|
</description>
|
||||||
|
</method>
|
||||||
|
<method name="_get_name" qualifiers="virtual const">
|
||||||
|
<return type="String" />
|
||||||
|
<description>
|
||||||
|
Return the name identifier of this plugin (for future identification by the exporter).
|
||||||
|
</description>
|
||||||
|
</method>
|
||||||
<method name="add_file">
|
<method name="add_file">
|
||||||
<return type="void" />
|
<return type="void" />
|
||||||
<param index="0" name="path" type="String" />
|
<param index="0" name="path" type="String" />
|
||||||
|
@ -4107,6 +4107,7 @@ void EditorNode::register_editor_types() {
|
|||||||
GDREGISTER_CLASS(EditorSyntaxHighlighter);
|
GDREGISTER_CLASS(EditorSyntaxHighlighter);
|
||||||
GDREGISTER_ABSTRACT_CLASS(EditorInterface);
|
GDREGISTER_ABSTRACT_CLASS(EditorInterface);
|
||||||
GDREGISTER_CLASS(EditorExportPlugin);
|
GDREGISTER_CLASS(EditorExportPlugin);
|
||||||
|
GDREGISTER_ABSTRACT_CLASS(EditorExportPlatform);
|
||||||
GDREGISTER_CLASS(EditorResourceConversionPlugin);
|
GDREGISTER_CLASS(EditorResourceConversionPlugin);
|
||||||
GDREGISTER_CLASS(EditorSceneFormatImporter);
|
GDREGISTER_CLASS(EditorSceneFormatImporter);
|
||||||
GDREGISTER_CLASS(EditorScenePostImportPlugin);
|
GDREGISTER_CLASS(EditorScenePostImportPlugin);
|
||||||
@ -7418,11 +7419,6 @@ EditorNode::EditorNode() {
|
|||||||
editor_plugins_force_over = memnew(EditorPluginList);
|
editor_plugins_force_over = memnew(EditorPluginList);
|
||||||
editor_plugins_force_input_forwarding = memnew(EditorPluginList);
|
editor_plugins_force_input_forwarding = memnew(EditorPluginList);
|
||||||
|
|
||||||
Ref<EditorExportTextSceneToBinaryPlugin> export_text_to_binary_plugin;
|
|
||||||
export_text_to_binary_plugin.instantiate();
|
|
||||||
|
|
||||||
EditorExport::get_singleton()->add_export_plugin(export_text_to_binary_plugin);
|
|
||||||
|
|
||||||
Ref<GDExtensionExportPlugin> gdextension_export_plugin;
|
Ref<GDExtensionExportPlugin> gdextension_export_plugin;
|
||||||
gdextension_export_plugin.instantiate();
|
gdextension_export_plugin.instantiate();
|
||||||
|
|
||||||
|
@ -351,6 +351,8 @@ EditorExport::EditorExport() {
|
|||||||
|
|
||||||
singleton = this;
|
singleton = this;
|
||||||
set_process(true);
|
set_process(true);
|
||||||
|
|
||||||
|
GLOBAL_DEF("editor/export/convert_text_resources_to_binary", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
EditorExport::~EditorExport() {
|
EditorExport::~EditorExport() {
|
||||||
|
@ -44,6 +44,7 @@
|
|||||||
#include "editor/editor_settings.h"
|
#include "editor/editor_settings.h"
|
||||||
#include "editor/plugins/script_editor_plugin.h"
|
#include "editor/plugins/script_editor_plugin.h"
|
||||||
#include "editor_export_plugin.h"
|
#include "editor_export_plugin.h"
|
||||||
|
#include "scene/resources/packed_scene.h"
|
||||||
|
|
||||||
static int _get_pad(int p_alignment, int p_n) {
|
static int _get_pad(int p_alignment, int p_n) {
|
||||||
int rest = p_n % p_alignment;
|
int rest = p_n % p_alignment;
|
||||||
@ -488,6 +489,295 @@ EditorExportPlatform::ExportNotifier::~ExportNotifier() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool EditorExportPlatform::_export_customize_dictionary(Dictionary &dict, LocalVector<Ref<EditorExportPlugin>> &customize_resources_plugins) {
|
||||||
|
bool changed = false;
|
||||||
|
|
||||||
|
List<Variant> keys;
|
||||||
|
dict.get_key_list(&keys);
|
||||||
|
for (const Variant &K : keys) {
|
||||||
|
Variant v = dict[K];
|
||||||
|
switch (v.get_type()) {
|
||||||
|
case Variant::OBJECT: {
|
||||||
|
Ref<Resource> res = v;
|
||||||
|
if (res.is_valid()) {
|
||||||
|
for (uint32_t j = 0; j < customize_resources_plugins.size(); j++) {
|
||||||
|
Ref<Resource> new_res = customize_resources_plugins[j]->_customize_resource(res, "");
|
||||||
|
if (new_res.is_valid()) {
|
||||||
|
changed = true;
|
||||||
|
if (new_res != res) {
|
||||||
|
dict[K] = new_res;
|
||||||
|
res = new_res;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If it was not replaced, go through and see if there is something to replace.
|
||||||
|
if (res.is_valid() && !res->get_path().is_resource_file() && _export_customize_object(res.ptr(), customize_resources_plugins), true) {
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} break;
|
||||||
|
case Variant::DICTIONARY: {
|
||||||
|
Dictionary d = v;
|
||||||
|
if (_export_customize_dictionary(d, customize_resources_plugins)) {
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
case Variant::ARRAY: {
|
||||||
|
Array a = v;
|
||||||
|
if (_export_customize_array(a, customize_resources_plugins)) {
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
default: {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return changed;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool EditorExportPlatform::_export_customize_array(Array &arr, LocalVector<Ref<EditorExportPlugin>> &customize_resources_plugins) {
|
||||||
|
bool changed = false;
|
||||||
|
|
||||||
|
for (int i = 0; i < arr.size(); i++) {
|
||||||
|
Variant v = arr.get(i);
|
||||||
|
switch (v.get_type()) {
|
||||||
|
case Variant::OBJECT: {
|
||||||
|
Ref<Resource> res = v;
|
||||||
|
if (res.is_valid()) {
|
||||||
|
for (uint32_t j = 0; j < customize_resources_plugins.size(); j++) {
|
||||||
|
Ref<Resource> new_res = customize_resources_plugins[j]->_customize_resource(res, "");
|
||||||
|
if (new_res.is_valid()) {
|
||||||
|
changed = true;
|
||||||
|
if (new_res != res) {
|
||||||
|
arr.set(i, new_res);
|
||||||
|
res = new_res;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If it was not replaced, go through and see if there is something to replace.
|
||||||
|
if (res.is_valid() && !res->get_path().is_resource_file() && _export_customize_object(res.ptr(), customize_resources_plugins), true) {
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
case Variant::DICTIONARY: {
|
||||||
|
Dictionary d = v;
|
||||||
|
if (_export_customize_dictionary(d, customize_resources_plugins)) {
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
case Variant::ARRAY: {
|
||||||
|
Array a = v;
|
||||||
|
if (_export_customize_array(a, customize_resources_plugins)) {
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
default: {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return changed;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool EditorExportPlatform::_export_customize_object(Object *p_object, LocalVector<Ref<EditorExportPlugin>> &customize_resources_plugins) {
|
||||||
|
bool changed = false;
|
||||||
|
|
||||||
|
List<PropertyInfo> props;
|
||||||
|
p_object->get_property_list(&props);
|
||||||
|
for (const PropertyInfo &E : props) {
|
||||||
|
switch (E.type) {
|
||||||
|
case Variant::OBJECT: {
|
||||||
|
Ref<Resource> res = p_object->get(E.name);
|
||||||
|
if (res.is_valid()) {
|
||||||
|
for (uint32_t j = 0; j < customize_resources_plugins.size(); j++) {
|
||||||
|
Ref<Resource> new_res = customize_resources_plugins[j]->_customize_resource(res, "");
|
||||||
|
if (new_res.is_valid()) {
|
||||||
|
changed = true;
|
||||||
|
if (new_res != res) {
|
||||||
|
p_object->set(E.name, new_res);
|
||||||
|
res = new_res;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If it was not replaced, go through and see if there is something to replace.
|
||||||
|
if (res.is_valid() && !res->get_path().is_resource_file() && _export_customize_object(res.ptr(), customize_resources_plugins), true) {
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} break;
|
||||||
|
case Variant::DICTIONARY: {
|
||||||
|
Dictionary d = p_object->get(E.name);
|
||||||
|
if (_export_customize_dictionary(d, customize_resources_plugins)) {
|
||||||
|
// May have been generated, so set back just in case
|
||||||
|
p_object->set(E.name, d);
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
case Variant::ARRAY: {
|
||||||
|
Array a = p_object->get(E.name);
|
||||||
|
if (_export_customize_array(a, customize_resources_plugins)) {
|
||||||
|
// May have been generated, so set back just in case
|
||||||
|
p_object->set(E.name, a);
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
default: {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return changed;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool EditorExportPlatform::_export_customize_scene_resources(Node *p_root, Node *p_node, LocalVector<Ref<EditorExportPlugin>> &customize_resources_plugins) {
|
||||||
|
bool changed = false;
|
||||||
|
|
||||||
|
if (p_node == p_root || p_node->get_owner() == p_root) {
|
||||||
|
if (_export_customize_object(p_node, customize_resources_plugins)) {
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < p_node->get_child_count(); i++) {
|
||||||
|
if (_export_customize_scene_resources(p_root, p_node->get_child(i), customize_resources_plugins)) {
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return changed;
|
||||||
|
}
|
||||||
|
|
||||||
|
String EditorExportPlatform::_export_customize(const String &p_path, LocalVector<Ref<EditorExportPlugin>> &customize_resources_plugins, LocalVector<Ref<EditorExportPlugin>> &customize_scenes_plugins, HashMap<String, FileExportCache> &export_cache, const String &export_base_path, bool p_force_save) {
|
||||||
|
if (!p_force_save && customize_resources_plugins.is_empty() && customize_scenes_plugins.is_empty()) {
|
||||||
|
return p_path; // do none
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if a cache exists
|
||||||
|
if (export_cache.has(p_path)) {
|
||||||
|
FileExportCache &fec = export_cache[p_path];
|
||||||
|
|
||||||
|
if (fec.saved_path.is_empty() || FileAccess::exists(fec.saved_path)) {
|
||||||
|
// Destination file exists (was not erased) or not needed
|
||||||
|
|
||||||
|
uint64_t mod_time = FileAccess::get_modified_time(p_path);
|
||||||
|
if (fec.source_modified_time == mod_time) {
|
||||||
|
// Cached (modified time matches).
|
||||||
|
fec.used = true;
|
||||||
|
return fec.saved_path.is_empty() ? p_path : fec.saved_path;
|
||||||
|
}
|
||||||
|
|
||||||
|
String md5 = FileAccess::get_md5(p_path);
|
||||||
|
if (FileAccess::exists(p_path + ".import")) {
|
||||||
|
// Also consider the import file in the string
|
||||||
|
md5 += FileAccess::get_md5(p_path + ".import");
|
||||||
|
}
|
||||||
|
if (fec.source_md5 == md5) {
|
||||||
|
// Cached (md5 matches).
|
||||||
|
fec.source_modified_time = mod_time;
|
||||||
|
fec.used = true;
|
||||||
|
return fec.saved_path.is_empty() ? p_path : fec.saved_path;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FileExportCache fec;
|
||||||
|
fec.used = true;
|
||||||
|
fec.source_modified_time = FileAccess::get_modified_time(p_path);
|
||||||
|
|
||||||
|
String md5 = FileAccess::get_md5(p_path);
|
||||||
|
if (FileAccess::exists(p_path + ".import")) {
|
||||||
|
// Also consider the import file in the string
|
||||||
|
md5 += FileAccess::get_md5(p_path + ".import");
|
||||||
|
}
|
||||||
|
|
||||||
|
fec.source_md5 = md5;
|
||||||
|
|
||||||
|
// Check if it should convert
|
||||||
|
|
||||||
|
String type = ResourceLoader::get_resource_type(p_path);
|
||||||
|
|
||||||
|
bool modified = false;
|
||||||
|
|
||||||
|
String save_path;
|
||||||
|
|
||||||
|
if (type == "PackedScene") { // Its a scene.
|
||||||
|
Ref<PackedScene> ps = ResourceLoader::load(p_path, "PackedScene", ResourceFormatLoader::CACHE_MODE_IGNORE);
|
||||||
|
ERR_FAIL_COND_V(ps.is_null(), p_path);
|
||||||
|
Node *node = ps->instantiate();
|
||||||
|
ERR_FAIL_COND_V(node == nullptr, p_path);
|
||||||
|
if (customize_scenes_plugins.size()) {
|
||||||
|
for (uint32_t i = 0; i < customize_scenes_plugins.size(); i++) {
|
||||||
|
Node *customized = customize_scenes_plugins[i]->_customize_scene(node, p_path);
|
||||||
|
if (customized != nullptr) {
|
||||||
|
node = customized;
|
||||||
|
modified = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (customize_resources_plugins.size()) {
|
||||||
|
if (_export_customize_scene_resources(node, node, customize_resources_plugins)) {
|
||||||
|
modified = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (modified || p_force_save) {
|
||||||
|
// If modified, save it again. This is also used for TSCN -> SCN conversion on export.
|
||||||
|
|
||||||
|
String base_file = p_path.get_file().get_basename() + ".scn"; // use SCN for saving (binary) and repack (If conversting, TSCN PackedScene representation is inefficient, so repacking is also desired).
|
||||||
|
save_path = export_base_path.path_join("export-" + p_path.md5_text() + "-" + base_file);
|
||||||
|
|
||||||
|
Ref<PackedScene> s;
|
||||||
|
s.instantiate();
|
||||||
|
s->pack(node);
|
||||||
|
Error err = ResourceSaver::save(s, save_path);
|
||||||
|
ERR_FAIL_COND_V_MSG(err != OK, p_path, "Unable to save export scene file to: " + save_path);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Ref<Resource> res = ResourceLoader::load(p_path, "", ResourceFormatLoader::CACHE_MODE_IGNORE);
|
||||||
|
ERR_FAIL_COND_V(res.is_null(), p_path);
|
||||||
|
|
||||||
|
if (customize_resources_plugins.size()) {
|
||||||
|
for (uint32_t i = 0; i < customize_resources_plugins.size(); i++) {
|
||||||
|
Ref<Resource> new_res = customize_resources_plugins[i]->_customize_resource(res, p_path);
|
||||||
|
if (new_res.is_valid()) {
|
||||||
|
modified = true;
|
||||||
|
if (new_res != res) {
|
||||||
|
res = new_res;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_export_customize_object(res.ptr(), customize_resources_plugins)) {
|
||||||
|
modified = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (modified || p_force_save) {
|
||||||
|
// If modified, save it again. This is also used for TRES -> RES conversion on export.
|
||||||
|
|
||||||
|
String base_file = p_path.get_file().get_basename() + ".res"; // use RES for saving (binary)
|
||||||
|
save_path = export_base_path.path_join("export-" + p_path.md5_text() + "-" + base_file);
|
||||||
|
|
||||||
|
Error err = ResourceSaver::save(res, save_path);
|
||||||
|
ERR_FAIL_COND_V_MSG(err != OK, p_path, "Unable to save export resource file to: " + save_path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fec.saved_path = save_path;
|
||||||
|
|
||||||
|
export_cache[p_path] = fec;
|
||||||
|
|
||||||
|
return save_path.is_empty() ? p_path : save_path;
|
||||||
|
}
|
||||||
|
|
||||||
Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> &p_preset, bool p_debug, EditorExportSaveFunction p_func, void *p_udata, EditorExportSaveSharedObject p_so_func) {
|
Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> &p_preset, bool p_debug, EditorExportSaveFunction p_func, void *p_udata, EditorExportSaveSharedObject p_so_func) {
|
||||||
//figure out paths of files that will be exported
|
//figure out paths of files that will be exported
|
||||||
HashSet<String> paths;
|
HashSet<String> paths;
|
||||||
@ -601,6 +891,15 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> &
|
|||||||
Error err = OK;
|
Error err = OK;
|
||||||
Vector<Ref<EditorExportPlugin>> export_plugins = EditorExport::get_singleton()->get_export_plugins();
|
Vector<Ref<EditorExportPlugin>> export_plugins = EditorExport::get_singleton()->get_export_plugins();
|
||||||
|
|
||||||
|
struct SortByName {
|
||||||
|
bool operator()(const Ref<EditorExportPlugin> &left, const Ref<EditorExportPlugin> &right) const {
|
||||||
|
return left->_get_name() < right->_get_name();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Always sort by name, to so if for some reason theya are re-arranged, it still works.
|
||||||
|
export_plugins.sort_custom<SortByName>();
|
||||||
|
|
||||||
for (int i = 0; i < export_plugins.size(); i++) {
|
for (int i = 0; i < export_plugins.size(); i++) {
|
||||||
export_plugins.write[i]->set_export_preset(p_preset);
|
export_plugins.write[i]->set_export_preset(p_preset);
|
||||||
|
|
||||||
@ -623,6 +922,65 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> &
|
|||||||
}
|
}
|
||||||
|
|
||||||
HashSet<String> features = get_features(p_preset, p_debug);
|
HashSet<String> features = get_features(p_preset, p_debug);
|
||||||
|
PackedStringArray features_psa;
|
||||||
|
for (const String &feature : features) {
|
||||||
|
features_psa.push_back(feature);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if custom processing is needed
|
||||||
|
uint32_t custom_resources_hash = HASH_MURMUR3_SEED;
|
||||||
|
uint32_t custom_scene_hash = HASH_MURMUR3_SEED;
|
||||||
|
|
||||||
|
LocalVector<Ref<EditorExportPlugin>> customize_resources_plugins;
|
||||||
|
LocalVector<Ref<EditorExportPlugin>> customize_scenes_plugins;
|
||||||
|
|
||||||
|
for (int i = 0; i < export_plugins.size(); i++) {
|
||||||
|
if (export_plugins[i]->_begin_customize_resources(Ref<EditorExportPlatform>(this), features_psa)) {
|
||||||
|
customize_resources_plugins.push_back(export_plugins[i]);
|
||||||
|
|
||||||
|
custom_resources_hash = hash_murmur3_one_64(export_plugins[i]->_get_name().hash64(), custom_resources_hash);
|
||||||
|
uint64_t hash = export_plugins[i]->_get_customization_configuration_hash();
|
||||||
|
custom_resources_hash = hash_murmur3_one_64(hash, custom_resources_hash);
|
||||||
|
}
|
||||||
|
if (export_plugins[i]->_begin_customize_scenes(Ref<EditorExportPlatform>(this), features_psa)) {
|
||||||
|
customize_scenes_plugins.push_back(export_plugins[i]);
|
||||||
|
|
||||||
|
custom_resources_hash = hash_murmur3_one_64(export_plugins[i]->_get_name().hash64(), custom_resources_hash);
|
||||||
|
uint64_t hash = export_plugins[i]->_get_customization_configuration_hash();
|
||||||
|
custom_scene_hash = hash_murmur3_one_64(hash, custom_scene_hash);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
HashMap<String, FileExportCache> export_cache;
|
||||||
|
String export_base_path = ProjectSettings::get_singleton()->get_project_data_path().path_join("exported/") + itos(custom_resources_hash);
|
||||||
|
|
||||||
|
bool convert_text_to_binary = GLOBAL_GET("editor/export/convert_text_resources_to_binary");
|
||||||
|
|
||||||
|
if (convert_text_to_binary || customize_resources_plugins.size() || customize_scenes_plugins.size()) {
|
||||||
|
// See if we have something to open
|
||||||
|
Ref<FileAccess> f = FileAccess::open(export_base_path.path_join("file_cache"), FileAccess::READ);
|
||||||
|
if (f.is_valid()) {
|
||||||
|
String l = f->get_line();
|
||||||
|
while (l != String()) {
|
||||||
|
Vector<String> fields = l.split("::");
|
||||||
|
if (fields.size() == 4) {
|
||||||
|
FileExportCache fec;
|
||||||
|
String path = fields[0];
|
||||||
|
fec.source_md5 = fields[1].strip_edges();
|
||||||
|
fec.source_modified_time = fields[2].strip_edges().to_int();
|
||||||
|
fec.saved_path = fields[3];
|
||||||
|
fec.used = false; // Assume unused until used.
|
||||||
|
export_cache[path] = fec;
|
||||||
|
}
|
||||||
|
l = f->get_line();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// create the path
|
||||||
|
Ref<DirAccess> d = DirAccess::create(DirAccess::ACCESS_RESOURCES);
|
||||||
|
d->change_dir(ProjectSettings::get_singleton()->get_project_data_path());
|
||||||
|
d->make_dir_recursive("exported/" + itos(custom_resources_hash));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//store everything in the export medium
|
//store everything in the export medium
|
||||||
int idx = 0;
|
int idx = 0;
|
||||||
@ -633,7 +991,56 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> &
|
|||||||
String type = ResourceLoader::get_resource_type(path);
|
String type = ResourceLoader::get_resource_type(path);
|
||||||
|
|
||||||
if (FileAccess::exists(path + ".import")) {
|
if (FileAccess::exists(path + ".import")) {
|
||||||
//file is imported, replace by what it imports
|
// Before doing this, try to see if it can be customized
|
||||||
|
|
||||||
|
String export_path = _export_customize(path, customize_resources_plugins, customize_scenes_plugins, export_cache, export_base_path, false);
|
||||||
|
|
||||||
|
if (export_path != path) {
|
||||||
|
// It was actually customized..
|
||||||
|
// Since the original file is likely not recognized, just use the import system
|
||||||
|
|
||||||
|
Ref<ConfigFile> config;
|
||||||
|
config.instantiate();
|
||||||
|
err = config->load(path + ".import");
|
||||||
|
if (err != OK) {
|
||||||
|
ERR_PRINT("Could not parse: '" + path + "', not exported.");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
config->set_value("remap", "type", ResourceLoader::get_resource_type(export_path));
|
||||||
|
|
||||||
|
// Erase all PAths
|
||||||
|
List<String> keys;
|
||||||
|
config->get_section_keys("remap", &keys);
|
||||||
|
for (const String &K : keys) {
|
||||||
|
if (E.begins_with("path")) {
|
||||||
|
config->erase_section_key("remap", K);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Set actual converted path.
|
||||||
|
config->set_value("remap", "path", export_path);
|
||||||
|
|
||||||
|
// erase useless sections
|
||||||
|
config->erase_section("deps");
|
||||||
|
config->erase_section("params");
|
||||||
|
|
||||||
|
String import_text = config->encode_to_text();
|
||||||
|
CharString cs = import_text.utf8();
|
||||||
|
Vector<uint8_t> sarr;
|
||||||
|
sarr.resize(cs.size());
|
||||||
|
memcpy(sarr.ptrw(), cs.ptr(), sarr.size());
|
||||||
|
|
||||||
|
err = p_func(p_udata, path + ".import", sarr, idx, total, enc_in_filters, enc_ex_filters, key);
|
||||||
|
if (err != OK) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
// Now actual remapped file:
|
||||||
|
sarr = FileAccess::get_file_as_array(export_path);
|
||||||
|
err = p_func(p_udata, export_path, sarr, idx, total, enc_in_filters, enc_ex_filters, key);
|
||||||
|
if (err != OK) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// file is imported and not customized, replace by what it imports
|
||||||
Ref<ConfigFile> config;
|
Ref<ConfigFile> config;
|
||||||
config.instantiate();
|
config.instantiate();
|
||||||
err = config->load(path + ".import");
|
err = config->load(path + ".import");
|
||||||
@ -703,15 +1110,14 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> &
|
|||||||
if (err != OK) {
|
if (err != OK) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
// Customize
|
||||||
|
|
||||||
bool do_export = true;
|
bool do_export = true;
|
||||||
for (int i = 0; i < export_plugins.size(); i++) {
|
for (int i = 0; i < export_plugins.size(); i++) {
|
||||||
if (export_plugins[i]->get_script_instance()) { //script based
|
if (export_plugins[i]->get_script_instance()) { //script based
|
||||||
PackedStringArray features_psa;
|
|
||||||
for (const String &feature : features) {
|
|
||||||
features_psa.push_back(feature);
|
|
||||||
}
|
|
||||||
export_plugins.write[i]->_export_file_script(path, type, features_psa);
|
export_plugins.write[i]->_export_file_script(path, type, features_psa);
|
||||||
} else {
|
} else {
|
||||||
export_plugins.write[i]->_export_file(path, type, features);
|
export_plugins.write[i]->_export_file(path, type, features);
|
||||||
@ -748,8 +1154,18 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> &
|
|||||||
}
|
}
|
||||||
//just store it as it comes
|
//just store it as it comes
|
||||||
if (do_export) {
|
if (do_export) {
|
||||||
Vector<uint8_t> array = FileAccess::get_file_as_array(path);
|
// Customization only happens if plugins did not take care of it before
|
||||||
err = p_func(p_udata, path, array, idx, total, enc_in_filters, enc_ex_filters, key);
|
bool force_binary = convert_text_to_binary && (path.get_extension().to_lower() == "tres" || path.get_extension().to_lower() == "tscn");
|
||||||
|
String export_path = _export_customize(path, customize_resources_plugins, customize_scenes_plugins, export_cache, export_base_path, force_binary);
|
||||||
|
|
||||||
|
if (export_path != path) {
|
||||||
|
// Add a remap entry
|
||||||
|
path_remaps.push_back(path);
|
||||||
|
path_remaps.push_back(export_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector<uint8_t> array = FileAccess::get_file_as_array(export_path);
|
||||||
|
err = p_func(p_udata, export_path, array, idx, total, enc_in_filters, enc_ex_filters, key);
|
||||||
if (err != OK) {
|
if (err != OK) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
@ -759,6 +1175,31 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> &
|
|||||||
idx++;
|
idx++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (convert_text_to_binary || customize_resources_plugins.size() || customize_scenes_plugins.size()) {
|
||||||
|
// End scene customization
|
||||||
|
|
||||||
|
String fcache = export_base_path.path_join("file_cache");
|
||||||
|
Ref<FileAccess> f = FileAccess::open(fcache, FileAccess::WRITE);
|
||||||
|
|
||||||
|
if (f.is_valid()) {
|
||||||
|
for (const KeyValue<String, FileExportCache> &E : export_cache) {
|
||||||
|
if (E.value.used) { // May be old, unused
|
||||||
|
String l = E.key + "::" + E.value.source_md5 + "::" + itos(E.value.source_modified_time) + "::" + E.value.saved_path;
|
||||||
|
f->store_line(l);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ERR_PRINT("Error opening export file cache: " + fcache);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < customize_resources_plugins.size(); i++) {
|
||||||
|
customize_resources_plugins[i]->_end_customize_resources();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < customize_scenes_plugins.size(); i++) {
|
||||||
|
customize_scenes_plugins[i]->_end_customize_scenes();
|
||||||
|
}
|
||||||
|
}
|
||||||
//save config!
|
//save config!
|
||||||
|
|
||||||
Vector<String> custom_list;
|
Vector<String> custom_list;
|
||||||
|
@ -40,6 +40,8 @@ struct EditorProgress;
|
|||||||
#include "scene/gui/rich_text_label.h"
|
#include "scene/gui/rich_text_label.h"
|
||||||
#include "scene/main/node.h"
|
#include "scene/main/node.h"
|
||||||
|
|
||||||
|
class EditorExportPlugin;
|
||||||
|
|
||||||
class EditorExportPlatform : public RefCounted {
|
class EditorExportPlatform : public RefCounted {
|
||||||
GDCLASS(EditorExportPlatform, RefCounted);
|
GDCLASS(EditorExportPlatform, RefCounted);
|
||||||
|
|
||||||
@ -99,6 +101,20 @@ private:
|
|||||||
|
|
||||||
static Error _add_shared_object(void *p_userdata, const SharedObject &p_so);
|
static Error _add_shared_object(void *p_userdata, const SharedObject &p_so);
|
||||||
|
|
||||||
|
struct FileExportCache {
|
||||||
|
uint64_t source_modified_time = 0;
|
||||||
|
String source_md5;
|
||||||
|
String saved_path;
|
||||||
|
bool used = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool _export_customize_dictionary(Dictionary &dict, LocalVector<Ref<EditorExportPlugin>> &customize_resources_plugins);
|
||||||
|
bool _export_customize_array(Array &array, LocalVector<Ref<EditorExportPlugin>> &customize_resources_plugins);
|
||||||
|
bool _export_customize_object(Object *p_object, LocalVector<Ref<EditorExportPlugin>> &customize_resources_plugins);
|
||||||
|
bool _export_customize_scene_resources(Node *p_root, Node *p_node, LocalVector<Ref<EditorExportPlugin>> &customize_resources_plugins);
|
||||||
|
|
||||||
|
String _export_customize(const String &p_path, LocalVector<Ref<EditorExportPlugin>> &customize_resources_plugins, LocalVector<Ref<EditorExportPlugin>> &customize_scenes_plugins, HashMap<String, FileExportCache> &export_cache, const String &export_base_path, bool p_force_save);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
struct ExportNotifier {
|
struct ExportNotifier {
|
||||||
ExportNotifier(EditorExportPlatform &p_platform, const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags);
|
ExportNotifier(EditorExportPlatform &p_platform, const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags);
|
||||||
|
@ -138,6 +138,64 @@ void EditorExportPlugin::_export_end_script() {
|
|||||||
GDVIRTUAL_CALL(_export_end);
|
GDVIRTUAL_CALL(_export_end);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Customization
|
||||||
|
|
||||||
|
bool EditorExportPlugin::_begin_customize_resources(const Ref<EditorExportPlatform> &p_platform, const Vector<String> &p_features) const {
|
||||||
|
bool ret = false;
|
||||||
|
if (GDVIRTUAL_CALL(_begin_customize_resources, p_platform, p_features, ret)) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ref<Resource> EditorExportPlugin::_customize_resource(const Ref<Resource> &p_resource, const String &p_path) {
|
||||||
|
Ref<Resource> ret;
|
||||||
|
if (GDVIRTUAL_REQUIRED_CALL(_customize_resource, p_resource, p_path, ret)) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
return Ref<Resource>();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool EditorExportPlugin::_begin_customize_scenes(const Ref<EditorExportPlatform> &p_platform, const Vector<String> &p_features) const {
|
||||||
|
bool ret = false;
|
||||||
|
if (GDVIRTUAL_CALL(_begin_customize_scenes, p_platform, p_features, ret)) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Node *EditorExportPlugin::_customize_scene(Node *p_root, const String &p_path) {
|
||||||
|
Node *ret = nullptr;
|
||||||
|
if (GDVIRTUAL_REQUIRED_CALL(_customize_scene, p_root, p_path, ret)) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t EditorExportPlugin::_get_customization_configuration_hash() const {
|
||||||
|
uint64_t ret = 0;
|
||||||
|
if (GDVIRTUAL_REQUIRED_CALL(_get_customization_configuration_hash, ret)) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditorExportPlugin::_end_customize_scenes() {
|
||||||
|
GDVIRTUAL_CALL(_end_customize_scenes);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditorExportPlugin::_end_customize_resources() {
|
||||||
|
GDVIRTUAL_CALL(_end_customize_resources);
|
||||||
|
}
|
||||||
|
|
||||||
|
String EditorExportPlugin::_get_name() const {
|
||||||
|
String ret;
|
||||||
|
if (GDVIRTUAL_REQUIRED_CALL(_get_name, ret)) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
void EditorExportPlugin::_export_file(const String &p_path, const String &p_type, const HashSet<String> &p_features) {
|
void EditorExportPlugin::_export_file(const String &p_path, const String &p_type, const HashSet<String> &p_features) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -164,38 +222,20 @@ void EditorExportPlugin::_bind_methods() {
|
|||||||
GDVIRTUAL_BIND(_export_file, "path", "type", "features");
|
GDVIRTUAL_BIND(_export_file, "path", "type", "features");
|
||||||
GDVIRTUAL_BIND(_export_begin, "features", "is_debug", "path", "flags");
|
GDVIRTUAL_BIND(_export_begin, "features", "is_debug", "path", "flags");
|
||||||
GDVIRTUAL_BIND(_export_end);
|
GDVIRTUAL_BIND(_export_end);
|
||||||
|
|
||||||
|
GDVIRTUAL_BIND(_begin_customize_resources, "platform", "features");
|
||||||
|
GDVIRTUAL_BIND(_customize_resource, "resource", "path");
|
||||||
|
|
||||||
|
GDVIRTUAL_BIND(_begin_customize_scenes, "platform", "features");
|
||||||
|
GDVIRTUAL_BIND(_customize_scene, "scene", "path");
|
||||||
|
|
||||||
|
GDVIRTUAL_BIND(_get_customization_configuration_hash);
|
||||||
|
|
||||||
|
GDVIRTUAL_BIND(_end_customize_scenes);
|
||||||
|
GDVIRTUAL_BIND(_end_customize_resources);
|
||||||
|
|
||||||
|
GDVIRTUAL_BIND(_get_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
EditorExportPlugin::EditorExportPlugin() {
|
EditorExportPlugin::EditorExportPlugin() {
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////
|
|
||||||
|
|
||||||
void EditorExportTextSceneToBinaryPlugin::_export_file(const String &p_path, const String &p_type, const HashSet<String> &p_features) {
|
|
||||||
String extension = p_path.get_extension().to_lower();
|
|
||||||
if (extension != "tres" && extension != "tscn") {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool convert = GLOBAL_GET("editor/export/convert_text_resources_to_binary");
|
|
||||||
if (!convert) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
String tmp_path = EditorPaths::get_singleton()->get_cache_dir().path_join("tmpfile.res");
|
|
||||||
Error err = ResourceFormatLoaderText::convert_file_to_binary(p_path, tmp_path);
|
|
||||||
if (err != OK) {
|
|
||||||
DirAccess::remove_file_or_error(tmp_path);
|
|
||||||
ERR_FAIL();
|
|
||||||
}
|
|
||||||
Vector<uint8_t> data = FileAccess::get_file_as_array(tmp_path);
|
|
||||||
if (data.size() == 0) {
|
|
||||||
DirAccess::remove_file_or_error(tmp_path);
|
|
||||||
ERR_FAIL();
|
|
||||||
}
|
|
||||||
DirAccess::remove_file_or_error(tmp_path);
|
|
||||||
add_file(p_path + ".converted.res", data, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
EditorExportTextSceneToBinaryPlugin::EditorExportTextSceneToBinaryPlugin() {
|
|
||||||
GLOBAL_DEF("editor/export/convert_text_resources_to_binary", false);
|
|
||||||
}
|
|
||||||
|
@ -34,6 +34,7 @@
|
|||||||
#include "core/extension/native_extension.h"
|
#include "core/extension/native_extension.h"
|
||||||
#include "editor_export_preset.h"
|
#include "editor_export_preset.h"
|
||||||
#include "editor_export_shared_object.h"
|
#include "editor_export_shared_object.h"
|
||||||
|
#include "scene/main/node.h"
|
||||||
|
|
||||||
class EditorExportPlugin : public RefCounted {
|
class EditorExportPlugin : public RefCounted {
|
||||||
GDCLASS(EditorExportPlugin, RefCounted);
|
GDCLASS(EditorExportPlugin, RefCounted);
|
||||||
@ -77,6 +78,7 @@ class EditorExportPlugin : public RefCounted {
|
|||||||
macos_plugin_files.clear();
|
macos_plugin_files.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Export
|
||||||
void _export_file_script(const String &p_path, const String &p_type, const Vector<String> &p_features);
|
void _export_file_script(const String &p_path, const String &p_type, const Vector<String> &p_features);
|
||||||
void _export_begin_script(const Vector<String> &p_features, bool p_debug, const String &p_path, int p_flags);
|
void _export_begin_script(const Vector<String> &p_features, bool p_debug, const String &p_path, int p_flags);
|
||||||
void _export_end_script();
|
void _export_end_script();
|
||||||
@ -108,6 +110,31 @@ protected:
|
|||||||
GDVIRTUAL4(_export_begin, Vector<String>, bool, String, uint32_t)
|
GDVIRTUAL4(_export_begin, Vector<String>, bool, String, uint32_t)
|
||||||
GDVIRTUAL0(_export_end)
|
GDVIRTUAL0(_export_end)
|
||||||
|
|
||||||
|
GDVIRTUAL2RC(bool, _begin_customize_resources, const Ref<EditorExportPlatform> &, const Vector<String> &)
|
||||||
|
GDVIRTUAL2R(Ref<Resource>, _customize_resource, const Ref<Resource> &, String)
|
||||||
|
|
||||||
|
GDVIRTUAL2RC(bool, _begin_customize_scenes, const Ref<EditorExportPlatform> &, const Vector<String> &)
|
||||||
|
GDVIRTUAL2R(Node *, _customize_scene, Node *, String)
|
||||||
|
GDVIRTUAL0RC(uint64_t, _get_customization_configuration_hash)
|
||||||
|
|
||||||
|
GDVIRTUAL0(_end_customize_scenes)
|
||||||
|
GDVIRTUAL0(_end_customize_resources)
|
||||||
|
|
||||||
|
GDVIRTUAL0RC(String, _get_name)
|
||||||
|
|
||||||
|
bool _begin_customize_resources(const Ref<EditorExportPlatform> &p_platform, const Vector<String> &p_features) const; // Return true if this plugin does property export customization
|
||||||
|
Ref<Resource> _customize_resource(const Ref<Resource> &p_resource, const String &p_path); // If nothing is returned, it means do not touch (nothing changed). If something is returned (either the same or a different resource) it means changes are made.
|
||||||
|
|
||||||
|
bool _begin_customize_scenes(const Ref<EditorExportPlatform> &p_platform, const Vector<String> &p_features) const; // Return true if this plugin does property export customization
|
||||||
|
Node *_customize_scene(Node *p_root, const String &p_path); // Return true if a change was made
|
||||||
|
|
||||||
|
uint64_t _get_customization_configuration_hash() const; // Hash used for caching customized resources and scenes.
|
||||||
|
|
||||||
|
void _end_customize_scenes();
|
||||||
|
void _end_customize_resources();
|
||||||
|
|
||||||
|
virtual String _get_name() const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Vector<String> get_ios_frameworks() const;
|
Vector<String> get_ios_frameworks() const;
|
||||||
Vector<String> get_ios_embedded_frameworks() const;
|
Vector<String> get_ios_embedded_frameworks() const;
|
||||||
@ -121,12 +148,4 @@ public:
|
|||||||
EditorExportPlugin();
|
EditorExportPlugin();
|
||||||
};
|
};
|
||||||
|
|
||||||
class EditorExportTextSceneToBinaryPlugin : public EditorExportPlugin {
|
|
||||||
GDCLASS(EditorExportTextSceneToBinaryPlugin, EditorExportPlugin);
|
|
||||||
|
|
||||||
public:
|
|
||||||
virtual void _export_file(const String &p_path, const String &p_type, const HashSet<String> &p_features) override;
|
|
||||||
EditorExportTextSceneToBinaryPlugin();
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // EDITOR_EXPORT_PLUGIN_H
|
#endif // EDITOR_EXPORT_PLUGIN_H
|
||||||
|
@ -36,6 +36,7 @@
|
|||||||
class GDExtensionExportPlugin : public EditorExportPlugin {
|
class GDExtensionExportPlugin : public EditorExportPlugin {
|
||||||
protected:
|
protected:
|
||||||
virtual void _export_file(const String &p_path, const String &p_type, const HashSet<String> &p_features);
|
virtual void _export_file(const String &p_path, const String &p_type, const HashSet<String> &p_features);
|
||||||
|
virtual String _get_name() const { return "GDExtension"; }
|
||||||
};
|
};
|
||||||
|
|
||||||
void GDExtensionExportPlugin::_export_file(const String &p_path, const String &p_type, const HashSet<String> &p_features) {
|
void GDExtensionExportPlugin::_export_file(const String &p_path, const String &p_type, const HashSet<String> &p_features) {
|
||||||
|
@ -88,6 +88,8 @@ public:
|
|||||||
// TODO: Re-add compiled GDScript on export.
|
// TODO: Re-add compiled GDScript on export.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual String _get_name() const override { return "GDScript"; }
|
||||||
};
|
};
|
||||||
|
|
||||||
static void _editor_init() {
|
static void _editor_init() {
|
||||||
|
Loading…
Reference in New Issue
Block a user