From 38adcdbee15eca22d5523079a1f2c83968b54936 Mon Sep 17 00:00:00 2001 From: Chicken Bones Date: Mon, 3 Jun 2013 19:58:06 +1000 Subject: [PATCH] Added buttons Moved cuboid render function to CCC-Public Fixed a redstone transmission bug Added Tick Scheduler --- codechicken/microblock/CommonMicroblock.scala | 86 +-------- codechicken/microblock/HolloMicroblock.scala | 2 +- codechicken/multipart/BlockMultipart.scala | 7 + codechicken/multipart/IRedstonePart.scala | 22 ++- .../multipart/MultipartGenerator.scala | 12 +- codechicken/multipart/PartMap.java | 2 - codechicken/multipart/TCuboidPart.scala | 2 +- codechicken/multipart/TMultiPart.scala | 15 +- codechicken/multipart/TickScheduler.scala | 124 ++++++++++++ codechicken/multipart/TileMultipart.scala | 171 +++++++++++++---- .../multipart/handler/EventHandler.scala | 12 +- codechicken/multipart/handler/Proxies.scala | 4 + .../multipart/minecraft/ButtonPart.java | 178 ++++++++++++++++++ codechicken/multipart/minecraft/Content.java | 12 +- .../multipart/minecraft/EventHandler.java | 4 + .../multipart/minecraft/LeverPart.java | 44 +++-- .../multipart/minecraft/McMetaPart.java | 15 ++ .../multipart/minecraft/PartMetaAccess.java | 2 +- .../multipart/minecraft/TorchPart.java | 9 - 19 files changed, 561 insertions(+), 162 deletions(-) create mode 100644 codechicken/multipart/TickScheduler.scala create mode 100644 codechicken/multipart/minecraft/ButtonPart.java diff --git a/codechicken/microblock/CommonMicroblock.scala b/codechicken/microblock/CommonMicroblock.scala index fce8fc6..3116558 100644 --- a/codechicken/microblock/CommonMicroblock.scala +++ b/codechicken/microblock/CommonMicroblock.scala @@ -28,6 +28,8 @@ import codechicken.scala.JSeq import codechicken.scala.ScalaBridge._ import codechicken.core.data.MCDataOutput import codechicken.core.data.MCDataInput +import codechicken.core.render.RenderUtils +import codechicken.core.render.IFaceRenderer object CommonMicroblock { @@ -79,86 +81,16 @@ import CommonMicroblock._ def renderCuboid(pos:Vector3, olm:LazyLightMatrix, mat:IMicroMaterial, c:Cuboid6, sideMask:Int) { - val x1 = c.min.x - val x2 = c.max.x - val y1 = c.min.y - val y2 = c.max.y - val z1 = c.min.z - val z2 = c.max.z - var u1:Double = 0 - var u2:Double = 0 - var v1:Double = 0 - var v2:Double = 0 - var side = 0 var lightMatrix:LightMatrix = null if(olm != null) lightMatrix = olm.lightMatrix - - if((sideMask&1) == 0) - { - u1 = x1; v1 = z1 - u2 = x2; v2 = z2 - face(0).set(x1, y1, z2, u1, v2) - face(1).set(x1, y1, z1, u1, v1) - face(2).set(x2, y1, z1, u2, v1) - face(3).set(x2, y1, z2, u2, v2) - mat.renderMicroFace(face, if(c.min.y > 0) 6 else 0, pos, lightMatrix, this) - } - - if((sideMask&2) == 0) - { - u1 = x1+2; v1 = z1 - u2 = x2+2; v2 = z2 - face(0).set(x2, y2, z2, u2, v2) - face(1).set(x2, y2, z1, u2, v1) - face(2).set(x1, y2, z1, u1, v1) - face(3).set(x1, y2, z2, u1, v2) - mat.renderMicroFace(face, if(c.max.y < 1) 7 else 1, pos, lightMatrix, this) - } - - if((sideMask&4) == 0) - { - u1 = 1-x1+4; v1 = 1-y2 - u2 = 1-x2+4; v2 = 1-y1 - face(0).set(x1, y1, z1, u1, v2) - face(1).set(x1, y2, z1, u1, v1) - face(2).set(x2, y2, z1, u2, v1) - face(3).set(x2, y1, z1, u2, v2) - mat.renderMicroFace(face, if(c.min.z > 0) 8 else 2, pos, lightMatrix, this) - } - - if((sideMask&8) == 0) - { - u1 = x1+6; v1 = 1-y2 - u2 = x2+6; v2 = 1-y1 - face(0).set(x2, y1, z2, u2, v2) - face(1).set(x2, y2, z2, u2, v1) - face(2).set(x1, y2, z2, u1, v1) - face(3).set(x1, y1, z2, u1, v2) - mat.renderMicroFace(face, if(c.max.z < 1) 9 else 3, pos, lightMatrix, this) - } - - if((sideMask&0x10) == 0) - { - u1 = z1+8; v1 = 1-y2 - u2 = z2+8; v2 = 1-y1 - face(0).set(x1, y1, z2, u2, v2) - face(1).set(x1, y2, z2, u2, v1) - face(2).set(x1, y2, z1, u1, v1) - face(3).set(x1, y1, z1, u1, v2) - mat.renderMicroFace(face, if(c.min.x > 0) 10 else 4, pos, lightMatrix, this) - } - - if((sideMask&0x20) == 0) - { - u1 = 1-z1+10; v1 = 1-y2 - u2 = 1-z2+10; v2 = 1-y1 - face(0).set(x2, y1, z1, u1, v2) - face(1).set(x2, y2, z1, u1, v1) - face(2).set(x2, y2, z2, u2, v1) - face(3).set(x2, y1, z2, u2, v2) - mat.renderMicroFace(face, if(c.max.x < 1) 11 else 5, pos, lightMatrix, this) - } + + RenderUtils.renderBlock(c, sideMask, pos, lightMatrix, + new IFaceRenderer() + { + def renderFace(face:Array[Vertex5], side:Int, pos:Vector3, lightMatrix:LightMatrix) = + mat.renderMicroFace(face, side, pos, lightMatrix, MicroblockClient.this) + }) } } diff --git a/codechicken/microblock/HolloMicroblock.scala b/codechicken/microblock/HolloMicroblock.scala index 03e3f82..b11cef2 100644 --- a/codechicken/microblock/HolloMicroblock.scala +++ b/codechicken/microblock/HolloMicroblock.scala @@ -89,7 +89,7 @@ class HollowMicroblockClient(shape$:Byte = 0, material$:Int = 0) extends HollowM val icont = new IconTransformation(renderBlocks.overrideBlockTexture) renderHollow(Vector3.fromTileEntity(tile), null, null, getBounds, 0, false, (pos:Vector3, olm:LazyLightMatrix, mat:IMicroMaterial, c:Cuboid6, sideMask:Int)=> - RenderUtils.renderBlock(c, sideMask, pos, icont)) + RenderUtils.renderBlock(c, sideMask, pos, null, -1, icont)) } override def render(pos:Vector3, olm:LazyLightMatrix, mat:IMicroMaterial, c:Cuboid6, sideMask:Int) diff --git a/codechicken/multipart/BlockMultipart.scala b/codechicken/multipart/BlockMultipart.scala index b384ef5..94490f7 100644 --- a/codechicken/multipart/BlockMultipart.scala +++ b/codechicken/multipart/BlockMultipart.scala @@ -258,6 +258,13 @@ trait BlockMultipart extends Block if(tile != null) return tile.canConnectRedstone(side) return false } + + 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) + } } class BlockMultipartImpl(id:Int) extends Block(id, Material.rock) with BlockMultipart diff --git a/codechicken/multipart/IRedstonePart.scala b/codechicken/multipart/IRedstonePart.scala index 7a7c9cd..1f863da 100644 --- a/codechicken/multipart/IRedstonePart.scala +++ b/codechicken/multipart/IRedstonePart.scala @@ -59,7 +59,7 @@ trait TRedstoneTile extends TileMultipart with IRedstoneConnector override def weakPowerLevel(side:Int):Int = { - val mask = openConnections(side)&otherConnectionMap(worldObj, xCoord, yCoord, zCoord, side) + val mask = openConnections(side)&otherConnectionMap(worldObj, xCoord, yCoord, zCoord, side, true) var max = 0 partList.foreach(p => if((connectionMask(p, side)&mask) > 0) @@ -73,7 +73,7 @@ trait TRedstoneTile extends TileMultipart with IRedstoneConnector override def canConnectRedstone(side:Int):Boolean = { val vside = vanillaToSide(side) - return (getConnectionMap(vside) & otherConnectionMap(worldObj, xCoord, yCoord, zCoord, vside)) > 0 + return (getConnectionMap(vside) & otherConnectionMap(worldObj, xCoord, yCoord, zCoord, vside, false)) > 0 } def getConnectionMap(side:Int):Int = @@ -116,10 +116,13 @@ object RedstoneInteractions def vanillaToSide(vside:Int) = sideVanillaMap(vside+1) - def otherConnectionMap(world:IBlockAccess, x:Int, y:Int, z:Int, side:Int):Int = - getConnectionMap(world, x+offsetsXForSide(side), y+offsetsYForSide(side), z+offsetsZForSide(side), side^1) + def otherConnectionMap(world:IBlockAccess, x:Int, y:Int, z:Int, side:Int, power:Boolean):Int = + getConnectionMap(world, x+offsetsXForSide(side), y+offsetsYForSide(side), z+offsetsZForSide(side), side^1, power) - def getConnectionMap(world:IBlockAccess, x:Int, y:Int, z:Int, side:Int):Int = + /** + * @param power If true, don't test canConnectRedstone on blocks, just get a power transmission mask rather than a visual connection + */ + def getConnectionMap(world:IBlockAccess, x:Int, y:Int, z:Int, side:Int, power:Boolean):Int = { val tile = world.getBlockTileEntity(x, y, z) if(tile.isInstanceOf[IRedstoneConnector]) @@ -132,8 +135,13 @@ object RedstoneInteractions if(block.isInstanceOf[IRedstoneConnectorBlock]) return block.asInstanceOf[IRedstoneConnectorBlock].getConnectionMap(x, y, z, side) - if(side == 0) + //start vanilla interactions + if(side == 0)//vanilla doesn't handle side 0 + { + if(power) + return 0x1F return 0 + } if(block == Block.redstoneWire) { @@ -158,7 +166,7 @@ object RedstoneInteractions return 0 } - if(block.canConnectRedstone(world, x, y, z, vside)) + if(power || block.canConnectRedstone(world, x, y, z, vside))//some blocks accept power without visualising connections return 0x1F return 0 diff --git a/codechicken/multipart/MultipartGenerator.scala b/codechicken/multipart/MultipartGenerator.scala index b6a7e11..d8f7f87 100644 --- a/codechicken/multipart/MultipartGenerator.scala +++ b/codechicken/multipart/MultipartGenerator.scala @@ -9,6 +9,8 @@ import codechicken.core.vec.BlockCoord import codechicken.multipart.handler.MultipartProxy import cpw.mods.fml.common.FMLCommonHandler import cpw.mods.fml.relauncher.Side +import codechicken.core.packet.PacketCustom +import net.minecraft.network.packet.Packet53BlockChange object MultipartGenerator { @@ -193,9 +195,11 @@ object MultipartGenerator var ntile = tile if(tile != null) { - if(!tile.loaded) + val converted = !tile.loaded + if(converted)//perform client conversion { - world.setBlock(pos.x, pos.y, pos.z, MultipartProxy.block.blockID, 0, 3) + world.setBlock(pos.x, pos.y, pos.z, MultipartProxy.block.blockID, 0, 1) + PacketCustom.sendToChunk(new Packet53BlockChange(pos.x, pos.y, pos.z, world), world, pos.x>>4, pos.z>>4) ntile.writeAddPart(ntile.partList(0)) } @@ -207,11 +211,13 @@ object MultipartGenerator world.setBlockTileEntity(pos.x, pos.y, pos.z, ntile) ntile.loadFrom(tile) } - else if(!tile.loaded)//converted + else if(converted) { ntile.validate() world.setBlockTileEntity(pos.x, pos.y, pos.z, ntile) } + if(converted) + ntile.partList(0).onConverted() } else { diff --git a/codechicken/multipart/PartMap.java b/codechicken/multipart/PartMap.java index 2bb3faa..52ddeb0 100644 --- a/codechicken/multipart/PartMap.java +++ b/codechicken/multipart/PartMap.java @@ -1,7 +1,5 @@ package codechicken.multipart; -import java.util.Arrays; - public enum PartMap { BOTTOM(0), diff --git a/codechicken/multipart/TCuboidPart.scala b/codechicken/multipart/TCuboidPart.scala index 66f5826..b40a4c2 100644 --- a/codechicken/multipart/TCuboidPart.scala +++ b/codechicken/multipart/TCuboidPart.scala @@ -23,6 +23,6 @@ trait TCuboidPart extends TMultiPart override def drawBreaking(renderBlocks:RenderBlocks) { CCRenderState.reset() - RenderUtils.renderBlock(getBounds, 0, Vector3.fromTileEntity(tile), new IconTransformation(renderBlocks.overrideBlockTexture)) + RenderUtils.renderBlock(getBounds, 0, Vector3.fromTileEntity(tile), null, -1, new IconTransformation(renderBlocks.overrideBlockTexture)) } } \ No newline at end of file diff --git a/codechicken/multipart/TMultiPart.scala b/codechicken/multipart/TMultiPart.scala index 039052a..13b679c 100644 --- a/codechicken/multipart/TMultiPart.scala +++ b/codechicken/multipart/TMultiPart.scala @@ -23,6 +23,7 @@ import codechicken.scala.ScalaBridge._ import codechicken.core.lighting.LazyLightMatrix import codechicken.core.data.MCDataOutput import codechicken.core.data.MCDataInput +import net.minecraft.entity.Entity abstract class TMultiPart { @@ -31,9 +32,11 @@ abstract class TMultiPart def getTile():TileEntity = tile def getType:String - def bind(tile:TileMultipart) + def bind(t:TileMultipart) { - TMultiPart.this.tile = tile + if(tile != null && t == null) + onRemoved() + tile = t } def getSlotMask:Int = 0 @@ -67,13 +70,17 @@ abstract class TMultiPart def onWorldJoin(world:World){onPartChanged()} def onPartChanged(){} def onNeighbourChanged(){} + def onRemoved(){} + def onConverted(){} - def activate(player:EntityPlayer, part:MovingObjectPosition, item:ItemStack):Boolean = false - def click(player:EntityPlayer, part:MovingObjectPosition, item:ItemStack){} def doesTick = true def update(){} def scheduledTick(){} + def pickItem(hit:MovingObjectPosition):ItemStack = null + def activate(player:EntityPlayer, part:MovingObjectPosition, item:ItemStack):Boolean = false + def click(player:EntityPlayer, part:MovingObjectPosition, item:ItemStack){} + def onEntityCollision(entity:Entity){} def sendDescUpdate() = writeDesc(tile.getWriteStream(this)) def scheduleTick(ticks:Int) = TickScheduler.scheduleTick(this, ticks) diff --git a/codechicken/multipart/TickScheduler.scala b/codechicken/multipart/TickScheduler.scala new file mode 100644 index 0000000..9c990e1 --- /dev/null +++ b/codechicken/multipart/TickScheduler.scala @@ -0,0 +1,124 @@ +package codechicken.multipart + +import codechicken.core.world.WorldExtensionInstantiator +import codechicken.core.world.WorldExtension +import codechicken.core.world.ChunkExtension +import net.minecraft.world.chunk.Chunk +import net.minecraft.world.World +import net.minecraft.nbt.NBTTagCompound +import scala.collection.mutable.ListBuffer +import net.minecraft.nbt.NBTTagList +import codechicken.core.vec.BlockCoord +import net.minecraft.world.ChunkCoordIntPair +import net.minecraft.world.ChunkPosition +import scala.collection.mutable.HashSet + +object TickScheduler extends WorldExtensionInstantiator +{ + class PartTickEntry(val part:TMultiPart, var ticks:Int) + + class WorldTickScheduler(world:World) extends WorldExtension(world) + { + var tickChunks = HashSet[ChunkTickScheduler]() + + def scheduleTick(part:TMultiPart, ticks:Int) + { + getChunkExtension(part.tile.xCoord>>4, part.tile.zCoord>>4).asInstanceOf[ChunkTickScheduler].scheduleTick(part, ticks) + } + + override def preTick() + { + if(!tickChunks.isEmpty) + tickChunks = tickChunks.filter(_.processTicks()) + } + } + + def createWorldExtension(world:World) = new WorldTickScheduler(world) + + class ChunkTickScheduler(chunk:Chunk, world:WorldTickScheduler) extends ChunkExtension(chunk, world) + { + import codechicken.multipart.handler.MultipartProxy._ + + var tickList = ListBuffer[PartTickEntry]() + + def scheduleTick(part:TMultiPart, ticks:Int) + { + tickList+=new PartTickEntry(part, ticks) + if(tickList.size == 1) + world.tickChunks+=this + } + + def processTicks():Boolean = + { + tickList = tickList.filter(processTick(_)) + return !tickList.isEmpty + } + + def processTick(e:PartTickEntry):Boolean = + { + e.ticks-=1 + if(e.ticks == 0) + { + if(e.part.tile != null) + e.part.scheduledTick() + return false + } + return true + } + + override def saveData(data:NBTTagCompound) + { + val tagList = new NBTTagList + tickList.foreach(e => { + val part = e.part + if(part.tile != null) + { + val tag = new NBTTagCompound + tag.setShort("pos", indexInChunk(new BlockCoord(part.tile)).toShort) + tag.setByte("i", part.tile.partList.indexOf(part).toByte) + tag.setInteger("ticks", e.ticks) + tagList.appendTag(tag) + } + }) + if(tagList.tagCount > 0) + data.setTag("multipartTicks", tagList) + } + + override def loadData(data:NBTTagCompound) + { + tickList.clear() + if(!data.hasKey("multipartTicks")) + return + + val tagList = data.getTagList("multipartTicks") + val cc = new ChunkCoordIntPair(0, 0) + for(i <- 0 until tagList.tagCount) + { + val tag = tagList.tagAt(i).asInstanceOf[NBTTagCompound] + val pos = indexInChunk(cc, tag.getShort("pos")) + val tile = chunk.chunkTileEntityMap.get(new ChunkPosition(pos.x, pos.y, pos.z)) + if(tile.isInstanceOf[TileMultipart]) + tickList+=new PartTickEntry(tile.asInstanceOf[TileMultipart].partList(tag.getByte("i")), tag.getInteger("ticks")) + } + } + + override def load() + { + if(!tickList.isEmpty) + world.tickChunks+=this + } + + override def unload() + { + if(!tickList.isEmpty) + world.tickChunks-=this + } + } + + def createChunkExtension(chunk:Chunk, world:WorldExtension) = new ChunkTickScheduler(chunk, world.asInstanceOf[WorldTickScheduler]) + + def scheduleTick(part:TMultiPart, ticks:Int) + { + getExtension(part.tile.worldObj).asInstanceOf[WorldTickScheduler].scheduleTick(part, ticks) + } +} \ No newline at end of file diff --git a/codechicken/multipart/TileMultipart.scala b/codechicken/multipart/TileMultipart.scala index 73a0a65..f71fe55 100644 --- a/codechicken/multipart/TileMultipart.scala +++ b/codechicken/multipart/TileMultipart.scala @@ -37,6 +37,7 @@ import codechicken.core.lighting.LazyLightMatrix import net.minecraft.world.ChunkCoordIntPair import net.minecraft.entity.item.EntityItem import net.minecraft.entity.player.EntityPlayer +import net.minecraft.entity.Entity trait TileMultipart extends TileEntity { @@ -304,6 +305,13 @@ trait TileMultipart extends TileEntity tag.setTag("parts", taglist) } + def onEntityCollision(entity:Entity) + { + TileMultipartObj.startOperation(this) + partList.foreach(_.onEntityCollision(entity)) + TileMultipartObj.finishOperation(this) + } + def strongPowerLevel(side:Int) = 0 def weakPowerLevel(side:Int) = 0 @@ -336,57 +344,148 @@ object TileMultipartObj { var renderID:Int = -1 - private var operatingTile = new ThreadLocal[TileMultipart] - private val removalQueue = Queue[TMultiPart]() - private val additionQueue = Queue[TMultiPart]() - - def startOperation(tile:TileMultipart) + class TileOperationSet { - if(operatingTile.get != null) - throw new IllegalStateException("Recursive operations not implemented") + var tile:TileMultipart = _ + var depth = 0 + private val removalQueue = Queue[TMultiPart]() + private val additionQueue = Queue[TMultiPart]() - operatingTile.set(tile) + def start(t:TileMultipart) + { + tile = t + depth = 1 + } + + def queueAddition(part:TMultiPart) + { + if(!additionQueue.contains(part)) + additionQueue+=part + } + + def queueRemoval(part:TMultiPart) + { + if(!removalQueue.contains(part)) + removalQueue+=part + } + + def finish() + { + if(removalQueue.isEmpty && additionQueue.isEmpty) + return + + var otile = tile + val world = tile.worldObj + val pos = new BlockCoord(tile) + while(!removalQueue.isEmpty) + otile = otile.remPart(removalQueue.dequeue) + + while(!additionQueue.isEmpty) + MultipartGenerator.addPart(world, pos, additionQueue.dequeue) + } } - def finishOperation(tile:TileMultipart) + class OperationSynchroniser { - operatingTile.remove + private val operations = ArrayBuffer[TileOperationSet]() + private var depth = 0 - if(removalQueue.isEmpty && additionQueue.isEmpty) - return + def startOperation(tile:TileMultipart) + { + var i = 0 + while(i < depth) + { + val op = operations(i) + if(op.tile == tile) + { + op.depth+=1 + return + } + i+=1 + } + if(depth == operations.length) + operations+=new TileOperationSet + operations(depth).start(tile) + depth+=1 + } - var otile = tile - val world = tile.worldObj - val pos = new BlockCoord(tile) - while(!removalQueue.isEmpty) - otile = otile.remPart(removalQueue.dequeue) + def finishOperation(tile:TileMultipart) + { + var i = depth-1 + while(i >= 0) + { + val op = operations(i) + if(op.tile == tile) + { + op.depth-=1 + if(op.depth == 0) + { + if(i != depth-1) + throw new IllegalStateException("Tried to finish an operation that was not on top") + depth-=1 + op.finish() + } + return + } + i-=1 + } + throw new IllegalStateException("Inconsistant Operation stack") + } - while(!additionQueue.isEmpty) - MultipartGenerator.addPart(world, pos, additionQueue.dequeue) - } - - def queueRemoval(tile:TileMultipart, part:TMultiPart):Boolean = - { - if(tile != operatingTile.get) + def queueRemoval(tile:TileMultipart, part:TMultiPart):Boolean = + { + var i = depth-1 + while(i >= 0) + { + val op = operations(i) + if(op.tile == tile) + { + op.queueRemoval(part) + return true + } + i-=1 + } return false + } - if(!removalQueue.contains(part)) - removalQueue+=part - return true + def queueAddition(world:World, pos:BlockCoord, part:TMultiPart):Boolean = + { + var i = depth-1 + while(i >= 0) + { + val op = operations(i) + val opt = op.tile + if(opt.worldObj == world && opt.xCoord == pos.x && opt.yCoord == pos.y && opt.zCoord == pos.z) + { + op.queueRemoval(part) + return true + } + i-=1 + } + return false + } } - def queueAddition(world:World, pos:BlockCoord, part:TMultiPart):Boolean = + private var operationSync_ = new ThreadLocal[OperationSynchroniser] + private def operationSync():OperationSynchroniser = { - val opt = operatingTile.get - if(opt == null || opt.worldObj != world || opt.xCoord != pos.x || opt.yCoord != pos.y || opt.zCoord != pos.z) - return false - - if(!additionQueue.contains(part)) - additionQueue+=part - - return true + var r = operationSync_.get + if(r == null) + { + r = new OperationSynchroniser + operationSync_.set(r) + } + return r } + def startOperation(tile:TileMultipart) = operationSync.startOperation(tile) + + def finishOperation(tile:TileMultipart) = operationSync.finishOperation(tile) + + def queueRemoval(tile:TileMultipart, part:TMultiPart):Boolean = operationSync.queueRemoval(tile, part) + + def queueAddition(world:World, pos:BlockCoord, part:TMultiPart):Boolean = operationSync.queueAddition(world, pos, part) + def getOrConvertTile(world:World, pos:BlockCoord):TileMultipart = { val t = world.getBlockTileEntity(pos.x, pos.y, pos.z) diff --git a/codechicken/multipart/handler/EventHandler.scala b/codechicken/multipart/handler/EventHandler.scala index 99897e3..521285d 100644 --- a/codechicken/multipart/handler/EventHandler.scala +++ b/codechicken/multipart/handler/EventHandler.scala @@ -20,10 +20,11 @@ import cpw.mods.fml.common.TickType import scala.collection.JavaConverters._ import java.util.List import net.minecraft.entity.player.EntityPlayerMP +import net.minecraftforge.event.EventPriority object MultipartEventHandler extends IConnectionHandler with ITickHandler { - @ForgeSubscribe + @ForgeSubscribe(priority = EventPriority.HIGHEST) def tileEntityLoad(event:ChunkDataEvent.Load) { MultipartSaveLoad.loadTiles(event.getChunk()) @@ -67,8 +68,11 @@ object MultipartEventHandler extends IConnectionHandler with ITickHandler def tickStart(tickType:EnumSet[TickType], data:Object*){} def tickEnd(tickType:EnumSet[TickType], data:Object*) { - MultipartSPH.onTickEnd( - MinecraftServer.getServer.getConfigurationManager.playerEntityList - .asInstanceOf[List[EntityPlayerMP]].asScala) + if(tickType.contains(TickType.SERVER)) + { + MultipartSPH.onTickEnd( + MinecraftServer.getServer.getConfigurationManager.playerEntityList + .asInstanceOf[List[EntityPlayerMP]].asScala) + } } } \ No newline at end of file diff --git a/codechicken/multipart/handler/Proxies.scala b/codechicken/multipart/handler/Proxies.scala index abcbed2..9a5cf25 100644 --- a/codechicken/multipart/handler/Proxies.scala +++ b/codechicken/multipart/handler/Proxies.scala @@ -25,6 +25,8 @@ import cpw.mods.fml.common.registry.TickRegistry import net.minecraft.block.Block import net.minecraft.world.ChunkCoordIntPair import codechicken.core.vec.BlockCoord +import codechicken.core.world.WorldExtensionManager +import codechicken.multipart.TickScheduler class MultipartProxy_serverImpl { @@ -48,6 +50,8 @@ class MultipartProxy_serverImpl PacketCustom.assignHandler(MultipartSPH.channel, MultipartSPH) NetworkRegistry.instance.registerConnectionHandler(MultipartEventHandler) TickRegistry.registerTickHandler(MultipartEventHandler, Side.SERVER) + + WorldExtensionManager.registerWorldExtension(TickScheduler) } def getFreeBlockID(preferred:Int):Int = diff --git a/codechicken/multipart/minecraft/ButtonPart.java b/codechicken/multipart/minecraft/ButtonPart.java new file mode 100644 index 0000000..bd174d8 --- /dev/null +++ b/codechicken/multipart/minecraft/ButtonPart.java @@ -0,0 +1,178 @@ +package codechicken.multipart.minecraft; + +import codechicken.core.vec.BlockCoord; +import codechicken.core.vec.Cuboid6; +import codechicken.core.vec.Vector3; +import codechicken.multipart.IRedstonePart; +import codechicken.multipart.TickScheduler; +import net.minecraft.block.Block; +import net.minecraft.block.BlockButton; +import net.minecraft.entity.Entity; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.projectile.EntityArrow; +import net.minecraft.item.ItemStack; +import net.minecraft.util.MovingObjectPosition; +import net.minecraft.world.World; +import net.minecraftforge.common.ForgeDirection; + +public class ButtonPart extends McSidedMetaPart implements IRedstonePart +{ + public static BlockButton stoneButton = (BlockButton) Block.stoneButton; + public static BlockButton woodenButton = (BlockButton) Block.woodenButton; + public static int[] metaSideMap = new int[]{-1, 4, 5, 2, 3}; + public static int[] sideMetaMap = new int[]{-1, -1, 3, 4, 1, 2}; + + public static BlockButton getButton(int meta) + { + return (meta&0x10) > 0 ? woodenButton : stoneButton; + } + + public ButtonPart() + { + } + + public ButtonPart(int meta) + { + super(meta); + } + + @Override + public int sideForMeta(int meta) + { + return metaSideMap[meta&7]; + } + + @Override + public Block getBlock() + { + return getButton(meta); + } + + @Override + public String getType() + { + return "mc_button"; + } + + public int delay() + { + return sensitive() ? 30 : 20; + } + + public boolean sensitive() + { + return (meta&0x10) > 0; + } + + @Override + public Cuboid6 getBounds() + { + int m = meta & 7; + double d = pressed() ? 0.0625 : 0.125; + + if (m == 1) + return new Cuboid6(0.0, 0.375, 0.5 - 0.1875, d, 0.625, 0.5 + 0.1875); + if (m == 2) + return new Cuboid6(1.0 - d, 0.375, 0.5 - 0.1875, 1.0, 0.625, 0.5 + 0.1875); + if (m == 3) + return new Cuboid6(0.5 - 0.1875, 0.375, 0.0, 0.5 + 0.1875, 0.625, d); + if (m == 4) + return new Cuboid6(0.5 - 0.1875, 0.375, 1.0 - d, 0.5 + 0.1875, 0.625, 1.0); + + return null;//falloff + } + + public static McBlockPart placement(World world, BlockCoord pos, EntityPlayer player, int side, int type) + { + if(side == 0 || side == 1) + return null; + + pos = pos.copy().offset(side^1); + if(!world.isBlockSolidOnSide(pos.x, pos.y, pos.z, ForgeDirection.getOrientation(side))) + return null; + + return new ButtonPart(sideMetaMap[side^1]|type<<4); + } + + @Override + public boolean activate(EntityPlayer player, MovingObjectPosition part, ItemStack item) + { + if(pressed()) + return false; + + if(!getTile().worldObj.isRemote) + toggle(); + + return true; + } + + @Override + public void scheduledTick() + { + if(pressed()) + updateState(); + } + + public boolean pressed() + { + return (meta&8) > 0; + } + + @Override + public void onEntityCollision(Entity entity) + { + if(!pressed() && !getTile().worldObj.isRemote && entity instanceof EntityArrow) + updateState(); + } + + private void toggle() + { + boolean in = !pressed(); + meta^=8; + getTile().worldObj.playSoundEffect(getTile().xCoord + 0.5, getTile().yCoord + 0.5, getTile().zCoord + 0.5, "random.click", 0.3F, in ? 0.6F : 0.5F); + if(in) + TickScheduler.scheduleTick(this, delay()); + + sendDescUpdate(); + tile().notifyPartChange(); + tile().notifyNeighborChange(metaSideMap[meta&7]); + tile().markDirty(); + } + + private void updateState() + { + boolean arrows = sensitive() && !getTile().worldObj.getEntitiesWithinAABB(EntityArrow.class, + getBounds().add(Vector3.fromTileEntity(getTile())).toAABB()).isEmpty(); + boolean pressed = pressed(); + + if(arrows != pressed) + toggle(); + if(arrows && pressed) + TickScheduler.scheduleTick(this, delay()); + } + + @Override + public void onRemoved() + { + if(pressed()) + tile().notifyNeighborChange(metaSideMap[meta&7]); + } + + @Override + public int weakPowerLevel(int side) + { + return pressed() ? 15 : 0; + } + + @Override + public int strongPowerLevel(int side) + { + return pressed() && side == metaSideMap[meta&7] ? 15 : 0; + } + + @Override + public boolean canConnectRedstone(int side) + { + return true; + } +} diff --git a/codechicken/multipart/minecraft/Content.java b/codechicken/multipart/minecraft/Content.java index 0141a65..9634d36 100644 --- a/codechicken/multipart/minecraft/Content.java +++ b/codechicken/multipart/minecraft/Content.java @@ -15,6 +15,7 @@ public class Content implements IPartFactory, IPartConverter { if(name.equals("mc_torch")) return new TorchPart(); if(name.equals("mc_lever")) return new LeverPart(); + if(name.equals("mc_button")) return new ButtonPart(); return null; } @@ -24,7 +25,8 @@ public class Content implements IPartFactory, IPartConverter MultiPartRegistry.registerConverter(this); MultiPartRegistry.registerParts(this, new String[]{ "mc_torch", - "mc_lever" + "mc_lever", + "mc_button" }); } @@ -32,7 +34,9 @@ public class Content implements IPartFactory, IPartConverter public boolean canConvert(int blockID) { return blockID == Block.torchWood.blockID || - blockID == Block.lever.blockID; + blockID == Block.lever.blockID || + blockID == Block.stoneButton.blockID || + blockID == Block.woodenButton.blockID; } @Override @@ -44,6 +48,10 @@ public class Content implements IPartFactory, IPartConverter return new TorchPart(meta); if(id == Block.lever.blockID) return new LeverPart(meta); + if(id == Block.stoneButton.blockID) + return new ButtonPart(meta); + if(id == Block.woodenButton.blockID) + return new ButtonPart(meta|0x10); return null; } diff --git a/codechicken/multipart/minecraft/EventHandler.java b/codechicken/multipart/minecraft/EventHandler.java index d52ef3f..d18099c 100644 --- a/codechicken/multipart/minecraft/EventHandler.java +++ b/codechicken/multipart/minecraft/EventHandler.java @@ -40,6 +40,10 @@ public class EventHandler part = TorchPart.placement(world, pos, hit.sideHit); else if(held.itemID == Block.lever.blockID) part = LeverPart.placement(world, pos, player, hit.sideHit); + else if(held.itemID == Block.stoneButton.blockID) + part = ButtonPart.placement(world, pos, player, hit.sideHit, 0); + else if(held.itemID == Block.woodenButton.blockID) + part = ButtonPart.placement(world, pos, player, hit.sideHit, 1); if(part == null) return false; diff --git a/codechicken/multipart/minecraft/LeverPart.java b/codechicken/multipart/minecraft/LeverPart.java index 019e1fb..cc0ae50 100644 --- a/codechicken/multipart/minecraft/LeverPart.java +++ b/codechicken/multipart/minecraft/LeverPart.java @@ -9,10 +9,8 @@ import net.minecraft.util.MovingObjectPosition; import net.minecraft.world.IBlockAccess; import net.minecraft.world.World; import net.minecraftforge.common.ForgeDirection; -import codechicken.core.lighting.LazyLightMatrix; import codechicken.core.vec.BlockCoord; import codechicken.core.vec.Cuboid6; -import codechicken.core.vec.Vector3; import codechicken.multipart.IRedstonePart; public class LeverPart extends McSidedMetaPart implements IRedstonePart @@ -43,6 +41,11 @@ public class LeverPart extends McSidedMetaPart implements IRedstonePart return "mc_lever"; } + public boolean active() + { + return (meta&8) > 0; + } + @Override public Cuboid6 getBounds() { @@ -83,12 +86,6 @@ public class LeverPart extends McSidedMetaPart implements IRedstonePart return new LeverPart(meta); } - - @Override - public void renderStatic(Vector3 pos, LazyLightMatrix olm, int pass) - { - new RenderBlocks(new PartMetaAccess(this)).renderBlockLever(lever, getTile().xCoord, getTile().yCoord, getTile().zCoord); - } @Override public boolean activate(EntityPlayer player, MovingObjectPosition part, ItemStack item) @@ -97,8 +94,7 @@ public class LeverPart extends McSidedMetaPart implements IRedstonePart if(world.isRemote) return true; - int state = meta&8; - world.playSoundEffect(getTile().xCoord + 0.5, getTile().yCoord + 0.5, getTile().zCoord + 0.5, "random.click", 0.3F, state > 0 ? 0.6F : 0.5F); + world.playSoundEffect(getTile().xCoord + 0.5, getTile().yCoord + 0.5, getTile().zCoord + 0.5, "random.click", 0.3F, !active() ? 0.6F : 0.5F); meta = (byte) (meta^8); sendDescUpdate(); tile().notifyPartChange(); @@ -106,7 +102,8 @@ public class LeverPart extends McSidedMetaPart implements IRedstonePart tile().markDirty(); return true; } - + + @Override public void drawBreaking(RenderBlocks renderBlocks) { IBlockAccess actual = renderBlocks.blockAccess; @@ -114,17 +111,34 @@ public class LeverPart extends McSidedMetaPart implements IRedstonePart renderBlocks.renderBlockLever(lever, getTile().xCoord, getTile().yCoord, getTile().zCoord); renderBlocks.blockAccess = actual; } + + @Override + public void onRemoved() + { + if(active()) + tile().notifyNeighborChange(metaSideMap[meta&7]); + } + @Override + public void onConverted() + { + if(active()) + tile().notifyNeighborChange(metaSideMap[meta&7]); + } + + @Override public int weakPowerLevel(int side) { - return (meta & 8) > 0 ? 15 : 0; + return active() ? 15 : 0; } - + + @Override public int strongPowerLevel(int side) { - return (meta & 8) > 0 && side == metaSideMap[meta&7] ? 15 : 0; + return active() && side == metaSideMap[meta&7] ? 15 : 0; } - + + @Override public boolean canConnectRedstone(int side) { return true; diff --git a/codechicken/multipart/minecraft/McMetaPart.java b/codechicken/multipart/minecraft/McMetaPart.java index 4fb41b4..5382c54 100644 --- a/codechicken/multipart/minecraft/McMetaPart.java +++ b/codechicken/multipart/minecraft/McMetaPart.java @@ -2,7 +2,10 @@ package codechicken.multipart.minecraft; import codechicken.core.data.MCDataInput; import codechicken.core.data.MCDataOutput; +import codechicken.core.lighting.LazyLightMatrix; import codechicken.core.vec.BlockCoord; +import codechicken.core.vec.Vector3; +import net.minecraft.client.renderer.RenderBlocks; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.world.World; @@ -73,4 +76,16 @@ public abstract class McMetaPart extends McBlockPart implements IPartMeta { return new BlockCoord(getTile()); } + + @Override + public boolean doesTick() + { + return false; + } + + @Override + public void renderStatic(Vector3 pos, LazyLightMatrix olm, int pass) + { + new RenderBlocks(new PartMetaAccess(this)).renderBlockByRenderType(getBlock(), getTile().xCoord, getTile().yCoord, getTile().zCoord); + } } diff --git a/codechicken/multipart/minecraft/PartMetaAccess.java b/codechicken/multipart/minecraft/PartMetaAccess.java index 8b3fbeb..6d6521b 100644 --- a/codechicken/multipart/minecraft/PartMetaAccess.java +++ b/codechicken/multipart/minecraft/PartMetaAccess.java @@ -48,7 +48,7 @@ public class PartMetaAccess implements IBlockAccess public int getBlockMetadata(int i, int j, int k) { if(i == pos.x && j == pos.y && k == pos.z) - return part.getMetadata(); + return part.getMetadata()&0xF; return part.getWorld().getBlockMetadata(i, j, k); } diff --git a/codechicken/multipart/minecraft/TorchPart.java b/codechicken/multipart/minecraft/TorchPart.java index 35c2401..e4d9f21 100644 --- a/codechicken/multipart/minecraft/TorchPart.java +++ b/codechicken/multipart/minecraft/TorchPart.java @@ -4,14 +4,11 @@ import java.util.Random; import net.minecraft.block.Block; import net.minecraft.block.BlockTorch; -import net.minecraft.client.renderer.RenderBlocks; import net.minecraft.world.World; import net.minecraftforge.common.ForgeDirection; import codechicken.multipart.IRandomDisplayTick; -import codechicken.core.lighting.LazyLightMatrix; import codechicken.core.vec.BlockCoord; import codechicken.core.vec.Cuboid6; -import codechicken.core.vec.Vector3; public class TorchPart extends McSidedMetaPart implements IRandomDisplayTick { @@ -110,10 +107,4 @@ public class TorchPart extends McSidedMetaPart implements IRandomDisplayTick world.spawnParticle("flame", d0, d1, d2, 0, 0, 0); } } - - @Override - public void renderStatic(Vector3 pos, LazyLightMatrix olm, int pass) - { - new RenderBlocks(new PartMetaAccess(this)).renderBlockTorch(torch, getTile().xCoord, getTile().yCoord, getTile().zCoord); - } }