diff options
| author | 2019-01-30 21:05:32 +0200 | |
|---|---|---|
| committer | 2019-01-30 21:05:32 +0200 | |
| commit | ba7a354efae7d49833c887cf147ac940c975a1fa (patch) | |
| tree | 02e14fda81dd5984e24f2df392c57c6e829fc875 /src/main/java/cuchaz/enigma/translation/mapping | |
| parent | Rewrite the Jenkinsfile to use the new declarative pipeline syntax, lets hope... (diff) | |
| download | enigma-fork-ba7a354efae7d49833c887cf147ac940c975a1fa.tar.gz enigma-fork-ba7a354efae7d49833c887cf147ac940c975a1fa.tar.xz enigma-fork-ba7a354efae7d49833c887cf147ac940c975a1fa.zip | |
Remap sources (#106)
* Source remapping beginnings
* Fix navigation to remapped classes
* Translate identifier info reference
* Remap local variables with default names in source
* Caching translator
* Fix lack of highlighting for first opened class
* Fix unicode variable names
* Unicode checker shouldn't be checking just alphanumeric
* Fix package tree being built from obf names
* Don't index `this` as method call for method::reference
* Apply proposed names
* Fix source export issues
* Replace unicode var names at bytecode level uniquely
* Drop imports from editor source
* Class selector fixes
* Delta keep track of base mappings to enable lookup of old names
* Optimize source remapping by remapping source with a StringBuffer instead of copying
* Bump version
Diffstat (limited to 'src/main/java/cuchaz/enigma/translation/mapping')
10 files changed, 101 insertions, 155 deletions
diff --git a/src/main/java/cuchaz/enigma/translation/mapping/EntryRemapper.java b/src/main/java/cuchaz/enigma/translation/mapping/EntryRemapper.java index b7d8d17..1203aba 100644 --- a/src/main/java/cuchaz/enigma/translation/mapping/EntryRemapper.java +++ b/src/main/java/cuchaz/enigma/translation/mapping/EntryRemapper.java | |||
| @@ -6,7 +6,6 @@ import cuchaz.enigma.translation.Translatable; | |||
| 6 | import cuchaz.enigma.translation.Translator; | 6 | import cuchaz.enigma.translation.Translator; |
| 7 | import cuchaz.enigma.translation.mapping.tree.DeltaTrackingTree; | 7 | import cuchaz.enigma.translation.mapping.tree.DeltaTrackingTree; |
| 8 | import cuchaz.enigma.translation.mapping.tree.EntryTree; | 8 | import cuchaz.enigma.translation.mapping.tree.EntryTree; |
| 9 | import cuchaz.enigma.translation.mapping.tree.EntryTreeNode; | ||
| 10 | import cuchaz.enigma.translation.mapping.tree.HashEntryTree; | 9 | import cuchaz.enigma.translation.mapping.tree.HashEntryTree; |
| 11 | import cuchaz.enigma.translation.representation.entry.Entry; | 10 | import cuchaz.enigma.translation.representation.entry.Entry; |
| 12 | 11 | ||
| @@ -14,59 +13,25 @@ import javax.annotation.Nullable; | |||
| 14 | import java.util.Collection; | 13 | import java.util.Collection; |
| 15 | 14 | ||
| 16 | public class EntryRemapper { | 15 | public class EntryRemapper { |
| 17 | private final EntryTree<EntryMapping> obfToDeobf; | 16 | private final DeltaTrackingTree<EntryMapping> obfToDeobf; |
| 18 | private final DeltaTrackingTree<EntryMapping> deobfToObf; | ||
| 19 | |||
| 20 | private final JarIndex obfIndex; | ||
| 21 | 17 | ||
| 22 | private final EntryResolver obfResolver; | 18 | private final EntryResolver obfResolver; |
| 23 | private EntryResolver deobfResolver; | ||
| 24 | |||
| 25 | private final Translator deobfuscator; | 19 | private final Translator deobfuscator; |
| 26 | private Translator obfuscator; | ||
| 27 | 20 | ||
| 28 | private final MappingValidator validator; | 21 | private final MappingValidator validator; |
| 29 | 22 | ||
| 30 | private EntryRemapper(JarIndex jarIndex, EntryTree<EntryMapping> obfToDeobf, EntryTree<EntryMapping> deobfToObf) { | 23 | public EntryRemapper(JarIndex jarIndex, EntryTree<EntryMapping> obfToDeobf) { |
| 31 | this.obfToDeobf = obfToDeobf; | 24 | this.obfToDeobf = new DeltaTrackingTree<>(obfToDeobf); |
| 32 | this.deobfToObf = new DeltaTrackingTree<>(deobfToObf); | ||
| 33 | 25 | ||
| 34 | this.obfIndex = jarIndex; | ||
| 35 | this.obfResolver = jarIndex.getEntryResolver(); | 26 | this.obfResolver = jarIndex.getEntryResolver(); |
| 36 | 27 | ||
| 37 | this.deobfuscator = new MappingTranslator(obfToDeobf, obfResolver); | 28 | this.deobfuscator = new MappingTranslator(obfToDeobf, obfResolver); |
| 38 | rebuildDeobfIndex(); | ||
| 39 | 29 | ||
| 40 | this.validator = new MappingValidator(this.deobfToObf, deobfuscator, obfResolver); | 30 | this.validator = new MappingValidator(obfToDeobf, deobfuscator, obfResolver); |
| 41 | } | 31 | } |
| 42 | 32 | ||
| 43 | public EntryRemapper(JarIndex jarIndex) { | 33 | public EntryRemapper(JarIndex jarIndex) { |
| 44 | this(jarIndex, new HashEntryTree<>(), new HashEntryTree<>()); | 34 | this(jarIndex, new HashEntryTree<>()); |
| 45 | } | ||
| 46 | |||
| 47 | public EntryRemapper(JarIndex jarIndex, EntryTree<EntryMapping> deobfuscationTrees) { | ||
| 48 | this(jarIndex, deobfuscationTrees, inverse(deobfuscationTrees)); | ||
| 49 | } | ||
| 50 | |||
| 51 | private static EntryTree<EntryMapping> inverse(EntryTree<EntryMapping> tree) { | ||
| 52 | Translator translator = new MappingTranslator(tree, VoidEntryResolver.INSTANCE); | ||
| 53 | EntryTree<EntryMapping> inverse = new HashEntryTree<>(); | ||
| 54 | |||
| 55 | // Naive approach, could operate on the nodes of the tree. However, this runs infrequently. | ||
| 56 | Collection<Entry<?>> entries = tree.getAllEntries(); | ||
| 57 | for (Entry<?> sourceEntry : entries) { | ||
| 58 | Entry<?> targetEntry = translator.translate(sourceEntry); | ||
| 59 | inverse.insert(targetEntry, new EntryMapping(sourceEntry.getName())); | ||
| 60 | } | ||
| 61 | |||
| 62 | return inverse; | ||
| 63 | } | ||
| 64 | |||
| 65 | private void rebuildDeobfIndex() { | ||
| 66 | JarIndex deobfIndex = obfIndex.remapped(deobfuscator); | ||
| 67 | |||
| 68 | this.deobfResolver = deobfIndex.getEntryResolver(); | ||
| 69 | this.obfuscator = new MappingTranslator(deobfToObf, deobfResolver); | ||
| 70 | } | 35 | } |
| 71 | 36 | ||
| 72 | public <E extends Entry<?>> void mapFromObf(E obfuscatedEntry, @Nullable EntryMapping deobfMapping) { | 37 | public <E extends Entry<?>> void mapFromObf(E obfuscatedEntry, @Nullable EntryMapping deobfMapping) { |
| @@ -76,84 +41,31 @@ public class EntryRemapper { | |||
| 76 | validator.validateRename(resolvedEntry, deobfMapping.getTargetName()); | 41 | validator.validateRename(resolvedEntry, deobfMapping.getTargetName()); |
| 77 | } | 42 | } |
| 78 | 43 | ||
| 79 | setObfToDeobf(resolvedEntry, deobfMapping); | 44 | obfToDeobf.insert(obfuscatedEntry, deobfMapping); |
| 80 | } | 45 | } |
| 81 | |||
| 82 | // Temporary hack, not very performant | ||
| 83 | rebuildDeobfIndex(); | ||
| 84 | } | ||
| 85 | |||
| 86 | public <E extends Entry<?>> void mapFromDeobf(E deobfuscatedEntry, @Nullable EntryMapping deobfMapping) { | ||
| 87 | E obfuscatedEntry = obfuscate(deobfuscatedEntry); | ||
| 88 | mapFromObf(obfuscatedEntry, deobfMapping); | ||
| 89 | } | 46 | } |
| 90 | 47 | ||
| 91 | public void removeByObf(Entry<?> obfuscatedEntry) { | 48 | public void removeByObf(Entry<?> obfuscatedEntry) { |
| 92 | mapFromObf(obfuscatedEntry, null); | 49 | mapFromObf(obfuscatedEntry, null); |
| 93 | } | 50 | } |
| 94 | 51 | ||
| 95 | public void removeByDeobf(Entry<?> deobfuscatedEntry) { | ||
| 96 | mapFromObf(obfuscate(deobfuscatedEntry), null); | ||
| 97 | } | ||
| 98 | |||
| 99 | private <E extends Entry<?>> void setObfToDeobf(E obfuscatedEntry, @Nullable EntryMapping deobfMapping) { | ||
| 100 | E prevDeobf = deobfuscate(obfuscatedEntry); | ||
| 101 | obfToDeobf.insert(obfuscatedEntry, deobfMapping); | ||
| 102 | |||
| 103 | E newDeobf = deobfuscate(obfuscatedEntry); | ||
| 104 | |||
| 105 | // Reconstruct the children of this node in the deobf -> obf tree with our new mapping | ||
| 106 | // We only need to do this for deobf -> obf because the obf tree is always consistent on the left hand side | ||
| 107 | // We lookup by obf, and the obf never changes. This is not the case for deobf so we need to update the tree. | ||
| 108 | |||
| 109 | EntryTreeNode<EntryMapping> node = deobfToObf.findNode(prevDeobf); | ||
| 110 | if (node != null) { | ||
| 111 | for (EntryTreeNode<EntryMapping> child : node.getNodesRecursively()) { | ||
| 112 | Entry<?> entry = child.getEntry(); | ||
| 113 | EntryMapping mapping = new EntryMapping(obfuscate(entry).getName()); | ||
| 114 | |||
| 115 | deobfToObf.insert(entry.replaceAncestor(prevDeobf, newDeobf), mapping); | ||
| 116 | deobfToObf.remove(entry); | ||
| 117 | } | ||
| 118 | } else { | ||
| 119 | deobfToObf.insert(newDeobf, new EntryMapping(obfuscatedEntry.getName())); | ||
| 120 | } | ||
| 121 | } | ||
| 122 | |||
| 123 | @Nullable | 52 | @Nullable |
| 124 | public EntryMapping getDeobfMapping(Entry<?> entry) { | 53 | public EntryMapping getDeobfMapping(Entry<?> entry) { |
| 125 | return obfToDeobf.get(entry); | 54 | return obfToDeobf.get(entry); |
| 126 | } | 55 | } |
| 127 | 56 | ||
| 128 | @Nullable | ||
| 129 | public EntryMapping getObfMapping(Entry<?> entry) { | ||
| 130 | return deobfToObf.get(entry); | ||
| 131 | } | ||
| 132 | |||
| 133 | public boolean hasDeobfMapping(Entry<?> obfEntry) { | 57 | public boolean hasDeobfMapping(Entry<?> obfEntry) { |
| 134 | return obfToDeobf.contains(obfEntry); | 58 | return obfToDeobf.contains(obfEntry); |
| 135 | } | 59 | } |
| 136 | 60 | ||
| 137 | public boolean hasObfMapping(Entry<?> deobfEntry) { | ||
| 138 | return deobfToObf.contains(deobfEntry); | ||
| 139 | } | ||
| 140 | |||
| 141 | public <T extends Translatable> T deobfuscate(T translatable) { | 61 | public <T extends Translatable> T deobfuscate(T translatable) { |
| 142 | return deobfuscator.translate(translatable); | 62 | return deobfuscator.translate(translatable); |
| 143 | } | 63 | } |
| 144 | 64 | ||
| 145 | public <T extends Translatable> T obfuscate(T translatable) { | ||
| 146 | return obfuscator.translate(translatable); | ||
| 147 | } | ||
| 148 | |||
| 149 | public Translator getDeobfuscator() { | 65 | public Translator getDeobfuscator() { |
| 150 | return deobfuscator; | 66 | return deobfuscator; |
| 151 | } | 67 | } |
| 152 | 68 | ||
| 153 | public Translator getObfuscator() { | ||
| 154 | return obfuscator; | ||
| 155 | } | ||
| 156 | |||
| 157 | public Collection<Entry<?>> getObfEntries() { | 69 | public Collection<Entry<?>> getObfEntries() { |
| 158 | return obfToDeobf.getAllEntries(); | 70 | return obfToDeobf.getAllEntries(); |
| 159 | } | 71 | } |
| @@ -162,40 +74,23 @@ public class EntryRemapper { | |||
| 162 | return obfToDeobf.getRootEntries(); | 74 | return obfToDeobf.getRootEntries(); |
| 163 | } | 75 | } |
| 164 | 76 | ||
| 165 | public Collection<Entry<?>> getDeobfEntries() { | ||
| 166 | return deobfToObf.getAllEntries(); | ||
| 167 | } | ||
| 168 | |||
| 169 | public Collection<Entry<?>> getObfChildren(Entry<?> obfuscatedEntry) { | 77 | public Collection<Entry<?>> getObfChildren(Entry<?> obfuscatedEntry) { |
| 170 | return obfToDeobf.getChildren(obfuscatedEntry); | 78 | return obfToDeobf.getChildren(obfuscatedEntry); |
| 171 | } | 79 | } |
| 172 | 80 | ||
| 173 | public Collection<Entry<?>> getDeobfChildren(Entry<?> deobfuscatedEntry) { | 81 | public DeltaTrackingTree<EntryMapping> getObfToDeobf() { |
| 174 | return deobfToObf.getChildren(deobfuscatedEntry); | ||
| 175 | } | ||
| 176 | |||
| 177 | public EntryTree<EntryMapping> getObfToDeobf() { | ||
| 178 | return obfToDeobf; | 82 | return obfToDeobf; |
| 179 | } | 83 | } |
| 180 | 84 | ||
| 181 | public DeltaTrackingTree<EntryMapping> getDeobfToObf() { | 85 | public MappingDelta<EntryMapping> takeMappingDelta() { |
| 182 | return deobfToObf; | 86 | return obfToDeobf.takeDelta(); |
| 183 | } | ||
| 184 | |||
| 185 | public MappingDelta takeMappingDelta() { | ||
| 186 | MappingDelta delta = deobfToObf.takeDelta(); | ||
| 187 | return delta.translate(obfuscator, VoidEntryResolver.INSTANCE, deobfToObf); | ||
| 188 | } | 87 | } |
| 189 | 88 | ||
| 190 | public boolean isDirty() { | 89 | public boolean isDirty() { |
| 191 | return deobfToObf.isDirty(); | 90 | return obfToDeobf.isDirty(); |
| 192 | } | 91 | } |
| 193 | 92 | ||
| 194 | public EntryResolver getObfResolver() { | 93 | public EntryResolver getObfResolver() { |
| 195 | return obfResolver; | 94 | return obfResolver; |
| 196 | } | 95 | } |
| 197 | |||
| 198 | public EntryResolver getDeobfResolver() { | ||
| 199 | return deobfResolver; | ||
| 200 | } | ||
| 201 | } | 96 | } |
diff --git a/src/main/java/cuchaz/enigma/translation/mapping/MappingDelta.java b/src/main/java/cuchaz/enigma/translation/mapping/MappingDelta.java index 4fba49d..9f1f468 100644 --- a/src/main/java/cuchaz/enigma/translation/mapping/MappingDelta.java +++ b/src/main/java/cuchaz/enigma/translation/mapping/MappingDelta.java | |||
| @@ -6,28 +6,35 @@ import cuchaz.enigma.translation.mapping.tree.HashEntryTree; | |||
| 6 | import cuchaz.enigma.translation.mapping.tree.EntryTree; | 6 | import cuchaz.enigma.translation.mapping.tree.EntryTree; |
| 7 | import cuchaz.enigma.translation.representation.entry.Entry; | 7 | import cuchaz.enigma.translation.representation.entry.Entry; |
| 8 | 8 | ||
| 9 | public class MappingDelta implements Translatable { | 9 | public class MappingDelta<T> implements Translatable { |
| 10 | public static final Object PLACEHOLDER = new Object(); | 10 | public static final Object PLACEHOLDER = new Object(); |
| 11 | 11 | ||
| 12 | private final EntryTree<T> baseMappings; | ||
| 13 | |||
| 12 | private final EntryTree<Object> additions; | 14 | private final EntryTree<Object> additions; |
| 13 | private final EntryTree<Object> deletions; | 15 | private final EntryTree<Object> deletions; |
| 14 | 16 | ||
| 15 | public MappingDelta(EntryTree<Object> additions, EntryTree<Object> deletions) { | 17 | public MappingDelta(EntryTree<T> baseMappings, EntryTree<Object> additions, EntryTree<Object> deletions) { |
| 18 | this.baseMappings = baseMappings; | ||
| 16 | this.additions = additions; | 19 | this.additions = additions; |
| 17 | this.deletions = deletions; | 20 | this.deletions = deletions; |
| 18 | } | 21 | } |
| 19 | 22 | ||
| 20 | public MappingDelta() { | 23 | public MappingDelta(EntryTree<T> baseMappings) { |
| 21 | this(new HashEntryTree<>(), new HashEntryTree<>()); | 24 | this(baseMappings, new HashEntryTree<>(), new HashEntryTree<>()); |
| 22 | } | 25 | } |
| 23 | 26 | ||
| 24 | public static MappingDelta added(EntryTree<EntryMapping> mappings) { | 27 | public static <T> MappingDelta<T> added(EntryTree<T> mappings) { |
| 25 | EntryTree<Object> additions = new HashEntryTree<>(); | 28 | EntryTree<Object> additions = new HashEntryTree<>(); |
| 26 | for (Entry<?> entry : mappings.getAllEntries()) { | 29 | for (Entry<?> entry : mappings.getAllEntries()) { |
| 27 | additions.insert(entry, PLACEHOLDER); | 30 | additions.insert(entry, PLACEHOLDER); |
| 28 | } | 31 | } |
| 29 | 32 | ||
| 30 | return new MappingDelta(additions, new HashEntryTree<>()); | 33 | return new MappingDelta<>(new HashEntryTree<>(), additions, new HashEntryTree<>()); |
| 34 | } | ||
| 35 | |||
| 36 | public EntryTree<T> getBaseMappings() { | ||
| 37 | return baseMappings; | ||
| 31 | } | 38 | } |
| 32 | 39 | ||
| 33 | public EntryTree<?> getAdditions() { | 40 | public EntryTree<?> getAdditions() { |
| @@ -39,18 +46,11 @@ public class MappingDelta implements Translatable { | |||
| 39 | } | 46 | } |
| 40 | 47 | ||
| 41 | @Override | 48 | @Override |
| 42 | public MappingDelta translate(Translator translator, EntryResolver resolver, EntryMap<EntryMapping> mappings) { | 49 | public MappingDelta<T> translate(Translator translator, EntryResolver resolver, EntryMap<EntryMapping> mappings) { |
| 43 | return new MappingDelta( | 50 | return new MappingDelta<>( |
| 44 | translate(translator, additions), | 51 | translator.translate(baseMappings), |
| 45 | translate(translator, deletions) | 52 | translator.translate(additions), |
| 53 | translator.translate(deletions) | ||
| 46 | ); | 54 | ); |
| 47 | } | 55 | } |
| 48 | |||
| 49 | private EntryTree<Object> translate(Translator translator, EntryTree<Object> tree) { | ||
| 50 | EntryTree<Object> translatedTree = new HashEntryTree<>(); | ||
| 51 | for (Entry<?> entry : tree.getAllEntries()) { | ||
| 52 | translatedTree.insert(translator.translate(entry), PLACEHOLDER); | ||
| 53 | } | ||
| 54 | return translatedTree; | ||
| 55 | } | ||
| 56 | } | 56 | } |
diff --git a/src/main/java/cuchaz/enigma/translation/mapping/MappingValidator.java b/src/main/java/cuchaz/enigma/translation/mapping/MappingValidator.java index 422bf38..9be48c3 100644 --- a/src/main/java/cuchaz/enigma/translation/mapping/MappingValidator.java +++ b/src/main/java/cuchaz/enigma/translation/mapping/MappingValidator.java | |||
| @@ -6,14 +6,15 @@ import cuchaz.enigma.translation.mapping.tree.EntryTree; | |||
| 6 | import cuchaz.enigma.translation.representation.entry.Entry; | 6 | import cuchaz.enigma.translation.representation.entry.Entry; |
| 7 | 7 | ||
| 8 | import java.util.Collection; | 8 | import java.util.Collection; |
| 9 | import java.util.stream.Collectors; | ||
| 9 | 10 | ||
| 10 | public class MappingValidator { | 11 | public class MappingValidator { |
| 11 | private final EntryTree<EntryMapping> deobfToObf; | 12 | private final EntryTree<EntryMapping> obfToDeobf; |
| 12 | private final Translator deobfuscator; | 13 | private final Translator deobfuscator; |
| 13 | private final EntryResolver entryResolver; | 14 | private final EntryResolver entryResolver; |
| 14 | 15 | ||
| 15 | public MappingValidator(EntryTree<EntryMapping> deobfToObf, Translator deobfuscator, EntryResolver entryResolver) { | 16 | public MappingValidator(EntryTree<EntryMapping> obfToDeobf, Translator deobfuscator, EntryResolver entryResolver) { |
| 16 | this.deobfToObf = deobfToObf; | 17 | this.obfToDeobf = obfToDeobf; |
| 17 | this.deobfuscator = deobfuscator; | 18 | this.deobfuscator = deobfuscator; |
| 18 | this.entryResolver = entryResolver; | 19 | this.entryResolver = entryResolver; |
| 19 | } | 20 | } |
| @@ -28,8 +29,11 @@ public class MappingValidator { | |||
| 28 | 29 | ||
| 29 | private void validateUnique(Entry<?> entry, String name) { | 30 | private void validateUnique(Entry<?> entry, String name) { |
| 30 | Entry<?> translatedEntry = deobfuscator.translate(entry); | 31 | Entry<?> translatedEntry = deobfuscator.translate(entry); |
| 31 | Collection<Entry<?>> siblings = deobfToObf.getSiblings(translatedEntry); | 32 | Collection<Entry<?>> translatedSiblings = obfToDeobf.getSiblings(entry).stream() |
| 32 | if (!isUnique(translatedEntry, siblings, name)) { | 33 | .map(deobfuscator::translate) |
| 34 | .collect(Collectors.toList()); | ||
| 35 | |||
| 36 | if (!isUnique(translatedEntry, translatedSiblings, name)) { | ||
| 33 | throw new IllegalNameException(name, "Name is not unique in " + translatedEntry.getParent() + "!"); | 37 | throw new IllegalNameException(name, "Name is not unique in " + translatedEntry.getParent() + "!"); |
| 34 | } | 38 | } |
| 35 | } | 39 | } |
diff --git a/src/main/java/cuchaz/enigma/translation/mapping/serde/EnigmaMappingsWriter.java b/src/main/java/cuchaz/enigma/translation/mapping/serde/EnigmaMappingsWriter.java index 5acb1da..1d44b6e 100644 --- a/src/main/java/cuchaz/enigma/translation/mapping/serde/EnigmaMappingsWriter.java +++ b/src/main/java/cuchaz/enigma/translation/mapping/serde/EnigmaMappingsWriter.java | |||
| @@ -14,10 +14,7 @@ package cuchaz.enigma.translation.mapping.serde; | |||
| 14 | import cuchaz.enigma.ProgressListener; | 14 | import cuchaz.enigma.ProgressListener; |
| 15 | import cuchaz.enigma.translation.MappingTranslator; | 15 | import cuchaz.enigma.translation.MappingTranslator; |
| 16 | import cuchaz.enigma.translation.Translator; | 16 | import cuchaz.enigma.translation.Translator; |
| 17 | import cuchaz.enigma.translation.mapping.AccessModifier; | 17 | import cuchaz.enigma.translation.mapping.*; |
| 18 | import cuchaz.enigma.translation.mapping.EntryMapping; | ||
| 19 | import cuchaz.enigma.translation.mapping.MappingDelta; | ||
| 20 | import cuchaz.enigma.translation.mapping.VoidEntryResolver; | ||
| 21 | import cuchaz.enigma.translation.mapping.tree.EntryTree; | 18 | import cuchaz.enigma.translation.mapping.tree.EntryTree; |
| 22 | import cuchaz.enigma.translation.mapping.tree.EntryTreeNode; | 19 | import cuchaz.enigma.translation.mapping.tree.EntryTreeNode; |
| 23 | import cuchaz.enigma.translation.representation.entry.*; | 20 | import cuchaz.enigma.translation.representation.entry.*; |
| @@ -37,7 +34,7 @@ import java.util.stream.Collectors; | |||
| 37 | public enum EnigmaMappingsWriter implements MappingsWriter { | 34 | public enum EnigmaMappingsWriter implements MappingsWriter { |
| 38 | FILE { | 35 | FILE { |
| 39 | @Override | 36 | @Override |
| 40 | public void write(EntryTree<EntryMapping> mappings, MappingDelta delta, Path path, ProgressListener progress) { | 37 | public void write(EntryTree<EntryMapping> mappings, MappingDelta<EntryMapping> delta, Path path, ProgressListener progress) { |
| 41 | Collection<ClassEntry> classes = mappings.getRootEntries().stream() | 38 | Collection<ClassEntry> classes = mappings.getRootEntries().stream() |
| 42 | .filter(entry -> entry instanceof ClassEntry) | 39 | .filter(entry -> entry instanceof ClassEntry) |
| 43 | .map(entry -> (ClassEntry) entry) | 40 | .map(entry -> (ClassEntry) entry) |
| @@ -58,8 +55,8 @@ public enum EnigmaMappingsWriter implements MappingsWriter { | |||
| 58 | }, | 55 | }, |
| 59 | DIRECTORY { | 56 | DIRECTORY { |
| 60 | @Override | 57 | @Override |
| 61 | public void write(EntryTree<EntryMapping> mappings, MappingDelta delta, Path path, ProgressListener progress) { | 58 | public void write(EntryTree<EntryMapping> mappings, MappingDelta<EntryMapping> delta, Path path, ProgressListener progress) { |
| 62 | applyDeletions(delta.getDeletions(), path); | 59 | applyDeletions(delta.getBaseMappings(), delta.getDeletions(), path); |
| 63 | 60 | ||
| 64 | Collection<ClassEntry> classes = delta.getAdditions().getRootEntries().stream() | 61 | Collection<ClassEntry> classes = delta.getAdditions().getRootEntries().stream() |
| 65 | .filter(entry -> entry instanceof ClassEntry) | 62 | .filter(entry -> entry instanceof ClassEntry) |
| @@ -76,8 +73,8 @@ public enum EnigmaMappingsWriter implements MappingsWriter { | |||
| 76 | 73 | ||
| 77 | try { | 74 | try { |
| 78 | Path classPath = resolve(path, translator.translate(classEntry)); | 75 | Path classPath = resolve(path, translator.translate(classEntry)); |
| 79 | Files.deleteIfExists(classPath); | ||
| 80 | Files.createDirectories(classPath.getParent()); | 76 | Files.createDirectories(classPath.getParent()); |
| 77 | Files.deleteIfExists(classPath); | ||
| 81 | 78 | ||
| 82 | try (PrintWriter writer = new LFPrintWriter(Files.newBufferedWriter(classPath))) { | 79 | try (PrintWriter writer = new LFPrintWriter(Files.newBufferedWriter(classPath))) { |
| 83 | writeRoot(writer, mappings, classEntry); | 80 | writeRoot(writer, mappings, classEntry); |
| @@ -89,10 +86,12 @@ public enum EnigmaMappingsWriter implements MappingsWriter { | |||
| 89 | }); | 86 | }); |
| 90 | } | 87 | } |
| 91 | 88 | ||
| 92 | private void applyDeletions(EntryTree<?> deletions, Path root) { | 89 | private void applyDeletions(EntryTree<EntryMapping> baseMappings, EntryTree<?> deletions, Path root) { |
| 90 | Translator oldMappingTranslator = new MappingTranslator(baseMappings, VoidEntryResolver.INSTANCE); | ||
| 91 | |||
| 93 | Collection<ClassEntry> deletedClasses = deletions.getRootEntries().stream() | 92 | Collection<ClassEntry> deletedClasses = deletions.getRootEntries().stream() |
| 94 | .filter(e -> e instanceof ClassEntry) | 93 | .filter(e -> e instanceof ClassEntry) |
| 95 | .map(e -> (ClassEntry) e) | 94 | .map(e -> oldMappingTranslator.translate((ClassEntry) e)) |
| 96 | .collect(Collectors.toList()); | 95 | .collect(Collectors.toList()); |
| 97 | 96 | ||
| 98 | for (ClassEntry classEntry : deletedClasses) { | 97 | for (ClassEntry classEntry : deletedClasses) { |
diff --git a/src/main/java/cuchaz/enigma/translation/mapping/serde/MappingFormat.java b/src/main/java/cuchaz/enigma/translation/mapping/serde/MappingFormat.java index 4db1645..622a0e1 100644 --- a/src/main/java/cuchaz/enigma/translation/mapping/serde/MappingFormat.java +++ b/src/main/java/cuchaz/enigma/translation/mapping/serde/MappingFormat.java | |||
| @@ -28,7 +28,7 @@ public enum MappingFormat { | |||
| 28 | write(mappings, MappingDelta.added(mappings), path, progressListener); | 28 | write(mappings, MappingDelta.added(mappings), path, progressListener); |
| 29 | } | 29 | } |
| 30 | 30 | ||
| 31 | public void write(EntryTree<EntryMapping> mappings, MappingDelta delta, Path path, ProgressListener progressListener) { | 31 | public void write(EntryTree<EntryMapping> mappings, MappingDelta<EntryMapping> delta, Path path, ProgressListener progressListener) { |
| 32 | if (writer == null) { | 32 | if (writer == null) { |
| 33 | throw new IllegalStateException(name() + " does not support writing"); | 33 | throw new IllegalStateException(name() + " does not support writing"); |
| 34 | } | 34 | } |
diff --git a/src/main/java/cuchaz/enigma/translation/mapping/serde/MappingsWriter.java b/src/main/java/cuchaz/enigma/translation/mapping/serde/MappingsWriter.java index b519668..77f6ee0 100644 --- a/src/main/java/cuchaz/enigma/translation/mapping/serde/MappingsWriter.java +++ b/src/main/java/cuchaz/enigma/translation/mapping/serde/MappingsWriter.java | |||
| @@ -8,5 +8,9 @@ import cuchaz.enigma.translation.mapping.tree.EntryTree; | |||
| 8 | import java.nio.file.Path; | 8 | import java.nio.file.Path; |
| 9 | 9 | ||
| 10 | public interface MappingsWriter { | 10 | public interface MappingsWriter { |
| 11 | void write(EntryTree<EntryMapping> mappings, MappingDelta delta, Path path, ProgressListener progress); | 11 | void write(EntryTree<EntryMapping> mappings, MappingDelta<EntryMapping> delta, Path path, ProgressListener progress); |
| 12 | |||
| 13 | default void write(EntryTree<EntryMapping> mappings, Path path, ProgressListener progress) { | ||
| 14 | write(mappings, MappingDelta.added(mappings), path, progress); | ||
| 15 | } | ||
| 12 | } | 16 | } |
diff --git a/src/main/java/cuchaz/enigma/translation/mapping/serde/SrgMappingsWriter.java b/src/main/java/cuchaz/enigma/translation/mapping/serde/SrgMappingsWriter.java index 5ff9141..40be136 100644 --- a/src/main/java/cuchaz/enigma/translation/mapping/serde/SrgMappingsWriter.java +++ b/src/main/java/cuchaz/enigma/translation/mapping/serde/SrgMappingsWriter.java | |||
| @@ -29,7 +29,7 @@ public enum SrgMappingsWriter implements MappingsWriter { | |||
| 29 | INSTANCE; | 29 | INSTANCE; |
| 30 | 30 | ||
| 31 | @Override | 31 | @Override |
| 32 | public void write(EntryTree<EntryMapping> mappings, MappingDelta delta, Path path, ProgressListener progress) { | 32 | public void write(EntryTree<EntryMapping> mappings, MappingDelta<EntryMapping> delta, Path path, ProgressListener progress) { |
| 33 | try { | 33 | try { |
| 34 | Files.deleteIfExists(path); | 34 | Files.deleteIfExists(path); |
| 35 | Files.createFile(path); | 35 | Files.createFile(path); |
diff --git a/src/main/java/cuchaz/enigma/translation/mapping/tree/DeltaTrackingTree.java b/src/main/java/cuchaz/enigma/translation/mapping/tree/DeltaTrackingTree.java index 98a01df..36be5e1 100644 --- a/src/main/java/cuchaz/enigma/translation/mapping/tree/DeltaTrackingTree.java +++ b/src/main/java/cuchaz/enigma/translation/mapping/tree/DeltaTrackingTree.java | |||
| @@ -1,5 +1,9 @@ | |||
| 1 | package cuchaz.enigma.translation.mapping.tree; | 1 | package cuchaz.enigma.translation.mapping.tree; |
| 2 | 2 | ||
| 3 | import cuchaz.enigma.translation.Translator; | ||
| 4 | import cuchaz.enigma.translation.mapping.EntryMap; | ||
| 5 | import cuchaz.enigma.translation.mapping.EntryMapping; | ||
| 6 | import cuchaz.enigma.translation.mapping.EntryResolver; | ||
| 3 | import cuchaz.enigma.translation.mapping.MappingDelta; | 7 | import cuchaz.enigma.translation.mapping.MappingDelta; |
| 4 | import cuchaz.enigma.translation.representation.entry.Entry; | 8 | import cuchaz.enigma.translation.representation.entry.Entry; |
| 5 | 9 | ||
| @@ -10,11 +14,13 @@ import java.util.Iterator; | |||
| 10 | public class DeltaTrackingTree<T> implements EntryTree<T> { | 14 | public class DeltaTrackingTree<T> implements EntryTree<T> { |
| 11 | private final EntryTree<T> delegate; | 15 | private final EntryTree<T> delegate; |
| 12 | 16 | ||
| 17 | private EntryTree<T> deltaReference; | ||
| 13 | private EntryTree<Object> additions = new HashEntryTree<>(); | 18 | private EntryTree<Object> additions = new HashEntryTree<>(); |
| 14 | private EntryTree<Object> deletions = new HashEntryTree<>(); | 19 | private EntryTree<Object> deletions = new HashEntryTree<>(); |
| 15 | 20 | ||
| 16 | public DeltaTrackingTree(EntryTree<T> delegate) { | 21 | public DeltaTrackingTree(EntryTree<T> delegate) { |
| 17 | this.delegate = delegate; | 22 | this.delegate = delegate; |
| 23 | this.deltaReference = new HashEntryTree<>(delegate); | ||
| 18 | } | 24 | } |
| 19 | 25 | ||
| 20 | public DeltaTrackingTree() { | 26 | public DeltaTrackingTree() { |
| @@ -40,7 +46,7 @@ public class DeltaTrackingTree<T> implements EntryTree<T> { | |||
| 40 | } | 46 | } |
| 41 | 47 | ||
| 42 | public void trackAddition(Entry<?> entry) { | 48 | public void trackAddition(Entry<?> entry) { |
| 43 | deletions.remove(entry); | 49 | deletions.insert(entry, MappingDelta.PLACEHOLDER); |
| 44 | additions.insert(entry, MappingDelta.PLACEHOLDER); | 50 | additions.insert(entry, MappingDelta.PLACEHOLDER); |
| 45 | } | 51 | } |
| 46 | 52 | ||
| @@ -82,6 +88,14 @@ public class DeltaTrackingTree<T> implements EntryTree<T> { | |||
| 82 | } | 88 | } |
| 83 | 89 | ||
| 84 | @Override | 90 | @Override |
| 91 | public DeltaTrackingTree<T> translate(Translator translator, EntryResolver resolver, EntryMap<EntryMapping> mappings) { | ||
| 92 | DeltaTrackingTree<T> translatedTree = new DeltaTrackingTree<>(delegate.translate(translator, resolver, mappings)); | ||
| 93 | translatedTree.additions = additions.translate(translator, resolver, mappings); | ||
| 94 | translatedTree.deletions = deletions.translate(translator, resolver, mappings); | ||
| 95 | return translatedTree; | ||
| 96 | } | ||
| 97 | |||
| 98 | @Override | ||
| 85 | public Collection<Entry<?>> getAllEntries() { | 99 | public Collection<Entry<?>> getAllEntries() { |
| 86 | return delegate.getAllEntries(); | 100 | return delegate.getAllEntries(); |
| 87 | } | 101 | } |
| @@ -96,13 +110,14 @@ public class DeltaTrackingTree<T> implements EntryTree<T> { | |||
| 96 | return delegate.iterator(); | 110 | return delegate.iterator(); |
| 97 | } | 111 | } |
| 98 | 112 | ||
| 99 | public MappingDelta takeDelta() { | 113 | public MappingDelta<T> takeDelta() { |
| 100 | MappingDelta delta = new MappingDelta(additions, deletions); | 114 | MappingDelta<T> delta = new MappingDelta<>(deltaReference, additions, deletions); |
| 101 | resetDelta(); | 115 | resetDelta(); |
| 102 | return delta; | 116 | return delta; |
| 103 | } | 117 | } |
| 104 | 118 | ||
| 105 | private void resetDelta() { | 119 | private void resetDelta() { |
| 120 | deltaReference = new HashEntryTree<>(delegate); | ||
| 106 | additions = new HashEntryTree<>(); | 121 | additions = new HashEntryTree<>(); |
| 107 | deletions = new HashEntryTree<>(); | 122 | deletions = new HashEntryTree<>(); |
| 108 | } | 123 | } |
diff --git a/src/main/java/cuchaz/enigma/translation/mapping/tree/EntryTree.java b/src/main/java/cuchaz/enigma/translation/mapping/tree/EntryTree.java index 73fe12d..4f341f4 100644 --- a/src/main/java/cuchaz/enigma/translation/mapping/tree/EntryTree.java +++ b/src/main/java/cuchaz/enigma/translation/mapping/tree/EntryTree.java | |||
| @@ -1,12 +1,16 @@ | |||
| 1 | package cuchaz.enigma.translation.mapping.tree; | 1 | package cuchaz.enigma.translation.mapping.tree; |
| 2 | 2 | ||
| 3 | import cuchaz.enigma.translation.Translatable; | ||
| 4 | import cuchaz.enigma.translation.Translator; | ||
| 3 | import cuchaz.enigma.translation.mapping.EntryMap; | 5 | import cuchaz.enigma.translation.mapping.EntryMap; |
| 6 | import cuchaz.enigma.translation.mapping.EntryMapping; | ||
| 7 | import cuchaz.enigma.translation.mapping.EntryResolver; | ||
| 4 | import cuchaz.enigma.translation.representation.entry.Entry; | 8 | import cuchaz.enigma.translation.representation.entry.Entry; |
| 5 | 9 | ||
| 6 | import javax.annotation.Nullable; | 10 | import javax.annotation.Nullable; |
| 7 | import java.util.Collection; | 11 | import java.util.Collection; |
| 8 | 12 | ||
| 9 | public interface EntryTree<T> extends EntryMap<T>, Iterable<EntryTreeNode<T>> { | 13 | public interface EntryTree<T> extends EntryMap<T>, Iterable<EntryTreeNode<T>>, Translatable { |
| 10 | Collection<Entry<?>> getChildren(Entry<?> entry); | 14 | Collection<Entry<?>> getChildren(Entry<?> entry); |
| 11 | 15 | ||
| 12 | Collection<Entry<?>> getSiblings(Entry<?> entry); | 16 | Collection<Entry<?>> getSiblings(Entry<?> entry); |
| @@ -17,4 +21,7 @@ public interface EntryTree<T> extends EntryMap<T>, Iterable<EntryTreeNode<T>> { | |||
| 17 | Collection<EntryTreeNode<T>> getAllNodes(); | 21 | Collection<EntryTreeNode<T>> getAllNodes(); |
| 18 | 22 | ||
| 19 | Collection<Entry<?>> getRootEntries(); | 23 | Collection<Entry<?>> getRootEntries(); |
| 24 | |||
| 25 | @Override | ||
| 26 | EntryTree<T> translate(Translator translator, EntryResolver resolver, EntryMap<EntryMapping> mappings); | ||
| 20 | } | 27 | } |
diff --git a/src/main/java/cuchaz/enigma/translation/mapping/tree/HashEntryTree.java b/src/main/java/cuchaz/enigma/translation/mapping/tree/HashEntryTree.java index ff88bf9..551fb1c 100644 --- a/src/main/java/cuchaz/enigma/translation/mapping/tree/HashEntryTree.java +++ b/src/main/java/cuchaz/enigma/translation/mapping/tree/HashEntryTree.java | |||
| @@ -1,5 +1,9 @@ | |||
| 1 | package cuchaz.enigma.translation.mapping.tree; | 1 | package cuchaz.enigma.translation.mapping.tree; |
| 2 | 2 | ||
| 3 | import cuchaz.enigma.translation.Translator; | ||
| 4 | import cuchaz.enigma.translation.mapping.EntryMap; | ||
| 5 | import cuchaz.enigma.translation.mapping.EntryMapping; | ||
| 6 | import cuchaz.enigma.translation.mapping.EntryResolver; | ||
| 3 | import cuchaz.enigma.translation.representation.entry.Entry; | 7 | import cuchaz.enigma.translation.representation.entry.Entry; |
| 4 | 8 | ||
| 5 | import javax.annotation.Nullable; | 9 | import javax.annotation.Nullable; |
| @@ -9,6 +13,15 @@ import java.util.stream.Collectors; | |||
| 9 | public class HashEntryTree<T> implements EntryTree<T> { | 13 | public class HashEntryTree<T> implements EntryTree<T> { |
| 10 | private final Map<Entry<?>, HashTreeNode<T>> root = new HashMap<>(); | 14 | private final Map<Entry<?>, HashTreeNode<T>> root = new HashMap<>(); |
| 11 | 15 | ||
| 16 | public HashEntryTree() { | ||
| 17 | } | ||
| 18 | |||
| 19 | public HashEntryTree(EntryTree<T> tree) { | ||
| 20 | for (EntryTreeNode<T> node : tree.getAllNodes()) { | ||
| 21 | insert(node.getEntry(), node.getValue()); | ||
| 22 | } | ||
| 23 | } | ||
| 24 | |||
| 12 | @Override | 25 | @Override |
| 13 | public void insert(Entry<?> entry, T value) { | 26 | public void insert(Entry<?> entry, T value) { |
| 14 | List<HashTreeNode<T>> path = computePath(entry); | 27 | List<HashTreeNode<T>> path = computePath(entry); |
| @@ -156,4 +169,13 @@ public class HashEntryTree<T> implements EntryTree<T> { | |||
| 156 | public boolean isEmpty() { | 169 | public boolean isEmpty() { |
| 157 | return root.isEmpty(); | 170 | return root.isEmpty(); |
| 158 | } | 171 | } |
| 172 | |||
| 173 | @Override | ||
| 174 | public HashEntryTree<T> translate(Translator translator, EntryResolver resolver, EntryMap<EntryMapping> mappings) { | ||
| 175 | HashEntryTree<T> translatedTree = new HashEntryTree<>(); | ||
| 176 | for (EntryTreeNode<T> node : getAllNodes()) { | ||
| 177 | translatedTree.insert(translator.translate(node.getEntry()), node.getValue()); | ||
| 178 | } | ||
| 179 | return translatedTree; | ||
| 180 | } | ||
| 159 | } | 181 | } |