import { TimeInternal } from "./Time" ; import { Scene } from "../assets/Scene" ; import { CollisionSystemInternal } from "../collision/CollisionSystem" ; import { Debug } from "../io/Debug" ; import { Entity } from "./Entity" ; import { AnimationComponent } from "../animation/AnimationComponent" ; import { EngineHud } from "./hud/EngineHud" ; import { ObjectManagerInternal } from "./ObjectManager" ; import { AssetIdDatabase } from "../assets/AssetIdDatabase" ; import { RendererInternal } from "../graphics/Renderer" ; import { SerializerUtils } from "../serialization/SerializerUtils" ; import { IObjectManagerInternal } from "./IObjectManager" ; import { defaultAssets } from "../assets/DefaultAssets" ; import { GraphicUtils } from "../graphics/GraphicUtils" ; interface SceneLoadInfo { path : string ; additive : boolean ; scene ? : Scene ; previousFogType ? : string ; previousEnvType ? : string ; resolve : ( scene : Scene ) => void ; } namespace Private { export let scenes = [ ] ; export let transitionInProgress = false ; export let sceneLoadInProgress = null ; export const preloadedScenesRequests = [ ] ; export const preloadedScenesInProgress = [ ] ; export const preloadedScenes = [ ] ; export function getTransitionAnimComponent ( ) { const fadeQuad = defaultAssets . transitionScene . root . findChild ( "FadeQuad" ) as Entity ; return fadeQuad . getComponent ( AnimationComponent ) as AnimationComponent ; } export function finalizeSceneLoad ( ) { const isFirstScene = scenes . length === 0 ; if ( ! Private . sceneLoadInProgress ) { console . assert ( false ) ; return ; } const { additive , scene , previousFogType , previousEnvType , resolve } = Private . sceneLoadInProgress ; if ( ! scene ) { console . assert ( false ) ; return ; } let sceneRemovedFromCache = false ; if ( ! additive ) { scenes . forEach ( _scene => { sceneRemovedFromCache = _scene . templatePath === scene . templatePath ; IObjectManagerInternal . instance . deleteObject ( _scene ) ; } ) ; RendererInternal . clearDefaultPerspectiveCamera ( ) ; TimeInternal . resetCurrentFrame ( ) ; EngineHud . onSceneDestroyed ( ) ; CollisionSystemInternal . clearCollisions ( ) ; scenes . length = 0 ; } if ( sceneRemovedFromCache ) { IObjectManagerInternal . instance . addToCache ( scene ) ; } scenes . push ( scene ) ; const fogType = scene ?. fog ?. constructor . name ; const envType = scene ?. environment ?. constructor . name ; if ( fogType !== previousFogType || envType !== previousEnvType ) { GraphicUtils . invalidateShaders ( ) ; } if ( isFirstScene ) { if ( process . env . CONFIG === "standalone" ) { EngineHud . create ( ) ; IObjectManagerInternal . instance . loadGraphicObjects ( ) ; } } else { IObjectManagerInternal . instance . loadGraphicObjects ( ) ; } Private . sceneLoadInProgress = null ; SerializerUtils . clearNonPersistentObjectCache ( ) ; resolve ( scene ) ; } export function onTransitionAnimFinished ( name ) { const anim = getTransitionAnimComponent ( ) ; if ( name === "FadeOut" ) { scenes . pop ( ) ; finalizeSceneLoad ( ) ; anim . animationFinished . once ( onTransitionAnimFinished ) ; anim . playAnimation ( "FadeIn" ) ; scenes . push ( defaultAssets . transitionScene ) ; } else if ( name === "FadeIn" ) { scenes . pop ( ) ; transitionInProgress = false ; } } } hidden export namespace ScenesInternal { export function list ( ) { return Private . scenes ; } export function updateTransition ( ) { if ( Private . transitionInProgress ) { return ; } if ( ! Private . sceneLoadInProgress ) { return ; } const { scene } = Private . sceneLoadInProgress ; if ( ! scene || ! scene . isLoaded ( ) ) { return ; } Debug . log ( `Scene '${ scene . templatePath }' loaded.` ) ; if ( process . env . CONFIG === "standalone" ) { if ( Private . scenes . length > 0 ) { const anim = Private . getTransitionAnimComponent ( ) ; anim . animationFinished . once ( Private . onTransitionAnimFinished ) ; anim . playAnimation ( "FadeOut" ) ; Private . transitionInProgress = true ; Private . scenes . push ( defaultAssets . transitionScene ) ; } else { Private . finalizeSceneLoad ( ) ; } } else { Private . finalizeSceneLoad ( ) ; } } export function destroy ( ) { Private . scenes . forEach ( scene => IObjectManagerInternal . instance . deleteObject ( scene ) ) ; Private . scenes = [ ] ; } export function updatePreloading ( ) { for ( let i = 0 ; i < Private . preloadedScenesInProgress . length ; ) { const info = Private . preloadedScenesInProgress [ i ] ; if ( info . scene . isLoaded ( ) ) { Private . preloadedScenes . push ( info . scene ) ; Private . preloadedScenesInProgress . splice ( i , 1 ) ; info . resolve ( ) ; } else { ++ i ; } } } } export class Scenes { param path param additive static load ( path , additive = false ) { if ( Private . sceneLoadInProgress ) { console . warn ( `Only one scene load is supported at a time. Loading '${ Private . sceneLoadInProgress . path }', skipping '${ path }'` ) ; return Promise . reject ( ) ; } const preloadIndex = Private . preloadedScenes . findIndex ( s => s . templatePath === path ) ; if ( preloadIndex >= 0 ) { Private . preloadedScenes . splice ( preloadIndex , 1 ) ; const scene = Private . preloadedScenes [ preloadIndex ] ; Private . sceneLoadInProgress = { scene : scene , path : path , additive : additive , previousFogType : Private . scenes [ 0 ] ?. fog ?. constructor . name , previousEnvType : Private . scenes [ 0 ] ?. environment ?. constructor . name , resolve : ( ) => { } } ; Private . finalizeSceneLoad ( ) ; return Promise . resolve ( scene ) ; } return new Promise < Scene > ( ( resolve , reject ) => { Private . sceneLoadInProgress = { path : path , additive : additive , previousFogType : Private . scenes [ 0 ] ?. fog ?. constructor . name , previousEnvType : Private . scenes [ 0 ] ?. environment ?. constructor . name , resolve : resolve } ; ObjectManagerInternal . loadObjectIgnoreCache ( path ) . then ( ( [ scene ] ) => { ( Private . sceneLoadInProgress as SceneLoadInfo ) . scene = scene as Scene ; if ( process . env . CONFIG === "editor" ) { if ( ScenesInternal . list ( ) . length === 0 ) { Private . finalizeSceneLoad ( ) ; } } } ) . catch ( ( ) => { Debug . logError ( `Could not load '${ path }'` ) ; Private . sceneLoadInProgress = null ; reject ( ) ; } ) ; } ) ; } static loadById ( id ) { const path = AssetIdDatabase . getPath ( id ) ; if ( path ) { return Scenes . load ( path ) ; } else { return Promise . reject ( ) ; } } /**
     * Unloads a scene
     */ static unload ( scene ) { const sceneIndex = Private . scenes . indexOf ( scene ) ; if ( sceneIndex >= 0 ) { scene . destroy ( ) ; Private . scenes . splice ( sceneIndex , 1 ) ; } else { console . warn ( `Trying to unload an unregistered scene instance` ) ; } } /**
     * Unloads a scene by path
     */ static unloadByPath ( path ) { const scene = Private . scenes . find ( s => s . templatePath === path ) ; if ( scene ) { Scenes . unload ( scene ) ; } else { console . warn ( `Trying to unload an unknown scene '${ path }'` ) ; } } /**
     *  Creates an empty scene
     */ static create ( ) { const scene = new Scene ( ) ; Private . scenes . push ( scene ) ; return scene ; } param path static preLoad ( path ) { if ( Private . preloadedScenesRequests . some ( p => p === path ) || Private . preloadedScenesInProgress . some ( p => p . scene . templatePath === path ) || Private . preloadedScenes . some ( p => p . templatePath === path ) ) { console . warn ( `Scene '${ path }' is already pre-load(ed/ing). Skipping request.` ) ; return Promise . reject ( ) ; } Private . preloadedScenesRequests . push ( path ) ; return new Promise < void > ( ( resolve , reject ) => { ObjectManagerInternal . loadObjectIgnoreCache ( path ) . then ( ( [ scene ] ) => { Private . preloadedScenesInProgress . push ( { scene : scene as Scene , resolve } ) ; const index = Private . preloadedScenesRequests . indexOf ( path ) ; console . assert ( index >= 0 ) ; Private . preloadedScenesRequests . splice ( index , 1 ) ; } ) . catch ( reject ) ; } ) ; } /**
     * Destroys all current scenes
     */ static clear ( ) { ScenesInternal . destroy ( ) ; } }