Remapper extensions (#984)

* Remapper extension API

* Fix build

* More work

* Fixes, thanks Gradle.

* Build fix

* Cleanup
This commit is contained in:
modmuss
2023-12-15 09:47:26 +00:00
committed by GitHub
parent 0e9663b7a4
commit 014a6fce2b
17 changed files with 595 additions and 4 deletions

View File

@@ -45,6 +45,7 @@ import net.fabricmc.loom.configuration.providers.minecraft.mapped.IntermediaryMi
import net.fabricmc.loom.configuration.providers.minecraft.mapped.NamedMinecraftProvider;
import net.fabricmc.loom.extension.LoomFiles;
import net.fabricmc.loom.extension.MixinExtension;
import net.fabricmc.loom.extension.RemapperExtensionHolder;
import net.fabricmc.loom.util.download.DownloadBuilder;
@ApiStatus.Internal
@@ -115,4 +116,6 @@ public interface LoomGradleExtension extends LoomGradleExtensionAPI {
boolean multiProjectOptimisation();
ListProperty<LibraryProcessorManager.LibraryProcessorFactory> getLibraryProcessors();
ListProperty<RemapperExtensionHolder> getRemapperExtensions();
}

View File

@@ -44,6 +44,8 @@ import net.fabricmc.loom.api.decompilers.DecompilerOptions;
import net.fabricmc.loom.api.mappings.intermediate.IntermediateMappingsProvider;
import net.fabricmc.loom.api.mappings.layered.spec.LayeredMappingSpecBuilder;
import net.fabricmc.loom.api.processor.MinecraftJarProcessor;
import net.fabricmc.loom.api.remapping.RemapperExtension;
import net.fabricmc.loom.api.remapping.RemapperParameters;
import net.fabricmc.loom.configuration.ide.RunConfigSettings;
import net.fabricmc.loom.configuration.processors.JarProcessor;
import net.fabricmc.loom.configuration.providers.mappings.NoOpIntermediateMappingsProvider;
@@ -221,4 +223,6 @@ public interface LoomGradleExtensionAPI {
Property<Boolean> getRuntimeOnlyLog4j();
Property<Boolean> getSplitModDependencies();
<T extends RemapperParameters> void addRemapperExtension(Class<RemapperExtension<T>> remapperExtensionClass, Class<T> parametersClass, Action<T> parameterAction);
}

View File

@@ -0,0 +1,47 @@
/*
* 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.api.remapping;
import org.objectweb.asm.commons.Remapper;
/**
* Context for a {@link RemapperExtension}.
*/
public interface RemapperContext {
/**
* @return The {@link Remapper} instance
*/
Remapper remapper();
/**
* @return the source namespace
*/
String sourceNamespace();
/**
* @return the target namespace
*/
String targetNamespace();
}

View File

@@ -0,0 +1,53 @@
/*
* 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.api.remapping;
import javax.inject.Inject;
import org.gradle.api.Action;
import org.objectweb.asm.ClassVisitor;
/**
* A remapper extension can be used to add extra processing to the remapping process.
*
* <p>Implementations of RemapperExtension's must have the following:
* A single constructor annotated with {@link Inject}, and taking a single argument of the parameters.
* Or a single constructor annotated with {@link Inject} taking no arguments, when the extension does not have any parameters.
*
* <p>Use {@link net.fabricmc.loom.api.LoomGradleExtensionAPI#addRemapperExtension(Class, Class, Action)} to register a remapper extension.
*
* @param <T> Parameter type for the extension. Should be {@link RemapperParameters.None} if the action does not have parameters.
*/
public interface RemapperExtension<T extends RemapperParameters> {
/**
* Return a {@link ClassVisitor} that will be used when remapping the given class.
*
* @param className The name of the class being remapped
* @param remapperContext The remapper context
* @param classVisitor The parent class visitor
* @return A {@link ClassVisitor} that will be used when remapping the given class, or the given {@code classVisitor} if no extra processing is required for this class.
*/
ClassVisitor insertVisitor(String className, RemapperContext remapperContext, ClassVisitor classVisitor);
}

View File

@@ -0,0 +1,42 @@
/*
* 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.api.remapping;
import org.jetbrains.annotations.ApiStatus;
/**
* Marker interface for parameter objects to {@link RemapperExtension}s.
*
* <p>Design based off of Gradle's {@link org.gradle.workers.WorkParameters}.
*/
public interface RemapperParameters {
final class None implements RemapperParameters {
@ApiStatus.Internal
public static None INSTANCE = new None();
private None() {
}
}
}

View File

@@ -0,0 +1,68 @@
/*
* 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.api.remapping;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.Nullable;
import net.fabricmc.tinyremapper.TinyRemapper;
/**
* A remapper extension, that has direct access to the TinyRemapper APIs.
*
* <p>This API is not stable and may change without notice.
*/
@ApiStatus.Experimental
public interface TinyRemapperExtension {
/**
* See: {@link TinyRemapper.Builder#extraAnalyzeVisitor(TinyRemapper.AnalyzeVisitorProvider)}.
*
* @return A {@link TinyRemapper.AnalyzeVisitorProvider} or {@code null}.
*/
@Nullable
default TinyRemapper.AnalyzeVisitorProvider getAnalyzeVisitorProvider() {
return null;
}
/**
* See: {@link TinyRemapper.Builder#extraPreApplyVisitor(TinyRemapper.ApplyVisitorProvider)}.
*
* @return A {@link TinyRemapper.ApplyVisitorProvider} or {@code null}.
*/
@Nullable
default TinyRemapper.ApplyVisitorProvider getPreApplyVisitor() {
return null;
}
/**
* See: {@link TinyRemapper.Builder#extraPostApplyVisitor(TinyRemapper.ApplyVisitorProvider)}.
*
* @return A {@link TinyRemapper.ApplyVisitorProvider} or {@code null}.
*/
@Nullable
default TinyRemapper.ApplyVisitorProvider getPostApplyVisitor() {
return null;
}
}

View File

@@ -51,6 +51,7 @@ import net.fabricmc.loom.api.RemapConfigurationSettings;
import net.fabricmc.loom.api.mappings.layered.MappingsNamespace;
import net.fabricmc.loom.configuration.mods.dependency.ModDependency;
import net.fabricmc.loom.configuration.providers.mappings.MappingConfiguration;
import net.fabricmc.loom.extension.RemapperExtensionHolder;
import net.fabricmc.loom.util.Constants;
import net.fabricmc.loom.util.Pair;
import net.fabricmc.loom.util.TinyRemapperHelper;
@@ -157,6 +158,10 @@ public class ModProcessor {
builder.extension(new MixinExtension(remapMixins::contains));
}
for (RemapperExtensionHolder holder : extension.getRemapperExtensions().get()) {
holder.apply(builder, fromM, toM, project.getObjects());
}
final TinyRemapper remapper = builder.build();
for (Path minecraftJar : extension.getMinecraftJars(MappingsNamespace.INTERMEDIARY)) {

View File

@@ -34,6 +34,7 @@ import org.gradle.api.Project;
import org.gradle.api.artifacts.Dependency;
import org.gradle.api.file.ConfigurableFileCollection;
import org.gradle.api.file.RegularFileProperty;
import org.gradle.api.model.ObjectFactory;
import org.gradle.api.provider.ListProperty;
import org.gradle.api.provider.Property;
import org.gradle.api.provider.SetProperty;
@@ -50,6 +51,8 @@ import net.fabricmc.loom.api.decompilers.DecompilerOptions;
import net.fabricmc.loom.api.mappings.intermediate.IntermediateMappingsProvider;
import net.fabricmc.loom.api.mappings.layered.spec.LayeredMappingSpecBuilder;
import net.fabricmc.loom.api.processor.MinecraftJarProcessor;
import net.fabricmc.loom.api.remapping.RemapperExtension;
import net.fabricmc.loom.api.remapping.RemapperParameters;
import net.fabricmc.loom.configuration.RemapConfigurations;
import net.fabricmc.loom.configuration.ide.RunConfigSettings;
import net.fabricmc.loom.configuration.processors.JarProcessor;
@@ -91,6 +94,7 @@ public abstract class LoomGradleExtensionApiImpl implements LoomGradleExtensionA
private final NamedDomainObjectContainer<ModSettings> mods;
private final NamedDomainObjectList<RemapConfigurationSettings> remapConfigurations;
private final ListProperty<MinecraftJarProcessor<?>> minecraftJarProcessors;
protected final ListProperty<RemapperExtensionHolder> remapperExtensions;
// A common mistake with layered mappings is to call the wrong `officialMojangMappings` method, use this to keep track of when we are building a layered mapping spec.
protected final ThreadLocal<Boolean> layeredSpecBuilderScope = ThreadLocal.withInitial(() -> false);
@@ -150,6 +154,9 @@ public abstract class LoomGradleExtensionApiImpl implements LoomGradleExtensionA
this.splitEnvironmentalSourceSet = project.getObjects().property(Boolean.class).convention(false);
this.splitEnvironmentalSourceSet.finalizeValueOnRead();
remapperExtensions = project.getObjects().listProperty(RemapperExtensionHolder.class);
remapperExtensions.finalizeValueOnRead();
// Enable dep iface injection by default
interfaceInjection(interfaceInjection -> {
interfaceInjection.getEnableDependencyInterfaceInjection().convention(true).finalizeValueOnRead();
@@ -382,6 +389,23 @@ public abstract class LoomGradleExtensionApiImpl implements LoomGradleExtensionA
RemapConfigurations.setupForSourceSet(getProject(), sourceSet);
}
@Override
public <T extends RemapperParameters> void addRemapperExtension(Class<RemapperExtension<T>> remapperExtensionClass, Class<T> parametersClass, Action<T> parameterAction) {
final ObjectFactory objectFactory = getProject().getObjects();
final RemapperExtensionHolder holder;
if (parametersClass != RemapperParameters.None.class) {
T parameters = objectFactory.newInstance(parametersClass);
parameterAction.execute(parameters);
holder = objectFactory.newInstance(RemapperExtensionHolder.class, parameters);
} else {
holder = objectFactory.newInstance(RemapperExtensionHolder.class, RemapperParameters.None.INSTANCE);
}
holder.getRemapperExtensionClassName().set(remapperExtensionClass.getName());
remapperExtensions.add(holder);
}
// This is here to ensure that LoomGradleExtensionApiImpl compiles without any unimplemented methods
private final class EnsureCompile extends LoomGradleExtensionApiImpl {
private EnsureCompile() {

View File

@@ -247,6 +247,11 @@ public class LoomGradleExtensionImpl extends LoomGradleExtensionApiImpl implemen
return libraryProcessorFactories;
}
@Override
public ListProperty<RemapperExtensionHolder> getRemapperExtensions() {
return remapperExtensions;
}
@Override
protected <T extends IntermediateMappingsProvider> void configureIntermediateMappingsProviderInternal(T provider) {
provider.getMinecraftVersion().set(getProject().provider(() -> getMinecraftProvider().minecraftVersion()));

View File

@@ -0,0 +1,128 @@
/*
* 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.extension;
import javax.inject.Inject;
import org.gradle.api.model.ObjectFactory;
import org.gradle.api.provider.Property;
import org.gradle.api.tasks.Input;
import org.gradle.api.tasks.Nested;
import org.gradle.api.tasks.Optional;
import org.jetbrains.annotations.Nullable;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.commons.Remapper;
import net.fabricmc.loom.api.remapping.RemapperContext;
import net.fabricmc.loom.api.remapping.RemapperExtension;
import net.fabricmc.loom.api.remapping.RemapperParameters;
import net.fabricmc.loom.api.remapping.TinyRemapperExtension;
import net.fabricmc.tinyremapper.TinyRemapper;
import net.fabricmc.tinyremapper.api.TrClass;
public abstract class RemapperExtensionHolder {
// Null when RemapperParameters.None.class
private final RemapperParameters remapperParameters;
@Inject
public RemapperExtensionHolder(RemapperParameters remapperParameters) {
this.remapperParameters = remapperParameters;
}
@Input
public abstract Property<String> getRemapperExtensionClassName();
@Nested
@Optional
public RemapperParameters getRemapperParameters() {
return remapperParameters;
}
public void apply(TinyRemapper.Builder tinyRemapperBuilder, String sourceNamespace, String targetNamespace, ObjectFactory objectFactory) {
final RemapperExtension<?> remapperExtension = newInstance(objectFactory);
tinyRemapperBuilder.extraPostApplyVisitor(new RemapperExtensionImpl(remapperExtension, sourceNamespace, targetNamespace));
if (remapperExtension instanceof TinyRemapperExtension tinyRemapperExtension) {
final TinyRemapper.AnalyzeVisitorProvider analyzeVisitorProvider = tinyRemapperExtension.getAnalyzeVisitorProvider();
final TinyRemapper.ApplyVisitorProvider preApplyVisitorProvider = tinyRemapperExtension.getPreApplyVisitor();
final TinyRemapper.ApplyVisitorProvider postApplyVisitorProvider = tinyRemapperExtension.getPostApplyVisitor();
if (analyzeVisitorProvider != null) {
tinyRemapperBuilder.extraAnalyzeVisitor(analyzeVisitorProvider);
}
if (preApplyVisitorProvider != null) {
tinyRemapperBuilder.extraPreApplyVisitor(preApplyVisitorProvider);
}
if (postApplyVisitorProvider != null) {
tinyRemapperBuilder.extraPostApplyVisitor(postApplyVisitorProvider);
}
}
}
private RemapperExtension<?> newInstance(ObjectFactory objectFactory) {
try {
Class<? extends RemapperExtension> remapperExtensionClass = Class.forName(getRemapperExtensionClassName().get())
.asSubclass(RemapperExtension.class);
if (remapperParameters == RemapperParameters.None.INSTANCE) {
return objectFactory.newInstance(remapperExtensionClass);
}
return objectFactory.newInstance(remapperExtensionClass, remapperParameters);
} catch (Exception e) {
throw new RuntimeException("Failed to create remapper extension", e);
}
}
private static final class RemapperExtensionImpl implements TinyRemapper.ApplyVisitorProvider {
private final RemapperExtension<?> remapperExtension;
private final String sourceNamespace;
private final String targetNamespace;
@Nullable
private RemapperContext context;
private RemapperExtensionImpl(RemapperExtension<?> remapperExtension, String sourceNamespace, String targetNamespace) {
this.remapperExtension = remapperExtension;
this.sourceNamespace = sourceNamespace;
this.targetNamespace = targetNamespace;
}
@Override
public ClassVisitor insertApplyVisitor(TrClass cls, ClassVisitor next) {
if (context == null) {
context = new RemapperContextImpl(cls.getEnvironment().getRemapper(), sourceNamespace, targetNamespace);
}
return remapperExtension.insertVisitor(cls.getName(), context, next);
}
}
private record RemapperContextImpl(Remapper remapper, String sourceNamespace, String targetNamespace) implements RemapperContext {
}
}

View File

@@ -39,11 +39,13 @@ import java.util.StringJoiner;
import org.gradle.api.Project;
import org.gradle.api.invocation.Gradle;
import org.gradle.api.model.ObjectFactory;
import org.gradle.api.tasks.SourceSet;
import org.jetbrains.annotations.Nullable;
import net.fabricmc.loom.LoomGradleExtension;
import net.fabricmc.loom.build.mixin.AnnotationProcessorInvoker;
import net.fabricmc.loom.extension.RemapperExtensionHolder;
import net.fabricmc.loom.task.AbstractRemapJarTask;
import net.fabricmc.loom.util.gradle.GradleUtils;
import net.fabricmc.loom.util.gradle.SourceSetHelper;
@@ -90,7 +92,7 @@ public class TinyRemapperService implements SharedService {
mappings.add(gradleMixinMappingProvider(serviceManager, project.getGradle(), extension.getMappingConfiguration().mappingsIdentifier, from, to));
}
return new TinyRemapperService(mappings, !legacyMixin, kotlinClasspathService, extension.getKnownIndyBsms().get());
return new TinyRemapperService(mappings, !legacyMixin, kotlinClasspathService, extension.getKnownIndyBsms().get(), extension.getRemapperExtensions().get(), from, to, project.getObjects());
});
service.readClasspath(remapJarTask.getClasspath().getFiles().stream().map(File::toPath).filter(Files::exists).toList());
@@ -129,7 +131,7 @@ public class TinyRemapperService implements SharedService {
// Set to true once remapping has started, once set no inputs can be read.
private boolean isRemapping = false;
public TinyRemapperService(List<IMappingProvider> mappings, boolean useMixinExtension, @Nullable KotlinClasspath kotlinClasspath, Set<String> knownIndyBsms) {
private TinyRemapperService(List<IMappingProvider> mappings, boolean useMixinExtension, @Nullable KotlinClasspath kotlinClasspath, Set<String> knownIndyBsms, List<RemapperExtensionHolder> remapperExtensions, String sourceNamespace, String targetNamespace, ObjectFactory objectFactory) {
TinyRemapper.Builder builder = TinyRemapper.newRemapper().withKnownIndyBsm(knownIndyBsms);
for (IMappingProvider provider : mappings) {
@@ -145,6 +147,10 @@ public class TinyRemapperService implements SharedService {
builder.extension(kotlinRemapperClassloader.getTinyRemapperExtension());
}
for (RemapperExtensionHolder holder : remapperExtensions) {
holder.apply(builder, sourceNamespace, targetNamespace, objectFactory);
}
tinyRemapper = builder.build();
}

View File

@@ -42,6 +42,7 @@ class SimpleProjectTest extends Specification implements GradleProjectTestTrait
def "build and run (gradle #version)"() {
setup:
def gradle = gradleProject(project: "simple", version: version)
gradle.buildSrc("remapext") // apply the remap extension plugin
def server = ServerRunner.create(gradle.projectDir, "1.16.5")
.withMod(gradle.getOutputFile("fabric-example-mod-1.0.0.jar"))
@@ -60,6 +61,7 @@ class SimpleProjectTest extends Specification implements GradleProjectTestTrait
serverResult.successful()
serverResult.output.contains("Hello simple Fabric mod") // A check to ensure our mod init was actually called
serverResult.output.contains("Hello Loom!") // Check that the remapper extension worked
where:
version << STANDARD_TEST_VERSIONS
}

View File

@@ -0,0 +1,61 @@
/*
* 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.integration.buildSrc.remapext
import org.objectweb.asm.ClassVisitor
import org.objectweb.asm.MethodVisitor
class StringReplacementClassVisitor extends ClassVisitor {
final Map<String, String> replacements
StringReplacementClassVisitor(int api, ClassVisitor classVisitor, Map<String, String> replacements) {
super(api, classVisitor)
this.replacements = replacements
}
@Override
MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) {
def methodVisitor = super.visitMethod(access, name, descriptor, signature, exceptions)
return new StringReplacementMethodVisitor(api, methodVisitor)
}
class StringReplacementMethodVisitor extends MethodVisitor {
StringReplacementMethodVisitor(int api, MethodVisitor methodVisitor) {
super(api, methodVisitor)
}
@Override
void visitLdcInsn(Object value) {
if (value instanceof String) {
String replacement = replacements.get(value)
if (replacement != null) {
value = replacement
}
}
super.visitLdcInsn(value)
}
}
}

View File

@@ -0,0 +1,43 @@
/*
* 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.integration.buildSrc.remapext
import org.gradle.api.Plugin
import org.gradle.api.Project
import net.fabricmc.loom.LoomGradleExtension
import net.fabricmc.loom.api.remapping.RemapperParameters
class TestPlugin implements Plugin<Project> {
@Override
void apply(Project project) {
def extension = LoomGradleExtension.get(project)
extension.addRemapperExtension(TestRemapperExtension.class, TestRemapperExtension.Params.class) { TestRemapperExtension.Params p ->
p.replacements.put("Hello World!", "Hello Loom!")
}
extension.addRemapperExtension(TestTinyRemapperExtension.class, RemapperParameters.None.class) { RemapperParameters.None p ->
}
}
}

View File

@@ -0,0 +1,54 @@
/*
* 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.integration.buildSrc.remapext
import javax.inject.Inject
import org.gradle.api.provider.MapProperty
import org.objectweb.asm.ClassVisitor
import net.fabricmc.loom.api.remapping.RemapperContext
import net.fabricmc.loom.api.remapping.RemapperExtension
import net.fabricmc.loom.api.remapping.RemapperParameters
import net.fabricmc.loom.util.Constants
abstract class TestRemapperExtension implements RemapperExtension<Params> {
final Params parameters
@Inject
TestRemapperExtension(Params parameters) {
this.parameters = parameters
}
@Override
ClassVisitor insertVisitor(String className, RemapperContext remapperContext, ClassVisitor classVisitor) {
def replacements = parameters.replacements.get()
return new StringReplacementClassVisitor(Constants.ASM_VERSION, classVisitor, replacements)
}
interface Params extends RemapperParameters {
MapProperty<String, String> getReplacements()
}
}

View File

@@ -0,0 +1,44 @@
/*
* 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.integration.buildSrc.remapext
import org.objectweb.asm.ClassVisitor
import net.fabricmc.loom.api.remapping.RemapperContext
import net.fabricmc.loom.api.remapping.RemapperExtension
import net.fabricmc.loom.api.remapping.RemapperParameters
import net.fabricmc.loom.api.remapping.TinyRemapperExtension
import net.fabricmc.tinyremapper.TinyRemapper
class TestTinyRemapperExtension implements RemapperExtension<RemapperParameters.None>, TinyRemapperExtension {
@Override
ClassVisitor insertVisitor(String className, RemapperContext remapperContext, ClassVisitor classVisitor) {
return classVisitor
}
TinyRemapper.AnalyzeVisitorProvider analyzeVisitorProvider = null
TinyRemapper.ApplyVisitorProvider preApplyVisitor = null
TinyRemapper.ApplyVisitorProvider PostApplyVisitor = null
}

View File

@@ -1,9 +1,10 @@
package net.fabricmc.example;
import net.fabricmc.api.ModInitializer;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import net.fabricmc.api.ModInitializer;
public class ExampleMod implements ModInitializer {
public static final Logger LOGGER = LogManager.getLogger("modid");
@@ -13,5 +14,6 @@ public class ExampleMod implements ModInitializer {
@Override
public void onInitialize() {
LOGGER.info("Hello simple Fabric mod!");
LOGGER.info("Hello World!");
}
}
}