gdcore-tools 2.0.0-beta9 → 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 (110) hide show
  1. package/README.md +64 -64
  2. package/dist/Runtime/Extensions/3D/JsExtension.js +7 -3
  3. package/dist/Runtime/Extensions/DialogueTree/JsExtension.js +44 -32
  4. package/dist/Runtime/Extensions/DialogueTree/bondage.js/dist/bondage.min.js +10 -10
  5. package/dist/Runtime/Extensions/DialogueTree/bondage.js/version.txt +5 -5
  6. package/dist/Runtime/Extensions/DialogueTree/dialoguetools.js +2 -2
  7. package/dist/Runtime/Extensions/DialogueTree/dialoguetools.js.map +2 -2
  8. package/dist/Runtime/Extensions/Firebase/A_firebasejs/NOTICE.txt +6 -6
  9. package/dist/Runtime/Extensions/Multiplayer/messageManager.js +1 -1
  10. package/dist/Runtime/Extensions/Multiplayer/messageManager.js.map +2 -2
  11. package/dist/Runtime/Extensions/Multiplayer/multiplayerobjectruntimebehavior.js +1 -1
  12. package/dist/Runtime/Extensions/Multiplayer/multiplayerobjectruntimebehavior.js.map +2 -2
  13. package/dist/Runtime/Extensions/Physics2Behavior/physics2runtimebehavior.js +1 -1
  14. package/dist/Runtime/Extensions/Physics2Behavior/physics2runtimebehavior.js.map +2 -2
  15. package/dist/Runtime/Extensions/PhysicsBehavior/box2djs/box2d.js +804 -804
  16. package/dist/Runtime/Extensions/Shopify/shopify-buy.umd.polyfilled.min.js +1 -1
  17. package/dist/Runtime/Extensions/Spine/managers/pixi-spine-atlas-manager.js +1 -1
  18. package/dist/Runtime/Extensions/Spine/managers/pixi-spine-atlas-manager.js.map +2 -2
  19. package/dist/Runtime/Extensions/Spine/managers/pixi-spine-manager.js +1 -1
  20. package/dist/Runtime/Extensions/Spine/managers/pixi-spine-manager.js.map +2 -2
  21. package/dist/Runtime/Extensions/TileMap/example/anotherIsland.json +5768 -5768
  22. package/dist/Runtime/Extensions/TileMap/example/island.json +5822 -5822
  23. package/dist/Runtime/Model3DManager.js +1 -1
  24. package/dist/Runtime/Model3DManager.js.map +2 -2
  25. package/dist/Runtime/ResourceLoader.js +1 -1
  26. package/dist/Runtime/ResourceLoader.js.map +2 -2
  27. package/dist/Runtime/capturemanager.js +2 -0
  28. package/dist/Runtime/capturemanager.js.map +7 -0
  29. package/dist/Runtime/fontfaceobserver-font-manager/fontfaceobserver-font-manager.js +1 -1
  30. package/dist/Runtime/fontfaceobserver-font-manager/fontfaceobserver-font-manager.js.map +2 -2
  31. package/dist/Runtime/howler-sound-manager/howler-sound-manager.js +1 -1
  32. package/dist/Runtime/howler-sound-manager/howler-sound-manager.js.map +2 -2
  33. package/dist/Runtime/jsonmanager.js +1 -1
  34. package/dist/Runtime/jsonmanager.js.map +2 -2
  35. package/dist/Runtime/layer.js +1 -1
  36. package/dist/Runtime/layer.js.map +2 -2
  37. package/dist/Runtime/pixi-renderers/pixi-bitmapfont-manager.js +1 -1
  38. package/dist/Runtime/pixi-renderers/pixi-bitmapfont-manager.js.map +2 -2
  39. package/dist/Runtime/pixi-renderers/pixi-image-manager.js +1 -1
  40. package/dist/Runtime/pixi-renderers/pixi-image-manager.js.map +2 -2
  41. package/dist/Runtime/pixi-renderers/runtimegame-pixi-renderer.js +1 -1
  42. package/dist/Runtime/pixi-renderers/runtimegame-pixi-renderer.js.map +2 -2
  43. package/dist/Runtime/runtimegame.js +1 -1
  44. package/dist/Runtime/runtimegame.js.map +2 -2
  45. package/dist/Runtime/runtimewatermark.js +2 -2
  46. package/dist/Runtime/runtimewatermark.js.map +2 -2
  47. package/dist/Runtime/scenestack.js +1 -1
  48. package/dist/Runtime/scenestack.js.map +2 -2
  49. package/dist/Runtime/spriteruntimeobject.js +1 -1
  50. package/dist/Runtime/spriteruntimeobject.js.map +2 -2
  51. package/dist/lib/libGD.cjs +21 -21
  52. package/dist/lib/libGD.wasm +0 -0
  53. package/gd.d.ts +22 -6
  54. package/package.json +1 -1
  55. package/dist/Runtime/Extensions/TileMap/helper/node_modules/.package-lock.json +0 -19
  56. package/dist/Runtime/Extensions/TileMap/helper/node_modules/@types/pako/index.d.ts +0 -165
  57. package/dist/Runtime/Extensions/TileMap/helper/node_modules/@types/pako/package.json +0 -35
  58. package/dist/Runtime/Extensions/TileMap/helper/node_modules/pako/dist/pako.es5.js +0 -2
  59. package/dist/Runtime/Extensions/TileMap/helper/node_modules/pako/dist/pako.es5.js.map +0 -7
  60. package/dist/Runtime/Extensions/TileMap/helper/node_modules/pako/dist/pako.es5.min.js +0 -2
  61. package/dist/Runtime/Extensions/TileMap/helper/node_modules/pako/dist/pako.js +0 -2
  62. package/dist/Runtime/Extensions/TileMap/helper/node_modules/pako/dist/pako.js.map +0 -7
  63. package/dist/Runtime/Extensions/TileMap/helper/node_modules/pako/dist/pako.min.js +0 -2
  64. package/dist/Runtime/Extensions/TileMap/helper/node_modules/pako/dist/pako_deflate.es5.js +0 -2
  65. package/dist/Runtime/Extensions/TileMap/helper/node_modules/pako/dist/pako_deflate.es5.js.map +0 -7
  66. package/dist/Runtime/Extensions/TileMap/helper/node_modules/pako/dist/pako_deflate.es5.min.js +0 -2
  67. package/dist/Runtime/Extensions/TileMap/helper/node_modules/pako/dist/pako_deflate.js +0 -2
  68. package/dist/Runtime/Extensions/TileMap/helper/node_modules/pako/dist/pako_deflate.js.map +0 -7
  69. package/dist/Runtime/Extensions/TileMap/helper/node_modules/pako/dist/pako_deflate.min.js +0 -2
  70. package/dist/Runtime/Extensions/TileMap/helper/node_modules/pako/dist/pako_inflate.es5.js +0 -2
  71. package/dist/Runtime/Extensions/TileMap/helper/node_modules/pako/dist/pako_inflate.es5.js.map +0 -7
  72. package/dist/Runtime/Extensions/TileMap/helper/node_modules/pako/dist/pako_inflate.es5.min.js +0 -2
  73. package/dist/Runtime/Extensions/TileMap/helper/node_modules/pako/dist/pako_inflate.js +0 -2
  74. package/dist/Runtime/Extensions/TileMap/helper/node_modules/pako/dist/pako_inflate.js.map +0 -7
  75. package/dist/Runtime/Extensions/TileMap/helper/node_modules/pako/dist/pako_inflate.min.js +0 -2
  76. package/dist/Runtime/Extensions/TileMap/helper/node_modules/pako/index.js +0 -2
  77. package/dist/Runtime/Extensions/TileMap/helper/node_modules/pako/index.js.map +0 -7
  78. package/dist/Runtime/Extensions/TileMap/helper/node_modules/pako/lib/deflate.js +0 -2
  79. package/dist/Runtime/Extensions/TileMap/helper/node_modules/pako/lib/deflate.js.map +0 -7
  80. package/dist/Runtime/Extensions/TileMap/helper/node_modules/pako/lib/inflate.js +0 -2
  81. package/dist/Runtime/Extensions/TileMap/helper/node_modules/pako/lib/inflate.js.map +0 -7
  82. package/dist/Runtime/Extensions/TileMap/helper/node_modules/pako/lib/utils/common.js +0 -2
  83. package/dist/Runtime/Extensions/TileMap/helper/node_modules/pako/lib/utils/common.js.map +0 -7
  84. package/dist/Runtime/Extensions/TileMap/helper/node_modules/pako/lib/utils/strings.js +0 -2
  85. package/dist/Runtime/Extensions/TileMap/helper/node_modules/pako/lib/utils/strings.js.map +0 -7
  86. package/dist/Runtime/Extensions/TileMap/helper/node_modules/pako/lib/zlib/adler32.js +0 -2
  87. package/dist/Runtime/Extensions/TileMap/helper/node_modules/pako/lib/zlib/adler32.js.map +0 -7
  88. package/dist/Runtime/Extensions/TileMap/helper/node_modules/pako/lib/zlib/constants.js +0 -2
  89. package/dist/Runtime/Extensions/TileMap/helper/node_modules/pako/lib/zlib/constants.js.map +0 -7
  90. package/dist/Runtime/Extensions/TileMap/helper/node_modules/pako/lib/zlib/crc32.js +0 -2
  91. package/dist/Runtime/Extensions/TileMap/helper/node_modules/pako/lib/zlib/crc32.js.map +0 -7
  92. package/dist/Runtime/Extensions/TileMap/helper/node_modules/pako/lib/zlib/deflate.js +0 -2
  93. package/dist/Runtime/Extensions/TileMap/helper/node_modules/pako/lib/zlib/deflate.js.map +0 -7
  94. package/dist/Runtime/Extensions/TileMap/helper/node_modules/pako/lib/zlib/gzheader.js +0 -2
  95. package/dist/Runtime/Extensions/TileMap/helper/node_modules/pako/lib/zlib/gzheader.js.map +0 -7
  96. package/dist/Runtime/Extensions/TileMap/helper/node_modules/pako/lib/zlib/inffast.js +0 -2
  97. package/dist/Runtime/Extensions/TileMap/helper/node_modules/pako/lib/zlib/inffast.js.map +0 -7
  98. package/dist/Runtime/Extensions/TileMap/helper/node_modules/pako/lib/zlib/inflate.js +0 -2
  99. package/dist/Runtime/Extensions/TileMap/helper/node_modules/pako/lib/zlib/inflate.js.map +0 -7
  100. package/dist/Runtime/Extensions/TileMap/helper/node_modules/pako/lib/zlib/inftrees.js +0 -2
  101. package/dist/Runtime/Extensions/TileMap/helper/node_modules/pako/lib/zlib/inftrees.js.map +0 -7
  102. package/dist/Runtime/Extensions/TileMap/helper/node_modules/pako/lib/zlib/messages.js +0 -2
  103. package/dist/Runtime/Extensions/TileMap/helper/node_modules/pako/lib/zlib/messages.js.map +0 -7
  104. package/dist/Runtime/Extensions/TileMap/helper/node_modules/pako/lib/zlib/trees.js +0 -2
  105. package/dist/Runtime/Extensions/TileMap/helper/node_modules/pako/lib/zlib/trees.js.map +0 -7
  106. package/dist/Runtime/Extensions/TileMap/helper/node_modules/pako/lib/zlib/zstream.js +0 -2
  107. package/dist/Runtime/Extensions/TileMap/helper/node_modules/pako/lib/zlib/zstream.js.map +0 -7
  108. package/dist/Runtime/Extensions/TileMap/helper/node_modules/pako/package.json +0 -64
  109. package/types/index.d.ts +0 -23
  110. package/types/open_project.d.ts +0 -25
@@ -1,2 +1,2 @@
1
- var gdjs;(function(t){const a=new t.Logger("Model3DManager"),n=["model3D"];class c{constructor(r){this._loadedThreeModels=new t.ResourceCache;this._downloadedArrayBuffers=new t.ResourceCache;this._loader=null;this._dracoLoader=null;if(this._resourceLoader=r,typeof THREE!="undefined"){this._loader=new THREE_ADDONS.GLTFLoader,this._dracoLoader=new THREE_ADDONS.DRACOLoader,this._dracoLoader.setDecoderPath("./pixi-renderers/draco/gltf/"),this._loader.setDRACOLoader(this._dracoLoader);const e=new THREE.Group;e.add(new THREE.Mesh(new THREE.BoxGeometry(1,1,1),new THREE.MeshBasicMaterial({color:"#ff00ff"}))),this._invalidModel={scene:e,animations:[],cameras:[],scenes:[],asset:{},userData:{},parser:null}}}getResourceKinds(){return n}async processResource(r){const e=this._resourceLoader.getResource(r);if(!e){a.warn('Unable to find texture for resource "'+r+'".');return}const d=this._loader;if(!d)return;const s=this._downloadedArrayBuffers.get(e);if(!!s){this._downloadedArrayBuffers.delete(e);try{const o=await d.parseAsync(s,"");this._loadedThreeModels.set(e,o)}catch(o){a.error("Can't fetch the 3D model file "+e.file+", error: "+o)}}}async loadResource(r){const e=this._resourceLoader.getResource(r);if(!e){a.warn('Unable to find texture for resource "'+r+'".');return}if(!this._loader||this._loadedThreeModels.get(e))return;const s=this._resourceLoader.getFullUrl(e.file);try{const o=await fetch(s,{credentials:this._resourceLoader.checkIfCredentialsRequired(s)?"include":"omit"});if(!o.ok)throw new Error("Network response was not ok");const i=await o.arrayBuffer();this._downloadedArrayBuffers.set(e,i)}catch(o){a.error("Can't fetch the 3D model file "+e.file+", error: "+o)}}getModel(r){return this._loadedThreeModels.getFromName(r)||this._invalidModel}}t.Model3DManager=c})(gdjs||(gdjs={}));
1
+ var gdjs;(function(d){const a=new d.Logger("Model3DManager"),i=["model3D"];class l{constructor(r){this._loadedThreeModels=new d.ResourceCache;this._downloadedArrayBuffers=new d.ResourceCache;this._loader=null;this._dracoLoader=null;if(this._resourceLoader=r,typeof THREE!="undefined"){this._loader=new THREE_ADDONS.GLTFLoader,this._dracoLoader=new THREE_ADDONS.DRACOLoader,this._dracoLoader.setDecoderPath("./pixi-renderers/draco/gltf/"),this._loader.setDRACOLoader(this._dracoLoader);const e=new THREE.Group;e.add(new THREE.Mesh(new THREE.BoxGeometry(1,1,1),new THREE.MeshBasicMaterial({color:"#ff00ff"}))),this._invalidModel={scene:e,animations:[],cameras:[],scenes:[],asset:{},userData:{},parser:null}}}getResourceKinds(){return i}async processResource(r){const e=this._resourceLoader.getResource(r);if(!e){a.warn('Unable to find texture for resource "'+r+'".');return}const t=this._loader;if(!t)return;const s=this._downloadedArrayBuffers.get(e);if(!!s){this._downloadedArrayBuffers.delete(e);try{const o=await t.parseAsync(s,"");this._loadedThreeModels.set(e,o)}catch(o){a.error("Can't fetch the 3D model file "+e.file+", error: "+o)}}}async loadResource(r){const e=this._resourceLoader.getResource(r);if(!e){a.warn('Unable to find texture for resource "'+r+'".');return}if(!this._loader||this._loadedThreeModels.get(e))return;const s=this._resourceLoader.getFullUrl(e.file);try{const o=await fetch(s,{credentials:this._resourceLoader.checkIfCredentialsRequired(s)?"include":"omit"});if(!o.ok)throw new Error("Network response was not ok");const n=await o.arrayBuffer();this._downloadedArrayBuffers.set(e,n)}catch(o){a.error("Can't fetch the 3D model file "+e.file+", error: "+o)}}getModel(r){return this._loadedThreeModels.getFromName(r)||this._invalidModel}dispose(){this._loadedThreeModels.clear(),this._downloadedArrayBuffers.clear(),this._loader=null,this._dracoLoader=null,this._invalidModel&&(this._invalidModel.cameras=[],this._invalidModel.animations=[],this._invalidModel.scenes=[],this._invalidModel.userData={},this._invalidModel.asset={},this._invalidModel.scene.clear())}}d.Model3DManager=l})(gdjs||(gdjs={}));
2
2
  //# sourceMappingURL=Model3DManager.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../GDevelop/GDJS/Runtime/Model3DManager.ts"],
4
- "sourcesContent": ["/*\n * GDevelop JS Platform\n * Copyright 2013-present 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('Model3DManager');\n\n const resourceKinds: Array<ResourceKind> = ['model3D'];\n\n /**\n * Load GLB files (using `Three.js`), using the \"model3D\" resources\n * registered in the game resources.\n */\n export class Model3DManager implements gdjs.ResourceManager {\n /**\n * Map associating a resource name to the loaded Three.js model.\n */\n private _loadedThreeModels = new gdjs.ResourceCache<THREE_ADDONS.GLTF>();\n private _downloadedArrayBuffers = new gdjs.ResourceCache<ArrayBuffer>();\n\n _resourceLoader: gdjs.ResourceLoader;\n\n _loader: THREE_ADDONS.GLTFLoader | null = null;\n _dracoLoader: THREE_ADDONS.DRACOLoader | null = null;\n\n //@ts-ignore Can only be null if THREE is not loaded.\n _invalidModel: THREE_ADDONS.GLTF;\n\n /**\n * @param resourceDataArray The resources data of the game.\n * @param resourceLoader The resources loader of the game.\n */\n constructor(resourceLoader: gdjs.ResourceLoader) {\n this._resourceLoader = resourceLoader;\n\n if (typeof THREE !== 'undefined') {\n this._loader = new THREE_ADDONS.GLTFLoader();\n\n this._dracoLoader = new THREE_ADDONS.DRACOLoader();\n this._dracoLoader.setDecoderPath('./pixi-renderers/draco/gltf/');\n this._loader.setDRACOLoader(this._dracoLoader);\n\n /**\n * The invalid model is a box with magenta (#ff00ff) faces, to be\n * easily spotted if rendered on screen.\n */\n const group = new THREE.Group();\n group.add(\n new THREE.Mesh(\n new THREE.BoxGeometry(1, 1, 1),\n new THREE.MeshBasicMaterial({ color: '#ff00ff' })\n )\n );\n this._invalidModel = {\n scene: group,\n animations: [],\n cameras: [],\n scenes: [],\n asset: {},\n userData: {},\n //@ts-ignore\n parser: null,\n };\n }\n }\n\n getResourceKinds(): ResourceKind[] {\n return resourceKinds;\n }\n\n async processResource(resourceName: string): Promise<void> {\n const resource = this._resourceLoader.getResource(resourceName);\n if (!resource) {\n logger.warn(\n 'Unable to find texture for resource \"' + resourceName + '\".'\n );\n return;\n }\n const loader = this._loader;\n if (!loader) {\n return;\n }\n const data = this._downloadedArrayBuffers.get(resource);\n if (!data) {\n return;\n }\n this._downloadedArrayBuffers.delete(resource);\n try {\n const gltf: THREE_ADDONS.GLTF = await loader.parseAsync(data, '');\n this._loadedThreeModels.set(resource, gltf);\n } catch (error) {\n logger.error(\n \"Can't fetch the 3D model file \" + resource.file + ', error: ' + error\n );\n }\n }\n\n async loadResource(resourceName: string): Promise<void> {\n const resource = this._resourceLoader.getResource(resourceName);\n if (!resource) {\n logger.warn(\n 'Unable to find texture for resource \"' + resourceName + '\".'\n );\n return;\n }\n const loader = this._loader;\n if (!loader) {\n return;\n }\n if (this._loadedThreeModels.get(resource)) {\n return;\n }\n const url = this._resourceLoader.getFullUrl(resource.file);\n try {\n const response = await fetch(url, {\n credentials: this._resourceLoader.checkIfCredentialsRequired(url)\n ? 'include'\n : 'omit',\n });\n if (!response.ok) {\n throw new Error('Network response was not ok');\n }\n const data = await response.arrayBuffer();\n this._downloadedArrayBuffers.set(resource, data);\n } catch (error) {\n logger.error(\n \"Can't fetch the 3D model file \" + resource.file + ', error: ' + error\n );\n }\n }\n\n /**\n * Return a 3D model.\n *\n * Caller should not modify the object but clone it.\n *\n * @param resourceName The name of the json resource.\n * @returns a 3D model if it exists.\n */\n getModel(resourceName: string): THREE_ADDONS.GLTF {\n return (\n this._loadedThreeModels.getFromName(resourceName) || this._invalidModel\n );\n }\n }\n}\n"],
5
- "mappings": "AAKA,GAAU,MAAV,UAAU,EAAV,CACE,KAAM,GAAS,GAAI,GAAK,OAAO,kBAEzB,EAAqC,CAAC,WAMrC,OAAqD,CAmB1D,YAAY,EAAqC,CAfzC,wBAAqB,GAAI,GAAK,cAC9B,6BAA0B,GAAI,GAAK,cAI3C,aAA0C,KAC1C,kBAAgD,KAY9C,GAFA,KAAK,gBAAkB,EAEnB,MAAO,QAAU,YAAa,CAChC,KAAK,QAAU,GAAI,cAAa,WAEhC,KAAK,aAAe,GAAI,cAAa,YACrC,KAAK,aAAa,eAAe,gCACjC,KAAK,QAAQ,eAAe,KAAK,cAMjC,KAAM,GAAQ,GAAI,OAAM,MACxB,EAAM,IACJ,GAAI,OAAM,KACR,GAAI,OAAM,YAAY,EAAG,EAAG,GAC5B,GAAI,OAAM,kBAAkB,CAAE,MAAO,cAGzC,KAAK,cAAgB,CACnB,MAAO,EACP,WAAY,GACZ,QAAS,GACT,OAAQ,GACR,MAAO,GACP,SAAU,GAEV,OAAQ,OAKd,kBAAmC,CACjC,MAAO,QAGH,iBAAgB,EAAqC,CACzD,KAAM,GAAW,KAAK,gBAAgB,YAAY,GAClD,GAAI,CAAC,EAAU,CACb,EAAO,KACL,wCAA0C,EAAe,MAE3D,OAEF,KAAM,GAAS,KAAK,QACpB,GAAI,CAAC,EACH,OAEF,KAAM,GAAO,KAAK,wBAAwB,IAAI,GAC9C,GAAI,EAAC,EAGL,MAAK,wBAAwB,OAAO,GACpC,GAAI,CACF,KAAM,GAA0B,KAAM,GAAO,WAAW,EAAM,IAC9D,KAAK,mBAAmB,IAAI,EAAU,SAC/B,EAAP,CACA,EAAO,MACL,iCAAmC,EAAS,KAAO,YAAc,UAKjE,cAAa,EAAqC,CACtD,KAAM,GAAW,KAAK,gBAAgB,YAAY,GAClD,GAAI,CAAC,EAAU,CACb,EAAO,KACL,wCAA0C,EAAe,MAE3D,OAMF,GAHI,CADW,KAAK,SAIhB,KAAK,mBAAmB,IAAI,GAC9B,OAEF,KAAM,GAAM,KAAK,gBAAgB,WAAW,EAAS,MACrD,GAAI,CACF,KAAM,GAAW,KAAM,OAAM,EAAK,CAChC,YAAa,KAAK,gBAAgB,2BAA2B,GACzD,UACA,SAEN,GAAI,CAAC,EAAS,GACZ,KAAM,IAAI,OAAM,+BAElB,KAAM,GAAO,KAAM,GAAS,cAC5B,KAAK,wBAAwB,IAAI,EAAU,SACpC,EAAP,CACA,EAAO,MACL,iCAAmC,EAAS,KAAO,YAAc,IAavE,SAAS,EAAyC,CAChD,MACE,MAAK,mBAAmB,YAAY,IAAiB,KAAK,eAhIzD,EAAM,mBATL",
4
+ "sourcesContent": ["/*\n * GDevelop JS Platform\n * Copyright 2013-present 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('Model3DManager');\n\n const resourceKinds: Array<ResourceKind> = ['model3D'];\n\n /**\n * Load GLB files (using `Three.js`), using the \"model3D\" resources\n * registered in the game resources.\n */\n export class Model3DManager implements gdjs.ResourceManager {\n /**\n * Map associating a resource name to the loaded Three.js model.\n */\n private _loadedThreeModels = new gdjs.ResourceCache<THREE_ADDONS.GLTF>();\n private _downloadedArrayBuffers = new gdjs.ResourceCache<ArrayBuffer>();\n\n _resourceLoader: gdjs.ResourceLoader;\n\n _loader: THREE_ADDONS.GLTFLoader | null = null;\n _dracoLoader: THREE_ADDONS.DRACOLoader | null = null;\n\n //@ts-ignore Can only be null if THREE is not loaded.\n _invalidModel: THREE_ADDONS.GLTF;\n\n /**\n * @param resourceDataArray The resources data of the game.\n * @param resourceLoader The resources loader of the game.\n */\n constructor(resourceLoader: gdjs.ResourceLoader) {\n this._resourceLoader = resourceLoader;\n\n if (typeof THREE !== 'undefined') {\n this._loader = new THREE_ADDONS.GLTFLoader();\n\n this._dracoLoader = new THREE_ADDONS.DRACOLoader();\n this._dracoLoader.setDecoderPath('./pixi-renderers/draco/gltf/');\n this._loader.setDRACOLoader(this._dracoLoader);\n\n /**\n * The invalid model is a box with magenta (#ff00ff) faces, to be\n * easily spotted if rendered on screen.\n */\n const group = new THREE.Group();\n group.add(\n new THREE.Mesh(\n new THREE.BoxGeometry(1, 1, 1),\n new THREE.MeshBasicMaterial({ color: '#ff00ff' })\n )\n );\n this._invalidModel = {\n scene: group,\n animations: [],\n cameras: [],\n scenes: [],\n asset: {},\n userData: {},\n //@ts-ignore\n parser: null,\n };\n }\n }\n\n getResourceKinds(): ResourceKind[] {\n return resourceKinds;\n }\n\n async processResource(resourceName: string): Promise<void> {\n const resource = this._resourceLoader.getResource(resourceName);\n if (!resource) {\n logger.warn(\n 'Unable to find texture for resource \"' + resourceName + '\".'\n );\n return;\n }\n const loader = this._loader;\n if (!loader) {\n return;\n }\n const data = this._downloadedArrayBuffers.get(resource);\n if (!data) {\n return;\n }\n this._downloadedArrayBuffers.delete(resource);\n try {\n const gltf: THREE_ADDONS.GLTF = await loader.parseAsync(data, '');\n this._loadedThreeModels.set(resource, gltf);\n } catch (error) {\n logger.error(\n \"Can't fetch the 3D model file \" + resource.file + ', error: ' + error\n );\n }\n }\n\n async loadResource(resourceName: string): Promise<void> {\n const resource = this._resourceLoader.getResource(resourceName);\n if (!resource) {\n logger.warn(\n 'Unable to find texture for resource \"' + resourceName + '\".'\n );\n return;\n }\n const loader = this._loader;\n if (!loader) {\n return;\n }\n if (this._loadedThreeModels.get(resource)) {\n return;\n }\n const url = this._resourceLoader.getFullUrl(resource.file);\n try {\n const response = await fetch(url, {\n credentials: this._resourceLoader.checkIfCredentialsRequired(url)\n ? 'include'\n : 'omit',\n });\n if (!response.ok) {\n throw new Error('Network response was not ok');\n }\n const data = await response.arrayBuffer();\n this._downloadedArrayBuffers.set(resource, data);\n } catch (error) {\n logger.error(\n \"Can't fetch the 3D model file \" + resource.file + ', error: ' + error\n );\n }\n }\n\n /**\n * Return a 3D model.\n *\n * Caller should not modify the object but clone it.\n *\n * @param resourceName The name of the json resource.\n * @returns a 3D model if it exists.\n */\n getModel(resourceName: string): THREE_ADDONS.GLTF {\n return (\n this._loadedThreeModels.getFromName(resourceName) || this._invalidModel\n );\n }\n\n /**\n * To be called when the game is disposed.\n * Clear the models, resources loaded and destroy 3D models loaders in this manager.\n */\n dispose(): void {\n this._loadedThreeModels.clear();\n this._downloadedArrayBuffers.clear();\n this._loader = null;\n this._dracoLoader = null;\n\n if (this._invalidModel) {\n this._invalidModel.cameras = [];\n this._invalidModel.animations = [];\n this._invalidModel.scenes = [];\n this._invalidModel.userData = {};\n this._invalidModel.asset = {};\n this._invalidModel.scene.clear();\n }\n }\n }\n}\n"],
5
+ "mappings": "AAKA,GAAU,MAAV,UAAU,EAAV,CACE,KAAM,GAAS,GAAI,GAAK,OAAO,kBAEzB,EAAqC,CAAC,WAMrC,OAAqD,CAmB1D,YAAY,EAAqC,CAfzC,wBAAqB,GAAI,GAAK,cAC9B,6BAA0B,GAAI,GAAK,cAI3C,aAA0C,KAC1C,kBAAgD,KAY9C,GAFA,KAAK,gBAAkB,EAEnB,MAAO,QAAU,YAAa,CAChC,KAAK,QAAU,GAAI,cAAa,WAEhC,KAAK,aAAe,GAAI,cAAa,YACrC,KAAK,aAAa,eAAe,gCACjC,KAAK,QAAQ,eAAe,KAAK,cAMjC,KAAM,GAAQ,GAAI,OAAM,MACxB,EAAM,IACJ,GAAI,OAAM,KACR,GAAI,OAAM,YAAY,EAAG,EAAG,GAC5B,GAAI,OAAM,kBAAkB,CAAE,MAAO,cAGzC,KAAK,cAAgB,CACnB,MAAO,EACP,WAAY,GACZ,QAAS,GACT,OAAQ,GACR,MAAO,GACP,SAAU,GAEV,OAAQ,OAKd,kBAAmC,CACjC,MAAO,QAGH,iBAAgB,EAAqC,CACzD,KAAM,GAAW,KAAK,gBAAgB,YAAY,GAClD,GAAI,CAAC,EAAU,CACb,EAAO,KACL,wCAA0C,EAAe,MAE3D,OAEF,KAAM,GAAS,KAAK,QACpB,GAAI,CAAC,EACH,OAEF,KAAM,GAAO,KAAK,wBAAwB,IAAI,GAC9C,GAAI,EAAC,EAGL,MAAK,wBAAwB,OAAO,GACpC,GAAI,CACF,KAAM,GAA0B,KAAM,GAAO,WAAW,EAAM,IAC9D,KAAK,mBAAmB,IAAI,EAAU,SAC/B,EAAP,CACA,EAAO,MACL,iCAAmC,EAAS,KAAO,YAAc,UAKjE,cAAa,EAAqC,CACtD,KAAM,GAAW,KAAK,gBAAgB,YAAY,GAClD,GAAI,CAAC,EAAU,CACb,EAAO,KACL,wCAA0C,EAAe,MAE3D,OAMF,GAHI,CADW,KAAK,SAIhB,KAAK,mBAAmB,IAAI,GAC9B,OAEF,KAAM,GAAM,KAAK,gBAAgB,WAAW,EAAS,MACrD,GAAI,CACF,KAAM,GAAW,KAAM,OAAM,EAAK,CAChC,YAAa,KAAK,gBAAgB,2BAA2B,GACzD,UACA,SAEN,GAAI,CAAC,EAAS,GACZ,KAAM,IAAI,OAAM,+BAElB,KAAM,GAAO,KAAM,GAAS,cAC5B,KAAK,wBAAwB,IAAI,EAAU,SACpC,EAAP,CACA,EAAO,MACL,iCAAmC,EAAS,KAAO,YAAc,IAavE,SAAS,EAAyC,CAChD,MACE,MAAK,mBAAmB,YAAY,IAAiB,KAAK,cAQ9D,SAAgB,CACd,KAAK,mBAAmB,QACxB,KAAK,wBAAwB,QAC7B,KAAK,QAAU,KACf,KAAK,aAAe,KAEhB,KAAK,eACP,MAAK,cAAc,QAAU,GAC7B,KAAK,cAAc,WAAa,GAChC,KAAK,cAAc,OAAS,GAC5B,KAAK,cAAc,SAAW,GAC9B,KAAK,cAAc,MAAQ,GAC3B,KAAK,cAAc,MAAM,UApJxB,EAAM,mBATL",
6
6
  "names": []
7
7
  }
@@ -1,2 +1,2 @@
1
- var gdjs;(function(i){const c=new i.Logger("ResourceLoader"),R=(t,e,s)=>{if(t.startsWith("data:")||t.startsWith("blob:"))return t;const n=t.indexOf("?")===-1?"?":"&";return t+n+e+"="+s},_=t=>t.startsWith("https://project-resources.gdevelop.io/")||t.startsWith("https://project-resources-dev.gdevelop.io/"),g=20,f=5,d=3;class v{constructor(e){this.isFinished=!1;this.sceneName=e,this.onProgressCallbacks=new Array,this.onFinishCallbacks=new Array}registerCallback(e,s){if(this.isFinished){e();return}this.onFinishCallbacks.push(e),s&&this.onProgressCallbacks.push(s)}onProgress(e,s){for(const n of this.onProgressCallbacks)n(e,s)}onFinish(){this.isFinished=!0;for(const e of this.onFinishCallbacks)e()}}class w{constructor(e,s,n,r){this._sceneToLoadQueue=new Array;this._spineAtlasManager=null;this._spineManager=null;this.currentLoadingSceneName="";this.currentSceneLoadingProgress=0;this._isLoadingInForeground=!0;this._runtimeGame=e,this._resources=new Map,this._globalResources=n,this._sceneResources=new Map,this._sceneNamesToLoad=new Set,this._sceneNamesToMakeReady=new Set,this.setResources(s,n,r),this._imageManager=new i.ImageManager(this),this._soundManager=new i.SoundManager(this),this._fontManager=new i.FontManager(this),this._jsonManager=new i.JsonManager(this),this._bitmapFontManager=new i.BitmapFontManager(this,this._imageManager),this._model3DManager=new i.Model3DManager(this),i.SpineAtlasManager&&i.SpineManager&&(this._spineAtlasManager=new i.SpineAtlasManager(this,this._imageManager),this._spineManager=new i.SpineManager(this,this._spineAtlasManager));const a=[this._imageManager,this._soundManager,this._fontManager,this._jsonManager,this._bitmapFontManager,this._model3DManager];this._spineAtlasManager&&a.push(this._spineAtlasManager),this._spineManager&&a.push(this._spineManager),this._resourceManagersMap=new Map;for(const o of a)for(const u of o.getResourceKinds())this._resourceManagersMap.set(u,o)}getRuntimeGame(){return this._runtimeGame}setResources(e,s,n){this._globalResources=s,this._sceneResources.clear(),this._sceneNamesToLoad.clear(),this._sceneNamesToMakeReady.clear();for(const r of n)this._sceneResources.set(r.name,r.usedResources.map(a=>a.name)),this._sceneNamesToLoad.add(r.name),this._sceneNamesToMakeReady.add(r.name);this._sceneToLoadQueue.length=0;for(let r=n.length-1;r>=0;r--){const a=n[r];this._sceneToLoadQueue.push(new v(a.name))}this._resources.clear();for(const r of e)!r.file||this._resources.set(r.name,r)}async loadAllResources(e){let s=0;await h([...this._resources.values()],g,d,async n=>{await this._loadResource(n),await this._processResource(n),s++,e(s,this._resources.size)}),this._sceneNamesToLoad.clear(),this._sceneNamesToMakeReady.clear()}async loadGlobalAndFirstSceneResources(e,s){const n=this._sceneResources.get(e);if(!n){c.warn(`Can't load resource for unknown scene: "`+e+'".');return}let r=0;const a=[...this._globalResources,...n.values()];await h(a,g,d,async o=>{const u=this._resources.get(o);if(!u){c.warn('Unable to find resource "'+o+'".');return}await this._loadResource(u),await this._processResource(u),r++,s(r,a.length)}),this._setSceneAssetsLoaded(e),this._setSceneAssetsReady(e)}async loadAllSceneInBackground(){for(;this._sceneToLoadQueue.length>0;){const e=this._sceneToLoadQueue[this._sceneToLoadQueue.length-1];e!==void 0&&(this.currentLoadingSceneName=e.sceneName,this.areSceneAssetsLoaded(e.sceneName)?this._sceneToLoadQueue.pop():(await this._doLoadSceneResources(e.sceneName,async(s,n)=>e.onProgress(s,n)),this._sceneToLoadQueue.splice(this._sceneToLoadQueue.findIndex(s=>s===e),1),e.onFinish()))}this.currentLoadingSceneName=""}async _doLoadSceneResources(e,s){const n=this._sceneResources.get(e);if(!n){c.warn(`Can't load resource for unknown scene: "`+e+'".');return}let r=0;await h([...n.values()],this._isLoadingInForeground?g:f,d,async a=>{const o=this._resources.get(a);if(!o){c.warn('Unable to find resource "'+a+'".');return}await this._loadResource(o),r++,this.currentSceneLoadingProgress=r/this._resources.size,s&&await s(r,this._resources.size)}),this._setSceneAssetsLoaded(e)}async _loadResource(e){const s=this._resourceManagersMap.get(e.kind);if(!s){c.warn('Unknown resource kind: "'+e.kind+'" for: "'+e.name+'".');return}await s.loadResource(e.name)}async loadAndProcessSceneResources(e,s){if(this.areSceneAssetsReady(e))return;await this.loadSceneResources(e,s);const n=this._sceneResources.get(e);if(!n){c.warn(`Can't load resource for unknown scene: "`+e+'".');return}let r=0;for(const a of n){const o=this._resources.get(a);if(!o){c.warn('Unable to find resource "'+a+'".');continue}await this._processResource(o),r++,s&&await s(r,n.length)}this._setSceneAssetsReady(e)}async loadSceneResources(e,s){this._isLoadingInForeground=!0;const n=this._prioritizeScene(e);return new Promise((r,a)=>{if(!n){this._isLoadingInForeground=!1,r();return}n.registerCallback(()=>{this._isLoadingInForeground=!1,r()},s)})}_prioritizeScene(e){const s=this._sceneToLoadQueue.findIndex(r=>r.sceneName===e);if(s<0)return null;const n=this._sceneToLoadQueue[s];return this._sceneToLoadQueue.splice(s,1),this._sceneToLoadQueue.push(n),n}async _processResource(e){const s=this._resourceManagersMap.get(e.kind);if(!s){c.warn('Unknown resource kind: "'+e.kind+'" for: "'+e.name+'".');return}await s.processResource(e.name)}getSceneLoadingProgress(e){return e===this.currentLoadingSceneName?this.currentSceneLoadingProgress:this.areSceneAssetsLoaded(e)?1:0}areSceneAssetsLoaded(e){return!this._sceneNamesToLoad.has(e)}areSceneAssetsReady(e){return!this._sceneNamesToMakeReady.has(e)}_setSceneAssetsLoaded(e){this._sceneNamesToLoad.delete(e)}_setSceneAssetsReady(e){this._sceneNamesToMakeReady.delete(e)}getResource(e){return this._resources.get(e)||null}getFullUrl(e){const{gdevelopResourceToken:s}=this._runtimeGame._options;return!s||!_(e)?e:R(e,"gd_resource_token",encodeURIComponent(s))}checkIfCredentialsRequired(e){return this._runtimeGame._options.gdevelopResourceToken?!1:!!_(e)}getSoundManager(){return this._soundManager}getImageManager(){return this._imageManager}getFontManager(){return this._fontManager}getBitmapFontManager(){return this._bitmapFontManager}getJsonManager(){return this._jsonManager}getModel3DManager(){return this._model3DManager}getSpineManager(){return this._spineManager}getSpineAtlasManager(){return this._spineAtlasManager}}i.ResourceLoader=w;const m=(t,e,s)=>{const n=[],r=[];let a=0,o=0;return new Promise((u,y)=>{const p=()=>{if(t.length===0){u({results:n,errors:r});return}for(;a<e&&o<t.length;){const M=t[o++];a++,s(M).then(l=>n.push(l)).catch(l=>r.push({item:M,error:l})).finally(()=>{a--,o===t.length&&a===0?u({results:n,errors:r}):p()})}};p()})},h=async(t,e,s,n)=>{const r=await m(t,e,n);r.errors.length!==0&&c.warn("Some assets couldn't be downloaded. Trying again now.");for(let a=1;a<s&&r.errors.length!==0;a++){const o=await m(t,e,n);r.results.push.apply(r.results,o.results),r.errors=o.errors}return r}})(gdjs||(gdjs={}));
1
+ var gdjs;(function(i){const c=new i.Logger("ResourceLoader"),f=(t,e,s)=>{if(t.startsWith("data:")||t.startsWith("blob:"))return t;const n=t.indexOf("?")===-1?"?":"&";return t+n+e+"="+s},_=t=>t.startsWith("https://project-resources.gdevelop.io/")||t.startsWith("https://project-resources-dev.gdevelop.io/"),g=20,R=5,d=3;class v{constructor(e){this.isFinished=!1;this.sceneName=e,this.onProgressCallbacks=new Array,this.onFinishCallbacks=new Array}registerCallback(e,s){if(this.isFinished){e();return}this.onFinishCallbacks.push(e),s&&this.onProgressCallbacks.push(s)}onProgress(e,s){for(const n of this.onProgressCallbacks)n(e,s)}onFinish(){this.isFinished=!0;for(const e of this.onFinishCallbacks)e()}}class w{constructor(e,s,n,r){this._sceneToLoadQueue=new Array;this._spineAtlasManager=null;this._spineManager=null;this.currentLoadingSceneName="";this.currentSceneLoadingProgress=0;this._isLoadingInForeground=!0;this._runtimeGame=e,this._resources=new Map,this._globalResources=n,this._sceneResources=new Map,this._sceneNamesToLoad=new Set,this._sceneNamesToMakeReady=new Set,this.setResources(s,n,r),this._imageManager=new i.ImageManager(this),this._soundManager=new i.SoundManager(this),this._fontManager=new i.FontManager(this),this._jsonManager=new i.JsonManager(this),this._bitmapFontManager=new i.BitmapFontManager(this,this._imageManager),this._model3DManager=new i.Model3DManager(this),i.SpineAtlasManager&&i.SpineManager&&(this._spineAtlasManager=new i.SpineAtlasManager(this,this._imageManager),this._spineManager=new i.SpineManager(this,this._spineAtlasManager));const a=[this._imageManager,this._soundManager,this._fontManager,this._jsonManager,this._bitmapFontManager,this._model3DManager];this._spineAtlasManager&&a.push(this._spineAtlasManager),this._spineManager&&a.push(this._spineManager),this._resourceManagersMap=new Map;for(const o of a)for(const u of o.getResourceKinds())this._resourceManagersMap.set(u,o)}getRuntimeGame(){return this._runtimeGame}setResources(e,s,n){this._globalResources=s,this._sceneResources.clear(),this._sceneNamesToLoad.clear(),this._sceneNamesToMakeReady.clear();for(const r of n)this._sceneResources.set(r.name,r.usedResources.map(a=>a.name)),this._sceneNamesToLoad.add(r.name),this._sceneNamesToMakeReady.add(r.name);this._sceneToLoadQueue.length=0;for(let r=n.length-1;r>=0;r--){const a=n[r];this._sceneToLoadQueue.push(new v(a.name))}this._resources.clear();for(const r of e)!r.file||this._resources.set(r.name,r)}async loadAllResources(e){let s=0;await h([...this._resources.values()],g,d,async n=>{await this._loadResource(n),await this._processResource(n),s++,e(s,this._resources.size)}),this._sceneNamesToLoad.clear(),this._sceneNamesToMakeReady.clear()}async loadGlobalAndFirstSceneResources(e,s){const n=this._sceneResources.get(e);if(!n){c.warn(`Can't load resource for unknown scene: "`+e+'".');return}let r=0;const a=[...this._globalResources,...n.values()];await h(a,g,d,async o=>{const u=this._resources.get(o);if(!u){c.warn('Unable to find resource "'+o+'".');return}await this._loadResource(u),await this._processResource(u),r++,s(r,a.length)}),this._setSceneAssetsLoaded(e),this._setSceneAssetsReady(e)}async loadAllSceneInBackground(){for(;this._sceneToLoadQueue.length>0;){const e=this._sceneToLoadQueue[this._sceneToLoadQueue.length-1];e!==void 0&&(this.currentLoadingSceneName=e.sceneName,this.areSceneAssetsLoaded(e.sceneName)?this._sceneToLoadQueue.pop():(await this._doLoadSceneResources(e.sceneName,async(s,n)=>e.onProgress(s,n)),this._sceneToLoadQueue.splice(this._sceneToLoadQueue.findIndex(s=>s===e),1),e.onFinish()))}this.currentLoadingSceneName=""}async _doLoadSceneResources(e,s){const n=this._sceneResources.get(e);if(!n){c.warn(`Can't load resource for unknown scene: "`+e+'".');return}let r=0;await h([...n.values()],this._isLoadingInForeground?g:R,d,async a=>{const o=this._resources.get(a);if(!o){c.warn('Unable to find resource "'+a+'".');return}await this._loadResource(o),r++,this.currentSceneLoadingProgress=r/this._resources.size,s&&await s(r,this._resources.size)}),this._setSceneAssetsLoaded(e)}async _loadResource(e){const s=this._resourceManagersMap.get(e.kind);if(!s){c.warn('Unknown resource kind: "'+e.kind+'" for: "'+e.name+'".');return}await s.loadResource(e.name)}async loadAndProcessSceneResources(e,s){if(this.areSceneAssetsReady(e))return;await this.loadSceneResources(e,s);const n=this._sceneResources.get(e);if(!n){c.warn(`Can't load resource for unknown scene: "`+e+'".');return}let r=0;for(const a of n){const o=this._resources.get(a);if(!o){c.warn('Unable to find resource "'+a+'".');continue}await this._processResource(o),r++,s&&await s(r,n.length)}this._setSceneAssetsReady(e)}async loadSceneResources(e,s){this._isLoadingInForeground=!0;const n=this._prioritizeScene(e);return new Promise((r,a)=>{if(!n){this._isLoadingInForeground=!1,r();return}n.registerCallback(()=>{this._isLoadingInForeground=!1,r()},s)})}dispose(){for(const e of this._resourceManagersMap.values())e.dispose()}_prioritizeScene(e){const s=this._sceneToLoadQueue.findIndex(r=>r.sceneName===e);if(s<0)return null;const n=this._sceneToLoadQueue[s];return this._sceneToLoadQueue.splice(s,1),this._sceneToLoadQueue.push(n),n}async _processResource(e){const s=this._resourceManagersMap.get(e.kind);if(!s){c.warn('Unknown resource kind: "'+e.kind+'" for: "'+e.name+'".');return}await s.processResource(e.name)}getSceneLoadingProgress(e){return e===this.currentLoadingSceneName?this.currentSceneLoadingProgress:this.areSceneAssetsLoaded(e)?1:0}areSceneAssetsLoaded(e){return!this._sceneNamesToLoad.has(e)}areSceneAssetsReady(e){return!this._sceneNamesToMakeReady.has(e)}_setSceneAssetsLoaded(e){this._sceneNamesToLoad.delete(e)}_setSceneAssetsReady(e){this._sceneNamesToMakeReady.delete(e)}getResource(e){return this._resources.get(e)||null}getFullUrl(e){const{gdevelopResourceToken:s}=this._runtimeGame._options;return!s||!_(e)?e:f(e,"gd_resource_token",encodeURIComponent(s))}checkIfCredentialsRequired(e){return this._runtimeGame._options.gdevelopResourceToken?!1:!!_(e)}getSoundManager(){return this._soundManager}getImageManager(){return this._imageManager}getFontManager(){return this._fontManager}getBitmapFontManager(){return this._bitmapFontManager}getJsonManager(){return this._jsonManager}getModel3DManager(){return this._model3DManager}getSpineManager(){return this._spineManager}getSpineAtlasManager(){return this._spineAtlasManager}}i.ResourceLoader=w;const p=(t,e,s)=>{const n=[],r=[];let a=0,o=0;return new Promise((u,y)=>{const m=()=>{if(t.length===0){u({results:n,errors:r});return}for(;a<e&&o<t.length;){const M=t[o++];a++,s(M).then(l=>n.push(l)).catch(l=>r.push({item:M,error:l})).finally(()=>{a--,o===t.length&&a===0?u({results:n,errors:r}):m()})}};m()})},h=async(t,e,s,n)=>{const r=await p(t,e,n);r.errors.length!==0&&c.warn("Some assets couldn't be downloaded. Trying again now.");for(let a=1;a<s&&r.errors.length!==0;a++){const o=await p(t,e,n);r.results.push.apply(r.results,o.results),r.errors=o.errors}return r}})(gdjs||(gdjs={}));
2
2
  //# sourceMappingURL=ResourceLoader.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../GDevelop/GDJS/Runtime/ResourceLoader.ts"],
4
- "sourcesContent": ["/*\n * GDevelop JS Platform\n * Copyright 2013-2023 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('ResourceLoader');\n\n const addSearchParameterToUrl = (\n url: string,\n urlEncodedParameterName: string,\n urlEncodedValue: string\n ) => {\n if (url.startsWith('data:') || url.startsWith('blob:')) {\n // blob/data protocol does not support search parameters, which are useless anyway.\n return url;\n }\n\n const separator = url.indexOf('?') === -1 ? '?' : '&';\n return url + separator + urlEncodedParameterName + '=' + urlEncodedValue;\n };\n\n const checkIfIsGDevelopCloudBucketUrl = (url: string): boolean => {\n return (\n url.startsWith('https://project-resources.gdevelop.io/') ||\n url.startsWith('https://project-resources-dev.gdevelop.io/')\n );\n };\n\n const maxForegroundConcurrency = 20;\n const maxBackgroundConcurrency = 5;\n const maxAttempt = 3;\n\n /**\n * A task of pre-loading resources used by a scene.\n *\n * A Promise can't be used instead of this class because a Promise will start\n * as soon as possible. It would flood the server with downloading requests\n * and make impossible to finely tune in which order scenes are actually\n * downloaded.\n */\n class SceneLoadingTask {\n sceneName: string;\n private onProgressCallbacks: Array<(count: number, total: number) => void>;\n private onFinishCallbacks: Array<() => void>;\n private isFinished = false;\n\n constructor(sceneName: string) {\n this.sceneName = sceneName;\n this.onProgressCallbacks = new Array<\n (count: number, total: number) => void\n >();\n this.onFinishCallbacks = new Array<() => void>();\n }\n\n registerCallback(\n onFinish: () => void,\n onProgress?: (count: number, total: number) => void\n ) {\n if (this.isFinished) {\n onFinish();\n return;\n }\n this.onFinishCallbacks.push(onFinish);\n if (onProgress) {\n this.onProgressCallbacks.push(onProgress);\n }\n }\n\n onProgress(count: number, total: number) {\n for (const onProgress of this.onProgressCallbacks) {\n onProgress(count, total);\n }\n }\n\n onFinish() {\n this.isFinished = true;\n for (const onFinish of this.onFinishCallbacks) {\n onFinish();\n }\n }\n }\n\n /**\n * Pre-load resources of any kind needed for a game or a scene.\n */\n export class ResourceLoader {\n _runtimeGame: RuntimeGame;\n /**\n * All the resource of a game by resource name.\n */\n private _resources: Map<string, ResourceData>;\n /**\n * Resources needed for any scene. Typically, they are resources from\n * global objects.\n */\n private _globalResources: Array<string>;\n /**\n * Resources by scene names.\n */\n private _sceneResources: Map<string, Array<string>>;\n /**\n * Keep track of which scene whose resources has already be pre-loaded.\n */\n private _sceneNamesToLoad: Set<string>;\n /**\n * Keep track of which scene whose resources has already be loaded.\n */\n private _sceneNamesToMakeReady: Set<string>;\n /**\n * A queue of scenes whose resources are still to be pre-loaded.\n */\n private _sceneToLoadQueue: Array<SceneLoadingTask> = new Array<\n SceneLoadingTask\n >();\n /**\n * The resource managers that actually download and remember downloaded\n * content.\n */\n _resourceManagersMap: Map<ResourceKind, ResourceManager>;\n private _imageManager: ImageManager;\n private _soundManager: SoundManager;\n private _fontManager: FontManager;\n private _jsonManager: JsonManager;\n private _model3DManager: Model3DManager;\n private _bitmapFontManager: BitmapFontManager;\n private _spineAtlasManager: SpineAtlasManager | null = null;\n private _spineManager: SpineManager | null = null;\n\n /**\n * Only used by events.\n */\n private currentLoadingSceneName: string = '';\n /**\n * Only used by events.\n */\n private currentSceneLoadingProgress: float = 0;\n /**\n * It's set to `true` during intermediary loading screen to use a greater\n * concurrency as the game is paused and doesn't need bandwidth (for video\n * or music streaming or online multiplayer).\n */\n private _isLoadingInForeground = true;\n\n /**\n * @param runtimeGame The game.\n * @param resourceDataArray The resources data of the game.\n * @param globalResources The resources needed for any layer.\n * @param layoutDataArray The resources used by each layer.\n */\n constructor(\n runtimeGame: RuntimeGame,\n resourceDataArray: ResourceData[],\n globalResources: Array<string>,\n layoutDataArray: Array<LayoutData>\n ) {\n this._runtimeGame = runtimeGame;\n this._resources = new Map<string, ResourceData>();\n this._globalResources = globalResources;\n\n // These 3 attributes are filled by `setResources`.\n this._sceneResources = new Map<string, Array<string>>();\n this._sceneNamesToLoad = new Set<string>();\n this._sceneNamesToMakeReady = new Set<string>();\n this.setResources(resourceDataArray, globalResources, layoutDataArray);\n\n this._imageManager = new gdjs.ImageManager(this);\n this._soundManager = new gdjs.SoundManager(this);\n this._fontManager = new gdjs.FontManager(this);\n this._jsonManager = new gdjs.JsonManager(this);\n this._bitmapFontManager = new gdjs.BitmapFontManager(\n this,\n this._imageManager\n );\n this._model3DManager = new gdjs.Model3DManager(this);\n\n // add spine related managers only if spine extension is used\n if (gdjs.SpineAtlasManager && gdjs.SpineManager) {\n this._spineAtlasManager = new gdjs.SpineAtlasManager(\n this,\n this._imageManager\n );\n this._spineManager = new gdjs.SpineManager(\n this,\n this._spineAtlasManager\n );\n }\n\n const resourceManagers: Array<ResourceManager> = [\n this._imageManager,\n this._soundManager,\n this._fontManager,\n this._jsonManager,\n this._bitmapFontManager,\n this._model3DManager,\n ];\n\n if (this._spineAtlasManager)\n resourceManagers.push(this._spineAtlasManager);\n if (this._spineManager) resourceManagers.push(this._spineManager);\n\n this._resourceManagersMap = new Map<ResourceKind, ResourceManager>();\n for (const resourceManager of resourceManagers) {\n for (const resourceKind of resourceManager.getResourceKinds()) {\n this._resourceManagersMap.set(resourceKind, resourceManager);\n }\n }\n }\n\n /**\n * @returns the runtime game instance.\n */\n getRuntimeGame(): RuntimeGame {\n return this._runtimeGame;\n }\n\n /**\n * Update the resources data of the game. Useful for hot-reloading, should\n * not be used otherwise.\n */\n setResources(\n resourceDataArray: ResourceData[],\n globalResources: Array<string>,\n layoutDataArray: Array<LayoutData>\n ): void {\n this._globalResources = globalResources;\n\n this._sceneResources.clear();\n this._sceneNamesToLoad.clear();\n this._sceneNamesToMakeReady.clear();\n for (const layoutData of layoutDataArray) {\n this._sceneResources.set(\n layoutData.name,\n layoutData.usedResources.map((resource) => resource.name)\n );\n this._sceneNamesToLoad.add(layoutData.name);\n this._sceneNamesToMakeReady.add(layoutData.name);\n }\n // TODO Clearing the queue doesn't abort the running task, but it should\n // not matter as resource loading is really fast in preview mode.\n this._sceneToLoadQueue.length = 0;\n for (let index = layoutDataArray.length - 1; index >= 0; index--) {\n const layoutData = layoutDataArray[index];\n this._sceneToLoadQueue.push(new SceneLoadingTask(layoutData.name));\n }\n\n this._resources.clear();\n for (const resourceData of resourceDataArray) {\n if (!resourceData.file) {\n // Empty string or missing `file` field: not a valid resource, let's entirely ignore it.\n // Otherwise, this can confuse some loaders that will consider an empty string different\n // than a file that happen not to fail to load.\n continue;\n }\n\n this._resources.set(resourceData.name, resourceData);\n }\n }\n\n async loadAllResources(\n onProgress: (loadingCount: integer, totalCount: integer) => void\n ): Promise<void> {\n let loadedCount = 0;\n await processAndRetryIfNeededWithPromisePool(\n [...this._resources.values()],\n maxForegroundConcurrency,\n maxAttempt,\n async (resource) => {\n await this._loadResource(resource);\n await this._processResource(resource);\n loadedCount++;\n onProgress(loadedCount, this._resources.size);\n }\n );\n this._sceneNamesToLoad.clear();\n this._sceneNamesToMakeReady.clear();\n }\n\n /**\n * Load the resources that are needed to launch the first scene.\n */\n async loadGlobalAndFirstSceneResources(\n firstSceneName: string,\n onProgress: (count: number, total: number) => void\n ): Promise<void> {\n const sceneResources = this._sceneResources.get(firstSceneName);\n if (!sceneResources) {\n logger.warn(\n 'Can\\'t load resource for unknown scene: \"' + firstSceneName + '\".'\n );\n return;\n }\n let loadedCount = 0;\n const resources = [...this._globalResources, ...sceneResources.values()];\n await processAndRetryIfNeededWithPromisePool(\n resources,\n maxForegroundConcurrency,\n maxAttempt,\n async (resourceName) => {\n const resource = this._resources.get(resourceName);\n if (!resource) {\n logger.warn('Unable to find resource \"' + resourceName + '\".');\n return;\n }\n await this._loadResource(resource);\n await this._processResource(resource);\n loadedCount++;\n onProgress(loadedCount, resources.length);\n }\n );\n this._setSceneAssetsLoaded(firstSceneName);\n this._setSceneAssetsReady(firstSceneName);\n }\n\n /**\n * Load each scene in order.\n *\n * This is done in background to try to avoid loading screens when changing\n * scenes.\n */\n async loadAllSceneInBackground(): Promise<void> {\n while (this._sceneToLoadQueue.length > 0) {\n const task = this._sceneToLoadQueue[this._sceneToLoadQueue.length - 1];\n if (task === undefined) {\n continue;\n }\n this.currentLoadingSceneName = task.sceneName;\n if (!this.areSceneAssetsLoaded(task.sceneName)) {\n await this._doLoadSceneResources(\n task.sceneName,\n async (count, total) => task.onProgress(count, total)\n );\n // A scene may have been moved last while awaiting resources to be\n // downloaded (see _prioritizeScene).\n this._sceneToLoadQueue.splice(\n this._sceneToLoadQueue.findIndex((element) => element === task),\n 1\n );\n task.onFinish();\n } else {\n this._sceneToLoadQueue.pop();\n }\n }\n this.currentLoadingSceneName = '';\n }\n\n private async _doLoadSceneResources(\n sceneName: string,\n onProgress?: (count: number, total: number) => Promise<void>\n ): Promise<void> {\n const sceneResources = this._sceneResources.get(sceneName);\n if (!sceneResources) {\n logger.warn(\n 'Can\\'t load resource for unknown scene: \"' + sceneName + '\".'\n );\n return;\n }\n let loadedCount = 0;\n await processAndRetryIfNeededWithPromisePool(\n [...sceneResources.values()],\n this._isLoadingInForeground\n ? maxForegroundConcurrency\n : maxBackgroundConcurrency,\n maxAttempt,\n async (resourceName) => {\n const resource = this._resources.get(resourceName);\n if (!resource) {\n logger.warn('Unable to find resource \"' + resourceName + '\".');\n return;\n }\n await this._loadResource(resource);\n loadedCount++;\n this.currentSceneLoadingProgress = loadedCount / this._resources.size;\n onProgress && (await onProgress(loadedCount, this._resources.size));\n }\n );\n this._setSceneAssetsLoaded(sceneName);\n }\n\n private async _loadResource(resource: ResourceData): Promise<void> {\n const resourceManager = this._resourceManagersMap.get(resource.kind);\n if (!resourceManager) {\n logger.warn(\n 'Unknown resource kind: \"' +\n resource.kind +\n '\" for: \"' +\n resource.name +\n '\".'\n );\n return;\n }\n await resourceManager.loadResource(resource.name);\n }\n\n /**\n * Load and process a scene that is needed right away.\n *\n * The renderer will show a loading screen while its done.\n */\n async loadAndProcessSceneResources(\n sceneName: string,\n onProgress?: (count: number, total: number) => Promise<void>\n ): Promise<void> {\n if (this.areSceneAssetsReady(sceneName)) {\n return;\n }\n await this.loadSceneResources(sceneName, onProgress);\n\n const sceneResources = this._sceneResources.get(sceneName);\n if (!sceneResources) {\n logger.warn(\n 'Can\\'t load resource for unknown scene: \"' + sceneName + '\".'\n );\n return;\n }\n\n let parsedCount = 0;\n for (const resourceName of sceneResources) {\n const resource = this._resources.get(resourceName);\n if (!resource) {\n logger.warn('Unable to find resource \"' + resourceName + '\".');\n continue;\n }\n await this._processResource(resource);\n parsedCount++;\n onProgress && (await onProgress(parsedCount, sceneResources.length));\n }\n this._setSceneAssetsReady(sceneName);\n }\n\n /**\n * Load a scene resources without parsing them.\n *\n * When another scene resources are loading in background, it waits for\n * all its resources to be loaded before loading resources of the given\n * scene.\n */\n async loadSceneResources(\n sceneName: string,\n onProgress?: (count: number, total: number) => void\n ): Promise<void> {\n this._isLoadingInForeground = true;\n const task = this._prioritizeScene(sceneName);\n return new Promise<void>((resolve, reject) => {\n if (!task) {\n this._isLoadingInForeground = false;\n resolve();\n return;\n }\n task.registerCallback(() => {\n this._isLoadingInForeground = false;\n resolve();\n }, onProgress);\n });\n }\n\n /**\n * Put a given scene at the end of the queue.\n *\n * When the scene that is currently loading in background is done,\n * this scene will be the next to be loaded.\n */\n private _prioritizeScene(sceneName: string): SceneLoadingTask | null {\n const taskIndex = this._sceneToLoadQueue.findIndex(\n (task) => task.sceneName === sceneName\n );\n if (taskIndex < 0) {\n // The scene is already loaded.\n return null;\n }\n const task = this._sceneToLoadQueue[taskIndex];\n this._sceneToLoadQueue.splice(taskIndex, 1);\n this._sceneToLoadQueue.push(task);\n return task;\n }\n\n private async _processResource(resource: ResourceData): Promise<void> {\n const resourceManager = this._resourceManagersMap.get(resource.kind);\n if (!resourceManager) {\n logger.warn(\n 'Unknown resource kind: \"' +\n resource.kind +\n '\" for: \"' +\n resource.name +\n '\".'\n );\n return;\n }\n await resourceManager.processResource(resource.name);\n }\n\n getSceneLoadingProgress(sceneName: string): float {\n return sceneName === this.currentLoadingSceneName\n ? this.currentSceneLoadingProgress\n : this.areSceneAssetsLoaded(sceneName)\n ? 1\n : 0;\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._sceneNamesToLoad.has(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._sceneNamesToMakeReady.has(sceneName);\n }\n\n private _setSceneAssetsLoaded(sceneName: string): void {\n this._sceneNamesToLoad.delete(sceneName);\n }\n\n private _setSceneAssetsReady(sceneName: string): void {\n this._sceneNamesToMakeReady.delete(sceneName);\n }\n\n getResource(resourceName: string): ResourceData | null {\n return this._resources.get(resourceName) || null;\n }\n\n // Helper methods used when resources are loaded from an URL.\n\n /**\n * Complete the given URL with any specific parameter required to access\n * the resource (this can be for example a token needed to access the resource).\n */\n getFullUrl(url: string) {\n const { gdevelopResourceToken } = this._runtimeGame._options;\n if (!gdevelopResourceToken) return url;\n\n if (!checkIfIsGDevelopCloudBucketUrl(url)) return url;\n\n return addSearchParameterToUrl(\n url,\n 'gd_resource_token',\n encodeURIComponent(gdevelopResourceToken)\n );\n }\n\n /**\n * Return true if the specified URL must be loaded with cookies (\"credentials\")\n * sent to grant access to them.\n */\n checkIfCredentialsRequired(url: string) {\n if (this._runtimeGame._options.gdevelopResourceToken) return false;\n\n // Any resource stored on the GDevelop Cloud buckets needs the \"credentials\" of the user,\n // i.e: its gdevelop.io cookie, to be passed.\n // Note that this is only useful during previews.\n if (checkIfIsGDevelopCloudBucketUrl(url)) return true;\n\n // For other resources, use the default way of loading resources (\"anonymous\" or \"same-site\").\n return false;\n }\n\n /**\n * Get the gdjs.SoundManager of the RuntimeGame.\n * @return The sound manager.\n */\n getSoundManager(): gdjs.HowlerSoundManager {\n return this._soundManager;\n }\n\n /**\n * Get the gdjs.ImageManager of the RuntimeGame.\n * @return The image manager.\n */\n getImageManager(): gdjs.PixiImageManager {\n return this._imageManager;\n }\n\n /**\n * Get the gdjs.FontManager of the RuntimeGame.\n * @return The font manager.\n */\n getFontManager(): gdjs.FontFaceObserverFontManager {\n return this._fontManager;\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._bitmapFontManager;\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._jsonManager;\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._model3DManager;\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._spineManager;\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._spineAtlasManager;\n }\n }\n\n type PromiseError<T> = { item: T; error: Error };\n\n type PromisePoolOutput<T, U> = {\n results: Array<U>;\n errors: Array<PromiseError<T>>;\n };\n\n const processWithPromisePool = <T, U>(\n items: Array<T>,\n maxConcurrency: number,\n asyncFunction: (item: T) => Promise<U>\n ): Promise<PromisePoolOutput<T, U>> => {\n const results: Array<U> = [];\n const errors: Array<PromiseError<T>> = [];\n let activePromises = 0;\n let index = 0;\n\n return new Promise((resolve, reject) => {\n const executeNext = () => {\n if (items.length === 0) {\n resolve({ results, errors });\n return;\n }\n while (activePromises < maxConcurrency && index < items.length) {\n const item = items[index++];\n activePromises++;\n\n asyncFunction(item)\n .then((result) => results.push(result))\n .catch((error) => errors.push({ item, error }))\n .finally(() => {\n activePromises--;\n if (index === items.length && activePromises === 0) {\n resolve({ results, errors });\n } else {\n executeNext();\n }\n });\n }\n };\n\n executeNext();\n });\n };\n\n const processAndRetryIfNeededWithPromisePool = async <T, U>(\n items: Array<T>,\n maxConcurrency: number,\n maxAttempt: number,\n asyncFunction: (item: T) => Promise<U>\n ): Promise<PromisePoolOutput<T, U>> => {\n const output = await processWithPromisePool<T, U>(\n items,\n maxConcurrency,\n asyncFunction\n );\n if (output.errors.length !== 0) {\n logger.warn(\"Some assets couldn't be downloaded. Trying again now.\");\n }\n for (\n let attempt = 1;\n attempt < maxAttempt && output.errors.length !== 0;\n attempt++\n ) {\n const retryOutput = await processWithPromisePool<T, U>(\n items,\n maxConcurrency,\n asyncFunction\n );\n output.results.push.apply(output.results, retryOutput.results);\n output.errors = retryOutput.errors;\n }\n return output;\n };\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/*\n * GDevelop JS Platform\n * Copyright 2013-2023 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('ResourceLoader');\n\n const addSearchParameterToUrl = (\n url: string,\n urlEncodedParameterName: string,\n urlEncodedValue: string\n ) => {\n if (url.startsWith('data:') || url.startsWith('blob:')) {\n // blob/data protocol does not support search parameters, which are useless anyway.\n return url;\n }\n\n const separator = url.indexOf('?') === -1 ? '?' : '&';\n return url + separator + urlEncodedParameterName + '=' + urlEncodedValue;\n };\n\n const checkIfIsGDevelopCloudBucketUrl = (url: string): boolean => {\n return (\n url.startsWith('https://project-resources.gdevelop.io/') ||\n url.startsWith('https://project-resources-dev.gdevelop.io/')\n );\n };\n\n const maxForegroundConcurrency = 20;\n const maxBackgroundConcurrency = 5;\n const maxAttempt = 3;\n\n /**\n * A task of pre-loading resources used by a scene.\n *\n * A Promise can't be used instead of this class because a Promise will start\n * as soon as possible. It would flood the server with downloading requests\n * and make impossible to finely tune in which order scenes are actually\n * downloaded.\n */\n class SceneLoadingTask {\n sceneName: string;\n private onProgressCallbacks: Array<(count: number, total: number) => void>;\n private onFinishCallbacks: Array<() => void>;\n private isFinished = false;\n\n constructor(sceneName: string) {\n this.sceneName = sceneName;\n this.onProgressCallbacks = new Array<\n (count: number, total: number) => void\n >();\n this.onFinishCallbacks = new Array<() => void>();\n }\n\n registerCallback(\n onFinish: () => void,\n onProgress?: (count: number, total: number) => void\n ) {\n if (this.isFinished) {\n onFinish();\n return;\n }\n this.onFinishCallbacks.push(onFinish);\n if (onProgress) {\n this.onProgressCallbacks.push(onProgress);\n }\n }\n\n onProgress(count: number, total: number) {\n for (const onProgress of this.onProgressCallbacks) {\n onProgress(count, total);\n }\n }\n\n onFinish() {\n this.isFinished = true;\n for (const onFinish of this.onFinishCallbacks) {\n onFinish();\n }\n }\n }\n\n /**\n * Pre-load resources of any kind needed for a game or a scene.\n */\n export class ResourceLoader {\n _runtimeGame: RuntimeGame;\n /**\n * All the resource of a game by resource name.\n */\n private _resources: Map<string, ResourceData>;\n /**\n * Resources needed for any scene. Typically, they are resources from\n * global objects.\n */\n private _globalResources: Array<string>;\n /**\n * Resources by scene names.\n */\n private _sceneResources: Map<string, Array<string>>;\n /**\n * Keep track of which scene whose resources has already be pre-loaded.\n */\n private _sceneNamesToLoad: Set<string>;\n /**\n * Keep track of which scene whose resources has already be loaded.\n */\n private _sceneNamesToMakeReady: Set<string>;\n /**\n * A queue of scenes whose resources are still to be pre-loaded.\n */\n private _sceneToLoadQueue: Array<SceneLoadingTask> = new Array<\n SceneLoadingTask\n >();\n /**\n * The resource managers that actually download and remember downloaded\n * content.\n */\n _resourceManagersMap: Map<ResourceKind, ResourceManager>;\n private _imageManager: ImageManager;\n private _soundManager: SoundManager;\n private _fontManager: FontManager;\n private _jsonManager: JsonManager;\n private _model3DManager: Model3DManager;\n private _bitmapFontManager: BitmapFontManager;\n private _spineAtlasManager: SpineAtlasManager | null = null;\n private _spineManager: SpineManager | null = null;\n\n /**\n * Only used by events.\n */\n private currentLoadingSceneName: string = '';\n /**\n * Only used by events.\n */\n private currentSceneLoadingProgress: float = 0;\n /**\n * It's set to `true` during intermediary loading screen to use a greater\n * concurrency as the game is paused and doesn't need bandwidth (for video\n * or music streaming or online multiplayer).\n */\n private _isLoadingInForeground = true;\n\n /**\n * @param runtimeGame The game.\n * @param resourceDataArray The resources data of the game.\n * @param globalResources The resources needed for any layer.\n * @param layoutDataArray The resources used by each layer.\n */\n constructor(\n runtimeGame: RuntimeGame,\n resourceDataArray: ResourceData[],\n globalResources: Array<string>,\n layoutDataArray: Array<LayoutData>\n ) {\n this._runtimeGame = runtimeGame;\n this._resources = new Map<string, ResourceData>();\n this._globalResources = globalResources;\n\n // These 3 attributes are filled by `setResources`.\n this._sceneResources = new Map<string, Array<string>>();\n this._sceneNamesToLoad = new Set<string>();\n this._sceneNamesToMakeReady = new Set<string>();\n this.setResources(resourceDataArray, globalResources, layoutDataArray);\n\n this._imageManager = new gdjs.ImageManager(this);\n this._soundManager = new gdjs.SoundManager(this);\n this._fontManager = new gdjs.FontManager(this);\n this._jsonManager = new gdjs.JsonManager(this);\n this._bitmapFontManager = new gdjs.BitmapFontManager(\n this,\n this._imageManager\n );\n this._model3DManager = new gdjs.Model3DManager(this);\n\n // add spine related managers only if spine extension is used\n if (gdjs.SpineAtlasManager && gdjs.SpineManager) {\n this._spineAtlasManager = new gdjs.SpineAtlasManager(\n this,\n this._imageManager\n );\n this._spineManager = new gdjs.SpineManager(\n this,\n this._spineAtlasManager\n );\n }\n\n const resourceManagers: Array<ResourceManager> = [\n this._imageManager,\n this._soundManager,\n this._fontManager,\n this._jsonManager,\n this._bitmapFontManager,\n this._model3DManager,\n ];\n\n if (this._spineAtlasManager)\n resourceManagers.push(this._spineAtlasManager);\n if (this._spineManager) resourceManagers.push(this._spineManager);\n\n this._resourceManagersMap = new Map<ResourceKind, ResourceManager>();\n for (const resourceManager of resourceManagers) {\n for (const resourceKind of resourceManager.getResourceKinds()) {\n this._resourceManagersMap.set(resourceKind, resourceManager);\n }\n }\n }\n\n /**\n * @returns the runtime game instance.\n */\n getRuntimeGame(): RuntimeGame {\n return this._runtimeGame;\n }\n\n /**\n * Update the resources data of the game. Useful for hot-reloading, should\n * not be used otherwise.\n */\n setResources(\n resourceDataArray: ResourceData[],\n globalResources: Array<string>,\n layoutDataArray: Array<LayoutData>\n ): void {\n this._globalResources = globalResources;\n\n this._sceneResources.clear();\n this._sceneNamesToLoad.clear();\n this._sceneNamesToMakeReady.clear();\n for (const layoutData of layoutDataArray) {\n this._sceneResources.set(\n layoutData.name,\n layoutData.usedResources.map((resource) => resource.name)\n );\n this._sceneNamesToLoad.add(layoutData.name);\n this._sceneNamesToMakeReady.add(layoutData.name);\n }\n // TODO Clearing the queue doesn't abort the running task, but it should\n // not matter as resource loading is really fast in preview mode.\n this._sceneToLoadQueue.length = 0;\n for (let index = layoutDataArray.length - 1; index >= 0; index--) {\n const layoutData = layoutDataArray[index];\n this._sceneToLoadQueue.push(new SceneLoadingTask(layoutData.name));\n }\n\n this._resources.clear();\n for (const resourceData of resourceDataArray) {\n if (!resourceData.file) {\n // Empty string or missing `file` field: not a valid resource, let's entirely ignore it.\n // Otherwise, this can confuse some loaders that will consider an empty string different\n // than a file that happen not to fail to load.\n continue;\n }\n\n this._resources.set(resourceData.name, resourceData);\n }\n }\n\n async loadAllResources(\n onProgress: (loadingCount: integer, totalCount: integer) => void\n ): Promise<void> {\n let loadedCount = 0;\n await processAndRetryIfNeededWithPromisePool(\n [...this._resources.values()],\n maxForegroundConcurrency,\n maxAttempt,\n async (resource) => {\n await this._loadResource(resource);\n await this._processResource(resource);\n loadedCount++;\n onProgress(loadedCount, this._resources.size);\n }\n );\n this._sceneNamesToLoad.clear();\n this._sceneNamesToMakeReady.clear();\n }\n\n /**\n * Load the resources that are needed to launch the first scene.\n */\n async loadGlobalAndFirstSceneResources(\n firstSceneName: string,\n onProgress: (count: number, total: number) => void\n ): Promise<void> {\n const sceneResources = this._sceneResources.get(firstSceneName);\n if (!sceneResources) {\n logger.warn(\n 'Can\\'t load resource for unknown scene: \"' + firstSceneName + '\".'\n );\n return;\n }\n let loadedCount = 0;\n const resources = [...this._globalResources, ...sceneResources.values()];\n await processAndRetryIfNeededWithPromisePool(\n resources,\n maxForegroundConcurrency,\n maxAttempt,\n async (resourceName) => {\n const resource = this._resources.get(resourceName);\n if (!resource) {\n logger.warn('Unable to find resource \"' + resourceName + '\".');\n return;\n }\n await this._loadResource(resource);\n await this._processResource(resource);\n loadedCount++;\n onProgress(loadedCount, resources.length);\n }\n );\n this._setSceneAssetsLoaded(firstSceneName);\n this._setSceneAssetsReady(firstSceneName);\n }\n\n /**\n * Load each scene in order.\n *\n * This is done in background to try to avoid loading screens when changing\n * scenes.\n */\n async loadAllSceneInBackground(): Promise<void> {\n while (this._sceneToLoadQueue.length > 0) {\n const task = this._sceneToLoadQueue[this._sceneToLoadQueue.length - 1];\n if (task === undefined) {\n continue;\n }\n this.currentLoadingSceneName = task.sceneName;\n if (!this.areSceneAssetsLoaded(task.sceneName)) {\n await this._doLoadSceneResources(\n task.sceneName,\n async (count, total) => task.onProgress(count, total)\n );\n // A scene may have been moved last while awaiting resources to be\n // downloaded (see _prioritizeScene).\n this._sceneToLoadQueue.splice(\n this._sceneToLoadQueue.findIndex((element) => element === task),\n 1\n );\n task.onFinish();\n } else {\n this._sceneToLoadQueue.pop();\n }\n }\n this.currentLoadingSceneName = '';\n }\n\n private async _doLoadSceneResources(\n sceneName: string,\n onProgress?: (count: number, total: number) => Promise<void>\n ): Promise<void> {\n const sceneResources = this._sceneResources.get(sceneName);\n if (!sceneResources) {\n logger.warn(\n 'Can\\'t load resource for unknown scene: \"' + sceneName + '\".'\n );\n return;\n }\n let loadedCount = 0;\n await processAndRetryIfNeededWithPromisePool(\n [...sceneResources.values()],\n this._isLoadingInForeground\n ? maxForegroundConcurrency\n : maxBackgroundConcurrency,\n maxAttempt,\n async (resourceName) => {\n const resource = this._resources.get(resourceName);\n if (!resource) {\n logger.warn('Unable to find resource \"' + resourceName + '\".');\n return;\n }\n await this._loadResource(resource);\n loadedCount++;\n this.currentSceneLoadingProgress = loadedCount / this._resources.size;\n onProgress && (await onProgress(loadedCount, this._resources.size));\n }\n );\n this._setSceneAssetsLoaded(sceneName);\n }\n\n private async _loadResource(resource: ResourceData): Promise<void> {\n const resourceManager = this._resourceManagersMap.get(resource.kind);\n if (!resourceManager) {\n logger.warn(\n 'Unknown resource kind: \"' +\n resource.kind +\n '\" for: \"' +\n resource.name +\n '\".'\n );\n return;\n }\n await resourceManager.loadResource(resource.name);\n }\n\n /**\n * Load and process a scene that is needed right away.\n *\n * The renderer will show a loading screen while its done.\n */\n async loadAndProcessSceneResources(\n sceneName: string,\n onProgress?: (count: number, total: number) => Promise<void>\n ): Promise<void> {\n if (this.areSceneAssetsReady(sceneName)) {\n return;\n }\n await this.loadSceneResources(sceneName, onProgress);\n\n const sceneResources = this._sceneResources.get(sceneName);\n if (!sceneResources) {\n logger.warn(\n 'Can\\'t load resource for unknown scene: \"' + sceneName + '\".'\n );\n return;\n }\n\n let parsedCount = 0;\n for (const resourceName of sceneResources) {\n const resource = this._resources.get(resourceName);\n if (!resource) {\n logger.warn('Unable to find resource \"' + resourceName + '\".');\n continue;\n }\n await this._processResource(resource);\n parsedCount++;\n onProgress && (await onProgress(parsedCount, sceneResources.length));\n }\n this._setSceneAssetsReady(sceneName);\n }\n\n /**\n * Load a scene resources without parsing them.\n *\n * When another scene resources are loading in background, it waits for\n * all its resources to be loaded before loading resources of the given\n * scene.\n */\n async loadSceneResources(\n sceneName: string,\n onProgress?: (count: number, total: number) => void\n ): Promise<void> {\n this._isLoadingInForeground = true;\n const task = this._prioritizeScene(sceneName);\n return new Promise<void>((resolve, reject) => {\n if (!task) {\n this._isLoadingInForeground = false;\n resolve();\n return;\n }\n task.registerCallback(() => {\n this._isLoadingInForeground = false;\n resolve();\n }, onProgress);\n });\n }\n\n /**\n * To be called when the game is disposed.\n * Dispose all the resource managers.\n */\n dispose(): void {\n for (const resourceManager of this._resourceManagersMap.values()) {\n resourceManager.dispose();\n }\n }\n\n /**\n * Put a given scene at the end of the queue.\n *\n * When the scene that is currently loading in background is done,\n * this scene will be the next to be loaded.\n */\n private _prioritizeScene(sceneName: string): SceneLoadingTask | null {\n const taskIndex = this._sceneToLoadQueue.findIndex(\n (task) => task.sceneName === sceneName\n );\n if (taskIndex < 0) {\n // The scene is already loaded.\n return null;\n }\n const task = this._sceneToLoadQueue[taskIndex];\n this._sceneToLoadQueue.splice(taskIndex, 1);\n this._sceneToLoadQueue.push(task);\n return task;\n }\n\n private async _processResource(resource: ResourceData): Promise<void> {\n const resourceManager = this._resourceManagersMap.get(resource.kind);\n if (!resourceManager) {\n logger.warn(\n 'Unknown resource kind: \"' +\n resource.kind +\n '\" for: \"' +\n resource.name +\n '\".'\n );\n return;\n }\n await resourceManager.processResource(resource.name);\n }\n\n getSceneLoadingProgress(sceneName: string): float {\n return sceneName === this.currentLoadingSceneName\n ? this.currentSceneLoadingProgress\n : this.areSceneAssetsLoaded(sceneName)\n ? 1\n : 0;\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._sceneNamesToLoad.has(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._sceneNamesToMakeReady.has(sceneName);\n }\n\n private _setSceneAssetsLoaded(sceneName: string): void {\n this._sceneNamesToLoad.delete(sceneName);\n }\n\n private _setSceneAssetsReady(sceneName: string): void {\n this._sceneNamesToMakeReady.delete(sceneName);\n }\n\n getResource(resourceName: string): ResourceData | null {\n return this._resources.get(resourceName) || null;\n }\n\n // Helper methods used when resources are loaded from an URL.\n\n /**\n * Complete the given URL with any specific parameter required to access\n * the resource (this can be for example a token needed to access the resource).\n */\n getFullUrl(url: string) {\n const { gdevelopResourceToken } = this._runtimeGame._options;\n if (!gdevelopResourceToken) return url;\n\n if (!checkIfIsGDevelopCloudBucketUrl(url)) return url;\n\n return addSearchParameterToUrl(\n url,\n 'gd_resource_token',\n encodeURIComponent(gdevelopResourceToken)\n );\n }\n\n /**\n * Return true if the specified URL must be loaded with cookies (\"credentials\")\n * sent to grant access to them.\n */\n checkIfCredentialsRequired(url: string) {\n if (this._runtimeGame._options.gdevelopResourceToken) return false;\n\n // Any resource stored on the GDevelop Cloud buckets needs the \"credentials\" of the user,\n // i.e: its gdevelop.io cookie, to be passed.\n // Note that this is only useful during previews.\n if (checkIfIsGDevelopCloudBucketUrl(url)) return true;\n\n // For other resources, use the default way of loading resources (\"anonymous\" or \"same-site\").\n return false;\n }\n\n /**\n * Get the gdjs.SoundManager of the RuntimeGame.\n * @return The sound manager.\n */\n getSoundManager(): gdjs.HowlerSoundManager {\n return this._soundManager;\n }\n\n /**\n * Get the gdjs.ImageManager of the RuntimeGame.\n * @return The image manager.\n */\n getImageManager(): gdjs.PixiImageManager {\n return this._imageManager;\n }\n\n /**\n * Get the gdjs.FontManager of the RuntimeGame.\n * @return The font manager.\n */\n getFontManager(): gdjs.FontFaceObserverFontManager {\n return this._fontManager;\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._bitmapFontManager;\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._jsonManager;\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._model3DManager;\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._spineManager;\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._spineAtlasManager;\n }\n }\n\n type PromiseError<T> = { item: T; error: Error };\n\n type PromisePoolOutput<T, U> = {\n results: Array<U>;\n errors: Array<PromiseError<T>>;\n };\n\n const processWithPromisePool = <T, U>(\n items: Array<T>,\n maxConcurrency: number,\n asyncFunction: (item: T) => Promise<U>\n ): Promise<PromisePoolOutput<T, U>> => {\n const results: Array<U> = [];\n const errors: Array<PromiseError<T>> = [];\n let activePromises = 0;\n let index = 0;\n\n return new Promise((resolve, reject) => {\n const executeNext = () => {\n if (items.length === 0) {\n resolve({ results, errors });\n return;\n }\n while (activePromises < maxConcurrency && index < items.length) {\n const item = items[index++];\n activePromises++;\n\n asyncFunction(item)\n .then((result) => results.push(result))\n .catch((error) => errors.push({ item, error }))\n .finally(() => {\n activePromises--;\n if (index === items.length && activePromises === 0) {\n resolve({ results, errors });\n } else {\n executeNext();\n }\n });\n }\n };\n\n executeNext();\n });\n };\n\n const processAndRetryIfNeededWithPromisePool = async <T, U>(\n items: Array<T>,\n maxConcurrency: number,\n maxAttempt: number,\n asyncFunction: (item: T) => Promise<U>\n ): Promise<PromisePoolOutput<T, U>> => {\n const output = await processWithPromisePool<T, U>(\n items,\n maxConcurrency,\n asyncFunction\n );\n if (output.errors.length !== 0) {\n logger.warn(\"Some assets couldn't be downloaded. Trying again now.\");\n }\n for (\n let attempt = 1;\n attempt < maxAttempt && output.errors.length !== 0;\n attempt++\n ) {\n const retryOutput = await processWithPromisePool<T, U>(\n items,\n maxConcurrency,\n asyncFunction\n );\n output.results.push.apply(output.results, retryOutput.results);\n output.errors = retryOutput.errors;\n }\n return output;\n };\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -0,0 +1,2 @@
1
+ var gdjs;(function(i){const a=s=>{const e=atob(s.split(",")[1]),t=s.split(",")[0].split(":")[1].split(";")[0],n=new Uint8Array(e.length);for(let r=0;r<e.length;r++)n[r]=e.charCodeAt(r);return new Blob([n],{type:t})};class o{constructor(e,t){this._gameRenderer=e,this._captureOptions=t}setupCaptureOptions(e){if(!(!e||!this._captureOptions.screenshots))for(const t of this._captureOptions.screenshots)setTimeout(async()=>{await this.takeAndUploadScreenshot(t.signedUrl)},t.delayTimeInSeconds)}async takeAndUploadScreenshot(e){const t=this._gameRenderer.getCanvas();if(t)try{const n=t.toDataURL("image/png"),r=a(n);await fetch(e,{method:"PUT",body:r,headers:{"Content-Type":"image/png"}})}catch(n){console.error("Error while uploading screenshot:",n)}}}i.CaptureManager=o})(gdjs||(gdjs={}));
2
+ //# sourceMappingURL=capturemanager.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../GDevelop/GDJS/Runtime/capturemanager.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 export type CaptureOptions = {\n screenshots?: Array<{\n delayTimeInSeconds: number;\n signedUrl: string;\n publicUrl: string;\n }>;\n };\n\n /**\n * Helper function to convert a base64 string to a Blob, which can be uploaded to a server.\n */\n const base64ToBlob = (base64) => {\n const byteString = atob(base64.split(',')[1]);\n const mimeString = base64.split(',')[0].split(':')[1].split(';')[0];\n\n const arrayBuffer = new Uint8Array(byteString.length);\n for (let i = 0; i < byteString.length; i++) {\n arrayBuffer[i] = byteString.charCodeAt(i);\n }\n\n return new Blob([arrayBuffer], { type: mimeString });\n };\n\n /**\n * Manage the captures (screenshots, videos, etc...) that need to be taken during the game.\n */\n export class CaptureManager {\n _gameRenderer: gdjs.RuntimeGameRenderer;\n _captureOptions: CaptureOptions;\n\n constructor(\n renderer: gdjs.RuntimeGameRenderer,\n captureOptions: CaptureOptions\n ) {\n this._gameRenderer = renderer;\n this._captureOptions = captureOptions;\n }\n\n /**\n * To be called when the scene has started rendering.\n */\n setupCaptureOptions(isPreview: boolean): void {\n if (!isPreview || !this._captureOptions.screenshots) {\n return;\n }\n\n for (const screenshotCaptureOption of this._captureOptions.screenshots) {\n setTimeout(async () => {\n await this.takeAndUploadScreenshot(screenshotCaptureOption.signedUrl);\n }, screenshotCaptureOption.delayTimeInSeconds);\n }\n }\n\n /**\n * Take a screenshot and upload it to the server.\n */\n async takeAndUploadScreenshot(signedUrl: string) {\n const canvas = this._gameRenderer.getCanvas();\n if (canvas) {\n try {\n const base64Data = canvas.toDataURL('image/png');\n const blobData = base64ToBlob(base64Data);\n\n await fetch(signedUrl, {\n method: 'PUT',\n body: blobData,\n headers: {\n 'Content-Type': 'image/png',\n },\n });\n } catch (error) {\n console.error('Error while uploading screenshot:', error);\n }\n }\n }\n }\n}\n"],
5
+ "mappings": "AAKA,GAAU,MAAV,UAAU,EAAV,CAYE,KAAM,GAAe,AAAC,GAAW,CAC/B,KAAM,GAAa,KAAK,EAAO,MAAM,KAAK,IACpC,EAAa,EAAO,MAAM,KAAK,GAAG,MAAM,KAAK,GAAG,MAAM,KAAK,GAE3D,EAAc,GAAI,YAAW,EAAW,QAC9C,OAAS,GAAI,EAAG,EAAI,EAAW,OAAQ,IACrC,EAAY,GAAK,EAAW,WAAW,GAGzC,MAAO,IAAI,MAAK,CAAC,GAAc,CAAE,KAAM,KAMlC,OAAqB,CAI1B,YACE,EACA,EACA,CACA,KAAK,cAAgB,EACrB,KAAK,gBAAkB,EAMzB,oBAAoB,EAA0B,CAC5C,GAAI,GAAC,GAAa,CAAC,KAAK,gBAAgB,aAIxC,SAAW,KAA2B,MAAK,gBAAgB,YACzD,WAAW,SAAY,CACrB,KAAM,MAAK,wBAAwB,EAAwB,YAC1D,EAAwB,yBAOzB,yBAAwB,EAAmB,CAC/C,KAAM,GAAS,KAAK,cAAc,YAClC,GAAI,EACF,GAAI,CACF,KAAM,GAAa,EAAO,UAAU,aAC9B,EAAW,EAAa,GAE9B,KAAM,OAAM,EAAW,CACrB,OAAQ,MACR,KAAM,EACN,QAAS,CACP,eAAgB,qBAGb,EAAP,CACA,QAAQ,MAAM,oCAAqC,KA7CpD,EAAM,mBA3BL",
6
+ "names": []
7
+ }
@@ -1,2 +1,2 @@
1
- var gdjs;(function(i){const a=new i.Logger("Font manager"),c=["font"];class d{constructor(r){this._loadedFontFamily=new i.ResourceCache;this._loadedFontFamilySet=new Set;this._resourceLoader=r}getResourceKinds(){return c}getFontFamily(r){return this._loadedFontFamily.getFromName(r)||"Arial"}getFontFile(r){const e=this._resourceLoader.getResource(r);return e?e.file||"":r}_getFontFamilyFromFilename(r){let e="gdjs_font_"+r.file.toLowerCase().replace(/[^\w]/gi,"-");const o=e;let n=2;for(;this._loadedFontFamilySet.has(e);)e=e+"-"+n,n++;return o}_loadFont(r,e){const o={},n="url("+encodeURI(e)+")";if(typeof FontFace!="undefined")return fetch(this._resourceLoader.getFullUrl(e),{credentials:this._resourceLoader.checkIfCredentialsRequired(e)?"include":"same-origin"}).then(t=>{if(!t.ok){const s="Unable to fetch "+e+" to be loaded as a font. HTTP status is: "+t.status+".";throw a.error(s),new Error(s)}return t.arrayBuffer()}).then(t=>{const s=new FontFace(r,t,o);document.fonts.add(s)});{const t=document.createElement("style");return t.appendChild(document.createTextNode("@font-face { font-family: '"+r+"'; src: "+n+"; }")),document.head.appendChild(t),new FontFaceObserver(r,o).load()}}async processResource(r){}async loadResource(r){const e=this._resourceLoader.getResource(r);if(!e){a.warn('Unable to find font for resource "'+r+'".');return}if(this._loadedFontFamily.get(e))return;const o=e.file;if(!o)return;const n=this._getFontFamilyFromFilename(e);this._loadedFontFamily.set(e,n),this._loadedFontFamilySet.add(n);try{await this._loadFont(n,o)}catch(t){a.error('Error loading font resource "'+e.name+'" (file: '+o+"): "+(t.message||"Unknown error"))}}}i.FontFaceObserverFontManager=d,i.FontManager=d})(gdjs||(gdjs={}));
1
+ var gdjs;(function(i){const s=new i.Logger("Font manager"),d=["font"];class c{constructor(r){this._loadedFontFamily=new i.ResourceCache;this._loadedFontFamilySet=new Set;this._resourceLoader=r}getResourceKinds(){return d}getFontFamily(r){return this._loadedFontFamily.getFromName(r)||"Arial"}getFontFile(r){const e=this._resourceLoader.getResource(r);return e?e.file||"":r}_getFontFamilyFromFilename(r){let e="gdjs_font_"+r.file.toLowerCase().replace(/[^\w]/gi,"-");const o=e;let n=2;for(;this._loadedFontFamilySet.has(e);)e=e+"-"+n,n++;return o}_loadFont(r,e){const o={},n="url("+encodeURI(e)+")";if(typeof FontFace!="undefined")return fetch(this._resourceLoader.getFullUrl(e),{credentials:this._resourceLoader.checkIfCredentialsRequired(e)?"include":"same-origin"}).then(t=>{if(!t.ok){const a="Unable to fetch "+e+" to be loaded as a font. HTTP status is: "+t.status+".";throw s.error(a),new Error(a)}return t.arrayBuffer()}).then(t=>{const a=new FontFace(r,t,o);document.fonts.add(a)});{const t=document.createElement("style");return t.appendChild(document.createTextNode("@font-face { font-family: '"+r+"'; src: "+n+"; }")),document.head.appendChild(t),new FontFaceObserver(r,o).load()}}async processResource(r){}async loadResource(r){const e=this._resourceLoader.getResource(r);if(!e){s.warn('Unable to find font for resource "'+r+'".');return}if(this._loadedFontFamily.get(e))return;const o=e.file;if(!o)return;const n=this._getFontFamilyFromFilename(e);this._loadedFontFamily.set(e,n),this._loadedFontFamilySet.add(n);try{await this._loadFont(n,o)}catch(t){s.error('Error loading font resource "'+e.name+'" (file: '+o+"): "+(t.message||"Unknown error"))}}dispose(){this._loadedFontFamily.clear(),this._loadedFontFamilySet.clear()}}i.FontFaceObserverFontManager=c,i.FontManager=c})(gdjs||(gdjs={}));
2
2
  //# sourceMappingURL=fontfaceobserver-font-manager.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../GDevelop/GDJS/Runtime/fontfaceobserver-font-manager/fontfaceobserver-font-manager.ts"],
4
- "sourcesContent": ["/*\n * GDevelop JS Platform\n * Copyright 2013-present 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('Font manager');\n\n const resourceKinds: Array<ResourceKind> = ['font'];\n\n /**\n * FontFaceObserverFontManager loads fonts (using `FontFace` or `fontfaceobserver` library)\n * from the game resources (see `loadFonts`), and allow to access to\n * the font families of the loaded fonts during the game (see `getFontFamily`).\n */\n export class FontFaceObserverFontManager implements gdjs.ResourceManager {\n _resourceLoader: gdjs.ResourceLoader;\n // Associate font resource names to the loaded font family\n _loadedFontFamily = new gdjs.ResourceCache<string>();\n _loadedFontFamilySet = new Set<string>();\n\n /**\n * @param resources The resources data of the game.\n * @param resourceLoader The resources loader of the game.\n */\n constructor(resourceLoader: gdjs.ResourceLoader) {\n this._resourceLoader = resourceLoader;\n }\n\n getResourceKinds(): ResourceKind[] {\n return resourceKinds;\n }\n\n /**\n * Return the font family associated to the specified font resource name.\n * The font resource must have been loaded before. If that's not the case,\n * a default font family will be returned (\"Arial\").\n *\n * @param resourceName The name of the resource to get.\n * @returns The font family to be used for this font resource,\n * or \"Arial\" if not loaded.\n */\n getFontFamily(resourceName: string): string {\n return this._loadedFontFamily.getFromName(resourceName) || 'Arial';\n }\n\n /**\n * Return the font file associated to the specified font resource name.\n * The font resource must have been loaded before. If that's not the case,\n * the resource name will be returned (to\n * keep compatibility with GDevelop 5.0-beta56 and previous).\n *\n * Should only be useful for renderers running on a non HTML5/non browser environment.\n *\n * @param resourceName The name of the resource to get.\n * @returns The file of the font resource.\n */\n getFontFile(resourceName: string): string {\n const resource = this._resourceLoader.getResource(resourceName);\n return resource ? resource.file || '' : resourceName;\n }\n\n /**\n * Return the font family to use for a given filename.\n * Each filename is guaranteed to have a unique font family. You should not rely\n * on the font family formatting (consider it as an \"opaque string\") - it's slugified\n * (no spaces, no dots, no non-alphanumeric characters) to avoid issues when using the\n * font family in various contexts.\n *\n * @param filename The filename of the font.\n * @returns The font family to be used for this font resource.\n */\n _getFontFamilyFromFilename(resource: ResourceData): string {\n // Replaces all non-alphanumeric characters with dashes to ensure no issues when\n // referring to this font family (see https://github.com/4ian/GDevelop/issues/1521).\n let baseSlugifiedName =\n 'gdjs_font_' + resource.file.toLowerCase().replace(/[^\\w]/gi, '-');\n\n // Ensure the generated font family is unique.\n const slugifiedName = baseSlugifiedName;\n let uniqueSuffix = 2;\n while (this._loadedFontFamilySet.has(baseSlugifiedName)) {\n baseSlugifiedName = baseSlugifiedName + '-' + uniqueSuffix;\n uniqueSuffix++;\n }\n return slugifiedName;\n }\n\n /**\n * Load the font at the given `src` location (relative to the project), giving\n * it the specified `fontFamily` name.\n *\n * This uses FontFace (if supported) or @font-face + FontFaceObserver\n * to load a font from an url and be notified when loading is done (or failed).\n *\n * @param fontFamily The font\n * @returns The font family to be used for this font resource.\n */\n private _loadFont(fontFamily: string, src: string): Promise<void> {\n const descriptors = {};\n const srcWithUrl = 'url(' + encodeURI(src) + ')';\n\n // @ts-ignore\n if (typeof FontFace !== 'undefined') {\n // Load the given font using CSS Font Loading API.\n return fetch(this._resourceLoader.getFullUrl(src), {\n credentials: this._resourceLoader.checkIfCredentialsRequired(src)\n ? // Any resource stored on the GDevelop Cloud buckets needs the \"credentials\" of the user,\n // i.e: its gdevelop.io cookie, to be passed.\n 'include'\n : // For other resources, use \"same-origin\" as done by default by fetch.\n 'same-origin',\n })\n .then((response) => {\n if (!response.ok) {\n const errorMessage =\n 'Unable to fetch ' +\n src +\n ' to be loaded as a font. HTTP status is: ' +\n response.status +\n '.';\n logger.error(errorMessage);\n throw new Error(errorMessage);\n }\n\n return response.arrayBuffer();\n })\n .then((arrayBuffer) => {\n // @ts-ignore\n const fontFace = new FontFace(fontFamily, arrayBuffer, descriptors);\n\n // @ts-ignore\n document.fonts.add(fontFace);\n });\n } else {\n // TODO: this method of loading font should be removed as old and not allowing\n // to handle loading with credentials. All moderns and not-so-modern browsers\n // that we support also support FontFace API.\n\n // Add @font-face and use FontFaceObserver to be notified when the\n // font is ready.\n const newStyle = document.createElement('style');\n newStyle.appendChild(\n document.createTextNode(\n \"@font-face { font-family: '\" +\n fontFamily +\n \"'; src: \" +\n srcWithUrl +\n '; }'\n )\n );\n document.head.appendChild(newStyle);\n\n // @ts-ignore\n return new FontFaceObserver(fontFamily, descriptors).load();\n }\n }\n\n async processResource(resourceName: string): Promise<void> {\n // Do nothing because fonts are light enough to be parsed in background.\n }\n\n /**\n * Load the specified resources, so that fonts are loaded and can then be\n * used by using the font family returned by getFontFamily.\n * @param onProgress Callback called each time a new file is loaded.\n */\n async loadResource(resourceName: string): Promise<void> {\n const resource = this._resourceLoader.getResource(resourceName);\n if (!resource) {\n logger.warn('Unable to find font for resource \"' + resourceName + '\".');\n return;\n }\n\n if (this._loadedFontFamily.get(resource)) {\n return;\n }\n const file = resource.file;\n if (!file) {\n return;\n }\n\n const fontFamily = this._getFontFamilyFromFilename(resource);\n // Cache the result to avoid collision with a similar slugified name for another filename.\n this._loadedFontFamily.set(resource, fontFamily);\n this._loadedFontFamilySet.add(fontFamily);\n try {\n await this._loadFont(fontFamily, file);\n } catch (error) {\n logger.error(\n 'Error loading font resource \"' +\n resource.name +\n '\" (file: ' +\n file +\n '): ' +\n (error.message || 'Unknown error')\n );\n }\n }\n }\n\n //Register the class to let the engine use it.\n export type FontManager = FontFaceObserverFontManager;\n export const FontManager = FontFaceObserverFontManager;\n}\n"],
5
- "mappings": "AAKA,GAAU,MAAV,UAAU,EAAV,CACE,KAAM,GAAS,GAAI,GAAK,OAAO,gBAEzB,EAAqC,CAAC,QAOrC,OAAkE,CAUvE,YAAY,EAAqC,CAPjD,uBAAoB,GAAI,GAAK,cAC7B,0BAAuB,GAAI,KAOzB,KAAK,gBAAkB,EAGzB,kBAAmC,CACjC,MAAO,GAYT,cAAc,EAA8B,CAC1C,MAAO,MAAK,kBAAkB,YAAY,IAAiB,QAc7D,YAAY,EAA8B,CACxC,KAAM,GAAW,KAAK,gBAAgB,YAAY,GAClD,MAAO,GAAW,EAAS,MAAQ,GAAK,EAa1C,2BAA2B,EAAgC,CAGzD,GAAI,GACF,aAAe,EAAS,KAAK,cAAc,QAAQ,UAAW,KAGhE,KAAM,GAAgB,EACtB,GAAI,GAAe,EACnB,KAAO,KAAK,qBAAqB,IAAI,IACnC,EAAoB,EAAoB,IAAM,EAC9C,IAEF,MAAO,GAaD,UAAU,EAAoB,EAA4B,CAChE,KAAM,GAAc,GACd,EAAa,OAAS,UAAU,GAAO,IAG7C,GAAI,MAAO,WAAa,YAEtB,MAAO,OAAM,KAAK,gBAAgB,WAAW,GAAM,CACjD,YAAa,KAAK,gBAAgB,2BAA2B,GAGzD,UAEA,gBAEH,KAAK,AAAC,GAAa,CAClB,GAAI,CAAC,EAAS,GAAI,CAChB,KAAM,GACJ,mBACA,EACA,4CACA,EAAS,OACT,IACF,QAAO,MAAM,GACP,GAAI,OAAM,GAGlB,MAAO,GAAS,gBAEjB,KAAK,AAAC,GAAgB,CAErB,KAAM,GAAW,GAAI,UAAS,EAAY,EAAa,GAGvD,SAAS,MAAM,IAAI,KAElB,CAOL,KAAM,GAAW,SAAS,cAAc,SACxC,SAAS,YACP,SAAS,eACP,8BACE,EACA,WACA,EACA,QAGN,SAAS,KAAK,YAAY,GAGnB,GAAI,kBAAiB,EAAY,GAAa,aAInD,iBAAgB,EAAqC,OASrD,cAAa,EAAqC,CACtD,KAAM,GAAW,KAAK,gBAAgB,YAAY,GAClD,GAAI,CAAC,EAAU,CACb,EAAO,KAAK,qCAAuC,EAAe,MAClE,OAGF,GAAI,KAAK,kBAAkB,IAAI,GAC7B,OAEF,KAAM,GAAO,EAAS,KACtB,GAAI,CAAC,EACH,OAGF,KAAM,GAAa,KAAK,2BAA2B,GAEnD,KAAK,kBAAkB,IAAI,EAAU,GACrC,KAAK,qBAAqB,IAAI,GAC9B,GAAI,CACF,KAAM,MAAK,UAAU,EAAY,SAC1B,EAAP,CACA,EAAO,MACL,gCACE,EAAS,KACT,YACA,EACA,MACC,GAAM,SAAW,oBApLrB,EAAM,8BA4LA,cAAc,IAtMnB",
4
+ "sourcesContent": ["/*\n * GDevelop JS Platform\n * Copyright 2013-present 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('Font manager');\n\n const resourceKinds: Array<ResourceKind> = ['font'];\n\n /**\n * FontFaceObserverFontManager loads fonts (using `FontFace` or `fontfaceobserver` library)\n * from the game resources (see `loadFonts`), and allow to access to\n * the font families of the loaded fonts during the game (see `getFontFamily`).\n */\n export class FontFaceObserverFontManager implements gdjs.ResourceManager {\n _resourceLoader: gdjs.ResourceLoader;\n // Associate font resource names to the loaded font family\n _loadedFontFamily = new gdjs.ResourceCache<string>();\n _loadedFontFamilySet = new Set<string>();\n\n /**\n * @param resources The resources data of the game.\n * @param resourceLoader The resources loader of the game.\n */\n constructor(resourceLoader: gdjs.ResourceLoader) {\n this._resourceLoader = resourceLoader;\n }\n\n getResourceKinds(): ResourceKind[] {\n return resourceKinds;\n }\n\n /**\n * Return the font family associated to the specified font resource name.\n * The font resource must have been loaded before. If that's not the case,\n * a default font family will be returned (\"Arial\").\n *\n * @param resourceName The name of the resource to get.\n * @returns The font family to be used for this font resource,\n * or \"Arial\" if not loaded.\n */\n getFontFamily(resourceName: string): string {\n return this._loadedFontFamily.getFromName(resourceName) || 'Arial';\n }\n\n /**\n * Return the font file associated to the specified font resource name.\n * The font resource must have been loaded before. If that's not the case,\n * the resource name will be returned (to\n * keep compatibility with GDevelop 5.0-beta56 and previous).\n *\n * Should only be useful for renderers running on a non HTML5/non browser environment.\n *\n * @param resourceName The name of the resource to get.\n * @returns The file of the font resource.\n */\n getFontFile(resourceName: string): string {\n const resource = this._resourceLoader.getResource(resourceName);\n return resource ? resource.file || '' : resourceName;\n }\n\n /**\n * Return the font family to use for a given filename.\n * Each filename is guaranteed to have a unique font family. You should not rely\n * on the font family formatting (consider it as an \"opaque string\") - it's slugified\n * (no spaces, no dots, no non-alphanumeric characters) to avoid issues when using the\n * font family in various contexts.\n *\n * @param filename The filename of the font.\n * @returns The font family to be used for this font resource.\n */\n _getFontFamilyFromFilename(resource: ResourceData): string {\n // Replaces all non-alphanumeric characters with dashes to ensure no issues when\n // referring to this font family (see https://github.com/4ian/GDevelop/issues/1521).\n let baseSlugifiedName =\n 'gdjs_font_' + resource.file.toLowerCase().replace(/[^\\w]/gi, '-');\n\n // Ensure the generated font family is unique.\n const slugifiedName = baseSlugifiedName;\n let uniqueSuffix = 2;\n while (this._loadedFontFamilySet.has(baseSlugifiedName)) {\n baseSlugifiedName = baseSlugifiedName + '-' + uniqueSuffix;\n uniqueSuffix++;\n }\n return slugifiedName;\n }\n\n /**\n * Load the font at the given `src` location (relative to the project), giving\n * it the specified `fontFamily` name.\n *\n * This uses FontFace (if supported) or @font-face + FontFaceObserver\n * to load a font from an url and be notified when loading is done (or failed).\n *\n * @param fontFamily The font\n * @returns The font family to be used for this font resource.\n */\n private _loadFont(fontFamily: string, src: string): Promise<void> {\n const descriptors = {};\n const srcWithUrl = 'url(' + encodeURI(src) + ')';\n\n // @ts-ignore\n if (typeof FontFace !== 'undefined') {\n // Load the given font using CSS Font Loading API.\n return fetch(this._resourceLoader.getFullUrl(src), {\n credentials: this._resourceLoader.checkIfCredentialsRequired(src)\n ? // Any resource stored on the GDevelop Cloud buckets needs the \"credentials\" of the user,\n // i.e: its gdevelop.io cookie, to be passed.\n 'include'\n : // For other resources, use \"same-origin\" as done by default by fetch.\n 'same-origin',\n })\n .then((response) => {\n if (!response.ok) {\n const errorMessage =\n 'Unable to fetch ' +\n src +\n ' to be loaded as a font. HTTP status is: ' +\n response.status +\n '.';\n logger.error(errorMessage);\n throw new Error(errorMessage);\n }\n\n return response.arrayBuffer();\n })\n .then((arrayBuffer) => {\n // @ts-ignore\n const fontFace = new FontFace(fontFamily, arrayBuffer, descriptors);\n\n // @ts-ignore\n document.fonts.add(fontFace);\n });\n } else {\n // TODO: this method of loading font should be removed as old and not allowing\n // to handle loading with credentials. All moderns and not-so-modern browsers\n // that we support also support FontFace API.\n\n // Add @font-face and use FontFaceObserver to be notified when the\n // font is ready.\n const newStyle = document.createElement('style');\n newStyle.appendChild(\n document.createTextNode(\n \"@font-face { font-family: '\" +\n fontFamily +\n \"'; src: \" +\n srcWithUrl +\n '; }'\n )\n );\n document.head.appendChild(newStyle);\n\n // @ts-ignore\n return new FontFaceObserver(fontFamily, descriptors).load();\n }\n }\n\n async processResource(resourceName: string): Promise<void> {\n // Do nothing because fonts are light enough to be parsed in background.\n }\n\n /**\n * Load the specified resources, so that fonts are loaded and can then be\n * used by using the font family returned by getFontFamily.\n * @param onProgress Callback called each time a new file is loaded.\n */\n async loadResource(resourceName: string): Promise<void> {\n const resource = this._resourceLoader.getResource(resourceName);\n if (!resource) {\n logger.warn('Unable to find font for resource \"' + resourceName + '\".');\n return;\n }\n\n if (this._loadedFontFamily.get(resource)) {\n return;\n }\n const file = resource.file;\n if (!file) {\n return;\n }\n\n const fontFamily = this._getFontFamilyFromFilename(resource);\n // Cache the result to avoid collision with a similar slugified name for another filename.\n this._loadedFontFamily.set(resource, fontFamily);\n this._loadedFontFamilySet.add(fontFamily);\n try {\n await this._loadFont(fontFamily, file);\n } catch (error) {\n logger.error(\n 'Error loading font resource \"' +\n resource.name +\n '\" (file: ' +\n file +\n '): ' +\n (error.message || 'Unknown error')\n );\n }\n }\n\n /**\n * To be called when the game is disposed.\n * Clear caches of loaded font families.\n */\n dispose(): void {\n this._loadedFontFamily.clear();\n this._loadedFontFamilySet.clear();\n }\n }\n\n //Register the class to let the engine use it.\n export type FontManager = FontFaceObserverFontManager;\n export const FontManager = FontFaceObserverFontManager;\n}\n"],
5
+ "mappings": "AAKA,GAAU,MAAV,UAAU,EAAV,CACE,KAAM,GAAS,GAAI,GAAK,OAAO,gBAEzB,EAAqC,CAAC,QAOrC,OAAkE,CAUvE,YAAY,EAAqC,CAPjD,uBAAoB,GAAI,GAAK,cAC7B,0BAAuB,GAAI,KAOzB,KAAK,gBAAkB,EAGzB,kBAAmC,CACjC,MAAO,GAYT,cAAc,EAA8B,CAC1C,MAAO,MAAK,kBAAkB,YAAY,IAAiB,QAc7D,YAAY,EAA8B,CACxC,KAAM,GAAW,KAAK,gBAAgB,YAAY,GAClD,MAAO,GAAW,EAAS,MAAQ,GAAK,EAa1C,2BAA2B,EAAgC,CAGzD,GAAI,GACF,aAAe,EAAS,KAAK,cAAc,QAAQ,UAAW,KAGhE,KAAM,GAAgB,EACtB,GAAI,GAAe,EACnB,KAAO,KAAK,qBAAqB,IAAI,IACnC,EAAoB,EAAoB,IAAM,EAC9C,IAEF,MAAO,GAaD,UAAU,EAAoB,EAA4B,CAChE,KAAM,GAAc,GACd,EAAa,OAAS,UAAU,GAAO,IAG7C,GAAI,MAAO,WAAa,YAEtB,MAAO,OAAM,KAAK,gBAAgB,WAAW,GAAM,CACjD,YAAa,KAAK,gBAAgB,2BAA2B,GAGzD,UAEA,gBAEH,KAAK,AAAC,GAAa,CAClB,GAAI,CAAC,EAAS,GAAI,CAChB,KAAM,GACJ,mBACA,EACA,4CACA,EAAS,OACT,IACF,QAAO,MAAM,GACP,GAAI,OAAM,GAGlB,MAAO,GAAS,gBAEjB,KAAK,AAAC,GAAgB,CAErB,KAAM,GAAW,GAAI,UAAS,EAAY,EAAa,GAGvD,SAAS,MAAM,IAAI,KAElB,CAOL,KAAM,GAAW,SAAS,cAAc,SACxC,SAAS,YACP,SAAS,eACP,8BACE,EACA,WACA,EACA,QAGN,SAAS,KAAK,YAAY,GAGnB,GAAI,kBAAiB,EAAY,GAAa,aAInD,iBAAgB,EAAqC,OASrD,cAAa,EAAqC,CACtD,KAAM,GAAW,KAAK,gBAAgB,YAAY,GAClD,GAAI,CAAC,EAAU,CACb,EAAO,KAAK,qCAAuC,EAAe,MAClE,OAGF,GAAI,KAAK,kBAAkB,IAAI,GAC7B,OAEF,KAAM,GAAO,EAAS,KACtB,GAAI,CAAC,EACH,OAGF,KAAM,GAAa,KAAK,2BAA2B,GAEnD,KAAK,kBAAkB,IAAI,EAAU,GACrC,KAAK,qBAAqB,IAAI,GAC9B,GAAI,CACF,KAAM,MAAK,UAAU,EAAY,SAC1B,EAAP,CACA,EAAO,MACL,gCACE,EAAS,KACT,YACA,EACA,MACC,GAAM,SAAW,mBAS1B,SAAgB,CACd,KAAK,kBAAkB,QACvB,KAAK,qBAAqB,SA/LvB,EAAM,8BAqMA,cAAc,IA/MnB",
6
6
  "names": []
7
7
  }
@@ -1,2 +1,2 @@
1
- var gdjs;(function(a){const h=new a.Logger("Audio manager"),f=["audio"],c={preload:!0,onplayerror:(u,e)=>h.error("Can't play an audio file: "+e),onloaderror:(u,e)=>h.error("Error while loading an audio file: "+e)},d=u=>u>1?1:u<0?0:u;class g{constructor(e,s,t,o){this._id=null;this._oncePlay=[];this._onPlay=[];this._howl=e,this._initialVolume=d(s),this._loop=t,this._rate=o}isLoaded(){return this._howl.state()==="loaded"}play(){if(this.isLoaded()){const e=this._howl.play(this._id===null?"__default":this._id);this._id=e,this._howl.volume(this._initialVolume,e),this._howl.loop(this._loop,e),this._howl.rate(a.HowlerSoundManager.clampRate(this._rate),e),this._onPlay.forEach(s=>{this.on("play",s),s(e)}),this._oncePlay.forEach(s=>s(e)),this._onPlay=[],this._oncePlay=[]}else this._howl.once("load",()=>this.play());return this}pause(){return this._id!==null&&this._howl.pause(this._id),this}stop(){return this._id!==null&&this._howl.stop(this._id),this}playing(){return(this._id!==null?this._howl.playing(this._id):!0)||!this.isLoaded()}paused(){return!this.playing()}stopped(){return this.paused()&&this.getSeek()===0}getRate(){return this._rate}setRate(e){return this._rate=e,this._id!==null&&(e=a.HowlerSoundManager.clampRate(e),this._howl.rate(e,this._id)),this}getLoop(){return this._loop}setLoop(e){return this._loop=e,this._id!==null&&this._howl.loop(e,this._id),this}getVolume(){return this._id===null?this._initialVolume:this._howl.volume(this._id)}setVolume(e){return this._initialVolume=d(e),this._id!==null&&this._howl.volume(this._initialVolume,this._id),this}getMute(){return this._id===null?!1:this._howl.mute(this._id)}setMute(e){return this._id!==null&&this._howl.mute(e,this._id),this}getSeek(){return this._id===null?0:this._howl.seek(this._id)}setSeek(e){return this._id!==null&&this._howl.seek(e,this._id),this}getSpatialPosition(e){return this._id===null?0:this._howl.pos(this._id)[e==="x"?0:e==="y"?1:2]}setSpatialPosition(e,s,t){return this._id!==null&&this._howl.pos(e,s,t,this._id),this}fade(e,s,t){return this._id!==null&&this._howl.fade(d(e),d(s),t,this._id),this}on(e,s){return e==="play"?this._id===null?this._onPlay.push(s):this._howl.on(e,s,this._id):this._id===null?this.once("play",()=>this.on(e,s)):this._howl.on(e,s,this._id),this}once(e,s){return e==="play"?this._id===null?this._oncePlay.push(s):this.playing()?s(this._id):this._howl.once(e,s,this._id):this._id===null?this.once("play",()=>this.once(e,s)):this._howl.once(e,s,this._id),this}off(e,s){return this._id!==null&&this._howl.off(e,s,this._id),this}}a.HowlerSound=g;class p{constructor(e){this._loadedMusics=new a.ResourceCache;this._loadedSounds=new a.ResourceCache;this._availableResources={};this._globalVolume=100;this._sounds={};this._musics={};this._freeSounds=[];this._freeMusics=[];this._pausedSounds=[];this._paused=!1;this._getAudioResource=e=>{const s=this._resourceLoader.getResource(e);return s&&this.getResourceKinds().includes(s.kind)?s:{file:e,kind:"audio",metadata:"",name:e}};this._resourceLoader=e;const s=this;document.addEventListener("deviceready",function(){document.addEventListener("pause",function(){const t=s._freeSounds.concat(s._freeMusics);for(let o in s._sounds)s._sounds.hasOwnProperty(o)&&t.push(s._sounds[o]);for(let o in s._musics)s._musics.hasOwnProperty(o)&&t.push(s._musics[o]);for(let o=0;o<t.length;o++){const i=t[o];!i.paused()&&!i.stopped()&&(i.pause(),s._pausedSounds.push(i))}s._paused=!0},!1),document.addEventListener("resume",function(){try{for(let t=0;t<s._pausedSounds.length;t++){const o=s._pausedSounds[t];o.stopped()||o.play()}}catch(t){if(t.message&&typeof t.message=="string"&&t.message.startsWith("Maximum call stack size exceeded"))console.warn("An error occurred when resuming paused sounds while the game was in background:",t);else throw t}s._pausedSounds.length=0,s._paused=!1},!1)})}getResourceKinds(){return f}static clampRate(e){return e>4?4:e<.5?.5:e}_storeSoundInArray(e,s){for(let t=0,o=e.length;t<o;++t)if(!e[t]||e[t].stopped())return e[t]=s,s;return e.push(s),s}createHowlerSound(e,s,t,o,i){const l=s?this._loadedMusics:this._loadedSounds,r=this._getAudioResource(e);let n=l.get(r);if(!n){const _=r?r.file:e;n=new Howl(Object.assign({src:[this._resourceLoader.getFullUrl(_)],html5:s,xhr:{withCredentials:this._resourceLoader.checkIfCredentialsRequired(_)},volume:0},c)),l.set(r,n)}return new a.HowlerSound(n,t,o,i)}loadAudio(e,s){const t=s?this._loadedMusics:this._loadedSounds,o=this._getAudioResource(e);t.get(o)||t.set(o,new Howl(Object.assign({src:[this._resourceLoader.getFullUrl(o.file)],html5:s,xhr:{withCredentials:this._resourceLoader.checkIfCredentialsRequired(o.file)},volume:0},c)))}unloadAudio(e,s){const t=s?this._loadedMusics:this._loadedSounds,o=this._getAudioResource(e),i=t.get(o);if(!i)return;function l(r){for(let n in r)r[n]&&r[n]._howl===i&&(r[n].stop(),delete r[n])}l(this._freeMusics),l(this._freeSounds),l(Object.values(this._musics)),l(Object.values(this._sounds)),l(this._pausedSounds),i.unload(),t.delete(o)}unloadAll(){Howler.unload(),this._freeSounds.length=0,this._freeMusics.length=0,this._sounds={},this._musics={},this._pausedSounds.length=0,this._loadedMusics.clear(),this._loadedSounds.clear()}playSound(e,s,t,o){const i=this.createHowlerSound(e,!1,t/100,s,o);this._storeSoundInArray(this._freeSounds,i),i.once("play",()=>{this._paused&&(i.pause(),this._pausedSounds.push(i))}),i.play()}playSoundOnChannel(e,s,t,o,i){this._sounds[s]&&this._sounds[s].stop();const l=this.createHowlerSound(e,!1,o/100,t,i);this._sounds[s]=l,l.once("play",()=>{this._paused&&(l.pause(),this._pausedSounds.push(l))}),l.play()}getSoundOnChannel(e){return this._sounds[e]||null}playMusic(e,s,t,o){const i=this.createHowlerSound(e,!0,t/100,s,o);this._storeSoundInArray(this._freeMusics,i),i.once("play",()=>{this._paused&&(i.pause(),this._pausedSounds.push(i))}),i.play()}playMusicOnChannel(e,s,t,o,i){this._musics[s]&&this._musics[s].stop();const l=this.createHowlerSound(e,!0,o/100,t,i);this._musics[s]=l,l.once("play",()=>{this._paused&&(l.pause(),this._pausedSounds.push(l))}),l.play()}getMusicOnChannel(e){return this._musics[e]||null}setGlobalVolume(e){this._globalVolume=e,this._globalVolume>100&&(this._globalVolume=100),this._globalVolume<0&&(this._globalVolume=0),Howler.volume(this._globalVolume/100)}getGlobalVolume(){return this._globalVolume}clearAll(){Howler.stop(),this._freeSounds.length=0,this._freeMusics.length=0,this._sounds={},this._musics={},this._pausedSounds.length=0}async processResource(e){}async loadResource(e){const s=this._resourceLoader.getResource(e);if(!s){h.warn('Unable to find audio for resource "'+e+'".');return}if(s.file){if(this._availableResources[s.name])return;this._availableResources[s.name]=s}const t=(i,l)=>new Promise((r,n)=>{const _=l?this._loadedMusics:this._loadedSounds;_[i]=new Howl(Object.assign({},c,{src:[this._resourceLoader.getFullUrl(i)],onload:r,onloaderror:(y,w)=>n(w),html5:l,xhr:{withCredentials:this._resourceLoader.checkIfCredentialsRequired(i)},volume:0}))}),o=s.file;if(s.preloadAsMusic)try{await t(o,!0)}catch(i){h.warn("There was an error while preloading an audio file: "+i)}if(s.preloadAsSound)try{await t(o,!1)}catch(i){h.warn("There was an error while preloading an audio file: "+i)}else if(s.preloadInCache||!s.preloadAsMusic)try{await new Promise((i,l)=>{const r=new XMLHttpRequest;r.withCredentials=this._resourceLoader.checkIfCredentialsRequired(o),r.addEventListener("load",i),r.addEventListener("error",n=>l("XHR error: "+o)),r.addEventListener("abort",n=>l("XHR abort: "+o)),r.open("GET",this._resourceLoader.getFullUrl(o)),r.send()})}catch(i){h.warn("There was an error while preloading an audio file: "+i)}}}a.HowlerSoundManager=p,a.SoundManager=p})(gdjs||(gdjs={}));
1
+ var gdjs;(function(a){const h=new a.Logger("Audio manager"),f=["audio"],c={preload:!0,onplayerror:(u,e)=>h.error("Can't play an audio file: "+e),onloaderror:(u,e)=>h.error("Error while loading an audio file: "+e)},d=u=>u>1?1:u<0?0:u;class g{constructor(e,s,t,o){this._id=null;this._oncePlay=[];this._onPlay=[];this._howl=e,this._initialVolume=d(s),this._loop=t,this._rate=o}isLoaded(){return this._howl.state()==="loaded"}play(){if(this.isLoaded()){const e=this._howl.play(this._id===null?"__default":this._id);this._id=e,this._howl.volume(this._initialVolume,e),this._howl.loop(this._loop,e),this._howl.rate(a.HowlerSoundManager.clampRate(this._rate),e),this._onPlay.forEach(s=>{this.on("play",s),s(e)}),this._oncePlay.forEach(s=>s(e)),this._onPlay=[],this._oncePlay=[]}else this._howl.once("load",()=>this.play());return this}pause(){return this._id!==null&&this._howl.pause(this._id),this}stop(){return this._id!==null&&this._howl.stop(this._id),this}playing(){return(this._id!==null?this._howl.playing(this._id):!0)||!this.isLoaded()}paused(){return!this.playing()}stopped(){return this.paused()&&this.getSeek()===0}getRate(){return this._rate}setRate(e){return this._rate=e,this._id!==null&&(e=a.HowlerSoundManager.clampRate(e),this._howl.rate(e,this._id)),this}getLoop(){return this._loop}setLoop(e){return this._loop=e,this._id!==null&&this._howl.loop(e,this._id),this}getVolume(){return this._id===null?this._initialVolume:this._howl.volume(this._id)}setVolume(e){return this._initialVolume=d(e),this._id!==null&&this._howl.volume(this._initialVolume,this._id),this}getMute(){return this._id===null?!1:this._howl.mute(this._id)}setMute(e){return this._id!==null&&this._howl.mute(e,this._id),this}getSeek(){return this._id===null?0:this._howl.seek(this._id)}setSeek(e){return this._id!==null&&this._howl.seek(e,this._id),this}getSpatialPosition(e){return this._id===null?0:this._howl.pos(this._id)[e==="x"?0:e==="y"?1:2]}setSpatialPosition(e,s,t){return this._id!==null&&this._howl.pos(e,s,t,this._id),this}fade(e,s,t){return this._id!==null&&this._howl.fade(d(e),d(s),t,this._id),this}on(e,s){return e==="play"?this._id===null?this._onPlay.push(s):this._howl.on(e,s,this._id):this._id===null?this.once("play",()=>this.on(e,s)):this._howl.on(e,s,this._id),this}once(e,s){return e==="play"?this._id===null?this._oncePlay.push(s):this.playing()?s(this._id):this._howl.once(e,s,this._id):this._id===null?this.once("play",()=>this.once(e,s)):this._howl.once(e,s,this._id),this}off(e,s){return this._id!==null&&this._howl.off(e,s,this._id),this}}a.HowlerSound=g;class p{constructor(e){this._loadedMusics=new a.ResourceCache;this._loadedSounds=new a.ResourceCache;this._availableResources={};this._globalVolume=100;this._sounds={};this._musics={};this._freeSounds=[];this._freeMusics=[];this._pausedSounds=[];this._paused=!1;this._getAudioResource=e=>{const s=this._resourceLoader.getResource(e);return s&&this.getResourceKinds().includes(s.kind)?s:{file:e,kind:"audio",metadata:"",name:e}};this._resourceLoader=e;const s=this;document.addEventListener("deviceready",function(){document.addEventListener("pause",function(){const t=s._freeSounds.concat(s._freeMusics);for(let o in s._sounds)s._sounds.hasOwnProperty(o)&&t.push(s._sounds[o]);for(let o in s._musics)s._musics.hasOwnProperty(o)&&t.push(s._musics[o]);for(let o=0;o<t.length;o++){const i=t[o];!i.paused()&&!i.stopped()&&(i.pause(),s._pausedSounds.push(i))}s._paused=!0},!1),document.addEventListener("resume",function(){try{for(let t=0;t<s._pausedSounds.length;t++){const o=s._pausedSounds[t];o.stopped()||o.play()}}catch(t){if(t.message&&typeof t.message=="string"&&t.message.startsWith("Maximum call stack size exceeded"))console.warn("An error occurred when resuming paused sounds while the game was in background:",t);else throw t}s._pausedSounds.length=0,s._paused=!1},!1)})}getResourceKinds(){return f}static clampRate(e){return e>4?4:e<.5?.5:e}_storeSoundInArray(e,s){for(let t=0,o=e.length;t<o;++t)if(!e[t]||e[t].stopped())return e[t]=s,s;return e.push(s),s}createHowlerSound(e,s,t,o,i){const l=s?this._loadedMusics:this._loadedSounds,r=this._getAudioResource(e);let n=l.get(r);if(!n){const _=r?r.file:e;n=new Howl(Object.assign({src:[this._resourceLoader.getFullUrl(_)],html5:s,xhr:{withCredentials:this._resourceLoader.checkIfCredentialsRequired(_)},volume:0},c)),l.set(r,n)}return new a.HowlerSound(n,t,o,i)}loadAudio(e,s){const t=s?this._loadedMusics:this._loadedSounds,o=this._getAudioResource(e);t.get(o)||t.set(o,new Howl(Object.assign({src:[this._resourceLoader.getFullUrl(o.file)],html5:s,xhr:{withCredentials:this._resourceLoader.checkIfCredentialsRequired(o.file)},volume:0},c)))}unloadAudio(e,s){const t=s?this._loadedMusics:this._loadedSounds,o=this._getAudioResource(e),i=t.get(o);if(!i)return;function l(r){for(let n in r)r[n]&&r[n]._howl===i&&(r[n].stop(),delete r[n])}l(this._freeMusics),l(this._freeSounds),l(Object.values(this._musics)),l(Object.values(this._sounds)),l(this._pausedSounds),i.unload(),t.delete(o)}unloadAll(){Howler.unload(),this._freeSounds.length=0,this._freeMusics.length=0,this._sounds={},this._musics={},this._pausedSounds.length=0,this._loadedMusics.clear(),this._loadedSounds.clear()}playSound(e,s,t,o){const i=this.createHowlerSound(e,!1,t/100,s,o);this._storeSoundInArray(this._freeSounds,i),i.once("play",()=>{this._paused&&(i.pause(),this._pausedSounds.push(i))}),i.play()}playSoundOnChannel(e,s,t,o,i){this._sounds[s]&&this._sounds[s].stop();const l=this.createHowlerSound(e,!1,o/100,t,i);this._sounds[s]=l,l.once("play",()=>{this._paused&&(l.pause(),this._pausedSounds.push(l))}),l.play()}getSoundOnChannel(e){return this._sounds[e]||null}playMusic(e,s,t,o){const i=this.createHowlerSound(e,!0,t/100,s,o);this._storeSoundInArray(this._freeMusics,i),i.once("play",()=>{this._paused&&(i.pause(),this._pausedSounds.push(i))}),i.play()}playMusicOnChannel(e,s,t,o,i){this._musics[s]&&this._musics[s].stop();const l=this.createHowlerSound(e,!0,o/100,t,i);this._musics[s]=l,l.once("play",()=>{this._paused&&(l.pause(),this._pausedSounds.push(l))}),l.play()}getMusicOnChannel(e){return this._musics[e]||null}setGlobalVolume(e){this._globalVolume=e,this._globalVolume>100&&(this._globalVolume=100),this._globalVolume<0&&(this._globalVolume=0),Howler.volume(this._globalVolume/100)}getGlobalVolume(){return this._globalVolume}clearAll(){Howler.stop(),this._freeSounds.length=0,this._freeMusics.length=0,this._sounds={},this._musics={},this._pausedSounds.length=0}async processResource(e){}async loadResource(e){const s=this._resourceLoader.getResource(e);if(!s){h.warn('Unable to find audio for resource "'+e+'".');return}if(s.file){if(this._availableResources[s.name])return;this._availableResources[s.name]=s}const t=(i,l)=>new Promise((r,n)=>{const _=l?this._loadedMusics:this._loadedSounds;_[i]=new Howl(Object.assign({},c,{src:[this._resourceLoader.getFullUrl(i)],onload:r,onloaderror:(y,w)=>n(w),html5:l,xhr:{withCredentials:this._resourceLoader.checkIfCredentialsRequired(i)},volume:0}))}),o=s.file;if(s.preloadAsMusic)try{await t(o,!0)}catch(i){h.warn("There was an error while preloading an audio file: "+i)}if(s.preloadAsSound)try{await t(o,!1)}catch(i){h.warn("There was an error while preloading an audio file: "+i)}else if(s.preloadInCache||!s.preloadAsMusic)try{await new Promise((i,l)=>{const r=new XMLHttpRequest;r.withCredentials=this._resourceLoader.checkIfCredentialsRequired(o),r.addEventListener("load",i),r.addEventListener("error",n=>l("XHR error: "+o)),r.addEventListener("abort",n=>l("XHR abort: "+o)),r.open("GET",this._resourceLoader.getFullUrl(o)),r.send()})}catch(i){h.warn("There was an error while preloading an audio file: "+i)}}dispose(){this.unloadAll()}}a.HowlerSoundManager=p,a.SoundManager=p})(gdjs||(gdjs={}));
2
2
  //# sourceMappingURL=howler-sound-manager.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../GDevelop/GDJS/Runtime/howler-sound-manager/howler-sound-manager.ts"],
4
- "sourcesContent": ["///<reference path='../types/howler'>\n/*\n * GDevelop JS Platform\n * Copyright 2013-present 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('Audio manager');\n\n const resourceKinds: Array<ResourceKind> = ['audio'];\n\n const HowlParameters: HowlOptions = {\n preload: true,\n onplayerror: (_, error) =>\n logger.error(\"Can't play an audio file: \" + error),\n onloaderror: (_, error) =>\n logger.error('Error while loading an audio file: ' + error),\n };\n\n /**\n * Ensure the volume is between 0 and 1.\n */\n const clampVolume = (volume: float): float => {\n if (volume > 1.0) {\n return 1.0;\n }\n if (volume < 0) {\n return 0;\n }\n return volume;\n };\n\n /**\n * A thin wrapper around a Howl object with:\n * * Handling of callbacks when the sound is not yet loaded.\n * * Automatic clamping when calling `setRate` to ensure a valid value is passed to Howler.js.\n * * Automatic clamping when calling `setVolume` so that the volume is always between 0 and 1.\n *\n * @memberof gdjs\n * @class HowlerSound\n */\n export class HowlerSound {\n /**\n * The ID of the played sound.\n */\n private _id: integer | null = null;\n\n /**\n * The Howl passed to the constructor.\n * It defines the sound file that is being played.\n */\n private _howl: Howl;\n\n /**\n * The **initial** volume at which the sound is being played.\n * Once the sound is started, this volume can be not in sync\n * (in the case the sound is faded by Howler), so volume must\n * be gotten from `this._howl` directly.\n *\n * This value is clamped between 0 and 1.\n */\n private _initialVolume: float;\n\n /**\n * Whether the sound is being played in a loop or not.\n */\n private _loop: boolean;\n\n /**\n * The rate (speed) the sound is being played at.\n * This value is not clamped, though technically Howler.js will only\n * accepts values between a specific range (so we clamp this when\n * passing it to Howler.js, but keep the original value here).\n */\n private _rate: float;\n\n /**\n * An array of callbacks to call once the sound starts to play.\n */\n private _oncePlay: Array<HowlCallback> = [];\n\n /**\n * An array of callbacks to call everytime the sound starts to play.\n */\n private _onPlay: Array<HowlCallback> = [];\n\n constructor(howl: Howl, volume: float, loop: boolean, rate: float) {\n this._howl = howl;\n this._initialVolume = clampVolume(volume);\n this._loop = loop;\n this._rate = rate;\n }\n\n /**\n * Returns true if the associated howl is fully loaded.\n */\n isLoaded(): boolean {\n return this._howl.state() === 'loaded';\n }\n\n /**\n * Begins playback of the sound, or if the Howl is still loading, schedule playing for once it loads.\n * @returns The current instance for chaining.\n */\n play(): this {\n if (this.isLoaded()) {\n const newID = this._howl.play(\n this._id === null ? '__default' : this._id\n );\n this._id = newID;\n\n // Set the howl properties as soon as the sound is played and we have its ID.\n this._howl.volume(this._initialVolume, newID); // this._initialVolume is already clamped between 0 and 1.\n this._howl.loop(this._loop, newID);\n // this._rate is not clamped, but we need to clamp it when passing it to Howler.js as it\n // only supports a specific range.\n this._howl.rate(gdjs.HowlerSoundManager.clampRate(this._rate), newID);\n\n // Manually handle the play event before we have an ID.\n // Before loading, howler won't register events as without an ID we cannot set a listener.\n // Once we have an ID, we can transfer control of the events to howler.\n // We also need to call them once as Howler doesn't for the first play event.\n this._onPlay.forEach((func) => {\n // Transfer the event to howler now that we have an ID\n this.on('play', func);\n func(newID);\n });\n this._oncePlay.forEach((func) => func(newID));\n this._onPlay = [];\n this._oncePlay = [];\n } else this._howl.once('load', () => this.play()); // Play only once the howl is fully loaded\n\n return this;\n }\n\n /**\n * Pauses playback of the sound, saving the seek of playback.\n * @returns The current instance for chaining.\n */\n pause(): this {\n if (this._id !== null) this._howl.pause(this._id);\n return this;\n }\n\n /**\n * Stops playback of the sound, resetting seek to 0.\n * @returns The current instance for chaining.\n */\n stop(): this {\n if (this._id !== null) this._howl.stop(this._id);\n return this;\n }\n\n /**\n * Check if the sound is currently playing.\n * Note that a loading sound is considered as playing (as it will be\n * played as soon as it's loaded). To avoid loading at runtime, prefer\n * to preload the sounds.\n */\n playing(): boolean {\n return (\n (this._id !== null ? this._howl.playing(this._id) : true) ||\n !this.isLoaded() // Loading is considered playing\n );\n }\n\n /**\n * Check if the sound is currently paused.\n */\n paused(): boolean {\n return !this.playing();\n }\n\n /**\n * Check if the sound is currently stopped.\n */\n stopped(): boolean {\n return this.paused() && this.getSeek() === 0;\n }\n\n /**\n * Get the sound playback rate. This 1 for the default speed.\n * This value is not clamped (any value greater than 0 is valid),\n * but the underlying audio system might not play the sound at the required\n * rate if it's very low or very high.\n */\n getRate(): float {\n return this._rate;\n }\n\n /**\n * Set the playback rate.\n * This value is not clamped (any value greater than 0 is valid),\n * but the underlying audio system might not play the sound at the required\n * rate if it's very low or very high.\n * @returns The current instance for chaining.\n */\n setRate(rate: float): this {\n this._rate = rate;\n // If the sound has already started playing, then change the value directly.\n if (this._id !== null) {\n rate = gdjs.HowlerSoundManager.clampRate(rate);\n this._howl.rate(rate, this._id);\n }\n return this;\n }\n\n /**\n * Get if the sound is looping.\n */\n getLoop(): boolean {\n return this._loop;\n }\n\n /**\n * Set if the sound is looping.\n * @returns The current instance for chaining.\n */\n setLoop(loop: boolean): this {\n this._loop = loop;\n // If the sound has already started playing, then change the value directly.\n if (this._id !== null) this._howl.loop(loop, this._id);\n return this;\n }\n\n //TODO: Replace float type in those 2 methods with RangeOf<0..1> once it is standardized (https://github.com/Microsoft/TypeScript/issues/15480)\n /**\n * Get the sound volume.\n * @returns A float from 0 to 1.\n */\n getVolume(): float {\n if (this._id === null) return this._initialVolume;\n return this._howl.volume(this._id);\n }\n\n /**\n * Set the sound volume.\n * @param volume A float from 0 to 1. The value is clamped if too high or too low.\n * @returns The current instance for chaining.\n */\n setVolume(volume: float): this {\n this._initialVolume = clampVolume(volume);\n\n // If the sound has already started playing, then change the value directly.\n if (this._id !== null) this._howl.volume(this._initialVolume, this._id);\n return this;\n }\n\n /**\n * Get if the sound is muted.\n */\n getMute(): boolean {\n if (this._id === null) return false;\n return this._howl.mute(this._id);\n }\n\n /**\n * Set if the sound is muted.\n * @returns The current instance for chaining.\n */\n setMute(mute: boolean): this {\n if (this._id !== null) this._howl.mute(mute, this._id);\n return this;\n }\n\n /**\n * Get the sound seek.\n */\n getSeek(): float {\n if (this._id === null) return 0;\n return this._howl.seek(this._id);\n }\n\n /**\n * Set the sound seek.\n * @returns The current instance for chaining.\n */\n setSeek(seek: float): this {\n if (this._id !== null) this._howl.seek(seek, this._id);\n return this;\n }\n\n /**\n * Get the sound spatial position.\n */\n getSpatialPosition(axis: 'x' | 'y' | 'z'): float {\n if (this._id === null) return 0;\n return this._howl.pos(this._id)[axis === 'x' ? 0 : axis === 'y' ? 1 : 2];\n }\n\n /**\n * Set the sound spatial position.\n * @returns The current instance for chaining.\n */\n setSpatialPosition(x: float, y: float, z: float): this {\n if (this._id !== null) this._howl.pos(x, y, z, this._id);\n return this;\n }\n\n /**\n * Fade the volume sound.\n * @returns The current instance for chaining.\n */\n fade(from: float, to: float, duration: float): this {\n if (this._id !== null)\n this._howl.fade(clampVolume(from), clampVolume(to), duration, this._id);\n return this;\n }\n\n /**\n * Adds an event listener to the howl.\n */\n on(event: HowlEvent, handler: HowlCallback): this {\n if (event === 'play') {\n if (this._id === null) {\n this._onPlay.push(handler);\n } else {\n this._howl.on(event, handler, this._id);\n }\n } else if (this._id === null)\n this.once('play', () => this.on(event, handler));\n else this._howl.on(event, handler, this._id);\n\n return this;\n }\n\n /**\n * Adds an event listener to the howl that removes itself after being called.\n * If the event is `play` and the sound is being played, the handler is\n * called synchronously.\n */\n once(event: HowlEvent, handler: HowlCallback): this {\n if (event === 'play') {\n if (this._id === null) {\n this._oncePlay.push(handler);\n } else if (this.playing()) {\n // Immediately call the handler if the sound is already playing.\n // This is useful for sounds that were just started and have a `.once('play', ...)`\n // handler added on them to set up the volume/rate/loop. If we don't do it\n // synchronously, the sound can play for a tiny bit at the default volume and rate.\n // See https://github.com/4ian/GDevelop/issues/2490.\n handler(this._id);\n } else {\n this._howl.once(event, handler, this._id);\n }\n } else if (this._id === null)\n this.once('play', () => this.once(event, handler));\n else this._howl.once(event, handler, this._id);\n\n return this;\n }\n\n /**\n * Removes an event listener to the howl.\n */\n off(event: HowlEvent, handler: HowlCallback): this {\n if (this._id !== null) this._howl.off(event, handler, this._id);\n return this;\n }\n }\n\n /**\n * HowlerSoundManager is used to manage the sounds and musics of a RuntimeScene.\n *\n * It is basically a container to associate channels to sounds and keep a list\n * of all sounds being played.\n */\n export class HowlerSoundManager {\n _loadedMusics = new gdjs.ResourceCache<Howl>();\n _loadedSounds = new gdjs.ResourceCache<Howl>();\n _availableResources: Record<string, ResourceData> = {};\n _globalVolume: float = 100;\n _sounds: Record<integer, HowlerSound> = {};\n _musics: Record<integer, HowlerSound> = {};\n _freeSounds: HowlerSound[] = []; // Sounds without an assigned channel.\n _freeMusics: HowlerSound[] = []; // Musics without an assigned channel.\n\n /** Paused sounds or musics that should be played once the game is resumed. */\n _pausedSounds: HowlerSound[] = [];\n _paused: boolean = false;\n\n _resourceLoader: gdjs.ResourceLoader;\n\n /**\n * @param resources The resources data of the game.\n * @param resourceLoader The resources loader of the game.\n */\n constructor(resourceLoader: gdjs.ResourceLoader) {\n this._resourceLoader = resourceLoader;\n\n const that = this;\n document.addEventListener('deviceready', function () {\n // pause/resume sounds in Cordova when the app is being paused/resumed\n document.addEventListener(\n 'pause',\n function () {\n const soundList = that._freeSounds.concat(that._freeMusics);\n for (let key in that._sounds) {\n if (that._sounds.hasOwnProperty(key)) {\n soundList.push(that._sounds[key]);\n }\n }\n for (let key in that._musics) {\n if (that._musics.hasOwnProperty(key)) {\n soundList.push(that._musics[key]);\n }\n }\n for (let i = 0; i < soundList.length; i++) {\n const sound = soundList[i];\n if (!sound.paused() && !sound.stopped()) {\n sound.pause();\n that._pausedSounds.push(sound);\n }\n }\n that._paused = true;\n },\n false\n );\n document.addEventListener(\n 'resume',\n function () {\n try {\n for (let i = 0; i < that._pausedSounds.length; i++) {\n const sound = that._pausedSounds[i];\n if (!sound.stopped()) {\n sound.play();\n }\n }\n } catch (error) {\n if (\n error.message &&\n typeof error.message === 'string' &&\n error.message.startsWith('Maximum call stack size exceeded')\n ) {\n console.warn(\n 'An error occurred when resuming paused sounds while the game was in background:',\n error\n );\n } else {\n throw error;\n }\n }\n that._pausedSounds.length = 0;\n that._paused = false;\n },\n false\n );\n });\n }\n\n getResourceKinds(): ResourceKind[] {\n return resourceKinds;\n }\n\n /**\n * Ensure rate is in a range valid for Howler.js\n * @return The clamped rate\n */\n static clampRate(rate: float): float {\n if (rate > 4.0) {\n return 4.0;\n }\n if (rate < 0.5) {\n return 0.5;\n }\n return rate;\n }\n\n /**\n * Return the file associated to the given sound name.\n *\n * Names and files are loaded from resources when preloadAudio is called. If no\n * file is associated to the given name, then the name will be considered as a\n * filename and will be returned.\n *\n * @return The associated resource\n */\n private _getAudioResource = (resourceName: string): ResourceData => {\n const resource = this._resourceLoader.getResource(resourceName);\n return resource && this.getResourceKinds().includes(resource.kind)\n ? resource\n : ({\n file: resourceName,\n kind: 'audio',\n metadata: '',\n name: resourceName,\n } as ResourceData);\n };\n\n /**\n * Store the sound in the specified array, put it at the first index that\n * is free, or add it at the end if no element is free\n * (\"free\" means that the gdjs.HowlerSound can be destroyed).\n *\n * @param arr The array containing the sounds.\n * @param arr The gdjs.HowlerSound to add.\n * @return The gdjs.HowlerSound that have been added (i.e: the second parameter).\n */\n private _storeSoundInArray(\n arr: Array<HowlerSound>,\n sound: HowlerSound\n ): HowlerSound {\n // Try to recycle an old sound.\n for (let i = 0, len = arr.length; i < len; ++i) {\n if (!arr[i] || arr[i].stopped()) {\n arr[i] = sound;\n return sound;\n }\n }\n\n arr.push(sound);\n return sound;\n }\n\n /**\n * Creates a new gdjs.HowlerSound using preloaded/cached Howl instances.\n * @param soundName The name of the file or resource to play.\n * @param isMusic True if a music, false if a sound.\n * @param volume Between 0 and 1.\n * @param loop True if it should be played looping.\n * @param rate speed at which it is played.\n */\n createHowlerSound(\n soundName: string,\n isMusic: boolean,\n volume: float,\n loop: boolean,\n rate: float\n ): HowlerSound {\n const cacheContainer = isMusic ? this._loadedMusics : this._loadedSounds;\n const resource = this._getAudioResource(soundName);\n\n let howl = cacheContainer.get(resource);\n if (!howl) {\n const fileName = resource ? resource.file : soundName;\n howl = new Howl(\n Object.assign(\n {\n src: [this._resourceLoader.getFullUrl(fileName)],\n html5: isMusic,\n xhr: {\n withCredentials: this._resourceLoader.checkIfCredentialsRequired(\n fileName\n ),\n },\n // Cache the sound with no volume. This avoids a bug where it plays at full volume\n // for a split second before setting its correct volume.\n volume: 0,\n },\n HowlParameters\n )\n );\n cacheContainer.set(resource, howl);\n }\n\n return new gdjs.HowlerSound(howl, volume, loop, rate);\n }\n\n /**\n * Preloads a sound or a music in memory.\n * @param soundName The name of the file or resource to preload.\n * @param isMusic True if a music, false if a sound.\n */\n loadAudio(soundName: string, isMusic: boolean) {\n const cacheContainer = isMusic ? this._loadedMusics : this._loadedSounds;\n const resource = this._getAudioResource(soundName);\n\n // Do not reload if it is already loaded.\n if (cacheContainer.get(resource)) {\n return;\n }\n\n cacheContainer.set(\n resource,\n new Howl(\n Object.assign(\n {\n src: [this._resourceLoader.getFullUrl(resource.file)],\n html5: isMusic,\n xhr: {\n withCredentials: this._resourceLoader.checkIfCredentialsRequired(\n resource.file\n ),\n },\n // Cache the sound with no volume. This avoids a bug where it plays at full volume\n // for a split second before setting its correct volume.\n volume: 0,\n },\n HowlParameters\n )\n )\n );\n }\n\n /**\n * Unloads a sound or a music from memory. This will stop any sound/music using it.\n * @param soundName The name of the file or resource to unload.\n * @param isMusic True if a music, false if a sound.\n */\n unloadAudio(soundName: string, isMusic: boolean) {\n const cacheContainer = isMusic ? this._loadedMusics : this._loadedSounds;\n const resource = this._getAudioResource(soundName);\n\n const howl = cacheContainer.get(resource);\n if (!howl) {\n return;\n }\n\n // Make sure any sound using the howl is deleted so\n // that the howl can be garbage collected\n // and no weird \"zombies\" using the unloaded howl can exist.\n function clearContainer(howlerSoundContainer: HowlerSound[]) {\n for (let i in howlerSoundContainer) {\n if (\n howlerSoundContainer[i] &&\n //@ts-ignore We really need to access the raw howl here.\n howlerSoundContainer[i]._howl === howl\n ) {\n howlerSoundContainer[i].stop();\n delete howlerSoundContainer[i];\n }\n }\n }\n\n clearContainer(this._freeMusics);\n clearContainer(this._freeSounds);\n clearContainer(Object.values(this._musics));\n clearContainer(Object.values(this._sounds));\n clearContainer(this._pausedSounds);\n\n howl.unload();\n cacheContainer.delete(resource);\n }\n\n /**\n * Unloads all audio from memory.\n * This will clear the Howl cache.\n * This will also stop any running music or sounds.\n */\n unloadAll() {\n Howler.unload();\n\n // Clean up old sounds that still have the dead Howl instances.\n this._freeSounds.length = 0;\n this._freeMusics.length = 0;\n this._sounds = {};\n this._musics = {};\n this._pausedSounds.length = 0;\n this._loadedMusics.clear();\n this._loadedSounds.clear();\n }\n\n playSound(soundName: string, loop: boolean, volume: float, pitch: float) {\n const sound = this.createHowlerSound(\n soundName,\n /* isMusic= */ false,\n volume / 100,\n loop,\n pitch\n );\n this._storeSoundInArray(this._freeSounds, sound);\n sound.once('play', () => {\n if (this._paused) {\n sound.pause();\n this._pausedSounds.push(sound);\n }\n });\n sound.play();\n }\n\n playSoundOnChannel(\n soundName: string,\n channel: integer,\n loop: boolean,\n volume: float,\n pitch: float\n ) {\n if (this._sounds[channel]) this._sounds[channel].stop();\n\n const sound = this.createHowlerSound(\n soundName,\n /* isMusic= */ false,\n volume / 100,\n loop,\n pitch\n );\n this._sounds[channel] = sound;\n sound.once('play', () => {\n if (this._paused) {\n sound.pause();\n this._pausedSounds.push(sound);\n }\n });\n sound.play();\n }\n\n getSoundOnChannel(channel: integer): HowlerSound | null {\n return this._sounds[channel] || null;\n }\n\n playMusic(soundName: string, loop: boolean, volume: float, pitch: float) {\n const music = this.createHowlerSound(\n soundName,\n /* isMusic= */ true,\n volume / 100,\n loop,\n pitch\n );\n this._storeSoundInArray(this._freeMusics, music);\n music.once('play', () => {\n if (this._paused) {\n music.pause();\n this._pausedSounds.push(music);\n }\n });\n music.play();\n }\n\n playMusicOnChannel(\n soundName: string,\n channel: integer,\n loop: boolean,\n volume: float,\n pitch: float\n ) {\n if (this._musics[channel]) this._musics[channel].stop();\n\n const music = this.createHowlerSound(\n soundName,\n /* isMusic= */ true,\n volume / 100,\n loop,\n pitch\n );\n this._musics[channel] = music;\n music.once('play', () => {\n if (this._paused) {\n music.pause();\n this._pausedSounds.push(music);\n }\n });\n music.play();\n }\n\n getMusicOnChannel(channel: integer): HowlerSound | null {\n return this._musics[channel] || null;\n }\n\n setGlobalVolume(volume: float): void {\n this._globalVolume = volume;\n if (this._globalVolume > 100) {\n this._globalVolume = 100;\n }\n if (this._globalVolume < 0) {\n this._globalVolume = 0;\n }\n Howler.volume(this._globalVolume / 100);\n }\n\n getGlobalVolume(): float {\n return this._globalVolume;\n }\n\n clearAll() {\n Howler.stop();\n\n this._freeSounds.length = 0;\n this._freeMusics.length = 0;\n this._sounds = {};\n this._musics = {};\n this._pausedSounds.length = 0;\n }\n\n async processResource(resourceName: string): Promise<void> {\n // Do nothing because sounds are light enough to be parsed in background.\n }\n\n async loadResource(resourceName: string): Promise<void> {\n const resource = this._resourceLoader.getResource(resourceName);\n if (!resource) {\n logger.warn(\n 'Unable to find audio for resource \"' + resourceName + '\".'\n );\n return;\n }\n if (resource.file) {\n if (this._availableResources[resource.name]) {\n return;\n }\n\n this._availableResources[resource.name] = resource;\n }\n\n const preloadAudioFile = (\n file: string,\n isMusic: boolean\n ): Promise<number> => {\n return new Promise((resolve, reject) => {\n const container = isMusic ? this._loadedMusics : this._loadedSounds;\n container[file] = new Howl(\n Object.assign({}, HowlParameters, {\n src: [this._resourceLoader.getFullUrl(file)],\n onload: resolve,\n onloaderror: (soundId: number, error?: string) => reject(error),\n html5: isMusic,\n xhr: {\n withCredentials: this._resourceLoader.checkIfCredentialsRequired(\n file\n ),\n },\n // Cache the sound with no volume. This avoids a bug where it plays at full volume\n // for a split second before setting its correct volume.\n volume: 0,\n })\n );\n });\n };\n\n const file = resource.file;\n if (resource.preloadAsMusic) {\n try {\n await preloadAudioFile(file, /* isMusic= */ true);\n } catch (error) {\n logger.warn(\n 'There was an error while preloading an audio file: ' + error\n );\n }\n }\n\n if (resource.preloadAsSound) {\n try {\n await preloadAudioFile(file, /* isMusic= */ false);\n } catch (error) {\n logger.warn(\n 'There was an error while preloading an audio file: ' + error\n );\n }\n } else if (\n resource.preloadInCache ||\n // Force downloading of sounds.\n // TODO Decide if sounds should be allowed to be downloaded after the scene starts.\n // - they should be requested automatically at the end of the scene loading\n // - they will be downloaded while the scene is playing\n // - other scenes will be pre-loaded only when all the sounds for the current scene are in cache\n !resource.preloadAsMusic\n ) {\n // preloading as sound already does a XHR request, hence \"else if\"\n try {\n await new Promise((resolve, reject) => {\n const sound = new XMLHttpRequest();\n sound.withCredentials = this._resourceLoader.checkIfCredentialsRequired(\n file\n );\n sound.addEventListener('load', resolve);\n sound.addEventListener('error', (_) =>\n reject('XHR error: ' + file)\n );\n sound.addEventListener('abort', (_) =>\n reject('XHR abort: ' + file)\n );\n sound.open('GET', this._resourceLoader.getFullUrl(file));\n sound.send();\n });\n } catch (error) {\n logger.warn(\n 'There was an error while preloading an audio file: ' + error\n );\n }\n }\n }\n }\n\n // Register the class to let the engine use it.\n export const SoundManager = HowlerSoundManager;\n export type SoundManager = HowlerSoundManager;\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["///<reference path='../types/howler'>\n/*\n * GDevelop JS Platform\n * Copyright 2013-present 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('Audio manager');\n\n const resourceKinds: Array<ResourceKind> = ['audio'];\n\n const HowlParameters: HowlOptions = {\n preload: true,\n onplayerror: (_, error) =>\n logger.error(\"Can't play an audio file: \" + error),\n onloaderror: (_, error) =>\n logger.error('Error while loading an audio file: ' + error),\n };\n\n /**\n * Ensure the volume is between 0 and 1.\n */\n const clampVolume = (volume: float): float => {\n if (volume > 1.0) {\n return 1.0;\n }\n if (volume < 0) {\n return 0;\n }\n return volume;\n };\n\n /**\n * A thin wrapper around a Howl object with:\n * * Handling of callbacks when the sound is not yet loaded.\n * * Automatic clamping when calling `setRate` to ensure a valid value is passed to Howler.js.\n * * Automatic clamping when calling `setVolume` so that the volume is always between 0 and 1.\n *\n * @memberof gdjs\n * @class HowlerSound\n */\n export class HowlerSound {\n /**\n * The ID of the played sound.\n */\n private _id: integer | null = null;\n\n /**\n * The Howl passed to the constructor.\n * It defines the sound file that is being played.\n */\n private _howl: Howl;\n\n /**\n * The **initial** volume at which the sound is being played.\n * Once the sound is started, this volume can be not in sync\n * (in the case the sound is faded by Howler), so volume must\n * be gotten from `this._howl` directly.\n *\n * This value is clamped between 0 and 1.\n */\n private _initialVolume: float;\n\n /**\n * Whether the sound is being played in a loop or not.\n */\n private _loop: boolean;\n\n /**\n * The rate (speed) the sound is being played at.\n * This value is not clamped, though technically Howler.js will only\n * accepts values between a specific range (so we clamp this when\n * passing it to Howler.js, but keep the original value here).\n */\n private _rate: float;\n\n /**\n * An array of callbacks to call once the sound starts to play.\n */\n private _oncePlay: Array<HowlCallback> = [];\n\n /**\n * An array of callbacks to call everytime the sound starts to play.\n */\n private _onPlay: Array<HowlCallback> = [];\n\n constructor(howl: Howl, volume: float, loop: boolean, rate: float) {\n this._howl = howl;\n this._initialVolume = clampVolume(volume);\n this._loop = loop;\n this._rate = rate;\n }\n\n /**\n * Returns true if the associated howl is fully loaded.\n */\n isLoaded(): boolean {\n return this._howl.state() === 'loaded';\n }\n\n /**\n * Begins playback of the sound, or if the Howl is still loading, schedule playing for once it loads.\n * @returns The current instance for chaining.\n */\n play(): this {\n if (this.isLoaded()) {\n const newID = this._howl.play(\n this._id === null ? '__default' : this._id\n );\n this._id = newID;\n\n // Set the howl properties as soon as the sound is played and we have its ID.\n this._howl.volume(this._initialVolume, newID); // this._initialVolume is already clamped between 0 and 1.\n this._howl.loop(this._loop, newID);\n // this._rate is not clamped, but we need to clamp it when passing it to Howler.js as it\n // only supports a specific range.\n this._howl.rate(gdjs.HowlerSoundManager.clampRate(this._rate), newID);\n\n // Manually handle the play event before we have an ID.\n // Before loading, howler won't register events as without an ID we cannot set a listener.\n // Once we have an ID, we can transfer control of the events to howler.\n // We also need to call them once as Howler doesn't for the first play event.\n this._onPlay.forEach((func) => {\n // Transfer the event to howler now that we have an ID\n this.on('play', func);\n func(newID);\n });\n this._oncePlay.forEach((func) => func(newID));\n this._onPlay = [];\n this._oncePlay = [];\n } else this._howl.once('load', () => this.play()); // Play only once the howl is fully loaded\n\n return this;\n }\n\n /**\n * Pauses playback of the sound, saving the seek of playback.\n * @returns The current instance for chaining.\n */\n pause(): this {\n if (this._id !== null) this._howl.pause(this._id);\n return this;\n }\n\n /**\n * Stops playback of the sound, resetting seek to 0.\n * @returns The current instance for chaining.\n */\n stop(): this {\n if (this._id !== null) this._howl.stop(this._id);\n return this;\n }\n\n /**\n * Check if the sound is currently playing.\n * Note that a loading sound is considered as playing (as it will be\n * played as soon as it's loaded). To avoid loading at runtime, prefer\n * to preload the sounds.\n */\n playing(): boolean {\n return (\n (this._id !== null ? this._howl.playing(this._id) : true) ||\n !this.isLoaded() // Loading is considered playing\n );\n }\n\n /**\n * Check if the sound is currently paused.\n */\n paused(): boolean {\n return !this.playing();\n }\n\n /**\n * Check if the sound is currently stopped.\n */\n stopped(): boolean {\n return this.paused() && this.getSeek() === 0;\n }\n\n /**\n * Get the sound playback rate. This 1 for the default speed.\n * This value is not clamped (any value greater than 0 is valid),\n * but the underlying audio system might not play the sound at the required\n * rate if it's very low or very high.\n */\n getRate(): float {\n return this._rate;\n }\n\n /**\n * Set the playback rate.\n * This value is not clamped (any value greater than 0 is valid),\n * but the underlying audio system might not play the sound at the required\n * rate if it's very low or very high.\n * @returns The current instance for chaining.\n */\n setRate(rate: float): this {\n this._rate = rate;\n // If the sound has already started playing, then change the value directly.\n if (this._id !== null) {\n rate = gdjs.HowlerSoundManager.clampRate(rate);\n this._howl.rate(rate, this._id);\n }\n return this;\n }\n\n /**\n * Get if the sound is looping.\n */\n getLoop(): boolean {\n return this._loop;\n }\n\n /**\n * Set if the sound is looping.\n * @returns The current instance for chaining.\n */\n setLoop(loop: boolean): this {\n this._loop = loop;\n // If the sound has already started playing, then change the value directly.\n if (this._id !== null) this._howl.loop(loop, this._id);\n return this;\n }\n\n //TODO: Replace float type in those 2 methods with RangeOf<0..1> once it is standardized (https://github.com/Microsoft/TypeScript/issues/15480)\n /**\n * Get the sound volume.\n * @returns A float from 0 to 1.\n */\n getVolume(): float {\n if (this._id === null) return this._initialVolume;\n return this._howl.volume(this._id);\n }\n\n /**\n * Set the sound volume.\n * @param volume A float from 0 to 1. The value is clamped if too high or too low.\n * @returns The current instance for chaining.\n */\n setVolume(volume: float): this {\n this._initialVolume = clampVolume(volume);\n\n // If the sound has already started playing, then change the value directly.\n if (this._id !== null) this._howl.volume(this._initialVolume, this._id);\n return this;\n }\n\n /**\n * Get if the sound is muted.\n */\n getMute(): boolean {\n if (this._id === null) return false;\n return this._howl.mute(this._id);\n }\n\n /**\n * Set if the sound is muted.\n * @returns The current instance for chaining.\n */\n setMute(mute: boolean): this {\n if (this._id !== null) this._howl.mute(mute, this._id);\n return this;\n }\n\n /**\n * Get the sound seek.\n */\n getSeek(): float {\n if (this._id === null) return 0;\n return this._howl.seek(this._id);\n }\n\n /**\n * Set the sound seek.\n * @returns The current instance for chaining.\n */\n setSeek(seek: float): this {\n if (this._id !== null) this._howl.seek(seek, this._id);\n return this;\n }\n\n /**\n * Get the sound spatial position.\n */\n getSpatialPosition(axis: 'x' | 'y' | 'z'): float {\n if (this._id === null) return 0;\n return this._howl.pos(this._id)[axis === 'x' ? 0 : axis === 'y' ? 1 : 2];\n }\n\n /**\n * Set the sound spatial position.\n * @returns The current instance for chaining.\n */\n setSpatialPosition(x: float, y: float, z: float): this {\n if (this._id !== null) this._howl.pos(x, y, z, this._id);\n return this;\n }\n\n /**\n * Fade the volume sound.\n * @returns The current instance for chaining.\n */\n fade(from: float, to: float, duration: float): this {\n if (this._id !== null)\n this._howl.fade(clampVolume(from), clampVolume(to), duration, this._id);\n return this;\n }\n\n /**\n * Adds an event listener to the howl.\n */\n on(event: HowlEvent, handler: HowlCallback): this {\n if (event === 'play') {\n if (this._id === null) {\n this._onPlay.push(handler);\n } else {\n this._howl.on(event, handler, this._id);\n }\n } else if (this._id === null)\n this.once('play', () => this.on(event, handler));\n else this._howl.on(event, handler, this._id);\n\n return this;\n }\n\n /**\n * Adds an event listener to the howl that removes itself after being called.\n * If the event is `play` and the sound is being played, the handler is\n * called synchronously.\n */\n once(event: HowlEvent, handler: HowlCallback): this {\n if (event === 'play') {\n if (this._id === null) {\n this._oncePlay.push(handler);\n } else if (this.playing()) {\n // Immediately call the handler if the sound is already playing.\n // This is useful for sounds that were just started and have a `.once('play', ...)`\n // handler added on them to set up the volume/rate/loop. If we don't do it\n // synchronously, the sound can play for a tiny bit at the default volume and rate.\n // See https://github.com/4ian/GDevelop/issues/2490.\n handler(this._id);\n } else {\n this._howl.once(event, handler, this._id);\n }\n } else if (this._id === null)\n this.once('play', () => this.once(event, handler));\n else this._howl.once(event, handler, this._id);\n\n return this;\n }\n\n /**\n * Removes an event listener to the howl.\n */\n off(event: HowlEvent, handler: HowlCallback): this {\n if (this._id !== null) this._howl.off(event, handler, this._id);\n return this;\n }\n }\n\n /**\n * HowlerSoundManager is used to manage the sounds and musics of a RuntimeScene.\n *\n * It is basically a container to associate channels to sounds and keep a list\n * of all sounds being played.\n */\n export class HowlerSoundManager {\n _loadedMusics = new gdjs.ResourceCache<Howl>();\n _loadedSounds = new gdjs.ResourceCache<Howl>();\n _availableResources: Record<string, ResourceData> = {};\n _globalVolume: float = 100;\n _sounds: Record<integer, HowlerSound> = {};\n _musics: Record<integer, HowlerSound> = {};\n _freeSounds: HowlerSound[] = []; // Sounds without an assigned channel.\n _freeMusics: HowlerSound[] = []; // Musics without an assigned channel.\n\n /** Paused sounds or musics that should be played once the game is resumed. */\n _pausedSounds: HowlerSound[] = [];\n _paused: boolean = false;\n\n _resourceLoader: gdjs.ResourceLoader;\n\n /**\n * @param resources The resources data of the game.\n * @param resourceLoader The resources loader of the game.\n */\n constructor(resourceLoader: gdjs.ResourceLoader) {\n this._resourceLoader = resourceLoader;\n\n const that = this;\n document.addEventListener('deviceready', function () {\n // pause/resume sounds in Cordova when the app is being paused/resumed\n document.addEventListener(\n 'pause',\n function () {\n const soundList = that._freeSounds.concat(that._freeMusics);\n for (let key in that._sounds) {\n if (that._sounds.hasOwnProperty(key)) {\n soundList.push(that._sounds[key]);\n }\n }\n for (let key in that._musics) {\n if (that._musics.hasOwnProperty(key)) {\n soundList.push(that._musics[key]);\n }\n }\n for (let i = 0; i < soundList.length; i++) {\n const sound = soundList[i];\n if (!sound.paused() && !sound.stopped()) {\n sound.pause();\n that._pausedSounds.push(sound);\n }\n }\n that._paused = true;\n },\n false\n );\n document.addEventListener(\n 'resume',\n function () {\n try {\n for (let i = 0; i < that._pausedSounds.length; i++) {\n const sound = that._pausedSounds[i];\n if (!sound.stopped()) {\n sound.play();\n }\n }\n } catch (error) {\n if (\n error.message &&\n typeof error.message === 'string' &&\n error.message.startsWith('Maximum call stack size exceeded')\n ) {\n console.warn(\n 'An error occurred when resuming paused sounds while the game was in background:',\n error\n );\n } else {\n throw error;\n }\n }\n that._pausedSounds.length = 0;\n that._paused = false;\n },\n false\n );\n });\n }\n\n getResourceKinds(): ResourceKind[] {\n return resourceKinds;\n }\n\n /**\n * Ensure rate is in a range valid for Howler.js\n * @return The clamped rate\n */\n static clampRate(rate: float): float {\n if (rate > 4.0) {\n return 4.0;\n }\n if (rate < 0.5) {\n return 0.5;\n }\n return rate;\n }\n\n /**\n * Return the file associated to the given sound name.\n *\n * Names and files are loaded from resources when preloadAudio is called. If no\n * file is associated to the given name, then the name will be considered as a\n * filename and will be returned.\n *\n * @return The associated resource\n */\n private _getAudioResource = (resourceName: string): ResourceData => {\n const resource = this._resourceLoader.getResource(resourceName);\n return resource && this.getResourceKinds().includes(resource.kind)\n ? resource\n : ({\n file: resourceName,\n kind: 'audio',\n metadata: '',\n name: resourceName,\n } as ResourceData);\n };\n\n /**\n * Store the sound in the specified array, put it at the first index that\n * is free, or add it at the end if no element is free\n * (\"free\" means that the gdjs.HowlerSound can be destroyed).\n *\n * @param arr The array containing the sounds.\n * @param arr The gdjs.HowlerSound to add.\n * @return The gdjs.HowlerSound that have been added (i.e: the second parameter).\n */\n private _storeSoundInArray(\n arr: Array<HowlerSound>,\n sound: HowlerSound\n ): HowlerSound {\n // Try to recycle an old sound.\n for (let i = 0, len = arr.length; i < len; ++i) {\n if (!arr[i] || arr[i].stopped()) {\n arr[i] = sound;\n return sound;\n }\n }\n\n arr.push(sound);\n return sound;\n }\n\n /**\n * Creates a new gdjs.HowlerSound using preloaded/cached Howl instances.\n * @param soundName The name of the file or resource to play.\n * @param isMusic True if a music, false if a sound.\n * @param volume Between 0 and 1.\n * @param loop True if it should be played looping.\n * @param rate speed at which it is played.\n */\n createHowlerSound(\n soundName: string,\n isMusic: boolean,\n volume: float,\n loop: boolean,\n rate: float\n ): HowlerSound {\n const cacheContainer = isMusic ? this._loadedMusics : this._loadedSounds;\n const resource = this._getAudioResource(soundName);\n\n let howl = cacheContainer.get(resource);\n if (!howl) {\n const fileName = resource ? resource.file : soundName;\n howl = new Howl(\n Object.assign(\n {\n src: [this._resourceLoader.getFullUrl(fileName)],\n html5: isMusic,\n xhr: {\n withCredentials: this._resourceLoader.checkIfCredentialsRequired(\n fileName\n ),\n },\n // Cache the sound with no volume. This avoids a bug where it plays at full volume\n // for a split second before setting its correct volume.\n volume: 0,\n },\n HowlParameters\n )\n );\n cacheContainer.set(resource, howl);\n }\n\n return new gdjs.HowlerSound(howl, volume, loop, rate);\n }\n\n /**\n * Preloads a sound or a music in memory.\n * @param soundName The name of the file or resource to preload.\n * @param isMusic True if a music, false if a sound.\n */\n loadAudio(soundName: string, isMusic: boolean) {\n const cacheContainer = isMusic ? this._loadedMusics : this._loadedSounds;\n const resource = this._getAudioResource(soundName);\n\n // Do not reload if it is already loaded.\n if (cacheContainer.get(resource)) {\n return;\n }\n\n cacheContainer.set(\n resource,\n new Howl(\n Object.assign(\n {\n src: [this._resourceLoader.getFullUrl(resource.file)],\n html5: isMusic,\n xhr: {\n withCredentials: this._resourceLoader.checkIfCredentialsRequired(\n resource.file\n ),\n },\n // Cache the sound with no volume. This avoids a bug where it plays at full volume\n // for a split second before setting its correct volume.\n volume: 0,\n },\n HowlParameters\n )\n )\n );\n }\n\n /**\n * Unloads a sound or a music from memory. This will stop any sound/music using it.\n * @param soundName The name of the file or resource to unload.\n * @param isMusic True if a music, false if a sound.\n */\n unloadAudio(soundName: string, isMusic: boolean) {\n const cacheContainer = isMusic ? this._loadedMusics : this._loadedSounds;\n const resource = this._getAudioResource(soundName);\n\n const howl = cacheContainer.get(resource);\n if (!howl) {\n return;\n }\n\n // Make sure any sound using the howl is deleted so\n // that the howl can be garbage collected\n // and no weird \"zombies\" using the unloaded howl can exist.\n function clearContainer(howlerSoundContainer: HowlerSound[]) {\n for (let i in howlerSoundContainer) {\n if (\n howlerSoundContainer[i] &&\n //@ts-ignore We really need to access the raw howl here.\n howlerSoundContainer[i]._howl === howl\n ) {\n howlerSoundContainer[i].stop();\n delete howlerSoundContainer[i];\n }\n }\n }\n\n clearContainer(this._freeMusics);\n clearContainer(this._freeSounds);\n clearContainer(Object.values(this._musics));\n clearContainer(Object.values(this._sounds));\n clearContainer(this._pausedSounds);\n\n howl.unload();\n cacheContainer.delete(resource);\n }\n\n /**\n * Unloads all audio from memory.\n * This will clear the Howl cache.\n * This will also stop any running music or sounds.\n */\n unloadAll() {\n Howler.unload();\n\n // Clean up old sounds that still have the dead Howl instances.\n this._freeSounds.length = 0;\n this._freeMusics.length = 0;\n this._sounds = {};\n this._musics = {};\n this._pausedSounds.length = 0;\n this._loadedMusics.clear();\n this._loadedSounds.clear();\n }\n\n playSound(soundName: string, loop: boolean, volume: float, pitch: float) {\n const sound = this.createHowlerSound(\n soundName,\n /* isMusic= */ false,\n volume / 100,\n loop,\n pitch\n );\n this._storeSoundInArray(this._freeSounds, sound);\n sound.once('play', () => {\n if (this._paused) {\n sound.pause();\n this._pausedSounds.push(sound);\n }\n });\n sound.play();\n }\n\n playSoundOnChannel(\n soundName: string,\n channel: integer,\n loop: boolean,\n volume: float,\n pitch: float\n ) {\n if (this._sounds[channel]) this._sounds[channel].stop();\n\n const sound = this.createHowlerSound(\n soundName,\n /* isMusic= */ false,\n volume / 100,\n loop,\n pitch\n );\n this._sounds[channel] = sound;\n sound.once('play', () => {\n if (this._paused) {\n sound.pause();\n this._pausedSounds.push(sound);\n }\n });\n sound.play();\n }\n\n getSoundOnChannel(channel: integer): HowlerSound | null {\n return this._sounds[channel] || null;\n }\n\n playMusic(soundName: string, loop: boolean, volume: float, pitch: float) {\n const music = this.createHowlerSound(\n soundName,\n /* isMusic= */ true,\n volume / 100,\n loop,\n pitch\n );\n this._storeSoundInArray(this._freeMusics, music);\n music.once('play', () => {\n if (this._paused) {\n music.pause();\n this._pausedSounds.push(music);\n }\n });\n music.play();\n }\n\n playMusicOnChannel(\n soundName: string,\n channel: integer,\n loop: boolean,\n volume: float,\n pitch: float\n ) {\n if (this._musics[channel]) this._musics[channel].stop();\n\n const music = this.createHowlerSound(\n soundName,\n /* isMusic= */ true,\n volume / 100,\n loop,\n pitch\n );\n this._musics[channel] = music;\n music.once('play', () => {\n if (this._paused) {\n music.pause();\n this._pausedSounds.push(music);\n }\n });\n music.play();\n }\n\n getMusicOnChannel(channel: integer): HowlerSound | null {\n return this._musics[channel] || null;\n }\n\n setGlobalVolume(volume: float): void {\n this._globalVolume = volume;\n if (this._globalVolume > 100) {\n this._globalVolume = 100;\n }\n if (this._globalVolume < 0) {\n this._globalVolume = 0;\n }\n Howler.volume(this._globalVolume / 100);\n }\n\n getGlobalVolume(): float {\n return this._globalVolume;\n }\n\n clearAll() {\n Howler.stop();\n\n this._freeSounds.length = 0;\n this._freeMusics.length = 0;\n this._sounds = {};\n this._musics = {};\n this._pausedSounds.length = 0;\n }\n\n async processResource(resourceName: string): Promise<void> {\n // Do nothing because sounds are light enough to be parsed in background.\n }\n\n async loadResource(resourceName: string): Promise<void> {\n const resource = this._resourceLoader.getResource(resourceName);\n if (!resource) {\n logger.warn(\n 'Unable to find audio for resource \"' + resourceName + '\".'\n );\n return;\n }\n if (resource.file) {\n if (this._availableResources[resource.name]) {\n return;\n }\n\n this._availableResources[resource.name] = resource;\n }\n\n const preloadAudioFile = (\n file: string,\n isMusic: boolean\n ): Promise<number> => {\n return new Promise((resolve, reject) => {\n const container = isMusic ? this._loadedMusics : this._loadedSounds;\n container[file] = new Howl(\n Object.assign({}, HowlParameters, {\n src: [this._resourceLoader.getFullUrl(file)],\n onload: resolve,\n onloaderror: (soundId: number, error?: string) => reject(error),\n html5: isMusic,\n xhr: {\n withCredentials: this._resourceLoader.checkIfCredentialsRequired(\n file\n ),\n },\n // Cache the sound with no volume. This avoids a bug where it plays at full volume\n // for a split second before setting its correct volume.\n volume: 0,\n })\n );\n });\n };\n\n const file = resource.file;\n if (resource.preloadAsMusic) {\n try {\n await preloadAudioFile(file, /* isMusic= */ true);\n } catch (error) {\n logger.warn(\n 'There was an error while preloading an audio file: ' + error\n );\n }\n }\n\n if (resource.preloadAsSound) {\n try {\n await preloadAudioFile(file, /* isMusic= */ false);\n } catch (error) {\n logger.warn(\n 'There was an error while preloading an audio file: ' + error\n );\n }\n } else if (\n resource.preloadInCache ||\n // Force downloading of sounds.\n // TODO Decide if sounds should be allowed to be downloaded after the scene starts.\n // - they should be requested automatically at the end of the scene loading\n // - they will be downloaded while the scene is playing\n // - other scenes will be pre-loaded only when all the sounds for the current scene are in cache\n !resource.preloadAsMusic\n ) {\n // preloading as sound already does a XHR request, hence \"else if\"\n try {\n await new Promise((resolve, reject) => {\n const sound = new XMLHttpRequest();\n sound.withCredentials = this._resourceLoader.checkIfCredentialsRequired(\n file\n );\n sound.addEventListener('load', resolve);\n sound.addEventListener('error', (_) =>\n reject('XHR error: ' + file)\n );\n sound.addEventListener('abort', (_) =>\n reject('XHR abort: ' + file)\n );\n sound.open('GET', this._resourceLoader.getFullUrl(file));\n sound.send();\n });\n } catch (error) {\n logger.warn(\n 'There was an error while preloading an audio file: ' + error\n );\n }\n }\n }\n\n /**\n * To be called when the game is disposed.\n * Unloads all audio from memory, clear Howl cache and stop all audio.\n */\n dispose(): void {\n this.unloadAll();\n }\n }\n\n // Register the class to let the engine use it.\n export const SoundManager = HowlerSoundManager;\n export type SoundManager = HowlerSoundManager;\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -1,2 +1,2 @@
1
- var gdjs;(function(c){const l=new c.Logger("JSON Manager"),u=["json","tilemap","tileset"];class i{constructor(r){this._loadedJsons=new c.ResourceCache;this._callbacks=new c.ResourceCache;this._getJsonResource=r=>{const s=this._resourceLoader.getResource(r);return s&&this.getResourceKinds().includes(s.kind)?s:null};this._resourceLoader=r}getResourceKinds(){return u}async loadResource(r){const s=this._resourceLoader.getResource(r);if(!s){l.warn('Unable to find json for resource "'+r+'".');return}if(!s.disablePreload)try{await this.loadJsonAsync(s.name)}catch(e){l.error(`Error while preloading json resource ${s.name}:`,e)}}loadJsonAsync(r){const s=this;return new Promise((e,t)=>{s.loadJson(r,(o,n)=>{o&&t(o.message),e(n)})})}async processResource(r){}loadJson(r,s){const e=this._getJsonResource(r);if(!e){s(new Error(`Can't find resource with name: "`+r+'" (or is not a json resource).'),null);return}if(this._loadedJsons.get(e)){s(null,this._loadedJsons.get(e));return}{const n=this._callbacks.get(e);if(n){n.push(s);return}else this._callbacks.set(e,[s])}const t=this,o=new XMLHttpRequest;o.responseType="json",o.withCredentials=this._resourceLoader.checkIfCredentialsRequired(e.file),o.open("GET",this._resourceLoader.getFullUrl(e.file)),o.onload=function(){const n=t._callbacks.get(e);if(!!n){if(o.status!==200){for(const a of n)a(new Error("HTTP error: "+o.status+"("+o.statusText+")"),null);t._callbacks.delete(e);return}t._loadedJsons.set(e,o.response);for(const a of n)a(null,o.response);t._callbacks.delete(e)}},o.onerror=function(){const n=t._callbacks.get(e);if(!!n){for(const a of n)a(new Error("Network error"),null);t._callbacks.delete(e)}},o.onabort=function(){const n=t._callbacks.get(e);if(!!n){for(const a of n)a(new Error("Request aborted"),null);t._callbacks.delete(e)}},o.send()}isJsonLoaded(r){return!!this._loadedJsons.getFromName(r)}getLoadedJson(r){return this._loadedJsons.getFromName(r)||null}}c.JsonManager=i})(gdjs||(gdjs={}));
1
+ var gdjs;(function(c){const l=new c.Logger("JSON Manager"),i=["json","tilemap","tileset"];class u{constructor(s){this._loadedJsons=new c.ResourceCache;this._callbacks=new c.ResourceCache;this._getJsonResource=s=>{const r=this._resourceLoader.getResource(s);return r&&this.getResourceKinds().includes(r.kind)?r:null};this._resourceLoader=s}getResourceKinds(){return i}async loadResource(s){const r=this._resourceLoader.getResource(s);if(!r){l.warn('Unable to find json for resource "'+s+'".');return}if(!r.disablePreload)try{await this.loadJsonAsync(r.name)}catch(e){l.error(`Error while preloading json resource ${r.name}:`,e)}}loadJsonAsync(s){const r=this;return new Promise((e,t)=>{r.loadJson(s,(o,n)=>{o&&t(o.message),e(n)})})}async processResource(s){}loadJson(s,r){const e=this._getJsonResource(s);if(!e){r(new Error(`Can't find resource with name: "`+s+'" (or is not a json resource).'),null);return}if(this._loadedJsons.get(e)){r(null,this._loadedJsons.get(e));return}{const n=this._callbacks.get(e);if(n){n.push(r);return}else this._callbacks.set(e,[r])}const t=this,o=new XMLHttpRequest;o.responseType="json",o.withCredentials=this._resourceLoader.checkIfCredentialsRequired(e.file),o.open("GET",this._resourceLoader.getFullUrl(e.file)),o.onload=function(){const n=t._callbacks.get(e);if(!!n){if(o.status!==200){for(const a of n)a(new Error("HTTP error: "+o.status+"("+o.statusText+")"),null);t._callbacks.delete(e);return}t._loadedJsons.set(e,o.response);for(const a of n)a(null,o.response);t._callbacks.delete(e)}},o.onerror=function(){const n=t._callbacks.get(e);if(!!n){for(const a of n)a(new Error("Network error"),null);t._callbacks.delete(e)}},o.onabort=function(){const n=t._callbacks.get(e);if(!!n){for(const a of n)a(new Error("Request aborted"),null);t._callbacks.delete(e)}},o.send()}isJsonLoaded(s){return!!this._loadedJsons.getFromName(s)}getLoadedJson(s){return this._loadedJsons.getFromName(s)||null}dispose(){this._loadedJsons.clear(),this._callbacks.clear()}}c.JsonManager=u})(gdjs||(gdjs={}));
2
2
  //# sourceMappingURL=jsonmanager.js.map