2021-01-03 02:53:57 +08:00
|
|
|
package customskinloader.fabric;
|
|
|
|
|
|
|
|
|
|
import java.lang.reflect.Field;
|
2022-04-14 19:52:11 +08:00
|
|
|
import java.util.AbstractMap;
|
|
|
|
|
import java.util.ArrayList;
|
2021-01-03 02:53:57 +08:00
|
|
|
import java.util.HashMap;
|
|
|
|
|
import java.util.List;
|
|
|
|
|
import java.util.Map;
|
|
|
|
|
import java.util.Objects;
|
|
|
|
|
|
|
|
|
|
import com.google.common.collect.Lists;
|
|
|
|
|
import net.fabricmc.loader.api.FabricLoader;
|
2021-10-16 01:41:54 +08:00
|
|
|
import net.fabricmc.loader.impl.FabricLoaderImpl;
|
|
|
|
|
import net.fabricmc.loader.impl.game.patch.GameTransformer;
|
2021-01-03 02:53:57 +08:00
|
|
|
import org.apache.commons.io.IOUtils;
|
|
|
|
|
import org.objectweb.asm.ClassReader;
|
|
|
|
|
import org.objectweb.asm.ClassWriter;
|
|
|
|
|
import org.objectweb.asm.Type;
|
|
|
|
|
import org.objectweb.asm.commons.ClassRemapper;
|
|
|
|
|
import org.objectweb.asm.commons.SimpleRemapper;
|
|
|
|
|
import org.objectweb.asm.tree.ClassNode;
|
|
|
|
|
|
|
|
|
|
public class DevEnvRemapper extends SimpleRemapper {
|
2022-04-14 19:52:11 +08:00
|
|
|
// key: correct method owner names,
|
|
|
|
|
// value:
|
|
|
|
|
// left: fake method owner names,
|
|
|
|
|
// right: other classes which contain fake methods.
|
|
|
|
|
private static Map<String, Map.Entry<List<String>, List<String>>> remappedClasses = new HashMap<>();
|
2021-01-03 02:53:57 +08:00
|
|
|
|
|
|
|
|
static {
|
2022-04-14 19:52:11 +08:00
|
|
|
remappedClasses.put(
|
|
|
|
|
"net.minecraft.class_310",
|
|
|
|
|
new AbstractMap.SimpleEntry<>(
|
|
|
|
|
Lists.newArrayList("customskinloader.fake.itf.IFakeMinecraft"),
|
|
|
|
|
Lists.newArrayList("customskinloader.fake.itf.FakeInterfaceManager")
|
|
|
|
|
)
|
|
|
|
|
);
|
|
|
|
|
remappedClasses.put(
|
|
|
|
|
"net.minecraft.class_3298",
|
|
|
|
|
new AbstractMap.SimpleEntry<>(
|
|
|
|
|
Lists.newArrayList("customskinloader.fake.itf.IFakeIResource"),
|
|
|
|
|
Lists.newArrayList("customskinloader.fake.itf.FakeInterfaceManager")
|
|
|
|
|
)
|
|
|
|
|
);
|
|
|
|
|
remappedClasses.put(
|
|
|
|
|
"net.minecraft.class_3300",
|
|
|
|
|
new AbstractMap.SimpleEntry<>(
|
|
|
|
|
Lists.newArrayList("customskinloader.fake.itf.IFakeIResourceManager"),
|
|
|
|
|
Lists.newArrayList("customskinloader.fake.itf.FakeInterfaceManager")
|
|
|
|
|
)
|
|
|
|
|
);
|
2021-01-03 02:53:57 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@SuppressWarnings("unchecked")
|
|
|
|
|
public static void initRemapper() {
|
|
|
|
|
try {
|
|
|
|
|
if (FabricLoader.getInstance().isDevelopmentEnvironment()) {
|
|
|
|
|
ClassLoader cl = Thread.currentThread().getContextClassLoader();
|
2021-10-16 01:41:54 +08:00
|
|
|
Field patchedClassesField = GameTransformer.class.getDeclaredField("patchedClasses");
|
2021-01-03 02:53:57 +08:00
|
|
|
patchedClassesField.setAccessible(true);
|
2021-10-16 01:41:54 +08:00
|
|
|
Map<String, byte[]> patchedClasses = (Map<String, byte[]>) patchedClassesField.get(FabricLoaderImpl.INSTANCE.getGameProvider().getEntrypointTransformer());
|
2021-01-03 02:53:57 +08:00
|
|
|
|
2022-04-14 19:52:11 +08:00
|
|
|
for (Map.Entry<String, Map.Entry<List<String>, List<String>>> entry : remappedClasses.entrySet()) {
|
|
|
|
|
List<String> targetClasses = new ArrayList<>(entry.getValue().getKey());
|
|
|
|
|
targetClasses.addAll(entry.getValue().getValue());
|
|
|
|
|
for (String clazz : targetClasses) {
|
2021-01-03 02:53:57 +08:00
|
|
|
byte[] classBytes = patchedClasses.get(clazz);
|
|
|
|
|
if (classBytes == null) {
|
|
|
|
|
classBytes = IOUtils.toByteArray(Objects.requireNonNull(cl.getResourceAsStream(clazz.replace(".", "/") + ".class")));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
patchedClasses.put(clazz, remapClass(entry.getKey(), classBytes));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} catch (Throwable t) {
|
|
|
|
|
MixinConfigPlugin.logger.warning(t);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Remap all method names with specific method owner name.
|
|
|
|
|
public static byte[] remapClass(String owner, byte[] bytes) {
|
|
|
|
|
ClassNode cn = new ClassNode();
|
|
|
|
|
new ClassReader(bytes).accept(new ClassRemapper(cn, new DevEnvRemapper(owner)), ClassReader.EXPAND_FRAMES);
|
|
|
|
|
|
|
|
|
|
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);
|
|
|
|
|
cn.accept(cw);
|
|
|
|
|
return cw.toByteArray();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private final String owner;
|
2021-07-25 15:48:50 +08:00
|
|
|
private final SimpleRemapper remapper = new SimpleRemapper(new HashMap<>()) {
|
|
|
|
|
@Override
|
|
|
|
|
public String map(String key) {
|
|
|
|
|
return FabricLoader.getInstance().getMappingResolver().unmapClassName("intermediary", Type.getType("L" + key + ";").getClassName()).replace(".", "/");
|
|
|
|
|
}
|
|
|
|
|
};
|
2021-01-03 02:53:57 +08:00
|
|
|
|
|
|
|
|
public DevEnvRemapper(String owner) {
|
|
|
|
|
super(new HashMap<>());
|
|
|
|
|
this.owner = owner;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public String mapMethodName(String owner, String name, String desc) {
|
|
|
|
|
// Method desc should be unmapped in the development environment.
|
2021-07-25 15:48:50 +08:00
|
|
|
desc = this.remapper.mapDesc(desc);
|
2021-01-03 02:53:57 +08:00
|
|
|
|
2022-04-14 19:52:11 +08:00
|
|
|
String s = this.isFakeOwner(owner) ? FabricLoader.getInstance().getMappingResolver().mapMethodName("intermediary", this.owner, name, desc) : name;
|
2021-01-03 02:53:57 +08:00
|
|
|
return s == null ? name : s;
|
|
|
|
|
}
|
2022-04-14 19:52:11 +08:00
|
|
|
|
|
|
|
|
private boolean isFakeOwner(String owner) {
|
|
|
|
|
return remappedClasses.get(this.owner).getKey().contains(owner.replace("/", "."));
|
|
|
|
|
}
|
2021-01-03 02:53:57 +08:00
|
|
|
}
|