mirror of
https://github.com/MightyPirates/OpenComputers.git
synced 2025-09-09 15:25:56 -04:00
Added transposer block for moving items and fluids between adjacent blocks. Closes #1244.
Also refactored fluid stuffs quite a bit; may lead to slight changes in behavior here and there (e.g. returning empty table for tank info instead of "no tank" errors).
This commit is contained in:
parent
9ab9861ef4
commit
fb816b9da7
@ -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
|
||||
|
@ -9,11 +9,11 @@ import li.cil.oc.Settings
|
||||
import li.cil.oc.api.component
|
||||
import li.cil.oc.api.event.FileSystemAccessEvent
|
||||
import li.cil.oc.client.renderer.PetRenderer
|
||||
import li.cil.oc.common.Loot
|
||||
import li.cil.oc.common.PacketType
|
||||
import li.cil.oc.common.container
|
||||
import li.cil.oc.common.tileentity._
|
||||
import li.cil.oc.common.tileentity.traits._
|
||||
import li.cil.oc.common.Loot
|
||||
import li.cil.oc.common.{PacketHandler => CommonPacketHandler}
|
||||
import li.cil.oc.util.Audio
|
||||
import li.cil.oc.util.ExtendedWorld._
|
||||
@ -79,6 +79,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.
|
||||
}
|
||||
@ -263,6 +264,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.x, t.y, t.z)
|
||||
case _ => // Invalid packet.
|
||||
}
|
||||
|
||||
def onParticleEffect(p: PacketParser) = {
|
||||
val dimension = p.readInt()
|
||||
world(p.player, dimension) match {
|
||||
@ -592,15 +602,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.x, t.y, t.z)
|
||||
case _ => // Invalid packet.
|
||||
}
|
||||
|
||||
def onScreenTouchMode(p: PacketParser) =
|
||||
p.readTileEntity[Screen]() match {
|
||||
case Some(t) => t.invertTouchMode = p.readBoolean()
|
||||
@ -641,6 +642,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()
|
||||
|
@ -61,6 +61,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)
|
||||
@ -70,7 +71,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)
|
||||
|
||||
MinecraftForgeClient.registerItemRenderer(Items.get(Constants.ItemName.Floppy).createItemStack(1).getItem, ItemRenderer)
|
||||
MinecraftForgeClient.registerItemRenderer(Items.get(Constants.BlockName.Print).createItemStack(1).getItem, ItemRenderer)
|
||||
|
@ -104,6 +104,10 @@ object Textures {
|
||||
var iconOn: IIcon = _
|
||||
}
|
||||
|
||||
object Transposer {
|
||||
var iconOn: IIcon = _
|
||||
}
|
||||
|
||||
def init(tm: TextureManager) {
|
||||
tm.bindTexture(fontAntiAliased)
|
||||
tm.bindTexture(fontAliased)
|
||||
|
@ -67,6 +67,13 @@ object BlockRenderer extends ISimpleBlockRenderingHandler {
|
||||
Tessellator.instance.draw()
|
||||
|
||||
RenderState.checkError(getClass.getName + ".renderInventoryBlock: splitter")
|
||||
case _: Transposer =>
|
||||
GL11.glTranslatef(-0.5f, -0.5f, -0.5f)
|
||||
Tessellator.instance.startDrawingQuads()
|
||||
Transposer.render(block, metadata, renderer)
|
||||
Tessellator.instance.draw()
|
||||
|
||||
RenderState.checkError(getClass.getName + ".renderInventoryBlock: transposer")
|
||||
case _ =>
|
||||
block match {
|
||||
case simple: SimpleBlock =>
|
||||
@ -103,7 +110,7 @@ object BlockRenderer extends ISimpleBlockRenderingHandler {
|
||||
RenderState.checkError(getClass.getName + ".renderWorldBlock: assembler")
|
||||
|
||||
true
|
||||
case cable: tileentity.Cable =>
|
||||
case _: tileentity.Cable =>
|
||||
Cable.render(world, x, y, z, block, renderer)
|
||||
|
||||
RenderState.checkError(getClass.getName + ".renderWorldBlock: cable")
|
||||
@ -127,7 +134,7 @@ object BlockRenderer extends ISimpleBlockRenderingHandler {
|
||||
RenderState.checkError(getClass.getName + ".renderWorldBlock: print")
|
||||
|
||||
true
|
||||
case printer: tileentity.Printer =>
|
||||
case _: tileentity.Printer =>
|
||||
Printer.render(block, x, y, z, renderer)
|
||||
|
||||
RenderState.checkError(getClass.getName + ".renderWorldBlock: printer")
|
||||
@ -144,6 +151,12 @@ object BlockRenderer extends ISimpleBlockRenderingHandler {
|
||||
|
||||
RenderState.checkError(getClass.getName + ".renderWorldBlock: splitter")
|
||||
|
||||
true
|
||||
case _: tileentity.Transposer =>
|
||||
Transposer.render(block, x, y, z, renderer)
|
||||
|
||||
RenderState.checkError(getClass.getName + ".renderWorldBlock: transposer")
|
||||
|
||||
true
|
||||
case _ =>
|
||||
val result = renderer.renderStandardBlock(block, x, y, z)
|
||||
@ -158,7 +171,8 @@ object BlockRenderer extends ISimpleBlockRenderingHandler {
|
||||
block.isInstanceOf[Hologram] ||
|
||||
block.isInstanceOf[Printer] ||
|
||||
block.isInstanceOf[Print] ||
|
||||
block.isInstanceOf[NetSplitter]
|
||||
block.isInstanceOf[NetSplitter] ||
|
||||
block.isInstanceOf[Transposer]
|
||||
|
||||
// The texture flip this works around only seems to occur for blocks with custom block renderers?
|
||||
def patchedRenderer(renderer: RenderBlocks, block: Block) =
|
||||
|
124
src/main/scala/li/cil/oc/client/renderer/block/Transposer.scala
Normal file
124
src/main/scala/li/cil/oc/client/renderer/block/Transposer.scala
Normal file
@ -0,0 +1,124 @@
|
||||
package li.cil.oc.client.renderer.block
|
||||
|
||||
import net.minecraft.block.Block
|
||||
import net.minecraft.client.renderer.RenderBlocks
|
||||
|
||||
object Transposer {
|
||||
def render(block: Block, x: Int, y: Int, z: Int, renderer: RenderBlocks) {
|
||||
val previousRenderAllFaces = renderer.renderAllFaces
|
||||
renderer.renderAllFaces = true
|
||||
|
||||
// Corners.
|
||||
renderer.setRenderBounds(0 / 16f, 0 / 16f, 0 / 16f, 7 / 16f, 7 / 16f, 7 / 16f)
|
||||
renderer.renderStandardBlock(block, x, y, z)
|
||||
renderer.setRenderBounds(0 / 16f, 0 / 16f, 9 / 16f, 7 / 16f, 7 / 16f, 16 / 16f)
|
||||
renderer.renderStandardBlock(block, x, y, z)
|
||||
renderer.setRenderBounds(0 / 16f, 9 / 16f, 0 / 16f, 7 / 16f, 16 / 16f, 7 / 16f)
|
||||
renderer.renderStandardBlock(block, x, y, z)
|
||||
renderer.setRenderBounds(0 / 16f, 9 / 16f, 9 / 16f, 7 / 16f, 16 / 16f, 16 / 16f)
|
||||
renderer.renderStandardBlock(block, x, y, z)
|
||||
renderer.setRenderBounds(9 / 16f, 0 / 16f, 0 / 16f, 16 / 16f, 7 / 16f, 7 / 16f)
|
||||
renderer.renderStandardBlock(block, x, y, z)
|
||||
renderer.setRenderBounds(9 / 16f, 0 / 16f, 9 / 16f, 16 / 16f, 7 / 16f, 16 / 16f)
|
||||
renderer.renderStandardBlock(block, x, y, z)
|
||||
renderer.setRenderBounds(9 / 16f, 9 / 16f, 0 / 16f, 16 / 16f, 16 / 16f, 7 / 16f)
|
||||
renderer.renderStandardBlock(block, x, y, z)
|
||||
renderer.setRenderBounds(9 / 16f, 9 / 16f, 9 / 16f, 16 / 16f, 16 / 16f, 16 / 16f)
|
||||
renderer.renderStandardBlock(block, x, y, z)
|
||||
|
||||
// Gaps.
|
||||
renderer.setRenderBounds(0 / 16f, 0 / 16f, 7 / 16f, 5 / 16f, 5 / 16f, 9 / 16f)
|
||||
renderer.renderStandardBlock(block, x, y, z)
|
||||
renderer.setRenderBounds(0 / 16f, 11 / 16f, 7 / 16f, 5 / 16f, 16 / 16f, 9 / 16f)
|
||||
renderer.renderStandardBlock(block, x, y, z)
|
||||
renderer.setRenderBounds(11 / 16f, 0 / 16f, 7 / 16f, 16 / 16f, 5 / 16f, 9 / 16f)
|
||||
renderer.renderStandardBlock(block, x, y, z)
|
||||
renderer.setRenderBounds(11 / 16f, 11 / 16f, 7 / 16f, 16 / 16f, 16 / 16f, 9 / 16f)
|
||||
renderer.renderStandardBlock(block, x, y, z)
|
||||
|
||||
renderer.setRenderBounds(0 / 16f, 7 / 16f, 0 / 16f, 5 / 16f, 9 / 16f, 5 / 16f)
|
||||
renderer.renderStandardBlock(block, x, y, z)
|
||||
renderer.setRenderBounds(0 / 16f, 7 / 16f, 11 / 16f, 5 / 16f, 9 / 16f, 16 / 16f)
|
||||
renderer.renderStandardBlock(block, x, y, z)
|
||||
renderer.setRenderBounds(11 / 16f, 7 / 16f, 0 / 16f, 16 / 16f, 9 / 16f, 5 / 16f)
|
||||
renderer.renderStandardBlock(block, x, y, z)
|
||||
renderer.setRenderBounds(11 / 16f, 7 / 16f, 11 / 16f, 16 / 16f, 9 / 16f, 16 / 16f)
|
||||
renderer.renderStandardBlock(block, x, y, z)
|
||||
|
||||
renderer.setRenderBounds(7 / 16f, 0 / 16f, 0 / 16f, 9 / 16f, 5 / 16f, 5 / 16f)
|
||||
renderer.renderStandardBlock(block, x, y, z)
|
||||
renderer.setRenderBounds(7 / 16f, 0 / 16f, 11 / 16f, 9 / 16f, 5 / 16f, 16 / 16f)
|
||||
renderer.renderStandardBlock(block, x, y, z)
|
||||
renderer.setRenderBounds(7 / 16f, 11 / 16f, 0 / 16f, 9 / 16f, 16 / 16f, 5 / 16f)
|
||||
renderer.renderStandardBlock(block, x, y, z)
|
||||
renderer.setRenderBounds(7 / 16f, 11 / 16f, 11 / 16f, 9 / 16f, 16 / 16f, 16 / 16f)
|
||||
renderer.renderStandardBlock(block, x, y, z)
|
||||
|
||||
// Core.
|
||||
renderer.setRenderBounds(1 / 16f, 1 / 16f, 1 / 16f, 15 / 16f, 15 / 16f, 15 / 16f)
|
||||
renderer.renderStandardBlock(block, x, y, z)
|
||||
|
||||
renderer.renderAllFaces = previousRenderAllFaces
|
||||
}
|
||||
|
||||
def render(block: Block, metadata: Int, renderer: RenderBlocks) {
|
||||
// Corners.
|
||||
renderer.setRenderBounds(0 / 16f, 0 / 16f, 0 / 16f, 7 / 16f, 7 / 16f, 7 / 16f)
|
||||
renderAllFaces(block, metadata, renderer)
|
||||
renderer.setRenderBounds(0 / 16f, 0 / 16f, 9 / 16f, 7 / 16f, 7 / 16f, 16 / 16f)
|
||||
renderAllFaces(block, metadata, renderer)
|
||||
renderer.setRenderBounds(0 / 16f, 9 / 16f, 0 / 16f, 7 / 16f, 16 / 16f, 7 / 16f)
|
||||
renderAllFaces(block, metadata, renderer)
|
||||
renderer.setRenderBounds(0 / 16f, 9 / 16f, 9 / 16f, 7 / 16f, 16 / 16f, 16 / 16f)
|
||||
renderAllFaces(block, metadata, renderer)
|
||||
renderer.setRenderBounds(9 / 16f, 0 / 16f, 0 / 16f, 16 / 16f, 7 / 16f, 7 / 16f)
|
||||
renderAllFaces(block, metadata, renderer)
|
||||
renderer.setRenderBounds(9 / 16f, 0 / 16f, 9 / 16f, 16 / 16f, 7 / 16f, 16 / 16f)
|
||||
renderAllFaces(block, metadata, renderer)
|
||||
renderer.setRenderBounds(9 / 16f, 9 / 16f, 0 / 16f, 16 / 16f, 16 / 16f, 7 / 16f)
|
||||
renderAllFaces(block, metadata, renderer)
|
||||
renderer.setRenderBounds(9 / 16f, 9 / 16f, 9 / 16f, 16 / 16f, 16 / 16f, 16 / 16f)
|
||||
renderAllFaces(block, metadata, renderer)
|
||||
|
||||
// Gaps.
|
||||
renderer.setRenderBounds(0 / 16f, 0 / 16f, 7 / 16f, 5 / 16f, 5 / 16f, 9 / 16f)
|
||||
renderAllFaces(block, metadata, renderer)
|
||||
renderer.setRenderBounds(0 / 16f, 11 / 16f, 7 / 16f, 5 / 16f, 16 / 16f, 9 / 16f)
|
||||
renderAllFaces(block, metadata, renderer)
|
||||
renderer.setRenderBounds(11 / 16f, 0 / 16f, 7 / 16f, 16 / 16f, 5 / 16f, 9 / 16f)
|
||||
renderAllFaces(block, metadata, renderer)
|
||||
renderer.setRenderBounds(11 / 16f, 11 / 16f, 7 / 16f, 16 / 16f, 16 / 16f, 9 / 16f)
|
||||
renderAllFaces(block, metadata, renderer)
|
||||
|
||||
renderer.setRenderBounds(0 / 16f, 7 / 16f, 0 / 16f, 5 / 16f, 9 / 16f, 5 / 16f)
|
||||
renderAllFaces(block, metadata, renderer)
|
||||
renderer.setRenderBounds(0 / 16f, 7 / 16f, 11 / 16f, 5 / 16f, 9 / 16f, 16 / 16f)
|
||||
renderAllFaces(block, metadata, renderer)
|
||||
renderer.setRenderBounds(11 / 16f, 7 / 16f, 0 / 16f, 16 / 16f, 9 / 16f, 5 / 16f)
|
||||
renderAllFaces(block, metadata, renderer)
|
||||
renderer.setRenderBounds(11 / 16f, 7 / 16f, 11 / 16f, 16 / 16f, 9 / 16f, 16 / 16f)
|
||||
renderAllFaces(block, metadata, renderer)
|
||||
|
||||
renderer.setRenderBounds(7 / 16f, 0 / 16f, 0 / 16f, 9 / 16f, 5 / 16f, 5 / 16f)
|
||||
renderAllFaces(block, metadata, renderer)
|
||||
renderer.setRenderBounds(7 / 16f, 0 / 16f, 11 / 16f, 9 / 16f, 5 / 16f, 16 / 16f)
|
||||
renderAllFaces(block, metadata, renderer)
|
||||
renderer.setRenderBounds(7 / 16f, 11 / 16f, 0 / 16f, 9 / 16f, 16 / 16f, 5 / 16f)
|
||||
renderAllFaces(block, metadata, renderer)
|
||||
renderer.setRenderBounds(7 / 16f, 11 / 16f, 11 / 16f, 9 / 16f, 16 / 16f, 16 / 16f)
|
||||
renderAllFaces(block, metadata, renderer)
|
||||
|
||||
// Core.
|
||||
renderer.setRenderBounds(1 / 16f, 1 / 16f, 1 / 16f, 15 / 16f, 15 / 16f, 15 / 16f)
|
||||
renderAllFaces(block, metadata, renderer)
|
||||
}
|
||||
|
||||
private def renderAllFaces(block: Block, metadata: Int, renderer: RenderBlocks): Unit = {
|
||||
BlockRenderer.renderFaceYPos(block, metadata, renderer)
|
||||
BlockRenderer.renderFaceYNeg(block, metadata, renderer)
|
||||
BlockRenderer.renderFaceXPos(block, metadata, renderer)
|
||||
BlockRenderer.renderFaceXNeg(block, metadata, renderer)
|
||||
BlockRenderer.renderFaceZPos(block, metadata, renderer)
|
||||
BlockRenderer.renderFaceZNeg(block, metadata, renderer)
|
||||
}
|
||||
}
|
@ -0,0 +1,77 @@
|
||||
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) {
|
||||
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.instance
|
||||
t.startDrawingQuads()
|
||||
|
||||
val icon = Textures.Transposer.iconOn
|
||||
|
||||
t.addVertexWithUV(0, 1, 0, icon.getMaxU, icon.getMinV)
|
||||
t.addVertexWithUV(1, 1, 0, icon.getMinU, icon.getMinV)
|
||||
t.addVertexWithUV(1, 1, 1, icon.getMinU, icon.getMaxV)
|
||||
t.addVertexWithUV(0, 1, 1, icon.getMaxU, icon.getMaxV)
|
||||
|
||||
t.addVertexWithUV(0, 0, 0, icon.getMaxU, icon.getMaxV)
|
||||
t.addVertexWithUV(0, 0, 1, icon.getMaxU, icon.getMinV)
|
||||
t.addVertexWithUV(1, 0, 1, icon.getMinU, icon.getMinV)
|
||||
t.addVertexWithUV(1, 0, 0, icon.getMinU, icon.getMaxV)
|
||||
|
||||
t.addVertexWithUV(1, 1, 0, icon.getMinU, icon.getMaxV)
|
||||
t.addVertexWithUV(0, 1, 0, icon.getMaxU, icon.getMaxV)
|
||||
t.addVertexWithUV(0, 0, 0, icon.getMaxU, icon.getMinV)
|
||||
t.addVertexWithUV(1, 0, 0, icon.getMinU, icon.getMinV)
|
||||
|
||||
t.addVertexWithUV(0, 1, 1, icon.getMinU, icon.getMaxV)
|
||||
t.addVertexWithUV(1, 1, 1, icon.getMaxU, icon.getMaxV)
|
||||
t.addVertexWithUV(1, 0, 1, icon.getMaxU, icon.getMinV)
|
||||
t.addVertexWithUV(0, 0, 1, icon.getMinU, icon.getMinV)
|
||||
|
||||
t.addVertexWithUV(0, 1, 0, icon.getMinU, icon.getMaxV)
|
||||
t.addVertexWithUV(0, 1, 1, icon.getMaxU, icon.getMaxV)
|
||||
t.addVertexWithUV(0, 0, 1, icon.getMaxU, icon.getMinV)
|
||||
t.addVertexWithUV(0, 0, 0, icon.getMinU, icon.getMinV)
|
||||
|
||||
t.addVertexWithUV(1, 1, 1, icon.getMinU, icon.getMaxV)
|
||||
t.addVertexWithUV(1, 1, 0, icon.getMaxU, icon.getMaxV)
|
||||
t.addVertexWithUV(1, 0, 0, icon.getMaxU, icon.getMinV)
|
||||
t.addVertexWithUV(1, 0, 1, icon.getMinU, icon.getMinV)
|
||||
|
||||
t.draw()
|
||||
|
||||
RenderState.enableLighting()
|
||||
|
||||
GL11.glPopMatrix()
|
||||
GL11.glPopAttrib()
|
||||
}
|
||||
|
||||
RenderState.checkError(getClass.getName + ".renderTileEntityAt: leaving")
|
||||
}
|
||||
}
|
@ -21,6 +21,7 @@ object PacketType extends Enumeration {
|
||||
HologramTranslation,
|
||||
HologramValues,
|
||||
LootDisk,
|
||||
NetSplitterState,
|
||||
ParticleEffect,
|
||||
PetVisibility, // Goes both ways.
|
||||
PowerState,
|
||||
@ -50,11 +51,11 @@ object PacketType extends Enumeration {
|
||||
TextBufferMultiRawSetBackground,
|
||||
TextBufferMultiRawSetForeground,
|
||||
TextBufferPowerChange,
|
||||
NetSplitterState,
|
||||
ScreenTouchMode,
|
||||
ServerPresence,
|
||||
Sound,
|
||||
SoundPattern,
|
||||
TransposerActivity,
|
||||
WaypointLabel, // Goes both ways.
|
||||
|
||||
// Client -> Server
|
||||
|
@ -1,5 +1,7 @@
|
||||
package li.cil.oc.common.block
|
||||
|
||||
import cpw.mods.fml.relauncher.Side
|
||||
import cpw.mods.fml.relauncher.SideOnly
|
||||
import li.cil.oc.Settings
|
||||
import li.cil.oc.client.Textures
|
||||
import li.cil.oc.common.tileentity
|
||||
@ -19,6 +21,7 @@ class Geolyzer extends SimpleBlock {
|
||||
Some("GeolyzerSide")
|
||||
)
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
override def registerBlockIcons(iconRegister: IIconRegister) = {
|
||||
super.registerBlockIcons(iconRegister)
|
||||
Textures.Geolyzer.iconTopOn = iconRegister.registerIcon(Settings.resourceDomain + ":GeolyzerTopOn")
|
||||
|
@ -23,8 +23,8 @@ class NetSplitter extends RedstoneAware {
|
||||
Some("NetSplitterSide")
|
||||
)
|
||||
|
||||
@SideOnly(Side.CLIENT) override
|
||||
def registerBlockIcons(iconRegister: IIconRegister): Unit = {
|
||||
@SideOnly(Side.CLIENT)
|
||||
override def registerBlockIcons(iconRegister: IIconRegister): Unit = {
|
||||
super.registerBlockIcons(iconRegister)
|
||||
Textures.NetSplitter.iconOn = iconRegister.registerIcon(Settings.resourceDomain + ":NetSplitterOn")
|
||||
}
|
||||
|
36
src/main/scala/li/cil/oc/common/block/Transposer.scala
Normal file
36
src/main/scala/li/cil/oc/common/block/Transposer.scala
Normal file
@ -0,0 +1,36 @@
|
||||
package li.cil.oc.common.block
|
||||
|
||||
import cpw.mods.fml.relauncher.Side
|
||||
import cpw.mods.fml.relauncher.SideOnly
|
||||
import li.cil.oc.Settings
|
||||
import li.cil.oc.client.Textures
|
||||
import li.cil.oc.common.tileentity
|
||||
import net.minecraft.client.renderer.texture.IIconRegister
|
||||
import net.minecraft.world.IBlockAccess
|
||||
import net.minecraft.world.World
|
||||
import net.minecraftforge.common.util.ForgeDirection
|
||||
|
||||
class Transposer extends SimpleBlock {
|
||||
override protected def customTextures = Array(
|
||||
Some("TransposerTop"),
|
||||
Some("TransposerTop"),
|
||||
Some("TransposerSide"),
|
||||
Some("TransposerSide"),
|
||||
Some("TransposerSide"),
|
||||
Some("TransposerSide")
|
||||
)
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
override def registerBlockIcons(iconRegister: IIconRegister): Unit = {
|
||||
super.registerBlockIcons(iconRegister)
|
||||
Textures.Transposer.iconOn = iconRegister.registerIcon(Settings.resourceDomain + ":TransposerOn")
|
||||
}
|
||||
|
||||
override def isSideSolid(world: IBlockAccess, x: Int, y: Int, z: Int, side: ForgeDirection): Boolean = false
|
||||
|
||||
// ----------------------------------------------------------------------- //
|
||||
|
||||
override def hasTileEntity(metadata: Int) = true
|
||||
|
||||
override def createTileEntity(world: World, metadata: 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 + "motion_sensor")
|
||||
GameRegistry.registerTileEntity(classOf[tileentity.NetSplitter], Settings.namespace + "netSplitter")
|
||||
GameRegistry.registerTileEntity(classOf[tileentity.PowerConverter], Settings.namespace + "power_converter")
|
||||
GameRegistry.registerTileEntity(classOf[tileentity.PowerDistributor], Settings.namespace + "power_distributor")
|
||||
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)
|
||||
@ -81,5 +82,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)
|
||||
}
|
||||
}
|
@ -234,6 +234,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, name: String, count: Int, velocity: Double, direction: Option[ForgeDirection] = None): Unit = if (count > 0) {
|
||||
val pb = new SimplePacketBuilder(PacketType.ParticleEffect)
|
||||
|
||||
@ -529,16 +539,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)
|
||||
|
||||
@ -619,6 +619,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)
|
||||
|
||||
|
68
src/main/scala/li/cil/oc/server/component/Transposer.scala
Normal file
68
src/main/scala/li/cil/oc/server/component/Transposer.scala
Normal file
@ -0,0 +1,68 @@
|
||||
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.minecraftforge.common.util.ForgeDirection
|
||||
|
||||
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, ForgeDirection.VALID_DIRECTIONS: _*)
|
||||
|
||||
@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.x, blockPos.y, blockPos.z) =>
|
||||
val drained = fluidBlock.drain(world, blockPos.x, blockPos.y, blockPos.z, false)
|
||||
if ((drained != null && drained.amount > 0) && (drained.amount <= amount || amount == 0)) {
|
||||
if (drained.amount <= amount) {
|
||||
val filled = tank.fill(fluidBlock.drain(world, blockPos.x, blockPos.y, blockPos.z, true), true)
|
||||
result(true, filled)
|
||||
}
|
||||
else /* if (amount == 0) */ {
|
||||
result(true, 0)
|
||||
}
|
||||
}
|
||||
else result(Unit, "tank is full")
|
||||
case liquidBlock: BlockLiquid if world.getBlockMetadata(blockPos) == 0 =>
|
||||
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")
|
||||
}
|
||||
case _ => result(Unit, "incompatible or no fluid")
|
||||
}
|
||||
else result(Unit, "incompatible or no fluid")
|
||||
}
|
||||
else result(Unit, "tank is full")
|
||||
case _ => result(Unit, "no tank selected")
|
||||
}
|
||||
}
|
||||
@ -97,49 +56,28 @@ 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")
|
||||
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)
|
||||
if (filled > 0 || amount == 0) {
|
||||
tank.drain(filled, true)
|
||||
result(true, filled)
|
||||
}
|
||||
else result(Unit, "incompatible or no fluid")
|
||||
case _ =>
|
||||
result(Unit, "tank is empty")
|
||||
}
|
||||
case _ => result(Unit, "no space")
|
||||
}
|
||||
}
|
||||
val blockPos = position.offset(facing)
|
||||
if (world.blockExists(blockPos)) world.getTileEntity(blockPos) match {
|
||||
case handler: IFluidHandler =>
|
||||
tank.getFluid match {
|
||||
case stack: FluidStack =>
|
||||
val filled = handler.fill(facing.getOpposite, new FluidStack(stack, amount), true)
|
||||
if (filled > 0 || amount == 0) {
|
||||
tank.drain(filled, true)
|
||||
result(true, filled)
|
||||
}
|
||||
else result(Unit, "incompatible or no fluid")
|
||||
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)
|
||||
}
|
||||
}
|
||||
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.minecraftforge.common.util.ForgeDirection
|
||||
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
|
||||
|
||||
@ -20,4 +21,14 @@ object ExtendedBlock {
|
||||
def getCollisionBoundingBoxFromPool(position: BlockPosition) = block.getCollisionBoundingBoxFromPool(position.world.get, position.x, position.y, position.z)
|
||||
}
|
||||
|
||||
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.x, position.y, position.z, doDrain)
|
||||
|
||||
def canDrain(position: BlockPosition) = block.canDrain(position.world.get, position.x, position.y, position.z)
|
||||
|
||||
def getFilledPercentage(position: BlockPosition) = block.getFilledPercentage(position.world.get, position.x, position.y, position.z)
|
||||
}
|
||||
|
||||
}
|
||||
|
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.minecraftforge.common.util.ForgeDirection
|
||||
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: ForgeDirection, sink: IFluidHandler, sinkSide: ForgeDirection, 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: ForgeDirection, sinkPos: BlockPosition, sinkSide: ForgeDirection, 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: ForgeDirection, fluid: Fluid): Boolean = currentWrapper.fold(false)(_.canDrain(from, fluid))
|
||||
|
||||
override def drain(from: ForgeDirection, resource: FluidStack, doDrain: Boolean): FluidStack = currentWrapper.fold(null: FluidStack)(_.drain(from, resource, doDrain))
|
||||
|
||||
override def drain(from: ForgeDirection, maxDrain: Int, doDrain: Boolean): FluidStack = currentWrapper.fold(null: FluidStack)(_.drain(from, maxDrain, doDrain))
|
||||
|
||||
override def canFill(from: ForgeDirection, fluid: Fluid): Boolean = currentWrapper.fold(false)(_.canFill(from, fluid))
|
||||
|
||||
override def fill(from: ForgeDirection, resource: FluidStack, doFill: Boolean): Int = currentWrapper.fold(0)(_.fill(from, resource, doFill))
|
||||
|
||||
override def getTankInfo(from: ForgeDirection): 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: ForgeDirection, 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: ForgeDirection, maxDrain: Int, doDrain: Boolean): FluidStack = {
|
||||
val drained = uncheckedDrain(false)
|
||||
if (drained != null && drained.amount <= maxDrain) {
|
||||
uncheckedDrain(doDrain)
|
||||
}
|
||||
else null
|
||||
}
|
||||
|
||||
override def canFill(from: ForgeDirection, fluid: Fluid): Boolean = false
|
||||
|
||||
override def fill(from: ForgeDirection, 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: ForgeDirection, fluid: Fluid): Boolean = block.canDrain(position)
|
||||
|
||||
override def getTankInfo(from: ForgeDirection): 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: ForgeDirection, fluid: Fluid): Boolean = true
|
||||
|
||||
override def getTankInfo(from: ForgeDirection): 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: ForgeDirection, fluid: Fluid): Boolean = false
|
||||
|
||||
override def drain(from: ForgeDirection, resource: FluidStack, doDrain: Boolean): FluidStack = null
|
||||
|
||||
override def drain(from: ForgeDirection, maxDrain: Int, doDrain: Boolean): FluidStack = null
|
||||
|
||||
override def canFill(from: ForgeDirection, fluid: Fluid): Boolean = fluid.canBePlacedInWorld
|
||||
|
||||
override def fill(from: ForgeDirection, 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: ForgeDirection): Array[FluidTankInfo] = Array.empty
|
||||
}
|
||||
|
||||
}
|
@ -221,6 +221,48 @@ object InventoryUtils {
|
||||
def extractFromInventoryAt(consumer: (ItemStack) => Unit, position: BlockPosition, side: ForgeDirection, 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: ForgeDirection, sink: IInventory, sinkSide: Option[ForgeDirection], 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: ForgeDirection, sourceSlot: Int, sink: IInventory, sinkSide: Option[ForgeDirection], 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: ForgeDirection, sink: BlockPosition, sinkSide: Option[ForgeDirection], 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: ForgeDirection, sourceSlot: Int, sinkPos: BlockPosition, sinkSide: Option[ForgeDirection], 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