diff --git a/src/main/resources/application.conf b/src/main/resources/application.conf index 4f31b80a5..97aa94738 100644 --- a/src/main/resources/application.conf +++ b/src/main/resources/application.conf @@ -972,6 +972,11 @@ opencomputers { # don't care about that and prefer them to be not totally shadowless, # enable this. printsHaveOpacity: false + + # By what (linear) factor the cost of a print increases if one or both of + # its states are non-collidable (i.e. entities can move through them). + # This only influences the chamelium cost. + noclipMultiplier: 2 } hologram { diff --git a/src/main/resources/assets/opencomputers/recipes/default.recipes b/src/main/resources/assets/opencomputers/recipes/default.recipes index f06981354..c4dc61add 100644 --- a/src/main/resources/assets/opencomputers/recipes/default.recipes +++ b/src/main/resources/assets/opencomputers/recipes/default.recipes @@ -144,6 +144,7 @@ hdd3 { ["oc:materialCircuitBoardPrinted", "oc:materialDisk", craftingPiston] ["oc:circuitChip3", "oc:materialDisk", diamond]] } + dataCard { input: [[nuggetIron, "oc:materialALU", "oc:circuitChip2"] ["", "oc:materialCard", ""]] diff --git a/src/main/scala/li/cil/oc/Settings.scala b/src/main/scala/li/cil/oc/Settings.scala index 4920c2aa9..6e81e801b 100644 --- a/src/main/scala/li/cil/oc/Settings.scala +++ b/src/main/scala/li/cil/oc/Settings.scala @@ -328,6 +328,7 @@ class Settings(val config: Config) { val printMaterialValue = config.getInt("printer.materialValue") max 0 val printInkValue = config.getInt("printer.inkValue") max 0 val printsHaveOpacity = config.getBoolean("printer.printsHaveOpacity") + val noclipMultiplier = config.getDouble("printer.noclipMultiplier") max 0 // ----------------------------------------------------------------------- // // integration diff --git a/src/main/scala/li/cil/oc/client/renderer/block/Print.scala b/src/main/scala/li/cil/oc/client/renderer/block/Print.scala index e88af409a..fff9779d9 100644 --- a/src/main/scala/li/cil/oc/client/renderer/block/Print.scala +++ b/src/main/scala/li/cil/oc/client/renderer/block/Print.scala @@ -1,5 +1,6 @@ package li.cil.oc.client.renderer.block +import com.google.common.base.Strings import li.cil.oc.Constants import li.cil.oc.api.Items import li.cil.oc.common.block @@ -17,12 +18,13 @@ object Print { def render(data: PrintData, state: Boolean, facing: ForgeDirection, x: Int, y: Int, z: Int, block: Block, renderer: RenderBlocks): Unit = { val shapes = if (state) data.stateOn else data.stateOff + printBlock.isSingleShape = shapes.size == 1 if (shapes.isEmpty) { printBlock.textureOverride = Option(resolveTexture("missingno")) renderer.setRenderBounds(0, 0, 0, 1, 1, 1) renderer.renderStandardBlock(block, x, y, z) } - else for (shape <- shapes) { + else for (shape <- shapes if !Strings.isNullOrEmpty(shape.texture)) { val bounds = shape.bounds.rotateTowards(facing) printBlock.colorMultiplierOverride = shape.tint printBlock.textureOverride = Option(resolveTexture(shape.texture)) @@ -33,6 +35,7 @@ object Print { } printBlock.colorMultiplierOverride = None printBlock.textureOverride = None + printBlock.isSingleShape = false } def resolveTexture(name: String): IIcon = { diff --git a/src/main/scala/li/cil/oc/client/renderer/item/ItemRenderer.scala b/src/main/scala/li/cil/oc/client/renderer/item/ItemRenderer.scala index a70b86c93..ed71f8ccf 100644 --- a/src/main/scala/li/cil/oc/client/renderer/item/ItemRenderer.scala +++ b/src/main/scala/li/cil/oc/client/renderer/item/ItemRenderer.scala @@ -1,5 +1,6 @@ package li.cil.oc.client.renderer.item +import com.google.common.base.Strings import li.cil.oc.Constants import li.cil.oc.Settings import li.cil.oc.api @@ -150,6 +151,11 @@ object ItemRenderer extends IItemRenderer { val bounds = shape.bounds val texture = Print.resolveTexture(shape.texture) + if (Strings.isNullOrEmpty(shape.texture)) { + RenderState.makeItBlend() + GL11.glColor4f(1, 1, 1, 0.25f) + } + shape.tint.foreach(color => { val r = (color >> 16).toByte val g = (color >> 8).toByte 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 afc8d8ee3..5267245ee 100644 --- a/src/main/scala/li/cil/oc/common/block/Print.scala +++ b/src/main/scala/li/cil/oc/common/block/Print.scala @@ -3,6 +3,7 @@ package li.cil.oc.common.block import java.util import java.util.Random +import com.google.common.base.Strings import cpw.mods.fml.relauncher.Side import cpw.mods.fml.relauncher.SideOnly import li.cil.oc.Localization @@ -40,6 +41,8 @@ class Print(protected implicit val tileTag: ClassTag[tileentity.Print]) extends var colorMultiplierOverride: Option[Int] = None // Also used in model rendering, can't use renderer's override logic because that'll disable tinting. var textureOverride: Option[IIcon] = None + // Again, used in model rendering, used to know whether we can potentially skip rendering sides. + var isSingleShape = false @SideOnly(Side.CLIENT) override def getIcon(world: IBlockAccess, x: Int, y: Int, z: Int, globalSide: ForgeDirection, localSide: ForgeDirection): IIcon = @@ -80,7 +83,19 @@ class Print(protected implicit val tileTag: ClassTag[tileentity.Print]) extends case _ => super.getLightOpacity(world, x, y, z) } - override def shouldSideBeRendered(world: IBlockAccess, x: Int, y: Int, z: Int, side: ForgeDirection) = true + override def shouldSideBeRendered(world: IBlockAccess, x: Int, y: Int, z: Int, side: ForgeDirection) = !isSingleShape || (world.getTileEntity(x, y, z) match { + case print: tileentity.Print if isSideSolid(world, x, y, z, side.getOpposite) => + side match { + case ForgeDirection.DOWN => minY > 0 + case ForgeDirection.UP => maxY < 1 + case ForgeDirection.NORTH => minZ > 0 + case ForgeDirection.SOUTH => maxZ < 1 + case ForgeDirection.WEST => minX > 0 + case ForgeDirection.EAST => maxX < 1 + case _ => true + } + case _ => super.shouldSideBeRendered(world, x, y, z, side) + }) override def isBlockSolid(world: IBlockAccess, x: Int, y: Int, z: Int, side: ForgeDirection) = isSideSolid(world, x, y, z, side) @@ -88,7 +103,7 @@ class Print(protected implicit val tileTag: ClassTag[tileentity.Print]) extends 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) { + for (shape <- shapes if !Strings.isNullOrEmpty(shape.texture)) { val bounds = shape.bounds.rotateTowards(print.facing) val fullX = bounds.minX == 0 && bounds.maxX == 1 val fullY = bounds.minY == 0 && bounds.maxY == 1 @@ -118,6 +133,8 @@ class Print(protected implicit val tileTag: ClassTag[tileentity.Print]) extends 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 => + if (if (print.state) print.data.noclipOn else print.data.noclipOff) return + 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) { diff --git a/src/main/scala/li/cil/oc/common/item/data/PrintData.scala b/src/main/scala/li/cil/oc/common/item/data/PrintData.scala index eb095a821..d998ca846 100644 --- a/src/main/scala/li/cil/oc/common/item/data/PrintData.scala +++ b/src/main/scala/li/cil/oc/common/item/data/PrintData.scala @@ -30,6 +30,8 @@ class PrintData extends ItemData(Constants.BlockName.Print) { val stateOn = mutable.Set.empty[PrintData.Shape] var isBeaconBase = false var lightLevel = 0 + var noclipOff = false + var noclipOn = false def hasActiveState = stateOn.nonEmpty @@ -68,6 +70,8 @@ class PrintData extends ItemData(Constants.BlockName.Print) { stateOn ++= nbt.getTagList("stateOn", NBT.TAG_COMPOUND).map(PrintData.nbtToShape) isBeaconBase = nbt.getBoolean("isBeaconBase") lightLevel = (nbt.getByte("lightLevel") & 0xFF) max 0 min 15 + noclipOff = nbt.getBoolean("noclipOff") + noclipOn = nbt.getBoolean("noclipOn") opacityDirty = true } @@ -82,6 +86,8 @@ class PrintData extends ItemData(Constants.BlockName.Print) { nbt.setNewTagList("stateOn", stateOn.map(PrintData.shapeToNBT)) nbt.setBoolean("isBeaconBase", isBeaconBase) nbt.setByte("lightLevel", lightLevel.toByte) + nbt.setBoolean("noclipOff", noclipOff) + nbt.setBoolean("noclipOn", noclipOn) } } @@ -119,6 +125,7 @@ object PrintData { def computeCosts(data: PrintData) = { 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 multiplier = if (data.noclipOff || data.noclipOn) Settings.get.noclipMultiplier else 1 if (totalVolume > 0) { val baseMaterialRequired = (totalVolume / 2) max 1 @@ -127,7 +134,7 @@ object PrintData { else baseMaterialRequired val inkRequired = (totalSurface / 6) max 1 - Option((materialRequired, inkRequired)) + Option((materialRequired * multiplier, inkRequired)) } else None } 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 43c2b7373..4ced0160e 100644 --- a/src/main/scala/li/cil/oc/common/tileentity/Printer.scala +++ b/src/main/scala/li/cil/oc/common/tileentity/Printer.scala @@ -56,7 +56,7 @@ class Printer extends traits.Environment with traits.Inventory with traits.Rotat // ----------------------------------------------------------------------- // - def canPrint = data.stateOff.size > 0 && data.stateOff.size <= Settings.get.maxPrintComplexity && data.stateOn.size <= Settings.get.maxPrintComplexity + def canPrint = data.stateOff.nonEmpty && data.stateOff.size <= Settings.get.maxPrintComplexity && data.stateOn.size <= Settings.get.maxPrintComplexity def isPrinting = output.isDefined @@ -136,6 +136,19 @@ class Printer extends traits.Environment with traits.Inventory with traits.Rotat result(data.isButtonMode) } + @Callback(doc = """function(collideOff:boolean, collideOn:boolean) -- Get whether the printed block should be collidable or not.""") + def setCollidable(context: Context, args: Arguments): Array[Object] = { + val (collideOff, collideOn) = (args.checkBoolean(0), args.checkBoolean(1)) + data.noclipOff = !collideOff + data.noclipOn = !collideOn + null + } + + @Callback(doc = """function():boolean, boolean -- Get whether the printed block should be collidable or not.""") + def isCollidable(context: Context, args: Arguments): Array[Object] = { + result(!data.noclipOff, !data.noclipOn) + } + @Callback(doc = """function(minX:number, minY:number, minZ:number, maxX:number, maxY:number, maxZ:number, texture:string[, state:boolean=false][,tint:number]) -- 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 > Settings.get.maxPrintComplexity || data.stateOn.size > Settings.get.maxPrintComplexity) {