-
-
Notifications
You must be signed in to change notification settings - Fork 24
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Handle duplicate intermediary names in mapping
Fixes #567
- Loading branch information
Showing
3 changed files
with
85 additions
and
37 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
84 changes: 65 additions & 19 deletions
84
src/main/java/dev/su5ed/sinytra/connector/transformer/jar/IntermediateMapping.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,62 +1,108 @@ | ||
package dev.su5ed.sinytra.connector.transformer.jar; | ||
|
||
import com.mojang.datafixers.util.Pair; | ||
import com.mojang.logging.LogUtils; | ||
import net.fabricmc.loader.impl.FabricLoaderImpl; | ||
import net.fabricmc.loader.impl.MappingResolverImpl; | ||
import net.minecraftforge.srgutils.IMappingFile; | ||
import org.jetbrains.annotations.Nullable; | ||
import org.slf4j.Logger; | ||
|
||
import java.util.Collection; | ||
import java.util.HashMap; | ||
import java.util.HashSet; | ||
import java.util.Map; | ||
import java.util.Objects; | ||
import java.util.Set; | ||
import java.util.stream.Stream; | ||
|
||
import static dev.su5ed.sinytra.connector.transformer.jar.JarTransformer.TRANSFORM_MARKER; | ||
|
||
public class IntermediateMapping { | ||
private static final Map<String, Map<String, String>> INTERMEDIATE_MAPPINGS_CACHE = new HashMap<>(); | ||
private static final Map<String, IntermediateMapping> INTERMEDIATE_MAPPINGS_CACHE = new HashMap<>(); | ||
// Filter out non-obfuscated method names used in mapping namespaces as those don't need | ||
// to be remapped and will only cause issues with our barebones find/replace remapper | ||
private static final Map<String, Collection<String>> MAPPING_PREFIXES = Map.of( | ||
"intermediary", Set.of("net/minecraft/class_", "field_", "method_", "comp_") | ||
); | ||
private static final Logger LOGGER = LogUtils.getLogger(); | ||
|
||
public static Map<String, String> get(String sourceNamespace) { | ||
Map<String, String> map = INTERMEDIATE_MAPPINGS_CACHE.get(sourceNamespace); | ||
if (map == null) { | ||
// Original -> Mapped | ||
private final Map<String, String> mappings; | ||
// Original + Descriptor -> Mapped | ||
private final Map<String, String> extendedMappings; | ||
|
||
public static IntermediateMapping get(String sourceNamespace) { | ||
IntermediateMapping existing = INTERMEDIATE_MAPPINGS_CACHE.get(sourceNamespace); | ||
if (existing == null) { | ||
synchronized (JarTransformer.class) { | ||
Map<String, String> existing = INTERMEDIATE_MAPPINGS_CACHE.get(sourceNamespace); | ||
existing = INTERMEDIATE_MAPPINGS_CACHE.get(sourceNamespace); | ||
if (existing != null) { | ||
return existing; | ||
} | ||
|
||
LOGGER.debug(TRANSFORM_MARKER, "Creating flat intermediate mapping for namespace {}", sourceNamespace); | ||
// Intermediary sometimes contains duplicate names for different methods (why?). We exclude those. | ||
Set<String> excludedNames = new HashSet<>(); | ||
Collection<String> prefixes = MAPPING_PREFIXES.get(sourceNamespace); | ||
MappingResolverImpl resolver = FabricLoaderImpl.INSTANCE.getMappingResolver(); | ||
Map<String, String> resolved = new HashMap<>(); | ||
Map<String, String> extendedMappings = new HashMap<>(); | ||
resolver.getCurrentMap(sourceNamespace).getClasses().stream() | ||
.flatMap(cls -> Stream.concat(Stream.of(cls), Stream.concat(cls.getFields().stream(), cls.getMethods().stream())) | ||
.filter(node -> prefixes.stream().anyMatch(node.getOriginal()::startsWith)) | ||
.map(node -> Pair.of(node.getOriginal(), node.getMapped()))) | ||
.forEach(pair -> { | ||
String original = pair.getFirst(); | ||
if (resolved.containsKey(original)) { | ||
excludedNames.add(original); | ||
.filter(node -> prefixes.stream().anyMatch(node.getOriginal()::startsWith))) | ||
.forEach(node -> { | ||
String original = node.getOriginal(); | ||
String mapped = node.getMapped(); | ||
String mapping = resolved.get(original); | ||
if (mapping != null && !mapping.equals(mapped)) { | ||
extendedMappings.put(getMappingKey(node), mapped); | ||
resolved.remove(original); | ||
} | ||
if (!excludedNames.contains(original)) { | ||
resolved.put(original, pair.getSecond()); | ||
else if (!extendedMappings.containsKey(getMappingKey(node))) { | ||
resolved.put(original, mapped); | ||
} | ||
}); | ||
INTERMEDIATE_MAPPINGS_CACHE.put(sourceNamespace, resolved); | ||
return resolved; | ||
IntermediateMapping mapping = new IntermediateMapping(resolved, extendedMappings); | ||
INTERMEDIATE_MAPPINGS_CACHE.put(sourceNamespace, mapping); | ||
return mapping; | ||
} | ||
} | ||
return map; | ||
return existing; | ||
} | ||
|
||
private static String getMappingKey(IMappingFile.INode node) { | ||
if (node instanceof IMappingFile.IField field) { | ||
String desc = field.getDescriptor(); | ||
return field.getOriginal() + (desc != null ? ":" + desc : ""); | ||
} | ||
else if (node instanceof IMappingFile.IMethod method) { | ||
return method.getOriginal() + Objects.requireNonNullElse(method.getDescriptor(), ""); | ||
} | ||
return node.getOriginal(); | ||
} | ||
|
||
public IntermediateMapping(Map<String, String> mappings, Map<String, String> extendedMappings) { | ||
this.mappings = mappings; | ||
this.extendedMappings = extendedMappings; | ||
} | ||
|
||
public String map(String name) { | ||
return this.mappings.getOrDefault(name, name); | ||
} | ||
|
||
public String mapField(String name, @Nullable String desc) { | ||
String mapped = this.mappings.get(name); | ||
if (mapped == null) { | ||
String qualifier = name + ":" + desc; | ||
mapped = this.extendedMappings.get(qualifier); | ||
} | ||
return mapped != null ? mapped : name; | ||
} | ||
|
||
public String mapMethod(String name, String desc) { | ||
String mapped = this.mappings.get(name); | ||
if (mapped == null) { | ||
String qualifier = name + desc; | ||
mapped = this.extendedMappings.get(qualifier); | ||
} | ||
return mapped != null ? mapped : name; | ||
} | ||
} |