Search code examples
gradleintellij-ideabuild.gradleminecraft-forge

Minecraft Forge assets not loading on Intellij


I’m working on a Forge mod for Minecraft 1.12 on Intellij. Like a lot of people I ran into the issue of assets not being loaded when running the game from the IDE. All solutions that I tried have failed so far:

A lot of people have suggested to add the code below to build.gradle, but it raises an error because classesDir is deprecated; replacing it with classesDirs raises another error.

sourceSets {
    main { output.resourcesDir = output.classesDir }
}

I changed the “Build and run using” setting from “Gradle” to “Intellij IDEA” in Build, Execution, Deployment > Build Tools > Gradle but I did not fix the problem either.

Additionally, when I try to build the jar, I get the following error: Entry assets/mccode/lang/en_us.lang is a duplicate but no duplicate handling strategy has been set. I don’t know what’s wrong here neither…

Here is the build.gradle script I’m using, as generated by Intellij:

buildscript {
    repositories {
        // These repositories are only for Gradle plugins, put any other repositories in the repository block further below
        maven { url = 'https://maven.minecraftforge.net' }
        mavenCentral()
    }
    dependencies {
        classpath group: 'net.minecraftforge.gradle', name: 'ForgeGradle', version: '5.1.+', changing: true
    }
}

apply plugin: 'net.minecraftforge.gradle'

group = 'net.darmo_creations.mccode'
version = '1.0'

java {
    archivesBaseName = 'mccode'
    toolchain.languageVersion = JavaLanguageVersion.of(8)
}

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: 'stable', version: '39-1.12'

    // 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 added/removed as needed separated by commas.
            // "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 {
                mc_code {
                    source sourceSets.main
                }
            }
        }

        server {
            workingDirectory project.file('run')

            // Recommended logging data for a userdev environment
            // The markers can be added/removed as needed separated by commas.
            // "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 {
                mc_code {
                    source sourceSets.main
                }
            }
        }
    }
}

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

repositories {
    // Put repositories for dependencies here
    // ForgeGradle automatically adds the Forge maven and Maven Central for you

    // If you have mod jar dependencies in ./libs, you can declare them as a repository like so:
    // flatDir {
    //     dir 'libs'
    // }
}

dependencies {
    // Specify the version of Minecraft to use. If this is any group other than 'net.minecraft' it is assumed
    // that the dep is a ForgeGradle 'patcher' dependency, and its 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.12.2-14.23.5.2854'

    // Real mod deobf dependency examples - these get remapped to your current mappings
    // compileOnly fg.deobf("mezz.jei:jei-${mc_version}:${jei_version}:api") // Adds JEI API as a compile dependency
    // runtimeOnly fg.deobf("mezz.jei:jei-${mc_version}:${jei_version}") // Adds the full JEI mod as a runtime dependency
    // implementation fg.deobf("com.tterrag.registrate:Registrate:MC${mc_version}-${registrate_version}") // Adds registrate as a dependency
    implementation "org.antlr:antlr4:4.9.3"

    // Examples using mod jars from ./libs
    // implementation fg.deobf("blank:coolmod-${mc_version}:${coolmod_version}")

    // 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 at runtime.
jar {
    manifest {
        attributes([
                "Specification-Title"     : "mc_code",
                "Specification-Vendor"    : "Darmo",
                "Specification-Version"   : "1", // We are version 1 of ourselves
                "Implementation-Title"    : project.name,
                "Implementation-Version"  : project.jar.archiveVersion,
                "Implementation-Vendor"   : "Darmo",
                "Implementation-Timestamp": new Date().format("yyyy-MM-dd'T'HH:mm:ssZ")
        ])
    }
}

jar.finalizedBy('reobfJar')

What am I doing wrong? I don’t understand why Intellij is not capable of properly setting up Forge projects by itself…


Solution

  • Here's an adjusted version that works on ForgeGradle 5/Gradle 7 (and will also work if you make source sets other than main):

    sourceSets.all {
      it.output.resourcesDir = it.output.classesDirs.getFiles().iterator().next()
    }
    

    No need to downgrade to Gradle 4 or "build and run with intellij", this should just work™.

    The reason classesDir-singular was removed is because Gradle now supports multiple JVM languages at the same time - your project might compile Java classes to ./build/classes/main/java and Scala classes to ./build/classes/main/scala, for example, so there might be more than one classesDir.

    classesDirs-plural is a FileCollection, so you need to use .getFiles() to turn it into a Set<File>, then pick one arbitrarily with .iterator().next() - it doesn't matter which one you pick, all that matters is that resources end up in some directory that ends up on the classpath, because that's the only way Forge 1.12.2 knows how to load resources.