Last active
April 12, 2021 12:59
-
-
Save ZekerZhayard/2a4310dd7525f15a00cc1db37ebca0ae to your computer and use it in GitHub Desktop.
custom_earlyloading_screen
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package io.github.zekerzhayard.custom_earlyloading_screen; | |
import java.lang.invoke.MethodHandles; | |
import java.lang.reflect.Field; | |
import java.net.URLClassLoader; | |
import sun.misc.Unsafe; | |
public class Constants { | |
public final static Unsafe UNSAFE; | |
public final static MethodHandles.Lookup IMPL_LOOKUP; | |
public final static ClassLoader APP_CLASS_LOADER = ClassLoader.getSystemClassLoader(); | |
public final static boolean IS_JAVA_8 = APP_CLASS_LOADER instanceof URLClassLoader; | |
public final static String PACKAGE_NAME = IS_JAVA_8 ? "sun.misc." : "jdk.internal.loader."; | |
public final static Class<?> URL_CLASS_PATH_CLASS; | |
public final static Object UCP; | |
static { | |
try { | |
Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe"); | |
unsafeField.setAccessible(true); | |
UNSAFE = (Unsafe) unsafeField.get(null); | |
Field implLookupField = MethodHandles.Lookup.class.getDeclaredField("IMPL_LOOKUP"); | |
IMPL_LOOKUP = (MethodHandles.Lookup) UNSAFE.getObject(UNSAFE.staticFieldBase(implLookupField), UNSAFE.staticFieldOffset(implLookupField)); | |
URL_CLASS_PATH_CLASS = Class.forName(PACKAGE_NAME + "URLClassPath"); | |
UCP = IMPL_LOOKUP.findGetter(APP_CLASS_LOADER.getClass().getSuperclass(), "ucp", URL_CLASS_PATH_CLASS).invokeWithArguments(APP_CLASS_LOADER); | |
} catch (Throwable t) { | |
throw new RuntimeException(t); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package io.github.zekerzhayard.custom_earlyloading_screen; | |
import java.util.List; | |
import java.util.Set; | |
import javax.annotation.Nonnull; | |
import com.google.common.collect.Lists; | |
import cpw.mods.modlauncher.api.IEnvironment; | |
import cpw.mods.modlauncher.api.ITransformationService; | |
import cpw.mods.modlauncher.api.ITransformer; | |
public class Entrance implements ITransformationService { | |
@Nonnull | |
@Override | |
public String name() { | |
return "custom_earlyloading_screen"; | |
} | |
@Override | |
public void initialize(@Nonnull IEnvironment environment) { | |
} | |
@Override | |
public void beginScanning(@Nonnull IEnvironment environment) { | |
} | |
@Override | |
public void onLoad(@Nonnull IEnvironment env, @Nonnull Set<String> otherServices) { | |
try { | |
Transformer.start(); | |
} catch (Throwable t) { | |
throw new RuntimeException(t); | |
} | |
} | |
@Nonnull | |
@Override | |
@SuppressWarnings("rawtypes") | |
public List<ITransformer> transformers() { | |
return Lists.newArrayList(); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package io.github.zekerzhayard.custom_earlyloading_screen; | |
import java.io.ByteArrayInputStream; | |
import java.io.IOException; | |
import java.io.InputStream; | |
import java.lang.invoke.MethodType; | |
import java.lang.reflect.Field; | |
import java.lang.reflect.Modifier; | |
import java.nio.file.Files; | |
import java.nio.file.Paths; | |
import java.util.ArrayList; | |
import java.util.Objects; | |
import java.util.jar.JarFile; | |
import java.util.zip.ZipEntry; | |
import net.minecraftforge.fml.loading.FMLServiceProvider; | |
import org.apache.commons.io.IOUtils; | |
public class FakeJarFile extends JarFile { | |
public static void replaceLoaders() throws Throwable { | |
ArrayList<?> loaders = (ArrayList<?>) Constants.IMPL_LOOKUP.findGetter(Constants.URL_CLASS_PATH_CLASS, "loaders", ArrayList.class).invokeWithArguments(Constants.UCP); | |
Class<?> jarLoaderClass = Class.forName(Constants.PACKAGE_NAME + "URLClassPath$JarLoader"); | |
for (Object loader : loaders) { | |
if (jarLoaderClass.isInstance(loader)) { | |
JarFile jar = (JarFile) Constants.IMPL_LOOKUP.findGetter(jarLoaderClass, "jar", JarFile.class).invokeWithArguments(loader); | |
if (jar != null && Files.isSameFile(Paths.get(jar.getName()), Paths.get(FMLServiceProvider.class.getProtectionDomain().getCodeSource().getLocation().toURI()))) { | |
FakeJarFile fakeJarFile = (FakeJarFile) Constants.UNSAFE.allocateInstance(FakeJarFile.class); | |
fakeJarFile.clone(jar, JarFile.class); | |
Constants.IMPL_LOOKUP.findSetter(jarLoaderClass, "jar", JarFile.class).invokeWithArguments(loader, fakeJarFile); | |
} | |
} | |
} | |
} | |
// This constructor will be skipped. | |
public FakeJarFile(String name) throws IOException { | |
super(name); | |
} | |
public void clone(JarFile jarFile, Class<?> clazz) throws Throwable { | |
if (clazz == null || !clazz.isInstance(jarFile)) { | |
return; | |
} | |
Field[] fields = (Field[]) Constants.IMPL_LOOKUP.findVirtual(Class.class, "getDeclaredFields0", MethodType.methodType(Field[].class, boolean.class)).invokeWithArguments(clazz, false); | |
for (Field field : fields) { | |
if ((field.getModifiers() | Modifier.STATIC) != field.getModifiers()) { | |
Constants.IMPL_LOOKUP.findSetter(field.getDeclaringClass(), field.getName(), field.getType()) | |
.invokeWithArguments(this, Constants.IMPL_LOOKUP.findGetter(field.getDeclaringClass(), field.getName(), field.getType()).invokeWithArguments(jarFile)); | |
} | |
} | |
this.clone(jarFile, clazz.getSuperclass()); | |
} | |
@Override | |
public synchronized InputStream getInputStream(ZipEntry ze) throws IOException { | |
InputStream is = super.getInputStream(ze); | |
if (ze == null || !Objects.equals(ze.getName(), "net/minecraftforge/fml/loading/progress/ClientVisualization.class")) { | |
return is; | |
} | |
byte[] classBytes = Transformer.transform(IOUtils.toByteArray(is)); | |
ze.setSize(classBytes.length); | |
return new ByteArrayInputStream(classBytes); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package io.github.zekerzhayard.custom_earlyloading_screen; | |
import java.util.Objects; | |
import org.objectweb.asm.ClassReader; | |
import org.objectweb.asm.ClassWriter; | |
import org.objectweb.asm.Opcodes; | |
import org.objectweb.asm.tree.AbstractInsnNode; | |
import org.objectweb.asm.tree.ClassNode; | |
import org.objectweb.asm.tree.InsnList; | |
import org.objectweb.asm.tree.InsnNode; | |
import org.objectweb.asm.tree.LdcInsnNode; | |
import org.objectweb.asm.tree.MethodInsnNode; | |
import org.objectweb.asm.tree.MethodNode; | |
public class Transformer { | |
public static void start() throws Throwable { | |
FakeJarFile.replaceLoaders(); | |
} | |
public static byte[] transform(byte[] input) { | |
ClassNode cn = new ClassNode(); | |
new ClassReader(input).accept(cn, ClassReader.EXPAND_FRAMES); | |
for (MethodNode mn : cn.methods) { | |
if (Objects.equals(mn.name, "renderBackground") && Objects.equals(mn.desc, "()V")) { | |
for (AbstractInsnNode ain : mn.instructions.toArray()) { | |
if (ain.getOpcode() == Opcodes.INVOKESTATIC) { | |
MethodInsnNode min = (MethodInsnNode) ain; | |
if (Objects.equals(min.owner, "org/lwjgl/opengl/GL11") && Objects.equals(min.name, "glColor4f") && Objects.equals(min.desc, "(FFFF)V")) { | |
InsnList il = new InsnList(); | |
il.add(new InsnNode(Opcodes.POP2)); | |
il.add(new InsnNode(Opcodes.POP2)); | |
il.add(new LdcInsnNode(0x2E / 255F)); | |
il.add(new LdcInsnNode(34 / 255F)); | |
il.add(new LdcInsnNode(40 / 255F)); | |
il.add(new InsnNode(Opcodes.FCONST_1)); | |
mn.instructions.insertBefore(min, il); | |
} | |
} | |
} | |
} | |
} | |
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES); | |
cn.accept(cw); | |
return cw.toByteArray(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment