Skip to content

Commit 5b17ac4

Browse files
committed
Implement a patch system.
1 parent f4b047a commit 5b17ac4

12 files changed

+414
-14
lines changed

core/io/file_access_pack.cpp

+19
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,25 @@ void PackedData::add_pack_source(PackSource *p_source) {
102102
}
103103
}
104104

105+
uint8_t *PackedData::get_file_hash(const String &p_path) {
106+
PathMD5 pmd5(p_path.md5_buffer());
107+
HashMap<PathMD5, PackedFile, PathMD5>::Iterator E = files.find(pmd5);
108+
if (!E) {
109+
return nullptr;
110+
}
111+
if (E->value.offset == 0) {
112+
return nullptr;
113+
}
114+
115+
return E->value.md5;
116+
}
117+
118+
void PackedData::clear() {
119+
files.clear();
120+
_free_packed_dirs(root);
121+
root = memnew(PackedDir);
122+
}
123+
105124
PackedData *PackedData::singleton = nullptr;
106125

107126
PackedData::PackedData() {

core/io/file_access_pack.h

+3
Original file line numberDiff line numberDiff line change
@@ -111,13 +111,16 @@ class PackedData {
111111
public:
112112
void add_pack_source(PackSource *p_source);
113113
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
114+
uint8_t *get_file_hash(const String &p_path);
114115

115116
void set_disabled(bool p_disabled) { disabled = p_disabled; }
116117
_FORCE_INLINE_ bool is_disabled() const { return disabled; }
117118

118119
static PackedData *get_singleton() { return singleton; }
119120
Error add_pack(const String &p_path, bool p_replace_files, uint64_t p_offset);
120121

122+
void clear();
123+
121124
_FORCE_INLINE_ Ref<FileAccess> try_open_path(const String &p_path);
122125
_FORCE_INLINE_ bool has_path(const String &p_path);
123126

editor/editor_node.cpp

+12-3
Original file line numberDiff line numberDiff line change
@@ -992,9 +992,17 @@ void EditorNode::_fs_changed() {
992992
export_preset->update_value_overrides();
993993
if (export_defer.pack_only) { // Only export .pck or .zip data pack.
994994
if (export_path.ends_with(".zip")) {
995-
err = platform->export_zip(export_preset, export_defer.debug, export_path);
995+
if (export_defer.patch) {
996+
err = platform->export_zip_patch(export_preset, export_defer.debug, export_path);
997+
} else {
998+
err = platform->export_zip(export_preset, export_defer.debug, export_path);
999+
}
9961000
} else if (export_path.ends_with(".pck")) {
997-
err = platform->export_pack(export_preset, export_defer.debug, export_path);
1001+
if (export_defer.patch) {
1002+
err = platform->export_patch(export_preset, export_defer.debug, export_path);
1003+
} else {
1004+
err = platform->export_pack(export_preset, export_defer.debug, export_path);
1005+
}
9981006
} else {
9991007
ERR_PRINT(vformat("Export path \"%s\" doesn't end with a supported extension.", export_path));
10001008
err = FAILED;
@@ -4886,12 +4894,13 @@ void EditorNode::_begin_first_scan() {
48864894
requested_first_scan = true;
48874895
}
48884896

4889-
Error EditorNode::export_preset(const String &p_preset, const String &p_path, bool p_debug, bool p_pack_only, bool p_android_build_template) {
4897+
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) {
48904898
export_defer.preset = p_preset;
48914899
export_defer.path = p_path;
48924900
export_defer.debug = p_debug;
48934901
export_defer.pack_only = p_pack_only;
48944902
export_defer.android_build_template = p_android_build_template;
4903+
export_defer.patch = p_patch;
48954904
cmdline_export_mode = true;
48964905
return OK;
48974906
}

editor/editor_node.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,7 @@ class EditorNode : public Node {
254254
bool debug = false;
255255
bool pack_only = false;
256256
bool android_build_template = false;
257+
bool patch = false;
257258
} export_defer;
258259

259260
static EditorNode *singleton;
@@ -845,7 +846,7 @@ class EditorNode : public Node {
845846

846847
void _copy_warning(const String &p_str);
847848

848-
Error export_preset(const String &p_preset, const String &p_path, bool p_debug, bool p_pack_only, bool p_android_build_template);
849+
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);
849850
bool is_project_exporting() const;
850851

851852
Control *get_gui_base() { return gui_base; }

editor/export/editor_export.cpp

+7
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,9 @@ void EditorExport::_save() {
8383
config->set_value(section, "include_filter", preset->get_include_filter());
8484
config->set_value(section, "exclude_filter", preset->get_exclude_filter());
8585
config->set_value(section, "export_path", preset->get_export_path());
86+
config->set_value(section, "patches", preset->get_patches());
87+
config->set_value(section, "disabled_patches", preset->get_disabled_patches());
88+
8689
config->set_value(section, "encryption_include_filters", preset->get_enc_in_filter());
8790
config->set_value(section, "encryption_exclude_filters", preset->get_enc_ex_filter());
8891
config->set_value(section, "encrypt_pck", preset->get_enc_pck());
@@ -294,6 +297,10 @@ void EditorExport::load_config() {
294297
preset->set_export_path(config->get_value(section, "export_path", ""));
295298
preset->set_script_export_mode(config->get_value(section, "script_export_mode", EditorExportPreset::MODE_SCRIPT_BINARY_TOKENS_COMPRESSED));
296299

300+
Vector<String> patches = config->get_value(section, "patches", Vector<String>());
301+
Vector<String> disabled_patches = config->get_value(section, "disabled_patches", Vector<String>());
302+
preset->set_patches(patches, disabled_patches);
303+
297304
if (config->has_section_key(section, "encrypt_pck")) {
298305
preset->set_enc_pck(config->get_value(section, "encrypt_pck"));
299306
}

editor/export/editor_export_platform.cpp

+79-5
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,34 @@ bool EditorExportPlatform::fill_log_messages(RichTextLabel *p_log, Error p_err)
167167
return has_messages;
168168
}
169169

170+
Error EditorExportPlatform::_load_patches(const Vector<String> &p_patches) {
171+
Error err = OK;
172+
if (!p_patches.is_empty()) {
173+
for (const String &path : p_patches) {
174+
err = PackedData::get_singleton()->add_pack(path, true, 0);
175+
if (err != OK) {
176+
add_message(EXPORT_MESSAGE_ERROR, TTR("Patch Creation"), vformat(TTR("Could not recognize pack file from path \"%s\"."), path));
177+
return err;
178+
}
179+
}
180+
}
181+
return err;
182+
}
183+
184+
bool EditorExportPlatform::_check_hash(const uint8_t *p_hash, const Vector<uint8_t> &p_data) {
185+
if (p_hash) {
186+
unsigned char hash[16];
187+
CryptoCore::md5(p_data.ptr(), p_data.size(), hash);
188+
for (int i = 0; i < 16; i++) {
189+
if (p_hash[i] != hash[i]) {
190+
return false;
191+
}
192+
}
193+
return true;
194+
}
195+
return false;
196+
}
197+
170198
void EditorExportPlatform::gen_debug_flags(Vector<String> &r_flags, int p_flags) {
171199
String host = EDITOR_GET("network/debug/remote_host");
172200
int remote_port = (int)EDITOR_GET("network/debug/remote_port");
@@ -219,6 +247,14 @@ void EditorExportPlatform::gen_debug_flags(Vector<String> &r_flags, int p_flags)
219247
}
220248
}
221249

250+
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) {
251+
return _save_pack(p_preset, p_debug, p_path, _save_pack_file, p_so_files, p_embed, r_embedded_start, r_embedded_size);
252+
}
253+
254+
Error EditorExportPlatform::save_zip(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path) {
255+
return _save_zip(p_preset, p_debug, p_path, _save_zip_file);
256+
}
257+
222258
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) {
223259
ERR_FAIL_COND_V_MSG(p_total < 1, ERR_PARAMETER_RANGE_ERROR, "Must select at least one file to export.");
224260

@@ -289,6 +325,14 @@ Error EditorExportPlatform::_save_pack_file(void *p_userdata, const String &p_pa
289325
return OK;
290326
}
291327

328+
Error EditorExportPlatform::_save_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) {
329+
if (_check_hash(PackedData::get_singleton()->get_file_hash(p_path), p_data)) {
330+
return OK;
331+
}
332+
333+
return _save_pack_file(p_userdata, p_path, p_data, p_file, p_total, p_enc_in_filters, p_enc_ex_filters, p_key);
334+
}
335+
292336
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) {
293337
ERR_FAIL_COND_V_MSG(p_total < 1, ERR_PARAMETER_RANGE_ERROR, "Must select at least one file to export.");
294338

@@ -319,6 +363,14 @@ Error EditorExportPlatform::_save_zip_file(void *p_userdata, const String &p_pat
319363
return OK;
320364
}
321365

366+
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) {
367+
if (_check_hash(PackedData::get_singleton()->get_file_hash(p_path), p_data)) {
368+
return OK;
369+
}
370+
371+
return _save_zip_file(p_userdata, p_path, p_data, p_file, p_total, p_enc_in_filters, p_enc_ex_filters, p_key);
372+
}
373+
322374
Ref<ImageTexture> EditorExportPlatform::get_option_icon(int p_index) const {
323375
Ref<Theme> theme = EditorNode::get_singleton()->get_editor_theme();
324376
ERR_FAIL_COND_V(theme.is_null(), Ref<ImageTexture>());
@@ -1544,7 +1596,7 @@ void EditorExportPlatform::zip_folder_recursive(zipFile &p_zip, const String &p_
15441596
da->list_dir_end();
15451597
}
15461598

1547-
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) {
1599+
Error EditorExportPlatform::_save_pack(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, EditorExportSaveFunction p_func, Vector<SharedObject> *p_so_files, bool p_embed, int64_t *r_embedded_start, int64_t *r_embedded_size) {
15481600
EditorProgress ep("savepack", TTR("Packing"), 102, true);
15491601

15501602
// Create the temporary export directory if it doesn't exist.
@@ -1563,13 +1615,13 @@ Error EditorExportPlatform::save_pack(const Ref<EditorExportPreset> &p_preset, b
15631615
pd.f = ftmp;
15641616
pd.so_files = p_so_files;
15651617

1566-
Error err = export_project_files(p_preset, p_debug, _save_pack_file, &pd, _add_shared_object);
1618+
Error err = export_project_files(p_preset, p_debug, p_func, &pd, _add_shared_object);
15671619

15681620
// Close temp file.
15691621
pd.f.unref();
15701622
ftmp.unref();
15711623

1572-
if (err != OK) {
1624+
if (err != OK || pd.file_ofs.is_empty()) {
15731625
DirAccess::remove_file_or_error(tmppath);
15741626
add_message(EXPORT_MESSAGE_ERROR, TTR("Save PCK"), TTR("Failed to export project files."));
15751627
return err;
@@ -1770,7 +1822,7 @@ Error EditorExportPlatform::save_pack(const Ref<EditorExportPreset> &p_preset, b
17701822
return OK;
17711823
}
17721824

1773-
Error EditorExportPlatform::save_zip(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path) {
1825+
Error EditorExportPlatform::_save_zip(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, EditorExportSaveFunction p_func) {
17741826
EditorProgress ep("savezip", TTR("Packing"), 102, true);
17751827

17761828
Ref<FileAccess> io_fa;
@@ -1781,7 +1833,7 @@ Error EditorExportPlatform::save_zip(const Ref<EditorExportPreset> &p_preset, bo
17811833
zd.ep = &ep;
17821834
zd.zip = zip;
17831835

1784-
Error err = export_project_files(p_preset, p_debug, _save_zip_file, &zd);
1836+
Error err = export_project_files(p_preset, p_debug, p_func, &zd);
17851837
if (err != OK && err != ERR_SKIP) {
17861838
add_message(EXPORT_MESSAGE_ERROR, TTR("Save ZIP"), TTR("Failed to export project files."));
17871839
}
@@ -1796,11 +1848,33 @@ Error EditorExportPlatform::export_pack(const Ref<EditorExportPreset> &p_preset,
17961848
return save_pack(p_preset, p_debug, p_path);
17971849
}
17981850

1851+
Error EditorExportPlatform::export_patch(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags) {
1852+
ExportNotifier notifier(*this, p_preset, p_debug, p_path, p_flags);
1853+
Error err = _load_patches(p_preset->get_enabled_patches());
1854+
if (err != OK) {
1855+
return err;
1856+
}
1857+
err = _save_pack(p_preset, p_debug, p_path, _save_patch_file);
1858+
PackedData::get_singleton()->clear();
1859+
return err;
1860+
}
1861+
17991862
Error EditorExportPlatform::export_zip(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags) {
18001863
ExportNotifier notifier(*this, p_preset, p_debug, p_path, p_flags);
18011864
return save_zip(p_preset, p_debug, p_path);
18021865
}
18031866

1867+
Error EditorExportPlatform::export_zip_patch(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags) {
1868+
ExportNotifier notifier(*this, p_preset, p_debug, p_path, p_flags);
1869+
Error err = _load_patches(p_preset->get_enabled_patches());
1870+
if (err != OK) {
1871+
return err;
1872+
}
1873+
err = _save_zip(p_preset, p_debug, p_path, _save_zip_patch_file);
1874+
PackedData::get_singleton()->clear();
1875+
return err;
1876+
}
1877+
18041878
void EditorExportPlatform::gen_export_flags(Vector<String> &r_flags, int p_flags) {
18051879
String host = EDITOR_GET("network/debug/remote_host");
18061880
int remote_port = (int)EDITOR_GET("network/debug/remote_port");

editor/export/editor_export_platform.h

+10
Original file line numberDiff line numberDiff line change
@@ -100,8 +100,16 @@ class EditorExportPlatform : public RefCounted {
100100
void _export_find_customized_resources(const Ref<EditorExportPreset> &p_preset, EditorFileSystemDirectory *p_dir, EditorExportPreset::FileExportMode p_mode, HashSet<String> &p_paths);
101101
void _export_find_dependencies(const String &p_path, HashSet<String> &p_paths);
102102

103+
Error _load_patches(const Vector<String> &p_patches);
104+
static bool _check_hash(const uint8_t *p_hash, const Vector<uint8_t> &p_data);
105+
106+
Error _save_pack(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, EditorExportSaveFunction p_func, Vector<SharedObject> *p_so_files = nullptr, bool p_embed = false, int64_t *r_embedded_start = nullptr, int64_t *r_embedded_size = nullptr);
107+
Error _save_zip(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, EditorExportSaveFunction p_func);
108+
103109
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);
110+
static Error _save_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);
104111
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);
112+
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);
105113

106114
void _edit_files_with_filter(Ref<DirAccess> &da, const Vector<String> &p_filters, HashSet<String> &r_list, bool exclude);
107115
void _edit_filter_list(HashSet<String> &r_list, const String &p_filter, bool exclude);
@@ -248,7 +256,9 @@ class EditorExportPlatform : public RefCounted {
248256
virtual List<String> get_binary_extensions(const Ref<EditorExportPreset> &p_preset) const = 0;
249257
virtual Error export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags = 0) = 0;
250258
virtual Error export_pack(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags = 0);
259+
virtual Error export_patch(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags = 0);
251260
virtual Error export_zip(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags = 0);
261+
virtual Error export_zip_patch(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags = 0);
252262
virtual void get_platform_features(List<String> *r_features) const = 0;
253263
virtual void resolve_platform_feature_priorities(const Ref<EditorExportPreset> &p_preset, HashSet<String> &p_features) = 0;
254264
virtual String get_debug_protocol() const { return "tcp://"; }

editor/export/editor_export_preset.cpp

+61
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,67 @@ EditorExportPreset::FileExportMode EditorExportPreset::get_file_export_mode(cons
324324
return p_default;
325325
}
326326

327+
void EditorExportPreset::add_patch(const String &p_path, bool p_enabled, int p_at_pos) {
328+
ERR_FAIL_COND_EDMSG(patches.has(p_path), vformat("Failed to add patch \"%s\". Patches must be unique.", p_path));
329+
330+
if (p_at_pos < 0) {
331+
patches.push_back(p_path);
332+
} else {
333+
patches.insert(p_at_pos, p_path);
334+
}
335+
336+
if (!p_enabled) {
337+
disabled_patches.push_back(p_path);
338+
}
339+
340+
EditorExport::singleton->save_presets();
341+
}
342+
343+
void EditorExportPreset::set_patch(int p_index, const String &p_path, bool p_enabled) {
344+
remove_patch(p_index);
345+
add_patch(p_path, p_enabled, p_index);
346+
EditorExport::singleton->save_presets();
347+
}
348+
349+
String EditorExportPreset::get_patch(int p_index) {
350+
ERR_FAIL_INDEX_V(p_index, patches.size(), String());
351+
return patches[p_index];
352+
}
353+
354+
void EditorExportPreset::remove_patch(int p_index) {
355+
ERR_FAIL_INDEX(p_index, patches.size());
356+
disabled_patches.erase(patches[p_index]);
357+
patches.remove_at(p_index);
358+
EditorExport::singleton->save_presets();
359+
}
360+
361+
void EditorExportPreset::set_patches(const Vector<String> &p_patches, const Vector<String> &p_disabled_patches) {
362+
patches = p_patches;
363+
disabled_patches = p_disabled_patches;
364+
}
365+
366+
Vector<String> EditorExportPreset::get_patches() const {
367+
return patches;
368+
}
369+
370+
Vector<String> EditorExportPreset::get_disabled_patches() const {
371+
return disabled_patches;
372+
}
373+
374+
bool EditorExportPreset::is_patch_enabled(const String &p_path) const {
375+
return !disabled_patches.has(p_path);
376+
}
377+
378+
Vector<String> EditorExportPreset::get_enabled_patches() const {
379+
Vector<String> res;
380+
for (const String &path : patches) {
381+
if (is_patch_enabled(path)) {
382+
res.push_back(path);
383+
}
384+
}
385+
return res;
386+
}
387+
327388
void EditorExportPreset::set_custom_features(const String &p_custom_features) {
328389
custom_features = p_custom_features;
329390
EditorExport::singleton->save_presets();

editor/export/editor_export_preset.h

+13
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,9 @@ class EditorExportPreset : public RefCounted {
7474
bool advanced_options_enabled = false;
7575
bool dedicated_server = false;
7676

77+
Vector<String> patches;
78+
Vector<String> disabled_patches;
79+
7780
friend class EditorExport;
7881
friend class EditorExportPlatform;
7982

@@ -144,6 +147,16 @@ class EditorExportPreset : public RefCounted {
144147
void set_exclude_filter(const String &p_exclude);
145148
String get_exclude_filter() const;
146149

150+
void add_patch(const String &p_path, bool p_enable = true, int p_at_pos = -1);
151+
void set_patch(int p_index, const String &p_path, bool p_enable);
152+
String get_patch(int p_index);
153+
void remove_patch(int p_index);
154+
void set_patches(const Vector<String> &p_patches, const Vector<String> &p_disabled_patches);
155+
Vector<String> get_patches() const;
156+
Vector<String> get_disabled_patches() const;
157+
bool is_patch_enabled(const String &p_path) const;
158+
Vector<String> get_enabled_patches() const;
159+
147160
void set_custom_features(const String &p_custom_features);
148161
String get_custom_features() const;
149162

0 commit comments

Comments
 (0)