mirror of
https://github.com/MightyPirates/OpenComputers.git
synced 2025-09-18 19:56:17 -04:00
Merge branch 'master' of https://github.com/MightyPirates/OpenComputers into MC1.7
Also updated srg names where used. Conflicts: src/main/scala/li/cil/oc/client/GuiHandler.scala src/main/scala/li/cil/oc/common/Proxy.scala src/main/scala/li/cil/oc/common/tileentity/Screen.scala
This commit is contained in:
commit
2f3f52adc1
@ -69,4 +69,17 @@ public @interface Callback {
|
||||
* which is synchronized, so you can consume/produce power in direct calls.
|
||||
*/
|
||||
int limit() default Integer.MAX_VALUE;
|
||||
|
||||
/**
|
||||
* A documentation string that is made available to the computers the
|
||||
* component this callback belongs to is connected to. This allows for
|
||||
* ingame documentation of callbacks.
|
||||
* <p/>
|
||||
* You may want to give a short description of what a method does here, but
|
||||
* more importantly you should document the expected parameters and return
|
||||
* type here.
|
||||
* <p/>
|
||||
* TODO Actually implement for this to be available to computers...
|
||||
*/
|
||||
String doc() default "";
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ package li.cil.oc.api.network;
|
||||
* those defined via the {@link li.cil.oc.api.network.Callback} annotation, and
|
||||
* invoking said methods.
|
||||
*/
|
||||
public interface ManagedPeripheral extends ManagedEnvironment {
|
||||
public interface ManagedPeripheral extends Environment {
|
||||
/**
|
||||
* Get the list of methods provided by this environment, in
|
||||
* <em>addition</em> to methods marked as callbacks.
|
||||
|
84
src/main/java/li/cil/oc/api/network/SimpleComponent.java
Normal file
84
src/main/java/li/cil/oc/api/network/SimpleComponent.java
Normal file
@ -0,0 +1,84 @@
|
||||
package li.cil.oc.api.network;
|
||||
|
||||
/**
|
||||
* This interface can be used to easily convert tile entities to components,
|
||||
* without having to implement {@link li.cil.oc.api.network.Environment}
|
||||
* themselves. The simple implementation will provide no access to OC's internal
|
||||
* component network, since you won't have access to the node representing the
|
||||
* tile entity. Use this only for simple cases, where you want to expose a
|
||||
* couple of methods to the programs running computers.
|
||||
* <p/>
|
||||
* This is an interface instead of an annotation, to allow stripping via the
|
||||
* ever so handy {@link cpw.mods.fml.common.Optional} annotation, meaning there
|
||||
* will be no strong dependency on OpenComputers.
|
||||
* <p/>
|
||||
* Classes implementing this interface will be expanded with the methods
|
||||
* required for them to function as native block components (say, like the
|
||||
* screen or keyboard). This means functions in the <tt>Environment</tt>
|
||||
* interface have to created using a class transformer. If any of the methods
|
||||
* already exist, this will fail! If things don't work, check your logs, first.
|
||||
* <p/>
|
||||
* To expose methods to OC, tag them with {@link li.cil.oc.api.network.Callback}
|
||||
* and have them use the according signature (see the documentation on the
|
||||
* <tt>Callback</tt> annotation).
|
||||
* <p/>
|
||||
* Alternatively, implement {@link li.cil.oc.api.network.ManagedPeripheral} in
|
||||
* addition to this interface, to make methods available ComputerCraft style.
|
||||
* <p/>
|
||||
* So, in short:
|
||||
* <ul>
|
||||
* <li>Implement this interface on a tile entity that should expose
|
||||
* methods to computers.</li>
|
||||
* <li>Annotate methods with <tt>Callback</tt> so they exported.</li>
|
||||
* <li>Alternatively/additionally implement <tt>ManagedPeripheral</tt> to
|
||||
* provide methods via a list of names and single callback method.</li>
|
||||
* </ul>
|
||||
* <p/>
|
||||
* For example:
|
||||
* <pre>
|
||||
* {@literal @}Optional.Interface(iface = "li.cil.oc.api.network.SimpleComponent", modid = "OpenComputers")
|
||||
* public class TileEntityMyFancyThing extends TileEntity
|
||||
* implements SimpleComponent
|
||||
* {
|
||||
* {@literal @}Callback
|
||||
* public Object[] greet(Context context, Arguments args) {
|
||||
* return new Object[]{String.format("Hello, %s!", args.checkString(0))};
|
||||
* }
|
||||
* }
|
||||
* </pre>
|
||||
* Using the alternative method to provide methods:
|
||||
* <pre>
|
||||
* {@literal @}Optional.InterfaceList({
|
||||
* {@literal @}Optional.Interface(iface = "li.cil.oc.api.network.SimpleComponent", modid = "OpenComputers"),
|
||||
* {@literal @}Optional.Interface(iface = "li.cil.oc.api.network.ManagedPeripheral", modid = "OpenComputers")
|
||||
* })
|
||||
* public class TileEntityMyFancyThing extends TileEntity
|
||||
* implements SimpleComponent, ManagedPeripheral
|
||||
* {
|
||||
* public String[] methods() {
|
||||
* return new String[] {"greet"};
|
||||
* }
|
||||
*
|
||||
* public Object[] invoke(String method, Context context, Arguments args) {
|
||||
* if ("greet".equals(method)) {
|
||||
* return new Object[]{String.format("Hello, %s!", args.checkString(0))};
|
||||
* } else {
|
||||
* throw new NoSuchMethodException();
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* </pre>
|
||||
*/
|
||||
public interface SimpleComponent {
|
||||
/**
|
||||
* The name the component should be made available as.
|
||||
* <p/
|
||||
* This is the name as seen in the <tt>component.list()</tt> in Lua, for
|
||||
* example. You'll want to make this short and descriptive. The convention
|
||||
* for component names is: all lowercase, underscores where necessary. Good
|
||||
* component names are for example: disk_drive, furnace, crafting_table.
|
||||
*
|
||||
* @return the component's name.
|
||||
*/
|
||||
String getComponentName();
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
package li.cil.oc.common.asm;
|
||||
|
||||
import cpw.mods.fml.common.eventhandler.SubscribeEvent;
|
||||
import cpw.mods.fml.common.gameevent.TickEvent;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
// This class is used for adding simple components to the component network.
|
||||
// It is triggered from a validate call, and executed in the next update tick.
|
||||
public final class SimpleComponentTickHandler {
|
||||
public static final ArrayList<Runnable> pendingOperations = new java.util.ArrayList<Runnable>();
|
||||
|
||||
public static final SimpleComponentTickHandler Instance = new SimpleComponentTickHandler();
|
||||
|
||||
@SubscribeEvent
|
||||
public void onTick(TickEvent.ServerTickEvent e) {
|
||||
synchronized (pendingOperations) {
|
||||
for (Runnable runnable : pendingOperations) {
|
||||
runnable.run();
|
||||
}
|
||||
pendingOperations.clear();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
package li.cil.oc.common.asm.template;
|
||||
|
||||
import li.cil.oc.api.network.Environment;
|
||||
import li.cil.oc.api.network.SimpleComponent;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
|
||||
// This interface defines the names to which existing or placeholders for
|
||||
// existing methods will be moved. This allows transparent injection of our
|
||||
// functionality, i.e. existing validate() etc. methods will be called as
|
||||
// if we didn't inject our code.
|
||||
public interface SimpleComponentImpl extends Environment, SimpleComponent {
|
||||
void validate0();
|
||||
|
||||
void invalidate0();
|
||||
|
||||
void onChunkUnload0();
|
||||
|
||||
void readFromNBT0(NBTTagCompound nbt);
|
||||
|
||||
void writeToNBT0(NBTTagCompound nbt);
|
||||
}
|
@ -0,0 +1,85 @@
|
||||
package li.cil.oc.common.asm.template;
|
||||
|
||||
import li.cil.oc.api.network.Message;
|
||||
import li.cil.oc.api.network.Node;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
|
||||
// This is a template implementation of methods injected into classes that are
|
||||
// marked for component functionality. These methods will be copied into tile
|
||||
// entities marked as simple components as necessary by the class transformer.
|
||||
@SuppressWarnings("unused")
|
||||
public abstract class SimpleEnvironment extends TileEntity implements SimpleComponentImpl {
|
||||
@Override
|
||||
public Node node() {
|
||||
return StaticSimpleEnvironment.node(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConnect(Node node) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisconnect(Node node) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMessage(Message message) {
|
||||
}
|
||||
|
||||
// These are always injected, after possibly existing versions have been
|
||||
// renamed to the below variants from the SimpleComponentImpl interface.
|
||||
// This allows transparent wrapping of already present implementations,
|
||||
// instead of plain overwriting them.
|
||||
|
||||
@Override
|
||||
public void validate() {
|
||||
StaticSimpleEnvironment.validate(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invalidate() {
|
||||
StaticSimpleEnvironment.invalidate(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onChunkUnload() {
|
||||
StaticSimpleEnvironment.onChunkUnload(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readFromNBT(NBTTagCompound nbt) {
|
||||
StaticSimpleEnvironment.readFromNBT(this, nbt);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToNBT(NBTTagCompound nbt) {
|
||||
StaticSimpleEnvironment.writeToNBT(this, nbt);
|
||||
}
|
||||
|
||||
// The following methods are only injected if their real versions do not
|
||||
// exist in the class we're injecting into. Otherwise their real versions
|
||||
// are renamed to these variations, which simply delegate to the parent.
|
||||
// This way they are always guaranteed to be present, so we can simply call
|
||||
// them through an interface, and need no runtime reflection.
|
||||
|
||||
public void validate0() {
|
||||
super.validate();
|
||||
}
|
||||
|
||||
public void invalidate0() {
|
||||
super.invalidate();
|
||||
}
|
||||
|
||||
public void onChunkUnload0() {
|
||||
super.onChunkUnload();
|
||||
}
|
||||
|
||||
public void readFromNBT0(NBTTagCompound nbt) {
|
||||
super.readFromNBT(nbt);
|
||||
}
|
||||
|
||||
public void writeToNBT0(NBTTagCompound nbt) {
|
||||
super.writeToNBT(nbt);
|
||||
}
|
||||
}
|
@ -0,0 +1,91 @@
|
||||
package li.cil.oc.common.asm.template;
|
||||
|
||||
import cpw.mods.fml.common.FMLCommonHandler;
|
||||
import li.cil.oc.api.Network;
|
||||
import li.cil.oc.api.network.Environment;
|
||||
import li.cil.oc.api.network.Node;
|
||||
import li.cil.oc.api.network.Visibility;
|
||||
import li.cil.oc.common.asm.SimpleComponentTickHandler;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
// This class contains actual implementations of methods injected into tile
|
||||
// entities marked as simple components using the SimpleComponent interface.
|
||||
// They are called from the template methods, to keep the injected methods
|
||||
// minimal, instruction wise, and avoid weird dependencies making the injection
|
||||
// unnecessarily complicated.
|
||||
public final class StaticSimpleEnvironment {
|
||||
private StaticSimpleEnvironment() {
|
||||
}
|
||||
|
||||
private static final Map<Environment, Node> nodes = new HashMap<Environment, Node>();
|
||||
|
||||
public static Node node(final SimpleComponentImpl self) {
|
||||
// Save ourselves the lookup time in the hash map and avoid mixing in
|
||||
// client side tile entities into the map when in single player.
|
||||
if (FMLCommonHandler.instance().getEffectiveSide().isClient()) {
|
||||
return null;
|
||||
}
|
||||
if (!nodes.containsKey(self)) {
|
||||
final String name = self.getComponentName();
|
||||
nodes.put(self, Network.
|
||||
newNode(self, Visibility.Network).
|
||||
withComponent(name).
|
||||
create());
|
||||
}
|
||||
return nodes.get(self);
|
||||
}
|
||||
|
||||
public static void validate(final SimpleComponentImpl self) {
|
||||
self.validate0();
|
||||
if (FMLCommonHandler.instance().getEffectiveSide().isServer()) {
|
||||
synchronized (SimpleComponentTickHandler.pendingOperations) {
|
||||
SimpleComponentTickHandler.pendingOperations.add(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Network.joinOrCreateNetwork((TileEntity) self);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void invalidate(final SimpleComponentImpl self) {
|
||||
self.invalidate0();
|
||||
final Node node = node(self);
|
||||
if (node != null) {
|
||||
node.remove();
|
||||
nodes.remove(self);
|
||||
}
|
||||
}
|
||||
|
||||
public static void onChunkUnload(final SimpleComponentImpl self) {
|
||||
self.onChunkUnload0();
|
||||
final Node node = node(self);
|
||||
if (node != null) {
|
||||
node.remove();
|
||||
nodes.remove(self);
|
||||
}
|
||||
}
|
||||
|
||||
public static void readFromNBT(final SimpleComponentImpl self, NBTTagCompound nbt) {
|
||||
self.readFromNBT0(nbt);
|
||||
final Node node = node(self);
|
||||
if (node != null) {
|
||||
node.load(nbt.getCompoundTag("oc:node"));
|
||||
}
|
||||
}
|
||||
|
||||
public static void writeToNBT(final SimpleComponentImpl self, NBTTagCompound nbt) {
|
||||
self.writeToNBT0(nbt);
|
||||
final Node node = node(self);
|
||||
if (node != null) {
|
||||
final NBTTagCompound nodeNbt = new NBTTagCompound();
|
||||
node.save(nodeNbt);
|
||||
nbt.setTag("oc:node", nodeNbt);
|
||||
}
|
||||
}
|
||||
}
|
@ -62,7 +62,7 @@ object GuiHandler extends CommonGuiHandler {
|
||||
else player.addChatMessage(new ChatComponentTranslation(Settings.namespace + "gui.Terminal.InvalidKey"))
|
||||
}
|
||||
else player.addChatMessage(new ChatComponentTranslation(Settings.namespace + "gui.Terminal.OutOfRange"))
|
||||
case _ => null
|
||||
case _ => player.addChatMessage(new ChatComponentTranslation(Settings.namespace + "gui.Terminal.OutOfRange"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -39,7 +39,6 @@ private[oc] class Proxy extends CommonProxy {
|
||||
|
||||
MinecraftForgeClient.registerItemRenderer(Items.multi, UpgradeRenderer)
|
||||
|
||||
|
||||
OpenComputers.channel.register(client.PacketHandler)
|
||||
}
|
||||
|
||||
|
@ -4,6 +4,7 @@ import cpw.mods.fml.common.FMLCommonHandler
|
||||
import cpw.mods.fml.common.event._
|
||||
import cpw.mods.fml.common.network.NetworkRegistry
|
||||
import li.cil.oc._
|
||||
import li.cil.oc.common.asm.SimpleComponentTickHandler
|
||||
import li.cil.oc.server
|
||||
import li.cil.oc.server.driver
|
||||
import li.cil.oc.server.fs
|
||||
@ -51,6 +52,7 @@ class Proxy {
|
||||
driver.Registry.locked = true
|
||||
|
||||
FMLCommonHandler.instance().bus().register(EventHandler)
|
||||
FMLCommonHandler.instance().bus().register(SimpleComponentTickHandler.Instance)
|
||||
MinecraftForge.EVENT_BUS.register(Network)
|
||||
MinecraftForge.EVENT_BUS.register(WirelessNetwork)
|
||||
}
|
||||
|
@ -1,34 +1,150 @@
|
||||
package li.cil.oc.common.asm
|
||||
|
||||
import cpw.mods.fml.common.Loader
|
||||
import cpw.mods.fml.common.asm.transformers.deobf.FMLDeobfuscatingRemapper
|
||||
import cpw.mods.fml.relauncher.IFMLLoadingPlugin.TransformerExclusions
|
||||
import java.util.logging.{Level, Logger}
|
||||
import li.cil.oc.util.mods.StargateTech2
|
||||
import net.minecraft.launchwrapper.IClassTransformer
|
||||
import org.objectweb.asm.tree.ClassNode
|
||||
import net.minecraft.launchwrapper.{LaunchClassLoader, IClassTransformer}
|
||||
import org.objectweb.asm.tree._
|
||||
import org.objectweb.asm.{ClassWriter, ClassReader}
|
||||
import scala.collection.convert.WrapAsScala._
|
||||
import net.minecraft.tileentity.TileEntity
|
||||
|
||||
@TransformerExclusions(Array("li.cil.oc.common.asm"))
|
||||
class ClassTransformer extends IClassTransformer {
|
||||
val loader = classOf[ClassTransformer].getClassLoader.asInstanceOf[LaunchClassLoader]
|
||||
|
||||
val log = Logger.getLogger("OpenComputers")
|
||||
|
||||
override def transform(name: String, transformedName: String, basicClass: Array[Byte]): Array[Byte] = {
|
||||
if (name == "li.cil.oc.common.tileentity.Computer" || name == "li.cil.oc.common.tileentity.Rack") {
|
||||
if (!Loader.isModLoaded("StargateTech2")) {
|
||||
// Handled by @Optional.
|
||||
return basicClass
|
||||
}
|
||||
|
||||
if (StargateTech2.isAvailable) {
|
||||
// All green, API version is new enough.
|
||||
return basicClass
|
||||
}
|
||||
|
||||
// Version of SGT2 is too old, abstract bus API doesn't exist.
|
||||
val classNode = new ClassNode()
|
||||
new ClassReader(basicClass).accept(classNode, 0)
|
||||
|
||||
classNode.interfaces.remove("stargatetech2/api/bus/IBusDevice")
|
||||
|
||||
val writer = new ClassWriter(ClassWriter.COMPUTE_MAXS)
|
||||
classNode.accept(writer)
|
||||
writer.toByteArray
|
||||
return ensureStargateTechCompatibility(basicClass)
|
||||
}
|
||||
else basicClass
|
||||
else if (basicClass != null
|
||||
&& !name.startsWith( """net.minecraft.""")
|
||||
&& !name.startsWith( """net.minecraftforge.""")
|
||||
&& !name.startsWith( """li.cil.oc.common.asm.""")
|
||||
&& !name.startsWith( """li.cil.oc.api.""")) {
|
||||
val classNode = newClassNode(basicClass)
|
||||
if (classNode.interfaces.contains("li/cil/oc/api/network/SimpleComponent")) {
|
||||
try {
|
||||
val transformedClass = injectEnvironmentImplementation(classNode, basicClass)
|
||||
log.info(s"Successfully injected component logic into class $name.")
|
||||
return transformedClass
|
||||
} catch {
|
||||
case e: Throwable =>
|
||||
log.log(Level.WARNING, s"Failed injecting component logic into class $name.", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
basicClass
|
||||
}
|
||||
|
||||
def ensureStargateTechCompatibility(basicClass: Array[Byte]): Array[Byte] = {
|
||||
if (!Loader.isModLoaded("StargateTech2")) {
|
||||
// Handled by @Optional.
|
||||
return basicClass
|
||||
}
|
||||
|
||||
if (StargateTech2.isAvailable) {
|
||||
// All green, API version is new enough.
|
||||
return basicClass
|
||||
}
|
||||
|
||||
// Version of SGT2 is too old, abstract bus API doesn't exist.
|
||||
val classNode = newClassNode(basicClass)
|
||||
classNode.interfaces.remove("stargatetech2/api/bus/IBusDevice")
|
||||
writeClass(classNode)
|
||||
}
|
||||
|
||||
def injectEnvironmentImplementation(classNode: ClassNode, basicClass: Array[Byte]): Array[Byte] = {
|
||||
// TODO find actual implementations, i.e. descend into sub-classes until in a leaf, and transform those?
|
||||
if (!isTileEntity(classNode)) {
|
||||
throw new InjectionFailedException("Found SimpleComponent on something that isn't a tile entity, ignoring.")
|
||||
}
|
||||
|
||||
val template = classNodeFor("li/cil/oc/common/asm/template/SimpleEnvironment")
|
||||
|
||||
log.fine("Injecting methods from Environment interface.")
|
||||
def inject(methodName: String, signature: String, required: Boolean = false) {
|
||||
def filter(method: MethodNode) = method.name == methodName && method.desc == signature
|
||||
if (classNode.methods.exists(filter)) {
|
||||
if (required) {
|
||||
throw new InjectionFailedException(s"Could not inject method $methodName$signature because it was already present!")
|
||||
}
|
||||
}
|
||||
else template.methods.find(filter) match {
|
||||
case Some(method) => classNode.methods.add(method)
|
||||
case _ => throw new AssertionError()
|
||||
}
|
||||
}
|
||||
inject("node", "()Lli/cil/oc/api/network/Node;", required = true)
|
||||
inject("onConnect", "(Lli/cil/oc/api/network/Node;)V")
|
||||
inject("onDisconnect", "(Lli/cil/oc/api/network/Node;)V")
|
||||
inject("onMessage", "(Lli/cil/oc/api/network/Message;)V")
|
||||
|
||||
log.fine("Injecting / wrapping overrides for required tile entity methods.")
|
||||
def replace(methodName: String, methodNameSrg: String, desc: String) {
|
||||
val mapper = FMLDeobfuscatingRemapper.INSTANCE
|
||||
def filter(method: MethodNode) = {
|
||||
val descDeObf = mapper.mapMethodDesc(method.desc)
|
||||
val methodNameDeObf = mapper.mapMethodName(tileEntityName, method.name, method.desc)
|
||||
val areSamePlain = method.name + descDeObf == methodName + desc
|
||||
val areSameDeObf = methodNameDeObf + descDeObf == methodNameSrg + desc
|
||||
areSamePlain || areSameDeObf
|
||||
}
|
||||
if (classNode.methods.exists(method => method.name == methodName + "0" && mapper.mapMethodDesc(method.desc) == desc)) {
|
||||
throw new InjectionFailedException(s"Delegator method name ${methodName}0 is already in use.")
|
||||
}
|
||||
classNode.methods.find(filter) match {
|
||||
case Some(method) =>
|
||||
log.fine(s"Found original implementation of $methodName, wrapping.")
|
||||
method.name = methodName + "0"
|
||||
case _ =>
|
||||
log.fine(s"No original implementation of $methodName, will inject override.")
|
||||
template.methods.find(_.name == methodName + "0") match {
|
||||
case Some(method) => classNode.methods.add(method)
|
||||
case _ => throw new AssertionError(s"Couldn't find ${methodName}0 in template implementation.")
|
||||
}
|
||||
}
|
||||
template.methods.find(filter) match {
|
||||
case Some(method) => classNode.methods.add(method)
|
||||
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")
|
||||
|
||||
log.fine("Injecting interface.")
|
||||
classNode.interfaces.add("li/cil/oc/common/asm/template/SimpleComponentImpl")
|
||||
|
||||
writeClass(classNode, ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES)
|
||||
}
|
||||
|
||||
val tileEntityName = classOf[TileEntity].getName.replace('.', '/')
|
||||
|
||||
def isTileEntity(classNode: ClassNode): Boolean = {
|
||||
classNode.name != "java/lang/Object" && (classNode.name == tileEntityName || isTileEntity(classNodeFor(classNode.superName)))
|
||||
}
|
||||
|
||||
def classNodeFor(name: String) = newClassNode(loader.getClassBytes(name.replace('/', '.')))
|
||||
|
||||
def newClassNode(data: Array[Byte]) = {
|
||||
val classNode = new ClassNode()
|
||||
new ClassReader(data).accept(classNode, 0)
|
||||
classNode
|
||||
}
|
||||
|
||||
def writeClass(classNode: ClassNode, flags: Int = ClassWriter.COMPUTE_MAXS) = {
|
||||
val writer = new ClassWriter(flags)
|
||||
classNode.accept(writer)
|
||||
writer.toByteArray
|
||||
}
|
||||
|
||||
class InjectionFailedException(message: String) extends Exception(message)
|
||||
|
||||
}
|
||||
|
@ -14,7 +14,6 @@ import net.minecraft.entity.projectile.EntityArrow
|
||||
import net.minecraft.nbt.NBTTagCompound
|
||||
import net.minecraft.util.AxisAlignedBB
|
||||
import net.minecraftforge.common.util.ForgeDirection
|
||||
import scala.Some
|
||||
import scala.collection.mutable
|
||||
import scala.language.postfixOps
|
||||
|
||||
|
@ -40,7 +40,7 @@ class CompoundBlockDriver(val blocks: driver.Block*) extends driver.Block {
|
||||
}
|
||||
try world.getTileEntity(x, y, z) match {
|
||||
case tileEntity: TileEntity =>
|
||||
val map = ReflectionHelper.getPrivateValue[java.util.Map[Class[_], String], TileEntity](classOf[TileEntity], tileEntity, "classToNameMap", "field_70323_b")
|
||||
val map = ReflectionHelper.getPrivateValue[java.util.Map[Class[_], String], TileEntity](classOf[TileEntity], tileEntity, "classToNameMap", "field_145853_j")
|
||||
return map.get(tileEntity.getClass)
|
||||
} catch {
|
||||
case _: Throwable =>
|
||||
|
Loading…
x
Reference in New Issue
Block a user