Assigning 3D prints to multipart "slots" where they intersect with those areas. Makes them properly block Project Red bundled cables, for example. Closes #1015.

There are some... interesting cases with multi-state prints and redstone logic (e.g. the printed trapdoor cutting of the power that triggers it), but it shouldn't be a real problem.
This commit is contained in:
Florian Nücke 2015-04-04 18:06:29 +02:00
parent e98866473a
commit 6f02abad8c

View File

@ -5,11 +5,18 @@ import java.lang
import codechicken.lib.data.MCDataInput import codechicken.lib.data.MCDataInput
import codechicken.lib.data.MCDataOutput import codechicken.lib.data.MCDataOutput
import codechicken.lib.raytracer.ExtendedMOP import codechicken.lib.raytracer.ExtendedMOP
import codechicken.lib.raytracer.IndexedCuboid6
import codechicken.lib.vec.Cuboid6 import codechicken.lib.vec.Cuboid6
import codechicken.lib.vec.Vector3 import codechicken.lib.vec.Vector3
import codechicken.multipart.IRedstonePart import codechicken.multipart.IRedstonePart
import codechicken.multipart.PartMap
import codechicken.multipart.TCuboidPart import codechicken.multipart.TCuboidPart
import codechicken.multipart.TEdgePart
import codechicken.multipart.TFacePart
import codechicken.multipart.TMultiPart
import codechicken.multipart.TNormalOcclusion import codechicken.multipart.TNormalOcclusion
import codechicken.multipart.TSlottedPart
import codechicken.multipart.scalatraits.TSlottedTile
import cpw.mods.fml.relauncher.Side import cpw.mods.fml.relauncher.Side
import cpw.mods.fml.relauncher.SideOnly import cpw.mods.fml.relauncher.SideOnly
import li.cil.oc.Settings import li.cil.oc.Settings
@ -38,14 +45,55 @@ import net.minecraftforge.common.util.ForgeDirection
import org.lwjgl.opengl.GL11 import org.lwjgl.opengl.GL11
import scala.collection.convert.WrapAsJava._ import scala.collection.convert.WrapAsJava._
import scala.collection.convert.WrapAsScala._
class PrintPart(val original: Option[tileentity.Print] = None) extends SimpleBlockPart with TCuboidPart with TNormalOcclusion with IRedstonePart { object PrintPart {
private val q0 = 0 / 16f
private val q1 = 4 / 16f
private val q2 = 12 / 16f
private val q3 = 16 / 16f
val slotBounds = Array(
new Cuboid6(q1, q0, q1, q2, q1, q2),
new Cuboid6(q1, q2, q1, q2, q3, q2),
new Cuboid6(q1, q1, q0, q2, q2, q1),
new Cuboid6(q1, q1, q2, q2, q2, q3),
new Cuboid6(q0, q1, q1, q1, q2, q2),
new Cuboid6(q2, q1, q1, q3, q2, q2),
new Cuboid6(q1, q1, q1, q2, q2, q2),
new Cuboid6(q0, q0, q0, q1, q1, q1),
new Cuboid6(q0, q2, q0, q1, q3, q1),
new Cuboid6(q0, q0, q2, q1, q1, q3),
new Cuboid6(q0, q2, q2, q1, q3, q3),
new Cuboid6(q2, q0, q0, q3, q1, q1),
new Cuboid6(q2, q2, q0, q3, q3, q1),
new Cuboid6(q2, q0, q2, q3, q1, q3),
new Cuboid6(q2, q2, q2, q3, q3, q3),
new Cuboid6(q0, q1, q0, q1, q2, q1),
new Cuboid6(q0, q1, q2, q1, q2, q3),
new Cuboid6(q2, q1, q0, q3, q2, q1),
new Cuboid6(q2, q1, q2, q3, q2, q3),
new Cuboid6(q0, q0, q1, q1, q1, q2),
new Cuboid6(q2, q0, q1, q3, q1, q2),
new Cuboid6(q0, q2, q1, q1, q3, q2),
new Cuboid6(q2, q2, q1, q3, q3, q2),
new Cuboid6(q1, q0, q0, q2, q1, q1),
new Cuboid6(q1, q2, q0, q2, q3, q1),
new Cuboid6(q1, q0, q2, q2, q1, q3),
new Cuboid6(q1, q2, q2, q2, q3, q3)
)
}
class PrintPart(val original: Option[tileentity.Print] = None) extends SimpleBlockPart with TCuboidPart with TNormalOcclusion with IRedstonePart with TSlottedPart with TEdgePart with TFacePart {
var facing = ForgeDirection.SOUTH var facing = ForgeDirection.SOUTH
var data = new PrintData() var data = new PrintData()
var boundsOff = ExtendedAABB.unitBounds var boundsOff = ExtendedAABB.unitBounds
var boundsOn = ExtendedAABB.unitBounds var boundsOn = ExtendedAABB.unitBounds
var state = false var state = false
var toggling = false // avoid infinite loops when updating neighbors
original.foreach(print => { original.foreach(print => {
facing = print.facing facing = print.facing
@ -74,8 +122,24 @@ class PrintPart(val original: Option[tileentity.Print] = None) extends SimpleBlo
override def getRenderBounds = getBounds override def getRenderBounds = getBounds
override def getSlotMask: Int = {
var mask = 0
val boxes = getOcclusionBoxes
for (slot <- PartMap.values) {
val bounds = PrintPart.slotBounds(slot.i)
if (boxes.exists(_.intersects(bounds))) {
mask |= slot.mask
}
}
mask
}
// ----------------------------------------------------------------------- // // ----------------------------------------------------------------------- //
override def conductsRedstone: Boolean = data.emitRedstone && state
override def redstoneConductionMap: Int = if (data.emitRedstone && state) 0xFF else 0
override def canConnectRedstone(side: Int): Boolean = true override def canConnectRedstone(side: Int): Boolean = true
override def strongPowerLevel(side: Int): Int = weakPowerLevel(side) override def strongPowerLevel(side: Int): Int = weakPowerLevel(side)
@ -96,22 +160,29 @@ class PrintPart(val original: Option[tileentity.Print] = None) extends SimpleBlo
def toggleState(): Unit = { def toggleState(): Unit = {
if (canToggle) { if (canToggle) {
toggling = true
state = !state state = !state
world.playSoundEffect(x + 0.5, y + 0.5, z + 0.5, "random.click", 0.3F, if (state) 0.6F else 0.5F) // Update slot info in tile... kinda meh, but works.
world.notifyBlocksOfNeighborChange(x, y, z, tile.getBlockType) tile match {
world.markBlockForUpdate(x, y, z) case slotted: TSlottedTile =>
if (!world.isRemote) sendDescUpdate() for (i <- 0 until slotted.v_partMap.length) {
tile.partList.foreach { if (slotted.v_partMap(i) == this)
case print: PrintPart if print != this => print.onNeighborChanged() slotted.v_partMap(i) = null
}
tile.bindPart(this)
case _ => case _ =>
} }
world.playSoundEffect(x + 0.5, y + 0.5, z + 0.5, "random.click", 0.3F, if (state) 0.6F else 0.5F)
tile.notifyPartChange(this)
sendDescUpdate()
if (state && data.isButtonMode) { if (state && data.isButtonMode) {
scheduleTick(simpleBlock.tickRate(world)) scheduleTick(simpleBlock.tickRate(world))
} }
toggling = false
} }
} }
def canToggle = { def canToggle = !toggling && world != null && !world.isRemote && {
val toggled = new PrintPart() val toggled = new PrintPart()
toggled.facing = facing toggled.facing = facing
toggled.data = data toggled.data = data
@ -177,22 +248,33 @@ class PrintPart(val original: Option[tileentity.Print] = None) extends SimpleBlo
true true
} }
override def onPartChanged(part: TMultiPart): Unit = {
super.onPartChanged(part)
checkRedstone()
}
override def onNeighborChanged(): Unit = { override def onNeighborChanged(): Unit = {
super.onNeighborChanged() super.onNeighborChanged()
checkRedstone()
}
protected def checkRedstone(): Unit = {
val newMaxValue = computeInput()
val newState = newMaxValue > 1 // Fixes oddities in cycling updates.
if (!data.emitRedstone && data.stateOn.size > 0 && state != newState) {
toggleState()
}
}
protected def computeInput(): Int = {
val inner = tile.partList.foldLeft(false)((powered, part) => part match { val inner = tile.partList.foldLeft(false)((powered, part) => part match {
case print: PrintPart => powered || (print.state && print.data.emitRedstone) case print: PrintPart => powered || (print.state && print.data.emitRedstone)
case _ => powered case _ => powered
}) })
val newMaxValue = if (inner) 15 else ForgeDirection.VALID_DIRECTIONS.map(computeInput).max if (inner) 15 else ForgeDirection.VALID_DIRECTIONS.map(computeInput).max
if (!data.emitRedstone && data.stateOn.size > 0) {
val newState = newMaxValue > 0
if (state != newState) {
toggleState()
}
}
} }
protected def computeInput(side: ForgeDirection) = { protected def computeInput(side: ForgeDirection): Int = {
val blockPos = BlockPosition(x, y, z).offset(side) val blockPos = BlockPosition(x, y, z).offset(side)
if (!world.blockExists(blockPos)) 0 if (!world.blockExists(blockPos)) 0
else { else {