| 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.Arrays |
| import net.minecraft.server.management.PlayerInstance |
| import codechicken.lib.asm.ObfMapping |
| |
| /** |
| * Static helper class for handling the unusual way that multipart tile entities load from nbt and send description packets |
| * <br> |
| * 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. |
| * <br> |
| * 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. |
| * <br> |
| * 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 |
| { |
| val f_playersInChunk = classOf[PlayerInstance].getDeclaredField( |
| new ObfMapping("net/minecraft/server/management/PlayerInstance", "playersInChunk", "Ljava/util/List;") |
| .toRuntime.s_name) |
| f_playersInChunk.setAccessible(true) |
| |
| def playersInChunk(inst:PlayerInstance) = f_playersInChunk.get(inst).asInstanceOf[List[_]] |
| |
| def createTileFromNBT(world:World, tag:NBTTagCompound):TileEntity = { |
| if(!tag.getString("id").equals("savedMultipart")) |
| return null |
| |
| MultipartSaveLoad.loadingWorld = world |
| return TileMultipart.createFromNBT(tag) |
| } |
| |
| /** |
| * Note. This method should only be used to send tiles that have been created on the server mid-game via an NBT load to clients. |
| */ |
| 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.filter(_.isInstanceOf[TileMultipart]).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(!playersInChunk(inst).isEmpty) |
| inst.sendToAllPlayersWatchingChunk(pkt.toPacket) |
| } |
| } |
| } |