aboutsummaryrefslogtreecommitdiff
path: root/src/forgeInject
diff options
context:
space:
mode:
Diffstat (limited to 'src/forgeInject')
-rw-r--r--src/forgeInject/java/mcp/MethodsReturnNonnullByDefault.java34
-rw-r--r--src/forgeInject/java/net/fabricmc/loom/inject/Pair.java52
-rw-r--r--src/forgeInject/java/net/fabricmc/loom/inject/YarnNamingService.java127
-rw-r--r--src/forgeInject/java/net/fabricmc/loom/inject/mixin/ForgeLoomMixinRemapperInjectorService.java93
-rw-r--r--src/forgeInject/java/net/fabricmc/loom/inject/mixin/MixinIntermediaryDevRemapper.java233
-rw-r--r--src/forgeInject/resources/META-INF/services/cpw.mods.modlauncher.api.INameMappingService1
-rw-r--r--src/forgeInject/resources/META-INF/services/cpw.mods.modlauncher.api.ITransformationService1
7 files changed, 541 insertions, 0 deletions
diff --git a/src/forgeInject/java/mcp/MethodsReturnNonnullByDefault.java b/src/forgeInject/java/mcp/MethodsReturnNonnullByDefault.java
new file mode 100644
index 00000000..8fbac050
--- /dev/null
+++ b/src/forgeInject/java/mcp/MethodsReturnNonnullByDefault.java
@@ -0,0 +1,34 @@
+/*
+ * This file is part of fabric-loom, licensed under the MIT License (MIT).
+ *
+ * Copyright (c) 2016, 2017, 2018 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 mcp;
+
+/**
+ * A dummy class, required for some Forge classes to load.
+ *
+ * @deprecated Don't use this in your mods. JetBrains annotations are there for you.
+ */
+@Deprecated
+public @interface MethodsReturnNonnullByDefault {
+}
diff --git a/src/forgeInject/java/net/fabricmc/loom/inject/Pair.java b/src/forgeInject/java/net/fabricmc/loom/inject/Pair.java
new file mode 100644
index 00000000..0206cb5d
--- /dev/null
+++ b/src/forgeInject/java/net/fabricmc/loom/inject/Pair.java
@@ -0,0 +1,52 @@
+/*
+ * This file is part of fabric-loom, licensed under the MIT License (MIT).
+ *
+ * Copyright (c) 2016, 2017, 2018 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.inject;
+
+import java.util.Map;
+
+final class Pair<A, B> implements Map.Entry<A, B> {
+ private final A first;
+ private final B second;
+
+ Pair(A first, B second) {
+ this.first = first;
+ this.second = second;
+ }
+
+ @Override
+ public A getKey() {
+ return first;
+ }
+
+ @Override
+ public B getValue() {
+ return second;
+ }
+
+ @Override
+ public B setValue(B value) {
+ throw new UnsupportedOperationException("Pairs are immutable!");
+ }
+}
diff --git a/src/forgeInject/java/net/fabricmc/loom/inject/YarnNamingService.java b/src/forgeInject/java/net/fabricmc/loom/inject/YarnNamingService.java
new file mode 100644
index 00000000..2b62dc53
--- /dev/null
+++ b/src/forgeInject/java/net/fabricmc/loom/inject/YarnNamingService.java
@@ -0,0 +1,127 @@
+/*
+ * This file is part of fabric-loom, licensed under the MIT License (MIT).
+ *
+ * Copyright (c) 2016, 2017, 2018 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.inject;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Map;
+import java.util.Optional;
+import java.util.function.BiFunction;
+import java.util.function.Predicate;
+
+import cpw.mods.modlauncher.api.INameMappingService;
+
+import net.fabricmc.mapping.tree.TinyMappingFactory;
+import net.fabricmc.mapping.tree.TinyTree;
+
+public class YarnNamingService implements INameMappingService {
+ private static final String PATH_TO_MAPPINGS = "fabric.yarnWithSrg.path";
+ private TinyTree mappings = null;
+
+ @Override
+ public String mappingName() {
+ return "srgtoyarn";
+ }
+
+ @Override
+ public String mappingVersion() {
+ return "1";
+ }
+
+ @Override
+ public Map.Entry<String, String> understanding() {
+ return new Pair<>("srg", "mcp");
+ }
+
+ @Override
+ public BiFunction<Domain, String, String> namingFunction() {
+ return this::remap;
+ }
+
+ private TinyTree getMappings() {
+ if (mappings != null) {
+ return mappings;
+ }
+
+ String pathStr = System.getProperty(PATH_TO_MAPPINGS);
+ if (pathStr == null) throw new RuntimeException("Missing system property '" + PATH_TO_MAPPINGS + "'!");
+ Path path = Paths.get(pathStr);
+
+ try (BufferedReader reader = Files.newBufferedReader(path)) {
+ mappings = TinyMappingFactory.loadWithDetection(reader);
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+
+ return mappings;
+ }
+
+ private String remap(Domain domain, String name) {
+ TinyTree mappings = getMappings();
+
+ switch (domain) {
+ case CLASS:
+ boolean dot = name.contains(".");
+ return find(mappings.getClasses(), def -> maybeReplace(dot, def.getName("srg"), '/', '.').equals(name))
+ .map(def -> maybeReplace(dot, def.getName("named"), '/', '.'))
+ .orElse(name);
+ case METHOD:
+ return mappings.getClasses().stream()
+ .flatMap(def -> def.getMethods().stream())
+ .filter(def -> def.getName("srg").equals(name))
+ .findAny()
+ .map(def -> def.getName("named"))
+ .orElse(name);
+ case FIELD:
+ return mappings.getClasses().stream()
+ .flatMap(def -> def.getFields().stream())
+ .filter(def -> def.getName("srg").equals(name))
+ .findAny()
+ .map(def -> def.getName("named"))
+ .orElse(name);
+ default:
+ return name;
+ }
+ }
+
+ // From CollectionUtil
+ private static <E> Optional<E> find(Iterable<? extends E> collection, Predicate<? super E> filter) {
+ for (E e : collection) {
+ if (filter.test(e)) {
+ return Optional.of(e);
+ }
+ }
+
+ return Optional.empty();
+ }
+
+ private static String maybeReplace(boolean run, String s, char from, char to) {
+ return run ? s.replace(from, to) : s;
+ }
+}
diff --git a/src/forgeInject/java/net/fabricmc/loom/inject/mixin/ForgeLoomMixinRemapperInjectorService.java b/src/forgeInject/java/net/fabricmc/loom/inject/mixin/ForgeLoomMixinRemapperInjectorService.java
new file mode 100644
index 00000000..1fe961c6
--- /dev/null
+++ b/src/forgeInject/java/net/fabricmc/loom/inject/mixin/ForgeLoomMixinRemapperInjectorService.java
@@ -0,0 +1,93 @@
+/*
+ * This file is part of fabric-loom, licensed under the MIT License (MIT).
+ *
+ * Copyright (c) 2016, 2017, 2018 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.inject.mixin;
+
+import java.io.BufferedReader;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+import java.util.Set;
+
+import cpw.mods.modlauncher.api.IEnvironment;
+import cpw.mods.modlauncher.api.ITransformationService;
+import cpw.mods.modlauncher.api.ITransformer;
+import cpw.mods.modlauncher.api.IncompatibleEnvironmentException;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.spongepowered.asm.mixin.MixinEnvironment;
+
+import net.fabricmc.mapping.tree.TinyMappingFactory;
+import net.fabricmc.mapping.tree.TinyTree;
+
+public class ForgeLoomMixinRemapperInjectorService implements ITransformationService {
+ private static final Logger LOGGER = LogManager.getLogger("ForgeLoomRemapperInjector");
+
+ @Override
+ public String name() {
+ return "ForgeLoomMixinRemapperInjector";
+ }
+
+ @Override
+ public void initialize(IEnvironment environment) {
+ }
+
+ @Override
+ public void beginScanning(IEnvironment environment) {
+ LOGGER.debug("We will be injecting our remapper.");
+
+ try {
+ MixinEnvironment.getDefaultEnvironment().getRemappers().add(new MixinIntermediaryDevRemapper(Objects.requireNonNull(resolveMappings()), "intermediary", "named"));
+ LOGGER.debug("We have successfully injected our remapper.");
+ } catch (Exception e) {
+ LOGGER.debug("We have failed to inject our remapper.", e);
+ }
+ }
+
+ @Override
+ public void onLoad(IEnvironment env, Set<String> otherServices) throws IncompatibleEnvironmentException {
+ }
+
+ @Override
+ public List<ITransformer> transformers() {
+ return Collections.emptyList();
+ }
+
+ private static TinyTree resolveMappings() {
+ try {
+ String srgNamedProperty = System.getProperty("mixin.forgeloom.inject.mappings.srg-named");
+ Path path = Paths.get(srgNamedProperty);
+
+ try (BufferedReader reader = Files.newBufferedReader(path)) {
+ return TinyMappingFactory.loadWithDetection(reader);
+ }
+ } catch (Throwable throwable) {
+ throwable.printStackTrace();
+ return null;
+ }
+ }
+}
diff --git a/src/forgeInject/java/net/fabricmc/loom/inject/mixin/MixinIntermediaryDevRemapper.java b/src/forgeInject/java/net/fabricmc/loom/inject/mixin/MixinIntermediaryDevRemapper.java
new file mode 100644
index 00000000..ef5724dc
--- /dev/null
+++ b/src/forgeInject/java/net/fabricmc/loom/inject/mixin/MixinIntermediaryDevRemapper.java
@@ -0,0 +1,233 @@
+/*
+ * Copyright 2016 FabricMC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.fabricmc.loom.inject.mixin;
+
+import java.util.ArrayDeque;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Queue;
+import java.util.Set;
+
+import org.spongepowered.asm.mixin.transformer.ClassInfo;
+
+import net.fabricmc.mapping.tree.ClassDef;
+import net.fabricmc.mapping.tree.Descriptored;
+import net.fabricmc.mapping.tree.TinyTree;
+import net.fabricmc.mapping.util.MixinRemapper;
+
+public class MixinIntermediaryDevRemapper extends MixinRemapper {
+ private static final String ambiguousName = "<ambiguous>"; // dummy value for ambiguous mappings - needs querying with additional owner and/or desc info
+
+ private final Set<String> allPossibleClassNames = new HashSet<>();
+ private final Map<String, String> nameFieldLookup = new HashMap<>();
+ private final Map<String, String> nameMethodLookup = new HashMap<>();
+ private final Map<String, String> nameDescFieldLookup = new HashMap<>();
+ private final Map<String, String> nameDescMethodLookup = new HashMap<>();
+
+ public MixinIntermediaryDevRemapper(TinyTree mappings, String from, String to) {
+ super(mappings, from, to);
+
+ for (ClassDef classDef : mappings.getClasses()) {
+ allPossibleClassNames.add(classDef.getName(from));
+ allPossibleClassNames.add(classDef.getName(to));
+
+ putMemberInLookup(from, to, classDef.getFields(), nameFieldLookup, nameDescFieldLookup);
+ putMemberInLookup(from, to, classDef.getMethods(), nameMethodLookup, nameDescMethodLookup);
+ }
+ }
+
+ private <T extends Descriptored> void putMemberInLookup(String from, String to, Collection<T> descriptored, Map<String, String> nameMap, Map<String, String> nameDescMap) {
+ for (T field : descriptored) {
+ String nameFrom = field.getName(from);
+ String descFrom = field.getDescriptor(from);
+ String nameTo = field.getName(to);
+
+ String prev = nameMap.putIfAbsent(nameFrom, nameTo);
+
+ if (prev != null && prev != ambiguousName && !prev.equals(nameTo)) {
+ nameDescMap.put(nameFrom, ambiguousName);
+ }
+
+ String key = getNameDescKey(nameFrom, descFrom);
+ prev = nameDescMap.putIfAbsent(key, nameTo);
+
+ if (prev != null && prev != ambiguousName && !prev.equals(nameTo)) {
+ nameDescMap.put(key, ambiguousName);
+ }
+ }
+ }
+
+ private void throwAmbiguousLookup(String type, String name, String desc) {
+ throw new RuntimeException("Ambiguous Mixin: " + type + " lookup " + name + " " + desc + " is not unique");
+ }
+
+ private String mapMethodNameInner(String owner, String name, String desc) {
+ String result = super.mapMethodName(owner, name, desc);
+
+ if (result.equals(name)) {
+ String otherClass = unmap(owner);
+ return super.mapMethodName(otherClass, name, unmapDesc(desc));
+ } else {
+ return result;
+ }
+ }
+
+ private String mapFieldNameInner(String owner, String name, String desc) {
+ String result = super.mapFieldName(owner, name, desc);
+
+ if (result.equals(name)) {
+ String otherClass = unmap(owner);
+ return super.mapFieldName(otherClass, name, unmapDesc(desc));
+ } else {
+ return result;
+ }
+ }
+
+ @Override
+ public String mapMethodName(String owner, String name, String desc) {
+ // handle unambiguous values early
+ if (owner == null || allPossibleClassNames.contains(owner)) {
+ String newName;
+
+ if (desc == null) {
+ newName = nameMethodLookup.get(name);
+ } else {
+ newName = nameDescMethodLookup.get(getNameDescKey(name, desc));
+ }
+
+ if (newName != null) {
+ if (newName == ambiguousName) {
+ if (owner == null) {
+ throwAmbiguousLookup("method", name, desc);
+ }
+ } else {
+ return newName;
+ }
+ } else if (owner == null) {
+ return name;
+ } else {
+ // FIXME: this kind of namespace mixing shouldn't happen..
+ // TODO: this should not repeat more than once
+ String unmapOwner = unmap(owner);
+ String unmapDesc = unmapDesc(desc);
+
+ if (!unmapOwner.equals(owner) || !unmapDesc.equals(desc)) {
+ return mapMethodName(unmapOwner, name, unmapDesc);
+ } else {
+ // take advantage of the fact allPossibleClassNames
+ // and nameDescLookup cover all sets; if none are present,
+ // we don't have a mapping for it.
+ return name;
+ }
+ }
+ }
+
+ Queue<ClassInfo> classInfos = new ArrayDeque<>();
+ classInfos.add(ClassInfo.forName(owner));
+
+ while (!classInfos.isEmpty()) {
+ ClassInfo c = classInfos.remove();
+ String ownerO = unmap(c.getName());
+ String s;
+
+ if (!(s = mapMethodNameInner(ownerO, name, desc)).equals(name)) {
+ return s;
+ }
+
+ if (!c.getSuperName().startsWith("java/")) {
+ ClassInfo cSuper = c.getSuperClass();
+
+ if (cSuper != null) {
+ classInfos.add(cSuper);
+ }
+ }
+
+ for (String itf : c.getInterfaces()) {
+ if (itf.startsWith("java/")) {
+ continue;
+ }
+
+ ClassInfo cItf = ClassInfo.forName(itf);
+
+ if (cItf != null) {
+ classInfos.add(cItf);
+ }
+ }
+ }
+
+ return name;
+ }
+
+ @Override
+ public String mapFieldName(String owner, String name, String desc) {
+ // handle unambiguous values early
+ if (owner == null || allPossibleClassNames.contains(owner)) {
+ String newName = nameDescFieldLookup.get(getNameDescKey(name, desc));
+
+ if (newName != null) {
+ if (newName == ambiguousName) {
+ if (owner == null) {
+ throwAmbiguousLookup("field", name, desc);
+ }
+ } else {
+ return newName;
+ }
+ } else if (owner == null) {
+ return name;
+ } else {
+ // FIXME: this kind of namespace mixing shouldn't happen..
+ // TODO: this should not repeat more than once
+ String unmapOwner = unmap(owner);
+ String unmapDesc = unmapDesc(desc);
+
+ if (!unmapOwner.equals(owner) || !unmapDesc.equals(desc)) {
+ return mapFieldName(unmapOwner, name, unmapDesc);
+ } else {
+ // take advantage of the fact allPossibleClassNames
+ // and nameDescLookup cover all sets; if none are present,
+ // we don't have a mapping for it.
+ return name;
+ }
+ }
+ }
+
+ ClassInfo c = ClassInfo.forName(map(owner));
+
+ while (c != null) {
+ String nextOwner = unmap(c.getName());
+ String s;
+
+ if (!(s = mapFieldNameInner(nextOwner, name, desc)).equals(name)) {
+ return s;
+ }
+
+ if (c.getSuperName().startsWith("java/")) {
+ break;
+ }
+
+ c = c.getSuperClass();
+ }
+
+ return name;
+ }
+
+ private static String getNameDescKey(String name, String descriptor) {
+ return name + ";;" + descriptor;
+ }
+}
diff --git a/src/forgeInject/resources/META-INF/services/cpw.mods.modlauncher.api.INameMappingService b/src/forgeInject/resources/META-INF/services/cpw.mods.modlauncher.api.INameMappingService
new file mode 100644
index 00000000..45290566
--- /dev/null
+++ b/src/forgeInject/resources/META-INF/services/cpw.mods.modlauncher.api.INameMappingService
@@ -0,0 +1 @@
+net.fabricmc.loom.inject.YarnNamingService
diff --git a/src/forgeInject/resources/META-INF/services/cpw.mods.modlauncher.api.ITransformationService b/src/forgeInject/resources/META-INF/services/cpw.mods.modlauncher.api.ITransformationService
new file mode 100644
index 00000000..0fb04144
--- /dev/null
+++ b/src/forgeInject/resources/META-INF/services/cpw.mods.modlauncher.api.ITransformationService
@@ -0,0 +1 @@
+net.fabricmc.loom.inject.mixin.ForgeLoomMixinRemapperInjectorService \ No newline at end of file