mirror of
https://github.com/architectury/architectury-loom.git
synced 2026-03-28 04:07:01 -05:00
Merge 1.8, part 8
This commit is contained in:
@@ -6,7 +6,7 @@ gson = "2.10.1"
|
||||
guava = "33.0.0-jre"
|
||||
|
||||
stitch = "0.6.2"
|
||||
tiny-remapper = "0.10.3"
|
||||
tiny-remapper = "0.10.4"
|
||||
access-widener = "2.1.0"
|
||||
mapping-io = "0.6.1"
|
||||
lorenz-tiny = "4.0.2"
|
||||
|
||||
@@ -8,7 +8,7 @@ vineflower = "1.10.1"
|
||||
mixin-compile-extensions = "0.6.0"
|
||||
dev-launch-injector = "0.2.1+build.8"
|
||||
terminal-console-appender = "1.3.0"
|
||||
jetbrains-annotations = "24.1.0"
|
||||
jetbrains-annotations = "25.0.0"
|
||||
native-support = "1.0.1"
|
||||
|
||||
# Forge Runtime depedencies
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
[versions]
|
||||
spock = "2.3-groovy-3.0"
|
||||
junit = "5.10.2"
|
||||
javalin = "6.1.6"
|
||||
mockito = "5.12.0"
|
||||
junit = "5.11.1"
|
||||
javalin = "6.3.0"
|
||||
mockito = "5.13.0"
|
||||
java-debug = "0.52.0"
|
||||
mixin = "0.12.5+mixin.0.8.5"
|
||||
mixin = "0.15.3+mixin.0.8.7"
|
||||
|
||||
gradle-nightly = "8.11-20240814172604+0000"
|
||||
fabric-loader = "0.15.11"
|
||||
gradle-nightly = "8.11-20240926001708+0000"
|
||||
fabric-loader = "0.16.5"
|
||||
fabric-installer = "1.0.1"
|
||||
|
||||
[libraries]
|
||||
|
||||
@@ -57,7 +57,6 @@ import net.fabricmc.loom.configuration.providers.minecraft.mapped.MojangMappedMi
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.mapped.NamedMinecraftProvider;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.mapped.SrgMinecraftProvider;
|
||||
import net.fabricmc.loom.extension.LoomFiles;
|
||||
import net.fabricmc.loom.extension.LoomProblemReporter;
|
||||
import net.fabricmc.loom.extension.MixinExtension;
|
||||
import net.fabricmc.loom.extension.RemapperExtensionHolder;
|
||||
import net.fabricmc.loom.util.ModPlatform;
|
||||
@@ -147,8 +146,6 @@ public interface LoomGradleExtension extends LoomGradleExtensionAPI {
|
||||
|
||||
Collection<LayeredMappingsFactory> getLayeredMappingFactories();
|
||||
|
||||
LoomProblemReporter getProblemReporter();
|
||||
|
||||
boolean isConfigurationCacheActive();
|
||||
|
||||
// ===================
|
||||
|
||||
@@ -37,9 +37,6 @@ import org.gradle.api.artifacts.ResolvedDependency;
|
||||
import org.gradle.api.artifacts.component.ComponentIdentifier;
|
||||
import org.gradle.api.artifacts.component.ModuleComponentIdentifier;
|
||||
|
||||
import net.fabricmc.loom.LoomGradleExtension;
|
||||
import net.fabricmc.loom.util.gradle.SelfResolvingDependencyUtils;
|
||||
|
||||
public class DependencyInfo {
|
||||
final Project project;
|
||||
final Dependency dependency;
|
||||
@@ -66,10 +63,7 @@ public class DependencyInfo {
|
||||
}
|
||||
|
||||
public static DependencyInfo create(Project project, Dependency dependency, Configuration sourceConfiguration) {
|
||||
if (SelfResolvingDependencyUtils.isExplicitSRD(dependency)) {
|
||||
LoomGradleExtension.get(project).getProblemReporter().reportSelfResolvingDependencyUsage();
|
||||
return FileDependencyInfo.createForDeprecatedSRD(project, dependency, sourceConfiguration);
|
||||
} else if (dependency instanceof FileCollectionDependency fileCollectionDependency) {
|
||||
if (dependency instanceof FileCollectionDependency fileCollectionDependency) {
|
||||
return new FileDependencyInfo(project, fileCollectionDependency, sourceConfiguration);
|
||||
} else {
|
||||
return new DependencyInfo(project, dependency, sourceConfiguration);
|
||||
|
||||
@@ -46,7 +46,6 @@ import org.gradle.api.artifacts.Dependency;
|
||||
import org.gradle.api.artifacts.FileCollectionDependency;
|
||||
|
||||
import net.fabricmc.loom.util.ZipUtils;
|
||||
import net.fabricmc.loom.util.gradle.SelfResolvingDependencyUtils;
|
||||
|
||||
public class FileDependencyInfo extends DependencyInfo {
|
||||
protected final Map<String, File> classifierToFile = new HashMap<>();
|
||||
@@ -152,15 +151,6 @@ public class FileDependencyInfo extends DependencyInfo {
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated // Remove in Gradle 9
|
||||
public static FileDependencyInfo createForDeprecatedSRD(Project project, Dependency dependency, Configuration configuration) {
|
||||
if (!SelfResolvingDependencyUtils.isExplicitSRD(dependency)) {
|
||||
throw new IllegalArgumentException("Dependency is a FileCollectionDependency");
|
||||
}
|
||||
|
||||
return new FileDependencyInfo(project, dependency, configuration, SelfResolvingDependencyUtils.resolve(dependency));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getResolvedVersion() {
|
||||
return version;
|
||||
|
||||
@@ -247,7 +247,7 @@ public abstract class InterfaceInjectionProcessor implements MinecraftJarProcess
|
||||
name = ifaceInfo.substring(0, ifaceInfo.indexOf("<"));
|
||||
generics = ifaceInfo.substring(ifaceInfo.indexOf("<"));
|
||||
|
||||
// First Generics Check, if there are generics, are them correctly written?
|
||||
// First Generics Check, if there are generics, are they correctly written?
|
||||
SignatureReader reader = new SignatureReader("Ljava/lang/Object" + generics + ";");
|
||||
CheckSignatureAdapter checker = new CheckSignatureAdapter(CheckSignatureAdapter.CLASS_SIGNATURE, null);
|
||||
reader.accept(checker);
|
||||
@@ -318,6 +318,7 @@ public abstract class InterfaceInjectionProcessor implements MinecraftJarProcess
|
||||
// Second Generics Check, if there are passed generics, are all of them present in the target class?
|
||||
GenericsChecker checker = new GenericsChecker(Constants.ASM_VERSION, injectedInterfaces);
|
||||
reader.accept(checker);
|
||||
checker.check();
|
||||
|
||||
var resultingSignature = new StringBuilder(signature);
|
||||
|
||||
@@ -350,7 +351,7 @@ public abstract class InterfaceInjectionProcessor implements MinecraftJarProcess
|
||||
@Override
|
||||
public void visitEnd() {
|
||||
// inject any necessary inner class entries
|
||||
// this may produce technically incorrect bytecode cuz we don't know the actual access flags for inner class entries
|
||||
// this may produce technically incorrect bytecode cuz we don't know the actual access flags for inner class entries,
|
||||
// but it's hopefully enough to quiet some IDE errors
|
||||
for (final InjectedInterface itf : injectedInterfaces) {
|
||||
if (this.knownInnerClasses.contains(itf.ifaceName())) {
|
||||
@@ -407,8 +408,8 @@ public abstract class InterfaceInjectionProcessor implements MinecraftJarProcess
|
||||
super.visitFormalTypeParameter(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitEnd() {
|
||||
// Ensures that injected interfaces only use collected type parameters from the target class
|
||||
public void check() {
|
||||
for (InjectedInterface injectedInterface : this.injectedInterfaces) {
|
||||
if (injectedInterface.generics() != null) {
|
||||
SignatureReader reader = new SignatureReader("Ljava/lang/Object" + injectedInterface.generics() + ";");
|
||||
@@ -421,8 +422,6 @@ public abstract class InterfaceInjectionProcessor implements MinecraftJarProcess
|
||||
reader.accept(confirm);
|
||||
}
|
||||
}
|
||||
|
||||
super.visitEnd();
|
||||
}
|
||||
|
||||
public static class GenericsConfirm extends SignatureVisitor {
|
||||
|
||||
@@ -166,7 +166,7 @@ public record SpecContextImpl(List<FabricModJson> modDependencies, List<FabricMo
|
||||
return configuration.getAllDependencies()
|
||||
.withType(ProjectDependency.class)
|
||||
.stream()
|
||||
.map(ProjectDependency::getDependencyProject)
|
||||
.map(GradleUtils::getDependencyProject)
|
||||
.filter(GradleUtils::isLoomProject);
|
||||
}
|
||||
|
||||
|
||||
@@ -34,13 +34,13 @@ import java.util.Map;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import com.google.common.base.Stopwatch;
|
||||
import org.jetbrains.annotations.VisibleForTesting;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import net.fabricmc.loom.api.mappings.layered.MappingsNamespace;
|
||||
import net.fabricmc.loom.configuration.providers.mappings.IntermediateMappingsService;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftProvider;
|
||||
import net.fabricmc.mappingio.adapter.MappingNsCompleter;
|
||||
import net.fabricmc.mappingio.adapter.MappingSourceNsSwitch;
|
||||
import net.fabricmc.mappingio.format.tiny.Tiny2FileReader;
|
||||
import net.fabricmc.mappingio.format.tiny.Tiny2FileWriter;
|
||||
@@ -63,7 +63,8 @@ public final class MappingsMerger {
|
||||
LOGGER.info(":merged mappings in " + stopwatch.stop());
|
||||
}
|
||||
|
||||
private static void mergeAndSaveMappings(Path from, Path out, IntermediateMappingsService intermediateMappingsService) throws IOException {
|
||||
@VisibleForTesting
|
||||
public static void mergeAndSaveMappings(Path from, Path out, IntermediateMappingsService intermediateMappingsService) throws IOException {
|
||||
MemoryMappingTree intermediaryTree = new MemoryMappingTree();
|
||||
intermediateMappingsService.getMemoryMappingTree().accept(new MappingSourceNsSwitch(intermediaryTree, MappingsNamespace.INTERMEDIARY.toString()));
|
||||
|
||||
@@ -72,7 +73,7 @@ public final class MappingsMerger {
|
||||
}
|
||||
|
||||
MemoryMappingTree officialTree = new MemoryMappingTree();
|
||||
MappingNsCompleter nsCompleter = new MappingNsCompleter(officialTree, Map.of(MappingsNamespace.OFFICIAL.toString(), MappingsNamespace.INTERMEDIARY.toString()));
|
||||
UnobfuscatedMappingNsCompleter nsCompleter = new UnobfuscatedMappingNsCompleter(officialTree, MappingsNamespace.NAMED.toString(), Map.of(MappingsNamespace.OFFICIAL.toString(), MappingsNamespace.INTERMEDIARY.toString()));
|
||||
MappingSourceNsSwitch nsSwitch = new MappingSourceNsSwitch(nsCompleter, MappingsNamespace.OFFICIAL.toString());
|
||||
intermediaryTree.accept(nsSwitch);
|
||||
|
||||
@@ -83,7 +84,8 @@ public final class MappingsMerger {
|
||||
}
|
||||
}
|
||||
|
||||
private static void legacyMergeAndSaveMappings(Path from, Path out, IntermediateMappingsService intermediateMappingsService) throws IOException {
|
||||
@VisibleForTesting
|
||||
public static void legacyMergeAndSaveMappings(Path from, Path out, IntermediateMappingsService intermediateMappingsService) throws IOException {
|
||||
MemoryMappingTree intermediaryTree = new MemoryMappingTree();
|
||||
intermediateMappingsService.getMemoryMappingTree().accept(intermediaryTree);
|
||||
|
||||
@@ -92,7 +94,7 @@ public final class MappingsMerger {
|
||||
}
|
||||
|
||||
MemoryMappingTree officialTree = new MemoryMappingTree();
|
||||
MappingNsCompleter nsCompleter = new MappingNsCompleter(officialTree, Map.of(MappingsNamespace.CLIENT_OFFICIAL.toString(), MappingsNamespace.INTERMEDIARY.toString(), MappingsNamespace.SERVER_OFFICIAL.toString(), MappingsNamespace.INTERMEDIARY.toString()));
|
||||
UnobfuscatedMappingNsCompleter nsCompleter = new UnobfuscatedMappingNsCompleter(officialTree, MappingsNamespace.NAMED.toString(), Map.of(MappingsNamespace.CLIENT_OFFICIAL.toString(), MappingsNamespace.INTERMEDIARY.toString(), MappingsNamespace.SERVER_OFFICIAL.toString(), MappingsNamespace.INTERMEDIARY.toString()));
|
||||
intermediaryTree.accept(nsCompleter);
|
||||
|
||||
// versions this old strip inner class attributes
|
||||
|
||||
@@ -0,0 +1,231 @@
|
||||
/*
|
||||
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
||||
*
|
||||
* Copyright (c) 2024 FabricMC
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package net.fabricmc.loom.configuration.providers.mappings.tiny;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import net.fabricmc.mappingio.MappedElementKind;
|
||||
import net.fabricmc.mappingio.MappingVisitor;
|
||||
import net.fabricmc.mappingio.adapter.ForwardingMappingVisitor;
|
||||
|
||||
/**
|
||||
* Adapted from {@link net.fabricmc.mappingio.adapter.MappingNsCompleter}.
|
||||
* This visitor completes any empty namespace with some alternative namespace
|
||||
* only if that alternative namespace is equal to some test namespace.
|
||||
* Mostly this will be used to complete official namespaces with intermediary
|
||||
* names only if those intermediary names are equal to the named names.
|
||||
*/
|
||||
public final class UnobfuscatedMappingNsCompleter extends ForwardingMappingVisitor {
|
||||
private final String testNs;
|
||||
private final Map<String, String> alternatives;
|
||||
private int testNsId;
|
||||
private int[] alternativesMapping;
|
||||
|
||||
private String srcName;
|
||||
private String[] dstNames;
|
||||
private boolean[] unobf;
|
||||
private boolean[] lastMethodUnobf;
|
||||
|
||||
private boolean relayHeaderOrMetadata;
|
||||
|
||||
public UnobfuscatedMappingNsCompleter(MappingVisitor next, String testNs, Map<String, String> alternatives) {
|
||||
super(next);
|
||||
|
||||
this.testNs = testNs;
|
||||
this.alternatives = alternatives;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean visitHeader() throws IOException {
|
||||
relayHeaderOrMetadata = next.visitHeader();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitNamespaces(String srcNamespace, List<String> dstNamespaces) throws IOException {
|
||||
int count = dstNamespaces.size();
|
||||
testNsId = -1;
|
||||
alternativesMapping = new int[count];
|
||||
dstNames = new String[count];
|
||||
unobf = new boolean[count + 1]; // contains src ns as well
|
||||
lastMethodUnobf = new boolean[count + 1]; // contains src ns as well
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
String dst = dstNamespaces.get(i);
|
||||
|
||||
if (testNs.equals(dst)) {
|
||||
testNsId = i;
|
||||
}
|
||||
|
||||
String src = alternatives.get(dst);
|
||||
int srcIdx;
|
||||
|
||||
if (src == null) {
|
||||
srcIdx = i;
|
||||
} else if (src.equals(srcNamespace)) {
|
||||
srcIdx = -1;
|
||||
} else {
|
||||
srcIdx = dstNamespaces.indexOf(src);
|
||||
if (srcIdx < 0) throw new RuntimeException("invalid alternative mapping ns "+src+": not in "+dstNamespaces+" or "+srcNamespace);
|
||||
}
|
||||
|
||||
alternativesMapping[i] = srcIdx;
|
||||
}
|
||||
|
||||
if (testNsId == -1 && !testNs.equals(srcNamespace)) throw new RuntimeException("test namespace " + testNs + " not present in src and dst namespaces!");
|
||||
|
||||
if (relayHeaderOrMetadata) next.visitNamespaces(srcNamespace, dstNamespaces);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitMetadata(String key, @Nullable String value) throws IOException {
|
||||
if (relayHeaderOrMetadata) next.visitMetadata(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean visitContent() throws IOException {
|
||||
relayHeaderOrMetadata = true; // for in-content metadata
|
||||
|
||||
return next.visitContent();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean visitClass(String srcName) throws IOException {
|
||||
this.srcName = srcName;
|
||||
|
||||
return next.visitClass(srcName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean visitField(String srcName, @Nullable String srcDesc) throws IOException {
|
||||
this.srcName = srcName;
|
||||
|
||||
return next.visitField(srcName, srcDesc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean visitMethod(String srcName, @Nullable String srcDesc) throws IOException {
|
||||
this.srcName = srcName;
|
||||
|
||||
return next.visitMethod(srcName, srcDesc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean visitMethodArg(int argPosition, int lvIndex, @Nullable String srcName) throws IOException {
|
||||
this.srcName = srcName;
|
||||
|
||||
return next.visitMethodArg(argPosition, lvIndex, srcName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean visitMethodVar(int lvtRowIndex, int lvIndex, int startOpIdx, int endOpIdx, @Nullable String srcName) throws IOException {
|
||||
this.srcName = srcName;
|
||||
|
||||
return next.visitMethodVar(lvtRowIndex, lvIndex, startOpIdx, endOpIdx, srcName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitDstName(MappedElementKind targetKind, int namespace, String name) {
|
||||
dstNames[namespace] = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean visitElementContent(MappedElementKind targetKind) throws IOException {
|
||||
for (int ns : alternativesMapping) {
|
||||
int idx = ns + 1; // offset by 1 bc src ns is -1
|
||||
|
||||
if (targetKind == MappedElementKind.METHOD_ARG || targetKind == MappedElementKind.METHOD_VAR) {
|
||||
unobf[idx] = lastMethodUnobf[idx];
|
||||
} else if (ns == testNsId) {
|
||||
unobf[idx] = true;
|
||||
|
||||
if (targetKind == MappedElementKind.METHOD) {
|
||||
lastMethodUnobf[idx] = true;
|
||||
}
|
||||
} else if (!unobf[idx]) { // only check each ns once
|
||||
String name = ns == -1 ? srcName : dstNames[ns];
|
||||
String testName = dstNames[testNsId];
|
||||
|
||||
if (testName != null && testName.equals(name)) {
|
||||
unobf[idx] = true;
|
||||
|
||||
if (targetKind == MappedElementKind.METHOD) {
|
||||
lastMethodUnobf[idx] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nsLoop: for (int i = 0; i < dstNames.length; i++) {
|
||||
String name = dstNames[i];
|
||||
|
||||
if (name == null) {
|
||||
int src = i;
|
||||
long visited = 1L << src;
|
||||
|
||||
do {
|
||||
int newSrc = alternativesMapping[src];
|
||||
|
||||
if (newSrc < 0) { // mapping to src name
|
||||
if (unobf[newSrc + 1]) {
|
||||
name = srcName;
|
||||
break; // srcName must never be null
|
||||
} else {
|
||||
continue nsLoop;
|
||||
}
|
||||
} else if (newSrc == src) { // no-op (identity) mapping, explicit in case src > 64
|
||||
continue nsLoop; // always null
|
||||
} else if ((visited & 1L << newSrc) != 0) { // cyclic mapping
|
||||
continue nsLoop; // always null
|
||||
} else {
|
||||
if (unobf[newSrc + 1]) {
|
||||
src = newSrc;
|
||||
name = dstNames[src];
|
||||
visited |= 1L << src;
|
||||
} else {
|
||||
continue nsLoop;
|
||||
}
|
||||
}
|
||||
} while (name == null);
|
||||
|
||||
assert name != null;
|
||||
}
|
||||
|
||||
next.visitDstName(targetKind, i, name);
|
||||
}
|
||||
|
||||
Arrays.fill(dstNames, null);
|
||||
Arrays.fill(unobf, false);
|
||||
Arrays.fill(lastMethodUnobf, false);
|
||||
|
||||
return next.visitElementContent(targetKind);
|
||||
}
|
||||
}
|
||||
@@ -34,27 +34,11 @@ import org.gradle.api.artifacts.FileCollectionDependency;
|
||||
|
||||
import net.fabricmc.loom.api.mappings.layered.MappingContext;
|
||||
import net.fabricmc.loom.api.mappings.layered.spec.FileSpec;
|
||||
import net.fabricmc.loom.configuration.providers.mappings.GradleMappingContext;
|
||||
import net.fabricmc.loom.util.gradle.SelfResolvingDependencyUtils;
|
||||
|
||||
public record DependencyFileSpec(Dependency dependency) implements FileSpec {
|
||||
@Override
|
||||
public Path get(MappingContext context) {
|
||||
if (SelfResolvingDependencyUtils.isExplicitSRD(dependency)) {
|
||||
if (context instanceof GradleMappingContext gradleMappingContext) {
|
||||
gradleMappingContext.getExtension().getProblemReporter().reportSelfResolvingDependencyUsage();
|
||||
}
|
||||
|
||||
Set<File> files = SelfResolvingDependencyUtils.resolve(dependency);
|
||||
|
||||
if (files.isEmpty()) {
|
||||
throw new RuntimeException("SelfResolvingDependency (%s) resolved no files".formatted(dependency.toString()));
|
||||
} else if (files.size() > 1) {
|
||||
throw new RuntimeException("SelfResolvingDependency (%s) resolved too many files (%d) only 1 is expected".formatted(dependency.toString(), files.size()));
|
||||
}
|
||||
|
||||
return files.iterator().next().toPath();
|
||||
} else if (dependency instanceof FileCollectionDependency fileCollectionDependency) {
|
||||
if (dependency instanceof FileCollectionDependency fileCollectionDependency) {
|
||||
Set<File> files = fileCollectionDependency.getFiles().getFiles();
|
||||
|
||||
if (files.isEmpty()) {
|
||||
|
||||
@@ -119,10 +119,23 @@ public class MinecraftLibraryProvider {
|
||||
}
|
||||
|
||||
private List<Library> processLibraries(List<Library> libraries) {
|
||||
final LibraryContext libraryContext = new LibraryContext(minecraftProvider.getVersionInfo(), JavaVersion.current());
|
||||
final LibraryContext libraryContext = new LibraryContext(minecraftProvider.getVersionInfo(), getTargetRuntimeJavaVersion());
|
||||
return processorManager.processLibraries(libraries, libraryContext);
|
||||
}
|
||||
|
||||
private JavaVersion getTargetRuntimeJavaVersion() {
|
||||
final Object property = project.findProperty(Constants.Properties.RUNTIME_JAVA_COMPATIBILITY_VERSION);
|
||||
|
||||
if (property != null) {
|
||||
// This is very much a last ditch effort to allow users to set the runtime java version
|
||||
// It's not recommended and will likely cause support confusion if it has been changed without good reason.
|
||||
project.getLogger().warn("Runtime java compatibility version has manually been set to: %s".formatted(property));
|
||||
return JavaVersion.toVersion(property);
|
||||
}
|
||||
|
||||
return JavaVersion.current();
|
||||
}
|
||||
|
||||
private void applyClientLibrary(Library library) {
|
||||
switch (library.target()) {
|
||||
case COMPILE -> addLibrary(Constants.Configurations.MINECRAFT_CLIENT_COMPILE_LIBRARIES, library);
|
||||
|
||||
@@ -209,6 +209,12 @@ public abstract sealed class MinecraftSourceSets permits MinecraftSourceSets.Sin
|
||||
extendsFrom(project, clientOnlySourceSet.getCompileClasspathConfigurationName(), mainSourceSet.getCompileClasspathConfigurationName());
|
||||
extendsFrom(project, clientOnlySourceSet.getRuntimeClasspathConfigurationName(), mainSourceSet.getRuntimeClasspathConfigurationName());
|
||||
|
||||
// Test source set depends on client
|
||||
final SourceSet testSourceSet = SourceSetHelper.getSourceSetByName(SourceSet.TEST_SOURCE_SET_NAME, project);
|
||||
extendsFrom(project, testSourceSet.getCompileClasspathConfigurationName(), clientOnlySourceSet.getCompileClasspathConfigurationName());
|
||||
extendsFrom(project, testSourceSet.getRuntimeClasspathConfigurationName(), clientOnlySourceSet.getRuntimeClasspathConfigurationName());
|
||||
project.getDependencies().add(testSourceSet.getImplementationConfigurationName(), clientOnlySourceSet.getOutput());
|
||||
|
||||
RemapConfigurations.configureClientConfigurations(project, clientOnlySourceSet);
|
||||
|
||||
// Include the client only output in the jars
|
||||
|
||||
@@ -84,7 +84,6 @@ public abstract class LoomGradleExtensionImpl extends LoomGradleExtensionApiImpl
|
||||
private InstallerData installerData;
|
||||
private boolean refreshDeps;
|
||||
private final ListProperty<LibraryProcessorManager.LibraryProcessorFactory> libraryProcessorFactories;
|
||||
private final LoomProblemReporter problemReporter;
|
||||
private final boolean configurationCacheActive;
|
||||
private final boolean isolatedProjectsActive;
|
||||
|
||||
@@ -127,15 +126,9 @@ public abstract class LoomGradleExtensionImpl extends LoomGradleExtensionApiImpl
|
||||
configurationCacheActive = getBuildFeatures().getConfigurationCache().getActive().get();
|
||||
isolatedProjectsActive = getBuildFeatures().getIsolatedProjects().getActive().get();
|
||||
|
||||
if (configurationCacheActive) {
|
||||
project.getLogger().warn("Loom support for the Gradle configuration cache is highly experimental and may not work as expected. Please report any issues you encounter.");
|
||||
}
|
||||
|
||||
if (refreshDeps) {
|
||||
project.getLogger().lifecycle("Refresh dependencies is in use, loom will be significantly slower.");
|
||||
}
|
||||
|
||||
problemReporter = project.getObjects().newInstance(LoomProblemReporter.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -329,11 +322,6 @@ public abstract class LoomGradleExtensionImpl extends LoomGradleExtensionApiImpl
|
||||
provider.getIsLegacyMinecraft().disallowChanges();
|
||||
}
|
||||
|
||||
@Override
|
||||
public LoomProblemReporter getProblemReporter() {
|
||||
return problemReporter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isConfigurationCacheActive() {
|
||||
return configurationCacheActive;
|
||||
|
||||
@@ -241,6 +241,8 @@ public abstract class GenerateSourcesTask extends AbstractLoomTask {
|
||||
getResetCache().convention(getExtension().refreshDeps());
|
||||
|
||||
getMappings().set(SourceMappingsService.create(getProject()));
|
||||
|
||||
mustRunAfter(getProject().getTasks().withType(AbstractRemapJarTask.class));
|
||||
}
|
||||
|
||||
@TaskAction
|
||||
|
||||
@@ -161,6 +161,11 @@ public class Constants {
|
||||
public static final String LIBRARY_PROCESSORS = "fabric.loom.libraryProcessors";
|
||||
@ApiStatus.Experimental
|
||||
public static final String SANDBOX = "fabric.loom.experimental.sandbox";
|
||||
/**
|
||||
* When set the version of java that will be assumed that the game will run on, this defaults to the current java version.
|
||||
* Only set this when you have a good reason to do so, the default should be fine for almost all cases.
|
||||
*/
|
||||
public static final String RUNTIME_JAVA_COMPATIBILITY_VERSION = "fabric.loom.runtimeJavaCompatibilityVersion";
|
||||
public static final String ALLOW_MISMATCHED_PLATFORM_VERSION = "loom.allowMismatchedPlatformVersion";
|
||||
public static final String IGNORE_DEPENDENCY_LOOM_VERSION_VALIDATION = "loom.ignoreDependencyLoomVersionValidation";
|
||||
}
|
||||
|
||||
@@ -133,22 +133,51 @@ public final class TinyRemapperHelper {
|
||||
|
||||
for (MappingTree.ClassMapping classDef : mappings.getClasses()) {
|
||||
String className = classDef.getName(fromId);
|
||||
String dstName = classDef.getName(toId);
|
||||
|
||||
if (dstName == null) {
|
||||
// Unsure if this is correct, should be better than crashing tho.
|
||||
dstName = className;
|
||||
if (className == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
acceptor.acceptClass(className, dstName);
|
||||
String dstClassName = classDef.getName(toId);
|
||||
|
||||
if (dstClassName == null) {
|
||||
// Unsure if this is correct, should be better than crashing tho.
|
||||
dstClassName = className;
|
||||
}
|
||||
|
||||
acceptor.acceptClass(className, dstClassName);
|
||||
|
||||
for (MappingTree.FieldMapping field : classDef.getFields()) {
|
||||
acceptor.acceptField(memberOf(className, field.getName(fromId), field.getDesc(fromId)), field.getName(toId));
|
||||
String fieldName = field.getName(fromId);
|
||||
|
||||
if (fieldName == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
String dstFieldName = field.getName(toId);
|
||||
|
||||
if (dstFieldName == null) {
|
||||
dstFieldName = fieldName;
|
||||
}
|
||||
|
||||
acceptor.acceptField(memberOf(className, fieldName, field.getDesc(fromId)), dstFieldName);
|
||||
}
|
||||
|
||||
for (MappingTree.MethodMapping method : classDef.getMethods()) {
|
||||
IMappingProvider.Member methodIdentifier = memberOf(className, method.getName(fromId), method.getDesc(fromId));
|
||||
acceptor.acceptMethod(methodIdentifier, method.getName(toId));
|
||||
String methodName = method.getName(fromId);
|
||||
|
||||
if (methodName == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
String dstMethodName = method.getName(toId);
|
||||
|
||||
if (dstMethodName == null) {
|
||||
dstMethodName = methodName;
|
||||
}
|
||||
|
||||
IMappingProvider.Member methodIdentifier = memberOf(className, methodName, method.getDesc(fromId));
|
||||
acceptor.acceptMethod(methodIdentifier, dstMethodName);
|
||||
|
||||
if (remapLocalVariables) {
|
||||
for (MappingTree.MethodArgMapping parameter : method.getArgs()) {
|
||||
|
||||
@@ -25,10 +25,13 @@
|
||||
package net.fabricmc.loom.util.gradle;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.gradle.api.Project;
|
||||
import org.gradle.api.artifacts.ProjectDependency;
|
||||
import org.gradle.api.file.RegularFileProperty;
|
||||
import org.gradle.api.internal.artifacts.dependencies.DefaultProjectDependency;
|
||||
import org.gradle.api.invocation.Gradle;
|
||||
import org.gradle.api.provider.Provider;
|
||||
|
||||
@@ -90,4 +93,18 @@ public final class GradleUtils {
|
||||
property.set(file);
|
||||
return property.getAsFile().get();
|
||||
}
|
||||
|
||||
// Get the project from the field with reflection to suppress the deprecation warning.
|
||||
// If you hate it find a solution yourself and make a PR, I'm getting a bit tired of chasing Gradle updates
|
||||
public static Project getDependencyProject(ProjectDependency projectDependency) {
|
||||
try {
|
||||
final Class<DefaultProjectDependency> clazz = DefaultProjectDependency.class;
|
||||
final Field dependencyProject = clazz.getDeclaredField("dependencyProject");
|
||||
dependencyProject.setAccessible(true);
|
||||
return (Project) dependencyProject.get(projectDependency);
|
||||
} catch (NoSuchFieldException | IllegalAccessException ignored) {
|
||||
// Just fallback and trigger the warning, this will break in Gradle 9
|
||||
return projectDependency.getDependencyProject();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,114 +0,0 @@
|
||||
/*
|
||||
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
||||
*
|
||||
* Copyright (c) 2024 FabricMC
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package net.fabricmc.loom.util.gradle;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import org.gradle.api.artifacts.Dependency;
|
||||
import org.gradle.api.artifacts.FileCollectionDependency;
|
||||
import org.gradle.api.artifacts.ProjectDependency;
|
||||
|
||||
// SelfResolvingDependency is deprecated for removal, use reflection to ensure backwards compat.
|
||||
@Deprecated
|
||||
public class SelfResolvingDependencyUtils {
|
||||
// Set this system prop to disable SRD support before Gradle does.
|
||||
public static final boolean DISABLE_SRD_SUPPORT = System.getProperty("fabric.loom.disable.srd") != null;
|
||||
|
||||
private static final String SELF_RESOLVING_DEPENDENCY_CLASS_NAME = "org.gradle.api.artifacts.SelfResolvingDependency";
|
||||
@Nullable
|
||||
private static final Class<?> SELF_RESOLVING_DEPENDENCY_CLASS = getSelfResolvingDependencyOrNull();
|
||||
@Nullable
|
||||
private static final Method RESOLVE_METHOD = getResolveMethod(SELF_RESOLVING_DEPENDENCY_CLASS);
|
||||
|
||||
/**
|
||||
* @return true when dependency is a SelfResolvingDependency but NOT a FileCollectionDependency.
|
||||
*/
|
||||
public static boolean isExplicitSRD(Dependency dependency) {
|
||||
// FileCollectionDependency is usually the replacement for SelfResolvingDependency
|
||||
if (dependency instanceof FileCollectionDependency) {
|
||||
return false;
|
||||
} else if (dependency instanceof ProjectDependency) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return isSRD(dependency);
|
||||
}
|
||||
|
||||
private static boolean isSRD(Dependency dependency) {
|
||||
if (SELF_RESOLVING_DEPENDENCY_CLASS == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return dependency.getClass().isAssignableFrom(SELF_RESOLVING_DEPENDENCY_CLASS);
|
||||
}
|
||||
|
||||
public static Set<File> resolve(Dependency dependency) {
|
||||
if (!isSRD(dependency)) {
|
||||
throw new IllegalStateException("dependency is not a SelfResolvingDependency");
|
||||
}
|
||||
|
||||
try {
|
||||
return (Set<File>) RESOLVE_METHOD.invoke(dependency);
|
||||
} catch (IllegalAccessException | InvocationTargetException e) {
|
||||
throw new RuntimeException("Failed to resolve SelfResolvingDependency", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static Class<?> getSelfResolvingDependencyOrNull() {
|
||||
if (DISABLE_SRD_SUPPORT) {
|
||||
// Lets pretend SRD doesnt exist.
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
return Class.forName(SELF_RESOLVING_DEPENDENCY_CLASS_NAME);
|
||||
} catch (ClassNotFoundException e) {
|
||||
// Gradle 9+
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static Method getResolveMethod(Class<?> clazz) {
|
||||
if (clazz == null) {
|
||||
// Gradle 9+
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
var method = clazz.getDeclaredMethod("resolve");
|
||||
method.setAccessible(true);
|
||||
return method;
|
||||
} catch (NoSuchMethodException e) {
|
||||
throw new IllegalStateException("Failed to get SelfResolvingDependency.resolve() method", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -43,6 +43,7 @@ class SplitProjectTest extends Specification implements GradleProjectTestTrait {
|
||||
|
||||
then:
|
||||
result.task(":build").outcome == SUCCESS
|
||||
result.task(":test").outcome == SUCCESS
|
||||
|
||||
where:
|
||||
version << STANDARD_TEST_VERSIONS
|
||||
|
||||
@@ -24,9 +24,11 @@
|
||||
|
||||
package net.fabricmc.loom.test.unit
|
||||
|
||||
import java.nio.file.Path
|
||||
import java.util.function.Function
|
||||
|
||||
import net.fabricmc.loom.configuration.providers.mappings.IntermediaryMappingsProvider
|
||||
import net.fabricmc.loom.configuration.providers.mappings.IntermediateMappingsService
|
||||
import net.fabricmc.loom.test.util.GradleTestUtil
|
||||
import net.fabricmc.loom.util.download.Download
|
||||
|
||||
@@ -49,4 +51,20 @@ class LoomMocks {
|
||||
when(mock.getRefreshDeps()).thenReturn(refreshDeps)
|
||||
return mock
|
||||
}
|
||||
|
||||
static IntermediateMappingsService.Options intermediateMappingsServiceOptionsMock(Path intermediaryTiny, String expectedSrcNs) {
|
||||
def intermediaryTinyProperty = GradleTestUtil.mockProperty(intermediaryTiny)
|
||||
def expectedSrcNsProperty = GradleTestUtil.mockProperty(expectedSrcNs)
|
||||
|
||||
def mock = spy(IntermediateMappingsService.Options.class)
|
||||
when(mock.getIntermediaryTiny()).thenReturn(intermediaryTinyProperty)
|
||||
when(mock.getExpectedSrcNs()).thenReturn(expectedSrcNsProperty)
|
||||
return mock
|
||||
}
|
||||
|
||||
static IntermediateMappingsService intermediateMappingsServiceMock(IntermediateMappingsService.Options options) {
|
||||
def mock = spy(IntermediateMappingsService.class)
|
||||
when(mock.getOptions()).thenReturn(options)
|
||||
return mock
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,291 @@
|
||||
/*
|
||||
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
||||
*
|
||||
* Copyright (c) 2024 FabricMC
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package net.fabricmc.loom.test.unit
|
||||
|
||||
import java.nio.file.Files
|
||||
import java.nio.file.Path
|
||||
|
||||
import spock.lang.TempDir
|
||||
|
||||
import net.fabricmc.loom.api.mappings.layered.MappingsNamespace
|
||||
import net.fabricmc.loom.configuration.providers.mappings.IntermediateMappingsService
|
||||
import net.fabricmc.loom.configuration.providers.mappings.tiny.MappingsMerger
|
||||
import net.fabricmc.mappingio.MappingReader
|
||||
import net.fabricmc.mappingio.adapter.MappingSourceNsSwitch
|
||||
import net.fabricmc.mappingio.tree.MemoryMappingTree
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*
|
||||
|
||||
class MappingsMergerTest {
|
||||
@TempDir
|
||||
Path tempDir
|
||||
|
||||
def "mappings merger"() {
|
||||
given:
|
||||
Path intermediaryTiny = tempDir.resolve("intermediary.tiny")
|
||||
Path mappingsTiny = tempDir.resolve("mappings.tiny")
|
||||
Path mergedMappingsTiny = tempDir.resolve("merged_mappings.tiny")
|
||||
|
||||
Files.writeString(intermediaryTiny, INTERMEDIARY_MAPPINGS)
|
||||
Files.writeString(mappingsTiny, NAMED_MAPPINGS)
|
||||
|
||||
IntermediateMappingsService.Options intermediateMappingsServiceOptions = LoomMocks.intermediateMappingsServiceOptionsMock(intermediaryTiny, OFFICIAL)
|
||||
IntermediateMappingsService intermediateMappingsService = LoomMocks.intermediateMappingsServiceMock(intermediateMappingsServiceOptions)
|
||||
|
||||
when:
|
||||
MappingsMerger.mergeAndSaveMappings(mappingsTiny, mergedMappingsTiny, intermediateMappingsService)
|
||||
|
||||
def mappings = new MemoryMappingTree()
|
||||
MappingReader.read(mergedMappingsTiny, mappings)
|
||||
|
||||
then:
|
||||
mappings.srcNamespace == OFFICIAL
|
||||
mappings.dstNamespaces == [INTERMEDIARY, NAMED]
|
||||
def namedNs = mappings.getNamespaceId(NAMED)
|
||||
mappings.classes.size() == 2
|
||||
mappings.classes[0].srcName == "a"
|
||||
mappings.classes[0].getDstName(namedNs) == "net/fabricmc/loom/test/unit/ObfuscatedClass"
|
||||
mappings.classes[0].comment == "class comment"
|
||||
mappings.classes[0].fields.size() == 1
|
||||
mappings.classes[0].fields[0].srcName == "a"
|
||||
mappings.classes[0].fields[0].getDstDesc(namedNs) == "obfuscatedField"
|
||||
mappings.classes[0].fields[0].comment == "field comment"
|
||||
mappings.classes[0].methods.size() == 1
|
||||
mappings.classes[0].methods[0].srcName == "a"
|
||||
mappings.classes[0].methods[0].getDstDesc(namedNs) == "obfuscatedMethod"
|
||||
mappings.classes[0].methods[0].comment == "method comment"
|
||||
mappings.classes[0].methods[0].args.size() == 1
|
||||
mappings.classes[0].methods[1].args[0].getDstName(namedNs) == "obfuscatedMethodParameter"
|
||||
mappings.classes[1].srcName == "net/fabricmc/loom/test/unit/UnobfuscatedClass"
|
||||
mappings.classes[1].getDstName(namedNs) == "net/fabricmc/loom/test/unit/UnobfuscatedClass"
|
||||
mappings.classes[1].comment == "class comment"
|
||||
mappings.classes[1].fields.size() == 1
|
||||
mappings.classes[1].fields[0].srcName == "unobfuscatedField"
|
||||
mappings.classes[1].fields[0].getDstDesc(namedNs) == "unobfuscatedField"
|
||||
mappings.classes[1].fields[0].comment == "field comment"
|
||||
mappings.classes[1].methods.size() == 1
|
||||
mappings.classes[1].methods[0].srcName == "unobfuscatedMethod"
|
||||
mappings.classes[1].methods[0].getDstDesc(namedNs) == "unobfuscatedMethod"
|
||||
mappings.classes[1].methods[0].comment == "method comment"
|
||||
mappings.classes[1].methods[0].args.size() == 1
|
||||
mappings.classes[1].methods[1].args[0].getDstName(namedNs) == "unobfuscatedMethodParameter"
|
||||
}
|
||||
|
||||
def "mappings merger legacy"() {
|
||||
given:
|
||||
Path intermediaryTiny = tempDir.resolve("intermediary.tiny")
|
||||
Path mappingsTiny = tempDir.resolve("mappings.tiny")
|
||||
Path mergedMappingsTiny = tempDir.resolve("merged_mappings.tiny")
|
||||
|
||||
Files.writeString(intermediaryTiny, LEGACY_INTERMEDIARY_MAPPINGS)
|
||||
Files.writeString(mappingsTiny, LEGACY_NAMED_MAPPINGS)
|
||||
|
||||
IntermediateMappingsService.Options intermediateMappingsServiceOptions = LoomMocks.intermediateMappingsServiceOptionsMock(intermediaryTiny, INTERMEDIARY)
|
||||
IntermediateMappingsService intermediateMappingsService = LoomMocks.intermediateMappingsServiceMock(intermediateMappingsServiceOptions)
|
||||
|
||||
when:
|
||||
MappingsMerger.legacyMergeAndSaveMappings(mappingsTiny, mergedMappingsTiny, intermediateMappingsService)
|
||||
|
||||
def mappings = new MemoryMappingTree()
|
||||
MappingReader.read(mergedMappingsTiny, mappings)
|
||||
|
||||
def clientMappings = new MemoryMappingTree()
|
||||
def serverMappings = new MemoryMappingTree()
|
||||
|
||||
mappings.accept(new MappingSourceNsSwitch(clientMappings, CLIENT_OFFICIAL, true))
|
||||
mappings.accept(new MappingSourceNsSwitch(serverMappings, SERVER_OFFICIAL, true))
|
||||
|
||||
then:
|
||||
clientMappings.srcNamespace == CLIENT_OFFICIAL
|
||||
clientMappings.dstNamespaces == [
|
||||
INTERMEDIARY,
|
||||
SERVER_OFFICIAL,
|
||||
NAMED
|
||||
]
|
||||
def clientNamedNs = clientMappings.getNamespaceId(NAMED)
|
||||
clientMappings.classes.size() == 3
|
||||
clientMappings.classes[0].srcName == "a"
|
||||
clientMappings.classes[0].getDstName(namedNs) == "net/fabricmc/loom/test/unit/CommonObfuscatedClass"
|
||||
clientMappings.classes[0].comment == "class comment"
|
||||
clientMappings.classes[0].fields.size() == 1
|
||||
clientMappings.classes[0].fields[0].srcName == "a"
|
||||
clientMappings.classes[0].fields[0].getDstDesc(namedNs) == "commonObfuscatedField"
|
||||
clientMappings.classes[0].fields[0].comment == "field comment"
|
||||
clientMappings.classes[0].methods.size() == 1
|
||||
clientMappings.classes[0].methods[0].srcName == "a"
|
||||
clientMappings.classes[0].methods[0].getDstDesc(namedNs) == "commonObfuscatedMethod"
|
||||
clientMappings.classes[0].methods[0].comment == "method comment"
|
||||
clientMappings.classes[0].methods[0].args.size() == 1
|
||||
clientMappings.classes[0].methods[1].args[0].getDstName(namedNs) == "commonObfuscatedMethodParameter"
|
||||
clientMappings.classes[1].srcName == "b"
|
||||
clientMappings.classes[1].getDstName(namedNs) == "net/fabricmc/loom/test/unit/ClientObfuscatedClass"
|
||||
clientMappings.classes[1].comment == "class comment"
|
||||
clientMappings.classes[1].fields.size() == 1
|
||||
clientMappings.classes[1].fields[0].srcName == "a"
|
||||
clientMappings.classes[1].fields[0].getDstDesc(namedNs) == "clientObfuscatedField"
|
||||
clientMappings.classes[1].fields[0].comment == "field comment"
|
||||
clientMappings.classes[1].methods.size() == 1
|
||||
clientMappings.classes[1].methods[0].srcName == "a"
|
||||
clientMappings.classes[1].methods[0].getDstDesc(namedNs) == "clientObfuscatedMethod"
|
||||
clientMappings.classes[1].methods[0].comment == "method comment"
|
||||
clientMappings.classes[1].methods[0].args.size() == 1
|
||||
clientMappings.classes[1].methods[1].args[0].getDstName(namedNs) == "clientObfuscatedMethodParameter"
|
||||
clientMappings.classes[2].srcName == "net/fabricmc/loom/test/unit/UnobfuscatedClass"
|
||||
clientMappings.classes[2].getDstName(namedNs) == "net/fabricmc/loom/test/unit/UnobfuscatedClass"
|
||||
clientMappings.classes[2].comment == "class comment"
|
||||
clientMappings.classes[2].fields.size() == 1
|
||||
clientMappings.classes[2].fields[0].srcName == "unobfuscatedField"
|
||||
clientMappings.classes[2].fields[0].getDstDesc(namedNs) == "unobfuscatedField"
|
||||
clientMappings.classes[2].fields[0].comment == "field comment"
|
||||
clientMappings.classes[2].methods.size() == 1
|
||||
clientMappings.classes[2].methods[0].srcName == "unobfuscatedMethod"
|
||||
clientMappings.classes[2].methods[0].getDstDesc(namedNs) == "unobfuscatedMethod"
|
||||
clientMappings.classes[2].methods[0].comment == "method comment"
|
||||
clientMappings.classes[2].methods[0].args.size() == 1
|
||||
clientMappings.classes[2].methods[1].args[0].getDstName(namedNs) == "unobfuscatedMethodParameter"
|
||||
|
||||
serverMappings.srcNamespace == SERVER_OFFICIAL
|
||||
serverMappings.dstNamespaces == [
|
||||
INTERMEDIARY,
|
||||
CLIENT_OFFICIAL,
|
||||
NAMED
|
||||
]
|
||||
def serverNamedNs = serverMappings.getNamespaceId(NAMED)
|
||||
serverMappings.classes.size() == 3
|
||||
serverMappings.classes[0].srcName == "a"
|
||||
serverMappings.classes[0].getDstName(namedNs) == "net/fabricmc/loom/test/unit/CommonObfuscatedClass"
|
||||
serverMappings.classes[0].comment == "class comment"
|
||||
serverMappings.classes[0].fields.size() == 1
|
||||
serverMappings.classes[0].fields[0].srcName == "a"
|
||||
serverMappings.classes[0].fields[0].getDstDesc(namedNs) == "commonObfuscatedField"
|
||||
serverMappings.classes[0].fields[0].comment == "field comment"
|
||||
serverMappings.classes[0].methods.size() == 1
|
||||
serverMappings.classes[0].methods[0].srcName == "a"
|
||||
serverMappings.classes[0].methods[0].getDstDesc(namedNs) == "commonObfuscatedMethod"
|
||||
serverMappings.classes[0].methods[0].comment == "method comment"
|
||||
serverMappings.classes[0].methods[0].args.size() == 1
|
||||
serverMappings.classes[0].methods[1].args[0].getDstName(namedNs) == "commonObfuscatedMethodParameter"
|
||||
serverMappings.classes[1].srcName == "b"
|
||||
serverMappings.classes[1].getDstName(namedNs) == "net/fabricmc/loom/test/unit/ClientObfuscatedClass"
|
||||
serverMappings.classes[1].comment == "class comment"
|
||||
serverMappings.classes[1].fields.size() == 1
|
||||
serverMappings.classes[1].fields[0].srcName == "a"
|
||||
serverMappings.classes[1].fields[0].getDstDesc(namedNs) == "clientObfuscatedField"
|
||||
serverMappings.classes[1].fields[0].comment == "field comment"
|
||||
serverMappings.classes[1].methods.size() == 1
|
||||
serverMappings.classes[1].methods[0].srcName == "a"
|
||||
serverMappings.classes[1].methods[0].getDstDesc(namedNs) == "clientObfuscatedMethod"
|
||||
serverMappings.classes[1].methods[0].comment == "method comment"
|
||||
serverMappings.classes[1].methods[0].args.size() == 1
|
||||
serverMappings.classes[1].methods[1].args[0].getDstName(namedNs) == "clientObfuscatedMethodParameter"
|
||||
serverMappings.classes[2].srcName == "net/fabricmc/loom/test/unit/UnobfuscatedClass"
|
||||
serverMappings.classes[2].getDstName(namedNs) == "net/fabricmc/loom/test/unit/UnobfuscatedClass"
|
||||
serverMappings.classes[2].comment == "class comment"
|
||||
serverMappings.classes[2].fields.size() == 1
|
||||
serverMappings.classes[2].fields[0].srcName == "unobfuscatedField"
|
||||
serverMappings.classes[2].fields[0].getDstDesc(namedNs) == "unobfuscatedField"
|
||||
serverMappings.classes[2].fields[0].comment == "field comment"
|
||||
serverMappings.classes[2].methods.size() == 1
|
||||
serverMappings.classes[2].methods[0].srcName == "unobfuscatedMethod"
|
||||
serverMappings.classes[2].methods[0].getDstDesc(namedNs) == "unobfuscatedMethod"
|
||||
serverMappings.classes[2].methods[0].comment == "method comment"
|
||||
serverMappings.classes[2].methods[0].args.size() == 1
|
||||
serverMappings.classes[2].methods[1].args[0].getDstName(namedNs) == "unobfuscatedMethodParameter"
|
||||
}
|
||||
|
||||
private static final String OFFICIAL = MappingsNamespace.OFFICIAL.toString()
|
||||
private static final String CLIENT_OFFICIAL = MappingsNamespace.CLIENT_OFFICIAL.toString()
|
||||
private static final String SERVER_OFFICIAL = MappingsNamespace.SERVER_OFFICIAL.toString()
|
||||
private static final String INTERMEDIARY = MappingsNamespace.INTERMEDIARY.toString()
|
||||
private static final String NAMED = MappingsNamespace.NAMED.toString()
|
||||
|
||||
private static final String INTERMEDIARY_MAPPINGS = """
|
||||
tiny\t2\t0\tofficial\tintermediary
|
||||
c\ta\tclass_1
|
||||
\tf\tZ\ta\tfield_1
|
||||
\tm\t(Z)V\ta\tmethod_1
|
||||
""".trim()
|
||||
private static final String NAMED_MAPPINGS = """
|
||||
tiny\t2\t0\tintermediary\tnamed
|
||||
c\tclass_1\tnet/fabricmc/loom/test/unit/ObfuscatedClass
|
||||
\tc\tclass comment
|
||||
\tf\tZ\tfield_1\tobfuscatedField
|
||||
\t\tc\tfield comment
|
||||
\tm\t(Z)V\tmethod_1\tobfuscatedMethod
|
||||
\t\tc\tmethod comment
|
||||
\t\tp\t0\t\t\tobfuscatedMethodParameter
|
||||
c\tnet/fabricmc/loom/test/unit/UnobfuscatedClass\tnet/fabricmc/loom/test/unit/UnobfuscatedClass
|
||||
\tc\tclass comment
|
||||
\tf\tZ\tunobfuscatedField\tunobfuscatedField
|
||||
\t\tc\tfield comment
|
||||
\tm\t(Z)V\tunobfuscatedMethod\tunobfuscatedMethod
|
||||
\t\tc\tmethod comment
|
||||
\t\tp\t0\t\t\tunobfuscatedMethodParameter
|
||||
""".trim()
|
||||
|
||||
private static final String LEGACY_INTERMEDIARY_MAPPINGS = """
|
||||
tiny\t2\t0\tintermediary\tclientOfficial\tserverOfficial
|
||||
c\tclass_1\ta\ta
|
||||
\tf\tZ\tfield_1\ta\ta
|
||||
\tm\t(Z)V\tmethod_1\ta\ta
|
||||
c\tclass_2\tc\t
|
||||
\tf\tZ\tfield_2\ta\t
|
||||
\tm\t(Z)V\tmethod_2\ta\t
|
||||
c\tclass_3\t\tc
|
||||
\tf\tZ\tfield_3\t\ta
|
||||
\tm\t(Z)V\tmethod_3\t\ta
|
||||
""".trim()
|
||||
private static final String LEGACY_NAMED_MAPPINGS = """
|
||||
tiny\t2\t0\tintermediary\tnamed
|
||||
c\tclass_1\tnet/fabricmc/loom/test/unit/CommonObfuscatedClass
|
||||
\tc\tclass comment
|
||||
\tf\tZ\tfield_1\tcommonObfuscatedField
|
||||
\t\tc\tfield comment
|
||||
\tm\t(Z)V\tmethod_1\tcommonObfuscatedMethod
|
||||
\t\tc\tmethod comment
|
||||
\t\tp\t0\t\t\tcommonObfuscatedMethodParameter
|
||||
c\tclass_2\tnet/fabricmc/loom/test/unit/ClientObfuscatedClass
|
||||
\tc\tclass comment
|
||||
\tf\tZ\tfield_2\tclientObfuscatedField
|
||||
\t\tc\tfield comment
|
||||
\tm\t(Z)V\tmethod_2\tclientObfuscatedMethod
|
||||
\t\tc\tmethod comment
|
||||
\t\tp\t0\t\t\tclientObfuscatedMethodParameter
|
||||
c\tclass_3\tnet/fabricmc/loom/test/unit/ServerObfuscatedClass
|
||||
\tc\tclass comment
|
||||
\tf\tZ\tfield_3\tserverObfuscatedField
|
||||
\t\tc\tfield comment
|
||||
\tm\t(Z)V\tmethod_3\tserverObfuscatedMethod
|
||||
\t\tc\tmethod comment
|
||||
\t\tp\t0\t\t\tserverObfuscatedMethodParameter
|
||||
c\tnet/fabricmc/loom/test/unit/UnobfuscatedClass\tnet/fabricmc/loom/test/unit/UnobfuscatedClass
|
||||
\tc\tclass comment
|
||||
\tf\tZ\tunobfuscatedField\tunobfuscatedField
|
||||
\t\tc\tfield comment
|
||||
\tm\t(Z)V\tunobfuscatedMethod\tunobfuscatedMethod
|
||||
\t\tc\tmethod comment
|
||||
\t\tp\t0\t\t\tunobfuscatedMethodParameter
|
||||
""".trim()
|
||||
}
|
||||
@@ -39,6 +39,8 @@ import net.fabricmc.loom.configuration.ifaceinject.InterfaceInjectionProcessor
|
||||
import net.fabricmc.loom.test.unit.processor.classes.AdvancedGenericInterface
|
||||
import net.fabricmc.loom.test.unit.processor.classes.AdvancedGenericTargetClass
|
||||
import net.fabricmc.loom.test.unit.processor.classes.DoubleGenericTargetClass
|
||||
import net.fabricmc.loom.test.unit.processor.classes.DoublePassingGenericInterface
|
||||
import net.fabricmc.loom.test.unit.processor.classes.DoublePassingGenericTargetClass
|
||||
import net.fabricmc.loom.test.unit.processor.classes.FirstGenericInterface
|
||||
import net.fabricmc.loom.test.unit.processor.classes.GenericInterface
|
||||
import net.fabricmc.loom.test.unit.processor.classes.GenericTargetClass
|
||||
@@ -137,6 +139,12 @@ class InterfaceInjectionProcessorTest extends Specification {
|
||||
loadedClass.interfaces.first().name == "net/fabricmc/loom/test/unit/proessor/classes/SelfGenericInterface"
|
||||
loadedClass.constructors.first().newInstance().selfGenericInjectedMethod() == null
|
||||
}
|
||||
|
||||
// Class using double generics and passing them to the interface
|
||||
"class_9" | "net/fabricmc/loom/test/unit/processor/classes/DoublePassingGenericInterface<TF;TS;>" | DoublePassingGenericTargetClass.class | { Class<?> loadedClass ->
|
||||
loadedClass.interfaces.first().name == "net/fabricmc/loom/test/unit/processor/classes/DoublePassingGenericTargetClass"
|
||||
loadedClass.constructors.first().newInstance().doublePassingGenericInjectedMethod().getClass() == DoublePassingGenericTargetClass.Pair.class
|
||||
}
|
||||
}
|
||||
|
||||
def "nothing to inject"() {
|
||||
@@ -230,7 +238,10 @@ class InterfaceInjectionProcessorTest extends Specification {
|
||||
FirstGenericInterface.class,
|
||||
SecondGenericInterface.class,
|
||||
SelfGenericTargetClass.class,
|
||||
SelfGenericInterface.class
|
||||
SelfGenericInterface.class,
|
||||
DoublePassingGenericTargetClass.class,
|
||||
DoublePassingGenericTargetClass.Pair.class,
|
||||
DoublePassingGenericInterface.class
|
||||
]
|
||||
|
||||
private static final String MAPPINGS = """
|
||||
@@ -243,5 +254,7 @@ c\tclass_5\tnet/fabricmc/loom/test/unit/processor/classes/AdvancedGenericTargetC
|
||||
c\tclass_5\$class_6\tnet/fabricmc/loom/test/unit/processor/classes/AdvancedGenericTargetClass\$Pair
|
||||
c\tclass_7\tnet/fabricmc/loom/test/unit/processor/classes/DoubleGenericTargetClass
|
||||
c\tclass_8\tnet/fabricmc/loom/test/unit/processor/classes/SelfGenericTargetClass
|
||||
c\tclass_9\tnet/fabricmc/loom/test/unit/processor/classes/DoublePassingGenericTargetClass
|
||||
c\tclass_9\$class_10\tnet/fabricmc/loom/test/unit/processor/classes/DoublePassingGenericTargetClass\$Pair
|
||||
""".trim()
|
||||
}
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
||||
*
|
||||
* Copyright (c) 2024 FabricMC
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package net.fabricmc.loom.test.util
|
||||
|
||||
// A helper script to extract the test project from the resources and add the gradle wrapper
|
||||
// Useful for testing an intergration test project in a real environment
|
||||
class ExtractTestProject {
|
||||
static void main(String[] args) {
|
||||
if (args.length != 1) {
|
||||
throw new IllegalArgumentException("Expected one argument: the project name")
|
||||
}
|
||||
|
||||
def projectName = args[0]
|
||||
def targetDirectory = new File("test/$projectName")
|
||||
def sourceDirectory = new File("src/test/resources/projects/$projectName")
|
||||
|
||||
if (targetDirectory.exists()) {
|
||||
targetDirectory.deleteDir()
|
||||
}
|
||||
|
||||
copyDir(sourceDirectory, targetDirectory)
|
||||
copyDir(new File("gradle"), new File(targetDirectory, "gradle"))
|
||||
copyFile(new File("gradlew"), new File(targetDirectory, "gradlew"))
|
||||
copyFile(new File("gradlew.bat"), new File(targetDirectory, "gradlew.bat"))
|
||||
|
||||
new File(targetDirectory, "settings.gradle").text = """
|
||||
pluginManagement {
|
||||
repositories {
|
||||
maven {
|
||||
name = 'Fabric'
|
||||
url = 'https://maven.fabricmc.net/'
|
||||
}
|
||||
mavenCentral()
|
||||
gradlePluginPortal()
|
||||
mavenLocal()
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
def buildGradle = new File(targetDirectory, "build.gradle")
|
||||
buildGradle.text = buildGradle.text.replace("id 'fabric-loom'", "id 'fabric-loom' version '1.8.local'")
|
||||
}
|
||||
|
||||
private static void copyDir(File source, File target) {
|
||||
source.eachFileRecurse { file ->
|
||||
if (file.isDirectory()) {
|
||||
return
|
||||
}
|
||||
|
||||
def relativePath = source.toPath().relativize(file.toPath())
|
||||
def targetFile = new File(target, relativePath.toString())
|
||||
copyFile(file, targetFile)
|
||||
}
|
||||
}
|
||||
|
||||
private static void copyFile(File source, File target) {
|
||||
target.parentFile.mkdirs()
|
||||
target.bytes = source.bytes
|
||||
println("Copied $source to $target")
|
||||
}
|
||||
}
|
||||
@@ -22,30 +22,10 @@
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package net.fabricmc.loom.extension;
|
||||
package net.fabricmc.loom.test.unit.processor.classes;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import org.gradle.api.problems.ProblemReporter;
|
||||
import org.gradle.api.problems.Problems;
|
||||
import org.gradle.api.problems.Severity;
|
||||
|
||||
public abstract class LoomProblemReporter {
|
||||
private final ProblemReporter problemReporter;
|
||||
|
||||
@Inject
|
||||
public LoomProblemReporter(Problems problems) {
|
||||
this.problemReporter = problems.forNamespace("net.fabricmc.loom");
|
||||
}
|
||||
|
||||
public void reportSelfResolvingDependencyUsage() {
|
||||
problemReporter.reporting(spec -> spec
|
||||
.id("loom-deprecated-selfresolvingdependency", "SelfResolvingDependency is deprecated")
|
||||
.details("SelfResolvingDependency has been deprecated for removal in Gradle 9")
|
||||
.solution("Please replace usages of SelfResolvingDependency")
|
||||
.documentedAt("https://github.com/gradle/gradle/pull/27420")
|
||||
.severity(Severity.WARNING)
|
||||
.stackLocation()
|
||||
);
|
||||
public interface DoublePassingGenericInterface<F, S> {
|
||||
default DoublePassingGenericTargetClass.Pair<F, S> doublePassingGenericInjectedMethod() {
|
||||
return new DoublePassingGenericTargetClass.Pair<>(null, null);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
||||
*
|
||||
* Copyright (c) 2024 FabricMC
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package net.fabricmc.loom.test.unit.processor.classes;
|
||||
|
||||
public class DoublePassingGenericTargetClass<F, S> {
|
||||
public static class Pair<F, S> {
|
||||
Pair(F ignoredF, S ignoredS) {
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
plugins {
|
||||
id 'dev.architectury.loom' version '0.12.local'
|
||||
id 'dev.architectury.loom'
|
||||
id 'maven-publish'
|
||||
}
|
||||
|
||||
@@ -24,13 +24,18 @@ loom {
|
||||
dependencies {
|
||||
minecraft "com.mojang:minecraft:1.18.2"
|
||||
mappings "net.fabricmc:yarn:1.18.2+build.1:v2"
|
||||
modImplementation "net.fabricmc:fabric-loader:0.13.3"
|
||||
modImplementation "net.fabricmc:fabric-loader:0.16.5"
|
||||
testImplementation "net.fabricmc:fabric-loader-junit:0.16.5"
|
||||
|
||||
modImplementation "net.fabricmc.fabric-api:fabric-api:0.47.8+1.18.2"
|
||||
|
||||
shade "com.googlecode.json-simple:json-simple:1.1.1"
|
||||
}
|
||||
|
||||
test {
|
||||
useJUnitPlatform()
|
||||
}
|
||||
|
||||
tasks.withType(JavaCompile).configureEach {
|
||||
it.options.release = 17
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"required": true,
|
||||
"minVersion": "0.8",
|
||||
"package": "net.fabricmc.example.mixin",
|
||||
"package": "net.fabricmc.example.client.mixin",
|
||||
"compatibilityLevel": "JAVA_17",
|
||||
"mixins": [
|
||||
],
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
package net.fabricmc.example.test;
|
||||
|
||||
import net.fabricmc.example.client.ExampleModClient;
|
||||
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class ExampleModTest {
|
||||
@Test
|
||||
void testClientClass() {
|
||||
// Check we can compile against our own client code
|
||||
ExampleModClient exampleModClient = new ExampleModClient();
|
||||
|
||||
// And minecrafts client code
|
||||
MinecraftClient client = null;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user