diff --git a/li/cil/oc/api/network/Analyzable.java b/li/cil/oc/api/network/Analyzable.java new file mode 100644 index 000000000..93bc3ff33 --- /dev/null +++ b/li/cil/oc/api/network/Analyzable.java @@ -0,0 +1,34 @@ +package li.cil.oc.api.network; + +import net.minecraft.entity.player.EntityPlayer; + +/** + * Allows defining a callback for when a block is right-clicked with an + * analyzer. + *
+ * This has to be implemented by a {@link net.minecraft.tileentity.TileEntity}, + * else it will have no effect. + */ +public interface Analyzable extends Environment { + /** + * Called when a player uses the analyzer tool on the tile entity's block. + * + * This can be used to display additional block specific information in the + * player's chat when the analyzer is used (or do whatever) and may also be + * used to redirect the query to some other environment by returning some + * other environment than this. The latter is used by multi-block + * screens, for example, to always show information of the primary screen. + * + * Return null to suppress any further node information being + * displayed. + * + * @param player the player that used the analyzer. + * @param side the side of the block the player clicked. + * @param hitX the relative X coordinate the player clicked. + * @param hitY the relative Y coordinate the player clicked. + * @param hitZ the relative Z coordinate the player clicked. + * @return the environment to display node information for, usually the + * environment itself (i.e. just return this). + */ + Environment onAnalyze(EntityPlayer player, int side, float hitX, float hitY, float hitZ); +} diff --git a/li/cil/oc/client/PacketHandler.scala b/li/cil/oc/client/PacketHandler.scala index 687399ef4..38f994619 100644 --- a/li/cil/oc/client/PacketHandler.scala +++ b/li/cil/oc/client/PacketHandler.scala @@ -10,6 +10,7 @@ import net.minecraft.client.gui.GuiScreen import net.minecraft.entity.player.EntityPlayer import net.minecraft.tileentity.TileEntity import net.minecraftforge.common.ForgeDirection +import org.lwjgl.input.Keyboard class PacketHandler extends CommonPacketHandler { protected override def world(player: Player, dimension: Int) = { @@ -36,8 +37,10 @@ class PacketHandler extends CommonPacketHandler { } def onClipboard(p: PacketParser) = { - GuiScreen.setClipboardString(p.readUTF()) - p.player.asInstanceOf[EntityPlayer].addChatMessage("Copied to clipboard.") + if (Keyboard.isKeyDown(Keyboard.KEY_LCONTROL) || Keyboard.isKeyDown(Keyboard.KEY_LCONTROL)) { + GuiScreen.setClipboardString(p.readUTF()) + p.player.asInstanceOf[EntityPlayer].addChatMessage("Copied to clipboard.") + } } def onComputerStateResponse(p: PacketParser) = diff --git a/li/cil/oc/common/block/Delegator.scala b/li/cil/oc/common/block/Delegator.scala index 868e72176..4e4539470 100644 --- a/li/cil/oc/common/block/Delegator.scala +++ b/li/cil/oc/common/block/Delegator.scala @@ -4,7 +4,7 @@ import cpw.mods.fml.common.registry.GameRegistry import java.util import li.cil.oc.api.network.Environment import li.cil.oc.common.tileentity.Rotatable -import li.cil.oc.{Items, Config, CreativeTab} +import li.cil.oc.{Config, CreativeTab} import net.minecraft.block.Block import net.minecraft.block.material.Material import net.minecraft.client.renderer.texture.IconRegister @@ -233,10 +233,6 @@ class Delegator[Child <: Delegate](id: Int) extends Block(id, Material.iron) { } override def onBlockActivated(world: World, x: Int, y: Int, z: Int, player: EntityPlayer, side: Int, hitX: Float, hitY: Float, hitZ: Float): Boolean = { - // Do nothing if we have an analyzer in hand. - if (Items.analyzer.equals(player.getCurrentEquippedItem)) - return false - // Helper method to detect items that can be used to rotate blocks, such as // wrenches. This structural type is compatible with the BuildCraft wrench // interface. @@ -331,12 +327,13 @@ class Delegator[Child <: Delegate](id: Int) extends Block(id, Material.iron) { case _ => true }) && super.removeBlockByPlayer(world, player, x, y, z) - override def rotateBlock(world: World, x: Int, y: Int, z: Int, axis: ForgeDirection) = { - val newFacing = getFacing(world, x, y, z).getRotation(axis) - if (getValidRotations(world, x, y, z).contains(newFacing)) - setFacing(world, x, y, z, newFacing) - else false - } + override def rotateBlock(world: World, x: Int, y: Int, z: Int, axis: ForgeDirection) = + world.getBlockTileEntity(x, y, z) match { + case rotatable: Rotatable if rotatable.rotate(axis) => + world.markBlockForRenderUpdate(x, y, z) + true + case _ => false + } } class SimpleDelegator(id: Int) extends Delegator[SimpleDelegate](id) diff --git a/li/cil/oc/common/block/Item.scala b/li/cil/oc/common/block/Item.scala index 5d97d3d14..5ef06bdc2 100644 --- a/li/cil/oc/common/block/Item.scala +++ b/li/cil/oc/common/block/Item.scala @@ -28,7 +28,8 @@ class Item(id: Int) extends ItemBlock(id) { // If it's a rotatable block try to make it face the player. world.getBlockTileEntity(x, y, z) match { case rotatable: Rotatable => - rotatable.setFromEntityPitchAndYaw(player).invertRotation() + rotatable.setFromEntityPitchAndYaw(player) + rotatable.invertRotation() case _ => // Ignore. } true diff --git a/li/cil/oc/common/item/Analyzer.scala b/li/cil/oc/common/item/Analyzer.scala index 420b81787..b57ddb090 100644 --- a/li/cil/oc/common/item/Analyzer.scala +++ b/li/cil/oc/common/item/Analyzer.scala @@ -2,8 +2,7 @@ package li.cil.oc.common.item import cpw.mods.fml.common.network.Player import li.cil.oc.Config -import li.cil.oc.api.network.{Connector, Environment} -import li.cil.oc.common.tileentity +import li.cil.oc.api.network.{Analyzable, Connector, Environment} import li.cil.oc.server.PacketSender import net.minecraft.client.renderer.texture.IconRegister import net.minecraft.entity.player.EntityPlayer @@ -15,18 +14,9 @@ class Analyzer(val parent: Delegator) extends Delegate { override def onItemUse(item: ItemStack, player: EntityPlayer, world: World, x: Int, y: Int, z: Int, side: Int, hitX: Float, hitY: Float, hitZ: Float) = { world.getBlockTileEntity(x, y, z) match { - case computer: tileentity.Computer => + case analyzable: Analyzable => if (!world.isRemote) { - computer.instance.lastError match { - case Some(value) => player.addChatMessage("Last error: " + value) - case _ => - } - analyzeNode(computer, player) - } - true - case screen: tileentity.Screen => - if (!world.isRemote) { - analyzeNode(screen.origin, player) + analyzeNode(analyzable.onAnalyze(player, side, hitX, hitY, hitZ), player) } true case environment: Environment => @@ -38,7 +28,7 @@ class Analyzer(val parent: Delegator) extends Delegate { } } - private def analyzeNode(environment: Environment, player: EntityPlayer) { + private def analyzeNode(environment: Environment, player: EntityPlayer) = if (environment != null) { environment.node match { case connector: Connector => player.addChatMessage("Power: %.2f/%.2f".format(connector.buffer, connector.bufferSize)) diff --git a/li/cil/oc/common/tileentity/Computer.scala b/li/cil/oc/common/tileentity/Computer.scala index 481ab5a2c..f0ba6a7ee 100644 --- a/li/cil/oc/common/tileentity/Computer.scala +++ b/li/cil/oc/common/tileentity/Computer.scala @@ -4,6 +4,7 @@ import cpw.mods.fml.common.Loader import li.cil.oc.Config import li.cil.oc.api.Network import li.cil.oc.api.driver.Slot +import li.cil.oc.api.network.Analyzable import li.cil.oc.client.{PacketSender => ClientPacketSender} import li.cil.oc.server.component import li.cil.oc.server.component.Computer.{Environment => ComputerEnvironment} @@ -17,7 +18,7 @@ import net.minecraft.item.ItemStack import net.minecraft.nbt.NBTTagCompound import net.minecraftforge.common.ForgeDirection -class Computer(isClient: Boolean) extends Rotatable with ComputerEnvironment with ComponentInventory with Redstone { +class Computer(isClient: Boolean) extends Rotatable with ComputerEnvironment with ComponentInventory with Redstone with Analyzable { def this() = this(false) // ----------------------------------------------------------------------- // @@ -50,6 +51,16 @@ class Computer(isClient: Boolean) extends Rotatable with ComputerEnvironment wit // ----------------------------------------------------------------------- // + def onAnalyze(player: EntityPlayer, side: Int, hitX: Float, hitY: Float, hitZ: Float) = { + instance.lastError match { + case Some(value) => player.addChatMessage("Last error: " + value) + case _ => + } + this + } + + // ----------------------------------------------------------------------- // + override def readFromNBT(nbt: NBTTagCompound) { super.readFromNBT(nbt) super.load(nbt) diff --git a/li/cil/oc/common/tileentity/Rotatable.scala b/li/cil/oc/common/tileentity/Rotatable.scala index 58159dcca..2214c0d87 100644 --- a/li/cil/oc/common/tileentity/Rotatable.scala +++ b/li/cil/oc/common/tileentity/Rotatable.scala @@ -127,6 +127,16 @@ abstract class Rotatable extends TileEntity { case _ => _yaw } + def rotate(axis: ForgeDirection) = { + val (newPitch, newYaw) = facing.getRotation(axis) match { + case value@(ForgeDirection.UP | ForgeDirection.DOWN) => + if (value == pitch) (value, yaw.getRotation(axis)) + else (value, yaw) + case value => (ForgeDirection.NORTH, value) + } + trySetPitchYaw(newPitch, newYaw) + } + def toLocal(value: ForgeDirection) = cachedTranslation(value.ordinal) def toGlobal(value: ForgeDirection) = cachedInverseTranslation(value.ordinal) @@ -173,16 +183,21 @@ abstract class Rotatable extends TileEntity { /** Validates new values against the allowed rotations as set in our block. */ private def trySetPitchYaw(pitch: ForgeDirection, yaw: ForgeDirection) = { + var changed = false val block = Block.blocksList(worldObj.getBlockId(xCoord, yCoord, zCoord)) if (block != null) { val valid = block.getValidRotations(worldObj, xCoord, yCoord, zCoord) - if (valid.contains(pitch)) + if (valid.contains(pitch)) { + changed = true _pitch = pitch - if (valid.contains(yaw)) + } + if (valid.contains(yaw)) { + changed = true _yaw = yaw + } updateTranslation() } - this + changed } private def invert(t: Array[ForgeDirection]) = diff --git a/li/cil/oc/common/tileentity/Screen.scala b/li/cil/oc/common/tileentity/Screen.scala index 2102f273d..d572bda46 100644 --- a/li/cil/oc/common/tileentity/Screen.scala +++ b/li/cil/oc/common/tileentity/Screen.scala @@ -2,13 +2,14 @@ package li.cil.oc.common.tileentity import li.cil.oc.Config import li.cil.oc.api.Network -import li.cil.oc.api.network.Visibility +import li.cil.oc.api.network.{Analyzable, Visibility} import li.cil.oc.client.gui import li.cil.oc.client.{PacketSender => ClientPacketSender} import li.cil.oc.common.component.Screen.{Environment => ScreenEnvironment} import li.cil.oc.server.{PacketSender => ServerPacketSender} import li.cil.oc.util.PackedColor import net.minecraft.client.Minecraft +import net.minecraft.entity.player.EntityPlayer import net.minecraft.nbt.NBTTagCompound import net.minecraft.util.AxisAlignedBB import net.minecraftforge.common.ForgeDirection @@ -26,7 +27,7 @@ class ScreenTier3 extends Screen { protected def tier = 2 } -abstract class Screen extends Rotatable with ScreenEnvironment { +abstract class Screen extends Rotatable with ScreenEnvironment with Analyzable { var currentGui: Option[gui.Screen] = None /** @@ -68,6 +69,10 @@ abstract class Screen extends Rotatable with ScreenEnvironment { // ----------------------------------------------------------------------- // + def onAnalyze(player: EntityPlayer, side: Int, hitX: Float, hitY: Float, hitZ: Float) = origin + + // ----------------------------------------------------------------------- // + override def readFromNBT(nbt: NBTTagCompound) { super.readFromNBT(nbt) super.load(nbt)