blob: 853ba18a7b94fe013ed958ed2a4405cc4d589857 [file] [log] [blame] [raw]
package codechicken.multipart.handler
import codechicken.lib.packet.PacketCustom.IClientPacketHandler
import codechicken.lib.packet.PacketCustom.IServerPacketHandler
import codechicken.lib.packet.PacketCustom
import net.minecraft.client.multiplayer.NetClientHandler
import net.minecraft.client.Minecraft
import codechicken.multipart.MultiPartRegistry
import net.minecraft.network.NetServerHandler
import net.minecraft.entity.player.EntityPlayerMP
import codechicken.multipart.ControlKeyModifer
import net.minecraft.network.packet.Packet255KickDisconnect
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
import scala.collection.mutable.{Map => MMap}
import codechicken.lib.vec.BlockCoord
import codechicken.lib.data.MCOutputStreamWrapper
import java.io.DataOutputStream
import java.io.ByteArrayOutputStream
import net.minecraft.world.WorldServer
import net.minecraft.world.ChunkCoordIntPair
import MultipartProxy._
import codechicken.multipart.PacketScheduler
class MultipartPH
{
val channel = MultipartMod
val registryChannel = "ForgeMultipart"//Must use the 250 system for ID registry as the NetworkMod idMap hasn't been properly initialized from the server yet.
}
object MultipartCPH extends MultipartPH with IClientPacketHandler
{
def handlePacket(packet:PacketCustom, netHandler:NetClientHandler, mc:Minecraft)
{
packet.getType match
{
case 1 => handlePartRegistration(packet, netHandler)
case 2 => handleCompressedTileDesc(packet, mc.theWorld)
case 3 => handleCompressedTileData(packet, mc.theWorld)
}
}
def handlePartRegistration(packet:PacketCustom, netHandler:NetClientHandler)
{
val missing = MultiPartRegistry.readIDMap(packet)
if(!missing.isEmpty)
netHandler.handleKickDisconnect(new Packet255KickDisconnect("The following multiparts are not installed on this client: "+missing.mkString(", ")))
}
def handleCompressedTileDesc(packet:PacketCustom, world:World)
{
val cc = new ChunkCoordIntPair(packet.readInt, packet.readInt)
val num = packet.readUShort
for(i <- 0 until num)
TileMultipart.handleDescPacket(world, indexInChunk(cc, packet.readShort), packet)
}
def handleCompressedTileData(packet:PacketCustom, world:World)
{
var x = packet.readInt
while(x != Int.MaxValue)
{
val pos = new BlockCoord(x, packet.readInt, packet.readInt)
var i = packet.readUByte
while(i < 255)
{
TileMultipart.handlePacket(pos, world, i, packet)
i = packet.readUByte
}
x = packet.readInt
}
TileMultipart.flushClientCache()
}
}
object MultipartSPH extends MultipartPH with IServerPacketHandler
{
class MCByteStream(bout:ByteArrayOutputStream) extends MCOutputStreamWrapper(new DataOutputStream(bout))
{
def getBytes = bout.toByteArray
}
private val updateMap = MMap[World, MMap[BlockCoord, MCByteStream]]()
def handlePacket(packet:PacketCustom, netHandler:NetServerHandler, sender:EntityPlayerMP)
{
packet.getType match
{
case 1 => ControlKeyModifer.map.put(sender, packet.readBoolean)
}
}
def onWorldUnload(world:World)
{
if(!world.isRemote)
updateMap.remove(world)
}
def getTileStream(world:World, pos:BlockCoord) =
updateMap.getOrElseUpdate(world, {
if(world.isRemote)
throw new IllegalArgumentException("Cannot use MultipartSPH on a client world")
MMap()
}).getOrElseUpdate(pos, {
val s = new MCByteStream(new ByteArrayOutputStream)
s.writeCoord(pos)
s
})
def onTickEnd(players:Seq[EntityPlayerMP])
{
PacketScheduler.sendScheduled()
players.foreach{p =>
val m = updateMap.getOrElse(p.worldObj, null)
if(m != null && !m.isEmpty)
{
val manager = p.worldObj.asInstanceOf[WorldServer].getPlayerManager
val packet = new PacketCustom(channel, 3).setChunkDataPacket().compressed()
var send = false
m.foreach(e =>
if(manager.isPlayerWatchingChunk(p, e._1.x>>4, e._1.z>>4))
{
send = true
packet.writeByteArray(e._2.getBytes)
packet.writeByte(255)//terminator
})
if(send)
{
packet.writeInt(Int.MaxValue)//terminator
packet.sendToPlayer(p)
}
}
}
updateMap.foreach(_._2.clear())
}
def onChunkWatch(player:EntityPlayer, chunk:Chunk)
{
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(it.hasNext)
{
val tile = it.next
if(tile.isInstanceOf[TileMultipart])
{
s.writeShort(indexInChunk(new BlockCoord(tile)))
tile.asInstanceOf[TileMultipart].writeDesc(s)
num+=1
}
}
if(num != 0)
{
return new PacketCustom(channel, 2).setChunkDataPacket().compressed()
.writeInt(chunk.xPosition).writeInt(chunk.zPosition)
.writeShort(num)
.writeByteArray(s.getBytes)
}
return null
}
}