Jump to content
Search In
  • More options...
Find results that contain...
Find results in...

[How-To]Build multiple separate projects with Gradle


GotoLink
 Share

Recommended Posts

This post is meant to help those not accustomed to building with Gradle, but wanting to use separate directories for making mods. (I think some people name it "Pahimar setup" or something...)

As each setup can be different, I will take mine as a reference (the "Goto setup" :P), and explain it as simply as possible.

 

Before beginning

This tutorial is meant to be IDE independent, and as such, use "conventional" naming of things and doesn't describe IDE settings step. Those you should know how to do, since you are supposed to choose your IDE while learning to code.

 

For example, a "Project" is a group of resources, eventually with dependencies, that can be run. Eclipse uses this term, while IntellijIdea uses "Module". Not to be confused with IntellijIdea "Project" (which can be a group of projects) nor Gradle "Project", which are things that can be "built" through Gradle.

 

I personally go with one "Project" = one mod = one Gradle "Project". (because Forge recommended it this way, and it makes sense too)

 

The "dependency" setup

This setup is based on dependencies, so build files are simplified and easier to change.

 

My directories are as follows:

-Forge (the folder inside which forge source has been extracted, per the main tutorial)

\build.gradle

\settings.gradle

-Project1 (another folder, which contains the mod1)

\build.gradle

-Project2 (another folder, which contains the mod2)

etc.

 

Note the new file, settings.gradle, which only contain:

includeFlat 'Project1','Project2'

This basically specify that "Project1" and "Project2" folders depend on the Forge folder. For example you code a main core API in the Forge source, and dependent mods in the other folders. You can add more to the list.

Specific subfolders can be added with line such as 'Project/subfolder'.

You can make it a bit more intelligent with code for folder look-up, but this is outside of my post scope.

 

build.gradle in Forge folder is a modified version of the file shipped with Forge sources:

[spoiler=For 1.6.4]

buildscript {
    repositories {
        mavenCentral()
        maven {
            name = "forge"
            url = "http://files.minecraftforge.net/maven"
        }
    }
    dependencies {
        classpath 'net.minecraftforge.gradle:ForgeGradle:1.0-SNAPSHOT'
    }
}
allprojects {
    apply plugin: 'forge'
    minecraft{version = "1.6.4-9.11.1.964"}
    version = "1.0"
    archivesBaseName = project.projectDir.name
}

 

 

[spoiler=For 1.7.2]

buildscript {
    repositories {
        mavenCentral()
        maven {
            name = "forge"
            url = "http://files.minecraftforge.net/maven"
        }maven {
            name = "sonatype"
            url = "https://oss.sonatype.org/content/repositories/snapshots/"
        }
    }
    dependencies {
        classpath 'net.minecraftforge.gradle:ForgeGradle:1.1-SNAPSHOT'
    }
}
allprojects {
    apply plugin: 'forge'
    minecraft{version = "1.7.2-10.12.0.985"}
    version = "1.0"
    archivesBaseName = project.projectDir.name
}

 

 

It adds a body to "allprojects" with basic settings, such as applying forge, settings minecraft version and a general name for the mod jar. (

archivesBaseName

) This body applies parameters to all projects, including the Forge one.

Use "subprojects" to work on all projects except the Forge one.

 

Let see how it simplify the mod build.gradle, for example the Project1/build.gradle:

version = "1.1"
sourceSets.main{
    java{
srcDirs project.projectDir.getPath() exclude ("bin/**", "build*")
}
    resources{
srcDirs project.projectDir.getPath() exclude ("bin/**", "build*")
}
}
processResources {
    // replace stuff in mcmod.info, nothing else
    from(sourceSets.main.resources.srcDirs) {
        include 'mcmod.info'
    // replace $version and $mcversion
        expand 'version':project.version, 'mcversion':project.minecraft.version
    }

    // copy everything else, thats not the mcmod.info
    from(sourceSets.main.resources.srcDirs) {
        exclude 'mcmod.info'
    }
}

The first body is made to set the mod source differently. With this, the "Project1" folder contains directly the source package, without "src/main/" intermediate folders, and making sure all superfluous files are excluded (here, a "bin" folder, and any file or folder whose name begin with "build").

Project1
\assets\modid1\textures\...
\mods\modid1\...

Of course, this entire file is optional and highly dependent on your own setup.

Note that

project.projectDir

reference the folder as File, for easy copy-pasting in another mod folder.

 

Now we can test the build with

gradlew build

by command line in Forge folder.

 

Or with the Gradle plugin in Eclipse, open the gradle view and launch the "build" task for the Forge imported Gradle project.

 

You should now have a simple jar into each Project/build/libs :)

 

 

The "Independent" setup

Again, you have multiple mods in separate folders, but don't want to use the Forge folder, nor do you want to build all mods at the same time.

Indeed, you don't need to.

Per the main tutorial, you made a Forge project, ran with either

gradlew setupDevWorkspace

or

gradlew setupDecompWorkspace

ForgeGradle and its dependencies should now be cached.

 

Copy over the build.gradle file from the Forge folder in all your mods roots. (plus the gradle folder and gradlew files if you don't want to install Gradle)

You can now delete the Forge project folder.

 

With this project structure:

Project2
\resources\assets\modid\textures\...
\src\mods\modid\...
\build.gradle

 

A valid build.gradle file is:

[spoiler=For 1.6.4]

buildscript {
    repositories {
        mavenCentral()
        maven {
            name = "forge"
            url = "http://files.minecraftforge.net/maven"
        }
    }
    dependencies {
        classpath 'net.minecraftforge.gradle:ForgeGradle:1.0-SNAPSHOT'
    }
}
apply plugin: 'forge'
minecraft{version = "1.6.4-9.11.1.964"}
version = "1.0"//Set the mod version, is appended to the end of the jar name
archivesBaseName = project.projectDir.name// Set the jar name as the project root folder name
//Optional: change the project structure
sourceSets.main{
    java{
srcDirs 'src'//set the source folder as the /src subfolder
}
    resources{
srcDirs 'resources'//set the resources folder as the /resources subfolder
}
}
processResources {
    // replace stuff in mcmod.info, nothing else
    from(sourceSets.main.resources.srcDirs) {
        include 'mcmod.info'
        // replace $version and $mcversion
        expand 'version':project.version, 'mcversion':project.minecraft.version
    }

    // copy everything else, thats not the mcmod.info
    from(sourceSets.main.resources.srcDirs) {
        exclude 'mcmod.info'
    }
}

 

 

[spoiler=For 1.7.2]

buildscript {
    repositories {
        mavenCentral()
        maven {
            name = "forge"
            url = "http://files.minecraftforge.net/maven"
        }maven {
            name = "sonatype"
            url = "https://oss.sonatype.org/content/repositories/snapshots/"
        }
    }
    dependencies {
        classpath 'net.minecraftforge.gradle:ForgeGradle:1.1-SNAPSHOT'
    }
}
apply plugin: 'forge'
minecraft{version = "1.7.2-10.12.0.985"}
version = "1.0"//Set the mod version, is appended to the end of the jar name
archivesBaseName = project.projectDir.name// Set the jar name as the project root folder name
//Optional: change the project structure
sourceSets.main{
    java{
srcDirs 'src'//set the source folder as the /src subfolder
}
    resources{
srcDirs 'resources'//set the resources folder as the /resources subfolder
}
}
processResources {
    // replace stuff in mcmod.info, nothing else
    from(sourceSets.main.resources.srcDirs) {
        include 'mcmod.info'
    // replace $version and $mcversion
        expand 'version':project.version, 'mcversion':project.minecraft.version
    }

    // copy everything else, thats not the mcmod.info
    from(sourceSets.main.resources.srcDirs) {
        exclude 'mcmod.info'
    }
}

 

 

 

You can now import the mod project in your favourite IDE , with the build.gradle file.

 

You can also run

gradlew build

by command line in a project folder, to get the corresponding mod jar in its build/libs subfolder. :)

Link to comment
Share on other sites

Thanks for your guide. I begin to understand what gradle is being used for (or atleast whats the intention :) )

 

People call this setup "Pahimar-Setup", because Pahimar (Youtube Channel) introduced some tutorials on how to setup eclipse to include each mod as a separate project.

 

Now I'm looking for on how to teach IntelliJ to load my sub-modules as separate mods.

Link to comment
Share on other sites

Yeah, this is the nice part of Gradle for us modders, looks at lot better than Ant script IMO :)

And don't forget the automated forge updates.

 

Ok, fixed Pahimar name :P

 

I think IntelliJ can import Gradle projects if you point it the build.gradle file.

You might have to change the run configuration on your own though.

Link to comment
Share on other sites

Thank you for that clarification. Is there any way to include the Project1 and Project2 outlined in the code block?

Development
    Forge
        the stuff normally in the forge dir
    src
        Project1
            Project1 Stuff
        Project2
            Project2 Stuff

Link to comment
Share on other sites

Aboout this piece of code:

sourceSets.main{
    java{
srcDirs project.projectDir.getPath() exclude ("bin/", "build*")
}
    resources{
srcDirs project.projectDir.getPath() exclude ("bin/", "build*")
}
}
version = "1.1"

is that code in the build.gradle in the forge folder, or is is it the build.gradle in the "Project1" folder?

Don't PM me with questions. They will be ignored! Make a thread on the appropriate board for support.

 

1.12 -> 1.13 primer by williewillus.

 

1.7.10 and older versions of Minecraft are no longer supported due to it's age! Update to the latest version for support.

 

http://www.howoldisminecraft1710.today/

Link to comment
Share on other sites

Could you please update the main post so it fits the 1.7 upgrade because a lot of stuff changed in 1.7 so there's a new gradle version?

Don't PM me with questions. They will be ignored! Make a thread on the appropriate board for support.

 

1.12 -> 1.13 primer by williewillus.

 

1.7.10 and older versions of Minecraft are no longer supported due to it's age! Update to the latest version for support.

 

http://www.howoldisminecraft1710.today/

Link to comment
Share on other sites

I have to admit that I could only get this to work once... there is something I am missing.

 

I have added the allprojects section to build.gradle (as listed in the OP), and I can successfully build the project with no errors, but this is only as long as there is no settings.gradle file with includeFlat 'someproject' (as in it only builds the main project)

 

as soon as i try to add a project to settings.gradle I get this error:

 

* Where:
Build file 'C:\Users\tenowg\Desktop\Forge\EclipseTest\build.gradle' line: 19

* What went wrong:
A problem occurred evaluating root project 'EclipseTest'.
> java.lang.NullPointerException (no error message)

 

EclipseTest is the main test project, I have tried the following:

 

  • Creating a full project as the subproject (and rewriting the build.gradle for the subproject)
  • Creating a empty project with just the build.gradle (and without)
  • Letting it create the folders
  • beating my head on the keyboard

 

This is under 1.7.2.... using all builds I could find.

 

I have tried all this in IntelliJ and Eclipse

 

The error line is always on the "apply plugin: forge" in build.gradle of the main project.

 

Maybe a complete "noob" step by step version?

 

Thanks again, and I do know this works, as it has worked once, but I can't seem to replicate it...

 

 

Link to comment
Share on other sites

At the independent setup, you said that you need to setup your forge folder with either "gradlew setupDecompWorkspace" or "gradlew setupDevWorkspace". Do you also need to run "gradlew eclipse" to make it work, cause i did everything you said in the post, but if i import a existing project into workspace, it can't find my project.

 

PS: i didn't use the gradle plugin for eclipse because it seems like i don't have the eclipse marketplace...

Don't PM me with questions. They will be ignored! Make a thread on the appropriate board for support.

 

1.12 -> 1.13 primer by williewillus.

 

1.7.10 and older versions of Minecraft are no longer supported due to it's age! Update to the latest version for support.

 

http://www.howoldisminecraft1710.today/

Link to comment
Share on other sites

I have to admit that I could only get this to work once... there is something I am missing.

 

I have added the allprojects section to build.gradle (as listed in the OP), and I can successfully build the project with no errors, but this is only as long as there is no settings.gradle file with includeFlat 'someproject' (as in it only builds the main project)

So your setup should be like:

Forge
\EclipseTest
->build.gradle
->settings.gradle
\someproject
->build.gradle (optional)

 

Make sure the 'allprojects" body is between the "buildscript" and the "processResources" bodies.

Try to

gradlew clean cleanEclipse cleanIdea

once before next attemp. Old build attempts could screw things.

 

You can have a try with the "Independent" setup.

I'd recommend using Eclipse with Gradle plugin to import as a Gradle Project.

Then run

gradlew clean setupDecompWorkspace eclipse

It is less clumsy that IntelliJ, IMHO.

 

@larsgerrits

Running the Forge gradlew things is only needed once, to cache the libraries. The "eclipse" task is not needed here, AFAIK, because you are not using the Forge folder to import into Eclipse.

The "independent" setup only needs a valid build.gradle file inside your project (not forge, the mod one).

Then, either import your project (not forge, the mod one) with the Gradle plugin, or, run

gradlew clean setupDecompWorkspace eclipse

at your project, then import it.

Link to comment
Share on other sites

  • 3 weeks later...

Thanks, this really helps me understand gradle abit. I'm trying to set it up so that my separate mods are source folders, and to build them separately. To test I copied the example mod and source folder and changed the names over to "test" (instead of example). I used the 1.7.4 build.gradle code from the Independent Setup, and changed the srcDirs to 'src/test'. When I build and copy the jar to minecraft, under the mods menu I get both the original example mod and my copied test mod. How can I set it up so that it excludes any other source folders in eclipse and builds a specific mod? It would be easier than moving the mods source folder out of the full directory itself, build, then replace the source folder again. Would be very tedious with more than one mod.

 

Heres a screenshot if I don't make sense (really tired while writing this):

 

http://s28.postimg.org/tc4c6a5jx/forge_help.png

 

Red and Green are separate mods and the Blue is what I changed in build.gradle

Link to comment
Share on other sites

@dev909

You didn't follow my instructions for the "Independent setup" here.

I see two mods in the same project folder, and the forge license, readme files...bad boy :P

 

The problem you might not see, is that Gradle sets by default a test folder as src/test/java and src/test/resources, but this is for testing purposes and not supposed to be built with the 'main' sources. This probably conflicts with what you set into the build.gradle file.

 

If you don't want to move out of the Forge folder, at least make a build.gradle file per mod. That is the easiest way to go.

In your situation, put them into the "main" and "test" subfolders with:

sourceSets.main{
    java{
srcDirs 'java'
}
    resources{
srcDirs 'resources'
}
}

Link to comment
Share on other sites

  • 1 month later...
  • 5 weeks later...

I get an error when importing a gradle project with the independent setup:

 

 

VC9dch1.png

 

 

This is my build.gradle:

 

 

buildscript {
    repositories {
        mavenCentral()
        maven {
            name = "forge"
            url = "http://files.minecraftforge.net/maven"
        }maven {
            name = "sonatype"
            url = "https://oss.sonatype.org/content/repositories/snapshots/"
        }
    }
    dependencies {
        classpath 'net.minecraftforge.gradle:ForgeGradle:1.2-SNAPSHOT'
    }
}
apply plugin: 'forge'
minecraft{version = "1.7.2-10.12.0.1056"}
version = "1.7.2-v0.01"
archivesBaseName = project.projectDir.name
sourceSets.main{
    java{
srcDirs 'src'
}
    resources{
srcDirs 'resources'
}
}
processResources {
    from(sourceSets.main.resources.srcDirs) {
        include 'mcmod.info'
        expand 'version':project.version, 'mcversion':project.minecraft.version
    }
    from(sourceSets.main.resources.srcDirs) {
        exclude 'mcmod.info'
    }
}

 

 

Don't PM me with questions. They will be ignored! Make a thread on the appropriate board for support.

 

1.12 -> 1.13 primer by williewillus.

 

1.7.10 and older versions of Minecraft are no longer supported due to it's age! Update to the latest version for support.

 

http://www.howoldisminecraft1710.today/

Link to comment
Share on other sites

I ticked the "Run before" box, and changed that line next to it to "cleanEclipse setupDevWorkspace eclipse", but i got the same error.

Don't PM me with questions. They will be ignored! Make a thread on the appropriate board for support.

 

1.12 -> 1.13 primer by williewillus.

 

1.7.10 and older versions of Minecraft are no longer supported due to it's age! Update to the latest version for support.

 

http://www.howoldisminecraft1710.today/

Link to comment
Share on other sites

I searched over the internet, but i couldn't find a solution. Can you help me with this or are you out of ideas too?

Don't PM me with questions. They will be ignored! Make a thread on the appropriate board for support.

 

1.12 -> 1.13 primer by williewillus.

 

1.7.10 and older versions of Minecraft are no longer supported due to it's age! Update to the latest version for support.

 

http://www.howoldisminecraft1710.today/

Link to comment
Share on other sites

  • 3 months later...
  • 4 months later...

Having built a chunk of related but separate mods, I was keeping all the files in the same /src/main directory mostly because of not knowing what else to do, but given that I'd like to build them as separate jar files, I ended up here.

 

Good news: I got it to compile.

Bad news: it shoved them all into one jar anyway (which has a clever file name of "Forge 1180.jar")

 

Umm...what didn't I do correctly?

 

Unrelated, I should update Forge at some point, heh.

Apparently I'm a complete and utter jerk and come to this forum just like to make fun of people, be confrontational, and make your personal life miserable.  If you think this is the case, JUST REPORT ME.  Otherwise you're just going to get reported when you reply to my posts and point it out, because odds are, I was trying to be nice.

 

Exception: If you do not understand Java, I WILL NOT HELP YOU and your thread will get locked.

 

DO NOT PM ME WITH PROBLEMS. No help will be given.

Link to comment
Share on other sites

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
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.

 Share



  • Recently Browsing

    No registered users viewing this page.

  • Posts

    • Use the forge provided spawn egg. Not your current hack.
    • Lol. I didn't mean the literate word. Of course I can review that in a translator. By definition that would mean "to repeatedly, or in succession tag/label/numerize/sent/release something", if related to actual code? I may as well completely expressed myself wrongly. What I mend was, when do I want to use it? Is it comparable to a "for loop", only it automatically applies numbered variables? Does it have any relation to "produce in series"? I've seen people using it, and asking for it all the time, yet I haven't had a case to use it myself. I just want to prepared, so I actually understand when I want to use it, once it shows up. I guess I'd use it when a serializer doesn't exist for a given tag/recipe/loot_table etc.?
    • Error = Required RegistryObject<?extends EntityType<?>> Provided EntityType<SKELETON>
    • What's then the problem? As uSkizzik already mentioned Forge has their own SpawnEggItem use it
    • I think the error comes from this java class even though it dosen't show any error -  package com.mahidhoni123.forgemod.items; import net.minecraft.core.BlockSource; import net.minecraft.core.Direction; import net.minecraft.core.dispenser.DefaultDispenseItemBehavior; import net.minecraft.nbt.CompoundTag; import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.MobSpawnType; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.SpawnEggItem; import net.minecraft.world.level.block.DispenserBlock; import net.minecraftforge.common.util.Lazy; import net.minecraftforge.fml.util.ObfuscationReflectionHelper; import net.minecraftforge.fmllegacy.RegistryObject; import java.util.ArrayList; import java.util.List; import java.util.Map; public class ModSpawnEggItem extends SpawnEggItem { protected static final List<ModSpawnEggItem> UNADDED_EGGS = new ArrayList<>(); private final Lazy<? extends EntityType<?>> entityTypeSupplier; public ModSpawnEggItem(final RegistryObject<? extends EntityType<?>> entityTypeSupplier, int p_43208_, int p_43209_, Properties p_43210_) { super(null, p_43208_, p_43209_, p_43210_); this.entityTypeSupplier = Lazy.of(entityTypeSupplier::get); UNADDED_EGGS.add(this); } public static void initSpawnEggs(){ final Map<EntityType<?>, SpawnEggItem> EGGS = ObfuscationReflectionHelper.getPrivateValue(SpawnEggItem.class, null, "field_195987_b"); DefaultDispenseItemBehavior dispenseBehavior = new DefaultDispenseItemBehavior() { @Override protected ItemStack execute(BlockSource p_123385_, ItemStack p_123386_) { Direction direction = p_123385_ .getBlockState().getValue(DispenserBlock.FACING); EntityType<?> type = ((SpawnEggItem) p_123386_.getItem()).getType(p_123386_.getTag()); type.spawn(p_123385_.getLevel(), p_123386_, null, p_123385_.getPos(), MobSpawnType.DISPENSER, direction != Direction.UP, false); p_123386_.shrink(1); return p_123386_; } }; for (final SpawnEggItem spawnEgg : UNADDED_EGGS) { EGGS.put(spawnEgg.getType(null ), spawnEgg); DispenserBlock.registerBehavior(spawnEgg, dispenseBehavior); } UNADDED_EGGS.clear(); } @Override public EntityType<?> getType(CompoundTag nbt) { return this.entityTypeSupplier.get(); } }  
  • Topics

  • Who's Online (See full list)

×
×
  • Create New...

Important Information

By using this site, you agree to our Privacy Policy.