Jump to content

Add external jar as dependency - NoClassDefFoundError in Forge 1.16


Recommended Posts

Posted (edited)

I have tried all imaginable configurations in order to load an external jar to my mod.

Forge version: 1.16

IDE: IntelliJ

Java: 11.0.11 for building and running

 

On 1.12 version I used to simply add the jars to the build.gradle with the `compile files()` command and then add them to the mods folder together with the mod jar. It used to work. But now it seems it cannot find the jars anymore. I'll post the logs at the end. Even more I scanned for IO access from the java (procmon) and I can't see it trying to read any file when the function containing the external reference is called (I suppose it loads the jar on request).

I admit I am confused about all the maven and "libraries" vs "libs" features. I noticed that everything in META-INF in src/main/resources is automatically included in the final jar. But if this is supposed to happen what's with all the maven? Isn't maven supposed to automatically download jars from some public repository/local repo when needed? Why bundle it in the jar and then require the special .meta files just to make it work?

Here's what I tried for the build.gradle. I tried many different configurations but the uncommented one is aproximatelly what worked in the past.

buildscript {
    repositories {
        maven { url = 'https://maven.minecraftforge.net' }
        mavenCentral()

    }
    dependencies {
        classpath group: 'net.minecraftforge.gradle', name: 'ForgeGradle', version: '4.1.+', changing: true
    }
}

repositories {

    mavenLocal()
    mavenCentral()


    flatDir {
        dirs 'C:\\MinecraftForge\\Forge1.16\\src\\main\\resources\\META-INF\\libraries'
    }

}

configurations {
    inJar
}
configurations.compile.extendsFrom(configurations.inJar)

dependencies {
	// Old fashioned way that worked before
    compile files("libs/automaton.jar","libs/xeger.jar")

	// Tried the maven public repository - I am afraid that this old library could actually contain malware
     // implementation group: 'nl.flotsam', name: 'xeger', version: '1.0.0-lorislab-1'

     // Seen this on another forum - adding the jars to the maven with the .maven file and including for the local repo
     //inJar 'com.lumieresombre.lib:xeger:1.0.0'
     //inJar 'com.lumieresombre.lib:automaton:1.0.0'

		// Something else I tried. Didn't work. Could
//    compile "com.lumieresombre.lib:xeger:1.0.0"
//    compile "com.lumieresombre.lib:automaton:1.0.0"

}

// Example for how to get properties into the manifest for reading by the runtime..
jar {
    from(configurations.inJar) {
        into 'META-INF/libraries'
    }

    manifest {
        attributes([
            "Specification-Title": "examplemod",
            "Specification-Vendor": "examplemodsareus",
            "Specification-Version": "1", // We are version 1 of ourselves
            "Implementation-Title": project.name,
            "Implementation-Version": "${version}",
            "Implementation-Vendor" :"examplemodsareus",
            "Implementation-Timestamp": new Date().format("yyyy-MM-dd'T'HH:mm:ssZ"),
            "ContainedDeps":"automaton-1.0.0.jar xeger-1.0.0.jar"
        ])
    }
}

// Example configuration to allow publishing using the maven-publish task
// This is the preferred method to reobfuscate your jar file
jar.finalizedBy('reobfJar') 
// However if you are in a multi-project build, dev time needs unobfed jar files, so you can delay the obfuscation until publishing by doing
//publish.dependsOn('reobfJar')

publishing {
    publications {
        mavenJava(MavenPublication) {
            artifact jar
        }
    }
    repositories {

        maven {
            url "file:///${project.projectDir}/mcmodsrepo"
        }
    }
}

 

I read here about inserting all the jars in the libraries folder and that the mod loader will take care of everything. I am not sure if it still exists in the 1.16

The mod jar did get large but gave the same error.

 

Then I read about moving the libs to maven. I tried this variant using a local repo aka flatDir. Here you can see my confusion: I pointed the flatDirs to the libraries folder which already contained the needed .meta files. This gave the same result.

Then I read that I can specify the dependencies in the jar classpath/manifest. I am not sure if I should have copied the file to the final jar path or if it was included in the file.

What should I do? I just want to drop the jars near the mod file and make it work.

 

The error log:

https://pastebin.com/KJF37fZ6

 

And here's the code around the line of the crash:

    protected void init() {
        // Create the options row list
        // It must be created in this method instead of in the constructor,
        // or it will not be displayed properly
        this.optionsRowList = new OptionsRowList(
                this.minecraft, this.width, this.height,
                OPTIONS_LIST_TOP_HEIGHT,
                this.height - OPTIONS_LIST_BOTTOM_OFFSET,
                OPTIONS_LIST_ITEM_HEIGHT
        );

        // Add the options row list as this screen's child
        // If this is not done, users cannot click on items in the list
        this.children.add(this.optionsRowList);

        IteratableOption usernameChanger=new IteratableOption(
                "hbwhelper.configGui.dreamMode.title",
                (unused, newValue) -> {
                    Xeger generator = new Xeger(GeneralConfig.get().username_generator);
                    String result = generator.generate();

                    Main.ReflectionChangeUsername(result);
                },
                (unused, option) -> new StringTextComponent("Username: "+Minecraft.getInstance().getUser().getName())
        );

        SliderPercentageOption attackProbability=new SliderPercentageOption(
                "Attack Probability",
                // Range: 0 to width of game window
                0.0, 100,
                // Steps
                0.5F,
                // Getter and setter are similar to those in BooleanOption
                unused -> GeneralConfig.get().constants.hit_probability,
                (unused, newValue) -> GeneralConfig.get().constants.hit_probability=newValue,
                // BiFunction that returns a string text component
                // in format "<name>: <value>"
                (gs, option) -> new StringTextComponent("Probability: "+GeneralConfig.get().constants.hit_probability)
        );


        this.optionsRowList.addBig(usernameChanger);

        this.optionsRowList.addBig(attackProbability);


        // Add the "Done" button
        this.addButton(new Button(
                (this.width - BUTTON_WIDTH) / 2,
                this.height - DONE_BUTTON_TOP_OFFSET,
                BUTTON_WIDTH, BUTTON_HEIGHT,
                // Text shown on the button
                new TranslationTextComponent("gui.done"),
                // Action performed when the button is pressed
                button -> this.onClose()
        ));


    }

 

Edited by Antonii
Add more code
Posted

Yes finally. I took some suggestions from here

The libraries are now embedded and loaded on runtime.

I used embed and works perfectly. This is the final configuration:

 

buildscript {
    repositories {
        maven { url = 'https://maven.minecraftforge.net' }
        mavenCentral()

    }
    dependencies {
        classpath group: 'net.minecraftforge.gradle', name: 'ForgeGradle', version: '4.1.+', changing: true
    }
}
apply plugin: 'net.minecraftforge.gradle'
// Only edit below this line, the above code adds and enables the necessary things for Forge to be setup.
apply plugin: 'eclipse'
apply plugin: 'maven-publish'

version = '1.0'
group = 'com.lumieresombre.horizonprivatemodid' // http://maven.apache.org/guides/mini/guide-naming-conventions.html
archivesBaseName = 'modid'

java.toolchain.languageVersion = JavaLanguageVersion.of(11) // Mojang ships Java 8 to end users, so your mod should target Java 8.

println('Java: ' + System.getProperty('java.version') + ' JVM: ' + System.getProperty('java.vm.version') + '(' + System.getProperty('java.vendor') + ') Arch: ' + System.getProperty('os.arch'))
minecraft {
    // The mappings can be changed at any time, and must be in the following format.
    // Channel:   Version:
    // snapshot   YYYYMMDD   Snapshot are built nightly.
    // stable     #          Stables are built at the discretion of the MCP team.
    // official   MCVersion  Official field/method names from Mojang mapping files
    //
    // You must be aware of the Mojang license when using the 'official' mappings.
    // See more information here: https://github.com/MinecraftForge/MCPConfig/blob/master/Mojang.md
    //
    // Use non-default mappings at your own risk. they may not always work.
    // Simply re-run your setup task after changing the mappings to update your workspace.
    mappings channel: 'official', version: '1.16.5'
    // makeObfSourceJar = false // an Srg named sources jar is made by default. uncomment this to disable.
    
    // accessTransformer = file('src/main/resources/META-INF/accesstransformer.cfg')

    // Default run configurations.
    // These can be tweaked, removed, or duplicated as needed.
    runs {
        client {
            workingDirectory project.file('run')

            // Recommended logging data for a userdev environment
            // The markers can be changed as needed.
            // "SCAN": For mods scan.
            // "REGISTRIES": For firing of registry events.
            // "REGISTRYDUMP": For getting the contents of all registries.
            property 'forge.logging.markers', 'REGISTRIES'

            // Recommended logging level for the console
            // You can set various levels here.
            // Please read: https://stackoverflow.com/questions/2031163/when-to-use-the-different-log-levels
            property 'forge.logging.console.level', 'debug'

            mods {
                horizonprivatemodid{
                    source sourceSets.main
                }
            }
        }

        server {
            workingDirectory project.file('run')

            // Recommended logging data for a userdev environment
            // The markers can be changed as needed.
            // "SCAN": For mods scan.
            // "REGISTRIES": For firing of registry events.
            // "REGISTRYDUMP": For getting the contents of all registries.
            property 'forge.logging.markers', 'REGISTRIES'

            // Recommended logging level for the console
            // You can set various levels here.
            // Please read: https://stackoverflow.com/questions/2031163/when-to-use-the-different-log-levels
            property 'forge.logging.console.level', 'debug'

            mods {
                examplemod {
                    source sourceSets.main
                }
            }
        }

        data {
            workingDirectory project.file('run')

            // Recommended logging data for a userdev environment
            // The markers can be changed as needed.
            // "SCAN": For mods scan.
            // "REGISTRIES": For firing of registry events.
            // "REGISTRYDUMP": For getting the contents of all registries.
            property 'forge.logging.markers', 'REGISTRIES'

            // Recommended logging level for the console
            // You can set various levels here.
            // Please read: https://stackoverflow.com/questions/2031163/when-to-use-the-different-log-levels
            property 'forge.logging.console.level', 'debug'

            // Specify the modid for data generation, where to output the resulting resource, and where to look for existing resources.
            args '--mod', 'examplemod', '--all', '--output', file('src/generated/resources/'), '--existing', file('src/main/resources/')

            mods {
                horizonprivatemodid{
                    source sourceSets.main
                }
            }
        }
    }
}

repositories {

    mavenLocal()
    mavenCentral()

    flatDir {
        dirs 'libs\\'
    }

}


// Include resources generated by data generators.
sourceSets.main.resources { srcDir 'src/generated/resources' }

configurations {
    embed
}

dependencies {
    // Specify the version of Minecraft to use, If this is any group other then 'net.minecraft' it is assumed
    // that the dep is a ForgeGradle 'patcher' dependency. And it's patches will be applied.
    // The userdev artifact is a special name and will get all sorts of transformations applied to it.
    minecraft 'net.minecraftforge:forge:1.16.5-36.1.24'

    // You may put jars on which you depend on in ./libs or you may define them like so..
    // compile "some.group:artifact:version:classifier"
    // compile "some.group:artifact:version"

    //compile files("libs/automaton.jar","libs/xeger-1.0-SNAPSHOT.jar")

    compile "com.lumieresombre.lib:xeger:1.0.0"
    compile "com.lumieresombre.lib:automaton:1.0.0"

    embed "com.lumieresombre.lib:xeger:1.0.0"
    embed "com.lumieresombre.lib:automaton:1.0.0"

    // Real examples
    // compile 'com.mod-buildcraft:buildcraft:6.0.8:dev'  // adds buildcraft to the dev env
    // compile 'com.googlecode.efficient-java-matrix-library:ejml:0.24' // adds ejml to the dev env

    // The 'provided' configuration is for optional dependencies that exist at compile-time but might not at runtime.
    // provided 'com.mod-buildcraft:buildcraft:6.0.8:dev'

    // These dependencies get remapped to your current MCP mappings
    // deobf 'com.mod-buildcraft:buildcraft:6.0.8:dev'

    // For more info...
    // http://www.gradle.org/docs/current/userguide/artifact_dependencies_tutorial.html
    // http://www.gradle.org/docs/current/userguide/dependency_management.html

}

// Example for how to get properties into the manifest for reading by the runtime..
jar {
    manifest {
        attributes([
            "Specification-Title": "examplemod",
            "Specification-Vendor": "examplemodsareus",
            "Specification-Version": "1", // We are version 1 of ourselves
            "Implementation-Title": project.name,
            "Implementation-Version": "${version}",
            "Implementation-Vendor" :"examplemodsareus",
            "Implementation-Timestamp": new Date().format("yyyy-MM-dd'T'HH:mm:ssZ"),
            "ContainedDeps":"automaton-1.0.0.jar xeger-1.0.0.jar",
            "Class-Path":"automaton-1.0.0.jar xeger-1.0.0.jar"
        ])
    }
    from configurations.embed.collect { it.isDirectory() ? it : zipTree(it) }
}

// Example configuration to allow publishing using the maven-publish task
// This is the preferred method to reobfuscate your jar file
jar.finalizedBy('reobfJar') 
// However if you are in a multi-project build, dev time needs unobfed jar files, so you can delay the obfuscation until publishing by doing
//publish.dependsOn('reobfJar')

publishing {
    publications {
        mavenJava(MavenPublication) {
            artifact jar
        }
    }
    repositories {

        maven {
            url "file:///${project.projectDir}/mcmodsrepo"
        }
    }
}

 

  • Thanks 1

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Announcements



×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.