Gradle - How to isolate concurrent runs?

I’ve run into some problems this week with my game, I noticed the game would work when it was played on another computer and someone else joined, but me running two games (server+client and a second client) on my computer caused JVM crashes, and class not found errors.

After some debugging and very long stares at hs_err_pidXXX logs (y’all know the struggle) I found out the errors were caused by classes in the gradle build folder being changed + deleted when I build the game a second time… Closing one game deleted the files for the server, and when it went to load the classes for the disconnect event the server crashed.

I sifted the internet for gradle task properties of the “application” plugin’s “run” task, to maybe run the program in a second build folder, but no luck…

I’m considering changing my run task to build the game into a jar, and run that instead… But I havent written gradle scripts before and that seems like a pain.

If anyone has some ideas on how to isolate gradle runs that would be awesome!

The run task depends on the classes task which depends on processResources and compileJava. This should not rebuild every time as it should cache things and know it has run things before, sounds like it is not happening and you are actually rebuilding the class files between runs so one run removes the classes from the other. I’d investigate more why this happens

here, have my gradle script template to create a jar - calling it with gradle createJar


apply plugin: 'maven'
apply plugin: 'java'

def mainClassName = 'com.mainclasspackage.Main'

repositories {
	mavenLocal()
	mavenCentral()
}


dependencies {
   // compile '<group>:<name>:<version>'
   // ... more here if necessary
}

task copyRuntimeLibs(type: Copy) {
    into "build/libs/lib"
    from configurations.runtime
}

task createJar(type: Jar){
	
	dependsOn build
	dependsOn compileJava
	dependsOn copyRuntimeLibs
	
	from 'build/classes/main'
	
	manifest {
        attributes(
			"Main-Class": mainClassName,
			"Class-Path": ". " + configurations.compile.collect { 'lib/' + it.getName() }.join(' ')
		)
    }
}

note: replace the dependencies (if you have any)
this setup copies the dependency jars next to the resulting jar inside a lib folder and sets the class path accordingly in the generated jar

the generated jar lands in build/lib

In your jar task you can add

into(‘lib’){
from configurations.runtime
include ‘*.jar’
}

To save depending on a custom copy task

Although it does have to rebuild, because one game is running the server and the other isn’t… Half of the codebase (server code) in one instance of the game isnt even loaded, which causes differences in classes, and some confusion in the JVM in general as the two instances share the same classes folder (I think)

I’d love to investigate more but I dont know where to take it, past sifting the .class files finding client-only code being run on the server+client instance.

Since April I’ve done two things to fix this,

  1. A separate clientRun task that builds in a different folder than run, but to no avail. (Still crashes with the same errors)
  2. Copied the entire root folder and ran the game concurrently, this worked but copying the game to test multiplayer is very tedious!

If anyone has more info on why these crashes are happening I’d be grateful! And thanks guys for the jar code, but running the game through a built jar each time is more of an afterthought that wouldn’t be convenient.