mirror of
https://github.com/MightyPirates/OpenComputers.git
synced 2025-09-10 07:45:05 -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,
|
# Per-byte cost for ECDSA operation is controlled by `complex` value,
|
||||||
# because data is hashed with SHA256 before signing/verifying
|
# because data is hashed with SHA256 before signing/verifying
|
||||||
dataCardAsymmetric: 10.0
|
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
|
# 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.keyboard.name=Keyboard
|
||||||
tile.oc.microcontroller.name=Microcontroller
|
tile.oc.microcontroller.name=Microcontroller
|
||||||
tile.oc.motionSensor.name=Motion Sensor
|
tile.oc.motionSensor.name=Motion Sensor
|
||||||
|
tile.oc.netSplitter.name=Net Splitter
|
||||||
tile.oc.powerConverter.name=Power Converter
|
tile.oc.powerConverter.name=Power Converter
|
||||||
tile.oc.powerDistributor.name=Power Distributor
|
tile.oc.powerDistributor.name=Power Distributor
|
||||||
tile.oc.print.name=3D Print
|
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.screen3.name=Screen (Tier 3)
|
||||||
tile.oc.serverRack.name=Server Rack
|
tile.oc.serverRack.name=Server Rack
|
||||||
tile.oc.switch.name=§cSwitch§7
|
tile.oc.switch.name=§cSwitch§7
|
||||||
tile.oc.netSplitter.name=Net Splitter
|
tile.oc.transposer.name=Transposer
|
||||||
tile.oc.waypoint.name=Waypoint
|
tile.oc.waypoint.name=Waypoint
|
||||||
|
|
||||||
# Items
|
# 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.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.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.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.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.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.
|
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]
|
[yellowDust, "oc:circuitChip3", glass]
|
||||||
[obsidian, yellowDust, obsidian]]
|
[obsidian, yellowDust, obsidian]]
|
||||||
}
|
}
|
||||||
|
transposer {
|
||||||
|
input: [[ingotIron, "oc:inventoryControllerUpgrade", ingotIron]
|
||||||
|
[hopper, bucket, hopper]
|
||||||
|
[ingotIron, "oc:tankControllerUpgrade", ingotIron]]
|
||||||
|
output: 4
|
||||||
|
}
|
||||||
waypoint {
|
waypoint {
|
||||||
input: [[ingotIron, "oc:circuitChip1", ingotIron]
|
input: [[ingotIron, "oc:circuitChip1", ingotIron]
|
||||||
["oc:materialTransistor", "oc:materialInterweb", "oc:materialTransistor"],
|
["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 Keyboard = "keyboard"
|
||||||
final val Microcontroller = "microcontroller"
|
final val Microcontroller = "microcontroller"
|
||||||
final val MotionSensor = "motionSensor"
|
final val MotionSensor = "motionSensor"
|
||||||
|
final val NetSplitter = "netSplitter"
|
||||||
final val PowerConverter = "powerConverter"
|
final val PowerConverter = "powerConverter"
|
||||||
final val PowerDistributor = "powerDistributor"
|
final val PowerDistributor = "powerDistributor"
|
||||||
final val Print = "print"
|
final val Print = "print"
|
||||||
@ -39,7 +40,7 @@ object Constants {
|
|||||||
final val ScreenTier3 = "screen3"
|
final val ScreenTier3 = "screen3"
|
||||||
final val ServerRack = "serverRack"
|
final val ServerRack = "serverRack"
|
||||||
final val Switch = "switch"
|
final val Switch = "switch"
|
||||||
final val NetSplitter = "netSplitter"
|
final val Transposer = "transposer"
|
||||||
final val Waypoint = "waypoint"
|
final val Waypoint = "waypoint"
|
||||||
|
|
||||||
def Case(tier: Int) = ItemUtils.caseNameWithTierSuffix("case", tier)
|
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 dataCardComplex = config.getDouble("power.cost.dataCardComplex") max 0
|
||||||
val dataCardComplexByte = config.getDouble("power.cost.dataCardComplexByte") max 0
|
val dataCardComplexByte = config.getDouble("power.cost.dataCardComplexByte") max 0
|
||||||
val dataCardAsymmetric = config.getDouble("power.cost.dataCardAsymmetric") max 0
|
val dataCardAsymmetric = config.getDouble("power.cost.dataCardAsymmetric") max 0
|
||||||
|
val transposerCost = config.getDouble("power.cost.transposer") max 0
|
||||||
|
|
||||||
// power.rate
|
// power.rate
|
||||||
val accessPointRate = config.getDouble("power.rate.accessPoint") max 0
|
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.component
|
||||||
import li.cil.oc.api.event.FileSystemAccessEvent
|
import li.cil.oc.api.event.FileSystemAccessEvent
|
||||||
import li.cil.oc.client.renderer.PetRenderer
|
import li.cil.oc.client.renderer.PetRenderer
|
||||||
|
import li.cil.oc.common.Loot
|
||||||
import li.cil.oc.common.PacketType
|
import li.cil.oc.common.PacketType
|
||||||
import li.cil.oc.common.container
|
import li.cil.oc.common.container
|
||||||
import li.cil.oc.common.tileentity._
|
import li.cil.oc.common.tileentity._
|
||||||
import li.cil.oc.common.tileentity.traits._
|
import li.cil.oc.common.tileentity.traits._
|
||||||
import li.cil.oc.common.Loot
|
|
||||||
import li.cil.oc.common.{PacketHandler => CommonPacketHandler}
|
import li.cil.oc.common.{PacketHandler => CommonPacketHandler}
|
||||||
import li.cil.oc.util.Audio
|
import li.cil.oc.util.Audio
|
||||||
import li.cil.oc.util.ExtendedWorld._
|
import li.cil.oc.util.ExtendedWorld._
|
||||||
@ -79,6 +79,7 @@ object PacketHandler extends CommonPacketHandler {
|
|||||||
case PacketType.ServerPresence => onServerPresence(p)
|
case PacketType.ServerPresence => onServerPresence(p)
|
||||||
case PacketType.Sound => onSound(p)
|
case PacketType.Sound => onSound(p)
|
||||||
case PacketType.SoundPattern => onSoundPattern(p)
|
case PacketType.SoundPattern => onSoundPattern(p)
|
||||||
|
case PacketType.TransposerActivity => onTransposerActivity(p)
|
||||||
case PacketType.WaypointLabel => onWaypointLabel(p)
|
case PacketType.WaypointLabel => onWaypointLabel(p)
|
||||||
case _ => // Invalid packet.
|
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) = {
|
def onParticleEffect(p: PacketParser) = {
|
||||||
val dimension = p.readInt()
|
val dimension = p.readInt()
|
||||||
world(p.player, dimension) match {
|
world(p.player, dimension) match {
|
||||||
@ -592,15 +602,6 @@ object PacketHandler extends CommonPacketHandler {
|
|||||||
buffer.rawSetForeground(col, row, color)
|
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) =
|
def onScreenTouchMode(p: PacketParser) =
|
||||||
p.readTileEntity[Screen]() match {
|
p.readTileEntity[Screen]() match {
|
||||||
case Some(t) => t.invertTouchMode = p.readBoolean()
|
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) =
|
def onWaypointLabel(p: PacketParser) =
|
||||||
p.readTileEntity[Waypoint]() match {
|
p.readTileEntity[Waypoint]() match {
|
||||||
case Some(waypoint) => waypoint.label = p.readUTF()
|
case Some(waypoint) => waypoint.label = p.readUTF()
|
||||||
|
@ -61,6 +61,7 @@ private[oc] class Proxy extends CommonProxy {
|
|||||||
else
|
else
|
||||||
ClientRegistry.bindTileEntitySpecialRenderer(classOf[tileentity.Hologram], HologramRendererFallback)
|
ClientRegistry.bindTileEntitySpecialRenderer(classOf[tileentity.Hologram], HologramRendererFallback)
|
||||||
ClientRegistry.bindTileEntitySpecialRenderer(classOf[tileentity.Microcontroller], MicrocontrollerRenderer)
|
ClientRegistry.bindTileEntitySpecialRenderer(classOf[tileentity.Microcontroller], MicrocontrollerRenderer)
|
||||||
|
ClientRegistry.bindTileEntitySpecialRenderer(classOf[tileentity.NetSplitter], NetSplitterRenderer)
|
||||||
ClientRegistry.bindTileEntitySpecialRenderer(classOf[tileentity.PowerDistributor], PowerDistributorRenderer)
|
ClientRegistry.bindTileEntitySpecialRenderer(classOf[tileentity.PowerDistributor], PowerDistributorRenderer)
|
||||||
ClientRegistry.bindTileEntitySpecialRenderer(classOf[tileentity.Printer], PrinterRenderer)
|
ClientRegistry.bindTileEntitySpecialRenderer(classOf[tileentity.Printer], PrinterRenderer)
|
||||||
ClientRegistry.bindTileEntitySpecialRenderer(classOf[tileentity.Raid], RaidRenderer)
|
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.Relay], SwitchRenderer)
|
||||||
ClientRegistry.bindTileEntitySpecialRenderer(classOf[tileentity.RobotProxy], RobotRenderer)
|
ClientRegistry.bindTileEntitySpecialRenderer(classOf[tileentity.RobotProxy], RobotRenderer)
|
||||||
ClientRegistry.bindTileEntitySpecialRenderer(classOf[tileentity.Screen], ScreenRenderer)
|
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.ItemName.Floppy).createItemStack(1).getItem, ItemRenderer)
|
||||||
MinecraftForgeClient.registerItemRenderer(Items.get(Constants.BlockName.Print).createItemStack(1).getItem, ItemRenderer)
|
MinecraftForgeClient.registerItemRenderer(Items.get(Constants.BlockName.Print).createItemStack(1).getItem, ItemRenderer)
|
||||||
|
@ -104,6 +104,10 @@ object Textures {
|
|||||||
var iconOn: IIcon = _
|
var iconOn: IIcon = _
|
||||||
}
|
}
|
||||||
|
|
||||||
|
object Transposer {
|
||||||
|
var iconOn: IIcon = _
|
||||||
|
}
|
||||||
|
|
||||||
def init(tm: TextureManager) {
|
def init(tm: TextureManager) {
|
||||||
tm.bindTexture(fontAntiAliased)
|
tm.bindTexture(fontAntiAliased)
|
||||||
tm.bindTexture(fontAliased)
|
tm.bindTexture(fontAliased)
|
||||||
|
@ -67,6 +67,13 @@ object BlockRenderer extends ISimpleBlockRenderingHandler {
|
|||||||
Tessellator.instance.draw()
|
Tessellator.instance.draw()
|
||||||
|
|
||||||
RenderState.checkError(getClass.getName + ".renderInventoryBlock: splitter")
|
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 _ =>
|
case _ =>
|
||||||
block match {
|
block match {
|
||||||
case simple: SimpleBlock =>
|
case simple: SimpleBlock =>
|
||||||
@ -103,7 +110,7 @@ object BlockRenderer extends ISimpleBlockRenderingHandler {
|
|||||||
RenderState.checkError(getClass.getName + ".renderWorldBlock: assembler")
|
RenderState.checkError(getClass.getName + ".renderWorldBlock: assembler")
|
||||||
|
|
||||||
true
|
true
|
||||||
case cable: tileentity.Cable =>
|
case _: tileentity.Cable =>
|
||||||
Cable.render(world, x, y, z, block, renderer)
|
Cable.render(world, x, y, z, block, renderer)
|
||||||
|
|
||||||
RenderState.checkError(getClass.getName + ".renderWorldBlock: cable")
|
RenderState.checkError(getClass.getName + ".renderWorldBlock: cable")
|
||||||
@ -127,7 +134,7 @@ object BlockRenderer extends ISimpleBlockRenderingHandler {
|
|||||||
RenderState.checkError(getClass.getName + ".renderWorldBlock: print")
|
RenderState.checkError(getClass.getName + ".renderWorldBlock: print")
|
||||||
|
|
||||||
true
|
true
|
||||||
case printer: tileentity.Printer =>
|
case _: tileentity.Printer =>
|
||||||
Printer.render(block, x, y, z, renderer)
|
Printer.render(block, x, y, z, renderer)
|
||||||
|
|
||||||
RenderState.checkError(getClass.getName + ".renderWorldBlock: printer")
|
RenderState.checkError(getClass.getName + ".renderWorldBlock: printer")
|
||||||
@ -144,6 +151,12 @@ object BlockRenderer extends ISimpleBlockRenderingHandler {
|
|||||||
|
|
||||||
RenderState.checkError(getClass.getName + ".renderWorldBlock: splitter")
|
RenderState.checkError(getClass.getName + ".renderWorldBlock: splitter")
|
||||||
|
|
||||||
|
true
|
||||||
|
case _: tileentity.Transposer =>
|
||||||
|
Transposer.render(block, x, y, z, renderer)
|
||||||
|
|
||||||
|
RenderState.checkError(getClass.getName + ".renderWorldBlock: transposer")
|
||||||
|
|
||||||
true
|
true
|
||||||
case _ =>
|
case _ =>
|
||||||
val result = renderer.renderStandardBlock(block, x, y, z)
|
val result = renderer.renderStandardBlock(block, x, y, z)
|
||||||
@ -158,7 +171,8 @@ object BlockRenderer extends ISimpleBlockRenderingHandler {
|
|||||||
block.isInstanceOf[Hologram] ||
|
block.isInstanceOf[Hologram] ||
|
||||||
block.isInstanceOf[Printer] ||
|
block.isInstanceOf[Printer] ||
|
||||||
block.isInstanceOf[Print] ||
|
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?
|
// The texture flip this works around only seems to occur for blocks with custom block renderers?
|
||||||
def patchedRenderer(renderer: RenderBlocks, block: Block) =
|
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,
|
HologramTranslation,
|
||||||
HologramValues,
|
HologramValues,
|
||||||
LootDisk,
|
LootDisk,
|
||||||
|
NetSplitterState,
|
||||||
ParticleEffect,
|
ParticleEffect,
|
||||||
PetVisibility, // Goes both ways.
|
PetVisibility, // Goes both ways.
|
||||||
PowerState,
|
PowerState,
|
||||||
@ -50,11 +51,11 @@ object PacketType extends Enumeration {
|
|||||||
TextBufferMultiRawSetBackground,
|
TextBufferMultiRawSetBackground,
|
||||||
TextBufferMultiRawSetForeground,
|
TextBufferMultiRawSetForeground,
|
||||||
TextBufferPowerChange,
|
TextBufferPowerChange,
|
||||||
NetSplitterState,
|
|
||||||
ScreenTouchMode,
|
ScreenTouchMode,
|
||||||
ServerPresence,
|
ServerPresence,
|
||||||
Sound,
|
Sound,
|
||||||
SoundPattern,
|
SoundPattern,
|
||||||
|
TransposerActivity,
|
||||||
WaypointLabel, // Goes both ways.
|
WaypointLabel, // Goes both ways.
|
||||||
|
|
||||||
// Client -> Server
|
// Client -> Server
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
package li.cil.oc.common.block
|
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.Settings
|
||||||
import li.cil.oc.client.Textures
|
import li.cil.oc.client.Textures
|
||||||
import li.cil.oc.common.tileentity
|
import li.cil.oc.common.tileentity
|
||||||
@ -19,6 +21,7 @@ class Geolyzer extends SimpleBlock {
|
|||||||
Some("GeolyzerSide")
|
Some("GeolyzerSide")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@SideOnly(Side.CLIENT)
|
||||||
override def registerBlockIcons(iconRegister: IIconRegister) = {
|
override def registerBlockIcons(iconRegister: IIconRegister) = {
|
||||||
super.registerBlockIcons(iconRegister)
|
super.registerBlockIcons(iconRegister)
|
||||||
Textures.Geolyzer.iconTopOn = iconRegister.registerIcon(Settings.resourceDomain + ":GeolyzerTopOn")
|
Textures.Geolyzer.iconTopOn = iconRegister.registerIcon(Settings.resourceDomain + ":GeolyzerTopOn")
|
||||||
|
@ -23,8 +23,8 @@ class NetSplitter extends RedstoneAware {
|
|||||||
Some("NetSplitterSide")
|
Some("NetSplitterSide")
|
||||||
)
|
)
|
||||||
|
|
||||||
@SideOnly(Side.CLIENT) override
|
@SideOnly(Side.CLIENT)
|
||||||
def registerBlockIcons(iconRegister: IIconRegister): Unit = {
|
override def registerBlockIcons(iconRegister: IIconRegister): Unit = {
|
||||||
super.registerBlockIcons(iconRegister)
|
super.registerBlockIcons(iconRegister)
|
||||||
Textures.NetSplitter.iconOn = iconRegister.registerIcon(Settings.resourceDomain + ":NetSplitterOn")
|
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.Geolyzer], Settings.namespace + "geolyzer")
|
||||||
GameRegistry.registerTileEntity(classOf[tileentity.Microcontroller], Settings.namespace + "microcontroller")
|
GameRegistry.registerTileEntity(classOf[tileentity.Microcontroller], Settings.namespace + "microcontroller")
|
||||||
GameRegistry.registerTileEntity(classOf[tileentity.MotionSensor], Settings.namespace + "motion_sensor")
|
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.PowerConverter], Settings.namespace + "power_converter")
|
||||||
GameRegistry.registerTileEntity(classOf[tileentity.PowerDistributor], Settings.namespace + "power_distributor")
|
GameRegistry.registerTileEntity(classOf[tileentity.PowerDistributor], Settings.namespace + "power_distributor")
|
||||||
GameRegistry.registerTileEntity(classOf[tileentity.Print], Settings.namespace + "print")
|
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.Switch], Settings.namespace + "switch")
|
||||||
GameRegistry.registerTileEntity(classOf[tileentity.Screen], Settings.namespace + "screen")
|
GameRegistry.registerTileEntity(classOf[tileentity.Screen], Settings.namespace + "screen")
|
||||||
GameRegistry.registerTileEntity(classOf[tileentity.ServerRack], Settings.namespace + "serverRack")
|
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")
|
GameRegistry.registerTileEntity(classOf[tileentity.Waypoint], Settings.namespace + "waypoint")
|
||||||
|
|
||||||
Items.registerBlock(new AccessPoint(), Constants.BlockName.AccessPoint)
|
Items.registerBlock(new AccessPoint(), Constants.BlockName.AccessPoint)
|
||||||
@ -81,5 +82,8 @@ object Blocks {
|
|||||||
|
|
||||||
// v1.5.14
|
// v1.5.14
|
||||||
Recipes.addBlock(new NetSplitter(), Constants.BlockName.NetSplitter, "oc:netSplitter")
|
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) {
|
def sendParticleEffect(position: BlockPosition, name: String, count: Int, velocity: Double, direction: Option[ForgeDirection] = None): Unit = if (count > 0) {
|
||||||
val pb = new SimplePacketBuilder(PacketType.ParticleEffect)
|
val pb = new SimplePacketBuilder(PacketType.ParticleEffect)
|
||||||
|
|
||||||
@ -529,16 +539,6 @@ object PacketSender {
|
|||||||
pb.sendToPlayersNearHost(host)
|
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) {
|
def sendScreenTouchMode(t: tileentity.Screen, value: Boolean) {
|
||||||
val pb = new SimplePacketBuilder(PacketType.ScreenTouchMode)
|
val pb = new SimplePacketBuilder(PacketType.ScreenTouchMode)
|
||||||
|
|
||||||
@ -619,6 +619,14 @@ object PacketSender {
|
|||||||
pb.sendToNearbyPlayers(world, x, y, z, Option(32))
|
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 = {
|
def sendWaypointLabel(t: Waypoint): Unit = {
|
||||||
val pb = new SimplePacketBuilder(PacketType.WaypointLabel)
|
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.Callback
|
||||||
import li.cil.oc.api.machine.Context
|
import li.cil.oc.api.machine.Context
|
||||||
import li.cil.oc.util.ExtendedArguments._
|
import li.cil.oc.util.ExtendedArguments._
|
||||||
import li.cil.oc.util.ExtendedBlock._
|
import li.cil.oc.util.FluidUtils
|
||||||
import li.cil.oc.util.ExtendedWorld._
|
|
||||||
import li.cil.oc.util.ResultWrapper.result
|
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.FluidStack
|
||||||
import net.minecraftforge.fluids.IFluidBlock
|
|
||||||
import net.minecraftforge.fluids.IFluidHandler
|
|
||||||
|
|
||||||
trait TankWorldControl extends TankAware with WorldAware with SideRestricted {
|
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.")
|
@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)
|
val side = checkSideForAction(args, 0)
|
||||||
fluidInTank(selectedTank) match {
|
fluidInTank(selectedTank) match {
|
||||||
case Some(stack) =>
|
case Some(stack) =>
|
||||||
val blockPos = position.offset(side)
|
FluidUtils.fluidHandlerAt(position.offset(side)) match {
|
||||||
if (world.blockExists(blockPos)) world.getTileEntity(blockPos) match {
|
case Some(handler) => result(Option(handler.getTankInfo(side.getOpposite)).exists(_.exists(other => stack.isFluidEqual(other.fluid))))
|
||||||
case handler: IFluidHandler =>
|
case _ => result(false)
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
else result(false)
|
|
||||||
case _ => 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.")
|
@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] = {
|
def drain(context: Context, args: Arguments): Array[AnyRef] = {
|
||||||
val facing = checkSideForAction(args, 0)
|
val facing = checkSideForAction(args, 0)
|
||||||
val count = args.optFluidCount(1)
|
val count = args.optFluidCount(1) max 0
|
||||||
getTank(selectedTank) match {
|
getTank(selectedTank) match {
|
||||||
case Some(tank) =>
|
case Some(tank) =>
|
||||||
val space = tank.getCapacity - tank.getFluidAmount
|
val space = tank.getCapacity - tank.getFluidAmount
|
||||||
val amount = math.min(count, space)
|
val amount = math.min(count, space)
|
||||||
if (count > 0 && amount == 0) {
|
if (count < 1 || amount > 0) {
|
||||||
result(Unit, "tank is full")
|
FluidUtils.fluidHandlerAt(position.offset(facing)) match {
|
||||||
}
|
case Some(handler) =>
|
||||||
else {
|
|
||||||
val blockPos = position.offset(facing)
|
|
||||||
if (world.blockExists(blockPos)) world.getTileEntity(blockPos) match {
|
|
||||||
case handler: IFluidHandler =>
|
|
||||||
tank.getFluid match {
|
tank.getFluid match {
|
||||||
case stack: FluidStack =>
|
case stack: FluidStack =>
|
||||||
val drained = handler.drain(facing.getOpposite, new FluidStack(stack, amount), true)
|
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)
|
val transferred = tank.fill(handler.drain(facing.getOpposite, amount, true), true)
|
||||||
result(transferred > 0, transferred)
|
result(transferred > 0, transferred)
|
||||||
}
|
}
|
||||||
case _ => world.getBlock(blockPos) match {
|
case _ => result(Unit, "incompatible or no fluid")
|
||||||
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")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else result(Unit, "incompatible or no fluid")
|
|
||||||
}
|
}
|
||||||
|
else result(Unit, "tank is full")
|
||||||
case _ => result(Unit, "no tank selected")
|
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.")
|
@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] = {
|
def fill(context: Context, args: Arguments): Array[AnyRef] = {
|
||||||
val facing = checkSideForAction(args, 0)
|
val facing = checkSideForAction(args, 0)
|
||||||
val count = args.optFluidCount(1)
|
val count = args.optFluidCount(1) max 0
|
||||||
getTank(selectedTank) match {
|
getTank(selectedTank) match {
|
||||||
case Some(tank) =>
|
case Some(tank) =>
|
||||||
val amount = math.min(count, tank.getFluidAmount)
|
val amount = math.min(count, tank.getFluidAmount)
|
||||||
if (count > 0 && amount == 0) {
|
if (count < 1 || amount > 0) {
|
||||||
result(Unit, "tank is empty")
|
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)
|
else result(Unit, "tank is empty")
|
||||||
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")
|
|
||||||
case _ => result(Unit, "no tank selected")
|
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.Callback
|
||||||
import li.cil.oc.api.machine.Context
|
import li.cil.oc.api.machine.Context
|
||||||
import li.cil.oc.server.component.result
|
import li.cil.oc.server.component.result
|
||||||
import li.cil.oc.util.ExtendedWorld._
|
import li.cil.oc.util.FluidUtils
|
||||||
import net.minecraftforge.fluids.IFluidHandler
|
|
||||||
|
|
||||||
trait WorldTankAnalytics extends WorldAware with SideRestricted {
|
trait WorldTankAnalytics extends WorldAware with SideRestricted {
|
||||||
@Callback(doc = """function(side:number):number -- Get the amount of fluid in the tank on the specified side.""")
|
@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] = {
|
def getTankLevel(context: Context, args: Arguments): Array[AnyRef] = {
|
||||||
val facing = checkSideForAction(args, 0)
|
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)
|
result(handler.getTankInfo(facing.getOpposite).map(info => Option(info.fluid).fold(0)(_.amount)).sum)
|
||||||
case _ => result(Unit, "no tank")
|
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.""")
|
@Callback(doc = """function(side:number):number -- Get the capacity of the tank on the specified side.""")
|
||||||
def getTankCapacity(context: Context, args: Arguments): Array[AnyRef] = {
|
def getTankCapacity(context: Context, args: Arguments): Array[AnyRef] = {
|
||||||
val facing = checkSideForAction(args, 0)
|
val facing = checkSideForAction(args, 0)
|
||||||
world.getTileEntity(position.offset(facing)) match {
|
FluidUtils.fluidHandlerAt(position.offset(facing)) match {
|
||||||
case handler: IFluidHandler =>
|
case Some(handler) =>
|
||||||
result(handler.getTankInfo(facing.getOpposite).map(_.capacity).foldLeft(0)((max, capacity) => math.max(max, capacity)))
|
result(handler.getTankInfo(facing.getOpposite).map(_.capacity).foldLeft(0)((max, capacity) => math.max(max, capacity)))
|
||||||
case _ => result(Unit, "no tank")
|
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.""")
|
@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) {
|
def getFluidInTank(context: Context, args: Arguments): Array[AnyRef] = if (Settings.get.allowItemStackInspection) {
|
||||||
val facing = checkSideForAction(args, 0)
|
val facing = checkSideForAction(args, 0)
|
||||||
world.getTileEntity(position.offset(facing)) match {
|
FluidUtils.fluidHandlerAt(position.offset(facing)) match {
|
||||||
case handler: IFluidHandler =>
|
case Some(handler) =>
|
||||||
result(handler.getTankInfo(facing.getOpposite))
|
result(handler.getTankInfo(facing.getOpposite))
|
||||||
case _ => result(Unit, "no tank")
|
case _ => result(Unit, "no tank")
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ import li.cil.oc.api.internal.MultiTank
|
|||||||
import li.cil.oc.api.machine.Arguments
|
import li.cil.oc.api.machine.Arguments
|
||||||
import net.minecraft.inventory.IInventory
|
import net.minecraft.inventory.IInventory
|
||||||
import net.minecraftforge.common.util.ForgeDirection
|
import net.minecraftforge.common.util.ForgeDirection
|
||||||
|
import net.minecraftforge.fluids.FluidContainerRegistry
|
||||||
|
|
||||||
import scala.language.implicitConversions
|
import scala.language.implicitConversions
|
||||||
|
|
||||||
@ -16,7 +17,7 @@ object ExtendedArguments {
|
|||||||
if (!isDefined(index) || !hasValue(index)) default
|
if (!isDefined(index) || !hasValue(index)) default
|
||||||
else math.max(0, math.min(64, args.checkInteger(index)))
|
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
|
if (!isDefined(index) || !hasValue(index)) default
|
||||||
else math.max(0, args.checkInteger(index))
|
else math.max(0, args.checkInteger(index))
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package li.cil.oc.util
|
package li.cil.oc.util
|
||||||
|
|
||||||
import net.minecraft.block.Block
|
import net.minecraft.block.Block
|
||||||
|
import net.minecraftforge.fluids.IFluidBlock
|
||||||
|
|
||||||
import scala.language.implicitConversions
|
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)
|
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) =
|
def extractFromInventoryAt(consumer: (ItemStack) => Unit, position: BlockPosition, side: ForgeDirection, limit: Int = 64) =
|
||||||
inventoryAt(position).exists(extractFromInventory(consumer, _, side, limit))
|
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
|
* Utility method for dropping contents from a single inventory slot into
|
||||||
* the world.
|
* the world.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user