diff --git a/assets/items.psd b/assets/items.psd index 6856b63bd..9eaa421ec 100644 Binary files a/assets/items.psd and b/assets/items.psd differ diff --git a/src/main/resources/application.conf b/src/main/resources/application.conf index f68159751..f3a84f3ba 100644 --- a/src/main/resources/application.conf +++ b/src/main/resources/application.conf @@ -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: 10 + # 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 diff --git a/src/main/resources/assets/opencomputers/lang/en_US.lang b/src/main/resources/assets/opencomputers/lang/en_US.lang index 5de7bef65..629e1551e 100644 --- a/src/main/resources/assets/opencomputers/lang/en_US.lang +++ b/src/main/resources/assets/opencomputers/lang/en_US.lang @@ -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 @@ -66,6 +68,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 @@ -84,6 +88,7 @@ item.oc.MicrocontrollerCase1.name=Microcontroller Case (Tier 2) item.oc.MicrocontrollerCase3.name=Microcontroller Case (Creative) item.oc.NetworkCard.name=Network Card item.oc.NumPad.name=Numeric Keypad +item.oc.Plastic.name=Plastic item.oc.Present.name=A little something... item.oc.PrintedCircuitBoard.name=Printed Circuit Board (PCB) item.oc.RawCircuitBoard.name=Raw Circuit Board @@ -197,6 +202,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 @@ -237,6 +243,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... @@ -253,6 +261,7 @@ oc:tooltip.Microcontroller=Microcontrollers are computers boiled down to the ess oc:tooltip.MicrocontrollerCase=Base component for building microcontrollers. Place it into an assembler to add further components and assemble a microcontroller. oc:tooltip.MotionSensor=Can detect movement of nearby living beings. Requires clear line-of-sight. oc:tooltip.NetworkCard=Allows distant computers connected by other blocks (such as cable) to communicate by sending messages to each other. +oc:tooltip.Plastic=Raw material for 3D prints. Do not swallow. Not that you could even if you wanted to. oc:tooltip.PowerAcceptor=Energy conversion speed: §f%s/t§7 oc:tooltip.PowerConverter.BuildCraft=§fBuildCraft MJ§7: §a%s:%s§7 oc:tooltip.PowerConverter.Factorization=§fFactorization Charge§7: §a%s:%s§7 @@ -262,6 +271,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 plastic 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. diff --git a/src/main/resources/assets/opencomputers/recipes/default.recipes b/src/main/resources/assets/opencomputers/recipes/default.recipes index 6cb743bcd..b85a2a94b 100644 --- a/src/main/resources/assets/opencomputers/recipes/default.recipes +++ b/src/main/resources/assets/opencomputers/recipes/default.recipes @@ -318,6 +318,21 @@ disk { [nuggetIron, "", nuggetIron] ["", nuggetIron, ""]] } +plastic { + input: [[gravel, gravel, gravel], + [gravel, {item=coal, subID=1}, gravel], + [gravel, water_bucket, gravel]] + output: 8 +} +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] diff --git a/src/main/resources/assets/opencomputers/textures/gui/printer_ink.png b/src/main/resources/assets/opencomputers/textures/gui/printer_ink.png new file mode 100644 index 000000000..b125722a7 Binary files /dev/null and b/src/main/resources/assets/opencomputers/textures/gui/printer_ink.png differ diff --git a/src/main/resources/assets/opencomputers/textures/gui/printer_plastic.png b/src/main/resources/assets/opencomputers/textures/gui/printer_plastic.png new file mode 100644 index 000000000..3f67324d2 Binary files /dev/null and b/src/main/resources/assets/opencomputers/textures/gui/printer_plastic.png differ diff --git a/src/main/resources/assets/opencomputers/textures/gui/printer_progress.png b/src/main/resources/assets/opencomputers/textures/gui/printer_progress.png index a4df8cc55..919b987d9 100644 Binary files a/src/main/resources/assets/opencomputers/textures/gui/printer_progress.png and b/src/main/resources/assets/opencomputers/textures/gui/printer_progress.png differ diff --git a/src/main/resources/assets/opencomputers/textures/items/InkCartridge.png b/src/main/resources/assets/opencomputers/textures/items/InkCartridge.png new file mode 100644 index 000000000..a2b92d00b Binary files /dev/null and b/src/main/resources/assets/opencomputers/textures/items/InkCartridge.png differ diff --git a/src/main/resources/assets/opencomputers/textures/items/InkCartridgeEmpty.png b/src/main/resources/assets/opencomputers/textures/items/InkCartridgeEmpty.png new file mode 100644 index 000000000..007697d69 Binary files /dev/null and b/src/main/resources/assets/opencomputers/textures/items/InkCartridgeEmpty.png differ diff --git a/src/main/resources/assets/opencomputers/textures/items/Plastic.png b/src/main/resources/assets/opencomputers/textures/items/Plastic.png new file mode 100644 index 000000000..914588f6b Binary files /dev/null and b/src/main/resources/assets/opencomputers/textures/items/Plastic.png differ diff --git a/src/main/scala/li/cil/oc/Settings.scala b/src/main/scala/li/cil/oc/Settings.scala index 73a96a9f7..3cc13b778 100644 --- a/src/main/scala/li/cil/oc/Settings.scala +++ b/src/main/scala/li/cil/oc/Settings.scala @@ -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 diff --git a/src/main/scala/li/cil/oc/client/PacketHandler.scala b/src/main/scala/li/cil/oc/client/PacketHandler.scala index da0dc4f38..b4d7162c6 100644 --- a/src/main/scala/li/cil/oc/client/PacketHandler.scala +++ b/src/main/scala/li/cil/oc/client/PacketHandler.scala @@ -52,6 +52,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) @@ -242,6 +243,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) => diff --git a/src/main/scala/li/cil/oc/client/Textures.scala b/src/main/scala/li/cil/oc/client/Textures.scala index 4d02efe8f..19e3ce67d 100644 --- a/src/main/scala/li/cil/oc/client/Textures.scala +++ b/src/main/scala/li/cil/oc/client/Textures.scala @@ -26,6 +26,8 @@ object Textures { 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 guiPrinterPlastic = new ResourceLocation(Settings.resourceDomain, "textures/gui/printer_plastic.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") diff --git a/src/main/scala/li/cil/oc/client/gui/Printer.scala b/src/main/scala/li/cil/oc/client/gui/Printer.scala index 3ad735a26..d5217af59 100644 --- a/src/main/scala/li/cil/oc/client/gui/Printer.scala +++ b/src/main/scala/li/cil/oc/client/gui/Printer.scala @@ -3,19 +3,31 @@ 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.client.{PacketSender => ClientPacketSender} 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 net.minecraft.util.ResourceLocation 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 progress = addWidget(new ProgressBar(104, 21) { + private val plasticBar = addWidget(new ProgressBar(40, 21) { + override def width = 62 + + override def height = 12 + + override def barTexture = Textures.guiPrinterPlastic + }) + 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 @@ -23,7 +35,7 @@ class Printer(playerInventory: InventoryPlayer, val printer: tileentity.Printer) override def barTexture = Textures.guiPrinterProgress }) - private def assemblerContainer = inventorySlots.asInstanceOf[container.Printer] + private def printerContainer = inventorySlots.asInstanceOf[container.Printer] override def initGui() { super.initGui() @@ -35,27 +47,27 @@ class Printer(playerInventory: InventoryPlayer, val printer: tileentity.Printer) Localization.localizeImmediately(printer.getInventoryName), 8, 6, 0x404040) GL11.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS) // Me lazy... prevents NEI render glitch. - if (assemblerContainer.isAssembling && func_146978_c(progress.x, progress.y, progress.width, progress.height, mouseX, mouseY)) { + if (func_146978_c(plasticBar.x, plasticBar.y, plasticBar.width, plasticBar.height, mouseX, mouseY)) { val tooltip = new java.util.ArrayList[String] - val timeRemaining = formatTime(assemblerContainer.assemblyRemainingTime) - tooltip.add(Localization.Assembler.Progress(assemblerContainer.assemblyProgress, timeRemaining)) + tooltip.add(printerContainer.amountPlastic + "/" + printer.maxAmountPlastic) + 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() } - private def formatTime(seconds: Int) = { - // Assembly times should not / rarely exceed one hour, so this is good enough. - if (seconds < 60) f"0:$seconds%02d" - else f"${seconds / 60}:${seconds % 60}%02d" - } - 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) - if (assemblerContainer.isAssembling) progress.level = assemblerContainer.assemblyProgress / 100.0 - else progress.level = 0 + plasticBar.level = printerContainer.amountPlastic / printer.maxAmountPlastic.toDouble + inkBar.level = printerContainer.amountInk / printer.maxAmountInk.toDouble + if (printerContainer.isPrinting) progressBar.level = (System.currentTimeMillis() % 3000) / 3000.0 + else progressBar.level = 0 drawWidgets() drawInventorySlots() } diff --git a/src/main/scala/li/cil/oc/client/gui/widget/ProgressBar.scala b/src/main/scala/li/cil/oc/client/gui/widget/ProgressBar.scala index 22541fbe5..4a049d221 100644 --- a/src/main/scala/li/cil/oc/client/gui/widget/ProgressBar.scala +++ b/src/main/scala/li/cil/oc/client/gui/widget/ProgressBar.scala @@ -16,8 +16,8 @@ class ProgressBar(val x: Int, val y: Int) extends Widget { 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 diff --git a/src/main/scala/li/cil/oc/common/PacketType.scala b/src/main/scala/li/cil/oc/common/PacketType.scala index 6a0a0f201..f2f16c868 100644 --- a/src/main/scala/li/cil/oc/common/PacketType.scala +++ b/src/main/scala/li/cil/oc/common/PacketType.scala @@ -20,6 +20,7 @@ object PacketType extends Enumeration { HologramTranslation, PetVisibility, // Goes both ways. PowerState, + PrinterState, RaidStateChange, RedstoneState, RobotAnimateSwing, diff --git a/src/main/scala/li/cil/oc/common/Slot.scala b/src/main/scala/li/cil/oc/common/Slot.scala index 4cbb05bd6..fed8e914b 100644 --- a/src/main/scala/li/cil/oc/common/Slot.scala +++ b/src/main/scala/li/cil/oc/common/Slot.scala @@ -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 diff --git a/src/main/scala/li/cil/oc/common/block/Item.scala b/src/main/scala/li/cil/oc/common/block/Item.scala index 022012ada..42a121d6b 100644 --- a/src/main/scala/li/cil/oc/common/block/Item.scala +++ b/src/main/scala/li/cil/oc/common/block/Item.scala @@ -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" diff --git a/src/main/scala/li/cil/oc/common/block/Print.scala b/src/main/scala/li/cil/oc/common/block/Print.scala index f28a8540f..5fe0b37bc 100644 --- a/src/main/scala/li/cil/oc/common/block/Print.scala +++ b/src/main/scala/li/cil/oc/common/block/Print.scala @@ -1,6 +1,9 @@ package li.cil.oc.common.block +import java.util + import li.cil.oc.Settings +import li.cil.oc.common.item.data.PrintData import li.cil.oc.common.tileentity import li.cil.oc.util.ExtendedAABB import net.minecraft.entity.EntityLivingBase @@ -11,6 +14,7 @@ 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 SimpleBlock with traits.SpecialBlock with traits.CustomDrops[tileentity.Print] { @@ -19,6 +23,12 @@ class Print(protected implicit val tileTag: ClassTag[tileentity.Print]) extends // 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) = true diff --git a/src/main/scala/li/cil/oc/common/block/Printer.scala b/src/main/scala/li/cil/oc/common/block/Printer.scala index d0be27b26..5f56b939e 100644 --- a/src/main/scala/li/cil/oc/common/block/Printer.scala +++ b/src/main/scala/li/cil/oc/common/block/Printer.scala @@ -9,7 +9,7 @@ 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.PowerAcceptor with traits.StateAware with traits.GUI { +class Printer extends SimpleBlock with traits.SpecialBlock with traits.StateAware with traits.GUI { override protected def customTextures = Array( None, Some("AssemblerTop"), @@ -32,8 +32,6 @@ class Printer extends SimpleBlock with traits.SpecialBlock with traits.PowerAcce // ----------------------------------------------------------------------- // - override def energyThroughput = Settings.get.assemblerRate - override def guiType = GuiType.Printer override def hasTileEntity(metadata: Int) = true diff --git a/src/main/scala/li/cil/oc/common/container/DynamicComponentSlot.scala b/src/main/scala/li/cil/oc/common/container/DynamicComponentSlot.scala index 0d296d213..bc96137b4 100644 --- a/src/main/scala/li/cil/oc/common/container/DynamicComponentSlot.scala +++ b/src/main/scala/li/cil/oc/common/container/DynamicComponentSlot.scala @@ -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 } diff --git a/src/main/scala/li/cil/oc/common/container/Printer.scala b/src/main/scala/li/cil/oc/common/container/Printer.scala index c50c50acf..b9172c9d1 100644 --- a/src/main/scala/li/cil/oc/common/container/Printer.scala +++ b/src/main/scala/li/cil/oc/common/container/Printer.scala @@ -2,51 +2,53 @@ package li.cil.oc.common.container import cpw.mods.fml.relauncher.Side import cpw.mods.fml.relauncher.SideOnly +import li.cil.oc.common.Slot import li.cil.oc.common.tileentity import li.cil.oc.util.SideTracker import net.minecraft.entity.player.InventoryPlayer class Printer(playerInventory: InventoryPlayer, val printer: tileentity.Printer) extends Player(playerInventory, printer) { - addSlotToContainer(18, 19) - addSlotToContainer(18, 51) + addSlotToContainer(18, 19, Slot.Filtered) + addSlotToContainer(18, 51, Slot.Filtered) addSlotToContainer(152, 35) // Show the player's inventory. addPlayerInventorySlots(8, 84) - var isAssembling = false - var assemblyProgress = 0.0 - var assemblyRemainingTime = 0 + var isPrinting = false + var amountPlastic = 0 + var amountInk = 0 @SideOnly(Side.CLIENT) override def updateProgressBar(id: Int, value: Int) { super.updateProgressBar(id, value) if (id == 0) { - isAssembling = value == 1 + isPrinting = value == 1 } if (id == 1) { - assemblyProgress = value / 5.0 + amountPlastic = value } if (id == 2) { - assemblyRemainingTime = value + amountInk = value } } override def detectAndSendChanges() { super.detectAndSendChanges() if (SideTracker.isServer) { - if (isAssembling != printer.isAssembling) { - isAssembling = printer.isAssembling - sendProgressBarUpdate(0, if (isAssembling) 1 else 0) + if (isPrinting != printer.isPrinting) { + isPrinting = printer.isPrinting + sendProgressBarUpdate(0, if (isPrinting) 1 else 0) } - val timeRemaining = printer.timeRemaining - if (math.abs(printer.progress - assemblyProgress) > 0.2 || assemblyRemainingTime != timeRemaining) { - assemblyProgress = printer.progress - assemblyRemainingTime = timeRemaining - sendProgressBarUpdate(1, (assemblyProgress * 5).toInt) - sendProgressBarUpdate(2, timeRemaining) + if (amountPlastic != printer.amountPlastic) { + amountPlastic = printer.amountPlastic + sendProgressBarUpdate(1, amountPlastic) + } + if (amountInk != printer.amountInk) { + amountInk = printer.amountInk + sendProgressBarUpdate(2, amountInk) } } } diff --git a/src/main/scala/li/cil/oc/common/container/StaticComponentSlot.scala b/src/main/scala/li/cil/oc/common/container/StaticComponentSlot.scala index 0155308b4..ea7bae721 100644 --- a/src/main/scala/li/cil/oc/common/container/StaticComponentSlot.scala +++ b/src/main/scala/li/cil/oc/common/container/StaticComponentSlot.scala @@ -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 } diff --git a/src/main/scala/li/cil/oc/common/init/Items.scala b/src/main/scala/li/cil/oc/common/init/Items.scala index 88fb189e5..960dac1ce 100644 --- a/src/main/scala/li/cil/oc/common/init/Items.scala +++ b/src/main/scala/li/cil/oc/common/init/Items.scala @@ -470,5 +470,10 @@ 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.Plastic(multi), "plastic", "oc:plastic") } } diff --git a/src/main/scala/li/cil/oc/common/item/InkCartridge.scala b/src/main/scala/li/cil/oc/common/item/InkCartridge.scala new file mode 100644 index 000000000..363af10c2 --- /dev/null +++ b/src/main/scala/li/cil/oc/common/item/InkCartridge.scala @@ -0,0 +1,5 @@ +package li.cil.oc.common.item + +class InkCartridge(val parent: Delegator) extends Delegate { + override def maxStackSize = 1 +} diff --git a/src/main/scala/li/cil/oc/common/item/InkCartridgeEmpty.scala b/src/main/scala/li/cil/oc/common/item/InkCartridgeEmpty.scala new file mode 100644 index 000000000..913460404 --- /dev/null +++ b/src/main/scala/li/cil/oc/common/item/InkCartridgeEmpty.scala @@ -0,0 +1,5 @@ +package li.cil.oc.common.item + +class InkCartridgeEmpty(val parent: Delegator) extends Delegate { + override def maxStackSize = 1 +} diff --git a/src/main/scala/li/cil/oc/common/item/Plastic.scala b/src/main/scala/li/cil/oc/common/item/Plastic.scala new file mode 100644 index 000000000..ead7618ac --- /dev/null +++ b/src/main/scala/li/cil/oc/common/item/Plastic.scala @@ -0,0 +1,3 @@ +package li.cil.oc.common.item + +class Plastic(val parent: Delegator) extends Delegate diff --git a/src/main/scala/li/cil/oc/common/tileentity/Printer.scala b/src/main/scala/li/cil/oc/common/tileentity/Printer.scala index 00954516d..b54aa3cee 100644 --- a/src/main/scala/li/cil/oc/common/tileentity/Printer.scala +++ b/src/main/scala/li/cil/oc/common/tileentity/Printer.scala @@ -11,6 +11,7 @@ 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 @@ -19,18 +20,26 @@ import net.minecraft.nbt.NBTTagCompound import net.minecraft.util.AxisAlignedBB import net.minecraftforge.common.util.ForgeDirection -class Printer extends traits.Environment with traits.PowerAcceptor with traits.Inventory with traits.Rotatable with SidedEnvironment with traits.StateAware { +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 maxAmountPlastic = 256000 + var amountPlastic = 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 plasticPerItem = 2000 + val inkPerCartridge = 50000 + val slotPlastic = 0 val slotInk = 1 val slotOutput = 2 @@ -42,27 +51,22 @@ class Printer extends traits.Environment with traits.PowerAcceptor with traits.I override def sidedNode(side: ForgeDirection) = if (side != ForgeDirection.UP) node else null - @SideOnly(Side.CLIENT) - override protected def hasConnector(side: ForgeDirection) = canConnect(side) - - override protected def connector(side: ForgeDirection) = Option(if (side != ForgeDirection.UP) node else null) - - override protected def energyThroughput = Settings.get.assemblerRate - override def currentState = { - if (isAssembling) util.EnumSet.of(traits.State.IsWorking) - else if (canAssemble) util.EnumSet.of(traits.State.CanWork) + 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 canAssemble = { + def canPrint = { val complexity = data.stateOff.size + data.stateOn.size complexity > 0 && complexity <= Settings.get.maxPrintComplexity } - def isAssembling = requiredEnergy > 0 + 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 @@ -79,7 +83,7 @@ class Printer extends traits.Environment with traits.PowerAcceptor with traits.I @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)) + data.label = Option(args.optString(0, null)).map(_.take(16)) isActive = false // Needs committing. null } @@ -91,7 +95,7 @@ class Printer extends traits.Environment with traits.PowerAcceptor with traits.I @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)) + data.tooltip = Option(args.optString(0, null)).map(_.take(128)) isActive = false // Needs committing. null } @@ -140,7 +144,7 @@ class Printer extends traits.Environment with traits.PowerAcceptor with traits.I @Callback(doc = """function():boolean -- Commit and begin printing the current configuration.""") def commit(context: Context, args: Arguments): Array[Object] = { - if (!canAssemble) { + if (!canPrint) { return result(null, "model invalid") } isActive = true @@ -149,8 +153,8 @@ class Printer extends traits.Environment with traits.PowerAcceptor with traits.I @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 (isAssembling) result("busy", progress) - else if (canAssemble) result("idle", true) + if (isPrinting) result("busy", progress) + else if (canPrint) result("idle", true) else result("idle", false) } @@ -163,47 +167,74 @@ class Printer extends traits.Environment with traits.PowerAcceptor with traits.I override def updateEntity() { super.updateEntity() - if (world.getTotalWorldTime % Settings.get.tickFrequency == 0) { - if (isActive && output.isEmpty) { - 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) - val totalShapes = data.stateOn.size + data.stateOff.size - // TODO Consume plastic (totalVolume) and ink (totalSurface). + if (isActive && output.isEmpty) { + 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) + val totalShapes = data.stateOn.size + data.stateOff.size + + if (totalVolume == 0) { + isActive = false + } + else { + val plasticRequired = totalVolume + val inkRequired = (totalSurface / 6) max 1 + totalRequiredEnergy = totalShapes * Settings.get.printShapeCost requiredEnergy = totalRequiredEnergy - output = Option(data.createItemStack()) - // ServerPacketSender.sendRobotAssembling(this, assembling = true) - } - if (output.isDefined) { - val want = math.max(1, math.min(requiredEnergy, Settings.get.assemblerTickAmount * Settings.get.tickFrequency)) - val success = Settings.get.ignorePower || node.tryChangeBuffer(-want) - if (success) { - requiredEnergy -= want + if (amountPlastic >= plasticRequired && amountInk >= inkRequired) { + amountPlastic -= plasticRequired + amountInk -= inkRequired + output = Option(data.createItemStack()) + ServerPacketSender.sendPrinting(this, printing = true) } - 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 + } + } + + 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) } - // ServerPacketSender.sendRobotAssembling(this, success && output.isDefined) + 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 (maxAmountPlastic - amountPlastic >= plasticPerItem) { + val plastic = decrStackSize(slotPlastic, 1) + if (plastic != null) { + amountPlastic += plasticPerItem + } + } + + 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) - data.load(nbt.getCompoundTag("data")) + amountPlastic = nbt.getInteger(Settings.namespace + "amountPlastic") + 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"))) @@ -214,7 +245,9 @@ class Printer extends traits.Environment with traits.PowerAcceptor with traits.I override def writeToNBTForServer(nbt: NBTTagCompound) { super.writeToNBTForServer(nbt) - nbt.setNewCompoundTag("data", data.save) + nbt.setInteger(Settings.namespace + "amountPlastic", amountPlastic) + 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) @@ -240,8 +273,8 @@ class Printer extends traits.Environment with traits.PowerAcceptor with traits.I override def isItemValidForSlot(slot: Int, stack: ItemStack) = if (slot == 0) - true // TODO Plastic + api.Items.get(stack) == api.Items.get("plastic") else if (slot == 1) - true // TODO Color + api.Items.get(stack) == api.Items.get("inkCartridge") else false } diff --git a/src/main/scala/li/cil/oc/server/PacketSender.scala b/src/main/scala/li/cil/oc/server/PacketSender.scala index 68e1df349..17c4278fd 100644 --- a/src/main/scala/li/cil/oc/server/PacketSender.scala +++ b/src/main/scala/li/cil/oc/server/PacketSender.scala @@ -226,6 +226,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)