Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix lazily provided layered mappings causing crash #1229

Open
wants to merge 2 commits into
base: dev/1.9
Choose a base branch
from

Conversation

isXander
Copy link

@isXander isXander commented Dec 10, 2024

Problem

mappings project.provider {
	loom.layered() {
		officialMojangMappings()
	}
}

The above is the configuration that caused the following crash.

> Failed to setup Minecraft, java.lang.IllegalStateException: Layered mappings have already been evaluated

Why is this behaviour wanted?

This allows people to use providers to define the mappings used by a project, for example, a gradle plugin that wraps Loom might define parchment via a extension property.

mappings myExtension.parchmentArtifact.orElse("").map { parchmentArtifact ->
	loom.layered() {
		officialMojangMappings()

		if (!parchmentArtifact.isEmpty()) {
			parchment(parchmentArtifact)
		}
	}
}

excuse the possible invalid groovy syntax, I am used to Kotlin DSL

Code analysis

During setupMinecraft in CompileConfiguration:

// 1
LayeredMappingsFactory.afterEvaluate(configContext);

// 2
final DependencyInfo mappingsDep = DependencyInfo.create(getProject(), Configurations.MAPPINGS);

// 3
final MappingConfiguration mappingConfiguration = MappingConfiguration.create(getProject(), configContext.serviceFactory(), mappingsDep, minecraftProvider);
  1. LayeredMappings are finalised - afterEvaluate method prevents any further configuration being made to the layered spec via loom.layered() {}.
  2. The dependency for mappings is fetched, this is where the provider is called upon and loom.layered() in the buildscript is now evaluated.
  3. Loom then applies the mapping that was fetched in step 2

Can you see the problem?

How did this work before?

Previously, Loom relied on the fact that the buildscript itself is evaluated before setupMinecraft. Which meant that if a loom.layered() {} was called, it would happen before it was finalised.

Using a provider exposed the problem: the layered spec is finalised before actually retrieving the dependency for mappings. The layered spec would finalise and THEN the provider would trigger, trying to call loom.layered() {} .

The fix

The fix is simple, finalise the layered mappings factory AFTER retrieving the dependency. Just swap lines 1 and 2.

// 2
final DependencyInfo mappingsDep = DependencyInfo.create(getProject(), Configurations.MAPPINGS);

// 1
LayeredMappingsFactory.afterEvaluate(configContext);

// 3
final MappingConfiguration mappingConfiguration = MappingConfiguration.create(getProject(), configContext.serviceFactory(), mappingsDep, minecraftProvider);

An integration test has been added to test for this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant