Fix silent exceptions when resource loading finished after an instance was reset/removed (#7054)

Only show in developer changelog
This commit is contained in:
Florian Rival
2024-10-15 12:39:20 +02:00
committed by GitHub
parent 33dcc04112
commit e7decc7b92
14 changed files with 59 additions and 5 deletions
+5
View File
@@ -2203,6 +2203,8 @@ module.exports = {
if (!texture.baseTexture.valid) {
// Post pone texture update if texture is not loaded.
texture.once('update', () => {
if (this._wasDestroyed) return;
this.updateTexture();
this.updatePIXISprite();
});
@@ -2375,6 +2377,7 @@ module.exports = {
getFaceMaterial(this._project, materialIndexToFaceIndex[4]),
getFaceMaterial(this._project, materialIndexToFaceIndex[5]),
]);
if (this._wasDestroyed) return;
this._threeObject.material[0] = materials[0];
this._threeObject.material[1] = materials[1];
@@ -2823,6 +2826,7 @@ module.exports = {
this._pixiResourcesLoader
.get3DModel(project, modelResourceName)
.then((model3d) => {
if (this._wasDestroyed) return;
const clonedModel3D = THREE_ADDONS.SkeletonUtils.clone(
model3d.scene
);
@@ -3338,6 +3342,7 @@ module.exports = {
this._pixiResourcesLoader
.get3DModel(this._project, modelResourceName)
.then((model3d) => {
if (this._wasDestroyed) return;
this._clonedModel3D = THREE_ADDONS.SkeletonUtils.clone(
model3d.scene
);
+2
View File
@@ -697,6 +697,8 @@ module.exports = {
this._currentBitmapFontResourceName,
this._currentTextureAtlasResourceName
).then((bitmapFont) => {
if (this._wasDestroyed) return;
this._pixiObject.fontName = bitmapFont.font;
this._pixiObject.fontSize = bitmapFont.size;
this._pixiObject.dirty = true;
+8 -2
View File
@@ -14,9 +14,12 @@ class RenderedInstance {
_associatedObjectConfiguration: gd.ObjectConfiguration;
_pixiContainer: PIXI.Container;
_pixiResourcesLoader: Class<PixiResourcesLoader>;
_pixiObject: PIXI.DisplayObject;
_pixiObject: PIXI.DisplayObject | null;
wasUsed: boolean;
/** Set to true when onRemovedFromScene is called. Allows to cancel promises/asynchronous operations (notably: waiting for a resource load). */
_wasDestroyed: boolean;
constructor(
project: gdProject,
instance: gdInitialInstance,
@@ -89,10 +92,13 @@ class Rendered3DInstance {
_pixiContainer: PIXI.Container;
_threeGroup: THREE.Group;
_pixiResourcesLoader: Class<PixiResourcesLoader>;
_pixiObject: PIXI.DisplayObject;
_pixiObject: PIXI.DisplayObject | null;
_threeObject: THREE.Object3D | null;
wasUsed: boolean;
/** Set to true when onRemovedFromScene is called. Allows to cancel promises/asynchronous operations (notably: waiting for a resource load). */
_wasDestroyed: boolean;
constructor(
project: gdProject,
instance: gdInitialInstance,
+1
View File
@@ -323,6 +323,7 @@ module.exports = {
this._pixiResourcesLoader
.getSpineData(this._project, this._spineResourceName)
.then((spineDataOrLoadingError) => {
if (this._wasDestroyed) return;
if (this._spine) this._pixiObject.removeChild(this._spine);
if (!spineDataOrLoadingError.skeleton) {
+1
View File
@@ -711,6 +711,7 @@ module.exports = {
this._pixiResourcesLoader
.loadFontFamily(this._project, fontResourceName)
.then((fontFamily) => {
if (this._wasDestroyed) return;
this._pixiText.style.fontFamily = fontFamily;
this._pixiText.dirty = true;
})
+9
View File
@@ -1760,6 +1760,7 @@ module.exports = {
levelIndex,
pako,
(tileMap) => {
if (this._wasDestroyed) return;
if (!tileMap) {
this._onLoadingError();
// _loadTileMapWithCallback already log errors
@@ -1781,6 +1782,7 @@ module.exports = {
tilesetJsonFile,
levelIndex,
(textureCache) => {
if (this._wasDestroyed) return;
if (!textureCache) {
this._onLoadingError();
// getOrLoadTextureCache already log warns and errors.
@@ -1809,6 +1811,7 @@ module.exports = {
} else {
// Wait for the atlas image to load.
atlasTexture.once('update', () => {
if (this._wasDestroyed) return;
loadTileMap();
});
}
@@ -1855,6 +1858,7 @@ module.exports = {
tilesetJsonFile,
levelIndex,
(textureCache) => {
if (this._wasDestroyed) return;
if (!textureCache) {
this._onLoadingError();
// getOrLoadTextureCache already log warns and errors.
@@ -2208,6 +2212,7 @@ module.exports = {
columnCount,
rowCount,
(tileMap) => {
if (this._wasDestroyed) return;
if (!tileMap) {
this._onLoadingError();
console.error('Could not parse tilemap.');
@@ -2230,6 +2235,7 @@ module.exports = {
/** @type {TileMapHelper.TileTextureCache | null} */
textureCache
) => {
if (this._wasDestroyed) return;
this._onLoadingSuccess();
if (!this._editableTileMap) return;
@@ -2257,6 +2263,7 @@ module.exports = {
} else {
// Wait for the atlas image to load.
atlasTexture.once('update', () => {
if (this._wasDestroyed) return;
loadTileMap();
});
}
@@ -2293,6 +2300,7 @@ module.exports = {
/** @type {TileMapHelper.TileTextureCache | null} */
textureCache
) => {
if (this._wasDestroyed) return;
this._onLoadingSuccess();
if (!this._editableTileMap) return;
@@ -2536,6 +2544,7 @@ module.exports = {
0, // levelIndex
pako,
(tileMap) => {
if (this._wasDestroyed) return;
if (!tileMap) {
this._onLoadingError();
// _loadTiledMapWithCallback already log errors
+1
View File
@@ -609,6 +609,7 @@ module.exports = {
that._pixiObject.texture.on('error', function () {
that._pixiObject.texture.off('error', this);
if (this._wasDestroyed) return;
that._pixiObject.texture = that._pixiResourcesLoader.getInvalidPIXITexture();
});
@@ -18,6 +18,7 @@ export default class Rendered3DInstance {
_pixiObject: PIXI.DisplayObject;
_threeObject: THREE.Object3D | null;
wasUsed: boolean;
_wasDestroyed: boolean;
constructor(
project: gdProject,
@@ -36,6 +37,7 @@ export default class Rendered3DInstance {
this._project = project;
this._pixiResourcesLoader = pixiResourcesLoader;
this.wasUsed = true; //Used by InstancesRenderer to track rendered instance that are not used anymore.
this._wasDestroyed = false;
}
isRenderedIn3D(): boolean {
@@ -89,6 +91,7 @@ export default class Rendered3DInstance {
* the default implementation of the method does.
*/
onRemovedFromScene() {
this._wasDestroyed = true;
if (this._pixiObject !== null)
this._pixiContainer.removeChild(this._pixiObject);
if (this._threeObject !== null) this._threeGroup.remove(this._threeObject);
@@ -179,6 +179,12 @@ export default class RenderedCustomObjectInstance extends Rendered3DInstance
for (const [i, renderedInstance] of this.renderedInstances) {
if (!renderedInstance.wasUsed) {
renderedInstance.onRemovedFromScene();
if (!renderedInstance._wasDestroyed)
console.error(
'Rendered instance was not marked as destroyed by onRemovedFromScene - verify the implementation.',
renderedInstance
);
this.renderedInstances.delete(i);
this.layoutedInstances.delete(i);
}
@@ -196,6 +202,11 @@ export default class RenderedCustomObjectInstance extends Rendered3DInstance
// Destroy all instances
for (const renderedInstance of this.renderedInstances.values()) {
renderedInstance.onRemovedFromScene();
if (!renderedInstance._wasDestroyed)
console.error(
'Rendered instance (of a custom object) was not marked as destroyed by onRemovedFromScene - verify the implementation.',
renderedInstance
);
}
this.renderedInstances.clear();
this.layoutedInstances.clear();
@@ -14,6 +14,7 @@ export default class RenderedInstance {
_pixiResourcesLoader: Class<PixiResourcesLoader>;
_pixiObject: PIXI.DisplayObject;
wasUsed: boolean;
_wasDestroyed: boolean;
constructor(
project: gdProject,
@@ -29,6 +30,7 @@ export default class RenderedInstance {
this._project = project;
this._pixiResourcesLoader = pixiResourcesLoader;
this.wasUsed = true; //Used by InstancesRenderer to track rendered instance that are not used anymore.
this._wasDestroyed = false;
}
isRenderedIn3D(): boolean {
@@ -63,6 +65,7 @@ export default class RenderedInstance {
* the default implementation of the method does.
*/
onRemovedFromScene(): void {
this._wasDestroyed = true;
if (this._pixiObject !== null)
this._pixiContainer.removeChild(this._pixiObject);
}
@@ -265,7 +265,10 @@ export default class RenderedPanelSpriteInstance extends RenderedInstance {
);
if (!texture.baseTexture.valid) {
// Post pone texture update if texture is not loaded.
texture.once('update', () => this.updateTextures());
texture.once('update', () => {
if (this._wasDestroyed) return;
this.updateTextures();
});
return;
}
@@ -199,7 +199,10 @@ export default class RenderedSprite3DInstance extends Rendered3DInstance {
if (!texture.baseTexture.valid) {
// Post pone texture update if texture is not loaded.
texture.once('update', () => this.updateTextureAndSprite());
texture.once('update', () => {
if (this._wasDestroyed) return;
this.updateTextureAndSprite();
});
return;
}
this._textureWidth = texture.width;
@@ -212,6 +215,7 @@ export default class RenderedSprite3DInstance extends Rendered3DInstance {
useTransparentTexture: true,
}
);
if (this._wasDestroyed) return;
if (this._threeObject) {
this._threeObject.material = material;
}
@@ -187,7 +187,10 @@ export default class RenderedSpriteInstance extends RenderedInstance {
if (!texture.baseTexture.valid) {
// Post pone texture update if texture is not loaded.
texture.once('update', () => this.updatePIXITextureAndSprite());
texture.once('update', () => {
if (this._wasDestroyed) return;
this.updatePIXITextureAndSprite();
});
return;
}
@@ -140,6 +140,8 @@ export default class RenderedTextInstance extends RenderedInstance {
textObjectConfiguration.getFontName()
)
.then(fontFamily => {
if (this._wasDestroyed) return;
// Once the font is loaded, we can use the given fontFamily.
this._fontFamily = fontFamily;
this._styleFontDirty = true;