{-# LANGUAGE OverloadedStrings #-}
{-# OPTIONS_GHC -fno-warn-name-shadowing #-}
{-# OPTIONS_GHC -fno-warn-unused-binds #-}
{-# OPTIONS_GHC -fno-warn-unused-matches #-}
---------------------------------------------------------------
-- |
-- Module        : Data.Minecraft.Snapshot16w20a.Protocol
-- Copyright     : (c) 2016 Michael Carpenter
-- License       : BSD3
-- Maintainer    : Michael Carpenter <oldmanmike.dev@gmail.com>
-- Stability     : experimental
-- Portability   : portable
--
---------------------------------------------------------------
module Data.Minecraft.Snapshot16w20a.Protocol
  ( ServerBoundHandshakingPacket (..)
  , ClientBoundStatusPacket (..)
  , ServerBoundStatusPacket (..)
  , ClientBoundLoginPacket (..)
  , ServerBoundLoginPacket (..)
  , ClientBoundPlayPacket (..)
  , ServerBoundPlayPacket (..)
  ) where


import Data.Attoparsec.ByteString
import Data.ByteString as B
import Data.ByteString.Builder as BB
import Data.Int
import Data.Fixed
import Data.Minecraft.Types
import Data.NBT
import Data.Serialize hiding (putByteString,getByteString)
import Data.Text as T
import Data.UUID
import Data.Word


data ServerBoundHandshakingPacket
  = ServerBoundSetProtocol VarInt Text Word16 VarInt
  | ServerBoundLegacyServerListPing Word8
  deriving (Show,Eq)


data ClientBoundStatusPacket
  = ClientBoundServerInfo Text
  | ClientBoundPing Int64
  deriving (Show,Eq)


data ServerBoundStatusPacket
  = ServerBoundPingStart
  | ServerBoundPing Int64
  deriving (Show,Eq)


data ClientBoundLoginPacket
  = ClientBoundDisconnect Text
  | ClientBoundEncryptionBegin Text Buffer Buffer
  | ClientBoundSuccess Text Text
  | ClientBoundCompress VarInt
  deriving (Show,Eq)


data ServerBoundLoginPacket
  = ServerBoundLoginStart Text
  | ServerBoundEncryptionBegin Buffer Buffer
  deriving (Show,Eq)


data ClientBoundPlayPacket
  = ClientBoundSpawnEntity VarInt UUID Int8 Double Double Double Int8 Int8 Int32 Int16 Int16 Int16
  | ClientBoundSpawnEntityExperienceOrb VarInt Double Double Double Int16
  | ClientBoundSpawnEntityWeather VarInt Int8 Double Double Double
  | ClientBoundSpawnEntityLiving VarInt UUID Word8 Double Double Double Int8 Int8 Int8 Int16 Int16 Int16 EntityMetadata
  | ClientBoundSpawnEntityPainting VarInt UUID Text Position Word8
  | ClientBoundNamedEntitySpawn VarInt UUID Double Double Double Int8 Int8 EntityMetadata
  | ClientBoundAnimation VarInt Word8
  | ClientBoundStatistics Array
  | ClientBoundBlockBreakAnimation VarInt Position Int8
  | ClientBoundTileEntityData Position Word8 (Maybe NBT)
  | ClientBoundBlockAction Position Word8 Word8 VarInt
  | ClientBoundBlockChange Position VarInt
  | ClientBoundBossBar UUID VarInt (Maybe Text) (Maybe Float) (Maybe VarInt) (Maybe VarInt) (Maybe Word8)
  | ClientBoundDifficulty Word8
  | ClientBoundTabComplete Array
  | ClientBoundChat Text Int8
  | ClientBoundMultiBlockChange Int32 Int32 Array
  | ClientBoundTransaction Int8 Int16 Bool
  | ClientBoundCloseWindow Word8
  | ClientBoundOpenWindow Word8 Text Text Word8 (Maybe Int32)
  | ClientBoundWindowItems Word8 Array
  | ClientBoundCraftProgressBar Word8 Int16 Int16
  | ClientBoundSetSlot Int8 Int16 Slot
  | ClientBoundSetCooldown VarInt VarInt
  | ClientBoundCustomPayload Text RestBuffer
  | ClientBoundNamedSoundEffect Text VarInt Int32 Int32 Int32 Float Float
  | ClientBoundKickDisconnect Text
  | ClientBoundEntityStatus Int32 Int8
  | ClientBoundExplosion Float Float Float Float Array Float Float Float
  | ClientBoundUnloadChunk Int32 Int32
  | ClientBoundGameStateChange Word8 Float
  | ClientBoundKeepAlive VarInt
  | ClientBoundMapChunk Int32 Int32 Bool VarInt Buffer Array
  | ClientBoundWorldEvent Int32 Position Int32 Bool
  | ClientBoundWorldParticles Int32 Bool Float Float Float Float Float Float Float Int32 (Maybe Array)
  | ClientBoundLogin Int32 Word8 Int32 Word8 Word8 Text Bool
  | ClientBoundMap VarInt Int8 Bool Array Int8 (Maybe Int8) (Maybe Int8) (Maybe Int8) (Maybe Buffer)
  | ClientBoundRelEntityMove VarInt Int16 Int16 Int16 Bool
  | ClientBoundEntityMoveLook VarInt Int16 Int16 Int16 Int8 Int8 Bool
  | ClientBoundEntityLook VarInt Int8 Int8 Bool
  | ClientBoundEntity VarInt
  | ClientBoundVehicleMove Double Double Double Float Float
  | ClientBoundOpenSignEntity Position
  | ClientBoundAbilities Int8 Float Float
  | ClientBoundCombatEvent VarInt (Maybe VarInt) (Maybe VarInt) (Maybe Int32) (Maybe Text)
  | ClientBoundPlayerInfo VarInt Array
  | ClientBoundPosition Double Double Double Float Float Int8 VarInt
  | ClientBoundBed VarInt Position
  | ClientBoundEntityDestroy Array
  | ClientBoundRemoveEntityEffect VarInt Int8
  | ClientBoundResourcePackSend Text Text
  | ClientBoundRespawn Int32 Word8 Word8 Text
  | ClientBoundEntityHeadRotation VarInt Int8
  | ClientBoundWorldBorder VarInt (Maybe Double) (Maybe Double) (Maybe Double) (Maybe Double) (Maybe Double) (Maybe VarInt) (Maybe VarInt) (Maybe VarInt) (Maybe VarInt)
  | ClientBoundCamera VarInt
  | ClientBoundHeldItemSlot Int8
  | ClientBoundScoreboardDisplayObjective Int8 Text
  | ClientBoundEntityMetadata VarInt EntityMetadata
  | ClientBoundAttachEntity Int32 Int32
  | ClientBoundEntityVelocity VarInt Int16 Int16 Int16
  | ClientBoundEntityEquipment VarInt VarInt Slot
  | ClientBoundExperience Float VarInt VarInt
  | ClientBoundUpdateHealth Float VarInt Float
  | ClientBoundScoreboardObjective Text Int8 (Maybe Text) (Maybe Text)
  | ClientBoundSetPassengers VarInt Array
  | ClientBoundTeams Text Int8 (Maybe Text) (Maybe Text) (Maybe Text) (Maybe Int8) (Maybe Text) (Maybe Text) (Maybe Int8) (Maybe Array)
  | ClientBoundScoreboardScore Text Int8 Text (Maybe VarInt)
  | ClientBoundSpawnPosition Position
  | ClientBoundUpdateTime Int64 Int64
  | ClientBoundTitle VarInt (Maybe Text) (Maybe Int32) (Maybe Int32) (Maybe Int32)
  | ClientBoundSoundEffect VarInt VarInt Int32 Int32 Int32 Float Float
  | ClientBoundPlayerlistHeader Text Text
  | ClientBoundCollect VarInt VarInt
  | ClientBoundEntityTeleport VarInt Double Double Double Int8 Int8 Bool
  | ClientBoundEntityUpdateAttributes VarInt Array
  | ClientBoundEntityEffect VarInt Int8 Int8 VarInt Int8
  deriving (Show,Eq)


data ServerBoundPlayPacket
  = ServerBoundTeleportConfirm VarInt
  | ServerBoundTabComplete Text Bool (Maybe Position)
  | ServerBoundChat Text
  | ServerBoundClientCommand VarInt
  | ServerBoundSettings Text Int8 VarInt Bool Word8 VarInt
  | ServerBoundTransaction Int8 Int16 Bool
  | ServerBoundEnchantItem Int8 Int8
  | ServerBoundWindowClick Word8 Int16 Int8 Int16 Int8 Slot
  | ServerBoundCloseWindow Word8
  | ServerBoundCustomPayload Text RestBuffer
  | ServerBoundUseEntity VarInt VarInt (Maybe Float) (Maybe Float) (Maybe Float) (Maybe VarInt)
  | ServerBoundKeepAlive VarInt
  | ServerBoundPosition Double Double Double Bool
  | ServerBoundPositionLook Double Double Double Float Float Bool
  | ServerBoundLook Float Float Bool
  | ServerBoundFlying Bool
  | ServerBoundVehicleMove Double Double Double Float Float
  | ServerBoundSteerBoat Bool Bool
  | ServerBoundAbilities Int8 Float Float
  | ServerBoundBlockDig Int8 Position Int8
  | ServerBoundEntityAction VarInt VarInt VarInt
  | ServerBoundSteerVehicle Float Float Word8
  | ServerBoundResourcePackReceive Text VarInt
  | ServerBoundHeldItemSlot Int16
  | ServerBoundSetCreativeSlot Int16 Slot
  | ServerBoundUpdateSign Position Text Text Text Text
  | ServerBoundArmAnimation VarInt
  | ServerBoundSpectate UUID
  | ServerBoundBlockPlace Position VarInt VarInt Int8 Int8 Int8
  | ServerBoundUseItem VarInt
  deriving (Show,Eq)


instance Serialize ServerBoundHandshakingPacket where
  put (ServerBoundSetProtocol protocolVersion serverHost serverPort nextState) = do
    putWord8 0x00
    putVarInt protocolVersion
    putText serverHost
    putWord16 serverPort
    putVarInt nextState
  put (ServerBoundLegacyServerListPing payload) = do
    putWord8 0xfe
    putWord8 payload


  get = do
    packetId <- getWord8
    case packetId of
      0x00 -> do
        protocolVersion <- getVarInt
        serverHost <- getText
        serverPort <- getWord16
        nextState <- getVarInt
        return $ ServerBoundSetProtocol protocolVersion serverHost serverPort nextState
      0xfe -> do
        payload <- getWord8
        return $ ServerBoundLegacyServerListPing payload


instance Serialize ClientBoundStatusPacket where
  put (ClientBoundServerInfo response) = do
    putWord8 0x00
    putText response
  put (ClientBoundPing time) = do
    putWord8 0x01
    putInt64 time


  get = do
    packetId <- getWord8
    case packetId of
      0x00 -> do
        response <- getText
        return $ ClientBoundServerInfo response
      0x01 -> do
        time <- getInt64
        return $ ClientBoundPing time


instance Serialize ServerBoundStatusPacket where
  put (ServerBoundPingStart ) = do
    putWord8 0x00
  put (ServerBoundPing time) = do
    putWord8 0x01
    putInt64 time


  get = do
    packetId <- getWord8
    case packetId of
      0x00 -> do
        return $ ServerBoundPingStart
      0x01 -> do
        time <- getInt64
        return $ ServerBoundPing time


instance Serialize ClientBoundLoginPacket where
  put (ClientBoundDisconnect reason) = do
    putWord8 0x00
    putText reason
  put (ClientBoundEncryptionBegin serverId publicKey verifyToken) = do
    putWord8 0x01
    putText serverId
    putBuffer publicKey
    putBuffer verifyToken
  put (ClientBoundSuccess uuid username) = do
    putWord8 0x02
    putText uuid
    putText username
  put (ClientBoundCompress threshold) = do
    putWord8 0x03
    putVarInt threshold


  get = do
    packetId <- getWord8
    case packetId of
      0x00 -> do
        reason <- getText
        return $ ClientBoundDisconnect reason
      0x01 -> do
        serverId <- getText
        publicKey <- getBuffer
        verifyToken <- getBuffer
        return $ ClientBoundEncryptionBegin serverId publicKey verifyToken
      0x02 -> do
        uuid <- getText
        username <- getText
        return $ ClientBoundSuccess uuid username
      0x03 -> do
        threshold <- getVarInt
        return $ ClientBoundCompress threshold


instance Serialize ServerBoundLoginPacket where
  put (ServerBoundLoginStart username) = do
    putWord8 0x00
    putText username
  put (ServerBoundEncryptionBegin sharedSecret verifyToken) = do
    putWord8 0x01
    putBuffer sharedSecret
    putBuffer verifyToken


  get = do
    packetId <- getWord8
    case packetId of
      0x00 -> do
        username <- getText
        return $ ServerBoundLoginStart username
      0x01 -> do
        sharedSecret <- getBuffer
        verifyToken <- getBuffer
        return $ ServerBoundEncryptionBegin sharedSecret verifyToken


instance Serialize ClientBoundPlayPacket where
  put (ClientBoundSpawnEntity entityId objectUUID pType x y z pitch yaw intField velocityX velocityY velocityZ) = do
    putWord8 0x00
    putVarInt entityId
    putUUID objectUUID
    putInt8 pType
    putDouble x
    putDouble y
    putDouble z
    putInt8 pitch
    putInt8 yaw
    putInt32 intField
    putInt16 velocityX
    putInt16 velocityY
    putInt16 velocityZ
  put (ClientBoundSpawnEntityExperienceOrb entityId x y z count) = do
    putWord8 0x01
    putVarInt entityId
    putDouble x
    putDouble y
    putDouble z
    putInt16 count
  put (ClientBoundSpawnEntityWeather entityId pType x y z) = do
    putWord8 0x02
    putVarInt entityId
    putInt8 pType
    putDouble x
    putDouble y
    putDouble z
  put (ClientBoundSpawnEntityLiving entityId entityUUID pType x y z yaw pitch headPitch velocityX velocityY velocityZ metadata) = do
    putWord8 0x03
    putVarInt entityId
    putUUID entityUUID
    putWord8 pType
    putDouble x
    putDouble y
    putDouble z
    putInt8 yaw
    putInt8 pitch
    putInt8 headPitch
    putInt16 velocityX
    putInt16 velocityY
    putInt16 velocityZ
    putEntityMetadata metadata
  put (ClientBoundSpawnEntityPainting entityId entityUUID title location direction) = do
    putWord8 0x04
    putVarInt entityId
    putUUID entityUUID
    putText title
    putPosition location
    putWord8 direction
  put (ClientBoundNamedEntitySpawn entityId playerUUID x y z yaw pitch metadata) = do
    putWord8 0x05
    putVarInt entityId
    putUUID playerUUID
    putDouble x
    putDouble y
    putDouble z
    putInt8 yaw
    putInt8 pitch
    putEntityMetadata metadata
  put (ClientBoundAnimation entityId animation) = do
    putWord8 0x06
    putVarInt entityId
    putWord8 animation
  put (ClientBoundStatistics entries) = do
    putWord8 0x07
    putArray entries
  put (ClientBoundBlockBreakAnimation entityId location destroyStage) = do
    putWord8 0x08
    putVarInt entityId
    putPosition location
    putInt8 destroyStage
  put (ClientBoundTileEntityData location action nbtData) = do
    putWord8 0x09
    putPosition location
    putWord8 action
    case nbtData of
      Just nbtData' -> putNBT nbtData'
      Nothing -> return ()
  put (ClientBoundBlockAction location byte1 byte2 blockId) = do
    putWord8 0x0a
    putPosition location
    putWord8 byte1
    putWord8 byte2
    putVarInt blockId
  put (ClientBoundBlockChange location pType) = do
    putWord8 0x0b
    putPosition location
    putVarInt pType
  put (ClientBoundBossBar entityUUID action title health color dividers flags) = do
    putWord8 0x0c
    putUUID entityUUID
    putVarInt action
    case title of
      Just title' -> putText title'
      Nothing -> return ()
    case health of
      Just health' -> putFloat health'
      Nothing -> return ()
    case color of
      Just color' -> putVarInt color'
      Nothing -> return ()
    case dividers of
      Just dividers' -> putVarInt dividers'
      Nothing -> return ()
    case flags of
      Just flags' -> putWord8 flags'
      Nothing -> return ()
  put (ClientBoundDifficulty difficulty) = do
    putWord8 0x0d
    putWord8 difficulty
  put (ClientBoundTabComplete matches) = do
    putWord8 0x0e
    putArray matches
  put (ClientBoundChat message position) = do
    putWord8 0x0f
    putText message
    putInt8 position
  put (ClientBoundMultiBlockChange chunkX chunkZ records) = do
    putWord8 0x10
    putInt32 chunkX
    putInt32 chunkZ
    putArray records
  put (ClientBoundTransaction windowId action accepted) = do
    putWord8 0x11
    putInt8 windowId
    putInt16 action
    putBool accepted
  put (ClientBoundCloseWindow windowId) = do
    putWord8 0x12
    putWord8 windowId
  put (ClientBoundOpenWindow windowId inventoryType windowTitle slotCount entityId) = do
    putWord8 0x13
    putWord8 windowId
    putText inventoryType
    putText windowTitle
    putWord8 slotCount
    case entityId of
      Just entityId' -> putInt32 entityId'
      Nothing -> return ()
  put (ClientBoundWindowItems windowId items) = do
    putWord8 0x14
    putWord8 windowId
    putArray items
  put (ClientBoundCraftProgressBar windowId property value) = do
    putWord8 0x15
    putWord8 windowId
    putInt16 property
    putInt16 value
  put (ClientBoundSetSlot windowId slot item) = do
    putWord8 0x16
    putInt8 windowId
    putInt16 slot
    putSlot item
  put (ClientBoundSetCooldown itemID cooldownTicks) = do
    putWord8 0x17
    putVarInt itemID
    putVarInt cooldownTicks
  put (ClientBoundCustomPayload channel pData) = do
    putWord8 0x18
    putText channel
    putRestBuffer pData
  put (ClientBoundNamedSoundEffect soundName soundCategory x y z volume pitch) = do
    putWord8 0x19
    putText soundName
    putVarInt soundCategory
    putInt32 x
    putInt32 y
    putInt32 z
    putFloat volume
    putFloat pitch
  put (ClientBoundKickDisconnect reason) = do
    putWord8 0x1a
    putText reason
  put (ClientBoundEntityStatus entityId entityStatus) = do
    putWord8 0x1b
    putInt32 entityId
    putInt8 entityStatus
  put (ClientBoundExplosion x y z radius affectedBlockOffsets playerMotionX playerMotionY playerMotionZ) = do
    putWord8 0x1c
    putFloat x
    putFloat y
    putFloat z
    putFloat radius
    putArray affectedBlockOffsets
    putFloat playerMotionX
    putFloat playerMotionY
    putFloat playerMotionZ
  put (ClientBoundUnloadChunk chunkX chunkZ) = do
    putWord8 0x1d
    putInt32 chunkX
    putInt32 chunkZ
  put (ClientBoundGameStateChange reason gameMode) = do
    putWord8 0x1e
    putWord8 reason
    putFloat gameMode
  put (ClientBoundKeepAlive keepAliveId) = do
    putWord8 0x1f
    putVarInt keepAliveId
  put (ClientBoundMapChunk x z groundUp bitMap chunkData blockEntities) = do
    putWord8 0x20
    putInt32 x
    putInt32 z
    putBool groundUp
    putVarInt bitMap
    putBuffer chunkData
    putArray blockEntities
  put (ClientBoundWorldEvent effectId location pData global) = do
    putWord8 0x21
    putInt32 effectId
    putPosition location
    putInt32 pData
    putBool global
  put (ClientBoundWorldParticles particleId longDistance x y z offsetX offsetY offsetZ particleData particles pData) = do
    putWord8 0x22
    putInt32 particleId
    putBool longDistance
    putFloat x
    putFloat y
    putFloat z
    putFloat offsetX
    putFloat offsetY
    putFloat offsetZ
    putFloat particleData
    putInt32 particles
    case pData of
      Just pData' -> putArray pData'
      Nothing -> return ()
  put (ClientBoundLogin entityId gameMode dimension difficulty maxPlayers levelType reducedDebugInfo) = do
    putWord8 0x23
    putInt32 entityId
    putWord8 gameMode
    putInt32 dimension
    putWord8 difficulty
    putWord8 maxPlayers
    putText levelType
    putBool reducedDebugInfo
  put (ClientBoundMap itemDamage scale trackingPosition icons columns rows x y pData) = do
    putWord8 0x24
    putVarInt itemDamage
    putInt8 scale
    putBool trackingPosition
    putArray icons
    putInt8 columns
    case rows of
      Just rows' -> putInt8 rows'
      Nothing -> return ()
    case x of
      Just x' -> putInt8 x'
      Nothing -> return ()
    case y of
      Just y' -> putInt8 y'
      Nothing -> return ()
    case pData of
      Just pData' -> putBuffer pData'
      Nothing -> return ()
  put (ClientBoundRelEntityMove entityId dX dY dZ onGround) = do
    putWord8 0x25
    putVarInt entityId
    putInt16 dX
    putInt16 dY
    putInt16 dZ
    putBool onGround
  put (ClientBoundEntityMoveLook entityId dX dY dZ yaw pitch onGround) = do
    putWord8 0x26
    putVarInt entityId
    putInt16 dX
    putInt16 dY
    putInt16 dZ
    putInt8 yaw
    putInt8 pitch
    putBool onGround
  put (ClientBoundEntityLook entityId yaw pitch onGround) = do
    putWord8 0x27
    putVarInt entityId
    putInt8 yaw
    putInt8 pitch
    putBool onGround
  put (ClientBoundEntity entityId) = do
    putWord8 0x28
    putVarInt entityId
  put (ClientBoundVehicleMove x y z yaw pitch) = do
    putWord8 0x29
    putDouble x
    putDouble y
    putDouble z
    putFloat yaw
    putFloat pitch
  put (ClientBoundOpenSignEntity location) = do
    putWord8 0x2a
    putPosition location
  put (ClientBoundAbilities flags flyingSpeed walkingSpeed) = do
    putWord8 0x2b
    putInt8 flags
    putFloat flyingSpeed
    putFloat walkingSpeed
  put (ClientBoundCombatEvent event duration playerId entityId message) = do
    putWord8 0x2c
    putVarInt event
    case duration of
      Just duration' -> putVarInt duration'
      Nothing -> return ()
    case playerId of
      Just playerId' -> putVarInt playerId'
      Nothing -> return ()
    case entityId of
      Just entityId' -> putInt32 entityId'
      Nothing -> return ()
    case message of
      Just message' -> putText message'
      Nothing -> return ()
  put (ClientBoundPlayerInfo action pData) = do
    putWord8 0x2d
    putVarInt action
    putArray pData
  put (ClientBoundPosition x y z yaw pitch flags teleportId) = do
    putWord8 0x2e
    putDouble x
    putDouble y
    putDouble z
    putFloat yaw
    putFloat pitch
    putInt8 flags
    putVarInt teleportId
  put (ClientBoundBed entityId location) = do
    putWord8 0x2f
    putVarInt entityId
    putPosition location
  put (ClientBoundEntityDestroy entityIds) = do
    putWord8 0x30
    putArray entityIds
  put (ClientBoundRemoveEntityEffect entityId effectId) = do
    putWord8 0x31
    putVarInt entityId
    putInt8 effectId
  put (ClientBoundResourcePackSend url hash) = do
    putWord8 0x32
    putText url
    putText hash
  put (ClientBoundRespawn dimension difficulty gamemode levelType) = do
    putWord8 0x33
    putInt32 dimension
    putWord8 difficulty
    putWord8 gamemode
    putText levelType
  put (ClientBoundEntityHeadRotation entityId headYaw) = do
    putWord8 0x34
    putVarInt entityId
    putInt8 headYaw
  put (ClientBoundWorldBorder action radius x z oldRadius newRadius speed portalBoundary warningTime warningBlocks) = do
    putWord8 0x35
    putVarInt action
    case radius of
      Just radius' -> putDouble radius'
      Nothing -> return ()
    case x of
      Just x' -> putDouble x'
      Nothing -> return ()
    case z of
      Just z' -> putDouble z'
      Nothing -> return ()
    case oldRadius of
      Just oldRadius' -> putDouble oldRadius'
      Nothing -> return ()
    case newRadius of
      Just newRadius' -> putDouble newRadius'
      Nothing -> return ()
    case speed of
      Just speed' -> putVarInt speed'
      Nothing -> return ()
    case portalBoundary of
      Just portalBoundary' -> putVarInt portalBoundary'
      Nothing -> return ()
    case warningTime of
      Just warningTime' -> putVarInt warningTime'
      Nothing -> return ()
    case warningBlocks of
      Just warningBlocks' -> putVarInt warningBlocks'
      Nothing -> return ()
  put (ClientBoundCamera cameraId) = do
    putWord8 0x36
    putVarInt cameraId
  put (ClientBoundHeldItemSlot slot) = do
    putWord8 0x37
    putInt8 slot
  put (ClientBoundScoreboardDisplayObjective position name) = do
    putWord8 0x38
    putInt8 position
    putText name
  put (ClientBoundEntityMetadata entityId metadata) = do
    putWord8 0x39
    putVarInt entityId
    putEntityMetadata metadata
  put (ClientBoundAttachEntity entityId vehicleId) = do
    putWord8 0x3a
    putInt32 entityId
    putInt32 vehicleId
  put (ClientBoundEntityVelocity entityId velocityX velocityY velocityZ) = do
    putWord8 0x3b
    putVarInt entityId
    putInt16 velocityX
    putInt16 velocityY
    putInt16 velocityZ
  put (ClientBoundEntityEquipment entityId slot item) = do
    putWord8 0x3c
    putVarInt entityId
    putVarInt slot
    putSlot item
  put (ClientBoundExperience experienceBar level totalExperience) = do
    putWord8 0x3d
    putFloat experienceBar
    putVarInt level
    putVarInt totalExperience
  put (ClientBoundUpdateHealth health food foodSaturation) = do
    putWord8 0x3e
    putFloat health
    putVarInt food
    putFloat foodSaturation
  put (ClientBoundScoreboardObjective name action displayText pType) = do
    putWord8 0x3f
    putText name
    putInt8 action
    case displayText of
      Just displayText' -> putText displayText'
      Nothing -> return ()
    case pType of
      Just pType' -> putText pType'
      Nothing -> return ()
  put (ClientBoundSetPassengers entityId passengers) = do
    putWord8 0x40
    putVarInt entityId
    putArray passengers
  put (ClientBoundTeams team mode name prefix suffix friendlyFire nameTagVisibility collisionRule color players) = do
    putWord8 0x41
    putText team
    putInt8 mode
    case name of
      Just name' -> putText name'
      Nothing -> return ()
    case prefix of
      Just prefix' -> putText prefix'
      Nothing -> return ()
    case suffix of
      Just suffix' -> putText suffix'
      Nothing -> return ()
    case friendlyFire of
      Just friendlyFire' -> putInt8 friendlyFire'
      Nothing -> return ()
    case nameTagVisibility of
      Just nameTagVisibility' -> putText nameTagVisibility'
      Nothing -> return ()
    case collisionRule of
      Just collisionRule' -> putText collisionRule'
      Nothing -> return ()
    case color of
      Just color' -> putInt8 color'
      Nothing -> return ()
    case players of
      Just players' -> putArray players'
      Nothing -> return ()
  put (ClientBoundScoreboardScore itemName action scoreName value) = do
    putWord8 0x42
    putText itemName
    putInt8 action
    putText scoreName
    case value of
      Just value' -> putVarInt value'
      Nothing -> return ()
  put (ClientBoundSpawnPosition location) = do
    putWord8 0x43
    putPosition location
  put (ClientBoundUpdateTime age time) = do
    putWord8 0x44
    putInt64 age
    putInt64 time
  put (ClientBoundTitle action text fadeIn stay fadeOut) = do
    putWord8 0x45
    putVarInt action
    case text of
      Just text' -> putText text'
      Nothing -> return ()
    case fadeIn of
      Just fadeIn' -> putInt32 fadeIn'
      Nothing -> return ()
    case stay of
      Just stay' -> putInt32 stay'
      Nothing -> return ()
    case fadeOut of
      Just fadeOut' -> putInt32 fadeOut'
      Nothing -> return ()
  put (ClientBoundSoundEffect soundId soundCatagory x y z volume pitch) = do
    putWord8 0x46
    putVarInt soundId
    putVarInt soundCatagory
    putInt32 x
    putInt32 y
    putInt32 z
    putFloat volume
    putFloat pitch
  put (ClientBoundPlayerlistHeader header footer) = do
    putWord8 0x47
    putText header
    putText footer
  put (ClientBoundCollect collectedEntityId collectorEntityId) = do
    putWord8 0x48
    putVarInt collectedEntityId
    putVarInt collectorEntityId
  put (ClientBoundEntityTeleport entityId x y z yaw pitch onGround) = do
    putWord8 0x49
    putVarInt entityId
    putDouble x
    putDouble y
    putDouble z
    putInt8 yaw
    putInt8 pitch
    putBool onGround
  put (ClientBoundEntityUpdateAttributes entityId properties) = do
    putWord8 0x4a
    putVarInt entityId
    putArray properties
  put (ClientBoundEntityEffect entityId effectId amplifier duration hideParticles) = do
    putWord8 0x4b
    putVarInt entityId
    putInt8 effectId
    putInt8 amplifier
    putVarInt duration
    putInt8 hideParticles


  get = do
    packetId <- getWord8
    case packetId of
      0x00 -> do
        entityId <- getVarInt
        objectUUID <- getUUID
        pType <- getInt8
        x <- getDouble
        y <- getDouble
        z <- getDouble
        pitch <- getInt8
        yaw <- getInt8
        intField <- getInt32
        velocityX <- getInt16
        velocityY <- getInt16
        velocityZ <- getInt16
        return $ ClientBoundSpawnEntity entityId objectUUID pType x y z pitch yaw intField velocityX velocityY velocityZ
      0x01 -> do
        entityId <- getVarInt
        x <- getDouble
        y <- getDouble
        z <- getDouble
        count <- getInt16
        return $ ClientBoundSpawnEntityExperienceOrb entityId x y z count
      0x02 -> do
        entityId <- getVarInt
        pType <- getInt8
        x <- getDouble
        y <- getDouble
        z <- getDouble
        return $ ClientBoundSpawnEntityWeather entityId pType x y z
      0x03 -> do
        entityId <- getVarInt
        entityUUID <- getUUID
        pType <- getWord8
        x <- getDouble
        y <- getDouble
        z <- getDouble
        yaw <- getInt8
        pitch <- getInt8
        headPitch <- getInt8
        velocityX <- getInt16
        velocityY <- getInt16
        velocityZ <- getInt16
        metadata <- getEntityMetadata
        return $ ClientBoundSpawnEntityLiving entityId entityUUID pType x y z yaw pitch headPitch velocityX velocityY velocityZ metadata
      0x04 -> do
        entityId <- getVarInt
        entityUUID <- getUUID
        title <- getText
        location <- getPosition
        direction <- getWord8
        return $ ClientBoundSpawnEntityPainting entityId entityUUID title location direction
      0x05 -> do
        entityId <- getVarInt
        playerUUID <- getUUID
        x <- getDouble
        y <- getDouble
        z <- getDouble
        yaw <- getInt8
        pitch <- getInt8
        metadata <- getEntityMetadata
        return $ ClientBoundNamedEntitySpawn entityId playerUUID x y z yaw pitch metadata
      0x06 -> do
        entityId <- getVarInt
        animation <- getWord8
        return $ ClientBoundAnimation entityId animation
      0x07 -> do
        entries <- getArray
        return $ ClientBoundStatistics entries
      0x08 -> do
        entityId <- getVarInt
        location <- getPosition
        destroyStage <- getInt8
        return $ ClientBoundBlockBreakAnimation entityId location destroyStage
      0x09 -> do
        location <- getPosition
        action <- getWord8
        let nbtData =
          case of
            _ ->
        return $ ClientBoundTileEntityData location action nbtData
      0x0a -> do
        location <- getPosition
        byte1 <- getWord8
        byte2 <- getWord8
        blockId <- getVarInt
        return $ ClientBoundBlockAction location byte1 byte2 blockId
      0x0b -> do
        location <- getPosition
        pType <- getVarInt
        return $ ClientBoundBlockChange location pType
      0x0c -> do
        entityUUID <- getUUID
        action <- getVarInt
        let title =
          case action of
            0 ->
            3 ->
            _ ->
        let health =
          case action of
            0 ->
            2 ->
            _ ->
        let color =
          case action of
            0 ->
            4 ->
            _ ->
        let dividers =
          case action of
            0 ->
            4 ->
            _ ->
        let flags =
          case action of
            0 ->
            5 ->
            _ ->
        return $ ClientBoundBossBar entityUUID action title health color dividers flags
      0x0d -> do
        difficulty <- getWord8
        return $ ClientBoundDifficulty difficulty
      0x0e -> do
        matches <- getArray
        return $ ClientBoundTabComplete matches
      0x0f -> do
        message <- getText
        position <- getInt8
        return $ ClientBoundChat message position
      0x10 -> do
        chunkX <- getInt32
        chunkZ <- getInt32
        records <- getArray
        return $ ClientBoundMultiBlockChange chunkX chunkZ records
      0x11 -> do
        windowId <- getInt8
        action <- getInt16
        accepted <- getBool
        return $ ClientBoundTransaction windowId action accepted
      0x12 -> do
        windowId <- getWord8
        return $ ClientBoundCloseWindow windowId
      0x13 -> do
        windowId <- getWord8
        inventoryType <- getText
        windowTitle <- getText
        slotCount <- getWord8
        let entityId =
          case inventoryType of
            EntityHorse ->
            _ ->
        return $ ClientBoundOpenWindow windowId inventoryType windowTitle slotCount entityId
      0x14 -> do
        windowId <- getWord8
        items <- getArray
        return $ ClientBoundWindowItems windowId items
      0x15 -> do
        windowId <- getWord8
        property <- getInt16
        value <- getInt16
        return $ ClientBoundCraftProgressBar windowId property value
      0x16 -> do
        windowId <- getInt8
        slot <- getInt16
        item <- getSlot
        return $ ClientBoundSetSlot windowId slot item
      0x17 -> do
        itemID <- getVarInt
        cooldownTicks <- getVarInt
        return $ ClientBoundSetCooldown itemID cooldownTicks
      0x18 -> do
        channel <- getText
        pData <- getRestBuffer
        return $ ClientBoundCustomPayload channel pData
      0x19 -> do
        soundName <- getText
        soundCategory <- getVarInt
        x <- getInt32
        y <- getInt32
        z <- getInt32
        volume <- getFloat
        pitch <- getFloat
        return $ ClientBoundNamedSoundEffect soundName soundCategory x y z volume pitch
      0x1a -> do
        reason <- getText
        return $ ClientBoundKickDisconnect reason
      0x1b -> do
        entityId <- getInt32
        entityStatus <- getInt8
        return $ ClientBoundEntityStatus entityId entityStatus
      0x1c -> do
        x <- getFloat
        y <- getFloat
        z <- getFloat
        radius <- getFloat
        affectedBlockOffsets <- getArray
        playerMotionX <- getFloat
        playerMotionY <- getFloat
        playerMotionZ <- getFloat
        return $ ClientBoundExplosion x y z radius affectedBlockOffsets playerMotionX playerMotionY playerMotionZ
      0x1d -> do
        chunkX <- getInt32
        chunkZ <- getInt32
        return $ ClientBoundUnloadChunk chunkX chunkZ
      0x1e -> do
        reason <- getWord8
        gameMode <- getFloat
        return $ ClientBoundGameStateChange reason gameMode
      0x1f -> do
        keepAliveId <- getVarInt
        return $ ClientBoundKeepAlive keepAliveId
      0x20 -> do
        x <- getInt32
        z <- getInt32
        groundUp <- getBool
        bitMap <- getVarInt
        chunkData <- getBuffer
        blockEntities <- getArray
        return $ ClientBoundMapChunk x z groundUp bitMap chunkData blockEntities
      0x21 -> do
        effectId <- getInt32
        location <- getPosition
        pData <- getInt32
        global <- getBool
        return $ ClientBoundWorldEvent effectId location pData global
      0x22 -> do
        particleId <- getInt32
        longDistance <- getBool
        x <- getFloat
        y <- getFloat
        z <- getFloat
        offsetX <- getFloat
        offsetY <- getFloat
        offsetZ <- getFloat
        particleData <- getFloat
        particles <- getInt32
        let pData =
          case particleId of
            37 ->
            36 ->
            38 ->
            _ ->
        return $ ClientBoundWorldParticles particleId longDistance x y z offsetX offsetY offsetZ particleData particles pData
      0x23 -> do
        entityId <- getInt32
        gameMode <- getWord8
        dimension <- getInt32
        difficulty <- getWord8
        maxPlayers <- getWord8
        levelType <- getText
        reducedDebugInfo <- getBool
        return $ ClientBoundLogin entityId gameMode dimension difficulty maxPlayers levelType reducedDebugInfo
      0x24 -> do
        itemDamage <- getVarInt
        scale <- getInt8
        trackingPosition <- getBool
        icons <- getArray
        columns <- getInt8
        let rows =
          case columns of
            0 ->
            _ ->
        let x =
          case columns of
            0 ->
            _ ->
        let y =
          case columns of
            0 ->
            _ ->
        let pData =
          case columns of
            0 ->
            _ ->
        return $ ClientBoundMap itemDamage scale trackingPosition icons columns rows x y pData
      0x25 -> do
        entityId <- getVarInt
        dX <- getInt16
        dY <- getInt16
        dZ <- getInt16
        onGround <- getBool
        return $ ClientBoundRelEntityMove entityId dX dY dZ onGround
      0x26 -> do
        entityId <- getVarInt
        dX <- getInt16
        dY <- getInt16
        dZ <- getInt16
        yaw <- getInt8
        pitch <- getInt8
        onGround <- getBool
        return $ ClientBoundEntityMoveLook entityId dX dY dZ yaw pitch onGround
      0x27 -> do
        entityId <- getVarInt
        yaw <- getInt8
        pitch <- getInt8
        onGround <- getBool
        return $ ClientBoundEntityLook entityId yaw pitch onGround
      0x28 -> do
        entityId <- getVarInt
        return $ ClientBoundEntity entityId
      0x29 -> do
        x <- getDouble
        y <- getDouble
        z <- getDouble
        yaw <- getFloat
        pitch <- getFloat
        return $ ClientBoundVehicleMove x y z yaw pitch
      0x2a -> do
        location <- getPosition
        return $ ClientBoundOpenSignEntity location
      0x2b -> do
        flags <- getInt8
        flyingSpeed <- getFloat
        walkingSpeed <- getFloat
        return $ ClientBoundAbilities flags flyingSpeed walkingSpeed
      0x2c -> do
        event <- getVarInt
        let duration =
          case event of
            1 ->
            _ ->
        let playerId =
          case event of
            2 ->
            _ ->
        let entityId =
          case event of
            1 ->
            2 ->
            _ ->
        let message =
          case event of
            2 ->
            _ ->
        return $ ClientBoundCombatEvent event duration playerId entityId message
      0x2d -> do
        action <- getVarInt
        pData <- getArray
        return $ ClientBoundPlayerInfo action pData
      0x2e -> do
        x <- getDouble
        y <- getDouble
        z <- getDouble
        yaw <- getFloat
        pitch <- getFloat
        flags <- getInt8
        teleportId <- getVarInt
        return $ ClientBoundPosition x y z yaw pitch flags teleportId
      0x2f -> do
        entityId <- getVarInt
        location <- getPosition
        return $ ClientBoundBed entityId location
      0x30 -> do
        entityIds <- getArray
        return $ ClientBoundEntityDestroy entityIds
      0x31 -> do
        entityId <- getVarInt
        effectId <- getInt8
        return $ ClientBoundRemoveEntityEffect entityId effectId
      0x32 -> do
        url <- getText
        hash <- getText
        return $ ClientBoundResourcePackSend url hash
      0x33 -> do
        dimension <- getInt32
        difficulty <- getWord8
        gamemode <- getWord8
        levelType <- getText
        return $ ClientBoundRespawn dimension difficulty gamemode levelType
      0x34 -> do
        entityId <- getVarInt
        headYaw <- getInt8
        return $ ClientBoundEntityHeadRotation entityId headYaw
      0x35 -> do
        action <- getVarInt
        let radius =
          case action of
            0 ->
            _ ->
        let x =
          case action of
            2 ->
            3 ->
            _ ->
        let z =
          case action of
            2 ->
            3 ->
            _ ->
        let oldRadius =
          case action of
            1 ->
            3 ->
            _ ->
        let newRadius =
          case action of
            1 ->
            3 ->
            _ ->
        let speed =
          case action of
            1 ->
            3 ->
            _ ->
        let portalBoundary =
          case action of
            3 ->
            _ ->
        let warningTime =
          case action of
            4 ->
            3 ->
            _ ->
        let warningBlocks =
          case action of
            5 ->
            3 ->
            _ ->
        return $ ClientBoundWorldBorder action radius x z oldRadius newRadius speed portalBoundary warningTime warningBlocks
      0x36 -> do
        cameraId <- getVarInt
        return $ ClientBoundCamera cameraId
      0x37 -> do
        slot <- getInt8
        return $ ClientBoundHeldItemSlot slot
      0x38 -> do
        position <- getInt8
        name <- getText
        return $ ClientBoundScoreboardDisplayObjective position name
      0x39 -> do
        entityId <- getVarInt
        metadata <- getEntityMetadata
        return $ ClientBoundEntityMetadata entityId metadata
      0x3a -> do
        entityId <- getInt32
        vehicleId <- getInt32
        return $ ClientBoundAttachEntity entityId vehicleId
      0x3b -> do
        entityId <- getVarInt
        velocityX <- getInt16
        velocityY <- getInt16
        velocityZ <- getInt16
        return $ ClientBoundEntityVelocity entityId velocityX velocityY velocityZ
      0x3c -> do
        entityId <- getVarInt
        slot <- getVarInt
        item <- getSlot
        return $ ClientBoundEntityEquipment entityId slot item
      0x3d -> do
        experienceBar <- getFloat
        level <- getVarInt
        totalExperience <- getVarInt
        return $ ClientBoundExperience experienceBar level totalExperience
      0x3e -> do
        health <- getFloat
        food <- getVarInt
        foodSaturation <- getFloat
        return $ ClientBoundUpdateHealth health food foodSaturation
      0x3f -> do
        name <- getText
        action <- getInt8
        let displayText =
          case action of
            0 ->
            2 ->
            _ ->
        let pType =
          case action of
            0 ->
            2 ->
            _ ->
        return $ ClientBoundScoreboardObjective name action displayText pType
      0x40 -> do
        entityId <- getVarInt
        passengers <- getArray
        return $ ClientBoundSetPassengers entityId passengers
      0x41 -> do
        team <- getText
        mode <- getInt8
        let name =
          case mode of
            0 ->
            2 ->
            _ ->
        let prefix =
          case mode of
            0 ->
            2 ->
            _ ->
        let suffix =
          case mode of
            0 ->
            2 ->
            _ ->
        let friendlyFire =
          case mode of
            0 ->
            2 ->
            _ ->
        let nameTagVisibility =
          case mode of
            0 ->
            2 ->
            _ ->
        let collisionRule =
          case mode of
            0 ->
            2 ->
            _ ->
        let color =
          case mode of
            0 ->
            2 ->
            _ ->
        let players =
          case mode of
            0 ->
            4 ->
            3 ->
            _ ->
        return $ ClientBoundTeams team mode name prefix suffix friendlyFire nameTagVisibility collisionRule color players
      0x42 -> do
        itemName <- getText
        action <- getInt8
        scoreName <- getText
        let value =
          case action of
            1 ->
            _ ->
        return $ ClientBoundScoreboardScore itemName action scoreName value
      0x43 -> do
        location <- getPosition
        return $ ClientBoundSpawnPosition location
      0x44 -> do
        age <- getInt64
        time <- getInt64
        return $ ClientBoundUpdateTime age time
      0x45 -> do
        action <- getVarInt
        let text =
          case action of
            0 ->
            1 ->
            _ ->
        let fadeIn =
          case action of
            2 ->
            _ ->
        let stay =
          case action of
            2 ->
            _ ->
        let fadeOut =
          case action of
            2 ->
            _ ->
        return $ ClientBoundTitle action text fadeIn stay fadeOut
      0x46 -> do
        soundId <- getVarInt
        soundCatagory <- getVarInt
        x <- getInt32
        y <- getInt32
        z <- getInt32
        volume <- getFloat
        pitch <- getFloat
        return $ ClientBoundSoundEffect soundId soundCatagory x y z volume pitch
      0x47 -> do
        header <- getText
        footer <- getText
        return $ ClientBoundPlayerlistHeader header footer
      0x48 -> do
        collectedEntityId <- getVarInt
        collectorEntityId <- getVarInt
        return $ ClientBoundCollect collectedEntityId collectorEntityId
      0x49 -> do
        entityId <- getVarInt
        x <- getDouble
        y <- getDouble
        z <- getDouble
        yaw <- getInt8
        pitch <- getInt8
        onGround <- getBool
        return $ ClientBoundEntityTeleport entityId x y z yaw pitch onGround
      0x4a -> do
        entityId <- getVarInt
        properties <- getArray
        return $ ClientBoundEntityUpdateAttributes entityId properties
      0x4b -> do
        entityId <- getVarInt
        effectId <- getInt8
        amplifier <- getInt8
        duration <- getVarInt
        hideParticles <- getInt8
        return $ ClientBoundEntityEffect entityId effectId amplifier duration hideParticles


instance Serialize ServerBoundPlayPacket where
  put (ServerBoundTeleportConfirm teleportId) = do
    putWord8 0x00
    putVarInt teleportId
  put (ServerBoundTabComplete text assumeCommand lookedAtBlock) = do
    putWord8 0x01
    putText text
    putBool assumeCommand
    case lookedAtBlock of
      Just lookedAtBlock' -> putPosition lookedAtBlock'
      Nothing -> return ()
  put (ServerBoundChat message) = do
    putWord8 0x02
    putText message
  put (ServerBoundClientCommand actionId) = do
    putWord8 0x03
    putVarInt actionId
  put (ServerBoundSettings locale viewDistance chatFlags chatColors skinParts mainHand) = do
    putWord8 0x04
    putText locale
    putInt8 viewDistance
    putVarInt chatFlags
    putBool chatColors
    putWord8 skinParts
    putVarInt mainHand
  put (ServerBoundTransaction windowId action accepted) = do
    putWord8 0x05
    putInt8 windowId
    putInt16 action
    putBool accepted
  put (ServerBoundEnchantItem windowId enchantment) = do
    putWord8 0x06
    putInt8 windowId
    putInt8 enchantment
  put (ServerBoundWindowClick windowId slot mouseButton action mode item) = do
    putWord8 0x07
    putWord8 windowId
    putInt16 slot
    putInt8 mouseButton
    putInt16 action
    putInt8 mode
    putSlot item
  put (ServerBoundCloseWindow windowId) = do
    putWord8 0x08
    putWord8 windowId
  put (ServerBoundCustomPayload channel pData) = do
    putWord8 0x09
    putText channel
    putRestBuffer pData
  put (ServerBoundUseEntity target mouse x y z hand) = do
    putWord8 0x0a
    putVarInt target
    putVarInt mouse
    case x of
      Just x' -> putFloat x'
      Nothing -> return ()
    case y of
      Just y' -> putFloat y'
      Nothing -> return ()
    case z of
      Just z' -> putFloat z'
      Nothing -> return ()
    case hand of
      Just hand' -> putVarInt hand'
      Nothing -> return ()
  put (ServerBoundKeepAlive keepAliveId) = do
    putWord8 0x0b
    putVarInt keepAliveId
  put (ServerBoundPosition x y z onGround) = do
    putWord8 0x0c
    putDouble x
    putDouble y
    putDouble z
    putBool onGround
  put (ServerBoundPositionLook x y z yaw pitch onGround) = do
    putWord8 0x0d
    putDouble x
    putDouble y
    putDouble z
    putFloat yaw
    putFloat pitch
    putBool onGround
  put (ServerBoundLook yaw pitch onGround) = do
    putWord8 0x0e
    putFloat yaw
    putFloat pitch
    putBool onGround
  put (ServerBoundFlying onGround) = do
    putWord8 0x0f
    putBool onGround
  put (ServerBoundVehicleMove x y z yaw pitch) = do
    putWord8 0x10
    putDouble x
    putDouble y
    putDouble z
    putFloat yaw
    putFloat pitch
  put (ServerBoundSteerBoat unknown1 unknown2) = do
    putWord8 0x11
    putBool unknown1
    putBool unknown2
  put (ServerBoundAbilities flags flyingSpeed walkingSpeed) = do
    putWord8 0x12
    putInt8 flags
    putFloat flyingSpeed
    putFloat walkingSpeed
  put (ServerBoundBlockDig status location face) = do
    putWord8 0x13
    putInt8 status
    putPosition location
    putInt8 face
  put (ServerBoundEntityAction entityId actionId jumpBoost) = do
    putWord8 0x14
    putVarInt entityId
    putVarInt actionId
    putVarInt jumpBoost
  put (ServerBoundSteerVehicle sideways forward jump) = do
    putWord8 0x15
    putFloat sideways
    putFloat forward
    putWord8 jump
  put (ServerBoundResourcePackReceive hash result) = do
    putWord8 0x16
    putText hash
    putVarInt result
  put (ServerBoundHeldItemSlot slotId) = do
    putWord8 0x17
    putInt16 slotId
  put (ServerBoundSetCreativeSlot slot item) = do
    putWord8 0x18
    putInt16 slot
    putSlot item
  put (ServerBoundUpdateSign location text1 text2 text3 text4) = do
    putWord8 0x19
    putPosition location
    putText text1
    putText text2
    putText text3
    putText text4
  put (ServerBoundArmAnimation hand) = do
    putWord8 0x1a
    putVarInt hand
  put (ServerBoundSpectate target) = do
    putWord8 0x1b
    putUUID target
  put (ServerBoundBlockPlace location direction hand cursorX cursorY cursorZ) = do
    putWord8 0x1c
    putPosition location
    putVarInt direction
    putVarInt hand
    putInt8 cursorX
    putInt8 cursorY
    putInt8 cursorZ
  put (ServerBoundUseItem hand) = do
    putWord8 0x1d
    putVarInt hand


  get = do
    packetId <- getWord8
    case packetId of
      0x00 -> do
        teleportId <- getVarInt
        return $ ServerBoundTeleportConfirm teleportId
      0x01 -> do
        text <- getText
        assumeCommand <- getBool
        let lookedAtBlock =
          case of
            _ ->
        return $ ServerBoundTabComplete text assumeCommand lookedAtBlock
      0x02 -> do
        message <- getText
        return $ ServerBoundChat message
      0x03 -> do
        actionId <- getVarInt
        return $ ServerBoundClientCommand actionId
      0x04 -> do
        locale <- getText
        viewDistance <- getInt8
        chatFlags <- getVarInt
        chatColors <- getBool
        skinParts <- getWord8
        mainHand <- getVarInt
        return $ ServerBoundSettings locale viewDistance chatFlags chatColors skinParts mainHand
      0x05 -> do
        windowId <- getInt8
        action <- getInt16
        accepted <- getBool
        return $ ServerBoundTransaction windowId action accepted
      0x06 -> do
        windowId <- getInt8
        enchantment <- getInt8
        return $ ServerBoundEnchantItem windowId enchantment
      0x07 -> do
        windowId <- getWord8
        slot <- getInt16
        mouseButton <- getInt8
        action <- getInt16
        mode <- getInt8
        item <- getSlot
        return $ ServerBoundWindowClick windowId slot mouseButton action mode item
      0x08 -> do
        windowId <- getWord8
        return $ ServerBoundCloseWindow windowId
      0x09 -> do
        channel <- getText
        pData <- getRestBuffer
        return $ ServerBoundCustomPayload channel pData
      0x0a -> do
        target <- getVarInt
        mouse <- getVarInt
        let x =
          case mouse of
            2 ->
            _ ->
        let y =
          case mouse of
            2 ->
            _ ->
        let z =
          case mouse of
            2 ->
            _ ->
        let hand =
          case mouse of
            0 ->
            2 ->
            _ ->
        return $ ServerBoundUseEntity target mouse x y z hand
      0x0b -> do
        keepAliveId <- getVarInt
        return $ ServerBoundKeepAlive keepAliveId
      0x0c -> do
        x <- getDouble
        y <- getDouble
        z <- getDouble
        onGround <- getBool
        return $ ServerBoundPosition x y z onGround
      0x0d -> do
        x <- getDouble
        y <- getDouble
        z <- getDouble
        yaw <- getFloat
        pitch <- getFloat
        onGround <- getBool
        return $ ServerBoundPositionLook x y z yaw pitch onGround
      0x0e -> do
        yaw <- getFloat
        pitch <- getFloat
        onGround <- getBool
        return $ ServerBoundLook yaw pitch onGround
      0x0f -> do
        onGround <- getBool
        return $ ServerBoundFlying onGround
      0x10 -> do
        x <- getDouble
        y <- getDouble
        z <- getDouble
        yaw <- getFloat
        pitch <- getFloat
        return $ ServerBoundVehicleMove x y z yaw pitch
      0x11 -> do
        unknown1 <- getBool
        unknown2 <- getBool
        return $ ServerBoundSteerBoat unknown1 unknown2
      0x12 -> do
        flags <- getInt8
        flyingSpeed <- getFloat
        walkingSpeed <- getFloat
        return $ ServerBoundAbilities flags flyingSpeed walkingSpeed
      0x13 -> do
        status <- getInt8
        location <- getPosition
        face <- getInt8
        return $ ServerBoundBlockDig status location face
      0x14 -> do
        entityId <- getVarInt
        actionId <- getVarInt
        jumpBoost <- getVarInt
        return $ ServerBoundEntityAction entityId actionId jumpBoost
      0x15 -> do
        sideways <- getFloat
        forward <- getFloat
        jump <- getWord8
        return $ ServerBoundSteerVehicle sideways forward jump
      0x16 -> do
        hash <- getText
        result <- getVarInt
        return $ ServerBoundResourcePackReceive hash result
      0x17 -> do
        slotId <- getInt16
        return $ ServerBoundHeldItemSlot slotId
      0x18 -> do
        slot <- getInt16
        item <- getSlot
        return $ ServerBoundSetCreativeSlot slot item
      0x19 -> do
        location <- getPosition
        text1 <- getText
        text2 <- getText
        text3 <- getText
        text4 <- getText
        return $ ServerBoundUpdateSign location text1 text2 text3 text4
      0x1a -> do
        hand <- getVarInt
        return $ ServerBoundArmAnimation hand
      0x1b -> do
        target <- getUUID
        return $ ServerBoundSpectate target
      0x1c -> do
        location <- getPosition
        direction <- getVarInt
        hand <- getVarInt
        cursorX <- getInt8
        cursorY <- getInt8
        cursorZ <- getInt8
        return $ ServerBoundBlockPlace location direction hand cursorX cursorY cursorZ
      0x1d -> do
        hand <- getVarInt
        return $ ServerBoundUseItem hand

