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; } }