CrossPlaformModule

Hi there, this was the promised version of the cross platform gradle template :slight_smile:

Running the template was fine on desktop & android, assembling a debug on android was also fine, but assembling jar for desktop lacks jme3 dependencies ( i have tried many things like copying from runtimePath to the build/classes, jar tasks,…etc ).

Ref : => Gradle for java : Structuring and Building a Software Component with Gradle

If you want to test this, open android studio and clone the project, or use command line git & gradle, but beware of changing sdk.dir from gradle.properties file if you will use command line.

3 Likes

Nice job, @Pavl_G

I see only 2 subprojects, why there is not a game subproject? (that should hold game logic and must be shared with desktop and android)

I think there should be

  • desktop
  • android
  • game // game logic code that is shared with desktop and android

Edit:
See these templates for an example:

1 Like

Yes, the game is within the same module of desktop, i think its equivalent to have it in a the same or a separate module.

EDIT : Outside of this context, i have tried to assemble a command line gradle project through ./gradlew assemble and it also fails to collect jme3 dependencies ?

if you can assemble these to jars from the command line let me know.

EDIT : i think the answer is here (since i was playing in the past with javac and i know you must have all .java compiled to .class in a single folder) but i donot know the right syntax of include() :

jar {
   manifest {
      attributes 'Main-Class': 'javaApp.App'
   }
 
}

what about gradle distZip?

1 Like

I assume assemble depends on distZip task, so distZip already runs before assembe :

> Configure project :
Evaluating root project 'CrossPlatformModule' using build file '/home/twisted/AndroidStudioProjects/CrossPlatformModule/build.gradle'.

> Configure project :app
Evaluating project ':app' using build file '/home/twisted/AndroidStudioProjects/CrossPlatformModule/app/build.gradle'.

> Configure project :desktop
Evaluating project ':desktop' using build file '/home/twisted/AndroidStudioProjects/CrossPlatformModule/desktop/build.gradle'.

> Configure project :game
Evaluating project ':game' using build file '/home/twisted/AndroidStudioProjects/CrossPlatformModule/game/build.gradle'.
All projects evaluated.
Selected primary task ':desktop:assemble' from project :desktop
Tasks to be executed: [task ':game:compileJava', task ':desktop:compileJava', task ':desktop:processResources', task ':desktop:classes', task ':desktop:jar', task ':game:processResources', task ':game:classes', task ':game:jar', task ':desktop:startScripts', task ':desktop:distTar', task ':desktop:distZip', task ':desktop:assemble']
Tasks that were excluded: []
:game:compileJava (Thread[Execution worker for ':',5,main]) started.

> Task :game:compileJava UP-TO-DATE
Caching disabled for task ':game:compileJava' because:
  Build cache is disabled
Skipping task ':game:compileJava' as it is up-to-date.
:game:compileJava (Thread[Execution worker for ':',5,main]) completed. Took 0.035 secs.
:desktop:compileJava (Thread[Execution worker for ':',5,main]) started.

> Task :desktop:compileJava UP-TO-DATE
Caching disabled for task ':desktop:compileJava' because:
  Build cache is disabled
Skipping task ':desktop:compileJava' as it is up-to-date.
:desktop:compileJava (Thread[Execution worker for ':',5,main]) completed. Took 0.008 secs.
:desktop:processResources (Thread[Execution worker for ':',5,main]) started.

> Task :desktop:processResources NO-SOURCE
file or directory '/home/twisted/AndroidStudioProjects/CrossPlatformModule/desktop/src/main/resources', not found
Skipping task ':desktop:processResources' as it has no source files and no previous output files.
:desktop:processResources (Thread[Execution worker for ':',5,main]) completed. Took 0.0 secs.
:desktop:classes (Thread[Execution worker for ':',5,main]) started.

> Task :desktop:classes UP-TO-DATE
Skipping task ':desktop:classes' as it has no actions.
:desktop:classes (Thread[Execution worker for ':',5,main]) completed. Took 0.0 secs.
:desktop:jar (Thread[Execution worker for ':',5,main]) started.

> Task :desktop:jar UP-TO-DATE
Caching disabled for task ':desktop:jar' because:
  Build cache is disabled
Skipping task ':desktop:jar' as it is up-to-date.
:desktop:jar (Thread[Execution worker for ':',5,main]) completed. Took 0.007 secs.
:game:processResources (Thread[Execution worker for ':',5,main]) started.

> Task :game:processResources UP-TO-DATE
Caching disabled for task ':game:processResources' because:
  Build cache is disabled
Skipping task ':game:processResources' as it is up-to-date.
:game:processResources (Thread[Execution worker for ':',5,main]) completed. Took 0.001 secs.
:game:classes (Thread[Execution worker for ':',5,main]) started.

> Task :game:classes UP-TO-DATE
Skipping task ':game:classes' as it has no actions.
:game:classes (Thread[Execution worker for ':',5,main]) completed. Took 0.0 secs.
:game:jar (Thread[Execution worker for ':',5,main]) started.

> Task :game:jar UP-TO-DATE
Caching disabled for task ':game:jar' because:
  Build cache is disabled
Skipping task ':game:jar' as it is up-to-date.
:game:jar (Thread[Execution worker for ':',5,main]) completed. Took 0.001 secs.
:desktop:startScripts (Thread[Execution worker for ':',5,main]) started.

> Task :desktop:startScripts UP-TO-DATE
Caching disabled for task ':desktop:startScripts' because:
  Build cache is disabled
Skipping task ':desktop:startScripts' as it is up-to-date.
:desktop:startScripts (Thread[Execution worker for ':',5,main]) completed. Took 0.007 secs.
:desktop:distTar (Thread[Execution worker for ':',5,main]) started.

> Task :desktop:distTar UP-TO-DATE
file or directory '/home/twisted/AndroidStudioProjects/CrossPlatformModule/desktop/src/main/dist', not found
file or directory '/home/twisted/AndroidStudioProjects/CrossPlatformModule/desktop/src/dist', not found
Caching disabled for task ':desktop:distTar' because:
  Build cache is disabled
Skipping task ':desktop:distTar' as it is up-to-date.
:desktop:distTar (Thread[Execution worker for ':',5,main]) completed. Took 0.002 secs.
:desktop:distZip (Thread[Daemon worker Thread 52,5,main]) started.

> Task :desktop:distZip UP-TO-DATE
file or directory '/home/twisted/AndroidStudioProjects/CrossPlatformModule/desktop/src/main/dist', not found
file or directory '/home/twisted/AndroidStudioProjects/CrossPlatformModule/desktop/src/dist', not found
Caching disabled for task ':desktop:distZip' because:
  Build cache is disabled
Skipping task ':desktop:distZip' as it is up-to-date.
:desktop:distZip (Thread[Daemon worker Thread 52,5,main]) completed. Took 0.003 secs.
:desktop:assemble (Thread[Daemon worker Thread 52,5,main]) started.

> Task :desktop:assemble UP-TO-DATE
Skipping task ':desktop:assemble' as it has no actions.
:desktop:assemble (Thread[Daemon worker Thread 52,5,main]) completed. Took 0.0 secs.

Deprecated Gradle features were used in this build, making it incompatible with Gradle 8.0.
Use '--warning-mode all' to show the individual deprecation warnings.
See https://docs.gradle.org/7.0.2/userguide/command_line_interface.html#sec:command_line_warnings

BUILD SUCCESSFUL in 1s
8 actionable tasks: 8 up-to-date
Watching 59 directories to track changes

I think the problem is within compilation of jme3 dependencies as build/classes doesn’t contain the jme3 compiled files, jme3 is compiled within runtime only. why ?

It says build successfully. Still can not run?

ClassDefNotFoundException, seems gradle didn’t include jme3 dependencies within the compileClassPath folder.

Does it work when you build a regular JME Gradle project?

for example this

I haven’t tried, but i have tried to assemble a project created by gradle init command, it didn’t package jme3 dependencies.

That was its gradle :

/*
 * This file was generated by the Gradle 'init' task.
 *
 * This generated file contains a sample Java application project to get you started.
 * For more details take a look at the 'Building Java & JVM projects' chapter in the Gradle
 * User Manual available at https://docs.gradle.org/6.7/userguide/building_java_projects.html
 */

plugins {
    // Apply the application plugin to add support for building a CLI application in Java.
    id 'application'
}

repositories {
    // Use JCenter for resolving dependencies.
    jcenter()
            mavenCentral()

}

dependencies {
    // Use JUnit test framework.
    testImplementation 'junit:junit:4.13'
    implementation 'org.jmonkeyengine:jme3-core:3.4.0-stable'
    implementation "org.jmonkeyengine:jme3-effects:3.4.0-stable"
    implementation "org.jmonkeyengine:jme3-lwjgl:3.4.0-stable"
    implementation "org.jmonkeyengine:jme3-desktop:3.4.0-stable"
    // This dependency is used by the application.
    implementation 'com.google.guava:guava:29.0-jre'
}

application {
    // Define the main class for the application.
    mainClass = 'javaApp.App'
}
jar {
   manifest {
      attributes 'Main-Class': 'javaApp.App'
   }
}

And i did ./gradlew build & then ./gradlew assemble

usually for my small projects I add build-jar task like

            task([type: Jar, description: 'Generates runnable jar with all dependencies'], 'fatJar', {
                baseName = project.name + '-all'
                from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } }
                exclude 'META-INF/*'
                with jar

                manifest {
                    attributes(
                            "Main-Class": "${{ -> project.hasProperty('mainClassName') ? mainClassName : '' }}",
                            "buildTime": new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ").format(new Date())
                    )
                }
            })

probably you need something similar here

1 Like

@Pavl_G I have one more question. Do assets get bundled inside the APK file when building for Android?

How can we distribute assets as OBB files and inside the app load them from SD card or internal storage like other android games do?

Or what about distributing assets as ZIP and loading them from the SD card using ZipLocator, is it possible?

Edit:
What about Play Asset Delivery service? Have you tried it or know how we can use it with JME and Gradle?

1 Like

Yes, it works.

Well, that’s another topic, there’s an Android API for this, i have never tried it till now.

I think Adi has done something like that on the GameHub Apk, but i am not sure.

1 Like

Alright, you are right, while you were answering the problem, i partially solved it, the problem was with the jars not being included into the Manifest so a rough solution for this :

jar{
    manifest{
        attributes('Main-Class': mainClassName)
        attributes('Class-Path' : 'dependencies/game.jar ' +
                'dependencies/jme3-core-3.4.0-stable.jar ')
        attributes('Created-By' : 'Jme3-Gradle')
    }
}
task makeDirectory(dependsOn : Jar){
    doFirst {
        mkdir('build/libs/dependencies')
    }
}
task releaseJar(type: Copy, dependsOn : makeDirectory) {
    mustRunAfter(makeDirectory)
    from (sourceSets.main.compileClasspath, sourceSets.main.runtimeClasspath)
    into('build/libs/dependencies')
}

the problem now is mkdir doesnot work & i need a more automated solution, plus @wizzardo where should i place your snippet.?

just to the build.gradle and run as ./gradlew fatJar

1 Like

Fat jars are kind of a hack from the maven days because for some reason no one could make classpath attributes work in the manifest. (Even gradle’s application plugin doesn’t do this right.)

Fat jars make integrating with auto-update software essentially impossible.

1 Like

But it creates problems with building.

what kind of problems?

$./gradlew :desktop:fatJar 

FAILURE: Build failed with an exception.

* Where:
Build file '/home/twisted/AndroidStudioProjects/CrossPlatformModule/desktop/build.gradle' line: 25

* What went wrong:
Could not determine the dependencies of task ':desktop:fatJar'.
> Could not get unknown property 'compile' for configuration container of type org.gradle.api.internal.artifacts.configurations.DefaultConfigurationContainer.

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.

* Get more help at https://help.gradle.org

Deprecated Gradle features were used in this build, making it incompatible with Gradle 8.0.
Use '--warning-mode all' to show the individual deprecation warnings.
See https://docs.gradle.org/7.0.2/userguide/command_line_interface.html#sec:command_line_warnings

BUILD FAILED in 1s

i hope i am typing the command correctly

When replacing compile with implementation :

* What went wrong:
Could not determine the dependencies of task ':desktop:fatJar'.
> Resolving dependency configuration 'implementation' is not allowed as it is defined as 'canBeResolved=false'.
  Instead, a resolvable ('canBeResolved=true') dependency configuration that extends 'implementation' should be resolved.

* Try:

looks like something changed in gradle 7 =(, it works for me in 6.8

1 Like