CosPlay game is a no different from any other JVM-based application written in any JVM-based programming language like Java, Scala, Kotlin, etc. And although specific tools we will be discussing are specific to Scala - the overall idea of how a CosPlay game can be packaged are 100% the same as for any other, in our case, Scala application.
There are four stages of game packaging - also often called a publishing a build - that you can do with CosPlay game in relation to how self-contained and automated that package will be:
CosPlay & JavaFX
CosPlay uses JavaFX technology for its support for audio playback. JavaFX is a platform-specific SDK that is widely available for many platforms. Since JDK 11 the JavaFX is no longer a part of the official JDK from Oracle and is now a separate OpenJFX open source project. Some third-party JDK implementations may not provide support for JavaFX making CosPlay incompatible with these JDKs.
Make sure to use and/or bundle JDKs that are compatible with JavaFX.
Java 17+
When running CosPlay game under Java 17+ you need to add additional JVM command line parameter --add-opens javafx.graphics/com.sun.javafx.application=ALL-UNNAMED
for JavaFX to operate correctly. Note that when running examples and built-in games from project's Maven or SBT, this parameter is set automatically.
We only mention it here because it is a default mode in which you are developing, running, testing and debugging a CosPlay game. Once you have your Maven or SBT based project in IDE or an editor you can build and run your game automatically without any additional configuration or set up.
However, we obviously cannot ask the end user player to set up the IDE, checkout the source code, build the game and run it the same way as you do. Hence, there are other ways to package the game in a more convenient way for the end user.
A single JAR file that includes all dependencies - often called a "Fat JAR" - is a strategy of including all CosPlay and your game dependencies into a single large JAR file. This technique requires the end user to know how to execute a JAR file. This requirement is the biggest limitation of this approach - if you expect that your game users do not have the basic understanding of how to run applications packaged into JAR files - use other two packaging approaches.
Let's consider the game from our quick game tutorial. This game was built as an SBT project with the following minimal build.sbt
file:
ThisBuild / version := "0.1.0-SNAPSHOT" ThisBuild / scalaVersion := "3.1.1" lazy val root = (project in file(".")) .settings( name := "macarena", // JVM options for Java 17+. javaOptions += "--add-opens", javaOptions += "javafx.graphics/com.sun.javafx.application=ALL-UNNAMED", // Dependencies. libraryDependencies += "org.cosplayengine" % "cosplay" % "0.8.8" )
To create a single all-dependency JAR file we will be using SBT plugin:
project/plugins.sbt
file.1.2.0
):addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "1.2.0")
build.sbt
file:ThisBuild / version := "0.1.0-SNAPSHOT" ThisBuild / scalaVersion := "3.1.1" ThisBuild / assemblyMergeStrategy := { case PathList("org", "jline", xs @ _*) ⇒ MergeStrategy.last case PathList(ps @ _*) if ps.last endsWith "module-info.class" ⇒ MergeStrategy.rename case PathList(ps @ _*) if ps.last endsWith ".json" ⇒ MergeStrategy.rename case PathList(ps @ _*) if ps.last endsWith "resourcebundles" ⇒ MergeStrategy.rename case PathList(ps @ _*) if ps.last startsWith "Inspector" ⇒ MergeStrategy.rename case x => val oldStrategy = (ThisBuild / assemblyMergeStrategy).value oldStrategy(x) } lazy val root = (project in file(".")) .settings( name := "cosplay-macarena", // JVM options for Java 17+. javaOptions += "--add-opens", javaOptions += "javafx.graphics/com.sun.javafx.application=ALL-UNNAMED", libraryDependencies += "org.cosplayengine" % "cosplay" % "0.8.8", assembly / assemblyJarName := "macarena.jar", assembly / mainClass := Option(mainCls) )
$ sbt clean compile $ sbt assemblyThis creates a single JAR file:
target/scala-3.1.1/macarena.jar
(3.1.1
is the whatever version of Scala you are using).macarena.jar
file and anyone can play the game by running following command as long as they have Java 11 or later installed:$ java -jar macarena.jarThat's it! 👌
As we mentioned above the biggest drawback of this method is that the end user player must have Java installed and know how to run executable JAR file. Casual gamers are unlikely to know how to install Java or have the knowledge about its runtime.
Universal ZIP installer is a strategy that creates a ZIP archive that includes all necessary binaries from CosPlay and your game as well a user-friendly platform specific scripts (*.bat
and *.sh
) to run the game. Note that the end user player is still required to have Java runtime installed - but he or she does not need to know how to operate it anymore.
To demonstrate how to use create a universal ZIP installer we are going to reuse the game from our quick game tutorial. This game was built as an SBT project with the following minimal build.sbt
file:
ThisBuild / version := "0.1.0-SNAPSHOT" ThisBuild / scalaVersion := "3.1.1" lazy val root = (project in file(".")) .settings( name := "macarena", // JVM options for Java 17+. javaOptions += "--add-opens", javaOptions += "javafx.graphics/com.sun.javafx.application=ALL-UNNAMED", // Dependencies. libraryDependencies += "org.cosplayengine" % "cosplay" % "0.8.8" )
To create universal ZIP installer we are going to use SBT plugin:
project/plugins.sbt
file.1.9.4
):addSbtPlugin("com.github.sbt" % "sbt-native-packager" % "1.9.4")
build.sbt
file:enablePlugins(JavaAppPackaging) val mainCls = "com.rowangames.AsciiMacarena" maintainer := "my@email.com" Compile / mainClass := Some(mainCls) ThisBuild / version := "0.1.0-SNAPSHOT" ThisBuild / scalaVersion := "3.1.1" lazy val root = (project in file(".")) .settings( name := "cosplay-macarena", // JVM options for Java 17+. javaOptions += "--add-opens", javaOptions += "javafx.graphics/com.sun.javafx.application=ALL-UNNAMED", libraryDependencies += "org.cosplayengine" % "cosplay" % "0.8.8" )
$ sbt clean compile $ sbt universal:packageBinThis creates ZIP archive:
target/universal/cosplay-macarena-0.1.0-SNAPSHOT.zip
.$ bin/cosplay-macarena.{sh|bat}That's it! 👌
To create a native installer you will need to use the same SBT plugin we have used above. This plugin allows creation of platform-specific native installers:
.rpm
and .deb
for Linux.msi
for Windows.dmg
for MacOS Note that unlike previous packaging strategies this approach allows creation of installers that may or may not include automatic Java runtime installation. The specific details of plugin configuration are outside this tutorial and the reader is encouraged to look through documentation SBT plugin for more details. Note also that for many platform-specific installers the packaging process using this SBT plugin must be performed on the target platform.