Created
January 30, 2016 22:54
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package temportalist.ropes.common.block | |
import javax.vecmath.{AxisAngle4f, Quat4f, Vector3f} | |
import com.google.common.collect.Lists | |
import net.minecraft.block.material.Material | |
import net.minecraft.block.properties.IProperty | |
import net.minecraft.block.state.{BlockState, IBlockState} | |
import net.minecraft.block.{Block, BlockFence} | |
import net.minecraft.entity.{EntityLeashKnot, EntityLivingBase} | |
import net.minecraft.item.{ItemStack, ItemBlock} | |
import net.minecraft.util.EnumFacing.{Axis, AxisDirection} | |
import net.minecraft.util.{BlockPos, EnumFacing} | |
import net.minecraft.world.{IBlockAccess, World} | |
import net.minecraftforge.client.model.TRSRTransformation | |
import net.minecraftforge.client.model.obj.OBJModel | |
import net.minecraftforge.client.model.obj.OBJModel.OBJState | |
import net.minecraftforge.common.property.{IExtendedBlockState, IUnlistedProperty} | |
import temportalist.origin.api.common.block.StateProperties._ | |
import temportalist.origin.api.common.block.{BlockBase, StateProperties} | |
import temportalist.origin.api.common.lib.V3O | |
import temportalist.origin.api.common.utility.Cursor | |
import temportalist.ropes.common.entity.EntityRopeKnot | |
import temportalist.ropes.common.init.ModBlocks | |
/** | |
* Created by TheTemportalist on 1/18/2016. | |
*/ | |
class BlockRope(mat: Material, itemBlock: Class[_ <: ItemBlock] = classOf[ItemBlockRope]) | |
extends BlockBase(ModBlocks, mat, itemBlock = itemBlock) { | |
var BRIDGE_LENGTH: IProperty[Integer] = null | |
var BRIDGE_INDEX: IProperty[Integer] = null | |
this.setDefaultState(this.getBlockState.getBaseState.withProperty(AXIS, Axis.X)) | |
override def setBlockBoundsBasedOnState(worldIn: IBlockAccess, pos: BlockPos): Unit = { | |
val axis = worldIn.getBlockState(pos).getValue(AXIS) | |
axis match { | |
case Axis.X => this.setBlockBounds(0.4375F, 0, 0, 0.5625F, 0.125F, 1F) | |
case Axis.Z => this.setBlockBounds(0, 0, 0.4275F, 0.5625F, 1, 0.5625F) | |
case Axis.Y => this.setBlockBounds(0.4375F, 0F, 0.4375F, 0.5625F, 1F, 0.5625F) | |
} | |
} | |
override def onBlockPlaced(worldIn: World, pos: BlockPos, facing: EnumFacing, hitX: Float, | |
hitY: Float, hitZ: Float, meta: Int, placer: EntityLivingBase): IBlockState = { | |
var state = this.getStateFromMeta(meta) | |
facing.getAxis match { | |
case Axis.Y => | |
state = state.withProperty(AXIS, placer.getHorizontalFacing.getAxis) | |
case _ => state = state.withProperty(AXIS, Axis.Y) | |
} | |
state | |
} | |
override def createBlockState(): BlockState = { | |
val MAX_BRIDGE_LENGTH = 1 | |
this.BRIDGE_LENGTH = StateProperties.createPropInt("bridge_length", 0, MAX_BRIDGE_LENGTH) | |
this.BRIDGE_INDEX = StateProperties.createPropInt("bridge_index", 0, MAX_BRIDGE_LENGTH) | |
this.createState(this, | |
Seq[IProperty[_]](AXIS, BRIDGE_LENGTH, BRIDGE_INDEX), | |
Seq[IUnlistedProperty[_]](OBJModel.OBJProperty.instance)) | |
} | |
override def getExtendedState(state: IBlockState, world: IBlockAccess, | |
pos: BlockPos): IBlockState = { | |
//println(state.isInstanceOf[IExtendedBlockState]) | |
state match { | |
case extended: IExtendedBlockState => | |
val rot = new V3O(0, 0, 0) | |
//println(state.getValue(AXIS)) | |
extended.getValue(AXIS) match { | |
case Axis.X => //rot.y += 90 | |
case Axis.Y => rot.x += 90 | |
case Axis.Z => | |
} | |
//rot.x += 90 | |
val offsetRot = this.updateSagLogic(state, world, pos) | |
if (offsetRot != null) { | |
} | |
println(rot) | |
extended.withProperty(OBJModel.OBJProperty.instance, | |
new OBJState(Lists.newArrayList(OBJModel.Group.ALL), true, | |
new TRSRTransformation( | |
new Vector3f(0, 0, 0), { | |
val quat = new Quat4f() | |
rot.x = 90 | |
quat.mul({ | |
val q = new Quat4f() | |
q.set(new AxisAngle4f(1, 0, 0, rot.x_f() / 180 * 3.14F)) | |
q | |
}) | |
/* | |
quat.mul({ | |
val q = new Quat4f() | |
q.set(new AxisAngle4f(0, 1, 0, rot.y_f())) | |
q | |
}) | |
quat.mul({ | |
val q = new Quat4f() | |
q.set(new AxisAngle4f(0, 0, 1, rot.z_f())) | |
q | |
}) | |
*/ | |
quat | |
}, | |
null, null))) | |
case _ => state | |
} | |
} | |
def updateSagLogic(state: IBlockState, worldIn: IBlockAccess, pos: BlockPos): (Float, V3O) = { | |
if (!worldIn.isInstanceOf[World]) return null | |
// https://www.desmos.com/calculator/rv0kzpd0n3 | |
// m = 0.08xa^(-2) | |
// y = 0.04((x/a)^(2)-b) | |
// p1 = (l/2)^(2) | |
// a = p1 <= 25 ? 1 : l/10 | |
// b = p1 <= 25 ? p1 : 25 | |
val l = state.getValue(BRIDGE_LENGTH) | |
val x = state.getValue(BRIDGE_INDEX) | |
val p1 = Math.pow(l / 2, 2) | |
val a = if (p1 <= 25) 1 else l / 10 | |
val b = Math.min(p1, 25) | |
val y = 0.04 * (Math.pow(x / a, 2) - b) | |
val m = 0.08 * x * Math.pow(a, -2) | |
state.getValue(AXIS) match { | |
case Axis.X => // rotate around Z | |
(y.toFloat, new V3O(0, 0, m)) | |
case Axis.Z => // rotate around X | |
(y.toFloat, new V3O(m, 0, 0)) | |
case _ => null | |
} | |
} | |
override def isOpaqueCube: Boolean = false | |
override def isFullCube: Boolean = false | |
override def isVisuallyOpaque: Boolean = false | |
override def getRenderType: Int = 3 | |
override def getMetaFromState(state: IBlockState): Int = { | |
state.getValue(AXIS).ordinal() | |
} | |
override def getStateFromMeta(meta: Int): IBlockState = { | |
this.getBaseExtState.withProperty(AXIS, Axis.values()(meta)) | |
} | |
override def usesOBJ: Boolean = true | |
override def hasCustomItemModel: Boolean = true | |
override def onNeighborBlockChange(worldIn: World, pos: BlockPos, state: IBlockState, | |
neighborBlock: Block): Unit = { | |
if (neighborBlock == this) { | |
println("notify min please") | |
this.notifyMinToUpdateLine(worldIn, pos, state) | |
} | |
} | |
def notifyMinToUpdateLine(world: World, pos: BlockPos, state: IBlockState): Unit = { | |
println("notifying something") | |
val axis = state.getValue(AXIS) | |
println(this.isEndRope(world, pos, state)) | |
if (this.isEndRope(world, pos, state)) { | |
println("update") | |
this.updateLine(world, pos, state) | |
} | |
else { | |
val axisOffset = new V3O(axis, -1) | |
println("AxisOff: " + axisOffset) | |
val nextPos = new V3O(pos) + axisOffset | |
val nextState = nextPos.getBlockState(world) | |
println("try to notify " + nextPos) | |
val nextIsRope = nextState.getBlock == this && nextState.getValue(AXIS) == axis | |
println(nextIsRope) | |
if (nextIsRope) { | |
} | |
/* | |
if (nextState.getBlock == this && nextState.getValue(AXIS) == axis) { | |
println("notifying next") | |
this.notifyMinToUpdateLine(world, nextPos.toBlockPos, nextState) | |
} | |
else println("didnt notify") | |
*/ | |
} | |
} | |
def updateLine(world: World, pos: BlockPos, state: IBlockState): Unit = { | |
println("updating from " + pos) | |
val axis = state.getValue(AXIS) | |
//return | |
def getLastPos(dir: AxisDirection): BlockPos = { | |
var currentPos = pos | |
var currentState = state | |
do { | |
currentPos = V3O.offset(currentPos, axis, dir) | |
currentState = world.getBlockState(currentPos) | |
} while (currentState.getBlock == this && currentState.getValue(AXIS) == axis) | |
currentPos | |
} | |
val posMin = new V3O(pos) | |
val posMax = new V3O(getLastPos(AxisDirection.POSITIVE)) | |
val posMin_2D = posMin.copy().packAxis(axis) | |
val posMax_2D = posMax.copy().packAxis(axis) | |
val lengthOfBridge = (posMax_2D.x - posMin_2D.x).toInt | |
println(lengthOfBridge) | |
/* | |
for (i <- -lengthOfBridge / 2 until lengthOfBridge / 2) { | |
val blockPos = posMin + (axis, scale = i) | |
blockPos.getBlockState(world). | |
withProperty(BRIDGE_LENGTH, Int.box(lengthOfBridge)). | |
withProperty(BRIDGE_INDEX, Int.box(i)) | |
blockPos.markBlockForUpdate(world) | |
} | |
*/ | |
} | |
def shouldCheckForKnot: Boolean = true | |
def isEndRope(world: World, pos: BlockPos, state: IBlockState): Boolean = { | |
return !world.isAirBlock(pos.down()) | |
val axis = state.getValue(AXIS) | |
def isRope(world: World, pos: BlockPos, doCheckKnot: Boolean = true): Boolean = { | |
if (world.getBlockState(pos).getBlock == this) return true | |
val checkDatKnot = if (!this.shouldCheckForKnot) doCheckKnot else false | |
if (checkDatKnot && world.getBlockState(pos).getBlock.isInstanceOf[BlockFence]) { | |
EntityLeashKnot.getKnotForPosition(world, pos) match { | |
case knot: EntityRopeKnot => return true | |
case _ => | |
} | |
} | |
false | |
} | |
axis match { | |
case Axis.X => | |
if (!(isRope(world, pos.add(1, 0, 0)) && isRope(world, pos.add(-1, 0, 0)))) | |
return true | |
case Axis.Z => | |
if (!(isRope(world, pos.add(0, 0, 1)) && isRope(world, pos.add(0, 0, -1)))) | |
return true | |
case Axis.Y => | |
if (!(isRope(world, pos.add(0, 1, 0), doCheckKnot = false) && | |
isRope(world, pos.add(0, -1, 0), doCheckKnot = false))) | |
return true | |
case _ => | |
} | |
false | |
} | |
def isValidAxis(axis: Axis): Boolean = true | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment