Merge pull request #269 from moulins/fix-mc1-11

Fix for #247
master
Stefan Dollase 2016-11-20 17:14:03 +01:00 committed by GitHub
commit ea3ae61ed4
18 changed files with 89 additions and 330 deletions

View File

@ -1,14 +1,14 @@
package amidst.clazz.real.detector;
package amidst.clazz.real;
import java.util.ArrayList;
import java.util.List;
import amidst.clazz.real.RealClass;
import amidst.documentation.Immutable;
@Immutable
public abstract class RealClassDetector {
public RealClass firstMatching(List<RealClass> realClasses) {
@FunctionalInterface
public interface RealClassDetector {
public default RealClass firstMatching(List<RealClass> realClasses) {
for (RealClass realClass : realClasses) {
if (detect(realClass)) {
return realClass;
@ -17,7 +17,7 @@ public abstract class RealClassDetector {
return null;
}
public List<RealClass> allMatching(List<RealClass> realClasses) {
public default List<RealClass> allMatching(List<RealClass> realClasses) {
List<RealClass> result = new ArrayList<RealClass>();
for (RealClass realClass : realClasses) {
if (detect(realClass)) {
@ -27,5 +27,5 @@ public abstract class RealClassDetector {
return result;
}
public abstract boolean detect(RealClass realClass);
public boolean detect(RealClass realClass);
}

View File

@ -16,7 +16,7 @@ import amidst.documentation.Immutable;
public enum RealClasses {
;
private static final int MAXIMUM_CLASS_BYTES = 8000;
private static final int MAXIMUM_CLASS_BYTES = 16*1024;
private static final RealClassBuilder REAL_CLASS_BUILDER = new RealClassBuilder();
public static List<RealClass> fromJarFile(File jarFile) throws FileNotFoundException, JarFileParsingException {

View File

@ -1,25 +0,0 @@
package amidst.clazz.real.detector;
import java.util.List;
import amidst.clazz.real.RealClass;
import amidst.documentation.Immutable;
@Immutable
public class AllRCD extends RealClassDetector {
private final List<RealClassDetector> detectors;
public AllRCD(List<RealClassDetector> detectors) {
this.detectors = detectors;
}
@Override
public boolean detect(RealClass realClass) {
for (RealClassDetector detector : detectors) {
if (!detector.detect(realClass)) {
return false;
}
}
return true;
}
}

View File

@ -1,25 +0,0 @@
package amidst.clazz.real.detector;
import java.util.List;
import amidst.clazz.real.RealClass;
import amidst.documentation.Immutable;
@Immutable
public class AnyRCD extends RealClassDetector {
private final List<RealClassDetector> detectors;
public AnyRCD(List<RealClassDetector> detectors) {
this.detectors = detectors;
}
@Override
public boolean detect(RealClass realClass) {
for (RealClassDetector detector : detectors) {
if (detector.detect(realClass)) {
return true;
}
}
return false;
}
}

View File

@ -1,27 +0,0 @@
package amidst.clazz.real.detector;
import amidst.clazz.real.RealClass;
import amidst.clazz.real.RealClassField;
import amidst.documentation.Immutable;
@Immutable
public class FieldFlagsRCD extends RealClassDetector {
private final int flags;
private final int[] fieldIndices;
public FieldFlagsRCD(int flags, int... fieldIndices) {
this.flags = flags;
this.fieldIndices = fieldIndices;
}
@Override
public boolean detect(RealClass realClass) {
for (int fieldIndex : fieldIndices) {
RealClassField field = realClass.getField(fieldIndex);
if (!field.hasFlags(flags)) {
return false;
}
}
return true;
}
}

View File

@ -1,23 +0,0 @@
package amidst.clazz.real.detector;
import amidst.clazz.real.RealClass;
import amidst.documentation.Immutable;
@Immutable
public class LongRCD extends RealClassDetector {
private final long[] longs;
public LongRCD(long... longs) {
this.longs = longs;
}
@Override
public boolean detect(RealClass realClass) {
for (long element : longs) {
if (!realClass.searchForLong(element)) {
return false;
}
}
return true;
}
}

View File

@ -1,18 +0,0 @@
package amidst.clazz.real.detector;
import amidst.clazz.real.RealClass;
import amidst.documentation.Immutable;
@Immutable
public class NumberOfConstructorsRCD extends RealClassDetector {
private final int count;
public NumberOfConstructorsRCD(int count) {
this.count = count;
}
@Override
public boolean detect(RealClass realClass) {
return realClass.getNumberOfConstructors() == count;
}
}

View File

@ -1,18 +0,0 @@
package amidst.clazz.real.detector;
import amidst.clazz.real.RealClass;
import amidst.documentation.Immutable;
@Immutable
public class NumberOfFieldsRCD extends RealClassDetector {
private final int count;
public NumberOfFieldsRCD(int count) {
this.count = count;
}
@Override
public boolean detect(RealClass realClass) {
return realClass.getNumberOfFields() == count;
}
}

View File

@ -1,18 +0,0 @@
package amidst.clazz.real.detector;
import amidst.clazz.real.RealClass;
import amidst.documentation.Immutable;
@Immutable
public class NumberOfMethodsRCD extends RealClassDetector {
private final int count;
public NumberOfMethodsRCD(int count) {
this.count = count;
}
@Override
public boolean detect(RealClass realClass) {
return realClass.getNumberOfMethods() == count;
}
}

View File

@ -1,18 +0,0 @@
package amidst.clazz.real.detector;
import amidst.clazz.real.RealClass;
import amidst.documentation.Immutable;
@Immutable
public class StringContainingRCD extends RealClassDetector {
private final String string;
public StringContainingRCD(String string) {
this.string = string;
}
@Override
public boolean detect(RealClass realClass) {
return realClass.searchForStringContaining(string);
}
}

View File

@ -1,18 +0,0 @@
package amidst.clazz.real.detector;
import amidst.clazz.real.RealClass;
import amidst.documentation.Immutable;
@Immutable
public class Utf8EqualToRCD extends RealClassDetector {
private final String utf8;
public Utf8EqualToRCD(String utf8) {
this.utf8 = utf8;
}
@Override
public boolean detect(RealClass realClass) {
return realClass.searchForUtf8EqualTo(utf8);
}
}

View File

@ -1,18 +0,0 @@
package amidst.clazz.real.detector;
import amidst.clazz.real.RealClass;
import amidst.documentation.Immutable;
@Immutable
public class WildcardByteRCD extends RealClassDetector {
private final int[] bytes;
public WildcardByteRCD(int[] bytes) {
this.bytes = bytes;
}
@Override
public boolean detect(RealClass realClass) {
return realClass.isClassDataWildcardMatching(bytes);
}
}

View File

@ -5,17 +5,7 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import amidst.clazz.real.detector.AllRCD;
import amidst.clazz.real.detector.AnyRCD;
import amidst.clazz.real.detector.FieldFlagsRCD;
import amidst.clazz.real.detector.LongRCD;
import amidst.clazz.real.detector.NumberOfConstructorsRCD;
import amidst.clazz.real.detector.NumberOfFieldsRCD;
import amidst.clazz.real.detector.NumberOfMethodsRCD;
import amidst.clazz.real.detector.RealClassDetector;
import amidst.clazz.real.detector.StringContainingRCD;
import amidst.clazz.real.detector.Utf8EqualToRCD;
import amidst.clazz.real.detector.WildcardByteRCD;
import amidst.clazz.real.RealClassDetector;
import amidst.clazz.symbolic.declaration.SymbolicClassDeclaration;
import amidst.clazz.symbolic.declaration.SymbolicConstructorDeclaration;
import amidst.clazz.symbolic.declaration.SymbolicFieldDeclaration;
@ -30,84 +20,6 @@ import amidst.documentation.NotThreadSafe;
*/
@NotThreadSafe
public class CTBuilder {
@NotThreadSafe
public class RCDBuilder {
private final List<List<RealClassDetector>> allDetectors = new ArrayList<List<RealClassDetector>>();
private List<RealClassDetector> detectors = new ArrayList<RealClassDetector>();
private RealClassDetector constructThis() {
if (allDetectors.size() == 1) {
return new AllRCD(allDetectors.get(0));
} else {
List<RealClassDetector> result = new ArrayList<RealClassDetector>();
for (List<RealClassDetector> detectors : allDetectors) {
result.add(new AllRCD(detectors));
}
return new AnyRCD(result);
}
}
public RCDBuilder or() {
allDetectors.add(detectors);
detectors = new ArrayList<RealClassDetector>();
return this;
}
public SCDBuilder thenDeclareRequired(String symbolicClassName) {
return thenDeclare(symbolicClassName, false);
}
public SCDBuilder thenDeclareOptional(String symbolicClassName) {
return thenDeclare(symbolicClassName, true);
}
private SCDBuilder thenDeclare(String symbolicClassName, boolean isOptional) {
allDetectors.add(detectors);
CTBuilder.this.declarationBuilder.init(symbolicClassName, isOptional);
return CTBuilder.this.declarationBuilder;
}
public RCDBuilder fieldFlags(int flags, int... fieldIndices) {
detectors.add(new FieldFlagsRCD(flags, fieldIndices));
return this;
}
public RCDBuilder longs(long... longs) {
detectors.add(new LongRCD(longs));
return this;
}
public RCDBuilder numberOfConstructors(int count) {
detectors.add(new NumberOfConstructorsRCD(count));
return this;
}
public RCDBuilder numberOfFields(int count) {
detectors.add(new NumberOfFieldsRCD(count));
return this;
}
public RCDBuilder numberOfMethods(int count) {
detectors.add(new NumberOfMethodsRCD(count));
return this;
}
public RCDBuilder stringContaining(String string) {
detectors.add(new StringContainingRCD(string));
return this;
}
public RCDBuilder utf8EqualTo(String utf8) {
detectors.add(new Utf8EqualToRCD(utf8));
return this;
}
public RCDBuilder wildcardBytes(int[] bytes) {
detectors.add(new WildcardByteRCD(bytes));
return this;
}
}
@NotThreadSafe
public class SCDBuilder {
private String symbolicClassName;
@ -192,15 +104,31 @@ public class CTBuilder {
private final CTBuilder previous;
private final RCDBuilder detectorBuilder = new RCDBuilder();
private RealClassDetector detector = null;
private final SCDBuilder declarationBuilder = new SCDBuilder();
private CTBuilder(CTBuilder previous) {
this.previous = previous;
}
public RCDBuilder ifDetect() {
return detectorBuilder;
public CTBuilder ifDetect(RealClassDetector detector) {
this.detector = detector;
return this;
}
public SCDBuilder thenDeclareRequired(String symbolicClassName) {
return thenDeclare(symbolicClassName, false);
}
public SCDBuilder thenDeclareOptional(String symbolicClassName) {
return thenDeclare(symbolicClassName, true);
}
private SCDBuilder thenDeclare(String symbolicClassName, boolean isOptional) {
if(detector == null)
throw new IllegalStateException("can't declare a symbolic class without calling ifDetect before");
CTBuilder.this.declarationBuilder.init(symbolicClassName, isOptional);
return CTBuilder.this.declarationBuilder;
}
public ClassTranslator construct() {
@ -209,7 +137,7 @@ public class CTBuilder {
private Map<RealClassDetector, SymbolicClassDeclaration> constructResult() {
Map<RealClassDetector, SymbolicClassDeclaration> result = constructPreviousResult();
result.put(detectorBuilder.constructThis(), declarationBuilder.constructThis());
result.put(detector, declarationBuilder.constructThis());
return result;
}

View File

@ -6,7 +6,7 @@ import java.util.Map;
import java.util.Map.Entry;
import amidst.clazz.real.RealClass;
import amidst.clazz.real.detector.RealClassDetector;
import amidst.clazz.real.RealClassDetector;
import amidst.clazz.symbolic.declaration.SymbolicClassDeclaration;
import amidst.documentation.Immutable;

View File

@ -21,15 +21,14 @@ public enum DefaultClassTranslator {
private ClassTranslator createClassTranslator() {
return ClassTranslator
.builder()
.ifDetect()
.wildcardBytes(createIntCacheWildcardBytes())
.or()
.stringContaining(", tcache: ")
.ifDetect(c ->
c.isClassDataWildcardMatching(createIntCacheWildcardBytes())
|| c.searchForStringContaining(", tcache: ")
)
.thenDeclareRequired(SymbolicNames.CLASS_INT_CACHE)
.requiredMethod(SymbolicNames.METHOD_INT_CACHE_RESET_INT_CACHE, "a").end()
.next()
.ifDetect()
.stringContaining("default_1_1")
.ifDetect(c -> c.searchForStringContaining("default_1_1"))
.thenDeclareOptional(SymbolicNames.CLASS_WORLD_TYPE)
.requiredField(SymbolicNames.FIELD_WORLD_TYPE_DEFAULT, "b")
.requiredField(SymbolicNames.FIELD_WORLD_TYPE_FLAT, "c")
@ -37,30 +36,47 @@ public enum DefaultClassTranslator {
.requiredField(SymbolicNames.FIELD_WORLD_TYPE_AMPLIFIED, "e")
.requiredField(SymbolicNames.FIELD_WORLD_TYPE_CUSTOMIZED, "f")
.next()
.ifDetect()
.longs(1000L, 2001L, 2000L)
.ifDetect(c ->
c.searchForLong(1000L)
&& c.searchForLong(2001L)
&& c.searchForLong(2000L)
)
.thenDeclareRequired(SymbolicNames.CLASS_GEN_LAYER)
// one if the initializeAllBiomeGenerators-methods is required!
.optionalMethod(SymbolicNames.METHOD_GEN_LAYER_INITIALIZE_ALL_BIOME_GENERATORS_1, "a").real("long").end()
.optionalMethod(SymbolicNames.METHOD_GEN_LAYER_INITIALIZE_ALL_BIOME_GENERATORS_2, "a").real("long").symbolic("WorldType").end()
.optionalMethod(SymbolicNames.METHOD_GEN_LAYER_INITIALIZE_ALL_BIOME_GENERATORS_3, "a").real("long").symbolic("WorldType").real("String").end()
.optionalMethod(SymbolicNames.METHOD_GEN_LAYER_INITIALIZE_ALL_BIOME_GENERATORS_3A,"a").real("long").symbolic("WorldType").symbolic("ChunkProviderSettings").end()
.requiredMethod(SymbolicNames.METHOD_GEN_LAYER_GET_INTS, "a").real("int") .real("int") .real("int") .real("int").end()
.next()
.ifDetect()
.numberOfConstructors(0)
.numberOfMethods(6)
.numberOfFields(3)
.fieldFlags(AccessFlags.PRIVATE | AccessFlags.STATIC, 0, 1, 2)
.utf8EqualTo("isDebugEnabled")
.or()
.numberOfConstructors(0)
.numberOfMethods(6)
.numberOfFields(3)
.fieldFlags(AccessFlags.PUBLIC | AccessFlags.STATIC, 0)
.fieldFlags(AccessFlags.PRIVATE | AccessFlags.STATIC, 1, 2)
.utf8EqualTo("isDebugEnabled")
.ifDetect(c ->
c.getNumberOfConstructors() == 0
&& c.getNumberOfMethods() == 6
&& c.getNumberOfFields() == 3
&& c.getField(0).hasFlags(AccessFlags.STATIC)
&& c.getField(1).hasFlags(AccessFlags.PRIVATE | AccessFlags.STATIC)
&& c.getField(2).hasFlags(AccessFlags.PRIVATE | AccessFlags.STATIC)
&& c.searchForUtf8EqualTo("isDebugEnabled")
)
.thenDeclareOptional(SymbolicNames.CLASS_BLOCK_INIT)
.requiredMethod(SymbolicNames.METHOD_BLOCK_INIT_INITIALIZE, "c").end()
.next()
.ifDetect(c ->
//some leeway in case Mojang adds or removes fields in the future
c.getNumberOfFields() > 70 && c.getNumberOfFields() < 100
&& c.getNumberOfMethods() == 0
)
.thenDeclareOptional(SymbolicNames.CLASS_GEN_OPTIONS)
.next()
.ifDetect(c ->
//same as above
c.getNumberOfFields() > 70 && c.getNumberOfFields() < 100
&& c.getField(0).hasFlags(AccessFlags.STATIC | AccessFlags.FINAL)
&& c.getField(1).hasFlags(AccessFlags.PUBLIC)
)
.thenDeclareOptional(SymbolicNames.CLASS_GEN_OPTIONS_FACTORY)
.requiredMethod(SymbolicNames.METHOD_GEN_OPTIONS_FACTORY_BUILD, "b").end()
.requiredMethod(SymbolicNames.METHOD_GEN_OPTIONS_FACTORY_JSON_TO_FACTORY, "a").real("String").end()
.construct();
}
// @formatter:on

View File

@ -33,6 +33,7 @@ public class LocalMinecraftInterface implements MinecraftInterface {
private final SymbolicClass blockInitClass;
private final SymbolicClass genLayerClass;
private final SymbolicClass worldTypeClass;
private final SymbolicClass genOptionsFactoryClass;
private final RecognisedVersion recognisedVersion;
LocalMinecraftInterface(
@ -40,11 +41,13 @@ public class LocalMinecraftInterface implements MinecraftInterface {
SymbolicClass blockInitClass,
SymbolicClass genLayerClass,
SymbolicClass worldTypeClass,
SymbolicClass genOptionsFactoryClass,
RecognisedVersion recognisedVersion) {
this.intCacheClass = intCacheClass;
this.blockInitClass = blockInitClass;
this.genLayerClass = genLayerClass;
this.worldTypeClass = worldTypeClass;
this.genOptionsFactoryClass = genOptionsFactoryClass;
this.recognisedVersion = recognisedVersion;
}
@ -98,12 +101,25 @@ public class LocalMinecraftInterface implements MinecraftInterface {
throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
if (worldTypeClass == null) {
return (Object[]) genLayerClass.callStaticMethod(SymbolicNames.METHOD_GEN_LAYER_INITIALIZE_ALL_BIOME_GENERATORS_1, seed);
} else if (genLayerClass.hasMethod(SymbolicNames.METHOD_GEN_LAYER_INITIALIZE_ALL_BIOME_GENERATORS_3A)) {
SymbolicObject options = getGeneratorOptions(generatorOptions);
return (Object[]) genLayerClass.callStaticMethod(SymbolicNames.METHOD_GEN_LAYER_INITIALIZE_ALL_BIOME_GENERATORS_3A, seed, getWorldType(worldType).getObject(), options.getObject());
} else if (genLayerClass.hasMethod(SymbolicNames.METHOD_GEN_LAYER_INITIALIZE_ALL_BIOME_GENERATORS_3)) {
return (Object[]) genLayerClass.callStaticMethod(SymbolicNames.METHOD_GEN_LAYER_INITIALIZE_ALL_BIOME_GENERATORS_3, seed, getWorldType(worldType).getObject(), generatorOptions);
} else {
return (Object[]) genLayerClass.callStaticMethod(SymbolicNames.METHOD_GEN_LAYER_INITIALIZE_ALL_BIOME_GENERATORS_2, seed, getWorldType(worldType).getObject());
}
}
private SymbolicObject getGeneratorOptions(String generatorOptions)
throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
SymbolicObject factory = (SymbolicObject) genOptionsFactoryClass.callStaticMethod(SymbolicNames.METHOD_GEN_OPTIONS_FACTORY_JSON_TO_FACTORY, generatorOptions);
return (SymbolicObject) factory.callMethod(SymbolicNames.METHOD_GEN_OPTIONS_FACTORY_BUILD);
}
private SymbolicObject getWorldType(WorldType worldType)
throws IllegalArgumentException, IllegalAccessException {

View File

@ -40,6 +40,7 @@ public class LocalMinecraftInterfaceBuilder {
symbolicClassMap.get(SymbolicNames.CLASS_BLOCK_INIT),
symbolicClassMap.get(SymbolicNames.CLASS_GEN_LAYER),
symbolicClassMap.get(SymbolicNames.CLASS_WORLD_TYPE),
symbolicClassMap.get(SymbolicNames.CLASS_GEN_OPTIONS_FACTORY),
recognisedVersion);
} catch (MalformedURLException | ClassNotFoundException | FileNotFoundException | JarFileParsingException
| SymbolicClassGraphCreationException e) {

View File

@ -20,8 +20,14 @@ public enum SymbolicNames {
public static final String METHOD_GEN_LAYER_INITIALIZE_ALL_BIOME_GENERATORS_1 = "initializeAllBiomeGenerators1";
public static final String METHOD_GEN_LAYER_INITIALIZE_ALL_BIOME_GENERATORS_2 = "initializeAllBiomeGenerators2";
public static final String METHOD_GEN_LAYER_INITIALIZE_ALL_BIOME_GENERATORS_3 = "initializeAllBiomeGenerators3";
public static final String METHOD_GEN_LAYER_INITIALIZE_ALL_BIOME_GENERATORS_3A = "initializeAllBiomeGenerators3a";
public static final String METHOD_GEN_LAYER_GET_INTS = "getInts";
public static final String CLASS_BLOCK_INIT = "BlockInit";
public static final String METHOD_BLOCK_INIT_INITIALIZE = "initialize";
public static final String CLASS_GEN_OPTIONS = "ChunkProviderSettings";
public static final String CLASS_GEN_OPTIONS_FACTORY = CLASS_GEN_OPTIONS + ".Factory";
public static final String METHOD_GEN_OPTIONS_FACTORY_JSON_TO_FACTORY = "jsonToFactory";
public static final String METHOD_GEN_OPTIONS_FACTORY_BUILD = "build";
}