mirror of
https://github.com/MightyPirates/OpenComputers.git
synced 2025-09-13 09:18:05 -04:00
Merge branch 'master-MC1.7.10' of github.com:MightyPirates/OpenComputers into master-MC1.8
Conflicts: src/main/scala/li/cil/oc/client/PacketHandler.scala src/main/scala/li/cil/oc/client/Textures.scala src/main/scala/li/cil/oc/client/renderer/block/BlockRenderer.scala src/main/scala/li/cil/oc/common/block/Geolyzer.scala src/main/scala/li/cil/oc/common/block/NetSplitter.scala src/main/scala/li/cil/oc/common/init/Blocks.scala src/main/scala/li/cil/oc/server/PacketSender.scala src/main/scala/li/cil/oc/server/component/traits/TankWorldControl.scala src/main/scala/li/cil/oc/util/ExtendedArguments.scala
This commit is contained in:
commit
0a9e950869
@ -767,6 +767,10 @@ opencomputers {
|
||||
# Per-byte cost for ECDSA operation is controlled by `complex` value,
|
||||
# because data is hashed with SHA256 before signing/verifying
|
||||
dataCardAsymmetric: 10.0
|
||||
|
||||
# Energy required for one transposer operation (regardless of the number
|
||||
# of items / fluid volume moved).
|
||||
transposer: 1
|
||||
}
|
||||
|
||||
# The rate at which different blocks accept external power. All of these
|
||||
|
@ -0,0 +1,9 @@
|
||||
# Transposer
|
||||
|
||||

|
||||
|
||||
The transposer bridges the gap between redstone controlled hoppers and [robots](robot.md), allowing [computer](../general/computer.md)-controlled transferral of items and fluids between adjacent blocks.
|
||||
|
||||
*Note that this block has no internal inventory.*
|
||||
|
||||
Besides moving things around, it can also be used to inspect the contents of the adjacent inventories, like an [adapter](adapter.md) with an [inventory controller upgrade](../item/inventoryControllerUpgrade.md) could, and the contents of adjacent tanks, like and adapter with a [tank controller upgrade](../item/tankControllerUpgrade.md) could.
|
@ -23,6 +23,7 @@ tile.oc.hologram2.name=Hologram Projector (Tier 2)
|
||||
tile.oc.keyboard.name=Keyboard
|
||||
tile.oc.microcontroller.name=Microcontroller
|
||||
tile.oc.motionSensor.name=Motion Sensor
|
||||
tile.oc.netSplitter.name=Net Splitter
|
||||
tile.oc.powerConverter.name=Power Converter
|
||||
tile.oc.powerDistributor.name=Power Distributor
|
||||
tile.oc.print.name=3D Print
|
||||
@ -37,7 +38,7 @@ tile.oc.screen2.name=Screen (Tier 2)
|
||||
tile.oc.screen3.name=Screen (Tier 3)
|
||||
tile.oc.serverRack.name=Server Rack
|
||||
tile.oc.switch.name=§cSwitch§7
|
||||
tile.oc.netSplitter.name=Net Splitter
|
||||
tile.oc.transposer.name=Transposer
|
||||
tile.oc.waypoint.name=Waypoint
|
||||
|
||||
# Items
|
||||
@ -348,6 +349,7 @@ oc:tooltip.Tier=§8Tier %s
|
||||
oc:tooltip.NetSplitter=Acts as a dynamic connector. Connectivity of each side can be toggled by hitting it with a wrench. Connectivity of all sides can be inverted by applying a redstone signal.
|
||||
oc:tooltip.TooLong=Hold [§f%s§7] for a detailed tooltip.
|
||||
oc:tooltip.Transistor=A basic element in most other computer parts. It's a bit twisted, but it does the job.
|
||||
oc:tooltip.Transposer=Allows automated transferral of items and fluids between adjacent inventories and fluid containers.
|
||||
oc:tooltip.UpgradeAngel=Allows robots to place blocks in thin air, even if there is no point of reference.
|
||||
oc:tooltip.UpgradeBattery=Increase the amount of energy a device can store, allowing it work longer without having to be recharged. [nl] Capacity: §f%s§7
|
||||
oc:tooltip.UpgradeChunkloader=If a robot moves in a forest and no one is around to see it, does it really move? This upgrades makes sure it does. It keeps the chunk a device is in loaded, but continually consumes energy while active.
|
||||
|
@ -634,6 +634,12 @@ screen3 {
|
||||
[yellowDust, "oc:circuitChip3", glass]
|
||||
[obsidian, yellowDust, obsidian]]
|
||||
}
|
||||
transposer {
|
||||
input: [[ingotIron, "oc:inventoryControllerUpgrade", ingotIron]
|
||||
[hopper, bucket, hopper]
|
||||
[ingotIron, "oc:tankControllerUpgrade", ingotIron]]
|
||||
output: 4
|
||||
}
|
||||
waypoint {
|
||||
input: [[ingotIron, "oc:circuitChip1", ingotIron]
|
||||
["oc:materialTransistor", "oc:materialInterweb", "oc:materialTransistor"],
|
||||
|
Binary file not shown.
After Width: | Height: | Size: 154 B |
Binary file not shown.
After Width: | Height: | Size: 523 B |
Binary file not shown.
After Width: | Height: | Size: 425 B |
@ -25,6 +25,7 @@ object Constants {
|
||||
final val Keyboard = "keyboard"
|
||||
final val Microcontroller = "microcontroller"
|
||||
final val MotionSensor = "motionSensor"
|
||||
final val NetSplitter = "netSplitter"
|
||||
final val PowerConverter = "powerConverter"
|
||||
final val PowerDistributor = "powerDistributor"
|
||||
final val Print = "print"
|
||||
@ -39,7 +40,7 @@ object Constants {
|
||||
final val ScreenTier3 = "screen3"
|
||||
final val ServerRack = "serverRack"
|
||||
final val Switch = "switch"
|
||||
final val NetSplitter = "netSplitter"
|
||||
final val Transposer = "transposer"
|
||||
final val Waypoint = "waypoint"
|
||||
|
||||
def Case(tier: Int) = ItemUtils.caseNameWithTierSuffix("case", tier)
|
||||
|
@ -201,6 +201,7 @@ class Settings(val config: Config) {
|
||||
val dataCardComplex = config.getDouble("power.cost.dataCardComplex") max 0
|
||||
val dataCardComplexByte = config.getDouble("power.cost.dataCardComplexByte") max 0
|
||||
val dataCardAsymmetric = config.getDouble("power.cost.dataCardAsymmetric") max 0
|
||||
val transposerCost = config.getDouble("power.cost.transposer") max 0
|
||||
|
||||
// power.rate
|
||||
val accessPointRate = config.getDouble("power.rate.accessPoint") max 0
|
||||
|
@ -81,6 +81,7 @@ object PacketHandler extends CommonPacketHandler {
|
||||
case PacketType.ServerPresence => onServerPresence(p)
|
||||
case PacketType.Sound => onSound(p)
|
||||
case PacketType.SoundPattern => onSoundPattern(p)
|
||||
case PacketType.TransposerActivity => onTransposerActivity(p)
|
||||
case PacketType.WaypointLabel => onWaypointLabel(p)
|
||||
case _ => // Invalid packet.
|
||||
}
|
||||
@ -260,6 +261,15 @@ object PacketHandler extends CommonPacketHandler {
|
||||
}
|
||||
}
|
||||
|
||||
def onNetSplitterState(p: PacketParser) =
|
||||
p.readTileEntity[NetSplitter]() match {
|
||||
case Some(t) =>
|
||||
t.isInverted = p.readBoolean()
|
||||
t.openSides = t.uncompressSides(p.readByte())
|
||||
t.world.markBlockForUpdate(t.getPos)
|
||||
case _ => // Invalid packet.
|
||||
}
|
||||
|
||||
def onParticleEffect(p: PacketParser) = {
|
||||
val dimension = p.readInt()
|
||||
world(p.player, dimension) match {
|
||||
@ -589,15 +599,6 @@ object PacketHandler extends CommonPacketHandler {
|
||||
buffer.rawSetForeground(col, row, color)
|
||||
}
|
||||
|
||||
def onNetSplitterState(p: PacketParser) =
|
||||
p.readTileEntity[NetSplitter]() match {
|
||||
case Some(t) =>
|
||||
t.isInverted = p.readBoolean()
|
||||
t.openSides = t.uncompressSides(p.readByte())
|
||||
t.world.markBlockForUpdate(t.getPos)
|
||||
case _ => // Invalid packet.
|
||||
}
|
||||
|
||||
def onScreenTouchMode(p: PacketParser) =
|
||||
p.readTileEntity[Screen]() match {
|
||||
case Some(t) => t.invertTouchMode = p.readBoolean()
|
||||
@ -638,6 +639,12 @@ object PacketHandler extends CommonPacketHandler {
|
||||
}
|
||||
}
|
||||
|
||||
def onTransposerActivity(p: PacketParser) =
|
||||
p.readTileEntity[Transposer]() match {
|
||||
case Some(transposer) => transposer.lastOperation = System.currentTimeMillis()
|
||||
case _ => // Invalid packet.
|
||||
}
|
||||
|
||||
def onWaypointLabel(p: PacketParser) =
|
||||
p.readTileEntity[Waypoint]() match {
|
||||
case Some(waypoint) => waypoint.label = p.readUTF()
|
||||
|
@ -63,6 +63,7 @@ private[oc] class Proxy extends CommonProxy {
|
||||
else
|
||||
ClientRegistry.bindTileEntitySpecialRenderer(classOf[tileentity.Hologram], HologramRendererFallback)
|
||||
ClientRegistry.bindTileEntitySpecialRenderer(classOf[tileentity.Microcontroller], MicrocontrollerRenderer)
|
||||
ClientRegistry.bindTileEntitySpecialRenderer(classOf[tileentity.NetSplitter], NetSplitterRenderer)
|
||||
ClientRegistry.bindTileEntitySpecialRenderer(classOf[tileentity.PowerDistributor], PowerDistributorRenderer)
|
||||
ClientRegistry.bindTileEntitySpecialRenderer(classOf[tileentity.Printer], PrinterRenderer)
|
||||
ClientRegistry.bindTileEntitySpecialRenderer(classOf[tileentity.Raid], RaidRenderer)
|
||||
@ -72,7 +73,7 @@ private[oc] class Proxy extends CommonProxy {
|
||||
ClientRegistry.bindTileEntitySpecialRenderer(classOf[tileentity.Relay], SwitchRenderer)
|
||||
ClientRegistry.bindTileEntitySpecialRenderer(classOf[tileentity.RobotProxy], RobotRenderer)
|
||||
ClientRegistry.bindTileEntitySpecialRenderer(classOf[tileentity.Screen], ScreenRenderer)
|
||||
ClientRegistry.bindTileEntitySpecialRenderer(classOf[tileentity.NetSplitter], NetSplitterRenderer)
|
||||
ClientRegistry.bindTileEntitySpecialRenderer(classOf[tileentity.Transposer], TransposerRenderer)
|
||||
|
||||
ClientRegistry.registerKeyBinding(KeyBindings.materialCosts)
|
||||
ClientRegistry.registerKeyBinding(KeyBindings.clipboardPaste)
|
||||
|
@ -143,6 +143,7 @@ object Textures {
|
||||
val RaidFrontError = L("overlay/raid_front_error")
|
||||
val ScreenUpIndicator = L("overlay/screen_up_indicator")
|
||||
val SwitchSideOn = L("overlay/switch_side_on")
|
||||
val TransposerOn = L("overlay/transposer_on")
|
||||
|
||||
val Cable = L("cable")
|
||||
val CableCap = L("cableCap")
|
||||
|
@ -0,0 +1,78 @@
|
||||
package li.cil.oc.client.renderer.tileentity
|
||||
|
||||
import li.cil.oc.client.Textures
|
||||
import li.cil.oc.common.tileentity
|
||||
import li.cil.oc.util.RenderState
|
||||
import net.minecraft.client.renderer.Tessellator
|
||||
import net.minecraft.client.renderer.texture.TextureMap
|
||||
import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer
|
||||
import net.minecraft.tileentity.TileEntity
|
||||
import org.lwjgl.opengl.GL11
|
||||
|
||||
object TransposerRenderer extends TileEntitySpecialRenderer {
|
||||
override def renderTileEntityAt(tileEntity: TileEntity, x: Double, y: Double, z: Double, f: Float, damage: Int) {
|
||||
RenderState.checkError(getClass.getName + ".renderTileEntityAt: entering (aka: wasntme)")
|
||||
|
||||
val transposer = tileEntity.asInstanceOf[tileentity.Transposer]
|
||||
val activity = math.max(0, 1 - (System.currentTimeMillis() - transposer.lastOperation) / 1000.0)
|
||||
if (activity > 0) {
|
||||
GL11.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS)
|
||||
|
||||
RenderState.disableLighting()
|
||||
RenderState.makeItBlend()
|
||||
RenderState.setBlendAlpha(activity.toFloat)
|
||||
|
||||
GL11.glPushMatrix()
|
||||
|
||||
GL11.glTranslated(x + 0.5, y + 0.5, z + 0.5)
|
||||
GL11.glScaled(1.0025, -1.0025, 1.0025)
|
||||
GL11.glTranslatef(-0.5f, -0.5f, -0.5f)
|
||||
|
||||
bindTexture(TextureMap.locationBlocksTexture)
|
||||
val t = Tessellator.getInstance
|
||||
val r = t.getWorldRenderer
|
||||
r.startDrawingQuads()
|
||||
|
||||
val icon = Textures.getSprite(Textures.Block.TransposerOn)
|
||||
|
||||
r.addVertexWithUV(0, 1, 0, icon.getMaxU, icon.getMinV)
|
||||
r.addVertexWithUV(1, 1, 0, icon.getMinU, icon.getMinV)
|
||||
r.addVertexWithUV(1, 1, 1, icon.getMinU, icon.getMaxV)
|
||||
r.addVertexWithUV(0, 1, 1, icon.getMaxU, icon.getMaxV)
|
||||
|
||||
r.addVertexWithUV(0, 0, 0, icon.getMaxU, icon.getMaxV)
|
||||
r.addVertexWithUV(0, 0, 1, icon.getMaxU, icon.getMinV)
|
||||
r.addVertexWithUV(1, 0, 1, icon.getMinU, icon.getMinV)
|
||||
r.addVertexWithUV(1, 0, 0, icon.getMinU, icon.getMaxV)
|
||||
|
||||
r.addVertexWithUV(1, 1, 0, icon.getMinU, icon.getMaxV)
|
||||
r.addVertexWithUV(0, 1, 0, icon.getMaxU, icon.getMaxV)
|
||||
r.addVertexWithUV(0, 0, 0, icon.getMaxU, icon.getMinV)
|
||||
r.addVertexWithUV(1, 0, 0, icon.getMinU, icon.getMinV)
|
||||
|
||||
r.addVertexWithUV(0, 1, 1, icon.getMinU, icon.getMaxV)
|
||||
r.addVertexWithUV(1, 1, 1, icon.getMaxU, icon.getMaxV)
|
||||
r.addVertexWithUV(1, 0, 1, icon.getMaxU, icon.getMinV)
|
||||
r.addVertexWithUV(0, 0, 1, icon.getMinU, icon.getMinV)
|
||||
|
||||
r.addVertexWithUV(0, 1, 0, icon.getMinU, icon.getMaxV)
|
||||
r.addVertexWithUV(0, 1, 1, icon.getMaxU, icon.getMaxV)
|
||||
r.addVertexWithUV(0, 0, 1, icon.getMaxU, icon.getMinV)
|
||||
r.addVertexWithUV(0, 0, 0, icon.getMinU, icon.getMinV)
|
||||
|
||||
r.addVertexWithUV(1, 1, 1, icon.getMinU, icon.getMaxV)
|
||||
r.addVertexWithUV(1, 1, 0, icon.getMaxU, icon.getMaxV)
|
||||
r.addVertexWithUV(1, 0, 0, icon.getMaxU, icon.getMinV)
|
||||
r.addVertexWithUV(1, 0, 1, icon.getMinU, icon.getMinV)
|
||||
|
||||
t.draw()
|
||||
|
||||
RenderState.enableLighting()
|
||||
|
||||
GL11.glPopMatrix()
|
||||
GL11.glPopAttrib()
|
||||
}
|
||||
|
||||
RenderState.checkError(getClass.getName + ".renderTileEntityAt: leaving")
|
||||
}
|
||||
}
|
@ -20,6 +20,7 @@ object PacketType extends Enumeration {
|
||||
HologramTranslation,
|
||||
HologramValues,
|
||||
LootDisk,
|
||||
NetSplitterState,
|
||||
ParticleEffect,
|
||||
PetVisibility, // Goes both ways.
|
||||
PowerState,
|
||||
@ -49,11 +50,11 @@ object PacketType extends Enumeration {
|
||||
TextBufferMultiRawSetBackground,
|
||||
TextBufferMultiRawSetForeground,
|
||||
TextBufferPowerChange,
|
||||
NetSplitterState,
|
||||
ScreenTouchMode,
|
||||
ServerPresence,
|
||||
Sound,
|
||||
SoundPattern,
|
||||
TransposerActivity,
|
||||
WaypointLabel, // Goes both ways.
|
||||
|
||||
// Client -> Server
|
||||
|
18
src/main/scala/li/cil/oc/common/block/Transposer.scala
Normal file
18
src/main/scala/li/cil/oc/common/block/Transposer.scala
Normal file
@ -0,0 +1,18 @@
|
||||
package li.cil.oc.common.block
|
||||
|
||||
import li.cil.oc.common.tileentity
|
||||
import net.minecraft.block.state.IBlockState
|
||||
import net.minecraft.util.BlockPos
|
||||
import net.minecraft.util.EnumFacing
|
||||
import net.minecraft.world.IBlockAccess
|
||||
import net.minecraft.world.World
|
||||
|
||||
class Transposer extends SimpleBlock {
|
||||
override def isSideSolid(world: IBlockAccess, pos: BlockPos, side: EnumFacing): Boolean = false
|
||||
|
||||
// ----------------------------------------------------------------------- //
|
||||
|
||||
override def hasTileEntity(state: IBlockState): Boolean = true
|
||||
|
||||
override def createNewTileEntity(world: World, meta: Int) = new tileentity.Transposer()
|
||||
}
|
@ -24,6 +24,7 @@ object Blocks {
|
||||
GameRegistry.registerTileEntity(classOf[tileentity.Geolyzer], Settings.namespace + "geolyzer")
|
||||
GameRegistry.registerTileEntity(classOf[tileentity.Microcontroller], Settings.namespace + "microcontroller")
|
||||
GameRegistry.registerTileEntity(classOf[tileentity.MotionSensor], Settings.namespace + "motionSensor")
|
||||
GameRegistry.registerTileEntity(classOf[tileentity.NetSplitter], Settings.namespace + "netSplitter")
|
||||
GameRegistry.registerTileEntity(classOf[tileentity.PowerConverter], Settings.namespace + "powerConverter")
|
||||
GameRegistry.registerTileEntity(classOf[tileentity.PowerDistributor], Settings.namespace + "powerDistributor")
|
||||
GameRegistry.registerTileEntity(classOf[tileentity.Print], Settings.namespace + "print")
|
||||
@ -35,7 +36,7 @@ object Blocks {
|
||||
GameRegistry.registerTileEntity(classOf[tileentity.Switch], Settings.namespace + "switch")
|
||||
GameRegistry.registerTileEntity(classOf[tileentity.Screen], Settings.namespace + "screen")
|
||||
GameRegistry.registerTileEntity(classOf[tileentity.ServerRack], Settings.namespace + "serverRack")
|
||||
GameRegistry.registerTileEntity(classOf[tileentity.NetSplitter], Settings.namespace + "netSplitter")
|
||||
GameRegistry.registerTileEntity(classOf[tileentity.Transposer], Settings.namespace + "transposer")
|
||||
GameRegistry.registerTileEntity(classOf[tileentity.Waypoint], Settings.namespace + "waypoint")
|
||||
|
||||
Items.registerBlock(new AccessPoint(), Constants.BlockName.AccessPoint)
|
||||
@ -79,5 +80,8 @@ object Blocks {
|
||||
|
||||
// v1.5.14
|
||||
Recipes.addBlock(new NetSplitter(), Constants.BlockName.NetSplitter, "oc:netSplitter")
|
||||
|
||||
// v1.5.16
|
||||
Recipes.addBlock(new Transposer(), Constants.BlockName.Transposer, "oc:transposer")
|
||||
}
|
||||
}
|
||||
|
25
src/main/scala/li/cil/oc/common/tileentity/Transposer.scala
Normal file
25
src/main/scala/li/cil/oc/common/tileentity/Transposer.scala
Normal file
@ -0,0 +1,25 @@
|
||||
package li.cil.oc.common.tileentity
|
||||
|
||||
import li.cil.oc.server.component
|
||||
import net.minecraft.nbt.NBTTagCompound
|
||||
|
||||
class Transposer extends traits.Environment {
|
||||
val transposer = new component.Transposer(this)
|
||||
|
||||
def node = transposer.node
|
||||
|
||||
// Used on client side to check whether to render activity indicators.
|
||||
var lastOperation = 0L
|
||||
|
||||
override def canUpdate = false
|
||||
|
||||
override def readFromNBTForServer(nbt: NBTTagCompound) {
|
||||
super.readFromNBTForServer(nbt)
|
||||
transposer.load(nbt)
|
||||
}
|
||||
|
||||
override def writeToNBTForServer(nbt: NBTTagCompound) {
|
||||
super.writeToNBTForServer(nbt)
|
||||
transposer.save(nbt)
|
||||
}
|
||||
}
|
@ -227,6 +227,16 @@ object PacketSender {
|
||||
}
|
||||
}
|
||||
|
||||
def sendNetSplitterState(t: tileentity.NetSplitter): Unit = {
|
||||
val pb = new SimplePacketBuilder(PacketType.NetSplitterState)
|
||||
|
||||
pb.writeTileEntity(t)
|
||||
pb.writeBoolean(t.isInverted)
|
||||
pb.writeByte(t.compressSides)
|
||||
|
||||
pb.sendToPlayersNearTileEntity(t)
|
||||
}
|
||||
|
||||
def sendParticleEffect(position: BlockPosition, particleType: EnumParticleTypes, count: Int, velocity: Double, direction: Option[EnumFacing] = None): Unit = if (count > 0) {
|
||||
val pb = new SimplePacketBuilder(PacketType.ParticleEffect)
|
||||
|
||||
@ -522,16 +532,6 @@ object PacketSender {
|
||||
pb.sendToPlayersNearHost(host)
|
||||
}
|
||||
|
||||
def sendNetSplitterState(t: tileentity.NetSplitter): Unit = {
|
||||
val pb = new SimplePacketBuilder(PacketType.NetSplitterState)
|
||||
|
||||
pb.writeTileEntity(t)
|
||||
pb.writeBoolean(t.isInverted)
|
||||
pb.writeByte(t.compressSides)
|
||||
|
||||
pb.sendToPlayersNearTileEntity(t)
|
||||
}
|
||||
|
||||
def sendScreenTouchMode(t: tileentity.Screen, value: Boolean) {
|
||||
val pb = new SimplePacketBuilder(PacketType.ScreenTouchMode)
|
||||
|
||||
@ -612,6 +612,14 @@ object PacketSender {
|
||||
pb.sendToNearbyPlayers(world, x, y, z, Option(32))
|
||||
}
|
||||
|
||||
def sendTransposerActivity(t: tileentity.Transposer) {
|
||||
val pb = new SimplePacketBuilder(PacketType.TransposerActivity)
|
||||
|
||||
pb.writeTileEntity(t)
|
||||
|
||||
pb.sendToPlayersNearTileEntity(t, Option(32))
|
||||
}
|
||||
|
||||
def sendWaypointLabel(t: Waypoint): Unit = {
|
||||
val pb = new SimplePacketBuilder(PacketType.WaypointLabel)
|
||||
|
||||
|
67
src/main/scala/li/cil/oc/server/component/Transposer.scala
Normal file
67
src/main/scala/li/cil/oc/server/component/Transposer.scala
Normal file
@ -0,0 +1,67 @@
|
||||
package li.cil.oc.server.component
|
||||
|
||||
import li.cil.oc.Settings
|
||||
import li.cil.oc.api
|
||||
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()
|
||||
|
||||
override def position = BlockPosition(host)
|
||||
|
||||
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))
|
||||
}
|
||||
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)
|
||||
|
||||
if (node.tryChangeBuffer(-Settings.get.transposerCost)) {
|
||||
ServerPacketSender.sendTransposerActivity(host)
|
||||
|
||||
result(FluidUtils.transferBetweenFluidHandlersAt(sourcePos, sourceSide.getOpposite, sinkPos, sinkSide.getOpposite, count))
|
||||
}
|
||||
else result(Unit, "not enough energy")
|
||||
}
|
||||
}
|
@ -4,14 +4,9 @@ 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.util.ExtendedArguments._
|
||||
import li.cil.oc.util.ExtendedBlock._
|
||||
import li.cil.oc.util.ExtendedWorld._
|
||||
import li.cil.oc.util.FluidUtils
|
||||
import li.cil.oc.util.ResultWrapper.result
|
||||
import net.minecraft.block.BlockLiquid
|
||||
import net.minecraftforge.fluids.FluidRegistry
|
||||
import net.minecraftforge.fluids.FluidStack
|
||||
import net.minecraftforge.fluids.IFluidBlock
|
||||
import net.minecraftforge.fluids.IFluidHandler
|
||||
|
||||
trait TankWorldControl extends TankAware with WorldAware with SideRestricted {
|
||||
@Callback(doc = "function(side:number):boolean -- Compare the fluid in the selected tank with the fluid on the specified side. Returns true if equal.")
|
||||
@ -19,16 +14,10 @@ trait TankWorldControl extends TankAware with WorldAware with SideRestricted {
|
||||
val side = checkSideForAction(args, 0)
|
||||
fluidInTank(selectedTank) match {
|
||||
case Some(stack) =>
|
||||
val blockPos = position.offset(side)
|
||||
if (world.blockExists(blockPos)) world.getTileEntity(blockPos) match {
|
||||
case handler: IFluidHandler =>
|
||||
result(Option(handler.getTankInfo(side.getOpposite)).exists(_.exists(other => stack.isFluidEqual(other.fluid))))
|
||||
case _ =>
|
||||
val block = world.getBlock(blockPos)
|
||||
val fluid = FluidRegistry.lookupFluidForBlock(block)
|
||||
result(stack.getFluid == fluid)
|
||||
FluidUtils.fluidHandlerAt(position.offset(side)) match {
|
||||
case Some(handler) => result(Option(handler.getTankInfo(side.getOpposite)).exists(_.exists(other => stack.isFluidEqual(other.fluid))))
|
||||
case _ => result(false)
|
||||
}
|
||||
else result(false)
|
||||
case _ => result(false)
|
||||
}
|
||||
}
|
||||
@ -36,18 +25,14 @@ trait TankWorldControl extends TankAware with WorldAware with SideRestricted {
|
||||
@Callback(doc = "function(side:boolean[, amount:number=1000]):boolean, number or string -- Drains the specified amount of fluid from the specified side. Returns the amount drained, or an error message.")
|
||||
def drain(context: Context, args: Arguments): Array[AnyRef] = {
|
||||
val facing = checkSideForAction(args, 0)
|
||||
val count = args.optFluidCount(1)
|
||||
val count = args.optFluidCount(1) max 0
|
||||
getTank(selectedTank) match {
|
||||
case Some(tank) =>
|
||||
val space = tank.getCapacity - tank.getFluidAmount
|
||||
val amount = math.min(count, space)
|
||||
if (count > 0 && amount == 0) {
|
||||
result(Unit, "tank is full")
|
||||
}
|
||||
else {
|
||||
val blockPos = position.offset(facing)
|
||||
if (world.blockExists(blockPos)) world.getTileEntity(blockPos) match {
|
||||
case handler: IFluidHandler =>
|
||||
if (count < 1 || amount > 0) {
|
||||
FluidUtils.fluidHandlerAt(position.offset(facing)) match {
|
||||
case Some(handler) =>
|
||||
tank.getFluid match {
|
||||
case stack: FluidStack =>
|
||||
val drained = handler.drain(facing.getOpposite, new FluidStack(stack, amount), true)
|
||||
@ -60,36 +45,10 @@ trait TankWorldControl extends TankAware with WorldAware with SideRestricted {
|
||||
val transferred = tank.fill(handler.drain(facing.getOpposite, amount, true), true)
|
||||
result(transferred > 0, transferred)
|
||||
}
|
||||
case _ => world.getBlock(blockPos) match {
|
||||
case fluidBlock: IFluidBlock if fluidBlock.canDrain(world, blockPos.toBlockPos) =>
|
||||
val drained = fluidBlock.drain(world, blockPos.toBlockPos, false)
|
||||
if ((drained != null && drained.amount > 0) && (drained.amount <= amount || amount == 0)) {
|
||||
if (drained.amount <= amount) {
|
||||
val filled = tank.fill(fluidBlock.drain(world, blockPos.toBlockPos, true), true)
|
||||
result(true, filled)
|
||||
}
|
||||
else /* if (amount == 0) */ {
|
||||
result(true, 0)
|
||||
case _ => result(Unit, "incompatible or no fluid")
|
||||
}
|
||||
}
|
||||
else result(Unit, "tank is full")
|
||||
case liquidBlock: BlockLiquid if world.getBlockState(blockPos.toBlockPos) == liquidBlock.getDefaultState =>
|
||||
val fluid = FluidRegistry.lookupFluidForBlock(liquidBlock)
|
||||
if (fluid == null) {
|
||||
result(Unit, "incompatible or no fluid")
|
||||
}
|
||||
else if (tank.fill(new FluidStack(fluid, 1000), false) == 1000) {
|
||||
tank.fill(new FluidStack(fluid, 1000), true)
|
||||
world.setBlockToAir(blockPos)
|
||||
result(true, 1000)
|
||||
}
|
||||
else result(Unit, "tank is full")
|
||||
case _ =>
|
||||
result(Unit, "incompatible or no fluid")
|
||||
}
|
||||
}
|
||||
else result(Unit, "incompatible or no fluid")
|
||||
}
|
||||
case _ => result(Unit, "no tank selected")
|
||||
}
|
||||
}
|
||||
@ -97,16 +56,13 @@ trait TankWorldControl extends TankAware with WorldAware with SideRestricted {
|
||||
@Callback(doc = "function(side:number[, amount:number=1000]):boolean, number of string -- Eject the specified amount of fluid to the specified side. Returns the amount ejected or an error message.")
|
||||
def fill(context: Context, args: Arguments): Array[AnyRef] = {
|
||||
val facing = checkSideForAction(args, 0)
|
||||
val count = args.optFluidCount(1)
|
||||
val count = args.optFluidCount(1) max 0
|
||||
getTank(selectedTank) match {
|
||||
case Some(tank) =>
|
||||
val amount = math.min(count, tank.getFluidAmount)
|
||||
if (count > 0 && amount == 0) {
|
||||
result(Unit, "tank is empty")
|
||||
}
|
||||
val blockPos = position.offset(facing)
|
||||
if (world.blockExists(blockPos)) world.getTileEntity(blockPos) match {
|
||||
case handler: IFluidHandler =>
|
||||
if (count < 1 || amount > 0) {
|
||||
FluidUtils.fluidHandlerAt(position.offset(facing)) match {
|
||||
case Some(handler) =>
|
||||
tank.getFluid match {
|
||||
case stack: FluidStack =>
|
||||
val filled = handler.fill(facing.getOpposite, new FluidStack(stack, amount), true)
|
||||
@ -118,28 +74,10 @@ trait TankWorldControl extends TankAware with WorldAware with SideRestricted {
|
||||
case _ =>
|
||||
result(Unit, "tank is empty")
|
||||
}
|
||||
case _ =>
|
||||
val block = world.getBlock(blockPos)
|
||||
if (!block.isAir(blockPos) && !block.isReplaceable(blockPos)) {
|
||||
result(Unit, "no space")
|
||||
}
|
||||
else if (tank.getFluidAmount < 1000) {
|
||||
result(Unit, "tank is empty")
|
||||
}
|
||||
else if (!tank.getFluid.getFluid.canBePlacedInWorld) {
|
||||
result(Unit, "incompatible fluid")
|
||||
}
|
||||
else {
|
||||
val fluidBlock = tank.getFluid.getFluid.getBlock
|
||||
tank.drain(1000, true)
|
||||
world.breakBlock(blockPos)
|
||||
world.setBlock(blockPos, fluidBlock)
|
||||
// This fake neighbor update is required to get stills to start flowing.
|
||||
world.notifyBlockOfNeighborChange(blockPos, world.getBlock(position))
|
||||
result(true, 1000)
|
||||
case _ => result(Unit, "no space")
|
||||
}
|
||||
}
|
||||
else result(Unit, "no space")
|
||||
else result(Unit, "tank is empty")
|
||||
case _ => result(Unit, "no tank selected")
|
||||
}
|
||||
}
|
||||
|
@ -5,15 +5,15 @@ 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.result
|
||||
import li.cil.oc.util.ExtendedWorld._
|
||||
import net.minecraftforge.fluids.IFluidHandler
|
||||
import li.cil.oc.util.FluidUtils
|
||||
|
||||
trait WorldTankAnalytics extends WorldAware with SideRestricted {
|
||||
@Callback(doc = """function(side:number):number -- Get the amount of fluid in the tank on the specified side.""")
|
||||
def getTankLevel(context: Context, args: Arguments): Array[AnyRef] = {
|
||||
val facing = checkSideForAction(args, 0)
|
||||
world.getTileEntity(position.offset(facing)) match {
|
||||
case handler: IFluidHandler =>
|
||||
|
||||
FluidUtils.fluidHandlerAt(position.offset(facing)) match {
|
||||
case Some(handler) =>
|
||||
result(handler.getTankInfo(facing.getOpposite).map(info => Option(info.fluid).fold(0)(_.amount)).sum)
|
||||
case _ => result(Unit, "no tank")
|
||||
}
|
||||
@ -22,8 +22,8 @@ trait WorldTankAnalytics extends WorldAware with SideRestricted {
|
||||
@Callback(doc = """function(side:number):number -- Get the capacity of the tank on the specified side.""")
|
||||
def getTankCapacity(context: Context, args: Arguments): Array[AnyRef] = {
|
||||
val facing = checkSideForAction(args, 0)
|
||||
world.getTileEntity(position.offset(facing)) match {
|
||||
case handler: IFluidHandler =>
|
||||
FluidUtils.fluidHandlerAt(position.offset(facing)) match {
|
||||
case Some(handler) =>
|
||||
result(handler.getTankInfo(facing.getOpposite).map(_.capacity).foldLeft(0)((max, capacity) => math.max(max, capacity)))
|
||||
case _ => result(Unit, "no tank")
|
||||
}
|
||||
@ -32,8 +32,8 @@ trait WorldTankAnalytics extends WorldAware with SideRestricted {
|
||||
@Callback(doc = """function(side:number):table -- Get a description of the fluid in the the tank on the specified side.""")
|
||||
def getFluidInTank(context: Context, args: Arguments): Array[AnyRef] = if (Settings.get.allowItemStackInspection) {
|
||||
val facing = checkSideForAction(args, 0)
|
||||
world.getTileEntity(position.offset(facing)) match {
|
||||
case handler: IFluidHandler =>
|
||||
FluidUtils.fluidHandlerAt(position.offset(facing)) match {
|
||||
case Some(handler) =>
|
||||
result(handler.getTankInfo(facing.getOpposite))
|
||||
case _ => result(Unit, "no tank")
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ import li.cil.oc.api.internal.MultiTank
|
||||
import li.cil.oc.api.machine.Arguments
|
||||
import net.minecraft.inventory.IInventory
|
||||
import net.minecraft.util.EnumFacing
|
||||
import net.minecraftforge.fluids.FluidContainerRegistry
|
||||
|
||||
import scala.language.implicitConversions
|
||||
|
||||
@ -16,7 +17,7 @@ object ExtendedArguments {
|
||||
if (!isDefined(index) || !hasValue(index)) default
|
||||
else math.max(0, math.min(64, args.checkInteger(index)))
|
||||
|
||||
def optFluidCount(index: Int, default: Int = 1000) =
|
||||
def optFluidCount(index: Int, default: Int = FluidContainerRegistry.BUCKET_VOLUME) =
|
||||
if (!isDefined(index) || !hasValue(index)) default
|
||||
else math.max(0, args.checkInteger(index))
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
package li.cil.oc.util
|
||||
|
||||
import net.minecraft.block.Block
|
||||
import net.minecraftforge.fluids.IFluidBlock
|
||||
|
||||
import scala.language.implicitConversions
|
||||
|
||||
@ -22,4 +23,14 @@ object ExtendedBlock {
|
||||
def getCollisionBoundingBoxFromPool(position: BlockPosition) = block.getCollisionBoundingBox(position.world.get, position.toBlockPos, position.world.get.getBlockState(position.toBlockPos))
|
||||
}
|
||||
|
||||
implicit def extendedFluidBlock(block: IFluidBlock): ExtendedFluidBlock = new ExtendedFluidBlock(block)
|
||||
|
||||
class ExtendedFluidBlock(val block: IFluidBlock) {
|
||||
def drain(position: BlockPosition, doDrain: Boolean) = block.drain(position.world.get, position.toBlockPos, doDrain)
|
||||
|
||||
def canDrain(position: BlockPosition) = block.canDrain(position.world.get, position.toBlockPos)
|
||||
|
||||
def getFilledPercentage(position: BlockPosition) = block.getFilledPercentage(position.world.get, position.toBlockPos)
|
||||
}
|
||||
|
||||
}
|
||||
|
157
src/main/scala/li/cil/oc/util/FluidUtils.scala
Normal file
157
src/main/scala/li/cil/oc/util/FluidUtils.scala
Normal file
@ -0,0 +1,157 @@
|
||||
package li.cil.oc.util
|
||||
|
||||
import li.cil.oc.util.ExtendedBlock._
|
||||
import li.cil.oc.util.ExtendedWorld._
|
||||
import net.minecraft.block.Block
|
||||
import net.minecraft.block.BlockLiquid
|
||||
import net.minecraft.util.EnumFacing
|
||||
import net.minecraftforge.fluids.Fluid
|
||||
import net.minecraftforge.fluids.FluidContainerRegistry
|
||||
import net.minecraftforge.fluids.FluidRegistry
|
||||
import net.minecraftforge.fluids.FluidStack
|
||||
import net.minecraftforge.fluids.FluidTank
|
||||
import net.minecraftforge.fluids.FluidTankInfo
|
||||
import net.minecraftforge.fluids.IFluidBlock
|
||||
import net.minecraftforge.fluids.IFluidHandler
|
||||
|
||||
object FluidUtils {
|
||||
/**
|
||||
* Retrieves an actual fluid handler implementation for a specified world coordinate.
|
||||
* <p/>
|
||||
* This performs special handling for in-world liquids.
|
||||
*/
|
||||
def fluidHandlerAt(position: BlockPosition): Option[IFluidHandler] = position.world match {
|
||||
case Some(world) if world.blockExists(position) => world.getTileEntity(position) match {
|
||||
case handler: IFluidHandler => Option(handler)
|
||||
case _ => Option(new GenericBlockWrapper(position))
|
||||
}
|
||||
case _ => None
|
||||
}
|
||||
|
||||
/**
|
||||
* Transfers some fluid between two fluid handlers.
|
||||
* <p/>
|
||||
* This will try to extract up the specified amount of fluid from any handler,
|
||||
* then insert it into the specified sink handler. If the insertion fails, the
|
||||
* fluid will remain in the source handler.
|
||||
* <p/>
|
||||
* This returns <tt>true</tt> if some fluid was transferred.
|
||||
*/
|
||||
def transferBetweenFluidHandlers(source: IFluidHandler, sourceSide: EnumFacing, sink: IFluidHandler, sinkSide: EnumFacing, limit: Int = FluidContainerRegistry.BUCKET_VOLUME) = {
|
||||
val drained = source.drain(sourceSide, limit, false)
|
||||
val filled = sink.fill(sinkSide, drained, false)
|
||||
sink.fill(sinkSide, source.drain(sourceSide, filled, true), true)
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility method for calling <tt>transferBetweenFluidHandlers</tt> on handlers
|
||||
* in the world.
|
||||
* <p/>
|
||||
* This uses the <tt>fluidHandlerAt</tt> method, and therefore handles special
|
||||
* cases such as fluid blocks.
|
||||
*/
|
||||
def transferBetweenFluidHandlersAt(sourcePos: BlockPosition, sourceSide: EnumFacing, sinkPos: BlockPosition, sinkSide: EnumFacing, limit: Int = FluidContainerRegistry.BUCKET_VOLUME) =
|
||||
fluidHandlerAt(sourcePos).fold(0)(source =>
|
||||
fluidHandlerAt(sinkPos).fold(0)(sink =>
|
||||
transferBetweenFluidHandlers(source, sourceSide, sink, sinkSide, limit)))
|
||||
|
||||
// ----------------------------------------------------------------------- //
|
||||
|
||||
private class GenericBlockWrapper(position: BlockPosition) extends IFluidHandler {
|
||||
override def canDrain(from: EnumFacing, fluid: Fluid): Boolean = currentWrapper.fold(false)(_.canDrain(from, fluid))
|
||||
|
||||
override def drain(from: EnumFacing, resource: FluidStack, doDrain: Boolean): FluidStack = currentWrapper.fold(null: FluidStack)(_.drain(from, resource, doDrain))
|
||||
|
||||
override def drain(from: EnumFacing, maxDrain: Int, doDrain: Boolean): FluidStack = currentWrapper.fold(null: FluidStack)(_.drain(from, maxDrain, doDrain))
|
||||
|
||||
override def canFill(from: EnumFacing, fluid: Fluid): Boolean = currentWrapper.fold(false)(_.canFill(from, fluid))
|
||||
|
||||
override def fill(from: EnumFacing, resource: FluidStack, doFill: Boolean): Int = currentWrapper.fold(0)(_.fill(from, resource, doFill))
|
||||
|
||||
override def getTankInfo(from: EnumFacing): Array[FluidTankInfo] = currentWrapper.fold(Array.empty[FluidTankInfo])(_.getTankInfo(from))
|
||||
|
||||
def currentWrapper = if (position.world.get.blockExists(position)) position.world.get.getBlock(position) match {
|
||||
case block: IFluidBlock => Option(new FluidBlockWrapper(position, block))
|
||||
case block: BlockLiquid if FluidRegistry.lookupFluidForBlock(block) != null => Option(new LiquidBlockWrapper(position, block))
|
||||
case block: Block if block.isAir(position) || block.isReplaceable(position) => Option(new AirBlockWrapper(position, block))
|
||||
case _ => None
|
||||
}
|
||||
else None
|
||||
}
|
||||
|
||||
private trait BlockWrapperBase extends IFluidHandler {
|
||||
protected def uncheckedDrain(doDrain: Boolean): FluidStack
|
||||
|
||||
override def drain(from: EnumFacing, resource: FluidStack, doDrain: Boolean): FluidStack = {
|
||||
val drained = uncheckedDrain(false)
|
||||
if (drained != null && (resource == null || (drained.getFluid == resource.getFluid && drained.amount <= resource.amount))) {
|
||||
uncheckedDrain(doDrain)
|
||||
}
|
||||
else null
|
||||
}
|
||||
|
||||
override def drain(from: EnumFacing, maxDrain: Int, doDrain: Boolean): FluidStack = {
|
||||
val drained = uncheckedDrain(false)
|
||||
if (drained != null && drained.amount <= maxDrain) {
|
||||
uncheckedDrain(doDrain)
|
||||
}
|
||||
else null
|
||||
}
|
||||
|
||||
override def canFill(from: EnumFacing, fluid: Fluid): Boolean = false
|
||||
|
||||
override def fill(from: EnumFacing, resource: FluidStack, doFill: Boolean): Int = 0
|
||||
}
|
||||
|
||||
private class FluidBlockWrapper(val position: BlockPosition, val block: IFluidBlock) extends BlockWrapperBase {
|
||||
final val AssumedCapacity = FluidContainerRegistry.BUCKET_VOLUME
|
||||
|
||||
override def canDrain(from: EnumFacing, fluid: Fluid): Boolean = block.canDrain(position)
|
||||
|
||||
override def getTankInfo(from: EnumFacing): Array[FluidTankInfo] = Array(new FluidTankInfo(new FluidTank(block.getFluid, (block.getFilledPercentage(position) * AssumedCapacity).toInt, AssumedCapacity)))
|
||||
|
||||
override protected def uncheckedDrain(doDrain: Boolean): FluidStack = block.drain(position, doDrain)
|
||||
}
|
||||
|
||||
private class LiquidBlockWrapper(val position: BlockPosition, val block: BlockLiquid) extends BlockWrapperBase {
|
||||
val fluid = FluidRegistry.lookupFluidForBlock(block)
|
||||
|
||||
override def canDrain(from: EnumFacing, fluid: Fluid): Boolean = true
|
||||
|
||||
override def getTankInfo(from: EnumFacing): Array[FluidTankInfo] = Array(new FluidTankInfo(new FluidTank(fluid, FluidContainerRegistry.BUCKET_VOLUME, FluidContainerRegistry.BUCKET_VOLUME)))
|
||||
|
||||
override protected def uncheckedDrain(doDrain: Boolean): FluidStack = {
|
||||
if (doDrain) {
|
||||
position.world.get.setBlockToAir(position)
|
||||
}
|
||||
new FluidStack(fluid, FluidContainerRegistry.BUCKET_VOLUME)
|
||||
}
|
||||
}
|
||||
|
||||
private class AirBlockWrapper(val position: BlockPosition, val block: Block) extends IFluidHandler {
|
||||
override def canDrain(from: EnumFacing, fluid: Fluid): Boolean = false
|
||||
|
||||
override def drain(from: EnumFacing, resource: FluidStack, doDrain: Boolean): FluidStack = null
|
||||
|
||||
override def drain(from: EnumFacing, maxDrain: Int, doDrain: Boolean): FluidStack = null
|
||||
|
||||
override def canFill(from: EnumFacing, fluid: Fluid): Boolean = fluid.canBePlacedInWorld
|
||||
|
||||
override def fill(from: EnumFacing, resource: FluidStack, doFill: Boolean): Int = {
|
||||
if (resource != null && resource.getFluid.canBePlacedInWorld && resource.getFluid.getBlock != null) {
|
||||
if (doFill) {
|
||||
val world = position.world.get
|
||||
world.breakBlock(position)
|
||||
world.setBlock(position, resource.getFluid.getBlock)
|
||||
// This fake neighbor update is required to get stills to start flowing.
|
||||
world.notifyBlockOfNeighborChange(position, world.getBlock(position))
|
||||
}
|
||||
FluidContainerRegistry.BUCKET_VOLUME
|
||||
}
|
||||
else 0
|
||||
}
|
||||
|
||||
override def getTankInfo(from: EnumFacing): Array[FluidTankInfo] = Array.empty
|
||||
}
|
||||
|
||||
}
|
@ -221,6 +221,48 @@ object InventoryUtils {
|
||||
def extractFromInventoryAt(consumer: (ItemStack) => Unit, position: BlockPosition, side: EnumFacing, limit: Int = 64) =
|
||||
inventoryAt(position).exists(extractFromInventory(consumer, _, side, limit))
|
||||
|
||||
/**
|
||||
* Transfers some items between two inventories.
|
||||
* <p/>
|
||||
* This will try to extract up the specified number of items from any inventory,
|
||||
* then insert it into the specified sink inventory. If the insertion fails, the
|
||||
* items will remain in the source inventory.
|
||||
* <p/>
|
||||
* This uses the <tt>extractFromInventory</tt> and <tt>insertIntoInventory</tt>
|
||||
* methods, and therefore handles special cases such as sided inventories and
|
||||
* stack size limits.
|
||||
* <p/>
|
||||
* This returns <tt>true</tt> if at least one item was transferred.
|
||||
*/
|
||||
def transferBetweenInventories(source: IInventory, sourceSide: EnumFacing, sink: IInventory, sinkSide: Option[EnumFacing], limit: Int = 64) =
|
||||
extractFromInventory(
|
||||
insertIntoInventory(_, sink, sinkSide, limit), source, sourceSide, limit)
|
||||
|
||||
/**
|
||||
* Like <tt>transferBetweenInventories</tt> 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)
|
||||
|
||||
/**
|
||||
* Utility method for calling <tt>transferBetweenInventories</tt> on inventories
|
||||
* in the world.
|
||||
*/
|
||||
def transferBetweenInventoriesAt(source: BlockPosition, sourceSide: EnumFacing, sink: BlockPosition, sinkSide: Option[EnumFacing], limit: Int = 64) =
|
||||
inventoryAt(source).exists(sourceInventory =>
|
||||
inventoryAt(sink).exists(sinkInventory =>
|
||||
transferBetweenInventories(sourceInventory, sourceSide, sinkInventory, sinkSide, limit)))
|
||||
|
||||
/**
|
||||
* Utility method for calling <tt>transferBetweenInventoriesSlots</tt> on inventories
|
||||
* in the world.
|
||||
*/
|
||||
def transferBetweenInventoriesSlotsAt(sourcePos: BlockPosition, sourceSide: EnumFacing, sourceSlot: Int, sinkPos: BlockPosition, sinkSide: Option[EnumFacing], sinkSlot: Int, limit: Int = 64) =
|
||||
inventoryAt(sourcePos).exists(sourceInventory =>
|
||||
inventoryAt(sinkPos).exists(sinkInventory =>
|
||||
transferBetweenInventoriesSlots(sourceInventory, sourceSide, sourceSlot, sinkInventory, sinkSide, sinkSlot, limit)))
|
||||
|
||||
/**
|
||||
* Utility method for dropping contents from a single inventory slot into
|
||||
* the world.
|
||||
|
Loading…
x
Reference in New Issue
Block a user