|  | package li.cil.oc.common | 
|  |  | 
|  | import cpw.mods.fml.common.network.IPacketHandler | 
|  | import cpw.mods.fml.common.network.Player | 
|  | import java.io.ByteArrayInputStream | 
|  | import java.io.DataInputStream | 
|  | import java.util.logging.Level | 
|  | import li.cil.oc.{Blocks, OpenComputers} | 
|  | import net.minecraft.item.ItemStack | 
|  | import net.minecraft.nbt.{NBTTagCompound, NBTBase} | 
|  | import net.minecraft.network.INetworkManager | 
|  | import net.minecraft.network.packet.Packet250CustomPayload | 
|  | import net.minecraft.world.World | 
|  | import net.minecraftforge.common.ForgeDirection | 
|  | import scala.reflect.ClassTag | 
|  | import scala.reflect.classTag | 
|  |  | 
|  | abstract class PacketHandler extends IPacketHandler { | 
|  | /** Top level dispatcher based on packet type. */ | 
|  | def onPacketData(manager: INetworkManager, packet: Packet250CustomPayload, player: Player) { | 
|  | // Don't crash on badly formatted packets (may have been altered by a | 
|  | // malicious client, in which case we don't want to allow it to kill the | 
|  | // server like this). Just spam the log a bit... ;) | 
|  | try { | 
|  | dispatch(new PacketParser(packet, player)) | 
|  | } catch { | 
|  | case e: Throwable => | 
|  | OpenComputers.log.log(Level.WARNING, "Received a badly formatted packet.", e) | 
|  | } | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Gets the world for the specified dimension. | 
|  | * | 
|  | * For clients this returns the client's world if it is the specified | 
|  | * dimension; None otherwise. For the server it returns the world for the | 
|  | * specified dimension, if such a dimension exists; None otherwise. | 
|  | */ | 
|  | protected def world(player: Player, dimension: Int): Option[World] | 
|  |  | 
|  | protected def dispatch(p: PacketParser) | 
|  |  | 
|  | protected class PacketParser(packet: Packet250CustomPayload, val player: Player) extends DataInputStream(new ByteArrayInputStream(packet.data)) { | 
|  | val packetType = PacketType(readByte()) | 
|  |  | 
|  | def readTileEntity[T: ClassTag](): Option[T] = { | 
|  | val dimension = readInt() | 
|  | val x = readInt() | 
|  | val y = readInt() | 
|  | val z = readInt() | 
|  |  | 
|  | world(player, dimension) match { | 
|  | case None => // Invalid dimension. | 
|  | case Some(world) => | 
|  | val t = world.getBlockTileEntity(x, y, z) | 
|  | if (t != null && classTag[T].runtimeClass.isAssignableFrom(t.getClass)) { | 
|  | return Some(t.asInstanceOf[T]) | 
|  | } | 
|  | // In case a robot moved away before the packet arrived. This is | 
|  | // mostly used when the robot *starts* moving while the client sends | 
|  | // a request to the server. | 
|  | Blocks.robotAfterimage.findMovingRobot(world, x, y, z) match { | 
|  | case Some(robot) if classTag[T].runtimeClass.isAssignableFrom(robot.proxy.getClass) => | 
|  | return Some(robot.proxy.asInstanceOf[T]) | 
|  | case _ => | 
|  | } | 
|  | } | 
|  | None | 
|  | } | 
|  |  | 
|  | def readDirection() = ForgeDirection.getOrientation(readInt()) | 
|  |  | 
|  | def readItemStack() = { | 
|  | val haveStack = readBoolean() | 
|  | if (haveStack) { | 
|  | ItemStack.loadItemStackFromNBT(readNBT().asInstanceOf[NBTTagCompound]) | 
|  | } | 
|  | else null | 
|  | } | 
|  |  | 
|  | def readNBT() = NBTBase.readNamedTag(this) | 
|  | } | 
|  |  | 
|  | } |