I have the jme project structure with some minimal assets (icons and splash screen), then most of the assets are on a folder outside the project (where I actually run the game).
I did this mainly for having the assets on a separate repository.
Now I’d like to have these external assets bundled with the application, and also with a JVM. Any advice is welcome, thanks!
how is your update concept and game size?
does packing all assets into a jar work for you? then the first part is solved. (create a small gradle tasks/ or whatever tool you like to just zip them and rename to .jar, use classpath locator then to load them)
For bundling there is the the offical javafx way (it works even if you have 0% javafx)
There are handmade but quite reliable solutions that involve using multiple java zip releases,
put them all to a folder. Then use a small start script to use the correct one and start your application with it.
Eg. for windows something like this:
:CheckOS
IF EXIST "%PROGRAMFILES(X86)%" (GOTO 64BIT) ELSE (GOTO 32BIT)
:64BIT
echo 64-bit...
./win64_oracle_jre/bin/java -cp myjarFilea.jar;myJarFileb.jar com.example.ClassWithMain
GOTO END
:32BIT
echo 32-bit...
./win32_oracle_jre/bin/java -cp myjarFilea.jar;myJarFileb.jar com.example.ClassWithMain
GOTO END
:END
3 Likes
I’d like to pack the jars from 2 folders into one jar:
project(":assets") {
apply plugin: "java"
buildDir = rootProject.file("build/assets")
sourceSets {
main {
resources {
srcDir '.'
}
}
}
}
project(":assetsm") {
apply plugin: "java"
buildDir = rootProject.file("build/assets")
sourceSets {
main {
resources {
srcDir 'run'
}
}
}
}
OK solved:
task myCopy(type: Copy)
myCopy {
from 'assets','run/assets'
into 'pack'
exclude('**/*.blend','**/*.j3odata')
}
pspeed
June 28, 2016, 1:33pm
5
This implies that the other assets are in a run subdirectory unser build/assets… but then they would have been packaged already in the regular assets.jar.
Can you describe at a higher level what you are trying to do? I know you solved it but sometimes there are more elegant ways.
My tree hierarchy looks like this:
/src
/assets
/run/assets
And I want to merge the contents of “assets” and “run/assets” into a single asset.jar.
This is my gradle
apply plugin: 'java'
apply plugin: 'application'
apply plugin: 'idea'
mainClassName='com.pesegato.p8s.Main'
repositories {
mavenLocal()
jcenter()
}
ext.jmeVersion = "[3.1,)"
project(":assets") {
apply plugin: "java"
buildDir = rootProject.file("build/assets")
sourceSets {
main {
resources {
srcDir '.'
}
}
}
}
/*
task myCopy(type: Copy)
myCopy {
from 'assets','run/assets'
into 'pack'
exclude('**/*.blend','**/*.j3odata')
}
*/
task myPack(type: Jar) {
from 'assets','run/assets'
exclude('**/*.blend','**/*.j3odata')
baseName 'assets'
}
//myPack.dependsOn myCopy
sourceSets {
main {
java { srcDir 'src'}
}
}
dependencies {
compile "org.jmonkeyengine:jme3-core:$jmeVersion"
compile "org.jmonkeyengine:jme3-desktop:$jmeVersion"
compile "org.jmonkeyengine:jme3-lwjgl:$jmeVersion"
compile 'com.simsilica:zay-es:1.2.1'
compile 'com.simsilica:lemur:1.8.1'
compile 'com.google.guava:guava:19.0'
compile 'org.slf4j:slf4j-api:1.7.21'
compile "com.pesegato:GoldMonkey:[0.1,)"
compile "com.pesegato:MonkeySheet:[0.1,)"
compile files('../commons-math3-3.5.jar')
compile files('../tonegod.emitter.jar')
compile files('../tonegodgui-0.0.2.jar')
compile files('../Mermaid-0.0.1.jar')
runtime ":myPack"
// runtime project(':assets')
}
My current problem is that I’d like to declare the task myPack to be executed by the assets project… or something like that
pspeed
June 28, 2016, 2:09pm
7
So, it might help to know why you want the separate directories and why you want them in one jar.
Is there a reason two jars would be bad?
Some assets must reside on src/assets (icon+splashscreen), so I can’t put them on the separate assets repo.
This also allow me to have a production logback.xml that overwrite the development one
This would prevent 2) above but I can live with it.
So I get that you suggest to have 2 subprojects, one for each asset folder?
pspeed
June 28, 2016, 2:16pm
9
Anyway, if you don’t to have them as two jars (though that seems like it would make your life easier just to have two assets projects or put everything in one directory tree since they are effectively treated that way) then you might try…
But my syntax may be a bit off and/or the project may have issues with going outside it’s own root.
Personally, if I wanted two different directories for some reason then I’d just treat them like two different assets projects. And if I didn’t want them as two different assets projects then that strongly implies that I should be just keeping them together anyway.
Edit: had typed this before seeing your reply… yes, two assets projects named appropriately for why they are different.
1 Like
pspeed
June 28, 2016, 2:20pm
10
Pesegato:
This also allow me to have a production logback.xml that overwrite the development one
I don’t know how logback resolves it’s XML… does it take the first one or the last one or try to load all of them?
It’s not the same thing but you want something similar to the “provided” idea in maven… in that you want your runtime build to depend on something that you don’t want to package. And I only say that because if you lookup the gradle solutions for ‘provided’ then they basically show you how to have your runtime development depend on something that you don’t package… in which case you might be able to just depend on a directory of local resources for your logback.xml that you want to be dev only.
1 Like
pspeed
June 28, 2016, 11:10pm
11
Pesegato:
Some assets must reside on src/assets (icon+splashscreen), so I can’t put them on the separate assets repo.
Note: icons and splash screens should be able to exist anywhere on your classpath… if you mean the ones settable in AppSettings. I do this all the time.
Edit: and by “anywhere on your classpath” I mean in any jar that you depend on… whether src/main/resources or assets or other.
1 Like
I’m posting here my latest gradle. Bundles both the game and the JVM, and I think is a good starting point for publishing games:
apply plugin: 'java'
apply plugin: 'application'
apply plugin: 'idea'
version = "0.1.0"
mainClassName='com.pesegato.p8s.Main'
buildscript {
dependencies {
classpath group: 'de.dynamicfiles.projects.gradle.plugins', name: 'javafx-gradle-plugin', version: '8.5.1'
}
repositories {
mavenCentral()
}
}
repositories {
mavenLocal()
jcenter()
}
ext.jmeVersion = "[3.1,)"
project(":assets") {
apply plugin: "java"
buildDir = rootProject.file("build/assets")
sourceSets {
main {
resources {
srcDirs = [ '.', '../run/assets' ]
}
}
}
}
task myPack(type: Jar) {
from 'assets','run/assets'
exclude('**/*.blend','**/*.j3odata')
baseName 'assets'
}
//myPack.dependsOn myCopy
task versionInfo(type:Exec){
commandLine 'hg id -i -b -t'.split()
ext.versionfile = new File('assets/buildinfo.properties')
standardOutput = new ByteArrayOutputStream()
doLast {
versionfile.text = 'build.revision=' + standardOutput.toString()
}
}
sourceSets {
main {
java { srcDir 'src'}
}
}
dependencies {
compile "org.jmonkeyengine:jme3-core:$jmeVersion"
compile "org.jmonkeyengine:jme3-desktop:$jmeVersion"
compile "org.jmonkeyengine:jme3-lwjgl:$jmeVersion"
compile "org.jmonkeyengine:jme3-jogg:$jmeVersion"
compile 'com.simsilica:zay-es:1.2.1'
compile 'com.simsilica:lemur:1.8.1'
compile 'com.google.guava:guava:19.0'
compile 'org.slf4j:slf4j-api:1.7.21'
compile "com.pesegato:GoldMonkey:[0.1,)"
compile "com.pesegato:MonkeySheet:[0.1,)"
compile files('../commons-math3-3.5.jar')
compile files('../tonegod.emitter.jar')
compile files('../tonegodgui-0.0.2.jar')
compile files('../Mermaid-0.0.1.jar')
runtime project(':assets')
}
apply plugin: 'javafx-gradle-plugin'
// configure javafx-gradle-plugin
jfx {
verbose = true
mainClass = "com.pesegato.p8s.Main"
jfxAppOutputDir = "build/jfx/app"
jfxMainAppJarName = "Simonetta.jar"
deployDir = "src/main/deploy"
// gradle jfxJar
css2bin = false
preLoader = null
updateExistingJar = false
allPermissions = false
manifestAttributes = null // Map<String, String>
addPackagerJar = true
// gradle jfxNative
identifier = null // setting this for windows-bundlers makes it possible to generate upgradeable installers (using same GUID)
vendor = "some serious business corp."
nativeOutputDir = "build/jfx/native"
bundler = "ALL" // set this to some specific, if your don't want all bundlers running, examples "windows.app", "jnlp", ...
jvmProperties = null // Map<String, String>
jvmArgs = null // List<String>
userJvmArgs = null // Map<String, String>
launcherArguments = null // List<String>
nativeReleaseVersion = "1.0"
needShortcut = false
needMenu = false
bundleArguments = [
// dont bundle JRE (not recommended, but increases build-size/-speed)
runtime: "C:/Program Files/Java/jre1.8.0_91"
]
appName = "simonetta" // this is used for files below "src/main/deploy", e.g. "src/main/deploy/windows/project.ico"
additionalAppResources = ["package/windows/simonetta.ico"] // path to some additional resources when creating application-bundle
//secondaryLaunchers = [[appName:"somethingDifferent"], [appName:"somethingDifferent2"]]
fileAssociations = null // List<Map<String, Object>>
noBlobSigning = false // when using bundler "jnlp", you can choose to NOT use blob signing
customBundlers // List<String>
skipNativeLauncherWorkaround205 = false
skipNativeLauncherWorkaround124 = false
skipNativeLauncherWorkaround167 = false
skipJNLPRessourcePathWorkaround182 = false
skipSigningJarFilesJNLP185 = false
skipSizeRecalculationForJNLP185 = false
/*
// gradle jfxGenerateKeyStore
keyStore = "src/main/deploy/keystore.jks"
keyStoreAlias = "myalias"
keyStorePassword = "password"
keyPassword = null // will default to keyStorePassword
keyStoreType = "jks"
overwriteKeyStore = false
certDomain = null // required
certOrgUnit = null // defaults to "none"
certOrg = null // required
certState = null // required
certCountry = null // required
*/
}
/*
task myPublish(dependsOn: [build, jfxNative]) << {
println "done"
}
*/
/*
set JAVA_HOME="C:\Program Files\Java\jdk1.8.0_77
gradlew clean
gradlew build jfxNative
gradlew myBundle
*/
task myBundle(type: Zip) {
from 'build/jfx/native/simonetta'
baseName 'Simonetta-bundle-Windows-x64.zip'
}
Question: to avoid errors, I have to invoke:
gradlew build jfxNative myBundle
…why is “build” needed? I’d also like to simply invoke gradlew myBundle…
1 Like
pspeed
July 4, 2016, 2:39pm
13
Because myBundle doesn’t depend on anything.
Added
myBundle.dependsOn jfxNative
jfxNative.dependsOn build
Still have no idea why jfxNative requires build, however… it works.
This is my last version of the script http://pastebin.com/BVGEtTvQ
I have a .properties file on the source dir (that gets bundled on the jar with jme sdk) which is not included with the gradle build. What am I missing? Thanks!
(the file is actually the default settings for the game, which are copied if not already present).
pspeed
August 22, 2016, 11:33am
16
Tried to look at the file but it was this giant video playing at the top… so I closed it again.
Most likely, you’ve put the properties file in the java directory… but it’s not a java file, it’s a resource… so should go in src/main/resources.
Sorry about that. here it is again:
apply plugin: 'java'
apply plugin: 'application'
apply plugin: 'idea'
version = "0.1.0"
mainClassName='com.pesegato.p8s.Main'
buildscript {
dependencies {
classpath group: 'de.dynamicfiles.projects.gradle.plugins', name: 'javafx-gradle-plugin', version: '8.5.1'
}
repositories {
mavenCentral()
}
}
repositories {
mavenLocal()
jcenter()
}
ext.jmeVersion = "[3.1,)"
project(":assets") {
apply plugin: "java"
buildDir = rootProject.file("build/assets")
sourceSets {
main {
resources {
srcDirs = [ '.', '../run/assets' ]
exclude('**/*.blend','**/*.j3odata')
}
}
}
}
task myPack(type: Jar) {
from 'assets','run/assets'
exclude('**/*.blend','**/*.j3odata')
baseName 'assets'
}
def buildDate
def buildCommit
task dateInfo(type:Exec){
commandLine 'powershell get-date -format "{dd-MM-yyyy HHmm}"'.split()
standardOutput = new ByteArrayOutputStream()
doLast {
//versionfile.text = 'build.date=' + standardOutput.toString()
buildDate=standardOutput.toString().trim()
}
}
task dateInfo2(type:Exec){
commandLine 'hg id -i -b -t'.split()
//ext.versionfile = new File('assets/buildinfo2.properties')
standardOutput = new ByteArrayOutputStream()
doLast {
//versionfile.text = 'build.revision=' + standardOutput.toString()
buildCommit=standardOutput.toString().trim()
}
}
task versionInfo << {
def props = new Properties()
/*
['assets/buildinfo1.properties','assets/buildinfo2.properties'].each {
props.load(new FileReader(file(it)))
}
*/
props.put('build.date',buildDate)
props.put('build.revision',buildCommit)
def writer = new FileWriter(file('assets/buildinfo.properties'))
try {
props.store(writer, 'Automatically generated by gradle')
writer.flush()
} finally {
writer.close()
}
}
versionInfo.dependsOn dateInfo
versionInfo.dependsOn dateInfo2
/*
task versionInfo(type:Exec){
def props = new Properties()
File propsFile = new File('assets/buildinfo.properties')
commandLine 'hg id -i -b -t'.split()
standardOutput = new ByteArrayOutputStream()
props.setProperty('build.revision', 'aaa' )
commandLine 'powershell get-date'.split() // -format "{dd-MM-yyyy HH:mm}"'
props.setProperty('build.date', 'bbb' )
props.store(propsFile.newWriter(), null)
ext.versionfile = new File('assets/buildinfo.properties')
doLast {
versionfile.text = 'build.revision=' + standardOutput.toString() + 'build.date='
}
}
*/
sourceSets {
main {
java { srcDir 'src'}
}
}
dependencies {
compile "org.jmonkeyengine:jme3-core:$jmeVersion"
compile "org.jmonkeyengine:jme3-desktop:$jmeVersion"
compile "org.jmonkeyengine:jme3-lwjgl:$jmeVersion"
compile "org.jmonkeyengine:jme3-jogg:$jmeVersion"
compile 'com.simsilica:zay-es:1.2.1'
compile 'com.simsilica:lemur:1.8.1'
compile 'com.google.guava:guava:19.0'
compile 'org.slf4j:slf4j-api:1.7.21'
compile "com.pesegato:GoldMonkey:[0.1,)"
compile "com.pesegato:MonkeySheet:[0.1,)"
compile files('../commons-math3-3.5.jar')
compile files('../tonegod.emitter.jar')
compile files('../tonegodgui-0.0.2.jar')
compile files('../Mermaid.jar')
runtime project(':assets')
}
apply plugin: 'javafx-gradle-plugin'
// configure javafx-gradle-plugin
jfx {
verbose = true
mainClass = "com.pesegato.p8s.Main"
jfxAppOutputDir = "build/jfx/app"
jfxMainAppJarName = "Simonetta.jar"
deployDir = "src/main/deploy"
// gradle jfxJar
css2bin = false
preLoader = null
updateExistingJar = false
allPermissions = false
manifestAttributes = null // Map<String, String>
addPackagerJar = true
// gradle jfxNative
identifier = null // setting this for windows-bundlers makes it possible to generate upgradeable installers (using same GUID)
vendor = "some serious business corp."
nativeOutputDir = "build/jfx/native"
bundler = "ALL" // set this to some specific, if your don't want all bundlers running, examples "windows.app", "jnlp", ...
jvmProperties = null // Map<String, String>
jvmArgs = null // List<String>
userJvmArgs = null // Map<String, String>
launcherArguments = null // List<String>
nativeReleaseVersion = "1.0"
needShortcut = false
needMenu = false
/*
bundleArguments = [
// dont bundle JRE (not recommended, but increases build-size/-speed)
]
*/
appName = "simonetta" // this is used for files below "src/main/deploy", e.g. "src/main/deploy/windows/project.ico"
additionalAppResources = null // path to some additional resources when creating application-bundle
//secondaryLaunchers = [[appName:"somethingDifferent"], [appName:"somethingDifferent2"]]
fileAssociations = null // List<Map<String, Object>>
noBlobSigning = false // when using bundler "jnlp", you can choose to NOT use blob signing
customBundlers // List<String>
skipNativeLauncherWorkaround205 = false
skipNativeLauncherWorkaround124 = false
skipNativeLauncherWorkaround167 = false
skipJNLPRessourcePathWorkaround182 = false
skipSigningJarFilesJNLP185 = false
skipSizeRecalculationForJNLP185 = false
/*
// gradle jfxGenerateKeyStore
keyStore = "src/main/deploy/keystore.jks"
keyStoreAlias = "myalias"
keyStorePassword = "password"
keyPassword = null // will default to keyStorePassword
keyStoreType = "jks"
overwriteKeyStore = false
certDomain = null // required
certOrgUnit = null // defaults to "none"
certOrg = null // required
certState = null // required
certCountry = null // required
*/
}
/*
PER 32bit
set JAVA_HOME="C:\Program Files (x86)\Java\jdk1.8.0_91"
PER 64bit
set JAVA_HOME="C:\Program Files\Java\jdk1.8.0_77
gradlew clean
gradlew release
*/
task makePretty(type: Delete) {
delete 'build/jfx/native/simonetta/simonetta.ico' //, 'uglyFile'
}
task release(type: Zip) {
from 'build/jfx/native'
baseName 'Simonetta-Windows-x64.zip'
}
release.dependsOn makePretty
makePretty.dependsOn jfxNative
jfxNative.dependsOn build
jar.dependsOn versionInfo