Skip to content

Commit

Permalink
[Feature]: Add support for DevLogin (#192)
Browse files Browse the repository at this point in the history
  • Loading branch information
marchermans authored Jun 4, 2024
1 parent 87633a9 commit 602139f
Show file tree
Hide file tree
Showing 11 changed files with 274 additions and 12 deletions.
96 changes: 95 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -335,7 +335,6 @@ By default, the import in IDEA is run during the sync task.
If you want to disable this, and use a post sync task, you can set the following property in your gradle.properties:
```properties
neogradle.subsystems.conventions.ide.idea.use-post-sync-task=true

```

### Runs
Expand All @@ -359,3 +358,98 @@ The following properties can be used to configure the JST tool:
```properties
neogradle.subsystems.tools.jst=<artifact coordinate for jst cli tool>
```
### DevLogin
This tool is used by the runs subsystem to enable Minecraft authentication in client runs.
The following properties can be used to configure the DevLogin tool:
```properties
neogradle.subsystems.tools.devLogin=<artifact coordinate for devlogin cli tool>
```
More information on the relevant tool, its released version and documentation can be found here: [DevLogin by Covers1624](https://github.com/covers1624/DevLogin)

## DevLogin
The DevLogin tool is a tool that allows you to log in to a Minecraft account without having to use the Minecraft launcher, during development.
During first start it will show you a link to log in to your Minecraft account, and then you can use the tool to log in to your account.
The credentials are cached on your local machine, and then reused for future logins, so that re-logging is only needed when the tokens expire.
This tool is used by the runs subsystem to enable logged in plays on all client runs.
The tool can be configured using the following properties:
```properties
neogradle.subsystems.devLogin.enabled=<true/false>
```
By default, the subsystem is enabled, and it will prepare everything for you to log in to a Minecraft account, however you will still need to enable it on the runs you want.
If you want to disable this you can set the property to false, and then you will not be asked to log in, but use a random non-signed in dev account.

### Per run configuration
If you want to configure the dev login tool per run, you can do so by setting the following properties in your run configuration:
```groovy
runs {
someRun {
devLogin {
enabled true
}
}
}
```
This will enable the dev login tool for this run.
By default, the dev login tool is disabled, and can only be enabled for client runs.

> [!WARNING]
> If you enable the dev login tool for a non-client run, you will get an error message.
If you want to enable the dev login tool for all client runs, you can set the following property in your gradle.properties:
```properties
neogradle.subsystems.devLogin.conventionForRun=true
```
This will enable the dev login tool for all client runs, unless explicitly disabled.

Additionally, it is possible to use a different user profile for the dev login tool, by setting the following property in your run configuration:
```groovy
runs {
someRun {
devLogin {
profile '<profile>'
}
}
}
```
If it is not set then the default profile will be used. See the DevLogin documentation for more information on profiles: [DevLogin by Covers1624](https://github.com/covers1624/DevLogin/blob/main/README.md#multiple-accounts)

### Configurations
To add the dev login tool to your run we create a custom configuration to which we add the dev login tool.
This configuration is created for the first source-set you register with the run as a mod source set.
The suffix for the configuration can be configured to your personal preference, by setting the following property in your gradle.properties:
```properties
neogradle.subsystems.devLogin.configurationSuffix=<suffix>
```
By default, the suffix is set to "DevLoginLocalOnly".
We use this approach to create a runtime only configuration, that does not leak to other consumers of your project.

## Centralized Cache
NeoGradle has a centralized cache that can be used to store the decompiled Minecraft sources, the recompiled Minecraft sources, and other task outputs of complex tasks.
The cache is enabled by default, and can be disabled by setting the following property in your gradle.properties:
```properties
net.neoforged.gradle.caching.enabled=false
```

You can clean the artifacts that are stored in the cache by running the following command:
```shell
./gradlew cleanCache
```

This command is also automatically run, when you run the clean task.
The command will check if the stored artifact count is higher than the configured threshold, and if so, remove the oldest artifacts until the count is below the threshold.
The count is configured by the following property in your gradle.properties:
```properties
net.neoforged.gradle.caching.maxCacheSize=<number>
```

### Debugging
There are two properties you can tweak to get more information about the cache:
```properties
net.neoforged.gradle.caching.logCacheHits=<true/false>
```
and
```properties
net.neoforged.gradle.caching.debug=<true/false>
```
The first property will log when a cache hit occurs, and the second property will log more information about the cache in general, including how hashes are calculated.
If you are experiencing issues with the cache, you can enable these properties to get more information about what is happening.
Original file line number Diff line number Diff line change
Expand Up @@ -23,30 +23,31 @@
import net.neoforged.gradle.dsl.common.extensions.dependency.replacement.DependencyReplacement;
import net.neoforged.gradle.dsl.common.extensions.repository.Repository;
import net.neoforged.gradle.dsl.common.extensions.subsystems.Conventions;
import net.neoforged.gradle.dsl.common.extensions.subsystems.DevLogin;
import net.neoforged.gradle.dsl.common.extensions.subsystems.Subsystems;
import net.neoforged.gradle.dsl.common.extensions.subsystems.Tools;
import net.neoforged.gradle.dsl.common.extensions.subsystems.conventions.Configurations;
import net.neoforged.gradle.dsl.common.extensions.subsystems.conventions.IDE;
import net.neoforged.gradle.dsl.common.extensions.subsystems.conventions.Runs;
import net.neoforged.gradle.dsl.common.extensions.subsystems.conventions.SourceSets;
import net.neoforged.gradle.dsl.common.extensions.subsystems.conventions.ide.IDEA;
import net.neoforged.gradle.dsl.common.runs.run.Run;
import net.neoforged.gradle.dsl.common.runs.run.RunDevLogin;
import net.neoforged.gradle.dsl.common.runs.type.RunType;
import net.neoforged.gradle.dsl.common.util.ConfigurationUtils;
import net.neoforged.gradle.dsl.common.util.NamingConstants;
import net.neoforged.gradle.util.UrlConstants;
import org.gradle.StartParameter;
import org.gradle.TaskExecutionRequest;
import org.gradle.api.Action;
import org.gradle.api.NamedDomainObjectContainer;
import org.gradle.api.Plugin;
import org.gradle.api.Project;
import org.gradle.api.*;
import org.gradle.api.artifacts.Configuration;
import org.gradle.api.artifacts.repositories.MavenArtifactRepository;
import org.gradle.api.attributes.AttributeContainer;
import org.gradle.api.attributes.Category;
import org.gradle.api.component.AdhocComponentWithVariants;
import org.gradle.api.plugins.JavaPlugin;
import org.gradle.api.tasks.Delete;
import org.gradle.api.tasks.SourceSet;
import org.gradle.api.tasks.SourceSetContainer;
import org.gradle.api.tasks.TaskProvider;
import org.gradle.internal.DefaultTaskExecutionRequest;
Expand Down Expand Up @@ -130,9 +131,10 @@ public void apply(Project project) {
project.getObjects().domainObjectContainer(RunType.class, name -> project.getObjects().newInstance(RunType.class, name))
);

final NamedDomainObjectContainer<Run> runs = project.getObjects().domainObjectContainer(Run.class, name -> RunsUtil.create(project, name));
project.getExtensions().add(
RunsConstants.Extensions.RUNS,
project.getObjects().domainObjectContainer(Run.class, name -> RunsUtil.create(project, name))
runs
);

setupAccessTransformerConfigurations(project, accessTransformers);
Expand All @@ -149,6 +151,14 @@ public void apply(Project project) {
//Needs to be before after evaluate
configureConventions(project);

final DevLogin devLogin = project.getExtensions().getByType(Subsystems.class).getDevLogin();
if (devLogin.getEnabled().get()) {
runs.configureEach(run -> {
final RunDevLogin runsDevLogin = run.getExtensions().create("devLogin", RunDevLogin.class);
runsDevLogin.getIsEnabled().convention(devLogin.getConventionForRun());
});
}

project.afterEvaluate(this::applyAfterEvaluate);
}

Expand Down Expand Up @@ -346,6 +356,10 @@ private void applyAfterEvaluate(final Project project) {
}
}

if (run.getModSources().get().isEmpty()) {
throw new InvalidUserDataException("Run: " + run.getName() + " has no source sets configured. Please configure at least one source set.");
}

if (run.getConfigureFromDependencies().get()) {
final RunImpl runImpl = (RunImpl) run;

Expand Down Expand Up @@ -374,6 +388,41 @@ private void applyAfterEvaluate(final Project project) {
definitionSet.forEach((identifier, definition) -> {
definition.configureRun(runImpl);
});

//Handle dev login.
final DevLogin devLogin = project.getExtensions().getByType(Subsystems.class).getDevLogin();
final Tools tools = project.getExtensions().getByType(Subsystems.class).getTools();
if (devLogin.getEnabled().get()) {
final RunDevLogin runsDevLogin = runImpl.getExtensions().getByType(RunDevLogin.class);

//Dev login is only supported on the client side
if (runImpl.getIsClient().get() && runsDevLogin.getIsEnabled().get()) {
final String mainClass = runImpl.getMainClass().get();

//We add the dev login tool to a custom configuration which runtime classpath extends from the default runtime classpath
final SourceSet defaultSourceSet = runImpl.getModSources().get().get(0);
final String runtimeOnlyDevLoginConfigurationName = ConfigurationUtils.getSourceSetName(defaultSourceSet, devLogin.getConfigurationSuffix().get());
final Configuration sourceSetRuntimeOnlyDevLoginConfiguration = project.getConfigurations().maybeCreate(runtimeOnlyDevLoginConfigurationName);
final Configuration sourceSetRuntimeClasspathConfiguration = project.getConfigurations().maybeCreate(defaultSourceSet.getRuntimeClasspathConfigurationName());

sourceSetRuntimeClasspathConfiguration.extendsFrom(sourceSetRuntimeOnlyDevLoginConfiguration);
sourceSetRuntimeOnlyDevLoginConfiguration.getDependencies().add(project.getDependencies().create(tools.getDevLogin().get()));

//Update the program arguments to properly launch the dev login tool
run.getProgramArguments().add("--launch_target");
run.getProgramArguments().add(mainClass);

if (runsDevLogin.getProfile().isPresent()) {
run.getProgramArguments().add("--launch_profile");
run.getProgramArguments().add(runsDevLogin.getProfile().get());
}

//Set the main class to the dev login tool
run.getMainClass().set(devLogin.getMainClass());
} else if (!runImpl.getIsClient().get() && runsDevLogin.getIsEnabled().get()) {
throw new InvalidUserDataException("Dev login is only supported on runs which are marked as clients! The run: " + runImpl.getName() + " is not a client run.");
}
}
}
}
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,7 @@
import java.util.Collections;
import java.util.Locale;

import static net.neoforged.gradle.dsl.common.util.Constants.DEFAULT_PARCHMENT_ARTIFACT_PREFIX;
import static net.neoforged.gradle.dsl.common.util.Constants.DEFAULT_PARCHMENT_GROUP;
import static net.neoforged.gradle.dsl.common.util.Constants.DEFAULT_PARCHMENT_MAVEN_URL;
import static net.neoforged.gradle.dsl.common.util.Constants.JST_TOOL_ARTIFACT;
import static net.neoforged.gradle.dsl.common.util.Constants.DEFAULT_RECOMPILER_MAX_MEMORY;
import static net.neoforged.gradle.dsl.common.util.Constants.*;

public abstract class SubsystemsExtension extends WithPropertyLookup implements ConfigurableDSLElement<Subsystems>, Subsystems {

Expand All @@ -33,13 +29,33 @@ public SubsystemsExtension(Project project) {
configureRecompilerDefaults();
configureParchmentDefaults();
configureToolsDefaults();
configureDevLoginDefaults();
}

private void configureDevLoginDefaults() {
DevLogin devLogin = getDevLogin();
devLogin.getEnabled().convention(
getBooleanProperty("devLogin.enabled").orElse(true)
);
devLogin.getMainClass().convention(
getStringProperty("devLogin.mainClass").orElse(DEVLOGIN_MAIN_CLASS)
);
devLogin.getConfigurationSuffix().convention(
getStringProperty("devLogin.configurationSuffix").orElse("DevLoginLocalOnly")
);
devLogin.getConventionForRun().convention(
getBooleanProperty("devLogin.conventionForRun").orElse(false)
);
}

private void configureToolsDefaults() {
Tools tools = getTools();
tools.getJST().convention(
getStringProperty("tools.jst").orElse(JST_TOOL_ARTIFACT)
);
tools.getDevLogin().convention(
getStringProperty("tools.devLogin").orElse(DEVLOGIN_TOOL_ARTIFACT)
);
}

private void configureDecompilerDefaults() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import com.google.common.collect.Sets;
import net.minecraftforge.gdi.ConfigurableDSLElement;
import net.neoforged.gradle.common.util.constants.RunsConstants;
import net.neoforged.gradle.dsl.common.extensions.subsystems.Subsystems;
import net.neoforged.gradle.dsl.common.runs.run.Run;
import net.neoforged.gradle.dsl.common.runs.type.RunType;
import net.neoforged.gradle.util.StringCapitalizationUtils;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package net.neoforged.gradle.dsl.common.extensions.subsystems

import groovy.transform.CompileStatic
import net.minecraftforge.gdi.ConfigurableDSLElement
import net.minecraftforge.gdi.annotations.DSLProperty
import org.gradle.api.provider.Property
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.Optional

/**
* Allows configuration of the dev login system.
*/
@CompileStatic
interface DevLogin extends ConfigurableDSLElement<DevLogin> {

/**
* @return Whether or not dev login is enabled on launch.
*/
@Input
@Optional
@DSLProperty
Property<Boolean> getEnabled();

/**
* @return The main class to use when launching the game through dev login.
*/
@Input
@Optional
@DSLProperty
Property<String> getMainClass();

/**
* @return The suffix for the configuration name to use when adding the dev login configuration.
*/
@Input
@Optional
@DSLProperty
Property<String> getConfigurationSuffix()

/**
* @return The default usage flag state for runs. This is by default false (meaning the dev login configuration is not used by default), setting this to true will make all clients use dev login by default.
*/
@Input
@Optional
@DSLProperty
Property<Boolean> getConventionForRun()
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,4 +45,11 @@ interface Subsystems extends BaseDSLElement<Subsystems> {
@Nested
@DSLProperty
Tools getTools();

/**
* @return settings for the dev login subsystem
*/
@Nested
@DSLProperty
DevLogin getDevLogin();
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,12 @@ interface Tools extends ConfigurableDSLElement<Parchment> {
@DSLProperty
Property<String> getJST();

/**
* Artifact coordinates for the NeoGradle decompiler.
* Used by the runs subsystem to allow login to the dev environment.
*/
@Input
@Optional
@DSLProperty
Property<String> getDevLogin();
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package net.neoforged.gradle.dsl.common.runs.run


import groovy.transform.CompileStatic
import net.minecraftforge.gdi.BaseDSLElement
import net.minecraftforge.gdi.NamedDSLElement
Expand Down Expand Up @@ -231,7 +232,6 @@ interface Run extends BaseDSLElement<Run>, NamedDSLElement {
@Optional
abstract Property<Boolean> getConfigureFromDependencies();


/**
* Configures the run using the settings of the associated run type.
* <p/>
Expand Down
Loading

0 comments on commit 602139f

Please sign in to comment.