mirror of
https://github.com/architectury/architectury-loom.git
synced 2026-03-28 04:07:01 -05:00
Merge remote-tracking branch 'FabricMC/exp/1.5' into exp/1.5
# Conflicts: # build.gradle # gradle/libs.versions.toml # src/main/java/net/fabricmc/loom/configuration/ide/RunConfigSettings.java # src/main/java/net/fabricmc/loom/configuration/mods/ModProcessor.java # src/main/java/net/fabricmc/loom/configuration/providers/mappings/MappingConfiguration.java # src/test/groovy/net/fabricmc/loom/test/integration/FabricAPITest.groovy
This commit is contained in:
@@ -50,7 +50,7 @@ tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).all {
|
||||
}
|
||||
|
||||
group = "dev.architectury"
|
||||
def baseVersion = '1.4'
|
||||
def baseVersion = '1.5'
|
||||
|
||||
def ENV = System.getenv()
|
||||
def runNumber = ENV.GITHUB_RUN_NUMBER ?: "9999"
|
||||
|
||||
@@ -9,7 +9,7 @@ guava = "32.1.2-jre"
|
||||
stitch = "0.6.2"
|
||||
tiny-remapper = "1.10.23"
|
||||
access-widener = "2.1.0"
|
||||
mapping-io = "0.4.2"
|
||||
mapping-io = "0.5.0-beta.3"
|
||||
lorenz-tiny = "4.0.2"
|
||||
mercury = "0.1.2.15"
|
||||
kotlinx-metadata = "0.7.0"
|
||||
|
||||
@@ -6,7 +6,7 @@ mockito = "5.4.0"
|
||||
java-debug = "0.48.0"
|
||||
mixin = "0.11.4+mixin.0.8.5"
|
||||
|
||||
gradle-nightly = "8.5-20230908221250+0000"
|
||||
gradle-nightly = "8.6-20231107135843+0000"
|
||||
fabric-loader = "0.14.22"
|
||||
fabric-installer = "0.11.1"
|
||||
|
||||
|
||||
@@ -159,6 +159,8 @@ public abstract class FabricApiExtension {
|
||||
// Create a classpath group for this mod. Assume that the main sourceset is already in a group.
|
||||
mod.sourceSet(DATAGEN_SOURCESET_NAME);
|
||||
});
|
||||
|
||||
extension.createRemapConfigurations(sourceSets.getByName(DATAGEN_SOURCESET_NAME));
|
||||
}
|
||||
|
||||
if (settings.getCreateRunConfiguration().get()) {
|
||||
|
||||
@@ -345,6 +345,11 @@ public class RunConfigSettings implements Named {
|
||||
environment("client");
|
||||
defaultMainClass(Constants.Knot.KNOT_CLIENT);
|
||||
|
||||
if (Platform.CURRENT.isRaspberryPi()) {
|
||||
getProject().getLogger().info("Raspberry Pi detected, setting MESA_GL_VERSION_OVERRIDE=4.3");
|
||||
environmentVariable("MESA_GL_VERSION_OVERRIDE", "4.3");
|
||||
}
|
||||
|
||||
if (getExtension().isForgeLike()) {
|
||||
forgeTemplate("client");
|
||||
}
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
||||
*
|
||||
* Copyright (c) 2023 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.mods;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParseException;
|
||||
|
||||
import net.fabricmc.loom.LoomGradlePlugin;
|
||||
import net.fabricmc.loom.util.FileSystemUtil;
|
||||
import net.fabricmc.loom.util.fmj.FabricModJson;
|
||||
import net.fabricmc.loom.util.fmj.FabricModJsonFactory;
|
||||
|
||||
public final class MixinDetector {
|
||||
public static boolean hasMixinsWithoutRefmap(Path modJar) throws IOException {
|
||||
try (FileSystemUtil.Delegate fs = FileSystemUtil.getJarFileSystem(modJar)) {
|
||||
final List<String> mixinConfigs = getMixinConfigs(modJar);
|
||||
|
||||
if (!mixinConfigs.isEmpty()) {
|
||||
for (String mixinConfig : mixinConfigs) {
|
||||
final Path configPath = fs.getPath(mixinConfig);
|
||||
if (Files.notExists(configPath)) continue;
|
||||
|
||||
try (BufferedReader reader = Files.newBufferedReader(configPath)) {
|
||||
final JsonObject json = LoomGradlePlugin.GSON.fromJson(reader, JsonObject.class);
|
||||
|
||||
if (!json.has("refmap")) {
|
||||
// We found a mixin config with no refmap, exit the loop.
|
||||
return true;
|
||||
}
|
||||
} catch (JsonParseException e) {
|
||||
throw new RuntimeException("Could not parse mixin config %s from jar %s".formatted(mixinConfig, modJar.toAbsolutePath()), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static List<String> getMixinConfigs(Path modJar) {
|
||||
// Nullable because we don't care here if we can't read it.
|
||||
// We can just assume there are no mixins.
|
||||
final FabricModJson fabricModJson = FabricModJsonFactory.createFromZipNullable(modJar);
|
||||
return fabricModJson != null ? fabricModJson.getMixinConfigurations() : List.of();
|
||||
}
|
||||
}
|
||||
@@ -32,9 +32,11 @@ import java.io.UncheckedIOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.jar.Manifest;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
@@ -187,9 +189,9 @@ public class ModProcessor {
|
||||
builder.extension(kotlinRemapperClassloader.getTinyRemapperExtension());
|
||||
}
|
||||
|
||||
if (extension.isNeoForge()) {
|
||||
builder.extension(new MixinExtension());
|
||||
}
|
||||
final Set<InputTag> hasMixinsWithoutRefmaps = new HashSet<>();
|
||||
// Configure the mixin extension to remap mixins from mod jars detected not to contain refmaps.
|
||||
builder.extension(new MixinExtension(tag -> extension.isNeoForge() || hasMixinsWithoutRefmaps.contains(tag)));
|
||||
|
||||
final TinyRemapper remapper = builder.build();
|
||||
|
||||
@@ -218,6 +220,12 @@ public class ModProcessor {
|
||||
|
||||
project.getLogger().debug("Adding " + info.getInputFile() + " as a remap input");
|
||||
|
||||
// Note: this is done at a jar level, not at the level of an individual mixin config.
|
||||
// If a mod has multiple mixin configs, it's assumed that either all or none of them have refmaps.
|
||||
if (MixinDetector.hasMixinsWithoutRefmap(info.getInputFile())) {
|
||||
hasMixinsWithoutRefmaps.add(tag);
|
||||
}
|
||||
|
||||
remapper.readInputsAsync(tag, info.getInputFile());
|
||||
tagMap.put(info, tag);
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@ import net.fabricmc.loom.configuration.providers.minecraft.MinecraftProvider;
|
||||
import net.fabricmc.loom.util.service.SharedService;
|
||||
import net.fabricmc.loom.util.service.SharedServiceManager;
|
||||
import net.fabricmc.mappingio.adapter.MappingNsCompleter;
|
||||
import net.fabricmc.mappingio.format.Tiny2Reader;
|
||||
import net.fabricmc.mappingio.format.tiny.Tiny2FileReader;
|
||||
import net.fabricmc.mappingio.tree.MemoryMappingTree;
|
||||
|
||||
public final class IntermediateMappingsService implements SharedService {
|
||||
@@ -90,7 +90,7 @@ public final class IntermediateMappingsService implements SharedService {
|
||||
MappingNsCompleter nsCompleter = new MappingNsCompleter(tree, Collections.singletonMap(MappingsNamespace.NAMED.toString(), MappingsNamespace.INTERMEDIARY.toString()), true);
|
||||
|
||||
try (BufferedReader reader = Files.newBufferedReader(getIntermediaryTiny(), StandardCharsets.UTF_8)) {
|
||||
Tiny2Reader.read(reader, nsCompleter);
|
||||
Tiny2FileReader.read(reader, nsCompleter);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException("Failed to read intermediary mappings", e);
|
||||
|
||||
@@ -53,7 +53,7 @@ import net.fabricmc.loom.configuration.providers.mappings.utils.AddConstructorMa
|
||||
import net.fabricmc.loom.util.ZipUtils;
|
||||
import net.fabricmc.mappingio.adapter.MappingDstNsReorder;
|
||||
import net.fabricmc.mappingio.adapter.MappingSourceNsSwitch;
|
||||
import net.fabricmc.mappingio.format.Tiny2Writer;
|
||||
import net.fabricmc.mappingio.format.tiny.Tiny2FileWriter;
|
||||
import net.fabricmc.mappingio.tree.MemoryMappingTree;
|
||||
|
||||
public class LayeredMappingsDependency implements SelfResolvingDependency, FileCollectionDependency {
|
||||
@@ -99,7 +99,7 @@ public class LayeredMappingsDependency implements SelfResolvingDependency, FileC
|
||||
MemoryMappingTree mappings = processor.getMappings(layers);
|
||||
|
||||
try (Writer writer = new StringWriter()) {
|
||||
Tiny2Writer tiny2Writer = new Tiny2Writer(writer, false);
|
||||
var tiny2Writer = new Tiny2FileWriter(writer, false);
|
||||
|
||||
MappingDstNsReorder nsReorder = new MappingDstNsReorder(tiny2Writer, Collections.singletonList(MappingsNamespace.NAMED.toString()));
|
||||
MappingSourceNsSwitch nsSwitch = new MappingSourceNsSwitch(nsReorder, MappingsNamespace.INTERMEDIARY.toString(), true);
|
||||
|
||||
@@ -384,7 +384,7 @@ public class MappingConfiguration {
|
||||
|
||||
private static boolean areMappingsV2(Path path) throws IOException {
|
||||
try (BufferedReader reader = Files.newBufferedReader(path)) {
|
||||
return MappingReader.detectFormat(reader) == MappingFormat.TINY_2;
|
||||
return MappingReader.detectFormat(reader) == MappingFormat.TINY_2_FILE;
|
||||
} catch (NoSuchFileException e) {
|
||||
// TODO: just check the mappings version when Parser supports V1 in readMetadata()
|
||||
return false;
|
||||
|
||||
@@ -78,7 +78,7 @@ public record FileMappingsLayer(
|
||||
);
|
||||
MappingNsRenamer renamer = new MappingNsRenamer(nsSwitch, fallbackNamespaceReplacements);
|
||||
|
||||
MappingReader.read(path, enigma ? MappingFormat.ENIGMA : null, renamer);
|
||||
MappingReader.read(path, enigma ? MappingFormat.ENIGMA_DIR : null, renamer);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -40,7 +40,7 @@ import net.fabricmc.loom.configuration.providers.mappings.intermediary.Intermedi
|
||||
import net.fabricmc.loom.configuration.providers.mappings.utils.DstNameFilterMappingVisitor;
|
||||
import net.fabricmc.mappingio.MappingVisitor;
|
||||
import net.fabricmc.mappingio.adapter.MappingSourceNsSwitch;
|
||||
import net.fabricmc.mappingio.format.ProGuardReader;
|
||||
import net.fabricmc.mappingio.format.proguard.ProGuardFileReader;
|
||||
|
||||
public record MojangMappingLayer(String minecraftVersion,
|
||||
Path clientMappings,
|
||||
@@ -63,8 +63,8 @@ public record MojangMappingLayer(String minecraftVersion,
|
||||
|
||||
try (BufferedReader clientBufferedReader = Files.newBufferedReader(clientMappings, StandardCharsets.UTF_8);
|
||||
BufferedReader serverBufferedReader = Files.newBufferedReader(serverMappings, StandardCharsets.UTF_8)) {
|
||||
ProGuardReader.read(clientBufferedReader, MappingsNamespace.NAMED.toString(), MappingsNamespace.OFFICIAL.toString(), nsSwitch);
|
||||
ProGuardReader.read(serverBufferedReader, MappingsNamespace.NAMED.toString(), MappingsNamespace.OFFICIAL.toString(), nsSwitch);
|
||||
ProGuardFileReader.read(clientBufferedReader, MappingsNamespace.NAMED.toString(), MappingsNamespace.OFFICIAL.toString(), nsSwitch);
|
||||
ProGuardFileReader.read(serverBufferedReader, MappingsNamespace.NAMED.toString(), MappingsNamespace.OFFICIAL.toString(), nsSwitch);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -41,8 +41,8 @@ import net.fabricmc.loom.api.mappings.layered.MappingsNamespace;
|
||||
import net.fabricmc.loom.configuration.providers.mappings.IntermediateMappingsService;
|
||||
import net.fabricmc.mappingio.adapter.MappingNsCompleter;
|
||||
import net.fabricmc.mappingio.adapter.MappingSourceNsSwitch;
|
||||
import net.fabricmc.mappingio.format.Tiny2Reader;
|
||||
import net.fabricmc.mappingio.format.Tiny2Writer;
|
||||
import net.fabricmc.mappingio.format.tiny.Tiny2FileReader;
|
||||
import net.fabricmc.mappingio.format.tiny.Tiny2FileWriter;
|
||||
import net.fabricmc.mappingio.tree.MappingTree;
|
||||
import net.fabricmc.mappingio.tree.MemoryMappingTree;
|
||||
|
||||
@@ -57,7 +57,7 @@ public final class MappingsMerger {
|
||||
intermediateMappingsService.getMemoryMappingTree().accept(new MappingSourceNsSwitch(intermediaryTree, MappingsNamespace.INTERMEDIARY.toString()));
|
||||
|
||||
try (BufferedReader reader = Files.newBufferedReader(from, StandardCharsets.UTF_8)) {
|
||||
Tiny2Reader.read(reader, intermediaryTree);
|
||||
Tiny2FileReader.read(reader, intermediaryTree);
|
||||
}
|
||||
|
||||
MemoryMappingTree officialTree = new MemoryMappingTree();
|
||||
@@ -67,7 +67,7 @@ public final class MappingsMerger {
|
||||
|
||||
inheritMappedNamesOfEnclosingClasses(officialTree);
|
||||
|
||||
try (Tiny2Writer writer = new Tiny2Writer(Files.newBufferedWriter(out, StandardCharsets.UTF_8), false)) {
|
||||
try (var writer = new Tiny2FileWriter(Files.newBufferedWriter(out, StandardCharsets.UTF_8), false)) {
|
||||
officialTree.accept(writer);
|
||||
}
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ public record TinyJarInfo(boolean v2, Optional<String> minecraftVersionId) {
|
||||
private static boolean doesJarContainV2Mappings(Path path) throws IOException {
|
||||
try (FileSystemUtil.Delegate delegate = FileSystemUtil.getJarFileSystem(path)) {
|
||||
try (BufferedReader reader = Files.newBufferedReader(delegate.fs().getPath("mappings", "mappings.tiny"))) {
|
||||
return MappingReader.detectFormat(reader) == MappingFormat.TINY_2;
|
||||
return MappingReader.detectFormat(reader) == MappingFormat.TINY_2_FILE;
|
||||
}
|
||||
} catch (NoSuchFileException e) {
|
||||
return false;
|
||||
|
||||
@@ -28,7 +28,7 @@ import java.io.File;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Objects;
|
||||
|
||||
public abstract sealed class MinecraftJar permits MinecraftJar.Merged, MinecraftJar.Common, MinecraftJar.ServerOnly, MinecraftJar.ClientOnly {
|
||||
public abstract sealed class MinecraftJar permits MinecraftJar.Client, MinecraftJar.ClientOnly, MinecraftJar.Common, MinecraftJar.Merged, MinecraftJar.Server {
|
||||
private final Path path;
|
||||
private final boolean merged, client, server;
|
||||
private final String name;
|
||||
@@ -68,8 +68,10 @@ public abstract sealed class MinecraftJar permits MinecraftJar.Merged, Minecraft
|
||||
public abstract MinecraftJar forPath(Path path);
|
||||
|
||||
public static final class Merged extends MinecraftJar {
|
||||
public static final String NAME = "merged";
|
||||
|
||||
public Merged(Path path) {
|
||||
super(path, true, true, true, "merged");
|
||||
super(path, true, true, true, NAME);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -79,8 +81,10 @@ public abstract sealed class MinecraftJar permits MinecraftJar.Merged, Minecraft
|
||||
}
|
||||
|
||||
public static final class Common extends MinecraftJar {
|
||||
public static final String NAME = "common";
|
||||
|
||||
public Common(Path path) {
|
||||
super(path, false, false, true, "common");
|
||||
super(path, false, false, true, NAME);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -89,20 +93,39 @@ public abstract sealed class MinecraftJar permits MinecraftJar.Merged, Minecraft
|
||||
}
|
||||
}
|
||||
|
||||
public static final class ServerOnly extends MinecraftJar {
|
||||
public ServerOnly(Path path) {
|
||||
super(path, false, false, true, "serverOnly");
|
||||
public static final class Server extends MinecraftJar {
|
||||
public static final String NAME = "server";
|
||||
|
||||
public Server(Path path) {
|
||||
super(path, false, false, true, NAME);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MinecraftJar forPath(Path path) {
|
||||
return new ServerOnly(path);
|
||||
return new Server(path);
|
||||
}
|
||||
}
|
||||
|
||||
// Un-split client jar
|
||||
public static final class Client extends MinecraftJar {
|
||||
public static final String NAME = "client";
|
||||
|
||||
public Client(Path path) {
|
||||
super(path, false, true, false, NAME);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MinecraftJar forPath(Path path) {
|
||||
return new Client(path);
|
||||
}
|
||||
}
|
||||
|
||||
// Split client jar
|
||||
public static final class ClientOnly extends MinecraftJar {
|
||||
public static final String NAME = "clientOnly";
|
||||
|
||||
public ClientOnly(Path path) {
|
||||
super(path, false, true, false, "clientOnly");
|
||||
super(path, false, true, false, NAME);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -156,13 +156,13 @@ public abstract sealed class MinecraftSourceSets permits MinecraftSourceSets.Sin
|
||||
@Override
|
||||
public void applyDependencies(BiConsumer<String, String> consumer, List<String> targets) {
|
||||
Preconditions.checkArgument(targets.size() == 2);
|
||||
Preconditions.checkArgument(targets.contains("common"));
|
||||
Preconditions.checkArgument(targets.contains("clientOnly"));
|
||||
Preconditions.checkArgument(targets.contains(MinecraftJar.Common.NAME));
|
||||
Preconditions.checkArgument(targets.contains(MinecraftJar.ClientOnly.NAME));
|
||||
|
||||
consumer.accept(MINECRAFT_COMMON_NAMED.runtime(), "common");
|
||||
consumer.accept(MINECRAFT_CLIENT_ONLY_NAMED.runtime(), "clientOnly");
|
||||
consumer.accept(MINECRAFT_COMMON_NAMED.compile(), "common");
|
||||
consumer.accept(MINECRAFT_CLIENT_ONLY_NAMED.compile(), "clientOnly");
|
||||
consumer.accept(MINECRAFT_COMMON_NAMED.runtime(), MinecraftJar.Common.NAME);
|
||||
consumer.accept(MINECRAFT_CLIENT_ONLY_NAMED.runtime(), MinecraftJar.ClientOnly.NAME);
|
||||
consumer.accept(MINECRAFT_COMMON_NAMED.compile(), MinecraftJar.Common.NAME);
|
||||
consumer.accept(MINECRAFT_CLIENT_ONLY_NAMED.compile(), MinecraftJar.ClientOnly.NAME);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -28,16 +28,22 @@ import java.nio.file.Path;
|
||||
import java.util.function.Function;
|
||||
|
||||
public enum SingleJarEnvType {
|
||||
CLIENT(MinecraftJar.ClientOnly::new),
|
||||
SERVER(MinecraftJar.ServerOnly::new);
|
||||
CLIENT(MinecraftJar.Client::new, MinecraftJar.Client.NAME),
|
||||
SERVER(MinecraftJar.Server::new, MinecraftJar.Server.NAME);
|
||||
|
||||
private final Function<Path, MinecraftJar> jarFunction;
|
||||
private final String name;
|
||||
|
||||
SingleJarEnvType(Function<Path, MinecraftJar> jarFunction) {
|
||||
SingleJarEnvType(Function<Path, MinecraftJar> jarFunction, String name) {
|
||||
this.jarFunction = jarFunction;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Function<Path, MinecraftJar> getJar() {
|
||||
return jarFunction;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ public interface MappedMinecraftProvider {
|
||||
}
|
||||
|
||||
interface Merged extends ProviderImpl {
|
||||
String MERGED = "merged";
|
||||
String MERGED = MinecraftJar.Merged.NAME;
|
||||
|
||||
default MinecraftJar getMergedJar() {
|
||||
return new MinecraftJar.Merged(getJar(MERGED));
|
||||
@@ -55,8 +55,8 @@ public interface MappedMinecraftProvider {
|
||||
}
|
||||
|
||||
interface Split extends ProviderImpl {
|
||||
String COMMON = "common";
|
||||
String CLIENT_ONLY = "clientOnly";
|
||||
String COMMON = MinecraftJar.Common.NAME;
|
||||
String CLIENT_ONLY = MinecraftJar.ClientOnly.NAME;
|
||||
|
||||
default MinecraftJar getCommonJar() {
|
||||
return new MinecraftJar.Common(getJar(COMMON));
|
||||
@@ -76,7 +76,7 @@ public interface MappedMinecraftProvider {
|
||||
SingleJarEnvType env();
|
||||
|
||||
default String envName() {
|
||||
return "%sOnly".formatted(env());
|
||||
return env().getName();
|
||||
}
|
||||
|
||||
default MinecraftJar getEnvOnlyJar() {
|
||||
|
||||
@@ -94,7 +94,7 @@ import net.fabricmc.loom.util.ipc.IPCServer;
|
||||
import net.fabricmc.loom.util.service.ScopedSharedServiceManager;
|
||||
import net.fabricmc.mappingio.MappingReader;
|
||||
import net.fabricmc.mappingio.adapter.MappingSourceNsSwitch;
|
||||
import net.fabricmc.mappingio.format.Tiny2Writer;
|
||||
import net.fabricmc.mappingio.format.tiny.Tiny2FileWriter;
|
||||
import net.fabricmc.mappingio.tree.MemoryMappingTree;
|
||||
|
||||
@DisableCachingByDefault
|
||||
@@ -521,7 +521,7 @@ public abstract class GenerateSourcesTask extends AbstractLoomTask {
|
||||
}
|
||||
|
||||
try (Writer writer = Files.newBufferedWriter(outputMappings, StandardCharsets.UTF_8)) {
|
||||
Tiny2Writer tiny2Writer = new Tiny2Writer(writer, false);
|
||||
var tiny2Writer = new Tiny2FileWriter(writer, false);
|
||||
mappingTree.accept(new MappingSourceNsSwitch(tiny2Writer, MappingsNamespace.NAMED.toString()));
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("Failed to write mappings", e);
|
||||
|
||||
@@ -134,21 +134,31 @@ public abstract class LoomTasks implements Runnable {
|
||||
});
|
||||
}
|
||||
|
||||
private static String getRunConfigTaskName(RunConfigSettings config) {
|
||||
String configName = config.getName();
|
||||
return "run" + configName.substring(0, 1).toUpperCase() + configName.substring(1);
|
||||
}
|
||||
|
||||
private void registerRunTasks() {
|
||||
LoomGradleExtension extension = LoomGradleExtension.get(getProject());
|
||||
|
||||
Preconditions.checkArgument(extension.getRunConfigs().size() == 0, "Run configurations must not be registered before loom");
|
||||
|
||||
extension.getRunConfigs().whenObjectAdded(config -> {
|
||||
String configName = config.getName();
|
||||
String taskName = "run" + configName.substring(0, 1).toUpperCase() + configName.substring(1);
|
||||
|
||||
getTasks().register(taskName, RunGameTask.class, config).configure(t -> {
|
||||
getTasks().register(getRunConfigTaskName(config), RunGameTask.class, config).configure(t -> {
|
||||
t.setDescription("Starts the '" + config.getConfigName() + "' run configuration");
|
||||
|
||||
t.dependsOn(config.getEnvironment().equals("client") ? "configureClientLaunch" : "configureLaunch");
|
||||
});
|
||||
});
|
||||
|
||||
extension.getRunConfigs().whenObjectRemoved(runConfigSettings -> {
|
||||
getTasks().named(getRunConfigTaskName(runConfigSettings), task -> {
|
||||
// Disable the task so it can't be run
|
||||
task.setEnabled(false);
|
||||
});
|
||||
});
|
||||
|
||||
extension.getRunConfigs().create("client", RunConfigSettings::client);
|
||||
extension.getRunConfigs().create("server", RunConfigSettings::server);
|
||||
|
||||
|
||||
@@ -28,6 +28,10 @@ import java.io.IOException;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.net.StandardProtocolFamily;
|
||||
import java.nio.channels.ServerSocketChannel;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
final class CurrentPlatform implements Platform {
|
||||
static final Platform INSTANCE = new CurrentPlatform();
|
||||
@@ -35,11 +39,13 @@ final class CurrentPlatform implements Platform {
|
||||
private final OperatingSystem operatingSystem;
|
||||
private final Architecture architecture;
|
||||
private final boolean supportsUnixDomainSockets;
|
||||
private final boolean isRaspberryPi;
|
||||
|
||||
private CurrentPlatform() {
|
||||
this.operatingSystem = getCurrentOperatingSystem();
|
||||
this.architecture = getCurrentArchitecture();
|
||||
this.supportsUnixDomainSockets = isUnixDomainSocketsSupported();
|
||||
this.isRaspberryPi = getIsRaspberryPi(operatingSystem, architecture);
|
||||
}
|
||||
|
||||
private static OperatingSystem getCurrentOperatingSystem() {
|
||||
@@ -84,6 +90,29 @@ final class CurrentPlatform implements Platform {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the current system is a Raspberry Pi running Debian 12 (Bookworm).
|
||||
*/
|
||||
private static boolean getIsRaspberryPi(OperatingSystem operatingSystem, Architecture architecture) {
|
||||
if (operatingSystem != OperatingSystem.LINUX || !architecture.isArm()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
final Path releasePath = Paths.get("/etc/os-release");
|
||||
final String release = Files.readString(releasePath, StandardCharsets.UTF_8);
|
||||
final boolean isDebianBookworm = release.contains("VERSION_CODENAME=bookworm");
|
||||
|
||||
final Path modelPath = Paths.get("/sys/firmware/devicetree/base/model");
|
||||
final String model = Files.readString(modelPath, StandardCharsets.UTF_8);
|
||||
final boolean isRaspberryPi = model.startsWith("Raspberry Pi");
|
||||
|
||||
return isDebianBookworm && isRaspberryPi;
|
||||
} catch (IOException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public OperatingSystem getOperatingSystem() {
|
||||
return operatingSystem;
|
||||
@@ -98,4 +127,9 @@ final class CurrentPlatform implements Platform {
|
||||
public boolean supportsUnixDomainSockets() {
|
||||
return supportsUnixDomainSockets;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRaspberryPi() {
|
||||
return isRaspberryPi;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,4 +56,6 @@ public interface Platform {
|
||||
Architecture getArchitecture();
|
||||
|
||||
boolean supportsUnixDomainSockets();
|
||||
|
||||
boolean isRaspberryPi();
|
||||
}
|
||||
|
||||
@@ -85,6 +85,8 @@ class DataGenerationTest extends Specification implements GradleProjectTestTrait
|
||||
mappings "net.fabricmc:yarn:1.20.2+build.4:v2"
|
||||
modImplementation "net.fabricmc:fabric-loader:0.14.23"
|
||||
modImplementation "net.fabricmc.fabric-api:fabric-api:0.90.0+1.20.2"
|
||||
|
||||
modDatagenImplementation fabricApi.module("fabric-data-generation-api-v1", "0.90.0+1.20.2")
|
||||
}
|
||||
'''
|
||||
when:
|
||||
|
||||
@@ -41,6 +41,7 @@ import io.reactivex.functions.Function
|
||||
import spock.lang.Specification
|
||||
import spock.lang.Timeout
|
||||
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftJar
|
||||
import net.fabricmc.loom.test.util.GradleProjectTestTrait
|
||||
import net.fabricmc.loom.util.ZipUtils
|
||||
|
||||
@@ -138,7 +139,7 @@ class DebugLineNumbersTest extends Specification implements GradleProjectTestTra
|
||||
}
|
||||
|
||||
private static String getClassSource(GradleProject gradle, String classname, String mappings = MAPPINGS) {
|
||||
File sourcesJar = gradle.getGeneratedSources(mappings, "serveronly")
|
||||
File sourcesJar = gradle.getGeneratedSources(mappings, MinecraftJar.Server.NAME)
|
||||
return new String(ZipUtils.unpack(sourcesJar.toPath(), classname), StandardCharsets.UTF_8)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
||||
*
|
||||
* Copyright (c) 2021 FabricMC
|
||||
* Copyright (c) 2021-2023 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
|
||||
@@ -41,7 +41,7 @@ class FabricAPITest extends Specification implements GradleProjectTestTrait {
|
||||
private static final String API_VERSION = "0.0.0+loom"
|
||||
|
||||
@Unroll
|
||||
def "build and run (gradle #version)"() {
|
||||
def "build and run (gradle #version, mixin ap disabled: #disableMixinAp)"() {
|
||||
setup:
|
||||
def gradle = gradleProject(
|
||||
repo: "https://github.com/FabricMC/fabric.git",
|
||||
@@ -52,10 +52,22 @@ class FabricAPITest extends Specification implements GradleProjectTestTrait {
|
||||
|
||||
gradle.enableMultiProjectOptimisation()
|
||||
|
||||
// Disable the mixin ap if needed. Fabric API is a large enough test project to see if something breaks.
|
||||
def mixinApPatch = ""
|
||||
|
||||
if (disableMixinAp) {
|
||||
mixinApPatch = """
|
||||
|
||||
allprojects {
|
||||
loom.mixin.useLegacyMixinAp = false
|
||||
}
|
||||
""".stripIndent()
|
||||
}
|
||||
|
||||
// Set the version to something constant
|
||||
gradle.buildGradle.text = gradle.buildGradle.text.replace('project.version + "+" + (ENV.GITHUB_RUN_NUMBER ? "" : "local-") + getBranch()', "\"$API_VERSION\"")
|
||||
.replace('id "fabric-loom" version "0.9.50"', 'id "dev.architectury.loom"')
|
||||
.replace('"fabric-loom"', '"dev.architectury.loom"')
|
||||
.replace('"fabric-loom"', '"dev.architectury.loom"') + mixinApPatch
|
||||
|
||||
def server = ServerRunner.create(gradle.projectDir, "23w33a")
|
||||
.withMod(gradle.getOutputFile("fabric-api-${API_VERSION}.jar"))
|
||||
@@ -85,7 +97,9 @@ class FabricAPITest extends Specification implements GradleProjectTestTrait {
|
||||
serverResult.successful()
|
||||
serverResult.output.contains("- fabric-api $API_VERSION")
|
||||
where:
|
||||
//version << STANDARD_TEST_VERSIONS
|
||||
version << [DEFAULT_GRADLE]
|
||||
[version, disableMixinAp] << [
|
||||
[DEFAULT_GRADLE],
|
||||
[false, true]
|
||||
].combinations()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,29 +33,34 @@ import static net.fabricmc.loom.test.LoomTestConstants.STANDARD_TEST_VERSIONS
|
||||
import static org.gradle.testkit.runner.TaskOutcome.SUCCESS
|
||||
|
||||
class MultiMcVersionTest extends Specification implements GradleProjectTestTrait {
|
||||
static def versions = [
|
||||
'fabric-1.14.4',
|
||||
'fabric-1.15',
|
||||
'fabric-1.15.2',
|
||||
'fabric-1.16',
|
||||
'fabric-1.16.5',
|
||||
'fabric-1.17',
|
||||
'fabric-1.17.1',
|
||||
'fabric-1.18',
|
||||
'fabric-1.18.2',
|
||||
'fabric-1.19',
|
||||
'fabric-1.19.3'
|
||||
]
|
||||
|
||||
@Unroll
|
||||
def "build (gradle #version)"() {
|
||||
setup:
|
||||
def gradle = gradleProject(project: "multi-mc-versions", version: version)
|
||||
|
||||
versions.forEach {
|
||||
// Make dir as its now required by Gradle
|
||||
new File(gradle.projectDir, it).mkdir()
|
||||
}
|
||||
|
||||
when:
|
||||
def result = gradle.run(tasks: "build")
|
||||
|
||||
then:
|
||||
def versions = [
|
||||
'fabric-1.14.4',
|
||||
'fabric-1.15',
|
||||
'fabric-1.15.2',
|
||||
'fabric-1.16',
|
||||
'fabric-1.16.5',
|
||||
'fabric-1.17',
|
||||
'fabric-1.17.1',
|
||||
'fabric-1.18',
|
||||
'fabric-1.18.2',
|
||||
'fabric-1.19',
|
||||
'fabric-1.19.3'
|
||||
]
|
||||
|
||||
result.task(":build").outcome == SUCCESS
|
||||
versions.forEach {
|
||||
result.task(":$it:build").outcome == SUCCESS
|
||||
|
||||
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
||||
*
|
||||
* Copyright (c) 2023 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.Path
|
||||
|
||||
import groovy.json.JsonOutput
|
||||
import spock.lang.Specification
|
||||
import spock.lang.TempDir
|
||||
|
||||
import net.fabricmc.loom.configuration.mods.MixinDetector
|
||||
import net.fabricmc.loom.util.FileSystemUtil
|
||||
|
||||
class MixinDetectorTest extends Specification {
|
||||
@TempDir
|
||||
Path tempDir
|
||||
|
||||
private Path makeJar(Map<String, String> mixinConfigs) {
|
||||
def path = tempDir.resolve("test.jar")
|
||||
def fs = FileSystemUtil.getJarFileSystem(path, true)
|
||||
|
||||
try {
|
||||
// Create fabric.mod.json
|
||||
def fabricModJson = JsonOutput.toJson([
|
||||
schemaVersion: 1,
|
||||
id: 'test',
|
||||
version: '1',
|
||||
mixins: mixinConfigs.keySet()
|
||||
])
|
||||
fs.getPath('fabric.mod.json').text = fabricModJson
|
||||
|
||||
// Write all mixin configs
|
||||
mixinConfigs.forEach { name, content ->
|
||||
fs.getPath(name).text = content
|
||||
}
|
||||
} finally {
|
||||
fs.close()
|
||||
}
|
||||
|
||||
return path
|
||||
}
|
||||
|
||||
def "jar without mixins has no mixins without refmaps"() {
|
||||
setup:
|
||||
def jarPath = makeJar([:])
|
||||
|
||||
when:
|
||||
def hasMixinsWithoutRefmaps = MixinDetector.hasMixinsWithoutRefmap(jarPath)
|
||||
|
||||
then:
|
||||
!hasMixinsWithoutRefmaps // no mixins
|
||||
}
|
||||
|
||||
def "jar with one mixin config with refmap has no mixins without refmaps"() {
|
||||
setup:
|
||||
def jarPath = makeJar([
|
||||
'test.mixins.json': JsonOutput.toJson([
|
||||
'package': 'com.example.test',
|
||||
'mixins': ['TestMixin'],
|
||||
'refmap': 'test-refmap.json'
|
||||
])
|
||||
])
|
||||
|
||||
when:
|
||||
def hasMixinsWithoutRefmaps = MixinDetector.hasMixinsWithoutRefmap(jarPath)
|
||||
|
||||
then:
|
||||
!hasMixinsWithoutRefmaps // no mixins with refmaps
|
||||
}
|
||||
|
||||
def "jar with one mixin config without refmap has mixins without refmaps"() {
|
||||
setup:
|
||||
def jarPath = makeJar([
|
||||
'test.mixins.json': JsonOutput.toJson([
|
||||
'package': 'com.example.test',
|
||||
'mixins': ['TestMixin']
|
||||
])
|
||||
])
|
||||
|
||||
when:
|
||||
def hasMixinsWithoutRefmaps = MixinDetector.hasMixinsWithoutRefmap(jarPath)
|
||||
|
||||
then:
|
||||
hasMixinsWithoutRefmaps // mixins with refmaps
|
||||
}
|
||||
|
||||
def "jar with mixed mixin configs has mixins without refmaps"() {
|
||||
setup:
|
||||
def jarPath = makeJar([
|
||||
'test.mixins.json': JsonOutput.toJson([
|
||||
'package': 'com.example.test',
|
||||
'mixins': ['TestMixin']
|
||||
]),
|
||||
'test2.mixins.json': JsonOutput.toJson([
|
||||
'package': 'com.example.test2',
|
||||
'mixins': ['TestMixin2'],
|
||||
'refmap': 'test2-refmap.json'
|
||||
])
|
||||
])
|
||||
|
||||
when:
|
||||
def hasMixinsWithoutRefmaps = MixinDetector.hasMixinsWithoutRefmap(jarPath)
|
||||
|
||||
then:
|
||||
hasMixinsWithoutRefmaps // mixins with refmaps
|
||||
}
|
||||
}
|
||||
@@ -48,7 +48,7 @@ import net.fabricmc.loom.util.download.Download
|
||||
import net.fabricmc.loom.util.download.DownloadBuilder
|
||||
import net.fabricmc.mappingio.adapter.MappingDstNsReorder
|
||||
import net.fabricmc.mappingio.adapter.MappingSourceNsSwitch
|
||||
import net.fabricmc.mappingio.format.Tiny2Writer
|
||||
import net.fabricmc.mappingio.format.tiny.Tiny2FileWriter
|
||||
import net.fabricmc.mappingio.tree.MemoryMappingTree
|
||||
|
||||
abstract class LayeredMappingsSpecification extends Specification implements LayeredMappingsTestConstants {
|
||||
@@ -102,7 +102,7 @@ abstract class LayeredMappingsSpecification extends Specification implements Lay
|
||||
|
||||
String getTiny(MemoryMappingTree mappingTree) {
|
||||
def sw = new StringWriter()
|
||||
mappingTree.accept(new Tiny2Writer(sw, false))
|
||||
mappingTree.accept(new Tiny2FileWriter(sw, false))
|
||||
return sw.toString()
|
||||
}
|
||||
|
||||
|
||||
@@ -58,6 +58,11 @@ class PlatformTestUtils implements Platform {
|
||||
supportsUnixDomainSockets
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean isRaspberryPi() {
|
||||
return false
|
||||
}
|
||||
|
||||
@Immutable
|
||||
static class TestArchitecture implements Architecture {
|
||||
boolean is64Bit
|
||||
|
||||
@@ -25,6 +25,13 @@ loom {
|
||||
name = 'Custom Main Class'
|
||||
mainClass.set 'net.fabricmc.example.Main'
|
||||
}
|
||||
|
||||
// Test that removing a run config works
|
||||
removeMe {
|
||||
inherit server
|
||||
}
|
||||
|
||||
remove removeMe
|
||||
}
|
||||
|
||||
runConfigs.configureEach {
|
||||
|
||||
Reference in New Issue
Block a user