actionbinder.js 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  1. const cp = require('child_process')
  2. const path = require('path')
  3. const {AssetGuard} = require(path.join(__dirname, 'assets', 'js', 'assetguard.js'))
  4. const ProcessBuilder = require(path.join(__dirname, 'assets', 'js', 'processbuilder.js'))
  5. const ConfigManager = require(path.join(__dirname, 'assets', 'js', 'configmanager.js'))
  6. const DiscordWrapper = require(path.join(__dirname, 'assets', 'js', 'discordwrapper.js'))
  7. const Mojang = require(path.join(__dirname, 'assets', 'js', 'mojang.js'))
  8. const AuthManager = require(path.join(__dirname, 'assets', 'js', 'authmanager.js'))
  9. let mojangStatusListener
  10. // Launch Elements
  11. let launch_content, launch_details, launch_progress, launch_progress_label, launch_details_text
  12. // Synchronous Listener
  13. document.addEventListener('readystatechange', function(){
  14. if (document.readyState === 'interactive'){
  15. // Save a reference to the launch elements.
  16. launch_content = document.getElementById('launch_content')
  17. launch_details = document.getElementById('launch_details')
  18. launch_progress = document.getElementById('launch_progress')
  19. launch_progress_label = document.getElementById('launch_progress_label')
  20. launch_details_text = document.getElementById('launch_details_text')
  21. // Bind launch button
  22. document.getElementById('launch_button').addEventListener('click', function(e){
  23. console.log('Launching game..')
  24. //testdownloads()
  25. dlAsync()
  26. })
  27. // TODO convert this to dropdown menu.
  28. // Bind selected server
  29. document.getElementById('server_selection').innerHTML = '\u2022 ' + AssetGuard.getServerById(ConfigManager.getGameDirectory(), ConfigManager.getSelectedServer()).name
  30. // Update Mojang Status Color
  31. const refreshMojangStatuses = async function(){
  32. console.log('Refreshing Mojang Statuses..')
  33. try {
  34. let status = 'grey'
  35. const statuses = await Mojang.status()
  36. greenCount = 0
  37. for(let i=0; i<statuses.length; i++){
  38. if(statuses[i].status === 'yellow' && status !== 'red'){
  39. status = 'yellow'
  40. continue
  41. } else if(statuses[i].status === 'red'){
  42. status = 'red'
  43. break
  44. }
  45. ++greenCount
  46. }
  47. if(greenCount == statuses.length){
  48. status = 'green'
  49. }
  50. document.getElementById('mojang_status_icon').style.color = Mojang.statusToHex(status)
  51. } catch (err) {
  52. console.error('Unable to refresh Mojang service status..', err)
  53. }
  54. }
  55. refreshMojangStatuses()
  56. // Set refresh rate to once every 5 minutes.
  57. mojangStatusListener = setInterval(refreshMojangStatuses, 300000)
  58. }
  59. }, false)
  60. // Keep reference to Minecraft Process
  61. let proc
  62. // Is DiscordRPC enabled
  63. let hasRPC = false
  64. // Joined server regex
  65. const servJoined = /[[0-2][0-9]:[0-6][0-9]:[0-6][0-9]\] \[Client thread\/INFO\]: \[CHAT\] [a-zA-Z0-9_]{1,16} joined the game/g
  66. const gameJoined = /\[[0-2][0-9]:[0-6][0-9]:[0-6][0-9]\] \[Client thread\/WARN\]: Skipping bad option: lastServer:/g
  67. const gameJoined2 = /\[[0-2][0-9]:[0-6][0-9]:[0-6][0-9]\] \[Client thread\/INFO\]: Created: \d+x\d+ textures-atlas/g
  68. let aEx
  69. let currentProc
  70. let serv
  71. let versionData
  72. let forgeData
  73. function dlAsync(login = true){
  74. // Login parameter is temporary for debug purposes. Allows testing the validation/downloads without
  75. // launching the game.
  76. if(login) {
  77. if(ConfigManager.getSelectedAccount() == null){
  78. console.error('login first.')
  79. //in devtools AuthManager.addAccount(username, pass)
  80. return
  81. }
  82. }
  83. launch_details_text.innerHTML = 'Please wait..'
  84. launch_progress.setAttribute('max', '100')
  85. launch_details.style.display = 'flex'
  86. launch_content.style.display = 'none'
  87. aEx = cp.fork(path.join(__dirname, 'assets', 'js', 'assetexec.js'), [
  88. ConfigManager.getGameDirectory(),
  89. ConfigManager.getJavaExecutable()
  90. ])
  91. aEx.on('message', (m) => {
  92. if(currentProc === 'validateDistribution'){
  93. launch_progress.setAttribute('value', 20)
  94. launch_progress_label.innerHTML = '20%'
  95. serv = m.result
  96. console.log('forge stuff done')
  97. // Begin version load.
  98. launch_details_text.innerHTML = 'Loading version information..'
  99. currentProc = 'loadVersionData'
  100. aEx.send({task: 0, content: currentProc, argsArr: [serv.mc_version]})
  101. } else if(currentProc === 'loadVersionData'){
  102. launch_progress.setAttribute('value', 40)
  103. launch_progress_label.innerHTML = '40%'
  104. versionData = m.result
  105. // Begin asset validation.
  106. launch_details_text.innerHTML = 'Validating asset integrity..'
  107. currentProc = 'validateAssets'
  108. aEx.send({task: 0, content: currentProc, argsArr: [versionData]})
  109. } else if(currentProc === 'validateAssets'){
  110. launch_progress.setAttribute('value', 60)
  111. launch_progress_label.innerHTML = '60%'
  112. console.log('assets done')
  113. // Begin library validation.
  114. launch_details_text.innerHTML = 'Validating library integrity..'
  115. currentProc = 'validateLibraries'
  116. aEx.send({task: 0, content: currentProc, argsArr: [versionData]})
  117. } else if(currentProc === 'validateLibraries'){
  118. launch_progress.setAttribute('value', 80)
  119. launch_progress_label.innerHTML = '80%'
  120. console.log('libs done')
  121. // Begin miscellaneous validation.
  122. launch_details_text.innerHTML = 'Validating miscellaneous file integrity..'
  123. currentProc = 'validateMiscellaneous'
  124. aEx.send({task: 0, content: currentProc, argsArr: [versionData]})
  125. } else if(currentProc === 'validateMiscellaneous'){
  126. launch_progress.setAttribute('value', 100)
  127. launch_progress_label.innerHTML = '100%'
  128. console.log('files done')
  129. launch_details_text.innerHTML = 'Downloading files..'
  130. currentProc = 'processDlQueues'
  131. aEx.send({task: 0, content: currentProc})
  132. } else if(currentProc === 'processDlQueues'){
  133. if(m.task === 0){
  134. remote.getCurrentWindow().setProgressBar(m.value/m.total)
  135. launch_progress.setAttribute('max', m.total)
  136. launch_progress.setAttribute('value', m.value)
  137. launch_progress_label.innerHTML = m.percent + '%'
  138. } else if(m.task === 1){
  139. remote.getCurrentWindow().setProgressBar(-1)
  140. launch_details_text.innerHTML = 'Preparing to launch..'
  141. currentProc = 'loadForgeData'
  142. aEx.send({task: 0, content: currentProc, argsArr: [serv.id]})
  143. } else {
  144. console.error('Unknown download data type.', m)
  145. }
  146. } else if(currentProc === 'loadForgeData'){
  147. forgeData = m.result
  148. if(login) {
  149. //if(!(await AuthManager.validateSelected())){
  150. //
  151. //}
  152. const authUser = ConfigManager.getSelectedAccount();
  153. console.log('authu', authUser)
  154. let pb = new ProcessBuilder(ConfigManager.getGameDirectory(), serv, versionData, forgeData, authUser)
  155. launch_details_text.innerHTML = 'Launching game..'
  156. try{
  157. proc = pb.build()
  158. launch_details_text.innerHTML = 'Done. Enjoy the server!'
  159. const tempListener = function(data){
  160. if(data.indexOf('[Client thread/INFO]: -- System Details --') > -1){
  161. launch_details.style.display = 'none'
  162. launch_content.style.display = 'inline-flex'
  163. if(hasRPC){
  164. DiscordWrapper.updateDetails('Loading game..')
  165. }
  166. proc.stdout.removeListener('data', tempListener)
  167. }
  168. }
  169. const gameStateChange = function(data){
  170. if(servJoined.test(data)){
  171. DiscordWrapper.updateDetails('Exploring the Realm!')
  172. } else if(gameJoined.test(data)){
  173. DiscordWrapper.updateDetails('Idling on Main Menu')
  174. }
  175. }
  176. proc.stdout.on('data', tempListener)
  177. proc.stdout.on('data', gameStateChange)
  178. // Init Discord Hook (Untested)
  179. const distro = AssetGuard.retrieveDistributionDataSync(ConfigManager.getGameDirectory)
  180. if(distro.discord != null && serv.discord != null){
  181. DiscordWrapper.initRPC(distro.discord, serv.discord)
  182. hasRPC = true
  183. proc.on('close', (code, signal) => {
  184. console.log('Shutting down Discord Rich Presence..')
  185. DiscordWrapper.shutdownRPC()
  186. hasRPC = false
  187. proc = null
  188. })
  189. }
  190. } catch(err) {
  191. //launch_details_text.innerHTML = 'Error: ' + err.message;
  192. launch_details_text.innerHTML = 'Error: See log for details..';
  193. console.log(err)
  194. setTimeout(function(){
  195. launch_details.style.display = 'none'
  196. launch_content.style.display = 'inline-flex'
  197. }, 5000)
  198. }
  199. }
  200. // Disconnect from AssetExec
  201. aEx.disconnect()
  202. }
  203. })
  204. launch_details_text.innerHTML = 'Loading server information..'
  205. currentProc = 'validateDistribution'
  206. aEx.send({task: 0, content: currentProc, argsArr: [ConfigManager.getSelectedServer()]})
  207. }