UnityGLTF icon indicating copy to clipboard operation
UnityGLTF copied to clipboard

Import at runtime from local file with spaces in the path

Open andybak opened this issue 10 months ago • 5 comments

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 avatar Jan 21 '25 13:01 andybak

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.

hybridherbst avatar Jan 21 '25 15:01 hybridherbst

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 avatar Jan 21 '25 15:01 andybak

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.

hybridherbst avatar Jan 21 '25 20:01 hybridherbst

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 avatar Jan 23 '25 12:01 andybak

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.

hybridherbst avatar Jan 23 '25 21:01 hybridherbst