Source: Engines/Wine/QuickScript/Steam Script/script.js

  1. const QuickScript = include("engines.wine.quick_script.quick_script");
  2. const Downloader = include("utils.functions.net.download");
  3. const Wine = include("engines.wine.engine.object");
  4. const { cat, fileExists, writeToFile, createTempFile } = include("utils.functions.filesystem.files");
  5. const Luna = include("engines.wine.verbs.luna");
  6. const Corefonts = include("engines.wine.verbs.corefonts");
  7. const OverrideDLL = include("engines.wine.plugins.override_dll");
  8. const WindowsVersion = include("engines.wine.plugins.windows_version");
  9. const Thread = Java.type("java.lang.Thread");
  10. module.default = class SteamScript extends QuickScript {
  11. constructor() {
  12. super();
  13. this._executable = "steam.exe";
  14. this._category = "Games";
  15. this._gameOverlay = true;
  16. }
  17. appId(appId) {
  18. this._appId = appId;
  19. return this;
  20. }
  21. gameOverlay(gameOverlay) {
  22. // get
  23. if (arguments.length == 0) {
  24. return this._gameOverlay;
  25. }
  26. // set
  27. this._gameOverlay = gameOverlay;
  28. return this;
  29. }
  30. manifest(wine) {
  31. if (!this._manifest) {
  32. // cache manifest path (will not change during the installation)
  33. this._manifest = `${wine.prefixDirectory()}/drive_c/${wine.programFiles()}/Steam/steamapps/appmanifest_${
  34. this._appId
  35. }.acf`;
  36. }
  37. return this._manifest;
  38. }
  39. /**
  40. * Checks whether the software download has started
  41. *
  42. * @param {Wine} wine The wine engine object
  43. * @returns {boolean} True if the download has started, false otherwise
  44. */
  45. downloadStarted(wine) {
  46. if (fileExists(this.manifest(wine))) {
  47. const manifest = cat(this.manifest(wine));
  48. const state = parseInt(manifest.match(/"StateFlags"\s+"(\d+)"/)[1], 10);
  49. return state == 1026 || state == 1042 || state == 1062 || state == 1030;
  50. } else {
  51. return false;
  52. }
  53. }
  54. /**
  55. * Checks whether the software download has finished.
  56. * To get a valid result with this method `downloadStarted(wine)` needs to return `true` first
  57. *
  58. * @param {Wine} wine The wine engine object
  59. * @returns {boolean} True if the download has finished, false otherwise
  60. */
  61. downloadFinished(wine) {
  62. // check if download already finished (download folder has been deleted)
  63. if (fileExists(this.manifest(wine))) {
  64. const manifest = cat(this.manifest(wine));
  65. const state = parseInt(manifest.match(/"StateFlags"\s+"(\d+)"/)[1], 10);
  66. return state != 1026 && state != 1042 && state != 1062 && state != 1030;
  67. } else {
  68. return false;
  69. }
  70. }
  71. configVdf(wine) {
  72. if (!this._configVdf) {
  73. // cache config.vdf path (will not change during the installation)
  74. this._configVdf = `${wine.prefixDirectory()}/drive_c/${wine.programFiles()}/Steam/config/config.vdf`;
  75. }
  76. return this._configVdf;
  77. }
  78. // Fix for the "content server unavailable" error (Wine bug 45329)
  79. fixCertificateIssue(wine) {
  80. const steamConfigFile = this.configVdf(wine);
  81. const steamConfig = cat(steamConfigFile);
  82. const cmPos = steamConfig.indexOf(`"CM"`);
  83. const csConfig = `"CS" "valve511.steamcontent.com;valve501.steamcontent.com;valve517.steamcontent.com;valve557.steamcontent.com;valve513.steamcontent.com;valve535.steamcontent.com;valve546.steamcontent.com;valve538.steamcontent.com;valve536.steamcontent.com;valve530.steamcontent.com;valve559.steamcontent.com;valve545.steamcontent.com;valve518.steamcontent.com;valve548.steamcontent.com;valve555.steamcontent.com;valve556.steamcontent.com;valve506.steamcontent.com;valve544.steamcontent.com;valve525.steamcontent.com;valve567.steamcontent.com;valve521.steamcontent.com;valve510.steamcontent.com;valve542.steamcontent.com;valve519.steamcontent.com;valve526.steamcontent.com;valve504.steamcontent.com;valve500.steamcontent.com;valve554.steamcontent.com;valve562.steamcontent.com;valve524.steamcontent.com;valve502.steamcontent.com;valve505.steamcontent.com;valve547.steamcontent.com;valve560.steamcontent.com;valve503.steamcontent.com;valve507.steamcontent.com;valve553.steamcontent.com;valve520.steamcontent.com;valve550.steamcontent.com;valve531.steamcontent.com;valve558.steamcontent.com;valve552.steamcontent.com;valve563.steamcontent.com;valve540.steamcontent.com;valve541.steamcontent.com;valve537.steamcontent.com;valve528.steamcontent.com;valve523.steamcontent.com;valve512.steamcontent.com;valve532.steamcontent.com;valve561.steamcontent.com;valve549.steamcontent.com;valve522.steamcontent.com;valve514.steamcontent.com;valve551.steamcontent.com;valve564.steamcontent.com;valve543.steamcontent.com;valve565.steamcontent.com;valve529.steamcontent.com;valve539.steamcontent.com;valve566.steamcontent.com;valve165.steamcontent.com;valve959.steamcontent.com;valve164.steamcontent.com;valve1611.steamcontent.com;valve1601.steamcontent.com;valve1617.steamcontent.com;valve1603.steamcontent.com;valve1602.steamcontent.com;valve1610.steamcontent.com;valve1615.steamcontent.com;valve909.steamcontent.com;valve900.steamcontent.com;valve905.steamcontent.com;valve954.steamcontent.com;valve955.steamcontent.com;valve1612.steamcontent.com;valve1607.steamcontent.com;valve1608.steamcontent.com;valve1618.steamcontent.com;valve1619.steamcontent.com;valve1606.steamcontent.com;valve1605.steamcontent.com;valve1609.steamcontent.com;valve907.steamcontent.com;valve901.steamcontent.com;valve902.steamcontent.com;valve1604.steamcontent.com;valve908.steamcontent.com;valve950.steamcontent.com;valve957.steamcontent.com;valve903.steamcontent.com;valve1614.steamcontent.com;valve904.steamcontent.com;valve952.steamcontent.com;valve1616.steamcontent.com;valve1613.steamcontent.com;valve958.steamcontent.com;valve956.steamcontent.com;valve906.steamcontent.com"\n`;
  84. const newSteamConfig = steamConfig.slice(0, cmPos) + csConfig + steamConfig.slice(cmPos);
  85. writeToFile(steamConfigFile, newSteamConfig);
  86. }
  87. go() {
  88. // default application homepage if not specified
  89. if (!this._applicationHomepage) {
  90. this._applicationHomepage = `https://store.steampowered.com/app/${this._appId}`;
  91. }
  92. // default executable args if not specified
  93. if (!this._executableArgs) {
  94. this._executableArgs = ["-no-cef-sandbox", "-silent", "-applaunch", `${this._appId}`];
  95. }
  96. const setupWizard = SetupWizard(InstallationType.APPS, this._name, this.miniature());
  97. setupWizard.presentation(this._name, this._editor, this._applicationHomepage, this._author);
  98. this._determineWineVersion(setupWizard);
  99. const tempFile = createTempFile("exe");
  100. new Downloader()
  101. .wizard(setupWizard)
  102. .url("https://steamcdn-a.akamaihd.net/client/installer/SteamSetup.exe")
  103. .checksum("1e5598f2de49fed2e81f3dd8630c7346a2b89487")
  104. .to(tempFile)
  105. .get();
  106. const wine = new Wine()
  107. .wizard(setupWizard)
  108. .prefix(this._name, this._wineDistribution, this._wineArchitecture, this._wineVersion);
  109. new Luna(wine).go();
  110. new Corefonts(wine).go();
  111. // Steam must be started once such that config.vdf is created (see fixCertificateIssue())
  112. setupWizard.wait(
  113. tr(
  114. 'Please follow the steps of the Steam setup. Then, wait until Steam is updated, log in and finally close Steam completely so the installation of "{0}" can continue.',
  115. this._name
  116. )
  117. );
  118. wine.run(tempFile, [], null, false, true);
  119. // Fix for Uplay games that are executed on steam
  120. new WindowsVersion(wine)
  121. .withApplicationWindowsVersion("upc.exe", "winvista")
  122. .withApplicationWindowsVersion("UbisoftGameLauncher.exe", "winvista")
  123. .go();
  124. // ensure that Steam is running (user might have unchecked "run Steam after installation finished")
  125. wine.runInsidePrefix(`${wine.programFiles()}/Steam/steam.exe`, ["steam://nav/games"], false);
  126. // wait until config.vdf exists
  127. while (!fileExists(this.configVdf(wine))) {
  128. Thread.sleep(1000);
  129. }
  130. // wait until Steam and Wine are closed
  131. wine.wait();
  132. this.fixCertificateIssue(wine);
  133. // Steam installation has finished
  134. setupWizard.wait(tr("Please wait..."));
  135. this._preInstall(wine, setupWizard);
  136. // back to generic wait (might have been changed in preInstall)
  137. setupWizard.wait(tr("Please wait..."));
  138. wine.runInsidePrefix(`${wine.programFiles()}/Steam/steam.exe`, [`steam://install/${this._appId}`], false);
  139. setupWizard.wait(tr("Please wait until Steam has finished the download..."));
  140. // wait until download started
  141. while (!this.downloadStarted(wine)) {
  142. Thread.sleep(100);
  143. }
  144. // make sure download is finished
  145. while (!this.downloadFinished(wine)) {
  146. Thread.sleep(1000);
  147. }
  148. // close Steam
  149. wine.runInsidePrefix(`${wine.programFiles()}/Steam/steam.exe`, "-shutdown", true);
  150. // back to generic wait
  151. setupWizard.wait(tr("Please wait..."));
  152. // create shortcut after installation (if executable is specified, it does not exist earlier)
  153. this._createShortcut(wine.prefix());
  154. this._postInstall(wine, setupWizard);
  155. // deactivate game overlay if desired
  156. if (!this._gameOverlay) {
  157. new OverrideDLL(wine).withMode("", ["gameoverlayrenderer"]).go();
  158. }
  159. // back to generic wait (might have been changed in postInstall)
  160. setupWizard.wait(tr("Please wait..."));
  161. setupWizard.close();
  162. }
  163. };