diff --git a/FCHost.bat b/FCHost.bat new file mode 100644 index 0000000000000000000000000000000000000000..400243fc2b65360a807712f2986eb8c2ca6517ab --- /dev/null +++ b/FCHost.bat @@ -0,0 +1,25 @@ +@ECHO off +:: Free Cities FCHost Launcher - Windows + +:: run dependencyCheck.bat +CALL .\devTools\scripts\dependencyCheck.bat +SET CODE=%ERRORLEVEL% + +IF %CODE% EQU 69 ( + :: if exit code is 69, then we don't have all the dependencies we need + ECHO. + ECHO Dependencies not met. + ECHO. + EXIT /b 0 +) ELSE IF %CODE% EQU 0 ( + :: if exit code is 0, run FCHostInstallAndRun.js + CALL node devTools\scripts\FCHostInstallAndRun.js + EXIT /b 0 +) ELSE ( + :: if exit code is not 0, print error message + ECHO. + ECHO dependencyCheck.bat exited with code: %CODE% + ECHO Dependency check failed unexpectedly. + ECHO. + EXIT /b 0 +) diff --git a/FCHost.sh b/FCHost.sh new file mode 100755 index 0000000000000000000000000000000000000000..8464283545f3886ec14c881ec0108af12e319e4c --- /dev/null +++ b/FCHost.sh @@ -0,0 +1,24 @@ +#!/bin/bash + +# Free Cities FCHost Launcher - Unix + +# run dependencyCheck.sh +./devTools/scripts/dependencyCheck.sh +exitCode=$? +# exit code is now stored in $exitCode + +# if exit code is 69, then we don't have all the dependencies we need +if [[ $exitCode -eq 69 ]]; then + echo "Dependencies not met." + echo "" + exit 0 +# if exit code is not 0, print error message +elif [[ $exitCode -ne 0 ]]; then + echo "dependencyCheck.sh exited with code: $exitCode" + echo "Dependency check failed unexpectedly." + echo "" + exit 0 +# if exit code is 0, run FCHostInstallAndRun.js +else + node devTools/scripts/FCHostInstallAndRun.js +fi diff --git a/FCHost/.gitignore b/FCHost/.gitignore index 0c8b4c1c999e1e2ae5c9a61da951ddc483dab3ee..00e8d2bdbdac408ce9523ae1c3216684553414aa 100644 --- a/FCHost/.gitignore +++ b/FCHost/.gitignore @@ -2,6 +2,7 @@ CMakeCache.txt CMakeFiles Debug Release +Release.file x64 *.sln *.vcxproj @@ -11,4 +12,5 @@ libcef_dll_wrapper .vs cmake_install.cmake *.VC.db -GPUCache \ No newline at end of file +GPUCache +PreCompiledFCHost.zip diff --git a/devTools/scripts/FCHostInstallAndRun.js b/devTools/scripts/FCHostInstallAndRun.js new file mode 100644 index 0000000000000000000000000000000000000000..7184a331c5111e1a66167e6c6ac78659ce7528be --- /dev/null +++ b/devTools/scripts/FCHostInstallAndRun.js @@ -0,0 +1,187 @@ +// cSpell:ignore fchost, megajs + +// @ts-ignore +import jetpack from "fs-jetpack"; +import {execSync} from "child_process"; +import * as path from "path"; +import inquirer from 'inquirer'; +import {File} from 'megajs'; +import decompress from "decompress"; + +// location to save the zip file to +const zipLocation = path.join("fchost", "PreCompiledFCHost.zip"); + +// make sure settings.json exists and has all the required properties +execSync("node devTools/scripts/setup.js --settings"); + +// load settings.json +/** @type {import("./setup.js").Settings} */ +const settings = jetpack.read("settings.json", "json"); + +// link to pre-compiled fchost +let windowsLink = "https://mega.nz/file/AFhTxLxR#fQgZFswJHVLpLlY5BzhTPmUKtmISeHdJ065b_MW0700"; + +let wineExists = false; +try { + if (execSync("command -v wine").toString().trim() !== "") { wineExists = true; } +} catch (e) { + // fail silently + // console.log(e); +} + +let megaLink = ""; + +// if FCHost doesn't exist +if ( + jetpack.exists(path.join(settings.FCHostPath, "fchost.exe")) === false && + jetpack.exists(path.join(settings.FCHostPath, "fchost")) === false +) { + if (process.platform === "win32") { + megaLink = windowsLink; + } else { + if (wineExists === false) { + // there are no pre-compiled versions of FCHost for this os at this time and wine isn't installed. + console.log("There is not a pre-compiled version of FCHost available for your system at this time."); + console.log("You can still use FCHost, but you will have to manually build it yourself."); + console.log("Instructions for doing so are here: https://gitgud.io/pregmodfan/fc-pregmod/-/blob/pregmod-master/FCHost/Building_FCHost.txt"); + console.log("Alternatively you can install Wine (https://www.winehq.org/) and rerun this script to attempt to run the Windows version of FCHost."); + } else { + // use windows FCHost link + megaLink = windowsLink; + console.log("A native pre-compiled version of FCHost is not available for your os, but Wine is installed."); + console.log("Selected the pre-compiled Windows version of FCHost for download."); + } + } + + // ask user if they want to download FCHost + if ( + megaLink !== "" + ) { + console.log("This script will download, extract, and run FCHost."); + // ask the users permission to download FCHost + let choice; + // @ts-ignore + await inquirer + .prompt([{ + type: "rawlist", + name: "choice", + message: `Do you want to download and extract a pre-compiled version of FCHost from '${megaLink}'?`, + choices: ["Yes", "No"], + default: "Yes", + loop: false + }]) + .then((answers) => { + choice = answers.choice; + }); + if (choice === "Yes") { + // download FCHost + const file = File.fromURL(megaLink); + + // @ts-ignore + await file.loadAttributes(); + console.log(`Downloading ${file.name} with a size of ${file.size} bytes`); + + // if zipLocation exists then remove it + jetpack.remove(zipLocation); + + // @ts-ignore + const data = await file.downloadBuffer(); + // check that buffer size is the same as file.size + if (data.byteLength !== file.size) { + console.log(`File did not download correctly! There is a ${file.size - data.byteLength} byte size difference.}`); + console.log("Rerun this script to try again."); + process.exit(); + } + jetpack.write(zipLocation, data, {atomic: true}); + + // create settings.FCHostPath directory + if (jetpack.exists(settings.FCHostPath) === "file") { + // I don't know how we got both a folder and a file with the same name, but that is invalid on Windows + // Renaming it to `${settings.FCHostPath}.file` should be okay since anyone manually compiling should be recreating the file anyway + jetpack.move(settings.FCHostPath, settings.FCHostPath + ".file"); + } + jetpack.dir(settings.FCHostPath); + // extract FCHost + // @ts-ignore + await decompress(zipLocation, settings.FCHostPath).then(files => { + // find the FCHost folder in releases + /** @type {string[]|string} */ + let folder = jetpack.find(settings.FCHostPath, { + matching: "FCHost*", files: false, directories: true, recursive: false + }); + if (folder.length === 0) { + console.log("Zip file extraction failed!"); + jetpack.remove(settings.FCHostPath); + process.exit(); + } else { + // move contents of folder[0] to settings.FCHostPath + jetpack.find(folder[0]).forEach(element => { + jetpack.move(element, path.join(settings.FCHostPath, path.relative(folder[0], element))); + }); + // remove folder[0] + jetpack.remove(folder[0]); + console.log('Zip file extracted successfully!'); + } + }); + // delete zip file + jetpack.remove(zipLocation); + } else { + console.log("You can run this script at any time if you change your mind."); + console.log("You can also manually compile FCHost if you wish."); + console.log("Instructions for doing so are here: https://gitgud.io/pregmodfan/fc-pregmod/-/blob/pregmod-master/FCHost/Building_FCHost.txt"); + process.exit(); + } + } +} + +if ( + jetpack.exists(path.join(settings.FCHostPath, "fchost.exe")) === false && + jetpack.exists(path.join(settings.FCHostPath, "fchost")) === false +) { + console.log(`FCHost doesn't exist at "${settings.FCHostPath}"`); + console.log("You can manually compile FCHost if you wish."); + console.log("Instructions for doing so are here: https://gitgud.io/pregmodfan/fc-pregmod/-/blob/pregmod-master/FCHost/Building_FCHost.txt"); + process.exit(); +} + +// if FC_pregmod.html is not in settings.FCHostPath +if (jetpack.exists(path.join(settings.FCHostPath, "FC_pregmod.html")) !== "file") { + console.log(`There doesn't seem to be a FC_pregmod.html file at ${settings.FCHostPath}`); + console.log("Running the compiler with it's default settings should fix this problem."); + let choice; + // @ts-ignore + await inquirer + .prompt([{ + type: "rawlist", + name: "choice", + message: `Do want to run the compiler now?`, + choices: ["Yes", "No"], + default: "Yes", + loop: false + }]) + .then((answers) => { + choice = answers.choice; + }); + if (choice === "Yes") { + try { + execSync("node devTools/scripts/advancedCompiler.js --skip-sanity-checks --no-interaction", {stdio: "inherit"}); + } catch (e) { + console.log(e); + } + } +} + +// launch FCHost +// cd into settings.FCHostPath +process.chdir(settings.FCHostPath); +console.log("Launching FCHost"); +if (process.platform === "win32") { + // run fchost + execSync("fchost.exe", {stdio: "inherit"}); +} else if (wineExists === true) { + console.log("Using Wine to run the Windows version of FCHost"); + execSync("wine fchost.exe", {stdio: "inherit"}); +} else { + // run fchost + execSync("./fchost", {stdio: "inherit"}); +} diff --git a/devTools/scripts/advancedCompiler.js b/devTools/scripts/advancedCompiler.js index 0eadef0df4fbbe0027dac382da2f58a8aa7ceeb3..a888e473cb8fdc6ac152ab5d038e71edacb924e6 100644 --- a/devTools/scripts/advancedCompiler.js +++ b/devTools/scripts/advancedCompiler.js @@ -23,6 +23,11 @@ const args = yargs(hideBin(process.argv)) description: 'The filename to save the compiled HTML file as', default: "FC_pregmod.html" }) + .option('skip-sanity-checks', { + type: 'boolean', + description: 'If true sanity checks will be skipped regardless of settings', + default: false, + }) .parse(); const batSh = (process.platform === "win32") ? "bat" : "sh"; @@ -50,7 +55,7 @@ if (settings.compilerMode === "simple") { command += ` --themes`; } } else { - if (settings.compilerRunSanityChecks === 1) { + if (settings.compilerRunSanityChecks === 1 && args.skipSanityChecks === false) { try { execSync( `node devTools/scripts/sanityCheck.js${args.interaction ? "" : " --no-interaction"}`, @@ -122,7 +127,7 @@ if (settings.compilerCopyToFCHost === true) { } } -if (settings.compilerMode === "advanced" && settings.compilerRunSanityChecks === 2) { +if (settings.compilerMode === "advanced" && settings.compilerRunSanityChecks === 2 && args.skipSanityChecks === false) { try { execSync( `node devTools/scripts/sanityCheck.js${args.interaction ? "" : " --no-interaction"}`, diff --git a/package.json b/package.json index 2f38d3d8c84b3d186a282014c581ad30a3dcf1a9..ef97ab154d723e621ee1f3866d40db866ac1ec60 100644 --- a/package.json +++ b/package.json @@ -38,12 +38,14 @@ "@types/twine-sugarcube": "^2.36.1", "ansi-colors": "^4.1.3", "cspell": "^8.3.2", + "decompress": "^4.2.1", "eslint": "^8.0.0", "eslint-plugin-jsdoc": "^46.0.0", "eslint-plugin-sonarjs": "^0.23.0", "http-server": "^14.1.1", "indefinite": "^2.4.3", "inquirer": "^9.2.15", + "megajs": "^1.1.8", "node-watch": "^0.7.4", "strip-ansi": "^7.1.0", "ts-essentials": "^9.1.1",