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.MCDataOutput
import codechicken.lib.raytracer.ExtendedMOP
import codechicken.lib.raytracer.IndexedCuboid6
import codechicken.lib.vec.Cuboid6
import codechicken.lib.vec.Vector3
import codechicken.multipart.IRedstonePart
import codechicken.multipart.PartMap
import codechicken.multipart.TCuboidPart
import codechicken.multipart.TEdgePart
import codechicken.multipart.TFacePart
import codechicken.multipart.TMultiPart
import codechicken.multipart.TNormalOcclusion
import codechicken.multipart.TSlottedPart
import codechicken.multipart.scalatraits.TSlottedTile
import cpw.mods.fml.relauncher.Side
import cpw.mods.fml.relauncher.SideOnly
import li.cil.oc.Settings
@ -38,14 +45,55 @@ import net.minecraftforge.common.util.ForgeDirection
import org.lwjgl.opengl.GL11
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 data = new PrintData()
var boundsOff = ExtendedAABB.unitBounds
var boundsOn = ExtendedAABB.unitBounds
var state = false
var toggling = false // avoid infinite loops when updating neighbors
original.foreach(print => {
facing = print.facing
@ -74,8 +122,24 @@ class PrintPart(val original: Option[tileentity.Print] = None) extends SimpleBlo
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 strongPowerLevel(side: Int): Int = weakPowerLevel(side)
@ -96,22 +160,29 @@ class PrintPart(val original: Option[tileentity.Print] = None) extends SimpleBlo
def toggleState(): Unit = {
if (canToggle) {
toggling = true
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.notifyBlocksOfNeighborChange(x, y, z, tile.getBlockType)
world.markBlockForUpdate(x, y, z)
if (!world.isRemote) sendDescUpdate()
tile.partList.foreach {
case print: PrintPart if print != this => print.onNeighborChanged()
// Update slot info in tile... kinda meh, but works.
tile match {
case slotted: TSlottedTile =>
for (i <- 0 until slotted.v_partMap.length) {
if (slotted.v_partMap(i) == this)
slotted.v_partMap(i) = null
}
tile.bindPart(this)
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) {
scheduleTick(simpleBlock.tickRate(world))
}
toggling = false
}
}
def canToggle = {
def canToggle = !toggling && world != null && !world.isRemote && {
val toggled = new PrintPart()
toggled.facing = facing
toggled.data = data
@ -177,22 +248,33 @@ class PrintPart(val original: Option[tileentity.Print] = None) extends SimpleBlo
true
}
override def onPartChanged(part: TMultiPart): Unit = {
super.onPartChanged(part)
checkRedstone()
}
override def onNeighborChanged(): Unit = {
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 {
case print: PrintPart => powered || (print.state && print.data.emitRedstone)
case _ => powered
})
val newMaxValue = 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()
}
}
if (inner) 15 else ForgeDirection.VALID_DIRECTIONS.map(computeInput).max
}
protected def computeInput(side: ForgeDirection) = {
protected def computeInput(side: ForgeDirection): Int = {
val blockPos = BlockPosition(x, y, z).offset(side)
if (!world.blockExists(blockPos)) 0
else {