Added custom intersect check for racks to take into account the mountables being inset by one.

Avoid floating point inaccuracies leading to incorrect local coordinates for mountable onActivate.
This commit is contained in:
Florian Nücke 2016-06-26 11:21:59 +02:00
parent 9a3fd0feb2
commit 1279537f8d
2 changed files with 54 additions and 9 deletions

View File

@ -9,7 +9,9 @@ import li.cil.oc.common.GuiType
import li.cil.oc.common.tileentity import li.cil.oc.common.tileentity
import net.minecraft.client.renderer.texture.IIconRegister import net.minecraft.client.renderer.texture.IIconRegister
import net.minecraft.entity.player.EntityPlayer import net.minecraft.entity.player.EntityPlayer
import net.minecraft.util.AxisAlignedBB
import net.minecraft.util.IIcon import net.minecraft.util.IIcon
import net.minecraft.util.MovingObjectPosition
import net.minecraft.util.Vec3 import net.minecraft.util.Vec3
import net.minecraft.world.IBlockAccess import net.minecraft.world.IBlockAccess
import net.minecraft.world.World import net.minecraft.world.World
@ -71,22 +73,64 @@ class Rack extends RedstoneAware with traits.SpecialBlock with traits.PowerAccep
// ----------------------------------------------------------------------- // // ----------------------------------------------------------------------- //
final val collisionBounds = Array(
AxisAlignedBB.getBoundingBox(0, 0, 0, 1, 1/16f, 1),
AxisAlignedBB.getBoundingBox(0, 15/16f, 0, 1, 1, 1),
AxisAlignedBB.getBoundingBox(0, 0, 0, 1, 1, 1/16f),
AxisAlignedBB.getBoundingBox(0, 0, 15/16f, 1, 1, 1),
AxisAlignedBB.getBoundingBox(0, 0, 0, 1/16f, 1, 1),
AxisAlignedBB.getBoundingBox(15/16f, 0, 0, 1, 1, 1),
AxisAlignedBB.getBoundingBox(1/16f, 1/16f, 1/16f, 15/16f, 15/16f, 15/16f)
)
override protected def intersect(world: World, x: Int, y: Int, z: Int, start: Vec3, end: Vec3): MovingObjectPosition = {
world.getTileEntity(x, y, z) match {
case rack: tileentity.Rack =>
var closestDistance = Double.PositiveInfinity
var closest: Option[MovingObjectPosition] = None
def intersect(bounds: AxisAlignedBB): Unit = {
val hit = bounds.copy().offset(x, y, z).calculateIntercept(start, end)
if (hit != null) {
val distance = hit.hitVec.distanceTo(start)
if (distance < closestDistance) {
closestDistance = distance
closest = Option(hit)
}
}
}
val facings = ForgeDirection.VALID_DIRECTIONS
for (i <- 0 until facings.length) {
if (rack.facing != facings(i)) {
intersect(collisionBounds(i))
}
}
intersect(collisionBounds.last)
closest.map(hit => new MovingObjectPosition(x, y, z, hit.sideHit, hit.hitVec)).orNull
case _ => super.intersect(world, x, y, z, start, end)
}
}
override def onBlockActivated(world: World, x: Int, y: Int, z: Int, player: EntityPlayer, side: ForgeDirection, hitX: Float, hitY: Float, hitZ: Float): Boolean = { 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 { world.getTileEntity(x, y, z) match {
case rack: tileentity.Rack => rack.slotAt(side, hitX, hitY, hitZ) match { case rack: tileentity.Rack => rack.slotAt(side, hitX, hitY, hitZ) match {
case Some(slot) => case Some(slot) =>
val hitVec = Vec3.createVectorHelper(hitX, hitY, hitZ) // Snap to grid to get same behavior on client and server...
val hitVec = Vec3.createVectorHelper((hitX*16f).toInt/16f, (hitY*16f).toInt/16f, (hitZ*16f).toInt/16f)
val rotation = side match { val rotation = side match {
case ForgeDirection.WEST => Math.toRadians(90).toFloat case ForgeDirection.WEST => Math.toRadians(90).toFloat
case ForgeDirection.NORTH => Math.toRadians(180).toFloat case ForgeDirection.NORTH => Math.toRadians(180).toFloat
case ForgeDirection.EAST => Math.toRadians(270).toFloat case ForgeDirection.EAST => Math.toRadians(270).toFloat
case _ => 0 case _ => 0
} }
val localHitVec = rotate(hitVec.addVector(-0.5, -0.5, -0.5), rotation).addVector(0.5, 0.5, 0.5) // Rotate *centers* of pixels to keep association when reversing axis.
localHitVec.xCoord = ((if (side.offsetX != 0) 1 - localHitVec.xCoord else localHitVec.xCoord) * 16 - 1) / 14f val localHitVec = rotate(hitVec.addVector(-0.5+1/32f, -0.5+1/32f, -0.5+1/32f), rotation).addVector(0.5-1/32f, 0.5-1/32f, 0.5-1/32f)
localHitVec.yCoord = ((1 - localHitVec.yCoord) * 16 - 2 - 3 * slot) / 3f val globalX = (localHitVec.xCoord * 16.05f).toInt // [0, 15], work around floating point inaccuracies
rack.getMountable(slot) match { val globalY = (localHitVec.yCoord * 16.05f).toInt // [0, 15], work around floating point inaccuracies
case mountable: RackMountable if mountable.onActivate(player, localHitVec.xCoord.toFloat, localHitVec.yCoord.toFloat) => return true // Activation handled by mountable. val localX = (if (side.offsetX != 0) 15 - globalX else globalX) - 1
val localY = (15 - globalY) - 2 - 3 * slot
if (localX >= 0 && localX < 14 && localY >= 0 && localY < 3) rack.getMountable(slot) match {
case mountable: RackMountable if mountable.onActivate(player, localX / 14f, localY / 3f) => return true // Activation handled by mountable.
case _ => case _ =>
} }
case _ => case _ =>

View File

@ -444,9 +444,10 @@ class Rack extends traits.PowerAcceptor with traits.Hub with traits.PowerBalance
def slotAt(side: ForgeDirection, hitX: Float, hitY: Float, hitZ: Float) = { def slotAt(side: ForgeDirection, hitX: Float, hitY: Float, hitZ: Float) = {
if (side == facing) { if (side == facing) {
val l = 2 / 16.0 val globalY = (hitY * 16).toInt // [0, 15]
val h = 14 / 16.0 val l = 2
val slot = (((1 - hitY) - l) / (h - l) * getSizeInventory).toInt val h = 14
val slot = ((15 - globalY) - l) * getSizeInventory / (h - l)
Some(math.max(0, math.min(getSizeInventory - 1, slot))) Some(math.max(0, math.min(getSizeInventory - 1, slot)))
} }
else None else None