interop.ts 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. //
  2. // Copyright (c) 2014-2015, THUNDERBEAST GAMES LLC All rights reserved
  3. // LICENSE: Atomic Game Engine Editor and Tools EULA
  4. // Please see LICENSE_ATOMIC_EDITOR_AND_TOOLS.md in repository root for
  5. // license information: https://github.com/AtomicGameEngine/AtomicGameEngine
  6. //
  7. // This is the interop file, exposing functions that can be called by the host game engine
  8. import * as editorCommands from "./editor/editorCommands";
  9. /**
  10. * Port to attach Chrome Dev Tools to
  11. * @type {Number}
  12. */
  13. const DEBUG_PORT = 3335;
  14. /**
  15. * Display "Attach dev tools now" alert on startup if this is set to true
  16. * @type {Boolean}
  17. */
  18. const DEBUG_ALERT = false;
  19. /**
  20. * Promise version of atomic query
  21. * @param {string} message the query to use to pass to atomicQuery. If there is no payload, this will be passed directly, otherwise it will be passed in a data object
  22. * @param {any} payload optional data to send
  23. * @return {Promise}
  24. */
  25. function atomicQueryPromise(message: any): Promise<{}> {
  26. return new Promise(function(resolve, reject) {
  27. let queryMessage = message;
  28. // if message is coming in as an object then let's stringify it
  29. if (typeof (message) != "string") {
  30. queryMessage = JSON.stringify(message);
  31. }
  32. window.atomicQuery({
  33. request: queryMessage,
  34. persistent: false,
  35. onSuccess: resolve,
  36. onFailure: (error_code, error_message) => reject({ error_code: error_code, error_message: error_message })
  37. });
  38. });
  39. }
  40. export default class HostInteropType {
  41. private static _inst: HostInteropType = null;
  42. static getInstance(): HostInteropType {
  43. if (HostInteropType._inst == null) {
  44. HostInteropType._inst = new HostInteropType();
  45. }
  46. return HostInteropType._inst;
  47. }
  48. static EDITOR_SAVE_CODE = "editorSaveCode";
  49. static EDITOR_SAVE_FILE = "editorSaveFile";
  50. static EDITOR_LOAD_COMPLETE = "editorLoadComplete";
  51. static EDITOR_CHANGE = "editorChange";
  52. constructor() {
  53. // Set up the window object so the host can call into it
  54. window.HOST_loadCode = this.loadCode.bind(this);
  55. window.HOST_saveCode = this.saveCode.bind(this);
  56. window.HOST_projectUnloaded = this.projectUnloaded.bind(this);
  57. window.HOST_resourceRenamed = this.resourceRenamed.bind(this);
  58. window.HOST_resourceDeleted = this.resourceDeleted.bind(this);
  59. }
  60. /**
  61. * Called from the host to notify the client what file to load
  62. * @param {string} codeUrl
  63. */
  64. loadCode(codeUrl: string) {
  65. console.log("Load Code called for :" + codeUrl);
  66. const fileExt = codeUrl.split(".").pop();
  67. const filename = codeUrl.replace("atomic://", "");
  68. // go ahead and set the theme prior to pulling the file across
  69. editorCommands.configure(fileExt, filename);
  70. // get the code
  71. this.getResource(codeUrl).then((src: string) => {
  72. editorCommands.loadCodeIntoEditor(src, filename, fileExt);
  73. }).catch((e: Editor.ClientExtensions.AtomicErrorMessage) => {
  74. console.log("Error loading code: " + e.error_message);
  75. });
  76. }
  77. /**
  78. * Save the contents of the editor
  79. * @return {Promise}
  80. */
  81. saveCode(): Promise<{}> {
  82. return atomicQueryPromise({
  83. message: HostInteropType.EDITOR_SAVE_CODE,
  84. payload: editorCommands.getSourceText()
  85. });
  86. }
  87. /**
  88. * Save the contents of a file as filename
  89. * @param {string} filename
  90. * @param {string} fileContents
  91. * @return {Promise}
  92. */
  93. saveFile(filename: string, fileContents: string): Promise<{}> {
  94. return atomicQueryPromise({
  95. message: HostInteropType.EDITOR_SAVE_FILE,
  96. filename: filename,
  97. payload: fileContents
  98. });
  99. }
  100. /**
  101. * Call this function when the client is fully loaded up. This will notify the host that
  102. * it can start loading code
  103. */
  104. editorLoaded() {
  105. if (DEBUG_ALERT) {
  106. alert(`Attach chrome dev tools to this instance by navigating to http://localhost:${DEBUG_PORT}`);
  107. }
  108. atomicQueryPromise(HostInteropType.EDITOR_LOAD_COMPLETE);
  109. }
  110. /**
  111. * Queries the host for a particular resource and returns it in a promise
  112. * @param {string} codeUrl
  113. * @return {Promise}
  114. */
  115. getResource(codeUrl: string): Promise<{}> {
  116. return new Promise(function(resolve, reject) {
  117. const xmlHttp = new XMLHttpRequest();
  118. xmlHttp.onreadystatechange = () => {
  119. if (xmlHttp.readyState == 4 && xmlHttp.status == 200) {
  120. resolve(xmlHttp.responseText);
  121. }
  122. };
  123. xmlHttp.open("GET", codeUrl, true); // true for asynchronous
  124. xmlHttp.send(null);
  125. });
  126. }
  127. /**
  128. * Returns a file resource from the resources directory
  129. * @param {string} filename name and path of file under the project directory or a fully qualified file name
  130. * @return {Promise}
  131. */
  132. getFileResource(filename: string): Promise<{}> {
  133. return this.getResource(`atomic://${filename}`);
  134. }
  135. /**
  136. * Notify the host that the contents of the editor has changed
  137. */
  138. notifyEditorChange() {
  139. atomicQueryPromise(HostInteropType.EDITOR_CHANGE).catch((e: Editor.ClientExtensions.AtomicErrorMessage) => {
  140. console.log("Error on change: " + e.error_message);
  141. });
  142. }
  143. /**
  144. * Notify that the project has been unloaded
  145. */
  146. projectUnloaded() {
  147. editorCommands.projectUnloaded();
  148. }
  149. /**
  150. * Notify that a resource has been renamed
  151. * @param {string} path
  152. * @param {string} newPath
  153. */
  154. resourceRenamed(path: string, newPath: string) {
  155. editorCommands.resourceRenamed(path, newPath);
  156. }
  157. /**
  158. * Notify that a resource has been deleted
  159. * @param {string} path
  160. */
  161. resourceDeleted(path: string) {
  162. editorCommands.resourceDeleted(path);
  163. }
  164. }
  165. HostInteropType.getInstance().editorLoaded();