Home Reference Source

cables_dev/cables/src/core/loadingstatus.js

  1. import { Logger } from "cables-shared-client";
  2. import { generateUUID } from "./utils.js";
  3. import { EventTarget } from "./eventtarget.js";
  4.  
  5. /**
  6. * LoadingStatus class, manages asynchronous loading jobs
  7. *
  8. * @namespace external:CABLES#LoadingStatus
  9. * @hideconstructor
  10. * @class
  11. * @param patch
  12. */
  13. const LoadingStatus = function (patch)
  14. {
  15. EventTarget.apply(this);
  16.  
  17. this._log = new Logger("LoadingStatus");
  18. this._loadingAssets = {};
  19. this._cbFinished = [];
  20. this._assetTasks = [];
  21. this._percent = 0;
  22. this._count = 0;
  23. this._countFinished = 0;
  24. this._order = 0;
  25. this._startTime = 0;
  26. this._patch = patch;
  27. this._wasFinishedPrinted = false;
  28. this._loadingAssetTaskCb = false;
  29. };
  30.  
  31. LoadingStatus.prototype.setOnFinishedLoading = function (cb)
  32. {
  33. this._cbFinished.push(cb);
  34. };
  35.  
  36. LoadingStatus.prototype.getNumAssets = function ()
  37. {
  38. return this._countFinished;
  39. };
  40.  
  41. LoadingStatus.prototype.getProgress = function ()
  42. {
  43. return this._percent;
  44. };
  45.  
  46. LoadingStatus.prototype.checkStatus = function ()
  47. {
  48. this._countFinished = 0;
  49. this._count = 0;
  50.  
  51. for (const i in this._loadingAssets)
  52. {
  53. this._count++;
  54. if (!this._loadingAssets[i].finished)
  55. {
  56. this._countFinished++;
  57. }
  58. }
  59.  
  60. this._percent = (this._count - this._countFinished) / this._count;
  61.  
  62. if (this._countFinished === 0)
  63. {
  64. for (let j = 0; j < this._cbFinished.length; j++)
  65. {
  66. if (this._cbFinished[j])
  67. {
  68. const cb = this._cbFinished[j];
  69. setTimeout(() => { cb(this._patch); this.emitEvent("finishedAll"); }, 100);
  70. }
  71. }
  72.  
  73. if (!this._wasFinishedPrinted)
  74. {
  75. this._wasFinishedPrinted = true;
  76. this.print();
  77. }
  78. this.emitEvent("finishedAll");
  79. }
  80. };
  81.  
  82. LoadingStatus.prototype.getList = function ()
  83. {
  84. let arr = [];
  85. for (const i in this._loadingAssets)
  86. {
  87. arr.push(this._loadingAssets[i]);
  88. }
  89.  
  90. return arr;
  91. };
  92.  
  93.  
  94. LoadingStatus.prototype.getListJobs = function ()
  95. {
  96. let arr = [];
  97. for (const i in this._loadingAssets)
  98. {
  99. if (!this._loadingAssets[i].finished)arr.push(this._loadingAssets[i].name);
  100. }
  101.  
  102. return arr;
  103. };
  104.  
  105. LoadingStatus.prototype.print = function ()
  106. {
  107. if (this._patch.config.silent) return;
  108.  
  109. const rows = [];
  110.  
  111. for (const i in this._loadingAssets)
  112. {
  113. rows.push([
  114. this._loadingAssets[i].order,
  115. this._loadingAssets[i].type,
  116. this._loadingAssets[i].name,
  117. (this._loadingAssets[i].timeEnd - this._loadingAssets[i].timeStart) / 1000 + "s",
  118. ]);
  119. }
  120.  
  121. this._log.groupCollapsed("finished loading " + this._order + " assets in " + (Date.now() - this._startTime) / 1000 + "s");
  122. this._log.table(rows);
  123. this._log.groupEnd();
  124. };
  125.  
  126. LoadingStatus.prototype.finished = function (id)
  127. {
  128. const l = this._loadingAssets[id];
  129. if (l)
  130. {
  131. if (l.finished) this._log.warn("loading job was already finished", l);
  132.  
  133. if (l.op) l.op.setUiAttribs({ "loading": false });
  134. l.finished = true;
  135. l.timeEnd = Date.now();
  136. }
  137.  
  138. this.checkStatus();
  139. this.emitEvent("finishedTask");
  140. return null;
  141. };
  142.  
  143. LoadingStatus.prototype._startAssetTasks = function ()
  144. {
  145. for (let i = 0; i < this._assetTasks.length; i++) this._assetTasks[i]();
  146. this._assetTasks.length = 0;
  147. };
  148.  
  149. /**
  150. * delay an asset loading task, mainly to wait for ui to be finished loading and showing, and only then start loading assets
  151. * @function addAssetLoadingTask
  152. * @instance
  153. * @memberof LoadingStatus
  154. * @param {function} cb callback
  155. */
  156. LoadingStatus.prototype.addAssetLoadingTask = function (cb)
  157. {
  158. if (this._patch.isEditorMode() && !CABLES.UI.loaded)
  159. {
  160. this._assetTasks.push(cb);
  161.  
  162. if (!this._loadingAssetTaskCb)window.gui.addEventListener("uiloaded", this._startAssetTasks.bind(this));
  163. this._loadingAssetTaskCb = true;
  164. }
  165. else
  166. {
  167. cb();
  168. }
  169. this.emitEvent("addAssetTask");
  170. };
  171.  
  172. LoadingStatus.prototype.existByName = function (name)
  173. {
  174. for (let i in this._loadingAssets)
  175. {
  176. if (this._loadingAssets[i].name == name && !this._loadingAssets[i].finished)
  177. return true;
  178. }
  179. };
  180.  
  181. LoadingStatus.prototype.start = function (type, name, op)
  182. {
  183. if (this._startTime == 0) this._startTime = Date.now();
  184. const id = generateUUID();
  185.  
  186. name = name || "unknown";
  187. if (name.length > 100)name = name.substring(0, 100);
  188.  
  189.  
  190. if (op)op.setUiAttribs({ "loading": true });
  191.  
  192. this._loadingAssets[id] = {
  193. "id": id,
  194. "op": op,
  195. "type": type,
  196. "name": name,
  197. "finished": false,
  198. "timeStart": Date.now(),
  199. "order": this._order,
  200. };
  201. this._order++;
  202.  
  203. this.emitEvent("startTask");
  204.  
  205. return id;
  206. };
  207.  
  208. export { LoadingStatus };