forked from MirrorHub/authlib-injector
Merge pull request #38 from yushijinhun/mlsupport
通过 invokedynamic 来绕过 launchwrapper
This commit is contained in:
commit
11086df465
15 changed files with 259 additions and 118 deletions
|
@ -57,7 +57,6 @@ import moe.yushi.authlibinjector.transform.MainArgumentsTransformer;
|
||||||
import moe.yushi.authlibinjector.transform.SkinWhitelistTransformUnit;
|
import moe.yushi.authlibinjector.transform.SkinWhitelistTransformUnit;
|
||||||
import moe.yushi.authlibinjector.transform.YggdrasilKeyTransformUnit;
|
import moe.yushi.authlibinjector.transform.YggdrasilKeyTransformUnit;
|
||||||
import moe.yushi.authlibinjector.transform.support.CitizensTransformer;
|
import moe.yushi.authlibinjector.transform.support.CitizensTransformer;
|
||||||
import moe.yushi.authlibinjector.transform.support.LaunchWrapperTransformer;
|
|
||||||
import moe.yushi.authlibinjector.transform.support.MC52974Workaround;
|
import moe.yushi.authlibinjector.transform.support.MC52974Workaround;
|
||||||
import moe.yushi.authlibinjector.transform.support.MC52974_1710Workaround;
|
import moe.yushi.authlibinjector.transform.support.MC52974_1710Workaround;
|
||||||
import moe.yushi.authlibinjector.util.Logging;
|
import moe.yushi.authlibinjector.util.Logging;
|
||||||
|
@ -356,7 +355,6 @@ public final class AuthlibInjector {
|
||||||
transformer.units.add(new MainArgumentsTransformer());
|
transformer.units.add(new MainArgumentsTransformer());
|
||||||
transformer.units.add(new ConstantURLTransformUnit(urlProcessor));
|
transformer.units.add(new ConstantURLTransformUnit(urlProcessor));
|
||||||
transformer.units.add(new CitizensTransformer());
|
transformer.units.add(new CitizensTransformer());
|
||||||
transformer.units.add(new LaunchWrapperTransformer());
|
|
||||||
|
|
||||||
transformer.units.add(new SkinWhitelistTransformUnit(config.getSkinDomains().toArray(new String[0])));
|
transformer.units.add(new SkinWhitelistTransformUnit(config.getSkinDomains().toArray(new String[0])));
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,6 @@
|
||||||
package moe.yushi.authlibinjector.transform;
|
package moe.yushi.authlibinjector.transform;
|
||||||
|
|
||||||
import static org.objectweb.asm.Opcodes.ASM7;
|
import static org.objectweb.asm.Opcodes.ASM7;
|
||||||
import static org.objectweb.asm.Opcodes.INVOKESTATIC;
|
|
||||||
import static org.objectweb.asm.Opcodes.INVOKEVIRTUAL;
|
import static org.objectweb.asm.Opcodes.INVOKEVIRTUAL;
|
||||||
|
|
||||||
import java.lang.annotation.Annotation;
|
import java.lang.annotation.Annotation;
|
||||||
|
@ -44,6 +43,7 @@ public class AuthlibLogInterceptor implements TransformUnit {
|
||||||
|
|
||||||
private static Set<ClassLoader> interceptedClassloaders = Collections.newSetFromMap(new WeakHashMap<>());
|
private static Set<ClassLoader> interceptedClassloaders = Collections.newSetFromMap(new WeakHashMap<>());
|
||||||
|
|
||||||
|
@CallbackMethod
|
||||||
public static void onClassLoading(ClassLoader classLoader) {
|
public static void onClassLoading(ClassLoader classLoader) {
|
||||||
Class<?> classLogManager;
|
Class<?> classLogManager;
|
||||||
try {
|
try {
|
||||||
|
@ -212,7 +212,7 @@ public class AuthlibLogInterceptor implements TransformUnit {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Optional<ClassVisitor> transform(ClassLoader classLoader, String className, ClassVisitor writer, Runnable modifiedCallback) {
|
public Optional<ClassVisitor> transform(ClassLoader classLoader, String className, ClassVisitor writer, TransformContext ctx) {
|
||||||
if (className.startsWith("com.mojang.authlib.")) {
|
if (className.startsWith("com.mojang.authlib.")) {
|
||||||
synchronized (interceptedClassloaders) {
|
synchronized (interceptedClassloaders) {
|
||||||
if (interceptedClassloaders.contains(classLoader)) {
|
if (interceptedClassloaders.contains(classLoader)) {
|
||||||
|
@ -223,14 +223,20 @@ public class AuthlibLogInterceptor implements TransformUnit {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) {
|
public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) {
|
||||||
MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions);
|
|
||||||
if ("<clinit>".equals(name)) {
|
if ("<clinit>".equals(name)) {
|
||||||
mv.visitLdcInsn(Type.getType("L" + className.replace('.', '/') + ";"));
|
return new MethodVisitor(ASM7, super.visitMethod(access, name, descriptor, signature, exceptions)) {
|
||||||
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Class", "getClassLoader", "()Ljava/lang/ClassLoader;", false);
|
@Override
|
||||||
mv.visitMethodInsn(INVOKESTATIC, AuthlibLogInterceptor.class.getName().replace('.', '/'), "onClassLoading", "(Ljava/lang/ClassLoader;)V", false);
|
public void visitCode() {
|
||||||
modifiedCallback.run();
|
super.visitCode();
|
||||||
|
super.visitLdcInsn(Type.getType("L" + className.replace('.', '/') + ";"));
|
||||||
|
super.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Class", "getClassLoader", "()Ljava/lang/ClassLoader;", false);
|
||||||
|
CallbackSupport.invoke(ctx, mv, AuthlibLogInterceptor.class, "onClassLoading");
|
||||||
|
ctx.markModified();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
return super.visitMethod(access, name, descriptor, signature, exceptions);
|
||||||
}
|
}
|
||||||
return mv;
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2019 Haowei Wen <yushijinhun@gmail.com> and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package moe.yushi.authlibinjector.transform;
|
||||||
|
|
||||||
|
import java.lang.invoke.CallSite;
|
||||||
|
import java.lang.invoke.ConstantCallSite;
|
||||||
|
import java.lang.invoke.MethodHandles.Lookup;
|
||||||
|
import java.lang.invoke.MethodType;
|
||||||
|
|
||||||
|
public final class CallbackEntryPoint {
|
||||||
|
private CallbackEntryPoint() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static CallSite bootstrap(Lookup lookup, String name, MethodType type, String owner) throws ReflectiveOperationException {
|
||||||
|
return new ConstantCallSite(
|
||||||
|
lookup.findStatic(
|
||||||
|
ClassLoader.getSystemClassLoader().loadClass(owner),
|
||||||
|
name,
|
||||||
|
type));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2019 Haowei Wen <yushijinhun@gmail.com> and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package moe.yushi.authlibinjector.transform;
|
||||||
|
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Target(ElementType.METHOD)
|
||||||
|
public @interface CallbackMethod {
|
||||||
|
}
|
|
@ -0,0 +1,60 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2019 Haowei Wen <yushijinhun@gmail.com> and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package moe.yushi.authlibinjector.transform;
|
||||||
|
|
||||||
|
import static org.objectweb.asm.Opcodes.H_INVOKESTATIC;
|
||||||
|
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.lang.reflect.Modifier;
|
||||||
|
|
||||||
|
import org.objectweb.asm.Handle;
|
||||||
|
import org.objectweb.asm.MethodVisitor;
|
||||||
|
import org.objectweb.asm.Type;
|
||||||
|
|
||||||
|
import moe.yushi.authlibinjector.transform.TransformUnit.TransformContext;
|
||||||
|
|
||||||
|
public final class CallbackSupport {
|
||||||
|
private CallbackSupport() {
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Method findCallbackMethod(Class<?> owner, String methodName) {
|
||||||
|
for (Method method : owner.getDeclaredMethods()) {
|
||||||
|
int modifiers = method.getModifiers();
|
||||||
|
if (Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers) &&
|
||||||
|
methodName.equals(method.getName()) &&
|
||||||
|
method.getAnnotation(CallbackMethod.class) != null) {
|
||||||
|
return method;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new IllegalArgumentException("No such method: " + methodName);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final Handle BOOTSTRAP_METHOD = new Handle(
|
||||||
|
H_INVOKESTATIC,
|
||||||
|
Type.getInternalName(CallbackEntryPoint.class),
|
||||||
|
"bootstrap",
|
||||||
|
"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;",
|
||||||
|
false);
|
||||||
|
|
||||||
|
public static void invoke(TransformContext ctx, MethodVisitor mv, Class<?> owner, String methodName) {
|
||||||
|
ctx.requireMinimumClassVersion(50);
|
||||||
|
ctx.upgradeClassVersion(51);
|
||||||
|
|
||||||
|
String descriptor = Type.getMethodDescriptor(findCallbackMethod(owner, methodName));
|
||||||
|
mv.visitInvokeDynamicInsn(methodName, descriptor, BOOTSTRAP_METHOD, owner.getName());
|
||||||
|
}
|
||||||
|
}
|
|
@ -17,6 +17,7 @@
|
||||||
package moe.yushi.authlibinjector.transform;
|
package moe.yushi.authlibinjector.transform;
|
||||||
|
|
||||||
import static java.util.Collections.emptyList;
|
import static java.util.Collections.emptyList;
|
||||||
|
import static org.objectweb.asm.Opcodes.ASM7;
|
||||||
|
|
||||||
import java.lang.instrument.ClassFileTransformer;
|
import java.lang.instrument.ClassFileTransformer;
|
||||||
import java.lang.instrument.IllegalClassFormatException;
|
import java.lang.instrument.IllegalClassFormatException;
|
||||||
|
@ -34,6 +35,7 @@ import org.objectweb.asm.ClassVisitor;
|
||||||
import org.objectweb.asm.ClassWriter;
|
import org.objectweb.asm.ClassWriter;
|
||||||
|
|
||||||
import moe.yushi.authlibinjector.AuthlibInjector;
|
import moe.yushi.authlibinjector.AuthlibInjector;
|
||||||
|
import moe.yushi.authlibinjector.transform.TransformUnit.TransformContext;
|
||||||
import moe.yushi.authlibinjector.util.Logging;
|
import moe.yushi.authlibinjector.util.Logging;
|
||||||
|
|
||||||
public class ClassTransformer implements ClassFileTransformer {
|
public class ClassTransformer implements ClassFileTransformer {
|
||||||
|
@ -46,12 +48,71 @@ public class ClassTransformer implements ClassFileTransformer {
|
||||||
|
|
||||||
private static class TransformHandle {
|
private static class TransformHandle {
|
||||||
|
|
||||||
|
private static class TransformContextImpl implements TransformContext {
|
||||||
|
public boolean modifiedMark;
|
||||||
|
public int minVersionMark = -1;
|
||||||
|
public int upgradedVersionMark = -1;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void markModified() {
|
||||||
|
modifiedMark = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void requireMinimumClassVersion(int version) {
|
||||||
|
if (this.minVersionMark < version) {
|
||||||
|
this.minVersionMark = version;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void upgradeClassVersion(int version) {
|
||||||
|
if (this.upgradedVersionMark < version) {
|
||||||
|
this.upgradedVersionMark = version;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class ClassVersionException extends RuntimeException {
|
||||||
|
public ClassVersionException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ClassVersionTransformUnit implements TransformUnit {
|
||||||
|
@Override
|
||||||
|
public Optional<ClassVisitor> transform(ClassLoader classLoader, String className, ClassVisitor writer, TransformContext context) {
|
||||||
|
return Optional.of(new ClassVisitor(ASM7, writer) {
|
||||||
|
@Override
|
||||||
|
public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
|
||||||
|
int major = version & 0xffff;
|
||||||
|
|
||||||
|
if (minVersion != -1 && major < minVersion) {
|
||||||
|
throw new ClassVersionException("class version (" + major + ") is lower than required(" + minVersion + ")");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (upgradedVersion != -1 && major < upgradedVersion) {
|
||||||
|
Logging.TRANSFORM.fine("Upgrading class version from " + major + " to " + upgradedVersion);
|
||||||
|
version = upgradedVersion;
|
||||||
|
context.markModified();
|
||||||
|
}
|
||||||
|
super.visit(version, access, name, signature, superName, interfaces);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "Class File Version Transformer";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private List<TransformUnit> appliedTransformers;
|
private List<TransformUnit> appliedTransformers;
|
||||||
private boolean currentModified;
|
|
||||||
private String className;
|
private String className;
|
||||||
private byte[] classBuffer;
|
private byte[] classBuffer;
|
||||||
private ClassWriter pooledClassWriter;
|
|
||||||
private ClassLoader classLoader;
|
private ClassLoader classLoader;
|
||||||
|
private int minVersion = -1;
|
||||||
|
private int upgradedVersion = -1;
|
||||||
|
|
||||||
public TransformHandle(ClassLoader classLoader, String className, byte[] classBuffer) {
|
public TransformHandle(ClassLoader classLoader, String className, byte[] classBuffer) {
|
||||||
this.className = className;
|
this.className = className;
|
||||||
|
@ -60,37 +121,45 @@ public class ClassTransformer implements ClassFileTransformer {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void accept(TransformUnit unit) {
|
public void accept(TransformUnit unit) {
|
||||||
ClassWriter writer;
|
ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_MAXS);
|
||||||
if (pooledClassWriter == null) {
|
TransformContextImpl ctx = new TransformContextImpl();
|
||||||
writer = new ClassWriter(ClassWriter.COMPUTE_MAXS);
|
|
||||||
} else {
|
|
||||||
writer = pooledClassWriter;
|
|
||||||
pooledClassWriter = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
Optional<ClassVisitor> optionalVisitor = unit.transform(classLoader, className, writer, () -> currentModified = true);
|
Optional<ClassVisitor> optionalVisitor = unit.transform(classLoader, className, writer, ctx);
|
||||||
if (optionalVisitor.isPresent()) {
|
if (optionalVisitor.isPresent()) {
|
||||||
currentModified = false;
|
|
||||||
ClassReader reader = new ClassReader(classBuffer);
|
ClassReader reader = new ClassReader(classBuffer);
|
||||||
reader.accept(optionalVisitor.get(), 0);
|
reader.accept(optionalVisitor.get(), 0);
|
||||||
if (currentModified) {
|
if (ctx.modifiedMark) {
|
||||||
Logging.TRANSFORM.info("Transformed [" + className + "] with [" + unit + "]");
|
Logging.TRANSFORM.info("Transformed [" + className + "] with [" + unit + "]");
|
||||||
if (appliedTransformers == null) {
|
if (appliedTransformers == null) {
|
||||||
appliedTransformers = new ArrayList<>();
|
appliedTransformers = new ArrayList<>();
|
||||||
}
|
}
|
||||||
appliedTransformers.add(unit);
|
appliedTransformers.add(unit);
|
||||||
classBuffer = writer.toByteArray();
|
classBuffer = writer.toByteArray();
|
||||||
|
if (ctx.minVersionMark > this.minVersion) {
|
||||||
|
this.minVersion = ctx.minVersionMark;
|
||||||
|
}
|
||||||
|
if (ctx.upgradedVersionMark > this.upgradedVersion) {
|
||||||
|
this.upgradedVersion = ctx.upgradedVersionMark;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
pooledClassWriter = writer;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Optional<byte[]> getTransformResult() {
|
public Optional<byte[]> finish() {
|
||||||
if (appliedTransformers == null || appliedTransformers.isEmpty()) {
|
if (appliedTransformers == null || appliedTransformers.isEmpty()) {
|
||||||
return Optional.empty();
|
return Optional.empty();
|
||||||
} else {
|
} else {
|
||||||
return Optional.of(classBuffer);
|
if (minVersion == -1 && upgradedVersion == -1) {
|
||||||
|
return Optional.of(classBuffer);
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
accept(new ClassVersionTransformUnit());
|
||||||
|
return Optional.of(classBuffer);
|
||||||
|
} catch (ClassVersionException e) {
|
||||||
|
Logging.TRANSFORM.warning("Skipping [" + className + "], " + e.getMessage());
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -119,7 +188,7 @@ public class ClassTransformer implements ClassFileTransformer {
|
||||||
units.forEach(handle::accept);
|
units.forEach(handle::accept);
|
||||||
listeners.forEach(it -> it.onClassLoading(loader, className, handle.getFinalResult(), handle.getAppliedTransformers()));
|
listeners.forEach(it -> it.onClassLoading(loader, className, handle.getFinalResult(), handle.getAppliedTransformers()));
|
||||||
|
|
||||||
Optional<byte[]> transformResult = handle.getTransformResult();
|
Optional<byte[]> transformResult = handle.finish();
|
||||||
if (PRINT_UNTRANSFORMED_CLASSES && !transformResult.isPresent()) {
|
if (PRINT_UNTRANSFORMED_CLASSES && !transformResult.isPresent()) {
|
||||||
Logging.TRANSFORM.fine("No transformation is applied to [" + className + "]");
|
Logging.TRANSFORM.fine("No transformation is applied to [" + className + "]");
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,7 @@ import org.objectweb.asm.MethodVisitor;
|
||||||
public abstract class LdcTransformUnit implements TransformUnit {
|
public abstract class LdcTransformUnit implements TransformUnit {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Optional<ClassVisitor> transform(ClassLoader classLoader, String className, ClassVisitor writer, Runnable modifiedCallback) {
|
public Optional<ClassVisitor> transform(ClassLoader classLoader, String className, ClassVisitor writer, TransformContext ctx) {
|
||||||
return Optional.of(new ClassVisitor(ASM7, writer) {
|
return Optional.of(new ClassVisitor(ASM7, writer) {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -36,7 +36,7 @@ public abstract class LdcTransformUnit implements TransformUnit {
|
||||||
if (cst instanceof String) {
|
if (cst instanceof String) {
|
||||||
Optional<String> transformed = transformLdc((String) cst);
|
Optional<String> transformed = transformLdc((String) cst);
|
||||||
if (transformed.isPresent() && !transformed.get().equals(cst)) {
|
if (transformed.isPresent() && !transformed.get().equals(cst)) {
|
||||||
modifiedCallback.run();
|
ctx.markModified();
|
||||||
super.visitLdcInsn(transformed.get());
|
super.visitLdcInsn(transformed.get());
|
||||||
} else {
|
} else {
|
||||||
super.visitLdcInsn(cst);
|
super.visitLdcInsn(cst);
|
||||||
|
|
|
@ -20,7 +20,6 @@ import static java.util.stream.Collectors.joining;
|
||||||
import static org.objectweb.asm.Opcodes.ALOAD;
|
import static org.objectweb.asm.Opcodes.ALOAD;
|
||||||
import static org.objectweb.asm.Opcodes.ASM7;
|
import static org.objectweb.asm.Opcodes.ASM7;
|
||||||
import static org.objectweb.asm.Opcodes.ASTORE;
|
import static org.objectweb.asm.Opcodes.ASTORE;
|
||||||
import static org.objectweb.asm.Opcodes.INVOKESTATIC;
|
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
@ -31,14 +30,13 @@ import java.util.stream.Stream;
|
||||||
|
|
||||||
import org.objectweb.asm.ClassVisitor;
|
import org.objectweb.asm.ClassVisitor;
|
||||||
import org.objectweb.asm.MethodVisitor;
|
import org.objectweb.asm.MethodVisitor;
|
||||||
import org.objectweb.asm.Type;
|
|
||||||
|
|
||||||
import moe.yushi.authlibinjector.util.Logging;
|
import moe.yushi.authlibinjector.util.Logging;
|
||||||
|
|
||||||
public class MainArgumentsTransformer implements TransformUnit {
|
public class MainArgumentsTransformer implements TransformUnit {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Optional<ClassVisitor> transform(ClassLoader classLoader, String className, ClassVisitor writer, Runnable modifiedCallback) {
|
public Optional<ClassVisitor> transform(ClassLoader classLoader, String className, ClassVisitor writer, TransformContext ctx) {
|
||||||
if ("net.minecraft.client.main.Main".equals(className)) {
|
if ("net.minecraft.client.main.Main".equals(className)) {
|
||||||
return Optional.of(new ClassVisitor(ASM7, writer) {
|
return Optional.of(new ClassVisitor(ASM7, writer) {
|
||||||
@Override
|
@Override
|
||||||
|
@ -48,10 +46,10 @@ public class MainArgumentsTransformer implements TransformUnit {
|
||||||
@Override
|
@Override
|
||||||
public void visitCode() {
|
public void visitCode() {
|
||||||
super.visitCode();
|
super.visitCode();
|
||||||
modifiedCallback.run();
|
ctx.markModified();
|
||||||
|
|
||||||
super.visitVarInsn(ALOAD, 0);
|
super.visitVarInsn(ALOAD, 0);
|
||||||
super.visitMethodInsn(INVOKESTATIC, Type.getInternalName(MainArgumentsTransformer.class), "processMainArguments", "([Ljava/lang/String;)[Ljava/lang/String;", false);
|
CallbackSupport.invoke(ctx, mv, MainArgumentsTransformer.class, "processMainArguments");
|
||||||
super.visitVarInsn(ASTORE, 0);
|
super.visitVarInsn(ASTORE, 0);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -73,6 +71,7 @@ public class MainArgumentsTransformer implements TransformUnit {
|
||||||
// ==== Main arguments processing ====
|
// ==== Main arguments processing ====
|
||||||
private static final List<Function<String[], String[]>> ARGUMENTS_LISTENERS = new CopyOnWriteArrayList<>();
|
private static final List<Function<String[], String[]>> ARGUMENTS_LISTENERS = new CopyOnWriteArrayList<>();
|
||||||
|
|
||||||
|
@CallbackMethod
|
||||||
public static String[] processMainArguments(String[] args) {
|
public static String[] processMainArguments(String[] args) {
|
||||||
Logging.TRANSFORM.fine(() -> "Main arguments: " + Stream.of(args).collect(joining(" ")));
|
Logging.TRANSFORM.fine(() -> "Main arguments: " + Stream.of(args).collect(joining(" ")));
|
||||||
|
|
||||||
|
|
|
@ -37,7 +37,7 @@ public class SkinWhitelistTransformUnit implements TransformUnit {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Optional<ClassVisitor> transform(ClassLoader classLoader, String className, ClassVisitor writer, Runnable modifiedCallback) {
|
public Optional<ClassVisitor> transform(ClassLoader classLoader, String className, ClassVisitor writer, TransformContext ctx) {
|
||||||
if ("com.mojang.authlib.yggdrasil.YggdrasilMinecraftSessionService".equals(className)) {
|
if ("com.mojang.authlib.yggdrasil.YggdrasilMinecraftSessionService".equals(className)) {
|
||||||
return Optional.of(new ClassVisitor(ASM7, writer) {
|
return Optional.of(new ClassVisitor(ASM7, writer) {
|
||||||
|
|
||||||
|
@ -59,7 +59,7 @@ public class SkinWhitelistTransformUnit implements TransformUnit {
|
||||||
} else if ((status == 5 || status == 9) && opcode == AASTORE) {
|
} else if ((status == 5 || status == 9) && opcode == AASTORE) {
|
||||||
status++;
|
status++;
|
||||||
if (status == 10) {
|
if (status == 10) {
|
||||||
modifiedCallback.run();
|
ctx.markModified();
|
||||||
super.visitIntInsn(SIPUSH, skinWhitelist.length + 2);
|
super.visitIntInsn(SIPUSH, skinWhitelist.length + 2);
|
||||||
super.visitTypeInsn(ANEWARRAY, "java/lang/String");
|
super.visitTypeInsn(ANEWARRAY, "java/lang/String");
|
||||||
super.visitInsn(DUP);
|
super.visitInsn(DUP);
|
||||||
|
|
|
@ -21,6 +21,16 @@ import org.objectweb.asm.ClassVisitor;
|
||||||
|
|
||||||
public interface TransformUnit {
|
public interface TransformUnit {
|
||||||
|
|
||||||
Optional<ClassVisitor> transform(ClassLoader classLoader, String className, ClassVisitor writer, Runnable modifiedCallback);
|
public interface TransformContext {
|
||||||
|
|
||||||
|
void markModified();
|
||||||
|
|
||||||
|
void requireMinimumClassVersion(int version);
|
||||||
|
|
||||||
|
void upgradeClassVersion(int version);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Optional<ClassVisitor> transform(ClassLoader classLoader, String className, ClassVisitor writer, TransformContext context);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,18 +43,18 @@ import java.util.concurrent.CopyOnWriteArrayList;
|
||||||
import org.objectweb.asm.ClassVisitor;
|
import org.objectweb.asm.ClassVisitor;
|
||||||
import org.objectweb.asm.Label;
|
import org.objectweb.asm.Label;
|
||||||
import org.objectweb.asm.MethodVisitor;
|
import org.objectweb.asm.MethodVisitor;
|
||||||
import org.objectweb.asm.Type;
|
|
||||||
|
|
||||||
public class YggdrasilKeyTransformUnit implements TransformUnit {
|
public class YggdrasilKeyTransformUnit implements TransformUnit {
|
||||||
|
|
||||||
private static final List<PublicKey> PUBLIC_KEYS = new CopyOnWriteArrayList<>();
|
private static final List<PublicKey> PUBLIC_KEYS = new CopyOnWriteArrayList<>();
|
||||||
|
|
||||||
|
@CallbackMethod
|
||||||
public static List<PublicKey> getPublicKeys() {
|
public static List<PublicKey> getPublicKeys() {
|
||||||
return PUBLIC_KEYS;
|
return PUBLIC_KEYS;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Optional<ClassVisitor> transform(ClassLoader classLoader, String className, ClassVisitor writer, Runnable modifiedCallback) {
|
public Optional<ClassVisitor> transform(ClassLoader classLoader, String className, ClassVisitor writer, TransformContext ctx) {
|
||||||
if ("com.mojang.authlib.yggdrasil.YggdrasilMinecraftSessionService".equals(className)) {
|
if ("com.mojang.authlib.yggdrasil.YggdrasilMinecraftSessionService".equals(className)) {
|
||||||
return Optional.of(new ClassVisitor(ASM7, writer) {
|
return Optional.of(new ClassVisitor(ASM7, writer) {
|
||||||
|
|
||||||
|
@ -76,7 +76,7 @@ public class YggdrasilKeyTransformUnit implements TransformUnit {
|
||||||
mv.visitInsn(IRETURN);
|
mv.visitInsn(IRETURN);
|
||||||
mv.visitLabel(l0);
|
mv.visitLabel(l0);
|
||||||
mv.visitFrame(F_SAME, 0, null, 0, null);
|
mv.visitFrame(F_SAME, 0, null, 0, null);
|
||||||
mv.visitMethodInsn(INVOKESTATIC, Type.getInternalName(YggdrasilKeyTransformUnit.class), "getPublicKeys", "()Ljava/util/List;", false);
|
CallbackSupport.invoke(ctx, mv, YggdrasilKeyTransformUnit.class, "getPublicKeys");
|
||||||
mv.visitMethodInsn(INVOKEINTERFACE, "java/util/List", "iterator", "()Ljava/util/Iterator;", true);
|
mv.visitMethodInsn(INVOKEINTERFACE, "java/util/List", "iterator", "()Ljava/util/Iterator;", true);
|
||||||
mv.visitVarInsn(ASTORE, 2);
|
mv.visitVarInsn(ASTORE, 2);
|
||||||
Label l1 = new Label();
|
Label l1 = new Label();
|
||||||
|
@ -117,7 +117,7 @@ public class YggdrasilKeyTransformUnit implements TransformUnit {
|
||||||
&& "com/mojang/authlib/properties/Property".equals(owner)
|
&& "com/mojang/authlib/properties/Property".equals(owner)
|
||||||
&& "isSignatureValid".equals(name)
|
&& "isSignatureValid".equals(name)
|
||||||
&& "(Ljava/security/PublicKey;)Z".equals(descriptor)) {
|
&& "(Ljava/security/PublicKey;)Z".equals(descriptor)) {
|
||||||
modifiedCallback.run();
|
ctx.markModified();
|
||||||
super.visitMethodInsn(INVOKESTATIC,
|
super.visitMethodInsn(INVOKESTATIC,
|
||||||
"com/mojang/authlib/yggdrasil/YggdrasilMinecraftSessionService",
|
"com/mojang/authlib/yggdrasil/YggdrasilMinecraftSessionService",
|
||||||
"authlib_injector_isSignatureValid",
|
"authlib_injector_isSignatureValid",
|
||||||
|
|
|
@ -42,7 +42,7 @@ import moe.yushi.authlibinjector.transform.TransformUnit;
|
||||||
public class CitizensTransformer implements TransformUnit {
|
public class CitizensTransformer implements TransformUnit {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Optional<ClassVisitor> transform(ClassLoader classLoader, String className, ClassVisitor writer, Runnable modifiedCallback) {
|
public Optional<ClassVisitor> transform(ClassLoader classLoader, String className, ClassVisitor writer, TransformContext ctx) {
|
||||||
if ("net.citizensnpcs.Settings$Setting".equals(className)) {
|
if ("net.citizensnpcs.Settings$Setting".equals(className)) {
|
||||||
return Optional.of(new ClassVisitor(ASM7, writer) {
|
return Optional.of(new ClassVisitor(ASM7, writer) {
|
||||||
@Override
|
@Override
|
||||||
|
@ -62,7 +62,7 @@ public class CitizensTransformer implements TransformUnit {
|
||||||
super.visitInsn(RETURN);
|
super.visitInsn(RETURN);
|
||||||
super.visitLabel(lbl);
|
super.visitLabel(lbl);
|
||||||
super.visitFrame(F_SAME, 0, null, 0, null);
|
super.visitFrame(F_SAME, 0, null, 0, null);
|
||||||
modifiedCallback.run();
|
ctx.markModified();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,66 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2019 Haowei Wen <yushijinhun@gmail.com> and contributors
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Affero General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
package moe.yushi.authlibinjector.transform.support;
|
|
||||||
|
|
||||||
import static org.objectweb.asm.Opcodes.ALOAD;
|
|
||||||
import static org.objectweb.asm.Opcodes.ASM7;
|
|
||||||
import static org.objectweb.asm.Opcodes.INVOKEVIRTUAL;
|
|
||||||
import static org.objectweb.asm.Opcodes.RETURN;
|
|
||||||
|
|
||||||
import java.util.Optional;
|
|
||||||
|
|
||||||
import org.objectweb.asm.ClassVisitor;
|
|
||||||
import org.objectweb.asm.MethodVisitor;
|
|
||||||
|
|
||||||
import moe.yushi.authlibinjector.transform.TransformUnit;
|
|
||||||
|
|
||||||
public class LaunchWrapperTransformer implements TransformUnit {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Optional<ClassVisitor> transform(ClassLoader classLoader, String className, ClassVisitor writer, Runnable modifiedCallback) {
|
|
||||||
if ("net.minecraft.launchwrapper.LaunchClassLoader".equals(className)) {
|
|
||||||
return Optional.of(new ClassVisitor(ASM7, writer) {
|
|
||||||
@Override
|
|
||||||
public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) {
|
|
||||||
if ("<init>".equals(name)) {
|
|
||||||
return new MethodVisitor(ASM7, super.visitMethod(access, name, descriptor, signature, exceptions)) {
|
|
||||||
@Override
|
|
||||||
public void visitInsn(int opcode) {
|
|
||||||
if (opcode == RETURN) {
|
|
||||||
modifiedCallback.run();
|
|
||||||
super.visitVarInsn(ALOAD, 0);
|
|
||||||
super.visitLdcInsn("moe.yushi.authlibinjector.");
|
|
||||||
super.visitMethodInsn(INVOKEVIRTUAL, "net/minecraft/launchwrapper/LaunchClassLoader", "addClassLoaderExclusion", "(Ljava/lang/String;)V", false);
|
|
||||||
}
|
|
||||||
super.visitInsn(opcode);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
return super.visitMethod(access, name, descriptor, signature, exceptions);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
return Optional.empty();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return "LaunchWrapper Support";
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -60,7 +60,7 @@ public class MC52974Workaround implements TransformUnit {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Optional<ClassVisitor> transform(ClassLoader classLoader, String className, ClassVisitor writer, Runnable modifiedCallback) {
|
public Optional<ClassVisitor> transform(ClassLoader classLoader, String className, ClassVisitor writer, TransformContext ctx) {
|
||||||
if ("com.mojang.authlib.yggdrasil.YggdrasilMinecraftSessionService".equals(className)) {
|
if ("com.mojang.authlib.yggdrasil.YggdrasilMinecraftSessionService".equals(className)) {
|
||||||
return Optional.of(new ClassVisitor(ASM7, writer) {
|
return Optional.of(new ClassVisitor(ASM7, writer) {
|
||||||
@Override
|
@Override
|
||||||
|
@ -70,7 +70,7 @@ public class MC52974Workaround implements TransformUnit {
|
||||||
@Override
|
@Override
|
||||||
public void visitCode() {
|
public void visitCode() {
|
||||||
super.visitCode();
|
super.visitCode();
|
||||||
modifiedCallback.run();
|
ctx.markModified();
|
||||||
super.visitLdcInsn(1);
|
super.visitLdcInsn(1);
|
||||||
super.visitVarInsn(ISTORE, 2);
|
super.visitVarInsn(ISTORE, 2);
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,9 +31,10 @@ import java.util.logging.Level;
|
||||||
|
|
||||||
import org.objectweb.asm.ClassVisitor;
|
import org.objectweb.asm.ClassVisitor;
|
||||||
import org.objectweb.asm.MethodVisitor;
|
import org.objectweb.asm.MethodVisitor;
|
||||||
import org.objectweb.asm.Type;
|
|
||||||
|
|
||||||
import moe.yushi.authlibinjector.AuthlibInjector;
|
import moe.yushi.authlibinjector.AuthlibInjector;
|
||||||
|
import moe.yushi.authlibinjector.transform.CallbackMethod;
|
||||||
|
import moe.yushi.authlibinjector.transform.CallbackSupport;
|
||||||
import moe.yushi.authlibinjector.transform.MainArgumentsTransformer;
|
import moe.yushi.authlibinjector.transform.MainArgumentsTransformer;
|
||||||
import moe.yushi.authlibinjector.transform.TransformUnit;
|
import moe.yushi.authlibinjector.transform.TransformUnit;
|
||||||
import moe.yushi.authlibinjector.util.Logging;
|
import moe.yushi.authlibinjector.util.Logging;
|
||||||
|
@ -57,12 +58,14 @@ public class MC52974_1710Workaround {
|
||||||
// Empty GameProfile -> Filled GameProfile?
|
// Empty GameProfile -> Filled GameProfile?
|
||||||
private static final Map<Object, Optional<Object>> markedGameProfiles = new WeakIdentityHashMap<>();
|
private static final Map<Object, Optional<Object>> markedGameProfiles = new WeakIdentityHashMap<>();
|
||||||
|
|
||||||
|
@CallbackMethod
|
||||||
public static void markGameProfile(Object gp) {
|
public static void markGameProfile(Object gp) {
|
||||||
synchronized (markedGameProfiles) {
|
synchronized (markedGameProfiles) {
|
||||||
markedGameProfiles.putIfAbsent(gp, Optional.empty());
|
markedGameProfiles.putIfAbsent(gp, Optional.empty());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@CallbackMethod
|
||||||
public static Object accessGameProfile(Object gp, Object minecraftServer, boolean isNotchName) {
|
public static Object accessGameProfile(Object gp, Object minecraftServer, boolean isNotchName) {
|
||||||
synchronized (markedGameProfiles) {
|
synchronized (markedGameProfiles) {
|
||||||
Optional<Object> value = markedGameProfiles.get(gp);
|
Optional<Object> value = markedGameProfiles.get(gp);
|
||||||
|
@ -105,7 +108,7 @@ public class MC52974_1710Workaround {
|
||||||
|
|
||||||
private static class SessionTransformer implements TransformUnit {
|
private static class SessionTransformer implements TransformUnit {
|
||||||
@Override
|
@Override
|
||||||
public Optional<ClassVisitor> transform(ClassLoader classLoader, String className, ClassVisitor writer, Runnable modifiedCallback) {
|
public Optional<ClassVisitor> transform(ClassLoader classLoader, String className, ClassVisitor writer, TransformContext ctx) {
|
||||||
return detectNotchName(className, "bbs", "net.minecraft.util.Session", isNotchName -> new ClassVisitor(ASM7, writer) {
|
return detectNotchName(className, "bbs", "net.minecraft.util.Session", isNotchName -> new ClassVisitor(ASM7, writer) {
|
||||||
@Override
|
@Override
|
||||||
public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) {
|
public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) {
|
||||||
|
@ -117,9 +120,9 @@ public class MC52974_1710Workaround {
|
||||||
@Override
|
@Override
|
||||||
public void visitInsn(int opcode) {
|
public void visitInsn(int opcode) {
|
||||||
if (opcode == ARETURN) {
|
if (opcode == ARETURN) {
|
||||||
modifiedCallback.run();
|
ctx.markModified();
|
||||||
super.visitInsn(DUP);
|
super.visitInsn(DUP);
|
||||||
super.visitMethodInsn(INVOKESTATIC, Type.getInternalName(MC52974_1710Workaround.class), "markGameProfile", "(Ljava/lang/Object;)V", false);
|
CallbackSupport.invoke(ctx, mv, MC52974_1710Workaround.class, "markGameProfile");
|
||||||
}
|
}
|
||||||
super.visitInsn(opcode);
|
super.visitInsn(opcode);
|
||||||
}
|
}
|
||||||
|
@ -139,7 +142,7 @@ public class MC52974_1710Workaround {
|
||||||
|
|
||||||
private static class S0CPacketSpawnPlayerTransformer implements TransformUnit {
|
private static class S0CPacketSpawnPlayerTransformer implements TransformUnit {
|
||||||
@Override
|
@Override
|
||||||
public Optional<ClassVisitor> transform(ClassLoader classLoader, String className, ClassVisitor writer, Runnable modifiedCallback) {
|
public Optional<ClassVisitor> transform(ClassLoader classLoader, String className, ClassVisitor writer, TransformContext ctx) {
|
||||||
return detectNotchName(className, "gb", "net.minecraft.network.play.server.S0CPacketSpawnPlayer", isNotchName -> new ClassVisitor(ASM7, writer) {
|
return detectNotchName(className, "gb", "net.minecraft.network.play.server.S0CPacketSpawnPlayer", isNotchName -> new ClassVisitor(ASM7, writer) {
|
||||||
@Override
|
@Override
|
||||||
public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) {
|
public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) {
|
||||||
|
@ -155,14 +158,14 @@ public class MC52974_1710Workaround {
|
||||||
if (opcode == GETFIELD && (isNotchName
|
if (opcode == GETFIELD && (isNotchName
|
||||||
? "gb".equals(owner) && "b".equals(name) && "Lcom/mojang/authlib/GameProfile;".equals(descriptor)
|
? "gb".equals(owner) && "b".equals(name) && "Lcom/mojang/authlib/GameProfile;".equals(descriptor)
|
||||||
: "net/minecraft/network/play/server/S0CPacketSpawnPlayer".equals(owner) && "field_148955_b".equals(name) && "Lcom/mojang/authlib/GameProfile;".equals(descriptor))) {
|
: "net/minecraft/network/play/server/S0CPacketSpawnPlayer".equals(owner) && "field_148955_b".equals(name) && "Lcom/mojang/authlib/GameProfile;".equals(descriptor))) {
|
||||||
modifiedCallback.run();
|
ctx.markModified();
|
||||||
if (isNotchName) {
|
if (isNotchName) {
|
||||||
super.visitMethodInsn(INVOKESTATIC, "net/minecraft/server/MinecraftServer", "I", "()Lnet/minecraft/server/MinecraftServer;", false);
|
super.visitMethodInsn(INVOKESTATIC, "net/minecraft/server/MinecraftServer", "I", "()Lnet/minecraft/server/MinecraftServer;", false);
|
||||||
} else {
|
} else {
|
||||||
super.visitMethodInsn(INVOKESTATIC, "net/minecraft/server/MinecraftServer", "func_71276_C", "()Lnet/minecraft/server/MinecraftServer;", false);
|
super.visitMethodInsn(INVOKESTATIC, "net/minecraft/server/MinecraftServer", "func_71276_C", "()Lnet/minecraft/server/MinecraftServer;", false);
|
||||||
}
|
}
|
||||||
super.visitLdcInsn(isNotchName ? 1 : 0);
|
super.visitLdcInsn(isNotchName ? 1 : 0);
|
||||||
super.visitMethodInsn(INVOKESTATIC, Type.getInternalName(MC52974_1710Workaround.class), "accessGameProfile", "(Ljava/lang/Object;Ljava/lang/Object;Z)Ljava/lang/Object;", false);
|
CallbackSupport.invoke(ctx, mv, MC52974_1710Workaround.class, "accessGameProfile");
|
||||||
super.visitTypeInsn(CHECKCAST, "com/mojang/authlib/GameProfile");
|
super.visitTypeInsn(CHECKCAST, "com/mojang/authlib/GameProfile");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue