gdcore-tools 2.0.0-gd-v5.4.217-autobuild → 2.0.0-gd-v5.4.218-autobuild

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/dist/Runtime/Extensions/3D/JsExtension.js +7 -3
  2. package/dist/Runtime/Extensions/DialogueTree/JsExtension.js +44 -32
  3. package/dist/Runtime/Extensions/DialogueTree/dialoguetools.js +2 -2
  4. package/dist/Runtime/Extensions/DialogueTree/dialoguetools.js.map +2 -2
  5. package/dist/Runtime/Extensions/Multiplayer/JsExtension.js +15 -0
  6. package/dist/Runtime/Extensions/Multiplayer/messageManager.js +1 -1
  7. package/dist/Runtime/Extensions/Multiplayer/messageManager.js.map +2 -2
  8. package/dist/Runtime/Extensions/Multiplayer/multiplayerobjectruntimebehavior.js +1 -1
  9. package/dist/Runtime/Extensions/Multiplayer/multiplayerobjectruntimebehavior.js.map +2 -2
  10. package/dist/Runtime/Extensions/Physics2Behavior/physics2runtimebehavior.js +1 -1
  11. package/dist/Runtime/Extensions/Physics2Behavior/physics2runtimebehavior.js.map +2 -2
  12. package/dist/Runtime/Extensions/Spine/managers/pixi-spine-atlas-manager.js +1 -1
  13. package/dist/Runtime/Extensions/Spine/managers/pixi-spine-atlas-manager.js.map +2 -2
  14. package/dist/Runtime/Extensions/Spine/managers/pixi-spine-manager.js +1 -1
  15. package/dist/Runtime/Extensions/Spine/managers/pixi-spine-manager.js.map +2 -2
  16. package/dist/Runtime/Model3DManager.js +1 -1
  17. package/dist/Runtime/Model3DManager.js.map +2 -2
  18. package/dist/Runtime/ResourceLoader.js +1 -1
  19. package/dist/Runtime/ResourceLoader.js.map +2 -2
  20. package/dist/Runtime/capturemanager.js +2 -0
  21. package/dist/Runtime/capturemanager.js.map +7 -0
  22. package/dist/Runtime/fontfaceobserver-font-manager/fontfaceobserver-font-manager.js +1 -1
  23. package/dist/Runtime/fontfaceobserver-font-manager/fontfaceobserver-font-manager.js.map +2 -2
  24. package/dist/Runtime/howler-sound-manager/howler-sound-manager.js +1 -1
  25. package/dist/Runtime/howler-sound-manager/howler-sound-manager.js.map +2 -2
  26. package/dist/Runtime/jsonmanager.js +1 -1
  27. package/dist/Runtime/jsonmanager.js.map +2 -2
  28. package/dist/Runtime/layer.js +1 -1
  29. package/dist/Runtime/layer.js.map +2 -2
  30. package/dist/Runtime/pixi-renderers/pixi-bitmapfont-manager.js +1 -1
  31. package/dist/Runtime/pixi-renderers/pixi-bitmapfont-manager.js.map +2 -2
  32. package/dist/Runtime/pixi-renderers/pixi-image-manager.js +1 -1
  33. package/dist/Runtime/pixi-renderers/pixi-image-manager.js.map +2 -2
  34. package/dist/Runtime/pixi-renderers/runtimegame-pixi-renderer.js +1 -1
  35. package/dist/Runtime/pixi-renderers/runtimegame-pixi-renderer.js.map +2 -2
  36. package/dist/Runtime/runtimegame.js +1 -1
  37. package/dist/Runtime/runtimegame.js.map +2 -2
  38. package/dist/Runtime/runtimewatermark.js +2 -2
  39. package/dist/Runtime/runtimewatermark.js.map +2 -2
  40. package/dist/Runtime/scenestack.js +1 -1
  41. package/dist/Runtime/scenestack.js.map +2 -2
  42. package/dist/Runtime/spriteruntimeobject.js +1 -1
  43. package/dist/Runtime/spriteruntimeobject.js.map +2 -2
  44. package/dist/lib/libGD.cjs +1 -1
  45. package/dist/lib/libGD.wasm +0 -0
  46. package/gd.d.ts +22 -6
  47. package/package.json +1 -1
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../GDevelop/GDJS/Runtime/runtimegame.ts"],
4
- "sourcesContent": ["/*\n * GDevelop JS Platform\n * Copyright 2013-2016 Florian Rival (Florian.Rival@gmail.com). All rights reserved.\n * This project is released under the MIT License.\n */\nnamespace gdjs {\n const logger = new gdjs.Logger('Game manager');\n\n const sleep = (ms: float) =>\n new Promise((resolve) => setTimeout(resolve, ms));\n\n /** Identify a script file, with its content hash (useful for hot-reloading). */\n export type RuntimeGameOptionsScriptFile = {\n /** The path for this script file. */\n path: string;\n /** The hash of the script file content. */\n hash: number;\n };\n\n const getGlobalResourceNames = (projectData: ProjectData): Array<string> =>\n projectData.usedResources.map((resource) => resource.name);\n\n let supportedCompressionMethods: ('cs:gzip' | 'cs:deflate')[] | null = null;\n const getSupportedCompressionMethods = (): ('cs:gzip' | 'cs:deflate')[] => {\n if (!!supportedCompressionMethods) {\n return supportedCompressionMethods;\n }\n supportedCompressionMethods = [];\n\n try {\n // @ts-ignore - We are checking if the CompressionStream is available.\n new CompressionStream('gzip');\n supportedCompressionMethods.push('cs:gzip');\n } catch (e) {}\n try {\n // @ts-ignore - We are checking if the CompressionStream is available.\n new CompressionStream('deflate');\n supportedCompressionMethods.push('cs:deflate');\n } catch (e) {}\n\n return supportedCompressionMethods;\n };\n\n /** Options given to the game at startup. */\n export type RuntimeGameOptions = {\n /** if true, force fullscreen. */\n forceFullscreen?: boolean;\n /** if true, game is run as a preview launched from an editor. */\n isPreview?: boolean;\n /** The name of the external layout to create in the scene at position 0;0. */\n injectExternalLayout?: string;\n /** Script files, used for hot-reloading. */\n scriptFiles?: Array<RuntimeGameOptionsScriptFile>;\n /** if true, export is a partial preview without events. */\n projectDataOnlyExport?: boolean;\n /** if true, preview is launched from GDevelop native mobile app. */\n nativeMobileApp?: boolean;\n /** The address of the debugger server, to reach out using WebSocket. */\n websocketDebuggerServerAddress?: string;\n /** The port of the debugger server, to reach out using WebSocket. */\n websocketDebuggerServerPort?: string;\n\n /**\n * The path to require `@electron/remote` module.\n * This is only useful in a preview, where this can't be required from\n * `@electron/remote` directly as previews don't have any node_modules.\n * On the contrary, a game packaged with Electron as a standalone app\n * has its node_modules.\n * This can be removed once there are no more dependencies on\n * `@electron/remote` in the game engine and extensions.\n */\n electronRemoteRequirePath?: string;\n\n /**\n * The token to use by the game engine when requiring any resource stored on\n * GDevelop Cloud buckets. Note that this is only useful during previews.\n */\n gdevelopResourceToken?: string;\n\n /**\n * Check if, in some exceptional cases, we allow authentication\n * to be done through a iframe.\n * This is usually discouraged as the user can't verify that the authentication\n * window is a genuine one. It's only to be used in trusted contexts.\n */\n allowAuthenticationUsingIframeForPreview?: boolean;\n\n /** If set, the game will send crash reports to GDevelop APIs. */\n crashReportUploadLevel?: 'all' | 'exclude-javascript-code-events' | 'none';\n\n /** Arbitrary string explaining in which context the game is being played. */\n previewContext?: string;\n\n /** The GDevelop version used to build the game. */\n gdevelopVersionWithHash?: string;\n\n /** The template slug that was used to create the project. */\n projectTemplateSlug?: string;\n\n /** The source game id that was used to create the project. */\n sourceGameId?: string;\n\n /**\n * If set, this data is used to authenticate automatically when launching the game.\n * This is only useful during previews.\n */\n playerUsername?: string;\n playerId?: string;\n playerToken?: string;\n\n /**\n * If set, the game should use the specified environment for making calls\n * to GDevelop APIs (\"dev\" = development APIs).\n */\n environment?: 'dev';\n };\n\n /**\n * Represents a game being played.\n */\n export class RuntimeGame {\n _resourcesLoader: gdjs.ResourceLoader;\n _variables: VariablesContainer;\n _variablesByExtensionName: Map<string, gdjs.VariablesContainer>;\n _data: ProjectData;\n _sceneAndExtensionsData: Array<SceneAndExtensionsData> = [];\n _eventsBasedObjectDatas: Map<String, EventsBasedObjectData>;\n _effectsManager: EffectsManager;\n _maxFPS: integer;\n _minFPS: integer;\n _gameResolutionWidth: integer;\n _gameResolutionHeight: integer;\n _originalWidth: float;\n _originalHeight: float;\n _resizeMode: 'adaptWidth' | 'adaptHeight' | string;\n _adaptGameResolutionAtRuntime: boolean;\n _scaleMode: 'linear' | 'nearest';\n _pixelsRounding: boolean;\n _antialiasingMode: 'none' | 'MSAA';\n _isAntialisingEnabledOnMobile: boolean;\n /**\n * Game loop management (see startGameLoop method)\n */\n _renderer: RuntimeGameRenderer;\n _sessionId: string | null;\n _playerId: string | null;\n _watermark: watermark.RuntimeWatermark;\n\n _sceneStack: SceneStack;\n /**\n * When set to true, the scenes are notified that game resolution size changed.\n */\n _notifyScenesForGameResolutionResize: boolean = false;\n\n /**\n * When paused, the game won't step and will be freezed. Useful for debugging.\n */\n _paused: boolean = false;\n\n /**\n * True during the first frame the game is back from being hidden.\n * This has nothing to do with `_paused`.\n */\n _hasJustResumed: boolean = false;\n\n //Inputs :\n _inputManager: InputManager;\n\n /**\n * Allow to specify an external layout to insert in the first scene.\n */\n _injectExternalLayout: any;\n _options: RuntimeGameOptions;\n\n /**\n * The mappings for embedded resources\n */\n _embeddedResourcesMappings: Map<string, Record<string, string>>;\n\n /**\n * Optional client to connect to a debugger server.\n */\n _debuggerClient: gdjs.AbstractDebuggerClient | null;\n _sessionMetricsInitialized: boolean = false;\n _disableMetrics: boolean = false;\n _isPreview: boolean;\n\n /**\n * @param data The object (usually stored in data.json) containing the full project data\n * @param\n */\n constructor(data: ProjectData, options?: RuntimeGameOptions) {\n this._options = options || {};\n this._variables = new gdjs.VariablesContainer(data.variables);\n this._variablesByExtensionName = new Map<\n string,\n gdjs.VariablesContainer\n >();\n for (const extensionData of data.eventsFunctionsExtensions) {\n if (extensionData.globalVariables.length > 0) {\n this._variablesByExtensionName.set(\n extensionData.name,\n new gdjs.VariablesContainer(extensionData.globalVariables)\n );\n }\n }\n this._eventsBasedObjectDatas = new Map<String, EventsBasedObjectData>();\n this._data = data;\n this._updateSceneAndExtensionsData();\n\n this._resourcesLoader = new gdjs.ResourceLoader(\n this,\n data.resources.resources,\n getGlobalResourceNames(data),\n data.layouts\n );\n\n this._effectsManager = new gdjs.EffectsManager();\n this._maxFPS = this._data.properties.maxFPS;\n this._minFPS = this._data.properties.minFPS;\n this._gameResolutionWidth = this._data.properties.windowWidth;\n this._gameResolutionHeight = this._data.properties.windowHeight;\n this._originalWidth = this._gameResolutionWidth;\n this._originalHeight = this._gameResolutionHeight;\n this._resizeMode = this._data.properties.sizeOnStartupMode;\n this._adaptGameResolutionAtRuntime = this._data.properties.adaptGameResolutionAtRuntime;\n this._scaleMode = data.properties.scaleMode || 'linear';\n this._pixelsRounding = this._data.properties.pixelsRounding;\n this._antialiasingMode = this._data.properties.antialiasingMode;\n this._isAntialisingEnabledOnMobile = this._data.properties.antialisingEnabledOnMobile;\n this._renderer = new gdjs.RuntimeGameRenderer(\n this,\n this._options.forceFullscreen || false\n );\n this._watermark = new gdjs.watermark.RuntimeWatermark(\n this,\n data.properties.authorUsernames,\n this._data.properties.watermark\n );\n this._sceneStack = new gdjs.SceneStack(this);\n this._inputManager = new gdjs.InputManager();\n this._injectExternalLayout = this._options.injectExternalLayout || '';\n this._debuggerClient = gdjs.DebuggerClient\n ? new gdjs.DebuggerClient(this)\n : null;\n this._isPreview = this._options.isPreview || false;\n this._sessionId = null;\n this._playerId = null;\n\n this._embeddedResourcesMappings = new Map();\n for (const resource of this._data.resources.resources) {\n if (resource.metadata) {\n try {\n const metadata = JSON.parse(resource.metadata);\n if (metadata?.embeddedResourcesMapping) {\n this._embeddedResourcesMappings.set(\n resource.name,\n metadata.embeddedResourcesMapping\n );\n }\n } catch {\n logger.error(\n 'Some metadata of resources can not be successfully parsed.'\n );\n }\n }\n }\n\n if (this.isUsingGDevelopDevelopmentEnvironment()) {\n logger.info(\n 'This game will run on the development version of GDevelop APIs.'\n );\n }\n }\n\n /**\n * Update the project data. Useful for hot-reloading, should not be used otherwise.\n *\n * @param projectData The object (usually stored in data.json) containing the full project data\n */\n setProjectData(projectData: ProjectData): void {\n this._data = projectData;\n this._updateSceneAndExtensionsData();\n this._resourcesLoader.setResources(\n projectData.resources.resources,\n getGlobalResourceNames(projectData),\n projectData.layouts\n );\n }\n\n private _updateSceneAndExtensionsData(): void {\n const usedExtensionsWithVariablesData = this._data.eventsFunctionsExtensions.filter(\n (extensionData) => extensionData.sceneVariables.length > 0\n );\n this._sceneAndExtensionsData = this._data.layouts.map((sceneData) => ({\n sceneData,\n usedExtensionsWithVariablesData,\n }));\n\n this._eventsBasedObjectDatas.clear();\n if (this._data.eventsFunctionsExtensions) {\n for (const extension of this._data.eventsFunctionsExtensions) {\n for (const eventsBasedObject of extension.eventsBasedObjects) {\n this._eventsBasedObjectDatas.set(\n extension.name + '::' + eventsBasedObject.name,\n eventsBasedObject\n );\n }\n }\n }\n }\n\n /**\n * Return the additional options passed to the RuntimeGame when created.\n * @returns The additional options, if any.\n */\n getAdditionalOptions(): RuntimeGameOptions {\n return this._options;\n }\n\n getRenderer(): gdjs.RuntimeGameRenderer {\n return this._renderer;\n }\n\n /**\n * Get the variables of the RuntimeGame.\n * @return The global variables\n */\n getVariables(): gdjs.VariablesContainer {\n return this._variables;\n }\n\n /**\n * Get the extension's global variables.\n * @param extensionName The extension name.\n * @returns The extension's global variables.\n */\n getVariablesForExtension(extensionName: string) {\n return this._variablesByExtensionName.get(extensionName) || null;\n }\n\n /**\n * Get the gdjs.SoundManager of the RuntimeGame.\n * @return The sound manager.\n */\n getSoundManager(): gdjs.HowlerSoundManager {\n return this._resourcesLoader.getSoundManager();\n }\n\n /**\n * Get the gdjs.ImageManager of the RuntimeGame.\n * @return The image manager.\n */\n getImageManager(): gdjs.PixiImageManager {\n return this._resourcesLoader.getImageManager();\n }\n\n /**\n * Get the gdjs.FontManager of the RuntimeGame.\n * @return The font manager.\n */\n getFontManager(): gdjs.FontFaceObserverFontManager {\n return this._resourcesLoader.getFontManager();\n }\n\n /**\n * Get the gdjs.BitmapFontManager of the RuntimeGame.\n * @return The bitmap font manager.\n */\n getBitmapFontManager(): gdjs.BitmapFontManager {\n return this._resourcesLoader.getBitmapFontManager();\n }\n\n /**\n * Get the JSON manager of the game, used to load JSON from game\n * resources.\n * @return The json manager for the game\n */\n getJsonManager(): gdjs.JsonManager {\n return this._resourcesLoader.getJsonManager();\n }\n\n /**\n * Get the 3D model manager of the game, used to load 3D model from game\n * resources.\n * @return The 3D model manager for the game\n */\n getModel3DManager(): gdjs.Model3DManager {\n return this._resourcesLoader.getModel3DManager();\n }\n\n /**\n * Get the Spine manager of the game, used to load and construct spine skeletons from game\n * resources.\n * @return The Spine manager for the game\n */\n getSpineManager(): gdjs.SpineManager | null {\n return this._resourcesLoader.getSpineManager();\n }\n\n /**\n * Get the Spine Atlas manager of the game, used to load atlases from game\n * resources.\n * @return The Spine Atlas manager for the game\n */\n getSpineAtlasManager(): gdjs.SpineAtlasManager | null {\n return this._resourcesLoader.getSpineAtlasManager();\n }\n\n /**\n * Get the input manager of the game, storing mouse, keyboard\n * and touches states.\n * @return The input manager owned by the game\n */\n getInputManager(): gdjs.InputManager {\n return this._inputManager;\n }\n\n /**\n * Get the effects manager of the game, which allows to manage\n * effects on runtime objects or runtime layers.\n * @return The effects manager for the game\n */\n getEffectsManager(): gdjs.EffectsManager {\n return this._effectsManager;\n }\n\n /**\n * Get the object containing the game data\n * @return The object associated to the game.\n */\n getGameData(): ProjectData {\n return this._data;\n }\n\n getEventsBasedObjectData(type: string): EventsBasedObjectData | null {\n const eventsBasedObjectData = this._eventsBasedObjectDatas.get(type);\n if (!eventsBasedObjectData) {\n logger.error(\n 'The game has no events-based object of the type \"' + type + '\"'\n );\n return null;\n }\n return eventsBasedObjectData;\n }\n\n /**\n * Get the data associated to a scene.\n *\n * @param sceneName The name of the scene. If not defined, the first scene will be returned.\n * @return The data associated to the scene.\n */\n getSceneAndExtensionsData(\n sceneName?: string\n ): SceneAndExtensionsData | null {\n for (let i = 0, len = this._sceneAndExtensionsData.length; i < len; ++i) {\n const sceneAndExtensionsData = this._sceneAndExtensionsData[i];\n if (\n sceneName === undefined ||\n sceneAndExtensionsData.sceneData.name === sceneName\n ) {\n return sceneAndExtensionsData;\n }\n }\n logger.error('The game has no scene called \"' + sceneName + '\"');\n return null;\n }\n\n /**\n * Check if a scene exists\n *\n * @param sceneName The name of the scene to search.\n * @return true if the scene exists. If sceneName is undefined, true if the game has a scene.\n */\n hasScene(sceneName?: string): boolean {\n for (let i = 0, len = this._data.layouts.length; i < len; ++i) {\n const sceneData = this._data.layouts[i];\n if (sceneName === undefined || sceneData.name == sceneName) {\n return true;\n }\n }\n return false;\n }\n\n /**\n * Get the data associated to an external layout.\n *\n * @param name The name of the external layout.\n * @return The data associated to the external layout or null if not found.\n */\n getExternalLayoutData(name: string): ExternalLayoutData | null {\n let externalLayout: ExternalLayoutData | null = null;\n for (let i = 0, len = this._data.externalLayouts.length; i < len; ++i) {\n const layoutData = this._data.externalLayouts[i];\n if (layoutData.name === name) {\n externalLayout = layoutData;\n break;\n }\n }\n return externalLayout;\n }\n\n /**\n * Get the data representing all the global objects of the game.\n * @return The data associated to the global objects.\n */\n getInitialObjectsData(): ObjectData[] {\n return this._data.objects || [];\n }\n\n /**\n * Get the original width of the game, as set on the startup of the game.\n *\n * This is guaranteed to never change, even if the size of the game is changed afterwards.\n */\n getOriginalWidth(): float {\n return this._originalWidth;\n }\n\n /**\n * Get the original height of the game, as set on the startup of the game.\n *\n * This is guaranteed to never change, even if the size of the game is changed afterwards.\n */\n getOriginalHeight(): float {\n return this._originalHeight;\n }\n\n /**\n * Get the game resolution (the size at which the game is played and rendered) width.\n * @returns The game resolution width, in pixels.\n */\n getGameResolutionWidth(): float {\n return this._gameResolutionWidth;\n }\n\n /**\n * Get the game resolution (the size at which the game is played and rendered) height.\n * @returns The game resolution height, in pixels.\n */\n getGameResolutionHeight(): float {\n return this._gameResolutionHeight;\n }\n\n /**\n * Change the game resolution.\n *\n * @param width The new width\n * @param height The new height\n */\n setGameResolutionSize(width: float, height: float): void {\n this._gameResolutionWidth = width;\n this._gameResolutionHeight = height;\n if (this._adaptGameResolutionAtRuntime) {\n if (\n gdjs.RuntimeGameRenderer &&\n gdjs.RuntimeGameRenderer.getWindowInnerWidth &&\n gdjs.RuntimeGameRenderer.getWindowInnerHeight\n ) {\n const windowInnerWidth = gdjs.RuntimeGameRenderer.getWindowInnerWidth();\n const windowInnerHeight = gdjs.RuntimeGameRenderer.getWindowInnerHeight();\n\n // Enlarge either the width or the eight to fill the inner window space.\n if (this._resizeMode === 'adaptWidth') {\n this._gameResolutionWidth =\n (this._gameResolutionHeight * windowInnerWidth) /\n windowInnerHeight;\n } else {\n if (this._resizeMode === 'adaptHeight') {\n this._gameResolutionHeight =\n (this._gameResolutionWidth * windowInnerHeight) /\n windowInnerWidth;\n }\n }\n }\n } else {\n }\n\n // Don't alter the game resolution. The renderer\n // will maybe adapt the size of the canvas or whatever is used to render the\n // game in the window, but this does not change the \"game resolution\".\n\n // Notify the renderer that game resolution changed (so that the renderer size\n // can be updated, and maybe other things like the canvas size), and let the\n // scenes know too.\n this._renderer.updateRendererSize();\n this._notifyScenesForGameResolutionResize = true;\n }\n\n /**\n * Set if the width or the height of the game resolution\n * should be changed to fit the game window - or if the game\n * resolution should not be updated automatically.\n *\n * @param resizeMode Either \"\" (don't change game resolution), \"adaptWidth\" or \"adaptHeight\".\n */\n setGameResolutionResizeMode(resizeMode: string): void {\n this._resizeMode = resizeMode;\n this._forceGameResolutionUpdate();\n }\n\n /**\n * Returns if the width or the height of the game resolution\n * should be changed to fit the game window - or if the game\n * resolution should not be updated automatically (empty string).\n *\n * @returns Either \"\" (don't change game resolution), \"adaptWidth\" or \"adaptHeight\".\n */\n getGameResolutionResizeMode(): string {\n return this._resizeMode;\n }\n\n /**\n * Set if the game resolution should be automatically adapted\n * when the game window or screen size change. This will only\n * be the case if the game resolution resize mode is\n * configured to adapt the width or the height of the game.\n * @param enable true to change the game resolution according to the window/screen size.\n */\n setAdaptGameResolutionAtRuntime(enable: boolean): void {\n this._adaptGameResolutionAtRuntime = enable;\n this._forceGameResolutionUpdate();\n }\n\n /**\n * Returns if the game resolution should be automatically adapted\n * when the game window or screen size change. This will only\n * be the case if the game resolution resize mode is\n * configured to adapt the width or the height of the game.\n * @returns true if the game resolution is automatically changed according to the window/screen size.\n */\n getAdaptGameResolutionAtRuntime(): boolean {\n return this._adaptGameResolutionAtRuntime;\n }\n\n /**\n * Return the minimal fps that must be guaranteed by the game\n * (otherwise, game is slowed down).\n */\n getMinimalFramerate(): integer {\n return this._minFPS;\n }\n\n /**\n * Return the scale mode of the game (\"linear\" or \"nearest\").\n */\n getScaleMode(): 'linear' | 'nearest' {\n return this._scaleMode;\n }\n\n /**\n * Return if the game is rounding pixels when rendering.\n */\n getPixelsRounding(): boolean {\n return this._pixelsRounding;\n }\n\n /**\n * Return the antialiasing mode used by the game (\"none\" or \"MSAA\").\n */\n getAntialiasingMode(): 'none' | 'MSAA' {\n return this._antialiasingMode;\n }\n\n /**\n * Return true if antialising is enabled on mobiles.\n */\n isAntialisingEnabledOnMobile(): boolean {\n return this._isAntialisingEnabledOnMobile;\n }\n\n /**\n * Set or unset the game as paused.\n * When paused, the game won't step and will be freezed. Useful for debugging.\n * @param enable true to pause the game, false to unpause\n */\n pause(enable: boolean) {\n if (this._paused === enable) return;\n\n this._paused = enable;\n if (this._debuggerClient) {\n if (this._paused) this._debuggerClient.sendGamePaused();\n else this._debuggerClient.sendGameResumed();\n }\n }\n\n /**\n * @returns true during the first frame the game is back from being hidden.\n * This has nothing to do with `_paused`.\n */\n hasJustResumed() {\n return this._hasJustResumed;\n }\n\n /**\n * Preload a scene assets as soon as possible in background.\n */\n prioritizeLoadingOfScene(sceneName: string) {\n // Don't await the scene assets to be loaded.\n this._resourcesLoader.loadSceneResources(sceneName);\n }\n\n /**\n * @return The progress of assets loading in background for a scene\n * (between 0 and 1).\n */\n getSceneLoadingProgress(sceneName: string): number {\n return this._resourcesLoader.getSceneLoadingProgress(sceneName);\n }\n\n /**\n * @returns true when all the resources of the given scene are loaded\n * (but maybe not parsed).\n */\n areSceneAssetsLoaded(sceneName: string): boolean {\n return this._resourcesLoader.areSceneAssetsLoaded(sceneName);\n }\n\n /**\n * @returns true when all the resources of the given scene are loaded and\n * parsed.\n */\n areSceneAssetsReady(sceneName: string): boolean {\n return this._resourcesLoader.areSceneAssetsReady(sceneName);\n }\n\n /**\n * Load all assets needed to display the 1st scene, displaying progress in\n * renderer.\n */\n loadAllAssets(\n callback: () => void,\n progressCallback?: (progress: float) => void\n ) {\n this.loadFirstAssetsAndStartBackgroundLoading(\n this._getFirstSceneName(),\n progressCallback\n ).then(callback);\n }\n\n /**\n * Load all assets needed to display the 1st scene, displaying progress in\n * renderer.\n *\n * When a game is hot-reload, this method can be called with the current\n * scene.\n */\n async loadFirstAssetsAndStartBackgroundLoading(\n firstSceneName: string,\n progressCallback?: (progress: float) => void\n ): Promise<void> {\n try {\n // Download the loading screen background image first to be able to\n // display the loading screen as soon as possible.\n const backgroundImageResourceName = this._data.properties.loadingScreen\n .backgroundImageResourceName;\n if (backgroundImageResourceName) {\n await this._resourcesLoader\n .getImageManager()\n .loadResource(backgroundImageResourceName);\n }\n await Promise.all([\n this._loadAssetsWithLoadingScreen(\n /* isFirstScene = */ true,\n async (onProgress) => {\n // TODO Is a setting needed?\n if (false) {\n await this._resourcesLoader.loadAllResources(onProgress);\n } else {\n await this._resourcesLoader.loadGlobalAndFirstSceneResources(\n firstSceneName,\n onProgress\n );\n // Don't await as it must not block the first scene from starting.\n this._resourcesLoader.loadAllSceneInBackground();\n }\n },\n progressCallback\n ),\n // TODO This is probably not necessary in case of hot reload.\n gdjs.getAllAsynchronouslyLoadingLibraryPromise(),\n ]);\n } catch (e) {\n if (this._debuggerClient) this._debuggerClient.onUncaughtException(e);\n\n throw e;\n }\n }\n\n /**\n * Load all assets for a given scene, displaying progress in renderer.\n */\n async loadSceneAssets(\n sceneName: string,\n progressCallback?: (progress: float) => void\n ): Promise<void> {\n await this._loadAssetsWithLoadingScreen(\n /* isFirstLayout = */ false,\n async (onProgress) => {\n await this._resourcesLoader.loadAndProcessSceneResources(\n sceneName,\n onProgress\n );\n },\n progressCallback\n );\n }\n\n /**\n * Load assets, displaying progress in renderer.\n */\n private async _loadAssetsWithLoadingScreen(\n isFirstScene: boolean,\n loadAssets: (\n onProgress: (count: integer, total: integer) => Promise<void>\n ) => Promise<void>,\n progressCallback?: (progress: float) => void\n ): Promise<void> {\n this.pause(true);\n const loadingScreen = new gdjs.LoadingScreenRenderer(\n this.getRenderer(),\n this._resourcesLoader.getImageManager(),\n this._data.properties.loadingScreen,\n this._data.properties.watermark.showWatermark,\n isFirstScene\n );\n\n const onProgress = async (count: integer, total: integer) => {\n const percent = Math.floor((100 * count) / total);\n loadingScreen.setPercent(percent);\n if (progressCallback) {\n progressCallback(percent);\n }\n const hasRendered = loadingScreen.renderIfNeeded();\n if (hasRendered) {\n // Give a chance to draw calls from the renderer to be handled.\n await sleep(1);\n }\n };\n await loadAssets(onProgress);\n\n await loadingScreen.unload();\n this.pause(false);\n }\n\n private _getFirstSceneName(): string {\n const firstSceneName = this._data.firstLayout;\n return this.hasScene(firstSceneName)\n ? firstSceneName\n : // There is always at least a scene\n this.getSceneAndExtensionsData()!.sceneData.name;\n }\n\n /**\n * Start the game loop, to be called once assets are loaded.\n */\n startGameLoop() {\n try {\n if (!this.hasScene()) {\n logger.error('The game has no scene.');\n return;\n }\n this._forceGameResolutionUpdate();\n\n // Load the first scene\n this._sceneStack.push(\n this._getFirstSceneName(),\n this._injectExternalLayout\n );\n this._watermark.displayAtStartup();\n\n //Uncomment to profile the first x frames of the game.\n // var x = 500;\n // var startTime = Date.now();\n // console.profile(\"Stepping for \" + x + \" frames\")\n // for(var i = 0; i < x; ++i) {\n // this._sceneStack.step(16);\n // }\n // console.profileEnd();\n // var time = Date.now() - startTime;\n // logger.log(\"Took\", time, \"ms\");\n // return;\n\n this._setupGameVisibilityEvents();\n\n // The standard game loop\n let accumulatedElapsedTime = 0;\n this._hasJustResumed = false;\n this._renderer.startGameLoop((lastCallElapsedTime) => {\n try {\n if (this._paused) {\n return true;\n }\n\n // Skip the frame if we rendering frames too fast\n accumulatedElapsedTime += lastCallElapsedTime;\n if (\n this._maxFPS > 0 &&\n 1000.0 / accumulatedElapsedTime > this._maxFPS + 7\n ) {\n // Only skip frame if the framerate is 7 frames above the maximum framerate.\n // Most browser/engines will try to run at slightly more than 60 frames per second.\n // If game is set to have a maximum FPS to 60, then one out of two frames will be dropped.\n // Hence, we use a 7 frames margin to ensure that we're not skipping frames too much.\n return true;\n }\n const elapsedTime = accumulatedElapsedTime;\n accumulatedElapsedTime = 0;\n\n // Manage resize events.\n if (this._notifyScenesForGameResolutionResize) {\n this._sceneStack.onGameResolutionResized();\n this._notifyScenesForGameResolutionResize = false;\n }\n\n // Render and step the scene.\n if (this._sceneStack.step(elapsedTime)) {\n this.getInputManager().onFrameEnded();\n this._hasJustResumed = false;\n return true;\n }\n return false;\n } catch (e) {\n if (this._debuggerClient)\n this._debuggerClient.onUncaughtException(e);\n\n throw e;\n }\n });\n setTimeout(() => {\n this._setupSessionMetrics();\n }, 4000);\n } catch (e) {\n if (this._debuggerClient) this._debuggerClient.onUncaughtException(e);\n\n throw e;\n }\n }\n\n /**\n * Set if the session should be registered.\n */\n enableMetrics(enable: boolean): void {\n this._disableMetrics = !enable;\n if (enable) {\n this._setupSessionMetrics();\n }\n }\n\n /**\n * Helper function to get information about the platform running the game.\n */\n getPlatformInfo = () => {\n return {\n // @ts-ignore\n isCordova: !!window.cordova,\n devicePlatform:\n // @ts-ignore\n typeof device !== 'undefined' ? device.platform || '' : '',\n navigatorPlatform:\n typeof navigator !== 'undefined' ? navigator.platform : '',\n hasTouch:\n typeof navigator !== 'undefined'\n ? !!navigator.maxTouchPoints && navigator.maxTouchPoints > 2\n : false,\n supportedCompressionMethods: getSupportedCompressionMethods(),\n };\n };\n\n _setupGameVisibilityEvents() {\n if (typeof navigator !== 'undefined' && typeof document !== 'undefined') {\n document.addEventListener('visibilitychange', () => {\n if (document.visibilityState === 'visible') {\n this._hasJustResumed = true;\n }\n });\n window.addEventListener(\n 'resume',\n () => {\n this._hasJustResumed = true;\n },\n false\n );\n }\n }\n\n /**\n * Register a new session for the game, and set up listeners to follow the session\n * time.\n */\n _setupSessionMetrics() {\n if (this._sessionMetricsInitialized) {\n return;\n }\n if (this._disableMetrics) {\n return;\n }\n if (this.isPreview()) {\n return;\n }\n if (typeof fetch === 'undefined') {\n return;\n }\n if (!this._data.properties.projectUuid) {\n return;\n }\n const baseUrl = 'https://api.gdevelop-app.com/analytics';\n this._playerId = this._makePlayerUuid();\n /**\n * The duration that is already sent to the service\n * (in milliseconds).\n **/\n let sentDuration = 0;\n /**\n * The duration that is not yet sent to the service to avoid flooding\n * (in milliseconds).\n **/\n let notYetSentDuration = 0;\n /**\n * The last time when duration has been counted\n * either in sendedDuration or notYetSentDuration.\n **/\n let lastSessionResumeTime = Date.now();\n const platform = this.getPlatformInfo();\n fetch(baseUrl + '/session', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n // It's important to ensure that the data sent here does not contain\n // any personal information from the player or that would allow to\n // precisely identify someone.\n body: JSON.stringify({\n gameId: this._data.properties.projectUuid,\n playerId: this._playerId,\n game: {\n name: this._data.properties.name || '',\n packageName: this._data.properties.packageName || '',\n version: this._data.properties.version || '',\n location: window.location.href,\n },\n platform: {\n isCordova: platform.isCordova,\n devicePlatform: platform.devicePlatform,\n navigatorPlatform: platform.navigatorPlatform,\n hasTouch: platform.hasTouch,\n },\n }),\n })\n .then((response) => {\n // Ensure the session is correctly created to avoid sending hits that will fail.\n if (!response.ok) {\n console.error('Error while creating the session', response);\n throw new Error('Error while creating the session');\n }\n return response;\n })\n .then((response) => response.text())\n .then((returnedSessionId) => {\n this._sessionId = returnedSessionId;\n })\n .catch(() => {});\n\n /* Ignore any error */\n const sendSessionHit = () => {\n if (!this._sessionId) {\n return;\n }\n\n const now = Date.now();\n notYetSentDuration += now - lastSessionResumeTime;\n lastSessionResumeTime = now;\n\n // Group repeated calls to sendSessionHit - which could\n // happen because of multiple event listeners being fired.\n if (notYetSentDuration < 5 * 1000) {\n return;\n }\n // The backend use seconds for duration.\n // The milliseconds will stay in notYetSentDuration.\n const toBeSentDuration = Math.floor(notYetSentDuration / 1000) * 1000;\n sentDuration += toBeSentDuration;\n notYetSentDuration -= toBeSentDuration;\n\n navigator.sendBeacon(\n baseUrl + '/session-hit',\n JSON.stringify({\n gameId: this._data.properties.projectUuid,\n playerId: this._playerId,\n sessionId: this._sessionId,\n duration: Math.floor(sentDuration / 1000),\n })\n );\n };\n if (typeof navigator !== 'undefined' && typeof document !== 'undefined') {\n document.addEventListener('visibilitychange', () => {\n if (document.visibilityState === 'visible') {\n // Skip the duration the game was hidden.\n lastSessionResumeTime = Date.now();\n } else {\n sendSessionHit();\n }\n });\n window.addEventListener('pagehide', sendSessionHit, false);\n // Cordova events\n window.addEventListener('pause', sendSessionHit, false);\n window.addEventListener(\n 'resume',\n () => {\n // Skip the duration the game was hidden.\n lastSessionResumeTime = Date.now();\n },\n false\n );\n\n // Detect Safari to work around Safari-specific bugs:\n // - https://bugs.webkit.org/show_bug.cgi?id=151610\n // - https://bugs.webkit.org/show_bug.cgi?id=151234\n // @ts-ignore\n const isSafari = typeof safari === 'object' && safari.pushNotification;\n const isElectron = /electron/i.test(navigator.userAgent);\n if (isSafari || isElectron) {\n window.addEventListener('beforeunload', () => {\n sendSessionHit();\n });\n }\n }\n this._sessionMetricsInitialized = true;\n this._sessionId = this._sessionId;\n }\n\n /**\n * Generate an anonymous unique identifier to differentiate\n * the player from others in the game metrics.\n */\n _makePlayerUuid(): string {\n try {\n const key = 'GDJS-internal-player-uuid';\n const existingPlayerUuid = localStorage.getItem(key);\n if (existingPlayerUuid) {\n return existingPlayerUuid;\n }\n const newPlayerUuid = gdjs.makeUuid();\n localStorage.setItem(key, newPlayerUuid);\n return newPlayerUuid;\n } catch (err) {\n return gdjs.makeUuid();\n }\n }\n\n getSessionId(): string | null {\n return this._sessionId;\n }\n\n getPlayerId(): string | null {\n return this._playerId;\n }\n\n /**\n * Called by the game renderer when the window containing the game\n * has changed size (this can result from a resize of the window,\n * but also other factors like a device orientation change on mobile).\n */\n onWindowInnerSizeChanged() {\n this._forceGameResolutionUpdate();\n }\n\n /**\n * Enlarge/reduce the width (or the height) of the game to fill the inner window.\n */\n _forceGameResolutionUpdate() {\n this.setGameResolutionSize(\n this._gameResolutionWidth,\n this._gameResolutionHeight\n );\n }\n\n /**\n * Start a profiler for the currently running scene.\n * @param onProfilerStopped Function to be called when the profiler is stopped. Will be passed the profiler as argument.\n */\n startCurrentSceneProfiler(\n onProfilerStopped: (oldProfiler: Profiler) => void\n ) {\n const currentScene = this._sceneStack.getCurrentScene();\n if (!currentScene) {\n return false;\n }\n currentScene.startProfiler(onProfilerStopped);\n return true;\n }\n\n /**\n * Stop the profiler for the currently running scene.\n */\n stopCurrentSceneProfiler() {\n const currentScene = this._sceneStack.getCurrentScene();\n if (!currentScene) {\n return;\n }\n currentScene.stopProfiler();\n }\n\n /**\n * Return true if a scene was loaded, false otherwise (i.e: game not yet started).\n */\n wasFirstSceneLoaded(): boolean {\n return this._sceneStack.wasFirstSceneLoaded();\n }\n\n /**\n * Return the stack of {@link gdjs.RuntimeScene} being played.\n */\n getSceneStack(): gdjs.SceneStack {\n return this._sceneStack;\n }\n\n /**\n * Check if the game is running as a preview, launched from an editor.\n * @returns true if the current game is a preview.\n */\n isPreview(): boolean {\n return this._isPreview;\n }\n\n /**\n * Check if the game should call GDevelop development APIs or not.\n *\n * Unless you are contributing to GDevelop, avoid using this.\n */\n isUsingGDevelopDevelopmentEnvironment(): boolean {\n return this._options.environment === 'dev';\n }\n\n /**\n * Gets an extension property from the project data.\n * @param extensionName The extension name.\n * @param propertyName The property name.\n * @return The property value.\n */\n getExtensionProperty(\n extensionName: string,\n propertyName: string\n ): string | null {\n for (let property of this._data.properties.extensionProperties) {\n if (\n property.extension === extensionName &&\n property.property === propertyName\n ) {\n return property.value;\n }\n }\n return null;\n }\n\n /**\n * Resolves the name of an embedded resource.\n * @param mainResourceName The name of the resource containing the embedded resource.\n * @param embeddedResourceName The name of the embedded resource.\n * @return The resource name.\n */\n resolveEmbeddedResource(\n mainResourceName: string,\n embeddedResourceName: string\n ): string {\n const mapping = this._embeddedResourcesMappings.get(mainResourceName);\n return mapping && mapping[embeddedResourceName]\n ? mapping[embeddedResourceName]\n : embeddedResourceName;\n }\n\n /**\n * Returns the array of resources that are embedded to passed one.\n * @param resourceName The name of resource to find embedded resources of.\n * @returns The array of related resources names.\n */\n getEmbeddedResourcesNames(resourceName: string): string[] {\n return this._embeddedResourcesMappings.has(resourceName)\n ? Object.keys(this._embeddedResourcesMappings.get(resourceName)!)\n : [];\n }\n\n getNetworkSyncData(\n syncOptions: GetNetworkSyncDataOptions\n ): GameNetworkSyncData | null {\n const syncData: GameNetworkSyncData = {\n var: this._variables.getNetworkSyncData(syncOptions),\n ss: this._sceneStack.getNetworkSyncData(syncOptions) || undefined,\n };\n\n const extensionsVariablesSyncData = {};\n this._variablesByExtensionName.forEach((variables, extensionName) => {\n const extensionVariablesSyncData = variables.getNetworkSyncData(\n syncOptions\n );\n // If there is no variables to sync, don't include the extension in the sync data.\n if (extensionVariablesSyncData.length) {\n extensionsVariablesSyncData[\n extensionName\n ] = extensionVariablesSyncData;\n }\n });\n syncData.extVar = extensionsVariablesSyncData;\n\n if (\n (!syncData.var || syncData.var.length === 0) &&\n !syncData.ss &&\n (!syncData.extVar || Object.keys(syncData.extVar).length === 0)\n ) {\n // Nothing to sync.\n return null;\n }\n\n return syncData;\n }\n\n updateFromNetworkSyncData(syncData: GameNetworkSyncData) {\n if (syncData.var) {\n this._variables.updateFromNetworkSyncData(syncData.var);\n }\n if (syncData.ss) {\n this._sceneStack.updateFromNetworkSyncData(syncData.ss);\n }\n if (syncData.extVar) {\n for (const extensionName in syncData.extVar) {\n if (!syncData.extVar.hasOwnProperty(extensionName)) {\n continue;\n }\n const extensionVariablesData = syncData.extVar[extensionName];\n const extensionVariables = this.getVariablesForExtension(\n extensionName\n );\n if (extensionVariables) {\n extensionVariables.updateFromNetworkSyncData(\n extensionVariablesData\n );\n }\n }\n }\n }\n }\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/*\n * GDevelop JS Platform\n * Copyright 2013-2016 Florian Rival (Florian.Rival@gmail.com). All rights reserved.\n * This project is released under the MIT License.\n */\nnamespace gdjs {\n const logger = new gdjs.Logger('Game manager');\n\n const sleep = (ms: float) =>\n new Promise((resolve) => setTimeout(resolve, ms));\n\n /** Identify a script file, with its content hash (useful for hot-reloading). */\n export type RuntimeGameOptionsScriptFile = {\n /** The path for this script file. */\n path: string;\n /** The hash of the script file content. */\n hash: number;\n };\n\n const getGlobalResourceNames = (projectData: ProjectData): Array<string> =>\n projectData.usedResources.map((resource) => resource.name);\n\n let supportedCompressionMethods: ('cs:gzip' | 'cs:deflate')[] | null = null;\n const getSupportedCompressionMethods = (): ('cs:gzip' | 'cs:deflate')[] => {\n if (!!supportedCompressionMethods) {\n return supportedCompressionMethods;\n }\n supportedCompressionMethods = [];\n\n try {\n // @ts-ignore - We are checking if the CompressionStream is available.\n new CompressionStream('gzip');\n supportedCompressionMethods.push('cs:gzip');\n } catch (e) {}\n try {\n // @ts-ignore - We are checking if the CompressionStream is available.\n new CompressionStream('deflate');\n supportedCompressionMethods.push('cs:deflate');\n } catch (e) {}\n\n return supportedCompressionMethods;\n };\n\n /** Options given to the game at startup. */\n export type RuntimeGameOptions = {\n /** if true, force fullscreen. */\n forceFullscreen?: boolean;\n /** if true, game is run as a preview launched from an editor. */\n isPreview?: boolean;\n /** The name of the external layout to create in the scene at position 0;0. */\n injectExternalLayout?: string;\n /** Script files, used for hot-reloading. */\n scriptFiles?: Array<RuntimeGameOptionsScriptFile>;\n /** if true, export is a partial preview without events. */\n projectDataOnlyExport?: boolean;\n /** if true, preview is launched from GDevelop native mobile app. */\n nativeMobileApp?: boolean;\n /** The address of the debugger server, to reach out using WebSocket. */\n websocketDebuggerServerAddress?: string;\n /** The port of the debugger server, to reach out using WebSocket. */\n websocketDebuggerServerPort?: string;\n\n /**\n * The path to require `@electron/remote` module.\n * This is only useful in a preview, where this can't be required from\n * `@electron/remote` directly as previews don't have any node_modules.\n * On the contrary, a game packaged with Electron as a standalone app\n * has its node_modules.\n * This can be removed once there are no more dependencies on\n * `@electron/remote` in the game engine and extensions.\n */\n electronRemoteRequirePath?: string;\n\n /**\n * The token to use by the game engine when requiring any resource stored on\n * GDevelop Cloud buckets. Note that this is only useful during previews.\n */\n gdevelopResourceToken?: string;\n\n /**\n * Check if, in some exceptional cases, we allow authentication\n * to be done through a iframe.\n * This is usually discouraged as the user can't verify that the authentication\n * window is a genuine one. It's only to be used in trusted contexts.\n */\n allowAuthenticationUsingIframeForPreview?: boolean;\n\n /** If set, the game will send crash reports to GDevelop APIs. */\n crashReportUploadLevel?: 'all' | 'exclude-javascript-code-events' | 'none';\n\n /** Arbitrary string explaining in which context the game is being played. */\n previewContext?: string;\n\n /** The GDevelop version used to build the game. */\n gdevelopVersionWithHash?: string;\n\n /** The template slug that was used to create the project. */\n projectTemplateSlug?: string;\n\n /** The source game id that was used to create the project. */\n sourceGameId?: string;\n\n /** Any capture that should be done during the preview. */\n captureOptions?: CaptureOptions;\n\n /**\n * If set, this data is used to authenticate automatically when launching the game.\n * This is only useful during previews.\n */\n playerUsername?: string;\n playerId?: string;\n playerToken?: string;\n\n /**\n * If set, the game should use the specified environment for making calls\n * to GDevelop APIs (\"dev\" = development APIs).\n */\n environment?: 'dev';\n };\n\n /**\n * Represents a game being played.\n */\n export class RuntimeGame {\n _resourcesLoader: gdjs.ResourceLoader;\n _variables: VariablesContainer;\n _variablesByExtensionName: Map<string, gdjs.VariablesContainer>;\n _data: ProjectData;\n _sceneAndExtensionsData: Array<SceneAndExtensionsData> = [];\n _eventsBasedObjectDatas: Map<String, EventsBasedObjectData>;\n _effectsManager: EffectsManager;\n _maxFPS: integer;\n _minFPS: integer;\n _gameResolutionWidth: integer;\n _gameResolutionHeight: integer;\n _originalWidth: float;\n _originalHeight: float;\n _resizeMode: 'adaptWidth' | 'adaptHeight' | string;\n _adaptGameResolutionAtRuntime: boolean;\n _scaleMode: 'linear' | 'nearest';\n _pixelsRounding: boolean;\n _antialiasingMode: 'none' | 'MSAA';\n _isAntialisingEnabledOnMobile: boolean;\n /**\n * Game loop management (see startGameLoop method)\n */\n _renderer: RuntimeGameRenderer;\n _sessionId: string | null;\n _playerId: string | null;\n _watermark: watermark.RuntimeWatermark;\n\n _sceneStack: SceneStack;\n /**\n * When set to true, the scenes are notified that game resolution size changed.\n */\n _notifyScenesForGameResolutionResize: boolean = false;\n\n /**\n * When paused, the game won't step and will be freezed. Useful for debugging.\n */\n _paused: boolean = false;\n\n /**\n * True during the first frame the game is back from being hidden.\n * This has nothing to do with `_paused`.\n */\n _hasJustResumed: boolean = false;\n\n //Inputs :\n _inputManager: InputManager;\n\n /**\n * Allow to specify an external layout to insert in the first scene.\n */\n _injectExternalLayout: any;\n _options: RuntimeGameOptions;\n\n /**\n * The mappings for embedded resources\n */\n _embeddedResourcesMappings: Map<string, Record<string, string>>;\n\n /**\n * Optional client to connect to a debugger server.\n */\n _debuggerClient: gdjs.AbstractDebuggerClient | null;\n _sessionMetricsInitialized: boolean = false;\n _disableMetrics: boolean = false;\n _isPreview: boolean;\n\n /**\n * The capture manager, used to manage captures (screenshots, videos, etc...).\n */\n _captureManager: CaptureManager | null;\n\n /** True if the RuntimeGame has been disposed and should not be used anymore. */\n _wasDisposed: boolean = false;\n\n /**\n * @param data The object (usually stored in data.json) containing the full project data\n * @param\n */\n constructor(data: ProjectData, options?: RuntimeGameOptions) {\n this._options = options || {};\n this._variables = new gdjs.VariablesContainer(data.variables);\n this._variablesByExtensionName = new Map<\n string,\n gdjs.VariablesContainer\n >();\n for (const extensionData of data.eventsFunctionsExtensions) {\n if (extensionData.globalVariables.length > 0) {\n this._variablesByExtensionName.set(\n extensionData.name,\n new gdjs.VariablesContainer(extensionData.globalVariables)\n );\n }\n }\n this._eventsBasedObjectDatas = new Map<String, EventsBasedObjectData>();\n this._data = data;\n this._updateSceneAndExtensionsData();\n\n this._resourcesLoader = new gdjs.ResourceLoader(\n this,\n data.resources.resources,\n getGlobalResourceNames(data),\n data.layouts\n );\n\n this._effectsManager = new gdjs.EffectsManager();\n this._maxFPS = this._data.properties.maxFPS;\n this._minFPS = this._data.properties.minFPS;\n this._gameResolutionWidth = this._data.properties.windowWidth;\n this._gameResolutionHeight = this._data.properties.windowHeight;\n this._originalWidth = this._gameResolutionWidth;\n this._originalHeight = this._gameResolutionHeight;\n this._resizeMode = this._data.properties.sizeOnStartupMode;\n this._adaptGameResolutionAtRuntime = this._data.properties.adaptGameResolutionAtRuntime;\n this._scaleMode = data.properties.scaleMode || 'linear';\n this._pixelsRounding = this._data.properties.pixelsRounding;\n this._antialiasingMode = this._data.properties.antialiasingMode;\n this._isAntialisingEnabledOnMobile = this._data.properties.antialisingEnabledOnMobile;\n this._renderer = new gdjs.RuntimeGameRenderer(\n this,\n this._options.forceFullscreen || false\n );\n this._watermark = new gdjs.watermark.RuntimeWatermark(\n this,\n data.properties.authorUsernames,\n this._data.properties.watermark\n );\n this._sceneStack = new gdjs.SceneStack(this);\n this._inputManager = new gdjs.InputManager();\n this._injectExternalLayout = this._options.injectExternalLayout || '';\n this._debuggerClient = gdjs.DebuggerClient\n ? new gdjs.DebuggerClient(this)\n : null;\n this._captureManager = gdjs.CaptureManager\n ? new gdjs.CaptureManager(\n this._renderer,\n this._options.captureOptions || {}\n )\n : null;\n this._isPreview = this._options.isPreview || false;\n this._sessionId = null;\n this._playerId = null;\n\n this._embeddedResourcesMappings = new Map();\n for (const resource of this._data.resources.resources) {\n if (resource.metadata) {\n try {\n const metadata = JSON.parse(resource.metadata);\n if (metadata?.embeddedResourcesMapping) {\n this._embeddedResourcesMappings.set(\n resource.name,\n metadata.embeddedResourcesMapping\n );\n }\n } catch {\n logger.error(\n 'Some metadata of resources can not be successfully parsed.'\n );\n }\n }\n }\n\n if (this.isUsingGDevelopDevelopmentEnvironment()) {\n logger.info(\n 'This game will run on the development version of GDevelop APIs.'\n );\n }\n }\n\n /**\n * Update the project data. Useful for hot-reloading, should not be used otherwise.\n *\n * @param projectData The object (usually stored in data.json) containing the full project data\n */\n setProjectData(projectData: ProjectData): void {\n this._data = projectData;\n this._updateSceneAndExtensionsData();\n this._resourcesLoader.setResources(\n projectData.resources.resources,\n getGlobalResourceNames(projectData),\n projectData.layouts\n );\n }\n\n private _updateSceneAndExtensionsData(): void {\n const usedExtensionsWithVariablesData = this._data.eventsFunctionsExtensions.filter(\n (extensionData) => extensionData.sceneVariables.length > 0\n );\n this._sceneAndExtensionsData = this._data.layouts.map((sceneData) => ({\n sceneData,\n usedExtensionsWithVariablesData,\n }));\n\n this._eventsBasedObjectDatas.clear();\n if (this._data.eventsFunctionsExtensions) {\n for (const extension of this._data.eventsFunctionsExtensions) {\n for (const eventsBasedObject of extension.eventsBasedObjects) {\n this._eventsBasedObjectDatas.set(\n extension.name + '::' + eventsBasedObject.name,\n eventsBasedObject\n );\n }\n }\n }\n }\n\n /**\n * Return the additional options passed to the RuntimeGame when created.\n * @returns The additional options, if any.\n */\n getAdditionalOptions(): RuntimeGameOptions {\n return this._options;\n }\n\n getRenderer(): gdjs.RuntimeGameRenderer {\n return this._renderer;\n }\n\n /**\n * Get the variables of the RuntimeGame.\n * @return The global variables\n */\n getVariables(): gdjs.VariablesContainer {\n return this._variables;\n }\n\n /**\n * Get the extension's global variables.\n * @param extensionName The extension name.\n * @returns The extension's global variables.\n */\n getVariablesForExtension(extensionName: string) {\n return this._variablesByExtensionName.get(extensionName) || null;\n }\n\n /**\n * Get the gdjs.SoundManager of the RuntimeGame.\n * @return The sound manager.\n */\n getSoundManager(): gdjs.HowlerSoundManager {\n return this._resourcesLoader.getSoundManager();\n }\n\n /**\n * Get the gdjs.ImageManager of the RuntimeGame.\n * @return The image manager.\n */\n getImageManager(): gdjs.PixiImageManager {\n return this._resourcesLoader.getImageManager();\n }\n\n /**\n * Get the gdjs.FontManager of the RuntimeGame.\n * @return The font manager.\n */\n getFontManager(): gdjs.FontFaceObserverFontManager {\n return this._resourcesLoader.getFontManager();\n }\n\n /**\n * Get the gdjs.BitmapFontManager of the RuntimeGame.\n * @return The bitmap font manager.\n */\n getBitmapFontManager(): gdjs.BitmapFontManager {\n return this._resourcesLoader.getBitmapFontManager();\n }\n\n /**\n * Get the JSON manager of the game, used to load JSON from game\n * resources.\n * @return The json manager for the game\n */\n getJsonManager(): gdjs.JsonManager {\n return this._resourcesLoader.getJsonManager();\n }\n\n /**\n * Get the 3D model manager of the game, used to load 3D model from game\n * resources.\n * @return The 3D model manager for the game\n */\n getModel3DManager(): gdjs.Model3DManager {\n return this._resourcesLoader.getModel3DManager();\n }\n\n /**\n * Get the Spine manager of the game, used to load and construct spine skeletons from game\n * resources.\n * @return The Spine manager for the game\n */\n getSpineManager(): gdjs.SpineManager | null {\n return this._resourcesLoader.getSpineManager();\n }\n\n /**\n * Get the Spine Atlas manager of the game, used to load atlases from game\n * resources.\n * @return The Spine Atlas manager for the game\n */\n getSpineAtlasManager(): gdjs.SpineAtlasManager | null {\n return this._resourcesLoader.getSpineAtlasManager();\n }\n\n /**\n * Get the input manager of the game, storing mouse, keyboard\n * and touches states.\n * @return The input manager owned by the game\n */\n getInputManager(): gdjs.InputManager {\n return this._inputManager;\n }\n\n /**\n * Get the effects manager of the game, which allows to manage\n * effects on runtime objects or runtime layers.\n * @return The effects manager for the game\n */\n getEffectsManager(): gdjs.EffectsManager {\n return this._effectsManager;\n }\n\n /**\n * Get the object containing the game data\n * @return The object associated to the game.\n */\n getGameData(): ProjectData {\n return this._data;\n }\n\n getEventsBasedObjectData(type: string): EventsBasedObjectData | null {\n const eventsBasedObjectData = this._eventsBasedObjectDatas.get(type);\n if (!eventsBasedObjectData) {\n logger.error(\n 'The game has no events-based object of the type \"' + type + '\"'\n );\n return null;\n }\n return eventsBasedObjectData;\n }\n\n /**\n * Get the data associated to a scene.\n *\n * @param sceneName The name of the scene. If not defined, the first scene will be returned.\n * @return The data associated to the scene.\n */\n getSceneAndExtensionsData(\n sceneName?: string\n ): SceneAndExtensionsData | null {\n for (let i = 0, len = this._sceneAndExtensionsData.length; i < len; ++i) {\n const sceneAndExtensionsData = this._sceneAndExtensionsData[i];\n if (\n sceneName === undefined ||\n sceneAndExtensionsData.sceneData.name === sceneName\n ) {\n return sceneAndExtensionsData;\n }\n }\n logger.error('The game has no scene called \"' + sceneName + '\"');\n return null;\n }\n\n /**\n * Check if a scene exists\n *\n * @param sceneName The name of the scene to search.\n * @return true if the scene exists. If sceneName is undefined, true if the game has a scene.\n */\n hasScene(sceneName?: string): boolean {\n for (let i = 0, len = this._data.layouts.length; i < len; ++i) {\n const sceneData = this._data.layouts[i];\n if (sceneName === undefined || sceneData.name == sceneName) {\n return true;\n }\n }\n return false;\n }\n\n /**\n * Get the data associated to an external layout.\n *\n * @param name The name of the external layout.\n * @return The data associated to the external layout or null if not found.\n */\n getExternalLayoutData(name: string): ExternalLayoutData | null {\n let externalLayout: ExternalLayoutData | null = null;\n for (let i = 0, len = this._data.externalLayouts.length; i < len; ++i) {\n const layoutData = this._data.externalLayouts[i];\n if (layoutData.name === name) {\n externalLayout = layoutData;\n break;\n }\n }\n return externalLayout;\n }\n\n /**\n * Get the data representing all the global objects of the game.\n * @return The data associated to the global objects.\n */\n getInitialObjectsData(): ObjectData[] {\n return this._data.objects || [];\n }\n\n /**\n * Get the original width of the game, as set on the startup of the game.\n *\n * This is guaranteed to never change, even if the size of the game is changed afterwards.\n */\n getOriginalWidth(): float {\n return this._originalWidth;\n }\n\n /**\n * Get the original height of the game, as set on the startup of the game.\n *\n * This is guaranteed to never change, even if the size of the game is changed afterwards.\n */\n getOriginalHeight(): float {\n return this._originalHeight;\n }\n\n /**\n * Get the game resolution (the size at which the game is played and rendered) width.\n * @returns The game resolution width, in pixels.\n */\n getGameResolutionWidth(): float {\n return this._gameResolutionWidth;\n }\n\n /**\n * Get the game resolution (the size at which the game is played and rendered) height.\n * @returns The game resolution height, in pixels.\n */\n getGameResolutionHeight(): float {\n return this._gameResolutionHeight;\n }\n\n /**\n * Change the game resolution.\n *\n * @param width The new width\n * @param height The new height\n */\n setGameResolutionSize(width: float, height: float): void {\n this._throwIfDisposed();\n\n this._gameResolutionWidth = width;\n this._gameResolutionHeight = height;\n if (this._adaptGameResolutionAtRuntime) {\n if (\n gdjs.RuntimeGameRenderer &&\n gdjs.RuntimeGameRenderer.getWindowInnerWidth &&\n gdjs.RuntimeGameRenderer.getWindowInnerHeight\n ) {\n const windowInnerWidth = gdjs.RuntimeGameRenderer.getWindowInnerWidth();\n const windowInnerHeight = gdjs.RuntimeGameRenderer.getWindowInnerHeight();\n\n // Enlarge either the width or the eight to fill the inner window space.\n if (this._resizeMode === 'adaptWidth') {\n this._gameResolutionWidth =\n (this._gameResolutionHeight * windowInnerWidth) /\n windowInnerHeight;\n } else {\n if (this._resizeMode === 'adaptHeight') {\n this._gameResolutionHeight =\n (this._gameResolutionWidth * windowInnerHeight) /\n windowInnerWidth;\n }\n }\n }\n } else {\n }\n\n // Don't alter the game resolution. The renderer\n // will maybe adapt the size of the canvas or whatever is used to render the\n // game in the window, but this does not change the \"game resolution\".\n\n // Notify the renderer that game resolution changed (so that the renderer size\n // can be updated, and maybe other things like the canvas size), and let the\n // scenes know too.\n this._renderer.updateRendererSize();\n this._notifyScenesForGameResolutionResize = true;\n }\n\n /**\n * Set if the width or the height of the game resolution\n * should be changed to fit the game window - or if the game\n * resolution should not be updated automatically.\n *\n * @param resizeMode Either \"\" (don't change game resolution), \"adaptWidth\" or \"adaptHeight\".\n */\n setGameResolutionResizeMode(resizeMode: string): void {\n this._resizeMode = resizeMode;\n this._forceGameResolutionUpdate();\n }\n\n /**\n * Returns if the width or the height of the game resolution\n * should be changed to fit the game window - or if the game\n * resolution should not be updated automatically (empty string).\n *\n * @returns Either \"\" (don't change game resolution), \"adaptWidth\" or \"adaptHeight\".\n */\n getGameResolutionResizeMode(): string {\n return this._resizeMode;\n }\n\n /**\n * Set if the game resolution should be automatically adapted\n * when the game window or screen size change. This will only\n * be the case if the game resolution resize mode is\n * configured to adapt the width or the height of the game.\n * @param enable true to change the game resolution according to the window/screen size.\n */\n setAdaptGameResolutionAtRuntime(enable: boolean): void {\n this._adaptGameResolutionAtRuntime = enable;\n this._forceGameResolutionUpdate();\n }\n\n /**\n * Returns if the game resolution should be automatically adapted\n * when the game window or screen size change. This will only\n * be the case if the game resolution resize mode is\n * configured to adapt the width or the height of the game.\n * @returns true if the game resolution is automatically changed according to the window/screen size.\n */\n getAdaptGameResolutionAtRuntime(): boolean {\n return this._adaptGameResolutionAtRuntime;\n }\n\n /**\n * Return the minimal fps that must be guaranteed by the game\n * (otherwise, game is slowed down).\n */\n getMinimalFramerate(): integer {\n return this._minFPS;\n }\n\n /**\n * Return the scale mode of the game (\"linear\" or \"nearest\").\n */\n getScaleMode(): 'linear' | 'nearest' {\n return this._scaleMode;\n }\n\n /**\n * Return if the game is rounding pixels when rendering.\n */\n getPixelsRounding(): boolean {\n return this._pixelsRounding;\n }\n\n /**\n * Return the antialiasing mode used by the game (\"none\" or \"MSAA\").\n */\n getAntialiasingMode(): 'none' | 'MSAA' {\n return this._antialiasingMode;\n }\n\n /**\n * Return true if antialising is enabled on mobiles.\n */\n isAntialisingEnabledOnMobile(): boolean {\n return this._isAntialisingEnabledOnMobile;\n }\n\n /**\n * Set or unset the game as paused.\n * When paused, the game won't step and will be freezed. Useful for debugging.\n * @param enable true to pause the game, false to unpause\n */\n pause(enable: boolean) {\n if (this._paused === enable) return;\n\n this._paused = enable;\n if (this._debuggerClient) {\n if (this._paused) this._debuggerClient.sendGamePaused();\n else this._debuggerClient.sendGameResumed();\n }\n }\n\n /**\n * @returns true during the first frame the game is back from being hidden.\n * This has nothing to do with `_paused`.\n */\n hasJustResumed() {\n return this._hasJustResumed;\n }\n\n /**\n * Preload a scene assets as soon as possible in background.\n */\n prioritizeLoadingOfScene(sceneName: string) {\n // Don't await the scene assets to be loaded.\n this._resourcesLoader.loadSceneResources(sceneName);\n }\n\n /**\n * @return The progress of assets loading in background for a scene\n * (between 0 and 1).\n */\n getSceneLoadingProgress(sceneName: string): number {\n return this._resourcesLoader.getSceneLoadingProgress(sceneName);\n }\n\n /**\n * @returns true when all the resources of the given scene are loaded\n * (but maybe not parsed).\n */\n areSceneAssetsLoaded(sceneName: string): boolean {\n return this._resourcesLoader.areSceneAssetsLoaded(sceneName);\n }\n\n /**\n * @returns true when all the resources of the given scene are loaded and\n * parsed.\n */\n areSceneAssetsReady(sceneName: string): boolean {\n return this._resourcesLoader.areSceneAssetsReady(sceneName);\n }\n\n /**\n * Load all assets needed to display the 1st scene, displaying progress in\n * renderer.\n */\n loadAllAssets(\n callback: () => void,\n progressCallback?: (progress: float) => void\n ) {\n this._throwIfDisposed();\n this.loadFirstAssetsAndStartBackgroundLoading(\n this._getFirstSceneName(),\n progressCallback\n ).then(callback);\n }\n\n /**\n * Load all assets needed to display the 1st scene, displaying progress in\n * renderer.\n *\n * When a game is hot-reload, this method can be called with the current\n * scene.\n */\n async loadFirstAssetsAndStartBackgroundLoading(\n firstSceneName: string,\n progressCallback?: (progress: float) => void\n ): Promise<void> {\n try {\n // Download the loading screen background image first to be able to\n // display the loading screen as soon as possible.\n const backgroundImageResourceName = this._data.properties.loadingScreen\n .backgroundImageResourceName;\n if (backgroundImageResourceName) {\n await this._resourcesLoader\n .getImageManager()\n .loadResource(backgroundImageResourceName);\n }\n await Promise.all([\n this._loadAssetsWithLoadingScreen(\n /* isFirstScene = */ true,\n async (onProgress) => {\n // TODO Is a setting needed?\n if (false) {\n await this._resourcesLoader.loadAllResources(onProgress);\n } else {\n await this._resourcesLoader.loadGlobalAndFirstSceneResources(\n firstSceneName,\n onProgress\n );\n // Don't await as it must not block the first scene from starting.\n this._resourcesLoader.loadAllSceneInBackground();\n }\n },\n progressCallback\n ),\n // TODO This is probably not necessary in case of hot reload.\n gdjs.getAllAsynchronouslyLoadingLibraryPromise(),\n ]);\n } catch (e) {\n if (this._debuggerClient) this._debuggerClient.onUncaughtException(e);\n\n throw e;\n }\n }\n\n /**\n * Load all assets for a given scene, displaying progress in renderer.\n */\n async loadSceneAssets(\n sceneName: string,\n progressCallback?: (progress: float) => void\n ): Promise<void> {\n await this._loadAssetsWithLoadingScreen(\n /* isFirstLayout = */ false,\n async (onProgress) => {\n await this._resourcesLoader.loadAndProcessSceneResources(\n sceneName,\n onProgress\n );\n },\n progressCallback\n );\n }\n\n /**\n * Load assets, displaying progress in renderer.\n */\n private async _loadAssetsWithLoadingScreen(\n isFirstScene: boolean,\n loadAssets: (\n onProgress: (count: integer, total: integer) => Promise<void>\n ) => Promise<void>,\n progressCallback?: (progress: float) => void\n ): Promise<void> {\n this.pause(true);\n const loadingScreen = new gdjs.LoadingScreenRenderer(\n this.getRenderer(),\n this._resourcesLoader.getImageManager(),\n this._data.properties.loadingScreen,\n this._data.properties.watermark.showWatermark,\n isFirstScene\n );\n\n const onProgress = async (count: integer, total: integer) => {\n const percent = Math.floor((100 * count) / total);\n loadingScreen.setPercent(percent);\n if (progressCallback) {\n progressCallback(percent);\n }\n const hasRendered = loadingScreen.renderIfNeeded();\n if (hasRendered) {\n // Give a chance to draw calls from the renderer to be handled.\n await sleep(1);\n }\n };\n await loadAssets(onProgress);\n\n await loadingScreen.unload();\n this.pause(false);\n }\n\n private _getFirstSceneName(): string {\n const firstSceneName = this._data.firstLayout;\n return this.hasScene(firstSceneName)\n ? firstSceneName\n : // There is always at least a scene\n this.getSceneAndExtensionsData()!.sceneData.name;\n }\n\n /**\n * Start the game loop, to be called once assets are loaded.\n */\n startGameLoop() {\n this._throwIfDisposed();\n try {\n if (!this.hasScene()) {\n logger.error('The game has no scene.');\n return;\n }\n this._forceGameResolutionUpdate();\n\n // Load the first scene\n this._sceneStack.push(\n this._getFirstSceneName(),\n this._injectExternalLayout\n );\n this._watermark.displayAtStartup();\n\n //Uncomment to profile the first x frames of the game.\n // var x = 500;\n // var startTime = Date.now();\n // console.profile(\"Stepping for \" + x + \" frames\")\n // for(var i = 0; i < x; ++i) {\n // this._sceneStack.step(16);\n // }\n // console.profileEnd();\n // var time = Date.now() - startTime;\n // logger.log(\"Took\", time, \"ms\");\n // return;\n\n this._setupGameVisibilityEvents();\n\n // The standard game loop\n let accumulatedElapsedTime = 0;\n this._hasJustResumed = false;\n this._renderer.startGameLoop((lastCallElapsedTime) => {\n try {\n if (this._paused) {\n return true;\n }\n\n // Skip the frame if we rendering frames too fast\n accumulatedElapsedTime += lastCallElapsedTime;\n if (\n this._maxFPS > 0 &&\n 1000.0 / accumulatedElapsedTime > this._maxFPS + 7\n ) {\n // Only skip frame if the framerate is 7 frames above the maximum framerate.\n // Most browser/engines will try to run at slightly more than 60 frames per second.\n // If game is set to have a maximum FPS to 60, then one out of two frames will be dropped.\n // Hence, we use a 7 frames margin to ensure that we're not skipping frames too much.\n return true;\n }\n const elapsedTime = accumulatedElapsedTime;\n accumulatedElapsedTime = 0;\n\n // Manage resize events.\n if (this._notifyScenesForGameResolutionResize) {\n this._sceneStack.onGameResolutionResized();\n this._notifyScenesForGameResolutionResize = false;\n }\n\n // Render and step the scene.\n if (this._sceneStack.step(elapsedTime)) {\n this.getInputManager().onFrameEnded();\n this._hasJustResumed = false;\n return true;\n }\n return false;\n } catch (e) {\n if (this._debuggerClient)\n this._debuggerClient.onUncaughtException(e);\n\n throw e;\n }\n });\n setTimeout(() => {\n this._setupSessionMetrics();\n }, 4000);\n if (this._captureManager) {\n this._captureManager.setupCaptureOptions(this._isPreview);\n }\n } catch (e) {\n if (this._debuggerClient) this._debuggerClient.onUncaughtException(e);\n\n throw e;\n }\n }\n\n /**\n * Stop game loop, unload all scenes, dispose renderer and resources.\n * After calling this method, the RuntimeGame should not be used anymore.\n */\n dispose(): void {\n this._renderer.stopGameLoop();\n this._sceneStack.dispose();\n this._renderer.dispose();\n this._resourcesLoader.dispose();\n\n this._wasDisposed = true;\n }\n\n /**\n * Set if the session should be registered.\n */\n enableMetrics(enable: boolean): void {\n this._disableMetrics = !enable;\n if (enable) {\n this._setupSessionMetrics();\n }\n }\n\n /**\n * Helper function to get information about the platform running the game.\n */\n getPlatformInfo = () => {\n return {\n // @ts-ignore\n isCordova: !!window.cordova,\n devicePlatform:\n // @ts-ignore\n typeof device !== 'undefined' ? device.platform || '' : '',\n navigatorPlatform:\n typeof navigator !== 'undefined' ? navigator.platform : '',\n hasTouch:\n typeof navigator !== 'undefined'\n ? !!navigator.maxTouchPoints && navigator.maxTouchPoints > 2\n : false,\n supportedCompressionMethods: getSupportedCompressionMethods(),\n };\n };\n\n _setupGameVisibilityEvents() {\n if (typeof navigator !== 'undefined' && typeof document !== 'undefined') {\n document.addEventListener('visibilitychange', () => {\n if (document.visibilityState === 'visible') {\n this._hasJustResumed = true;\n }\n });\n window.addEventListener(\n 'resume',\n () => {\n this._hasJustResumed = true;\n },\n false\n );\n }\n }\n\n /**\n * Register a new session for the game, and set up listeners to follow the session\n * time.\n */\n _setupSessionMetrics() {\n if (this._sessionMetricsInitialized) {\n return;\n }\n if (this._disableMetrics) {\n return;\n }\n if (this.isPreview()) {\n return;\n }\n if (typeof fetch === 'undefined') {\n return;\n }\n if (!this._data.properties.projectUuid) {\n return;\n }\n const baseUrl = 'https://api.gdevelop-app.com/analytics';\n this._playerId = this._makePlayerUuid();\n /**\n * The duration that is already sent to the service\n * (in milliseconds).\n **/\n let sentDuration = 0;\n /**\n * The duration that is not yet sent to the service to avoid flooding\n * (in milliseconds).\n **/\n let notYetSentDuration = 0;\n /**\n * The last time when duration has been counted\n * either in sendedDuration or notYetSentDuration.\n **/\n let lastSessionResumeTime = Date.now();\n const platform = this.getPlatformInfo();\n fetch(baseUrl + '/session', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n // It's important to ensure that the data sent here does not contain\n // any personal information from the player or that would allow to\n // precisely identify someone.\n body: JSON.stringify({\n gameId: this._data.properties.projectUuid,\n playerId: this._playerId,\n game: {\n name: this._data.properties.name || '',\n packageName: this._data.properties.packageName || '',\n version: this._data.properties.version || '',\n location: window.location.href,\n },\n platform: {\n isCordova: platform.isCordova,\n devicePlatform: platform.devicePlatform,\n navigatorPlatform: platform.navigatorPlatform,\n hasTouch: platform.hasTouch,\n },\n }),\n })\n .then((response) => {\n // Ensure the session is correctly created to avoid sending hits that will fail.\n if (!response.ok) {\n console.error('Error while creating the session', response);\n throw new Error('Error while creating the session');\n }\n return response;\n })\n .then((response) => response.text())\n .then((returnedSessionId) => {\n this._sessionId = returnedSessionId;\n })\n .catch(() => {});\n\n /* Ignore any error */\n const sendSessionHit = () => {\n if (!this._sessionId) {\n return;\n }\n\n const now = Date.now();\n notYetSentDuration += now - lastSessionResumeTime;\n lastSessionResumeTime = now;\n\n // Group repeated calls to sendSessionHit - which could\n // happen because of multiple event listeners being fired.\n if (notYetSentDuration < 5 * 1000) {\n return;\n }\n // The backend use seconds for duration.\n // The milliseconds will stay in notYetSentDuration.\n const toBeSentDuration = Math.floor(notYetSentDuration / 1000) * 1000;\n sentDuration += toBeSentDuration;\n notYetSentDuration -= toBeSentDuration;\n\n navigator.sendBeacon(\n baseUrl + '/session-hit',\n JSON.stringify({\n gameId: this._data.properties.projectUuid,\n playerId: this._playerId,\n sessionId: this._sessionId,\n duration: Math.floor(sentDuration / 1000),\n })\n );\n };\n if (typeof navigator !== 'undefined' && typeof document !== 'undefined') {\n document.addEventListener('visibilitychange', () => {\n if (document.visibilityState === 'visible') {\n // Skip the duration the game was hidden.\n lastSessionResumeTime = Date.now();\n } else {\n sendSessionHit();\n }\n });\n window.addEventListener('pagehide', sendSessionHit, false);\n // Cordova events\n window.addEventListener('pause', sendSessionHit, false);\n window.addEventListener(\n 'resume',\n () => {\n // Skip the duration the game was hidden.\n lastSessionResumeTime = Date.now();\n },\n false\n );\n\n // Detect Safari to work around Safari-specific bugs:\n // - https://bugs.webkit.org/show_bug.cgi?id=151610\n // - https://bugs.webkit.org/show_bug.cgi?id=151234\n // @ts-ignore\n const isSafari = typeof safari === 'object' && safari.pushNotification;\n const isElectron = /electron/i.test(navigator.userAgent);\n if (isSafari || isElectron) {\n window.addEventListener('beforeunload', () => {\n sendSessionHit();\n });\n }\n }\n this._sessionMetricsInitialized = true;\n this._sessionId = this._sessionId;\n }\n\n /**\n * Generate an anonymous unique identifier to differentiate\n * the player from others in the game metrics.\n */\n _makePlayerUuid(): string {\n try {\n const key = 'GDJS-internal-player-uuid';\n const existingPlayerUuid = localStorage.getItem(key);\n if (existingPlayerUuid) {\n return existingPlayerUuid;\n }\n const newPlayerUuid = gdjs.makeUuid();\n localStorage.setItem(key, newPlayerUuid);\n return newPlayerUuid;\n } catch (err) {\n return gdjs.makeUuid();\n }\n }\n\n getSessionId(): string | null {\n return this._sessionId;\n }\n\n getPlayerId(): string | null {\n return this._playerId;\n }\n\n /**\n * Called by the game renderer when the window containing the game\n * has changed size (this can result from a resize of the window,\n * but also other factors like a device orientation change on mobile).\n */\n onWindowInnerSizeChanged() {\n this._forceGameResolutionUpdate();\n }\n\n /**\n * Enlarge/reduce the width (or the height) of the game to fill the inner window.\n */\n _forceGameResolutionUpdate() {\n this.setGameResolutionSize(\n this._gameResolutionWidth,\n this._gameResolutionHeight\n );\n }\n\n /**\n * Start a profiler for the currently running scene.\n * @param onProfilerStopped Function to be called when the profiler is stopped. Will be passed the profiler as argument.\n */\n startCurrentSceneProfiler(\n onProfilerStopped: (oldProfiler: Profiler) => void\n ) {\n this._throwIfDisposed();\n const currentScene = this._sceneStack.getCurrentScene();\n if (!currentScene) {\n return false;\n }\n currentScene.startProfiler(onProfilerStopped);\n return true;\n }\n\n /**\n * Stop the profiler for the currently running scene.\n */\n stopCurrentSceneProfiler() {\n this._throwIfDisposed();\n const currentScene = this._sceneStack.getCurrentScene();\n if (!currentScene) {\n return;\n }\n currentScene.stopProfiler();\n }\n\n /**\n * Return true if a scene was loaded, false otherwise (i.e: game not yet started).\n */\n wasFirstSceneLoaded(): boolean {\n return this._sceneStack.wasFirstSceneLoaded();\n }\n\n /**\n * Return the stack of {@link gdjs.RuntimeScene} being played.\n */\n getSceneStack(): gdjs.SceneStack {\n return this._sceneStack;\n }\n\n /**\n * Check if the game is running as a preview, launched from an editor.\n * @returns true if the current game is a preview.\n */\n isPreview(): boolean {\n return this._isPreview;\n }\n\n /**\n * Check if the game should call GDevelop development APIs or not.\n *\n * Unless you are contributing to GDevelop, avoid using this.\n */\n isUsingGDevelopDevelopmentEnvironment(): boolean {\n return this._options.environment === 'dev';\n }\n\n /**\n * Gets an extension property from the project data.\n * @param extensionName The extension name.\n * @param propertyName The property name.\n * @return The property value.\n */\n getExtensionProperty(\n extensionName: string,\n propertyName: string\n ): string | null {\n for (let property of this._data.properties.extensionProperties) {\n if (\n property.extension === extensionName &&\n property.property === propertyName\n ) {\n return property.value;\n }\n }\n return null;\n }\n\n /**\n * Resolves the name of an embedded resource.\n * @param mainResourceName The name of the resource containing the embedded resource.\n * @param embeddedResourceName The name of the embedded resource.\n * @return The resource name.\n */\n resolveEmbeddedResource(\n mainResourceName: string,\n embeddedResourceName: string\n ): string {\n const mapping = this._embeddedResourcesMappings.get(mainResourceName);\n return mapping && mapping[embeddedResourceName]\n ? mapping[embeddedResourceName]\n : embeddedResourceName;\n }\n\n /**\n * Returns the array of resources that are embedded to passed one.\n * @param resourceName The name of resource to find embedded resources of.\n * @returns The array of related resources names.\n */\n getEmbeddedResourcesNames(resourceName: string): string[] {\n return this._embeddedResourcesMappings.has(resourceName)\n ? Object.keys(this._embeddedResourcesMappings.get(resourceName)!)\n : [];\n }\n\n getNetworkSyncData(\n syncOptions: GetNetworkSyncDataOptions\n ): GameNetworkSyncData | null {\n const syncData: GameNetworkSyncData = {\n var: this._variables.getNetworkSyncData(syncOptions),\n ss: this._sceneStack.getNetworkSyncData(syncOptions) || undefined,\n };\n\n const extensionsVariablesSyncData = {};\n this._variablesByExtensionName.forEach((variables, extensionName) => {\n const extensionVariablesSyncData = variables.getNetworkSyncData(\n syncOptions\n );\n // If there is no variables to sync, don't include the extension in the sync data.\n if (extensionVariablesSyncData.length) {\n extensionsVariablesSyncData[\n extensionName\n ] = extensionVariablesSyncData;\n }\n });\n syncData.extVar = extensionsVariablesSyncData;\n\n if (\n (!syncData.var || syncData.var.length === 0) &&\n !syncData.ss &&\n (!syncData.extVar || Object.keys(syncData.extVar).length === 0)\n ) {\n // Nothing to sync.\n return null;\n }\n\n return syncData;\n }\n\n updateFromNetworkSyncData(syncData: GameNetworkSyncData) {\n this._throwIfDisposed();\n if (syncData.var) {\n this._variables.updateFromNetworkSyncData(syncData.var);\n }\n if (syncData.ss) {\n this._sceneStack.updateFromNetworkSyncData(syncData.ss);\n }\n if (syncData.extVar) {\n for (const extensionName in syncData.extVar) {\n if (!syncData.extVar.hasOwnProperty(extensionName)) {\n continue;\n }\n const extensionVariablesData = syncData.extVar[extensionName];\n const extensionVariables = this.getVariablesForExtension(\n extensionName\n );\n if (extensionVariables) {\n extensionVariables.updateFromNetworkSyncData(\n extensionVariablesData\n );\n }\n }\n }\n }\n\n private _throwIfDisposed(): void {\n if (this._wasDisposed) {\n throw 'The RuntimeGame has been disposed and should not be used anymore.';\n }\n }\n }\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -1,4 +1,4 @@
1
- var gdjs;(function(n){let a;(function(s){class r{constructor(e,t,i){this._linkElement=null;this._containerElement=null;this._backgroundElement=null;this._svgElement=null;this._usernameTextElement=null;this._madeWithTextElement=null;this._resizeObserver=null;this._displayDuration=20;this._changeTextDelay=7;this._fadeInDelayAfterGameLoaded=1;this._fadeDuration=.3;this._fadeOutTimeout=null;this._hideTimeout=null;this._fadeOutFirstTextTimeout=null;this._fadeInSecondTextTimeout=null;this._textFontSize=14;this._logoWidth=56;this._logoHeight=45;this._backgroundHeight=150;this._margin=10;this._gameId=e._data.properties.projectUuid,this._gameRenderer=e.getRenderer(),this._authorUsername=t[0],this._placement=i.placement,this._showAtStartup=i.showWatermark,this._isDevEnvironment=e.isUsingGDevelopDevelopmentEnvironment(),this.addStyle()}displayAtStartup(){this._showAtStartup&&this.display()}display(){const e=this._gameRenderer.getDomElementContainer();e&&(this.addWatermarkToGameContainer(e),this._resizeObserver=new ResizeObserver(()=>{const t=e.getBoundingClientRect();this.onResizeGameContainer(t.height)}),this._resizeObserver.observe(e))}updateFontSize(e){this._textFontSize=Math.max(.025*e,12)}updateLogoSize(e){this._logoWidth=Math.max(.06*e,25),this._logoHeight=Math.round(45/56*this._logoWidth)}updateBackgroundHeight(e){this._backgroundHeight=Math.max(.13*e,45)}updateMargin(e){this._margin=Math.max(.025*e,8)}onResizeGameContainer(e){this.updateFontSize(e),this._madeWithTextElement&&(this._madeWithTextElement.style.fontSize=`${this._textFontSize}px`),this._usernameTextElement&&(this._usernameTextElement.style.fontSize=`${this._textFontSize}px`),this.updateLogoSize(e),this._svgElement&&(this._svgElement.setAttribute("height",this._logoHeight.toString()),this._svgElement.setAttribute("width",this._logoWidth.toString())),this.updateBackgroundHeight(e),this._backgroundElement&&(this._backgroundElement.style.height=`${this._backgroundHeight}px`),this.updateMargin(e),this._linkElement&&this.updateElementMargins(this._linkElement)}addWatermarkToGameContainer(e){const t=e.getBoundingClientRect();this.updateFontSize(t.height),this.updateLogoSize(t.height),this.updateBackgroundHeight(t.height),this._containerElement=this.createDivContainer(),this.createBackground();const i=document.createElement("div");this.generateSVGLogo(t.height),this.createMadeWithTextElement(),this.createUsernameTextElement(),this._linkElement=this.createLinkElement(),this._svgElement&&this._containerElement.appendChild(this._svgElement),this._madeWithTextElement&&i.appendChild(this._madeWithTextElement),this._usernameTextElement&&i.appendChild(this._usernameTextElement),this._containerElement.appendChild(i),this._backgroundElement&&e.appendChild(this._backgroundElement),this._linkElement.append(this._containerElement),e.appendChild(this._linkElement),this.setupAnimations()}createBackground(){this._backgroundElement=document.createElement("div"),this._backgroundElement.setAttribute("id","watermark-background"),this._backgroundElement.style.height=`${this._backgroundHeight}px`,this._backgroundElement.style.opacity="0",this._placement.startsWith("top")?(this._backgroundElement.style.top="0",this._backgroundElement.style.backgroundImage="linear-gradient(180deg, rgba(38, 38, 38, .6) 0%, rgba(38, 38, 38, 0) 100% )"):(this._backgroundElement.style.bottom="0",this._backgroundElement.style.backgroundImage="linear-gradient(0deg, rgba(38, 38, 38, .6) 0%, rgba(38, 38, 38, 0) 100% )")}setupAnimations(){requestAnimationFrame(()=>{setTimeout(()=>{!this._containerElement||!this._backgroundElement||!this._linkElement||(this._containerElement.style.opacity="1",this._backgroundElement.style.opacity="1",this._linkElement.style.pointerEvents="all",this._svgElement&&this._svgElement.classList.add("spinning"))},this._fadeInDelayAfterGameLoaded*1e3)}),this._fadeOutTimeout=setTimeout(()=>{!this._containerElement||!this._backgroundElement||(this._containerElement.style.opacity="0",this._backgroundElement.style.opacity="0",this._hideTimeout=setTimeout(()=>{!this._containerElement||!this._backgroundElement||!this._linkElement||(this._linkElement.style.pointerEvents="none",this._containerElement.style.display="none",this._backgroundElement.style.display="none",this._resizeObserver&&this._resizeObserver.disconnect())},this._fadeDuration*1e3))},(this._fadeInDelayAfterGameLoaded+this._displayDuration)*1e3),this._fadeOutFirstTextTimeout=setTimeout(()=>{const{_madeWithTextElement:e,_usernameTextElement:t}=this;!e||t&&(e.style.opacity="0",this._fadeInSecondTextTimeout=setTimeout(()=>{t.style.lineHeight="normal",t.style.opacity="1",e.style.lineHeight="0"},this._fadeDuration*1e3))},(this._fadeInDelayAfterGameLoaded+this._changeTextDelay)*1e3)}createMadeWithTextElement(){this._madeWithTextElement=document.createElement("span"),this._madeWithTextElement.innerText="Made with GDevelop",this._madeWithTextElement.style.fontSize=`${this._textFontSize}px`}createUsernameTextElement(){!this._authorUsername||(this._usernameTextElement=document.createElement("span"),this._usernameTextElement.innerText=`@${this._authorUsername}`,this._usernameTextElement.style.fontSize=`${this._textFontSize}px`,this._usernameTextElement.style.opacity="0",this._usernameTextElement.style.lineHeight="0")}updateElementMargins(e){switch(this._placement){case"top-left":e.style.top=`${this._margin}px`,e.style.left=`${this._margin}px`;break;case"top-right":e.style.top=`${this._margin}px`,e.style.right=`${this._margin}px`;break;case"bottom-left":e.style.bottom=`${this._margin}px`,e.style.left=`${this._margin}px`;break;case"bottom-right":e.style.bottom=`${this._margin}px`,e.style.right=`${this._margin}px`;break;case"top":e.style.top=`${this._margin}px`,e.style.left="50%",e.style.transform="translate(-50%, 0)";break;case"bottom":default:e.style.bottom=`${this._margin}px`,e.style.left="50%",e.style.transform="translate(-50%, 0)";break}}createLinkElement(){const e=document.createElement("a");e.id="watermark-link";let t=this._authorUsername?new URL(`https://gd.games/${this._authorUsername}`):new URL("https://gd.games");return this._isDevEnvironment?t.searchParams.set("dev","true"):(t.searchParams.set("utm_source","gdevelop-game"),t.searchParams.set("utm_medium","game-watermark"),this._gameId&&t.searchParams.set("utm_campaign",this._gameId)),e.href=t.href,e.target="_blank",this.updateElementMargins(e),e}createDivContainer(){const e=document.createElement("div");return e.setAttribute("id","watermark"),e.style.opacity="0",e}generateSVGLogo(e){this._svgElement=document.createElementNS("http://www.w3.org/2000/svg","svg"),this.updateLogoSize(e),this._svgElement.setAttribute("height",this._logoHeight.toString()),this._svgElement.setAttribute("width",this._logoWidth.toString()),this._svgElement.setAttribute("viewBox","-2 -2 59 48"),this._svgElement.setAttribute("fill","none");const t=document.createElementNS("http://www.w3.org/2000/svg","path"),i=document.createElementNS("http://www.w3.org/2000/svg","path");t.setAttribute("d","M29.3447 33C25.1061 33 21.0255 31.8475 17.4207 29.3381C14.9081 27.5897 12 23.6418 12 16.9488C12 4.53178 18.3074 0 30.9827 0H53.8027L56 7.07232H32.7217C24.3558 7.07232 19.3813 7.72835 19.3813 16.9488C19.3813 19.9944 20.2354 22.1618 21.9933 23.574C24.9642 25.9612 30.7388 26.0628 34.2673 25.7208C34.2673 25.7208 35.715 21.0394 35.9534 20.2794C36.2327 19.3888 36.1104 19.1763 35.2392 19.1763C33.9808 19.1763 31.7185 19.1763 29.3175 19.1763C27.6349 19.1763 25.9818 18.3247 25.9818 16.2793C25.9818 14.3039 27.5198 13.1573 29.6281 13.1573C33.2786 13.1573 40.7969 13.1573 42.2041 13.1573C44.0489 13.1573 45.9315 13.4233 44.971 16.3601L39.8842 31.8734C39.8845 31.8738 35.7287 33 29.3447 33Z"),i.setAttribute("d","M43.3039 35.3278C40.7894 37.1212 37.0648 38.1124 30.7449 38.1124C19.852 38.1124 11.8797 34.1251 8.62927 26.3952C7.0925 22.7415 7.24041 18.6005 7.24041 13H0.00129513C0.00129513 18.9056 -0.0984386 23.5361 1.45249 27.8011C5.51933 38.989 15.992 45 30.0606 45C43.6783 45 49.3213 41.0443 53 35.3278H43.3039Z"),this._svgElement.appendChild(t),this._svgElement.appendChild(i)}addStyle(){const e=document.createElement("style");e.innerHTML=`
1
+ var gdjs;(function(n){let a;(function(r){class s{constructor(e,t,i){this._linkElement=null;this._containerElement=null;this._backgroundElement=null;this._svgElement=null;this._usernameTextElement=null;this._madeWithTextElement=null;this._resizeObserver=null;this._displayDuration=20;this._changeTextDelay=7;this._fadeInDelayAfterGameLoaded=1;this._fadeDuration=.3;this._fadeOutTimeout=null;this._hideTimeout=null;this._fadeOutFirstTextTimeout=null;this._fadeInSecondTextTimeout=null;this._textFontSize=14;this._logoWidth=56;this._logoHeight=45;this._backgroundHeight=150;this._margin=10;this._gameId=e._data.properties.projectUuid,this._gameRenderer=e.getRenderer(),this._authorUsername=t[0],this._placement=i.placement,this._showAtStartup=i.showWatermark,this._isDevEnvironment=e.isUsingGDevelopDevelopmentEnvironment(),i.showWatermark&&this.addStyle()}displayAtStartup(){this._showAtStartup&&this.display()}display(){const e=this._gameRenderer.getDomElementContainer();e&&(this.addWatermarkToGameContainer(e),this._resizeObserver=new ResizeObserver(()=>{const t=e.getBoundingClientRect();this.onResizeGameContainer(t.height)}),this._resizeObserver.observe(e))}updateFontSize(e){this._textFontSize=Math.max(.025*e,12)}updateLogoSize(e){this._logoWidth=Math.max(.06*e,25),this._logoHeight=Math.round(45/56*this._logoWidth)}updateBackgroundHeight(e){this._backgroundHeight=Math.max(.13*e,45)}updateMargin(e){this._margin=Math.max(.025*e,8)}onResizeGameContainer(e){this.updateFontSize(e),this._madeWithTextElement&&(this._madeWithTextElement.style.fontSize=`${this._textFontSize}px`),this._usernameTextElement&&(this._usernameTextElement.style.fontSize=`${this._textFontSize}px`),this.updateLogoSize(e),this._svgElement&&(this._svgElement.setAttribute("height",this._logoHeight.toString()),this._svgElement.setAttribute("width",this._logoWidth.toString())),this.updateBackgroundHeight(e),this._backgroundElement&&(this._backgroundElement.style.height=`${this._backgroundHeight}px`),this.updateMargin(e),this._linkElement&&this.updateElementMargins(this._linkElement)}addWatermarkToGameContainer(e){const t=e.getBoundingClientRect();this.updateFontSize(t.height),this.updateLogoSize(t.height),this.updateBackgroundHeight(t.height),this._containerElement=this.createDivContainer(),this.createBackground();const i=document.createElement("div");this.generateSVGLogo(t.height),this.createMadeWithTextElement(),this.createUsernameTextElement(),this._linkElement=this.createLinkElement(),this._svgElement&&this._containerElement.appendChild(this._svgElement),this._madeWithTextElement&&i.appendChild(this._madeWithTextElement),this._usernameTextElement&&i.appendChild(this._usernameTextElement),this._containerElement.appendChild(i),this._backgroundElement&&e.appendChild(this._backgroundElement),this._linkElement.append(this._containerElement),e.appendChild(this._linkElement),this.setupAnimations()}createBackground(){this._backgroundElement=document.createElement("div"),this._backgroundElement.setAttribute("id","watermark-background"),this._backgroundElement.style.height=`${this._backgroundHeight}px`,this._backgroundElement.style.opacity="0",this._placement.startsWith("top")?(this._backgroundElement.style.top="0",this._backgroundElement.style.backgroundImage="linear-gradient(180deg, rgba(38, 38, 38, .6) 0%, rgba(38, 38, 38, 0) 100% )"):(this._backgroundElement.style.bottom="0",this._backgroundElement.style.backgroundImage="linear-gradient(0deg, rgba(38, 38, 38, .6) 0%, rgba(38, 38, 38, 0) 100% )")}setupAnimations(){requestAnimationFrame(()=>{setTimeout(()=>{!this._containerElement||!this._backgroundElement||!this._linkElement||(this._containerElement.style.opacity="1",this._backgroundElement.style.opacity="1",this._linkElement.style.pointerEvents="all",this._svgElement&&this._svgElement.classList.add("spinning"))},this._fadeInDelayAfterGameLoaded*1e3)}),this._fadeOutTimeout=setTimeout(()=>{!this._containerElement||!this._backgroundElement||(this._containerElement.style.opacity="0",this._backgroundElement.style.opacity="0",this._hideTimeout=setTimeout(()=>{!this._containerElement||!this._backgroundElement||!this._linkElement||(this._linkElement.style.pointerEvents="none",this._containerElement.style.display="none",this._backgroundElement.style.display="none",this._resizeObserver&&this._resizeObserver.disconnect())},this._fadeDuration*1e3))},(this._fadeInDelayAfterGameLoaded+this._displayDuration)*1e3),this._fadeOutFirstTextTimeout=setTimeout(()=>{const{_madeWithTextElement:e,_usernameTextElement:t}=this;!e||t&&(e.style.opacity="0",this._fadeInSecondTextTimeout=setTimeout(()=>{t.style.lineHeight="normal",t.style.opacity="1",e.style.lineHeight="0"},this._fadeDuration*1e3))},(this._fadeInDelayAfterGameLoaded+this._changeTextDelay)*1e3)}createMadeWithTextElement(){this._madeWithTextElement=document.createElement("span"),this._madeWithTextElement.innerText="Made with GDevelop",this._madeWithTextElement.style.fontSize=`${this._textFontSize}px`}createUsernameTextElement(){!this._authorUsername||(this._usernameTextElement=document.createElement("span"),this._usernameTextElement.innerText=`@${this._authorUsername}`,this._usernameTextElement.style.fontSize=`${this._textFontSize}px`,this._usernameTextElement.style.opacity="0",this._usernameTextElement.style.lineHeight="0")}updateElementMargins(e){switch(this._placement){case"top-left":e.style.top=`${this._margin}px`,e.style.left=`${this._margin}px`;break;case"top-right":e.style.top=`${this._margin}px`,e.style.right=`${this._margin}px`;break;case"bottom-left":e.style.bottom=`${this._margin}px`,e.style.left=`${this._margin}px`;break;case"bottom-right":e.style.bottom=`${this._margin}px`,e.style.right=`${this._margin}px`;break;case"top":e.style.top=`${this._margin}px`,e.style.left="50%",e.style.transform="translate(-50%, 0)";break;case"bottom":default:e.style.bottom=`${this._margin}px`,e.style.left="50%",e.style.transform="translate(-50%, 0)";break}}createLinkElement(){const e=document.createElement("a");e.id="watermark-link";let t=this._authorUsername?new URL(`https://gd.games/${this._authorUsername}`):new URL("https://gd.games");return this._isDevEnvironment?t.searchParams.set("dev","true"):(t.searchParams.set("utm_source","gdevelop-game"),t.searchParams.set("utm_medium","game-watermark"),this._gameId&&t.searchParams.set("utm_campaign",this._gameId)),e.href=t.href,e.target="_blank",this.updateElementMargins(e),e}createDivContainer(){const e=document.createElement("div");return e.setAttribute("id","watermark"),e.style.opacity="0",e}generateSVGLogo(e){this._svgElement=document.createElementNS("http://www.w3.org/2000/svg","svg"),this.updateLogoSize(e),this._svgElement.setAttribute("height",this._logoHeight.toString()),this._svgElement.setAttribute("width",this._logoWidth.toString()),this._svgElement.setAttribute("viewBox","-2 -2 59 48"),this._svgElement.setAttribute("fill","none");const t=document.createElementNS("http://www.w3.org/2000/svg","path"),i=document.createElementNS("http://www.w3.org/2000/svg","path");t.setAttribute("d","M29.3447 33C25.1061 33 21.0255 31.8475 17.4207 29.3381C14.9081 27.5897 12 23.6418 12 16.9488C12 4.53178 18.3074 0 30.9827 0H53.8027L56 7.07232H32.7217C24.3558 7.07232 19.3813 7.72835 19.3813 16.9488C19.3813 19.9944 20.2354 22.1618 21.9933 23.574C24.9642 25.9612 30.7388 26.0628 34.2673 25.7208C34.2673 25.7208 35.715 21.0394 35.9534 20.2794C36.2327 19.3888 36.1104 19.1763 35.2392 19.1763C33.9808 19.1763 31.7185 19.1763 29.3175 19.1763C27.6349 19.1763 25.9818 18.3247 25.9818 16.2793C25.9818 14.3039 27.5198 13.1573 29.6281 13.1573C33.2786 13.1573 40.7969 13.1573 42.2041 13.1573C44.0489 13.1573 45.9315 13.4233 44.971 16.3601L39.8842 31.8734C39.8845 31.8738 35.7287 33 29.3447 33Z"),i.setAttribute("d","M43.3039 35.3278C40.7894 37.1212 37.0648 38.1124 30.7449 38.1124C19.852 38.1124 11.8797 34.1251 8.62927 26.3952C7.0925 22.7415 7.24041 18.6005 7.24041 13H0.00129513C0.00129513 18.9056 -0.0984386 23.5361 1.45249 27.8011C5.51933 38.989 15.992 45 30.0606 45C43.6783 45 49.3213 41.0443 53 35.3278H43.3039Z"),this._svgElement.appendChild(t),this._svgElement.appendChild(i)}addStyle(){const e=document.createElement("style");e.innerHTML=`
2
2
  @keyframes spin {
3
3
  0% {
4
4
  transform: rotate(0deg);
@@ -96,5 +96,5 @@ var gdjs;(function(n){let a;(function(s){class r{constructor(e,t,i){this._linkEl
96
96
  -webkit-text-decoration-color: white;
97
97
  }
98
98
  }
99
- `,document.head.appendChild(e)}}s.RuntimeWatermark=r})(a=n.watermark||(n.watermark={}))})(gdjs||(gdjs={}));
99
+ `,document.head.appendChild(e)}}r.RuntimeWatermark=s})(a=n.watermark||(n.watermark={}))})(gdjs||(gdjs={}));
100
100
  //# sourceMappingURL=runtimewatermark.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../GDevelop/GDJS/Runtime/runtimewatermark.ts"],
4
- "sourcesContent": ["namespace gdjs {\n export namespace watermark {\n export class RuntimeWatermark {\n _gameRenderer: RuntimeGameRenderer;\n _isDevEnvironment: boolean;\n\n // Configuration\n _placement:\n | 'top-left'\n | 'top-right'\n | 'bottom-left'\n | 'bottom-right'\n | 'bottom'\n | 'top';\n _showAtStartup: boolean;\n _authorUsername: string | undefined;\n _gameId: string | undefined;\n\n // Dom elements\n _linkElement: HTMLAnchorElement | null = null;\n _containerElement: HTMLDivElement | null = null;\n _backgroundElement: HTMLDivElement | null = null;\n _svgElement: SVGElement | null = null;\n _usernameTextElement: HTMLSpanElement | null = null;\n _madeWithTextElement: HTMLSpanElement | null = null;\n\n _resizeObserver: ResizeObserver | null = null;\n\n // Durations in seconds\n _displayDuration: number = 20;\n _changeTextDelay: number = 7;\n _fadeInDelayAfterGameLoaded: number = 1;\n _fadeDuration: number = 0.3;\n\n // Timeout registration\n _fadeOutTimeout: NodeJS.Timeout | null = null;\n _hideTimeout: NodeJS.Timeout | null = null;\n _fadeOutFirstTextTimeout: NodeJS.Timeout | null = null;\n _fadeInSecondTextTimeout: NodeJS.Timeout | null = null;\n\n // Sizes\n _textFontSize: number = 14;\n _logoWidth: number = 56;\n _logoHeight: number = 45;\n _backgroundHeight: number = 150;\n _margin: number = 10;\n\n constructor(\n game: RuntimeGame,\n authorUsernames: Array<string>,\n watermarkData: WatermarkData\n ) {\n this._gameId = game._data.properties.projectUuid;\n this._gameRenderer = game.getRenderer();\n this._authorUsername = authorUsernames[0];\n this._placement = watermarkData.placement;\n this._showAtStartup = watermarkData.showWatermark;\n this._isDevEnvironment = game.isUsingGDevelopDevelopmentEnvironment();\n this.addStyle();\n }\n\n displayAtStartup() {\n if (this._showAtStartup) {\n this.display();\n }\n }\n\n display() {\n const gameContainer = this._gameRenderer.getDomElementContainer();\n if (gameContainer) {\n this.addWatermarkToGameContainer(gameContainer);\n this._resizeObserver = new ResizeObserver(() => {\n const gameContainerRectangle = gameContainer.getBoundingClientRect();\n this.onResizeGameContainer(gameContainerRectangle.height);\n });\n this._resizeObserver.observe(gameContainer);\n }\n }\n\n private updateFontSize(height: number) {\n this._textFontSize = Math.max(0.025 * height, 12);\n }\n private updateLogoSize(height: number) {\n this._logoWidth = Math.max(0.06 * height, 25);\n this._logoHeight = Math.round((45 / 56) * this._logoWidth);\n }\n private updateBackgroundHeight(height: number) {\n this._backgroundHeight = Math.max(0.13 * height, 45);\n }\n private updateMargin(height: number) {\n this._margin = Math.max(0.025 * height, 8);\n }\n\n private onResizeGameContainer(height: number) {\n this.updateFontSize(height);\n if (this._madeWithTextElement) {\n this._madeWithTextElement.style.fontSize = `${this._textFontSize}px`;\n }\n if (this._usernameTextElement) {\n this._usernameTextElement.style.fontSize = `${this._textFontSize}px`;\n }\n this.updateLogoSize(height);\n if (this._svgElement) {\n this._svgElement.setAttribute('height', this._logoHeight.toString());\n this._svgElement.setAttribute('width', this._logoWidth.toString());\n }\n this.updateBackgroundHeight(height);\n if (this._backgroundElement) {\n this._backgroundElement.style.height = `${this._backgroundHeight}px`;\n }\n this.updateMargin(height);\n if (this._linkElement) {\n this.updateElementMargins(this._linkElement);\n }\n }\n\n private addWatermarkToGameContainer(container: HTMLElement) {\n const gameContainerRectangle = container.getBoundingClientRect();\n this.updateFontSize(gameContainerRectangle.height);\n this.updateLogoSize(gameContainerRectangle.height);\n this.updateBackgroundHeight(gameContainerRectangle.height);\n\n this._containerElement = this.createDivContainer();\n this.createBackground();\n const textContainer = document.createElement('div');\n\n this.generateSVGLogo(gameContainerRectangle.height);\n this.createMadeWithTextElement();\n this.createUsernameTextElement();\n\n this._linkElement = this.createLinkElement();\n\n if (this._svgElement)\n this._containerElement.appendChild(this._svgElement);\n if (this._madeWithTextElement)\n textContainer.appendChild(this._madeWithTextElement);\n if (this._usernameTextElement)\n textContainer.appendChild(this._usernameTextElement);\n this._containerElement.appendChild(textContainer);\n if (this._backgroundElement)\n container.appendChild(this._backgroundElement);\n\n this._linkElement.append(this._containerElement);\n container.appendChild(this._linkElement);\n\n this.setupAnimations();\n }\n\n private createBackground() {\n this._backgroundElement = document.createElement('div');\n this._backgroundElement.setAttribute('id', 'watermark-background');\n this._backgroundElement.style.height = `${this._backgroundHeight}px`;\n this._backgroundElement.style.opacity = '0';\n if (this._placement.startsWith('top')) {\n this._backgroundElement.style.top = '0';\n this._backgroundElement.style.backgroundImage =\n 'linear-gradient(180deg, rgba(38, 38, 38, .6) 0%, rgba(38, 38, 38, 0) 100% )';\n } else {\n this._backgroundElement.style.bottom = '0';\n this._backgroundElement.style.backgroundImage =\n 'linear-gradient(0deg, rgba(38, 38, 38, .6) 0%, rgba(38, 38, 38, 0) 100% )';\n }\n }\n\n private setupAnimations() {\n // Necessary to trigger fade in transition\n requestAnimationFrame(() => {\n // Display the watermark\n setTimeout(() => {\n if (\n !this._containerElement ||\n !this._backgroundElement ||\n !this._linkElement\n )\n return;\n this._containerElement.style.opacity = '1';\n this._backgroundElement.style.opacity = '1';\n this._linkElement.style.pointerEvents = 'all';\n if (this._svgElement) this._svgElement.classList.add('spinning');\n }, this._fadeInDelayAfterGameLoaded * 1000);\n });\n\n // Hide the watermark\n this._fadeOutTimeout = setTimeout(() => {\n if (!this._containerElement || !this._backgroundElement) {\n return;\n }\n this._containerElement.style.opacity = '0';\n this._backgroundElement.style.opacity = '0';\n\n // Completely remove the watermark once the fade out duration has ended.\n this._hideTimeout = setTimeout(\n () => {\n if (\n !this._containerElement ||\n !this._backgroundElement ||\n !this._linkElement\n )\n return;\n this._linkElement.style.pointerEvents = 'none';\n this._containerElement.style.display = 'none';\n this._backgroundElement.style.display = 'none';\n if (this._resizeObserver) this._resizeObserver.disconnect();\n },\n // Deactivate all interaction possibilities with watermark at\n // the end of the animation to make sure it doesn't deactivate too early\n this._fadeDuration * 1000\n );\n }, (this._fadeInDelayAfterGameLoaded + this._displayDuration) * 1000);\n\n // Change text below watermark\n this._fadeOutFirstTextTimeout = setTimeout(() => {\n const { _madeWithTextElement, _usernameTextElement } = this;\n if (!_madeWithTextElement) return;\n\n // Do not hide madeWith text if there is no author username to display.\n if (_usernameTextElement) {\n _madeWithTextElement.style.opacity = '0';\n this._fadeInSecondTextTimeout = setTimeout(() => {\n _usernameTextElement.style.lineHeight = 'normal';\n _usernameTextElement.style.opacity = '1';\n _madeWithTextElement.style.lineHeight = '0';\n }, this._fadeDuration * 1000);\n }\n }, (this._fadeInDelayAfterGameLoaded + this._changeTextDelay) * 1000);\n }\n\n private createMadeWithTextElement() {\n this._madeWithTextElement = document.createElement('span');\n this._madeWithTextElement.innerText = 'Made with GDevelop';\n this._madeWithTextElement.style.fontSize = `${this._textFontSize}px`;\n }\n\n private createUsernameTextElement() {\n if (!this._authorUsername) return;\n this._usernameTextElement = document.createElement('span');\n this._usernameTextElement.innerText = `@${this._authorUsername}`;\n this._usernameTextElement.style.fontSize = `${this._textFontSize}px`;\n this._usernameTextElement.style.opacity = '0';\n this._usernameTextElement.style.lineHeight = '0';\n }\n\n private updateElementMargins(element: HTMLElement) {\n switch (this._placement) {\n case 'top-left':\n element.style.top = `${this._margin}px`;\n element.style.left = `${this._margin}px`;\n break;\n case 'top-right':\n element.style.top = `${this._margin}px`;\n element.style.right = `${this._margin}px`;\n break;\n case 'bottom-left':\n element.style.bottom = `${this._margin}px`;\n element.style.left = `${this._margin}px`;\n break;\n case 'bottom-right':\n element.style.bottom = `${this._margin}px`;\n element.style.right = `${this._margin}px`;\n break;\n case 'top':\n element.style.top = `${this._margin}px`;\n element.style.left = '50%';\n element.style.transform = 'translate(-50%, 0)';\n break;\n case 'bottom':\n default:\n element.style.bottom = `${this._margin}px`;\n element.style.left = '50%';\n element.style.transform = 'translate(-50%, 0)';\n break;\n }\n }\n\n private createLinkElement(): HTMLAnchorElement {\n const linkElement = document.createElement('a');\n linkElement.id = 'watermark-link';\n\n let targetUrl = this._authorUsername\n ? new URL(`https://gd.games/${this._authorUsername}`)\n : new URL('https://gd.games');\n\n if (this._isDevEnvironment) {\n targetUrl.searchParams.set('dev', 'true');\n } else {\n targetUrl.searchParams.set('utm_source', 'gdevelop-game');\n targetUrl.searchParams.set('utm_medium', 'game-watermark');\n\n if (this._gameId) {\n targetUrl.searchParams.set('utm_campaign', this._gameId);\n }\n }\n linkElement.href = targetUrl.href;\n linkElement.target = '_blank';\n\n this.updateElementMargins(linkElement);\n\n return linkElement;\n }\n\n private createDivContainer(): HTMLDivElement {\n const divContainer = document.createElement('div');\n divContainer.setAttribute('id', 'watermark');\n\n divContainer.style.opacity = '0';\n return divContainer;\n }\n\n private generateSVGLogo(height: number) {\n this._svgElement = document.createElementNS(\n 'http://www.w3.org/2000/svg',\n 'svg'\n );\n\n this.updateLogoSize(height);\n this._svgElement.setAttribute('height', this._logoHeight.toString());\n this._svgElement.setAttribute('width', this._logoWidth.toString());\n this._svgElement.setAttribute('viewBox', '-2 -2 59 48');\n this._svgElement.setAttribute('fill', 'none');\n const path1 = document.createElementNS(\n 'http://www.w3.org/2000/svg',\n 'path'\n );\n const path2 = document.createElementNS(\n 'http://www.w3.org/2000/svg',\n 'path'\n );\n path1.setAttribute(\n 'd',\n 'M29.3447 33C25.1061 33 21.0255 31.8475 17.4207 29.3381C14.9081 27.5897 12 23.6418 12 16.9488C12 4.53178 18.3074 0 30.9827 0H53.8027L56 7.07232H32.7217C24.3558 7.07232 19.3813 7.72835 19.3813 16.9488C19.3813 19.9944 20.2354 22.1618 21.9933 23.574C24.9642 25.9612 30.7388 26.0628 34.2673 25.7208C34.2673 25.7208 35.715 21.0394 35.9534 20.2794C36.2327 19.3888 36.1104 19.1763 35.2392 19.1763C33.9808 19.1763 31.7185 19.1763 29.3175 19.1763C27.6349 19.1763 25.9818 18.3247 25.9818 16.2793C25.9818 14.3039 27.5198 13.1573 29.6281 13.1573C33.2786 13.1573 40.7969 13.1573 42.2041 13.1573C44.0489 13.1573 45.9315 13.4233 44.971 16.3601L39.8842 31.8734C39.8845 31.8738 35.7287 33 29.3447 33Z'\n );\n path2.setAttribute(\n 'd',\n 'M43.3039 35.3278C40.7894 37.1212 37.0648 38.1124 30.7449 38.1124C19.852 38.1124 11.8797 34.1251 8.62927 26.3952C7.0925 22.7415 7.24041 18.6005 7.24041 13H0.00129513C0.00129513 18.9056 -0.0984386 23.5361 1.45249 27.8011C5.51933 38.989 15.992 45 30.0606 45C43.6783 45 49.3213 41.0443 53 35.3278H43.3039Z'\n );\n this._svgElement.appendChild(path1);\n this._svgElement.appendChild(path2);\n }\n\n private addStyle() {\n const styleElement = document.createElement('style');\n styleElement.innerHTML = `\n @keyframes spin {\n 0% {\n transform: rotate(0deg);\n }\n\n 5% {\n transform: rotate(-10deg);\n animation-timing-function: ease-out;\n }\n\n 17% {\n transform: rotate(370deg);\n animation-timing-function: ease-in-out;\n }\n\n 20% {\n transform: rotate(360deg);\n animation-timing-function: ease-in-out;\n }\n\n 100% {\n transform: rotate(360deg);\n }\n }\n\n #watermark-background {\n position: absolute;\n pointer-events: none;\n width: 100%;\n transition-property: opacity;\n transition-duration: ${this._fadeDuration}s;\n }\n\n #watermark-link {\n all: unset;\n position: absolute;\n cursor: pointer;\n pointer-events: none;\n user-select: none;\n\n /* For Safari */\n -webkit-user-select: none;\n }\n\n #watermark {\n display: flex;\n flex-direction: row;\n align-items: center;\n transition-property: opacity;\n transition-duration: ${this._fadeDuration}s;\n transition-timing-function: ease-out;\n }\n\n #watermark > div {\n display: flex;\n flex-direction: column;\n margin-left: 5px;\n }\n\n #watermark span {\n color: white;\n font-family: 'Tahoma', 'Gill sans', 'Helvetica', 'Arial';\n font-size: ${this._textFontSize}px;\n transition: opacity;\n transition-duration: ${this._fadeDuration}s;\n\n /* For Safari */\n -webkit-transition: opacity;\n -webkit-transition-duration: ${this._fadeDuration}s;\n }\n\n #watermark svg.spinning {\n animation-name: spin;\n animation-direction: normal;\n animation-duration: 5s;\n animation-iteration-count: 3;\n animation-delay: 1.5s;\n }\n\n #watermark svg path {\n fill: white;\n }\n\n @media (hover: hover) {\n #watermark span {\n text-decoration: underline;\n text-decoration-style: solid;\n text-decoration-color: transparent;\n }\n\n #watermark:hover span {\n text-decoration-color: white;\n\n /* For Safari */\n -webkit-text-decoration-color: white;\n }\n }\n `;\n document.head.appendChild(styleElement);\n }\n }\n }\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["namespace gdjs {\n export namespace watermark {\n export class RuntimeWatermark {\n _gameRenderer: RuntimeGameRenderer;\n _isDevEnvironment: boolean;\n\n // Configuration\n _placement:\n | 'top-left'\n | 'top-right'\n | 'bottom-left'\n | 'bottom-right'\n | 'bottom'\n | 'top';\n _showAtStartup: boolean;\n _authorUsername: string | undefined;\n _gameId: string | undefined;\n\n // Dom elements\n _linkElement: HTMLAnchorElement | null = null;\n _containerElement: HTMLDivElement | null = null;\n _backgroundElement: HTMLDivElement | null = null;\n _svgElement: SVGElement | null = null;\n _usernameTextElement: HTMLSpanElement | null = null;\n _madeWithTextElement: HTMLSpanElement | null = null;\n\n _resizeObserver: ResizeObserver | null = null;\n\n // Durations in seconds\n _displayDuration: number = 20;\n _changeTextDelay: number = 7;\n _fadeInDelayAfterGameLoaded: number = 1;\n _fadeDuration: number = 0.3;\n\n // Timeout registration\n _fadeOutTimeout: NodeJS.Timeout | null = null;\n _hideTimeout: NodeJS.Timeout | null = null;\n _fadeOutFirstTextTimeout: NodeJS.Timeout | null = null;\n _fadeInSecondTextTimeout: NodeJS.Timeout | null = null;\n\n // Sizes\n _textFontSize: number = 14;\n _logoWidth: number = 56;\n _logoHeight: number = 45;\n _backgroundHeight: number = 150;\n _margin: number = 10;\n\n constructor(\n game: RuntimeGame,\n authorUsernames: Array<string>,\n watermarkData: WatermarkData\n ) {\n this._gameId = game._data.properties.projectUuid;\n this._gameRenderer = game.getRenderer();\n this._authorUsername = authorUsernames[0];\n this._placement = watermarkData.placement;\n this._showAtStartup = watermarkData.showWatermark;\n this._isDevEnvironment = game.isUsingGDevelopDevelopmentEnvironment();\n if (watermarkData.showWatermark) {\n this.addStyle();\n }\n }\n\n displayAtStartup() {\n if (this._showAtStartup) {\n this.display();\n }\n }\n\n display() {\n const gameContainer = this._gameRenderer.getDomElementContainer();\n if (gameContainer) {\n this.addWatermarkToGameContainer(gameContainer);\n this._resizeObserver = new ResizeObserver(() => {\n const gameContainerRectangle = gameContainer.getBoundingClientRect();\n this.onResizeGameContainer(gameContainerRectangle.height);\n });\n this._resizeObserver.observe(gameContainer);\n }\n }\n\n private updateFontSize(height: number) {\n this._textFontSize = Math.max(0.025 * height, 12);\n }\n private updateLogoSize(height: number) {\n this._logoWidth = Math.max(0.06 * height, 25);\n this._logoHeight = Math.round((45 / 56) * this._logoWidth);\n }\n private updateBackgroundHeight(height: number) {\n this._backgroundHeight = Math.max(0.13 * height, 45);\n }\n private updateMargin(height: number) {\n this._margin = Math.max(0.025 * height, 8);\n }\n\n private onResizeGameContainer(height: number) {\n this.updateFontSize(height);\n if (this._madeWithTextElement) {\n this._madeWithTextElement.style.fontSize = `${this._textFontSize}px`;\n }\n if (this._usernameTextElement) {\n this._usernameTextElement.style.fontSize = `${this._textFontSize}px`;\n }\n this.updateLogoSize(height);\n if (this._svgElement) {\n this._svgElement.setAttribute('height', this._logoHeight.toString());\n this._svgElement.setAttribute('width', this._logoWidth.toString());\n }\n this.updateBackgroundHeight(height);\n if (this._backgroundElement) {\n this._backgroundElement.style.height = `${this._backgroundHeight}px`;\n }\n this.updateMargin(height);\n if (this._linkElement) {\n this.updateElementMargins(this._linkElement);\n }\n }\n\n private addWatermarkToGameContainer(container: HTMLElement) {\n const gameContainerRectangle = container.getBoundingClientRect();\n this.updateFontSize(gameContainerRectangle.height);\n this.updateLogoSize(gameContainerRectangle.height);\n this.updateBackgroundHeight(gameContainerRectangle.height);\n\n this._containerElement = this.createDivContainer();\n this.createBackground();\n const textContainer = document.createElement('div');\n\n this.generateSVGLogo(gameContainerRectangle.height);\n this.createMadeWithTextElement();\n this.createUsernameTextElement();\n\n this._linkElement = this.createLinkElement();\n\n if (this._svgElement)\n this._containerElement.appendChild(this._svgElement);\n if (this._madeWithTextElement)\n textContainer.appendChild(this._madeWithTextElement);\n if (this._usernameTextElement)\n textContainer.appendChild(this._usernameTextElement);\n this._containerElement.appendChild(textContainer);\n if (this._backgroundElement)\n container.appendChild(this._backgroundElement);\n\n this._linkElement.append(this._containerElement);\n container.appendChild(this._linkElement);\n\n this.setupAnimations();\n }\n\n private createBackground() {\n this._backgroundElement = document.createElement('div');\n this._backgroundElement.setAttribute('id', 'watermark-background');\n this._backgroundElement.style.height = `${this._backgroundHeight}px`;\n this._backgroundElement.style.opacity = '0';\n if (this._placement.startsWith('top')) {\n this._backgroundElement.style.top = '0';\n this._backgroundElement.style.backgroundImage =\n 'linear-gradient(180deg, rgba(38, 38, 38, .6) 0%, rgba(38, 38, 38, 0) 100% )';\n } else {\n this._backgroundElement.style.bottom = '0';\n this._backgroundElement.style.backgroundImage =\n 'linear-gradient(0deg, rgba(38, 38, 38, .6) 0%, rgba(38, 38, 38, 0) 100% )';\n }\n }\n\n private setupAnimations() {\n // Necessary to trigger fade in transition\n requestAnimationFrame(() => {\n // Display the watermark\n setTimeout(() => {\n if (\n !this._containerElement ||\n !this._backgroundElement ||\n !this._linkElement\n )\n return;\n this._containerElement.style.opacity = '1';\n this._backgroundElement.style.opacity = '1';\n this._linkElement.style.pointerEvents = 'all';\n if (this._svgElement) this._svgElement.classList.add('spinning');\n }, this._fadeInDelayAfterGameLoaded * 1000);\n });\n\n // Hide the watermark\n this._fadeOutTimeout = setTimeout(() => {\n if (!this._containerElement || !this._backgroundElement) {\n return;\n }\n this._containerElement.style.opacity = '0';\n this._backgroundElement.style.opacity = '0';\n\n // Completely remove the watermark once the fade out duration has ended.\n this._hideTimeout = setTimeout(\n () => {\n if (\n !this._containerElement ||\n !this._backgroundElement ||\n !this._linkElement\n )\n return;\n this._linkElement.style.pointerEvents = 'none';\n this._containerElement.style.display = 'none';\n this._backgroundElement.style.display = 'none';\n if (this._resizeObserver) this._resizeObserver.disconnect();\n },\n // Deactivate all interaction possibilities with watermark at\n // the end of the animation to make sure it doesn't deactivate too early\n this._fadeDuration * 1000\n );\n }, (this._fadeInDelayAfterGameLoaded + this._displayDuration) * 1000);\n\n // Change text below watermark\n this._fadeOutFirstTextTimeout = setTimeout(() => {\n const { _madeWithTextElement, _usernameTextElement } = this;\n if (!_madeWithTextElement) return;\n\n // Do not hide madeWith text if there is no author username to display.\n if (_usernameTextElement) {\n _madeWithTextElement.style.opacity = '0';\n this._fadeInSecondTextTimeout = setTimeout(() => {\n _usernameTextElement.style.lineHeight = 'normal';\n _usernameTextElement.style.opacity = '1';\n _madeWithTextElement.style.lineHeight = '0';\n }, this._fadeDuration * 1000);\n }\n }, (this._fadeInDelayAfterGameLoaded + this._changeTextDelay) * 1000);\n }\n\n private createMadeWithTextElement() {\n this._madeWithTextElement = document.createElement('span');\n this._madeWithTextElement.innerText = 'Made with GDevelop';\n this._madeWithTextElement.style.fontSize = `${this._textFontSize}px`;\n }\n\n private createUsernameTextElement() {\n if (!this._authorUsername) return;\n this._usernameTextElement = document.createElement('span');\n this._usernameTextElement.innerText = `@${this._authorUsername}`;\n this._usernameTextElement.style.fontSize = `${this._textFontSize}px`;\n this._usernameTextElement.style.opacity = '0';\n this._usernameTextElement.style.lineHeight = '0';\n }\n\n private updateElementMargins(element: HTMLElement) {\n switch (this._placement) {\n case 'top-left':\n element.style.top = `${this._margin}px`;\n element.style.left = `${this._margin}px`;\n break;\n case 'top-right':\n element.style.top = `${this._margin}px`;\n element.style.right = `${this._margin}px`;\n break;\n case 'bottom-left':\n element.style.bottom = `${this._margin}px`;\n element.style.left = `${this._margin}px`;\n break;\n case 'bottom-right':\n element.style.bottom = `${this._margin}px`;\n element.style.right = `${this._margin}px`;\n break;\n case 'top':\n element.style.top = `${this._margin}px`;\n element.style.left = '50%';\n element.style.transform = 'translate(-50%, 0)';\n break;\n case 'bottom':\n default:\n element.style.bottom = `${this._margin}px`;\n element.style.left = '50%';\n element.style.transform = 'translate(-50%, 0)';\n break;\n }\n }\n\n private createLinkElement(): HTMLAnchorElement {\n const linkElement = document.createElement('a');\n linkElement.id = 'watermark-link';\n\n let targetUrl = this._authorUsername\n ? new URL(`https://gd.games/${this._authorUsername}`)\n : new URL('https://gd.games');\n\n if (this._isDevEnvironment) {\n targetUrl.searchParams.set('dev', 'true');\n } else {\n targetUrl.searchParams.set('utm_source', 'gdevelop-game');\n targetUrl.searchParams.set('utm_medium', 'game-watermark');\n\n if (this._gameId) {\n targetUrl.searchParams.set('utm_campaign', this._gameId);\n }\n }\n linkElement.href = targetUrl.href;\n linkElement.target = '_blank';\n\n this.updateElementMargins(linkElement);\n\n return linkElement;\n }\n\n private createDivContainer(): HTMLDivElement {\n const divContainer = document.createElement('div');\n divContainer.setAttribute('id', 'watermark');\n\n divContainer.style.opacity = '0';\n return divContainer;\n }\n\n private generateSVGLogo(height: number) {\n this._svgElement = document.createElementNS(\n 'http://www.w3.org/2000/svg',\n 'svg'\n );\n\n this.updateLogoSize(height);\n this._svgElement.setAttribute('height', this._logoHeight.toString());\n this._svgElement.setAttribute('width', this._logoWidth.toString());\n this._svgElement.setAttribute('viewBox', '-2 -2 59 48');\n this._svgElement.setAttribute('fill', 'none');\n const path1 = document.createElementNS(\n 'http://www.w3.org/2000/svg',\n 'path'\n );\n const path2 = document.createElementNS(\n 'http://www.w3.org/2000/svg',\n 'path'\n );\n path1.setAttribute(\n 'd',\n 'M29.3447 33C25.1061 33 21.0255 31.8475 17.4207 29.3381C14.9081 27.5897 12 23.6418 12 16.9488C12 4.53178 18.3074 0 30.9827 0H53.8027L56 7.07232H32.7217C24.3558 7.07232 19.3813 7.72835 19.3813 16.9488C19.3813 19.9944 20.2354 22.1618 21.9933 23.574C24.9642 25.9612 30.7388 26.0628 34.2673 25.7208C34.2673 25.7208 35.715 21.0394 35.9534 20.2794C36.2327 19.3888 36.1104 19.1763 35.2392 19.1763C33.9808 19.1763 31.7185 19.1763 29.3175 19.1763C27.6349 19.1763 25.9818 18.3247 25.9818 16.2793C25.9818 14.3039 27.5198 13.1573 29.6281 13.1573C33.2786 13.1573 40.7969 13.1573 42.2041 13.1573C44.0489 13.1573 45.9315 13.4233 44.971 16.3601L39.8842 31.8734C39.8845 31.8738 35.7287 33 29.3447 33Z'\n );\n path2.setAttribute(\n 'd',\n 'M43.3039 35.3278C40.7894 37.1212 37.0648 38.1124 30.7449 38.1124C19.852 38.1124 11.8797 34.1251 8.62927 26.3952C7.0925 22.7415 7.24041 18.6005 7.24041 13H0.00129513C0.00129513 18.9056 -0.0984386 23.5361 1.45249 27.8011C5.51933 38.989 15.992 45 30.0606 45C43.6783 45 49.3213 41.0443 53 35.3278H43.3039Z'\n );\n this._svgElement.appendChild(path1);\n this._svgElement.appendChild(path2);\n }\n\n private addStyle() {\n const styleElement = document.createElement('style');\n styleElement.innerHTML = `\n @keyframes spin {\n 0% {\n transform: rotate(0deg);\n }\n\n 5% {\n transform: rotate(-10deg);\n animation-timing-function: ease-out;\n }\n\n 17% {\n transform: rotate(370deg);\n animation-timing-function: ease-in-out;\n }\n\n 20% {\n transform: rotate(360deg);\n animation-timing-function: ease-in-out;\n }\n\n 100% {\n transform: rotate(360deg);\n }\n }\n\n #watermark-background {\n position: absolute;\n pointer-events: none;\n width: 100%;\n transition-property: opacity;\n transition-duration: ${this._fadeDuration}s;\n }\n\n #watermark-link {\n all: unset;\n position: absolute;\n cursor: pointer;\n pointer-events: none;\n user-select: none;\n\n /* For Safari */\n -webkit-user-select: none;\n }\n\n #watermark {\n display: flex;\n flex-direction: row;\n align-items: center;\n transition-property: opacity;\n transition-duration: ${this._fadeDuration}s;\n transition-timing-function: ease-out;\n }\n\n #watermark > div {\n display: flex;\n flex-direction: column;\n margin-left: 5px;\n }\n\n #watermark span {\n color: white;\n font-family: 'Tahoma', 'Gill sans', 'Helvetica', 'Arial';\n font-size: ${this._textFontSize}px;\n transition: opacity;\n transition-duration: ${this._fadeDuration}s;\n\n /* For Safari */\n -webkit-transition: opacity;\n -webkit-transition-duration: ${this._fadeDuration}s;\n }\n\n #watermark svg.spinning {\n animation-name: spin;\n animation-direction: normal;\n animation-duration: 5s;\n animation-iteration-count: 3;\n animation-delay: 1.5s;\n }\n\n #watermark svg path {\n fill: white;\n }\n\n @media (hover: hover) {\n #watermark span {\n text-decoration: underline;\n text-decoration-style: solid;\n text-decoration-color: transparent;\n }\n\n #watermark:hover span {\n text-decoration-color: white;\n\n /* For Safari */\n -webkit-text-decoration-color: white;\n }\n }\n `;\n document.head.appendChild(styleElement);\n }\n }\n }\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -1,2 +1,2 @@
1
- var gdjs;(function(c){const o=new c.Logger("Scene stack"),r=new c.Logger("Multiplayer - Debug");class h{constructor(t){this._stack=[];this._wasFirstSceneLoaded=!1;this._isNextLayoutLoading=!1;this._sceneStackSyncDataToApply=null;if(!t)throw"SceneStack must be constructed with a gdjs.RuntimeGame.";this._runtimeGame=t}onGameResolutionResized(){for(let t=0;t<this._stack.length;++t)this._stack[t].onGameResolutionResized()}step(t){if(this._isNextLayoutLoading||this._stack.length===0)return!1;if(this.applyUpdateFromNetworkSyncDataIfAny())return r.info("Scene stack has been updated from network sync data, skipping step."),!0;const e=this._stack[this._stack.length-1];if(e.renderAndStep(t)){const n=e.getRequestedChange();if(n===c.SceneChangeRequest.STOP_GAME)return this._runtimeGame.getRenderer().stopGame(),!0;n===c.SceneChangeRequest.POP_SCENE?this.pop():n===c.SceneChangeRequest.PUSH_SCENE?this.push(e.getRequestedScene()):n===c.SceneChangeRequest.REPLACE_SCENE?this.replace(e.getRequestedScene()):n===c.SceneChangeRequest.CLEAR_SCENES?this.replace(e.getRequestedScene(),!0):o.error("Unrecognized change in scene stack: "+n)}return!0}renderWithoutStep(){return this._stack.length===0?!1:(this._stack[this._stack.length-1].render(),!0)}pop(t=1){let s=!1;for(let e=0;e<t&&!(this._stack.length<=1);++e){s=!0;const n=this._stack.pop();if(!n)return;n.unloadScene()}if(s){const e=this._stack[this._stack.length-1];e&&e.onResume()}}push(t,s){const e=this._stack[this._stack.length-1];return e&&e.onPause(),this._runtimeGame.areSceneAssetsReady(t)?this._loadNewScene(t,s):(this._isNextLayoutLoading=!0,this._runtimeGame.loadSceneAssets(t).then(()=>{this._loadNewScene(t),this._isNextLayoutLoading=!1}),null)}_loadNewScene(t,s){const e=new c.RuntimeScene(this._runtimeGame);if(e.loadFromScene(this._runtimeGame.getSceneAndExtensionsData(t)),this._wasFirstSceneLoaded=!0,s){const n=this._runtimeGame.getExternalLayoutData(s);n&&e.createObjectsFrom(n.instances,0,0,0,!0)}return this._stack.push(e),e}replace(t,s){if(s)for(;this._stack.length!==0;){let e=this._stack.pop();e&&e.unloadScene()}else if(this._stack.length!==0){let e=this._stack.pop();e&&e.unloadScene()}return this.push(t)}getCurrentScene(){return this._stack.length===0?null:this._stack[this._stack.length-1]}wasFirstSceneLoaded(){return this._wasFirstSceneLoaded}getAllSceneNames(){return this._stack.map(t=>t.getName())}getNetworkSyncData(t){const s=t.playerNumber,e=t.isHost;if(s!==void 0&&!e)return null;const n=[];for(let a=0;a<this._stack.length;++a){const i=this._stack[a];n.push({name:i.getName(),networkId:i.getOrCreateNetworkId()})}return n}updateFromNetworkSyncData(t){this._sceneStackSyncDataToApply=t}applyUpdateFromNetworkSyncDataIfAny(){const t=this._sceneStackSyncDataToApply;let s=!1;if(!t)return s;this._sceneStackSyncDataToApply=null;for(let e=0;e<t.length;++e){const n=t[e],a=this._stack[e];if(!a){r.info(`Scene at position ${e} with name ${n.name} is missing from the stack, adding it.`);const i=this.push(n.name);i&&(i.networkId=n.networkId),s=!0;continue}if(a.getName()!==n.name){r.info(`Scene at position ${e} and name ${a.getName()} is not the same as the expected ${n.name}, replacing.`);const i=this.replace(n.name,!0);i&&(i.networkId=n.networkId),s=!0;continue}if(!a.networkId&&n.networkId&&n.name===a.getName()){r.info(`Scene at position ${e} and name ${a.getName()} has no networkId, let's assume it's the right one and reconcile it with the id ${n.networkId}.`),a.networkId=n.networkId;continue}if(a.networkId!==n.networkId){r.info(`Scene at position ${e} and name ${a.getName()} has a different networkId ${a.networkId} than the expected ${n.networkId}, replacing.`);const i=this.replace(n.name,!1);i&&(i.networkId=n.networkId),s=!0;continue}}if(this._stack.length>t.length){const e=this._stack.length-t.length;this.pop(e),s=!0}return s}}c.SceneStack=h})(gdjs||(gdjs={}));
1
+ var gdjs;(function(o){const r=new o.Logger("Scene stack"),c=new o.Logger("Multiplayer - Debug");class h{constructor(t){this._stack=[];this._wasFirstSceneLoaded=!1;this._isNextLayoutLoading=!1;this._sceneStackSyncDataToApply=null;this._wasDisposed=!1;if(!t)throw"SceneStack must be constructed with a gdjs.RuntimeGame.";this._runtimeGame=t}onGameResolutionResized(){for(let t=0;t<this._stack.length;++t)this._stack[t].onGameResolutionResized()}step(t){if(this._throwIfDisposed(),this._isNextLayoutLoading||this._stack.length===0)return!1;if(this.applyUpdateFromNetworkSyncDataIfAny())return c.info("Scene stack has been updated from network sync data, skipping step."),!0;const e=this._stack[this._stack.length-1];if(e.renderAndStep(t)){const n=e.getRequestedChange();if(n===o.SceneChangeRequest.STOP_GAME)return this._runtimeGame.getRenderer().stopGame(),!0;n===o.SceneChangeRequest.POP_SCENE?this.pop():n===o.SceneChangeRequest.PUSH_SCENE?this.push(e.getRequestedScene()):n===o.SceneChangeRequest.REPLACE_SCENE?this.replace(e.getRequestedScene()):n===o.SceneChangeRequest.CLEAR_SCENES?this.replace(e.getRequestedScene(),!0):r.error("Unrecognized change in scene stack: "+n)}return!0}renderWithoutStep(){return this._throwIfDisposed(),this._stack.length===0?!1:(this._stack[this._stack.length-1].render(),!0)}pop(t=1){this._throwIfDisposed();let s=!1;for(let e=0;e<t&&!(this._stack.length<=1);++e){s=!0;const n=this._stack.pop();if(!n)return;n.unloadScene()}if(s){const e=this._stack[this._stack.length-1];e&&e.onResume()}}push(t,s){this._throwIfDisposed();const e=this._stack[this._stack.length-1];return e&&e.onPause(),this._runtimeGame.areSceneAssetsReady(t)?this._loadNewScene(t,s):(this._isNextLayoutLoading=!0,this._runtimeGame.loadSceneAssets(t).then(()=>{this._loadNewScene(t),this._isNextLayoutLoading=!1}),null)}_loadNewScene(t,s){this._throwIfDisposed();const e=new o.RuntimeScene(this._runtimeGame);if(e.loadFromScene(this._runtimeGame.getSceneAndExtensionsData(t)),this._wasFirstSceneLoaded=!0,s){const n=this._runtimeGame.getExternalLayoutData(s);n&&e.createObjectsFrom(n.instances,0,0,0,!0)}return this._stack.push(e),e}replace(t,s){if(this._throwIfDisposed(),s)for(;this._stack.length!==0;){let e=this._stack.pop();e&&e.unloadScene()}else if(this._stack.length!==0){let e=this._stack.pop();e&&e.unloadScene()}return this.push(t)}getCurrentScene(){return this._throwIfDisposed(),this._stack.length===0?null:this._stack[this._stack.length-1]}wasFirstSceneLoaded(){return this._wasFirstSceneLoaded}getAllSceneNames(){return this._throwIfDisposed(),this._stack.map(t=>t.getName())}getNetworkSyncData(t){const s=t.playerNumber,e=t.isHost;if(s!==void 0&&!e)return null;const n=[];for(let a=0;a<this._stack.length;++a){const i=this._stack[a];n.push({name:i.getName(),networkId:i.getOrCreateNetworkId()})}return n}updateFromNetworkSyncData(t){this._sceneStackSyncDataToApply=t}applyUpdateFromNetworkSyncDataIfAny(){this._throwIfDisposed();const t=this._sceneStackSyncDataToApply;let s=!1;if(!t)return s;this._sceneStackSyncDataToApply=null;for(let e=0;e<t.length;++e){const n=t[e],a=this._stack[e];if(!a){c.info(`Scene at position ${e} with name ${n.name} is missing from the stack, adding it.`);const i=this.push(n.name);i&&(i.networkId=n.networkId),s=!0;continue}if(a.getName()!==n.name){c.info(`Scene at position ${e} and name ${a.getName()} is not the same as the expected ${n.name}, replacing.`);const i=this.replace(n.name,!0);i&&(i.networkId=n.networkId),s=!0;continue}if(!a.networkId&&n.networkId&&n.name===a.getName()){c.info(`Scene at position ${e} and name ${a.getName()} has no networkId, let's assume it's the right one and reconcile it with the id ${n.networkId}.`),a.networkId=n.networkId;continue}if(a.networkId!==n.networkId){c.info(`Scene at position ${e} and name ${a.getName()} has a different networkId ${a.networkId} than the expected ${n.networkId}, replacing.`);const i=this.replace(n.name,!1);i&&(i.networkId=n.networkId),s=!0;continue}}if(this._stack.length>t.length){const e=this._stack.length-t.length;this.pop(e),s=!0}return s}dispose(){for(const t of this._stack)t.unloadScene();this._stack.length=0,this._wasDisposed=!0}_throwIfDisposed(){if(this._wasDisposed)throw"The scene stack has been disposed and should not be used anymore."}}o.SceneStack=h})(gdjs||(gdjs={}));
2
2
  //# sourceMappingURL=scenestack.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../GDevelop/GDJS/Runtime/scenestack.ts"],
4
- "sourcesContent": ["namespace gdjs {\n const logger = new gdjs.Logger('Scene stack');\n const debugLogger = new gdjs.Logger('Multiplayer - Debug');\n\n /**\n * Hold the stack of scenes ({@link gdjs.RuntimeScene}) being played.\n */\n export class SceneStack {\n _runtimeGame: gdjs.RuntimeGame;\n _stack: gdjs.RuntimeScene[] = [];\n _wasFirstSceneLoaded: boolean = false;\n _isNextLayoutLoading: boolean = false;\n _sceneStackSyncDataToApply: SceneStackNetworkSyncData | null = null;\n\n /**\n * @param runtimeGame The runtime game that is using the scene stack\n */\n constructor(runtimeGame: gdjs.RuntimeGame) {\n if (!runtimeGame) {\n throw 'SceneStack must be constructed with a gdjs.RuntimeGame.';\n }\n this._runtimeGame = runtimeGame;\n }\n\n /**\n * Called by the RuntimeGame when the game resolution is changed.\n * Useful to notify scene and layers that resolution is changed, as they\n * might be caching it.\n */\n onGameResolutionResized(): void {\n for (let i = 0; i < this._stack.length; ++i) {\n this._stack[i].onGameResolutionResized();\n }\n }\n\n step(elapsedTime: float): boolean {\n if (this._isNextLayoutLoading || this._stack.length === 0) {\n return false;\n }\n\n const hasMadeChangeToStack = this.applyUpdateFromNetworkSyncDataIfAny();\n if (hasMadeChangeToStack) {\n debugLogger.info(\n 'Scene stack has been updated from network sync data, skipping step.'\n );\n // If we have made changes to the stack as part of the network sync,\n // we trust the network to be the source of truth for the scene stack,\n // and skip the scene rendering (and so any other request to change the scene stack from it)\n return true;\n }\n\n const currentScene = this._stack[this._stack.length - 1];\n if (currentScene.renderAndStep(elapsedTime)) {\n const request = currentScene.getRequestedChange();\n\n // A scene change was requested by the current scene.\n if (request === gdjs.SceneChangeRequest.STOP_GAME) {\n this._runtimeGame.getRenderer().stopGame();\n return true;\n } else if (request === gdjs.SceneChangeRequest.POP_SCENE) {\n this.pop();\n } else if (request === gdjs.SceneChangeRequest.PUSH_SCENE) {\n this.push(currentScene.getRequestedScene());\n } else if (request === gdjs.SceneChangeRequest.REPLACE_SCENE) {\n this.replace(currentScene.getRequestedScene());\n } else if (request === gdjs.SceneChangeRequest.CLEAR_SCENES) {\n this.replace(currentScene.getRequestedScene(), true);\n } else {\n logger.error('Unrecognized change in scene stack: ' + request);\n }\n }\n\n return true;\n }\n\n renderWithoutStep(): boolean {\n if (this._stack.length === 0) {\n return false;\n }\n const currentScene = this._stack[this._stack.length - 1];\n currentScene.render();\n return true;\n }\n\n pop(popCount = 1): void {\n let hasDoneAnyChanges = false;\n for (let i = 0; i < popCount; ++i) {\n if (this._stack.length <= 1) {\n break;\n }\n\n // Unload the current scene\n hasDoneAnyChanges = true;\n const scene = this._stack.pop();\n if (!scene) {\n return;\n }\n scene.unloadScene();\n }\n\n // Tell the new current scene it's being resumed\n if (hasDoneAnyChanges) {\n const currentScene = this._stack[this._stack.length - 1];\n if (currentScene) {\n currentScene.onResume();\n }\n }\n }\n\n /**\n * Pause the scene currently being played and start the new scene that is specified.\n * If `externalLayoutName` is set, also instantiate the objects from this external layout.\n */\n push(\n newSceneName: string,\n externalLayoutName?: string\n ): gdjs.RuntimeScene | null {\n // Tell the scene it's being paused\n const currentScene = this._stack[this._stack.length - 1];\n if (currentScene) {\n currentScene.onPause();\n }\n\n // Avoid a risk of displaying an intermediate loading screen\n // during 1 frame.\n if (this._runtimeGame.areSceneAssetsReady(newSceneName)) {\n return this._loadNewScene(newSceneName, externalLayoutName);\n }\n\n this._isNextLayoutLoading = true;\n this._runtimeGame.loadSceneAssets(newSceneName).then(() => {\n this._loadNewScene(newSceneName);\n this._isNextLayoutLoading = false;\n });\n return null;\n }\n\n private _loadNewScene(\n newSceneName: string,\n externalLayoutName?: string\n ): gdjs.RuntimeScene {\n // Load the new one\n const newScene = new gdjs.RuntimeScene(this._runtimeGame);\n newScene.loadFromScene(\n this._runtimeGame.getSceneAndExtensionsData(newSceneName)\n );\n this._wasFirstSceneLoaded = true;\n\n // Optionally create the objects from an external layout.\n if (externalLayoutName) {\n const externalLayoutData = this._runtimeGame.getExternalLayoutData(\n externalLayoutName\n );\n if (externalLayoutData) {\n newScene.createObjectsFrom(\n externalLayoutData.instances,\n 0,\n 0,\n 0,\n /*trackByPersistentUuid=*/\n true\n );\n }\n }\n this._stack.push(newScene);\n return newScene;\n }\n\n /**\n * Start the specified scene, replacing the one currently being played.\n * If `clear` is set to true, all running scenes are also removed from the stack of scenes.\n */\n replace(newSceneName: string, clear?: boolean): gdjs.RuntimeScene | null {\n if (!!clear) {\n // Unload all the scenes\n while (this._stack.length !== 0) {\n let scene = this._stack.pop();\n if (scene) {\n scene.unloadScene();\n }\n }\n } else {\n // Unload the current scene\n if (this._stack.length !== 0) {\n let scene = this._stack.pop();\n if (scene) {\n scene.unloadScene();\n }\n }\n }\n return this.push(newSceneName);\n }\n\n /**\n * Return the current gdjs.RuntimeScene being played, or null if none is run.\n */\n getCurrentScene(): gdjs.RuntimeScene | null {\n if (this._stack.length === 0) {\n return null;\n }\n return this._stack[this._stack.length - 1];\n }\n\n /**\n * Return true if a scene was loaded, false otherwise (i.e: game not yet started).\n */\n wasFirstSceneLoaded(): boolean {\n return this._wasFirstSceneLoaded;\n }\n\n getAllSceneNames(): Array<string> {\n return this._stack.map((scene) => scene.getName());\n }\n\n getNetworkSyncData(\n syncOptions: GetNetworkSyncDataOptions\n ): SceneStackNetworkSyncData | null {\n const syncedPlayerNumber = syncOptions.playerNumber;\n const isHost = syncOptions.isHost;\n if (syncedPlayerNumber !== undefined && !isHost) {\n // If we are getting sync data of a specific player,\n // and they are not the host, we don't sync the scene stack.\n return null;\n }\n\n // If we are the host, we can take charge of\n // generating a networkId for each scene if they don't have one.\n // They will be reconciled on the other players' games.\n const sceneStackSyncData: SceneStackSceneNetworkSyncData[] = [];\n for (let i = 0; i < this._stack.length; ++i) {\n const scene = this._stack[i];\n sceneStackSyncData.push({\n name: scene.getName(),\n networkId: scene.getOrCreateNetworkId(),\n });\n }\n return sceneStackSyncData;\n }\n\n updateFromNetworkSyncData(\n sceneStackSyncData: SceneStackNetworkSyncData\n ): void {\n // Don't directly apply changes to the scene stack. Store them and they will be applied\n // in `step` (i.e: at the end of a frame). Otherwise, we would risk doing operations on the scene\n // stack, like creating a new scene or unloading a scene, while being inside the `renderAndStep` method\n // of the current scene.\n this._sceneStackSyncDataToApply = sceneStackSyncData;\n }\n\n applyUpdateFromNetworkSyncDataIfAny(): boolean {\n const sceneStackSyncData = this._sceneStackSyncDataToApply;\n let hasMadeChangeToStack = false;\n if (!sceneStackSyncData) return hasMadeChangeToStack;\n\n this._sceneStackSyncDataToApply = null;\n\n // If this method is called, we are a client.\n // We trust the host to be the source of truth for the scene stack.\n // So we loop through the scenes in the stack given by the host and either:\n // - Set the networkId of the scene if it's already in the stack at the right place\n // - Add the scene to the stack if it's not there, and set its networkId\n // - Remove any scenes that are in the stack but not in the data given by the host\n for (let i = 0; i < sceneStackSyncData.length; ++i) {\n const sceneSyncData = sceneStackSyncData[i];\n const sceneAtThisPositionInOurStack = this._stack[i];\n if (!sceneAtThisPositionInOurStack) {\n debugLogger.info(\n `Scene at position ${i} with name ${sceneSyncData.name} is missing from the stack, adding it.`\n );\n // We have fewer scenes in the stack than the host, let's add the scene.\n const newScene = this.push(sceneSyncData.name);\n if (newScene) {\n newScene.networkId = sceneSyncData.networkId;\n }\n hasMadeChangeToStack = true;\n // Continue to the next scene in the stack received from the host.\n continue;\n }\n\n if (sceneAtThisPositionInOurStack.getName() !== sceneSyncData.name) {\n debugLogger.info(\n `Scene at position ${i} and name ${sceneAtThisPositionInOurStack.getName()} is not the same as the expected ${\n sceneSyncData.name\n }, replacing.`\n );\n // The scene does not correspond to the scene at this position in our stack\n // Let's unload everything after this position to recreate the stack.\n const newScene = this.replace(\n sceneSyncData.name,\n true // Clear the stack\n );\n if (newScene) {\n newScene.networkId = sceneSyncData.networkId;\n }\n hasMadeChangeToStack = true;\n // Continue to the next scene in the stack received from the host.\n continue;\n }\n\n if (\n !sceneAtThisPositionInOurStack.networkId &&\n sceneSyncData.networkId &&\n sceneSyncData.name === sceneAtThisPositionInOurStack.getName()\n ) {\n debugLogger.info(\n `Scene at position ${i} and name ${sceneAtThisPositionInOurStack.getName()} has no networkId, let's assume it's the right one and reconcile it with the id ${\n sceneSyncData.networkId\n }.`\n );\n // The scene is in the stack but has no networkId,\n // this can happen at the start of the game on a player that is not the host,\n // or if a player switch to another scene before the host has sent the scene stack.\n // Let's set the networkId of the scene.\n sceneAtThisPositionInOurStack.networkId = sceneSyncData.networkId;\n // Continue to the next scene in the stack received from the host.\n continue;\n }\n\n if (\n sceneAtThisPositionInOurStack.networkId !== sceneSyncData.networkId\n ) {\n debugLogger.info(\n `Scene at position ${i} and name ${sceneAtThisPositionInOurStack.getName()} has a different networkId ${\n sceneAtThisPositionInOurStack.networkId\n } than the expected ${sceneSyncData.networkId}, replacing.`\n );\n // The scene is in the stack but has a different networkId\n // This can happen if the host has restarted the scene\n // We can't just update the networkId of the scene in the stack\n // We need to replace it with a new scene\n const newScene = this.replace(\n sceneSyncData.name,\n false // Don't clear the stack\n );\n if (newScene) {\n newScene.networkId = sceneSyncData.networkId;\n }\n hasMadeChangeToStack = true;\n // Continue to the next scene in the stack received from the host.\n continue;\n }\n\n // The scene is in the stack and has the right networkId.\n // Nothing to do, just continue to the next scene in the stack received from the host.\n }\n\n // Pop any scene not on the host.\n // In the future, we could avoid to pop scenes if they are not set to be synchronized.\n if (this._stack.length > sceneStackSyncData.length) {\n const popCount = this._stack.length - sceneStackSyncData.length;\n this.pop(popCount);\n hasMadeChangeToStack = true;\n }\n\n return hasMadeChangeToStack;\n }\n }\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["namespace gdjs {\n const logger = new gdjs.Logger('Scene stack');\n const debugLogger = new gdjs.Logger('Multiplayer - Debug');\n\n /**\n * Hold the stack of scenes ({@link gdjs.RuntimeScene}) being played.\n */\n export class SceneStack {\n _runtimeGame: gdjs.RuntimeGame;\n _stack: gdjs.RuntimeScene[] = [];\n _wasFirstSceneLoaded: boolean = false;\n _isNextLayoutLoading: boolean = false;\n _sceneStackSyncDataToApply: SceneStackNetworkSyncData | null = null;\n _wasDisposed: boolean = false;\n\n /**\n * @param runtimeGame The runtime game that is using the scene stack\n */\n constructor(runtimeGame: gdjs.RuntimeGame) {\n if (!runtimeGame) {\n throw 'SceneStack must be constructed with a gdjs.RuntimeGame.';\n }\n this._runtimeGame = runtimeGame;\n }\n\n /**\n * Called by the RuntimeGame when the game resolution is changed.\n * Useful to notify scene and layers that resolution is changed, as they\n * might be caching it.\n */\n onGameResolutionResized(): void {\n for (let i = 0; i < this._stack.length; ++i) {\n this._stack[i].onGameResolutionResized();\n }\n }\n\n step(elapsedTime: float): boolean {\n this._throwIfDisposed();\n if (this._isNextLayoutLoading || this._stack.length === 0) {\n return false;\n }\n\n const hasMadeChangeToStack = this.applyUpdateFromNetworkSyncDataIfAny();\n if (hasMadeChangeToStack) {\n debugLogger.info(\n 'Scene stack has been updated from network sync data, skipping step.'\n );\n // If we have made changes to the stack as part of the network sync,\n // we trust the network to be the source of truth for the scene stack,\n // and skip the scene rendering (and so any other request to change the scene stack from it)\n return true;\n }\n\n const currentScene = this._stack[this._stack.length - 1];\n if (currentScene.renderAndStep(elapsedTime)) {\n const request = currentScene.getRequestedChange();\n\n // A scene change was requested by the current scene.\n if (request === gdjs.SceneChangeRequest.STOP_GAME) {\n this._runtimeGame.getRenderer().stopGame();\n return true;\n } else if (request === gdjs.SceneChangeRequest.POP_SCENE) {\n this.pop();\n } else if (request === gdjs.SceneChangeRequest.PUSH_SCENE) {\n this.push(currentScene.getRequestedScene());\n } else if (request === gdjs.SceneChangeRequest.REPLACE_SCENE) {\n this.replace(currentScene.getRequestedScene());\n } else if (request === gdjs.SceneChangeRequest.CLEAR_SCENES) {\n this.replace(currentScene.getRequestedScene(), true);\n } else {\n logger.error('Unrecognized change in scene stack: ' + request);\n }\n }\n\n return true;\n }\n\n renderWithoutStep(): boolean {\n this._throwIfDisposed();\n\n if (this._stack.length === 0) {\n return false;\n }\n const currentScene = this._stack[this._stack.length - 1];\n currentScene.render();\n return true;\n }\n\n pop(popCount = 1): void {\n this._throwIfDisposed();\n\n let hasDoneAnyChanges = false;\n for (let i = 0; i < popCount; ++i) {\n if (this._stack.length <= 1) {\n break;\n }\n\n // Unload the current scene\n hasDoneAnyChanges = true;\n const scene = this._stack.pop();\n if (!scene) {\n return;\n }\n scene.unloadScene();\n }\n\n // Tell the new current scene it's being resumed\n if (hasDoneAnyChanges) {\n const currentScene = this._stack[this._stack.length - 1];\n if (currentScene) {\n currentScene.onResume();\n }\n }\n }\n\n /**\n * Pause the scene currently being played and start the new scene that is specified.\n * If `externalLayoutName` is set, also instantiate the objects from this external layout.\n */\n push(\n newSceneName: string,\n externalLayoutName?: string\n ): gdjs.RuntimeScene | null {\n this._throwIfDisposed();\n\n // Tell the scene it's being paused\n const currentScene = this._stack[this._stack.length - 1];\n if (currentScene) {\n currentScene.onPause();\n }\n\n // Avoid a risk of displaying an intermediate loading screen\n // during 1 frame.\n if (this._runtimeGame.areSceneAssetsReady(newSceneName)) {\n return this._loadNewScene(newSceneName, externalLayoutName);\n }\n\n this._isNextLayoutLoading = true;\n this._runtimeGame.loadSceneAssets(newSceneName).then(() => {\n this._loadNewScene(newSceneName);\n this._isNextLayoutLoading = false;\n });\n return null;\n }\n\n private _loadNewScene(\n newSceneName: string,\n externalLayoutName?: string\n ): gdjs.RuntimeScene {\n this._throwIfDisposed();\n\n // Load the new one\n const newScene = new gdjs.RuntimeScene(this._runtimeGame);\n newScene.loadFromScene(\n this._runtimeGame.getSceneAndExtensionsData(newSceneName)\n );\n this._wasFirstSceneLoaded = true;\n\n // Optionally create the objects from an external layout.\n if (externalLayoutName) {\n const externalLayoutData = this._runtimeGame.getExternalLayoutData(\n externalLayoutName\n );\n if (externalLayoutData) {\n newScene.createObjectsFrom(\n externalLayoutData.instances,\n 0,\n 0,\n 0,\n /*trackByPersistentUuid=*/\n true\n );\n }\n }\n this._stack.push(newScene);\n return newScene;\n }\n\n /**\n * Start the specified scene, replacing the one currently being played.\n * If `clear` is set to true, all running scenes are also removed from the stack of scenes.\n */\n replace(newSceneName: string, clear?: boolean): gdjs.RuntimeScene | null {\n this._throwIfDisposed();\n if (!!clear) {\n // Unload all the scenes\n while (this._stack.length !== 0) {\n let scene = this._stack.pop();\n if (scene) {\n scene.unloadScene();\n }\n }\n } else {\n // Unload the current scene\n if (this._stack.length !== 0) {\n let scene = this._stack.pop();\n if (scene) {\n scene.unloadScene();\n }\n }\n }\n return this.push(newSceneName);\n }\n\n /**\n * Return the current gdjs.RuntimeScene being played, or null if none is run.\n */\n getCurrentScene(): gdjs.RuntimeScene | null {\n this._throwIfDisposed();\n if (this._stack.length === 0) {\n return null;\n }\n return this._stack[this._stack.length - 1];\n }\n\n /**\n * Return true if a scene was loaded, false otherwise (i.e: game not yet started).\n */\n wasFirstSceneLoaded(): boolean {\n return this._wasFirstSceneLoaded;\n }\n\n getAllSceneNames(): Array<string> {\n this._throwIfDisposed();\n return this._stack.map((scene) => scene.getName());\n }\n\n getNetworkSyncData(\n syncOptions: GetNetworkSyncDataOptions\n ): SceneStackNetworkSyncData | null {\n const syncedPlayerNumber = syncOptions.playerNumber;\n const isHost = syncOptions.isHost;\n if (syncedPlayerNumber !== undefined && !isHost) {\n // If we are getting sync data of a specific player,\n // and they are not the host, we don't sync the scene stack.\n return null;\n }\n\n // If we are the host, we can take charge of\n // generating a networkId for each scene if they don't have one.\n // They will be reconciled on the other players' games.\n const sceneStackSyncData: SceneStackSceneNetworkSyncData[] = [];\n for (let i = 0; i < this._stack.length; ++i) {\n const scene = this._stack[i];\n sceneStackSyncData.push({\n name: scene.getName(),\n networkId: scene.getOrCreateNetworkId(),\n });\n }\n return sceneStackSyncData;\n }\n\n updateFromNetworkSyncData(\n sceneStackSyncData: SceneStackNetworkSyncData\n ): void {\n // Don't directly apply changes to the scene stack. Store them and they will be applied\n // in `step` (i.e: at the end of a frame). Otherwise, we would risk doing operations on the scene\n // stack, like creating a new scene or unloading a scene, while being inside the `renderAndStep` method\n // of the current scene.\n this._sceneStackSyncDataToApply = sceneStackSyncData;\n }\n\n applyUpdateFromNetworkSyncDataIfAny(): boolean {\n this._throwIfDisposed();\n const sceneStackSyncData = this._sceneStackSyncDataToApply;\n let hasMadeChangeToStack = false;\n if (!sceneStackSyncData) return hasMadeChangeToStack;\n\n this._sceneStackSyncDataToApply = null;\n\n // If this method is called, we are a client.\n // We trust the host to be the source of truth for the scene stack.\n // So we loop through the scenes in the stack given by the host and either:\n // - Set the networkId of the scene if it's already in the stack at the right place\n // - Add the scene to the stack if it's not there, and set its networkId\n // - Remove any scenes that are in the stack but not in the data given by the host\n for (let i = 0; i < sceneStackSyncData.length; ++i) {\n const sceneSyncData = sceneStackSyncData[i];\n const sceneAtThisPositionInOurStack = this._stack[i];\n if (!sceneAtThisPositionInOurStack) {\n debugLogger.info(\n `Scene at position ${i} with name ${sceneSyncData.name} is missing from the stack, adding it.`\n );\n // We have fewer scenes in the stack than the host, let's add the scene.\n const newScene = this.push(sceneSyncData.name);\n if (newScene) {\n newScene.networkId = sceneSyncData.networkId;\n }\n hasMadeChangeToStack = true;\n // Continue to the next scene in the stack received from the host.\n continue;\n }\n\n if (sceneAtThisPositionInOurStack.getName() !== sceneSyncData.name) {\n debugLogger.info(\n `Scene at position ${i} and name ${sceneAtThisPositionInOurStack.getName()} is not the same as the expected ${\n sceneSyncData.name\n }, replacing.`\n );\n // The scene does not correspond to the scene at this position in our stack\n // Let's unload everything after this position to recreate the stack.\n const newScene = this.replace(\n sceneSyncData.name,\n true // Clear the stack\n );\n if (newScene) {\n newScene.networkId = sceneSyncData.networkId;\n }\n hasMadeChangeToStack = true;\n // Continue to the next scene in the stack received from the host.\n continue;\n }\n\n if (\n !sceneAtThisPositionInOurStack.networkId &&\n sceneSyncData.networkId &&\n sceneSyncData.name === sceneAtThisPositionInOurStack.getName()\n ) {\n debugLogger.info(\n `Scene at position ${i} and name ${sceneAtThisPositionInOurStack.getName()} has no networkId, let's assume it's the right one and reconcile it with the id ${\n sceneSyncData.networkId\n }.`\n );\n // The scene is in the stack but has no networkId,\n // this can happen at the start of the game on a player that is not the host,\n // or if a player switch to another scene before the host has sent the scene stack.\n // Let's set the networkId of the scene.\n sceneAtThisPositionInOurStack.networkId = sceneSyncData.networkId;\n // Continue to the next scene in the stack received from the host.\n continue;\n }\n\n if (\n sceneAtThisPositionInOurStack.networkId !== sceneSyncData.networkId\n ) {\n debugLogger.info(\n `Scene at position ${i} and name ${sceneAtThisPositionInOurStack.getName()} has a different networkId ${\n sceneAtThisPositionInOurStack.networkId\n } than the expected ${sceneSyncData.networkId}, replacing.`\n );\n // The scene is in the stack but has a different networkId\n // This can happen if the host has restarted the scene\n // We can't just update the networkId of the scene in the stack\n // We need to replace it with a new scene\n const newScene = this.replace(\n sceneSyncData.name,\n false // Don't clear the stack\n );\n if (newScene) {\n newScene.networkId = sceneSyncData.networkId;\n }\n hasMadeChangeToStack = true;\n // Continue to the next scene in the stack received from the host.\n continue;\n }\n\n // The scene is in the stack and has the right networkId.\n // Nothing to do, just continue to the next scene in the stack received from the host.\n }\n\n // Pop any scene not on the host.\n // In the future, we could avoid to pop scenes if they are not set to be synchronized.\n if (this._stack.length > sceneStackSyncData.length) {\n const popCount = this._stack.length - sceneStackSyncData.length;\n this.pop(popCount);\n hasMadeChangeToStack = true;\n }\n\n return hasMadeChangeToStack;\n }\n\n /**\n * Unload all the scenes and clear the stack.\n */\n dispose(): void {\n for (const item of this._stack) {\n item.unloadScene();\n }\n\n this._stack.length = 0;\n this._wasDisposed = true;\n }\n\n private _throwIfDisposed(): void {\n if (this._wasDisposed) {\n throw 'The scene stack has been disposed and should not be used anymore.';\n }\n }\n }\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }