Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 30 additions & 11 deletions core/config/project_settings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -472,13 +472,30 @@ void ProjectSettings::_emit_changed() {
emit_signal("settings_changed");
}

bool ProjectSettings::_load_resource_pack(const String &p_pack, bool p_replace_files, int p_offset) {
bool ProjectSettings::load_resource_pack(const String &p_pack, bool p_replace_files, int p_offset) {
return ProjectSettings::_load_resource_pack(p_pack, p_replace_files, p_offset, false);
}

bool ProjectSettings::_load_resource_pack(const String &p_pack, bool p_replace_files, int p_offset, bool p_main_pack) {
if (PackedData::get_singleton()->is_disabled()) {
return false;
}

bool ok = PackedData::get_singleton()->add_pack(p_pack, p_replace_files, p_offset) == OK;
if (p_pack == "res://") {
// Loading the resource directory as a pack source is reserved for internal use only.
return false;
}

if (!p_main_pack && !using_datapack && !OS::get_singleton()->get_resource_dir().is_empty()) {
// Add the project's resource file system to PackedData so directory access keeps working when
// the game is running without a main pack, like in the editor or on Android.
PackedData::get_singleton()->add_pack_source(memnew(PackedSourceDirectory));
PackedData::get_singleton()->add_pack("res://", false, 0);
DirAccess::make_default<DirAccessPack>(DirAccess::ACCESS_RESOURCES);
using_datapack = true;
}

bool ok = PackedData::get_singleton()->add_pack(p_pack, p_replace_files, p_offset) == OK;
if (!ok) {
return false;
}
Expand All @@ -491,9 +508,11 @@ bool ProjectSettings::_load_resource_pack(const String &p_pack, bool p_replace_f
ResourceUID::get_singleton()->load_from_cache(false);
}

//if data.pck is found, all directory access will be from here
DirAccess::make_default<DirAccessPack>(DirAccess::ACCESS_RESOURCES);
using_datapack = true;
// If the data pack was found, all directory access will be from here.
if (!using_datapack) {
DirAccess::make_default<DirAccessPack>(DirAccess::ACCESS_RESOURCES);
using_datapack = true;
}

return true;
}
Expand Down Expand Up @@ -572,7 +591,7 @@ Error ProjectSettings::_setup(const String &p_path, const String &p_main_pack, b
// Attempt with a user-defined main pack first

if (!p_main_pack.is_empty()) {
bool ok = _load_resource_pack(p_main_pack);
bool ok = _load_resource_pack(p_main_pack, false, 0, true);
ERR_FAIL_COND_V_MSG(!ok, ERR_CANT_OPEN, vformat("Cannot open resource pack '%s'.", p_main_pack));

Error err = _load_settings_text_or_binary("res://project.godot", "res://project.binary");
Expand All @@ -591,7 +610,7 @@ Error ProjectSettings::_setup(const String &p_path, const String &p_main_pack, b
// and if so, we attempt loading it at the end.

// Attempt with PCK bundled into executable.
bool found = _load_resource_pack(exec_path);
bool found = _load_resource_pack(exec_path, false, 0, true);

// Attempt with exec_name.pck.
// (This is the usual case when distributing a Godot game.)
Expand All @@ -607,20 +626,20 @@ Error ProjectSettings::_setup(const String &p_path, const String &p_main_pack, b
#ifdef MACOS_ENABLED
if (!found) {
// Attempt to load PCK from macOS .app bundle resources.
found = _load_resource_pack(OS::get_singleton()->get_bundle_resource_dir().path_join(exec_basename + ".pck")) || _load_resource_pack(OS::get_singleton()->get_bundle_resource_dir().path_join(exec_filename + ".pck"));
found = _load_resource_pack(OS::get_singleton()->get_bundle_resource_dir().path_join(exec_basename + ".pck"), false, 0, true) || _load_resource_pack(OS::get_singleton()->get_bundle_resource_dir().path_join(exec_filename + ".pck"), false, 0, true);
}
#endif

if (!found) {
// Try to load data pack at the location of the executable.
// As mentioned above, we have two potential names to attempt.
found = _load_resource_pack(exec_dir.path_join(exec_basename + ".pck")) || _load_resource_pack(exec_dir.path_join(exec_filename + ".pck"));
found = _load_resource_pack(exec_dir.path_join(exec_basename + ".pck"), false, 0, true) || _load_resource_pack(exec_dir.path_join(exec_filename + ".pck"), false, 0, true);
}

if (!found) {
// If we couldn't find them next to the executable, we attempt
// the current working directory. Same story, two tests.
found = _load_resource_pack(exec_basename + ".pck") || _load_resource_pack(exec_filename + ".pck");
found = _load_resource_pack(exec_basename + ".pck", false, 0, true) || _load_resource_pack(exec_filename + ".pck", false, 0, true);
}

// If we opened our package, try and load our project.
Expand Down Expand Up @@ -1418,7 +1437,7 @@ void ProjectSettings::_bind_methods() {
ClassDB::bind_method(D_METHOD("localize_path", "path"), &ProjectSettings::localize_path);
ClassDB::bind_method(D_METHOD("globalize_path", "path"), &ProjectSettings::globalize_path);
ClassDB::bind_method(D_METHOD("save"), &ProjectSettings::save);
ClassDB::bind_method(D_METHOD("load_resource_pack", "pack", "replace_files", "offset"), &ProjectSettings::_load_resource_pack, DEFVAL(true), DEFVAL(0));
ClassDB::bind_method(D_METHOD("load_resource_pack", "pack", "replace_files", "offset"), &ProjectSettings::load_resource_pack, DEFVAL(true), DEFVAL(0));

ClassDB::bind_method(D_METHOD("save_custom", "file"), &ProjectSettings::_save_custom_bnd);

Expand Down
3 changes: 2 additions & 1 deletion core/config/project_settings.h
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,8 @@ class ProjectSettings : public Object {

void _convert_to_last_version(int p_from_version);

bool _load_resource_pack(const String &p_pack, bool p_replace_files = true, int p_offset = 0);
bool load_resource_pack(const String &p_pack, bool p_replace_files, int p_offset);
bool _load_resource_pack(const String &p_pack, bool p_replace_files = true, int p_offset = 0, bool p_main_pack = false);

void _add_property_info_bind(const Dictionary &p_info);

Expand Down
38 changes: 38 additions & 0 deletions core/io/file_access_pack.cpp

This comment was marked as resolved.

Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,44 @@ Ref<FileAccess> PackedSourcePCK::get_file(const String &p_path, PackedData::Pack

//////////////////////////////////////////////////////////////////

bool PackedSourceDirectory::try_open_pack(const String &p_path, bool p_replace_files, uint64_t p_offset) {
// Load with offset feature only supported for PCK files.
ERR_FAIL_COND_V_MSG(p_offset != 0, false, "Invalid PCK data. Note that loading files with a non-zero offset isn't supported with directories.");

if (p_path != "res://") {
return false;
}
add_directory(p_path, p_replace_files);
return true;
}

Ref<FileAccess> PackedSourceDirectory::get_file(const String &p_path, PackedData::PackedFile *p_file) {
Ref<FileAccess> ret = FileAccess::create_for_path(p_path);
ret->reopen(p_path, FileAccess::READ);
return ret;
}

void PackedSourceDirectory::add_directory(const String &p_path, bool p_replace_files) {
Ref<DirAccess> da = DirAccess::open(p_path);
if (da.is_null()) {
return;
}
da->set_include_hidden(true);

for (const String &file_name : da->get_files()) {
String file_path = p_path.path_join(file_name);
uint8_t md5[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
PackedData::get_singleton()->add_path(p_path, file_path, 0, 0, md5, this, p_replace_files, false);
}

for (const String &sub_dir_name : da->get_directories()) {
String sub_dir_path = p_path.path_join(sub_dir_name);
add_directory(sub_dir_path, p_replace_files);
}
}

//////////////////////////////////////////////////////////////////

Error FileAccessPack::open_internal(const String &p_path, int p_mode_flags) {
ERR_PRINT("Can't open pack-referenced file.");
return ERR_UNAVAILABLE;
Expand Down
8 changes: 8 additions & 0 deletions core/io/file_access_pack.h
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,14 @@ class PackedSourcePCK : public PackSource {
virtual Ref<FileAccess> get_file(const String &p_path, PackedData::PackedFile *p_file) override;
};

class PackedSourceDirectory : public PackSource {
void add_directory(const String &p_path, bool p_replace_files);

public:
virtual bool try_open_pack(const String &p_path, bool p_replace_files, uint64_t p_offset) override;
virtual Ref<FileAccess> get_file(const String &p_path, PackedData::PackedFile *p_file) override;
};

class FileAccessPack : public FileAccess {
PackedData::PackedFile pf;

Expand Down
1 change: 1 addition & 0 deletions doc/classes/ProjectSettings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@
Loads the contents of the .pck or .zip file specified by [param pack] into the resource filesystem ([code]res://[/code]). Returns [code]true[/code] on success.
[b]Note:[/b] If a file from [param pack] shares the same path as a file already in the resource filesystem, any attempts to load that file will use the file from [param pack] unless [param replace_files] is set to [code]false[/code].
[b]Note:[/b] The optional [param offset] parameter can be used to specify the offset in bytes to the start of the resource pack. This is only supported for .pck files.
[b]Note:[/b] [DirAccess] will not show changes made to the contents of [code]res://[/code] after calling this function.
</description>
</method>
<method name="localize_path" qualifiers="const">
Expand Down