package coloredlightscore.src.asm.transformer.core;
import cpw.mods.fml.common.FMLLog;
import org.objectweb.asm.Type;
import org.objectweb.asm.tree.MethodNode;
import java.util.HashMap;
public class NameMapper {
private HashMap<String, SeargeData> m_NameList;
private static NameMapper INSTANCE = null;
private boolean MCP_ENVIRONMENT = false;
public static NameMapper getInstance() {
if (INSTANCE == null)
INSTANCE = new NameMapper();
return INSTANCE;
}
public NameMapper() {
m_NameList = new HashMap<>();
// ***********************************************
// CLASSES (CL) AND METHODS (MD) SHOULD COME FROM MCP-NOTCH.SRG
// FIELDS (FD) SHOULD COME FROM MCP-SRG.SRG
// Block
registerSrgName("CL: net/minecraft/block/Block aji");
registerSrgName("MD: net/minecraft/block/Block/setLightLevel (F)Lnet/minecraft/block/Block; aji/a (F)Laji;");
// ChunkCache
registerSrgName("CL: net/minecraft/world/ChunkCache ahr");
registerSrgName("MD: net/minecraft/world/ChunkCache/getLightBrightnessForSkyBlocks (IIII)I ahr/c (IIII)I");
// EntityPlayerMP
registerSrgName("CL: net/minecraft/entity/player/EntityPlayerMP mw");
registerSrgName("MD: net/minecraft/entity/player/EntityPlayerMP/onUpdate ()V mw/h ()V");
// EntityRenderer
registerSrgName("CL: net/minecraft/client/renderer/EntityRenderer blt");
registerSrgName("MD: net/minecraft/client/renderer/EntityRenderer/updateLightmap (F)V blt/i (F)V");
// ExtendedBlockStorage
registerSrgName("CL: net/minecraft/world/chunk/storage/ExtendedBlockStorage apz");
registerSrgName("MD: net/minecraft/world/chunk/storage/ExtendedBlockStorage/setExtBlocklightValue (IIII)V apz/c (IIII)V");
registerSrgName("MD: net/minecraft/world/chunk/storage/ExtendedBlockStorage/getExtBlocklightValue (III)I apz/d (III)I");
registerSrgName("FD: net/minecraft/world/chunk/storage/ExtendedBlockStorage/blockLSBArray net/minecraft/world/chunk/storage/ExtendedBlockStorage/field_76680_d");
// PlayerInstance
registerSrgName("CL: net/minecraft/server/management/PlayerManager$PlayerInstance mr");
registerSrgName("MD: net/minecraft/server/management/PlayerManager$PlayerInstance/sendToAllPlayersWatchingChunk (Lnet/minecraft/network/Packet;)V mr/a (Lft;)V");
registerSrgName("FD: net/minecraft/server/management/PlayerManager$PlayerInstance/chunkLocation net/minecraft/server/management/PlayerManager$PlayerInstance/field_73264_c");
// RenderBlocks
registerSrgName("CL: net/minecraft/client/renderer/RenderBlocks blm");
registerSrgName("MD: net/minecraft/client/renderer/RenderBlocks/renderStandardBlockWithAmbientOcclusion (Lnet/minecraft/block/Block;IIIFFF)Z blm/a (Laji;IIIFFF)Z");
registerSrgName("MD: net/minecraft/client/renderer/RenderBlocks/renderStandardBlockWithColorMultiplier (Lnet/minecraft/block/Block;IIIFFF)Z blm/d (Laji;IIIFFF)Z");
// Tessellator
registerSrgName("CL: net/minecraft/client/renderer/Tessellator bmh");
registerSrgName("MD: net/minecraft/client/renderer/Tessellator/setBrightness (I)V bmh/b (I)V");
// World
registerSrgName("CL: net/minecraft/world/World ahb");
registerSrgName("MD: net/minecraft/world/World/getBlockLightValue_do (IIIZ)I ahb/b (IIIZ)I");
registerSrgName("MD: net/minecraft/world/World/getLightBrightnessForSkyBlocks (IIII)I ahb/c (IIII)I");
registerSrgName("MD: net/minecraft/world/World/getLightBrightness (III)F ahb/n (III)F");
registerSrgName("MD: net/minecraft/world/World/computeLightValue (IIILnet/minecraft/world/EnumSkyBlock;)I ahb/a (IIILahn;)I");
registerSrgName("MD: net/minecraft/world/World/updateLightByType (Lnet/minecraft/world/EnumSkyBlock;III)Z ahb/c (Lahn;III)Z");
// NetHandlerPlayServer
registerSrgName("CL: net/minecraft/network/NetHandlerPlayServer io");
registerSrgName("MD: net/minecraft/network/NetHandlerPlayServer/sendPacket (Lnet/minecraft/network/Packet;)V nh/a (Lft;)V");
// NibbleArray
registerSrgName("CL: net/minecraft/world/chunk/NibbleArray apv");
registerSrgName("MD: net/minecraft/world/chunk/NibbleArray/get (III)I apv/a (III)I");
registerSrgName("MD: net/minecraft/world/chunk/NibbleArray/set (IIII)V apv/a (IIII)V");
// S26PacketMapChunkBulk
registerSrgName("CL: net/minecraft/network/play/server/S26PacketMapChunkBulk gz");
// ***********************************************
MCP_ENVIRONMENT = (this.getClass().getClassLoader().getResource("net/minecraft/world/World.class") != null);
FMLLog.info("ColoredLightsCore: MCP_ENVIORNMENT=%s", MCP_ENVIRONMENT);
}
public boolean isObfuscated() {
return !MCP_ENVIRONMENT;
}
/**
* Returns the appropriate obfuscated or unobfuscated class name for a Minecraft class
*
* @param className De-obfuscated class name, in either dot or internal format.
* @return renamed class
*/
public String getClassName(String className) {
String indexer = internalizeName(className);
SeargeData srg = m_NameList.get(indexer);
return (srg == null ? className : (MCP_ENVIRONMENT ? srg.objectName : srg.objectNameObfuscated));
}
/**
* Given a method name in path/to/class/methodname or path.to.class.methodname format
* Returns proper method name in path/to/class/methodname format
*
* @param ownerName The de-obfuscated class that contains the method (dot or internal format OK)
* @param methodName The de-obfuscated name of the method
* @param methodSignature The de-obfuscated signature of the method
* @return The obfuscated/unobfuscated name based on MCP_ENVIRONMENT
*/
public String getMethodName(String ownerName, String methodName, String methodSignature) {
// Methods are indexed as "path/to/class/methodName signature"
String indexer = internalizeName(ownerName + "." + methodName + " " + methodSignature);
SeargeData srg = m_NameList.get(indexer);
String obfMethodName = (srg == null ? methodName : (MCP_ENVIRONMENT ? srg.objectName : srg.objectNameObfuscated));
if (obfMethodName.lastIndexOf('/') > -1)
return obfMethodName.substring(obfMethodName.lastIndexOf('/') + 1);
else
return obfMethodName;
}
/**
* Given a method name in path/to/class/methodname or path.to.class.methodname format
* Returns method descriptor
*
* @param ownerName The de-obfuscated class that contains the method (dot or internal format OK)
* @param methodNameAndDescriptor The de-obfuscated name of the method with descriptor
* @return The obfuscated/unobfuscated descriptor based on MCP_ENVIRONMENT
*/
public String getMethodName(String ownerName, String methodNameAndDescriptor) {
String rawMaD[] = methodNameAndDescriptor.split("\\s+");
String indexer = internalizeName(ownerName + "." + methodNameAndDescriptor);
SeargeData srg = m_NameList.get(indexer);
String obfMethodName = (srg == null ? rawMaD[0] : (MCP_ENVIRONMENT ? srg.objectName : srg.objectNameObfuscated));
if (obfMethodName.lastIndexOf('/') > -1)
return obfMethodName.substring(obfMethodName.lastIndexOf('/') + 1);
else
return obfMethodName;
}
/**
* Given a method name in path/to/class/methodname or path.to.class.methodname format
* Returns method descriptor
*
* @param ownerName The de-obfuscated class that contains the method (dot or internal format OK)
* @param methodName The de-obfuscated name of the method
* @param methodSignature The de-obfuscated signature of the method
* @return The obfuscated/unobfuscated descriptor based on MCP_ENVIRONMENT
*/
public String getMethodDescriptor(String ownerName, String methodName, String methodSignature) {
String indexer = internalizeName(ownerName + "." + methodName + " " + methodSignature);
SeargeData srg = m_NameList.get(indexer);
return (srg == null ? methodSignature : (MCP_ENVIRONMENT ? srg.objectSignature : srg.objectSignatureObfuscated));
}
/**
* Given a method name in path/to/class/methodname or path.to.class.methodname format
* Returns method descriptor
*
* @param ownerName The de-obfuscated class that contains the method (dot or internal format OK)
* @param methodNameAndDescriptor The de-obfuscated name of the method with descriptor
* @return The obfuscated/unobfuscated descriptor based on MCP_ENVIRONMENT
*/
public String getMethodDescriptor(String ownerName, String methodNameAndDescriptor) {
String rawMaD[] = methodNameAndDescriptor.split("\\s+");
String indexer = internalizeName(ownerName + "." + methodNameAndDescriptor);
SeargeData srg = m_NameList.get(indexer);
return (srg == null ? rawMaD[1] : (MCP_ENVIRONMENT ? srg.objectSignature : srg.objectSignatureObfuscated));
}
/**
* Determines if methodNode matches the specified method name and signature
*
* @param methodNode Node to test
* @param ownerName The de-obfuscated owner class of the method to test for
* @param methodNameWithSignature The de-obfuscated method WITH signature to test for (eg: "setLightLevel (F)Lnet/minecraft/block/Block;")
* @return true if method exists, false if not
*/
public boolean isMethod(MethodNode methodNode, String ownerName, String methodNameWithSignature) {
String indexer = internalizeName(ownerName + "/" + methodNameWithSignature);
SeargeData srg = m_NameList.get(indexer);
String methodName = "/" + internalizeName(methodNode.name);
String methodSig = internalizeName(methodNode.desc);
// BROKE: methodName=/a methodSig=(Lahu;)Z srgNameObf=amm/a srgSigObf=(Lahu;)Z
//FMLLog.info("MethodIs: methodName=" + methodName + " methodSig=" + methodSig + " srgNameObf=" + srg.objectNameObfuscated + " srgSigObf=" + srg.objectSignatureObfuscated);
if (srg != null) {
// srg.objectName = net/path/to/class/myMethodName
// methodName = /myMethodName
if (MCP_ENVIRONMENT)
return srg.objectName.endsWith(methodName) && methodSig.equals(srg.objectSignature);
else
return srg.objectNameObfuscated.endsWith(methodName) && methodSig.equals(srg.objectSignatureObfuscated);
} else
return false;
}
/**
* Given a JVM method/type descriptor such as "(Ljava/util/ArrayList;Lnet/minecraft/entity/player/EntityPlayerMP;)V",
* returns an obfuscated descriptor like "(Ljava/util/ArrayList;Lmm;)V". Note: This method will return the
* deobfuscated descriptor if running in Eclipse (MCP_ENVIRONMENT=true)
*
* @param descriptor The descriptor to decode
* @return The proper descriptor
*/
public String getJVMTypeObfuscated(String descriptor) {
int i = 0, j;
String className;
String result = "";
while (i < descriptor.length()) {
if (descriptor.substring(i, i + 1).equals("L")) {
// Extract class name
j = i;
while (!descriptor.substring(j, j + 1).equals(";"))
j++;
className = descriptor.substring(i + 1, j);
//FMLLog.info("getMethodDescriptorObfuscated - Found class %s", className);
result = result + "L" + getClassName(className) + ";";
// Skip to end of class name
i = j;
} else
result = result + descriptor.substring(i, i + 1);
i++;
}
return result;
}
/**
* Given a deobfuscated type, returns the appropriate obfuscated/deobfuscated name ready to use
* in transformer code.
*
* @param deobfuscatedTypeDescriptor Eg: "net.minecraft.world.chunk.NibbleArray"
* @return Deobfuscated name if running in eclipse. Obfuscated if running in production.
* @author heaton84
*/
public Type getType(String deobfuscatedTypeDescriptor) {
String internalName = internalizeName(deobfuscatedTypeDescriptor);
if (internalName.startsWith("L") && internalName.endsWith(";"))
internalName = internalName.substring(1, internalName.length() - 1);
return Type.getType("L" + (MCP_ENVIRONMENT ? internalName : getClassName(internalName)) + ";");
}
public String getClassField(String deobfuscatedClassName, String deobfuscatedFieldName) {
String indexer = internalizeName(deobfuscatedClassName + "/" + deobfuscatedFieldName);
SeargeData srg = m_NameList.get(indexer);
String fieldName = (MCP_ENVIRONMENT ? deobfuscatedFieldName : (srg == null ? null : srg.objectNameObfuscated));
if (fieldName.lastIndexOf('/') > -1)
return fieldName.substring(fieldName.lastIndexOf('/') + 1);
else
return fieldName;
}
private void registerSrgName(String data) {
SeargeData item = new SeargeData(data);
m_NameList.put(item.uniqueName, item);
}
private String internalizeName(String name) {
return name.replace('.', '/');
}
private class SeargeData {
//public String objectType;
public String uniqueName; // Used to index object in array. Namely: Methods must include a signature!
public String objectName;
public String objectNameObfuscated;
public String objectSignature;
public String objectSignatureObfuscated;
public SeargeData(String src) {
String[] srcToken = src.split("\\s+");
switch (srcToken[0]) {
case "PK:":
// Ignore package types for now
break;
case "CL:":
// Class descriptor
//objectType = "CL";
if (srcToken.length == 3) {
objectName = srcToken[1];
objectNameObfuscated = srcToken[2];
uniqueName = objectName;
} else {
// TODO
}
break;
case "MD:":
// Method descriptor
//objectType = "MD";
if (srcToken.length == 5) {
objectName = srcToken[1];
objectNameObfuscated = srcToken[3];
objectSignature = srcToken[2];
objectSignatureObfuscated = srcToken[4];
uniqueName = objectName + " " + objectSignature;
} else {
// TODO
}
break;
case "FD:":
// Field descriptor
if (srcToken.length == 3) {
objectName = srcToken[1];
objectNameObfuscated = srcToken[2];
uniqueName = objectName;
} else {
// TODO
}
break;
}
}
}
}