Merge branch '3d-printer' into master-MC1.7.10

Conflicts:
	src/main/resources/application.conf
	src/main/scala/li/cil/oc/Settings.scala
This commit is contained in:
Florian Nücke 2015-03-24 17:16:42 +01:00
commit 6ccf328752
64 changed files with 1569 additions and 212 deletions

Binary file not shown.

Binary file not shown.

View File

@ -509,6 +509,10 @@ opencomputers {
# controls the speed at which items are disassembled, basically.
disassemblerTickAmount: 25
# The amount of energy the printer can apply per tick. This controls
# the speed at which prints are completed, basically.
printerTickAmount: 1
# If you don't want OpenComputers to accept power from one or more of the
# supported power mods, for example because it doesn't suit the vision
# of your mod pack, you can disable support for them here. To stop
@ -729,6 +733,9 @@ opencomputers {
# Energy it costs to re-program an EEPROM. This is deliberately
# expensive, to discourage frequent re-writing of EEPROMs.
eepromWrite: 50
# How much energy is required for a single 3D print.
printerModel: 25
}
# The rate at which different blocks accept external power. All of these
@ -1022,6 +1029,12 @@ opencomputers {
# avoid issues with computers timing out, but can also lead to higher
# server load. AGAIN, USE WITH CARE!
threadPriority: -1
# The maximum number of shape for a state of a 3D print allowed. This is
# for the individual states (off and on), so it is possible to have up to
# this many shapes *per state* (the reasoning being that only one state
# will ever be visible at a time).
maxPrinterShapes: 16
}
# Settings for mod integration (the mod previously known as OpenComponents).

View File

@ -23,6 +23,8 @@ tile.oc.microcontroller.name=Microcontroller
tile.oc.motionSensor.name=Motion Sensor
tile.oc.powerConverter.name=Power Converter
tile.oc.powerDistributor.name=Power Distributor
tile.oc.print.name=3D Print
tile.oc.printer.name=3D Printer
tile.oc.raid.name=Raid
tile.oc.redstone.name=Redstone I/O
tile.oc.robot.name=Robot
@ -42,6 +44,7 @@ item.oc.appengTunnel.name=P2P Tunnel - OpenComputers
item.oc.ArrowKeys.name=Arrow Keys
item.oc.ButtonGroup.name=Button Group
item.oc.CardBase.name=Card Base
item.oc.Chamelium.name=Chamelium
item.oc.CircuitBoard.name=Circuit Board
item.oc.ControlUnit.name=Control Unit (CU)
item.oc.ComponentBus0.name=Component Bus (Tier 1)
@ -66,6 +69,8 @@ item.oc.GraphicsCard2.name=Graphics Card (Tier 3)
item.oc.HardDiskDrive0.name=Hard Disk Drive (Tier 1)
item.oc.HardDiskDrive1.name=Hard Disk Drive (Tier 2)
item.oc.HardDiskDrive2.name=Hard Disk Drive (Tier 3)
item.oc.InkCartridge.name=Ink Cartidge
item.oc.InkCartridgeEmpty.name=Ink Cartidge (Empty)
item.oc.InternetCard.name=Internet Card
item.oc.Interweb.name=Interweb
item.oc.IronNugget.name=Iron Nugget
@ -98,6 +103,7 @@ item.oc.TabletCase0.name=Tablet Case (Tier 1)
item.oc.TabletCase1.name=Tablet Case (Tier 2)
item.oc.TabletCase3.name=Tablet Case (Creative)
item.oc.Terminal.name=Remote Terminal
item.oc.TexturePicker.name=Texture Picker
item.oc.Transistor.name=Transistor
item.oc.UpgradeAngel.name=Angel Upgrade
item.oc.UpgradeBattery0.name=Battery Upgrade (Tier 1)
@ -164,6 +170,7 @@ oc:gui.Chat.NewVersion=A new version is available: %s
oc:gui.Chat.WarningFingerprint=§cWARNING§f - fingerprint mismatch! Expected '§a%s§f' but got '§e%s§f'. Unless you are a modder and are running the deobfuscated version of the mod, it is §lstrongly§f recommended to redownload OpenComputers, because the JAR you are using may have been tampered with.
oc:gui.Chat.WarningLuaFallback=Native Lua libraries are not available, computers will not be able to persist their state. They will reboot on chunk reloads.
oc:gui.Chat.WarningPower=No supported power providing mod available. Computers, screens and all other components will §lnot§f require energy. Install one of the following mods to enable power: BuildCraft, Electrical Age, IndustrialCraft2, Mekanism or Thermal Expansion. Disable power in the config to suppress this warning.
oc:gui.Chat.TextureName=§7Texture name is §a%s§f.
oc:gui.Chat.WarningProjectRed=You are using a version of Project: Red that is incompatible with OpenComputers. Try updating your version of Project: Red.
oc:gui.Error.ComponentOverflow=Too many components connected to the computer.
oc:gui.Error.InternalError=Internal error, please see the log file. This is probably a bug.
@ -197,6 +204,7 @@ oc:container.Charger=Charger
oc:container.Case=Computer
oc:container.Disassembler=Disassembler
oc:container.DiskDrive=Disk Drive
oc:container.Printer=Printer
oc:container.Raid=Raid
oc:container.Server=Server
oc:container.ServerRack=Server Rack
@ -219,6 +227,7 @@ oc:tooltip.Cable=A cheap way of connecting blocks.
oc:tooltip.Capacitor=Stores energy for later use. Can be filled and emptied very quickly.
oc:tooltip.CardBase=As the name indicates, this is the basic building block for all expansion cards.
oc:tooltip.Case=The Computer Case is the basic building block for computers and houses the computer's §fextension cards§7, §fRAM§7 and §fhard disks§7.[nl] Slots: §f%s§7
oc:tooltip.Chamelium=Raw material for 3D prints. Do not swallow. Not that you could even if you wanted to.
oc:tooltip.Charger=Transfers energy from capacitors into adjacent robots and drones. The transfer rate depends on the incoming §fredstone signal§7, where no signal means don't charge devices, and maximum strength means charge at full speed. Can also be used to charge tablets and access hard drives in tablets.
oc:tooltip.CircuitBoard=Now we're getting somewhere. Can be etched to obtain a printed circuit board.
oc:tooltip.ControlUnit=This is the unit that... controls... stuff. You need it to build a CPU. So yeah, totally important.
@ -237,6 +246,8 @@ oc:tooltip.DroneCase=This casing is used to build Drones in the assembler. It ha
oc:tooltip.EEPROM=Small, programmable storage that contains the BIOS computers use to boot.
oc:tooltip.Geolyzer=Allows scanning the surrounding area's blocks' hardness. This information can be useful for generating holograms of the area or for detecting ores.
oc:tooltip.GraphicsCard=Used to change what's displayed on screens.[nl] Maximum resolution: §f%sx%s§7[nl] Maximum color depth: §f%s§7[nl] Operations/tick: §f%s§7
oc:tooltip.InkCartridge=Used to refill ink in 3D printers. For mysterious reasons it does not have to remain in the printer.
oc:tooltip.InkCartridgeEmpty=This ink cartridge has been sucked dry. Refill it using dyes. Or throw it away. See if I care.
oc:tooltip.InternetCard=This card allows making HTTP requests and using real TCP sockets.
oc:tooltip.Interweb=Congratulations, you win one (1) interweb. You can connect to it using an Internet Card. Beware: don't feed the trolls.
oc:tooltip.IronNugget=A nugget made of iron, that's why it's called an Iron Nugget, duh...
@ -262,6 +273,7 @@ oc:tooltip.PowerConverter.ThermalExpansion=§fThermal Expansion RF§7: §a%s:%s
oc:tooltip.PowerConverter.ResonantEngine=§fResonant Engine Coulombs§7: §a%s:%s§7
oc:tooltip.PowerConverter=Converts power from other mods to the internal energy type. Conversion rates:
oc:tooltip.PowerDistributor=Distributes energy among different networks. This is useful for sharing power fed into your system from one converter among different sub-networks that should remain separate.
oc:tooltip.Printer=Allows printing blocks of user-defined shapes using Chamelium and Ink Cartridges. Must be configured using a computer. Keep away from small children. Because reasons.
oc:tooltip.PrintedCircuitBoard=The basic building block for expansion cards and memory and such.
oc:tooltip.Present=... for your troubles. Open this present for a chance to receive some §kphat lewt§7![nl]§8Craft OpenComputers items when the time is right for a chance to receive a present.§7
oc:tooltip.Raid=Allows combining three hard drives into one larger file system that can be used by all connected computers.
@ -285,6 +297,7 @@ oc:tooltip.Switch=Allows connecting different networks to each other. Only netwo
oc:tooltip.Tablet=A tablet computer, for fresh Lua on the go. Can be forced to shut down by sneak-activating it.
oc:tooltip.TabletCase=Basic case for tablets. Place it into the assembler to add in components and create a tablet computer.
oc:tooltip.Terminal=Allows controlling a server remotely, as long as you are in range of it. Acts like a portable screen and keyboard. Shift-right-click a server in a server rack to bind the terminal to it.
oc:tooltip.TexturePicker=This tool allows showing a string describing a block's surface, for use in 3D printer shape definitions. Totally not texture names, nope. No sir.
oc:tooltip.Tier=§8Tier %s
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.

View File

@ -6,6 +6,11 @@ analyzer {
["oc:materialTransistor", nuggetGold, ""]
["oc:materialCircuitBoardPrinted", nuggetGold, ""]]
}
texturePicker {
input: [[dyeBlack, dyeRed, dyeGreen]
[dyeBlue, "oc:analyzer", dyePurple]
[dyeYellow, dyeMagenta, dyeWhite]]
}
droneCase1 {
input: [[{block="minecraft:end_stone"}, compass, {block="minecraft:end_stone"}]
["oc:circuitChip1", "oc:microcontrollerCase1", "oc:circuitChip1"]
@ -318,6 +323,21 @@ disk {
[nuggetIron, "", nuggetIron]
["", nuggetIron, ""]]
}
chamelium {
input: [[gravel, redstone, gravel],
[redstone, {item=coal, subID=1}, redstone],
[gravel, water_bucket, gravel]]
output: 16
}
inkCartridgeEmpty {
input: [[nuggetIron, dispenser, nuggetIron],
["oc:materialTransistor", bucket, "oc:materialTransistor"],
[nuggetIron, "oc:materialCircuitBoardPrinted", nuggetIron]]
}
inkCartridge {
type: shapeless
input: [dyeCyan, dyeMagenta, dyeYellow, dyeBlack, "oc:inkCartridgeEmpty"]
}
buttonGroup {
input: [[button, button, button]

Binary file not shown.

After

Width:  |  Height:  |  Size: 509 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 365 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 634 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 189 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 313 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 645 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 636 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 346 B

View File

@ -84,6 +84,8 @@ object Localization {
def WarningFingerprint(event: FMLFingerprintViolationEvent) = new ChatComponentText("§aOpenComputers§f: ").appendSibling(localizeLater("gui.Chat.WarningFingerprint", event.expectedFingerprint, event.fingerprints.toArray.mkString(", ")))
def InfoNewVersion(version: String) = new ChatComponentText("§aOpenComputers§f: ").appendSibling(localizeLater("gui.Chat.NewVersion", version))
def TextureName(name: String) = new ChatComponentText("§aOpenComputers§f: ").appendSibling(localizeLater("gui.Chat.TextureName", name))
}
object Computer {

View File

@ -139,6 +139,7 @@ class Settings(val config: Config) {
val solarGeneratorEfficiency = config.getDouble("power.solarGeneratorEfficiency")
val assemblerTickAmount = config.getDouble("power.assemblerTickAmount") max 1
val disassemblerTickAmount = config.getDouble("power.disassemblerTickAmount") max 1
val printerTickAmount = config.getDouble("power.printerTickAmount") max 1
val powerModBlacklist = config.getStringList("power.modBlacklist")
// power.buffer
@ -192,6 +193,7 @@ class Settings(val config: Config) {
val chunkloaderCost = config.getDouble("power.cost.chunkloaderCost") max 0
val pistonCost = config.getDouble("power.cost.pistonPush") max 0
val eepromWriteCost = config.getDouble("power.cost.eepromWrite") max 0
val printCost = config.getDouble("power.cost.printerModel") max 0
// power.rate
val accessPointRate = config.getDouble("power.rate.accessPoint") max 0
@ -291,6 +293,7 @@ class Settings(val config: Config) {
val presentChance = config.getDouble("misc.presentChance") max 0 min 1
val assemblerBlacklist = config.getStringList("misc.assemblerBlacklist")
val threadPriority = config.getInt("misc.threadPriority")
val maxPrintComplexity = config.getInt("misc.maxPrinterShapes")
// ----------------------------------------------------------------------- //
// integration

View File

@ -32,6 +32,8 @@ object GuiHandler extends CommonGuiHandler {
new gui.Disassembler(player.inventory, t)
case t: tileentity.DiskDrive if id == GuiType.DiskDrive.id =>
new gui.DiskDrive(player.inventory, t)
case t: tileentity.Printer if id == GuiType.Printer.id =>
new gui.Printer(player.inventory, t)
case t: tileentity.Raid if id == GuiType.Raid.id =>
new gui.Raid(player.inventory, t)
case t: tileentity.RobotProxy if id == GuiType.Robot.id =>

View File

@ -9,6 +9,7 @@ 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.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.{PacketHandler => CommonPacketHandler}
@ -41,6 +42,7 @@ object PacketHandler extends CommonPacketHandler {
case PacketType.ColorChange => onColorChange(p)
case PacketType.ComputerState => onComputerState(p)
case PacketType.ComputerUserList => onComputerUserList(p)
case PacketType.ContainerUpdate => onContainerUpdate(p)
case PacketType.DisassemblerActiveChange => onDisassemblerActiveChange(p)
case PacketType.FileSystemActivity => onFileSystemActivity(p)
case PacketType.FloppyChange => onFloppyChange(p)
@ -52,6 +54,7 @@ object PacketHandler extends CommonPacketHandler {
case PacketType.HologramTranslation => onHologramPositionOffsetY(p)
case PacketType.PetVisibility => onPetVisibility(p)
case PacketType.PowerState => onPowerState(p)
case PacketType.PrinterState => onPrinterState(p)
case PacketType.RaidStateChange => onRaidStateChange(p)
case PacketType.RedstoneState => onRedstoneState(p)
case PacketType.RobotAnimateSwing => onRobotAnimateSwing(p)
@ -134,6 +137,16 @@ object PacketHandler extends CommonPacketHandler {
case _ => // Invalid packet.
}
def onContainerUpdate(p: PacketParser) = {
val windowId = p.readUnsignedByte()
if (p.player.openContainer != null && p.player.openContainer.windowId == windowId) {
p.player.openContainer match {
case container: container.Player => container.updateCustomData(p.readNBT())
case _ => // Invalid packet.
}
}
}
def onDisassemblerActiveChange(p: PacketParser) =
p.readTileEntity[Disassembler]() match {
case Some(t) => t.isActive = p.readBoolean()
@ -242,6 +255,14 @@ object PacketHandler extends CommonPacketHandler {
case _ => // Invalid packet.
}
def onPrinterState(p: PacketParser) =
p.readTileEntity[Printer]() match {
case Some(t) =>
if (p.readBoolean()) t.requiredEnergy = 9001
else t.requiredEnergy = 0
case _ => // Invalid packet.
}
def onRaidStateChange(p: PacketParser) =
p.readTileEntity[Raid]() match {
case Some(t) =>

View File

@ -58,6 +58,7 @@ private[oc] class Proxy extends CommonProxy {
ClientRegistry.bindTileEntitySpecialRenderer(classOf[tileentity.Hologram], HologramRendererFallback)
ClientRegistry.bindTileEntitySpecialRenderer(classOf[tileentity.Microcontroller], MicrocontrollerRenderer)
ClientRegistry.bindTileEntitySpecialRenderer(classOf[tileentity.PowerDistributor], PowerDistributorRenderer)
ClientRegistry.bindTileEntitySpecialRenderer(classOf[tileentity.Printer], PrinterRenderer)
ClientRegistry.bindTileEntitySpecialRenderer(classOf[tileentity.Raid], RaidRenderer)
ClientRegistry.bindTileEntitySpecialRenderer(classOf[tileentity.ServerRack], ServerRackRenderer)
ClientRegistry.bindTileEntitySpecialRenderer(classOf[tileentity.Switch], SwitchRenderer)
@ -66,6 +67,7 @@ private[oc] class Proxy extends CommonProxy {
ClientRegistry.bindTileEntitySpecialRenderer(classOf[tileentity.Screen], ScreenRenderer)
MinecraftForgeClient.registerItemRenderer(Items.multi, ItemRenderer)
MinecraftForgeClient.registerItemRenderer(Items.get("print").createItemStack(1).getItem, ItemRenderer)
ClientRegistry.registerKeyBinding(KeyBindings.materialCosts)
ClientRegistry.registerKeyBinding(KeyBindings.clipboardPaste)

View File

@ -25,6 +25,10 @@ object Textures {
val guiDisassembler = new ResourceLocation(Settings.resourceDomain, "textures/gui/disassembler.png")
val guiDrone = new ResourceLocation(Settings.resourceDomain, "textures/gui/drone.png")
val guiKeyboardMissing = new ResourceLocation(Settings.resourceDomain, "textures/gui/keyboard_missing.png")
val guiPrinter = new ResourceLocation(Settings.resourceDomain, "textures/gui/printer.png")
val guiPrinterInk = new ResourceLocation(Settings.resourceDomain, "textures/gui/printer_ink.png")
val guiPrinterMaterial = new ResourceLocation(Settings.resourceDomain, "textures/gui/printer_material.png")
val guiPrinterProgress = new ResourceLocation(Settings.resourceDomain, "textures/gui/printer_progress.png")
val guiRaid = new ResourceLocation(Settings.resourceDomain, "textures/gui/raid.png")
val guiRange = new ResourceLocation(Settings.resourceDomain, "textures/gui/range.png")
val guiRobot = new ResourceLocation(Settings.resourceDomain, "textures/gui/robot.png")

View File

@ -0,0 +1,78 @@
package li.cil.oc.client.gui
import li.cil.oc.Localization
import li.cil.oc.client.Textures
import li.cil.oc.client.gui.widget.ProgressBar
import li.cil.oc.common.container
import li.cil.oc.common.container.ComponentSlot
import li.cil.oc.common.tileentity
import net.minecraft.entity.player.InventoryPlayer
import org.lwjgl.opengl.GL11
class Printer(playerInventory: InventoryPlayer, val printer: tileentity.Printer) extends DynamicGuiContainer(new container.Printer(playerInventory, printer)) {
xSize = 176
ySize = 166
private val materialBar = addWidget(new ProgressBar(40, 21) {
override def width = 62
override def height = 12
override def barTexture = Textures.guiPrinterMaterial
})
private val inkBar = addWidget(new ProgressBar(40, 53) {
override def width = 62
override def height = 12
override def barTexture = Textures.guiPrinterInk
})
private val progressBar = addWidget(new ProgressBar(105, 20) {
override def width = 46
override def height = 46
override def barTexture = Textures.guiPrinterProgress
})
private def printerContainer = inventorySlots.asInstanceOf[container.Printer]
override def initGui() {
super.initGui()
}
override def drawSecondaryForegroundLayer(mouseX: Int, mouseY: Int) = {
super.drawSecondaryForegroundLayer(mouseX, mouseY)
fontRendererObj.drawString(
Localization.localizeImmediately(printer.getInventoryName),
8, 6, 0x404040)
GL11.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS) // Me lazy... prevents NEI render glitch.
if (func_146978_c(materialBar.x, materialBar.y, materialBar.width, materialBar.height, mouseX, mouseY)) {
val tooltip = new java.util.ArrayList[String]
tooltip.add(printerContainer.amountMaterial + "/" + printer.maxAmountMaterial)
copiedDrawHoveringText(tooltip, mouseX - guiLeft, mouseY - guiTop, fontRendererObj)
}
if (func_146978_c(inkBar.x, inkBar.y, inkBar.width, inkBar.height, mouseX, mouseY)) {
val tooltip = new java.util.ArrayList[String]
tooltip.add(printerContainer.amountInk + "/" + printer.maxAmountInk)
copiedDrawHoveringText(tooltip, mouseX - guiLeft, mouseY - guiTop, fontRendererObj)
}
GL11.glPopAttrib()
}
override def drawGuiContainerBackgroundLayer(dt: Float, mouseX: Int, mouseY: Int) {
GL11.glColor3f(1, 1, 1) // Required under Linux.
mc.renderEngine.bindTexture(Textures.guiPrinter)
drawTexturedModalRect(guiLeft, guiTop, 0, 0, xSize, ySize)
materialBar.level = printerContainer.amountMaterial / printer.maxAmountMaterial.toDouble
inkBar.level = printerContainer.amountInk / printer.maxAmountInk.toDouble
if (printerContainer.isPrinting) progressBar.level = (System.currentTimeMillis() % 3000) / 3000.0
else progressBar.level = 0
drawWidgets()
drawInventorySlots()
}
override protected def drawDisabledSlot(slot: ComponentSlot) {}
override def doesGuiPauseGame = false
}

View File

@ -9,19 +9,21 @@ class ProgressBar(val x: Int, val y: Int) extends Widget {
override def height = 12
def barTexture = Textures.guiBar
var level = 0.0
def draw() {
if (level > 0) {
val u0 = 0
val u1 = width / 256.0 * level
val v0 = 1 - height / 256.0
val u1 = level
val v0 = 0
val v1 = 1
val tx = owner.windowX + x
val ty = owner.windowY + y
val w = width * level
Minecraft.getMinecraft.renderEngine.bindTexture(Textures.guiBar)
Minecraft.getMinecraft.renderEngine.bindTexture(barTexture)
val t = Tessellator.instance
t.startDrawingQuads()
t.addVertexWithUV(tx, ty, owner.windowZ, u0, v0)

View File

@ -11,5 +11,5 @@ abstract class Widget {
def height: Int
def draw()
def draw(): Unit
}

View File

@ -4,12 +4,15 @@ import cpw.mods.fml.common.eventhandler.SubscribeEvent
import li.cil.oc.Settings
import li.cil.oc.api
import li.cil.oc.client.Textures
import li.cil.oc.common
import li.cil.oc.util.BlockPosition
import li.cil.oc.util.ExtendedAABB._
import li.cil.oc.util.ExtendedBlock._
import li.cil.oc.util.ExtendedWorld._
import li.cil.oc.util.RenderState
import net.minecraft.client.Minecraft
import net.minecraft.client.renderer.OpenGlHelper
import net.minecraft.client.renderer.RenderGlobal
import net.minecraft.client.renderer.Tessellator
import net.minecraft.util.MovingObjectPosition.MovingObjectType
import net.minecraftforge.client.event.DrawBlockHighlightEvent
@ -95,5 +98,33 @@ object HighlightRenderer {
GL11.glPopMatrix()
}
}
if (hitInfo.typeOfHit == MovingObjectType.BLOCK) e.player.getEntityWorld.getTileEntity(hitInfo.blockX, hitInfo.blockY, hitInfo.blockZ) match {
case print: common.tileentity.Print =>
val pos = e.player.getPosition(e.partialTicks)
val expansion = 0.002f
// See RenderGlobal.drawSelectionBox.
GL11.glEnable(GL11.GL_BLEND)
OpenGlHelper.glBlendFunc(770, 771, 1, 0)
GL11.glColor4f(0, 0, 0, 0.4f)
GL11.glLineWidth(2)
GL11.glDisable(GL11.GL_TEXTURE_2D)
GL11.glDepthMask(false)
for (shape <- if (print.state) print.data.stateOn else print.data.stateOff) {
val bounds = shape.bounds.rotateTowards(print.facing)
RenderGlobal.drawOutlinedBoundingBox(bounds.copy().expand(expansion, expansion, expansion)
.offset(e.target.blockX, e.target.blockY, e.target.blockZ)
.offset(-pos.xCoord, -pos.yCoord, -pos.zCoord), -1)
}
GL11.glDepthMask(true)
GL11.glEnable(GL11.GL_TEXTURE_2D)
GL11.glDisable(GL11.GL_BLEND)
e.setCanceled(true)
case _ =>
}
}
}

View File

@ -1,9 +1,7 @@
package li.cil.oc.client.renderer.block
import cpw.mods.fml.client.registry.ISimpleBlockRenderingHandler
import cpw.mods.fml.common.Loader
import li.cil.oc.Settings
import li.cil.oc.client.Textures
import li.cil.oc.client.renderer.tileentity.RobotRenderer
import li.cil.oc.common.block._
import li.cil.oc.common.tileentity
@ -54,6 +52,13 @@ object BlockRenderer extends ISimpleBlockRenderingHandler {
Tessellator.instance.draw()
RenderState.checkError(getClass.getName + ".renderInventoryBlock: hologram")
case printer: Printer =>
GL11.glTranslatef(-0.5f, -0.5f, -0.5f)
Tessellator.instance.startDrawingQuads()
Printer.render(block, metadata, renderer)
Tessellator.instance.draw()
RenderState.checkError(getClass.getName + ".renderInventoryBlock: printer")
case _ =>
block match {
case simple: SimpleBlock =>
@ -82,7 +87,7 @@ object BlockRenderer extends ISimpleBlockRenderingHandler {
override def renderWorldBlock(world: IBlockAccess, x: Int, y: Int, z: Int, block: Block, modelId: Int, realRenderer: RenderBlocks) = {
RenderState.checkError(getClass.getName + ".renderWorldBlock: entering (aka: wasntme)")
val renderer = patchedRenderer(realRenderer)
val renderer = patchedRenderer(realRenderer, block)
world.getTileEntity(x, y, z) match {
case cable: tileentity.Cable =>
Cable.render(world, x, y, z, block, renderer)
@ -91,85 +96,25 @@ object BlockRenderer extends ISimpleBlockRenderingHandler {
true
case keyboard: tileentity.Keyboard =>
if (keyboard.facing == ForgeDirection.UP || keyboard.facing == ForgeDirection.DOWN) {
keyboard.yaw match {
case ForgeDirection.NORTH =>
renderer.uvRotateTop = 0
renderer.uvRotateBottom = 0
case ForgeDirection.SOUTH =>
renderer.uvRotateTop = 3
renderer.uvRotateBottom = 3
case ForgeDirection.WEST =>
renderer.uvRotateTop = 2
renderer.uvRotateBottom = 1
case ForgeDirection.EAST =>
renderer.uvRotateTop = 1
renderer.uvRotateBottom = 2
case _ => throw new AssertionError("Impossible yaw value on keyboard.")
}
if (keyboard.facing == ForgeDirection.DOWN) {
renderer.flipTexture = true
}
}
val result = renderer.renderStandardBlock(block, x, y, z)
renderer.uvRotateTop = 0
renderer.uvRotateBottom = 0
renderer.flipTexture = false
val result = Keyboard.render(keyboard, x, y, z, block, renderer)
RenderState.checkError(getClass.getName + ".renderWorldBlock: keyboard")
result
case print: tileentity.Print =>
Print.render(print, x, y, z, block, renderer)
RenderState.checkError(getClass.getName + ".renderWorldBlock: print")
true
case printer: tileentity.Printer =>
Printer.render(block, x, y, z, renderer)
RenderState.checkError(getClass.getName + ".renderWorldBlock: printer")
true
case rack: tileentity.ServerRack =>
val previousRenderAllFaces = renderer.renderAllFaces
val u1 = 1 / 16f
val u2 = 15 / 16f
val v1 = 2 / 16f
val v2 = 14 / 16f
val fs = 3 / 16f
// Top and bottom.
renderer.renderAllFaces = true
renderer.setRenderBounds(0, 0, 0, 1, v1, 1)
renderer.renderStandardBlock(block, x, y, z)
renderer.setRenderBounds(0, v2, 0, 1, 1, 1)
renderer.renderStandardBlock(block, x, y, z)
// Sides.
val front = rack.facing
def renderSide(side: ForgeDirection, lx: Double, lz: Double, hx: Double, hz: Double) {
if (side == front) {
for (i <- 0 until 4 if rack.isPresent(i).isDefined) {
side match {
case ForgeDirection.WEST =>
renderer.setRenderBounds(lx, v2 - (i + 1) * fs, lz + u1, u2, v2 - i * fs, hz - u1)
case ForgeDirection.EAST =>
renderer.setRenderBounds(u1, v2 - (i + 1) * fs, lz + u1, hx, v2 - i * fs, hz - u1)
case ForgeDirection.NORTH =>
renderer.setRenderBounds(lx + u1, v2 - (i + 1) * fs, lz, hx - u1, v2 - i * fs, u2)
case ForgeDirection.SOUTH =>
renderer.setRenderBounds(lx + u1, v2 - (i + 1) * fs, u1, hx - u1, v2 - i * fs, hz)
case _ =>
}
renderer.renderStandardBlock(block, x, y, z)
}
}
else {
val isBack = front == side.getOpposite
if (isBack) {
renderer.setOverrideBlockTexture(Textures.ServerRack.icons(ForgeDirection.NORTH.ordinal))
}
renderer.setRenderBounds(lx, v1, lz, hx, v2, hz)
renderer.renderStandardBlock(block, x, y, z)
renderer.clearOverrideBlockTexture()
}
}
renderSide(ForgeDirection.WEST, 0, 0, u1, 1)
renderSide(ForgeDirection.EAST, u2, 0, 1, 1)
renderSide(ForgeDirection.NORTH, 0, 0, 1, u1)
renderSide(ForgeDirection.SOUTH, 0, u2, 1, 1)
renderer.renderAllFaces = previousRenderAllFaces
ServerRack.render(rack, x, y, z, block, renderer)
RenderState.checkError(getClass.getName + ".renderWorldBlock: rack")
@ -195,9 +140,8 @@ object BlockRenderer extends ISimpleBlockRenderingHandler {
}
}
val isOneSevenTwo = Loader.instance.getMinecraftModContainer.getVersion == "1.7.2"
def patchedRenderer(renderer: RenderBlocks) = if (isOneSevenTwo) {
// The texture flip this works around only seems to occur for blocks with custom block renderers?
def patchedRenderer(renderer: RenderBlocks, block: Block) = if (block.isInstanceOf[Hologram] || block.isInstanceOf[Printer]) {
PatchedRenderBlocks.blockAccess = renderer.blockAccess
PatchedRenderBlocks.overrideBlockTexture = renderer.overrideBlockTexture
PatchedRenderBlocks.flipTexture = renderer.flipTexture

View File

@ -0,0 +1,36 @@
package li.cil.oc.client.renderer.block
import li.cil.oc.common.tileentity
import net.minecraft.block.Block
import net.minecraft.client.renderer.RenderBlocks
import net.minecraftforge.common.util.ForgeDirection
object Keyboard {
def render(keyboard: tileentity.Keyboard, x: Int, y: Int, z: Int, block: Block, renderer: RenderBlocks): Boolean = {
if (keyboard.facing == ForgeDirection.UP || keyboard.facing == ForgeDirection.DOWN) {
keyboard.yaw match {
case ForgeDirection.NORTH =>
renderer.uvRotateTop = 0
renderer.uvRotateBottom = 0
case ForgeDirection.SOUTH =>
renderer.uvRotateTop = 3
renderer.uvRotateBottom = 3
case ForgeDirection.WEST =>
renderer.uvRotateTop = 2
renderer.uvRotateBottom = 1
case ForgeDirection.EAST =>
renderer.uvRotateTop = 1
renderer.uvRotateBottom = 2
case _ => throw new AssertionError("Impossible yaw value on keyboard.")
}
if (keyboard.facing == ForgeDirection.DOWN) {
renderer.flipTexture = true
}
}
val result = renderer.renderStandardBlock(block, x, y, z)
renderer.uvRotateTop = 0
renderer.uvRotateBottom = 0
renderer.flipTexture = false
result
}
}

View File

@ -0,0 +1,29 @@
package li.cil.oc.client.renderer.block
import li.cil.oc.common.tileentity
import li.cil.oc.util.ExtendedAABB._
import net.minecraft.block.Block
import net.minecraft.client.Minecraft
import net.minecraft.client.renderer.RenderBlocks
import net.minecraft.client.renderer.texture.TextureMap
import net.minecraft.util.IIcon
object Print {
def render(print: tileentity.Print, x: Int, y: Int, z: Int, block: Block, renderer: RenderBlocks): Unit = {
for (shape <- if (print.state) print.data.stateOn else print.data.stateOff) {
val bounds = shape.bounds.rotateTowards(print.facing)
renderer.setOverrideBlockTexture(resolveTexture(shape.texture))
renderer.setRenderBounds(
bounds.minX, bounds.minY, bounds.minZ,
bounds.maxX, bounds.maxY, bounds.maxZ)
renderer.renderStandardBlock(block, x, y, z)
}
renderer.clearOverrideBlockTexture()
}
def resolveTexture(name: String): IIcon = {
val icon = Minecraft.getMinecraft.getTextureMapBlocks.getTextureExtry(name)
if (icon == null) Minecraft.getMinecraft.getTextureManager.getTexture(TextureMap.locationBlocksTexture).asInstanceOf[TextureMap].getAtlasSprite("missingno")
else icon
}
}

View File

@ -0,0 +1,68 @@
package li.cil.oc.client.renderer.block
import net.minecraft.block.Block
import net.minecraft.client.renderer.RenderBlocks
object Printer {
def render(block: Block, x: Int, y: Int, z: Int, renderer: RenderBlocks) {
val previousRenderAllFaces = renderer.renderAllFaces
renderer.renderAllFaces = true
// Bottom.
renderer.setRenderBounds(0, 0, 0, 1, 8 / 16f, 1)
renderer.renderStandardBlock(block, x, y, z)
// Corners.
renderer.setRenderBounds(0 / 16f, 8 / 16f, 0 / 16f, 3 / 16f, 16 / 16f, 3 / 16f)
renderer.renderStandardBlock(block, x, y, z)
renderer.setRenderBounds(13 / 16f, 8 / 16f, 0 / 16f, 16 / 16f, 16 / 16f, 3 / 16f)
renderer.renderStandardBlock(block, x, y, z)
renderer.setRenderBounds(0 / 16f, 8 / 16f, 13 / 16f, 3 / 16f, 16 / 16f, 16 / 16f)
renderer.renderStandardBlock(block, x, y, z)
renderer.setRenderBounds(13 / 16f, 8 / 16f, 13 / 16f, 16 / 16f, 16 / 16f, 16 / 16f)
renderer.renderStandardBlock(block, x, y, z)
// Top.
renderer.setRenderBounds(3 / 16f, 13 / 16f, 0 / 16f, 13 / 16f, 16 / 16f, 3 / 16f)
renderer.renderStandardBlock(block, x, y, z)
renderer.setRenderBounds(3 / 16f, 13 / 16f, 13 / 16f, 13 / 16f, 16 / 16f, 16 / 16f)
renderer.renderStandardBlock(block, x, y, z)
renderer.setRenderBounds(0 / 16f, 13 / 16f, 3 / 16f, 3 / 16f, 16 / 16f, 13 / 16f)
renderer.renderStandardBlock(block, x, y, z)
renderer.setRenderBounds(13 / 16f, 13 / 16f, 3 / 16f, 16 / 16f, 16 / 16f, 13 / 16f)
renderer.renderStandardBlock(block, x, y, z)
renderer.renderAllFaces = previousRenderAllFaces
}
def render(block: Block, metadata: Int, renderer: RenderBlocks) {
// Bottom.
renderer.setRenderBounds(0, 0, 0, 1, 8 / 16f, 1)
renderAllFaces(block, metadata, renderer)
// Corners.
renderer.setRenderBounds(0 / 16f, 8 / 16f, 0 / 16f, 3 / 16f, 16 / 16f, 3 / 16f)
renderAllFaces(block, metadata, renderer)
renderer.setRenderBounds(13 / 16f, 8 / 16f, 0 / 16f, 16 / 16f, 16 / 16f, 3 / 16f)
renderAllFaces(block, metadata, renderer)
renderer.setRenderBounds(0 / 16f, 8 / 16f, 13 / 16f, 3 / 16f, 16 / 16f, 16 / 16f)
renderAllFaces(block, metadata, renderer)
renderer.setRenderBounds(13 / 16f, 8 / 16f, 13 / 16f, 16 / 16f, 16 / 16f, 16 / 16f)
renderAllFaces(block, metadata, renderer)
// Top.
renderer.setRenderBounds(3 / 16f, 13 / 16f, 0 / 16f, 13 / 16f, 16 / 16f, 3 / 16f)
renderAllFaces(block, metadata, renderer)
renderer.setRenderBounds(3 / 16f, 13 / 16f, 13 / 16f, 13 / 16f, 16 / 16f, 16 / 16f)
renderAllFaces(block, metadata, renderer)
renderer.setRenderBounds(0 / 16f, 13 / 16f, 3 / 16f, 3 / 16f, 16 / 16f, 13 / 16f)
renderAllFaces(block, metadata, renderer)
renderer.setRenderBounds(13 / 16f, 13 / 16f, 3 / 16f, 16 / 16f, 16 / 16f, 13 / 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)
}
}

View File

@ -0,0 +1,62 @@
package li.cil.oc.client.renderer.block
import li.cil.oc.client.Textures
import li.cil.oc.common.tileentity
import net.minecraft.block.Block
import net.minecraft.client.renderer.RenderBlocks
import net.minecraftforge.common.util.ForgeDirection
object ServerRack {
def render(rack: tileentity.ServerRack, x: Int, y: Int, z: Int, block: Block, renderer: RenderBlocks): Unit = {
val previousRenderAllFaces = renderer.renderAllFaces
val u1 = 1 / 16f
val u2 = 15 / 16f
val v1 = 2 / 16f
val v2 = 14 / 16f
val fs = 3 / 16f
// Top and bottom.
renderer.renderAllFaces = true
renderer.setRenderBounds(0, 0, 0, 1, v1, 1)
renderer.renderStandardBlock(block, x, y, z)
renderer.setRenderBounds(0, v2, 0, 1, 1, 1)
renderer.renderStandardBlock(block, x, y, z)
// Sides.
val front = rack.facing
def renderSide(side: ForgeDirection, lx: Double, lz: Double, hx: Double, hz: Double) {
if (side == front) {
for (i <- 0 until 4 if rack.isPresent(i).isDefined) {
side match {
case ForgeDirection.WEST =>
renderer.setRenderBounds(lx, v2 - (i + 1) * fs, lz + u1, u2, v2 - i * fs, hz - u1)
case ForgeDirection.EAST =>
renderer.setRenderBounds(u1, v2 - (i + 1) * fs, lz + u1, hx, v2 - i * fs, hz - u1)
case ForgeDirection.NORTH =>
renderer.setRenderBounds(lx + u1, v2 - (i + 1) * fs, lz, hx - u1, v2 - i * fs, u2)
case ForgeDirection.SOUTH =>
renderer.setRenderBounds(lx + u1, v2 - (i + 1) * fs, u1, hx - u1, v2 - i * fs, hz)
case _ =>
}
renderer.renderStandardBlock(block, x, y, z)
}
}
else {
val isBack = front == side.getOpposite
if (isBack) {
renderer.setOverrideBlockTexture(Textures.ServerRack.icons(ForgeDirection.NORTH.ordinal))
}
renderer.setRenderBounds(lx, v1, lz, hx, v2, hz)
renderer.renderStandardBlock(block, x, y, z)
renderer.clearOverrideBlockTexture()
}
}
renderSide(ForgeDirection.WEST, 0, 0, u1, 1)
renderSide(ForgeDirection.EAST, u2, 0, 1, 1)
renderSide(ForgeDirection.NORTH, 0, 0, 1, u1)
renderSide(ForgeDirection.SOUTH, 0, u2, 1, 1)
renderer.renderAllFaces = previousRenderAllFaces
}
}

View File

@ -4,13 +4,16 @@ import li.cil.oc.Settings
import li.cil.oc.api
import li.cil.oc.api.detail.ItemInfo
import li.cil.oc.client.Textures
import li.cil.oc.client.renderer.block.Print
import li.cil.oc.client.renderer.entity.DroneRenderer
import li.cil.oc.common.item.data.PrintData
import li.cil.oc.integration.opencomputers.Item
import li.cil.oc.util.RenderState
import net.minecraft.client.Minecraft
import net.minecraft.client.gui.ScaledResolution
import net.minecraft.client.renderer.entity.RenderItem
import net.minecraft.client.renderer.entity.RenderManager
import net.minecraft.client.renderer.texture.TextureMap
import net.minecraft.item.ItemStack
import net.minecraft.util.AxisAlignedBB
import net.minecraft.util.EnumChatFormatting
@ -32,6 +35,7 @@ object ItemRenderer extends IItemRenderer {
lazy val floppy = api.Items.get("floppy")
lazy val lootDisk = api.Items.get("lootDisk")
lazy val print = api.Items.get("print")
def bounds = AxisAlignedBB.getBoundingBox(-0.1, -0.1, -0.1, 0.1, 0.1, 0.1)
@ -48,11 +52,13 @@ object ItemRenderer extends IItemRenderer {
val descriptor = api.Items.get(stack)
(renderType == ItemRenderType.EQUIPPED && isUpgrade(api.Items.get(stack))) ||
(renderType == ItemRenderType.INVENTORY && isFloppy(api.Items.get(stack))) ||
((renderType == ItemRenderType.INVENTORY || renderType == ItemRenderType.ENTITY || renderType == ItemRenderType.EQUIPPED || renderType == ItemRenderType.EQUIPPED_FIRST_PERSON) && descriptor == drone)
((renderType == ItemRenderType.INVENTORY || renderType == ItemRenderType.ENTITY || renderType == ItemRenderType.EQUIPPED || renderType == ItemRenderType.EQUIPPED_FIRST_PERSON) && descriptor == drone) ||
((renderType == ItemRenderType.INVENTORY || renderType == ItemRenderType.ENTITY || renderType == ItemRenderType.EQUIPPED || renderType == ItemRenderType.EQUIPPED_FIRST_PERSON) && api.Items.get(stack) == print)
}
override def shouldUseRenderHelper(renderType: ItemRenderType, stack: ItemStack, helper: ItemRendererHelper) =
if (renderType == ItemRenderType.ENTITY) true
else if (renderType == ItemRenderType.INVENTORY && api.Items.get(stack) == print) helper == ItemRendererHelper.INVENTORY_BLOCK
// Note: it's easier to revert changes introduced by this "helper" than by
// the code that applies if no helper is used...
else helper == ItemRendererHelper.EQUIPPED_BLOCK
@ -116,6 +122,7 @@ object ItemRenderer extends IItemRenderer {
RenderState.checkError("ItemRenderer.renderItem: floppy")
}
else if (descriptor == drone) {
GL11.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS)
GL11.glPushMatrix()
@ -144,6 +151,26 @@ object ItemRenderer extends IItemRenderer {
RenderState.checkError("ItemRenderer.renderItem: drone")
}
else if (descriptor == print) {
GL11.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS)
GL11.glPushMatrix()
if (renderType == ItemRenderType.ENTITY) {
GL11.glTranslatef(-0.5f, 0, -0.5f)
}
val data = new PrintData(stack)
Minecraft.getMinecraft.renderEngine.bindTexture(TextureMap.locationBlocksTexture)
for (shape <- data.stateOff) {
drawShape(shape)
}
GL11.glPopMatrix()
GL11.glPopAttrib()
RenderState.checkError("ItemRenderer.renderItem: print")
}
RenderState.checkError("ItemRenderer.renderItem: leaving")
}
@ -207,4 +234,79 @@ object ItemRenderer extends IItemRenderer {
GL11.glEnd()
}
private def drawShape(shape: PrintData.Shape) {
val bounds = shape.bounds
val texture = Print.resolveTexture(shape.texture)
GL11.glBegin(GL11.GL_QUADS)
// Front.
GL11.glNormal3f(0, 0, 1)
GL11.glTexCoord2f(texture.getInterpolatedU(bounds.minX * 16), texture.getInterpolatedV(bounds.minY * 16))
GL11.glVertex3d(bounds.minX, bounds.minY, bounds.maxZ)
GL11.glTexCoord2f(texture.getInterpolatedU(bounds.maxX * 16), texture.getInterpolatedV(bounds.minY * 16))
GL11.glVertex3d(bounds.maxX, bounds.minY, bounds.maxZ)
GL11.glTexCoord2f(texture.getInterpolatedU(bounds.maxX * 16), texture.getInterpolatedV(bounds.maxY * 16))
GL11.glVertex3d(bounds.maxX, bounds.maxY, bounds.maxZ)
GL11.glTexCoord2f(texture.getInterpolatedU(bounds.minX * 16), texture.getInterpolatedV(bounds.maxY * 16))
GL11.glVertex3d(bounds.minX, bounds.maxY, bounds.maxZ)
// Back.
GL11.glNormal3f(0, 0, -1)
GL11.glTexCoord2f(texture.getInterpolatedU(bounds.maxX * 16), texture.getInterpolatedV(bounds.minY * 16))
GL11.glVertex3d(bounds.maxX, bounds.minY, bounds.minZ)
GL11.glTexCoord2f(texture.getInterpolatedU(bounds.minX * 16), texture.getInterpolatedV(bounds.minY * 16))
GL11.glVertex3d(bounds.minX, bounds.minY, bounds.minZ)
GL11.glTexCoord2f(texture.getInterpolatedU(bounds.minX * 16), texture.getInterpolatedV(bounds.maxY * 16))
GL11.glVertex3d(bounds.minX, bounds.maxY, bounds.minZ)
GL11.glTexCoord2f(texture.getInterpolatedU(bounds.maxX * 16), texture.getInterpolatedV(bounds.maxY * 16))
GL11.glVertex3d(bounds.maxX, bounds.maxY, bounds.minZ)
// Top.
GL11.glNormal3f(0, 1, 0)
GL11.glTexCoord2f(texture.getInterpolatedU(bounds.maxX * 16), texture.getInterpolatedV(bounds.maxZ * 16))
GL11.glVertex3d(bounds.maxX, bounds.maxY, bounds.maxZ)
GL11.glTexCoord2f(texture.getInterpolatedU(bounds.maxX * 16), texture.getInterpolatedV(bounds.minZ * 16))
GL11.glVertex3d(bounds.maxX, bounds.maxY, bounds.minZ)
GL11.glTexCoord2f(texture.getInterpolatedU(bounds.minX * 16), texture.getInterpolatedV(bounds.minZ * 16))
GL11.glVertex3d(bounds.minX, bounds.maxY, bounds.minZ)
GL11.glTexCoord2f(texture.getInterpolatedU(bounds.minX * 16), texture.getInterpolatedV(bounds.maxZ * 16))
GL11.glVertex3d(bounds.minX, bounds.maxY, bounds.maxZ)
// Bottom.
GL11.glNormal3f(0, -1, 0)
GL11.glTexCoord2f(texture.getInterpolatedU(bounds.minX * 16), texture.getInterpolatedV(bounds.maxZ * 16))
GL11.glVertex3d(bounds.minX, bounds.minY, bounds.maxZ)
GL11.glTexCoord2f(texture.getInterpolatedU(bounds.minX * 16), texture.getInterpolatedV(bounds.minZ * 16))
GL11.glVertex3d(bounds.minX, bounds.minY, bounds.minZ)
GL11.glTexCoord2f(texture.getInterpolatedU(bounds.maxX * 16), texture.getInterpolatedV(bounds.minZ * 16))
GL11.glVertex3d(bounds.maxX, bounds.minY, bounds.minZ)
GL11.glTexCoord2f(texture.getInterpolatedU(bounds.maxX * 16), texture.getInterpolatedV(bounds.maxZ * 16))
GL11.glVertex3d(bounds.maxX, bounds.minY, bounds.maxZ)
// Left.
GL11.glNormal3f(1, 0, 0)
GL11.glTexCoord2f(texture.getInterpolatedU(bounds.maxY * 16), texture.getInterpolatedV(bounds.maxZ * 16))
GL11.glVertex3d(bounds.maxX, bounds.maxY, bounds.maxZ)
GL11.glTexCoord2f(texture.getInterpolatedU(bounds.minY * 16), texture.getInterpolatedV(bounds.maxZ * 16))
GL11.glVertex3d(bounds.maxX, bounds.minY, bounds.maxZ)
GL11.glTexCoord2f(texture.getInterpolatedU(bounds.minY * 16), texture.getInterpolatedV(bounds.minZ * 16))
GL11.glVertex3d(bounds.maxX, bounds.minY, bounds.minZ)
GL11.glTexCoord2f(texture.getInterpolatedU(bounds.maxY * 16), texture.getInterpolatedV(bounds.minZ * 16))
GL11.glVertex3d(bounds.maxX, bounds.maxY, bounds.minZ)
// Right.
GL11.glNormal3f(-1, 0, 0)
GL11.glTexCoord2f(texture.getInterpolatedU(bounds.minY * 16), texture.getInterpolatedV(bounds.maxZ * 16))
GL11.glVertex3d(bounds.minX, bounds.minY, bounds.maxZ)
GL11.glTexCoord2f(texture.getInterpolatedU(bounds.maxY * 16), texture.getInterpolatedV(bounds.maxZ * 16))
GL11.glVertex3d(bounds.minX, bounds.maxY, bounds.maxZ)
GL11.glTexCoord2f(texture.getInterpolatedU(bounds.maxY * 16), texture.getInterpolatedV(bounds.minZ * 16))
GL11.glVertex3d(bounds.minX, bounds.maxY, bounds.minZ)
GL11.glTexCoord2f(texture.getInterpolatedU(bounds.minY * 16), texture.getInterpolatedV(bounds.minZ * 16))
GL11.glVertex3d(bounds.minX, bounds.minY, bounds.minZ)
GL11.glEnd()
}
}

View File

@ -0,0 +1,46 @@
package li.cil.oc.client.renderer.tileentity
import li.cil.oc.common.tileentity.Printer
import li.cil.oc.util.RenderState
import net.minecraft.client.renderer.OpenGlHelper
import net.minecraft.client.renderer.entity.RenderItem
import net.minecraft.client.renderer.entity.RenderManager
import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer
import net.minecraft.entity.item.EntityItem
import net.minecraft.tileentity.TileEntity
import org.lwjgl.opengl.GL11
object PrinterRenderer extends TileEntitySpecialRenderer {
override def renderTileEntityAt(tileEntity: TileEntity, x: Double, y: Double, z: Double, f: Float) {
RenderState.checkError(getClass.getName + ".renderTileEntityAt: entering (aka: wasntme)")
val printer = tileEntity.asInstanceOf[Printer]
if (printer.data.stateOff.size > 0) {
val stack = printer.data.createItemStack()
GL11.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS)
GL11.glPushMatrix()
GL11.glTranslated(x + 0.5, y + 0.5, z + 0.5)
// GL11.glTranslated(-0.5, -0.5, -0.5)
GL11.glRotated((System.currentTimeMillis() % 20000) / 20000.0 * 360, 0, 1, 0)
// GL11.glTranslated(0.5, 0.5, 0.5)
val brightness = printer.world.getLightBrightnessForSkyBlocks(printer.x, printer.y, printer.z, 0)
OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, brightness % 65536, brightness / 65536)
// This is very 'meh', but item frames do it like this, too!
val entity = new EntityItem(printer.world, 0, 0, 0, stack)
entity.hoverStart = 0
RenderItem.renderInFrame = true
RenderManager.instance.renderEntityWithPosYaw(entity, 0, -0.1, 0, 0, 0)
RenderItem.renderInFrame = false
GL11.glPopMatrix()
GL11.glPopAttrib()
}
RenderState.checkError(getClass.getName + ".renderTileEntityAt: leaving")
}
}

View File

@ -24,6 +24,8 @@ abstract class GuiHandler extends IGuiHandler {
new container.Disassembler(player.inventory, t)
case t: tileentity.DiskDrive if id == GuiType.DiskDrive.id =>
new container.DiskDrive(player.inventory, t)
case t: tileentity.Printer if id == GuiType.Printer.id =>
new container.Printer(player.inventory, t)
case t: tileentity.Raid if id == GuiType.Raid.id =>
new container.Raid(player.inventory, t)
case t: tileentity.RobotProxy if id == GuiType.Robot.id =>

View File

@ -21,6 +21,7 @@ object GuiType extends ScalaEnum {
val Disassembler = new EnumVal { def name = "Disassembler"; def subType = GuiType.Category.Block }
val DiskDrive = new EnumVal { def name = "DiskDrive"; def subType = GuiType.Category.Block }
val Drone = new EnumVal { def name = "Drone"; def subType = GuiType.Category.Entity }
val Printer = new EnumVal { def name = "Printer"; def subType = GuiType.Category.Block }
val Rack = new EnumVal { def name = "Rack"; def subType = GuiType.Category.Block }
val Raid = new EnumVal { def name = "Raid"; def subType = GuiType.Category.Block }
val Robot = new EnumVal { def name = "Robot"; def subType = GuiType.Category.Block }

View File

@ -9,6 +9,7 @@ object PacketType extends Enumeration {
ColorChange,
ComputerState,
ComputerUserList,
ContainerUpdate,
DisassemblerActiveChange,
FileSystemActivity,
FloppyChange,
@ -20,6 +21,7 @@ object PacketType extends Enumeration {
HologramTranslation,
PetVisibility, // Goes both ways.
PowerState,
PrinterState,
RaidStateChange,
RedstoneState,
RobotAnimateSwing,

View File

@ -5,6 +5,7 @@ import li.cil.oc.api.driver
object Slot {
val None = driver.item.Slot.None
val Any = driver.item.Slot.Any
val Filtered = "filtered"
val Card = driver.item.Slot.Card
val ComponentBus = driver.item.Slot.ComponentBus

View File

@ -5,6 +5,7 @@ import java.util
import li.cil.oc.Settings
import li.cil.oc.api
import li.cil.oc.client.KeyBindings
import li.cil.oc.common.item.data.PrintData
import li.cil.oc.common.item.data.RobotData
import li.cil.oc.common.tileentity
import li.cil.oc.util.ItemCosts
@ -47,6 +48,14 @@ class Item(value: Block) extends ItemBlock(value) {
override def getMetadata(itemDamage: Int) = itemDamage
override def getItemStackDisplayName(stack: ItemStack): String = {
if (api.Items.get(stack) == api.Items.get("print")) {
val data = new PrintData(stack)
data.label.getOrElse(super.getItemStackDisplayName(stack))
}
else super.getItemStackDisplayName(stack)
}
override def getUnlocalizedName = block match {
case simple: SimpleBlock => simple.getUnlocalizedName
case _ => Settings.namespace + "tile"

View File

@ -102,9 +102,11 @@ class Microcontroller(protected implicit val tileTag: ClassTag[tileentity.Microc
override protected def doCustomInit(tileEntity: tileentity.Microcontroller, player: EntityLivingBase, stack: ItemStack): Unit = {
super.doCustomInit(tileEntity, player, stack)
if (!tileEntity.world.isRemote) {
tileEntity.info.load(stack)
tileEntity.snooperNode.changeBuffer(tileEntity.info.storedEnergy - tileEntity.snooperNode.localBuffer)
}
}
override protected def doCustomDrops(tileEntity: tileentity.Microcontroller, player: EntityPlayer, willHarvest: Boolean): Unit = {
super.doCustomDrops(tileEntity, player, willHarvest)

View File

@ -0,0 +1,160 @@
package li.cil.oc.common.block
import java.util
import java.util.Random
import li.cil.oc.Settings
import li.cil.oc.common.item.data.PrintData
import li.cil.oc.common.tileentity
import li.cil.oc.integration.util.NEI
import li.cil.oc.util.ExtendedAABB
import li.cil.oc.util.ExtendedAABB._
import net.minecraft.entity.Entity
import net.minecraft.entity.EntityLivingBase
import net.minecraft.entity.EnumCreatureType
import net.minecraft.entity.player.EntityPlayer
import net.minecraft.item.ItemStack
import net.minecraft.util.AxisAlignedBB
import net.minecraft.util.MovingObjectPosition
import net.minecraft.util.Vec3
import net.minecraft.world.IBlockAccess
import net.minecraft.world.World
import net.minecraftforge.common.util.ForgeDirection
import scala.collection.convert.WrapAsJava._
import scala.reflect.ClassTag
class Print(protected implicit val tileTag: ClassTag[tileentity.Print]) extends RedstoneAware with traits.SpecialBlock with traits.CustomDrops[tileentity.Print] {
setLightOpacity(0)
setHardness(1)
setCreativeTab(null)
NEI.hide(this)
setBlockTextureName(Settings.resourceDomain + "GenericTop")
override protected def tooltipBody(metadata: Int, stack: ItemStack, player: EntityPlayer, tooltip: util.List[String], advanced: Boolean): Unit = {
super.tooltipBody(metadata, stack, player, tooltip, advanced)
val data = new PrintData(stack)
data.tooltip.foreach(s => tooltip.addAll(s.lines.toIterable))
}
override def shouldSideBeRendered(world: IBlockAccess, x: Int, y: Int, z: Int, side: ForgeDirection) = true
override def isBlockSolid(world: IBlockAccess, x: Int, y: Int, z: Int, side: ForgeDirection) = isSideSolid(world, x, y, z, side)
override def isSideSolid(world: IBlockAccess, x: Int, y: Int, z: Int, side: ForgeDirection): Boolean = {
world.getTileEntity(x, y, z) match {
case print: tileentity.Print =>
val shapes = if (print.state) print.data.stateOn else print.data.stateOff
for (shape <- shapes) {
val bounds = shape.bounds
val fullX = bounds.minX == 0 && bounds.maxX == 1
val fullY = bounds.minY == 0 && bounds.maxY == 1
val fullZ = bounds.minZ == 0 && bounds.maxZ == 1
if (side match {
case ForgeDirection.DOWN => bounds.minY == 0 && fullX && fullZ
case ForgeDirection.UP => bounds.maxY == 1 && fullX && fullZ
case ForgeDirection.NORTH => bounds.minZ == 0 && fullX && fullY
case ForgeDirection.SOUTH => bounds.maxZ == 1 && fullX && fullY
case ForgeDirection.WEST => bounds.minX == 0 && fullY && fullZ
case ForgeDirection.EAST => bounds.maxX == 1 && fullY && fullZ
case _ => false
}) return true
}
case _ =>
}
false
}
override def getPickBlock(target: MovingObjectPosition, world: World, x: Int, y: Int, z: Int, player: EntityPlayer): ItemStack = {
world.getTileEntity(x, y, z) match {
case print: tileentity.Print => print.data.createItemStack()
case _ => null
}
}
override def addCollisionBoxesToList(world: World, x: Int, y: Int, z: Int, mask: AxisAlignedBB, list: util.List[_], entity: Entity): Unit = {
world.getTileEntity(x, y, z) match {
case print: tileentity.Print =>
def add[T](list: util.List[T], value: Any) = list.add(value.asInstanceOf[T])
val shapes = if (print.state) print.data.stateOn else print.data.stateOff
for (shape <- shapes) {
val bounds = shape.bounds.rotateTowards(print.facing).offset(x, y, z)
if (bounds.intersectsWith(mask)) {
add(list, bounds)
}
}
case _ => super.addCollisionBoxesToList(world, x, y, z, mask, list, entity)
}
}
override protected def intersect(world: World, x: Int, y: Int, z: Int, origin: Vec3, direction: Vec3): MovingObjectPosition = {
world.getTileEntity(x, y, z) match {
case print: tileentity.Print =>
var closestDistance = Double.PositiveInfinity
var closest: Option[MovingObjectPosition] = None
for (shape <- if (print.state) print.data.stateOn else print.data.stateOff) {
val bounds = shape.bounds.rotateTowards(print.facing).offset(x, y, z)
val hit = bounds.calculateIntercept(origin, direction)
if (hit != null) {
val distance = hit.hitVec.distanceTo(origin)
if (distance < closestDistance) {
closestDistance = distance
closest = Option(hit)
}
}
}
closest.map(hit => new MovingObjectPosition(x, y, z, hit.sideHit, hit.hitVec)).orNull
case _ => super.intersect(world, x, y, z, origin, direction)
}
}
override protected def doSetBlockBoundsBasedOnState(world: IBlockAccess, x: Int, y: Int, z: Int): Unit = {
world.getTileEntity(x, y, z) match {
case print: tileentity.Print => setBlockBounds(if (print.state) print.boundsOn else print.boundsOff)
case _ => super.doSetBlockBoundsBasedOnState(world, x, y, z)
}
}
override def setBlockBoundsForItemRender(metadata: Int): Unit = {
setBlockBounds(ExtendedAABB.unitBounds)
}
override def canCreatureSpawn(creature: EnumCreatureType, world: IBlockAccess, x: Int, y: Int, z: Int): Boolean = true
override def tickRate(world: World) = 20
override def updateTick(world: World, x: Int, y: Int, z: Int, rng: Random): Unit = {
if (!world.isRemote) world.getTileEntity(x, y, z) match {
case print: tileentity.Print => if (print.state) print.toggleState()
case _ =>
}
}
// ----------------------------------------------------------------------- //
override def hasTileEntity(metadata: Int) = true
override def createTileEntity(world: World, metadata: Int) = new tileentity.Print()
// ----------------------------------------------------------------------- //
override def onBlockActivated(world: World, x: Int, y: Int, z: Int, player: EntityPlayer, side: ForgeDirection, hitX: Float, hitY: Float, hitZ: Float): Boolean = {
world.getTileEntity(x, y, z) match {
case print: tileentity.Print => print.activate()
case _ => super.onBlockActivated(world, x, y, z, player, side, hitX, hitY, hitZ)
}
}
override protected def doCustomInit(tileEntity: tileentity.Print, player: EntityLivingBase, stack: ItemStack): Unit = {
super.doCustomInit(tileEntity, player, stack)
tileEntity.data.load(stack)
tileEntity.updateBounds()
}
override protected def doCustomDrops(tileEntity: tileentity.Print, player: EntityPlayer, willHarvest: Boolean): Unit = {
super.doCustomDrops(tileEntity, player, willHarvest)
if (!player.capabilities.isCreativeMode) {
dropBlockAsItem(tileEntity.world, tileEntity.x, tileEntity.y, tileEntity.z, tileEntity.data.createItemStack())
}
}
}

View File

@ -0,0 +1,40 @@
package li.cil.oc.common.block
import li.cil.oc.Settings
import li.cil.oc.client.Textures
import li.cil.oc.common.GuiType
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 Printer extends SimpleBlock with traits.SpecialBlock with traits.StateAware with traits.GUI {
override protected def customTextures = Array(
None,
Some("PrinterTop"),
Some("PrinterSide"),
Some("PrinterSide"),
Some("PrinterSide"),
Some("PrinterSide")
)
override def registerBlockIcons(iconRegister: IIconRegister) = {
super.registerBlockIcons(iconRegister)
Textures.Assembler.iconSideAssembling = iconRegister.registerIcon(Settings.resourceDomain + ":AssemblerSideAssembling")
Textures.Assembler.iconSideOn = iconRegister.registerIcon(Settings.resourceDomain + ":AssemblerSideOn")
Textures.Assembler.iconTopOn = iconRegister.registerIcon(Settings.resourceDomain + ":AssemblerTopOn")
}
override def isBlockSolid(world: IBlockAccess, x: Int, y: Int, z: Int, side: ForgeDirection) = side == ForgeDirection.DOWN
override def isSideSolid(world: IBlockAccess, x: Int, y: Int, z: Int, side: ForgeDirection) = side == ForgeDirection.DOWN
// ----------------------------------------------------------------------- //
override def guiType = GuiType.Printer
override def hasTileEntity(metadata: Int) = true
override def createTileEntity(world: World, metadata: Int) = new tileentity.Printer()
}

View File

@ -55,6 +55,7 @@ class Raid(protected implicit val tileTag: ClassTag[tileentity.Raid]) extends Si
override protected def doCustomInit(tileEntity: tileentity.Raid, player: EntityLivingBase, stack: ItemStack): Unit = {
super.doCustomInit(tileEntity, player, stack)
if (!tileEntity.world.isRemote) {
val data = new RaidData(stack)
for (i <- 0 until math.min(data.disks.length, tileEntity.getSizeInventory)) {
tileEntity.setInventorySlotContents(i, data.disks(i))
@ -65,6 +66,7 @@ class Raid(protected implicit val tileTag: ClassTag[tileentity.Raid]) extends Si
tileEntity.filesystem.foreach(_.load(data.filesystem))
}
}
}
override protected def doCustomDrops(tileEntity: tileentity.Raid, player: EntityPlayer, willHarvest: Boolean): Unit = {
super.doCustomDrops(tileEntity, player, willHarvest)

View File

@ -51,7 +51,11 @@ abstract class RedstoneAware extends SimpleBlock with IRedNetOmniNode {
}
}
world.getTileEntity(x, y, z) match {
case redstone: tileentity.traits.RedstoneAware => redstone.checkRedstoneInputChanged()
case redstone: tileentity.traits.RedstoneAware =>
if (redstone.canUpdate)
redstone.checkRedstoneInputChanged()
else
ForgeDirection.VALID_DIRECTIONS.foreach(redstone.updateRedstoneInput)
case _ => // Ignore.
}
}

View File

@ -27,6 +27,7 @@ import net.minecraftforge.common.util.ForgeDirection
class SimpleBlock(material: Material = Material.iron) extends Block(material) {
setHardness(2f)
setResistance(5)
setCreativeTab(CreativeTab)
var showInItemList = true

View File

@ -31,14 +31,12 @@ trait CustomDrops[Tile <: TileEntity] extends SimpleBlock {
override def onBlockPlacedBy(world: World, x: Int, y: Int, z: Int, player: EntityLivingBase, stack: ItemStack): Unit = {
super.onBlockPlacedBy(world, x, y, z, player, stack)
if (!world.isRemote) {
val matcher = tileTag
world.getTileEntity(x, y, z) match {
case matcher(tileEntity) => doCustomInit(tileEntity, player, stack)
case _ =>
}
}
}
protected def doCustomInit(tileEntity: Tile, player: EntityLivingBase, stack: ItemStack): Unit = {}

View File

@ -7,8 +7,8 @@ import li.cil.oc.common
import li.cil.oc.common.InventorySlots.InventorySlot
import li.cil.oc.common.template.AssemblerTemplates
import li.cil.oc.common.tileentity
import li.cil.oc.util.SideTracker
import net.minecraft.entity.player.InventoryPlayer
import net.minecraft.nbt.NBTTagCompound
class Assembler(playerInventory: InventoryPlayer, val assembler: tileentity.Assembler) extends Player(playerInventory, assembler) {
// Computer case.
@ -67,40 +67,16 @@ class Assembler(playerInventory: InventoryPlayer, val assembler: tileentity.Asse
// Show the player's inventory.
addPlayerInventorySlots(8, 110)
var isAssembling = false
var assemblyProgress = 0.0
var assemblyRemainingTime = 0
def isAssembling = synchronizedData.getBoolean("isAssembling")
@SideOnly(Side.CLIENT)
override def updateProgressBar(id: Int, value: Int) {
super.updateProgressBar(id, value)
if (id == 0) {
isAssembling = value == 1
}
def assemblyProgress = synchronizedData.getDouble("assemblyProgress")
if (id == 1) {
assemblyProgress = value / 5.0
}
def assemblyRemainingTime = synchronizedData.getInteger("assemblyRemainingTime")
if (id == 2) {
assemblyRemainingTime = value
}
}
override def detectAndSendChanges() {
super.detectAndSendChanges()
if (SideTracker.isServer) {
if (isAssembling != assembler.isAssembling) {
isAssembling = assembler.isAssembling
sendProgressBarUpdate(0, if (isAssembling) 1 else 0)
}
val timeRemaining = assembler.timeRemaining
if (math.abs(assembler.progress - assemblyProgress) > 0.2 || assemblyRemainingTime != timeRemaining) {
assemblyProgress = assembler.progress
assemblyRemainingTime = timeRemaining
sendProgressBarUpdate(1, (assemblyProgress * 5).toInt)
sendProgressBarUpdate(2, timeRemaining)
}
}
override protected def detectCustomDataChanges(nbt: NBTTagCompound): Unit = {
synchronizedData.setBoolean("isAssembling", assembler.isAssembling)
synchronizedData.setDouble("assemblyProgress", assembler.progress)
synchronizedData.setInteger("assemblyRemainingTime", assembler.timeRemaining)
super.detectCustomDataChanges(nbt)
}
}

View File

@ -1,32 +1,17 @@
package li.cil.oc.common.container
import cpw.mods.fml.relauncher.Side
import cpw.mods.fml.relauncher.SideOnly
import li.cil.oc.common.tileentity
import li.cil.oc.util.SideTracker
import net.minecraft.entity.player.InventoryPlayer
import net.minecraft.nbt.NBTTagCompound
class Disassembler(playerInventory: InventoryPlayer, val disassembler: tileentity.Disassembler) extends Player(playerInventory, disassembler) {
addSlotToContainer(80, 35, "ocitem")
addPlayerInventorySlots(8, 84)
var disassemblyProgress = 0.0
def disassemblyProgress = synchronizedData.getDouble("disassemblyProgress")
@SideOnly(Side.CLIENT)
override def updateProgressBar(id: Int, value: Int) {
super.updateProgressBar(id, value)
if (id == 0) {
disassemblyProgress = value / 5.0
}
}
override def detectAndSendChanges() {
super.detectAndSendChanges()
if (SideTracker.isServer) {
if (math.abs(disassembler.progress - disassemblyProgress) > 0.2) {
disassemblyProgress = disassembler.progress
sendProgressBarUpdate(0, (disassemblyProgress * 5).toInt)
}
}
override protected def detectCustomDataChanges(nbt: NBTTagCompound): Unit = {
synchronizedData.setDouble("disassemblyProgress", disassembler.progress)
super.detectCustomDataChanges(nbt)
}
}

View File

@ -28,7 +28,7 @@ class DynamicComponentSlot(val container: Player, inventory: IInventory, index:
override def getSlotStackLimit =
slot match {
case common.Slot.Tool | common.Slot.Any => super.getSlotStackLimit
case common.Slot.Tool | common.Slot.Any | common.Slot.Filtered => super.getSlotStackLimit
case common.Slot.None => 0
case _ => 1
}

View File

@ -3,14 +3,18 @@ package li.cil.oc.common.container
import li.cil.oc.common
import li.cil.oc.common.InventorySlots.InventorySlot
import li.cil.oc.common.Tier
import li.cil.oc.server.{PacketSender => ServerPacketSender}
import li.cil.oc.util.SideTracker
import net.minecraft.entity.player.EntityPlayer
import net.minecraft.entity.player.EntityPlayerMP
import net.minecraft.entity.player.InventoryPlayer
import net.minecraft.inventory.Container
import net.minecraft.inventory.ICrafting
import net.minecraft.inventory.IInventory
import net.minecraft.inventory.Slot
import net.minecraft.item.ItemStack
import net.minecraft.nbt.NBTBase
import net.minecraft.nbt.NBTTagCompound
import scala.collection.convert.WrapAsScala._
@ -133,4 +137,104 @@ abstract class Player(val playerInventory: InventoryPlayer, val otherInventory:
case _ =>
}
}
override def detectAndSendChanges(): Unit = {
super.detectAndSendChanges()
if (SideTracker.isServer) {
val nbt = new NBTTagCompound()
detectCustomDataChanges(nbt)
for (entry <- crafters) entry match {
case player: EntityPlayerMP => ServerPacketSender.sendContainerUpdate(this, nbt, player)
case _ =>
}
}
}
// Used for custom value synchronization, because shorts simply don't cut it most of the time.
protected def detectCustomDataChanges(nbt: NBTTagCompound): Unit = {
val delta = synchronizedData.getDelta
if (delta != null && !delta.hasNoTags) {
nbt.setTag("delta", delta)
}
}
def updateCustomData(nbt: NBTTagCompound): Unit = {
if (nbt.hasKey("delta")) {
val delta = nbt.getCompoundTag("delta")
delta.func_150296_c().foreach {
case key: String => synchronizedData.setTag(key, delta.getTag(key))
}
}
}
protected class SynchronizedData extends NBTTagCompound {
private var delta = new NBTTagCompound()
def getDelta: NBTTagCompound = this.synchronized {
if (delta.hasNoTags) null
else {
val result = delta
delta = new NBTTagCompound()
result
}
}
override def setTag(key: String, value: NBTBase): Unit = this.synchronized {
if (!value.equals(getTag(key))) delta.setTag(key, value)
super.setTag(key, value)
}
override def setByte(key: String, value: Byte): Unit = this.synchronized {
if (value != getByte(key)) delta.setByte(key, value)
super.setByte(key, value)
}
override def setShort(key: String, value: Short): Unit = this.synchronized {
if (value != getShort(key)) delta.setShort(key, value)
super.setShort(key, value)
}
override def setInteger(key: String, value: Int): Unit = this.synchronized {
if (value != getInteger(key)) delta.setInteger(key, value)
super.setInteger(key, value)
}
override def setLong(key: String, value: Long): Unit = this.synchronized {
if (value != getLong(key)) delta.setLong(key, value)
super.setLong(key, value)
}
override def setFloat(key: String, value: Float): Unit = this.synchronized {
if (value != getFloat(key)) delta.setFloat(key, value)
super.setFloat(key, value)
}
override def setDouble(key: String, value: Double): Unit = this.synchronized {
if (value != getDouble(key)) delta.setDouble(key, value)
super.setDouble(key, value)
}
override def setString(key: String, value: String): Unit = this.synchronized {
if (value != getString(key)) delta.setString(key, value)
super.setString(key, value)
}
override def setByteArray(key: String, value: Array[Byte]): Unit = this.synchronized {
if (value.deep != getByteArray(key).deep) delta.setByteArray(key, value)
super.setByteArray(key, value)
}
override def setIntArray(key: String, value: Array[Int]): Unit = this.synchronized {
if (value.deep != getIntArray(key).deep) delta.setIntArray(key, value)
super.setIntArray(key, value)
}
override def setBoolean(key: String, value: Boolean): Unit = this.synchronized {
if (value != getBoolean(key)) delta.setBoolean(key, value)
super.setBoolean(key, value)
}
}
protected val synchronizedData = new SynchronizedData()
}

View File

@ -0,0 +1,28 @@
package li.cil.oc.common.container
import li.cil.oc.common.Slot
import li.cil.oc.common.tileentity
import net.minecraft.entity.player.InventoryPlayer
import net.minecraft.nbt.NBTTagCompound
class Printer(playerInventory: InventoryPlayer, val printer: tileentity.Printer) extends Player(playerInventory, printer) {
addSlotToContainer(18, 19, Slot.Filtered)
addSlotToContainer(18, 51, Slot.Filtered)
addSlotToContainer(152, 35)
// Show the player's inventory.
addPlayerInventorySlots(8, 84)
def isPrinting = synchronizedData.getBoolean("isPrinting")
def amountMaterial = synchronizedData.getInteger("amountMaterial")
def amountInk = synchronizedData.getInteger("amountInk")
override protected def detectCustomDataChanges(nbt: NBTTagCompound): Unit = {
synchronizedData.setBoolean("isPrinting", printer.isPrinting)
synchronizedData.setInteger("amountMaterial", printer.amountMaterial)
synchronizedData.setInteger("amountInk", printer.amountInk)
super.detectCustomDataChanges(nbt)
}
}

View File

@ -12,7 +12,7 @@ class StaticComponentSlot(val container: Player, inventory: IInventory, index: I
override def getSlotStackLimit =
slot match {
case common.Slot.Tool | common.Slot.Any => super.getSlotStackLimit
case common.Slot.Tool | common.Slot.Any | common.Slot.Filtered => super.getSlotStackLimit
case common.Slot.None => 0
case _ => 1
}

View File

@ -1,9 +1,9 @@
package li.cil.oc.common.container
import cpw.mods.fml.common.FMLCommonHandler
import li.cil.oc.common.Slot
import li.cil.oc.common.tileentity
import net.minecraft.entity.player.InventoryPlayer
import net.minecraft.nbt.NBTTagCompound
class Switch(playerInventory: InventoryPlayer, switch: tileentity.Switch) extends Player(playerInventory, switch) {
addSlotToContainer(151, 15, Slot.CPU)
@ -11,58 +11,22 @@ class Switch(playerInventory: InventoryPlayer, switch: tileentity.Switch) extend
addSlotToContainer(151, 53, Slot.HDD)
addPlayerInventorySlots(8, 84)
var relayDelay = 0
def relayDelay = synchronizedData.getInteger("relayDelay")
var relayAmount = 0
def relayAmount = synchronizedData.getInteger("relayAmount")
var maxQueueSize = 0
def maxQueueSize = synchronizedData.getInteger("maxQueueSize")
var packetsPerCycleAvg = 0
def packetsPerCycleAvg = synchronizedData.getInteger("packetsPerCycleAvg")
var queueSize = 0
def queueSize = synchronizedData.getInteger("queueSize")
override def updateProgressBar(id: Int, value: Int) {
super.updateProgressBar(id, value)
if (id == 0) {
relayDelay = value
}
else if (id == 1) {
relayAmount = value
}
else if (id == 2) {
maxQueueSize = value
}
else if (id == 3) {
packetsPerCycleAvg = value
}
else if (id == 4) {
queueSize = value
}
}
override def detectAndSendChanges() {
super.detectAndSendChanges()
if (FMLCommonHandler.instance.getEffectiveSide.isServer) {
if (switch.relayDelay != relayDelay) {
relayDelay = switch.relayDelay
sendProgressBarUpdate(0, relayDelay)
}
if (switch.relayAmount != relayAmount) {
relayAmount = switch.relayAmount
sendProgressBarUpdate(1, relayAmount)
}
if (switch.maxQueueSize != maxQueueSize) {
maxQueueSize = switch.maxQueueSize
sendProgressBarUpdate(2, maxQueueSize)
}
if (switch.packetsPerCycleAvg() != packetsPerCycleAvg) {
packetsPerCycleAvg = switch.packetsPerCycleAvg()
sendProgressBarUpdate(3, packetsPerCycleAvg)
}
if (switch.queue.size != queueSize) {
queueSize = switch.queue.size
sendProgressBarUpdate(4, queueSize)
}
}
override protected def detectCustomDataChanges(nbt: NBTTagCompound): Unit = {
synchronizedData.setInteger("relayDelay", switch.relayDelay)
synchronizedData.setInteger("relayAmount", switch.relayAmount)
synchronizedData.setInteger("maxQueueSize", switch.maxQueueSize)
synchronizedData.setInteger("packetsPerCycleAvg", switch.packetsPerCycleAvg())
synchronizedData.setInteger("queueSize", switch.queue.size)
super.detectCustomDataChanges(nbt)
}
}

View File

@ -25,6 +25,8 @@ object Blocks {
GameRegistry.registerTileEntity(classOf[tileentity.MotionSensor], Settings.namespace + "motion_sensor")
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")
GameRegistry.registerTileEntity(classOf[tileentity.Printer], Settings.namespace + "printer")
GameRegistry.registerTileEntity(classOf[tileentity.Raid], Settings.namespace + "raid")
GameRegistry.registerTileEntity(classOf[tileentity.Redstone], Settings.namespace + "redstone")
GameRegistry.registerTileEntity(classOf[tileentity.RobotProxy], Settings.namespace + "robot")
@ -81,5 +83,9 @@ object Blocks {
// v1.4.2
Recipes.addBlock(new Raid(), "raid", "oc:raid")
Items.registerBlock(new Microcontroller(), "microcontroller")
// v1.5.4
Items.registerBlock(new Print(), "print")
Items.registerBlock(new Printer(), "printer")
}
}

View File

@ -470,5 +470,11 @@ object Items extends ItemAPI {
// 1.4.7
Recipes.addMultiItem(new item.TabletCase(multi, Tier.Two), "tabletCase2", "oc:tabletCase2")
registerItem(new item.TabletCase(multi, Tier.Four), "tabletCaseCreative")
// 1.5.4
Recipes.addMultiItem(new item.InkCartridgeEmpty(multi), "inkCartridgeEmpty", "oc:inkCartridgeEmpty")
Recipes.addMultiItem(new item.InkCartridge(multi), "inkCartridge", "oc:inkCartridge")
Recipes.addMultiItem(new item.Chamelium(multi), "chamelium", "oc:chamelium")
Recipes.addMultiItem(new item.TexturePicker(multi), "texturePicker", "oc:texturePicker")
}
}

View File

@ -0,0 +1,3 @@
package li.cil.oc.common.item
class Chamelium(val parent: Delegator) extends Delegate

View File

@ -0,0 +1,5 @@
package li.cil.oc.common.item
class InkCartridge(val parent: Delegator) extends Delegate {
override def maxStackSize = 1
}

View File

@ -0,0 +1,5 @@
package li.cil.oc.common.item
class InkCartridgeEmpty(val parent: Delegator) extends Delegate {
override def maxStackSize = 1
}

View File

@ -0,0 +1,24 @@
package li.cil.oc.common.item
import li.cil.oc.Localization
import li.cil.oc.util.BlockPosition
import li.cil.oc.util.ExtendedWorld._
import net.minecraft.block.Block
import net.minecraft.entity.player.EntityPlayer
import net.minecraft.item.ItemStack
class TexturePicker(val parent: Delegator) extends Delegate {
override def onItemUse(stack: ItemStack, player: EntityPlayer, position: BlockPosition, side: Int, hitX: Float, hitY: Float, hitZ: Float): Boolean = {
player.getEntityWorld.getBlock(position) match {
case block: Block =>
if (player.getEntityWorld.isRemote) {
val icon = block.getIcon(player.getEntityWorld, position.x, position.y, position.z, side)
if (icon != null) {
player.addChatMessage(Localization.Chat.TextureName(icon.getIconName))
}
}
true
case _ => super.onItemUse(stack, player, position, side, hitX, hitY, hitZ)
}
}
}

View File

@ -4,10 +4,6 @@ import li.cil.oc.api.Persistable
import net.minecraft.item.ItemStack
import net.minecraft.nbt.NBTTagCompound
object ItemData {
}
abstract class ItemData extends Persistable {
def load(stack: ItemStack) {
if (stack.hasTagCompound) {

View File

@ -0,0 +1,81 @@
package li.cil.oc.common.item.data
import li.cil.oc.api
import li.cil.oc.util.ExtendedNBT._
import net.minecraft.item.ItemStack
import net.minecraft.nbt.NBTTagCompound
import net.minecraft.util.AxisAlignedBB
import net.minecraftforge.common.util.Constants.NBT
import scala.collection.mutable
class PrintData extends ItemData {
def this(stack: ItemStack) {
this()
load(stack)
}
var label: Option[String] = None
var tooltip: Option[String] = None
var isButtonMode = false
var emitRedstone = false
var pressurePlate = false
val stateOff = mutable.Set.empty[PrintData.Shape]
val stateOn = mutable.Set.empty[PrintData.Shape]
override def load(nbt: NBTTagCompound): Unit = {
if (nbt.hasKey("label")) label = Option(nbt.getString("label")) else label = None
if (nbt.hasKey("tooltip")) tooltip = Option(nbt.getString("tooltip")) else tooltip = None
isButtonMode = nbt.getBoolean("isButtonMode")
emitRedstone = nbt.getBoolean("emitRedstone")
pressurePlate = nbt.getBoolean("pressurePlate")
stateOff.clear()
stateOff ++= nbt.getTagList("stateOff", NBT.TAG_COMPOUND).map(PrintData.nbtToShape)
stateOn.clear()
stateOn ++= nbt.getTagList("stateOn", NBT.TAG_COMPOUND).map(PrintData.nbtToShape)
}
override def save(nbt: NBTTagCompound): Unit = {
label.foreach(nbt.setString("label", _))
tooltip.foreach(nbt.setString("tooltip", _))
nbt.setBoolean("isButtonMode", isButtonMode)
nbt.setBoolean("emitRedstone", emitRedstone)
nbt.setBoolean("pressurePlate", pressurePlate)
nbt.setNewTagList("stateOff", stateOff.map(PrintData.shapeToNBT))
nbt.setNewTagList("stateOn", stateOn.map(PrintData.shapeToNBT))
}
def createItemStack() = {
val stack = api.Items.get("print").createItemStack(1)
save(stack)
stack
}
}
object PrintData {
def nbtToShape(nbt: NBTTagCompound): Shape = {
val minX = nbt.getByte("minX") / 16f
val minY = nbt.getByte("minY") / 16f
val minZ = nbt.getByte("minZ") / 16f
val maxX = nbt.getByte("maxX") / 16f
val maxY = nbt.getByte("maxY") / 16f
val maxZ = nbt.getByte("maxZ") / 16f
val texture = nbt.getString("texture")
new Shape(AxisAlignedBB.getBoundingBox(minX, minY, minZ, maxX, maxY, maxZ), texture)
}
def shapeToNBT(shape: Shape): NBTTagCompound = {
val nbt = new NBTTagCompound()
nbt.setByte("minX", (shape.bounds.minX * 16).round.toByte)
nbt.setByte("minY", (shape.bounds.minY * 16).round.toByte)
nbt.setByte("minZ", (shape.bounds.minZ * 16).round.toByte)
nbt.setByte("maxX", (shape.bounds.maxX * 16).round.toByte)
nbt.setByte("maxY", (shape.bounds.maxY * 16).round.toByte)
nbt.setByte("maxZ", (shape.bounds.maxZ * 16).round.toByte)
nbt.setString("texture", shape.texture)
nbt
}
class Shape(val bounds: AxisAlignedBB, val texture: String)
}

View File

@ -0,0 +1,95 @@
package li.cil.oc.common.tileentity
import cpw.mods.fml.relauncher.Side
import cpw.mods.fml.relauncher.SideOnly
import li.cil.oc.common.item.data.PrintData
import li.cil.oc.util.ExtendedAABB
import li.cil.oc.util.ExtendedAABB._
import li.cil.oc.util.ExtendedNBT._
import net.minecraft.nbt.NBTTagCompound
import net.minecraftforge.common.util.ForgeDirection
class Print extends traits.TileEntity with traits.RedstoneAware with traits.Rotatable {
val data = new PrintData()
var boundsOff = ExtendedAABB.unitBounds
var boundsOn = ExtendedAABB.unitBounds
var state = false
_isOutputEnabled = true
def activate(): Boolean = {
if (data.stateOn.size > 0) {
if (!state || !data.isButtonMode) {
toggleState()
return true
}
}
false
}
def toggleState(): Unit = {
state = !state
world.playSoundEffect(x + 0.5, y + 0.5, z + 0.5, "random.click", 0.3F, if (state) 0.6F else 0.5F)
world.markBlockForUpdate(x, y, z)
if (data.emitRedstone) {
ForgeDirection.VALID_DIRECTIONS.foreach(output(_, if (state) 15 else 0))
}
if (state && data.isButtonMode) {
world.scheduleBlockUpdate(x, y, z, block, block.tickRate(world))
}
}
override def canUpdate = false
override protected def onRedstoneInputChanged(side: ForgeDirection, oldMaxValue: Int, newMaxValue: Int): Unit = {
super.onRedstoneInputChanged(side, oldMaxValue, newMaxValue)
if (!data.emitRedstone && data.stateOn.size > 0) {
state = newMaxValue > 0
world.playSoundEffect(x + 0.5, y + 0.5, z + 0.5, "random.click", 0.3F, if (state) 0.6F else 0.5F)
world.markBlockForUpdate(x, y, z)
}
}
override def readFromNBTForServer(nbt: NBTTagCompound): Unit = {
super.readFromNBTForServer(nbt)
data.load(nbt.getCompoundTag("data"))
state = nbt.getBoolean("state")
updateBounds()
}
override def writeToNBTForServer(nbt: NBTTagCompound): Unit = {
super.writeToNBTForServer(nbt)
nbt.setNewCompoundTag("data", data.save)
nbt.setBoolean("state", state)
}
@SideOnly(Side.CLIENT)
override def readFromNBTForClient(nbt: NBTTagCompound): Unit = {
super.readFromNBTForClient(nbt)
data.load(nbt.getCompoundTag("data"))
state = nbt.getBoolean("state")
updateBounds()
world.markBlockForUpdate(x, y, z)
}
override def writeToNBTForClient(nbt: NBTTagCompound): Unit = {
super.writeToNBTForClient(nbt)
nbt.setNewCompoundTag("data", data.save)
nbt.setBoolean("state", state)
}
def updateBounds(): Unit = {
boundsOff = data.stateOff.drop(1).foldLeft(data.stateOff.headOption.fold(ExtendedAABB.unitBounds)(_.bounds))((a, b) => a.func_111270_a(b.bounds))
if (boundsOff.volume == 0) boundsOff = ExtendedAABB.unitBounds
else boundsOff = boundsOff.rotateTowards(facing)
boundsOn = data.stateOn.drop(1).foldLeft(data.stateOn.headOption.fold(ExtendedAABB.unitBounds)(_.bounds))((a, b) => a.func_111270_a(b.bounds))
if (boundsOn.volume == 0) boundsOn = ExtendedAABB.unitBounds
else boundsOn = boundsOn.rotateTowards(facing)
}
override protected def onRotationChanged(): Unit = {
super.onRotationChanged()
updateBounds()
}
}

View File

@ -0,0 +1,307 @@
package li.cil.oc.common.tileentity
import java.util
import cpw.mods.fml.relauncher.Side
import cpw.mods.fml.relauncher.SideOnly
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._
import li.cil.oc.common.item.data.PrintData
import li.cil.oc.server.{PacketSender => ServerPacketSender}
import li.cil.oc.util.ExtendedAABB._
import li.cil.oc.util.ExtendedNBT._
import li.cil.oc.util.ItemUtils
import net.minecraft.item.ItemStack
import net.minecraft.nbt.NBTTagCompound
import net.minecraft.util.AxisAlignedBB
import net.minecraftforge.common.util.ForgeDirection
class Printer extends traits.Environment with traits.Inventory with traits.Rotatable with SidedEnvironment with traits.StateAware {
val node = api.Network.newNode(this, Visibility.Network).
withComponent("printer3d").
withConnector(Settings.get.bufferConverter).
create()
val maxAmountMaterial = 256000
var amountMaterial = 0
val maxAmountInk = 100000
var amountInk = 0
var data = new PrintData()
var isActive = false
var output: Option[ItemStack] = None
var totalRequiredEnergy = 0.0
var requiredEnergy = 0.0
val materialPerItem = 2000
val inkPerCartridge = 50000
val slotMaterial = 0
val slotInk = 1
val slotOutput = 2
// ----------------------------------------------------------------------- //
@SideOnly(Side.CLIENT)
override def canConnect(side: ForgeDirection) = side != ForgeDirection.UP
override def sidedNode(side: ForgeDirection) = if (side != ForgeDirection.UP) node else null
override def currentState = {
if (isPrinting) util.EnumSet.of(traits.State.IsWorking)
else if (canPrint) util.EnumSet.of(traits.State.CanWork)
else util.EnumSet.noneOf(classOf[traits.State])
}
// ----------------------------------------------------------------------- //
def canPrint = data.stateOff.size > 0 && data.stateOff.size + data.stateOn.size <= Settings.get.maxPrintComplexity
def isPrinting = (requiredEnergy > 0 || isActive) && Option(getStackInSlot(slotOutput)).fold(true)(stack => {
stack.stackSize < stack.getMaxStackSize && output.fold(true)(ItemStack.areItemStackTagsEqual(stack, _))
})
def progress = (1 - requiredEnergy / totalRequiredEnergy) * 100
def timeRemaining = (requiredEnergy / Settings.get.assemblerTickAmount / 20).toInt
// ----------------------------------------------------------------------- //
@Callback(doc = """function() -- Resets the configuration of the printer and stop printing (current job will finish).""")
def reset(context: Context, args: Arguments): Array[Object] = {
data = new PrintData()
isActive = false // Needs committing.
null
}
@Callback(doc = """function(value:string) -- Set a label for the block being printed.""")
def setLabel(context: Context, args: Arguments): Array[Object] = {
data.label = Option(args.optString(0, null)).map(_.take(24))
if (data.label.fold(false)(_.isEmpty)) data.label = None
isActive = false // Needs committing.
null
}
@Callback(doc = """function():string -- Get the current label for the block being printed.""")
def getLabel(context: Context, args: Arguments): Array[Object] = {
result(data.label.orNull)
}
@Callback(doc = """function(value:string) -- Set a tooltip for the block being printed.""")
def setTooltip(context: Context, args: Arguments): Array[Object] = {
data.tooltip = Option(args.optString(0, null)).map(_.take(128))
if (data.tooltip.fold(false)(_.isEmpty)) data.tooltip = None
isActive = false // Needs committing.
null
}
@Callback(doc = """function():string -- Get the current tooltip for the block being printed.""")
def getTooltip(context: Context, args: Arguments): Array[Object] = {
result(data.tooltip.orNull)
}
@Callback(doc = """function(value:boolean) -- Set whether the printed block should emit redstone when in its active state.""")
def setRedstoneEmitter(context: Context, args: Arguments): Array[Object] = {
data.emitRedstone = args.checkBoolean(0)
isActive = false // Needs committing.
null
}
@Callback(doc = """function():boolean -- Get whether the printed block should emit redstone when in its active state.""")
def isRedstoneEmitter(context: Context, args: Arguments): Array[Object] = {
result(data.emitRedstone)
}
@Callback(doc = """function(value:boolean) -- Set whether the printed block should automatically return to its off state.""")
def setButtonMode(context: Context, args: Arguments): Array[Object] = {
data.isButtonMode = args.checkBoolean(0)
isActive = false // Needs committing.
null
}
@Callback(doc = """function():boolean -- Get whether the printed block should automatically return to its off state.""")
def isButtonMode(context: Context, args: Arguments): Array[Object] = {
result(data.isButtonMode)
}
@Callback(doc = """function(minX:number, minY:number, minZ:number, maxX:number, maxY:number, maxZ:number, texture:string[, state:boolean=false]) -- Adds a shape to the printers configuration, optionally specifying whether it is for the off or on state.""")
def addShape(context: Context, args: Arguments): Array[Object] = {
if (data.stateOff.size + data.stateOn.size >= Settings.get.maxPrintComplexity) {
return result(null, "model too complex")
}
val minX = (args.checkInteger(0) max 0 min 16) / 16f
val minY = (args.checkInteger(1) max 0 min 16) / 16f
val minZ = (16 - (args.checkInteger(2) max 0 min 16)) / 16f
val maxX = (args.checkInteger(3) max 0 min 16) / 16f
val maxY = (args.checkInteger(4) max 0 min 16) / 16f
val maxZ = (16 - (args.checkInteger(5) max 0 min 16)) / 16f
val texture = args.checkString(6).take(64)
val state = args.checkAny(7) != null && args.optBoolean(7, false)
if (minX == maxX) throw new IllegalArgumentException("empty block")
if (minY == maxY) throw new IllegalArgumentException("empty block")
if (minZ == maxZ) throw new IllegalArgumentException("empty block")
val list = if (state) data.stateOn else data.stateOff
list += new PrintData.Shape(AxisAlignedBB.getBoundingBox(
math.min(minX, maxX),
math.min(minY, maxY),
math.min(minZ, maxZ),
math.max(maxX, minX),
math.max(maxY, minY),
math.max(maxZ, minZ)), texture)
isActive = false // Needs committing.
world.markBlockForUpdate(x, y, z)
result(true)
}
@Callback(doc = """function():number -- Get the number of shapes in the current configuration.""")
def getShapeCount(context: Context, args: Arguments): Array[Object] = result(data.stateOff.size + data.stateOn.size)
@Callback(doc = """function():number -- Get the maximum allowed number of shapes.""")
def getMaxShapeCount(context: Context, args: Arguments): Array[Object] = result(Settings.get.maxPrintComplexity)
@Callback(doc = """function():boolean -- Commit and begin printing the current configuration.""")
def commit(context: Context, args: Arguments): Array[Object] = {
if (!canPrint) {
return result(null, "model invalid")
}
isActive = true
result(true)
}
@Callback(doc = """function(): string, number or boolean -- The current state of the printer, `busy' or `idle', followed by the progress or model validity, respectively.""")
def status(context: Context, args: Arguments): Array[Object] = {
if (isPrinting) result("busy", progress)
else if (canPrint) result("idle", true)
else result("idle", false)
}
// ----------------------------------------------------------------------- //
override def canUpdate = isServer
// ----------------------------------------------------------------------- //
override def updateEntity() {
super.updateEntity()
if (isActive && output.isEmpty && Option(getStackInSlot(slotOutput)).fold(true)(stack => stack.stackSize < stack.getMaxStackSize)) {
val totalVolume = data.stateOn.foldLeft(0)((acc, shape) => acc + shape.bounds.volume) + data.stateOff.foldLeft(0)((acc, shape) => acc + shape.bounds.volume)
val totalSurface = data.stateOn.foldLeft(0)((acc, shape) => acc + shape.bounds.surface) + data.stateOff.foldLeft(0)((acc, shape) => acc + shape.bounds.surface)
if (totalVolume == 0) {
isActive = false
data = new PrintData()
}
else {
val materialRequired = (totalVolume / 2) max 1
val inkRequired = (totalSurface / 6) max 1
totalRequiredEnergy = Settings.get.printCost
requiredEnergy = totalRequiredEnergy
if (amountMaterial >= materialRequired && amountInk >= inkRequired) {
amountMaterial -= materialRequired
amountInk -= inkRequired
output = Option(data.createItemStack())
ServerPacketSender.sendPrinting(this, printing = true)
}
}
}
if (output.isDefined) {
val want = math.max(1, math.min(requiredEnergy, Settings.get.printerTickAmount))
val success = Settings.get.ignorePower || node.tryChangeBuffer(-want)
if (success) {
requiredEnergy -= want
}
if (requiredEnergy <= 0) {
val result = getStackInSlot(slotOutput)
if (result == null) {
setInventorySlotContents(slotOutput, output.get)
}
else if (output.get.isItemEqual(result) && ItemStack.areItemStackTagsEqual(output.get, result) && result.stackSize < result.getMaxStackSize) {
result.stackSize += 1
markDirty()
}
else {
return
}
requiredEnergy = 0
output = None
}
ServerPacketSender.sendPrinting(this, success && output.isDefined)
}
if (maxAmountMaterial - amountMaterial >= materialPerItem) {
val material = decrStackSize(slotMaterial, 1)
if (material != null) {
amountMaterial += materialPerItem
}
}
if (maxAmountInk - amountInk >= inkPerCartridge) {
if (api.Items.get(getStackInSlot(slotInk)) == api.Items.get("inkCartridge")) {
setInventorySlotContents(slotInk, api.Items.get("inkCartridgeEmpty").createItemStack(1))
amountInk += inkPerCartridge
}
}
}
override def readFromNBTForServer(nbt: NBTTagCompound) {
super.readFromNBTForServer(nbt)
amountMaterial = nbt.getInteger(Settings.namespace + "amountMaterial")
amountInk = nbt.getInteger(Settings.namespace + "amountInk")
data.load(nbt.getCompoundTag(Settings.namespace + "data"))
isActive = nbt.getBoolean(Settings.namespace + "active")
if (nbt.hasKey(Settings.namespace + "output")) {
output = Option(ItemUtils.loadStack(nbt.getCompoundTag(Settings.namespace + "output")))
}
totalRequiredEnergy = nbt.getDouble(Settings.namespace + "total")
requiredEnergy = nbt.getDouble(Settings.namespace + "remaining")
}
override def writeToNBTForServer(nbt: NBTTagCompound) {
super.writeToNBTForServer(nbt)
nbt.setInteger(Settings.namespace + "amountMaterial", amountMaterial)
nbt.setInteger(Settings.namespace + "amountInk", amountInk)
nbt.setNewCompoundTag(Settings.namespace + "data", data.save)
nbt.setBoolean(Settings.namespace + "active", isActive)
output.foreach(stack => nbt.setNewCompoundTag(Settings.namespace + "output", stack.writeToNBT))
nbt.setDouble(Settings.namespace + "total", totalRequiredEnergy)
nbt.setDouble(Settings.namespace + "remaining", requiredEnergy)
}
@SideOnly(Side.CLIENT) override
def readFromNBTForClient(nbt: NBTTagCompound) {
super.readFromNBTForClient(nbt)
data.load(nbt.getCompoundTag(Settings.namespace + "data"))
requiredEnergy = nbt.getDouble("remaining")
}
override def writeToNBTForClient(nbt: NBTTagCompound) {
super.writeToNBTForClient(nbt)
nbt.setNewCompoundTag(Settings.namespace + "data", data.save)
nbt.setDouble("remaining", requiredEnergy)
}
// ----------------------------------------------------------------------- //
override def getSizeInventory = 3
override def getInventoryStackLimit = 64
override def isItemValidForSlot(slot: Int, stack: ItemStack) =
if (slot == 0)
api.Items.get(stack) == api.Items.get("chamelium")
else if (slot == 1)
api.Items.get(stack) == api.Items.get("inkCartridge")
else false
}

View File

@ -75,7 +75,7 @@ trait RedstoneAware extends RotationAware with IConnectable with IRedstoneEmitte
}
}
protected def updateRedstoneInput(side: ForgeDirection) {
def updateRedstoneInput(side: ForgeDirection) {
val oldInput = _input(side.ordinal())
val newInput = computeInput(side)
_input(side.ordinal()) = newInput

View File

@ -9,6 +9,7 @@ import li.cil.oc.common.tileentity.traits._
import li.cil.oc.util.BlockPosition
import li.cil.oc.util.PackedColor
import net.minecraft.entity.player.EntityPlayerMP
import net.minecraft.inventory.Container
import net.minecraft.item.ItemStack
import net.minecraft.nbt.CompressedStreamTools
import net.minecraft.nbt.NBTTagCompound
@ -74,6 +75,17 @@ object PacketSender {
pb.sendToPlayersNearTileEntity(t)
}
def sendContainerUpdate(c: Container, nbt: NBTTagCompound, player: EntityPlayerMP): Unit = {
if (!nbt.hasNoTags) {
val pb = new SimplePacketBuilder(PacketType.ContainerUpdate)
pb.writeByte(c.windowId.toByte)
pb.writeNBT(nbt)
pb.sendToPlayer(player)
}
}
def sendDisassemblerActive(t: tileentity.Disassembler, active: Boolean) {
val pb = new SimplePacketBuilder(PacketType.DisassemblerActiveChange)
@ -226,6 +238,15 @@ object PacketSender {
pb.sendToPlayersNearTileEntity(t)
}
def sendPrinting(t: tileentity.Printer, printing: Boolean) {
val pb = new SimplePacketBuilder(PacketType.PrinterState)
pb.writeTileEntity(t)
pb.writeBoolean(printing)
pb.sendToPlayersNearHost(t)
}
def sendRaidChange(t: tileentity.Raid) {
val pb = new SimplePacketBuilder(PacketType.RaidStateChange)

View File

@ -0,0 +1,51 @@
package li.cil.oc.util
import net.minecraft.util.AxisAlignedBB
import net.minecraft.util.Vec3
import net.minecraftforge.common.util.ForgeDirection
import scala.language.implicitConversions
object ExtendedAABB {
implicit def extendedAABB(bounds: AxisAlignedBB): ExtendedAABB = new ExtendedAABB(bounds)
def unitBounds = AxisAlignedBB.getBoundingBox(0, 0, 0, 1, 1, 1)
class ExtendedAABB(val bounds: AxisAlignedBB) {
def volume: Int = {
val sx = ((bounds.maxX - bounds.minX) * 16).round.toInt
val sy = ((bounds.maxY - bounds.minY) * 16).round.toInt
val sz = ((bounds.maxZ - bounds.minZ) * 16).round.toInt
sx * sy * sz
}
def surface: Int = {
val sx = ((bounds.maxX - bounds.minX) * 16).round.toInt
val sy = ((bounds.maxY - bounds.minY) * 16).round.toInt
val sz = ((bounds.maxZ - bounds.minZ) * 16).round.toInt
sx * sy * 2 + sx * sz * 2 + sy * sz * 2
}
def rotateTowards(facing: ForgeDirection) = rotateY(facing match {
case ForgeDirection.WEST => 3
case ForgeDirection.NORTH => 2
case ForgeDirection.EAST => 1
case _ => 0
})
def rotateY(count: Int): AxisAlignedBB = {
val min = Vec3.createVectorHelper(bounds.minX - 0.5, bounds.minY - 0.5, bounds.minZ - 0.5)
val max = Vec3.createVectorHelper(bounds.maxX - 0.5, bounds.maxY - 0.5, bounds.maxZ - 0.5)
min.rotateAroundY(count * Math.PI.toFloat * 0.5f)
max.rotateAroundY(count * Math.PI.toFloat * 0.5f)
AxisAlignedBB.getBoundingBox(
(math.min(min.xCoord + 0.5, max.xCoord + 0.5) * 32).round / 32f,
(math.min(min.yCoord + 0.5, max.yCoord + 0.5) * 32).round / 32f,
(math.min(min.zCoord + 0.5, max.zCoord + 0.5) * 32).round / 32f,
(math.max(min.xCoord + 0.5, max.xCoord + 0.5) * 32).round / 32f,
(math.max(min.yCoord + 0.5, max.yCoord + 0.5) * 32).round / 32f,
(math.max(min.zCoord + 0.5, max.zCoord + 0.5) * 32).round / 32f)
}
}
}