godotengine / godot

Godot Engine – Multi-platform 2D and 3D game engine
https://godotengine.org
MIT License
90.93k stars 21.15k forks source link

Issues with ProjectSettings.load_resource_pack(pack) when running the project from the editor #19815

Open LikeLakers2 opened 6 years ago

LikeLakers2 commented 6 years ago

Godot version: v3.0.4 stable + PR 19708 (because it fixes my touchscreen issues)

OS/device including version: Surface Pro 4, running Windows 10 Home v1709 (Fall Creator's Update)

Issue description: ProjectSettings.load_resource_pack('pack.pck') seems to replace the entire res:// structure rather than add to it upon its first use (edit: only when running from the editor; see comment for details). After the first use, any new loads will add to the current file list.

To give you some examples (presume current_pack.pck is the game's main file pack):

# No load; or
ProjectSettings.load_resource_pack("current_pack.pck")
# Can load current_pack.pck's files (expected)
ProjectSettings.load_resource_pack("other_pack.pck")
# Will replace files
# Can't load files from current_pack.pck as the file list has been replaced (NOT expected)

In order to still have access to my main pack's files, I have to load my game's pck first:

ProjectSettings.load_resource_pack("current_pack.pck")
ProjectSettings.load_resource_pack("other_pack.pck")

# Will add other_pack.pck's files onto the file list (replacing any files that are already in current_pack.pck) (expected)
# Can load current_pack.pck's files as normal except where they've been replaced by other_pack.pck (expected)
# But now I need to load the current .pck over itself, which isn't fun. (NOT expected)

# At this point though, loading resource packs works the same:
# always adding/replacing files after the first load, rather than replacing them like the first load.

I would expect to be able to use ProjectSettings.load_resource_pack("other_pack.pck") alone and still have access to the files from current_pack.pck, without needing to load current_pack.pck over itself.

Steps to reproduce: N/A, though here is some code you can use to check the res:// structure after loading:

func _ready():
    # Should print normal directory structure
    print(dir_contents('res://'))

    # Is supposed to only append/replace files, but instead replaces the entire `res://` filesystem
    ProjectSettings.load_resource_pack("other_pack.pck")
    print(dir_contents('res://'))

    # But this brings it back to normal by reloading the original pack
    # Except this appends/replaces, which means inconsistent behavior!
    ProjectSettings.load_resource_pack("current_pack.pck")
    print(dir_contents('res://'))

func dir_contents(path):
    # taken from the docs and modified
    var dir = Directory.new()
    if dir.open(path) == OK:
        dir.list_dir_begin(true, false)
        var files = []
        var file_name = dir.get_next()
        while (file_name != ""):
            if (file_name == '.git') or (file_name == '.import'):
                pass
            elif dir.current_is_dir():
                for file in dir_contents(path + file_name + '/'):
                    files.append(file)
            else:
                files.append(path + file_name)
            file_name = dir.get_next()
        dir.list_dir_end()
        return files
    else:
        print("An error occurred when trying to access the path.")
        return []

Minimal reproduction project: N/A (you can use the demo project repository for this -- just export a couple or five to .pck files and replace current_pack.pck and other_pack.pck in the script above with appropriate paths)

eon-s commented 6 years ago

You cannot use directory with resource packs, files are there but the virtual filesystem lose references.

See #7845.

LikeLakers2 commented 6 years ago

I already checked this. The files aren't there unless I load the game's main .pck over top of itself, and even the global load() function fails to see the old assets.

Presume my main game pack (let's say current_pack.pck) has node1.tscn. If I load another .pck (let's say other_pack.pck) that doesn't have a node1.tscn, without first loading the main game pack over itself:

# No `ProjectSettings.load_resource_pack("current_pack.pck")` here!
ProjectSettings.load_resource_pack("other_pack.pck")

Then attempting to load('res://node1.tscn') will return a null object. I lose access to node1.tscn, even through load(), until I do this:

ProjectSettings.load_resource_pack("current_pack.pck")

At which point load('res://node1.tscn') will work again, and I'll still have access to other_pack.pck's files.

eon-s commented 6 years ago

Also related #17696 #16798

LikeLakers2 commented 6 years ago

16798 seems to be the closest to what issue I'm having. Though load() just doesn't work for me as I described in my comment above.

LikeLakers2 commented 6 years ago

It's been nearly a month since anything was done with this issue. Is it being marked as a bug? Or should I close it?

eon-s commented 6 years ago

Patience, some issues can be stalled longer and devs are now doing checks and tagging, etc. before alpha.

sxkod commented 6 years ago

I am up against the same hurdle. Anyone found a way round? I would like to have a menu/init scene at the root and then offer various scenes that can be downloaded as a zip from a server. I got everything set and can download, save in user:// etc. However once I do a load_resource_pack it overwrites the menu/init, so no way to go back to it again!

Any suggestions/work arounds or any update on fixes?

By the way, great engine, I keep finding new things that have a lot of thought behind them. It constantly surprises me with how well planned it is overall.

Thanks

sxkod commented 6 years ago

Don't mean to answer my own question but I found a way round for now. Not great but seem to work. As follows:

  1. game starts and loads user://menu.zip and changes in to menu.tscn
  2. menu offers and loads user://packN.zip and changes to packN.tscn
  3. Each packN.tscn has an option to quit and on quit, will load user://menu.zip and changes to menu.tscn again.

So essentially I could cycle between the menu and various loadable packs. However this probably won't let me use a single globals file for singletons. I guess one can store the necessary global data to user://transition_file and reload it on change.

Thanks

charliewhitfield commented 5 years ago

OK, Please register me as another developer who discovered this issue and (for now) has put modding on the back-burner.

Please, please, please...! I was a modder before I was a game developer. Let's have some love for modders! (Related issues: https://github.com/godotengine/godot/issues/22950, https://github.com/godotengine/godot/issues/7753)

LikeLakers2 commented 5 years ago

So I tested this today with a build of the master branch, and while the issue I described seems to occur when running a project from the editor... running an exported version of the project (I used godot_editor.exe --main-pack "path/to/exported.pck") seems to not have this issue? At least, using the code I placed under "Steps to Reproduce" seems to show that the file list is not replaced when running an exported version.

However, this still leaves the issue of why it happens when running the project from the editor.

I'm surprised (and admittedly, feel a little stupid) that I didn't think of trying an exported version before I made this issue -- or at any point before now.

EIREXE commented 4 years ago

So I tested this today with a build of the master branch, and while the issue I described seems to occur when running a project from the editor... running an exported version of the project (I used godot_editor.exe --main-pack "path/to/exported.pck") seems to not have this issue? At least, using the code I placed under "Steps to Reproduce" seems to show that the file list is not replaced when running an exported version.

However, this still leaves the issue of why it happens when running the project from the editor.

I'm surprised (and admittedly, feel a little stupid) that I didn't think of trying an exported version before I made this issue -- or at any point before now.

I know this is a late reply, but the reason why this works is that godot has no problem loading multiple pcks, the problem comes when you mix the editor filesystem type and pcks, that's when pcks replace the tree.

KoBeWi commented 3 years ago

Can anyone still reproduce this bug in Godot 3.2.3 or any later release?

If yes, please ensure that an up-to-date Minimal Reproduction Project (MRP) is included in this report (a MRP is a zipped Godot project with the minimal elements necessary to reliably trigger the bug). You can upload ZIP files in an issue comment with a drag and drop.

EIREXE commented 3 years ago

Can anyone still reproduce this bug in Godot 3.2.3 or any later release?

If yes, please ensure that an up-to-date Minimal Reproduction Project (MRP) is included in this report (a MRP is a zipped Godot project with the minimal elements necessary to reliably trigger the bug). You can upload ZIP files in an issue comment with a drag and drop.

It's not really a bug, it's a design problem, it's still present in 3.2.3

dioptryk commented 1 year ago

Issue is still present in 3.5.stable.mono. I think that solving this (if possible) would allow for some really useful scenarios. Let me explain:

I'm wrinting an RPG game with a few GBs of resources already. I expect much more. Currently, everything is present under a single folder. Since I'm the sole dev, from time to time I'm rewriting and remaking sizeable chunks of things. But, at the same time, some resources are fine as they are and I would like to prevent them from being reimported or changed by mistake, to not lose time. I just had a thought, why not simply pack some of my Item or Monster resources (just textures, models and sounds) into standalone PCKs, remove from res:// and load on startup? So almost like NuGet packages, but with resources.

Then boom - a single PCK, when loading from editor, made stuff in my main res:// structure unavailable. Well, I know it works if exported game, but it prevents development within the editor. Mind you, I don't need the resources to even be accessible IN the editor itself, I just need everything to be accessible from a game started in editor, as I have most things defined in JSON (so, for example, monsters.json defines a monster script and specifies resource paths).

The scenarios this allows are:

Of course, if one had access to resources in the packs from editor itself, it would be even better!

dioptryk commented 1 year ago

Actually, it seems mono version can deal with this easily! You just have to use .NET Framework's System.IO types (File and Directory) instead of Godot's, whenever you're running an editor build. For example, if I wanted to scan for my json files after loading a PCK in editor build, I'd get nothing. But it works if I just do this:

if (OS.HasFeature("editor"))
{
  directory = ProjectSettings.GlobalizePath("res://json_data");
  var files = System.IO.Directory.GetFiles(directory, "*.json", System.IO.SearchOption.AllDirectories);
  // blah blah
}
else
{
  // do classic stuff with Godot.Directory etc.
}

Works like a charm and now I can start moving most of my stuff to immutable PCKs. Great!

d10sfan commented 10 months ago

I'm also seeing this issue. I'd recommend that this be called out in the documentation such as:

As it's unclear from the docs about this behavior.

Is there any workaround for this to make it work in the editor? I'm trying to add mod loading to my game, and needing to do a full compile of the game to test each step would get painful.