How to deploy a JME project as executable with the integrated JVM using JME 3.6 and above?

I use JME 3.6 have tried the recipes from the official homepage: jMonkeyEngine SDK: Application Deployment :: jMonkeyEngine Docs

but there is no Application submenu in project preferences menu.
I have tried “clean and build” but I have no .EXE, but a .bat file and one file with no extension in the bin subfolder. I have tried also JPackage (instruction for LibGDX) but it doesn’t run after export.

How can I export my game with the integrated JRE?

I don’t use the SDK so unsure what built in option it has but are you using a gradle build system? If so you can get gradle to produce a distributable with a bundled JVM for each OS (not quite an EXE, but functionally equivalent. The windows version is a bat file that links up your jars with the jvm and includes the whole thing in a zip).

The templates produced by https://start.jmonkeyengine.org/ will include this if the relevant deployment option is ticked

@richtea
Yes, I use Gradle. I found (using Intellij Idea) the build script “assembleDist” which makes the same as the “Clean and build” in the SDK. It creates .TAR and .ZIP archives with the game. The .bat file can be launched but only in the user has the same or more actual version of the JVM. Without preinstalled JAVA I can not launch it (or if the default JAVA < 17). How can Gradle or SDK append JRE to the distributed package?

Yeah, with Gradle you can use the distZip to build a ZIP version. The SDK EXE path is only available for Ant projects.

If you need bundled JDK, then you need to look for some advanced methods to pack your application. Like JPackage. Essentially there is nothing special about having a jME project. You can Google with “gradle bundle jdk distribution”. Also discussed here in the forums before, so you might want to look for existing solutions from here too.

@tonihele
Does it mean that I can recreate my game under Ant build system to deploy with the integrated JRE?

You can but it makes very little sense. Very little. A president would not in any circumstances consider you an applicant for any medal or title after that. Actually I’m pretty sure one could even lose their citizenship if converting from Gradle to Ant.

Well, I googled for you. Please try some of these existing solutions other people use:

Essentially these point to same solutions. But you’ll get the point.

Does it mean that I can recreate my game under Ant build system to deploy with the integrated JRE?

Why would you need? In Gradle you can do Everything you like, its much more elastic than Ant.

Gradle example from topics that tonihele linked:

task addJreToDistributable(type: Copy) {
    from zipTree("resources/desktop-deployment/OpenJDK11U-jre_x64_windows_hotspot_11.0.4_11.zip")
    destinationDir = file("$buildDir/windowsDistribution/oneMillionWorlds")
}

createWindowsDist.dependsOn addJreToDistributable

and ofc you can solve this on 999 ways in Gradle, its just one example.

and .EXE is no problem, its just file that run JAR, thats all. (also you can just copy gradle generation for it from JME init tool)

@tonihele
the second link was helpful. Thanks! I think I couldn’t export using JPackage because it doesn’t support JRE>=17. When I use JPackage in LibGDX with Java 14 it works perfect.

@oxplay2
tonyhele helped me already. I thought that JME3 has “in build” tool but it seems it has no “ready-to-use” solution for deployment.

Yes, in JME you have Gradle for deployment and TON of ways to solve what you need.

There is “ready-to-use” initializer in JME for an EXE/etc distributions, but as i see there is lack of integrated JRE part, yes. Tho its very easy to add as you see.

The initializer does bundle the JRE, here is how it works

in scripts\desktopDeployment there is a file for each distribution, just considering windows for now

TestWithWindows.bat

"jre/bin/java" -XX:MaxRAMPercentage=60 -classpath "lib/*" testwithwindows.TestWithWindows
exit 0

Note that it is referencing a relative path to a jre

In the build.gradle file there are a bunch of tasks, the top level one being buildAllDistributions

distZip {
    //having a degenerate folder within the dist zip complicates generating the other zips
    eachFile { file ->
        String path = file.relativePath
        file.setPath(path.substring(path.indexOf("/") + 1, path.length()))
    }
    includeEmptyDirs(false)
}

//See https://api.adoptium.net/v3/assets/feature_releases/11/ga?image_type=jre for jre urls
def windowsJreUrl = "https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.6%2B10/OpenJDK17U-jre_x64_windows_hotspot_17.0.6_10.zip"



task downloadWindowsJre(type: Download) {
    src windowsJreUrl
    dest new File(buildDir, '/jres/windowsJre.zip')
    overwrite false
}

task downloadAndUnzipWindowsJre(dependsOn: downloadWindowsJre, type: Copy) {
    from zipTree(downloadWindowsJre.dest)
    into "${buildDir}/jres/windowsJre/"
    includeEmptyDirs(false)
    filesMatching("**") {
        it.path = it.path.replaceAll("^[a-zA-Z0-9.+-]*[/\\\\]", "jre/") //rename the top level to something standard so the rest of the script will be easier
    }
}

task buildWindowsDistribution(dependsOn: [distZip, downloadAndUnzipWindowsJre], type: Copy)
{
    group 'distribution'
    from files("${projectDir}/scripts/desktopDeployment/TestWithWindows.bat"), zipTree(distZip.archiveFile), "${buildDir}/jres/windowsJre"
    into new File(buildDir, 'distributions/TestWithWindows-windows')
    includeEmptyDirs false
    exclude 'bin/**' //we are adding our own run scripts, exclude the ones coming from distZip
}

task zipWindowsDistribution( dependsOn:buildWindowsDistribution, type: Zip) {
    group 'distribution'
    archiveFileName = "TestWithWindows-windows.zip"
    destinationDirectory = file("$buildDir/distributions")
    from "$buildDir/distributions/TestWithWindows-windows"
}


task buildAllDistributions{
    group 'distribution'
    dependsOn 'zipWindowsDistribution'
    
}

The overall behaviour is that it downloads a JRE (17 in the examples case) from a URL and includes the JRE, your application, and that launch bat within a zip archive. That zip archive can then be distributed to end customers to unzip and use, or used as the upload to steam (where steam will handle getting everything on the end users machine.

For a working example

  • go to https://start.jmonkeyengine.org > download your project

  • unzip it

  • At the root of the project run .\gradlew buildAllDistributions (or ./gradlew buildAllDistributions depending on your os)

  • look in folder \build\distributions

  • See the zip that ends -windows.zip (or the folder that ends -windows)

  • Look inside to see a bundled JRE, your application (in lib) and a bat file to start it all up

  • Unzip it (pretending to be an end user)

  • Double click the bat file

  • Application opens without needing a local JRE (the cmd window remains open in the background, that could probably be improved)

2 Likes

In my case, I first download an jre for the openjdk I use to bundle with the app.
There are two free ways to bundle your project as an exe outside of the SDK that I use

  1. There is a gradle plugin to add launch4j functionality and and use the jre you downloaded to make the exe. The gradle plugin is a bit easier then using pure launch4J

  2. Libgdx has a Packr tool that can also make your exe and you can add the jre you want to bundle with. I used this one to publish my game Depthris on Steam

2 Likes

For creating .exe files out of my jars I use: https://launch4j.sourceforge.net/
Works great for me.

1 Like

launch4j does not bundle a JRE, though, I think.

I use this for Mythruna: GitHub - beryx/badass-runtime-plugin: Create a custom runtime image of your non-modular application

…the only painful thing is having to build on the different platforms. That’s why I only have executable versions for Windows and Linux and a separate cross-platform version using gradle’s regular application plugin for anyone else.

Setup is pretty straight-forward, though.

1 Like

It can enforce running using a specific JRE version which is bundled with your setup app (I use INNO Setup)

Yeah, but this is not really what the OP was asking for, I think.

He wants the more modern “JRE bundled into my EXE” approach… the added benefit is that it only includes the parts of the JRE that you actually use.

1 Like

I have tried JavaPackager and it works. Thanks for tonihele. It seems to be logical that JME3 should have the build_in solution but no problem - I will use another tools for this purpose.

2 Likes

It is not that straight forward. But possible. Probably need to present more than one solution… To me it looks like there is no one solution to rule them all if one wants to target all platforms and everything. Something to investigate.

1 Like

If JavaPackager finally doesn’t fit you and you’re feeling brave enough, you could try to use graalvm to generate a final binary file. I created a sample project for this at GitHub - joliver82/jme3-graalvm-sample-project some weeks ago which you could use as an example for modifying your gradle

2 Likes

How about using C: exec function simply run our java files.
exec family in C

Means you have to build a C program.