blob: baa7ec50156b1cded13e54d1a47940a465e5da88 [file] [log] [blame] [raw]
package codechicken.multipart
import java.util.List
import java.lang.Iterable
import net.minecraft.block.Block
import net.minecraft.block.material.Material
import net.minecraft.entity.Entity
import net.minecraft.util.AxisAlignedBB
import net.minecraft.world.World
import net.minecraftforge.common.ForgeDirection
import net.minecraft.util.Vec3
import net.minecraft.util.MovingObjectPosition
import codechicken.lib.raytracer.RayTracer
import net.minecraft.entity.player.EntityPlayer
import java.util.Random
import java.util.ArrayList
import net.minecraft.item.ItemStack
import net.minecraft.client.particle.EffectRenderer
import net.minecraft.client.Minecraft
import net.minecraft.client.renderer.texture.IconRegister
import codechicken.lib.render.TextureUtils
import net.minecraft.world.IBlockAccess
import codechicken.lib.raytracer.ExtendedMOP
import scala.collection.JavaConversions._
object BlockMultipart
{
def getTile(world:IBlockAccess, x:Int, y:Int, z:Int):TileMultipart =
{
val tile = world.getBlockTileEntity(x, y, z)
if(tile.isInstanceOf[TileMultipart])
tile.asInstanceOf[TileMultipart]
else
null
}
def getClientTile(world:IBlockAccess, x:Int, y:Int, z:Int):TileMultipartClient =
{
val tile = world.getBlockTileEntity(x, y, z)
if(tile.isInstanceOf[TileMultipartClient])
tile.asInstanceOf[TileMultipartClient]
else
null
}
def reduceMOP(hit:MovingObjectPosition):(Int, ExtendedMOP) = {
val ehit = hit.asInstanceOf[ExtendedMOP]
val data:(Int, _) = ExtendedMOP.getData(hit)
return (data._1, new ExtendedMOP(ehit, data._2, ehit.dist))
}
def drawHighlight(world:World, player:EntityPlayer, hit:MovingObjectPosition, frame:Float):Boolean =
{
val tile = getTile(world, hit.blockX, hit.blockY, hit.blockZ)
if(tile == null)
return false
val (index, mop) = reduceMOP(hit)
if(tile.partList(index).drawHighlight(mop, player, frame))
return true
tile.partList(index).collisionRayTrace(RayTracer.getStartVec(player), RayTracer.getEndVec(player))
return false
}
}
/**
* Block class for all multiparts, should be internal use only.
*/
class BlockMultipart(id:Int) extends Block(id, Material.rock)
{
import BlockMultipart._
override def hasTileEntity(meta:Int = 0) = true
override def isBlockSolidOnSide(world:World, x:Int, y:Int, z:Int, side:ForgeDirection):Boolean =
getTile(world, x, y, z) match {
case null => false
case tile => tile.isSolid(side.ordinal())
}
override def onNeighborBlockChange(world:World, x:Int, y:Int, z:Int, id:Int)
{
val tile = getTile(world, x, y, z)
if(tile != null)
tile.onNeighborBlockChange()
}
override def collisionRayTrace(world:World, x:Int, y:Int, z:Int, start:Vec3, end:Vec3):ExtendedMOP =
getTile(world, x, y, z) match {
case null => null
case tile => tile.collisionRayTrace(start, end)
}
def rayTraceAll(world:World, x:Int, y:Int, z:Int, start:Vec3, end:Vec3):Iterable[ExtendedMOP] =
getTile(world, x, y, z) match {
case null => Seq()
case tile => tile.rayTraceAll(start, end)
}
override def removeBlockByPlayer(world:World, player:EntityPlayer, x:Int, y:Int, z:Int):Boolean =
{
val hit = RayTracer.retraceBlock(world, player, x, y, z)
val tile = getTile(world, x, y, z)
if(hit == null || tile == null)
{
dropAndDestroy(world, x, y, z)
return true
}
val (index, mop) = reduceMOP(hit)
if(world.isRemote)
{
tile.partList(index).addDestroyEffects(mop, Minecraft.getMinecraft.effectRenderer)
return true
}
tile.harvestPart(index, mop, player)
return world.getBlockTileEntity(x, y, z) == null
}
def dropAndDestroy(world:World, x:Int, y:Int, z:Int)
{
val tile = getTile(world, x, y, z)
if(tile != null && !world.isRemote)
tile.dropItems(getBlockDropped(world, x, y, z, 0, 0))
world.setBlockToAir(x, y, z)
}
override def quantityDropped(meta:Int, fortune:Int, random:Random) = 0
override def getBlockDropped(world:World, x:Int, y:Int, z:Int, meta:Int, fortune:Int):ArrayList[ItemStack] =
{
val ai = new ArrayList[ItemStack]()
if(world.isRemote)
return ai
val tile = getTile(world, x, y, z)
if(tile != null)
tile.partList.foreach(part => part.getDrops.foreach(item => ai.add(item)))
return ai
}
override def addCollisionBoxesToList(world:World, x:Int, y:Int, z:Int, ebb:AxisAlignedBB, list$:List[_], entity:Entity)
{
val list = list$.asInstanceOf[List[AxisAlignedBB]]
val tile = getTile(world, x, y, z)
if(tile != null)
tile.partList.foreach(part =>
part.getCollisionBoxes.foreach{c =>
val aabb = c.toAABB.offset(x, y, z)
if(aabb.intersectsWith(ebb))
list.add(aabb)
})
}
override def addBlockHitEffects(world:World, hit:MovingObjectPosition, effectRenderer:EffectRenderer):Boolean =
{
val tile = getClientTile(world, hit.blockX, hit.blockY, hit.blockZ)
if(tile != null) {
val (index, mop) = reduceMOP(hit)
tile.partList(index).addHitEffects(mop, effectRenderer)
}
return true
}
override def addBlockDestroyEffects(world:World, x:Int, y:Int, z:Int, s:Int, effectRenderer:EffectRenderer) = true
override def renderAsNormalBlock() = false
override def isOpaqueCube = false
override def getRenderType = TileMultipart.renderID
override def isAirBlock(world:World, x:Int, y:Int, z:Int):Boolean =
getTile(world, x, y, z) match {
case null => true
case tile => tile.partList.isEmpty
}
override def isBlockReplaceable(world:World, x:Int, y:Int, z:Int) = isAirBlock(world, x, y, z)
override def getRenderBlockPass = 1
override def canRenderInPass(pass:Int):Boolean =
{
MultipartRenderer.pass = pass
return true
}
override def getPickBlock(hit:MovingObjectPosition, world:World, x:Int, y:Int, z:Int):ItemStack =
{
val tile = getTile(world, x, y, z)
if(tile != null)
{
val (index, mop) = reduceMOP(hit)
return tile.partList(index).pickItem(mop)
}
return null
}
override def getPlayerRelativeBlockHardness(player:EntityPlayer, world:World, x:Int, y:Int, z:Int):Float =
{
val hit = RayTracer.retraceBlock(world, player, x, y, z)
val tile = getTile(world, x, y, z)
if(hit != null && tile != null) {
val (index, mop) = reduceMOP(hit)
return tile.partList(index).getStrength(mop, player)/30F
}
return 1/100F
}
/**
* Kludge to set PROTECTED blockIcon to a blank icon
*/
override def registerIcons(register:IconRegister)
{
val icon = TextureUtils.getBlankIcon(16, register)
setTextureName(icon.getIconName)
super.registerIcons(register)
}
override def getLightValue(world:IBlockAccess, x:Int, y:Int, z:Int):Int =
getTile(world, x, y, z) match {
case null => 0
case tile => tile.getLightValue
}
override def randomDisplayTick(world:World, x:Int, y:Int, z:Int, random:Random)
{
val tile = getClientTile(world, x, y, z)
if(tile != null)
tile.randomDisplayTick(random)
}
override def onBlockActivated(world:World, x:Int, y:Int, z:Int, player:EntityPlayer, side:Int, hitX:Float, hitY:Float, hitZ:Float):Boolean =
{
val hit = RayTracer.retraceBlock(world, player, x, y, z)
if(hit == null)
return false
val tile = getTile(world, x, y, z)
if(tile == null)
return false
val (index, mop) = reduceMOP(hit)
return tile.partList(index).activate(player, mop, player.getHeldItem)
}
override def onBlockClicked(world:World, x:Int, y:Int, z:Int, player:EntityPlayer)
{
val hit = RayTracer.retraceBlock(world, player, x, y, z)
if(hit == null)
return
val tile = getTile(world, x, y, z)
if(tile == null)
return
val (index, mop) = reduceMOP(hit)
tile.partList(index).click(player, mop, player.getHeldItem)
}
override def isProvidingStrongPower(world:IBlockAccess, x:Int, y:Int, z:Int, side:Int):Int =
getTile(world, x, y, z) match {
case null => 0
case tile => tile.strongPowerLevel(side^1)
}
override def isProvidingWeakPower(world:IBlockAccess, x:Int, y:Int, z:Int, side:Int):Int =
getTile(world, x, y, z) match {
case null => 0
case tile => tile.weakPowerLevel(side^1)
}
override def canConnectRedstone(world:IBlockAccess, x:Int, y:Int, z:Int, side:Int):Boolean =
getTile(world, x, y, z) match {
case null => false
case tile => tile.canConnectRedstone(side)
}
override def onEntityCollidedWithBlock(world:World, x:Int, y:Int, z:Int, entity:Entity)
{
val tile = getTile(world, x, y, z)
if(tile != null)
tile.onEntityCollision(entity)
}
override def onNeighborTileChange(world:World, x:Int, y:Int, z:Int, tileX:Int, tileY:Int, tileZ:Int)
{
getTile(world, x, y, z) match {
case null => world.setBlockToAir(x, y, z)
case tile => tile.onNeighborTileChange(tileX, tileY, tileZ)
}
}
override def getExplosionResistance(entity:Entity, world:World, x:Int, y:Int, z:Int, explosionX:Double, explosionY:Double, explosionZ:Double):Float =
getTile(world, x, y, z) match {
case null => 0
case tile => tile.getExplosionResistance(entity)
}
override def weakTileChanges() = true
override def canProvidePower = true
}