diff --git a/src/main/resources/application.conf b/src/main/resources/application.conf index 67c82af2e..85a11cbd9 100644 --- a/src/main/resources/application.conf +++ b/src/main/resources/application.conf @@ -465,8 +465,8 @@ opencomputers { # screens. This also controls how frequent distributors revalidate their # global state and secondary distributors, as well as how often the power # converter queries sources for energy (for now: only BuildCraft). If set - # to 1, this would query every tick. The default queries every 20 ticks, - # or in other words once per second. + # to 1, this would query every tick. The default queries every 10 ticks, + # or in other words twice per second. # Higher values mean more responsive power consumption, but slightly more # work per tick (shouldn't be that noticeable, though). Note that this # has no influence on the actual amount of energy required by computers diff --git a/src/main/scala/li/cil/oc/common/EventHandler.scala b/src/main/scala/li/cil/oc/common/EventHandler.scala index 65b51bcb2..2970924d8 100644 --- a/src/main/scala/li/cil/oc/common/EventHandler.scala +++ b/src/main/scala/li/cil/oc/common/EventHandler.scala @@ -118,6 +118,7 @@ object EventHandler { @SubscribeEvent def playerLoggedIn(e: PlayerLoggedInEvent) { if (SideTracker.isServer) e.player match { + case _: FakePlayer => // Nope case player: EntityPlayerMP => if (!LuaStateFactory.isAvailable) { player.addChatMessage(Localization.Chat.WarningLuaFallback) diff --git a/src/main/scala/li/cil/oc/common/container/Player.scala b/src/main/scala/li/cil/oc/common/container/Player.scala index 23067a191..e392003dc 100644 --- a/src/main/scala/li/cil/oc/common/container/Player.scala +++ b/src/main/scala/li/cil/oc/common/container/Player.scala @@ -15,6 +15,7 @@ import net.minecraft.inventory.Slot import net.minecraft.item.ItemStack import net.minecraft.nbt.NBTBase import net.minecraft.nbt.NBTTagCompound +import net.minecraftforge.common.util.FakePlayer import scala.collection.convert.WrapAsScala._ @@ -155,6 +156,7 @@ abstract class Player(val playerInventory: InventoryPlayer, val otherInventory: val nbt = new NBTTagCompound() detectCustomDataChanges(nbt) for (entry <- crafters) entry match { + case _: FakePlayer => // Nope case player: EntityPlayerMP => ServerPacketSender.sendContainerUpdate(this, nbt, player) case _ => } diff --git a/src/main/scala/li/cil/oc/common/entity/Drone.scala b/src/main/scala/li/cil/oc/common/entity/Drone.scala index 659dd09df..b14c09106 100644 --- a/src/main/scala/li/cil/oc/common/entity/Drone.scala +++ b/src/main/scala/li/cil/oc/common/entity/Drone.scala @@ -465,7 +465,13 @@ class Drone(val world: World) extends Entity(world) with MachineHost with intern override def interactFirst(player: EntityPlayer) = { if (player.isSneaking) { - kill() + if (api.Items.get(player.getCurrentEquippedItem) == api.Items.get(Constants.ItemName.Wrench)) { + kill() + } + else if (!world.isRemote && !machine.isRunning) { + preparePowerUp() + start() + } } else if (!world.isRemote) { player.openGui(OpenComputers, GuiType.Drone.id, world, getEntityId, 0, 0) diff --git a/src/main/scala/li/cil/oc/common/item/Analyzer.scala b/src/main/scala/li/cil/oc/common/item/Analyzer.scala index bc15ef557..228366e75 100644 --- a/src/main/scala/li/cil/oc/common/item/Analyzer.scala +++ b/src/main/scala/li/cil/oc/common/item/Analyzer.scala @@ -16,6 +16,7 @@ import net.minecraft.entity.player.EntityPlayerMP import net.minecraft.item.ItemStack import net.minecraft.util.EnumFacing import net.minecraft.world.World +import net.minecraftforge.common.util.FakePlayer import net.minecraftforge.event.entity.player.EntityInteractEvent import net.minecraftforge.fml.common.eventhandler.SubscribeEvent @@ -59,6 +60,7 @@ object Analyzer { private def analyzeNodes(nodes: Array[Node], player: EntityPlayer) = if (nodes != null) for (node <- nodes if node != null) { player match { + case _: FakePlayer => // Nope case playerMP: EntityPlayerMP => if (node != null) node.host match { case machine: Machine => diff --git a/src/main/scala/li/cil/oc/common/item/Debugger.scala b/src/main/scala/li/cil/oc/common/item/Debugger.scala index 7f96c6eb4..7b20cdba6 100644 --- a/src/main/scala/li/cil/oc/common/item/Debugger.scala +++ b/src/main/scala/li/cil/oc/common/item/Debugger.scala @@ -9,11 +9,13 @@ import net.minecraft.entity.player.EntityPlayer import net.minecraft.entity.player.EntityPlayerMP import net.minecraft.item.ItemStack import net.minecraft.util.EnumFacing +import net.minecraftforge.common.util.FakePlayer class Debugger(val parent: Delegator) extends traits.Delegate { override def onItemUse(stack: ItemStack, player: EntityPlayer, position: BlockPosition, side: EnumFacing, hitX: Float, hitY: Float, hitZ: Float) = { val world = position.world.get player match { + case _: FakePlayer => false // Nope case realPlayer: EntityPlayerMP => world.getTileEntity(position) match { case host: SidedEnvironment => diff --git a/src/main/scala/li/cil/oc/common/nanomachines/provider/DisintegrationProvider.scala b/src/main/scala/li/cil/oc/common/nanomachines/provider/DisintegrationProvider.scala index d02111685..52e254ef2 100644 --- a/src/main/scala/li/cil/oc/common/nanomachines/provider/DisintegrationProvider.scala +++ b/src/main/scala/li/cil/oc/common/nanomachines/provider/DisintegrationProvider.scala @@ -1,6 +1,5 @@ package li.cil.oc.common.nanomachines.provider -import li.cil.oc.Settings import li.cil.oc.Settings import li.cil.oc.api import li.cil.oc.api.nanomachines.DisableReason @@ -14,6 +13,7 @@ import net.minecraft.entity.player.EntityPlayerMP import net.minecraft.item.ItemStack import net.minecraft.nbt.NBTTagCompound import net.minecraft.world.World +import net.minecraftforge.common.util.FakePlayer import net.minecraftforge.event.ForgeEventFactory import net.minecraftforge.event.entity.player.PlayerInteractEvent.Action import net.minecraftforge.fml.common.eventhandler.Event @@ -42,6 +42,7 @@ object DisintegrationProvider extends ScalaProvider("c4e7e3c2-8069-4fbb-b08e-74b override def update(): Unit = { val world = player.getEntityWorld if (!world.isRemote) player match { + case _: FakePlayer => // Nope case playerMP: EntityPlayerMP => val now = world.getTotalWorldTime diff --git a/src/main/scala/li/cil/oc/common/tileentity/Charger.scala b/src/main/scala/li/cil/oc/common/tileentity/Charger.scala index 9dcdd85dc..2eba3cf7e 100644 --- a/src/main/scala/li/cil/oc/common/tileentity/Charger.scala +++ b/src/main/scala/li/cil/oc/common/tileentity/Charger.scala @@ -205,7 +205,7 @@ class Charger extends traits.Environment with traits.PowerAcceptor with traits.R } val players = world.getEntitiesWithinAABB(classOf[EntityPlayer], bounds).collect { - case player: EntityPlayer => new PlayerChargeable(player) + case player: EntityPlayer if api.Nanomachines.hasController(player) => new PlayerChargeable(player) } // Only update list when we have to, keeps pointless block updates to a minimum. diff --git a/src/main/scala/li/cil/oc/common/tileentity/Hologram.scala b/src/main/scala/li/cil/oc/common/tileentity/Hologram.scala index 10666c101..36028eb0b 100644 --- a/src/main/scala/li/cil/oc/common/tileentity/Hologram.scala +++ b/src/main/scala/li/cil/oc/common/tileentity/Hologram.scala @@ -319,7 +319,7 @@ class Hologram(var tier: Int) extends traits.Environment with SidedEnvironment w result(true) } - else result(null, "not supported") + else result(Unit, "not supported") } @Callback(doc = """function(speed:number, x:number, y:number, z:number):boolean -- Set the rotation speed of the displayed hologram.""") @@ -338,7 +338,7 @@ class Hologram(var tier: Int) extends traits.Environment with SidedEnvironment w result(true) } - else result(null, "not supported") + else result(Unit, "not supported") } private def checkCoordinates(args: Arguments, idxX: Int = 0, idxY: Int = 1, idxZ: Int = 2) = { diff --git a/src/main/scala/li/cil/oc/common/tileentity/Printer.scala b/src/main/scala/li/cil/oc/common/tileentity/Printer.scala index 34918b455..d177e02f8 100644 --- a/src/main/scala/li/cil/oc/common/tileentity/Printer.scala +++ b/src/main/scala/li/cil/oc/common/tileentity/Printer.scala @@ -152,7 +152,7 @@ class Printer extends traits.Environment with traits.Inventory with traits.Rotat @Callback(doc = """function(minX:number, minY:number, minZ:number, maxX:number, maxY:number, maxZ:number, texture:string[, state:boolean=false][,tint:number]) -- Adds a shape to the printers configuration, optionally specifying whether it is for the off or on state.""") def addShape(context: Context, args: Arguments): Array[Object] = { if (data.stateOff.size > Settings.get.maxPrintComplexity || data.stateOn.size > Settings.get.maxPrintComplexity) { - return result(null, "model too complex") + return result(Unit, "model too complex") } val minX = (args.checkInteger(0) max 0 min 16) / 16f val minY = (args.checkInteger(1) max 0 min 16) / 16f @@ -193,7 +193,7 @@ class Printer extends traits.Environment with traits.Inventory with traits.Rotat @Callback(doc = """function([count:number]):boolean -- Commit and begin printing the current configuration.""") def commit(context: Context, args: Arguments): Array[Object] = { if (!canPrint) { - return result(null, "model invalid") + return result(Unit, "model invalid") } limit = (args.optDouble(0, 1) max 0 min Integer.MAX_VALUE).toInt isActive = limit > 0 diff --git a/src/main/scala/li/cil/oc/common/tileentity/Transposer.scala b/src/main/scala/li/cil/oc/common/tileentity/Transposer.scala index b3e43b9f4..4860a866f 100644 --- a/src/main/scala/li/cil/oc/common/tileentity/Transposer.scala +++ b/src/main/scala/li/cil/oc/common/tileentity/Transposer.scala @@ -4,7 +4,7 @@ import li.cil.oc.server.component import net.minecraft.nbt.NBTTagCompound class Transposer extends traits.Environment { - val transposer = new component.Transposer(this) + val transposer = new component.Transposer.Block(this) def node = transposer.node diff --git a/src/main/scala/li/cil/oc/integration/appeng/PartEnvironmentBase.scala b/src/main/scala/li/cil/oc/integration/appeng/PartEnvironmentBase.scala index 1dbd70cef..fd1ccde4c 100644 --- a/src/main/scala/li/cil/oc/integration/appeng/PartEnvironmentBase.scala +++ b/src/main/scala/li/cil/oc/integration/appeng/PartEnvironmentBase.scala @@ -1,7 +1,5 @@ package li.cil.oc.integration.appeng -import appeng.api.implementations.tiles.ISegmentedInventory -import appeng.api.parts.IPartHost import li.cil.oc.api.internal.Database import li.cil.oc.api.machine.Arguments import li.cil.oc.api.machine.Context @@ -9,7 +7,6 @@ import li.cil.oc.api.network.Component import li.cil.oc.api.network.ManagedEnvironment import li.cil.oc.util.ExtendedArguments._ import li.cil.oc.util.ResultWrapper.result -import net.minecraftforge.common.util.ForgeDirection import scala.reflect.ClassTag @@ -25,7 +22,7 @@ trait PartEnvironmentBase extends ManagedEnvironment { val slot = args.optSlot(config, 1, 0) val stack = config.getStackInSlot(slot) result(stack) - case _ => result(null, "no matching part") + case _ => result(Unit, "no matching part") } } diff --git a/src/main/scala/li/cil/oc/integration/dsu/DriverDeepStorageUnit.scala b/src/main/scala/li/cil/oc/integration/dsu/DriverDeepStorageUnit.scala index cbc5510f9..ba0cbd53d 100644 --- a/src/main/scala/li/cil/oc/integration/dsu/DriverDeepStorageUnit.scala +++ b/src/main/scala/li/cil/oc/integration/dsu/DriverDeepStorageUnit.scala @@ -11,7 +11,6 @@ import li.cil.oc.integration.ManagedTileEntityEnvironment import li.cil.oc.util.ResultWrapper._ import net.minecraft.item.ItemStack import net.minecraft.world.World -import powercrystals.minefactoryreloaded.api.IDeepStorageUnit object DriverDeepStorageUnit extends DriverTileEntity with EnvironmentAware { override def getTileEntityClass: Class[_] = classOf[IDeepStorageUnit] @@ -31,7 +30,7 @@ object DriverDeepStorageUnit extends DriverTileEntity with EnvironmentAware { @Callback(doc = "function():int -- Get the maximum number of stored items.") def getStoredItemType(context: Context, args: Arguments): Array[AnyRef] = { if (Settings.get.allowItemStackInspection) result(tileEntity.getStoredItemType) - else result(null, "not enabled in config") + else result(Unit, "not enabled in config") } } diff --git a/src/main/scala/li/cil/oc/integration/opencomputers/DriverTransposer.scala b/src/main/scala/li/cil/oc/integration/opencomputers/DriverTransposer.scala new file mode 100644 index 000000000..bce4d0253 --- /dev/null +++ b/src/main/scala/li/cil/oc/integration/opencomputers/DriverTransposer.scala @@ -0,0 +1,21 @@ +package li.cil.oc.integration.opencomputers + +import li.cil.oc.Constants +import li.cil.oc.api +import li.cil.oc.api.driver.EnvironmentAware +import li.cil.oc.api.driver.EnvironmentHost +import li.cil.oc.api.driver.item.HostAware +import li.cil.oc.common.Slot +import li.cil.oc.server.component +import net.minecraft.item.ItemStack + +object DriverTransposer extends Item with HostAware with EnvironmentAware { + override def worksWith(stack: ItemStack) = isOneOf(stack, + api.Items.get(Constants.BlockName.Transposer)) + + override def createEnvironment(stack: ItemStack, host: EnvironmentHost) = new component.Transposer.Upgrade(host) + + override def slot(stack: ItemStack) = Slot.Upgrade + + override def providedEnvironment(stack: ItemStack) = classOf[component.Transposer.Upgrade] +} diff --git a/src/main/scala/li/cil/oc/integration/opencomputers/ModOpenComputers.scala b/src/main/scala/li/cil/oc/integration/opencomputers/ModOpenComputers.scala index 9c46309b0..27b43b4f2 100644 --- a/src/main/scala/li/cil/oc/integration/opencomputers/ModOpenComputers.scala +++ b/src/main/scala/li/cil/oc/integration/opencomputers/ModOpenComputers.scala @@ -105,7 +105,6 @@ object ModOpenComputers extends ModProxy { api.Driver.add(DriverDebugCard) api.Driver.add(DriverEEPROM) api.Driver.add(DriverFileSystem) - api.Driver.add(DriverGeolyzer) api.Driver.add(DriverGraphicsCard) api.Driver.add(DriverInternetCard) api.Driver.add(DriverLinkedCard) @@ -114,7 +113,6 @@ object ModOpenComputers extends ModProxy { api.Driver.add(DriverNetworkCard) api.Driver.add(DriverKeyboard) api.Driver.add(DriverRedstoneCard) - api.Driver.add(DriverScreen) api.Driver.add(DriverTablet) api.Driver.add(DriverWirelessNetworkCard) @@ -122,6 +120,10 @@ object ModOpenComputers extends ModProxy { api.Driver.add(DriverContainerFloppy) api.Driver.add(DriverContainerUpgrade) + api.Driver.add(DriverGeolyzer) + api.Driver.add(DriverScreen) + api.Driver.add(DriverTransposer) + api.Driver.add(DriverUpgradeAngel) api.Driver.add(DriverUpgradeBattery) api.Driver.add(DriverUpgradeChunkloader) @@ -145,6 +147,7 @@ object ModOpenComputers extends ModProxy { Constants.BlockName.Geolyzer, Constants.BlockName.Keyboard, Constants.BlockName.ScreenTier1, + Constants.BlockName.Transposer, Constants.ItemName.AngelUpgrade, Constants.ItemName.BatteryUpgradeTier1, Constants.ItemName.BatteryUpgradeTier2, @@ -163,27 +166,28 @@ object ModOpenComputers extends ModProxy { Constants.ItemName.TractorBeamUpgrade, Constants.ItemName.LeashUpgrade) blacklistHost(classOf[internal.Drone], + Constants.BlockName.Keyboard, + Constants.BlockName.ScreenTier1, + Constants.BlockName.Transposer, Constants.ItemName.APUTier1, Constants.ItemName.APUTier2, Constants.ItemName.GraphicsCardTier1, Constants.ItemName.GraphicsCardTier2, Constants.ItemName.GraphicsCardTier3, - Constants.BlockName.Keyboard, Constants.ItemName.NetworkCard, Constants.ItemName.RedstoneCardTier1, - Constants.BlockName.ScreenTier1, Constants.ItemName.AngelUpgrade, Constants.ItemName.CraftingUpgrade, Constants.ItemName.HoverUpgradeTier1, Constants.ItemName.HoverUpgradeTier2) blacklistHost(classOf[internal.Microcontroller], + Constants.BlockName.Keyboard, + Constants.BlockName.ScreenTier1, Constants.ItemName.APUTier1, Constants.ItemName.APUTier2, Constants.ItemName.GraphicsCardTier1, Constants.ItemName.GraphicsCardTier2, Constants.ItemName.GraphicsCardTier3, - Constants.BlockName.Keyboard, - Constants.BlockName.ScreenTier1, Constants.ItemName.AngelUpgrade, Constants.ItemName.ChunkloaderUpgrade, Constants.ItemName.CraftingUpgrade, @@ -202,11 +206,13 @@ object ModOpenComputers extends ModProxy { Constants.ItemName.TractorBeamUpgrade, Constants.ItemName.LeashUpgrade) blacklistHost(classOf[internal.Robot], + Constants.BlockName.Transposer, Constants.ItemName.LeashUpgrade) blacklistHost(classOf[internal.Tablet], + Constants.BlockName.ScreenTier1, + Constants.BlockName.Transposer, Constants.ItemName.NetworkCard, Constants.ItemName.RedstoneCardTier1, - Constants.BlockName.ScreenTier1, Constants.ItemName.AngelUpgrade, Constants.ItemName.ChunkloaderUpgrade, Constants.ItemName.CraftingUpgrade, diff --git a/src/main/scala/li/cil/oc/server/component/Agent.scala b/src/main/scala/li/cil/oc/server/component/Agent.scala index 5c062486a..0a7bd6f8e 100644 --- a/src/main/scala/li/cil/oc/server/component/Agent.scala +++ b/src/main/scala/li/cil/oc/server/component/Agent.scala @@ -6,6 +6,7 @@ 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.common.entity import li.cil.oc.server.agent.ActivationType import li.cil.oc.server.agent.Player import li.cil.oc.util.BlockPosition @@ -303,7 +304,7 @@ trait Agent extends traits.WorldControl with traits.InventoryControl with traits player.side.getFrontOffsetZ * range) val hit = world.rayTraceBlocks(origin, target) player.closestEntity[Entity]() match { - case Some(entity@(_: EntityLivingBase | _: EntityMinecart)) if hit == null || new Vec3(player.posX, player.posY, player.posZ).distanceTo(hit.hitVec) > player.getDistanceToEntity(entity) => new MovingObjectPosition(entity) + case Some(entity@(_: EntityLivingBase | _: EntityMinecart | _: entity.Drone)) if hit == null || new Vec3(player.posX, player.posY, player.posZ).distanceTo(hit.hitVec) > player.getDistanceToEntity(entity) => new MovingObjectPosition(entity) case _ => hit } } diff --git a/src/main/scala/li/cil/oc/server/component/DebugCard.scala b/src/main/scala/li/cil/oc/server/component/DebugCard.scala index 31562f7bd..be87b9741 100644 --- a/src/main/scala/li/cil/oc/server/component/DebugCard.scala +++ b/src/main/scala/li/cil/oc/server/component/DebugCard.scala @@ -440,9 +440,9 @@ object DebugCard { tileEntity.markDirty() world.markBlockForUpdate(blockPos) result(true) - case nbt => result(null, s"nbt tag compound expected, got '${NBTBase.NBT_TYPES(nbt.getId)}'") + case nbt => result(Unit, s"nbt tag compound expected, got '${NBTBase.NBT_TYPES(nbt.getId)}'") } - case _ => result(null, "no tile entity") + case _ => result(Unit, "no tile entity") } } @@ -524,7 +524,7 @@ object DebugCard { val removed = inventory.decrStackSize(slot, count) if (removed == null) result(0) else result(removed.stackSize) - case _ => result(null, "no inventory") + case _ => result(Unit, "no inventory") } } @@ -540,7 +540,7 @@ object DebugCard { 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") + case _ => result(Unit, "no tank") } } @@ -552,7 +552,7 @@ object DebugCard { 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") + case _ => result(Unit, "no tank") } } diff --git a/src/main/scala/li/cil/oc/server/component/InternetCard.scala b/src/main/scala/li/cil/oc/server/component/InternetCard.scala index eae05568e..bd6fe8abe 100644 --- a/src/main/scala/li/cil/oc/server/component/InternetCard.scala +++ b/src/main/scala/li/cil/oc/server/component/InternetCard.scala @@ -1,15 +1,27 @@ package li.cil.oc.server.component -import java.io.{BufferedWriter, FileNotFoundException, IOException, InputStream, OutputStreamWriter} +import java.io.BufferedWriter +import java.io.FileNotFoundException +import java.io.IOException +import java.io.InputStream +import java.io.OutputStreamWriter import java.net._ import java.nio.ByteBuffer import java.nio.channels.SocketChannel -import java.util.concurrent.{Callable, ConcurrentLinkedQueue, ExecutionException, Future} +import java.util.concurrent.Callable +import java.util.concurrent.ConcurrentLinkedQueue +import java.util.concurrent.ExecutionException +import java.util.concurrent.Future -import li.cil.oc.{OpenComputers, Settings, api} -import li.cil.oc.api.machine.{Arguments, Callback, Context} +import li.cil.oc.OpenComputers +import li.cil.oc.Settings +import li.cil.oc.api +import li.cil.oc.api.Network +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._ -import li.cil.oc.api.{Network, prefab} +import li.cil.oc.api.prefab import li.cil.oc.api.prefab.AbstractValue import li.cil.oc.util.ExtendedNBT._ import li.cil.oc.util.ThreadPoolFactory @@ -190,7 +202,7 @@ object InternetCard { if (checkConnected()) { val buffer = ByteBuffer.allocate(n) val read = channel.read(buffer) - if (read == -1) result(null) + if (read == -1) result(Unit) else result(buffer.array.view(0, read).toArray) } else result(Array.empty[Byte]) @@ -297,7 +309,7 @@ object InternetCard { def response(context: Context, args: Arguments): Array[AnyRef] = this.synchronized { response match { case Some((code, message, headers)) => result(code, message, headers) - case _ => result(null) + case _ => result(Unit) } } @@ -305,7 +317,7 @@ object InternetCard { def read(context: Context, args: Arguments): Array[AnyRef] = this.synchronized { val n = math.min(Settings.get.maxReadBuffer, math.max(0, args.optInteger(1, Int.MaxValue))) if (checkResponse()) { - if (eof && queue.isEmpty) result(null) + if (eof && queue.isEmpty) result(Unit) else { val buffer = ByteBuffer.allocate(n) var read = 0 diff --git a/src/main/scala/li/cil/oc/server/component/Transposer.scala b/src/main/scala/li/cil/oc/server/component/Transposer.scala index c51faeaf2..3d1f4c162 100644 --- a/src/main/scala/li/cil/oc/server/component/Transposer.scala +++ b/src/main/scala/li/cil/oc/server/component/Transposer.scala @@ -2,68 +2,49 @@ package li.cil.oc.server.component import li.cil.oc.Settings import li.cil.oc.api +import li.cil.oc.api.driver.EnvironmentHost 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.Visibility import li.cil.oc.api.prefab import li.cil.oc.common.tileentity import li.cil.oc.server.{PacketSender => ServerPacketSender} import li.cil.oc.util.BlockPosition import li.cil.oc.util.ExtendedArguments._ -import li.cil.oc.util.FluidUtils -import li.cil.oc.util.InventoryUtils import net.minecraft.util.EnumFacing import scala.language.existentials -class Transposer(val host: tileentity.Transposer) extends prefab.ManagedEnvironment with traits.WorldInventoryAnalytics with traits.WorldTankAnalytics { - override val node = api.Network.newNode(this, Visibility.Network). - withComponent("transposer"). - withConnector(). - create() +object Transposer { - override def position = BlockPosition(host) + abstract class Common extends prefab.ManagedEnvironment with traits.WorldInventoryAnalytics with traits.WorldTankAnalytics with traits.InventoryTransfer { + override val node = api.Network.newNode(this, Visibility.Network). + withComponent("transposer"). + withConnector(). + create() - override protected def checkSideForAction(args: Arguments, n: Int) = args.checkSide(n, EnumFacing.values: _*) + override protected def checkSideForAction(args: Arguments, n: Int) = + args.checkSide(n, EnumFacing.values: _*) - @Callback(doc = """function(sourceSide:number, sinkSide:number[, count:number[, sourceSlot:number, sinkSlot:number]]):number -- Transfer some items between two inventories.""") - def transferItem(context: Context, args: Arguments): Array[AnyRef] = { - val sourceSide = checkSideForAction(args, 0) - val sourcePos = position.offset(sourceSide) - val sinkSide = checkSideForAction(args, 1) - val sinkPos = position.offset(sinkSide) - val count = args.optItemCount(2) - - if (node.tryChangeBuffer(-Settings.get.transposerCost)) { - ServerPacketSender.sendTransposerActivity(host) - - if (args.count > 3) { - val sourceSlot = args.checkSlot(InventoryUtils.inventoryAt(sourcePos).getOrElse(throw new IllegalArgumentException("no inventory")), 3) - val sinkSlot = args.checkSlot(InventoryUtils.inventoryAt(sinkPos).getOrElse(throw new IllegalArgumentException("no inventory")), 4) - - result(InventoryUtils.transferBetweenInventoriesSlotsAt(sourcePos, sourceSide.getOpposite, sourceSlot, sinkPos, Option(sinkSide.getOpposite), sinkSlot, count)) - } - else result(InventoryUtils.transferBetweenInventoriesAt(sourcePos, sourceSide.getOpposite, sinkPos, Option(sinkSide.getOpposite), count)) + override def onTransferContents(): Option[String] = { + if (node.tryChangeBuffer(-Settings.get.transposerCost)) None + else Option("not enough energy") } - else result(Unit, "not enough energy") } - @Callback(doc = """function(sourceSide:number, sinkSide:number[, count:number]):number -- Transfer some items between two inventories.""") - def transferFluid(context: Context, args: Arguments): Array[AnyRef] = { - val sourceSide = checkSideForAction(args, 0) - val sourcePos = position.offset(sourceSide) - val sinkSide = checkSideForAction(args, 1) - val sinkPos = position.offset(sinkSide) - val count = args.optFluidCount(2) + class Block(val host: tileentity.Transposer) extends Common { + override def position = BlockPosition(host) - if (node.tryChangeBuffer(-Settings.get.transposerCost)) { - ServerPacketSender.sendTransposerActivity(host) - - val moved = FluidUtils.transferBetweenFluidHandlersAt(sourcePos, sourceSide.getOpposite, sinkPos, sinkSide.getOpposite, count) - if (moved > 0) context.pause(moved / 1000 * 0.25) // Allow up to 4 buckets per second. - result(moved > 0, moved) + override def onTransferContents(): Option[String] = { + val result = super.onTransferContents() + if (result.isEmpty) ServerPacketSender.sendTransposerActivity(host) + result } - else result(Unit, "not enough energy") } + + class Upgrade(val host: EnvironmentHost) extends Common { + node.setVisibility(Visibility.Neighbors) + + override def position = BlockPosition(host) + } + } diff --git a/src/main/scala/li/cil/oc/server/component/traits/InventoryTransfer.scala b/src/main/scala/li/cil/oc/server/component/traits/InventoryTransfer.scala new file mode 100644 index 000000000..704ddcdbc --- /dev/null +++ b/src/main/scala/li/cil/oc/server/component/traits/InventoryTransfer.scala @@ -0,0 +1,54 @@ +package li.cil.oc.server.component.traits + +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.server.component._ +import li.cil.oc.util.ExtendedArguments._ +import li.cil.oc.util.FluidUtils +import li.cil.oc.util.InventoryUtils + +trait InventoryTransfer extends traits.WorldAware with traits.SideRestricted { + // Return None on success, else Some("failure reason") + def onTransferContents(): Option[String] + + @Callback(doc = """function(sourceSide:number, sinkSide:number[, count:number[, sourceSlot:number[, sinkSlot:number]]]):number -- Transfer some items between two inventories.""") + def transferItem(context: Context, args: Arguments): Array[AnyRef] = { + val sourceSide = checkSideForAction(args, 0) + val sourcePos = position.offset(sourceSide) + val sinkSide = checkSideForAction(args, 1) + val sinkPos = position.offset(sinkSide) + val count = args.optItemCount(2) + + onTransferContents() match { + case Some(reason) => + result(Unit, reason) + case _ => + if (args.count > 3) { + val sourceSlot = args.checkSlot(InventoryUtils.inventoryAt(sourcePos).getOrElse(throw new IllegalArgumentException("no inventory")), 3) + val sinkSlot = args.optSlot(InventoryUtils.inventoryAt(sinkPos).getOrElse(throw new IllegalArgumentException("no inventory")), 4, -1) + + result(InventoryUtils.transferBetweenInventoriesSlotsAt(sourcePos, sourceSide.getOpposite, sourceSlot, sinkPos, Option(sinkSide.getOpposite), if (sinkSlot < 0) None else Option(sinkSlot), count)) + } + else result(InventoryUtils.transferBetweenInventoriesAt(sourcePos, sourceSide.getOpposite, sinkPos, Option(sinkSide.getOpposite), count)) + } + } + + @Callback(doc = """function(sourceSide:number, sinkSide:number[, count:number]):number -- Transfer some items between two inventories.""") + def transferFluid(context: Context, args: Arguments): Array[AnyRef] = { + val sourceSide = checkSideForAction(args, 0) + val sourcePos = position.offset(sourceSide) + val sinkSide = checkSideForAction(args, 1) + val sinkPos = position.offset(sinkSide) + val count = args.optFluidCount(2) + + onTransferContents() match { + case Some(reason) => + result(Unit, reason) + case _ => + val moved = FluidUtils.transferBetweenFluidHandlersAt(sourcePos, sourceSide.getOpposite, sinkPos, sinkSide.getOpposite, count) + if (moved > 0) context.pause(moved / 1000 * 0.25) // Allow up to 4 buckets per second. + result(moved > 0, moved) + } + } +} diff --git a/src/main/scala/li/cil/oc/server/component/traits/WorldInventoryAnalytics.scala b/src/main/scala/li/cil/oc/server/component/traits/WorldInventoryAnalytics.scala index 8cd75dfdd..887e81ba1 100644 --- a/src/main/scala/li/cil/oc/server/component/traits/WorldInventoryAnalytics.scala +++ b/src/main/scala/li/cil/oc/server/component/traits/WorldInventoryAnalytics.scala @@ -62,7 +62,7 @@ trait WorldInventoryAnalytics extends WorldAware with SideRestricted with Networ val facing = checkSideForAction(args, 0) withInventory(facing, inventory => result(inventory.getStackInSlot(args.checkSlot(inventory, 1)))) } - else result(null, "not enabled in config") + else result(Unit, "not enabled in config") @Callback(doc = """function(side:number, slot:number, dbAddress:string, dbSlot:number):boolean -- Store an item stack description in the specified slot of the database with the specified address.""") def store(context: Context, args: Arguments): Array[AnyRef] = { @@ -80,6 +80,6 @@ trait WorldInventoryAnalytics extends WorldAware with SideRestricted with Networ private def withInventory(side: EnumFacing, f: IInventory => Array[AnyRef]) = InventoryUtils.inventoryAt(position.offset(side)) match { case Some(inventory) if inventory.isUseableByPlayer(fakePlayer) && mayInteract(position.offset(side), side.getOpposite) => f(inventory) - case _ => result(null, "no inventory") + case _ => result(Unit, "no inventory") } } diff --git a/src/main/scala/li/cil/oc/util/InventoryUtils.scala b/src/main/scala/li/cil/oc/util/InventoryUtils.scala index ff2936839..97c75ae2c 100644 --- a/src/main/scala/li/cil/oc/util/InventoryUtils.scala +++ b/src/main/scala/li/cil/oc/util/InventoryUtils.scala @@ -249,9 +249,15 @@ object InventoryUtils { /** * Like transferBetweenInventories but moving between specific slots. */ - def transferBetweenInventoriesSlots(source: IInventory, sourceSide: EnumFacing, sourceSlot: Int, sink: IInventory, sinkSide: Option[EnumFacing], sinkSlot: Int, limit: Int = 64) = - extractFromInventorySlot( - insertIntoInventorySlot(_, sink, sinkSide, sinkSlot, limit), source, sourceSide, sourceSlot, limit) + def transferBetweenInventoriesSlots(source: IInventory, sourceSide: EnumFacing, sourceSlot: Int, sink: IInventory, sinkSide: Option[EnumFacing], sinkSlot: Option[Int], limit: Int = 64) = + sinkSlot match { + case Some(explicitSinkSlot) => + extractFromInventorySlot( + insertIntoInventorySlot(_, sink, sinkSide, explicitSinkSlot, limit), source, sourceSide, sourceSlot, limit) + case _ => + extractFromInventorySlot( + insertIntoInventory(_, sink, sinkSide, limit), source, sourceSide, sourceSlot, limit) + } /** * Utility method for calling transferBetweenInventories on inventories @@ -266,7 +272,7 @@ object InventoryUtils { * Utility method for calling transferBetweenInventoriesSlots on inventories * in the world. */ - def transferBetweenInventoriesSlotsAt(sourcePos: BlockPosition, sourceSide: EnumFacing, sourceSlot: Int, sinkPos: BlockPosition, sinkSide: Option[EnumFacing], sinkSlot: Int, limit: Int = 64) = + def transferBetweenInventoriesSlotsAt(sourcePos: BlockPosition, sourceSide: EnumFacing, sourceSlot: Int, sinkPos: BlockPosition, sinkSide: Option[EnumFacing], sinkSlot: Option[Int], limit: Int = 64) = inventoryAt(sourcePos).exists(sourceInventory => inventoryAt(sinkPos).exists(sinkInventory => transferBetweenInventoriesSlots(sourceInventory, sourceSide, sourceSlot, sinkInventory, sinkSide, sinkSlot, limit)))