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 & JDK 11+
It is recommended to use JDK 11+ when running and developing CosPlay applications. Note that JavaFX, used internally by CosPlay, is a modularized library and produces a warning every time CosPlay runtime starts complaining that it is started from the unnamed module (since Scala does not support JPMS). Consult the following Java and Scala compatibility table for support JDK versions.
Note also that default build.sbt
assumes that current JDK does NOT bundle JavaFX and JavaFX library is attached to the classpath by SBT. Using JDK that bundles JavaFX can lead to undefined behaviour.
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.3.0" lazy val root = (project in file(".")) .settings( name := "macarena", libraryDependencies += "org.cosplayengine" % "cosplay" % "0.9.5" )
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.3.0" 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", libraryDependencies += "org.cosplayengine" % "cosplay" % "0.9.5", assembly / assemblyJarName := "macarena.jar", assembly / mainClass := Option(mainCls) )
$ sbt clean compile $ sbt assemblyThis creates a single JAR file:
target/scala-3.3.0/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.3.0" lazy val root = (project in file(".")) .settings( name := "macarena", libraryDependencies += "org.cosplayengine" % "cosplay" % "0.9.5" )
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.3.0" lazy val root = (project in file(".")) .settings( name := "cosplay-macarena", libraryDependencies += "org.cosplayengine" % "cosplay" % "0.9.5" )
$ 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 MacOSNote 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.