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

With file loaders, when using JSON directly, (instead of a url), using multiple JSON files, and one is a multi-file, certain loading combinations will cause errors #3705

Closed
the-simian opened this issue May 27, 2018 · 4 comments

Comments

@the-simian
Copy link

the-simian commented May 27, 2018

When I call load.atlas() sometimes I get unexpected behavior when I pass actual JSON into the last argument instead of a URL This is very situational, and I've done my best to outline a series of working and failing cases in a subsequent comment.

Usually, I get the error:

Uncaught TypeError: Failed to execute 'createObjectURL' on 'URL': No function was found that matched the signature provided.
    at Function.File.createObjectURL (File.js:557)
    at ImageFile.onProcess (ImageFile.js:142)
    at LoaderPlugin.nextFile (LoaderPlugin.js:827)
    at ImageFile.onLoad (File.js:328)

Now by contrast, when I pass JSON directly into other methods that take a url to JSON, the behavior is usually correct. A good example is load.tilemapTiledJSON()

So to be clear,

if I run

const level = '/path/to/json.json';
this.load.tilemapTiledJSON('map', level);

OR

const level = { 
"height: 50, 
"infinte: false 
//.... well formed level JSON
};
this.load.tilemapTiledJSON('map', level);

BOTH of these will work, and the level will load correctly.

const playerImg = '/path/to/spritemap.png';
const playerAnimations = '/path/to/atlas.json'
this.load.atlas('player', playerImg, playerAnimations);

That works

but

const playerImg = '/path/to/player.png';
const playerAnimations = '{
   "textures": [{ "image" : "player.png" }]
   ///... well formed JSON
}
this.load.atlas('player', playerImg, playerAnimations);

In some situations, but not always, this fails unexpectedly.

heres what I could figure out...

In

File.createObjectURL = function (image, blob, defaultType)
{
    if (typeof URL === 'function')
    {
        image.src = URL.createObjectURL(blob); //here 'blob' is null.
    }
    else
    {
      ....
    }
};

However its not null on the file loaded by the atlas.. its null on whatever they very next thing you load is! This is what is so confusing. When I use the direct JSON in the

Whereas if I run the atlas.load, subsequent files that get loaded result in null here...

    /**
     * Called automatically by Loader.nextFile.
     * This method controls what extra work this File does with its loaded data.
     *
     * @method Phaser.Loader.FileTypes.ImageFile#onProcess
     * @since 3.7.0
     */
    onProcess: function ()
    {
        this.state = CONST.FILE_PROCESSING;
        this.data = new Image();
        this.data.crossOrigin = this.crossOrigin;
        var _this = this;

        this.data.onload = function ()
        {
            File.revokeObjectURL(_this.data);
            _this.onProcessComplete();
        };

        this.data.onerror = function ()
        {
            File.revokeObjectURL(_this.data);
            _this.onProcessError();
        };
        /// this.xhrLoader.response is  null on files that come after atlas.load!
        File.createObjectURL(this.data, this.xhrLoader.response, 'image/png'); null
    },

It seems to have something to do with the fact the atlas is a multifile , and its interfering with the file loader for other assets.

Moving the load.atlas to the end of the loading-chain still results in a failure on the imageFile that is indicated in position 1 of the atlas.

I noticed this error in version at least as recently as 3.7.0, 3.8.0 and also on the very latest 3.9.0 too.

In the next comment, I will outline a series of scenarios and whether or not it works or fails.

@the-simian the-simian changed the title game.load.atlas does not handle 'real' JSON correctly game.load.atlas (multiFile) does not handle 'real' JSON correctly, resulting in fail loading failures that cascade to other files. May 27, 2018
@the-simian the-simian changed the title game.load.atlas (multiFile) does not handle 'real' JSON correctly, resulting in fail loading failures that cascade to other files. When working with JSON directly, isntead of a url, using two JSON files the first will work but the second causes a cascade that causes subsequent files to not load correctly May 27, 2018
@the-simian the-simian changed the title When working with JSON directly, isntead of a url, using two JSON files the first will work but the second causes a cascade that causes subsequent files to not load correctly When working with JSON directly, (instead of a url), using two JSON files the first will work but the second causes a cascade that causes subsequent files to not load correctly May 27, 2018
@the-simian the-simian changed the title When working with JSON directly, (instead of a url), using two JSON files the first will work but the second causes a cascade that causes subsequent files to not load correctly When working with JSON directly, (instead of a url), using two JSON files, and one of them is in a multifile. If you load the multifile second the first will work but the second causes a cascade that causes subsequent files to not load correctly May 27, 2018
@the-simian
Copy link
Author

the-simian commented May 27, 2018

Here is a combination of file-load orders int he preload function, some of which express the issue, others which it does not seem to happen.

Using all 'imported' json if I load the file sin this order everything works:

WORKS

  preload() {
    this.load.image('background-gradient', backgroundGradient);
    this.load.image('background-trees', backgroundTrees);

    this.load.atlas({
      key: 'player',
      textureURL: playerTexture,
      atlasURL: playerJson //THIS IS JSON, NOT A URL
    });
    this.load.tilemapTiledJSON('map', level);  //THIS IS JSON, NOT A URL
  }

if I rearrange the loaders like this:
BREAKS

  preload() {
    this.load.image('background-gradient', backgroundGradient);
    this.load.image('background-trees', backgroundTrees);
    this.load.tilemapTiledJSON('map', level); //THIS IS JSON, NOT A URL
    this.load.atlas({
      key: 'player',
      textureURL: playerTexture,
      atlasURL: playerJson //THIS IS JSON, NOT A URL
    });
  }

Then I get this error

File.js:557 Uncaught TypeError: Failed to execute 'createObjectURL' on 'URL': No function was found that matched the signature provided.
    at Function.File.createObjectURL (File.js:557)
    at ImageFile.onProcess (ImageFile.js:142)
    at LoaderPlugin.nextFile (LoaderPlugin.js:827)
    at ImageFile.onLoad (File.js:328)

With the 'broken' load order....
if I change the level to a static url

WORKS

  preload() {
    this.load.image('background-gradient', backgroundGradient);
    this.load.image('background-trees', backgroundTrees);
    this.load.tilemapTiledJSON('map', level); //THIS IS NOW A URL, NOT JSON!
    this.load.atlas({
      key: 'player',
      textureURL: playerTexture,
      atlasURL: playerJson  //THIS IS JSON NOT A URL
    });
  }

This will work again.

if I change the OTHER url to a static url

BREAKS

  preload() {
    this.load.image('background-gradient', backgroundGradient);
    this.load.image('background-trees', backgroundTrees);
    this.load.tilemapTiledJSON('map', level); //THIS IS BACK TO JSON, NOT A URL
    this.load.atlas({
      key: 'player',
      textureURL: playerTexture,
      atlasURL: playerJson //THIS IS A URL, NOT JSON
    });
  }

I get two errors:

File.js:557 Uncaught TypeError: Failed to execute 'createObjectURL' on 'URL': No function was found that matched the signature provided.
    at Function.File.createObjectURL (File.js:557)
    at ImageFile.onProcess (ImageFile.js:142)
    at LoaderPlugin.nextFile (LoaderPlugin.js:827)
    at ImageFile.onLoad (File.js:328)
File.createObjectURL @ File.js:557
onProcess @ ImageFile.js:142
nextFile @ LoaderPlugin.js:827
onLoad @ File.js:328
load (async)
XHRLoader @ XHRLoader.js:50
load @ File.js:302
(anonymous) @ LoaderPlugin.js:773
each @ Set.js:194
checkLoadQueue @ LoaderPlugin.js:758
fileProcessComplete @ LoaderPlugin.js:894
onProcessComplete @ File.js:397
onProcess @ JSONFile.js:115
nextFile @ LoaderPlugin.js:827
load @ File.js:283
(anonymous) @ LoaderPlugin.js:773
each @ Set.js:194
checkLoadQueue @ LoaderPlugin.js:758
start @ LoaderPlugin.js:716
bootScene @ SceneManager.js:475
start @ SceneManager.js:1068
bootQueue @ SceneManager.js:224
emit @ index.js:201
updatePending @ TextureManager.js:148
emit @ index.js:182
image.onload @ TextureManager.js:250
load (async)
addBase64 @ TextureManager.js:242
boot @ TextureManager.js:128
emit @ index.js:201
boot @ Game.js:301
check @ DOMContentLoaded.js:38

(same error I described earlier)

And this new error

Uncaught SyntaxError: Unexpected end of JSON input
    at JSON.parse (<anonymous>)
    at JSONFile.onProcess (JSONFile.js:104)
    at LoaderPlugin.nextFile (LoaderPlugin.js:827)
    at JSONFile.onLoad (File.js:328)
onProcess @ JSONFile.js:104
nextFile @ LoaderPlugin.js:827
onLoad @ File.js:328
load (async)
XHRLoader @ XHRLoader.js:50
load @ File.js:302
(anonymous) @ LoaderPlugin.js:773
each @ Set.js:194
checkLoadQueue @ LoaderPlugin.js:758
fileProcessComplete @ LoaderPlugin.js:894
onProcessComplete @ File.js:397
onProcess @ JSONFile.js:115
nextFile @ LoaderPlugin.js:827
load @ File.js:283
(anonymous) @ LoaderPlugin.js:773
each @ Set.js:194
checkLoadQueue @ LoaderPlugin.js:758
start @ LoaderPlugin.js:716
bootScene @ SceneManager.js:475
start @ SceneManager.js:1068
bootQueue @ SceneManager.js:224
emit @ index.js:201
updatePending @ TextureManager.js:148
emit @ index.js:182
image.onload @ TextureManager.js:250
load (async)
addBase64 @ TextureManager.js:242
boot @ TextureManager.js:128
emit @ index.js:201
boot @ Game.js:301
check @ DOMContentLoaded.js:38

This second error may just be a side effect and only occurs in this specific load order and configuration.

If I make them BOTH urls...
WORKS

  preload() {
    this.load.image('background-gradient', backgroundGradient);
    this.load.image('background-trees', backgroundTrees);
    this.load.tilemapTiledJSON('map', level); //THIS IS A URL, NOT JSON
    this.load.atlas({
      key: 'player',
      textureURL: playerTexture,
      atlasURL: playerJson //THIS IS ALSO  A URL, NOT JSON
    });
  }

Everything works again. Actually using all urls (not JSON) works in pretty much any sequence.

I know this is confusing, and I'm doing my best to explain what's up, but when you use JSON and not urls, and one of them is a multipart file and there's more than one, there is some sort of interaction between them where sometimes things break.

@the-simian the-simian changed the title When working with JSON directly, (instead of a url), using two JSON files, and one of them is in a multifile. If you load the multifile second the first will work but the second causes a cascade that causes subsequent files to not load correctly With file loaders, when using JSON directly, (instead of a url), using multiple JSON files, and one is a multi-file, certain loading combinations will cause errors May 27, 2018
@photonstorm
Copy link
Collaborator

Just to say I have built a test-case confirming this breaking, so will be looking into it tomorrow.

@photonstorm
Copy link
Collaborator

Thank you for submitting this issue. We have fixed this and the fix has been pushed to the master branch. It will be part of the next release. If you get time to build and test it for yourself we would appreciate that.

@the-simian
Copy link
Author

@photonstorm Thank you, I looked at it myself but couldn't figure out how to fix it, I'd be happy to check master. How soon do you expect to push master as a new release?

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

No branches or pull requests

2 participants