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>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>NBTTagCompounds.</li>
* </ul>
* 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

View File

@ -110,6 +110,15 @@ object PacketSender {
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() {
val pb = new SimplePacketBuilder(PacketType.MultiPartPlace)
pb.sendToServer()

View File

@ -284,7 +284,7 @@ object RobotRenderer extends TileEntitySpecialRenderer {
val timeJitter = robot.hashCode ^ 0xFF
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
GL11.glTranslatef(0, hover, 0)

View File

@ -19,6 +19,7 @@ import net.minecraft.item.ItemStack
import net.minecraft.server.MinecraftServer
import net.minecraft.tileentity.TileEntity
import net.minecraftforge.common.util.FakePlayer
import net.minecraftforge.event.world.BlockEvent
import net.minecraftforge.event.world.WorldEvent
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
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 eeprom = api.Items.get("eeprom")
lazy val mcu = api.Items.get("microcontroller")

View File

@ -51,6 +51,7 @@ object PacketType extends Enumeration {
// Client -> Server
ComputerPower,
CopyToAnalyzer,
DronePower,
KeyDown,
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) =
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)
}
}

View File

@ -230,6 +230,11 @@ class RobotProxy extends RedstoneAware with traits.StateAware {
world.getTileEntity(pos) match {
case proxy: tileentity.RobotProxy =>
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 (robot.player == player) return false
robot.node.remove()

View File

@ -4,6 +4,7 @@ import java.util
import li.cil.oc.OpenComputers
import li.cil.oc.Settings
import li.cil.oc.api
import li.cil.oc.common.GuiType
import li.cil.oc.common.tileentity
import li.cil.oc.integration.util.Wrench
@ -13,6 +14,7 @@ import li.cil.oc.util.Rarity
import li.cil.oc.util.Tooltip
import net.minecraft.block.properties.IProperty
import net.minecraft.block.state.IBlockState
import net.minecraft.client.Minecraft
import net.minecraft.entity.Entity
import net.minecraft.entity.EntityLivingBase
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,
side: EnumFacing, hitX: Float, hitY: Float, hitZ: Float, force: Boolean) = {
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 {
case screen: tileentity.Screen if screen.hasKeyboard && (force || player.isSneaking == screen.invertTouchMode) =>
// 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
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
}
}

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.Node
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.Delegator
import li.cil.oc.common.tileentity
@ -23,9 +24,9 @@ class Terminal(val rack: tileentity.ServerRack, val number: Int) {
val buffer = {
val screenItem = api.Items.get("screen1").createItemStack(1)
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.setMaximumColorDepth(Settings.screenDepthsByTier(1))
buffer.setMaximumColorDepth(Settings.screenDepthsByTier(Tier.Three))
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) =
proxy.mouseScroll(x, y, delta, player)
def copyToAnalyzer(line: Int, player: EntityPlayer): Unit = {
proxy.copyToAnalyzer(line, player)
}
// ----------------------------------------------------------------------- //
override def onConnect(node: Node) {
@ -588,6 +592,8 @@ object TextBuffer {
def mouseUp(x: Double, y: Double, button: 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 {
@ -672,6 +678,10 @@ object TextBuffer {
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 def debug(message: String) {
@ -775,6 +785,27 @@ object TextBuffer {
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) = {
val args = mutable.ArrayBuffer.empty[AnyRef]

View File

@ -1,9 +1,11 @@
package li.cil.oc.common.item
import li.cil.oc.Localization
import li.cil.oc.Settings
import li.cil.oc.api
import li.cil.oc.api.network.Analyzable
import li.cil.oc.api.network._
import li.cil.oc.common.tileentity
import li.cil.oc.server.PacketSender
import li.cil.oc.util.BlockPosition
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.item.ItemStack
import net.minecraft.util.EnumFacing
import net.minecraft.world.World
import net.minecraftforge.event.entity.player.EntityInteractEvent
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
@ -79,7 +82,31 @@ object Analyzer {
}
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) = {
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.integration.opencomputers.DriverScreen
import li.cil.oc.server.component
import li.cil.oc.util.BlockPosition
import li.cil.oc.util.ExtendedNBT._
import li.cil.oc.util.Rarity
import li.cil.oc.util.RotationHelper
@ -93,6 +94,24 @@ class Tablet(val parent: Delegator) extends Delegate {
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) = {
if (!player.isSneaking) {
if (world.isRemote) {

View File

@ -35,7 +35,7 @@ class Case(var tier: Int) extends traits.PowerAcceptor with traits.Computer with
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 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.
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 isUseableByPlayer(player: EntityPlayer) =
super.isUseableByPlayer(player) && (!isCreativeCase || player.capabilities.isCreativeMode)
super.isUseableByPlayer(player) && (!isCreative || player.capabilities.isCreativeMode)
override def isItemValidForSlot(slot: Int, stack: ItemStack) =
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
def isCreative = tier == Tier.Four
// Wrapper for the part of the inventory that is mutable.
val dynamicInventory = new IInventory {
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))
}
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 {
case (0, _) => true // Allow anything in the tool slot.
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.api.network.Analyzable
import li.cil.oc.api.network._
import li.cil.oc.common.component.TextBuffer
import li.cil.oc.util.BlockPosition
import li.cil.oc.util.Color
import li.cil.oc.util.ExtendedWorld._
@ -95,7 +96,7 @@ class Screen(var tier: Int) extends traits.TextBuffer with SidedEnvironment with
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.
def dot(f: EnumFacing) = f.getFrontOffsetX * hitX + f.getFrontOffsetY * hitY + f.getFrontOffsetZ * hitZ
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.
val border = 2.25 / 16.0
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 (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 rh = bph.toDouble / bpw.toDouble
val bry = (ry - (1 - rh) * 0.5) / rh
if (bry <= 0 || bry >= 1) {
return true
}
(rx, bry)
}
else if (bph > bpw) {
val rw = bpw.toDouble / bph.toDouble
val brx = (rx - (1 - rw) * 0.5) / rw
if (brx <= 0 || brx >= 1) {
return true
}
(brx, ry)
}
else {
(rx, ry)
}
// Convert to absolute coordinates and send the packet to the server.
origin.buffer.mouseDown(brx * bw, bry * bh, 0, null)
val inBounds = bry >= 0 && bry <= 1 && brx >= 0 || brx <= 1
(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) {
@ -238,7 +255,7 @@ class Screen(var tier: Int) extends traits.TextBuffer with SidedEnvironment with
hitXInner && !hitYInner && hitZInner ||
!hitXInner && hitYInner && hitZInner) {
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 _ =>
}
}

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(ConverterFluidTankInfo)
Driver.add(ConverterItemStack)
Driver.add(ConverterNBT)
}
}

View File

@ -36,6 +36,7 @@ object PacketHandler extends CommonPacketHandler {
override def dispatch(p: PacketParser) {
p.packetType match {
case PacketType.ComputerPower => onComputerPower(p)
case PacketType.CopyToAnalyzer => onCopyToAnalyzer(p)
case PacketType.DronePower => onDronePower(p)
case PacketType.KeyDown => onKeyDown(p)
case PacketType.KeyUp => onKeyUp(p)
@ -73,6 +74,13 @@ object PacketHandler extends CommonPacketHandler {
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) =
p.readEntity[Drone]() 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.minecraftforge.common.DimensionManager
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 {
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.""")
def removeItem(context: Context, args: Arguments): Array[AnyRef] = {
checkEnabled()
val position = BlockPosition(args.checkDouble(0), args.checkDouble(1), args.checkDouble(2), world)
InventoryUtils.inventoryAt(position) match {
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) {

View File

@ -1,22 +1,27 @@
package li.cil.oc.server.component
import com.google.common.base.Strings
import li.cil.oc.Settings
import li.cil.oc.api
import li.cil.oc.api.driver.EnvironmentHost
import li.cil.oc.api.event.GeolyzerEvent
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.Callback
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.prefab
import li.cil.oc.util.BlockPosition
import li.cil.oc.util.DatabaseAccess
import li.cil.oc.util.ExtendedArguments._
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.ItemStack
import net.minecraft.nbt.NBTTagCompound
import net.minecraft.util.EnumFacing
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) {
val side = args.checkSide(0, EnumFacing.values: _*)
val globalSide = host match {
case rotatable: Rotatable => rotatable.toGlobal(side)
case rotatable: internal.Rotatable => rotatable.toGlobal(side)
case _ => side
}
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] = {
val side = args.checkSide(0, EnumFacing.values: _*)
val globalSide = host match {
case rotatable: Rotatable => rotatable.toGlobal(side)
case rotatable: internal.Rotatable => rotatable.toGlobal(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
import li.cil.oc.api
import li.cil.oc.api.Network
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.machine.Arguments
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.prefab
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.util.EnumFacing
class UpgradeNavigation(val host: EnvironmentHost with Rotatable) extends prefab.ManagedEnvironment {
override val node = Network.newNode(this, Visibility.Network).
@ -43,6 +49,21 @@ class UpgradeNavigation(val host: EnvironmentHost with Rotatable) extends prefab
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) {

View File

@ -7,7 +7,6 @@ import li.cil.oc.api.machine.Context
import li.cil.oc.server.component.result
import li.cil.oc.util.DatabaseAccess
import li.cil.oc.util.ExtendedArguments._
import net.minecraft.item.ItemStack
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.""")
@ -21,12 +20,24 @@ trait InventoryAnalytics extends InventoryAware with NetworkAware {
def storeInternal(context: Context, args: Arguments): Array[AnyRef] = {
val localSlot = args.checkSlot(inventory, 0)
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 nonEmpty = database.data.getStackInSlot(dbSlot) != null
database.data.setInventorySlotContents(dbSlot, stack.copy())
database.data.setInventorySlotContents(dbSlot, localStack.copy())
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 haveSameItemType(stackA: ItemStack, stackB: ItemStack) =
stackA.getItem == stackB.getItem &&
stackA != null && stackB != null &&
stackA.getItem == stackB.getItem &&
(!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: Array[Byte] => arg
case arg: Map[_, _] if arg.isEmpty || arg.head._1.isInstanceOf[String] && arg.head._2.isInstanceOf[String] => arg
case arg: NBTTagCompound => arg
case arg =>
OpenComputers.log.warn("Trying to push signal with an unsupported argument of type " + arg.getClass.getName)
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 => {
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
case tag: NBTTagCompound => tag
case _ => null
}.toArray[AnyRef])
})
@ -705,6 +707,7 @@ class Machine(val host: MachineHost) extends prefab.ManagedEnvironment with mach
list.append(value.toString)
}
args.setTag("arg" + i, list)
case (arg: NBTTagCompound, i) => args.setTag("arg" + i, arg)
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. */
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)
}