diff --git a/codechicken/multipart/MultipartHelper.scala b/codechicken/multipart/MultipartHelper.scala
new file mode 100644
index 0000000..64e49c3
--- /dev/null
+++ b/codechicken/multipart/MultipartHelper.scala
@@ -0,0 +1,60 @@
+package codechicken.multipart
+
+import net.minecraft.tileentity.TileEntity
+import net.minecraft.nbt.NBTTagCompound
+import net.minecraft.world.World
+import codechicken.multipart.handler.MultipartSaveLoad
+import com.google.common.collect.LinkedListMultimap
+import scala.collection.JavaConversions._
+import codechicken.multipart.handler.MultipartSPH
+import net.minecraft.world.WorldServer
+import java.util.{List => JList}
+import net.minecraft.entity.player.EntityPlayer
+import net.minecraft.entity.player.EntityPlayerMP
+import java.util.Arrays
+
+/**
+ * Static helper class for handling the unusual way that multipart tile entities load from nbt and send description packets
+ *
+ * Multipart tile entities will all save themselves with the id "savedMultipart" which if normally loaded by minecraft,
+ * will create a dummy tile entity which just holds the NBT it was read from. These dummies are then converted to actual container tiles on the ChunkLoad event.
+ * The createTileFromNBT function should be used to construct a multipart tile from NBT without the ChunkLoad event.
+ *
+ * Multipart tile entities do not send description packets via the conventional means of one packet per tile when PlayerInstance calls for it, to do so would be terribly inefficient.
+ * Instead, the ChunkWatch event is used to batch all the describing data for a chunk into one packet which is compressed using relative positions.
+ * The sendDescPacket(s) functions should be used to send the description packet of a tile or tiles without a ChunkWatch event.
+ *
+ * An example of using this class to move blocks/tile entites around can be found at www.chickenbones.craftsaddle.org/Files/Other/ItemDevTool2.java
+ */
+object MultipartHelper
+{
+ def createTileFromNBT(world:World, tag:NBTTagCompound):TileEntity = {
+ if(!tag.getString("id").equals("savedMultipart"))
+ return null
+
+ MultipartSaveLoad.loadingWorld = world
+ return TileMultipart.createFromNBT(tag);
+ }
+
+ def sendDescPacket(world:World, tile:TileEntity) {
+ val c = world.getChunkFromBlockCoords(tile.xCoord, tile.zCoord)
+ val pkt = MultipartSPH.getDescPacket(c, Arrays.asList(tile).iterator)
+ if(pkt != null)
+ pkt.sendToChunk(world, c.xPosition, c.zPosition)
+ }
+
+ def sendDescPackets(world:World, tiles:Iterable[TileEntity]) {
+ val map = LinkedListMultimap.create[Long, TileEntity]()
+ tiles.foreach(t => map.put(t.xCoord.toLong<<32|t.zCoord, t))
+
+ val mgr = world.asInstanceOf[WorldServer].getPlayerManager
+ map.asMap.entrySet.foreach{e =>
+ val coord = e.getKey
+ val c = world.getChunkFromBlockCoords((coord>>32).toInt, coord.toInt)
+ lazy val pkt = MultipartSPH.getDescPacket(c, e.getValue.iterator)
+ val inst = mgr.getOrCreateChunkWatcher(c.xPosition, c.zPosition, false)
+ if(!inst.playersInChunk.isEmpty)
+ inst.sendToAllPlayersWatchingChunk(pkt.toPacket)
+ }
+ }
+}
\ No newline at end of file
diff --git a/codechicken/multipart/handler/PacketHandlers.scala b/codechicken/multipart/handler/PacketHandlers.scala
index 32a172a..fa93558 100644
--- a/codechicken/multipart/handler/PacketHandlers.scala
+++ b/codechicken/multipart/handler/PacketHandlers.scala
@@ -16,6 +16,7 @@ import net.minecraft.server.MinecraftServer
import net.minecraft.world.World
import net.minecraft.world.chunk.Chunk
import java.util.Map
+import java.util.Iterator
import net.minecraft.tileentity.TileEntity
import codechicken.multipart.TileMultipart
import net.minecraft.entity.player.EntityPlayer
@@ -140,13 +141,19 @@ object MultipartSPH extends MultipartPH with IServerPacketHandler
def onChunkWatch(player:EntityPlayer, chunk:Chunk)
{
- val iterator = chunk.chunkTileEntityMap.asInstanceOf[Map[_, TileEntity]].values.iterator
+ val pkt = getDescPacket(chunk, chunk.chunkTileEntityMap.asInstanceOf[Map[_, TileEntity]].values.iterator)
+ if(pkt != null)
+ pkt.sendToPlayer(player)
+ }
+
+ def getDescPacket(chunk:Chunk, it:Iterator[TileEntity]):PacketCustom =
+ {
val s = new MCByteStream(new ByteArrayOutputStream)
var num = 0
- while(iterator.hasNext)
+ while(it.hasNext)
{
- val tile = iterator.next
+ val tile = it.next
if(tile.isInstanceOf[TileMultipart])
{
s.writeShort(indexInChunk(new BlockCoord(tile)))
@@ -156,11 +163,11 @@ object MultipartSPH extends MultipartPH with IServerPacketHandler
}
if(num != 0)
{
- new PacketCustom(channel, 2).setChunkDataPacket().compressed()
+ return new PacketCustom(channel, 2).setChunkDataPacket().compressed()
.writeInt(chunk.xPosition).writeInt(chunk.zPosition)
.writeShort(num)
.writeByteArray(s.getBytes)
- .sendToPlayer(player)
}
+ return null;
}
}