diff --git a/packages/decentraland-loader/lifecycle/controllers/position.ts b/packages/decentraland-loader/lifecycle/controllers/position.ts index 79d955850..39e70311c 100644 --- a/packages/decentraland-loader/lifecycle/controllers/position.ts +++ b/packages/decentraland-loader/lifecycle/controllers/position.ts @@ -10,7 +10,7 @@ export class PositionLifecycleController extends EventEmitter { constructor(public parcelController: ParcelLifeCycleController, public sceneController: SceneLifeCycleController) { super() - sceneController.on('Scene ready', () => this.checkPositionSettlement()) + sceneController.on('Scene status', () => this.checkPositionSettlement()) } async reportCurrentPosition(position: Vector2Component, teleported: boolean) { @@ -45,7 +45,7 @@ export class PositionLifecycleController extends EventEmitter { private checkPositionSettlement() { if (!this.positionSettled) { - const settling = this.currentlySightedScenes.every($ => this.sceneController.isReady($)) + const settling = this.currentlySightedScenes.every($ => this.sceneController.isRenderable($)) if (settling) { this.positionSettled = settling diff --git a/packages/decentraland-loader/lifecycle/controllers/scene.ts b/packages/decentraland-loader/lifecycle/controllers/scene.ts index abb8fcbec..d6c17a679 100644 --- a/packages/decentraland-loader/lifecycle/controllers/scene.ts +++ b/packages/decentraland-loader/lifecycle/controllers/scene.ts @@ -101,9 +101,9 @@ export class SceneLifeCycleController extends EventEmitter { } } - isReady(sceneId: SceneId): boolean { + isRenderable(sceneId: SceneId): boolean { const status = this.sceneStatus.get(sceneId) - return !!status && status.isReady() + return !!status && (status.isReady() || status.isFailed()) } reportStatus(sceneId: string, status: SceneLifeCycleStatusType) { @@ -114,7 +114,7 @@ export class SceneLifeCycleController extends EventEmitter { } lifeCycleStatus.status = status - this.emit('Scene ready', sceneId) + this.emit('Scene status', { sceneId, status }) } async requestSceneId(position: string): Promise { diff --git a/packages/decentraland-loader/lifecycle/lib/scene.status.ts b/packages/decentraland-loader/lifecycle/lib/scene.status.ts index 487e4bfae..1a8d93494 100644 --- a/packages/decentraland-loader/lifecycle/lib/scene.status.ts +++ b/packages/decentraland-loader/lifecycle/lib/scene.status.ts @@ -1,6 +1,6 @@ import { ILand } from 'shared/types' -export type SceneLifeCycleStatusType = 'unloaded' | 'awake' | 'loaded' | 'ready' +export type SceneLifeCycleStatusType = 'unloaded' | 'awake' | 'loaded' | 'ready' | 'failed' export class SceneLifeCycleStatus { status: SceneLifeCycleStatusType = 'unloaded' @@ -18,4 +18,8 @@ export class SceneLifeCycleStatus { isReady() { return this.status === 'ready' } + + isFailed() { + return this.status === 'failed' + } } diff --git a/packages/scene-system/scene.system.ts b/packages/scene-system/scene.system.ts index 161b89270..5d2e95453 100644 --- a/packages/scene-system/scene.system.ts +++ b/packages/scene-system/scene.system.ts @@ -396,11 +396,7 @@ export default class GamekitScene extends Script { try { await customEval((source as any) as string, getES5Context({ dcl })) - this.events.push({ - type: 'InitMessagesFinished', - tag: 'scene', - payload: '{}' - }) + this.events.push(this.initMessagesFinished()) this.onStartFunctions.push(() => { const engine: IEngineAPI = this.engine as any @@ -408,6 +404,8 @@ export default class GamekitScene extends Script { }) } catch (e) { that.onError(e) + + this.events.push(this.initMessagesFinished()) } this.sendBatch() @@ -431,6 +429,14 @@ export default class GamekitScene extends Script { this.sendBatch() } + private initMessagesFinished(): EntityAction { + return { + type: 'InitMessagesFinished', + tag: 'scene', + payload: '{}' + } + } + private sendBatch() { try { if (this.events.length) { diff --git a/packages/shared/world/SceneWorker.ts b/packages/shared/world/SceneWorker.ts index 604887b9d..eec5a9e0f 100644 --- a/packages/shared/world/SceneWorker.ts +++ b/packages/shared/world/SceneWorker.ts @@ -53,6 +53,8 @@ export class SceneWorker { public persistent = false public readonly onDisposeObservable = new Observable() + public sceneStarted: boolean = false + public readonly position: Vector3 = new Vector3() private readonly lastSentPosition = new Vector3(0, 0, 0) private readonly lastSentRotation = new Quaternion(0, 0, 0, 1) @@ -61,7 +63,6 @@ export class SceneWorker { private worldRunningObserver: Observer | null = null private sceneReady: boolean = false - private sceneStarted: boolean = false constructor(public parcelScene: ParcelSceneAPI, transport?: ScriptingTransport) { parcelScene.registerWorker(this) diff --git a/packages/shared/world/parcelSceneManager.ts b/packages/shared/world/parcelSceneManager.ts index b1434d7e8..beb852fb3 100644 --- a/packages/shared/world/parcelSceneManager.ts +++ b/packages/shared/world/parcelSceneManager.ts @@ -79,18 +79,34 @@ export async function enableParcelSceneLoading(options: EnableParcelSceneLoading }) ret.on('Scene.shouldStart', async (opts: { sceneId: string }) => { - const parcelSceneToStart = await ret.getParcelData(opts.sceneId) + const sceneId = opts.sceneId + const parcelSceneToStart = await ret.getParcelData(sceneId) // create the worker if don't exist - if (!getSceneWorkerBySceneID(opts.sceneId)) { + if (!getSceneWorkerBySceneID(sceneId)) { const parcelScene = new options.parcelSceneClass(ILandToLoadableParcelScene(parcelSceneToStart)) loadParcelScene(parcelScene) } + const observer = sceneLifeCycleObservable.add(sceneStatus => { + if (sceneStatus.sceneId === sceneId) { + ret.notify('Scene.status', sceneStatus) + } + sceneLifeCycleObservable.remove(observer) + }) + // tell the engine to load the parcel scene if (options.onLoadParcelScenes) { - options.onLoadParcelScenes([await ret.getParcelData(opts.sceneId)]) + options.onLoadParcelScenes([await ret.getParcelData(sceneId)]) } + + setTimeout(() => { + const worker = getSceneWorkerBySceneID(sceneId) + if (worker && !worker.sceneStarted) { + sceneLifeCycleObservable.remove(observer) + ret.notify('Scene.status', { sceneId, status: 'failed' }) + } + }, 30000) }) ret.on('Scene.shouldUnload', async (opts: { sceneId: string }) => { @@ -126,8 +142,4 @@ export async function enableParcelSceneLoading(options: EnableParcelSceneLoading worldToGrid(obj.position, position) ret.notify('User.setPosition', { position, teleported: false }) }) - - sceneLifeCycleObservable.add(sceneStatus => { - ret.notify('Scene.status', sceneStatus) - }) }