Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Import at runtime from local file with spaces in the path #805

Open
andybak opened this issue Jan 21, 2025 · 5 comments
Open

Import at runtime from local file with spaces in the path #805

andybak opened this issue Jan 21, 2025 · 5 comments
Assignees

Comments

@andybak
Copy link

andybak commented Jan 21, 2025

Unless I'm misunderstanding something or having a moment of stupidity - UnityWebRequestLoader breaks because the relative path is url encoded (so spaces become %20) by GetFileFromUri but then the File.Exists check in LoadStreamAsync fails because it doesn't unencode the spaces

I looked at using FileLoader instead but there's no documentation and it has wildly different behaviour when running in the editor (even in play mode) so I'm not sure if this is the right direction.

  1. Should I be using UnityWebRequestLoader or FileLoader?
  2. Is FileLoader's execution path differences in the editor intentional? Why is it trying to use the AssetDatabase?
@andybak andybak changed the title Unity Runtime Import from local file with spaces in the path Import at runtime from local file with spaces in the path Jan 21, 2025
@hybridherbst
Copy link
Collaborator

hybridherbst commented Jan 21, 2025

I'm not sure I can follow –
can you provide reproduction steps (a file, a script, etc.) for what goes wrong?
We're testing many different cases, including complex/non-typical paths, and they should all work. If something doesn't, it's a bug.
Thanks!

The different loaders are partly legacy, partly because different scenarios have different requirements – e.g. in most cases UnityWebRequest is the right one at runtime, but in the editor we want to be able to defer to the AssetDatabase so that textures and buffers living next to a .gltf file can be resolved from there, and so on.

@andybak
Copy link
Author

andybak commented Jan 21, 2025

in most cases UnityWebRequest is the right one at runtime,

OK. That at least tells me that it's probably an issue at my end rather than me just misunderstanding what loader to use.

I'll dig a bit deeper. Closing this as it's most likely pebkac...

@andybak andybak closed this as completed Jan 21, 2025
@hybridherbst
Copy link
Collaborator

OK – let us know if run into further issues. I definitely don't want to rule out that we can improve things with the current loaders, or that there's still a case where we do it wrong.

@andybak
Copy link
Author

andybak commented Jan 23, 2025

So - after more testing, there's either a bug or some surprising behaviour that needs to be documented.

I have a file on disk with a space in the path. I am calling the importer thus:

GLTFSceneImporter gltf = new GLTFSceneImporter(localPath, options);

Now - the only choice I have at this stage is whether localPath should be urlencoded or not. Unfortunately the code inside UnityWebRequestLoader fails in both cases:

If I pass in a urlencoded path it gets double-escaped (The constructor code calls GetFileFromUri on the supplied path)

So I conclude that I must pass in an non-encoded path (i.e. spaces are still spaces and not %20)

If I do pass in a non-encoded path it goes via this code in VerifyDataLoader:

    _options.DataLoader = new UnityWebRequestLoader(URIHelper.GetDirectoryName(_gltfFileName));
    _gltfFileName = URIHelper.GetFileFromUri(new Uri(_gltfFileName));

Note that UnityWebRequestLoader is initialized with the unescaped directory path but _gltfFileName is set to the escaped filename because of code in GetFileFromUri.

Then we get to the following code in UnityWebRequestLoader:

    var path = Path.Combine(dir, relativeFilePath).Replace("\\","/");
    if (File.Exists(path)) path = "file://" + Path.GetFullPath(path);
    var request = UnityWebRequest.Get(path);
    var asyncOperation = request.SendWebRequest();

The "File.Exists" check fails because you're testing an encoded path against the file system. Therefore "file://" is not preprended
UnityWebRequest

At this point you have a path like "c:\My folder\my%20filename.gltf"

This always results in a 404 from UnityWebRequest

The only thing that works is:

  1. Unescape the whole path to avoid double escaping
  2. Prepend file:/// yourself

This is an odd mix of requirements - which combined with complexities in my codebase - took me a fairly long time to figure out.

@andybak andybak reopened this Jan 23, 2025
@hybridherbst
Copy link
Collaborator

Hi again, and thanks for the summary – we can take a look if we can improve this!

The only thing that works is:
Unescape the whole path to avoid double escaping
Prepend file:/// yourself

My understanding is that this is exactly how UnityWebRequest is supposed to be used, with unescaped paths and with file:// prepended if what you want to request is actually a file (compared to the http: or https: protocols). Not saying that this is a great design though :) and also agree that other cases where we can figure out intent should just "gracefully work", ideally.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants