Merge branch 'master-MC1.7.10' of github.com:MightyPirates/OpenComputers into master-MC1.8

Conflicts:
	src/main/scala/li/cil/oc/client/renderer/tileentity/RobotRenderer.scala
	src/main/scala/li/cil/oc/common/EventHandler.scala
	src/main/scala/li/cil/oc/common/block/Case.scala
	src/main/scala/li/cil/oc/common/block/Screen.scala
	src/main/scala/li/cil/oc/common/component/Terminal.scala
	src/main/scala/li/cil/oc/common/component/TextBuffer.scala
	src/main/scala/li/cil/oc/common/item/Analyzer.scala
	src/main/scala/li/cil/oc/common/tileentity/Screen.scala
	src/main/scala/li/cil/oc/server/component/DebugCard.scala
	src/main/scala/li/cil/oc/server/component/Geolyzer.scala
This commit is contained in:
Florian Nücke 2015-02-03 01:39:50 +01:00
commit 57b8968060
24 changed files with 330 additions and 32 deletions

View File

@ -153,6 +153,7 @@ public interface Context {
* <li>Strings.</li> * <li>Strings.</li>
* <li>Byte arrays (which appear as strings on the Lua side, e.g.).</li> * <li>Byte arrays (which appear as strings on the Lua side, e.g.).</li>
* <li>Maps if and only if both keys and values are strings.</li> * <li>Maps if and only if both keys and values are strings.</li>
* <li>NBTTagCompounds.</li>
* </ul> * </ul>
* If an unsupported type is specified the method will enqueue nothing * If an unsupported type is specified the method will enqueue nothing
* instead, resulting in a <tt>nil</tt> on the Lua side, e.g., and log a * instead, resulting in a <tt>nil</tt> on the Lua side, e.g., and log a

View File

@ -110,6 +110,15 @@ object PacketSender {
pb.sendToServer() pb.sendToServer()
} }
def sendCopyToAnalyzer(address: String, line: Int): Unit = {
val pb = new SimplePacketBuilder(PacketType.CopyToAnalyzer)
pb.writeUTF(address)
pb.writeInt(line)
pb.sendToServer()
}
def sendMultiPlace() { def sendMultiPlace() {
val pb = new SimplePacketBuilder(PacketType.MultiPartPlace) val pb = new SimplePacketBuilder(PacketType.MultiPartPlace)
pb.sendToServer() pb.sendToServer()

View File

@ -284,7 +284,7 @@ object RobotRenderer extends TileEntitySpecialRenderer {
val timeJitter = robot.hashCode ^ 0xFF val timeJitter = robot.hashCode ^ 0xFF
val hover = val hover =
if (robot.isRunning) (Math.sin(timeJitter + (worldTime + f) / 20.0) * 0.03).toFloat if (robot.isRunning) (Math.sin(timeJitter + worldTime / 20.0) * 0.03).toFloat
else -0.03f else -0.03f
GL11.glTranslatef(0, hover, 0) GL11.glTranslatef(0, hover, 0)

View File

@ -19,6 +19,7 @@ import net.minecraft.item.ItemStack
import net.minecraft.server.MinecraftServer import net.minecraft.server.MinecraftServer
import net.minecraft.tileentity.TileEntity import net.minecraft.tileentity.TileEntity
import net.minecraftforge.common.util.FakePlayer import net.minecraftforge.common.util.FakePlayer
import net.minecraftforge.event.world.BlockEvent
import net.minecraftforge.event.world.WorldEvent import net.minecraftforge.event.world.WorldEvent
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
import net.minecraftforge.fml.common.gameevent.PlayerEvent._ import net.minecraftforge.fml.common.gameevent.PlayerEvent._
@ -114,6 +115,22 @@ object EventHandler {
} }
} }
@SubscribeEvent
def onBlockBreak(e: BlockEvent.BreakEvent): Unit = {
e.world.getTileEntity(e.pos) match {
case c: tileentity.Case =>
if (c.isCreative && (!e.getPlayer.capabilities.isCreativeMode || !c.canInteract(e.getPlayer.getName))) {
e.setCanceled(true)
}
case r: tileentity.RobotProxy =>
val robot = r.robot
if (robot.isCreative && (!e.getPlayer.capabilities.isCreativeMode || !robot.canInteract(e.getPlayer.getName))) {
e.setCanceled(true)
}
case _ =>
}
}
lazy val drone = api.Items.get("drone") lazy val drone = api.Items.get("drone")
lazy val eeprom = api.Items.get("eeprom") lazy val eeprom = api.Items.get("eeprom")
lazy val mcu = api.Items.get("microcontroller") lazy val mcu = api.Items.get("microcontroller")

View File

@ -51,6 +51,7 @@ object PacketType extends Enumeration {
// Client -> Server // Client -> Server
ComputerPower, ComputerPower,
CopyToAnalyzer,
DronePower, DronePower,
KeyDown, KeyDown,
KeyUp, KeyUp,

View File

@ -86,7 +86,9 @@ class Case(val tier: Int) extends RedstoneAware with traits.PowerAcceptor with t
override def removedByPlayer(world: World, pos: BlockPos, player: EntityPlayer, willHarvest: Boolean) = override def removedByPlayer(world: World, pos: BlockPos, player: EntityPlayer, willHarvest: Boolean) =
world.getTileEntity(pos) match { world.getTileEntity(pos) match {
case c: tileentity.Case => c.canInteract(player.getName) && super.removedByPlayer(world, pos, player, willHarvest) case c: tileentity.Case =>
if (c.isCreative && (!player.capabilities.isCreativeMode || !c.canInteract(player.getName))) false
else c.canInteract(player.getName) && super.removedByPlayer(world, pos, player, willHarvest)
case _ => super.removedByPlayer(world, pos, player, willHarvest) case _ => super.removedByPlayer(world, pos, player, willHarvest)
} }
} }

View File

@ -230,6 +230,11 @@ class RobotProxy extends RedstoneAware with traits.StateAware {
world.getTileEntity(pos) match { world.getTileEntity(pos) match {
case proxy: tileentity.RobotProxy => case proxy: tileentity.RobotProxy =>
val robot = proxy.robot val robot = proxy.robot
// Only allow breaking creative tier robots by allowed users.
// Unlike normal robots, griefing isn't really a valid concern
// here, because to get a creative robot you need creative
// mode in the first place.
if (robot.isCreative && (!player.capabilities.isCreativeMode || !robot.canInteract(player.getName))) return false
if (!world.isRemote) { if (!world.isRemote) {
if (robot.player == player) return false if (robot.player == player) return false
robot.node.remove() robot.node.remove()

View File

@ -4,6 +4,7 @@ import java.util
import li.cil.oc.OpenComputers import li.cil.oc.OpenComputers
import li.cil.oc.Settings import li.cil.oc.Settings
import li.cil.oc.api
import li.cil.oc.common.GuiType import li.cil.oc.common.GuiType
import li.cil.oc.common.tileentity import li.cil.oc.common.tileentity
import li.cil.oc.integration.util.Wrench import li.cil.oc.integration.util.Wrench
@ -13,6 +14,7 @@ import li.cil.oc.util.Rarity
import li.cil.oc.util.Tooltip import li.cil.oc.util.Tooltip
import net.minecraft.block.properties.IProperty import net.minecraft.block.properties.IProperty
import net.minecraft.block.state.IBlockState import net.minecraft.block.state.IBlockState
import net.minecraft.client.Minecraft
import net.minecraft.entity.Entity import net.minecraft.entity.Entity
import net.minecraft.entity.EntityLivingBase import net.minecraft.entity.EntityLivingBase
import net.minecraft.entity.player.EntityPlayer import net.minecraft.entity.player.EntityPlayer
@ -88,6 +90,7 @@ class Screen(val tier: Int) extends RedstoneAware with traits.OmniRotatable {
def rightClick(world: World, pos: BlockPos, player: EntityPlayer, def rightClick(world: World, pos: BlockPos, player: EntityPlayer,
side: EnumFacing, hitX: Float, hitY: Float, hitZ: Float, force: Boolean) = { side: EnumFacing, hitX: Float, hitY: Float, hitZ: Float, force: Boolean) = {
if (Wrench.holdsApplicableWrench(player, pos) && getValidRotations(world, pos).contains(side) && !force) false if (Wrench.holdsApplicableWrench(player, pos) && getValidRotations(world, pos).contains(side) && !force) false
else if (api.Items.get(player.getHeldItem) == api.Items.get("analyzer")) false
else world.getTileEntity(pos) match { else world.getTileEntity(pos) match {
case screen: tileentity.Screen if screen.hasKeyboard && (force || player.isSneaking == screen.invertTouchMode) => case screen: tileentity.Screen if screen.hasKeyboard && (force || player.isSneaking == screen.invertTouchMode) =>
// Yep, this GUI is actually purely client side. We could skip this // Yep, this GUI is actually purely client side. We could skip this
@ -98,7 +101,10 @@ class Screen(val tier: Int) extends RedstoneAware with traits.OmniRotatable {
} }
true true
case screen: tileentity.Screen if screen.tier > 0 && side == screen.facing => case screen: tileentity.Screen if screen.tier > 0 && side == screen.facing =>
screen.click(player, hitX, hitY, hitZ) if (world.isRemote && player == Minecraft.getMinecraft.thePlayer) {
screen.click(hitX, hitY, hitZ)
}
else true
case _ => false case _ => false
} }
} }

View File

@ -6,6 +6,7 @@ import li.cil.oc.api.component.Keyboard.UsabilityChecker
import li.cil.oc.api.network.Component import li.cil.oc.api.network.Component
import li.cil.oc.api.network.Node import li.cil.oc.api.network.Node
import li.cil.oc.api.network.Visibility import li.cil.oc.api.network.Visibility
import li.cil.oc.common.Tier
import li.cil.oc.common.item import li.cil.oc.common.item
import li.cil.oc.common.item.Delegator import li.cil.oc.common.item.Delegator
import li.cil.oc.common.tileentity import li.cil.oc.common.tileentity
@ -23,9 +24,9 @@ class Terminal(val rack: tileentity.ServerRack, val number: Int) {
val buffer = { val buffer = {
val screenItem = api.Items.get("screen1").createItemStack(1) val screenItem = api.Items.get("screen1").createItemStack(1)
val buffer = api.Driver.driverFor(screenItem, rack.getClass).createEnvironment(screenItem, rack).asInstanceOf[api.component.TextBuffer] val buffer = api.Driver.driverFor(screenItem, rack.getClass).createEnvironment(screenItem, rack).asInstanceOf[api.component.TextBuffer]
val (maxWidth, maxHeight) = Settings.screenResolutionsByTier(1) val (maxWidth, maxHeight) = Settings.screenResolutionsByTier(Tier.Three)
buffer.setMaximumResolution(maxWidth, maxHeight) buffer.setMaximumResolution(maxWidth, maxHeight)
buffer.setMaximumColorDepth(Settings.screenDepthsByTier(1)) buffer.setMaximumColorDepth(Settings.screenDepthsByTier(Tier.Three))
buffer buffer
} }

View File

@ -415,6 +415,10 @@ class TextBuffer(val host: EnvironmentHost) extends prefab.ManagedEnvironment wi
override def mouseScroll(x: Double, y: Double, delta: Int, player: EntityPlayer) = override def mouseScroll(x: Double, y: Double, delta: Int, player: EntityPlayer) =
proxy.mouseScroll(x, y, delta, player) proxy.mouseScroll(x, y, delta, player)
def copyToAnalyzer(line: Int, player: EntityPlayer): Unit = {
proxy.copyToAnalyzer(line, player)
}
// ----------------------------------------------------------------------- // // ----------------------------------------------------------------------- //
override def onConnect(node: Node) { override def onConnect(node: Node) {
@ -588,6 +592,8 @@ object TextBuffer {
def mouseUp(x: Double, y: Double, button: Int, player: EntityPlayer): Unit def mouseUp(x: Double, y: Double, button: Int, player: EntityPlayer): Unit
def mouseScroll(x: Double, y: Double, delta: Int, player: EntityPlayer): Unit def mouseScroll(x: Double, y: Double, delta: Int, player: EntityPlayer): Unit
def copyToAnalyzer(line: Int, player: EntityPlayer): Unit
} }
class ClientProxy(val owner: TextBuffer) extends Proxy { class ClientProxy(val owner: TextBuffer) extends Proxy {
@ -672,6 +678,10 @@ object TextBuffer {
ClientPacketSender.sendMouseScroll(nodeAddress, x, y, delta) ClientPacketSender.sendMouseScroll(nodeAddress, x, y, delta)
} }
override def copyToAnalyzer(line: Int, player: EntityPlayer): Unit = {
ClientPacketSender.sendCopyToAnalyzer(nodeAddress, line)
}
private lazy val Debugger = api.Items.get("debugger") private lazy val Debugger = api.Items.get("debugger")
private def debug(message: String) { private def debug(message: String) {
@ -775,6 +785,27 @@ object TextBuffer {
sendMouseEvent(player, "scroll", x, y, delta) sendMouseEvent(player, "scroll", x, y, delta)
} }
override def copyToAnalyzer(line: Int, player: EntityPlayer): Unit = {
val stack = player.getHeldItem
if (stack != null) {
if (!stack.hasTagCompound) {
stack.setTagCompound(new NBTTagCompound())
}
stack.getTagCompound.removeTag(Settings.namespace + "clipboard")
if (line >= 0 && line < owner.data.height) {
val text = new String(owner.data.buffer(line)).trim
if (!Strings.isNullOrEmpty(text)) {
stack.getTagCompound.setString(Settings.namespace + "clipboard", text)
}
}
if (stack.getTagCompound.hasNoTags) {
stack.setTagCompound(null)
}
}
}
private def sendMouseEvent(player: EntityPlayer, name: String, x: Double, y: Double, data: Int) = { private def sendMouseEvent(player: EntityPlayer, name: String, x: Double, y: Double, data: Int) = {
val args = mutable.ArrayBuffer.empty[AnyRef] val args = mutable.ArrayBuffer.empty[AnyRef]

View File

@ -1,9 +1,11 @@
package li.cil.oc.common.item package li.cil.oc.common.item
import li.cil.oc.Localization import li.cil.oc.Localization
import li.cil.oc.Settings
import li.cil.oc.api import li.cil.oc.api
import li.cil.oc.api.network.Analyzable import li.cil.oc.api.network.Analyzable
import li.cil.oc.api.network._ import li.cil.oc.api.network._
import li.cil.oc.common.tileentity
import li.cil.oc.server.PacketSender import li.cil.oc.server.PacketSender
import li.cil.oc.util.BlockPosition import li.cil.oc.util.BlockPosition
import li.cil.oc.util.ExtendedWorld._ import li.cil.oc.util.ExtendedWorld._
@ -11,6 +13,7 @@ import net.minecraft.entity.player.EntityPlayer
import net.minecraft.entity.player.EntityPlayerMP import net.minecraft.entity.player.EntityPlayerMP
import net.minecraft.item.ItemStack import net.minecraft.item.ItemStack
import net.minecraft.util.EnumFacing import net.minecraft.util.EnumFacing
import net.minecraft.world.World
import net.minecraftforge.event.entity.player.EntityInteractEvent import net.minecraftforge.event.entity.player.EntityInteractEvent
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
@ -79,7 +82,31 @@ object Analyzer {
} }
class Analyzer(val parent: Delegator) extends Delegate { class Analyzer(val parent: Delegator) extends Delegate {
override def onItemRightClick(stack: ItemStack, world: World, player: EntityPlayer): ItemStack = {
if (player.isSneaking && stack.hasTagCompound) {
stack.getTagCompound.removeTag(Settings.namespace + "clipboard")
if (stack.getTagCompound.hasNoTags) {
stack.setTagCompound(null)
}
}
super.onItemRightClick(stack, world, player)
}
override def onItemUse(stack: ItemStack, player: EntityPlayer, position: BlockPosition, side: EnumFacing, hitX: Float, hitY: Float, hitZ: Float) = { override def onItemUse(stack: ItemStack, player: EntityPlayer, position: BlockPosition, side: EnumFacing, hitX: Float, hitY: Float, hitZ: Float) = {
Analyzer.analyze(position.world.get.getTileEntity(position), player, side, hitX, hitY, hitZ) val world = player.getEntityWorld
world.getTileEntity(position) match {
case screen: tileentity.Screen if side == screen.facing =>
if (player.isSneaking) {
screen.copyToAnalyzer(hitX, hitY, hitZ)
}
else if (stack.hasTagCompound && stack.getTagCompound.hasKey(Settings.namespace + "clipboard")) {
if (!world.isRemote) {
screen.origin.buffer.clipboard(stack.getTagCompound.getString(Settings.namespace + "clipboard"), player)
}
true
}
else false
case _ => Analyzer.analyze(position.world.get.getTileEntity(position), player, side, hitX, hitY, hitZ)
}
} }
} }

View File

@ -29,6 +29,7 @@ import li.cil.oc.common.inventory.ComponentInventory
import li.cil.oc.common.item.data.TabletData import li.cil.oc.common.item.data.TabletData
import li.cil.oc.integration.opencomputers.DriverScreen import li.cil.oc.integration.opencomputers.DriverScreen
import li.cil.oc.server.component import li.cil.oc.server.component
import li.cil.oc.util.BlockPosition
import li.cil.oc.util.ExtendedNBT._ import li.cil.oc.util.ExtendedNBT._
import li.cil.oc.util.Rarity import li.cil.oc.util.Rarity
import li.cil.oc.util.RotationHelper import li.cil.oc.util.RotationHelper
@ -93,6 +94,24 @@ class Tablet(val parent: Delegator) extends Delegate {
case _ => case _ =>
} }
override def onItemUse(stack: ItemStack, player: EntityPlayer, position: BlockPosition, side: EnumFacing, hitX: Float, hitY: Float, hitZ: Float): Boolean = {
val world = player.getEntityWorld
if (!world.isRemote) try {
val computer = Tablet.get(stack, player).machine
if (computer.isRunning) {
val data = new NBTTagCompound()
computer.node.sendToReachable("tablet.use", data, stack, player, position, side, float2Float(hitX), float2Float(hitY), float2Float(hitZ))
if (!data.hasNoTags) {
computer.signal("tablet_use", data)
}
}
}
catch {
case t: Throwable => OpenComputers.log.warn("Block analysis on tablet right click failed gloriously!", t)
}
true
}
override def onItemRightClick(stack: ItemStack, world: World, player: EntityPlayer) = { override def onItemRightClick(stack: ItemStack, world: World, player: EntityPlayer) = {
if (!player.isSneaking) { if (!player.isSneaking) {
if (world.isRemote) { if (world.isRemote) {

View File

@ -35,7 +35,7 @@ class Case(var tier: Int) extends traits.PowerAcceptor with traits.Computer with
var maxComponents = 0 var maxComponents = 0
private def isCreativeCase = tier == Tier.Four def isCreative = tier == Tier.Four
// ----------------------------------------------------------------------- // // ----------------------------------------------------------------------- //
@ -74,7 +74,7 @@ class Case(var tier: Int) extends traits.PowerAcceptor with traits.Computer with
override def canUpdate = isServer override def canUpdate = isServer
override def updateEntity() { override def updateEntity() {
if (isServer && isCreativeCase && world.getTotalWorldTime % Settings.get.tickFrequency == 0) { if (isServer && isCreative && world.getTotalWorldTime % Settings.get.tickFrequency == 0) {
// Creative case, make it generate power. // Creative case, make it generate power.
node.asInstanceOf[Connector].changeBuffer(Double.PositiveInfinity) node.asInstanceOf[Connector].changeBuffer(Double.PositiveInfinity)
} }
@ -135,7 +135,7 @@ class Case(var tier: Int) extends traits.PowerAcceptor with traits.Computer with
override def getSizeInventory = if (tier < 0 || tier >= InventorySlots.computer.length) 0 else InventorySlots.computer(tier).length override def getSizeInventory = if (tier < 0 || tier >= InventorySlots.computer.length) 0 else InventorySlots.computer(tier).length
override def isUseableByPlayer(player: EntityPlayer) = override def isUseableByPlayer(player: EntityPlayer) =
super.isUseableByPlayer(player) && (!isCreativeCase || player.capabilities.isCreativeMode) super.isUseableByPlayer(player) && (!isCreative || player.capabilities.isCreativeMode)
override def isItemValidForSlot(slot: Int, stack: ItemStack) = override def isItemValidForSlot(slot: Int, stack: ItemStack) =
Option(Driver.driverFor(stack, getClass)).fold(false)(driver => { Option(Driver.driverFor(stack, getClass)).fold(false)(driver => {

View File

@ -70,6 +70,8 @@ class Robot extends traits.Computer with traits.PowerInformation with traits.Rot
override def tier = info.tier override def tier = info.tier
def isCreative = tier == Tier.Four
// Wrapper for the part of the inventory that is mutable. // Wrapper for the part of the inventory that is mutable.
val dynamicInventory = new IInventory { val dynamicInventory = new IInventory {
override def getSizeInventory = Robot.this.inventorySize override def getSizeInventory = Robot.this.inventorySize
@ -749,6 +751,9 @@ class Robot extends traits.Computer with traits.PowerInformation with traits.Rot
else if (stack != null && stack.stackSize > 0) spawnStackInWorld(stack, Option(EnumFacing.UP)) else if (stack != null && stack.stackSize > 0) spawnStackInWorld(stack, Option(EnumFacing.UP))
} }
override def isUseableByPlayer(player: EntityPlayer) =
super.isUseableByPlayer(player) && (!isCreative || player.capabilities.isCreativeMode)
override def isItemValidForSlot(slot: Int, stack: ItemStack) = (slot, Option(Driver.driverFor(stack, getClass))) match { override def isItemValidForSlot(slot: Int, stack: ItemStack) = (slot, Option(Driver.driverFor(stack, getClass))) match {
case (0, _) => true // Allow anything in the tool slot. case (0, _) => true // Allow anything in the tool slot.
case (i, Some(driver)) if isContainerSlot(i) => case (i, Some(driver)) if isContainerSlot(i) =>

View File

@ -3,6 +3,7 @@ package li.cil.oc.common.tileentity
import li.cil.oc.Settings import li.cil.oc.Settings
import li.cil.oc.api.network.Analyzable import li.cil.oc.api.network.Analyzable
import li.cil.oc.api.network._ import li.cil.oc.api.network._
import li.cil.oc.common.component.TextBuffer
import li.cil.oc.util.BlockPosition import li.cil.oc.util.BlockPosition
import li.cil.oc.util.Color import li.cil.oc.util.Color
import li.cil.oc.util.ExtendedWorld._ import li.cil.oc.util.ExtendedWorld._
@ -95,7 +96,7 @@ class Screen(var tier: Int) extends traits.TextBuffer with SidedEnvironment with
invertTouchMode = false invertTouchMode = false
} }
def click(player: EntityPlayer, hitX: Double, hitY: Double, hitZ: Double): Boolean = { def toScreenCoordinates(hitX: Double, hitY: Double, hitZ: Double): (Boolean, Option[(Double, Double)]) = {
// Compute absolute position of the click on the face, measured in blocks. // Compute absolute position of the click on the face, measured in blocks.
def dot(f: EnumFacing) = f.getFrontOffsetX * hitX + f.getFrontOffsetY * hitY + f.getFrontOffsetZ * hitZ def dot(f: EnumFacing) = f.getFrontOffsetX * hitX + f.getFrontOffsetY * hitY + f.getFrontOffsetZ * hitZ
val (hx, hy) = (dot(toGlobal(EnumFacing.EAST)), dot(toGlobal(EnumFacing.UP))) val (hx, hy) = (dot(toGlobal(EnumFacing.EAST)), dot(toGlobal(EnumFacing.UP)))
@ -107,9 +108,9 @@ class Screen(var tier: Int) extends traits.TextBuffer with SidedEnvironment with
// Get the relative position in the *display area* of the face. // Get the relative position in the *display area* of the face.
val border = 2.25 / 16.0 val border = 2.25 / 16.0
if (ax <= border || ay <= border || ax >= width - border || ay >= height - border) { if (ax <= border || ay <= border || ax >= width - border || ay >= height - border) {
return false return (false, None)
} }
if (!world.isRemote) return true if (!world.isRemote) return (true, None)
val (iw, ih) = (width - border * 2, height - border * 2) val (iw, ih) = (width - border * 2, height - border * 2)
val (rx, ry) = ((ax - border) / iw, (ay - border) / ih) val (rx, ry) = ((ax - border) / iw, (ay - border) / ih)
@ -121,27 +122,43 @@ class Screen(var tier: Int) extends traits.TextBuffer with SidedEnvironment with
val (brx, bry) = if (bpw > bph) { val (brx, bry) = if (bpw > bph) {
val rh = bph.toDouble / bpw.toDouble val rh = bph.toDouble / bpw.toDouble
val bry = (ry - (1 - rh) * 0.5) / rh val bry = (ry - (1 - rh) * 0.5) / rh
if (bry <= 0 || bry >= 1) {
return true
}
(rx, bry) (rx, bry)
} }
else if (bph > bpw) { else if (bph > bpw) {
val rw = bpw.toDouble / bph.toDouble val rw = bpw.toDouble / bph.toDouble
val brx = (rx - (1 - rw) * 0.5) / rw val brx = (rx - (1 - rw) * 0.5) / rw
if (brx <= 0 || brx >= 1) {
return true
}
(brx, ry) (brx, ry)
} }
else { else {
(rx, ry) (rx, ry)
} }
// Convert to absolute coordinates and send the packet to the server. val inBounds = bry >= 0 && bry <= 1 && brx >= 0 || brx <= 1
origin.buffer.mouseDown(brx * bw, bry * bh, 0, null) (inBounds, Some((brx * bw, bry * bh)))
}
true def copyToAnalyzer(hitX: Double, hitY: Double, hitZ: Double): Boolean = {
val (inBounds, coordinates) = toScreenCoordinates(hitX, hitY, hitZ)
coordinates match {
case Some((x, y)) => origin.buffer match {
case buffer: TextBuffer =>
buffer.copyToAnalyzer(y.toInt, null)
true
case _ => false
}
case _ => inBounds
}
}
def click(hitX: Double, hitY: Double, hitZ: Double): Boolean = {
val (inBounds, coordinates) = toScreenCoordinates(hitX, hitY, hitZ)
coordinates match {
case Some((x, y)) =>
// Send the packet to the server (manually, for accuracy).
origin.buffer.mouseDown(x, y, 0, null)
true
case _ => inBounds
}
} }
def walk(entity: Entity) { def walk(entity: Entity) {
@ -238,7 +255,7 @@ class Screen(var tier: Int) extends traits.TextBuffer with SidedEnvironment with
hitXInner && !hitYInner && hitZInner || hitXInner && !hitYInner && hitZInner ||
!hitXInner && hitYInner && hitZInner) { !hitXInner && hitYInner && hitZInner) {
arrow.shootingEntity match { arrow.shootingEntity match {
case player: EntityPlayer if player == Minecraft.getMinecraft.thePlayer => click(player, hitX, hitY, hitZ) case player: EntityPlayer if player == Minecraft.getMinecraft.thePlayer => click(hitX, hitY, hitZ)
case _ => case _ =>
} }
} }

View File

@ -0,0 +1,35 @@
package li.cil.oc.integration.vanilla
import java.util
import li.cil.oc.api
import net.minecraft.nbt._
import scala.collection.convert.WrapAsScala._
object ConverterNBT extends api.driver.Converter {
override def convert(value: AnyRef, output: util.Map[AnyRef, AnyRef]) =
value match {
case nbt: NBTTagCompound => output += "oc:flatten" -> convert(nbt)
case _ =>
}
private def convert(nbt: NBTBase): AnyRef = nbt match {
case tag: NBTTagByte => byte2Byte(tag.getByte)
case tag: NBTTagShort => short2Short(tag.getShort)
case tag: NBTTagInt => int2Integer(tag.getInt)
case tag: NBTTagLong => long2Long(tag.getLong)
case tag: NBTTagFloat => float2Float(tag.getFloat)
case tag: NBTTagDouble => double2Double(tag.getDouble)
case tag: NBTTagByteArray => tag.getByteArray
case tag: NBTTagString => tag.getString
case tag: NBTTagList =>
val copy = tag.copy().asInstanceOf[NBTTagList]
(0 until copy.tagCount).map(_ => convert(copy.removeTag(0))).toArray
case tag: NBTTagCompound =>
tag.getKeySet.collect {
case key: String => key -> convert(tag.getTag(key))
}.toMap
case tag: NBTTagIntArray => tag.getIntArray
}
}

View File

@ -31,5 +31,6 @@ object ModVanilla extends ModProxy {
Driver.add(ConverterFluidStack) Driver.add(ConverterFluidStack)
Driver.add(ConverterFluidTankInfo) Driver.add(ConverterFluidTankInfo)
Driver.add(ConverterItemStack) Driver.add(ConverterItemStack)
Driver.add(ConverterNBT)
} }
} }

View File

@ -36,6 +36,7 @@ object PacketHandler extends CommonPacketHandler {
override def dispatch(p: PacketParser) { override def dispatch(p: PacketParser) {
p.packetType match { p.packetType match {
case PacketType.ComputerPower => onComputerPower(p) case PacketType.ComputerPower => onComputerPower(p)
case PacketType.CopyToAnalyzer => onCopyToAnalyzer(p)
case PacketType.DronePower => onDronePower(p) case PacketType.DronePower => onDronePower(p)
case PacketType.KeyDown => onKeyDown(p) case PacketType.KeyDown => onKeyDown(p)
case PacketType.KeyUp => onKeyUp(p) case PacketType.KeyUp => onKeyUp(p)
@ -73,6 +74,13 @@ object PacketHandler extends CommonPacketHandler {
case _ => // Invalid packet. case _ => // Invalid packet.
} }
def onCopyToAnalyzer(p: PacketParser) {
ComponentTracker.get(p.player.worldObj, p.readUTF()) match {
case Some(buffer: TextBuffer) => buffer.copyToAnalyzer(p.readInt(), p.player.asInstanceOf[EntityPlayer])
case _ => // Invalid Packet
}
}
def onDronePower(p: PacketParser) = def onDronePower(p: PacketParser) =
p.readEntity[Drone]() match { p.readEntity[Drone]() match {
case Some(drone) => p.player match { case Some(drone) => p.player match {

View File

@ -35,6 +35,9 @@ import net.minecraft.world.WorldServer
import net.minecraft.world.WorldSettings.GameType import net.minecraft.world.WorldSettings.GameType
import net.minecraftforge.common.DimensionManager import net.minecraftforge.common.DimensionManager
import net.minecraftforge.common.util.FakePlayerFactory import net.minecraftforge.common.util.FakePlayerFactory
import net.minecraftforge.fluids.FluidRegistry
import net.minecraftforge.fluids.FluidStack
import net.minecraftforge.fluids.IFluidHandler
class DebugCard(host: EnvironmentHost) extends prefab.ManagedEnvironment { class DebugCard(host: EnvironmentHost) extends prefab.ManagedEnvironment {
override val node = Network.newNode(this, Visibility.Neighbors). override val node = Network.newNode(this, Visibility.Neighbors).
@ -426,6 +429,7 @@ object DebugCard {
@Callback(doc = """function(x:number, y:number, z:number, slot:number[, count:number]):number - Reduce the size of an item stack in the inventory at the specified location.""") @Callback(doc = """function(x:number, y:number, z:number, slot:number[, count:number]):number - Reduce the size of an item stack in the inventory at the specified location.""")
def removeItem(context: Context, args: Arguments): Array[AnyRef] = { def removeItem(context: Context, args: Arguments): Array[AnyRef] = {
checkEnabled()
val position = BlockPosition(args.checkDouble(0), args.checkDouble(1), args.checkDouble(2), world) val position = BlockPosition(args.checkDouble(0), args.checkDouble(1), args.checkDouble(2), world)
InventoryUtils.inventoryAt(position) match { InventoryUtils.inventoryAt(position) match {
case Some(inventory) => case Some(inventory) =>
@ -438,6 +442,34 @@ object DebugCard {
} }
} }
@Callback(doc = """function(id:string, amount:number, x:number, y:number, z:number, side:number):boolean - Insert some fluid into the tank at the specified location.""")
def insertFluid(context: Context, args: Arguments): Array[AnyRef] = {
checkEnabled()
val fluid = FluidRegistry.getFluid(args.checkString(0))
if (fluid == null) {
throw new IllegalArgumentException("invalid fluid id")
}
val amount = args.checkInteger(1)
val position = BlockPosition(args.checkDouble(2), args.checkDouble(3), args.checkDouble(4), world)
val side = args.checkSide(5, EnumFacing.values: _*)
world.getTileEntity(position) match {
case handler: IFluidHandler => result(handler.fill(side, new FluidStack(fluid, amount), true))
case _ => result(null, "no tank")
}
}
@Callback(doc = """function(amount:number, x:number, y:number, z:number, side:number):boolean - Remove some fluid from a tank at the specified location.""")
def removeFluid(context: Context, args: Arguments): Array[AnyRef] = {
checkEnabled()
val amount = args.checkInteger(0)
val position = BlockPosition(args.checkDouble(1), args.checkDouble(2), args.checkDouble(3), world)
val side = args.checkSide(4, EnumFacing.values: _*)
world.getTileEntity(position) match {
case handler: IFluidHandler => result(handler.drain(side, amount, true))
case _ => result(null, "no tank")
}
}
// ----------------------------------------------------------------------- // // ----------------------------------------------------------------------- //
override def load(nbt: NBTTagCompound) { override def load(nbt: NBTTagCompound) {

View File

@ -1,22 +1,27 @@
package li.cil.oc.server.component package li.cil.oc.server.component
import com.google.common.base.Strings
import li.cil.oc.Settings import li.cil.oc.Settings
import li.cil.oc.api import li.cil.oc.api
import li.cil.oc.api.driver.EnvironmentHost import li.cil.oc.api.driver.EnvironmentHost
import li.cil.oc.api.event.GeolyzerEvent import li.cil.oc.api.event.GeolyzerEvent
import li.cil.oc.api.event.GeolyzerEvent.Analyze import li.cil.oc.api.event.GeolyzerEvent.Analyze
import li.cil.oc.api.internal.Rotatable import li.cil.oc.api.internal
import li.cil.oc.api.machine.Arguments import li.cil.oc.api.machine.Arguments
import li.cil.oc.api.machine.Callback import li.cil.oc.api.machine.Callback
import li.cil.oc.api.machine.Context import li.cil.oc.api.machine.Context
import li.cil.oc.api.network.Message
import li.cil.oc.api.network.Visibility import li.cil.oc.api.network.Visibility
import li.cil.oc.api.prefab import li.cil.oc.api.prefab
import li.cil.oc.util.BlockPosition import li.cil.oc.util.BlockPosition
import li.cil.oc.util.DatabaseAccess import li.cil.oc.util.DatabaseAccess
import li.cil.oc.util.ExtendedArguments._ import li.cil.oc.util.ExtendedArguments._
import li.cil.oc.util.ExtendedWorld._ import li.cil.oc.util.ExtendedWorld._
import net.minecraft.block.Block
import net.minecraft.entity.player.EntityPlayer
import net.minecraft.item.Item import net.minecraft.item.Item
import net.minecraft.item.ItemStack import net.minecraft.item.ItemStack
import net.minecraft.nbt.NBTTagCompound
import net.minecraft.util.EnumFacing import net.minecraft.util.EnumFacing
import net.minecraftforge.common.MinecraftForge import net.minecraftforge.common.MinecraftForge
@ -51,7 +56,7 @@ class Geolyzer(val host: EnvironmentHost) extends prefab.ManagedEnvironment {
def analyze(computer: Context, args: Arguments): Array[AnyRef] = if (Settings.get.allowItemStackInspection) { def analyze(computer: Context, args: Arguments): Array[AnyRef] = if (Settings.get.allowItemStackInspection) {
val side = args.checkSide(0, EnumFacing.values: _*) val side = args.checkSide(0, EnumFacing.values: _*)
val globalSide = host match { val globalSide = host match {
case rotatable: Rotatable => rotatable.toGlobal(side) case rotatable: internal.Rotatable => rotatable.toGlobal(side)
case _ => side case _ => side
} }
val options = args.optTable(1, Map.empty[AnyRef, AnyRef]) val options = args.optTable(1, Map.empty[AnyRef, AnyRef])
@ -70,7 +75,7 @@ class Geolyzer(val host: EnvironmentHost) extends prefab.ManagedEnvironment {
def store(computer: Context, args: Arguments): Array[AnyRef] = { def store(computer: Context, args: Arguments): Array[AnyRef] = {
val side = args.checkSide(0, EnumFacing.values: _*) val side = args.checkSide(0, EnumFacing.values: _*)
val globalSide = host match { val globalSide = host match {
case rotatable: Rotatable => rotatable.toGlobal(side) case rotatable: internal.Rotatable => rotatable.toGlobal(side)
case _ => side case _ => side
} }
@ -93,4 +98,42 @@ class Geolyzer(val host: EnvironmentHost) extends prefab.ManagedEnvironment {
}) })
} }
} }
override def onMessage(message: Message): Unit = {
super.onMessage(message)
if (message.name == "tablet.use") message.source.host match {
case machine: api.machine.Machine => (machine.host, message.data) match {
case (tablet: internal.Tablet, Array(nbt: NBTTagCompound, stack: ItemStack, player: EntityPlayer, blockPos: BlockPosition, side: EnumFacing, hitX: java.lang.Float, hitY: java.lang.Float, hitZ: java.lang.Float)) =>
if (node.tryChangeBuffer(-Settings.get.geolyzerScanCost)) {
// TODO 1.5 replace with event (change event to allow arbitrary coordinates)
val world = player.getEntityWorld
val block = world.getBlock(blockPos)
Block.blockRegistry.getNameForObject(block) match {
case name: String if !Strings.isNullOrEmpty(name) => nbt.setString("name", name)
case _ =>
}
nbt.setInteger("metadata", block.getMetaFromState(world.getBlockMetadata(blockPos)))
nbt.setFloat("hardness", world.getBlockHardness(blockPos))
nbt.setInteger("harvestLevel", world.getBlockHarvestLevel(blockPos))
if (!Strings.isNullOrEmpty(world.getBlockHarvestTool(blockPos))) {
nbt.setString("harvestTool", world.getBlockHarvestTool(blockPos))
}
nbt.setInteger("color", world.getBlockMapColor(blockPos).colorValue)
// val event = new Analyze(host, Map.empty[AnyRef, AnyRef], side)
// MinecraftForge.EVENT_BUS.post(event)
// if (!event.isCanceled) {
// for ((key, value) <- event.data) value match {
// case number: java.lang.Number => nbt.setDouble(key, number.doubleValue())
// case string: String if !string.isEmpty => nbt.setString(key, string)
// case _ => // Unsupported, ignore.
// }
// }
}
case _ => // Ignore.
}
case _ => // Ignore.
}
}
} }

View File

@ -1,7 +1,9 @@
package li.cil.oc.server.component package li.cil.oc.server.component
import li.cil.oc.api
import li.cil.oc.api.Network import li.cil.oc.api.Network
import li.cil.oc.api.driver.EnvironmentHost import li.cil.oc.api.driver.EnvironmentHost
import li.cil.oc.api.internal
import li.cil.oc.api.internal.Rotatable import li.cil.oc.api.internal.Rotatable
import li.cil.oc.api.machine.Arguments import li.cil.oc.api.machine.Arguments
import li.cil.oc.api.machine.Callback import li.cil.oc.api.machine.Callback
@ -9,7 +11,11 @@ import li.cil.oc.api.machine.Context
import li.cil.oc.api.network._ import li.cil.oc.api.network._
import li.cil.oc.api.prefab import li.cil.oc.api.prefab
import li.cil.oc.common.item.data.NavigationUpgradeData import li.cil.oc.common.item.data.NavigationUpgradeData
import li.cil.oc.util.BlockPosition
import net.minecraft.entity.player.EntityPlayer
import net.minecraft.item.ItemStack
import net.minecraft.nbt.NBTTagCompound import net.minecraft.nbt.NBTTagCompound
import net.minecraft.util.EnumFacing
class UpgradeNavigation(val host: EnvironmentHost with Rotatable) extends prefab.ManagedEnvironment { class UpgradeNavigation(val host: EnvironmentHost with Rotatable) extends prefab.ManagedEnvironment {
override val node = Network.newNode(this, Visibility.Network). override val node = Network.newNode(this, Visibility.Network).
@ -43,6 +49,21 @@ class UpgradeNavigation(val host: EnvironmentHost with Rotatable) extends prefab
result(size / 2) result(size / 2)
} }
override def onMessage(message: Message): Unit = {
super.onMessage(message)
if (message.name == "tablet.use") message.source.host match {
case machine: api.machine.Machine => (machine.host, message.data) match {
case (tablet: internal.Tablet, Array(nbt: NBTTagCompound, stack: ItemStack, player: EntityPlayer, blockPos: BlockPosition, side: EnumFacing, hitX: java.lang.Float, hitY: java.lang.Float, hitZ: java.lang.Float)) =>
val info = data.mapData(host.world)
nbt.setInteger("posX", blockPos.x - info.xCenter)
nbt.setInteger("posY", blockPos.y)
nbt.setInteger("posZ", blockPos.z - info.zCenter)
case _ => // Ignore.
}
case _ => // Ignore.
}
}
// ----------------------------------------------------------------------- // // ----------------------------------------------------------------------- //
override def load(nbt: NBTTagCompound) { override def load(nbt: NBTTagCompound) {

View File

@ -7,7 +7,6 @@ import li.cil.oc.api.machine.Context
import li.cil.oc.server.component.result import li.cil.oc.server.component.result
import li.cil.oc.util.DatabaseAccess import li.cil.oc.util.DatabaseAccess
import li.cil.oc.util.ExtendedArguments._ import li.cil.oc.util.ExtendedArguments._
import net.minecraft.item.ItemStack
trait InventoryAnalytics extends InventoryAware with NetworkAware { trait InventoryAnalytics extends InventoryAware with NetworkAware {
@Callback(doc = """function([slot:number]):table -- Get a description of the stack in the specified slot or the selected slot.""") @Callback(doc = """function([slot:number]):table -- Get a description of the stack in the specified slot or the selected slot.""")
@ -21,12 +20,24 @@ trait InventoryAnalytics extends InventoryAware with NetworkAware {
def storeInternal(context: Context, args: Arguments): Array[AnyRef] = { def storeInternal(context: Context, args: Arguments): Array[AnyRef] = {
val localSlot = args.checkSlot(inventory, 0) val localSlot = args.checkSlot(inventory, 0)
val dbAddress = args.checkString(1) val dbAddress = args.checkString(1)
def store(stack: ItemStack) = DatabaseAccess.withDatabase(node, dbAddress, database => { val localStack = inventory.getStackInSlot(localSlot)
DatabaseAccess.withDatabase(node, dbAddress, database => {
val dbSlot = args.checkSlot(database.data, 2) val dbSlot = args.checkSlot(database.data, 2)
val nonEmpty = database.data.getStackInSlot(dbSlot) != null val nonEmpty = database.data.getStackInSlot(dbSlot) != null
database.data.setInventorySlotContents(dbSlot, stack.copy()) database.data.setInventorySlotContents(dbSlot, localStack.copy())
result(nonEmpty) result(nonEmpty)
}) })
store(inventory.getStackInSlot(localSlot)) }
@Callback(doc = """function(slot:number, dbAddress:string, dbSlot:number):boolean -- Compare an item in the specified slot with one in the database with the specified address.""")
def compareToDatabase(context: Context, args: Arguments): Array[AnyRef] = {
val localSlot = args.checkSlot(inventory, 0)
val dbAddress = args.checkString(1)
val localStack = inventory.getStackInSlot(localSlot)
DatabaseAccess.withDatabase(node, dbAddress, database => {
val dbSlot = args.checkSlot(database.data, 2)
val dbStack = database.data.getStackInSlot(dbSlot)
result(haveSameItemType(localStack, dbStack))
})
} }
} }

View File

@ -23,6 +23,7 @@ trait InventoryAware {
protected def stackInSlot(slot: Int) = Option(inventory.getStackInSlot(slot)) protected def stackInSlot(slot: Int) = Option(inventory.getStackInSlot(slot))
protected def haveSameItemType(stackA: ItemStack, stackB: ItemStack) = protected def haveSameItemType(stackA: ItemStack, stackB: ItemStack) =
stackA.getItem == stackB.getItem && stackA != null && stackB != null &&
stackA.getItem == stackB.getItem &&
(!stackA.getHasSubtypes || stackA.getItemDamage == stackB.getItemDamage) (!stackA.getHasSubtypes || stackA.getItemDamage == stackB.getItemDamage)
} }

View File

@ -238,6 +238,7 @@ class Machine(val host: MachineHost) extends prefab.ManagedEnvironment with mach
case arg: java.lang.String => arg case arg: java.lang.String => arg
case arg: Array[Byte] => arg case arg: Array[Byte] => arg
case arg: Map[_, _] if arg.isEmpty || arg.head._1.isInstanceOf[String] && arg.head._2.isInstanceOf[String] => arg case arg: Map[_, _] if arg.isEmpty || arg.head._1.isInstanceOf[String] && arg.head._2.isInstanceOf[String] => arg
case arg: NBTTagCompound => arg
case arg => case arg =>
OpenComputers.log.warn("Trying to push signal with an unsupported argument of type " + arg.getClass.getName) OpenComputers.log.warn("Trying to push signal with an unsupported argument of type " + arg.getClass.getName)
null null
@ -247,7 +248,7 @@ class Machine(val host: MachineHost) extends prefab.ManagedEnvironment with mach
} }
}) })
override def popSignal(): Machine.Signal = signals.synchronized(if (signals.isEmpty) null else signals.dequeue()) override def popSignal(): Machine.Signal = signals.synchronized(if (signals.isEmpty) null else signals.dequeue().convert())
override def methods(value: scala.AnyRef) = Callbacks(value).map(entry => { override def methods(value: scala.AnyRef) = Callbacks(value).map(entry => {
val (name, callback) = entry val (name, callback) = entry
@ -628,6 +629,7 @@ class Machine(val host: MachineHost) extends prefab.ManagedEnvironment with mach
data += tag.getStringTagAt(i) -> tag.getStringTagAt(i + 1) data += tag.getStringTagAt(i) -> tag.getStringTagAt(i + 1)
} }
data data
case tag: NBTTagCompound => tag
case _ => null case _ => null
}.toArray[AnyRef]) }.toArray[AnyRef])
}) })
@ -705,6 +707,7 @@ class Machine(val host: MachineHost) extends prefab.ManagedEnvironment with mach
list.append(value.toString) list.append(value.toString)
} }
args.setTag("arg" + i, list) args.setTag("arg" + i, list)
case (arg: NBTTagCompound, i) => args.setTag("arg" + i, arg)
case (_, i) => args.setByte("arg" + i, -1) case (_, i) => args.setByte("arg" + i, -1)
} }
}) })
@ -936,7 +939,9 @@ object Machine extends MachineAPI {
} }
/** Signals are messages sent to the Lua state from Java asynchronously. */ /** Signals are messages sent to the Lua state from Java asynchronously. */
private[machine] class Signal(val name: String, val args: Array[AnyRef]) extends machine.Signal private[machine] class Signal(val name: String, val args: Array[AnyRef]) extends machine.Signal {
def convert() = new Signal(name, Registry.convert(args))
}
private val threadPool = ThreadPoolFactory.create("Computer", Settings.get.threads) private val threadPool = ThreadPoolFactory.create("Computer", Settings.get.threads)
} }