diff --git a/indigo-plugin/indigo-plugin/src/indigoplugin/IndigoOptions.scala b/indigo-plugin/indigo-plugin/src/indigoplugin/IndigoOptions.scala index e9bfd7f8b..5c823787f 100644 --- a/indigo-plugin/indigo-plugin/src/indigoplugin/IndigoOptions.scala +++ b/indigo-plugin/indigo-plugin/src/indigoplugin/IndigoOptions.scala @@ -1,5 +1,111 @@ package indigoplugin +/** Represents the various options that go into an Indigo game build. + * + * @param metadata + * Metadata about your game, such as the title. + * @param assets + * Represents you game's assets processing. + * @param electron + * Represents options specific to Electron builds of your game. + */ +final case class IndigoOptions( + metadata: IndigoGameMetadata, + assets: IndigoAssets, + electron: IndigoElectronOptions +) { + + /** Sets a new title for your game's window / title bar / tab */ + def withTitle(newTitle: String): IndigoOptions = + this.copy(metadata = metadata.withTitle(newTitle)) + + /** Make the cursor visible */ + def cursorVisible: IndigoOptions = + this.copy(metadata = metadata.cursorVisible) + + /** Hide the cursor */ + def cursorHidden: IndigoOptions = + this.copy(metadata = metadata.cursorHidden) + + /** Sets the background color, any valid CSS color representation acceptable, e.g. 'black' or '#000000' */ + def withBackgroundColor(cssColorValue: String): IndigoOptions = + this.copy(metadata = metadata.withBackgroundColor(cssColorValue)) + + /** Set the background color from RGBA values */ + def withBackgroundColor(r: Double, g: Double, b: Double, a: Double): IndigoOptions = + this.copy(metadata = metadata.withBackgroundColor(r, g, b, a)) + + /** Set the background color from RGB values */ + def withBackgroundColor(r: Double, g: Double, b: Double): IndigoOptions = + this.copy(metadata = metadata.withBackgroundColor(r, g, b)) + + /** Sets the asset directory path */ + def withAssetDirectory(path: String): IndigoOptions = + this.copy(assets = assets.withAssetDirectory(path)) + def withAssetDirectory(path: os.Path): IndigoOptions = + this.copy(assets = assets.withAssetDirectory(path)) + + /** Set the window start width */ + def withWindowWidth(value: Int): IndigoOptions = + this.copy(metadata = metadata.withWindowWidth(value)) + + /** Set the window start height */ + def withWindowHeight(value: Int): IndigoOptions = + this.copy(metadata = metadata.withWindowHeight(value)) + + /** Set the window start width */ + def withWindowSize(w: Int, h: Int): IndigoOptions = + this.copy(metadata = metadata.withWindowSize(w, h)) + + /** Electron will limit the frame rate using the default browser refresh rate, typically it will sync with your + * monitor's refresh rate. It is recommended that you do this, and set your indigo config to limit the framerate too. + */ + def electronLimitsFrameRate: IndigoOptions = + this.copy(electron = electron.electronLimitsFrameRate) + + /** Electron will not limit the frame rate. */ + def electronUnlimitedFrameRate: IndigoOptions = + this.copy(electron = electron.electronUnlimitedFrameRate) + + /** Sets the electron installation type. It is recommended that, during development at least, you set this to + * `ElectronInstall.Latest` to take advantage of performance improvements. + */ + def withElectronInstallType(value: ElectronInstall): IndigoOptions = + this.copy(electron = electron.withElectronInstallType(value)) + + /** Use the latest version of Electron with the `indigoRun` command, which will be installed with NPM. */ + def useLatestElectron: IndigoOptions = + withElectronInstallType(ElectronInstall.Latest) + + /** Use a globally installed version of Electron with the `indigoRun` command. Global installs of Electron have the + * advantage of a slightly faster `indigoRun` startup time, however, global Electron installs can be of dubious + * quality, and suffer from poor performance or limited features. Not recommended. + */ + def useGlobalElectron: IndigoOptions = + withElectronInstallType(ElectronInstall.Global) + + /** Use a specific version of Electron, follows normal NPM version formats. */ + def useElectronVersion(version: String): IndigoOptions = + withElectronInstallType(ElectronInstall.Version(version)) + + /** Use an Electron install at the specified path with the `indigoRun` command. */ + def useElectronExecutable(path: String): IndigoOptions = + withElectronInstallType(ElectronInstall.PathToExecutable(path)) + +} + +object IndigoOptions { + + /** Default configuration for an Indigo game. */ + val defaults: IndigoOptions = + IndigoOptions( + metadata = IndigoGameMetadata.defaults, + assets = IndigoAssets.defaults, + electron = IndigoElectronOptions.defaults + ) + +} + /** Represents the various options that go into an Indigo game build. * * @param title @@ -8,47 +114,37 @@ package indigoplugin * Show the cursor? Default 'true'. * @param backgroundColor * HTML page background color Default 'white'. - * @param gameAssetsDirectory - * Project relative path to a directory that contains all of the assets the game needs to load. Default './assets'. - * @param windowStartWidth + * @param width * Initial window width. Default '550'. - * @param windowStartHeight + * @param height * Initial window height. Default '400'. - * @param disableFrameRateLimit - * If possible, disables the runtime's frame rate limit, recommended to be `false`. Default 'false'. - * @param electronInstall - * How should electron be run? ElectronInstall.Global | ElectronInstall.Version(version: String) | - * ElectronInstall.Latest | ElectronInstall.PathToExecutable(path: String). Default 'ElectronInstall.Latest'. */ -final case class IndigoOptions( +final case class IndigoGameMetadata( title: String, showCursor: Boolean, backgroundColor: String, - gameAssetsDirectory: os.Path, - windowStartWidth: Int, - windowStartHeight: Int, - disableFrameRateLimit: Boolean, - electronInstall: ElectronInstall + width: Int, + height: Int ) { /** Sets a new title for your game's window / title bar / tab */ - def withTitle(newTitle: String): IndigoOptions = + def withTitle(newTitle: String): IndigoGameMetadata = this.copy(title = newTitle) /** Make the cursor visible */ - def cursorVisible: IndigoOptions = + def cursorVisible: IndigoGameMetadata = this.copy(showCursor = true) /** Hide the cursor */ - def cursorHidden: IndigoOptions = + def cursorHidden: IndigoGameMetadata = this.copy(showCursor = false) /** Sets the background color, any valid CSS color representation acceptable, e.g. 'black' or '#000000' */ - def withBackgroundColor(cssColorValue: String): IndigoOptions = + def withBackgroundColor(cssColorValue: String): IndigoGameMetadata = this.copy(backgroundColor = cssColorValue) /** Set the background color from RGBA values */ - def withBackgroundColor(r: Double, g: Double, b: Double, a: Double): IndigoOptions = { + def withBackgroundColor(r: Double, g: Double, b: Double, a: Double): IndigoGameMetadata = { val convert: Double => String = d => { val hex = Integer.toHexString((Math.min(1, Math.max(0, d)) * 255).toInt) if (hex.length == 1) "0" + hex else hex @@ -57,7 +153,7 @@ final case class IndigoOptions( } /** Set the background color from RGB values */ - def withBackgroundColor(r: Double, g: Double, b: Double): IndigoOptions = { + def withBackgroundColor(r: Double, g: Double, b: Double): IndigoGameMetadata = { val convert: Double => String = d => { val hex = Integer.toHexString((Math.min(1, Math.max(0, d)) * 255).toInt) if (hex.length == 1) "0" + hex else hex @@ -65,73 +161,119 @@ final case class IndigoOptions( withBackgroundColor("#" + convert(r) + convert(g) + convert(b)) } - /** Sets the asset directory path */ - def withAssetDirectory(path: String): IndigoOptions = - this.copy( - gameAssetsDirectory = - if (path.startsWith("/")) os.Path(path) - else os.RelPath(path).resolveFrom(os.pwd) - ) - def withAssetDirectory(path: os.Path): IndigoOptions = - this.copy(gameAssetsDirectory = path) - /** Set the window start width */ - def withWindowStartWidth(value: Int): IndigoOptions = - this.copy(windowStartWidth = value) + def withWindowWidth(value: Int): IndigoGameMetadata = + this.copy(width = value) /** Set the window start height */ - def withWindowStartHeight(value: Int): IndigoOptions = - this.copy(windowStartHeight = value) + def withWindowHeight(value: Int): IndigoGameMetadata = + this.copy(height = value) + + /** Set the window start width */ + def withWindowSize(w: Int, h: Int): IndigoGameMetadata = + this.copy(width = w, height = h) + +} + +object IndigoGameMetadata { + + /** The default metadata for an Indigo game. */ + val defaults: IndigoGameMetadata = + IndigoGameMetadata( + title = "Made with Indigo", + showCursor = true, + backgroundColor = "white", + width = 550, + height = 400 + ) +} + +/** Represents options specific to Electron builds of your game. + * + * @param disableFrameRateLimit + * If possible, disables the runtime's frame rate limit, recommended to be `false`. Default 'false'. + * @param electronInstall + * How should electron be run? ElectronInstall.Global | ElectronInstall.Version(version: String) | + * ElectronInstall.Latest | ElectronInstall.PathToExecutable(path: String). Default 'ElectronInstall.Latest'. + */ +final case class IndigoElectronOptions( + disableFrameRateLimit: Boolean, + electronInstall: ElectronInstall +) { /** Electron will limit the frame rate using the default browser refresh rate, typically it will sync with your * monitor's refresh rate. It is recommended that you do this, and set your indigo config to limit the framerate too. */ - def electronLimitsFrameRate: IndigoOptions = + def electronLimitsFrameRate: IndigoElectronOptions = this.copy(disableFrameRateLimit = false) /** Electron will not limit the frame rate. */ - def electronUnlimitedFrameRate: IndigoOptions = + def electronUnlimitedFrameRate: IndigoElectronOptions = this.copy(disableFrameRateLimit = true) /** Sets the electron installation type. It is recommended that, during development at least, you set this to * `ElectronInstall.Latest` to take advantage of performance improvements. */ - def withElectronInstallType(value: ElectronInstall): IndigoOptions = + def withElectronInstallType(value: ElectronInstall): IndigoElectronOptions = this.copy(electronInstall = value) /** Use the latest version of Electron with the `indigoRun` command, which will be installed with NPM. */ - def useLatestElectron: IndigoOptions = + def useLatestElectron: IndigoElectronOptions = withElectronInstallType(ElectronInstall.Latest) /** Use a globally installed version of Electron with the `indigoRun` command. Global installs of Electron have the * advantage of a slightly faster `indigoRun` startup time, however, global Electron installs can be of dubious * quality, and suffer from poor performance or limited features. Not recommended. */ - def useGlobalElectron: IndigoOptions = + def useGlobalElectron: IndigoElectronOptions = withElectronInstallType(ElectronInstall.Global) /** Use a specific version of Electron, follows normal NPM version formats. */ - def useElectronVersion(version: String): IndigoOptions = + def useElectronVersion(version: String): IndigoElectronOptions = withElectronInstallType(ElectronInstall.Version(version)) /** Use an Electron install at the specified path with the `indigoRun` command. */ - def useElectronExecutable(path: String): IndigoOptions = + def useElectronExecutable(path: String): IndigoElectronOptions = withElectronInstallType(ElectronInstall.PathToExecutable(path)) } -object IndigoOptions { +object IndigoElectronOptions { - val defaults: IndigoOptions = - IndigoOptions( - title = "Made with Indigo", - showCursor = true, - backgroundColor = "white", - gameAssetsDirectory = os.pwd / "assets", - windowStartWidth = 550, - windowStartHeight = 400, + /** Default settings for Electron */ + val defaults: IndigoElectronOptions = + IndigoElectronOptions( disableFrameRateLimit = false, electronInstall = indigoplugin.ElectronInstall.Latest ) +} + +/** Represents you game's assets processing. + * + * @param gameAssetsDirectory + * Project relative path to a directory that contains all of the assets the game needs to load. Default './assets'. + */ +final case class IndigoAssets( + gameAssetsDirectory: os.Path +) { + /** Sets the asset directory path */ + def withAssetDirectory(path: String): IndigoAssets = + this.copy( + gameAssetsDirectory = + if (path.startsWith("/")) os.Path(path) + else os.RelPath(path).resolveFrom(os.pwd) + ) + def withAssetDirectory(path: os.Path): IndigoAssets = + this.copy(gameAssetsDirectory = path) + +} + +object IndigoAssets { + + /** Default settings for an Indigo game's asset management */ + val defaults: IndigoAssets = + IndigoAssets( + gameAssetsDirectory = os.pwd / "assets" + ) } diff --git a/indigo-plugin/indigo-plugin/src/indigoplugin/core/IndigoBuild.scala b/indigo-plugin/indigo-plugin/src/indigoplugin/core/IndigoBuild.scala index 275664651..6d85dc205 100644 --- a/indigo-plugin/indigo-plugin/src/indigoplugin/core/IndigoBuild.scala +++ b/indigo-plugin/indigo-plugin/src/indigoplugin/core/IndigoBuild.scala @@ -3,29 +3,30 @@ package indigoplugin.core import os._ import indigoplugin.templates.HtmlTemplate import indigoplugin.templates.SupportScriptTemplate -import indigoplugin.datatypes.TemplateOptions import indigoplugin.datatypes.DirectoryStructure import indigoplugin.utils.Utils +import indigoplugin.IndigoOptions object IndigoBuild { def build( - templateOptions: TemplateOptions, + scriptPathBase: Path, + options: IndigoOptions, directoryStructure: DirectoryStructure, scriptNames: List[String] ): Unit = { - val scriptName = findScriptName(scriptNames, templateOptions.scriptPathBase) + val scriptName = findScriptName(scriptNames, scriptPathBase) // copy built js file into scripts dir - IndigoBuild.copyScript(templateOptions, directoryStructure.artefacts, scriptName) + IndigoBuild.copyScript(scriptPathBase, directoryStructure.artefacts, scriptName) // copy assets into folder - IndigoBuild.copyAssets(templateOptions.gameAssetsDirectoryPath, directoryStructure.assets) + IndigoBuild.copyAssets(options.assets.gameAssetsDirectory, directoryStructure.assets) // copy built js source map file into scripts dir IndigoBuild.copyScript( - templateOptions, + scriptPathBase, directoryStructure.artefacts, scriptName + ".map" ) @@ -40,10 +41,10 @@ object IndigoBuild { // Fill out html template val html = HtmlTemplate.template( - templateOptions.title, - templateOptions.showCursor, + options.metadata.title, + options.metadata.showCursor, scriptName, - templateOptions.backgroundColor + options.metadata.backgroundColor ) // Write out file @@ -85,8 +86,8 @@ object IndigoBuild { } @SuppressWarnings(Array("org.wartremover.warts.Throw")) - def copyScript(templateOptions: TemplateOptions, destScriptsFolder: Path, fileName: String): Unit = { - val scriptFile = templateOptions.scriptPathBase / fileName + def copyScript(scriptPathBase: Path, destScriptsFolder: Path, fileName: String): Unit = { + val scriptFile = scriptPathBase / fileName if (os.exists(scriptFile)) os.copy(scriptFile, destScriptsFolder / fileName, true, false, false, false, false) diff --git a/indigo-plugin/indigo-plugin/src/indigoplugin/core/IndigoBuildMill.scala b/indigo-plugin/indigo-plugin/src/indigoplugin/core/IndigoBuildMill.scala index b50eb0660..287b2bb40 100644 --- a/indigo-plugin/indigo-plugin/src/indigoplugin/core/IndigoBuildMill.scala +++ b/indigo-plugin/indigo-plugin/src/indigoplugin/core/IndigoBuildMill.scala @@ -1,17 +1,18 @@ package indigoplugin.core import os._ -import indigoplugin.datatypes.TemplateOptions import indigoplugin.utils.AsciiLogo +import indigoplugin.IndigoOptions object IndigoBuildMill { - def build(baseDir: Path, templateOptions: TemplateOptions): Unit = { + def build(scriptPathBase: Path, baseDir: Path, options: IndigoOptions): Unit = { println(AsciiLogo.logo) IndigoBuild.build( - templateOptions, + scriptPathBase, + options, IndigoBuild.createDirectoryStructure(baseDir), List("main.js", "out.js") ) diff --git a/indigo-plugin/indigo-plugin/src/indigoplugin/core/IndigoBuildSBT.scala b/indigo-plugin/indigo-plugin/src/indigoplugin/core/IndigoBuildSBT.scala index 3b6d6af45..8f124647a 100644 --- a/indigo-plugin/indigo-plugin/src/indigoplugin/core/IndigoBuildSBT.scala +++ b/indigo-plugin/indigo-plugin/src/indigoplugin/core/IndigoBuildSBT.scala @@ -1,14 +1,15 @@ package indigoplugin.core import os._ -import indigoplugin.datatypes.TemplateOptions import indigoplugin.utils.AsciiLogo +import indigoplugin.IndigoOptions object IndigoBuildSBT { def build( + scriptPathBase: Path, baseDir: String, - templateOptions: TemplateOptions, + options: IndigoOptions, outputFolderName: String, scriptNames: List[String] ): Unit = { @@ -16,7 +17,8 @@ object IndigoBuildSBT { println(AsciiLogo.logo) IndigoBuild.build( - templateOptions, + scriptPathBase, + options, IndigoBuild.createDirectoryStructure(Path(baseDir) / "target" / outputFolderName), scriptNames ) diff --git a/indigo-plugin/indigo-plugin/src/indigoplugin/datatypes/TemplateOptions.scala b/indigo-plugin/indigo-plugin/src/indigoplugin/datatypes/TemplateOptions.scala deleted file mode 100644 index 4d98e0ff2..000000000 --- a/indigo-plugin/indigo-plugin/src/indigoplugin/datatypes/TemplateOptions.scala +++ /dev/null @@ -1,11 +0,0 @@ -package indigoplugin.datatypes - -import os._ - -final case class TemplateOptions( - title: String, - showCursor: Boolean, - scriptPathBase: Path, - gameAssetsDirectoryPath: Path, - backgroundColor: String = "white" -)