EsotericSoftware / spine-runtimes

2D skeletal animation runtimes for Spine.
http://esotericsoftware.com/
Other
4.42k stars 2.92k forks source link

[spine-ts/spine-phaser] Destroying the game makes the WebGLRenderer unusable #2390

Closed liarco closed 1 year ago

liarco commented 1 year ago

Package version: 4.2.23 PhaserJS version: 3.60.0 Error message: Error: Shader not compiled.

Description:

I'm running a PhaserJS game in a React (NextJS) environment. I need my game component to be mounted/unmounted many times on the same page and any resources should be released/reallocated at need.

My game config simply includes the plugin:

// ...
      plugins: {
        scene: [
           { key: `SpinePlugin`, plugin: SpinePlugin, mapping: 'spine' },
        ],
      },
// ...

And I destroy the game to free the allocated resources when the game component is unmounted:

// ...
      game.plugins.removeScenePlugin('SpinePlugin');
      game.destroy(true, false);
// ...

This seems to work fine on the first mount, but once the game is destroyed, any attempt to create another instance fires this:

Screenshot 2023-10-02 at 22 27 10

Which is fired by: https://github.com/EsotericSoftware/spine-runtimes/blob/c0032b4ffb5c0452af8444d14c20415f5867ed4e/spine-ts/spine-webgl/src/Shader.ts#L161

As far as I could understant, this happens because of: https://github.com/EsotericSoftware/spine-runtimes/blob/c0032b4ffb5c0452af8444d14c20415f5867ed4e/spine-ts/spine-phaser/src/SpinePlugin.ts#L195

On destroy, the renderer is disposed, but it's actually a static field so when a new instance is created it fails because the renderer has been disposed, but never restored.

My temporary solution

I managed to stop the error by doing this:

import { SpinePlugin } from '@esotericsoftware/spine-phaser';

class CustomSpinePlugin extends SpinePlugin {
  gameDestroy(): void {
    super.gameDestroy();

    // Reset the static instance so it can be recreated at next boot...
    SpinePlugin.gameWebGLRenderer = null;
  }
}

// ...
      plugins: {
        scene: [
           { key: `SpinePlugin`, plugin: CustomSpinePlugin, mapping: 'spine' },
        ],
      },
// ..

I'm afraid this might lead to some memory leaks. Does anyone have any suggestions to handle this properly?

I hope this helps, thank you for your time.

swcleo commented 1 year ago

I'm encountering the same issue on GitHub as well.

I'm running a PhaserJS game in a Vue environment. I need my game component to be mounted/unmounted many times on the same page and any resources should be released/reallocated at need.

badlogic commented 1 year ago

Your temporary solution is actually good and will not result in memory leaks. I'll implement this in the SpinePlugin and push a new package.

badlogic commented 1 year ago

I've just pushed new packages to NPM, 4.1.43 and 4.2.24. Please give those a try and let me know if you still run into issues.

liarco commented 1 year ago

Hi @badlogic, thanks a lot!

I will test this on my project as soon as possible and let you know here if I run into any problems, otherwise it's all good.

Thanks for your time.

Edit: everything works fine now. Thx again!