From 5032937cfbd54d2f4565c53b6b4c8cecc3807592 Mon Sep 17 00:00:00 2001 From: Chicken Bones Date: Tue, 4 Jun 2013 01:47:51 +1000 Subject: [PATCH] Redstone torch parts Improved tick scheduler, added random update ticks --- codechicken/multipart/IRandomUpdateTick.scala | 6 + codechicken/multipart/TMultiPart.scala | 3 +- codechicken/multipart/TickScheduler.scala | 65 ++++- codechicken/multipart/TileMultipart.scala | 1 + .../multipart/minecraft/ButtonPart.java | 2 +- codechicken/multipart/minecraft/Content.java | 12 +- .../multipart/minecraft/EventHandler.java | 6 +- .../multipart/minecraft/LeverPart.java | 2 +- .../multipart/minecraft/McSidedMetaPart.java | 16 +- .../minecraft/RedstoneTorchPart.java | 243 ++++++++++++++++++ .../multipart/minecraft/TorchPart.java | 5 + 11 files changed, 344 insertions(+), 17 deletions(-) create mode 100644 codechicken/multipart/IRandomUpdateTick.scala create mode 100644 codechicken/multipart/minecraft/RedstoneTorchPart.java diff --git a/codechicken/multipart/IRandomUpdateTick.scala b/codechicken/multipart/IRandomUpdateTick.scala new file mode 100644 index 0000000..5a28cd4 --- /dev/null +++ b/codechicken/multipart/IRandomUpdateTick.scala @@ -0,0 +1,6 @@ +package codechicken.multipart + +trait IRandomUpdateTick +{ + def randomUpdate() +} \ No newline at end of file diff --git a/codechicken/multipart/TMultiPart.scala b/codechicken/multipart/TMultiPart.scala index 13b679c..6257dc4 100644 --- a/codechicken/multipart/TMultiPart.scala +++ b/codechicken/multipart/TMultiPart.scala @@ -70,8 +70,9 @@ abstract class TMultiPart def onWorldJoin(world:World){onPartChanged()} def onPartChanged(){} def onNeighbourChanged(){} + def onAdded(){} def onRemoved(){} - def onConverted(){} + def onConverted() = onAdded() def doesTick = true def update(){} diff --git a/codechicken/multipart/TickScheduler.scala b/codechicken/multipart/TickScheduler.scala index 4f0c9c9..758f202 100644 --- a/codechicken/multipart/TickScheduler.scala +++ b/codechicken/multipart/TickScheduler.scala @@ -15,7 +15,10 @@ import scala.collection.mutable.HashSet object TickScheduler extends WorldExtensionInstantiator { - class PartTickEntry(val part:TMultiPart, var ticks:Int) + class PartTickEntry(val part:TMultiPart, var ticks:Int, var random:Boolean) + { + def this(part:TMultiPart, ticks:Int) = this(part, ticks, false) + } class WorldTickScheduler(world:World) extends WorldExtension(world) { @@ -40,17 +43,47 @@ object TickScheduler extends WorldExtensionInstantiator import codechicken.multipart.handler.MultipartProxy._ var tickList = ListBuffer[PartTickEntry]() + private var processing = false + private val pending = ListBuffer[PartTickEntry]() - def scheduleTick(part:TMultiPart, ticks:Int) + def scheduleTick(part:TMultiPart, ticks:Int):Unit = scheduleTick(part, ticks, false) + + def scheduleTick(part:TMultiPart, ticks:Int, random:Boolean) { - tickList+=new PartTickEntry(part, ticks) + if(processing) + { + pending+=new PartTickEntry(part, ticks, random) + return + } + + val it = tickList.iterator + while(it.hasNext) + { + val e = it.next + if(e.part == part) + { + if(ticks > e.ticks && random == e.random || e.random && !random) + { + e.ticks = ticks + e.random = random + } + return + } + } + tickList+=new PartTickEntry(part, ticks, random) if(tickList.size == 1) world.tickChunks+=this } + def nextRandomTick = world.world.rand.nextInt(800)+800 + def processTicks():Boolean = { + processing = true tickList = tickList.filter(processTick(_)) + processing = false + pending.foreach(e => scheduleTick(e.part, e.ticks, e.random)) + pending.clear() return !tickList.isEmpty } @@ -60,7 +93,19 @@ object TickScheduler extends WorldExtensionInstantiator if(e.ticks == 0) { if(e.part.tile != null) - e.part.scheduledTick() + { + if(e.random && e.part.isInstanceOf[IRandomUpdateTick]) + e.part.asInstanceOf[IRandomUpdateTick].randomUpdate() + else + e.part.scheduledTick() + + if(e.part.isInstanceOf[IRandomUpdateTick]) + { + e.ticks = nextRandomTick + e.random = true + return true + } + } return false } return true @@ -71,7 +116,7 @@ object TickScheduler extends WorldExtensionInstantiator val tagList = new NBTTagList tickList.foreach{e => val part = e.part - if(part.tile != null) + if(part.tile != null && !e.random) { val tag = new NBTTagCompound tag.setShort("pos", indexInChunk(new BlockCoord(part.tile)).toShort) @@ -104,6 +149,16 @@ object TickScheduler extends WorldExtensionInstantiator override def load() { + val it = chunk.chunkTileEntityMap.values.iterator + while(it.hasNext) + { + val t = it.next + if(t.isInstanceOf[TileMultipart]) + t.asInstanceOf[TileMultipart].partList.foreach(p => + if(p.isInstanceOf[IRandomUpdateTick]) + scheduleTick(p, nextRandomTick, true)) + } + if(!tickList.isEmpty) world.tickChunks+=this } diff --git a/codechicken/multipart/TileMultipart.scala b/codechicken/multipart/TileMultipart.scala index 22e1d07..ea4cfc6 100644 --- a/codechicken/multipart/TileMultipart.scala +++ b/codechicken/multipart/TileMultipart.scala @@ -155,6 +155,7 @@ trait TileMultipart extends TileEntity private[multipart] def addPart(part:TMultiPart) { addPart_do(part) + part.onAdded() notifyPartChange() markDirty() markRender() diff --git a/codechicken/multipart/minecraft/ButtonPart.java b/codechicken/multipart/minecraft/ButtonPart.java index bd174d8..d1aed91 100644 --- a/codechicken/multipart/minecraft/ButtonPart.java +++ b/codechicken/multipart/minecraft/ButtonPart.java @@ -82,7 +82,7 @@ public class ButtonPart extends McSidedMetaPart implements IRedstonePart return null;//falloff } - public static McBlockPart placement(World world, BlockCoord pos, EntityPlayer player, int side, int type) + public static McBlockPart placement(World world, BlockCoord pos, int side, int type) { if(side == 0 || side == 1) return null; diff --git a/codechicken/multipart/minecraft/Content.java b/codechicken/multipart/minecraft/Content.java index 9634d36..170fd91 100644 --- a/codechicken/multipart/minecraft/Content.java +++ b/codechicken/multipart/minecraft/Content.java @@ -16,6 +16,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(); + if(name.equals("mc_redtorch")) return new RedstoneTorchPart(); return null; } @@ -26,7 +27,8 @@ public class Content implements IPartFactory, IPartConverter MultiPartRegistry.registerParts(this, new String[]{ "mc_torch", "mc_lever", - "mc_button" + "mc_button", + "mc_redtorch" }); } @@ -36,7 +38,9 @@ public class Content implements IPartFactory, IPartConverter return blockID == Block.torchWood.blockID || blockID == Block.lever.blockID || blockID == Block.stoneButton.blockID || - blockID == Block.woodenButton.blockID; + blockID == Block.woodenButton.blockID || + blockID == Block.torchRedstoneIdle.blockID || + blockID == Block.torchRedstoneActive.blockID; } @Override @@ -52,6 +56,10 @@ public class Content implements IPartFactory, IPartConverter return new ButtonPart(meta); if(id == Block.woodenButton.blockID) return new ButtonPart(meta|0x10); + if(id == Block.torchRedstoneIdle.blockID) + return new RedstoneTorchPart(meta); + if(id == Block.torchRedstoneActive.blockID) + return new RedstoneTorchPart(meta|0x10); return null; } diff --git a/codechicken/multipart/minecraft/EventHandler.java b/codechicken/multipart/minecraft/EventHandler.java index d18099c..e55434b 100644 --- a/codechicken/multipart/minecraft/EventHandler.java +++ b/codechicken/multipart/minecraft/EventHandler.java @@ -41,9 +41,11 @@ public class EventHandler 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); + part = ButtonPart.placement(world, pos, hit.sideHit, 0); else if(held.itemID == Block.woodenButton.blockID) - part = ButtonPart.placement(world, pos, player, hit.sideHit, 1); + part = ButtonPart.placement(world, pos, hit.sideHit, 1); + else if(held.itemID == Block.torchRedstoneActive.blockID) + part = RedstoneTorchPart.placement(world, pos, hit.sideHit); if(part == null) return false; diff --git a/codechicken/multipart/minecraft/LeverPart.java b/codechicken/multipart/minecraft/LeverPart.java index cc0ae50..d0c1eb4 100644 --- a/codechicken/multipart/minecraft/LeverPart.java +++ b/codechicken/multipart/minecraft/LeverPart.java @@ -95,7 +95,7 @@ public class LeverPart extends McSidedMetaPart implements IRedstonePart return true; 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); + meta ^= 8; sendDescUpdate(); tile().notifyPartChange(); tile().notifyNeighborChange(metaSideMap[meta&7]); diff --git a/codechicken/multipart/minecraft/McSidedMetaPart.java b/codechicken/multipart/minecraft/McSidedMetaPart.java index ebf5392..eb23511 100644 --- a/codechicken/multipart/minecraft/McSidedMetaPart.java +++ b/codechicken/multipart/minecraft/McSidedMetaPart.java @@ -22,13 +22,19 @@ public abstract class McSidedMetaPart extends McMetaPart public void onNeighbourChanged() { - TileEntity tile = getTile(); - if(!tile.worldObj.isRemote) + if(!getTile().worldObj.isRemote) + dropIfCantStay(); + } + + public boolean dropIfCantStay() + { + BlockCoord pos = new BlockCoord(getTile()).offset(sideForMeta(meta)); + if(!getTile().worldObj.isBlockSolidOnSide(pos.x, pos.y, pos.z, ForgeDirection.getOrientation(sideForMeta(meta)^1))) { - BlockCoord pos = new BlockCoord(tile).offset(sideForMeta(meta)); - if(!tile.worldObj.isBlockSolidOnSide(pos.x, pos.y, pos.z, ForgeDirection.getOrientation(sideForMeta(meta)^1))) - drop(); + drop(); + return true; } + return false; } public void drop() diff --git a/codechicken/multipart/minecraft/RedstoneTorchPart.java b/codechicken/multipart/minecraft/RedstoneTorchPart.java new file mode 100644 index 0000000..e74c089 --- /dev/null +++ b/codechicken/multipart/minecraft/RedstoneTorchPart.java @@ -0,0 +1,243 @@ +package codechicken.multipart.minecraft; + +import java.util.Random; + +import net.minecraft.block.Block; +import net.minecraft.block.BlockRedstoneTorch; +import net.minecraft.item.ItemStack; +import net.minecraft.util.MovingObjectPosition; +import net.minecraft.world.World; +import net.minecraftforge.common.ForgeDirection; +import codechicken.core.vec.BlockCoord; +import codechicken.core.vec.Cuboid6; +import codechicken.core.vec.Vector3; +import codechicken.multipart.IRandomUpdateTick; +import codechicken.multipart.IRedstonePart; + +import static net.minecraft.util.Facing.*; + +public class RedstoneTorchPart extends TorchPart implements IRedstonePart, IRandomUpdateTick +{ + public static BlockRedstoneTorch torchActive = (BlockRedstoneTorch) Block.torchRedstoneActive; + public static BlockRedstoneTorch torchIdle = (BlockRedstoneTorch) Block.torchRedstoneIdle; + + public class BurnoutEntry + { + public BurnoutEntry(long l) + { + timeout = l; + } + + long timeout; + BurnoutEntry next; + } + + private BurnoutEntry burnout; + + public RedstoneTorchPart() + { + } + + public RedstoneTorchPart(int meta) + { + super(meta); + } + + @Override + public Block getBlock() + { + return active() ? torchActive : torchIdle; + } + + public boolean active() + { + return (meta&0x10) > 0; + } + + @Override + public String getType() + { + return "mc_redtorch"; + } + + @Override + public int sideForMeta(int meta) + { + return super.sideForMeta(meta&7); + } + + @Override + public Cuboid6 getBounds() + { + return getBounds(meta&7); + } + + public static McBlockPart placement(World world, BlockCoord pos, int side) + { + if(side == 0) + return null; + pos = pos.copy().offset(side^1); + if(!world.isBlockSolidOnSide(pos.x, pos.y, pos.z, ForgeDirection.getOrientation(side))) + return null; + + return new RedstoneTorchPart(sideMetaMap[side^1]|0x10); + } + + @Override + public void randomDisplayTick(Random random) + { + if(!active()) + return; + + double d0 = getTile().xCoord + 0.5 + (random.nextFloat() - 0.5) * 0.2; + double d1 = getTile().yCoord + 0.7 + (random.nextFloat() - 0.5) * 0.2; + double d2 = getTile().zCoord + 0.5 + (random.nextFloat() - 0.5) * 0.2; + double d3 = 0.22D; + double d4 = 0.27D; + + World world = getTile().worldObj; + int m = meta&7; + if (m == 1) + world.spawnParticle("reddust", d0 - d4, d1 + d3, d2, 0, 0, 0); + else if (m == 2) + world.spawnParticle("reddust", d0 + d4, d1 + d3, d2, 0, 0, 0); + else if (m == 3) + world.spawnParticle("reddust", d0, d1 + d3, d2 - d4, 0, 0, 0); + else if (m == 4) + world.spawnParticle("reddust", d0, d1 + d3, d2 + d4, 0, 0, 0); + else + world.spawnParticle("reddust", d0, d1, d2, 0, 0, 0); + } + + @Override + public ItemStack pickItem(MovingObjectPosition hit) + { + return new ItemStack(torchActive); + } + + @Override + public void onNeighbourChanged() + { + if(!getTile().worldObj.isRemote) + { + if(!dropIfCantStay() && isBeingPowered() == active()) + scheduleTick(2); + } + } + + public boolean isBeingPowered() + { + int side = metaSideMap[meta&7]; + return getTile().worldObj.getIndirectPowerOutput( + getTile().xCoord+offsetsXForSide[side], getTile().yCoord+offsetsYForSide[side], getTile().zCoord+offsetsZForSide[side], side); + } + + @Override + public void scheduledTick() + { + if(isBeingPowered() == active()) + toggle(); + } + + public void randomUpdate() + { + if(!active() && !isBeingPowered()) + scheduledTick(); + } + + private boolean burnedOut(boolean add) + { + long time = getTile().worldObj.getWorldTime(); + while(burnout != null && burnout.timeout <= time) + burnout = burnout.next; + + if(add) + { + BurnoutEntry e = new BurnoutEntry(getTile().worldObj.getWorldTime()+60); + if(burnout == null) + burnout = e; + else + { + BurnoutEntry b = burnout; + while(b.next != null) + b = b.next; + b.next = e; + } + } + + if(burnout == null) + return false; + + int i = 0; + BurnoutEntry b = burnout; + while(b != null) + { + i++; + b = b.next; + } + return i >= 8; + } + + private void toggle() + { + if(active())//deactivating + { + if(burnedOut(true)) + { + Vector3 pos = Vector3.fromTileEntityCenter(getTile()); + World world = getTile().worldObj; + Random rand = world.rand; + world.playSoundEffect(pos.x+0.5, pos.y+0.5, pos.z+0.5, "random.fizz", 0.5F, 2.6F + (rand.nextFloat() - rand.nextFloat()) * 0.8F); + + for (int l = 0; l < 5; ++l) + getTile().worldObj.spawnParticle("smoke", + pos.x + rand.nextDouble() * 0.6 + 0.2, + pos.y + rand.nextDouble() * 0.6 + 0.2, + pos.z + rand.nextDouble() * 0.6 + 0.2, 0, 0, 0); + } + } + else if(burnedOut(false)) + { + return; + } + + meta ^= 0x10; + sendDescUpdate(); + tile().markDirty(); + tile().notifyPartChange(); + tile().notifyNeighborChange(1); + } + + @Override + public void onRemoved() + { + if(active()) + tile().notifyNeighborChange(1); + } + + @Override + public void onAdded() + { + if(active()) + tile().notifyNeighborChange(1); + onNeighbourChanged(); + } + + @Override + public int strongPowerLevel(int side) + { + return side == 1 && active() ? 15 : 0; + } + + @Override + public int weakPowerLevel(int side) + { + return active() && side != metaSideMap[meta&7] ? 15 : 0; + } + + @Override + public boolean canConnectRedstone(int side) + { + return true; + } +} diff --git a/codechicken/multipart/minecraft/TorchPart.java b/codechicken/multipart/minecraft/TorchPart.java index e4d9f21..ba27292 100644 --- a/codechicken/multipart/minecraft/TorchPart.java +++ b/codechicken/multipart/minecraft/TorchPart.java @@ -39,6 +39,11 @@ public class TorchPart extends McSidedMetaPart implements IRandomDisplayTick @Override public Cuboid6 getBounds() + { + return getBounds(meta); + } + + public Cuboid6 getBounds(int meta) { double d = 0.15; if (meta == 1)