mirror of
https://github.com/MightyPirates/OpenComputers.git
synced 2025-09-16 18:55:03 -04:00
Fixed drones with an active leash causing leash items to be dropped when picked up (shift-rightclicked).
Fixed leash on drones not rendering centered on drone in obfed Minecraft.
This commit is contained in:
parent
5239eb3ab0
commit
bce4a60394
@ -11,23 +11,38 @@ import org.objectweb.asm.ClassWriter
|
||||
import org.objectweb.asm.Opcodes
|
||||
import org.objectweb.asm.tree._
|
||||
|
||||
import scala.annotation.tailrec
|
||||
import scala.collection.convert.WrapAsJava._
|
||||
import scala.collection.convert.WrapAsScala._
|
||||
|
||||
object ObfNames {
|
||||
final val Class_EntityHanging = Array("net/minecraft/entity/EntityHanging", "ss")
|
||||
final val Class_EntityLiving = Array("net/minecraft/entity/EntityLiving", "sw")
|
||||
final val Class_RenderLiving = Array("net/minecraft/client/renderer/entity/RenderLiving", "bok")
|
||||
final val Class_TileEntity = Array("net/minecraft/tileentity/TileEntity", "aor")
|
||||
final val Field_leashNBTTag = Array("leashNBTTag", "field_110170_bx", "bx")
|
||||
final val Method_leashedToEntity = Array("leashedToEntity", "field_110168_bw", "bw")
|
||||
final val Method_recreateLeash = Array("recreateLeash", "func_110165_bF", "bP")
|
||||
final val Method_recreateLeashDesc = Array("()V")
|
||||
final val Method_renderHanging = Array("func_110827_b", "b")
|
||||
final val Method_renderHangingDesc = Array("(Lsw;DDDFF)V", "(Lnet/minecraft/entity/EntityLiving;DDDFF)V")
|
||||
final val Method_validate = Array("validate", "func_145829_t")
|
||||
final val Method_invalidate = Array("invalidate", "func_145843_s")
|
||||
final val Method_onChunkUnload = Array("onChunkUnload", "func_76623_d")
|
||||
final val Method_readFromNBT = Array("readFromNBT", "func_145839_a")
|
||||
final val Method_writeToNBT = Array("writeToNBT", "func_145841_b")
|
||||
}
|
||||
|
||||
class ClassTransformer extends IClassTransformer {
|
||||
private val loader = classOf[ClassTransformer].getClassLoader.asInstanceOf[LaunchClassLoader]
|
||||
|
||||
private val log = LogManager.getLogger("OpenComputers")
|
||||
|
||||
override def transform(name: String, transformedName: String, basicClass: Array[Byte]): Array[Byte] = {
|
||||
if (basicClass == null || name.startsWith("scala.")) return basicClass
|
||||
var transformedClass = basicClass
|
||||
try {
|
||||
if (name == "li.cil.oc.common.tileentity.traits.Computer" || name == "li.cil.oc.common.tileentity.Rack") {
|
||||
transformedClass = ensureStargateTechCompatibility(transformedClass)
|
||||
}
|
||||
|
||||
if (transformedClass != null
|
||||
&& !name.startsWith("net.minecraft.")
|
||||
if (!name.startsWith("net.minecraft.")
|
||||
&& !name.startsWith("net.minecraftforge.")
|
||||
&& !name.startsWith("li.cil.oc.common.asm.")
|
||||
&& !name.startsWith("li.cil.oc.integration.")) {
|
||||
@ -137,18 +152,24 @@ class ClassTransformer extends IClassTransformer {
|
||||
// if (this.isLeashed && this.field_110170_bx != null && this.leashedToEntity == null)
|
||||
// which should not interfere with any existing logic, but avoid leashing
|
||||
// restored manually in the load phase to not be broken again.
|
||||
if (transformedClass != null && name == "net.minecraft.entity.EntityLiving") {
|
||||
insertInto(transformedClass, "recreateLeash", instructions => instructions.toArray.sliding(3, 1).exists {
|
||||
if (ObfNames.Class_EntityLiving.contains(name.replace('.', '/'))) {
|
||||
val classNode = newClassNode(transformedClass)
|
||||
insertInto(classNode, ObfNames.Method_recreateLeash, ObfNames.Method_recreateLeashDesc, instructions => instructions.toArray.sliding(3, 1).exists {
|
||||
case Array(varNode: VarInsnNode, fieldNode: FieldInsnNode, jumpNode: JumpInsnNode)
|
||||
if varNode.getOpcode == Opcodes.ALOAD && varNode.`var` == 0 &&
|
||||
fieldNode.getOpcode == Opcodes.GETFIELD && fieldNode.name == "field_110170_bx" &&
|
||||
fieldNode.getOpcode == Opcodes.GETFIELD && ObfNames.Field_leashNBTTag.contains(fieldNode.name) &&
|
||||
jumpNode.getOpcode == Opcodes.IFNULL =>
|
||||
val toInject = new InsnList()
|
||||
toInject.add(new VarInsnNode(Opcodes.ALOAD, 0))
|
||||
toInject.add(new FieldInsnNode(Opcodes.GETFIELD, "net/minecraft/entity/EntityLiving", "leashedToEntity", "Lnet/minecraft/entity/Entity;"))
|
||||
toInject.add(new JumpInsnNode(Opcodes.IFNONNULL, jumpNode.label))
|
||||
instructions.insert(jumpNode, toInject)
|
||||
true
|
||||
classNode.fields.find(field => ObfNames.Method_leashedToEntity.contains(field.name)) match {
|
||||
case Some(field) =>
|
||||
val toInject = new InsnList()
|
||||
toInject.add(new VarInsnNode(Opcodes.ALOAD, 0))
|
||||
toInject.add(new FieldInsnNode(Opcodes.GETFIELD, classNode.name, field.name, field.desc))
|
||||
toInject.add(new JumpInsnNode(Opcodes.IFNONNULL, jumpNode.label))
|
||||
instructions.insert(jumpNode, toInject)
|
||||
true
|
||||
case _ =>
|
||||
false
|
||||
}
|
||||
case _ =>
|
||||
false
|
||||
}) match {
|
||||
@ -165,11 +186,12 @@ class ClassTransformer extends IClassTransformer {
|
||||
// d7 = -0.75;
|
||||
// }
|
||||
// before the `instanceof EntityHanging` check in func_110827_b.
|
||||
if (transformedClass != null && name == "net.minecraft.client.renderer.entity.RenderLiving") {
|
||||
insertInto(transformedClass, "func_110827_b", instructions => instructions.toArray.sliding(3, 1).exists {
|
||||
if (ObfNames.Class_RenderLiving.contains(name.replace('.', '/'))) {
|
||||
val classNode = newClassNode(transformedClass)
|
||||
insertInto(classNode, ObfNames.Method_renderHanging, ObfNames.Method_renderHangingDesc, instructions => instructions.toArray.sliding(3, 1).exists {
|
||||
case Array(varNode: VarInsnNode, typeNode: TypeInsnNode, jumpNode: JumpInsnNode)
|
||||
if varNode.getOpcode == Opcodes.ALOAD && varNode.`var` == 10 &&
|
||||
typeNode.getOpcode == Opcodes.INSTANCEOF && typeNode.desc == "net/minecraft/entity/EntityHanging" &&
|
||||
typeNode.getOpcode == Opcodes.INSTANCEOF && ObfNames.Class_EntityHanging.contains(typeNode.desc) &&
|
||||
jumpNode.getOpcode == Opcodes.IFEQ =>
|
||||
val toInject = new InsnList()
|
||||
toInject.add(new VarInsnNode(Opcodes.ALOAD, 10))
|
||||
@ -202,20 +224,19 @@ class ClassTransformer extends IClassTransformer {
|
||||
}
|
||||
}
|
||||
|
||||
private def insertInto(classData: Array[Byte], method: String, inserter: (InsnList) => Boolean): Option[Array[Byte]] = {
|
||||
val classNode = newClassNode(classData)
|
||||
classNode.methods.find(_.name == method) match {
|
||||
private def insertInto(classNode: ClassNode, methodNames: Array[String], methodDescs: Array[String], inserter: (InsnList) => Boolean): Option[Array[Byte]] = {
|
||||
classNode.methods.find(method => methodNames.contains(method.name) && methodDescs.contains(method.desc)) match {
|
||||
case Some(methodNode) =>
|
||||
if (inserter(methodNode.instructions)) {
|
||||
log.warn(s"Successfully patched ${classNode.name}.$method.")
|
||||
log.info(s"Successfully patched ${classNode.name}.${methodNames(0)}.")
|
||||
Option(writeClass(classNode, ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES))
|
||||
}
|
||||
else {
|
||||
log.warn(s"Failed patching ${classNode.name}.$method}, injection point not found.")
|
||||
log.warn(s"Failed patching ${classNode.name}.${methodNames(0)}, injection point not found.")
|
||||
None
|
||||
}
|
||||
case _ =>
|
||||
log.warn(s"Failed patching ${classNode.name}.$method, method not found.")
|
||||
log.warn(s"Failed patching ${classNode.name}.${methodNames(0)}, method not found.")
|
||||
None
|
||||
}
|
||||
}
|
||||
@ -232,16 +253,6 @@ class ClassTransformer extends IClassTransformer {
|
||||
"""L([^;]+);""".r.findAllMatchIn(desc).map(_.group(1)).filter(!classExists(_))
|
||||
}
|
||||
|
||||
def ensureStargateTechCompatibility(basicClass: Array[Byte]): Array[Byte] = {
|
||||
if (!Mods.StargateTech2.isAvailable) {
|
||||
// No SGT2 or version is too old, abstract bus API doesn't exist.
|
||||
val classNode = newClassNode(basicClass)
|
||||
classNode.interfaces.remove("stargatetech2/api/bus/IBusDevice")
|
||||
writeClass(classNode)
|
||||
}
|
||||
else basicClass
|
||||
}
|
||||
|
||||
def injectEnvironmentImplementation(classNode: ClassNode): Array[Byte] = {
|
||||
log.trace(s"Injecting methods from Environment interface into ${classNode.name}.")
|
||||
if (!isTileEntity(classNode)) {
|
||||
@ -275,7 +286,7 @@ class ClassTransformer extends IClassTransformer {
|
||||
val mapper = FMLDeobfuscatingRemapper.INSTANCE
|
||||
def filter(method: MethodNode) = {
|
||||
val descDeObf = mapper.mapMethodDesc(method.desc)
|
||||
val methodNameDeObf = mapper.mapMethodName(tileEntityNameObfed, method.name, method.desc)
|
||||
val methodNameDeObf = mapper.mapMethodName(ObfNames.Class_TileEntity(1), method.name, method.desc)
|
||||
val areSamePlain = method.name + descDeObf == methodName + desc
|
||||
val areSameDeObf = methodNameDeObf + descDeObf == methodNameSrg + desc
|
||||
areSamePlain || areSameDeObf
|
||||
@ -289,7 +300,7 @@ class ClassTransformer extends IClassTransformer {
|
||||
method.name = methodName + SimpleComponentImpl.PostFix
|
||||
case _ =>
|
||||
log.trace(s"No original implementation of '$methodName', will inject override.")
|
||||
def ensureNonFinalIn(name: String) {
|
||||
@tailrec def ensureNonFinalIn(name: String) {
|
||||
if (name != null) {
|
||||
val node = classNodeFor(name)
|
||||
if (node != null) {
|
||||
@ -315,11 +326,11 @@ class ClassTransformer extends IClassTransformer {
|
||||
case _ => throw new AssertionError(s"Couldn't find '$methodName' in template implementation.")
|
||||
}
|
||||
}
|
||||
replace("validate", "func_145829_t", "()V")
|
||||
replace("invalidate", "func_145843_s", "()V")
|
||||
replace("onChunkUnload", "func_76623_d", "()V")
|
||||
replace("readFromNBT", "func_145839_a", "(Lnet/minecraft/nbt/NBTTagCompound;)V")
|
||||
replace("writeToNBT", "func_145841_b", "(Lnet/minecraft/nbt/NBTTagCompound;)V")
|
||||
replace(ObfNames.Method_validate(0), ObfNames.Method_validate(1), "()V")
|
||||
replace(ObfNames.Method_invalidate(0), ObfNames.Method_invalidate(1), "()V")
|
||||
replace(ObfNames.Method_onChunkUnload(0), ObfNames.Method_onChunkUnload(1), "()V")
|
||||
replace(ObfNames.Method_readFromNBT(0), ObfNames.Method_readFromNBT(1), "(Lnet/minecraft/nbt/NBTTagCompound;)V")
|
||||
replace(ObfNames.Method_writeToNBT(0), ObfNames.Method_writeToNBT(1), "(Lnet/minecraft/nbt/NBTTagCompound;)V")
|
||||
|
||||
log.trace("Injecting interface.")
|
||||
classNode.interfaces.add("li/cil/oc/common/asm/template/SimpleComponentImpl")
|
||||
@ -327,14 +338,11 @@ class ClassTransformer extends IClassTransformer {
|
||||
writeClass(classNode, ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES)
|
||||
}
|
||||
|
||||
val tileEntityNamePlain = "net/minecraft/tileentity/TileEntity"
|
||||
val tileEntityNameObfed = FMLDeobfuscatingRemapper.INSTANCE.unmap(tileEntityNamePlain)
|
||||
|
||||
def isTileEntity(classNode: ClassNode): Boolean = {
|
||||
if (classNode == null) false
|
||||
else {
|
||||
log.trace(s"Checking if class ${classNode.name} is a TileEntity...")
|
||||
classNode.name == tileEntityNamePlain || classNode.name == tileEntityNameObfed ||
|
||||
ObfNames.Class_TileEntity.contains(classNode.name) ||
|
||||
(classNode.superName != null && isTileEntity(classNodeFor(classNode.superName)))
|
||||
}
|
||||
}
|
||||
|
@ -320,6 +320,7 @@ class Drone(val world: World) extends Entity(world) with MachineHost with intern
|
||||
if (!world.isRemote) {
|
||||
machine.stop()
|
||||
machine.node.remove()
|
||||
components.disconnectComponents()
|
||||
components.saveComponents()
|
||||
val stack = api.Items.get("drone").createItemStack(1)
|
||||
info.storedEnergy = control.node.localBuffer.toInt
|
||||
|
@ -151,6 +151,7 @@ object Items extends ItemAPI {
|
||||
get("inventoryControllerUpgrade").createItemStack(1),
|
||||
get("tankUpgrade").createItemStack(1),
|
||||
get("tankControllerUpgrade").createItemStack(1),
|
||||
get("leashUpgrade").createItemStack(1),
|
||||
|
||||
get("wlanCard").createItemStack(1),
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user